1a5eb4965SSatish Balay #ifdef PETSC_RCS_HEADER 2*3a40ed3dSBarry Smith static char vcid[] = "$Id: zerodiag.c,v 1.17 1997/08/22 15:15:22 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 */ 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 27*3a40ed3dSBarry 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); 44*3a40ed3dSBarry 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); 51*3a40ed3dSBarry 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 66ad608de0SBarry Smith Notes: 67ad608de0SBarry Smith This is not intended as a replacement for pivoting for matrices that 68d252947aSBarry Smith have ``bad'' structure. It is only a stop-gap measure. Should be called 69d252947aSBarry Smith after a call to MatGetReordering(), this routine changes the column 70d252947aSBarry Smith ordering defined in cis. 71d252947aSBarry Smith 7251d1478bSLois Curfman McInnes Options Database Keys: (When using SLES) 73d252947aSBarry Smith . -pc_ilu_nonzeros_along_diagonal 74d252947aSBarry Smith . -pc_lu_nonzeros_along_diagonal 75ad608de0SBarry Smith 76ad608de0SBarry Smith Algorithm: 77ad608de0SBarry Smith Column pivoting is used. Choice of column is made by looking at the 78ad608de0SBarry Smith non-zero elements in the row. This algorithm is simple and fast but 79d252947aSBarry Smith does NOT guarantee that a non-singular or well conditioned 80ad608de0SBarry Smith principle submatrix will be produced. 81ad608de0SBarry Smith @*/ 8248b35521SBarry Smith int MatReorderForNonzeroDiagonal(Mat mat,double atol,IS ris,IS cis ) 83ad608de0SBarry Smith { 8448b35521SBarry Smith int ierr, prow, k, nz, n, repl, *j, *col, *row, m; 85d93a2b8dSBarry Smith Scalar *v; 86d93a2b8dSBarry Smith double repla; 87ad608de0SBarry Smith 88*3a40ed3dSBarry Smith PetscFunctionBegin; 8990f02eecSBarry Smith PetscValidHeaderSpecific(mat,MAT_COOKIE); 9090f02eecSBarry Smith PetscValidHeaderSpecific(ris,IS_COOKIE); 9190f02eecSBarry Smith PetscValidHeaderSpecific(cis,IS_COOKIE); 9290f02eecSBarry Smith 9348b35521SBarry Smith ierr = ISGetIndices(ris,&row); CHKERRQ(ierr); 9448b35521SBarry Smith ierr = ISGetIndices(cis,&col); CHKERRQ(ierr); 9548b35521SBarry Smith ierr = MatGetSize(mat,&m,&n); CHKERRQ(ierr); 96ad608de0SBarry Smith 97ad608de0SBarry Smith for (prow=0; prow<n; prow++) { 9890f02eecSBarry Smith ierr = MatGetRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr); 9948b35521SBarry Smith for (k=0; k<nz; k++) {if (col[j[k]] == prow) break;} 100cddf8d76SBarry Smith if (k >= nz || PetscAbsScalar(v[k]) <= atol) { 101ad608de0SBarry Smith /* Element too small or zero; find the best candidate */ 102ad608de0SBarry Smith repl = prow; 103cddf8d76SBarry Smith repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]); 104d4bb536fSBarry Smith /* 105d4bb536fSBarry Smith Here one could sort the col[j[k]] list to try to select the 106d4bb536fSBarry Smith column closest to the diagonal in the new ordering. (Note have 107d4bb536fSBarry Smith to permute the v[k] values as well, and use a fixed bound on the 108d4bb536fSBarry Smith quality of repla rather then looking for the absolute largest. 109d4bb536fSBarry Smith */ 11048b35521SBarry Smith for (k=0; k<nz; k++) { 111cddf8d76SBarry Smith if (col[j[k]] > prow && PetscAbsScalar(v[k]) > repla) { 112ad608de0SBarry Smith repl = col[j[k]]; 113cddf8d76SBarry Smith repla = PetscAbsScalar(v[k]); 114ad608de0SBarry Smith } 11548b35521SBarry Smith } 116ad608de0SBarry Smith if (prow == repl) { 117d4bb536fSBarry Smith /* Look for an element that allows us 118ad608de0SBarry Smith to pivot with a previous column. To do this, we need 119ad608de0SBarry Smith to be sure that we don't introduce a zero in a previous 120ad608de0SBarry Smith diagonal */ 121d5d45c9bSBarry Smith if (!MatZeroFindPre_Private(mat,prow,row,col,repla,atol,&repl,&repla)){ 122d4bb536fSBarry Smith SETERRQ(1,0,"Cannot reorder matrix to eliminate zero diagonal entry"); 123ad608de0SBarry Smith } 124ad608de0SBarry Smith } 125ad608de0SBarry Smith SWAP(col[prow],col[repl]); 126ad608de0SBarry Smith } 12790f02eecSBarry Smith ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr); 128ad608de0SBarry Smith } 12948b35521SBarry Smith ierr = ISRestoreIndices(ris,&row); CHKERRQ(ierr); 13048b35521SBarry Smith ierr = ISRestoreIndices(cis,&col); CHKERRQ(ierr); 131*3a40ed3dSBarry Smith PetscFunctionReturn(0); 132ad608de0SBarry Smith } 13348b35521SBarry Smith 13448b35521SBarry Smith 13548b35521SBarry Smith 136