xref: /petsc/src/mat/utils/zerodiag.c (revision 08b6dcc09476afde1cce98cc04f33d98301cef47)
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 SLES):
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,prow,k,nz,n,repl,*j,*col,*row,m,*icol,nnz,*jj,kk;
58   PetscScalar *v,*vv;
59   PetscReal   repla;
60   IS          icis;
61   PetscTruth  flg;
62 
63   PetscFunctionBegin;
64   PetscValidHeaderSpecific(mat,MAT_COOKIE);
65   PetscValidHeaderSpecific(ris,IS_COOKIE);
66   PetscValidHeaderSpecific(cis,IS_COOKIE);
67 
68   ierr = PetscTypeCompare((PetscObject)mat,MATSEQAIJ,&flg);CHKERRQ(ierr);
69   if (!flg) SETERRQ(1,"Matrix must be of type SeqAIJ");
70 
71   ierr = ISGetIndices(ris,&row);CHKERRQ(ierr);
72   ierr = ISGetIndices(cis,&col);CHKERRQ(ierr);
73   ierr = ISInvertPermutation(cis,PETSC_DECIDE,&icis);CHKERRQ(ierr);
74   ierr = ISGetIndices(icis,&icol);CHKERRQ(ierr);
75   ierr = MatGetSize(mat,&m,&n);CHKERRQ(ierr);
76 
77   for (prow=0; prow<n; prow++) {
78     ierr = MatGetRow(mat,row[prow],&nz,&j,&v);CHKERRQ(ierr);
79     for (k=0; k<nz; k++) {if (icol[j[k]] == prow) break;}
80     if (k >= nz || PetscAbsScalar(v[k]) <= atol) {
81       /* Element too small or zero; find the best candidate */
82       repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]);
83       /*
84           Look for a later column we can swap with this one
85       */
86       for (k=0; k<nz; k++) {
87 	if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) {
88           /* found a suitable later column */
89 	  repl  = icol[j[k]];
90           SWAP(icol[col[prow]],icol[col[repl]]);
91           SWAP(col[prow],col[repl]);
92           goto found;
93         }
94       }
95       /*
96            Did not find a suitable later column so look for an earlier column
97 	   We need to be sure that we don't introduce a zero in a previous
98 	   diagonal
99       */
100       for (k=0; k<nz; k++) {
101         if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) {
102           /* See if this one will work */
103           repl  = icol[j[k]];
104           ierr = MatGetRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr);
105           for (kk=0; kk<nnz; kk++) {
106             if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) {
107               ierr = MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr);
108               SWAP(icol[col[prow]],icol[col[repl]]);
109               SWAP(col[prow],col[repl]);
110               goto found;
111 	    }
112           }
113           ierr = MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr);
114         }
115       }
116       /*
117           No column  suitable; instead check all future rows
118           Note: this will be very slow
119       */
120       for (k=prow+1; k<n; k++) {
121         ierr = MatGetRow(mat,row[k],&nnz,&jj,&vv);CHKERRQ(ierr);
122         for (kk=0; kk<nnz; kk++) {
123           if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) {
124             /* found a row */
125             SWAP(row[prow],row[k]);
126             goto found;
127           }
128         }
129         ierr = MatRestoreRow(mat,row[k],&nnz,&jj,&vv);CHKERRQ(ierr);
130       }
131 
132       found:;
133     }
134     ierr = MatRestoreRow(mat,row[prow],&nz,&j,&v);CHKERRQ(ierr);
135   }
136   ierr = ISRestoreIndices(ris,&row);CHKERRQ(ierr);
137   ierr = ISRestoreIndices(cis,&col);CHKERRQ(ierr);
138   ierr = ISRestoreIndices(icis,&icol);CHKERRQ(ierr);
139   ierr = ISDestroy(icis);CHKERRQ(ierr);
140   PetscFunctionReturn(0);
141 }
142 
143 
144 
145