annotate DEPENDENCIES/generic/include/boost/graph/minimum_degree_ordering.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 //-*-c++-*-
Chris@16 2 //=======================================================================
Chris@16 3 // Copyright 1997-2001 University of Notre Dame.
Chris@16 4 // Authors: Lie-Quan Lee, Jeremy Siek
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 MINIMUM_DEGREE_ORDERING_HPP
Chris@16 12 #define MINIMUM_DEGREE_ORDERING_HPP
Chris@16 13
Chris@16 14 #include <vector>
Chris@16 15 #include <boost/assert.hpp>
Chris@16 16 #include <boost/config.hpp>
Chris@16 17 #include <boost/pending/bucket_sorter.hpp>
Chris@16 18 #include <boost/detail/numeric_traits.hpp> // for integer_traits
Chris@16 19 #include <boost/graph/graph_traits.hpp>
Chris@16 20 #include <boost/property_map/property_map.hpp>
Chris@16 21
Chris@16 22 namespace boost {
Chris@16 23
Chris@16 24 namespace detail {
Chris@16 25
Chris@16 26 //
Chris@16 27 // Given a set of n integers (where the integer values range from
Chris@16 28 // zero to n-1), we want to keep track of a collection of stacks
Chris@16 29 // of integers. It so happens that an integer will appear in at
Chris@16 30 // most one stack at a time, so the stacks form disjoint sets.
Chris@16 31 // Because of these restrictions, we can use one big array to
Chris@16 32 // store all the stacks, intertwined with one another.
Chris@16 33 // No allocation/deallocation happens in the push()/pop() methods
Chris@16 34 // so this is faster than using std::stack's.
Chris@16 35 //
Chris@16 36 template <class SignedInteger>
Chris@16 37 class Stacks {
Chris@16 38 typedef SignedInteger value_type;
Chris@16 39 typedef typename std::vector<value_type>::size_type size_type;
Chris@16 40 public:
Chris@16 41 Stacks(size_type n) : data(n) {}
Chris@16 42
Chris@16 43 //: stack
Chris@16 44 class stack {
Chris@16 45 typedef typename std::vector<value_type>::iterator Iterator;
Chris@16 46 public:
Chris@16 47 stack(Iterator _data, const value_type& head)
Chris@16 48 : data(_data), current(head) {}
Chris@16 49
Chris@16 50 // did not use default argument here to avoid internal compiler error
Chris@16 51 // in g++.
Chris@16 52 stack(Iterator _data)
Chris@16 53 : data(_data), current(-(std::numeric_limits<value_type>::max)()) {}
Chris@16 54
Chris@16 55 void pop() {
Chris@16 56 BOOST_ASSERT(! empty());
Chris@16 57 current = data[current];
Chris@16 58 }
Chris@16 59 void push(value_type v) {
Chris@16 60 data[v] = current;
Chris@16 61 current = v;
Chris@16 62 }
Chris@16 63 bool empty() {
Chris@16 64 return current == -(std::numeric_limits<value_type>::max)();
Chris@16 65 }
Chris@16 66 value_type& top() { return current; }
Chris@16 67 private:
Chris@16 68 Iterator data;
Chris@16 69 value_type current;
Chris@16 70 };
Chris@16 71
Chris@16 72 // To return a stack object
Chris@16 73 stack make_stack()
Chris@16 74 { return stack(data.begin()); }
Chris@16 75 protected:
Chris@16 76 std::vector<value_type> data;
Chris@16 77 };
Chris@16 78
Chris@16 79
Chris@16 80 // marker class, a generalization of coloring.
Chris@16 81 //
Chris@16 82 // This class is to provide a generalization of coloring which has
Chris@16 83 // complexity of amortized constant time to set all vertices' color
Chris@16 84 // back to be untagged. It implemented by increasing a tag.
Chris@16 85 //
Chris@16 86 // The colors are:
Chris@16 87 // not tagged
Chris@16 88 // tagged
Chris@16 89 // multiple_tagged
Chris@16 90 // done
Chris@16 91 //
Chris@16 92 template <class SignedInteger, class Vertex, class VertexIndexMap>
Chris@16 93 class Marker {
Chris@16 94 typedef SignedInteger value_type;
Chris@16 95 typedef typename std::vector<value_type>::size_type size_type;
Chris@16 96
Chris@16 97 static value_type done()
Chris@16 98 { return (std::numeric_limits<value_type>::max)()/2; }
Chris@16 99 public:
Chris@16 100 Marker(size_type _num, VertexIndexMap index_map)
Chris@16 101 : tag(1 - (std::numeric_limits<value_type>::max)()),
Chris@16 102 data(_num, - (std::numeric_limits<value_type>::max)()),
Chris@16 103 id(index_map) {}
Chris@16 104
Chris@16 105 void mark_done(Vertex node) { data[get(id, node)] = done(); }
Chris@16 106
Chris@16 107 bool is_done(Vertex node) { return data[get(id, node)] == done(); }
Chris@16 108
Chris@16 109 void mark_tagged(Vertex node) { data[get(id, node)] = tag; }
Chris@16 110
Chris@16 111 void mark_multiple_tagged(Vertex node) { data[get(id, node)] = multiple_tag; }
Chris@16 112
Chris@16 113 bool is_tagged(Vertex node) const { return data[get(id, node)] >= tag; }
Chris@16 114
Chris@16 115 bool is_not_tagged(Vertex node) const { return data[get(id, node)] < tag; }
Chris@16 116
Chris@16 117 bool is_multiple_tagged(Vertex node) const
Chris@16 118 { return data[get(id, node)] >= multiple_tag; }
Chris@16 119
Chris@16 120 void increment_tag() {
Chris@16 121 const size_type num = data.size();
Chris@16 122 ++tag;
Chris@16 123 if ( tag >= done() ) {
Chris@16 124 tag = 1 - (std::numeric_limits<value_type>::max)();
Chris@16 125 for (size_type i = 0; i < num; ++i)
Chris@16 126 if ( data[i] < done() )
Chris@16 127 data[i] = - (std::numeric_limits<value_type>::max)();
Chris@16 128 }
Chris@16 129 }
Chris@16 130
Chris@16 131 void set_multiple_tag(value_type mdeg0)
Chris@16 132 {
Chris@16 133 const size_type num = data.size();
Chris@16 134 multiple_tag = tag + mdeg0;
Chris@16 135
Chris@16 136 if ( multiple_tag >= done() ) {
Chris@16 137 tag = 1-(std::numeric_limits<value_type>::max)();
Chris@16 138
Chris@16 139 for (size_type i=0; i<num; i++)
Chris@16 140 if ( data[i] < done() )
Chris@16 141 data[i] = -(std::numeric_limits<value_type>::max)();
Chris@16 142
Chris@16 143 multiple_tag = tag + mdeg0;
Chris@16 144 }
Chris@16 145 }
Chris@16 146
Chris@16 147 void set_tag_as_multiple_tag() { tag = multiple_tag; }
Chris@16 148
Chris@16 149 protected:
Chris@16 150 value_type tag;
Chris@16 151 value_type multiple_tag;
Chris@16 152 std::vector<value_type> data;
Chris@16 153 VertexIndexMap id;
Chris@16 154 };
Chris@16 155
Chris@16 156 template< class Iterator, class SignedInteger,
Chris@16 157 class Vertex, class VertexIndexMap, int offset = 1 >
Chris@16 158 class Numbering {
Chris@16 159 typedef SignedInteger number_type;
Chris@16 160 number_type num; //start from 1 instead of zero
Chris@16 161 Iterator data;
Chris@16 162 number_type max_num;
Chris@16 163 VertexIndexMap id;
Chris@16 164 public:
Chris@16 165 Numbering(Iterator _data, number_type _max_num, VertexIndexMap id)
Chris@16 166 : num(1), data(_data), max_num(_max_num), id(id) {}
Chris@16 167 void operator()(Vertex node) { data[get(id, node)] = -num; }
Chris@16 168 bool all_done(number_type i = 0) const { return num + i > max_num; }
Chris@16 169 void increment(number_type i = 1) { num += i; }
Chris@16 170 bool is_numbered(Vertex node) const {
Chris@16 171 return data[get(id, node)] < 0;
Chris@16 172 }
Chris@16 173 void indistinguishable(Vertex i, Vertex j) {
Chris@16 174 data[get(id, i)] = - (get(id, j) + offset);
Chris@16 175 }
Chris@16 176 };
Chris@16 177
Chris@16 178 template <class SignedInteger, class Vertex, class VertexIndexMap>
Chris@16 179 class degreelists_marker {
Chris@16 180 public:
Chris@16 181 typedef SignedInteger value_type;
Chris@16 182 typedef typename std::vector<value_type>::size_type size_type;
Chris@16 183 degreelists_marker(size_type n, VertexIndexMap id)
Chris@16 184 : marks(n, 0), id(id) {}
Chris@16 185 void mark_need_update(Vertex i) { marks[get(id, i)] = 1; }
Chris@16 186 bool need_update(Vertex i) { return marks[get(id, i)] == 1; }
Chris@16 187 bool outmatched_or_done (Vertex i) { return marks[get(id, i)] == -1; }
Chris@16 188 void mark(Vertex i) { marks[get(id, i)] = -1; }
Chris@16 189 void unmark(Vertex i) { marks[get(id, i)] = 0; }
Chris@16 190 private:
Chris@16 191 std::vector<value_type> marks;
Chris@16 192 VertexIndexMap id;
Chris@16 193 };
Chris@16 194
Chris@16 195 // Helper function object for edge removal
Chris@16 196 template <class Graph, class MarkerP, class NumberD, class Stack,
Chris@16 197 class VertexIndexMap>
Chris@16 198 class predicateRemoveEdge1 {
Chris@16 199 typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
Chris@16 200 typedef typename graph_traits<Graph>::edge_descriptor edge_t;
Chris@16 201 public:
Chris@16 202 predicateRemoveEdge1(Graph& _g, MarkerP& _marker,
Chris@16 203 NumberD _numbering, Stack& n_e, VertexIndexMap id)
Chris@16 204 : g(&_g), marker(&_marker), numbering(_numbering),
Chris@16 205 neighbor_elements(&n_e), id(id) {}
Chris@16 206
Chris@16 207 bool operator()(edge_t e) {
Chris@16 208 vertex_t dist = target(e, *g);
Chris@16 209 if ( marker->is_tagged(dist) )
Chris@16 210 return true;
Chris@16 211 marker->mark_tagged(dist);
Chris@16 212 if (numbering.is_numbered(dist)) {
Chris@16 213 neighbor_elements->push(get(id, dist));
Chris@16 214 return true;
Chris@16 215 }
Chris@16 216 return false;
Chris@16 217 }
Chris@16 218 private:
Chris@16 219 Graph* g;
Chris@16 220 MarkerP* marker;
Chris@16 221 NumberD numbering;
Chris@16 222 Stack* neighbor_elements;
Chris@16 223 VertexIndexMap id;
Chris@16 224 };
Chris@16 225
Chris@16 226 // Helper function object for edge removal
Chris@16 227 template <class Graph, class MarkerP>
Chris@16 228 class predicate_remove_tagged_edges
Chris@16 229 {
Chris@16 230 typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
Chris@16 231 typedef typename graph_traits<Graph>::edge_descriptor edge_t;
Chris@16 232 public:
Chris@16 233 predicate_remove_tagged_edges(Graph& _g, MarkerP& _marker)
Chris@16 234 : g(&_g), marker(&_marker) {}
Chris@16 235
Chris@16 236 bool operator()(edge_t e) {
Chris@16 237 vertex_t dist = target(e, *g);
Chris@16 238 if ( marker->is_tagged(dist) )
Chris@16 239 return true;
Chris@16 240 return false;
Chris@16 241 }
Chris@16 242 private:
Chris@16 243 Graph* g;
Chris@16 244 MarkerP* marker;
Chris@16 245 };
Chris@16 246
Chris@16 247 template<class Graph, class DegreeMap,
Chris@16 248 class InversePermutationMap,
Chris@16 249 class PermutationMap,
Chris@16 250 class SuperNodeMap,
Chris@16 251 class VertexIndexMap>
Chris@16 252 class mmd_impl
Chris@16 253 {
Chris@16 254 // Typedefs
Chris@16 255 typedef graph_traits<Graph> Traits;
Chris@16 256 typedef typename Traits::vertices_size_type size_type;
Chris@16 257 typedef typename detail::integer_traits<size_type>::difference_type
Chris@16 258 diff_t;
Chris@16 259 typedef typename Traits::vertex_descriptor vertex_t;
Chris@16 260 typedef typename Traits::adjacency_iterator adj_iter;
Chris@16 261 typedef iterator_property_map<vertex_t*,
Chris@16 262 identity_property_map, vertex_t, vertex_t&> IndexVertexMap;
Chris@16 263 typedef detail::Stacks<diff_t> Workspace;
Chris@16 264 typedef bucket_sorter<size_type, vertex_t, DegreeMap, VertexIndexMap>
Chris@16 265 DegreeLists;
Chris@16 266 typedef Numbering<InversePermutationMap, diff_t, vertex_t,VertexIndexMap>
Chris@16 267 NumberingD;
Chris@16 268 typedef degreelists_marker<diff_t, vertex_t, VertexIndexMap>
Chris@16 269 DegreeListsMarker;
Chris@16 270 typedef Marker<diff_t, vertex_t, VertexIndexMap> MarkerP;
Chris@16 271
Chris@16 272 // Data Members
Chris@16 273
Chris@16 274 // input parameters
Chris@16 275 Graph& G;
Chris@16 276 int delta;
Chris@16 277 DegreeMap degree;
Chris@16 278 InversePermutationMap inverse_perm;
Chris@16 279 PermutationMap perm;
Chris@16 280 SuperNodeMap supernode_size;
Chris@16 281 VertexIndexMap vertex_index_map;
Chris@16 282
Chris@16 283 // internal data-structures
Chris@16 284 std::vector<vertex_t> index_vertex_vec;
Chris@16 285 size_type n;
Chris@16 286 IndexVertexMap index_vertex_map;
Chris@16 287 DegreeLists degreelists;
Chris@16 288 NumberingD numbering;
Chris@16 289 DegreeListsMarker degree_lists_marker;
Chris@16 290 MarkerP marker;
Chris@16 291 Workspace work_space;
Chris@16 292 public:
Chris@16 293 mmd_impl(Graph& g, size_type n_, int delta, DegreeMap degree,
Chris@16 294 InversePermutationMap inverse_perm,
Chris@16 295 PermutationMap perm,
Chris@16 296 SuperNodeMap supernode_size,
Chris@16 297 VertexIndexMap id)
Chris@16 298 : G(g), delta(delta), degree(degree),
Chris@16 299 inverse_perm(inverse_perm),
Chris@16 300 perm(perm),
Chris@16 301 supernode_size(supernode_size),
Chris@16 302 vertex_index_map(id),
Chris@16 303 index_vertex_vec(n_),
Chris@16 304 n(n_),
Chris@16 305 degreelists(n_ + 1, n_, degree, id),
Chris@16 306 numbering(inverse_perm, n_, vertex_index_map),
Chris@16 307 degree_lists_marker(n_, vertex_index_map),
Chris@16 308 marker(n_, vertex_index_map),
Chris@16 309 work_space(n_)
Chris@16 310 {
Chris@16 311 typename graph_traits<Graph>::vertex_iterator v, vend;
Chris@16 312 size_type vid = 0;
Chris@16 313 for (boost::tie(v, vend) = vertices(G); v != vend; ++v, ++vid)
Chris@16 314 index_vertex_vec[vid] = *v;
Chris@16 315 index_vertex_map = IndexVertexMap(&index_vertex_vec[0]);
Chris@16 316
Chris@16 317 // Initialize degreelists. Degreelists organizes the nodes
Chris@16 318 // according to their degree.
Chris@16 319 for (boost::tie(v, vend) = vertices(G); v != vend; ++v) {
Chris@16 320 put(degree, *v, out_degree(*v, G));
Chris@16 321 degreelists.push(*v);
Chris@16 322 }
Chris@16 323 }
Chris@16 324
Chris@16 325 void do_mmd()
Chris@16 326 {
Chris@16 327 // Eliminate the isolated nodes -- these are simply the nodes
Chris@16 328 // with no neighbors, which are accessible as a list (really, a
Chris@16 329 // stack) at location 0. Since these don't affect any other
Chris@16 330 // nodes, we can eliminate them without doing degree updates.
Chris@16 331 typename DegreeLists::stack list_isolated = degreelists[0];
Chris@16 332 while (!list_isolated.empty()) {
Chris@16 333 vertex_t node = list_isolated.top();
Chris@16 334 marker.mark_done(node);
Chris@16 335 numbering(node);
Chris@16 336 numbering.increment();
Chris@16 337 list_isolated.pop();
Chris@16 338 }
Chris@16 339 size_type min_degree = 1;
Chris@16 340 typename DegreeLists::stack list_min_degree = degreelists[min_degree];
Chris@16 341
Chris@16 342 while (list_min_degree.empty()) {
Chris@16 343 ++min_degree;
Chris@16 344 list_min_degree = degreelists[min_degree];
Chris@16 345 }
Chris@16 346
Chris@16 347 // check if the whole eliminating process is done
Chris@16 348 while (!numbering.all_done()) {
Chris@16 349
Chris@16 350 size_type min_degree_limit = min_degree + delta; // WARNING
Chris@16 351 typename Workspace::stack llist = work_space.make_stack();
Chris@16 352
Chris@16 353 // multiple elimination
Chris@16 354 while (delta >= 0) {
Chris@16 355
Chris@16 356 // Find the next non-empty degree
Chris@16 357 for (list_min_degree = degreelists[min_degree];
Chris@16 358 list_min_degree.empty() && min_degree <= min_degree_limit;
Chris@16 359 ++min_degree, list_min_degree = degreelists[min_degree])
Chris@16 360 ;
Chris@16 361 if (min_degree > min_degree_limit)
Chris@16 362 break;
Chris@16 363
Chris@16 364 const vertex_t node = list_min_degree.top();
Chris@16 365 const size_type node_id = get(vertex_index_map, node);
Chris@16 366 list_min_degree.pop();
Chris@16 367 numbering(node);
Chris@16 368
Chris@16 369 // check if node is the last one
Chris@16 370 if (numbering.all_done(supernode_size[node])) {
Chris@16 371 numbering.increment(supernode_size[node]);
Chris@16 372 break;
Chris@16 373 }
Chris@16 374 marker.increment_tag();
Chris@16 375 marker.mark_tagged(node);
Chris@16 376
Chris@16 377 this->eliminate(node);
Chris@16 378
Chris@16 379 numbering.increment(supernode_size[node]);
Chris@16 380 llist.push(node_id);
Chris@16 381 } // multiple elimination
Chris@16 382
Chris@16 383 if (numbering.all_done())
Chris@16 384 break;
Chris@16 385
Chris@16 386 this->update( llist, min_degree);
Chris@16 387 }
Chris@16 388
Chris@16 389 } // do_mmd()
Chris@16 390
Chris@16 391 void eliminate(vertex_t node)
Chris@16 392 {
Chris@16 393 typename Workspace::stack element_neighbor = work_space.make_stack();
Chris@16 394
Chris@16 395 // Create two function objects for edge removal
Chris@16 396 typedef typename Workspace::stack WorkStack;
Chris@16 397 predicateRemoveEdge1<Graph, MarkerP, NumberingD,
Chris@16 398 WorkStack, VertexIndexMap>
Chris@16 399 p(G, marker, numbering, element_neighbor, vertex_index_map);
Chris@16 400
Chris@16 401 predicate_remove_tagged_edges<Graph, MarkerP> p2(G, marker);
Chris@16 402
Chris@16 403 // Reconstruct the adjacent node list, push element neighbor in a List.
Chris@16 404 remove_out_edge_if(node, p, G);
Chris@16 405 //during removal element neighbors are collected.
Chris@16 406
Chris@16 407 while (!element_neighbor.empty()) {
Chris@16 408 // element absorb
Chris@16 409 size_type e_id = element_neighbor.top();
Chris@16 410 vertex_t element = get(index_vertex_map, e_id);
Chris@16 411 adj_iter i, i_end;
Chris@16 412 for (boost::tie(i, i_end) = adjacent_vertices(element, G); i != i_end; ++i){
Chris@16 413 vertex_t i_node = *i;
Chris@16 414 if (!marker.is_tagged(i_node) && !numbering.is_numbered(i_node)) {
Chris@16 415 marker.mark_tagged(i_node);
Chris@16 416 add_edge(node, i_node, G);
Chris@16 417 }
Chris@16 418 }
Chris@16 419 element_neighbor.pop();
Chris@16 420 }
Chris@16 421 adj_iter v, ve;
Chris@16 422 for (boost::tie(v, ve) = adjacent_vertices(node, G); v != ve; ++v) {
Chris@16 423 vertex_t v_node = *v;
Chris@16 424 if (!degree_lists_marker.need_update(v_node)
Chris@16 425 && !degree_lists_marker.outmatched_or_done(v_node)) {
Chris@16 426 degreelists.remove(v_node);
Chris@16 427 }
Chris@16 428 //update out edges of v_node
Chris@16 429 remove_out_edge_if(v_node, p2, G);
Chris@16 430
Chris@16 431 if ( out_degree(v_node, G) == 0 ) { // indistinguishable nodes
Chris@16 432 supernode_size[node] += supernode_size[v_node];
Chris@16 433 supernode_size[v_node] = 0;
Chris@16 434 numbering.indistinguishable(v_node, node);
Chris@16 435 marker.mark_done(v_node);
Chris@16 436 degree_lists_marker.mark(v_node);
Chris@16 437 } else { // not indistinguishable nodes
Chris@16 438 add_edge(v_node, node, G);
Chris@16 439 degree_lists_marker.mark_need_update(v_node);
Chris@16 440 }
Chris@16 441 }
Chris@16 442 } // eliminate()
Chris@16 443
Chris@16 444
Chris@16 445 template <class Stack>
Chris@16 446 void update(Stack llist, size_type& min_degree)
Chris@16 447 {
Chris@16 448 size_type min_degree0 = min_degree + delta + 1;
Chris@16 449
Chris@16 450 while (! llist.empty()) {
Chris@16 451 size_type deg, deg0 = 0;
Chris@16 452
Chris@16 453 marker.set_multiple_tag(min_degree0);
Chris@16 454 typename Workspace::stack q2list = work_space.make_stack();
Chris@16 455 typename Workspace::stack qxlist = work_space.make_stack();
Chris@16 456
Chris@16 457 vertex_t current = get(index_vertex_map, llist.top());
Chris@16 458 adj_iter i, ie;
Chris@16 459 for (boost::tie(i,ie) = adjacent_vertices(current, G); i != ie; ++i) {
Chris@16 460 vertex_t i_node = *i;
Chris@16 461 const size_type i_id = get(vertex_index_map, i_node);
Chris@16 462 if (supernode_size[i_node] != 0) {
Chris@16 463 deg0 += supernode_size[i_node];
Chris@16 464 marker.mark_multiple_tagged(i_node);
Chris@16 465 if (degree_lists_marker.need_update(i_node)) {
Chris@16 466 if (out_degree(i_node, G) == 2)
Chris@16 467 q2list.push(i_id);
Chris@16 468 else
Chris@16 469 qxlist.push(i_id);
Chris@16 470 }
Chris@16 471 }
Chris@16 472 }
Chris@16 473
Chris@16 474 while (!q2list.empty()) {
Chris@16 475 const size_type u_id = q2list.top();
Chris@16 476 vertex_t u_node = get(index_vertex_map, u_id);
Chris@16 477 // if u_id is outmatched by others, no need to update degree
Chris@16 478 if (degree_lists_marker.outmatched_or_done(u_node)) {
Chris@16 479 q2list.pop();
Chris@16 480 continue;
Chris@16 481 }
Chris@16 482 marker.increment_tag();
Chris@16 483 deg = deg0;
Chris@16 484
Chris@16 485 adj_iter nu = adjacent_vertices(u_node, G).first;
Chris@16 486 vertex_t neighbor = *nu;
Chris@16 487 if (neighbor == u_node) {
Chris@16 488 ++nu;
Chris@16 489 neighbor = *nu;
Chris@16 490 }
Chris@16 491 if (numbering.is_numbered(neighbor)) {
Chris@16 492 adj_iter i, ie;
Chris@16 493 for (boost::tie(i,ie) = adjacent_vertices(neighbor, G);
Chris@16 494 i != ie; ++i) {
Chris@16 495 const vertex_t i_node = *i;
Chris@16 496 if (i_node == u_node || supernode_size[i_node] == 0)
Chris@16 497 continue;
Chris@16 498 if (marker.is_tagged(i_node)) {
Chris@16 499 if (degree_lists_marker.need_update(i_node)) {
Chris@16 500 if ( out_degree(i_node, G) == 2 ) { // is indistinguishable
Chris@16 501 supernode_size[u_node] += supernode_size[i_node];
Chris@16 502 supernode_size[i_node] = 0;
Chris@16 503 numbering.indistinguishable(i_node, u_node);
Chris@16 504 marker.mark_done(i_node);
Chris@16 505 degree_lists_marker.mark(i_node);
Chris@16 506 } else // is outmatched
Chris@16 507 degree_lists_marker.mark(i_node);
Chris@16 508 }
Chris@16 509 } else {
Chris@16 510 marker.mark_tagged(i_node);
Chris@16 511 deg += supernode_size[i_node];
Chris@16 512 }
Chris@16 513 }
Chris@16 514 } else
Chris@16 515 deg += supernode_size[neighbor];
Chris@16 516
Chris@16 517 deg -= supernode_size[u_node];
Chris@16 518 degree[u_node] = deg; //update degree
Chris@16 519 degreelists[deg].push(u_node);
Chris@16 520 //u_id has been pushed back into degreelists
Chris@16 521 degree_lists_marker.unmark(u_node);
Chris@16 522 if (min_degree > deg)
Chris@16 523 min_degree = deg;
Chris@16 524 q2list.pop();
Chris@16 525 } // while (!q2list.empty())
Chris@16 526
Chris@16 527 while (!qxlist.empty()) {
Chris@16 528 const size_type u_id = qxlist.top();
Chris@16 529 const vertex_t u_node = get(index_vertex_map, u_id);
Chris@16 530
Chris@16 531 // if u_id is outmatched by others, no need to update degree
Chris@16 532 if (degree_lists_marker.outmatched_or_done(u_node)) {
Chris@16 533 qxlist.pop();
Chris@16 534 continue;
Chris@16 535 }
Chris@16 536 marker.increment_tag();
Chris@16 537 deg = deg0;
Chris@16 538 adj_iter i, ie;
Chris@16 539 for (boost::tie(i, ie) = adjacent_vertices(u_node, G); i != ie; ++i) {
Chris@16 540 vertex_t i_node = *i;
Chris@16 541 if (marker.is_tagged(i_node))
Chris@16 542 continue;
Chris@16 543 marker.mark_tagged(i_node);
Chris@16 544
Chris@16 545 if (numbering.is_numbered(i_node)) {
Chris@16 546 adj_iter j, je;
Chris@16 547 for (boost::tie(j, je) = adjacent_vertices(i_node, G); j != je; ++j) {
Chris@16 548 const vertex_t j_node = *j;
Chris@16 549 if (marker.is_not_tagged(j_node)) {
Chris@16 550 marker.mark_tagged(j_node);
Chris@16 551 deg += supernode_size[j_node];
Chris@16 552 }
Chris@16 553 }
Chris@16 554 } else
Chris@16 555 deg += supernode_size[i_node];
Chris@16 556 } // for adjacent vertices of u_node
Chris@16 557 deg -= supernode_size[u_node];
Chris@16 558 degree[u_node] = deg;
Chris@16 559 degreelists[deg].push(u_node);
Chris@16 560 // u_id has been pushed back into degreelists
Chris@16 561 degree_lists_marker.unmark(u_node);
Chris@16 562 if (min_degree > deg)
Chris@16 563 min_degree = deg;
Chris@16 564 qxlist.pop();
Chris@16 565 } // while (!qxlist.empty()) {
Chris@16 566
Chris@16 567 marker.set_tag_as_multiple_tag();
Chris@16 568 llist.pop();
Chris@16 569 } // while (! llist.empty())
Chris@16 570
Chris@16 571 } // update()
Chris@16 572
Chris@16 573
Chris@16 574 void build_permutation(InversePermutationMap next,
Chris@16 575 PermutationMap prev)
Chris@16 576 {
Chris@16 577 // collect the permutation info
Chris@16 578 size_type i;
Chris@16 579 for (i = 0; i < n; ++i) {
Chris@16 580 diff_t size = supernode_size[get(index_vertex_map, i)];
Chris@16 581 if ( size <= 0 ) {
Chris@16 582 prev[i] = next[i];
Chris@16 583 supernode_size[get(index_vertex_map, i)]
Chris@16 584 = next[i] + 1; // record the supernode info
Chris@16 585 } else
Chris@16 586 prev[i] = - next[i];
Chris@16 587 }
Chris@16 588 for (i = 1; i < n + 1; ++i) {
Chris@16 589 if ( prev[i-1] > 0 )
Chris@16 590 continue;
Chris@16 591 diff_t parent = i;
Chris@16 592 while ( prev[parent - 1] < 0 ) {
Chris@16 593 parent = - prev[parent - 1];
Chris@16 594 }
Chris@16 595
Chris@16 596 diff_t root = parent;
Chris@16 597 diff_t num = prev[root - 1] + 1;
Chris@16 598 next[i-1] = - num;
Chris@16 599 prev[root-1] = num;
Chris@16 600
Chris@16 601 parent = i;
Chris@16 602 diff_t next_node = - prev[parent - 1];
Chris@16 603 while (next_node > 0) {
Chris@16 604 prev[parent-1] = - root;
Chris@16 605 parent = next_node;
Chris@16 606 next_node = - prev[parent - 1];
Chris@16 607 }
Chris@16 608 }
Chris@16 609 for (i = 0; i < n; i++) {
Chris@16 610 diff_t num = - next[i] - 1;
Chris@16 611 next[i] = num;
Chris@16 612 prev[num] = i;
Chris@16 613 }
Chris@16 614 } // build_permutation()
Chris@16 615 };
Chris@16 616
Chris@16 617 } //namespace detail
Chris@16 618
Chris@16 619
Chris@16 620 // MMD algorithm
Chris@16 621 //
Chris@16 622 //The implementation presently includes the enhancements for mass
Chris@16 623 //elimination, incomplete degree update, multiple elimination, and
Chris@16 624 //external degree.
Chris@16 625 //
Chris@16 626 //Important Note: This implementation requires the BGL graph to be
Chris@16 627 //directed. Therefore, nonzero entry (i, j) in a symmetrical matrix
Chris@16 628 //A coresponds to two directed edges (i->j and j->i).
Chris@16 629 //
Chris@16 630 //see Alan George and Joseph W. H. Liu, The Evolution of the Minimum
Chris@16 631 //Degree Ordering Algorithm, SIAM Review, 31, 1989, Page 1-19
Chris@16 632 template<class Graph, class DegreeMap,
Chris@16 633 class InversePermutationMap,
Chris@16 634 class PermutationMap,
Chris@16 635 class SuperNodeMap, class VertexIndexMap>
Chris@16 636 void minimum_degree_ordering
Chris@16 637 (Graph& G,
Chris@16 638 DegreeMap degree,
Chris@16 639 InversePermutationMap inverse_perm,
Chris@16 640 PermutationMap perm,
Chris@16 641 SuperNodeMap supernode_size,
Chris@16 642 int delta,
Chris@16 643 VertexIndexMap vertex_index_map)
Chris@16 644 {
Chris@16 645 detail::mmd_impl<Graph,DegreeMap,InversePermutationMap,
Chris@16 646 PermutationMap, SuperNodeMap, VertexIndexMap>
Chris@16 647 impl(G, num_vertices(G), delta, degree, inverse_perm,
Chris@16 648 perm, supernode_size, vertex_index_map);
Chris@16 649 impl.do_mmd();
Chris@16 650 impl.build_permutation(inverse_perm, perm);
Chris@16 651 }
Chris@16 652
Chris@16 653 } // namespace boost
Chris@16 654
Chris@16 655 #endif // MINIMUM_DEGREE_ORDERING_HPP