xref: /petsc/src/mat/interface/matproduct.c (revision 93c87e653a96ce16476a56a0af60371aaa497750)
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_producttype(D):
11            # Check matrix global sizes
12            -> MatProductSetFromOptions_Atype_Btype_Ctype(D);
13                 ->MatProductSetFromOptions_Atype_Btype_Ctype_productype(D):
14                     # Check matrix local sizes for mpi matrices
15                     # Set default algorithm
16                     # Get runtime option
17                     # Set D->ops->productsymbolic = MatProductSymbolic_productype_Atype_Btype_Ctype;
18 
19     PetscLogEventBegin()
20     MatProductSymbolic(D):
21       # Call MatxxxSymbolic_Atype_Btype_Ctype();
22       # Set D->ops->productnumeric = MatProductNumeric_productype_Atype_Btype_Ctype;
23     PetscLogEventEnd()
24 
25     PetscLogEventBegin()
26     MatProductNumeric(D);
27       # Call (D->ops->matxxxnumeric)();
28     PetscLogEventEnd()
29 */
30 
31 #include <petsc/private/matimpl.h>      /*I "petscmat.h" I*/
32 
33 const char *const MatProductTypes[] = {"AB","AtB","ABt","PtAP","RARt","ABC","MatProductType","MAT_Product_",0};
34 
35 static PetscErrorCode MatProductNumeric_PtAP_Basic(Mat C)
36 {
37   PetscErrorCode ierr;
38   Mat_Product    *product = C->product;
39   Mat            P = product->B,AP = product->Dwork;
40 
41   PetscFunctionBegin;
42   /* AP = A*P */
43   ierr = MatProductNumeric(AP);CHKERRQ(ierr);
44   /* C = P^T*AP */
45   if (!C->ops->transposematmultnumeric) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Missing numeric stage");
46   ierr = (*C->ops->transposematmultnumeric)(P,AP,C);CHKERRQ(ierr);
47   PetscFunctionReturn(0);
48 }
49 
50 static PetscErrorCode MatProductSymbolic_PtAP_Basic(Mat C)
51 {
52   PetscErrorCode ierr;
53   Mat_Product    *product = C->product;
54   Mat            A=product->A,P=product->B,AP;
55   PetscReal      fill=product->fill;
56 
57   PetscFunctionBegin;
58   /* AP = A*P */
59   ierr = MatProductCreate(A,P,NULL,&AP);CHKERRQ(ierr);
60   ierr = MatProductSetType(AP,MATPRODUCT_AB);CHKERRQ(ierr);
61   ierr = MatProductSetAlgorithm(AP,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
62   ierr = MatProductSetFill(AP,fill);CHKERRQ(ierr);
63   ierr = MatProductSetFromOptions(AP);CHKERRQ(ierr);
64   ierr = MatProductSymbolic(AP);CHKERRQ(ierr);
65 
66   /* C = P^T*AP */
67   ierr = MatProductSetType(C,MATPRODUCT_AtB);CHKERRQ(ierr);
68   ierr = MatProductSetAlgorithm(C,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
69   product->A = P;
70   product->B = AP;
71   ierr = MatProductSetFromOptions(C);CHKERRQ(ierr);
72   ierr = MatProductSymbolic(C);CHKERRQ(ierr);
73 
74   /* resume user's original input matrix setting for A and B */
75   product->A     = A;
76   product->B     = P;
77   product->Dwork = AP;
78 
79   C->ops->productnumeric = MatProductNumeric_PtAP_Basic;
80   PetscFunctionReturn(0);
81 }
82 
83 static PetscErrorCode MatProductNumeric_RARt_Basic(Mat C)
84 {
85   PetscErrorCode ierr;
86   Mat_Product    *product = C->product;
87   Mat            R=product->B,RA=product->Dwork;
88 
89   PetscFunctionBegin;
90   /* RA = R*A */
91   ierr = MatProductNumeric(RA);CHKERRQ(ierr);
92   /* C = RA*R^T */
93   if (!C->ops->mattransposemultnumeric) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Missing numeric stage");
94   ierr = (*C->ops->mattransposemultnumeric)(RA,R,C);CHKERRQ(ierr);
95   PetscFunctionReturn(0);
96 }
97 
98 static PetscErrorCode MatProductSymbolic_RARt_Basic(Mat C)
99 {
100   PetscErrorCode ierr;
101   Mat_Product    *product = C->product;
102   Mat            A=product->A,R=product->B,RA;
103   PetscReal      fill=product->fill;
104 
105   PetscFunctionBegin;
106   /* RA = R*A */
107   ierr = MatProductCreate(R,A,NULL,&RA);CHKERRQ(ierr);
108   ierr = MatProductSetType(RA,MATPRODUCT_AB);CHKERRQ(ierr);
109   ierr = MatProductSetAlgorithm(RA,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
110   ierr = MatProductSetFill(RA,fill);CHKERRQ(ierr);
111   ierr = MatProductSetFromOptions(RA);CHKERRQ(ierr);
112   ierr = MatProductSymbolic(RA);CHKERRQ(ierr);
113 
114   /* C = RA*R^T */
115   ierr = MatProductSetType(C,MATPRODUCT_ABt);CHKERRQ(ierr);
116   ierr = MatProductSetAlgorithm(C,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
117   product->A = RA;
118   ierr = MatProductSetFromOptions(C);CHKERRQ(ierr);
119   ierr = MatProductSymbolic(C);CHKERRQ(ierr);
120 
121   /* resume user's original input matrix setting for A */
122   product->A     = A;
123   product->Dwork = RA; /* save here so it will be destroyed with product C */
124   C->ops->productnumeric = MatProductNumeric_RARt_Basic;
125   PetscFunctionReturn(0);
126 }
127 
128 static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat)
129 {
130   PetscErrorCode ierr;
131   Mat_Product    *product = mat->product;
132   Mat            A=product->A,BC=product->Dwork;
133 
134   PetscFunctionBegin;
135   /* Numeric BC = B*C */
136   ierr = MatProductNumeric(BC);CHKERRQ(ierr);
137   /* Numeric mat = A*BC */
138   if (!mat->ops->transposematmultnumeric) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric stage");
139   ierr = (*mat->ops->matmultnumeric)(A,BC,mat);CHKERRQ(ierr);
140   PetscFunctionReturn(0);
141 }
142 
143 static PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat)
144 {
145   PetscErrorCode ierr;
146   Mat_Product    *product = mat->product;
147   Mat            B=product->B,C=product->C,BC;
148   PetscReal      fill=product->fill;
149 
150   PetscFunctionBegin;
151   /* Symbolic BC = B*C */
152   ierr = MatProductCreate(B,C,NULL,&BC);CHKERRQ(ierr);
153   ierr = MatProductSetType(BC,MATPRODUCT_AB);CHKERRQ(ierr);
154   ierr = MatProductSetAlgorithm(BC,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
155   ierr = MatProductSetFill(BC,fill);CHKERRQ(ierr);
156   ierr = MatProductSetFromOptions(BC);CHKERRQ(ierr);
157   ierr = MatProductSymbolic(BC);CHKERRQ(ierr);
158 
159   /* Symbolic mat = A*BC */
160   ierr = MatProductSetType(mat,MATPRODUCT_AB);CHKERRQ(ierr);
161   ierr = MatProductSetAlgorithm(mat,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
162   product->B     = BC;
163   product->Dwork = BC;
164   ierr = MatProductSetFromOptions(mat);CHKERRQ(ierr);
165   ierr = MatProductSymbolic(mat);CHKERRQ(ierr);
166 
167   /* resume user's original input matrix setting for B */
168   product->B = B;
169   mat->ops->productnumeric = MatProductNumeric_ABC_Basic;
170   PetscFunctionReturn(0);
171 }
172 
173 PetscErrorCode MatProductSymbolic_Basic(Mat mat)
174 {
175   PetscErrorCode ierr;
176   Mat_Product    *product = mat->product;
177 
178   PetscFunctionBegin;
179   switch (product->type) {
180   case MATPRODUCT_PtAP:
181     ierr = PetscInfo2((PetscObject)mat, "MatProduct_Basic_PtAP() for A %s, P %s is used\n",((PetscObject)product->A)->type_name,((PetscObject)product->B)->type_name);CHKERRQ(ierr);
182     ierr = MatProductSymbolic_PtAP_Basic(mat);CHKERRQ(ierr);
183     break;
184   case MATPRODUCT_RARt:
185     ierr = PetscInfo2((PetscObject)mat, "MatProduct_Basic_RARt() for A %s, R %s is used\n",((PetscObject)product->A)->type_name,((PetscObject)product->B)->type_name);CHKERRQ(ierr);
186     ierr = MatProductSymbolic_RARt_Basic(mat);CHKERRQ(ierr);
187     break;
188   case MATPRODUCT_ABC:
189     ierr = PetscInfo3((PetscObject)mat, "MatProduct_Basic_ABC() 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);
190     ierr = MatProductSymbolic_ABC_Basic(mat);CHKERRQ(ierr);
191     break;
192   default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType is not supported");
193   }
194   PetscFunctionReturn(0);
195 }
196 
197 /* ----------------------------------------------- */
198 /*@C
199    MatProductReplaceMats - Replace input matrices for a matrix product.
200 
201    Collective on Mat
202 
203    Input Parameters:
204 +  A - the matrix or NULL if not being replaced
205 .  B - the matrix or NULL if not being replaced
206 .  C - the matrix or NULL if not being replaced
207 -  D - the matrix product
208 
209    Level: intermediate
210 
211    Notes:
212      Input matrix must have exactly same data structure as replaced one.
213 
214 .seealso: MatProductCreate()
215 @*/
216 PetscErrorCode MatProductReplaceMats(Mat A,Mat B,Mat C,Mat D)
217 {
218   PetscErrorCode ierr;
219   Mat_Product    *product=D->product;
220 
221   PetscFunctionBegin;
222   PetscValidHeaderSpecific(D,MAT_CLASSID,4);
223   if (!product) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ORDER,"Mat D does not have struct 'product'. Call MatProductReplaceProduct()");
224   if (A) {
225     PetscValidHeaderSpecific(A,MAT_CLASSID,1);
226     if (!product->Areplaced) {
227       ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr); /* take ownership of input */
228       ierr = MatDestroy(&product->A);CHKERRQ(ierr); /* release old reference */
229       product->A = A;
230     } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"Matrix A was changed by a PETSc internal routine, cannot be replaced");
231   }
232   if (B) {
233     PetscValidHeaderSpecific(B,MAT_CLASSID,2);
234     if (!product->Breplaced) {
235       ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr); /* take ownership of input */
236       ierr = MatDestroy(&product->B);CHKERRQ(ierr); /* release old reference */
237       product->B = B;
238     } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"Matrix B was changed by a PETSc internal routine, cannot be replaced");
239   }
240   if (C) {
241     PetscValidHeaderSpecific(C,MAT_CLASSID,3);
242     ierr = PetscObjectReference((PetscObject)C);CHKERRQ(ierr); /* take ownership of input */
243     ierr = MatDestroy(&product->C);CHKERRQ(ierr); /* release old reference */
244     product->C = C;
245   }
246   PetscFunctionReturn(0);
247 }
248 
249 static PetscErrorCode MatProductNumeric_X_Dense(Mat C)
250 {
251   PetscErrorCode ierr;
252   Mat_Product    *product = C->product;
253   Mat            A = product->A, B = product->B;
254   PetscInt       k, K = B->cmap->N;
255   PetscBool      t = PETSC_TRUE,iscuda = PETSC_FALSE;
256   PetscBool      Bcpu = PETSC_TRUE, Ccpu = PETSC_TRUE;
257   char           *Btype = NULL,*Ctype = NULL;
258 
259   PetscFunctionBegin;
260   switch (product->type) {
261   case MATPRODUCT_AB:
262     t = PETSC_FALSE;
263   case MATPRODUCT_AtB:
264     break;
265   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);
266   }
267   if (PetscDefined(HAVE_CUDA)) {
268     VecType vtype;
269 
270     ierr = MatGetVecType(A,&vtype);CHKERRQ(ierr);
271     ierr = PetscStrcmp(vtype,VECCUDA,&iscuda);CHKERRQ(ierr);
272     if (!iscuda) {
273       ierr = PetscStrcmp(vtype,VECSEQCUDA,&iscuda);CHKERRQ(ierr);
274     }
275     if (!iscuda) {
276       ierr = PetscStrcmp(vtype,VECMPICUDA,&iscuda);CHKERRQ(ierr);
277     }
278     if (iscuda) { /* Make sure we have up-to-date data on the GPU */
279       ierr = PetscStrallocpy(((PetscObject)B)->type_name,&Btype);CHKERRQ(ierr);
280       ierr = PetscStrallocpy(((PetscObject)C)->type_name,&Ctype);CHKERRQ(ierr);
281       ierr = MatConvert(B,MATDENSECUDA,MAT_INPLACE_MATRIX,&B);CHKERRQ(ierr);
282       if (!C->assembled) { /* need to flag the matrix as assembled, otherwise MatConvert will complain */
283         ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
284         ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
285       }
286       ierr = MatConvert(C,MATDENSECUDA,MAT_INPLACE_MATRIX,&C);CHKERRQ(ierr);
287     } else { /* Make sure we have up-to-date data on the CPU */
288 #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_VIENNACL)
289       Bcpu = B->boundtocpu;
290       Ccpu = C->boundtocpu;
291 #endif
292       ierr = MatBindToCPU(B,PETSC_TRUE);CHKERRQ(ierr);
293       ierr = MatBindToCPU(C,PETSC_TRUE);CHKERRQ(ierr);
294     }
295   }
296   for (k=0;k<K;k++) {
297     Vec x,y;
298 
299     ierr = MatDenseGetColumnVecRead(B,k,&x);CHKERRQ(ierr);
300     ierr = MatDenseGetColumnVecWrite(C,k,&y);CHKERRQ(ierr);
301     if (t) {
302       ierr = MatMultTranspose(A,x,y);CHKERRQ(ierr);
303     } else {
304       ierr = MatMult(A,x,y);CHKERRQ(ierr);
305     }
306     ierr = MatDenseRestoreColumnVecRead(B,k,&x);CHKERRQ(ierr);
307     ierr = MatDenseRestoreColumnVecWrite(C,k,&y);CHKERRQ(ierr);
308   }
309   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
310   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
311   if (PetscDefined(HAVE_CUDA)) {
312     if (iscuda) {
313       ierr = MatConvert(B,Btype,MAT_INPLACE_MATRIX,&B);CHKERRQ(ierr);
314       ierr = MatConvert(C,Ctype,MAT_INPLACE_MATRIX,&C);CHKERRQ(ierr);
315     } else {
316       ierr = MatBindToCPU(B,Bcpu);CHKERRQ(ierr);
317       ierr = MatBindToCPU(C,Ccpu);CHKERRQ(ierr);
318     }
319   }
320   ierr = PetscFree(Btype);CHKERRQ(ierr);
321   ierr = PetscFree(Ctype);CHKERRQ(ierr);
322   PetscFunctionReturn(0);
323 }
324 
325 static PetscErrorCode MatProductSymbolic_X_Dense(Mat C)
326 {
327   PetscErrorCode ierr;
328   Mat_Product    *product = C->product;
329   Mat            A = product->A, B = product->B;
330   PetscBool      isdense;
331 
332   PetscFunctionBegin;
333   switch (product->type) {
334   case MATPRODUCT_AB:
335     ierr = MatSetSizes(C,A->rmap->n,B->cmap->n,A->rmap->N,B->cmap->N);CHKERRQ(ierr);
336     break;
337   case MATPRODUCT_AtB:
338     ierr = MatSetSizes(C,A->cmap->n,B->cmap->n,A->cmap->N,B->cmap->N);CHKERRQ(ierr);
339     break;
340   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);
341   }
342   ierr = PetscObjectBaseTypeCompareAny((PetscObject)C,&isdense,MATSEQDENSE,MATMPIDENSE,"");CHKERRQ(ierr);
343   if (!isdense) {
344     ierr = MatSetType(C,((PetscObject)B)->type_name);CHKERRQ(ierr);
345     /* If matrix type of C was not set or not dense, we need to reset this pointers */
346     C->ops->productsymbolic = MatProductSymbolic_X_Dense;
347     C->ops->productnumeric  = MatProductNumeric_X_Dense;
348   }
349   ierr = MatSetUp(C);CHKERRQ(ierr);
350   PetscFunctionReturn(0);
351 }
352 
353 static PetscErrorCode MatProductSetFromOptions_X_Dense(Mat C)
354 {
355   Mat_Product *product = C->product;
356   Mat         A = product->A, B = product->B;
357 
358   PetscFunctionBegin;
359   C->ops->productsymbolic = NULL;
360   C->ops->productnumeric  = NULL;
361   switch (product->type) {
362   case MATPRODUCT_AB:
363   case MATPRODUCT_AtB:
364     C->ops->productsymbolic = MatProductSymbolic_X_Dense;
365     C->ops->productnumeric  = MatProductNumeric_X_Dense;
366     break;
367   default: SETERRQ3(PetscObjectComm((PetscObject)C),PETSC_ERR_SUP,"MatProduct type %s not supported for %s and %s matrices",MatProductTypes[product->type],((PetscObject)A)->type_name,((PetscObject)B)->type_name);
368   }
369   PetscFunctionReturn(0);
370 }
371 
372 /* ----------------------------------------------- */
373 static PetscErrorCode MatProductSetFromOptions_AB(Mat mat)
374 {
375   PetscErrorCode ierr;
376   Mat_Product    *product = mat->product;
377   Mat            A=product->A,B=product->B;
378   PetscBool      sametype;
379   PetscErrorCode (*fA)(Mat);
380   PetscErrorCode (*fB)(Mat);
381   PetscErrorCode (*f)(Mat)=NULL;
382   PetscBool      A_istrans,B_istrans;
383 
384   PetscFunctionBegin;
385   /* Check matrix global sizes */
386   if (B->rmap->N!=A->cmap->N) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %D != %D",B->rmap->N,A->cmap->N);
387 
388   fA = A->ops->productsetfromoptions;
389   fB = B->ops->productsetfromoptions;
390 
391   ierr = PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);CHKERRQ(ierr);
392   ierr = PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&A_istrans);CHKERRQ(ierr);
393   ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&B_istrans);CHKERRQ(ierr);
394   ierr = PetscInfo2(mat,"for A %s, B %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
395 
396   if (fB == fA && sametype && (!A_istrans || !B_istrans)) {
397     ierr = PetscInfo(mat,"  sametype and matching op\n");CHKERRQ(ierr);
398     f = fB;
399   } else {
400     char      mtypes[256];
401     PetscBool At_istrans=PETSC_TRUE,Bt_istrans=PETSC_TRUE;
402     Mat       At = NULL,Bt = NULL;
403 
404     if (A_istrans && !B_istrans) {
405       ierr = MatTransposeGetMat(A,&At);CHKERRQ(ierr);
406       ierr = PetscObjectTypeCompare((PetscObject)At,MATTRANSPOSEMAT,&At_istrans);CHKERRQ(ierr);
407       if (At_istrans) { /* mat = ATT * B */
408         Mat Att = NULL;
409         ierr = MatTransposeGetMat(At,&Att);CHKERRQ(ierr);
410         ierr = PetscObjectReference((PetscObject)Att);CHKERRQ(ierr);
411         ierr = MatDestroy(&product->A);CHKERRQ(ierr);
412         A                  = Att;
413         product->A         = Att; /* use Att for matproduct */
414         product->Areplaced = PETSC_TRUE; /* Att = A, but has native matrix type */
415       } else { /* !At_istrans: mat = At^T*B */
416         ierr = PetscObjectReference((PetscObject)At);CHKERRQ(ierr);
417         ierr = MatDestroy(&product->A);CHKERRQ(ierr);
418         A                  = At;
419         product->A         = At;
420         product->Areplaced = PETSC_TRUE;
421         product->type      = MATPRODUCT_AtB;
422       }
423     } else if (!A_istrans && B_istrans) {
424       ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
425       ierr = PetscObjectTypeCompare((PetscObject)Bt,MATTRANSPOSEMAT,&Bt_istrans);CHKERRQ(ierr);
426       if (Bt_istrans) { /* mat = A * BTT */
427         Mat Btt = NULL;
428         ierr = MatTransposeGetMat(Bt,&Btt);CHKERRQ(ierr);
429         ierr = PetscObjectReference((PetscObject)Btt);CHKERRQ(ierr);
430         ierr = MatDestroy(&product->B);CHKERRQ(ierr);
431         B                  = Btt;
432         product->B         = Btt; /* use Btt for matproduct */
433         product->Breplaced = PETSC_TRUE;
434       } else { /* !Bt_istrans */
435         /* mat = A*Bt^T */
436         ierr = PetscObjectReference((PetscObject)Bt);CHKERRQ(ierr);
437         ierr = MatDestroy(&product->B);CHKERRQ(ierr);
438         B                  = Bt;
439         product->B         = Bt;
440         product->Breplaced = PETSC_TRUE;
441         product->type = MATPRODUCT_ABt;
442       }
443     } else if (A_istrans && B_istrans) { /* mat = At^T * Bt^T */
444       ierr = MatTransposeGetMat(A,&At);CHKERRQ(ierr);
445       ierr = PetscObjectTypeCompare((PetscObject)At,MATTRANSPOSEMAT,&At_istrans);CHKERRQ(ierr);
446       ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
447       ierr = PetscObjectTypeCompare((PetscObject)Bt,MATTRANSPOSEMAT,&Bt_istrans);CHKERRQ(ierr);
448       if (At_istrans && Bt_istrans) {
449         Mat Att= NULL,Btt = NULL;
450         ierr = MatTransposeGetMat(At,&Att);CHKERRQ(ierr);
451         ierr = MatTransposeGetMat(Bt,&Btt);CHKERRQ(ierr);
452         ierr = PetscObjectReference((PetscObject)Att);CHKERRQ(ierr);
453         ierr = PetscObjectReference((PetscObject)Btt);CHKERRQ(ierr);
454         ierr = MatDestroy(&product->A);CHKERRQ(ierr);
455         ierr = MatDestroy(&product->B);CHKERRQ(ierr);
456         A             = Att;
457         product->A    = Att; product->Areplaced = PETSC_TRUE;
458         B             = Btt;
459         product->B    = Btt; product->Breplaced = PETSC_TRUE;
460       } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Not supported yet");
461     }
462 
463     /* query MatProductSetFromOptions_Atype_Btype */
464     ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
465     ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
466     ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
467     ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
468     ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
469     ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
470     ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
471     if (!f) {
472       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
473       ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
474     }
475   }
476 
477   /* last chance, we can still compute the product if B is of type dense */
478   if (!f && (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB)) {
479     PetscBool isdense;
480 
481     ierr = PetscObjectBaseTypeCompareAny((PetscObject)B,&isdense,MATSEQDENSE,MATMPIDENSE,"");CHKERRQ(ierr);
482     if (isdense) {
483       f    = MatProductSetFromOptions_X_Dense;
484       ierr = PetscInfo(mat,"  using basic looping over columns of a dense matrix\n");CHKERRQ(ierr);
485     }
486   }
487 
488   if (f) {
489     ierr = (*f)(mat);CHKERRQ(ierr);
490   } else { /* reset pointers since the matrix types combination is not available */
491     ierr = PetscInfo2(mat,"  for A %s and B %s is not supported\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
492     mat->ops->productsymbolic = NULL;
493     mat->ops->productnumeric  = NULL;
494   }
495   PetscFunctionReturn(0);
496 }
497 
498 static PetscErrorCode MatProductSetFromOptions_AtB(Mat mat)
499 {
500   PetscErrorCode ierr;
501   Mat_Product    *product = mat->product;
502   Mat            A=product->A,B=product->B;
503   PetscBool      sametype;
504   PetscErrorCode (*fA)(Mat);
505   PetscErrorCode (*fB)(Mat);
506   PetscErrorCode (*f)(Mat)=NULL;
507 
508   PetscFunctionBegin;
509   /* Check matrix global sizes */
510   if (B->rmap->N!=A->rmap->N) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %D != %D",B->rmap->N,A->rmap->N);
511 
512   fA = A->ops->productsetfromoptions;
513   fB = B->ops->productsetfromoptions;
514 
515   ierr = PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);CHKERRQ(ierr);
516   ierr = PetscInfo2(mat,"for A %s, B %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
517 
518   if (fB == fA && sametype) {
519     ierr = PetscInfo(mat,"  sametype and matching op\n");CHKERRQ(ierr);
520     f = fB;
521   } else {
522     char      mtypes[256];
523     PetscBool istrans;
524     ierr = PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
525     if (!istrans) {
526       /* query MatProductSetFromOptions_Atype_Btype */
527       ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
528       ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
529       ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
530       ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
531       ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
532       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
533       ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
534     } else {
535       Mat T = NULL;
536       SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"MatProductSetFromOptions_AtB for A %s and B %s is not supported",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
537 
538       ierr = MatTransposeGetMat(A,&T);CHKERRQ(ierr);
539       ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
540       ierr = PetscStrlcat(mtypes,((PetscObject)T)->type_name,sizeof(mtypes));CHKERRQ(ierr);
541       ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
542       ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
543       ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
544 
545       product->type = MATPRODUCT_AtB;
546       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
547       ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
548     }
549 
550     if (!f) {
551       ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
552       ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
553     }
554   }
555 
556   /* last chance, we can still compute the product if B is of type dense */
557   if (!f && (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB)) {
558     PetscBool isdense;
559 
560     ierr = PetscObjectBaseTypeCompareAny((PetscObject)B,&isdense,MATSEQDENSE,MATMPIDENSE,"");CHKERRQ(ierr);
561     if (isdense) {
562       f    = MatProductSetFromOptions_X_Dense;
563       ierr = PetscInfo(mat,"  using basic looping over columns of a dense matrix\n");CHKERRQ(ierr);
564     }
565   }
566 
567   if (f) {
568     ierr = (*f)(mat);CHKERRQ(ierr);
569   } else { /* reset pointers since the matrix types combination is not available */
570     ierr = PetscInfo2(mat,"  for A %s and B %s is not supported\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
571     mat->ops->productsymbolic = NULL;
572     mat->ops->productnumeric  = NULL;
573   }
574   PetscFunctionReturn(0);
575 }
576 
577 static PetscErrorCode MatProductSetFromOptions_ABt(Mat mat)
578 {
579   PetscErrorCode ierr;
580   Mat_Product    *product = mat->product;
581   Mat            A=product->A,B=product->B;
582   PetscBool      sametype;
583   PetscErrorCode (*fA)(Mat);
584   PetscErrorCode (*fB)(Mat);
585   PetscErrorCode (*f)(Mat)=NULL;
586 
587   PetscFunctionBegin;
588   /* Check matrix global sizes */
589   if (B->cmap->N!=A->cmap->N) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, AN %D != BN %D",A->cmap->N,B->cmap->N);
590 
591   fA = A->ops->productsetfromoptions;
592   fB = B->ops->productsetfromoptions;
593 
594   ierr = PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);CHKERRQ(ierr);
595   ierr = PetscInfo2(mat,"for A %s, B %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
596   if (fB == fA && sametype) {
597     ierr = PetscInfo(mat,"  sametype and matching op\n");CHKERRQ(ierr);
598     f = fB;
599   } else {
600     char      mtypes[256];
601     PetscBool istrans;
602     ierr = PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
603     if (!istrans) {
604       /* query MatProductSetFromOptions_Atype_Btype */
605       ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
606       ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
607       ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
608       ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
609       ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
610       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
611       ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
612     } else {
613       Mat T = NULL;
614       SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"MatProductSetFromOptions_ABt for A %s and B %s is not supported",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
615 
616       ierr = MatTransposeGetMat(A,&T);CHKERRQ(ierr);
617       ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
618       ierr = PetscStrlcat(mtypes,((PetscObject)T)->type_name,sizeof(mtypes));CHKERRQ(ierr);
619       ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
620       ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
621       ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
622 
623       product->type = MATPRODUCT_ABt;
624       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
625       ierr = PetscInfo2(mat,"  querying %s (ABt)? %p\n",mtypes,f);CHKERRQ(ierr);
626     }
627 
628     if (!f) {
629       ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
630       ierr = PetscInfo2(mat,"  querying %s (ABt)? %p\n",mtypes,f);CHKERRQ(ierr);
631     }
632   }
633 
634   /* last chance, we can still compute the product if B is of type dense */
635   if (!f && (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB)) {
636     PetscBool isdense;
637 
638     ierr = PetscObjectBaseTypeCompareAny((PetscObject)B,&isdense,MATSEQDENSE,MATMPIDENSE,"");CHKERRQ(ierr);
639     if (isdense) {
640       f    = MatProductSetFromOptions_X_Dense;
641       ierr = PetscInfo(mat,"  using basic looping over columns of a dense matrix\n");CHKERRQ(ierr);
642     }
643   }
644 
645   if (f) {
646     ierr = (*f)(mat);CHKERRQ(ierr);
647   } else { /* reset pointers since the matrix types combination is not available */
648     ierr = PetscInfo2(mat,"  for A %s and B %s is not supported\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
649     mat->ops->productsymbolic = NULL;
650     mat->ops->productnumeric  = NULL;
651   }
652   PetscFunctionReturn(0);
653 }
654 
655 static PetscErrorCode MatProductSetFromOptions_PtAP(Mat mat)
656 {
657   PetscErrorCode ierr;
658   Mat_Product    *product = mat->product;
659   Mat            A=product->A,B=product->B;
660   PetscBool      sametype;
661   PetscErrorCode (*fA)(Mat);
662   PetscErrorCode (*fB)(Mat);
663   PetscErrorCode (*f)(Mat)=NULL;
664 
665   PetscFunctionBegin;
666   /* Check matrix global sizes */
667   if (A->rmap->N != A->cmap->N) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Matrix A must be square, %D != %D",A->rmap->N,A->cmap->N);
668   if (B->rmap->N != A->cmap->N) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %D != %D",B->rmap->N,A->cmap->N);
669 
670   fA = A->ops->productsetfromoptions;
671   fB = B->ops->productsetfromoptions;
672 
673   ierr = PetscInfo2(mat,"for A %s, P %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
674   ierr = PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);CHKERRQ(ierr);
675   if (fB == fA && sametype) {
676     ierr = PetscInfo(mat,"  sametype and matching op\n");CHKERRQ(ierr);
677     f = fB;
678   } else {
679     /* query MatProductSetFromOptions_Atype_Btype */
680     char  mtypes[256];
681     ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
682     ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
683     ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
684     ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
685     ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
686     ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
687     ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
688 
689     if (!f) {
690       ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
691       ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
692     }
693   }
694 
695   if (f) {
696     ierr = (*f)(mat);CHKERRQ(ierr);
697   } else {
698     ierr = PetscInfo2(mat,"  for A %s, P %s uses MatProduct_Basic() implementation\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
699     mat->ops->productsymbolic = MatProductSymbolic_Basic;
700   }
701   PetscFunctionReturn(0);
702 }
703 
704 static PetscErrorCode MatProductSetFromOptions_RARt(Mat mat)
705 {
706   PetscErrorCode ierr;
707   Mat_Product    *product = mat->product;
708   Mat            A=product->A,B=product->B;
709   PetscBool      sametype;
710   PetscErrorCode (*fA)(Mat);
711   PetscErrorCode (*fB)(Mat);
712   PetscErrorCode (*f)(Mat)=NULL;
713 
714   PetscFunctionBegin;
715   /* Check matrix global sizes */
716   if (A->rmap->N != B->cmap->N) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Matrix A must be square, %D != %D",A->rmap->N,A->cmap->N);
717   if (B->cmap->N != A->cmap->N) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %D != %D",B->cmap->N,A->cmap->N);
718 
719   fA = A->ops->productsetfromoptions;
720   fB = B->ops->productsetfromoptions;
721 
722   ierr = PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);CHKERRQ(ierr);
723   ierr = PetscInfo2(mat,"for A %s, B %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
724   if (fB == fA && sametype) {
725     ierr = PetscInfo(mat,"  sametype and matching op\n");CHKERRQ(ierr);
726     f = fB;
727   } else {
728     /* query MatProductSetFromOptions_Atype_Btype */
729     char  mtypes[256];
730     ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
731     ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
732     ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
733     ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
734     ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
735     ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
736     ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
737 
738     if (!f) {
739       ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
740       ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
741     }
742   }
743 
744   if (f) {
745     ierr = (*f)(mat);CHKERRQ(ierr);
746   } else {
747     ierr = PetscInfo2(mat,"  for A %s, P %s uses MatProduct_Basic() implementation\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);CHKERRQ(ierr);
748     mat->ops->productsymbolic = MatProductSymbolic_Basic;
749   }
750   PetscFunctionReturn(0);
751 }
752 
753 static PetscErrorCode MatProductSetFromOptions_ABC(Mat mat)
754 {
755   PetscErrorCode ierr;
756   Mat_Product    *product = mat->product;
757   Mat            A=product->A,B=product->B,C=product->C;
758   PetscErrorCode (*fA)(Mat);
759   PetscErrorCode (*fB)(Mat);
760   PetscErrorCode (*fC)(Mat);
761   PetscErrorCode (*f)(Mat)=NULL;
762 
763   PetscFunctionBegin;
764   /* Check matrix global sizes */
765   if (B->rmap->N!= A->cmap->N) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %D != %D",B->rmap->N,A->cmap->N);
766   if (C->rmap->N!= B->cmap->N) SETERRQ2(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %D != %D",C->rmap->N,B->cmap->N);
767 
768   fA = A->ops->productsetfromoptions;
769   fB = B->ops->productsetfromoptions;
770   fC = C->ops->productsetfromoptions;
771   ierr = PetscInfo3(mat,"for A %s, B %s and C %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name,((PetscObject)C)->type_name);CHKERRQ(ierr);
772   if (fA == fB && fA == fC && fA) {
773     ierr = PetscInfo(mat,"  matching op\n");CHKERRQ(ierr);
774     f = fA;
775   } else {
776     /* query MatProductSetFromOptions_Atype_Btype_Ctype */
777     char  mtypes[256];
778     ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
779     ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
780     ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
781     ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
782     ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
783     ierr = PetscStrlcat(mtypes,((PetscObject)C)->type_name,sizeof(mtypes));CHKERRQ(ierr);
784     ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
785 
786     ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
787     ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
788     if (!f) {
789       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
790       ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
791     }
792     if (!f) {
793       ierr = PetscObjectQueryFunction((PetscObject)C,mtypes,&f);CHKERRQ(ierr);
794       ierr = PetscInfo2(mat,"  querying %s? %p\n",mtypes,f);CHKERRQ(ierr);
795     }
796   }
797 
798   if (f) {
799     ierr = (*f)(mat);CHKERRQ(ierr);
800   } else { /* use MatProductSymbolic/Numeric_Basic() */
801     ierr = PetscInfo3(mat,"  for A %s, B %s and C %s uses MatProduct_Basic() implementation",((PetscObject)A)->type_name,((PetscObject)B)->type_name,((PetscObject)C)->type_name);CHKERRQ(ierr);
802     mat->ops->productsymbolic = MatProductSymbolic_Basic;
803   }
804   PetscFunctionReturn(0);
805 }
806 
807 /*@C
808    MatProductSetFromOptions - Creates a matrix product where the type, the algorithm etc are determined from the options database.
809 
810    Logically Collective on Mat
811 
812    Input Parameter:
813 .  mat - the matrix
814 
815    Level: beginner
816 
817 .seealso: MatSetFromOptions()
818 @*/
819 PetscErrorCode MatProductSetFromOptions(Mat mat)
820 {
821   PetscErrorCode ierr;
822 
823   PetscFunctionBegin;
824   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
825   if (mat->ops->productsetfromoptions) {
826     ierr = (*mat->ops->productsetfromoptions)(mat);CHKERRQ(ierr);
827   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Call MatProductSetType() first");
828   PetscFunctionReturn(0);
829 }
830 
831 /* ----------------------------------------------- */
832 PetscErrorCode MatProductNumeric_AB(Mat mat)
833 {
834   PetscErrorCode ierr;
835   Mat_Product    *product = mat->product;
836   Mat            A=product->A,B=product->B;
837 
838   PetscFunctionBegin;
839   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);
840   ierr = PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
841   ierr = (*mat->ops->matmultnumeric)(A,B,mat);CHKERRQ(ierr);
842   ierr = PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
843   PetscFunctionReturn(0);
844 }
845 
846 PetscErrorCode MatProductNumeric_AtB(Mat mat)
847 {
848   PetscErrorCode ierr;
849   Mat_Product    *product = mat->product;
850   Mat            A=product->A,B=product->B;
851 
852   PetscFunctionBegin;
853   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);
854   ierr = PetscLogEventBegin(MAT_TransposeMatMultNumeric,A,B,0,0);CHKERRQ(ierr);
855   ierr = (*mat->ops->transposematmultnumeric)(A,B,mat);CHKERRQ(ierr);
856   ierr = PetscLogEventEnd(MAT_TransposeMatMultNumeric,A,B,0,0);CHKERRQ(ierr);
857   PetscFunctionReturn(0);
858 }
859 
860 PetscErrorCode MatProductNumeric_ABt(Mat mat)
861 {
862   PetscErrorCode ierr;
863   Mat_Product    *product = mat->product;
864   Mat            A=product->A,B=product->B;
865 
866   PetscFunctionBegin;
867   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);
868   ierr = PetscLogEventBegin(MAT_MatTransposeMultNumeric,A,B,0,0);CHKERRQ(ierr);
869   ierr = (*mat->ops->mattransposemultnumeric)(A,B,mat);CHKERRQ(ierr);
870   ierr = PetscLogEventEnd(MAT_MatTransposeMultNumeric,A,B,0,0);CHKERRQ(ierr);
871   PetscFunctionReturn(0);
872 }
873 
874 PetscErrorCode MatProductNumeric_PtAP(Mat mat)
875 {
876   PetscErrorCode ierr;
877   Mat_Product    *product = mat->product;
878   Mat            A=product->A,B=product->B;
879 
880   PetscFunctionBegin;
881   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);
882   ierr = PetscLogEventBegin(MAT_PtAPNumeric,mat,0,0,0);CHKERRQ(ierr);
883   ierr = (*mat->ops->ptapnumeric)(A,B,mat);CHKERRQ(ierr);
884   ierr = PetscLogEventEnd(MAT_PtAPNumeric,mat,0,0,0);CHKERRQ(ierr);
885   PetscFunctionReturn(0);
886 }
887 
888 PetscErrorCode MatProductNumeric_RARt(Mat mat)
889 {
890   PetscErrorCode ierr;
891   Mat_Product    *product = mat->product;
892   Mat            A=product->A,B=product->B;
893 
894   PetscFunctionBegin;
895   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);
896   ierr = PetscLogEventBegin(MAT_RARtNumeric,A,B,0,0);CHKERRQ(ierr);
897   ierr = (*mat->ops->rartnumeric)(A,B,mat);CHKERRQ(ierr);
898   ierr = PetscLogEventEnd(MAT_RARtNumeric,A,B,0,0);CHKERRQ(ierr);
899   PetscFunctionReturn(0);
900 }
901 
902 PetscErrorCode MatProductNumeric_ABC(Mat mat)
903 {
904   PetscErrorCode ierr;
905   Mat_Product    *product = mat->product;
906   Mat            A=product->A,B=product->B,C=product->C;
907 
908   PetscFunctionBegin;
909   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);
910   ierr = PetscLogEventBegin(MAT_MatMatMultNumeric,A,B,C,0);CHKERRQ(ierr);
911   ierr = (*mat->ops->matmatmultnumeric)(A,B,C,mat);CHKERRQ(ierr);
912   ierr = PetscLogEventEnd(MAT_MatMatMultNumeric,A,B,C,0);CHKERRQ(ierr);
913   PetscFunctionReturn(0);
914 }
915 
916 /*@
917    MatProductNumeric - Implement a matrix product with numerical values.
918 
919    Collective on Mat
920 
921    Input Parameters:
922 .  mat - the matrix to hold a product
923 
924    Output Parameters:
925 .  mat - the matrix product
926 
927    Level: intermediate
928 
929 .seealso: MatProductCreate(), MatSetType()
930 @*/
931 PetscErrorCode MatProductNumeric(Mat mat)
932 {
933   PetscErrorCode ierr;
934 
935   PetscFunctionBegin;
936   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
937   if (mat->ops->productnumeric) {
938     ierr = (*mat->ops->productnumeric)(mat);CHKERRQ(ierr);
939   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Call MatProductSymbolic() first");
940   PetscFunctionReturn(0);
941 }
942 
943 /* ----------------------------------------------- */
944 PetscErrorCode MatProductSymbolic_AB(Mat mat)
945 {
946   PetscErrorCode ierr;
947   Mat_Product    *product = mat->product;
948   Mat            A=product->A,B=product->B;
949 
950   PetscFunctionBegin;
951   if (!mat->ops->matmultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]);
952   ierr = (*mat->ops->matmultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr);
953   mat->ops->productnumeric = MatProductNumeric_AB;
954   PetscFunctionReturn(0);
955 }
956 
957 PetscErrorCode MatProductSymbolic_AtB(Mat mat)
958 {
959   PetscErrorCode ierr;
960   Mat_Product    *product = mat->product;
961   Mat            A=product->A,B=product->B;
962 
963   PetscFunctionBegin;
964   if (!mat->ops->transposematmultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]);
965   ierr = (*mat->ops->transposematmultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr);
966   mat->ops->productnumeric = MatProductNumeric_AtB;
967   PetscFunctionReturn(0);
968 }
969 
970 PetscErrorCode MatProductSymbolic_ABt(Mat mat)
971 {
972   PetscErrorCode ierr;
973   Mat_Product    *product = mat->product;
974   Mat            A=product->A,B=product->B;
975 
976   PetscFunctionBegin;
977   if (!mat->ops->mattransposemultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]);
978   ierr = (*mat->ops->mattransposemultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr);
979   mat->ops->productnumeric = MatProductNumeric_ABt;
980   PetscFunctionReturn(0);
981 }
982 
983 PetscErrorCode MatProductSymbolic_ABC(Mat mat)
984 {
985   PetscErrorCode ierr;
986   Mat_Product    *product = mat->product;
987   Mat            A=product->A,B=product->B,C=product->C;
988 
989   PetscFunctionBegin;
990   if (!mat->ops->matmatmultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]);
991   ierr = (*mat->ops->matmatmultsymbolic)(A,B,C,product->fill,mat);CHKERRQ(ierr);
992   mat->ops->productnumeric = MatProductNumeric_ABC;
993   PetscFunctionReturn(0);
994 }
995 
996 /*@
997    MatProductSymbolic - Perform the symbolic portion of a matrix product, this creates a data structure for use with the numerical produce.
998 
999    Collective on Mat
1000 
1001    Input Parameters:
1002 .  mat - the matrix to hold a product
1003 
1004    Output Parameters:
1005 .  mat - the matrix product data structure
1006 
1007    Level: intermediate
1008 
1009 .seealso: MatProductCreate(), MatSetType(), MatProductNumeric(), MatProductType, MatProductAlgorithm
1010 @*/
1011 PetscErrorCode MatProductSymbolic(Mat mat)
1012 {
1013   PetscErrorCode ierr;
1014   Mat_Product    *product = mat->product;
1015   MatProductType productype = product->type;
1016   PetscLogEvent  eventtype=-1;
1017 
1018   PetscFunctionBegin;
1019   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1020 
1021   /* log event */
1022   switch (productype) {
1023   case MATPRODUCT_AB:
1024     eventtype = MAT_MatMultSymbolic;
1025     break;
1026   case MATPRODUCT_AtB:
1027     eventtype = MAT_TransposeMatMultSymbolic;
1028     break;
1029   case MATPRODUCT_ABt:
1030     eventtype = MAT_MatTransposeMultSymbolic;
1031     break;
1032   case MATPRODUCT_PtAP:
1033     eventtype = MAT_PtAPSymbolic;
1034     break;
1035   case MATPRODUCT_RARt:
1036     eventtype = MAT_RARtSymbolic;
1037     break;
1038   case MATPRODUCT_ABC:
1039     eventtype = MAT_MatMatMultSymbolic;
1040     break;
1041   default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"MATPRODUCT type is not supported");
1042   }
1043 
1044   if (mat->ops->productsymbolic) {
1045     ierr = PetscLogEventBegin(eventtype,mat,0,0,0);CHKERRQ(ierr);
1046     ierr = (*mat->ops->productsymbolic)(mat);CHKERRQ(ierr);
1047     ierr = PetscLogEventEnd(eventtype,mat,0,0,0);CHKERRQ(ierr);
1048   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Call MatProductSetFromOptions() first");
1049   PetscFunctionReturn(0);
1050 }
1051 
1052 /*@
1053    MatProductSetFill - Set an expected fill of the matrix product.
1054 
1055    Collective on Mat
1056 
1057    Input Parameters:
1058 +  mat - the matrix product
1059 -  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.
1060 
1061    Level: intermediate
1062 
1063 .seealso: MatProductSetType(), MatProductSetAlgorithm(), MatProductCreate()
1064 @*/
1065 PetscErrorCode MatProductSetFill(Mat mat,PetscReal fill)
1066 {
1067   Mat_Product *product = mat->product;
1068 
1069   PetscFunctionBegin;
1070   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1071   if (!product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Data struct Mat_Product is not created, call MatProductCreate() first");
1072   if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) product->fill = 2.0;
1073   else product->fill = fill;
1074   PetscFunctionReturn(0);
1075 }
1076 
1077 /*@
1078    MatProductSetAlgorithm - Requests a particular algorithm for a matrix product implementation.
1079 
1080    Collective on Mat
1081 
1082    Input Parameters:
1083 +  mat - the matrix product
1084 -  alg - particular implementation algorithm of the matrix product, e.g., MATPRODUCTALGORITHM_DEFAULT.
1085 
1086    Level: intermediate
1087 
1088 .seealso: MatProductSetType(), MatProductSetFill(), MatProductCreate()
1089 @*/
1090 PetscErrorCode MatProductSetAlgorithm(Mat mat,MatProductAlgorithm alg)
1091 {
1092   PetscErrorCode ierr;
1093   Mat_Product    *product = mat->product;
1094 
1095   PetscFunctionBegin;
1096   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1097   if (!product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Data struct Mat_Product is not created, call MatProductCreate() first");
1098   ierr = PetscFree(product->alg);CHKERRQ(ierr);
1099   ierr = PetscStrallocpy(alg,&product->alg);CHKERRQ(ierr);
1100   PetscFunctionReturn(0);
1101 }
1102 
1103 /*@
1104    MatProductSetType - Sets a particular matrix product type, for example Mat*Mat.
1105 
1106    Collective on Mat
1107 
1108    Input Parameters:
1109 +  mat - the matrix
1110 -  productype   - matrix product type, e.g., MATPRODUCT_AB,MATPRODUCT_AtB,MATPRODUCT_ABt,MATPRODUCT_PtAP,MATPRODUCT_RARt,MATPRODUCT_ABC.
1111 
1112    Level: intermediate
1113 
1114 .seealso: MatProductCreate(), MatProductType, MatProductAlgorithm
1115 @*/
1116 PetscErrorCode MatProductSetType(Mat mat,MatProductType productype)
1117 {
1118   Mat_Product *product = mat->product;
1119 
1120   PetscFunctionBegin;
1121   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1122   PetscValidLogicalCollectiveEnum(mat,productype,2);
1123   if (!product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Data struct Mat_Product is not created, call MatProductCreate() first");
1124   product->type = productype;
1125 
1126   switch (productype) {
1127   case MATPRODUCT_AB:
1128     mat->ops->productsetfromoptions = MatProductSetFromOptions_AB;
1129     break;
1130   case MATPRODUCT_AtB:
1131     mat->ops->productsetfromoptions = MatProductSetFromOptions_AtB;
1132     break;
1133   case MATPRODUCT_ABt:
1134     mat->ops->productsetfromoptions = MatProductSetFromOptions_ABt;
1135     break;
1136   case MATPRODUCT_PtAP:
1137     mat->ops->productsetfromoptions = MatProductSetFromOptions_PtAP;
1138     break;
1139   case MATPRODUCT_RARt:
1140     mat->ops->productsetfromoptions = MatProductSetFromOptions_RARt;
1141     break;
1142   case MATPRODUCT_ABC:
1143     mat->ops->productsetfromoptions = MatProductSetFromOptions_ABC;
1144     break;
1145   default: SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[product->type]);
1146   }
1147   PetscFunctionReturn(0);
1148 }
1149 
1150 /*@
1151    MatProductClear - Clears matrix product internal structure.
1152 
1153    Collective on Mat
1154 
1155    Input Parameters:
1156 .  mat - the product matrix
1157 
1158    Level: intermediate
1159 @*/
1160 PetscErrorCode MatProductClear(Mat mat)
1161 {
1162   PetscErrorCode ierr;
1163   Mat_Product    *product = mat->product;
1164 
1165   PetscFunctionBegin;
1166   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
1167   if (product) {
1168     /* release reference */
1169     ierr = MatDestroy(&product->A);CHKERRQ(ierr);
1170     ierr = MatDestroy(&product->B);CHKERRQ(ierr);
1171     ierr = MatDestroy(&product->C);CHKERRQ(ierr);
1172     ierr = PetscFree(product->alg);CHKERRQ(ierr);
1173     ierr = MatDestroy(&product->Dwork);CHKERRQ(ierr);
1174     ierr = PetscFree(mat->product);CHKERRQ(ierr);
1175   }
1176   PetscFunctionReturn(0);
1177 }
1178 
1179 /* Create a supporting struct and attach it to the matrix product */
1180 PetscErrorCode MatProductCreate_Private(Mat A,Mat B,Mat C,Mat D)
1181 {
1182   PetscErrorCode ierr;
1183   Mat_Product    *product=NULL;
1184 
1185   PetscFunctionBegin;
1186   ierr = PetscNewLog(D,&product);CHKERRQ(ierr);
1187   product->A        = A;
1188   product->B        = B;
1189   product->C        = C;
1190   product->Dwork    = NULL;
1191   product->fill     = 2.0; /* PETSC_DEFAULT */
1192   product->Areplaced = PETSC_FALSE;
1193   product->Breplaced = PETSC_FALSE;
1194   product->api_user  = PETSC_FALSE;
1195   D->product         = product;
1196 
1197   ierr = MatProductSetAlgorithm(D,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr);
1198 
1199   /* take ownership */
1200   ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);
1201   ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr);
1202   ierr = PetscObjectReference((PetscObject)C);CHKERRQ(ierr);
1203   PetscFunctionReturn(0);
1204 }
1205 
1206 /*@
1207    MatProductCreateWithMat - Setup a given matrix as a matrix product.
1208 
1209    Collective on Mat
1210 
1211    Input Parameters:
1212 +  A - the first matrix
1213 .  B - the second matrix
1214 .  C - the third matrix (optional)
1215 -  D - the matrix which will be used as a product
1216 
1217    Output Parameters:
1218 .  D - the product matrix
1219 
1220    Level: intermediate
1221 
1222 .seealso: MatProductCreate()
1223 @*/
1224 PetscErrorCode MatProductCreateWithMat(Mat A,Mat B,Mat C,Mat D)
1225 {
1226   PetscErrorCode ierr;
1227 
1228   PetscFunctionBegin;
1229   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1230   PetscValidType(A,1);
1231   MatCheckPreallocated(A,1);
1232   if (!A->assembled) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1233   if (A->factortype) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1234 
1235   PetscValidHeaderSpecific(B,MAT_CLASSID,2);
1236   PetscValidType(B,2);
1237   MatCheckPreallocated(B,2);
1238   if (!B->assembled) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1239   if (B->factortype) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1240 
1241   if (C) {
1242     PetscValidHeaderSpecific(C,MAT_CLASSID,3);
1243     PetscValidType(C,3);
1244     MatCheckPreallocated(C,3);
1245     if (!C->assembled) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1246     if (C->factortype) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1247   }
1248 
1249   PetscValidHeaderSpecific(D,MAT_CLASSID,4);
1250   PetscValidType(D,4);
1251   MatCheckPreallocated(D,4);
1252   if (!D->assembled) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1253   if (D->factortype) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1254 
1255   /* Create a supporting struct and attach it to D */
1256   ierr = MatProductCreate_Private(A,B,C,D);CHKERRQ(ierr);
1257   PetscFunctionReturn(0);
1258 }
1259 
1260 /*@
1261    MatProductCreate - create a matrix product object that can be used to compute various matrix times matrix operations.
1262 
1263    Collective on Mat
1264 
1265    Input Parameters:
1266 +  A - the first matrix
1267 .  B - the second matrix
1268 -  C - the third matrix (optional)
1269 
1270    Output Parameters:
1271 .  D - the product matrix
1272 
1273    Level: intermediate
1274 
1275 .seealso: MatProductCreateWithMat(), MatProductSetType(), MatProductSetAlgorithm()
1276 @*/
1277 PetscErrorCode MatProductCreate(Mat A,Mat B,Mat C,Mat *D)
1278 {
1279   PetscErrorCode ierr;
1280 
1281   PetscFunctionBegin;
1282   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1283   PetscValidType(A,1);
1284   MatCheckPreallocated(A,1);
1285   if (!A->assembled) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1286   if (A->factortype) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1287 
1288   PetscValidHeaderSpecific(B,MAT_CLASSID,2);
1289   PetscValidType(B,2);
1290   MatCheckPreallocated(B,2);
1291   if (!B->assembled) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1292   if (B->factortype) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1293 
1294   if (C) {
1295     PetscValidHeaderSpecific(C,MAT_CLASSID,3);
1296     PetscValidType(C,3);
1297     MatCheckPreallocated(C,3);
1298     if (!C->assembled) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1299     if (C->factortype) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1300   }
1301 
1302   PetscValidPointer(D,4);
1303 
1304   ierr = MatCreate(PetscObjectComm((PetscObject)A),D);CHKERRQ(ierr);
1305   ierr = MatProductCreate_Private(A,B,C,*D);CHKERRQ(ierr);
1306   PetscFunctionReturn(0);
1307 }
1308