Rev 3695 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* ========================================================================= *//* === AMD_1 =============================================================== *//* ========================================================================= *//* ------------------------------------------------------------------------- *//* AMD, Copyright (c) Timothy A. Davis, *//* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. *//* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. *//* web: http://www.cise.ufl.edu/research/sparse/amd *//* ------------------------------------------------------------------------- *//* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.** The n-by-n sparse matrix A can be unsymmetric. It is stored in MATLAB-style* compressed-column form, with sorted row indices in each column, and no* duplicate entries. Diagonal entries may be present, but they are ignored.* Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].* Ap [0] must be zero, and nz = Ap [n] is the number of entries in A. The* size of the matrix, n, must be greater than or equal to zero.** This routine must be preceded by a call to AMD_aat, which computes the* number of entries in each row/column in A+A', excluding the diagonal.* Len [j], on input, is the number of entries in row/column j of A+A'. This* routine constructs the matrix A+A' and then calls AMD_2. No error checking* is performed (this was done in AMD_valid).*/#include "amd_internal.h"GLOBAL void AMD_1(Int n, /* n > 0 */const Int Ap [ ], /* input of size n+1, not modified */const Int Ai [ ], /* input of size nz = Ap [n], not modified */Int P [ ], /* size n output permutation */Int Pinv [ ], /* size n output inverse permutation */Int Len [ ], /* size n input, undefined on output */Int slen, /* slen >= sum (Len [0..n-1]) + 7n,* ideally slen = 1.2 * sum (Len) + 8n */Int S [ ], /* size slen workspace */double Control [ ], /* input array of size AMD_CONTROL */double Info [ ] /* output array of size AMD_INFO */){Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,*Elen, *Degree, *s, *W, *Sp, *Tp ;/* --------------------------------------------------------------------- *//* construct the matrix for AMD_2 *//* --------------------------------------------------------------------- */ASSERT (n > 0) ;iwlen = slen - 6*n ;s = S ;Pe = s ; s += n ;Nv = s ; s += n ;Head = s ; s += n ;Elen = s ; s += n ;Degree = s ; s += n ;W = s ; s += n ;Iw = s ; s += iwlen ;ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;/* construct the pointers for A+A' */Sp = Nv ; /* use Nv and W as workspace for Sp and Tp [ */Tp = W ;pfree = 0 ;for (j = 0 ; j < n ; j++){Pe [j] = pfree ;Sp [j] = pfree ;pfree += Len [j] ;}/* Note that this restriction on iwlen is slightly more restrictive than* what is strictly required in AMD_2. AMD_2 can operate with no elbow* room at all, but it will be very slow. For better performance, at* least size-n elbow room is enforced. */ASSERT (iwlen >= pfree + n) ;#ifndef NDEBUGfor (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;#endiffor (k = 0 ; k < n ; k++){AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k)) ;p1 = Ap [k] ;p2 = Ap [k+1] ;/* construct A+A' */for (p = p1 ; p < p2 ; ){/* scan the upper triangular part of A */j = Ai [p] ;ASSERT (j >= 0 && j < n) ;if (j < k){/* entry A (j,k) in the strictly upper triangular part */ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;Iw [Sp [j]++] = k ;Iw [Sp [k]++] = j ;p++ ;}else if (j == k){/* skip the diagonal */p++ ;break ;}else /* j > k */{/* first entry below the diagonal */break ;}/* scan lower triangular part of A, in column j until reaching* row k. Start where last scan left off. */ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;pj2 = Ap [j+1] ;for (pj = Tp [j] ; pj < pj2 ; ){i = Ai [pj] ;ASSERT (i >= 0 && i < n) ;if (i < k){/* A (i,j) is only in the lower part, not in upper */ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;Iw [Sp [i]++] = j ;Iw [Sp [j]++] = i ;pj++ ;}else if (i == k){/* entry A (k,j) in lower part and A (j,k) in upper */pj++ ;break ;}else /* i > k */{/* consider this entry later, when k advances to i */break ;}}Tp [j] = pj ;}Tp [k] = p ;}/* clean up, for remaining mismatched entries */for (j = 0 ; j < n ; j++){for (pj = Tp [j] ; pj < Ap [j+1] ; pj++){i = Ai [pj] ;ASSERT (i >= 0 && i < n) ;/* A (i,j) is only in the lower part, not in upper */ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;Iw [Sp [i]++] = j ;Iw [Sp [j]++] = i ;}}#ifndef NDEBUGfor (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;ASSERT (Sp [n-1] == pfree) ;#endif/* Tp and Sp no longer needed ] *//* --------------------------------------------------------------------- *//* order the matrix *//* --------------------------------------------------------------------- */AMD_2 (n, Pe, Iw, Len, iwlen, pfree,Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;}