xref: /petsc/src/mat/utils/axpy.c (revision c3339decea92175325d9368fa13196bcd0e0e58b)
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));
34d54c938cSPierre Jolivet   PetscFunctionReturn(0);
35d54c938cSPierre Jolivet }
36d54c938cSPierre Jolivet 
3706be10caSBarry Smith /*@
3821c89e3eSBarry Smith    MatAXPY - Computes Y = a*X + Y.
396f79c3a4SBarry Smith 
40*c3339decSBarry 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
46531d0c6aSBarry 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)
4798a79cdbSBarry Smith 
4811a5261eSBarry Smith    Note:
4911a5261eSBarry Smith    No operation is performed when a is zero.
50edf9a46cSStefano Zampini 
512860a424SLois Curfman McInnes    Level: intermediate
522860a424SLois Curfman McInnes 
53db781477SPatrick Sanan .seealso: `MatAYPX()`
5406be10caSBarry Smith  @*/
55d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY(Mat Y, PetscScalar a, Mat X, MatStructure str)
56d71ae5a4SJacob Faibussowitsch {
57646531bbSStefano Zampini   PetscInt  M1, M2, N1, N2;
58c1ac3661SBarry Smith   PetscInt  m1, m2, n1, n2;
59a683ea4aSPierre Jolivet   PetscBool sametype, transpose;
606f79c3a4SBarry Smith 
613a40ed3dSBarry Smith   PetscFunctionBegin;
620700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
63c5eb9154SBarry Smith   PetscValidLogicalCollectiveScalar(Y, a, 2);
64646531bbSStefano Zampini   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
65646531bbSStefano Zampini   PetscCheckSameComm(Y, 1, X, 3);
669566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X, &M1, &N1));
679566063dSJacob Faibussowitsch   PetscCall(MatGetSize(Y, &M2, &N2));
689566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(X, &m1, &n1));
699566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Y, &m2, &n2));
702c71b3e2SJacob 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);
712c71b3e2SJacob 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);
722c71b3e2SJacob Faibussowitsch   PetscCheck(Y->assembled, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix (Y)");
732c71b3e2SJacob Faibussowitsch   PetscCheck(X->assembled, PetscObjectComm((PetscObject)X), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix (X)");
74edf9a46cSStefano Zampini   if (a == (PetscScalar)0.0) PetscFunctionReturn(0);
75edf9a46cSStefano Zampini   if (Y == X) {
769566063dSJacob Faibussowitsch     PetscCall(MatScale(Y, 1.0 + a));
77edf9a46cSStefano Zampini     PetscFunctionReturn(0);
78edf9a46cSStefano Zampini   }
79013e2dc7SBarry Smith   PetscCall(PetscObjectObjectTypeCompare((PetscObject)X, (PetscObject)Y, &sametype));
809566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(MAT_AXPY, Y, 0, 0, 0));
8193c87e65SStefano Zampini   if (Y->ops->axpy && (sametype || X->ops->axpy == Y->ops->axpy)) {
82dbbe0bcdSBarry Smith     PetscUseTypeMethod(Y, axpy, a, X, str);
83d4bb536fSBarry Smith   } else {
84013e2dc7SBarry Smith     PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &transpose, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
85a683ea4aSPierre Jolivet     if (transpose) {
869566063dSJacob Faibussowitsch       PetscCall(MatTransposeAXPY_Private(Y, a, X, str, X));
87a683ea4aSPierre Jolivet     } else {
88013e2dc7SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)Y, &transpose, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
89a683ea4aSPierre Jolivet       if (transpose) {
909566063dSJacob Faibussowitsch         PetscCall(MatTransposeAXPY_Private(Y, a, X, str, Y));
91a683ea4aSPierre Jolivet       } else {
929566063dSJacob Faibussowitsch         PetscCall(MatAXPY_Basic(Y, a, X, str));
93607cd303SBarry Smith       }
94a683ea4aSPierre Jolivet     }
95a683ea4aSPierre Jolivet   }
969566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(MAT_AXPY, Y, 0, 0, 0));
97607cd303SBarry Smith   PetscFunctionReturn(0);
98607cd303SBarry Smith }
99607cd303SBarry Smith 
100d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_Basic_Preallocate(Mat Y, Mat X, Mat *B)
101d71ae5a4SJacob Faibussowitsch {
10227afe9e8SStefano Zampini   PetscErrorCode (*preall)(Mat, Mat, Mat *) = NULL;
103646531bbSStefano Zampini 
104646531bbSStefano Zampini   PetscFunctionBegin;
105646531bbSStefano Zampini   /* look for any available faster alternative to the general preallocator */
1069566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)Y, "MatAXPYGetPreallocation_C", &preall));
107646531bbSStefano Zampini   if (preall) {
1089566063dSJacob Faibussowitsch     PetscCall((*preall)(Y, X, B));
109646531bbSStefano Zampini   } else { /* Use MatPrellocator, assumes same row-col distribution */
110646531bbSStefano Zampini     Mat      preallocator;
111646531bbSStefano Zampini     PetscInt r, rstart, rend;
112646531bbSStefano Zampini     PetscInt m, n, M, N;
113646531bbSStefano Zampini 
1149566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(Y));
1159566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(X));
1169566063dSJacob Faibussowitsch     PetscCall(MatGetSize(Y, &M, &N));
1179566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(Y, &m, &n));
1189566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &preallocator));
1199566063dSJacob Faibussowitsch     PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
1209566063dSJacob Faibussowitsch     PetscCall(MatSetLayouts(preallocator, Y->rmap, Y->cmap));
1219566063dSJacob Faibussowitsch     PetscCall(MatSetUp(preallocator));
1229566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(preallocator, &rstart, &rend));
123646531bbSStefano Zampini     for (r = rstart; r < rend; ++r) {
124646531bbSStefano Zampini       PetscInt           ncols;
125646531bbSStefano Zampini       const PetscInt    *row;
126646531bbSStefano Zampini       const PetscScalar *vals;
127646531bbSStefano Zampini 
1289566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, r, &ncols, &row, &vals));
1299566063dSJacob Faibussowitsch       PetscCall(MatSetValues(preallocator, 1, &r, ncols, row, vals, INSERT_VALUES));
1309566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, r, &ncols, &row, &vals));
1319566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, r, &ncols, &row, &vals));
1329566063dSJacob Faibussowitsch       PetscCall(MatSetValues(preallocator, 1, &r, ncols, row, vals, INSERT_VALUES));
1339566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, r, &ncols, &row, &vals));
134646531bbSStefano Zampini     }
1359566063dSJacob Faibussowitsch     PetscCall(MatSetOption(preallocator, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
1369566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
1379566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
1389566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(Y));
1399566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(X));
140646531bbSStefano Zampini 
1419566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), B));
1429566063dSJacob Faibussowitsch     PetscCall(MatSetType(*B, ((PetscObject)Y)->type_name));
1439566063dSJacob Faibussowitsch     PetscCall(MatSetLayouts(*B, Y->rmap, Y->cmap));
1449566063dSJacob Faibussowitsch     PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_FALSE, *B));
1459566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&preallocator));
146646531bbSStefano Zampini   }
147646531bbSStefano Zampini   PetscFunctionReturn(0);
148646531bbSStefano Zampini }
149646531bbSStefano Zampini 
150d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_Basic(Mat Y, PetscScalar a, Mat X, MatStructure str)
151d71ae5a4SJacob Faibussowitsch {
152be705e3aSPierre Jolivet   PetscBool isshell, isdense, isnest;
153edf9a46cSStefano Zampini 
154edf9a46cSStefano Zampini   PetscFunctionBegin;
1559566063dSJacob Faibussowitsch   PetscCall(MatIsShell(Y, &isshell));
156edf9a46cSStefano Zampini   if (isshell) { /* MatShell has special support for AXPY */
157edf9a46cSStefano Zampini     PetscErrorCode (*f)(Mat, PetscScalar, Mat, MatStructure);
158edf9a46cSStefano Zampini 
1599566063dSJacob Faibussowitsch     PetscCall(MatGetOperation(Y, MATOP_AXPY, (void (**)(void)) & f));
160edf9a46cSStefano Zampini     if (f) {
1619566063dSJacob Faibussowitsch       PetscCall((*f)(Y, a, X, str));
162edf9a46cSStefano Zampini       PetscFunctionReturn(0);
163edf9a46cSStefano Zampini     }
164edf9a46cSStefano Zampini   }
16593c87e65SStefano Zampini   /* no need to preallocate if Y is dense */
1669566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isdense, MATSEQDENSE, MATMPIDENSE, ""));
167be705e3aSPierre Jolivet   if (isdense) {
1689566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)X, MATNEST, &isnest));
169be705e3aSPierre Jolivet     if (isnest) {
1709566063dSJacob Faibussowitsch       PetscCall(MatAXPY_Dense_Nest(Y, a, X));
171be705e3aSPierre Jolivet       PetscFunctionReturn(0);
172be705e3aSPierre Jolivet     }
173be705e3aSPierre Jolivet     if (str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN) str = SUBSET_NONZERO_PATTERN;
174be705e3aSPierre Jolivet   }
175a6ab3590SBarry Smith   if (str != DIFFERENT_NONZERO_PATTERN && str != UNKNOWN_NONZERO_PATTERN) {
176edf9a46cSStefano Zampini     PetscInt           i, start, end, j, ncols, m, n;
17738baddfdSBarry Smith     const PetscInt    *row;
178b3cc6726SBarry Smith     PetscScalar       *val;
179b3cc6726SBarry Smith     const PetscScalar *vals;
180607cd303SBarry Smith 
1819566063dSJacob Faibussowitsch     PetscCall(MatGetSize(X, &m, &n));
1829566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(X, &start, &end));
1839566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(X));
184f4df32b1SMatthew Knepley     if (a == 1.0) {
185d4bb536fSBarry Smith       for (i = start; i < end; i++) {
1869566063dSJacob Faibussowitsch         PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
1879566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Y, 1, &i, ncols, row, vals, ADD_VALUES));
1889566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
189d4bb536fSBarry Smith       }
190d4bb536fSBarry Smith     } else {
19121a3365eSStefano Zampini       PetscInt vs = 100;
19221a3365eSStefano Zampini       /* realloc if needed, as this function may be used in parallel */
1939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(vs, &val));
19406be10caSBarry Smith       for (i = start; i < end; i++) {
1959566063dSJacob Faibussowitsch         PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
19621a3365eSStefano Zampini         if (vs < ncols) {
19721a3365eSStefano Zampini           vs = PetscMin(2 * ncols, n);
1989566063dSJacob Faibussowitsch           PetscCall(PetscRealloc(vs * sizeof(*val), &val));
1996f79c3a4SBarry Smith         }
20021a3365eSStefano Zampini         for (j = 0; j < ncols; j++) val[j] = a * vals[j];
2019566063dSJacob Faibussowitsch         PetscCall(MatSetValues(Y, 1, &i, ncols, row, val, ADD_VALUES));
2029566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
2036f79c3a4SBarry Smith       }
2049566063dSJacob Faibussowitsch       PetscCall(PetscFree(val));
205d4bb536fSBarry Smith     }
2069566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(X));
2079566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
2089566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
209edf9a46cSStefano Zampini   } else {
210edf9a46cSStefano Zampini     Mat B;
211edf9a46cSStefano Zampini 
2129566063dSJacob Faibussowitsch     PetscCall(MatAXPY_Basic_Preallocate(Y, X, &B));
2139566063dSJacob Faibussowitsch     PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str));
2149566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(Y, &B));
215edf9a46cSStefano Zampini   }
2163a40ed3dSBarry Smith   PetscFunctionReturn(0);
2176f79c3a4SBarry Smith }
218052efed2SBarry Smith 
219d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAXPY_BasicWithPreallocation(Mat B, Mat Y, PetscScalar a, Mat X, MatStructure str)
220d71ae5a4SJacob Faibussowitsch {
221ec7775f6SShri Abhyankar   PetscInt           i, start, end, j, ncols, m, n;
222ec7775f6SShri Abhyankar   const PetscInt    *row;
223ec7775f6SShri Abhyankar   PetscScalar       *val;
224ec7775f6SShri Abhyankar   const PetscScalar *vals;
225ec7775f6SShri Abhyankar 
226ec7775f6SShri Abhyankar   PetscFunctionBegin;
2279566063dSJacob Faibussowitsch   PetscCall(MatGetSize(X, &m, &n));
2289566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(X, &start, &end));
2299566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(Y));
2309566063dSJacob Faibussowitsch   PetscCall(MatGetRowUpperTriangular(X));
231ec7775f6SShri Abhyankar   if (a == 1.0) {
232ec7775f6SShri Abhyankar     for (i = start; i < end; i++) {
2339566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, i, &ncols, &row, &vals));
2349566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2359566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, i, &ncols, &row, &vals));
236ec7775f6SShri Abhyankar 
2379566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
2389566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2399566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
240ec7775f6SShri Abhyankar     }
241ec7775f6SShri Abhyankar   } else {
24221a3365eSStefano Zampini     PetscInt vs = 100;
24321a3365eSStefano Zampini     /* realloc if needed, as this function may be used in parallel */
2449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(vs, &val));
245ec7775f6SShri Abhyankar     for (i = start; i < end; i++) {
2469566063dSJacob Faibussowitsch       PetscCall(MatGetRow(Y, i, &ncols, &row, &vals));
2479566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, vals, ADD_VALUES));
2489566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(Y, i, &ncols, &row, &vals));
249ec7775f6SShri Abhyankar 
2509566063dSJacob Faibussowitsch       PetscCall(MatGetRow(X, i, &ncols, &row, &vals));
25121a3365eSStefano Zampini       if (vs < ncols) {
25221a3365eSStefano Zampini         vs = PetscMin(2 * ncols, n);
2539566063dSJacob Faibussowitsch         PetscCall(PetscRealloc(vs * sizeof(*val), &val));
254ec7775f6SShri Abhyankar       }
25521a3365eSStefano Zampini       for (j = 0; j < ncols; j++) val[j] = a * vals[j];
2569566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &i, ncols, row, val, ADD_VALUES));
2579566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(X, i, &ncols, &row, &vals));
258ec7775f6SShri Abhyankar     }
2599566063dSJacob Faibussowitsch     PetscCall(PetscFree(val));
260ec7775f6SShri Abhyankar   }
2619566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(Y));
2629566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowUpperTriangular(X));
2639566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
2649566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
265ec7775f6SShri Abhyankar   PetscFunctionReturn(0);
266ec7775f6SShri Abhyankar }
267ec7775f6SShri Abhyankar 
268052efed2SBarry Smith /*@
26987828ca2SBarry Smith    MatShift - Computes Y =  Y + a I, where a is a PetscScalar and I is the identity matrix.
270052efed2SBarry Smith 
271*c3339decSBarry Smith    Neighbor-wise Collective
272fee21e36SBarry Smith 
27398a79cdbSBarry Smith    Input Parameters:
27498a79cdbSBarry Smith +  Y - the matrices
27587828ca2SBarry Smith -  a - the PetscScalar
27698a79cdbSBarry Smith 
2772860a424SLois Curfman McInnes    Level: intermediate
2782860a424SLois Curfman McInnes 
27995452b02SPatrick Sanan    Notes:
28084e19e3eSJunchao Zhang     If Y is a rectangular matrix, the shift is done on the main diagonal Y_{ii} of the matrix (https://en.wikipedia.org/wiki/Main_diagonal)
28184e19e3eSJunchao Zhang 
28295452b02SPatrick Sanan     If the matrix Y is missing some diagonal entries this routine can be very slow. To make it fast one should initially
2836f33a894SBarry 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
284edf9a46cSStefano Zampini    entry). No operation is performed when a is zero.
2856f33a894SBarry Smith 
2860c0fd78eSBarry Smith    To form Y = Y + diag(V) use MatDiagonalSet()
2870c0fd78eSBarry Smith 
288db781477SPatrick Sanan .seealso: `MatDiagonalSet()`, `MatScale()`, `MatDiagonalScale()`
289052efed2SBarry Smith  @*/
290d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShift(Mat Y, PetscScalar a)
291d71ae5a4SJacob Faibussowitsch {
2923a40ed3dSBarry Smith   PetscFunctionBegin;
2930700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
2945f80ce2aSJacob Faibussowitsch   PetscCheck(Y->assembled, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2955f80ce2aSJacob Faibussowitsch   PetscCheck(!Y->factortype, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2964994cf47SJed Brown   MatCheckPreallocated(Y, 1);
2971b71c1a7SBarry Smith   if (a == 0.0) PetscFunctionReturn(0);
298b50b34bdSBarry Smith 
299dbbe0bcdSBarry Smith   if (Y->ops->shift) PetscUseTypeMethod(Y, shift, a);
3009566063dSJacob Faibussowitsch   else PetscCall(MatShift_Basic(Y, a));
3017d68702bSBarry Smith 
3029566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
3033a40ed3dSBarry Smith   PetscFunctionReturn(0);
304052efed2SBarry Smith }
3056d84be18SBarry Smith 
306d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalSet_Default(Mat Y, Vec D, InsertMode is)
307d71ae5a4SJacob Faibussowitsch {
30867576b8bSBarry Smith   PetscInt           i, start, end;
309fa2e578bSStefano Zampini   const PetscScalar *v;
31009f38230SBarry Smith 
31109f38230SBarry Smith   PetscFunctionBegin;
3129566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(Y, &start, &end));
3139566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(D, &v));
31448a46eb9SPierre Jolivet   for (i = start; i < end; i++) PetscCall(MatSetValues(Y, 1, &i, 1, &i, v + i - start, is));
3159566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(D, &v));
3169566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
3179566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
31809f38230SBarry Smith   PetscFunctionReturn(0);
31909f38230SBarry Smith }
32009f38230SBarry Smith 
3216d84be18SBarry Smith /*@
322f56f2b3fSBarry Smith    MatDiagonalSet - Computes Y = Y + D, where D is a diagonal matrix
323f56f2b3fSBarry Smith    that is represented as a vector. Or Y[i,i] = D[i] if InsertMode is
324f56f2b3fSBarry Smith    INSERT_VALUES.
3256d84be18SBarry Smith 
326*c3339decSBarry Smith    Neighbor-wise Collective
32748e586daSJose E. Roman 
3286d84be18SBarry Smith    Input Parameters:
32998a79cdbSBarry Smith +  Y - the input matrix
330f56f2b3fSBarry Smith .  D - the diagonal matrix, represented as a vector
331f56f2b3fSBarry Smith -  i - INSERT_VALUES or ADD_VALUES
3326d84be18SBarry Smith 
33311a5261eSBarry Smith    Note:
33495452b02SPatrick Sanan     If the matrix Y is missing some diagonal entries this routine can be very slow. To make it fast one should initially
3356f33a894SBarry 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
3366f33a894SBarry Smith    entry).
3376f33a894SBarry Smith 
3382860a424SLois Curfman McInnes    Level: intermediate
3392860a424SLois Curfman McInnes 
340db781477SPatrick Sanan .seealso: `MatShift()`, `MatScale()`, `MatDiagonalScale()`
3416d84be18SBarry Smith @*/
342d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalSet(Mat Y, Vec D, InsertMode is)
343d71ae5a4SJacob Faibussowitsch {
34467576b8bSBarry Smith   PetscInt matlocal, veclocal;
3456d84be18SBarry Smith 
3463a40ed3dSBarry Smith   PetscFunctionBegin;
3470700a824SBarry Smith   PetscValidHeaderSpecific(Y, MAT_CLASSID, 1);
3480700a824SBarry Smith   PetscValidHeaderSpecific(D, VEC_CLASSID, 2);
3499566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Y, &matlocal, NULL));
3509566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(D, &veclocal));
3515f80ce2aSJacob 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);
352dbbe0bcdSBarry Smith   if (Y->ops->diagonalset) PetscUseTypeMethod(Y, diagonalset, D, is);
353dbbe0bcdSBarry Smith   else PetscCall(MatDiagonalSet_Default(Y, D, is));
3549566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
3553a40ed3dSBarry Smith   PetscFunctionReturn(0);
3566d84be18SBarry Smith }
357d4bb536fSBarry Smith 
358d4bb536fSBarry Smith /*@
35904aac2b0SHong Zhang    MatAYPX - Computes Y = a*Y + X.
360d4bb536fSBarry Smith 
3613f9fe445SBarry Smith    Logically on Mat
362fee21e36SBarry Smith 
36398a79cdbSBarry Smith    Input Parameters:
36404aac2b0SHong Zhang +  a - the PetscScalar multiplier
36504aac2b0SHong Zhang .  Y - the first matrix
36604aac2b0SHong Zhang .  X - the second matrix
367531d0c6aSBarry 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)
368d4bb536fSBarry Smith 
3692860a424SLois Curfman McInnes    Level: intermediate
3702860a424SLois Curfman McInnes 
371db781477SPatrick Sanan .seealso: `MatAXPY()`
372d4bb536fSBarry Smith  @*/
373d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAYPX(Mat Y, PetscScalar a, Mat X, MatStructure str)
374d71ae5a4SJacob Faibussowitsch {
3753a40ed3dSBarry Smith   PetscFunctionBegin;
3769566063dSJacob Faibussowitsch   PetscCall(MatScale(Y, a));
3779566063dSJacob Faibussowitsch   PetscCall(MatAXPY(Y, 1.0, X, str));
3783a40ed3dSBarry Smith   PetscFunctionReturn(0);
379d4bb536fSBarry Smith }
380b0a32e0cSBarry Smith 
381b0a32e0cSBarry Smith /*@
3820bacdadaSStefano Zampini     MatComputeOperator - Computes the explicit matrix
383b0a32e0cSBarry Smith 
384*c3339decSBarry Smith     Collective
385b0a32e0cSBarry Smith 
386d8d19677SJose E. Roman     Input Parameters:
387186a3e20SStefano Zampini +   inmat - the matrix
388186a3e20SStefano Zampini -   mattype - the matrix type for the explicit operator
389b0a32e0cSBarry Smith 
390b0a32e0cSBarry Smith     Output Parameter:
391a5b23f4aSJose E. Roman .   mat - the explicit  operator
392b0a32e0cSBarry Smith 
39311a5261eSBarry Smith     Note:
394186a3e20SStefano Zampini     This computation is done by applying the operators to columns of the identity matrix.
395186a3e20SStefano Zampini     This routine is costly in general, and is recommended for use only with relatively small systems.
396186a3e20SStefano Zampini     Currently, this routine uses a dense matrix format if mattype == NULL.
397b0a32e0cSBarry Smith 
398b0a32e0cSBarry Smith     Level: advanced
399b0a32e0cSBarry Smith 
400b0a32e0cSBarry Smith @*/
401d71ae5a4SJacob Faibussowitsch PetscErrorCode MatComputeOperator(Mat inmat, MatType mattype, Mat *mat)
402d71ae5a4SJacob Faibussowitsch {
403b0a32e0cSBarry Smith   PetscFunctionBegin;
4040700a824SBarry Smith   PetscValidHeaderSpecific(inmat, MAT_CLASSID, 1);
405186a3e20SStefano Zampini   PetscValidPointer(mat, 3);
4069566063dSJacob Faibussowitsch   PetscCall(MatConvert_Shell(inmat, mattype ? mattype : MATDENSE, MAT_INITIAL_MATRIX, mat));
40724f910e3SHong Zhang   PetscFunctionReturn(0);
40824f910e3SHong Zhang }
4094325cce7SMatthew G Knepley 
4104325cce7SMatthew G Knepley /*@
4110bacdadaSStefano Zampini     MatComputeOperatorTranspose - Computes the explicit matrix representation of
412f3b1f45cSBarry Smith         a give matrix that can apply MatMultTranspose()
413f3b1f45cSBarry Smith 
414*c3339decSBarry Smith     Collective
415f3b1f45cSBarry Smith 
4166b867d5aSJose E. Roman     Input Parameters:
4176b867d5aSJose E. Roman +   inmat - the matrix
4186b867d5aSJose E. Roman -   mattype - the matrix type for the explicit operator
419f3b1f45cSBarry Smith 
420f3b1f45cSBarry Smith     Output Parameter:
421a5b23f4aSJose E. Roman .   mat - the explicit  operator transposed
422f3b1f45cSBarry Smith 
42311a5261eSBarry Smith     Note:
424186a3e20SStefano Zampini     This computation is done by applying the transpose of the operator to columns of the identity matrix.
425186a3e20SStefano Zampini     This routine is costly in general, and is recommended for use only with relatively small systems.
426186a3e20SStefano Zampini     Currently, this routine uses a dense matrix format if mattype == NULL.
427f3b1f45cSBarry Smith 
428f3b1f45cSBarry Smith     Level: advanced
429f3b1f45cSBarry Smith 
430f3b1f45cSBarry Smith @*/
431d71ae5a4SJacob Faibussowitsch PetscErrorCode MatComputeOperatorTranspose(Mat inmat, MatType mattype, Mat *mat)
432d71ae5a4SJacob Faibussowitsch {
433186a3e20SStefano Zampini   Mat A;
434f3b1f45cSBarry Smith 
435f3b1f45cSBarry Smith   PetscFunctionBegin;
436f3b1f45cSBarry Smith   PetscValidHeaderSpecific(inmat, MAT_CLASSID, 1);
437186a3e20SStefano Zampini   PetscValidPointer(mat, 3);
4389566063dSJacob Faibussowitsch   PetscCall(MatCreateTranspose(inmat, &A));
4399566063dSJacob Faibussowitsch   PetscCall(MatConvert_Shell(A, mattype ? mattype : MATDENSE, MAT_INITIAL_MATRIX, mat));
4409566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A));
441f3b1f45cSBarry Smith   PetscFunctionReturn(0);
442f3b1f45cSBarry Smith }
443f3b1f45cSBarry Smith 
444f3b1f45cSBarry Smith /*@
4454325cce7SMatthew G Knepley   MatChop - Set all values in the matrix less than the tolerance to zero
4464325cce7SMatthew G Knepley 
4474325cce7SMatthew G Knepley   Input Parameters:
4484325cce7SMatthew G Knepley + A   - The matrix
4494325cce7SMatthew G Knepley - tol - The zero tolerance
4504325cce7SMatthew G Knepley 
4514325cce7SMatthew G Knepley   Output Parameters:
4524325cce7SMatthew G Knepley . A - The chopped matrix
4534325cce7SMatthew G Knepley 
4544325cce7SMatthew G Knepley   Level: intermediate
4554325cce7SMatthew G Knepley 
456db781477SPatrick Sanan .seealso: `MatCreate()`, `MatZeroEntries()`
4573fc99919SSatish Balay  @*/
458d71ae5a4SJacob Faibussowitsch PetscErrorCode MatChop(Mat A, PetscReal tol)
459d71ae5a4SJacob Faibussowitsch {
460038df967SPierre Jolivet   Mat          a;
4614325cce7SMatthew G Knepley   PetscScalar *newVals;
462cf5d3338SPierre Jolivet   PetscInt    *newCols, rStart, rEnd, numRows, maxRows, r, colMax = 0;
463038df967SPierre Jolivet   PetscBool    flg;
4644325cce7SMatthew G Knepley 
4654325cce7SMatthew G Knepley   PetscFunctionBegin;
4669566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)A, &flg, MATSEQDENSE, MATMPIDENSE, ""));
467038df967SPierre Jolivet   if (flg) {
4689566063dSJacob Faibussowitsch     PetscCall(MatDenseGetLocalMatrix(A, &a));
4699566063dSJacob Faibussowitsch     PetscCall(MatDenseGetLDA(a, &r));
4709566063dSJacob Faibussowitsch     PetscCall(MatGetSize(a, &rStart, &rEnd));
4719566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(a, &newVals));
472038df967SPierre Jolivet     for (; colMax < rEnd; ++colMax) {
473ad540459SPierre Jolivet       for (maxRows = 0; maxRows < rStart; ++maxRows) newVals[maxRows + colMax * r] = PetscAbsScalar(newVals[maxRows + colMax * r]) < tol ? 0.0 : newVals[maxRows + colMax * r];
474038df967SPierre Jolivet     }
4759566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArray(a, &newVals));
476038df967SPierre Jolivet   } else {
4779566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(A, &rStart, &rEnd));
4789566063dSJacob Faibussowitsch     PetscCall(MatGetRowUpperTriangular(A));
4794325cce7SMatthew G Knepley     for (r = rStart; r < rEnd; ++r) {
4804325cce7SMatthew G Knepley       PetscInt ncols;
4814325cce7SMatthew G Knepley 
4829566063dSJacob Faibussowitsch       PetscCall(MatGetRow(A, r, &ncols, NULL, NULL));
4835f80ce2aSJacob Faibussowitsch       colMax = PetscMax(colMax, ncols);
4849566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(A, r, &ncols, NULL, NULL));
4854325cce7SMatthew G Knepley     }
4864325cce7SMatthew G Knepley     numRows = rEnd - rStart;
4871c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&numRows, &maxRows, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)A)));
4889566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(colMax, &newCols, colMax, &newVals));
4899566063dSJacob Faibussowitsch     PetscCall(MatGetOption(A, MAT_NO_OFF_PROC_ENTRIES, &flg)); /* cache user-defined value */
4909566063dSJacob Faibussowitsch     PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
491cf5d3338SPierre Jolivet     /* short-circuit code in MatAssemblyBegin() and MatAssemblyEnd()             */
492cf5d3338SPierre Jolivet     /* that are potentially called many times depending on the distribution of A */
4934325cce7SMatthew G Knepley     for (r = rStart; r < rStart + maxRows; ++r) {
4944325cce7SMatthew G Knepley       const PetscScalar *vals;
4954325cce7SMatthew G Knepley       const PetscInt    *cols;
496fad45679SMatthew G. Knepley       PetscInt           ncols, newcols, c;
4974325cce7SMatthew G Knepley 
4984325cce7SMatthew G Knepley       if (r < rEnd) {
4999566063dSJacob Faibussowitsch         PetscCall(MatGetRow(A, r, &ncols, &cols, &vals));
5004325cce7SMatthew G Knepley         for (c = 0; c < ncols; ++c) {
5014325cce7SMatthew G Knepley           newCols[c] = cols[c];
5024325cce7SMatthew G Knepley           newVals[c] = PetscAbsScalar(vals[c]) < tol ? 0.0 : vals[c];
5034325cce7SMatthew G Knepley         }
504fad45679SMatthew G. Knepley         newcols = ncols;
5059566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(A, r, &ncols, &cols, &vals));
5069566063dSJacob Faibussowitsch         PetscCall(MatSetValues(A, 1, &r, newcols, newCols, newVals, INSERT_VALUES));
5074325cce7SMatthew G Knepley       }
5089566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
5099566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
5104325cce7SMatthew G Knepley     }
5119566063dSJacob Faibussowitsch     PetscCall(MatRestoreRowUpperTriangular(A));
5129566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newCols, newVals));
5139566063dSJacob Faibussowitsch     PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, flg)); /* reset option to its user-defined value */
514038df967SPierre Jolivet   }
5154325cce7SMatthew G Knepley   PetscFunctionReturn(0);
5164325cce7SMatthew G Knepley }
517