maximum_adjacency_search.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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. {
  48. template < class Visitor, class Graph > struct MASVisitorConcept
  49. {
  50. void constraints()
  51. {
  52. boost::function_requires<
  53. boost::CopyConstructibleConcept< Visitor > >();
  54. vis.initialize_vertex(u, g);
  55. vis.start_vertex(u, g);
  56. vis.examine_edge(e, g);
  57. vis.finish_vertex(u, g);
  58. }
  59. Visitor vis;
  60. Graph g;
  61. typename boost::graph_traits< Graph >::vertex_descriptor u;
  62. typename boost::graph_traits< Graph >::edge_descriptor e;
  63. };
  64. template < class Visitors = null_visitor > class mas_visitor
  65. {
  66. public:
  67. mas_visitor() {}
  68. mas_visitor(Visitors vis) : m_vis(vis) {}
  69. template < class Vertex, class Graph >
  70. void initialize_vertex(Vertex u, Graph& g)
  71. {
  72. invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex());
  73. }
  74. template < class Vertex, class Graph > void 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 > void examine_edge(Edge e, Graph& g)
  79. {
  80. invoke_visitors(m_vis, e, g, ::boost::on_examine_edge());
  81. }
  82. template < class Vertex, class Graph >
  83. void finish_vertex(Vertex u, Graph& g)
  84. {
  85. invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex());
  86. }
  87. BOOST_GRAPH_EVENT_STUB(on_initialize_vertex, mas)
  88. BOOST_GRAPH_EVENT_STUB(on_start_vertex, mas)
  89. BOOST_GRAPH_EVENT_STUB(on_examine_edge, mas)
  90. BOOST_GRAPH_EVENT_STUB(on_finish_vertex, mas)
  91. protected:
  92. Visitors m_vis;
  93. };
  94. template < class Visitors >
  95. mas_visitor< Visitors > make_mas_visitor(Visitors vis)
  96. {
  97. return mas_visitor< Visitors >(vis);
  98. }
  99. typedef mas_visitor<> default_mas_visitor;
  100. namespace detail
  101. {
  102. template < class Graph, class WeightMap, class MASVisitor,
  103. class VertexAssignmentMap, class KeyedUpdatablePriorityQueue >
  104. void maximum_adjacency_search(const Graph& g, WeightMap weights,
  105. MASVisitor vis,
  106. const typename boost::graph_traits< Graph >::vertex_descriptor start,
  107. VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq)
  108. {
  109. typedef typename boost::graph_traits< Graph >::vertex_descriptor
  110. vertex_descriptor;
  111. typedef typename boost::property_traits< WeightMap >::value_type
  112. weight_type;
  113. std::set< vertex_descriptor > assignedVertices;
  114. // initialize `assignments` (all vertices are initially
  115. // assigned to themselves)
  116. BGL_FORALL_VERTICES_T(v, g, Graph) { put(assignments, v, v); }
  117. typename KeyedUpdatablePriorityQueue::key_map keys = pq.keys();
  118. // set number of visited neighbors for all vertices to 0
  119. BGL_FORALL_VERTICES_T(v, g, Graph)
  120. {
  121. if (v == get(assignments, v))
  122. { // foreach u \in V do
  123. put(keys, v, weight_type(0));
  124. vis.initialize_vertex(v, g);
  125. pq.push(v);
  126. }
  127. }
  128. BOOST_ASSERT(pq.size() >= 2);
  129. // Give the starting vertex high priority
  130. put(keys, start, get(keys, start) + num_vertices(g) + 1);
  131. pq.update(start);
  132. // start traversing the graph
  133. // vertex_descriptor s, t;
  134. // weight_type w;
  135. while (!pq.empty())
  136. { // while PQ \neq {} do
  137. const vertex_descriptor u = pq.top(); // u = extractmax(PQ)
  138. /* weight_type w = */ get(keys, u);
  139. vis.start_vertex(u, g);
  140. pq.pop(); // vis.start_vertex(u, g);
  141. BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
  142. { // foreach (u, v) \in E do
  143. vis.examine_edge(e, g);
  144. const vertex_descriptor v = get(assignments, target(e, g));
  145. if (pq.contains(v))
  146. { // if v \in PQ then
  147. put(keys, v,
  148. get(keys, v)
  149. + get(weights,
  150. e)); // increasekey(PQ, v, wA(v) + w(u, v))
  151. pq.update(v);
  152. }
  153. }
  154. typename std::set< vertex_descriptor >::const_iterator
  155. assignedVertexIt,
  156. assignedVertexEnd = assignedVertices.end();
  157. for (assignedVertexIt = assignedVertices.begin();
  158. assignedVertexIt != assignedVertexEnd; ++assignedVertexIt)
  159. {
  160. const vertex_descriptor uPrime = *assignedVertexIt;
  161. if (get(assignments, uPrime) == u)
  162. {
  163. BGL_FORALL_OUTEDGES_T(uPrime, e, g, Graph)
  164. { // foreach (u, v) \in E do
  165. vis.examine_edge(e, g);
  166. const vertex_descriptor v
  167. = get(assignments, target(e, g));
  168. if (pq.contains(v))
  169. { // if v \in PQ then
  170. put(keys, v,
  171. get(keys, v)
  172. + get(weights, e)); // increasekey(PQ, v,
  173. // wA(v) + w(u, v))
  174. pq.update(v);
  175. }
  176. }
  177. }
  178. }
  179. vis.finish_vertex(u, g);
  180. }
  181. }
  182. } // end namespace detail
  183. template < class Graph, class WeightMap, class MASVisitor,
  184. class VertexAssignmentMap, class KeyedUpdatablePriorityQueue >
  185. void maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis,
  186. const typename boost::graph_traits< Graph >::vertex_descriptor start,
  187. VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq)
  188. {
  189. BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept< Graph >));
  190. BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept< Graph >));
  191. typedef typename boost::graph_traits< Graph >::vertex_descriptor
  192. vertex_descriptor;
  193. typedef typename boost::graph_traits< Graph >::vertices_size_type
  194. vertices_size_type;
  195. typedef
  196. typename boost::graph_traits< Graph >::edge_descriptor edge_descriptor;
  197. BOOST_CONCEPT_ASSERT((boost::Convertible<
  198. typename boost::graph_traits< Graph >::directed_category,
  199. boost::undirected_tag >));
  200. BOOST_CONCEPT_ASSERT(
  201. (boost::ReadablePropertyMapConcept< WeightMap, edge_descriptor >));
  202. // typedef typename boost::property_traits<WeightMap>::value_type
  203. // weight_type;
  204. boost::function_requires< MASVisitorConcept< MASVisitor, Graph > >();
  205. BOOST_CONCEPT_ASSERT(
  206. (boost::ReadWritePropertyMapConcept< VertexAssignmentMap,
  207. vertex_descriptor >));
  208. BOOST_CONCEPT_ASSERT((boost::Convertible< vertex_descriptor,
  209. typename boost::property_traits< VertexAssignmentMap >::value_type >));
  210. BOOST_CONCEPT_ASSERT(
  211. (boost::KeyedUpdatableQueueConcept< KeyedUpdatablePriorityQueue >));
  212. vertices_size_type n = num_vertices(g);
  213. if (n < 2)
  214. throw boost::bad_graph(
  215. "the input graph must have at least two vertices.");
  216. else if (!pq.empty())
  217. throw std::invalid_argument(
  218. "the max-priority queue must be empty initially.");
  219. detail::maximum_adjacency_search(g, weights, vis, start, assignments, pq);
  220. }
  221. namespace graph
  222. {
  223. namespace detail
  224. {
  225. template < typename WeightMap > struct mas_dispatch
  226. {
  227. typedef void result_type;
  228. template < typename Graph, typename ArgPack >
  229. static result_type apply(const Graph& g,
  230. // const bgl_named_params<P,T,R>& params,
  231. const ArgPack& params, WeightMap w)
  232. {
  233. using namespace boost::graph::keywords;
  234. typedef typename boost::graph_traits< Graph >::vertex_descriptor
  235. vertex_descriptor;
  236. typedef typename WeightMap::value_type weight_type;
  237. typedef boost::detail::make_priority_queue_from_arg_pack_gen<
  238. boost::graph::keywords::tag::max_priority_queue,
  239. weight_type, vertex_descriptor,
  240. std::greater< weight_type > >
  241. default_pq_gen_type;
  242. default_pq_gen_type pq_gen(
  243. choose_param(get_param(params, boost::distance_zero_t()),
  244. weight_type(0)));
  245. typename boost::result_of< default_pq_gen_type(
  246. const Graph&, const ArgPack&) >::type pq
  247. = pq_gen(g, params);
  248. boost::null_visitor null_vis;
  249. boost::mas_visitor< boost::null_visitor > default_visitor(
  250. null_vis);
  251. vertex_descriptor v = vertex_descriptor();
  252. boost::detail::make_property_map_from_arg_pack_gen<
  253. boost::graph::keywords::tag::vertex_assignment_map,
  254. vertex_descriptor >
  255. map_gen(v);
  256. typename boost::detail::map_maker< Graph, ArgPack,
  257. boost::graph::keywords::tag::vertex_assignment_map,
  258. vertex_descriptor >::map_type default_map
  259. = map_gen(g, params);
  260. boost::maximum_adjacency_search(g, w,
  261. params[_visitor | default_visitor],
  262. params[_root_vertex | *vertices(g).first],
  263. params[_vertex_assignment_map | default_map], pq);
  264. }
  265. };
  266. template <> struct mas_dispatch< boost::param_not_found >
  267. {
  268. typedef void result_type;
  269. template < typename Graph, typename ArgPack >
  270. static result_type apply(
  271. const Graph& g, const ArgPack& params, param_not_found)
  272. {
  273. using namespace boost::graph::keywords;
  274. typedef typename boost::graph_traits< Graph >::vertex_descriptor
  275. vertex_descriptor;
  276. // get edge_weight_t as the weight type
  277. typedef typename boost::property_map< Graph, edge_weight_t >
  278. WeightMap;
  279. typedef typename WeightMap::value_type weight_type;
  280. typedef boost::detail::make_priority_queue_from_arg_pack_gen<
  281. boost::graph::keywords::tag::max_priority_queue,
  282. weight_type, vertex_descriptor,
  283. std::greater< weight_type > >
  284. default_pq_gen_type;
  285. default_pq_gen_type pq_gen(
  286. choose_param(get_param(params, boost::distance_zero_t()),
  287. weight_type(0)));
  288. typename boost::result_of< default_pq_gen_type(
  289. const Graph&, const ArgPack&) >::type pq
  290. = pq_gen(g, params);
  291. boost::null_visitor null_vis;
  292. boost::mas_visitor< boost::null_visitor > default_visitor(
  293. null_vis);
  294. vertex_descriptor v = vertex_descriptor();
  295. boost::detail::make_property_map_from_arg_pack_gen<
  296. boost::graph::keywords::tag::vertex_assignment_map,
  297. vertex_descriptor >
  298. map_gen(v);
  299. typename boost::detail::map_maker< Graph, ArgPack,
  300. boost::graph::keywords::tag::vertex_assignment_map,
  301. vertex_descriptor >::map_type default_map
  302. = map_gen(g, params);
  303. boost::maximum_adjacency_search(g, get(edge_weight, g),
  304. params[_visitor | default_visitor],
  305. params[_root_vertex | *vertices(g).first],
  306. params[_vertex_assignment_map | default_map], pq);
  307. }
  308. };
  309. } // end namespace detail
  310. } // end namespace graph
  311. // Named parameter interface
  312. // BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(maximum_adjacency_search, 1)
  313. template < typename Graph, typename P, typename T, typename R >
  314. void maximum_adjacency_search(
  315. const Graph& g, const bgl_named_params< P, T, R >& params)
  316. {
  317. typedef bgl_named_params< P, T, R > params_type;
  318. BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params)
  319. // do the dispatch based on WeightMap
  320. typedef typename get_param_type< edge_weight_t,
  321. bgl_named_params< P, T, R > >::type W;
  322. graph::detail::mas_dispatch< W >::apply(
  323. g, arg_pack, get_param(params, edge_weight));
  324. }
  325. namespace graph
  326. {
  327. namespace detail
  328. {
  329. template < typename Graph > struct maximum_adjacency_search_impl
  330. {
  331. typedef void result_type;
  332. template < typename ArgPack >
  333. void operator()(const Graph& g, const ArgPack& arg_pack) const
  334. {
  335. // call the function that does the dispatching
  336. typedef
  337. typename get_param_type< edge_weight_t, ArgPack >::type W;
  338. graph::detail::mas_dispatch< W >::apply(
  339. g, arg_pack, get_param(arg_pack, edge_weight));
  340. }
  341. };
  342. } // end namespace detail
  343. BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(maximum_adjacency_search, 1, 5)
  344. } // end namespace graph
  345. } // end namespace boost
  346. #include <boost/graph/iteration_macros_undef.hpp>
  347. #endif // BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H