Program Listing for File graph.hpp#
↰ Return to documentation for file (source/pele/graph.hpp)
#ifndef _GRAPH_CPP_H_
#define _GRAPH_CPP_H_
/*
* This implements a lightweight directed graph. This was primarily designed
* for use in the New Graph Transformation (NGT) method. This graph was
* optimized for the following actions to be as fast as possible
*
* * removing nodes
* * iteration over out edges
* * iteration over in edges
* * return the edge u->v
* * access node property `double `
* * access edge property `double P`
* * allow for loop edges u->u
* * copy graph
*
* The requirement for fast removing of nodes means I can't assign each node
* an index and use std::vector's. This is at odds with fast access to the edge
* u->v. The solution here is to use a std::map Node.successor_edge_
*/
#include <assert.h>
#include <cstdlib>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <set>
#include <stdexcept>
namespace pele {
class Edge;
class Node;
typedef size_t node_id;
typedef Node *node_ptr;
typedef Edge *edge_ptr;
typedef int color_type;
static color_type color_white = 0;
static color_type color_grey = 1;
static color_type color_black = 4;
class Edge {
public:
node_ptr head_; // node the edge points to
node_ptr tail_; // node the edge comes from
double P;
Edge(node_ptr tail, node_ptr head) : head_(head), tail_(tail) {}
node_ptr head() { return head_; }
node_ptr tail() { return tail_; }
};
class Node {
public:
typedef std::set<edge_ptr> edge_list;
typedef typename edge_list::iterator edge_iterator;
typedef std::map<node_ptr, edge_ptr> successor_map_t;
private:
node_id id_;
edge_list out_edge_list_; // list of outgoing edges
edge_list in_edge_list_; // list of outgoing edges
public:
successor_map_t successor_map_;
double tau;
Node(node_id id) : id_(id) {}
void add_out_edge(edge_ptr edge) {
out_edge_list_.insert(edge);
successor_map_[edge->head()] = edge;
}
void remove_out_edge(edge_ptr edge) {
out_edge_list_.erase(edge);
successor_map_.erase(edge->head());
}
edge_list &get_out_edges() { return out_edge_list_; }
edge_iterator out_edge_begin() { return out_edge_list_.begin(); }
edge_iterator out_edge_end() { return out_edge_list_.end(); }
void add_in_edge(edge_ptr edge) { in_edge_list_.insert(edge); }
void remove_in_edge(edge_ptr edge) { in_edge_list_.erase(edge); }
edge_list &get_in_edges() { return in_edge_list_; }
edge_iterator in_edge_begin() { return in_edge_list_.begin(); }
edge_iterator in_edge_end() { return in_edge_list_.end(); }
node_id id() const { return id_; }
size_t out_degree() const { return out_edge_list_.size(); }
size_t in_degree() const { return in_edge_list_.size(); }
size_t in_out_degree() const { return out_degree() + in_degree(); }
inline std::set<node_ptr> in_out_neighbors();
/*
* return the edge u->v
*/
edge_ptr get_successor_edge(node_ptr v) {
successor_map_t::iterator miter = successor_map_.find(v);
if (miter == successor_map_.end()) {
return NULL;
} else {
return miter->second;
}
}
};
inline std::set<node_ptr> Node::in_out_neighbors() {
std::set<node_ptr> neibs;
Node::edge_iterator eiter;
for (eiter = out_edge_begin(); eiter != out_edge_end(); eiter++) {
neibs.insert((*eiter)->head());
}
for (eiter = in_edge_begin(); eiter != in_edge_end(); eiter++) {
neibs.insert((*eiter)->tail());
}
return neibs;
}
class Graph {
public:
typedef std::map<node_id, node_ptr> node_map_t;
node_map_t node_map_;
typedef std::set<edge_ptr> edge_list_t;
edge_list_t edge_list_;
node_id next_node_id_;
Graph() : next_node_id_(0) {}
~Graph() {
// delete all nodes
for (auto const &mapval : node_map_) {
node_ptr node = mapval.second;
delete node;
}
// delete all edges
for (auto edge : edge_list_) {
delete edge;
}
}
size_t number_of_nodes() const { return node_map_.size(); }
size_t number_of_edges() const { return edge_list_.size(); }
node_ptr add_node() {
node_ptr node = new Node(next_node_id_);
next_node_id_++;
node_map_.insert(std::pair<node_id, node_ptr>(node->id(), node));
return node;
}
node_ptr add_node(node_id nodeid) {
node_ptr node = NULL;
try {
node = node_map_.at(nodeid);
return node;
} catch (std::out_of_range &e) {
node = new Node(nodeid);
}
if (next_node_id_ < nodeid) {
next_node_id_ = nodeid + 1;
}
node_map_[node->id()] = node;
return node;
}
void add_nodes(node_id n) {
for (node_id i = 0; i < n; ++i) {
add_node();
}
}
node_ptr get_node(node_id nodeid) {
typedef std::map<node_id, node_ptr> maptype;
maptype::iterator iter = node_map_.find(nodeid);
if (iter == node_map_.end()) {
return NULL;
}
return iter->second;
return NULL;
}
edge_ptr add_edge(node_id tail, node_id head) {
return _add_edge(get_node(tail), get_node(head));
}
edge_ptr _add_edge(node_ptr node_tail, node_ptr node_head) {
assert(node_tail != NULL);
assert(node_head != NULL);
// check whether they're already connected
edge_ptr edge = node_tail->get_successor_edge(node_head);
if (edge != NULL) {
return edge;
}
edge = new Edge(node_tail, node_head);
edge_list_.insert(edge);
node_tail->add_out_edge(edge);
node_head->add_in_edge(edge);
return edge;
}
void remove_node(node_id nodeid) { return _remove_node(get_node(nodeid)); }
void _remove_node(node_ptr u) {
Node::edge_iterator eiter;
// remove the edges from the nodes connected to u
for (eiter = u->out_edge_begin(); eiter != u->out_edge_end(); ++eiter) {
edge_ptr edge = *eiter;
edge->head()->remove_in_edge(edge);
}
for (eiter = u->in_edge_begin(); eiter != u->in_edge_end(); ++eiter) {
edge_ptr edge = *eiter;
edge->tail()->remove_out_edge(edge);
}
Node::edge_list to_delete;
to_delete.insert(u->in_edge_begin(), u->in_edge_end());
to_delete.insert(u->out_edge_begin(), u->out_edge_end());
// remove the edges from the edge list
for (auto edge : to_delete) {
edge_list_.erase(edge);
}
// remove the node from the node list
node_map_.erase(u->id());
// deallocate the memory
for (auto edge : to_delete) {
delete edge;
}
delete u;
}
/*
* copy constructor
*/
Graph(Graph &graph) : next_node_id_(0) {
for (auto const &mapval : graph.node_map_) {
node_ptr u = mapval.second;
// std::cout << "making node " << u->id() << "\n";
node_ptr unew = this->add_node(u->id());
unew->tau = u->tau;
}
for (auto eiter = graph.edge_list_.begin(); eiter != graph.edge_list_.end();
++eiter) {
edge_ptr edge = *eiter;
node_id uid = edge->tail()->id();
node_id vid = edge->head()->id();
edge_ptr edge_new = this->add_edge(uid, vid);
edge_new->P = edge->P;
}
}
};
inline std::ostream &operator<<(std::ostream &out, std::shared_ptr<Graph> g) {
out << "nodes\n";
out << "-----\n";
for (auto const &nn : g->node_map_) {
out << nn.first << " tau " << nn.second->tau << "\n";
}
out << "edges\n";
out << "-----\n";
for (auto const &e : g->edge_list_) {
out << e->tail_->id() << " -> " << e->head_->id() << " P " << e->P << "\n";
}
return out;
}
} // namespace pele
#endif