xref: /petsc/src/mat/impls/composite/mcomposite.c (revision 89669be4d29968dc8d4c19ce1b69194a6a561ea4)
1 
2 #include <petsc/private/matimpl.h>        /*I "petscmat.h" I*/
3 
4 const char *const MatCompositeMergeTypes[] = {"left","right","MatCompositeMergeType","MAT_COMPOSITE_",NULL};
5 
6 typedef struct _Mat_CompositeLink *Mat_CompositeLink;
7 struct _Mat_CompositeLink {
8   Mat               mat;
9   Vec               work;
10   Mat_CompositeLink next,prev;
11 };
12 
13 typedef struct {
14   MatCompositeType      type;
15   Mat_CompositeLink     head,tail;
16   Vec                   work;
17   PetscScalar           scale;        /* scale factor supplied with MatScale() */
18   Vec                   left,right;   /* left and right diagonal scaling provided with MatDiagonalScale() */
19   Vec                   leftwork,rightwork,leftwork2,rightwork2; /* Two pairs of working vectors */
20   PetscInt              nmat;
21   PetscBool             merge;
22   MatCompositeMergeType mergetype;
23   MatStructure          structure;
24 
25   PetscScalar           *scalings;
26   PetscBool             merge_mvctx;  /* Whether need to merge mvctx of component matrices */
27   Vec                   *lvecs;       /* [nmat] Basically, they are Mvctx->lvec of each component matrix */
28   PetscScalar           *larray;      /* [len] Data arrays of lvecs[] are stored consecutively in larray */
29   PetscInt              len;          /* Length of larray[] */
30   Vec                   gvec;         /* Union of lvecs[] without duplicated entries */
31   PetscInt              *location;    /* A map that maps entries in garray[] to larray[] */
32   VecScatter            Mvctx;
33 } Mat_Composite;
34 
35 PetscErrorCode MatDestroy_Composite(Mat mat)
36 {
37   Mat_Composite     *shell = (Mat_Composite*)mat->data;
38   Mat_CompositeLink next   = shell->head,oldnext;
39   PetscInt          i;
40 
41   PetscFunctionBegin;
42   while (next) {
43     PetscCall(MatDestroy(&next->mat));
44     if (next->work && (!next->next || next->work != next->next->work)) {
45       PetscCall(VecDestroy(&next->work));
46     }
47     oldnext = next;
48     next    = next->next;
49     PetscCall(PetscFree(oldnext));
50   }
51   PetscCall(VecDestroy(&shell->work));
52   PetscCall(VecDestroy(&shell->left));
53   PetscCall(VecDestroy(&shell->right));
54   PetscCall(VecDestroy(&shell->leftwork));
55   PetscCall(VecDestroy(&shell->rightwork));
56   PetscCall(VecDestroy(&shell->leftwork2));
57   PetscCall(VecDestroy(&shell->rightwork2));
58 
59   if (shell->Mvctx) {
60     for (i=0; i<shell->nmat; i++) PetscCall(VecDestroy(&shell->lvecs[i]));
61     PetscCall(PetscFree3(shell->location,shell->larray,shell->lvecs));
62     PetscCall(PetscFree(shell->larray));
63     PetscCall(VecDestroy(&shell->gvec));
64     PetscCall(VecScatterDestroy(&shell->Mvctx));
65   }
66 
67   PetscCall(PetscFree(shell->scalings));
68   PetscCall(PetscFree(mat->data));
69   PetscFunctionReturn(0);
70 }
71 
72 PetscErrorCode MatMult_Composite_Multiplicative(Mat A,Vec x,Vec y)
73 {
74   Mat_Composite     *shell = (Mat_Composite*)A->data;
75   Mat_CompositeLink next   = shell->head;
76   Vec               in,out;
77   PetscScalar       scale;
78   PetscInt          i;
79 
80   PetscFunctionBegin;
81   PetscCheck(next,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
82   in = x;
83   if (shell->right) {
84     if (!shell->rightwork) {
85       PetscCall(VecDuplicate(shell->right,&shell->rightwork));
86     }
87     PetscCall(VecPointwiseMult(shell->rightwork,shell->right,in));
88     in   = shell->rightwork;
89   }
90   while (next->next) {
91     if (!next->work) { /* should reuse previous work if the same size */
92       PetscCall(MatCreateVecs(next->mat,NULL,&next->work));
93     }
94     out  = next->work;
95     PetscCall(MatMult(next->mat,in,out));
96     in   = out;
97     next = next->next;
98   }
99   PetscCall(MatMult(next->mat,in,y));
100   if (shell->left) {
101     PetscCall(VecPointwiseMult(y,shell->left,y));
102   }
103   scale = shell->scale;
104   if (shell->scalings) {for (i=0; i<shell->nmat; i++) scale *= shell->scalings[i];}
105   PetscCall(VecScale(y,scale));
106   PetscFunctionReturn(0);
107 }
108 
109 PetscErrorCode MatMultTranspose_Composite_Multiplicative(Mat A,Vec x,Vec y)
110 {
111   Mat_Composite     *shell = (Mat_Composite*)A->data;
112   Mat_CompositeLink tail   = shell->tail;
113   Vec               in,out;
114   PetscScalar       scale;
115   PetscInt          i;
116 
117   PetscFunctionBegin;
118   PetscCheck(tail,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
119   in = x;
120   if (shell->left) {
121     if (!shell->leftwork) {
122       PetscCall(VecDuplicate(shell->left,&shell->leftwork));
123     }
124     PetscCall(VecPointwiseMult(shell->leftwork,shell->left,in));
125     in   = shell->leftwork;
126   }
127   while (tail->prev) {
128     if (!tail->prev->work) { /* should reuse previous work if the same size */
129       PetscCall(MatCreateVecs(tail->mat,NULL,&tail->prev->work));
130     }
131     out  = tail->prev->work;
132     PetscCall(MatMultTranspose(tail->mat,in,out));
133     in   = out;
134     tail = tail->prev;
135   }
136   PetscCall(MatMultTranspose(tail->mat,in,y));
137   if (shell->right) {
138     PetscCall(VecPointwiseMult(y,shell->right,y));
139   }
140 
141   scale = shell->scale;
142   if (shell->scalings) {for (i=0; i<shell->nmat; i++) scale *= shell->scalings[i];}
143   PetscCall(VecScale(y,scale));
144   PetscFunctionReturn(0);
145 }
146 
147 PetscErrorCode MatMult_Composite(Mat mat,Vec x,Vec y)
148 {
149   Mat_Composite     *shell = (Mat_Composite*)mat->data;
150   Mat_CompositeLink cur = shell->head;
151   Vec               in,y2,xin;
152   Mat               A,B;
153   PetscInt          i,j,k,n,nuniq,lo,hi,mid,*gindices,*buf,*tmp,tot;
154   const PetscScalar *vals;
155   const PetscInt    *garray;
156   IS                ix,iy;
157   PetscBool         match;
158 
159   PetscFunctionBegin;
160   PetscCheck(cur,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
161   in = x;
162   if (shell->right) {
163     if (!shell->rightwork) {
164       PetscCall(VecDuplicate(shell->right,&shell->rightwork));
165     }
166     PetscCall(VecPointwiseMult(shell->rightwork,shell->right,in));
167     in   = shell->rightwork;
168   }
169 
170   /* Try to merge Mvctx when instructed but not yet done. We did not do it in MatAssemblyEnd() since at that time
171      we did not know whether mat is ADDITIVE or MULTIPLICATIVE. Only now we are assured mat is ADDITIVE and
172      it is legal to merge Mvctx, because all component matrices have the same size.
173    */
174   if (shell->merge_mvctx && !shell->Mvctx) {
175     /* Currently only implemented for MATMPIAIJ */
176     for (cur=shell->head; cur; cur=cur->next) {
177       PetscCall(PetscObjectTypeCompare((PetscObject)cur->mat,MATMPIAIJ,&match));
178       if (!match) {
179         shell->merge_mvctx = PETSC_FALSE;
180         goto skip_merge_mvctx;
181       }
182     }
183 
184     /* Go through matrices first time to count total number of nonzero off-diag columns (may have dups) */
185     tot = 0;
186     for (cur=shell->head; cur; cur=cur->next) {
187       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat,NULL,&B,NULL));
188       PetscCall(MatGetLocalSize(B,NULL,&n));
189       tot += n;
190     }
191     PetscCall(PetscMalloc3(tot,&shell->location,tot,&shell->larray,shell->nmat,&shell->lvecs));
192     shell->len = tot;
193 
194     /* Go through matrices second time to sort off-diag columns and remove dups */
195     PetscCall(PetscMalloc1(tot,&gindices)); /* No Malloc2() since we will give one to petsc and free the other */
196     PetscCall(PetscMalloc1(tot,&buf));
197     nuniq = 0; /* Number of unique nonzero columns */
198     for (cur=shell->head; cur; cur=cur->next) {
199       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat,NULL,&B,&garray));
200       PetscCall(MatGetLocalSize(B,NULL,&n));
201       /* Merge pre-sorted garray[0,n) and gindices[0,nuniq) to buf[] */
202       i = j = k = 0;
203       while (i < n && j < nuniq) {
204         if (garray[i] < gindices[j]) buf[k++] = garray[i++];
205         else if (garray[i] > gindices[j]) buf[k++] = gindices[j++];
206         else {buf[k++] = garray[i++]; j++;}
207       }
208       /* Copy leftover in garray[] or gindices[] */
209       if (i < n) {
210         PetscCall(PetscArraycpy(buf+k,garray+i,n-i));
211         nuniq = k + n-i;
212       } else if (j < nuniq) {
213         PetscCall(PetscArraycpy(buf+k,gindices+j,nuniq-j));
214         nuniq = k + nuniq-j;
215       } else nuniq = k;
216       /* Swap gindices and buf to merge garray of the next matrix */
217       tmp      = gindices;
218       gindices = buf;
219       buf      = tmp;
220     }
221     PetscCall(PetscFree(buf));
222 
223     /* Go through matrices third time to build a map from gindices[] to garray[] */
224     tot = 0;
225     for (cur=shell->head,j=0; cur; cur=cur->next,j++) { /* j-th matrix */
226       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat,NULL,&B,&garray));
227       PetscCall(MatGetLocalSize(B,NULL,&n));
228       PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF,1,n,NULL,&shell->lvecs[j]));
229       /* This is an optimized PetscFindInt(garray[i],nuniq,gindices,&shell->location[tot+i]), using the fact that garray[] is also sorted */
230       lo   = 0;
231       for (i=0; i<n; i++) {
232         hi = nuniq;
233         while (hi - lo > 1) {
234           mid = lo + (hi - lo)/2;
235           if (garray[i] < gindices[mid]) hi = mid;
236           else lo = mid;
237         }
238         shell->location[tot+i] = lo; /* gindices[lo] = garray[i] */
239         lo++; /* Since garray[i+1] > garray[i], we can safely advance lo */
240       }
241       tot += n;
242     }
243 
244     /* Build merged Mvctx */
245     PetscCall(ISCreateGeneral(PETSC_COMM_SELF,nuniq,gindices,PETSC_OWN_POINTER,&ix));
246     PetscCall(ISCreateStride(PETSC_COMM_SELF,nuniq,0,1,&iy));
247     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)mat),1,mat->cmap->n,mat->cmap->N,NULL,&xin));
248     PetscCall(VecCreateSeq(PETSC_COMM_SELF,nuniq,&shell->gvec));
249     PetscCall(VecScatterCreate(xin,ix,shell->gvec,iy,&shell->Mvctx));
250     PetscCall(VecDestroy(&xin));
251     PetscCall(ISDestroy(&ix));
252     PetscCall(ISDestroy(&iy));
253   }
254 
255 skip_merge_mvctx:
256   PetscCall(VecSet(y,0));
257   if (!shell->leftwork2) PetscCall(VecDuplicate(y,&shell->leftwork2));
258   y2 = shell->leftwork2;
259 
260   if (shell->Mvctx) { /* Have a merged Mvctx */
261     /* Suppose we want to compute y = sMx, where s is the scaling factor and A, B are matrix M's diagonal/off-diagonal part. We could do
262        in y = s(Ax1 + Bx2) or y = sAx1 + sBx2. The former incurs less FLOPS than the latter, but the latter provides an oppertunity to
263        overlap communication/computation since we can do sAx1 while communicating x2. Here, we use the former approach.
264      */
265     PetscCall(VecScatterBegin(shell->Mvctx,in,shell->gvec,INSERT_VALUES,SCATTER_FORWARD));
266     PetscCall(VecScatterEnd(shell->Mvctx,in,shell->gvec,INSERT_VALUES,SCATTER_FORWARD));
267 
268     PetscCall(VecGetArrayRead(shell->gvec,&vals));
269     for (i=0; i<shell->len; i++) shell->larray[i] = vals[shell->location[i]];
270     PetscCall(VecRestoreArrayRead(shell->gvec,&vals));
271 
272     for (cur=shell->head,tot=i=0; cur; cur=cur->next,i++) { /* i-th matrix */
273       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat,&A,&B,NULL));
274       PetscCall((*A->ops->mult)(A,in,y2));
275       PetscCall(MatGetLocalSize(B,NULL,&n));
276       PetscCall(VecPlaceArray(shell->lvecs[i],&shell->larray[tot]));
277       PetscCall((*B->ops->multadd)(B,shell->lvecs[i],y2,y2));
278       PetscCall(VecResetArray(shell->lvecs[i]));
279       PetscCall(VecAXPY(y,(shell->scalings ? shell->scalings[i] : 1.0),y2));
280       tot += n;
281     }
282   } else {
283     if (shell->scalings) {
284       for (cur=shell->head,i=0; cur; cur=cur->next,i++) {
285         PetscCall(MatMult(cur->mat,in,y2));
286         PetscCall(VecAXPY(y,shell->scalings[i],y2));
287       }
288     } else {
289       for (cur=shell->head; cur; cur=cur->next) PetscCall(MatMultAdd(cur->mat,in,y,y));
290     }
291   }
292 
293   if (shell->left) PetscCall(VecPointwiseMult(y,shell->left,y));
294   PetscCall(VecScale(y,shell->scale));
295   PetscFunctionReturn(0);
296 }
297 
298 PetscErrorCode MatMultTranspose_Composite(Mat A,Vec x,Vec y)
299 {
300   Mat_Composite     *shell = (Mat_Composite*)A->data;
301   Mat_CompositeLink next   = shell->head;
302   Vec               in,y2 = NULL;
303   PetscInt          i;
304 
305   PetscFunctionBegin;
306   PetscCheck(next,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
307   in = x;
308   if (shell->left) {
309     if (!shell->leftwork) {
310       PetscCall(VecDuplicate(shell->left,&shell->leftwork));
311     }
312     PetscCall(VecPointwiseMult(shell->leftwork,shell->left,in));
313     in   = shell->leftwork;
314   }
315 
316   PetscCall(MatMultTranspose(next->mat,in,y));
317   if (shell->scalings) {
318     PetscCall(VecScale(y,shell->scalings[0]));
319     if (!shell->rightwork2) PetscCall(VecDuplicate(y,&shell->rightwork2));
320     y2 = shell->rightwork2;
321   }
322   i = 1;
323   while ((next = next->next)) {
324     if (!shell->scalings) PetscCall(MatMultTransposeAdd(next->mat,in,y,y));
325     else {
326       PetscCall(MatMultTranspose(next->mat,in,y2));
327       PetscCall(VecAXPY(y,shell->scalings[i++],y2));
328     }
329   }
330   if (shell->right) {
331     PetscCall(VecPointwiseMult(y,shell->right,y));
332   }
333   PetscCall(VecScale(y,shell->scale));
334   PetscFunctionReturn(0);
335 }
336 
337 PetscErrorCode MatMultAdd_Composite(Mat A,Vec x,Vec y,Vec z)
338 {
339   Mat_Composite     *shell = (Mat_Composite*)A->data;
340 
341   PetscFunctionBegin;
342   if (y != z) {
343     PetscCall(MatMult(A,x,z));
344     PetscCall(VecAXPY(z,1.0,y));
345   } else {
346     if (!shell->leftwork) {
347       PetscCall(VecDuplicate(z,&shell->leftwork));
348     }
349     PetscCall(MatMult(A,x,shell->leftwork));
350     PetscCall(VecCopy(y,z));
351     PetscCall(VecAXPY(z,1.0,shell->leftwork));
352   }
353   PetscFunctionReturn(0);
354 }
355 
356 PetscErrorCode MatMultTransposeAdd_Composite(Mat A,Vec x,Vec y, Vec z)
357 {
358   Mat_Composite     *shell = (Mat_Composite*)A->data;
359 
360   PetscFunctionBegin;
361   if (y != z) {
362     PetscCall(MatMultTranspose(A,x,z));
363     PetscCall(VecAXPY(z,1.0,y));
364   } else {
365     if (!shell->rightwork) {
366       PetscCall(VecDuplicate(z,&shell->rightwork));
367     }
368     PetscCall(MatMultTranspose(A,x,shell->rightwork));
369     PetscCall(VecCopy(y,z));
370     PetscCall(VecAXPY(z,1.0,shell->rightwork));
371   }
372   PetscFunctionReturn(0);
373 }
374 
375 PetscErrorCode MatGetDiagonal_Composite(Mat A,Vec v)
376 {
377   Mat_Composite     *shell = (Mat_Composite*)A->data;
378   Mat_CompositeLink next   = shell->head;
379   PetscInt          i;
380 
381   PetscFunctionBegin;
382   PetscCheck(next,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
383   PetscCheck(!shell->right && !shell->left,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get diagonal if left or right scaling");
384 
385   PetscCall(MatGetDiagonal(next->mat,v));
386   if (shell->scalings) PetscCall(VecScale(v,shell->scalings[0]));
387 
388   if (next->next && !shell->work) {
389     PetscCall(VecDuplicate(v,&shell->work));
390   }
391   i = 1;
392   while ((next = next->next)) {
393     PetscCall(MatGetDiagonal(next->mat,shell->work));
394     PetscCall(VecAXPY(v,(shell->scalings ? shell->scalings[i++] : 1.0),shell->work));
395   }
396   PetscCall(VecScale(v,shell->scale));
397   PetscFunctionReturn(0);
398 }
399 
400 PetscErrorCode MatAssemblyEnd_Composite(Mat Y,MatAssemblyType t)
401 {
402   Mat_Composite  *shell = (Mat_Composite*)Y->data;
403 
404   PetscFunctionBegin;
405   if (shell->merge) {
406     PetscCall(MatCompositeMerge(Y));
407   }
408   PetscFunctionReturn(0);
409 }
410 
411 PetscErrorCode MatScale_Composite(Mat inA,PetscScalar alpha)
412 {
413   Mat_Composite *a = (Mat_Composite*)inA->data;
414 
415   PetscFunctionBegin;
416   a->scale *= alpha;
417   PetscFunctionReturn(0);
418 }
419 
420 PetscErrorCode MatDiagonalScale_Composite(Mat inA,Vec left,Vec right)
421 {
422   Mat_Composite  *a = (Mat_Composite*)inA->data;
423 
424   PetscFunctionBegin;
425   if (left) {
426     if (!a->left) {
427       PetscCall(VecDuplicate(left,&a->left));
428       PetscCall(VecCopy(left,a->left));
429     } else {
430       PetscCall(VecPointwiseMult(a->left,left,a->left));
431     }
432   }
433   if (right) {
434     if (!a->right) {
435       PetscCall(VecDuplicate(right,&a->right));
436       PetscCall(VecCopy(right,a->right));
437     } else {
438       PetscCall(VecPointwiseMult(a->right,right,a->right));
439     }
440   }
441   PetscFunctionReturn(0);
442 }
443 
444 PetscErrorCode MatSetFromOptions_Composite(PetscOptionItems *PetscOptionsObject,Mat A)
445 {
446   Mat_Composite  *a = (Mat_Composite*)A->data;
447 
448   PetscFunctionBegin;
449   PetscOptionsHeadBegin(PetscOptionsObject,"MATCOMPOSITE options");
450   PetscCall(PetscOptionsBool("-mat_composite_merge","Merge at MatAssemblyEnd","MatCompositeMerge",a->merge,&a->merge,NULL));
451   PetscCall(PetscOptionsEnum("-mat_composite_merge_type","Set composite merge direction","MatCompositeSetMergeType",MatCompositeMergeTypes,(PetscEnum)a->mergetype,(PetscEnum*)&a->mergetype,NULL));
452   PetscCall(PetscOptionsBool("-mat_composite_merge_mvctx","Merge MatMult() vecscat contexts","MatCreateComposite",a->merge_mvctx,&a->merge_mvctx,NULL));
453   PetscOptionsHeadEnd();
454   PetscFunctionReturn(0);
455 }
456 
457 /*@
458    MatCreateComposite - Creates a matrix as the sum or product of one or more matrices
459 
460   Collective
461 
462    Input Parameters:
463 +  comm - MPI communicator
464 .  nmat - number of matrices to put in
465 -  mats - the matrices
466 
467    Output Parameter:
468 .  mat - the matrix
469 
470    Options Database Keys:
471 +  -mat_composite_merge         - merge in MatAssemblyEnd()
472 .  -mat_composite_merge_mvctx   - merge Mvctx of component matrices to optimize communication in MatMult() for ADDITIVE matrices
473 -  -mat_composite_merge_type    - set merge direction
474 
475    Level: advanced
476 
477    Notes:
478      Alternative construction
479 $       MatCreate(comm,&mat);
480 $       MatSetSizes(mat,m,n,M,N);
481 $       MatSetType(mat,MATCOMPOSITE);
482 $       MatCompositeAddMat(mat,mats[0]);
483 $       ....
484 $       MatCompositeAddMat(mat,mats[nmat-1]);
485 $       MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
486 $       MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
487 
488      For the multiplicative form the product is mat[nmat-1]*mat[nmat-2]*....*mat[0]
489 
490 .seealso: `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCompositeGetMat()`, `MatCompositeMerge()`, `MatCompositeSetType()`, `MATCOMPOSITE`
491 
492 @*/
493 PetscErrorCode MatCreateComposite(MPI_Comm comm,PetscInt nmat,const Mat *mats,Mat *mat)
494 {
495   PetscInt       m,n,M,N,i;
496 
497   PetscFunctionBegin;
498   PetscCheck(nmat >= 1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must pass in at least one matrix");
499   PetscValidPointer(mat,4);
500 
501   PetscCall(MatGetLocalSize(mats[0],PETSC_IGNORE,&n));
502   PetscCall(MatGetLocalSize(mats[nmat-1],&m,PETSC_IGNORE));
503   PetscCall(MatGetSize(mats[0],PETSC_IGNORE,&N));
504   PetscCall(MatGetSize(mats[nmat-1],&M,PETSC_IGNORE));
505   PetscCall(MatCreate(comm,mat));
506   PetscCall(MatSetSizes(*mat,m,n,M,N));
507   PetscCall(MatSetType(*mat,MATCOMPOSITE));
508   for (i=0; i<nmat; i++) {
509     PetscCall(MatCompositeAddMat(*mat,mats[i]));
510   }
511   PetscCall(MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY));
512   PetscCall(MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY));
513   PetscFunctionReturn(0);
514 }
515 
516 static PetscErrorCode MatCompositeAddMat_Composite(Mat mat,Mat smat)
517 {
518   Mat_Composite     *shell = (Mat_Composite*)mat->data;
519   Mat_CompositeLink ilink,next = shell->head;
520 
521   PetscFunctionBegin;
522   PetscCall(PetscNewLog(mat,&ilink));
523   ilink->next = NULL;
524   PetscCall(PetscObjectReference((PetscObject)smat));
525   ilink->mat  = smat;
526 
527   if (!next) shell->head = ilink;
528   else {
529     while (next->next) {
530       next = next->next;
531     }
532     next->next  = ilink;
533     ilink->prev = next;
534   }
535   shell->tail =  ilink;
536   shell->nmat += 1;
537 
538   /* Retain the old scalings (if any) and expand it with a 1.0 for the newly added matrix */
539   if (shell->scalings) {
540     PetscCall(PetscRealloc(sizeof(PetscScalar)*shell->nmat,&shell->scalings));
541     shell->scalings[shell->nmat-1] = 1.0;
542   }
543   PetscFunctionReturn(0);
544 }
545 
546 /*@
547     MatCompositeAddMat - Add another matrix to a composite matrix.
548 
549    Collective on Mat
550 
551     Input Parameters:
552 +   mat - the composite matrix
553 -   smat - the partial matrix
554 
555    Level: advanced
556 
557 .seealso: `MatCreateComposite()`, `MatCompositeGetMat()`, `MATCOMPOSITE`
558 @*/
559 PetscErrorCode MatCompositeAddMat(Mat mat,Mat smat)
560 {
561   PetscFunctionBegin;
562   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
563   PetscValidHeaderSpecific(smat,MAT_CLASSID,2);
564   PetscUseMethod(mat,"MatCompositeAddMat_C",(Mat,Mat),(mat,smat));
565   PetscFunctionReturn(0);
566 }
567 
568 static PetscErrorCode MatCompositeSetType_Composite(Mat mat,MatCompositeType type)
569 {
570   Mat_Composite  *b = (Mat_Composite*)mat->data;
571 
572   PetscFunctionBegin;
573   b->type = type;
574   if (type == MAT_COMPOSITE_MULTIPLICATIVE) {
575     mat->ops->getdiagonal   = NULL;
576     mat->ops->mult          = MatMult_Composite_Multiplicative;
577     mat->ops->multtranspose = MatMultTranspose_Composite_Multiplicative;
578     b->merge_mvctx          = PETSC_FALSE;
579   } else {
580     mat->ops->getdiagonal   = MatGetDiagonal_Composite;
581     mat->ops->mult          = MatMult_Composite;
582     mat->ops->multtranspose = MatMultTranspose_Composite;
583   }
584   PetscFunctionReturn(0);
585 }
586 
587 /*@
588    MatCompositeSetType - Indicates if the matrix is defined as the sum of a set of matrices or the product.
589 
590    Logically Collective on Mat
591 
592    Input Parameters:
593 .  mat - the composite matrix
594 
595    Level: advanced
596 
597 .seealso: `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCreateComposite()`, `MatCompositeGetType()`, `MATCOMPOSITE`
598 
599 @*/
600 PetscErrorCode MatCompositeSetType(Mat mat,MatCompositeType type)
601 {
602   PetscFunctionBegin;
603   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
604   PetscValidLogicalCollectiveEnum(mat,type,2);
605   PetscUseMethod(mat,"MatCompositeSetType_C",(Mat,MatCompositeType),(mat,type));
606   PetscFunctionReturn(0);
607 }
608 
609 static PetscErrorCode MatCompositeGetType_Composite(Mat mat,MatCompositeType *type)
610 {
611   Mat_Composite  *b = (Mat_Composite*)mat->data;
612 
613   PetscFunctionBegin;
614   *type = b->type;
615   PetscFunctionReturn(0);
616 }
617 
618 /*@
619    MatCompositeGetType - Returns type of composite.
620 
621    Not Collective
622 
623    Input Parameter:
624 .  mat - the composite matrix
625 
626    Output Parameter:
627 .  type - type of composite
628 
629    Level: advanced
630 
631 .seealso: `MatCreateComposite()`, `MatCompositeSetType()`, `MATCOMPOSITE`
632 
633 @*/
634 PetscErrorCode MatCompositeGetType(Mat mat,MatCompositeType *type)
635 {
636   PetscFunctionBegin;
637   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
638   PetscValidPointer(type,2);
639   PetscUseMethod(mat,"MatCompositeGetType_C",(Mat,MatCompositeType*),(mat,type));
640   PetscFunctionReturn(0);
641 }
642 
643 static PetscErrorCode MatCompositeSetMatStructure_Composite(Mat mat,MatStructure str)
644 {
645   Mat_Composite  *b = (Mat_Composite*)mat->data;
646 
647   PetscFunctionBegin;
648   b->structure = str;
649   PetscFunctionReturn(0);
650 }
651 
652 /*@
653    MatCompositeSetMatStructure - Indicates structure of matrices in the composite matrix.
654 
655    Not Collective
656 
657    Input Parameters:
658 +  mat - the composite matrix
659 -  str - either SAME_NONZERO_PATTERN, DIFFERENT_NONZERO_PATTERN (default) or SUBSET_NONZERO_PATTERN
660 
661    Level: advanced
662 
663    Notes:
664     Information about the matrices structure is used in MatCompositeMerge() for additive composite matrix.
665 
666 .seealso: `MatAXPY()`, `MatCreateComposite()`, `MatCompositeMerge()` `MatCompositeGetMatStructure()`, `MATCOMPOSITE`
667 
668 @*/
669 PetscErrorCode MatCompositeSetMatStructure(Mat mat,MatStructure str)
670 {
671   PetscFunctionBegin;
672   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
673   PetscUseMethod(mat,"MatCompositeSetMatStructure_C",(Mat,MatStructure),(mat,str));
674   PetscFunctionReturn(0);
675 }
676 
677 static PetscErrorCode MatCompositeGetMatStructure_Composite(Mat mat,MatStructure *str)
678 {
679   Mat_Composite  *b = (Mat_Composite*)mat->data;
680 
681   PetscFunctionBegin;
682   *str = b->structure;
683   PetscFunctionReturn(0);
684 }
685 
686 /*@
687    MatCompositeGetMatStructure - Returns the structure of matrices in the composite matrix.
688 
689    Not Collective
690 
691    Input Parameter:
692 .  mat - the composite matrix
693 
694    Output Parameter:
695 .  str - structure of the matrices
696 
697    Level: advanced
698 
699 .seealso: `MatCreateComposite()`, `MatCompositeSetMatStructure()`, `MATCOMPOSITE`
700 
701 @*/
702 PetscErrorCode MatCompositeGetMatStructure(Mat mat,MatStructure *str)
703 {
704   PetscFunctionBegin;
705   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
706   PetscValidPointer(str,2);
707   PetscUseMethod(mat,"MatCompositeGetMatStructure_C",(Mat,MatStructure*),(mat,str));
708   PetscFunctionReturn(0);
709 }
710 
711 static PetscErrorCode MatCompositeSetMergeType_Composite(Mat mat,MatCompositeMergeType type)
712 {
713   Mat_Composite     *shell = (Mat_Composite*)mat->data;
714 
715   PetscFunctionBegin;
716   shell->mergetype = type;
717   PetscFunctionReturn(0);
718 }
719 
720 /*@
721    MatCompositeSetMergeType - Sets order of MatCompositeMerge().
722 
723    Logically Collective on Mat
724 
725    Input Parameters:
726 +  mat - the composite matrix
727 -  type - MAT_COMPOSITE_MERGE RIGHT (default) to start merge from right with the first added matrix (mat[0]),
728           MAT_COMPOSITE_MERGE_LEFT to start merge from left with the last added matrix (mat[nmat-1])
729 
730    Level: advanced
731 
732    Notes:
733     The resulting matrix is the same regardles of the MergeType. Only the order of operation is changed.
734     If set to MAT_COMPOSITE_MERGE_RIGHT the order of the merge is mat[nmat-1]*(mat[nmat-2]*(...*(mat[1]*mat[0])))
735     otherwise the order is (((mat[nmat-1]*mat[nmat-2])*mat[nmat-3])*...)*mat[0].
736 
737 .seealso: `MatCreateComposite()`, `MatCompositeMerge()`, `MATCOMPOSITE`
738 
739 @*/
740 PetscErrorCode MatCompositeSetMergeType(Mat mat,MatCompositeMergeType type)
741 {
742   PetscFunctionBegin;
743   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
744   PetscValidLogicalCollectiveEnum(mat,type,2);
745   PetscUseMethod(mat,"MatCompositeSetMergeType_C",(Mat,MatCompositeMergeType),(mat,type));
746   PetscFunctionReturn(0);
747 }
748 
749 static PetscErrorCode MatCompositeMerge_Composite(Mat mat)
750 {
751   Mat_Composite     *shell = (Mat_Composite*)mat->data;
752   Mat_CompositeLink next   = shell->head, prev = shell->tail;
753   Mat               tmat,newmat;
754   Vec               left,right;
755   PetscScalar       scale;
756   PetscInt          i;
757 
758   PetscFunctionBegin;
759   PetscCheck(next,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
760   scale = shell->scale;
761   if (shell->type == MAT_COMPOSITE_ADDITIVE) {
762     if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
763       i = 0;
764       PetscCall(MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat));
765       if (shell->scalings) PetscCall(MatScale(tmat,shell->scalings[i++]));
766       while ((next = next->next)) {
767         PetscCall(MatAXPY(tmat,(shell->scalings ? shell->scalings[i++] : 1.0),next->mat,shell->structure));
768       }
769     } else {
770       i = shell->nmat-1;
771       PetscCall(MatDuplicate(prev->mat,MAT_COPY_VALUES,&tmat));
772       if (shell->scalings) PetscCall(MatScale(tmat,shell->scalings[i--]));
773       while ((prev = prev->prev)) {
774         PetscCall(MatAXPY(tmat,(shell->scalings ? shell->scalings[i--] : 1.0),prev->mat,shell->structure));
775       }
776     }
777   } else {
778     if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
779       PetscCall(MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat));
780       while ((next = next->next)) {
781         PetscCall(MatMatMult(next->mat,tmat,MAT_INITIAL_MATRIX,PETSC_DECIDE,&newmat));
782         PetscCall(MatDestroy(&tmat));
783         tmat = newmat;
784       }
785     } else {
786       PetscCall(MatDuplicate(prev->mat,MAT_COPY_VALUES,&tmat));
787       while ((prev = prev->prev)) {
788         PetscCall(MatMatMult(tmat,prev->mat,MAT_INITIAL_MATRIX,PETSC_DECIDE,&newmat));
789         PetscCall(MatDestroy(&tmat));
790         tmat = newmat;
791       }
792     }
793     if (shell->scalings) {for (i=0; i<shell->nmat; i++) scale *= shell->scalings[i];}
794   }
795 
796   if ((left = shell->left)) PetscCall(PetscObjectReference((PetscObject)left));
797   if ((right = shell->right)) PetscCall(PetscObjectReference((PetscObject)right));
798 
799   PetscCall(MatHeaderReplace(mat,&tmat));
800 
801   PetscCall(MatDiagonalScale(mat,left,right));
802   PetscCall(MatScale(mat,scale));
803   PetscCall(VecDestroy(&left));
804   PetscCall(VecDestroy(&right));
805   PetscFunctionReturn(0);
806 }
807 
808 /*@
809    MatCompositeMerge - Given a composite matrix, replaces it with a "regular" matrix
810      by summing or computing the product of all the matrices inside the composite matrix.
811 
812   Collective
813 
814    Input Parameter:
815 .  mat - the composite matrix
816 
817    Options Database Keys:
818 +  -mat_composite_merge - merge in MatAssemblyEnd()
819 -  -mat_composite_merge_type - set merge direction
820 
821    Level: advanced
822 
823    Notes:
824       The MatType of the resulting matrix will be the same as the MatType of the FIRST
825     matrix in the composite matrix.
826 
827 .seealso: `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCreateComposite()`, `MatCompositeSetMatStructure()`, `MatCompositeSetMergeType()`, `MATCOMPOSITE`
828 
829 @*/
830 PetscErrorCode MatCompositeMerge(Mat mat)
831 {
832   PetscFunctionBegin;
833   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
834   PetscUseMethod(mat,"MatCompositeMerge_C",(Mat),(mat));
835   PetscFunctionReturn(0);
836 }
837 
838 static PetscErrorCode MatCompositeGetNumberMat_Composite(Mat mat,PetscInt *nmat)
839 {
840   Mat_Composite     *shell = (Mat_Composite*)mat->data;
841 
842   PetscFunctionBegin;
843   *nmat = shell->nmat;
844   PetscFunctionReturn(0);
845 }
846 
847 /*@
848    MatCompositeGetNumberMat - Returns the number of matrices in the composite matrix.
849 
850    Not Collective
851 
852    Input Parameter:
853 .  mat - the composite matrix
854 
855    Output Parameter:
856 .  nmat - number of matrices in the composite matrix
857 
858    Level: advanced
859 
860 .seealso: `MatCreateComposite()`, `MatCompositeGetMat()`, `MATCOMPOSITE`
861 
862 @*/
863 PetscErrorCode MatCompositeGetNumberMat(Mat mat,PetscInt *nmat)
864 {
865   PetscFunctionBegin;
866   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
867   PetscValidIntPointer(nmat,2);
868   PetscUseMethod(mat,"MatCompositeGetNumberMat_C",(Mat,PetscInt*),(mat,nmat));
869   PetscFunctionReturn(0);
870 }
871 
872 static PetscErrorCode MatCompositeGetMat_Composite(Mat mat,PetscInt i,Mat *Ai)
873 {
874   Mat_Composite     *shell = (Mat_Composite*)mat->data;
875   Mat_CompositeLink ilink;
876   PetscInt          k;
877 
878   PetscFunctionBegin;
879   PetscCheck(i < shell->nmat,PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_OUTOFRANGE,"index out of range: %" PetscInt_FMT " >= %" PetscInt_FMT,i,shell->nmat);
880   ilink = shell->head;
881   for (k=0; k<i; k++) {
882     ilink = ilink->next;
883   }
884   *Ai = ilink->mat;
885   PetscFunctionReturn(0);
886 }
887 
888 /*@
889    MatCompositeGetMat - Returns the ith matrix from the composite matrix.
890 
891    Logically Collective on Mat
892 
893    Input Parameters:
894 +  mat - the composite matrix
895 -  i - the number of requested matrix
896 
897    Output Parameter:
898 .  Ai - ith matrix in composite
899 
900    Level: advanced
901 
902 .seealso: `MatCreateComposite()`, `MatCompositeGetNumberMat()`, `MatCompositeAddMat()`, `MATCOMPOSITE`
903 
904 @*/
905 PetscErrorCode MatCompositeGetMat(Mat mat,PetscInt i,Mat *Ai)
906 {
907   PetscFunctionBegin;
908   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
909   PetscValidLogicalCollectiveInt(mat,i,2);
910   PetscValidPointer(Ai,3);
911   PetscUseMethod(mat,"MatCompositeGetMat_C",(Mat,PetscInt,Mat*),(mat,i,Ai));
912   PetscFunctionReturn(0);
913 }
914 
915 PetscErrorCode MatCompositeSetScalings_Composite(Mat mat,const PetscScalar *scalings)
916 {
917   Mat_Composite  *shell = (Mat_Composite*)mat->data;
918   PetscInt       nmat;
919 
920   PetscFunctionBegin;
921   PetscCall(MatCompositeGetNumberMat(mat,&nmat));
922   if (!shell->scalings) PetscCall(PetscMalloc1(nmat,&shell->scalings));
923   PetscCall(PetscArraycpy(shell->scalings,scalings,nmat));
924   PetscFunctionReturn(0);
925 }
926 
927 /*@
928    MatCompositeSetScalings - Sets separate scaling factors for component matrices.
929 
930    Logically Collective on Mat
931 
932    Input Parameters:
933 +  mat      - the composite matrix
934 -  scalings - array of scaling factors with scalings[i] being factor of i-th matrix, for i in [0, nmat)
935 
936    Level: advanced
937 
938 .seealso: `MatScale()`, `MatDiagonalScale()`, `MATCOMPOSITE`
939 
940 @*/
941 PetscErrorCode MatCompositeSetScalings(Mat mat,const PetscScalar *scalings)
942 {
943   PetscFunctionBegin;
944   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
945   PetscValidScalarPointer(scalings,2);
946   PetscValidLogicalCollectiveScalar(mat,*scalings,2);
947   PetscUseMethod(mat,"MatCompositeSetScalings_C",(Mat,const PetscScalar*),(mat,scalings));
948   PetscFunctionReturn(0);
949 }
950 
951 static struct _MatOps MatOps_Values = {NULL,
952                                        NULL,
953                                        NULL,
954                                        MatMult_Composite,
955                                        MatMultAdd_Composite,
956                                /*  5*/ MatMultTranspose_Composite,
957                                        MatMultTransposeAdd_Composite,
958                                        NULL,
959                                        NULL,
960                                        NULL,
961                                /* 10*/ NULL,
962                                        NULL,
963                                        NULL,
964                                        NULL,
965                                        NULL,
966                                /* 15*/ NULL,
967                                        NULL,
968                                        MatGetDiagonal_Composite,
969                                        MatDiagonalScale_Composite,
970                                        NULL,
971                                /* 20*/ NULL,
972                                        MatAssemblyEnd_Composite,
973                                        NULL,
974                                        NULL,
975                                /* 24*/ NULL,
976                                        NULL,
977                                        NULL,
978                                        NULL,
979                                        NULL,
980                                /* 29*/ NULL,
981                                        NULL,
982                                        NULL,
983                                        NULL,
984                                        NULL,
985                                /* 34*/ NULL,
986                                        NULL,
987                                        NULL,
988                                        NULL,
989                                        NULL,
990                                /* 39*/ NULL,
991                                        NULL,
992                                        NULL,
993                                        NULL,
994                                        NULL,
995                                /* 44*/ NULL,
996                                        MatScale_Composite,
997                                        MatShift_Basic,
998                                        NULL,
999                                        NULL,
1000                                /* 49*/ NULL,
1001                                        NULL,
1002                                        NULL,
1003                                        NULL,
1004                                        NULL,
1005                                /* 54*/ NULL,
1006                                        NULL,
1007                                        NULL,
1008                                        NULL,
1009                                        NULL,
1010                                /* 59*/ NULL,
1011                                        MatDestroy_Composite,
1012                                        NULL,
1013                                        NULL,
1014                                        NULL,
1015                                /* 64*/ NULL,
1016                                        NULL,
1017                                        NULL,
1018                                        NULL,
1019                                        NULL,
1020                                /* 69*/ NULL,
1021                                        NULL,
1022                                        NULL,
1023                                        NULL,
1024                                        NULL,
1025                                /* 74*/ NULL,
1026                                        NULL,
1027                                        MatSetFromOptions_Composite,
1028                                        NULL,
1029                                        NULL,
1030                                /* 79*/ NULL,
1031                                        NULL,
1032                                        NULL,
1033                                        NULL,
1034                                        NULL,
1035                                /* 84*/ NULL,
1036                                        NULL,
1037                                        NULL,
1038                                        NULL,
1039                                        NULL,
1040                                /* 89*/ NULL,
1041                                        NULL,
1042                                        NULL,
1043                                        NULL,
1044                                        NULL,
1045                                /* 94*/ NULL,
1046                                        NULL,
1047                                        NULL,
1048                                        NULL,
1049                                        NULL,
1050                                 /*99*/ NULL,
1051                                        NULL,
1052                                        NULL,
1053                                        NULL,
1054                                        NULL,
1055                                /*104*/ NULL,
1056                                        NULL,
1057                                        NULL,
1058                                        NULL,
1059                                        NULL,
1060                                /*109*/ NULL,
1061                                        NULL,
1062                                        NULL,
1063                                        NULL,
1064                                        NULL,
1065                                /*114*/ NULL,
1066                                        NULL,
1067                                        NULL,
1068                                        NULL,
1069                                        NULL,
1070                                /*119*/ NULL,
1071                                        NULL,
1072                                        NULL,
1073                                        NULL,
1074                                        NULL,
1075                                /*124*/ NULL,
1076                                        NULL,
1077                                        NULL,
1078                                        NULL,
1079                                        NULL,
1080                                /*129*/ NULL,
1081                                        NULL,
1082                                        NULL,
1083                                        NULL,
1084                                        NULL,
1085                                /*134*/ NULL,
1086                                        NULL,
1087                                        NULL,
1088                                        NULL,
1089                                        NULL,
1090                                /*139*/ NULL,
1091                                        NULL,
1092                                        NULL,
1093                                        NULL,
1094                                        NULL,
1095                                 /*144*/NULL,
1096                                        NULL,
1097                                        NULL,
1098                                        NULL
1099 };
1100 
1101 /*MC
1102    MATCOMPOSITE - A matrix defined by the sum (or product) of one or more matrices.
1103     The matrices need to have a correct size and parallel layout for the sum or product to be valid.
1104 
1105    Notes:
1106     to use the product of the matrices call MatCompositeSetType(mat,MAT_COMPOSITE_MULTIPLICATIVE);
1107 
1108   Level: advanced
1109 
1110 .seealso: `MatCreateComposite()`, `MatCompositeSetScalings()`, `MatCompositeAddMat()`, `MatSetType()`, `MatCompositeSetType()`, `MatCompositeGetType()`, `MatCompositeSetMatStructure()`, `MatCompositeGetMatStructure()`, `MatCompositeMerge()`, `MatCompositeSetMergeType()`, `MatCompositeGetNumberMat()`, `MatCompositeGetMat()`
1111 M*/
1112 
1113 PETSC_EXTERN PetscErrorCode MatCreate_Composite(Mat A)
1114 {
1115   Mat_Composite  *b;
1116 
1117   PetscFunctionBegin;
1118   PetscCall(PetscNewLog(A,&b));
1119   A->data = (void*)b;
1120   PetscCall(PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps)));
1121 
1122   PetscCall(PetscLayoutSetUp(A->rmap));
1123   PetscCall(PetscLayoutSetUp(A->cmap));
1124 
1125   A->assembled    = PETSC_TRUE;
1126   A->preallocated = PETSC_TRUE;
1127   b->type         = MAT_COMPOSITE_ADDITIVE;
1128   b->scale        = 1.0;
1129   b->nmat         = 0;
1130   b->merge        = PETSC_FALSE;
1131   b->mergetype    = MAT_COMPOSITE_MERGE_RIGHT;
1132   b->structure    = DIFFERENT_NONZERO_PATTERN;
1133   b->merge_mvctx  = PETSC_TRUE;
1134 
1135   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatCompositeAddMat_C",MatCompositeAddMat_Composite));
1136   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatCompositeSetType_C",MatCompositeSetType_Composite));
1137   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatCompositeGetType_C",MatCompositeGetType_Composite));
1138   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatCompositeSetMergeType_C",MatCompositeSetMergeType_Composite));
1139   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatCompositeSetMatStructure_C",MatCompositeSetMatStructure_Composite));
1140   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatCompositeGetMatStructure_C",MatCompositeGetMatStructure_Composite));
1141   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatCompositeMerge_C",MatCompositeMerge_Composite));
1142   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatCompositeGetNumberMat_C",MatCompositeGetNumberMat_Composite));
1143   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatCompositeGetMat_C",MatCompositeGetMat_Composite));
1144   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatCompositeSetScalings_C",MatCompositeSetScalings_Composite));
1145 
1146   PetscCall(PetscObjectChangeTypeName((PetscObject)A,MATCOMPOSITE));
1147   PetscFunctionReturn(0);
1148 }
1149