xref: /petsc/src/mat/interface/matrix.c (revision 2ff79c18c26c94ed8cb599682f680f231dca6444)
1 /*
2    This is where the abstract matrix operations are defined
3    Portions of this code are under:
4    Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
5 */
6 
7 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
8 #include <petsc/private/isimpl.h>
9 #include <petsc/private/vecimpl.h>
10 
11 /* Logging support */
12 PetscClassId MAT_CLASSID;
13 PetscClassId MAT_COLORING_CLASSID;
14 PetscClassId MAT_FDCOLORING_CLASSID;
15 PetscClassId MAT_TRANSPOSECOLORING_CLASSID;
16 
17 PetscLogEvent MAT_Mult, MAT_MultAdd, MAT_MultTranspose;
18 PetscLogEvent MAT_MultTransposeAdd, MAT_Solve, MAT_Solves, MAT_SolveAdd, MAT_SolveTranspose, MAT_MatSolve, MAT_MatTrSolve;
19 PetscLogEvent MAT_SolveTransposeAdd, MAT_SOR, MAT_ForwardSolve, MAT_BackwardSolve, MAT_LUFactor, MAT_LUFactorSymbolic;
20 PetscLogEvent MAT_LUFactorNumeric, MAT_CholeskyFactor, MAT_CholeskyFactorSymbolic, MAT_CholeskyFactorNumeric, MAT_ILUFactor;
21 PetscLogEvent MAT_ILUFactorSymbolic, MAT_ICCFactorSymbolic, MAT_Copy, MAT_Convert, MAT_Scale, MAT_AssemblyBegin;
22 PetscLogEvent MAT_QRFactorNumeric, MAT_QRFactorSymbolic, MAT_QRFactor;
23 PetscLogEvent MAT_AssemblyEnd, MAT_SetValues, MAT_GetValues, MAT_GetRow, MAT_GetRowIJ, MAT_CreateSubMats, MAT_GetOrdering, MAT_RedundantMat, MAT_GetSeqNonzeroStructure;
24 PetscLogEvent MAT_IncreaseOverlap, MAT_Partitioning, MAT_PartitioningND, MAT_Coarsen, MAT_ZeroEntries, MAT_Load, MAT_View, MAT_AXPY, MAT_FDColoringCreate;
25 PetscLogEvent MAT_FDColoringSetUp, MAT_FDColoringApply, MAT_Transpose, MAT_FDColoringFunction, MAT_CreateSubMat;
26 PetscLogEvent MAT_TransposeColoringCreate;
27 PetscLogEvent MAT_MatMult, MAT_MatMultSymbolic, MAT_MatMultNumeric;
28 PetscLogEvent MAT_PtAP, MAT_PtAPSymbolic, MAT_PtAPNumeric, MAT_RARt, MAT_RARtSymbolic, MAT_RARtNumeric;
29 PetscLogEvent MAT_MatTransposeMult, MAT_MatTransposeMultSymbolic, MAT_MatTransposeMultNumeric;
30 PetscLogEvent MAT_TransposeMatMult, MAT_TransposeMatMultSymbolic, MAT_TransposeMatMultNumeric;
31 PetscLogEvent MAT_MatMatMult, MAT_MatMatMultSymbolic, MAT_MatMatMultNumeric;
32 PetscLogEvent MAT_MultHermitianTranspose, MAT_MultHermitianTransposeAdd;
33 PetscLogEvent MAT_Getsymtransreduced, MAT_GetBrowsOfAcols;
34 PetscLogEvent MAT_GetBrowsOfAocols, MAT_Getlocalmat, MAT_Getlocalmatcondensed, MAT_Seqstompi, MAT_Seqstompinum, MAT_Seqstompisym;
35 PetscLogEvent MAT_GetMultiProcBlock;
36 PetscLogEvent MAT_CUSPARSECopyToGPU, MAT_CUSPARSECopyFromGPU, MAT_CUSPARSEGenerateTranspose, MAT_CUSPARSESolveAnalysis;
37 PetscLogEvent MAT_HIPSPARSECopyToGPU, MAT_HIPSPARSECopyFromGPU, MAT_HIPSPARSEGenerateTranspose, MAT_HIPSPARSESolveAnalysis;
38 PetscLogEvent MAT_PreallCOO, MAT_SetVCOO;
39 PetscLogEvent MAT_CreateGraph;
40 PetscLogEvent MAT_SetValuesBatch;
41 PetscLogEvent MAT_ViennaCLCopyToGPU;
42 PetscLogEvent MAT_CUDACopyToGPU, MAT_HIPCopyToGPU;
43 PetscLogEvent MAT_DenseCopyToGPU, MAT_DenseCopyFromGPU;
44 PetscLogEvent MAT_Merge, MAT_Residual, MAT_SetRandom;
45 PetscLogEvent MAT_FactorFactS, MAT_FactorInvS;
46 PetscLogEvent MATCOLORING_Apply, MATCOLORING_Comm, MATCOLORING_Local, MATCOLORING_ISCreate, MATCOLORING_SetUp, MATCOLORING_Weights;
47 PetscLogEvent MAT_H2Opus_Build, MAT_H2Opus_Compress, MAT_H2Opus_Orthog, MAT_H2Opus_LR;
48 
49 const char *const MatFactorTypes[] = {"NONE", "LU", "CHOLESKY", "ILU", "ICC", "ILUDT", "QR", "MatFactorType", "MAT_FACTOR_", NULL};
50 
51 /*@
52   MatSetRandom - Sets all components of a matrix to random numbers.
53 
54   Logically Collective
55 
56   Input Parameters:
57 + x    - the matrix
58 - rctx - the `PetscRandom` object, formed by `PetscRandomCreate()`, or `NULL` and
59           it will create one internally.
60 
61   Example:
62 .vb
63      PetscRandomCreate(PETSC_COMM_WORLD,&rctx);
64      MatSetRandom(x,rctx);
65      PetscRandomDestroy(rctx);
66 .ve
67 
68   Level: intermediate
69 
70   Notes:
71   For sparse matrices that have been preallocated but not been assembled, it randomly selects appropriate locations,
72 
73   for sparse matrices that already have nonzero locations, it fills the locations with random numbers.
74 
75   It generates an error if used on unassembled sparse matrices that have not been preallocated.
76 
77 .seealso: [](ch_matrices), `Mat`, `PetscRandom`, `PetscRandomCreate()`, `MatZeroEntries()`, `MatSetValues()`, `PetscRandomDestroy()`
78 @*/
79 PetscErrorCode MatSetRandom(Mat x, PetscRandom rctx)
80 {
81   PetscRandom randObj = NULL;
82 
83   PetscFunctionBegin;
84   PetscValidHeaderSpecific(x, MAT_CLASSID, 1);
85   if (rctx) PetscValidHeaderSpecific(rctx, PETSC_RANDOM_CLASSID, 2);
86   PetscValidType(x, 1);
87   MatCheckPreallocated(x, 1);
88 
89   if (!rctx) {
90     MPI_Comm comm;
91     PetscCall(PetscObjectGetComm((PetscObject)x, &comm));
92     PetscCall(PetscRandomCreate(comm, &randObj));
93     PetscCall(PetscRandomSetType(randObj, x->defaultrandtype));
94     PetscCall(PetscRandomSetFromOptions(randObj));
95     rctx = randObj;
96   }
97   PetscCall(PetscLogEventBegin(MAT_SetRandom, x, rctx, 0, 0));
98   PetscUseTypeMethod(x, setrandom, rctx);
99   PetscCall(PetscLogEventEnd(MAT_SetRandom, x, rctx, 0, 0));
100 
101   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
102   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
103   PetscCall(PetscRandomDestroy(&randObj));
104   PetscFunctionReturn(PETSC_SUCCESS);
105 }
106 
107 /*@
108   MatCopyHashToXAIJ - copy hash table entries into an XAIJ matrix type
109 
110   Logically Collective
111 
112   Input Parameter:
113 . A - A matrix in unassembled, hash table form
114 
115   Output Parameter:
116 . B - The XAIJ matrix. This can either be `A` or some matrix of equivalent size, e.g. obtained from `A` via `MatDuplicate()`
117 
118   Example:
119 .vb
120      PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &B));
121      PetscCall(MatCopyHashToXAIJ(A, B));
122 .ve
123 
124   Level: advanced
125 
126   Notes:
127   If `B` is `A`, then the hash table data structure will be destroyed. `B` is assembled
128 
129 .seealso: [](ch_matrices), `Mat`, `MAT_USE_HASH_TABLE`
130 @*/
131 PetscErrorCode MatCopyHashToXAIJ(Mat A, Mat B)
132 {
133   PetscFunctionBegin;
134   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
135   PetscUseTypeMethod(A, copyhashtoxaij, B);
136   PetscFunctionReturn(PETSC_SUCCESS);
137 }
138 
139 /*@
140   MatFactorGetErrorZeroPivot - returns the pivot value that was determined to be zero and the row it occurred in
141 
142   Logically Collective
143 
144   Input Parameter:
145 . mat - the factored matrix
146 
147   Output Parameters:
148 + pivot - the pivot value computed
149 - row   - the row that the zero pivot occurred. This row value must be interpreted carefully due to row reorderings and which processes
150          the share the matrix
151 
152   Level: advanced
153 
154   Notes:
155   This routine does not work for factorizations done with external packages.
156 
157   This routine should only be called if `MatGetFactorError()` returns a value of `MAT_FACTOR_NUMERIC_ZEROPIVOT`
158 
159   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
160 
161 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`,
162 `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`, `MatFactorClearError()`,
163 `MAT_FACTOR_NUMERIC_ZEROPIVOT`
164 @*/
165 PetscErrorCode MatFactorGetErrorZeroPivot(Mat mat, PetscReal *pivot, PetscInt *row)
166 {
167   PetscFunctionBegin;
168   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
169   PetscAssertPointer(pivot, 2);
170   PetscAssertPointer(row, 3);
171   *pivot = mat->factorerror_zeropivot_value;
172   *row   = mat->factorerror_zeropivot_row;
173   PetscFunctionReturn(PETSC_SUCCESS);
174 }
175 
176 /*@
177   MatFactorGetError - gets the error code from a factorization
178 
179   Logically Collective
180 
181   Input Parameter:
182 . mat - the factored matrix
183 
184   Output Parameter:
185 . err - the error code
186 
187   Level: advanced
188 
189   Note:
190   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
191 
192 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`,
193           `MatFactorClearError()`, `MatFactorGetErrorZeroPivot()`, `MatFactorError`
194 @*/
195 PetscErrorCode MatFactorGetError(Mat mat, MatFactorError *err)
196 {
197   PetscFunctionBegin;
198   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
199   PetscAssertPointer(err, 2);
200   *err = mat->factorerrortype;
201   PetscFunctionReturn(PETSC_SUCCESS);
202 }
203 
204 /*@
205   MatFactorClearError - clears the error code in a factorization
206 
207   Logically Collective
208 
209   Input Parameter:
210 . mat - the factored matrix
211 
212   Level: developer
213 
214   Note:
215   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
216 
217 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`, `MatFactorGetError()`, `MatFactorGetErrorZeroPivot()`,
218           `MatGetErrorCode()`, `MatFactorError`
219 @*/
220 PetscErrorCode MatFactorClearError(Mat mat)
221 {
222   PetscFunctionBegin;
223   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
224   mat->factorerrortype             = MAT_FACTOR_NOERROR;
225   mat->factorerror_zeropivot_value = 0.0;
226   mat->factorerror_zeropivot_row   = 0;
227   PetscFunctionReturn(PETSC_SUCCESS);
228 }
229 
230 PetscErrorCode MatFindNonzeroRowsOrCols_Basic(Mat mat, PetscBool cols, PetscReal tol, IS *nonzero)
231 {
232   Vec                r, l;
233   const PetscScalar *al;
234   PetscInt           i, nz, gnz, N, n, st;
235 
236   PetscFunctionBegin;
237   PetscCall(MatCreateVecs(mat, &r, &l));
238   if (!cols) { /* nonzero rows */
239     PetscCall(MatGetOwnershipRange(mat, &st, NULL));
240     PetscCall(MatGetSize(mat, &N, NULL));
241     PetscCall(MatGetLocalSize(mat, &n, NULL));
242     PetscCall(VecSet(l, 0.0));
243     PetscCall(VecSetRandom(r, NULL));
244     PetscCall(MatMult(mat, r, l));
245     PetscCall(VecGetArrayRead(l, &al));
246   } else { /* nonzero columns */
247     PetscCall(MatGetOwnershipRangeColumn(mat, &st, NULL));
248     PetscCall(MatGetSize(mat, NULL, &N));
249     PetscCall(MatGetLocalSize(mat, NULL, &n));
250     PetscCall(VecSet(r, 0.0));
251     PetscCall(VecSetRandom(l, NULL));
252     PetscCall(MatMultTranspose(mat, l, r));
253     PetscCall(VecGetArrayRead(r, &al));
254   }
255   if (tol <= 0.0) {
256     for (i = 0, nz = 0; i < n; i++)
257       if (al[i] != 0.0) nz++;
258   } else {
259     for (i = 0, nz = 0; i < n; i++)
260       if (PetscAbsScalar(al[i]) > tol) nz++;
261   }
262   PetscCallMPI(MPIU_Allreduce(&nz, &gnz, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
263   if (gnz != N) {
264     PetscInt *nzr;
265     PetscCall(PetscMalloc1(nz, &nzr));
266     if (nz) {
267       if (tol < 0) {
268         for (i = 0, nz = 0; i < n; i++)
269           if (al[i] != 0.0) nzr[nz++] = i + st;
270       } else {
271         for (i = 0, nz = 0; i < n; i++)
272           if (PetscAbsScalar(al[i]) > tol) nzr[nz++] = i + st;
273       }
274     }
275     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nz, nzr, PETSC_OWN_POINTER, nonzero));
276   } else *nonzero = NULL;
277   if (!cols) { /* nonzero rows */
278     PetscCall(VecRestoreArrayRead(l, &al));
279   } else {
280     PetscCall(VecRestoreArrayRead(r, &al));
281   }
282   PetscCall(VecDestroy(&l));
283   PetscCall(VecDestroy(&r));
284   PetscFunctionReturn(PETSC_SUCCESS);
285 }
286 
287 /*@
288   MatFindNonzeroRows - Locate all rows that are not completely zero in the matrix
289 
290   Input Parameter:
291 . mat - the matrix
292 
293   Output Parameter:
294 . keptrows - the rows that are not completely zero
295 
296   Level: intermediate
297 
298   Note:
299   `keptrows` is set to `NULL` if all rows are nonzero.
300 
301   Developer Note:
302   If `keptrows` is not `NULL`, it must be sorted.
303 
304 .seealso: [](ch_matrices), `Mat`, `MatFindZeroRows()`
305  @*/
306 PetscErrorCode MatFindNonzeroRows(Mat mat, IS *keptrows)
307 {
308   PetscFunctionBegin;
309   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
310   PetscValidType(mat, 1);
311   PetscAssertPointer(keptrows, 2);
312   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
313   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
314   if (mat->ops->findnonzerorows) PetscUseTypeMethod(mat, findnonzerorows, keptrows);
315   else PetscCall(MatFindNonzeroRowsOrCols_Basic(mat, PETSC_FALSE, 0.0, keptrows));
316   if (keptrows && *keptrows) PetscCall(ISSetInfo(*keptrows, IS_SORTED, IS_GLOBAL, PETSC_FALSE, PETSC_TRUE));
317   PetscFunctionReturn(PETSC_SUCCESS);
318 }
319 
320 /*@
321   MatFindZeroRows - Locate all rows that are completely zero in the matrix
322 
323   Input Parameter:
324 . mat - the matrix
325 
326   Output Parameter:
327 . zerorows - the rows that are completely zero
328 
329   Level: intermediate
330 
331   Note:
332   `zerorows` is set to `NULL` if no rows are zero.
333 
334 .seealso: [](ch_matrices), `Mat`, `MatFindNonzeroRows()`
335  @*/
336 PetscErrorCode MatFindZeroRows(Mat mat, IS *zerorows)
337 {
338   IS       keptrows;
339   PetscInt m, n;
340 
341   PetscFunctionBegin;
342   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
343   PetscValidType(mat, 1);
344   PetscAssertPointer(zerorows, 2);
345   PetscCall(MatFindNonzeroRows(mat, &keptrows));
346   /* MatFindNonzeroRows sets keptrows to NULL if there are no zero rows.
347      In keeping with this convention, we set zerorows to NULL if there are no zero
348      rows. */
349   if (keptrows == NULL) {
350     *zerorows = NULL;
351   } else {
352     PetscCall(MatGetOwnershipRange(mat, &m, &n));
353     PetscCall(ISComplement(keptrows, m, n, zerorows));
354     PetscCall(ISDestroy(&keptrows));
355   }
356   PetscFunctionReturn(PETSC_SUCCESS);
357 }
358 
359 /*@
360   MatGetDiagonalBlock - Returns the part of the matrix associated with the on-process coupling
361 
362   Not Collective
363 
364   Input Parameter:
365 . A - the matrix
366 
367   Output Parameter:
368 . a - the diagonal part (which is a SEQUENTIAL matrix)
369 
370   Level: advanced
371 
372   Notes:
373   See `MatCreateAIJ()` for more information on the "diagonal part" of the matrix.
374 
375   Use caution, as the reference count on the returned matrix is not incremented and it is used as part of `A`'s normal operation.
376 
377 .seealso: [](ch_matrices), `Mat`, `MatCreateAIJ()`, `MATAIJ`, `MATBAIJ`, `MATSBAIJ`
378 @*/
379 PetscErrorCode MatGetDiagonalBlock(Mat A, Mat *a)
380 {
381   PetscFunctionBegin;
382   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
383   PetscValidType(A, 1);
384   PetscAssertPointer(a, 2);
385   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
386   if (A->ops->getdiagonalblock) PetscUseTypeMethod(A, getdiagonalblock, a);
387   else {
388     PetscMPIInt size;
389 
390     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
391     PetscCheck(size == 1, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for parallel matrix type %s", ((PetscObject)A)->type_name);
392     *a = A;
393   }
394   PetscFunctionReturn(PETSC_SUCCESS);
395 }
396 
397 /*@
398   MatGetTrace - Gets the trace of a matrix. The sum of the diagonal entries.
399 
400   Collective
401 
402   Input Parameter:
403 . mat - the matrix
404 
405   Output Parameter:
406 . trace - the sum of the diagonal entries
407 
408   Level: advanced
409 
410 .seealso: [](ch_matrices), `Mat`
411 @*/
412 PetscErrorCode MatGetTrace(Mat mat, PetscScalar *trace)
413 {
414   Vec diag;
415 
416   PetscFunctionBegin;
417   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
418   PetscAssertPointer(trace, 2);
419   PetscCall(MatCreateVecs(mat, &diag, NULL));
420   PetscCall(MatGetDiagonal(mat, diag));
421   PetscCall(VecSum(diag, trace));
422   PetscCall(VecDestroy(&diag));
423   PetscFunctionReturn(PETSC_SUCCESS);
424 }
425 
426 /*@
427   MatRealPart - Zeros out the imaginary part of the matrix
428 
429   Logically Collective
430 
431   Input Parameter:
432 . mat - the matrix
433 
434   Level: advanced
435 
436 .seealso: [](ch_matrices), `Mat`, `MatImaginaryPart()`
437 @*/
438 PetscErrorCode MatRealPart(Mat mat)
439 {
440   PetscFunctionBegin;
441   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
442   PetscValidType(mat, 1);
443   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
444   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
445   MatCheckPreallocated(mat, 1);
446   PetscUseTypeMethod(mat, realpart);
447   PetscFunctionReturn(PETSC_SUCCESS);
448 }
449 
450 /*@C
451   MatGetGhosts - Get the global indices of all ghost nodes defined by the sparse matrix
452 
453   Collective
454 
455   Input Parameter:
456 . mat - the matrix
457 
458   Output Parameters:
459 + nghosts - number of ghosts (for `MATBAIJ` and `MATSBAIJ` matrices there is one ghost for each matrix block)
460 - ghosts  - the global indices of the ghost points
461 
462   Level: advanced
463 
464   Note:
465   `nghosts` and `ghosts` are suitable to pass into `VecCreateGhost()` or `VecCreateGhostBlock()`
466 
467 .seealso: [](ch_matrices), `Mat`, `VecCreateGhost()`, `VecCreateGhostBlock()`
468 @*/
469 PetscErrorCode MatGetGhosts(Mat mat, PetscInt *nghosts, const PetscInt *ghosts[])
470 {
471   PetscFunctionBegin;
472   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
473   PetscValidType(mat, 1);
474   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
475   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
476   if (mat->ops->getghosts) PetscUseTypeMethod(mat, getghosts, nghosts, ghosts);
477   else {
478     if (nghosts) *nghosts = 0;
479     if (ghosts) *ghosts = NULL;
480   }
481   PetscFunctionReturn(PETSC_SUCCESS);
482 }
483 
484 /*@
485   MatImaginaryPart - Moves the imaginary part of the matrix to the real part and zeros the imaginary part
486 
487   Logically Collective
488 
489   Input Parameter:
490 . mat - the matrix
491 
492   Level: advanced
493 
494 .seealso: [](ch_matrices), `Mat`, `MatRealPart()`
495 @*/
496 PetscErrorCode MatImaginaryPart(Mat mat)
497 {
498   PetscFunctionBegin;
499   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
500   PetscValidType(mat, 1);
501   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
502   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
503   MatCheckPreallocated(mat, 1);
504   PetscUseTypeMethod(mat, imaginarypart);
505   PetscFunctionReturn(PETSC_SUCCESS);
506 }
507 
508 /*@
509   MatMissingDiagonal - Determine if sparse matrix is missing a diagonal entry (or block entry for `MATBAIJ` and `MATSBAIJ` matrices) in the nonzero structure
510 
511   Not Collective
512 
513   Input Parameter:
514 . mat - the matrix
515 
516   Output Parameters:
517 + missing - is any diagonal entry missing
518 - dd      - first diagonal entry that is missing (optional) on this process
519 
520   Level: advanced
521 
522   Note:
523   This does not return diagonal entries that are in the nonzero structure but happen to have a zero numerical value
524 
525 .seealso: [](ch_matrices), `Mat`
526 @*/
527 PetscErrorCode MatMissingDiagonal(Mat mat, PetscBool *missing, PetscInt *dd)
528 {
529   PetscFunctionBegin;
530   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
531   PetscValidType(mat, 1);
532   PetscAssertPointer(missing, 2);
533   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix %s", ((PetscObject)mat)->type_name);
534   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
535   PetscUseTypeMethod(mat, missingdiagonal, missing, dd);
536   PetscFunctionReturn(PETSC_SUCCESS);
537 }
538 
539 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
540 /*@C
541   MatGetRow - Gets a row of a matrix.  You MUST call `MatRestoreRow()`
542   for each row that you get to ensure that your application does
543   not bleed memory.
544 
545   Not Collective
546 
547   Input Parameters:
548 + mat - the matrix
549 - row - the row to get
550 
551   Output Parameters:
552 + ncols - if not `NULL`, the number of nonzeros in `row`
553 . cols  - if not `NULL`, the column numbers
554 - vals  - if not `NULL`, the numerical values
555 
556   Level: advanced
557 
558   Notes:
559   This routine is provided for people who need to have direct access
560   to the structure of a matrix.  We hope that we provide enough
561   high-level matrix routines that few users will need it.
562 
563   `MatGetRow()` always returns 0-based column indices, regardless of
564   whether the internal representation is 0-based (default) or 1-based.
565 
566   For better efficiency, set `cols` and/or `vals` to `NULL` if you do
567   not wish to extract these quantities.
568 
569   The user can only examine the values extracted with `MatGetRow()`;
570   the values CANNOT be altered.  To change the matrix entries, one
571   must use `MatSetValues()`.
572 
573   You can only have one call to `MatGetRow()` outstanding for a particular
574   matrix at a time, per processor. `MatGetRow()` can only obtain rows
575   associated with the given processor, it cannot get rows from the
576   other processors; for that we suggest using `MatCreateSubMatrices()`, then
577   `MatGetRow()` on the submatrix. The row index passed to `MatGetRow()`
578   is in the global number of rows.
579 
580   Use `MatGetRowIJ()` and `MatRestoreRowIJ()` to access all the local indices of the sparse matrix.
581 
582   Use `MatSeqAIJGetArray()` and similar functions to access the numerical values for certain matrix types directly.
583 
584   Fortran Note:
585 .vb
586   PetscInt, pointer :: cols(:)
587   PetscScalar, pointer :: vals(:)
588 .ve
589 
590 .seealso: [](ch_matrices), `Mat`, `MatRestoreRow()`, `MatSetValues()`, `MatGetValues()`, `MatCreateSubMatrices()`, `MatGetDiagonal()`, `MatGetRowIJ()`, `MatRestoreRowIJ()`
591 @*/
592 PetscErrorCode MatGetRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
593 {
594   PetscInt incols;
595 
596   PetscFunctionBegin;
597   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
598   PetscValidType(mat, 1);
599   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
600   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
601   MatCheckPreallocated(mat, 1);
602   PetscCheck(row >= mat->rmap->rstart && row < mat->rmap->rend, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Only for local rows, %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ")", row, mat->rmap->rstart, mat->rmap->rend);
603   PetscCall(PetscLogEventBegin(MAT_GetRow, mat, 0, 0, 0));
604   PetscUseTypeMethod(mat, getrow, row, &incols, (PetscInt **)cols, (PetscScalar **)vals);
605   if (ncols) *ncols = incols;
606   PetscCall(PetscLogEventEnd(MAT_GetRow, mat, 0, 0, 0));
607   PetscFunctionReturn(PETSC_SUCCESS);
608 }
609 
610 /*@
611   MatConjugate - replaces the matrix values with their complex conjugates
612 
613   Logically Collective
614 
615   Input Parameter:
616 . mat - the matrix
617 
618   Level: advanced
619 
620 .seealso: [](ch_matrices), `Mat`, `MatRealPart()`, `MatImaginaryPart()`, `VecConjugate()`, `MatTranspose()`
621 @*/
622 PetscErrorCode MatConjugate(Mat mat)
623 {
624   PetscFunctionBegin;
625   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
626   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
627   if (PetscDefined(USE_COMPLEX) && mat->hermitian != PETSC_BOOL3_TRUE) {
628     PetscUseTypeMethod(mat, conjugate);
629     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
630   }
631   PetscFunctionReturn(PETSC_SUCCESS);
632 }
633 
634 /*@C
635   MatRestoreRow - Frees any temporary space allocated by `MatGetRow()`.
636 
637   Not Collective
638 
639   Input Parameters:
640 + mat   - the matrix
641 . row   - the row to get
642 . ncols - the number of nonzeros
643 . cols  - the columns of the nonzeros
644 - vals  - if nonzero the column values
645 
646   Level: advanced
647 
648   Notes:
649   This routine should be called after you have finished examining the entries.
650 
651   This routine zeros out `ncols`, `cols`, and `vals`. This is to prevent accidental
652   us of the array after it has been restored. If you pass `NULL`, it will
653   not zero the pointers.  Use of `cols` or `vals` after `MatRestoreRow()` is invalid.
654 
655   Fortran Note:
656 .vb
657   PetscInt, pointer :: cols(:)
658   PetscScalar, pointer :: vals(:)
659 .ve
660 
661 .seealso: [](ch_matrices), `Mat`, `MatGetRow()`
662 @*/
663 PetscErrorCode MatRestoreRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
664 {
665   PetscFunctionBegin;
666   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
667   if (ncols) PetscAssertPointer(ncols, 3);
668   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
669   PetscTryTypeMethod(mat, restorerow, row, ncols, (PetscInt **)cols, (PetscScalar **)vals);
670   if (ncols) *ncols = 0;
671   if (cols) *cols = NULL;
672   if (vals) *vals = NULL;
673   PetscFunctionReturn(PETSC_SUCCESS);
674 }
675 
676 /*@
677   MatGetRowUpperTriangular - Sets a flag to enable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
678   You should call `MatRestoreRowUpperTriangular()` after calling` MatGetRow()` and `MatRestoreRow()` to disable the flag.
679 
680   Not Collective
681 
682   Input Parameter:
683 . mat - the matrix
684 
685   Level: advanced
686 
687   Note:
688   The flag is to ensure that users are aware that `MatGetRow()` only provides the upper triangular part of the row for the matrices in `MATSBAIJ` format.
689 
690 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatRestoreRowUpperTriangular()`
691 @*/
692 PetscErrorCode MatGetRowUpperTriangular(Mat mat)
693 {
694   PetscFunctionBegin;
695   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
696   PetscValidType(mat, 1);
697   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
698   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
699   MatCheckPreallocated(mat, 1);
700   PetscTryTypeMethod(mat, getrowuppertriangular);
701   PetscFunctionReturn(PETSC_SUCCESS);
702 }
703 
704 /*@
705   MatRestoreRowUpperTriangular - Disable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
706 
707   Not Collective
708 
709   Input Parameter:
710 . mat - the matrix
711 
712   Level: advanced
713 
714   Note:
715   This routine should be called after you have finished calls to `MatGetRow()` and `MatRestoreRow()`.
716 
717 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatGetRowUpperTriangular()`
718 @*/
719 PetscErrorCode MatRestoreRowUpperTriangular(Mat mat)
720 {
721   PetscFunctionBegin;
722   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
723   PetscValidType(mat, 1);
724   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
725   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
726   MatCheckPreallocated(mat, 1);
727   PetscTryTypeMethod(mat, restorerowuppertriangular);
728   PetscFunctionReturn(PETSC_SUCCESS);
729 }
730 
731 /*@
732   MatSetOptionsPrefix - Sets the prefix used for searching for all
733   `Mat` options in the database.
734 
735   Logically Collective
736 
737   Input Parameters:
738 + A      - the matrix
739 - prefix - the prefix to prepend to all option names
740 
741   Level: advanced
742 
743   Notes:
744   A hyphen (-) must NOT be given at the beginning of the prefix name.
745   The first character of all runtime options is AUTOMATICALLY the hyphen.
746 
747   This is NOT used for options for the factorization of the matrix. Normally the
748   prefix is automatically passed in from the PC calling the factorization. To set
749   it directly use  `MatSetOptionsPrefixFactor()`
750 
751 .seealso: [](ch_matrices), `Mat`, `MatSetFromOptions()`, `MatSetOptionsPrefixFactor()`
752 @*/
753 PetscErrorCode MatSetOptionsPrefix(Mat A, const char prefix[])
754 {
755   PetscFunctionBegin;
756   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
757   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)A, prefix));
758   PetscTryMethod(A, "MatSetOptionsPrefix_C", (Mat, const char[]), (A, prefix));
759   PetscFunctionReturn(PETSC_SUCCESS);
760 }
761 
762 /*@
763   MatSetOptionsPrefixFactor - Sets the prefix used for searching for all matrix factor options in the database for
764   for matrices created with `MatGetFactor()`
765 
766   Logically Collective
767 
768   Input Parameters:
769 + A      - the matrix
770 - prefix - the prefix to prepend to all option names for the factored matrix
771 
772   Level: developer
773 
774   Notes:
775   A hyphen (-) must NOT be given at the beginning of the prefix name.
776   The first character of all runtime options is AUTOMATICALLY the hyphen.
777 
778   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
779   it directly when not using `KSP`/`PC` use  `MatSetOptionsPrefixFactor()`
780 
781 .seealso: [](ch_matrices), `Mat`,   [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSetFromOptions()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`
782 @*/
783 PetscErrorCode MatSetOptionsPrefixFactor(Mat A, const char prefix[])
784 {
785   PetscFunctionBegin;
786   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
787   if (prefix) {
788     PetscAssertPointer(prefix, 2);
789     PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
790     if (prefix != A->factorprefix) {
791       PetscCall(PetscFree(A->factorprefix));
792       PetscCall(PetscStrallocpy(prefix, &A->factorprefix));
793     }
794   } else PetscCall(PetscFree(A->factorprefix));
795   PetscFunctionReturn(PETSC_SUCCESS);
796 }
797 
798 /*@
799   MatAppendOptionsPrefixFactor - Appends to the prefix used for searching for all matrix factor options in the database for
800   for matrices created with `MatGetFactor()`
801 
802   Logically Collective
803 
804   Input Parameters:
805 + A      - the matrix
806 - prefix - the prefix to prepend to all option names for the factored matrix
807 
808   Level: developer
809 
810   Notes:
811   A hyphen (-) must NOT be given at the beginning of the prefix name.
812   The first character of all runtime options is AUTOMATICALLY the hyphen.
813 
814   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
815   it directly when not using `KSP`/`PC` use  `MatAppendOptionsPrefixFactor()`
816 
817 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `PetscOptionsCreate()`, `PetscOptionsDestroy()`, `PetscObjectSetOptionsPrefix()`, `PetscObjectPrependOptionsPrefix()`,
818           `PetscObjectGetOptionsPrefix()`, `TSAppendOptionsPrefix()`, `SNESAppendOptionsPrefix()`, `KSPAppendOptionsPrefix()`, `MatSetOptionsPrefixFactor()`,
819           `MatSetOptionsPrefix()`
820 @*/
821 PetscErrorCode MatAppendOptionsPrefixFactor(Mat A, const char prefix[])
822 {
823   size_t len1, len2, new_len;
824 
825   PetscFunctionBegin;
826   PetscValidHeader(A, 1);
827   if (!prefix) PetscFunctionReturn(PETSC_SUCCESS);
828   if (!A->factorprefix) {
829     PetscCall(MatSetOptionsPrefixFactor(A, prefix));
830     PetscFunctionReturn(PETSC_SUCCESS);
831   }
832   PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
833 
834   PetscCall(PetscStrlen(A->factorprefix, &len1));
835   PetscCall(PetscStrlen(prefix, &len2));
836   new_len = len1 + len2 + 1;
837   PetscCall(PetscRealloc(new_len * sizeof(*A->factorprefix), &A->factorprefix));
838   PetscCall(PetscStrncpy(A->factorprefix + len1, prefix, len2 + 1));
839   PetscFunctionReturn(PETSC_SUCCESS);
840 }
841 
842 /*@
843   MatAppendOptionsPrefix - Appends to the prefix used for searching for all
844   matrix options in the database.
845 
846   Logically Collective
847 
848   Input Parameters:
849 + A      - the matrix
850 - prefix - the prefix to prepend to all option names
851 
852   Level: advanced
853 
854   Note:
855   A hyphen (-) must NOT be given at the beginning of the prefix name.
856   The first character of all runtime options is AUTOMATICALLY the hyphen.
857 
858 .seealso: [](ch_matrices), `Mat`, `MatGetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefix()`
859 @*/
860 PetscErrorCode MatAppendOptionsPrefix(Mat A, const char prefix[])
861 {
862   PetscFunctionBegin;
863   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
864   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)A, prefix));
865   PetscTryMethod(A, "MatAppendOptionsPrefix_C", (Mat, const char[]), (A, prefix));
866   PetscFunctionReturn(PETSC_SUCCESS);
867 }
868 
869 /*@
870   MatGetOptionsPrefix - Gets the prefix used for searching for all
871   matrix options in the database.
872 
873   Not Collective
874 
875   Input Parameter:
876 . A - the matrix
877 
878   Output Parameter:
879 . prefix - pointer to the prefix string used
880 
881   Level: advanced
882 
883 .seealso: [](ch_matrices), `Mat`, `MatAppendOptionsPrefix()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefixFactor()`
884 @*/
885 PetscErrorCode MatGetOptionsPrefix(Mat A, const char *prefix[])
886 {
887   PetscFunctionBegin;
888   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
889   PetscAssertPointer(prefix, 2);
890   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)A, prefix));
891   PetscFunctionReturn(PETSC_SUCCESS);
892 }
893 
894 /*@
895   MatGetState - Gets the state of a `Mat`. Same value as returned by `PetscObjectStateGet()`
896 
897   Not Collective
898 
899   Input Parameter:
900 . A - the matrix
901 
902   Output Parameter:
903 . state - the object state
904 
905   Level: advanced
906 
907   Note:
908   Object state is an integer which gets increased every time
909   the object is changed. By saving and later querying the object state
910   one can determine whether information about the object is still current.
911 
912   See `MatGetNonzeroState()` to determine if the nonzero structure of the matrix has changed.
913 
914 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PetscObjectStateGet()`, `MatGetNonzeroState()`
915 @*/
916 PetscErrorCode MatGetState(Mat A, PetscObjectState *state)
917 {
918   PetscFunctionBegin;
919   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
920   PetscAssertPointer(state, 2);
921   PetscCall(PetscObjectStateGet((PetscObject)A, state));
922   PetscFunctionReturn(PETSC_SUCCESS);
923 }
924 
925 /*@
926   MatResetPreallocation - Reset matrix to use the original preallocation values provided by the user, for example with `MatXAIJSetPreallocation()`
927 
928   Collective
929 
930   Input Parameter:
931 . A - the matrix
932 
933   Level: beginner
934 
935   Notes:
936   After calling `MatAssemblyBegin()` and `MatAssemblyEnd()` with `MAT_FINAL_ASSEMBLY` the matrix data structures represent the nonzeros assigned to the
937   matrix. If that space is less than the preallocated space that extra preallocated space is no longer available to take on new values. `MatResetPreallocation()`
938   makes all of the preallocation space available
939 
940   Current values in the matrix are lost in this call
941 
942   Currently only supported for  `MATAIJ` matrices.
943 
944 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatXAIJSetPreallocation()`
945 @*/
946 PetscErrorCode MatResetPreallocation(Mat A)
947 {
948   PetscFunctionBegin;
949   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
950   PetscValidType(A, 1);
951   PetscUseMethod(A, "MatResetPreallocation_C", (Mat), (A));
952   PetscFunctionReturn(PETSC_SUCCESS);
953 }
954 
955 /*@
956   MatResetHash - Reset the matrix so that it will use a hash table for the next round of `MatSetValues()` and `MatAssemblyBegin()`/`MatAssemblyEnd()`.
957 
958   Collective
959 
960   Input Parameter:
961 . A - the matrix
962 
963   Level: intermediate
964 
965   Notes:
966   The matrix will again delete the hash table data structures after following calls to `MatAssemblyBegin()`/`MatAssemblyEnd()` with `MAT_FINAL_ASSEMBLY`.
967 
968   Currently only supported for `MATAIJ` matrices.
969 
970 .seealso: [](ch_matrices), `Mat`, `MatResetPreallocation()`
971 @*/
972 PetscErrorCode MatResetHash(Mat A)
973 {
974   PetscFunctionBegin;
975   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
976   PetscValidType(A, 1);
977   PetscCheck(A->insertmode == NOT_SET_VALUES, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot reset to hash state after setting some values but not yet calling MatAssemblyBegin()/MatAssemblyEnd()");
978   if (A->num_ass == 0) PetscFunctionReturn(PETSC_SUCCESS);
979   PetscUseMethod(A, "MatResetHash_C", (Mat), (A));
980   /* These flags are used to determine whether certain setups occur */
981   A->was_assembled = PETSC_FALSE;
982   A->assembled     = PETSC_FALSE;
983   /* Log that the state of this object has changed; this will help guarantee that preconditioners get re-setup */
984   PetscCall(PetscObjectStateIncrease((PetscObject)A));
985   PetscFunctionReturn(PETSC_SUCCESS);
986 }
987 
988 /*@
989   MatSetUp - Sets up the internal matrix data structures for later use by the matrix
990 
991   Collective
992 
993   Input Parameter:
994 . A - the matrix
995 
996   Level: advanced
997 
998   Notes:
999   If the user has not set preallocation for this matrix then an efficient algorithm will be used for the first round of
1000   setting values in the matrix.
1001 
1002   This routine is called internally by other `Mat` functions when needed so rarely needs to be called by users
1003 
1004 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatCreate()`, `MatDestroy()`, `MatXAIJSetPreallocation()`
1005 @*/
1006 PetscErrorCode MatSetUp(Mat A)
1007 {
1008   PetscFunctionBegin;
1009   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1010   if (!((PetscObject)A)->type_name) {
1011     PetscMPIInt size;
1012 
1013     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1014     PetscCall(MatSetType(A, size == 1 ? MATSEQAIJ : MATMPIAIJ));
1015   }
1016   if (!A->preallocated) PetscTryTypeMethod(A, setup);
1017   PetscCall(PetscLayoutSetUp(A->rmap));
1018   PetscCall(PetscLayoutSetUp(A->cmap));
1019   A->preallocated = PETSC_TRUE;
1020   PetscFunctionReturn(PETSC_SUCCESS);
1021 }
1022 
1023 #if defined(PETSC_HAVE_SAWS)
1024   #include <petscviewersaws.h>
1025 #endif
1026 
1027 /*
1028    If threadsafety is on extraneous matrices may be printed
1029 
1030    This flag cannot be stored in the matrix because the original matrix in MatView() may assemble a new matrix which is passed into MatViewFromOptions()
1031 */
1032 #if !defined(PETSC_HAVE_THREADSAFETY)
1033 static PetscInt insidematview = 0;
1034 #endif
1035 
1036 /*@
1037   MatViewFromOptions - View properties of the matrix based on options set in the options database
1038 
1039   Collective
1040 
1041   Input Parameters:
1042 + A    - the matrix
1043 . obj  - optional additional object that provides the options prefix to use
1044 - name - command line option
1045 
1046   Options Database Key:
1047 . -mat_view [viewertype]:... - the viewer and its options
1048 
1049   Level: intermediate
1050 
1051   Note:
1052 .vb
1053     If no value is provided ascii:stdout is used
1054        ascii[:[filename][:[format][:append]]]    defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
1055                                                   for example ascii::ascii_info prints just the information about the object not all details
1056                                                   unless :append is given filename opens in write mode, overwriting what was already there
1057        binary[:[filename][:[format][:append]]]   defaults to the file binaryoutput
1058        draw[:drawtype[:filename]]                for example, draw:tikz, draw:tikz:figure.tex  or draw:x
1059        socket[:port]                             defaults to the standard output port
1060        saws[:communicatorname]                    publishes object to the Scientific Application Webserver (SAWs)
1061 .ve
1062 
1063 .seealso: [](ch_matrices), `Mat`, `MatView()`, `PetscObjectViewFromOptions()`, `MatCreate()`
1064 @*/
1065 PetscErrorCode MatViewFromOptions(Mat A, PetscObject obj, const char name[])
1066 {
1067   PetscFunctionBegin;
1068   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1069 #if !defined(PETSC_HAVE_THREADSAFETY)
1070   if (insidematview) PetscFunctionReturn(PETSC_SUCCESS);
1071 #endif
1072   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
1073   PetscFunctionReturn(PETSC_SUCCESS);
1074 }
1075 
1076 /*@
1077   MatView - display information about a matrix in a variety ways
1078 
1079   Collective on viewer
1080 
1081   Input Parameters:
1082 + mat    - the matrix
1083 - viewer - visualization context
1084 
1085   Options Database Keys:
1086 + -mat_view ::ascii_info           - Prints info on matrix at conclusion of `MatAssemblyEnd()`
1087 . -mat_view ::ascii_info_detail    - Prints more detailed info
1088 . -mat_view                        - Prints matrix in ASCII format
1089 . -mat_view ::ascii_matlab         - Prints matrix in MATLAB format
1090 . -mat_view draw                   - PetscDraws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
1091 . -display <name>                  - Sets display name (default is host)
1092 . -draw_pause <sec>                - Sets number of seconds to pause after display
1093 . -mat_view socket                 - Sends matrix to socket, can be accessed from MATLAB (see Users-Manual: ch_matlab for details)
1094 . -viewer_socket_machine <machine> - -
1095 . -viewer_socket_port <port>       - -
1096 . -mat_view binary                 - save matrix to file in binary format
1097 - -viewer_binary_filename <name>   - -
1098 
1099   Level: beginner
1100 
1101   Notes:
1102   The available visualization contexts include
1103 +    `PETSC_VIEWER_STDOUT_SELF`   - for sequential matrices
1104 .    `PETSC_VIEWER_STDOUT_WORLD`  - for parallel matrices created on `PETSC_COMM_WORLD`
1105 .    `PETSC_VIEWER_STDOUT_`(comm) - for matrices created on MPI communicator comm
1106 -     `PETSC_VIEWER_DRAW_WORLD`   - graphical display of nonzero structure
1107 
1108   The user can open alternative visualization contexts with
1109 +    `PetscViewerASCIIOpen()`  - Outputs matrix to a specified file
1110 .    `PetscViewerBinaryOpen()` - Outputs matrix in binary to a  specified file; corresponding input uses `MatLoad()`
1111 .    `PetscViewerDrawOpen()`   - Outputs nonzero matrix nonzero structure to an X window display
1112 -    `PetscViewerSocketOpen()` - Outputs matrix to Socket viewer, `PETSCVIEWERSOCKET`. Only the `MATSEQDENSE` and `MATAIJ` types support this viewer.
1113 
1114   The user can call `PetscViewerPushFormat()` to specify the output
1115   format of ASCII printed objects (when using `PETSC_VIEWER_STDOUT_SELF`,
1116   `PETSC_VIEWER_STDOUT_WORLD` and `PetscViewerASCIIOpen()`).  Available formats include
1117 +    `PETSC_VIEWER_DEFAULT`           - default, prints matrix contents
1118 .    `PETSC_VIEWER_ASCII_MATLAB`      - prints matrix contents in MATLAB format
1119 .    `PETSC_VIEWER_ASCII_DENSE`       - prints entire matrix including zeros
1120 .    `PETSC_VIEWER_ASCII_COMMON`      - prints matrix contents, using a sparse  format common among all matrix types
1121 .    `PETSC_VIEWER_ASCII_IMPL`        - prints matrix contents, using an implementation-specific format (which is in many cases the same as the default)
1122 .    `PETSC_VIEWER_ASCII_INFO`        - prints basic information about the matrix size and structure (not the matrix entries)
1123 -    `PETSC_VIEWER_ASCII_INFO_DETAIL` - prints more detailed information about the matrix nonzero structure (still not vector or matrix entries)
1124 
1125   The ASCII viewers are only recommended for small matrices on at most a moderate number of processes,
1126   the program will seemingly hang and take hours for larger matrices, for larger matrices one should use the binary format.
1127 
1128   In the debugger you can do "call MatView(mat,0)" to display the matrix. (The same holds for any PETSc object viewer).
1129 
1130   See the manual page for `MatLoad()` for the exact format of the binary file when the binary
1131   viewer is used.
1132 
1133   See share/petsc/matlab/PetscBinaryRead.m for a MATLAB code that can read in the binary file when the binary
1134   viewer is used and lib/petsc/bin/PetscBinaryIO.py for loading them into Python.
1135 
1136   One can use '-mat_view draw -draw_pause -1' to pause the graphical display of matrix nonzero structure,
1137   and then use the following mouse functions.
1138 .vb
1139   left mouse: zoom in
1140   middle mouse: zoom out
1141   right mouse: continue with the simulation
1142 .ve
1143 
1144 .seealso: [](ch_matrices), `Mat`, `PetscViewerPushFormat()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`, `PetscViewer`,
1145           `PetscViewerSocketOpen()`, `PetscViewerBinaryOpen()`, `MatLoad()`, `MatViewFromOptions()`
1146 @*/
1147 PetscErrorCode MatView(Mat mat, PetscViewer viewer)
1148 {
1149   PetscInt          rows, cols, rbs, cbs;
1150   PetscBool         isascii, isstring, issaws;
1151   PetscViewerFormat format;
1152   PetscMPIInt       size;
1153 
1154   PetscFunctionBegin;
1155   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1156   PetscValidType(mat, 1);
1157   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer));
1158   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1159 
1160   PetscCall(PetscViewerGetFormat(viewer, &format));
1161   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
1162   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
1163 
1164 #if !defined(PETSC_HAVE_THREADSAFETY)
1165   insidematview++;
1166 #endif
1167   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
1168   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1169   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
1170   PetscCheck((isascii && (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL)) || !mat->factortype, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "No viewers for factored matrix except ASCII, info, or info_detail");
1171 
1172   PetscCall(PetscLogEventBegin(MAT_View, mat, viewer, 0, 0));
1173   if (isascii) {
1174     if (!mat->preallocated) {
1175       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been preallocated yet\n"));
1176 #if !defined(PETSC_HAVE_THREADSAFETY)
1177       insidematview--;
1178 #endif
1179       PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1180       PetscFunctionReturn(PETSC_SUCCESS);
1181     }
1182     if (!mat->assembled) {
1183       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been assembled yet\n"));
1184 #if !defined(PETSC_HAVE_THREADSAFETY)
1185       insidematview--;
1186 #endif
1187       PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1188       PetscFunctionReturn(PETSC_SUCCESS);
1189     }
1190     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)mat, viewer));
1191     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1192       MatNullSpace nullsp, transnullsp;
1193 
1194       PetscCall(PetscViewerASCIIPushTab(viewer));
1195       PetscCall(MatGetSize(mat, &rows, &cols));
1196       PetscCall(MatGetBlockSizes(mat, &rbs, &cbs));
1197       if (rbs != 1 || cbs != 1) {
1198         if (rbs != cbs) PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", rbs=%" PetscInt_FMT ", cbs=%" PetscInt_FMT "%s\n", rows, cols, rbs, cbs, mat->bsizes ? " variable blocks set" : ""));
1199         else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", bs=%" PetscInt_FMT "%s\n", rows, cols, rbs, mat->bsizes ? " variable blocks set" : ""));
1200       } else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", rows, cols));
1201       if (mat->factortype) {
1202         MatSolverType solver;
1203         PetscCall(MatFactorGetSolverType(mat, &solver));
1204         PetscCall(PetscViewerASCIIPrintf(viewer, "package used to perform factorization: %s\n", solver));
1205       }
1206       if (mat->ops->getinfo) {
1207         PetscBool is_constant_or_diagonal;
1208 
1209         // Don't print nonzero information for constant or diagonal matrices, it just adds noise to the output
1210         PetscCall(PetscObjectTypeCompareAny((PetscObject)mat, &is_constant_or_diagonal, MATCONSTANTDIAGONAL, MATDIAGONAL, ""));
1211         if (!is_constant_or_diagonal) {
1212           MatInfo info;
1213 
1214           PetscCall(MatGetInfo(mat, MAT_GLOBAL_SUM, &info));
1215           PetscCall(PetscViewerASCIIPrintf(viewer, "total: nonzeros=%.f, allocated nonzeros=%.f\n", info.nz_used, info.nz_allocated));
1216           if (!mat->factortype) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of mallocs used during MatSetValues calls=%" PetscInt_FMT "\n", (PetscInt)info.mallocs));
1217         }
1218       }
1219       PetscCall(MatGetNullSpace(mat, &nullsp));
1220       PetscCall(MatGetTransposeNullSpace(mat, &transnullsp));
1221       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached null space\n"));
1222       if (transnullsp && transnullsp != nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached transposed null space\n"));
1223       PetscCall(MatGetNearNullSpace(mat, &nullsp));
1224       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached near null space\n"));
1225       PetscCall(PetscViewerASCIIPushTab(viewer));
1226       PetscCall(MatProductView(mat, viewer));
1227       PetscCall(PetscViewerASCIIPopTab(viewer));
1228       if (mat->bsizes && format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1229         IS tmp;
1230 
1231         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), mat->nblocks, mat->bsizes, PETSC_USE_POINTER, &tmp));
1232         PetscCall(PetscObjectSetName((PetscObject)tmp, "Block Sizes"));
1233         PetscCall(PetscViewerASCIIPushTab(viewer));
1234         PetscCall(ISView(tmp, viewer));
1235         PetscCall(PetscViewerASCIIPopTab(viewer));
1236         PetscCall(ISDestroy(&tmp));
1237       }
1238     }
1239   } else if (issaws) {
1240 #if defined(PETSC_HAVE_SAWS)
1241     PetscMPIInt rank;
1242 
1243     PetscCall(PetscObjectName((PetscObject)mat));
1244     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1245     if (!((PetscObject)mat)->amsmem && rank == 0) PetscCall(PetscObjectViewSAWs((PetscObject)mat, viewer));
1246 #endif
1247   } else if (isstring) {
1248     const char *type;
1249     PetscCall(MatGetType(mat, &type));
1250     PetscCall(PetscViewerStringSPrintf(viewer, " MatType: %-7.7s", type));
1251     PetscTryTypeMethod(mat, view, viewer);
1252   }
1253   if ((format == PETSC_VIEWER_NATIVE || format == PETSC_VIEWER_LOAD_BALANCE) && mat->ops->viewnative) {
1254     PetscCall(PetscViewerASCIIPushTab(viewer));
1255     PetscUseTypeMethod(mat, viewnative, viewer);
1256     PetscCall(PetscViewerASCIIPopTab(viewer));
1257   } else if (mat->ops->view) {
1258     PetscCall(PetscViewerASCIIPushTab(viewer));
1259     PetscUseTypeMethod(mat, view, viewer);
1260     PetscCall(PetscViewerASCIIPopTab(viewer));
1261   }
1262   if (isascii) {
1263     PetscCall(PetscViewerGetFormat(viewer, &format));
1264     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscCall(PetscViewerASCIIPopTab(viewer));
1265   }
1266   PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1267 #if !defined(PETSC_HAVE_THREADSAFETY)
1268   insidematview--;
1269 #endif
1270   PetscFunctionReturn(PETSC_SUCCESS);
1271 }
1272 
1273 #if defined(PETSC_USE_DEBUG)
1274   #include <../src/sys/totalview/tv_data_display.h>
1275 PETSC_UNUSED static int TV_display_type(const struct _p_Mat *mat)
1276 {
1277   TV_add_row("Local rows", "int", &mat->rmap->n);
1278   TV_add_row("Local columns", "int", &mat->cmap->n);
1279   TV_add_row("Global rows", "int", &mat->rmap->N);
1280   TV_add_row("Global columns", "int", &mat->cmap->N);
1281   TV_add_row("Typename", TV_ascii_string_type, ((PetscObject)mat)->type_name);
1282   return TV_format_OK;
1283 }
1284 #endif
1285 
1286 /*@
1287   MatLoad - Loads a matrix that has been stored in binary/HDF5 format
1288   with `MatView()`.  The matrix format is determined from the options database.
1289   Generates a parallel MPI matrix if the communicator has more than one
1290   processor.  The default matrix type is `MATAIJ`.
1291 
1292   Collective
1293 
1294   Input Parameters:
1295 + mat    - the newly loaded matrix, this needs to have been created with `MatCreate()`
1296             or some related function before a call to `MatLoad()`
1297 - viewer - `PETSCVIEWERBINARY`/`PETSCVIEWERHDF5` file viewer
1298 
1299   Options Database Key:
1300 . -matload_block_size <bs> - set block size
1301 
1302   Level: beginner
1303 
1304   Notes:
1305   If the `Mat` type has not yet been given then `MATAIJ` is used, call `MatSetFromOptions()` on the
1306   `Mat` before calling this routine if you wish to set it from the options database.
1307 
1308   `MatLoad()` automatically loads into the options database any options
1309   given in the file filename.info where filename is the name of the file
1310   that was passed to the `PetscViewerBinaryOpen()`. The options in the info
1311   file will be ignored if you use the -viewer_binary_skip_info option.
1312 
1313   If the type or size of mat is not set before a call to `MatLoad()`, PETSc
1314   sets the default matrix type AIJ and sets the local and global sizes.
1315   If type and/or size is already set, then the same are used.
1316 
1317   In parallel, each processor can load a subset of rows (or the
1318   entire matrix).  This routine is especially useful when a large
1319   matrix is stored on disk and only part of it is desired on each
1320   processor.  For example, a parallel solver may access only some of
1321   the rows from each processor.  The algorithm used here reads
1322   relatively small blocks of data rather than reading the entire
1323   matrix and then subsetting it.
1324 
1325   Viewer's `PetscViewerType` must be either `PETSCVIEWERBINARY` or `PETSCVIEWERHDF5`.
1326   Such viewer can be created using `PetscViewerBinaryOpen()` or `PetscViewerHDF5Open()`,
1327   or the sequence like
1328 .vb
1329     `PetscViewer` v;
1330     `PetscViewerCreate`(`PETSC_COMM_WORLD`,&v);
1331     `PetscViewerSetType`(v,`PETSCVIEWERBINARY`);
1332     `PetscViewerSetFromOptions`(v);
1333     `PetscViewerFileSetMode`(v,`FILE_MODE_READ`);
1334     `PetscViewerFileSetName`(v,"datafile");
1335 .ve
1336   The optional `PetscViewerSetFromOptions()` call allows overriding `PetscViewerSetType()` using the option
1337 .vb
1338   -viewer_type {binary, hdf5}
1339 .ve
1340 
1341   See the example src/ksp/ksp/tutorials/ex27.c with the first approach,
1342   and src/mat/tutorials/ex10.c with the second approach.
1343 
1344   In case of `PETSCVIEWERBINARY`, a native PETSc binary format is used. Each of the blocks
1345   is read onto MPI rank 0 and then shipped to its destination MPI rank, one after another.
1346   Multiple objects, both matrices and vectors, can be stored within the same file.
1347   Their `PetscObject` name is ignored; they are loaded in the order of their storage.
1348 
1349   Most users should not need to know the details of the binary storage
1350   format, since `MatLoad()` and `MatView()` completely hide these details.
1351   But for anyone who is interested, the standard binary matrix storage
1352   format is
1353 
1354 .vb
1355     PetscInt    MAT_FILE_CLASSID
1356     PetscInt    number of rows
1357     PetscInt    number of columns
1358     PetscInt    total number of nonzeros
1359     PetscInt    *number nonzeros in each row
1360     PetscInt    *column indices of all nonzeros (starting index is zero)
1361     PetscScalar *values of all nonzeros
1362 .ve
1363   If PETSc was not configured with `--with-64-bit-indices` then only `MATMPIAIJ` matrices with more than `PETSC_INT_MAX` non-zeros can be
1364   stored or loaded (each MPI process part of the matrix must have less than `PETSC_INT_MAX` nonzeros). Since the total nonzero count in this
1365   case will not fit in a (32-bit) `PetscInt` the value `PETSC_INT_MAX` is used for the header entry `total number of nonzeros`.
1366 
1367   PETSc automatically does the byte swapping for
1368   machines that store the bytes reversed. Thus if you write your own binary
1369   read/write routines you have to swap the bytes; see `PetscBinaryRead()`
1370   and `PetscBinaryWrite()` to see how this may be done.
1371 
1372   In case of `PETSCVIEWERHDF5`, a parallel HDF5 reader is used.
1373   Each processor's chunk is loaded independently by its owning MPI process.
1374   Multiple objects, both matrices and vectors, can be stored within the same file.
1375   They are looked up by their PetscObject name.
1376 
1377   As the MATLAB MAT-File Version 7.3 format is also a HDF5 flavor, we decided to use
1378   by default the same structure and naming of the AIJ arrays and column count
1379   within the HDF5 file. This means that a MAT file saved with -v7.3 flag, e.g.
1380 .vb
1381   save example.mat A b -v7.3
1382 .ve
1383   can be directly read by this routine (see Reference 1 for details).
1384 
1385   Depending on your MATLAB version, this format might be a default,
1386   otherwise you can set it as default in Preferences.
1387 
1388   Unless -nocompression flag is used to save the file in MATLAB,
1389   PETSc must be configured with ZLIB package.
1390 
1391   See also examples src/mat/tutorials/ex10.c and src/ksp/ksp/tutorials/ex27.c
1392 
1393   This reader currently supports only real `MATSEQAIJ`, `MATMPIAIJ`, `MATSEQDENSE` and `MATMPIDENSE` matrices for `PETSCVIEWERHDF5`
1394 
1395   Corresponding `MatView()` is not yet implemented.
1396 
1397   The loaded matrix is actually a transpose of the original one in MATLAB,
1398   unless you push `PETSC_VIEWER_HDF5_MAT` format (see examples above).
1399   With this format, matrix is automatically transposed by PETSc,
1400   unless the matrix is marked as SPD or symmetric
1401   (see `MatSetOption()`, `MAT_SPD`, `MAT_SYMMETRIC`).
1402 
1403   See MATLAB Documentation on `save()`, <https://www.mathworks.com/help/matlab/ref/save.html#btox10b-1-version>
1404 
1405 .seealso: [](ch_matrices), `Mat`, `PetscViewerBinaryOpen()`, `PetscViewerSetType()`, `MatView()`, `VecLoad()`
1406  @*/
1407 PetscErrorCode MatLoad(Mat mat, PetscViewer viewer)
1408 {
1409   PetscBool flg;
1410 
1411   PetscFunctionBegin;
1412   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1413   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1414 
1415   if (!((PetscObject)mat)->type_name) PetscCall(MatSetType(mat, MATAIJ));
1416 
1417   flg = PETSC_FALSE;
1418   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_symmetric", &flg, NULL));
1419   if (flg) {
1420     PetscCall(MatSetOption(mat, MAT_SYMMETRIC, PETSC_TRUE));
1421     PetscCall(MatSetOption(mat, MAT_SYMMETRY_ETERNAL, PETSC_TRUE));
1422   }
1423   flg = PETSC_FALSE;
1424   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_spd", &flg, NULL));
1425   if (flg) PetscCall(MatSetOption(mat, MAT_SPD, PETSC_TRUE));
1426 
1427   PetscCall(PetscLogEventBegin(MAT_Load, mat, viewer, 0, 0));
1428   PetscUseTypeMethod(mat, load, viewer);
1429   PetscCall(PetscLogEventEnd(MAT_Load, mat, viewer, 0, 0));
1430   PetscFunctionReturn(PETSC_SUCCESS);
1431 }
1432 
1433 static PetscErrorCode MatDestroy_Redundant(Mat_Redundant **redundant)
1434 {
1435   Mat_Redundant *redund = *redundant;
1436 
1437   PetscFunctionBegin;
1438   if (redund) {
1439     if (redund->matseq) { /* via MatCreateSubMatrices()  */
1440       PetscCall(ISDestroy(&redund->isrow));
1441       PetscCall(ISDestroy(&redund->iscol));
1442       PetscCall(MatDestroySubMatrices(1, &redund->matseq));
1443     } else {
1444       PetscCall(PetscFree2(redund->send_rank, redund->recv_rank));
1445       PetscCall(PetscFree(redund->sbuf_j));
1446       PetscCall(PetscFree(redund->sbuf_a));
1447       for (PetscInt i = 0; i < redund->nrecvs; i++) {
1448         PetscCall(PetscFree(redund->rbuf_j[i]));
1449         PetscCall(PetscFree(redund->rbuf_a[i]));
1450       }
1451       PetscCall(PetscFree4(redund->sbuf_nz, redund->rbuf_nz, redund->rbuf_j, redund->rbuf_a));
1452     }
1453 
1454     if (redund->subcomm) PetscCall(PetscCommDestroy(&redund->subcomm));
1455     PetscCall(PetscFree(redund));
1456   }
1457   PetscFunctionReturn(PETSC_SUCCESS);
1458 }
1459 
1460 /*@
1461   MatDestroy - Frees space taken by a matrix.
1462 
1463   Collective
1464 
1465   Input Parameter:
1466 . A - the matrix
1467 
1468   Level: beginner
1469 
1470   Developer Note:
1471   Some special arrays of matrices are not destroyed in this routine but instead by the routines called by
1472   `MatDestroySubMatrices()`. Thus one must be sure that any changes here must also be made in those routines.
1473   `MatHeaderMerge()` and `MatHeaderReplace()` also manipulate the data in the `Mat` object and likely need changes
1474   if changes are needed here.
1475 
1476 .seealso: [](ch_matrices), `Mat`, `MatCreate()`
1477 @*/
1478 PetscErrorCode MatDestroy(Mat *A)
1479 {
1480   PetscFunctionBegin;
1481   if (!*A) PetscFunctionReturn(PETSC_SUCCESS);
1482   PetscValidHeaderSpecific(*A, MAT_CLASSID, 1);
1483   if (--((PetscObject)*A)->refct > 0) {
1484     *A = NULL;
1485     PetscFunctionReturn(PETSC_SUCCESS);
1486   }
1487 
1488   /* if memory was published with SAWs then destroy it */
1489   PetscCall(PetscObjectSAWsViewOff((PetscObject)*A));
1490   PetscTryTypeMethod(*A, destroy);
1491 
1492   PetscCall(PetscFree((*A)->factorprefix));
1493   PetscCall(PetscFree((*A)->defaultvectype));
1494   PetscCall(PetscFree((*A)->defaultrandtype));
1495   PetscCall(PetscFree((*A)->bsizes));
1496   PetscCall(PetscFree((*A)->solvertype));
1497   for (PetscInt i = 0; i < MAT_FACTOR_NUM_TYPES; i++) PetscCall(PetscFree((*A)->preferredordering[i]));
1498   if ((*A)->redundant && (*A)->redundant->matseq[0] == *A) (*A)->redundant->matseq[0] = NULL;
1499   PetscCall(MatDestroy_Redundant(&(*A)->redundant));
1500   PetscCall(MatProductClear(*A));
1501   PetscCall(MatNullSpaceDestroy(&(*A)->nullsp));
1502   PetscCall(MatNullSpaceDestroy(&(*A)->transnullsp));
1503   PetscCall(MatNullSpaceDestroy(&(*A)->nearnullsp));
1504   PetscCall(MatDestroy(&(*A)->schur));
1505   PetscCall(PetscLayoutDestroy(&(*A)->rmap));
1506   PetscCall(PetscLayoutDestroy(&(*A)->cmap));
1507   PetscCall(PetscHeaderDestroy(A));
1508   PetscFunctionReturn(PETSC_SUCCESS);
1509 }
1510 
1511 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1512 /*@
1513   MatSetValues - Inserts or adds a block of values into a matrix.
1514   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1515   MUST be called after all calls to `MatSetValues()` have been completed.
1516 
1517   Not Collective
1518 
1519   Input Parameters:
1520 + mat  - the matrix
1521 . m    - the number of rows
1522 . idxm - the global indices of the rows
1523 . n    - the number of columns
1524 . idxn - the global indices of the columns
1525 . v    - a one-dimensional array that contains the values implicitly stored as a two-dimensional array, by default in row-major order.
1526          See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
1527 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1528 
1529   Level: beginner
1530 
1531   Notes:
1532   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1533   options cannot be mixed without intervening calls to the assembly
1534   routines.
1535 
1536   `MatSetValues()` uses 0-based row and column numbers in Fortran
1537   as well as in C.
1538 
1539   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
1540   simply ignored. This allows easily inserting element stiffness matrices
1541   with homogeneous Dirichlet boundary conditions that you don't want represented
1542   in the matrix.
1543 
1544   Efficiency Alert:
1545   The routine `MatSetValuesBlocked()` may offer much better efficiency
1546   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1547 
1548   Fortran Notes:
1549   If any of `idxm`, `idxn`, and `v` are scalars pass them using, for example,
1550 .vb
1551   call MatSetValues(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES, ierr)
1552 .ve
1553 
1554   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
1555 
1556   Developer Note:
1557   This is labeled with C so does not automatically generate Fortran stubs and interfaces
1558   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
1559 
1560 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1561           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1562 @*/
1563 PetscErrorCode MatSetValues(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
1564 {
1565   PetscFunctionBeginHot;
1566   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1567   PetscValidType(mat, 1);
1568   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1569   PetscAssertPointer(idxm, 3);
1570   PetscAssertPointer(idxn, 5);
1571   MatCheckPreallocated(mat, 1);
1572 
1573   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
1574   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
1575 
1576   if (PetscDefined(USE_DEBUG)) {
1577     PetscInt i, j;
1578 
1579     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1580     if (v) {
1581       for (i = 0; i < m; i++) {
1582         for (j = 0; j < n; j++) {
1583           if (mat->erroriffailure && PetscIsInfOrNanScalar(v[i * n + j]))
1584 #if defined(PETSC_USE_COMPLEX)
1585             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Inserting %g+i%g at matrix entry (%" PetscInt_FMT ",%" PetscInt_FMT ")", (double)PetscRealPart(v[i * n + j]), (double)PetscImaginaryPart(v[i * n + j]), idxm[i], idxn[j]);
1586 #else
1587             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Inserting %g at matrix entry (%" PetscInt_FMT ",%" PetscInt_FMT ")", (double)v[i * n + j], idxm[i], idxn[j]);
1588 #endif
1589         }
1590       }
1591     }
1592     for (i = 0; i < m; i++) PetscCheck(idxm[i] < mat->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot insert in row %" PetscInt_FMT ", maximum is %" PetscInt_FMT, idxm[i], mat->rmap->N - 1);
1593     for (i = 0; i < n; i++) PetscCheck(idxn[i] < mat->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot insert in column %" PetscInt_FMT ", maximum is %" PetscInt_FMT, idxn[i], mat->cmap->N - 1);
1594   }
1595 
1596   if (mat->assembled) {
1597     mat->was_assembled = PETSC_TRUE;
1598     mat->assembled     = PETSC_FALSE;
1599   }
1600   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1601   PetscUseTypeMethod(mat, setvalues, m, idxm, n, idxn, v, addv);
1602   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1603   PetscFunctionReturn(PETSC_SUCCESS);
1604 }
1605 
1606 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1607 /*@
1608   MatSetValuesIS - Inserts or adds a block of values into a matrix using an `IS` to indicate the rows and columns
1609   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1610   MUST be called after all calls to `MatSetValues()` have been completed.
1611 
1612   Not Collective
1613 
1614   Input Parameters:
1615 + mat  - the matrix
1616 . ism  - the rows to provide
1617 . isn  - the columns to provide
1618 . v    - a one-dimensional array that contains the values implicitly stored as a two-dimensional array, by default in row-major order.
1619          See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
1620 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1621 
1622   Level: beginner
1623 
1624   Notes:
1625   By default, the values, `v`, are stored in row-major order. See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
1626 
1627   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1628   options cannot be mixed without intervening calls to the assembly
1629   routines.
1630 
1631   `MatSetValues()` uses 0-based row and column numbers in Fortran
1632   as well as in C.
1633 
1634   Negative indices may be passed in `ism` and `isn`, these rows and columns are
1635   simply ignored. This allows easily inserting element stiffness matrices
1636   with homogeneous Dirichlet boundary conditions that you don't want represented
1637   in the matrix.
1638 
1639   Fortran Note:
1640   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
1641 
1642   Efficiency Alert:
1643   The routine `MatSetValuesBlocked()` may offer much better efficiency
1644   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1645 
1646   This is currently not optimized for any particular `ISType`
1647 
1648 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatSetValues()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1649           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1650 @*/
1651 PetscErrorCode MatSetValuesIS(Mat mat, IS ism, IS isn, const PetscScalar v[], InsertMode addv)
1652 {
1653   PetscInt        m, n;
1654   const PetscInt *rows, *cols;
1655 
1656   PetscFunctionBeginHot;
1657   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1658   PetscCall(ISGetIndices(ism, &rows));
1659   PetscCall(ISGetIndices(isn, &cols));
1660   PetscCall(ISGetLocalSize(ism, &m));
1661   PetscCall(ISGetLocalSize(isn, &n));
1662   PetscCall(MatSetValues(mat, m, rows, n, cols, v, addv));
1663   PetscCall(ISRestoreIndices(ism, &rows));
1664   PetscCall(ISRestoreIndices(isn, &cols));
1665   PetscFunctionReturn(PETSC_SUCCESS);
1666 }
1667 
1668 /*@
1669   MatSetValuesRowLocal - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1670   values into a matrix
1671 
1672   Not Collective
1673 
1674   Input Parameters:
1675 + mat - the matrix
1676 . row - the (block) row to set
1677 - v   - a one-dimensional array that contains the values. For `MATBAIJ` they are implicitly stored as a two-dimensional array, by default in row-major order.
1678         See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
1679 
1680   Level: intermediate
1681 
1682   Notes:
1683   The values, `v`, are column-oriented (for the block version) and sorted
1684 
1685   All the nonzero values in `row` must be provided
1686 
1687   The matrix must have previously had its column indices set, likely by having been assembled.
1688 
1689   `row` must belong to this MPI process
1690 
1691   Fortran Note:
1692   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
1693 
1694 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1695           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetValuesRow()`, `MatSetLocalToGlobalMapping()`
1696 @*/
1697 PetscErrorCode MatSetValuesRowLocal(Mat mat, PetscInt row, const PetscScalar v[])
1698 {
1699   PetscInt globalrow;
1700 
1701   PetscFunctionBegin;
1702   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1703   PetscValidType(mat, 1);
1704   PetscAssertPointer(v, 3);
1705   PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, 1, &row, &globalrow));
1706   PetscCall(MatSetValuesRow(mat, globalrow, v));
1707   PetscFunctionReturn(PETSC_SUCCESS);
1708 }
1709 
1710 /*@
1711   MatSetValuesRow - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1712   values into a matrix
1713 
1714   Not Collective
1715 
1716   Input Parameters:
1717 + mat - the matrix
1718 . row - the (block) row to set
1719 - v   - a logically two-dimensional (column major) array of values for  block matrices with blocksize larger than one, otherwise a one dimensional array of values
1720 
1721   Level: advanced
1722 
1723   Notes:
1724   The values, `v`, are column-oriented for the block version.
1725 
1726   All the nonzeros in `row` must be provided
1727 
1728   THE MATRIX MUST HAVE PREVIOUSLY HAD ITS COLUMN INDICES SET. IT IS RARE THAT THIS ROUTINE IS USED, usually `MatSetValues()` is used.
1729 
1730   `row` must belong to this process
1731 
1732 .seealso: [](ch_matrices), `Mat`, `MatSetValues()`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1733           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1734 @*/
1735 PetscErrorCode MatSetValuesRow(Mat mat, PetscInt row, const PetscScalar v[])
1736 {
1737   PetscFunctionBeginHot;
1738   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1739   PetscValidType(mat, 1);
1740   MatCheckPreallocated(mat, 1);
1741   PetscAssertPointer(v, 3);
1742   PetscCheck(mat->insertmode != ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add and insert values");
1743   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1744   mat->insertmode = INSERT_VALUES;
1745 
1746   if (mat->assembled) {
1747     mat->was_assembled = PETSC_TRUE;
1748     mat->assembled     = PETSC_FALSE;
1749   }
1750   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1751   PetscUseTypeMethod(mat, setvaluesrow, row, v);
1752   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1753   PetscFunctionReturn(PETSC_SUCCESS);
1754 }
1755 
1756 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1757 /*@
1758   MatSetValuesStencil - Inserts or adds a block of values into a matrix.
1759   Using structured grid indexing
1760 
1761   Not Collective
1762 
1763   Input Parameters:
1764 + mat  - the matrix
1765 . m    - number of rows being entered
1766 . idxm - grid coordinates (and component number when dof > 1) for matrix rows being entered
1767 . n    - number of columns being entered
1768 . idxn - grid coordinates (and component number when dof > 1) for matrix columns being entered
1769 . v    - a one-dimensional array that contains the values implicitly stored as a two-dimensional array, by default in row-major order.
1770          See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
1771 - addv - either `ADD_VALUES` to add to existing entries at that location or `INSERT_VALUES` to replace existing entries with new values
1772 
1773   Level: beginner
1774 
1775   Notes:
1776   By default the values, `v`, are row-oriented.  See `MatSetOption()` for other options.
1777 
1778   Calls to `MatSetValuesStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1779   options cannot be mixed without intervening calls to the assembly
1780   routines.
1781 
1782   The grid coordinates are across the entire grid, not just the local portion
1783 
1784   `MatSetValuesStencil()` uses 0-based row and column numbers in Fortran
1785   as well as in C.
1786 
1787   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1788 
1789   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1790   or call `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1791 
1792   The columns and rows in the stencil passed in MUST be contained within the
1793   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1794   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1795   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1796   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1797 
1798   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
1799   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
1800   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
1801   `DM_BOUNDARY_PERIODIC` boundary type.
1802 
1803   For indices that don't mean anything for your case (like the k index when working in 2d) or the c index when you have
1804   a single value per point) you can skip filling those indices.
1805 
1806   Inspired by the structured grid interface to the HYPRE package
1807   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1808 
1809   Fortran Note:
1810   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
1811 
1812   Efficiency Alert:
1813   The routine `MatSetValuesBlockedStencil()` may offer much better efficiency
1814   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1815 
1816 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1817           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`
1818 @*/
1819 PetscErrorCode MatSetValuesStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1820 {
1821   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1822   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1823   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1824 
1825   PetscFunctionBegin;
1826   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1827   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1828   PetscValidType(mat, 1);
1829   PetscAssertPointer(idxm, 3);
1830   PetscAssertPointer(idxn, 5);
1831 
1832   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1833     jdxm = buf;
1834     jdxn = buf + m;
1835   } else {
1836     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1837     jdxm = bufm;
1838     jdxn = bufn;
1839   }
1840   for (i = 0; i < m; i++) {
1841     for (j = 0; j < 3 - sdim; j++) dxm++;
1842     tmp = *dxm++ - starts[0];
1843     for (j = 0; j < dim - 1; j++) {
1844       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1845       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1846     }
1847     if (mat->stencil.noc) dxm++;
1848     jdxm[i] = tmp;
1849   }
1850   for (i = 0; i < n; i++) {
1851     for (j = 0; j < 3 - sdim; j++) dxn++;
1852     tmp = *dxn++ - starts[0];
1853     for (j = 0; j < dim - 1; j++) {
1854       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1855       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1856     }
1857     if (mat->stencil.noc) dxn++;
1858     jdxn[i] = tmp;
1859   }
1860   PetscCall(MatSetValuesLocal(mat, m, jdxm, n, jdxn, v, addv));
1861   PetscCall(PetscFree2(bufm, bufn));
1862   PetscFunctionReturn(PETSC_SUCCESS);
1863 }
1864 
1865 /*@
1866   MatSetValuesBlockedStencil - Inserts or adds a block of values into a matrix.
1867   Using structured grid indexing
1868 
1869   Not Collective
1870 
1871   Input Parameters:
1872 + mat  - the matrix
1873 . m    - number of rows being entered
1874 . idxm - grid coordinates for matrix rows being entered
1875 . n    - number of columns being entered
1876 . idxn - grid coordinates for matrix columns being entered
1877 . v    - a one-dimensional array that contains the values implicitly stored as a two-dimensional array, by default in row-major order.
1878          See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
1879 - addv - either `ADD_VALUES` to add to existing entries or `INSERT_VALUES` to replace existing entries with new values
1880 
1881   Level: beginner
1882 
1883   Notes:
1884   By default the values, `v`, are row-oriented and unsorted.
1885   See `MatSetOption()` for other options.
1886 
1887   Calls to `MatSetValuesBlockedStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1888   options cannot be mixed without intervening calls to the assembly
1889   routines.
1890 
1891   The grid coordinates are across the entire grid, not just the local portion
1892 
1893   `MatSetValuesBlockedStencil()` uses 0-based row and column numbers in Fortran
1894   as well as in C.
1895 
1896   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1897 
1898   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1899   or call `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1900 
1901   The columns and rows in the stencil passed in MUST be contained within the
1902   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1903   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1904   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1905   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1906 
1907   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
1908   simply ignored. This allows easily inserting element stiffness matrices
1909   with homogeneous Dirichlet boundary conditions that you don't want represented
1910   in the matrix.
1911 
1912   Inspired by the structured grid interface to the HYPRE package
1913   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1914 
1915   Fortran Notes:
1916   `idxm` and `idxn` should be declared as
1917 .vb
1918     MatStencil idxm(4,m),idxn(4,n)
1919 .ve
1920   and the values inserted using
1921 .vb
1922     idxm(MatStencil_i,1) = i
1923     idxm(MatStencil_j,1) = j
1924     idxm(MatStencil_k,1) = k
1925    etc
1926 .ve
1927 
1928   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
1929 
1930 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1931           `MatSetValues()`, `MatSetValuesStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`,
1932           `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`
1933 @*/
1934 PetscErrorCode MatSetValuesBlockedStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1935 {
1936   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1937   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1938   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1939 
1940   PetscFunctionBegin;
1941   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1942   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1943   PetscValidType(mat, 1);
1944   PetscAssertPointer(idxm, 3);
1945   PetscAssertPointer(idxn, 5);
1946   PetscAssertPointer(v, 6);
1947 
1948   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1949     jdxm = buf;
1950     jdxn = buf + m;
1951   } else {
1952     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1953     jdxm = bufm;
1954     jdxn = bufn;
1955   }
1956   for (i = 0; i < m; i++) {
1957     for (j = 0; j < 3 - sdim; j++) dxm++;
1958     tmp = *dxm++ - starts[0];
1959     for (j = 0; j < sdim - 1; j++) {
1960       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1961       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1962     }
1963     dxm++;
1964     jdxm[i] = tmp;
1965   }
1966   for (i = 0; i < n; i++) {
1967     for (j = 0; j < 3 - sdim; j++) dxn++;
1968     tmp = *dxn++ - starts[0];
1969     for (j = 0; j < sdim - 1; j++) {
1970       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1971       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1972     }
1973     dxn++;
1974     jdxn[i] = tmp;
1975   }
1976   PetscCall(MatSetValuesBlockedLocal(mat, m, jdxm, n, jdxn, v, addv));
1977   PetscCall(PetscFree2(bufm, bufn));
1978   PetscFunctionReturn(PETSC_SUCCESS);
1979 }
1980 
1981 /*@
1982   MatSetStencil - Sets the grid information for setting values into a matrix via
1983   `MatSetValuesStencil()`
1984 
1985   Not Collective
1986 
1987   Input Parameters:
1988 + mat    - the matrix
1989 . dim    - dimension of the grid 1, 2, or 3
1990 . dims   - number of grid points in x, y, and z direction, including ghost points on your processor
1991 . starts - starting point of ghost nodes on your processor in x, y, and z direction
1992 - dof    - number of degrees of freedom per node
1993 
1994   Level: beginner
1995 
1996   Notes:
1997   Inspired by the structured grid interface to the HYPRE package
1998   (www.llnl.gov/CASC/hyper)
1999 
2000   For matrices generated with `DMCreateMatrix()` this routine is automatically called and so not needed by the
2001   user.
2002 
2003 .seealso: [](ch_matrices), `Mat`, `MatStencil`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
2004           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetValuesStencil()`
2005 @*/
2006 PetscErrorCode MatSetStencil(Mat mat, PetscInt dim, const PetscInt dims[], const PetscInt starts[], PetscInt dof)
2007 {
2008   PetscFunctionBegin;
2009   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2010   PetscAssertPointer(dims, 3);
2011   PetscAssertPointer(starts, 4);
2012 
2013   mat->stencil.dim = dim + (dof > 1);
2014   for (PetscInt i = 0; i < dim; i++) {
2015     mat->stencil.dims[i]   = dims[dim - i - 1]; /* copy the values in backwards */
2016     mat->stencil.starts[i] = starts[dim - i - 1];
2017   }
2018   mat->stencil.dims[dim]   = dof;
2019   mat->stencil.starts[dim] = 0;
2020   mat->stencil.noc         = (PetscBool)(dof == 1);
2021   PetscFunctionReturn(PETSC_SUCCESS);
2022 }
2023 
2024 /*@
2025   MatSetValuesBlocked - Inserts or adds a block of values into a matrix.
2026 
2027   Not Collective
2028 
2029   Input Parameters:
2030 + mat  - the matrix
2031 . m    - the number of block rows
2032 . idxm - the global block indices
2033 . n    - the number of block columns
2034 . idxn - the global block indices
2035 . v    - a one-dimensional array that contains the values implicitly stored as a two-dimensional array, by default in row-major order.
2036          See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
2037 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` replaces existing entries with new values
2038 
2039   Level: intermediate
2040 
2041   Notes:
2042   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call
2043   MatXXXXSetPreallocation() or `MatSetUp()` before using this routine.
2044 
2045   The `m` and `n` count the NUMBER of blocks in the row direction and column direction,
2046   NOT the total number of rows/columns; for example, if the block size is 2 and
2047   you are passing in values for rows 2,3,4,5  then `m` would be 2 (not 4).
2048   The values in `idxm` would be 1 2; that is the first index for each block divided by
2049   the block size.
2050 
2051   You must call `MatSetBlockSize()` when constructing this matrix (before
2052   preallocating it).
2053 
2054   By default, the values, `v`, are stored in row-major order. See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
2055 
2056   Calls to `MatSetValuesBlocked()` with the `INSERT_VALUES` and `ADD_VALUES`
2057   options cannot be mixed without intervening calls to the assembly
2058   routines.
2059 
2060   `MatSetValuesBlocked()` uses 0-based row and column numbers in Fortran
2061   as well as in C.
2062 
2063   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
2064   simply ignored. This allows easily inserting element stiffness matrices
2065   with homogeneous Dirichlet boundary conditions that you don't want represented
2066   in the matrix.
2067 
2068   Each time an entry is set within a sparse matrix via `MatSetValues()`,
2069   internal searching must be done to determine where to place the
2070   data in the matrix storage space.  By instead inserting blocks of
2071   entries via `MatSetValuesBlocked()`, the overhead of matrix assembly is
2072   reduced.
2073 
2074   Example:
2075 .vb
2076    Suppose m=n=2 and block size(bs) = 2 The array is
2077 
2078    1  2  | 3  4
2079    5  6  | 7  8
2080    - - - | - - -
2081    9  10 | 11 12
2082    13 14 | 15 16
2083 
2084    v[] should be passed in like
2085    v[] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
2086 
2087   If you are not using row-oriented storage of v (that is you called MatSetOption(mat,MAT_ROW_ORIENTED,PETSC_FALSE)) then
2088    v[] = [1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16]
2089 .ve
2090 
2091   Fortran Notes:
2092   If any of `idmx`, `idxn`, and `v` are scalars pass them using, for example,
2093 .vb
2094   call MatSetValuesBlocked(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES, ierr)
2095 .ve
2096 
2097   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2098 
2099 .seealso: [](ch_matrices), `Mat`, `MatSetBlockSize()`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetValuesBlockedLocal()`
2100 @*/
2101 PetscErrorCode MatSetValuesBlocked(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
2102 {
2103   PetscFunctionBeginHot;
2104   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2105   PetscValidType(mat, 1);
2106   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2107   PetscAssertPointer(idxm, 3);
2108   PetscAssertPointer(idxn, 5);
2109   MatCheckPreallocated(mat, 1);
2110   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2111   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2112   if (PetscDefined(USE_DEBUG)) {
2113     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2114     PetscCheck(mat->ops->setvaluesblocked || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2115   }
2116   if (PetscDefined(USE_DEBUG)) {
2117     PetscInt rbs, cbs, M, N, i;
2118     PetscCall(MatGetBlockSizes(mat, &rbs, &cbs));
2119     PetscCall(MatGetSize(mat, &M, &N));
2120     for (i = 0; i < m; i++) PetscCheck(idxm[i] * rbs < M, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row block %" PetscInt_FMT " contains an index %" PetscInt_FMT "*%" PetscInt_FMT " greater than row length %" PetscInt_FMT, i, idxm[i], rbs, M);
2121     for (i = 0; i < n; i++)
2122       PetscCheck(idxn[i] * cbs < N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column block %" PetscInt_FMT " contains an index %" PetscInt_FMT "*%" PetscInt_FMT " greater than column length %" PetscInt_FMT, i, idxn[i], cbs, N);
2123   }
2124   if (mat->assembled) {
2125     mat->was_assembled = PETSC_TRUE;
2126     mat->assembled     = PETSC_FALSE;
2127   }
2128   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2129   if (mat->ops->setvaluesblocked) {
2130     PetscUseTypeMethod(mat, setvaluesblocked, m, idxm, n, idxn, v, addv);
2131   } else {
2132     PetscInt buf[8192], *bufr = NULL, *bufc = NULL, *iidxm, *iidxn;
2133     PetscInt i, j, bs, cbs;
2134 
2135     PetscCall(MatGetBlockSizes(mat, &bs, &cbs));
2136     if ((m * bs + n * cbs) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2137       iidxm = buf;
2138       iidxn = buf + m * bs;
2139     } else {
2140       PetscCall(PetscMalloc2(m * bs, &bufr, n * cbs, &bufc));
2141       iidxm = bufr;
2142       iidxn = bufc;
2143     }
2144     for (i = 0; i < m; i++) {
2145       for (j = 0; j < bs; j++) iidxm[i * bs + j] = bs * idxm[i] + j;
2146     }
2147     if (m != n || bs != cbs || idxm != idxn) {
2148       for (i = 0; i < n; i++) {
2149         for (j = 0; j < cbs; j++) iidxn[i * cbs + j] = cbs * idxn[i] + j;
2150       }
2151     } else iidxn = iidxm;
2152     PetscCall(MatSetValues(mat, m * bs, iidxm, n * cbs, iidxn, v, addv));
2153     PetscCall(PetscFree2(bufr, bufc));
2154   }
2155   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2156   PetscFunctionReturn(PETSC_SUCCESS);
2157 }
2158 
2159 /*@
2160   MatGetValues - Gets a block of local values from a matrix.
2161 
2162   Not Collective; can only return values that are owned by the give process
2163 
2164   Input Parameters:
2165 + mat  - the matrix
2166 . v    - a logically two-dimensional array for storing the values
2167 . m    - the number of rows
2168 . idxm - the  global indices of the rows
2169 . n    - the number of columns
2170 - idxn - the global indices of the columns
2171 
2172   Level: advanced
2173 
2174   Notes:
2175   The user must allocate space (m*n `PetscScalar`s) for the values, `v`.
2176   The values, `v`, are then returned in a row-oriented format,
2177   analogous to that used by default in `MatSetValues()`.
2178 
2179   `MatGetValues()` uses 0-based row and column numbers in
2180   Fortran as well as in C.
2181 
2182   `MatGetValues()` requires that the matrix has been assembled
2183   with `MatAssemblyBegin()`/`MatAssemblyEnd()`.  Thus, calls to
2184   `MatSetValues()` and `MatGetValues()` CANNOT be made in succession
2185   without intermediate matrix assembly.
2186 
2187   Negative row or column indices will be ignored and those locations in `v` will be
2188   left unchanged.
2189 
2190   For the standard row-based matrix formats, `idxm` can only contain rows owned by the requesting MPI process.
2191   That is, rows with global index greater than or equal to rstart and less than rend where rstart and rend are obtainable
2192   from `MatGetOwnershipRange`(mat,&rstart,&rend).
2193 
2194 .seealso: [](ch_matrices), `Mat`, `MatGetRow()`, `MatCreateSubMatrices()`, `MatSetValues()`, `MatGetOwnershipRange()`, `MatGetValuesLocal()`, `MatGetValue()`
2195 @*/
2196 PetscErrorCode MatGetValues(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], PetscScalar v[])
2197 {
2198   PetscFunctionBegin;
2199   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2200   PetscValidType(mat, 1);
2201   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS);
2202   PetscAssertPointer(idxm, 3);
2203   PetscAssertPointer(idxn, 5);
2204   PetscAssertPointer(v, 6);
2205   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2206   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2207   MatCheckPreallocated(mat, 1);
2208 
2209   PetscCall(PetscLogEventBegin(MAT_GetValues, mat, 0, 0, 0));
2210   PetscUseTypeMethod(mat, getvalues, m, idxm, n, idxn, v);
2211   PetscCall(PetscLogEventEnd(MAT_GetValues, mat, 0, 0, 0));
2212   PetscFunctionReturn(PETSC_SUCCESS);
2213 }
2214 
2215 /*@
2216   MatGetValuesLocal - retrieves values from certain locations in a matrix using the local numbering of the indices
2217   defined previously by `MatSetLocalToGlobalMapping()`
2218 
2219   Not Collective
2220 
2221   Input Parameters:
2222 + mat  - the matrix
2223 . nrow - number of rows
2224 . irow - the row local indices
2225 . ncol - number of columns
2226 - icol - the column local indices
2227 
2228   Output Parameter:
2229 . y - a one-dimensional array that contains the values implicitly stored as a two-dimensional array, by default in row-major order.
2230       See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
2231 
2232   Level: advanced
2233 
2234   Notes:
2235   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetLocalToGlobalMapping()` before using this routine.
2236 
2237   This routine can only return values that are owned by the requesting MPI process. That is, for standard matrix formats, rows that, in the global numbering,
2238   are greater than or equal to rstart and less than rend where rstart and rend are obtainable from `MatGetOwnershipRange`(mat,&rstart,&rend). One can
2239   determine if the resulting global row associated with the local row r is owned by the requesting MPI process by applying the `ISLocalToGlobalMapping` set
2240   with `MatSetLocalToGlobalMapping()`.
2241 
2242 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2243           `MatSetValuesLocal()`, `MatGetValues()`
2244 @*/
2245 PetscErrorCode MatGetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], PetscScalar y[])
2246 {
2247   PetscFunctionBeginHot;
2248   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2249   PetscValidType(mat, 1);
2250   MatCheckPreallocated(mat, 1);
2251   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to retrieve */
2252   PetscAssertPointer(irow, 3);
2253   PetscAssertPointer(icol, 5);
2254   if (PetscDefined(USE_DEBUG)) {
2255     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2256     PetscCheck(mat->ops->getvalueslocal || mat->ops->getvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2257   }
2258   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2259   PetscCall(PetscLogEventBegin(MAT_GetValues, mat, 0, 0, 0));
2260   if (mat->ops->getvalueslocal) PetscUseTypeMethod(mat, getvalueslocal, nrow, irow, ncol, icol, y);
2261   else {
2262     PetscInt buf[8192], *bufr = NULL, *bufc = NULL, *irowm, *icolm;
2263     if ((nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2264       irowm = buf;
2265       icolm = buf + nrow;
2266     } else {
2267       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2268       irowm = bufr;
2269       icolm = bufc;
2270     }
2271     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global row mapping (See MatSetLocalToGlobalMapping()).");
2272     PetscCheck(mat->cmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global column mapping (See MatSetLocalToGlobalMapping()).");
2273     PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, irowm));
2274     PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, icolm));
2275     PetscCall(MatGetValues(mat, nrow, irowm, ncol, icolm, y));
2276     PetscCall(PetscFree2(bufr, bufc));
2277   }
2278   PetscCall(PetscLogEventEnd(MAT_GetValues, mat, 0, 0, 0));
2279   PetscFunctionReturn(PETSC_SUCCESS);
2280 }
2281 
2282 /*@
2283   MatSetValuesBatch - Adds (`ADD_VALUES`) many blocks of values into a matrix at once. The blocks must all be square and
2284   the same size. Currently, this can only be called once and creates the given matrix.
2285 
2286   Not Collective
2287 
2288   Input Parameters:
2289 + mat  - the matrix
2290 . nb   - the number of blocks
2291 . bs   - the number of rows (and columns) in each block
2292 . rows - a concatenation of the rows for each block
2293 - v    - a concatenation of logically two-dimensional arrays of values
2294 
2295   Level: advanced
2296 
2297   Notes:
2298   `MatSetPreallocationCOO()` and `MatSetValuesCOO()` may be a better way to provide the values
2299 
2300   In the future, we will extend this routine to handle rectangular blocks, and to allow multiple calls for a given matrix.
2301 
2302 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
2303           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetPreallocationCOO()`, `MatSetValuesCOO()`
2304 @*/
2305 PetscErrorCode MatSetValuesBatch(Mat mat, PetscInt nb, PetscInt bs, PetscInt rows[], const PetscScalar v[])
2306 {
2307   PetscFunctionBegin;
2308   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2309   PetscValidType(mat, 1);
2310   PetscAssertPointer(rows, 4);
2311   PetscAssertPointer(v, 5);
2312   PetscAssert(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2313 
2314   PetscCall(PetscLogEventBegin(MAT_SetValuesBatch, mat, 0, 0, 0));
2315   if (mat->ops->setvaluesbatch) PetscUseTypeMethod(mat, setvaluesbatch, nb, bs, rows, v);
2316   else {
2317     for (PetscInt b = 0; b < nb; ++b) PetscCall(MatSetValues(mat, bs, &rows[b * bs], bs, &rows[b * bs], &v[b * bs * bs], ADD_VALUES));
2318   }
2319   PetscCall(PetscLogEventEnd(MAT_SetValuesBatch, mat, 0, 0, 0));
2320   PetscFunctionReturn(PETSC_SUCCESS);
2321 }
2322 
2323 /*@
2324   MatSetLocalToGlobalMapping - Sets a local-to-global numbering for use by
2325   the routine `MatSetValuesLocal()` to allow users to insert matrix entries
2326   using a local (per-processor) numbering.
2327 
2328   Not Collective
2329 
2330   Input Parameters:
2331 + x        - the matrix
2332 . rmapping - row mapping created with `ISLocalToGlobalMappingCreate()` or `ISLocalToGlobalMappingCreateIS()`
2333 - cmapping - column mapping
2334 
2335   Level: intermediate
2336 
2337   Note:
2338   If the matrix is obtained with `DMCreateMatrix()` then this may already have been called on the matrix
2339 
2340 .seealso: [](ch_matrices), `Mat`, `DM`, `DMCreateMatrix()`, `MatGetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetValuesLocal()`, `MatGetValuesLocal()`
2341 @*/
2342 PetscErrorCode MatSetLocalToGlobalMapping(Mat x, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2343 {
2344   PetscFunctionBegin;
2345   PetscValidHeaderSpecific(x, MAT_CLASSID, 1);
2346   PetscValidType(x, 1);
2347   if (rmapping) PetscValidHeaderSpecific(rmapping, IS_LTOGM_CLASSID, 2);
2348   if (cmapping) PetscValidHeaderSpecific(cmapping, IS_LTOGM_CLASSID, 3);
2349   if (x->ops->setlocaltoglobalmapping) PetscUseTypeMethod(x, setlocaltoglobalmapping, rmapping, cmapping);
2350   else {
2351     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->rmap, rmapping));
2352     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->cmap, cmapping));
2353   }
2354   PetscFunctionReturn(PETSC_SUCCESS);
2355 }
2356 
2357 /*@
2358   MatGetLocalToGlobalMapping - Gets the local-to-global numbering set by `MatSetLocalToGlobalMapping()`
2359 
2360   Not Collective
2361 
2362   Input Parameter:
2363 . A - the matrix
2364 
2365   Output Parameters:
2366 + rmapping - row mapping
2367 - cmapping - column mapping
2368 
2369   Level: advanced
2370 
2371 .seealso: [](ch_matrices), `Mat`, `MatSetLocalToGlobalMapping()`, `MatSetValuesLocal()`
2372 @*/
2373 PetscErrorCode MatGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
2374 {
2375   PetscFunctionBegin;
2376   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2377   PetscValidType(A, 1);
2378   if (rmapping) {
2379     PetscAssertPointer(rmapping, 2);
2380     *rmapping = A->rmap->mapping;
2381   }
2382   if (cmapping) {
2383     PetscAssertPointer(cmapping, 3);
2384     *cmapping = A->cmap->mapping;
2385   }
2386   PetscFunctionReturn(PETSC_SUCCESS);
2387 }
2388 
2389 /*@
2390   MatSetLayouts - Sets the `PetscLayout` objects for rows and columns of a matrix
2391 
2392   Logically Collective
2393 
2394   Input Parameters:
2395 + A    - the matrix
2396 . rmap - row layout
2397 - cmap - column layout
2398 
2399   Level: advanced
2400 
2401   Note:
2402   The `PetscLayout` objects are usually created automatically for the matrix so this routine rarely needs to be called.
2403 
2404 .seealso: [](ch_matrices), `Mat`, `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatGetLayouts()`
2405 @*/
2406 PetscErrorCode MatSetLayouts(Mat A, PetscLayout rmap, PetscLayout cmap)
2407 {
2408   PetscFunctionBegin;
2409   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2410   PetscCall(PetscLayoutReference(rmap, &A->rmap));
2411   PetscCall(PetscLayoutReference(cmap, &A->cmap));
2412   PetscFunctionReturn(PETSC_SUCCESS);
2413 }
2414 
2415 /*@
2416   MatGetLayouts - Gets the `PetscLayout` objects for rows and columns
2417 
2418   Not Collective
2419 
2420   Input Parameter:
2421 . A - the matrix
2422 
2423   Output Parameters:
2424 + rmap - row layout
2425 - cmap - column layout
2426 
2427   Level: advanced
2428 
2429 .seealso: [](ch_matrices), `Mat`, [Matrix Layouts](sec_matlayout), `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatSetLayouts()`
2430 @*/
2431 PetscErrorCode MatGetLayouts(Mat A, PetscLayout *rmap, PetscLayout *cmap)
2432 {
2433   PetscFunctionBegin;
2434   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2435   PetscValidType(A, 1);
2436   if (rmap) {
2437     PetscAssertPointer(rmap, 2);
2438     *rmap = A->rmap;
2439   }
2440   if (cmap) {
2441     PetscAssertPointer(cmap, 3);
2442     *cmap = A->cmap;
2443   }
2444   PetscFunctionReturn(PETSC_SUCCESS);
2445 }
2446 
2447 /*@
2448   MatSetValuesLocal - Inserts or adds values into certain locations of a matrix,
2449   using a local numbering of the rows and columns.
2450 
2451   Not Collective
2452 
2453   Input Parameters:
2454 + mat  - the matrix
2455 . nrow - number of rows
2456 . irow - the row local indices
2457 . ncol - number of columns
2458 . icol - the column local indices
2459 . y    - a one-dimensional array that contains the values implicitly stored as a two-dimensional array, by default in row-major order.
2460          See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
2461 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2462 
2463   Level: intermediate
2464 
2465   Notes:
2466   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetLocalToGlobalMapping()` before using this routine
2467 
2468   Calls to `MatSetValuesLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2469   options cannot be mixed without intervening calls to the assembly
2470   routines.
2471 
2472   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2473   MUST be called after all calls to `MatSetValuesLocal()` have been completed.
2474 
2475   Fortran Notes:
2476   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2477 .vb
2478   call MatSetValuesLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES, ierr)
2479 .ve
2480 
2481   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2482 
2483 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2484           `MatGetValuesLocal()`
2485 @*/
2486 PetscErrorCode MatSetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2487 {
2488   PetscFunctionBeginHot;
2489   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2490   PetscValidType(mat, 1);
2491   MatCheckPreallocated(mat, 1);
2492   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2493   PetscAssertPointer(irow, 3);
2494   PetscAssertPointer(icol, 5);
2495   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2496   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2497   if (PetscDefined(USE_DEBUG)) {
2498     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2499     PetscCheck(mat->ops->setvalueslocal || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2500   }
2501 
2502   if (mat->assembled) {
2503     mat->was_assembled = PETSC_TRUE;
2504     mat->assembled     = PETSC_FALSE;
2505   }
2506   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2507   if (mat->ops->setvalueslocal) PetscUseTypeMethod(mat, setvalueslocal, nrow, irow, ncol, icol, y, addv);
2508   else {
2509     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2510     const PetscInt *irowm, *icolm;
2511 
2512     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2513       bufr  = buf;
2514       bufc  = buf + nrow;
2515       irowm = bufr;
2516       icolm = bufc;
2517     } else {
2518       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2519       irowm = bufr;
2520       icolm = bufc;
2521     }
2522     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, bufr));
2523     else irowm = irow;
2524     if (mat->cmap->mapping) {
2525       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, bufc));
2526       else icolm = irowm;
2527     } else icolm = icol;
2528     PetscCall(MatSetValues(mat, nrow, irowm, ncol, icolm, y, addv));
2529     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2530   }
2531   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2532   PetscFunctionReturn(PETSC_SUCCESS);
2533 }
2534 
2535 /*@
2536   MatSetValuesBlockedLocal - Inserts or adds values into certain locations of a matrix,
2537   using a local ordering of the nodes a block at a time.
2538 
2539   Not Collective
2540 
2541   Input Parameters:
2542 + mat  - the matrix
2543 . nrow - number of rows
2544 . irow - the row local indices
2545 . ncol - number of columns
2546 . icol - the column local indices
2547 . y    - a one-dimensional array that contains the values implicitly stored as a two-dimensional array, by default in row-major order.
2548          See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
2549 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2550 
2551   Level: intermediate
2552 
2553   Notes:
2554   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetBlockSize()` and `MatSetLocalToGlobalMapping()`
2555   before using this routineBefore calling `MatSetValuesLocal()`, the user must first set the
2556 
2557   Calls to `MatSetValuesBlockedLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2558   options cannot be mixed without intervening calls to the assembly
2559   routines.
2560 
2561   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2562   MUST be called after all calls to `MatSetValuesBlockedLocal()` have been completed.
2563 
2564   Fortran Notes:
2565   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2566 .vb
2567   call MatSetValuesBlockedLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES, ierr)
2568 .ve
2569 
2570   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2571 
2572 .seealso: [](ch_matrices), `Mat`, `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`,
2573           `MatSetValuesLocal()`, `MatSetValuesBlocked()`
2574 @*/
2575 PetscErrorCode MatSetValuesBlockedLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2576 {
2577   PetscFunctionBeginHot;
2578   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2579   PetscValidType(mat, 1);
2580   MatCheckPreallocated(mat, 1);
2581   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2582   PetscAssertPointer(irow, 3);
2583   PetscAssertPointer(icol, 5);
2584   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2585   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2586   if (PetscDefined(USE_DEBUG)) {
2587     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2588     PetscCheck(mat->ops->setvaluesblockedlocal || mat->ops->setvaluesblocked || mat->ops->setvalueslocal || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2589   }
2590 
2591   if (mat->assembled) {
2592     mat->was_assembled = PETSC_TRUE;
2593     mat->assembled     = PETSC_FALSE;
2594   }
2595   if (PetscUnlikelyDebug(mat->rmap->mapping)) { /* Condition on the mapping existing, because MatSetValuesBlockedLocal_IS does not require it to be set. */
2596     PetscInt irbs, rbs;
2597     PetscCall(MatGetBlockSizes(mat, &rbs, NULL));
2598     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &irbs));
2599     PetscCheck(rbs == irbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different row block sizes! mat %" PetscInt_FMT ", row l2g map %" PetscInt_FMT, rbs, irbs);
2600   }
2601   if (PetscUnlikelyDebug(mat->cmap->mapping)) {
2602     PetscInt icbs, cbs;
2603     PetscCall(MatGetBlockSizes(mat, NULL, &cbs));
2604     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &icbs));
2605     PetscCheck(cbs == icbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different col block sizes! mat %" PetscInt_FMT ", col l2g map %" PetscInt_FMT, cbs, icbs);
2606   }
2607   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2608   if (mat->ops->setvaluesblockedlocal) PetscUseTypeMethod(mat, setvaluesblockedlocal, nrow, irow, ncol, icol, y, addv);
2609   else {
2610     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2611     const PetscInt *irowm, *icolm;
2612 
2613     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= ((PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf))) {
2614       bufr  = buf;
2615       bufc  = buf + nrow;
2616       irowm = bufr;
2617       icolm = bufc;
2618     } else {
2619       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2620       irowm = bufr;
2621       icolm = bufc;
2622     }
2623     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApplyBlock(mat->rmap->mapping, nrow, irow, bufr));
2624     else irowm = irow;
2625     if (mat->cmap->mapping) {
2626       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) PetscCall(ISLocalToGlobalMappingApplyBlock(mat->cmap->mapping, ncol, icol, bufc));
2627       else icolm = irowm;
2628     } else icolm = icol;
2629     PetscCall(MatSetValuesBlocked(mat, nrow, irowm, ncol, icolm, y, addv));
2630     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2631   }
2632   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2633   PetscFunctionReturn(PETSC_SUCCESS);
2634 }
2635 
2636 /*@
2637   MatMultDiagonalBlock - Computes the matrix-vector product, $y = Dx$. Where `D` is defined by the inode or block structure of the diagonal
2638 
2639   Collective
2640 
2641   Input Parameters:
2642 + mat - the matrix
2643 - x   - the vector to be multiplied
2644 
2645   Output Parameter:
2646 . y - the result
2647 
2648   Level: developer
2649 
2650   Note:
2651   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2652   call `MatMultDiagonalBlock`(A,y,y).
2653 
2654 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2655 @*/
2656 PetscErrorCode MatMultDiagonalBlock(Mat mat, Vec x, Vec y)
2657 {
2658   PetscFunctionBegin;
2659   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2660   PetscValidType(mat, 1);
2661   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2662   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2663 
2664   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2665   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2666   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2667   MatCheckPreallocated(mat, 1);
2668 
2669   PetscUseTypeMethod(mat, multdiagonalblock, x, y);
2670   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2671   PetscFunctionReturn(PETSC_SUCCESS);
2672 }
2673 
2674 /*@
2675   MatMult - Computes the matrix-vector product, $y = Ax$.
2676 
2677   Neighbor-wise Collective
2678 
2679   Input Parameters:
2680 + mat - the matrix
2681 - x   - the vector to be multiplied
2682 
2683   Output Parameter:
2684 . y - the result
2685 
2686   Level: beginner
2687 
2688   Note:
2689   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2690   call `MatMult`(A,y,y).
2691 
2692 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2693 @*/
2694 PetscErrorCode MatMult(Mat mat, Vec x, Vec y)
2695 {
2696   PetscFunctionBegin;
2697   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2698   PetscValidType(mat, 1);
2699   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2700   VecCheckAssembled(x);
2701   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2702   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2703   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2704   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2705   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
2706   PetscCheck(mat->rmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, y->map->N);
2707   PetscCheck(mat->cmap->n == x->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->n, x->map->n);
2708   PetscCheck(mat->rmap->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, y->map->n);
2709   PetscCall(VecSetErrorIfLocked(y, 3));
2710   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2711   MatCheckPreallocated(mat, 1);
2712 
2713   PetscCall(VecLockReadPush(x));
2714   PetscCall(PetscLogEventBegin(MAT_Mult, mat, x, y, 0));
2715   PetscUseTypeMethod(mat, mult, x, y);
2716   PetscCall(PetscLogEventEnd(MAT_Mult, mat, x, y, 0));
2717   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2718   PetscCall(VecLockReadPop(x));
2719   PetscFunctionReturn(PETSC_SUCCESS);
2720 }
2721 
2722 /*@
2723   MatMultTranspose - Computes matrix transpose times a vector $y = A^T * x$.
2724 
2725   Neighbor-wise Collective
2726 
2727   Input Parameters:
2728 + mat - the matrix
2729 - x   - the vector to be multiplied
2730 
2731   Output Parameter:
2732 . y - the result
2733 
2734   Level: beginner
2735 
2736   Notes:
2737   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2738   call `MatMultTranspose`(A,y,y).
2739 
2740   For complex numbers this does NOT compute the Hermitian (complex conjugate) transpose multiple,
2741   use `MatMultHermitianTranspose()`
2742 
2743 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatMultHermitianTranspose()`, `MatTranspose()`
2744 @*/
2745 PetscErrorCode MatMultTranspose(Mat mat, Vec x, Vec y)
2746 {
2747   PetscErrorCode (*op)(Mat, Vec, Vec) = NULL;
2748 
2749   PetscFunctionBegin;
2750   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2751   PetscValidType(mat, 1);
2752   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2753   VecCheckAssembled(x);
2754   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2755 
2756   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2757   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2758   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2759   PetscCheck(mat->cmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, y->map->N);
2760   PetscCheck(mat->rmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, x->map->N);
2761   PetscCheck(mat->cmap->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->n, y->map->n);
2762   PetscCheck(mat->rmap->n == x->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, x->map->n);
2763   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2764   MatCheckPreallocated(mat, 1);
2765 
2766   if (!mat->ops->multtranspose) {
2767     if (mat->symmetric == PETSC_BOOL3_TRUE && mat->ops->mult) op = mat->ops->mult;
2768     PetscCheck(op, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Matrix type %s does not have a multiply transpose defined or is symmetric and does not have a multiply defined", ((PetscObject)mat)->type_name);
2769   } else op = mat->ops->multtranspose;
2770   PetscCall(PetscLogEventBegin(MAT_MultTranspose, mat, x, y, 0));
2771   PetscCall(VecLockReadPush(x));
2772   PetscCall((*op)(mat, x, y));
2773   PetscCall(VecLockReadPop(x));
2774   PetscCall(PetscLogEventEnd(MAT_MultTranspose, mat, x, y, 0));
2775   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2776   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2777   PetscFunctionReturn(PETSC_SUCCESS);
2778 }
2779 
2780 /*@
2781   MatMultHermitianTranspose - Computes matrix Hermitian-transpose times a vector $y = A^H * x$.
2782 
2783   Neighbor-wise Collective
2784 
2785   Input Parameters:
2786 + mat - the matrix
2787 - x   - the vector to be multiplied
2788 
2789   Output Parameter:
2790 . y - the result
2791 
2792   Level: beginner
2793 
2794   Notes:
2795   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2796   call `MatMultHermitianTranspose`(A,y,y).
2797 
2798   Also called the conjugate transpose, complex conjugate transpose, or adjoint.
2799 
2800   For real numbers `MatMultTranspose()` and `MatMultHermitianTranspose()` are identical.
2801 
2802 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultHermitianTransposeAdd()`, `MatMultTranspose()`
2803 @*/
2804 PetscErrorCode MatMultHermitianTranspose(Mat mat, Vec x, Vec y)
2805 {
2806   PetscFunctionBegin;
2807   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2808   PetscValidType(mat, 1);
2809   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2810   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2811 
2812   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2813   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2814   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2815   PetscCheck(mat->cmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, y->map->N);
2816   PetscCheck(mat->rmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, x->map->N);
2817   PetscCheck(mat->cmap->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->n, y->map->n);
2818   PetscCheck(mat->rmap->n == x->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, x->map->n);
2819   MatCheckPreallocated(mat, 1);
2820 
2821   PetscCall(PetscLogEventBegin(MAT_MultHermitianTranspose, mat, x, y, 0));
2822 #if defined(PETSC_USE_COMPLEX)
2823   if (mat->ops->multhermitiantranspose || (mat->hermitian == PETSC_BOOL3_TRUE && mat->ops->mult)) {
2824     PetscCall(VecLockReadPush(x));
2825     if (mat->ops->multhermitiantranspose) PetscUseTypeMethod(mat, multhermitiantranspose, x, y);
2826     else PetscUseTypeMethod(mat, mult, x, y);
2827     PetscCall(VecLockReadPop(x));
2828   } else {
2829     Vec w;
2830     PetscCall(VecDuplicate(x, &w));
2831     PetscCall(VecCopy(x, w));
2832     PetscCall(VecConjugate(w));
2833     PetscCall(MatMultTranspose(mat, w, y));
2834     PetscCall(VecDestroy(&w));
2835     PetscCall(VecConjugate(y));
2836   }
2837   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2838 #else
2839   PetscCall(MatMultTranspose(mat, x, y));
2840 #endif
2841   PetscCall(PetscLogEventEnd(MAT_MultHermitianTranspose, mat, x, y, 0));
2842   PetscFunctionReturn(PETSC_SUCCESS);
2843 }
2844 
2845 /*@
2846   MatMultAdd -  Computes $v3 = v2 + A * v1$.
2847 
2848   Neighbor-wise Collective
2849 
2850   Input Parameters:
2851 + mat - the matrix
2852 . v1  - the vector to be multiplied by `mat`
2853 - v2  - the vector to be added to the result
2854 
2855   Output Parameter:
2856 . v3 - the result
2857 
2858   Level: beginner
2859 
2860   Note:
2861   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2862   call `MatMultAdd`(A,v1,v2,v1).
2863 
2864 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMult()`, `MatMultTransposeAdd()`
2865 @*/
2866 PetscErrorCode MatMultAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2867 {
2868   PetscFunctionBegin;
2869   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2870   PetscValidType(mat, 1);
2871   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2872   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2873   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2874 
2875   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2876   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2877   PetscCheck(mat->cmap->N == v1->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v1: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v1->map->N);
2878   /* PetscCheck(mat->rmap->N == v2->map->N,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Mat mat,Vec v2: global dim %" PetscInt_FMT " %" PetscInt_FMT,mat->rmap->N,v2->map->N);
2879      PetscCheck(mat->rmap->N == v3->map->N,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Mat mat,Vec v3: global dim %" PetscInt_FMT " %" PetscInt_FMT,mat->rmap->N,v3->map->N); */
2880   PetscCheck(mat->rmap->n == v3->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec v3: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, v3->map->n);
2881   PetscCheck(mat->rmap->n == v2->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec v2: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, v2->map->n);
2882   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2883   MatCheckPreallocated(mat, 1);
2884 
2885   PetscCall(PetscLogEventBegin(MAT_MultAdd, mat, v1, v2, v3));
2886   PetscCall(VecLockReadPush(v1));
2887   PetscUseTypeMethod(mat, multadd, v1, v2, v3);
2888   PetscCall(VecLockReadPop(v1));
2889   PetscCall(PetscLogEventEnd(MAT_MultAdd, mat, v1, v2, v3));
2890   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2891   PetscFunctionReturn(PETSC_SUCCESS);
2892 }
2893 
2894 /*@
2895   MatMultTransposeAdd - Computes $v3 = v2 + A^T * v1$.
2896 
2897   Neighbor-wise Collective
2898 
2899   Input Parameters:
2900 + mat - the matrix
2901 . v1  - the vector to be multiplied by the transpose of the matrix
2902 - v2  - the vector to be added to the result
2903 
2904   Output Parameter:
2905 . v3 - the result
2906 
2907   Level: beginner
2908 
2909   Note:
2910   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2911   call `MatMultTransposeAdd`(A,v1,v2,v1).
2912 
2913 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2914 @*/
2915 PetscErrorCode MatMultTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2916 {
2917   PetscErrorCode (*op)(Mat, Vec, Vec, Vec) = (!mat->ops->multtransposeadd && mat->symmetric) ? mat->ops->multadd : mat->ops->multtransposeadd;
2918 
2919   PetscFunctionBegin;
2920   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2921   PetscValidType(mat, 1);
2922   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2923   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2924   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2925 
2926   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2927   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2928   PetscCheck(mat->rmap->N == v1->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v1: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, v1->map->N);
2929   PetscCheck(mat->cmap->N == v2->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v2: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v2->map->N);
2930   PetscCheck(mat->cmap->N == v3->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v3: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v3->map->N);
2931   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2932   PetscCheck(op, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2933   MatCheckPreallocated(mat, 1);
2934 
2935   PetscCall(PetscLogEventBegin(MAT_MultTransposeAdd, mat, v1, v2, v3));
2936   PetscCall(VecLockReadPush(v1));
2937   PetscCall((*op)(mat, v1, v2, v3));
2938   PetscCall(VecLockReadPop(v1));
2939   PetscCall(PetscLogEventEnd(MAT_MultTransposeAdd, mat, v1, v2, v3));
2940   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2941   PetscFunctionReturn(PETSC_SUCCESS);
2942 }
2943 
2944 /*@
2945   MatMultHermitianTransposeAdd - Computes $v3 = v2 + A^H * v1$.
2946 
2947   Neighbor-wise Collective
2948 
2949   Input Parameters:
2950 + mat - the matrix
2951 . v1  - the vector to be multiplied by the Hermitian transpose
2952 - v2  - the vector to be added to the result
2953 
2954   Output Parameter:
2955 . v3 - the result
2956 
2957   Level: beginner
2958 
2959   Note:
2960   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2961   call `MatMultHermitianTransposeAdd`(A,v1,v2,v1).
2962 
2963 .seealso: [](ch_matrices), `Mat`, `MatMultHermitianTranspose()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2964 @*/
2965 PetscErrorCode MatMultHermitianTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2966 {
2967   PetscFunctionBegin;
2968   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2969   PetscValidType(mat, 1);
2970   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2971   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2972   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2973 
2974   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2975   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2976   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2977   PetscCheck(mat->rmap->N == v1->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v1: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, v1->map->N);
2978   PetscCheck(mat->cmap->N == v2->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v2: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v2->map->N);
2979   PetscCheck(mat->cmap->N == v3->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v3: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v3->map->N);
2980   MatCheckPreallocated(mat, 1);
2981 
2982   PetscCall(PetscLogEventBegin(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
2983   PetscCall(VecLockReadPush(v1));
2984   if (mat->ops->multhermitiantransposeadd) PetscUseTypeMethod(mat, multhermitiantransposeadd, v1, v2, v3);
2985   else {
2986     Vec w, z;
2987     PetscCall(VecDuplicate(v1, &w));
2988     PetscCall(VecCopy(v1, w));
2989     PetscCall(VecConjugate(w));
2990     PetscCall(VecDuplicate(v3, &z));
2991     PetscCall(MatMultTranspose(mat, w, z));
2992     PetscCall(VecDestroy(&w));
2993     PetscCall(VecConjugate(z));
2994     if (v2 != v3) {
2995       PetscCall(VecWAXPY(v3, 1.0, v2, z));
2996     } else {
2997       PetscCall(VecAXPY(v3, 1.0, z));
2998     }
2999     PetscCall(VecDestroy(&z));
3000   }
3001   PetscCall(VecLockReadPop(v1));
3002   PetscCall(PetscLogEventEnd(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
3003   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
3004   PetscFunctionReturn(PETSC_SUCCESS);
3005 }
3006 
3007 /*@
3008   MatGetFactorType - gets the type of factorization a matrix is
3009 
3010   Not Collective
3011 
3012   Input Parameter:
3013 . mat - the matrix
3014 
3015   Output Parameter:
3016 . t - the type, one of `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`, `MAT_FACTOR_ICC,MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3017 
3018   Level: intermediate
3019 
3020 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatSetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3021           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3022 @*/
3023 PetscErrorCode MatGetFactorType(Mat mat, MatFactorType *t)
3024 {
3025   PetscFunctionBegin;
3026   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3027   PetscValidType(mat, 1);
3028   PetscAssertPointer(t, 2);
3029   *t = mat->factortype;
3030   PetscFunctionReturn(PETSC_SUCCESS);
3031 }
3032 
3033 /*@
3034   MatSetFactorType - sets the type of factorization a matrix is
3035 
3036   Logically Collective
3037 
3038   Input Parameters:
3039 + mat - the matrix
3040 - t   - the type, one of `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`, `MAT_FACTOR_ICC,MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3041 
3042   Level: intermediate
3043 
3044 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatGetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3045           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3046 @*/
3047 PetscErrorCode MatSetFactorType(Mat mat, MatFactorType t)
3048 {
3049   PetscFunctionBegin;
3050   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3051   PetscValidType(mat, 1);
3052   mat->factortype = t;
3053   PetscFunctionReturn(PETSC_SUCCESS);
3054 }
3055 
3056 /*@
3057   MatGetInfo - Returns information about matrix storage (number of
3058   nonzeros, memory, etc.).
3059 
3060   Collective if `MAT_GLOBAL_MAX` or `MAT_GLOBAL_SUM` is used as the flag
3061 
3062   Input Parameters:
3063 + mat  - the matrix
3064 - flag - flag indicating the type of parameters to be returned (`MAT_LOCAL` - local matrix, `MAT_GLOBAL_MAX` - maximum over all processors, `MAT_GLOBAL_SUM` - sum over all processors)
3065 
3066   Output Parameter:
3067 . info - matrix information context
3068 
3069   Options Database Key:
3070 . -mat_view ::ascii_info - print matrix info to `PETSC_STDOUT`
3071 
3072   Level: intermediate
3073 
3074   Notes:
3075   The `MatInfo` context contains a variety of matrix data, including
3076   number of nonzeros allocated and used, number of mallocs during
3077   matrix assembly, etc.  Additional information for factored matrices
3078   is provided (such as the fill ratio, number of mallocs during
3079   factorization, etc.).
3080 
3081   Example:
3082   See the file ${PETSC_DIR}/include/petscmat.h for a complete list of
3083   data within the `MatInfo` context.  For example,
3084 .vb
3085       MatInfo info;
3086       Mat     A;
3087       double  mal, nz_a, nz_u;
3088 
3089       MatGetInfo(A, MAT_LOCAL, &info);
3090       mal  = info.mallocs;
3091       nz_a = info.nz_allocated;
3092 .ve
3093 
3094 .seealso: [](ch_matrices), `Mat`, `MatInfo`, `MatStashGetInfo()`
3095 @*/
3096 PetscErrorCode MatGetInfo(Mat mat, MatInfoType flag, MatInfo *info)
3097 {
3098   PetscFunctionBegin;
3099   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3100   PetscValidType(mat, 1);
3101   PetscAssertPointer(info, 3);
3102   MatCheckPreallocated(mat, 1);
3103   PetscUseTypeMethod(mat, getinfo, flag, info);
3104   PetscFunctionReturn(PETSC_SUCCESS);
3105 }
3106 
3107 /*
3108    This is used by external packages where it is not easy to get the info from the actual
3109    matrix factorization.
3110 */
3111 PetscErrorCode MatGetInfo_External(Mat A, MatInfoType flag, MatInfo *info)
3112 {
3113   PetscFunctionBegin;
3114   PetscCall(PetscMemzero(info, sizeof(MatInfo)));
3115   PetscFunctionReturn(PETSC_SUCCESS);
3116 }
3117 
3118 /*@
3119   MatLUFactor - Performs in-place LU factorization of matrix.
3120 
3121   Collective
3122 
3123   Input Parameters:
3124 + mat  - the matrix
3125 . row  - row permutation
3126 . col  - column permutation
3127 - info - options for factorization, includes
3128 .vb
3129           fill - expected fill as ratio of original fill.
3130           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3131                    Run with the option -info to determine an optimal value to use
3132 .ve
3133 
3134   Level: developer
3135 
3136   Notes:
3137   Most users should employ the `KSP` interface for linear solvers
3138   instead of working directly with matrix algebra routines such as this.
3139   See, e.g., `KSPCreate()`.
3140 
3141   This changes the state of the matrix to a factored matrix; it cannot be used
3142   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3143 
3144   This is really in-place only for dense matrices, the preferred approach is to use `MatGetFactor()`, `MatLUFactorSymbolic()`, and `MatLUFactorNumeric()`
3145   when not using `KSP`.
3146 
3147   Fortran Note:
3148   A valid (non-null) `info` argument must be provided
3149 
3150 .seealso: [](ch_matrices), [Matrix Factorization](sec_matfactor), `Mat`, `MatFactorType`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`,
3151           `MatGetOrdering()`, `MatSetUnfactored()`, `MatFactorInfo`, `MatGetFactor()`
3152 @*/
3153 PetscErrorCode MatLUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3154 {
3155   MatFactorInfo tinfo;
3156 
3157   PetscFunctionBegin;
3158   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3159   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3160   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3161   if (info) PetscAssertPointer(info, 4);
3162   PetscValidType(mat, 1);
3163   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3164   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3165   MatCheckPreallocated(mat, 1);
3166   if (!info) {
3167     PetscCall(MatFactorInfoInitialize(&tinfo));
3168     info = &tinfo;
3169   }
3170 
3171   PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, row, col, 0));
3172   PetscUseTypeMethod(mat, lufactor, row, col, info);
3173   PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, row, col, 0));
3174   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3175   PetscFunctionReturn(PETSC_SUCCESS);
3176 }
3177 
3178 /*@
3179   MatILUFactor - Performs in-place ILU factorization of matrix.
3180 
3181   Collective
3182 
3183   Input Parameters:
3184 + mat  - the matrix
3185 . row  - row permutation
3186 . col  - column permutation
3187 - info - structure containing
3188 .vb
3189       levels - number of levels of fill.
3190       expected fill - as ratio of original fill.
3191       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
3192                 missing diagonal entries)
3193 .ve
3194 
3195   Level: developer
3196 
3197   Notes:
3198   Most users should employ the `KSP` interface for linear solvers
3199   instead of working directly with matrix algebra routines such as this.
3200   See, e.g., `KSPCreate()`.
3201 
3202   Probably really in-place only when level of fill is zero, otherwise allocates
3203   new space to store factored matrix and deletes previous memory. The preferred approach is to use `MatGetFactor()`, `MatILUFactorSymbolic()`, and `MatILUFactorNumeric()`
3204   when not using `KSP`.
3205 
3206   Fortran Note:
3207   A valid (non-null) `info` argument must be provided
3208 
3209 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatILUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
3210 @*/
3211 PetscErrorCode MatILUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3212 {
3213   PetscFunctionBegin;
3214   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3215   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3216   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3217   PetscAssertPointer(info, 4);
3218   PetscValidType(mat, 1);
3219   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
3220   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3221   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3222   MatCheckPreallocated(mat, 1);
3223 
3224   PetscCall(PetscLogEventBegin(MAT_ILUFactor, mat, row, col, 0));
3225   PetscUseTypeMethod(mat, ilufactor, row, col, info);
3226   PetscCall(PetscLogEventEnd(MAT_ILUFactor, mat, row, col, 0));
3227   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3228   PetscFunctionReturn(PETSC_SUCCESS);
3229 }
3230 
3231 /*@
3232   MatLUFactorSymbolic - Performs symbolic LU factorization of matrix.
3233   Call this routine before calling `MatLUFactorNumeric()` and after `MatGetFactor()`.
3234 
3235   Collective
3236 
3237   Input Parameters:
3238 + fact - the factor matrix obtained with `MatGetFactor()`
3239 . mat  - the matrix
3240 . row  - the row permutation
3241 . col  - the column permutation
3242 - info - options for factorization, includes
3243 .vb
3244           fill - expected fill as ratio of original fill. Run with the option -info to determine an optimal value to use
3245           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3246 .ve
3247 
3248   Level: developer
3249 
3250   Notes:
3251   See [Matrix Factorization](sec_matfactor) for additional information about factorizations
3252 
3253   Most users should employ the simplified `KSP` interface for linear solvers
3254   instead of working directly with matrix algebra routines such as this.
3255   See, e.g., `KSPCreate()`.
3256 
3257   Fortran Note:
3258   A valid (non-null) `info` argument must be provided
3259 
3260 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`, `MatFactorInfoInitialize()`
3261 @*/
3262 PetscErrorCode MatLUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
3263 {
3264   MatFactorInfo tinfo;
3265 
3266   PetscFunctionBegin;
3267   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3268   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3269   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
3270   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
3271   if (info) PetscAssertPointer(info, 5);
3272   PetscValidType(fact, 1);
3273   PetscValidType(mat, 2);
3274   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3275   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3276   MatCheckPreallocated(mat, 2);
3277   if (!info) {
3278     PetscCall(MatFactorInfoInitialize(&tinfo));
3279     info = &tinfo;
3280   }
3281 
3282   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorSymbolic, mat, row, col, 0));
3283   PetscUseTypeMethod(fact, lufactorsymbolic, mat, row, col, info);
3284   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorSymbolic, mat, row, col, 0));
3285   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3286   PetscFunctionReturn(PETSC_SUCCESS);
3287 }
3288 
3289 /*@
3290   MatLUFactorNumeric - Performs numeric LU factorization of a matrix.
3291   Call this routine after first calling `MatLUFactorSymbolic()` and `MatGetFactor()`.
3292 
3293   Collective
3294 
3295   Input Parameters:
3296 + fact - the factor matrix obtained with `MatGetFactor()`
3297 . mat  - the matrix
3298 - info - options for factorization
3299 
3300   Level: developer
3301 
3302   Notes:
3303   See `MatLUFactor()` for in-place factorization.  See
3304   `MatCholeskyFactorNumeric()` for the symmetric, positive definite case.
3305 
3306   Most users should employ the `KSP` interface for linear solvers
3307   instead of working directly with matrix algebra routines such as this.
3308   See, e.g., `KSPCreate()`.
3309 
3310   Fortran Note:
3311   A valid (non-null) `info` argument must be provided
3312 
3313 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactorSymbolic()`, `MatLUFactor()`, `MatCholeskyFactor()`
3314 @*/
3315 PetscErrorCode MatLUFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3316 {
3317   MatFactorInfo tinfo;
3318 
3319   PetscFunctionBegin;
3320   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3321   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3322   PetscValidType(fact, 1);
3323   PetscValidType(mat, 2);
3324   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3325   PetscCheck(mat->rmap->N == (fact)->rmap->N && mat->cmap->N == (fact)->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Mat fact: global dimensions are different %" PetscInt_FMT " should = %" PetscInt_FMT " %" PetscInt_FMT " should = %" PetscInt_FMT,
3326              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3327 
3328   MatCheckPreallocated(mat, 2);
3329   if (!info) {
3330     PetscCall(MatFactorInfoInitialize(&tinfo));
3331     info = &tinfo;
3332   }
3333 
3334   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorNumeric, mat, fact, 0, 0));
3335   else PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, fact, 0, 0));
3336   PetscUseTypeMethod(fact, lufactornumeric, mat, info);
3337   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorNumeric, mat, fact, 0, 0));
3338   else PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, fact, 0, 0));
3339   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3340   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3341   PetscFunctionReturn(PETSC_SUCCESS);
3342 }
3343 
3344 /*@
3345   MatCholeskyFactor - Performs in-place Cholesky factorization of a
3346   symmetric matrix.
3347 
3348   Collective
3349 
3350   Input Parameters:
3351 + mat  - the matrix
3352 . perm - row and column permutations
3353 - info - expected fill as ratio of original fill
3354 
3355   Level: developer
3356 
3357   Notes:
3358   See `MatLUFactor()` for the nonsymmetric case.  See also `MatGetFactor()`,
3359   `MatCholeskyFactorSymbolic()`, and `MatCholeskyFactorNumeric()`.
3360 
3361   Most users should employ the `KSP` interface for linear solvers
3362   instead of working directly with matrix algebra routines such as this.
3363   See, e.g., `KSPCreate()`.
3364 
3365   Fortran Note:
3366   A valid (non-null) `info` argument must be provided
3367 
3368 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactorNumeric()`
3369           `MatGetOrdering()`
3370 @*/
3371 PetscErrorCode MatCholeskyFactor(Mat mat, IS perm, const MatFactorInfo *info)
3372 {
3373   MatFactorInfo tinfo;
3374 
3375   PetscFunctionBegin;
3376   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3377   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 2);
3378   if (info) PetscAssertPointer(info, 3);
3379   PetscValidType(mat, 1);
3380   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3381   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3382   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3383   MatCheckPreallocated(mat, 1);
3384   if (!info) {
3385     PetscCall(MatFactorInfoInitialize(&tinfo));
3386     info = &tinfo;
3387   }
3388 
3389   PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, perm, 0, 0));
3390   PetscUseTypeMethod(mat, choleskyfactor, perm, info);
3391   PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, perm, 0, 0));
3392   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3393   PetscFunctionReturn(PETSC_SUCCESS);
3394 }
3395 
3396 /*@
3397   MatCholeskyFactorSymbolic - Performs symbolic Cholesky factorization
3398   of a symmetric matrix.
3399 
3400   Collective
3401 
3402   Input Parameters:
3403 + fact - the factor matrix obtained with `MatGetFactor()`
3404 . mat  - the matrix
3405 . perm - row and column permutations
3406 - info - options for factorization, includes
3407 .vb
3408           fill - expected fill as ratio of original fill.
3409           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3410                    Run with the option -info to determine an optimal value to use
3411 .ve
3412 
3413   Level: developer
3414 
3415   Notes:
3416   See `MatLUFactorSymbolic()` for the nonsymmetric case.  See also
3417   `MatCholeskyFactor()` and `MatCholeskyFactorNumeric()`.
3418 
3419   Most users should employ the `KSP` interface for linear solvers
3420   instead of working directly with matrix algebra routines such as this.
3421   See, e.g., `KSPCreate()`.
3422 
3423   Fortran Note:
3424   A valid (non-null) `info` argument must be provided
3425 
3426 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactor()`, `MatCholeskyFactorNumeric()`
3427           `MatGetOrdering()`
3428 @*/
3429 PetscErrorCode MatCholeskyFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
3430 {
3431   MatFactorInfo tinfo;
3432 
3433   PetscFunctionBegin;
3434   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3435   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3436   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
3437   if (info) PetscAssertPointer(info, 4);
3438   PetscValidType(fact, 1);
3439   PetscValidType(mat, 2);
3440   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3441   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3442   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3443   MatCheckPreallocated(mat, 2);
3444   if (!info) {
3445     PetscCall(MatFactorInfoInitialize(&tinfo));
3446     info = &tinfo;
3447   }
3448 
3449   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3450   PetscUseTypeMethod(fact, choleskyfactorsymbolic, mat, perm, info);
3451   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3452   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3453   PetscFunctionReturn(PETSC_SUCCESS);
3454 }
3455 
3456 /*@
3457   MatCholeskyFactorNumeric - Performs numeric Cholesky factorization
3458   of a symmetric matrix. Call this routine after first calling `MatGetFactor()` and
3459   `MatCholeskyFactorSymbolic()`.
3460 
3461   Collective
3462 
3463   Input Parameters:
3464 + fact - the factor matrix obtained with `MatGetFactor()`, where the factored values are stored
3465 . mat  - the initial matrix that is to be factored
3466 - info - options for factorization
3467 
3468   Level: developer
3469 
3470   Note:
3471   Most users should employ the `KSP` interface for linear solvers
3472   instead of working directly with matrix algebra routines such as this.
3473   See, e.g., `KSPCreate()`.
3474 
3475   Fortran Note:
3476   A valid (non-null) `info` argument must be provided
3477 
3478 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactor()`, `MatLUFactorNumeric()`
3479 @*/
3480 PetscErrorCode MatCholeskyFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3481 {
3482   MatFactorInfo tinfo;
3483 
3484   PetscFunctionBegin;
3485   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3486   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3487   PetscValidType(fact, 1);
3488   PetscValidType(mat, 2);
3489   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3490   PetscCheck(mat->rmap->N == (fact)->rmap->N && mat->cmap->N == (fact)->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Mat fact: global dim %" PetscInt_FMT " should = %" PetscInt_FMT " %" PetscInt_FMT " should = %" PetscInt_FMT,
3491              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3492   MatCheckPreallocated(mat, 2);
3493   if (!info) {
3494     PetscCall(MatFactorInfoInitialize(&tinfo));
3495     info = &tinfo;
3496   }
3497 
3498   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3499   else PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, fact, 0, 0));
3500   PetscUseTypeMethod(fact, choleskyfactornumeric, mat, info);
3501   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3502   else PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, fact, 0, 0));
3503   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3504   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3505   PetscFunctionReturn(PETSC_SUCCESS);
3506 }
3507 
3508 /*@
3509   MatQRFactor - Performs in-place QR factorization of matrix.
3510 
3511   Collective
3512 
3513   Input Parameters:
3514 + mat  - the matrix
3515 . col  - column permutation
3516 - info - options for factorization, includes
3517 .vb
3518           fill - expected fill as ratio of original fill.
3519           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3520                    Run with the option -info to determine an optimal value to use
3521 .ve
3522 
3523   Level: developer
3524 
3525   Notes:
3526   Most users should employ the `KSP` interface for linear solvers
3527   instead of working directly with matrix algebra routines such as this.
3528   See, e.g., `KSPCreate()`.
3529 
3530   This changes the state of the matrix to a factored matrix; it cannot be used
3531   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3532 
3533   Fortran Note:
3534   A valid (non-null) `info` argument must be provided
3535 
3536 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactorSymbolic()`, `MatQRFactorNumeric()`, `MatLUFactor()`,
3537           `MatSetUnfactored()`
3538 @*/
3539 PetscErrorCode MatQRFactor(Mat mat, IS col, const MatFactorInfo *info)
3540 {
3541   PetscFunctionBegin;
3542   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3543   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 2);
3544   if (info) PetscAssertPointer(info, 3);
3545   PetscValidType(mat, 1);
3546   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3547   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3548   MatCheckPreallocated(mat, 1);
3549   PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, col, 0, 0));
3550   PetscUseMethod(mat, "MatQRFactor_C", (Mat, IS, const MatFactorInfo *), (mat, col, info));
3551   PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, col, 0, 0));
3552   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3553   PetscFunctionReturn(PETSC_SUCCESS);
3554 }
3555 
3556 /*@
3557   MatQRFactorSymbolic - Performs symbolic QR factorization of matrix.
3558   Call this routine after `MatGetFactor()` but before calling `MatQRFactorNumeric()`.
3559 
3560   Collective
3561 
3562   Input Parameters:
3563 + fact - the factor matrix obtained with `MatGetFactor()`
3564 . mat  - the matrix
3565 . col  - column permutation
3566 - info - options for factorization, includes
3567 .vb
3568           fill - expected fill as ratio of original fill.
3569           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3570                    Run with the option -info to determine an optimal value to use
3571 .ve
3572 
3573   Level: developer
3574 
3575   Note:
3576   Most users should employ the `KSP` interface for linear solvers
3577   instead of working directly with matrix algebra routines such as this.
3578   See, e.g., `KSPCreate()`.
3579 
3580   Fortran Note:
3581   A valid (non-null) `info` argument must be provided
3582 
3583 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatQRFactor()`, `MatQRFactorNumeric()`, `MatLUFactor()`, `MatFactorInfoInitialize()`
3584 @*/
3585 PetscErrorCode MatQRFactorSymbolic(Mat fact, Mat mat, IS col, const MatFactorInfo *info)
3586 {
3587   MatFactorInfo tinfo;
3588 
3589   PetscFunctionBegin;
3590   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3591   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3592   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3593   if (info) PetscAssertPointer(info, 4);
3594   PetscValidType(fact, 1);
3595   PetscValidType(mat, 2);
3596   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3597   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3598   MatCheckPreallocated(mat, 2);
3599   if (!info) {
3600     PetscCall(MatFactorInfoInitialize(&tinfo));
3601     info = &tinfo;
3602   }
3603 
3604   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorSymbolic, fact, mat, col, 0));
3605   PetscUseMethod(fact, "MatQRFactorSymbolic_C", (Mat, Mat, IS, const MatFactorInfo *), (fact, mat, col, info));
3606   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorSymbolic, fact, mat, col, 0));
3607   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3608   PetscFunctionReturn(PETSC_SUCCESS);
3609 }
3610 
3611 /*@
3612   MatQRFactorNumeric - Performs numeric QR factorization of a matrix.
3613   Call this routine after first calling `MatGetFactor()`, and `MatQRFactorSymbolic()`.
3614 
3615   Collective
3616 
3617   Input Parameters:
3618 + fact - the factor matrix obtained with `MatGetFactor()`
3619 . mat  - the matrix
3620 - info - options for factorization
3621 
3622   Level: developer
3623 
3624   Notes:
3625   See `MatQRFactor()` for in-place factorization.
3626 
3627   Most users should employ the `KSP` interface for linear solvers
3628   instead of working directly with matrix algebra routines such as this.
3629   See, e.g., `KSPCreate()`.
3630 
3631   Fortran Note:
3632   A valid (non-null) `info` argument must be provided
3633 
3634 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactor()`, `MatQRFactorSymbolic()`, `MatLUFactor()`
3635 @*/
3636 PetscErrorCode MatQRFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3637 {
3638   MatFactorInfo tinfo;
3639 
3640   PetscFunctionBegin;
3641   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3642   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3643   PetscValidType(fact, 1);
3644   PetscValidType(mat, 2);
3645   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3646   PetscCheck(mat->rmap->N == fact->rmap->N && mat->cmap->N == fact->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Mat fact: global dimensions are different %" PetscInt_FMT " should = %" PetscInt_FMT " %" PetscInt_FMT " should = %" PetscInt_FMT,
3647              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3648 
3649   MatCheckPreallocated(mat, 2);
3650   if (!info) {
3651     PetscCall(MatFactorInfoInitialize(&tinfo));
3652     info = &tinfo;
3653   }
3654 
3655   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorNumeric, mat, fact, 0, 0));
3656   else PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, fact, 0, 0));
3657   PetscUseMethod(fact, "MatQRFactorNumeric_C", (Mat, Mat, const MatFactorInfo *), (fact, mat, info));
3658   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorNumeric, mat, fact, 0, 0));
3659   else PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, fact, 0, 0));
3660   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3661   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3662   PetscFunctionReturn(PETSC_SUCCESS);
3663 }
3664 
3665 /*@
3666   MatSolve - Solves $A x = b$, given a factored matrix.
3667 
3668   Neighbor-wise Collective
3669 
3670   Input Parameters:
3671 + mat - the factored matrix
3672 - b   - the right-hand-side vector
3673 
3674   Output Parameter:
3675 . x - the result vector
3676 
3677   Level: developer
3678 
3679   Notes:
3680   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3681   call `MatSolve`(A,x,x).
3682 
3683   Most users should employ the `KSP` interface for linear solvers
3684   instead of working directly with matrix algebra routines such as this.
3685   See, e.g., `KSPCreate()`.
3686 
3687 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
3688 @*/
3689 PetscErrorCode MatSolve(Mat mat, Vec b, Vec x)
3690 {
3691   PetscFunctionBegin;
3692   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3693   PetscValidType(mat, 1);
3694   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3695   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3696   PetscCheckSameComm(mat, 1, b, 2);
3697   PetscCheckSameComm(mat, 1, x, 3);
3698   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3699   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
3700   PetscCheck(mat->rmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, b->map->N);
3701   PetscCheck(mat->rmap->n == b->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, b->map->n);
3702   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3703   MatCheckPreallocated(mat, 1);
3704 
3705   PetscCall(PetscLogEventBegin(MAT_Solve, mat, b, x, 0));
3706   PetscCall(VecFlag(x, mat->factorerrortype));
3707   if (mat->factorerrortype) PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
3708   else PetscUseTypeMethod(mat, solve, b, x);
3709   PetscCall(PetscLogEventEnd(MAT_Solve, mat, b, x, 0));
3710   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3711   PetscFunctionReturn(PETSC_SUCCESS);
3712 }
3713 
3714 static PetscErrorCode MatMatSolve_Basic(Mat A, Mat B, Mat X, PetscBool trans)
3715 {
3716   Vec      b, x;
3717   PetscInt N, i;
3718   PetscErrorCode (*f)(Mat, Vec, Vec);
3719   PetscBool Abound, Bneedconv = PETSC_FALSE, Xneedconv = PETSC_FALSE;
3720 
3721   PetscFunctionBegin;
3722   if (A->factorerrortype) {
3723     PetscCall(PetscInfo(A, "MatFactorError %d\n", A->factorerrortype));
3724     PetscCall(MatSetInf(X));
3725     PetscFunctionReturn(PETSC_SUCCESS);
3726   }
3727   f = (!trans || (!A->ops->solvetranspose && A->symmetric)) ? A->ops->solve : A->ops->solvetranspose;
3728   PetscCheck(f, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)A)->type_name);
3729   PetscCall(MatBoundToCPU(A, &Abound));
3730   if (!Abound) {
3731     PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &Bneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3732     PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &Xneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3733   }
3734 #if PetscDefined(HAVE_CUDA)
3735   if (Bneedconv) PetscCall(MatConvert(B, MATDENSECUDA, MAT_INPLACE_MATRIX, &B));
3736   if (Xneedconv) PetscCall(MatConvert(X, MATDENSECUDA, MAT_INPLACE_MATRIX, &X));
3737 #elif PetscDefined(HAVE_HIP)
3738   if (Bneedconv) PetscCall(MatConvert(B, MATDENSEHIP, MAT_INPLACE_MATRIX, &B));
3739   if (Xneedconv) PetscCall(MatConvert(X, MATDENSEHIP, MAT_INPLACE_MATRIX, &X));
3740 #endif
3741   PetscCall(MatGetSize(B, NULL, &N));
3742   for (i = 0; i < N; i++) {
3743     PetscCall(MatDenseGetColumnVecRead(B, i, &b));
3744     PetscCall(MatDenseGetColumnVecWrite(X, i, &x));
3745     PetscCall((*f)(A, b, x));
3746     PetscCall(MatDenseRestoreColumnVecWrite(X, i, &x));
3747     PetscCall(MatDenseRestoreColumnVecRead(B, i, &b));
3748   }
3749   if (Bneedconv) PetscCall(MatConvert(B, MATDENSE, MAT_INPLACE_MATRIX, &B));
3750   if (Xneedconv) PetscCall(MatConvert(X, MATDENSE, MAT_INPLACE_MATRIX, &X));
3751   PetscFunctionReturn(PETSC_SUCCESS);
3752 }
3753 
3754 /*@
3755   MatMatSolve - Solves $A X = B$, given a factored matrix.
3756 
3757   Neighbor-wise Collective
3758 
3759   Input Parameters:
3760 + A - the factored matrix
3761 - B - the right-hand-side matrix `MATDENSE` (or sparse `MATAIJ`-- when using MUMPS)
3762 
3763   Output Parameter:
3764 . X - the result matrix (dense matrix)
3765 
3766   Level: developer
3767 
3768   Note:
3769   If `B` is a `MATDENSE` matrix then one can call `MatMatSolve`(A,B,B) except with `MATSOLVERMKL_CPARDISO`;
3770   otherwise, `B` and `X` cannot be the same.
3771 
3772 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3773 @*/
3774 PetscErrorCode MatMatSolve(Mat A, Mat B, Mat X)
3775 {
3776   PetscFunctionBegin;
3777   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3778   PetscValidType(A, 1);
3779   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3780   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3781   PetscCheckSameComm(A, 1, B, 2);
3782   PetscCheckSameComm(A, 1, X, 3);
3783   PetscCheck(A->cmap->N == X->rmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat X: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->cmap->N, X->rmap->N);
3784   PetscCheck(A->rmap->N == B->rmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat B: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->rmap->N, B->rmap->N);
3785   PetscCheck(X->cmap->N == B->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Solution matrix must have same number of columns as rhs matrix");
3786   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3787   MatCheckPreallocated(A, 1);
3788 
3789   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3790   if (!A->ops->matsolve) {
3791     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolve\n", ((PetscObject)A)->type_name));
3792     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_FALSE));
3793   } else PetscUseTypeMethod(A, matsolve, B, X);
3794   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3795   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3796   PetscFunctionReturn(PETSC_SUCCESS);
3797 }
3798 
3799 /*@
3800   MatMatSolveTranspose - Solves $A^T X = B $, given a factored matrix.
3801 
3802   Neighbor-wise Collective
3803 
3804   Input Parameters:
3805 + A - the factored matrix
3806 - B - the right-hand-side matrix  (`MATDENSE` matrix)
3807 
3808   Output Parameter:
3809 . X - the result matrix (dense matrix)
3810 
3811   Level: developer
3812 
3813   Note:
3814   The matrices `B` and `X` cannot be the same.  I.e., one cannot
3815   call `MatMatSolveTranspose`(A,X,X).
3816 
3817 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolveTranspose()`, `MatMatSolve()`, `MatLUFactor()`, `MatCholeskyFactor()`
3818 @*/
3819 PetscErrorCode MatMatSolveTranspose(Mat A, Mat B, Mat X)
3820 {
3821   PetscFunctionBegin;
3822   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3823   PetscValidType(A, 1);
3824   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3825   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3826   PetscCheckSameComm(A, 1, B, 2);
3827   PetscCheckSameComm(A, 1, X, 3);
3828   PetscCheck(X != B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3829   PetscCheck(A->cmap->N == X->rmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat X: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->cmap->N, X->rmap->N);
3830   PetscCheck(A->rmap->N == B->rmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat B: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->rmap->N, B->rmap->N);
3831   PetscCheck(A->rmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat A,Mat B: local dim %" PetscInt_FMT " %" PetscInt_FMT, A->rmap->n, B->rmap->n);
3832   PetscCheck(X->cmap->N >= B->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Solution matrix must have same number of columns as rhs matrix");
3833   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3834   MatCheckPreallocated(A, 1);
3835 
3836   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3837   if (!A->ops->matsolvetranspose) {
3838     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolveTranspose\n", ((PetscObject)A)->type_name));
3839     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_TRUE));
3840   } else PetscUseTypeMethod(A, matsolvetranspose, B, X);
3841   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3842   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3843   PetscFunctionReturn(PETSC_SUCCESS);
3844 }
3845 
3846 /*@
3847   MatMatTransposeSolve - Solves $A X = B^T$, given a factored matrix.
3848 
3849   Neighbor-wise Collective
3850 
3851   Input Parameters:
3852 + A  - the factored matrix
3853 - Bt - the transpose of right-hand-side matrix as a `MATDENSE`
3854 
3855   Output Parameter:
3856 . X - the result matrix (dense matrix)
3857 
3858   Level: developer
3859 
3860   Note:
3861   For MUMPS, it only supports centralized sparse compressed column format on the host processor for right-hand side matrix. User must create `Bt` in sparse compressed row
3862   format on the host processor and call `MatMatTransposeSolve()` to implement MUMPS' `MatMatSolve()`.
3863 
3864 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatMatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3865 @*/
3866 PetscErrorCode MatMatTransposeSolve(Mat A, Mat Bt, Mat X)
3867 {
3868   PetscFunctionBegin;
3869   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3870   PetscValidType(A, 1);
3871   PetscValidHeaderSpecific(Bt, MAT_CLASSID, 2);
3872   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3873   PetscCheckSameComm(A, 1, Bt, 2);
3874   PetscCheckSameComm(A, 1, X, 3);
3875 
3876   PetscCheck(X != Bt, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3877   PetscCheck(A->cmap->N == X->rmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat X: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->cmap->N, X->rmap->N);
3878   PetscCheck(A->rmap->N == Bt->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat Bt: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->rmap->N, Bt->cmap->N);
3879   PetscCheck(X->cmap->N >= Bt->rmap->N, PetscObjectComm((PetscObject)X), PETSC_ERR_ARG_SIZ, "Solution matrix must have same number of columns as row number of the rhs matrix");
3880   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3881   PetscCheck(A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
3882   MatCheckPreallocated(A, 1);
3883 
3884   PetscCall(PetscLogEventBegin(MAT_MatTrSolve, A, Bt, X, 0));
3885   PetscUseTypeMethod(A, mattransposesolve, Bt, X);
3886   PetscCall(PetscLogEventEnd(MAT_MatTrSolve, A, Bt, X, 0));
3887   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3888   PetscFunctionReturn(PETSC_SUCCESS);
3889 }
3890 
3891 /*@
3892   MatForwardSolve - Solves $ L x = b $, given a factored matrix, $A = LU $, or
3893   $U^T*D^(1/2) x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3894 
3895   Neighbor-wise Collective
3896 
3897   Input Parameters:
3898 + mat - the factored matrix
3899 - b   - the right-hand-side vector
3900 
3901   Output Parameter:
3902 . x - the result vector
3903 
3904   Level: developer
3905 
3906   Notes:
3907   `MatSolve()` should be used for most applications, as it performs
3908   a forward solve followed by a backward solve.
3909 
3910   The vectors `b` and `x` cannot be the same,  i.e., one cannot
3911   call `MatForwardSolve`(A,x,x).
3912 
3913   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3914   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3915   `MatForwardSolve()` solves $U^T*D y = b$, and
3916   `MatBackwardSolve()` solves $U x = y$.
3917   Thus they do not provide a symmetric preconditioner.
3918 
3919 .seealso: [](ch_matrices), `Mat`, `MatBackwardSolve()`, `MatGetFactor()`, `MatSolve()`
3920 @*/
3921 PetscErrorCode MatForwardSolve(Mat mat, Vec b, Vec x)
3922 {
3923   PetscFunctionBegin;
3924   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3925   PetscValidType(mat, 1);
3926   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3927   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3928   PetscCheckSameComm(mat, 1, b, 2);
3929   PetscCheckSameComm(mat, 1, x, 3);
3930   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3931   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
3932   PetscCheck(mat->rmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, b->map->N);
3933   PetscCheck(mat->rmap->n == b->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, b->map->n);
3934   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3935   MatCheckPreallocated(mat, 1);
3936 
3937   PetscCall(PetscLogEventBegin(MAT_ForwardSolve, mat, b, x, 0));
3938   PetscUseTypeMethod(mat, forwardsolve, b, x);
3939   PetscCall(PetscLogEventEnd(MAT_ForwardSolve, mat, b, x, 0));
3940   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3941   PetscFunctionReturn(PETSC_SUCCESS);
3942 }
3943 
3944 /*@
3945   MatBackwardSolve - Solves $U x = b$, given a factored matrix, $A = LU$.
3946   $D^(1/2) U x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3947 
3948   Neighbor-wise Collective
3949 
3950   Input Parameters:
3951 + mat - the factored matrix
3952 - b   - the right-hand-side vector
3953 
3954   Output Parameter:
3955 . x - the result vector
3956 
3957   Level: developer
3958 
3959   Notes:
3960   `MatSolve()` should be used for most applications, as it performs
3961   a forward solve followed by a backward solve.
3962 
3963   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3964   call `MatBackwardSolve`(A,x,x).
3965 
3966   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3967   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3968   `MatForwardSolve()` solves $U^T*D y = b$, and
3969   `MatBackwardSolve()` solves $U x = y$.
3970   Thus they do not provide a symmetric preconditioner.
3971 
3972 .seealso: [](ch_matrices), `Mat`, `MatForwardSolve()`, `MatGetFactor()`, `MatSolve()`
3973 @*/
3974 PetscErrorCode MatBackwardSolve(Mat mat, Vec b, Vec x)
3975 {
3976   PetscFunctionBegin;
3977   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3978   PetscValidType(mat, 1);
3979   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3980   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3981   PetscCheckSameComm(mat, 1, b, 2);
3982   PetscCheckSameComm(mat, 1, x, 3);
3983   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3984   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
3985   PetscCheck(mat->rmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, b->map->N);
3986   PetscCheck(mat->rmap->n == b->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, b->map->n);
3987   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3988   MatCheckPreallocated(mat, 1);
3989 
3990   PetscCall(PetscLogEventBegin(MAT_BackwardSolve, mat, b, x, 0));
3991   PetscUseTypeMethod(mat, backwardsolve, b, x);
3992   PetscCall(PetscLogEventEnd(MAT_BackwardSolve, mat, b, x, 0));
3993   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3994   PetscFunctionReturn(PETSC_SUCCESS);
3995 }
3996 
3997 /*@
3998   MatSolveAdd - Computes $x = y + A^{-1}*b$, given a factored matrix.
3999 
4000   Neighbor-wise Collective
4001 
4002   Input Parameters:
4003 + mat - the factored matrix
4004 . b   - the right-hand-side vector
4005 - y   - the vector to be added to
4006 
4007   Output Parameter:
4008 . x - the result vector
4009 
4010   Level: developer
4011 
4012   Note:
4013   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4014   call `MatSolveAdd`(A,x,y,x).
4015 
4016 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolve()`, `MatGetFactor()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
4017 @*/
4018 PetscErrorCode MatSolveAdd(Mat mat, Vec b, Vec y, Vec x)
4019 {
4020   PetscScalar one = 1.0;
4021   Vec         tmp;
4022 
4023   PetscFunctionBegin;
4024   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4025   PetscValidType(mat, 1);
4026   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4027   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4028   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4029   PetscCheckSameComm(mat, 1, b, 2);
4030   PetscCheckSameComm(mat, 1, y, 3);
4031   PetscCheckSameComm(mat, 1, x, 4);
4032   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4033   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
4034   PetscCheck(mat->rmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, b->map->N);
4035   PetscCheck(mat->rmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, y->map->N);
4036   PetscCheck(mat->rmap->n == b->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, b->map->n);
4037   PetscCheck(x->map->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Vec x,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, x->map->n, y->map->n);
4038   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4039   MatCheckPreallocated(mat, 1);
4040 
4041   PetscCall(PetscLogEventBegin(MAT_SolveAdd, mat, b, x, y));
4042   PetscCall(VecFlag(x, mat->factorerrortype));
4043   if (mat->factorerrortype) {
4044     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4045   } else if (mat->ops->solveadd) {
4046     PetscUseTypeMethod(mat, solveadd, b, y, x);
4047   } else {
4048     /* do the solve then the add manually */
4049     if (x != y) {
4050       PetscCall(MatSolve(mat, b, x));
4051       PetscCall(VecAXPY(x, one, y));
4052     } else {
4053       PetscCall(VecDuplicate(x, &tmp));
4054       PetscCall(VecCopy(x, tmp));
4055       PetscCall(MatSolve(mat, b, x));
4056       PetscCall(VecAXPY(x, one, tmp));
4057       PetscCall(VecDestroy(&tmp));
4058     }
4059   }
4060   PetscCall(PetscLogEventEnd(MAT_SolveAdd, mat, b, x, y));
4061   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4062   PetscFunctionReturn(PETSC_SUCCESS);
4063 }
4064 
4065 /*@
4066   MatSolveTranspose - Solves $A^T x = b$, given a factored matrix.
4067 
4068   Neighbor-wise Collective
4069 
4070   Input Parameters:
4071 + mat - the factored matrix
4072 - b   - the right-hand-side vector
4073 
4074   Output Parameter:
4075 . x - the result vector
4076 
4077   Level: developer
4078 
4079   Notes:
4080   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4081   call `MatSolveTranspose`(A,x,x).
4082 
4083   Most users should employ the `KSP` interface for linear solvers
4084   instead of working directly with matrix algebra routines such as this.
4085   See, e.g., `KSPCreate()`.
4086 
4087 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `KSP`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTransposeAdd()`
4088 @*/
4089 PetscErrorCode MatSolveTranspose(Mat mat, Vec b, Vec x)
4090 {
4091   PetscErrorCode (*f)(Mat, Vec, Vec) = (!mat->ops->solvetranspose && mat->symmetric) ? mat->ops->solve : mat->ops->solvetranspose;
4092 
4093   PetscFunctionBegin;
4094   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4095   PetscValidType(mat, 1);
4096   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4097   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
4098   PetscCheckSameComm(mat, 1, b, 2);
4099   PetscCheckSameComm(mat, 1, x, 3);
4100   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4101   PetscCheck(mat->rmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, x->map->N);
4102   PetscCheck(mat->cmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, b->map->N);
4103   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4104   MatCheckPreallocated(mat, 1);
4105   PetscCall(PetscLogEventBegin(MAT_SolveTranspose, mat, b, x, 0));
4106   PetscCall(VecFlag(x, mat->factorerrortype));
4107   if (mat->factorerrortype) {
4108     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4109   } else {
4110     PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Matrix type %s", ((PetscObject)mat)->type_name);
4111     PetscCall((*f)(mat, b, x));
4112   }
4113   PetscCall(PetscLogEventEnd(MAT_SolveTranspose, mat, b, x, 0));
4114   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4115   PetscFunctionReturn(PETSC_SUCCESS);
4116 }
4117 
4118 /*@
4119   MatSolveTransposeAdd - Computes $x = y + A^{-T} b$
4120   factored matrix.
4121 
4122   Neighbor-wise Collective
4123 
4124   Input Parameters:
4125 + mat - the factored matrix
4126 . b   - the right-hand-side vector
4127 - y   - the vector to be added to
4128 
4129   Output Parameter:
4130 . x - the result vector
4131 
4132   Level: developer
4133 
4134   Note:
4135   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4136   call `MatSolveTransposeAdd`(A,x,y,x).
4137 
4138 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTranspose()`
4139 @*/
4140 PetscErrorCode MatSolveTransposeAdd(Mat mat, Vec b, Vec y, Vec x)
4141 {
4142   PetscScalar one = 1.0;
4143   Vec         tmp;
4144   PetscErrorCode (*f)(Mat, Vec, Vec, Vec) = (!mat->ops->solvetransposeadd && mat->symmetric) ? mat->ops->solveadd : mat->ops->solvetransposeadd;
4145 
4146   PetscFunctionBegin;
4147   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4148   PetscValidType(mat, 1);
4149   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4150   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4151   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4152   PetscCheckSameComm(mat, 1, b, 2);
4153   PetscCheckSameComm(mat, 1, y, 3);
4154   PetscCheckSameComm(mat, 1, x, 4);
4155   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4156   PetscCheck(mat->rmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, x->map->N);
4157   PetscCheck(mat->cmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, b->map->N);
4158   PetscCheck(mat->cmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, y->map->N);
4159   PetscCheck(x->map->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Vec x,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, x->map->n, y->map->n);
4160   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4161   MatCheckPreallocated(mat, 1);
4162 
4163   PetscCall(PetscLogEventBegin(MAT_SolveTransposeAdd, mat, b, x, y));
4164   PetscCall(VecFlag(x, mat->factorerrortype));
4165   if (mat->factorerrortype) {
4166     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4167   } else if (f) {
4168     PetscCall((*f)(mat, b, y, x));
4169   } else {
4170     /* do the solve then the add manually */
4171     if (x != y) {
4172       PetscCall(MatSolveTranspose(mat, b, x));
4173       PetscCall(VecAXPY(x, one, y));
4174     } else {
4175       PetscCall(VecDuplicate(x, &tmp));
4176       PetscCall(VecCopy(x, tmp));
4177       PetscCall(MatSolveTranspose(mat, b, x));
4178       PetscCall(VecAXPY(x, one, tmp));
4179       PetscCall(VecDestroy(&tmp));
4180     }
4181   }
4182   PetscCall(PetscLogEventEnd(MAT_SolveTransposeAdd, mat, b, x, y));
4183   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4184   PetscFunctionReturn(PETSC_SUCCESS);
4185 }
4186 
4187 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
4188 /*@
4189   MatSOR - Computes relaxation (SOR, Gauss-Seidel) sweeps.
4190 
4191   Neighbor-wise Collective
4192 
4193   Input Parameters:
4194 + mat   - the matrix
4195 . b     - the right-hand side
4196 . omega - the relaxation factor
4197 . flag  - flag indicating the type of SOR (see below)
4198 . shift - diagonal shift
4199 . its   - the number of iterations
4200 - lits  - the number of local iterations
4201 
4202   Output Parameter:
4203 . x - the solution (can contain an initial guess, use option `SOR_ZERO_INITIAL_GUESS` to indicate no guess)
4204 
4205   SOR Flags:
4206 +     `SOR_FORWARD_SWEEP` - forward SOR
4207 .     `SOR_BACKWARD_SWEEP` - backward SOR
4208 .     `SOR_SYMMETRIC_SWEEP` - SSOR (symmetric SOR)
4209 .     `SOR_LOCAL_FORWARD_SWEEP` - local forward SOR
4210 .     `SOR_LOCAL_BACKWARD_SWEEP` - local forward SOR
4211 .     `SOR_LOCAL_SYMMETRIC_SWEEP` - local SSOR
4212 .     `SOR_EISENSTAT` - SOR with Eisenstat trick
4213 .     `SOR_APPLY_UPPER`, `SOR_APPLY_LOWER` - applies
4214   upper/lower triangular part of matrix to
4215   vector (with omega)
4216 -     `SOR_ZERO_INITIAL_GUESS` - zero initial guess
4217 
4218   Level: developer
4219 
4220   Notes:
4221   `SOR_LOCAL_FORWARD_SWEEP`, `SOR_LOCAL_BACKWARD_SWEEP`, and
4222   `SOR_LOCAL_SYMMETRIC_SWEEP` perform separate independent smoothings
4223   on each processor.
4224 
4225   Application programmers will not generally use `MatSOR()` directly,
4226   but instead will employ the `KSP`/`PC` interface.
4227 
4228   For `MATBAIJ`, `MATSBAIJ`, and `MATAIJ` matrices with Inodes this does a block SOR smoothing, otherwise it does a pointwise smoothing
4229 
4230   Most users should employ the `KSP` interface for linear solvers
4231   instead of working directly with matrix algebra routines such as this.
4232   See, e.g., `KSPCreate()`.
4233 
4234   Vectors `x` and `b` CANNOT be the same
4235 
4236   The flags are implemented as bitwise inclusive or operations.
4237   For example, use (`SOR_ZERO_INITIAL_GUESS` | `SOR_SYMMETRIC_SWEEP`)
4238   to specify a zero initial guess for SSOR.
4239 
4240   Developer Note:
4241   We should add block SOR support for `MATAIJ` matrices with block size set to great than one and no inodes
4242 
4243 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `KSP`, `PC`, `MatGetFactor()`
4244 @*/
4245 PetscErrorCode MatSOR(Mat mat, Vec b, PetscReal omega, MatSORType flag, PetscReal shift, PetscInt its, PetscInt lits, Vec x)
4246 {
4247   PetscFunctionBegin;
4248   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4249   PetscValidType(mat, 1);
4250   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4251   PetscValidHeaderSpecific(x, VEC_CLASSID, 8);
4252   PetscCheckSameComm(mat, 1, b, 2);
4253   PetscCheckSameComm(mat, 1, x, 8);
4254   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4255   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4256   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
4257   PetscCheck(mat->rmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, b->map->N);
4258   PetscCheck(mat->rmap->n == b->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, b->map->n);
4259   PetscCheck(its > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires global its %" PetscInt_FMT " positive", its);
4260   PetscCheck(lits > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires local its %" PetscInt_FMT " positive", lits);
4261   PetscCheck(b != x, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "b and x vector cannot be the same");
4262 
4263   MatCheckPreallocated(mat, 1);
4264   PetscCall(PetscLogEventBegin(MAT_SOR, mat, b, x, 0));
4265   PetscUseTypeMethod(mat, sor, b, omega, flag, shift, its, lits, x);
4266   PetscCall(PetscLogEventEnd(MAT_SOR, mat, b, x, 0));
4267   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4268   PetscFunctionReturn(PETSC_SUCCESS);
4269 }
4270 
4271 /*
4272       Default matrix copy routine.
4273 */
4274 PetscErrorCode MatCopy_Basic(Mat A, Mat B, MatStructure str)
4275 {
4276   PetscInt           i, rstart = 0, rend = 0, nz;
4277   const PetscInt    *cwork;
4278   const PetscScalar *vwork;
4279 
4280   PetscFunctionBegin;
4281   if (B->assembled) PetscCall(MatZeroEntries(B));
4282   if (str == SAME_NONZERO_PATTERN) {
4283     PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
4284     for (i = rstart; i < rend; i++) {
4285       PetscCall(MatGetRow(A, i, &nz, &cwork, &vwork));
4286       PetscCall(MatSetValues(B, 1, &i, nz, cwork, vwork, INSERT_VALUES));
4287       PetscCall(MatRestoreRow(A, i, &nz, &cwork, &vwork));
4288     }
4289   } else {
4290     PetscCall(MatAYPX(B, 0.0, A, str));
4291   }
4292   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
4293   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
4294   PetscFunctionReturn(PETSC_SUCCESS);
4295 }
4296 
4297 /*@
4298   MatCopy - Copies a matrix to another matrix.
4299 
4300   Collective
4301 
4302   Input Parameters:
4303 + A   - the matrix
4304 - str - `SAME_NONZERO_PATTERN` or `DIFFERENT_NONZERO_PATTERN`
4305 
4306   Output Parameter:
4307 . B - where the copy is put
4308 
4309   Level: intermediate
4310 
4311   Notes:
4312   If you use `SAME_NONZERO_PATTERN`, then the two matrices must have the same nonzero pattern or the routine will crash.
4313 
4314   `MatCopy()` copies the matrix entries of a matrix to another existing
4315   matrix (after first zeroing the second matrix).  A related routine is
4316   `MatConvert()`, which first creates a new matrix and then copies the data.
4317 
4318 .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatDuplicate()`
4319 @*/
4320 PetscErrorCode MatCopy(Mat A, Mat B, MatStructure str)
4321 {
4322   PetscInt i;
4323 
4324   PetscFunctionBegin;
4325   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
4326   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
4327   PetscValidType(A, 1);
4328   PetscValidType(B, 2);
4329   PetscCheckSameComm(A, 1, B, 2);
4330   MatCheckPreallocated(B, 2);
4331   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4332   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4333   PetscCheck(A->rmap->N == B->rmap->N && A->cmap->N == B->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat B: global dim (%" PetscInt_FMT ",%" PetscInt_FMT ") (%" PetscInt_FMT ",%" PetscInt_FMT ")", A->rmap->N, B->rmap->N,
4334              A->cmap->N, B->cmap->N);
4335   MatCheckPreallocated(A, 1);
4336   if (A == B) PetscFunctionReturn(PETSC_SUCCESS);
4337 
4338   PetscCall(PetscLogEventBegin(MAT_Copy, A, B, 0, 0));
4339   if (A->ops->copy) PetscUseTypeMethod(A, copy, B, str);
4340   else PetscCall(MatCopy_Basic(A, B, str));
4341 
4342   B->stencil.dim = A->stencil.dim;
4343   B->stencil.noc = A->stencil.noc;
4344   for (i = 0; i <= A->stencil.dim + (A->stencil.noc ? 0 : -1); i++) {
4345     B->stencil.dims[i]   = A->stencil.dims[i];
4346     B->stencil.starts[i] = A->stencil.starts[i];
4347   }
4348 
4349   PetscCall(PetscLogEventEnd(MAT_Copy, A, B, 0, 0));
4350   PetscCall(PetscObjectStateIncrease((PetscObject)B));
4351   PetscFunctionReturn(PETSC_SUCCESS);
4352 }
4353 
4354 /*@
4355   MatConvert - Converts a matrix to another matrix, either of the same
4356   or different type.
4357 
4358   Collective
4359 
4360   Input Parameters:
4361 + mat     - the matrix
4362 . newtype - new matrix type.  Use `MATSAME` to create a new matrix of the
4363             same type as the original matrix.
4364 - reuse   - denotes if the destination matrix is to be created or reused.
4365             Use `MAT_INPLACE_MATRIX` for inplace conversion (that is when you want the input `Mat` to be changed to contain the matrix in the new format), otherwise use
4366             `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX` (can only be used after the first call was made with `MAT_INITIAL_MATRIX`, causes the matrix space in M to be reused).
4367 
4368   Output Parameter:
4369 . M - pointer to place new matrix
4370 
4371   Level: intermediate
4372 
4373   Notes:
4374   `MatConvert()` first creates a new matrix and then copies the data from
4375   the first matrix.  A related routine is `MatCopy()`, which copies the matrix
4376   entries of one matrix to another already existing matrix context.
4377 
4378   Cannot be used to convert a sequential matrix to parallel or parallel to sequential,
4379   the MPI communicator of the generated matrix is always the same as the communicator
4380   of the input matrix.
4381 
4382 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatDuplicate()`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
4383 @*/
4384 PetscErrorCode MatConvert(Mat mat, MatType newtype, MatReuse reuse, Mat *M)
4385 {
4386   PetscBool  sametype, issame, flg;
4387   PetscBool3 issymmetric, ishermitian;
4388   char       convname[256], mtype[256];
4389   Mat        B;
4390 
4391   PetscFunctionBegin;
4392   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4393   PetscValidType(mat, 1);
4394   PetscAssertPointer(M, 4);
4395   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4396   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4397   MatCheckPreallocated(mat, 1);
4398 
4399   PetscCall(PetscOptionsGetString(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matconvert_type", mtype, sizeof(mtype), &flg));
4400   if (flg) newtype = mtype;
4401 
4402   PetscCall(PetscObjectTypeCompare((PetscObject)mat, newtype, &sametype));
4403   PetscCall(PetscStrcmp(newtype, "same", &issame));
4404   PetscCheck(!(reuse == MAT_INPLACE_MATRIX) || !(mat != *M), PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires same input and output matrix");
4405   if (reuse == MAT_REUSE_MATRIX) {
4406     PetscValidHeaderSpecific(*M, MAT_CLASSID, 4);
4407     PetscCheck(mat != *M, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_REUSE_MATRIX means reuse matrix in final argument, perhaps you mean MAT_INPLACE_MATRIX");
4408   }
4409 
4410   if ((reuse == MAT_INPLACE_MATRIX) && (issame || sametype)) {
4411     PetscCall(PetscInfo(mat, "Early return for inplace %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4412     PetscFunctionReturn(PETSC_SUCCESS);
4413   }
4414 
4415   /* Cache Mat options because some converters use MatHeaderReplace  */
4416   issymmetric = mat->symmetric;
4417   ishermitian = mat->hermitian;
4418 
4419   if ((sametype || issame) && (reuse == MAT_INITIAL_MATRIX) && mat->ops->duplicate) {
4420     PetscCall(PetscInfo(mat, "Calling duplicate for initial matrix %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4421     PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4422   } else {
4423     PetscErrorCode (*conv)(Mat, MatType, MatReuse, Mat *) = NULL;
4424     const char *prefix[3]                                 = {"seq", "mpi", ""};
4425     PetscInt    i;
4426     /*
4427        Order of precedence:
4428        0) See if newtype is a superclass of the current matrix.
4429        1) See if a specialized converter is known to the current matrix.
4430        2) See if a specialized converter is known to the desired matrix class.
4431        3) See if a good general converter is registered for the desired class
4432           (as of 6/27/03 only MATMPIADJ falls into this category).
4433        4) See if a good general converter is known for the current matrix.
4434        5) Use a really basic converter.
4435     */
4436 
4437     /* 0) See if newtype is a superclass of the current matrix.
4438           i.e mat is mpiaij and newtype is aij */
4439     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4440       PetscCall(PetscStrncpy(convname, prefix[i], sizeof(convname)));
4441       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4442       PetscCall(PetscStrcmp(convname, ((PetscObject)mat)->type_name, &flg));
4443       PetscCall(PetscInfo(mat, "Check superclass %s %s -> %d\n", convname, ((PetscObject)mat)->type_name, flg));
4444       if (flg) {
4445         if (reuse == MAT_INPLACE_MATRIX) {
4446           PetscCall(PetscInfo(mat, "Early return\n"));
4447           PetscFunctionReturn(PETSC_SUCCESS);
4448         } else if (reuse == MAT_INITIAL_MATRIX && mat->ops->duplicate) {
4449           PetscCall(PetscInfo(mat, "Calling MatDuplicate\n"));
4450           PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4451           PetscFunctionReturn(PETSC_SUCCESS);
4452         } else if (reuse == MAT_REUSE_MATRIX && mat->ops->copy) {
4453           PetscCall(PetscInfo(mat, "Calling MatCopy\n"));
4454           PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
4455           PetscFunctionReturn(PETSC_SUCCESS);
4456         }
4457       }
4458     }
4459     /* 1) See if a specialized converter is known to the current matrix and the desired class */
4460     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4461       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4462       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4463       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4464       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4465       PetscCall(PetscStrlcat(convname, issame ? ((PetscObject)mat)->type_name : newtype, sizeof(convname)));
4466       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4467       PetscCall(PetscObjectQueryFunction((PetscObject)mat, convname, &conv));
4468       PetscCall(PetscInfo(mat, "Check specialized (1) %s (%s) -> %d\n", convname, ((PetscObject)mat)->type_name, !!conv));
4469       if (conv) goto foundconv;
4470     }
4471 
4472     /* 2)  See if a specialized converter is known to the desired matrix class. */
4473     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
4474     PetscCall(MatSetSizes(B, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
4475     PetscCall(MatSetType(B, newtype));
4476     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4477       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4478       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4479       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4480       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4481       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4482       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4483       PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4484       PetscCall(PetscInfo(mat, "Check specialized (2) %s (%s) -> %d\n", convname, ((PetscObject)B)->type_name, !!conv));
4485       if (conv) {
4486         PetscCall(MatDestroy(&B));
4487         goto foundconv;
4488       }
4489     }
4490 
4491     /* 3) See if a good general converter is registered for the desired class */
4492     conv = B->ops->convertfrom;
4493     PetscCall(PetscInfo(mat, "Check convertfrom (%s) -> %d\n", ((PetscObject)B)->type_name, !!conv));
4494     PetscCall(MatDestroy(&B));
4495     if (conv) goto foundconv;
4496 
4497     /* 4) See if a good general converter is known for the current matrix */
4498     if (mat->ops->convert) conv = mat->ops->convert;
4499     PetscCall(PetscInfo(mat, "Check general convert (%s) -> %d\n", ((PetscObject)mat)->type_name, !!conv));
4500     if (conv) goto foundconv;
4501 
4502     /* 5) Use a really basic converter. */
4503     PetscCall(PetscInfo(mat, "Using MatConvert_Basic\n"));
4504     conv = MatConvert_Basic;
4505 
4506   foundconv:
4507     PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4508     PetscCall((*conv)(mat, newtype, reuse, M));
4509     if (mat->rmap->mapping && mat->cmap->mapping && !(*M)->rmap->mapping && !(*M)->cmap->mapping) {
4510       /* the block sizes must be same if the mappings are copied over */
4511       (*M)->rmap->bs = mat->rmap->bs;
4512       (*M)->cmap->bs = mat->cmap->bs;
4513       PetscCall(PetscObjectReference((PetscObject)mat->rmap->mapping));
4514       PetscCall(PetscObjectReference((PetscObject)mat->cmap->mapping));
4515       (*M)->rmap->mapping = mat->rmap->mapping;
4516       (*M)->cmap->mapping = mat->cmap->mapping;
4517     }
4518     (*M)->stencil.dim = mat->stencil.dim;
4519     (*M)->stencil.noc = mat->stencil.noc;
4520     for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
4521       (*M)->stencil.dims[i]   = mat->stencil.dims[i];
4522       (*M)->stencil.starts[i] = mat->stencil.starts[i];
4523     }
4524     PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4525   }
4526   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4527 
4528   /* Copy Mat options */
4529   if (issymmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_TRUE));
4530   else if (issymmetric == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_FALSE));
4531   if (ishermitian == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_TRUE));
4532   else if (ishermitian == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_FALSE));
4533   PetscFunctionReturn(PETSC_SUCCESS);
4534 }
4535 
4536 /*@
4537   MatFactorGetSolverType - Returns name of the package providing the factorization routines
4538 
4539   Not Collective
4540 
4541   Input Parameter:
4542 . mat - the matrix, must be a factored matrix
4543 
4544   Output Parameter:
4545 . type - the string name of the package (do not free this string)
4546 
4547   Level: intermediate
4548 
4549 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolverType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`
4550 @*/
4551 PetscErrorCode MatFactorGetSolverType(Mat mat, MatSolverType *type)
4552 {
4553   PetscErrorCode (*conv)(Mat, MatSolverType *);
4554 
4555   PetscFunctionBegin;
4556   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4557   PetscValidType(mat, 1);
4558   PetscAssertPointer(type, 2);
4559   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
4560   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorGetSolverType_C", &conv));
4561   if (conv) PetscCall((*conv)(mat, type));
4562   else *type = MATSOLVERPETSC;
4563   PetscFunctionReturn(PETSC_SUCCESS);
4564 }
4565 
4566 typedef struct _MatSolverTypeForSpecifcType *MatSolverTypeForSpecifcType;
4567 struct _MatSolverTypeForSpecifcType {
4568   MatType mtype;
4569   /* no entry for MAT_FACTOR_NONE */
4570   PetscErrorCode (*createfactor[MAT_FACTOR_NUM_TYPES - 1])(Mat, MatFactorType, Mat *);
4571   MatSolverTypeForSpecifcType next;
4572 };
4573 
4574 typedef struct _MatSolverTypeHolder *MatSolverTypeHolder;
4575 struct _MatSolverTypeHolder {
4576   char                       *name;
4577   MatSolverTypeForSpecifcType handlers;
4578   MatSolverTypeHolder         next;
4579 };
4580 
4581 static MatSolverTypeHolder MatSolverTypeHolders = NULL;
4582 
4583 /*@C
4584   MatSolverTypeRegister - Registers a `MatSolverType` that works for a particular matrix type
4585 
4586   Logically Collective, No Fortran Support
4587 
4588   Input Parameters:
4589 + package      - name of the package, for example `petsc` or `superlu`
4590 . mtype        - the matrix type that works with this package
4591 . ftype        - the type of factorization supported by the package
4592 - createfactor - routine that will create the factored matrix ready to be used
4593 
4594   Level: developer
4595 
4596 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorGetSolverType()`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`,
4597   `MatGetFactor()`
4598 @*/
4599 PetscErrorCode MatSolverTypeRegister(MatSolverType package, MatType mtype, MatFactorType ftype, PetscErrorCode (*createfactor)(Mat, MatFactorType, Mat *))
4600 {
4601   MatSolverTypeHolder         next = MatSolverTypeHolders, prev = NULL;
4602   PetscBool                   flg;
4603   MatSolverTypeForSpecifcType inext, iprev = NULL;
4604 
4605   PetscFunctionBegin;
4606   PetscCall(MatInitializePackage());
4607   if (!next) {
4608     PetscCall(PetscNew(&MatSolverTypeHolders));
4609     PetscCall(PetscStrallocpy(package, &MatSolverTypeHolders->name));
4610     PetscCall(PetscNew(&MatSolverTypeHolders->handlers));
4611     PetscCall(PetscStrallocpy(mtype, (char **)&MatSolverTypeHolders->handlers->mtype));
4612     MatSolverTypeHolders->handlers->createfactor[(int)ftype - 1] = createfactor;
4613     PetscFunctionReturn(PETSC_SUCCESS);
4614   }
4615   while (next) {
4616     PetscCall(PetscStrcasecmp(package, next->name, &flg));
4617     if (flg) {
4618       PetscCheck(next->handlers, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatSolverTypeHolder is missing handlers");
4619       inext = next->handlers;
4620       while (inext) {
4621         PetscCall(PetscStrcasecmp(mtype, inext->mtype, &flg));
4622         if (flg) {
4623           inext->createfactor[(int)ftype - 1] = createfactor;
4624           PetscFunctionReturn(PETSC_SUCCESS);
4625         }
4626         iprev = inext;
4627         inext = inext->next;
4628       }
4629       PetscCall(PetscNew(&iprev->next));
4630       PetscCall(PetscStrallocpy(mtype, (char **)&iprev->next->mtype));
4631       iprev->next->createfactor[(int)ftype - 1] = createfactor;
4632       PetscFunctionReturn(PETSC_SUCCESS);
4633     }
4634     prev = next;
4635     next = next->next;
4636   }
4637   PetscCall(PetscNew(&prev->next));
4638   PetscCall(PetscStrallocpy(package, &prev->next->name));
4639   PetscCall(PetscNew(&prev->next->handlers));
4640   PetscCall(PetscStrallocpy(mtype, (char **)&prev->next->handlers->mtype));
4641   prev->next->handlers->createfactor[(int)ftype - 1] = createfactor;
4642   PetscFunctionReturn(PETSC_SUCCESS);
4643 }
4644 
4645 /*@C
4646   MatSolverTypeGet - Gets the function that creates the factor matrix if it exist
4647 
4648   Input Parameters:
4649 + type  - name of the package, for example `petsc` or `superlu`, if this is 'NULL', then the first result that satisfies the other criteria is returned
4650 . ftype - the type of factorization supported by the type
4651 - mtype - the matrix type that works with this type
4652 
4653   Output Parameters:
4654 + foundtype    - `PETSC_TRUE` if the type was registered
4655 . foundmtype   - `PETSC_TRUE` if the type supports the requested mtype
4656 - createfactor - routine that will create the factored matrix ready to be used or `NULL` if not found
4657 
4658   Calling sequence of `createfactor`:
4659 + A     - the matrix providing the factor matrix
4660 . ftype - the `MatFactorType` of the factor requested
4661 - B     - the new factor matrix that responds to MatXXFactorSymbolic,Numeric() functions, such as `MatLUFactorSymbolic()`
4662 
4663   Level: developer
4664 
4665   Note:
4666   When `type` is `NULL` the available functions are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4667   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4668   For example if one configuration had `--download-mumps` while a different one had `--download-superlu_dist`.
4669 
4670 .seealso: [](ch_matrices), `Mat`, `MatFactorType`, `MatType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatSolverTypeRegister()`, `MatGetFactor()`,
4671           `MatInitializePackage()`
4672 @*/
4673 PetscErrorCode MatSolverTypeGet(MatSolverType type, MatType mtype, MatFactorType ftype, PetscBool *foundtype, PetscBool *foundmtype, PetscErrorCode (**createfactor)(Mat A, MatFactorType ftype, Mat *B))
4674 {
4675   MatSolverTypeHolder         next = MatSolverTypeHolders;
4676   PetscBool                   flg;
4677   MatSolverTypeForSpecifcType inext;
4678 
4679   PetscFunctionBegin;
4680   if (foundtype) *foundtype = PETSC_FALSE;
4681   if (foundmtype) *foundmtype = PETSC_FALSE;
4682   if (createfactor) *createfactor = NULL;
4683 
4684   if (type) {
4685     while (next) {
4686       PetscCall(PetscStrcasecmp(type, next->name, &flg));
4687       if (flg) {
4688         if (foundtype) *foundtype = PETSC_TRUE;
4689         inext = next->handlers;
4690         while (inext) {
4691           PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4692           if (flg) {
4693             if (foundmtype) *foundmtype = PETSC_TRUE;
4694             if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4695             PetscFunctionReturn(PETSC_SUCCESS);
4696           }
4697           inext = inext->next;
4698         }
4699       }
4700       next = next->next;
4701     }
4702   } else {
4703     while (next) {
4704       inext = next->handlers;
4705       while (inext) {
4706         PetscCall(PetscStrcmp(mtype, inext->mtype, &flg));
4707         if (flg && inext->createfactor[(int)ftype - 1]) {
4708           if (foundtype) *foundtype = PETSC_TRUE;
4709           if (foundmtype) *foundmtype = PETSC_TRUE;
4710           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4711           PetscFunctionReturn(PETSC_SUCCESS);
4712         }
4713         inext = inext->next;
4714       }
4715       next = next->next;
4716     }
4717     /* try with base classes inext->mtype */
4718     next = MatSolverTypeHolders;
4719     while (next) {
4720       inext = next->handlers;
4721       while (inext) {
4722         PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4723         if (flg && inext->createfactor[(int)ftype - 1]) {
4724           if (foundtype) *foundtype = PETSC_TRUE;
4725           if (foundmtype) *foundmtype = PETSC_TRUE;
4726           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4727           PetscFunctionReturn(PETSC_SUCCESS);
4728         }
4729         inext = inext->next;
4730       }
4731       next = next->next;
4732     }
4733   }
4734   PetscFunctionReturn(PETSC_SUCCESS);
4735 }
4736 
4737 PetscErrorCode MatSolverTypeDestroy(void)
4738 {
4739   MatSolverTypeHolder         next = MatSolverTypeHolders, prev;
4740   MatSolverTypeForSpecifcType inext, iprev;
4741 
4742   PetscFunctionBegin;
4743   while (next) {
4744     PetscCall(PetscFree(next->name));
4745     inext = next->handlers;
4746     while (inext) {
4747       PetscCall(PetscFree(inext->mtype));
4748       iprev = inext;
4749       inext = inext->next;
4750       PetscCall(PetscFree(iprev));
4751     }
4752     prev = next;
4753     next = next->next;
4754     PetscCall(PetscFree(prev));
4755   }
4756   MatSolverTypeHolders = NULL;
4757   PetscFunctionReturn(PETSC_SUCCESS);
4758 }
4759 
4760 /*@
4761   MatFactorGetCanUseOrdering - Indicates if the factorization can use the ordering provided in `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4762 
4763   Logically Collective
4764 
4765   Input Parameter:
4766 . mat - the matrix
4767 
4768   Output Parameter:
4769 . flg - `PETSC_TRUE` if uses the ordering
4770 
4771   Level: developer
4772 
4773   Note:
4774   Most internal PETSc factorizations use the ordering passed to the factorization routine but external
4775   packages do not, thus we want to skip generating the ordering when it is not needed or used.
4776 
4777 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4778 @*/
4779 PetscErrorCode MatFactorGetCanUseOrdering(Mat mat, PetscBool *flg)
4780 {
4781   PetscFunctionBegin;
4782   *flg = mat->canuseordering;
4783   PetscFunctionReturn(PETSC_SUCCESS);
4784 }
4785 
4786 /*@
4787   MatFactorGetPreferredOrdering - The preferred ordering for a particular matrix factor object
4788 
4789   Logically Collective
4790 
4791   Input Parameters:
4792 + mat   - the matrix obtained with `MatGetFactor()`
4793 - ftype - the factorization type to be used
4794 
4795   Output Parameter:
4796 . otype - the preferred ordering type
4797 
4798   Level: developer
4799 
4800 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatOrderingType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4801 @*/
4802 PetscErrorCode MatFactorGetPreferredOrdering(Mat mat, MatFactorType ftype, MatOrderingType *otype)
4803 {
4804   PetscFunctionBegin;
4805   *otype = mat->preferredordering[ftype];
4806   PetscCheck(*otype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatFactor did not have a preferred ordering");
4807   PetscFunctionReturn(PETSC_SUCCESS);
4808 }
4809 
4810 /*@
4811   MatGetFactor - Returns a matrix suitable to calls to MatXXFactorSymbolic,Numeric()
4812 
4813   Collective
4814 
4815   Input Parameters:
4816 + mat   - the matrix
4817 . type  - name of solver type, for example, `superlu`, `petsc` (to use PETSc's solver if it is available), if this is 'NULL', then the first result that satisfies
4818           the other criteria is returned
4819 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4820 
4821   Output Parameter:
4822 . f - the factor matrix used with MatXXFactorSymbolic,Numeric() calls. Can be `NULL` in some cases, see notes below.
4823 
4824   Options Database Keys:
4825 + -pc_factor_mat_solver_type <type>    - choose the type at run time. When using `KSP` solvers
4826 . -pc_factor_mat_factor_on_host <bool> - do mat factorization on host (with device matrices). Default is doing it on device
4827 - -pc_factor_mat_solve_on_host <bool>  - do mat solve on host (with device matrices). Default is doing it on device
4828 
4829   Level: intermediate
4830 
4831   Notes:
4832   The return matrix can be `NULL` if the requested factorization is not available, since some combinations of matrix types and factorization
4833   types registered with `MatSolverTypeRegister()` cannot be fully tested if not at runtime.
4834 
4835   Users usually access the factorization solvers via `KSP`
4836 
4837   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4838   such as pastix, superlu, mumps etc. PETSc must have been ./configure to use the external solver, using the option --download-package or --with-package-dir
4839 
4840   When `type` is `NULL` the available results are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4841   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4842   For example if one configuration had --download-mumps while a different one had --download-superlu_dist.
4843 
4844   Some of the packages have options for controlling the factorization, these are in the form -prefix_mat_packagename_packageoption
4845   where prefix is normally obtained from the calling `KSP`/`PC`. If `MatGetFactor()` is called directly one can set
4846   call `MatSetOptionsPrefixFactor()` on the originating matrix or  `MatSetOptionsPrefix()` on the resulting factor matrix.
4847 
4848   Developer Note:
4849   This should actually be called `MatCreateFactor()` since it creates a new factor object
4850 
4851 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `KSP`, `MatSolverType`, `MatFactorType`, `MatCopy()`, `MatDuplicate()`,
4852           `MatGetFactorAvailable()`, `MatFactorGetCanUseOrdering()`, `MatSolverTypeRegister()`, `MatSolverTypeGet()`
4853           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatInitializePackage()`
4854 @*/
4855 PetscErrorCode MatGetFactor(Mat mat, MatSolverType type, MatFactorType ftype, Mat *f)
4856 {
4857   PetscBool foundtype, foundmtype, shell, hasop = PETSC_FALSE;
4858   PetscErrorCode (*conv)(Mat, MatFactorType, Mat *);
4859 
4860   PetscFunctionBegin;
4861   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4862   PetscValidType(mat, 1);
4863 
4864   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4865   MatCheckPreallocated(mat, 1);
4866 
4867   PetscCall(MatIsShell(mat, &shell));
4868   if (shell) PetscCall(MatHasOperation(mat, MATOP_GET_FACTOR, &hasop));
4869   if (hasop) {
4870     PetscUseTypeMethod(mat, getfactor, type, ftype, f);
4871     PetscFunctionReturn(PETSC_SUCCESS);
4872   }
4873 
4874   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, &foundtype, &foundmtype, &conv));
4875   if (!foundtype) {
4876     if (type) {
4877       SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "Could not locate solver type %s for factorization type %s and matrix type %s. Perhaps you must ./configure with --download-%s", type, MatFactorTypes[ftype],
4878               ((PetscObject)mat)->type_name, type);
4879     } else {
4880       SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "Could not locate a solver type for factorization type %s and matrix type %s.", MatFactorTypes[ftype], ((PetscObject)mat)->type_name);
4881     }
4882   }
4883   PetscCheck(foundmtype, PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "MatSolverType %s does not support matrix type %s", type, ((PetscObject)mat)->type_name);
4884   PetscCheck(conv, PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "MatSolverType %s does not support factorization type %s for matrix type %s", type, MatFactorTypes[ftype], ((PetscObject)mat)->type_name);
4885 
4886   PetscCall((*conv)(mat, ftype, f));
4887   if (mat->factorprefix) PetscCall(MatSetOptionsPrefix(*f, mat->factorprefix));
4888   PetscFunctionReturn(PETSC_SUCCESS);
4889 }
4890 
4891 /*@
4892   MatGetFactorAvailable - Returns a flag if matrix supports particular type and factor type
4893 
4894   Not Collective
4895 
4896   Input Parameters:
4897 + mat   - the matrix
4898 . type  - name of solver type, for example, `superlu`, `petsc` (to use PETSc's default)
4899 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4900 
4901   Output Parameter:
4902 . flg - PETSC_TRUE if the factorization is available
4903 
4904   Level: intermediate
4905 
4906   Notes:
4907   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4908   such as pastix, superlu, mumps etc.
4909 
4910   PETSc must have been ./configure to use the external solver, using the option --download-package
4911 
4912   Developer Note:
4913   This should actually be called `MatCreateFactorAvailable()` since `MatGetFactor()` creates a new factor object
4914 
4915 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolverType`, `MatFactorType`, `MatGetFactor()`, `MatCopy()`, `MatDuplicate()`, `MatSolverTypeRegister()`,
4916           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatSolverTypeGet()`
4917 @*/
4918 PetscErrorCode MatGetFactorAvailable(Mat mat, MatSolverType type, MatFactorType ftype, PetscBool *flg)
4919 {
4920   PetscErrorCode (*gconv)(Mat, MatFactorType, Mat *);
4921 
4922   PetscFunctionBegin;
4923   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4924   PetscAssertPointer(flg, 4);
4925 
4926   *flg = PETSC_FALSE;
4927   if (!((PetscObject)mat)->type_name) PetscFunctionReturn(PETSC_SUCCESS);
4928 
4929   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4930   MatCheckPreallocated(mat, 1);
4931 
4932   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, NULL, NULL, &gconv));
4933   *flg = gconv ? PETSC_TRUE : PETSC_FALSE;
4934   PetscFunctionReturn(PETSC_SUCCESS);
4935 }
4936 
4937 /*@
4938   MatDuplicate - Duplicates a matrix including the non-zero structure.
4939 
4940   Collective
4941 
4942   Input Parameters:
4943 + mat - the matrix
4944 - op  - One of `MAT_DO_NOT_COPY_VALUES`, `MAT_COPY_VALUES`, or `MAT_SHARE_NONZERO_PATTERN`.
4945         See the manual page for `MatDuplicateOption()` for an explanation of these options.
4946 
4947   Output Parameter:
4948 . M - pointer to place new matrix
4949 
4950   Level: intermediate
4951 
4952   Notes:
4953   You cannot change the nonzero pattern for the parent or child matrix later if you use `MAT_SHARE_NONZERO_PATTERN`.
4954 
4955   If `op` is not `MAT_COPY_VALUES` the numerical values in the new matrix are zeroed.
4956 
4957   May be called with an unassembled input `Mat` if `MAT_DO_NOT_COPY_VALUES` is used, in which case the output `Mat` is unassembled as well.
4958 
4959   When original mat is a product of matrix operation, e.g., an output of `MatMatMult()` or `MatCreateSubMatrix()`, only the matrix data structure of `mat`
4960   is duplicated and the internal data structures created for the reuse of previous matrix operations are not duplicated.
4961   User should not use `MatDuplicate()` to create new matrix `M` if `M` is intended to be reused as the product of matrix operation.
4962 
4963 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatConvert()`, `MatDuplicateOption`
4964 @*/
4965 PetscErrorCode MatDuplicate(Mat mat, MatDuplicateOption op, Mat *M)
4966 {
4967   Mat         B;
4968   VecType     vtype;
4969   PetscInt    i;
4970   PetscObject dm, container_h, container_d;
4971   void (*viewf)(void);
4972 
4973   PetscFunctionBegin;
4974   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4975   PetscValidType(mat, 1);
4976   PetscAssertPointer(M, 3);
4977   PetscCheck(op != MAT_COPY_VALUES || mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MAT_COPY_VALUES not allowed for unassembled matrix");
4978   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4979   MatCheckPreallocated(mat, 1);
4980 
4981   PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4982   PetscUseTypeMethod(mat, duplicate, op, M);
4983   PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4984   B = *M;
4985 
4986   PetscCall(MatGetOperation(mat, MATOP_VIEW, &viewf));
4987   if (viewf) PetscCall(MatSetOperation(B, MATOP_VIEW, viewf));
4988   PetscCall(MatGetVecType(mat, &vtype));
4989   PetscCall(MatSetVecType(B, vtype));
4990 
4991   B->stencil.dim = mat->stencil.dim;
4992   B->stencil.noc = mat->stencil.noc;
4993   for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
4994     B->stencil.dims[i]   = mat->stencil.dims[i];
4995     B->stencil.starts[i] = mat->stencil.starts[i];
4996   }
4997 
4998   B->nooffproczerorows = mat->nooffproczerorows;
4999   B->nooffprocentries  = mat->nooffprocentries;
5000 
5001   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_dm", &dm));
5002   if (dm) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_dm", dm));
5003   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Host", &container_h));
5004   if (container_h) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Host", container_h));
5005   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Device", &container_d));
5006   if (container_d) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Device", container_d));
5007   if (op == MAT_COPY_VALUES) PetscCall(MatPropagateSymmetryOptions(mat, B));
5008   PetscCall(PetscObjectStateIncrease((PetscObject)B));
5009   PetscFunctionReturn(PETSC_SUCCESS);
5010 }
5011 
5012 /*@
5013   MatGetDiagonal - Gets the diagonal of a matrix as a `Vec`
5014 
5015   Logically Collective
5016 
5017   Input Parameter:
5018 . mat - the matrix
5019 
5020   Output Parameter:
5021 . v - the diagonal of the matrix
5022 
5023   Level: intermediate
5024 
5025   Note:
5026   If `mat` has local sizes `n` x `m`, this routine fills the first `ndiag = min(n, m)` entries
5027   of `v` with the diagonal values. Thus `v` must have local size of at least `ndiag`. If `v`
5028   is larger than `ndiag`, the values of the remaining entries are unspecified.
5029 
5030   Currently only correct in parallel for square matrices.
5031 
5032 .seealso: [](ch_matrices), `Mat`, `Vec`, `MatGetRow()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`
5033 @*/
5034 PetscErrorCode MatGetDiagonal(Mat mat, Vec v)
5035 {
5036   PetscFunctionBegin;
5037   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5038   PetscValidType(mat, 1);
5039   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5040   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5041   MatCheckPreallocated(mat, 1);
5042   if (PetscDefined(USE_DEBUG)) {
5043     PetscInt nv, row, col, ndiag;
5044 
5045     PetscCall(VecGetLocalSize(v, &nv));
5046     PetscCall(MatGetLocalSize(mat, &row, &col));
5047     ndiag = PetscMin(row, col);
5048     PetscCheck(nv >= ndiag, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming Mat and Vec. Vec local size %" PetscInt_FMT " < Mat local diagonal length %" PetscInt_FMT, nv, ndiag);
5049   }
5050 
5051   PetscUseTypeMethod(mat, getdiagonal, v);
5052   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5053   PetscFunctionReturn(PETSC_SUCCESS);
5054 }
5055 
5056 /*@
5057   MatGetRowMin - Gets the minimum value (of the real part) of each
5058   row of the matrix
5059 
5060   Logically Collective
5061 
5062   Input Parameter:
5063 . mat - the matrix
5064 
5065   Output Parameters:
5066 + v   - the vector for storing the maximums
5067 - idx - the indices of the column found for each row (optional, pass `NULL` if not needed)
5068 
5069   Level: intermediate
5070 
5071   Note:
5072   The result of this call are the same as if one converted the matrix to dense format
5073   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5074 
5075   This code is only implemented for a couple of matrix formats.
5076 
5077 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`,
5078           `MatGetRowMax()`
5079 @*/
5080 PetscErrorCode MatGetRowMin(Mat mat, Vec v, PetscInt idx[])
5081 {
5082   PetscFunctionBegin;
5083   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5084   PetscValidType(mat, 1);
5085   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5086   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5087 
5088   if (!mat->cmap->N) {
5089     PetscCall(VecSet(v, PETSC_MAX_REAL));
5090     if (idx) {
5091       PetscInt i, m = mat->rmap->n;
5092       for (i = 0; i < m; i++) idx[i] = -1;
5093     }
5094   } else {
5095     MatCheckPreallocated(mat, 1);
5096   }
5097   PetscUseTypeMethod(mat, getrowmin, v, idx);
5098   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5099   PetscFunctionReturn(PETSC_SUCCESS);
5100 }
5101 
5102 /*@
5103   MatGetRowMinAbs - Gets the minimum value (in absolute value) of each
5104   row of the matrix
5105 
5106   Logically Collective
5107 
5108   Input Parameter:
5109 . mat - the matrix
5110 
5111   Output Parameters:
5112 + v   - the vector for storing the minimums
5113 - idx - the indices of the column found for each row (or `NULL` if not needed)
5114 
5115   Level: intermediate
5116 
5117   Notes:
5118   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5119   row is 0 (the first column).
5120 
5121   This code is only implemented for a couple of matrix formats.
5122 
5123 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`
5124 @*/
5125 PetscErrorCode MatGetRowMinAbs(Mat mat, Vec v, PetscInt idx[])
5126 {
5127   PetscFunctionBegin;
5128   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5129   PetscValidType(mat, 1);
5130   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5131   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5132   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5133 
5134   if (!mat->cmap->N) {
5135     PetscCall(VecSet(v, 0.0));
5136     if (idx) {
5137       PetscInt i, m = mat->rmap->n;
5138       for (i = 0; i < m; i++) idx[i] = -1;
5139     }
5140   } else {
5141     MatCheckPreallocated(mat, 1);
5142     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5143     PetscUseTypeMethod(mat, getrowminabs, v, idx);
5144   }
5145   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5146   PetscFunctionReturn(PETSC_SUCCESS);
5147 }
5148 
5149 /*@
5150   MatGetRowMax - Gets the maximum value (of the real part) of each
5151   row of the matrix
5152 
5153   Logically Collective
5154 
5155   Input Parameter:
5156 . mat - the matrix
5157 
5158   Output Parameters:
5159 + v   - the vector for storing the maximums
5160 - idx - the indices of the column found for each row (optional, otherwise pass `NULL`)
5161 
5162   Level: intermediate
5163 
5164   Notes:
5165   The result of this call are the same as if one converted the matrix to dense format
5166   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5167 
5168   This code is only implemented for a couple of matrix formats.
5169 
5170 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5171 @*/
5172 PetscErrorCode MatGetRowMax(Mat mat, Vec v, PetscInt idx[])
5173 {
5174   PetscFunctionBegin;
5175   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5176   PetscValidType(mat, 1);
5177   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5178   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5179 
5180   if (!mat->cmap->N) {
5181     PetscCall(VecSet(v, PETSC_MIN_REAL));
5182     if (idx) {
5183       PetscInt i, m = mat->rmap->n;
5184       for (i = 0; i < m; i++) idx[i] = -1;
5185     }
5186   } else {
5187     MatCheckPreallocated(mat, 1);
5188     PetscUseTypeMethod(mat, getrowmax, v, idx);
5189   }
5190   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5191   PetscFunctionReturn(PETSC_SUCCESS);
5192 }
5193 
5194 /*@
5195   MatGetRowMaxAbs - Gets the maximum value (in absolute value) of each
5196   row of the matrix
5197 
5198   Logically Collective
5199 
5200   Input Parameter:
5201 . mat - the matrix
5202 
5203   Output Parameters:
5204 + v   - the vector for storing the maximums
5205 - idx - the indices of the column found for each row (or `NULL` if not needed)
5206 
5207   Level: intermediate
5208 
5209   Notes:
5210   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5211   row is 0 (the first column).
5212 
5213   This code is only implemented for a couple of matrix formats.
5214 
5215 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowSum()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5216 @*/
5217 PetscErrorCode MatGetRowMaxAbs(Mat mat, Vec v, PetscInt idx[])
5218 {
5219   PetscFunctionBegin;
5220   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5221   PetscValidType(mat, 1);
5222   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5223   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5224 
5225   if (!mat->cmap->N) {
5226     PetscCall(VecSet(v, 0.0));
5227     if (idx) {
5228       PetscInt i, m = mat->rmap->n;
5229       for (i = 0; i < m; i++) idx[i] = -1;
5230     }
5231   } else {
5232     MatCheckPreallocated(mat, 1);
5233     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5234     PetscUseTypeMethod(mat, getrowmaxabs, v, idx);
5235   }
5236   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5237   PetscFunctionReturn(PETSC_SUCCESS);
5238 }
5239 
5240 /*@
5241   MatGetRowSumAbs - Gets the sum value (in absolute value) of each row of the matrix
5242 
5243   Logically Collective
5244 
5245   Input Parameter:
5246 . mat - the matrix
5247 
5248   Output Parameter:
5249 . v - the vector for storing the sum
5250 
5251   Level: intermediate
5252 
5253   This code is only implemented for a couple of matrix formats.
5254 
5255 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5256 @*/
5257 PetscErrorCode MatGetRowSumAbs(Mat mat, Vec v)
5258 {
5259   PetscFunctionBegin;
5260   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5261   PetscValidType(mat, 1);
5262   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5263   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5264 
5265   if (!mat->cmap->N) {
5266     PetscCall(VecSet(v, 0.0));
5267   } else {
5268     MatCheckPreallocated(mat, 1);
5269     PetscUseTypeMethod(mat, getrowsumabs, v);
5270   }
5271   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5272   PetscFunctionReturn(PETSC_SUCCESS);
5273 }
5274 
5275 /*@
5276   MatGetRowSum - Gets the sum of each row of the matrix
5277 
5278   Logically or Neighborhood Collective
5279 
5280   Input Parameter:
5281 . mat - the matrix
5282 
5283   Output Parameter:
5284 . v - the vector for storing the sum of rows
5285 
5286   Level: intermediate
5287 
5288   Note:
5289   This code is slow since it is not currently specialized for different formats
5290 
5291 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`, `MatGetRowSumAbs()`
5292 @*/
5293 PetscErrorCode MatGetRowSum(Mat mat, Vec v)
5294 {
5295   Vec ones;
5296 
5297   PetscFunctionBegin;
5298   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5299   PetscValidType(mat, 1);
5300   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5301   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5302   MatCheckPreallocated(mat, 1);
5303   PetscCall(MatCreateVecs(mat, &ones, NULL));
5304   PetscCall(VecSet(ones, 1.));
5305   PetscCall(MatMult(mat, ones, v));
5306   PetscCall(VecDestroy(&ones));
5307   PetscFunctionReturn(PETSC_SUCCESS);
5308 }
5309 
5310 /*@
5311   MatTransposeSetPrecursor - Set the matrix from which the second matrix will receive numerical transpose data with a call to `MatTranspose`(A,`MAT_REUSE_MATRIX`,&B)
5312   when B was not obtained with `MatTranspose`(A,`MAT_INITIAL_MATRIX`,&B)
5313 
5314   Collective
5315 
5316   Input Parameter:
5317 . mat - the matrix to provide the transpose
5318 
5319   Output Parameter:
5320 . B - the matrix to contain the transpose; it MUST have the nonzero structure of the transpose of A or the code will crash or generate incorrect results
5321 
5322   Level: advanced
5323 
5324   Note:
5325   Normally the use of `MatTranspose`(A, `MAT_REUSE_MATRIX`, &B) requires that `B` was obtained with a call to `MatTranspose`(A, `MAT_INITIAL_MATRIX`, &B). This
5326   routine allows bypassing that call.
5327 
5328 .seealso: [](ch_matrices), `Mat`, `MatTransposeSymbolic()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5329 @*/
5330 PetscErrorCode MatTransposeSetPrecursor(Mat mat, Mat B)
5331 {
5332   MatParentState *rb = NULL;
5333 
5334   PetscFunctionBegin;
5335   PetscCall(PetscNew(&rb));
5336   rb->id    = ((PetscObject)mat)->id;
5337   rb->state = 0;
5338   PetscCall(MatGetNonzeroState(mat, &rb->nonzerostate));
5339   PetscCall(PetscObjectContainerCompose((PetscObject)B, "MatTransposeParent", rb, PetscCtxDestroyDefault));
5340   PetscFunctionReturn(PETSC_SUCCESS);
5341 }
5342 
5343 /*@
5344   MatTranspose - Computes the transpose of a matrix, either in-place or out-of-place.
5345 
5346   Collective
5347 
5348   Input Parameters:
5349 + mat   - the matrix to transpose
5350 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5351 
5352   Output Parameter:
5353 . B - the transpose of the matrix
5354 
5355   Level: intermediate
5356 
5357   Notes:
5358   If you use `MAT_INPLACE_MATRIX` then you must pass in `&mat` for `B`
5359 
5360   `MAT_REUSE_MATRIX` uses the `B` matrix obtained from a previous call to this function with `MAT_INITIAL_MATRIX` to store the transpose. If you already have a matrix to contain the
5361   transpose, call `MatTransposeSetPrecursor(mat, B)` before calling this routine.
5362 
5363   If the nonzero structure of `mat` changed from the previous call to this function with the same matrices an error will be generated for some matrix types.
5364 
5365   Consider using `MatCreateTranspose()` instead if you only need a matrix that behaves like the transpose but don't need the storage to be changed.
5366   For example, the result of `MatCreateTranspose()` will compute the transpose of the given matrix times a vector for matrix-vector products computed with `MatMult()`.
5367 
5368   If `mat` is unchanged from the last call this function returns immediately without recomputing the result
5369 
5370   If you only need the symbolic transpose of a matrix, and not the numerical values, use `MatTransposeSymbolic()`
5371 
5372 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`,
5373           `MatTransposeSymbolic()`, `MatCreateTranspose()`
5374 @*/
5375 PetscErrorCode MatTranspose(Mat mat, MatReuse reuse, Mat *B)
5376 {
5377   PetscContainer  rB = NULL;
5378   MatParentState *rb = NULL;
5379 
5380   PetscFunctionBegin;
5381   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5382   PetscValidType(mat, 1);
5383   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5384   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5385   PetscCheck(reuse != MAT_INPLACE_MATRIX || mat == *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires last matrix to match first");
5386   PetscCheck(reuse != MAT_REUSE_MATRIX || mat != *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Perhaps you mean MAT_INPLACE_MATRIX");
5387   MatCheckPreallocated(mat, 1);
5388   if (reuse == MAT_REUSE_MATRIX) {
5389     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5390     PetscCheck(rB, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose(). Suggest MatTransposeSetPrecursor().");
5391     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5392     PetscCheck(rb->id == ((PetscObject)mat)->id, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5393     if (rb->state == ((PetscObject)mat)->state) PetscFunctionReturn(PETSC_SUCCESS);
5394   }
5395 
5396   PetscCall(PetscLogEventBegin(MAT_Transpose, mat, 0, 0, 0));
5397   if (reuse != MAT_INPLACE_MATRIX || mat->symmetric != PETSC_BOOL3_TRUE) {
5398     PetscUseTypeMethod(mat, transpose, reuse, B);
5399     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5400   }
5401   PetscCall(PetscLogEventEnd(MAT_Transpose, mat, 0, 0, 0));
5402 
5403   if (reuse == MAT_INITIAL_MATRIX) PetscCall(MatTransposeSetPrecursor(mat, *B));
5404   if (reuse != MAT_INPLACE_MATRIX) {
5405     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5406     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5407     rb->state        = ((PetscObject)mat)->state;
5408     rb->nonzerostate = mat->nonzerostate;
5409   }
5410   PetscFunctionReturn(PETSC_SUCCESS);
5411 }
5412 
5413 /*@
5414   MatTransposeSymbolic - Computes the symbolic part of the transpose of a matrix.
5415 
5416   Collective
5417 
5418   Input Parameter:
5419 . A - the matrix to transpose
5420 
5421   Output Parameter:
5422 . B - the transpose. This is a complete matrix but the numerical portion is invalid. One can call `MatTranspose`(A,`MAT_REUSE_MATRIX`,&B) to compute the
5423       numerical portion.
5424 
5425   Level: intermediate
5426 
5427   Note:
5428   This is not supported for many matrix types, use `MatTranspose()` in those cases
5429 
5430 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5431 @*/
5432 PetscErrorCode MatTransposeSymbolic(Mat A, Mat *B)
5433 {
5434   PetscFunctionBegin;
5435   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5436   PetscValidType(A, 1);
5437   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5438   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5439   PetscCall(PetscLogEventBegin(MAT_Transpose, A, 0, 0, 0));
5440   PetscUseTypeMethod(A, transposesymbolic, B);
5441   PetscCall(PetscLogEventEnd(MAT_Transpose, A, 0, 0, 0));
5442 
5443   PetscCall(MatTransposeSetPrecursor(A, *B));
5444   PetscFunctionReturn(PETSC_SUCCESS);
5445 }
5446 
5447 PetscErrorCode MatTransposeCheckNonzeroState_Private(Mat A, Mat B)
5448 {
5449   PetscContainer  rB;
5450   MatParentState *rb;
5451 
5452   PetscFunctionBegin;
5453   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5454   PetscValidType(A, 1);
5455   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5456   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5457   PetscCall(PetscObjectQuery((PetscObject)B, "MatTransposeParent", (PetscObject *)&rB));
5458   PetscCheck(rB, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose()");
5459   PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5460   PetscCheck(rb->id == ((PetscObject)A)->id, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5461   PetscCheck(rb->nonzerostate == A->nonzerostate, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Reuse matrix has changed nonzero structure");
5462   PetscFunctionReturn(PETSC_SUCCESS);
5463 }
5464 
5465 /*@
5466   MatIsTranspose - Test whether a matrix is another one's transpose,
5467   or its own, in which case it tests symmetry.
5468 
5469   Collective
5470 
5471   Input Parameters:
5472 + A   - the matrix to test
5473 . B   - the matrix to test against, this can equal the first parameter
5474 - tol - tolerance, differences between entries smaller than this are counted as zero
5475 
5476   Output Parameter:
5477 . flg - the result
5478 
5479   Level: intermediate
5480 
5481   Notes:
5482   The sequential algorithm has a running time of the order of the number of nonzeros; the parallel
5483   test involves parallel copies of the block off-diagonal parts of the matrix.
5484 
5485 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`
5486 @*/
5487 PetscErrorCode MatIsTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5488 {
5489   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5490 
5491   PetscFunctionBegin;
5492   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5493   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5494   PetscAssertPointer(flg, 4);
5495   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsTranspose_C", &f));
5496   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsTranspose_C", &g));
5497   *flg = PETSC_FALSE;
5498   if (f && g) {
5499     PetscCheck(f == g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for symmetry test");
5500     PetscCall((*f)(A, B, tol, flg));
5501   } else {
5502     MatType mattype;
5503 
5504     PetscCall(MatGetType(f ? B : A, &mattype));
5505     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Matrix of type %s does not support checking for transpose", mattype);
5506   }
5507   PetscFunctionReturn(PETSC_SUCCESS);
5508 }
5509 
5510 /*@
5511   MatHermitianTranspose - Computes an in-place or out-of-place Hermitian transpose of a matrix in complex conjugate.
5512 
5513   Collective
5514 
5515   Input Parameters:
5516 + mat   - the matrix to transpose and complex conjugate
5517 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5518 
5519   Output Parameter:
5520 . B - the Hermitian transpose
5521 
5522   Level: intermediate
5523 
5524 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`
5525 @*/
5526 PetscErrorCode MatHermitianTranspose(Mat mat, MatReuse reuse, Mat *B)
5527 {
5528   PetscFunctionBegin;
5529   PetscCall(MatTranspose(mat, reuse, B));
5530 #if defined(PETSC_USE_COMPLEX)
5531   PetscCall(MatConjugate(*B));
5532 #endif
5533   PetscFunctionReturn(PETSC_SUCCESS);
5534 }
5535 
5536 /*@
5537   MatIsHermitianTranspose - Test whether a matrix is another one's Hermitian transpose,
5538 
5539   Collective
5540 
5541   Input Parameters:
5542 + A   - the matrix to test
5543 . B   - the matrix to test against, this can equal the first parameter
5544 - tol - tolerance, differences between entries smaller than this are counted as zero
5545 
5546   Output Parameter:
5547 . flg - the result
5548 
5549   Level: intermediate
5550 
5551   Notes:
5552   Only available for `MATAIJ` matrices.
5553 
5554   The sequential algorithm
5555   has a running time of the order of the number of nonzeros; the parallel
5556   test involves parallel copies of the block off-diagonal parts of the matrix.
5557 
5558 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsTranspose()`
5559 @*/
5560 PetscErrorCode MatIsHermitianTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5561 {
5562   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5563 
5564   PetscFunctionBegin;
5565   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5566   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5567   PetscAssertPointer(flg, 4);
5568   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsHermitianTranspose_C", &f));
5569   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsHermitianTranspose_C", &g));
5570   if (f && g) {
5571     PetscCheck(f != g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for Hermitian test");
5572     PetscCall((*f)(A, B, tol, flg));
5573   }
5574   PetscFunctionReturn(PETSC_SUCCESS);
5575 }
5576 
5577 /*@
5578   MatPermute - Creates a new matrix with rows and columns permuted from the
5579   original.
5580 
5581   Collective
5582 
5583   Input Parameters:
5584 + mat - the matrix to permute
5585 . row - row permutation, each processor supplies only the permutation for its rows
5586 - col - column permutation, each processor supplies only the permutation for its columns
5587 
5588   Output Parameter:
5589 . B - the permuted matrix
5590 
5591   Level: advanced
5592 
5593   Note:
5594   The index sets map from row/col of permuted matrix to row/col of original matrix.
5595   The index sets should be on the same communicator as mat and have the same local sizes.
5596 
5597   Developer Note:
5598   If you want to implement `MatPermute()` for a matrix type, and your approach doesn't
5599   exploit the fact that row and col are permutations, consider implementing the
5600   more general `MatCreateSubMatrix()` instead.
5601 
5602 .seealso: [](ch_matrices), `Mat`, `MatGetOrdering()`, `ISAllGather()`, `MatCreateSubMatrix()`
5603 @*/
5604 PetscErrorCode MatPermute(Mat mat, IS row, IS col, Mat *B)
5605 {
5606   PetscFunctionBegin;
5607   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5608   PetscValidType(mat, 1);
5609   PetscValidHeaderSpecific(row, IS_CLASSID, 2);
5610   PetscValidHeaderSpecific(col, IS_CLASSID, 3);
5611   PetscAssertPointer(B, 4);
5612   PetscCheckSameComm(mat, 1, row, 2);
5613   if (row != col) PetscCheckSameComm(row, 2, col, 3);
5614   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5615   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5616   PetscCheck(mat->ops->permute || mat->ops->createsubmatrix, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatPermute not available for Mat type %s", ((PetscObject)mat)->type_name);
5617   MatCheckPreallocated(mat, 1);
5618 
5619   if (mat->ops->permute) {
5620     PetscUseTypeMethod(mat, permute, row, col, B);
5621     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5622   } else {
5623     PetscCall(MatCreateSubMatrix(mat, row, col, MAT_INITIAL_MATRIX, B));
5624   }
5625   PetscFunctionReturn(PETSC_SUCCESS);
5626 }
5627 
5628 /*@
5629   MatEqual - Compares two matrices.
5630 
5631   Collective
5632 
5633   Input Parameters:
5634 + A - the first matrix
5635 - B - the second matrix
5636 
5637   Output Parameter:
5638 . flg - `PETSC_TRUE` if the matrices are equal; `PETSC_FALSE` otherwise.
5639 
5640   Level: intermediate
5641 
5642   Note:
5643   If either of the matrix is "matrix-free", meaning the matrix entries are not stored explicitly then equality is determined by comparing
5644   the results of several matrix-vector product using randomly created vectors, see `MatMultEqual()`.
5645 
5646 .seealso: [](ch_matrices), `Mat`, `MatMultEqual()`
5647 @*/
5648 PetscErrorCode MatEqual(Mat A, Mat B, PetscBool *flg)
5649 {
5650   PetscFunctionBegin;
5651   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5652   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5653   PetscValidType(A, 1);
5654   PetscValidType(B, 2);
5655   PetscAssertPointer(flg, 3);
5656   PetscCheckSameComm(A, 1, B, 2);
5657   MatCheckPreallocated(A, 1);
5658   MatCheckPreallocated(B, 2);
5659   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5660   PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5661   PetscCheck(A->rmap->N == B->rmap->N && A->cmap->N == B->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat B: global dim %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT, A->rmap->N, B->rmap->N, A->cmap->N,
5662              B->cmap->N);
5663   if (A->ops->equal && A->ops->equal == B->ops->equal) {
5664     PetscUseTypeMethod(A, equal, B, flg);
5665   } else {
5666     PetscCall(MatMultEqual(A, B, 10, flg));
5667   }
5668   PetscFunctionReturn(PETSC_SUCCESS);
5669 }
5670 
5671 /*@
5672   MatDiagonalScale - Scales a matrix on the left and right by diagonal
5673   matrices that are stored as vectors.  Either of the two scaling
5674   matrices can be `NULL`.
5675 
5676   Collective
5677 
5678   Input Parameters:
5679 + mat - the matrix to be scaled
5680 . l   - the left scaling vector (or `NULL`)
5681 - r   - the right scaling vector (or `NULL`)
5682 
5683   Level: intermediate
5684 
5685   Note:
5686   `MatDiagonalScale()` computes $A = LAR$, where
5687   L = a diagonal matrix (stored as a vector), R = a diagonal matrix (stored as a vector)
5688   The L scales the rows of the matrix, the R scales the columns of the matrix.
5689 
5690 .seealso: [](ch_matrices), `Mat`, `MatScale()`, `MatShift()`, `MatDiagonalSet()`
5691 @*/
5692 PetscErrorCode MatDiagonalScale(Mat mat, Vec l, Vec r)
5693 {
5694   PetscFunctionBegin;
5695   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5696   PetscValidType(mat, 1);
5697   if (l) {
5698     PetscValidHeaderSpecific(l, VEC_CLASSID, 2);
5699     PetscCheckSameComm(mat, 1, l, 2);
5700   }
5701   if (r) {
5702     PetscValidHeaderSpecific(r, VEC_CLASSID, 3);
5703     PetscCheckSameComm(mat, 1, r, 3);
5704   }
5705   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5706   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5707   MatCheckPreallocated(mat, 1);
5708   if (!l && !r) PetscFunctionReturn(PETSC_SUCCESS);
5709 
5710   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5711   PetscUseTypeMethod(mat, diagonalscale, l, r);
5712   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5713   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5714   if (l != r) mat->symmetric = PETSC_BOOL3_FALSE;
5715   PetscFunctionReturn(PETSC_SUCCESS);
5716 }
5717 
5718 /*@
5719   MatScale - Scales all elements of a matrix by a given number.
5720 
5721   Logically Collective
5722 
5723   Input Parameters:
5724 + mat - the matrix to be scaled
5725 - a   - the scaling value
5726 
5727   Level: intermediate
5728 
5729 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
5730 @*/
5731 PetscErrorCode MatScale(Mat mat, PetscScalar a)
5732 {
5733   PetscFunctionBegin;
5734   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5735   PetscValidType(mat, 1);
5736   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5737   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5738   PetscValidLogicalCollectiveScalar(mat, a, 2);
5739   MatCheckPreallocated(mat, 1);
5740 
5741   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5742   if (a != (PetscScalar)1.0) {
5743     PetscUseTypeMethod(mat, scale, a);
5744     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5745   }
5746   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5747   PetscFunctionReturn(PETSC_SUCCESS);
5748 }
5749 
5750 /*@
5751   MatNorm - Calculates various norms of a matrix.
5752 
5753   Collective
5754 
5755   Input Parameters:
5756 + mat  - the matrix
5757 - type - the type of norm, `NORM_1`, `NORM_FROBENIUS`, `NORM_INFINITY`
5758 
5759   Output Parameter:
5760 . nrm - the resulting norm
5761 
5762   Level: intermediate
5763 
5764 .seealso: [](ch_matrices), `Mat`
5765 @*/
5766 PetscErrorCode MatNorm(Mat mat, NormType type, PetscReal *nrm)
5767 {
5768   PetscFunctionBegin;
5769   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5770   PetscValidType(mat, 1);
5771   PetscAssertPointer(nrm, 3);
5772 
5773   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5774   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5775   MatCheckPreallocated(mat, 1);
5776 
5777   PetscUseTypeMethod(mat, norm, type, nrm);
5778   PetscFunctionReturn(PETSC_SUCCESS);
5779 }
5780 
5781 /*
5782      This variable is used to prevent counting of MatAssemblyBegin() that
5783    are called from within a MatAssemblyEnd().
5784 */
5785 static PetscInt MatAssemblyEnd_InUse = 0;
5786 /*@
5787   MatAssemblyBegin - Begins assembling the matrix.  This routine should
5788   be called after completing all calls to `MatSetValues()`.
5789 
5790   Collective
5791 
5792   Input Parameters:
5793 + mat  - the matrix
5794 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5795 
5796   Level: beginner
5797 
5798   Notes:
5799   `MatSetValues()` generally caches the values that belong to other MPI processes.  The matrix is ready to
5800   use only after `MatAssemblyBegin()` and `MatAssemblyEnd()` have been called.
5801 
5802   Use `MAT_FLUSH_ASSEMBLY` when switching between `ADD_VALUES` and `INSERT_VALUES`
5803   in `MatSetValues()`; use `MAT_FINAL_ASSEMBLY` for the final assembly before
5804   using the matrix.
5805 
5806   ALL processes that share a matrix MUST call `MatAssemblyBegin()` and `MatAssemblyEnd()` the SAME NUMBER of times, and each time with the
5807   same flag of `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY` for all processes. Thus you CANNOT locally change from `ADD_VALUES` to `INSERT_VALUES`, that is
5808   a global collective operation requiring all processes that share the matrix.
5809 
5810   Space for preallocated nonzeros that is not filled by a call to `MatSetValues()` or a related routine are compressed
5811   out by assembly. If you intend to use that extra space on a subsequent assembly, be sure to insert explicit zeros
5812   before `MAT_FINAL_ASSEMBLY` so the space is not compressed out.
5813 
5814 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssembled()`
5815 @*/
5816 PetscErrorCode MatAssemblyBegin(Mat mat, MatAssemblyType type)
5817 {
5818   PetscFunctionBegin;
5819   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5820   PetscValidType(mat, 1);
5821   MatCheckPreallocated(mat, 1);
5822   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix. Did you forget to call MatSetUnfactored()?");
5823   if (mat->assembled) {
5824     mat->was_assembled = PETSC_TRUE;
5825     mat->assembled     = PETSC_FALSE;
5826   }
5827 
5828   if (!MatAssemblyEnd_InUse) {
5829     PetscCall(PetscLogEventBegin(MAT_AssemblyBegin, mat, 0, 0, 0));
5830     PetscTryTypeMethod(mat, assemblybegin, type);
5831     PetscCall(PetscLogEventEnd(MAT_AssemblyBegin, mat, 0, 0, 0));
5832   } else PetscTryTypeMethod(mat, assemblybegin, type);
5833   PetscFunctionReturn(PETSC_SUCCESS);
5834 }
5835 
5836 /*@
5837   MatAssembled - Indicates if a matrix has been assembled and is ready for
5838   use; for example, in matrix-vector product.
5839 
5840   Not Collective
5841 
5842   Input Parameter:
5843 . mat - the matrix
5844 
5845   Output Parameter:
5846 . assembled - `PETSC_TRUE` or `PETSC_FALSE`
5847 
5848   Level: advanced
5849 
5850 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssemblyBegin()`
5851 @*/
5852 PetscErrorCode MatAssembled(Mat mat, PetscBool *assembled)
5853 {
5854   PetscFunctionBegin;
5855   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5856   PetscAssertPointer(assembled, 2);
5857   *assembled = mat->assembled;
5858   PetscFunctionReturn(PETSC_SUCCESS);
5859 }
5860 
5861 /*@
5862   MatAssemblyEnd - Completes assembling the matrix.  This routine should
5863   be called after `MatAssemblyBegin()`.
5864 
5865   Collective
5866 
5867   Input Parameters:
5868 + mat  - the matrix
5869 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5870 
5871   Options Database Keys:
5872 + -mat_view ::ascii_info             - Prints info on matrix at conclusion of `MatAssemblyEnd()`
5873 . -mat_view ::ascii_info_detail      - Prints more detailed info
5874 . -mat_view                          - Prints matrix in ASCII format
5875 . -mat_view ::ascii_matlab           - Prints matrix in MATLAB format
5876 . -mat_view draw                     - draws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
5877 . -display <name>                    - Sets display name (default is host)
5878 . -draw_pause <sec>                  - Sets number of seconds to pause after display
5879 . -mat_view socket                   - Sends matrix to socket, can be accessed from MATLAB (See [Using MATLAB with PETSc](ch_matlab))
5880 . -viewer_socket_machine <machine>   - Machine to use for socket
5881 . -viewer_socket_port <port>         - Port number to use for socket
5882 - -mat_view binary:filename[:append] - Save matrix to file in binary format
5883 
5884   Level: beginner
5885 
5886 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatSetValues()`, `PetscDrawOpenX()`, `PetscDrawCreate()`, `MatView()`, `MatAssembled()`, `PetscViewerSocketOpen()`
5887 @*/
5888 PetscErrorCode MatAssemblyEnd(Mat mat, MatAssemblyType type)
5889 {
5890   static PetscInt inassm = 0;
5891   PetscBool       flg    = PETSC_FALSE;
5892 
5893   PetscFunctionBegin;
5894   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5895   PetscValidType(mat, 1);
5896 
5897   inassm++;
5898   MatAssemblyEnd_InUse++;
5899   if (MatAssemblyEnd_InUse == 1) { /* Do the logging only the first time through */
5900     PetscCall(PetscLogEventBegin(MAT_AssemblyEnd, mat, 0, 0, 0));
5901     PetscTryTypeMethod(mat, assemblyend, type);
5902     PetscCall(PetscLogEventEnd(MAT_AssemblyEnd, mat, 0, 0, 0));
5903   } else PetscTryTypeMethod(mat, assemblyend, type);
5904 
5905   /* Flush assembly is not a true assembly */
5906   if (type != MAT_FLUSH_ASSEMBLY) {
5907     if (mat->num_ass) {
5908       if (!mat->symmetry_eternal) {
5909         mat->symmetric = PETSC_BOOL3_UNKNOWN;
5910         mat->hermitian = PETSC_BOOL3_UNKNOWN;
5911       }
5912       if (!mat->structural_symmetry_eternal && mat->ass_nonzerostate != mat->nonzerostate) mat->structurally_symmetric = PETSC_BOOL3_UNKNOWN;
5913       if (!mat->spd_eternal) mat->spd = PETSC_BOOL3_UNKNOWN;
5914     }
5915     mat->num_ass++;
5916     mat->assembled        = PETSC_TRUE;
5917     mat->ass_nonzerostate = mat->nonzerostate;
5918   }
5919 
5920   mat->insertmode = NOT_SET_VALUES;
5921   MatAssemblyEnd_InUse--;
5922   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5923   if (inassm == 1 && type != MAT_FLUSH_ASSEMBLY) {
5924     PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
5925 
5926     if (mat->checksymmetryonassembly) {
5927       PetscCall(MatIsSymmetric(mat, mat->checksymmetrytol, &flg));
5928       if (flg) {
5929         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5930       } else {
5931         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is not symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5932       }
5933     }
5934     if (mat->nullsp && mat->checknullspaceonassembly) PetscCall(MatNullSpaceTest(mat->nullsp, mat, NULL));
5935   }
5936   inassm--;
5937   PetscFunctionReturn(PETSC_SUCCESS);
5938 }
5939 
5940 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
5941 /*@
5942   MatSetOption - Sets a parameter option for a matrix. Some options
5943   may be specific to certain storage formats.  Some options
5944   determine how values will be inserted (or added). Sorted,
5945   row-oriented input will generally assemble the fastest. The default
5946   is row-oriented.
5947 
5948   Logically Collective for certain operations, such as `MAT_SPD`, not collective for `MAT_ROW_ORIENTED`, see `MatOption`
5949 
5950   Input Parameters:
5951 + mat - the matrix
5952 . op  - the option, one of those listed below (and possibly others),
5953 - flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
5954 
5955   Options Describing Matrix Structure:
5956 + `MAT_SPD`                         - symmetric positive definite
5957 . `MAT_SYMMETRIC`                   - symmetric in terms of both structure and value
5958 . `MAT_HERMITIAN`                   - transpose is the complex conjugation
5959 . `MAT_STRUCTURALLY_SYMMETRIC`      - symmetric nonzero structure
5960 . `MAT_SYMMETRY_ETERNAL`            - indicates the symmetry (or Hermitian structure) or its absence will persist through any changes to the matrix
5961 . `MAT_STRUCTURAL_SYMMETRY_ETERNAL` - indicates the structural symmetry or its absence will persist through any changes to the matrix
5962 . `MAT_SPD_ETERNAL`                 - indicates the value of `MAT_SPD` (true or false) will persist through any changes to the matrix
5963 
5964    These are not really options of the matrix, they are knowledge about the structure of the matrix that users may provide so that they
5965    do not need to be computed (usually at a high cost)
5966 
5967    Options For Use with `MatSetValues()`:
5968    Insert a logically dense subblock, which can be
5969 . `MAT_ROW_ORIENTED`                - row-oriented (default)
5970 
5971    These options reflect the data you pass in with `MatSetValues()`; it has
5972    nothing to do with how the data is stored internally in the matrix
5973    data structure.
5974 
5975    When (re)assembling a matrix, we can restrict the input for
5976    efficiency/debugging purposes.  These options include
5977 . `MAT_NEW_NONZERO_LOCATIONS`       - additional insertions will be allowed if they generate a new nonzero (slow)
5978 . `MAT_FORCE_DIAGONAL_ENTRIES`      - forces diagonal entries to be allocated
5979 . `MAT_IGNORE_OFF_PROC_ENTRIES`     - drops off-processor entries
5980 . `MAT_NEW_NONZERO_LOCATION_ERR`    - generates an error for new matrix entry
5981 . `MAT_USE_HASH_TABLE`              - uses a hash table to speed up matrix assembly
5982 . `MAT_NO_OFF_PROC_ENTRIES`         - you know each process will only set values for its own rows, will generate an error if
5983         any process sets values for another process. This avoids all reductions in the MatAssembly routines and thus improves
5984         performance for very large process counts.
5985 - `MAT_SUBSET_OFF_PROC_ENTRIES`     - you know that the first assembly after setting this flag will set a superset
5986         of the off-process entries required for all subsequent assemblies. This avoids a rendezvous step in the MatAssembly
5987         functions, instead sending only neighbor messages.
5988 
5989   Level: intermediate
5990 
5991   Notes:
5992   Except for `MAT_UNUSED_NONZERO_LOCATION_ERR` and  `MAT_ROW_ORIENTED` all processes that share the matrix must pass the same value in flg!
5993 
5994   Some options are relevant only for particular matrix types and
5995   are thus ignored by others.  Other options are not supported by
5996   certain matrix types and will generate an error message if set.
5997 
5998   If using Fortran to compute a matrix, one may need to
5999   use the column-oriented option (or convert to the row-oriented
6000   format).
6001 
6002   `MAT_NEW_NONZERO_LOCATIONS` set to `PETSC_FALSE` indicates that any add or insertion
6003   that would generate a new entry in the nonzero structure is instead
6004   ignored.  Thus, if memory has not already been allocated for this particular
6005   data, then the insertion is ignored. For dense matrices, in which
6006   the entire array is allocated, no entries are ever ignored.
6007   Set after the first `MatAssemblyEnd()`. If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
6008 
6009   `MAT_NEW_NONZERO_LOCATION_ERR` set to PETSC_TRUE indicates that any add or insertion
6010   that would generate a new entry in the nonzero structure instead produces
6011   an error. (Currently supported for `MATAIJ` and `MATBAIJ` formats only.) If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
6012 
6013   `MAT_NEW_NONZERO_ALLOCATION_ERR` set to `PETSC_TRUE` indicates that any add or insertion
6014   that would generate a new entry that has not been preallocated will
6015   instead produce an error. (Currently supported for `MATAIJ` and `MATBAIJ` formats
6016   only.) This is a useful flag when debugging matrix memory preallocation.
6017   If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
6018 
6019   `MAT_IGNORE_OFF_PROC_ENTRIES` set to `PETSC_TRUE` indicates entries destined for
6020   other processors should be dropped, rather than stashed.
6021   This is useful if you know that the "owning" processor is also
6022   always generating the correct matrix entries, so that PETSc need
6023   not transfer duplicate entries generated on another processor.
6024 
6025   `MAT_USE_HASH_TABLE` indicates that a hash table be used to improve the
6026   searches during matrix assembly. When this flag is set, the hash table
6027   is created during the first matrix assembly. This hash table is
6028   used the next time through, during `MatSetValues()`/`MatSetValuesBlocked()`
6029   to improve the searching of indices. `MAT_NEW_NONZERO_LOCATIONS` flag
6030   should be used with `MAT_USE_HASH_TABLE` flag. This option is currently
6031   supported by `MATMPIBAIJ` format only.
6032 
6033   `MAT_KEEP_NONZERO_PATTERN` indicates when `MatZeroRows()` is called the zeroed entries
6034   are kept in the nonzero structure. This flag is not used for `MatZeroRowsColumns()`
6035 
6036   `MAT_IGNORE_ZERO_ENTRIES` - for `MATAIJ` and `MATIS` matrices this will stop zero values from creating
6037   a zero location in the matrix
6038 
6039   `MAT_USE_INODES` - indicates using inode version of the code - works with `MATAIJ` matrix types
6040 
6041   `MAT_NO_OFF_PROC_ZERO_ROWS` - you know each process will only zero its own rows. This avoids all reductions in the
6042   zero row routines and thus improves performance for very large process counts.
6043 
6044   `MAT_IGNORE_LOWER_TRIANGULAR` - For `MATSBAIJ` matrices will ignore any insertions you make in the lower triangular
6045   part of the matrix (since they should match the upper triangular part).
6046 
6047   `MAT_SORTED_FULL` - each process provides exactly its local rows; all column indices for a given row are passed in a
6048   single call to `MatSetValues()`, preallocation is perfect, row-oriented, `INSERT_VALUES` is used. Common
6049   with finite difference schemes with non-periodic boundary conditions.
6050 
6051   Developer Note:
6052   `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, and `MAT_SPD_ETERNAL` are used by `MatAssemblyEnd()` and in other
6053   places where otherwise the value of `MAT_SYMMETRIC`, `MAT_STRUCTURALLY_SYMMETRIC` or `MAT_SPD` would need to be changed back
6054   to `PETSC_BOOL3_UNKNOWN` because the matrix values had changed so the code cannot be certain that the related property had
6055   not changed.
6056 
6057 .seealso: [](ch_matrices), `MatOption`, `Mat`, `MatGetOption()`
6058 @*/
6059 PetscErrorCode MatSetOption(Mat mat, MatOption op, PetscBool flg)
6060 {
6061   PetscFunctionBegin;
6062   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6063   if (op > 0) {
6064     PetscValidLogicalCollectiveEnum(mat, op, 2);
6065     PetscValidLogicalCollectiveBool(mat, flg, 3);
6066   }
6067 
6068   PetscCheck(((int)op) > MAT_OPTION_MIN && ((int)op) < MAT_OPTION_MAX, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Options %d is out of range", (int)op);
6069 
6070   switch (op) {
6071   case MAT_FORCE_DIAGONAL_ENTRIES:
6072     mat->force_diagonals = flg;
6073     PetscFunctionReturn(PETSC_SUCCESS);
6074   case MAT_NO_OFF_PROC_ENTRIES:
6075     mat->nooffprocentries = flg;
6076     PetscFunctionReturn(PETSC_SUCCESS);
6077   case MAT_SUBSET_OFF_PROC_ENTRIES:
6078     mat->assembly_subset = flg;
6079     if (!mat->assembly_subset) { /* See the same logic in VecAssembly wrt VEC_SUBSET_OFF_PROC_ENTRIES */
6080 #if !defined(PETSC_HAVE_MPIUNI)
6081       PetscCall(MatStashScatterDestroy_BTS(&mat->stash));
6082 #endif
6083       mat->stash.first_assembly_done = PETSC_FALSE;
6084     }
6085     PetscFunctionReturn(PETSC_SUCCESS);
6086   case MAT_NO_OFF_PROC_ZERO_ROWS:
6087     mat->nooffproczerorows = flg;
6088     PetscFunctionReturn(PETSC_SUCCESS);
6089   case MAT_SPD:
6090     if (flg) {
6091       mat->spd                    = PETSC_BOOL3_TRUE;
6092       mat->symmetric              = PETSC_BOOL3_TRUE;
6093       mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6094     } else {
6095       mat->spd = PETSC_BOOL3_FALSE;
6096     }
6097     break;
6098   case MAT_SYMMETRIC:
6099     mat->symmetric = PetscBoolToBool3(flg);
6100     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6101 #if !defined(PETSC_USE_COMPLEX)
6102     mat->hermitian = PetscBoolToBool3(flg);
6103 #endif
6104     break;
6105   case MAT_HERMITIAN:
6106     mat->hermitian = PetscBoolToBool3(flg);
6107     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6108 #if !defined(PETSC_USE_COMPLEX)
6109     mat->symmetric = PetscBoolToBool3(flg);
6110 #endif
6111     break;
6112   case MAT_STRUCTURALLY_SYMMETRIC:
6113     mat->structurally_symmetric = PetscBoolToBool3(flg);
6114     break;
6115   case MAT_SYMMETRY_ETERNAL:
6116     PetscCheck(mat->symmetric != PETSC_BOOL3_UNKNOWN, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot set MAT_SYMMETRY_ETERNAL without first setting MAT_SYMMETRIC to true or false");
6117     mat->symmetry_eternal = flg;
6118     if (flg) mat->structural_symmetry_eternal = PETSC_TRUE;
6119     break;
6120   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6121     PetscCheck(mat->structurally_symmetric != PETSC_BOOL3_UNKNOWN, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot set MAT_STRUCTURAL_SYMMETRY_ETERNAL without first setting MAT_STRUCTURALLY_SYMMETRIC to true or false");
6122     mat->structural_symmetry_eternal = flg;
6123     break;
6124   case MAT_SPD_ETERNAL:
6125     PetscCheck(mat->spd != PETSC_BOOL3_UNKNOWN, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot set MAT_SPD_ETERNAL without first setting MAT_SPD to true or false");
6126     mat->spd_eternal = flg;
6127     if (flg) {
6128       mat->structural_symmetry_eternal = PETSC_TRUE;
6129       mat->symmetry_eternal            = PETSC_TRUE;
6130     }
6131     break;
6132   case MAT_STRUCTURE_ONLY:
6133     mat->structure_only = flg;
6134     break;
6135   case MAT_SORTED_FULL:
6136     mat->sortedfull = flg;
6137     break;
6138   default:
6139     break;
6140   }
6141   PetscTryTypeMethod(mat, setoption, op, flg);
6142   PetscFunctionReturn(PETSC_SUCCESS);
6143 }
6144 
6145 /*@
6146   MatGetOption - Gets a parameter option that has been set for a matrix.
6147 
6148   Logically Collective
6149 
6150   Input Parameters:
6151 + mat - the matrix
6152 - op  - the option, this only responds to certain options, check the code for which ones
6153 
6154   Output Parameter:
6155 . flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
6156 
6157   Level: intermediate
6158 
6159   Notes:
6160   Can only be called after `MatSetSizes()` and `MatSetType()` have been set.
6161 
6162   Certain option values may be unknown, for those use the routines `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, or
6163   `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6164 
6165 .seealso: [](ch_matrices), `Mat`, `MatOption`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`,
6166     `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6167 @*/
6168 PetscErrorCode MatGetOption(Mat mat, MatOption op, PetscBool *flg)
6169 {
6170   PetscFunctionBegin;
6171   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6172   PetscValidType(mat, 1);
6173 
6174   PetscCheck(((int)op) > MAT_OPTION_MIN && ((int)op) < MAT_OPTION_MAX, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Options %d is out of range", (int)op);
6175   PetscCheck(((PetscObject)mat)->type_name, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_TYPENOTSET, "Cannot get options until type and size have been set, see MatSetType() and MatSetSizes()");
6176 
6177   switch (op) {
6178   case MAT_NO_OFF_PROC_ENTRIES:
6179     *flg = mat->nooffprocentries;
6180     break;
6181   case MAT_NO_OFF_PROC_ZERO_ROWS:
6182     *flg = mat->nooffproczerorows;
6183     break;
6184   case MAT_SYMMETRIC:
6185     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSymmetric() or MatIsSymmetricKnown()");
6186     break;
6187   case MAT_HERMITIAN:
6188     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsHermitian() or MatIsHermitianKnown()");
6189     break;
6190   case MAT_STRUCTURALLY_SYMMETRIC:
6191     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsStructurallySymmetric() or MatIsStructurallySymmetricKnown()");
6192     break;
6193   case MAT_SPD:
6194     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSPDKnown()");
6195     break;
6196   case MAT_SYMMETRY_ETERNAL:
6197     *flg = mat->symmetry_eternal;
6198     break;
6199   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6200     *flg = mat->symmetry_eternal;
6201     break;
6202   default:
6203     break;
6204   }
6205   PetscFunctionReturn(PETSC_SUCCESS);
6206 }
6207 
6208 /*@
6209   MatZeroEntries - Zeros all entries of a matrix.  For sparse matrices
6210   this routine retains the old nonzero structure.
6211 
6212   Logically Collective
6213 
6214   Input Parameter:
6215 . mat - the matrix
6216 
6217   Level: intermediate
6218 
6219   Note:
6220   If the matrix was not preallocated then a default, likely poor preallocation will be set in the matrix, so this should be called after the preallocation phase.
6221   See the Performance chapter of the users manual for information on preallocating matrices.
6222 
6223 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`
6224 @*/
6225 PetscErrorCode MatZeroEntries(Mat mat)
6226 {
6227   PetscFunctionBegin;
6228   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6229   PetscValidType(mat, 1);
6230   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6231   PetscCheck(mat->insertmode == NOT_SET_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for matrices where you have set values but not yet assembled");
6232   MatCheckPreallocated(mat, 1);
6233 
6234   PetscCall(PetscLogEventBegin(MAT_ZeroEntries, mat, 0, 0, 0));
6235   PetscUseTypeMethod(mat, zeroentries);
6236   PetscCall(PetscLogEventEnd(MAT_ZeroEntries, mat, 0, 0, 0));
6237   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6238   PetscFunctionReturn(PETSC_SUCCESS);
6239 }
6240 
6241 /*@
6242   MatZeroRowsColumns - Zeros all entries (except possibly the main diagonal)
6243   of a set of rows and columns of a matrix.
6244 
6245   Collective
6246 
6247   Input Parameters:
6248 + mat     - the matrix
6249 . numRows - the number of rows/columns to zero
6250 . rows    - the global row indices
6251 . diag    - value put in the diagonal of the eliminated rows
6252 . x       - optional vector of the solution for zeroed rows (other entries in vector are not used), these must be set before this call
6253 - b       - optional vector of the right-hand side, that will be adjusted by provided solution entries
6254 
6255   Level: intermediate
6256 
6257   Notes:
6258   This routine, along with `MatZeroRows()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6259 
6260   For each zeroed row, the value of the corresponding `b` is set to diag times the value of the corresponding `x`.
6261   The other entries of `b` will be adjusted by the known values of `x` times the corresponding matrix entries in the columns that are being eliminated
6262 
6263   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6264   Krylov method to take advantage of the known solution on the zeroed rows.
6265 
6266   For the parallel case, all processes that share the matrix (i.e.,
6267   those in the communicator used for matrix creation) MUST call this
6268   routine, regardless of whether any rows being zeroed are owned by
6269   them.
6270 
6271   Unlike `MatZeroRows()`, this ignores the `MAT_KEEP_NONZERO_PATTERN` option value set with `MatSetOption()`, it merely zeros those entries in the matrix, but never
6272   removes them from the nonzero pattern. The nonzero pattern of the matrix can still change if a nonzero needs to be inserted on a diagonal entry that was previously
6273   missing.
6274 
6275   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6276   list only rows local to itself).
6277 
6278   The option `MAT_NO_OFF_PROC_ZERO_ROWS` does not apply to this routine.
6279 
6280 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRows()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6281           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6282 @*/
6283 PetscErrorCode MatZeroRowsColumns(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6284 {
6285   PetscFunctionBegin;
6286   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6287   PetscValidType(mat, 1);
6288   if (numRows) PetscAssertPointer(rows, 3);
6289   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6290   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6291   MatCheckPreallocated(mat, 1);
6292 
6293   PetscUseTypeMethod(mat, zerorowscolumns, numRows, rows, diag, x, b);
6294   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6295   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6296   PetscFunctionReturn(PETSC_SUCCESS);
6297 }
6298 
6299 /*@
6300   MatZeroRowsColumnsIS - Zeros all entries (except possibly the main diagonal)
6301   of a set of rows and columns of a matrix.
6302 
6303   Collective
6304 
6305   Input Parameters:
6306 + mat  - the matrix
6307 . is   - the rows to zero
6308 . diag - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6309 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6310 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6311 
6312   Level: intermediate
6313 
6314   Note:
6315   See `MatZeroRowsColumns()` for details on how this routine operates.
6316 
6317 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6318           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRows()`, `MatZeroRowsColumnsStencil()`
6319 @*/
6320 PetscErrorCode MatZeroRowsColumnsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6321 {
6322   PetscInt        numRows;
6323   const PetscInt *rows;
6324 
6325   PetscFunctionBegin;
6326   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6327   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6328   PetscValidType(mat, 1);
6329   PetscValidType(is, 2);
6330   PetscCall(ISGetLocalSize(is, &numRows));
6331   PetscCall(ISGetIndices(is, &rows));
6332   PetscCall(MatZeroRowsColumns(mat, numRows, rows, diag, x, b));
6333   PetscCall(ISRestoreIndices(is, &rows));
6334   PetscFunctionReturn(PETSC_SUCCESS);
6335 }
6336 
6337 /*@
6338   MatZeroRows - Zeros all entries (except possibly the main diagonal)
6339   of a set of rows of a matrix.
6340 
6341   Collective
6342 
6343   Input Parameters:
6344 + mat     - the matrix
6345 . numRows - the number of rows to zero
6346 . rows    - the global row indices
6347 . diag    - value put in the diagonal of the zeroed rows
6348 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used), these must be set before this call
6349 - b       - optional vector of right-hand side, that will be adjusted by provided solution entries
6350 
6351   Level: intermediate
6352 
6353   Notes:
6354   This routine, along with `MatZeroRowsColumns()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6355 
6356   For each zeroed row, the value of the corresponding `b` is set to `diag` times the value of the corresponding `x`.
6357 
6358   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6359   Krylov method to take advantage of the known solution on the zeroed rows.
6360 
6361   May be followed by using a `PC` of type `PCREDISTRIBUTE` to solve the reduced problem (`PCDISTRIBUTE` completely eliminates the zeroed rows and their corresponding columns)
6362   from the matrix.
6363 
6364   Unlike `MatZeroRowsColumns()` for the `MATAIJ` and `MATBAIJ` matrix formats this removes the old nonzero structure, from the eliminated rows of the matrix
6365   but does not release memory.  Because of this removal matrix-vector products with the adjusted matrix will be a bit faster. For the dense
6366   formats this does not alter the nonzero structure.
6367 
6368   If the option `MatSetOption`(mat,`MAT_KEEP_NONZERO_PATTERN`,`PETSC_TRUE`) the nonzero structure
6369   of the matrix is not changed the values are
6370   merely zeroed.
6371 
6372   The user can set a value in the diagonal entry (or for the `MATAIJ` format
6373   formats can optionally remove the main diagonal entry from the
6374   nonzero structure as well, by passing 0.0 as the final argument).
6375 
6376   For the parallel case, all processes that share the matrix (i.e.,
6377   those in the communicator used for matrix creation) MUST call this
6378   routine, regardless of whether any rows being zeroed are owned by
6379   them.
6380 
6381   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6382   list only rows local to itself).
6383 
6384   You can call `MatSetOption`(mat,`MAT_NO_OFF_PROC_ZERO_ROWS`,`PETSC_TRUE`) if each process indicates only rows it
6385   owns that are to be zeroed. This saves a global synchronization in the implementation.
6386 
6387 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6388           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`, `PCREDISTRIBUTE`, `MAT_KEEP_NONZERO_PATTERN`
6389 @*/
6390 PetscErrorCode MatZeroRows(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6391 {
6392   PetscFunctionBegin;
6393   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6394   PetscValidType(mat, 1);
6395   if (numRows) PetscAssertPointer(rows, 3);
6396   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6397   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6398   MatCheckPreallocated(mat, 1);
6399 
6400   PetscUseTypeMethod(mat, zerorows, numRows, rows, diag, x, b);
6401   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6402   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6403   PetscFunctionReturn(PETSC_SUCCESS);
6404 }
6405 
6406 /*@
6407   MatZeroRowsIS - Zeros all entries (except possibly the main diagonal)
6408   of a set of rows of a matrix indicated by an `IS`
6409 
6410   Collective
6411 
6412   Input Parameters:
6413 + mat  - the matrix
6414 . is   - index set, `IS`, of rows to remove (if `NULL` then no row is removed)
6415 . diag - value put in all diagonals of eliminated rows
6416 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6417 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6418 
6419   Level: intermediate
6420 
6421   Note:
6422   See `MatZeroRows()` for details on how this routine operates.
6423 
6424 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6425           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`, `IS`
6426 @*/
6427 PetscErrorCode MatZeroRowsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6428 {
6429   PetscInt        numRows = 0;
6430   const PetscInt *rows    = NULL;
6431 
6432   PetscFunctionBegin;
6433   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6434   PetscValidType(mat, 1);
6435   if (is) {
6436     PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6437     PetscCall(ISGetLocalSize(is, &numRows));
6438     PetscCall(ISGetIndices(is, &rows));
6439   }
6440   PetscCall(MatZeroRows(mat, numRows, rows, diag, x, b));
6441   if (is) PetscCall(ISRestoreIndices(is, &rows));
6442   PetscFunctionReturn(PETSC_SUCCESS);
6443 }
6444 
6445 /*@
6446   MatZeroRowsStencil - Zeros all entries (except possibly the main diagonal)
6447   of a set of rows of a matrix indicated by a `MatStencil`. These rows must be local to the process.
6448 
6449   Collective
6450 
6451   Input Parameters:
6452 + mat     - the matrix
6453 . numRows - the number of rows to remove
6454 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows indicated by an array of `MatStencil`
6455 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6456 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6457 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6458 
6459   Level: intermediate
6460 
6461   Notes:
6462   See `MatZeroRows()` for details on how this routine operates.
6463 
6464   The grid coordinates are across the entire grid, not just the local portion
6465 
6466   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6467   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6468   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6469   `DM_BOUNDARY_PERIODIC` boundary type.
6470 
6471   For indices that don't mean anything for your case (like the `k` index when working in 2d) or the `c` index when you have
6472   a single value per point) you can skip filling those indices.
6473 
6474   Fortran Note:
6475   `idxm` and `idxn` should be declared as
6476 .vb
6477     MatStencil idxm(4, m)
6478 .ve
6479   and the values inserted using
6480 .vb
6481     idxm(MatStencil_i, 1) = i
6482     idxm(MatStencil_j, 1) = j
6483     idxm(MatStencil_k, 1) = k
6484     idxm(MatStencil_c, 1) = c
6485    etc
6486 .ve
6487 
6488 .seealso: [](ch_matrices), `Mat`, `MatStencil`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRows()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6489           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6490 @*/
6491 PetscErrorCode MatZeroRowsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6492 {
6493   PetscInt  dim    = mat->stencil.dim;
6494   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6495   PetscInt *dims   = mat->stencil.dims + 1;
6496   PetscInt *starts = mat->stencil.starts;
6497   PetscInt *dxm    = (PetscInt *)rows;
6498   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6499 
6500   PetscFunctionBegin;
6501   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6502   PetscValidType(mat, 1);
6503   if (numRows) PetscAssertPointer(rows, 3);
6504 
6505   PetscCall(PetscMalloc1(numRows, &jdxm));
6506   for (i = 0; i < numRows; ++i) {
6507     /* Skip unused dimensions (they are ordered k, j, i, c) */
6508     for (j = 0; j < 3 - sdim; ++j) dxm++;
6509     /* Local index in X dir */
6510     tmp = *dxm++ - starts[0];
6511     /* Loop over remaining dimensions */
6512     for (j = 0; j < dim - 1; ++j) {
6513       /* If nonlocal, set index to be negative */
6514       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6515       /* Update local index */
6516       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6517     }
6518     /* Skip component slot if necessary */
6519     if (mat->stencil.noc) dxm++;
6520     /* Local row number */
6521     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6522   }
6523   PetscCall(MatZeroRowsLocal(mat, numNewRows, jdxm, diag, x, b));
6524   PetscCall(PetscFree(jdxm));
6525   PetscFunctionReturn(PETSC_SUCCESS);
6526 }
6527 
6528 /*@
6529   MatZeroRowsColumnsStencil - Zeros all row and column entries (except possibly the main diagonal)
6530   of a set of rows and columns of a matrix.
6531 
6532   Collective
6533 
6534   Input Parameters:
6535 + mat     - the matrix
6536 . numRows - the number of rows/columns to remove
6537 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows
6538 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6539 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6540 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6541 
6542   Level: intermediate
6543 
6544   Notes:
6545   See `MatZeroRowsColumns()` for details on how this routine operates.
6546 
6547   The grid coordinates are across the entire grid, not just the local portion
6548 
6549   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6550   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6551   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6552   `DM_BOUNDARY_PERIODIC` boundary type.
6553 
6554   For indices that don't mean anything for your case (like the `k` index when working in 2d) or the `c` index when you have
6555   a single value per point) you can skip filling those indices.
6556 
6557   Fortran Note:
6558   `idxm` and `idxn` should be declared as
6559 .vb
6560     MatStencil idxm(4, m)
6561 .ve
6562   and the values inserted using
6563 .vb
6564     idxm(MatStencil_i, 1) = i
6565     idxm(MatStencil_j, 1) = j
6566     idxm(MatStencil_k, 1) = k
6567     idxm(MatStencil_c, 1) = c
6568     etc
6569 .ve
6570 
6571 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6572           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRows()`
6573 @*/
6574 PetscErrorCode MatZeroRowsColumnsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6575 {
6576   PetscInt  dim    = mat->stencil.dim;
6577   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6578   PetscInt *dims   = mat->stencil.dims + 1;
6579   PetscInt *starts = mat->stencil.starts;
6580   PetscInt *dxm    = (PetscInt *)rows;
6581   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6582 
6583   PetscFunctionBegin;
6584   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6585   PetscValidType(mat, 1);
6586   if (numRows) PetscAssertPointer(rows, 3);
6587 
6588   PetscCall(PetscMalloc1(numRows, &jdxm));
6589   for (i = 0; i < numRows; ++i) {
6590     /* Skip unused dimensions (they are ordered k, j, i, c) */
6591     for (j = 0; j < 3 - sdim; ++j) dxm++;
6592     /* Local index in X dir */
6593     tmp = *dxm++ - starts[0];
6594     /* Loop over remaining dimensions */
6595     for (j = 0; j < dim - 1; ++j) {
6596       /* If nonlocal, set index to be negative */
6597       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6598       /* Update local index */
6599       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6600     }
6601     /* Skip component slot if necessary */
6602     if (mat->stencil.noc) dxm++;
6603     /* Local row number */
6604     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6605   }
6606   PetscCall(MatZeroRowsColumnsLocal(mat, numNewRows, jdxm, diag, x, b));
6607   PetscCall(PetscFree(jdxm));
6608   PetscFunctionReturn(PETSC_SUCCESS);
6609 }
6610 
6611 /*@
6612   MatZeroRowsLocal - Zeros all entries (except possibly the main diagonal)
6613   of a set of rows of a matrix; using local numbering of rows.
6614 
6615   Collective
6616 
6617   Input Parameters:
6618 + mat     - the matrix
6619 . numRows - the number of rows to remove
6620 . rows    - the local row indices
6621 . diag    - value put in all diagonals of eliminated rows
6622 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6623 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6624 
6625   Level: intermediate
6626 
6627   Notes:
6628   Before calling `MatZeroRowsLocal()`, the user must first set the
6629   local-to-global mapping by calling MatSetLocalToGlobalMapping(), this is often already set for matrices obtained with `DMCreateMatrix()`.
6630 
6631   See `MatZeroRows()` for details on how this routine operates.
6632 
6633 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRows()`, `MatSetOption()`,
6634           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6635 @*/
6636 PetscErrorCode MatZeroRowsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6637 {
6638   PetscFunctionBegin;
6639   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6640   PetscValidType(mat, 1);
6641   if (numRows) PetscAssertPointer(rows, 3);
6642   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6643   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6644   MatCheckPreallocated(mat, 1);
6645 
6646   if (mat->ops->zerorowslocal) {
6647     PetscUseTypeMethod(mat, zerorowslocal, numRows, rows, diag, x, b);
6648   } else {
6649     IS        is, newis;
6650     PetscInt *newRows, nl = 0;
6651 
6652     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6653     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_USE_POINTER, &is));
6654     PetscCall(ISLocalToGlobalMappingApplyIS(mat->rmap->mapping, is, &newis));
6655     PetscCall(ISGetIndices(newis, (const PetscInt **)&newRows));
6656     for (PetscInt i = 0; i < numRows; i++)
6657       if (newRows[i] > -1) newRows[nl++] = newRows[i];
6658     PetscUseTypeMethod(mat, zerorows, nl, newRows, diag, x, b);
6659     PetscCall(ISRestoreIndices(newis, (const PetscInt **)&newRows));
6660     PetscCall(ISDestroy(&newis));
6661     PetscCall(ISDestroy(&is));
6662   }
6663   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6664   PetscFunctionReturn(PETSC_SUCCESS);
6665 }
6666 
6667 /*@
6668   MatZeroRowsLocalIS - Zeros all entries (except possibly the main diagonal)
6669   of a set of rows of a matrix; using local numbering of rows.
6670 
6671   Collective
6672 
6673   Input Parameters:
6674 + mat  - the matrix
6675 . is   - index set of rows to remove
6676 . diag - value put in all diagonals of eliminated rows
6677 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6678 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6679 
6680   Level: intermediate
6681 
6682   Notes:
6683   Before calling `MatZeroRowsLocalIS()`, the user must first set the
6684   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6685 
6686   See `MatZeroRows()` for details on how this routine operates.
6687 
6688 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRows()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6689           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6690 @*/
6691 PetscErrorCode MatZeroRowsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6692 {
6693   PetscInt        numRows;
6694   const PetscInt *rows;
6695 
6696   PetscFunctionBegin;
6697   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6698   PetscValidType(mat, 1);
6699   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6700   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6701   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6702   MatCheckPreallocated(mat, 1);
6703 
6704   PetscCall(ISGetLocalSize(is, &numRows));
6705   PetscCall(ISGetIndices(is, &rows));
6706   PetscCall(MatZeroRowsLocal(mat, numRows, rows, diag, x, b));
6707   PetscCall(ISRestoreIndices(is, &rows));
6708   PetscFunctionReturn(PETSC_SUCCESS);
6709 }
6710 
6711 /*@
6712   MatZeroRowsColumnsLocal - Zeros all entries (except possibly the main diagonal)
6713   of a set of rows and columns of a matrix; using local numbering of rows.
6714 
6715   Collective
6716 
6717   Input Parameters:
6718 + mat     - the matrix
6719 . numRows - the number of rows to remove
6720 . rows    - the global row indices
6721 . diag    - value put in all diagonals of eliminated rows
6722 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6723 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6724 
6725   Level: intermediate
6726 
6727   Notes:
6728   Before calling `MatZeroRowsColumnsLocal()`, the user must first set the
6729   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6730 
6731   See `MatZeroRowsColumns()` for details on how this routine operates.
6732 
6733 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6734           `MatZeroRows()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6735 @*/
6736 PetscErrorCode MatZeroRowsColumnsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6737 {
6738   PetscFunctionBegin;
6739   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6740   PetscValidType(mat, 1);
6741   if (numRows) PetscAssertPointer(rows, 3);
6742   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6743   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6744   MatCheckPreallocated(mat, 1);
6745 
6746   if (mat->ops->zerorowscolumnslocal) {
6747     PetscUseTypeMethod(mat, zerorowscolumnslocal, numRows, rows, diag, x, b);
6748   } else {
6749     IS        is, newis;
6750     PetscInt *newRows, nl = 0;
6751 
6752     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6753     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_USE_POINTER, &is));
6754     PetscCall(ISLocalToGlobalMappingApplyIS(mat->rmap->mapping, is, &newis));
6755     PetscCall(ISGetIndices(newis, (const PetscInt **)&newRows));
6756     for (PetscInt i = 0; i < numRows; i++)
6757       if (newRows[i] > -1) newRows[nl++] = newRows[i];
6758     PetscUseTypeMethod(mat, zerorowscolumns, nl, newRows, diag, x, b);
6759     PetscCall(ISRestoreIndices(newis, (const PetscInt **)&newRows));
6760     PetscCall(ISDestroy(&newis));
6761     PetscCall(ISDestroy(&is));
6762   }
6763   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6764   PetscFunctionReturn(PETSC_SUCCESS);
6765 }
6766 
6767 /*@
6768   MatZeroRowsColumnsLocalIS - Zeros all entries (except possibly the main diagonal)
6769   of a set of rows and columns of a matrix; using local numbering of rows.
6770 
6771   Collective
6772 
6773   Input Parameters:
6774 + mat  - the matrix
6775 . is   - index set of rows to remove
6776 . diag - value put in all diagonals of eliminated rows
6777 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6778 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6779 
6780   Level: intermediate
6781 
6782   Notes:
6783   Before calling `MatZeroRowsColumnsLocalIS()`, the user must first set the
6784   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6785 
6786   See `MatZeroRowsColumns()` for details on how this routine operates.
6787 
6788 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6789           `MatZeroRowsColumnsLocal()`, `MatZeroRows()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6790 @*/
6791 PetscErrorCode MatZeroRowsColumnsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6792 {
6793   PetscInt        numRows;
6794   const PetscInt *rows;
6795 
6796   PetscFunctionBegin;
6797   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6798   PetscValidType(mat, 1);
6799   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6800   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6801   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6802   MatCheckPreallocated(mat, 1);
6803 
6804   PetscCall(ISGetLocalSize(is, &numRows));
6805   PetscCall(ISGetIndices(is, &rows));
6806   PetscCall(MatZeroRowsColumnsLocal(mat, numRows, rows, diag, x, b));
6807   PetscCall(ISRestoreIndices(is, &rows));
6808   PetscFunctionReturn(PETSC_SUCCESS);
6809 }
6810 
6811 /*@
6812   MatGetSize - Returns the numbers of rows and columns in a matrix.
6813 
6814   Not Collective
6815 
6816   Input Parameter:
6817 . mat - the matrix
6818 
6819   Output Parameters:
6820 + m - the number of global rows
6821 - n - the number of global columns
6822 
6823   Level: beginner
6824 
6825   Note:
6826   Both output parameters can be `NULL` on input.
6827 
6828 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetLocalSize()`
6829 @*/
6830 PetscErrorCode MatGetSize(Mat mat, PetscInt *m, PetscInt *n)
6831 {
6832   PetscFunctionBegin;
6833   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6834   if (m) *m = mat->rmap->N;
6835   if (n) *n = mat->cmap->N;
6836   PetscFunctionReturn(PETSC_SUCCESS);
6837 }
6838 
6839 /*@
6840   MatGetLocalSize - For most matrix formats, excluding `MATELEMENTAL` and `MATSCALAPACK`, Returns the number of local rows and local columns
6841   of a matrix. For all matrices this is the local size of the left and right vectors as returned by `MatCreateVecs()`.
6842 
6843   Not Collective
6844 
6845   Input Parameter:
6846 . mat - the matrix
6847 
6848   Output Parameters:
6849 + m - the number of local rows, use `NULL` to not obtain this value
6850 - n - the number of local columns, use `NULL` to not obtain this value
6851 
6852   Level: beginner
6853 
6854 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetSize()`
6855 @*/
6856 PetscErrorCode MatGetLocalSize(Mat mat, PetscInt *m, PetscInt *n)
6857 {
6858   PetscFunctionBegin;
6859   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6860   if (m) PetscAssertPointer(m, 2);
6861   if (n) PetscAssertPointer(n, 3);
6862   if (m) *m = mat->rmap->n;
6863   if (n) *n = mat->cmap->n;
6864   PetscFunctionReturn(PETSC_SUCCESS);
6865 }
6866 
6867 /*@
6868   MatGetOwnershipRangeColumn - Returns the range of matrix columns associated with rows of a
6869   vector one multiplies this matrix by that are owned by this processor.
6870 
6871   Not Collective, unless matrix has not been allocated, then collective
6872 
6873   Input Parameter:
6874 . mat - the matrix
6875 
6876   Output Parameters:
6877 + m - the global index of the first local column, use `NULL` to not obtain this value
6878 - n - one more than the global index of the last local column, use `NULL` to not obtain this value
6879 
6880   Level: developer
6881 
6882   Notes:
6883   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6884 
6885   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6886   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6887 
6888   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6889   the local values in the matrix.
6890 
6891   Returns the columns of the "diagonal block" for most sparse matrix formats. See [Matrix
6892   Layouts](sec_matlayout) for details on matrix layouts.
6893 
6894 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6895           `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6896 @*/
6897 PetscErrorCode MatGetOwnershipRangeColumn(Mat mat, PetscInt *m, PetscInt *n)
6898 {
6899   PetscFunctionBegin;
6900   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6901   PetscValidType(mat, 1);
6902   if (m) PetscAssertPointer(m, 2);
6903   if (n) PetscAssertPointer(n, 3);
6904   MatCheckPreallocated(mat, 1);
6905   if (m) *m = mat->cmap->rstart;
6906   if (n) *n = mat->cmap->rend;
6907   PetscFunctionReturn(PETSC_SUCCESS);
6908 }
6909 
6910 /*@
6911   MatGetOwnershipRange - For matrices that own values by row, excludes `MATELEMENTAL` and `MATSCALAPACK`, returns the range of matrix rows owned by
6912   this MPI process.
6913 
6914   Not Collective
6915 
6916   Input Parameter:
6917 . mat - the matrix
6918 
6919   Output Parameters:
6920 + m - the global index of the first local row, use `NULL` to not obtain this value
6921 - n - one more than the global index of the last local row, use `NULL` to not obtain this value
6922 
6923   Level: beginner
6924 
6925   Notes:
6926   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6927 
6928   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6929   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6930 
6931   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6932   the local values in the matrix.
6933 
6934   The high argument is one more than the last element stored locally.
6935 
6936   For all matrices  it returns the range of matrix rows associated with rows of a vector that
6937   would contain the result of a matrix vector product with this matrix. See [Matrix
6938   Layouts](sec_matlayout) for details on matrix layouts.
6939 
6940 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscSplitOwnership()`,
6941           `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6942 @*/
6943 PetscErrorCode MatGetOwnershipRange(Mat mat, PetscInt *m, PetscInt *n)
6944 {
6945   PetscFunctionBegin;
6946   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6947   PetscValidType(mat, 1);
6948   if (m) PetscAssertPointer(m, 2);
6949   if (n) PetscAssertPointer(n, 3);
6950   MatCheckPreallocated(mat, 1);
6951   if (m) *m = mat->rmap->rstart;
6952   if (n) *n = mat->rmap->rend;
6953   PetscFunctionReturn(PETSC_SUCCESS);
6954 }
6955 
6956 /*@C
6957   MatGetOwnershipRanges - For matrices that own values by row, excludes `MATELEMENTAL` and
6958   `MATSCALAPACK`, returns the range of matrix rows owned by each process.
6959 
6960   Not Collective, unless matrix has not been allocated
6961 
6962   Input Parameter:
6963 . mat - the matrix
6964 
6965   Output Parameter:
6966 . ranges - start of each processors portion plus one more than the total length at the end, of length `size` + 1
6967            where `size` is the number of MPI processes used by `mat`
6968 
6969   Level: beginner
6970 
6971   Notes:
6972   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6973 
6974   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6975   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6976 
6977   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6978   the local values in the matrix.
6979 
6980   For all matrices  it returns the ranges of matrix rows associated with rows of a vector that
6981   would contain the result of a matrix vector product with this matrix. See [Matrix
6982   Layouts](sec_matlayout) for details on matrix layouts.
6983 
6984 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6985           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `MatSetSizes()`, `MatCreateAIJ()`,
6986           `DMDAGetGhostCorners()`, `DM`
6987 @*/
6988 PetscErrorCode MatGetOwnershipRanges(Mat mat, const PetscInt *ranges[])
6989 {
6990   PetscFunctionBegin;
6991   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6992   PetscValidType(mat, 1);
6993   MatCheckPreallocated(mat, 1);
6994   PetscCall(PetscLayoutGetRanges(mat->rmap, ranges));
6995   PetscFunctionReturn(PETSC_SUCCESS);
6996 }
6997 
6998 /*@C
6999   MatGetOwnershipRangesColumn - Returns the ranges of matrix columns associated with rows of a
7000   vector one multiplies this vector by that are owned by each processor.
7001 
7002   Not Collective, unless matrix has not been allocated
7003 
7004   Input Parameter:
7005 . mat - the matrix
7006 
7007   Output Parameter:
7008 . ranges - start of each processors portion plus one more than the total length at the end
7009 
7010   Level: beginner
7011 
7012   Notes:
7013   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
7014 
7015   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
7016   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
7017 
7018   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
7019   the local values in the matrix.
7020 
7021   Returns the columns of the "diagonal blocks", for most sparse matrix formats. See [Matrix
7022   Layouts](sec_matlayout) for details on matrix layouts.
7023 
7024 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRanges()`,
7025           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`,
7026           `DMDAGetGhostCorners()`, `DM`
7027 @*/
7028 PetscErrorCode MatGetOwnershipRangesColumn(Mat mat, const PetscInt *ranges[])
7029 {
7030   PetscFunctionBegin;
7031   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7032   PetscValidType(mat, 1);
7033   MatCheckPreallocated(mat, 1);
7034   PetscCall(PetscLayoutGetRanges(mat->cmap, ranges));
7035   PetscFunctionReturn(PETSC_SUCCESS);
7036 }
7037 
7038 /*@
7039   MatGetOwnershipIS - Get row and column ownership of a matrices' values as index sets.
7040 
7041   Not Collective
7042 
7043   Input Parameter:
7044 . A - matrix
7045 
7046   Output Parameters:
7047 + rows - rows in which this process owns elements, , use `NULL` to not obtain this value
7048 - cols - columns in which this process owns elements, use `NULL` to not obtain this value
7049 
7050   Level: intermediate
7051 
7052   Note:
7053   You should call `ISDestroy()` on the returned `IS`
7054 
7055   For most matrices, excluding `MATELEMENTAL` and `MATSCALAPACK`, this corresponds to values
7056   returned by `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`. For `MATELEMENTAL` and
7057   `MATSCALAPACK` the ownership is more complicated. See [Matrix Layouts](sec_matlayout) for
7058   details on matrix layouts.
7059 
7060 .seealso: [](ch_matrices), `IS`, `Mat`, `MatGetOwnershipRanges()`, `MatSetValues()`, `MATELEMENTAL`, `MATSCALAPACK`
7061 @*/
7062 PetscErrorCode MatGetOwnershipIS(Mat A, IS *rows, IS *cols)
7063 {
7064   PetscErrorCode (*f)(Mat, IS *, IS *);
7065 
7066   PetscFunctionBegin;
7067   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
7068   PetscValidType(A, 1);
7069   MatCheckPreallocated(A, 1);
7070   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatGetOwnershipIS_C", &f));
7071   if (f) {
7072     PetscCall((*f)(A, rows, cols));
7073   } else { /* Create a standard row-based partition, each process is responsible for ALL columns in their row block */
7074     if (rows) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->rmap->n, A->rmap->rstart, 1, rows));
7075     if (cols) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->cmap->N, 0, 1, cols));
7076   }
7077   PetscFunctionReturn(PETSC_SUCCESS);
7078 }
7079 
7080 /*@
7081   MatILUFactorSymbolic - Performs symbolic ILU factorization of a matrix obtained with `MatGetFactor()`
7082   Uses levels of fill only, not drop tolerance. Use `MatLUFactorNumeric()`
7083   to complete the factorization.
7084 
7085   Collective
7086 
7087   Input Parameters:
7088 + fact - the factorized matrix obtained with `MatGetFactor()`
7089 . mat  - the matrix
7090 . row  - row permutation
7091 . col  - column permutation
7092 - info - structure containing
7093 .vb
7094       levels - number of levels of fill.
7095       expected fill - as ratio of original fill.
7096       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
7097                 missing diagonal entries)
7098 .ve
7099 
7100   Level: developer
7101 
7102   Notes:
7103   See [Matrix Factorization](sec_matfactor) for additional information.
7104 
7105   Most users should employ the `KSP` interface for linear solvers
7106   instead of working directly with matrix algebra routines such as this.
7107   See, e.g., `KSPCreate()`.
7108 
7109   Uses the definition of level of fill as in Y. Saad, {cite}`saad2003`
7110 
7111   Fortran Note:
7112   A valid (non-null) `info` argument must be provided
7113 
7114 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
7115           `MatGetOrdering()`, `MatFactorInfo`
7116 @*/
7117 PetscErrorCode MatILUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
7118 {
7119   PetscFunctionBegin;
7120   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7121   PetscValidType(mat, 2);
7122   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
7123   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
7124   PetscAssertPointer(info, 5);
7125   PetscAssertPointer(fact, 1);
7126   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels of fill negative %" PetscInt_FMT, (PetscInt)info->levels);
7127   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7128   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7129   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7130   MatCheckPreallocated(mat, 2);
7131 
7132   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ILUFactorSymbolic, mat, row, col, 0));
7133   PetscUseTypeMethod(fact, ilufactorsymbolic, mat, row, col, info);
7134   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ILUFactorSymbolic, mat, row, col, 0));
7135   PetscFunctionReturn(PETSC_SUCCESS);
7136 }
7137 
7138 /*@
7139   MatICCFactorSymbolic - Performs symbolic incomplete
7140   Cholesky factorization for a symmetric matrix.  Use
7141   `MatCholeskyFactorNumeric()` to complete the factorization.
7142 
7143   Collective
7144 
7145   Input Parameters:
7146 + fact - the factorized matrix obtained with `MatGetFactor()`
7147 . mat  - the matrix to be factored
7148 . perm - row and column permutation
7149 - info - structure containing
7150 .vb
7151       levels - number of levels of fill.
7152       expected fill - as ratio of original fill.
7153 .ve
7154 
7155   Level: developer
7156 
7157   Notes:
7158   Most users should employ the `KSP` interface for linear solvers
7159   instead of working directly with matrix algebra routines such as this.
7160   See, e.g., `KSPCreate()`.
7161 
7162   This uses the definition of level of fill as in Y. Saad {cite}`saad2003`
7163 
7164   Fortran Note:
7165   A valid (non-null) `info` argument must be provided
7166 
7167 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
7168 @*/
7169 PetscErrorCode MatICCFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
7170 {
7171   PetscFunctionBegin;
7172   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7173   PetscValidType(mat, 2);
7174   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
7175   PetscAssertPointer(info, 4);
7176   PetscAssertPointer(fact, 1);
7177   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7178   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels negative %" PetscInt_FMT, (PetscInt)info->levels);
7179   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7180   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7181   MatCheckPreallocated(mat, 2);
7182 
7183   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7184   PetscUseTypeMethod(fact, iccfactorsymbolic, mat, perm, info);
7185   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7186   PetscFunctionReturn(PETSC_SUCCESS);
7187 }
7188 
7189 /*@C
7190   MatCreateSubMatrices - Extracts several submatrices from a matrix. If submat
7191   points to an array of valid matrices, they may be reused to store the new
7192   submatrices.
7193 
7194   Collective
7195 
7196   Input Parameters:
7197 + mat   - the matrix
7198 . n     - the number of submatrixes to be extracted (on this processor, may be zero)
7199 . irow  - index set of rows to extract
7200 . icol  - index set of columns to extract
7201 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7202 
7203   Output Parameter:
7204 . submat - the array of submatrices
7205 
7206   Level: advanced
7207 
7208   Notes:
7209   `MatCreateSubMatrices()` can extract ONLY sequential submatrices
7210   (from both sequential and parallel matrices). Use `MatCreateSubMatrix()`
7211   to extract a parallel submatrix.
7212 
7213   Some matrix types place restrictions on the row and column
7214   indices, such as that they be sorted or that they be equal to each other.
7215 
7216   The index sets may not have duplicate entries.
7217 
7218   When extracting submatrices from a parallel matrix, each processor can
7219   form a different submatrix by setting the rows and columns of its
7220   individual index sets according to the local submatrix desired.
7221 
7222   When finished using the submatrices, the user should destroy
7223   them with `MatDestroySubMatrices()`.
7224 
7225   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
7226   original matrix has not changed from that last call to `MatCreateSubMatrices()`.
7227 
7228   This routine creates the matrices in submat; you should NOT create them before
7229   calling it. It also allocates the array of matrix pointers submat.
7230 
7231   For `MATBAIJ` matrices the index sets must respect the block structure, that is if they
7232   request one row/column in a block, they must request all rows/columns that are in
7233   that block. For example, if the block size is 2 you cannot request just row 0 and
7234   column 0.
7235 
7236   Fortran Note:
7237 .vb
7238   Mat, pointer :: submat(:)
7239 .ve
7240 
7241 .seealso: [](ch_matrices), `Mat`, `MatDestroySubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7242 @*/
7243 PetscErrorCode MatCreateSubMatrices(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7244 {
7245   PetscInt  i;
7246   PetscBool eq;
7247 
7248   PetscFunctionBegin;
7249   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7250   PetscValidType(mat, 1);
7251   if (n) {
7252     PetscAssertPointer(irow, 3);
7253     for (i = 0; i < n; i++) PetscValidHeaderSpecific(irow[i], IS_CLASSID, 3);
7254     PetscAssertPointer(icol, 4);
7255     for (i = 0; i < n; i++) PetscValidHeaderSpecific(icol[i], IS_CLASSID, 4);
7256   }
7257   PetscAssertPointer(submat, 6);
7258   if (n && scall == MAT_REUSE_MATRIX) {
7259     PetscAssertPointer(*submat, 6);
7260     for (i = 0; i < n; i++) PetscValidHeaderSpecific((*submat)[i], MAT_CLASSID, 6);
7261   }
7262   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7263   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7264   MatCheckPreallocated(mat, 1);
7265   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7266   PetscUseTypeMethod(mat, createsubmatrices, n, irow, icol, scall, submat);
7267   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7268   for (i = 0; i < n; i++) {
7269     (*submat)[i]->factortype = MAT_FACTOR_NONE; /* in case in place factorization was previously done on submatrix */
7270     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7271     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7272 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
7273     if (mat->boundtocpu && mat->bindingpropagates) {
7274       PetscCall(MatBindToCPU((*submat)[i], PETSC_TRUE));
7275       PetscCall(MatSetBindingPropagates((*submat)[i], PETSC_TRUE));
7276     }
7277 #endif
7278   }
7279   PetscFunctionReturn(PETSC_SUCCESS);
7280 }
7281 
7282 /*@C
7283   MatCreateSubMatricesMPI - Extracts MPI submatrices across a sub communicator of `mat` (by pairs of `IS` that may live on subcomms).
7284 
7285   Collective
7286 
7287   Input Parameters:
7288 + mat   - the matrix
7289 . n     - the number of submatrixes to be extracted
7290 . irow  - index set of rows to extract
7291 . icol  - index set of columns to extract
7292 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7293 
7294   Output Parameter:
7295 . submat - the array of submatrices
7296 
7297   Level: advanced
7298 
7299   Note:
7300   This is used by `PCGASM`
7301 
7302 .seealso: [](ch_matrices), `Mat`, `PCGASM`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7303 @*/
7304 PetscErrorCode MatCreateSubMatricesMPI(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7305 {
7306   PetscInt  i;
7307   PetscBool eq;
7308 
7309   PetscFunctionBegin;
7310   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7311   PetscValidType(mat, 1);
7312   if (n) {
7313     PetscAssertPointer(irow, 3);
7314     PetscValidHeaderSpecific(*irow, IS_CLASSID, 3);
7315     PetscAssertPointer(icol, 4);
7316     PetscValidHeaderSpecific(*icol, IS_CLASSID, 4);
7317   }
7318   PetscAssertPointer(submat, 6);
7319   if (n && scall == MAT_REUSE_MATRIX) {
7320     PetscAssertPointer(*submat, 6);
7321     PetscValidHeaderSpecific(**submat, MAT_CLASSID, 6);
7322   }
7323   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7324   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7325   MatCheckPreallocated(mat, 1);
7326 
7327   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7328   PetscUseTypeMethod(mat, createsubmatricesmpi, n, irow, icol, scall, submat);
7329   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7330   for (i = 0; i < n; i++) {
7331     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7332     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7333   }
7334   PetscFunctionReturn(PETSC_SUCCESS);
7335 }
7336 
7337 /*@C
7338   MatDestroyMatrices - Destroys an array of matrices
7339 
7340   Collective
7341 
7342   Input Parameters:
7343 + n   - the number of local matrices
7344 - mat - the matrices (this is a pointer to the array of matrices)
7345 
7346   Level: advanced
7347 
7348   Notes:
7349   Frees not only the matrices, but also the array that contains the matrices
7350 
7351   For matrices obtained with  `MatCreateSubMatrices()` use `MatDestroySubMatrices()`
7352 
7353 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroySubMatrices()`
7354 @*/
7355 PetscErrorCode MatDestroyMatrices(PetscInt n, Mat *mat[])
7356 {
7357   PetscInt i;
7358 
7359   PetscFunctionBegin;
7360   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7361   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7362   PetscAssertPointer(mat, 2);
7363 
7364   for (i = 0; i < n; i++) PetscCall(MatDestroy(&(*mat)[i]));
7365 
7366   /* memory is allocated even if n = 0 */
7367   PetscCall(PetscFree(*mat));
7368   PetscFunctionReturn(PETSC_SUCCESS);
7369 }
7370 
7371 /*@C
7372   MatDestroySubMatrices - Destroys a set of matrices obtained with `MatCreateSubMatrices()`.
7373 
7374   Collective
7375 
7376   Input Parameters:
7377 + n   - the number of local matrices
7378 - mat - the matrices (this is a pointer to the array of matrices, to match the calling sequence of `MatCreateSubMatrices()`)
7379 
7380   Level: advanced
7381 
7382   Note:
7383   Frees not only the matrices, but also the array that contains the matrices
7384 
7385 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7386 @*/
7387 PetscErrorCode MatDestroySubMatrices(PetscInt n, Mat *mat[])
7388 {
7389   Mat mat0;
7390 
7391   PetscFunctionBegin;
7392   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7393   /* mat[] is an array of length n+1, see MatCreateSubMatrices_xxx() */
7394   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7395   PetscAssertPointer(mat, 2);
7396 
7397   mat0 = (*mat)[0];
7398   if (mat0 && mat0->ops->destroysubmatrices) {
7399     PetscCall((*mat0->ops->destroysubmatrices)(n, mat));
7400   } else {
7401     PetscCall(MatDestroyMatrices(n, mat));
7402   }
7403   PetscFunctionReturn(PETSC_SUCCESS);
7404 }
7405 
7406 /*@
7407   MatGetSeqNonzeroStructure - Extracts the nonzero structure from a matrix and stores it, in its entirety, on each process
7408 
7409   Collective
7410 
7411   Input Parameter:
7412 . mat - the matrix
7413 
7414   Output Parameter:
7415 . matstruct - the sequential matrix with the nonzero structure of `mat`
7416 
7417   Level: developer
7418 
7419 .seealso: [](ch_matrices), `Mat`, `MatDestroySeqNonzeroStructure()`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7420 @*/
7421 PetscErrorCode MatGetSeqNonzeroStructure(Mat mat, Mat *matstruct)
7422 {
7423   PetscFunctionBegin;
7424   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7425   PetscAssertPointer(matstruct, 2);
7426 
7427   PetscValidType(mat, 1);
7428   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7429   MatCheckPreallocated(mat, 1);
7430 
7431   PetscCall(PetscLogEventBegin(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7432   PetscUseTypeMethod(mat, getseqnonzerostructure, matstruct);
7433   PetscCall(PetscLogEventEnd(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7434   PetscFunctionReturn(PETSC_SUCCESS);
7435 }
7436 
7437 /*@C
7438   MatDestroySeqNonzeroStructure - Destroys matrix obtained with `MatGetSeqNonzeroStructure()`.
7439 
7440   Collective
7441 
7442   Input Parameter:
7443 . mat - the matrix
7444 
7445   Level: advanced
7446 
7447   Note:
7448   This is not needed, one can just call `MatDestroy()`
7449 
7450 .seealso: [](ch_matrices), `Mat`, `MatGetSeqNonzeroStructure()`
7451 @*/
7452 PetscErrorCode MatDestroySeqNonzeroStructure(Mat *mat)
7453 {
7454   PetscFunctionBegin;
7455   PetscAssertPointer(mat, 1);
7456   PetscCall(MatDestroy(mat));
7457   PetscFunctionReturn(PETSC_SUCCESS);
7458 }
7459 
7460 /*@
7461   MatIncreaseOverlap - Given a set of submatrices indicated by index sets,
7462   replaces the index sets by larger ones that represent submatrices with
7463   additional overlap.
7464 
7465   Collective
7466 
7467   Input Parameters:
7468 + mat - the matrix
7469 . n   - the number of index sets
7470 . is  - the array of index sets (these index sets will changed during the call)
7471 - ov  - the additional overlap requested
7472 
7473   Options Database Key:
7474 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7475 
7476   Level: developer
7477 
7478   Note:
7479   The computed overlap preserves the matrix block sizes when the blocks are square.
7480   That is: if a matrix nonzero for a given block would increase the overlap all columns associated with
7481   that block are included in the overlap regardless of whether each specific column would increase the overlap.
7482 
7483 .seealso: [](ch_matrices), `Mat`, `PCASM`, `MatSetBlockSize()`, `MatIncreaseOverlapSplit()`, `MatCreateSubMatrices()`
7484 @*/
7485 PetscErrorCode MatIncreaseOverlap(Mat mat, PetscInt n, IS is[], PetscInt ov)
7486 {
7487   PetscInt i, bs, cbs;
7488 
7489   PetscFunctionBegin;
7490   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7491   PetscValidType(mat, 1);
7492   PetscValidLogicalCollectiveInt(mat, n, 2);
7493   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7494   if (n) {
7495     PetscAssertPointer(is, 3);
7496     for (i = 0; i < n; i++) PetscValidHeaderSpecific(is[i], IS_CLASSID, 3);
7497   }
7498   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7499   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7500   MatCheckPreallocated(mat, 1);
7501 
7502   if (!ov || !n) PetscFunctionReturn(PETSC_SUCCESS);
7503   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7504   PetscUseTypeMethod(mat, increaseoverlap, n, is, ov);
7505   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7506   PetscCall(MatGetBlockSizes(mat, &bs, &cbs));
7507   if (bs == cbs) {
7508     for (i = 0; i < n; i++) PetscCall(ISSetBlockSize(is[i], bs));
7509   }
7510   PetscFunctionReturn(PETSC_SUCCESS);
7511 }
7512 
7513 PetscErrorCode MatIncreaseOverlapSplit_Single(Mat, IS *, PetscInt);
7514 
7515 /*@
7516   MatIncreaseOverlapSplit - Given a set of submatrices indicated by index sets across
7517   a sub communicator, replaces the index sets by larger ones that represent submatrices with
7518   additional overlap.
7519 
7520   Collective
7521 
7522   Input Parameters:
7523 + mat - the matrix
7524 . n   - the number of index sets
7525 . is  - the array of index sets (these index sets will changed during the call)
7526 - ov  - the additional overlap requested
7527 
7528   `   Options Database Key:
7529 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7530 
7531   Level: developer
7532 
7533 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatIncreaseOverlap()`
7534 @*/
7535 PetscErrorCode MatIncreaseOverlapSplit(Mat mat, PetscInt n, IS is[], PetscInt ov)
7536 {
7537   PetscInt i;
7538 
7539   PetscFunctionBegin;
7540   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7541   PetscValidType(mat, 1);
7542   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7543   if (n) {
7544     PetscAssertPointer(is, 3);
7545     PetscValidHeaderSpecific(*is, IS_CLASSID, 3);
7546   }
7547   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7548   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7549   MatCheckPreallocated(mat, 1);
7550   if (!ov) PetscFunctionReturn(PETSC_SUCCESS);
7551   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7552   for (i = 0; i < n; i++) PetscCall(MatIncreaseOverlapSplit_Single(mat, &is[i], ov));
7553   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7554   PetscFunctionReturn(PETSC_SUCCESS);
7555 }
7556 
7557 /*@
7558   MatGetBlockSize - Returns the matrix block size.
7559 
7560   Not Collective
7561 
7562   Input Parameter:
7563 . mat - the matrix
7564 
7565   Output Parameter:
7566 . bs - block size
7567 
7568   Level: intermediate
7569 
7570   Notes:
7571   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7572 
7573   If the block size has not been set yet this routine returns 1.
7574 
7575 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSizes()`
7576 @*/
7577 PetscErrorCode MatGetBlockSize(Mat mat, PetscInt *bs)
7578 {
7579   PetscFunctionBegin;
7580   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7581   PetscAssertPointer(bs, 2);
7582   *bs = mat->rmap->bs;
7583   PetscFunctionReturn(PETSC_SUCCESS);
7584 }
7585 
7586 /*@
7587   MatGetBlockSizes - Returns the matrix block row and column sizes.
7588 
7589   Not Collective
7590 
7591   Input Parameter:
7592 . mat - the matrix
7593 
7594   Output Parameters:
7595 + rbs - row block size
7596 - cbs - column block size
7597 
7598   Level: intermediate
7599 
7600   Notes:
7601   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7602   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
7603 
7604   If a block size has not been set yet this routine returns 1.
7605 
7606 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatSetBlockSizes()`
7607 @*/
7608 PetscErrorCode MatGetBlockSizes(Mat mat, PetscInt *rbs, PetscInt *cbs)
7609 {
7610   PetscFunctionBegin;
7611   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7612   if (rbs) PetscAssertPointer(rbs, 2);
7613   if (cbs) PetscAssertPointer(cbs, 3);
7614   if (rbs) *rbs = mat->rmap->bs;
7615   if (cbs) *cbs = mat->cmap->bs;
7616   PetscFunctionReturn(PETSC_SUCCESS);
7617 }
7618 
7619 /*@
7620   MatSetBlockSize - Sets the matrix block size.
7621 
7622   Logically Collective
7623 
7624   Input Parameters:
7625 + mat - the matrix
7626 - bs  - block size
7627 
7628   Level: intermediate
7629 
7630   Notes:
7631   Block row formats are `MATBAIJ` and `MATSBAIJ` formats ALWAYS have square block storage in the matrix.
7632   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
7633 
7634   For `MATAIJ` matrix format, this function can be called at a later stage, provided that the specified block size
7635   is compatible with the matrix local sizes.
7636 
7637 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MATAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`
7638 @*/
7639 PetscErrorCode MatSetBlockSize(Mat mat, PetscInt bs)
7640 {
7641   PetscFunctionBegin;
7642   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7643   PetscValidLogicalCollectiveInt(mat, bs, 2);
7644   PetscCall(MatSetBlockSizes(mat, bs, bs));
7645   PetscFunctionReturn(PETSC_SUCCESS);
7646 }
7647 
7648 typedef struct {
7649   PetscInt         n;
7650   IS              *is;
7651   Mat             *mat;
7652   PetscObjectState nonzerostate;
7653   Mat              C;
7654 } EnvelopeData;
7655 
7656 static PetscErrorCode EnvelopeDataDestroy(void **ptr)
7657 {
7658   EnvelopeData *edata = (EnvelopeData *)*ptr;
7659 
7660   PetscFunctionBegin;
7661   for (PetscInt i = 0; i < edata->n; i++) PetscCall(ISDestroy(&edata->is[i]));
7662   PetscCall(PetscFree(edata->is));
7663   PetscCall(PetscFree(edata));
7664   PetscFunctionReturn(PETSC_SUCCESS);
7665 }
7666 
7667 /*@
7668   MatComputeVariableBlockEnvelope - Given a matrix whose nonzeros are in blocks along the diagonal this computes and stores
7669   the sizes of these blocks in the matrix. An individual block may lie over several processes.
7670 
7671   Collective
7672 
7673   Input Parameter:
7674 . mat - the matrix
7675 
7676   Level: intermediate
7677 
7678   Notes:
7679   There can be zeros within the blocks
7680 
7681   The blocks can overlap between processes, including laying on more than two processes
7682 
7683 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatSetVariableBlockSizes()`
7684 @*/
7685 PetscErrorCode MatComputeVariableBlockEnvelope(Mat mat)
7686 {
7687   PetscInt           n, *sizes, *starts, i = 0, env = 0, tbs = 0, lblocks = 0, rstart, II, ln = 0, cnt = 0, cstart, cend;
7688   PetscInt          *diag, *odiag, sc;
7689   VecScatter         scatter;
7690   PetscScalar       *seqv;
7691   const PetscScalar *parv;
7692   const PetscInt    *ia, *ja;
7693   PetscBool          set, flag, done;
7694   Mat                AA = mat, A;
7695   MPI_Comm           comm;
7696   PetscMPIInt        rank, size, tag;
7697   MPI_Status         status;
7698   PetscContainer     container;
7699   EnvelopeData      *edata;
7700   Vec                seq, par;
7701   IS                 isglobal;
7702 
7703   PetscFunctionBegin;
7704   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7705   PetscCall(MatIsSymmetricKnown(mat, &set, &flag));
7706   if (!set || !flag) {
7707     /* TODO: only needs nonzero structure of transpose */
7708     PetscCall(MatTranspose(mat, MAT_INITIAL_MATRIX, &AA));
7709     PetscCall(MatAXPY(AA, 1.0, mat, DIFFERENT_NONZERO_PATTERN));
7710   }
7711   PetscCall(MatAIJGetLocalMat(AA, &A));
7712   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7713   PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Unable to get IJ structure from matrix");
7714 
7715   PetscCall(MatGetLocalSize(mat, &n, NULL));
7716   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag));
7717   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
7718   PetscCallMPI(MPI_Comm_size(comm, &size));
7719   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7720 
7721   PetscCall(PetscMalloc2(n, &sizes, n, &starts));
7722 
7723   if (rank > 0) {
7724     PetscCallMPI(MPI_Recv(&env, 1, MPIU_INT, rank - 1, tag, comm, &status));
7725     PetscCallMPI(MPI_Recv(&tbs, 1, MPIU_INT, rank - 1, tag, comm, &status));
7726   }
7727   PetscCall(MatGetOwnershipRange(mat, &rstart, NULL));
7728   for (i = 0; i < n; i++) {
7729     env = PetscMax(env, ja[ia[i + 1] - 1]);
7730     II  = rstart + i;
7731     if (env == II) {
7732       starts[lblocks]  = tbs;
7733       sizes[lblocks++] = 1 + II - tbs;
7734       tbs              = 1 + II;
7735     }
7736   }
7737   if (rank < size - 1) {
7738     PetscCallMPI(MPI_Send(&env, 1, MPIU_INT, rank + 1, tag, comm));
7739     PetscCallMPI(MPI_Send(&tbs, 1, MPIU_INT, rank + 1, tag, comm));
7740   }
7741 
7742   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7743   if (!set || !flag) PetscCall(MatDestroy(&AA));
7744   PetscCall(MatDestroy(&A));
7745 
7746   PetscCall(PetscNew(&edata));
7747   PetscCall(MatGetNonzeroState(mat, &edata->nonzerostate));
7748   edata->n = lblocks;
7749   /* create IS needed for extracting blocks from the original matrix */
7750   PetscCall(PetscMalloc1(lblocks, &edata->is));
7751   for (PetscInt i = 0; i < lblocks; i++) PetscCall(ISCreateStride(PETSC_COMM_SELF, sizes[i], starts[i], 1, &edata->is[i]));
7752 
7753   /* Create the resulting inverse matrix nonzero structure with preallocation information */
7754   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &edata->C));
7755   PetscCall(MatSetSizes(edata->C, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
7756   PetscCall(MatSetBlockSizesFromMats(edata->C, mat, mat));
7757   PetscCall(MatSetType(edata->C, MATAIJ));
7758 
7759   /* Communicate the start and end of each row, from each block to the correct rank */
7760   /* TODO: Use PetscSF instead of VecScatter */
7761   for (PetscInt i = 0; i < lblocks; i++) ln += sizes[i];
7762   PetscCall(VecCreateSeq(PETSC_COMM_SELF, 2 * ln, &seq));
7763   PetscCall(VecGetArrayWrite(seq, &seqv));
7764   for (PetscInt i = 0; i < lblocks; i++) {
7765     for (PetscInt j = 0; j < sizes[i]; j++) {
7766       seqv[cnt]     = starts[i];
7767       seqv[cnt + 1] = starts[i] + sizes[i];
7768       cnt += 2;
7769     }
7770   }
7771   PetscCall(VecRestoreArrayWrite(seq, &seqv));
7772   PetscCallMPI(MPI_Scan(&cnt, &sc, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
7773   sc -= cnt;
7774   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)mat), 2 * mat->rmap->n, 2 * mat->rmap->N, &par));
7775   PetscCall(ISCreateStride(PETSC_COMM_SELF, cnt, sc, 1, &isglobal));
7776   PetscCall(VecScatterCreate(seq, NULL, par, isglobal, &scatter));
7777   PetscCall(ISDestroy(&isglobal));
7778   PetscCall(VecScatterBegin(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7779   PetscCall(VecScatterEnd(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7780   PetscCall(VecScatterDestroy(&scatter));
7781   PetscCall(VecDestroy(&seq));
7782   PetscCall(MatGetOwnershipRangeColumn(mat, &cstart, &cend));
7783   PetscCall(PetscMalloc2(mat->rmap->n, &diag, mat->rmap->n, &odiag));
7784   PetscCall(VecGetArrayRead(par, &parv));
7785   cnt = 0;
7786   PetscCall(MatGetSize(mat, NULL, &n));
7787   for (PetscInt i = 0; i < mat->rmap->n; i++) {
7788     PetscInt start, end, d = 0, od = 0;
7789 
7790     start = (PetscInt)PetscRealPart(parv[cnt]);
7791     end   = (PetscInt)PetscRealPart(parv[cnt + 1]);
7792     cnt += 2;
7793 
7794     if (start < cstart) {
7795       od += cstart - start + n - cend;
7796       d += cend - cstart;
7797     } else if (start < cend) {
7798       od += n - cend;
7799       d += cend - start;
7800     } else od += n - start;
7801     if (end <= cstart) {
7802       od -= cstart - end + n - cend;
7803       d -= cend - cstart;
7804     } else if (end < cend) {
7805       od -= n - cend;
7806       d -= cend - end;
7807     } else od -= n - end;
7808 
7809     odiag[i] = od;
7810     diag[i]  = d;
7811   }
7812   PetscCall(VecRestoreArrayRead(par, &parv));
7813   PetscCall(VecDestroy(&par));
7814   PetscCall(MatXAIJSetPreallocation(edata->C, mat->rmap->bs, diag, odiag, NULL, NULL));
7815   PetscCall(PetscFree2(diag, odiag));
7816   PetscCall(PetscFree2(sizes, starts));
7817 
7818   PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container));
7819   PetscCall(PetscContainerSetPointer(container, edata));
7820   PetscCall(PetscContainerSetCtxDestroy(container, EnvelopeDataDestroy));
7821   PetscCall(PetscObjectCompose((PetscObject)mat, "EnvelopeData", (PetscObject)container));
7822   PetscCall(PetscObjectDereference((PetscObject)container));
7823   PetscFunctionReturn(PETSC_SUCCESS);
7824 }
7825 
7826 /*@
7827   MatInvertVariableBlockEnvelope - set matrix C to be the inverted block diagonal of matrix A
7828 
7829   Collective
7830 
7831   Input Parameters:
7832 + A     - the matrix
7833 - reuse - indicates if the `C` matrix was obtained from a previous call to this routine
7834 
7835   Output Parameter:
7836 . C - matrix with inverted block diagonal of `A`
7837 
7838   Level: advanced
7839 
7840   Note:
7841   For efficiency the matrix `A` should have all the nonzero entries clustered in smallish blocks along the diagonal.
7842 
7843 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatComputeBlockDiagonal()`
7844 @*/
7845 PetscErrorCode MatInvertVariableBlockEnvelope(Mat A, MatReuse reuse, Mat *C)
7846 {
7847   PetscContainer   container;
7848   EnvelopeData    *edata;
7849   PetscObjectState nonzerostate;
7850 
7851   PetscFunctionBegin;
7852   PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7853   if (!container) {
7854     PetscCall(MatComputeVariableBlockEnvelope(A));
7855     PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7856   }
7857   PetscCall(PetscContainerGetPointer(container, (void **)&edata));
7858   PetscCall(MatGetNonzeroState(A, &nonzerostate));
7859   PetscCheck(nonzerostate <= edata->nonzerostate, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot handle changes to matrix nonzero structure");
7860   PetscCheck(reuse != MAT_REUSE_MATRIX || *C == edata->C, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "C matrix must be the same as previously output");
7861 
7862   PetscCall(MatCreateSubMatrices(A, edata->n, edata->is, edata->is, MAT_INITIAL_MATRIX, &edata->mat));
7863   *C = edata->C;
7864 
7865   for (PetscInt i = 0; i < edata->n; i++) {
7866     Mat          D;
7867     PetscScalar *dvalues;
7868 
7869     PetscCall(MatConvert(edata->mat[i], MATSEQDENSE, MAT_INITIAL_MATRIX, &D));
7870     PetscCall(MatSetOption(*C, MAT_ROW_ORIENTED, PETSC_FALSE));
7871     PetscCall(MatSeqDenseInvert(D));
7872     PetscCall(MatDenseGetArray(D, &dvalues));
7873     PetscCall(MatSetValuesIS(*C, edata->is[i], edata->is[i], dvalues, INSERT_VALUES));
7874     PetscCall(MatDestroy(&D));
7875   }
7876   PetscCall(MatDestroySubMatrices(edata->n, &edata->mat));
7877   PetscCall(MatAssemblyBegin(*C, MAT_FINAL_ASSEMBLY));
7878   PetscCall(MatAssemblyEnd(*C, MAT_FINAL_ASSEMBLY));
7879   PetscFunctionReturn(PETSC_SUCCESS);
7880 }
7881 
7882 /*@
7883   MatSetVariableBlockSizes - Sets diagonal point-blocks of the matrix that need not be of the same size
7884 
7885   Not Collective
7886 
7887   Input Parameters:
7888 + mat     - the matrix
7889 . nblocks - the number of blocks on this process, each block can only exist on a single process
7890 - bsizes  - the block sizes
7891 
7892   Level: intermediate
7893 
7894   Notes:
7895   Currently used by `PCVPBJACOBI` for `MATAIJ` matrices
7896 
7897   Each variable point-block set of degrees of freedom must live on a single MPI process. That is a point block cannot straddle two MPI processes.
7898 
7899 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatGetVariableBlockSizes()`,
7900           `MatComputeVariableBlockEnvelope()`, `PCVPBJACOBI`
7901 @*/
7902 PetscErrorCode MatSetVariableBlockSizes(Mat mat, PetscInt nblocks, const PetscInt bsizes[])
7903 {
7904   PetscInt ncnt = 0, nlocal;
7905 
7906   PetscFunctionBegin;
7907   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7908   PetscCall(MatGetLocalSize(mat, &nlocal, NULL));
7909   PetscCheck(nblocks >= 0 && nblocks <= nlocal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of local blocks %" PetscInt_FMT " is not in [0, %" PetscInt_FMT "]", nblocks, nlocal);
7910   for (PetscInt i = 0; i < nblocks; i++) ncnt += bsizes[i];
7911   PetscCheck(ncnt == nlocal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Sum of local block sizes %" PetscInt_FMT " does not equal local size of matrix %" PetscInt_FMT, ncnt, nlocal);
7912   PetscCall(PetscFree(mat->bsizes));
7913   mat->nblocks = nblocks;
7914   PetscCall(PetscMalloc1(nblocks, &mat->bsizes));
7915   PetscCall(PetscArraycpy(mat->bsizes, bsizes, nblocks));
7916   PetscFunctionReturn(PETSC_SUCCESS);
7917 }
7918 
7919 /*@C
7920   MatGetVariableBlockSizes - Gets a diagonal blocks of the matrix that need not be of the same size
7921 
7922   Not Collective; No Fortran Support
7923 
7924   Input Parameter:
7925 . mat - the matrix
7926 
7927   Output Parameters:
7928 + nblocks - the number of blocks on this process
7929 - bsizes  - the block sizes
7930 
7931   Level: intermediate
7932 
7933 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatSetVariableBlockSizes()`, `MatComputeVariableBlockEnvelope()`
7934 @*/
7935 PetscErrorCode MatGetVariableBlockSizes(Mat mat, PetscInt *nblocks, const PetscInt *bsizes[])
7936 {
7937   PetscFunctionBegin;
7938   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7939   if (nblocks) *nblocks = mat->nblocks;
7940   if (bsizes) *bsizes = mat->bsizes;
7941   PetscFunctionReturn(PETSC_SUCCESS);
7942 }
7943 
7944 /*
7945   MatSelectVariableBlockSizes - When creating a submatrix, pass on the variable block sizes
7946 
7947   Not Collective
7948 
7949   Input Parameter:
7950 + subA  - the submatrix
7951 . A     - the original matrix
7952 - isrow - The `IS` of selected rows for the submatrix
7953 
7954   Level: developer
7955 
7956 .seealso: [](ch_matrices), `Mat`, `MatSetVariableBlockSizes()`, `MatComputeVariableBlockEnvelope()`
7957 */
7958 static PetscErrorCode MatSelectVariableBlockSizes(Mat subA, Mat A, IS isrow)
7959 {
7960   const PetscInt *rows;
7961   PetscInt        n, rStart, rEnd, Nb = 0;
7962 
7963   PetscFunctionBegin;
7964   if (!A->bsizes) PetscFunctionReturn(PETSC_SUCCESS);
7965   // The IS contains global row numbers, we cannot preserve blocks if it contains off-process entries
7966   PetscCall(MatGetOwnershipRange(A, &rStart, &rEnd));
7967   PetscCall(ISGetIndices(isrow, &rows));
7968   PetscCall(ISGetLocalSize(isrow, &n));
7969   for (PetscInt i = 0; i < n; ++i) {
7970     if (rows[i] < rStart || rows[i] >= rEnd) {
7971       PetscCall(ISRestoreIndices(isrow, &rows));
7972       PetscFunctionReturn(PETSC_SUCCESS);
7973     }
7974   }
7975   for (PetscInt b = 0, gr = rStart, i = 0; b < A->nblocks; ++b) {
7976     PetscBool occupied = PETSC_FALSE;
7977 
7978     for (PetscInt br = 0; br < A->bsizes[b]; ++br) {
7979       const PetscInt row = gr + br;
7980 
7981       if (i == n) break;
7982       if (rows[i] == row) {
7983         occupied = PETSC_TRUE;
7984         ++i;
7985       }
7986       while (i < n && rows[i] < row) ++i;
7987     }
7988     gr += A->bsizes[b];
7989     if (occupied) ++Nb;
7990   }
7991   subA->nblocks = Nb;
7992   PetscCall(PetscFree(subA->bsizes));
7993   PetscCall(PetscMalloc1(subA->nblocks, &subA->bsizes));
7994   PetscInt sb = 0;
7995   for (PetscInt b = 0, gr = rStart, i = 0; b < A->nblocks; ++b) {
7996     if (sb < subA->nblocks) subA->bsizes[sb] = 0;
7997     for (PetscInt br = 0; br < A->bsizes[b]; ++br) {
7998       const PetscInt row = gr + br;
7999 
8000       if (i == n) break;
8001       if (rows[i] == row) {
8002         ++subA->bsizes[sb];
8003         ++i;
8004       }
8005       while (i < n && rows[i] < row) ++i;
8006     }
8007     gr += A->bsizes[b];
8008     if (sb < subA->nblocks && subA->bsizes[sb]) ++sb;
8009   }
8010   PetscCheck(sb == subA->nblocks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of blocks %" PetscInt_FMT " != %" PetscInt_FMT, sb, subA->nblocks);
8011   PetscInt nlocal, ncnt = 0;
8012   PetscCall(MatGetLocalSize(subA, &nlocal, NULL));
8013   PetscCheck(subA->nblocks >= 0 && subA->nblocks <= nlocal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of local blocks %" PetscInt_FMT " is not in [0, %" PetscInt_FMT "]", subA->nblocks, nlocal);
8014   for (PetscInt i = 0; i < subA->nblocks; i++) ncnt += subA->bsizes[i];
8015   PetscCheck(ncnt == nlocal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Sum of local block sizes %" PetscInt_FMT " does not equal local size of matrix %" PetscInt_FMT, ncnt, nlocal);
8016   PetscCall(ISRestoreIndices(isrow, &rows));
8017   PetscFunctionReturn(PETSC_SUCCESS);
8018 }
8019 
8020 /*@
8021   MatSetBlockSizes - Sets the matrix block row and column sizes.
8022 
8023   Logically Collective
8024 
8025   Input Parameters:
8026 + mat - the matrix
8027 . rbs - row block size
8028 - cbs - column block size
8029 
8030   Level: intermediate
8031 
8032   Notes:
8033   Block row formats are `MATBAIJ` and  `MATSBAIJ`. These formats ALWAYS have square block storage in the matrix.
8034   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
8035   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
8036 
8037   For `MATAIJ` matrix this function can be called at a later stage, provided that the specified block sizes
8038   are compatible with the matrix local sizes.
8039 
8040   The row and column block size determine the blocksize of the "row" and "column" vectors returned by `MatCreateVecs()`.
8041 
8042 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatGetBlockSizes()`
8043 @*/
8044 PetscErrorCode MatSetBlockSizes(Mat mat, PetscInt rbs, PetscInt cbs)
8045 {
8046   PetscFunctionBegin;
8047   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8048   PetscValidLogicalCollectiveInt(mat, rbs, 2);
8049   PetscValidLogicalCollectiveInt(mat, cbs, 3);
8050   PetscTryTypeMethod(mat, setblocksizes, rbs, cbs);
8051   if (mat->rmap->refcnt) {
8052     ISLocalToGlobalMapping l2g  = NULL;
8053     PetscLayout            nmap = NULL;
8054 
8055     PetscCall(PetscLayoutDuplicate(mat->rmap, &nmap));
8056     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->rmap->mapping, &l2g));
8057     PetscCall(PetscLayoutDestroy(&mat->rmap));
8058     mat->rmap          = nmap;
8059     mat->rmap->mapping = l2g;
8060   }
8061   if (mat->cmap->refcnt) {
8062     ISLocalToGlobalMapping l2g  = NULL;
8063     PetscLayout            nmap = NULL;
8064 
8065     PetscCall(PetscLayoutDuplicate(mat->cmap, &nmap));
8066     if (mat->cmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->cmap->mapping, &l2g));
8067     PetscCall(PetscLayoutDestroy(&mat->cmap));
8068     mat->cmap          = nmap;
8069     mat->cmap->mapping = l2g;
8070   }
8071   PetscCall(PetscLayoutSetBlockSize(mat->rmap, rbs));
8072   PetscCall(PetscLayoutSetBlockSize(mat->cmap, cbs));
8073   PetscFunctionReturn(PETSC_SUCCESS);
8074 }
8075 
8076 /*@
8077   MatSetBlockSizesFromMats - Sets the matrix block row and column sizes to match a pair of matrices
8078 
8079   Logically Collective
8080 
8081   Input Parameters:
8082 + mat     - the matrix
8083 . fromRow - matrix from which to copy row block size
8084 - fromCol - matrix from which to copy column block size (can be same as fromRow)
8085 
8086   Level: developer
8087 
8088 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`
8089 @*/
8090 PetscErrorCode MatSetBlockSizesFromMats(Mat mat, Mat fromRow, Mat fromCol)
8091 {
8092   PetscFunctionBegin;
8093   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8094   PetscValidHeaderSpecific(fromRow, MAT_CLASSID, 2);
8095   PetscValidHeaderSpecific(fromCol, MAT_CLASSID, 3);
8096   PetscCall(PetscLayoutSetBlockSize(mat->rmap, fromRow->rmap->bs));
8097   PetscCall(PetscLayoutSetBlockSize(mat->cmap, fromCol->cmap->bs));
8098   PetscFunctionReturn(PETSC_SUCCESS);
8099 }
8100 
8101 /*@
8102   MatResidual - Default routine to calculate the residual r = b - Ax
8103 
8104   Collective
8105 
8106   Input Parameters:
8107 + mat - the matrix
8108 . b   - the right-hand-side
8109 - x   - the approximate solution
8110 
8111   Output Parameter:
8112 . r - location to store the residual
8113 
8114   Level: developer
8115 
8116 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `PCMGSetResidual()`
8117 @*/
8118 PetscErrorCode MatResidual(Mat mat, Vec b, Vec x, Vec r)
8119 {
8120   PetscFunctionBegin;
8121   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8122   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
8123   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
8124   PetscValidHeaderSpecific(r, VEC_CLASSID, 4);
8125   PetscValidType(mat, 1);
8126   MatCheckPreallocated(mat, 1);
8127   PetscCall(PetscLogEventBegin(MAT_Residual, mat, 0, 0, 0));
8128   if (!mat->ops->residual) {
8129     PetscCall(MatMult(mat, x, r));
8130     PetscCall(VecAYPX(r, -1.0, b));
8131   } else {
8132     PetscUseTypeMethod(mat, residual, b, x, r);
8133   }
8134   PetscCall(PetscLogEventEnd(MAT_Residual, mat, 0, 0, 0));
8135   PetscFunctionReturn(PETSC_SUCCESS);
8136 }
8137 
8138 /*@C
8139   MatGetRowIJ - Returns the compressed row storage i and j indices for the local rows of a sparse matrix
8140 
8141   Collective
8142 
8143   Input Parameters:
8144 + mat             - the matrix
8145 . shift           - 0 or 1 indicating we want the indices starting at 0 or 1
8146 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8147 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE`  indicating if the nonzero structure of the
8148                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8149                  always used.
8150 
8151   Output Parameters:
8152 + n    - number of local rows in the (possibly compressed) matrix, use `NULL` if not needed
8153 . ia   - the row pointers; that is ia[0] = 0, ia[row] = ia[row-1] + number of elements in that row of the matrix, use `NULL` if not needed
8154 . ja   - the column indices, use `NULL` if not needed
8155 - done - indicates if the routine actually worked and returned appropriate ia[] and ja[] arrays; callers
8156            are responsible for handling the case when done == `PETSC_FALSE` and ia and ja are not set
8157 
8158   Level: developer
8159 
8160   Notes:
8161   You CANNOT change any of the ia[] or ja[] values.
8162 
8163   Use `MatRestoreRowIJ()` when you are finished accessing the ia[] and ja[] values.
8164 
8165   Fortran Notes:
8166   Use
8167 .vb
8168     PetscInt, pointer :: ia(:),ja(:)
8169     call MatGetRowIJ(mat,shift,symmetric,inodecompressed,n,ia,ja,done,ierr)
8170     ! Access the ith and jth entries via ia(i) and ja(j)
8171 .ve
8172 
8173 .seealso: [](ch_matrices), `Mat`, `MATAIJ`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`, `MatSeqAIJGetArray()`
8174 @*/
8175 PetscErrorCode MatGetRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8176 {
8177   PetscFunctionBegin;
8178   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8179   PetscValidType(mat, 1);
8180   if (n) PetscAssertPointer(n, 5);
8181   if (ia) PetscAssertPointer(ia, 6);
8182   if (ja) PetscAssertPointer(ja, 7);
8183   if (done) PetscAssertPointer(done, 8);
8184   MatCheckPreallocated(mat, 1);
8185   if (!mat->ops->getrowij && done) *done = PETSC_FALSE;
8186   else {
8187     if (done) *done = PETSC_TRUE;
8188     PetscCall(PetscLogEventBegin(MAT_GetRowIJ, mat, 0, 0, 0));
8189     PetscUseTypeMethod(mat, getrowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8190     PetscCall(PetscLogEventEnd(MAT_GetRowIJ, mat, 0, 0, 0));
8191   }
8192   PetscFunctionReturn(PETSC_SUCCESS);
8193 }
8194 
8195 /*@C
8196   MatGetColumnIJ - Returns the compressed column storage i and j indices for sequential matrices.
8197 
8198   Collective
8199 
8200   Input Parameters:
8201 + mat             - the matrix
8202 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8203 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be
8204                 symmetrized
8205 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8206                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8207                  always used.
8208 
8209   Output Parameters:
8210 + n    - number of columns in the (possibly compressed) matrix
8211 . ia   - the column pointers; that is ia[0] = 0, ia[col] = i[col-1] + number of elements in that col of the matrix
8212 . ja   - the row indices
8213 - done - `PETSC_TRUE` or `PETSC_FALSE`, indicating whether the values have been returned
8214 
8215   Level: developer
8216 
8217 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8218 @*/
8219 PetscErrorCode MatGetColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8220 {
8221   PetscFunctionBegin;
8222   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8223   PetscValidType(mat, 1);
8224   PetscAssertPointer(n, 5);
8225   if (ia) PetscAssertPointer(ia, 6);
8226   if (ja) PetscAssertPointer(ja, 7);
8227   PetscAssertPointer(done, 8);
8228   MatCheckPreallocated(mat, 1);
8229   if (!mat->ops->getcolumnij) *done = PETSC_FALSE;
8230   else {
8231     *done = PETSC_TRUE;
8232     PetscUseTypeMethod(mat, getcolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8233   }
8234   PetscFunctionReturn(PETSC_SUCCESS);
8235 }
8236 
8237 /*@C
8238   MatRestoreRowIJ - Call after you are completed with the ia,ja indices obtained with `MatGetRowIJ()`.
8239 
8240   Collective
8241 
8242   Input Parameters:
8243 + mat             - the matrix
8244 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8245 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8246 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8247                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8248                     always used.
8249 . n               - size of (possibly compressed) matrix
8250 . ia              - the row pointers
8251 - ja              - the column indices
8252 
8253   Output Parameter:
8254 . done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8255 
8256   Level: developer
8257 
8258   Note:
8259   This routine zeros out `n`, `ia`, and `ja`. This is to prevent accidental
8260   us of the array after it has been restored. If you pass `NULL`, it will
8261   not zero the pointers.  Use of ia or ja after `MatRestoreRowIJ()` is invalid.
8262 
8263 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8264 @*/
8265 PetscErrorCode MatRestoreRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8266 {
8267   PetscFunctionBegin;
8268   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8269   PetscValidType(mat, 1);
8270   if (ia) PetscAssertPointer(ia, 6);
8271   if (ja) PetscAssertPointer(ja, 7);
8272   if (done) PetscAssertPointer(done, 8);
8273   MatCheckPreallocated(mat, 1);
8274 
8275   if (!mat->ops->restorerowij && done) *done = PETSC_FALSE;
8276   else {
8277     if (done) *done = PETSC_TRUE;
8278     PetscUseTypeMethod(mat, restorerowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8279     if (n) *n = 0;
8280     if (ia) *ia = NULL;
8281     if (ja) *ja = NULL;
8282   }
8283   PetscFunctionReturn(PETSC_SUCCESS);
8284 }
8285 
8286 /*@C
8287   MatRestoreColumnIJ - Call after you are completed with the ia,ja indices obtained with `MatGetColumnIJ()`.
8288 
8289   Collective
8290 
8291   Input Parameters:
8292 + mat             - the matrix
8293 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8294 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8295 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8296                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8297                     always used.
8298 
8299   Output Parameters:
8300 + n    - size of (possibly compressed) matrix
8301 . ia   - the column pointers
8302 . ja   - the row indices
8303 - done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8304 
8305   Level: developer
8306 
8307 .seealso: [](ch_matrices), `Mat`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`
8308 @*/
8309 PetscErrorCode MatRestoreColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8310 {
8311   PetscFunctionBegin;
8312   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8313   PetscValidType(mat, 1);
8314   if (ia) PetscAssertPointer(ia, 6);
8315   if (ja) PetscAssertPointer(ja, 7);
8316   PetscAssertPointer(done, 8);
8317   MatCheckPreallocated(mat, 1);
8318 
8319   if (!mat->ops->restorecolumnij) *done = PETSC_FALSE;
8320   else {
8321     *done = PETSC_TRUE;
8322     PetscUseTypeMethod(mat, restorecolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8323     if (n) *n = 0;
8324     if (ia) *ia = NULL;
8325     if (ja) *ja = NULL;
8326   }
8327   PetscFunctionReturn(PETSC_SUCCESS);
8328 }
8329 
8330 /*@
8331   MatColoringPatch - Used inside matrix coloring routines that use `MatGetRowIJ()` and/or
8332   `MatGetColumnIJ()`.
8333 
8334   Collective
8335 
8336   Input Parameters:
8337 + mat        - the matrix
8338 . ncolors    - maximum color value
8339 . n          - number of entries in colorarray
8340 - colorarray - array indicating color for each column
8341 
8342   Output Parameter:
8343 . iscoloring - coloring generated using colorarray information
8344 
8345   Level: developer
8346 
8347 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatGetColumnIJ()`
8348 @*/
8349 PetscErrorCode MatColoringPatch(Mat mat, PetscInt ncolors, PetscInt n, ISColoringValue colorarray[], ISColoring *iscoloring)
8350 {
8351   PetscFunctionBegin;
8352   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8353   PetscValidType(mat, 1);
8354   PetscAssertPointer(colorarray, 4);
8355   PetscAssertPointer(iscoloring, 5);
8356   MatCheckPreallocated(mat, 1);
8357 
8358   if (!mat->ops->coloringpatch) {
8359     PetscCall(ISColoringCreate(PetscObjectComm((PetscObject)mat), ncolors, n, colorarray, PETSC_OWN_POINTER, iscoloring));
8360   } else {
8361     PetscUseTypeMethod(mat, coloringpatch, ncolors, n, colorarray, iscoloring);
8362   }
8363   PetscFunctionReturn(PETSC_SUCCESS);
8364 }
8365 
8366 /*@
8367   MatSetUnfactored - Resets a factored matrix to be treated as unfactored.
8368 
8369   Logically Collective
8370 
8371   Input Parameter:
8372 . mat - the factored matrix to be reset
8373 
8374   Level: developer
8375 
8376   Notes:
8377   This routine should be used only with factored matrices formed by in-place
8378   factorization via ILU(0) (or by in-place LU factorization for the `MATSEQDENSE`
8379   format).  This option can save memory, for example, when solving nonlinear
8380   systems with a matrix-free Newton-Krylov method and a matrix-based, in-place
8381   ILU(0) preconditioner.
8382 
8383   One can specify in-place ILU(0) factorization by calling
8384 .vb
8385      PCType(pc,PCILU);
8386      PCFactorSeUseInPlace(pc);
8387 .ve
8388   or by using the options -pc_type ilu -pc_factor_in_place
8389 
8390   In-place factorization ILU(0) can also be used as a local
8391   solver for the blocks within the block Jacobi or additive Schwarz
8392   methods (runtime option: -sub_pc_factor_in_place).  See Users-Manual: ch_pc
8393   for details on setting local solver options.
8394 
8395   Most users should employ the `KSP` interface for linear solvers
8396   instead of working directly with matrix algebra routines such as this.
8397   See, e.g., `KSPCreate()`.
8398 
8399 .seealso: [](ch_matrices), `Mat`, `PCFactorSetUseInPlace()`, `PCFactorGetUseInPlace()`
8400 @*/
8401 PetscErrorCode MatSetUnfactored(Mat mat)
8402 {
8403   PetscFunctionBegin;
8404   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8405   PetscValidType(mat, 1);
8406   MatCheckPreallocated(mat, 1);
8407   mat->factortype = MAT_FACTOR_NONE;
8408   if (!mat->ops->setunfactored) PetscFunctionReturn(PETSC_SUCCESS);
8409   PetscUseTypeMethod(mat, setunfactored);
8410   PetscFunctionReturn(PETSC_SUCCESS);
8411 }
8412 
8413 /*@
8414   MatCreateSubMatrix - Gets a single submatrix on the same number of processors
8415   as the original matrix.
8416 
8417   Collective
8418 
8419   Input Parameters:
8420 + mat   - the original matrix
8421 . isrow - parallel `IS` containing the rows this processor should obtain
8422 . iscol - parallel `IS` containing all columns you wish to keep. Each process should list the columns that will be in IT's "diagonal part" in the new matrix.
8423 - cll   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
8424 
8425   Output Parameter:
8426 . newmat - the new submatrix, of the same type as the original matrix
8427 
8428   Level: advanced
8429 
8430   Notes:
8431   The submatrix will be able to be multiplied with vectors using the same layout as `iscol`.
8432 
8433   Some matrix types place restrictions on the row and column indices, such
8434   as that they be sorted or that they be equal to each other. For `MATBAIJ` and `MATSBAIJ` matrices the indices must include all rows/columns of a block;
8435   for example, if the block size is 3 one cannot select the 0 and 2 rows without selecting the 1 row.
8436 
8437   The index sets may not have duplicate entries.
8438 
8439   The first time this is called you should use a cll of `MAT_INITIAL_MATRIX`,
8440   the `MatCreateSubMatrix()` routine will create the newmat for you. Any additional calls
8441   to this routine with a mat of the same nonzero structure and with a call of `MAT_REUSE_MATRIX`
8442   will reuse the matrix generated the first time.  You should call `MatDestroy()` on `newmat` when
8443   you are finished using it.
8444 
8445   The communicator of the newly obtained matrix is ALWAYS the same as the communicator of
8446   the input matrix.
8447 
8448   If `iscol` is `NULL` then all columns are obtained (not supported in Fortran).
8449 
8450   If `isrow` and `iscol` have a nontrivial block-size, then the resulting matrix has this block-size as well. This feature
8451   is used by `PCFIELDSPLIT` to allow easy nesting of its use.
8452 
8453   Example usage:
8454   Consider the following 8x8 matrix with 34 non-zero values, that is
8455   assembled across 3 processors. Let's assume that proc0 owns 3 rows,
8456   proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
8457   as follows
8458 .vb
8459             1  2  0  |  0  3  0  |  0  4
8460     Proc0   0  5  6  |  7  0  0  |  8  0
8461             9  0 10  | 11  0  0  | 12  0
8462     -------------------------------------
8463            13  0 14  | 15 16 17  |  0  0
8464     Proc1   0 18  0  | 19 20 21  |  0  0
8465             0  0  0  | 22 23  0  | 24  0
8466     -------------------------------------
8467     Proc2  25 26 27  |  0  0 28  | 29  0
8468            30  0  0  | 31 32 33  |  0 34
8469 .ve
8470 
8471   Suppose `isrow` = [0 1 | 4 | 6 7] and `iscol` = [1 2 | 3 4 5 | 6].  The resulting submatrix is
8472 
8473 .vb
8474             2  0  |  0  3  0  |  0
8475     Proc0   5  6  |  7  0  0  |  8
8476     -------------------------------
8477     Proc1  18  0  | 19 20 21  |  0
8478     -------------------------------
8479     Proc2  26 27  |  0  0 28  | 29
8480             0  0  | 31 32 33  |  0
8481 .ve
8482 
8483 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatCreateSubMatricesMPI()`, `MatCreateSubMatrixVirtual()`, `MatSubMatrixVirtualUpdate()`
8484 @*/
8485 PetscErrorCode MatCreateSubMatrix(Mat mat, IS isrow, IS iscol, MatReuse cll, Mat *newmat)
8486 {
8487   PetscMPIInt size;
8488   Mat        *local;
8489   IS          iscoltmp;
8490   PetscBool   flg;
8491 
8492   PetscFunctionBegin;
8493   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8494   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
8495   if (iscol) PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
8496   PetscAssertPointer(newmat, 5);
8497   if (cll == MAT_REUSE_MATRIX) PetscValidHeaderSpecific(*newmat, MAT_CLASSID, 5);
8498   PetscValidType(mat, 1);
8499   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
8500   PetscCheck(cll != MAT_IGNORE_MATRIX, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot use MAT_IGNORE_MATRIX");
8501 
8502   MatCheckPreallocated(mat, 1);
8503   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
8504 
8505   if (!iscol || isrow == iscol) {
8506     PetscBool   stride;
8507     PetscMPIInt grabentirematrix = 0, grab;
8508     PetscCall(PetscObjectTypeCompare((PetscObject)isrow, ISSTRIDE, &stride));
8509     if (stride) {
8510       PetscInt first, step, n, rstart, rend;
8511       PetscCall(ISStrideGetInfo(isrow, &first, &step));
8512       if (step == 1) {
8513         PetscCall(MatGetOwnershipRange(mat, &rstart, &rend));
8514         if (rstart == first) {
8515           PetscCall(ISGetLocalSize(isrow, &n));
8516           if (n == rend - rstart) grabentirematrix = 1;
8517         }
8518       }
8519     }
8520     PetscCallMPI(MPIU_Allreduce(&grabentirematrix, &grab, 1, MPI_INT, MPI_MIN, PetscObjectComm((PetscObject)mat)));
8521     if (grab) {
8522       PetscCall(PetscInfo(mat, "Getting entire matrix as submatrix\n"));
8523       if (cll == MAT_INITIAL_MATRIX) {
8524         *newmat = mat;
8525         PetscCall(PetscObjectReference((PetscObject)mat));
8526       }
8527       PetscFunctionReturn(PETSC_SUCCESS);
8528     }
8529   }
8530 
8531   if (!iscol) {
8532     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)mat), mat->cmap->n, mat->cmap->rstart, 1, &iscoltmp));
8533   } else {
8534     iscoltmp = iscol;
8535   }
8536 
8537   /* if original matrix is on just one processor then use submatrix generated */
8538   if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1 && cll == MAT_REUSE_MATRIX) {
8539     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_REUSE_MATRIX, &newmat));
8540     goto setproperties;
8541   } else if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1) {
8542     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_INITIAL_MATRIX, &local));
8543     *newmat = *local;
8544     PetscCall(PetscFree(local));
8545     goto setproperties;
8546   } else if (!mat->ops->createsubmatrix) {
8547     /* Create a new matrix type that implements the operation using the full matrix */
8548     PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8549     switch (cll) {
8550     case MAT_INITIAL_MATRIX:
8551       PetscCall(MatCreateSubMatrixVirtual(mat, isrow, iscoltmp, newmat));
8552       break;
8553     case MAT_REUSE_MATRIX:
8554       PetscCall(MatSubMatrixVirtualUpdate(*newmat, mat, isrow, iscoltmp));
8555       break;
8556     default:
8557       SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Invalid MatReuse, must be either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX");
8558     }
8559     PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8560     goto setproperties;
8561   }
8562 
8563   PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8564   PetscUseTypeMethod(mat, createsubmatrix, isrow, iscoltmp, cll, newmat);
8565   PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8566 
8567 setproperties:
8568   if ((*newmat)->symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->structurally_symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->spd == PETSC_BOOL3_UNKNOWN && (*newmat)->hermitian == PETSC_BOOL3_UNKNOWN) {
8569     PetscCall(ISEqualUnsorted(isrow, iscoltmp, &flg));
8570     if (flg) PetscCall(MatPropagateSymmetryOptions(mat, *newmat));
8571   }
8572   if (!iscol) PetscCall(ISDestroy(&iscoltmp));
8573   if (*newmat && cll == MAT_INITIAL_MATRIX) PetscCall(PetscObjectStateIncrease((PetscObject)*newmat));
8574   if (!iscol || isrow == iscol) PetscCall(MatSelectVariableBlockSizes(*newmat, mat, isrow));
8575   PetscFunctionReturn(PETSC_SUCCESS);
8576 }
8577 
8578 /*@
8579   MatPropagateSymmetryOptions - Propagates symmetry options set on a matrix to another matrix
8580 
8581   Not Collective
8582 
8583   Input Parameters:
8584 + A - the matrix we wish to propagate options from
8585 - B - the matrix we wish to propagate options to
8586 
8587   Level: beginner
8588 
8589   Note:
8590   Propagates the options associated to `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_HERMITIAN`, `MAT_SPD`, `MAT_SYMMETRIC`, and `MAT_STRUCTURAL_SYMMETRY_ETERNAL`
8591 
8592 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatIsSymmetricKnown()`, `MatIsSPDKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
8593 @*/
8594 PetscErrorCode MatPropagateSymmetryOptions(Mat A, Mat B)
8595 {
8596   PetscFunctionBegin;
8597   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8598   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
8599   B->symmetry_eternal            = A->symmetry_eternal;
8600   B->structural_symmetry_eternal = A->structural_symmetry_eternal;
8601   B->symmetric                   = A->symmetric;
8602   B->structurally_symmetric      = A->structurally_symmetric;
8603   B->spd                         = A->spd;
8604   B->hermitian                   = A->hermitian;
8605   PetscFunctionReturn(PETSC_SUCCESS);
8606 }
8607 
8608 /*@
8609   MatStashSetInitialSize - sets the sizes of the matrix stash, that is
8610   used during the assembly process to store values that belong to
8611   other processors.
8612 
8613   Not Collective
8614 
8615   Input Parameters:
8616 + mat   - the matrix
8617 . size  - the initial size of the stash.
8618 - bsize - the initial size of the block-stash(if used).
8619 
8620   Options Database Keys:
8621 + -matstash_initial_size <size> or <size0,size1,...sizep-1>            - set initial size
8622 - -matstash_block_initial_size <bsize>  or <bsize0,bsize1,...bsizep-1> - set initial block size
8623 
8624   Level: intermediate
8625 
8626   Notes:
8627   The block-stash is used for values set with `MatSetValuesBlocked()` while
8628   the stash is used for values set with `MatSetValues()`
8629 
8630   Run with the option -info and look for output of the form
8631   MatAssemblyBegin_MPIXXX:Stash has MM entries, uses nn mallocs.
8632   to determine the appropriate value, MM, to use for size and
8633   MatAssemblyBegin_MPIXXX:Block-Stash has BMM entries, uses nn mallocs.
8634   to determine the value, BMM to use for bsize
8635 
8636 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashGetInfo()`
8637 @*/
8638 PetscErrorCode MatStashSetInitialSize(Mat mat, PetscInt size, PetscInt bsize)
8639 {
8640   PetscFunctionBegin;
8641   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8642   PetscValidType(mat, 1);
8643   PetscCall(MatStashSetInitialSize_Private(&mat->stash, size));
8644   PetscCall(MatStashSetInitialSize_Private(&mat->bstash, bsize));
8645   PetscFunctionReturn(PETSC_SUCCESS);
8646 }
8647 
8648 /*@
8649   MatInterpolateAdd - $w = y + A*x$ or $A^T*x$ depending on the shape of
8650   the matrix
8651 
8652   Neighbor-wise Collective
8653 
8654   Input Parameters:
8655 + A - the matrix
8656 . x - the vector to be multiplied by the interpolation operator
8657 - y - the vector to be added to the result
8658 
8659   Output Parameter:
8660 . w - the resulting vector
8661 
8662   Level: intermediate
8663 
8664   Notes:
8665   `w` may be the same vector as `y`.
8666 
8667   This allows one to use either the restriction or interpolation (its transpose)
8668   matrix to do the interpolation
8669 
8670 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8671 @*/
8672 PetscErrorCode MatInterpolateAdd(Mat A, Vec x, Vec y, Vec w)
8673 {
8674   PetscInt M, N, Ny;
8675 
8676   PetscFunctionBegin;
8677   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8678   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8679   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8680   PetscValidHeaderSpecific(w, VEC_CLASSID, 4);
8681   PetscCall(MatGetSize(A, &M, &N));
8682   PetscCall(VecGetSize(y, &Ny));
8683   if (M == Ny) {
8684     PetscCall(MatMultAdd(A, x, y, w));
8685   } else {
8686     PetscCall(MatMultTransposeAdd(A, x, y, w));
8687   }
8688   PetscFunctionReturn(PETSC_SUCCESS);
8689 }
8690 
8691 /*@
8692   MatInterpolate - $y = A*x$ or $A^T*x$ depending on the shape of
8693   the matrix
8694 
8695   Neighbor-wise Collective
8696 
8697   Input Parameters:
8698 + A - the matrix
8699 - x - the vector to be interpolated
8700 
8701   Output Parameter:
8702 . y - the resulting vector
8703 
8704   Level: intermediate
8705 
8706   Note:
8707   This allows one to use either the restriction or interpolation (its transpose)
8708   matrix to do the interpolation
8709 
8710 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8711 @*/
8712 PetscErrorCode MatInterpolate(Mat A, Vec x, Vec y)
8713 {
8714   PetscInt M, N, Ny;
8715 
8716   PetscFunctionBegin;
8717   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8718   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8719   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8720   PetscCall(MatGetSize(A, &M, &N));
8721   PetscCall(VecGetSize(y, &Ny));
8722   if (M == Ny) {
8723     PetscCall(MatMult(A, x, y));
8724   } else {
8725     PetscCall(MatMultTranspose(A, x, y));
8726   }
8727   PetscFunctionReturn(PETSC_SUCCESS);
8728 }
8729 
8730 /*@
8731   MatRestrict - $y = A*x$ or $A^T*x$
8732 
8733   Neighbor-wise Collective
8734 
8735   Input Parameters:
8736 + A - the matrix
8737 - x - the vector to be restricted
8738 
8739   Output Parameter:
8740 . y - the resulting vector
8741 
8742   Level: intermediate
8743 
8744   Note:
8745   This allows one to use either the restriction or interpolation (its transpose)
8746   matrix to do the restriction
8747 
8748 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatInterpolate()`, `PCMG`
8749 @*/
8750 PetscErrorCode MatRestrict(Mat A, Vec x, Vec y)
8751 {
8752   PetscInt M, N, Nx;
8753 
8754   PetscFunctionBegin;
8755   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8756   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8757   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8758   PetscCall(MatGetSize(A, &M, &N));
8759   PetscCall(VecGetSize(x, &Nx));
8760   if (M == Nx) {
8761     PetscCall(MatMultTranspose(A, x, y));
8762   } else {
8763     PetscCall(MatMult(A, x, y));
8764   }
8765   PetscFunctionReturn(PETSC_SUCCESS);
8766 }
8767 
8768 /*@
8769   MatMatInterpolateAdd - $Y = W + A*X$ or $W + A^T*X$ depending on the shape of `A`
8770 
8771   Neighbor-wise Collective
8772 
8773   Input Parameters:
8774 + A - the matrix
8775 . x - the input dense matrix to be multiplied
8776 - w - the input dense matrix to be added to the result
8777 
8778   Output Parameter:
8779 . y - the output dense matrix
8780 
8781   Level: intermediate
8782 
8783   Note:
8784   This allows one to use either the restriction or interpolation (its transpose)
8785   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8786   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8787 
8788 .seealso: [](ch_matrices), `Mat`, `MatInterpolateAdd()`, `MatMatInterpolate()`, `MatMatRestrict()`, `PCMG`
8789 @*/
8790 PetscErrorCode MatMatInterpolateAdd(Mat A, Mat x, Mat w, Mat *y)
8791 {
8792   PetscInt  M, N, Mx, Nx, Mo, My = 0, Ny = 0;
8793   PetscBool trans = PETSC_TRUE;
8794   MatReuse  reuse = MAT_INITIAL_MATRIX;
8795 
8796   PetscFunctionBegin;
8797   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8798   PetscValidHeaderSpecific(x, MAT_CLASSID, 2);
8799   PetscValidType(x, 2);
8800   if (w) PetscValidHeaderSpecific(w, MAT_CLASSID, 3);
8801   if (*y) PetscValidHeaderSpecific(*y, MAT_CLASSID, 4);
8802   PetscCall(MatGetSize(A, &M, &N));
8803   PetscCall(MatGetSize(x, &Mx, &Nx));
8804   if (N == Mx) trans = PETSC_FALSE;
8805   else PetscCheck(M == Mx, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Size mismatch: A %" PetscInt_FMT "x%" PetscInt_FMT ", X %" PetscInt_FMT "x%" PetscInt_FMT, M, N, Mx, Nx);
8806   Mo = trans ? N : M;
8807   if (*y) {
8808     PetscCall(MatGetSize(*y, &My, &Ny));
8809     if (Mo == My && Nx == Ny) {
8810       reuse = MAT_REUSE_MATRIX;
8811     } else {
8812       PetscCheck(w || *y != w, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot reuse y and w, size mismatch: A %" PetscInt_FMT "x%" PetscInt_FMT ", X %" PetscInt_FMT "x%" PetscInt_FMT ", Y %" PetscInt_FMT "x%" PetscInt_FMT, M, N, Mx, Nx, My, Ny);
8813       PetscCall(MatDestroy(y));
8814     }
8815   }
8816 
8817   if (w && *y == w) { /* this is to minimize changes in PCMG */
8818     PetscBool flg;
8819 
8820     PetscCall(PetscObjectQuery((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject *)&w));
8821     if (w) {
8822       PetscInt My, Ny, Mw, Nw;
8823 
8824       PetscCall(PetscObjectTypeCompare((PetscObject)*y, ((PetscObject)w)->type_name, &flg));
8825       PetscCall(MatGetSize(*y, &My, &Ny));
8826       PetscCall(MatGetSize(w, &Mw, &Nw));
8827       if (!flg || My != Mw || Ny != Nw) w = NULL;
8828     }
8829     if (!w) {
8830       PetscCall(MatDuplicate(*y, MAT_COPY_VALUES, &w));
8831       PetscCall(PetscObjectCompose((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject)w));
8832       PetscCall(PetscObjectDereference((PetscObject)w));
8833     } else {
8834       PetscCall(MatCopy(*y, w, UNKNOWN_NONZERO_PATTERN));
8835     }
8836   }
8837   if (!trans) {
8838     PetscCall(MatMatMult(A, x, reuse, PETSC_DETERMINE, y));
8839   } else {
8840     PetscCall(MatTransposeMatMult(A, x, reuse, PETSC_DETERMINE, y));
8841   }
8842   if (w) PetscCall(MatAXPY(*y, 1.0, w, UNKNOWN_NONZERO_PATTERN));
8843   PetscFunctionReturn(PETSC_SUCCESS);
8844 }
8845 
8846 /*@
8847   MatMatInterpolate - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8848 
8849   Neighbor-wise Collective
8850 
8851   Input Parameters:
8852 + A - the matrix
8853 - x - the input dense matrix
8854 
8855   Output Parameter:
8856 . y - the output dense matrix
8857 
8858   Level: intermediate
8859 
8860   Note:
8861   This allows one to use either the restriction or interpolation (its transpose)
8862   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8863   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8864 
8865 .seealso: [](ch_matrices), `Mat`, `MatInterpolate()`, `MatRestrict()`, `MatMatRestrict()`, `PCMG`
8866 @*/
8867 PetscErrorCode MatMatInterpolate(Mat A, Mat x, Mat *y)
8868 {
8869   PetscFunctionBegin;
8870   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8871   PetscFunctionReturn(PETSC_SUCCESS);
8872 }
8873 
8874 /*@
8875   MatMatRestrict - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8876 
8877   Neighbor-wise Collective
8878 
8879   Input Parameters:
8880 + A - the matrix
8881 - x - the input dense matrix
8882 
8883   Output Parameter:
8884 . y - the output dense matrix
8885 
8886   Level: intermediate
8887 
8888   Note:
8889   This allows one to use either the restriction or interpolation (its transpose)
8890   matrix to do the restriction. `y` matrix can be reused if already created with the proper sizes,
8891   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8892 
8893 .seealso: [](ch_matrices), `Mat`, `MatRestrict()`, `MatInterpolate()`, `MatMatInterpolate()`, `PCMG`
8894 @*/
8895 PetscErrorCode MatMatRestrict(Mat A, Mat x, Mat *y)
8896 {
8897   PetscFunctionBegin;
8898   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8899   PetscFunctionReturn(PETSC_SUCCESS);
8900 }
8901 
8902 /*@
8903   MatGetNullSpace - retrieves the null space of a matrix.
8904 
8905   Logically Collective
8906 
8907   Input Parameters:
8908 + mat    - the matrix
8909 - nullsp - the null space object
8910 
8911   Level: developer
8912 
8913 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetNullSpace()`, `MatNullSpace`
8914 @*/
8915 PetscErrorCode MatGetNullSpace(Mat mat, MatNullSpace *nullsp)
8916 {
8917   PetscFunctionBegin;
8918   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8919   PetscAssertPointer(nullsp, 2);
8920   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->nullsp) ? mat->transnullsp : mat->nullsp;
8921   PetscFunctionReturn(PETSC_SUCCESS);
8922 }
8923 
8924 /*@C
8925   MatGetNullSpaces - gets the null spaces, transpose null spaces, and near null spaces from an array of matrices
8926 
8927   Logically Collective
8928 
8929   Input Parameters:
8930 + n   - the number of matrices
8931 - mat - the array of matrices
8932 
8933   Output Parameters:
8934 . nullsp - an array of null spaces, `NULL` for each matrix that does not have a null space, length 3 * `n`
8935 
8936   Level: developer
8937 
8938   Note:
8939   Call `MatRestoreNullspaces()` to provide these to another array of matrices
8940 
8941 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8942           `MatNullSpaceRemove()`, `MatRestoreNullSpaces()`
8943 @*/
8944 PetscErrorCode MatGetNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8945 {
8946   PetscFunctionBegin;
8947   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8948   PetscAssertPointer(mat, 2);
8949   PetscAssertPointer(nullsp, 3);
8950 
8951   PetscCall(PetscCalloc1(3 * n, nullsp));
8952   for (PetscInt i = 0; i < n; i++) {
8953     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8954     (*nullsp)[i] = mat[i]->nullsp;
8955     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[i]));
8956     (*nullsp)[n + i] = mat[i]->nearnullsp;
8957     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[n + i]));
8958     (*nullsp)[2 * n + i] = mat[i]->transnullsp;
8959     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[2 * n + i]));
8960   }
8961   PetscFunctionReturn(PETSC_SUCCESS);
8962 }
8963 
8964 /*@C
8965   MatRestoreNullSpaces - sets the null spaces, transpose null spaces, and near null spaces obtained with `MatGetNullSpaces()` for an array of matrices
8966 
8967   Logically Collective
8968 
8969   Input Parameters:
8970 + n      - the number of matrices
8971 . mat    - the array of matrices
8972 - nullsp - an array of null spaces
8973 
8974   Level: developer
8975 
8976   Note:
8977   Call `MatGetNullSpaces()` to create `nullsp`
8978 
8979 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8980           `MatNullSpaceRemove()`, `MatGetNullSpaces()`
8981 @*/
8982 PetscErrorCode MatRestoreNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8983 {
8984   PetscFunctionBegin;
8985   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8986   PetscAssertPointer(mat, 2);
8987   PetscAssertPointer(nullsp, 3);
8988   PetscAssertPointer(*nullsp, 3);
8989 
8990   for (PetscInt i = 0; i < n; i++) {
8991     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8992     PetscCall(MatSetNullSpace(mat[i], (*nullsp)[i]));
8993     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[i]));
8994     PetscCall(MatSetNearNullSpace(mat[i], (*nullsp)[n + i]));
8995     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[n + i]));
8996     PetscCall(MatSetTransposeNullSpace(mat[i], (*nullsp)[2 * n + i]));
8997     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[2 * n + i]));
8998   }
8999   PetscCall(PetscFree(*nullsp));
9000   PetscFunctionReturn(PETSC_SUCCESS);
9001 }
9002 
9003 /*@
9004   MatSetNullSpace - attaches a null space to a matrix.
9005 
9006   Logically Collective
9007 
9008   Input Parameters:
9009 + mat    - the matrix
9010 - nullsp - the null space object
9011 
9012   Level: advanced
9013 
9014   Notes:
9015   This null space is used by the `KSP` linear solvers to solve singular systems.
9016 
9017   Overwrites any previous null space that may have been attached. You can remove the null space from the matrix object by calling this routine with an nullsp of `NULL`
9018 
9019   For inconsistent singular systems (linear systems where the right-hand side is not in the range of the operator) the `KSP` residuals will not converge
9020   to zero but the linear system will still be solved in a least squares sense.
9021 
9022   The fundamental theorem of linear algebra (Gilbert Strang, Introduction to Applied Mathematics, page 72) states that
9023   the domain of a matrix $A$ (from $R^n$ to $R^m$ ($m$ rows, $n$ columns) $R^n$ = the direct sum of the null space of $A$, $n(A)$, plus the range of $A^T$, $R(A^T)$.
9024   Similarly $R^m$ = direct sum $n(A^T) + R(A)$.  Hence the linear system $A x = b$ has a solution only if $b$ in $R(A)$ (or correspondingly $b$ is orthogonal to
9025   $n(A^T))$ and if $x$ is a solution then $x + \alpha n(A)$ is a solution for any $\alpha$. The minimum norm solution is orthogonal to $n(A)$. For problems without a solution
9026   the solution that minimizes the norm of the residual (the least squares solution) can be obtained by solving $A x = \hat{b}$ where $\hat{b}$ is $b$ orthogonalized to the $n(A^T)$.
9027   This  $\hat{b}$ can be obtained by calling `MatNullSpaceRemove()` with the null space of the transpose of the matrix.
9028 
9029   If the matrix is known to be symmetric because it is an `MATSBAIJ` matrix or one has called
9030   `MatSetOption`(mat,`MAT_SYMMETRIC` or possibly `MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`); this
9031   routine also automatically calls `MatSetTransposeNullSpace()`.
9032 
9033   The user should call `MatNullSpaceDestroy()`.
9034 
9035 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`,
9036           `KSPSetPCSide()`
9037 @*/
9038 PetscErrorCode MatSetNullSpace(Mat mat, MatNullSpace nullsp)
9039 {
9040   PetscFunctionBegin;
9041   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9042   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9043   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9044   PetscCall(MatNullSpaceDestroy(&mat->nullsp));
9045   mat->nullsp = nullsp;
9046   if (mat->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetTransposeNullSpace(mat, nullsp));
9047   PetscFunctionReturn(PETSC_SUCCESS);
9048 }
9049 
9050 /*@
9051   MatGetTransposeNullSpace - retrieves the null space of the transpose of a matrix.
9052 
9053   Logically Collective
9054 
9055   Input Parameters:
9056 + mat    - the matrix
9057 - nullsp - the null space object
9058 
9059   Level: developer
9060 
9061 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetTransposeNullSpace()`, `MatSetNullSpace()`, `MatGetNullSpace()`
9062 @*/
9063 PetscErrorCode MatGetTransposeNullSpace(Mat mat, MatNullSpace *nullsp)
9064 {
9065   PetscFunctionBegin;
9066   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9067   PetscValidType(mat, 1);
9068   PetscAssertPointer(nullsp, 2);
9069   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->transnullsp) ? mat->nullsp : mat->transnullsp;
9070   PetscFunctionReturn(PETSC_SUCCESS);
9071 }
9072 
9073 /*@
9074   MatSetTransposeNullSpace - attaches the null space of a transpose of a matrix to the matrix
9075 
9076   Logically Collective
9077 
9078   Input Parameters:
9079 + mat    - the matrix
9080 - nullsp - the null space object
9081 
9082   Level: advanced
9083 
9084   Notes:
9085   This allows solving singular linear systems defined by the transpose of the matrix using `KSP` solvers with left preconditioning.
9086 
9087   See `MatSetNullSpace()`
9088 
9089 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`, `KSPSetPCSide()`
9090 @*/
9091 PetscErrorCode MatSetTransposeNullSpace(Mat mat, MatNullSpace nullsp)
9092 {
9093   PetscFunctionBegin;
9094   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9095   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9096   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9097   PetscCall(MatNullSpaceDestroy(&mat->transnullsp));
9098   mat->transnullsp = nullsp;
9099   PetscFunctionReturn(PETSC_SUCCESS);
9100 }
9101 
9102 /*@
9103   MatSetNearNullSpace - attaches a null space to a matrix, which is often the null space (rigid body modes) of the operator without boundary conditions
9104   This null space will be used to provide near null space vectors to a multigrid preconditioner built from this matrix.
9105 
9106   Logically Collective
9107 
9108   Input Parameters:
9109 + mat    - the matrix
9110 - nullsp - the null space object
9111 
9112   Level: advanced
9113 
9114   Notes:
9115   Overwrites any previous near null space that may have been attached
9116 
9117   You can remove the null space by calling this routine with an `nullsp` of `NULL`
9118 
9119 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNullSpace()`, `MatNullSpaceCreateRigidBody()`, `MatGetNearNullSpace()`
9120 @*/
9121 PetscErrorCode MatSetNearNullSpace(Mat mat, MatNullSpace nullsp)
9122 {
9123   PetscFunctionBegin;
9124   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9125   PetscValidType(mat, 1);
9126   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9127   MatCheckPreallocated(mat, 1);
9128   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9129   PetscCall(MatNullSpaceDestroy(&mat->nearnullsp));
9130   mat->nearnullsp = nullsp;
9131   PetscFunctionReturn(PETSC_SUCCESS);
9132 }
9133 
9134 /*@
9135   MatGetNearNullSpace - Get null space attached with `MatSetNearNullSpace()`
9136 
9137   Not Collective
9138 
9139   Input Parameter:
9140 . mat - the matrix
9141 
9142   Output Parameter:
9143 . nullsp - the null space object, `NULL` if not set
9144 
9145   Level: advanced
9146 
9147 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatNullSpaceCreate()`
9148 @*/
9149 PetscErrorCode MatGetNearNullSpace(Mat mat, MatNullSpace *nullsp)
9150 {
9151   PetscFunctionBegin;
9152   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9153   PetscValidType(mat, 1);
9154   PetscAssertPointer(nullsp, 2);
9155   MatCheckPreallocated(mat, 1);
9156   *nullsp = mat->nearnullsp;
9157   PetscFunctionReturn(PETSC_SUCCESS);
9158 }
9159 
9160 /*@
9161   MatICCFactor - Performs in-place incomplete Cholesky factorization of matrix.
9162 
9163   Collective
9164 
9165   Input Parameters:
9166 + mat  - the matrix
9167 . row  - row/column permutation
9168 - info - information on desired factorization process
9169 
9170   Level: developer
9171 
9172   Notes:
9173   Probably really in-place only when level of fill is zero, otherwise allocates
9174   new space to store factored matrix and deletes previous memory.
9175 
9176   Most users should employ the `KSP` interface for linear solvers
9177   instead of working directly with matrix algebra routines such as this.
9178   See, e.g., `KSPCreate()`.
9179 
9180   Fortran Note:
9181   A valid (non-null) `info` argument must be provided
9182 
9183 .seealso: [](ch_matrices), `Mat`, `MatFactorInfo`, `MatGetFactor()`, `MatICCFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
9184 @*/
9185 PetscErrorCode MatICCFactor(Mat mat, IS row, const MatFactorInfo *info)
9186 {
9187   PetscFunctionBegin;
9188   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9189   PetscValidType(mat, 1);
9190   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
9191   PetscAssertPointer(info, 3);
9192   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
9193   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
9194   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9195   MatCheckPreallocated(mat, 1);
9196   PetscUseTypeMethod(mat, iccfactor, row, info);
9197   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9198   PetscFunctionReturn(PETSC_SUCCESS);
9199 }
9200 
9201 /*@
9202   MatDiagonalScaleLocal - Scales columns of a matrix given the scaling values including the
9203   ghosted ones.
9204 
9205   Not Collective
9206 
9207   Input Parameters:
9208 + mat  - the matrix
9209 - diag - the diagonal values, including ghost ones
9210 
9211   Level: developer
9212 
9213   Notes:
9214   Works only for `MATMPIAIJ` and `MATMPIBAIJ` matrices
9215 
9216   This allows one to avoid during communication to perform the scaling that must be done with `MatDiagonalScale()`
9217 
9218 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
9219 @*/
9220 PetscErrorCode MatDiagonalScaleLocal(Mat mat, Vec diag)
9221 {
9222   PetscMPIInt size;
9223 
9224   PetscFunctionBegin;
9225   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9226   PetscValidHeaderSpecific(diag, VEC_CLASSID, 2);
9227   PetscValidType(mat, 1);
9228 
9229   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must be already assembled");
9230   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
9231   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
9232   if (size == 1) {
9233     PetscInt n, m;
9234     PetscCall(VecGetSize(diag, &n));
9235     PetscCall(MatGetSize(mat, NULL, &m));
9236     PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supported for sequential matrices when no ghost points/periodic conditions");
9237     PetscCall(MatDiagonalScale(mat, NULL, diag));
9238   } else {
9239     PetscUseMethod(mat, "MatDiagonalScaleLocal_C", (Mat, Vec), (mat, diag));
9240   }
9241   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
9242   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9243   PetscFunctionReturn(PETSC_SUCCESS);
9244 }
9245 
9246 /*@
9247   MatGetInertia - Gets the inertia from a factored matrix
9248 
9249   Collective
9250 
9251   Input Parameter:
9252 . mat - the matrix
9253 
9254   Output Parameters:
9255 + nneg  - number of negative eigenvalues
9256 . nzero - number of zero eigenvalues
9257 - npos  - number of positive eigenvalues
9258 
9259   Level: advanced
9260 
9261   Note:
9262   Matrix must have been factored by `MatCholeskyFactor()`
9263 
9264 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactor()`
9265 @*/
9266 PetscErrorCode MatGetInertia(Mat mat, PetscInt *nneg, PetscInt *nzero, PetscInt *npos)
9267 {
9268   PetscFunctionBegin;
9269   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9270   PetscValidType(mat, 1);
9271   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9272   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Numeric factor mat is not assembled");
9273   PetscUseTypeMethod(mat, getinertia, nneg, nzero, npos);
9274   PetscFunctionReturn(PETSC_SUCCESS);
9275 }
9276 
9277 /*@C
9278   MatSolves - Solves $A x = b$, given a factored matrix, for a collection of vectors
9279 
9280   Neighbor-wise Collective
9281 
9282   Input Parameters:
9283 + mat - the factored matrix obtained with `MatGetFactor()`
9284 - b   - the right-hand-side vectors
9285 
9286   Output Parameter:
9287 . x - the result vectors
9288 
9289   Level: developer
9290 
9291   Note:
9292   The vectors `b` and `x` cannot be the same.  I.e., one cannot
9293   call `MatSolves`(A,x,x).
9294 
9295 .seealso: [](ch_matrices), `Mat`, `Vecs`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`, `MatSolve()`
9296 @*/
9297 PetscErrorCode MatSolves(Mat mat, Vecs b, Vecs x)
9298 {
9299   PetscFunctionBegin;
9300   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9301   PetscValidType(mat, 1);
9302   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
9303   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9304   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
9305 
9306   MatCheckPreallocated(mat, 1);
9307   PetscCall(PetscLogEventBegin(MAT_Solves, mat, 0, 0, 0));
9308   PetscUseTypeMethod(mat, solves, b, x);
9309   PetscCall(PetscLogEventEnd(MAT_Solves, mat, 0, 0, 0));
9310   PetscFunctionReturn(PETSC_SUCCESS);
9311 }
9312 
9313 /*@
9314   MatIsSymmetric - Test whether a matrix is symmetric
9315 
9316   Collective
9317 
9318   Input Parameters:
9319 + A   - the matrix to test
9320 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact transpose)
9321 
9322   Output Parameter:
9323 . flg - the result
9324 
9325   Level: intermediate
9326 
9327   Notes:
9328   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9329 
9330   If the matrix does not yet know if it is symmetric or not this can be an expensive operation, also available `MatIsSymmetricKnown()`
9331 
9332   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9333   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9334 
9335 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetricKnown()`,
9336           `MAT_SYMMETRIC`, `MAT_SYMMETRY_ETERNAL`
9337 @*/
9338 PetscErrorCode MatIsSymmetric(Mat A, PetscReal tol, PetscBool *flg)
9339 {
9340   PetscFunctionBegin;
9341   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9342   PetscAssertPointer(flg, 3);
9343   if (A->symmetric != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->symmetric);
9344   else {
9345     if (A->ops->issymmetric) PetscUseTypeMethod(A, issymmetric, tol, flg);
9346     else PetscCall(MatIsTranspose(A, A, tol, flg));
9347     if (!tol) PetscCall(MatSetOption(A, MAT_SYMMETRIC, *flg));
9348   }
9349   PetscFunctionReturn(PETSC_SUCCESS);
9350 }
9351 
9352 /*@
9353   MatIsHermitian - Test whether a matrix is Hermitian
9354 
9355   Collective
9356 
9357   Input Parameters:
9358 + A   - the matrix to test
9359 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact Hermitian)
9360 
9361   Output Parameter:
9362 . flg - the result
9363 
9364   Level: intermediate
9365 
9366   Notes:
9367   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9368 
9369   If the matrix does not yet know if it is Hermitian or not this can be an expensive operation, also available `MatIsHermitianKnown()`
9370 
9371   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9372   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMEMTRY_ETERNAL`,`PETSC_TRUE`)
9373 
9374 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetric()`, `MatSetOption()`,
9375           `MatIsSymmetricKnown()`, `MatIsSymmetric()`, `MAT_HERMITIAN`, `MAT_SYMMETRY_ETERNAL`
9376 @*/
9377 PetscErrorCode MatIsHermitian(Mat A, PetscReal tol, PetscBool *flg)
9378 {
9379   PetscFunctionBegin;
9380   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9381   PetscAssertPointer(flg, 3);
9382   if (A->hermitian != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->hermitian);
9383   else {
9384     if (A->ops->ishermitian) PetscUseTypeMethod(A, ishermitian, tol, flg);
9385     else PetscCall(MatIsHermitianTranspose(A, A, tol, flg));
9386     if (!tol) PetscCall(MatSetOption(A, MAT_HERMITIAN, *flg));
9387   }
9388   PetscFunctionReturn(PETSC_SUCCESS);
9389 }
9390 
9391 /*@
9392   MatIsSymmetricKnown - Checks if a matrix knows if it is symmetric or not and its symmetric state
9393 
9394   Not Collective
9395 
9396   Input Parameter:
9397 . A - the matrix to check
9398 
9399   Output Parameters:
9400 + set - `PETSC_TRUE` if the matrix knows its symmetry state (this tells you if the next flag is valid)
9401 - flg - the result (only valid if set is `PETSC_TRUE`)
9402 
9403   Level: advanced
9404 
9405   Notes:
9406   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsSymmetric()`
9407   if you want it explicitly checked
9408 
9409   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9410   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9411 
9412 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9413 @*/
9414 PetscErrorCode MatIsSymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9415 {
9416   PetscFunctionBegin;
9417   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9418   PetscAssertPointer(set, 2);
9419   PetscAssertPointer(flg, 3);
9420   if (A->symmetric != PETSC_BOOL3_UNKNOWN) {
9421     *set = PETSC_TRUE;
9422     *flg = PetscBool3ToBool(A->symmetric);
9423   } else {
9424     *set = PETSC_FALSE;
9425   }
9426   PetscFunctionReturn(PETSC_SUCCESS);
9427 }
9428 
9429 /*@
9430   MatIsSPDKnown - Checks if a matrix knows if it is symmetric positive definite or not and its symmetric positive definite state
9431 
9432   Not Collective
9433 
9434   Input Parameter:
9435 . A - the matrix to check
9436 
9437   Output Parameters:
9438 + set - `PETSC_TRUE` if the matrix knows its symmetric positive definite state (this tells you if the next flag is valid)
9439 - flg - the result (only valid if set is `PETSC_TRUE`)
9440 
9441   Level: advanced
9442 
9443   Notes:
9444   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`).
9445 
9446   One can declare that a matrix is SPD with `MatSetOption`(mat,`MAT_SPD`,`PETSC_TRUE`) and if it is known to remain SPD
9447   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SPD_ETERNAL`,`PETSC_TRUE`)
9448 
9449 .seealso: [](ch_matrices), `Mat`, `MAT_SPD_ETERNAL`, `MAT_SPD`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9450 @*/
9451 PetscErrorCode MatIsSPDKnown(Mat A, PetscBool *set, PetscBool *flg)
9452 {
9453   PetscFunctionBegin;
9454   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9455   PetscAssertPointer(set, 2);
9456   PetscAssertPointer(flg, 3);
9457   if (A->spd != PETSC_BOOL3_UNKNOWN) {
9458     *set = PETSC_TRUE;
9459     *flg = PetscBool3ToBool(A->spd);
9460   } else {
9461     *set = PETSC_FALSE;
9462   }
9463   PetscFunctionReturn(PETSC_SUCCESS);
9464 }
9465 
9466 /*@
9467   MatIsHermitianKnown - Checks if a matrix knows if it is Hermitian or not and its Hermitian state
9468 
9469   Not Collective
9470 
9471   Input Parameter:
9472 . A - the matrix to check
9473 
9474   Output Parameters:
9475 + set - `PETSC_TRUE` if the matrix knows its Hermitian state (this tells you if the next flag is valid)
9476 - flg - the result (only valid if set is `PETSC_TRUE`)
9477 
9478   Level: advanced
9479 
9480   Notes:
9481   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsHermitian()`
9482   if you want it explicitly checked
9483 
9484   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9485   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9486 
9487 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MAT_HERMITIAN`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`
9488 @*/
9489 PetscErrorCode MatIsHermitianKnown(Mat A, PetscBool *set, PetscBool *flg)
9490 {
9491   PetscFunctionBegin;
9492   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9493   PetscAssertPointer(set, 2);
9494   PetscAssertPointer(flg, 3);
9495   if (A->hermitian != PETSC_BOOL3_UNKNOWN) {
9496     *set = PETSC_TRUE;
9497     *flg = PetscBool3ToBool(A->hermitian);
9498   } else {
9499     *set = PETSC_FALSE;
9500   }
9501   PetscFunctionReturn(PETSC_SUCCESS);
9502 }
9503 
9504 /*@
9505   MatIsStructurallySymmetric - Test whether a matrix is structurally symmetric
9506 
9507   Collective
9508 
9509   Input Parameter:
9510 . A - the matrix to test
9511 
9512   Output Parameter:
9513 . flg - the result
9514 
9515   Level: intermediate
9516 
9517   Notes:
9518   If the matrix does yet know it is structurally symmetric this can be an expensive operation, also available `MatIsStructurallySymmetricKnown()`
9519 
9520   One can declare that a matrix is structurally symmetric with `MatSetOption`(mat,`MAT_STRUCTURALLY_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain structurally
9521   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9522 
9523 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsSymmetric()`, `MatSetOption()`, `MatIsStructurallySymmetricKnown()`
9524 @*/
9525 PetscErrorCode MatIsStructurallySymmetric(Mat A, PetscBool *flg)
9526 {
9527   PetscFunctionBegin;
9528   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9529   PetscAssertPointer(flg, 2);
9530   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9531     *flg = PetscBool3ToBool(A->structurally_symmetric);
9532   } else {
9533     PetscUseTypeMethod(A, isstructurallysymmetric, flg);
9534     PetscCall(MatSetOption(A, MAT_STRUCTURALLY_SYMMETRIC, *flg));
9535   }
9536   PetscFunctionReturn(PETSC_SUCCESS);
9537 }
9538 
9539 /*@
9540   MatIsStructurallySymmetricKnown - Checks if a matrix knows if it is structurally symmetric or not and its structurally symmetric state
9541 
9542   Not Collective
9543 
9544   Input Parameter:
9545 . A - the matrix to check
9546 
9547   Output Parameters:
9548 + set - PETSC_TRUE if the matrix knows its structurally symmetric state (this tells you if the next flag is valid)
9549 - flg - the result (only valid if set is PETSC_TRUE)
9550 
9551   Level: advanced
9552 
9553   Notes:
9554   One can declare that a matrix is structurally symmetric with `MatSetOption`(mat,`MAT_STRUCTURALLY_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain structurally
9555   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9556 
9557   Use `MatIsStructurallySymmetric()` to explicitly check if a matrix is structurally symmetric (this is an expensive operation)
9558 
9559 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9560 @*/
9561 PetscErrorCode MatIsStructurallySymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9562 {
9563   PetscFunctionBegin;
9564   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9565   PetscAssertPointer(set, 2);
9566   PetscAssertPointer(flg, 3);
9567   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9568     *set = PETSC_TRUE;
9569     *flg = PetscBool3ToBool(A->structurally_symmetric);
9570   } else {
9571     *set = PETSC_FALSE;
9572   }
9573   PetscFunctionReturn(PETSC_SUCCESS);
9574 }
9575 
9576 /*@
9577   MatStashGetInfo - Gets how many values are currently in the matrix stash, i.e. need
9578   to be communicated to other processors during the `MatAssemblyBegin()`/`MatAssemblyEnd()` process
9579 
9580   Not Collective
9581 
9582   Input Parameter:
9583 . mat - the matrix
9584 
9585   Output Parameters:
9586 + nstash    - the size of the stash
9587 . reallocs  - the number of additional mallocs incurred.
9588 . bnstash   - the size of the block stash
9589 - breallocs - the number of additional mallocs incurred.in the block stash
9590 
9591   Level: advanced
9592 
9593 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashSetInitialSize()`
9594 @*/
9595 PetscErrorCode MatStashGetInfo(Mat mat, PetscInt *nstash, PetscInt *reallocs, PetscInt *bnstash, PetscInt *breallocs)
9596 {
9597   PetscFunctionBegin;
9598   PetscCall(MatStashGetInfo_Private(&mat->stash, nstash, reallocs));
9599   PetscCall(MatStashGetInfo_Private(&mat->bstash, bnstash, breallocs));
9600   PetscFunctionReturn(PETSC_SUCCESS);
9601 }
9602 
9603 /*@
9604   MatCreateVecs - Get vector(s) compatible with the matrix, i.e. with the same
9605   parallel layout, `PetscLayout` for rows and columns
9606 
9607   Collective
9608 
9609   Input Parameter:
9610 . mat - the matrix
9611 
9612   Output Parameters:
9613 + right - (optional) vector that the matrix can be multiplied against
9614 - left  - (optional) vector that the matrix vector product can be stored in
9615 
9616   Level: advanced
9617 
9618   Notes:
9619   The blocksize of the returned vectors is determined by the row and column block sizes set with `MatSetBlockSizes()` or the single blocksize (same for both) set by `MatSetBlockSize()`.
9620 
9621   These are new vectors which are not owned by the mat, they should be destroyed in `VecDestroy()` when no longer needed
9622 
9623 .seealso: [](ch_matrices), `Mat`, `Vec`, `VecCreate()`, `VecDestroy()`, `DMCreateGlobalVector()`
9624 @*/
9625 PetscErrorCode MatCreateVecs(Mat mat, Vec *right, Vec *left)
9626 {
9627   PetscFunctionBegin;
9628   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9629   PetscValidType(mat, 1);
9630   if (mat->ops->getvecs) {
9631     PetscUseTypeMethod(mat, getvecs, right, left);
9632   } else {
9633     if (right) {
9634       PetscCheck(mat->cmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for columns not yet setup");
9635       PetscCall(VecCreateWithLayout_Private(mat->cmap, right));
9636       PetscCall(VecSetType(*right, mat->defaultvectype));
9637 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9638       if (mat->boundtocpu && mat->bindingpropagates) {
9639         PetscCall(VecSetBindingPropagates(*right, PETSC_TRUE));
9640         PetscCall(VecBindToCPU(*right, PETSC_TRUE));
9641       }
9642 #endif
9643     }
9644     if (left) {
9645       PetscCheck(mat->rmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for rows not yet setup");
9646       PetscCall(VecCreateWithLayout_Private(mat->rmap, left));
9647       PetscCall(VecSetType(*left, mat->defaultvectype));
9648 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9649       if (mat->boundtocpu && mat->bindingpropagates) {
9650         PetscCall(VecSetBindingPropagates(*left, PETSC_TRUE));
9651         PetscCall(VecBindToCPU(*left, PETSC_TRUE));
9652       }
9653 #endif
9654     }
9655   }
9656   PetscFunctionReturn(PETSC_SUCCESS);
9657 }
9658 
9659 /*@
9660   MatFactorInfoInitialize - Initializes a `MatFactorInfo` data structure
9661   with default values.
9662 
9663   Not Collective
9664 
9665   Input Parameter:
9666 . info - the `MatFactorInfo` data structure
9667 
9668   Level: developer
9669 
9670   Notes:
9671   The solvers are generally used through the `KSP` and `PC` objects, for example
9672   `PCLU`, `PCILU`, `PCCHOLESKY`, `PCICC`
9673 
9674   Once the data structure is initialized one may change certain entries as desired for the particular factorization to be performed
9675 
9676 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorInfo`
9677 @*/
9678 PetscErrorCode MatFactorInfoInitialize(MatFactorInfo *info)
9679 {
9680   PetscFunctionBegin;
9681   PetscCall(PetscMemzero(info, sizeof(MatFactorInfo)));
9682   PetscFunctionReturn(PETSC_SUCCESS);
9683 }
9684 
9685 /*@
9686   MatFactorSetSchurIS - Set indices corresponding to the Schur complement you wish to have computed
9687 
9688   Collective
9689 
9690   Input Parameters:
9691 + mat - the factored matrix
9692 - is  - the index set defining the Schur indices (0-based)
9693 
9694   Level: advanced
9695 
9696   Notes:
9697   Call `MatFactorSolveSchurComplement()` or `MatFactorSolveSchurComplementTranspose()` after this call to solve a Schur complement system.
9698 
9699   You can call `MatFactorGetSchurComplement()` or `MatFactorCreateSchurComplement()` after this call.
9700 
9701   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9702 
9703 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorGetSchurComplement()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSolveSchurComplement()`,
9704           `MatFactorSolveSchurComplementTranspose()`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9705 @*/
9706 PetscErrorCode MatFactorSetSchurIS(Mat mat, IS is)
9707 {
9708   PetscErrorCode (*f)(Mat, IS);
9709 
9710   PetscFunctionBegin;
9711   PetscValidType(mat, 1);
9712   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9713   PetscValidType(is, 2);
9714   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
9715   PetscCheckSameComm(mat, 1, is, 2);
9716   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
9717   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorSetSchurIS_C", &f));
9718   PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "The selected MatSolverType does not support Schur complement computation. You should use MATSOLVERMUMPS or MATSOLVERMKL_PARDISO");
9719   PetscCall(MatDestroy(&mat->schur));
9720   PetscCall((*f)(mat, is));
9721   PetscCheck(mat->schur, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Schur complement has not been created");
9722   PetscFunctionReturn(PETSC_SUCCESS);
9723 }
9724 
9725 /*@
9726   MatFactorCreateSchurComplement - Create a Schur complement matrix object using Schur data computed during the factorization step
9727 
9728   Logically Collective
9729 
9730   Input Parameters:
9731 + F      - the factored matrix obtained by calling `MatGetFactor()`
9732 . S      - location where to return the Schur complement, can be `NULL`
9733 - status - the status of the Schur complement matrix, can be `NULL`
9734 
9735   Level: advanced
9736 
9737   Notes:
9738   You must call `MatFactorSetSchurIS()` before calling this routine.
9739 
9740   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9741 
9742   The routine provides a copy of the Schur matrix stored within the solver data structures.
9743   The caller must destroy the object when it is no longer needed.
9744   If `MatFactorInvertSchurComplement()` has been called, the routine gets back the inverse.
9745 
9746   Use `MatFactorGetSchurComplement()` to get access to the Schur complement matrix inside the factored matrix instead of making a copy of it (which this function does)
9747 
9748   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9749 
9750   Developer Note:
9751   The reason this routine exists is because the representation of the Schur complement within the factor matrix may be different than a standard PETSc
9752   matrix representation and we normally do not want to use the time or memory to make a copy as a regular PETSc matrix.
9753 
9754 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorSchurStatus`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9755 @*/
9756 PetscErrorCode MatFactorCreateSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9757 {
9758   PetscFunctionBegin;
9759   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9760   if (S) PetscAssertPointer(S, 2);
9761   if (status) PetscAssertPointer(status, 3);
9762   if (S) {
9763     PetscErrorCode (*f)(Mat, Mat *);
9764 
9765     PetscCall(PetscObjectQueryFunction((PetscObject)F, "MatFactorCreateSchurComplement_C", &f));
9766     if (f) {
9767       PetscCall((*f)(F, S));
9768     } else {
9769       PetscCall(MatDuplicate(F->schur, MAT_COPY_VALUES, S));
9770     }
9771   }
9772   if (status) *status = F->schur_status;
9773   PetscFunctionReturn(PETSC_SUCCESS);
9774 }
9775 
9776 /*@
9777   MatFactorGetSchurComplement - Gets access to a Schur complement matrix using the current Schur data within a factored matrix
9778 
9779   Logically Collective
9780 
9781   Input Parameters:
9782 + F      - the factored matrix obtained by calling `MatGetFactor()`
9783 . S      - location where to return the Schur complement, can be `NULL`
9784 - status - the status of the Schur complement matrix, can be `NULL`
9785 
9786   Level: advanced
9787 
9788   Notes:
9789   You must call `MatFactorSetSchurIS()` before calling this routine.
9790 
9791   Schur complement mode is currently implemented for sequential matrices with factor type of `MATSOLVERMUMPS`
9792 
9793   The routine returns a the Schur Complement stored within the data structures of the solver.
9794 
9795   If `MatFactorInvertSchurComplement()` has previously been called, the returned matrix is actually the inverse of the Schur complement.
9796 
9797   The returned matrix should not be destroyed; the caller should call `MatFactorRestoreSchurComplement()` when the object is no longer needed.
9798 
9799   Use `MatFactorCreateSchurComplement()` to create a copy of the Schur complement matrix that is within a factored matrix
9800 
9801   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9802 
9803 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9804 @*/
9805 PetscErrorCode MatFactorGetSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9806 {
9807   PetscFunctionBegin;
9808   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9809   if (S) {
9810     PetscAssertPointer(S, 2);
9811     *S = F->schur;
9812   }
9813   if (status) {
9814     PetscAssertPointer(status, 3);
9815     *status = F->schur_status;
9816   }
9817   PetscFunctionReturn(PETSC_SUCCESS);
9818 }
9819 
9820 static PetscErrorCode MatFactorUpdateSchurStatus_Private(Mat F)
9821 {
9822   Mat S = F->schur;
9823 
9824   PetscFunctionBegin;
9825   switch (F->schur_status) {
9826   case MAT_FACTOR_SCHUR_UNFACTORED: // fall-through
9827   case MAT_FACTOR_SCHUR_INVERTED:
9828     if (S) {
9829       S->ops->solve             = NULL;
9830       S->ops->matsolve          = NULL;
9831       S->ops->solvetranspose    = NULL;
9832       S->ops->matsolvetranspose = NULL;
9833       S->ops->solveadd          = NULL;
9834       S->ops->solvetransposeadd = NULL;
9835       S->factortype             = MAT_FACTOR_NONE;
9836       PetscCall(PetscFree(S->solvertype));
9837     }
9838   case MAT_FACTOR_SCHUR_FACTORED: // fall-through
9839     break;
9840   default:
9841     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9842   }
9843   PetscFunctionReturn(PETSC_SUCCESS);
9844 }
9845 
9846 /*@
9847   MatFactorRestoreSchurComplement - Restore the Schur complement matrix object obtained from a call to `MatFactorGetSchurComplement()`
9848 
9849   Logically Collective
9850 
9851   Input Parameters:
9852 + F      - the factored matrix obtained by calling `MatGetFactor()`
9853 . S      - location where the Schur complement is stored
9854 - status - the status of the Schur complement matrix (see `MatFactorSchurStatus`)
9855 
9856   Level: advanced
9857 
9858 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9859 @*/
9860 PetscErrorCode MatFactorRestoreSchurComplement(Mat F, Mat *S, MatFactorSchurStatus status)
9861 {
9862   PetscFunctionBegin;
9863   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9864   if (S) {
9865     PetscValidHeaderSpecific(*S, MAT_CLASSID, 2);
9866     *S = NULL;
9867   }
9868   F->schur_status = status;
9869   PetscCall(MatFactorUpdateSchurStatus_Private(F));
9870   PetscFunctionReturn(PETSC_SUCCESS);
9871 }
9872 
9873 /*@
9874   MatFactorSolveSchurComplementTranspose - Solve the transpose of the Schur complement system computed during the factorization step
9875 
9876   Logically Collective
9877 
9878   Input Parameters:
9879 + F   - the factored matrix obtained by calling `MatGetFactor()`
9880 . rhs - location where the right-hand side of the Schur complement system is stored
9881 - sol - location where the solution of the Schur complement system has to be returned
9882 
9883   Level: advanced
9884 
9885   Notes:
9886   The sizes of the vectors should match the size of the Schur complement
9887 
9888   Must be called after `MatFactorSetSchurIS()`
9889 
9890 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplement()`
9891 @*/
9892 PetscErrorCode MatFactorSolveSchurComplementTranspose(Mat F, Vec rhs, Vec sol)
9893 {
9894   PetscFunctionBegin;
9895   PetscValidType(F, 1);
9896   PetscValidType(rhs, 2);
9897   PetscValidType(sol, 3);
9898   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9899   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9900   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9901   PetscCheckSameComm(F, 1, rhs, 2);
9902   PetscCheckSameComm(F, 1, sol, 3);
9903   PetscCall(MatFactorFactorizeSchurComplement(F));
9904   switch (F->schur_status) {
9905   case MAT_FACTOR_SCHUR_FACTORED:
9906     PetscCall(MatSolveTranspose(F->schur, rhs, sol));
9907     break;
9908   case MAT_FACTOR_SCHUR_INVERTED:
9909     PetscCall(MatMultTranspose(F->schur, rhs, sol));
9910     break;
9911   default:
9912     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9913   }
9914   PetscFunctionReturn(PETSC_SUCCESS);
9915 }
9916 
9917 /*@
9918   MatFactorSolveSchurComplement - Solve the Schur complement system computed during the factorization step
9919 
9920   Logically Collective
9921 
9922   Input Parameters:
9923 + F   - the factored matrix obtained by calling `MatGetFactor()`
9924 . rhs - location where the right-hand side of the Schur complement system is stored
9925 - sol - location where the solution of the Schur complement system has to be returned
9926 
9927   Level: advanced
9928 
9929   Notes:
9930   The sizes of the vectors should match the size of the Schur complement
9931 
9932   Must be called after `MatFactorSetSchurIS()`
9933 
9934 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplementTranspose()`
9935 @*/
9936 PetscErrorCode MatFactorSolveSchurComplement(Mat F, Vec rhs, Vec sol)
9937 {
9938   PetscFunctionBegin;
9939   PetscValidType(F, 1);
9940   PetscValidType(rhs, 2);
9941   PetscValidType(sol, 3);
9942   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9943   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9944   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9945   PetscCheckSameComm(F, 1, rhs, 2);
9946   PetscCheckSameComm(F, 1, sol, 3);
9947   PetscCall(MatFactorFactorizeSchurComplement(F));
9948   switch (F->schur_status) {
9949   case MAT_FACTOR_SCHUR_FACTORED:
9950     PetscCall(MatSolve(F->schur, rhs, sol));
9951     break;
9952   case MAT_FACTOR_SCHUR_INVERTED:
9953     PetscCall(MatMult(F->schur, rhs, sol));
9954     break;
9955   default:
9956     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9957   }
9958   PetscFunctionReturn(PETSC_SUCCESS);
9959 }
9960 
9961 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode MatSeqDenseInvertFactors_Private(Mat);
9962 #if PetscDefined(HAVE_CUDA)
9963 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode MatSeqDenseCUDAInvertFactors_Internal(Mat);
9964 #endif
9965 
9966 /* Schur status updated in the interface */
9967 static PetscErrorCode MatFactorInvertSchurComplement_Private(Mat F)
9968 {
9969   Mat S = F->schur;
9970 
9971   PetscFunctionBegin;
9972   if (S) {
9973     PetscMPIInt size;
9974     PetscBool   isdense, isdensecuda;
9975 
9976     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)S), &size));
9977     PetscCheck(size <= 1, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not yet implemented");
9978     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSE, &isdense));
9979     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSECUDA, &isdensecuda));
9980     PetscCheck(isdense || isdensecuda, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not implemented for type %s", ((PetscObject)S)->type_name);
9981     PetscCall(PetscLogEventBegin(MAT_FactorInvS, F, 0, 0, 0));
9982     if (isdense) {
9983       PetscCall(MatSeqDenseInvertFactors_Private(S));
9984     } else if (isdensecuda) {
9985 #if defined(PETSC_HAVE_CUDA)
9986       PetscCall(MatSeqDenseCUDAInvertFactors_Internal(S));
9987 #endif
9988     }
9989     // HIP??????????????
9990     PetscCall(PetscLogEventEnd(MAT_FactorInvS, F, 0, 0, 0));
9991   }
9992   PetscFunctionReturn(PETSC_SUCCESS);
9993 }
9994 
9995 /*@
9996   MatFactorInvertSchurComplement - Invert the Schur complement matrix computed during the factorization step
9997 
9998   Logically Collective
9999 
10000   Input Parameter:
10001 . F - the factored matrix obtained by calling `MatGetFactor()`
10002 
10003   Level: advanced
10004 
10005   Notes:
10006   Must be called after `MatFactorSetSchurIS()`.
10007 
10008   Call `MatFactorGetSchurComplement()` or  `MatFactorCreateSchurComplement()` AFTER this call to actually compute the inverse and get access to it.
10009 
10010 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorCreateSchurComplement()`
10011 @*/
10012 PetscErrorCode MatFactorInvertSchurComplement(Mat F)
10013 {
10014   PetscFunctionBegin;
10015   PetscValidType(F, 1);
10016   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
10017   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED) PetscFunctionReturn(PETSC_SUCCESS);
10018   PetscCall(MatFactorFactorizeSchurComplement(F));
10019   PetscCall(MatFactorInvertSchurComplement_Private(F));
10020   F->schur_status = MAT_FACTOR_SCHUR_INVERTED;
10021   PetscFunctionReturn(PETSC_SUCCESS);
10022 }
10023 
10024 /*@
10025   MatFactorFactorizeSchurComplement - Factorize the Schur complement matrix computed during the factorization step
10026 
10027   Logically Collective
10028 
10029   Input Parameter:
10030 . F - the factored matrix obtained by calling `MatGetFactor()`
10031 
10032   Level: advanced
10033 
10034   Note:
10035   Must be called after `MatFactorSetSchurIS()`
10036 
10037 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorInvertSchurComplement()`
10038 @*/
10039 PetscErrorCode MatFactorFactorizeSchurComplement(Mat F)
10040 {
10041   MatFactorInfo info;
10042 
10043   PetscFunctionBegin;
10044   PetscValidType(F, 1);
10045   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
10046   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED || F->schur_status == MAT_FACTOR_SCHUR_FACTORED) PetscFunctionReturn(PETSC_SUCCESS);
10047   PetscCall(PetscLogEventBegin(MAT_FactorFactS, F, 0, 0, 0));
10048   PetscCall(PetscMemzero(&info, sizeof(MatFactorInfo)));
10049   if (F->factortype == MAT_FACTOR_CHOLESKY) { /* LDL^t regarded as Cholesky */
10050     PetscCall(MatCholeskyFactor(F->schur, NULL, &info));
10051   } else {
10052     PetscCall(MatLUFactor(F->schur, NULL, NULL, &info));
10053   }
10054   PetscCall(PetscLogEventEnd(MAT_FactorFactS, F, 0, 0, 0));
10055   F->schur_status = MAT_FACTOR_SCHUR_FACTORED;
10056   PetscFunctionReturn(PETSC_SUCCESS);
10057 }
10058 
10059 /*@
10060   MatPtAP - Creates the matrix product $C = P^T * A * P$
10061 
10062   Neighbor-wise Collective
10063 
10064   Input Parameters:
10065 + A     - the matrix
10066 . P     - the projection matrix
10067 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10068 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(P)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10069           if the result is a dense matrix this is irrelevant
10070 
10071   Output Parameter:
10072 . C - the product matrix
10073 
10074   Level: intermediate
10075 
10076   Notes:
10077   C will be created and must be destroyed by the user with `MatDestroy()`.
10078 
10079   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10080 
10081   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10082 
10083   Developer Note:
10084   For matrix types without special implementation the function fallbacks to `MatMatMult()` followed by `MatTransposeMatMult()`.
10085 
10086 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatRARt()`
10087 @*/
10088 PetscErrorCode MatPtAP(Mat A, Mat P, MatReuse scall, PetscReal fill, Mat *C)
10089 {
10090   PetscFunctionBegin;
10091   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10092   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10093 
10094   if (scall == MAT_INITIAL_MATRIX) {
10095     PetscCall(MatProductCreate(A, P, NULL, C));
10096     PetscCall(MatProductSetType(*C, MATPRODUCT_PtAP));
10097     PetscCall(MatProductSetAlgorithm(*C, "default"));
10098     PetscCall(MatProductSetFill(*C, fill));
10099 
10100     (*C)->product->api_user = PETSC_TRUE;
10101     PetscCall(MatProductSetFromOptions(*C));
10102     PetscCheck((*C)->ops->productsymbolic, PetscObjectComm((PetscObject)*C), PETSC_ERR_SUP, "MatProduct %s not supported for A %s and P %s", MatProductTypes[MATPRODUCT_PtAP], ((PetscObject)A)->type_name, ((PetscObject)P)->type_name);
10103     PetscCall(MatProductSymbolic(*C));
10104   } else { /* scall == MAT_REUSE_MATRIX */
10105     PetscCall(MatProductReplaceMats(A, P, NULL, *C));
10106   }
10107 
10108   PetscCall(MatProductNumeric(*C));
10109   (*C)->symmetric = A->symmetric;
10110   (*C)->spd       = A->spd;
10111   PetscFunctionReturn(PETSC_SUCCESS);
10112 }
10113 
10114 /*@
10115   MatRARt - Creates the matrix product $C = R * A * R^T$
10116 
10117   Neighbor-wise Collective
10118 
10119   Input Parameters:
10120 + A     - the matrix
10121 . R     - the projection matrix
10122 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10123 - fill  - expected fill as ratio of nnz(C)/nnz(A), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10124           if the result is a dense matrix this is irrelevant
10125 
10126   Output Parameter:
10127 . C - the product matrix
10128 
10129   Level: intermediate
10130 
10131   Notes:
10132   `C` will be created and must be destroyed by the user with `MatDestroy()`.
10133 
10134   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10135 
10136   This routine is currently only implemented for pairs of `MATAIJ` matrices and classes
10137   which inherit from `MATAIJ`. Due to PETSc sparse matrix block row distribution among processes,
10138   the parallel `MatRARt()` is implemented computing the explicit transpose of `R`, which can be very expensive.
10139   We recommend using `MatPtAP()` when possible.
10140 
10141   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10142 
10143 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatPtAP()`
10144 @*/
10145 PetscErrorCode MatRARt(Mat A, Mat R, MatReuse scall, PetscReal fill, Mat *C)
10146 {
10147   PetscFunctionBegin;
10148   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10149   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10150 
10151   if (scall == MAT_INITIAL_MATRIX) {
10152     PetscCall(MatProductCreate(A, R, NULL, C));
10153     PetscCall(MatProductSetType(*C, MATPRODUCT_RARt));
10154     PetscCall(MatProductSetAlgorithm(*C, "default"));
10155     PetscCall(MatProductSetFill(*C, fill));
10156 
10157     (*C)->product->api_user = PETSC_TRUE;
10158     PetscCall(MatProductSetFromOptions(*C));
10159     PetscCheck((*C)->ops->productsymbolic, PetscObjectComm((PetscObject)*C), PETSC_ERR_SUP, "MatProduct %s not supported for A %s and R %s", MatProductTypes[MATPRODUCT_RARt], ((PetscObject)A)->type_name, ((PetscObject)R)->type_name);
10160     PetscCall(MatProductSymbolic(*C));
10161   } else { /* scall == MAT_REUSE_MATRIX */
10162     PetscCall(MatProductReplaceMats(A, R, NULL, *C));
10163   }
10164 
10165   PetscCall(MatProductNumeric(*C));
10166   if (A->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10167   PetscFunctionReturn(PETSC_SUCCESS);
10168 }
10169 
10170 static PetscErrorCode MatProduct_Private(Mat A, Mat B, MatReuse scall, PetscReal fill, MatProductType ptype, Mat *C)
10171 {
10172   PetscBool flg = PETSC_TRUE;
10173 
10174   PetscFunctionBegin;
10175   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX product not supported");
10176   if (scall == MAT_INITIAL_MATRIX) {
10177     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_INITIAL_MATRIX and product type %s\n", MatProductTypes[ptype]));
10178     PetscCall(MatProductCreate(A, B, NULL, C));
10179     PetscCall(MatProductSetAlgorithm(*C, MATPRODUCTALGORITHMDEFAULT));
10180     PetscCall(MatProductSetFill(*C, fill));
10181   } else { /* scall == MAT_REUSE_MATRIX */
10182     Mat_Product *product = (*C)->product;
10183 
10184     PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)*C, &flg, MATSEQDENSE, MATMPIDENSE, ""));
10185     if (flg && product && product->type != ptype) {
10186       PetscCall(MatProductClear(*C));
10187       product = NULL;
10188     }
10189     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_REUSE_MATRIX %s product present and product type %s\n", product ? "with" : "without", MatProductTypes[ptype]));
10190     if (!product) { /* user provide the dense matrix *C without calling MatProductCreate() or reusing it from previous calls */
10191       PetscCheck(flg, PetscObjectComm((PetscObject)*C), PETSC_ERR_SUP, "Call MatProductCreate() first");
10192       PetscCall(MatProductCreate_Private(A, B, NULL, *C));
10193       product        = (*C)->product;
10194       product->fill  = fill;
10195       product->clear = PETSC_TRUE;
10196     } else { /* user may change input matrices A or B when MAT_REUSE_MATRIX */
10197       flg = PETSC_FALSE;
10198       PetscCall(MatProductReplaceMats(A, B, NULL, *C));
10199     }
10200   }
10201   if (flg) {
10202     (*C)->product->api_user = PETSC_TRUE;
10203     PetscCall(MatProductSetType(*C, ptype));
10204     PetscCall(MatProductSetFromOptions(*C));
10205     PetscCall(MatProductSymbolic(*C));
10206   }
10207   PetscCall(MatProductNumeric(*C));
10208   PetscFunctionReturn(PETSC_SUCCESS);
10209 }
10210 
10211 /*@
10212   MatMatMult - Performs matrix-matrix multiplication C=A*B.
10213 
10214   Neighbor-wise Collective
10215 
10216   Input Parameters:
10217 + A     - the left matrix
10218 . B     - the right matrix
10219 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10220 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10221           if the result is a dense matrix this is irrelevant
10222 
10223   Output Parameter:
10224 . C - the product matrix
10225 
10226   Notes:
10227   Unless scall is `MAT_REUSE_MATRIX` C will be created.
10228 
10229   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call and C was obtained from a previous
10230   call to this function with `MAT_INITIAL_MATRIX`.
10231 
10232   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value actually needed.
10233 
10234   In the special case where matrix `B` (and hence `C`) are dense you can create the correctly sized matrix `C` yourself and then call this routine with `MAT_REUSE_MATRIX`,
10235   rather than first having `MatMatMult()` create it for you. You can NEVER do this if the matrix `C` is sparse.
10236 
10237   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10238 
10239   Example of Usage:
10240 .vb
10241      MatProductCreate(A,B,NULL,&C);
10242      MatProductSetType(C,MATPRODUCT_AB);
10243      MatProductSymbolic(C);
10244      MatProductNumeric(C); // compute C=A * B
10245      MatProductReplaceMats(A1,B1,NULL,C); // compute C=A1 * B1
10246      MatProductNumeric(C);
10247      MatProductReplaceMats(A2,NULL,NULL,C); // compute C=A2 * B1
10248      MatProductNumeric(C);
10249 .ve
10250 
10251   Level: intermediate
10252 
10253 .seealso: [](ch_matrices), `Mat`, `MatProductType`, `MATPRODUCT_AB`, `MatTransposeMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`, `MatProductCreate()`, `MatProductSymbolic()`, `MatProductReplaceMats()`, `MatProductNumeric()`
10254 @*/
10255 PetscErrorCode MatMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10256 {
10257   PetscFunctionBegin;
10258   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AB, C));
10259   PetscFunctionReturn(PETSC_SUCCESS);
10260 }
10261 
10262 /*@
10263   MatMatTransposeMult - Performs matrix-matrix multiplication $C = A*B^T$.
10264 
10265   Neighbor-wise Collective
10266 
10267   Input Parameters:
10268 + A     - the left matrix
10269 . B     - the right matrix
10270 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10271 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10272 
10273   Output Parameter:
10274 . C - the product matrix
10275 
10276   Options Database Key:
10277 . -matmattransmult_mpidense_mpidense_via {allgatherv,cyclic} - Choose between algorithms for `MATMPIDENSE` matrices: the
10278               first redundantly copies the transposed `B` matrix on each process and requires O(log P) communication complexity;
10279               the second never stores more than one portion of the `B` matrix at a time but requires O(P) communication complexity.
10280 
10281   Level: intermediate
10282 
10283   Notes:
10284   C will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10285 
10286   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call
10287 
10288   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10289   actually needed.
10290 
10291   This routine is currently only implemented for pairs of `MATSEQAIJ` matrices, for the `MATSEQDENSE` class,
10292   and for pairs of `MATMPIDENSE` matrices.
10293 
10294   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABt`
10295 
10296   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10297 
10298 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABt`, `MatMatMult()`, `MatTransposeMatMult()` `MatPtAP()`, `MatProductAlgorithm`, `MatProductType`
10299 @*/
10300 PetscErrorCode MatMatTransposeMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10301 {
10302   PetscFunctionBegin;
10303   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_ABt, C));
10304   if (A == B) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10305   PetscFunctionReturn(PETSC_SUCCESS);
10306 }
10307 
10308 /*@
10309   MatTransposeMatMult - Performs matrix-matrix multiplication $C = A^T*B$.
10310 
10311   Neighbor-wise Collective
10312 
10313   Input Parameters:
10314 + A     - the left matrix
10315 . B     - the right matrix
10316 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10317 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10318 
10319   Output Parameter:
10320 . C - the product matrix
10321 
10322   Level: intermediate
10323 
10324   Notes:
10325   `C` will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10326 
10327   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call.
10328 
10329   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_AtB`
10330 
10331   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10332   actually needed.
10333 
10334   This routine is currently implemented for pairs of `MATAIJ` matrices and pairs of `MATSEQDENSE` matrices and classes
10335   which inherit from `MATSEQAIJ`.  `C` will be of the same type as the input matrices.
10336 
10337   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10338 
10339 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_AtB`, `MatMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`
10340 @*/
10341 PetscErrorCode MatTransposeMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10342 {
10343   PetscFunctionBegin;
10344   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AtB, C));
10345   PetscFunctionReturn(PETSC_SUCCESS);
10346 }
10347 
10348 /*@
10349   MatMatMatMult - Performs matrix-matrix-matrix multiplication D=A*B*C.
10350 
10351   Neighbor-wise Collective
10352 
10353   Input Parameters:
10354 + A     - the left matrix
10355 . B     - the middle matrix
10356 . C     - the right matrix
10357 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10358 - fill  - expected fill as ratio of nnz(D)/(nnz(A) + nnz(B)+nnz(C)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10359           if the result is a dense matrix this is irrelevant
10360 
10361   Output Parameter:
10362 . D - the product matrix
10363 
10364   Level: intermediate
10365 
10366   Notes:
10367   Unless `scall` is `MAT_REUSE_MATRIX` `D` will be created.
10368 
10369   `MAT_REUSE_MATRIX` can only be used if the matrices `A`, `B`, and `C` have the same nonzero pattern as in the previous call
10370 
10371   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABC`
10372 
10373   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value
10374   actually needed.
10375 
10376   If you have many matrices with the same non-zero structure to multiply, you
10377   should use `MAT_REUSE_MATRIX` in all calls but the first
10378 
10379   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10380 
10381 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABC`, `MatMatMult`, `MatPtAP()`, `MatMatTransposeMult()`, `MatTransposeMatMult()`
10382 @*/
10383 PetscErrorCode MatMatMatMult(Mat A, Mat B, Mat C, MatReuse scall, PetscReal fill, Mat *D)
10384 {
10385   PetscFunctionBegin;
10386   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*D, 6);
10387   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10388 
10389   if (scall == MAT_INITIAL_MATRIX) {
10390     PetscCall(MatProductCreate(A, B, C, D));
10391     PetscCall(MatProductSetType(*D, MATPRODUCT_ABC));
10392     PetscCall(MatProductSetAlgorithm(*D, "default"));
10393     PetscCall(MatProductSetFill(*D, fill));
10394 
10395     (*D)->product->api_user = PETSC_TRUE;
10396     PetscCall(MatProductSetFromOptions(*D));
10397     PetscCheck((*D)->ops->productsymbolic, PetscObjectComm((PetscObject)*D), PETSC_ERR_SUP, "MatProduct %s not supported for A %s, B %s and C %s", MatProductTypes[MATPRODUCT_ABC], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name,
10398                ((PetscObject)C)->type_name);
10399     PetscCall(MatProductSymbolic(*D));
10400   } else { /* user may change input matrices when REUSE */
10401     PetscCall(MatProductReplaceMats(A, B, C, *D));
10402   }
10403   PetscCall(MatProductNumeric(*D));
10404   PetscFunctionReturn(PETSC_SUCCESS);
10405 }
10406 
10407 /*@
10408   MatCreateRedundantMatrix - Create redundant matrices and put them into processors of subcommunicators.
10409 
10410   Collective
10411 
10412   Input Parameters:
10413 + mat      - the matrix
10414 . nsubcomm - the number of subcommunicators (= number of redundant parallel or sequential matrices)
10415 . subcomm  - MPI communicator split from the communicator where mat resides in (or `MPI_COMM_NULL` if nsubcomm is used)
10416 - reuse    - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10417 
10418   Output Parameter:
10419 . matredundant - redundant matrix
10420 
10421   Level: advanced
10422 
10423   Notes:
10424   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
10425   original matrix has not changed from that last call to `MatCreateRedundantMatrix()`.
10426 
10427   This routine creates the duplicated matrices in the subcommunicators; you should NOT create them before
10428   calling it.
10429 
10430   `PetscSubcommCreate()` can be used to manage the creation of the subcomm but need not be.
10431 
10432 .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `PetscSubcommCreate()`, `PetscSubcomm`
10433 @*/
10434 PetscErrorCode MatCreateRedundantMatrix(Mat mat, PetscInt nsubcomm, MPI_Comm subcomm, MatReuse reuse, Mat *matredundant)
10435 {
10436   MPI_Comm       comm;
10437   PetscMPIInt    size;
10438   PetscInt       mloc_sub, nloc_sub, rstart, rend, M = mat->rmap->N, N = mat->cmap->N, bs = mat->rmap->bs;
10439   Mat_Redundant *redund     = NULL;
10440   PetscSubcomm   psubcomm   = NULL;
10441   MPI_Comm       subcomm_in = subcomm;
10442   Mat           *matseq;
10443   IS             isrow, iscol;
10444   PetscBool      newsubcomm = PETSC_FALSE;
10445 
10446   PetscFunctionBegin;
10447   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10448   if (nsubcomm && reuse == MAT_REUSE_MATRIX) {
10449     PetscAssertPointer(*matredundant, 5);
10450     PetscValidHeaderSpecific(*matredundant, MAT_CLASSID, 5);
10451   }
10452 
10453   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
10454   if (size == 1 || nsubcomm == 1) {
10455     if (reuse == MAT_INITIAL_MATRIX) {
10456       PetscCall(MatDuplicate(mat, MAT_COPY_VALUES, matredundant));
10457     } else {
10458       PetscCheck(*matredundant != mat, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MAT_REUSE_MATRIX means reuse the matrix passed in as the final argument, not the original matrix");
10459       PetscCall(MatCopy(mat, *matredundant, SAME_NONZERO_PATTERN));
10460     }
10461     PetscFunctionReturn(PETSC_SUCCESS);
10462   }
10463 
10464   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10465   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10466   MatCheckPreallocated(mat, 1);
10467 
10468   PetscCall(PetscLogEventBegin(MAT_RedundantMat, mat, 0, 0, 0));
10469   if (subcomm_in == MPI_COMM_NULL && reuse == MAT_INITIAL_MATRIX) { /* get subcomm if user does not provide subcomm */
10470     /* create psubcomm, then get subcomm */
10471     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10472     PetscCallMPI(MPI_Comm_size(comm, &size));
10473     PetscCheck(nsubcomm >= 1 && nsubcomm <= size, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "nsubcomm must between 1 and %d", size);
10474 
10475     PetscCall(PetscSubcommCreate(comm, &psubcomm));
10476     PetscCall(PetscSubcommSetNumber(psubcomm, nsubcomm));
10477     PetscCall(PetscSubcommSetType(psubcomm, PETSC_SUBCOMM_CONTIGUOUS));
10478     PetscCall(PetscSubcommSetFromOptions(psubcomm));
10479     PetscCall(PetscCommDuplicate(PetscSubcommChild(psubcomm), &subcomm, NULL));
10480     newsubcomm = PETSC_TRUE;
10481     PetscCall(PetscSubcommDestroy(&psubcomm));
10482   }
10483 
10484   /* get isrow, iscol and a local sequential matrix matseq[0] */
10485   if (reuse == MAT_INITIAL_MATRIX) {
10486     mloc_sub = PETSC_DECIDE;
10487     nloc_sub = PETSC_DECIDE;
10488     if (bs < 1) {
10489       PetscCall(PetscSplitOwnership(subcomm, &mloc_sub, &M));
10490       PetscCall(PetscSplitOwnership(subcomm, &nloc_sub, &N));
10491     } else {
10492       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &mloc_sub, &M));
10493       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &nloc_sub, &N));
10494     }
10495     PetscCallMPI(MPI_Scan(&mloc_sub, &rend, 1, MPIU_INT, MPI_SUM, subcomm));
10496     rstart = rend - mloc_sub;
10497     PetscCall(ISCreateStride(PETSC_COMM_SELF, mloc_sub, rstart, 1, &isrow));
10498     PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &iscol));
10499     PetscCall(ISSetIdentity(iscol));
10500   } else { /* reuse == MAT_REUSE_MATRIX */
10501     PetscCheck(*matredundant != mat, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MAT_REUSE_MATRIX means reuse the matrix passed in as the final argument, not the original matrix");
10502     /* retrieve subcomm */
10503     PetscCall(PetscObjectGetComm((PetscObject)*matredundant, &subcomm));
10504     redund = (*matredundant)->redundant;
10505     isrow  = redund->isrow;
10506     iscol  = redund->iscol;
10507     matseq = redund->matseq;
10508   }
10509   PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscol, reuse, &matseq));
10510 
10511   /* get matredundant over subcomm */
10512   if (reuse == MAT_INITIAL_MATRIX) {
10513     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], nloc_sub, reuse, matredundant));
10514 
10515     /* create a supporting struct and attach it to C for reuse */
10516     PetscCall(PetscNew(&redund));
10517     (*matredundant)->redundant = redund;
10518     redund->isrow              = isrow;
10519     redund->iscol              = iscol;
10520     redund->matseq             = matseq;
10521     if (newsubcomm) {
10522       redund->subcomm = subcomm;
10523     } else {
10524       redund->subcomm = MPI_COMM_NULL;
10525     }
10526   } else {
10527     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], PETSC_DECIDE, reuse, matredundant));
10528   }
10529 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
10530   if (matseq[0]->boundtocpu && matseq[0]->bindingpropagates) {
10531     PetscCall(MatBindToCPU(*matredundant, PETSC_TRUE));
10532     PetscCall(MatSetBindingPropagates(*matredundant, PETSC_TRUE));
10533   }
10534 #endif
10535   PetscCall(PetscLogEventEnd(MAT_RedundantMat, mat, 0, 0, 0));
10536   PetscFunctionReturn(PETSC_SUCCESS);
10537 }
10538 
10539 /*@C
10540   MatGetMultiProcBlock - Create multiple 'parallel submatrices' from
10541   a given `Mat`. Each submatrix can span multiple procs.
10542 
10543   Collective
10544 
10545   Input Parameters:
10546 + mat     - the matrix
10547 . subComm - the sub communicator obtained as if by `MPI_Comm_split(PetscObjectComm((PetscObject)mat))`
10548 - scall   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10549 
10550   Output Parameter:
10551 . subMat - parallel sub-matrices each spanning a given `subcomm`
10552 
10553   Level: advanced
10554 
10555   Notes:
10556   The submatrix partition across processors is dictated by `subComm` a
10557   communicator obtained by `MPI_comm_split()` or via `PetscSubcommCreate()`. The `subComm`
10558   is not restricted to be grouped with consecutive original MPI processes.
10559 
10560   Due the `MPI_Comm_split()` usage, the parallel layout of the submatrices
10561   map directly to the layout of the original matrix [wrt the local
10562   row,col partitioning]. So the original 'DiagonalMat' naturally maps
10563   into the 'DiagonalMat' of the `subMat`, hence it is used directly from
10564   the `subMat`. However the offDiagMat looses some columns - and this is
10565   reconstructed with `MatSetValues()`
10566 
10567   This is used by `PCBJACOBI` when a single block spans multiple MPI processes.
10568 
10569 .seealso: [](ch_matrices), `Mat`, `MatCreateRedundantMatrix()`, `MatCreateSubMatrices()`, `PCBJACOBI`
10570 @*/
10571 PetscErrorCode MatGetMultiProcBlock(Mat mat, MPI_Comm subComm, MatReuse scall, Mat *subMat)
10572 {
10573   PetscMPIInt commsize, subCommSize;
10574 
10575   PetscFunctionBegin;
10576   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &commsize));
10577   PetscCallMPI(MPI_Comm_size(subComm, &subCommSize));
10578   PetscCheck(subCommSize <= commsize, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "CommSize %d < SubCommZize %d", commsize, subCommSize);
10579 
10580   PetscCheck(scall != MAT_REUSE_MATRIX || *subMat != mat, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MAT_REUSE_MATRIX means reuse the matrix passed in as the final argument, not the original matrix");
10581   PetscCall(PetscLogEventBegin(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10582   PetscUseTypeMethod(mat, getmultiprocblock, subComm, scall, subMat);
10583   PetscCall(PetscLogEventEnd(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10584   PetscFunctionReturn(PETSC_SUCCESS);
10585 }
10586 
10587 /*@
10588   MatGetLocalSubMatrix - Gets a reference to a submatrix specified in local numbering
10589 
10590   Not Collective
10591 
10592   Input Parameters:
10593 + mat   - matrix to extract local submatrix from
10594 . isrow - local row indices for submatrix
10595 - iscol - local column indices for submatrix
10596 
10597   Output Parameter:
10598 . submat - the submatrix
10599 
10600   Level: intermediate
10601 
10602   Notes:
10603   `submat` should be disposed of with `MatRestoreLocalSubMatrix()`.
10604 
10605   Depending on the format of `mat`, the returned `submat` may not implement `MatMult()`.  Its communicator may be
10606   the same as `mat`, it may be `PETSC_COMM_SELF`, or some other sub-communictor of `mat`'s.
10607 
10608   `submat` always implements `MatSetValuesLocal()`.  If `isrow` and `iscol` have the same block size, then
10609   `MatSetValuesBlockedLocal()` will also be implemented.
10610 
10611   `mat` must have had a `ISLocalToGlobalMapping` provided to it with `MatSetLocalToGlobalMapping()`.
10612   Matrices obtained with `DMCreateMatrix()` generally already have the local to global mapping provided.
10613 
10614 .seealso: [](ch_matrices), `Mat`, `MatRestoreLocalSubMatrix()`, `MatCreateLocalRef()`, `MatSetLocalToGlobalMapping()`
10615 @*/
10616 PetscErrorCode MatGetLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10617 {
10618   PetscFunctionBegin;
10619   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10620   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10621   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10622   PetscCheckSameComm(isrow, 2, iscol, 3);
10623   PetscAssertPointer(submat, 4);
10624   PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must have local to global mapping provided before this call");
10625 
10626   if (mat->ops->getlocalsubmatrix) {
10627     PetscUseTypeMethod(mat, getlocalsubmatrix, isrow, iscol, submat);
10628   } else {
10629     PetscCall(MatCreateLocalRef(mat, isrow, iscol, submat));
10630   }
10631   (*submat)->assembled = mat->assembled;
10632   PetscFunctionReturn(PETSC_SUCCESS);
10633 }
10634 
10635 /*@
10636   MatRestoreLocalSubMatrix - Restores a reference to a submatrix specified in local numbering obtained with `MatGetLocalSubMatrix()`
10637 
10638   Not Collective
10639 
10640   Input Parameters:
10641 + mat    - matrix to extract local submatrix from
10642 . isrow  - local row indices for submatrix
10643 . iscol  - local column indices for submatrix
10644 - submat - the submatrix
10645 
10646   Level: intermediate
10647 
10648 .seealso: [](ch_matrices), `Mat`, `MatGetLocalSubMatrix()`
10649 @*/
10650 PetscErrorCode MatRestoreLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10651 {
10652   PetscFunctionBegin;
10653   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10654   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10655   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10656   PetscCheckSameComm(isrow, 2, iscol, 3);
10657   PetscAssertPointer(submat, 4);
10658   if (*submat) PetscValidHeaderSpecific(*submat, MAT_CLASSID, 4);
10659 
10660   if (mat->ops->restorelocalsubmatrix) {
10661     PetscUseTypeMethod(mat, restorelocalsubmatrix, isrow, iscol, submat);
10662   } else {
10663     PetscCall(MatDestroy(submat));
10664   }
10665   *submat = NULL;
10666   PetscFunctionReturn(PETSC_SUCCESS);
10667 }
10668 
10669 /*@
10670   MatFindZeroDiagonals - Finds all the rows of a matrix that have zero or no diagonal entry in the matrix
10671 
10672   Collective
10673 
10674   Input Parameter:
10675 . mat - the matrix
10676 
10677   Output Parameter:
10678 . is - if any rows have zero diagonals this contains the list of them
10679 
10680   Level: developer
10681 
10682 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10683 @*/
10684 PetscErrorCode MatFindZeroDiagonals(Mat mat, IS *is)
10685 {
10686   PetscFunctionBegin;
10687   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10688   PetscValidType(mat, 1);
10689   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10690   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10691 
10692   if (!mat->ops->findzerodiagonals) {
10693     Vec                diag;
10694     const PetscScalar *a;
10695     PetscInt          *rows;
10696     PetscInt           rStart, rEnd, r, nrow = 0;
10697 
10698     PetscCall(MatCreateVecs(mat, &diag, NULL));
10699     PetscCall(MatGetDiagonal(mat, diag));
10700     PetscCall(MatGetOwnershipRange(mat, &rStart, &rEnd));
10701     PetscCall(VecGetArrayRead(diag, &a));
10702     for (r = 0; r < rEnd - rStart; ++r)
10703       if (a[r] == 0.0) ++nrow;
10704     PetscCall(PetscMalloc1(nrow, &rows));
10705     nrow = 0;
10706     for (r = 0; r < rEnd - rStart; ++r)
10707       if (a[r] == 0.0) rows[nrow++] = r + rStart;
10708     PetscCall(VecRestoreArrayRead(diag, &a));
10709     PetscCall(VecDestroy(&diag));
10710     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nrow, rows, PETSC_OWN_POINTER, is));
10711   } else {
10712     PetscUseTypeMethod(mat, findzerodiagonals, is);
10713   }
10714   PetscFunctionReturn(PETSC_SUCCESS);
10715 }
10716 
10717 /*@
10718   MatFindOffBlockDiagonalEntries - Finds all the rows of a matrix that have entries outside of the main diagonal block (defined by the matrix block size)
10719 
10720   Collective
10721 
10722   Input Parameter:
10723 . mat - the matrix
10724 
10725   Output Parameter:
10726 . is - contains the list of rows with off block diagonal entries
10727 
10728   Level: developer
10729 
10730 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10731 @*/
10732 PetscErrorCode MatFindOffBlockDiagonalEntries(Mat mat, IS *is)
10733 {
10734   PetscFunctionBegin;
10735   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10736   PetscValidType(mat, 1);
10737   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10738   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10739 
10740   PetscUseTypeMethod(mat, findoffblockdiagonalentries, is);
10741   PetscFunctionReturn(PETSC_SUCCESS);
10742 }
10743 
10744 /*@C
10745   MatInvertBlockDiagonal - Inverts the block diagonal entries.
10746 
10747   Collective; No Fortran Support
10748 
10749   Input Parameter:
10750 . mat - the matrix
10751 
10752   Output Parameter:
10753 . values - the block inverses in column major order (FORTRAN-like)
10754 
10755   Level: advanced
10756 
10757   Notes:
10758   The size of the blocks is determined by the block size of the matrix.
10759 
10760   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10761 
10762   The blocks all have the same size, use `MatInvertVariableBlockDiagonal()` for variable block size
10763 
10764 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatInvertBlockDiagonalMat()`
10765 @*/
10766 PetscErrorCode MatInvertBlockDiagonal(Mat mat, const PetscScalar *values[])
10767 {
10768   PetscFunctionBegin;
10769   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10770   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10771   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10772   PetscUseTypeMethod(mat, invertblockdiagonal, values);
10773   PetscFunctionReturn(PETSC_SUCCESS);
10774 }
10775 
10776 /*@
10777   MatInvertVariableBlockDiagonal - Inverts the point block diagonal entries.
10778 
10779   Collective; No Fortran Support
10780 
10781   Input Parameters:
10782 + mat     - the matrix
10783 . nblocks - the number of blocks on the process, set with `MatSetVariableBlockSizes()`
10784 - bsizes  - the size of each block on the process, set with `MatSetVariableBlockSizes()`
10785 
10786   Output Parameter:
10787 . values - the block inverses in column major order (FORTRAN-like)
10788 
10789   Level: advanced
10790 
10791   Notes:
10792   Use `MatInvertBlockDiagonal()` if all blocks have the same size
10793 
10794   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10795 
10796 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatSetVariableBlockSizes()`, `MatInvertVariableBlockEnvelope()`
10797 @*/
10798 PetscErrorCode MatInvertVariableBlockDiagonal(Mat mat, PetscInt nblocks, const PetscInt bsizes[], PetscScalar values[])
10799 {
10800   PetscFunctionBegin;
10801   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10802   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10803   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10804   PetscUseTypeMethod(mat, invertvariableblockdiagonal, nblocks, bsizes, values);
10805   PetscFunctionReturn(PETSC_SUCCESS);
10806 }
10807 
10808 /*@
10809   MatInvertBlockDiagonalMat - set the values of matrix C to be the inverted block diagonal of matrix A
10810 
10811   Collective
10812 
10813   Input Parameters:
10814 + A - the matrix
10815 - C - matrix with inverted block diagonal of `A`.  This matrix should be created and may have its type set.
10816 
10817   Level: advanced
10818 
10819   Note:
10820   The blocksize of the matrix is used to determine the blocks on the diagonal of `C`
10821 
10822 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`
10823 @*/
10824 PetscErrorCode MatInvertBlockDiagonalMat(Mat A, Mat C)
10825 {
10826   const PetscScalar *vals;
10827   PetscInt          *dnnz;
10828   PetscInt           m, rstart, rend, bs, i, j;
10829 
10830   PetscFunctionBegin;
10831   PetscCall(MatInvertBlockDiagonal(A, &vals));
10832   PetscCall(MatGetBlockSize(A, &bs));
10833   PetscCall(MatGetLocalSize(A, &m, NULL));
10834   PetscCall(MatSetLayouts(C, A->rmap, A->cmap));
10835   PetscCall(MatSetBlockSizes(C, A->rmap->bs, A->cmap->bs));
10836   PetscCall(PetscMalloc1(m / bs, &dnnz));
10837   for (j = 0; j < m / bs; j++) dnnz[j] = 1;
10838   PetscCall(MatXAIJSetPreallocation(C, bs, dnnz, NULL, NULL, NULL));
10839   PetscCall(PetscFree(dnnz));
10840   PetscCall(MatGetOwnershipRange(C, &rstart, &rend));
10841   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_FALSE));
10842   for (i = rstart / bs; i < rend / bs; i++) PetscCall(MatSetValuesBlocked(C, 1, &i, 1, &i, &vals[(i - rstart / bs) * bs * bs], INSERT_VALUES));
10843   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
10844   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
10845   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_TRUE));
10846   PetscFunctionReturn(PETSC_SUCCESS);
10847 }
10848 
10849 /*@
10850   MatTransposeColoringDestroy - Destroys a coloring context for matrix product $C = A*B^T$ that was created
10851   via `MatTransposeColoringCreate()`.
10852 
10853   Collective
10854 
10855   Input Parameter:
10856 . c - coloring context
10857 
10858   Level: intermediate
10859 
10860 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`
10861 @*/
10862 PetscErrorCode MatTransposeColoringDestroy(MatTransposeColoring *c)
10863 {
10864   MatTransposeColoring matcolor = *c;
10865 
10866   PetscFunctionBegin;
10867   if (!matcolor) PetscFunctionReturn(PETSC_SUCCESS);
10868   if (--((PetscObject)matcolor)->refct > 0) {
10869     matcolor = NULL;
10870     PetscFunctionReturn(PETSC_SUCCESS);
10871   }
10872 
10873   PetscCall(PetscFree3(matcolor->ncolumns, matcolor->nrows, matcolor->colorforrow));
10874   PetscCall(PetscFree(matcolor->rows));
10875   PetscCall(PetscFree(matcolor->den2sp));
10876   PetscCall(PetscFree(matcolor->colorforcol));
10877   PetscCall(PetscFree(matcolor->columns));
10878   if (matcolor->brows > 0) PetscCall(PetscFree(matcolor->lstart));
10879   PetscCall(PetscHeaderDestroy(c));
10880   PetscFunctionReturn(PETSC_SUCCESS);
10881 }
10882 
10883 /*@
10884   MatTransColoringApplySpToDen - Given a symbolic matrix product $C = A*B^T$ for which
10885   a `MatTransposeColoring` context has been created, computes a dense $B^T$ by applying
10886   `MatTransposeColoring` to sparse `B`.
10887 
10888   Collective
10889 
10890   Input Parameters:
10891 + coloring - coloring context created with `MatTransposeColoringCreate()`
10892 - B        - sparse matrix
10893 
10894   Output Parameter:
10895 . Btdense - dense matrix $B^T$
10896 
10897   Level: developer
10898 
10899   Note:
10900   These are used internally for some implementations of `MatRARt()`
10901 
10902 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplyDenToSp()`
10903 @*/
10904 PetscErrorCode MatTransColoringApplySpToDen(MatTransposeColoring coloring, Mat B, Mat Btdense)
10905 {
10906   PetscFunctionBegin;
10907   PetscValidHeaderSpecific(coloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10908   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
10909   PetscValidHeaderSpecific(Btdense, MAT_CLASSID, 3);
10910 
10911   PetscCall((*B->ops->transcoloringapplysptoden)(coloring, B, Btdense));
10912   PetscFunctionReturn(PETSC_SUCCESS);
10913 }
10914 
10915 /*@
10916   MatTransColoringApplyDenToSp - Given a symbolic matrix product $C_{sp} = A*B^T$ for which
10917   a `MatTransposeColoring` context has been created and a dense matrix $C_{den} = A*B^T_{dense}$
10918   in which `B^T_{dens}` is obtained from `MatTransColoringApplySpToDen()`, recover sparse matrix
10919   $C_{sp}$ from $C_{den}$.
10920 
10921   Collective
10922 
10923   Input Parameters:
10924 + matcoloring - coloring context created with `MatTransposeColoringCreate()`
10925 - Cden        - matrix product of a sparse matrix and a dense matrix Btdense
10926 
10927   Output Parameter:
10928 . Csp - sparse matrix
10929 
10930   Level: developer
10931 
10932   Note:
10933   These are used internally for some implementations of `MatRARt()`
10934 
10935 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`
10936 @*/
10937 PetscErrorCode MatTransColoringApplyDenToSp(MatTransposeColoring matcoloring, Mat Cden, Mat Csp)
10938 {
10939   PetscFunctionBegin;
10940   PetscValidHeaderSpecific(matcoloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10941   PetscValidHeaderSpecific(Cden, MAT_CLASSID, 2);
10942   PetscValidHeaderSpecific(Csp, MAT_CLASSID, 3);
10943 
10944   PetscCall((*Csp->ops->transcoloringapplydentosp)(matcoloring, Cden, Csp));
10945   PetscCall(MatAssemblyBegin(Csp, MAT_FINAL_ASSEMBLY));
10946   PetscCall(MatAssemblyEnd(Csp, MAT_FINAL_ASSEMBLY));
10947   PetscFunctionReturn(PETSC_SUCCESS);
10948 }
10949 
10950 /*@
10951   MatTransposeColoringCreate - Creates a matrix coloring context for the matrix product $C = A*B^T$.
10952 
10953   Collective
10954 
10955   Input Parameters:
10956 + mat        - the matrix product C
10957 - iscoloring - the coloring of the matrix; usually obtained with `MatColoringCreate()` or `DMCreateColoring()`
10958 
10959   Output Parameter:
10960 . color - the new coloring context
10961 
10962   Level: intermediate
10963 
10964 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`,
10965           `MatTransColoringApplyDenToSp()`
10966 @*/
10967 PetscErrorCode MatTransposeColoringCreate(Mat mat, ISColoring iscoloring, MatTransposeColoring *color)
10968 {
10969   MatTransposeColoring c;
10970   MPI_Comm             comm;
10971 
10972   PetscFunctionBegin;
10973   PetscAssertPointer(color, 3);
10974 
10975   PetscCall(PetscLogEventBegin(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10976   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10977   PetscCall(PetscHeaderCreate(c, MAT_TRANSPOSECOLORING_CLASSID, "MatTransposeColoring", "Matrix product C=A*B^T via coloring", "Mat", comm, MatTransposeColoringDestroy, NULL));
10978   c->ctype = iscoloring->ctype;
10979   PetscUseTypeMethod(mat, transposecoloringcreate, iscoloring, c);
10980   *color = c;
10981   PetscCall(PetscLogEventEnd(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10982   PetscFunctionReturn(PETSC_SUCCESS);
10983 }
10984 
10985 /*@
10986   MatGetNonzeroState - Returns a 64-bit integer representing the current state of nonzeros in the matrix. If the
10987   matrix has had new nonzero locations added to (or removed from) the matrix since the previous call, the value will be larger.
10988 
10989   Not Collective
10990 
10991   Input Parameter:
10992 . mat - the matrix
10993 
10994   Output Parameter:
10995 . state - the current state
10996 
10997   Level: intermediate
10998 
10999   Notes:
11000   You can only compare states from two different calls to the SAME matrix, you cannot compare calls between
11001   different matrices
11002 
11003   Use `PetscObjectStateGet()` to check for changes to the numerical values in a matrix
11004 
11005   Use the result of `PetscObjectGetId()` to compare if a previously checked matrix is the same as the current matrix, do not compare object pointers.
11006 
11007 .seealso: [](ch_matrices), `Mat`, `PetscObjectStateGet()`, `PetscObjectGetId()`
11008 @*/
11009 PetscErrorCode MatGetNonzeroState(Mat mat, PetscObjectState *state)
11010 {
11011   PetscFunctionBegin;
11012   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11013   *state = mat->nonzerostate;
11014   PetscFunctionReturn(PETSC_SUCCESS);
11015 }
11016 
11017 /*@
11018   MatCreateMPIMatConcatenateSeqMat - Creates a single large PETSc matrix by concatenating sequential
11019   matrices from each processor
11020 
11021   Collective
11022 
11023   Input Parameters:
11024 + comm   - the communicators the parallel matrix will live on
11025 . seqmat - the input sequential matrices
11026 . n      - number of local columns (or `PETSC_DECIDE`)
11027 - reuse  - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
11028 
11029   Output Parameter:
11030 . mpimat - the parallel matrix generated
11031 
11032   Level: developer
11033 
11034   Note:
11035   The number of columns of the matrix in EACH processor MUST be the same.
11036 
11037 .seealso: [](ch_matrices), `Mat`
11038 @*/
11039 PetscErrorCode MatCreateMPIMatConcatenateSeqMat(MPI_Comm comm, Mat seqmat, PetscInt n, MatReuse reuse, Mat *mpimat)
11040 {
11041   PetscMPIInt size;
11042 
11043   PetscFunctionBegin;
11044   PetscCallMPI(MPI_Comm_size(comm, &size));
11045   if (size == 1) {
11046     if (reuse == MAT_INITIAL_MATRIX) {
11047       PetscCall(MatDuplicate(seqmat, MAT_COPY_VALUES, mpimat));
11048     } else {
11049       PetscCall(MatCopy(seqmat, *mpimat, SAME_NONZERO_PATTERN));
11050     }
11051     PetscFunctionReturn(PETSC_SUCCESS);
11052   }
11053 
11054   PetscCheck(reuse != MAT_REUSE_MATRIX || seqmat != *mpimat, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MAT_REUSE_MATRIX means reuse the matrix passed in as the final argument, not the original matrix");
11055 
11056   PetscCall(PetscLogEventBegin(MAT_Merge, seqmat, 0, 0, 0));
11057   PetscCall((*seqmat->ops->creatempimatconcatenateseqmat)(comm, seqmat, n, reuse, mpimat));
11058   PetscCall(PetscLogEventEnd(MAT_Merge, seqmat, 0, 0, 0));
11059   PetscFunctionReturn(PETSC_SUCCESS);
11060 }
11061 
11062 /*@
11063   MatSubdomainsCreateCoalesce - Creates index subdomains by coalescing adjacent MPI processes' ownership ranges.
11064 
11065   Collective
11066 
11067   Input Parameters:
11068 + A - the matrix to create subdomains from
11069 - N - requested number of subdomains
11070 
11071   Output Parameters:
11072 + n   - number of subdomains resulting on this MPI process
11073 - iss - `IS` list with indices of subdomains on this MPI process
11074 
11075   Level: advanced
11076 
11077   Note:
11078   The number of subdomains must be smaller than the communicator size
11079 
11080 .seealso: [](ch_matrices), `Mat`, `IS`
11081 @*/
11082 PetscErrorCode MatSubdomainsCreateCoalesce(Mat A, PetscInt N, PetscInt *n, IS *iss[])
11083 {
11084   MPI_Comm    comm, subcomm;
11085   PetscMPIInt size, rank, color;
11086   PetscInt    rstart, rend, k;
11087 
11088   PetscFunctionBegin;
11089   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
11090   PetscCallMPI(MPI_Comm_size(comm, &size));
11091   PetscCallMPI(MPI_Comm_rank(comm, &rank));
11092   PetscCheck(N >= 1 && N < size, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "number of subdomains must be > 0 and < %d, got N = %" PetscInt_FMT, size, N);
11093   *n    = 1;
11094   k     = size / N + (size % N > 0); /* There are up to k ranks to a color */
11095   color = rank / k;
11096   PetscCallMPI(MPI_Comm_split(comm, color, rank, &subcomm));
11097   PetscCall(PetscMalloc1(1, iss));
11098   PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
11099   PetscCall(ISCreateStride(subcomm, rend - rstart, rstart, 1, iss[0]));
11100   PetscCallMPI(MPI_Comm_free(&subcomm));
11101   PetscFunctionReturn(PETSC_SUCCESS);
11102 }
11103 
11104 /*@
11105   MatGalerkin - Constructs the coarse grid problem matrix via Galerkin projection.
11106 
11107   If the interpolation and restriction operators are the same, uses `MatPtAP()`.
11108   If they are not the same, uses `MatMatMatMult()`.
11109 
11110   Once the coarse grid problem is constructed, correct for interpolation operators
11111   that are not of full rank, which can legitimately happen in the case of non-nested
11112   geometric multigrid.
11113 
11114   Input Parameters:
11115 + restrct     - restriction operator
11116 . dA          - fine grid matrix
11117 . interpolate - interpolation operator
11118 . reuse       - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
11119 - fill        - expected fill, use `PETSC_DETERMINE` or `PETSC_DETERMINE` if you do not have a good estimate
11120 
11121   Output Parameter:
11122 . A - the Galerkin coarse matrix
11123 
11124   Options Database Key:
11125 . -pc_mg_galerkin <both,pmat,mat,none> - for what matrices the Galerkin process should be used
11126 
11127   Level: developer
11128 
11129   Note:
11130   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
11131 
11132 .seealso: [](ch_matrices), `Mat`, `MatPtAP()`, `MatMatMatMult()`
11133 @*/
11134 PetscErrorCode MatGalerkin(Mat restrct, Mat dA, Mat interpolate, MatReuse reuse, PetscReal fill, Mat *A)
11135 {
11136   IS  zerorows;
11137   Vec diag;
11138 
11139   PetscFunctionBegin;
11140   PetscCheck(reuse != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
11141   /* Construct the coarse grid matrix */
11142   if (interpolate == restrct) {
11143     PetscCall(MatPtAP(dA, interpolate, reuse, fill, A));
11144   } else {
11145     PetscCall(MatMatMatMult(restrct, dA, interpolate, reuse, fill, A));
11146   }
11147 
11148   /* If the interpolation matrix is not of full rank, A will have zero rows.
11149      This can legitimately happen in the case of non-nested geometric multigrid.
11150      In that event, we set the rows of the matrix to the rows of the identity,
11151      ignoring the equations (as the RHS will also be zero). */
11152 
11153   PetscCall(MatFindZeroRows(*A, &zerorows));
11154 
11155   if (zerorows != NULL) { /* if there are any zero rows */
11156     PetscCall(MatCreateVecs(*A, &diag, NULL));
11157     PetscCall(MatGetDiagonal(*A, diag));
11158     PetscCall(VecISSet(diag, zerorows, 1.0));
11159     PetscCall(MatDiagonalSet(*A, diag, INSERT_VALUES));
11160     PetscCall(VecDestroy(&diag));
11161     PetscCall(ISDestroy(&zerorows));
11162   }
11163   PetscFunctionReturn(PETSC_SUCCESS);
11164 }
11165 
11166 /*@C
11167   MatSetOperation - Allows user to set a matrix operation for any matrix type
11168 
11169   Logically Collective
11170 
11171   Input Parameters:
11172 + mat - the matrix
11173 . op  - the name of the operation
11174 - f   - the function that provides the operation
11175 
11176   Level: developer
11177 
11178   Example Usage:
11179 .vb
11180   extern PetscErrorCode usermult(Mat, Vec, Vec);
11181 
11182   PetscCall(MatCreateXXX(comm, ..., &A));
11183   PetscCall(MatSetOperation(A, MATOP_MULT, (PetscVoidFn *)usermult));
11184 .ve
11185 
11186   Notes:
11187   See the file `include/petscmat.h` for a complete list of matrix
11188   operations, which all have the form MATOP_<OPERATION>, where
11189   <OPERATION> is the name (in all capital letters) of the
11190   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11191 
11192   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
11193   sequence as the usual matrix interface routines, since they
11194   are intended to be accessed via the usual matrix interface
11195   routines, e.g.,
11196 .vb
11197   MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
11198 .ve
11199 
11200   In particular each function MUST return `PETSC_SUCCESS` on success and
11201   nonzero on failure.
11202 
11203   This routine is distinct from `MatShellSetOperation()` in that it can be called on any matrix type.
11204 
11205 .seealso: [](ch_matrices), `Mat`, `MatGetOperation()`, `MatCreateShell()`, `MatShellSetContext()`, `MatShellSetOperation()`
11206 @*/
11207 PetscErrorCode MatSetOperation(Mat mat, MatOperation op, void (*f)(void))
11208 {
11209   PetscFunctionBegin;
11210   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11211   if (op == MATOP_VIEW && !mat->ops->viewnative && f != (void (*)(void))mat->ops->view) mat->ops->viewnative = mat->ops->view;
11212   (((void (**)(void))mat->ops)[op]) = f;
11213   PetscFunctionReturn(PETSC_SUCCESS);
11214 }
11215 
11216 /*@C
11217   MatGetOperation - Gets a matrix operation for any matrix type.
11218 
11219   Not Collective
11220 
11221   Input Parameters:
11222 + mat - the matrix
11223 - op  - the name of the operation
11224 
11225   Output Parameter:
11226 . f - the function that provides the operation
11227 
11228   Level: developer
11229 
11230   Example Usage:
11231 .vb
11232   PetscErrorCode (*usermult)(Mat, Vec, Vec);
11233 
11234   MatGetOperation(A, MATOP_MULT, (void (**)(void))&usermult);
11235 .ve
11236 
11237   Notes:
11238   See the file include/petscmat.h for a complete list of matrix
11239   operations, which all have the form MATOP_<OPERATION>, where
11240   <OPERATION> is the name (in all capital letters) of the
11241   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11242 
11243   This routine is distinct from `MatShellGetOperation()` in that it can be called on any matrix type.
11244 
11245 .seealso: [](ch_matrices), `Mat`, `MatSetOperation()`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
11246 @*/
11247 PetscErrorCode MatGetOperation(Mat mat, MatOperation op, void (**f)(void))
11248 {
11249   PetscFunctionBegin;
11250   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11251   *f = (((void (**)(void))mat->ops)[op]);
11252   PetscFunctionReturn(PETSC_SUCCESS);
11253 }
11254 
11255 /*@
11256   MatHasOperation - Determines whether the given matrix supports the particular operation.
11257 
11258   Not Collective
11259 
11260   Input Parameters:
11261 + mat - the matrix
11262 - op  - the operation, for example, `MATOP_GET_DIAGONAL`
11263 
11264   Output Parameter:
11265 . has - either `PETSC_TRUE` or `PETSC_FALSE`
11266 
11267   Level: advanced
11268 
11269   Note:
11270   See `MatSetOperation()` for additional discussion on naming convention and usage of `op`.
11271 
11272 .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`, `MatGetOperation()`, `MatSetOperation()`
11273 @*/
11274 PetscErrorCode MatHasOperation(Mat mat, MatOperation op, PetscBool *has)
11275 {
11276   PetscFunctionBegin;
11277   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11278   PetscAssertPointer(has, 3);
11279   if (mat->ops->hasoperation) {
11280     PetscUseTypeMethod(mat, hasoperation, op, has);
11281   } else {
11282     if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
11283     else {
11284       *has = PETSC_FALSE;
11285       if (op == MATOP_CREATE_SUBMATRIX) {
11286         PetscMPIInt size;
11287 
11288         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
11289         if (size == 1) PetscCall(MatHasOperation(mat, MATOP_CREATE_SUBMATRICES, has));
11290       }
11291     }
11292   }
11293   PetscFunctionReturn(PETSC_SUCCESS);
11294 }
11295 
11296 /*@
11297   MatHasCongruentLayouts - Determines whether the rows and columns layouts of the matrix are congruent
11298 
11299   Collective
11300 
11301   Input Parameter:
11302 . mat - the matrix
11303 
11304   Output Parameter:
11305 . cong - either `PETSC_TRUE` or `PETSC_FALSE`
11306 
11307   Level: beginner
11308 
11309 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatSetSizes()`, `PetscLayout`
11310 @*/
11311 PetscErrorCode MatHasCongruentLayouts(Mat mat, PetscBool *cong)
11312 {
11313   PetscFunctionBegin;
11314   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11315   PetscValidType(mat, 1);
11316   PetscAssertPointer(cong, 2);
11317   if (!mat->rmap || !mat->cmap) {
11318     *cong = mat->rmap == mat->cmap ? PETSC_TRUE : PETSC_FALSE;
11319     PetscFunctionReturn(PETSC_SUCCESS);
11320   }
11321   if (mat->congruentlayouts == PETSC_DECIDE) { /* first time we compare rows and cols layouts */
11322     PetscCall(PetscLayoutSetUp(mat->rmap));
11323     PetscCall(PetscLayoutSetUp(mat->cmap));
11324     PetscCall(PetscLayoutCompare(mat->rmap, mat->cmap, cong));
11325     if (*cong) mat->congruentlayouts = 1;
11326     else mat->congruentlayouts = 0;
11327   } else *cong = mat->congruentlayouts ? PETSC_TRUE : PETSC_FALSE;
11328   PetscFunctionReturn(PETSC_SUCCESS);
11329 }
11330 
11331 PetscErrorCode MatSetInf(Mat A)
11332 {
11333   PetscFunctionBegin;
11334   PetscUseTypeMethod(A, setinf);
11335   PetscFunctionReturn(PETSC_SUCCESS);
11336 }
11337 
11338 /*@
11339   MatCreateGraph - create a scalar matrix (that is a matrix with one vertex for each block vertex in the original matrix), for use in graph algorithms
11340   and possibly removes small values from the graph structure.
11341 
11342   Collective
11343 
11344   Input Parameters:
11345 + A       - the matrix
11346 . sym     - `PETSC_TRUE` indicates that the graph should be symmetrized
11347 . scale   - `PETSC_TRUE` indicates that the graph edge weights should be symmetrically scaled with the diagonal entry
11348 . filter  - filter value - < 0: does nothing; == 0: removes only 0.0 entries; otherwise: removes entries with abs(entries) <= value
11349 . num_idx - size of 'index' array
11350 - index   - array of block indices to use for graph strength of connection weight
11351 
11352   Output Parameter:
11353 . graph - the resulting graph
11354 
11355   Level: advanced
11356 
11357 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PCGAMG`
11358 @*/
11359 PetscErrorCode MatCreateGraph(Mat A, PetscBool sym, PetscBool scale, PetscReal filter, PetscInt num_idx, PetscInt index[], Mat *graph)
11360 {
11361   PetscFunctionBegin;
11362   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11363   PetscValidType(A, 1);
11364   PetscValidLogicalCollectiveBool(A, scale, 3);
11365   PetscAssertPointer(graph, 7);
11366   PetscCall(PetscLogEventBegin(MAT_CreateGraph, A, 0, 0, 0));
11367   PetscUseTypeMethod(A, creategraph, sym, scale, filter, num_idx, index, graph);
11368   PetscCall(PetscLogEventEnd(MAT_CreateGraph, A, 0, 0, 0));
11369   PetscFunctionReturn(PETSC_SUCCESS);
11370 }
11371 
11372 /*@
11373   MatEliminateZeros - eliminate the nondiagonal zero entries in place from the nonzero structure of a sparse `Mat` in place,
11374   meaning the same memory is used for the matrix, and no new memory is allocated.
11375 
11376   Collective
11377 
11378   Input Parameters:
11379 + A    - the matrix
11380 - keep - if for a given row of `A`, the diagonal coefficient is zero, indicates whether it should be left in the structure or eliminated as well
11381 
11382   Level: intermediate
11383 
11384   Developer Note:
11385   The entries in the sparse matrix data structure are shifted to fill in the unneeded locations in the data. Thus the end
11386   of the arrays in the data structure are unneeded.
11387 
11388 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateGraph()`, `MatFilter()`
11389 @*/
11390 PetscErrorCode MatEliminateZeros(Mat A, PetscBool keep)
11391 {
11392   PetscFunctionBegin;
11393   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11394   PetscUseTypeMethod(A, eliminatezeros, keep);
11395   PetscFunctionReturn(PETSC_SUCCESS);
11396 }
11397 
11398 /*@C
11399   MatGetCurrentMemType - Get the memory location of the matrix
11400 
11401   Not Collective, but the result will be the same on all MPI processes
11402 
11403   Input Parameter:
11404 . A - the matrix whose memory type we are checking
11405 
11406   Output Parameter:
11407 . m - the memory type
11408 
11409   Level: intermediate
11410 
11411 .seealso: [](ch_matrices), `Mat`, `MatBoundToCPU()`, `PetscMemType`
11412 @*/
11413 PetscErrorCode MatGetCurrentMemType(Mat A, PetscMemType *m)
11414 {
11415   PetscFunctionBegin;
11416   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11417   PetscAssertPointer(m, 2);
11418   if (A->ops->getcurrentmemtype) PetscUseTypeMethod(A, getcurrentmemtype, m);
11419   else *m = PETSC_MEMTYPE_HOST;
11420   PetscFunctionReturn(PETSC_SUCCESS);
11421 }
11422