xref: /petsc/src/mat/utils/zerodiag.c (revision 4482741e5b2e2bbc854fb1f8dba65221386520f2)
1 /*$Id: zerodiag.c,v 1.44 2001/08/06 21:16:10 bsmith Exp $*/
2 
3 /*
4     This file contains routines to reorder a matrix so that the diagonal
5     elements are nonzero.
6  */
7 
8 #include "src/mat/matimpl.h"       /*I  "petscmat.h"  I*/
9 
10 #define SWAP(a,b) {int _t; _t = a; a = b; b = _t; }
11 
12 #undef __FUNCT__
13 #define __FUNCT__ "MatReorderForNonzeroDiagonal"
14 /*@
15     MatReorderForNonzeroDiagonal - Changes matrix ordering to remove
16     zeros from diagonal. This may help in the LU factorization to
17     prevent a zero pivot.
18 
19     Collective on Mat
20 
21     Input Parameters:
22 +   mat  - matrix to reorder
23 -   rmap,cmap - row and column permutations.  Usually obtained from
24                MatGetOrdering().
25 
26     Level: intermediate
27 
28     Notes:
29     This is not intended as a replacement for pivoting for matrices that
30     have ``bad'' structure. It is only a stop-gap measure. Should be called
31     after a call to MatGetOrdering(), this routine changes the column
32     ordering defined in cis.
33 
34     Only works for SeqAIJ matrices
35 
36     Options Database Keys (When using KSP):
37 +      -pc_ilu_nonzeros_along_diagonal
38 -      -pc_lu_nonzeros_along_diagonal
39 
40     Algorithm Notes:
41     Column pivoting is used.
42 
43     1) Choice of column is made by looking at the
44        non-zero elements in the troublesome row for columns that are not yet
45        included (moving from left to right).
46 
47     2) If (1) fails we check all the columns to the left of the current row
48        and see if one of them has could be swapped. It can be swapped if
49        its corresponding row has a non-zero in the column it is being
50        swapped with; to make sure the previous nonzero diagonal remains
51        nonzero
52 
53 
54 @*/
55 int MatReorderForNonzeroDiagonal(Mat mat,PetscReal atol,IS ris,IS cis)
56 {
57   int ierr,(*f)(Mat,PetscReal,IS,IS);
58 
59   PetscFunctionBegin;
60   ierr = PetscObjectQueryFunction((PetscObject)mat,"MatReorderForNonzeroDiagonal_C",(void (**)(void))&f);CHKERRQ(ierr);
61   if (f) {
62     ierr = (*f)(mat,atol,ris,cis);CHKERRQ(ierr);
63   }
64   PetscFunctionReturn(0);
65 }
66 
67 EXTERN_C_BEGIN
68 #undef __FUNCT__
69 #define __FUNCT__ "MatReorderForNonzeroDiagonal_SeqAIJ"
70 int MatReorderForNonzeroDiagonal_SeqAIJ(Mat mat,PetscReal atol,IS ris,IS cis)
71 {
72   int         ierr,prow,k,nz,n,repl,*j,*col,*row,m,*icol,nnz,*jj,kk;
73   PetscScalar *v,*vv;
74   PetscReal   repla;
75   IS          icis;
76 
77   PetscFunctionBegin;
78   ierr = ISGetIndices(ris,&row);CHKERRQ(ierr);
79   ierr = ISGetIndices(cis,&col);CHKERRQ(ierr);
80   ierr = ISInvertPermutation(cis,PETSC_DECIDE,&icis);CHKERRQ(ierr);
81   ierr = ISGetIndices(icis,&icol);CHKERRQ(ierr);
82   ierr = MatGetSize(mat,&m,&n);CHKERRQ(ierr);
83 
84   for (prow=0; prow<n; prow++) {
85     ierr = MatGetRow(mat,row[prow],&nz,&j,&v);CHKERRQ(ierr);
86     for (k=0; k<nz; k++) {if (icol[j[k]] == prow) break;}
87     if (k >= nz || PetscAbsScalar(v[k]) <= atol) {
88       /* Element too small or zero; find the best candidate */
89       repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]);
90       /*
91           Look for a later column we can swap with this one
92       */
93       for (k=0; k<nz; k++) {
94 	if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) {
95           /* found a suitable later column */
96 	  repl  = icol[j[k]];
97           SWAP(icol[col[prow]],icol[col[repl]]);
98           SWAP(col[prow],col[repl]);
99           goto found;
100         }
101       }
102       /*
103            Did not find a suitable later column so look for an earlier column
104 	   We need to be sure that we don't introduce a zero in a previous
105 	   diagonal
106       */
107       for (k=0; k<nz; k++) {
108         if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) {
109           /* See if this one will work */
110           repl  = icol[j[k]];
111           ierr = MatGetRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr);
112           for (kk=0; kk<nnz; kk++) {
113             if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) {
114               ierr = MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr);
115               SWAP(icol[col[prow]],icol[col[repl]]);
116               SWAP(col[prow],col[repl]);
117               goto found;
118 	    }
119           }
120           ierr = MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr);
121         }
122       }
123       /*
124           No column  suitable; instead check all future rows
125           Note: this will be very slow
126       */
127       for (k=prow+1; k<n; k++) {
128         ierr = MatGetRow(mat,row[k],&nnz,&jj,&vv);CHKERRQ(ierr);
129         for (kk=0; kk<nnz; kk++) {
130           if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) {
131             /* found a row */
132             SWAP(row[prow],row[k]);
133             goto found;
134           }
135         }
136         ierr = MatRestoreRow(mat,row[k],&nnz,&jj,&vv);CHKERRQ(ierr);
137       }
138 
139       found:;
140     }
141     ierr = MatRestoreRow(mat,row[prow],&nz,&j,&v);CHKERRQ(ierr);
142   }
143   ierr = ISRestoreIndices(ris,&row);CHKERRQ(ierr);
144   ierr = ISRestoreIndices(cis,&col);CHKERRQ(ierr);
145   ierr = ISRestoreIndices(icis,&icol);CHKERRQ(ierr);
146   ierr = ISDestroy(icis);CHKERRQ(ierr);
147   PetscFunctionReturn(0);
148 }
149 EXTERN_C_END
150 
151 
152