TuttleOFX  1
InternalGraph.hpp
Go to the documentation of this file.
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