maximum_adjacency_search.hpp 14 KB

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