xref: /petsc/src/mat/utils/zerodiag.c (revision 33f51a72e10cddd5cc44569a6eaa6fc65cc2020d)
1a5eb4965SSatish Balay #ifdef PETSC_RCS_HEADER
2*33f51a72SBarry Smith static char vcid[] = "$Id: zerodiag.c,v 1.25 1998/11/04 16:23:24 bsmith Exp bsmith $";
3ad608de0SBarry Smith #endif
4ad608de0SBarry Smith 
5ad608de0SBarry Smith /*
6ad608de0SBarry Smith     This file contains routines to reorder a matrix so that the diagonal
748b35521SBarry Smith     elements are nonzero.
8ad608de0SBarry Smith  */
9ad608de0SBarry Smith 
1070f55243SBarry Smith #include "src/mat/matimpl.h"       /*I  "mat.h"  I*/
11ad608de0SBarry Smith #include <math.h>
12ad608de0SBarry Smith 
1348b35521SBarry Smith #define SWAP(a,b) {int _t; _t = a; a = b; b = _t; }
1448b35521SBarry Smith 
155615d1e5SSatish Balay #undef __FUNC__
165615d1e5SSatish Balay #define __FUNC__ "MatZeroFindPre_Private"
17d4bb536fSBarry Smith /*
18d4bb536fSBarry Smith    Given a current row and current permutation, find a column permutation
19d4bb536fSBarry Smith    that removes a zero diagonal.
20d4bb536fSBarry Smith */
21*33f51a72SBarry Smith int MatZeroFindPre_Private(Mat mat,int prow,int* row,int* col,int *icol,double repla,
22ec201a9bSBarry Smith                            double atol,int* rc,double* rcv,int nz, int *j, Scalar *v)
2348b35521SBarry Smith {
24ec201a9bSBarry Smith   int      k, repl, kk, nnz, *jj,ierr;
25ec201a9bSBarry Smith   Scalar   *vv;
2648b35521SBarry Smith 
273a40ed3dSBarry Smith   PetscFunctionBegin;
28d4bb536fSBarry Smith    /*
29d4bb536fSBarry Smith       Here one could sort the col[j[k]] to try to select the column closest
30d4bb536fSBarry Smith      to the diagonal (in the new ordering) that satisfies the criteria
31d4bb536fSBarry Smith   */
3248b35521SBarry Smith   for (k=0; k<nz; k++) {
33*33f51a72SBarry Smith     if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) {
3448b35521SBarry Smith       /* See if this one will work */
35*33f51a72SBarry Smith       repl  = icol[j[k]];
36*33f51a72SBarry Smith       ierr = MatGetRow( mat, irow[repl], &nnz, &jj, &vv ); CHKERRQ(ierr);
3748b35521SBarry Smith       for (kk=0; kk<nnz; kk++) {
38*33f51a72SBarry Smith 	if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) {
39cddf8d76SBarry Smith 	  *rcv = PetscAbsScalar(v[k]);
4048b35521SBarry Smith 	  *rc  = repl;
41*33f51a72SBarry Smith           ierr = MatRestoreRow( mat, irow[repl], &nnz, &jj, &vv ); CHKERRQ(ierr);
423a40ed3dSBarry Smith 	  PetscFunctionReturn(1);
4348b35521SBarry Smith 	}
4448b35521SBarry Smith       }
45*33f51a72SBarry Smith       ierr = MatRestoreRow( mat, irow[repl], &nnz, &jj, &vv ); CHKERRQ(ierr);
4648b35521SBarry Smith     }
4748b35521SBarry Smith   }
483a40ed3dSBarry Smith   PetscFunctionReturn(0);
4948b35521SBarry Smith }
50ad608de0SBarry Smith 
515615d1e5SSatish Balay #undef __FUNC__
525615d1e5SSatish Balay #define __FUNC__ "MatReorderForNonzeroDiagonal"
53ad608de0SBarry Smith /*@
5448b35521SBarry Smith     MatReorderForNonzeroDiagonal - Changes matrix ordering to remove
5548b35521SBarry Smith     zeros from diagonal. This may help in the LU factorization to
5648b35521SBarry Smith     prevent a zero pivot.
57ad608de0SBarry Smith 
58fee21e36SBarry Smith     Collective on Mat
59fee21e36SBarry Smith 
6098a79cdbSBarry Smith     Input Parameters:
6198a79cdbSBarry Smith +   mat  - matrix to reorder
6298a79cdbSBarry Smith -   rmap,cmap - row and column permutations.  Usually obtained from
6398a79cdbSBarry Smith                MatGetReordering().
6498a79cdbSBarry Smith 
65ad608de0SBarry Smith     Notes:
66ad608de0SBarry Smith     This is not intended as a replacement for pivoting for matrices that
67d252947aSBarry Smith     have ``bad'' structure. It is only a stop-gap measure. Should be called
68d252947aSBarry Smith     after a call to MatGetReordering(), this routine changes the column
69d252947aSBarry Smith     ordering defined in cis.
70d252947aSBarry Smith 
71b259b22eSLois Curfman McInnes     Options Database Keys (When using SLES):
7298a79cdbSBarry Smith +      -pc_ilu_nonzeros_along_diagonal
7398a79cdbSBarry Smith -      -pc_lu_nonzeros_along_diagonal
74ad608de0SBarry Smith 
75*33f51a72SBarry Smith     Algorithm Notes:
76*33f51a72SBarry Smith     Column pivoting is used.
77*33f51a72SBarry Smith 
78*33f51a72SBarry Smith     1) Choice of column is made by looking at the
79*33f51a72SBarry Smith        non-zero elements in the troublesome row for columns that are not yet
80*33f51a72SBarry Smith        included (moving from left to right).
81*33f51a72SBarry Smith 
82*33f51a72SBarry Smith     2) If (1) fails we check all the columns to the left of the current row
83*33f51a72SBarry Smith        and see if we can
84*33f51a72SBarry Smith 
8598a79cdbSBarry Smith 
86ad608de0SBarry Smith @*/
8748b35521SBarry Smith int MatReorderForNonzeroDiagonal(Mat mat,double atol,IS ris,IS cis )
88ad608de0SBarry Smith {
89*33f51a72SBarry Smith   int      ierr, prow, k, nz, n, repl, *j, *col, *row, m, *irow, *icol;
90d93a2b8dSBarry Smith   Scalar   *v;
91d93a2b8dSBarry Smith   double   repla;
92*33f51a72SBarry Smith   IS       icis,iris;
93ad608de0SBarry Smith 
943a40ed3dSBarry Smith   PetscFunctionBegin;
9590f02eecSBarry Smith   PetscValidHeaderSpecific(mat,MAT_COOKIE);
9690f02eecSBarry Smith   PetscValidHeaderSpecific(ris,IS_COOKIE);
9790f02eecSBarry Smith   PetscValidHeaderSpecific(cis,IS_COOKIE);
9890f02eecSBarry Smith 
9948b35521SBarry Smith   ierr = ISGetIndices(ris,&row); CHKERRQ(ierr);
10048b35521SBarry Smith   ierr = ISGetIndices(cis,&col); CHKERRQ(ierr);
101*33f51a72SBarry Smith   ierr = ISInvertPermutation(cis,&icis);CHKERRQ(ierr);
102*33f51a72SBarry Smith   ierr = ISInvertPermutation(ris,&iris);CHKERRQ(ierr);
103*33f51a72SBarry Smith   ierr = ISGetIndices(icis,&icol); CHKERRQ(ierr);
10448b35521SBarry Smith   ierr = MatGetSize(mat,&m,&n); CHKERRQ(ierr);
105ad608de0SBarry Smith 
106ad608de0SBarry Smith   for (prow=0; prow<n; prow++) {
10790f02eecSBarry Smith     ierr = MatGetRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr);
108*33f51a72SBarry Smith     for (k=0; k<nz; k++) {if (icol[j[k]] == prow) break;}
109cddf8d76SBarry Smith     if (k >= nz || PetscAbsScalar(v[k]) <= atol) {
110ad608de0SBarry Smith       /* Element too small or zero; find the best candidate */
111ad608de0SBarry Smith       repl  = prow;
112cddf8d76SBarry Smith       repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]);
113d4bb536fSBarry Smith       /*
114*33f51a72SBarry Smith         Here one could sort the icol[j[k]] list to try to select the
115d4bb536fSBarry Smith         column closest to the diagonal in the new ordering. (Note have
116d4bb536fSBarry Smith         to permute the v[k] values as well, and use a fixed bound on the
117d4bb536fSBarry Smith         quality of repla rather then looking for the absolute largest.
118d4bb536fSBarry Smith       */
11948b35521SBarry Smith       for (k=0; k<nz; k++) {
120*33f51a72SBarry Smith 	if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) {
121*33f51a72SBarry Smith 	  repl  = icol[j[k]];
122cddf8d76SBarry Smith 	  repla = PetscAbsScalar(v[k]);
123ad608de0SBarry Smith         }
12448b35521SBarry Smith       }
125ad608de0SBarry Smith       if (prow == repl) {
1265f944b44SBarry Smith 	/*
1275f944b44SBarry Smith            Look for an element that allows us
128ad608de0SBarry Smith 	   to pivot with a previous column.  To do this, we need
129ad608de0SBarry Smith 	   to be sure that we don't introduce a zero in a previous
1305f944b44SBarry Smith 	   diagonal
1315f944b44SBarry Smith         */
132*33f51a72SBarry Smith         if (!MatZeroFindPre_Private(mat,prow,row,col,icol,repla,atol,&repl,&repla,nz,j,v)){
1335f051944SBarry Smith           (*PetscErrorPrintf)("Permuted row number %d\n",prow);
134a8c6a408SBarry Smith 	  SETERRQ(PETSC_ERR_MAT_LU_ZRPVT,0,"Cannot reorder matrix to eliminate zero diagonal entry");
135ad608de0SBarry Smith 	}
136ad608de0SBarry Smith       }
137*33f51a72SBarry Smith       SWAP(icol[col[prow]],icol[col[repl]]);
138ad608de0SBarry Smith       SWAP(col[prow],col[repl]);
139ad608de0SBarry Smith     }
14090f02eecSBarry Smith     ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr);
141ad608de0SBarry Smith   }
14248b35521SBarry Smith   ierr = ISRestoreIndices(ris,&row); CHKERRQ(ierr);
14348b35521SBarry Smith   ierr = ISRestoreIndices(cis,&col); CHKERRQ(ierr);
144*33f51a72SBarry Smith   ierr = ISRestoreIndices(icis,&icol); CHKERRQ(ierr);
145*33f51a72SBarry Smith   ierr = ISDestroy(icis); CHKERRQ(ierr);
1463a40ed3dSBarry Smith   PetscFunctionReturn(0);
147ad608de0SBarry Smith }
14848b35521SBarry Smith 
14948b35521SBarry Smith 
15048b35521SBarry Smith 
151