xref: /petsc/src/mat/utils/axpy.c (revision d9b70fcd6cd17cba869b7cfd98301b53b74a4385)
1af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I   "petscmat.h"  I*/
26f79c3a4SBarry Smith 
3d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTransposeAXPY_Private(Mat Y, PetscScalar a, Mat X, MatStructure str, Mat T)
4d71ae5a4SJacob Faibussowitsch {
5d54c938cSPierre Jolivet   Mat A, F;
65f80ce2aSJacob Faibussowitsch   PetscErrorCode (*f)(Mat, Mat *);
7d54c938cSPierre Jolivet 
8d54c938cSPierre Jolivet   PetscFunctionBegin;
99566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)T, "MatTransposeGetMat_C", &f));
10d54c938cSPierre Jolivet   if (f) {
119566063dSJacob Faibussowitsch     PetscCall(MatTransposeGetMat(T, &A));
12d54c938cSPierre Jolivet     if (T == X) {
13013e2dc7SBarry Smith       PetscCall(PetscInfo(NULL, "Explicitly transposing X of type MATTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
149566063dSJacob Faibussowitsch       PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &F));
15d54c938cSPierre Jolivet       A = Y;
16d54c938cSPierre Jolivet     } else {
17013e2dc7SBarry Smith       PetscCall(PetscInfo(NULL, "Transposing X because Y of type MATTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
189566063dSJacob Faibussowitsch       PetscCall(MatTranspose(X, MAT_INITIAL_MATRIX, &F));
19d54c938cSPierre Jolivet     }
20d54c938cSPierre Jolivet   } else {
219566063dSJacob Faibussowitsch     PetscCall(MatHermitianTransposeGetMat(T, &A));
22d54c938cSPierre Jolivet     if (T == X) {
2352cd20c4SPierre Jolivet       PetscCall(PetscInfo(NULL, "Explicitly Hermitian transposing X of type MATHERMITIANTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
249566063dSJacob Faibussowitsch       PetscCall(MatHermitianTranspose(A, MAT_INITIAL_MATRIX, &F));
25d54c938cSPierre Jolivet       A = Y;
26d54c938cSPierre Jolivet     } else {
2752cd20c4SPierre Jolivet       PetscCall(PetscInfo(NULL, "Hermitian transposing X because Y of type MATHERMITIANTRANSPOSEVIRTUAL to perform MatAXPY()\n"));
289566063dSJacob Faibussowitsch       PetscCall(MatHermitianTranspose(X, MAT_INITIAL_MATRIX, &F));
29d54c938cSPierre Jolivet     }
30d54c938cSPierre Jolivet   }
319566063dSJacob Faibussowitsch   PetscCall(MatAXPY(A, a, F, str));
329566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&F));
333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34d54c938cSPierre Jolivet }
35d54c938cSPierre Jolivet 
3606be10caSBarry Smith /*@
3721c89e3eSBarry Smith   MatAXPY - Computes Y = a*X + Y.
386f79c3a4SBarry Smith 
39c3339decSBarry Smith   Logically Collective
40fee21e36SBarry Smith 
4198a79cdbSBarry Smith   Input Parameters:
42607cd303SBarry Smith + a   - the scalar multiplier
43607cd303SBarry Smith . X   - the first matrix
44607cd303SBarry Smith . Y   - the second matrix
4527430b45SBarry 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)
46edf9a46cSStefano Zampini 
472860a424SLois Curfman McInnes   Level: intermediate
482860a424SLois Curfman McInnes 
491cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatAYPX()`
5006be10caSBarry Smith  @*/
51d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY(Mat Y, PetscScalar a, Mat X, MatStructure str)
52d71ae5a4SJacob Faibussowitsch {
53646531bbSStefano Zampini   PetscInt  M1, M2, N1, N2;
54c1ac3661SBarry Smith   PetscInt  m1, m2, n1, n2;
55a683ea4aSPierre Jolivet   PetscBool sametype, transpose;
566f79c3a4SBarry Smith 
573a40ed3dSBarry Smith   PetscFunctionBegin;
580700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
59c5eb9154SBarry Smith   PetscValidLogicalCollectiveScalar(Y, a, 2);
60646531bbSStefano Zampini   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
61646531bbSStefano Zampini   PetscCheckSameComm(Y, 1, X, 3);
629566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X, &M1, &N1));
639566063dSJacob Faibussowitsch   PetscCall(MatGetSize(Y, &M2, &N2));
649566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(X, &m1, &n1));
659566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Y, &m2, &n2));
662c71b3e2SJacob 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);
672c71b3e2SJacob 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);
682c71b3e2SJacob Faibussowitsch   PetscCheck(Y->assembled, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix (Y)");
692c71b3e2SJacob Faibussowitsch   PetscCheck(X->assembled, PetscObjectComm((PetscObject)X), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix (X)");
703ba16761SJacob Faibussowitsch   if (a == (PetscScalar)0.0) PetscFunctionReturn(PETSC_SUCCESS);
71edf9a46cSStefano Zampini   if (Y == X) {
729566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 1.0 + a));
733ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
74edf9a46cSStefano Zampini   }
75013e2dc7SBarry Smith   PetscCall(PetscObjectObjectTypeCompare((PetscObject)X, (PetscObject)Y, &sametype));
769566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(MAT_AXPY, Y, 0, 0, 0));
7793c87e65SStefano Zampini   if (Y->ops->axpy && (sametype || X->ops->axpy == Y->ops->axpy)) {
78dbbe0bcdSBarry Smith     PetscUseTypeMethod(Y, axpy, a, X, str);
79d4bb536fSBarry Smith   } else {
80013e2dc7SBarry Smith     PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &transpose, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
81a683ea4aSPierre Jolivet     if (transpose) {
829566063dSJacob Faibussowitsch       PetscCall(MatTransposeAXPY_Private(Y, a, X, str, X));
83a683ea4aSPierre Jolivet     } else {
84013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)Y, &transpose, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
85a683ea4aSPierre Jolivet       if (transpose) {
869566063dSJacob Faibussowitsch         PetscCall(MatTransposeAXPY_Private(Y, a, X, str, Y));
87a683ea4aSPierre Jolivet       } else {
889566063dSJacob Faibussowitsch         PetscCall(MatAXPY_Basic(Y, a, X, str));
89607cd303SBarry Smith       }
90a683ea4aSPierre Jolivet     }
91a683ea4aSPierre Jolivet   }
929566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(MAT_AXPY, Y, 0, 0, 0));
933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
94607cd303SBarry Smith }
95607cd303SBarry Smith 
96d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_Basic_Preallocate(Mat Y, Mat X, Mat *B)
97d71ae5a4SJacob Faibussowitsch {
9827afe9e8SStefano Zampini   PetscErrorCode (*preall)(Mat, Mat, Mat *) = NULL;
99646531bbSStefano Zampini 
100646531bbSStefano Zampini   PetscFunctionBegin;
101646531bbSStefano Zampini   /* look for any available faster alternative to the general preallocator */
1029566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)Y, "MatAXPYGetPreallocation_C", &preall));
103646531bbSStefano Zampini   if (preall) {
1049566063dSJacob Faibussowitsch     PetscCall((*preall)(Y, X, B));
105646531bbSStefano Zampini   } else { /* Use MatPrellocator, assumes same row-col distribution */
106646531bbSStefano Zampini     Mat      preallocator;
107646531bbSStefano Zampini     PetscInt r, rstart, rend;
108646531bbSStefano Zampini     PetscInt m, n, M, N;
109646531bbSStefano Zampini 
1109566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(Y));
1119566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(X));
1129566063dSJacob Faibussowitsch     PetscCall(MatGetSize(Y, &M, &N));
1139566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(Y, &m, &n));
1149566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &preallocator));
1159566063dSJacob Faibussowitsch     PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
1169566063dSJacob Faibussowitsch     PetscCall(MatSetLayouts(preallocator, Y->rmap, Y->cmap));
1179566063dSJacob Faibussowitsch     PetscCall(MatSetUp(preallocator));
1189566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(preallocator, &rstart, &rend));
119646531bbSStefano Zampini     for (r = rstart; r < rend; ++r) {
120646531bbSStefano Zampini       PetscInt           ncols;
121646531bbSStefano Zampini       const PetscInt    *row;
122646531bbSStefano Zampini       const PetscScalar *vals;
123646531bbSStefano Zampini 
1249566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, r, &ncols, &row, &vals));
1259566063dSJacob Faibussowitsch       PetscCall(MatSetValues(preallocator, 1, &r, ncols, row, vals, INSERT_VALUES));
1269566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, r, &ncols, &row, &vals));
1279566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, r, &ncols, &row, &vals));
1289566063dSJacob Faibussowitsch       PetscCall(MatSetValues(preallocator, 1, &r, ncols, row, vals, INSERT_VALUES));
1299566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, r, &ncols, &row, &vals));
130646531bbSStefano Zampini     }
1319566063dSJacob Faibussowitsch     PetscCall(MatSetOption(preallocator, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
1329566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
1339566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
1349566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(Y));
1359566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(X));
136646531bbSStefano Zampini 
1379566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), B));
1389566063dSJacob Faibussowitsch     PetscCall(MatSetType(*B, ((PetscObject)Y)->type_name));
1399566063dSJacob Faibussowitsch     PetscCall(MatSetLayouts(*B, Y->rmap, Y->cmap));
1409566063dSJacob Faibussowitsch     PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_FALSE, *B));
1419566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&preallocator));
142646531bbSStefano Zampini   }
1433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
144646531bbSStefano Zampini }
145646531bbSStefano Zampini 
146d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_Basic(Mat Y, PetscScalar a, Mat X, MatStructure str)
147d71ae5a4SJacob Faibussowitsch {
148be705e3aSPierre Jolivet   PetscBool isshell, isdense, isnest;
149edf9a46cSStefano Zampini 
150edf9a46cSStefano Zampini   PetscFunctionBegin;
1519566063dSJacob Faibussowitsch   PetscCall(MatIsShell(Y, &isshell));
152edf9a46cSStefano Zampini   if (isshell) { /* MatShell has special support for AXPY */
153edf9a46cSStefano Zampini     PetscErrorCode (*f)(Mat, PetscScalar, Mat, MatStructure);
154edf9a46cSStefano Zampini 
1559566063dSJacob Faibussowitsch     PetscCall(MatGetOperation(Y, MATOP_AXPY, (void (**)(void)) & f));
156edf9a46cSStefano Zampini     if (f) {
1579566063dSJacob Faibussowitsch       PetscCall((*f)(Y, a, X, str));
1583ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
159edf9a46cSStefano Zampini     }
160edf9a46cSStefano Zampini   }
16193c87e65SStefano Zampini   /* no need to preallocate if Y is dense */
1629566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isdense, MATSEQDENSE, MATMPIDENSE, ""));
163be705e3aSPierre Jolivet   if (isdense) {
1649566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATNEST, &isnest));
165be705e3aSPierre Jolivet     if (isnest) {
1669566063dSJacob Faibussowitsch       PetscCall(MatAXPY_Dense_Nest(Y, a, X));
1673ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
168be705e3aSPierre Jolivet     }
169be705e3aSPierre Jolivet     if (str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN) str = SUBSET_NONZERO_PATTERN;
170be705e3aSPierre Jolivet   }
171a6ab3590SBarry Smith   if (str != DIFFERENT_NONZERO_PATTERN && str != UNKNOWN_NONZERO_PATTERN) {
172edf9a46cSStefano Zampini     PetscInt           i, start, end, j, ncols, m, n;
17338baddfdSBarry Smith     const PetscInt    *row;
174b3cc6726SBarry Smith     PetscScalar       *val;
175b3cc6726SBarry Smith     const PetscScalar *vals;
176607cd303SBarry Smith 
1779566063dSJacob Faibussowitsch     PetscCall(MatGetSize(X, &m, &n));
1789566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(X, &start, &end));
1799566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(X));
180f4df32b1SMatthew Knepley     if (a == 1.0) {
181d4bb536fSBarry Smith       for (i = start; i < end; i++) {
1829566063dSJacob Faibussowitsch         PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
1839566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Y, 1, &i, ncols, row, vals, ADD_VALUES));
1849566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
185d4bb536fSBarry Smith       }
186d4bb536fSBarry Smith     } else {
18721a3365eSStefano Zampini       PetscInt vs = 100;
18821a3365eSStefano Zampini       /* realloc if needed, as this function may be used in parallel */
1899566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(vs, &val));
19006be10caSBarry Smith       for (i = start; i < end; i++) {
1919566063dSJacob Faibussowitsch         PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
19221a3365eSStefano Zampini         if (vs < ncols) {
19321a3365eSStefano Zampini           vs = PetscMin(2 * ncols, n);
1949566063dSJacob Faibussowitsch           PetscCall(PetscRealloc(vs * sizeof(*val), &val));
1956f79c3a4SBarry Smith         }
19621a3365eSStefano Zampini         for (j = 0; j < ncols; j++) val[j] = a * vals[j];
1979566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Y, 1, &i, ncols, row, val, ADD_VALUES));
1989566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
1996f79c3a4SBarry Smith       }
2009566063dSJacob Faibussowitsch       PetscCall(PetscFree(val));
201d4bb536fSBarry Smith     }
2029566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(X));
2039566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
2049566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
205edf9a46cSStefano Zampini   } else {
206edf9a46cSStefano Zampini     Mat B;
207edf9a46cSStefano Zampini 
2089566063dSJacob Faibussowitsch     PetscCall(MatAXPY_Basic_Preallocate(Y, X, &B));
2099566063dSJacob Faibussowitsch     PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str));
2109566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(Y, &B));
211edf9a46cSStefano Zampini   }
2123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2136f79c3a4SBarry Smith }
214052efed2SBarry Smith 
215d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_BasicWithPreallocation(Mat B, Mat Y, PetscScalar a, Mat X, MatStructure str)
216d71ae5a4SJacob Faibussowitsch {
217ec7775f6SShri Abhyankar   PetscInt           i, start, end, j, ncols, m, n;
218ec7775f6SShri Abhyankar   const PetscInt    *row;
219ec7775f6SShri Abhyankar   PetscScalar       *val;
220ec7775f6SShri Abhyankar   const PetscScalar *vals;
221ec7775f6SShri Abhyankar 
222ec7775f6SShri Abhyankar   PetscFunctionBegin;
2239566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X, &m, &n));
2249566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(X, &start, &end));
2259566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(Y));
2269566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(X));
227ec7775f6SShri Abhyankar   if (a == 1.0) {
228ec7775f6SShri Abhyankar     for (i = start; i < end; i++) {
2299566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, i, &ncols, &row, &vals));
2309566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2319566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, i, &ncols, &row, &vals));
232ec7775f6SShri Abhyankar 
2339566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
2349566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2359566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
236ec7775f6SShri Abhyankar     }
237ec7775f6SShri Abhyankar   } else {
23821a3365eSStefano Zampini     PetscInt vs = 100;
23921a3365eSStefano Zampini     /* realloc if needed, as this function may be used in parallel */
2409566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(vs, &val));
241ec7775f6SShri Abhyankar     for (i = start; i < end; i++) {
2429566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, i, &ncols, &row, &vals));
2439566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2449566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, i, &ncols, &row, &vals));
245ec7775f6SShri Abhyankar 
2469566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
24721a3365eSStefano Zampini       if (vs < ncols) {
24821a3365eSStefano Zampini         vs = PetscMin(2 * ncols, n);
2499566063dSJacob Faibussowitsch         PetscCall(PetscRealloc(vs * sizeof(*val), &val));
250ec7775f6SShri Abhyankar       }
25121a3365eSStefano Zampini       for (j = 0; j < ncols; j++) val[j] = a * vals[j];
2529566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, val, ADD_VALUES));
2539566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
254ec7775f6SShri Abhyankar     }
2559566063dSJacob Faibussowitsch     PetscCall(PetscFree(val));
256ec7775f6SShri Abhyankar   }
2579566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(Y));
2589566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(X));
2599566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
2609566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
2613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
262ec7775f6SShri Abhyankar }
263ec7775f6SShri Abhyankar 
264052efed2SBarry Smith /*@
2652ef1f0ffSBarry Smith   MatShift - Computes `Y =  Y + a I`, where `a` is a `PetscScalar`
266052efed2SBarry Smith 
267c3339decSBarry Smith   Neighbor-wise Collective
268fee21e36SBarry Smith 
26998a79cdbSBarry Smith   Input Parameters:
27027430b45SBarry Smith + Y - the matrix
27127430b45SBarry Smith - a - the `PetscScalar`
27298a79cdbSBarry Smith 
2732860a424SLois Curfman McInnes   Level: intermediate
2742860a424SLois Curfman McInnes 
27595452b02SPatrick Sanan   Notes:
27627430b45SBarry 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)
27784e19e3eSJunchao Zhang 
2782ef1f0ffSBarry Smith   If the matrix `Y` is missing some diagonal entries this routine can be very slow. To make it fast one should initially
2796f33a894SBarry 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
280edf9a46cSStefano Zampini   entry). No operation is performed when a is zero.
2816f33a894SBarry Smith 
28227430b45SBarry Smith   To form Y = Y + diag(V) use `MatDiagonalSet()`
2830c0fd78eSBarry Smith 
2841cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatDiagonalSet()`, `MatScale()`, `MatDiagonalScale()`
285052efed2SBarry Smith  @*/
286d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShift(Mat Y, PetscScalar a)
287d71ae5a4SJacob Faibussowitsch {
2883a40ed3dSBarry Smith   PetscFunctionBegin;
2890700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
2905f80ce2aSJacob Faibussowitsch   PetscCheck(Y->assembled, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2915f80ce2aSJacob Faibussowitsch   PetscCheck(!Y->factortype, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2924994cf47SJed Brown   MatCheckPreallocated(Y, 1);
2933ba16761SJacob Faibussowitsch   if (a == 0.0) PetscFunctionReturn(PETSC_SUCCESS);
294b50b34bdSBarry Smith 
295dbbe0bcdSBarry Smith   if (Y->ops->shift) PetscUseTypeMethod(Y, shift, a);
2969566063dSJacob Faibussowitsch   else PetscCall(MatShift_Basic(Y, a));
2977d68702bSBarry Smith 
2989566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
2993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
300052efed2SBarry Smith }
3016d84be18SBarry Smith 
302d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalSet_Default(Mat Y, Vec D, InsertMode is)
303d71ae5a4SJacob Faibussowitsch {
30467576b8bSBarry Smith   PetscInt           i, start, end;
305fa2e578bSStefano Zampini   const PetscScalar *v;
30609f38230SBarry Smith 
30709f38230SBarry Smith   PetscFunctionBegin;
3089566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(Y, &start, &end));
3099566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(D, &v));
31048a46eb9SPierre Jolivet   for (i = start; i < end; i++) PetscCall(MatSetValues(Y, 1, &i, 1, &i, v + i - start, is));
3119566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(D, &v));
3129566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
3139566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
3143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31509f38230SBarry Smith }
31609f38230SBarry Smith 
3176d84be18SBarry Smith /*@
3182ef1f0ffSBarry Smith   MatDiagonalSet - Computes `Y` = `Y` + `D`, where `D` is a diagonal matrix
3192ef1f0ffSBarry Smith   that is represented as a vector. Or Y[i,i] = D[i] if `InsertMode` is
3202ef1f0ffSBarry Smith   `INSERT_VALUES`.
3216d84be18SBarry Smith 
322c3339decSBarry Smith   Neighbor-wise Collective
32348e586daSJose E. Roman 
3246d84be18SBarry Smith   Input Parameters:
32598a79cdbSBarry Smith + Y  - the input matrix
326f56f2b3fSBarry Smith . D  - the diagonal matrix, represented as a vector
327fe59aa6dSJacob Faibussowitsch - is - `INSERT_VALUES` or `ADD_VALUES`
3286f33a894SBarry Smith 
3292860a424SLois Curfman McInnes   Level: intermediate
3302860a424SLois Curfman McInnes 
3312ef1f0ffSBarry Smith   Note:
3322ef1f0ffSBarry Smith   If the matrix `Y` is missing some diagonal entries this routine can be very slow. To make it fast one should initially
3332ef1f0ffSBarry 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
3342ef1f0ffSBarry Smith   entry).
3352ef1f0ffSBarry Smith 
3361cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatShift()`, `MatScale()`, `MatDiagonalScale()`
3376d84be18SBarry Smith @*/
338d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalSet(Mat Y, Vec D, InsertMode is)
339d71ae5a4SJacob Faibussowitsch {
34067576b8bSBarry Smith   PetscInt matlocal, veclocal;
3416d84be18SBarry Smith 
3423a40ed3dSBarry Smith   PetscFunctionBegin;
3430700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
3440700a824SBarry Smith   PetscValidHeaderSpecific(D, VEC_CLASSID, 2);
3459566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Y, &matlocal, NULL));
3469566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(D, &veclocal));
3475f80ce2aSJacob 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);
348dbbe0bcdSBarry Smith   if (Y->ops->diagonalset) PetscUseTypeMethod(Y, diagonalset, D, is);
349dbbe0bcdSBarry Smith   else PetscCall(MatDiagonalSet_Default(Y, D, is));
3509566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
3513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3526d84be18SBarry Smith }
353d4bb536fSBarry Smith 
354d4bb536fSBarry Smith /*@
35504aac2b0SHong Zhang   MatAYPX - Computes Y = a*Y + X.
356d4bb536fSBarry Smith 
3572ef1f0ffSBarry Smith   Logically Collective
358fee21e36SBarry Smith 
35998a79cdbSBarry Smith   Input Parameters:
3602ef1f0ffSBarry Smith + a   - the `PetscScalar` multiplier
36104aac2b0SHong Zhang . Y   - the first matrix
36204aac2b0SHong Zhang . X   - the second matrix
363aaa8cc7dSPierre 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)
364d4bb536fSBarry Smith 
3652860a424SLois Curfman McInnes   Level: intermediate
3662860a424SLois Curfman McInnes 
3671cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatAXPY()`
368d4bb536fSBarry Smith  @*/
369d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAYPX(Mat Y, PetscScalar a, Mat X, MatStructure str)
370d71ae5a4SJacob Faibussowitsch {
3713a40ed3dSBarry Smith   PetscFunctionBegin;
3729566063dSJacob Faibussowitsch   PetscCall(MatScale(Y, a));
3739566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Y, 1.0, X, str));
3743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
375d4bb536fSBarry Smith }
376b0a32e0cSBarry Smith 
377fe59aa6dSJacob Faibussowitsch /*@C
3780bacdadaSStefano Zampini   MatComputeOperator - Computes the explicit matrix
379b0a32e0cSBarry Smith 
380c3339decSBarry Smith   Collective
381b0a32e0cSBarry Smith 
382d8d19677SJose E. Roman   Input Parameters:
383186a3e20SStefano Zampini + inmat   - the matrix
384186a3e20SStefano Zampini - mattype - the matrix type for the explicit operator
385b0a32e0cSBarry Smith 
386b0a32e0cSBarry Smith   Output Parameter:
387a5b23f4aSJose E. Roman . mat - the explicit  operator
388b0a32e0cSBarry Smith 
3892ef1f0ffSBarry Smith   Level: advanced
3902ef1f0ffSBarry Smith 
39111a5261eSBarry Smith   Note:
392186a3e20SStefano Zampini   This computation is done by applying the operators to columns of the identity matrix.
393186a3e20SStefano Zampini   This routine is costly in general, and is recommended for use only with relatively small systems.
3942ef1f0ffSBarry Smith   Currently, this routine uses a dense matrix format if `mattype` == `NULL`.
395b0a32e0cSBarry Smith 
3961cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatMult()`, `MatComputeOperatorTranspose()`
397b0a32e0cSBarry Smith @*/
398d71ae5a4SJacob Faibussowitsch PetscErrorCode MatComputeOperator(Mat inmat, MatType mattype, Mat *mat)
399d71ae5a4SJacob Faibussowitsch {
400b0a32e0cSBarry Smith   PetscFunctionBegin;
4010700a824SBarry Smith   PetscValidHeaderSpecific(inmat, MAT_CLASSID, 1);
4024f572ea9SToby Isaac   PetscAssertPointer(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 
407fe59aa6dSJacob Faibussowitsch /*@C
4080bacdadaSStefano Zampini   MatComputeOperatorTranspose - Computes the explicit matrix representation of
4092ef1f0ffSBarry 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 
4202ef1f0ffSBarry Smith   Level: advanced
4212ef1f0ffSBarry Smith 
42211a5261eSBarry Smith   Note:
423186a3e20SStefano Zampini   This computation is done by applying the transpose of the operator to columns of the identity matrix.
424186a3e20SStefano Zampini   This routine is costly in general, and is recommended for use only with relatively small systems.
4252ef1f0ffSBarry Smith   Currently, this routine uses a dense matrix format if `mattype` == `NULL`.
426f3b1f45cSBarry Smith 
4271cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatMult()`, `MatComputeOperator()`
428f3b1f45cSBarry Smith @*/
429d71ae5a4SJacob Faibussowitsch PetscErrorCode MatComputeOperatorTranspose(Mat inmat, MatType mattype, Mat *mat)
430d71ae5a4SJacob Faibussowitsch {
431186a3e20SStefano Zampini   Mat A;
432f3b1f45cSBarry Smith 
433f3b1f45cSBarry Smith   PetscFunctionBegin;
434f3b1f45cSBarry Smith   PetscValidHeaderSpecific(inmat, MAT_CLASSID, 1);
4354f572ea9SToby Isaac   PetscAssertPointer(mat, 3);
4369566063dSJacob Faibussowitsch   PetscCall(MatCreateTranspose(inmat, &A));
4379566063dSJacob Faibussowitsch   PetscCall(MatConvert_Shell(A, mattype ? mattype : MATDENSE, MAT_INITIAL_MATRIX, mat));
4389566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A));
4393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
440f3b1f45cSBarry Smith }
441f3b1f45cSBarry Smith 
442f3b1f45cSBarry Smith /*@
4432ce66baaSPierre 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
4444325cce7SMatthew G Knepley 
4454325cce7SMatthew G Knepley   Input Parameters:
4464325cce7SMatthew G Knepley + A        - The matrix
4472ce66baaSPierre Jolivet . tol      - The zero tolerance
4482ce66baaSPierre 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
4492ce66baaSPierre 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
4504325cce7SMatthew G Knepley 
4514325cce7SMatthew G Knepley   Level: intermediate
4524325cce7SMatthew G Knepley 
453*d9b70fcdSPierre Jolivet .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatZeroEntries()`, `MatEliminateZeros()`, `VecFilter()`
4543fc99919SSatish Balay  @*/
4552ce66baaSPierre Jolivet PetscErrorCode MatFilter(Mat A, PetscReal tol, PetscBool compress, PetscBool keep)
456d71ae5a4SJacob Faibussowitsch {
457038df967SPierre Jolivet   Mat          a;
4584325cce7SMatthew G Knepley   PetscScalar *newVals;
45934bf4ff8Smarkadams4   PetscInt    *newCols, rStart, rEnd, maxRows, r, colMax = 0, nnz0 = 0, nnz1 = 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) {
47082fa6941SPierre 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 {
4743da7c217SPierre Jolivet     const PetscInt *ranges;
4753da7c217SPierre Jolivet     PetscMPIInt     rank, size;
4763da7c217SPierre Jolivet 
4773da7c217SPierre Jolivet     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank));
4783da7c217SPierre Jolivet     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
4793da7c217SPierre Jolivet     PetscCall(MatGetOwnershipRanges(A, &ranges));
4803da7c217SPierre Jolivet     rStart = ranges[rank];
4813da7c217SPierre Jolivet     rEnd   = ranges[rank + 1];
4829566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(A));
4834325cce7SMatthew G Knepley     for (r = rStart; r < rEnd; ++r) {
4844325cce7SMatthew G Knepley       PetscInt ncols;
4854325cce7SMatthew G Knepley 
4869566063dSJacob Faibussowitsch       PetscCall(MatGetRow(A, r, &ncols, NULL, NULL));
4875f80ce2aSJacob Faibussowitsch       colMax = PetscMax(colMax, ncols);
4889566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(A, r, &ncols, NULL, NULL));
4894325cce7SMatthew G Knepley     }
4903da7c217SPierre Jolivet     maxRows = 0;
4913da7c217SPierre Jolivet     for (r = 0; r < size; ++r) maxRows = PetscMax(maxRows, ranges[r + 1] - ranges[r]);
4923da7c217SPierre Jolivet     PetscCall(PetscCalloc2(colMax, &newCols, colMax, &newVals));
4939566063dSJacob Faibussowitsch     PetscCall(MatGetOption(A, MAT_NO_OFF_PROC_ENTRIES, &flg)); /* cache user-defined value */
4949566063dSJacob Faibussowitsch     PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
495cf5d3338SPierre Jolivet     /* short-circuit code in MatAssemblyBegin() and MatAssemblyEnd()             */
496cf5d3338SPierre Jolivet     /* that are potentially called many times depending on the distribution of A */
4974325cce7SMatthew G Knepley     for (r = rStart; r < rStart + maxRows; ++r) {
4983da7c217SPierre Jolivet       if (r < rEnd) {
4994325cce7SMatthew G Knepley         const PetscScalar *vals;
5004325cce7SMatthew G Knepley         const PetscInt    *cols;
5013da7c217SPierre Jolivet         PetscInt           ncols, newcols = 0, c;
5024325cce7SMatthew G Knepley 
5039566063dSJacob Faibussowitsch         PetscCall(MatGetRow(A, r, &ncols, &cols, &vals));
50434bf4ff8Smarkadams4         nnz0 += ncols - 1;
5054325cce7SMatthew G Knepley         for (c = 0; c < ncols; ++c) {
50682fa6941SPierre Jolivet           if (PetscUnlikely(PetscAbsScalar(vals[c]) <= tol)) newCols[newcols++] = cols[c];
5074325cce7SMatthew G Knepley         }
50834bf4ff8Smarkadams4         nnz1 += ncols - newcols - 1;
5099566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(A, r, &ncols, &cols, &vals));
5109566063dSJacob Faibussowitsch         PetscCall(MatSetValues(A, 1, &r, newcols, newCols, newVals, INSERT_VALUES));
5114325cce7SMatthew G Knepley       }
5129566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
5139566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
5144325cce7SMatthew G Knepley     }
5159566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(A));
5169566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCols, newVals));
5179566063dSJacob Faibussowitsch     PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, flg)); /* reset option to its user-defined value */
51834bf4ff8Smarkadams4     if (nnz0 > 0) PetscCall(PetscInfo(NULL, "Filtering left %g %% edges in graph\n", 100 * (double)nnz1 / (double)nnz0));
51934bf4ff8Smarkadams4     else PetscCall(PetscInfo(NULL, "Warning: %d edges to filter with %d rows\n", (int)nnz0, (int)maxRows));
520038df967SPierre Jolivet   }
5212ce66baaSPierre Jolivet   if (compress && A->ops->eliminatezeros) {
5222ce66baaSPierre Jolivet     Mat       B;
52324c7e8a4SPierre Jolivet     PetscBool flg;
5242ce66baaSPierre Jolivet 
52524c7e8a4SPierre Jolivet     PetscCall(PetscObjectTypeCompareAny((PetscObject)A, &flg, MATSEQAIJHIPSPARSE, MATMPIAIJHIPSPARSE, ""));
52624c7e8a4SPierre Jolivet     if (!flg) {
5272ce66baaSPierre Jolivet       PetscCall(MatEliminateZeros(A, keep));
5282ce66baaSPierre Jolivet       PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &B));
5292ce66baaSPierre Jolivet       PetscCall(MatHeaderReplace(A, &B));
5302ce66baaSPierre Jolivet     }
53124c7e8a4SPierre Jolivet   }
5323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5334325cce7SMatthew G Knepley }
534