Ticket #6780: max_adj_search_v8.patch

File max_adj_search_v8.patch, 51.1 KB (added by fvilas@…, 10 years ago)

Updated patch

  • boost/graph/maximum_adjacency_search.hpp

     
     1//
     2//=======================================================================
     3// Copyright 2012 Fernando Vilas
     4//           2010 Daniel Trebbien
     5//
     6// Distributed under the Boost Software License, Version 1.0. (See
     7// accompanying file LICENSE_1_0.txt or copy at
     8// http://www.boost.org/LICENSE_1_0.txt)
     9//=======================================================================
     10//
     11
     12// The maximum adjacency search algorithm was originally part of the
     13// Stoer-Wagner min cut implementation by Daniel Trebbien. It has been
     14// broken out into its own file to be a public search algorithm, with
     15// visitor concepts.
     16#ifndef BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H
     17#define BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H
     18
     19/**
     20 * This is an implementation of the maximum adjacency search on an
     21 * undirected graph. It allows a visitor object to perform some
     22 * operation on each vertex as that vertex is visited.
     23 *
     24 * The algorithm runs as follows:
     25 *
     26 * Initialize all nodes to be unvisited (reach count = 0)
     27 *   and call vis.initialize_vertex
     28 * For i = number of nodes in graph downto 1
     29 *   Select the unvisited node with the highest reach count
     30 *     The user provides the starting node to break the first tie,
     31 *     but future ties are broken arbitrarily
     32 *   Visit the node by calling vis.start_vertex
     33 *   Increment the reach count for all unvisited neighbors
     34 *     and call vis.examine_edge for each of these edges
     35 *   Mark the node as visited and call vis.finish_vertex
     36 *
     37 */
     38
     39#include <boost/concept_check.hpp>
     40#include <boost/concept/assert.hpp>
     41#include <boost/graph/buffer_concepts.hpp>
     42#include <boost/graph/exception.hpp>
     43#include <boost/graph/graph_concepts.hpp>
     44#include <boost/graph/iteration_macros.hpp>
     45#include <boost/graph/named_function_params.hpp>
     46#include <boost/graph/visitors.hpp>
     47#include <boost/tuple/tuple.hpp>
     48
     49#include <set>
     50
     51namespace boost {
     52  template <class Visitor, class Graph>
     53  struct MASVisitorConcept {
     54    void constraints() {
     55      boost::function_requires< boost::CopyConstructibleConcept<Visitor> >();
     56      vis.initialize_vertex(u, g);
     57      vis.start_vertex(u, g);
     58      vis.examine_edge(e, g);
     59      vis.finish_vertex(u, g);
     60    }
     61    Visitor vis;
     62    Graph g;
     63    typename boost::graph_traits<Graph>::vertex_descriptor u;
     64    typename boost::graph_traits<Graph>::edge_descriptor e;
     65  };
     66
     67  template <class Visitors = null_visitor>
     68  class mas_visitor {
     69  public:
     70    mas_visitor() { }
     71    mas_visitor(Visitors vis) : m_vis(vis) { }
     72
     73    template <class Vertex, class Graph>
     74    void
     75    initialize_vertex(Vertex u, Graph& g)
     76    {
     77      invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex());
     78    }
     79
     80    template <class Vertex, class Graph>
     81    void
     82    start_vertex(Vertex u, Graph& g)
     83    {
     84      invoke_visitors(m_vis, u, g, ::boost::on_start_vertex());
     85    }
     86
     87    template <class Edge, class Graph>
     88    void
     89    examine_edge(Edge e, Graph& g)
     90    {
     91      invoke_visitors(m_vis, e, g, ::boost::on_examine_edge());
     92    }
     93
     94    template <class Vertex, class Graph>
     95    void
     96    finish_vertex(Vertex u, Graph& g)
     97    {
     98      invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex());
     99    }
     100
     101    BOOST_GRAPH_EVENT_STUB(on_initialize_vertex,mas)
     102    BOOST_GRAPH_EVENT_STUB(on_start_vertex,mas)
     103    BOOST_GRAPH_EVENT_STUB(on_examine_edge,mas)
     104    BOOST_GRAPH_EVENT_STUB(on_finish_vertex,mas)
     105
     106  protected:
     107    Visitors m_vis;
     108  };
     109  template <class Visitors>
     110  mas_visitor<Visitors>
     111  make_mas_visitor(Visitors vis) {
     112    return mas_visitor<Visitors>(vis);
     113  }
     114  typedef mas_visitor<> default_mas_visitor;
     115
     116  namespace detail {
     117    template <class Graph, class WeightMap, class MASVisitor, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue>
     118      void
     119      maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, const typename boost::graph_traits<Graph>::vertex_descriptor start, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) {
     120      typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
     121      typedef typename boost::graph_traits<Graph>::vertices_size_type vertices_size_type;
     122      typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
     123      typedef typename boost::property_traits<WeightMap>::value_type weight_type;
     124
     125     std::set<vertex_descriptor> assignedVertices;
     126
     127     // initialize `assignments` (all vertices are initially
     128     // assigned to themselves)
     129     BGL_FORALL_VERTICES_T(v, g, Graph) {
     130       put(assignments, v, v);
     131     }
     132
     133      typename KeyedUpdatablePriorityQueue::key_map keys = pq.keys();
     134
     135      // set number of visited neighbors for all vertices to 0
     136      BGL_FORALL_VERTICES_T(v, g, Graph) {
     137        if (v == get(assignments, v)) { // foreach u \in V do
     138          put(keys, v, weight_type(0));          vis.initialize_vertex(v, g);
     139
     140          pq.push(v);
     141        }
     142      }
     143      BOOST_ASSERT(pq.size() >= 2);
     144
     145      // Give the starting vertex high priority
     146      put(keys, start, get(keys, start) + num_vertices(g) + 1);
     147      pq.update(start);
     148
     149      // start traversing the graph
     150      //vertex_descriptor s, t;
     151      weight_type w;
     152      while (!pq.empty()) { // while PQ \neq {} do
     153        const vertex_descriptor u = pq.top(); // u = extractmax(PQ)
     154        w = get(keys, u);                        vis.start_vertex(u, g);
     155        pq.pop();                  //            vis.start_vertex(u, g);
     156
     157        BGL_FORALL_OUTEDGES_T(u, e, g, Graph) { // foreach (u, v) \in E do
     158                                                 vis.examine_edge(e, g);
     159
     160          const vertex_descriptor v = get(assignments, target(e, g));
     161
     162          if (pq.contains(v)) { // if v \in PQ then
     163            put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v))
     164            pq.update(v);
     165          }
     166        }
     167
     168        typename std::set<vertex_descriptor>::const_iterator assignedVertexIt, assignedVertexEnd = assignedVertices.end();
     169        for (assignedVertexIt = assignedVertices.begin(); assignedVertexIt != assignedVertexEnd; ++assignedVertexIt) {
     170          const vertex_descriptor uPrime = *assignedVertexIt;
     171
     172          if (get(assignments, uPrime) == u) {
     173            BGL_FORALL_OUTEDGES_T(uPrime, e, g, Graph) { // foreach (u, v) \in E do
     174                                                 vis.examine_edge(e, g);
     175
     176              const vertex_descriptor v = get(assignments, target(e, g));
     177
     178              if (pq.contains(v)) { // if v \in PQ then
     179                put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v))
     180                pq.update(v);
     181              }
     182            }
     183          }
     184        }
     185                                                 vis.finish_vertex(u, g);
     186      }
     187    }
     188  } // end namespace detail
     189
     190  template <class Graph, class WeightMap, class MASVisitor, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue>
     191    void
     192maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, const typename boost::graph_traits<Graph>::vertex_descriptor start, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) {
     193    BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept<Graph>));
     194    BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept<Graph>));
     195    typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
     196    typedef typename boost::graph_traits<Graph>::vertices_size_type vertices_size_type;
     197    typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
     198    BOOST_CONCEPT_ASSERT((boost::Convertible<typename boost::graph_traits<Graph>::directed_category, boost::undirected_tag>));
     199    BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept<WeightMap, edge_descriptor>));
     200    typedef typename boost::property_traits<WeightMap>::value_type weight_type;
     201    boost::function_requires< MASVisitorConcept<MASVisitor, Graph> >();
     202    BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept<VertexAssignmentMap, vertex_descriptor>));
     203    BOOST_CONCEPT_ASSERT((boost::Convertible<vertex_descriptor, typename boost::property_traits<VertexAssignmentMap>::value_type>));
     204    BOOST_CONCEPT_ASSERT((boost::KeyedUpdatableQueueConcept<KeyedUpdatablePriorityQueue>));
     205
     206    vertices_size_type n = num_vertices(g);
     207    if (n < 2)
     208      throw boost::bad_graph("the input graph must have at least two vertices.");
     209    else if (!pq.empty())
     210      throw std::invalid_argument("the max-priority queue must be empty initially.");
     211
     212    detail::maximum_adjacency_search(g, weights,
     213                                            vis, start,
     214                                            assignments, pq);
     215  }
     216
     217  namespace graph {
     218    namespace detail {
     219      template <typename WeightMap>
     220      struct mas_dispatch {
     221        typedef void result_type;
     222        template <typename Graph, typename ArgPack>
     223        static result_type apply(const Graph& g,
     224                          //const bgl_named_params<P,T,R>& params,
     225                          const ArgPack& params,
     226                          WeightMap w) {
     227
     228          using namespace boost::graph::keywords;
     229          typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
     230          typedef typename WeightMap::value_type weight_type;
     231
     232          typedef boost::detail::make_priority_queue_from_arg_pack_gen<boost::graph::keywords::tag::max_priority_queue, weight_type, vertex_descriptor, std::greater<weight_type> > default_pq_gen_type;
     233
     234          default_pq_gen_type pq_gen(choose_param(get_param(params, boost::distance_zero_t()), weight_type(0)));
     235
     236          typename boost::result_of<default_pq_gen_type(const Graph&, const ArgPack&)>::type pq = pq_gen(g, params);
     237
     238          boost::maximum_adjacency_search
     239               (g,
     240                w,
     241                params [ _visitor | make_mas_visitor(null_visitor())],
     242                params [ _root_vertex | *vertices(g).first],
     243                params [ _vertex_assignment_map | boost::detail::make_property_map_from_arg_pack_gen<boost::graph::keywords::tag::vertex_assignment_map, vertex_descriptor>(vertex_descriptor())(g, params)],
     244                pq
     245                );
     246        }
     247      };
     248
     249      template <>
     250      struct mas_dispatch<boost::param_not_found> {
     251        typedef void result_type;
     252
     253        template <typename Graph, typename ArgPack>
     254        static result_type apply(const Graph& g,
     255                          const ArgPack& params,
     256                          param_not_found) {
     257
     258          using namespace boost::graph::keywords;
     259          typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
     260
     261          // get edge_weight_t as the weight type
     262          typedef typename boost::property_map<Graph, edge_weight_t> WeightMap;
     263          typedef typename WeightMap::value_type weight_type;
     264
     265          typedef boost::detail::make_priority_queue_from_arg_pack_gen<boost::graph::keywords::tag::max_priority_queue, weight_type, vertex_descriptor, std::greater<weight_type> > default_pq_gen_type;
     266
     267          default_pq_gen_type pq_gen(choose_param(get_param(params, boost::distance_zero_t()), weight_type(0)));
     268
     269          typename boost::result_of<default_pq_gen_type(const Graph&, const ArgPack&)>::type pq = pq_gen(g, params);
     270
     271          boost::maximum_adjacency_search
     272               (g,
     273                get(edge_weight, g),
     274                params [ _visitor | make_mas_visitor(null_visitor())],
     275                params [ _root_vertex | *vertices(g).first],
     276                params [ _vertex_assignment_map | boost::detail::make_property_map_from_arg_pack_gen<boost::graph::keywords::tag::vertex_assignment_map, vertex_descriptor>(vertex_descriptor())(g, params)],
     277                pq
     278                );
     279        }
     280      };
     281    } // end namespace detail
     282  } // end namespace graph
     283
     284  // Named parameter interface
     285  //BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(maximum_adjacency_search, 1)
     286  template <typename Graph, typename P, typename T, typename R>
     287  void
     288  maximum_adjacency_search (const Graph& g,
     289      const bgl_named_params<P,T,R>& params) {
     290
     291    typedef bgl_named_params<P, T, R> params_type;
     292    BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params)
     293
     294    // do the dispatch based on WeightMap
     295    typedef typename get_param_type<edge_weight_t, bgl_named_params<P,T,R> >::type W;
     296    graph::detail::mas_dispatch<W>::apply(g, arg_pack, get_param(params, edge_weight));
     297  }
     298
     299  namespace graph {
     300    namespace detail {
     301      template <typename Graph>
     302      struct maximum_adjacency_search_impl {
     303        typedef void result_type;
     304
     305        template <typename ArgPack>
     306        void
     307        operator() (const Graph& g, const ArgPack arg_pack) const {
     308          // call the function that does the dispatching
     309          typedef typename get_param_type<edge_weight_t, ArgPack >::type W;
     310          graph::detail::mas_dispatch<W>::apply(g, arg_pack, get_param(arg_pack, edge_weight));
     311        }
     312      };
     313    } // end namespace detail
     314    BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(maximum_adjacency_search,1,5)
     315  } // end namespace graph
     316
     317} // end namespace boost
     318
     319#include <boost/graph/iteration_macros_undef.hpp>
     320
     321#endif // BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H
  • boost/graph/stoer_wagner_min_cut.hpp

     
    1515#include <boost/graph/buffer_concepts.hpp>
    1616#include <boost/graph/exception.hpp>
    1717#include <boost/graph/graph_traits.hpp>
    18 #include <boost/graph/iteration_macros.hpp>
     18#include <boost/graph/maximum_adjacency_search.hpp>
    1919#include <boost/graph/named_function_params.hpp>
     20#include <boost/graph/one_bit_color_map.hpp>
    2021#include <boost/graph/detail/d_ary_heap.hpp>
    2122#include <boost/property_map/property_map.hpp>
    2223#include <boost/tuple/tuple.hpp>
    2324#include <boost/utility/result_of.hpp>
     25#include <boost/graph/iteration_macros.hpp>
    2426
    2527namespace boost {
    26  
     28
    2729  namespace detail {
    28    
    29     /**
    30      * \brief Performs a phase of the Stoer-Wagner min-cut algorithm
    31      *
    32      * Performs a phase of the Stoer-Wagner min-cut algorithm.
    33      *
    34      * As described by Stoer & Wagner (1997), a phase is simply a maximum adjacency search
    35      * (also called a maximum cardinality search), which results in the selection of two vertices
    36      * \em s and \em t, and, as a side product, a minimum <em>s</em>-<em>t</em> cut of
    37      * the input graph. Here, the input graph is basically \p g, but some vertices are virtually
    38      * assigned to others as a way of viewing \p g as a graph with some sets of
    39      * vertices merged together.
    40      *
    41      * This implementation is a translation of pseudocode by Professor Uri Zwick,
    42      * School of Computer Science, Tel Aviv University.
    43      *
    44      * \pre \p g is a connected, undirected graph
    45      * \param[in] g the input graph
    46      * \param[in] assignments a read/write property map from each vertex to the vertex that it is assigned to
    47      * \param[in] assignedVertices a list of vertices that are assigned to others
    48      * \param[in] weights a readable property map from each edge to its weight (a non-negative value)
    49      * \param[out] pq a keyed, updatable max-priority queue
    50      * \returns a tuple (\em s, \em t, \em w) of the "<em>s</em>" and "<em>t</em>"
    51      *     of the minimum <em>s</em>-<em>t</em> cut and the cut weight \em w
    52      *     of the minimum <em>s</em>-<em>t</em> cut.
    53      * \see http://www.cs.tau.ac.il/~zwick/grad-algo-08/gmc.pdf
    54      *
    55      * \author Daniel Trebbien
    56      * \date 2010-09-11
    57      */
    58     template <class UndirectedGraph, class VertexAssignmentMap, class WeightMap, class KeyedUpdatablePriorityQueue>
    59     boost::tuple<typename boost::graph_traits<UndirectedGraph>::vertex_descriptor, typename boost::graph_traits<UndirectedGraph>::vertex_descriptor, typename boost::property_traits<WeightMap>::value_type>
    60     stoer_wagner_phase(const UndirectedGraph& g, VertexAssignmentMap assignments, const std::set<typename boost::graph_traits<UndirectedGraph>::vertex_descriptor>& assignedVertices, WeightMap weights, KeyedUpdatablePriorityQueue& pq) {
    61       typedef typename boost::graph_traits<UndirectedGraph>::vertex_descriptor vertex_descriptor;
     30    template < typename ParityMap, typename WeightMap, typename IndexMap >
     31    class mas_min_cut_visitor : public boost::default_mas_visitor {
     32      typedef one_bit_color_map <IndexMap> InternalParityMap;
    6233      typedef typename boost::property_traits<WeightMap>::value_type weight_type;
    63      
    64       BOOST_ASSERT(pq.empty());
    65       typename KeyedUpdatablePriorityQueue::key_map keys = pq.keys();
    66      
    67       BGL_FORALL_VERTICES_T(v, g, UndirectedGraph) {
    68         if (v == get(assignments, v)) { // foreach u \in V do
    69           put(keys, v, weight_type(0));
    70          
    71           pq.push(v);
     34    public:
     35      template < typename Graph >
     36      mas_min_cut_visitor(const Graph& g,
     37                          ParityMap parity,
     38                          weight_type& cutweight,
     39                          WeightMap weight_map,
     40                          IndexMap index_map)
     41        : m_bestParity(parity),
     42          m_parity(make_one_bit_color_map(num_vertices(g), index_map)),
     43          m_bestWeight(cutweight),
     44          m_cutweight(0),
     45          m_visited(0),
     46          m_weightMap(weight_map)
     47      {
     48        // set here since the init list sets the reference
     49        m_bestWeight = (std::numeric_limits<weight_type>::max)();
     50      }
     51
     52      template < typename Vertex, typename Graph >
     53      void initialize_vertex(Vertex u, const Graph & g)
     54      {
     55        typedef typename boost::property_traits<ParityMap>::value_type parity_type;
     56        typedef typename boost::property_traits<InternalParityMap>::value_type internal_parity_type;
     57
     58        put(m_parity, u, internal_parity_type(0));
     59        put(m_bestParity, u, parity_type(0));
     60      }
     61
     62      template < typename Edge, typename Graph >
     63      void examine_edge(Edge e, const Graph & g)
     64      {
     65        weight_type w = get(m_weightMap, e);
     66
     67        // if the target of e is already marked then decrease cutweight
     68        // otherwise, increase it
     69        if (get(m_parity, boost::target(e, g))) {
     70          m_cutweight -= w;
     71        } else {
     72          m_cutweight += w;
    7273        }
    7374      }
    74      
    75       BOOST_ASSERT(pq.size() >= 2);
    76      
    77       vertex_descriptor s = boost::graph_traits<UndirectedGraph>::null_vertex();
    78       vertex_descriptor t = boost::graph_traits<UndirectedGraph>::null_vertex();
    79       weight_type w;
    80       while (!pq.empty()) { // while PQ \neq {} do
    81         const vertex_descriptor u = pq.top(); // u = extractmax(PQ)
    82         w = get(keys, u);
    83         pq.pop();
    84        
    85         s = t; t = u;
    86        
    87         BGL_FORALL_OUTEDGES_T(u, e, g, UndirectedGraph) { // foreach (u, v) \in E do
    88           const vertex_descriptor v = get(assignments, target(e, g));
    89          
    90           if (pq.contains(v)) { // if v \in PQ then
    91             put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v))
    92             pq.update(v);
     75
     76      template < typename Vertex, typename Graph >
     77      void finish_vertex(Vertex u, const Graph & g)
     78      {
     79        typedef typename boost::property_traits<ParityMap>::value_type parity_type;
     80        typedef typename boost::property_traits<InternalParityMap>::value_type internal_parity_type;
     81
     82        ++m_visited;
     83        put(m_parity, u, internal_parity_type(1));
     84
     85        if (m_cutweight < m_bestWeight && m_visited < num_vertices(g)) {
     86          m_bestWeight = m_cutweight;
     87          BGL_FORALL_VERTICES_T(i, g, Graph) {
     88            put(m_bestParity,i, get(m_parity,i));
    9389          }
    9490        }
    95        
    96         typename std::set<vertex_descriptor>::const_iterator assignedVertexIt, assignedVertexEnd = assignedVertices.end();
    97         for (assignedVertexIt = assignedVertices.begin(); assignedVertexIt != assignedVertexEnd; ++assignedVertexIt) {
    98           const vertex_descriptor uPrime = *assignedVertexIt;
    99          
    100           if (get(assignments, uPrime) == u) {
    101             BGL_FORALL_OUTEDGES_T(uPrime, e, g, UndirectedGraph) { // foreach (u, v) \in E do
    102               const vertex_descriptor v = get(assignments, target(e, g));
    103              
    104               if (pq.contains(v)) { // if v \in PQ then
    105                 put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v))
    106                 pq.update(v);
    107               }
    108             }
    109           }
    110         }
    11191      }
    112      
    113       return boost::make_tuple(s, t, w);
    114     }
    115    
     92
     93      inline void clear() {
     94        m_bestWeight = (std::numeric_limits<weight_type>::max)();
     95        m_visited = 0;
     96        m_cutweight = 0;
     97      }
     98
     99    private:
     100      ParityMap m_bestParity;
     101      InternalParityMap m_parity;
     102      weight_type& m_bestWeight;
     103      weight_type m_cutweight;
     104      unsigned m_visited;
     105      const WeightMap& m_weightMap;
     106    };
     107
    116108    /**
    117109     * \brief Computes a min-cut of the input graph
    118110     *
     
    135127     * \author Daniel Trebbien
    136128     * \date 2010-09-11
    137129     */
    138     template <class UndirectedGraph, class WeightMap, class ParityMap, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue>
     130    template <class UndirectedGraph, class WeightMap, class ParityMap, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue, class IndexMap>
    139131    typename boost::property_traits<WeightMap>::value_type
    140     stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq) {
     132    stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq, IndexMap index_map) {
     133      typedef typename boost::graph_traits<UndirectedGraph>::vertex_descriptor vertex_descriptor;
     134      typedef typename boost::graph_traits<UndirectedGraph>::vertices_size_type vertices_size_type;
     135      typedef typename boost::graph_traits<UndirectedGraph>::edge_descriptor edge_descriptor;
     136      typedef typename boost::property_traits<WeightMap>::value_type weight_type;
     137      typedef typename boost::property_traits<ParityMap>::value_type parity_type;
     138
     139      typename graph_traits<UndirectedGraph>::vertex_iterator u_iter, u_end;
     140
     141      weight_type bestW = (std::numeric_limits<weight_type>::max)();
     142      weight_type bestThisTime = (std::numeric_limits<weight_type>::max)();
     143      vertex_descriptor bestStart;
     144
     145      detail::mas_min_cut_visitor<ParityMap, WeightMap, IndexMap>
     146        vis(g, parities, bestThisTime, weights, index_map);
     147
     148      // for each node in the graph,
     149      for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
     150        // run the MAS and find the min cut
     151        vis.clear();
     152        boost::maximum_adjacency_search(g,
     153            boost::weight_map(weights).
     154            visitor(vis).
     155            root_vertex(*u_iter).
     156            vertex_assignment_map(assignments).
     157            max_priority_queue(pq));
     158        if (bestThisTime < bestW) {
     159          bestW = bestThisTime;
     160          bestStart = *u_iter;
     161        }
     162      }
     163
     164      // Run one more time, starting from the best start location, to
     165      // ensure the visitor has the best values.
     166      vis.clear();
     167      boost::maximum_adjacency_search(g,
     168        boost::vertex_assignment_map(assignments).
     169        weight_map(weights).
     170        visitor(vis).
     171        root_vertex(bestStart).
     172        max_priority_queue(pq));
     173
     174      return bestW;
     175    }
     176  } // end `namespace detail` within `namespace boost`
     177
     178    template <class UndirectedGraph, class WeightMap, class ParityMap, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue, class IndexMap>
     179    typename boost::property_traits<WeightMap>::value_type
     180    stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq, IndexMap index_map) {
    141181      BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept<UndirectedGraph>));
    142182      BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept<UndirectedGraph>));
    143183      typedef typename boost::graph_traits<UndirectedGraph>::vertex_descriptor vertex_descriptor;
     
    151191      BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept<VertexAssignmentMap, vertex_descriptor>));
    152192      BOOST_CONCEPT_ASSERT((boost::Convertible<vertex_descriptor, typename boost::property_traits<VertexAssignmentMap>::value_type>));
    153193      BOOST_CONCEPT_ASSERT((boost::KeyedUpdatableQueueConcept<KeyedUpdatablePriorityQueue>));
    154      
     194
    155195      vertices_size_type n = num_vertices(g);
    156196      if (n < 2)
    157197        throw boost::bad_graph("the input graph must have at least two vertices.");
    158198      else if (!pq.empty())
    159199        throw std::invalid_argument("the max-priority queue must be empty initially.");
    160      
    161       std::set<vertex_descriptor> assignedVertices;
    162      
    163       // initialize `assignments` (all vertices are initially assigned to themselves)
    164       BGL_FORALL_VERTICES_T(v, g, UndirectedGraph) {
    165         put(assignments, v, v);
     200
     201      return detail::stoer_wagner_min_cut(g, weights,
     202                                          parities, assignments, pq, index_map);
     203    }
     204
     205namespace graph {
     206  namespace detail {
     207    template <class UndirectedGraph, class WeightMap>
     208    struct stoer_wagner_min_cut_impl {
     209      typedef typename boost::property_traits<WeightMap>::value_type result_type;
     210      template <typename ArgPack>
     211      result_type operator() (const UndirectedGraph& g, WeightMap weights, const ArgPack& arg_pack) const {
     212        using namespace boost::graph::keywords;
     213        typedef typename boost::graph_traits<UndirectedGraph>::vertex_descriptor vertex_descriptor;
     214        typedef typename boost::property_traits<WeightMap>::value_type weight_type;
     215
     216        typedef typename boost::detail::make_priority_queue_from_arg_pack_gen<boost::graph::keywords::tag::max_priority_queue, weight_type, vertex_descriptor, std::greater<weight_type> > gen_type;
     217
     218        gen_type gen(choose_param(get_param(arg_pack, boost::distance_zero_t()), weight_type(0)));
     219
     220        typename boost::result_of<gen_type(const UndirectedGraph&, const ArgPack&)>::type pq = gen(g, arg_pack);
     221
     222        return boost::stoer_wagner_min_cut(g,
     223          weights,
     224          arg_pack [_parity_map | boost::dummy_property_map()],
     225          boost::detail::make_property_map_from_arg_pack_gen<tag::vertex_assignment_map, vertex_descriptor>(vertex_descriptor())(g, arg_pack),
     226          pq,
     227          boost::detail::override_const_property(arg_pack, _vertex_index_map, g, vertex_index)
     228        );
    166229      }
    167      
    168       vertex_descriptor s, t;
    169       weight_type bestW;
    170      
    171       boost::tie(s, t, bestW) = boost::detail::stoer_wagner_phase(g, assignments, assignedVertices, weights, pq);
    172       BOOST_ASSERT(s != t);
    173       BGL_FORALL_VERTICES_T(v, g, UndirectedGraph) {
    174         put(parities, v, parity_type(v == t ? 1 : 0));
    175       }
    176       put(assignments, t, s);
    177       assignedVertices.insert(t);
    178       --n;
    179      
    180       for (; n >= 2; --n) {
    181         weight_type w;
    182         boost::tie(s, t, w) = boost::detail::stoer_wagner_phase(g, assignments, assignedVertices, weights, pq);
    183         BOOST_ASSERT(s != t);
    184        
    185         if (w < bestW) {
    186           BGL_FORALL_VERTICES_T(v, g, UndirectedGraph) {
    187             put(parities, v, parity_type(get(assignments, v) == t ? 1 : 0));
    188            
    189             if (get(assignments, v) == t) // all vertices that were assigned to t are now assigned to s
    190               put(assignments, v, s);
    191           }
    192          
    193           bestW = w;
    194         } else {
    195           BGL_FORALL_VERTICES_T(v, g, UndirectedGraph) {
    196             if (get(assignments, v) == t) // all vertices that were assigned to t are now assigned to s
    197               put(assignments, v, s);
    198           }
    199         }
    200         put(assignments, t, s);
    201         assignedVertices.insert(t);
    202       }
    203      
    204       BOOST_ASSERT(pq.empty());
    205      
    206       return bestW;
     230    };
     231  }
     232  BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(stoer_wagner_min_cut,2,4)
     233}
     234
     235  // Named parameter interface
     236  BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(stoer_wagner_min_cut, 2)
     237namespace graph {
     238    // version without IndexMap kept for backwards compatibility
     239    // (but requires vertex_index_t to be defined in the graph)
     240    // Place after the macro to avoid compilation errors
     241    template <class UndirectedGraph, class WeightMap, class ParityMap, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue>
     242    typename boost::property_traits<WeightMap>::value_type
     243    stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq) {
     244
     245      return stoer_wagner_min_cut(g, weights,
     246                                  parities, assignments, pq,
     247                                  get(vertex_index, g));
    207248    }
    208    
    209   } // end `namespace detail` within `namespace boost`
    210  
    211   template <class UndirectedGraph, class WeightMap, class P, class T, class R>
    212   inline typename boost::property_traits<WeightMap>::value_type
    213   stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, const boost::bgl_named_params<P, T, R>& params) {
    214     typedef typename boost::graph_traits<UndirectedGraph>::vertex_descriptor vertex_descriptor;
    215     typedef typename std::vector<vertex_descriptor>::size_type heap_container_size_type;
    216     typedef typename boost::property_traits<WeightMap>::value_type weight_type;
    217    
    218     typedef boost::bgl_named_params<P, T, R> params_type;
    219     BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params)
    220    
    221     typedef boost::detail::make_priority_queue_from_arg_pack_gen<boost::graph::keywords::tag::max_priority_queue, weight_type, vertex_descriptor, std::greater<weight_type> > gen_type;
    222     gen_type gen(choose_param(get_param(params, boost::distance_zero_t()), weight_type(0)));
    223     typename boost::result_of<gen_type(const UndirectedGraph&, const arg_pack_type&)>::type pq = gen(g, arg_pack);
    224    
    225     return boost::detail::stoer_wagner_min_cut(g,
    226         weights,
    227         choose_param(get_param(params, boost::parity_map_t()), boost::dummy_property_map()),
    228         boost::detail::make_property_map_from_arg_pack_gen<boost::graph::keywords::tag::vertex_assignment_map, vertex_descriptor>(vertex_descriptor())(g, arg_pack),
    229         pq
    230       );
    231   }
    232  
    233   template <class UndirectedGraph, class WeightMap>
    234   inline typename boost::property_traits<WeightMap>::value_type
    235   stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights) {
    236     return boost::stoer_wagner_min_cut(g, weights, boost::vertex_index_map(get(boost::vertex_index, g)));
    237   }
    238  
     249} // end `namespace graph`
    239250} // end `namespace boost`
    240251
    241252#include <boost/graph/iteration_macros_undef.hpp>
  • libs/graph/doc/maximum_adjacency_search.html

     
     1<html>
     2<!--
     3    Copyright (c) Fernando Vilas 2013
     4
     5
     6    Some content from the Stoer-Wagner Min Cut documentation,
     7    Copyright (c) Daniel Trebbien 2010
     8
     9     Distributed under the Boost Software License, Version 1.0.
     10     (See accompanying file LICENSE_1_0.txt or copy at
     11     http://www.boost.org/LICENSE_1_0.txt)
     12  -->
     13<head>
     14<title>Boost Graph Library: Maximum Adjacency Search</Title>
     15<body>
     16<img src="../../../boost.png" alt="C++ Boost" width="277" height="86">
     17
     18<h1><a name="sec:maximum-adjacency-search"></a>
     19<tt>maximum_adjacency_search</tt>
     20</h1>
     21
     22<p>
     23<pre>
     24<em>// named parameter versions</em>
     25template &lt;class Graph, class class P, class T, class R&gt;
     26void
     27maximum_adjacency_search(const Graph&amp; g,
     28       const bgl_named_params&lt;P, T, R&gt;&amp; params);
     29
     30<i>// non-named parameter versions</i>
     31template &lt;class Graph, class WeightMap, class MASVisitor&gt;
     32void
     33maximum_adjacency_search(const Graph&amp; g, WeightMap weights, MASVisitor vis,
     34       const typename graph_traits&lt;Graph&gt;::vertex_descriptor start);
     35
     36</pre>
     37
     38<p>
     39The <tt>maximum_adjacency_search()</tt> function performs a traversal
     40of the vertices in an undirected graph. The next vertex visited is the
     41vertex that has the most visited neighbors at any time. In the case of
     42an unweighted, undirected graph, the number of visited neighbors of the
     43very last vertex visited in the graph is also the number of edge-disjoint
     44paths between that vertex and the next-to-last vertex visited. These can be
     45retrieved from a visitor, an example of which is in the test harness
     46mas_test.cpp.
     47</p>
     48
     49<p>
     50The <tt>maximum_adjacency_search()</tt> function invokes user-defined
     51actions at certain event-points within the algorithm. This provides a
     52mechanism for adapting the generic MAS algorithm to the many situations
     53in which it can be used. In the pseudo-code below, the event points
     54for MAS are the labels on the right. The user-defined actions must be
     55provided in the form of a visitor object, that is, an object whose type
     56meets the requirements for a MAS Visitor.
     57</p>
     58
     59<table>
     60<tr>
     61<td valign="top">
     62<pre>
     63MAS(<i>G</i>)
     64  <b>for</b> each vertex <i>u in V</i>
     65    <i>reach_count[u] := 0</i>
     66  <b>end for</b>
     67  // for the starting vertex s
     68  <i>reach_count[s] := 1</i>
     69  <b>for</b> each unvisited vertex <i>u in V</i>
     70    <b>call</b> MAS-VISIT(<i>G</i>, <i>u</i>)
     71    remove u from the list on unvisited vertices
     72    <b>for</b> each out edge from <i>u</i> to <i>t</i>
     73       <b>if</b> <i>t</i> has not yet been visited
     74         increment <i>reach_count[t]</i>
     75       <b>end if</b>
     76    <b>end for</b> each out edge
     77    <b>call</b> MAS-VISIT(<i>G</i>, <i>u</i>)
     78  <b>end for</b> each unvisited vertex
     79<pre>
     80</td>
     81<td valign="top">
     82<pre>
     83-
     84-
     85initialize vertex <i>u</i>
     86-
     87-
     88-
     89-
     90examine vertex <i>u</i>
     91-
     92examine edge <i>(u,t)</i>
     93-
     94-
     95-
     96-
     97finish vertex <i>u</i>
     98-
     99</pre>
     100</td>
     101</tr>
     102</table>
     103
     104<h3>Where Defined</h3>
     105
     106<p>
     107<a href="../../../boost/graph/maximum_adjacency_search.hpp"><tt>boost/graph/maximum_adjacency_search.hpp</tt></a></p>
     108
     109<h3>Parameters</h3>
     110
     111IN: <tt>const UndirectedGraph&amp; g</tt></p>
     112<blockquote>
     113  A connected, directed graph. The graph type must
     114  be a model of <a href="./IncidenceGraph.html">Incidence Graph</a>
     115  and <a href="./VertexListGraph.html">Vertex List Graph</a>.<br>
     116</blockquote>
     117
     118<h3>Named Parameters</h3>
     119
     120<p>IN: <tt>WeightMap weights</tt></p>
     121<blockquote>
     122  The weight or length of each edge in the graph. The
     123  <tt>WeightMap</tt> type must be a model of
     124  <a href="../../property_map/doc/ReadablePropertyMap.html">Readable
     125  Property Map</a> and its value type must be <a class="external"
     126  href="http://www.sgi.com/tech/stl/LessThanComparable.html">
     127  Less Than Comparable</a> and summable. The key type of this map
     128  needs to be the graph's edge descriptor type.
     129  <b>Default:</b> <tt>get(edge_weight, g)</tt><br>
     130</blockquote>
     131
     132IN: <tt>visitor(MASVisitor vis)</tt></p>
     133<blockquote>
     134  A visitor object that is invoked inside the algorithm at the
     135  event-points specified by the MAS Visitor concept. The visitor
     136  object is passed by value <a href="#1">[1]</a>. <br>
     137  <b>Default:</b> <tt>mas_visitor&lt;null_visitor&gt;</tt><br>
     138</blockquote>
     139
     140IN: <tt>root_vertex(typename
     141graph_traits&lt;VertexListGraph&gt;::vertex_descriptor start)</tt></p>
     142<blockquote>
     143  This specifies the vertex that the depth-first search should
     144  originate from. The type is the type of a vertex descriptor for the
     145  given graph.<br>
     146  <b>Default:</b> <tt>*vertices(g).first</tt><br>
     147</blockquote>
     148
     149<h4>Expert Parameters</h4>
     150
     151<p>IN: <tt>vertex_index_map(VertexIndexMap vertexIndices)</tt> </p>
     152<blockquote>
     153  This maps each vertex to an integer in the range
     154  [0, <tt>num_vertices(g)</tt>). This is only necessary if the default is
     155  used for the assignment, index-in-heap, or distance maps.
     156  <tt>VertexIndexMap</tt> must be a model of <a
     157  href="../../property_map/doc/ReadablePropertyMap.html">Readable Property
     158  Map</a>. The value type of the map must be an integer type. The
     159  key type must be the graph's vertex descriptor type.<br>
     160  <b>Default:</b> <tt>get(boost::vertex_index, g)</tt>
     161    Note: if you use this default, make sure your graph has
     162    an internal <tt>vertex_index</tt> property. For example,
     163    <tt>adjacency_list</tt> with <tt>VertexList=listS</tt> does
     164    not have an internal <tt>vertex_index</tt> property.
     165</blockquote>
     166
     167<p>UTIL: <tt>vertex_assignment_map(AssignmentMap assignments)</tt></p>
     168<blockquote>
     169  <tt>AssignmentMap</tt> must be a model of <a
     170  href="../../property_map/doc/ReadWritePropertyMap.html">Read/Write Property
     171  Map</a>. The key and value types must be the graph's vertex descriptor
     172  type.<br>
     173  <b>Default:</b> A <tt>boost::iterator_property_map</tt> using a
     174  <tt>std::vector</tt> of <tt>num_vertices(g)</tt> vertex descriptors and
     175  <tt>vertexIndices</tt> for the index map.
     176</blockquote>
     177
     178<p>UTIL: <tt>max_priority_queue(MaxPriorityQueue&amp; pq)</tt></p>
     179<blockquote>
     180  <tt>MaxPriorityQueue</tt> must be a model of <a
     181  href="./KeyedUpdatableQueue.html">Keyed Updatable Queue</a> and a
     182  max-<a href="./UpdatableQueue.html#concept%3AUpdatablePriorityQueue">
     183  Updatable Priority Queue</a>. The value type must be the graph's vertex
     184  descriptor and the key type must be the weight type.
     185  <b>Default:</b> A <tt>boost::d_ary_heap_indirect</tt> using a default
     186  index-in-heap and distance map.
     187</blockquote>
     188
     189<p>UTIL: <tt>index_in_heap_map(IndexInHeapMap indicesInHeap)</tt></p>
     190<blockquote>
     191  This parameter only has an effect when the default max-priority queue is used.<br>
     192  <tt>IndexInHeapMap</tt> must be a model of <a
     193  href="../../property_map/doc/ReadWritePropertyMap.html">Read/Write Property
     194  Map</a>. The key type must be the graph's vertex descriptor type. The
     195  value type must be a size type
     196  (<tt>typename&nbsp;std::vector&lt;vertex_descriptor&gt;::size_type</tt>).<br>
     197  <b>Default:</b> A <tt>boost::iterator_property_map</tt> using a
     198  <tt>std::vector</tt> of <tt>num_vertices(g)</tt> size type objects and
     199  <tt>vertexIndices</tt> for the index map.
     200</blockquote>
     201
     202<p>UTIL: <tt>distance_map(DistanceMap wAs)</tt></p>
     203<blockquote>
     204  This parameter only has an effect when the default max-priority queue is used.<br>
     205  <tt>DistanceMap</tt> must be a model of <a
     206  href="../../property_map/doc/ReadWritePropertyMap.html">Read/Write Property
     207  Map</a>. The key type must be the graph's vertex descriptor type. The
     208  value type must be the weight type
     209  (<tt>typename&nbsp;boost::property_traits&lt;WeightMap&gt;::value_type</tt>).
     210  <br>
     211  <b>Default:</b> A <tt>boost::iterator_property_map</tt> using a
     212  <tt>std::vector</tt> of <tt>num_vertices(g)</tt> weight type objects
     213  and <tt>vertexIndices</tt> for the index map.
     214</blockquote>
     215
     216<h3>Returns</h3>
     217<p>void</p>
     218
     219<h3>Throws</h3>
     220
     221<p><tt>bad_graph</tt>
     222<blockquote>
     223  If <tt>num_vertices(g)</tt> is less than 2
     224</blockquote></p>
     225
     226<p><tt>std::invalid_argument</tt>
     227<blockquote>
     228  If a max-priority queue is given as an argument and it is not empty
     229</blockquote>.
     230
     231<h3><a name="SECTION001340300000000000000">
     232Complexity</a>
     233</h3>
     234
     235<p>
     236The time complexity is <i>O(E + V)</i>.
     237</p>
     238
     239<h3>References</h3>
     240<ul>
     241<li>David Matula (1993). <q><a href="http://dl.acm.org/citation.cfm?id=313872&dl=ACM&coll=DL&CFID=85991501&CFTOKEN=44461131">A linear time 2 + epsilon approximation algorightm for edge connectivity</a></q>
     242</li>
     243</ul>
     244
     245<h3>Visitor Event Points</h3>
     246
     247<ul>
     248<li><b><tt>vis.initialize_vertex(s, g)</tt></b> is invoked on every
     249  vertex of the graph before the start of the graph search.</li>
     250
     251<li><b><tt>vis.start_vertex(s, g)</tt></b> is invoked on the source
     252  vertex once before processing its out edges.</li>
     253
     254<li><b><tt>vis.examine_edge(e, g)</tt></b> is invoked on every out-edge
     255  of each vertex after it is started.</li>
     256
     257<li><b><tt>vis.finish_vertex(u, g)</tt></b> is invoked on a vertex after
     258  all of its out edges have been examined and the reach counts of the
     259  unvisited targets have been updated.</li>
     260</ul>
     261
     262<h3>Notes</h3>
     263
     264<p><a name="1">[1]</a>
     265  Since the visitor parameter is passed by value, if your visitor
     266  contains state then any changes to the state during the algorithm
     267  will be made to a copy of the visitor object, not the visitor object
     268  passed in. Therefore you may want the visitor to hold this state by
     269  pointer or reference.</p>
     270
     271<hr>
     272<table>
     273<tr valign=top>
     274<td nowrap>Copyright &copy; 2012</td><td>
     275Fernando Vilas
     276</td></tr></table>
     277
     278</body>
     279</html>
  • libs/graph/test/Jamfile.v2

     
    123123    [ run two_graphs_common_spanning_trees_test.cpp ]
    124124    [ run random_spanning_tree_test.cpp ../build//boost_graph ]
    125125    [ run graphml_test.cpp ../build//boost_graph : : "graphml_test.xml" ]
     126    [ run mas_test.cpp ../../test/build//boost_unit_test_framework/<link>static : $(TEST_DIR) ]
    126127    [ run stoer_wagner_test.cpp ../../test/build//boost_unit_test_framework/<link>static : $(TEST_DIR) ]
    127128    [ compile filtered_graph_properties_dijkstra.cpp ]
    128129    [ run vf2_sub_graph_iso_test.cpp ]
  • libs/graph/test/mas_test.cpp

     
     1//            Copyright Fernando Vilas 2012.
     2//     Based on stoer_wagner_test.cpp by Daniel Trebbien.
     3// Distributed under the Boost Software License, Version 1.0.
     4//   (See accompanying file LICENSE_1_0.txt or the copy at
     5//         http://www.boost.org/LICENSE_1_0.txt)
     6
     7#include <fstream>
     8#include <iostream>
     9#include <map>
     10#include <vector>
     11#include <string>
     12#include <boost/graph/adjacency_list.hpp>
     13#include <boost/graph/connected_components.hpp>
     14#include <boost/graph/exception.hpp>
     15#include <boost/graph/graph_traits.hpp>
     16#include <boost/graph/read_dimacs.hpp>
     17#include <boost/graph/maximum_adjacency_search.hpp>
     18#include <boost/graph/visitors.hpp>
     19#include <boost/graph/property_maps/constant_property_map.hpp>
     20#include <boost/property_map/property_map.hpp>
     21#include <boost/test/unit_test.hpp>
     22#include <boost/tuple/tuple.hpp>
     23#include <boost/tuple/tuple_comparison.hpp>
     24#include <boost/tuple/tuple_io.hpp>
     25
     26#include <boost/graph/iteration_macros.hpp>
     27
     28typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, boost::no_property, boost::property<boost::edge_weight_t, int> > undirected_graph;
     29typedef boost::property_map<undirected_graph, boost::edge_weight_t>::type weight_map_type;
     30typedef boost::property_traits<weight_map_type>::value_type weight_type;
     31
     32typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> undirected_unweighted_graph;
     33
     34std::string test_dir;
     35
     36boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) {
     37  if (argc != 2) {
     38    std::cerr << "Usage: " << argv[0] << " path-to-libs-graph-test" << std::endl;
     39    throw boost::unit_test::framework::setup_error("Invalid command line arguments");
     40  }
     41  test_dir = argv[1];
     42  return 0;
     43}
     44
     45struct edge_t
     46{
     47  unsigned long first;
     48  unsigned long second;
     49};
     50
     51template <typename Graph, typename KeyedUpdatablePriorityQueue>
     52class mas_edge_connectivity_visitor : public boost::default_mas_visitor {
     53  public:
     54    typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
     55    typedef typename KeyedUpdatablePriorityQueue::key_type weight_type;
     56#if 0
     57    mas_edge_connectivity_visitor(const mas_edge_connectivity_visitor<Graph, KeyedUpdatablePriorityQueue>& r)
     58      : m_pq(r.m_pq), m_curr(r.m_curr), m_prev(r.m_prev),
     59        m_reach_weight(r.m_reach_weight) {
     60          BOOST_TEST_MESSAGE( "COPY CTOR" );
     61        }
     62#endif
     63    explicit mas_edge_connectivity_visitor(KeyedUpdatablePriorityQueue& pq)
     64      : m_pq(pq),
     65        m_curr(new vertex_descriptor(0)), m_prev(new vertex_descriptor(0)),
     66        m_reach_weight(new weight_type(0)) {
     67      //    BOOST_TEST_MESSAGE( "CTOR" );
     68        }
     69
     70  void clear() {
     71    *m_curr = 0;
     72    *m_prev = 0;
     73    *m_reach_weight = 0;
     74  }
     75
     76  //template <typename Vertex> //, typename Graph>
     77  //void start_vertex(Vertex u, const Graph& g) {
     78  void start_vertex(vertex_descriptor u, const Graph& g) {
     79    *m_prev = *m_curr;
     80    *m_curr = u;
     81    //BOOST_TEST_MESSAGE( "Initializing Vertex(weight): " << u << "(" << *m_reach_weight << ")" );
     82    *m_reach_weight = get(m_pq.keys(), u);
     83  }
     84
     85  vertex_descriptor curr() const { return *m_curr; }
     86  vertex_descriptor prev() const { return *m_prev; }
     87  weight_type reach_weight() const { return *m_reach_weight; }
     88
     89  private:
     90
     91    const KeyedUpdatablePriorityQueue& m_pq;
     92    boost::shared_ptr<vertex_descriptor> m_curr, m_prev;
     93    boost::shared_ptr<weight_type> m_reach_weight;
     94};
     95
     96
     97// the example from Stoer & Wagner (1997)
     98// Check various implementations of the ArgPack where
     99// the weights are provided in it, and one case where
     100// they are not.
     101BOOST_AUTO_TEST_CASE(test0)
     102{
     103  typedef boost::graph_traits<undirected_graph>::vertex_descriptor vertex_descriptor;
     104  typedef boost::graph_traits<undirected_graph>::edge_descriptor edge_descriptor;
     105
     106  edge_t edges[] = {{0, 1}, {1, 2}, {2, 3},
     107    {0, 4}, {1, 4}, {1, 5}, {2, 6}, {3, 6}, {3, 7}, {4, 5}, {5, 6}, {6, 7}};
     108  weight_type ws[] = {2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3};
     109  undirected_graph g(edges, edges + 12, ws, 8, 12);
     110
     111  weight_map_type weights = get(boost::edge_weight, g);
     112
     113  std::map<vertex_descriptor, vertex_descriptor> assignment;
     114  boost::associative_property_map<std::map<vertex_descriptor, vertex_descriptor> > assignments(assignment);
     115
     116  typedef boost::shared_array_property_map<weight_type, boost::property_map<undirected_graph, boost::vertex_index_t>::const_type> distances_type;
     117  distances_type distances = boost::make_shared_array_property_map(num_vertices(g), weight_type(0), get(boost::vertex_index, g));
     118  typedef std::vector<vertex_descriptor>::size_type index_in_heap_type;
     119  typedef boost::shared_array_property_map<index_in_heap_type, boost::property_map<undirected_graph, boost::vertex_index_t>::const_type> indicesInHeap_type;
     120  indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map(num_vertices(g), index_in_heap_type(-1), get(boost::vertex_index, g));
     121  boost::d_ary_heap_indirect<vertex_descriptor, 22, indicesInHeap_type, distances_type, std::greater<weight_type> > pq(distances, indicesInHeap);
     122
     123  mas_edge_connectivity_visitor<undirected_graph,boost::d_ary_heap_indirect<vertex_descriptor, 22, indicesInHeap_type, distances_type, std::greater<weight_type> > >  test_vis(pq);
     124
     125  boost::maximum_adjacency_search(g,
     126        boost::weight_map(weights).
     127        visitor(test_vis).
     128        root_vertex(*vertices(g).first).
     129        vertex_assignment_map(assignments).
     130        max_priority_queue(pq));
     131
     132  BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7));
     133  BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(6));
     134  BOOST_CHECK_EQUAL(test_vis.reach_weight(), 5);
     135
     136  test_vis.clear();
     137  boost::maximum_adjacency_search(g,
     138        boost::weight_map(weights).
     139        visitor(test_vis).
     140        root_vertex(*vertices(g).first).
     141        max_priority_queue(pq));
     142
     143  BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7));
     144  BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(6));
     145  BOOST_CHECK_EQUAL(test_vis.reach_weight(), 5);
     146
     147  test_vis.clear();
     148  boost::maximum_adjacency_search(g,
     149        boost::weight_map(weights).
     150        visitor(test_vis).
     151        max_priority_queue(pq));
     152
     153  BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7));
     154  BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(6));
     155  BOOST_CHECK_EQUAL(test_vis.reach_weight(), 5);
     156
     157  boost::maximum_adjacency_search(g,
     158        boost::weight_map(weights).
     159        visitor(boost::make_mas_visitor(boost::null_visitor())));
     160
     161  boost::maximum_adjacency_search(g,
     162        boost::weight_map(weights));
     163
     164  boost::maximum_adjacency_search(g,
     165        boost::root_vertex(*vertices(g).first));
     166
     167  test_vis.clear();
     168  boost::maximum_adjacency_search(g,
     169      boost::weight_map(boost::make_constant_property<edge_descriptor>(weight_type(1))).
     170      visitor(test_vis).
     171      max_priority_queue(pq));
     172  BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7));
     173  BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(3));
     174  BOOST_CHECK_EQUAL(test_vis.reach_weight(), 2);
     175
     176}
     177
     178// Check the unweighted case
     179// with and without providing a weight_map
     180BOOST_AUTO_TEST_CASE(test1)
     181{
     182  typedef boost::graph_traits<undirected_unweighted_graph>::vertex_descriptor vertex_descriptor;
     183  typedef boost::graph_traits<undirected_unweighted_graph>::edge_descriptor edge_descriptor;
     184
     185  edge_t edge_list[] = {{0, 1}, {1, 2}, {2, 3},
     186    {0, 4}, {1, 4}, {1, 5}, {2, 6}, {3, 6}, {3, 7}, {4, 5}, {5, 6}, {6, 7}};
     187  undirected_unweighted_graph g(edge_list, edge_list + 12, 8);
     188
     189  std::map<vertex_descriptor, vertex_descriptor> assignment;
     190  boost::associative_property_map<std::map<vertex_descriptor, vertex_descriptor> > assignments(assignment);
     191
     192  typedef unsigned weight_type;
     193  typedef boost::shared_array_property_map<weight_type, boost::property_map<undirected_graph, boost::vertex_index_t>::const_type> distances_type;
     194  distances_type distances = boost::make_shared_array_property_map(num_vertices(g), weight_type(0), get(boost::vertex_index, g));
     195  typedef std::vector<vertex_descriptor>::size_type index_in_heap_type;
     196  typedef boost::shared_array_property_map<index_in_heap_type, boost::property_map<undirected_graph, boost::vertex_index_t>::const_type> indicesInHeap_type;
     197  indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map(num_vertices(g), index_in_heap_type(-1), get(boost::vertex_index, g));
     198  boost::d_ary_heap_indirect<vertex_descriptor, 22, indicesInHeap_type, distances_type, std::greater<weight_type> > pq(distances, indicesInHeap);
     199
     200  mas_edge_connectivity_visitor<undirected_unweighted_graph,boost::d_ary_heap_indirect<vertex_descriptor, 22, indicesInHeap_type, distances_type, std::greater<weight_type> > >  test_vis(pq);
     201
     202  boost::maximum_adjacency_search(g,
     203         boost::weight_map(boost::make_constant_property<edge_descriptor>(weight_type(1))).visitor(test_vis).max_priority_queue(pq));
     204
     205  BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7));
     206  BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(3));
     207  BOOST_CHECK_EQUAL(test_vis.reach_weight(), weight_type(2));
     208
     209  weight_type ws[] = {2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3};
     210  std::map<edge_descriptor, weight_type> wm;
     211
     212  weight_type i = 0;
     213  BGL_FORALL_EDGES_T(e, g, undirected_unweighted_graph) {
     214    wm[e] = ws[i];
     215    ++i;
     216  }
     217  boost::associative_property_map<std::map<edge_descriptor, weight_type> > ws_map(wm);
     218
     219  boost::maximum_adjacency_search(g, boost::weight_map(ws_map).visitor(test_vis).max_priority_queue(pq));
     220  BOOST_CHECK_EQUAL(test_vis.curr(), vertex_descriptor(7));
     221  BOOST_CHECK_EQUAL(test_vis.prev(), vertex_descriptor(6));
     222  BOOST_CHECK_EQUAL(test_vis.reach_weight(), weight_type(5));
     223
     224}
     225
     226#include <boost/graph/iteration_macros_undef.hpp>
     227