第一次接触多线程编程,第一次使用Visual Studio调试程序(多线程程序,100+条线程)
总的来说,在算法实现还是比较顺利的,大学前一年半的学习打下了坚实的底子,即使是几十面的论文,虽然只给出了不全的伪代码,但最后还是能够凭借脑补写出来
中途也有很崩溃的时候,第一次写这么难的程序,自己设计数据录入,数据处理,文件读写,没有任何提示,只有一篇还没写完的论文放在面前,第一次调试程序的时候还要拿纸笔记录是哪条线程发生的事件
好几次想放弃,好几次就要哭出来,最后还是坚持住,一行行写完
第一次真正体会到自己养成的"见名知意"的习惯是多么的有用
昨天和好朋友QH去看电影流浪地球,亲眼目睹了中国CG的崛起,脑子里就反复地回荡一句"会有的,都会有的",再过一个学期,短短4个月之后,就要专业分流了,数字媒体这个方向的形象昨晚被重塑了,但是还是决定在软件这条路上走下去
听到大神LHW寒假去北京实习的消息,想着自己组里的人也是这样的给力,很感激,要努力,才配得上这么强的队友!
最后把这十几天的成果保存在这里作为一段回忆
#include <list>
#include <vector>
#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
#include <cmath>
#include <sstream>
#include <fstream>
#include <cstring>
#include <algorithm>
#include <windows.h>
#include <future>
#include <condition_variable>
using namespace std;
class Node {
public:
int num;
int depth;
double energy;
double x, y;
double depth_distribution;
double transition_distance_distribution;
double remaining_energy_residual_distribution;
double product; //product of depth_distribution & transition_distance_distribution & remaining_energy_residual_distribution
bool visited;
Node* father;
list <Node*> child;
vector <Node*> neighborhood;
int child_num;
Node(int& node_num, double energy, double x, double y) {
this->visited = false;
this->num = node_num;
this->energy = energy;
this->x = x;
this->y = y;
this->father = nullptr;
this->child_num = 0;
node_num++;
}
~Node() {}
};
struct Cordinate {
int x, y;
Cordinate() {
x = y = 0;
}
~Cordinate() {}
};
class Tree {
public:
bool begin_flag;
mutex begin_lock, dis_lock;
vector <mutex*> my_lock;
condition_variable my_condition;
double THRESHOLD;
double energy_threshold_rate; //when a node's energy reaches 50% of its initial energy, then it has came to the energy_threshold_rate
double specific_energy_threshold_rate; // default value is 60% in the paper
int level_num;
int SINK_ID; //from 0 to n - 1
Node* root;
double Eelec;
double Efs;
double Emp;
double k;
int frequency;
double initial_energy_for_sink_node;
double initial_energy_for_average_node;
vector <Cordinate> c_vec;
double communication_range;
int source_node_sent_in_a_round;
int number_of_each_node_package;
int num_getter();
double get_distance(Node* p1, Node* p2);
bool able_conn(Node* p1, Node* p2, double communication_range);
double send_energy(Node* p1, Node* p2);
double receive_energy();
int get_average_children_num(int l);
bool verify_conn(Cordinate c1, Cordinate c2);
void random_helper();
Tree();
~Tree();
vector <Node*> vec; //to storage node[i]'s info (vec[i] = node[i])
vector <vector <Node*> > v2d; //to storage node[i]'s able connected node (v2d[i][j] = node v2d[i][j] able to communicate with node[i])
vector <list <Node*> > level; //to storage each level's node (level[i] represents for all nodes in the level[i])
vector <int> node_in_tree_vec;
vector <int> node_in_tree_beyond_sink_vec;
vector <int> random_choosed;
vector <Node*> temp_candidate_parents; //to storage the temporary valid parents for the node under examing
void random_data_generator();
Node* buildTree();
int get_level_num();
int level_counter(Node* root);
Node* get_sink();
void levelizer(Node* root, int count);
void random_chooser();
int get_frenquency();
void levelOrderTraverse();
void show_residual_energy(int);
int get_source_node_sent_in_a_round();
void topDownBalancing();
void downTopBalancing();
string name_getter();
void saving_energy_algorithm(Node*); //
//void updating_the_depth_distribution(); // no defination cause I have already added this function into saving energy algorithm
void get_candidate_parents(Node*, Node*); //
Node* get_depth_distribution(Node*); //
Node* get_transmission_distance_distribution(Node*); //
Node* get_remaining_energy_residual_distribution(Node*); //
Node* get_valid_candidate(Node*, Node*); //
void get_neighborhood(); //
};
Node* Tree::get_depth_distribution(Node* root) { // actually after the removal of some nodes, then have to fix the nodes' level
//get normalzed depth
if (temp_candidate_parents.empty()) return nullptr;
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
(*it)->depth_distribution = 1 + (double((*it)->depth) / (this->vec.size() - 1));
}
//get mass probability
double sum = 0.0;
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
sum += (*it)->depth_distribution;
}
//normalize and get mass probability
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
(*it)->depth_distribution = (*it)->depth_distribution / sum;
}
//fix the probability
//get sum(1 - temp_depth_distribution);
sum = 0.0;
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
sum += (1 - (*it)->depth_distribution);
}
//now fix it
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
(*it)->depth_distribution = (1 - (*it)->depth_distribution) / sum;
}
return root;
}
Node* Tree::get_transmission_distance_distribution(Node* root) { // this one just need to caculate once, cause the node's position is fixed
//get distance between the node and its neighbor nodes
if (temp_candidate_parents.empty()) return nullptr;
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
(*it)->transition_distance_distribution = get_distance((*it), root);
}
//get each node's probability
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
(*it)->transition_distance_distribution = 1 + ((*it)->transition_distance_distribution / this->communication_range);
}
//normalize the mass probility
//get sum for denominator of each node's probability
double sum = 0.0;
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
sum += (*it)->transition_distance_distribution;
}
//get mass probability
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
(*it)->transition_distance_distribution = (*it)->transition_distance_distribution / sum;
}
//fix the probability
sum = 0.0;
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
sum += (1 - (*it)->transition_distance_distribution);
}
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
(*it)->transition_distance_distribution = (1 - (*it)->transition_distance_distribution) / sum;
}
return root;
}
Node* Tree::get_remaining_energy_residual_distribution(Node* root) {
if (temp_candidate_parents.empty()) return nullptr;
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
(*it)->remaining_energy_residual_distribution = 1 + (*it)->energy / this->initial_energy_for_average_node;
}
//caculate the denominator and get it as sum
double sum = 0.0;
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
sum += (*it)->remaining_energy_residual_distribution;
}
//fix the probability
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
(*it)->remaining_energy_residual_distribution = (*it)->remaining_energy_residual_distribution / sum;
}
return root;
}
Node* Tree::get_valid_candidate(Node* root, Node* node_need_help) { //root means that node need parent
get_candidate_parents(root, node_need_help); //after this function , all valid cadidates will be storeged in the vector temp_candidate_parents
if (!this->temp_candidate_parents.empty()) {
get_depth_distribution(root);
get_transmission_distance_distribution(root);
get_remaining_energy_residual_distribution(root);
double max_value = -1.0;
Node* max_node = nullptr;
for (vector <Node*> ::iterator it = this->temp_candidate_parents.begin(); it != this->temp_candidate_parents.end(); it++) {
(*it)->product = (*it)->depth_distribution * (*it)->remaining_energy_residual_distribution * (*it)->transition_distance_distribution;
if ((*it)->product > max_value) {
max_value = (*it)->product;
max_node = (*it);
}
}
return max_node;
}
return nullptr; //means no valid candidate has been found
}
void Tree::get_candidate_parents(Node* root, Node* node_need_help) { //root is the node that need help's child which is called node need parents, while node_need_help is its father
this->temp_candidate_parents.clear(); //clear the last times' result
for (vector <Node*> ::iterator it = root->neighborhood.begin(); it != root->neighborhood.end(); it++) {
//Initially we get the neighbor nodes for root first, so we examine all the nodes in the tree and find the contactable nodes for the root
if ((*it) != this->get_sink() && (*it) != root && (double((*it)->energy) / this->initial_energy_for_average_node) > specific_energy_threshold_rate) {
//then it means the (*it) node is the node in root's neighborhood(root is node need parents)
bool is_root_child = false;
for (list <Node*> ::iterator it1 = root->child.begin(); it1 != root->child.end(); it1++) {
if ((*it1) == (*it)) {
is_root_child = true;
}
}
if (!is_root_child) { //node is not (node need parents)'s children
if ((*it) != node_need_help) { //node != nodeNeedHelp
//now doing level order traverse to know if the (*it) node belongs to the node need help
bool node_belongs_to_subTree_of_nodeNeedHelp = false;
Node* temp_node = node_need_help;
queue <Node*> q;
q.push(temp_node);
while (!q.empty() && node_belongs_to_subTree_of_nodeNeedHelp == false) {
temp_node = q.front();
q.pop();
if (temp_node == (*it)) {
node_belongs_to_subTree_of_nodeNeedHelp = true;
break;
}
for (list <Node*> ::iterator it2 = temp_node->child.begin(); it2 != temp_node->child.end(); it2++) {
if (temp_node != (*it)) {
q.push(*it2);
}
else {
node_belongs_to_subTree_of_nodeNeedHelp = true;
break;
}
}
}
//finish the levelOrderTraverse and get the result that if a node is belonged to the nodeNeedHelp's sub tree
if (!node_belongs_to_subTree_of_nodeNeedHelp) {
this->temp_candidate_parents.push_back((*it));
}
}
}
}
}
}
void Tree::get_neighborhood() { // get neighborhood after DTB for faster simulation(then no need to do Travese to get the neighbors) only running once
for (vector <Node*> ::iterator it = this->vec.begin(); it != this->vec.end(); it++) {
for (vector <Node*> ::iterator it1 = this->vec.begin(); it1 != this->vec.end(); it1++) {
if ((*it1) != (*it) && able_conn((*it), (*it1), communication_range)) {
(*it)->neighborhood.push_back(*it1);
}
}
}
}
void Tree::saving_energy_algorithm(Node* node_need_help) {
cout << "Use SEA to check node if it need help" << endl;
if ((double(node_need_help->energy) / this->initial_energy_for_average_node) <= this->energy_threshold_rate) {
//node root need help right now
int original_depth = 0, new_depth = 0;
if (node_need_help->child.size() > 1) {
Node* lowest_node = *((node_need_help->child).begin());
for (list <Node*> ::iterator it = node_need_help->child.begin(); it != node_need_help->child.end(); it++) {
if ((*it)->energy < lowest_node->energy) {
lowest_node = (*it);
}
}
//found the node with lowest energy in root's child set(also called node need parents)
Node* valid_candidate = this->get_valid_candidate(lowest_node, node_need_help);
bool find_it = false;
Node* temp = nullptr;
if (valid_candidate != nullptr) {
(valid_candidate->child).push_back(lowest_node);
lowest_node->father = valid_candidate;
original_depth = lowest_node->depth;
new_depth = (valid_candidate->depth) + 1;
list <Node*> ::iterator it1 = node_need_help->child.begin();
while (it1 != node_need_help->child.end()) {
if ((*it1) == lowest_node) {
node_need_help->child.erase(it1++);
find_it = true;
break;
}
else {
++it1;
}
}
}
if (valid_candidate != nullptr && !find_it) { //bug occurs, gathering info
cout << "valid_candidate != nullptr , bug occurs" << endl;
system("pause");
}
//now fix the level (I added updating the depth distribution into this function)
if (original_depth != new_depth) {
while (new_depth >= level.size()) {
level.push_back(list <Node*>()); // if level is not enough then add a new level container
}
level[new_depth].push_back(lowest_node);
bool level_fixed = false;
cout << "Wanna find node " << lowest_node->num << " in level " << lowest_node->depth << " : " << endl;
list <Node*> ::iterator it2 = level[original_depth].begin();
while (it2 != level[original_depth].end()) {
if ((*it2)->num == lowest_node->num) {
level[original_depth].erase(it2++);
level_fixed = true;
break;
}
else {
++it2;
}
}
if (!level_fixed) {
cout << "Level not fixed, contact coder at 3181939597@qq.com" << endl;
system("pause");
}
}
}
}
}
// All parameters start here
int MAX_VERTICES = 100; // 100 nodes[the nodes' ID range from 0 to 99]
int AREA_SIZE = 100; // 100 * 100 m ^ 2 then cordinate x range from 0 to 100, cordinate y range from 0 to 100
Tree::Tree() {
cout << "Enter num to initialize the parameters : " << endl;
cout << "Current defult parameters :" << endl;
cout << "THRESHOLD = sqrt(Efs / Emp); //meters " << endl;
cout << "Eelec = 50 * pow(10, -9); //J energy " << endl;
cout << "Efs = 10 * pow(10, -12); //J energy " << endl;
cout << "Emp = 0.0013 * pow(10, -12); //J energy " << endl;
cout << "k = 1024; //bits" << endl;
cout << "source_node_sent_in_a_round = 2; //integer " << endl;
cout << "number_of_each_node_package = 5; //integer " << endl;
cout << "communication_range = 25; //meters" << endl;
cout << "frequency = 50; // frenquency * round / second" << endl;
cout << "MAX_VERTICES = 100; // 100 nodes[the nodes' ID range from 0 to 99]" << endl;
cout << "AREA_SIZE = 100; // 100 * 100 m ^ 2 then cordinate x range from 0 to 100, cordinate y range from 0 to 100" << endl;
cout << "Initial energy for sink node = 100 (J)" << endl;
cout << "Initial energy for average node = 0.1 (J)" << endl;
cout << "Energy threshold rate = 0.5 // 0.5 for 50%" << endl;
cout << "Specific energy threshold rate = 0.6; //0.6 for 60% (in candidate choosing process)" << endl;
cout << "* SINK_ID = 0 is fixed and its location is always at (EDGE_SIZE / 2 , EDGE_SIZE / 2)" << endl;
this->energy_threshold_rate = 0.5; //0.5 for 50%
this->specific_energy_threshold_rate = 0.6; //0.6 for 60%;
this->THRESHOLD = sqrt(Efs / Emp); //meters
this->SINK_ID = 0; //integer number *this parameter is fixed , do not change, or the program go wrong
this->level_num = 0; //integer number
Eelec = 50 * pow(10, -9); //J energy *
Efs = 10 * pow(10, -12); //J energy *
Emp = 0.0013 * pow(10, -12); //J energy *
k = 1024; //bits
source_node_sent_in_a_round = 2; //ones (node2)
number_of_each_node_package = 5; //package //new added
communication_range = 25; //meters
frequency = 50; // frenquency * round / second
initial_energy_for_sink_node = 100; // J energy
initial_energy_for_average_node = 0.1; // J energy
cout << "Do u wanna change the default value?[yes/no]" << endl;
string order;
cin >> order;
// order.push_back('n');
if (order[0] == 'y' || order[0] == 'Y') {
cout << "MAX_VERTICES (integer) : ";
cin >> MAX_VERTICES;
cout << "AREA_SIZE (integer, length of edge) (meters) : ";
cin >> AREA_SIZE;
cout << "Eelec (nJ) : ";
cin >> Eelec;
Eelec *= pow(10, -9);
cout << "Efs (pJ) : ";
cin >> Efs;
Efs *= pow(10, -12);
cout << "Emp (pJ) : ";
cin >> Emp;
Emp *= pow(10, -12);
cout << "k (integer) : ";
cin >> k;
while (1) {
cout << "source_node_sent_in_a_round (integer) : ";
cin >> source_node_sent_in_a_round;
if (!(source_node_sent_in_a_round > 0 && source_node_sent_in_a_round < MAX_VERTICES)) {
cerr << "data illegal, It should be in the range (0, MAX_VERTICES - 1)" << endl;
}
else break;
}
cout << "number_of_each_node_package (integer) : ";
cin >> number_of_each_node_package;
cout << "communication_range (meters) : ";
cin >> communication_range;
cout << "frequency (frenquency * round / second) : ";
cin >> frequency;
cout << "Initial energy for sink node (J) : ";
cin >> initial_energy_for_sink_node;
cout << "Initial energy for average node (J) : ";
cin >> initial_energy_for_average_node;
cout << "Specific energy threshold rate (rate for candidate selection) : ";
cin >> specific_energy_threshold_rate;
cout << "Energy threshold rate : ";
cin >> energy_threshold_rate;
cout << endl << "ALL data is collected, start building tree phase" << endl;
}
for (int i = 0; i < MAX_VERTICES; i++) {
std::mutex *p = new mutex;
my_lock.push_back(p);
}
begin_flag = false;
}
//All parameters end here
int Tree::get_source_node_sent_in_a_round() {
return this->source_node_sent_in_a_round;
}
string Tree::name_getter() {
string str1 = ".txt";
string str2;
stringstream ss;
ss << MAX_VERTICES;
ss >> str2;
ss.clear();
str2 += str1;
return str2;
}
bool Tree::verify_conn(Cordinate c1, Cordinate c2) {
return sqrt(pow(c1.x - c2.x, 2) + pow(c1.y - c2.y, 2)) < communication_range;
}
void Tree::random_helper() {
Cordinate sink_node;
sink_node.x = sink_node.y = AREA_SIZE / 2;
c_vec.push_back(sink_node);
while (c_vec.size() < MAX_VERTICES) {
int xx = double(rand()) / RAND_MAX * (AREA_SIZE - 0);
int yy = double(rand()) / RAND_MAX * (AREA_SIZE - 0);
Cordinate *p = new Cordinate;
p->x = xx;
p->y = yy;
bool flag = false;
for (vector <Cordinate> ::iterator it = c_vec.begin(); it != c_vec.end(); it++) {
if (verify_conn(*it, *p)) {
flag = true;
break;
}
}
if (flag) {
c_vec.push_back(*p);
};
}
}
void Tree::random_data_generator() {
string file_name = name_getter();
cout << "According to the parameter - MAX_VERTICES , the program created " << MAX_VERTICES << " nodes randomly, and the file_name is " << file_name << endl;
ofstream outfile(&file_name[0], ios::out);
vector <int> vec_ran1, vec_ran2;
srand(time(NULL));
random_helper();
int flag = true;
for (vector <Cordinate> ::iterator it = c_vec.begin(); it != c_vec.end(); it++) {
if (flag) {
outfile << initial_energy_for_sink_node << " " << (*it).x << " " << (*it).y << endl;
flag = false;
}
else outfile << initial_energy_for_average_node << " " << (*it).x << " " << (*it).y << endl;
}
outfile.close();
}
int Tree::num_getter()
{
FILE *fin;
int temp = 0, count = 0;
double f = 0.0;
string file_name = name_getter();
if ((fin = fopen(&file_name[0], "r")) == NULL) {
// if ((fin = fopen("1001.txt", "r")) == NULL) {
fprintf(stderr, "Open error");
exit(1);
}
double block[3] = { 0.0, 0.0, 0.0 };
//set the vector vec to control all nodes' info(include the depth/energy/cordiante(x&y))
//only need to be calculate once
//but vector vec has to be fixed when testing a new algorithm(DTB&TDB / added SEA)
while (fscanf(fin, "%lf", &f) != EOF) {
block[temp] = f;
temp++;
if (temp % 3 == 0) {
temp = 0;
Node* p = new Node(count, block[0], block[1], block[2]);
vec.push_back(p);
}
}
int node_num = count;
int size = vec.size();
if (node_num != size) {
cout << "------------------------------------------" << endl;
cout << "Data got broken" << endl;
cout << "Delete all the logs and run the program again" << endl;
cout << "------------------------------------------" << endl;
return 0;
}
// fresh the vector v2d(show each node's contactable nodes)
for (int i = 0; i < size; i++) {
v2d.push_back(vector <Node*>());
}
for (int i = 0; i < size; i++) {
for (int j = i + 1; j < size; j++) {
if (able_conn(vec[i], vec[j], communication_range)) {
v2d[i].push_back(vec[j]);
v2d[j].push_back(vec[i]);
}
}
}
return count;
}
void Tree::random_chooser() {
random_choosed.clear();
random_shuffle(node_in_tree_beyond_sink_vec.begin(), node_in_tree_beyond_sink_vec.end());
for (int i = 0; i < source_node_sent_in_a_round; i++) {
random_choosed.push_back(node_in_tree_beyond_sink_vec[i]);
}
}
Node* transmit(Node* source, Tree* t) {
if (source == t->get_sink()) {
return nullptr;
}
std::unique_lock <std::mutex> _5214_lock(t->begin_lock);
t->my_condition.wait(_5214_lock, [&] {
return t->begin_flag == true;
});
cout << "Transmit" << endl;
_5214_lock.unlock();
(*(t->my_lock[source->num])).lock();
source->energy -= t->number_of_each_node_package * t->send_energy(source, source->father); // leaf node just need to send
(*(t->my_lock[source->num])).unlock();
(*(t->my_lock[source->num])).lock();
if (source->energy <= 0) {
(*(t->my_lock[source->num])).unlock();
return source;
}
(*(t->my_lock[source->num])).unlock();
source = source->father;
while (source != t->vec[t->SINK_ID]) {
(*(t->my_lock[source->num])).lock();
source->energy -= t->number_of_each_node_package * (t->send_energy(source, source->father) + t->receive_energy()); //average node both need to receive and send
(*(t->my_lock[source->num])).unlock();
(*(t->my_lock[source->num])).lock();
if (source->energy <= 0) {
(*(t->my_lock[source->num])).unlock();
return source;
}
(*(t->my_lock[source->num])).unlock();
source = source->father;
}
(*(t->my_lock[source->num])).lock();
source->energy -= t->number_of_each_node_package * t->k * t->Eelec; //sink node just need to receive
(*(t->my_lock[source->num])).unlock();
(*(t->my_lock[source->num])).lock();
if (source->energy <= 0) {
(*(t->my_lock[source->num])).unlock();
return source;
}
(*(t->my_lock[source->num])).unlock();
return nullptr;
}
double Tree::receive_energy() {
return number_of_each_node_package * k * Eelec;
}
int Tree::get_average_children_num(int l) {
int nodes = level[l].size();
int sum = 0;
for (list <Node*> ::iterator it = level[l].begin(); it != level[l].end(); it++) {
sum += (*it)->child_num;
}
return ceil(sum / nodes);
}
void Tree::levelOrderTraverse() {
ofstream outfile("LevelOrderTraverse.txt", ios::out | ios::app);
if (!outfile) {
cerr << "levelOrderTeaverse.txt Open error" << endl;
exit(1);
}
cout << "LevelOrderTraverse" << endl;
queue <Node*> q;
q.push(this->get_sink());
while (!q.empty()) {
Node* temp = q.front();
q.pop();
outfile << temp->num << " ";
if (temp->father != nullptr) outfile << "fa = " << temp->father->num << endl;
else outfile << "no father" << endl;
for (list <Node*> ::iterator it = temp->child.begin(); it != temp->child.end(); it++) {
q.push(*it);
}
}
cout << endl;
outfile.close();
}
void Tree::levelizer(Node* root, int count = -1) {
count++;
root->depth = count;
level[count].push_back(root);
if (root->child_num == 0) {
return;
}
for (list <Node*> ::iterator it = (root->child).begin(); it != (root->child).end(); it++) {
levelizer(*it, count);
}
}
Node* Tree::get_sink() {
return this->vec[this->SINK_ID];
}
int Tree::get_level_num() {
return level_num;
}
int Tree::level_counter(Node* root) {
if (root->child_num == 0) {
return 1;
}
int *max_num = new int[root->child_num];
memset(max_num, 0, sizeof(max_num));
int i = 0;
for (list <Node*> ::iterator it = (root->child).begin(); it != (root->child).end(); it++, i++) {
max_num[i] = 1 + level_counter(*it);
}
int temp_max = max_num[0];
for (int i = 0; i < root->child_num; i++) {
if (temp_max < max_num[i]) {
temp_max = max_num[i];
}
}
return level_num = temp_max;
}
Tree :: ~Tree() {
for (vector <mutex*> ::iterator it = my_lock.begin(); it != my_lock.end(); it++) {
delete (*it);
}
}
double Tree::get_distance(Node* p1, Node* p2) {
return sqrt(pow(p1->x - p2->x, 2) + pow(p1->y - p2->y, 2));
}
bool Tree::able_conn(Node* p1, Node* p2, double communication_range) {
return get_distance(p1, p2) < communication_range;
}
double Tree::send_energy(Node* p1, Node* p2) { //retrun energy consumption for delivery
if (able_conn(p1, p2, THRESHOLD)) {
return k * Eelec + k * Efs * pow(get_distance(p1, p2), 2);
}
return k * Eelec + k * Emp * pow(get_distance(p1, p2), 4);
}
Node* Tree::buildTree() {
int node_num = num_getter();
if (!node_num) {
cout << endl << "Building Tree process failed" << endl;
}
queue <Node*> q;
q.push(vec[SINK_ID]); //vec[0] always be the first node
Node* temp = q.front();
temp->visited = true;
//for (auto & iter : v2d) {
//iter.clear();
//}
while (!q.empty()) {
temp = q.front();
q.pop();
node_in_tree_vec.push_back(temp->num);
node_num--;
for (vector <Node*> ::iterator it = v2d[temp->num].begin(); it != v2d[temp->num].end(); it++) {
if (!((*it)->visited)) {
(*it)->visited = true;
temp->child.push_back((*it));
temp->child_num++;
(*it)->father = temp;
q.push(*it);
}
}
}
for (vector <int> ::iterator it = node_in_tree_vec.begin(); it != node_in_tree_vec.end(); it++) {
if ((*it) != this->vec[SINK_ID]->num) {
node_in_tree_beyond_sink_vec.push_back(*it);
}
}
cout << endl << "Tree Built successfully" << endl;
root = vec[SINK_ID];
level_counter(vec[SINK_ID]);
for (int i = 0; i < level_num; i++) {
level.push_back(list <Node*>());
}
levelizer(vec[SINK_ID]);
srand(time(NULL));
vec[SINK_ID]->energy = initial_energy_for_sink_node;
if (node_num != 0) cout << "Data not good, there must be some nodes get sperated from the system due to the distance reason" << endl;
return vec[SINK_ID];
}
void Tree::show_residual_energy(int simulation_type) {
string file_name;
switch (simulation_type)
{
case 0: {
file_name = "not_balanced_tree_residual.txt";
break;
}
case 1: {
file_name = "just_topDownBalacing_residual.txt";
break;
}
case 2: {
file_name = "just_downTopBalacing_residual.txt";
break;
}
case 3: {
file_name = "topDownBalacing_and_downTopBalacing_residual.txt";
break;
}
case 4: {
file_name = "topDownBalacing_and_sea_residual.txt";
break;
}
case 5: {
file_name = "downTopBalacing_and_sea_residual.txt";
break;
}
case 6: {
file_name = "topDownBalacing_and_downTopBalacing_and_sea_residual.txt";
break;
}
case 7: {
file_name = "topDownBalacing_and_dynamic_sea_residual.txt";
break;
}
case 8: {
file_name = "downTopBalacing_and_dynamic_sea_residual.txt";
}
case 9: {
file_name = "topDownBalancing_and_downTopBalacing_and_dynamic_sea_residual.txt";
}
default:
break;
}
fstream outfile(&file_name[0], ios::out);
if (!outfile) {
cerr << "Open error" << endl;
exit(1);
}
outfile << "-------------------------------------------------" << endl;
time_t tt = time(NULL);
tm* t = localtime(&tt);
outfile << "Log created end at : " << t->tm_year + 1900 << " / " << t->tm_mon + 1 << " / " << t->tm_mday << " / " << t->tm_hour << " : " << t->tm_min << " : " << t->tm_sec << endl;
for (vector <Node*> ::iterator it = vec.begin(); it != vec.end(); it++) {
outfile << "node " << (*it)->num << " 's residual energy : " << (*it)->energy << endl;
}
outfile << "-------------------------------------------------" << endl;
outfile.close();
}
int Tree::get_frenquency() {
return this->frequency;
}
void create_file_head() {
ofstream outfile("result.txt", ios::out | ios::app);
if (!outfile) {
cerr << "Open error" << endl;
exit(1);
}
time_t tt = time(NULL);
tm* t = localtime(&tt);
outfile << "------------------------------------------------------" << endl;
outfile << "Log created start at : " << t->tm_year + 1900 << " / " << t->tm_mon + 1 << " / " << t->tm_mday << " / " << t->tm_hour << " : " << t->tm_min << " : " << t->tm_sec << endl;
outfile.close();
}
bool create_file_body(Node* p_sink, Tree &newTree) {
fstream outfile("result.txt", ios::out | ios::app);
if (!outfile) {
cerr << "open error" << endl;
exit(1);
}
if (p_sink != nullptr) {
outfile << "Tree's info : (For verifying)" << endl;
outfile << endl << "*********************Parameters********************" << endl << endl;
outfile << "max vertices (integer) : " << MAX_VERTICES << endl;
outfile << "area size (integer, length of edge) (meters) : " << AREA_SIZE << endl;
outfile << "Eelec (J) : " << newTree.Eelec << endl;
outfile << "Efs (J) : " << newTree.Efs << endl;
outfile << "Emp (J) : " << newTree.Emp << endl;
outfile << "k (integer) : " << newTree.k << endl;
outfile << "source node sent in a round (integer) : " << newTree.source_node_sent_in_a_round << endl;
outfile << "number of each node package (integer) : " << newTree.number_of_each_node_package << endl;
outfile << "communication range (meters) : " << newTree.communication_range << endl;
outfile << "frequency (frenquency * round / second) : " << newTree.frequency << endl;
outfile << "Initial energy for sink node (J) : " << newTree.initial_energy_for_sink_node << endl;
outfile << "Initial energy for average node (J) : " << newTree.initial_energy_for_average_node << endl;
outfile << endl << "*********************Parameters********************" << endl << endl;
outfile << "All sensors : " << newTree.vec.size() << endl;
outfile << "Sensors in Tree : " << newTree.node_in_tree_vec.size() << endl;
outfile << "Sink Node - ID : " << p_sink->num << " energy : " << p_sink->energy << " x : " << p_sink->x << " y : " << p_sink->y << " " << endl;
outfile << "Level num = " << newTree.get_level_num() << endl;//get n levels and start from the 0th level to the (n-1)th level
outfile << "Level print : " << endl;
int size = newTree.level.size();
for (int i = 0; i < size; i++) {
outfile << "Level " << i << " th : ";
for (list <Node*> ::iterator it = newTree.level[i].begin(); it != newTree.level[i].end(); it++) {
outfile << (*it)->num << " ";
}
outfile << endl;
}
outfile.close();
return true;
}
else {
outfile << "Illegal data, check the data.txt again" << endl << endl;
outfile.close();
return false;
}
return false;
}
void create_file_tail(Tree &newTree) {
fstream outfile("result.txt", ios::out | ios::app);
if (!outfile) {
cerr << "open error" << endl;
exit(1);
}
time_t tt = time(NULL);
tm* t = localtime(&tt);
outfile << "Log created end at : " << t->tm_year + 1900 << " / " << t->tm_mon + 1 << " / " << t->tm_mday << " / " << t->tm_hour << " : " << t->tm_min << " : " << t->tm_sec << endl;
outfile << "------------------------------------------------------" << endl;
cout << "For logs, check the 'result.txt' and find the log history" << endl;
cout << "For residual energy , check the 'residual.txt' for the energy history" << endl;
cout << "For randomly created node's info, check the '" << newTree.name_getter() << "' for all node's info" << endl;
outfile.close();
}
void create_file_result(Node* die_first, double time_consumption, int type) {
fstream outfile("result.txt", ios::app | ios::out);
if (!outfile) {
cerr << "open error" << endl;
exit(1);
}
switch (type)
{
case 0: {
outfile << endl << "Not balanced Tree (no DTB or TDB) simulation result : " << endl;
break;
}
case 1: {
outfile << endl << "Balanced Tree (TopDownBalacing) simulation result : " << endl;
break;
}
case 2: {
outfile << endl << "Balanced Tree (DownTopBalacing) simulation result : " << endl;
break;
}
case 3: {
outfile << endl << "Balanced Tree (TopDownBalacing + DownTopBalacing) simulation result : " << endl;
break;
}
case 4: {
outfile << endl << "SEA Tree (TopDownBalacing + SEA) simulation result : " << endl;
break;
}
case 5: {
outfile << endl << "SEA Tree (DownTopBalacing + SEA) simulation result : " << endl;
break;
}
case 6: {
outfile << endl << "SEA Tree (TopDownBalacing + DownTopBalacing + SEA) simulation result : " << endl;
break;
}
case 7: {
outfile << endl << "Dynamic SEA Tree (TopDownBalacing + improved SEA) simulation result : " << endl;
break;
}
case 8: {
outfile << endl << "Dynamic SEA Tree (DownTopBalacing + improved SEA) simulation result : " << endl;
break;
}
case 9: {
outfile << endl << "Dynamic SEA Tree(TopDownBalacing + DownTopBalacing + improved SEA) simulation result : " << endl;
break;
}
default:
break;
}
outfile << "The first node " << die_first->num << " die after " << time_consumption << " seconds and system stop working" << endl;
outfile.close();
}
void fix_tree_for_balanced_tree_simulation(Tree& newTree) {
for (vector <Node*> ::iterator it = newTree.vec.begin(); it != newTree.vec.end(); it++) {
if ((*it) == newTree.get_sink()) {
(*it)->energy = newTree.initial_energy_for_sink_node;
}
else {
(*it)->energy = newTree.initial_energy_for_average_node;
}
}
cout << "Energy fixed " << endl;
}
void Tree::topDownBalancing() {
int level_size = level.size();
if (level_size < 2) {
return; // no need to be balancedc
}
for (int i = 1; i < level_size - 1; i++) { //from the top to the bottom, level[0] and level[n-1] no need to be balanced
int average = get_average_children_num(i);
for (list <Node*> ::iterator it = level[i].begin(); it != level[i].end(); it++) { //this dynamic process will let vector get some problem
for (list <Node*> ::iterator it1 = level[i].begin(); it1 != level[i].end(); it1++) {
if (((*it)->num != (*it1)->num) && (*it)->child.size() > average && (*it1)->child.size() < average) {
list <Node*> ::iterator it0 = ((*it)->child).begin();
while (it0 != ((*it)->child).end()) {
if (!((*it)->child.size() > average && (*it1)->child.size() < average)) {
break;
}
else if (able_conn((*it0), (*it1), communication_range)) {
((*it1)->child).push_back(*it0); //add child
((*it1)->child_num)++;
(*it0)->father = (*it1); //new father linked
//remomve the child and avoid the decrementable fault
((*it)->child).erase(it0++); //remove child
((*it)->child_num)--;
}
else {
//check if its children can take the mission
bool child_could_help = false;
for (list <Node*> ::iterator it2 = ((*it1)->child).begin(); it2 != ((*it1)->child).end(); it2++) {
if (able_conn((*it0), (*it2), communication_range)) {
child_could_help = true;
(*it2)->child.push_back(*it0); //supporter's child add new child
(*it2)->child_num++; //supporter's child ' child_num++
(*it0)->father = *it2; //nodeNeedBalance's child get supporterNode's child as new father
int temp_num = (*it0)->num;
(*it)->child.erase(it0++); //nodeNeedBalance remove one child
(*it)->child_num--; //nodeNeedBalance's child_num--
//fix the level
bool find_it = false;
list <Node*> ::iterator it3 = level[i + 1].begin();
while (it3 != level[i + 1].end()) {
if ((*it3)->num == temp_num) {
if (i + 2 == level.size()) {
level.push_back(list <Node*>());
}
level[i + 2].push_back(*it3);
level[i + 1].erase(it3++);
find_it = true;
break;
}
else {
++it3;
}
} // nearest end for loop
if (!find_it) {
cout << "bug occurs during TDB, contact code author at 3181939597@qq.com" << endl;
system("pause");
}
break;
}
} //in circle end while loop
if (!child_could_help) {
++it0;
}
}
} // out end while loop
}
}
}
}
}
void Tree::downTopBalancing() {
int last_level = level.size() - 1;
for (int i = last_level; i >= 1; i--) { //from the bottom to the top(the last level to the top - 1 level)
for (list <Node*> ::iterator it = level[i].begin(); it != level[i].end(); it++) {
for (list <Node*> ::iterator it1 = level[i].begin(); it1 != level[i].end(); it1++) {
if ((*it1)->father != (*it)->father && (*it1) != (*it)) {
if (able_conn((*it), (*it1)->father, communication_range) && ((*it)->father)->child.size() - (((*it1)->father)->child.size()) > 1) {
((*it)->father)->child_num--;
((*it1)->father)->child.push_back(*it); //add child
((*it1)->father)->child_num++;
(*it)->father = (*it1)->father;
//remove child
list <Node*> ::iterator it2 = ((*it)->father)->child.begin();
while (it2 != ((*it)->father)->child.end()) {
if ((*it2)->num == (*it)->num) {
((*it)->father)->child.erase(it2++);
}
else {
++it2;
}
} //nearest for loop
}
}
}
}
}
}
void stable_simulation(double& time_consumption, Node*& die_first, Tree& newTree) { //for not_balanced_tree and balanced tree without SEA
bool is_first_one_to_die = true;
bool jump_while = false;
while (!jump_while) {
newTree.begin_flag = true;
newTree.random_chooser();
cout << "Choosing phase successful" << endl;
time_consumption += double(1.0 / newTree.get_frenquency());
std::vector <std::future <Node*> > futures;
for (int i = 0; i < newTree.source_node_sent_in_a_round; i++) {
int random_index = newTree.random_choosed[i];
std::packaged_task<Node*(Node*, Tree*)> pac(transmit);
futures.push_back(pac.get_future());
std::thread(std::move(pac), newTree.vec[random_index], &newTree).join();
}
for (auto& future : futures) {
auto* node = future.get();
if (node != nullptr) {
if (is_first_one_to_die) {
die_first = node;
is_first_one_to_die = false;
}
jump_while = true;
}
}
}
}
void create_file_for_balanced_tree(Node* die_first, double time_consumption) {
fstream outfile("result.txt", ios::out | ios::app);
if (!outfile) {
cerr << "open error" << endl;
exit(1);
}
outfile << endl << "Balanced Tree (without SEA) simulation result : " << endl;
outfile << "The first node " << die_first->num << " after " << time_consumption << " seconds and system stop working" << endl;
outfile.close();
}
Node* dynamic_transmit(Node* source, Tree* t) {
if (source == t->get_sink()) {
return nullptr;
}
std::unique_lock <std::mutex> _5214_lock(t->begin_lock);
t->my_condition.wait(_5214_lock, [&] {
return t->begin_flag == true;
});
cout << "Transmit" << endl;
_5214_lock.unlock();
(*(t->my_lock[source->num])).lock();
source->energy -= t->number_of_each_node_package * t->send_energy(source, source->father); // leaf node just need to send
t->saving_energy_algorithm(source);
(*(t->my_lock[source->num])).unlock();
(*(t->my_lock[source->num])).lock();
if (source->energy <= 0) {
(*(t->my_lock[source->num])).unlock();
return source;
}
t->saving_energy_algorithm(source);
(*(t->my_lock[source->num])).unlock();
source = source->father;
while (source != t->vec[t->SINK_ID]) {
(*(t->my_lock[source->num])).lock();
source->energy -= t->number_of_each_node_package * (t->send_energy(source, source->father) + t->receive_energy()); //average node both need to receive and send
t->saving_energy_algorithm(source);
(*(t->my_lock[source->num])).unlock();
(*(t->my_lock[source->num])).lock();
if (source->energy <= 0) {
(*(t->my_lock[source->num])).unlock();
return source;
}
t->saving_energy_algorithm(source);
(*(t->my_lock[source->num])).unlock();
source = source->father;
}
(*(t->my_lock[source->num])).lock();
source->energy -= t->number_of_each_node_package * t->k * t->Eelec; //sink node just need to receive
t->saving_energy_algorithm(source);
(*(t->my_lock[source->num])).unlock();
(*(t->my_lock[source->num])).lock();
if (source->energy <= 0) {
(*(t->my_lock[source->num])).unlock();
return source;
}
t->saving_energy_algorithm(source);
(*(t->my_lock[source->num])).unlock();
return nullptr;
}
void dynamic_simulation(double& time_consumption, Node*& die_first, Tree& newTree) { //for balanced tree with SEA
bool is_first_one_to_die = true;
bool jump_while = false;
while (!jump_while) {
newTree.begin_flag = true;
newTree.random_chooser();
cout << "Choosing phase successful" << endl;
time_consumption += double(1.0 / newTree.get_frenquency());
std::vector <std::future <Node*> > futures;
for (int i = 0; i < newTree.source_node_sent_in_a_round; i++) {
int random_index = newTree.random_choosed[i];
std::packaged_task<Node*(Node*, Tree*)> pac(dynamic_transmit);
futures.push_back(pac.get_future());
std::thread(std::move(pac), newTree.vec[random_index], &newTree).join();
}
for (auto& future : futures) {
auto* node = future.get();
if (node != nullptr) {
if (is_first_one_to_die) {
die_first = node;
is_first_one_to_die = false;
}
jump_while = true;
}
}
}
}
int main() {
Tree newTree;
newTree.random_data_generator(); //generate the data by all parameters and ensure all the nodes can be connected to the network
create_file_head();
Node* p_sink = newTree.buildTree();
if (!create_file_body(p_sink, newTree)) { return 0; }
// not balanced tree simulation
double time_consumption = 0.0;
Node* die_first = nullptr;
stable_simulation(time_consumption, die_first, newTree);
create_file_result(die_first, time_consumption, 0); // for not balanced tree
newTree.show_residual_energy(0); //for unbalanced tree
// just use TopDownBalacing without downTopBalancing
fix_tree_for_balanced_tree_simulation(newTree);
newTree.topDownBalancing();
stable_simulation(time_consumption, die_first, newTree);
create_file_result(die_first, time_consumption, 1);
newTree.show_residual_energy(1);
// use both DownTopBalancing and TopDownBalacing simulation
time_consumption = 0.0;
die_first = nullptr;
fix_tree_for_balanced_tree_simulation(newTree);
newTree.downTopBalancing();
stable_simulation(time_consumption, die_first, newTree);
create_file_result(die_first, time_consumption, 3);
newTree.show_residual_energy(3);
//stable_simulation_part_finished
// use downTopBalancing + topDownBalacing + SEA
time_consumption = 0.0;
die_first = nullptr;
fix_tree_for_balanced_tree_simulation(newTree);
dynamic_simulation(time_consumption, die_first, newTree);
create_file_result(die_first, time_consumption, 6);
newTree.show_residual_energy(6);
create_file_tail(newTree);
system("pause");
return 0;
}