123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- //
- //=======================================================================
- // Copyright 2012 Fernando Vilas
- // 2010 Daniel Trebbien
- //
- // Distributed under the Boost Software License, Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //=======================================================================
- //
- // The maximum adjacency search algorithm was originally part of the
- // Stoer-Wagner min cut implementation by Daniel Trebbien. It has been
- // broken out into its own file to be a public search algorithm, with
- // visitor concepts.
- #ifndef BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H
- #define BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H
- /**
- * This is an implementation of the maximum adjacency search on an
- * undirected graph. It allows a visitor object to perform some
- * operation on each vertex as that vertex is visited.
- *
- * The algorithm runs as follows:
- *
- * Initialize all nodes to be unvisited (reach count = 0)
- * and call vis.initialize_vertex
- * For i = number of nodes in graph downto 1
- * Select the unvisited node with the highest reach count
- * The user provides the starting node to break the first tie,
- * but future ties are broken arbitrarily
- * Visit the node by calling vis.start_vertex
- * Increment the reach count for all unvisited neighbors
- * and call vis.examine_edge for each of these edges
- * Mark the node as visited and call vis.finish_vertex
- *
- */
- #include <boost/concept_check.hpp>
- #include <boost/concept/assert.hpp>
- #include <boost/graph/buffer_concepts.hpp>
- #include <boost/graph/exception.hpp>
- #include <boost/graph/graph_concepts.hpp>
- #include <boost/graph/iteration_macros.hpp>
- #include <boost/graph/named_function_params.hpp>
- #include <boost/graph/visitors.hpp>
- #include <boost/tuple/tuple.hpp>
- #include <set>
- namespace boost
- {
- template < class Visitor, class Graph > struct MASVisitorConcept
- {
- void constraints()
- {
- boost::function_requires<
- boost::CopyConstructibleConcept< Visitor > >();
- vis.initialize_vertex(u, g);
- vis.start_vertex(u, g);
- vis.examine_edge(e, g);
- vis.finish_vertex(u, g);
- }
- Visitor vis;
- Graph g;
- typename boost::graph_traits< Graph >::vertex_descriptor u;
- typename boost::graph_traits< Graph >::edge_descriptor e;
- };
- template < class Visitors = null_visitor > class mas_visitor
- {
- public:
- mas_visitor() {}
- mas_visitor(Visitors vis) : m_vis(vis) {}
- template < class Vertex, class Graph >
- void initialize_vertex(Vertex u, Graph& g)
- {
- invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex());
- }
- template < class Vertex, class Graph > void start_vertex(Vertex u, Graph& g)
- {
- invoke_visitors(m_vis, u, g, ::boost::on_start_vertex());
- }
- template < class Edge, class Graph > void examine_edge(Edge e, Graph& g)
- {
- invoke_visitors(m_vis, e, g, ::boost::on_examine_edge());
- }
- template < class Vertex, class Graph >
- void finish_vertex(Vertex u, Graph& g)
- {
- invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex());
- }
- BOOST_GRAPH_EVENT_STUB(on_initialize_vertex, mas)
- BOOST_GRAPH_EVENT_STUB(on_start_vertex, mas)
- BOOST_GRAPH_EVENT_STUB(on_examine_edge, mas)
- BOOST_GRAPH_EVENT_STUB(on_finish_vertex, mas)
- protected:
- Visitors m_vis;
- };
- template < class Visitors >
- mas_visitor< Visitors > make_mas_visitor(Visitors vis)
- {
- return mas_visitor< Visitors >(vis);
- }
- typedef mas_visitor<> default_mas_visitor;
- namespace detail
- {
- template < class Graph, class WeightMap, class MASVisitor,
- class VertexAssignmentMap, class KeyedUpdatablePriorityQueue >
- void maximum_adjacency_search(const Graph& g, WeightMap weights,
- MASVisitor vis,
- const typename boost::graph_traits< Graph >::vertex_descriptor start,
- VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq)
- {
- typedef typename boost::graph_traits< Graph >::vertex_descriptor
- vertex_descriptor;
- typedef typename boost::property_traits< WeightMap >::value_type
- weight_type;
- std::set< vertex_descriptor > assignedVertices;
- // initialize `assignments` (all vertices are initially
- // assigned to themselves)
- BGL_FORALL_VERTICES_T(v, g, Graph) { put(assignments, v, v); }
- typename KeyedUpdatablePriorityQueue::key_map keys = pq.keys();
- // set number of visited neighbors for all vertices to 0
- BGL_FORALL_VERTICES_T(v, g, Graph)
- {
- if (v == get(assignments, v))
- { // foreach u \in V do
- put(keys, v, weight_type(0));
- vis.initialize_vertex(v, g);
- pq.push(v);
- }
- }
- BOOST_ASSERT(pq.size() >= 2);
- // Give the starting vertex high priority
- put(keys, start, get(keys, start) + num_vertices(g) + 1);
- pq.update(start);
- // start traversing the graph
- // vertex_descriptor s, t;
- // weight_type w;
- while (!pq.empty())
- { // while PQ \neq {} do
- const vertex_descriptor u = pq.top(); // u = extractmax(PQ)
- /* weight_type w = */ get(keys, u);
- vis.start_vertex(u, g);
- pq.pop(); // vis.start_vertex(u, g);
- BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
- { // foreach (u, v) \in E do
- vis.examine_edge(e, g);
- const vertex_descriptor v = get(assignments, target(e, g));
- if (pq.contains(v))
- { // if v \in PQ then
- put(keys, v,
- get(keys, v)
- + get(weights,
- e)); // increasekey(PQ, v, wA(v) + w(u, v))
- pq.update(v);
- }
- }
- typename std::set< vertex_descriptor >::const_iterator
- assignedVertexIt,
- assignedVertexEnd = assignedVertices.end();
- for (assignedVertexIt = assignedVertices.begin();
- assignedVertexIt != assignedVertexEnd; ++assignedVertexIt)
- {
- const vertex_descriptor uPrime = *assignedVertexIt;
- if (get(assignments, uPrime) == u)
- {
- BGL_FORALL_OUTEDGES_T(uPrime, e, g, Graph)
- { // foreach (u, v) \in E do
- vis.examine_edge(e, g);
- const vertex_descriptor v
- = get(assignments, target(e, g));
- if (pq.contains(v))
- { // if v \in PQ then
- put(keys, v,
- get(keys, v)
- + get(weights, e)); // increasekey(PQ, v,
- // wA(v) + w(u, v))
- pq.update(v);
- }
- }
- }
- }
- vis.finish_vertex(u, g);
- }
- }
- } // end namespace detail
- template < class Graph, class WeightMap, class MASVisitor,
- class VertexAssignmentMap, class KeyedUpdatablePriorityQueue >
- void maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis,
- const typename boost::graph_traits< Graph >::vertex_descriptor start,
- VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq)
- {
- BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept< Graph >));
- BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept< Graph >));
- typedef typename boost::graph_traits< Graph >::vertex_descriptor
- vertex_descriptor;
- typedef typename boost::graph_traits< Graph >::vertices_size_type
- vertices_size_type;
- typedef
- typename boost::graph_traits< Graph >::edge_descriptor edge_descriptor;
- BOOST_CONCEPT_ASSERT((boost::Convertible<
- typename boost::graph_traits< Graph >::directed_category,
- boost::undirected_tag >));
- BOOST_CONCEPT_ASSERT(
- (boost::ReadablePropertyMapConcept< WeightMap, edge_descriptor >));
- // typedef typename boost::property_traits<WeightMap>::value_type
- // weight_type;
- boost::function_requires< MASVisitorConcept< MASVisitor, Graph > >();
- BOOST_CONCEPT_ASSERT(
- (boost::ReadWritePropertyMapConcept< VertexAssignmentMap,
- vertex_descriptor >));
- BOOST_CONCEPT_ASSERT((boost::Convertible< vertex_descriptor,
- typename boost::property_traits< VertexAssignmentMap >::value_type >));
- BOOST_CONCEPT_ASSERT(
- (boost::KeyedUpdatableQueueConcept< KeyedUpdatablePriorityQueue >));
- vertices_size_type n = num_vertices(g);
- if (n < 2)
- throw boost::bad_graph(
- "the input graph must have at least two vertices.");
- else if (!pq.empty())
- throw std::invalid_argument(
- "the max-priority queue must be empty initially.");
- detail::maximum_adjacency_search(g, weights, vis, start, assignments, pq);
- }
- namespace graph
- {
- namespace detail
- {
- template < typename WeightMap > struct mas_dispatch
- {
- typedef void result_type;
- template < typename Graph, typename ArgPack >
- static result_type apply(const Graph& g,
- // const bgl_named_params<P,T,R>& params,
- const ArgPack& params, WeightMap w)
- {
- using namespace boost::graph::keywords;
- typedef typename boost::graph_traits< Graph >::vertex_descriptor
- vertex_descriptor;
- typedef typename WeightMap::value_type weight_type;
- 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;
- default_pq_gen_type pq_gen(
- choose_param(get_param(params, boost::distance_zero_t()),
- weight_type(0)));
- typename boost::result_of< default_pq_gen_type(
- const Graph&, const ArgPack&) >::type pq
- = pq_gen(g, params);
- boost::null_visitor null_vis;
- boost::mas_visitor< boost::null_visitor > default_visitor(
- null_vis);
- vertex_descriptor v = vertex_descriptor();
- boost::detail::make_property_map_from_arg_pack_gen<
- boost::graph::keywords::tag::vertex_assignment_map,
- vertex_descriptor >
- map_gen(v);
- typename boost::detail::map_maker< Graph, ArgPack,
- boost::graph::keywords::tag::vertex_assignment_map,
- vertex_descriptor >::map_type default_map
- = map_gen(g, params);
- boost::maximum_adjacency_search(g, w,
- params[_visitor | default_visitor],
- params[_root_vertex | *vertices(g).first],
- params[_vertex_assignment_map | default_map], pq);
- }
- };
- template <> struct mas_dispatch< boost::param_not_found >
- {
- typedef void result_type;
- template < typename Graph, typename ArgPack >
- static result_type apply(
- const Graph& g, const ArgPack& params, param_not_found)
- {
- using namespace boost::graph::keywords;
- typedef typename boost::graph_traits< Graph >::vertex_descriptor
- vertex_descriptor;
- // get edge_weight_t as the weight type
- typedef typename boost::property_map< Graph, edge_weight_t >
- WeightMap;
- typedef typename WeightMap::value_type weight_type;
- 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;
- default_pq_gen_type pq_gen(
- choose_param(get_param(params, boost::distance_zero_t()),
- weight_type(0)));
- typename boost::result_of< default_pq_gen_type(
- const Graph&, const ArgPack&) >::type pq
- = pq_gen(g, params);
- boost::null_visitor null_vis;
- boost::mas_visitor< boost::null_visitor > default_visitor(
- null_vis);
- vertex_descriptor v = vertex_descriptor();
- boost::detail::make_property_map_from_arg_pack_gen<
- boost::graph::keywords::tag::vertex_assignment_map,
- vertex_descriptor >
- map_gen(v);
- typename boost::detail::map_maker< Graph, ArgPack,
- boost::graph::keywords::tag::vertex_assignment_map,
- vertex_descriptor >::map_type default_map
- = map_gen(g, params);
- boost::maximum_adjacency_search(g, get(edge_weight, g),
- params[_visitor | default_visitor],
- params[_root_vertex | *vertices(g).first],
- params[_vertex_assignment_map | default_map], pq);
- }
- };
- } // end namespace detail
- } // end namespace graph
- // Named parameter interface
- // BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(maximum_adjacency_search, 1)
- template < typename Graph, typename P, typename T, typename R >
- void maximum_adjacency_search(
- const Graph& g, const bgl_named_params< P, T, R >& params)
- {
- typedef bgl_named_params< P, T, R > params_type;
- BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params)
- // do the dispatch based on WeightMap
- typedef typename get_param_type< edge_weight_t,
- bgl_named_params< P, T, R > >::type W;
- graph::detail::mas_dispatch< W >::apply(
- g, arg_pack, get_param(params, edge_weight));
- }
- namespace graph
- {
- namespace detail
- {
- template < typename Graph > struct maximum_adjacency_search_impl
- {
- typedef void result_type;
- template < typename ArgPack >
- void operator()(const Graph& g, const ArgPack& arg_pack) const
- {
- // call the function that does the dispatching
- typedef
- typename get_param_type< edge_weight_t, ArgPack >::type W;
- graph::detail::mas_dispatch< W >::apply(
- g, arg_pack, get_param(arg_pack, edge_weight));
- }
- };
- } // end namespace detail
- BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(maximum_adjacency_search, 1, 5)
- } // end namespace graph
- } // end namespace boost
- #include <boost/graph/iteration_macros_undef.hpp>
- #endif // BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H
|