TuttleOFX  1
TuttleOFX/libraries/tuttle/src/tuttle/host/graph/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         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