minimum_degree_ordering.w
来自「Boost provides free peer-reviewed portab」· W 代码 · 共 319 行
W
319 行
\documentclass[11pt]{report}\input{defs}\setlength\overfullrule{5pt}\tolerance=10000\sloppy\hfuzz=10pt\makeindex\begin{document}\title{An Implementation of the Multiple Minimum Degree Algorithm}\author{Jeremy G. Siek and Lie Quan Lee}\maketitle\section{Introduction}The minimum degree ordering algorithm \cite{LIU:MMD,George:evolution}reorders a matrix to reduce fill-in. Fill-in is the term used to referto the zero elements of a matrix that become non-zero during thegaussian elimination process. Fill-in is bad because it makes thematrix less sparse and therefore consume more time and space in laterstages of the elimintation and in computations that use the resultingfactorization. Reordering the rows of a matrix can have a dramaticaffect on the amount of fill-in that occurs. So instead of solving\begin{eqnarray}A x = b\end{eqnarray}we instead solve the reordered (but equivalent) system\begin{eqnarray}(P A P^T)(P x) = P b.\end{eqnarray}where $P$ is a permutation matrix.Finding the optimal ordering is an NP-complete problem (e.i., it cannot be solved in a reasonable amount of time) so instead we just findan ordering that is ``good enough'' using heuristics. The minimumdegree ordering algorithm is one such approach.A symmetric matrix $A$ is typically represented with an undirectedgraph, however for this function we require the input to be a directedgraph. Each nonzero matrix entry $A_{ij}$ must be represented by twodirected edges, $(i,j)$ and $(j,i)$, in $G$.An \keyword{elimination graph} $G_v$ is formed by removing vertex $v$and all of its incident edges from graph $G$ and then adding edges tomake the vertices adjacent to $v$ into a clique\footnote{A clique is acomplete subgraph. That is, it is a subgraph where each vertex isadjacent to every other vertex in the subgraph}.quotient graph set of cliques in the graphMass elmination: if $y$ is selected as the minimum degree node thenthe the vertices adjacent to $y$ with degree equal to $degree(y) - 1$can be selected next (in any order).Two nodes are \keyword{indistinguishable} if they have identicalneighborhood sets. That is,\begin{eqnarray}Adj[u] \cup \{ u \} = Adj[v] \bigcup \{ v \}\end{eqnarray}Nodes that are indistiguishable can be eliminated at the same time.A representative for a set of indistiguishable nodes is called a\keyword{supernode}.incomplete degree updateexternal degree\section{Algorithm Overview}@d MMD Algorithm Overview @{ @<Eliminate isolated nodes@> @}@d Set up a mapping from integers to vertices @{size_type vid = 0;typename graph_traits<Graph>::vertex_iterator v, vend;for (tie(v, vend) = vertices(G); v != vend; ++v, ++vid) index_vertex_vec[vid] = *v;index_vertex_map = IndexVertexMap(&index_vertex_vec[0]);@}@d Insert vertices into bucket sorter (bucket number equals degree) @{for (tie(v, vend) = vertices(G); v != vend; ++v) { put(degree, *v, out_degree(*v, G)); degreelists.push(*v);}@}@d Eliminate isolated nodes (nodes with zero degree) @{typename DegreeLists::stack list_isolated = degreelists[0];while (!list_isolated.empty()) { vertex_t node = list_isolated.top(); marker.mark_done(node); numbering(node); numbering.increment(); list_isolated.pop();}@}@d Find first non-empty degree bucket@{size_type min_degree = 1;typename DegreeLists::stack list_min_degree = degreelists[min_degree];while (list_min_degree.empty()) { ++min_degree; list_min_degree = degreelists[min_degree];}@}@d Main Loop@{while (!numbering.all_done()) { eliminated_nodes = work_space.make_stack(); if (delta >= 0) while (true) { @<Find next non-empty degree bucket@> @<Select a node of minimum degree for elimination@> eliminate(node); } if (numbering.all_done()) break; update(eliminated_nodes, min_degree);}@}@d Elimination Function@{void eliminate(vertex_t node){ remove out-edges from the node if the target vertex was tagged or if it is numbered add vertices adjacent to node to the clique put all numbered adjacent vertices into the temporary neighbors stack @<Perform element absorption optimization@>}@}@d@{bool remove_out_edges_predicate::operator()(edge_t e){ vertex_t v = target(e, *g); bool is_tagged = marker->is_tagged(dist); bool is_numbered = numbering.is_numbered(v); if (is_numbered) neighbors->push(id[v]); if (!is_tagged) marker->mark_tagged(v); return is_tagged || is_numbered;}@}How does this work????Does \code{is\_tagged} mean in the clique??@d Perform element absorption optimization@{while (!neighbors.empty()) { size_type n_id = neighbors.top(); vertex_t neighbor = index_vertex_map[n_id]; adjacency_iterator i, i_end; for (tie(i, i_end) = adjacent_vertices(neighbor, G); i != i_end; ++i) { vertex_t i_node = *i; if (!marker.is_tagged(i_node) && !numbering.is_numbered(i_node)) { marker.mark_tagged(i_node); add_edge(node, i_node, G); } } neighbors.pop();}@}@d@{predicateRemoveEdge1<Graph, MarkerP, NumberingD, typename Workspace::stack, VertexIndexMap> p(G, marker, numbering, element_neighbor, vertex_index_map);remove_out_edge_if(node, p, G);@}\section{The Interface}@d Interface of the MMD function @{template<class Graph, class DegreeMap, class InversePermutationMap, class PermutationMap, class SuperNodeMap, class VertexIndexMap>void minimum_degree_ordering (Graph& G, DegreeMap degree, InversePermutationMap inverse_perm, PermutationMap perm, SuperNodeMap supernode_size, int delta, VertexIndexMap vertex_index_map)@}\section{Representing Disjoint Stacks}Given a set of $N$ integers (where the integer values range from zeroto $N-1$), we want to keep track of a collection of stacks ofintegers. It so happens that an integer will appear in at most onestack at a time, so the stacks form disjoint sets. Because of theserestrictions, we can use one big array to store all the stacks,intertwined with one another. No allocation/deallocation happens inthe \code{push()}/\code{pop()} methods so this is faster than using\code{std::stack}.\section{Bucket Sorting}@d Bucket Sorter Class Interface @{template <typename BucketMap, typename ValueIndexMap>class bucket_sorter {public: typedef typename property_traits<BucketMap>::value_type bucket_type; typedef typename property_traits<ValueIndex>::key_type value_type; typedef typename property_traits<ValueIndex>::value_type size_type; bucket_sorter(size_type length, bucket_type max_bucket, const BucketMap& bucket = BucketMap(), const ValueIndexMap& index_map = ValueIndexMap()); void remove(const value_type& x); void push(const value_type& x); void update(const value_type& x); class stack { public: void push(const value_type& x); void pop(); value_type& top(); const value_type& top() const; bool empty() const; private: @<Bucket Stack Constructor@> @<Bucket Stack Data Members@> }; stack operator[](const bucket_type& i);private: @<Bucket Sorter Data Members@>};@}\code{BucketMap} is a \concept{LvaluePropertyMap} that converts avalue object to a bucket number (an integer). The range of the mappingmust be finite. \code{ValueIndexMap} is a \concept{LvaluePropertyMap}that maps from value objects to a unique integer. At the top of thedefinition of \code{bucket\_sorter} we create some typedefs for thebucket number type, the value type, and the index type.@d Bucket Sorter Data Members @{std::vector<size_type> head;std::vector<size_type> next;std::vector<size_type> prev;std::vector<value_type> id_to_value;BucketMap bucket_map;ValueIndexMap index_map;@}\code{N} is the maximum integer that the \code{index\_map} will map avalue object to (the minimum is assumed to be zero).@d Bucket Sorter Constructor @{bucket_sorter::bucket_sorter (size_type N, bucket_type max_bucket, const BucketMap& bucket_map = BucketMap(), const ValueIndexMap& index_map = ValueIndexMap()) : head(max_bucket, invalid_value()), next(N, invalid_value()), prev(N, invalid_value()), id_to_value(N), bucket_map(bucket_map), index_map(index_map) { }@}\bibliographystyle{abbrv}\bibliography{jtran,ggcl,optimization,generic-programming,cad}\end{document}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?