/* ========================================================================== */
/* === 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
syntax highlighted by Code2HTML, v. 0.9.1