src/amd/amd_1.c
changeset 1 c445c931472f
equal deleted inserted replaced
-1:000000000000 0:0568e2d63581
       
     1 /* ========================================================================= */
       
     2 /* === AMD_1 =============================================================== */
       
     3 /* ========================================================================= */
       
     4 
       
     5 /* ------------------------------------------------------------------------- */
       
     6 /* AMD, Copyright (c) Timothy A. Davis,                                      */
       
     7 /* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
       
     8 /* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
       
     9 /* web: http://www.cise.ufl.edu/research/sparse/amd                          */
       
    10 /* ------------------------------------------------------------------------- */
       
    11 
       
    12 /* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.
       
    13  *
       
    14  * The n-by-n sparse matrix A can be unsymmetric.  It is stored in MATLAB-style
       
    15  * compressed-column form, with sorted row indices in each column, and no
       
    16  * duplicate entries.  Diagonal entries may be present, but they are ignored.
       
    17  * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].
       
    18  * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A.  The
       
    19  * size of the matrix, n, must be greater than or equal to zero.
       
    20  *
       
    21  * This routine must be preceded by a call to AMD_aat, which computes the
       
    22  * number of entries in each row/column in A+A', excluding the diagonal.
       
    23  * Len [j], on input, is the number of entries in row/column j of A+A'.  This
       
    24  * routine constructs the matrix A+A' and then calls AMD_2.  No error checking
       
    25  * is performed (this was done in AMD_valid).
       
    26  */
       
    27 
       
    28 #include "amd_internal.h"
       
    29 
       
    30 GLOBAL void AMD_1
       
    31 (
       
    32     Int n,              /* n > 0 */
       
    33     const Int Ap [ ],   /* input of size n+1, not modified */
       
    34     const Int Ai [ ],   /* input of size nz = Ap [n], not modified */
       
    35     Int P [ ],          /* size n output permutation */
       
    36     Int Pinv [ ],       /* size n output inverse permutation */
       
    37     Int Len [ ],        /* size n input, undefined on output */
       
    38     Int slen,           /* slen >= sum (Len [0..n-1]) + 7n,
       
    39                          * ideally slen = 1.2 * sum (Len) + 8n */
       
    40     Int S [ ],          /* size slen workspace */
       
    41     double Control [ ], /* input array of size AMD_CONTROL */
       
    42     double Info [ ]     /* output array of size AMD_INFO */
       
    43 )
       
    44 {
       
    45     Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,
       
    46         *Elen, *Degree, *s, *W, *Sp, *Tp ;
       
    47 
       
    48     /* --------------------------------------------------------------------- */
       
    49     /* construct the matrix for AMD_2 */
       
    50     /* --------------------------------------------------------------------- */
       
    51 
       
    52     ASSERT (n > 0) ;
       
    53 
       
    54     iwlen = slen - 6*n ;
       
    55     s = S ;
       
    56     Pe = s ;        s += n ;
       
    57     Nv = s ;        s += n ;
       
    58     Head = s ;      s += n ;
       
    59     Elen = s ;      s += n ;
       
    60     Degree = s ;    s += n ;
       
    61     W = s ;         s += n ;
       
    62     Iw = s ;        s += iwlen ;
       
    63 
       
    64     ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
       
    65 
       
    66     /* construct the pointers for A+A' */
       
    67     Sp = Nv ;                   /* use Nv and W as workspace for Sp and Tp [ */
       
    68     Tp = W ;
       
    69     pfree = 0 ;
       
    70     for (j = 0 ; j < n ; j++)
       
    71     {
       
    72         Pe [j] = pfree ;
       
    73         Sp [j] = pfree ;
       
    74         pfree += Len [j] ;
       
    75     }
       
    76 
       
    77     /* Note that this restriction on iwlen is slightly more restrictive than
       
    78      * what is strictly required in AMD_2.  AMD_2 can operate with no elbow
       
    79      * room at all, but it will be very slow.  For better performance, at
       
    80      * least size-n elbow room is enforced. */
       
    81     ASSERT (iwlen >= pfree + n) ;
       
    82 
       
    83 #ifndef NDEBUG
       
    84     for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;
       
    85 #endif
       
    86 
       
    87     for (k = 0 ; k < n ; k++)
       
    88     {
       
    89         AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k))  ;
       
    90         p1 = Ap [k] ;
       
    91         p2 = Ap [k+1] ;
       
    92 
       
    93         /* construct A+A' */
       
    94         for (p = p1 ; p < p2 ; )
       
    95         {
       
    96             /* scan the upper triangular part of A */
       
    97             j = Ai [p] ;
       
    98             ASSERT (j >= 0 && j < n) ;
       
    99             if (j < k)
       
   100             {
       
   101                 /* entry A (j,k) in the strictly upper triangular part */
       
   102                 ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
       
   103                 ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;
       
   104                 Iw [Sp [j]++] = k ;
       
   105                 Iw [Sp [k]++] = j ;
       
   106                 p++ ;
       
   107             }
       
   108             else if (j == k)
       
   109             {
       
   110                 /* skip the diagonal */
       
   111                 p++ ;
       
   112                 break ;
       
   113             }
       
   114             else /* j > k */
       
   115             {
       
   116                 /* first entry below the diagonal */
       
   117                 break ;
       
   118             }
       
   119             /* scan lower triangular part of A, in column j until reaching
       
   120              * row k.  Start where last scan left off. */
       
   121             ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
       
   122             pj2 = Ap [j+1] ;
       
   123             for (pj = Tp [j] ; pj < pj2 ; )
       
   124             {
       
   125                 i = Ai [pj] ;
       
   126                 ASSERT (i >= 0 && i < n) ;
       
   127                 if (i < k)
       
   128                 {
       
   129                     /* A (i,j) is only in the lower part, not in upper */
       
   130                     ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
       
   131                     ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
       
   132                     Iw [Sp [i]++] = j ;
       
   133                     Iw [Sp [j]++] = i ;
       
   134                     pj++ ;
       
   135                 }
       
   136                 else if (i == k)
       
   137                 {
       
   138                     /* entry A (k,j) in lower part and A (j,k) in upper */
       
   139                     pj++ ;
       
   140                     break ;
       
   141                 }
       
   142                 else /* i > k */
       
   143                 {
       
   144                     /* consider this entry later, when k advances to i */
       
   145                     break ;
       
   146                 }
       
   147             }
       
   148             Tp [j] = pj ;
       
   149         }
       
   150         Tp [k] = p ;
       
   151     }
       
   152 
       
   153     /* clean up, for remaining mismatched entries */
       
   154     for (j = 0 ; j < n ; j++)
       
   155     {
       
   156         for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
       
   157         {
       
   158             i = Ai [pj] ;
       
   159             ASSERT (i >= 0 && i < n) ;
       
   160             /* A (i,j) is only in the lower part, not in upper */
       
   161             ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
       
   162             ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
       
   163             Iw [Sp [i]++] = j ;
       
   164             Iw [Sp [j]++] = i ;
       
   165         }
       
   166     }
       
   167 
       
   168 #ifndef NDEBUG
       
   169     for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;
       
   170     ASSERT (Sp [n-1] == pfree) ;
       
   171 #endif
       
   172 
       
   173     /* Tp and Sp no longer needed ] */
       
   174 
       
   175     /* --------------------------------------------------------------------- */
       
   176     /* order the matrix */
       
   177     /* --------------------------------------------------------------------- */
       
   178 
       
   179     AMD_2 (n, Pe, Iw, Len, iwlen, pfree,
       
   180         Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;
       
   181 }