xref: /petsc/src/mat/utils/gcreate.c (revision 2da392cc7c10228af19ad9843ce5155178acb644)
1 
2 #include <petsc/private/matimpl.h>       /*I "petscmat.h"  I*/
3 
4 PETSC_INTERN PetscErrorCode MatSetBlockSizes_Default(Mat mat,PetscInt rbs, PetscInt cbs)
5 {
6   PetscFunctionBegin;
7   if (!mat->preallocated) PetscFunctionReturn(0);
8   if (mat->rmap->bs > 0 && mat->rmap->bs != rbs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot change row block size %D to %D\n",mat->rmap->bs,rbs);
9   if (mat->cmap->bs > 0 && mat->cmap->bs != cbs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot change column block size %D to %D\n",mat->cmap->bs,cbs);
10   PetscFunctionReturn(0);
11 }
12 
13 PETSC_INTERN PetscErrorCode MatShift_Basic(Mat Y,PetscScalar a)
14 {
15   PetscErrorCode ierr;
16   PetscInt       i,start,end;
17   PetscScalar    alpha = a;
18   PetscBool      prevoption;
19 
20   PetscFunctionBegin;
21   ierr = MatGetOption(Y,MAT_NO_OFF_PROC_ENTRIES,&prevoption);CHKERRQ(ierr);
22   ierr = MatSetOption(Y,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE);CHKERRQ(ierr);
23   ierr = MatGetOwnershipRange(Y,&start,&end);CHKERRQ(ierr);
24   for (i=start; i<end; i++) {
25     if (i < Y->cmap->N) {
26       ierr = MatSetValues(Y,1,&i,1,&i,&alpha,ADD_VALUES);CHKERRQ(ierr);
27     }
28   }
29   ierr = MatAssemblyBegin(Y,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
30   ierr = MatAssemblyEnd(Y,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
31   ierr = MatSetOption(Y,MAT_NO_OFF_PROC_ENTRIES,prevoption);CHKERRQ(ierr);
32   PetscFunctionReturn(0);
33 }
34 
35 /*@
36    MatCreate - Creates a matrix where the type is determined
37    from either a call to MatSetType() or from the options database
38    with a call to MatSetFromOptions(). The default matrix type is
39    AIJ, using the routines MatCreateSeqAIJ() or MatCreateAIJ()
40    if you do not set a type in the options database. If you never
41    call MatSetType() or MatSetFromOptions() it will generate an
42    error when you try to use the matrix.
43 
44    Collective
45 
46    Input Parameter:
47 .  comm - MPI communicator
48 
49    Output Parameter:
50 .  A - the matrix
51 
52    Options Database Keys:
53 +    -mat_type seqaij   - AIJ type, uses MatCreateSeqAIJ()
54 .    -mat_type mpiaij   - AIJ type, uses MatCreateAIJ()
55 .    -mat_type seqdense - dense type, uses MatCreateSeqDense()
56 .    -mat_type mpidense - dense type, uses MatCreateDense()
57 .    -mat_type seqbaij  - block AIJ type, uses MatCreateSeqBAIJ()
58 -    -mat_type mpibaij  - block AIJ type, uses MatCreateBAIJ()
59 
60    Even More Options Database Keys:
61    See the manpages for particular formats (e.g., MatCreateSeqAIJ())
62    for additional format-specific options.
63 
64    Level: beginner
65 
66 .seealso: MatCreateSeqAIJ(), MatCreateAIJ(),
67           MatCreateSeqDense(), MatCreateDense(),
68           MatCreateSeqBAIJ(), MatCreateBAIJ(),
69           MatCreateSeqSBAIJ(), MatCreateSBAIJ(),
70           MatConvert()
71 @*/
72 PetscErrorCode  MatCreate(MPI_Comm comm,Mat *A)
73 {
74   Mat            B;
75   PetscErrorCode ierr;
76 
77   PetscFunctionBegin;
78   PetscValidPointer(A,2);
79 
80   *A = NULL;
81   ierr = MatInitializePackage();CHKERRQ(ierr);
82 
83   ierr = PetscHeaderCreate(B,MAT_CLASSID,"Mat","Matrix","Mat",comm,MatDestroy,MatView);CHKERRQ(ierr);
84   ierr = PetscLayoutCreate(comm,&B->rmap);CHKERRQ(ierr);
85   ierr = PetscLayoutCreate(comm,&B->cmap);CHKERRQ(ierr);
86   ierr = PetscStrallocpy(VECSTANDARD,&B->defaultvectype);CHKERRQ(ierr);
87 
88   B->congruentlayouts = PETSC_DECIDE;
89   B->preallocated     = PETSC_FALSE;
90   *A                  = B;
91   PetscFunctionReturn(0);
92 }
93 
94 /*@
95    MatSetErrorIfFailure - Causes Mat to generate an error, for example a zero pivot, is detected.
96 
97    Logically Collective on Mat
98 
99    Input Parameters:
100 +  mat -  matrix obtained from MatCreate()
101 -  flg - PETSC_TRUE indicates you want the error generated
102 
103    Level: advanced
104 
105 .seealso: PCSetErrorIfFailure()
106 @*/
107 PetscErrorCode  MatSetErrorIfFailure(Mat mat,PetscBool flg)
108 {
109   PetscFunctionBegin;
110   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
111   PetscValidLogicalCollectiveBool(mat,flg,2);
112   mat->erroriffailure = flg;
113   PetscFunctionReturn(0);
114 }
115 
116 /*@
117   MatSetSizes - Sets the local and global sizes, and checks to determine compatibility
118 
119   Collective on Mat
120 
121   Input Parameters:
122 +  A - the matrix
123 .  m - number of local rows (or PETSC_DECIDE)
124 .  n - number of local columns (or PETSC_DECIDE)
125 .  M - number of global rows (or PETSC_DETERMINE)
126 -  N - number of global columns (or PETSC_DETERMINE)
127 
128    Notes:
129    m (n) and M (N) cannot be both PETSC_DECIDE
130    If one processor calls this with M (N) of PETSC_DECIDE then all processors must, otherwise the program will hang.
131 
132    If PETSC_DECIDE is not used for the arguments 'm' and 'n', then the
133    user must ensure that they are chosen to be compatible with the
134    vectors. To do this, one first considers the matrix-vector product
135    'y = A x'. The 'm' that is used in the above routine must match the
136    local size used in the vector creation routine VecCreateMPI() for 'y'.
137    Likewise, the 'n' used must match that used as the local size in
138    VecCreateMPI() for 'x'.
139 
140    You cannot change the sizes once they have been set.
141 
142    The sizes must be set before MatSetUp() or MatXXXSetPreallocation() is called.
143 
144   Level: beginner
145 
146 .seealso: MatGetSize(), PetscSplitOwnership()
147 @*/
148 PetscErrorCode  MatSetSizes(Mat A, PetscInt m, PetscInt n, PetscInt M, PetscInt N)
149 {
150   PetscFunctionBegin;
151   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
152   PetscValidLogicalCollectiveInt(A,M,4);
153   PetscValidLogicalCollectiveInt(A,N,5);
154   if (M > 0 && m > M) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Local row size %D cannot be larger than global row size %D",m,M);
155   if (N > 0 && n > N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Local column size %D cannot be larger than global column size %D",n,N);
156   if ((A->rmap->n >= 0 && A->rmap->N >= 0) && (A->rmap->n != m || (M > 0 && A->rmap->N != M))) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot change/reset row sizes to %D local %D global after previously setting them to %D local %D global",m,M,A->rmap->n,A->rmap->N);
157   if ((A->cmap->n >= 0 && A->cmap->N >= 0) && (A->cmap->n != n || (N > 0 && A->cmap->N != N))) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot change/reset column sizes to %D local %D global after previously setting them to %D local %D global",n,N,A->cmap->n,A->cmap->N);
158   A->rmap->n = m;
159   A->cmap->n = n;
160   A->rmap->N = M > -1 ? M : A->rmap->N;
161   A->cmap->N = N > -1 ? N : A->cmap->N;
162   PetscFunctionReturn(0);
163 }
164 
165 /*@
166    MatSetFromOptions - Creates a matrix where the type is determined
167    from the options database. Generates a parallel MPI matrix if the
168    communicator has more than one processor.  The default matrix type is
169    AIJ, using the routines MatCreateSeqAIJ() and MatCreateAIJ() if
170    you do not select a type in the options database.
171 
172    Collective on Mat
173 
174    Input Parameter:
175 .  A - the matrix
176 
177    Options Database Keys:
178 +    -mat_type seqaij   - AIJ type, uses MatCreateSeqAIJ()
179 .    -mat_type mpiaij   - AIJ type, uses MatCreateAIJ()
180 .    -mat_type seqdense - dense type, uses MatCreateSeqDense()
181 .    -mat_type mpidense - dense type, uses MatCreateDense()
182 .    -mat_type seqbaij  - block AIJ type, uses MatCreateSeqBAIJ()
183 -    -mat_type mpibaij  - block AIJ type, uses MatCreateBAIJ()
184 
185    Even More Options Database Keys:
186    See the manpages for particular formats (e.g., MatCreateSeqAIJ())
187    for additional format-specific options.
188 
189    Level: beginner
190 
191 .seealso: MatCreateSeqAIJ((), MatCreateAIJ(),
192           MatCreateSeqDense(), MatCreateDense(),
193           MatCreateSeqBAIJ(), MatCreateBAIJ(),
194           MatCreateSeqSBAIJ(), MatCreateSBAIJ(),
195           MatConvert()
196 @*/
197 PetscErrorCode  MatSetFromOptions(Mat B)
198 {
199   PetscErrorCode ierr;
200   const char     *deft = MATAIJ;
201   char           type[256];
202   PetscBool      flg,set;
203 
204   PetscFunctionBegin;
205   PetscValidHeaderSpecific(B,MAT_CLASSID,1);
206 
207   ierr = PetscObjectOptionsBegin((PetscObject)B);CHKERRQ(ierr);
208 
209   if (B->rmap->bs < 0) {
210     PetscInt newbs = -1;
211     ierr = PetscOptionsInt("-mat_block_size","Set the blocksize used to store the matrix","MatSetBlockSize",newbs,&newbs,&flg);CHKERRQ(ierr);
212     if (flg) {
213       ierr = PetscLayoutSetBlockSize(B->rmap,newbs);CHKERRQ(ierr);
214       ierr = PetscLayoutSetBlockSize(B->cmap,newbs);CHKERRQ(ierr);
215     }
216   }
217 
218   ierr = PetscOptionsFList("-mat_type","Matrix type","MatSetType",MatList,deft,type,256,&flg);CHKERRQ(ierr);
219   if (flg) {
220     ierr = MatSetType(B,type);CHKERRQ(ierr);
221   } else if (!((PetscObject)B)->type_name) {
222     ierr = MatSetType(B,deft);CHKERRQ(ierr);
223   }
224 
225   ierr = PetscOptionsName("-mat_is_symmetric","Checks if mat is symmetric on MatAssemblyEnd()","MatIsSymmetric",&B->checksymmetryonassembly);CHKERRQ(ierr);
226   ierr = PetscOptionsReal("-mat_is_symmetric","Checks if mat is symmetric on MatAssemblyEnd()","MatIsSymmetric",B->checksymmetrytol,&B->checksymmetrytol,NULL);CHKERRQ(ierr);
227   ierr = PetscOptionsBool("-mat_null_space_test","Checks if provided null space is correct in MatAssemblyEnd()","MatSetNullSpaceTest",B->checknullspaceonassembly,&B->checknullspaceonassembly,NULL);CHKERRQ(ierr);
228   ierr = PetscOptionsBool("-mat_error_if_failure","Generate an error if an error occurs when factoring the matrix","MatSetErrorIfFailure",B->erroriffailure,&B->erroriffailure,NULL);CHKERRQ(ierr);
229 
230   if (B->ops->setfromoptions) {
231     ierr = (*B->ops->setfromoptions)(PetscOptionsObject,B);CHKERRQ(ierr);
232   }
233 
234   flg  = PETSC_FALSE;
235   ierr = 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);CHKERRQ(ierr);
236   if (set) {ierr = MatSetOption(B,MAT_NEW_NONZERO_LOCATION_ERR,flg);CHKERRQ(ierr);}
237   flg  = PETSC_FALSE;
238   ierr = 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);CHKERRQ(ierr);
239   if (set) {ierr = MatSetOption(B,MAT_NEW_NONZERO_ALLOCATION_ERR,flg);CHKERRQ(ierr);}
240 
241   /* process any options handlers added with PetscObjectAddOptionsHandler() */
242   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)B);CHKERRQ(ierr);
243   ierr = PetscOptionsEnd();CHKERRQ(ierr);
244   PetscFunctionReturn(0);
245 }
246 
247 /*@C
248    MatXAIJSetPreallocation - set preallocation for serial and parallel AIJ, BAIJ, and SBAIJ matrices and their unassembled versions.
249 
250    Collective on Mat
251 
252    Input Arguments:
253 +  A - matrix being preallocated
254 .  bs - block size
255 .  dnnz - number of nonzero column blocks per block row of diagonal part of parallel matrix
256 .  onnz - number of nonzero column blocks per block row of off-diagonal part of parallel matrix
257 .  dnnzu - number of nonzero column blocks per block row of upper-triangular part of diagonal part of parallel matrix
258 -  onnzu - number of nonzero column blocks per block row of upper-triangular part of off-diagonal part of parallel matrix
259 
260    Level: beginner
261 
262 .seealso: MatSeqAIJSetPreallocation(), MatMPIAIJSetPreallocation(), MatSeqBAIJSetPreallocation(), MatMPIBAIJSetPreallocation(), MatSeqSBAIJSetPreallocation(), MatMPISBAIJSetPreallocation(),
263           PetscSplitOwnership()
264 @*/
265 PetscErrorCode MatXAIJSetPreallocation(Mat A,PetscInt bs,const PetscInt dnnz[],const PetscInt onnz[],const PetscInt dnnzu[],const PetscInt onnzu[])
266 {
267   PetscErrorCode ierr;
268   PetscInt       cbs;
269   void           (*aij)(void);
270   void           (*is)(void);
271   void           (*hyp)(void) = NULL;
272 
273   PetscFunctionBegin;
274   if (bs != PETSC_DECIDE) { /* don't mess with an already set block size */
275     ierr = MatSetBlockSize(A,bs);CHKERRQ(ierr);
276   }
277   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
278   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
279   ierr = MatGetBlockSizes(A,&bs,&cbs);CHKERRQ(ierr);
280   /* these routines assumes bs == cbs, this should be checked somehow */
281   ierr = MatSeqBAIJSetPreallocation(A,bs,0,dnnz);CHKERRQ(ierr);
282   ierr = MatMPIBAIJSetPreallocation(A,bs,0,dnnz,0,onnz);CHKERRQ(ierr);
283   ierr = MatSeqSBAIJSetPreallocation(A,bs,0,dnnzu);CHKERRQ(ierr);
284   ierr = MatMPISBAIJSetPreallocation(A,bs,0,dnnzu,0,onnzu);CHKERRQ(ierr);
285   /*
286     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
287     good before going on with it.
288   */
289   ierr = PetscObjectQueryFunction((PetscObject)A,"MatMPIAIJSetPreallocation_C",&aij);CHKERRQ(ierr);
290   ierr = PetscObjectQueryFunction((PetscObject)A,"MatISSetPreallocation_C",&is);CHKERRQ(ierr);
291 #if defined(PETSC_HAVE_HYPRE)
292   ierr = PetscObjectQueryFunction((PetscObject)A,"MatHYPRESetPreallocation_C",&hyp);CHKERRQ(ierr);
293 #endif
294   if (!aij && !is && !hyp) {
295     ierr = PetscObjectQueryFunction((PetscObject)A,"MatSeqAIJSetPreallocation_C",&aij);CHKERRQ(ierr);
296   }
297   if (aij || is || hyp) {
298     if (bs == cbs && bs == 1) {
299       ierr = MatSeqAIJSetPreallocation(A,0,dnnz);CHKERRQ(ierr);
300       ierr = MatMPIAIJSetPreallocation(A,0,dnnz,0,onnz);CHKERRQ(ierr);
301       ierr = MatISSetPreallocation(A,0,dnnz,0,onnz);CHKERRQ(ierr);
302 #if defined(PETSC_HAVE_HYPRE)
303       ierr = MatHYPRESetPreallocation(A,0,dnnz,0,onnz);CHKERRQ(ierr);
304 #endif
305     } else { /* Convert block-row precallocation to scalar-row */
306       PetscInt i,m,*sdnnz,*sonnz;
307       ierr = MatGetLocalSize(A,&m,NULL);CHKERRQ(ierr);
308       ierr = PetscMalloc2((!!dnnz)*m,&sdnnz,(!!onnz)*m,&sonnz);CHKERRQ(ierr);
309       for (i=0; i<m; i++) {
310         if (dnnz) sdnnz[i] = dnnz[i/bs] * cbs;
311         if (onnz) sonnz[i] = onnz[i/bs] * cbs;
312       }
313       ierr = MatSeqAIJSetPreallocation(A,0,dnnz ? sdnnz : NULL);CHKERRQ(ierr);
314       ierr = MatMPIAIJSetPreallocation(A,0,dnnz ? sdnnz : NULL,0,onnz ? sonnz : NULL);CHKERRQ(ierr);
315       ierr = MatISSetPreallocation(A,0,dnnz ? sdnnz : NULL,0,onnz ? sonnz : NULL);CHKERRQ(ierr);
316 #if defined(PETSC_HAVE_HYPRE)
317       ierr = MatHYPRESetPreallocation(A,0,dnnz ? sdnnz : NULL,0,onnz ? sonnz : NULL);CHKERRQ(ierr);
318 #endif
319       ierr = PetscFree2(sdnnz,sonnz);CHKERRQ(ierr);
320     }
321   }
322   PetscFunctionReturn(0);
323 }
324 
325 /*
326         Merges some information from Cs header to A; the C object is then destroyed
327 
328         This is somewhat different from MatHeaderReplace() it would be nice to merge the code
329 */
330 PetscErrorCode MatHeaderMerge(Mat A,Mat *C)
331 {
332   PetscErrorCode ierr;
333   PetscInt       refct;
334   PetscOps       Abops;
335   struct _MatOps Aops;
336   char           *mtype,*mname,*mprefix;
337   Mat_Product    *product;
338 
339   PetscFunctionBegin;
340   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
341   PetscValidHeaderSpecific(*C,MAT_CLASSID,2);
342   if (A == *C) PetscFunctionReturn(0);
343   PetscCheckSameComm(A,1,*C,2);
344   /* save the parts of A we need */
345   Abops = ((PetscObject)A)->bops[0];
346   Aops  = A->ops[0];
347   refct = ((PetscObject)A)->refct;
348   mtype = ((PetscObject)A)->type_name;
349   mname = ((PetscObject)A)->name;
350   mprefix = ((PetscObject)A)->prefix;
351   product = A->product;
352 
353   /* zero these so the destroy below does not free them */
354   ((PetscObject)A)->type_name = NULL;
355   ((PetscObject)A)->name      = NULL;
356 
357   /* free all the interior data structures from mat */
358   ierr = (*A->ops->destroy)(A);CHKERRQ(ierr);
359 
360   ierr = PetscFree(A->defaultvectype);CHKERRQ(ierr);
361   ierr = PetscLayoutDestroy(&A->rmap);CHKERRQ(ierr);
362   ierr = PetscLayoutDestroy(&A->cmap);CHKERRQ(ierr);
363   ierr = PetscFunctionListDestroy(&((PetscObject)A)->qlist);CHKERRQ(ierr);
364   ierr = PetscObjectListDestroy(&((PetscObject)A)->olist);CHKERRQ(ierr);
365 
366   /* copy C over to A */
367   ierr = PetscMemcpy(A,*C,sizeof(struct _p_Mat));CHKERRQ(ierr);
368 
369   /* return the parts of A we saved */
370   ((PetscObject)A)->bops[0]   = Abops;
371   A->ops[0]                   = Aops;
372   ((PetscObject)A)->refct     = refct;
373   ((PetscObject)A)->type_name = mtype;
374   ((PetscObject)A)->name      = mname;
375   ((PetscObject)A)->prefix    = mprefix;
376   A->product                  = product;
377 
378   /* since these two are copied into A we do not want them destroyed in C */
379   ((PetscObject)*C)->qlist = NULL;
380   ((PetscObject)*C)->olist = NULL;
381 
382   ierr = PetscHeaderDestroy(C);CHKERRQ(ierr);
383   PetscFunctionReturn(0);
384 }
385 /*
386         Replace A's header with that of C; the C object is then destroyed
387 
388         This is essentially code moved from MatDestroy()
389 
390         This is somewhat different from MatHeaderMerge() it would be nice to merge the code
391 
392         Used in DM hence is declared PETSC_EXTERN
393 */
394 PETSC_EXTERN PetscErrorCode MatHeaderReplace(Mat A,Mat *C)
395 {
396   PetscErrorCode   ierr;
397   PetscInt         refct;
398   PetscObjectState state;
399   struct _p_Mat    buffer;
400 
401   PetscFunctionBegin;
402   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
403   PetscValidHeaderSpecific(*C,MAT_CLASSID,2);
404   if (A == *C) PetscFunctionReturn(0);
405   PetscCheckSameComm(A,1,*C,2);
406   if (((PetscObject)*C)->refct != 1) SETERRQ1(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Object C has refct %D > 1, would leave hanging reference",((PetscObject)*C)->refct);
407 
408   /* swap C and A */
409   refct = ((PetscObject)A)->refct;
410   state = ((PetscObject)A)->state;
411   ierr  = PetscMemcpy(&buffer,A,sizeof(struct _p_Mat));CHKERRQ(ierr);
412   ierr  = PetscMemcpy(A,*C,sizeof(struct _p_Mat));CHKERRQ(ierr);
413   ierr  = PetscMemcpy(*C,&buffer,sizeof(struct _p_Mat));CHKERRQ(ierr);
414   ((PetscObject)A)->refct = refct;
415   ((PetscObject)A)->state = state + 1;
416 
417   ((PetscObject)*C)->refct = 1;
418   ierr = MatShellSetOperation(*C,MATOP_DESTROY,(void(*)(void))NULL);CHKERRQ(ierr);
419   ierr = MatDestroy(C);CHKERRQ(ierr);
420   PetscFunctionReturn(0);
421 }
422 
423 /*@
424      MatBindToCPU - marks a matrix to temporarily stay on the CPU and perform computations on the CPU
425 
426    Input Parameters:
427 +   A - the matrix
428 -   flg - bind to the CPU if value of PETSC_TRUE
429 
430    Level: intermediate
431 @*/
432 PetscErrorCode MatBindToCPU(Mat A,PetscBool flg)
433 {
434 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
435   PetscErrorCode ierr;
436 
437   PetscFunctionBegin;
438   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
439   PetscValidLogicalCollectiveBool(A,flg,2);
440   if (A->boundtocpu == flg) PetscFunctionReturn(0);
441   A->boundtocpu = flg;
442   if (A->ops->bindtocpu) {
443     ierr = (*A->ops->bindtocpu)(A,flg);CHKERRQ(ierr);
444   }
445   PetscFunctionReturn(0);
446 #else
447   PetscFunctionBegin;
448   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
449   PetscValidLogicalCollectiveBool(A,flg,2);
450   PetscFunctionReturn(0);
451 #endif
452 }
453