xref: /petsc/src/mat/utils/zerodiag.c (revision 67b8a455b8687dfb2f87ed52b249206f831b8117)
1be1d678aSKris Buschelman 
2ad608de0SBarry Smith /*
3ad608de0SBarry Smith     This file contains routines to reorder a matrix so that the diagonal
448b35521SBarry Smith     elements are nonzero.
5ad608de0SBarry Smith  */
6ad608de0SBarry Smith 
7af0996ceSBarry Smith #include <petsc/private/matimpl.h>       /*I  "petscmat.h"  I*/
8ad608de0SBarry Smith 
938baddfdSBarry Smith #define SWAP(a,b) {PetscInt _t; _t = a; a = b; b = _t; }
1048b35521SBarry Smith 
11ad608de0SBarry Smith /*@
1248b35521SBarry Smith     MatReorderForNonzeroDiagonal - Changes matrix ordering to remove
1348b35521SBarry Smith     zeros from diagonal. This may help in the LU factorization to
1448b35521SBarry Smith     prevent a zero pivot.
15ad608de0SBarry Smith 
16fee21e36SBarry Smith     Collective on Mat
17fee21e36SBarry Smith 
1898a79cdbSBarry Smith     Input Parameters:
1998a79cdbSBarry Smith +   mat  - matrix to reorder
2098a79cdbSBarry Smith -   rmap,cmap - row and column permutations.  Usually obtained from
2191e9ee9fSBarry Smith                MatGetOrdering().
2298a79cdbSBarry Smith 
2315091d37SBarry Smith     Level: intermediate
2415091d37SBarry Smith 
25ad608de0SBarry Smith     Notes:
26ad608de0SBarry Smith     This is not intended as a replacement for pivoting for matrices that
27d252947aSBarry Smith     have ``bad'' structure. It is only a stop-gap measure. Should be called
2891e9ee9fSBarry Smith     after a call to MatGetOrdering(), this routine changes the column
29d252947aSBarry Smith     ordering defined in cis.
30d252947aSBarry Smith 
31106f7b34SBarry Smith     Only works for SeqAIJ matrices
32106f7b34SBarry Smith 
3394b7f48cSBarry Smith     Options Database Keys (When using KSP):
34*67b8a455SSatish Balay .      -pc_factor_nonzeros_along_diagonal - Reorder to remove zeros from diagonal
35ad608de0SBarry Smith 
3633f51a72SBarry Smith     Algorithm Notes:
3733f51a72SBarry Smith     Column pivoting is used.
3833f51a72SBarry Smith 
3933f51a72SBarry Smith     1) Choice of column is made by looking at the
4033f51a72SBarry Smith        non-zero elements in the troublesome row for columns that are not yet
4133f51a72SBarry Smith        included (moving from left to right).
4233f51a72SBarry Smith 
4333f51a72SBarry Smith     2) If (1) fails we check all the columns to the left of the current row
44814823dcSBarry Smith        and see if one of them has could be swapped. It can be swapped if
45814823dcSBarry Smith        its corresponding row has a non-zero in the column it is being
46814823dcSBarry Smith        swapped with; to make sure the previous nonzero diagonal remains
47814823dcSBarry Smith        nonzero
4833f51a72SBarry Smith 
49ad608de0SBarry Smith @*/
507087cfbeSBarry Smith PetscErrorCode  MatReorderForNonzeroDiagonal(Mat mat,PetscReal abstol,IS ris,IS cis)
51ad608de0SBarry Smith {
524ac538c5SBarry Smith   PetscErrorCode ierr;
5305b94e36SKris Buschelman 
5405b94e36SKris Buschelman   PetscFunctionBegin;
554ac538c5SBarry Smith   ierr = PetscTryMethod(mat,"MatReorderForNonzeroDiagonal_C",(Mat,PetscReal,IS,IS),(mat,abstol,ris,cis));CHKERRQ(ierr);
5605b94e36SKris Buschelman   PetscFunctionReturn(0);
5705b94e36SKris Buschelman }
5805b94e36SKris Buschelman 
595a576424SJed Brown PETSC_INTERN PetscErrorCode MatGetRow_SeqAIJ(Mat,PetscInt,PetscInt*,PetscInt**,PetscScalar**);
605a576424SJed Brown PETSC_INTERN PetscErrorCode MatRestoreRow_SeqAIJ(Mat,PetscInt,PetscInt*,PetscInt**,PetscScalar**);
61b3cc6726SBarry Smith 
62d9e81513SBarry Smith #include <../src/vec/is/is/impls/general/general.h>
635d0c19d7SBarry Smith 
64d8fa6a54SBarry Smith PETSC_INTERN PetscErrorCode  MatReorderForNonzeroDiagonal_SeqAIJ(Mat mat,PetscReal abstol,IS ris,IS cis)
6505b94e36SKris Buschelman {
66dfbe8321SBarry Smith   PetscErrorCode ierr;
6738baddfdSBarry Smith   PetscInt       prow,k,nz,n,repl,*j,*col,*row,m,*icol,nnz,*jj,kk;
6887828ca2SBarry Smith   PetscScalar    *v,*vv;
69329f5518SBarry Smith   PetscReal      repla;
70fd61f322SBarry Smith   IS             icis;
71ad608de0SBarry Smith 
723a40ed3dSBarry Smith   PetscFunctionBegin;
735d0c19d7SBarry Smith   /* access the indices of the IS directly, because it changes them */
745d0c19d7SBarry Smith   row  = ((IS_General*)ris->data)->idx;
755d0c19d7SBarry Smith   col  = ((IS_General*)cis->data)->idx;
764c49b128SBarry Smith   ierr = ISInvertPermutation(cis,PETSC_DECIDE,&icis);CHKERRQ(ierr);
775d0c19d7SBarry Smith   icol = ((IS_General*)icis->data)->idx;
7848b35521SBarry Smith   ierr = MatGetSize(mat,&m,&n);CHKERRQ(ierr);
79ad608de0SBarry Smith 
80ad608de0SBarry Smith   for (prow=0; prow<n; prow++) {
81b3cc6726SBarry Smith     ierr = MatGetRow_SeqAIJ(mat,row[prow],&nz,&j,&v);CHKERRQ(ierr);
828865f1eaSKarl Rupp     for (k=0; k<nz; k++) {
838865f1eaSKarl Rupp       if (icol[j[k]] == prow) break;
848865f1eaSKarl Rupp     }
8570441072SBarry Smith     if (k >= nz || PetscAbsScalar(v[k]) <= abstol) {
86ad608de0SBarry Smith       /* Element too small or zero; find the best candidate */
87cddf8d76SBarry Smith       repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]);
88d4bb536fSBarry Smith       /*
89fd61f322SBarry Smith           Look for a later column we can swap with this one
90d4bb536fSBarry Smith       */
9148b35521SBarry Smith       for (k=0; k<nz; k++) {
9233f51a72SBarry Smith         if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) {
93fd61f322SBarry Smith           /* found a suitable later column */
9433f51a72SBarry Smith           repl = icol[j[k]];
9533f51a72SBarry Smith           SWAP(icol[col[prow]],icol[col[repl]]);
96ad608de0SBarry Smith           SWAP(col[prow],col[repl]);
97fd61f322SBarry Smith           goto found;
98fd61f322SBarry Smith         }
99fd61f322SBarry Smith       }
100fd61f322SBarry Smith       /*
101fd61f322SBarry Smith            Did not find a suitable later column so look for an earlier column
102fd61f322SBarry Smith            We need to be sure that we don't introduce a zero in a previous
103fd61f322SBarry Smith            diagonal
104fd61f322SBarry Smith       */
105fd61f322SBarry Smith       for (k=0; k<nz; k++) {
106fd61f322SBarry Smith         if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) {
107fd61f322SBarry Smith           /* See if this one will work */
108fd61f322SBarry Smith           repl = icol[j[k]];
109b3cc6726SBarry Smith           ierr = MatGetRow_SeqAIJ(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr);
110fd61f322SBarry Smith           for (kk=0; kk<nnz; kk++) {
11170441072SBarry Smith             if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > abstol) {
112b3cc6726SBarry Smith               ierr = MatRestoreRow_SeqAIJ(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr);
113fd61f322SBarry Smith               SWAP(icol[col[prow]],icol[col[repl]]);
114fd61f322SBarry Smith               SWAP(col[prow],col[repl]);
115fd61f322SBarry Smith               goto found;
116fd61f322SBarry Smith             }
117fd61f322SBarry Smith           }
118b3cc6726SBarry Smith           ierr = MatRestoreRow_SeqAIJ(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr);
119fd61f322SBarry Smith         }
120fd61f322SBarry Smith       }
121fd61f322SBarry Smith       /*
122fd61f322SBarry Smith           No column  suitable; instead check all future rows
123fd61f322SBarry Smith           Note: this will be very slow
124fd61f322SBarry Smith       */
125fd61f322SBarry Smith       for (k=prow+1; k<n; k++) {
126b3cc6726SBarry Smith         ierr = MatGetRow_SeqAIJ(mat,row[k],&nnz,&jj,&vv);CHKERRQ(ierr);
127fd61f322SBarry Smith         for (kk=0; kk<nnz; kk++) {
12870441072SBarry Smith           if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > abstol) {
129fd61f322SBarry Smith             /* found a row */
130fd61f322SBarry Smith             SWAP(row[prow],row[k]);
131fd61f322SBarry Smith             goto found;
132fd61f322SBarry Smith           }
133fd61f322SBarry Smith         }
134b3cc6726SBarry Smith         ierr = MatRestoreRow_SeqAIJ(mat,row[k],&nnz,&jj,&vv);CHKERRQ(ierr);
135fd61f322SBarry Smith       }
136fd61f322SBarry Smith 
137fd61f322SBarry Smith found:;
138ad608de0SBarry Smith     }
139b3cc6726SBarry Smith     ierr = MatRestoreRow_SeqAIJ(mat,row[prow],&nz,&j,&v);CHKERRQ(ierr);
140ad608de0SBarry Smith   }
1416bf464f9SBarry Smith   ierr = ISDestroy(&icis);CHKERRQ(ierr);
1423a40ed3dSBarry Smith   PetscFunctionReturn(0);
143ad608de0SBarry Smith }
144b2573a8aSBarry Smith 
145