/* ========================================================================= */1/* === AMD_1 =============================================================== */2/* ========================================================================= */34/* ------------------------------------------------------------------------- */5/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */6/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */7/* email: [email protected] CISE Department, Univ. of Florida. */8/* web: http://www.cise.ufl.edu/research/sparse/amd */9/* ------------------------------------------------------------------------- */1011/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.12*13* The n-by-n sparse matrix A can be unsymmetric. It is stored in MATLAB-style14* compressed-column form, with sorted row indices in each column, and no15* duplicate entries. Diagonal entries may be present, but they are ignored.16* Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].17* Ap [0] must be zero, and nz = Ap [n] is the number of entries in A. The18* size of the matrix, n, must be greater than or equal to zero.19*20* This routine must be preceded by a call to AMD_aat, which computes the21* number of entries in each row/column in A+A', excluding the diagonal.22* Len [j], on input, is the number of entries in row/column j of A+A'. This23* routine constructs the matrix A+A' and then calls AMD_2. No error checking24* is performed (this was done in AMD_aat).25*/2627#include "amd_internal.h"2829GLOBAL void AMD_130(31Int n, /* n > 0 */32const Int Ap [ ], /* input of size n+1, not modified */33const Int Ai [ ], /* input of size nz = Ap [n], not modified */34Int P [ ], /* size n output permutation */35Int Pinv [ ], /* size n output inverse permutation */36Int Len [ ], /* size n input, undefined on output */37Int slen, /* slen >= sum (Len [0..n-1]) + 7n,38* ideally slen = 1.2 * sum (Len) + 8n */39Int S [ ], /* size slen workspace */40double Control [ ], /* input array of size AMD_CONTROL */41double Info [ ] /* output array of size AMD_INFO */42)43{44Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,45*Elen, *Degree, *s, *W, *Sp, *Tp ;4647/* --------------------------------------------------------------------- */48/* construct the matrix for AMD_2 */49/* --------------------------------------------------------------------- */5051ASSERT (n > 0) ;5253iwlen = slen - 6*n ;54s = S ;55Pe = s ; s += n ;56Nv = s ; s += n ;57Head = s ; s += n ;58Elen = s ; s += n ;59Degree = s ; s += n ;60W = s ; s += n ;61Iw = s ; s += iwlen ;6263ASSERT (AMD_valid (n, n, Ap, Ai)) ;6465/* construct the pointers for A+A' */66Sp = Nv ; /* use Nv and W as workspace for Sp and Tp [ */67Tp = W ;68pfree = 0 ;69for (j = 0 ; j < n ; j++)70{71Pe [j] = pfree ;72Sp [j] = pfree ;73pfree += Len [j] ;74}7576/* Note that this restriction on iwlen is slightly more restrictive than77* what is strictly required in AMD_2. AMD_2 can operate with no elbow78* room at all, but it will be very slow. For better performance, at79* least size-n elbow room is enforced. */80ASSERT (iwlen >= pfree + n) ;8182#ifndef NDEBUG83for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;84#endif8586for (k = 0 ; k < n ; k++)87{88AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k)) ;89p1 = Ap [k] ;90p2 = Ap [k+1] ;9192/* construct A+A' */93for (p = p1 ; p < p2 ; )94{95/* scan the upper triangular part of A */96j = Ai [p] ;97ASSERT (j >= 0 && j < n) ;98if (j < k)99{100/* entry A (j,k) in the strictly upper triangular part */101ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;102ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;103Iw [Sp [j]++] = k ;104Iw [Sp [k]++] = j ;105p++ ;106}107else if (j == k)108{109/* skip the diagonal */110p++ ;111break ;112}113else /* j > k */114{115/* first entry below the diagonal */116break ;117}118/* scan lower triangular part of A, in column j until reaching119* row k. Start where last scan left off. */120ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;121pj2 = Ap [j+1] ;122for (pj = Tp [j] ; pj < pj2 ; )123{124i = Ai [pj] ;125ASSERT (i >= 0 && i < n) ;126if (i < k)127{128/* A (i,j) is only in the lower part, not in upper */129ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;130ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;131Iw [Sp [i]++] = j ;132Iw [Sp [j]++] = i ;133pj++ ;134}135else if (i == k)136{137/* entry A (k,j) in lower part and A (j,k) in upper */138pj++ ;139break ;140}141else /* i > k */142{143/* consider this entry later, when k advances to i */144break ;145}146}147Tp [j] = pj ;148}149Tp [k] = p ;150}151152/* clean up, for remaining mismatched entries */153for (j = 0 ; j < n ; j++)154{155for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)156{157i = Ai [pj] ;158ASSERT (i >= 0 && i < n) ;159/* A (i,j) is only in the lower part, not in upper */160ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;161ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;162Iw [Sp [i]++] = j ;163Iw [Sp [j]++] = i ;164}165}166167#ifndef NDEBUG168for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;169ASSERT (Sp [n-1] == pfree) ;170#endif171172/* Tp and Sp no longer needed ] */173174/* --------------------------------------------------------------------- */175/* order the matrix */176/* --------------------------------------------------------------------- */177178AMD_2 (n, Pe, Iw, Len, iwlen, pfree,179Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;180}181182183