pele
Python energy landscape explorer
|
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