TuttleOFX
1
|
00001 #ifndef _TUTTLE_HOST_INTERNALGRAPH_HPP_ 00002 #define _TUTTLE_HOST_INTERNALGRAPH_HPP_ 00003 00004 #include <tuttle/host/exceptions.hpp> 00005 00006 #include <boost/graph/graph_traits.hpp> 00007 #include <boost/graph/adjacency_list.hpp> 00008 #include <boost/graph/properties.hpp> 00009 #include <boost/graph/depth_first_search.hpp> 00010 #include <boost/graph/breadth_first_search.hpp> 00011 #include <boost/graph/copy.hpp> 00012 #include <boost/graph/transpose_graph.hpp> 00013 #include <boost/graph/dominator_tree.hpp> 00014 #include <boost/foreach.hpp> 00015 #include <boost/exception/all.hpp> 00016 #include <boost/unordered_map.hpp> 00017 00018 #include <iostream> 00019 #include <algorithm> 00020 #include <utility> 00021 #include <vector> 00022 00023 // include this file after the definition of basic boost::graph properties 00024 #include <tuttle/host/graph/Visitors.hpp> 00025 00026 namespace tuttle { 00027 namespace host { 00028 namespace graph { 00029 00030 00031 namespace detail { 00032 00033 template<class GraphIn, class GraphOut> 00034 class Copier 00035 { 00036 public: 00037 Copier( const GraphIn& gIn, GraphOut& gOut ) 00038 : _gIn(gIn) 00039 , _gOut(gOut) 00040 {} 00041 template<class VIn, class VOut> 00042 void operator()(const VIn& vIn, VOut& vOut) 00043 { 00044 _gOut[vOut] = _gIn[vIn]; 00045 } 00046 private: 00047 const GraphIn& _gIn; 00048 GraphOut& _gOut; 00049 }; 00050 00051 } 00052 00053 template < typename VERTEX, typename EDGE, typename OutEdgeList = boost::multisetS, typename VertexList = boost::vecS, typename EdgeList = boost::listS > 00054 class InternalGraph 00055 { 00056 public: 00057 typedef VERTEX Vertex; 00058 typedef EDGE Edge; 00059 typedef InternalGraph<Vertex, Edge, OutEdgeList, VertexList, EdgeList> This; 00060 00061 // Directed acyclic graph 00062 typedef boost::adjacency_list< 00063 OutEdgeList, // disallow parallel edges (OutEdgeList), use hash_setS ? 00064 VertexList, // vertex container (VertexList) 00065 boost::bidirectionalS, // directed graph 00066 Vertex, 00067 Edge, 00068 boost::no_property, // no GraphProperty 00069 EdgeList // EdgeList 00070 > GraphContainer; 00071 00072 // a bunch of graph-specific typedefs 00073 typedef typename boost::graph_traits<GraphContainer>::vertex_descriptor vertex_descriptor; 00074 typedef typename boost::graph_traits<GraphContainer>::edge_descriptor edge_descriptor; 00075 00076 typedef typename boost::graph_traits<GraphContainer>::vertex_iterator vertex_iterator; 00077 typedef typename boost::graph_traits<GraphContainer>::edge_iterator edge_iterator; 00078 typedef typename boost::graph_traits<GraphContainer>::adjacency_iterator adjacency_iterator; 00079 typedef typename boost::graph_traits<GraphContainer>::out_edge_iterator out_edge_iterator; 00080 typedef typename boost::graph_traits<GraphContainer>::in_edge_iterator in_edge_iterator; 00081 00082 typedef typename boost::graph_traits<GraphContainer>::degree_size_type degree_t; 00083 00084 typedef std::pair<adjacency_iterator, adjacency_iterator> adjacency_vertex_range_t; 00085 typedef std::pair<out_edge_iterator, out_edge_iterator> out_edge_range_t; 00086 typedef std::pair<in_edge_iterator, in_edge_iterator> in_edge_range_t; 00087 typedef std::pair<vertex_iterator, vertex_iterator> vertex_range_t; 00088 typedef std::pair<edge_iterator, edge_iterator> edge_range_t; 00089 00090 typedef typename Vertex::Key VertexKey; 00091 00092 // constructors etc. 00093 InternalGraph() 00094 {} 00095 00096 InternalGraph( const This& g ) 00097 { 00098 *this = g; 00099 } 00100 00101 template<typename V, typename E, typename OEL, typename VL, typename EL> 00102 InternalGraph( const InternalGraph<V, E, OEL, VL, EL>& g ) 00103 { 00104 *this = g; 00105 } 00106 00107 This& operator=( const This& g ) 00108 { 00109 if( this == &g ) 00110 return *this; 00111 clear(); 00112 boost::copy_graph( g.getGraph(), _graph ); 00113 rebuildVertexDescriptorMap(); 00114 return *this; 00115 } 00116 00117 template<typename V, typename E, typename OEL, typename VL, typename EL> 00118 This& operator=( const InternalGraph<V, E, OEL, VL, EL>& g ) 00119 { 00120 detail::Copier< typename InternalGraph<V, E, OEL, VL, EL>::GraphContainer, GraphContainer > copier(g.getGraph(), _graph); 00121 boost::copy_graph( g.getGraph(), _graph, boost::vertex_copy(copier).edge_copy(copier) ); 00122 rebuildVertexDescriptorMap(); 00123 return *this; 00124 } 00125 00126 virtual ~InternalGraph() 00127 {} 00128 00129 // structure modification methods 00130 void clear() 00131 { 00132 _graph.clear(); 00133 _vertexDescriptorMap.clear(); 00134 } 00135 00136 std::size_t getNbEdges() const 00137 { 00138 return boost::num_edges(_graph); 00139 } 00140 00141 std::size_t getNbVertices() const 00142 { 00143 return boost::num_vertices(_graph); 00144 } 00145 00146 vertex_descriptor addVertex( const Vertex& prop ) 00147 { 00148 vertex_descriptor vd = boost::add_vertex( prop, _graph ); 00149 00150 //TUTTLE_TLOG( TUTTLE_INFO, "addVertex, vd: " << vd << ", prop.getKey(): " << prop.getKey() ); 00151 _vertexDescriptorMap[prop.getKey()] = vd; 00152 return vd; 00153 } 00154 00155 /** 00156 * @brief Remove in and out edges of a Vertex. 00157 */ 00158 void clearVertex( const vertex_descriptor& vd ) 00159 { 00160 boost::clear_vertex( vd, _graph ); // remove in and out edges 00161 } 00162 00163 /** 00164 * @brief Remove a Vertex. 00165 */ 00166 void removeVertex( const vertex_descriptor& vd ) 00167 { 00168 // clear_vertex is not called by boost graph itself. 00169 // It may result in an undefined behaviour if not called before. 00170 clearVertex( vd ); 00171 boost::remove_vertex( vd, _graph ); // finally remove the vertex from the boost graph 00172 rebuildVertexDescriptorMap(); 00173 } 00174 00175 void connect( const VertexKey& out, const VertexKey& in, const std::string& inAttr ) 00176 { 00177 try 00178 { 00179 const vertex_descriptor descOut = getVertexDescriptor( out ); 00180 const vertex_descriptor descIn = getVertexDescriptor( in ); 00181 00182 const Edge e( out, in, inAttr ); 00183 addEdge( descOut, descIn, e ); 00184 } 00185 catch( boost::exception& e ) 00186 { 00187 e << exception::user() + "Error while connecting " + out + " --> " + in + "." + inAttr; 00188 throw; 00189 } 00190 } 00191 00192 void unconnect( const VertexKey& out, const VertexKey& in, const std::string& inAttr ) 00193 { 00194 try 00195 { 00196 const edge_descriptor ed = getEdge( out, in, inAttr ); 00197 removeEdge( ed ); 00198 } 00199 catch( boost::exception& e ) 00200 { 00201 e << exception::user() + "No such connection in the graph. Can't unconnect from \"" + getVertex(out) + "\" to \"" + getVertex(in) + "." + inAttr + "\""; 00202 } 00203 } 00204 00205 bool hasEdge( const VertexKey& out, const VertexKey& in, const std::string& inAttr ) const 00206 { 00207 return hasEdge( getVertexDescriptor(out), getVertexDescriptor(in), inAttr ); 00208 } 00209 00210 bool hasEdge( const vertex_descriptor& out, const vertex_descriptor& in, const std::string& inAttr ) const 00211 { 00212 const out_edge_range_t edges = getEdges( out, in ); 00213 BOOST_FOREACH( const edge_descriptor ed, edges ) 00214 { 00215 if( instance(ed).getInAttrName() == inAttr ) 00216 { 00217 return true; 00218 } 00219 } 00220 return false; 00221 } 00222 00223 edge_descriptor getEdge( const VertexKey& out, const VertexKey& in, const std::string& inAttr ) const 00224 { 00225 const out_edge_range_t edges = getEdges( getVertexDescriptor(out), getVertexDescriptor(in) ); 00226 BOOST_FOREACH( const edge_descriptor ed, edges ) 00227 { 00228 if( instance(ed).getInAttrName() == inAttr ) 00229 { 00230 return ed; 00231 } 00232 } 00233 BOOST_THROW_EXCEPTION( exception::Logic() 00234 << exception::user() + "No connection in the graph from \"" + getVertex(out) + "\" to \"" + getVertex(in) + "/" + inAttr + "\"" ); 00235 } 00236 00237 out_edge_range_t getEdges( const vertex_descriptor& v1, const vertex_descriptor& v2 ) const 00238 { 00239 return boost::edge_range(v1, v2, _graph); 00240 } 00241 00242 edge_descriptor addEdge( const vertex_descriptor& v1, const vertex_descriptor& v2, const Edge& prop ) 00243 { 00244 if( hasEdge( v1, v2, prop.getInAttrName() ) ) 00245 { 00246 BOOST_THROW_EXCEPTION( exception::Logic() 00247 << exception::dev() + "Can't add Edge. There is already a connection from \"" + instance(v1) + "\" to \"" + instance(v2) + "/" + prop.getInAttrName() + "\"" ); 00248 } 00249 //TUTTLE_TLOG_VAR2( TUTTLE_TRACE, v1, instance(v1) ); 00250 //TUTTLE_TLOG_VAR2( TUTTLE_TRACE, v2, instance(v2) ); 00251 00252 const edge_descriptor addedEdge = boost::add_edge( v1, v2, prop, _graph ).first; 00253 00254 if( hasCycle() ) 00255 { 00256 removeEdge( addedEdge ); 00257 BOOST_THROW_EXCEPTION( exception::Logic() 00258 << exception::user() + "Connection error: the graph becomes cyclic while connecting \"" + instance(v1) + "\" to \"" + instance(v2) + "\"" ); 00259 } 00260 return addedEdge; 00261 } 00262 00263 void removeEdge( const edge_descriptor& e ) 00264 { 00265 boost::remove_edge( e, _graph ); 00266 } 00267 00268 vertex_descriptor& getVertexDescriptor( const VertexKey& vertexKey ) 00269 { 00270 return _vertexDescriptorMap[vertexKey]; 00271 } 00272 00273 const vertex_descriptor& getVertexDescriptor( const VertexKey& vertexKey ) const 00274 { 00275 return _vertexDescriptorMap.find(vertexKey)->second; 00276 } 00277 00278 Vertex& getVertex( const VertexKey& vertexKey ) 00279 { 00280 return instance( getVertexDescriptor( vertexKey ) ); 00281 } 00282 00283 const Vertex& getVertex( const VertexKey& vertexKey ) const 00284 { 00285 return instance( getVertexDescriptor( vertexKey ) ); 00286 } 00287 00288 const vertex_descriptor source( const edge_descriptor& e ) const 00289 { 00290 return boost::source( e, _graph ); 00291 } 00292 00293 Vertex& sourceInstance( const edge_descriptor& e ) 00294 { 00295 return instance( source( e ) ); 00296 } 00297 00298 const Vertex& sourceInstance( const edge_descriptor& e ) const 00299 { 00300 return instance( source( e ) ); 00301 } 00302 00303 const vertex_descriptor target( const edge_descriptor& e ) const 00304 { 00305 return boost::target( e, _graph ); 00306 } 00307 00308 Vertex& targetInstance( const edge_descriptor& e ) 00309 { 00310 return instance( target( e ) ); 00311 } 00312 00313 const Vertex& targetInstance( const edge_descriptor& e ) const 00314 { 00315 return instance( target( e ) ); 00316 } 00317 00318 // property access 00319 Vertex& instance( const vertex_descriptor& v ) 00320 { 00321 return _graph[v]; 00322 } 00323 00324 const Vertex& instance( const vertex_descriptor& v ) const 00325 { 00326 return _graph[v]; 00327 } 00328 00329 Edge& instance( const edge_descriptor& e ) 00330 { 00331 return _graph[e]; 00332 } 00333 00334 const Edge& instance( const edge_descriptor& e ) const 00335 { 00336 return _graph[e]; 00337 } 00338 00339 GraphContainer& getGraph() 00340 { 00341 return _graph; 00342 } 00343 00344 const GraphContainer& getGraph() const 00345 { 00346 return _graph; 00347 } 00348 00349 edge_range_t getEdges() { return edges( _graph ); } 00350 const edge_range_t getEdges() const { return edges( _graph ); } 00351 00352 in_edge_range_t getInEdges( const vertex_descriptor& v ) { return in_edges( v, _graph ); } 00353 const in_edge_range_t getInEdges( const vertex_descriptor& v ) const { return in_edges( v, _graph ); } 00354 00355 out_edge_range_t getOutEdges( const vertex_descriptor& v ) { return out_edges( v, _graph ); } 00356 const out_edge_range_t getOutEdges( const vertex_descriptor& v ) const { return out_edges( v, _graph ); } 00357 00358 vertex_range_t getVertices() const { return vertices( _graph ); } 00359 00360 adjacency_vertex_range_t getAdjacentVertices( const vertex_descriptor& v ) const { return adjacent_vertices( v, _graph ); } 00361 00362 std::size_t getVertexCount() const { return boost::num_vertices( _graph ); } 00363 00364 std::size_t getEdgeCount() const { return boost::num_edges( _graph ); } 00365 00366 degree_t getInDegree( const vertex_descriptor& v ) const { return in_degree( v, _graph ); } 00367 00368 degree_t getOutDegree( const vertex_descriptor& v ) const { return out_degree( v, _graph ); } 00369 00370 bool hasCycle() 00371 { 00372 // we use a depth first search visitor 00373 bool hasCycle = false; 00374 visitor::CycleDetector vis( hasCycle ); 00375 this->depthFirstSearch( vis ); 00376 return hasCycle; 00377 } 00378 00379 template<class Visitor> 00380 void depthFirstVisit( Visitor& vis, const vertex_descriptor& vroot ) 00381 { 00382 std::vector<boost::default_color_type > colormap( boost::num_vertices( _graph ), boost::white_color ); 00383 BOOST_FOREACH( const vertex_descriptor &vd, getVertices() ) 00384 { 00385 vis.initialize_vertex( vd, _graph ); 00386 } 00387 // use depth_first_visit (and not depth_first_search) because 00388 // we visit vertices from vroot, without visiting nodes not 00389 // reachable from vroot 00390 boost::depth_first_visit( _graph, 00391 vroot, 00392 vis, 00393 boost::make_iterator_property_map( colormap.begin(), boost::get( boost::vertex_index, _graph ) ) 00394 ); 00395 } 00396 00397 template<class Visitor> 00398 void depthFirstVisitReverse( Visitor& vis, const vertex_descriptor& vroot ) 00399 { 00400 boost::reverse_graph<GraphContainer> revGraph(_graph); 00401 00402 std::vector<boost::default_color_type > colormap( boost::num_vertices( revGraph ), boost::white_color ); 00403 BOOST_FOREACH( const vertex_descriptor& vd, vertices( revGraph ) ) 00404 { 00405 vis.initialize_vertex( vd, revGraph ); 00406 } 00407 00408 // use depth_first_visit (and not depth_first_search) because 00409 // we visit vertices from vroot, without visiting nodes not 00410 // reachable from vroot 00411 boost::depth_first_visit( revGraph, 00412 vroot, 00413 vis, 00414 boost::make_iterator_property_map( colormap.begin(), boost::get( boost::vertex_index, revGraph ) ) 00415 ); 00416 } 00417 00418 template<class Visitor> 00419 void depthFirstSearch( Visitor& vis ) 00420 { 00421 boost::depth_first_search( _graph, 00422 boost::visitor( vis ) 00423 ); 00424 } 00425 00426 template<class Visitor> 00427 void depthFirstSearchReverse( Visitor& vis ) 00428 { 00429 boost::reverse_graph<GraphContainer> revGraph(_graph); 00430 00431 boost::depth_first_search( revGraph, 00432 boost::visitor( vis ) 00433 ); 00434 } 00435 00436 template<class Visitor> 00437 void depthFirstSearch( Visitor& vis, const vertex_descriptor& vroot ) 00438 { 00439 boost::depth_first_search( _graph, 00440 vroot, 00441 boost::visitor( vis ) 00442 ); 00443 } 00444 00445 template<class Visitor> 00446 void depthFirstSearchReverse( Visitor& vis, const vertex_descriptor& vroot ) 00447 { 00448 boost::reverse_graph<GraphContainer> revGraph(_graph); 00449 boost::depth_first_search( revGraph, 00450 vroot, 00451 boost::visitor( vis ) 00452 ); 00453 } 00454 00455 template<class Visitor> 00456 void breadthFirstSearch( Visitor& vis, const vertex_descriptor& vroot ) 00457 { 00458 boost::breadth_first_search( _graph, 00459 vroot, 00460 boost::visitor( vis ) 00461 ); 00462 } 00463 00464 template<class Visitor> 00465 void breadthFirstSearch( Visitor& vis ) 00466 { 00467 boost::breadth_first_search( _graph, 00468 boost::visitor( vis ) 00469 ); 00470 } 00471 00472 void copyTransposed( const This& g ) 00473 { 00474 // make a transposed copy of g in _graph 00475 boost::transpose_graph( g._graph, _graph ); 00476 rebuildVertexDescriptorMap(); 00477 } 00478 00479 template<typename V, typename E, typename OEL, typename VL, typename EL> 00480 void copyTransposed( const InternalGraph<V, E, OEL, VL, EL>& g ) 00481 { 00482 detail::Copier< typename InternalGraph<V, E, OEL, VL, EL>::GraphContainer, GraphContainer > copier(g.getGraph(), _graph); 00483 // make a transposed copy of g in _graph 00484 boost::transpose_graph( g.getGraph(), _graph, boost::vertex_copy(copier).edge_copy(copier) ); 00485 rebuildVertexDescriptorMap(); 00486 } 00487 00488 /** 00489 * @brief Create a tree from the graph. 00490 */ 00491 void toDominatorTree(); 00492 00493 /** 00494 * @brief Create a vector of root vertices, ie. all nodes whithout parents. 00495 */ 00496 std::vector<vertex_descriptor> rootVertices(); 00497 00498 /** 00499 * @brief Create a vector of leaf vertices (or external node), ie. all nodes that has zero child node. 00500 */ 00501 std::vector<vertex_descriptor> leafVertices(); 00502 00503 /** 00504 * @brief Remove all vertices without connection with vroot. 00505 */ 00506 std::size_t removeUnconnectedVertices( const vertex_descriptor& vroot ); 00507 00508 template< typename Vertex, typename Edge > 00509 friend std::ostream& operator<<( std::ostream& os, const This& g ); 00510 00511 private: 00512 void rebuildVertexDescriptorMap(); 00513 00514 protected: 00515 GraphContainer _graph; 00516 boost::unordered_map<VertexKey, vertex_descriptor> _vertexDescriptorMap; 00517 00518 }; 00519 00520 } 00521 } 00522 } 00523 00524 #include "InternalGraph.tcc" 00525 00526 #endif