IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Ifpack_IC_Utils.cpp
00001 /*@HEADER
00002 // ***********************************************************************
00003 //
00004 //       Ifpack: Object-Oriented Algebraic Preconditioner Package
00005 //                 Copyright (2002) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 //@HEADER
00041 */
00042 
00043 #include "Ifpack_ConfigDefs.h"
00044 #include "Ifpack_IC_Utils.h"
00045 
00046 #define SYMSTR 1 /* structurally symmetric version */
00047 #include <stdio.h>
00048 
00049 #define MIN(a,b) ((a)<=(b) ? (a) : (b))
00050 #define MAX(a,b) ((a)>=(b) ? (a) : (b))
00051 #define ABS(a) ((a)>=0 ? (a) : -(a))
00052 
00053 #define SHORTCUT(p, a, ja, ia) \
00054         (a)  = (p)->val; \
00055         (ja) = (p)->col; \
00056         (ia) = (p)->ptr;
00057 
00058 #define MATNULL(p) \
00059         (p).val = NULL; \
00060         (p).col = NULL; \
00061         (p).ptr = NULL;
00062 
00063 void Ifpack_AIJMatrix_alloc(Ifpack_AIJMatrix *a, int n, int nnz)
00064 {
00065     a->val = new double[nnz];
00066     a->col = new int[nnz];
00067     a->ptr = new int[n+1];
00068 }
00069  
00070 void Ifpack_AIJMatrix_dealloc(Ifpack_AIJMatrix *a)
00071 {
00072     delete [] (a->val);
00073     delete [] (a->col);
00074     delete [] (a->ptr);
00075     a->val = 0;
00076     a->col = 0;
00077     a->ptr = 0;
00078 }
00079 
00080 static void qsplit(double *a, int *ind, int n, int ncut)
00081 {
00082     double tmp, abskey;
00083     int itmp, first, last, mid;
00084     int j;
00085  
00086     ncut--;
00087     first = 0;
00088     last = n-1;
00089     if (ncut < first || ncut > last) 
00090         return;
00091  
00092     /* outer loop while mid != ncut */
00093     while (1)
00094     {
00095         mid = first;
00096         abskey = ABS(a[mid]);
00097         for (j=first+1; j<=last; j++)
00098         {
00099             if (ABS(a[j]) > abskey)
00100             {
00101                 mid = mid+1;
00102                 /* interchange */
00103                 tmp = a[mid];
00104                 itmp = ind[mid];
00105                 a[mid] = a[j];
00106                 ind[mid] = ind[j];
00107                 a[j]  = tmp;
00108                 ind[j] = itmp;
00109             }
00110         }
00111        
00112         /* interchange */
00113         tmp = a[mid];
00114         a[mid] = a[first];
00115         a[first]  = tmp;
00116         itmp = ind[mid];
00117         ind[mid] = ind[first];
00118         ind[first] = itmp;
00119        
00120         /* test for while loop */
00121         if (mid == ncut) 
00122             return;
00123 
00124         if (mid > ncut)
00125             last = mid-1;
00126         else
00127             first = mid+1;
00128     }
00129 }
00130 
00131 /* update column k using previous columns */
00132 /* assumes that column of A resides in the work vector */
00133 /* this function can also be used to update rows */
00134  
00135 static void update_column(
00136     int k,
00137     const int *ia, const int *ja, const double *a,
00138     const int *ifirst,
00139     const int *ifirst2,
00140     const int *list2,
00141     const double *multipliers, /* the val array of the other factor */
00142     const double *d, /* diagonal of factorization */
00143     int *marker,
00144     double *ta,
00145     int *itcol,
00146     int *ptalen)
00147 {
00148     int j, i, isj, iej, row;
00149     int talen, pos;
00150     double mult;
00151  
00152     talen = *ptalen;
00153 
00154     j = list2[k];
00155     while (j != -1)
00156     {
00157         /* update column k using column j */
00158  
00159         isj = ifirst[j];
00160 
00161         /* skip first nonzero in column, since it does not contribute */
00162         /* if symmetric structure */
00163         /* isj++; */
00164  
00165         /* now do the actual update */
00166        if (isj != -1)
00167        {
00168         /* multiplier */
00169         mult = multipliers[ifirst2[j]] * d[j];
00170 
00171         /* section of column used for update */
00172         iej = ia[j+1]-1;
00173 
00174         for (i=isj; i<=iej; i++)
00175         {
00176             row = ja[i];
00177 
00178             /* if nonsymmetric structure */
00179             if (row <= k)
00180                 continue;
00181  
00182             if ((pos = marker[row]) != -1)
00183             {
00184                 /* already in pattern of working row */
00185                 ta[pos] -= mult*a[i];
00186             }
00187             else
00188             {
00189                 /* not yet in pattern of working row */
00190                 itcol[talen] = row;
00191                 ta[talen] = -mult*a[i];
00192                 marker[row] = talen++;
00193             }
00194         }
00195        }
00196  
00197         j = list2[j];
00198     }
00199 
00200     *ptalen = talen;
00201 }
00202 
00203 /* update ifirst and list */
00204  
00205 static void update_lists(
00206     int k,
00207     const int *ia,
00208     const int *ja,
00209     int *ifirst,
00210     int *list)
00211 {
00212     int j, isj, iej, iptr;
00213 
00214     j = list[k];
00215     while (j != -1)
00216     {
00217         isj = ifirst[j];
00218         iej = ia[j+1]-1;
00219  
00220         isj++;
00221  
00222         if (isj != 0 && isj <= iej) /* nonsymmetric structure */
00223         {
00224             /* increment ifirst for column j */
00225             ifirst[j] = isj;
00226 
00227             /* add j to head of list for list[ja[isj]] */
00228             iptr = j;
00229             j = list[j];
00230             list[iptr] = list[ja[isj]];
00231             list[ja[isj]] = iptr;
00232         }
00233         else
00234         {
00235             j = list[j];
00236         }
00237     }
00238 }
00239 
00240 static void update_lists_newcol(
00241     int k,
00242     int isk,
00243     int iptr,
00244     int *ifirst,
00245     int *list)
00246 {
00247     ifirst[k] = isk;
00248     list[k] = list[iptr];
00249     list[iptr] = k;
00250 }
00251 
00252 /*
00253  * crout_ict - Crout version of ICT - Incomplete Cholesky by Threshold
00254  *
00255  * The incomplete factorization L D L^T is computed,
00256  * where L is unit triangular, and D is diagonal
00257  *
00258  * INPUTS
00259  * n = number of rows or columns of the matrices
00260  * AL = unit lower triangular part of A stored by columns
00261  *            the unit diagonal is implied (not stored)
00262  * Adiag = diagonal part of A
00263  * droptol = drop tolerance
00264  * lfil  = max nonzeros per col in L factor or per row in U factor
00265  *   TODO: lfil should rather be a fill ratio applied to each column
00266  *
00267  * OUTPUTS
00268  * L     = lower triangular factor stored by columns
00269  * pdiag = diagonal factor stored in an array
00270  *
00271  * NOTE: calling function must free the memory allocated by this
00272  * function, i.e., L, pdiag.
00273  */
00274 
00275 void crout_ict(
00276     int n,
00277 #ifdef IFPACK
00278     void * A,
00279     int maxentries;
00280     int (*getcol)( void * A, int col, int ** nentries, double * val, int * ind),
00281     int (*getdiag)( void *A, double * diag),
00282 #else
00283     const Ifpack_AIJMatrix *AL,
00284     const double *Adiag,
00285 #endif
00286     double droptol,
00287     int lfil,
00288     Ifpack_AIJMatrix *L,
00289     double **pdiag)
00290 {
00291     int k, j, i, index;
00292     int count_l;
00293     double norm_l;
00294 
00295     /* work arrays; work_l is list of nonzero values */
00296     double *work_l = new double[n];
00297     int    *ind_l  = new int[n];
00298     int     len_l;
00299 
00300     /* list and ifirst data structures */
00301     int *list_l    = new int[n];
00302     int *ifirst_l  = new int[n];
00303     
00304     /* aliases */
00305     int *marker_l  = ifirst_l;
00306 
00307     /* matrix arrays */
00308     double *al; int *jal, *ial;
00309     double *l;  int *jl,  *il;
00310 
00311     int kl = 0;
00312 
00313     double *diag = new double[n];
00314     *pdiag = diag;
00315 
00316     Ifpack_AIJMatrix_alloc(L,  n, lfil*n);
00317 
00318     SHORTCUT(AL, al, jal, ial);
00319     SHORTCUT(L,  l,  jl,  il);
00320 
00321     /* initialize work arrays */
00322     for (i=0; i<n; i++)
00323     {
00324         list_l[i]    = -1;
00325         ifirst_l[i]  = -1;
00326         marker_l[i]  = -1;
00327     }
00328 
00329     /* copy the diagonal */
00330 #ifdef IFPACK
00331     getdiag(A, diag);
00332 #else
00333     for (i=0; i<n; i++)
00334         diag[i] = Adiag[i];
00335 #endif
00336 
00337     /* start off the matrices right */
00338     il[0]  = 0;
00339 
00340     /*
00341      * Main loop over columns and rows
00342      */
00343 
00344     for (k=0; k<n; k++)
00345     {
00346         /*
00347          * lower triangular factor update by columns
00348          * (need ifirst for L and lists for U)
00349          */
00350  
00351         /* copy column of A into work vector */
00352         norm_l = 0.;
00353 #ifdef IFPACK
00354       getcol(A, k, len_l, work_l, ind_l);
00355       for (j=0; j<len_l; j++)
00356     {
00357       norm_l += ABS(work_l[j]);
00358       marker_l[ind_l[j]] = j;
00359     }
00360 #else
00361         len_l = 0;
00362         for (j=ial[k]; j<ial[k+1]; j++)
00363         {
00364             index = jal[j];
00365             work_l[len_l] = al[j];
00366             norm_l += ABS(al[j]);
00367             ind_l[len_l] = index;
00368             marker_l[index] = len_l++; /* points into work array */
00369         }
00370 #endif
00371         norm_l = (len_l == 0) ? 0.0 : norm_l/((double) len_l);
00372  
00373         /* update and scale */
00374 
00375         update_column(k, il, jl, l, ifirst_l, ifirst_l, list_l, l,
00376             diag, marker_l, work_l, ind_l, &len_l);
00377 
00378         for (j=0; j<len_l; j++)
00379             work_l[j] /= diag[k];
00380 
00381     i = 0;
00382         for (j=0; j<len_l; j++)
00383     {
00384         if (ABS(work_l[j]) < droptol * norm_l)
00385         {
00386             /* zero out marker array for this */
00387         marker_l[ind_l[j]] = -1;
00388         }
00389         else
00390         {
00391             work_l[i] = work_l[j];
00392         ind_l[i]  = ind_l[j];
00393         i++;
00394         }
00395     }
00396     len_l = i;
00397 
00398     /*
00399      * dropping:  for each work vector, perform qsplit, and then
00400      * sort each part by increasing index; then copy each sorted
00401      * part into the factors
00402      */
00403 
00404         // TODO: keep different #nonzeros per column depending on original matrix
00405     count_l = MIN(len_l, lfil);
00406     qsplit(work_l, ind_l, len_l, count_l);
00407     ifpack_multilist_sort(ind_l, work_l, count_l);
00408 
00409     for (j=0; j<count_l; j++)
00410     {
00411         l[kl] = work_l[j];
00412         jl[kl++] = ind_l[j];
00413     }
00414     il[k+1] = kl;
00415 
00416     /*
00417      * update lists
00418      */
00419     
00420         update_lists(k, il, jl, ifirst_l, list_l);
00421 
00422     if (kl - il[k] > SYMSTR)
00423         update_lists_newcol(k, il[k], jl[il[k]], ifirst_l, list_l);
00424 
00425         /* zero out the marker arrays */
00426         for (j=0; j<len_l; j++)
00427             marker_l[ind_l[j]] = -1;
00428 
00429         /*
00430          * update the diagonal (after dropping)
00431          */
00432 
00433         for (j=0; j<count_l; j++)
00434         {
00435             index = ind_l[j];
00436             diag[index] -= work_l[j] * work_l[j] * diag[k];
00437         }
00438     }
00439 
00440     delete [] work_l;
00441     delete [] ind_l;
00442     delete [] list_l;
00443     delete [] ifirst_l;
00444 }
 All Classes Files Functions Variables Enumerations Friends