pele
Python energy landscape explorer
/home/js850/projects/pele/source/pele/graph.hpp
00001 #ifndef _GRAPH_CPP_H_
00002 #define _GRAPH_CPP_H_
00003 /*
00004  * This implements a lightweight directed graph.  This was primarily designed for
00005  * use in the New Graph Transformation (NGT) method.  This graph was optimized
00006  * for the following actions to be as fast as possible
00007  *
00008  *     * removing nodes
00009  *     * iteration over out edges
00010  *     * iteration over in edges
00011  *     * return the edge u->v
00012  *     * access node property `double `
00013  *     * access edge property `double P`
00014  *     * allow for loop edges u->u
00015  *     * copy graph
00016  *
00017  * The requirement for fast removing of nodes means I can't assign each node
00018  * an index and use std::vector's.  This is at odds with fast access to the edge u->v.
00019  * The solution here is to use a std::map Node.successor_edge_
00020  */
00021 
00022 #include <cstdlib>
00023 #include <iostream>
00024 #include <list>
00025 #include <map>
00026 #include <set>
00027 #include <assert.h>
00028 #include <stdexcept>
00029 #include <memory>
00030 
00031 
00032 namespace pele
00033 {
00034 class Edge;
00035 class Node;
00036 typedef size_t node_id;
00037 typedef Node * node_ptr;
00038 typedef Edge * edge_ptr;
00039 typedef int color_type;
00040 color_type color_white = 0;
00041 color_type color_grey = 1;
00042 color_type color_black = 4;
00043 
00047 class Edge{
00048 public:
00049     node_ptr head_; // node the edge points to
00050     node_ptr tail_; // node the edge comes from
00051     double P;
00052 
00053     Edge(node_ptr tail, node_ptr head):
00054         head_(head),
00055         tail_(tail)
00056     {}
00057 
00058     node_ptr head(){ return head_; }
00059     node_ptr tail(){ return tail_; }
00060 };
00061 
00065 class Node{
00066 public:
00067     typedef std::set<edge_ptr> edge_list;
00068     typedef typename edge_list::iterator edge_iterator;
00069     typedef std::map<node_ptr, edge_ptr> successor_map_t;
00070 private:
00071     node_id id_;
00072     edge_list out_edge_list_; // list of outgoing edges
00073     edge_list in_edge_list_; // list of outgoing edges
00074 
00075 
00076 public:
00077     successor_map_t successor_map_;
00078     double tau;
00079 
00080     Node(node_id id):
00081         id_(id)
00082     {}
00083 
00084     void add_out_edge(edge_ptr edge){
00085         out_edge_list_.insert(edge);
00086         successor_map_[edge->head()] = edge;
00087     }
00088     void remove_out_edge(edge_ptr edge){
00089         out_edge_list_.erase(edge);
00090         successor_map_.erase(edge->head());
00091     }
00092     edge_list & get_out_edges(){ return out_edge_list_; }
00093     edge_iterator out_edge_begin(){ return out_edge_list_.begin(); }
00094     edge_iterator out_edge_end(){ return out_edge_list_.end(); }
00095 
00096     void add_in_edge(edge_ptr edge){ in_edge_list_.insert(edge); }
00097     void remove_in_edge(edge_ptr edge){ in_edge_list_.erase(edge); }
00098     edge_list & get_in_edges(){ return in_edge_list_; }
00099     edge_iterator in_edge_begin(){ return in_edge_list_.begin(); }
00100     edge_iterator in_edge_end(){ return in_edge_list_.end(); }
00101 
00102     node_id id() const { return id_; }
00103     size_t out_degree() const { return out_edge_list_.size(); }
00104     size_t in_degree() const { return in_edge_list_.size(); }
00105     size_t in_out_degree() const { return out_degree() + in_degree(); }
00106     std::set<node_ptr> in_out_neighbors();
00107 
00108     /*
00109      * return the edge u->v
00110      */
00111     edge_ptr get_successor_edge(node_ptr v){
00112         successor_map_t::iterator miter = successor_map_.find(v);
00113         if (miter == successor_map_.end()){
00114             return NULL;
00115         } else{
00116             return miter->second;
00117         }
00118     }
00119 };
00120 
00121 std::set<node_ptr> Node::in_out_neighbors() {
00122     std::set<node_ptr> neibs;
00123     Node::edge_iterator eiter;
00124     for (eiter = out_edge_begin(); eiter != out_edge_end(); eiter++){
00125         neibs.insert((*eiter)->head());
00126     }
00127     for (eiter = in_edge_begin(); eiter != in_edge_end(); eiter++){
00128         neibs.insert((*eiter)->tail());
00129     }
00130     return neibs;
00131 }
00132 
00133 
00134 class Graph
00135 {
00136 public:
00137     typedef std::map<node_id, node_ptr> node_map_t;
00138     node_map_t node_map_;
00139     typedef std::set<edge_ptr> edge_list_t;
00140     edge_list_t edge_list_;
00141 
00142     node_id next_node_id_;
00143 
00144     Graph():
00145         next_node_id_(0)
00146     {}
00147 
00148     ~Graph()
00149     {
00150         // delete all nodes
00151         typedef std::map<node_id, Node *> maptype;
00152         for (auto const & mapval : node_map_){
00153             node_ptr node = mapval.second;
00154             delete node;
00155         }
00156         // delete all edges
00157         for (auto edge : edge_list_){
00158             delete edge;
00159         }
00160     }
00161 
00162     size_t number_of_nodes() const { return node_map_.size(); }
00163     size_t number_of_edges() const { return edge_list_.size(); }
00164 
00168     node_ptr add_node(){
00169         node_ptr node = new Node(next_node_id_);
00170         next_node_id_++;
00171         node_map_.insert(std::pair<node_id, node_ptr> (node->id(), node));
00172         return node;
00173     }
00174 
00175     node_ptr add_node(node_id nodeid){
00176         node_ptr node = NULL;
00177         try {
00178             node = node_map_.at(nodeid);
00179             return node;
00180         } catch (std::out_of_range & e) {
00181             node = new Node(nodeid);
00182         }
00183 
00184         if (next_node_id_ < nodeid){
00185             next_node_id_ = nodeid + 1;
00186         }
00187         node_map_[node->id()] = node;
00188         return node;
00189     }
00190 
00191 
00195     void add_nodes(node_id n){
00196         for (node_id i = 0; i < n; ++i){
00197             add_node();
00198         }
00199     }
00200 
00204     node_ptr get_node(node_id nodeid)
00205     {
00206         typedef std::map<node_id, node_ptr> maptype;
00207         maptype::iterator iter = node_map_.find(nodeid);
00208         if (iter == node_map_.end()){
00209             return NULL;
00210         }
00211         return iter->second;
00212         return NULL;
00213     }
00214 
00218     edge_ptr add_edge(node_id tail, node_id head)
00219     {
00220         return _add_edge(get_node(tail), get_node(head));
00221     }
00222     edge_ptr _add_edge(node_ptr node_tail, node_ptr node_head)
00223     {
00224         assert(node_tail != NULL);
00225         assert(node_head != NULL);
00226         // check whether they're already connected
00227         edge_ptr edge = node_tail->get_successor_edge(node_head);
00228         if (edge != NULL){
00229             return edge;
00230         }
00231         edge = new Edge(node_tail, node_head);
00232         edge_list_.insert(edge);
00233         node_tail->add_out_edge(edge);
00234         node_head->add_in_edge(edge);
00235         return edge;
00236     }
00237 
00241     void remove_node(node_id nodeid){
00242         return _remove_node(get_node(nodeid));
00243     }
00244 
00245     void _remove_node(node_ptr u)
00246     {
00247         Node::edge_iterator eiter;
00248 
00249         // remove the edges from the nodes connected to u
00250         for (eiter = u->out_edge_begin(); eiter != u->out_edge_end(); ++eiter){
00251             edge_ptr edge = *eiter;
00252             edge->head()->remove_in_edge(edge);
00253         }
00254         for (eiter = u->in_edge_begin(); eiter != u->in_edge_end(); ++eiter){
00255             edge_ptr edge = *eiter;
00256             edge->tail()->remove_out_edge(edge);
00257         }
00258 
00259         Node::edge_list to_delete;
00260         to_delete.insert(u->in_edge_begin(), u->in_edge_end());
00261         to_delete.insert(u->out_edge_begin(), u->out_edge_end());
00262 
00263         // remove the edges from the edge list
00264         for (auto edge : to_delete){
00265             edge_list_.erase(edge);
00266         }
00267 
00268         // remove the node from the node list
00269         node_map_.erase(u->id());
00270 
00271         // deallocate the memory
00272         for (auto edge : to_delete){
00273             delete edge;
00274         }
00275 
00276         delete u;
00277     }
00278 
00279     /*
00280      * copy constructor
00281      */
00282     Graph(Graph & graph):
00283         next_node_id_(0)
00284     {
00285         for (auto const & mapval : graph.node_map_){
00286             node_ptr u = mapval.second;
00287 //            std::cout << "making node " << u->id() << "\n";
00288             node_ptr unew = this->add_node(u->id());
00289             unew->tau = u->tau;
00290         }
00291 
00292         for (auto eiter = graph.edge_list_.begin(); eiter != graph.edge_list_.end(); ++eiter){
00293             edge_ptr edge = *eiter;
00294             node_id uid = edge->tail()->id();
00295             node_id vid = edge->head()->id();
00296             edge_ptr edge_new = this->add_edge(uid, vid);
00297             edge_new->P = edge->P;
00298         }
00299     }
00300 
00301 };
00302 
00303 inline std::ostream &operator<<(std::ostream &out, std::shared_ptr<Graph> g) {
00304     out << "nodes\n";
00305     out << "-----\n";
00306     for (auto const & nn : g->node_map_) {
00307         out << nn.first << " tau " << nn.second->tau << "\n";
00308     }
00309     out << "edges\n";
00310     out << "-----\n";
00311     for (auto const & e : g->edge_list_) {
00312         out << e->tail_->id() << " -> " << e->head_->id() << " P " << e->P << "\n";
00313     }
00314     return out;
00315 }
00316 
00317 }
00318 
00319 #endif
 All Classes Namespaces Functions Variables Typedefs