minimum_degree_ordering.hpp 26 KB

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