#include "random_graph_generator.h" random_graph_generator::random_graph_generator( size_t number_of_edges, size_t number_of_nodes, random_attribute_generator edge_generator, random_attribute_generator node_generator, std::map default_values_edge_attributes, std::map default_values_node_attributes ) : _template_node_attributes(default_values_node_attributes), _template_edge_attributes(default_values_edge_attributes), _number_of_nodes(number_of_nodes), _number_of_edges(number_of_edges), _node_generator(node_generator), _edge_generator(edge_generator) {} Graph random_graph_generator::next_acyclic(){ Graph g (this->_template_edge_attributes, this->_template_node_attributes); while(!random_graph_generator::grow_random_acyclic(g, this->_number_of_nodes, this->_number_of_edges, this->_edge_generator, this->_node_generator).first){ std::cout << "generation failed; retrying!" << std::endl; } return g; } Graph random_graph_generator::next(){ Graph g (this->_template_edge_attributes, this->_template_node_attributes); while(!random_graph_generator::grow_random(g, this->_number_of_nodes, this->_number_of_edges, this->_edge_generator, this->_node_generator).first){ std::cout << "generation failed; retrying!" << std::endl; } return g; } std::pair,Graph> random_graph_generator::next_acyclic_2_tips(){ Graph g (this->_template_edge_attributes, this->_template_node_attributes); while(!random_graph_generator::grow_random_acyclic(g, this->_number_of_nodes, this->_number_of_edges, this->_edge_generator, this->_node_generator).first){ std::cout << "generation failed; retrying!" << std::endl; } auto tips = g.tip_fringes(this->_edge_generator, this->_node_generator); return {tips, std::move(g)}; } std::pair random_graph_generator::node_template(const std::string& attr) const{ auto search = this->_template_node_attributes.find(attr); if(search == this->_template_node_attributes.end()){ return {false, {fix, 0}}; } return {true, search->second}; } std::pair random_graph_generator::edge_template(const std::string& attr) const { auto search = this->_template_edge_attributes.find(attr); if(search == this->_template_edge_attributes.end()){ return {false, {fix, 0}}; } return {true, search->second}; } Attribute random_graph_generator::edge_template_throwing(const std::string& attr){ auto search = this->_template_edge_attributes.find(attr); if(search == this->_template_edge_attributes.end()){ std::stringstream text; text << "\"" << attr << "\" is not defined by default for Edges generated by this Generator"; throw std::range_error(text.str()); } return search->second; } Attribute random_graph_generator::node_template_throwing(const std::string& attr){ auto search = this->_template_node_attributes.find(attr); if(search == this->_template_node_attributes.end()){ std::stringstream text; text << "\"" << attr << "\" is not defined by default for Nodes generated by this Generator"; throw std::range_error(text.str()); } return search->second; } std::pair, std::vector>> random_graph_generator::grow_random(Graph& g, size_t number_of_nodes, size_t number_of_edges, random_attribute_generator& edge_attribute_generator, random_attribute_generator& node_attribute_generator){ std::vector added_nodes; std::vector added_edges; added_nodes.reserve(number_of_nodes); added_edges.reserve(number_of_edges); for(size_t i = 0; i < number_of_nodes; ++i){ std::stringstream name; name << g.size().first; added_nodes.push_back(g.add_node(name.str(), node_attribute_generator.next())); } random_set_element_generator rand_stream (&g.nodes()); Node* n1; Node* n2; for(size_t i = 0; i < number_of_edges; ++i){ size_t attempt = 0; redo: if(attempt > g.nodes().size()*g.nodes().size()*g.nodes().size()){ goto failed; }; try{ rand_stream >> n1; rand_stream >> n2; }catch (std::range_error& e){ goto failed; } { auto existing_path = g.directed_admissible_st_path(n1, n2); if(existing_path.first && existing_path.second.number_of_edges() <= 1) { attempt++; goto redo; } } std::stringstream name; name << n1->description() << "_" << n2->description(); added_edges.push_back(g.add_edge(n1, n2, name.str(), edge_attribute_generator.next())); } return {true,{added_nodes, added_edges}}; failed: /* cleanup: restore state; due to failure: remove the already added components */ for(Edge* e : added_edges){ g.remove_edge(e); } for(Node* n : added_nodes){ g.remove_node(n); } return {false,{{},{}}}; } //TODO: add generate_random_edge and random node to node, edge and use additional parameters to generate random attributes for edges, nodes std::pair, std::vector>> random_graph_generator::grow_random_acyclic(Graph& g, size_t number_of_nodes, size_t number_of_edges, random_attribute_generator& edge_attribute_generator, random_attribute_generator& node_attribute_generator){ std::vector added_nodes; std::vector added_edges; added_nodes.reserve(number_of_nodes); added_edges.reserve(number_of_edges); for(size_t i = 0; i < number_of_nodes; ++i){ std::stringstream name; name << g.size().first; added_nodes.push_back(g.add_node(name.str(), node_attribute_generator.next())); } random_set_element_generator rand_stream (&g.nodes()); Node* n1; Node* n2; for(size_t i = 0; i < number_of_edges; ++i){ size_t attempt = 0; redo: if(attempt > g.nodes().size()*g.nodes().size()*g.nodes().size()){ goto failed; }; try{ rand_stream >> n1; rand_stream >> n2; }catch (std::range_error& e){ goto failed; } if(n1 == n2 || g.directed_admissible_st_path(n2, n1).first || g.directed_admissible_st_path(n1, n2).second.number_of_edges() == 1) { attempt++; goto redo; } std::stringstream name; name << n1->description() << "_" << n2->description(); added_edges.push_back(g.add_edge(n1, n2, name.str(), edge_attribute_generator.next())); } return {true,{added_nodes, added_edges}}; failed: /* cleanup: restore state; due to failure: remove the already added components */ for(Edge* e : added_edges){ g.remove_edge(e); } for(Node* n : added_nodes){ g.remove_node(n); } return {false,{{},{}}}; }