sl@0: //
sl@0: //=======================================================================
sl@0: // Copyright 1997-2001 University of Notre Dame.
sl@0: // Authors: Jeremy G. Siek, Lie-Quan Lee, Andrew Lumsdaine
sl@0: //
sl@0: // Distributed under the Boost Software License, Version 1.0. (See
sl@0: // accompanying file LICENSE_1_0.txt or copy at
sl@0: // http://www.boost.org/LICENSE_1_0.txt)
sl@0: //=======================================================================
sl@0: //
sl@0: 
sl@0: /*
sl@0:   This file implements the following functions:
sl@0: 
sl@0: 
sl@0:   template <typename VertexListGraph, typename MutableGraph>
sl@0:   void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out)
sl@0: 
sl@0:   template <typename VertexListGraph, typename MutableGraph, 
sl@0:     class P, class T, class R>
sl@0:   void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out, 
sl@0:                   const bgl_named_params<P, T, R>& params)
sl@0: 
sl@0: 
sl@0:   template <typename IncidenceGraph, typename MutableGraph>
sl@0:   typename graph_traits<MutableGraph>::vertex_descriptor
sl@0:   copy_component(IncidenceGraph& g_in, 
sl@0:                  typename graph_traits<IncidenceGraph>::vertex_descriptor src,
sl@0:                  MutableGraph& g_out)
sl@0: 
sl@0:   template <typename IncidenceGraph, typename MutableGraph, 
sl@0:            typename P, typename T, typename R>
sl@0:   typename graph_traits<MutableGraph>::vertex_descriptor
sl@0:   copy_component(IncidenceGraph& g_in, 
sl@0:                  typename graph_traits<IncidenceGraph>::vertex_descriptor src,
sl@0:                  MutableGraph& g_out, 
sl@0:                  const bgl_named_params<P, T, R>& params)
sl@0:  */
sl@0: 
sl@0: 
sl@0: #ifndef BOOST_GRAPH_COPY_HPP
sl@0: #define BOOST_GRAPH_COPY_HPP
sl@0: 
sl@0: #include <boost/config.hpp>
sl@0: #include <vector>
sl@0: #include <boost/graph/graph_traits.hpp>
sl@0: #include <boost/property_map.hpp>
sl@0: #include <boost/graph/named_function_params.hpp>
sl@0: #include <boost/graph/breadth_first_search.hpp>
sl@0: #include <boost/type_traits/conversion_traits.hpp>
sl@0: 
sl@0: namespace boost {
sl@0: 
sl@0:   namespace detail {
sl@0: 
sl@0:     // Default edge and vertex property copiers
sl@0: 
sl@0:     template <typename Graph1, typename Graph2>
sl@0:     struct edge_copier {
sl@0:       edge_copier(const Graph1& g1, Graph2& g2)
sl@0:         : edge_all_map1(get(edge_all, g1)), 
sl@0:           edge_all_map2(get(edge_all, g2)) { }
sl@0: 
sl@0:       template <typename Edge1, typename Edge2>
sl@0:       void operator()(const Edge1& e1, Edge2& e2) const {
sl@0:         put(edge_all_map2, e2, get(edge_all_map1, e1));
sl@0:       }
sl@0:       typename property_map<Graph1, edge_all_t>::const_type edge_all_map1;
sl@0:       mutable typename property_map<Graph2, edge_all_t>::type edge_all_map2;
sl@0:     };
sl@0:     template <typename Graph1, typename Graph2>
sl@0:     inline edge_copier<Graph1,Graph2>
sl@0:     make_edge_copier(const Graph1& g1, Graph2& g2)
sl@0:     {
sl@0:       return edge_copier<Graph1,Graph2>(g1, g2);
sl@0:     }
sl@0: 
sl@0:     template <typename Graph1, typename Graph2>
sl@0:     struct vertex_copier {
sl@0:       vertex_copier(const Graph1& g1, Graph2& g2)
sl@0:         : vertex_all_map1(get(vertex_all, g1)), 
sl@0:           vertex_all_map2(get(vertex_all, g2)) { }
sl@0: 
sl@0:       template <typename Vertex1, typename Vertex2>
sl@0:       void operator()(const Vertex1& v1, Vertex2& v2) const {
sl@0:         put(vertex_all_map2, v2, get(vertex_all_map1, v1));
sl@0:       }
sl@0:       typename property_map<Graph1, vertex_all_t>::const_type vertex_all_map1;
sl@0:       mutable typename property_map<Graph2, vertex_all_t>::type
sl@0:         vertex_all_map2;
sl@0:     };
sl@0:     template <typename Graph1, typename Graph2>
sl@0:     inline vertex_copier<Graph1,Graph2>
sl@0:     make_vertex_copier(const Graph1& g1, Graph2& g2)
sl@0:     {
sl@0:       return vertex_copier<Graph1,Graph2>(g1, g2);
sl@0:     }
sl@0: 
sl@0:     // Copy all the vertices and edges of graph g_in into graph g_out.
sl@0:     // The copy_vertex and copy_edge function objects control how vertex
sl@0:     // and edge properties are copied.
sl@0: 
sl@0:     template <int Version>
sl@0:     struct copy_graph_impl { };
sl@0: 
sl@0:     template <> struct copy_graph_impl<0>
sl@0:     {
sl@0:       template <typename Graph, typename MutableGraph, 
sl@0:         typename CopyVertex, typename CopyEdge, typename IndexMap,
sl@0:         typename Orig2CopyVertexIndexMap>
sl@0:       static void apply(const Graph& g_in, MutableGraph& g_out, 
sl@0:                         CopyVertex copy_vertex, CopyEdge copy_edge,
sl@0:                         Orig2CopyVertexIndexMap orig2copy, IndexMap)
sl@0:       {
sl@0:         typename graph_traits<Graph>::vertex_iterator vi, vi_end;
sl@0:         for (tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) {
sl@0:           typename graph_traits<MutableGraph>::vertex_descriptor
sl@0:             new_v = add_vertex(g_out);
sl@0:           put(orig2copy, *vi, new_v);
sl@0:           copy_vertex(*vi, new_v);
sl@0:         }
sl@0:         typename graph_traits<Graph>::edge_iterator ei, ei_end;
sl@0:         for (tie(ei, ei_end) = edges(g_in); ei != ei_end; ++ei) {
sl@0:           typename graph_traits<MutableGraph>::edge_descriptor new_e;
sl@0:           bool inserted;
sl@0:           tie(new_e, inserted) = add_edge(get(orig2copy, source(*ei, g_in)), 
sl@0:                                           get(orig2copy, target(*ei, g_in)),
sl@0:                                           g_out);
sl@0:           copy_edge(*ei, new_e);
sl@0:         }
sl@0:       }
sl@0:     };
sl@0: 
sl@0:     // for directed graphs
sl@0:     template <> struct copy_graph_impl<1>
sl@0:     {
sl@0:       template <typename Graph, typename MutableGraph, 
sl@0:         typename CopyVertex, typename CopyEdge, typename IndexMap,
sl@0:         typename Orig2CopyVertexIndexMap>
sl@0:       static void apply(const Graph& g_in, MutableGraph& g_out, 
sl@0:                         CopyVertex copy_vertex, CopyEdge copy_edge,
sl@0:                         Orig2CopyVertexIndexMap orig2copy, IndexMap)
sl@0:       {
sl@0:         typename graph_traits<Graph>::vertex_iterator vi, vi_end;
sl@0:         for (tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) {
sl@0:           typename graph_traits<MutableGraph>::vertex_descriptor
sl@0:             new_v = add_vertex(g_out);
sl@0:           put(orig2copy, *vi, new_v);
sl@0:           copy_vertex(*vi, new_v);
sl@0:         }
sl@0:         for (tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) {
sl@0:           typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
sl@0:           for (tie(ei, ei_end) = out_edges(*vi, g_in); ei != ei_end; ++ei) {
sl@0:             typename graph_traits<MutableGraph>::edge_descriptor new_e;
sl@0:             bool inserted;
sl@0:             tie(new_e, inserted) = add_edge(get(orig2copy, source(*ei, g_in)), 
sl@0:                                             get(orig2copy, target(*ei, g_in)),
sl@0:                                             g_out);
sl@0:             copy_edge(*ei, new_e);
sl@0:           }
sl@0:         }
sl@0:       }
sl@0:     };
sl@0: 
sl@0:     // for undirected graphs
sl@0:     template <> struct copy_graph_impl<2>
sl@0:     {
sl@0:       template <typename Graph, typename MutableGraph, 
sl@0:         typename CopyVertex, typename CopyEdge, typename IndexMap,
sl@0:         typename Orig2CopyVertexIndexMap>
sl@0:       static void apply(const Graph& g_in, MutableGraph& g_out, 
sl@0:                         CopyVertex copy_vertex, CopyEdge copy_edge,
sl@0:                         Orig2CopyVertexIndexMap orig2copy,
sl@0:                         IndexMap index_map)
sl@0:       {
sl@0:         typedef color_traits<default_color_type> Color;
sl@0:         std::vector<default_color_type> 
sl@0:           color(num_vertices(g_in), Color::white());
sl@0:         typename graph_traits<Graph>::vertex_iterator vi, vi_end;
sl@0:         for (tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) {
sl@0:           typename graph_traits<MutableGraph>::vertex_descriptor
sl@0:             new_v = add_vertex(g_out);
sl@0:           put(orig2copy, *vi, new_v);
sl@0:           copy_vertex(*vi, new_v);
sl@0:         }
sl@0:         for (tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) {
sl@0:           typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
sl@0:           for (tie(ei, ei_end) = out_edges(*vi, g_in); ei != ei_end; ++ei) {
sl@0:             typename graph_traits<MutableGraph>::edge_descriptor new_e;
sl@0:             bool inserted;
sl@0:             if (color[get(index_map, target(*ei, g_in))] == Color::white()) {
sl@0:               tie(new_e, inserted) = add_edge(get(orig2copy, source(*ei,g_in)),
sl@0:                                               get(orig2copy, target(*ei,g_in)),
sl@0:                                               g_out);
sl@0:               copy_edge(*ei, new_e);
sl@0:             }
sl@0:           }
sl@0:           color[get(index_map, *vi)] = Color::black();
sl@0:         }
sl@0:       }
sl@0:     };
sl@0: 
sl@0:     template <class Graph>
sl@0:     struct choose_graph_copy {
sl@0:       typedef typename Graph::traversal_category Trv;
sl@0:       typedef typename Graph::directed_category Dr;
sl@0:       enum { algo = 
sl@0:              (is_convertible<Trv, vertex_list_graph_tag>::value
sl@0:               && is_convertible<Trv, edge_list_graph_tag>::value)
sl@0:              ? 0 : is_convertible<Dr, directed_tag>::value ? 1 : 2 };
sl@0:       typedef copy_graph_impl<algo> type;
sl@0:     };
sl@0: 
sl@0:     //-------------------------------------------------------------------------
sl@0:     struct choose_copier_parameter {
sl@0:       template <class P, class G1, class G2>
sl@0:       struct bind_ {
sl@0:         typedef const P& result_type;
sl@0:         static result_type apply(const P& p, const G1&, G2&)
sl@0:         { return p; }
sl@0:       };
sl@0:     };
sl@0:     struct choose_default_edge_copier {
sl@0:       template <class P, class G1, class G2>
sl@0:       struct bind_ {
sl@0:         typedef edge_copier<G1, G2> result_type;
sl@0:         static result_type apply(const P&, const G1& g1, G2& g2) { 
sl@0:           return result_type(g1, g2);
sl@0:         }
sl@0:       };
sl@0:     };
sl@0:     template <class Param>
sl@0:     struct choose_edge_copy {
sl@0:       typedef choose_copier_parameter type;
sl@0:     };
sl@0:     template <>
sl@0:     struct choose_edge_copy<detail::error_property_not_found> {
sl@0:       typedef choose_default_edge_copier type;
sl@0:     };
sl@0:     template <class Param, class G1, class G2>
sl@0:     struct choose_edge_copier_helper {
sl@0:       typedef typename choose_edge_copy<Param>::type Selector;
sl@0:       typedef typename Selector:: template bind_<Param, G1, G2> Bind;
sl@0:       typedef Bind type;
sl@0:       typedef typename Bind::result_type result_type;
sl@0:     };
sl@0:     template <typename Param, typename G1, typename G2>
sl@0:     typename detail::choose_edge_copier_helper<Param,G1,G2>::result_type
sl@0:     choose_edge_copier(const Param& params, const G1& g_in, G2& g_out)
sl@0:     {
sl@0:       typedef typename 
sl@0:         detail::choose_edge_copier_helper<Param,G1,G2>::type Choice;
sl@0:       return Choice::apply(params, g_in, g_out);
sl@0:     }
sl@0: 
sl@0: 
sl@0:     struct choose_default_vertex_copier {
sl@0:       template <class P, class G1, class G2>
sl@0:       struct bind_ {
sl@0:         typedef vertex_copier<G1, G2> result_type;
sl@0:         static result_type apply(const P&, const G1& g1, G2& g2) { 
sl@0:           return result_type(g1, g2);
sl@0:         }
sl@0:       };
sl@0:     };
sl@0:     template <class Param>
sl@0:     struct choose_vertex_copy {
sl@0:       typedef choose_copier_parameter type;
sl@0:     };
sl@0:     template <>
sl@0:     struct choose_vertex_copy<detail::error_property_not_found> {
sl@0:       typedef choose_default_vertex_copier type;
sl@0:     };
sl@0:     template <class Param, class G1, class G2>
sl@0:     struct choose_vertex_copier_helper {
sl@0:       typedef typename choose_vertex_copy<Param>::type Selector;
sl@0:       typedef typename Selector:: template bind_<Param, G1, G2> Bind;
sl@0:       typedef Bind type;
sl@0:       typedef typename Bind::result_type result_type;
sl@0:     };
sl@0:     template <typename Param, typename G1, typename G2>
sl@0:     typename detail::choose_vertex_copier_helper<Param,G1,G2>::result_type
sl@0:     choose_vertex_copier(const Param& params, const G1& g_in, G2& g_out)
sl@0:     {
sl@0:       typedef typename 
sl@0:         detail::choose_vertex_copier_helper<Param,G1,G2>::type Choice;
sl@0:       return Choice::apply(params, g_in, g_out);
sl@0:     }
sl@0: 
sl@0:   } // namespace detail
sl@0: 
sl@0: 
sl@0:   template <typename VertexListGraph, typename MutableGraph>
sl@0:   void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out)
sl@0:   {
sl@0:     if (num_vertices(g_in) == 0)
sl@0:       return;
sl@0:     typedef typename graph_traits<MutableGraph>::vertex_descriptor vertex_t;
sl@0:     std::vector<vertex_t> orig2copy(num_vertices(g_in));
sl@0:     typedef typename detail::choose_graph_copy<VertexListGraph>::type 
sl@0:       copy_impl;
sl@0:     copy_impl::apply
sl@0:       (g_in, g_out, 
sl@0:        detail::make_vertex_copier(g_in, g_out), 
sl@0:        detail::make_edge_copier(g_in, g_out), 
sl@0:        make_iterator_property_map(orig2copy.begin(), 
sl@0:                                   get(vertex_index, g_in), orig2copy[0]),
sl@0:        get(vertex_index, g_in)
sl@0:        );
sl@0:   }
sl@0: 
sl@0:   template <typename VertexListGraph, typename MutableGraph, 
sl@0:     class P, class T, class R>
sl@0:   void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out, 
sl@0:                   const bgl_named_params<P, T, R>& params)
sl@0:   {
sl@0:     typename std::vector<T>::size_type n;
sl@0:       n = is_default_param(get_param(params, orig_to_copy_t()))
sl@0:         ? num_vertices(g_in) : 1;
sl@0:     if (n == 0)
sl@0:       return;
sl@0:     std::vector<BOOST_DEDUCED_TYPENAME graph_traits<MutableGraph>::vertex_descriptor> 
sl@0:       orig2copy(n);
sl@0: 
sl@0:     typedef typename detail::choose_graph_copy<VertexListGraph>::type 
sl@0:       copy_impl;
sl@0:     copy_impl::apply
sl@0:       (g_in, g_out,
sl@0:        detail::choose_vertex_copier(get_param(params, vertex_copy_t()), 
sl@0:                                     g_in, g_out),
sl@0:        detail::choose_edge_copier(get_param(params, edge_copy_t()), 
sl@0:                                   g_in, g_out),
sl@0:        choose_param(get_param(params, orig_to_copy_t()),
sl@0:                     make_iterator_property_map
sl@0:                     (orig2copy.begin(), 
sl@0:                      choose_const_pmap(get_param(params, vertex_index), 
sl@0:                                  g_in, vertex_index), orig2copy[0])),
sl@0:        choose_const_pmap(get_param(params, vertex_index), g_in, vertex_index)
sl@0:        );
sl@0:   }
sl@0: 
sl@0:   namespace detail {
sl@0:     
sl@0:     template <class NewGraph, class Copy2OrigIndexMap, 
sl@0:       class CopyVertex, class CopyEdge>
sl@0:     struct graph_copy_visitor : public bfs_visitor<>
sl@0:     {
sl@0:       graph_copy_visitor(NewGraph& graph, Copy2OrigIndexMap c,
sl@0:                          CopyVertex cv, CopyEdge ce)
sl@0:         : g_out(graph), orig2copy(c), copy_vertex(cv), copy_edge(ce) { }
sl@0: 
sl@0:       template <class Vertex, class Graph>
sl@0:       void examine_vertex(Vertex u, const Graph& g_in) const {
sl@0:         typename graph_traits<NewGraph>::vertex_descriptor
sl@0:           new_u = add_vertex(g_out);
sl@0:         put(orig2copy, u, new_u);
sl@0:         copy_vertex(u, new_u);
sl@0:       }
sl@0:       
sl@0:       template <class Edge, class Graph>
sl@0:       void examine_edge(Edge e, const Graph& g_in) const {
sl@0:         typename graph_traits<NewGraph>::edge_descriptor new_e;
sl@0:         bool inserted;
sl@0:         tie(new_e, inserted) = add_edge(get(orig2copy, source(e, g_in)), 
sl@0:                                         get(orig2copy, target(e, g_in)),
sl@0:                                         g_out);
sl@0:         copy_edge(e, new_e);
sl@0:       }
sl@0:     private:
sl@0:       NewGraph& g_out;
sl@0:       Copy2OrigIndexMap orig2copy;
sl@0:       CopyVertex copy_vertex;
sl@0:       CopyEdge copy_edge;
sl@0:     };
sl@0: 
sl@0:     template <typename Graph, typename MutableGraph, 
sl@0:               typename CopyVertex, typename CopyEdge, 
sl@0:               typename Orig2CopyVertexIndexMap, typename Params>
sl@0:     typename graph_traits<MutableGraph>::vertex_descriptor
sl@0:     copy_component_impl
sl@0:       (const Graph& g_in, 
sl@0:        typename graph_traits<Graph>::vertex_descriptor src,
sl@0:        MutableGraph& g_out, 
sl@0:        CopyVertex copy_vertex, CopyEdge copy_edge,
sl@0:        Orig2CopyVertexIndexMap orig2copy,
sl@0:        const Params& params)
sl@0:     {
sl@0:       graph_copy_visitor<MutableGraph, Orig2CopyVertexIndexMap, 
sl@0:         CopyVertex, CopyEdge> vis(g_out, orig2copy, copy_vertex, copy_edge);
sl@0:       breadth_first_search(g_in, src, params.visitor(vis));
sl@0:       return get(orig2copy, src);
sl@0:     }
sl@0: 
sl@0:   } // namespace detail
sl@0:   
sl@0:   
sl@0:   // Copy all the vertices and edges of graph g_in that are reachable
sl@0:   // from the source vertex into graph g_out. Return the vertex
sl@0:   // in g_out that matches the source vertex of g_in.
sl@0:   template <typename IncidenceGraph, typename MutableGraph, 
sl@0:            typename P, typename T, typename R>
sl@0:   typename graph_traits<MutableGraph>::vertex_descriptor
sl@0:   copy_component(IncidenceGraph& g_in, 
sl@0:                  typename graph_traits<IncidenceGraph>::vertex_descriptor src,
sl@0:                  MutableGraph& g_out, 
sl@0:                  const bgl_named_params<P, T, R>& params)
sl@0:   {
sl@0:     typename std::vector<T>::size_type n;
sl@0:       n = is_default_param(get_param(params, orig_to_copy_t()))
sl@0:         ? num_vertices(g_in) : 1;
sl@0:     std::vector<typename graph_traits<IncidenceGraph>::vertex_descriptor> 
sl@0:       orig2copy(n);
sl@0:     
sl@0:     return detail::copy_component_impl
sl@0:       (g_in, src, g_out,
sl@0:        detail::choose_vertex_copier(get_param(params, vertex_copy_t()), 
sl@0:                                     g_in, g_out),
sl@0:        detail::choose_edge_copier(get_param(params, edge_copy_t()), 
sl@0:                                   g_in, g_out),
sl@0:        choose_param(get_param(params, orig_to_copy_t()),
sl@0:                     make_iterator_property_map
sl@0:                     (orig2copy.begin(), 
sl@0:                      choose_pmap(get_param(params, vertex_index), 
sl@0:                                  g_in, vertex_index), orig2copy[0])),
sl@0:        params
sl@0:        );
sl@0:   }
sl@0: 
sl@0:   template <typename IncidenceGraph, typename MutableGraph>
sl@0:   typename graph_traits<MutableGraph>::vertex_descriptor
sl@0:   copy_component(IncidenceGraph& g_in, 
sl@0:                  typename graph_traits<IncidenceGraph>::vertex_descriptor src,
sl@0:                  MutableGraph& g_out)
sl@0:   {
sl@0:     std::vector<typename graph_traits<IncidenceGraph>::vertex_descriptor> 
sl@0:       orig2copy(num_vertices(g_in));
sl@0:     
sl@0:     return detail::copy_component_impl
sl@0:       (g_in, src, g_out,
sl@0:        make_vertex_copier(g_in, g_out), 
sl@0:        make_edge_copier(g_in, g_out), 
sl@0:        make_iterator_property_map(orig2copy.begin(), 
sl@0:                                   get(vertex_index, g_in), orig2copy[0]),
sl@0:        bgl_named_params<char,char>('x') // dummy param object
sl@0:        );
sl@0:   }
sl@0: 
sl@0: } // namespace boost
sl@0: 
sl@0: #endif // BOOST_GRAPH_COPY_HPP