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 void clearVertexInputs( const vertex_descriptor& vd ) 00163 { 00164 boost::clear_in_edges( vd, _graph ); // remove in and out edges 00165 } 00166 void clearVertexOutputs( const vertex_descriptor& vd ) 00167 { 00168 boost::clear_out_edges( vd, _graph ); // remove in and out edges 00169 } 00170 00171 /** 00172 * @brief Remove a Vertex. 00173 */ 00174 void removeVertex( const vertex_descriptor& vd ) 00175 { 00176 // clear_vertex is not called by boost graph itself. 00177 // It may result in an undefined behaviour if not called before. 00178 clearVertex( vd ); 00179 boost::remove_vertex( vd, _graph ); // finally remove the vertex from the boost graph 00180 rebuildVertexDescriptorMap(); 00181 } 00182 00183 void connect( const VertexKey& out, const VertexKey& in, const std::string& inAttr ) 00184 { 00185 try 00186 { 00187 const vertex_descriptor descOut = getVertexDescriptor( out ); 00188 const vertex_descriptor descIn = getVertexDescriptor( in ); 00189 00190 const Edge e( out, in, inAttr ); 00191 addEdge( descOut, descIn, e ); 00192 } 00193 catch( boost::exception& e ) 00194 { 00195 e << exception::user() + "Error while connecting " + out + " --> " + in + "." + inAttr; 00196 throw; 00197 } 00198 } 00199 00200 void unconnect( const VertexKey& out, const VertexKey& in, const std::string& inAttr ) 00201 { 00202 try 00203 { 00204 const edge_descriptor ed = getEdge( out, in, inAttr ); 00205 removeEdge( ed ); 00206 } 00207 catch( boost::exception& e ) 00208 { 00209 e << exception::user() + "No such connection in the graph. Can't unconnect from \"" + getVertex(out) + "\" to \"" + getVertex(in) + "." + inAttr + "\""; 00210 } 00211 } 00212 00213 bool hasEdge( const VertexKey& out, const VertexKey& in, const std::string& inAttr ) const 00214 { 00215 return hasEdge( getVertexDescriptor(out), getVertexDescriptor(in), inAttr ); 00216 } 00217 00218 bool hasEdge( const vertex_descriptor& out, const vertex_descriptor& in, const std::string& inAttr ) const 00219 { 00220 const out_edge_range_t edges = getEdges( out, in ); 00221 BOOST_FOREACH( const edge_descriptor ed, edges ) 00222 { 00223 if( instance(ed).getInAttrName() == inAttr ) 00224 { 00225 return true; 00226 } 00227 } 00228 return false; 00229 } 00230 00231 edge_descriptor getEdge( const VertexKey& out, const VertexKey& in, const std::string& inAttr ) const 00232 { 00233 const out_edge_range_t edges = getEdges( getVertexDescriptor(out), getVertexDescriptor(in) ); 00234 BOOST_FOREACH( const edge_descriptor ed, edges ) 00235 { 00236 if( instance(ed).getInAttrName() == inAttr ) 00237 { 00238 return ed; 00239 } 00240 } 00241 BOOST_THROW_EXCEPTION( exception::Logic() 00242 << exception::user() + "No connection in the graph from \"" + getVertex(out) + "\" to \"" + getVertex(in) + "/" + inAttr + "\"" ); 00243 } 00244 00245 out_edge_range_t getEdges( const vertex_descriptor& v1, const vertex_descriptor& v2 ) const 00246 { 00247 return boost::edge_range(v1, v2, _graph); 00248 } 00249 00250 edge_descriptor addEdge( const vertex_descriptor& v1, const vertex_descriptor& v2, const Edge& prop ) 00251 { 00252 if( hasEdge( v1, v2, prop.getInAttrName() ) ) 00253 { 00254 BOOST_THROW_EXCEPTION( exception::Logic() 00255 << exception::dev() + "Can't add Edge. There is already a connection from \"" + instance(v1) + "\" to \"" + instance(v2) + "/" + prop.getInAttrName() + "\"" ); 00256 } 00257 //TUTTLE_TLOG_VAR2( TUTTLE_TRACE, v1, instance(v1) ); 00258 //TUTTLE_TLOG_VAR2( TUTTLE_TRACE, v2, instance(v2) ); 00259 00260 const edge_descriptor addedEdge = boost::add_edge( v1, v2, prop, _graph ).first; 00261 00262 if( hasCycle() ) 00263 { 00264 removeEdge( addedEdge ); 00265 BOOST_THROW_EXCEPTION( exception::Logic() 00266 << exception::user() + "Connection error: the graph becomes cyclic while connecting \"" + instance(v1) + "\" to \"" + instance(v2) + "\"" ); 00267 } 00268 return addedEdge; 00269 } 00270 00271 void removeEdge( const edge_descriptor& e ) 00272 { 00273 boost::remove_edge( e, _graph ); 00274 } 00275 00276 vertex_descriptor& getVertexDescriptor( const VertexKey& vertexKey ) 00277 { 00278 return _vertexDescriptorMap[vertexKey]; 00279 } 00280 00281 const vertex_descriptor& getVertexDescriptor( const VertexKey& vertexKey ) const 00282 { 00283 return _vertexDescriptorMap.find(vertexKey)->second; 00284 } 00285 00286 Vertex& getVertex( const VertexKey& vertexKey ) 00287 { 00288 return instance( getVertexDescriptor( vertexKey ) ); 00289 } 00290 00291 const Vertex& getVertex( const VertexKey& vertexKey ) const 00292 { 00293 return instance( getVertexDescriptor( vertexKey ) ); 00294 } 00295 00296 const vertex_descriptor source( const edge_descriptor& e ) const 00297 { 00298 return boost::source( e, _graph ); 00299 } 00300 00301 Vertex& sourceInstance( const edge_descriptor& e ) 00302 { 00303 return instance( source( e ) ); 00304 } 00305 00306 const Vertex& sourceInstance( const edge_descriptor& e ) const 00307 { 00308 return instance( source( e ) ); 00309 } 00310 00311 const vertex_descriptor target( const edge_descriptor& e ) const 00312 { 00313 return boost::target( e, _graph ); 00314 } 00315 00316 Vertex& targetInstance( const edge_descriptor& e ) 00317 { 00318 return instance( target( e ) ); 00319 } 00320 00321 const Vertex& targetInstance( const edge_descriptor& e ) const 00322 { 00323 return instance( target( e ) ); 00324 } 00325 00326 // property access 00327 Vertex& instance( const vertex_descriptor& v ) 00328 { 00329 return _graph[v]; 00330 } 00331 00332 const Vertex& instance( const vertex_descriptor& v ) const 00333 { 00334 return _graph[v]; 00335 } 00336 00337 Edge& instance( const edge_descriptor& e ) 00338 { 00339 return _graph[e]; 00340 } 00341 00342 const Edge& instance( const edge_descriptor& e ) const 00343 { 00344 return _graph[e]; 00345 } 00346 00347 GraphContainer& getGraph() 00348 { 00349 return _graph; 00350 } 00351 00352 const GraphContainer& getGraph() const 00353 { 00354 return _graph; 00355 } 00356 00357 edge_range_t getEdges() { return edges( _graph ); } 00358 const edge_range_t getEdges() const { return edges( _graph ); } 00359 00360 in_edge_range_t getInEdges( const vertex_descriptor& v ) { return in_edges( v, _graph ); } 00361 const in_edge_range_t getInEdges( const vertex_descriptor& v ) const { return in_edges( v, _graph ); } 00362 00363 out_edge_range_t getOutEdges( const vertex_descriptor& v ) { return out_edges( v, _graph ); } 00364 const out_edge_range_t getOutEdges( const vertex_descriptor& v ) const { return out_edges( v, _graph ); } 00365 00366 vertex_range_t getVertices() const { return vertices( _graph ); } 00367 std::vector<vertex_descriptor> getConnectedVertices( const vertex_descriptor& vroot ); 00368 std::vector<vertex_descriptor> getUnconnectedVertices( const vertex_descriptor& vroot ); 00369 00370 adjacency_vertex_range_t getAdjacentVertices( const vertex_descriptor& v ) const { return adjacent_vertices( v, _graph ); } 00371 00372 std::size_t getVertexCount() const { return boost::num_vertices( _graph ); } 00373 00374 std::size_t getEdgeCount() const { return boost::num_edges( _graph ); } 00375 00376 degree_t getInDegree( const vertex_descriptor& v ) const { return in_degree( v, _graph ); } 00377 00378 degree_t getOutDegree( const vertex_descriptor& v ) const { return out_degree( v, _graph ); } 00379 00380 bool hasCycle() 00381 { 00382 // we use a depth first search visitor 00383 bool hasCycle = false; 00384 visitor::CycleDetector vis( hasCycle ); 00385 this->depthFirstSearch( vis ); 00386 return hasCycle; 00387 } 00388 00389 template<class Visitor> 00390 void depthFirstVisit( Visitor& vis, const vertex_descriptor& vroot ) 00391 { 00392 std::vector<boost::default_color_type > colormap( boost::num_vertices( _graph ), boost::white_color ); 00393 BOOST_FOREACH( const vertex_descriptor &vd, getVertices() ) 00394 { 00395 vis.initialize_vertex( vd, _graph ); 00396 } 00397 // use depth_first_visit (and not depth_first_search) because 00398 // we visit vertices from vroot, without visiting nodes not 00399 // reachable from vroot 00400 boost::depth_first_visit( _graph, 00401 vroot, 00402 vis, 00403 boost::make_iterator_property_map( colormap.begin(), boost::get( boost::vertex_index, _graph ) ) 00404 ); 00405 } 00406 00407 template<class Visitor> 00408 void depthFirstVisitReverse( Visitor& vis, const vertex_descriptor& vroot ) 00409 { 00410 boost::reverse_graph<GraphContainer> revGraph(_graph); 00411 00412 std::vector<boost::default_color_type > colormap( boost::num_vertices( revGraph ), boost::white_color ); 00413 BOOST_FOREACH( const vertex_descriptor& vd, vertices( revGraph ) ) 00414 { 00415 vis.initialize_vertex( vd, revGraph ); 00416 } 00417 00418 // use depth_first_visit (and not depth_first_search) because 00419 // we visit vertices from vroot, without visiting nodes not 00420 // reachable from vroot 00421 boost::depth_first_visit( revGraph, 00422 vroot, 00423 vis, 00424 boost::make_iterator_property_map( colormap.begin(), boost::get( boost::vertex_index, revGraph ) ) 00425 ); 00426 } 00427 00428 template<class Visitor> 00429 void depthFirstSearch( Visitor& vis ) 00430 { 00431 boost::depth_first_search( _graph, 00432 boost::visitor( vis ) 00433 ); 00434 } 00435 00436 template<class Visitor> 00437 void depthFirstSearchReverse( Visitor& vis ) 00438 { 00439 boost::reverse_graph<GraphContainer> revGraph(_graph); 00440 00441 boost::depth_first_search( revGraph, 00442 boost::visitor( vis ) 00443 ); 00444 } 00445 00446 template<class Visitor> 00447 void depthFirstSearch( Visitor& vis, const vertex_descriptor& vroot ) 00448 { 00449 boost::depth_first_search( _graph, 00450 vroot, 00451 boost::visitor( vis ) 00452 ); 00453 } 00454 00455 template<class Visitor> 00456 void depthFirstSearchReverse( Visitor& vis, const vertex_descriptor& vroot ) 00457 { 00458 boost::reverse_graph<GraphContainer> revGraph(_graph); 00459 boost::depth_first_search( revGraph, 00460 vroot, 00461 boost::visitor( vis ) 00462 ); 00463 } 00464 00465 template<class Visitor> 00466 void breadthFirstSearch( Visitor& vis, const vertex_descriptor& vroot ) 00467 { 00468 boost::breadth_first_search( _graph, 00469 vroot, 00470 boost::visitor( vis ) 00471 ); 00472 } 00473 00474 template<class Visitor> 00475 void breadthFirstSearch( Visitor& vis ) 00476 { 00477 boost::breadth_first_search( _graph, 00478 boost::visitor( vis ) 00479 ); 00480 } 00481 00482 void copyTransposed( const This& g ) 00483 { 00484 // make a transposed copy of g in _graph 00485 boost::transpose_graph( g._graph, _graph ); 00486 rebuildVertexDescriptorMap(); 00487 } 00488 00489 template<typename V, typename E, typename OEL, typename VL, typename EL> 00490 void copyTransposed( const InternalGraph<V, E, OEL, VL, EL>& g ) 00491 { 00492 detail::Copier< typename InternalGraph<V, E, OEL, VL, EL>::GraphContainer, GraphContainer > copier(g.getGraph(), _graph); 00493 // make a transposed copy of g in _graph 00494 boost::transpose_graph( g.getGraph(), _graph, boost::vertex_copy(copier).edge_copy(copier) ); 00495 rebuildVertexDescriptorMap(); 00496 } 00497 00498 /** 00499 * @brief Create a tree from the graph. 00500 */ 00501 void toDominatorTree(); 00502 00503 /** 00504 * @brief Create a vector of root vertices, ie. all nodes whithout parents. 00505 */ 00506 std::vector<vertex_descriptor> rootVertices(); 00507 00508 /** 00509 * @brief Create a vector of leaf vertices (or external node), ie. all nodes that has zero child node. 00510 */ 00511 std::vector<vertex_descriptor> leafVertices(); 00512 00513 /** 00514 * @brief Remove all vertices without connection with vroot. 00515 */ 00516 std::size_t removeUnconnectedVertices( const vertex_descriptor& vroot ); 00517 00518 template< typename Vertex, typename Edge > 00519 friend std::ostream& operator<<( std::ostream& os, const This& g ); 00520 00521 private: 00522 void rebuildVertexDescriptorMap(); 00523 00524 protected: 00525 GraphContainer _graph; 00526 boost::unordered_map<VertexKey, vertex_descriptor> _vertexDescriptorMap; 00527 00528 }; 00529 00530 } 00531 } 00532 } 00533 00534 #include "InternalGraph.tcc" 00535 00536 #endif