src/amd/amd_aat.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
alpar@1
     1
/* ========================================================================= */
alpar@1
     2
/* === AMD_aat ============================================================= */
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_aat:  compute the symmetry of the pattern of A, and count the number of
alpar@1
    13
 * nonzeros each column of A+A' (excluding the diagonal).  Assumes the input
alpar@1
    14
 * matrix has no errors, with sorted columns and no duplicates
alpar@1
    15
 * (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not
alpar@1
    16
 * checked).
alpar@1
    17
 */
alpar@1
    18
alpar@1
    19
#include "amd_internal.h"
alpar@1
    20
alpar@1
    21
GLOBAL size_t AMD_aat   /* returns nz in A+A' */
alpar@1
    22
(
alpar@1
    23
    Int n,
alpar@1
    24
    const Int Ap [ ],
alpar@1
    25
    const Int Ai [ ],
alpar@1
    26
    Int Len [ ],        /* Len [j]: length of column j of A+A', excl diagonal*/
alpar@1
    27
    Int Tp [ ],         /* workspace of size n */
alpar@1
    28
    double Info [ ]
alpar@1
    29
)
alpar@1
    30
{
alpar@1
    31
    Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ;
alpar@1
    32
    double sym ;
alpar@1
    33
    size_t nzaat ;
alpar@1
    34
alpar@1
    35
#ifndef NDEBUG
alpar@1
    36
    AMD_debug_init ("AMD AAT") ;
alpar@1
    37
    for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ;
alpar@1
    38
    ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
alpar@1
    39
#endif
alpar@1
    40
alpar@1
    41
    if (Info != (double *) NULL)
alpar@1
    42
    {
alpar@1
    43
        /* clear the Info array, if it exists */
alpar@1
    44
        for (i = 0 ; i < AMD_INFO ; i++)
alpar@1
    45
        {
alpar@1
    46
            Info [i] = EMPTY ;
alpar@1
    47
        }
alpar@1
    48
        Info [AMD_STATUS] = AMD_OK ;
alpar@1
    49
    }
alpar@1
    50
alpar@1
    51
    for (k = 0 ; k < n ; k++)
alpar@1
    52
    {
alpar@1
    53
        Len [k] = 0 ;
alpar@1
    54
    }
alpar@1
    55
alpar@1
    56
    nzdiag = 0 ;
alpar@1
    57
    nzboth = 0 ;
alpar@1
    58
    nz = Ap [n] ;
alpar@1
    59
alpar@1
    60
    for (k = 0 ; k < n ; k++)
alpar@1
    61
    {
alpar@1
    62
        p1 = Ap [k] ;
alpar@1
    63
        p2 = Ap [k+1] ;
alpar@1
    64
        AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ;
alpar@1
    65
alpar@1
    66
        /* construct A+A' */
alpar@1
    67
        for (p = p1 ; p < p2 ; )
alpar@1
    68
        {
alpar@1
    69
            /* scan the upper triangular part of A */
alpar@1
    70
            j = Ai [p] ;
alpar@1
    71
            if (j < k)
alpar@1
    72
            {
alpar@1
    73
                /* entry A (j,k) is in the strictly upper triangular part,
alpar@1
    74
                 * add both A (j,k) and A (k,j) to the matrix A+A' */
alpar@1
    75
                Len [j]++ ;
alpar@1
    76
                Len [k]++ ;
alpar@1
    77
                AMD_DEBUG3 (("    upper ("ID","ID") ("ID","ID")\n", j,k, k,j));
alpar@1
    78
                p++ ;
alpar@1
    79
            }
alpar@1
    80
            else if (j == k)
alpar@1
    81
            {
alpar@1
    82
                /* skip the diagonal */
alpar@1
    83
                p++ ;
alpar@1
    84
                nzdiag++ ;
alpar@1
    85
                break ;
alpar@1
    86
            }
alpar@1
    87
            else /* j > k */
alpar@1
    88
            {
alpar@1
    89
                /* first entry below the diagonal */
alpar@1
    90
                break ;
alpar@1
    91
            }
alpar@1
    92
            /* scan lower triangular part of A, in column j until reaching
alpar@1
    93
             * row k.  Start where last scan left off. */
alpar@1
    94
            ASSERT (Tp [j] != EMPTY) ;
alpar@1
    95
            ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
alpar@1
    96
            pj2 = Ap [j+1] ;
alpar@1
    97
            for (pj = Tp [j] ; pj < pj2 ; )
alpar@1
    98
            {
alpar@1
    99
                i = Ai [pj] ;
alpar@1
   100
                if (i < k)
alpar@1
   101
                {
alpar@1
   102
                    /* A (i,j) is only in the lower part, not in upper.
alpar@1
   103
                     * add both A (i,j) and A (j,i) to the matrix A+A' */
alpar@1
   104
                    Len [i]++ ;
alpar@1
   105
                    Len [j]++ ;
alpar@1
   106
                    AMD_DEBUG3 (("    lower ("ID","ID") ("ID","ID")\n",
alpar@1
   107
                        i,j, j,i)) ;
alpar@1
   108
                    pj++ ;
alpar@1
   109
                }
alpar@1
   110
                else if (i == k)
alpar@1
   111
                {
alpar@1
   112
                    /* entry A (k,j) in lower part and A (j,k) in upper */
alpar@1
   113
                    pj++ ;
alpar@1
   114
                    nzboth++ ;
alpar@1
   115
                    break ;
alpar@1
   116
                }
alpar@1
   117
                else /* i > k */
alpar@1
   118
                {
alpar@1
   119
                    /* consider this entry later, when k advances to i */
alpar@1
   120
                    break ;
alpar@1
   121
                }
alpar@1
   122
            }
alpar@1
   123
            Tp [j] = pj ;
alpar@1
   124
        }
alpar@1
   125
        /* Tp [k] points to the entry just below the diagonal in column k */
alpar@1
   126
        Tp [k] = p ;
alpar@1
   127
    }
alpar@1
   128
alpar@1
   129
    /* clean up, for remaining mismatched entries */
alpar@1
   130
    for (j = 0 ; j < n ; j++)
alpar@1
   131
    {
alpar@1
   132
        for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
alpar@1
   133
        {
alpar@1
   134
            i = Ai [pj] ;
alpar@1
   135
            /* A (i,j) is only in the lower part, not in upper.
alpar@1
   136
             * add both A (i,j) and A (j,i) to the matrix A+A' */
alpar@1
   137
            Len [i]++ ;
alpar@1
   138
            Len [j]++ ;
alpar@1
   139
            AMD_DEBUG3 (("    lower cleanup ("ID","ID") ("ID","ID")\n",
alpar@1
   140
                i,j, j,i)) ;
alpar@1
   141
        }
alpar@1
   142
    }
alpar@1
   143
alpar@1
   144
    /* --------------------------------------------------------------------- */
alpar@1
   145
    /* compute the symmetry of the nonzero pattern of A */
alpar@1
   146
    /* --------------------------------------------------------------------- */
alpar@1
   147
alpar@1
   148
    /* Given a matrix A, the symmetry of A is:
alpar@1
   149
     *  B = tril (spones (A), -1) + triu (spones (A), 1) ;
alpar@1
   150
     *  sym = nnz (B & B') / nnz (B) ;
alpar@1
   151
     *  or 1 if nnz (B) is zero.
alpar@1
   152
     */
alpar@1
   153
alpar@1
   154
    if (nz == nzdiag)
alpar@1
   155
    {
alpar@1
   156
        sym = 1 ;
alpar@1
   157
    }
alpar@1
   158
    else
alpar@1
   159
    {
alpar@1
   160
        sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ;
alpar@1
   161
    }
alpar@1
   162
alpar@1
   163
    nzaat = 0 ;
alpar@1
   164
    for (k = 0 ; k < n ; k++)
alpar@1
   165
    {
alpar@1
   166
        nzaat += Len [k] ;
alpar@1
   167
    }
alpar@1
   168
alpar@1
   169
    AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n",
alpar@1
   170
        (double) nzaat)) ;
alpar@1
   171
    AMD_DEBUG1 (("   nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n",
alpar@1
   172
                nzboth, nz, nzdiag, sym)) ;
alpar@1
   173
alpar@1
   174
    if (Info != (double *) NULL)
alpar@1
   175
    {
alpar@1
   176
        Info [AMD_STATUS] = AMD_OK ;
alpar@1
   177
        Info [AMD_N] = n ;
alpar@1
   178
        Info [AMD_NZ] = nz ;
alpar@1
   179
        Info [AMD_SYMMETRY] = sym ;         /* symmetry of pattern of A */
alpar@1
   180
        Info [AMD_NZDIAG] = nzdiag ;        /* nonzeros on diagonal of A */
alpar@1
   181
        Info [AMD_NZ_A_PLUS_AT] = nzaat ;   /* nonzeros in A+A' */
alpar@1
   182
    }
alpar@1
   183
alpar@1
   184
    return (nzaat) ;
alpar@1
   185
}