xref: /petsc/src/mat/utils/zerodiag.c (revision 814823dc4b6293d3c7e22b8a26ecbb2ccc30f100)
10367cb8aSBarry Smith 
20367cb8aSBarry Smith 
30367cb8aSBarry Smith 
4a5eb4965SSatish Balay #ifdef PETSC_RCS_HEADER
5*814823dcSBarry Smith static char vcid[] = "$Id: zerodiag.c,v 1.27 1998/11/04 19:45:13 bsmith Exp bsmith $";
6ad608de0SBarry Smith #endif
7ad608de0SBarry Smith 
8ad608de0SBarry Smith /*
9ad608de0SBarry Smith     This file contains routines to reorder a matrix so that the diagonal
1048b35521SBarry Smith     elements are nonzero.
11ad608de0SBarry Smith  */
12ad608de0SBarry Smith 
1370f55243SBarry Smith #include "src/mat/matimpl.h"       /*I  "mat.h"  I*/
14ad608de0SBarry Smith #include <math.h>
15ad608de0SBarry Smith 
1648b35521SBarry Smith #define SWAP(a,b) {int _t; _t = a; a = b; b = _t; }
1748b35521SBarry Smith 
185615d1e5SSatish Balay #undef __FUNC__
195615d1e5SSatish Balay #define __FUNC__ "MatZeroFindPre_Private"
20d4bb536fSBarry Smith /*
21d4bb536fSBarry Smith    Given a current row and current permutation, find a column permutation
22d4bb536fSBarry Smith    that removes a zero diagonal.
23d4bb536fSBarry Smith */
2433f51a72SBarry Smith int MatZeroFindPre_Private(Mat mat,int prow,int* row,int* col,int *icol,double repla,
25ec201a9bSBarry Smith                            double atol,int* rc,double* rcv,int nz, int *j, Scalar *v)
2648b35521SBarry Smith {
27ec201a9bSBarry Smith   int      k, repl, kk, nnz, *jj,ierr;
28ec201a9bSBarry Smith   Scalar   *vv;
2948b35521SBarry Smith 
303a40ed3dSBarry Smith   PetscFunctionBegin;
31d4bb536fSBarry Smith    /*
32d4bb536fSBarry Smith       Here one could sort the col[j[k]] to try to select the column closest
33d4bb536fSBarry Smith      to the diagonal (in the new ordering) that satisfies the criteria
34d4bb536fSBarry Smith   */
3548b35521SBarry Smith   for (k=0; k<nz; k++) {
3633f51a72SBarry Smith     if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) {
3748b35521SBarry Smith       /* See if this one will work */
3833f51a72SBarry Smith       repl  = icol[j[k]];
390367cb8aSBarry Smith       ierr = MatGetRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr);
4048b35521SBarry Smith       for (kk=0; kk<nnz; kk++) {
4133f51a72SBarry Smith 	if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) {
42cddf8d76SBarry Smith 	  *rcv = PetscAbsScalar(v[k]);
4348b35521SBarry Smith 	  *rc  = repl;
440367cb8aSBarry Smith           ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr);
453a40ed3dSBarry Smith 	  PetscFunctionReturn(1);
4648b35521SBarry Smith 	}
4748b35521SBarry Smith       }
480367cb8aSBarry Smith       ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr);
4948b35521SBarry Smith     }
5048b35521SBarry Smith   }
510367cb8aSBarry Smith 
520367cb8aSBarry Smith   SETERRQ(1,1," ");
533a40ed3dSBarry Smith   PetscFunctionReturn(0);
5448b35521SBarry Smith }
55ad608de0SBarry Smith 
565615d1e5SSatish Balay #undef __FUNC__
575615d1e5SSatish Balay #define __FUNC__ "MatReorderForNonzeroDiagonal"
58ad608de0SBarry Smith /*@
5948b35521SBarry Smith     MatReorderForNonzeroDiagonal - Changes matrix ordering to remove
6048b35521SBarry Smith     zeros from diagonal. This may help in the LU factorization to
6148b35521SBarry Smith     prevent a zero pivot.
62ad608de0SBarry Smith 
63fee21e36SBarry Smith     Collective on Mat
64fee21e36SBarry Smith 
6598a79cdbSBarry Smith     Input Parameters:
6698a79cdbSBarry Smith +   mat  - matrix to reorder
6798a79cdbSBarry Smith -   rmap,cmap - row and column permutations.  Usually obtained from
6898a79cdbSBarry Smith                MatGetReordering().
6998a79cdbSBarry Smith 
70ad608de0SBarry Smith     Notes:
71ad608de0SBarry Smith     This is not intended as a replacement for pivoting for matrices that
72d252947aSBarry Smith     have ``bad'' structure. It is only a stop-gap measure. Should be called
73d252947aSBarry Smith     after a call to MatGetReordering(), this routine changes the column
74d252947aSBarry Smith     ordering defined in cis.
75d252947aSBarry Smith 
76b259b22eSLois Curfman McInnes     Options Database Keys (When using SLES):
7798a79cdbSBarry Smith +      -pc_ilu_nonzeros_along_diagonal
7898a79cdbSBarry Smith -      -pc_lu_nonzeros_along_diagonal
79ad608de0SBarry Smith 
8033f51a72SBarry Smith     Algorithm Notes:
8133f51a72SBarry Smith     Column pivoting is used.
8233f51a72SBarry Smith 
8333f51a72SBarry Smith     1) Choice of column is made by looking at the
8433f51a72SBarry Smith        non-zero elements in the troublesome row for columns that are not yet
8533f51a72SBarry Smith        included (moving from left to right).
8633f51a72SBarry Smith 
8733f51a72SBarry Smith     2) If (1) fails we check all the columns to the left of the current row
88*814823dcSBarry Smith        and see if one of them has could be swapped. It can be swapped if
89*814823dcSBarry Smith        its corresponding row has a non-zero in the column it is being
90*814823dcSBarry Smith        swapped with; to make sure the previous nonzero diagonal remains
91*814823dcSBarry Smith        nonzero
9233f51a72SBarry Smith 
9398a79cdbSBarry Smith 
94ad608de0SBarry Smith @*/
9548b35521SBarry Smith int MatReorderForNonzeroDiagonal(Mat mat,double atol,IS ris,IS cis )
96ad608de0SBarry Smith {
9733f51a72SBarry Smith   int      ierr, prow, k, nz, n, repl, *j, *col, *row, m, *irow, *icol;
98d93a2b8dSBarry Smith   Scalar   *v;
99d93a2b8dSBarry Smith   double   repla;
10033f51a72SBarry Smith   IS       icis,iris;
101ad608de0SBarry Smith 
1023a40ed3dSBarry Smith   PetscFunctionBegin;
10390f02eecSBarry Smith   PetscValidHeaderSpecific(mat,MAT_COOKIE);
10490f02eecSBarry Smith   PetscValidHeaderSpecific(ris,IS_COOKIE);
10590f02eecSBarry Smith   PetscValidHeaderSpecific(cis,IS_COOKIE);
10690f02eecSBarry Smith 
10748b35521SBarry Smith   ierr = ISGetIndices(ris,&row); CHKERRQ(ierr);
10848b35521SBarry Smith   ierr = ISGetIndices(cis,&col); CHKERRQ(ierr);
10933f51a72SBarry Smith   ierr = ISInvertPermutation(cis,&icis);CHKERRQ(ierr);
11033f51a72SBarry Smith   ierr = ISInvertPermutation(ris,&iris);CHKERRQ(ierr);
11133f51a72SBarry Smith   ierr = ISGetIndices(icis,&icol); CHKERRQ(ierr);
11248b35521SBarry Smith   ierr = MatGetSize(mat,&m,&n); CHKERRQ(ierr);
113ad608de0SBarry Smith 
114ad608de0SBarry Smith   for (prow=0; prow<n; prow++) {
11590f02eecSBarry Smith     ierr = MatGetRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr);
11633f51a72SBarry Smith     for (k=0; k<nz; k++) {if (icol[j[k]] == prow) break;}
117cddf8d76SBarry Smith     if (k >= nz || PetscAbsScalar(v[k]) <= atol) {
118ad608de0SBarry Smith       /* Element too small or zero; find the best candidate */
119ad608de0SBarry Smith       repl  = prow;
120cddf8d76SBarry Smith       repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]);
121d4bb536fSBarry Smith       /*
12233f51a72SBarry Smith         Here one could sort the icol[j[k]] list to try to select the
123d4bb536fSBarry Smith         column closest to the diagonal in the new ordering. (Note have
124d4bb536fSBarry Smith         to permute the v[k] values as well, and use a fixed bound on the
125d4bb536fSBarry Smith         quality of repla rather then looking for the absolute largest.
126d4bb536fSBarry Smith       */
12748b35521SBarry Smith       for (k=0; k<nz; k++) {
12833f51a72SBarry Smith 	if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) {
12933f51a72SBarry Smith 	  repl  = icol[j[k]];
130cddf8d76SBarry Smith 	  repla = PetscAbsScalar(v[k]);
131ad608de0SBarry Smith         }
13248b35521SBarry Smith       }
133ad608de0SBarry Smith       if (prow == repl) {
1345f944b44SBarry Smith 	/*
1355f944b44SBarry Smith            Look for an element that allows us
136ad608de0SBarry Smith 	   to pivot with a previous column.  To do this, we need
137ad608de0SBarry Smith 	   to be sure that we don't introduce a zero in a previous
1385f944b44SBarry Smith 	   diagonal
1395f944b44SBarry Smith         */
14033f51a72SBarry Smith         if (!MatZeroFindPre_Private(mat,prow,row,col,icol,repla,atol,&repl,&repla,nz,j,v)){
1415f051944SBarry Smith           (*PetscErrorPrintf)("Permuted row number %d\n",prow);
142a8c6a408SBarry Smith 	  SETERRQ(PETSC_ERR_MAT_LU_ZRPVT,0,"Cannot reorder matrix to eliminate zero diagonal entry");
143ad608de0SBarry Smith 	}
144ad608de0SBarry Smith       }
14533f51a72SBarry Smith       SWAP(icol[col[prow]],icol[col[repl]]);
146ad608de0SBarry Smith       SWAP(col[prow],col[repl]);
147ad608de0SBarry Smith     }
14890f02eecSBarry Smith     ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr);
149ad608de0SBarry Smith   }
15048b35521SBarry Smith   ierr = ISRestoreIndices(ris,&row); CHKERRQ(ierr);
15148b35521SBarry Smith   ierr = ISRestoreIndices(cis,&col); CHKERRQ(ierr);
15233f51a72SBarry Smith   ierr = ISRestoreIndices(icis,&icol); CHKERRQ(ierr);
15333f51a72SBarry Smith   ierr = ISDestroy(icis); CHKERRQ(ierr);
1543a40ed3dSBarry Smith   PetscFunctionReturn(0);
155ad608de0SBarry Smith }
15648b35521SBarry Smith 
15748b35521SBarry Smith 
15848b35521SBarry Smith 
159