xref: /petsc/src/mat/utils/zerodiag.c (revision b259b22e26dd3b9878f0fc28c25238c245f2adbd)
1a5eb4965SSatish Balay #ifdef PETSC_RCS_HEADER
2*b259b22eSLois Curfman McInnes static char vcid[] = "$Id: zerodiag.c,v 1.20 1998/04/13 17:43:46 bsmith Exp curfman $";
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 */
21d5d45c9bSBarry Smith int MatZeroFindPre_Private(Mat mat,int prow,int* row,int* col,double repla,
22d93a2b8dSBarry Smith                            double atol,int* rc,double* rcv )
2348b35521SBarry Smith {
2490f02eecSBarry Smith   int      k, nz, repl, *j, kk, nnz, *jj,ierr;
2548b35521SBarry Smith   Scalar   *v, *vv;
2648b35521SBarry Smith 
273a40ed3dSBarry Smith   PetscFunctionBegin;
2890f02eecSBarry Smith   ierr = MatGetRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr);
29d4bb536fSBarry Smith /*
30d4bb536fSBarry Smith     Here one could sort the col[j[k]] to try to select the column closest
31d4bb536fSBarry Smith   to the diagonal (in the new ordering) that satisfies the criteria
32d4bb536fSBarry Smith */
3348b35521SBarry Smith   for (k=0; k<nz; k++) {
34cddf8d76SBarry Smith     if (col[j[k]] < prow && PetscAbsScalar(v[k]) > repla) {
3548b35521SBarry Smith       /* See if this one will work */
3648b35521SBarry Smith       repl  = col[j[k]];
3790f02eecSBarry Smith       ierr = MatGetRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr);
3848b35521SBarry Smith       for (kk=0; kk<nnz; kk++) {
39cddf8d76SBarry Smith 	if (col[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) {
40cddf8d76SBarry Smith 	  *rcv = PetscAbsScalar(v[k]);
4148b35521SBarry Smith 	  *rc  = repl;
4290f02eecSBarry Smith           ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr);
4390f02eecSBarry Smith           ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr);
443a40ed3dSBarry Smith 	  PetscFunctionReturn(1);
4548b35521SBarry Smith 	}
4648b35521SBarry Smith       }
4790f02eecSBarry Smith       ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr);
4848b35521SBarry Smith     }
4948b35521SBarry Smith   }
5090f02eecSBarry Smith   ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr);
513a40ed3dSBarry Smith   PetscFunctionReturn(0);
5248b35521SBarry Smith }
53ad608de0SBarry Smith 
545615d1e5SSatish Balay #undef __FUNC__
555615d1e5SSatish Balay #define __FUNC__ "MatReorderForNonzeroDiagonal"
56ad608de0SBarry Smith /*@
5748b35521SBarry Smith     MatReorderForNonzeroDiagonal - Changes matrix ordering to remove
5848b35521SBarry Smith     zeros from diagonal. This may help in the LU factorization to
5948b35521SBarry Smith     prevent a zero pivot.
60ad608de0SBarry Smith 
61ad608de0SBarry Smith     Input Parameters:
62ad608de0SBarry Smith .   mat  - matrix to reorder
6348b35521SBarry Smith .   rmap,cmap - row and column permutations.  Usually obtained from
6448b35521SBarry Smith .               MatGetReordering().
65ad608de0SBarry Smith 
66fee21e36SBarry Smith     Collective on Mat
67fee21e36SBarry Smith 
68ad608de0SBarry Smith     Notes:
69ad608de0SBarry Smith     This is not intended as a replacement for pivoting for matrices that
70d252947aSBarry Smith     have ``bad'' structure. It is only a stop-gap measure. Should be called
71d252947aSBarry Smith     after a call to MatGetReordering(), this routine changes the column
72d252947aSBarry Smith     ordering defined in cis.
73d252947aSBarry Smith 
74*b259b22eSLois Curfman McInnes     Options Database Keys (When using SLES):
75*b259b22eSLois Curfman McInnes $      -pc_ilu_nonzeros_along_diagonal
76*b259b22eSLois Curfman McInnes $      -pc_lu_nonzeros_along_diagonal
77ad608de0SBarry Smith 
78ad608de0SBarry Smith     Algorithm:
79ad608de0SBarry Smith     Column pivoting is used.  Choice of column is made by looking at the
80ad608de0SBarry Smith     non-zero elements in the row.  This algorithm is simple and fast but
81d252947aSBarry Smith     does NOT guarantee that a non-singular or well conditioned
82ad608de0SBarry Smith     principle submatrix will be produced.
83ad608de0SBarry Smith @*/
8448b35521SBarry Smith int MatReorderForNonzeroDiagonal(Mat mat,double atol,IS ris,IS cis )
85ad608de0SBarry Smith {
8648b35521SBarry Smith   int      ierr, prow, k, nz, n, repl, *j, *col, *row, m;
87d93a2b8dSBarry Smith   Scalar   *v;
88d93a2b8dSBarry Smith   double   repla;
89ad608de0SBarry Smith 
903a40ed3dSBarry Smith   PetscFunctionBegin;
9190f02eecSBarry Smith   PetscValidHeaderSpecific(mat,MAT_COOKIE);
9290f02eecSBarry Smith   PetscValidHeaderSpecific(ris,IS_COOKIE);
9390f02eecSBarry Smith   PetscValidHeaderSpecific(cis,IS_COOKIE);
9490f02eecSBarry Smith 
9548b35521SBarry Smith   ierr = ISGetIndices(ris,&row); CHKERRQ(ierr);
9648b35521SBarry Smith   ierr = ISGetIndices(cis,&col); CHKERRQ(ierr);
9748b35521SBarry Smith   ierr = MatGetSize(mat,&m,&n); CHKERRQ(ierr);
98ad608de0SBarry Smith 
99ad608de0SBarry Smith   for (prow=0; prow<n; prow++) {
10090f02eecSBarry Smith     ierr = MatGetRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr);
10148b35521SBarry Smith     for (k=0; k<nz; k++) {if (col[j[k]] == prow) break;}
102cddf8d76SBarry Smith     if (k >= nz || PetscAbsScalar(v[k]) <= atol) {
103ad608de0SBarry Smith       /* Element too small or zero; find the best candidate */
104ad608de0SBarry Smith       repl  = prow;
105cddf8d76SBarry Smith       repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]);
106d4bb536fSBarry Smith /*
107d4bb536fSBarry Smith    Here one could sort the col[j[k]] list to try to select the
108d4bb536fSBarry Smith   column closest to the diagonal in the new ordering. (Note have
109d4bb536fSBarry Smith   to permute the v[k] values as well, and use a fixed bound on the
110d4bb536fSBarry Smith   quality of repla rather then looking for the absolute largest.
111d4bb536fSBarry Smith */
11248b35521SBarry Smith       for (k=0; k<nz; k++) {
113cddf8d76SBarry Smith 	if (col[j[k]] > prow && PetscAbsScalar(v[k]) > repla) {
114ad608de0SBarry Smith 	  repl  = col[j[k]];
115cddf8d76SBarry Smith 	  repla = PetscAbsScalar(v[k]);
116ad608de0SBarry Smith         }
11748b35521SBarry Smith       }
118ad608de0SBarry Smith       if (prow == repl) {
119d4bb536fSBarry Smith 	    /* Look for an element that allows us
120ad608de0SBarry Smith 	       to pivot with a previous column.  To do this, we need
121ad608de0SBarry Smith 	       to be sure that we don't introduce a zero in a previous
122ad608de0SBarry Smith 	       diagonal */
123d5d45c9bSBarry Smith         if (!MatZeroFindPre_Private(mat,prow,row,col,repla,atol,&repl,&repla)){
124a8c6a408SBarry Smith 	  SETERRQ(PETSC_ERR_MAT_LU_ZRPVT,0,"Cannot reorder matrix to eliminate zero diagonal entry");
125ad608de0SBarry Smith 	}
126ad608de0SBarry Smith       }
127ad608de0SBarry Smith       SWAP(col[prow],col[repl]);
128ad608de0SBarry Smith     }
12990f02eecSBarry Smith     ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr);
130ad608de0SBarry Smith   }
13148b35521SBarry Smith   ierr = ISRestoreIndices(ris,&row); CHKERRQ(ierr);
13248b35521SBarry Smith   ierr = ISRestoreIndices(cis,&col); CHKERRQ(ierr);
1333a40ed3dSBarry Smith   PetscFunctionReturn(0);
134ad608de0SBarry Smith }
13548b35521SBarry Smith 
13648b35521SBarry Smith 
13748b35521SBarry Smith 
138