//======================================================================= // Copyright 2001 University of Notre Dame. // Authors: Jeremy G. Siek and Lie-Quan Lee // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= #ifndef BOOST_SUBGRAPH_HPP #define BOOST_SUBGRAPH_HPP // UNDER CONSTRUCTION #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { struct subgraph_tag { }; /** @name Property Lookup * The local_property and global_property functions are used to create * structures that determine the lookup strategy for properties in subgraphs. * Note that the nested kind member is used to help interoperate with actual * Property types. */ //@{ template < typename T > struct local_property { typedef T kind; local_property(T x) : value(x) {} T value; }; template < typename T > inline local_property< T > local(T x) { return local_property< T >(x); } template < typename T > struct global_property { typedef T kind; global_property(T x) : value(x) {} T value; }; template < typename T > inline global_property< T > global(T x) { return global_property< T >(x); } //@} // Invariants of an induced subgraph: // - If vertex u is in subgraph g, then u must be in g.parent(). // - If edge e is in subgraph g, then e must be in g.parent(). // - If edge e=(u,v) is in the root graph, then edge e // is also in any subgraph that contains both vertex u and v. // The Graph template parameter must have a vertex_index and edge_index // internal property. It is assumed that the vertex indices are assigned // automatically by the graph during a call to add_vertex(). It is not // assumed that the edge vertices are assigned automatically, they are // explicitly assigned here. template < typename Graph > class subgraph { typedef graph_traits< Graph > Traits; typedef std::list< subgraph< Graph >* > ChildrenList; public: // Graph requirements typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename Traits::edge_descriptor edge_descriptor; typedef typename Traits::directed_category directed_category; typedef typename Traits::edge_parallel_category edge_parallel_category; typedef typename Traits::traversal_category traversal_category; // IncidenceGraph requirements typedef typename Traits::out_edge_iterator out_edge_iterator; typedef typename Traits::degree_size_type degree_size_type; // AdjacencyGraph requirements typedef typename Traits::adjacency_iterator adjacency_iterator; // VertexListGraph requirements typedef typename Traits::vertex_iterator vertex_iterator; typedef typename Traits::vertices_size_type vertices_size_type; // EdgeListGraph requirements typedef typename Traits::edge_iterator edge_iterator; typedef typename Traits::edges_size_type edges_size_type; typedef typename Traits::in_edge_iterator in_edge_iterator; typedef typename edge_property_type< Graph >::type edge_property_type; typedef typename vertex_property_type< Graph >::type vertex_property_type; typedef subgraph_tag graph_tag; typedef Graph graph_type; typedef typename graph_property_type< Graph >::type graph_property_type; // Create the main graph, the root of the subgraph tree subgraph() : m_parent(0), m_edge_counter(0) {} subgraph(const graph_property_type& p) : m_graph(p), m_parent(0), m_edge_counter(0) { } subgraph(vertices_size_type n, const graph_property_type& p = graph_property_type()) : m_graph(n, p), m_parent(0), m_edge_counter(0), m_global_vertex(n) { typename Graph::vertex_iterator v, v_end; vertices_size_type i = 0; for (boost::tie(v, v_end) = vertices(m_graph); v != v_end; ++v) m_global_vertex[i++] = *v; } // copy constructor subgraph(const subgraph& x) : m_parent(x.m_parent), m_edge_counter(0) { if (x.is_root()) { m_graph = x.m_graph; m_edge_counter = x.m_edge_counter; m_global_vertex = x.m_global_vertex; m_global_edge = x.m_global_edge; } else { get_property(*this) = get_property(x); typename subgraph< Graph >::vertex_iterator vi, vi_end; boost::tie(vi, vi_end) = vertices(x); for (; vi != vi_end; ++vi) { add_vertex(x.local_to_global(*vi), *this); } } // Do a deep copy (recursive). // Only the root graph is copied, the subgraphs contain // only references to the global vertices they own. typename subgraph< Graph >::children_iterator i, i_end; boost::tie(i, i_end) = x.children(); for (; i != i_end; ++i) { m_children.push_back(new subgraph< Graph >(*i)); m_children.back()->m_parent = this; } } ~subgraph() { for (typename ChildrenList::iterator i = m_children.begin(); i != m_children.end(); ++i) { delete *i; } } // Return a null vertex descriptor for the graph. static vertex_descriptor null_vertex() { return Traits::null_vertex(); } // Create a subgraph subgraph< Graph >& create_subgraph() { m_children.push_back(new subgraph< Graph >()); m_children.back()->m_parent = this; return *m_children.back(); } // Create a subgraph with the specified vertex set. template < typename VertexIterator > subgraph< Graph >& create_subgraph( VertexIterator first, VertexIterator last) { m_children.push_back(new subgraph< Graph >()); m_children.back()->m_parent = this; for (; first != last; ++first) { add_vertex(*first, *m_children.back()); } return *m_children.back(); } // local <-> global descriptor conversion functions vertex_descriptor local_to_global(vertex_descriptor u_local) const { return is_root() ? u_local : m_global_vertex[u_local]; } vertex_descriptor global_to_local(vertex_descriptor u_global) const { vertex_descriptor u_local; bool in_subgraph; if (is_root()) return u_global; boost::tie(u_local, in_subgraph) = this->find_vertex(u_global); BOOST_ASSERT(in_subgraph == true); return u_local; } edge_descriptor local_to_global(edge_descriptor e_local) const { return is_root() ? e_local : m_global_edge[get(get(edge_index, m_graph), e_local)]; } edge_descriptor global_to_local(edge_descriptor e_global) const { return is_root() ? e_global : (*m_local_edge.find( get(get(edge_index, root().m_graph), e_global))) .second; } // Is vertex u (of the root graph) contained in this subgraph? // If so, return the matching local vertex. std::pair< vertex_descriptor, bool > find_vertex( vertex_descriptor u_global) const { if (is_root()) return std::make_pair(u_global, true); typename LocalVertexMap::const_iterator i = m_local_vertex.find(u_global); bool valid = i != m_local_vertex.end(); return std::make_pair((valid ? (*i).second : null_vertex()), valid); } // Is edge e (of the root graph) contained in this subgraph? // If so, return the matching local edge. std::pair< edge_descriptor, bool > find_edge(edge_descriptor e_global) const { if (is_root()) return std::make_pair(e_global, true); typename LocalEdgeMap::const_iterator i = m_local_edge.find(get(get(edge_index, root().m_graph), e_global)); bool valid = i != m_local_edge.end(); return std::make_pair((valid ? (*i).second : edge_descriptor()), valid); } // Return the parent graph. subgraph& parent() { return *m_parent; } const subgraph& parent() const { return *m_parent; } // Return true if this is the root subgraph bool is_root() const { return m_parent == 0; } // Return the root graph of the subgraph tree. subgraph& root() { return is_root() ? *this : m_parent->root(); } const subgraph& root() const { return is_root() ? *this : m_parent->root(); } // Return the children subgraphs of this graph/subgraph. // Use a list of pointers because the VC++ std::list doesn't like // storing incomplete type. typedef indirect_iterator< typename ChildrenList::const_iterator, subgraph< Graph >, std::bidirectional_iterator_tag > children_iterator; typedef indirect_iterator< typename ChildrenList::const_iterator, subgraph< Graph > const, std::bidirectional_iterator_tag > const_children_iterator; std::pair< const_children_iterator, const_children_iterator > children() const { return std::make_pair(const_children_iterator(m_children.begin()), const_children_iterator(m_children.end())); } std::pair< children_iterator, children_iterator > children() { return std::make_pair(children_iterator(m_children.begin()), children_iterator(m_children.end())); } std::size_t num_children() const { return m_children.size(); } #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES // Defualt property access delegates the lookup to global properties. template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type& operator[](Descriptor x) { return is_root() ? m_graph[x] : root().m_graph[local_to_global(x)]; } template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type const& operator[](Descriptor x) const { return is_root() ? m_graph[x] : root().m_graph[local_to_global(x)]; } // Local property access returns the local property of the given descripor. template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type& operator[](local_property< Descriptor > x) { return m_graph[x.value]; } template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type const& operator[](local_property< Descriptor > x) const { return m_graph[x.value]; } // Global property access returns the global property associated with the // given descriptor. This is an alias for the default bundled property // access operations. template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type& operator[](global_property< Descriptor > x) { return (*this)[x.value]; } template < typename Descriptor > typename graph::detail::bundled_result< Graph, Descriptor >::type const& operator[](global_property< Descriptor > x) const { return (*this)[x.value]; } #endif // BOOST_GRAPH_NO_BUNDLED_PROPERTIES // private: typedef typename property_map< Graph, edge_index_t >::type EdgeIndexMap; typedef typename property_traits< EdgeIndexMap >::value_type edge_index_type; BOOST_STATIC_ASSERT((!is_same< edge_index_type, boost::detail::error_property_not_found >::value)); private: typedef std::vector< vertex_descriptor > GlobalVertexList; typedef std::vector< edge_descriptor > GlobalEdgeList; typedef std::map< vertex_descriptor, vertex_descriptor > LocalVertexMap; typedef std::map< edge_index_type, edge_descriptor > LocalEdgeMap; // TODO: Should the LocalVertexMap be: map? // TODO: Can we relax the indexing requirement if both descriptors are // LessThanComparable? // TODO: Should we really be using unorderd_map for improved lookup times? public: // Probably shouldn't be public.... Graph m_graph; subgraph< Graph >* m_parent; edge_index_type m_edge_counter; // for generating unique edge indices ChildrenList m_children; GlobalVertexList m_global_vertex; // local -> global LocalVertexMap m_local_vertex; // global -> local GlobalEdgeList m_global_edge; // local -> global LocalEdgeMap m_local_edge; // global -> local edge_descriptor local_add_edge(vertex_descriptor u_local, vertex_descriptor v_local, edge_descriptor e_global) { edge_descriptor e_local; bool inserted; boost::tie(e_local, inserted) = add_edge(u_local, v_local, m_graph); put(edge_index, m_graph, e_local, m_edge_counter++); m_global_edge.push_back(e_global); m_local_edge[get(get(edge_index, this->root()), e_global)] = e_local; return e_local; } }; template < typename Graph > struct vertex_bundle_type< subgraph< Graph > > : vertex_bundle_type< Graph > { }; template < typename Graph > struct edge_bundle_type< subgraph< Graph > > : edge_bundle_type< Graph > { }; template < typename Graph > struct graph_bundle_type< subgraph< Graph > > : graph_bundle_type< Graph > { }; //=========================================================================== // Functions special to the Subgraph Class template < typename G > typename subgraph< G >::vertex_descriptor add_vertex( typename subgraph< G >::vertex_descriptor u_global, subgraph< G >& g) { BOOST_ASSERT(!g.is_root()); typename subgraph< G >::vertex_descriptor u_local; bool exists_local; boost::tie(u_local, exists_local) = g.find_vertex(u_global); if (!exists_local) { typename subgraph< G >::vertex_descriptor v_global; typename subgraph< G >::edge_descriptor e_global; // call recursion for parent subgraph if (!g.parent().is_root()) add_vertex(u_global, g.parent()); u_local = add_vertex(g.m_graph); g.m_global_vertex.push_back(u_global); g.m_local_vertex[u_global] = u_local; subgraph< G >& r = g.root(); // remember edge global and local maps { typename subgraph< G >::out_edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = out_edges(u_global, r); ei != ei_end; ++ei) { e_global = *ei; v_global = target(e_global, r); if (g.find_vertex(v_global).second == true) g.local_add_edge( u_local, g.global_to_local(v_global), e_global); } } if (is_directed(g)) { // not necessary for undirected graph typename subgraph< G >::vertex_iterator vi, vi_end; typename subgraph< G >::out_edge_iterator ei, ei_end; for (boost::tie(vi, vi_end) = vertices(r); vi != vi_end; ++vi) { v_global = *vi; if (v_global == u_global) continue; // don't insert self loops twice! if (!g.find_vertex(v_global).second) continue; // not a subgraph vertex => try next one for (boost::tie(ei, ei_end) = out_edges(*vi, r); ei != ei_end; ++ei) { e_global = *ei; if (target(e_global, r) == u_global) { g.local_add_edge( g.global_to_local(v_global), u_local, e_global); } } } } } return u_local; } // NOTE: Descriptors are local unless otherwise noted. //=========================================================================== // Functions required by the IncidenceGraph concept template < typename G > std::pair< typename graph_traits< G >::out_edge_iterator, typename graph_traits< G >::out_edge_iterator > out_edges( typename graph_traits< G >::vertex_descriptor v, const subgraph< G >& g) { return out_edges(v, g.m_graph); } template < typename G > typename graph_traits< G >::degree_size_type out_degree( typename graph_traits< G >::vertex_descriptor v, const subgraph< G >& g) { return out_degree(v, g.m_graph); } template < typename G > typename graph_traits< G >::vertex_descriptor source( typename graph_traits< G >::edge_descriptor e, const subgraph< G >& g) { return source(e, g.m_graph); } template < typename G > typename graph_traits< G >::vertex_descriptor target( typename graph_traits< G >::edge_descriptor e, const subgraph< G >& g) { return target(e, g.m_graph); } //=========================================================================== // Functions required by the BidirectionalGraph concept template < typename G > std::pair< typename graph_traits< G >::in_edge_iterator, typename graph_traits< G >::in_edge_iterator > in_edges( typename graph_traits< G >::vertex_descriptor v, const subgraph< G >& g) { return in_edges(v, g.m_graph); } template < typename G > typename graph_traits< G >::degree_size_type in_degree( typename graph_traits< G >::vertex_descriptor v, const subgraph< G >& g) { return in_degree(v, g.m_graph); } template < typename G > typename graph_traits< G >::degree_size_type degree( typename graph_traits< G >::vertex_descriptor v, const subgraph< G >& g) { return degree(v, g.m_graph); } //=========================================================================== // Functions required by the AdjacencyGraph concept template < typename G > std::pair< typename subgraph< G >::adjacency_iterator, typename subgraph< G >::adjacency_iterator > adjacent_vertices( typename subgraph< G >::vertex_descriptor v, const subgraph< G >& g) { return adjacent_vertices(v, g.m_graph); } //=========================================================================== // Functions required by the VertexListGraph concept template < typename G > std::pair< typename subgraph< G >::vertex_iterator, typename subgraph< G >::vertex_iterator > vertices(const subgraph< G >& g) { return vertices(g.m_graph); } template < typename G > typename subgraph< G >::vertices_size_type num_vertices(const subgraph< G >& g) { return num_vertices(g.m_graph); } //=========================================================================== // Functions required by the EdgeListGraph concept template < typename G > std::pair< typename subgraph< G >::edge_iterator, typename subgraph< G >::edge_iterator > edges(const subgraph< G >& g) { return edges(g.m_graph); } template < typename G > typename subgraph< G >::edges_size_type num_edges(const subgraph< G >& g) { return num_edges(g.m_graph); } //=========================================================================== // Functions required by the AdjacencyMatrix concept template < typename G > std::pair< typename subgraph< G >::edge_descriptor, bool > edge( typename subgraph< G >::vertex_descriptor u, typename subgraph< G >::vertex_descriptor v, const subgraph< G >& g) { return edge(u, v, g.m_graph); } //=========================================================================== // Functions required by the MutableGraph concept namespace detail { template < typename Vertex, typename Edge, typename Graph > void add_edge_recur_down( Vertex u_global, Vertex v_global, Edge e_global, subgraph< Graph >& g); template < typename Vertex, typename Edge, typename Children, typename G > void children_add_edge(Vertex u_global, Vertex v_global, Edge e_global, Children& c, subgraph< G >* orig) { for (typename Children::iterator i = c.begin(); i != c.end(); ++i) { if ((*i)->find_vertex(u_global).second && (*i)->find_vertex(v_global).second) { add_edge_recur_down(u_global, v_global, e_global, **i, orig); } } } template < typename Vertex, typename Edge, typename Graph > void add_edge_recur_down(Vertex u_global, Vertex v_global, Edge e_global, subgraph< Graph >& g, subgraph< Graph >* orig) { if (&g != orig) { // add local edge only if u_global and v_global are in subgraph g Vertex u_local, v_local; bool u_in_subgraph, v_in_subgraph; boost::tie(u_local, u_in_subgraph) = g.find_vertex(u_global); boost::tie(v_local, v_in_subgraph) = g.find_vertex(v_global); if (u_in_subgraph && v_in_subgraph) { g.local_add_edge(u_local, v_local, e_global); } } children_add_edge(u_global, v_global, e_global, g.m_children, orig); } template < typename Vertex, typename Graph > std::pair< typename subgraph< Graph >::edge_descriptor, bool > add_edge_recur_up(Vertex u_global, Vertex v_global, const typename Graph::edge_property_type& ep, subgraph< Graph >& g, subgraph< Graph >* orig) { if (g.is_root()) { typename subgraph< Graph >::edge_descriptor e_global; bool inserted; boost::tie(e_global, inserted) = add_edge(u_global, v_global, ep, g.m_graph); put(edge_index, g.m_graph, e_global, g.m_edge_counter++); g.m_global_edge.push_back(e_global); children_add_edge(u_global, v_global, e_global, g.m_children, orig); return std::make_pair(e_global, inserted); } else { return add_edge_recur_up(u_global, v_global, ep, *g.m_parent, orig); } } } // namespace detail // Add an edge to the subgraph g, specified by the local vertex descriptors u // and v. In addition, the edge will be added to any (all) other subgraphs that // contain vertex descriptors u and v. template < typename G > std::pair< typename subgraph< G >::edge_descriptor, bool > add_edge( typename subgraph< G >::vertex_descriptor u, typename subgraph< G >::vertex_descriptor v, const typename G::edge_property_type& ep, subgraph< G >& g) { if (g.is_root()) { // u and v are really global return detail::add_edge_recur_up(u, v, ep, g, &g); } else { typename subgraph< G >::edge_descriptor e_local, e_global; bool inserted; boost::tie(e_global, inserted) = detail::add_edge_recur_up( g.local_to_global(u), g.local_to_global(v), ep, g, &g); e_local = g.local_add_edge(u, v, e_global); return std::make_pair(e_local, inserted); } } template < typename G > std::pair< typename subgraph< G >::edge_descriptor, bool > add_edge( typename subgraph< G >::vertex_descriptor u, typename subgraph< G >::vertex_descriptor v, subgraph< G >& g) { return add_edge(u, v, typename G::edge_property_type(), g); } namespace detail { //------------------------------------------------------------------------- // implementation of remove_edge(u,v,g) template < typename Vertex, typename Graph > void remove_edge_recur_down( Vertex u_global, Vertex v_global, subgraph< Graph >& g); template < typename Vertex, typename Children > void children_remove_edge(Vertex u_global, Vertex v_global, Children& c) { for (typename Children::iterator i = c.begin(); i != c.end(); ++i) { if ((*i)->find_vertex(u_global).second && (*i)->find_vertex(v_global).second) { remove_edge_recur_down(u_global, v_global, **i); } } } template < typename Vertex, typename Graph > void remove_edge_recur_down( Vertex u_global, Vertex v_global, subgraph< Graph >& g) { Vertex u_local, v_local; u_local = g.m_local_vertex[u_global]; v_local = g.m_local_vertex[v_global]; remove_edge(u_local, v_local, g.m_graph); children_remove_edge(u_global, v_global, g.m_children); } template < typename Vertex, typename Graph > void remove_edge_recur_up( Vertex u_global, Vertex v_global, subgraph< Graph >& g) { if (g.is_root()) { remove_edge(u_global, v_global, g.m_graph); children_remove_edge(u_global, v_global, g.m_children); } else { remove_edge_recur_up(u_global, v_global, *g.m_parent); } } //------------------------------------------------------------------------- // implementation of remove_edge(e,g) template < typename G, typename Edge, typename Children > void children_remove_edge(Edge e_global, Children& c) { for (typename Children::iterator i = c.begin(); i != c.end(); ++i) { std::pair< typename subgraph< G >::edge_descriptor, bool > found = (*i)->find_edge(e_global); if (!found.second) { continue; } children_remove_edge< G >(e_global, (*i)->m_children); remove_edge(found.first, (*i)->m_graph); } } } // namespace detail template < typename G > void remove_edge(typename subgraph< G >::vertex_descriptor u, typename subgraph< G >::vertex_descriptor v, subgraph< G >& g) { if (g.is_root()) { detail::remove_edge_recur_up(u, v, g); } else { detail::remove_edge_recur_up( g.local_to_global(u), g.local_to_global(v), g); } } template < typename G > void remove_edge(typename subgraph< G >::edge_descriptor e, subgraph< G >& g) { typename subgraph< G >::edge_descriptor e_global = g.local_to_global(e); #ifndef NDEBUG std::pair< typename subgraph< G >::edge_descriptor, bool > fe = g.find_edge(e_global); BOOST_ASSERT(fe.second && fe.first == e); #endif // NDEBUG subgraph< G >& root = g.root(); // chase to root detail::children_remove_edge< G >(e_global, root.m_children); remove_edge(e_global, root.m_graph); // kick edge from root } // This is slow, but there may not be a good way to do it safely otherwise template < typename Predicate, typename G > void remove_edge_if(Predicate p, subgraph< G >& g) { while (true) { bool any_removed = false; typedef typename subgraph< G >::edge_iterator ei_type; for (std::pair< ei_type, ei_type > ep = edges(g); ep.first != ep.second; ++ep.first) { if (p(*ep.first)) { any_removed = true; remove_edge(*ep.first, g); break; /* Since iterators may be invalidated */ } } if (!any_removed) break; } } template < typename G > void clear_vertex(typename subgraph< G >::vertex_descriptor v, subgraph< G >& g) { while (true) { typedef typename subgraph< G >::out_edge_iterator oei_type; std::pair< oei_type, oei_type > p = out_edges(v, g); if (p.first == p.second) break; remove_edge(*p.first, g); } } namespace detail { template < typename G > typename subgraph< G >::vertex_descriptor add_vertex_recur_up( subgraph< G >& g) { typename subgraph< G >::vertex_descriptor u_local, u_global; if (g.is_root()) { u_global = add_vertex(g.m_graph); g.m_global_vertex.push_back(u_global); } else { u_global = add_vertex_recur_up(*g.m_parent); u_local = add_vertex(g.m_graph); g.m_global_vertex.push_back(u_global); g.m_local_vertex[u_global] = u_local; } return u_global; } } // namespace detail template < typename G > typename subgraph< G >::vertex_descriptor add_vertex(subgraph< G >& g) { typename subgraph< G >::vertex_descriptor u_local, u_global; if (g.is_root()) { u_global = add_vertex(g.m_graph); g.m_global_vertex.push_back(u_global); u_local = u_global; } else { u_global = detail::add_vertex_recur_up(g.parent()); u_local = add_vertex(g.m_graph); g.m_global_vertex.push_back(u_global); g.m_local_vertex[u_global] = u_local; } return u_local; } #if 0 // TODO: Under Construction template void remove_vertex(typename subgraph::vertex_descriptor u, subgraph& g) { BOOST_ASSERT(false); } #endif //=========================================================================== // Functions required by the PropertyGraph concept /** * The global property map returns the global properties associated with local * descriptors. */ template < typename GraphPtr, typename PropertyMap, typename Tag > class subgraph_global_property_map : public put_get_helper< typename property_traits< PropertyMap >::reference, subgraph_global_property_map< GraphPtr, PropertyMap, Tag > > { typedef property_traits< PropertyMap > Traits; public: typedef typename mpl::if_< is_const< typename remove_pointer< GraphPtr >::type >, readable_property_map_tag, typename Traits::category >::type category; typedef typename Traits::value_type value_type; typedef typename Traits::key_type key_type; typedef typename Traits::reference reference; subgraph_global_property_map() {} subgraph_global_property_map(GraphPtr g, Tag tag) : m_g(g), m_tag(tag) {} reference operator[](key_type e) const { PropertyMap pmap = get(m_tag, m_g->root().m_graph); return m_g->is_root() ? pmap[e] : pmap[m_g->local_to_global(e)]; } GraphPtr m_g; Tag m_tag; }; /** * The local property map returns the local property associated with the local * descriptors. */ template < typename GraphPtr, typename PropertyMap, typename Tag > class subgraph_local_property_map : public put_get_helper< typename property_traits< PropertyMap >::reference, subgraph_local_property_map< GraphPtr, PropertyMap, Tag > > { typedef property_traits< PropertyMap > Traits; public: typedef typename mpl::if_< is_const< typename remove_pointer< GraphPtr >::type >, readable_property_map_tag, typename Traits::category >::type category; typedef typename Traits::value_type value_type; typedef typename Traits::key_type key_type; typedef typename Traits::reference reference; typedef Tag tag; typedef PropertyMap pmap; subgraph_local_property_map() {} subgraph_local_property_map(GraphPtr g, Tag tag) : m_g(g), m_tag(tag) {} reference operator[](key_type e) const { // Get property map on the underlying graph. PropertyMap pmap = get(m_tag, m_g->m_graph); return pmap[e]; } GraphPtr m_g; Tag m_tag; }; namespace detail { // Extract the actual tags from local or global property maps so we don't // try to find non-properties. template < typename P > struct extract_lg_tag { typedef P type; }; template < typename P > struct extract_lg_tag< local_property< P > > { typedef P type; }; template < typename P > struct extract_lg_tag< global_property< P > > { typedef P type; }; // NOTE: Mysterious Property template parameter unused in both metafunction // classes. struct subgraph_global_pmap { template < class Tag, class SubGraph, class Property > struct bind_ { typedef typename SubGraph::graph_type Graph; typedef SubGraph* SubGraphPtr; typedef const SubGraph* const_SubGraphPtr; typedef typename extract_lg_tag< Tag >::type TagType; typedef typename property_map< Graph, TagType >::type PMap; typedef typename property_map< Graph, TagType >::const_type const_PMap; public: typedef subgraph_global_property_map< SubGraphPtr, PMap, TagType > type; typedef subgraph_global_property_map< const_SubGraphPtr, const_PMap, TagType > const_type; }; }; struct subgraph_local_pmap { template < class Tag, class SubGraph, class Property > struct bind_ { typedef typename SubGraph::graph_type Graph; typedef SubGraph* SubGraphPtr; typedef const SubGraph* const_SubGraphPtr; typedef typename extract_lg_tag< Tag >::type TagType; typedef typename property_map< Graph, TagType >::type PMap; typedef typename property_map< Graph, TagType >::const_type const_PMap; public: typedef subgraph_local_property_map< SubGraphPtr, PMap, TagType > type; typedef subgraph_local_property_map< const_SubGraphPtr, const_PMap, TagType > const_type; }; }; // These metafunctions select the corresponding metafunctions above, and // are used by the choose_pmap metafunction below to specialize the choice // of local/global property map. By default, we defer to the global // property. template < class Tag > struct subgraph_choose_pmap_helper { typedef subgraph_global_pmap type; }; template < class Tag > struct subgraph_choose_pmap_helper< local_property< Tag > > { typedef subgraph_local_pmap type; }; template < class Tag > struct subgraph_choose_pmap_helper< global_property< Tag > > { typedef subgraph_global_pmap type; }; // As above, unless we're requesting vertex_index_t. Then it's always a // local property map. This enables the correct translation of descriptors // between local and global layers. template <> struct subgraph_choose_pmap_helper< vertex_index_t > { typedef subgraph_local_pmap type; }; template <> struct subgraph_choose_pmap_helper< local_property< vertex_index_t > > { typedef subgraph_local_pmap type; }; template <> struct subgraph_choose_pmap_helper< global_property< vertex_index_t > > { typedef subgraph_local_pmap type; }; // Determine the kind of property. If SameType, then // the property lookup is always local. Otherwise, the lookup is global. // NOTE: Property parameter is basically unused. template < class Tag, class Graph, class Property > struct subgraph_choose_pmap { typedef typename subgraph_choose_pmap_helper< Tag >::type Helper; typedef typename Helper::template bind_< Tag, Graph, Property > Bind; typedef typename Bind::type type; typedef typename Bind::const_type const_type; }; // Used by the vertex/edge property selectors to determine the kind(s) of // property maps used by the property_map type generator. struct subgraph_property_generator { template < class SubGraph, class Property, class Tag > struct bind_ { typedef subgraph_choose_pmap< Tag, SubGraph, Property > Choice; typedef typename Choice::type type; typedef typename Choice::const_type const_type; }; }; } // namespace detail template <> struct vertex_property_selector< subgraph_tag > { typedef detail::subgraph_property_generator type; }; template <> struct edge_property_selector< subgraph_tag > { typedef detail::subgraph_property_generator type; }; // ================================================== // get(p, g), get(p, g, k), and put(p, g, k, v) // ================================================== template < typename G, typename Property > typename property_map< subgraph< G >, Property >::type get( Property p, subgraph< G >& g) { typedef typename property_map< subgraph< G >, Property >::type PMap; return PMap(&g, p); } template < typename G, typename Property > typename property_map< subgraph< G >, Property >::const_type get( Property p, const subgraph< G >& g) { typedef typename property_map< subgraph< G >, Property >::const_type PMap; return PMap(&g, p); } template < typename G, typename Property, typename Key > typename property_traits< typename property_map< subgraph< G >, Property >::const_type >::value_type get(Property p, const subgraph< G >& g, const Key& k) { typedef typename property_map< subgraph< G >, Property >::const_type PMap; PMap pmap(&g, p); return pmap[k]; } template < typename G, typename Property, typename Key, typename Value > void put(Property p, subgraph< G >& g, const Key& k, const Value& val) { typedef typename property_map< subgraph< G >, Property >::type PMap; PMap pmap(&g, p); pmap[k] = val; } // ================================================== // get(global(p), g) // NOTE: get(global(p), g, k) and put(global(p), g, k, v) not supported // ================================================== template < typename G, typename Property > typename property_map< subgraph< G >, global_property< Property > >::type get( global_property< Property > p, subgraph< G >& g) { typedef typename property_map< subgraph< G >, global_property< Property > >::type Map; return Map(&g, p.value); } template < typename G, typename Property > typename property_map< subgraph< G >, global_property< Property > >::const_type get(global_property< Property > p, const subgraph< G >& g) { typedef typename property_map< subgraph< G >, global_property< Property > >::const_type Map; return Map(&g, p.value); } // ================================================== // get(local(p), g) // NOTE: get(local(p), g, k) and put(local(p), g, k, v) not supported // ================================================== template < typename G, typename Property > typename property_map< subgraph< G >, local_property< Property > >::type get( local_property< Property > p, subgraph< G >& g) { typedef typename property_map< subgraph< G >, local_property< Property > >::type Map; return Map(&g, p.value); } template < typename G, typename Property > typename property_map< subgraph< G >, local_property< Property > >::const_type get(local_property< Property > p, const subgraph< G >& g) { typedef typename property_map< subgraph< G >, local_property< Property > >::const_type Map; return Map(&g, p.value); } template < typename G, typename Tag > inline typename graph_property< G, Tag >::type& get_property( subgraph< G >& g, Tag tag) { return get_property(g.m_graph, tag); } template < typename G, typename Tag > inline const typename graph_property< G, Tag >::type& get_property( const subgraph< G >& g, Tag tag) { return get_property(g.m_graph, tag); } //=========================================================================== // Miscellaneous Functions template < typename G > typename subgraph< G >::vertex_descriptor vertex( typename subgraph< G >::vertices_size_type n, const subgraph< G >& g) { return vertex(n, g.m_graph); } //=========================================================================== // Mutability Traits // Just pull the mutability traits form the underlying graph. Note that this // will probably fail (badly) for labeled graphs. template < typename G > struct graph_mutability_traits< subgraph< G > > { typedef typename graph_mutability_traits< G >::category category; }; } // namespace boost #endif // BOOST_SUBGRAPH_HPP