minimum_degree_ordering.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  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. // input parameters
  241. Graph& G;
  242. int delta;
  243. DegreeMap degree;
  244. InversePermutationMap inverse_perm;
  245. PermutationMap perm;
  246. SuperNodeMap supernode_size;
  247. VertexIndexMap vertex_index_map;
  248. // internal data-structures
  249. std::vector<vertex_t> index_vertex_vec;
  250. size_type n;
  251. IndexVertexMap index_vertex_map;
  252. DegreeLists degreelists;
  253. NumberingD numbering;
  254. DegreeListsMarker degree_lists_marker;
  255. MarkerP marker;
  256. Workspace work_space;
  257. public:
  258. mmd_impl(Graph& g, size_type n_, int delta, DegreeMap degree,
  259. InversePermutationMap inverse_perm,
  260. PermutationMap perm,
  261. SuperNodeMap supernode_size,
  262. VertexIndexMap id)
  263. : G(g), delta(delta), degree(degree),
  264. inverse_perm(inverse_perm),
  265. perm(perm),
  266. supernode_size(supernode_size),
  267. vertex_index_map(id),
  268. index_vertex_vec(n_),
  269. n(n_),
  270. degreelists(n_ + 1, n_, degree, id),
  271. numbering(inverse_perm, n_, vertex_index_map),
  272. degree_lists_marker(n_, vertex_index_map),
  273. marker(n_, vertex_index_map),
  274. work_space(n_)
  275. {
  276. typename graph_traits<Graph>::vertex_iterator v, vend;
  277. size_type vid = 0;
  278. for (boost::tie(v, vend) = vertices(G); v != vend; ++v, ++vid)
  279. index_vertex_vec[vid] = *v;
  280. index_vertex_map = IndexVertexMap(&index_vertex_vec[0]);
  281. // Initialize degreelists. Degreelists organizes the nodes
  282. // according to their degree.
  283. for (boost::tie(v, vend) = vertices(G); v != vend; ++v) {
  284. put(degree, *v, out_degree(*v, G));
  285. degreelists.push(*v);
  286. }
  287. }
  288. void do_mmd()
  289. {
  290. // Eliminate the isolated nodes -- these are simply the nodes
  291. // with no neighbors, which are accessible as a list (really, a
  292. // stack) at location 0. Since these don't affect any other
  293. // nodes, we can eliminate them without doing degree updates.
  294. typename DegreeLists::stack list_isolated = degreelists[0];
  295. while (!list_isolated.empty()) {
  296. vertex_t node = list_isolated.top();
  297. marker.mark_done(node);
  298. numbering(node);
  299. numbering.increment();
  300. list_isolated.pop();
  301. }
  302. size_type min_degree = 1;
  303. typename DegreeLists::stack list_min_degree = degreelists[min_degree];
  304. while (list_min_degree.empty()) {
  305. ++min_degree;
  306. list_min_degree = degreelists[min_degree];
  307. }
  308. // check if the whole eliminating process is done
  309. while (!numbering.all_done()) {
  310. size_type min_degree_limit = min_degree + delta; // WARNING
  311. typename Workspace::stack llist = work_space.make_stack();
  312. // multiple elimination
  313. while (delta >= 0) {
  314. // Find the next non-empty degree
  315. for (list_min_degree = degreelists[min_degree];
  316. list_min_degree.empty() && min_degree <= min_degree_limit;
  317. ++min_degree, list_min_degree = degreelists[min_degree])
  318. ;
  319. if (min_degree > min_degree_limit)
  320. break;
  321. const vertex_t node = list_min_degree.top();
  322. const size_type node_id = get(vertex_index_map, node);
  323. list_min_degree.pop();
  324. numbering(node);
  325. // check if node is the last one
  326. if (numbering.all_done(supernode_size[node])) {
  327. numbering.increment(supernode_size[node]);
  328. break;
  329. }
  330. marker.increment_tag();
  331. marker.mark_tagged(node);
  332. this->eliminate(node);
  333. numbering.increment(supernode_size[node]);
  334. llist.push(node_id);
  335. } // multiple elimination
  336. if (numbering.all_done())
  337. break;
  338. this->update( llist, min_degree);
  339. }
  340. } // do_mmd()
  341. void eliminate(vertex_t node)
  342. {
  343. typename Workspace::stack element_neighbor = work_space.make_stack();
  344. // Create two function objects for edge removal
  345. typedef typename Workspace::stack WorkStack;
  346. predicateRemoveEdge1<Graph, MarkerP, NumberingD,
  347. WorkStack, VertexIndexMap>
  348. p(G, marker, numbering, element_neighbor, vertex_index_map);
  349. predicate_remove_tagged_edges<Graph, MarkerP> p2(G, marker);
  350. // Reconstruct the adjacent node list, push element neighbor in a List.
  351. remove_out_edge_if(node, p, G);
  352. //during removal element neighbors are collected.
  353. while (!element_neighbor.empty()) {
  354. // element absorb
  355. size_type e_id = element_neighbor.top();
  356. vertex_t element = get(index_vertex_map, e_id);
  357. adj_iter i, i_end;
  358. for (boost::tie(i, i_end) = adjacent_vertices(element, G); i != i_end; ++i){
  359. vertex_t i_node = *i;
  360. if (!marker.is_tagged(i_node) && !numbering.is_numbered(i_node)) {
  361. marker.mark_tagged(i_node);
  362. add_edge(node, i_node, G);
  363. }
  364. }
  365. element_neighbor.pop();
  366. }
  367. adj_iter v, ve;
  368. for (boost::tie(v, ve) = adjacent_vertices(node, G); v != ve; ++v) {
  369. vertex_t v_node = *v;
  370. if (!degree_lists_marker.need_update(v_node)
  371. && !degree_lists_marker.outmatched_or_done(v_node)) {
  372. degreelists.remove(v_node);
  373. }
  374. //update out edges of v_node
  375. remove_out_edge_if(v_node, p2, G);
  376. if ( out_degree(v_node, G) == 0 ) { // indistinguishable nodes
  377. supernode_size[node] += supernode_size[v_node];
  378. supernode_size[v_node] = 0;
  379. numbering.indistinguishable(v_node, node);
  380. marker.mark_done(v_node);
  381. degree_lists_marker.mark(v_node);
  382. } else { // not indistinguishable nodes
  383. add_edge(v_node, node, G);
  384. degree_lists_marker.mark_need_update(v_node);
  385. }
  386. }
  387. } // eliminate()
  388. template <class Stack>
  389. void update(Stack llist, size_type& min_degree)
  390. {
  391. size_type min_degree0 = min_degree + delta + 1;
  392. while (! llist.empty()) {
  393. size_type deg, deg0 = 0;
  394. marker.set_multiple_tag(min_degree0);
  395. typename Workspace::stack q2list = work_space.make_stack();
  396. typename Workspace::stack qxlist = work_space.make_stack();
  397. vertex_t current = get(index_vertex_map, llist.top());
  398. adj_iter i, ie;
  399. for (boost::tie(i,ie) = adjacent_vertices(current, G); i != ie; ++i) {
  400. vertex_t i_node = *i;
  401. const size_type i_id = get(vertex_index_map, i_node);
  402. if (supernode_size[i_node] != 0) {
  403. deg0 += supernode_size[i_node];
  404. marker.mark_multiple_tagged(i_node);
  405. if (degree_lists_marker.need_update(i_node)) {
  406. if (out_degree(i_node, G) == 2)
  407. q2list.push(i_id);
  408. else
  409. qxlist.push(i_id);
  410. }
  411. }
  412. }
  413. while (!q2list.empty()) {
  414. const size_type u_id = q2list.top();
  415. vertex_t u_node = get(index_vertex_map, u_id);
  416. // if u_id is outmatched by others, no need to update degree
  417. if (degree_lists_marker.outmatched_or_done(u_node)) {
  418. q2list.pop();
  419. continue;
  420. }
  421. marker.increment_tag();
  422. deg = deg0;
  423. adj_iter nu = adjacent_vertices(u_node, G).first;
  424. vertex_t neighbor = *nu;
  425. if (neighbor == u_node) {
  426. ++nu;
  427. neighbor = *nu;
  428. }
  429. if (numbering.is_numbered(neighbor)) {
  430. adj_iter i, ie;
  431. for (boost::tie(i,ie) = adjacent_vertices(neighbor, G);
  432. i != ie; ++i) {
  433. const vertex_t i_node = *i;
  434. if (i_node == u_node || supernode_size[i_node] == 0)
  435. continue;
  436. if (marker.is_tagged(i_node)) {
  437. if (degree_lists_marker.need_update(i_node)) {
  438. if ( out_degree(i_node, G) == 2 ) { // is indistinguishable
  439. supernode_size[u_node] += supernode_size[i_node];
  440. supernode_size[i_node] = 0;
  441. numbering.indistinguishable(i_node, u_node);
  442. marker.mark_done(i_node);
  443. degree_lists_marker.mark(i_node);
  444. } else // is outmatched
  445. degree_lists_marker.mark(i_node);
  446. }
  447. } else {
  448. marker.mark_tagged(i_node);
  449. deg += supernode_size[i_node];
  450. }
  451. }
  452. } else
  453. deg += supernode_size[neighbor];
  454. deg -= supernode_size[u_node];
  455. degree[u_node] = deg; //update degree
  456. degreelists[deg].push(u_node);
  457. //u_id has been pushed back into degreelists
  458. degree_lists_marker.unmark(u_node);
  459. if (min_degree > deg)
  460. min_degree = deg;
  461. q2list.pop();
  462. } // while (!q2list.empty())
  463. while (!qxlist.empty()) {
  464. const size_type u_id = qxlist.top();
  465. const vertex_t u_node = get(index_vertex_map, u_id);
  466. // if u_id is outmatched by others, no need to update degree
  467. if (degree_lists_marker.outmatched_or_done(u_node)) {
  468. qxlist.pop();
  469. continue;
  470. }
  471. marker.increment_tag();
  472. deg = deg0;
  473. adj_iter i, ie;
  474. for (boost::tie(i, ie) = adjacent_vertices(u_node, G); i != ie; ++i) {
  475. vertex_t i_node = *i;
  476. if (marker.is_tagged(i_node))
  477. continue;
  478. marker.mark_tagged(i_node);
  479. if (numbering.is_numbered(i_node)) {
  480. adj_iter j, je;
  481. for (boost::tie(j, je) = adjacent_vertices(i_node, G); j != je; ++j) {
  482. const vertex_t j_node = *j;
  483. if (marker.is_not_tagged(j_node)) {
  484. marker.mark_tagged(j_node);
  485. deg += supernode_size[j_node];
  486. }
  487. }
  488. } else
  489. deg += supernode_size[i_node];
  490. } // for adjacent vertices of u_node
  491. deg -= supernode_size[u_node];
  492. degree[u_node] = deg;
  493. degreelists[deg].push(u_node);
  494. // u_id has been pushed back into degreelists
  495. degree_lists_marker.unmark(u_node);
  496. if (min_degree > deg)
  497. min_degree = deg;
  498. qxlist.pop();
  499. } // while (!qxlist.empty()) {
  500. marker.set_tag_as_multiple_tag();
  501. llist.pop();
  502. } // while (! llist.empty())
  503. } // update()
  504. void build_permutation(InversePermutationMap next,
  505. PermutationMap prev)
  506. {
  507. // collect the permutation info
  508. size_type i;
  509. for (i = 0; i < n; ++i) {
  510. diff_t size = supernode_size[get(index_vertex_map, i)];
  511. if ( size <= 0 ) {
  512. prev[i] = next[i];
  513. supernode_size[get(index_vertex_map, i)]
  514. = next[i] + 1; // record the supernode info
  515. } else
  516. prev[i] = - next[i];
  517. }
  518. for (i = 1; i < n + 1; ++i) {
  519. if ( prev[i-1] > 0 )
  520. continue;
  521. diff_t parent = i;
  522. while ( prev[parent - 1] < 0 ) {
  523. parent = - prev[parent - 1];
  524. }
  525. diff_t root = parent;
  526. diff_t num = prev[root - 1] + 1;
  527. next[i-1] = - num;
  528. prev[root-1] = num;
  529. parent = i;
  530. diff_t next_node = - prev[parent - 1];
  531. while (next_node > 0) {
  532. prev[parent-1] = - root;
  533. parent = next_node;
  534. next_node = - prev[parent - 1];
  535. }
  536. }
  537. for (i = 0; i < n; i++) {
  538. diff_t num = - next[i] - 1;
  539. next[i] = num;
  540. prev[num] = i;
  541. }
  542. } // build_permutation()
  543. };
  544. } //namespace detail
  545. // MMD algorithm
  546. //
  547. //The implementation presently includes the enhancements for mass
  548. //elimination, incomplete degree update, multiple elimination, and
  549. //external degree.
  550. //
  551. //Important Note: This implementation requires the BGL graph to be
  552. //directed. Therefore, nonzero entry (i, j) in a symmetrical matrix
  553. //A coresponds to two directed edges (i->j and j->i).
  554. //
  555. //see Alan George and Joseph W. H. Liu, The Evolution of the Minimum
  556. //Degree Ordering Algorithm, SIAM Review, 31, 1989, Page 1-19
  557. template<class Graph, class DegreeMap,
  558. class InversePermutationMap,
  559. class PermutationMap,
  560. class SuperNodeMap, class VertexIndexMap>
  561. void minimum_degree_ordering
  562. (Graph& G,
  563. DegreeMap degree,
  564. InversePermutationMap inverse_perm,
  565. PermutationMap perm,
  566. SuperNodeMap supernode_size,
  567. int delta,
  568. VertexIndexMap vertex_index_map)
  569. {
  570. detail::mmd_impl<Graph,DegreeMap,InversePermutationMap,
  571. PermutationMap, SuperNodeMap, VertexIndexMap>
  572. impl(G, num_vertices(G), delta, degree, inverse_perm,
  573. perm, supernode_size, vertex_index_map);
  574. impl.do_mmd();
  575. impl.build_permutation(inverse_perm, perm);
  576. }
  577. } // namespace boost
  578. #endif // MINIMUM_DEGREE_ORDERING_HPP