xref: /petsc/src/mat/utils/gcreate.c (revision 607e733f3db3ee7f6f605a13295c517df8dbb9c9)
1 #include <petsc/private/matimpl.h> /*I "petscmat.h"  I*/
2 
3 #include <../src/mat/impls/aij/seq/aij.h>
4 #include <../src/mat/impls/aij/mpi/mpiaij.h>
5 
6 PetscErrorCode MatSetBlockSizes_Default(Mat mat, PetscInt rbs, PetscInt cbs)
7 {
8   PetscFunctionBegin;
9   if (!mat->preallocated) PetscFunctionReturn(PETSC_SUCCESS);
10   PetscCheck(mat->rmap->bs <= 0 || mat->rmap->bs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot change row block size %" PetscInt_FMT " to %" PetscInt_FMT, mat->rmap->bs, rbs);
11   PetscCheck(mat->cmap->bs <= 0 || mat->cmap->bs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot change column block size %" PetscInt_FMT " to %" PetscInt_FMT, mat->cmap->bs, cbs);
12   PetscFunctionReturn(PETSC_SUCCESS);
13 }
14 
15 PetscErrorCode MatShift_Basic(Mat Y, PetscScalar a)
16 {
17   PetscInt    i, start, end, oldValA = 0, oldValB = 0;
18   PetscScalar alpha = a;
19   PetscBool   prevoption;
20   PetscBool   isSeqAIJDerived, isMPIAIJDerived; // all classes sharing SEQAIJHEADER or MPIAIJHEADER
21   Mat         A = NULL, B = NULL;
22 
23   PetscFunctionBegin;
24   PetscCall(MatGetOption(Y, MAT_NO_OFF_PROC_ENTRIES, &prevoption));
25   PetscCall(MatSetOption(Y, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
26   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isSeqAIJDerived, MATSEQAIJ, MATSEQBAIJ, MATSEQSBAIJ, ""));
27   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isMPIAIJDerived, MATMPIAIJ, MATMPIBAIJ, MATMPISBAIJ, ""));
28 
29   if (isSeqAIJDerived) A = Y;
30   else if (isMPIAIJDerived) {
31     Mat_MPIAIJ *mpiaij = (Mat_MPIAIJ *)Y->data;
32     A                  = mpiaij->A;
33     B                  = mpiaij->B;
34   }
35 
36   if (A) {
37     oldValA                        = ((Mat_SeqAIJ *)A->data)->nonew;
38     ((Mat_SeqAIJ *)A->data)->nonew = 0; // so that new nonzero locations are allowed
39   }
40   if (B) {
41     oldValB                        = ((Mat_SeqAIJ *)B->data)->nonew;
42     ((Mat_SeqAIJ *)B->data)->nonew = 0;
43   }
44 
45   PetscCall(MatGetOwnershipRange(Y, &start, &end));
46   for (i = start; i < end; i++) {
47     if (i < Y->cmap->N) PetscCall(MatSetValues(Y, 1, &i, 1, &i, &alpha, ADD_VALUES));
48   }
49   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
50   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
51   PetscCall(MatSetOption(Y, MAT_NO_OFF_PROC_ENTRIES, prevoption));
52   if (A) ((Mat_SeqAIJ *)A->data)->nonew = oldValA;
53   if (B) ((Mat_SeqAIJ *)B->data)->nonew = oldValB;
54   PetscFunctionReturn(PETSC_SUCCESS);
55 }
56 
57 /*@
58   MatCreate - Creates a matrix where the type is determined
59   from either a call to `MatSetType()` or from the options database
60   with a call to `MatSetFromOptions()`.
61 
62   Collective
63 
64   Input Parameter:
65 . comm - MPI communicator
66 
67   Output Parameter:
68 . A - the matrix
69 
70   Options Database Keys:
71 + -mat_type seqaij   - `MATSEQAIJ` type, uses `MatCreateSeqAIJ()`
72 . -mat_type mpiaij   - `MATMPIAIJ` type, uses `MatCreateAIJ()`
73 . -mat_type seqdense - `MATSEQDENSE`, uses `MatCreateSeqDense()`
74 . -mat_type mpidense - `MATMPIDENSE` type, uses `MatCreateDense()`
75 . -mat_type seqbaij  - `MATSEQBAIJ` type, uses `MatCreateSeqBAIJ()`
76 - -mat_type mpibaij  - `MATMPIBAIJ` type, uses `MatCreateBAIJ()`
77 
78    See the manpages for particular formats (e.g., `MATSEQAIJ`)
79    for additional format-specific options.
80 
81   Level: beginner
82 
83   Notes:
84   The default matrix type is `MATAIJ`, using the routines `MatCreateSeqAIJ()` or
85   `MatCreateAIJ()` if you do not set a type in the options database. If you never call
86   `MatSetType()` or `MatSetFromOptions()` it will generate an error when you try to use the
87   matrix.
88 
89 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`,
90           `MatCreateSeqDense()`, `MatCreateDense()`,
91           `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`,
92           `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`,
93           `MatConvert()`
94 @*/
95 PetscErrorCode MatCreate(MPI_Comm comm, Mat *A)
96 {
97   Mat B;
98 
99   PetscFunctionBegin;
100   PetscAssertPointer(A, 2);
101   PetscCall(MatInitializePackage());
102 
103   PetscCall(PetscHeaderCreate(B, MAT_CLASSID, "Mat", "Matrix", "Mat", comm, MatDestroy, MatView));
104   PetscCall(PetscLayoutCreate(comm, &B->rmap));
105   PetscCall(PetscLayoutCreate(comm, &B->cmap));
106   PetscCall(PetscStrallocpy(VECSTANDARD, &B->defaultvectype));
107   PetscCall(PetscStrallocpy(PETSCRANDER48, &B->defaultrandtype));
108 
109   B->symmetric                   = PETSC_BOOL3_UNKNOWN;
110   B->hermitian                   = PETSC_BOOL3_UNKNOWN;
111   B->structurally_symmetric      = PETSC_BOOL3_UNKNOWN;
112   B->spd                         = PETSC_BOOL3_UNKNOWN;
113   B->symmetry_eternal            = PETSC_FALSE;
114   B->structural_symmetry_eternal = PETSC_FALSE;
115 
116   B->congruentlayouts = PETSC_DECIDE;
117   B->preallocated     = PETSC_FALSE;
118 #if defined(PETSC_HAVE_DEVICE)
119   B->boundtocpu = PETSC_TRUE;
120 #endif
121   *A = B;
122   PetscFunctionReturn(PETSC_SUCCESS);
123 }
124 
125 /*@
126   MatCreateFromOptions - Creates a matrix whose type is set from the options database
127 
128   Collective
129 
130   Input Parameters:
131 + comm   - MPI communicator
132 . prefix - [optional] prefix for the options database
133 . bs     - the blocksize (commonly 1)
134 . m      - the local number of rows (or `PETSC_DECIDE`)
135 . n      - the local number of columns (or `PETSC_DECIDE` or `PETSC_DETERMINE`)
136 . M      - the global number of rows (or `PETSC_DETERMINE`)
137 - N      - the global number of columns (or `PETSC_DETERMINE`)
138 
139   Output Parameter:
140 . A - the matrix
141 
142   Options Database Key:
143 . -mat_type - see `MatType`, for example `aij`, `aijcusparse`, `baij`, `sbaij`, `dense`, defaults to `aij`
144 
145   Level: beginner
146 
147 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`,
148           `MatCreateSeqDense()`, `MatCreateDense()`,
149           `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`,
150           `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`,
151           `MatConvert()`, `MatCreate()`
152 @*/
153 PetscErrorCode MatCreateFromOptions(MPI_Comm comm, const char *prefix, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, Mat *A)
154 {
155   PetscFunctionBegin;
156   PetscAssertPointer(A, 8);
157   PetscCall(MatCreate(comm, A));
158   if (prefix) PetscCall(MatSetOptionsPrefix(*A, prefix));
159   PetscCall(MatSetBlockSize(*A, bs));
160   PetscCall(MatSetSizes(*A, m, n, M, N));
161   PetscCall(MatSetFromOptions(*A));
162   PetscFunctionReturn(PETSC_SUCCESS);
163 }
164 
165 /*@
166   MatSetErrorIfFailure - Causes `Mat` to generate an immediate error, for example a zero pivot, is detected.
167 
168   Logically Collective
169 
170   Input Parameters:
171 + mat - matrix obtained from `MatCreate()`
172 - flg - `PETSC_TRUE` indicates you want the error generated
173 
174   Level: advanced
175 
176   Note:
177   If this flag is not set then the matrix operation will note the error and continue. The error may cause a later `PC` or `KSP` error
178   or result in a `KSPConvergedReason` indicating the method did not converge.
179 
180 .seealso: [](ch_matrices), `Mat`, `PCSetErrorIfFailure()`, `KSPConvergedReason`, `SNESConvergedReason`
181 @*/
182 PetscErrorCode MatSetErrorIfFailure(Mat mat, PetscBool flg)
183 {
184   PetscFunctionBegin;
185   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
186   PetscValidLogicalCollectiveBool(mat, flg, 2);
187   mat->erroriffailure = flg;
188   PetscFunctionReturn(PETSC_SUCCESS);
189 }
190 
191 /*@
192   MatSetSizes - Sets the local and global sizes, and checks to determine compatibility
193 
194   Collective
195 
196   Input Parameters:
197 + A - the matrix
198 . m - number of local rows (or `PETSC_DECIDE`)
199 . n - number of local columns (or `PETSC_DECIDE`)
200 . M - number of global rows (or `PETSC_DETERMINE`)
201 - N - number of global columns (or `PETSC_DETERMINE`)
202 
203   Level: beginner
204 
205   Notes:
206   `m` (`n`) and `M` (`N`) cannot be both `PETSC_DECIDE`
207   If one processor calls this with `M` (`N`) of `PETSC_DECIDE` then all processors must, otherwise the program will hang.
208 
209   If `PETSC_DECIDE` is not used for the arguments 'm' and 'n', then the
210   user must ensure that they are chosen to be compatible with the
211   vectors. To do this, one first considers the matrix-vector product
212   'y = A x'. The `m` that is used in the above routine must match the
213   local size of 'y'. Likewise, the `n` used must match the local size of 'x'.
214 
215   If `m` and `n` are not `PETSC_DECIDE`, then the values determine the `PetscLayout` of the matrix and the ranges returned by
216   `MatGetOwnershipRange()`,  `MatGetOwnershipRanges()`, `MatGetOwnershipRangeColumn()`, and `MatGetOwnershipRangesColumn()`.
217 
218   You cannot change the sizes once they have been set.
219 
220   The sizes must be set before `MatSetUp()` or MatXXXSetPreallocation() is called.
221 
222 .seealso: [](ch_matrices), `Mat`, `MatGetSize()`, `PetscSplitOwnership()`, `MatGetOwnershipRange()`, `MatGetOwnershipRanges()`,
223           `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`, `VecSetSizes()`
224 @*/
225 PetscErrorCode MatSetSizes(Mat A, PetscInt m, PetscInt n, PetscInt M, PetscInt N)
226 {
227   PetscFunctionBegin;
228   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
229   PetscValidLogicalCollectiveInt(A, M, 4);
230   PetscValidLogicalCollectiveInt(A, N, 5);
231   PetscCheck(M <= 0 || m <= M, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local row size %" PetscInt_FMT " cannot be larger than global row size %" PetscInt_FMT, m, M);
232   PetscCheck(N <= 0 || n <= N, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local column size %" PetscInt_FMT " cannot be larger than global column size %" PetscInt_FMT, n, N);
233   PetscCheck((A->rmap->n < 0 || A->rmap->N < 0) || (A->rmap->n == m && (M <= 0 || A->rmap->N == M)), PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot change/reset row sizes to %" PetscInt_FMT " local %" PetscInt_FMT " global after previously setting them to %" PetscInt_FMT " local %" PetscInt_FMT " global", m, M,
234              A->rmap->n, A->rmap->N);
235   PetscCheck((A->cmap->n < 0 || A->cmap->N < 0) || (A->cmap->n == n && (N <= 0 || A->cmap->N == N)), PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot change/reset column sizes to %" PetscInt_FMT " local %" PetscInt_FMT " global after previously setting them to %" PetscInt_FMT " local %" PetscInt_FMT " global", n, N,
236              A->cmap->n, A->cmap->N);
237   A->rmap->n = m;
238   A->cmap->n = n;
239   A->rmap->N = M > -1 ? M : A->rmap->N;
240   A->cmap->N = N > -1 ? N : A->cmap->N;
241   PetscFunctionReturn(PETSC_SUCCESS);
242 }
243 
244 /*@
245   MatSetFromOptions - Creates a matrix where the type is determined
246   from the options database.
247 
248   Collective
249 
250   Input Parameter:
251 . B - the matrix
252 
253   Options Database Keys:
254 + -mat_type seqaij   - `MATSEQAIJ` type, uses `MatCreateSeqAIJ()`
255 . -mat_type mpiaij   - `MATMPIAIJ` type, uses `MatCreateAIJ()`
256 . -mat_type seqdense - `MATSEQDENSE` type, uses `MatCreateSeqDense()`
257 . -mat_type mpidense - `MATMPIDENSE`, uses `MatCreateDense()`
258 . -mat_type seqbaij  - `MATSEQBAIJ`, uses `MatCreateSeqBAIJ()`
259 - -mat_type mpibaij  - `MATMPIBAIJ`, uses `MatCreateBAIJ()`
260 
261    See the manpages for particular formats (e.g., `MATSEQAIJ`)
262    for additional format-specific options.
263 
264   Level: beginner
265 
266   Notes:
267   Generates a parallel MPI matrix if the communicator has more than one processor.  The default
268   matrix type is `MATAIJ`, using the routines `MatCreateSeqAIJ()` and `MatCreateAIJ()` if you
269   do not select a type in the options database.
270 
271 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`,
272           `MatCreateSeqDense()`, `MatCreateDense()`,
273           `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`,
274           `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`,
275           `MatConvert()`
276 @*/
277 PetscErrorCode MatSetFromOptions(Mat B)
278 {
279   const char *deft = MATAIJ;
280   char        type[256];
281   PetscBool   flg, set;
282   PetscInt    bind_below = 0, newbs = -1;
283 
284   PetscFunctionBegin;
285   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
286 
287   PetscObjectOptionsBegin((PetscObject)B);
288 
289   PetscCall(PetscOptionsInt("-mat_block_size", "Set the blocksize used to store the matrix", "MatSetBlockSize", newbs, &newbs, &flg));
290   if (flg) {
291     PetscCall(PetscLayoutSetBlockSize(B->rmap, newbs));
292     PetscCall(PetscLayoutSetBlockSize(B->cmap, newbs));
293   }
294 
295   PetscCall(PetscOptionsFList("-mat_type", "Matrix type", "MatSetType", MatList, deft, type, PETSC_STATIC_ARRAY_LENGTH(type), &flg));
296   if (flg) PetscCall(MatSetType(B, type));
297   else if (!((PetscObject)B)->type_name) PetscCall(MatSetType(B, deft));
298 
299   if (newbs > 0) PetscTryTypeMethod(B, setblocksizes, newbs, newbs);
300 
301   PetscCall(PetscOptionsName("-mat_is_symmetric", "Checks if mat is symmetric on MatAssemblyEnd()", "MatIsSymmetric", &B->checksymmetryonassembly));
302   PetscCall(PetscOptionsReal("-mat_is_symmetric", "Checks if mat is symmetric on MatAssemblyEnd()", "MatIsSymmetric", B->checksymmetrytol, &B->checksymmetrytol, NULL));
303   PetscCall(PetscOptionsBool("-mat_null_space_test", "Checks if provided null space is correct in MatAssemblyEnd()", "MatSetNullSpaceTest", B->checknullspaceonassembly, &B->checknullspaceonassembly, NULL));
304   PetscCall(PetscOptionsBool("-mat_error_if_failure", "Generate an error if an error occurs when factoring the matrix", "MatSetErrorIfFailure", B->erroriffailure, &B->erroriffailure, NULL));
305 
306   PetscTryTypeMethod(B, setfromoptions, PetscOptionsObject);
307 
308   flg = PETSC_FALSE;
309   PetscCall(PetscOptionsBool("-mat_new_nonzero_location_err", "Generate an error if new nonzeros are created in the matrix nonzero structure (useful to test preallocation)", "MatSetOption", flg, &flg, &set));
310   if (set) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, flg));
311   flg = PETSC_FALSE;
312   PetscCall(PetscOptionsBool("-mat_new_nonzero_allocation_err", "Generate an error if new nonzeros are allocated in the matrix nonzero structure (useful to test preallocation)", "MatSetOption", flg, &flg, &set));
313   if (set) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, flg));
314   flg = PETSC_FALSE;
315   PetscCall(PetscOptionsBool("-mat_ignore_zero_entries", "For AIJ/IS matrices this will stop zero values from creating a zero location in the matrix", "MatSetOption", flg, &flg, &set));
316   if (set) PetscCall(MatSetOption(B, MAT_IGNORE_ZERO_ENTRIES, flg));
317 
318   flg = PETSC_FALSE;
319   PetscCall(PetscOptionsBool("-mat_form_explicit_transpose", "Hint to form an explicit transpose for operations like MatMultTranspose", "MatSetOption", flg, &flg, &set));
320   if (set) PetscCall(MatSetOption(B, MAT_FORM_EXPLICIT_TRANSPOSE, flg));
321 
322   /* Bind to CPU if below a user-specified size threshold.
323    * This perhaps belongs in the options for the GPU Mat types, but MatBindToCPU() does nothing when called on non-GPU types,
324    * and putting it here makes is more maintainable than duplicating this for all. */
325   PetscCall(PetscOptionsInt("-mat_bind_below", "Set the size threshold (in local rows) below which the Mat is bound to the CPU", "MatBindToCPU", bind_below, &bind_below, &flg));
326   if (flg && B->rmap->n < bind_below) PetscCall(MatBindToCPU(B, PETSC_TRUE));
327 
328   /* process any options handlers added with PetscObjectAddOptionsHandler() */
329   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)B, PetscOptionsObject));
330   PetscOptionsEnd();
331   PetscFunctionReturn(PETSC_SUCCESS);
332 }
333 
334 /*@
335   MatXAIJSetPreallocation - set preallocation for serial and parallel `MATAIJ`, `MATBAIJ`, and `MATSBAIJ` matrices and their unassembled versions.
336 
337   Collective
338 
339   Input Parameters:
340 + A     - matrix being preallocated
341 . bs    - block size
342 . dnnz  - number of nonzero column blocks per block row of diagonal part of parallel matrix
343 . onnz  - number of nonzero column blocks per block row of off-diagonal part of parallel matrix
344 . dnnzu - number of nonzero column blocks per block row of upper-triangular part of diagonal part of parallel matrix
345 - onnzu - number of nonzero column blocks per block row of upper-triangular part of off-diagonal part of parallel matrix
346 
347   Level: beginner
348 
349 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`, `MatMPIBAIJSetPreallocation()`,
350           `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`,
351           `PetscSplitOwnership()`
352 @*/
353 PetscErrorCode MatXAIJSetPreallocation(Mat A, PetscInt bs, const PetscInt dnnz[], const PetscInt onnz[], const PetscInt dnnzu[], const PetscInt onnzu[])
354 {
355   PetscInt  cbs;
356   PetscBool aij, is, hyp;
357 
358   PetscFunctionBegin;
359   if (bs != PETSC_DECIDE) { /* don't mess with an already set block size */
360     PetscCall(MatSetBlockSize(A, bs));
361   }
362   PetscCall(PetscLayoutSetUp(A->rmap));
363   PetscCall(PetscLayoutSetUp(A->cmap));
364   PetscCall(MatGetBlockSizes(A, &bs, &cbs));
365   /* these routines assumes bs == cbs, this should be checked somehow */
366   PetscCall(MatSeqBAIJSetPreallocation(A, bs, 0, dnnz));
367   PetscCall(MatMPIBAIJSetPreallocation(A, bs, 0, dnnz, 0, onnz));
368   PetscCall(MatSeqSBAIJSetPreallocation(A, bs, 0, dnnzu));
369   PetscCall(MatMPISBAIJSetPreallocation(A, bs, 0, dnnzu, 0, onnzu));
370   /*
371     In general, we have to do extra work to preallocate for scalar (AIJ) or unassembled (IS) matrices so we check whether it will do any
372     good before going on with it.
373   */
374   PetscCall(PetscObjectHasFunction((PetscObject)A, "MatMPIAIJSetPreallocation_C", &aij));
375   PetscCall(PetscObjectHasFunction((PetscObject)A, "MatISSetPreallocation_C", &is));
376   PetscCall(PetscObjectHasFunction((PetscObject)A, "MatHYPRESetPreallocation_C", &hyp));
377   if (!aij && !is && !hyp) PetscCall(PetscObjectHasFunction((PetscObject)A, "MatSeqAIJSetPreallocation_C", &aij));
378   if (aij || is || hyp) {
379     if (bs == cbs && bs == 1) {
380       PetscCall(MatSeqAIJSetPreallocation(A, 0, dnnz));
381       PetscCall(MatMPIAIJSetPreallocation(A, 0, dnnz, 0, onnz));
382       PetscCall(MatISSetPreallocation(A, 0, dnnz, 0, onnz));
383 #if defined(PETSC_HAVE_HYPRE)
384       PetscCall(MatHYPRESetPreallocation(A, 0, dnnz, 0, onnz));
385 #endif
386     } else { /* Convert block-row precallocation to scalar-row */
387       PetscInt i, m, *sdnnz, *sonnz;
388       PetscCall(MatGetLocalSize(A, &m, NULL));
389       PetscCall(PetscMalloc2((!!dnnz) * m, &sdnnz, (!!onnz) * m, &sonnz));
390       for (i = 0; i < m; i++) {
391         if (dnnz) sdnnz[i] = dnnz[i / bs] * cbs;
392         if (onnz) sonnz[i] = onnz[i / bs] * cbs;
393       }
394       PetscCall(MatSeqAIJSetPreallocation(A, 0, dnnz ? sdnnz : NULL));
395       PetscCall(MatMPIAIJSetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
396       PetscCall(MatISSetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
397 #if defined(PETSC_HAVE_HYPRE)
398       PetscCall(MatHYPRESetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
399 #endif
400       PetscCall(PetscFree2(sdnnz, sonnz));
401     }
402   }
403   PetscFunctionReturn(PETSC_SUCCESS);
404 }
405 
406 /*@C
407   MatHeaderMerge - Merges some information from the header of `C` to `A`; the `C` object is then destroyed
408 
409   Collective, No Fortran Support
410 
411   Input Parameters:
412 + A - a `Mat` being merged into
413 - C - the `Mat` providing the merge information
414 
415   Level: developer
416 
417   Notes:
418   `A` and `C` must be of the same type.
419   The object list and query function list in `A` are retained, as well as the object name, and prefix.
420   The object state of `A` is increased by 1.
421 
422   Developer Note:
423   This is somewhat different from `MatHeaderReplace()`, it would be nice to merge the code
424 
425 .seealso: `Mat`, `MatHeaderReplace()`
426  @*/
427 PetscErrorCode MatHeaderMerge(Mat A, Mat *C)
428 {
429   PetscInt          refct;
430   PetscOps          Abops;
431   struct _MatOps    Aops;
432   char             *mtype, *mname, *mprefix;
433   Mat_Product      *product;
434   Mat_Redundant    *redundant;
435   PetscObjectState  state;
436   PetscObjectList   olist;
437   PetscFunctionList qlist;
438 
439   PetscFunctionBegin;
440   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
441   PetscValidHeaderSpecific(*C, MAT_CLASSID, 2);
442   if (A == *C) PetscFunctionReturn(PETSC_SUCCESS);
443   PetscCheckSameTypeAndComm(A, 1, *C, 2);
444   /* save the parts of A we need */
445   Abops     = ((PetscObject)A)->bops[0];
446   Aops      = A->ops[0];
447   refct     = ((PetscObject)A)->refct;
448   mtype     = ((PetscObject)A)->type_name;
449   mname     = ((PetscObject)A)->name;
450   state     = ((PetscObject)A)->state;
451   mprefix   = ((PetscObject)A)->prefix;
452   product   = A->product;
453   redundant = A->redundant;
454   qlist     = ((PetscObject)A)->qlist;
455   olist     = ((PetscObject)A)->olist;
456 
457   /* zero these so the destroy below does not free them */
458   ((PetscObject)A)->type_name = NULL;
459   ((PetscObject)A)->name      = NULL;
460   ((PetscObject)A)->qlist     = NULL;
461   ((PetscObject)A)->olist     = NULL;
462 
463   /*
464      free all the interior data structures from mat
465      cannot use PetscUseTypeMethod(A,destroy); because compiler
466      thinks it may print NULL type_name and name
467   */
468   PetscTryTypeMethod(A, destroy);
469 
470   PetscCall(PetscFree(A->defaultvectype));
471   PetscCall(PetscFree(A->defaultrandtype));
472   PetscCall(PetscLayoutDestroy(&A->rmap));
473   PetscCall(PetscLayoutDestroy(&A->cmap));
474   PetscCall(PetscComposedQuantitiesDestroy((PetscObject)A));
475 
476   /* copy C over to A */
477   PetscCall(PetscFree(A->factorprefix));
478   PetscCall(PetscMemcpy(A, *C, sizeof(struct _p_Mat)));
479 
480   /* return the parts of A we saved */
481   ((PetscObject)A)->bops[0]   = Abops;
482   A->ops[0]                   = Aops;
483   ((PetscObject)A)->refct     = refct;
484   ((PetscObject)A)->type_name = mtype;
485   ((PetscObject)A)->name      = mname;
486   ((PetscObject)A)->prefix    = mprefix;
487   ((PetscObject)A)->state     = state + 1;
488   A->product                  = product;
489   A->redundant                = redundant;
490 
491   /* Append the saved lists */
492   PetscCall(PetscFunctionListDuplicate(qlist, &((PetscObject)A)->qlist));
493   PetscCall(PetscObjectListDuplicate(olist, &((PetscObject)A)->olist));
494   PetscCall(PetscFunctionListDestroy(&qlist));
495   PetscCall(PetscObjectListDestroy(&olist));
496 
497   /* since these two are copied into A we do not want them destroyed in C */
498   ((PetscObject)*C)->qlist = NULL;
499   ((PetscObject)*C)->olist = NULL;
500   PetscCall(PetscHeaderDestroy(C));
501   PetscFunctionReturn(PETSC_SUCCESS);
502 }
503 
504 /*@
505   MatHeaderReplace - Replaces the internal data of matrix `A` by the internal data of matrix `C` while deleting the outer wrapper of `C`
506 
507   Input Parameters:
508 + A - a `Mat` whose internal data is to be replaced
509 - C - the `Mat` providing new internal data for `A`
510 
511   Level: advanced
512 
513   Example Usage\:
514 .vb
515   Mat C;
516   MatCreateSeqAIJWithArrays(..., &C);
517   MatHeaderReplace(A, &C);
518   // C has been destroyed and A contains the matrix entries of C
519 .ve
520 
521   Note:
522   This can be used inside a function provided to `SNESSetJacobian()`, `TSSetRHSJacobian()`, or `TSSetIJacobian()` in cases where the user code
523   computes an entirely new sparse matrix  (generally with a different matrix nonzero structure/pattern) for each Newton update.
524   It is usually better to reuse the matrix nonzero structure of `A` instead of constructing an entirely new one.
525 
526   Developer Note:
527   This is somewhat different from `MatHeaderMerge()` it would be nice to merge the code
528 
529 .seealso: `Mat`, `MatHeaderMerge()`
530  @*/
531 PetscErrorCode MatHeaderReplace(Mat A, Mat *C)
532 {
533   PetscInt         refct;
534   PetscObjectState state;
535   struct _p_Mat    buffer;
536   MatStencilInfo   stencil;
537 
538   PetscFunctionBegin;
539   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
540   PetscValidHeaderSpecific(*C, MAT_CLASSID, 2);
541   if (A == *C) PetscFunctionReturn(PETSC_SUCCESS);
542   PetscCheckSameComm(A, 1, *C, 2);
543   PetscCheck(((PetscObject)*C)->refct == 1, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Object C has refct %" PetscInt_FMT " > 1, would leave hanging reference", ((PetscObject)*C)->refct);
544 
545   /* swap C and A */
546   refct   = ((PetscObject)A)->refct;
547   state   = ((PetscObject)A)->state;
548   stencil = A->stencil;
549   PetscCall(PetscMemcpy(&buffer, A, sizeof(struct _p_Mat)));
550   PetscCall(PetscMemcpy(A, *C, sizeof(struct _p_Mat)));
551   PetscCall(PetscMemcpy(*C, &buffer, sizeof(struct _p_Mat)));
552   ((PetscObject)A)->refct = refct;
553   ((PetscObject)A)->state = state + 1;
554   A->stencil              = stencil;
555 
556   ((PetscObject)*C)->refct = 1;
557   PetscCall(MatDestroy(C));
558   PetscFunctionReturn(PETSC_SUCCESS);
559 }
560 
561 /*@
562   MatBindToCPU - marks a matrix to temporarily stay on the CPU and perform computations on the CPU
563 
564   Logically Collective
565 
566   Input Parameters:
567 + A   - the matrix
568 - flg - bind to the CPU if value of `PETSC_TRUE`
569 
570   Level: intermediate
571 
572 .seealso: [](ch_matrices), `Mat`, `MatBoundToCPU()`
573 @*/
574 PetscErrorCode MatBindToCPU(Mat A, PetscBool flg)
575 {
576   PetscFunctionBegin;
577   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
578   PetscValidLogicalCollectiveBool(A, flg, 2);
579 #if defined(PETSC_HAVE_DEVICE)
580   if (A->boundtocpu == flg) PetscFunctionReturn(PETSC_SUCCESS);
581   A->boundtocpu = flg;
582   PetscTryTypeMethod(A, bindtocpu, flg);
583 #endif
584   PetscFunctionReturn(PETSC_SUCCESS);
585 }
586 
587 /*@
588   MatBoundToCPU - query if a matrix is bound to the CPU
589 
590   Input Parameter:
591 . A - the matrix
592 
593   Output Parameter:
594 . flg - the logical flag
595 
596   Level: intermediate
597 
598 .seealso: [](ch_matrices), `Mat`, `MatBindToCPU()`
599 @*/
600 PetscErrorCode MatBoundToCPU(Mat A, PetscBool *flg)
601 {
602   PetscFunctionBegin;
603   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
604   PetscAssertPointer(flg, 2);
605 #if defined(PETSC_HAVE_DEVICE)
606   *flg = A->boundtocpu;
607 #else
608   *flg = PETSC_TRUE;
609 #endif
610   PetscFunctionReturn(PETSC_SUCCESS);
611 }
612 
613 PetscErrorCode MatSetValuesCOO_Basic(Mat A, const PetscScalar coo_v[], InsertMode imode)
614 {
615   IS              is_coo_i, is_coo_j;
616   const PetscInt *coo_i, *coo_j;
617   PetscInt        n, n_i, n_j;
618   PetscScalar     zero = 0.;
619 
620   PetscFunctionBegin;
621   PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_coo_i", (PetscObject *)&is_coo_i));
622   PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_coo_j", (PetscObject *)&is_coo_j));
623   PetscCheck(is_coo_i, PetscObjectComm((PetscObject)A), PETSC_ERR_COR, "Missing coo_i IS");
624   PetscCheck(is_coo_j, PetscObjectComm((PetscObject)A), PETSC_ERR_COR, "Missing coo_j IS");
625   PetscCall(ISGetLocalSize(is_coo_i, &n_i));
626   PetscCall(ISGetLocalSize(is_coo_j, &n_j));
627   PetscCheck(n_i == n_j, PETSC_COMM_SELF, PETSC_ERR_COR, "Wrong local size %" PetscInt_FMT " != %" PetscInt_FMT, n_i, n_j);
628   PetscCall(ISGetIndices(is_coo_i, &coo_i));
629   PetscCall(ISGetIndices(is_coo_j, &coo_j));
630   if (imode != ADD_VALUES) PetscCall(MatZeroEntries(A));
631   for (n = 0; n < n_i; n++) PetscCall(MatSetValue(A, coo_i[n], coo_j[n], coo_v ? coo_v[n] : zero, ADD_VALUES));
632   PetscCall(ISRestoreIndices(is_coo_i, &coo_i));
633   PetscCall(ISRestoreIndices(is_coo_j, &coo_j));
634   PetscFunctionReturn(PETSC_SUCCESS);
635 }
636 
637 PetscErrorCode MatSetPreallocationCOO_Basic(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
638 {
639   Mat         preallocator;
640   IS          is_coo_i, is_coo_j;
641   PetscInt    ncoo_i;
642   PetscScalar zero = 0.0;
643 
644   PetscFunctionBegin;
645   PetscCall(PetscIntCast(ncoo, &ncoo_i));
646   PetscCall(PetscLayoutSetUp(A->rmap));
647   PetscCall(PetscLayoutSetUp(A->cmap));
648   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &preallocator));
649   PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
650   PetscCall(MatSetSizes(preallocator, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
651   PetscCall(MatSetLayouts(preallocator, A->rmap, A->cmap));
652   PetscCall(MatSetUp(preallocator));
653   for (PetscCount n = 0; n < ncoo; n++) PetscCall(MatSetValue(preallocator, coo_i[n], coo_j[n], zero, INSERT_VALUES));
654   PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
655   PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
656   PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, A));
657   PetscCall(MatDestroy(&preallocator));
658   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncoo_i, coo_i, PETSC_COPY_VALUES, &is_coo_i));
659   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncoo_i, coo_j, PETSC_COPY_VALUES, &is_coo_j));
660   PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_coo_i", (PetscObject)is_coo_i));
661   PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_coo_j", (PetscObject)is_coo_j));
662   PetscCall(ISDestroy(&is_coo_i));
663   PetscCall(ISDestroy(&is_coo_j));
664   PetscFunctionReturn(PETSC_SUCCESS);
665 }
666 
667 /*@C
668   MatSetPreallocationCOO - set preallocation for matrices using a coordinate format of the entries with global indices
669 
670   Collective
671 
672   Input Parameters:
673 + A     - matrix being preallocated
674 . ncoo  - number of entries
675 . coo_i - row indices
676 - coo_j - column indices
677 
678   Level: beginner
679 
680   Notes:
681   The indices within `coo_i` and `coo_j` may be modified within this function. The caller should not rely on them
682   having any specific value after this function returns. The arrays can be freed or reused immediately
683   after this function returns.
684 
685   Entries can be repeated, see `MatSetValuesCOO()`. Entries with negative row or column indices are allowed
686   but will be ignored. The corresponding entries in `MatSetValuesCOO()` will be ignored too. Remote entries
687   are allowed and will be properly added or inserted to the matrix, unless the matrix option `MAT_IGNORE_OFF_PROC_ENTRIES`
688   is set, in which case remote entries are ignored, or `MAT_NO_OFF_PROC_ENTRIES` is set, in which case an error will be generated.
689 
690   If you just want to create a sequential AIJ matrix (`MATSEQAIJ`), and your matrix entries in COO format are unique, you can also use
691   `MatCreateSeqAIJFromTriple()`. But that is not recommended for iterative applications.
692 
693 .seealso: [](ch_matrices), `Mat`, `MatSetValuesCOO()`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`,
694           `MatMPIBAIJSetPreallocation()`, `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`, `MatSetPreallocationCOOLocal()`,
695           `DMSetMatrixPreallocateSkip()`, `MatCreateSeqAIJFromTriple()`
696 @*/
697 PetscErrorCode MatSetPreallocationCOO(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
698 {
699   PetscErrorCode (*f)(Mat, PetscCount, PetscInt[], PetscInt[]) = NULL;
700 
701   PetscFunctionBegin;
702   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
703   PetscValidType(A, 1);
704   if (ncoo) PetscAssertPointer(coo_i, 3);
705   if (ncoo) PetscAssertPointer(coo_j, 4);
706   PetscCall(PetscLayoutSetUp(A->rmap));
707   PetscCall(PetscLayoutSetUp(A->cmap));
708   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetPreallocationCOO_C", &f));
709 
710   PetscCall(PetscLogEventBegin(MAT_PreallCOO, A, 0, 0, 0));
711   if (f) {
712     PetscCall((*f)(A, ncoo, coo_i, coo_j));
713   } else { /* allow fallback, very slow */
714     PetscCall(MatSetPreallocationCOO_Basic(A, ncoo, coo_i, coo_j));
715   }
716   PetscCall(PetscLogEventEnd(MAT_PreallCOO, A, 0, 0, 0));
717   A->preallocated = PETSC_TRUE;
718   A->nonzerostate++;
719   PetscFunctionReturn(PETSC_SUCCESS);
720 }
721 
722 /*@C
723   MatSetPreallocationCOOLocal - set preallocation for matrices using a coordinate format of the entries with local indices
724 
725   Collective
726 
727   Input Parameters:
728 + A     - matrix being preallocated
729 . ncoo  - number of entries
730 . coo_i - row indices (local numbering; may be modified)
731 - coo_j - column indices (local numbering; may be modified)
732 
733   Level: beginner
734 
735   Notes:
736   The local indices are translated using the local to global mapping, thus `MatSetLocalToGlobalMapping()` must have been
737   called prior to this function. For matrices created with `DMCreateMatrix()` the local to global mapping is often already provided.
738 
739   The indices `coo_i` and `coo_j` may be modified within this function. They might be translated to corresponding global
740   indices, but the caller should not rely on them having any specific value after this function returns. The arrays
741   can be freed or reused immediately after this function returns.
742 
743   Entries can be repeated, see `MatSetValuesCOO()`. Entries with negative row or column indices are allowed
744   but will be ignored. The corresponding entries in `MatSetValuesCOO()` will be ignored too. Remote entries
745   are allowed and will be properly added or inserted to the matrix.
746 
747 .seealso: [](ch_matrices), `Mat`, `MatSetValuesCOO()`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`,
748           `MatMPIBAIJSetPreallocation()`, `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`, `MatSetPreallocationCOO()`,
749           `DMSetMatrixPreallocateSkip()`
750 @*/
751 PetscErrorCode MatSetPreallocationCOOLocal(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
752 {
753   PetscErrorCode (*f)(Mat, PetscCount, PetscInt[], PetscInt[]) = NULL;
754 
755   PetscFunctionBegin;
756   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
757   PetscValidType(A, 1);
758   if (ncoo) PetscAssertPointer(coo_i, 3);
759   if (ncoo) PetscAssertPointer(coo_j, 4);
760   PetscCall(PetscLayoutSetUp(A->rmap));
761   PetscCall(PetscLayoutSetUp(A->cmap));
762 
763   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", &f));
764   if (f) {
765     PetscCall((*f)(A, ncoo, coo_i, coo_j));
766     A->nonzerostate++;
767   } else {
768     PetscInt               ncoo_i;
769     ISLocalToGlobalMapping ltog_row, ltog_col;
770 
771     PetscCall(MatGetLocalToGlobalMapping(A, &ltog_row, &ltog_col));
772     if (ltog_row) {
773       PetscCall(PetscIntCast(ncoo, &ncoo_i));
774       PetscCall(ISLocalToGlobalMappingApply(ltog_row, ncoo_i, coo_i, coo_i));
775     }
776     if (ltog_col) {
777       PetscCall(PetscIntCast(ncoo, &ncoo_i));
778       PetscCall(ISLocalToGlobalMappingApply(ltog_col, ncoo_i, coo_j, coo_j));
779     }
780     PetscCall(MatSetPreallocationCOO(A, ncoo, coo_i, coo_j));
781   }
782   A->preallocated = PETSC_TRUE;
783   PetscFunctionReturn(PETSC_SUCCESS);
784 }
785 
786 /*@
787   MatSetValuesCOO - set values at once in a matrix preallocated using `MatSetPreallocationCOO()`
788 
789   Collective
790 
791   Input Parameters:
792 + A     - matrix being preallocated
793 . coo_v - the matrix values (can be `NULL`)
794 - imode - the insert mode
795 
796   Level: beginner
797 
798   Notes:
799   The values must follow the order of the indices prescribed with `MatSetPreallocationCOO()` or `MatSetPreallocationCOOLocal()`.
800 
801   When repeated entries are specified in the COO indices the `coo_v` values are first properly summed, regardless of the value of imode.
802   The imode flag indicates if coo_v must be added to the current values of the matrix (`ADD_VALUES`) or overwritten (`INSERT_VALUES`).
803 
804   `MatAssemblyBegin()` and `MatAssemblyEnd()` do not need to be called after this routine. It automatically handles the assembly process.
805 
806 .seealso: [](ch_matrices), `Mat`, `MatSetPreallocationCOO()`, `MatSetPreallocationCOOLocal()`, `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
807 @*/
808 PetscErrorCode MatSetValuesCOO(Mat A, const PetscScalar coo_v[], InsertMode imode)
809 {
810   PetscErrorCode (*f)(Mat, const PetscScalar[], InsertMode) = NULL;
811   PetscBool oldFlg;
812 
813   PetscFunctionBegin;
814   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
815   PetscValidType(A, 1);
816   MatCheckPreallocated(A, 1);
817   PetscValidLogicalCollectiveEnum(A, imode, 3);
818   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetValuesCOO_C", &f));
819   PetscCall(PetscLogEventBegin(MAT_SetVCOO, A, 0, 0, 0));
820   if (f) {
821     PetscCall((*f)(A, coo_v, imode)); // all known COO implementations do not use MatStash. They do their own off-proc communication
822     PetscCall(MatGetOption(A, MAT_NO_OFF_PROC_ENTRIES, &oldFlg));
823     PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); // set A->nooffprocentries to avoid costly MatStash scatter in MatAssembly
824   } else {
825     PetscCall(MatSetValuesCOO_Basic(A, coo_v, imode)); // fall back to MatSetValues, which might use MatStash
826   }
827   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
828   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
829   if (f) PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, oldFlg));
830   PetscCall(PetscLogEventEnd(MAT_SetVCOO, A, 0, 0, 0));
831   PetscFunctionReturn(PETSC_SUCCESS);
832 }
833 
834 /*@
835   MatSetBindingPropagates - Sets whether the state of being bound to the CPU for a GPU matrix type propagates to child and some other associated objects
836 
837   Input Parameters:
838 + A   - the matrix
839 - flg - flag indicating whether the boundtocpu flag should be propagated
840 
841   Level: developer
842 
843   Notes:
844   If the value of flg is set to true, the following will occur
845 +   `MatCreateSubMatrices()` and `MatCreateRedundantMatrix()` - bind created matrices to CPU if the input matrix is bound to the CPU.
846 -   `MatCreateVecs()` - bind created vectors to CPU if the input matrix is bound to the CPU.
847 
848   The bindingpropagates flag itself is also propagated by the above routines.
849 
850   Developer Notes:
851   If the fine-scale `DMDA` has the `-dm_bind_below` option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()`
852   on the restriction/interpolation operator to set the bindingpropagates flag to true.
853 
854 .seealso: [](ch_matrices), `Mat`, `VecSetBindingPropagates()`, `MatGetBindingPropagates()`
855 @*/
856 PetscErrorCode MatSetBindingPropagates(Mat A, PetscBool flg)
857 {
858   PetscFunctionBegin;
859   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
860 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
861   A->bindingpropagates = flg;
862 #endif
863   PetscFunctionReturn(PETSC_SUCCESS);
864 }
865 
866 /*@
867   MatGetBindingPropagates - Gets whether the state of being bound to the CPU for a GPU matrix type propagates to child and some other associated objects
868 
869   Input Parameter:
870 . A - the matrix
871 
872   Output Parameter:
873 . flg - flag indicating whether the boundtocpu flag will be propagated
874 
875   Level: developer
876 
877 .seealso: [](ch_matrices), `Mat`, `MatSetBindingPropagates()`
878 @*/
879 PetscErrorCode MatGetBindingPropagates(Mat A, PetscBool *flg)
880 {
881   PetscFunctionBegin;
882   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
883   PetscAssertPointer(flg, 2);
884 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
885   *flg = A->bindingpropagates;
886 #else
887   *flg = PETSC_FALSE;
888 #endif
889   PetscFunctionReturn(PETSC_SUCCESS);
890 }
891