minimum_degree_ordering.w 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. \documentclass[11pt]{report}
  2. \input{defs}
  3. \setlength\overfullrule{5pt}
  4. \tolerance=10000
  5. \sloppy
  6. \hfuzz=10pt
  7. \makeindex
  8. \begin{document}
  9. \title{An Implementation of the Multiple Minimum Degree Algorithm}
  10. \author{Jeremy G. Siek and Lie Quan Lee}
  11. \maketitle
  12. \section{Introduction}
  13. The minimum degree ordering algorithm \cite{LIU:MMD,George:evolution}
  14. reorders a matrix to reduce fill-in. Fill-in is the term used to refer
  15. to the zero elements of a matrix that become non-zero during the
  16. gaussian elimination process. Fill-in is bad because it makes the
  17. matrix less sparse and therefore consume more time and space in later
  18. stages of the elimintation and in computations that use the resulting
  19. factorization. Reordering the rows of a matrix can have a dramatic
  20. affect on the amount of fill-in that occurs. So instead of solving
  21. \begin{eqnarray}
  22. A x = b
  23. \end{eqnarray}
  24. we instead solve the reordered (but equivalent) system
  25. \begin{eqnarray}
  26. (P A P^T)(P x) = P b.
  27. \end{eqnarray}
  28. where $P$ is a permutation matrix.
  29. Finding the optimal ordering is an NP-complete problem (e.i., it can
  30. not be solved in a reasonable amount of time) so instead we just find
  31. an ordering that is ``good enough'' using heuristics. The minimum
  32. degree ordering algorithm is one such approach.
  33. A symmetric matrix $A$ is typically represented with an undirected
  34. graph, however for this function we require the input to be a directed
  35. graph. Each nonzero matrix entry $A_{ij}$ must be represented by two
  36. directed edges, $(i,j)$ and $(j,i)$, in $G$.
  37. An \keyword{elimination graph} $G_v$ is formed by removing vertex $v$
  38. and all of its incident edges from graph $G$ and then adding edges to
  39. make the vertices adjacent to $v$ into a clique\footnote{A clique is a
  40. complete subgraph. That is, it is a subgraph where each vertex is
  41. adjacent to every other vertex in the subgraph}.
  42. quotient graph
  43. set of cliques in the graph
  44. Mass elmination: if $y$ is selected as the minimum degree node then
  45. the the vertices adjacent to $y$ with degree equal to $degree(y) - 1$
  46. can be selected next (in any order).
  47. Two nodes are \keyword{indistinguishable} if they have identical
  48. neighborhood sets. That is,
  49. \begin{eqnarray}
  50. Adj[u] \cup \{ u \} = Adj[v] \bigcup \{ v \}
  51. \end{eqnarray}
  52. Nodes that are indistiguishable can be eliminated at the same time.
  53. A representative for a set of indistiguishable nodes is called a
  54. \keyword{supernode}.
  55. incomplete degree update
  56. external degree
  57. \section{Algorithm Overview}
  58. @d MMD Algorithm Overview @{
  59. @<Eliminate isolated nodes@>
  60. @}
  61. @d Set up a mapping from integers to vertices @{
  62. size_type vid = 0;
  63. typename graph_traits<Graph>::vertex_iterator v, vend;
  64. for (tie(v, vend) = vertices(G); v != vend; ++v, ++vid)
  65. index_vertex_vec[vid] = *v;
  66. index_vertex_map = IndexVertexMap(&index_vertex_vec[0]);
  67. @}
  68. @d Insert vertices into bucket sorter (bucket number equals degree) @{
  69. for (tie(v, vend) = vertices(G); v != vend; ++v) {
  70. put(degree, *v, out_degree(*v, G));
  71. degreelists.push(*v);
  72. }
  73. @}
  74. @d Eliminate isolated nodes (nodes with zero degree) @{
  75. typename DegreeLists::stack list_isolated = degreelists[0];
  76. while (!list_isolated.empty()) {
  77. vertex_t node = list_isolated.top();
  78. marker.mark_done(node);
  79. numbering(node);
  80. numbering.increment();
  81. list_isolated.pop();
  82. }
  83. @}
  84. @d Find first non-empty degree bucket
  85. @{
  86. size_type min_degree = 1;
  87. typename DegreeLists::stack list_min_degree = degreelists[min_degree];
  88. while (list_min_degree.empty()) {
  89. ++min_degree;
  90. list_min_degree = degreelists[min_degree];
  91. }
  92. @}
  93. @d Main Loop
  94. @{
  95. while (!numbering.all_done()) {
  96. eliminated_nodes = work_space.make_stack();
  97. if (delta >= 0)
  98. while (true) {
  99. @<Find next non-empty degree bucket@>
  100. @<Select a node of minimum degree for elimination@>
  101. eliminate(node);
  102. }
  103. if (numbering.all_done())
  104. break;
  105. update(eliminated_nodes, min_degree);
  106. }
  107. @}
  108. @d Elimination Function
  109. @{
  110. void eliminate(vertex_t node)
  111. {
  112. remove out-edges from the node if the target vertex was
  113. tagged or if it is numbered
  114. add vertices adjacent to node to the clique
  115. put all numbered adjacent vertices into the temporary neighbors stack
  116. @<Perform element absorption optimization@>
  117. }
  118. @}
  119. @d
  120. @{
  121. bool remove_out_edges_predicate::operator()(edge_t e)
  122. {
  123. vertex_t v = target(e, *g);
  124. bool is_tagged = marker->is_tagged(dist);
  125. bool is_numbered = numbering.is_numbered(v);
  126. if (is_numbered)
  127. neighbors->push(id[v]);
  128. if (!is_tagged)
  129. marker->mark_tagged(v);
  130. return is_tagged || is_numbered;
  131. }
  132. @}
  133. How does this work????
  134. Does \code{is\_tagged} mean in the clique??
  135. @d Perform element absorption optimization
  136. @{
  137. while (!neighbors.empty()) {
  138. size_type n_id = neighbors.top();
  139. vertex_t neighbor = index_vertex_map[n_id];
  140. adjacency_iterator i, i_end;
  141. for (tie(i, i_end) = adjacent_vertices(neighbor, G); i != i_end; ++i) {
  142. vertex_t i_node = *i;
  143. if (!marker.is_tagged(i_node) && !numbering.is_numbered(i_node)) {
  144. marker.mark_tagged(i_node);
  145. add_edge(node, i_node, G);
  146. }
  147. }
  148. neighbors.pop();
  149. }
  150. @}
  151. @d
  152. @{
  153. predicateRemoveEdge1<Graph, MarkerP, NumberingD,
  154. typename Workspace::stack, VertexIndexMap>
  155. p(G, marker, numbering, element_neighbor, vertex_index_map);
  156. remove_out_edge_if(node, p, G);
  157. @}
  158. \section{The Interface}
  159. @d Interface of the MMD function @{
  160. template<class Graph, class DegreeMap,
  161. class InversePermutationMap,
  162. class PermutationMap,
  163. class SuperNodeMap, class VertexIndexMap>
  164. void minimum_degree_ordering
  165. (Graph& G,
  166. DegreeMap degree,
  167. InversePermutationMap inverse_perm,
  168. PermutationMap perm,
  169. SuperNodeMap supernode_size,
  170. int delta,
  171. VertexIndexMap vertex_index_map)
  172. @}
  173. \section{Representing Disjoint Stacks}
  174. Given a set of $N$ integers (where the integer values range from zero
  175. to $N-1$), we want to keep track of a collection of stacks of
  176. integers. It so happens that an integer will appear in at most one
  177. stack at a time, so the stacks form disjoint sets. Because of these
  178. restrictions, we can use one big array to store all the stacks,
  179. intertwined with one another. No allocation/deallocation happens in
  180. the \code{push()}/\code{pop()} methods so this is faster than using
  181. \code{std::stack}.
  182. \section{Bucket Sorting}
  183. @d Bucket Sorter Class Interface @{
  184. template <typename BucketMap, typename ValueIndexMap>
  185. class bucket_sorter {
  186. public:
  187. typedef typename property_traits<BucketMap>::value_type bucket_type;
  188. typedef typename property_traits<ValueIndex>::key_type value_type;
  189. typedef typename property_traits<ValueIndex>::value_type size_type;
  190. bucket_sorter(size_type length, bucket_type max_bucket,
  191. const BucketMap& bucket = BucketMap(),
  192. const ValueIndexMap& index_map = ValueIndexMap());
  193. void remove(const value_type& x);
  194. void push(const value_type& x);
  195. void update(const value_type& x);
  196. class stack {
  197. public:
  198. void push(const value_type& x);
  199. void pop();
  200. value_type& top();
  201. const value_type& top() const;
  202. bool empty() const;
  203. private:
  204. @<Bucket Stack Constructor@>
  205. @<Bucket Stack Data Members@>
  206. };
  207. stack operator[](const bucket_type& i);
  208. private:
  209. @<Bucket Sorter Data Members@>
  210. };
  211. @}
  212. \code{BucketMap} is a \concept{LvaluePropertyMap} that converts a
  213. value object to a bucket number (an integer). The range of the mapping
  214. must be finite. \code{ValueIndexMap} is a \concept{LvaluePropertyMap}
  215. that maps from value objects to a unique integer. At the top of the
  216. definition of \code{bucket\_sorter} we create some typedefs for the
  217. bucket number type, the value type, and the index type.
  218. @d Bucket Sorter Data Members @{
  219. std::vector<size_type> head;
  220. std::vector<size_type> next;
  221. std::vector<size_type> prev;
  222. std::vector<value_type> id_to_value;
  223. BucketMap bucket_map;
  224. ValueIndexMap index_map;
  225. @}
  226. \code{N} is the maximum integer that the \code{index\_map} will map a
  227. value object to (the minimum is assumed to be zero).
  228. @d Bucket Sorter Constructor @{
  229. bucket_sorter::bucket_sorter
  230. (size_type N, bucket_type max_bucket,
  231. const BucketMap& bucket_map = BucketMap(),
  232. const ValueIndexMap& index_map = ValueIndexMap())
  233. : head(max_bucket, invalid_value()),
  234. next(N, invalid_value()),
  235. prev(N, invalid_value()),
  236. id_to_value(N),
  237. bucket_map(bucket_map), index_map(index_map) { }
  238. @}
  239. \bibliographystyle{abbrv}
  240. \bibliography{jtran,ggcl,optimization,generic-programming,cad}
  241. \end{document}