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; }
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 KSP):
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,(*f)(Mat,PetscReal,IS,IS);
60: PetscObjectQueryFunction((PetscObject)mat,"MatReorderForNonzeroDiagonal_C",(void (**)(void))&f);
61: if (f) {
62: (*f)(mat,atol,ris,cis);
63: }
64: return(0);
65: }
67: EXTERN_C_BEGIN
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;
78: ISGetIndices(ris,&row);
79: ISGetIndices(cis,&col);
80: ISInvertPermutation(cis,PETSC_DECIDE,&icis);
81: ISGetIndices(icis,&icol);
82: MatGetSize(mat,&m,&n);
84: for (prow=0; prow<n; prow++) {
85: MatGetRow(mat,row[prow],&nz,&j,&v);
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: MatGetRow(mat,row[repl],&nnz,&jj,&vv);
112: for (kk=0; kk<nnz; kk++) {
113: if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) {
114: MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);
115: SWAP(icol[col[prow]],icol[col[repl]]);
116: SWAP(col[prow],col[repl]);
117: goto found;
118: }
119: }
120: MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);
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: MatGetRow(mat,row[k],&nnz,&jj,&vv);
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: MatRestoreRow(mat,row[k],&nnz,&jj,&vv);
137: }
139: found:;
140: }
141: MatRestoreRow(mat,row[prow],&nz,&j,&v);
142: }
143: ISRestoreIndices(ris,&row);
144: ISRestoreIndices(cis,&col);
145: ISRestoreIndices(icis,&icol);
146: ISDestroy(icis);
147: return(0);
148: }
149: EXTERN_C_END