[日记]写网络模拟器的心路历程

2 篇文章 0 订阅
1 篇文章 0 订阅

第一次接触多线程编程,第一次使用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;
}

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值