xref: /petsc/src/mat/utils/zerodiag.c (revision 27430b45d0a5eedd7547ed99d6048b6750b3fa8a)
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 
99371c9d4SSatish Balay #define SWAP(a, b) \
109371c9d4SSatish Balay   { \
119371c9d4SSatish Balay     PetscInt _t; \
129371c9d4SSatish Balay     _t = a; \
139371c9d4SSatish Balay     a  = b; \
149371c9d4SSatish Balay     b  = _t; \
159371c9d4SSatish Balay   }
1648b35521SBarry Smith 
17ad608de0SBarry Smith /*@
1848b35521SBarry Smith     MatReorderForNonzeroDiagonal - Changes matrix ordering to remove
1911a5261eSBarry Smith     zeros from diagonal. This may help in the `PCLU` factorization to
2048b35521SBarry Smith     prevent a zero pivot.
21ad608de0SBarry Smith 
22c3339decSBarry Smith     Collective
23fee21e36SBarry Smith 
2498a79cdbSBarry Smith     Input Parameters:
2598a79cdbSBarry Smith +   mat  - matrix to reorder
2698a79cdbSBarry Smith -   rmap,cmap - row and column permutations.  Usually obtained from
2711a5261eSBarry Smith                `MatGetOrdering()`.
2898a79cdbSBarry Smith 
2915091d37SBarry Smith     Level: intermediate
3015091d37SBarry Smith 
31*27430b45SBarry Smith     Options Database Key:
32*27430b45SBarry Smith .      -pc_factor_nonzeros_along_diagonal - Reorder to remove zeros from diagonal
33*27430b45SBarry Smith 
34ad608de0SBarry Smith     Notes:
35ad608de0SBarry Smith     This is not intended as a replacement for pivoting for matrices that
36d252947aSBarry Smith     have ``bad'' structure. It is only a stop-gap measure. Should be called
3711a5261eSBarry Smith     after a call to `MatGetOrdering()`, this routine changes the column
38d252947aSBarry Smith     ordering defined in cis.
39d252947aSBarry Smith 
4011a5261eSBarry Smith     Only works for `MATSEQAIJ` matrices
41106f7b34SBarry Smith 
42*27430b45SBarry Smith     Developer 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 
55*27430b45SBarry Smith .seealso: `Mat`
56ad608de0SBarry Smith @*/
57d71ae5a4SJacob Faibussowitsch PetscErrorCode MatReorderForNonzeroDiagonal(Mat mat, PetscReal abstol, IS ris, IS cis)
58d71ae5a4SJacob Faibussowitsch {
5905b94e36SKris Buschelman   PetscFunctionBegin;
60cac4c232SBarry Smith   PetscTryMethod(mat, "MatReorderForNonzeroDiagonal_C", (Mat, PetscReal, IS, IS), (mat, abstol, ris, cis));
613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6205b94e36SKris Buschelman }
6305b94e36SKris Buschelman 
645a576424SJed Brown PETSC_INTERN PetscErrorCode MatGetRow_SeqAIJ(Mat, PetscInt, PetscInt *, PetscInt **, PetscScalar **);
655a576424SJed Brown PETSC_INTERN PetscErrorCode MatRestoreRow_SeqAIJ(Mat, PetscInt, PetscInt *, PetscInt **, PetscScalar **);
66b3cc6726SBarry Smith 
67d9e81513SBarry Smith #include <../src/vec/is/is/impls/general/general.h>
685d0c19d7SBarry Smith 
69d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatReorderForNonzeroDiagonal_SeqAIJ(Mat mat, PetscReal abstol, IS ris, IS cis)
70d71ae5a4SJacob Faibussowitsch {
7138baddfdSBarry Smith   PetscInt     prow, k, nz, n, repl, *j, *col, *row, m, *icol, nnz, *jj, kk;
7287828ca2SBarry Smith   PetscScalar *v, *vv;
73329f5518SBarry Smith   PetscReal    repla;
74fd61f322SBarry Smith   IS           icis;
75ad608de0SBarry Smith 
763a40ed3dSBarry Smith   PetscFunctionBegin;
775d0c19d7SBarry Smith   /* access the indices of the IS directly, because it changes them */
785d0c19d7SBarry Smith   row = ((IS_General *)ris->data)->idx;
795d0c19d7SBarry Smith   col = ((IS_General *)cis->data)->idx;
809566063dSJacob Faibussowitsch   PetscCall(ISInvertPermutation(cis, PETSC_DECIDE, &icis));
815d0c19d7SBarry Smith   icol = ((IS_General *)icis->data)->idx;
829566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat, &m, &n));
83ad608de0SBarry Smith 
84ad608de0SBarry Smith   for (prow = 0; prow < n; prow++) {
859566063dSJacob Faibussowitsch     PetscCall(MatGetRow_SeqAIJ(mat, row[prow], &nz, &j, &v));
868865f1eaSKarl Rupp     for (k = 0; k < nz; k++) {
878865f1eaSKarl Rupp       if (icol[j[k]] == prow) break;
888865f1eaSKarl Rupp     }
8970441072SBarry Smith     if (k >= nz || PetscAbsScalar(v[k]) <= abstol) {
90ad608de0SBarry Smith       /* Element too small or zero; find the best candidate */
91cddf8d76SBarry Smith       repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]);
92d4bb536fSBarry Smith       /*
93fd61f322SBarry Smith           Look for a later column we can swap with this one
94d4bb536fSBarry Smith       */
9548b35521SBarry Smith       for (k = 0; k < nz; k++) {
9633f51a72SBarry Smith         if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) {
97fd61f322SBarry Smith           /* found a suitable later column */
9833f51a72SBarry Smith           repl = icol[j[k]];
9933f51a72SBarry Smith           SWAP(icol[col[prow]], icol[col[repl]]);
100ad608de0SBarry Smith           SWAP(col[prow], col[repl]);
101fd61f322SBarry Smith           goto found;
102fd61f322SBarry Smith         }
103fd61f322SBarry Smith       }
104fd61f322SBarry Smith       /*
105fd61f322SBarry Smith            Did not find a suitable later column so look for an earlier column
106fd61f322SBarry Smith            We need to be sure that we don't introduce a zero in a previous
107fd61f322SBarry Smith            diagonal
108fd61f322SBarry Smith       */
109fd61f322SBarry Smith       for (k = 0; k < nz; k++) {
110fd61f322SBarry Smith         if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) {
111fd61f322SBarry Smith           /* See if this one will work */
112fd61f322SBarry Smith           repl = icol[j[k]];
1139566063dSJacob Faibussowitsch           PetscCall(MatGetRow_SeqAIJ(mat, row[repl], &nnz, &jj, &vv));
114fd61f322SBarry Smith           for (kk = 0; kk < nnz; kk++) {
11570441072SBarry Smith             if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > abstol) {
1169566063dSJacob Faibussowitsch               PetscCall(MatRestoreRow_SeqAIJ(mat, row[repl], &nnz, &jj, &vv));
117fd61f322SBarry Smith               SWAP(icol[col[prow]], icol[col[repl]]);
118fd61f322SBarry Smith               SWAP(col[prow], col[repl]);
119fd61f322SBarry Smith               goto found;
120fd61f322SBarry Smith             }
121fd61f322SBarry Smith           }
1229566063dSJacob Faibussowitsch           PetscCall(MatRestoreRow_SeqAIJ(mat, row[repl], &nnz, &jj, &vv));
123fd61f322SBarry Smith         }
124fd61f322SBarry Smith       }
125fd61f322SBarry Smith       /*
126fd61f322SBarry Smith           No column  suitable; instead check all future rows
127fd61f322SBarry Smith           Note: this will be very slow
128fd61f322SBarry Smith       */
129fd61f322SBarry Smith       for (k = prow + 1; k < n; k++) {
1309566063dSJacob Faibussowitsch         PetscCall(MatGetRow_SeqAIJ(mat, row[k], &nnz, &jj, &vv));
131fd61f322SBarry Smith         for (kk = 0; kk < nnz; kk++) {
13270441072SBarry Smith           if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > abstol) {
133fd61f322SBarry Smith             /* found a row */
134fd61f322SBarry Smith             SWAP(row[prow], row[k]);
135fd61f322SBarry Smith             goto found;
136fd61f322SBarry Smith           }
137fd61f322SBarry Smith         }
1389566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow_SeqAIJ(mat, row[k], &nnz, &jj, &vv));
139fd61f322SBarry Smith       }
140fd61f322SBarry Smith 
141fd61f322SBarry Smith     found:;
142ad608de0SBarry Smith     }
1439566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow_SeqAIJ(mat, row[prow], &nz, &j, &v));
144ad608de0SBarry Smith   }
1459566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&icis));
1463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
147ad608de0SBarry Smith }
148