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