xref: /petsc/src/mat/utils/axpy.c (revision 27430b45d0a5eedd7547ed99d6048b6750b3fa8a)
16f79c3a4SBarry Smith 
2af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I   "petscmat.h"  I*/
36f79c3a4SBarry Smith 
4d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTransposeAXPY_Private(Mat Y, PetscScalar a, Mat X, MatStructure str, Mat T)
5d71ae5a4SJacob Faibussowitsch {
6d54c938cSPierre Jolivet   Mat A, F;
75f80ce2aSJacob Faibussowitsch   PetscErrorCode (*f)(Mat, Mat *);
8d54c938cSPierre Jolivet 
9d54c938cSPierre Jolivet   PetscFunctionBegin;
109566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)T, "MatTransposeGetMat_C", &f));
11d54c938cSPierre Jolivet   if (f) {
129566063dSJacob Faibussowitsch     PetscCall(MatTransposeGetMat(T, &A));
13d54c938cSPierre Jolivet     if (T == X) {
14013e2dc7SBarry Smith       PetscCall(PetscInfo(NULL, "Explicitly transposing X of type MATTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
159566063dSJacob Faibussowitsch       PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &F));
16d54c938cSPierre Jolivet       A = Y;
17d54c938cSPierre Jolivet     } else {
18013e2dc7SBarry Smith       PetscCall(PetscInfo(NULL, "Transposing X because Y of type MATTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
199566063dSJacob Faibussowitsch       PetscCall(MatTranspose(X, MAT_INITIAL_MATRIX, &F));
20d54c938cSPierre Jolivet     }
21d54c938cSPierre Jolivet   } else {
229566063dSJacob Faibussowitsch     PetscCall(MatHermitianTransposeGetMat(T, &A));
23d54c938cSPierre Jolivet     if (T == X) {
24013e2dc7SBarry Smith       PetscCall(PetscInfo(NULL, "Explicitly Hermitian transposing X of type MATHERITIANTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
259566063dSJacob Faibussowitsch       PetscCall(MatHermitianTranspose(A, MAT_INITIAL_MATRIX, &F));
26d54c938cSPierre Jolivet       A = Y;
27d54c938cSPierre Jolivet     } else {
28013e2dc7SBarry Smith       PetscCall(PetscInfo(NULL, "Hermitian transposing X because Y of type MATHERITIANTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
299566063dSJacob Faibussowitsch       PetscCall(MatHermitianTranspose(X, MAT_INITIAL_MATRIX, &F));
30d54c938cSPierre Jolivet     }
31d54c938cSPierre Jolivet   }
329566063dSJacob Faibussowitsch   PetscCall(MatAXPY(A, a, F, str));
339566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&F));
343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35d54c938cSPierre Jolivet }
36d54c938cSPierre Jolivet 
3706be10caSBarry Smith /*@
3821c89e3eSBarry Smith    MatAXPY - Computes Y = a*X + Y.
396f79c3a4SBarry Smith 
40c3339decSBarry Smith    Logically Collective
41fee21e36SBarry Smith 
4298a79cdbSBarry Smith    Input Parameters:
43607cd303SBarry Smith +  a - the scalar multiplier
44607cd303SBarry Smith .  X - the first matrix
45607cd303SBarry Smith .  Y - the second matrix
46*27430b45SBarry 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)
47edf9a46cSStefano Zampini 
482860a424SLois Curfman McInnes    Level: intermediate
492860a424SLois Curfman McInnes 
50*27430b45SBarry Smith .seealso: `Mat`, `MatAYPX()`
5106be10caSBarry Smith  @*/
52d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY(Mat Y, PetscScalar a, Mat X, MatStructure str)
53d71ae5a4SJacob Faibussowitsch {
54646531bbSStefano Zampini   PetscInt  M1, M2, N1, N2;
55c1ac3661SBarry Smith   PetscInt  m1, m2, n1, n2;
56a683ea4aSPierre Jolivet   PetscBool sametype, transpose;
576f79c3a4SBarry Smith 
583a40ed3dSBarry Smith   PetscFunctionBegin;
590700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
60c5eb9154SBarry Smith   PetscValidLogicalCollectiveScalar(Y, a, 2);
61646531bbSStefano Zampini   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
62646531bbSStefano Zampini   PetscCheckSameComm(Y, 1, X, 3);
639566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X, &M1, &N1));
649566063dSJacob Faibussowitsch   PetscCall(MatGetSize(Y, &M2, &N2));
659566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(X, &m1, &n1));
669566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Y, &m2, &n2));
672c71b3e2SJacob 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);
682c71b3e2SJacob 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);
692c71b3e2SJacob Faibussowitsch   PetscCheck(Y->assembled, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix (Y)");
702c71b3e2SJacob Faibussowitsch   PetscCheck(X->assembled, PetscObjectComm((PetscObject)X), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix (X)");
713ba16761SJacob Faibussowitsch   if (a == (PetscScalar)0.0) PetscFunctionReturn(PETSC_SUCCESS);
72edf9a46cSStefano Zampini   if (Y == X) {
739566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 1.0 + a));
743ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
75edf9a46cSStefano Zampini   }
76013e2dc7SBarry Smith   PetscCall(PetscObjectObjectTypeCompare((PetscObject)X, (PetscObject)Y, &sametype));
779566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(MAT_AXPY, Y, 0, 0, 0));
7893c87e65SStefano Zampini   if (Y->ops->axpy && (sametype || X->ops->axpy == Y->ops->axpy)) {
79dbbe0bcdSBarry Smith     PetscUseTypeMethod(Y, axpy, a, X, str);
80d4bb536fSBarry Smith   } else {
81013e2dc7SBarry Smith     PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &transpose, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
82a683ea4aSPierre Jolivet     if (transpose) {
839566063dSJacob Faibussowitsch       PetscCall(MatTransposeAXPY_Private(Y, a, X, str, X));
84a683ea4aSPierre Jolivet     } else {
85013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)Y, &transpose, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
86a683ea4aSPierre Jolivet       if (transpose) {
879566063dSJacob Faibussowitsch         PetscCall(MatTransposeAXPY_Private(Y, a, X, str, Y));
88a683ea4aSPierre Jolivet       } else {
899566063dSJacob Faibussowitsch         PetscCall(MatAXPY_Basic(Y, a, X, str));
90607cd303SBarry Smith       }
91a683ea4aSPierre Jolivet     }
92a683ea4aSPierre Jolivet   }
939566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(MAT_AXPY, Y, 0, 0, 0));
943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
95607cd303SBarry Smith }
96607cd303SBarry Smith 
97d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_Basic_Preallocate(Mat Y, Mat X, Mat *B)
98d71ae5a4SJacob Faibussowitsch {
9927afe9e8SStefano Zampini   PetscErrorCode (*preall)(Mat, Mat, Mat *) = NULL;
100646531bbSStefano Zampini 
101646531bbSStefano Zampini   PetscFunctionBegin;
102646531bbSStefano Zampini   /* look for any available faster alternative to the general preallocator */
1039566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)Y, "MatAXPYGetPreallocation_C", &preall));
104646531bbSStefano Zampini   if (preall) {
1059566063dSJacob Faibussowitsch     PetscCall((*preall)(Y, X, B));
106646531bbSStefano Zampini   } else { /* Use MatPrellocator, assumes same row-col distribution */
107646531bbSStefano Zampini     Mat      preallocator;
108646531bbSStefano Zampini     PetscInt r, rstart, rend;
109646531bbSStefano Zampini     PetscInt m, n, M, N;
110646531bbSStefano Zampini 
1119566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(Y));
1129566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(X));
1139566063dSJacob Faibussowitsch     PetscCall(MatGetSize(Y, &M, &N));
1149566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(Y, &m, &n));
1159566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &preallocator));
1169566063dSJacob Faibussowitsch     PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
1179566063dSJacob Faibussowitsch     PetscCall(MatSetLayouts(preallocator, Y->rmap, Y->cmap));
1189566063dSJacob Faibussowitsch     PetscCall(MatSetUp(preallocator));
1199566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(preallocator, &rstart, &rend));
120646531bbSStefano Zampini     for (r = rstart; r < rend; ++r) {
121646531bbSStefano Zampini       PetscInt           ncols;
122646531bbSStefano Zampini       const PetscInt    *row;
123646531bbSStefano Zampini       const PetscScalar *vals;
124646531bbSStefano Zampini 
1259566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, r, &ncols, &row, &vals));
1269566063dSJacob Faibussowitsch       PetscCall(MatSetValues(preallocator, 1, &r, ncols, row, vals, INSERT_VALUES));
1279566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, r, &ncols, &row, &vals));
1289566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, r, &ncols, &row, &vals));
1299566063dSJacob Faibussowitsch       PetscCall(MatSetValues(preallocator, 1, &r, ncols, row, vals, INSERT_VALUES));
1309566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, r, &ncols, &row, &vals));
131646531bbSStefano Zampini     }
1329566063dSJacob Faibussowitsch     PetscCall(MatSetOption(preallocator, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
1339566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
1349566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
1359566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(Y));
1369566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(X));
137646531bbSStefano Zampini 
1389566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), B));
1399566063dSJacob Faibussowitsch     PetscCall(MatSetType(*B, ((PetscObject)Y)->type_name));
1409566063dSJacob Faibussowitsch     PetscCall(MatSetLayouts(*B, Y->rmap, Y->cmap));
1419566063dSJacob Faibussowitsch     PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_FALSE, *B));
1429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&preallocator));
143646531bbSStefano Zampini   }
1443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
145646531bbSStefano Zampini }
146646531bbSStefano Zampini 
147d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_Basic(Mat Y, PetscScalar a, Mat X, MatStructure str)
148d71ae5a4SJacob Faibussowitsch {
149be705e3aSPierre Jolivet   PetscBool isshell, isdense, isnest;
150edf9a46cSStefano Zampini 
151edf9a46cSStefano Zampini   PetscFunctionBegin;
1529566063dSJacob Faibussowitsch   PetscCall(MatIsShell(Y, &isshell));
153edf9a46cSStefano Zampini   if (isshell) { /* MatShell has special support for AXPY */
154edf9a46cSStefano Zampini     PetscErrorCode (*f)(Mat, PetscScalar, Mat, MatStructure);
155edf9a46cSStefano Zampini 
1569566063dSJacob Faibussowitsch     PetscCall(MatGetOperation(Y, MATOP_AXPY, (void (**)(void)) & f));
157edf9a46cSStefano Zampini     if (f) {
1589566063dSJacob Faibussowitsch       PetscCall((*f)(Y, a, X, str));
1593ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
160edf9a46cSStefano Zampini     }
161edf9a46cSStefano Zampini   }
16293c87e65SStefano Zampini   /* no need to preallocate if Y is dense */
1639566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isdense, MATSEQDENSE, MATMPIDENSE, ""));
164be705e3aSPierre Jolivet   if (isdense) {
1659566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATNEST, &isnest));
166be705e3aSPierre Jolivet     if (isnest) {
1679566063dSJacob Faibussowitsch       PetscCall(MatAXPY_Dense_Nest(Y, a, X));
1683ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
169be705e3aSPierre Jolivet     }
170be705e3aSPierre Jolivet     if (str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN) str = SUBSET_NONZERO_PATTERN;
171be705e3aSPierre Jolivet   }
172a6ab3590SBarry Smith   if (str != DIFFERENT_NONZERO_PATTERN && str != UNKNOWN_NONZERO_PATTERN) {
173edf9a46cSStefano Zampini     PetscInt           i, start, end, j, ncols, m, n;
17438baddfdSBarry Smith     const PetscInt    *row;
175b3cc6726SBarry Smith     PetscScalar       *val;
176b3cc6726SBarry Smith     const PetscScalar *vals;
177607cd303SBarry Smith 
1789566063dSJacob Faibussowitsch     PetscCall(MatGetSize(X, &m, &n));
1799566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(X, &start, &end));
1809566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(X));
181f4df32b1SMatthew Knepley     if (a == 1.0) {
182d4bb536fSBarry Smith       for (i = start; i < end; i++) {
1839566063dSJacob Faibussowitsch         PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
1849566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Y, 1, &i, ncols, row, vals, ADD_VALUES));
1859566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
186d4bb536fSBarry Smith       }
187d4bb536fSBarry Smith     } else {
18821a3365eSStefano Zampini       PetscInt vs = 100;
18921a3365eSStefano Zampini       /* realloc if needed, as this function may be used in parallel */
1909566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(vs, &val));
19106be10caSBarry Smith       for (i = start; i < end; i++) {
1929566063dSJacob Faibussowitsch         PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
19321a3365eSStefano Zampini         if (vs < ncols) {
19421a3365eSStefano Zampini           vs = PetscMin(2 * ncols, n);
1959566063dSJacob Faibussowitsch           PetscCall(PetscRealloc(vs * sizeof(*val), &val));
1966f79c3a4SBarry Smith         }
19721a3365eSStefano Zampini         for (j = 0; j < ncols; j++) val[j] = a * vals[j];
1989566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Y, 1, &i, ncols, row, val, ADD_VALUES));
1999566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
2006f79c3a4SBarry Smith       }
2019566063dSJacob Faibussowitsch       PetscCall(PetscFree(val));
202d4bb536fSBarry Smith     }
2039566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(X));
2049566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
2059566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
206edf9a46cSStefano Zampini   } else {
207edf9a46cSStefano Zampini     Mat B;
208edf9a46cSStefano Zampini 
2099566063dSJacob Faibussowitsch     PetscCall(MatAXPY_Basic_Preallocate(Y, X, &B));
2109566063dSJacob Faibussowitsch     PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str));
2119566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(Y, &B));
212edf9a46cSStefano Zampini   }
2133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2146f79c3a4SBarry Smith }
215052efed2SBarry Smith 
216d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_BasicWithPreallocation(Mat B, Mat Y, PetscScalar a, Mat X, MatStructure str)
217d71ae5a4SJacob Faibussowitsch {
218ec7775f6SShri Abhyankar   PetscInt           i, start, end, j, ncols, m, n;
219ec7775f6SShri Abhyankar   const PetscInt    *row;
220ec7775f6SShri Abhyankar   PetscScalar       *val;
221ec7775f6SShri Abhyankar   const PetscScalar *vals;
222ec7775f6SShri Abhyankar 
223ec7775f6SShri Abhyankar   PetscFunctionBegin;
2249566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X, &m, &n));
2259566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(X, &start, &end));
2269566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(Y));
2279566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(X));
228ec7775f6SShri Abhyankar   if (a == 1.0) {
229ec7775f6SShri Abhyankar     for (i = start; i < end; i++) {
2309566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, i, &ncols, &row, &vals));
2319566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2329566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, i, &ncols, &row, &vals));
233ec7775f6SShri Abhyankar 
2349566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
2359566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2369566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
237ec7775f6SShri Abhyankar     }
238ec7775f6SShri Abhyankar   } else {
23921a3365eSStefano Zampini     PetscInt vs = 100;
24021a3365eSStefano Zampini     /* realloc if needed, as this function may be used in parallel */
2419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(vs, &val));
242ec7775f6SShri Abhyankar     for (i = start; i < end; i++) {
2439566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, i, &ncols, &row, &vals));
2449566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2459566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, i, &ncols, &row, &vals));
246ec7775f6SShri Abhyankar 
2479566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
24821a3365eSStefano Zampini       if (vs < ncols) {
24921a3365eSStefano Zampini         vs = PetscMin(2 * ncols, n);
2509566063dSJacob Faibussowitsch         PetscCall(PetscRealloc(vs * sizeof(*val), &val));
251ec7775f6SShri Abhyankar       }
25221a3365eSStefano Zampini       for (j = 0; j < ncols; j++) val[j] = a * vals[j];
2539566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, val, ADD_VALUES));
2549566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
255ec7775f6SShri Abhyankar     }
2569566063dSJacob Faibussowitsch     PetscCall(PetscFree(val));
257ec7775f6SShri Abhyankar   }
2589566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(Y));
2599566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(X));
2609566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
2619566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
263ec7775f6SShri Abhyankar }
264ec7775f6SShri Abhyankar 
265052efed2SBarry Smith /*@
266*27430b45SBarry Smith    MatShift - Computes Y =  Y + a I, where a is a `PetscScalar` and I is the identity matrix.
267052efed2SBarry Smith 
268c3339decSBarry Smith    Neighbor-wise Collective
269fee21e36SBarry Smith 
27098a79cdbSBarry Smith    Input Parameters:
271*27430b45SBarry Smith +  Y - the matrix
272*27430b45SBarry Smith -  a - the `PetscScalar`
27398a79cdbSBarry Smith 
2742860a424SLois Curfman McInnes    Level: intermediate
2752860a424SLois Curfman McInnes 
27695452b02SPatrick Sanan    Notes:
277*27430b45SBarry 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)
27884e19e3eSJunchao Zhang 
27995452b02SPatrick Sanan     If the matrix Y is missing some diagonal entries this routine can be very slow. To make it fast one should initially
2806f33a894SBarry 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
281edf9a46cSStefano Zampini    entry). No operation is performed when a is zero.
2826f33a894SBarry Smith 
283*27430b45SBarry Smith    To form Y = Y + diag(V) use `MatDiagonalSet()`
2840c0fd78eSBarry Smith 
285db781477SPatrick Sanan .seealso: `MatDiagonalSet()`, `MatScale()`, `MatDiagonalScale()`
286052efed2SBarry Smith  @*/
287d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShift(Mat Y, PetscScalar a)
288d71ae5a4SJacob Faibussowitsch {
2893a40ed3dSBarry Smith   PetscFunctionBegin;
2900700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
2915f80ce2aSJacob Faibussowitsch   PetscCheck(Y->assembled, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2925f80ce2aSJacob Faibussowitsch   PetscCheck(!Y->factortype, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2934994cf47SJed Brown   MatCheckPreallocated(Y, 1);
2943ba16761SJacob Faibussowitsch   if (a == 0.0) PetscFunctionReturn(PETSC_SUCCESS);
295b50b34bdSBarry Smith 
296dbbe0bcdSBarry Smith   if (Y->ops->shift) PetscUseTypeMethod(Y, shift, a);
2979566063dSJacob Faibussowitsch   else PetscCall(MatShift_Basic(Y, a));
2987d68702bSBarry Smith 
2999566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
3003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
301052efed2SBarry Smith }
3026d84be18SBarry Smith 
303d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalSet_Default(Mat Y, Vec D, InsertMode is)
304d71ae5a4SJacob Faibussowitsch {
30567576b8bSBarry Smith   PetscInt           i, start, end;
306fa2e578bSStefano Zampini   const PetscScalar *v;
30709f38230SBarry Smith 
30809f38230SBarry Smith   PetscFunctionBegin;
3099566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(Y, &start, &end));
3109566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(D, &v));
31148a46eb9SPierre Jolivet   for (i = start; i < end; i++) PetscCall(MatSetValues(Y, 1, &i, 1, &i, v + i - start, is));
3129566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(D, &v));
3139566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
3149566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
3153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31609f38230SBarry Smith }
31709f38230SBarry Smith 
3186d84be18SBarry Smith /*@
319f56f2b3fSBarry Smith    MatDiagonalSet - Computes Y = Y + D, where D is a diagonal matrix
320f56f2b3fSBarry Smith    that is represented as a vector. Or Y[i,i] = D[i] if InsertMode is
321f56f2b3fSBarry Smith    INSERT_VALUES.
3226d84be18SBarry Smith 
323c3339decSBarry Smith    Neighbor-wise Collective
32448e586daSJose E. Roman 
3256d84be18SBarry Smith    Input Parameters:
32698a79cdbSBarry Smith +  Y - the input matrix
327f56f2b3fSBarry Smith .  D - the diagonal matrix, represented as a vector
328f56f2b3fSBarry Smith -  i - INSERT_VALUES or ADD_VALUES
3296d84be18SBarry Smith 
33011a5261eSBarry Smith    Note:
33195452b02SPatrick Sanan     If the matrix Y is missing some diagonal entries this routine can be very slow. To make it fast one should initially
3326f33a894SBarry 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
3336f33a894SBarry Smith    entry).
3346f33a894SBarry Smith 
3352860a424SLois Curfman McInnes    Level: intermediate
3362860a424SLois Curfman McInnes 
337db781477SPatrick Sanan .seealso: `MatShift()`, `MatScale()`, `MatDiagonalScale()`
3386d84be18SBarry Smith @*/
339d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalSet(Mat Y, Vec D, InsertMode is)
340d71ae5a4SJacob Faibussowitsch {
34167576b8bSBarry Smith   PetscInt matlocal, veclocal;
3426d84be18SBarry Smith 
3433a40ed3dSBarry Smith   PetscFunctionBegin;
3440700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
3450700a824SBarry Smith   PetscValidHeaderSpecific(D, VEC_CLASSID, 2);
3469566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Y, &matlocal, NULL));
3479566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(D, &veclocal));
3485f80ce2aSJacob 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);
349dbbe0bcdSBarry Smith   if (Y->ops->diagonalset) PetscUseTypeMethod(Y, diagonalset, D, is);
350dbbe0bcdSBarry Smith   else PetscCall(MatDiagonalSet_Default(Y, D, is));
3519566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
3523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3536d84be18SBarry Smith }
354d4bb536fSBarry Smith 
355d4bb536fSBarry Smith /*@
35604aac2b0SHong Zhang    MatAYPX - Computes Y = a*Y + X.
357d4bb536fSBarry Smith 
3583f9fe445SBarry Smith    Logically on Mat
359fee21e36SBarry Smith 
36098a79cdbSBarry Smith    Input Parameters:
36104aac2b0SHong Zhang +  a - the PetscScalar multiplier
36204aac2b0SHong Zhang .  Y - the first matrix
36304aac2b0SHong Zhang .  X - the second matrix
364531d0c6aSBarry 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)
365d4bb536fSBarry Smith 
3662860a424SLois Curfman McInnes    Level: intermediate
3672860a424SLois Curfman McInnes 
368db781477SPatrick Sanan .seealso: `MatAXPY()`
369d4bb536fSBarry Smith  @*/
370d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAYPX(Mat Y, PetscScalar a, Mat X, MatStructure str)
371d71ae5a4SJacob Faibussowitsch {
3723a40ed3dSBarry Smith   PetscFunctionBegin;
3739566063dSJacob Faibussowitsch   PetscCall(MatScale(Y, a));
3749566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Y, 1.0, X, str));
3753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
376d4bb536fSBarry Smith }
377b0a32e0cSBarry Smith 
378b0a32e0cSBarry Smith /*@
3790bacdadaSStefano Zampini     MatComputeOperator - Computes the explicit matrix
380b0a32e0cSBarry Smith 
381c3339decSBarry Smith     Collective
382b0a32e0cSBarry Smith 
383d8d19677SJose E. Roman     Input Parameters:
384186a3e20SStefano Zampini +   inmat - the matrix
385186a3e20SStefano Zampini -   mattype - the matrix type for the explicit operator
386b0a32e0cSBarry Smith 
387b0a32e0cSBarry Smith     Output Parameter:
388a5b23f4aSJose E. Roman .   mat - the explicit  operator
389b0a32e0cSBarry Smith 
39011a5261eSBarry Smith     Note:
391186a3e20SStefano Zampini     This computation is done by applying the operators to columns of the identity matrix.
392186a3e20SStefano Zampini     This routine is costly in general, and is recommended for use only with relatively small systems.
393186a3e20SStefano Zampini     Currently, this routine uses a dense matrix format if mattype == NULL.
394b0a32e0cSBarry Smith 
395b0a32e0cSBarry Smith     Level: advanced
396b0a32e0cSBarry Smith 
397b0a32e0cSBarry Smith @*/
398d71ae5a4SJacob Faibussowitsch PetscErrorCode MatComputeOperator(Mat inmat, MatType mattype, Mat *mat)
399d71ae5a4SJacob Faibussowitsch {
400b0a32e0cSBarry Smith   PetscFunctionBegin;
4010700a824SBarry Smith   PetscValidHeaderSpecific(inmat, MAT_CLASSID, 1);
402186a3e20SStefano Zampini   PetscValidPointer(mat, 3);
4039566063dSJacob Faibussowitsch   PetscCall(MatConvert_Shell(inmat, mattype ? mattype : MATDENSE, MAT_INITIAL_MATRIX, mat));
4043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40524f910e3SHong Zhang }
4064325cce7SMatthew G Knepley 
4074325cce7SMatthew G Knepley /*@
4080bacdadaSStefano Zampini     MatComputeOperatorTranspose - Computes the explicit matrix representation of
409f3b1f45cSBarry Smith         a give matrix that can apply MatMultTranspose()
410f3b1f45cSBarry Smith 
411c3339decSBarry Smith     Collective
412f3b1f45cSBarry Smith 
4136b867d5aSJose E. Roman     Input Parameters:
4146b867d5aSJose E. Roman +   inmat - the matrix
4156b867d5aSJose E. Roman -   mattype - the matrix type for the explicit operator
416f3b1f45cSBarry Smith 
417f3b1f45cSBarry Smith     Output Parameter:
418a5b23f4aSJose E. Roman .   mat - the explicit  operator transposed
419f3b1f45cSBarry Smith 
42011a5261eSBarry Smith     Note:
421186a3e20SStefano Zampini     This computation is done by applying the transpose of the operator to columns of the identity matrix.
422186a3e20SStefano Zampini     This routine is costly in general, and is recommended for use only with relatively small systems.
423186a3e20SStefano Zampini     Currently, this routine uses a dense matrix format if mattype == NULL.
424f3b1f45cSBarry Smith 
425f3b1f45cSBarry Smith     Level: advanced
426f3b1f45cSBarry Smith 
427f3b1f45cSBarry Smith @*/
428d71ae5a4SJacob Faibussowitsch PetscErrorCode MatComputeOperatorTranspose(Mat inmat, MatType mattype, Mat *mat)
429d71ae5a4SJacob Faibussowitsch {
430186a3e20SStefano Zampini   Mat A;
431f3b1f45cSBarry Smith 
432f3b1f45cSBarry Smith   PetscFunctionBegin;
433f3b1f45cSBarry Smith   PetscValidHeaderSpecific(inmat, MAT_CLASSID, 1);
434186a3e20SStefano Zampini   PetscValidPointer(mat, 3);
4359566063dSJacob Faibussowitsch   PetscCall(MatCreateTranspose(inmat, &A));
4369566063dSJacob Faibussowitsch   PetscCall(MatConvert_Shell(A, mattype ? mattype : MATDENSE, MAT_INITIAL_MATRIX, mat));
4379566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A));
4383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
439f3b1f45cSBarry Smith }
440f3b1f45cSBarry Smith 
441f3b1f45cSBarry Smith /*@
4424325cce7SMatthew G Knepley   MatChop - Set all values in the matrix less than the tolerance to zero
4434325cce7SMatthew G Knepley 
4444325cce7SMatthew G Knepley   Input Parameters:
4454325cce7SMatthew G Knepley + A   - The matrix
4464325cce7SMatthew G Knepley - tol - The zero tolerance
4474325cce7SMatthew G Knepley 
4484325cce7SMatthew G Knepley   Output Parameters:
4494325cce7SMatthew G Knepley . A - The chopped matrix
4504325cce7SMatthew G Knepley 
4514325cce7SMatthew G Knepley   Level: intermediate
4524325cce7SMatthew G Knepley 
453db781477SPatrick Sanan .seealso: `MatCreate()`, `MatZeroEntries()`
4543fc99919SSatish Balay  @*/
455d71ae5a4SJacob Faibussowitsch PetscErrorCode MatChop(Mat A, PetscReal tol)
456d71ae5a4SJacob Faibussowitsch {
457038df967SPierre Jolivet   Mat          a;
4584325cce7SMatthew G Knepley   PetscScalar *newVals;
459cf5d3338SPierre Jolivet   PetscInt    *newCols, rStart, rEnd, numRows, maxRows, r, colMax = 0;
460038df967SPierre Jolivet   PetscBool    flg;
4614325cce7SMatthew G Knepley 
4624325cce7SMatthew G Knepley   PetscFunctionBegin;
4639566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)A, &flg, MATSEQDENSE, MATMPIDENSE, ""));
464038df967SPierre Jolivet   if (flg) {
4659566063dSJacob Faibussowitsch     PetscCall(MatDenseGetLocalMatrix(A, &a));
4669566063dSJacob Faibussowitsch     PetscCall(MatDenseGetLDA(a, &r));
4679566063dSJacob Faibussowitsch     PetscCall(MatGetSize(a, &rStart, &rEnd));
4689566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(a, &newVals));
469038df967SPierre Jolivet     for (; colMax < rEnd; ++colMax) {
470ad540459SPierre Jolivet       for (maxRows = 0; maxRows < rStart; ++maxRows) newVals[maxRows + colMax * r] = PetscAbsScalar(newVals[maxRows + colMax * r]) < tol ? 0.0 : newVals[maxRows + colMax * r];
471038df967SPierre Jolivet     }
4729566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArray(a, &newVals));
473038df967SPierre Jolivet   } else {
4749566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(A, &rStart, &rEnd));
4759566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(A));
4764325cce7SMatthew G Knepley     for (r = rStart; r < rEnd; ++r) {
4774325cce7SMatthew G Knepley       PetscInt ncols;
4784325cce7SMatthew G Knepley 
4799566063dSJacob Faibussowitsch       PetscCall(MatGetRow(A, r, &ncols, NULL, NULL));
4805f80ce2aSJacob Faibussowitsch       colMax = PetscMax(colMax, ncols);
4819566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(A, r, &ncols, NULL, NULL));
4824325cce7SMatthew G Knepley     }
4834325cce7SMatthew G Knepley     numRows = rEnd - rStart;
4841c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&numRows, &maxRows, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)A)));
4859566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(colMax, &newCols, colMax, &newVals));
4869566063dSJacob Faibussowitsch     PetscCall(MatGetOption(A, MAT_NO_OFF_PROC_ENTRIES, &flg)); /* cache user-defined value */
4879566063dSJacob Faibussowitsch     PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
488cf5d3338SPierre Jolivet     /* short-circuit code in MatAssemblyBegin() and MatAssemblyEnd()             */
489cf5d3338SPierre Jolivet     /* that are potentially called many times depending on the distribution of A */
4904325cce7SMatthew G Knepley     for (r = rStart; r < rStart + maxRows; ++r) {
4914325cce7SMatthew G Knepley       const PetscScalar *vals;
4924325cce7SMatthew G Knepley       const PetscInt    *cols;
493fad45679SMatthew G. Knepley       PetscInt           ncols, newcols, c;
4944325cce7SMatthew G Knepley 
4954325cce7SMatthew G Knepley       if (r < rEnd) {
4969566063dSJacob Faibussowitsch         PetscCall(MatGetRow(A, r, &ncols, &cols, &vals));
4974325cce7SMatthew G Knepley         for (c = 0; c < ncols; ++c) {
4984325cce7SMatthew G Knepley           newCols[c] = cols[c];
4994325cce7SMatthew G Knepley           newVals[c] = PetscAbsScalar(vals[c]) < tol ? 0.0 : vals[c];
5004325cce7SMatthew G Knepley         }
501fad45679SMatthew G. Knepley         newcols = ncols;
5029566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(A, r, &ncols, &cols, &vals));
5039566063dSJacob Faibussowitsch         PetscCall(MatSetValues(A, 1, &r, newcols, newCols, newVals, INSERT_VALUES));
5044325cce7SMatthew G Knepley       }
5059566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
5069566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
5074325cce7SMatthew G Knepley     }
5089566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(A));
5099566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCols, newVals));
5109566063dSJacob Faibussowitsch     PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, flg)); /* reset option to its user-defined value */
511038df967SPierre Jolivet   }
5123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5134325cce7SMatthew G Knepley }
514