kusano 7d535a
/*! @file sp_coletree.c
kusano 7d535a
 * \brief Tree layout and computation routines
kusano 7d535a
 *
kusano 7d535a
 *
kusano 7d535a
 * -- SuperLU routine (version 3.1) --
kusano 7d535a
 * Univ. of California Berkeley, Xerox Palo Alto Research Center,
kusano 7d535a
 * and Lawrence Berkeley National Lab.
kusano 7d535a
 * August 1, 2008
kusano 7d535a
 *
kusano 7d535a
 * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
kusano 7d535a
 *
kusano 7d535a
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
kusano 7d535a
 * EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
kusano 7d535a
 *
kusano 7d535a
 * Permission is hereby granted to use or copy this program for any
kusano 7d535a
 * purpose, provided the above notices are retained on all copies.
kusano 7d535a
 * Permission to modify the code and to distribute modified code is
kusano 7d535a
 * granted, provided the above notices are retained, and a notice that
kusano 7d535a
 * the code was modified is included with the above copyright notice.
kusano 7d535a
 * 
kusano 7d535a
*/
kusano 7d535a
kusano 7d535a
/*  Elimination tree computation and layout routines */
kusano 7d535a
kusano 7d535a
#include <stdio.h></stdio.h>
kusano 7d535a
#include <stdlib.h></stdlib.h>
kusano 7d535a
#include "slu_ddefs.h"
kusano 7d535a
kusano 7d535a
/* 
kusano 7d535a
 *  Implementation of disjoint set union routines.
kusano 7d535a
 *  Elements are integers in 0..n-1, and the 
kusano 7d535a
 *  names of the sets themselves are of type int.
kusano 7d535a
 *  
kusano 7d535a
 *  Calls are:
kusano 7d535a
 *  initialize_disjoint_sets (n) initial call.
kusano 7d535a
 *  s = make_set (i)             returns a set containing only i.
kusano 7d535a
 *  s = link (t, u)		 returns s = t union u, destroying t and u.
kusano 7d535a
 *  s = find (i)		 return name of set containing i.
kusano 7d535a
 *  finalize_disjoint_sets 	 final call.
kusano 7d535a
 *
kusano 7d535a
 *  This implementation uses path compression but not weighted union.
kusano 7d535a
 *  See Tarjan's book for details.
kusano 7d535a
 *  John Gilbert, CMI, 1987.
kusano 7d535a
 *
kusano 7d535a
 *  Implemented path-halving by XSL 07/05/95.
kusano 7d535a
 */
kusano 7d535a
kusano 7d535a
kusano 7d535a
static 
kusano 7d535a
int *mxCallocInt(int n)
kusano 7d535a
{
kusano 7d535a
    register int i;
kusano 7d535a
    int *buf;
kusano 7d535a
kusano 7d535a
    buf = (int *) SUPERLU_MALLOC( n * sizeof(int) );
kusano 7d535a
    if ( !buf ) {
kusano 7d535a
         ABORT("SUPERLU_MALLOC fails for buf in mxCallocInt()");
kusano 7d535a
       }
kusano 7d535a
    for (i = 0; i < n; i++) buf[i] = 0;
kusano 7d535a
    return (buf);
kusano 7d535a
}
kusano 7d535a
      
kusano 7d535a
static
kusano 7d535a
void initialize_disjoint_sets (
kusano 7d535a
			       int n,
kusano 7d535a
			       int **pp
kusano 7d535a
			       )
kusano 7d535a
{
kusano 7d535a
	(*pp) = mxCallocInt(n);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
static
kusano 7d535a
int make_set (
kusano 7d535a
	      int i,
kusano 7d535a
	      int *pp
kusano 7d535a
	      )
kusano 7d535a
{
kusano 7d535a
	pp[i] = i;
kusano 7d535a
	return i;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
static
kusano 7d535a
int link (
kusano 7d535a
	  int s,
kusano 7d535a
	  int t,
kusano 7d535a
	  int *pp
kusano 7d535a
	  )
kusano 7d535a
{
kusano 7d535a
	pp[s] = t;
kusano 7d535a
	return t;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
/* PATH HALVING */
kusano 7d535a
static
kusano 7d535a
int find (
kusano 7d535a
	  int i,
kusano 7d535a
	  int *pp
kusano 7d535a
	  )
kusano 7d535a
{
kusano 7d535a
    register int p, gp;
kusano 7d535a
    
kusano 7d535a
    p = pp[i];
kusano 7d535a
    gp = pp[p];
kusano 7d535a
    while (gp != p) {
kusano 7d535a
	pp[i] = gp;
kusano 7d535a
	i = gp;
kusano 7d535a
	p = pp[i];
kusano 7d535a
	gp = pp[p];
kusano 7d535a
    }
kusano 7d535a
    return (p);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
#if 0
kusano 7d535a
/* PATH COMPRESSION */
kusano 7d535a
static
kusano 7d535a
int find (
kusano 7d535a
	int i
kusano 7d535a
	)
kusano 7d535a
{
kusano 7d535a
	if (pp[i] != i) 
kusano 7d535a
		pp[i] = find (pp[i]);
kusano 7d535a
	return pp[i];
kusano 7d535a
}
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
static
kusano 7d535a
void finalize_disjoint_sets (
kusano 7d535a
			     int *pp
kusano 7d535a
			     )
kusano 7d535a
{
kusano 7d535a
	SUPERLU_FREE(pp);
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
/*
kusano 7d535a
 *      Find the elimination tree for A'*A.
kusano 7d535a
 *      This uses something similar to Liu's algorithm. 
kusano 7d535a
 *      It runs in time O(nz(A)*log n) and does not form A'*A.
kusano 7d535a
 *
kusano 7d535a
 *      Input:
kusano 7d535a
 *        Sparse matrix A.  Numeric values are ignored, so any
kusano 7d535a
 *        explicit zeros are treated as nonzero.
kusano 7d535a
 *      Output:
kusano 7d535a
 *        Integer array of parents representing the elimination
kusano 7d535a
 *        tree of the symbolic product A'*A.  Each vertex is a
kusano 7d535a
 *        column of A, and nc means a root of the elimination forest.
kusano 7d535a
 *
kusano 7d535a
 *      John R. Gilbert, Xerox, 10 Dec 1990
kusano 7d535a
 *      Based on code by JRG dated 1987, 1988, and 1990.
kusano 7d535a
 */
kusano 7d535a
kusano 7d535a
/*
kusano 7d535a
 * Nonsymmetric elimination tree
kusano 7d535a
 */
kusano 7d535a
int
kusano 7d535a
sp_coletree(
kusano 7d535a
	    int *acolst, int *acolend, /* column start and end past 1 */
kusano 7d535a
	    int *arow,                 /* row indices of A */
kusano 7d535a
	    int nr, int nc,            /* dimension of A */
kusano 7d535a
	    int *parent	               /* parent in elim tree */
kusano 7d535a
	    )
kusano 7d535a
{
kusano 7d535a
	int	*root;			/* root of subtee of etree 	*/
kusano 7d535a
	int     *firstcol;		/* first nonzero col in each row*/
kusano 7d535a
	int	rset, cset;             
kusano 7d535a
	int	row, col;
kusano 7d535a
	int	rroot;
kusano 7d535a
	int	p;
kusano 7d535a
	int     *pp;
kusano 7d535a
kusano 7d535a
	root = mxCallocInt (nc);
kusano 7d535a
	initialize_disjoint_sets (nc, &pp);
kusano 7d535a
kusano 7d535a
	/* Compute firstcol[row] = first nonzero column in row */
kusano 7d535a
kusano 7d535a
	firstcol = mxCallocInt (nr);
kusano 7d535a
	for (row = 0; row < nr; firstcol[row++] = nc);
kusano 7d535a
	for (col = 0; col < nc; col++) 
kusano 7d535a
		for (p = acolst[col]; p < acolend[col]; p++) {
kusano 7d535a
			row = arow[p];
kusano 7d535a
			firstcol[row] = SUPERLU_MIN(firstcol[row], col);
kusano 7d535a
		}
kusano 7d535a
kusano 7d535a
	/* Compute etree by Liu's algorithm for symmetric matrices,
kusano 7d535a
           except use (firstcol[r],c) in place of an edge (r,c) of A.
kusano 7d535a
	   Thus each row clique in A'*A is replaced by a star
kusano 7d535a
	   centered at its first vertex, which has the same fill. */
kusano 7d535a
kusano 7d535a
	for (col = 0; col < nc; col++) {
kusano 7d535a
		cset = make_set (col, pp);
kusano 7d535a
		root[cset] = col;
kusano 7d535a
		parent[col] = nc; /* Matlab */
kusano 7d535a
		for (p = acolst[col]; p < acolend[col]; p++) {
kusano 7d535a
			row = firstcol[arow[p]];
kusano 7d535a
			if (row >= col) continue;
kusano 7d535a
			rset = find (row, pp);
kusano 7d535a
			rroot = root[rset];
kusano 7d535a
			if (rroot != col) {
kusano 7d535a
				parent[rroot] = col;
kusano 7d535a
				cset = link (cset, rset, pp);
kusano 7d535a
				root[cset] = col;
kusano 7d535a
			}
kusano 7d535a
		}
kusano 7d535a
	}
kusano 7d535a
kusano 7d535a
	SUPERLU_FREE (root);
kusano 7d535a
	SUPERLU_FREE (firstcol);
kusano 7d535a
	finalize_disjoint_sets (pp);
kusano 7d535a
	return 0;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
/*
kusano 7d535a
 *  q = TreePostorder (n, p);
kusano 7d535a
 *
kusano 7d535a
 *	Postorder a tree.
kusano 7d535a
 *	Input:
kusano 7d535a
 *	  p is a vector of parent pointers for a forest whose
kusano 7d535a
 *        vertices are the integers 0 to n-1; p[root]==n.
kusano 7d535a
 *	Output:
kusano 7d535a
 *	  q is a vector indexed by 0..n-1 such that q[i] is the
kusano 7d535a
 *	  i-th vertex in a postorder numbering of the tree.
kusano 7d535a
 *
kusano 7d535a
 *        ( 2/7/95 modified by X.Li:
kusano 7d535a
 *          q is a vector indexed by 0:n-1 such that vertex i is the
kusano 7d535a
 *          q[i]-th vertex in a postorder numbering of the tree.
kusano 7d535a
 *          That is, this is the inverse of the previous q. )
kusano 7d535a
 *
kusano 7d535a
 *	In the child structure, lower-numbered children are represented
kusano 7d535a
 *	first, so that a tree which is already numbered in postorder
kusano 7d535a
 *	will not have its order changed.
kusano 7d535a
 *    
kusano 7d535a
 *  Written by John Gilbert, Xerox, 10 Dec 1990.
kusano 7d535a
 *  Based on code written by John Gilbert at CMI in 1987.
kusano 7d535a
 */
kusano 7d535a
kusano 7d535a
static
kusano 7d535a
/*
kusano 7d535a
 * Depth-first search from vertex v.
kusano 7d535a
 */
kusano 7d535a
void etdfs (
kusano 7d535a
	    int	  v,
kusano 7d535a
	    int   first_kid[],
kusano 7d535a
	    int   next_kid[],
kusano 7d535a
	    int   post[], 
kusano 7d535a
	    int   *postnum
kusano 7d535a
	    )
kusano 7d535a
{
kusano 7d535a
	int	w;
kusano 7d535a
kusano 7d535a
	for (w = first_kid[v]; w != -1; w = next_kid[w]) {
kusano 7d535a
		etdfs (w, first_kid, next_kid, post, postnum);
kusano 7d535a
	}
kusano 7d535a
	/* post[postnum++] = v; in Matlab */
kusano 7d535a
	post[v] = (*postnum)++;    /* Modified by X. Li on 08/10/07 */
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
static
kusano 7d535a
/*
kusano 7d535a
 * Depth-first search from vertex n.  No recursion.
kusano 7d535a
 * This routine was contributed by CĂŠdric Doucet, CEDRAT Group, Meylan, France.
kusano 7d535a
 */
kusano 7d535a
void nr_etdfs (int n, int *parent,
kusano 7d535a
	       int *first_kid, int *next_kid,
kusano 7d535a
	       int *post, int postnum)
kusano 7d535a
{
kusano 7d535a
    int current = n, first, next;
kusano 7d535a
kusano 7d535a
    while (postnum != n){
kusano 7d535a
     
kusano 7d535a
        /* no kid for the current node */
kusano 7d535a
        first = first_kid[current];
kusano 7d535a
kusano 7d535a
        /* no first kid for the current node */
kusano 7d535a
        if (first == -1){
kusano 7d535a
kusano 7d535a
            /* numbering this node because it has no kid */
kusano 7d535a
            post[current] = postnum++;
kusano 7d535a
kusano 7d535a
            /* looking for the next kid */
kusano 7d535a
            next = next_kid[current];
kusano 7d535a
kusano 7d535a
            while (next == -1){
kusano 7d535a
kusano 7d535a
                /* no more kids : back to the parent node */
kusano 7d535a
                current = parent[current];
kusano 7d535a
kusano 7d535a
                /* numbering the parent node */
kusano 7d535a
                post[current] = postnum++;
kusano 7d535a
kusano 7d535a
                /* get the next kid */
kusano 7d535a
                next = next_kid[current];
kusano 7d535a
	    }
kusano 7d535a
            
kusano 7d535a
            /* stopping criterion */
kusano 7d535a
            if (postnum==n+1) return;
kusano 7d535a
kusano 7d535a
            /* updating current node */
kusano 7d535a
            current = next;
kusano 7d535a
        }
kusano 7d535a
        /* updating current node */
kusano 7d535a
        else {
kusano 7d535a
            current = first;
kusano 7d535a
	}
kusano 7d535a
    }
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
/*
kusano 7d535a
 * Post order a tree
kusano 7d535a
 */
kusano 7d535a
int *TreePostorder(
kusano 7d535a
		   int n,
kusano 7d535a
		   int *parent
kusano 7d535a
		   )
kusano 7d535a
{
kusano 7d535a
        int	*first_kid, *next_kid;	/* Linked list of children.	*/
kusano 7d535a
        int	*post, postnum;
kusano 7d535a
	int	v, dad;
kusano 7d535a
kusano 7d535a
	/* Allocate storage for working arrays and results	*/
kusano 7d535a
	first_kid = 	mxCallocInt (n+1);
kusano 7d535a
	next_kid  = 	mxCallocInt (n+1);
kusano 7d535a
	post	  = 	mxCallocInt (n+1);
kusano 7d535a
kusano 7d535a
	/* Set up structure describing children */
kusano 7d535a
	for (v = 0; v <= n; first_kid[v++] = -1);
kusano 7d535a
	for (v = n-1; v >= 0; v--) {
kusano 7d535a
		dad = parent[v];
kusano 7d535a
		next_kid[v] = first_kid[dad];
kusano 7d535a
		first_kid[dad] = v;
kusano 7d535a
	}
kusano 7d535a
kusano 7d535a
	/* Depth-first search from dummy root vertex #n */
kusano 7d535a
	postnum = 0;
kusano 7d535a
#if 0
kusano 7d535a
	/* recursion */
kusano 7d535a
	etdfs (n, first_kid, next_kid, post, &postnum);
kusano 7d535a
#else
kusano 7d535a
	/* no recursion */
kusano 7d535a
	nr_etdfs(n, parent, first_kid, next_kid, post, postnum);
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
	SUPERLU_FREE (first_kid);
kusano 7d535a
	SUPERLU_FREE (next_kid);
kusano 7d535a
	return post;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
kusano 7d535a
/*
kusano 7d535a
 *      p = spsymetree (A);
kusano 7d535a
 *
kusano 7d535a
 *      Find the elimination tree for symmetric matrix A.
kusano 7d535a
 *      This uses Liu's algorithm, and runs in time O(nz*log n).
kusano 7d535a
 *
kusano 7d535a
 *      Input:
kusano 7d535a
 *        Square sparse matrix A.  No check is made for symmetry;
kusano 7d535a
 *        elements below and on the diagonal are ignored.
kusano 7d535a
 *        Numeric values are ignored, so any explicit zeros are 
kusano 7d535a
 *        treated as nonzero.
kusano 7d535a
 *      Output:
kusano 7d535a
 *        Integer array of parents representing the etree, with n
kusano 7d535a
 *        meaning a root of the elimination forest.
kusano 7d535a
 *      Note:  
kusano 7d535a
 *        This routine uses only the upper triangle, while sparse
kusano 7d535a
 *        Cholesky (as in spchol.c) uses only the lower.  Matlab's
kusano 7d535a
 *        dense Cholesky uses only the upper.  This routine could
kusano 7d535a
 *        be modified to use the lower triangle either by transposing
kusano 7d535a
 *        the matrix or by traversing it by rows with auxiliary
kusano 7d535a
 *        pointer and link arrays.
kusano 7d535a
 *
kusano 7d535a
 *      John R. Gilbert, Xerox, 10 Dec 1990
kusano 7d535a
 *      Based on code by JRG dated 1987, 1988, and 1990.
kusano 7d535a
 *      Modified by X.S. Li, November 1999.
kusano 7d535a
 */
kusano 7d535a
kusano 7d535a
/*
kusano 7d535a
 * Symmetric elimination tree
kusano 7d535a
 */
kusano 7d535a
int
kusano 7d535a
sp_symetree(
kusano 7d535a
	    int *acolst, int *acolend, /* column starts and ends past 1 */
kusano 7d535a
	    int *arow,            /* row indices of A */
kusano 7d535a
	    int n,                /* dimension of A */
kusano 7d535a
	    int *parent	    /* parent in elim tree */
kusano 7d535a
	    )
kusano 7d535a
{
kusano 7d535a
	int	*root;		    /* root of subtree of etree 	*/
kusano 7d535a
	int	rset, cset;             
kusano 7d535a
	int	row, col;
kusano 7d535a
	int	rroot;
kusano 7d535a
	int	p;
kusano 7d535a
	int     *pp;
kusano 7d535a
kusano 7d535a
	root = mxCallocInt (n);
kusano 7d535a
	initialize_disjoint_sets (n, &pp);
kusano 7d535a
kusano 7d535a
	for (col = 0; col < n; col++) {
kusano 7d535a
		cset = make_set (col, pp);
kusano 7d535a
		root[cset] = col;
kusano 7d535a
		parent[col] = n; /* Matlab */
kusano 7d535a
		for (p = acolst[col]; p < acolend[col]; p++) {
kusano 7d535a
			row = arow[p];
kusano 7d535a
			if (row >= col) continue;
kusano 7d535a
			rset = find (row, pp);
kusano 7d535a
			rroot = root[rset];
kusano 7d535a
			if (rroot != col) {
kusano 7d535a
				parent[rroot] = col;
kusano 7d535a
				cset = link (cset, rset, pp);
kusano 7d535a
				root[cset] = col;
kusano 7d535a
			}
kusano 7d535a
		}
kusano 7d535a
	}
kusano 7d535a
	SUPERLU_FREE (root);
kusano 7d535a
	finalize_disjoint_sets (pp);
kusano 7d535a
	return 0;
kusano 7d535a
} /* SP_SYMETREE */