Commit 16b3fcfb authored by jonasseidel's avatar jonasseidel

more const correctness and an overhaul of the path data structure

parent e31b2f71
#include "Edge.h"
Edge::Edge(const Edge& remote_edge, const std::map<Node*, 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) {
Edge::Edge(const Edge& remote_edge, const std::map<const Node*, 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);
}
......@@ -50,7 +50,7 @@ void Edge::reconnect(){
this->to()->incident().insert(this);
}
std::ostream& operator<<(std::ostream& os, Edge& e){
std::ostream& operator<<(std::ostream& os, const Edge& e){
if(&os == &std::cout){
os << "\033[0;32m";
os << "Edge " << e.description() << " ( ";
......
......@@ -24,7 +24,7 @@ class Edge{
public:
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*, Node*>& node_lookup);
Edge(const Edge& remote_edge, const std::map<const Node*, Node*>& node_lookup);
Edge(Node* from, Node* to, std::string description, std::map<std::string, Attribute> attributes = {});
Edge(std::istream& is, const std::map<std::string, Node* >& name_lookup);
......@@ -37,21 +37,21 @@ public:
return this->_description;
}
Node* const & from() const {
Node* from() const {
return this->_from;
}
Node*& from() {
return this->_from;
}
Node* const & to() const {
Node* to() const {
return this->_to;
}
Node*& to() {
return this->_to;
}
Node* const & to(const Node* node) const {
Node* 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();
}
......@@ -63,6 +63,7 @@ public:
const std::map<std::string, Attribute>& attributes() const {
return this->_attributes;
}
std::map<std::string, Attribute>& attributes() {
return this->_attributes;
}
......@@ -85,6 +86,16 @@ public:
return search->second;
}
const Attribute& attribute_throwing(const std::string& attr) const {
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();
void reconnect();
......@@ -109,6 +120,6 @@ public:
void dump();
};
std::ostream& operator<<(std::ostream& os, Edge& e);
std::ostream& operator<<(std::ostream& os, const Edge& e);
#endif
......@@ -30,8 +30,12 @@ std::pair<std::pair<Node*, Node*>,Graph> random_graph_generator::next_acyclic_2_
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)};
auto [source, target] = g.tip_fringes(this->_edge_generator, this->_node_generator);
source->add_attribute("Source", Attribute({fix, 1, Integral}) );
target->add_attribute("Target", Attribute({fix, 1, Integral}) );
return {{source, target}, std::move(g)};
}
std::pair<std::pair<Node*, Node*>, Graph> random_graph_generator::next_acyclic_in_steps_2_tips(size_t steps, size_t fading){
......@@ -39,8 +43,12 @@ std::pair<std::pair<Node*, Node*>, Graph> random_graph_generator::next_acyclic_i
while(!random_graph_generator::grow_random_acyclic_in_steps(g, this->_number_of_nodes/steps, this->_number_of_edges/steps, steps, fading, 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)};
auto [source, target] = g.tip_fringes(this->_edge_generator, this->_node_generator);
source->add_attribute("Source", Attribute({fix, 1, Integral}) );
target->add_attribute("Target", Attribute({fix, 1, Integral}) );
return {{source, target}, std::move(g)};
}
......
......@@ -37,10 +37,10 @@ public:
Graph(Graph& graph);
Graph(Graph&& graph);
Edge* const add_edge(Node* from, Node* to, const std::string& description, const std::map<std::string,Attribute>& edge_attributes = {});
Edge* const add_edge(Edge* remote_edge, const std::map<Node*, Node*>& node_lookup);
Node* const add_node(std::string description, const std::map<std::string, Attribute>& node_attributes = {});
Node* const add_node(Node* remote_node);
Edge* add_edge(Node* from, Node* to, const std::string& description, const std::map<std::string,Attribute>& edge_attributes = {});
Edge* add_edge(const Edge* remote_edge, const std::map<const Node*, Node*>& node_lookup);
Node* add_node(std::string description, const std::map<std::string, Attribute>& node_attributes = {});
Node* add_node(const Node* remote_node);
void remove_node(Node* node);
void remove_edge(Edge* edge);
......@@ -53,7 +53,14 @@ public:
return this->_nodes;
}
std::pair<bool, Attribute> node_template(const std::string& attr) const{
std::set<const Edge*> edges() const {
return std::set<const Edge*>(this->_edges.begin(), this->_edges.end());
}
std::set<const Node*> nodes() const {
return std::set<const Node*>(this->_nodes.begin(), this->_nodes.end());
}
std::pair<bool, Attribute> node_template(const std::string& attr) const{ // TODO: change to returning iterator to support external manipulation and proper const functions
auto search = this->_template_node_attributes.find(attr);
if(search == this->_template_node_attributes.end()){
return {false, {fix, 0}};
......@@ -69,7 +76,27 @@ public:
return {true, search->second};
}
Attribute edge_template_throwing(const std::string& attr){
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;
}
const Attribute& edge_template_throwing(const std::string& attr) const {
auto search = this->_template_edge_attributes.find(attr);
if(search == this->_template_edge_attributes.end()){
std::stringstream text;
......@@ -79,7 +106,7 @@ public:
return search->second;
}
Attribute node_template_throwing(const std::string& attr){
const Attribute& node_template_throwing(const std::string& attr) const {
auto search = this->_template_node_attributes.find(attr);
if(search == this->_template_node_attributes.end()){
std::stringstream text;
......@@ -106,6 +133,10 @@ public:
Node* s, Node* t,
std::function<bool(Node* from, Edge* via)> guide = [](Node* n, Edge* e)->bool {return e->from() == n;}
);
std::pair<bool, const Path> directed_admissible_st_path(
const Node* s, const Node* t,
std::function<bool(const Node* from, const Edge* via)> guide = [](const Node* n, const Edge* e)->bool {return e->from() == n;}
) const ;
std::pair<bool, Path> directed_admissible_st_path(
Node* s, Node* t,
std::string opt_attr,
......@@ -116,15 +147,19 @@ public:
// _select_opertations
std::set<Edge*> gather_edges(std::vector<std::string> attributes);
std::set<Node*> gather_nodes(std::vector<std::string> attributes);
std::set<const Edge*> gather_edges(std::vector<std::string> attributes) const ;
std::set<const Node*> gather_nodes(std::vector<std::string> attributes) const ;
// fringe_operations
std::vector<Node*> select_targets();
std::vector<const Node*> select_targets() const ;
Node* tip_targets(
random_attribute_generator edge_attribute_generator = {{}},
random_attribute_generator node_attribute_generator = {{}}
);
std::vector<Node*> select_sources();
std::vector<const Node*> select_sources() const ;
Node* tip_sources(
random_attribute_generator edge_attribute_generator = {{}},
random_attribute_generator node_attribute_generator = {{}}
......@@ -140,6 +175,14 @@ public:
bool all_paths = false,
std::function<bool(Node* from, Edge* via)> guide = [](Node* n, Edge* e)->bool {return e->from() == n;}
);
void conditional_bfs_all_components(
std::function<void(const Node* from, const Edge* via, bool used_in_traversal)> edge_exec,
std::function<bool(const Edge* via, const Node* node)> node_exec,
std::deque<const Node*> starting_nodes = {},
bool all_paths = false,
std::function<bool(const Node* from, const Edge* via)> guide = [](const Node* n, const Edge* e)->bool {return e->from() == n;}
) const ;
// _flow_algorithms.cpp:
double ford_fulkerson(Node* s, Node* t, std::string opt_attr, std::string lower_limit_attr, std::string upper_limit_attr);
......@@ -147,19 +190,19 @@ public:
// _special_members_and_operators:
void operator=(const Graph& graph);
std::pair< Graph, std::map<Node*, Node*> > copy_ret_lookup() const;
std::pair< Graph, std::map<const Node*, Node*> > copy_ret_lookup() const;
void operator=(Graph&& graph);
// _debug_helpers (Graph.ipp)
void dump();
// friendships:
friend std::ostream& operator<<(std::ostream& os, Graph& g);
friend std::ostream& operator<<(std::ostream& os, const Graph& g);
friend std::istream& operator>>(std::istream& is, Graph& g);
};
std::ostream& operator<<(std::ostream& os, Graph& g);
std::ostream& operator<<(std::ostream& os, const Graph& g);
std::istream& operator>>(std::istream& is, Graph& g);
......
Graph::Graph(std::map<std::string, Attribute> default_values_edge_attributes, std::map<std::string, Attribute> 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<std::string, Attribute>& edge_attributes){
Edge* Graph::add_edge(Node* from, Node* to, const std::string& description, const std::map<std::string, Attribute>& edge_attributes){
std::map<std::string, Attribute> unified_attr = this->_template_edge_attributes;
for(std::pair<std::string, Attribute> overriding_attr : edge_attributes){
auto new_or_not = unified_attr.insert(overriding_attr);
......@@ -9,18 +9,18 @@ Edge* const Graph::add_edge(Node* from, Node* to, const std::string& description
}
}
Edge* const ptr = new Edge(from, to, description, unified_attr);
Edge* 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*, Node*>& node_lookup){
Edge* const ptr = new Edge(*remote_edge, node_lookup);
Edge* Graph::add_edge(const Edge* remote_edge, const std::map<const Node*, Node*>& node_lookup){
Edge* ptr = new Edge(*remote_edge, node_lookup);
this->edges().insert(ptr);
return ptr;
}
Node* const Graph::add_node(std::string description, const std::map<std::string, Attribute>& node_attributes){
Node* Graph::add_node(std::string description, const std::map<std::string, Attribute>& node_attributes){
std::map<std::string, Attribute> unified_attr = this->_template_node_attributes;
for(std::pair<std::string, Attribute> overriding_attr : node_attributes){
auto new_or_not = unified_attr.insert(overriding_attr);
......@@ -29,13 +29,13 @@ Node* const Graph::add_node(std::string description, const std::map<std::string,
}
}
Node* const ptr = new Node(description, unified_attr);
Node* 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);
Node* Graph::add_node(const Node* remote_node){
Node* ptr = new Node(*remote_node);
this->nodes().insert(ptr);
return ptr;
}
......@@ -67,16 +67,16 @@ void Graph::reset_attribute_values(const std::set<std::string>& edge_attr, const
}
}
std::ostream& operator<<(std::ostream& os, Graph& g){
std::ostream& operator<<(std::ostream& os, const Graph& g){
if(&os == &std::cout){
os << "\033[0;31m";
os << "Graph { Nodes { \n";
for(Node* n : g.nodes()){
for(const Node* n : g.nodes()){
os << *n << "\n";
}
os << "\033[0;31m";
os << "} Edges {" << "\n";
for(Edge* e : g.edges()){
for(const Edge* e : g.edges()){
os << *e << "\n";
}
os << "\033[0;31m";
......@@ -84,11 +84,11 @@ std::ostream& operator<<(std::ostream& os, Graph& g){
os << "\033[0m";
}else{
os << "Graph { Nodes { \n";
for(Node* n : g.nodes()){
for(const Node* n : g.nodes()){
os << *n << "\n";
}
os << "} Edges {" << "\n";
for(Edge* e : g.edges()){
for(const Edge* e : g.edges()){
os << *e << "\n";
}
os << "} \nNode_Defaults { ";
......
......@@ -112,3 +112,55 @@ void Graph::conditional_bfs_all_components(
}
}
}
void Graph::conditional_bfs_all_components(
std::function<void(const Node* from, const Edge* via, bool used_in_traversal)> edge_exec,
std::function<bool(const Edge* via, const Node* node)> node_exec,
std::deque<const Node*> starting_nodes,
bool all_paths,
std::function<bool(const Node* from, const Edge* via)> guide
) const {
/*
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 !!
node_exec will be called with nullptr for via for start node
node_exec might be called with nullptr for via if the graph is not strongly connected
if node_exec returns true traversal over its incident edges will be forced no matter their visitation status
*/
std::set<const Node*> uncharted = this->nodes();
std::deque<std::pair<const Edge*, const Node*>> active;
for(const Node* node : starting_nodes){
active.push_back({nullptr, node});
}
while(!uncharted.empty()){
if(active.empty()){
active.push_back({nullptr, *uncharted.begin()});
uncharted.erase(*uncharted.begin());
}
while(!active.empty()){
std::pair<const Edge*, const Node*> next = active.front(); active.pop_front();
bool local_all_paths = node_exec(next.first, next.second);
const Node* n = next.second;
for(const Edge* e : n->incident()){
bool used_in_traversal = false;
if(guide(n, e)){
if(uncharted.find(e->to(n)) != uncharted.end() || all_paths || local_all_paths) {
used_in_traversal = true;
active.push_back({e, e->to(n)});
uncharted.erase(e->to(n));
}
edge_exec(n, e, used_in_traversal);
}
}
}
}
}
......@@ -2,10 +2,28 @@
targets
*/
std::vector<Node*> Graph::select_targets(){
std::vector<Node*> Graph::select_targets(){ // TODO: rename to terminal / extreme or similar
std::vector<Node*> targets;
for(Node* n : this->nodes()){
if(n->is_target()){
for(Node* n : this->_nodes){
bool is_terminal_target = true;
for(Edge* e : n->incident()){
if(n == e->from()) is_terminal_target = false;
}
if(is_terminal_target){
targets.push_back(n);
}
}
return targets;
}
std::vector<const Node*> Graph::select_targets() const {
std::vector<const Node*> targets;
for(Node* n : this->_nodes){
bool is_terminal_target = true;
for(Edge* e : n->incident()){
if(n == e->from()) is_terminal_target = false;
}
if(is_terminal_target){
targets.push_back(n);
}
}
......@@ -42,8 +60,26 @@ Node* Graph::tip_targets(random_attribute_generator edge_attribute_generator, ra
std::vector<Node*> Graph::select_sources(){
std::vector<Node*> sources;
for(Node* n : this->nodes()){
if(n->is_source()){
for(Node* n : this->_nodes){
bool is_terminal_source = true;
for(Edge* e : n->incident()){
if(n == e->to()) is_terminal_source = false;
}
if(is_terminal_source){
sources.push_back(n);
}
}
return sources;
}
std::vector<const Node*> Graph::select_sources() const {
std::vector<const Node*> sources;
for(Node* n : this->_nodes){
bool is_terminal_source = true;
for(Edge* e : n->incident()){
if(n == e->to()) is_terminal_source = false;
}
if(is_terminal_source){
sources.push_back(n);
}
}
......
std::pair<bool, Path> Graph::directed_admissible_st_path(Node* s, Node* t, std::function<bool(Node* from, Edge* via)> guide){
std::map<const Node*, Edge*> predecessor;
std::unordered_map<Node*, Edge*> predecessor;
std::queue<Node*> active;
active.push(s);
......@@ -20,7 +20,7 @@ std::pair<bool, Path> Graph::directed_admissible_st_path(Node* s, Node* t, std::
}
}
Path p = Path(this, predecessor,t);
Path p = Path(this, predecessor, t);
if(predecessor.find(t) == predecessor.end() && s != t){
return {false, p};
}
......@@ -35,3 +35,8 @@ std::pair<bool, Path> Graph::directed_admissible_st_path(Node* s, Node* t, std::
};
return this->directed_admissible_st_path(s, t, f);
}
std::pair<bool, const Path> Graph::directed_admissible_st_path(const Node* s, const Node* t, std::function<bool(const Node* from, const Edge* via)> guide) const {
std::cout << "calling path creation method for const graph" << std::endl;
return const_cast<Graph*>(this)->directed_admissible_st_path(const_cast<Node*>(s), const_cast<Node*>(t), [guide](Node* from, Edge* via){return guide(from, via);});
}
......@@ -29,3 +29,34 @@ std::set<Node*> Graph::gather_nodes(std::vector<std::string> attributes){
return nodes;
}
std::set<const Edge*> Graph::gather_edges(std::vector<std::string> attributes) const {
std::set<const Edge*> edges;
for(Edge* e : this->_edges){
for(std::string attribute_name : attributes){
auto attribute_search = e->attribute(attribute_name);
if(attribute_search.first && attribute_search.second.value()){
edges.insert(e);
}
}
}
return edges;
}
std::set<const Node*> Graph::gather_nodes(std::vector<std::string> attributes) const {
std::set<const Node*> nodes;
for(Node* n : this->_nodes){
for(std::string attribute_name : attributes){
auto attribute_search = n->attribute(attribute_name);
if(attribute_search.first && attribute_search.second.value()){
nodes.insert(n);
}
}
}
return nodes;
}
......@@ -11,17 +11,17 @@ Graph::Graph(Graph&& graph)
graph._template_edge_attributes = {};
}
std::pair< Graph, std::map<Node*, Node*> > Graph::copy_ret_lookup() const{
std::pair< Graph, std::map<const Node*, Node*> > Graph::copy_ret_lookup() const{
Graph copy (this->_template_edge_attributes, this->_template_node_attributes);
std::map<Node*, Node*> node_lookup;
std::map<const Node*, Node*> node_lookup;
for(Node* node : this->_nodes){
for(const Node* node : this->_nodes){
Node* new_node = copy.add_node(node);
node_lookup.insert({node, new_node});
}
for(Edge* edge : this->_edges){
for(const Edge* edge : this->_edges){
copy.add_edge(edge, node_lookup);
}
......
......@@ -31,7 +31,7 @@ Node::Node(std::istream& is){
}
}
}
/*
bool Node::is_target() const {
for(Edge* e : this->incident()){
if(this == e->from()) return false;
......@@ -45,14 +45,14 @@ bool Node::is_source() const {
}
return true;
}
*/
Node::~Node(){
while(this->incident().begin() != this->incident().end()){
delete *this->incident().begin();
}
}
std::ostream& operator<<(std::ostream& os, Node& n){
std::ostream& operator<<(std::ostream& os, const Node& n){
if(&os == &std::cout){
os << "\033[0;36m";
os << "Node " << n.description() << " ( ";
......
......@@ -85,17 +85,28 @@ public:
return search->second;
}
Attribute& add_attribute(const std::string attr_name, Attribute attr){
auto [iter, success] = this->_attributes.insert({attr_name, attr});
if(!success) {
std::stringstream text;
text << "\"" << attr << "\" is could not be added to Node " << this->description();
throw std::range_error(text.str());
}
return iter->second;
}
/*
bool is_target() const;
bool is_source() const;
*/
~Node();
// _debug_helpers
void dump();
};
std::ostream& operator<<(std::ostream& os, Node& n);
std::ostream& operator<<(std::ostream& os, const Node& n);
std::istream& operator>>(std::istream& is, Node& n);
#endif
#include "Path.h"
#include <cfloat>
Path::Path(Graph* graph, std::unordered_map<Node*, Edge*>& successor_matrix, Node* start, bool invert_order) : _owner(graph){
std::unordered_map<Node*, Edge*>& given_dir = this->_next_edge;
std::unordered_map<Node*, Edge*>& opposing_dir = this->_prev_edge;
if(invert_order){
given_dir = this->_prev_edge;
opposing_dir = this->_next_edge;
}
Path::Path(Graph* graph, std::map<const Node*, Edge*>& successor_matrix, Node* start, bool invert_order) : _owner(graph){
Node* curr = start;
auto curr_iter = successor_matrix.find(curr);
while(curr_iter != successor_matrix.end()){
given_dir.insert({curr, curr_iter->second});
opposing_dir.insert({curr_iter->second->to(curr), curr_iter->second});
while(successor_matrix.find(curr) != successor_matrix.end()){
if(!invert_order){
this->edges().push_back(successor_matrix.find