Actual source code: zerodiag.c
1: /*$Id: zerodiag.c,v 1.44 2001/08/06 21:16:10 bsmith Exp $*/
3: /*
4: This file contains routines to reorder a matrix so that the diagonal
5: elements are nonzero.
6: */
8: #include src/mat/matimpl.h
10: #define SWAP(a,b) {int _t; _t = a; a = b; b = _t; }
12: #undef __FUNCT__
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.
19: Collective on Mat
21: Input Parameters:
22: + mat - matrix to reorder
23: - rmap,cmap - row and column permutations. Usually obtained from
24: MatGetOrdering().
26: Level: intermediate
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.
34: Only works for SeqAIJ matrices
36: Options Database Keys (When using SLES):
37: + -pc_ilu_nonzeros_along_diagonal
38: - -pc_lu_nonzeros_along_diagonal
40: Algorithm Notes:
41: Column pivoting is used.
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
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;
67:
68: PetscTypeCompare((PetscObject)mat,MATSEQAIJ,&flg);
69: if (!flg) SETERRQ(1,"Matrix must be of type SeqAIJ");
71: ISGetIndices(ris,&row);
72: ISGetIndices(cis,&col);
73: ISInvertPermutation(cis,PETSC_DECIDE,&icis);
74: ISGetIndices(icis,&icol);
75: MatGetSize(mat,&m,&n);
77: for (prow=0; prow<n; prow++) {
78: MatGetRow(mat,row[prow],&nz,&j,&v);
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: MatGetRow(mat,row[repl],&nnz,&jj,&vv);
105: for (kk=0; kk<nnz; kk++) {
106: if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) {
107: MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);
108: SWAP(icol[col[prow]],icol[col[repl]]);
109: SWAP(col[prow],col[repl]);
110: goto found;
111: }
112: }
113: MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);
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: MatGetRow(mat,row[k],&nnz,&jj,&vv);
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: MatRestoreRow(mat,row[k],&nnz,&jj,&vv);
130: }
132: found:;
133: }
134: MatRestoreRow(mat,row[prow],&nz,&j,&v);
135: }
136: ISRestoreIndices(ris,&row);
137: ISRestoreIndices(cis,&col);
138: ISRestoreIndices(icis,&icol);
139: ISDestroy(icis);
140: return(0);
141: }