Blender  V2.59
sp_coletree.c
Go to the documentation of this file.
00001 
00005 /*  Elimination tree computation and layout routines */
00006 
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include "ssp_defs.h"
00010 
00011 /* 
00012  *  Implementation of disjoint set union routines.
00013  *  Elements are integers in 0..n-1, and the 
00014  *  names of the sets themselves are of type int.
00015  *  
00016  *  Calls are:
00017  *  initialize_disjoint_sets (n) initial call.
00018  *  s = make_set (i)             returns a set containing only i.
00019  *  s = link (t, u)              returns s = t union u, destroying t and u.
00020  *  s = find (i)                 return name of set containing i.
00021  *  finalize_disjoint_sets       final call.
00022  *
00023  *  This implementation uses path compression but not weighted union.
00024  *  See Tarjan's book for details.
00025  *  John Gilbert, CMI, 1987.
00026  *
00027  *  Implemented path-halving by XSL 07/05/95.
00028  */
00029 
00030 static int      *pp;            /* parent array for sets */
00031 
00032 static 
00033 int *mxCallocInt(int n)
00034 {
00035     register int i;
00036     int *buf;
00037 
00038     buf = (int *) SUPERLU_MALLOC( n * sizeof(int) );
00039     if ( !buf ) {
00040          ABORT("SUPERLU_MALLOC fails for buf in mxCallocInt()");
00041        }
00042     for (i = 0; i < n; i++) buf[i] = 0;
00043     return (buf);
00044 }
00045       
00046 static
00047 void initialize_disjoint_sets (
00048         int n
00049         )
00050 {
00051         pp = mxCallocInt(n);
00052 }
00053 
00054 
00055 static
00056 int make_set (
00057         int i
00058         )
00059 {
00060         pp[i] = i;
00061         return i;
00062 }
00063 
00064 
00065 static
00066 int link (
00067         int s,
00068         int t
00069         )
00070 {
00071         pp[s] = t;
00072         return t;
00073 }
00074 
00075 
00076 /* PATH HALVING */
00077 static
00078 int find (int i)
00079 {
00080     register int p, gp;
00081     
00082     p = pp[i];
00083     gp = pp[p];
00084     while (gp != p) {
00085         pp[i] = gp;
00086         i = gp;
00087         p = pp[i];
00088         gp = pp[p];
00089     }
00090     return (p);
00091 }
00092 
00093 #if 0
00094 /* PATH COMPRESSION */
00095 static
00096 int find (
00097         int i
00098         )
00099 {
00100         if (pp[i] != i) 
00101                 pp[i] = find (pp[i]);
00102         return pp[i];
00103 }
00104 #endif
00105 
00106 static
00107 void finalize_disjoint_sets (
00108         void
00109         )
00110 {
00111         SUPERLU_FREE(pp);
00112 }
00113 
00114 
00115 /*
00116  *      Find the elimination tree for A'*A.
00117  *      This uses something similar to Liu's algorithm. 
00118  *      It runs in time O(nz(A)*log n) and does not form A'*A.
00119  *
00120  *      Input:
00121  *        Sparse matrix A.  Numeric values are ignored, so any
00122  *        explicit zeros are treated as nonzero.
00123  *      Output:
00124  *        Integer array of parents representing the elimination
00125  *        tree of the symbolic product A'*A.  Each vertex is a
00126  *        column of A, and nc means a root of the elimination forest.
00127  *
00128  *      John R. Gilbert, Xerox, 10 Dec 1990
00129  *      Based on code by JRG dated 1987, 1988, and 1990.
00130  */
00131 
00132 /*
00133  * Nonsymmetric elimination tree
00134  */
00135 int
00136 sp_coletree(
00137             int *acolst, int *acolend, /* column start and end past 1 */
00138             int *arow,                 /* row indices of A */
00139             int nr, int nc,            /* dimension of A */
00140             int *parent                /* parent in elim tree */
00141             )
00142 {
00143         int     *root;                  /* root of subtee of etree      */
00144         int     *firstcol;              /* first nonzero col in each row*/
00145         int     rset, cset;             
00146         int     row, col;
00147         int     rroot;
00148         int     p;
00149 
00150         root = mxCallocInt (nc);
00151         initialize_disjoint_sets (nc);
00152 
00153         /* Compute firstcol[row] = first nonzero column in row */
00154 
00155         firstcol = mxCallocInt (nr);
00156         for (row = 0; row < nr; firstcol[row++] = nc);
00157         for (col = 0; col < nc; col++) 
00158                 for (p = acolst[col]; p < acolend[col]; p++) {
00159                         row = arow[p];
00160                         firstcol[row] = SUPERLU_MIN(firstcol[row], col);
00161                 }
00162 
00163         /* Compute etree by Liu's algorithm for symmetric matrices,
00164            except use (firstcol[r],c) in place of an edge (r,c) of A.
00165            Thus each row clique in A'*A is replaced by a star
00166            centered at its first vertex, which has the same fill. */
00167 
00168         for (col = 0; col < nc; col++) {
00169                 cset = make_set (col);
00170                 root[cset] = col;
00171                 parent[col] = nc; /* Matlab */
00172                 for (p = acolst[col]; p < acolend[col]; p++) {
00173                         row = firstcol[arow[p]];
00174                         if (row >= col) continue;
00175                         rset = find (row);
00176                         rroot = root[rset];
00177                         if (rroot != col) {
00178                                 parent[rroot] = col;
00179                                 cset = link (cset, rset);
00180                                 root[cset] = col;
00181                         }
00182                 }
00183         }
00184 
00185         SUPERLU_FREE (root);
00186         SUPERLU_FREE (firstcol);
00187         finalize_disjoint_sets ();
00188         return 0;
00189 }
00190 
00191 /*
00192  *  q = TreePostorder (n, p);
00193  *
00194  *      Postorder a tree.
00195  *      Input:
00196  *        p is a vector of parent pointers for a forest whose
00197  *        vertices are the integers 0 to n-1; p[root]==n.
00198  *      Output:
00199  *        q is a vector indexed by 0..n-1 such that q[i] is the
00200  *        i-th vertex in a postorder numbering of the tree.
00201  *
00202  *        ( 2/7/95 modified by X.Li:
00203  *          q is a vector indexed by 0:n-1 such that vertex i is the
00204  *          q[i]-th vertex in a postorder numbering of the tree.
00205  *          That is, this is the inverse of the previous q. )
00206  *
00207  *      In the child structure, lower-numbered children are represented
00208  *      first, so that a tree which is already numbered in postorder
00209  *      will not have its order changed.
00210  *    
00211  *  Written by John Gilbert, Xerox, 10 Dec 1990.
00212  *  Based on code written by John Gilbert at CMI in 1987.
00213  */
00214 
00215 static int      *first_kid, *next_kid;  /* Linked list of children.     */
00216 static int      *post, postnum;
00217 
00218 static
00219 /*
00220  * Depth-first search from vertex v.
00221  */
00222 void etdfs (
00223         int     v
00224         )
00225 {
00226         int     w;
00227 
00228         for (w = first_kid[v]; w != -1; w = next_kid[w]) {
00229                 etdfs (w);
00230         }
00231         /* post[postnum++] = v; in Matlab */
00232         post[v] = postnum++;    /* Modified by X.Li on 2/14/95 */
00233 }
00234 
00235 
00236 /*
00237  * Post order a tree
00238  */
00239 int *TreePostorder(
00240         int n,
00241         int *parent
00242 )
00243 {
00244         int     v, dad;
00245 
00246         /* Allocate storage for working arrays and results      */
00247         first_kid =     mxCallocInt (n+1);
00248         next_kid  =     mxCallocInt (n+1);
00249         post      =     mxCallocInt (n+1);
00250 
00251         /* Set up structure describing children */
00252         for (v = 0; v <= n; first_kid[v++] = -1);
00253         for (v = n-1; v >= 0; v--) {
00254                 dad = parent[v];
00255                 next_kid[v] = first_kid[dad];
00256                 first_kid[dad] = v;
00257         }
00258 
00259         /* Depth-first search from dummy root vertex #n */
00260         postnum = 0;
00261         etdfs (n);
00262 
00263         SUPERLU_FREE (first_kid);
00264         SUPERLU_FREE (next_kid);
00265         return post;
00266 }
00267 
00268 
00269 /*
00270  *      p = spsymetree (A);
00271  *
00272  *      Find the elimination tree for symmetric matrix A.
00273  *      This uses Liu's algorithm, and runs in time O(nz*log n).
00274  *
00275  *      Input:
00276  *        Square sparse matrix A.  No check is made for symmetry;
00277  *        elements below and on the diagonal are ignored.
00278  *        Numeric values are ignored, so any explicit zeros are 
00279  *        treated as nonzero.
00280  *      Output:
00281  *        Integer array of parents representing the etree, with n
00282  *        meaning a root of the elimination forest.
00283  *      Note:  
00284  *        This routine uses only the upper triangle, while sparse
00285  *        Cholesky (as in spchol.c) uses only the lower.  Matlab's
00286  *        dense Cholesky uses only the upper.  This routine could
00287  *        be modified to use the lower triangle either by transposing
00288  *        the matrix or by traversing it by rows with auxiliary
00289  *        pointer and link arrays.
00290  *
00291  *      John R. Gilbert, Xerox, 10 Dec 1990
00292  *      Based on code by JRG dated 1987, 1988, and 1990.
00293  *      Modified by X.S. Li, November 1999.
00294  */
00295 
00296 /*
00297  * Symmetric elimination tree
00298  */
00299 int
00300 sp_symetree(
00301             int *acolst, int *acolend, /* column starts and ends past 1 */
00302             int *arow,            /* row indices of A */
00303             int n,                /* dimension of A */
00304             int *parent     /* parent in elim tree */
00305             )
00306 {
00307         int     *root;              /* root of subtree of etree         */
00308         int     rset, cset;             
00309         int     row, col;
00310         int     rroot;
00311         int     p;
00312 
00313         root = mxCallocInt (n);
00314         initialize_disjoint_sets (n);
00315 
00316         for (col = 0; col < n; col++) {
00317                 cset = make_set (col);
00318                 root[cset] = col;
00319                 parent[col] = n; /* Matlab */
00320                 for (p = acolst[col]; p < acolend[col]; p++) {
00321                         row = arow[p];
00322                         if (row >= col) continue;
00323                         rset = find (row);
00324                         rroot = root[rset];
00325                         if (rroot != col) {
00326                                 parent[rroot] = col;
00327                                 cset = link (cset, rset);
00328                                 root[cset] = col;
00329                         }
00330                 }
00331         }
00332         SUPERLU_FREE (root);
00333         finalize_disjoint_sets ();
00334         return 0;
00335 } /* SP_SYMETREE */