xref: /petsc/src/mat/interface/matproduct.c (revision e01e264644ab2c63b2b91f0ca8430547dde3f5f0)
1 
2 /*
3     Routines for matrix products. Calling procedure:
4 
5     MatProductCreate(A,B,C,&D); or MatProductCreateWithMat(A,B,C,D)
6     MatProductSetType(D, MATPRODUCT_AB/AtB/ABt/PtAP/RARt/ABC)
7     MatProductSetAlgorithm(D, alg)
8     MatProductSetFill(D,fill)
9     MatProductSetFromOptions(D)
10       -> MatProductSetFromOptions_Private(D)
11            # Check matrix global sizes
12            if the matrices have the same setfromoptions routine, use it
13            if not, try:
14              -> Query MatProductSetFromOptions_Atype_Btype_Ctype_C(D) from A, B and C (in order)
15              if found -> run the specific setup that must set the symbolic operation (these callbacks should never fail)
16            if callback not found or no symbolic operation set
17              -> Query MatProductSetFromOptions_anytype_C(D) from A, B and C (in order) (e.g, matrices may have inner matrices like MATTRANPOSEMAT)
18            if dispatch found but combination still not present do
19              -> check if B is dense and product type AtB or AB -> if true, basic looping of dense columns
20              -> check if triple product (PtAP, RARt or ABC) -> if true, set the Basic routines
21 
22     #  The setfromoptions calls MatProductSetFromOptions_Atype_Btype_Ctype should
23     #    Check matrix local sizes for mpi matrices
24     #    Set default algorithm
25     #    Get runtime option
26     #    Set D->ops->productsymbolic = MatProductSymbolic_productype_Atype_Btype_Ctype if found
27 
28     MatProductSymbolic(D)
29       # Call MatProductSymbolic_productype_Atype_Btype_Ctype()
30         the callback must set the numeric phase D->ops->productnumeric = MatProductNumeric_productype_Atype_Btype_Ctype
31 
32     MatProductNumeric(D)
33       # Call the numeric phase
34 
35     # The symbolic phases are allowed to set extra data structures and attach those to the product
36     # this additional data can be reused between multiple numeric phases with the same matrices
37     # if not needed, call
38     MatProductClear(D)
39 */
40 
41 #include <petsc/private/matimpl.h>      /*I "petscmat.h" I*/
42 
43 const char *const MatProductTypes[] = {"UNSPECIFIED","AB","AtB","ABt","PtAP","RARt","ABC"};
44 
45 /* these are basic implementations relying on the old function pointers
46  * they are dangerous and should be removed in the future */
47 static PetscErrorCode MatProductNumeric_PtAP_Basic(Mat C)
48 {
49   PetscErrorCode ierr;
50   Mat_Product    *product = C->product;
51   Mat            P = product->B,AP = product->Dwork;
52 
53   PetscFunctionBegin;
54   /* AP = A*P */
55   ierr = MatProductNumeric(AP);CHKERRQ(ierr);
56   /* C = P^T*AP */
57   if (!C->ops->transposematmultnumeric) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Missing numeric stage");
58   ierr = (*C->ops->transposematmultnumeric)(P,AP,C);CHKERRQ(ierr);
59   PetscFunctionReturn(0);
60 }
61 
62 static PetscErrorCode MatProductSymbolic_PtAP_Basic(Mat C)
63 {
64   PetscErrorCode ierr;
65   Mat_Product    *product = C->product;
66   Mat            A=product->A,P=product->B,AP;
67   PetscReal      fill=product->fill;
68 
69   PetscFunctionBegin;
70   ierr = PetscInfo2((PetscObject)C,"for A %s, P %s is used\n",((PetscObject)product->A)->type_name,((PetscObject)product->B)->type_name);CHKERRQ(ierr);
71   /* AP = A*P */
72   ierr = MatProductCreate(A,P,NULL,&AP);CHKERRQ(ierr);
73   ierr = MatProductSetType(AP,MATPRODUCT_AB);CHKERRQ(ierr);
74   ierr = MatProductSetAlgorithm(AP,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
75   ierr = MatProductSetFill(AP,fill);CHKERRQ(ierr);
76   ierr = MatProductSetFromOptions(AP);CHKERRQ(ierr);
77   ierr = MatProductSymbolic(AP);CHKERRQ(ierr);
78 
79   /* C = P^T*AP */
80   ierr = MatProductSetType(C,MATPRODUCT_AtB);CHKERRQ(ierr);
81   ierr = MatProductSetAlgorithm(C,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
82   product->A = P;
83   product->B = AP;
84   ierr = MatProductSetFromOptions(C);CHKERRQ(ierr);
85   ierr = MatProductSymbolic(C);CHKERRQ(ierr);
86 
87   /* resume user's original input matrix setting for A and B */
88   product->A     = A;
89   product->B     = P;
90   product->Dwork = AP;
91 
92   C->ops->productnumeric = MatProductNumeric_PtAP_Basic;
93   PetscFunctionReturn(0);
94 }
95 
96 static PetscErrorCode MatProductNumeric_RARt_Basic(Mat C)
97 {
98   PetscErrorCode ierr;
99   Mat_Product    *product = C->product;
100   Mat            R=product->B,RA=product->Dwork;
101 
102   PetscFunctionBegin;
103   /* RA = R*A */
104   ierr = MatProductNumeric(RA);CHKERRQ(ierr);
105   /* C = RA*R^T */
106   if (!C->ops->mattransposemultnumeric) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Missing numeric stage");
107   ierr = (*C->ops->mattransposemultnumeric)(RA,R,C);CHKERRQ(ierr);
108   PetscFunctionReturn(0);
109 }
110 
111 static PetscErrorCode MatProductSymbolic_RARt_Basic(Mat C)
112 {
113   PetscErrorCode ierr;
114   Mat_Product    *product = C->product;
115   Mat            A=product->A,R=product->B,RA;
116   PetscReal      fill=product->fill;
117 
118   PetscFunctionBegin;
119   ierr = PetscInfo2((PetscObject)C,"for A %s, R %s is used\n",((PetscObject)product->A)->type_name,((PetscObject)product->B)->type_name);CHKERRQ(ierr);
120   /* RA = R*A */
121   ierr = MatProductCreate(R,A,NULL,&RA);CHKERRQ(ierr);
122   ierr = MatProductSetType(RA,MATPRODUCT_AB);CHKERRQ(ierr);
123   ierr = MatProductSetAlgorithm(RA,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
124   ierr = MatProductSetFill(RA,fill);CHKERRQ(ierr);
125   ierr = MatProductSetFromOptions(RA);CHKERRQ(ierr);
126   ierr = MatProductSymbolic(RA);CHKERRQ(ierr);
127 
128   /* C = RA*R^T */
129   ierr = MatProductSetType(C,MATPRODUCT_ABt);CHKERRQ(ierr);
130   ierr = MatProductSetAlgorithm(C,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
131   product->A = RA;
132   ierr = MatProductSetFromOptions(C);CHKERRQ(ierr);
133   ierr = MatProductSymbolic(C);CHKERRQ(ierr);
134 
135   /* resume user's original input matrix setting for A */
136   product->A     = A;
137   product->Dwork = RA; /* save here so it will be destroyed with product C */
138   C->ops->productnumeric = MatProductNumeric_RARt_Basic;
139   PetscFunctionReturn(0);
140 }
141 
142 static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat)
143 {
144   PetscErrorCode ierr;
145   Mat_Product    *product = mat->product;
146   Mat            A=product->A,BC=product->Dwork;
147 
148   PetscFunctionBegin;
149   /* Numeric BC = B*C */
150   ierr = MatProductNumeric(BC);CHKERRQ(ierr);
151   /* Numeric mat = A*BC */
152   if (!mat->ops->transposematmultnumeric) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric stage");
153   ierr = (*mat->ops->matmultnumeric)(A,BC,mat);CHKERRQ(ierr);
154   PetscFunctionReturn(0);
155 }
156 
157 static PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat)
158 {
159   PetscErrorCode ierr;
160   Mat_Product    *product = mat->product;
161   Mat            B=product->B,C=product->C,BC;
162   PetscReal      fill=product->fill;
163 
164   PetscFunctionBegin;
165   ierr = PetscInfo3((PetscObject)mat,"for A %s, B %s, C %s is used\n",((PetscObject)product->A)->type_name,((PetscObject)product->B)->type_name,((PetscObject)product->C)->type_name);CHKERRQ(ierr);
166   /* Symbolic BC = B*C */
167   ierr = MatProductCreate(B,C,NULL,&BC);CHKERRQ(ierr);
168   ierr = MatProductSetType(BC,MATPRODUCT_AB);CHKERRQ(ierr);
169   ierr = MatProductSetAlgorithm(BC,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
170   ierr = MatProductSetFill(BC,fill);CHKERRQ(ierr);
171   ierr = MatProductSetFromOptions(BC);CHKERRQ(ierr);
172   ierr = MatProductSymbolic(BC);CHKERRQ(ierr);
173 
174   /* Symbolic mat = A*BC */
175   ierr = MatProductSetType(mat,MATPRODUCT_AB);CHKERRQ(ierr);
176   ierr = MatProductSetAlgorithm(mat,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
177   product->B     = BC;
178   product->Dwork = BC;
179   ierr = MatProductSetFromOptions(mat);CHKERRQ(ierr);
180   ierr = MatProductSymbolic(mat);CHKERRQ(ierr);
181 
182   /* resume user's original input matrix setting for B */
183   product->B = B;
184   mat->ops->productnumeric = MatProductNumeric_ABC_Basic;
185   PetscFunctionReturn(0);
186 }
187 
188 static PetscErrorCode MatProductSymbolic_Basic(Mat mat)
189 {
190   PetscErrorCode ierr;
191   Mat_Product    *product = mat->product;
192 
193   PetscFunctionBegin;
194   switch (product->type) {
195   case MATPRODUCT_PtAP:
196     ierr = MatProductSymbolic_PtAP_Basic(mat);CHKERRQ(ierr);
197     break;
198   case MATPRODUCT_RARt:
199     ierr = MatProductSymbolic_RARt_Basic(mat);CHKERRQ(ierr);
200     break;
201   case MATPRODUCT_ABC:
202     ierr = MatProductSymbolic_ABC_Basic(mat);CHKERRQ(ierr);
203     break;
204   default: SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[product->type]);
205   }
206   PetscFunctionReturn(0);
207 }
208 
209 /* ----------------------------------------------- */
210 /*@C
211    MatProductReplaceMats - Replace input matrices for a matrix product.
212 
213    Collective on Mat
214 
215    Input Parameters:
216 +  A - the matrix or NULL if not being replaced
217 .  B - the matrix or NULL if not being replaced
218 .  C - the matrix or NULL if not being replaced
219 -  D - the matrix product
220 
221    Level: intermediate
222 
223    Notes:
224      To reuse the symbolic phase, input matrices must have exactly the same data structure as the replaced one.
225      If the type of any of the input matrices is different than what previously used, the product is cleared and MatProductSetFromOptions()/MatProductSymbolic() are invoked again.
226 
227 .seealso: MatProductCreate(), MatProductSetFromOptions(), MatProductSymbolic(). MatProductClear()
228 @*/
229 PetscErrorCode MatProductReplaceMats(Mat A,Mat B,Mat C,Mat D)
230 {
231   PetscErrorCode ierr;
232   Mat_Product    *product;
233   PetscBool      flgA = PETSC_TRUE,flgB = PETSC_TRUE,flgC = PETSC_TRUE;
234 
235   PetscFunctionBegin;
236   PetscValidHeaderSpecific(D,MAT_CLASSID,4);
237   MatCheckProduct(D,4);
238   product = D->product;
239   if (A) {
240     PetscValidHeaderSpecific(A,MAT_CLASSID,1);
241     ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);
242     ierr = PetscObjectTypeCompare((PetscObject)product->A,((PetscObject)A)->type_name,&flgA);CHKERRQ(ierr);
243     ierr = MatDestroy(&product->A);CHKERRQ(ierr);
244     product->A = A;
245   }
246   if (B) {
247     PetscValidHeaderSpecific(B,MAT_CLASSID,2);
248     ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr);
249     ierr = PetscObjectTypeCompare((PetscObject)product->B,((PetscObject)B)->type_name,&flgB);CHKERRQ(ierr);
250     ierr = MatDestroy(&product->B);CHKERRQ(ierr);
251     product->B = B;
252   }
253   if (C) {
254     PetscValidHeaderSpecific(C,MAT_CLASSID,3);
255     ierr = PetscObjectReference((PetscObject)C);CHKERRQ(ierr);
256     ierr = PetscObjectTypeCompare((PetscObject)product->C,((PetscObject)C)->type_name,&flgC);CHKERRQ(ierr);
257     ierr = MatDestroy(&product->C);CHKERRQ(ierr);
258     product->C = C;
259   }
260   /* Any of the replaced mats is of a different type, reset */
261   if (!flgA || !flgB || !flgC) {
262     if (D->product->destroy) {
263       ierr = (*D->product->destroy)(D->product->data);CHKERRQ(ierr);
264     }
265     D->product->destroy = NULL;
266     D->product->data = NULL;
267     if (D->ops->productnumeric || D->ops->productsymbolic) {
268       ierr = MatProductSetFromOptions(D);CHKERRQ(ierr);
269       ierr = MatProductSymbolic(D);CHKERRQ(ierr);
270     }
271   }
272   PetscFunctionReturn(0);
273 }
274 
275 static PetscErrorCode MatProductNumeric_X_Dense(Mat C)
276 {
277   PetscErrorCode ierr;
278   Mat_Product    *product = C->product;
279   Mat            A = product->A, B = product->B;
280   PetscInt       k, K = B->cmap->N;
281   PetscBool      t = PETSC_TRUE,iscuda = PETSC_FALSE;
282   PetscBool      Bcpu = PETSC_TRUE, Ccpu = PETSC_TRUE;
283   char           *Btype = NULL,*Ctype = NULL;
284 
285   PetscFunctionBegin;
286   switch (product->type) {
287   case MATPRODUCT_AB:
288     t = PETSC_FALSE;
289   case MATPRODUCT_AtB:
290     break;
291   default: SETERRQ3(PetscObjectComm((PetscObject)C),PETSC_ERR_SUP,"MatProductNumeric type %s not supported for %s and %s matrices",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name);
292   }
293   if (PetscDefined(HAVE_CUDA)) {
294     VecType vtype;
295 
296     ierr = MatGetVecType(A,&vtype);CHKERRQ(ierr);
297     ierr = PetscStrcmp(vtype,VECCUDA,&iscuda);CHKERRQ(ierr);
298     if (!iscuda) {
299       ierr = PetscStrcmp(vtype,VECSEQCUDA,&iscuda);CHKERRQ(ierr);
300     }
301     if (!iscuda) {
302       ierr = PetscStrcmp(vtype,VECMPICUDA,&iscuda);CHKERRQ(ierr);
303     }
304     if (iscuda) { /* Make sure we have up-to-date data on the GPU */
305       ierr = PetscStrallocpy(((PetscObject)B)->type_name,&Btype);CHKERRQ(ierr);
306       ierr = PetscStrallocpy(((PetscObject)C)->type_name,&Ctype);CHKERRQ(ierr);
307       ierr = MatConvert(B,MATDENSECUDA,MAT_INPLACE_MATRIX,&B);CHKERRQ(ierr);
308       if (!C->assembled) { /* need to flag the matrix as assembled, otherwise MatConvert will complain */
309         ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
310         ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
311       }
312       ierr = MatConvert(C,MATDENSECUDA,MAT_INPLACE_MATRIX,&C);CHKERRQ(ierr);
313     } else { /* Make sure we have up-to-date data on the CPU */
314 #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_VIENNACL)
315       Bcpu = B->boundtocpu;
316       Ccpu = C->boundtocpu;
317 #endif
318       ierr = MatBindToCPU(B,PETSC_TRUE);CHKERRQ(ierr);
319       ierr = MatBindToCPU(C,PETSC_TRUE);CHKERRQ(ierr);
320     }
321   }
322   for (k=0;k<K;k++) {
323     Vec x,y;
324 
325     ierr = MatDenseGetColumnVecRead(B,k,&x);CHKERRQ(ierr);
326     ierr = MatDenseGetColumnVecWrite(C,k,&y);CHKERRQ(ierr);
327     if (t) {
328       ierr = MatMultTranspose(A,x,y);CHKERRQ(ierr);
329     } else {
330       ierr = MatMult(A,x,y);CHKERRQ(ierr);
331     }
332     ierr = MatDenseRestoreColumnVecRead(B,k,&x);CHKERRQ(ierr);
333     ierr = MatDenseRestoreColumnVecWrite(C,k,&y);CHKERRQ(ierr);
334   }
335   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
336   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
337   if (PetscDefined(HAVE_CUDA)) {
338     if (iscuda) {
339       ierr = MatConvert(B,Btype,MAT_INPLACE_MATRIX,&B);CHKERRQ(ierr);
340       ierr = MatConvert(C,Ctype,MAT_INPLACE_MATRIX,&C);CHKERRQ(ierr);
341     } else {
342       ierr = MatBindToCPU(B,Bcpu);CHKERRQ(ierr);
343       ierr = MatBindToCPU(C,Ccpu);CHKERRQ(ierr);
344     }
345   }
346   ierr = PetscFree(Btype);CHKERRQ(ierr);
347   ierr = PetscFree(Ctype);CHKERRQ(ierr);
348   PetscFunctionReturn(0);
349 }
350 
351 static PetscErrorCode MatProductSymbolic_X_Dense(Mat C)
352 {
353   PetscErrorCode ierr;
354   Mat_Product    *product = C->product;
355   Mat            A = product->A, B = product->B;
356   PetscBool      isdense;
357 
358   PetscFunctionBegin;
359   switch (product->type) {
360   case MATPRODUCT_AB:
361     ierr = MatSetSizes(C,A->rmap->n,B->cmap->n,A->rmap->N,B->cmap->N);CHKERRQ(ierr);
362     break;
363   case MATPRODUCT_AtB:
364     ierr = MatSetSizes(C,A->cmap->n,B->cmap->n,A->cmap->N,B->cmap->N);CHKERRQ(ierr);
365     break;
366   default: SETERRQ3(PetscObjectComm((PetscObject)C),PETSC_ERR_SUP,"MatProductSymbolic type %s not supported for %s and %s matrices",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name);
367   }
368   ierr = PetscObjectBaseTypeCompareAny((PetscObject)C,&isdense,MATSEQDENSE,MATMPIDENSE,"");CHKERRQ(ierr);
369   if (!isdense) {
370     ierr = MatSetType(C,((PetscObject)B)->type_name);CHKERRQ(ierr);
371     /* If matrix type of C was not set or not dense, we need to reset the pointer */
372     C->ops->productsymbolic = MatProductSymbolic_X_Dense;
373   }
374   C->ops->productnumeric = MatProductNumeric_X_Dense;
375   ierr = MatSetUp(C);CHKERRQ(ierr);
376   PetscFunctionReturn(0);
377 }
378 
379 /* a single driver to query the dispatching */
380 static PetscErrorCode MatProductSetFromOptions_Private(Mat mat)
381 {
382   PetscErrorCode    ierr;
383   Mat_Product       *product = mat->product;
384   PetscInt          Am,An,Bm,Bn,Cm,Cn;
385   Mat               A = product->A,B = product->B,C = product->C;
386   const char* const Bnames[] = { "B", "R", "P" };
387   const char*       bname;
388   PetscErrorCode    (*fA)(Mat);
389   PetscErrorCode    (*fB)(Mat);
390   PetscErrorCode    (*fC)(Mat);
391   PetscErrorCode    (*f)(Mat)=NULL;
392 
393   PetscFunctionBegin;
394   mat->ops->productsymbolic = NULL;
395   mat->ops->productnumeric = NULL;
396   if (product->type == MATPRODUCT_UNSPECIFIED) PetscFunctionReturn(0);
397   if (!A) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing A mat");
398   if (!B) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing B mat");
399   if (product->type == MATPRODUCT_ABC && !C) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing C mat");
400   if (product->type != MATPRODUCT_ABC) C = NULL; /* do not use C if not needed */
401   if (product->type == MATPRODUCT_RARt) bname = Bnames[1];
402   else if (product->type == MATPRODUCT_PtAP) bname = Bnames[2];
403   else bname = Bnames[0];
404 
405   /* Check matrices sizes */
406   Am = A->rmap->N;
407   An = A->cmap->N;
408   Bm = B->rmap->N;
409   Bn = B->cmap->N;
410   Cm = C ? C->rmap->N : 0;
411   Cn = C ? C->cmap->N : 0;
412   if (product->type == MATPRODUCT_RARt || product->type == MATPRODUCT_ABt) { PetscInt t = Bn; Bn = Bm; Bm = t; }
413   if (product->type == MATPRODUCT_AtB) { PetscInt t = An; An = Am; Am = t; }
414   if (An != Bm) SETERRQ7(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_SIZ,"Matrix dimensions of A and %s are incompatible for MatProductType %s: A %Dx%D, %s %Dx%D",bname,MatProductTypes[product->type],A->rmap->N,A->cmap->N,bname,B->rmap->N,B->cmap->N);
415   if (Cm && Cm != Bn) SETERRQ5(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_SIZ,"Matrix dimensions of B and C are incompatible for MatProductType %s: B %Dx%D, C %Dx%D",MatProductTypes[product->type],B->rmap->N,B->cmap->N,Cm,Cn);
416 
417   fA = A->ops->productsetfromoptions;
418   fB = B->ops->productsetfromoptions;
419   fC = C ? C->ops->productsetfromoptions : fA;
420   if (C) {
421     ierr = PetscInfo5(mat,"MatProductType %s for A %s, %s %s, C %s\n",MatProductTypes[product->type],((PetscObject)A)->type_name,bname,((PetscObject)B)->type_name,((PetscObject)C)->type_name);CHKERRQ(ierr);
422   } else {
423     ierr = PetscInfo4(mat,"MatProductType %s for A %s, %s %s\n",MatProductTypes[product->type],((PetscObject)A)->type_name,bname,((PetscObject)B)->type_name);CHKERRQ(ierr);
424   }
425   if (fA == fB && fA == fC && fA) {
426     ierr = PetscInfo(mat,"  matching op\n");CHKERRQ(ierr);
427     ierr = (*fA)(mat);CHKERRQ(ierr);
428   } else {
429     /* query MatProductSetFromOptions_Atype_Btype_Ctype */
430     char  mtypes[256];
431     ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
432     ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
433     ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
434     ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
435     if (C) {
436       ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
437       ierr = PetscStrlcat(mtypes,((PetscObject)C)->type_name,sizeof(mtypes));CHKERRQ(ierr);
438     }
439     ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
440 
441     ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
442     ierr = PetscInfo2(mat,"  querying %s from A? %p\n",mtypes,f);CHKERRQ(ierr);
443     if (!f) {
444       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
445       ierr = PetscInfo3(mat,"  querying %s from %s? %p\n",mtypes,bname,f);CHKERRQ(ierr);
446     }
447     if (!f && C) {
448       ierr = PetscObjectQueryFunction((PetscObject)C,mtypes,&f);CHKERRQ(ierr);
449       ierr = PetscInfo2(mat,"  querying %s from C? %p\n",mtypes,f);CHKERRQ(ierr);
450     }
451     if (f) { ierr = (*f)(mat);CHKERRQ(ierr); }
452 
453     /* We may have found f but it did not succeed */
454     /* some matrices (i.e. MATTRANSPOSE, MATSHELL constructed from MatConvert), knows what to do with their inner matrices */
455     if (!mat->ops->productsymbolic) {
456       ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_anytype_C",sizeof(mtypes));CHKERRQ(ierr);
457       ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
458       ierr = PetscInfo2(mat,"  querying %s from A? %p\n",mtypes,f);CHKERRQ(ierr);
459       if (!f) {
460         ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
461         ierr = PetscInfo3(mat,"  querying %s from %s? %p\n",mtypes,bname,f);CHKERRQ(ierr);
462       }
463       if (!f && C) {
464         ierr = PetscObjectQueryFunction((PetscObject)C,mtypes,&f);CHKERRQ(ierr);
465         ierr = PetscInfo2(mat,"  querying %s from C? %p\n",mtypes,f);CHKERRQ(ierr);
466       }
467     }
468     if (f) { ierr = (*f)(mat);CHKERRQ(ierr); }
469   }
470 
471   /* We may have found f but it did not succeed */
472   if (!mat->ops->productsymbolic) {
473     /* we can still compute the product if B is of type dense */
474     if (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB) {
475       PetscBool isdense;
476 
477       ierr = PetscObjectBaseTypeCompareAny((PetscObject)B,&isdense,MATSEQDENSE,MATMPIDENSE,"");CHKERRQ(ierr);
478       if (isdense) {
479 
480         mat->ops->productsymbolic = MatProductSymbolic_X_Dense;
481         ierr = PetscInfo(mat,"  using basic looping over columns of a dense matrix\n");CHKERRQ(ierr);
482       }
483     } else if (product->type != MATPRODUCT_ABt) { /* use MatProductSymbolic/Numeric_Basic() for triple products only */
484       /*
485          TODO: this should be changed to a proper setfromoptions, not setting the symbolic pointer here, because we do not know if
486                the compination will succeed. In order to be sure, we need MatProductGetProductType to return the type of the result
487                before computing the symbolic phase
488       */
489       ierr = PetscInfo(mat,"  symbolic product not supported, using MatProductSymbolic_Basic() implementation\n");CHKERRQ(ierr);
490       mat->ops->productsymbolic = MatProductSymbolic_Basic;
491     }
492   }
493   if (!mat->ops->productsymbolic) {
494     ierr = PetscInfo(mat,"  symbolic product is not supported\n");CHKERRQ(ierr);
495   }
496   PetscFunctionReturn(0);
497 }
498 
499 /*@C
500    MatProductSetFromOptions - Creates a matrix product where the type, the algorithm etc are determined from the options database.
501 
502    Logically Collective on Mat
503 
504    Input Parameter:
505 .  mat - the matrix
506 
507    Options Database Keys:
508 .    -mat_product_clear - Clear intermediate data structures after MatProductNumeric() has been called
509 
510    Level: intermediate
511 
512 .seealso: MatSetFromOptions(), MatProductCreate(), MatProductCreateWithMat()
513 @*/
514 PetscErrorCode MatProductSetFromOptions(Mat mat)
515 {
516   PetscErrorCode ierr;
517 
518   PetscFunctionBegin;
519   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
520   MatCheckProduct(mat,1);
521   if (mat->product->data) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Cannot call MatProductSetFromOptions with already present data");
522   ierr = PetscObjectOptionsBegin((PetscObject)mat);CHKERRQ(ierr);
523   ierr = PetscOptionsBool("-mat_product_clear","Clear intermediate data structures after MatProductNumeric() has been called","MatProductClear",mat->product->clear,&mat->product->clear,NULL);CHKERRQ(ierr);
524   ierr = PetscOptionsDeprecated("-mat_freeintermediatedatastructures","-mat_product_clear","3.13","Or call MatProductClear() after MatProductNumeric()");CHKERRQ(ierr);
525   ierr = PetscOptionsEnd();CHKERRQ(ierr);
526   ierr = MatProductSetFromOptions_Private(mat);CHKERRQ(ierr);
527   if (!mat->product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing product after setup phase");
528   PetscFunctionReturn(0);
529 }
530 
531 /*@C
532    MatProductView - View a MatProduct
533 
534    Logically Collective on Mat
535 
536    Input Parameter:
537 .  mat - the matrix obtained with MatProductCreate() or MatProductCreateWithMat()
538 
539    Level: intermediate
540 
541 .seealso: MatView(), MatProductCreate(), MatProductCreateWithMat()
542 @*/
543 PetscErrorCode MatProductView(Mat mat, PetscViewer viewer)
544 {
545   PetscErrorCode ierr;
546 
547   PetscFunctionBegin;
548   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
549   if (!mat->product) PetscFunctionReturn(0);
550   if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat),&viewer);CHKERRQ(ierr);}
551   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
552   PetscCheckSameComm(mat,1,viewer,2);
553   if (mat->product->view) {
554     ierr = (*mat->product->view)(mat,viewer);CHKERRQ(ierr);
555   }
556   PetscFunctionReturn(0);
557 }
558 
559 /* ----------------------------------------------- */
560 /* these are basic implementations relying on the old function pointers
561  * they are dangerous and should be removed in the future */
562 PetscErrorCode MatProductNumeric_AB(Mat mat)
563 {
564   PetscErrorCode ierr;
565   Mat_Product    *product = mat->product;
566   Mat            A=product->A,B=product->B;
567 
568   PetscFunctionBegin;
569   if (!mat->ops->matmultnumeric) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric implementation of product %s for mat %s",MatProductTypes[product->type],((PetscObject)mat)->type_name);
570   ierr = (*mat->ops->matmultnumeric)(A,B,mat);CHKERRQ(ierr);
571   PetscFunctionReturn(0);
572 }
573 
574 PetscErrorCode MatProductNumeric_AtB(Mat mat)
575 {
576   PetscErrorCode ierr;
577   Mat_Product    *product = mat->product;
578   Mat            A=product->A,B=product->B;
579 
580   PetscFunctionBegin;
581   if (!mat->ops->transposematmultnumeric) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric implementation of product %s for mat %s",MatProductTypes[product->type],((PetscObject)mat)->type_name);
582   ierr = (*mat->ops->transposematmultnumeric)(A,B,mat);CHKERRQ(ierr);
583   PetscFunctionReturn(0);
584 }
585 
586 PetscErrorCode MatProductNumeric_ABt(Mat mat)
587 {
588   PetscErrorCode ierr;
589   Mat_Product    *product = mat->product;
590   Mat            A=product->A,B=product->B;
591 
592   PetscFunctionBegin;
593   if (!mat->ops->mattransposemultnumeric) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric implementation of product %s for mat %s",MatProductTypes[product->type],((PetscObject)mat)->type_name);
594   ierr = (*mat->ops->mattransposemultnumeric)(A,B,mat);CHKERRQ(ierr);
595   PetscFunctionReturn(0);
596 }
597 
598 PetscErrorCode MatProductNumeric_PtAP(Mat mat)
599 {
600   PetscErrorCode ierr;
601   Mat_Product    *product = mat->product;
602   Mat            A=product->A,B=product->B;
603 
604   PetscFunctionBegin;
605   if (!mat->ops->ptapnumeric) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric implementation of product %s for mat %s",MatProductTypes[product->type],((PetscObject)mat)->type_name);
606   ierr = (*mat->ops->ptapnumeric)(A,B,mat);CHKERRQ(ierr);
607   PetscFunctionReturn(0);
608 }
609 
610 PetscErrorCode MatProductNumeric_RARt(Mat mat)
611 {
612   PetscErrorCode ierr;
613   Mat_Product    *product = mat->product;
614   Mat            A=product->A,B=product->B;
615 
616   PetscFunctionBegin;
617   if (!mat->ops->rartnumeric) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric implementation of product %s for mat %s",MatProductTypes[product->type],((PetscObject)mat)->type_name);
618   ierr = (*mat->ops->rartnumeric)(A,B,mat);CHKERRQ(ierr);
619   PetscFunctionReturn(0);
620 }
621 
622 PetscErrorCode MatProductNumeric_ABC(Mat mat)
623 {
624   PetscErrorCode ierr;
625   Mat_Product    *product = mat->product;
626   Mat            A=product->A,B=product->B,C=product->C;
627 
628   PetscFunctionBegin;
629   if (!mat->ops->matmatmultnumeric) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric implementation of product %s for mat %s",MatProductTypes[product->type],((PetscObject)mat)->type_name);
630   ierr = (*mat->ops->matmatmultnumeric)(A,B,C,mat);CHKERRQ(ierr);
631   PetscFunctionReturn(0);
632 }
633 
634 /* ----------------------------------------------- */
635 
636 /*@
637    MatProductNumeric - Implement a matrix product with numerical values.
638 
639    Collective on Mat
640 
641    Input/Output Parameter:
642 .  mat - the matrix holding the product
643 
644    Level: intermediate
645 
646    Notes: MatProductSymbolic() must have been called on mat before calling this function
647 
648 .seealso: MatProductCreate(), MatSetType(), MatProductSymbolic()
649 @*/
650 PetscErrorCode MatProductNumeric(Mat mat)
651 {
652   PetscErrorCode ierr;
653   PetscLogEvent  eventtype=-1;
654 
655   PetscFunctionBegin;
656   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
657   MatCheckProduct(mat,1);
658   /* log event */
659   switch (mat->product->type) {
660   case MATPRODUCT_AB:
661     eventtype = MAT_MatMultNumeric;
662     break;
663   case MATPRODUCT_AtB:
664     eventtype = MAT_TransposeMatMultNumeric;
665     break;
666   case MATPRODUCT_ABt:
667     eventtype = MAT_MatTransposeMultNumeric;
668     break;
669   case MATPRODUCT_PtAP:
670     eventtype = MAT_PtAPNumeric;
671     break;
672   case MATPRODUCT_RARt:
673     eventtype = MAT_RARtNumeric;
674     break;
675   case MATPRODUCT_ABC:
676     eventtype = MAT_MatMatMultNumeric;
677     break;
678   default: SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[mat->product->type]);
679   }
680   if (mat->ops->productnumeric) {
681     ierr = PetscLogEventBegin(eventtype,mat,0,0,0);CHKERRQ(ierr);
682     ierr = (*mat->ops->productnumeric)(mat);CHKERRQ(ierr);
683     ierr = PetscLogEventEnd(eventtype,mat,0,0,0);CHKERRQ(ierr);
684   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Call MatProductSymbolic() first");
685   if (!mat->product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing product after numeric phase");
686   if (mat->product->clear) {
687     ierr = MatProductClear(mat);CHKERRQ(ierr);
688   }
689   PetscFunctionReturn(0);
690 }
691 
692 /* ----------------------------------------------- */
693 /* these are basic implementations relying on the old function pointers
694  * they are dangerous and should be removed in the future */
695 PetscErrorCode MatProductSymbolic_AB(Mat mat)
696 {
697   PetscErrorCode ierr;
698   Mat_Product    *product = mat->product;
699   Mat            A=product->A,B=product->B;
700 
701   PetscFunctionBegin;
702   if (!mat->ops->matmultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]);
703   ierr = (*mat->ops->matmultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr);
704   mat->ops->productnumeric = MatProductNumeric_AB;
705   PetscFunctionReturn(0);
706 }
707 
708 PetscErrorCode MatProductSymbolic_AtB(Mat mat)
709 {
710   PetscErrorCode ierr;
711   Mat_Product    *product = mat->product;
712   Mat            A=product->A,B=product->B;
713 
714   PetscFunctionBegin;
715   if (!mat->ops->transposematmultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]);
716   ierr = (*mat->ops->transposematmultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr);
717   mat->ops->productnumeric = MatProductNumeric_AtB;
718   PetscFunctionReturn(0);
719 }
720 
721 PetscErrorCode MatProductSymbolic_ABt(Mat mat)
722 {
723   PetscErrorCode ierr;
724   Mat_Product    *product = mat->product;
725   Mat            A=product->A,B=product->B;
726 
727   PetscFunctionBegin;
728   if (!mat->ops->mattransposemultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]);
729   ierr = (*mat->ops->mattransposemultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr);
730   mat->ops->productnumeric = MatProductNumeric_ABt;
731   PetscFunctionReturn(0);
732 }
733 
734 PetscErrorCode MatProductSymbolic_ABC(Mat mat)
735 {
736   PetscErrorCode ierr;
737   Mat_Product    *product = mat->product;
738   Mat            A=product->A,B=product->B,C=product->C;
739 
740   PetscFunctionBegin;
741   if (!mat->ops->matmatmultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]);
742   ierr = (*mat->ops->matmatmultsymbolic)(A,B,C,product->fill,mat);CHKERRQ(ierr);
743   mat->ops->productnumeric = MatProductNumeric_ABC;
744   PetscFunctionReturn(0);
745 }
746 
747 /* ----------------------------------------------- */
748 
749 /*@
750    MatProductSymbolic - Perform the symbolic portion of a matrix product, this creates a data structure for use with the numerical produce.
751 
752    Collective on Mat
753 
754    Input/Output Parameter:
755 .  mat - the matrix to hold a product
756 
757    Level: intermediate
758 
759    Notes: MatProductSetFromOptions() must have been called on mat before calling this function
760 
761 .seealso: MatProductCreate(), MatProductCreateWithMat(), MatProductSetFromOptions(), MatProductNumeric(), MatProductSetType(), MatProductSetAlgorithm()
762 @*/
763 PetscErrorCode MatProductSymbolic(Mat mat)
764 {
765   PetscErrorCode ierr;
766   PetscLogEvent  eventtype=-1;
767 
768   PetscFunctionBegin;
769   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
770   MatCheckProduct(mat,1);
771   if (mat->product->data) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Cannot run symbolic phase. Product data not empty");
772   /* log event */
773   switch (mat->product->type) {
774   case MATPRODUCT_AB:
775     eventtype = MAT_MatMultSymbolic;
776     break;
777   case MATPRODUCT_AtB:
778     eventtype = MAT_TransposeMatMultSymbolic;
779     break;
780   case MATPRODUCT_ABt:
781     eventtype = MAT_MatTransposeMultSymbolic;
782     break;
783   case MATPRODUCT_PtAP:
784     eventtype = MAT_PtAPSymbolic;
785     break;
786   case MATPRODUCT_RARt:
787     eventtype = MAT_RARtSymbolic;
788     break;
789   case MATPRODUCT_ABC:
790     eventtype = MAT_MatMatMultSymbolic;
791     break;
792   default: SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[mat->product->type]);
793   }
794 
795   mat->ops->productnumeric = NULL;
796   if (mat->ops->productsymbolic) {
797     ierr = PetscLogEventBegin(eventtype,mat,0,0,0);CHKERRQ(ierr);
798     ierr = (*mat->ops->productsymbolic)(mat);CHKERRQ(ierr);
799     ierr = PetscLogEventEnd(eventtype,mat,0,0,0);CHKERRQ(ierr);
800   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Call MatProductSetFromOptions() first");
801   if (!mat->product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing product after symbolic phase");
802   if (!mat->ops->productnumeric) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Symbolic phase did not specify the numeric phase");
803   PetscFunctionReturn(0);
804 }
805 
806 /*@
807    MatProductSetFill - Set an expected fill of the matrix product.
808 
809    Collective on Mat
810 
811    Input Parameters:
812 +  mat - the matrix product
813 -  fill - expected fill as ratio of nnz(mat)/(nnz(A) + nnz(B) + nnz(C)); use PETSC_DEFAULT if you do not have a good estimate. If the product is a dense matrix, this is irrelevent.
814 
815    Level: intermediate
816 
817 .seealso: MatProductSetType(), MatProductSetAlgorithm(), MatProductCreate()
818 @*/
819 PetscErrorCode MatProductSetFill(Mat mat,PetscReal fill)
820 {
821   PetscFunctionBegin;
822   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
823   MatCheckProduct(mat,1);
824   if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) mat->product->fill = 2.0;
825   else mat->product->fill = fill;
826   PetscFunctionReturn(0);
827 }
828 
829 /*@
830    MatProductSetAlgorithm - Requests a particular algorithm for a matrix product implementation.
831 
832    Collective on Mat
833 
834    Input Parameters:
835 +  mat - the matrix product
836 -  alg - particular implementation algorithm of the matrix product, e.g., MATPRODUCTALGORITHM_DEFAULT.
837 
838    Level: intermediate
839 
840 .seealso: MatProductSetType(), MatProductSetFill(), MatProductCreate(), MatProductAlgorithm
841 @*/
842 PetscErrorCode MatProductSetAlgorithm(Mat mat,MatProductAlgorithm alg)
843 {
844   PetscErrorCode ierr;
845 
846   PetscFunctionBegin;
847   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
848   MatCheckProduct(mat,1);
849   ierr = PetscFree(mat->product->alg);CHKERRQ(ierr);
850   ierr = PetscStrallocpy(alg,&mat->product->alg);CHKERRQ(ierr);
851   PetscFunctionReturn(0);
852 }
853 
854 /*@
855    MatProductSetType - Sets a particular matrix product type
856 
857    Collective on Mat
858 
859    Input Parameters:
860 +  mat - the matrix
861 -  productype   - matrix product type, e.g., MATPRODUCT_AB,MATPRODUCT_AtB,MATPRODUCT_ABt,MATPRODUCT_PtAP,MATPRODUCT_RARt,MATPRODUCT_ABC.
862 
863    Level: intermediate
864 
865 .seealso: MatProductCreate(), MatProductType
866 @*/
867 PetscErrorCode MatProductSetType(Mat mat,MatProductType productype)
868 {
869   PetscErrorCode ierr;
870 
871   PetscFunctionBegin;
872   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
873   MatCheckProduct(mat,1);
874   PetscValidLogicalCollectiveEnum(mat,productype,2);
875   if (productype != mat->product->type) {
876     if (mat->product->destroy) {
877       ierr = (*mat->product->destroy)(mat->product->data);CHKERRQ(ierr);
878     }
879     mat->product->destroy = NULL;
880     mat->product->data = NULL;
881     mat->ops->productsymbolic = NULL;
882     mat->ops->productnumeric  = NULL;
883   }
884   mat->product->type = productype;
885   PetscFunctionReturn(0);
886 }
887 
888 /*@
889    MatProductClear - Clears matrix product internal structure.
890 
891    Collective on Mat
892 
893    Input Parameters:
894 .  mat - the product matrix
895 
896    Level: intermediate
897 
898    Notes: this function should be called to remove any intermediate data used by the product
899           After having called this function, MatProduct operations can no longer be used on mat
900 @*/
901 PetscErrorCode MatProductClear(Mat mat)
902 {
903   PetscErrorCode ierr;
904   Mat_Product    *product = mat->product;
905 
906   PetscFunctionBegin;
907   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
908   if (product) {
909     ierr = MatDestroy(&product->A);CHKERRQ(ierr);
910     ierr = MatDestroy(&product->B);CHKERRQ(ierr);
911     ierr = MatDestroy(&product->C);CHKERRQ(ierr);
912     ierr = PetscFree(product->alg);CHKERRQ(ierr);
913     ierr = MatDestroy(&product->Dwork);CHKERRQ(ierr);
914     if (product->destroy) {
915       ierr = (*product->destroy)(product->data);CHKERRQ(ierr);
916     }
917   }
918   ierr = PetscFree(mat->product);CHKERRQ(ierr);
919   mat->ops->productsymbolic = NULL;
920   mat->ops->productnumeric = NULL;
921   PetscFunctionReturn(0);
922 }
923 
924 /* Create a supporting struct and attach it to the matrix product */
925 PetscErrorCode MatProductCreate_Private(Mat A,Mat B,Mat C,Mat D)
926 {
927   PetscErrorCode ierr;
928   Mat_Product    *product=NULL;
929 
930   PetscFunctionBegin;
931   PetscValidHeaderSpecific(D,MAT_CLASSID,4);
932   if (D->product) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product already present");
933   ierr = PetscNewLog(D,&product);CHKERRQ(ierr);
934   product->A        = A;
935   product->B        = B;
936   product->C        = C;
937   product->type     = MATPRODUCT_UNSPECIFIED;
938   product->Dwork    = NULL;
939   product->api_user = PETSC_FALSE;
940   product->clear    = PETSC_FALSE;
941   D->product        = product;
942 
943   ierr = MatProductSetAlgorithm(D,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
944   ierr = MatProductSetFill(D,PETSC_DEFAULT);CHKERRQ(ierr);
945 
946   ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);
947   ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr);
948   ierr = PetscObjectReference((PetscObject)C);CHKERRQ(ierr);
949   PetscFunctionReturn(0);
950 }
951 
952 /*@
953    MatProductCreateWithMat - Setup a given matrix as a matrix product.
954 
955    Collective on Mat
956 
957    Input Parameters:
958 +  A - the first matrix
959 .  B - the second matrix
960 .  C - the third matrix (optional)
961 -  D - the matrix which will be used as a product
962 
963    Output Parameters:
964 .  D - the product matrix
965 
966    Notes:
967      Any product data attached to D will be cleared
968 
969    Level: intermediate
970 
971 .seealso: MatProductCreate(), MatProductClear()
972 @*/
973 PetscErrorCode MatProductCreateWithMat(Mat A,Mat B,Mat C,Mat D)
974 {
975   PetscErrorCode ierr;
976 
977   PetscFunctionBegin;
978   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
979   PetscValidType(A,1);
980   MatCheckPreallocated(A,1);
981   if (!A->assembled) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
982   if (A->factortype) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
983 
984   PetscValidHeaderSpecific(B,MAT_CLASSID,2);
985   PetscValidType(B,2);
986   MatCheckPreallocated(B,2);
987   if (!B->assembled) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
988   if (B->factortype) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
989 
990   if (C) {
991     PetscValidHeaderSpecific(C,MAT_CLASSID,3);
992     PetscValidType(C,3);
993     MatCheckPreallocated(C,3);
994     if (!C->assembled) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
995     if (C->factortype) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
996   }
997 
998   PetscValidHeaderSpecific(D,MAT_CLASSID,4);
999   PetscValidType(D,4);
1000   MatCheckPreallocated(D,4);
1001   if (!D->assembled) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1002   if (D->factortype) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1003 
1004   /* Create a supporting struct and attach it to D */
1005   ierr = MatProductClear(D);CHKERRQ(ierr);
1006   ierr = MatProductCreate_Private(A,B,C,D);CHKERRQ(ierr);
1007   PetscFunctionReturn(0);
1008 }
1009 
1010 /*@
1011    MatProductCreate - create a matrix product object that can be used to compute various matrix times matrix operations.
1012 
1013    Collective on Mat
1014 
1015    Input Parameters:
1016 +  A - the first matrix
1017 .  B - the second matrix
1018 -  C - the third matrix (optional)
1019 
1020    Output Parameters:
1021 .  D - the product matrix
1022 
1023    Level: intermediate
1024 
1025 .seealso: MatProductCreateWithMat(), MatProductSetType(), MatProductSetAlgorithm()
1026 @*/
1027 PetscErrorCode MatProductCreate(Mat A,Mat B,Mat C,Mat *D)
1028 {
1029   PetscErrorCode ierr;
1030 
1031   PetscFunctionBegin;
1032   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1033   PetscValidType(A,1);
1034   PetscValidHeaderSpecific(B,MAT_CLASSID,2);
1035   PetscValidType(B,2);
1036   if (A->factortype) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix A");
1037   if (B->factortype) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix B");
1038 
1039   if (C) {
1040     PetscValidHeaderSpecific(C,MAT_CLASSID,3);
1041     PetscValidType(C,3);
1042     if (C->factortype) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix C");
1043   }
1044 
1045   PetscValidPointer(D,4);
1046   ierr = MatCreate(PetscObjectComm((PetscObject)A),D);CHKERRQ(ierr);
1047   ierr = MatProductCreate_Private(A,B,C,*D);CHKERRQ(ierr);
1048   PetscFunctionReturn(0);
1049 }
1050