diff --git a/Graphtheory/Basic_Graph.h b/Graphtheory/Basic_Graph.h deleted file mode 100644 index 792ed7b77471ac9bbb8954beb15deb19916d3ee2..0000000000000000000000000000000000000000 --- a/Graphtheory/Basic_Graph.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef GRAPH_H -#define GRAPH_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Edge.h" -#include "Node.h" - - -template -class Graph{ - std::set*> _edges; - std::set*> _nodes; - std::map _template_node_attributes; - std::map _template_edge_attributes; -public: - // TODO: use references to speed up constructors - Graph(){}; - Graph(std::map default_values_edge_attributes, std::map default_values_node_attributes = {}); - Graph(Graph& graph); - Graph(Graph&& graph); - - Edge* add_edge(Node* from, Node* to, std::map edge_attributes = {}, std::string description = ""); - Edge* add_edge(Node* from, Node* to, std::map edge_attributes = {}, std::string description = ""); - Edge* add_edge(Edge* remote_edge, std::map*, Node*>& node_lookup); - Node* add_node(std::map node_attributes = {}, std::string description = ""); - Node* add_node(std::map node_attributes = {}, std::string description = ""); - Node* add_node(Node* remote_node); - - void remove_node(Node* node); - void remove_edge(Edge* edge); - - // change to non reference return type? - std::set*>& edges(){ - return this->_edges; - } - std::set*>& nodes(){ - return this->_nodes; - } - - Attribute node_template(E attr){ - return this->_templatNode_attributes.find(attr)->second; - } - Attribute edge_template(E attr){ - return this->_template_edge_attributes.find(attr)->second; - } - - void reset_attribute_values(std::set edge_attr, std::set node_attr = {}); - - std::pair size(){ - return {this->_nodes.size(), this->_edges.size()}; - } - - ~Graph(){ - while(this->nodes().begin() != this->nodes().end()){ - this->remove_node(*this->nodes().begin()); - } - } - - // _advanced.cpp: - Graph(std::istream& is); - void conditional_bfs_all_components(std::function* from, Edge* via, bool used_in_traversal)> edge_exec, std::function* via, Node* node)> node_exec, std::deque*> starting_nodes = {}, bool all_paths = false, std::function* from, Edge* via)> guide = [](Node* n, Edge* e)->bool {return e->from() == n;}); - - // _special_members_and_operators: - void operator=(const Graph& graph); - void operator=(Graph&& graph); -}; - -template -std::ostream& operator<<(std::ostream& os, Graph& g); - -template -std::istream& operator>>(std::istream& is, Graph& g){g = Graph(is); return is;} - -#include "Basic_Graph.ipp" -#include "Basic_Graph_advanced.ipp" -#include "Basic_Graph_special_members_and_operators.ipp" - -#endif diff --git a/Graphtheory/Basic_Graph.ipp b/Graphtheory/Basic_Graph.ipp deleted file mode 100644 index 72342df9d59175c2d3c283684743cf9d6e9e1f24..0000000000000000000000000000000000000000 --- a/Graphtheory/Basic_Graph.ipp +++ /dev/null @@ -1,104 +0,0 @@ -template -Graph::Graph(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){} - -template -Edge* Graph::add_edge(Node* from, Node* to, std::map edge_attributes, std::string description){ - Edge* ptr = new Edge(from, to, edge_attributes, description); - this->edges().insert(ptr); - return ptr; -} - -template -Edge* Graph::add_edge(Node* from, Node* to, std::map edge_attributes, std::string description){ - Edge* ptr = new Edge(from, to, this->_template_edge_attributes, edge_attributes, description); - this->edges().insert(ptr); - return ptr; -} - -template -Edge* Graph::add_edge(Edge* remote_edge, std::map*, Node*>& node_lookup){ - Edge* ptr = new Edge(*remote_edge, node_lookup); - this->edges().insert(ptr); - return ptr; -} - -template -Node* Graph::add_node(std::map node_attributes, std::string description){ - Node* ptr = new Node(node_attributes, description); - this->nodes().insert(ptr); - return ptr; -} - -template -Node* Graph::add_node(std::map node_attributes, std::string description){ - Node* ptr = new Node(this->_template_node_attributes, node_attributes, description); - this->nodes().insert(ptr); - return ptr; -} - -template -Node* Graph::add_node(Node* remote_node){ - Node* ptr = new Node(*remote_node); - this->nodes().insert(ptr); - return ptr; -} - -template -void Graph::remove_node(Node* node){ - for(Edge* e : node->incident()){ - this->edges().erase(e); - } - this->nodes().erase(node); // remove node pointer in graph - delete node; // removes pointers in node and edges & dealloc -} - -template -void Graph::remove_edge(Edge* edge){ - this->edges().erase(edge); - delete edge; -} - -template -void Graph::reset_attribute_values(std::set edge_attr, std::set node_attr){ - for(Node* n : this->nodes()){ - for(const N attr : node_attr){ - n->attribute(attr).value() = this->_template_node_attributes.find(attr)->second.value(); - } - } - - for(Edge* e : this->edges()){ - for(const E attr : edge_attr){ - e->attribute(attr).value() = this->_template_edge_attributes.find(attr)->second.value(); - } - } -} - -template -std::ostream& operator<<(std::ostream& os, Graph& g){ - if(&os == &std::cout){ - os << "\033[0;31m"; - os << "Graph { Nodes { \n"; - for(Node* n : g.nodes()){ - os << *n << "\n"; - } - os << "\033[0;31m"; - os << "} Edges {" << "\n"; - for(Edge* e : g.edges()){ - os << *e << "\n"; - } - os << "\033[0;31m"; - os << "} }"; - os << "\033[0m"; - }else{ - os << "Graph { Nodes { \n"; - for(Node* n : g.nodes()){ - os << *n << "\n"; - } - os << "} Edges {" << "\n"; - for(Edge* e : g.edges()){ - os << *e << "\n"; - } - os << "} }"; - } - return os; -} diff --git a/Graphtheory/Edge.cpp b/Graphtheory/Edge.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bc9b33e730804cd0cbe13048710dc228fd7c7cc8 --- /dev/null +++ b/Graphtheory/Edge.cpp @@ -0,0 +1,72 @@ +#include "Edge.h" + +Edge::Edge(const Edge& remote_edge, const std::map& node_lookup) : _description(remote_edge._description), _from(node_lookup.find(remote_edge._from)->second), _to(node_lookup.find(remote_edge._to)->second), _attributes(remote_edge._attributes) { + this->_from->add_incident(this); + this->_to->add_incident(this); +} + +Edge::Edge(Node* from, Node* to, std::string description, std::map attributes) : _description(std::move(description)), _from(from), _to(to), _attributes(std::move(attributes)){ + from->add_incident(this); + to->add_incident(this); +}; + +Edge::Edge(std::istream& is, const std::map& name_lookup){ + std::string curr; + is >> curr; + assert(curr == "Edge"); + + is >> this->_description; + + is >> curr; + assert(curr == "("); + is >> curr; + while(curr != ")"){ + std::string attribute = curr; + is >> curr; + assert(curr == "="); + is >> curr; + this->_attributes.insert({attribute, {fix, std::stod(curr), Continuous}}); + is >> curr; + } + is >> curr; + assert(curr == "{"); + is >> curr; + this->_from = name_lookup.find(curr)->second; + this->_from->add_incident(this); + is >> curr; + this->_to = name_lookup.find(curr)->second; + this->_to->add_incident(this); + is >> curr; + assert(curr == "}"); +} + +void Edge::disconnect(){ + this->from()->incident().erase(this); + this->to()->incident().erase(this); +} + +void Edge::reconnect(){ + this->from()->incident().insert(this); + this->to()->incident().insert(this); +} + +std::ostream& operator<<(std::ostream& os, Edge& e){ + if(&os == &std::cout){ + os << "\033[0;32m"; + os << "Edge " << e.description() << " ( "; + for(std::pair pair : e.attributes()){ + os << pair.first << " = " << pair.second.value() << ", "; + } + os << ") {" << e.from()->description() << ", " << e.to()->description() << "}"; + os << "\033[0m"; + }else{ + os << "Edge " << e.description() << " ( "; + for(std::pair pair : e.attributes()){ + os << pair.first << " = " << pair.second.value() << " "; + } + os << " ) { " << e.from()->description() << " " << e.to()->description() << " }"; + } + + + return os; +} diff --git a/Graphtheory/Edge.h b/Graphtheory/Edge.h index f0ccea5c6ea0aa49825e2974f545daa9a6a54359..9cad1cf038a1fcab015a6b414712ee1febeb62c4 100644 --- a/Graphtheory/Edge.h +++ b/Graphtheory/Edge.h @@ -11,77 +11,94 @@ #include #include "Attribute.h" +#include "Node.h" -template class Node; +class Node; -template class Edge{ std::string _description; - Node* _from; - Node* _to; + Node* _from; + Node* _to; - std::map _attributes; + std::map _attributes; public: - Edge(Edge& local_edge) : _description(local_edge._description), _from(local_edge._from), _to(local_edge._to), _attributes(local_edge._attributes) {} - Edge(Edge&& local_edge) : _description(std::move(local_edge._description)), _from(std::move(local_edge._from)), _to(std::move(local_edge._to)), _attributes(std::move(local_edge._attributes)) {} - Edge(Edge& remote_edge, std::map*, Node*>& node_lookup) : _description(remote_edge._description), _from(node_lookup.find(remote_edge._from)->second), _to(node_lookup.find(remote_edge._to)->second), _attributes(remote_edge._attributes) { - this->_from->add_incident(this); - this->_to->add_incident(this); - } - - Edge(Node* from, Node* to, std::string description = "") : _description(description), _from(from), _to(to){ - from->add_incident(this); - to->add_incident(this); - }; - - Edge(Node* from, Node* to, std::map& default_attributes, std::map attributes = {}, std::string description = "") : _description(description), _from(from), _to(to), _attributes(default_attributes){ - for(std::pair pair : attributes){ - this->attribute(pair.first).value() = pair.second; - } + Edge(const Edge& local_edge) : _description(local_edge._description), _from(local_edge._from), _to(local_edge._to), _attributes(local_edge._attributes) {} + Edge(Edge&& local_edge) : _description(std::move(local_edge._description)), _from(std::move(local_edge._from)), _to(std::move(local_edge._to)), _attributes(std::move(local_edge._attributes)) {} + Edge(const Edge& remote_edge, const std::map& node_lookup); - from->add_incident(this); - to->add_incident(this); - }; + Edge(Node* from, Node* to, std::string description, std::map attributes = {}); + Edge(std::istream& is, const std::map& name_lookup); - Edge(std::istream& is, std::map* >& name_lookup); + const std::string& description() const { + return this->_description; + } - std::string description(){ - if(this->_description == ""){ - std::stringstream name; - name << this; - return name.str(); - } + std::string& description() { return this->_description; } - Node* from(){ + Node* const & from() const { + return this->_from; + } + Node*& from() { return this->_from; } - Node* to(){ + + Node* const & to() const { + return this->_to; + } + Node*& to() { return this->_to; } - Node* to(const Node* node){ + Node* const & to(const Node* node) const { + if(node != this->to() && node != this->from()) throw std::range_error("node not incident to edge"); + return node == this->from() ? this->to() : this->from(); + } + Node*& to(const Node* node) { if(node != this->to() && node != this->from()) throw std::range_error("node not incident to edge"); return node == this->from() ? this->to() : this->from(); } - std::map attributes(){ + const std::map& attributes() const { return this->_attributes; } + std::map& attributes() { + return this->_attributes; + } + + std::pair attribute(const std::string& attr) const { + auto search = this->_attributes.find(attr); + if(search == this->_attributes.end()){ + return {false, {fix, 0}}; + } + return {true, search->second}; + } - Attribute& attribute(E key){ - return this->_attributes.find(key)->second; + Attribute& attribute_throwing(const std::string& attr){ + auto search = this->_attributes.find(attr); + if(search == this->_attributes.end()){ + std::stringstream text; + text << "\"" << attr << "\" is not defined for Node " << this->description(); + throw std::range_error(text.str()); + } + return search->second; } - void disconnect(){ - this->from()->incident().erase(this); - this->to()->incident().erase(this); + void disconnect(); + + void reconnect(); + + void operator=(const Edge& edge) { + this->_description = edge._description; + this->_from = edge._from; + this->_to = edge._to; } - void reconnect(){ - this->from()->incident().insert(this); - this->to()->incident().insert(this); + void operator=(Edge&& edge){ + this->_description = std::move(edge._description); + this->_from = std::move(edge._from); + this->_to = std::move(edge._to); } ~Edge(){ @@ -89,9 +106,6 @@ public: } }; -template -std::ostream& operator<<(std::ostream& os, Edge& e); - -#include "Edge.ipp" +std::ostream& operator<<(std::ostream& os, Edge& e); #endif diff --git a/Graphtheory/Edge.ipp b/Graphtheory/Edge.ipp deleted file mode 100644 index 51ce6e150b13ee721dcf9542fed59ded44496772..0000000000000000000000000000000000000000 --- a/Graphtheory/Edge.ipp +++ /dev/null @@ -1,53 +0,0 @@ -template -Edge::Edge(std::istream& is, std::map* >& name_lookup){ - std::string curr; - is >> curr; - assert(curr == "Edge"); - - is >> this->_description; - - is >> curr; - assert(curr == "("); - is >> curr; - while(curr != ")"){ - assert(curr.length() == 1); - E attribute = static_cast(curr.c_str()[0]); - is >> curr; - assert(curr == "="); - is >> curr; - this->_attributes.insert({attribute, {fix, std::stod(curr), Continuous}}); - is >> curr; - } - is >> curr; - assert(curr == "{"); - is >> curr; - this->_from = name_lookup.find(curr)->second; - this->_from->add_incident(this); - is >> curr; - this->_to = name_lookup.find(curr)->second; - this->_to->add_incident(this); - is >> curr; - assert(curr == "}"); -} - -template -std::ostream& operator<<(std::ostream& os, Edge& e){ - if(&os == &std::cout){ - os << "\033[0;32m"; - os << "Edge " << e.description() << " ( "; - for(std::pair pair : e.attributes()){ - os << static_cast(pair.first) << " = " << pair.second.value() << ", "; - } - os << ") {" << e.from()->description() << ", " << e.to()->description() << "}"; - os << "\033[0m"; - }else{ - os << "Edge " << e.description() << " ( "; - for(std::pair pair : e.attributes()){ - os << static_cast(pair.first) << " = " << pair.second.value() << " "; - } - os << " ) { " << e.from()->description() << " " << e.to()->description() << " }"; - } - - - return os; -} diff --git a/Graphtheory/Generators/random_attribute_generator.cpp b/Graphtheory/Generators/random_attribute_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..298a46cfb0e99c0166ac23042af8e98520bf3953 --- /dev/null +++ b/Graphtheory/Generators/random_attribute_generator.cpp @@ -0,0 +1,36 @@ +#include "random_attribute_generator.h" + +random_attribute_generator::random_attribute_generator( + std::map< + std::string, + std::tuple + > data +){ + for(std::pair > pair : data){ + assert(std::get<2>(pair.second) < std::get<3>(pair.second) ); + + std::pair constr_data = {std::get<0>(pair.second), std::get<1>(pair.second)}; + this->_constr_data.insert({pair.first, constr_data}); + if(constr_data.second == Integral){ + this->_integral_dist.insert({pair.first, std::uniform_int_distribution<>(std::get<2>(pair.second), std::get<3>(pair.second)) }); + }else{ + this->_continuous_dist.insert({pair.first, std::uniform_real_distribution<>(std::get<2>(pair.second), std::get<3>(pair.second)) }); + } + } +} + +std::map random_attribute_generator::next(){ + std::map instance; + for(std::pair > constr_pair : this->_constr_data){ + if(constr_pair.second.second == Integral){ + instance.insert({constr_pair.first, {constr_pair.second.first, (double) (this->_integral_dist.find(constr_pair.first)->second)(this->_engine), constr_pair.second.second}} ); + }else{ + instance.insert({constr_pair.first, {constr_pair.second.first, (this->_continuous_dist.find(constr_pair.first)->second)(this->_engine), constr_pair.second.second}}); + } + } + return instance; +} + +void random_attribute_generator::operator>>(std::map& var){ + var = this->next(); +} diff --git a/Graphtheory/Generators/random_attribute_generator.h b/Graphtheory/Generators/random_attribute_generator.h index be4ad1732fd6ddf37b6d62d9c4817b567ba8e13c..b6dbbe7e3f8bc4bff8b504eb4a90f91634ea8e9b 100644 --- a/Graphtheory/Generators/random_attribute_generator.h +++ b/Graphtheory/Generators/random_attribute_generator.h @@ -7,25 +7,23 @@ #include #include #include +#include #include "../Attribute.h" -template class random_attribute_generator{ std::default_random_engine _engine; - std::map _integrality; - std::map> _integral_dist; - std::map> _continuous_dist; + std::map> _constr_data; + std::map> _integral_dist; + std::map> _continuous_dist; public: - random_attribute_generator(std::map> ranges); + random_attribute_generator(std::map > data); - std::map next(); - void operator>>(std::map& var); + std::map next(); + void operator>>(std::map& var); }; -#include "random_attribute_generator.ipp" - #endif diff --git a/Graphtheory/Generators/random_attribute_generator.ipp b/Graphtheory/Generators/random_attribute_generator.ipp deleted file mode 100644 index edeae46acff4736a0d74ccb563480c88980786a2..0000000000000000000000000000000000000000 --- a/Graphtheory/Generators/random_attribute_generator.ipp +++ /dev/null @@ -1,32 +0,0 @@ -template -random_attribute_generator::random_attribute_generator(std::map> ranges){ - for(std::pair> pair : ranges){ - assert(std::get<1>(pair.second) < std::get<2>(pair.second)); - - integrality integrality = std::get<0>(pair.second); - this->_integrality.insert({pair.first, integrality}); - if(integrality == Integral){ - this->_integral_dist.insert({pair.first, std::uniform_int_distribution<>(std::get<1>(pair.second), std::get<2>(pair.second))}); - }else{ - this->_continuous_dist.insert({pair.first, std::uniform_real_distribution<>(std::get<1>(pair.second), std::get<2>(pair.second))}); - } - } -} - -template -std::map random_attribute_generator::next(){ - std::map instance; - for(std::pair inty_pair : this->_integrality){ - if(inty_pair.second == Integral){ - instance.insert({inty_pair.first, (this->_integral_dist.find(inty_pair.first)->second)(this->_engine)}); - }else{ - instance.insert({inty_pair.first, (this->_continuous_dist.find(inty_pair.first)->second)(this->_engine)}); - } - } - return instance; -} - -template -void random_attribute_generator::operator>>(std::map& var){ - var = this->next(); -} diff --git a/Graphtheory/Generators/random_graph_generator.cpp b/Graphtheory/Generators/random_graph_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ba997a413f07cee74def11a14b74d476d6eb281 --- /dev/null +++ b/Graphtheory/Generators/random_graph_generator.cpp @@ -0,0 +1,181 @@ +#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,{{},{}}}; +} diff --git a/Graphtheory/Generators/random_graph_generator.h b/Graphtheory/Generators/random_graph_generator.h index daa50cb371225a0f6d603676f24a3285bc00af20..f6246161b1f5dc702ec0555fe6bdfb53fd7ada6a 100644 --- a/Graphtheory/Generators/random_graph_generator.h +++ b/Graphtheory/Generators/random_graph_generator.h @@ -1,31 +1,41 @@ #include #include #include +#include #include -#include "../Basic_Graph.h" +#include "../Graph.h" #include "../../Common/random_set_element_generator.h" #include "random_attribute_generator.h" -template class random_graph_generator{ - std::map _default_values_node_attributes; - std::map _default_values_edge_attributes; + std::map _template_node_attributes; + std::map _template_edge_attributes; size_t _number_of_nodes; size_t _number_of_edges; - random_attribute_generator _node_generator; - random_attribute_generator _edge_generator; + random_attribute_generator _node_generator; + random_attribute_generator _edge_generator; public: - random_graph_generator(std::map default_values_edge_attributes, std::map default_values_node_attributes, size_t number_of_edges, random_attribute_generator edge_generator, size_t number_of_nodes, random_attribute_generator node_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 = {} + ); - Graph next_acyclic(); - Graph next(); - std::pair*, Node*>,Graph> next_acyclic_2_tips(); - void operator>>(Graph& var); + Graph next_acyclic(); + Graph next(); + std::pair, Graph> next_acyclic_2_tips(); + void operator>>(Graph& var); + + std::pair node_template(const std::string& attr) const; + std::pair edge_template(const std::string& attr) const; + + Attribute edge_template_throwing(const std::string& attr); + Attribute node_template_throwing(const std::string& attr); public: - static std::pair*>, std::vector*>>> 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); - static std::pair*>, std::vector*>>> 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); + static std::pair, std::vector>> 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); + static std::pair, std::vector>> 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); }; - -#include "random_graph_generator.ipp" diff --git a/Graphtheory/Generators/random_graph_generator.ipp b/Graphtheory/Generators/random_graph_generator.ipp deleted file mode 100644 index 1b726504a6b09afdb97f608d85e583e864121e09..0000000000000000000000000000000000000000 --- a/Graphtheory/Generators/random_graph_generator.ipp +++ /dev/null @@ -1,138 +0,0 @@ -template -random_graph_generator::random_graph_generator(std::map default_values_edge_attributes, std::map default_values_node_attributes, size_t number_of_edges, random_attribute_generator edge_generator, size_t number_of_nodes, random_attribute_generator node_generator) - : _default_values_node_attributes(default_values_node_attributes), _default_values_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) {} - -template -Graph random_graph_generator::next_acyclic(){ - Graph g (this->default_values_edge_attributes, this->default_values_edge_attributes); - while(!random_graph_generator::grow_random_acyclic(g, this->_number_of_nodes, this->_number_of_edges, this->_edge_generator, this->_node_generator)){ - std::cout << "generation failed; retrying!" << std::endl; - } - return g; -} - -template -Graph random_graph_generator::next(){ - Graph g (this->default_values_edge_attributes, this->default_values_edge_attributes); - while(!random_graph_generator::grow_random(g, this->_number_of_nodes, this->_number_of_edges, this->_edge_generator, this->_node_generator)){ - std::cout << "generation failed; retrying!" << std::endl; - } - return g; -} - -template -std::pair*, Node*>,Graph> random_graph_generator::next_acyclic_2_tips(){ - Graph g (this->_default_values_edge_attributes, this->_default_values_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 = tip_fringes(g, this->_edge_generator, this->_node_generator); - return {tips, std::move(g)}; -} - -template -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){ - added_nodes.push_back(g.add_node(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 = directed_admissible_st_path(g, n1, n2); - if(existing_path.first && existing_path.second.number_of_edges() <= 1) { - attempt++; - goto redo; - } - } - std::cout << "graph generation adding Edge" << std::endl; - added_edges.push_back(g.add_edge(n1, n2, 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,{{},{}}}; -} - -template //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(node_attribute_generator.next(), name.str())); - } - 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 || directed_admissible_st_path(g, n2, n1).first || directed_admissible_st_path(g, 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, edge_attribute_generator.next(), name.str())); - } - 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,{{},{}}}; -} diff --git a/Graphtheory/Graph.cpp b/Graphtheory/Graph.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7040926d53b2a26dbfd0dfdd24629a42d769c845 --- /dev/null +++ b/Graphtheory/Graph.cpp @@ -0,0 +1,8 @@ +#include "Graph.h" + +#include "Graph.ipp" +#include "Graph_fringe_operations.ipp" +#include "Graph_path_operations.ipp" +#include "Graph_special_members_and_operators.ipp" +#include "Graph_advanced.ipp" +#include "Graph_flow_algorithms.ipp" diff --git a/Graphtheory/Graph.h b/Graphtheory/Graph.h index 2a2ec1ba84cfcb2a310244a8d38bd86e7789f415..2a6737f4975e947df1863c9e7f6fb31b83b4d8c9 100644 --- a/Graphtheory/Graph.h +++ b/Graphtheory/Graph.h @@ -1,10 +1,151 @@ -#ifndef GRAPH_EXPORT -#define GRAPH_EXPORT +#ifndef GRAPH_H +#define GRAPH_H -#include "Basic_Graph.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Edge.h" +#include "Node.h" + +#include "Generators/random_attribute_generator.h" #include "Path.h" -#include "Graph_Operations/path_operations.ipp" -#include "Graph_Operations/fringe_graph_operations.ipp" -#include "Graph_Operations/flow_algorithms.ipp" + +enum Graphtheory_obj { + graph, + node, + edge +}; + +class Graph{ + std::set _edges; + std::set _nodes; + std::map _template_node_attributes; + std::map _template_edge_attributes; +public: + Graph(std::map default_values_edge_attributes = {}, std::map default_values_node_attributes = {}); + Graph(Graph& graph); + Graph(Graph&& graph); + + Edge* const add_edge(Node* from, Node* to, const std::string& description, const std::map& edge_attributes = {}); + Edge* const add_edge(Edge* remote_edge, const std::map& node_lookup); + Node* const add_node(std::string description, const std::map& node_attributes = {}); + Node* const add_node(Node* remote_node); + + void remove_node(Node* node); + void remove_edge(Edge* edge); + + // change to non reference return type? + std::set& edges(){ + return this->_edges; + } + std::set& nodes(){ + return this->_nodes; + } + + std::pair 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 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 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 in used Graph"; + throw std::range_error(text.str()); + } + return search->second; + } + + Attribute 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 in used Graph"; + throw std::range_error(text.str()); + } + return search->second; + } + + void reset_attribute_values(const std::set& edge_attr, const std::set& node_attr = {}); + + std::pair size(){ + return {this->_nodes.size(), this->_edges.size()}; + } + + ~Graph(){ + while(this->nodes().begin() != this->nodes().end()){ + this->remove_node(*this->nodes().begin()); + } + } + + // _path_operations + std::pair directed_admissible_st_path( + Node* s, Node* t, + std::function guide = [](Node* n, Edge* e)->bool {return e->from() == n;} + ); + std::pair directed_admissible_st_path( + Node* s, Node* t, + std::string opt_attr, + std::string lower_limit_attr, + std::string upper_limit_attr + ); + + // fringe_operations + std::vector select_targets(); + Node* tip_targets( + random_attribute_generator edge_attribute_generator = {{}}, + random_attribute_generator node_attribute_generator = {{}} + ); + std::vector select_sources(); + Node* tip_sources( + random_attribute_generator edge_attribute_generator = {{}}, + random_attribute_generator node_attribute_generator = {{}} + ); + std::pair tip_fringes(random_attribute_generator edge_attribute_generator = {{}}, random_attribute_generator node_attribute_generator = {{}}); + + // _advanced.cpp: + Graph(std::istream& is); + void conditional_bfs_all_components( + std::function edge_exec, + std::function node_exec, + std::deque starting_nodes = {}, + bool all_paths = false, + std::function guide = [](Node* n, Edge* e)->bool {return e->from() == n;} + ); + + // _flow_algorithms.cpp: + double ford_fulkerson(Node* s, Node* t, std::string opt_attr, std::string lower_limit_attr, std::string upper_limit_attr); + + + // _special_members_and_operators: + void operator=(const Graph& graph); + void operator=(Graph&& graph); +}; + +std::ostream& operator<<(std::ostream& os, Graph& g); + +std::istream& operator>>(std::istream& is, Graph& g); #endif diff --git a/Graphtheory/Graph.ipp b/Graphtheory/Graph.ipp new file mode 100644 index 0000000000000000000000000000000000000000..48b2f60b39851a356798677429cee8cecd96c21e --- /dev/null +++ b/Graphtheory/Graph.ipp @@ -0,0 +1,99 @@ +Graph::Graph(std::map default_values_edge_attributes, std::map default_values_node_attributes) : _template_node_attributes(std::move(default_values_node_attributes)), _template_edge_attributes(std::move(default_values_edge_attributes)){} + +Edge* const Graph::add_edge(Node* from, Node* to, const std::string& description, const std::map& edge_attributes){ + std::map unified_attr = this->_template_edge_attributes; + for(std::pair overriding_attr : edge_attributes){ + auto new_or_not = unified_attr.insert(overriding_attr); + if(new_or_not.second == false){ + new_or_not.first->second = overriding_attr.second; // test whether this actually works as intended + } + } + + Edge* const ptr = new Edge(from, to, description, unified_attr); + this->edges().insert(ptr); + return ptr; +} + +Edge* const Graph::add_edge(Edge* remote_edge, const std::map& node_lookup){ + Edge* const ptr = new Edge(*remote_edge, node_lookup); + this->edges().insert(ptr); + return ptr; +} + +Node* const Graph::add_node(std::string description, const std::map& node_attributes){ + std::map unified_attr = this->_template_node_attributes; + for(std::pair overriding_attr : node_attributes){ + auto new_or_not = unified_attr.insert(overriding_attr); + if(new_or_not.second == false){ + new_or_not.first->second = overriding_attr.second; // see above + } + } + + Node* const ptr = new Node(description, unified_attr); + this->nodes().insert(ptr); + return ptr; +} + +Node* const Graph::add_node(Node* remote_node){ + Node* const ptr = new Node(*remote_node); + this->nodes().insert(ptr); + return ptr; +} + +void Graph::remove_node(Node* node){ + for(Edge* e : node->incident()){ + this->edges().erase(e); + } + this->nodes().erase(node); // remove node pointer in graph + delete node; // removes pointers in node and edges & dealloc +} + +void Graph::remove_edge(Edge* edge){ + this->edges().erase(edge); + delete edge; +} + +void Graph::reset_attribute_values(const std::set& edge_attr, const std::set& node_attr){ + for(Node* n : this->nodes()){ + for(const std::string attr : node_attr){ + n->attribute_throwing(attr).value() = this->_template_node_attributes.find(attr)->second.value(); + } + } + + for(Edge* e : this->edges()){ + for(const std::string attr : edge_attr){ + e->attribute_throwing(attr).value() = this->_template_edge_attributes.find(attr)->second.value(); + } + } +} + +std::ostream& operator<<(std::ostream& os, Graph& g){ + if(&os == &std::cout){ + os << "\033[0;31m"; + os << "Graph { Nodes { \n"; + for(Node* n : g.nodes()){ + os << *n << "\n"; + } + os << "\033[0;31m"; + os << "} Edges {" << "\n"; + for(Edge* e : g.edges()){ + os << *e << "\n"; + } + os << "\033[0;31m"; + os << "} }"; + os << "\033[0m"; + }else{ + os << "Graph { Nodes { \n"; + for(Node* n : g.nodes()){ + os << *n << "\n"; + } + os << "} Edges {" << "\n"; + for(Edge* e : g.edges()){ + os << *e << "\n"; + } + os << "} }"; + } + return os; +} + +std::istream& operator>>(std::istream& is, Graph& g){g = Graph(is); return is;} diff --git a/Graphtheory/Graph_Operations/flow_algorithms.ipp b/Graphtheory/Graph_Operations/flow_algorithms.ipp deleted file mode 100644 index 78e94f158ec9690d231167c86c574ef4511fc190..0000000000000000000000000000000000000000 --- a/Graphtheory/Graph_Operations/flow_algorithms.ipp +++ /dev/null @@ -1,13 +0,0 @@ -template -double ford_fulkerson(Graph& g, Node* s, Node* t, E opt_attr, E lower_limit_attr, E upper_limit_attr){ - double value; - - while(true){ - auto path = directed_admissible_st_path(g, s,t, opt_attr, lower_limit_attr, upper_limit_attr); - if(!path.first) break; - - value += augment_edges_along_path(path.second, opt_attr, lower_limit_attr, upper_limit_attr); - } - - return value; -} diff --git a/Graphtheory/Graph_Operations/fringe_graph_operations.ipp b/Graphtheory/Graph_Operations/fringe_graph_operations.ipp deleted file mode 100644 index 488da2422562706a52246fa0dcfdd51795695d2e..0000000000000000000000000000000000000000 --- a/Graphtheory/Graph_Operations/fringe_graph_operations.ipp +++ /dev/null @@ -1,88 +0,0 @@ -#include - -#include "../Generators/random_attribute_generator.h" -/* - terminals -*/ - -template -bool is_terminal(Node* node){ - for(Edge* e : node->incident()){ - if(node == e->from()) return false; - } - return true; -} - -template -std::vector*> select_terminals(Graph& g){ - std::vector*> terminals; - for(Node* n : g.nodes()){ - if(is_terminal(n)){ - terminals.push_back(n); - } - } - return terminals; -} - -template -Node* tip_terminals(Graph& g, random_attribute_generator& edge_attribute_generator = random_attribute_generator({}), random_attribute_generator& node_attribute_generator = random_attribute_generator({})){ - std::vector*> terminals = select_terminals(g); - std::stringstream name; - name << g.size().first; - Node* t = g.add_node(node_attribute_generator.next(), name.str()); - for(Node* n : terminals){ - std::stringstream name; - name << n->description() << "_" << t->description(); - g.add_edge(n, t, edge_attribute_generator.next(), name.str()); - } - return t; -} - -/* - sources -*/ - -template -bool is_source(Node* node){ - for(Edge* e : node->incident()){ - if(node == e->to()) return false; - } - return true; -} - -template -std::vector*> select_sources(Graph& g){ - std::vector*> sources; - for(Node* n : g.nodes()){ - if(is_source(n)){ - sources.push_back(n); - } - } - return sources; -} - -template -Node* tip_sources(Graph& g, random_attribute_generator& edge_attribute_generator = random_attribute_generator({}), random_attribute_generator& node_attribute_generator = random_attribute_generator({})){ - std::vector*> sources = select_sources(g); - std::stringstream name; - name << g.size().first; - Node* s = g.add_node(node_attribute_generator.next(), name.str()); - for(Node* n : sources){ - std::stringstream name; - name << s->description() << "_" << n->description(); - g.add_edge(s, n, edge_attribute_generator.next(), name.str()); - } - return s; -} - -/* - tandem -*/ - -template -std::pair*, Node*> tip_fringes(Graph& g, random_attribute_generator& edge_attribute_generator = random_attribute_generator({}), random_attribute_generator& node_attribute_generator = random_attribute_generator({})){ - std::pair*, Node*> tips; - tips.first = tip_sources(g, edge_attribute_generator, node_attribute_generator); - tips.second = tip_terminals(g, edge_attribute_generator, node_attribute_generator); - return tips; -} diff --git a/Graphtheory/Graph_Operations/path_operations.ipp b/Graphtheory/Graph_Operations/path_operations.ipp deleted file mode 100644 index 513badb78cbc356b476cd559434c2020e989bcf7..0000000000000000000000000000000000000000 --- a/Graphtheory/Graph_Operations/path_operations.ipp +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -template -std::pair> directed_admissible_st_path(Graph& g, Node* s, Node* t, std::function* from, Edge* via)> guide = [](Node* n, Edge* e)->bool {return e->from() == n;}){ - std::map*, Edge*> predecessor; - std::queue*> active; - active.push(s); - - while(!active.empty()){ - Node* n = active.front(); active.pop(); - - if(predecessor.find(t) != predecessor.end()){ - break; - } - - for(Edge* e : n->incident()){ - if(predecessor.find(e->to(n)) == predecessor.end() && e->to(n) != s){ - if(guide(n, e)){ - predecessor.insert({e->to(n), e}); - active.push(e->to(n)); - } - } - } - } - - Path p = Path(&g, predecessor,t); - if(predecessor.find(t) == predecessor.end() && s != t){ - return {false, p}; - } - return {true, p}; -} - -template -std::pair> directed_admissible_st_path(Graph& g, Node* s, Node* t, E opt_attr, E lower_limit_attr, E upper_limit_attr){ - std::function*, Edge*)> f = [opt_attr, upper_limit_attr, lower_limit_attr](Node* n, Edge* e)->bool { - - return e->to(n) == e->to() ? ( 0 < e->attribute(opt_attr).optimization_direction()*(e->attribute(upper_limit_attr).value() - e->attribute(opt_attr).value()) ) : ( 0 < e->attribute(opt_attr).optimization_direction()*(e->attribute(opt_attr).value() - e->attribute(lower_limit_attr).value()) ); - - }; - return directed_admissible_st_path( - g, s, t, f - ); -} - -template -double best_along_path(Path& p, E opt_attr, E lower_limit_attr, E upper_limit_attr){ - opt_dir dir = p.graph()->edge_template(opt_attr).optimization_direction(); - auto it = p.begin(); - - auto slack = [opt_attr, lower_limit_attr, upper_limit_attr](const Node* n, Edge* e) -> double { - - return e->to(n) == e->to() ? ( e->attribute(opt_attr).optimization_direction()*(e->attribute(upper_limit_attr).value() - e->attribute(opt_attr).value()) ) : ( e->attribute(opt_attr).optimization_direction()*(e->attribute(opt_attr).value() - e->attribute(lower_limit_attr).value()) ); - - }; - - if(p.number_of_edges() == 0) return 0; - assert(dir == (*it).second->attribute(opt_attr).optimization_direction()); - double curr = slack((*it).first, (*it).second); - - while(++it != p.end()){ - assert(dir == (*it).second->attribute(opt_attr).optimization_direction()); - - curr = std::min(curr, slack((*it).first, (*it).second)); - } - - return curr*dir; -} - -template -double augment_edges_along_path(Path& p, E opt_attr, E lower_limit_attr, E upper_limit_attr){ - double best = best_along_path(p, opt_attr, lower_limit_attr, upper_limit_attr); - - for(Edge* e : p.edges()){ - e->attribute(opt_attr).value() += best; - } - - return best; -} diff --git a/Graphtheory/Basic_Graph_advanced.ipp b/Graphtheory/Graph_advanced.ipp similarity index 68% rename from Graphtheory/Basic_Graph_advanced.ipp rename to Graphtheory/Graph_advanced.ipp index 318088e6f7da3c749d514cbd68c54ced9d143735..8501ff2ae0f3718c02f193194e2873b35849bfd1 100644 --- a/Graphtheory/Basic_Graph_advanced.ipp +++ b/Graphtheory/Graph_advanced.ipp @@ -1,7 +1,5 @@ - -template -Graph::Graph(std::istream& is){ - std::map* > name_lookup; +Graph::Graph(std::istream& is){ + std::map name_lookup; std::string curr; is >> curr; assert(curr == "Graph"); @@ -15,7 +13,7 @@ Graph::Graph(std::istream& is){ is >> curr; while(curr == "Node"){ is.seekg(pos); - Node* tmp = new Node(is); + Node* tmp = new Node(is); name_lookup.insert({tmp->description(), tmp}); this->_nodes.insert(tmp); pos = is.tellg(); @@ -30,20 +28,20 @@ Graph::Graph(std::istream& is){ is >> curr; while(curr == "Edge"){ is.seekg(pos); - Edge* tmp = new Edge(is, name_lookup); + Edge* tmp = new Edge(is, name_lookup); this->_edges.insert(tmp); pos = is.tellg(); is >> curr; } } -template -void Graph::conditional_bfs_all_components( - std::function* from, Edge* via, bool used_in_traversal)> edge_exec, - std::function* via, Node* node)> node_exec, - std::deque*> starting_nodes, +void Graph::conditional_bfs_all_components( + std::function edge_exec, + std::function node_exec, + std::deque starting_nodes, bool all_paths, - std::function* from, Edge* via)> guide){ + std::function guide +){ /* executes edge_exec and node_exec for every edge or node in visiting order. Also executes for unused edges that test positive w.r.t guide !! possibly executes twice if guide allows !! @@ -52,21 +50,21 @@ void Graph::conditional_bfs_all_components( node_exec need to return true in order to continue traversal over its incident edges */ - std::set*> uncharted = this->nodes(); - std::deque*> active = starting_nodes; + std::set uncharted = this->nodes(); + std::deque active = starting_nodes; while(!uncharted.empty()){ if(active.empty()){ active.push_back(*uncharted.begin()); uncharted.erase(*uncharted.begin()); } - for(Node* manually_inserted_node : active){ + for(Node* manually_inserted_node : active){ node_exec(nullptr, manually_inserted_node); } while(!active.empty()){ - Node* n = active.front(); active.pop_front(); + Node* n = active.front(); active.pop_front(); - for(Edge* e : n->incident()){ + for(Edge* e : n->incident()){ bool used_in_traversal = false; if(guide(n, e)){ diff --git a/Graphtheory/Graph_flow_algorithms.ipp b/Graphtheory/Graph_flow_algorithms.ipp new file mode 100644 index 0000000000000000000000000000000000000000..e0bb5ae04da813afac52e7f6610eaebe6c2a4796 --- /dev/null +++ b/Graphtheory/Graph_flow_algorithms.ipp @@ -0,0 +1,14 @@ +double Graph::ford_fulkerson(Node* s, Node* t, std::string opt_attr, std::string lower_limit_attr, std::string upper_limit_attr){ + // this implementation currently does not respect validity of the resulting flow wrt lower_limit_attr, meaning that if flow 0 for instance the flow might not be valid + + double value = 0; + + while(true){ + auto path = this->directed_admissible_st_path(s,t, opt_attr, lower_limit_attr, upper_limit_attr); + if(!path.first) break; + + value += path.second.augment_edges_along_path(opt_attr, lower_limit_attr, upper_limit_attr); + } + + return value; +} diff --git a/Graphtheory/Graph_fringe_operations.ipp b/Graphtheory/Graph_fringe_operations.ipp new file mode 100644 index 0000000000000000000000000000000000000000..b9708665aa280d645218beb0b39066f96d221e0f --- /dev/null +++ b/Graphtheory/Graph_fringe_operations.ipp @@ -0,0 +1,66 @@ +/* + targets +*/ + +std::vector Graph::select_targets(){ + std::vector targets; + for(Node* n : this->nodes()){ + if(n->is_target()){ + targets.push_back(n); + } + } + return targets; +} + +Node* Graph::tip_targets(random_attribute_generator edge_attribute_generator, random_attribute_generator node_attribute_generator){ + std::vector targets = this->select_targets(); + std::stringstream name; + name << this->size().first; + Node* t = this->add_node(name.str(), node_attribute_generator.next()); + for(Node* n : targets){ + std::stringstream name; + name << n->description() << "_" << t->description(); + this->add_edge(n, t, name.str(), edge_attribute_generator.next()); + } + return t; +} + +/* + sources +*/ + + + +std::vector Graph::select_sources(){ + std::vector sources; + for(Node* n : this->nodes()){ + if(n->is_source()){ + sources.push_back(n); + } + } + return sources; +} + +Node* Graph::tip_sources(random_attribute_generator edge_attribute_generator, random_attribute_generator node_attribute_generator){ + std::vector sources = this->select_sources(); + std::stringstream name; + name << this->size().first; + Node* s = this->add_node(name.str(), node_attribute_generator.next()); + for(Node* n : sources){ + std::stringstream name; + name << s->description() << "_" << n->description(); + this->add_edge(s, n, name.str(), edge_attribute_generator.next()); + } + return s; +} + +/* + tandem +*/ + +std::pair Graph::tip_fringes(random_attribute_generator edge_attribute_generator, random_attribute_generator node_attribute_generator){ + std::pair tips; + tips.first = this->tip_sources(edge_attribute_generator, node_attribute_generator); + tips.second = this->tip_targets(edge_attribute_generator, node_attribute_generator); + return tips; +} diff --git a/Graphtheory/Graph_path_operations.ipp b/Graphtheory/Graph_path_operations.ipp new file mode 100644 index 0000000000000000000000000000000000000000..4c1c89dae340f4eb293adf5f216afbdc6830dead --- /dev/null +++ b/Graphtheory/Graph_path_operations.ipp @@ -0,0 +1,37 @@ +std::pair Graph::directed_admissible_st_path(Node* s, Node* t, std::function guide){ + std::map predecessor; + std::queue active; + active.push(s); + + while(!active.empty()){ + Node* n = active.front(); active.pop(); + + if(predecessor.find(t) != predecessor.end()){ + break; + } + + for(Edge* e : n->incident()){ + if(predecessor.find(e->to(n)) == predecessor.end() && e->to(n) != s){ + if(guide(n, e)){ + predecessor.insert({e->to(n), e}); + active.push(e->to(n)); + } + } + } + } + + Path p = Path(this, predecessor,t); + if(predecessor.find(t) == predecessor.end() && s != t){ + return {false, p}; + } + return {true, p}; +} + +std::pair Graph::directed_admissible_st_path(Node* s, Node* t, std::string opt_attr, std::string lower_limit_attr, std::string upper_limit_attr){ + std::function f = [opt_attr, upper_limit_attr, lower_limit_attr](Node* n, Edge* e)->bool { + + return e->to(n) == e->to() ? ( 0 < e->attribute_throwing(opt_attr).optimization_direction()*(e->attribute_throwing(upper_limit_attr).value() - e->attribute_throwing(opt_attr).value()) ) : ( 0 < e->attribute_throwing(opt_attr).optimization_direction()*(e->attribute_throwing(opt_attr).value() - e->attribute_throwing(lower_limit_attr).value()) ); + + }; + return this->directed_admissible_st_path(s, t, f); +} diff --git a/Graphtheory/Basic_Graph_special_members_and_operators.ipp b/Graphtheory/Graph_special_members_and_operators.ipp similarity index 62% rename from Graphtheory/Basic_Graph_special_members_and_operators.ipp rename to Graphtheory/Graph_special_members_and_operators.ipp index aaecbb88d7d3d44b699d7a3b0108ca4972e6b697..99660371f8e6be332b1cbaba350abf2383f444b8 100644 --- a/Graphtheory/Basic_Graph_special_members_and_operators.ipp +++ b/Graphtheory/Graph_special_members_and_operators.ipp @@ -1,10 +1,8 @@ -template -Graph::Graph(Graph& graph){ +Graph::Graph(Graph& graph){ *this = graph; } -template -Graph::Graph(Graph&& graph) +Graph::Graph(Graph&& graph) : _edges(std::move(graph._edges)), _nodes(std::move(graph._nodes)), _template_node_attributes(std::move(graph._template_node_attributes)), _template_edge_attributes(std::move(graph._template_edge_attributes)) { graph._nodes = {}; @@ -13,22 +11,23 @@ Graph::Graph(Graph&& graph) graph._template_edge_attributes = {}; } -template -void Graph::operator=(const Graph& graph){ - std::map*, Node*> node_lookup; +void Graph::operator=(const Graph& graph){ + this->_template_node_attributes = graph._template_node_attributes; + this->_template_edge_attributes = graph._template_edge_attributes; - for(Node* node : graph._nodes){ - Node* new_node = this->add_node(node); + std::map node_lookup; + + for(Node* node : graph._nodes){ + Node* new_node = this->add_node(node); node_lookup.insert({node, new_node}); } - for(Edge* edge : graph._edges){ + for(Edge* edge : graph._edges){ this->add_edge(edge, node_lookup); } } -template -void Graph::operator=(Graph&& graph){ +void Graph::operator=(Graph&& graph){ this->_edges = std::move(graph._edges); this->_nodes = std::move(graph._nodes); this->_template_node_attributes = std::move(graph._template_node_attributes); diff --git a/Graphtheory/Graphtheory.h b/Graphtheory/Graphtheory.h new file mode 100644 index 0000000000000000000000000000000000000000..47ed0c70a8bf312135f8d89468e8082246d197ae --- /dev/null +++ b/Graphtheory/Graphtheory.h @@ -0,0 +1,10 @@ +#ifndef GRAPH_EXPORT +#define GRAPH_EXPORT + +#include "Attribute.h" +#include "Graph.h" +#include "Path.h" +#include "Generators/random_graph_generator.h" +#include "Generators/random_attribute_generator.h" + +#endif diff --git a/Graphtheory/Node.cpp b/Graphtheory/Node.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd1921dac7af40f17cda82fb397a8ef628f4ba81 --- /dev/null +++ b/Graphtheory/Node.cpp @@ -0,0 +1,83 @@ +#include "Node.h" + +Node::Node(std::istream& is){ + std::string curr; + is >> curr; + assert(curr == "Node"); + + is >> this->_description; + + is >> curr; + assert(curr == "("); + is >> curr; + while(curr != ")"){ + std::string attribute = curr; + is >> curr; + assert(curr == "="); + is >> curr; + this->_attributes.insert({attribute, {fix, std::stod(curr), Continuous}}); + is >> curr; + } + is >> curr; + assert(curr == "{"); + size_t counter = 1; + while(counter != 0){ + + is >> curr; + if(curr == "{"){ + ++counter; + }else if(curr == "}"){ + --counter; + } + } +} + +bool Node::is_target() const { + for(Edge* e : this->incident()){ + if(this == e->from()) return false; + } + return true; +} + +bool Node::is_source() const { + for(Edge* e : this->incident()){ + if(this == e->to()) return false; + } + return true; +} + +Node::~Node(){ + while(this->incident().begin() != this->incident().end()){ + delete *this->incident().begin(); + } +} + +std::ostream& operator<<(std::ostream& os, Node& n){ + if(&os == &std::cout){ + os << "\033[0;36m"; + os << "Node " << n.description() << " ( "; + for(std::pair pair : n.attributes()){ + os << pair.first << " = " << pair.second.value() << ", "; + } + os << ") {\n \tEdges {\n"; + for(Edge* e : n.incident()){ + os << *e << "\n"; + } + os << "\033[0;36m"; + os << "} }"; + os << "\033[0m"; + }else{ + os << "Node " << n.description() << " ( "; + for(std::pair pair : n.attributes()){ + os << pair.first << " = " << pair.second.value() << ", "; + } + os << " ) {\n \tEdges {\n"; + for(Edge* e : n.incident()){ + os << *e << "\n"; + } + os << "} }"; + } + return os; +} + +std::istream& operator>>(std::istream& is, Node& n) { n = Node(is); return is;} diff --git a/Graphtheory/Node.h b/Graphtheory/Node.h index f452bf383f58e2a7e335ccff487f8610e43e796c..257d931088e335b0e3c74881943bee964120b23c 100644 --- a/Graphtheory/Node.h +++ b/Graphtheory/Node.h @@ -5,67 +5,92 @@ #include #include #include +#include #include "Attribute.h" +#include "Edge.h" +class Edge; -template class Edge; - -template class Node{ std::string _description; - std::set*> _incident; - std::map _attributes; + std::set _incident; + std::map _attributes; public: Node(){} - Node(std::map& default_attributes, std::map attributes = {}, std::string description = "") : _description(description), _attributes(default_attributes){ - for(std::pair pair : attributes){ - this->attribute(pair.first).value() = pair.second; - } - } - Node(Node& node) : _description(node.description()), _incident({}), _attributes(node.attributes()) {} + Node(const Node& node) : _description(node.description()), _incident({}), _attributes(node.attributes()) {} Node(Node&& node) : _description(std::move(node._description)), _incident(std::move(node._incident)), _attributes(std::move(node._attributes)) {} + + Node(std::string description, std::map attributes = {}) : _description(std::move(description)), _attributes(std::move(attributes)) {} Node(std::istream& is); - std::string description(){ - if(this->_description == ""){ - std::stringstream name; - name << this; - return name.str(); - } + void operator=(const Node& node) { + this->_description = node.description(); + this->_incident = {}; + this->_attributes = node.attributes(); + } + void operator=(Node&& node){ + this->_description = std::move(node._description); + this->_incident = std::move(node._incident); + this->_attributes = std::move(node._attributes); + } + + const std::string& description() const { + return this->_description; + } + + std::string& description(){ return this->_description; } - std::set*>& incident(){ + const std::set& incident() const { return this->_incident; } - Edge* add_incident(Edge* edge){ + std::set& incident() { + return this->_incident; + } + + const Edge* add_incident(Edge* edge){ this->_incident.insert(edge); return edge; } - std::map& attributes(){ - return this->_attributes; - } + const std::map& attributes() const { + return this->_attributes; + } - Attribute& attribute(N key){ - return this->_attributes.find(key)->second; + std::map& attributes() { + return this->_attributes; } - ~Node(){ - while(this->incident().begin() != this->incident().end()){ - delete *this->incident().begin(); + std::pair attribute(const std::string& attr) const { + auto search = this->_attributes.find(attr); + if(search == this->_attributes.end()){ + return {false, {fix, 0}}; } + return {true, search->second}; } -}; -template -std::ostream& operator<<(std::ostream& os, Node& n); -template -std::istream& operator>>(std::istream& is, Node& n) { n = Node(is); return is;} + Attribute& attribute_throwing(const std::string& attr){ + auto search = this->_attributes.find(attr); + if(search == this->_attributes.end()){ + std::stringstream text; + text << "\"" << attr << "\" is not defined for Node " << this->description(); + throw std::range_error(text.str()); + } + return search->second; + } + + bool is_target() const; + + bool is_source() const; + + ~Node(); +}; -#include "Node.ipp" +std::ostream& operator<<(std::ostream& os, Node& n); +std::istream& operator>>(std::istream& is, Node& n); #endif diff --git a/Graphtheory/Node.ipp b/Graphtheory/Node.ipp deleted file mode 100644 index a0c1abf994536d73f07a8d4b34975358cfdbc4a0..0000000000000000000000000000000000000000 --- a/Graphtheory/Node.ipp +++ /dev/null @@ -1,62 +0,0 @@ -template -Node::Node(std::istream& is){ - std::string curr; - is >> curr; - assert(curr == "Node"); - - is >> this->_description; - - is >> curr; - assert(curr == "("); - is >> curr; - while(curr != ")"){ - assert(curr.length() == 1); - N attribute = static_cast(curr.c_str()[0]); - is >> curr; - assert(curr == "="); - is >> curr; - this->_attributes.insert({attribute, {fix, std::stod(curr), Continuous}}); - is >> curr; - } - is >> curr; - assert(curr == "{"); - size_t counter = 1; - while(counter != 0){ - - is >> curr; - if(curr == "{"){ - ++counter; - }else if(curr == "}"){ - --counter; - } - } -} - -template -std::ostream& operator<<(std::ostream& os, Node& n){ - if(&os == &std::cout){ - os << "\033[0;36m"; - os << "Node " << n.description() << " ( "; - for(std::pair pair : n.attributes()){ - os << static_cast(pair.first) << " = " << pair.second.value() << ", "; - } - os << ") {\n \tEdges {\n"; - for(Edge* e : n.incident()){ - os << *e << "\n"; - } - os << "\033[0;36m"; - os << "} }"; - os << "\033[0m"; - }else{ - os << "Node " << n.description() << " ( "; - for(std::pair pair : n.attributes()){ - os << static_cast(pair.first) << " = " << pair.second.value() << ", "; - } - os << " ) {\n \tEdges {\n"; - for(Edge* e : n.incident()){ - os << *e << "\n"; - } - os << "} }"; - } - return os; -} diff --git a/Graphtheory/Path.cpp b/Graphtheory/Path.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3b03c20427ca9c4954debe9964eb0f9c994d8bd --- /dev/null +++ b/Graphtheory/Path.cpp @@ -0,0 +1,70 @@ +#include "Path.h" + +Path::Path(Graph* graph, std::map& successor_matrix, Node* start, bool invert_order) : _owner(graph){ + Node* curr = start; + + while(successor_matrix.find(curr) != successor_matrix.end()){ + if(!invert_order){ + this->edges().push_back(successor_matrix.find(curr)->second); + curr = this->edges().back()->to(curr); + }else{ + this->edges().push_front(successor_matrix.find(curr)->second); + curr = this->edges().front()->to(curr); + } + } + + if(!invert_order){ + this->_first = start; + this->_last = curr; + }else{ + this->_first = curr; + this->_last = start; + } +} + +double Path::best_along_path(std::string opt_attr, std::string lower_limit_attr, std::string upper_limit_attr){ + + opt_dir dir = this->graph()->edge_template_throwing(opt_attr).optimization_direction(); + iterator it = this->begin(); + + auto slack = [opt_attr, lower_limit_attr, upper_limit_attr](iterator it) -> double { + + return it->second->to(it->first) == it->second->to() ? ( it->second->attribute_throwing(opt_attr).optimization_direction()*(it->second->attribute_throwing(upper_limit_attr).value() - it->second->attribute_throwing(opt_attr).value()) ) : ( it->second->attribute_throwing(opt_attr).optimization_direction()*(it->second->attribute_throwing(opt_attr).value() - it->second->attribute_throwing(lower_limit_attr).value()) ); + + }; + + if(this->number_of_edges() == 0) return 0; + + + double curr = slack(it); + + while(++it != this->end()){ + curr = std::min(curr, slack(it)); + } + + return curr*dir; +} + +double Path::augment_edges_along_path(std::string opt_attr, std::string lower_limit_attr, std::string upper_limit_attr){ + double best = this->best_along_path(opt_attr, lower_limit_attr, upper_limit_attr); + + for(Edge* e : this->edges()){ + e->attribute_throwing(opt_attr).value() += best; + } + + return best; +} + +std::ostream& operator<<(std::ostream& os, Path& p){ + os << "\033[0;31m"; + std::cout << "Path: {" << "\n"; + auto it = p.edges().begin(); + while(it != p.edges().end()){ + std::cout << **it << "\n"; + it++; + } + os << "\033[0;31m"; + std::cout << "}"; + os << "\033[0m"; + return os; +} diff --git a/Graphtheory/Path.h b/Graphtheory/Path.h index b294e2899bf9477d1f47496f85328defedc42ec1..3ca4f99cd54709bc91fdd0a5c3db36184512e1b1 100644 --- a/Graphtheory/Path.h +++ b/Graphtheory/Path.h @@ -6,29 +6,33 @@ #include #include -template +#include "Node.h" +#include "Edge.h" + +class Graph; + class Path{ - Graph* _owner; - Node* _first; - Node* _last; - std::list*> _edges; + Graph* _owner; + Node* _first; + Node* _last; + std::list _edges; public: - Path(Graph* g, std::list*> edges) : _owner(g), _edges(edges){} - Path(Graph* g, std::map*, Edge*>& successor_matrix, Node* start, bool invert_order = true); + Path(Graph* g, std::list edges) : _owner(g), _edges(edges){} + Path(Graph* g, std::map& successor_matrix, Node* start, bool invert_order = true); - Graph* graph(){ + Graph* graph(){ return this->_owner; } - Node* first(){ + Node* first(){ return this->_first; } - Node* last(){ + Node* last(){ return this->_last; } - std::list*>& edges(){ + std::list& edges(){ return this->_edges; } @@ -36,24 +40,79 @@ public: return this->edges().size(); } + /* + optimization + */ + double best_along_path(std::string opt_attr, std::string lower_limit_attr, std::string upper_limit_attr); + double augment_edges_along_path(std::string opt_attr, std::string lower_limit_attr, std::string upper_limit_attr); + /* custom iterator */ + class iterator{ + Node* _current_node; + typename std::list::iterator _list_iterator; + typename std::list::iterator _end_iterator; + public: + iterator(const iterator& iter) : _current_node(iter._current_node), _list_iterator(iter._list_iterator), _end_iterator(iter._end_iterator) {} + iterator(Node* start_node, typename std::list::iterator start_list_iterator, typename std::list::iterator end_list_iterator) : _current_node(start_node), _list_iterator(start_list_iterator), _end_iterator(end_list_iterator) {} + + std::pair operator*(){ + if(this->_list_iterator == this->_end_iterator) throw std::range_error("dereferences ::end"); + return {this->_current_node, *this->_list_iterator}; + } + + const std::pair* operator->() const { + if(this->_list_iterator == this->_end_iterator) throw std::range_error("dereferences ::end"); + return new std::pair{(const Node*) this->_current_node, *this->_list_iterator}; + } + + iterator& operator++(){ + this->_current_node = (*this->_list_iterator)->to(this->_current_node); + ++this->_list_iterator; + return *this; + } + + iterator operator++(int){ + iterator iter (*this); + this->_current_node = (*this->_list_iterator)->to(this->_current_node); + ++this->_list_iterator; + return iter; + } + + void operator=(const iterator& iter){ + this->_current_node = iter._current_node; + this->_list_iterator = iter._list_iterator; + this->_end_iterator = iter._end_iterator; + } + + void operator=(iterator&& iter){ + this->_current_node = std::move(iter._current_node); + this->_list_iterator = std::move(iter._list_iterator); + this->_end_iterator = std::move(iter._end_iterator); + } + + friend bool operator==(iterator a, iterator b){ + return ( a._current_node == b._current_node && a._list_iterator == b._list_iterator && a._end_iterator == b._end_iterator); + } + + friend bool operator!=(iterator a, iterator b){ + return !(a == b); + } + }; - class iterator; iterator begin(){ - return iterator(this->first(), this->edges().begin(), this->edges().end()); + return {this->first(), this->edges().begin(), this->edges().end()}; } iterator end(){ - return iterator(this->last(), this->edges().end(), this->edges().end()); + return {this->last(), this->edges().end(), this->edges().end()}; } }; -template -std::ostream& operator<<(std::ostream& os, Path& p); +std::ostream& operator<<(std::ostream& os, Path& p); -#include "Path.ipp" +#include "Graph.h" #endif diff --git a/Graphtheory/Path.ipp b/Graphtheory/Path.ipp deleted file mode 100644 index 7423b1280d09a78b8dccdb15f1de15de6570e83f..0000000000000000000000000000000000000000 --- a/Graphtheory/Path.ipp +++ /dev/null @@ -1,73 +0,0 @@ -template -Path::Path(Graph* graph, std::map*, Edge*>& successor_matrix, Node* start, bool invert_order) : _owner(graph){ - Node* curr = start; - - while(successor_matrix.find(curr) != successor_matrix.end()){ - if(!invert_order){ - this->edges().push_back(successor_matrix.find(curr)->second); - curr = this->edges().back()->to(curr); - }else{ - this->edges().push_front(successor_matrix.find(curr)->second); - curr = this->edges().front()->to(curr); - } - } - - if(!invert_order){ - this->_first = start; - this->_last = curr; - }else{ - this->_first = curr; - this->_last = start; - } -} - -template -class Path::iterator{ - Node* _current_node; - typename std::list*>::iterator _list_iterator; - typename std::list*>::iterator _end_iterator; -public: - iterator(iterator& iter) : _current_node(iter._current_node), _list_iterator(iter._list_iterator) {} - iterator(Node* start_node, typename std::list*>::iterator start_list_iterator, typename std::list*>::iterator end_list_iterator) : _current_node(start_node), _list_iterator(start_list_iterator), _end_iterator(end_list_iterator) {} - - std::pair*, Edge*&> operator*(){ - if(this->_list_iterator == this->_end_iterator) throw std::range_error("dereferences ::end"); - return {this->_current_node, *this->_list_iterator}; - } - - iterator& operator++(){ - this->_current_node = (*this->_list_iterator)->to(this->_current_node); - ++this->_list_iterator; - return *this; - } - - iterator operator++(int){ - iterator iter (*this); - this->_current_node = (*this->_list_iterator)->to(this->_current_node); - ++this->_list_iterator; - return iter; - } - - friend bool operator==(iterator a, iterator b){ - return ( a._current_node == b._current_node && a._list_iterator == b._list_iterator && a._end_iterator == b._end_iterator); - } - - friend bool operator!=(iterator a, iterator b){ - return !(a == b); - } -}; - -template -std::ostream& operator<<(std::ostream& os, Path& p){ - os << "\033[0;31m"; - std::cout << "Path: {" << "\n"; - auto it = p.edges().begin(); - while(it != p.edges().end()){ - std::cout << **it << "\n"; - it++; - } - os << "\033[0;31m"; - std::cout << "}"; - os << "\033[0m"; - return os; -} diff --git a/Linear_Programming/lp_generator.cpp b/Linear_Programming/lp_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ee35332f389a91b22b94222ceb23ac83bbd65b7 --- /dev/null +++ b/Linear_Programming/lp_generator.cpp @@ -0,0 +1,129 @@ +#include "lp_generator.h" + +std::map lp_generator::lhs_from_data( + lhs_constraint_data& data, + + const std::map< + std::pair, + std::pair + >& edge_variable_lookup, + + const std::map< + std::pair, + std::pair + >& node_variable_lookup +){ + std::map lhs; + + for(std::pair, double> w : data.first){ + auto search_result = node_variable_lookup.find(w.first); + if(search_result == node_variable_lookup.end()) throw std::range_error("lp_generator::lhs_from_data use of undeclared variable in constraint generation! (node)"); + lhs.insert({search_result->second.first, {w.second}}); + } + for(std::pair, double> w : data.second){ + auto search_result = edge_variable_lookup.find(w.first); + if(search_result == edge_variable_lookup.end()) throw std::range_error("lp_generator::lhs_from_data use of undeclared variable in constraint generation! (edge)"); + lhs.insert({search_result->second.first, {w.second}}); + } + + return lhs; +} + + +std::pair< + std::map< + std::pair, + std::pair + >, + std::map< + std::pair, + std::pair + > +> + lp_generator::grow_from_graph +( + Linear_Program& lp, + + Graph& g, + + edge_constraint_data_generator edge_generator, + + node_constraint_data_generator node_generator, + + const std::vector< + std::pair< + std::string, + std::tuple< + integrality, + std::pair, + std::pair + > + > + > edge_var_data, + + const std::vector< + std::pair< + std::string, + std::tuple< + integrality, + std::pair, + std::pair + > + > + > node_var_data, + + std::string name_appendix +){ + Polyeder& p = lp.polyeder(); + std::map, std::pair> node_lookup; + std::map, std::pair> edge_lookup; + + // put inside conditional_bfs_all_components call as parameters; + std::function edge_function = [&p, &edge_lookup, &edge_var_data, name_appendix](Node* from, Edge* via, bool used_in_traversal) -> void { + for(std::pair, std::pair>> edge_prop : edge_var_data){ + std::stringstream name; + name << "edge_" << via->description() << "_" << edge_prop.first << "_" << name_appendix; + edge_lookup.insert({{via, edge_prop.first}, p.add_variable(Variable(name.str(), std::get<0>(edge_prop.second), std::get<1>(edge_prop.second), std::get<2>(edge_prop.second)))}); + } + }; + std::function node_function = [&p, &node_lookup, &node_var_data, name_appendix](Edge* via, Node* n) -> bool { + for(std::pair, std::pair>> node_prop : node_var_data){ + std::stringstream name; + name << "node_" << n->description() << "_" << node_prop.first << "_" << name_appendix; + node_lookup.insert({{n,node_prop.first}, p.add_variable(Variable(name.str(), std::get<0>(node_prop.second), std::get<1>(node_prop.second), std::get<2>(node_prop.second)))}); + } + return true; + }; + + g.conditional_bfs_all_components( + edge_function, + node_function + ); + + for(Node* n : g.nodes()){ + for(auto data : node_generator(n)){ + p.add_constraint( + Constraint( + std::get<0>(data), + std::get<1>(data), + lp_generator::lhs_from_data(std::get<2>(data), edge_lookup, node_lookup), + std::get<3>(data) + ) + ); + } + } + + for(Edge* e : g.edges()){ + for(auto data : edge_generator(e)){ + p.add_constraint( + Constraint( + std::get<0>(data), + std::get<1>(data), + lp_generator::lhs_from_data(std::get<2>(data), edge_lookup, node_lookup), + std::get<3>(data) + ) + ); + } + } + return {node_lookup, edge_lookup}; +} diff --git a/Linear_Programming/lp_generator.h b/Linear_Programming/lp_generator.h index d7e69611ca046ac323e61f237f763eed647e0251..3b687a3a64e10b077df0778a21b0c8d2edcda814 100644 --- a/Linear_Programming/lp_generator.h +++ b/Linear_Programming/lp_generator.h @@ -11,35 +11,103 @@ #include "../Linear_Programming/Linear_Program.h" #include "../Graphtheory/Graph.h" -template -using lhs_constraint_data = std::pair*,N>,double>>, std::vector*,E>,double>> >; -template -using constraint_data = std::tuple, double>; +using lhs_constraint_data = +std::pair< + std::vector< + std::pair< + std::pair, + double + > + >, + std::vector< + std::pair< + std::pair, + double + > + > +>; -template -using node_constraint_data_generator = std::function>(Node*)>; -template -using edge_constraint_data_generator = std::function>(Edge*)>; +using constraint_data = +std::tuple< + std::string, + relation, + lhs_constraint_data, + double +>; + + +using node_constraint_data_generator = +std::function< + std::vector(Node*) +>; + +using edge_constraint_data_generator = +std::function< + std::vector(Edge*) +>; class lp_generator{ - template static std::map lhs_from_data( - size_t start_index, size_t length, - lhs_constraint_data& data, - std::map*,E>, std::pair>& edge_variable_lookup, - std::map*,N>, std::pair>& node_variable_lookup + lhs_constraint_data& data, + + const std::map< + std::pair, + std::pair + >& edge_variable_lookup, + + const std::map< + std::pair, + std::pair + >& node_variable_lookup ); + public: - template - static std::pair*,N>, std::pair>, std::map*,E>, std::pair>> grow_from_graph( - Linear_Program& lp, Graph& g, - edge_constraint_data_generator edge_generator, node_constraint_data_generator node_generator, - std::vector, std::pair>> > edge_var_data, - std::vector, std::pair>> > node_var_data, + + static + std::pair< + std::map< + std::pair, + std::pair + >, + std::map< + std::pair, + std::pair + > + > + grow_from_graph( + Linear_Program& lp, + + Graph& g, + + edge_constraint_data_generator edge_generator, + + node_constraint_data_generator node_generator, + + const std::vector< + std::pair< + std::string, + std::tuple< + integrality, + std::pair, + std::pair + > + > + > edge_var_data, + + const std::vector< + std::pair< + std::string, + std::tuple< + integrality, + std::pair, + std::pair + > + > + > node_var_data, + std::string name_appendix ); -}; -#include "lp_generator.ipp" +}; #endif diff --git a/Linear_Programming/lp_generator.ipp b/Linear_Programming/lp_generator.ipp deleted file mode 100644 index 645d5e18ee53c698786928c7b5882c7a92f3e40e..0000000000000000000000000000000000000000 --- a/Linear_Programming/lp_generator.ipp +++ /dev/null @@ -1,81 +0,0 @@ -template -std::map lp_generator::lhs_from_data(size_t start_index, size_t length, lhs_constraint_data& data, std::map*,E>, std::pair>& edge_variable_lookup, std::map*,N>, std::pair>& node_variable_lookup){ - std::map lhs; - - for(std::pair*,N>, double> w : data.first){ - auto search_result = node_variable_lookup.find(w.first); - if(search_result == node_variable_lookup.end()) throw std::range_error("lp_generator::lhs_from_data use of undeclared variable in constraint generation! (node)"); - lhs.insert({search_result->second.first, {w.second}}); - } - for(std::pair*,E>, double> w : data.second){ - auto search_result = edge_variable_lookup.find(w.first); - if(search_result == edge_variable_lookup.end()) throw std::range_error("lp_generator::lhs_from_data use of undeclared variable in constraint generation! (edge)"); - lhs.insert({search_result->second.first, {w.second}}); - } - - return lhs; -} - -template -std::pair*,N>, std::pair>, std::map*,E>, std::pair>> lp_generator::grow_from_graph( - Linear_Program& lp, Graph& g, edge_constraint_data_generator edge_generator, node_constraint_data_generator node_generator, - std::vector, std::pair>> > edge_var_data, std::vector, std::pair>> > node_var_data, - std::string name_appendix - ) -{ - Polyeder& p = lp.polyeder(); - std::map*,N>, std::pair> node_lookup; - std::map*,E>, std::pair> edge_lookup; - - size_t start_index = p.vs_dim(); - - // put inside conditional_bfs_all_components call as parameters; - std::function* from, Edge* via, bool used_in_traversal)> edge_function = [&p, &edge_lookup, &edge_var_data, start_index, name_appendix](Node* from, Edge* via, bool used_in_traversal) -> void { - for(std::pair, std::pair>> edge_prop : edge_var_data){ - std::stringstream name; - name << "edge_" << via->description() << "_" << static_cast(edge_prop.first) << "_" << name_appendix; - edge_lookup.insert({{via, edge_prop.first}, p.add_variable(Variable(name.str(), std::get<0>(edge_prop.second), std::get<1>(edge_prop.second), std::get<2>(edge_prop.second)))}); - } - }; - std::function*, Node*)> node_function = [&p, &node_lookup, &node_var_data, start_index, name_appendix](Edge* via, Node* n) -> bool { - for(std::pair, std::pair>> node_prop : node_var_data){ - std::stringstream name; - name << "node_" << n->description() << "_" << static_cast(node_prop.first) << "_" << name_appendix; - node_lookup.insert({{n,node_prop.first}, p.add_variable(Variable(name.str(), std::get<0>(node_prop.second), std::get<1>(node_prop.second), std::get<2>(node_prop.second)))}); - } - return true; - }; - - g.conditional_bfs_all_components( - edge_function, - node_function - ); - - size_t length = p.vs_dim()-start_index; - for(Node* n : g.nodes()){ - for(auto data : node_generator(n)){ - p.add_constraint( - Constraint( - std::get<0>(data), - std::get<1>(data), - lp_generator::lhs_from_data(start_index, length, std::get<2>(data), edge_lookup, node_lookup), - std::get<3>(data) - ) - ); - } - } - - for(Edge* e : g.edges()){ - for(auto data : edge_generator(e)){ - p.add_constraint( - Constraint( - std::get<0>(data), - std::get<1>(data), - lp_generator::lhs_from_data(start_index, length, std::get<2>(data), edge_lookup, node_lookup), - std::get<3>(data) - ) - ); - } - } - return {node_lookup, edge_lookup}; -} diff --git a/Makefile b/Makefile index 945e4201cdebb4ce2ace2b226fb874dc6d888aff..cd7f35d718584bc2d2f0cc98bf66122c4931907b 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ LP_PROBLEMS_DEP := $(patsubst %.cpp,%.o,$(shell find -type f -wholename "./Speci COMMON_DEP := $(patsubst %.cpp,%.o,$(shell find -type f -wholename "./Common_Types/*")) GRAPH_OUT := $(patsubst %.cpp,%.o,$(shell find -wholename "./Graphtheory/*.cpp")) -LP_OUT := $(patsubst %.cpp,%.o,$(shell find -wholename "./Linear_Programming/*.cpp")) +LP_OUT := $(filter-out %lp_generator.o,$(patsubst %.cpp,%.o,$(shell find -wholename "./Linear_Programming/*.cpp"))) LP_PROBLEMS_OUT := $(patsubst %.cpp,%.o,$(shell find -wholename "./Specialization/LP_Problems/*.cpp")) COMMON_OUT := $(patsubst %.cpp,%.o,$(shell find -wholename "./Common_Types/*.cpp")) @@ -15,6 +15,8 @@ COMMON_OUT := $(patsubst %.cpp,%.o,$(shell find -wholename "./Common_Types/*.cpp all: graph_test ass_test linear_program_test maintenance_problem_test +OUTS := + #Graph Test graph_test: graph_test.o $(GRAPH_OUT) $(CXX) $(CXXFLAGS) $^ -o $@ @@ -41,7 +43,7 @@ linear_program_test.o: linear_programming_test.cpp ./Linear_Programming/Linear_P $(CXX) $(CXXFLAGS) -c $< -o $@ -maintenance_problem_test: maintenance_problem_test.o $(LP_PROBLEMS_OUT) $(LP_OUT) $(GRAPH_OUT) +maintenance_problem_test: maintenance_problem_test.o $(LP_PROBLEMS_OUT) $(LP_OUT) $(GRAPH_OUT) Linear_Programming/lp_generator.o $(CXX) $(CXXFLAGS) $^ -o $@ maintenance_problem_test.o: maintenance_problem_test.cpp ./Specialization/LP_Problems/maintenance_problem_generator.o $(GRAPH_DEP) $(COMMON_DEP) $(LP_DEP) $(LP_PROBLEMS_DEP) @@ -59,10 +61,11 @@ Coefficient_dep := Variable.o Monomial.o Monomial_dep := Variable.o maintenance_problem_generator_dep := Maintenance_Problem.o Maintenance_Problem_crossdep := Linear_Programming/Linear_Program.o $(GRAPH_DEP) -$(GRAPH_OUT) $(LP_OUT) $(LP_PROBLEMS_OUT) $(COMMON_OUT): $$(patsubst %.o,%.cpp,$$@) $$(patsubst %.o,%.h,$$@) $$(addprefix $$(@D)/,$$($$(patsubst %.o,%_dep,$$(@F)))) $$($$(patsubst %.o,%_crossdep,$$(@F))) +$(GRAPH_OUT) $(LP_OUT) $(LP_PROBLEMS_OUT) $(COMMON_OUT): $$(patsubst %.o,%.cpp,$$@) $$(patsubst %.o,%.h,$$@) $$(addprefix $$(@D)/,$$($$(patsubst %.o,%_dep,$$(@F)))) $$($$(patsubst %.o,%_crossdep,$$(@F))) #$$(addprefix $$(@D)/,$$(filter-out %include,$$(shell grep "include \"" $$(patsubst %.o,%.h,$$@) | tr -d '\"'))) $(CXX) $(CXXFLAGS) -c $(patsubst %.o, %.cpp, $@) -o $@ + .PHONY: clean clean: diff --git a/Specialization/Graph_Specialization/CircSelect_Network.h b/Specialization/Graph_Specialization/CircSelect_Network.h deleted file mode 100644 index 8dd1f30057ca70db75ff3de30e59b17eb73f076d..0000000000000000000000000000000000000000 --- a/Specialization/Graph_Specialization/CircSelect_Network.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef CIRCSELECT_H -#define CIRCSELECT_H - -#include "../../Graphtheory/Graph.h" - -typedef enum{} CircSelectNodeFields; -typedef enum : char {Flow = 'f', Demand = 'l', Capacity = 'u', Critical = 's'} CircSelectEdgeFields; -typedef Node CircSelectNode; -typedef Edge CircSelectEdge; -typedef Path CircSelectPath; -typedef Graph CircSelectNetwork; - -#endif diff --git a/Specialization/Graph_Specialization/Circulation_Network.h b/Specialization/Graph_Specialization/Circulation_Network.h deleted file mode 100644 index e7dd17bd449b89ccce2c4f37368231766db19e40..0000000000000000000000000000000000000000 --- a/Specialization/Graph_Specialization/Circulation_Network.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef CIRCULATION_H -#define CIRCULATION_H - -#include "../../Graphtheory/Graph.h" - -typedef enum{} CirculationNodeFields; -typedef enum : char {Flow = 'f', Demand = 'l', Capacity = 'u', Cost = 'c'} CirculationEdgeFields; -typedef Node CirculationNode; -typedef Edge CirculationEdge; -typedef Path CirculationPath; -typedef Graph CirculationNetwork; - -#endif diff --git a/Specialization/LP_Problems/Maintenance_Problem.cpp b/Specialization/LP_Problems/Maintenance_Problem.cpp index 2f222c3957f8a282e47f18278ee4ee24aa2f250c..8a14d903ed11ad94bb317818b1fee3b48a0fea58 100644 --- a/Specialization/LP_Problems/Maintenance_Problem.cpp +++ b/Specialization/LP_Problems/Maintenance_Problem.cpp @@ -1,21 +1,45 @@ #include "Maintenance_Problem.h" -Maintenance_Problem::Maintenance_Problem() : Linear_Program(true) {} +Maintenance_Problem::Maintenance_Problem() : Linear_Program(true), _g({{"Flow", Attribute(max, 0)},{"Upper", Attribute(fix, 1)}, {"Selected", Attribute(fix, 0)}}) { -Maintenance_Problem::Maintenance_Problem(Maintenance_Problem& mp) : Linear_Program(mp) { - this->_g = mp._g; - mp._g = CircSelectNetwork(); } -Maintenance_Problem::Maintenance_Problem(Maintenance_Problem&& mp) : Linear_Program(std::move(mp)) { - this->_g = std::move(mp._g); - mp._g = CircSelectNetwork(); +Maintenance_Problem::Maintenance_Problem(Maintenance_Problem& mp) : Linear_Program(mp), _g(mp._g) { + mp._g = Graph(); +} + +Maintenance_Problem::Maintenance_Problem(Maintenance_Problem&& mp) : Linear_Program(std::move(mp)), _g(std::move(mp._g)) { + mp._g = Graph(); } -Maintenance_Problem::Maintenance_Problem(CircSelectNetwork& g, CircSelectNode* source, CircSelectNode* target, std::set critical, size_t intervals) +Maintenance_Problem::Maintenance_Problem( + Graph& g, Node* source, + Node* target, + std::set critical, + size_t intervals +) : Linear_Program(true), _g(g) { - std::vector, std::pair>, std::map, std::pair> >> lookup; + for(std::string attr : std::vector({"Selected", "Upper", "Flow"})){ + if(!this->_g.edge_template(attr).first) { + std::cout << this->_g << std::endl; + throw std::invalid_argument("Maintenance_Problem needs Graph with predetermined attributes present"); + } + } + + + std::vector< + std::pair< + std::map< + std::pair, + std::pair + >, + std::map< + std::pair, + std::pair + > + > + > lookup; /* flow conservation constraints for all epochs @@ -23,35 +47,35 @@ Maintenance_Problem::Maintenance_Problem(CircSelectNetwork& g, CircSelectNode* s for(size_t epoch = 0; epoch < intervals; ++epoch){ std::stringstream name_appendix; name_appendix << "epoch_" << epoch; - lookup.push_back(lp_generator::grow_from_graph( + lookup.push_back(lp_generator::grow_from_graph( *this, g, - [&critical, epoch](CircSelectEdge* edge) -> std::vector> { + [&critical, epoch](Edge* edge) -> std::vector { std::stringstream capacity_name; capacity_name << "edge_" << edge->description() << "_capacity_epoch_" << epoch; std::stringstream non_critical_fix; non_critical_fix << "edge_" << edge->description() << "_non_critical_epoch_" << epoch; - std::vector> constraints; + std::vector constraints; if(critical.find(edge) == critical.end()){ - constraints.push_back({capacity_name.str(), Inequality, {{}, {{{edge, Flow}, 1}}}, edge->attribute(Capacity).value()}); - constraints.push_back({non_critical_fix.str(), Equality, {{}, {{{edge, Critical}, 1}}}, 0}); + constraints.push_back({capacity_name.str(), Inequality, {{}, {{{edge, "Flow"}, 1}}}, edge->attribute_throwing("Upper").value()}); + constraints.push_back({non_critical_fix.str(), Equality, {{}, {{{edge, "Selected"}, 1}}}, 0}); }else{ - constraints.push_back({capacity_name.str(), Inequality, {{}, {{{edge, Flow}, 1},{{edge,Critical}, edge->attribute(Capacity).value()}}}, edge->attribute(Capacity).value()}); + constraints.push_back({capacity_name.str(), Inequality, {{}, {{{edge, "Flow"}, 1},{{edge,"Selected"}, edge->attribute_throwing("Upper").value()}}}, edge->attribute_throwing("Upper").value()}); } return constraints; }, - [source, target, &critical, epoch](CircSelectNode* node) -> std::vector> { + [source, target, &critical, epoch](Node* node) -> std::vector { if(node == source || node == target) return {}; std::stringstream name; name << "node_" << node->description() << "_flow_conservation_epoch_" << epoch; - lhs_constraint_data lhs = {{},{}}; - for(CircSelectEdge* edge : node->incident()){ - lhs.second.push_back({{edge,Flow}, (edge->to() == node ? 1 : -1) }); + lhs_constraint_data lhs = {{},{}}; + for(Edge* edge : node->incident()){ + lhs.second.push_back({{edge,"Flow"}, (edge->to() == node ? 1 : -1) }); } return {{name.str(), Equality, lhs, 0}}; }, - {{Flow, {Continuous, {true, 0}, {false, 0}}}, {Critical, {Integral, {true, 0}, {true, 1}}}}, + {{"Flow", {Continuous, {true, 0}, {false, 0}}}, {"Selected", {Integral, {true, 0}, {true, 1}}}}, {}, name_appendix.str() )); @@ -60,10 +84,10 @@ Maintenance_Problem::Maintenance_Problem(CircSelectNetwork& g, CircSelectNode* s /* critical edges processed */ - for(CircSelectEdge* e : critical){ + for(Edge* e : critical){ std::map lhs; for(auto lookup_during_epoch : lookup){ - lhs.insert({lookup_during_epoch.second.find({e, Critical})->second.first, {1}}); + lhs.insert({lookup_during_epoch.second.find({e, "Selected"})->second.first, {1}}); } std::stringstream name; name << "critical_edge_" << e->description() << "_processed"; @@ -85,8 +109,8 @@ Maintenance_Problem::Maintenance_Problem(CircSelectNetwork& g, CircSelectNode* s for(size_t epoch = 0; epoch < intervals; ++epoch){ auto lookup_during_epoch = lookup[epoch]; std::map lhs; - for(CircSelectEdge* e : source->incident()){ - lhs.insert({lookup_during_epoch.second.find({e, Flow})->second.first, {-1}}); + for(Edge* e : source->incident()){ + lhs.insert({lookup_during_epoch.second.find({e, "Flow"})->second.first, {-1}}); } lhs.insert({target_var.first, {1}}); @@ -105,20 +129,20 @@ Maintenance_Problem::Maintenance_Problem(CircSelectNetwork& g, CircSelectNode* s this->add_direction_coefficient({target_var.first, 1}); } -CircSelectNetwork& Maintenance_Problem::network(){ +Graph& Maintenance_Problem::network(){ return this->_g; } void Maintenance_Problem::operator=(Maintenance_Problem& mp){ this->Linear_Program::operator=(mp); this->_g = mp._g; - mp._g = CircSelectNetwork(); + mp._g = Graph(); } void Maintenance_Problem::operator=(Maintenance_Problem&& mp){ this->Linear_Program::operator=(mp); this->_g = std::move(mp._g); - mp._g = CircSelectNetwork(); + mp._g = Graph(); } std::ostream& operator<<(std::ostream& os, Maintenance_Problem& mp){ diff --git a/Specialization/LP_Problems/Maintenance_Problem.h b/Specialization/LP_Problems/Maintenance_Problem.h index 82bfa16554cb5a621eaa6788a0f2c0508c8f4471..ec1a83b6dbf99fa2dae74ead2bd91cf92445358b 100644 --- a/Specialization/LP_Problems/Maintenance_Problem.h +++ b/Specialization/LP_Problems/Maintenance_Problem.h @@ -5,19 +5,19 @@ #include #include -#include "../../Specialization/Graph_Specialization/CircSelect_Network.h" +#include "../../Graphtheory/Graphtheory.h" #include "../../Linear_Programming/Linear_Program.h" #include "../../Linear_Programming/lp_generator.h" class Maintenance_Problem : public Linear_Program { - CircSelectNetwork _g; + Graph _g; public: Maintenance_Problem(); Maintenance_Problem(Maintenance_Problem& mp); Maintenance_Problem(Maintenance_Problem&& mp); - Maintenance_Problem(CircSelectNetwork& g, CircSelectNode* source, CircSelectNode* target, std::set critical, size_t intervals); + Maintenance_Problem(Graph& g, Node* source, Node* target, std::set critical, size_t intervals); - CircSelectNetwork& network(); + Graph& network(); void operator=(Maintenance_Problem& mp); void operator=(Maintenance_Problem&& mp); diff --git a/Specialization/LP_Problems/maintenance_problem_generator.cpp b/Specialization/LP_Problems/maintenance_problem_generator.cpp index ffbcffac90b6f0d7ae07e2da12289ed4af7699b3..1150c6bcdd44c285e86f03f044dd7c821d2d1ea3 100644 --- a/Specialization/LP_Problems/maintenance_problem_generator.cpp +++ b/Specialization/LP_Problems/maintenance_problem_generator.cpp @@ -1,21 +1,25 @@ #include "maintenance_problem_generator.h" -maintenance_problem_generator::maintenance_problem_generator(random_graph_generator graph_generator, size_t number_of_critical_edges, size_t length_of_interval) - : _graph_generator(graph_generator), _number_of_critical_edges(number_of_critical_edges), _length_of_interval(length_of_interval) {} +maintenance_problem_generator::maintenance_problem_generator(random_graph_generator graph_generator, size_t number_of_critical_edges, size_t length_of_interval) + : _graph_generator(graph_generator), _number_of_critical_edges(number_of_critical_edges), _length_of_interval(length_of_interval) { + for(std::string attr : std::vector({"Selected", "Upper", "Flow"})){ + if(!this->_graph_generator.edge_template(attr).first) throw std::invalid_argument("Maintenance_Problem needs Graph with predetermined attributes present"); + } + } Maintenance_Problem maintenance_problem_generator::next(){ - std::pair, CircSelectNetwork> stg = this->_graph_generator.next_acyclic_2_tips(); + std::pair, Graph> stg = this->_graph_generator.next_acyclic_2_tips(); - std::set critical_edges; - random_set_element_generator set_gen (&stg.second.edges()); + std::set critical_edges; + random_set_element_generator set_gen (&stg.second.edges()); for(size_t i = 0; i < this->_number_of_critical_edges; i++){ - CircSelectEdge* curr = set_gen.next(); + Edge* curr = set_gen.next(); while(critical_edges.find(curr) != critical_edges.end()){ set_gen >> curr; } critical_edges.insert(curr); - curr->attribute(Critical).value() = true; + curr->attribute_throwing("Selected").value() = true; } return Maintenance_Problem(stg.second, stg.first.first, stg.first.second, critical_edges, this->_length_of_interval); diff --git a/Specialization/LP_Problems/maintenance_problem_generator.h b/Specialization/LP_Problems/maintenance_problem_generator.h index 29136f3e7cad3b9fab733efa2ed52a6422a42272..baef2ba082f859b502334ceb916abb5522c4ecf9 100644 --- a/Specialization/LP_Problems/maintenance_problem_generator.h +++ b/Specialization/LP_Problems/maintenance_problem_generator.h @@ -1,13 +1,15 @@ +#include "stdexcept" + #include "Maintenance_Problem.h" -#include "../Graph_Specialization/CircSelect_Network.h" -#include "../../Graphtheory/Generators/random_graph_generator.h" +#include "../../Graphtheory/Graphtheory.h" + class maintenance_problem_generator{ - random_graph_generator _graph_generator; + random_graph_generator _graph_generator; size_t _number_of_critical_edges; size_t _length_of_interval; public: - maintenance_problem_generator(random_graph_generator graph_generator, size_t number_of_critical_edges, size_t length_of_interval); + maintenance_problem_generator(random_graph_generator graph_generator, size_t number_of_critical_edges, size_t length_of_interval); Maintenance_Problem next(); void operator>>(Maintenance_Problem& mp); diff --git a/assertion_test.cpp b/assertion_test.cpp index d062d911c0dc2a210faba702815e57f1c0f46361..ec43d9b9bf49db0dfecdf1232d78597db1a67f52 100644 --- a/assertion_test.cpp +++ b/assertion_test.cpp @@ -1,32 +1,32 @@ #include #include #include +#include -#include "Specialization/Graph_Specialization/Circulation_Network.h" -#include "Graphtheory/Generators/random_graph_generator.h" +#include "Graphtheory/Graphtheory.h" int main(){ - std::map defaults = {{Flow, Attribute(max, 0)}, {Demand, Attribute(fix, 0)}, {Capacity, Attribute(fix, 1)},{Cost, Attribute(fix, 0)}}; - random_attribute_generator rand_edges ({{Capacity, {Integral, 0, 5}}}); - random_attribute_generator rand_nodes ({}); + std::map defaults = {{"Flow", Attribute(max, 0)}, {"Demand", Attribute(fix, 0)}, {"Capacity", Attribute(fix, 1)},{"Cost", Attribute(fix, 0)}}; + random_attribute_generator rand_edges ({{"Capacity", {fix, Integral, 0, 5}}}); + random_attribute_generator rand_nodes ({}); while(true){ - CirculationNetwork g(defaults); - while(!random_graph_generator::grow_random(g, 5, 7, rand_edges, rand_nodes).first){ + Graph g(defaults); + while(!random_graph_generator::grow_random(g, 5, 7, rand_edges, rand_nodes).first){ std::cout << "failed graph generation" << std::endl; }; std::cout << "successfull generation" << std::endl; - std::pair m = tip_fringes(g, rand_edges, rand_nodes); - CirculationNode* s = m.first; - CirculationNode* t = m.second; + std::pair m = g.tip_fringes(rand_edges, rand_nodes); + Node* s = m.first; + Node* t = m.second; // Choose arbitrary subset - random_set_element_generator set_gen (&g.edges()); - std::set critical_edges; + random_set_element_generator set_gen (&g.edges()); + std::set critical_edges; size_t num_critical_edges = 4; assert(num_critical_edges <= g.edges().size()); for(size_t i = 0; i < num_critical_edges; i++){ - CirculationEdge* curr = set_gen.next(); + Edge* curr = set_gen.next(); while(critical_edges.find(curr) != critical_edges.end()){ set_gen >> curr; } @@ -37,19 +37,19 @@ int main(){ // Check Property bool property = true; - for(CirculationEdge* e : critical_edges){ + for(Edge* e : critical_edges){ e->disconnect(); } - if(directed_admissible_st_path(g, s, t).first) property = false; - for(CirculationEdge* e1 : critical_edges){ - for(CirculationEdge* e2 : critical_edges){ + if(g.directed_admissible_st_path(s, t).first) property = false; + for(Edge* e1 : critical_edges){ + for(Edge* e2 : critical_edges){ if(e1 == e2) continue; if(!property) break; - if(directed_admissible_st_path(g, e1->to(), e2->from()).first) property = false; + if(g.directed_admissible_st_path(e1->to(), e2->from()).first) property = false; } } - for(CirculationEdge* e : critical_edges){ + for(Edge* e : critical_edges){ e->reconnect(); } @@ -57,19 +57,19 @@ int main(){ // std::cout << g << std::endl; // std::cout << "critical edges: " << std::endl; - // for(CirculationEdge* e : critical_edges){ + // for(Edge* e : critical_edges){ // std::cout << *e << std::endl; // } // // break; // Determine 1-Optimal and 2-Optimal Edges - std::pair> opt1 = {0, {}}; - for(CirculationEdge* e1 : critical_edges){ + std::pair> opt1 = {0, {}}; + for(Edge* e1 : critical_edges){ e1->disconnect(); - double tmp = ford_fulkerson(g,s,t, Flow, Demand, Capacity); - g.reset_attribute_values({Flow}); + double tmp = g.ford_fulkerson(s, t, "Flow", "Demand", "Capacity"); + g.reset_attribute_values({"Flow"}); if(std::abs(tmp-opt1.first) < 1e-100){ opt1.second.insert(e1); @@ -80,17 +80,17 @@ int main(){ e1->reconnect(); } - std::pair> > opt2 = {0,{}}; - for(CirculationEdge* e1 : critical_edges){ + std::pair> > opt2 = {0,{}}; + for(Edge* e1 : critical_edges){ e1->disconnect(); - for(CirculationEdge* e2 : critical_edges){ + for(Edge* e2 : critical_edges){ if(e1 == e2) continue; e2->disconnect(); - double tmp = ford_fulkerson(g,s,t, Flow, Demand, Capacity); - g.reset_attribute_values({Flow}); + double tmp = g.ford_fulkerson(s, t, "Flow", "Demand", "Capacity"); + g.reset_attribute_values({"Flow"}); if(std::abs(tmp-opt2.first) < 1e-100 ){ opt2.second.insert({e1,e2}); @@ -108,8 +108,8 @@ int main(){ checking whether 1-optimal edge stays 2-optimal when no two critical edges are reachable */ bool assertion = true; - for(CirculationEdge* e : opt1.second){ - for(std::set c : opt2.second){ + for(Edge* e : opt1.second){ + for(std::set c : opt2.second){ if(c.find(e) != c.end()){ assertion = true; } @@ -128,17 +128,17 @@ int main(){ std::cout << g << std::endl; std::cout << "critical edges: " << std::endl; - for(CirculationEdge* e : critical_edges){ + for(Edge* e : critical_edges){ std::cout << *e << std::endl; } std::cout << "1-optimal: \n Value: " << opt1.first << std::endl; - for(CirculationEdge* e : opt1.second){ + for(Edge* e : opt1.second){ std::cout << *e << std::endl; } std::cout << "2-optimal: \n Value: " << opt2.first << std::endl; - for(std::set s : opt2.second){ + for(std::set s : opt2.second){ std::cout << "{" << std::endl; std::cout << **s.begin() << std::endl; std::cout << **(++s.begin()) << std::endl; diff --git a/graph_test.cpp b/graph_test.cpp index 49532a7416493549c4dbb760c623dcf60034270f..ac6a6923626d50ea7145ab743e117a618b00cf9f 100644 --- a/graph_test.cpp +++ b/graph_test.cpp @@ -1,28 +1,28 @@ -#include "Specialization/Graph_Specialization/Circulation_Network.h" +#include "Graphtheory/Graph.h" #include "Graphtheory/Generators/random_graph_generator.h" #include #include int main(){ - CirculationNetwork g({{Flow, Attribute(max, 0)}, {Demand, Attribute(fix, 0)}, {Capacity, Attribute(fix, 1)},{Cost, Attribute(fix, 0)}}); + Graph g({{"f", Attribute(max, 0)}, {"l", Attribute(fix, 0)}, {"u", Attribute(fix, 1)} }); std::cout << g << std::endl; - random_attribute_generator rand_gen_edge ({{Capacity, {Integral, 0, 5}}}); - random_attribute_generator rand_gen_node ({}); + random_attribute_generator rand_gen_edge ({{"u", {fix, Integral, 0, 5}}}); + random_attribute_generator rand_gen_node ({}); - while(!random_graph_generator::grow_random_acyclic(g,5,7, rand_gen_edge, rand_gen_node).first){ + while(!random_graph_generator::grow_random_acyclic(g, 5, 7, rand_gen_edge, rand_gen_node).first){ std::cout << "failed attempt" << std::endl; }; - auto m = tip_fringes(g, rand_gen_edge, rand_gen_node); + auto m = g.tip_fringes(rand_gen_edge, rand_gen_node); std::cout << g << std::endl; std::cout << "Source: \n" << *m.first << std::endl; std::cout << "Target: \n" << *m.second << std::endl; - std::cout << "MaxFlow: " << ford_fulkerson(g, m.first, m.second, Flow, Demand, Capacity) << std::endl; + std::cout << "MaxFlow: " << g.ford_fulkerson(m.first, m.second, "f", "l", "u") << std::endl; std::cout << g << std::endl; @@ -32,8 +32,12 @@ int main(){ ofs_graph << g << std::endl; ofs_graph.close(); + std::stringstream command; + command << "cd ../display/graph_display/ && (./graph_display --file ../../discrete_optimization_library/" << path.str() << " &) && cd ../../discrete_optimization_library"; + system(command.str().c_str()); + std::ifstream ifs_graph(path.str()); - CirculationNetwork g2 (ifs_graph); + Graph g2 (ifs_graph); std::cout << g2 << std::endl; return 0; diff --git a/maintenance_problem_test.cpp b/maintenance_problem_test.cpp index d0160d1c5812ff57018f01e6a578ba7f05513197..d9962e6958034c4684a5a557d144a90d25a17815 100644 --- a/maintenance_problem_test.cpp +++ b/maintenance_problem_test.cpp @@ -8,13 +8,12 @@ int main(){ maintenance_problem_generator mpg ( - random_graph_generator( - {{Flow, Attribute(max, 0)}, {Demand, Attribute(fix, 0)}, {Capacity, Attribute(fix, 1)}, {Critical, Attribute(fix, 0)}}, - {}, + random_graph_generator( 4, - random_attribute_generator({ {Capacity, {Integral, 1, 5}} }), 4, - random_attribute_generator({}) + random_attribute_generator({ {"Upper", {fix, Integral, 1, 5}} }), + random_attribute_generator({}), + {{"Flow", Attribute(max, 0)},{"Upper", Attribute(fix, 1)}, {"Selected", Attribute(fix, 0)}} ), 3, 2 ); @@ -24,6 +23,7 @@ int main(){ Maintenance_Problem mp; mpg >> mp; + std::ofstream ofs_graph("./.data/Maintenance_Problem/mp.netw"); ofs_graph << mp.network() << std::endl; ofs_graph.close();