diff --git a/BlockVisualisation/block_visual.cpp b/BlockVisualisation/block_visual.cpp index 43fc07f..16fc772 100644 --- a/BlockVisualisation/block_visual.cpp +++ b/BlockVisualisation/block_visual.cpp @@ -1,157 +1,187 @@ #include "block_visual.h" -#include "layout.h" #include "cluster.h" +#include "layout.h" #include - - -BlockVisual::BlockVisual(std::string file_settings = ""){ - _settings = Settings(); - if (file_settings != ""){ - std::ifstream setfile(file_settings.c_str()); - std::string str; - std::getline(setfile, str);std::getline(setfile, str);std::getline(setfile, str);std::getline(setfile, str); - _file_path_in = str; - std::getline(setfile, str);std::getline(setfile, str); - _file_path_out = str; - std::getline(setfile, str);std::getline(setfile, str);std::getline(setfile, str); - _settings.componentwise = std::stoi(str); - std::getline(setfile, str); std::getline(setfile, str); - _settings.iterations = std::stoi(str); - std::getline(setfile, str); std::getline(setfile, str); - _settings.edge_force = std::stod(str); - std::getline(setfile, str);std::getline(setfile, str); - _settings.gravity = std::stod(str); - std::getline(setfile, str);std::getline(setfile, str); - _settings.jitter_tol = std::stod(str); - std::getline(setfile, str);std::getline(setfile, str); - _settings.speed = std::stod(str); - std::getline(setfile, str);std::getline(setfile, str); - _settings.speed_efficiency = std::stod(str); - std::getline(setfile, str);std::getline(setfile, str); - _settings.layout_verbosity = std::stoi(str); - std::getline(setfile, str);std::getline(setfile, str);std::getline(setfile, str); - _settings.terms = std::stoi(str); - std::getline(setfile, str);std::getline(setfile, str); - _settings.thresh = std::stoi(str); - std::getline(setfile, str);std::getline(setfile, str);std::getline(setfile, str); - _settings.kk_edge_strength = std::stod(str); - std::getline(setfile, str);std::getline(setfile, str); - _settings.kk_thresh = std::stod(str); - std::getline(setfile, str);std::getline(setfile, str); - _settings.kk_iterations = std::stoi(str); - std::getline(setfile, str);std::getline(setfile, str); - _settings.kk_verbosity = std::stoi(str); - std::getline(setfile, str);std::getline(setfile, str);std::getline(setfile, str); - _settings.max_kamada_kawai_nodes = std::stoi(str); - } +BlockVisual::BlockVisual(std::string file_settings = "") { + _settings = Settings(); + if (file_settings != "") { + std::ifstream setfile(file_settings.c_str()); + std::string str; + std::getline(setfile, str); + std::getline(setfile, str); + std::getline(setfile, str); + std::getline(setfile, str); + _file_path_in = str; + std::getline(setfile, str); + std::getline(setfile, str); + _file_path_out = str; + std::getline(setfile, str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.componentwise = std::stoi(str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.iterations = std::stoi(str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.edge_force = std::stod(str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.gravity = std::stod(str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.jitter_tol = std::stod(str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.speed = std::stod(str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.speed_efficiency = std::stod(str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.layout_verbosity = std::stoi(str); + std::getline(setfile, str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.terms = std::stoi(str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.thresh = std::stoi(str); + std::getline(setfile, str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.kk_edge_strength = std::stod(str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.kk_thresh = std::stod(str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.kk_iterations = std::stoi(str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.kk_verbosity = std::stoi(str); + std::getline(setfile, str); + std::getline(setfile, str); + std::getline(setfile, str); + _settings.max_kamada_kawai_nodes = std::stoi(str); + } } +void write_particles(std::vector _particles, int component, + std::string filename) { -void write_particles(std::vector _particles, int component, std::string filename){ - - if (component == -1){ - std::ofstream myfile; - myfile.open((filename+".txt").c_str(), std::ios::out|std::ios::trunc); - for (Particle p: _particles){myfile << p.get_pos().real() << "|" << p.get_pos().imag() << std::endl;} - myfile.close(); - } else { - std::ofstream myfile; - myfile.open((filename+".txt").c_str(), std::ios::out|std::ios::app); - int p_index=0; - for (Particle p: _particles){myfile < _positions, std::string filename){ - - + myfile.close(); + } else { std::ofstream myfile; - myfile.open((filename+".txt").c_str()); - for (Compl p: _positions){myfile<< p.real() << "|" << p.imag() << std::endl;} + myfile.open((filename + ".txt").c_str(), std::ios::out | std::ios::app); + int p_index = 0; + for (Particle p : _particles) { + myfile << component << "|" << p.get_pos().real() << "|" + << p.get_pos().imag() << std::endl; + p_index++; + } myfile.close(); - + } }; +void write_positions(std::vector _positions, std::string filename) { -void BlockVisual::calc_visual(){ - std::string type = "standard"; - if (_file_path_in.find("gml") != std::string::npos) { - type="gml"; - } - Graph big_graph = Graph(type, _file_path_in); - - - LayoutGraph l; - - std::tuple, std::unordered_map, std::vector> components = big_graph.get_components(); - std::vector graphs = std::get<0>(components); - std::unordered_map new_id = std::get<1>(components); - std::vector component_vec = std::get<2>(components); - - std::vector> component_positions; - - for (auto graph: graphs){ - - ClusterGraph CL = ClusterGraph(graph); - Graph g = CL.get_graph(); - if (g.num_vertices()<_settings.max_kamada_kawai_nodes){ - //l.calc_kamada_kawai(g, 10000, 0.0001, 200, 2); - l.calc_kamada_kawai(g, _settings.kk_edge_strength, _settings.kk_thresh, _settings.kk_iterations,_settings.kk_verbosity); - std::vector clustered_layout; - for (auto p: g.get_particles()){ - clustered_layout.push_back(p.get_pos()); - } - component_positions.push_back(clustered_layout); - }else{ - l.calc_fa2(g, _settings.iterations, _settings.terms, _settings.thresh,_settings.edge_force, _settings.gravity, _settings.jitter_tol, _settings.speed, _settings.speed_efficiency, _settings.layout_verbosity); - - //CL.cluster_leaves(); - //CL.cluster_bridges(); - //CL.cluster_central_node(4); - - std::vector clustered_layout; - double mean_edge = 0; - for (auto e: g.get_edges()){ - mean_edge+=std::abs(g.get_particles()[e.source].get_pos()-g.get_particles()[e.target].get_pos()); - } - mean_edge /= g.num_edges(); - for (auto p: g.get_particles()){ - clustered_layout.push_back(p.get_pos()/mean_edge); - } - component_positions.push_back(clustered_layout); - //std::vector decluster_positions = CL.get_unclustered_layout(clustered_layout); - } - - - - } + std::ofstream myfile; + myfile.open((filename + ".txt").c_str()); + for (Compl p : _positions) { + myfile << p.real() << "|" << p.imag() << std::endl; + } + myfile.close(); +}; - component_positions = l.calc_many_components_layout(component_positions, component_positions.size()*15, 250); - std::vector positions; - for (int id=0;id, std::unordered_map, std::vector> + components = big_graph.get_components(); + std::vector graphs = std::get<0>(components); + std::unordered_map new_id = std::get<1>(components); + std::vector component_vec = std::get<2>(components); + + std::vector> component_positions; + + for (auto graph : graphs) { + + ClusterGraph CL = ClusterGraph(graph); + Graph g = CL.get_graph(); + if (g.num_vertices() < _settings.max_kamada_kawai_nodes) { + // l.calc_kamada_kawai(g, 10000, 0.0001, 200, 2); + l.calc_kamada_kawai(g, _settings.kk_edge_strength, _settings.kk_thresh, + _settings.kk_iterations, _settings.kk_verbosity); + std::vector clustered_layout; + for (auto p : g.get_particles()) { + clustered_layout.push_back(p.get_pos()); + } + component_positions.push_back(clustered_layout); + } else { + l.calc_fa2(g, _settings.iterations, _settings.terms, _settings.thresh, + _settings.edge_force, _settings.gravity, _settings.jitter_tol, + _settings.speed, _settings.speed_efficiency, + _settings.layout_verbosity); + + // CL.cluster_leaves(); + // CL.cluster_bridges(); + // CL.cluster_central_node(4); + + std::vector clustered_layout; + double mean_edge = 0; + for (auto e : g.get_edges()) { + mean_edge += std::abs(g.get_particles()[e.source].get_pos() - + g.get_particles()[e.target].get_pos()); + } + mean_edge /= g.num_edges(); + for (auto p : g.get_particles()) { + clustered_layout.push_back(p.get_pos() / mean_edge); + } + component_positions.push_back(clustered_layout); + // std::vector decluster_positions = + // CL.get_unclustered_layout(clustered_layout); } - write_positions(positions, _file_path_out); + } + + component_positions = l.calc_many_components_layout( + component_positions, component_positions.size() * 15, 250); + std::vector positions; + for (int id = 0; id < big_graph.num_vertices(); id++) { + positions.push_back(component_positions[component_vec[id]][new_id[id]]); + } + write_positions(positions, _file_path_out); } - -void BlockVisual::fa2_visual(){ - std::string type = "standard"; - if (_file_path_in.find("gml") != std::string::npos) { - type="gml"; - } - Graph big_graph = Graph(type, _file_path_in); - - - LayoutGraph l; - l.calc_fa2(big_graph, _settings.iterations, _settings.terms, _settings.thresh,_settings.edge_force, _settings.gravity, _settings.jitter_tol, _settings.speed, _settings.speed_efficiency, _settings.layout_verbosity); - std::vector positions; - for (auto p: big_graph.get_particles()){ - positions.push_back(p.get_pos()); - } - write_positions(positions, _file_path_out); - }; +void BlockVisual::fa2_visual() { + std::string type = "standard"; + if (_file_path_in.find("gml") != std::string::npos) { + type = "gml"; + } + Graph big_graph = Graph(type, _file_path_in); + + LayoutGraph l; + l.calc_fa2(big_graph, _settings.iterations, _settings.terms, _settings.thresh, + _settings.edge_force, _settings.gravity, _settings.jitter_tol, + _settings.speed, _settings.speed_efficiency, + _settings.layout_verbosity); + std::vector positions; + for (auto p : big_graph.get_particles()) { + positions.push_back(p.get_pos()); + } + write_positions(positions, _file_path_out); +}; diff --git a/BlockVisualisation/block_visual.h b/BlockVisualisation/block_visual.h index f27693e..0e43acf 100644 --- a/BlockVisualisation/block_visual.h +++ b/BlockVisualisation/block_visual.h @@ -4,53 +4,49 @@ #include "forces.h" -#include -#include -#include #include -#include -#include #include +#include +#include #include +#include +#include +#include -#include #include - +#include struct Settings { - - int componentwise = 0; - int iterations = 100; - double edge_force = 0.04; - double gravity = 0.04; - double jitter_tol =1.0; - double speed = 10.0; - double speed_efficiency = 1.0; - int layout_verbosity=1; - int terms =2; - int thresh =-1; - double kk_edge_strength=1; - double kk_thresh=0.00001; - int kk_iterations=100; - int kk_verbosity=2; - int max_kamada_kawai_nodes = 200; -}; + int componentwise = 0; + int iterations = 100; + double edge_force = 0.04; + double gravity = 0.04; + double jitter_tol = 1.0; + double speed = 10.0; + double speed_efficiency = 1.0; + int layout_verbosity = 1; + int terms = 2; + int thresh = -1; + double kk_edge_strength = 1; + double kk_thresh = 0.00001; + int kk_iterations = 100; + int kk_verbosity = 2; + int max_kamada_kawai_nodes = 200; +}; -class BlockVisual -{ +class BlockVisual { public: - BlockVisual(std::string file_settings); - void calc_visual(); - void fa2_visual(); + BlockVisual(std::string file_settings); + void calc_visual(); + void fa2_visual(); private: - std::string _file_path_in; - std::string _file_path_out; - int _timestamp; - Settings _settings; - + std::string _file_path_in; + std::string _file_path_out; + int _timestamp; + Settings _settings; }; #endif \ No newline at end of file diff --git a/BlockVisualisation/cluster.cpp b/BlockVisualisation/cluster.cpp index f7232aa..dbb495b 100644 --- a/BlockVisualisation/cluster.cpp +++ b/BlockVisualisation/cluster.cpp @@ -1,138 +1,153 @@ #include "cluster.h" #include "quadtree.h" -#include -#include -#include -#include #include -#include -#include #include #include +#include +#include #include +#include #include +#include +#include +#include - - - -void ClusterGraph::cluster_leaves(){ - int id=0; - while ( id<=cluster_nodes.size()){ - - ClusterNode & cl_node = cluster_nodes[id]; - if (cl_node.is_dead() ==false){ - if (cl_node.get_neighours().size()==1){ - cl_node.die(); - cluster_positions.push_back(ClusterPositioner(0, id, cl_node.get_neighours()[0], cl_node.get_neighbors_distances()[0])); - ClusterNode neigh = cluster_nodes[cl_node.get_neighours()[0]]; - cl_node.die(); - neigh.add_neighbour(cl_node.get_representant(), cl_node.get_neighbors_distances()[0]); - } - } - id++; +void ClusterGraph::cluster_leaves() { + int id = 0; + while (id <= cluster_nodes.size()) { + + ClusterNode &cl_node = cluster_nodes[id]; + if (cl_node.is_dead() == false) { + if (cl_node.get_neighours().size() == 1) { + cl_node.die(); + cluster_positions.push_back( + ClusterPositioner(0, id, cl_node.get_neighours()[0], + cl_node.get_neighbors_distances()[0])); + ClusterNode neigh = cluster_nodes[cl_node.get_neighours()[0]]; + cl_node.die(); + neigh.add_neighbour(cl_node.get_representant(), + cl_node.get_neighbors_distances()[0]); + } } + id++; + } } -void ClusterGraph::cluster_bridges(){ - int id=0; - while ( id<=cluster_nodes.size()){ - ClusterNode & cl_node = cluster_nodes[id]; - if (cl_node.is_dead() ==false){ - std::vector neighbors = cl_node.get_neighours(); - if (neighbors.size()==2){ - cl_node.die(); - cluster_positions.push_back(ClusterPositioner(1, id, cl_node.get_neighours()[0], cl_node.get_neighours()[1], cl_node.get_neighbors_distances()[0], cl_node.get_neighbors_distances()[1])); - ClusterNode & neigh1 = cluster_nodes[cl_node.get_neighours()[0]]; - ClusterNode & neigh2 = cluster_nodes[cl_node.get_neighours()[1]]; - neigh1.add_neighbour(neigh2.get_representant(), cl_node.get_neighbors_distances()[0]+cl_node.get_neighbors_distances()[1]); - neigh2.add_neighbour(neigh1.get_representant(), cl_node.get_neighbors_distances()[0]+cl_node.get_neighbors_distances()[1]); - neigh1.remove_neighbour(id); - neigh2.remove_neighbour(id); - } - } - id++; +void ClusterGraph::cluster_bridges() { + int id = 0; + while (id <= cluster_nodes.size()) { + ClusterNode &cl_node = cluster_nodes[id]; + if (cl_node.is_dead() == false) { + std::vector neighbors = cl_node.get_neighours(); + if (neighbors.size() == 2) { + cl_node.die(); + cluster_positions.push_back(ClusterPositioner( + 1, id, cl_node.get_neighours()[0], cl_node.get_neighours()[1], + cl_node.get_neighbors_distances()[0], + cl_node.get_neighbors_distances()[1])); + ClusterNode &neigh1 = cluster_nodes[cl_node.get_neighours()[0]]; + ClusterNode &neigh2 = cluster_nodes[cl_node.get_neighours()[1]]; + neigh1.add_neighbour(neigh2.get_representant(), + cl_node.get_neighbors_distances()[0] + + cl_node.get_neighbors_distances()[1]); + neigh2.add_neighbour(neigh1.get_representant(), + cl_node.get_neighbors_distances()[0] + + cl_node.get_neighbors_distances()[1]); + neigh1.remove_neighbour(id); + neigh2.remove_neighbour(id); + } } + id++; + } } -void ClusterGraph::cluster_central_node(int min_neigh){ - int id=0; - while ( id<=cluster_nodes.size()){ - ClusterNode & central_node = cluster_nodes[id]; - if (central_node.is_dead() ==false){ - std::vector neighbors = central_node.get_neighours(); - if (neighbors.size()>=min_neigh){ - int neigh_number = 0; - for (auto neigh_id: neighbors){ - ClusterNode & neigh = cluster_nodes[neigh_id]; - neigh.die(); - cluster_positions.push_back(ClusterPositioner(2, neigh_id, id, central_node.get_neighbors_distances()[neigh_number])); - central_node.add_to_cluster(neigh, central_node.get_neighbors_distances()[neigh_number]); - neigh_number++; - } - } +void ClusterGraph::cluster_central_node(int min_neigh) { + int id = 0; + while (id <= cluster_nodes.size()) { + ClusterNode ¢ral_node = cluster_nodes[id]; + if (central_node.is_dead() == false) { + std::vector neighbors = central_node.get_neighours(); + if (neighbors.size() >= min_neigh) { + int neigh_number = 0; + for (auto neigh_id : neighbors) { + ClusterNode &neigh = cluster_nodes[neigh_id]; + neigh.die(); + cluster_positions.push_back(ClusterPositioner( + 2, neigh_id, id, + central_node.get_neighbors_distances()[neigh_number])); + central_node.add_to_cluster( + neigh, central_node.get_neighbors_distances()[neigh_number]); + neigh_number++; } - id++; + } } + id++; + } } -Graph ClusterGraph::get_graph(){ - Graph g; - int id=0; - std::unordered_map id_map; - for (int n = 0; n < cluster_nodes.size(); n++){ - if (cluster_nodes[n].is_dead() == false){ - g.add_particle(Particle(cluster_nodes[n].get_pos(), cluster_nodes[n].get_charge(), id), ParticleData()); - id_map[cluster_nodes[n].get_representant()] = id; - id++; - } +Graph ClusterGraph::get_graph() { + Graph g; + int id = 0; + std::unordered_map id_map; + for (int n = 0; n < cluster_nodes.size(); n++) { + if (cluster_nodes[n].is_dead() == false) { + g.add_particle(Particle(cluster_nodes[n].get_pos(), + cluster_nodes[n].get_charge(), id), + ParticleData()); + id_map[cluster_nodes[n].get_representant()] = id; + id++; } - for (auto node: cluster_nodes){ - if (node.is_dead()==false){ - for (int m=0; m ClusterGraph::get_unclustered_layout(std::vector clustered_layout){ - std::unordered_map pos_map; - - Compl center = 0; - for (auto a: clustered_layout){ - center += a; +std::vector +ClusterGraph::get_unclustered_layout(std::vector clustered_layout) { + std::unordered_map pos_map; + + Compl center = 0; + for (auto a : clustered_layout) { + center += a; + } + center = center / Compl(clustered_layout.size(), 0); + + int i = 0; + for (int n = 0; n < cluster_nodes.size(); n++) { + if (cluster_nodes[n].is_dead() == false) { + pos_map[n] = clustered_layout[i]; + i++; + } else { + pos_map[n] = Compl(0, 0); } - center=center/Compl(clustered_layout.size(),0); + } - int i = 0; - for (int n = 0; n < cluster_nodes.size(); n++){ - if (cluster_nodes[n].is_dead() == false){ - pos_map[n]=clustered_layout[i]; - i++; - }else{ - pos_map[n] = Compl(0,0); - } - } + for (std::vector::reverse_iterator i = + cluster_positions.rbegin(); + i != cluster_positions.rend(); ++i) { + pos_map[i->get_id()] = + i->get_position(pos_map, cluster_nodes[i->get_id()].get_neighours()); + } - for (std::vector::reverse_iterator i = cluster_positions.rbegin(); i != cluster_positions.rend(); ++i ) { - pos_map[i->get_id()] = i->get_position(pos_map, cluster_nodes[i->get_id()].get_neighours()); - - } + std::vector res; - std::vector res; + for (i = 0; i < cluster_nodes.size(); i++) { + res.push_back(pos_map[i]); + } - for (i=0;i -#include -#include #include -#include -#include #include +#include +#include #include +#include +#include +#include -#include #include +#include - - -class ClusterNode -{ - public: - ClusterNode(int representant, std::vector neighbors, std::vector neighbors_distances, std::complex< double> repr_pos, double charge){ - _representant=representant; - _neighbors =neighbors; - _neighbors_distances=neighbors_distances; - _node_ids = {representant}; - _pos = repr_pos; - _charge = charge; - }; - std::vector get_neighours(){return _neighbors;} - std::vector get_neighbors_distances(){return _neighbors_distances;} - void add_neighbour(int neighbour_id, int distance){ - if (neighbour_id!= _representant){ - if (std::find(_neighbors.begin(), _neighbors.end(), neighbour_id) == _neighbors.end()) { - _neighbors.push_back(neighbour_id); - _neighbors_distances.push_back(distance); - } - } - } - void remove_neighbour(int id){ - for (int i=0; i<= _neighbors.size(); i++){ - if (_neighbors[i]==id){ - _neighbors.erase(_neighbors.begin() + i); - _neighbors_distances.erase(_neighbors_distances.begin() + i); - - } - } - } - - - int get_representant(){return _representant;} - std::vector get_node_ids(){return _node_ids;} - void add_node_id(int node_id){_node_ids.push_back(node_id);} - bool is_dead(){return _is_dead;} - void die(){ - _is_dead=true; - } - void add_to_cluster(ClusterNode other, int other_distance){ - for (int n: other.get_node_ids()){ - _node_ids.push_back(n); - } - for (int n=0; n neighbors, + std::vector neighbors_distances, + std::complex repr_pos, double charge) { + _representant = representant; + _neighbors = neighbors; + _neighbors_distances = neighbors_distances; + _node_ids = {representant}; + _pos = repr_pos; + _charge = charge; + }; + std::vector get_neighours() { return _neighbors; } + std::vector get_neighbors_distances() { return _neighbors_distances; } + void add_neighbour(int neighbour_id, int distance) { + if (neighbour_id != _representant) { + if (std::find(_neighbors.begin(), _neighbors.end(), neighbour_id) == + _neighbors.end()) { + _neighbors.push_back(neighbour_id); + _neighbors_distances.push_back(distance); + } + } + } + void remove_neighbour(int id) { + for (int i = 0; i <= _neighbors.size(); i++) { + if (_neighbors[i] == id) { + _neighbors.erase(_neighbors.begin() + i); + _neighbors_distances.erase(_neighbors_distances.begin() + i); + } + } + } + + int get_representant() { return _representant; } + std::vector get_node_ids() { return _node_ids; } + void add_node_id(int node_id) { _node_ids.push_back(node_id); } + bool is_dead() { return _is_dead; } + void die() { _is_dead = true; } + void add_to_cluster(ClusterNode other, int other_distance) { + for (int n : other.get_node_ids()) { + _node_ids.push_back(n); + } + for (int n = 0; n < other.get_neighours().size(); n++) { + int id = other.get_neighours()[n]; + if (id != _representant) { + if (std::find(_neighbors.begin(), _neighbors.end(), id) == + _neighbors.end()) { + _neighbors.push_back(id); + _neighbors_distances.push_back(other_distance + + other.get_neighbors_distances()[id]); } - std::complex< double> get_pos(){return _pos;} - double get_charge(){return _charge;} - - private: - bool _is_dead=false; - int _representant; - std::vector _node_ids; - std::vector _neighbors; - std::vector _neighbors_distances; - std::complex< double> _pos; - double _charge; + } + } + } + std::complex get_pos() { return _pos; } + double get_charge() { return _charge; } +private: + bool _is_dead = false; + int _representant; + std::vector _node_ids; + std::vector _neighbors; + std::vector _neighbors_distances; + std::complex _pos; + double _charge; }; +class ClusterPositioner { +public: + // type 0 leaf cluster, 1 bridge, 2 central + ClusterPositioner(int type, int id, int neigh1, double dist1) { + _type = type; + _id = id; + _neigh1 = neigh1; + _distance1 = dist1; + } + ClusterPositioner(int type, int id, int neigh1, int neigh2, double dist1, + double dist2) { + _type = type; + _id = id; + _neigh1 = neigh1; + _neigh2 = neigh2; + _distance1 = dist1; + _distance2 = dist2; + } + int get_id() { return _id; } + Compl get_position(std::unordered_map &pos_map, + std::vector neighbors = {}) { + if (_type == 0) { + // clustered because leaf node + Compl neighpos = pos_map[_neigh1]; + double angle = (double)rand() / RAND_MAX * 360; + return Compl(sin(angle), cos(angle)) * Compl(_distance1, 0) + neighpos; + + } else if (_type == 1) { + // clustered because bridge node + Compl neigh1pos = pos_map[_neigh1]; + Compl neigh2pos = pos_map[_neigh2]; + return neigh1pos + (neigh2pos - neigh1pos) * + Compl(_distance1 / (_distance1 + _distance2), 0); + + } else if (_type == 2) { + // clustered because next to central node + Compl neighpos = pos_map[_neigh1]; + Compl center = 0; + for (auto n : neighbors) { + center += pos_map[n]; + } + if (center == Compl(0, 0) || center == pos_map[_id]) { + Compl neighpos = pos_map[_neigh1]; + double angle = (double)rand() / RAND_MAX * 360; + return Compl(sin(angle), cos(angle)) * Compl(_distance1, 0) + neighpos; + } else { + return center; + } + } + return Compl(0, 0); + } -class ClusterPositioner -{ - public: - //type 0 leaf cluster, 1 bridge, 2 central - ClusterPositioner(int type, int id, int neigh1, double dist1){_type=type; _id=id; _neigh1 = neigh1; _distance1 = dist1;} - ClusterPositioner(int type, int id, int neigh1, int neigh2, double dist1, double dist2){_type=type; _id=id; _neigh1 = neigh1; _neigh2 = neigh2;_distance1 = dist1; _distance2=dist2;} - int get_id(){return _id;} - Compl get_position(std::unordered_map & pos_map, std::vector neighbors = {}){ - if (_type==0){ - // clustered because leaf node - Compl neighpos = pos_map[_neigh1]; - double angle = (double)rand() / RAND_MAX*360; - return Compl(sin(angle), cos(angle))*Compl(_distance1,0)+neighpos; - - } else if (_type==1){ - // clustered because bridge node - Compl neigh1pos = pos_map[_neigh1]; - Compl neigh2pos = pos_map[_neigh2]; - return neigh1pos+(neigh2pos-neigh1pos)*Compl(_distance1/(_distance1+_distance2),0); - - } else if(_type==2) { - // clustered because next to central node - Compl neighpos = pos_map[_neigh1]; - Compl center = 0; - for (auto n: neighbors){ - center += pos_map[n]; - } - if (center==Compl(0,0) || center == pos_map[_id]){ - Compl neighpos = pos_map[_neigh1]; - double angle = (double)rand() / RAND_MAX*360; - return Compl(sin(angle), cos(angle))*Compl(_distance1,0)+neighpos; - } else{ - return center; - } - - } - return Compl(0,0); - } - - private: - int _id; - int _type; - int _neigh1; - int _neigh2; - double _distance1; - double _distance2; +private: + int _id; + int _type; + int _neigh1; + int _neigh2; + double _distance1; + double _distance2; }; - -class ClusterGraph -{ +class ClusterGraph { public: - ClusterGraph(Graph graph){ - std::vector> neighbors(graph.num_vertices()); - for(auto e: graph.get_edges()){ - neighbors[e.source].push_back(e.target); - neighbors[e.target].push_back(e.source); - } - int i = 0; - for (auto particle: graph.get_particles()){ - std::vector distances(neighbors[i].size(), 1.0); - cluster_nodes.push_back(ClusterNode(particle.get_id(), neighbors[i], distances, particle.get_pos(), particle.get_charge())); - i++; - } - }; - - void cluster_leaves(); - void cluster_bridges(); - void cluster_central_node(int min_neigh); - Graph get_graph(); - std::vector get_unclustered_layout(std::vector clustered_layout); + ClusterGraph(Graph graph) { + std::vector> neighbors(graph.num_vertices()); + for (auto e : graph.get_edges()) { + neighbors[e.source].push_back(e.target); + neighbors[e.target].push_back(e.source); + } + int i = 0; + for (auto particle : graph.get_particles()) { + std::vector distances(neighbors[i].size(), 1.0); + cluster_nodes.push_back(ClusterNode(particle.get_id(), neighbors[i], + distances, particle.get_pos(), + particle.get_charge())); + i++; + } + }; + + void cluster_leaves(); + void cluster_bridges(); + void cluster_central_node(int min_neigh); + Graph get_graph(); + std::vector + get_unclustered_layout(std::vector clustered_layout); private: - std::vector cluster_nodes; - std::vector cluster_positions; - + std::vector cluster_nodes; + std::vector cluster_positions; }; - - - #endif diff --git a/BlockVisualisation/forces.h b/BlockVisualisation/forces.h index 341b82e..186b8a4 100644 --- a/BlockVisualisation/forces.h +++ b/BlockVisualisation/forces.h @@ -4,112 +4,120 @@ #include "quadtree.h" -#include -#include -#include #include +#include #include +#include +#include #include -#include - +#include using Compl = std::complex; struct hash_pair { - size_t operator()(std::pair a) - { - return std::hash{}(a.first.imag()) ^ std::hash{}(a.first.real()) ^ std::hash{}(a.second); - } + size_t operator()(std::pair a) { + return std::hash{}(a.first.imag()) ^ + std::hash{}(a.first.real()) ^ std::hash{}(a.second); + } }; -class Forces -{ +class Forces { public: - Forces(){}; - Forces(const std::vector>& particles); - Forces(const std::vector& particles); - - - void reset(const std::vector& particles){ - _binom_map.clear(); - _particles.clear(); - _particles=particles; - _forces.clear(); - _forces = std::vector (_particles.size(), Compl(0,0)); - _tree.reset(_particles); + Forces(){}; + Forces(const std::vector> &particles); + Forces(const std::vector &particles); + + void reset(const std::vector &particles) { + _binom_map.clear(); + _particles.clear(); + _particles = particles; + _forces.clear(); + _forces = std::vector(_particles.size(), Compl(0, 0)); + _tree.reset(_particles); + } + + void calc_ffm_forces(int terms = 3, int thresh = 10, int const node_id = 0, + double strength = .5); + + void calc_gravity_forces(double gravity) { + // centers around 0 + for (Particle p : _particles) { + double dist = std::abs(p.get_pos()); + if (dist > 0.0001) { + _forces[p.get_id()] -= + gravity * p.get_pos() * p.get_charge() / std::sqrt(dist); + } + } + }; + + void calc_gravity_forces2(double gravity) { + // centers around 0 + for (Particle p : _particles) { + double dist = std::abs(p.get_pos()); + if (dist > 0.0001) { + _forces[p.get_id()] -= gravity * p.get_pos() * p.get_charge(); + } + } + }; + + void calc_edge_forces(double edge_factor, const std::vector &edges, + std::vector degree) { + for (auto edge : edges) { + double distance = std::max(std::abs(_particles[edge.source].get_pos() - + _particles[edge.target].get_pos()), + 0.0001); + double opt_edge_length = 1; + Compl force = double(degree[edge.source] + 1) * + double(degree[edge.target] + 1) * Compl(edge_factor, 0) * + (_particles[edge.source].get_pos() - + _particles[edge.target].get_pos()) * + (1.0 - distance) / distance; + _forces[edge.source] += force; + _forces[edge.target] -= force; } - - void calc_ffm_forces(int terms=3, int thresh=10, int const node_id=0, double strength=.5); - - void calc_gravity_forces(double gravity){ - // centers around 0 - for (Particle p: _particles){ - double dist = std::abs(p.get_pos()); - if(dist>0.0001){ - _forces[p.get_id()]-=gravity*p.get_pos()*p.get_charge()/std::sqrt(dist); - } - } - }; - - void calc_gravity_forces2(double gravity){ - // centers around 0 - for (Particle p: _particles){ - double dist = std::abs(p.get_pos()); - if(dist>0.0001){ - _forces[p.get_id()]-=gravity*p.get_pos()*p.get_charge(); - } - } - }; - - void calc_edge_forces(double edge_factor, const std::vector& edges, std::vector degree){ - for (auto edge: edges){ - double distance = std::max(std::abs(_particles[edge.source].get_pos()-_particles[edge.target].get_pos()), 0.0001); - double opt_edge_length = 1; - Compl force = double(degree[edge.source]+1)*double(degree[edge.target]+1)*Compl(edge_factor,0)*(_particles[edge.source].get_pos()-_particles[edge.target].get_pos())*(1.0-distance)/distance; - _forces[edge.source] += force; - _forces[edge.target] -= force; - } - }; - - void calc_edge_forces_2(double edge_factor, const std::vector& edges){ - for (auto edge: edges){ - double distance = std::max(std::abs(_particles[edge.source].get_pos()-_particles[edge.target].get_pos()), 0.0001); - double opt_edge_length = 1; - Compl force = Compl(edge_factor,0)*(_particles[edge.source].get_pos()-_particles[edge.target].get_pos())*(1.0-distance)/distance; - _forces[edge.source] += force; - _forces[edge.target] -= force; - } - }; - - void update(std::vector& new_parts){ - - _particles = new_parts; - _forces = std::vector (_particles.size(), Compl(0,0)); - _tree = QuadTree(_particles); + }; + + void calc_edge_forces_2(double edge_factor, const std::vector &edges) { + for (auto edge : edges) { + double distance = std::max(std::abs(_particles[edge.source].get_pos() - + _particles[edge.target].get_pos()), + 0.0001); + double opt_edge_length = 1; + Compl force = Compl(edge_factor, 0) * + (_particles[edge.source].get_pos() - + _particles[edge.target].get_pos()) * + (1.0 - distance) / distance; + _forces[edge.source] += force; + _forces[edge.target] -= force; } + }; - std::vector get_forces(){return _forces;}; + void update(std::vector &new_parts) { + _particles = new_parts; + _forces = std::vector(_particles.size(), Compl(0, 0)); + _tree = QuadTree(_particles); + } + + std::vector get_forces() { return _forces; }; private: - void precomputations(); - void split(int const id); - void calc_outgoing(); - void calc_incoming(); - - void calc_outgoing_coef(int const id); - void calc_incoming_coef(int const id); - - int _terms = 0; - int _thresh = 0; - std::vector _forces; - std::vector _particles; - QuadTree _tree; - - std::unordered_map, Compl> _binom_map; -}; + void precomputations(); + void split(int const id); + void calc_outgoing(); + void calc_incoming(); + void calc_outgoing_coef(int const id); + void calc_incoming_coef(int const id); + int _terms = 0; + int _thresh = 0; + std::vector _forces; + std::vector _particles; + QuadTree _tree; + + std::unordered_map, Compl> _binom_map; +}; #endif \ No newline at end of file diff --git a/BlockVisualisation/graph.h b/BlockVisualisation/graph.h index 1e3b9d4..7a38f45 100644 --- a/BlockVisualisation/graph.h +++ b/BlockVisualisation/graph.h @@ -2,322 +2,335 @@ #ifndef GRAPH_H #define GRAPH_H - -#include -#include -#include #include -#include -#include #include -#include +#include +#include #include -#include +#include #include #include - +#include +#include +#include +#include struct ParticleData { - bool type; //true for address, false for transactions - int timestamp = 0; - std::string label; - std::string address = "NONE"; - std::string txid = "NONE"; + bool type; // true for address, false for transactions + int timestamp = 0; + std::string label; + std::string address = "NONE"; + std::string txid = "NONE"; }; struct Edge { - int source; - int target; - std::string type; - double value; - double length = 1.0; + int source; + int target; + std::string type; + double value; + double length = 1.0; }; - -class Particle -{ +class Particle { public: - Particle(std::complex pos, double charge, int id): _pos(pos), _charge(charge), _id(id){} + Particle(std::complex pos, double charge, int id) + : _pos(pos), _charge(charge), _id(id) {} - double const get_charge() const {return _charge;} - const std::complex& get_pos() const {return _pos;} - int const get_id () const {return _id;} - void set_id (int id) {_id=id;} - bool operator==(const Particle& rhs)const {return _id == rhs.get_id(); } + double const get_charge() const { return _charge; } + const std::complex &get_pos() const { return _pos; } + int const get_id() const { return _id; } + void set_id(int id) { _id = id; } + bool operator==(const Particle &rhs) const { return _id == rhs.get_id(); } - void add_pos (std::complex< double> _add) {_pos += _add;} - void mul_pos (std::complex< double> _add) {_pos *= _add;} + void add_pos(std::complex _add) { _pos += _add; } + void mul_pos(std::complex _add) { _pos *= _add; } private: - std::complex< double> _pos; - double _charge; - int _id; + std::complex _pos; + double _charge; + int _id; }; -class Graph -{ +class Graph { public: - - Graph(){}; - - Graph(std::vector particles, std::vector particle_data, std::vector edges){ - _particles=particles; - _particle_data = particle_data; - _edges=edges; - } - - Graph(std::string file_type, std::string file_path){ - std::cout<<"Reading file "<((double)rand() / RAND_MAX,(double)rand() / RAND_MAX), 1, i)); - _particle_data.push_back(ParticleData()); - } - while (std::getline(infile, str)){ - int slash_index = str.find(" "); - Edge edge; - edge.source = std::stoi(str.substr(0, slash_index)); - edge.target = std::stoi(str.substr(slash_index + 1, str.length())); - _edges.push_back(edge); - } - } else if (file_type == "gml"){ - // reads gml file into grpah format - std::ifstream infile(file_path.c_str()); - std::string str; - std::getline(infile, str); - int reading_node_edge = 0; - ParticleData particle_data; - Edge edge; - int id_counter = 0; - std::map id_map; - - while (std::getline(infile, str)){ - if (str == " node ["){ - reading_node_edge=1; - id_counter += 1; - } else if (str == " edge ["){ - reading_node_edge=2; - } - if (reading_node_edge==1){ - if (str.substr(0, 9)==" label"){ - particle_data.label = str.substr(10, str.size()); - } else if (str.substr(0, 7)==" id "){ - id_map[std::stoi(str.substr(7, str.size()))] = _particles.size(); - }else if (str.substr(0, 9)==" txid "){ - particle_data.txid = str.substr(9, str.size()); - particle_data.type = false; - } else if (str.substr(0, 12)==" address "){ - particle_data.address = str.substr(12, str.size()); - particle_data.type = true; - } else if (str.substr(0, 14)==" timestamp "){ - particle_data.timestamp = std::stoi(str.substr(14, str.size())); - } else if (str == " ]"){ - reading_node_edge=0; - _particle_data.push_back(particle_data); - _particles.emplace_back(Particle(std::complex((double)rand() / RAND_MAX,(double)rand() / RAND_MAX), 1, _particles.size())); - particle_data = ParticleData(); - } - } else if (reading_node_edge==2){ - - if (str.substr(0, 11)==" source "){ - edge.source = std::stoi(str.substr(10, str.size())); - } else if (str.substr(0, 11)==" target "){ - edge.target = std::stoi(str.substr(10, str.size())); - } else if (str.substr(0, 9)==" type "){ - edge.type = str.substr(9, str.size()); - } else if (str.substr(0, 10)==" value "){ - edge.value = std::stod(str.substr(10, str.size())); - } else if (str == " ]"){ - try{ - reading_node_edge=0; - _edges.push_back(edge); - edge = Edge(); - }catch (const std::out_of_range& ex) {} - } - } + Graph(){}; + + Graph(std::vector particles, + std::vector particle_data, std::vector edges) { + _particles = particles; + _particle_data = particle_data; + _edges = edges; + } + + Graph(std::string file_type, std::string file_path) { + std::cout << "Reading file " << file_path << ".\n"; + if (file_type == "standard") { + // reads file. first line is int with number of nodes and then each line + // has two ints the endpoints of an edge + std::ifstream infile(file_path.c_str()); + std::string str; + std::getline(infile, str); + int id_number = std::stoi(str); + for (int i = 0; i < id_number; i++) { + _particles.emplace_back( + Particle(std::complex((double)rand() / RAND_MAX, + (double)rand() / RAND_MAX), + 1, i)); + _particle_data.push_back(ParticleData()); + } + while (std::getline(infile, str)) { + int slash_index = str.find(" "); + Edge edge; + edge.source = std::stoi(str.substr(0, slash_index)); + edge.target = std::stoi(str.substr(slash_index + 1, str.length())); + _edges.push_back(edge); + } + } else if (file_type == "gml") { + // reads gml file into grpah format + std::ifstream infile(file_path.c_str()); + std::string str; + std::getline(infile, str); + int reading_node_edge = 0; + ParticleData particle_data; + Edge edge; + int id_counter = 0; + std::map id_map; + + while (std::getline(infile, str)) { + if (str == " node [") { + reading_node_edge = 1; + id_counter += 1; + } else if (str == " edge [") { + reading_node_edge = 2; + } + if (reading_node_edge == 1) { + if (str.substr(0, 9) == " label") { + particle_data.label = str.substr(10, str.size()); + } else if (str.substr(0, 7) == " id ") { + id_map[std::stoi(str.substr(7, str.size()))] = _particles.size(); + } else if (str.substr(0, 9) == " txid ") { + particle_data.txid = str.substr(9, str.size()); + particle_data.type = false; + } else if (str.substr(0, 12) == " address ") { + particle_data.address = str.substr(12, str.size()); + particle_data.type = true; + } else if (str.substr(0, 14) == " timestamp ") { + particle_data.timestamp = std::stoi(str.substr(14, str.size())); + } else if (str == " ]") { + reading_node_edge = 0; + _particle_data.push_back(particle_data); + _particles.emplace_back( + Particle(std::complex((double)rand() / RAND_MAX, + (double)rand() / RAND_MAX), + 1, _particles.size())); + particle_data = ParticleData(); + } + } else if (reading_node_edge == 2) { + + if (str.substr(0, 11) == " source ") { + edge.source = std::stoi(str.substr(10, str.size())); + } else if (str.substr(0, 11) == " target ") { + edge.target = std::stoi(str.substr(10, str.size())); + } else if (str.substr(0, 9) == " type ") { + edge.type = str.substr(9, str.size()); + } else if (str.substr(0, 10) == " value ") { + edge.value = std::stod(str.substr(10, str.size())); + } else if (str == " ]") { + try { + reading_node_edge = 0; + _edges.push_back(edge); + edge = Edge(); + } catch (const std::out_of_range &ex) { } - } else { - std::cout << " Graph init recieved bad file format, valid formats are: standard, gml"; + } } + } + } else { + std::cout << " Graph init recieved bad file format, valid formats are: " + "standard, gml"; } + } - int num_edges(){ - return _edges.size(); - } + int num_edges() { return _edges.size(); } - int num_vertices(){ - return _particles.size(); - } + int num_vertices() { return _particles.size(); } - void add_particle(Particle p, ParticleData pd){ - _particles.push_back(p); - _particle_data.push_back(pd); - } + void add_particle(Particle p, ParticleData pd) { + _particles.push_back(p); + _particle_data.push_back(pd); + } - void add_edge(Edge e){ - _edges.push_back(e); - } + void add_edge(Edge e) { _edges.push_back(e); } - std::vector> floyd_warschall(){ + std::vector> floyd_warschall() { - std::vector> distances(_particles.size(), std::vector(_particles.size(), std::numeric_limits::max())); + std::vector> distances( + _particles.size(), + std::vector(_particles.size(), + std::numeric_limits::max())); - // init distances matrix with zeros for nodes to itself and edge length from nodes to neighbours - for (int id = 0; id < _particles.size(); id++) { - distances[id][id] = 0; - } - for (auto e: _edges){ - distances[e.source][e.target] = e.length; - distances[e.target][e.source] = e.length; - } + // init distances matrix with zeros for nodes to itself and edge length from + // nodes to neighbours + for (int id = 0; id < _particles.size(); id++) { + distances[id][id] = 0; + } + for (auto e : _edges) { + distances[e.source][e.target] = e.length; + distances[e.target][e.source] = e.length; + } - // floyd warshall - for (int k = 0; k < _particles.size(); k++) { - for (int i = 0; i < _particles.size(); i++) { - for (int j = 0; j < _particles.size(); j++) { - if (distances[i][k] > 0 && distances[k][j] > std::numeric_limits::max() - distances[i][k]) { - distances[i][j] = std::min(distances[i][j], std::numeric_limits::max()); - } else{ - distances[i][j] = std::min(distances[i][j], distances[i][k] + distances[k][j]); - } - } - } + // floyd warshall + for (int k = 0; k < _particles.size(); k++) { + for (int i = 0; i < _particles.size(); i++) { + for (int j = 0; j < _particles.size(); j++) { + if (distances[i][k] > 0 && + distances[k][j] > + std::numeric_limits::max() - distances[i][k]) { + distances[i][j] = + std::min(distances[i][j], std::numeric_limits::max()); + } else { + distances[i][j] = + std::min(distances[i][j], distances[i][k] + distances[k][j]); + } } - - return distances; - + } } - std::tuple, std::unordered_map, std::vector> get_components(){ - - std::vector> neighbours(_particles.size()); + return distances; + } - std::vector parent_vec; - for (int i=0;i<_particles.size(); i++){ - parent_vec.push_back(-1); - } + std::tuple, std::unordered_map, std::vector> + get_components() { - for(auto e: _edges){ - neighbours[e.source].push_back(e.target); - neighbours[e.target].push_back(e.source); - } + std::vector> neighbours(_particles.size()); - class get - { - public: - static void get_neighbours(int node, int val, std::vector>& neighbours, std::vector& parent_vec) { - if (parent_vec[node]== -1){ - parent_vec[node] = val; - for (auto n: neighbours[node]){ - get_neighbours(n, val, neighbours, parent_vec); - } - } - } - }; + std::vector parent_vec; + for (int i = 0; i < _particles.size(); i++) { + parent_vec.push_back(-1); + } - for (int i=0;i<_particles.size(); i++){ - get::get_neighbours(i, i, neighbours, parent_vec); - } + for (auto e : _edges) { + neighbours[e.source].push_back(e.target); + neighbours[e.target].push_back(e.source); + } - int num_components = std::set( parent_vec.begin(), parent_vec.end() ).size(); - //for (auto i: parent_vec) std::cout << i << ' '; - std::unordered_map _components; - std::unordered_map _new_id; - std::unordered_map graph_number; - int counter=0; - for (int i: std::set( parent_vec.begin(), parent_vec.end() )){ - _components[i] = Graph(); - graph_number[i]=counter; - counter++; - } - for (int i=0;i> &neighbours, + std::vector &parent_vec) { + if (parent_vec[node] == -1) { + parent_vec[node] = val; + for (auto n : neighbours[node]) { + get_neighbours(n, val, neighbours, parent_vec); + } } + } + }; - auto value_selector = [](auto pair){return pair.second;}; - //std::vector components(_components.size()); - //std::transform(_components.begin(), _components.end(), components.begin(), value_selector); - std::vector components; - std::set unique_parent_vec; - for (auto p: parent_vec){ - if(unique_parent_vec.find(p) == unique_parent_vec.end()){ - components.push_back(_components[p]); - unique_parent_vec.insert(p); - } - } - - std::vector component_nr; - for (int i=0;i, std::unordered_map, std::vector> (components, _new_id, component_nr); + int num_components = + std::set(parent_vec.begin(), parent_vec.end()).size(); + // for (auto i: parent_vec) std::cout << i << ' '; + std::unordered_map _components; + std::unordered_map _new_id; + std::unordered_map graph_number; + int counter = 0; + for (int i : std::set(parent_vec.begin(), parent_vec.end())) { + _components[i] = Graph(); + graph_number[i] = counter; + counter++; + } + for (int i = 0; i < parent_vec.size(); i++) { + int new_id = _components[parent_vec[i]].num_vertices(); + _components[parent_vec[i]].add_particle( + Particle(_particles[i].get_pos(), _particles[i].get_charge(), new_id), + _particle_data[i]); + _new_id[i] = new_id; + } + for (auto e : _edges) { + int component = parent_vec[e.source]; + e.source = _new_id[e.source]; + e.target = _new_id[e.target]; + _components[component].add_edge(e); } - std::set get_timestampset(){ - std::set timestamps; - for (auto p:_particle_data){ - if (p.timestamp != 0){ - timestamps.insert(p.timestamp); - } - } - return timestamps; + auto value_selector = [](auto pair) { return pair.second; }; + // std::vector components(_components.size()); + // std::transform(_components.begin(), _components.end(), + // components.begin(), value_selector); + std::vector components; + std::set unique_parent_vec; + for (auto p : parent_vec) { + if (unique_parent_vec.find(p) == unique_parent_vec.end()) { + components.push_back(_components[p]); + unique_parent_vec.insert(p); + } } - Graph timestamp_subgraph(int timestamp){ - - std::vector part_mask(_particles.size(), false); - std::vector edge_mask(_edges.size(),false); - for (int i=0;i<_edges.size(); i++){ - if (_particle_data[_edges[i].source].timestamp==timestamp || - _particle_data[_edges[i].target].timestamp==timestamp){ - edge_mask[i]=true; - part_mask[_edges[i].source] = true; - part_mask[_edges[i].target] = true; - } - } - Graph subgraph = Graph(); - std::unordered_map _new_id; - for (int i=0;i<_particles.size();i++){ - if (part_mask[i]){ - int new_id = subgraph.num_vertices(); - subgraph.add_particle(Particle(_particles[i].get_pos(), _particles[i].get_charge(),new_id), _particle_data[i]); - _new_id[i] = new_id; - } - } - for (int i=0;i<_edges.size();i++){ - if(edge_mask[i]){ - _edges[i].source = _new_id[_edges[i].source]; - _edges[i].target = _new_id[_edges[i].target]; - subgraph.add_edge(_edges[i]); - } - } - return subgraph; + std::vector component_nr; + for (int i = 0; i < parent_vec.size(); i++) { + component_nr.push_back(graph_number[parent_vec[i]]); } + return std::tuple, std::unordered_map, + std::vector>(components, _new_id, component_nr); + } + + std::set get_timestampset() { + std::set timestamps; + for (auto p : _particle_data) { + if (p.timestamp != 0) { + timestamps.insert(p.timestamp); + } + } + return timestamps; + } + + Graph timestamp_subgraph(int timestamp) { + + std::vector part_mask(_particles.size(), false); + std::vector edge_mask(_edges.size(), false); + for (int i = 0; i < _edges.size(); i++) { + if (_particle_data[_edges[i].source].timestamp == timestamp || + _particle_data[_edges[i].target].timestamp == timestamp) { + edge_mask[i] = true; + part_mask[_edges[i].source] = true; + part_mask[_edges[i].target] = true; + } + } + Graph subgraph = Graph(); + std::unordered_map _new_id; + for (int i = 0; i < _particles.size(); i++) { + if (part_mask[i]) { + int new_id = subgraph.num_vertices(); + subgraph.add_particle(Particle(_particles[i].get_pos(), + _particles[i].get_charge(), new_id), + _particle_data[i]); + _new_id[i] = new_id; + } + } + for (int i = 0; i < _edges.size(); i++) { + if (edge_mask[i]) { + _edges[i].source = _new_id[_edges[i].source]; + _edges[i].target = _new_id[_edges[i].target]; + subgraph.add_edge(_edges[i]); + } + } + return subgraph; + } - std::vector& get_particles(){ return _particles;} - std::vector& get_particle_data(){ return _particle_data;} - std::vector& get_edges(){ return _edges;} + std::vector &get_particles() { return _particles; } + std::vector &get_particle_data() { return _particle_data; } + std::vector &get_edges() { return _edges; } private: - std::vector _particles = {}; - std::vector _particle_data = {}; - std::vector _edges; + std::vector _particles = {}; + std::vector _particle_data = {}; + std::vector _edges; }; - #endif \ No newline at end of file diff --git a/BlockVisualisation/layout.cpp b/BlockVisualisation/layout.cpp index 16ab4ac..aecec6d 100644 --- a/BlockVisualisation/layout.cpp +++ b/BlockVisualisation/layout.cpp @@ -1,386 +1,440 @@ #include "layout.h" #include "quadtree.h" -#include -#include -#include -#include #include -#include -#include #include #include +#include +#include #include +#include #include +#include +#include +#include using Compl = std::complex; -LayoutGraph::LayoutGraph(){ -}; - +LayoutGraph::LayoutGraph(){}; -bool is_normal(Compl a){ - return std::isnormal(a.real())&&std::isnormal(a.imag()); +bool is_normal(Compl a) { + return std::isnormal(a.real()) && std::isnormal(a.imag()); } -void LayoutGraph::calc_kamada_kawai(Graph& graph, double edge_strength, double thresh, int maxIter, int verbosity){ - - - if (graph.get_particles().size()==1){ - return; +void LayoutGraph::calc_kamada_kawai(Graph &graph, double edge_strength, + double thresh, int maxIter, int verbosity) { + + if (graph.get_particles().size() == 1) { + return; + } + + // initial rescaling so average edge size is correct. + double distance = 0; + + for (auto e : graph.get_edges()) { + distance += std::abs(graph.get_particles()[e.source].get_pos() - + graph.get_particles()[e.target].get_pos()); + } + double rescale = graph.get_edges().size() / (distance * 1.2); + + std::vector &_particles = graph.get_particles(); + for (auto p : _particles) { + p.mul_pos(rescale); + } + + if (verbosity >= 2) { + std::cout << "Calculating kamada kawai layout for graph with " + << graph.num_vertices() << " vertices: \n"; + } + + // distances matrix + std::vector> distances = graph.floyd_warschall(); + double biggest_distance = 0; + for (int i = 0; i < graph.num_vertices(); i++) { + int m = *std::max_element(distances[i].begin(), distances[i].end()); + if (m > biggest_distance) { + biggest_distance = m; } - - //initial rescaling so average edge size is correct. - double distance = 0; - - for (auto e: graph.get_edges()){ - distance += std::abs(graph.get_particles()[e.source].get_pos()-graph.get_particles()[e.target].get_pos()); + } + + // "radius"=1 + double edge_target_length = 1.0; + + // length matrix, with edge length times shortest path + std::vector> length_mat( + graph.num_vertices(), std::vector(graph.num_vertices())); + for (int i = 0; i < graph.num_vertices(); i++) { + for (int j = i; j < graph.num_vertices(); j++) { + if (i == j) { + length_mat[i][j] = 0.0; + } else { + length_mat[i][j] = distances[i][j] * edge_target_length; + length_mat[j][i] = length_mat[i][j]; + } } - double rescale = graph.get_edges().size()/(distance*1.2); - - - std::vector& _particles = graph.get_particles(); - for (auto p: _particles){ - p.mul_pos(rescale); + } + + // spring matrix, with spring constants times shortest path + std::vector> spring_mat( + graph.num_vertices(), std::vector(graph.num_vertices())); + for (int i = 0; i < graph.num_vertices(); i++) { + for (int j = i; j < graph.num_vertices(); j++) { + if (i == j) { + spring_mat[i][j] = 0.0; + } else { + spring_mat[i][j] = edge_strength / (distances[i][j] * distances[i][j]); + spring_mat[j][i] = spring_mat[i][j]; + } + } + } + + // energy matrix, with energy between each pair of nodes. these are complex + // numbers for energy from x direction and y direction + std::vector>> energy_mat( + graph.num_vertices(), + std::vector>(graph.num_vertices())); + std::vector> energy_mat_sums(graph.num_vertices(), + std::complex(0, 0)); + for (int i = 0; i < graph.num_vertices(); i++) { + for (int j = i; j < graph.num_vertices(); j++) { + if (i == j) { + energy_mat[i][j] = 0.0; + } else { + std::complex diff = + _particles[i].get_pos() - _particles[j].get_pos(); + double E_dx = spring_mat[i][j] * (diff.real()) * + (1 - length_mat[i][j] / (std::abs(diff))); + double E_dy = spring_mat[i][j] * (diff.imag()) * + (1 - length_mat[i][j] / (std::abs(diff))); + energy_mat[i][j] = std::complex(E_dx, E_dy); + energy_mat[j][i] = std::complex(-E_dx, -E_dy); + energy_mat_sums[i] += energy_mat[i][j]; + energy_mat_sums[j] += energy_mat[j][i]; + } + } + } + std::complex biggest_energy = + (std::numeric_limits::max(), std::numeric_limits::max()); + int biggest_energy_id = 0; + int iterations = 0; + double verbose_step = 0.01; + while (thresh < abs(biggest_energy) && iterations < maxIter) { + if (double(iterations) / double(maxIter) > verbose_step && verbosity >= 1) { + std::cout << "\b\b\b\b" << verbose_step * 100 << "%"; + verbose_step += 0.01; } - if (verbosity>=2) {std::cout << "Calculating kamada kawai layout for graph with "<> distances = graph.floyd_warschall(); - double biggest_distance = 0; + // find node with highest energy + biggest_energy = (0, 0); for (int i = 0; i < graph.num_vertices(); i++) { - int m = *std::max_element(distances[i].begin(), distances[i].end()); - if (m > biggest_distance) { - biggest_distance = m; - } + if (abs(energy_mat_sums[i]) > abs(biggest_energy)) { + biggest_energy = energy_mat_sums[i]; + biggest_energy_id = i; + } } + // move node to better energy position + double E_dx = biggest_energy.real(); + double E_dy = biggest_energy.imag(); + double E_d2x = 0; + double E_d2y = 0; + double E_dxdy = 0; - // "radius"=1 - double edge_target_length = 1.0; - - //length matrix, with edge length times shortest path - std::vector> length_mat (graph.num_vertices(), std::vector(graph.num_vertices())); - for (int i = 0; i < graph.num_vertices(); i ++) { - for (int j = i; j < graph.num_vertices(); j++) { - if (i == j) { - length_mat[i][j] = 0.0; - } else { - length_mat[i][j] = distances[i][j]*edge_target_length; - length_mat[j][i] = length_mat[i][j]; - } - } + for (int i = 0; i < graph.num_vertices(); i++) { + if (i != biggest_energy_id) { + std::complex diff = + _particles[biggest_energy_id].get_pos() - _particles[i].get_pos(); + double denom = 0.001 + pow(std::abs(diff), 3); + + double del_E_d2x = spring_mat[biggest_energy_id][i] * + (1 - length_mat[biggest_energy_id][i] * + pow(diff.imag(), 2) / denom); + double del_E_d2y = spring_mat[biggest_energy_id][i] * + (1 - length_mat[biggest_energy_id][i] * + pow(diff.real(), 2) / denom); + double del_E_dxdy = spring_mat[biggest_energy_id][i] * + length_mat[biggest_energy_id][i] * diff.real() * + diff.imag() / denom; + + E_d2x += del_E_d2x; + E_d2y += del_E_d2y; + E_dxdy += del_E_dxdy; + } } - - //spring matrix, with spring constants times shortest path - std::vector> spring_mat (graph.num_vertices(), std::vector(graph.num_vertices())); - for (int i = 0; i < graph.num_vertices(); i ++) { - for (int j = i; j < graph.num_vertices(); j++) { - if (i == j) { - spring_mat[i][j] = 0.0; - } else { - spring_mat[i][j] = edge_strength/(distances[i][j]*distances[i][j]); - spring_mat[j][i] = spring_mat[i][j]; - } - } + double denom = E_d2x * E_d2y - E_dxdy * E_dxdy; + double dx = (E_dxdy * E_dy - E_d2y * E_dx) / denom; + double dy = (E_dxdy * E_dx - E_d2x * E_dy) / denom; + + _particles[biggest_energy_id].add_pos(std::complex(dx, dy)); + + // update energy matrix + for (int j = 0; j < graph.num_vertices(); j++) { + if (biggest_energy_id == j) { + energy_mat[biggest_energy_id][j] = 0.0; + } else { + energy_mat_sums[biggest_energy_id] -= energy_mat[biggest_energy_id][j]; + energy_mat_sums[j] -= energy_mat[j][biggest_energy_id]; + std::complex diff = + _particles[biggest_energy_id].get_pos() - _particles[j].get_pos(); + double E_dx = spring_mat[biggest_energy_id][j] * (diff.real()) * + (1 - length_mat[biggest_energy_id][j] / (std::abs(diff))); + double E_dy = spring_mat[biggest_energy_id][j] * (diff.imag()) * + (1 - length_mat[biggest_energy_id][j] / (std::abs(diff))); + energy_mat[biggest_energy_id][j] = std::complex(E_dx, E_dy); + energy_mat[j][biggest_energy_id] = std::complex(-E_dx, -E_dy); + energy_mat_sums[biggest_energy_id] += energy_mat[biggest_energy_id][j]; + energy_mat_sums[j] += energy_mat[j][biggest_energy_id]; + } } + } + if (verbosity >= 1) { + std::cout << "\b\b\b\b100" + << "%\n"; + } +} - // energy matrix, with energy between each pair of nodes. these are complex numbers for energy from x direction and y direction - std::vector>> energy_mat (graph.num_vertices(), std::vector>(graph.num_vertices())); - std::vector> energy_mat_sums (graph.num_vertices(), std::complex(0,0)); - for (int i = 0; i < graph.num_vertices(); i ++) { - for (int j = i; j < graph.num_vertices(); j++) { - if (i == j) { - energy_mat[i][j] = 0.0; - } else { - std::complex diff = _particles[i].get_pos()-_particles[j].get_pos(); - double E_dx = spring_mat[i][j]*(diff.real())*(1-length_mat[i][j]/(std::abs(diff))); - double E_dy = spring_mat[i][j]*(diff.imag())*(1-length_mat[i][j]/(std::abs(diff))); - energy_mat[i][j] = std::complex(E_dx, E_dy); - energy_mat[j][i] = std::complex(-E_dx, -E_dy); - energy_mat_sums[i]+=energy_mat[i][j]; - energy_mat_sums[j]+=energy_mat[j][i]; - } - } +void LayoutGraph::calc_fa2(Graph &graph, int iterations, int _terms, + int _thresh, double _edge_force, double _gravity, + double _jitter_tol, double _speed, + double _speed_efficiency, int verbosity) { + + std::vector &_particles = graph.get_particles(); + + double speed = _speed; + double speed_efficiency = _speed_efficiency; + std::vector old_forces; + if (verbosity >= 2) { + std::cout << "Calculating fa2 layout for graph with " + << graph.num_vertices() << " vertices: \n"; + } + if (_thresh = -1) + _thresh = std::max(1, int(std::log10(graph.num_vertices()))); + double verbose_step = 0.01; + std::vector degrees(graph.num_vertices(), 0); + for (auto e : graph.get_edges()) { + degrees[e.source] += 1; + degrees[e.target] += 1; + } + Forces _ffm = Forces(_particles); + for (int i = 0; i < iterations; ++i) { + if (double(i) / double(iterations) > verbose_step && verbosity >= 1) { + std::cout << "\b\b\b\b" << verbose_step * 100 << "%"; + verbose_step += 0.01; } - std::complex biggest_energy = (std::numeric_limits::max(), std::numeric_limits::max()); - int biggest_energy_id = 0; - int iterations = 0; - double verbose_step = 0.01; - while (threshverbose_step && verbosity>=1){std::cout<<"\b\b\b\b"< abs(biggest_energy)) { - biggest_energy = energy_mat_sums[i]; - biggest_energy_id = i; - } - } - //move node to better energy position - double E_dx = biggest_energy.real(); - double E_dy = biggest_energy.imag(); - double E_d2x = 0; - double E_d2y = 0; - double E_dxdy = 0; - - - for (int i = 0; i< graph.num_vertices(); i++){ - if (i!=biggest_energy_id){ - std::complex diff = _particles[biggest_energy_id].get_pos() - _particles[i].get_pos(); - double denom = 0.001+pow(std::abs(diff), 3); - - double del_E_d2x = spring_mat[biggest_energy_id][i] * (1 - length_mat[biggest_energy_id][i] * pow(diff.imag(),2) / denom); - double del_E_d2y = spring_mat[biggest_energy_id][i] * (1 - length_mat[biggest_energy_id][i] * pow(diff.real(),2) / denom); - double del_E_dxdy = spring_mat[biggest_energy_id][i] * length_mat[biggest_energy_id][i] * diff.real()*diff.imag()/denom; - - E_d2x += del_E_d2x; - E_d2y += del_E_d2y; - E_dxdy += del_E_dxdy; - } - } - double denom = E_d2x*E_d2y-E_dxdy*E_dxdy; - double dx = (E_dxdy*E_dy - E_d2y*E_dx)/denom; - double dy = (E_dxdy*E_dx - E_d2x*E_dy)/denom; - - _particles[biggest_energy_id].add_pos(std::complex(dx, dy)); - - //update energy matrix - for (int j = 0; j < graph.num_vertices(); j++) { - if (biggest_energy_id == j) { - energy_mat[biggest_energy_id][j] = 0.0; - } else { - energy_mat_sums[biggest_energy_id]-=energy_mat[biggest_energy_id][j]; - energy_mat_sums[j]-=energy_mat[j][biggest_energy_id]; - std::complex diff = _particles[biggest_energy_id].get_pos()-_particles[j].get_pos(); - double E_dx = spring_mat[biggest_energy_id][j]*(diff.real())*(1-length_mat[biggest_energy_id][j]/(std::abs(diff))); - double E_dy = spring_mat[biggest_energy_id][j]*(diff.imag())*(1-length_mat[biggest_energy_id][j]/(std::abs(diff))); - energy_mat[biggest_energy_id][j] = std::complex(E_dx, E_dy); - energy_mat[j][biggest_energy_id] = std::complex(-E_dx, -E_dy); - energy_mat_sums[biggest_energy_id]+=energy_mat[biggest_energy_id][j]; - energy_mat_sums[j]+=energy_mat[j][biggest_energy_id]; - } - } + // calc forces + _ffm.reset(_particles); + _ffm.calc_ffm_forces(_terms, _thresh); + _ffm.calc_gravity_forces(_gravity); + _ffm.calc_edge_forces(_edge_force, graph.get_edges(), degrees); + std::vector forces = _ffm.get_forces(); + + if (i == 0) + old_forces = forces; + // calc speed + double total_swing = 0; // measurement of "erratic" movement + double total_traction = 0; // measurement of "sensible" movement + for (int j = 0; j < _particles.size(); j++) { + if (is_normal(forces[j] - old_forces[j])) { + total_swing += + _particles[j].get_charge() * std::abs(forces[j] - old_forces[j]); + total_traction += .5 * _particles[j].get_charge() * + std::abs(forces[j] + old_forces[j]); + } } - if (verbosity>=1){std::cout<<"\b\b\b\b100"<<"%\n";} - - + double estimatedOptimalJitterTolerance = .05 * std::sqrt(_particles.size()); + double minJT = std::sqrt(estimatedOptimalJitterTolerance); + double maxJT = 10.0; + double jt = + _jitter_tol * + std::max( + minJT, + std::min(maxJT, estimatedOptimalJitterTolerance * total_traction / + (_particles.size() * _particles.size()))); + + double minSpeedEfficiency = 0.05; + + if (total_traction > 0.0 && total_swing / total_traction > 2.0) { + if (speed_efficiency > minSpeedEfficiency) + speed_efficiency *= .5; + jt = std::max(jt, _jitter_tol); + } + double target_speed; + if (total_swing == 0) { + target_speed = std::numeric_limits::max(); + } else { + target_speed = jt * speed_efficiency * total_traction / total_swing; + } + if (total_swing > jt * total_traction) { + if (speed_efficiency > minSpeedEfficiency) { + speed_efficiency *= .7; + } + } else if (speed < 1000) { + speed_efficiency *= 1.3; + } + // std::cout<<"speed"<= 1) { + std::cout << "\b\b\b\b100" + << "%\n"; + } } -void LayoutGraph::calc_fa2(Graph& graph, int iterations, int _terms, int _thresh, double _edge_force, double _gravity, double _jitter_tol, double _speed, double _speed_efficiency, int verbosity){ - - - std::vector& _particles = graph.get_particles(); - - double speed = _speed; - double speed_efficiency = _speed_efficiency; - std::vector old_forces; - if (verbosity>=2) {std::cout << "Calculating fa2 layout for graph with "< degrees(graph.num_vertices(), 0); - for (auto e:graph.get_edges()){ - degrees[e.source]+=1; - degrees[e.target]+=1; +std::vector> +LayoutGraph::calc_components_layout(std::vector> positions, + int iterations) { + + Graph G; + std::vector component_sizes; + + int id = 0; + std::vector areas; + std::vector means; + for (auto l : positions) { + double min_x = std::numeric_limits::max(); + double min_y = std::numeric_limits::max(); + double max_x = std::numeric_limits::min(); + double max_y = std::numeric_limits::min(); + Compl mean = 0; + for (auto p : l) { + if (p.real() < min_x) { + min_x = p.real(); + } else if (p.real() > max_x) { + max_x = p.real(); + } + if (p.imag() < min_y) { + min_y = p.imag(); + } else if (p.imag() > max_y) { + max_y = p.imag(); + } + mean += p; } - Forces _ffm = Forces(_particles); - for (int i=0; iverbose_step && verbosity>=1){std::cout<<"\b\b\b\b"< forces = _ffm.get_forces(); - - if (i==0) old_forces = forces; - //calc speed - double total_swing = 0; // measurement of "erratic" movement - double total_traction = 0; // measurement of "sensible" movement - for (int j=0; j<_particles.size(); j++){ - if (is_normal(forces[j]-old_forces[j])){ - total_swing +=_particles[j].get_charge()*std::abs(forces[j]-old_forces[j]); - total_traction +=.5*_particles[j].get_charge()*std::abs(forces[j]+old_forces[j]); - } - } - double estimatedOptimalJitterTolerance = .05 * std::sqrt(_particles.size()); - double minJT = std::sqrt(estimatedOptimalJitterTolerance); - double maxJT = 10.0; - double jt = _jitter_tol * std::max(minJT, std::min(maxJT, estimatedOptimalJitterTolerance * total_traction / (_particles.size() * _particles.size()))); - - double minSpeedEfficiency = 0.05; - - if (total_traction>0.0 && total_swing / total_traction > 2.0){ - if (speed_efficiency > minSpeedEfficiency) speed_efficiency *= .5; - jt = std::max(jt, _jitter_tol); - } - double target_speed; - if (total_swing == 0){ - target_speed = std::numeric_limits::max(); - } else{ - target_speed = jt * speed_efficiency * total_traction / total_swing; - } - if (total_swing > jt * total_traction){ - if (speed_efficiency > minSpeedEfficiency){ - speed_efficiency *= .7; - } - }else if (speed < 1000){ - speed_efficiency *= 1.3; - } - //std::cout<<"speed"<((double)rand() / RAND_MAX, + (double)rand() / RAND_MAX), + 1, id), + ParticleData()); + id++; + component_sizes.push_back(l.size()); + } + double max_area = 0; + int max_area_id = 0; + for (int i = 1; i < areas.size(); i++) { + Edge ee; + ee.source = max_area_id; + ee.target = i; + ee.length = 10 + (areas[max_area_id] + areas[i]) / 1.5; + G.add_edge(ee); + if (max_area < areas[i]) { + max_area_id = i; + max_area = areas[i]; } - if (verbosity>=1){std::cout<<"\b\b\b\b100"<<"%\n";} - + } + + calc_kamada_kawai(G, 10, 0.0001, iterations, 2); + auto _particles = G.get_particles(); + + int index = 0; + std::vector> result; + for (int counter = 0; counter < component_sizes.size(); counter++) { + std::vector comp_result; + for (int sub = 0; sub < component_sizes[counter]; sub++) { + comp_result.push_back(positions[counter][sub] - means[counter] + + _particles[counter].get_pos()); + index++; + } + result.push_back(comp_result); + } + return result; } -std::vector> LayoutGraph::calc_components_layout(std::vector> positions, int iterations){ - - Graph G; - std::vector component_sizes; - - int id = 0; - std::vector areas; - std::vector means; - for (auto l: positions){ - double min_x=std::numeric_limits::max(); - double min_y=std::numeric_limits::max(); - double max_x=std::numeric_limits::min(); - double max_y=std::numeric_limits::min(); - Compl mean = 0; - for (auto p: l){ - if (p.real()max_x){ - max_x=p.real(); - } - if (p.imag()max_y){ - max_y=p.imag(); - } - mean+=p; - } - means.push_back(mean/Compl(l.size(),0)); - areas.push_back(std::max((max_x-min_x),(max_y-min_y))); - // or 1 as charge? - G.add_particle(Particle(std::complex((double)rand() / RAND_MAX,(double)rand() / RAND_MAX),1,id), ParticleData()); - id++; - component_sizes.push_back(l.size()); +std::vector> LayoutGraph::calc_many_components_layout( + std::vector> positions, int iterations, + int comp_per_calc) { + if (positions.size() < comp_per_calc) { + return calc_components_layout(positions, iterations); + } else { + int counter = 0; + std::vector>> split_positions; + std::vector> split; + for (auto p : positions) { + if (p.size() > 500) { + split_positions.push_back(std::vector>{p}); + counter--; + } else { + split.push_back(p); + } + if (counter < comp_per_calc - 1) { + counter++; + } else { + split_positions.push_back(split); + split.clear(); + counter = 0; + } + } + if (counter != 0) { + split_positions.push_back(split); } - double max_area = 0; - int max_area_id = 0; - for (int i=1;i> layouts; + std::vector sizes; + for (auto split : split_positions) { + std::vector> comp_layout = + calc_components_layout(split, iterations); + std::vector flat_comp_layout; + for (auto layout : comp_layout) { + sizes.push_back(layout.size()); + for (auto position : layout) { + flat_comp_layout.push_back(position); } + } + layouts.push_back(flat_comp_layout); + } + std::vector> res = + calc_many_components_layout(layouts, iterations, comp_per_calc); + std::vector flat_res; + for (auto rr : res) { + for (auto r : rr) { + flat_res.push_back(r); + } } - - calc_kamada_kawai(G, 10, 0.0001, iterations, 2); - auto _particles = G.get_particles(); - - - int index=0; std::vector> result; - for (int counter=0;counter comp_result; - for (int sub=0;sub comp_result; + counter = 0; + int size_counter = 0; + for (auto r : flat_res) { + comp_result.push_back(r); + if (counter < sizes[size_counter] - 1) { + counter++; + } else { + size_counter += 1; + counter = 0; result.push_back(comp_result); + comp_result.clear(); + } } return result; - -} - - - - - -std::vector> LayoutGraph::calc_many_components_layout(std::vector> positions, int iterations, int comp_per_calc){ - if (positions.size()>> split_positions; - std::vector> split; - for (auto p: positions){ - if (p.size()>500){ - split_positions.push_back(std::vector> {p}); - counter--; - } else{ - split.push_back(p); - } - if (counter> layouts; - std::vector sizes; - for (auto split: split_positions){ - std::vector> comp_layout = calc_components_layout(split, iterations); - std::vector flat_comp_layout; - for (auto layout: comp_layout){ - sizes.push_back(layout.size()); - for (auto position:layout){ - flat_comp_layout.push_back(position); - } - } - layouts.push_back(flat_comp_layout); - } - std::vector> res = calc_many_components_layout(layouts, iterations, comp_per_calc); - std::vector flat_res; - for (auto rr: res){ - for (auto r: rr){ - flat_res.push_back(r); - } - } - std::vector> result; - std::vector comp_result; - counter = 0; - int size_counter = 0; - for (auto r: flat_res){ - comp_result.push_back(r); - if (counter < sizes[size_counter]-1){ - counter++; - }else{ - size_counter +=1; - counter = 0; - result.push_back(comp_result); - comp_result.clear(); - } - } - return result; - - } - + } } diff --git a/BlockVisualisation/layout.h b/BlockVisualisation/layout.h index 1297367..1a68cbe 100644 --- a/BlockVisualisation/layout.h +++ b/BlockVisualisation/layout.h @@ -5,29 +5,33 @@ #include "forces.h" #include "graph.h" -#include -#include -#include #include -#include -#include #include +#include +#include #include +#include +#include +#include -#include #include +#include -class LayoutGraph -{ +class LayoutGraph { public: - LayoutGraph(); - void calc_fa2(Graph& graph, int iterations, int _terms, int _thresh, double _edge_force, double _gravity, double _jitter_tol, double _speed, double _speed_efficiency, int verbosity); - void calc_kamada_kawai(Graph& graph, double edge_strength, double thresh, int maxIter, int verbosity); - std::vector> calc_components_layout(std::vector> positions, int iterations=5); - std::vector> calc_many_components_layout(std::vector> positions, int iterations=5, int comp_per_calc=500); - - + LayoutGraph(); + void calc_fa2(Graph &graph, int iterations, int _terms, int _thresh, + double _edge_force, double _gravity, double _jitter_tol, + double _speed, double _speed_efficiency, int verbosity); + void calc_kamada_kawai(Graph &graph, double edge_strength, double thresh, + int maxIter, int verbosity); + std::vector> + calc_components_layout(std::vector> positions, + int iterations = 5); + std::vector> + calc_many_components_layout(std::vector> positions, + int iterations = 5, int comp_per_calc = 500); private: }; diff --git a/BlockVisualisation/main.cpp b/BlockVisualisation/main.cpp index afd8189..a6c7a77 100644 --- a/BlockVisualisation/main.cpp +++ b/BlockVisualisation/main.cpp @@ -1,22 +1,21 @@ // square.cpp (Compute the Square of an Integer) -#include +#include "block_visual.h" #include "forces.h" -#include "quadtree.h" #include "layout.h" -#include "block_visual.h" +#include "quadtree.h" +#include +#include +#include #include #include -#include -#include using namespace std::chrono; -//hardcoded that terms can be at most 16 since we used bitsets for the binomial maps -//g++ main.cpp forces.cpp quadtree.cpp -//g++ main.cpp forces.cpp quadtree.cpp layout.cpp - +// hardcoded that terms can be at most 16 since we used bitsets for the binomial +// maps g++ main.cpp forces.cpp quadtree.cpp g++ main.cpp forces.cpp quadtree.cpp +// layout.cpp /* Reading file sample/2019_06_15.gml. @@ -25,16 +24,15 @@ Calculating layout for graph with 1297265 vertices: 100 iterations*/ -int main() -{ - auto start = high_resolution_clock::now(); - - BlockVisual BV = BlockVisual("sample/visual_settings.txt"); - BV.calc_visual(); - //BV.fa2_visual(); +int main() { + auto start = high_resolution_clock::now(); - auto stop = high_resolution_clock::now(); - auto duration = duration_cast(stop - start); - std::cout<<"\nRan through in: "<(stop - start); + std::cout << "\nRan through in: " << double(duration.count()) / 1000000.0 + << " seconds...\n"; } diff --git a/BlockVisualisation/quadtree.cpp b/BlockVisualisation/quadtree.cpp index a622b89..77ec00a 100644 --- a/BlockVisualisation/quadtree.cpp +++ b/BlockVisualisation/quadtree.cpp @@ -1,175 +1,179 @@ // A2DD.cpp -#include "graph.h" #include "quadtree.h" +#include "graph.h" -#include -#include -#include -#include #include +#include #include +#include +#include +#include using Compl = std::complex; -int bit_ceil2(unsigned int a){ - int c = 0; - while (a!= 0){ - a = a>>1; - c+=1; - } - return c; +int bit_ceil2(unsigned int a) { + int c = 0; + while (a != 0) { + a = a >> 1; + c += 1; + } + return c; }; - // Represents a node in the quadtree. -void Node::split(int id1, int id2, int id3, int id4) -{ - _child_NW = id1; _child_NE = id2; _child_SW = id3; _child_SE = id4; - _is_leaf=false; +void Node::split(int id1, int id2, int id3, int id4) { + _child_NW = id1; + _child_NE = id2; + _child_SW = id3; + _child_SE = id4; + _is_leaf = false; } - - -std::vector< Particle> const QuadTree::get_close_particles(int const id){ - Node& node = get_node(id); - std::vector vec; - for (auto n_id: node.get_close_neighbours()){ - //if (n_id == -1) continue; - Node& cl_node = get_node(n_id); - for (auto particle: get_node(n_id).get_particles()){ - vec.push_back(particle); - } +std::vector const QuadTree::get_close_particles(int const id) { + Node &node = get_node(id); + std::vector vec; + for (auto n_id : node.get_close_neighbours()) { + // if (n_id == -1) continue; + Node &cl_node = get_node(n_id); + for (auto particle : get_node(n_id).get_particles()) { + vec.push_back(particle); } - return vec; + } + return vec; } -std::vector const QuadTree::get_active(int const id){ - //top level has no active neighbours... - if (id<4){return {};} - - std::vector vec; - Node& node = get_node(id); - auto my_close = node.get_close_neighbours(); - auto parent_close = get_node(node.get_parent()).get_close_neighbours(); - for (int p_close: parent_close){ - Node& close_Node = node_map[p_close]; - if(close_Node.is_leaf()){ - if(std::find(my_close.begin(), my_close.end(), p_close) == my_close.end()) { - vec.push_back(p_close); - } - } else{ - for (int c: close_Node.get_children()){ - if(std::find(my_close.begin(), my_close.end(), c) == my_close.end()) { - vec.push_back(c); - } - } +std::vector const QuadTree::get_active(int const id) { + // top level has no active neighbours... + if (id < 4) { + return {}; + } + + std::vector vec; + Node &node = get_node(id); + auto my_close = node.get_close_neighbours(); + auto parent_close = get_node(node.get_parent()).get_close_neighbours(); + for (int p_close : parent_close) { + Node &close_Node = node_map[p_close]; + if (close_Node.is_leaf()) { + if (std::find(my_close.begin(), my_close.end(), p_close) == + my_close.end()) { + vec.push_back(p_close); + } + } else { + for (int c : close_Node.get_children()) { + if (std::find(my_close.begin(), my_close.end(), c) == my_close.end()) { + vec.push_back(c); } + } } - return vec; + } + return vec; } - - -void QuadTree::split(int id) -{ - - Node& node = get_node(id); - - double const w2 = node.get_width()/2; - double const h2 = node.get_height()/2; - double const x0 = node.get_x0(); - double const y0 = node.get_y0(); - - int x_coord = node.get_x_coord()<<1; - int y_coord = node.get_y_coord()<<1; - int const& depth = node.get_depth()+1; - - std::vector particles1; - std::vector particles2; - std::vector particles3; - std::vector particles4; - - for (auto p: node.get_particles()){ - if (p.get_pos().real()< x0+w2){ - if (p.get_pos().imag()>= y0+h2){ - particles3.push_back(p); - continue; - } else{ - particles1.push_back(p); - continue; - } - } - else { - if (p.get_pos().imag()>= y0+h2){ - particles4.push_back(p); - continue; - } else{ - particles2.push_back(p); - continue; - } - } +void QuadTree::split(int id) { + + Node &node = get_node(id); + + double const w2 = node.get_width() / 2; + double const h2 = node.get_height() / 2; + double const x0 = node.get_x0(); + double const y0 = node.get_y0(); + + int x_coord = node.get_x_coord() << 1; + int y_coord = node.get_y_coord() << 1; + int const &depth = node.get_depth() + 1; + + std::vector particles1; + std::vector particles2; + std::vector particles3; + std::vector particles4; + + for (auto p : node.get_particles()) { + if (p.get_pos().real() < x0 + w2) { + if (p.get_pos().imag() >= y0 + h2) { + particles3.push_back(p); + continue; + } else { + particles1.push_back(p); + continue; + } + } else { + if (p.get_pos().imag() >= y0 + h2) { + particles4.push_back(p); + continue; + } else { + particles2.push_back(p); + continue; + } } + } - int id1 = node_map.size(); - int id2 = id1+1; - int id3 = id2+1; - int id4 = id3+1; + int id1 = node_map.size(); + int id2 = id1 + 1; + int id3 = id2 + 1; + int id4 = id3 + 1; - int y_coord1 = y_coord|1; - int x_coord1 = x_coord|1; + int y_coord1 = y_coord | 1; + int x_coord1 = x_coord | 1; - node.del_particles(); - - node_map.emplace_back(Node (id1, id, particles1, x0, y0, w2, h2, x_coord, y_coord, depth)); - node_map.emplace_back(Node (id2, id, particles2, x0+w2, y0, w2, h2, x_coord1, y_coord, depth)); - node_map.emplace_back(Node (id3, id, particles3, x0, y0+h2, w2, h2, x_coord, y_coord1, depth)); - node_map.emplace_back(Node (id4, id, particles4, x0+w2, y0+h2, w2, h2, y_coord1, y_coord1, depth)); + node.del_particles(); - Node& nodeP = get_node(id); - nodeP.split(id1, id2, id3, id4); - -} + node_map.emplace_back( + Node(id1, id, particles1, x0, y0, w2, h2, x_coord, y_coord, depth)); + node_map.emplace_back( + Node(id2, id, particles2, x0 + w2, y0, w2, h2, x_coord1, y_coord, depth)); + node_map.emplace_back( + Node(id3, id, particles3, x0, y0 + h2, w2, h2, x_coord, y_coord1, depth)); + node_map.emplace_back(Node(id4, id, particles4, x0 + w2, y0 + h2, w2, h2, + y_coord1, y_coord1, depth)); + Node &nodeP = get_node(id); + nodeP.split(id1, id2, id3, id4); +} -void QuadTree::calc_close() -{ - int size = node_map.size(); - for (int i = 0; i < size; i++){ - Node& p = node_map[i]; - int const& depth = p.get_depth(); - unsigned int const& x_coord = p.get_x_coord(); - unsigned int const& y_coord = p.get_y_coord(); - std::vector> const shifts = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}}; - std::vector close = {}; - for (std::pair shift: shifts){ - if (((shift.first == -1 & x_coord>=1) || (shift.first == 1 & bit_ceil2(x_coord+1)<=depth) || shift.first == 0)& - ((shift.second == -1 & y_coord>=1) || (shift.second == 1 & bit_ceil2(y_coord+1)<=depth) || shift.second == 0)){ - unsigned int close_x_coord = x_coord+shift.first; - unsigned int close_y_coord = y_coord+shift.second; - int counter = 1; - int temp = 0; - while (node_map[temp].is_leaf() == false & depth-counter>=0){ - if (0 == ( (close_x_coord >> depth-counter) & 1)){ - if (0 == ( (close_y_coord >> depth-counter) & 1)){ - temp = node_map[temp].get_children()[0]; - } else{ - temp = node_map[temp].get_children()[2]; - } - } else { - if (0 == ( (close_y_coord >> depth-counter) & 1)){ - temp = node_map[temp].get_children()[1]; - } else{ - temp = node_map[temp].get_children()[3]; - } - } - counter +=1; - } - if(std::find(close.begin(), close.end(), temp) == close.end()) { - close.push_back(temp); - } +void QuadTree::calc_close() { + int size = node_map.size(); + for (int i = 0; i < size; i++) { + Node &p = node_map[i]; + int const &depth = p.get_depth(); + unsigned int const &x_coord = p.get_x_coord(); + unsigned int const &y_coord = p.get_y_coord(); + std::vector> const shifts = { + {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}}; + std::vector close = {}; + for (std::pair shift : shifts) { + if (((shift.first == -1 & x_coord >= 1) || + (shift.first == 1 & bit_ceil2(x_coord + 1) <= depth) || + shift.first == 0) & + ((shift.second == -1 & y_coord >= 1) || + (shift.second == 1 & bit_ceil2(y_coord + 1) <= depth) || + shift.second == 0)) { + unsigned int close_x_coord = x_coord + shift.first; + unsigned int close_y_coord = y_coord + shift.second; + int counter = 1; + int temp = 0; + while (node_map[temp].is_leaf() == false & depth - counter >= 0) { + if (0 == ((close_x_coord >> depth - counter) & 1)) { + if (0 == ((close_y_coord >> depth - counter) & 1)) { + temp = node_map[temp].get_children()[0]; + } else { + temp = node_map[temp].get_children()[2]; + } + } else { + if (0 == ((close_y_coord >> depth - counter) & 1)) { + temp = node_map[temp].get_children()[1]; + } else { + temp = node_map[temp].get_children()[3]; } + } + counter += 1; + } + if (std::find(close.begin(), close.end(), temp) == close.end()) { + close.push_back(temp); } - node_map[i].set_close_neighbours(close); + } } + node_map[i].set_close_neighbours(close); + } } \ No newline at end of file diff --git a/BlockVisualisation/quadtree.h b/BlockVisualisation/quadtree.h index 2d82889..924cf04 100644 --- a/BlockVisualisation/quadtree.h +++ b/BlockVisualisation/quadtree.h @@ -4,198 +4,247 @@ #include "graph.h" -#include -#include -#include #include -#include -#include #include +#include +#include #include +#include +#include +#include +class Node { +public: + Node(int id, int parent, std::vector particles, double x0, + double y0, double width, double height, int x_coord, int y_coord, + int depth) + : _id(id), _parent(parent), _x0(x0), _y0(y0), _width(width), + _height(height), _particles(particles), _is_leaf(true), + _incoming_coeff(), _outgoing_coeff(), _x_coord(x_coord), + _y_coord(y_coord), _depth(depth) {} + void split(int id1, int id2, int id3, int id4); + double const get_x0() { return _x0; } + double const get_y0() { return _y0; } + double const get_width() { return _width; } + double const get_height() { return _height; } -class Node -{ -public: - Node(int id, int parent, std::vector particles, double x0, double y0, double width, double height, int x_coord, int y_coord, int depth): _id(id),_parent(parent), _x0(x0),_y0(y0), _width(width), _height(height), _particles(particles), _is_leaf(true), _incoming_coeff(), _outgoing_coeff(), _x_coord(x_coord), _y_coord(y_coord), _depth(depth) {} - - void split(int id1, int id2, int id3, int id4); + int get_id() { return _id; } - double const get_x0() {return _x0;} - double const get_y0() {return _y0;} - double const get_width() {return _width;} - double const get_height() {return _height;} + int const get_parent() { return _parent; } - int get_id () {return _id;} + std::vector const get_children() const { + return {_child_NW, _child_NE, _child_SW, _child_SE}; + } - int const get_parent(){return _parent;} + const std::vector &get_close_neighbours() const { return close_nodes; } - std::vector const get_children() const { - return {_child_NW, _child_NE, _child_SW, _child_SE}; - } + void set_close_neighbours(const std::vector &close) { + close_nodes = close; + } - const std::vector & get_close_neighbours()const { - return close_nodes; - } + std::vector &get_particles() { return _particles; } - void set_close_neighbours(const std::vector& close){ - close_nodes = close; - } + void del_particles() { _particles.clear(); } - std::vector & get_particles() { - return _particles; - } + int const size() const { return _particles.size(); } - void del_particles() { - _particles.clear(); - } + std::complex const get_center() const { + return std::complex(_x0 + _width / 2, _y0 + _height / 2); + } - int const size()const { - return _particles.size(); - } + bool const is_leaf() const { return _is_leaf; } - std::complex const get_center()const { - return std::complex(_x0+_width/2, _y0+_height/2); - } + const std::vector> &get_outgoing() const { + return _outgoing_coeff; + } - bool const is_leaf()const { - return _is_leaf; - } + const std::vector> &get_incoming() const { + return _incoming_coeff; + } + unsigned int const &get_x_coord() const { return _x_coord; } - const std::vector< std::complex> & get_outgoing()const { - return _outgoing_coeff; - } + unsigned int const &get_y_coord() const { return _y_coord; } - const std::vector< std::complex> & get_incoming()const { - return _incoming_coeff; - } + int const &get_depth() const { return _depth; } - - unsigned int const& get_x_coord()const { - return _x_coord; - } + void set_outgoing(std::vector> const out) { + _outgoing_coeff = out; + } - unsigned int const& get_y_coord()const { - return _y_coord; - } + void set_incoming(std::vector> const inc) { + _incoming_coeff = inc; + } - int const& get_depth()const { - return _depth; + void butput() { + std::cout << std::endl + << std::endl + << "===============butput============" << std::endl; + std::cout << "id " << _id << std::endl; + std::cout << "x0 " << _x0 << std::endl; + std::cout << "y0 " << _y0 << std::endl; + std::cout << "xcode " << _x_coord << std::endl; + std::cout << "ycode " << _y_coord << std::endl; + std::cout << "width " << _width << std::endl; + std::cout << "height " << _height << std::endl; + std::cout << "depth " << _depth << std::endl; + std::cout << "parent " << _parent << std::endl; + std::cout << "particles " << _particles.size() << std::endl; + for (auto i : _particles) { + std::cout << i.get_id() << ' '; } - - void set_outgoing(std::vector< std::complex> const out){ - _outgoing_coeff = out; + std::cout << std::endl << "outgoing_coeff " << std::endl; + for (auto i : _outgoing_coeff) { + std::cout << i << ' '; } - - void set_incoming(std::vector< std::complex> const inc){ - _incoming_coeff = inc; + std::cout << std::endl << "incoming coeff " << std::endl; + for (auto i : _incoming_coeff) { + std::cout << i << ' '; } - - void butput (){ - std::cout < _particles; - std::vector _particles; + std::vector> _outgoing_coeff; + std::vector> _incoming_coeff; - - std::vector> _outgoing_coeff; - std::vector> _incoming_coeff; + unsigned int const _x_coord = 0; + unsigned int const _y_coord = 0; + int const _depth = 0; - unsigned int const _x_coord = 0; - unsigned int const _y_coord = 0; - int const _depth = 0; + std::vector close_nodes = {}; - std::vector close_nodes = {}; - - int _child_NW=-1; int _child_NE=-1; int _child_SW=-1; int _child_SE=-1; - - int const _parent; - int _is_leaf; + int _child_NW = -1; + int _child_NE = -1; + int _child_SW = -1; + int _child_SE = -1; - double const _x0; double const _y0; - double const _width; double const _height; -}; + int const _parent; + int _is_leaf; + double const _x0; + double const _y0; + double const _width; + double const _height; +}; -class QuadTree -{ +class QuadTree { public: - // default constructor - QuadTree(){}; - QuadTree(std::vector particles) - { - double _x0 = (*std::min_element(particles.begin(),particles.end(), [&](Particle a, Particle b){return a.get_pos().real() particles){ - node_map.clear(); - - - double _x0 = (*std::min_element(particles.begin(),particles.end(), [&](Particle a, Particle b){return a.get_pos().real()_x0+_width || p.get_pos().real()<_x0 || p.get_pos().imag()>_y0+_height || p.get_pos().imag()<_y0){ - //std::cout<< "\n " <<_x0<<" < "< const get_close_particles(int const id); - std::vector const get_active(int const id); - - Node& get_node(int id){ - return node_map[id]; - } + // default constructor + QuadTree(){}; + QuadTree(std::vector particles) { + double _x0 = + (*std::min_element(particles.begin(), particles.end(), + [&](Particle a, Particle b) { + return a.get_pos().real() < b.get_pos().real(); + })) + .get_pos() + .real(); + double _y0 = + (*std::min_element(particles.begin(), particles.end(), + [&](Particle a, Particle b) { + return a.get_pos().imag() < b.get_pos().imag(); + })) + .get_pos() + .imag(); + double _width = + (*std::max_element(particles.begin(), particles.end(), + [&](Particle a, Particle b) { + return a.get_pos().real() < b.get_pos().real(); + })) + .get_pos() + .real() - + _x0; + double _height = + (*std::max_element(particles.begin(), particles.end(), + [&](Particle a, Particle b) { + return a.get_pos().imag() < b.get_pos().imag(); + })) + .get_pos() + .imag() - + _y0; + + node_map.emplace_back( + Node(0, 0, particles, _x0, _y0, _width, _height, 0, 0, 0)); + } + + void reset(std::vector particles) { + node_map.clear(); + + double _x0 = + (*std::min_element(particles.begin(), particles.end(), + [&](Particle a, Particle b) { + return a.get_pos().real() < b.get_pos().real(); + })) + .get_pos() + .real(); + double _y0 = + (*std::min_element(particles.begin(), particles.end(), + [&](Particle a, Particle b) { + return a.get_pos().imag() < b.get_pos().imag(); + })) + .get_pos() + .imag(); + double _width = + (*std::max_element(particles.begin(), particles.end(), + [&](Particle a, Particle b) { + return a.get_pos().real() < b.get_pos().real(); + })) + .get_pos() + .real() - + _x0; + double _height = + (*std::max_element(particles.begin(), particles.end(), + [&](Particle a, Particle b) { + return a.get_pos().imag() < b.get_pos().imag(); + })) + .get_pos() + .imag() - + _y0; + + for (auto p : particles) { + if (p.get_pos().real() > _x0 + _width || p.get_pos().real() < _x0 || + p.get_pos().imag() > _y0 + _height || p.get_pos().imag() < _y0) { + // std::cout<< "\n " <<_x0<<" < "< const get_close_particles(int const id); + std::vector const get_active(int const id); + + Node &get_node(int id) { return node_map[id]; } private: - std::vector node_map={}; - + std::vector node_map = {}; }; #endif \ No newline at end of file