xref: /petsc/src/mat/utils/zerodiag.c (revision 0367cb8a9fdb1d6d56f0aab810a2383e1e698d2e)
1*0367cb8aSBarry Smith 
2*0367cb8aSBarry Smith 
3*0367cb8aSBarry Smith 
4a5eb4965SSatish Balay #ifdef PETSC_RCS_HEADER
5*0367cb8aSBarry Smith static char vcid[] = "$Id: zerodiag.c,v 1.26 1998/11/04 19:40:26 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]];
39*0367cb8aSBarry 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;
44*0367cb8aSBarry Smith           ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr);
453a40ed3dSBarry Smith 	  PetscFunctionReturn(1);
4648b35521SBarry Smith 	}
4748b35521SBarry Smith       }
48*0367cb8aSBarry Smith       ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr);
4948b35521SBarry Smith     }
5048b35521SBarry Smith   }
51*0367cb8aSBarry Smith 
52*0367cb8aSBarry 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
8833f51a72SBarry Smith        and see if we can
8933f51a72SBarry Smith 
9098a79cdbSBarry Smith 
91ad608de0SBarry Smith @*/
9248b35521SBarry Smith int MatReorderForNonzeroDiagonal(Mat mat,double atol,IS ris,IS cis )
93ad608de0SBarry Smith {
9433f51a72SBarry Smith   int      ierr, prow, k, nz, n, repl, *j, *col, *row, m, *irow, *icol;
95d93a2b8dSBarry Smith   Scalar   *v;
96d93a2b8dSBarry Smith   double   repla;
9733f51a72SBarry Smith   IS       icis,iris;
98ad608de0SBarry Smith 
993a40ed3dSBarry Smith   PetscFunctionBegin;
10090f02eecSBarry Smith   PetscValidHeaderSpecific(mat,MAT_COOKIE);
10190f02eecSBarry Smith   PetscValidHeaderSpecific(ris,IS_COOKIE);
10290f02eecSBarry Smith   PetscValidHeaderSpecific(cis,IS_COOKIE);
10390f02eecSBarry Smith 
10448b35521SBarry Smith   ierr = ISGetIndices(ris,&row); CHKERRQ(ierr);
10548b35521SBarry Smith   ierr = ISGetIndices(cis,&col); CHKERRQ(ierr);
10633f51a72SBarry Smith   ierr = ISInvertPermutation(cis,&icis);CHKERRQ(ierr);
10733f51a72SBarry Smith   ierr = ISInvertPermutation(ris,&iris);CHKERRQ(ierr);
10833f51a72SBarry Smith   ierr = ISGetIndices(icis,&icol); CHKERRQ(ierr);
10948b35521SBarry Smith   ierr = MatGetSize(mat,&m,&n); CHKERRQ(ierr);
110ad608de0SBarry Smith 
111ad608de0SBarry Smith   for (prow=0; prow<n; prow++) {
11290f02eecSBarry Smith     ierr = MatGetRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr);
11333f51a72SBarry Smith     for (k=0; k<nz; k++) {if (icol[j[k]] == prow) break;}
114cddf8d76SBarry Smith     if (k >= nz || PetscAbsScalar(v[k]) <= atol) {
115ad608de0SBarry Smith       /* Element too small or zero; find the best candidate */
116ad608de0SBarry Smith       repl  = prow;
117cddf8d76SBarry Smith       repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]);
118d4bb536fSBarry Smith       /*
11933f51a72SBarry Smith         Here one could sort the icol[j[k]] list to try to select the
120d4bb536fSBarry Smith         column closest to the diagonal in the new ordering. (Note have
121d4bb536fSBarry Smith         to permute the v[k] values as well, and use a fixed bound on the
122d4bb536fSBarry Smith         quality of repla rather then looking for the absolute largest.
123d4bb536fSBarry Smith       */
12448b35521SBarry Smith       for (k=0; k<nz; k++) {
12533f51a72SBarry Smith 	if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) {
12633f51a72SBarry Smith 	  repl  = icol[j[k]];
127cddf8d76SBarry Smith 	  repla = PetscAbsScalar(v[k]);
128ad608de0SBarry Smith         }
12948b35521SBarry Smith       }
130ad608de0SBarry Smith       if (prow == repl) {
1315f944b44SBarry Smith 	/*
1325f944b44SBarry Smith            Look for an element that allows us
133ad608de0SBarry Smith 	   to pivot with a previous column.  To do this, we need
134ad608de0SBarry Smith 	   to be sure that we don't introduce a zero in a previous
1355f944b44SBarry Smith 	   diagonal
1365f944b44SBarry Smith         */
13733f51a72SBarry Smith         if (!MatZeroFindPre_Private(mat,prow,row,col,icol,repla,atol,&repl,&repla,nz,j,v)){
1385f051944SBarry Smith           (*PetscErrorPrintf)("Permuted row number %d\n",prow);
139a8c6a408SBarry Smith 	  SETERRQ(PETSC_ERR_MAT_LU_ZRPVT,0,"Cannot reorder matrix to eliminate zero diagonal entry");
140ad608de0SBarry Smith 	}
141ad608de0SBarry Smith       }
14233f51a72SBarry Smith       SWAP(icol[col[prow]],icol[col[repl]]);
143ad608de0SBarry Smith       SWAP(col[prow],col[repl]);
144ad608de0SBarry Smith     }
14590f02eecSBarry Smith     ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr);
146ad608de0SBarry Smith   }
14748b35521SBarry Smith   ierr = ISRestoreIndices(ris,&row); CHKERRQ(ierr);
14848b35521SBarry Smith   ierr = ISRestoreIndices(cis,&col); CHKERRQ(ierr);
14933f51a72SBarry Smith   ierr = ISRestoreIndices(icis,&icol); CHKERRQ(ierr);
15033f51a72SBarry Smith   ierr = ISDestroy(icis); CHKERRQ(ierr);
1513a40ed3dSBarry Smith   PetscFunctionReturn(0);
152ad608de0SBarry Smith }
15348b35521SBarry Smith 
15448b35521SBarry Smith 
15548b35521SBarry Smith 
156