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