xref: /petsc/src/mat/utils/gcreate.c (revision 4df4a32cb8db0b7b88394c85cd73c68458309a1d) !
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;
283 
284   PetscFunctionBegin;
285   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
286 
287   PetscObjectOptionsBegin((PetscObject)B);
288 
289   if (B->rmap->bs < 0) {
290     PetscInt newbs = -1;
291     PetscCall(PetscOptionsInt("-mat_block_size", "Set the blocksize used to store the matrix", "MatSetBlockSize", newbs, &newbs, &flg));
292     if (flg) {
293       PetscCall(PetscLayoutSetBlockSize(B->rmap, newbs));
294       PetscCall(PetscLayoutSetBlockSize(B->cmap, newbs));
295     }
296   }
297 
298   PetscCall(PetscOptionsFList("-mat_type", "Matrix type", "MatSetType", MatList, deft, type, 256, &flg));
299   if (flg) {
300     PetscCall(MatSetType(B, type));
301   } else if (!((PetscObject)B)->type_name) {
302     PetscCall(MatSetType(B, deft));
303   }
304 
305   PetscCall(PetscOptionsName("-mat_is_symmetric", "Checks if mat is symmetric on MatAssemblyEnd()", "MatIsSymmetric", &B->checksymmetryonassembly));
306   PetscCall(PetscOptionsReal("-mat_is_symmetric", "Checks if mat is symmetric on MatAssemblyEnd()", "MatIsSymmetric", B->checksymmetrytol, &B->checksymmetrytol, NULL));
307   PetscCall(PetscOptionsBool("-mat_null_space_test", "Checks if provided null space is correct in MatAssemblyEnd()", "MatSetNullSpaceTest", B->checknullspaceonassembly, &B->checknullspaceonassembly, NULL));
308   PetscCall(PetscOptionsBool("-mat_error_if_failure", "Generate an error if an error occurs when factoring the matrix", "MatSetErrorIfFailure", B->erroriffailure, &B->erroriffailure, NULL));
309 
310   PetscTryTypeMethod(B, setfromoptions, PetscOptionsObject);
311 
312   flg = PETSC_FALSE;
313   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));
314   if (set) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, flg));
315   flg = PETSC_FALSE;
316   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));
317   if (set) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, flg));
318   flg = PETSC_FALSE;
319   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));
320   if (set) PetscCall(MatSetOption(B, MAT_IGNORE_ZERO_ENTRIES, flg));
321 
322   flg = PETSC_FALSE;
323   PetscCall(PetscOptionsBool("-mat_form_explicit_transpose", "Hint to form an explicit transpose for operations like MatMultTranspose", "MatSetOption", flg, &flg, &set));
324   if (set) PetscCall(MatSetOption(B, MAT_FORM_EXPLICIT_TRANSPOSE, flg));
325 
326   /* Bind to CPU if below a user-specified size threshold.
327    * This perhaps belongs in the options for the GPU Mat types, but MatBindToCPU() does nothing when called on non-GPU types,
328    * and putting it here makes is more maintainable than duplicating this for all. */
329   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));
330   if (flg && B->rmap->n < bind_below) PetscCall(MatBindToCPU(B, PETSC_TRUE));
331 
332   /* process any options handlers added with PetscObjectAddOptionsHandler() */
333   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)B, PetscOptionsObject));
334   PetscOptionsEnd();
335   PetscFunctionReturn(PETSC_SUCCESS);
336 }
337 
338 /*@
339   MatXAIJSetPreallocation - set preallocation for serial and parallel `MATAIJ`, `MATBAIJ`, and `MATSBAIJ` matrices and their unassembled versions.
340 
341   Collective
342 
343   Input Parameters:
344 + A     - matrix being preallocated
345 . bs    - block size
346 . dnnz  - number of nonzero column blocks per block row of diagonal part of parallel matrix
347 . onnz  - number of nonzero column blocks per block row of off-diagonal part of parallel matrix
348 . dnnzu - number of nonzero column blocks per block row of upper-triangular part of diagonal part of parallel matrix
349 - onnzu - number of nonzero column blocks per block row of upper-triangular part of off-diagonal part of parallel matrix
350 
351   Level: beginner
352 
353 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`, `MatMPIBAIJSetPreallocation()`,
354           `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`,
355           `PetscSplitOwnership()`
356 @*/
357 PetscErrorCode MatXAIJSetPreallocation(Mat A, PetscInt bs, const PetscInt dnnz[], const PetscInt onnz[], const PetscInt dnnzu[], const PetscInt onnzu[])
358 {
359   PetscInt  cbs;
360   PetscBool aij, is, hyp;
361 
362   PetscFunctionBegin;
363   if (bs != PETSC_DECIDE) { /* don't mess with an already set block size */
364     PetscCall(MatSetBlockSize(A, bs));
365   }
366   PetscCall(PetscLayoutSetUp(A->rmap));
367   PetscCall(PetscLayoutSetUp(A->cmap));
368   PetscCall(MatGetBlockSizes(A, &bs, &cbs));
369   /* these routines assumes bs == cbs, this should be checked somehow */
370   PetscCall(MatSeqBAIJSetPreallocation(A, bs, 0, dnnz));
371   PetscCall(MatMPIBAIJSetPreallocation(A, bs, 0, dnnz, 0, onnz));
372   PetscCall(MatSeqSBAIJSetPreallocation(A, bs, 0, dnnzu));
373   PetscCall(MatMPISBAIJSetPreallocation(A, bs, 0, dnnzu, 0, onnzu));
374   /*
375     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
376     good before going on with it.
377   */
378   PetscCall(PetscObjectHasFunction((PetscObject)A, "MatMPIAIJSetPreallocation_C", &aij));
379   PetscCall(PetscObjectHasFunction((PetscObject)A, "MatISSetPreallocation_C", &is));
380   PetscCall(PetscObjectHasFunction((PetscObject)A, "MatHYPRESetPreallocation_C", &hyp));
381   if (!aij && !is && !hyp) PetscCall(PetscObjectHasFunction((PetscObject)A, "MatSeqAIJSetPreallocation_C", &aij));
382   if (aij || is || hyp) {
383     if (bs == cbs && bs == 1) {
384       PetscCall(MatSeqAIJSetPreallocation(A, 0, dnnz));
385       PetscCall(MatMPIAIJSetPreallocation(A, 0, dnnz, 0, onnz));
386       PetscCall(MatISSetPreallocation(A, 0, dnnz, 0, onnz));
387 #if defined(PETSC_HAVE_HYPRE)
388       PetscCall(MatHYPRESetPreallocation(A, 0, dnnz, 0, onnz));
389 #endif
390     } else { /* Convert block-row precallocation to scalar-row */
391       PetscInt i, m, *sdnnz, *sonnz;
392       PetscCall(MatGetLocalSize(A, &m, NULL));
393       PetscCall(PetscMalloc2((!!dnnz) * m, &sdnnz, (!!onnz) * m, &sonnz));
394       for (i = 0; i < m; i++) {
395         if (dnnz) sdnnz[i] = dnnz[i / bs] * cbs;
396         if (onnz) sonnz[i] = onnz[i / bs] * cbs;
397       }
398       PetscCall(MatSeqAIJSetPreallocation(A, 0, dnnz ? sdnnz : NULL));
399       PetscCall(MatMPIAIJSetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
400       PetscCall(MatISSetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
401 #if defined(PETSC_HAVE_HYPRE)
402       PetscCall(MatHYPRESetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
403 #endif
404       PetscCall(PetscFree2(sdnnz, sonnz));
405     }
406   }
407   PetscFunctionReturn(PETSC_SUCCESS);
408 }
409 
410 /*@C
411   MatHeaderMerge - Merges some information from the header of `C` to `A`; the `C` object is then destroyed
412 
413   Collective, No Fortran Support
414 
415   Input Parameters:
416 + A - a `Mat` being merged into
417 - C - the `Mat` providing the merge information
418 
419   Level: developer
420 
421   Notes:
422   `A` and `C` must be of the same type.
423   The object list and query function list in `A` are retained, as well as the object name, and prefix.
424   The object state of `A` is increased by 1.
425 
426   Developer Note:
427   This is somewhat different from `MatHeaderReplace()`, it would be nice to merge the code
428 
429 .seealso: `Mat`, `MatHeaderReplace()`
430  @*/
431 PetscErrorCode MatHeaderMerge(Mat A, Mat *C)
432 {
433   PetscInt          refct;
434   PetscOps          Abops;
435   struct _MatOps    Aops;
436   char             *mtype, *mname, *mprefix;
437   Mat_Product      *product;
438   Mat_Redundant    *redundant;
439   PetscObjectState  state;
440   PetscObjectList   olist;
441   PetscFunctionList qlist;
442 
443   PetscFunctionBegin;
444   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
445   PetscValidHeaderSpecific(*C, MAT_CLASSID, 2);
446   if (A == *C) PetscFunctionReturn(PETSC_SUCCESS);
447   PetscCheckSameTypeAndComm(A, 1, *C, 2);
448   /* save the parts of A we need */
449   Abops     = ((PetscObject)A)->bops[0];
450   Aops      = A->ops[0];
451   refct     = ((PetscObject)A)->refct;
452   mtype     = ((PetscObject)A)->type_name;
453   mname     = ((PetscObject)A)->name;
454   state     = ((PetscObject)A)->state;
455   mprefix   = ((PetscObject)A)->prefix;
456   product   = A->product;
457   redundant = A->redundant;
458   qlist     = ((PetscObject)A)->qlist;
459   olist     = ((PetscObject)A)->olist;
460 
461   /* zero these so the destroy below does not free them */
462   ((PetscObject)A)->type_name = NULL;
463   ((PetscObject)A)->name      = NULL;
464   ((PetscObject)A)->qlist     = NULL;
465   ((PetscObject)A)->olist     = NULL;
466 
467   /*
468      free all the interior data structures from mat
469      cannot use PetscUseTypeMethod(A,destroy); because compiler
470      thinks it may print NULL type_name and name
471   */
472   PetscTryTypeMethod(A, destroy);
473 
474   PetscCall(PetscFree(A->defaultvectype));
475   PetscCall(PetscFree(A->defaultrandtype));
476   PetscCall(PetscLayoutDestroy(&A->rmap));
477   PetscCall(PetscLayoutDestroy(&A->cmap));
478   PetscCall(PetscComposedQuantitiesDestroy((PetscObject)A));
479 
480   /* copy C over to A */
481   PetscCall(PetscFree(A->factorprefix));
482   PetscCall(PetscMemcpy(A, *C, sizeof(struct _p_Mat)));
483 
484   /* return the parts of A we saved */
485   ((PetscObject)A)->bops[0]   = Abops;
486   A->ops[0]                   = Aops;
487   ((PetscObject)A)->refct     = refct;
488   ((PetscObject)A)->type_name = mtype;
489   ((PetscObject)A)->name      = mname;
490   ((PetscObject)A)->prefix    = mprefix;
491   ((PetscObject)A)->state     = state + 1;
492   A->product                  = product;
493   A->redundant                = redundant;
494 
495   /* Append the saved lists */
496   PetscCall(PetscFunctionListDuplicate(qlist, &((PetscObject)A)->qlist));
497   PetscCall(PetscObjectListDuplicate(olist, &((PetscObject)A)->olist));
498   PetscCall(PetscFunctionListDestroy(&qlist));
499   PetscCall(PetscObjectListDestroy(&olist));
500 
501   /* since these two are copied into A we do not want them destroyed in C */
502   ((PetscObject)*C)->qlist = NULL;
503   ((PetscObject)*C)->olist = NULL;
504   PetscCall(PetscHeaderDestroy(C));
505   PetscFunctionReturn(PETSC_SUCCESS);
506 }
507 
508 /*@
509   MatHeaderReplace - Replaces the internal data of matrix `A` by the internal data of matrix `C` while deleting the outer wrapper of `C`
510 
511   Input Parameters:
512 + A - a `Mat` whose internal data is to be replaced
513 - C - the `Mat` providing new internal data for `A`
514 
515   Level: advanced
516 
517   Example Usage\:
518 .vb
519   Mat C;
520   MatCreateSeqAIJWithArrays(..., &C);
521   MatHeaderReplace(A, &C);
522   // C has been destroyed and A contains the matrix entries of C
523 .ve
524 
525   Note:
526   This can be used inside a function provided to `SNESSetJacobian()`, `TSSetRHSJacobian()`, or `TSSetIJacobian()` in cases where the user code
527   computes an entirely new sparse matrix  (generally with a different matrix nonzero structure/pattern) for each Newton update.
528   It is usually better to reuse the matrix nonzero structure of `A` instead of constructing an entirely new one.
529 
530   Developer Note:
531   This is somewhat different from `MatHeaderMerge()` it would be nice to merge the code
532 
533 .seealso: `Mat`, `MatHeaderMerge()`
534  @*/
535 PetscErrorCode MatHeaderReplace(Mat A, Mat *C)
536 {
537   PetscInt         refct;
538   PetscObjectState state;
539   struct _p_Mat    buffer;
540   MatStencilInfo   stencil;
541 
542   PetscFunctionBegin;
543   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
544   PetscValidHeaderSpecific(*C, MAT_CLASSID, 2);
545   if (A == *C) PetscFunctionReturn(PETSC_SUCCESS);
546   PetscCheckSameComm(A, 1, *C, 2);
547   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);
548 
549   /* swap C and A */
550   refct   = ((PetscObject)A)->refct;
551   state   = ((PetscObject)A)->state;
552   stencil = A->stencil;
553   PetscCall(PetscMemcpy(&buffer, A, sizeof(struct _p_Mat)));
554   PetscCall(PetscMemcpy(A, *C, sizeof(struct _p_Mat)));
555   PetscCall(PetscMemcpy(*C, &buffer, sizeof(struct _p_Mat)));
556   ((PetscObject)A)->refct = refct;
557   ((PetscObject)A)->state = state + 1;
558   A->stencil              = stencil;
559 
560   ((PetscObject)*C)->refct = 1;
561   PetscCall(MatDestroy(C));
562   PetscFunctionReturn(PETSC_SUCCESS);
563 }
564 
565 /*@
566   MatBindToCPU - marks a matrix to temporarily stay on the CPU and perform computations on the CPU
567 
568   Logically Collective
569 
570   Input Parameters:
571 + A   - the matrix
572 - flg - bind to the CPU if value of `PETSC_TRUE`
573 
574   Level: intermediate
575 
576 .seealso: [](ch_matrices), `Mat`, `MatBoundToCPU()`
577 @*/
578 PetscErrorCode MatBindToCPU(Mat A, PetscBool flg)
579 {
580   PetscFunctionBegin;
581   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
582   PetscValidLogicalCollectiveBool(A, flg, 2);
583 #if defined(PETSC_HAVE_DEVICE)
584   if (A->boundtocpu == flg) PetscFunctionReturn(PETSC_SUCCESS);
585   A->boundtocpu = flg;
586   PetscTryTypeMethod(A, bindtocpu, flg);
587 #endif
588   PetscFunctionReturn(PETSC_SUCCESS);
589 }
590 
591 /*@
592   MatBoundToCPU - query if a matrix is bound to the CPU
593 
594   Input Parameter:
595 . A - the matrix
596 
597   Output Parameter:
598 . flg - the logical flag
599 
600   Level: intermediate
601 
602 .seealso: [](ch_matrices), `Mat`, `MatBindToCPU()`
603 @*/
604 PetscErrorCode MatBoundToCPU(Mat A, PetscBool *flg)
605 {
606   PetscFunctionBegin;
607   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
608   PetscAssertPointer(flg, 2);
609 #if defined(PETSC_HAVE_DEVICE)
610   *flg = A->boundtocpu;
611 #else
612   *flg = PETSC_TRUE;
613 #endif
614   PetscFunctionReturn(PETSC_SUCCESS);
615 }
616 
617 PetscErrorCode MatSetValuesCOO_Basic(Mat A, const PetscScalar coo_v[], InsertMode imode)
618 {
619   IS              is_coo_i, is_coo_j;
620   const PetscInt *coo_i, *coo_j;
621   PetscInt        n, n_i, n_j;
622   PetscScalar     zero = 0.;
623 
624   PetscFunctionBegin;
625   PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_coo_i", (PetscObject *)&is_coo_i));
626   PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_coo_j", (PetscObject *)&is_coo_j));
627   PetscCheck(is_coo_i, PetscObjectComm((PetscObject)A), PETSC_ERR_COR, "Missing coo_i IS");
628   PetscCheck(is_coo_j, PetscObjectComm((PetscObject)A), PETSC_ERR_COR, "Missing coo_j IS");
629   PetscCall(ISGetLocalSize(is_coo_i, &n_i));
630   PetscCall(ISGetLocalSize(is_coo_j, &n_j));
631   PetscCheck(n_i == n_j, PETSC_COMM_SELF, PETSC_ERR_COR, "Wrong local size %" PetscInt_FMT " != %" PetscInt_FMT, n_i, n_j);
632   PetscCall(ISGetIndices(is_coo_i, &coo_i));
633   PetscCall(ISGetIndices(is_coo_j, &coo_j));
634   if (imode != ADD_VALUES) PetscCall(MatZeroEntries(A));
635   for (n = 0; n < n_i; n++) PetscCall(MatSetValue(A, coo_i[n], coo_j[n], coo_v ? coo_v[n] : zero, ADD_VALUES));
636   PetscCall(ISRestoreIndices(is_coo_i, &coo_i));
637   PetscCall(ISRestoreIndices(is_coo_j, &coo_j));
638   PetscFunctionReturn(PETSC_SUCCESS);
639 }
640 
641 PetscErrorCode MatSetPreallocationCOO_Basic(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
642 {
643   Mat         preallocator;
644   IS          is_coo_i, is_coo_j;
645   PetscInt    ncoo_i;
646   PetscScalar zero = 0.0;
647 
648   PetscFunctionBegin;
649   PetscCall(PetscIntCast(ncoo, &ncoo_i));
650   PetscCall(PetscLayoutSetUp(A->rmap));
651   PetscCall(PetscLayoutSetUp(A->cmap));
652   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &preallocator));
653   PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
654   PetscCall(MatSetSizes(preallocator, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
655   PetscCall(MatSetLayouts(preallocator, A->rmap, A->cmap));
656   PetscCall(MatSetUp(preallocator));
657   for (PetscCount n = 0; n < ncoo; n++) PetscCall(MatSetValue(preallocator, coo_i[n], coo_j[n], zero, INSERT_VALUES));
658   PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
659   PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
660   PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, A));
661   PetscCall(MatDestroy(&preallocator));
662   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncoo_i, coo_i, PETSC_COPY_VALUES, &is_coo_i));
663   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncoo_i, coo_j, PETSC_COPY_VALUES, &is_coo_j));
664   PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_coo_i", (PetscObject)is_coo_i));
665   PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_coo_j", (PetscObject)is_coo_j));
666   PetscCall(ISDestroy(&is_coo_i));
667   PetscCall(ISDestroy(&is_coo_j));
668   PetscFunctionReturn(PETSC_SUCCESS);
669 }
670 
671 /*@C
672   MatSetPreallocationCOO - set preallocation for matrices using a coordinate format of the entries with global indices
673 
674   Collective
675 
676   Input Parameters:
677 + A     - matrix being preallocated
678 . ncoo  - number of entries
679 . coo_i - row indices
680 - coo_j - column indices
681 
682   Level: beginner
683 
684   Notes:
685   The indices within `coo_i` and `coo_j` may be modified within this function. The caller should not rely on them
686   having any specific value after this function returns. The arrays can be freed or reused immediately
687   after this function returns.
688 
689   Entries can be repeated, see `MatSetValuesCOO()`. Entries with negative row or column indices are allowed
690   but will be ignored. The corresponding entries in `MatSetValuesCOO()` will be ignored too. Remote entries
691   are allowed and will be properly added or inserted to the matrix, unless the matrix option `MAT_IGNORE_OFF_PROC_ENTRIES`
692   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.
693 
694   If you just want to create a sequential AIJ matrix (`MATSEQAIJ`), and your matrix entries in COO format are unique, you can also use
695   `MatCreateSeqAIJFromTriple()`. But that is not recommended for iterative applications.
696 
697 .seealso: [](ch_matrices), `Mat`, `MatSetValuesCOO()`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`,
698           `MatMPIBAIJSetPreallocation()`, `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`, `MatSetPreallocationCOOLocal()`,
699           `DMSetMatrixPreallocateSkip()`, `MatCreateSeqAIJFromTriple()`
700 @*/
701 PetscErrorCode MatSetPreallocationCOO(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
702 {
703   PetscErrorCode (*f)(Mat, PetscCount, PetscInt[], PetscInt[]) = NULL;
704 
705   PetscFunctionBegin;
706   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
707   PetscValidType(A, 1);
708   if (ncoo) PetscAssertPointer(coo_i, 3);
709   if (ncoo) PetscAssertPointer(coo_j, 4);
710   PetscCall(PetscLayoutSetUp(A->rmap));
711   PetscCall(PetscLayoutSetUp(A->cmap));
712   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetPreallocationCOO_C", &f));
713 
714   PetscCall(PetscLogEventBegin(MAT_PreallCOO, A, 0, 0, 0));
715   if (f) {
716     PetscCall((*f)(A, ncoo, coo_i, coo_j));
717   } else { /* allow fallback, very slow */
718     PetscCall(MatSetPreallocationCOO_Basic(A, ncoo, coo_i, coo_j));
719   }
720   PetscCall(PetscLogEventEnd(MAT_PreallCOO, A, 0, 0, 0));
721   A->preallocated = PETSC_TRUE;
722   A->nonzerostate++;
723   PetscFunctionReturn(PETSC_SUCCESS);
724 }
725 
726 /*@C
727   MatSetPreallocationCOOLocal - set preallocation for matrices using a coordinate format of the entries with local indices
728 
729   Collective
730 
731   Input Parameters:
732 + A     - matrix being preallocated
733 . ncoo  - number of entries
734 . coo_i - row indices (local numbering; may be modified)
735 - coo_j - column indices (local numbering; may be modified)
736 
737   Level: beginner
738 
739   Notes:
740   The local indices are translated using the local to global mapping, thus `MatSetLocalToGlobalMapping()` must have been
741   called prior to this function. For matrices created with `DMCreateMatrix()` the local to global mapping is often already provided.
742 
743   The indices `coo_i` and `coo_j` may be modified within this function. They might be translated to corresponding global
744   indices, but the caller should not rely on them having any specific value after this function returns. The arrays
745   can be freed or reused immediately after this function returns.
746 
747   Entries can be repeated, see `MatSetValuesCOO()`. Entries with negative row or column indices are allowed
748   but will be ignored. The corresponding entries in `MatSetValuesCOO()` will be ignored too. Remote entries
749   are allowed and will be properly added or inserted to the matrix.
750 
751 .seealso: [](ch_matrices), `Mat`, `MatSetValuesCOO()`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`,
752           `MatMPIBAIJSetPreallocation()`, `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`, `MatSetPreallocationCOO()`,
753           `DMSetMatrixPreallocateSkip()`
754 @*/
755 PetscErrorCode MatSetPreallocationCOOLocal(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
756 {
757   PetscErrorCode (*f)(Mat, PetscCount, PetscInt[], PetscInt[]) = NULL;
758 
759   PetscFunctionBegin;
760   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
761   PetscValidType(A, 1);
762   if (ncoo) PetscAssertPointer(coo_i, 3);
763   if (ncoo) PetscAssertPointer(coo_j, 4);
764   PetscCall(PetscLayoutSetUp(A->rmap));
765   PetscCall(PetscLayoutSetUp(A->cmap));
766 
767   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", &f));
768   if (f) {
769     PetscCall((*f)(A, ncoo, coo_i, coo_j));
770     A->nonzerostate++;
771   } else {
772     PetscInt               ncoo_i;
773     ISLocalToGlobalMapping ltog_row, ltog_col;
774 
775     PetscCall(MatGetLocalToGlobalMapping(A, &ltog_row, &ltog_col));
776     if (ltog_row) {
777       PetscCall(PetscIntCast(ncoo, &ncoo_i));
778       PetscCall(ISLocalToGlobalMappingApply(ltog_row, ncoo_i, coo_i, coo_i));
779     }
780     if (ltog_col) {
781       PetscCall(PetscIntCast(ncoo, &ncoo_i));
782       PetscCall(ISLocalToGlobalMappingApply(ltog_col, ncoo_i, coo_j, coo_j));
783     }
784     PetscCall(MatSetPreallocationCOO(A, ncoo, coo_i, coo_j));
785   }
786   A->preallocated = PETSC_TRUE;
787   PetscFunctionReturn(PETSC_SUCCESS);
788 }
789 
790 /*@
791   MatSetValuesCOO - set values at once in a matrix preallocated using `MatSetPreallocationCOO()`
792 
793   Collective
794 
795   Input Parameters:
796 + A     - matrix being preallocated
797 . coo_v - the matrix values (can be `NULL`)
798 - imode - the insert mode
799 
800   Level: beginner
801 
802   Notes:
803   The values must follow the order of the indices prescribed with `MatSetPreallocationCOO()` or `MatSetPreallocationCOOLocal()`.
804 
805   When repeated entries are specified in the COO indices the `coo_v` values are first properly summed, regardless of the value of imode.
806   The imode flag indicates if coo_v must be added to the current values of the matrix (`ADD_VALUES`) or overwritten (`INSERT_VALUES`).
807 
808   `MatAssemblyBegin()` and `MatAssemblyEnd()` do not need to be called after this routine. It automatically handles the assembly process.
809 
810 .seealso: [](ch_matrices), `Mat`, `MatSetPreallocationCOO()`, `MatSetPreallocationCOOLocal()`, `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
811 @*/
812 PetscErrorCode MatSetValuesCOO(Mat A, const PetscScalar coo_v[], InsertMode imode)
813 {
814   PetscErrorCode (*f)(Mat, const PetscScalar[], InsertMode) = NULL;
815   PetscBool oldFlg;
816 
817   PetscFunctionBegin;
818   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
819   PetscValidType(A, 1);
820   MatCheckPreallocated(A, 1);
821   PetscValidLogicalCollectiveEnum(A, imode, 3);
822   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetValuesCOO_C", &f));
823   PetscCall(PetscLogEventBegin(MAT_SetVCOO, A, 0, 0, 0));
824   if (f) {
825     PetscCall((*f)(A, coo_v, imode)); // all known COO implementations do not use MatStash. They do their own off-proc communication
826     PetscCall(MatGetOption(A, MAT_NO_OFF_PROC_ENTRIES, &oldFlg));
827     PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); // set A->nooffprocentries to avoid costly MatStash scatter in MatAssembly
828   } else {
829     PetscCall(MatSetValuesCOO_Basic(A, coo_v, imode)); // fall back to MatSetValues, which might use MatStash
830   }
831   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
832   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
833   if (f) PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, oldFlg));
834   PetscCall(PetscLogEventEnd(MAT_SetVCOO, A, 0, 0, 0));
835   PetscFunctionReturn(PETSC_SUCCESS);
836 }
837 
838 /*@
839   MatSetBindingPropagates - Sets whether the state of being bound to the CPU for a GPU matrix type propagates to child and some other associated objects
840 
841   Input Parameters:
842 + A   - the matrix
843 - flg - flag indicating whether the boundtocpu flag should be propagated
844 
845   Level: developer
846 
847   Notes:
848   If the value of flg is set to true, the following will occur
849 +   `MatCreateSubMatrices()` and `MatCreateRedundantMatrix()` - bind created matrices to CPU if the input matrix is bound to the CPU.
850 -   `MatCreateVecs()` - bind created vectors to CPU if the input matrix is bound to the CPU.
851 
852   The bindingpropagates flag itself is also propagated by the above routines.
853 
854   Developer Notes:
855   If the fine-scale `DMDA` has the `-dm_bind_below` option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()`
856   on the restriction/interpolation operator to set the bindingpropagates flag to true.
857 
858 .seealso: [](ch_matrices), `Mat`, `VecSetBindingPropagates()`, `MatGetBindingPropagates()`
859 @*/
860 PetscErrorCode MatSetBindingPropagates(Mat A, PetscBool flg)
861 {
862   PetscFunctionBegin;
863   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
864 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
865   A->bindingpropagates = flg;
866 #endif
867   PetscFunctionReturn(PETSC_SUCCESS);
868 }
869 
870 /*@
871   MatGetBindingPropagates - Gets whether the state of being bound to the CPU for a GPU matrix type propagates to child and some other associated objects
872 
873   Input Parameter:
874 . A - the matrix
875 
876   Output Parameter:
877 . flg - flag indicating whether the boundtocpu flag will be propagated
878 
879   Level: developer
880 
881 .seealso: [](ch_matrices), `Mat`, `MatSetBindingPropagates()`
882 @*/
883 PetscErrorCode MatGetBindingPropagates(Mat A, PetscBool *flg)
884 {
885   PetscFunctionBegin;
886   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
887   PetscAssertPointer(flg, 2);
888 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
889   *flg = A->bindingpropagates;
890 #else
891   *flg = PETSC_FALSE;
892 #endif
893   PetscFunctionReturn(PETSC_SUCCESS);
894 }
895