core_numbers.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. //
  2. //=======================================================================
  3. // Copyright 2007 Stanford University
  4. // Authors: David Gleich
  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. #ifndef BOOST_GRAPH_CORE_NUMBERS_HPP
  12. #define BOOST_GRAPH_CORE_NUMBERS_HPP
  13. #include <boost/graph/detail/d_ary_heap.hpp>
  14. #include <boost/graph/breadth_first_search.hpp>
  15. #include <boost/iterator/reverse_iterator.hpp>
  16. #include <boost/concept/assert.hpp>
  17. /*
  18. * core_numbers
  19. *
  20. * Requirement: IncidenceGraph
  21. */
  22. // History
  23. //
  24. // 30 July 2007
  25. // Added visitors to the implementation
  26. //
  27. // 8 February 2008
  28. // Fixed headers and missing typename
  29. namespace boost {
  30. // A linear time O(m) algorithm to compute the indegree core number
  31. // of a graph for unweighted graphs.
  32. //
  33. // and a O((n+m) log n) algorithm to compute the in-edge-weight core
  34. // numbers of a weighted graph.
  35. //
  36. // The linear algorithm comes from:
  37. // Vladimir Batagelj and Matjaz Zaversnik, "An O(m) Algorithm for Cores
  38. // Decomposition of Networks." Sept. 1 2002.
  39. template <typename Visitor, typename Graph>
  40. struct CoreNumbersVisitorConcept {
  41. void constraints()
  42. {
  43. BOOST_CONCEPT_ASSERT(( CopyConstructibleConcept<Visitor> ));
  44. vis.examine_vertex(u,g);
  45. vis.finish_vertex(u,g);
  46. vis.examine_edge(e,g);
  47. }
  48. Visitor vis;
  49. Graph g;
  50. typename graph_traits<Graph>::vertex_descriptor u;
  51. typename graph_traits<Graph>::edge_descriptor e;
  52. };
  53. template <class Visitors = null_visitor>
  54. class core_numbers_visitor : public bfs_visitor<Visitors> {
  55. public:
  56. core_numbers_visitor() {}
  57. core_numbers_visitor(Visitors vis)
  58. : bfs_visitor<Visitors>(vis) {}
  59. private:
  60. template <class Vertex, class Graph>
  61. void initialize_vertex(Vertex, Graph&) {}
  62. template <class Vertex, class Graph>
  63. void discover_vertex(Vertex , Graph&) {}
  64. template <class Vertex, class Graph>
  65. void gray_target(Vertex, Graph&) {}
  66. template <class Vertex, class Graph>
  67. void black_target(Vertex, Graph&) {}
  68. template <class Edge, class Graph>
  69. void tree_edge(Edge, Graph&) {}
  70. template <class Edge, class Graph>
  71. void non_tree_edge(Edge, Graph&) {}
  72. };
  73. template <class Visitors>
  74. core_numbers_visitor<Visitors> make_core_numbers_visitor(Visitors vis)
  75. { return core_numbers_visitor<Visitors>(vis); }
  76. typedef core_numbers_visitor<> default_core_numbers_visitor;
  77. namespace detail {
  78. // implement a constant_property_map to simplify compute_in_degree
  79. // for the weighted and unweighted case
  80. // this is based on dummy property map
  81. template <typename ValueType>
  82. class constant_value_property_map
  83. : public boost::put_get_helper<ValueType,
  84. constant_value_property_map<ValueType> >
  85. {
  86. public:
  87. typedef void key_type;
  88. typedef ValueType value_type;
  89. typedef const ValueType& reference;
  90. typedef boost::readable_property_map_tag category;
  91. inline constant_value_property_map(ValueType cc) : c(cc) { }
  92. inline constant_value_property_map(const constant_value_property_map<ValueType>& x)
  93. : c(x.c) { }
  94. template <class Vertex>
  95. inline reference operator[](Vertex) const { return c; }
  96. protected:
  97. ValueType c;
  98. };
  99. // the core numbers start as the indegree or inweight. This function
  100. // will initialize these values
  101. template <typename Graph, typename CoreMap, typename EdgeWeightMap>
  102. void compute_in_degree_map(Graph& g, CoreMap d, EdgeWeightMap wm)
  103. {
  104. typename graph_traits<Graph>::vertex_iterator vi,vi_end;
  105. typename graph_traits<Graph>::out_edge_iterator ei,ei_end;
  106. for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
  107. put(d,*vi,0);
  108. }
  109. for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
  110. for (boost::tie(ei,ei_end) = out_edges(*vi,g); ei!=ei_end; ++ei) {
  111. put(d,target(*ei,g),get(d,target(*ei,g))+get(wm,*ei));
  112. }
  113. }
  114. }
  115. // the version for weighted graphs is a little different
  116. template <typename Graph, typename CoreMap,
  117. typename EdgeWeightMap, typename MutableQueue,
  118. typename Visitor>
  119. typename property_traits<CoreMap>::value_type
  120. core_numbers_impl(Graph& g, CoreMap c, EdgeWeightMap wm,
  121. MutableQueue& Q, Visitor vis)
  122. {
  123. typename property_traits<CoreMap>::value_type v_cn = 0;
  124. typedef typename graph_traits<Graph>::vertex_descriptor vertex;
  125. while (!Q.empty())
  126. {
  127. // remove v from the Q, and then decrease the core numbers
  128. // of its successors
  129. vertex v = Q.top();
  130. vis.examine_vertex(v,g);
  131. Q.pop();
  132. v_cn = get(c,v);
  133. typename graph_traits<Graph>::out_edge_iterator oi,oi_end;
  134. for (boost::tie(oi,oi_end) = out_edges(v,g); oi!=oi_end; ++oi) {
  135. vis.examine_edge(*oi,g);
  136. vertex u = target(*oi,g);
  137. // if c[u] > c[v], then u is still in the graph,
  138. if (get(c,u) > v_cn) {
  139. // remove the edge
  140. put(c,u,get(c,u)-get(wm,*oi));
  141. if (Q.contains(u))
  142. Q.update(u);
  143. }
  144. }
  145. vis.finish_vertex(v,g);
  146. }
  147. return (v_cn);
  148. }
  149. template <typename Graph, typename CoreMap, typename EdgeWeightMap,
  150. typename IndexMap, typename CoreNumVisitor>
  151. typename property_traits<CoreMap>::value_type
  152. core_numbers_dispatch(Graph&g, CoreMap c, EdgeWeightMap wm,
  153. IndexMap im, CoreNumVisitor vis)
  154. {
  155. typedef typename property_traits<CoreMap>::value_type D;
  156. typedef std::less<D> Cmp;
  157. // build the mutable queue
  158. typedef typename graph_traits<Graph>::vertex_descriptor vertex;
  159. std::vector<std::size_t> index_in_heap_data(num_vertices(g));
  160. typedef iterator_property_map<std::vector<std::size_t>::iterator, IndexMap>
  161. index_in_heap_map_type;
  162. index_in_heap_map_type index_in_heap_map(index_in_heap_data.begin(), im);
  163. typedef d_ary_heap_indirect<vertex, 4, index_in_heap_map_type, CoreMap, Cmp> MutableQueue;
  164. MutableQueue Q(c, index_in_heap_map, Cmp());
  165. typename graph_traits<Graph>::vertex_iterator vi,vi_end;
  166. for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
  167. Q.push(*vi);
  168. }
  169. return core_numbers_impl(g, c, wm, Q, vis);
  170. }
  171. // the version for the unweighted case
  172. // for this functions CoreMap must be initialized
  173. // with the in degree of each vertex
  174. template <typename Graph, typename CoreMap, typename PositionMap,
  175. typename Visitor>
  176. typename property_traits<CoreMap>::value_type
  177. core_numbers_impl(Graph& g, CoreMap c, PositionMap pos, Visitor vis)
  178. {
  179. typedef typename graph_traits<Graph>::vertices_size_type size_type;
  180. typedef typename graph_traits<Graph>::degree_size_type degree_type;
  181. typedef typename graph_traits<Graph>::vertex_descriptor vertex;
  182. typename graph_traits<Graph>::vertex_iterator vi,vi_end;
  183. // store the vertex core numbers
  184. typename property_traits<CoreMap>::value_type v_cn = 0;
  185. // compute the maximum degree (degrees are in the coremap)
  186. typename graph_traits<Graph>::degree_size_type max_deg = 0;
  187. for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
  188. max_deg = (std::max<typename graph_traits<Graph>::degree_size_type>)(max_deg, get(c,*vi));
  189. }
  190. // store the vertices in bins by their degree
  191. // allocate two extra locations to ease boundary cases
  192. std::vector<size_type> bin(max_deg+2);
  193. for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
  194. ++bin[get(c,*vi)];
  195. }
  196. // this loop sets bin[d] to the starting position of vertices
  197. // with degree d in the vert array for the bucket sort
  198. size_type cur_pos = 0;
  199. for (degree_type cur_deg = 0; cur_deg < max_deg+2; ++cur_deg) {
  200. degree_type tmp = bin[cur_deg];
  201. bin[cur_deg] = cur_pos;
  202. cur_pos += tmp;
  203. }
  204. // perform the bucket sort with pos and vert so that
  205. // pos[0] is the vertex of smallest degree
  206. std::vector<vertex> vert(num_vertices(g));
  207. for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
  208. vertex v=*vi;
  209. size_type p=bin[get(c,v)];
  210. put(pos,v,p);
  211. vert[p]=v;
  212. ++bin[get(c,v)];
  213. }
  214. // we ``abused'' bin while placing the vertices, now,
  215. // we need to restore it
  216. std::copy(boost::make_reverse_iterator(bin.end()-2),
  217. boost::make_reverse_iterator(bin.begin()),
  218. boost::make_reverse_iterator(bin.end()-1));
  219. // now simulate removing the vertices
  220. for (size_type i=0; i < num_vertices(g); ++i) {
  221. vertex v = vert[i];
  222. vis.examine_vertex(v,g);
  223. v_cn = get(c,v);
  224. typename graph_traits<Graph>::out_edge_iterator oi,oi_end;
  225. for (boost::tie(oi,oi_end) = out_edges(v,g); oi!=oi_end; ++oi) {
  226. vis.examine_edge(*oi,g);
  227. vertex u = target(*oi,g);
  228. // if c[u] > c[v], then u is still in the graph,
  229. if (get(c,u) > v_cn) {
  230. degree_type deg_u = get(c,u);
  231. degree_type pos_u = get(pos,u);
  232. // w is the first vertex with the same degree as u
  233. // (this is the resort operation!)
  234. degree_type pos_w = bin[deg_u];
  235. vertex w = vert[pos_w];
  236. if (u!=v) {
  237. // swap u and w
  238. put(pos,u,pos_w);
  239. put(pos,w,pos_u);
  240. vert[pos_w] = u;
  241. vert[pos_u] = w;
  242. }
  243. // now, the vertices array is sorted assuming
  244. // we perform the following step
  245. // start the set of vertices with degree of u
  246. // one into the future (this now points at vertex
  247. // w which we swapped with u).
  248. ++bin[deg_u];
  249. // we are removing v from the graph, so u's degree
  250. // decreases
  251. put(c,u,get(c,u)-1);
  252. }
  253. }
  254. vis.finish_vertex(v,g);
  255. }
  256. return v_cn;
  257. }
  258. } // namespace detail
  259. // non-named parameter version for the unweighted case
  260. template <typename Graph, typename CoreMap, typename CoreNumVisitor>
  261. typename property_traits<CoreMap>::value_type
  262. core_numbers(Graph& g, CoreMap c, CoreNumVisitor vis)
  263. {
  264. typedef typename graph_traits<Graph>::vertices_size_type size_type;
  265. detail::compute_in_degree_map(g,c,
  266. detail::constant_value_property_map<
  267. typename property_traits<CoreMap>::value_type>(1) );
  268. return detail::core_numbers_impl(g,c,
  269. make_iterator_property_map(
  270. std::vector<size_type>(num_vertices(g)).begin(),get(vertex_index, g)),
  271. vis
  272. );
  273. }
  274. // non-named paramter version for the unweighted case
  275. template <typename Graph, typename CoreMap>
  276. typename property_traits<CoreMap>::value_type
  277. core_numbers(Graph& g, CoreMap c)
  278. {
  279. return core_numbers(g, c, make_core_numbers_visitor(null_visitor()));
  280. }
  281. // non-named parameter version for the weighted case
  282. template <typename Graph, typename CoreMap, typename EdgeWeightMap,
  283. typename VertexIndexMap, typename CoreNumVisitor>
  284. typename property_traits<CoreMap>::value_type
  285. core_numbers(Graph& g, CoreMap c, EdgeWeightMap wm, VertexIndexMap vim,
  286. CoreNumVisitor vis)
  287. {
  288. detail::compute_in_degree_map(g,c,wm);
  289. return detail::core_numbers_dispatch(g,c,wm,vim,vis);
  290. }
  291. // non-named parameter version for the weighted case
  292. // template <typename Graph, typename CoreMap, typename EdgeWeightMap>
  293. // typename property_traits<CoreMap>::value_type
  294. // core_numbers(Graph& g, CoreMap c, EdgeWeightMap wm)
  295. // {
  296. // typedef typename graph_traits<Graph>::vertices_size_type size_type;
  297. // detail::compute_in_degree_map(g,c,wm);
  298. // return detail::core_numbers_dispatch(g,c,wm,get(vertex_index,g),
  299. // make_core_numbers_visitor(null_visitor()));
  300. // }
  301. template <typename Graph, typename CoreMap>
  302. typename property_traits<CoreMap>::value_type
  303. weighted_core_numbers(Graph& g, CoreMap c)
  304. {
  305. return weighted_core_numbers(
  306. g,c, make_core_numbers_visitor(null_visitor())
  307. );
  308. }
  309. template <typename Graph, typename CoreMap, typename CoreNumVisitor>
  310. typename property_traits<CoreMap>::value_type
  311. weighted_core_numbers(Graph& g, CoreMap c, CoreNumVisitor vis)
  312. { return core_numbers(g,c,get(edge_weight,g),get(vertex_index,g),vis); }
  313. } // namespace boost
  314. #endif // BOOST_GRAPH_CORE_NUMBERS_HPP