minimum_degree_ordering.hpp 23 KB

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