Rev 4428 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* ========================================================================== *//* === Cholesky/cholmod_postorder =========================================== *//* ========================================================================== *//* -----------------------------------------------------------------------------* CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis* The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU* Lesser General Public License. See lesser.txt for a text of the license.* CHOLMOD is also available under other licenses; contact authors for details.* http://www.cise.ufl.edu/research/sparse* -------------------------------------------------------------------------- *//* Compute the postorder of a tree. */#ifndef NCHOLESKY#include "cholmod_internal.h"#include "cholmod_cholesky.h"/* ========================================================================== *//* === dfs ================================================================== *//* ========================================================================== *//* The code below includes both a recursive and non-recursive depth-first-search* of a tree. The recursive code is simpler, but can lead to stack overflow.* It is left here for reference, to understand what the non-recursive code* is computing. To try the recursive version, uncomment the following* #define, or compile the code with -DRECURSIVE. Be aware that stack* overflow may occur.#define RECURSIVE*/#ifdef RECURSIVE/* recursive version: a working code for reference only, not actual use */static Int dfs /* return the new value of k */(Int p, /* start a DFS at node p */Int k, /* start the node numbering at k */Int Post [ ], /* Post ordering, modified on output */Int Head [ ], /* Head [p] = youngest child of p; EMPTY on output */Int Next [ ], /* Next [j] = sibling of j; unmodified */Int Pstack [ ] /* unused */){Int j ;/* start a DFS at each child of node p */for (j = Head [p] ; j != EMPTY ; j = Next [j]){/* start a DFS at child node j */k = dfs (j, k, Post, Head, Next, Pstack) ;}Post [k++] = p ; /* order node p as the kth node */Head [p] = EMPTY ; /* link list p no longer needed */return (k) ; /* the next node will be numbered k */}#else/* non-recursive version for actual use */static Int dfs /* return the new value of k */(Int p, /* start the DFS at a root node p */Int k, /* start the node numbering at k */Int Post [ ], /* Post ordering, modified on output */Int Head [ ], /* Head [p] = youngest child of p; EMPTY on output */Int Next [ ], /* Next [j] = sibling of j; unmodified */Int Pstack [ ] /* workspace of size n, undefined on input or output */){Int j, phead ;/* put the root node on the stack */Pstack [0] = p ;phead = 0 ;/* while the stack is not empty, do: */while (phead >= 0){/* grab the node p from top of the stack and get its youngest child j */p = Pstack [phead] ;j = Head [p] ;if (j == EMPTY){/* all children of p ordered. remove p from stack and order it */phead-- ;Post [k++] = p ; /* order node p as the kth node */}else{/* leave p on the stack. Start a DFS at child node j by putting* j on the stack and removing j from the list of children of p. */Head [p] = Next [j] ;Pstack [++phead] = j ;}}return (k) ; /* the next node will be numbered k */}#endif/* ========================================================================== *//* === cholmod_postorder ==================================================== *//* ========================================================================== *//* Postorder a tree. The tree is either an elimination tree (the output from* from cholmod_etree) or a component tree (from cholmod_nested_dissection).** An elimination tree is a complete tree of n nodes with Parent [j] > j or* Parent [j] = EMPTY if j is a root. On output Post [0..n-1] is a complete* permutation vector.** A component tree is a subset of 0..n-1. Parent [j] = -2 if node j is not* in the component tree. Parent [j] = EMPTY if j is a root of the component* tree, and Parent [j] is in the range 0 to n-1 if j is in the component* tree but not a root. On output, Post [k] is defined only for nodes in* the component tree. Post [k] = j if node j is the kth node in the* postordered component tree, where k is in the range 0 to the number of* components minus 1.** Node j is ignored and not included in the postorder if Parent [j] < EMPTY.** As a result, check_parent (Parent, n,...) may fail on input, since* cholmod_check_parent assumes Parent is an elimination tree. Similarly,* cholmod_check_perm (Post, ...) may fail on output, since Post is a partial* permutation if Parent is a component tree.** An optional node weight can be given. When starting a postorder at node j,* the children of j are ordered in decreasing order of their weight.* If no weights are given (Weight is NULL) then children are ordered in* decreasing order of their node number. The weight of a node must be in the* range 0 to n-1. Weights outside that range are silently converted to that* range (weights < 0 are treated as zero, and weights >= n are treated as n-1).*** workspace: Head (n), Iwork (2*n)*/UF_long CHOLMOD(postorder) /* return # of nodes postordered */(/* ---- input ---- */Int *Parent, /* size n. Parent [j] = p if p is the parent of j */size_t n,Int *Weight, /* size n, optional. Weight [j] is weight of node j *//* ---- output --- */Int *Post, /* size n. Post [k] = j is kth in postordered tree *//* --------------- */cholmod_common *Common){Int *Head, *Next, *Pstack, *Iwork ;Int j, p, k, w, nextj ;size_t s ;int ok = TRUE ;/* ---------------------------------------------------------------------- *//* check inputs *//* ---------------------------------------------------------------------- */RETURN_IF_NULL_COMMON (EMPTY) ;RETURN_IF_NULL (Parent, EMPTY) ;RETURN_IF_NULL (Post, EMPTY) ;Common->status = CHOLMOD_OK ;/* ---------------------------------------------------------------------- *//* allocate workspace *//* ---------------------------------------------------------------------- *//* s = 2*n */s = CHOLMOD(mult_size_t) (n, 2, &ok) ;if (!ok){ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;return (EMPTY) ;}CHOLMOD(allocate_work) (n, s, 0, Common) ;if (Common->status < CHOLMOD_OK){return (EMPTY) ;}ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;/* ---------------------------------------------------------------------- *//* get inputs *//* ---------------------------------------------------------------------- */Head = Common->Head ; /* size n+1, initially all EMPTY */Iwork = Common->Iwork ;Next = Iwork ; /* size n (i/i/l) */Pstack = Iwork + n ; /* size n (i/i/l) *//* ---------------------------------------------------------------------- *//* construct a link list of children for each node *//* ---------------------------------------------------------------------- */if (Weight == NULL){/* in reverse order so children are in ascending order in each list */for (j = n-1 ; j >= 0 ; j--){p = Parent [j] ;if (p >= 0 && p < ((Int) n)){/* add j to the list of children for node p */Next [j] = Head [p] ;Head [p] = j ;}}/* Head [p] = j if j is the youngest (least-numbered) child of p *//* Next [j1] = j2 if j2 is the next-oldest sibling of j1 */}else{/* First, construct a set of link lists according to Weight.** Whead [w] = j if node j is the first node in bucket w.* Next [j1] = j2 if node j2 follows j1 in a link list.*/Int *Whead = Pstack ; /* use Pstack as workspace for Whead [ */for (w = 0 ; w < ((Int) n) ; w++){Whead [w] = EMPTY ;}/* do in forward order, so nodes that ties are ordered by node index */for (j = 0 ; j < ((Int) n) ; j++){p = Parent [j] ;if (p >= 0 && p < ((Int) n)){w = Weight [j] ;w = MAX (0, w) ;w = MIN (w, ((Int) n) - 1) ;/* place node j at the head of link list for weight w */Next [j] = Whead [w] ;Whead [w] = j ;}}/* traverse weight buckets, placing each node in its parent's list */for (w = n-1 ; w >= 0 ; w--){for (j = Whead [w] ; j != EMPTY ; j = nextj){nextj = Next [j] ;/* put node j in the link list of its parent */p = Parent [j] ;ASSERT (p >= 0 && p < ((Int) n)) ;Next [j] = Head [p] ;Head [p] = j ;}}/* Whead no longer needed ] *//* Head [p] = j if j is the lightest child of p *//* Next [j1] = j2 if j2 is the next-heaviest sibling of j1 */}/* ---------------------------------------------------------------------- *//* start a DFS at each root node of the etree *//* ---------------------------------------------------------------------- */k = 0 ;for (j = 0 ; j < ((Int) n) ; j++){if (Parent [j] == EMPTY){/* j is the root of a tree; start a DFS here */k = dfs (j, k, Post, Head, Next, Pstack) ;}}/* this would normally be EMPTY already, unless Parent is invalid */for (j = 0 ; j < ((Int) n) ; j++){Head [j] = EMPTY ;}PRINT1 (("postordered "ID" nodes\n", k)) ;ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;return (k) ;}#endif