xref: /petsc/src/mat/utils/axpy.c (revision 5b12497f4ab2fae16b3dbcff7d3c608aa116b75c)
1af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I   "petscmat.h"  I*/
26f79c3a4SBarry Smith 
MatTransposeAXPY_Private(Mat Y,PetscScalar a,Mat X,MatStructure str,Mat T)3d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTransposeAXPY_Private(Mat Y, PetscScalar a, Mat X, MatStructure str, Mat T)
4d71ae5a4SJacob Faibussowitsch {
5d54c938cSPierre Jolivet   Mat         A, F;
64166f22eSPierre Jolivet   PetscScalar vshift, vscale;
75f80ce2aSJacob Faibussowitsch   PetscErrorCode (*f)(Mat, Mat *);
8d54c938cSPierre Jolivet 
9d54c938cSPierre Jolivet   PetscFunctionBegin;
104166f22eSPierre Jolivet   if (T == X) PetscCall(MatShellGetScalingShifts(T, &vshift, &vscale, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
114166f22eSPierre Jolivet   else {
124166f22eSPierre Jolivet     vshift = 0.0;
134166f22eSPierre Jolivet     vscale = 1.0;
144166f22eSPierre Jolivet   }
159566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)T, "MatTransposeGetMat_C", &f));
16d54c938cSPierre Jolivet   if (f) {
179566063dSJacob Faibussowitsch     PetscCall(MatTransposeGetMat(T, &A));
18d54c938cSPierre Jolivet     if (T == X) {
19013e2dc7SBarry Smith       PetscCall(PetscInfo(NULL, "Explicitly transposing X of type MATTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
209566063dSJacob Faibussowitsch       PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &F));
21d54c938cSPierre Jolivet       A = Y;
22d54c938cSPierre Jolivet     } else {
23013e2dc7SBarry Smith       PetscCall(PetscInfo(NULL, "Transposing X because Y of type MATTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
249566063dSJacob Faibussowitsch       PetscCall(MatTranspose(X, MAT_INITIAL_MATRIX, &F));
25d54c938cSPierre Jolivet     }
26d54c938cSPierre Jolivet   } else {
279566063dSJacob Faibussowitsch     PetscCall(MatHermitianTransposeGetMat(T, &A));
28d54c938cSPierre Jolivet     if (T == X) {
2952cd20c4SPierre Jolivet       PetscCall(PetscInfo(NULL, "Explicitly Hermitian transposing X of type MATHERMITIANTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
309566063dSJacob Faibussowitsch       PetscCall(MatHermitianTranspose(A, MAT_INITIAL_MATRIX, &F));
31d54c938cSPierre Jolivet       A = Y;
32d54c938cSPierre Jolivet     } else {
3352cd20c4SPierre Jolivet       PetscCall(PetscInfo(NULL, "Hermitian transposing X because Y of type MATHERMITIANTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
349566063dSJacob Faibussowitsch       PetscCall(MatHermitianTranspose(X, MAT_INITIAL_MATRIX, &F));
35d54c938cSPierre Jolivet     }
36d54c938cSPierre Jolivet   }
374166f22eSPierre Jolivet   PetscCall(MatAXPY(A, a * vscale, F, str));
384166f22eSPierre Jolivet   PetscCall(MatShift(A, a * vshift));
399566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&F));
403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41d54c938cSPierre Jolivet }
42d54c938cSPierre Jolivet 
MatAXPY_BasicWithTypeCompare(Mat Y,PetscScalar a,Mat X,MatStructure str)43b20dac60SPierre Jolivet static PetscErrorCode MatAXPY_BasicWithTypeCompare(Mat Y, PetscScalar a, Mat X, MatStructure str)
44b20dac60SPierre Jolivet {
45b20dac60SPierre Jolivet   PetscBool flg;
46b20dac60SPierre Jolivet 
47b20dac60SPierre Jolivet   PetscFunctionBegin;
48b20dac60SPierre Jolivet   PetscCall(MatIsShell(Y, &flg));
49b20dac60SPierre Jolivet   if (flg) { /* MatShell has special support for AXPY */
50b20dac60SPierre Jolivet     PetscErrorCode (*f)(Mat, PetscScalar, Mat, MatStructure);
51b20dac60SPierre Jolivet 
5257d50842SBarry Smith     PetscCall(MatGetOperation(Y, MATOP_AXPY, (PetscErrorCodeFn **)&f));
53b20dac60SPierre Jolivet     if (f) {
54b20dac60SPierre Jolivet       PetscCall((*f)(Y, a, X, str));
55b20dac60SPierre Jolivet       PetscFunctionReturn(PETSC_SUCCESS);
56b20dac60SPierre Jolivet     }
57b20dac60SPierre Jolivet   } else {
58b20dac60SPierre Jolivet     /* no need to preallocate if Y is dense */
59b20dac60SPierre Jolivet     PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &flg, MATSEQDENSE, MATMPIDENSE, ""));
60b20dac60SPierre Jolivet     if (flg) {
61b20dac60SPierre Jolivet       PetscCall(PetscObjectTypeCompare((PetscObject)X, MATNEST, &flg));
62b20dac60SPierre Jolivet       if (flg) {
63b20dac60SPierre Jolivet         PetscCall(MatAXPY_Dense_Nest(Y, a, X));
64b20dac60SPierre Jolivet         PetscFunctionReturn(PETSC_SUCCESS);
65b20dac60SPierre Jolivet       }
66b20dac60SPierre Jolivet     }
67b20dac60SPierre Jolivet     PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &flg, MATSCALAPACK, MATELEMENTAL, ""));
68b20dac60SPierre Jolivet     if (flg) { /* Avoid MatAXPY_Basic() due to missing MatGetRow() */
69b20dac60SPierre Jolivet       Mat C;
70b20dac60SPierre Jolivet 
71b20dac60SPierre Jolivet       PetscCall(MatConvert(X, ((PetscObject)Y)->type_name, MAT_INITIAL_MATRIX, &C));
72b20dac60SPierre Jolivet       PetscCall(MatAXPY(Y, a, C, str));
73b20dac60SPierre Jolivet       PetscCall(MatDestroy(&C));
74b20dac60SPierre Jolivet       PetscFunctionReturn(PETSC_SUCCESS);
75b20dac60SPierre Jolivet     }
76b20dac60SPierre Jolivet   }
77b20dac60SPierre Jolivet   PetscCall(MatAXPY_Basic(Y, a, X, str));
78b20dac60SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
79b20dac60SPierre Jolivet }
80b20dac60SPierre Jolivet 
8106be10caSBarry Smith /*@
8221c89e3eSBarry Smith   MatAXPY - Computes Y = a*X + Y.
836f79c3a4SBarry Smith 
84c3339decSBarry Smith   Logically Collective
85fee21e36SBarry Smith 
8698a79cdbSBarry Smith   Input Parameters:
87607cd303SBarry Smith + a   - the scalar multiplier
88607cd303SBarry Smith . X   - the first matrix
89607cd303SBarry Smith . Y   - the second matrix
9027430b45SBarry Smith - str - either `SAME_NONZERO_PATTERN`, `DIFFERENT_NONZERO_PATTERN`, `UNKNOWN_NONZERO_PATTERN`, or `SUBSET_NONZERO_PATTERN` (nonzeros of `X` is a subset of `Y`'s)
91edf9a46cSStefano Zampini 
922860a424SLois Curfman McInnes   Level: intermediate
932860a424SLois Curfman McInnes 
941cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatAYPX()`
9506be10caSBarry Smith  @*/
MatAXPY(Mat Y,PetscScalar a,Mat X,MatStructure str)96d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY(Mat Y, PetscScalar a, Mat X, MatStructure str)
97d71ae5a4SJacob Faibussowitsch {
98646531bbSStefano Zampini   PetscInt  M1, M2, N1, N2;
99c1ac3661SBarry Smith   PetscInt  m1, m2, n1, n2;
100b20dac60SPierre Jolivet   PetscBool sametype, transpose;
1016f79c3a4SBarry Smith 
1023a40ed3dSBarry Smith   PetscFunctionBegin;
1030700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
104c5eb9154SBarry Smith   PetscValidLogicalCollectiveScalar(Y, a, 2);
105646531bbSStefano Zampini   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
106646531bbSStefano Zampini   PetscCheckSameComm(Y, 1, X, 3);
1079566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X, &M1, &N1));
1089566063dSJacob Faibussowitsch   PetscCall(MatGetSize(Y, &M2, &N2));
1099566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(X, &m1, &n1));
1109566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Y, &m2, &n2));
1112c71b3e2SJacob Faibussowitsch   PetscCheck(M1 == M2 && N1 == N2, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_SIZ, "Non conforming matrix add: global sizes X %" PetscInt_FMT " x %" PetscInt_FMT ", Y %" PetscInt_FMT " x %" PetscInt_FMT, M1, N1, M2, N2);
1122c71b3e2SJacob Faibussowitsch   PetscCheck(m1 == m2 && n1 == n2, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Non conforming matrix add: local sizes X %" PetscInt_FMT " x %" PetscInt_FMT ", Y %" PetscInt_FMT " x %" PetscInt_FMT, m1, n1, m2, n2);
1132c71b3e2SJacob Faibussowitsch   PetscCheck(Y->assembled, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix (Y)");
1142c71b3e2SJacob Faibussowitsch   PetscCheck(X->assembled, PetscObjectComm((PetscObject)X), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix (X)");
1153ba16761SJacob Faibussowitsch   if (a == (PetscScalar)0.0) PetscFunctionReturn(PETSC_SUCCESS);
116edf9a46cSStefano Zampini   if (Y == X) {
1179566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 1.0 + a));
1183ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
119edf9a46cSStefano Zampini   }
120013e2dc7SBarry Smith   PetscCall(PetscObjectObjectTypeCompare((PetscObject)X, (PetscObject)Y, &sametype));
1219566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(MAT_AXPY, Y, 0, 0, 0));
12293c87e65SStefano Zampini   if (Y->ops->axpy && (sametype || X->ops->axpy == Y->ops->axpy)) {
123dbbe0bcdSBarry Smith     PetscUseTypeMethod(Y, axpy, a, X, str);
124d4bb536fSBarry Smith   } else {
125013e2dc7SBarry Smith     PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &transpose, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
126a683ea4aSPierre Jolivet     if (transpose) {
1279566063dSJacob Faibussowitsch       PetscCall(MatTransposeAXPY_Private(Y, a, X, str, X));
128a683ea4aSPierre Jolivet     } else {
129013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)Y, &transpose, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
130a683ea4aSPierre Jolivet       if (transpose) {
1319566063dSJacob Faibussowitsch         PetscCall(MatTransposeAXPY_Private(Y, a, X, str, Y));
132a683ea4aSPierre Jolivet       } else {
133b20dac60SPierre Jolivet         PetscCall(MatAXPY_BasicWithTypeCompare(Y, a, X, str));
134a683ea4aSPierre Jolivet       }
135a683ea4aSPierre Jolivet     }
1362e37cc59SJose E. Roman   }
1379566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(MAT_AXPY, Y, 0, 0, 0));
1383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
139607cd303SBarry Smith }
140607cd303SBarry Smith 
MatAXPY_Basic_Preallocate(Mat Y,Mat X,Mat * B)141d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_Basic_Preallocate(Mat Y, Mat X, Mat *B)
142d71ae5a4SJacob Faibussowitsch {
14327afe9e8SStefano Zampini   PetscErrorCode (*preall)(Mat, Mat, Mat *) = NULL;
144646531bbSStefano Zampini 
145646531bbSStefano Zampini   PetscFunctionBegin;
146646531bbSStefano Zampini   /* look for any available faster alternative to the general preallocator */
1479566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)Y, "MatAXPYGetPreallocation_C", &preall));
148646531bbSStefano Zampini   if (preall) {
1499566063dSJacob Faibussowitsch     PetscCall((*preall)(Y, X, B));
150646531bbSStefano Zampini   } else { /* Use MatPrellocator, assumes same row-col distribution */
151646531bbSStefano Zampini     Mat      preallocator;
152646531bbSStefano Zampini     PetscInt r, rstart, rend;
153646531bbSStefano Zampini     PetscInt m, n, M, N;
154646531bbSStefano Zampini 
1559566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(Y));
1569566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(X));
1579566063dSJacob Faibussowitsch     PetscCall(MatGetSize(Y, &M, &N));
1589566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(Y, &m, &n));
1599566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &preallocator));
1609566063dSJacob Faibussowitsch     PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
1619566063dSJacob Faibussowitsch     PetscCall(MatSetLayouts(preallocator, Y->rmap, Y->cmap));
1629566063dSJacob Faibussowitsch     PetscCall(MatSetUp(preallocator));
1639566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(preallocator, &rstart, &rend));
164646531bbSStefano Zampini     for (r = rstart; r < rend; ++r) {
165646531bbSStefano Zampini       PetscInt           ncols;
166646531bbSStefano Zampini       const PetscInt    *row;
167646531bbSStefano Zampini       const PetscScalar *vals;
168646531bbSStefano Zampini 
1699566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, r, &ncols, &row, &vals));
1709566063dSJacob Faibussowitsch       PetscCall(MatSetValues(preallocator, 1, &r, ncols, row, vals, INSERT_VALUES));
1719566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, r, &ncols, &row, &vals));
1729566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, r, &ncols, &row, &vals));
1739566063dSJacob Faibussowitsch       PetscCall(MatSetValues(preallocator, 1, &r, ncols, row, vals, INSERT_VALUES));
1749566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, r, &ncols, &row, &vals));
175646531bbSStefano Zampini     }
1769566063dSJacob Faibussowitsch     PetscCall(MatSetOption(preallocator, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
1779566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
1789566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
1799566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(Y));
1809566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(X));
181646531bbSStefano Zampini 
1829566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), B));
1839566063dSJacob Faibussowitsch     PetscCall(MatSetType(*B, ((PetscObject)Y)->type_name));
1849566063dSJacob Faibussowitsch     PetscCall(MatSetLayouts(*B, Y->rmap, Y->cmap));
1859566063dSJacob Faibussowitsch     PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_FALSE, *B));
1869566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&preallocator));
187646531bbSStefano Zampini   }
1883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
189646531bbSStefano Zampini }
190646531bbSStefano Zampini 
MatAXPY_Basic(Mat Y,PetscScalar a,Mat X,MatStructure str)191d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_Basic(Mat Y, PetscScalar a, Mat X, MatStructure str)
192d71ae5a4SJacob Faibussowitsch {
193edf9a46cSStefano Zampini   PetscFunctionBegin;
194b20dac60SPierre Jolivet   if (str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN) {
195b20dac60SPierre Jolivet     PetscBool isdense;
196edf9a46cSStefano Zampini 
19793c87e65SStefano Zampini     /* no need to preallocate if Y is dense */
1989566063dSJacob Faibussowitsch     PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isdense, MATSEQDENSE, MATMPIDENSE, ""));
199b20dac60SPierre Jolivet     if (isdense) str = SUBSET_NONZERO_PATTERN;
200be705e3aSPierre Jolivet   }
201a6ab3590SBarry Smith   if (str != DIFFERENT_NONZERO_PATTERN && str != UNKNOWN_NONZERO_PATTERN) {
202edf9a46cSStefano Zampini     PetscInt           i, start, end, j, ncols, m, n;
20338baddfdSBarry Smith     const PetscInt    *row;
204b3cc6726SBarry Smith     PetscScalar       *val;
205b3cc6726SBarry Smith     const PetscScalar *vals;
206*799b351eSPierre Jolivet     PetscBool          option;
207607cd303SBarry Smith 
2089566063dSJacob Faibussowitsch     PetscCall(MatGetSize(X, &m, &n));
2099566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(X, &start, &end));
2109566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(X));
211f4df32b1SMatthew Knepley     if (a == 1.0) {
212d4bb536fSBarry Smith       for (i = start; i < end; i++) {
2139566063dSJacob Faibussowitsch         PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
2149566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Y, 1, &i, ncols, row, vals, ADD_VALUES));
2159566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
216d4bb536fSBarry Smith       }
217d4bb536fSBarry Smith     } else {
21821a3365eSStefano Zampini       PetscInt vs = 100;
21921a3365eSStefano Zampini       /* realloc if needed, as this function may be used in parallel */
2209566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(vs, &val));
22106be10caSBarry Smith       for (i = start; i < end; i++) {
2229566063dSJacob Faibussowitsch         PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
22321a3365eSStefano Zampini         if (vs < ncols) {
22421a3365eSStefano Zampini           vs = PetscMin(2 * ncols, n);
2259566063dSJacob Faibussowitsch           PetscCall(PetscRealloc(vs * sizeof(*val), &val));
2266f79c3a4SBarry Smith         }
22721a3365eSStefano Zampini         for (j = 0; j < ncols; j++) val[j] = a * vals[j];
2289566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Y, 1, &i, ncols, row, val, ADD_VALUES));
2299566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
2306f79c3a4SBarry Smith       }
2319566063dSJacob Faibussowitsch       PetscCall(PetscFree(val));
232d4bb536fSBarry Smith     }
2339566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(X));
234*799b351eSPierre Jolivet     PetscCall(MatGetOption(Y, MAT_NO_OFF_PROC_ENTRIES, &option));
235*799b351eSPierre Jolivet     PetscCall(MatSetOption(Y, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
2369566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
2379566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
238*799b351eSPierre Jolivet     PetscCall(MatSetOption(Y, MAT_NO_OFF_PROC_ENTRIES, option));
239edf9a46cSStefano Zampini   } else {
240edf9a46cSStefano Zampini     Mat B;
241edf9a46cSStefano Zampini 
2429566063dSJacob Faibussowitsch     PetscCall(MatAXPY_Basic_Preallocate(Y, X, &B));
2439566063dSJacob Faibussowitsch     PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str));
2449566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(Y, &B));
245edf9a46cSStefano Zampini   }
2463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2476f79c3a4SBarry Smith }
248052efed2SBarry Smith 
MatAXPY_BasicWithPreallocation(Mat B,Mat Y,PetscScalar a,Mat X,MatStructure str)249d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_BasicWithPreallocation(Mat B, Mat Y, PetscScalar a, Mat X, MatStructure str)
250d71ae5a4SJacob Faibussowitsch {
251ec7775f6SShri Abhyankar   PetscInt           i, start, end, j, ncols, m, n;
252ec7775f6SShri Abhyankar   const PetscInt    *row;
253ec7775f6SShri Abhyankar   PetscScalar       *val;
254ec7775f6SShri Abhyankar   const PetscScalar *vals;
255*799b351eSPierre Jolivet   PetscBool          option;
256ec7775f6SShri Abhyankar 
257ec7775f6SShri Abhyankar   PetscFunctionBegin;
2589566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X, &m, &n));
2599566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(X, &start, &end));
2609566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(Y));
2619566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(X));
262ec7775f6SShri Abhyankar   if (a == 1.0) {
263ec7775f6SShri Abhyankar     for (i = start; i < end; i++) {
2649566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, i, &ncols, &row, &vals));
2659566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2669566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, i, &ncols, &row, &vals));
267ec7775f6SShri Abhyankar 
2689566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
2699566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2709566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
271ec7775f6SShri Abhyankar     }
272ec7775f6SShri Abhyankar   } else {
27321a3365eSStefano Zampini     PetscInt vs = 100;
27421a3365eSStefano Zampini     /* realloc if needed, as this function may be used in parallel */
2759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(vs, &val));
276ec7775f6SShri Abhyankar     for (i = start; i < end; i++) {
2779566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, i, &ncols, &row, &vals));
2789566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2799566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, i, &ncols, &row, &vals));
280ec7775f6SShri Abhyankar 
2819566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
28221a3365eSStefano Zampini       if (vs < ncols) {
28321a3365eSStefano Zampini         vs = PetscMin(2 * ncols, n);
2849566063dSJacob Faibussowitsch         PetscCall(PetscRealloc(vs * sizeof(*val), &val));
285ec7775f6SShri Abhyankar       }
28621a3365eSStefano Zampini       for (j = 0; j < ncols; j++) val[j] = a * vals[j];
2879566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, val, ADD_VALUES));
2889566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
289ec7775f6SShri Abhyankar     }
2909566063dSJacob Faibussowitsch     PetscCall(PetscFree(val));
291ec7775f6SShri Abhyankar   }
2929566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(Y));
2939566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(X));
294*799b351eSPierre Jolivet   PetscCall(MatGetOption(B, MAT_NO_OFF_PROC_ENTRIES, &option));
295*799b351eSPierre Jolivet   PetscCall(MatSetOption(B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
2969566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
2979566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
298*799b351eSPierre Jolivet   PetscCall(MatSetOption(B, MAT_NO_OFF_PROC_ENTRIES, option));
2993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
300ec7775f6SShri Abhyankar }
301ec7775f6SShri Abhyankar 
302052efed2SBarry Smith /*@
3032ef1f0ffSBarry Smith   MatShift - Computes `Y =  Y + a I`, where `a` is a `PetscScalar`
304052efed2SBarry Smith 
305c3339decSBarry Smith   Neighbor-wise Collective
306fee21e36SBarry Smith 
30798a79cdbSBarry Smith   Input Parameters:
30827430b45SBarry Smith + Y - the matrix
30927430b45SBarry Smith - a - the `PetscScalar`
31098a79cdbSBarry Smith 
3112860a424SLois Curfman McInnes   Level: intermediate
3122860a424SLois Curfman McInnes 
31395452b02SPatrick Sanan   Notes:
31427430b45SBarry Smith   If `Y` is a rectangular matrix, the shift is done on the main diagonal of the matrix (https://en.wikipedia.org/wiki/Main_diagonal)
31584e19e3eSJunchao Zhang 
3162ef1f0ffSBarry Smith   If the matrix `Y` is missing some diagonal entries this routine can be very slow. To make it fast one should initially
3176f33a894SBarry Smith   fill the matrix so that all diagonal entries have a value (with a value of zero for those locations that would not have an
318edf9a46cSStefano Zampini   entry). No operation is performed when a is zero.
3196f33a894SBarry Smith 
32027430b45SBarry Smith   To form Y = Y + diag(V) use `MatDiagonalSet()`
3210c0fd78eSBarry Smith 
3221cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatDiagonalSet()`, `MatScale()`, `MatDiagonalScale()`
323052efed2SBarry Smith  @*/
MatShift(Mat Y,PetscScalar a)324d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShift(Mat Y, PetscScalar a)
325d71ae5a4SJacob Faibussowitsch {
3263a40ed3dSBarry Smith   PetscFunctionBegin;
3270700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
3285f80ce2aSJacob Faibussowitsch   PetscCheck(Y->assembled, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3295f80ce2aSJacob Faibussowitsch   PetscCheck(!Y->factortype, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3304994cf47SJed Brown   MatCheckPreallocated(Y, 1);
3313ba16761SJacob Faibussowitsch   if (a == 0.0) PetscFunctionReturn(PETSC_SUCCESS);
332b50b34bdSBarry Smith 
333dbbe0bcdSBarry Smith   if (Y->ops->shift) PetscUseTypeMethod(Y, shift, a);
3349566063dSJacob Faibussowitsch   else PetscCall(MatShift_Basic(Y, a));
3357d68702bSBarry Smith 
3369566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
3373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
338052efed2SBarry Smith }
3396d84be18SBarry Smith 
MatDiagonalSet_Default(Mat Y,Vec D,InsertMode is)340d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalSet_Default(Mat Y, Vec D, InsertMode is)
341d71ae5a4SJacob Faibussowitsch {
34267576b8bSBarry Smith   PetscInt           i, start, end;
343fa2e578bSStefano Zampini   const PetscScalar *v;
34409f38230SBarry Smith 
34509f38230SBarry Smith   PetscFunctionBegin;
3469566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(Y, &start, &end));
3479566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(D, &v));
34848a46eb9SPierre Jolivet   for (i = start; i < end; i++) PetscCall(MatSetValues(Y, 1, &i, 1, &i, v + i - start, is));
3499566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(D, &v));
3509566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
3519566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
3523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35309f38230SBarry Smith }
35409f38230SBarry Smith 
3556d84be18SBarry Smith /*@
3562ef1f0ffSBarry Smith   MatDiagonalSet - Computes `Y` = `Y` + `D`, where `D` is a diagonal matrix
3572ef1f0ffSBarry Smith   that is represented as a vector. Or Y[i,i] = D[i] if `InsertMode` is
3582ef1f0ffSBarry Smith   `INSERT_VALUES`.
3596d84be18SBarry Smith 
360c3339decSBarry Smith   Neighbor-wise Collective
36148e586daSJose E. Roman 
3626d84be18SBarry Smith   Input Parameters:
36398a79cdbSBarry Smith + Y  - the input matrix
364f56f2b3fSBarry Smith . D  - the diagonal matrix, represented as a vector
365fe59aa6dSJacob Faibussowitsch - is - `INSERT_VALUES` or `ADD_VALUES`
3666f33a894SBarry Smith 
3672860a424SLois Curfman McInnes   Level: intermediate
3682860a424SLois Curfman McInnes 
3692ef1f0ffSBarry Smith   Note:
3702ef1f0ffSBarry Smith   If the matrix `Y` is missing some diagonal entries this routine can be very slow. To make it fast one should initially
3712ef1f0ffSBarry Smith   fill the matrix so that all diagonal entries have a value (with a value of zero for those locations that would not have an
3722ef1f0ffSBarry Smith   entry).
3732ef1f0ffSBarry Smith 
3741cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatShift()`, `MatScale()`, `MatDiagonalScale()`
3756d84be18SBarry Smith @*/
MatDiagonalSet(Mat Y,Vec D,InsertMode is)376d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalSet(Mat Y, Vec D, InsertMode is)
377d71ae5a4SJacob Faibussowitsch {
37867576b8bSBarry Smith   PetscInt matlocal, veclocal;
3796d84be18SBarry Smith 
3803a40ed3dSBarry Smith   PetscFunctionBegin;
3810700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
3820700a824SBarry Smith   PetscValidHeaderSpecific(D, VEC_CLASSID, 2);
3832fbb122aSJose E. Roman   MatCheckPreallocated(Y, 1);
3849566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Y, &matlocal, NULL));
3859566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(D, &veclocal));
3865f80ce2aSJacob Faibussowitsch   PetscCheck(matlocal == veclocal, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number local rows of matrix %" PetscInt_FMT " does not match that of vector for diagonal %" PetscInt_FMT, matlocal, veclocal);
387dbbe0bcdSBarry Smith   if (Y->ops->diagonalset) PetscUseTypeMethod(Y, diagonalset, D, is);
388dbbe0bcdSBarry Smith   else PetscCall(MatDiagonalSet_Default(Y, D, is));
3899566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
3903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3916d84be18SBarry Smith }
392d4bb536fSBarry Smith 
393d4bb536fSBarry Smith /*@
39404aac2b0SHong Zhang   MatAYPX - Computes Y = a*Y + X.
395d4bb536fSBarry Smith 
3962ef1f0ffSBarry Smith   Logically Collective
397fee21e36SBarry Smith 
39898a79cdbSBarry Smith   Input Parameters:
3992ef1f0ffSBarry Smith + a   - the `PetscScalar` multiplier
40004aac2b0SHong Zhang . Y   - the first matrix
40104aac2b0SHong Zhang . X   - the second matrix
402aaa8cc7dSPierre Jolivet - str - either `SAME_NONZERO_PATTERN`, `DIFFERENT_NONZERO_PATTERN`, `UNKNOWN_NONZERO_PATTERN`, or `SUBSET_NONZERO_PATTERN` (nonzeros of `X` is a subset of `Y`'s)
403d4bb536fSBarry Smith 
4042860a424SLois Curfman McInnes   Level: intermediate
4052860a424SLois Curfman McInnes 
4061cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatAXPY()`
407d4bb536fSBarry Smith  @*/
MatAYPX(Mat Y,PetscScalar a,Mat X,MatStructure str)408d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAYPX(Mat Y, PetscScalar a, Mat X, MatStructure str)
409d71ae5a4SJacob Faibussowitsch {
4103a40ed3dSBarry Smith   PetscFunctionBegin;
4119566063dSJacob Faibussowitsch   PetscCall(MatScale(Y, a));
4129566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Y, 1.0, X, str));
4133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
414d4bb536fSBarry Smith }
415b0a32e0cSBarry Smith 
4165d83a8b1SBarry Smith /*@
4170bacdadaSStefano Zampini   MatComputeOperator - Computes the explicit matrix
418b0a32e0cSBarry Smith 
419c3339decSBarry Smith   Collective
420b0a32e0cSBarry Smith 
421d8d19677SJose E. Roman   Input Parameters:
422186a3e20SStefano Zampini + inmat   - the matrix
423186a3e20SStefano Zampini - mattype - the matrix type for the explicit operator
424b0a32e0cSBarry Smith 
425b0a32e0cSBarry Smith   Output Parameter:
426a5b23f4aSJose E. Roman . mat - the explicit  operator
427b0a32e0cSBarry Smith 
4282ef1f0ffSBarry Smith   Level: advanced
4292ef1f0ffSBarry Smith 
43011a5261eSBarry Smith   Note:
431f13dfd9eSBarry Smith   This computation is done by applying the operator to columns of the identity matrix.
432186a3e20SStefano Zampini   This routine is costly in general, and is recommended for use only with relatively small systems.
4332ef1f0ffSBarry Smith   Currently, this routine uses a dense matrix format if `mattype` == `NULL`.
434b0a32e0cSBarry Smith 
4351cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatMult()`, `MatComputeOperatorTranspose()`
436b0a32e0cSBarry Smith @*/
MatComputeOperator(Mat inmat,MatType mattype,Mat * mat)437d71ae5a4SJacob Faibussowitsch PetscErrorCode MatComputeOperator(Mat inmat, MatType mattype, Mat *mat)
438d71ae5a4SJacob Faibussowitsch {
439b0a32e0cSBarry Smith   PetscFunctionBegin;
4400700a824SBarry Smith   PetscValidHeaderSpecific(inmat, MAT_CLASSID, 1);
4414f572ea9SToby Isaac   PetscAssertPointer(mat, 3);
4429566063dSJacob Faibussowitsch   PetscCall(MatConvert_Shell(inmat, mattype ? mattype : MATDENSE, MAT_INITIAL_MATRIX, mat));
4433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44424f910e3SHong Zhang }
4454325cce7SMatthew G Knepley 
4465d83a8b1SBarry Smith /*@
4470bacdadaSStefano Zampini   MatComputeOperatorTranspose - Computes the explicit matrix representation of
4482ef1f0ffSBarry Smith   a give matrix that can apply `MatMultTranspose()`
449f3b1f45cSBarry Smith 
450c3339decSBarry Smith   Collective
451f3b1f45cSBarry Smith 
4526b867d5aSJose E. Roman   Input Parameters:
4536b867d5aSJose E. Roman + inmat   - the matrix
4546b867d5aSJose E. Roman - mattype - the matrix type for the explicit operator
455f3b1f45cSBarry Smith 
456f3b1f45cSBarry Smith   Output Parameter:
457a5b23f4aSJose E. Roman . mat - the explicit  operator transposed
458f3b1f45cSBarry Smith 
4592ef1f0ffSBarry Smith   Level: advanced
4602ef1f0ffSBarry Smith 
46111a5261eSBarry Smith   Note:
462186a3e20SStefano Zampini   This computation is done by applying the transpose of the operator to columns of the identity matrix.
463186a3e20SStefano Zampini   This routine is costly in general, and is recommended for use only with relatively small systems.
4642ef1f0ffSBarry Smith   Currently, this routine uses a dense matrix format if `mattype` == `NULL`.
465f3b1f45cSBarry Smith 
4661cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatMult()`, `MatComputeOperator()`
467f3b1f45cSBarry Smith @*/
MatComputeOperatorTranspose(Mat inmat,MatType mattype,Mat * mat)468d71ae5a4SJacob Faibussowitsch PetscErrorCode MatComputeOperatorTranspose(Mat inmat, MatType mattype, Mat *mat)
469d71ae5a4SJacob Faibussowitsch {
470186a3e20SStefano Zampini   Mat A;
471f3b1f45cSBarry Smith 
472f3b1f45cSBarry Smith   PetscFunctionBegin;
473f3b1f45cSBarry Smith   PetscValidHeaderSpecific(inmat, MAT_CLASSID, 1);
4744f572ea9SToby Isaac   PetscAssertPointer(mat, 3);
4759566063dSJacob Faibussowitsch   PetscCall(MatCreateTranspose(inmat, &A));
4769566063dSJacob Faibussowitsch   PetscCall(MatConvert_Shell(A, mattype ? mattype : MATDENSE, MAT_INITIAL_MATRIX, mat));
4779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A));
4783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
479f3b1f45cSBarry Smith }
480f3b1f45cSBarry Smith 
481f3b1f45cSBarry Smith /*@
4822ce66baaSPierre Jolivet   MatFilter - Set all values in the matrix with an absolute value less than or equal to the tolerance to zero, and optionally compress the underlying storage
4834325cce7SMatthew G Knepley 
4844325cce7SMatthew G Knepley   Input Parameters:
4854325cce7SMatthew G Knepley + A        - The matrix
4862ce66baaSPierre Jolivet . tol      - The zero tolerance
4872ce66baaSPierre Jolivet . compress - Whether the storage from the input matrix `A` should be compressed once values less than or equal to `tol` are set to zero
4882ce66baaSPierre Jolivet - keep     - If `compress` is true and for a given row of `A`, the diagonal coefficient is less than or equal to `tol`, indicates whether it should be left in the structure or eliminated as well
4894325cce7SMatthew G Knepley 
4904325cce7SMatthew G Knepley   Level: intermediate
4914325cce7SMatthew G Knepley 
492d9b70fcdSPierre Jolivet .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatZeroEntries()`, `MatEliminateZeros()`, `VecFilter()`
4933fc99919SSatish Balay  @*/
MatFilter(Mat A,PetscReal tol,PetscBool compress,PetscBool keep)4942ce66baaSPierre Jolivet PetscErrorCode MatFilter(Mat A, PetscReal tol, PetscBool compress, PetscBool keep)
495d71ae5a4SJacob Faibussowitsch {
496038df967SPierre Jolivet   Mat          a;
4974325cce7SMatthew G Knepley   PetscScalar *newVals;
49834bf4ff8Smarkadams4   PetscInt    *newCols, rStart, rEnd, maxRows, r, colMax = 0, nnz0 = 0, nnz1 = 0;
499038df967SPierre Jolivet   PetscBool    flg;
5004325cce7SMatthew G Knepley 
5014325cce7SMatthew G Knepley   PetscFunctionBegin;
5029566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)A, &flg, MATSEQDENSE, MATMPIDENSE, ""));
503038df967SPierre Jolivet   if (flg) {
5049566063dSJacob Faibussowitsch     PetscCall(MatDenseGetLocalMatrix(A, &a));
5059566063dSJacob Faibussowitsch     PetscCall(MatDenseGetLDA(a, &r));
5069566063dSJacob Faibussowitsch     PetscCall(MatGetSize(a, &rStart, &rEnd));
5079566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(a, &newVals));
508038df967SPierre Jolivet     for (; colMax < rEnd; ++colMax) {
50982fa6941SPierre Jolivet       for (maxRows = 0; maxRows < rStart; ++maxRows) newVals[maxRows + colMax * r] = PetscAbsScalar(newVals[maxRows + colMax * r]) <= tol ? 0.0 : newVals[maxRows + colMax * r];
510038df967SPierre Jolivet     }
5119566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArray(a, &newVals));
512038df967SPierre Jolivet   } else {
5133da7c217SPierre Jolivet     const PetscInt *ranges;
5143da7c217SPierre Jolivet     PetscMPIInt     rank, size;
5153da7c217SPierre Jolivet 
5163da7c217SPierre Jolivet     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
5173da7c217SPierre Jolivet     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
5183da7c217SPierre Jolivet     PetscCall(MatGetOwnershipRanges(A, &ranges));
5193da7c217SPierre Jolivet     rStart = ranges[rank];
5203da7c217SPierre Jolivet     rEnd   = ranges[rank + 1];
5219566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(A));
5224325cce7SMatthew G Knepley     for (r = rStart; r < rEnd; ++r) {
5234325cce7SMatthew G Knepley       PetscInt ncols;
5244325cce7SMatthew G Knepley 
5259566063dSJacob Faibussowitsch       PetscCall(MatGetRow(A, r, &ncols, NULL, NULL));
5265f80ce2aSJacob Faibussowitsch       colMax = PetscMax(colMax, ncols);
5279566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(A, r, &ncols, NULL, NULL));
5284325cce7SMatthew G Knepley     }
5293da7c217SPierre Jolivet     maxRows = 0;
5303da7c217SPierre Jolivet     for (r = 0; r < size; ++r) maxRows = PetscMax(maxRows, ranges[r + 1] - ranges[r]);
5313da7c217SPierre Jolivet     PetscCall(PetscCalloc2(colMax, &newCols, colMax, &newVals));
5329566063dSJacob Faibussowitsch     PetscCall(MatGetOption(A, MAT_NO_OFF_PROC_ENTRIES, &flg)); /* cache user-defined value */
5339566063dSJacob Faibussowitsch     PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
534cf5d3338SPierre Jolivet     /* short-circuit code in MatAssemblyBegin() and MatAssemblyEnd()             */
535cf5d3338SPierre Jolivet     /* that are potentially called many times depending on the distribution of A */
5364325cce7SMatthew G Knepley     for (r = rStart; r < rStart + maxRows; ++r) {
5373da7c217SPierre Jolivet       if (r < rEnd) {
5384325cce7SMatthew G Knepley         const PetscScalar *vals;
5394325cce7SMatthew G Knepley         const PetscInt    *cols;
5403da7c217SPierre Jolivet         PetscInt           ncols, newcols = 0, c;
5414325cce7SMatthew G Knepley 
5429566063dSJacob Faibussowitsch         PetscCall(MatGetRow(A, r, &ncols, &cols, &vals));
54334bf4ff8Smarkadams4         nnz0 += ncols - 1;
5444325cce7SMatthew G Knepley         for (c = 0; c < ncols; ++c) {
54582fa6941SPierre Jolivet           if (PetscUnlikely(PetscAbsScalar(vals[c]) <= tol)) newCols[newcols++] = cols[c];
5464325cce7SMatthew G Knepley         }
54734bf4ff8Smarkadams4         nnz1 += ncols - newcols - 1;
5489566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(A, r, &ncols, &cols, &vals));
5499566063dSJacob Faibussowitsch         PetscCall(MatSetValues(A, 1, &r, newcols, newCols, newVals, INSERT_VALUES));
5504325cce7SMatthew G Knepley       }
5519566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
5529566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
5534325cce7SMatthew G Knepley     }
5549566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(A));
5559566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCols, newVals));
5569566063dSJacob Faibussowitsch     PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, flg)); /* reset option to its user-defined value */
55734bf4ff8Smarkadams4     if (nnz0 > 0) PetscCall(PetscInfo(NULL, "Filtering left %g%% edges in graph\n", 100 * (double)nnz1 / (double)nnz0));
5585afa97f7SPierre Jolivet     else PetscCall(PetscInfo(NULL, "Warning: %" PetscInt_FMT " edges to filter with %" PetscInt_FMT " rows\n", nnz0, maxRows));
559038df967SPierre Jolivet   }
5602ce66baaSPierre Jolivet   if (compress && A->ops->eliminatezeros) {
5612ce66baaSPierre Jolivet     Mat       B;
56224c7e8a4SPierre Jolivet     PetscBool flg;
5632ce66baaSPierre Jolivet 
56424c7e8a4SPierre Jolivet     PetscCall(PetscObjectTypeCompareAny((PetscObject)A, &flg, MATSEQAIJHIPSPARSE, MATMPIAIJHIPSPARSE, ""));
56524c7e8a4SPierre Jolivet     if (!flg) {
5662ce66baaSPierre Jolivet       PetscCall(MatEliminateZeros(A, keep));
5672ce66baaSPierre Jolivet       PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &B));
5682ce66baaSPierre Jolivet       PetscCall(MatHeaderReplace(A, &B));
5692ce66baaSPierre Jolivet     }
57024c7e8a4SPierre Jolivet   }
5713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5724325cce7SMatthew G Knepley }
573