xref: /petsc/src/mat/utils/zerodiag.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
1be1d678aSKris Buschelman 
2ad608de0SBarry Smith /*
3ad608de0SBarry Smith     This file contains routines to reorder a matrix so that the diagonal
448b35521SBarry Smith     elements are nonzero.
5ad608de0SBarry Smith  */
6ad608de0SBarry Smith 
7af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I  "petscmat.h"  I*/
8ad608de0SBarry Smith 
9*9371c9d4SSatish Balay #define SWAP(a, b) \
10*9371c9d4SSatish Balay   { \
11*9371c9d4SSatish Balay     PetscInt _t; \
12*9371c9d4SSatish Balay     _t = a; \
13*9371c9d4SSatish Balay     a  = b; \
14*9371c9d4SSatish Balay     b  = _t; \
15*9371c9d4SSatish Balay   }
1648b35521SBarry Smith 
17ad608de0SBarry Smith /*@
1848b35521SBarry Smith     MatReorderForNonzeroDiagonal - Changes matrix ordering to remove
1948b35521SBarry Smith     zeros from diagonal. This may help in the LU factorization to
2048b35521SBarry Smith     prevent a zero pivot.
21ad608de0SBarry Smith 
22fee21e36SBarry Smith     Collective on Mat
23fee21e36SBarry Smith 
2498a79cdbSBarry Smith     Input Parameters:
2598a79cdbSBarry Smith +   mat  - matrix to reorder
2698a79cdbSBarry Smith -   rmap,cmap - row and column permutations.  Usually obtained from
2791e9ee9fSBarry Smith                MatGetOrdering().
2898a79cdbSBarry Smith 
2915091d37SBarry Smith     Level: intermediate
3015091d37SBarry Smith 
31ad608de0SBarry Smith     Notes:
32ad608de0SBarry Smith     This is not intended as a replacement for pivoting for matrices that
33d252947aSBarry Smith     have ``bad'' structure. It is only a stop-gap measure. Should be called
3491e9ee9fSBarry Smith     after a call to MatGetOrdering(), this routine changes the column
35d252947aSBarry Smith     ordering defined in cis.
36d252947aSBarry Smith 
37106f7b34SBarry Smith     Only works for SeqAIJ matrices
38106f7b34SBarry Smith 
3994b7f48cSBarry Smith     Options Database Keys (When using KSP):
4067b8a455SSatish Balay .      -pc_factor_nonzeros_along_diagonal - Reorder to remove zeros from diagonal
41ad608de0SBarry Smith 
4233f51a72SBarry Smith     Algorithm Notes:
4333f51a72SBarry Smith     Column pivoting is used.
4433f51a72SBarry Smith 
4533f51a72SBarry Smith     1) Choice of column is made by looking at the
4633f51a72SBarry Smith        non-zero elements in the troublesome row for columns that are not yet
4733f51a72SBarry Smith        included (moving from left to right).
4833f51a72SBarry Smith 
4933f51a72SBarry Smith     2) If (1) fails we check all the columns to the left of the current row
50814823dcSBarry Smith        and see if one of them has could be swapped. It can be swapped if
51814823dcSBarry Smith        its corresponding row has a non-zero in the column it is being
52814823dcSBarry Smith        swapped with; to make sure the previous nonzero diagonal remains
53814823dcSBarry Smith        nonzero
5433f51a72SBarry Smith 
55ad608de0SBarry Smith @*/
56*9371c9d4SSatish Balay PetscErrorCode MatReorderForNonzeroDiagonal(Mat mat, PetscReal abstol, IS ris, IS cis) {
5705b94e36SKris Buschelman   PetscFunctionBegin;
58cac4c232SBarry Smith   PetscTryMethod(mat, "MatReorderForNonzeroDiagonal_C", (Mat, PetscReal, IS, IS), (mat, abstol, ris, cis));
5905b94e36SKris Buschelman   PetscFunctionReturn(0);
6005b94e36SKris Buschelman }
6105b94e36SKris Buschelman 
625a576424SJed Brown PETSC_INTERN PetscErrorCode MatGetRow_SeqAIJ(Mat, PetscInt, PetscInt *, PetscInt **, PetscScalar **);
635a576424SJed Brown PETSC_INTERN PetscErrorCode MatRestoreRow_SeqAIJ(Mat, PetscInt, PetscInt *, PetscInt **, PetscScalar **);
64b3cc6726SBarry Smith 
65d9e81513SBarry Smith #include <../src/vec/is/is/impls/general/general.h>
665d0c19d7SBarry Smith 
67*9371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatReorderForNonzeroDiagonal_SeqAIJ(Mat mat, PetscReal abstol, IS ris, IS cis) {
6838baddfdSBarry Smith   PetscInt     prow, k, nz, n, repl, *j, *col, *row, m, *icol, nnz, *jj, kk;
6987828ca2SBarry Smith   PetscScalar *v, *vv;
70329f5518SBarry Smith   PetscReal    repla;
71fd61f322SBarry Smith   IS           icis;
72ad608de0SBarry Smith 
733a40ed3dSBarry Smith   PetscFunctionBegin;
745d0c19d7SBarry Smith   /* access the indices of the IS directly, because it changes them */
755d0c19d7SBarry Smith   row = ((IS_General *)ris->data)->idx;
765d0c19d7SBarry Smith   col = ((IS_General *)cis->data)->idx;
779566063dSJacob Faibussowitsch   PetscCall(ISInvertPermutation(cis, PETSC_DECIDE, &icis));
785d0c19d7SBarry Smith   icol = ((IS_General *)icis->data)->idx;
799566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &m, &n));
80ad608de0SBarry Smith 
81ad608de0SBarry Smith   for (prow = 0; prow < n; prow++) {
829566063dSJacob Faibussowitsch     PetscCall(MatGetRow_SeqAIJ(mat, row[prow], &nz, &j, &v));
838865f1eaSKarl Rupp     for (k = 0; k < nz; k++) {
848865f1eaSKarl Rupp       if (icol[j[k]] == prow) break;
858865f1eaSKarl Rupp     }
8670441072SBarry Smith     if (k >= nz || PetscAbsScalar(v[k]) <= abstol) {
87ad608de0SBarry Smith       /* Element too small or zero; find the best candidate */
88cddf8d76SBarry Smith       repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]);
89d4bb536fSBarry Smith       /*
90fd61f322SBarry Smith           Look for a later column we can swap with this one
91d4bb536fSBarry Smith       */
9248b35521SBarry Smith       for (k = 0; k < nz; k++) {
9333f51a72SBarry Smith         if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) {
94fd61f322SBarry Smith           /* found a suitable later column */
9533f51a72SBarry Smith           repl = icol[j[k]];
9633f51a72SBarry Smith           SWAP(icol[col[prow]], icol[col[repl]]);
97ad608de0SBarry Smith           SWAP(col[prow], col[repl]);
98fd61f322SBarry Smith           goto found;
99fd61f322SBarry Smith         }
100fd61f322SBarry Smith       }
101fd61f322SBarry Smith       /*
102fd61f322SBarry Smith            Did not find a suitable later column so look for an earlier column
103fd61f322SBarry Smith            We need to be sure that we don't introduce a zero in a previous
104fd61f322SBarry Smith            diagonal
105fd61f322SBarry Smith       */
106fd61f322SBarry Smith       for (k = 0; k < nz; k++) {
107fd61f322SBarry Smith         if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) {
108fd61f322SBarry Smith           /* See if this one will work */
109fd61f322SBarry Smith           repl = icol[j[k]];
1109566063dSJacob Faibussowitsch           PetscCall(MatGetRow_SeqAIJ(mat, row[repl], &nnz, &jj, &vv));
111fd61f322SBarry Smith           for (kk = 0; kk < nnz; kk++) {
11270441072SBarry Smith             if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > abstol) {
1139566063dSJacob Faibussowitsch               PetscCall(MatRestoreRow_SeqAIJ(mat, row[repl], &nnz, &jj, &vv));
114fd61f322SBarry Smith               SWAP(icol[col[prow]], icol[col[repl]]);
115fd61f322SBarry Smith               SWAP(col[prow], col[repl]);
116fd61f322SBarry Smith               goto found;
117fd61f322SBarry Smith             }
118fd61f322SBarry Smith           }
1199566063dSJacob Faibussowitsch           PetscCall(MatRestoreRow_SeqAIJ(mat, row[repl], &nnz, &jj, &vv));
120fd61f322SBarry Smith         }
121fd61f322SBarry Smith       }
122fd61f322SBarry Smith       /*
123fd61f322SBarry Smith           No column  suitable; instead check all future rows
124fd61f322SBarry Smith           Note: this will be very slow
125fd61f322SBarry Smith       */
126fd61f322SBarry Smith       for (k = prow + 1; k < n; k++) {
1279566063dSJacob Faibussowitsch         PetscCall(MatGetRow_SeqAIJ(mat, row[k], &nnz, &jj, &vv));
128fd61f322SBarry Smith         for (kk = 0; kk < nnz; kk++) {
12970441072SBarry Smith           if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > abstol) {
130fd61f322SBarry Smith             /* found a row */
131fd61f322SBarry Smith             SWAP(row[prow], row[k]);
132fd61f322SBarry Smith             goto found;
133fd61f322SBarry Smith           }
134fd61f322SBarry Smith         }
1359566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow_SeqAIJ(mat, row[k], &nnz, &jj, &vv));
136fd61f322SBarry Smith       }
137fd61f322SBarry Smith 
138fd61f322SBarry Smith     found:;
139ad608de0SBarry Smith     }
1409566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow_SeqAIJ(mat, row[prow], &nz, &j, &v));
141ad608de0SBarry Smith   }
1429566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&icis));
1433a40ed3dSBarry Smith   PetscFunctionReturn(0);
144ad608de0SBarry Smith }
145