| // Copyright (C) 2012, Michele Caini. |
| // 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) |
| |
| // Two Graphs Common Spanning Trees Algorithm |
| // Based on academic article of Mint, Read and Tarjan |
| // Efficient Algorithm for Common Spanning Tree Problem |
| // Electron. Lett., 28 April 1983, Volume 19, Issue 9, p.346-347 |
| |
| |
| #ifndef BOOST_GRAPH_TWO_GRAPHS_COMMON_SPANNING_TREES_HPP |
| #define BOOST_GRAPH_TWO_GRAPHS_COMMON_SPANNING_TREES_HPP |
| |
| |
| #include <boost/config.hpp> |
| |
| #include <boost/bimap.hpp> |
| #include <boost/type_traits.hpp> |
| #include <boost/concept/requires.hpp> |
| #include <boost/graph/graph_traits.hpp> |
| #include <boost/graph/undirected_dfs.hpp> |
| #include <boost/graph/connected_components.hpp> |
| #include <boost/graph/filtered_graph.hpp> |
| #include <vector> |
| #include <stack> |
| #include <map> |
| |
| |
| namespace boost |
| { |
| |
| |
| namespace detail { |
| |
| |
| template |
| < |
| typename TreeMap, |
| typename PredMap, |
| typename DistMap, |
| typename LowMap, |
| typename Buffer |
| > |
| struct bridges_visitor: public default_dfs_visitor |
| { |
| bridges_visitor( |
| TreeMap tree, |
| PredMap pred, |
| DistMap dist, |
| LowMap low, |
| Buffer& buffer |
| ): mTree(tree), mPred(pred), mDist(dist), mLow(low), mBuffer(buffer) |
| { mNum = -1; } |
| |
| template <typename Vertex, typename Graph> |
| void initialize_vertex(const Vertex& u, const Graph& g) |
| { |
| put(mPred, u, u); |
| put(mDist, u, -1); |
| } |
| |
| template <typename Vertex, typename Graph> |
| void discover_vertex(const Vertex& u, const Graph& g) |
| { |
| put(mDist, u, ++mNum); |
| put(mLow, u, get(mDist, u)); |
| } |
| |
| template <typename Edge, typename Graph> |
| void tree_edge(const Edge& e, const Graph& g) |
| { |
| put(mPred, target(e, g), source(e, g)); |
| put(mTree, target(e, g), e); |
| } |
| |
| template <typename Edge, typename Graph> |
| void back_edge(const Edge& e, const Graph& g) |
| { |
| put(mLow, source(e, g), |
| (std::min)(get(mLow, source(e, g)), get(mDist, target(e, g)))); |
| } |
| |
| template <typename Vertex, typename Graph> |
| void finish_vertex(const Vertex& u, const Graph& g) |
| { |
| Vertex parent = get(mPred, u); |
| if(get(mLow, u) > get(mDist, parent)) |
| mBuffer.push(get(mTree, u)); |
| put(mLow, parent, |
| (std::min)(get(mLow, parent), get(mLow, u))); |
| } |
| |
| TreeMap mTree; |
| PredMap mPred; |
| DistMap mDist; |
| LowMap mLow; |
| Buffer& mBuffer; |
| int mNum; |
| }; |
| |
| |
| template <typename Buffer> |
| struct cycle_finder: public base_visitor< cycle_finder<Buffer> > |
| { |
| typedef on_back_edge event_filter; |
| cycle_finder(): mBuffer(0) { } |
| cycle_finder(Buffer* buffer) |
| : mBuffer(buffer) { } |
| template <typename Edge, typename Graph> |
| void operator()(const Edge& e, const Graph& g) |
| { |
| if(mBuffer) |
| mBuffer->push(e); |
| } |
| Buffer* mBuffer; |
| }; |
| |
| |
| template <typename DeletedMap> |
| struct deleted_edge_status |
| { |
| deleted_edge_status() { } |
| deleted_edge_status(DeletedMap map): mMap(map) { } |
| template <typename Edge> |
| bool operator()(const Edge& e) const |
| { return (!get(mMap, e)); } |
| DeletedMap mMap; |
| }; |
| |
| |
| template <typename InLMap> |
| struct inL_edge_status |
| { |
| inL_edge_status() { } |
| inL_edge_status(InLMap map): mMap(map) { } |
| template <typename Edge> |
| bool operator()(const Edge& e) const |
| { return get(mMap, e); } |
| InLMap mMap; |
| }; |
| |
| |
| template < |
| typename Graph, |
| typename Func, |
| typename Seq, |
| typename Map |
| > |
| void rec_two_graphs_common_spanning_trees |
| ( |
| const Graph& iG, |
| bimap< |
| bimaps::set_of<int>, |
| bimaps::set_of< typename graph_traits<Graph>::edge_descriptor > |
| > iG_bimap, |
| Map aiG_inL, |
| Map diG, |
| const Graph& vG, |
| bimap< |
| bimaps::set_of<int>, |
| bimaps::set_of< typename graph_traits<Graph>::edge_descriptor > |
| > vG_bimap, |
| Map avG_inL, |
| Map dvG, |
| Func func, |
| Seq inL |
| ) |
| { |
| typedef graph_traits<Graph> GraphTraits; |
| |
| typedef typename GraphTraits::vertex_descriptor vertex_descriptor; |
| typedef typename GraphTraits::edge_descriptor edge_descriptor; |
| |
| typedef typename Seq::size_type seq_size_type; |
| |
| int edges = num_vertices(iG) - 1; |
| // |
| // [ Michele Caini ] |
| // |
| // Using the condition (edges != 0) leads to the accidental submission of |
| // sub-graphs ((V-1+1)-fake-tree, named here fat-tree). |
| // Remove this condition is a workaround for the problem of fat-trees. |
| // Please do not add that condition, even if it improves performance. |
| // |
| // Here is proposed the previous guard (that was wrong): |
| // for(seq_size_type i = 0; (i < inL.size()) && (edges != 0); ++i) |
| // |
| { |
| for(seq_size_type i = 0; i < inL.size(); ++i) |
| if(inL[i]) |
| --edges; |
| |
| if(edges < 0) |
| return; |
| } |
| |
| bool is_tree = (edges == 0); |
| if(is_tree) { |
| func(inL); |
| } else { |
| std::map<vertex_descriptor, default_color_type> vertex_color; |
| std::map<edge_descriptor, default_color_type> edge_color; |
| |
| std::stack<edge_descriptor> iG_buf, vG_buf; |
| bool found = false; |
| |
| seq_size_type m; |
| for(seq_size_type j = 0; j < inL.size() && !found; ++j) { |
| if(!inL[j] |
| && !get(diG, iG_bimap.left.at(j)) |
| && !get(dvG, vG_bimap.left.at(j))) |
| { |
| put(aiG_inL, iG_bimap.left.at(j), true); |
| put(avG_inL, vG_bimap.left.at(j), true); |
| |
| undirected_dfs( |
| make_filtered_graph(iG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(aiG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< std::stack<edge_descriptor> > (&iG_buf)), |
| associative_property_map< |
| std::map<vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| undirected_dfs( |
| make_filtered_graph(vG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(avG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< std::stack<edge_descriptor> > (&vG_buf)), |
| associative_property_map< |
| std::map<vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| |
| if(iG_buf.empty() && vG_buf.empty()) { |
| inL[j] = true; |
| found = true; |
| m = j; |
| } else { |
| while(!iG_buf.empty()) iG_buf.pop(); |
| while(!vG_buf.empty()) vG_buf.pop(); |
| put(aiG_inL, iG_bimap.left.at(j), false); |
| put(avG_inL, vG_bimap.left.at(j), false); |
| } |
| } |
| } |
| |
| if(found) { |
| |
| std::stack<edge_descriptor> iG_buf_copy, vG_buf_copy; |
| for(seq_size_type j = 0; j < inL.size(); ++j) { |
| if(!inL[j] |
| && !get(diG, iG_bimap.left.at(j)) |
| && !get(dvG, vG_bimap.left.at(j))) |
| { |
| |
| put(aiG_inL, iG_bimap.left.at(j), true); |
| put(avG_inL, vG_bimap.left.at(j), true); |
| |
| undirected_dfs( |
| make_filtered_graph(iG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(aiG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< |
| std::stack<edge_descriptor> > (&iG_buf)), |
| associative_property_map< std::map< |
| vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| undirected_dfs( |
| make_filtered_graph(vG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(avG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< |
| std::stack<edge_descriptor> > (&vG_buf)), |
| associative_property_map< std::map< |
| vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| |
| if(!iG_buf.empty() || !vG_buf.empty()) { |
| while(!iG_buf.empty()) iG_buf.pop(); |
| while(!vG_buf.empty()) vG_buf.pop(); |
| put(diG, iG_bimap.left.at(j), true); |
| put(dvG, vG_bimap.left.at(j), true); |
| iG_buf_copy.push(iG_bimap.left.at(j)); |
| vG_buf_copy.push(vG_bimap.left.at(j)); |
| } |
| |
| put(aiG_inL, iG_bimap.left.at(j), false); |
| put(avG_inL, vG_bimap.left.at(j), false); |
| } |
| } |
| |
| // REC |
| detail::rec_two_graphs_common_spanning_trees<Graph, Func, Seq, Map> |
| (iG, iG_bimap, aiG_inL, diG, vG, vG_bimap, aiG_inL, dvG, func, inL); |
| |
| while(!iG_buf_copy.empty()) { |
| put(diG, iG_buf_copy.top(), false); |
| put(dvG, vG_bimap.left.at( |
| iG_bimap.right.at(iG_buf_copy.top())), false); |
| iG_buf_copy.pop(); |
| } |
| while(!vG_buf_copy.empty()) { |
| put(dvG, vG_buf_copy.top(), false); |
| put(diG, iG_bimap.left.at( |
| vG_bimap.right.at(vG_buf_copy.top())), false); |
| vG_buf_copy.pop(); |
| } |
| |
| inL[m] = false; |
| put(aiG_inL, iG_bimap.left.at(m), false); |
| put(avG_inL, vG_bimap.left.at(m), false); |
| |
| put(diG, iG_bimap.left.at(m), true); |
| put(dvG, vG_bimap.left.at(m), true); |
| |
| std::map<vertex_descriptor, edge_descriptor> tree_map; |
| std::map<vertex_descriptor, vertex_descriptor> pred_map; |
| std::map<vertex_descriptor, int> dist_map, low_map; |
| |
| detail::bridges_visitor< |
| associative_property_map< |
| std::map<vertex_descriptor, edge_descriptor> |
| >, |
| associative_property_map< |
| std::map<vertex_descriptor, vertex_descriptor> |
| >, |
| associative_property_map< std::map<vertex_descriptor, int> >, |
| associative_property_map< std::map<vertex_descriptor, int> >, |
| std::stack<edge_descriptor> |
| > |
| iG_vis( |
| associative_property_map< |
| std::map< vertex_descriptor, edge_descriptor> >(tree_map), |
| associative_property_map< |
| std::map< vertex_descriptor, vertex_descriptor> >(pred_map), |
| associative_property_map< |
| std::map< vertex_descriptor, int> >(dist_map), |
| associative_property_map< |
| std::map< vertex_descriptor, int> >(low_map), |
| iG_buf |
| ), |
| vG_vis( |
| associative_property_map< |
| std::map< vertex_descriptor, edge_descriptor> >(tree_map), |
| associative_property_map< |
| std::map< vertex_descriptor, vertex_descriptor> >(pred_map), |
| associative_property_map< |
| std::map< vertex_descriptor, int> >(dist_map), |
| associative_property_map< |
| std::map< vertex_descriptor, int> >(low_map), |
| vG_buf |
| ); |
| |
| undirected_dfs(make_filtered_graph(iG, |
| detail::deleted_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(diG)), |
| iG_vis, |
| associative_property_map< |
| std::map<vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| undirected_dfs(make_filtered_graph(vG, |
| detail::deleted_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(dvG)), |
| vG_vis, |
| associative_property_map< |
| std::map<vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| |
| found = false; |
| std::stack<edge_descriptor> iG_buf_tmp, vG_buf_tmp; |
| while(!iG_buf.empty() && !found) { |
| if(!inL[iG_bimap.right.at(iG_buf.top())]) { |
| put(aiG_inL, iG_buf.top(), true); |
| put(avG_inL, vG_bimap.left.at( |
| iG_bimap.right.at(iG_buf.top())), true); |
| |
| undirected_dfs( |
| make_filtered_graph(iG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(aiG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< |
| std::stack<edge_descriptor> > (&iG_buf_tmp)), |
| associative_property_map< |
| std::map< |
| vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| undirected_dfs( |
| make_filtered_graph(vG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(avG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< |
| std::stack<edge_descriptor> > (&vG_buf_tmp)), |
| associative_property_map< |
| std::map< |
| vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| |
| if(!iG_buf_tmp.empty() || !vG_buf_tmp.empty()) { |
| found = true; |
| } else { |
| while(!iG_buf_tmp.empty()) iG_buf_tmp.pop(); |
| while(!vG_buf_tmp.empty()) vG_buf_tmp.pop(); |
| iG_buf_copy.push(iG_buf.top()); |
| } |
| |
| put(aiG_inL, iG_buf.top(), false); |
| put(avG_inL, vG_bimap.left.at( |
| iG_bimap.right.at(iG_buf.top())), false); |
| } |
| iG_buf.pop(); |
| } |
| while(!vG_buf.empty() && !found) { |
| if(!inL[vG_bimap.right.at(vG_buf.top())]) { |
| put(avG_inL, vG_buf.top(), true); |
| put(aiG_inL, iG_bimap.left.at( |
| vG_bimap.right.at(vG_buf.top())), true); |
| |
| undirected_dfs( |
| make_filtered_graph(iG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(aiG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< |
| std::stack<edge_descriptor> > (&iG_buf_tmp)), |
| associative_property_map< |
| std::map< |
| vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| undirected_dfs( |
| make_filtered_graph(vG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(avG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< |
| std::stack<edge_descriptor> > (&vG_buf_tmp)), |
| associative_property_map< |
| std::map< |
| vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| |
| if(!iG_buf_tmp.empty() || !vG_buf_tmp.empty()) { |
| found = true; |
| } else { |
| while(!iG_buf_tmp.empty()) iG_buf_tmp.pop(); |
| while(!vG_buf_tmp.empty()) vG_buf_tmp.pop(); |
| vG_buf_copy.push(vG_buf.top()); |
| } |
| |
| put(avG_inL, vG_buf.top(), false); |
| put(aiG_inL, iG_bimap.left.at( |
| vG_bimap.right.at(vG_buf.top())), false); |
| } |
| vG_buf.pop(); |
| } |
| |
| if(!found) { |
| |
| while(!iG_buf_copy.empty()) { |
| inL[iG_bimap.right.at(iG_buf_copy.top())] = true; |
| put(aiG_inL, iG_buf_copy.top(), true); |
| put(avG_inL, vG_bimap.left.at( |
| iG_bimap.right.at(iG_buf_copy.top())), true); |
| iG_buf.push(iG_buf_copy.top()); |
| iG_buf_copy.pop(); |
| } |
| while(!vG_buf_copy.empty()) { |
| inL[vG_bimap.right.at(vG_buf_copy.top())] = true; |
| put(avG_inL, vG_buf_copy.top(), true); |
| put(aiG_inL, iG_bimap.left.at( |
| vG_bimap.right.at(vG_buf_copy.top())), true); |
| vG_buf.push(vG_buf_copy.top()); |
| vG_buf_copy.pop(); |
| } |
| |
| // REC |
| detail::rec_two_graphs_common_spanning_trees< |
| Graph, Func, Seq, Map> |
| (iG, iG_bimap, aiG_inL, diG, vG, vG_bimap, aiG_inL, dvG, func, inL); |
| |
| while(!iG_buf.empty()) { |
| inL[iG_bimap.right.at(iG_buf.top())] = false; |
| put(aiG_inL, iG_buf.top(), false); |
| put(avG_inL, vG_bimap.left.at( |
| iG_bimap.right.at(iG_buf.top())), false); |
| iG_buf.pop(); |
| } |
| while(!vG_buf.empty()) { |
| inL[vG_bimap.right.at(vG_buf.top())] = false; |
| put(avG_inL, vG_buf.top(), false); |
| put(aiG_inL, iG_bimap.left.at( |
| vG_bimap.right.at(vG_buf.top())), false); |
| vG_buf.pop(); |
| } |
| |
| } |
| |
| put(diG, iG_bimap.left.at(m), false); |
| put(dvG, vG_bimap.left.at(m), false); |
| |
| } |
| } |
| } |
| |
| } // namespace detail |
| |
| |
| |
| template <typename Coll, typename Seq> |
| struct tree_collector |
| { |
| |
| public: |
| BOOST_CONCEPT_ASSERT((BackInsertionSequence<Coll>)); |
| BOOST_CONCEPT_ASSERT((RandomAccessContainer<Seq>)); |
| BOOST_CONCEPT_ASSERT((CopyConstructible<Seq>)); |
| |
| typedef typename Coll::value_type coll_value_type; |
| typedef typename Seq::value_type seq_value_type; |
| |
| BOOST_STATIC_ASSERT((is_same<coll_value_type, Seq>::value)); |
| BOOST_STATIC_ASSERT((is_same<seq_value_type, bool>::value)); |
| |
| tree_collector(Coll& seqs): mSeqs(seqs) { } |
| |
| inline void operator()(Seq seq) |
| { mSeqs.push_back(seq); } |
| |
| private: |
| Coll& mSeqs; |
| |
| }; |
| |
| |
| |
| template < |
| typename Graph, |
| typename Order, |
| typename Func, |
| typename Seq |
| > |
| BOOST_CONCEPT_REQUIRES( |
| ((RandomAccessContainer<Order>)) |
| ((IncidenceGraphConcept<Graph>)) |
| ((UnaryFunction<Func, void, Seq>)) |
| ((Mutable_RandomAccessContainer<Seq>)) |
| ((VertexAndEdgeListGraphConcept<Graph>)), |
| (void) |
| ) |
| two_graphs_common_spanning_trees |
| ( |
| const Graph& iG, |
| Order iG_map, |
| const Graph& vG, |
| Order vG_map, |
| Func func, |
| Seq inL |
| ) |
| { |
| typedef graph_traits<Graph> GraphTraits; |
| |
| typedef typename GraphTraits::directed_category directed_category; |
| typedef typename GraphTraits::vertex_descriptor vertex_descriptor; |
| typedef typename GraphTraits::edge_descriptor edge_descriptor; |
| |
| typedef typename GraphTraits::edges_size_type edges_size_type; |
| typedef typename GraphTraits::edge_iterator edge_iterator; |
| |
| typedef typename Seq::value_type seq_value_type; |
| typedef typename Seq::size_type seq_size_type; |
| |
| typedef typename Order::value_type order_value_type; |
| typedef typename Order::size_type order_size_type; |
| |
| BOOST_STATIC_ASSERT((is_same<order_value_type, edge_descriptor>::value)); |
| BOOST_CONCEPT_ASSERT((Convertible<order_size_type, edges_size_type>)); |
| |
| BOOST_CONCEPT_ASSERT((Convertible<seq_size_type, edges_size_type>)); |
| BOOST_STATIC_ASSERT((is_same<seq_value_type, bool>::value)); |
| |
| BOOST_STATIC_ASSERT((is_same<directed_category, undirected_tag>::value)); |
| |
| if(num_vertices(iG) != num_vertices(vG)) |
| return; |
| |
| if(inL.size() != num_edges(iG) |
| || inL.size() != num_edges(vG)) |
| return; |
| |
| if(iG_map.size() != num_edges(iG) |
| || vG_map.size() != num_edges(vG)) |
| return; |
| |
| typedef bimaps::bimap< |
| bimaps::set_of< int >, |
| bimaps::set_of< order_value_type > |
| > bimap_type; |
| typedef typename bimap_type::value_type bimap_value; |
| |
| bimap_type iG_bimap, vG_bimap; |
| for(order_size_type i = 0; i < iG_map.size(); ++i) |
| iG_bimap.insert(bimap_value(i, iG_map[i])); |
| for(order_size_type i = 0; i < vG_map.size(); ++i) |
| vG_bimap.insert(bimap_value(i, vG_map[i])); |
| |
| edge_iterator current, last; |
| boost::tuples::tie(current, last) = edges(iG); |
| for(; current != last; ++current) |
| if(iG_bimap.right.find(*current) == iG_bimap.right.end()) |
| return; |
| boost::tuples::tie(current, last) = edges(vG); |
| for(; current != last; ++current) |
| if(vG_bimap.right.find(*current) == vG_bimap.right.end()) |
| return; |
| |
| std::stack<edge_descriptor> iG_buf, vG_buf; |
| |
| std::map<vertex_descriptor, edge_descriptor> tree_map; |
| std::map<vertex_descriptor, vertex_descriptor> pred_map; |
| std::map<vertex_descriptor, int> dist_map, low_map; |
| |
| detail::bridges_visitor< |
| associative_property_map< |
| std::map<vertex_descriptor, edge_descriptor> |
| >, |
| associative_property_map< |
| std::map<vertex_descriptor, vertex_descriptor> |
| >, |
| associative_property_map< std::map<vertex_descriptor, int> >, |
| associative_property_map< std::map<vertex_descriptor, int> >, |
| std::stack<edge_descriptor> |
| > |
| iG_vis( |
| associative_property_map< |
| std::map< vertex_descriptor, edge_descriptor> >(tree_map), |
| associative_property_map< |
| std::map< vertex_descriptor, vertex_descriptor> >(pred_map), |
| associative_property_map<std::map< vertex_descriptor, int> >(dist_map), |
| associative_property_map<std::map< vertex_descriptor, int> >(low_map), |
| iG_buf |
| ), |
| vG_vis( |
| associative_property_map< |
| std::map< vertex_descriptor, edge_descriptor> >(tree_map), |
| associative_property_map< |
| std::map< vertex_descriptor, vertex_descriptor> >(pred_map), |
| associative_property_map<std::map< vertex_descriptor, int> >(dist_map), |
| associative_property_map<std::map< vertex_descriptor, int> >(low_map), |
| vG_buf |
| ); |
| |
| std::map<vertex_descriptor, default_color_type> vertex_color; |
| std::map<edge_descriptor, default_color_type> edge_color; |
| |
| undirected_dfs(iG, iG_vis, |
| associative_property_map< |
| std::map<vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| undirected_dfs(vG, vG_vis, |
| associative_property_map< |
| std::map<vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| |
| while(!iG_buf.empty()) { |
| inL[iG_bimap.right.at(iG_buf.top())] = true; |
| iG_buf.pop(); |
| } |
| while(!vG_buf.empty()) { |
| inL[vG_bimap.right.at(vG_buf.top())] = true; |
| vG_buf.pop(); |
| } |
| |
| std::map<edge_descriptor, bool> iG_inL, vG_inL; |
| associative_property_map< std::map<edge_descriptor, bool> > |
| aiG_inL(iG_inL), avG_inL(vG_inL); |
| |
| for(seq_size_type i = 0; i < inL.size(); ++i) |
| { |
| if(inL[i]) { |
| put(aiG_inL, iG_bimap.left.at(i), true); |
| put(avG_inL, vG_bimap.left.at(i), true); |
| } else { |
| put(aiG_inL, iG_bimap.left.at(i), false); |
| put(avG_inL, vG_bimap.left.at(i), false); |
| } |
| } |
| |
| undirected_dfs( |
| make_filtered_graph(iG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(aiG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< std::stack<edge_descriptor> > (&iG_buf)), |
| associative_property_map< |
| std::map<vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| undirected_dfs( |
| make_filtered_graph(vG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(avG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< std::stack<edge_descriptor> > (&vG_buf)), |
| associative_property_map< |
| std::map<vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| |
| if(iG_buf.empty() && vG_buf.empty()) { |
| |
| std::map<edge_descriptor, bool> iG_deleted, vG_deleted; |
| associative_property_map< std::map<edge_descriptor, bool> > diG(iG_deleted); |
| associative_property_map< std::map<edge_descriptor, bool> > dvG(vG_deleted); |
| |
| boost::tuples::tie(current, last) = edges(iG); |
| for(; current != last; ++current) |
| put(diG, *current, false); |
| boost::tuples::tie(current, last) = edges(vG); |
| for(; current != last; ++current) |
| put(dvG, *current, false); |
| |
| for(seq_size_type j = 0; j < inL.size(); ++j) { |
| if(!inL[j]) { |
| put(aiG_inL, iG_bimap.left.at(j), true); |
| put(avG_inL, vG_bimap.left.at(j), true); |
| |
| undirected_dfs( |
| make_filtered_graph(iG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(aiG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< std::stack<edge_descriptor> > (&iG_buf)), |
| associative_property_map< |
| std::map<vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| undirected_dfs( |
| make_filtered_graph(vG, |
| detail::inL_edge_status< associative_property_map< |
| std::map<edge_descriptor, bool> > >(avG_inL)), |
| make_dfs_visitor( |
| detail::cycle_finder< std::stack<edge_descriptor> > (&vG_buf)), |
| associative_property_map< |
| std::map<vertex_descriptor, default_color_type> >(vertex_color), |
| associative_property_map< |
| std::map<edge_descriptor, default_color_type> >(edge_color) |
| ); |
| |
| if(!iG_buf.empty() || !vG_buf.empty()) { |
| while(!iG_buf.empty()) iG_buf.pop(); |
| while(!vG_buf.empty()) vG_buf.pop(); |
| put(diG, iG_bimap.left.at(j), true); |
| put(dvG, vG_bimap.left.at(j), true); |
| } |
| |
| put(aiG_inL, iG_bimap.left.at(j), false); |
| put(avG_inL, vG_bimap.left.at(j), false); |
| } |
| } |
| |
| int cc = 0; |
| |
| std::map<vertex_descriptor, int> com_map; |
| cc += connected_components( |
| make_filtered_graph(iG, |
| detail::deleted_edge_status<associative_property_map< |
| std::map<edge_descriptor, bool> > >(diG)), |
| associative_property_map<std::map<vertex_descriptor, int> >(com_map) |
| ); |
| cc += connected_components( |
| make_filtered_graph(vG, |
| detail::deleted_edge_status<associative_property_map< |
| std::map<edge_descriptor, bool> > >(dvG)), |
| associative_property_map< std::map<vertex_descriptor, int> >(com_map) |
| ); |
| |
| if(cc != 2) |
| return; |
| |
| // REC |
| detail::rec_two_graphs_common_spanning_trees<Graph, Func, Seq, |
| associative_property_map< std::map<edge_descriptor, bool> > > |
| (iG, iG_bimap, aiG_inL, diG, vG, vG_bimap, aiG_inL, dvG, func, inL); |
| |
| } |
| |
| } |
| |
| |
| template < |
| typename Graph, |
| typename Func, |
| typename Seq |
| > |
| BOOST_CONCEPT_REQUIRES( |
| ((IncidenceGraphConcept<Graph>)) |
| ((EdgeListGraphConcept<Graph>)), |
| (void) |
| ) |
| two_graphs_common_spanning_trees |
| ( |
| const Graph& iG, |
| const Graph& vG, |
| Func func, |
| Seq inL |
| ) |
| { |
| typedef graph_traits<Graph> GraphTraits; |
| |
| typedef typename GraphTraits::edge_descriptor edge_descriptor; |
| typedef typename GraphTraits::edge_iterator edge_iterator; |
| |
| std::vector<edge_descriptor> iGO, vGO; |
| edge_iterator curr, last; |
| |
| boost::tuples::tie(curr, last) = edges(iG); |
| for(; curr != last; ++curr) |
| iGO.push_back(*curr); |
| |
| boost::tuples::tie(curr, last) = edges(vG); |
| for(; curr != last; ++curr) |
| vGO.push_back(*curr); |
| |
| two_graphs_common_spanning_trees(iG, iGO, vG, vGO, func, inL); |
| } |
| |
| |
| } // namespace boost |
| |
| |
| #endif // BOOST_GRAPH_TWO_GRAPHS_COMMON_SPANNING_TREES_HPP |