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