src/amd/amd_1.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

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