annotate DEPENDENCIES/generic/include/boost/graph/core_numbers.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents 2665513ce2d3
children
rev   line source
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