Ticket #6780: max_adj_search_v6.patch

File max_adj_search_v6.patch, 37.7 KB (added by Jeremiah Willcock, 6 years ago)
  • 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 * The algorithm returns the last 2 vertices visited (s and t), and
     38 * the key from the priority queue of the last vertex (t) when
     39 * removed.
     40 *
     41 */
     42
     43#include <boost/concept_check.hpp>
     44#include <boost/concept/assert.hpp>
     45#include <boost/graph/buffer_concepts.hpp>
     46#include <boost/graph/exception.hpp>
     47#include <boost/graph/graph_concepts.hpp>
     48#include <boost/graph/iteration_macros.hpp>
     49#include <boost/graph/named_function_params.hpp>
     50#include <boost/graph/visitors.hpp>
     51#include <boost/tuple/tuple.hpp>
     52
     53#include <set>
     54
     55namespace boost {
     56template <class Visitor, class Graph>
     57struct MASVisitorConcept {
     58  void constraints() {
     59    boost::function_requires< boost::CopyConstructibleConcept<Visitor> >();
     60    vis.initialize_vertex(u, g);
     61    vis.start_vertex(u, g);
     62    vis.examine_edge(e, g);
     63    vis.finish_vertex(u, g);
     64  }
     65  Visitor vis;
     66  Graph g;
     67  typename boost::graph_traits<Graph>::vertex_descriptor u;
     68  typename boost::graph_traits<Graph>::edge_descriptor e;
     69};
     70
     71template <class Visitors = null_visitor>
     72class mas_visitor {
     73public:
     74  mas_visitor() { }
     75  mas_visitor(Visitors vis) : m_vis(vis) { }
     76
     77  template <class Vertex, class Graph>
     78  void
     79  initialize_vertex(Vertex u, Graph& g)
     80  {
     81    invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex());
     82  }
     83
     84  template <class Vertex, class Graph>
     85  void
     86  start_vertex(Vertex u, Graph& g)
     87  {
     88    invoke_visitors(m_vis, u, g, ::boost::on_start_vertex());
     89  }
     90
     91  template <class Edge, class Graph>
     92  void
     93  examine_edge(Edge e, Graph& g)
     94  {
     95    invoke_visitors(m_vis, e, g, ::boost::on_examine_edge());
     96  }
     97
     98  template <class Vertex, class Graph>
     99  void
     100  finish_vertex(Vertex u, Graph& g)
     101  {
     102    invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex());
     103  }
     104
     105  BOOST_GRAPH_EVENT_STUB(on_initialize_vertex,mas)
     106  BOOST_GRAPH_EVENT_STUB(on_start_vertex,mas)
     107  BOOST_GRAPH_EVENT_STUB(on_examine_edge,mas)
     108  BOOST_GRAPH_EVENT_STUB(on_finish_vertex,mas)
     109
     110protected:
     111  Visitors m_vis;
     112};
     113template <class Visitors>
     114mas_visitor<Visitors>
     115make_mas_visitor(Visitors vis) {
     116  return mas_visitor<Visitors>(vis);
     117}
     118typedef mas_visitor<> default_mas_visitor;
     119
     120namespace detail {
     121  template <class Graph, class WeightMap, class MASVisitor, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue>
     122    boost::tuple<typename boost::graph_traits<Graph>::vertex_descriptor, typename boost::graph_traits<Graph>::vertex_descriptor, typename KeyedUpdatablePriorityQueue::key_type>
     123    maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, const typename boost::graph_traits<Graph>::vertex_descriptor start, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) {
     124    typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
     125    typedef typename boost::graph_traits<Graph>::vertices_size_type vertices_size_type;
     126    typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
     127    typedef typename boost::property_traits<WeightMap>::value_type weight_type;
     128
     129   std::set<vertex_descriptor> assignedVertices;
     130
     131   // initialize `assignments` (all vertices are initially
     132   // assigned to themselves)
     133   BGL_FORALL_VERTICES_T(v, g, Graph) {
     134     put(assignments, v, v);
     135   }
     136
     137    typename KeyedUpdatablePriorityQueue::key_map keys = pq.keys();
     138
     139    // set number of visited neighbors for all vertices to 0
     140    BGL_FORALL_VERTICES_T(v, g, Graph) {
     141      if (v == get(assignments, v)) { // foreach u \in V do
     142        put(keys, v, weight_type(0));          vis.initialize_vertex(v, g);
     143
     144        pq.push(v);
     145      }
     146    }
     147    assert(pq.size() >= 2);
     148
     149    // Give the starting vertex high priority
     150    put(keys, start, get(keys, start) + num_vertices(g) + 1);
     151    pq.update(start);
     152
     153    // start traversing the graph
     154    vertex_descriptor s, t;
     155    weight_type w;
     156    while (!pq.empty()) { // while PQ \neq {} do
     157      const vertex_descriptor u = pq.top(); // u = extractmax(PQ)
     158      w = get(keys, u);
     159      pq.pop();                                vis.start_vertex(u, g);
     160
     161      // set s and t to the last and next-to-last vertices extracted
     162      s = t; t = u;
     163
     164      BGL_FORALL_OUTEDGES_T(u, e, g, Graph) { // foreach (u, v) \in E do
     165                                               vis.examine_edge(e, g);
     166
     167        const vertex_descriptor v = get(assignments, target(e, g));
     168
     169        if (pq.contains(v)) { // if v \in PQ then
     170          put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v))
     171          pq.update(v);
     172        }
     173      }
     174
     175      typename std::set<vertex_descriptor>::const_iterator assignedVertexIt, assignedVertexEnd = assignedVertices.end();
     176      for (assignedVertexIt = assignedVertices.begin(); assignedVertexIt != assignedVertexEnd; ++assignedVertexIt) {
     177        const vertex_descriptor uPrime = *assignedVertexIt;
     178
     179        if (get(assignments, uPrime) == u) {
     180          BGL_FORALL_OUTEDGES_T(uPrime, e, g, Graph) { // foreach (u, v) \in E do
     181                                               vis.examine_edge(e, g);
     182
     183            const vertex_descriptor v = get(assignments, target(e, g));
     184
     185            if (pq.contains(v)) { // if v \in PQ then
     186              put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v))
     187              pq.update(v);
     188            }
     189          }
     190        }
     191      }
     192                                               vis.finish_vertex(u, g);
     193    }
     194    return boost::make_tuple(s,t,w);
     195  }
     196} // end namespace detail
     197
     198  template <class Graph, class WeightMap, class MASVisitor, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue>
     199    boost::tuple<typename boost::graph_traits<Graph>::vertex_descriptor, typename boost::graph_traits<Graph>::vertex_descriptor, typename KeyedUpdatablePriorityQueue::key_type>
     200maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, const typename boost::graph_traits<Graph>::vertex_descriptor start, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) {
     201    BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept<Graph>));
     202    BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept<Graph>));
     203    typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
     204    typedef typename boost::graph_traits<Graph>::vertices_size_type vertices_size_type;
     205    typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
     206    BOOST_CONCEPT_ASSERT((boost::Convertible<typename boost::graph_traits<Graph>::directed_category, boost::undirected_tag>));
     207    BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept<WeightMap, edge_descriptor>));
     208    typedef typename boost::property_traits<WeightMap>::value_type weight_type;
     209    boost::function_requires< MASVisitorConcept<MASVisitor, Graph> >();
     210    BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept<VertexAssignmentMap, vertex_descriptor>));
     211    BOOST_CONCEPT_ASSERT((boost::Convertible<vertex_descriptor, typename boost::property_traits<VertexAssignmentMap>::value_type>));
     212    BOOST_CONCEPT_ASSERT((boost::KeyedUpdatableQueueConcept<KeyedUpdatablePriorityQueue>));
     213
     214    vertices_size_type n = num_vertices(g);
     215    if (n < 2)
     216      throw boost::bad_graph("the input graph must have at least two vertices.");
     217    else if (!pq.empty())
     218      throw std::invalid_argument("the max-priority queue must be empty initially.");
     219
     220    return detail::maximum_adjacency_search(g, weights,
     221                                            vis, start,
     222                                            assignments, pq);
     223}
     224
     225namespace graph {
     226  namespace detail {
     227    template <class Graph>
     228    struct maximum_adjacency_search_impl {
     229
     230      typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
     231
     232      //TODO: This assumes that the weight map has edge_weight_t values in it.
     233      // If this is not true, it may fail to compile. We should really rely on
     234      // the ArgPack, but the named parameter macros require a result_type.
     235      // Can this be fixed?
     236      typedef typename boost::tuple<vertex_descriptor, vertex_descriptor,
     237        typename boost::property_traits<typename property_map<Graph, edge_weight_t>::type>::value_type>
     238      result_type;
     239
     240      template <typename ArgPack>
     241      result_type
     242      operator() (const Graph& g, const ArgPack& arg_pack) const {
     243        using namespace boost::graph::keywords;
     244      typedef typename std::vector<vertex_descriptor>::size_type heap_container_size_type;
     245        typedef typename parameter::value_type<ArgPack, tag::weight_map, typename property_map<Graph, edge_weight_t>::type >::type WeightMap;
     246        typedef typename boost::property_traits<WeightMap>::value_type weight_type;
     247
     248        return boost::maximum_adjacency_search
     249             (g,
     250              arg_pack[_weight_map | get(edge_weight, g)],
     251              arg_pack[_visitor | make_mas_visitor(null_visitor())],
     252              arg_pack[_root_vertex | *vertices(g).first],
     253              arg_pack[_vertex_assignment_map | boost::detail::make_property_map_from_arg_pack_gen<tag::vertex_assignment_map, vertex_descriptor>(vertex_descriptor())(g, arg_pack)],
     254              unwrap_ref(arg_pack[_max_priority_queue | boost::detail::make_priority_queue_from_arg_pack_gen<tag::max_priority_queue, weight_type, vertex_descriptor, std::greater<weight_type> >(choose_param(get_param(arg_pack, boost::distance_zero_t()), weight_type(0)))(g, arg_pack)]));
     255      }
     256    };
     257  }
     258  BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(maximum_adjacency_search,1,5)
     259}
     260  // Named parameter interface
     261  BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(maximum_adjacency_search, 1)
     262
     263} // end namespace boost
     264
     265#include <boost/graph/iteration_macros_undef.hpp>
     266
     267#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>
    2020#include <boost/graph/detail/d_ary_heap.hpp>
    2121#include <boost/property_map/property_map.hpp>
    2222#include <boost/tuple/tuple.hpp>
    2323#include <boost/utility/result_of.hpp>
     24#include <boost/graph/iteration_macros.hpp>
    2425
    2526namespace boost {
    26  
     27
    2728  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;
    62       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);
     29    template < typename ParityMap, typename WeightType, typename WeightMap >
     30    class mas_min_cut_visitor : public boost::default_mas_visitor {
     31    public:
     32      mas_min_cut_visitor(ParityMap parity,
     33                          WeightType& cutweight,
     34                          const WeightMap& weight_map)
     35        : m_bestParity(parity),
     36          m_parity(parity),
     37          m_bestWeight(cutweight),
     38          m_cutweight(0),
     39          m_visited(0),
     40          m_weightMap(weight_map)
     41      {
     42        // set here since the init list sets the reference
     43        m_bestWeight = (std::numeric_limits<WeightType>::max)();
     44
     45        // reallocate the parity map since it is for internal
     46        // bookkeeping here only.
     47        // TODO: specific to one-bit color map. make it not depend on that.
     48        m_parity.data.reset(new unsigned char[(m_parity.n + m_parity.bits_per_char - 1) / m_parity.bits_per_char]);
     49      }
     50
     51      template < typename Vertex, typename Graph >
     52      void initialize_vertex(Vertex u, const Graph & g)
     53      {
     54        typedef typename boost::property_traits<ParityMap>::value_type parity_type;
     55        put(m_parity, u, parity_type(0));
     56        put(m_bestParity, u, parity_type(0));
     57      }
     58
     59      template < typename Edge, typename Graph >
     60      void examine_edge(Edge e, const Graph & g)
     61      {
     62        WeightType w = get(m_weightMap, e);
     63
     64        // if the target of e is already marked then decrease cutweight
     65        // otherwise, increase it
     66        if (get(m_parity, boost::target(e, g))) {
     67          m_cutweight -= w;
     68        } else {
     69          m_cutweight += w;
    7270        }
    7371      }
    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);
     72
     73      template < typename Vertex, typename Graph >
     74      void finish_vertex(Vertex u, const Graph & g)
     75      {
     76        typedef typename boost::property_traits<ParityMap>::value_type parity_type;
     77        ++m_visited;
     78        put(m_parity, u, parity_type(1));
     79
     80        if (m_cutweight < m_bestWeight && m_visited < num_vertices(g)) {
     81          m_bestWeight = m_cutweight;
     82          BGL_FORALL_VERTICES_T(i, g, Graph) {
     83            put(m_bestParity,i, get(m_parity,i));
    9384          }
    9485        }
    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         }
    11186      }
    112      
    113       return boost::make_tuple(s, t, w);
    114     }
    115    
     87
     88      inline void clear() {
     89        m_bestWeight = (std::numeric_limits<WeightType>::max)();
     90        m_visited = 0;
     91        m_cutweight = 0;
     92      }
     93
     94    private:
     95      ParityMap m_bestParity;
     96      ParityMap m_parity;
     97      WeightType & m_bestWeight;
     98      WeightType m_cutweight;
     99      unsigned m_visited;
     100      const WeightMap& m_weightMap;
     101    };
     102
    116103    /**
    117104     * \brief Computes a min-cut of the input graph
    118105     *
     
    137124     */
    138125    template <class UndirectedGraph, class WeightMap, class ParityMap, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue>
    139126    typename boost::property_traits<WeightMap>::value_type
    140127    stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq) {
     128      typedef typename boost::graph_traits<UndirectedGraph>::vertex_descriptor vertex_descriptor;
     129      typedef typename boost::graph_traits<UndirectedGraph>::vertices_size_type vertices_size_type;
     130      typedef typename boost::graph_traits<UndirectedGraph>::edge_descriptor edge_descriptor;
     131      typedef typename boost::property_traits<WeightMap>::value_type weight_type;
     132      typedef typename boost::property_traits<ParityMap>::value_type parity_type;
     133
     134      typename graph_traits<UndirectedGraph>::vertex_iterator u_iter, u_end;
     135
     136      weight_type bestW = (std::numeric_limits<weight_type>::max)();
     137      weight_type bestThisTime = (std::numeric_limits<weight_type>::max)();
     138      vertex_descriptor bestStart;
     139
     140      detail::mas_min_cut_visitor<ParityMap, weight_type, WeightMap>
     141        vis(parities, bestThisTime, weights);
     142
     143      // for each node in the graph,
     144      for (boost::tie(u_iter, u_end) = vertices(g); u_iter != u_end; ++u_iter) {
     145        // run the MAS and find the min cut
     146        vis.clear();
     147        boost::maximum_adjacency_search(g,
     148            boost::vertex_assignment_map(assignments).
     149            weight_map(weights).
     150            visitor(vis).
     151            root_vertex(*u_iter).
     152            max_priority_queue(pq));
     153        if (bestThisTime < bestW) {
     154          bestW = bestThisTime;
     155          bestStart = *u_iter;
     156        }
     157      }
     158
     159      // Run one more time, starting from the best start location, to
     160      // ensure the visitor has the best values.
     161      vis.clear();
     162      boost::maximum_adjacency_search(g,
     163        boost::vertex_assignment_map(assignments).
     164        weight_map(weights).
     165        visitor(vis).
     166        root_vertex(bestStart).
     167        max_priority_queue(pq));
     168
     169      return bestW;
     170    }
     171  } // end `namespace detail` within `namespace boost`
     172 
     173    template <class UndirectedGraph, class WeightMap, class ParityMap, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue>
     174    typename boost::property_traits<WeightMap>::value_type
     175    stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq) {
    141176      BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept<UndirectedGraph>));
    142177      BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept<UndirectedGraph>));
    143178      typedef typename boost::graph_traits<UndirectedGraph>::vertex_descriptor vertex_descriptor;
     
    151186      BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept<VertexAssignmentMap, vertex_descriptor>));
    152187      BOOST_CONCEPT_ASSERT((boost::Convertible<vertex_descriptor, typename boost::property_traits<VertexAssignmentMap>::value_type>));
    153188      BOOST_CONCEPT_ASSERT((boost::KeyedUpdatableQueueConcept<KeyedUpdatablePriorityQueue>));
    154      
     189
    155190      vertices_size_type n = num_vertices(g);
    156191      if (n < 2)
    157192        throw boost::bad_graph("the input graph must have at least two vertices.");
    158193      else if (!pq.empty())
    159194        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);
     195
     196      return detail::stoer_wagner_min_cut(g, weights,
     197                                          parities, assignments, pq);
     198    }
     199
     200namespace graph {
     201  namespace detail {
     202    template <class UndirectedGraph, class WeightMap>
     203    struct stoer_wagner_min_cut_impl {
     204      typedef typename boost::property_traits<WeightMap>::value_type result_type;
     205      template <typename ArgPack>
     206      result_type operator() (const UndirectedGraph& g, WeightMap weights, const ArgPack& arg_pack) const {
     207        using namespace boost::graph::keywords;
     208        typedef typename boost::graph_traits<UndirectedGraph>::vertex_descriptor vertex_descriptor;
     209        typedef typename std::vector<vertex_descriptor>::size_type heap_container_size_type;
     210        typedef typename boost::property_traits<WeightMap>::value_type weight_type;
     211        typedef typename boost::property_map<UndirectedGraph, boost::vertex_index_t>::type index_map;
     212        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;
     213        gen_type gen(choose_param(get_param(arg_pack, boost::distance_zero_t()), weight_type(0)));
     214        typename boost::result_of<gen_type(const UndirectedGraph&, const ArgPack&)>::type pq = gen(g, arg_pack);
     215
     216        return boost::stoer_wagner_min_cut(g,
     217          weights,
     218          arg_pack[_parity_map | boost::make_one_bit_color_map<index_map>(num_vertices(g),get(boost::vertex_index, g))],
     219          boost::detail::make_property_map_from_arg_pack_gen<boost::graph::keywords::tag::vertex_assignment_map, vertex_descriptor>(vertex_descriptor())(g, arg_pack),
     220          pq
     221        );
    166222      }
    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;
    207     }
    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       );
     223    };
    231224  }
    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  
     225  BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(stoer_wagner_min_cut,2,3)
     226}
     227
     228  // Named parameter interface
     229  BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(stoer_wagner_min_cut, 2)
     230
    239231} // end `namespace boost`
    240232
    241233#include <boost/graph/iteration_macros_undef.hpp>
  • libs/graph/doc/maximum_adjacency_search.html

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