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