xref: /petsc/src/mat/interface/matproduct.c (revision a80ff896a4e4b460fab449f7ca5556e439248e75)
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 static PetscErrorCode MatProductNumeric_PtAP_Basic(Mat C)
34 {
35   PetscErrorCode ierr;
36   Mat_Product    *product = C->product;
37   Mat            P = product->B,AP = product->Dwork;
38 
39   PetscFunctionBegin;
40   /* AP = A*P */
41   ierr = MatProductNumeric(AP);CHKERRQ(ierr);
42   /* C = P^T*AP */
43   ierr = (C->ops->transposematmultnumeric)(P,AP,C);CHKERRQ(ierr);
44   PetscFunctionReturn(0);
45 }
46 
47 static PetscErrorCode MatProductSymbolic_PtAP_Basic(Mat C)
48 {
49   PetscErrorCode ierr;
50   Mat_Product    *product = C->product;
51   Mat            A=product->A,P=product->B,AP;
52   PetscReal      fill=product->fill;
53 
54   PetscFunctionBegin;
55   /* AP = A*P */
56   ierr = MatProductCreate(A,P,NULL,&AP);CHKERRQ(ierr);
57   ierr = MatProductSetType(AP,MATPRODUCT_AB);CHKERRQ(ierr);
58   ierr = MatProductSetAlgorithm(AP,"default");CHKERRQ(ierr);
59   ierr = MatProductSetFill(AP,fill);CHKERRQ(ierr);
60   ierr = MatProductSetFromOptions(AP);CHKERRQ(ierr);
61   ierr = MatProductSymbolic(AP);CHKERRQ(ierr);
62 
63   /* C = P^T*AP */
64   ierr = MatProductSetType(C,MATPRODUCT_AtB);CHKERRQ(ierr);
65   product->alg = "default";
66   product->A   = P;
67   product->B   = AP;
68   ierr = MatProductSetFromOptions(C);CHKERRQ(ierr);
69   ierr = MatProductSymbolic(C);CHKERRQ(ierr);
70 
71   /* resume user's original input matrix setting for A and B */
72   product->A     = A;
73   product->B     = P;
74   product->Dwork = AP;
75 
76   C->ops->productnumeric = MatProductNumeric_PtAP_Basic;
77   PetscFunctionReturn(0);
78 }
79 
80 static PetscErrorCode MatProductNumeric_RARt_Basic(Mat C)
81 {
82   PetscErrorCode ierr;
83   Mat_Product    *product = C->product;
84   Mat            R=product->B,RA=product->Dwork;
85 
86   PetscFunctionBegin;
87   /* RA = R*A */
88   ierr = MatProductNumeric(RA);CHKERRQ(ierr);
89   /* C = RA*R^T */
90   ierr = (C->ops->mattransposemultnumeric)(RA,R,C);CHKERRQ(ierr);
91   PetscFunctionReturn(0);
92 }
93 
94 static PetscErrorCode MatProductSymbolic_RARt_Basic(Mat C)
95 {
96   PetscErrorCode ierr;
97   Mat_Product    *product = C->product;
98   Mat            A=product->A,R=product->B,RA;
99   PetscReal      fill=product->fill;
100 
101   PetscFunctionBegin;
102   /* RA = R*A */
103   ierr = MatProductCreate(R,A,NULL,&RA);CHKERRQ(ierr);
104   ierr = MatProductSetType(RA,MATPRODUCT_AB);CHKERRQ(ierr);
105   ierr = MatProductSetAlgorithm(RA,"default");CHKERRQ(ierr);
106   ierr = MatProductSetFill(RA,fill);CHKERRQ(ierr);
107   ierr = MatProductSetFromOptions(RA);CHKERRQ(ierr);
108   ierr = MatProductSymbolic(RA);CHKERRQ(ierr);
109 
110   /* C = RA*R^T */
111   ierr = MatProductSetType(C,MATPRODUCT_ABt);CHKERRQ(ierr);
112   product->alg  = "default";
113   product->A    = RA;
114   ierr = MatProductSetFromOptions(C);CHKERRQ(ierr);
115   ierr = MatProductSymbolic(C);CHKERRQ(ierr);
116 
117   /* resume user's original input matrix setting for A */
118   product->A     = A;
119   product->Dwork = RA; /* save here so it will be destroyed with product C */
120   C->ops->productnumeric = MatProductNumeric_RARt_Basic;
121   PetscFunctionReturn(0);
122 }
123 
124 static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat)
125 {
126   PetscErrorCode ierr;
127   Mat_Product    *product = mat->product;
128   Mat            A=product->A,BC=product->Dwork;
129 
130   PetscFunctionBegin;
131   /* Numeric BC = B*C */
132   ierr = MatProductNumeric(BC);CHKERRQ(ierr);
133   /* Numeric mat = A*BC */
134   ierr = (mat->ops->matmultnumeric)(A,BC,mat);CHKERRQ(ierr);
135   PetscFunctionReturn(0);
136 }
137 
138 static PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat)
139 {
140   PetscErrorCode ierr;
141   Mat_Product    *product = mat->product;
142   Mat            B=product->B,C=product->C,BC;
143   PetscReal      fill=product->fill;
144 
145   PetscFunctionBegin;
146   /* Symbolic BC = B*C */
147   ierr = MatProductCreate(B,C,NULL,&BC);CHKERRQ(ierr);
148   ierr = MatProductSetType(BC,MATPRODUCT_AB);CHKERRQ(ierr);
149   ierr = MatProductSetAlgorithm(BC,"default");CHKERRQ(ierr);
150   ierr = MatProductSetFill(BC,fill);CHKERRQ(ierr);
151   ierr = MatProductSetFromOptions(BC);CHKERRQ(ierr);
152   ierr = MatProductSymbolic(BC);CHKERRQ(ierr);
153 
154   /* Symbolic mat = A*BC */
155   ierr = MatProductSetType(mat,MATPRODUCT_AB);CHKERRQ(ierr);
156   product->alg   = "default";
157   product->B     = BC;
158   product->Dwork = BC;
159   ierr = MatProductSetFromOptions(mat);CHKERRQ(ierr);
160   ierr = MatProductSymbolic(mat);CHKERRQ(ierr);
161 
162   /* resume user's original input matrix setting for B */
163   product->B = B;
164   mat->ops->productnumeric = MatProductNumeric_ABC_Basic;
165   PetscFunctionReturn(0);
166 }
167 
168 PetscErrorCode MatProductSymbolic_Basic(Mat mat)
169 {
170   PetscErrorCode ierr;
171   Mat_Product    *product = mat->product;
172 
173   PetscFunctionBegin;
174   switch (product->type) {
175   case MATPRODUCT_PtAP:
176     PetscInfo2((PetscObject)mat, "MatProduct_Basic_PtAP() for A %s, P %s is used",((PetscObject)product->A)->type_name,((PetscObject)product->B)->type_name);
177     ierr = MatProductSymbolic_PtAP_Basic(mat);CHKERRQ(ierr);
178     break;
179   case MATPRODUCT_RARt:
180     PetscInfo2((PetscObject)mat, "MatProduct_Basic_RARt() for A %s, R %s is used",((PetscObject)product->A)->type_name,((PetscObject)product->B)->type_name);
181     ierr = MatProductSymbolic_RARt_Basic(mat);CHKERRQ(ierr);
182     break;
183   case MATPRODUCT_ABC:
184     PetscInfo3((PetscObject)mat, "MatProduct_Basic_ABC() for A %s, B %s, C %s is used",((PetscObject)product->A)->type_name,((PetscObject)product->B)->type_name,((PetscObject)product->C)->type_name);
185     ierr = MatProductSymbolic_ABC_Basic(mat);CHKERRQ(ierr);
186     break;
187   default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType is not supported");
188   }
189   PetscFunctionReturn(0);
190 }
191 
192 /* ----------------------------------------------- */
193 /*@C
194    MatProductReplaceMats - Replace input matrices for a matrix product.
195 
196    Collective on Mat
197 
198    Input Parameters:
199 +  A - the matrix or NULL if not being replaced
200 .  B - the matrix or NULL if not being replaced
201 .  C - the matrix or NULL if not being replaced
202 -  D - the matrix product
203 
204    Level: intermediate
205 
206    Notes:
207      Input matrix must have exactly same data structure as replaced one.
208 
209 .seealso: MatProductCreate()
210 @*/
211 PetscErrorCode MatProductReplaceMats(Mat A,Mat B,Mat C,Mat D)
212 {
213   PetscErrorCode ierr;
214   Mat_Product    *product=D->product;
215 
216   PetscFunctionBegin;
217   if (!product) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_NULL,"Mat D does not have struct 'product'. Call MatProductReplaceProduct(). \n");
218   if (A) {
219     if (!product->Areplaced) {
220       ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr); /* take ownership of input */
221       ierr = MatDestroy(&product->A);CHKERRQ(ierr); /* release old reference */
222       product->A = A;
223     } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"Matrix A was changed by a PETSc internal routine, cannot be replaced");
224   }
225   if (B) {
226     if (!product->Breplaced) {
227       ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr); /* take ownership of input */
228       ierr = MatDestroy(&product->B);CHKERRQ(ierr); /* release old reference */
229       product->B = B;
230     } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"Matrix B was changed by a PETSc internal routine, cannot be replaced");
231   }
232   if (C) {
233     ierr = PetscObjectReference((PetscObject)C);CHKERRQ(ierr); /* take ownership of input */
234     ierr = MatDestroy(&product->C);CHKERRQ(ierr); /* release old reference */
235     product->C = C;
236   }
237   PetscFunctionReturn(0);
238 }
239 
240 /* ----------------------------------------------- */
241 static PetscErrorCode MatProductSetFromOptions_AB(Mat mat)
242 {
243   PetscErrorCode ierr;
244   Mat_Product    *product = mat->product;
245   Mat            A=product->A,B=product->B;
246   PetscBool      sametype;
247   PetscErrorCode (*fA)(Mat);
248   PetscErrorCode (*fB)(Mat);
249   PetscErrorCode (*f)(Mat)=NULL;
250   PetscBool      A_istrans,B_istrans;
251 
252   PetscFunctionBegin;
253   /* Check matrix global sizes */
254   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);
255 
256   fA = A->ops->productsetfromoptions;
257   fB = B->ops->productsetfromoptions;
258 
259   ierr = PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);CHKERRQ(ierr);
260   ierr = PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&A_istrans);CHKERRQ(ierr);
261   ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&B_istrans);CHKERRQ(ierr);
262 
263   if (fB == fA && sametype && (!A_istrans || !B_istrans)) {
264     f = fB;
265   } else {
266     char      mtypes[256];
267     PetscBool At_istrans=PETSC_TRUE,Bt_istrans=PETSC_TRUE;
268     Mat       At = NULL,Bt = NULL;
269 
270     if (A_istrans && !B_istrans) {
271       ierr = MatTransposeGetMat(A,&At);CHKERRQ(ierr);
272       ierr = PetscObjectTypeCompare((PetscObject)At,MATTRANSPOSEMAT,&At_istrans);CHKERRQ(ierr);
273       if (At_istrans) { /* mat = ATT * B */
274         Mat Att = NULL;
275         ierr = MatTransposeGetMat(At,&Att);CHKERRQ(ierr);
276         ierr = PetscObjectReference((PetscObject)Att);CHKERRQ(ierr);
277         ierr = MatDestroy(&product->A);CHKERRQ(ierr);
278         A                  = Att;
279         product->A         = Att; /* use Att for matproduct */
280         product->Areplaced = PETSC_TRUE; /* Att = A, but has native matrix type */
281       } else { /* !At_istrans: mat = At^T*B */
282         ierr = PetscObjectReference((PetscObject)At);CHKERRQ(ierr);
283         ierr = MatDestroy(&product->A);CHKERRQ(ierr);
284         A                  = At;
285         product->A         = At;
286         product->Areplaced = PETSC_TRUE;
287         product->type      = MATPRODUCT_AtB;
288       }
289     } else if (!A_istrans && B_istrans) {
290       ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
291       ierr = PetscObjectTypeCompare((PetscObject)Bt,MATTRANSPOSEMAT,&Bt_istrans);CHKERRQ(ierr);
292       if (Bt_istrans) { /* mat = A * BTT */
293         Mat Btt = NULL;
294         ierr = MatTransposeGetMat(Bt,&Btt);CHKERRQ(ierr);
295         ierr = PetscObjectReference((PetscObject)Btt);CHKERRQ(ierr);
296         ierr = MatDestroy(&product->B);CHKERRQ(ierr);
297         B                  = Btt;
298         product->B         = Btt; /* use Btt for matproduct */
299         product->Breplaced = PETSC_TRUE;
300       } else { /* !Bt_istrans */
301         /* mat = A*Bt^T */
302         ierr = PetscObjectReference((PetscObject)Bt);CHKERRQ(ierr);
303         ierr = MatDestroy(&product->B);CHKERRQ(ierr);
304         B                  = Bt;
305         product->B         = Bt;
306         product->Breplaced = PETSC_TRUE;
307         product->type = MATPRODUCT_ABt;
308       }
309     } else if (A_istrans && B_istrans) { /* mat = At^T * Bt^T */
310       ierr = MatTransposeGetMat(A,&At);CHKERRQ(ierr);
311       ierr = PetscObjectTypeCompare((PetscObject)At,MATTRANSPOSEMAT,&At_istrans);CHKERRQ(ierr);
312       ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
313       ierr = PetscObjectTypeCompare((PetscObject)Bt,MATTRANSPOSEMAT,&Bt_istrans);CHKERRQ(ierr);
314       if (At_istrans && Bt_istrans) {
315         Mat Att= NULL,Btt = NULL;
316         ierr = MatTransposeGetMat(At,&Att);CHKERRQ(ierr);
317         ierr = MatTransposeGetMat(Bt,&Btt);CHKERRQ(ierr);
318         ierr = PetscObjectReference((PetscObject)Att);CHKERRQ(ierr);
319         ierr = PetscObjectReference((PetscObject)Btt);CHKERRQ(ierr);
320         ierr = MatDestroy(&product->A);CHKERRQ(ierr);
321         ierr = MatDestroy(&product->B);CHKERRQ(ierr);
322         A             = Att;
323         product->A    = Att; product->Areplaced = PETSC_TRUE;
324         B             = Btt;
325         product->B    = Btt; product->Breplaced = PETSC_TRUE;
326       } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Not supported yet");
327     }
328 
329     /* query MatProductSetFromOptions_Atype_Btype */
330     ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
331     ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
332     ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
333     ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
334     ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
335     ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
336     if (!f) {
337       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
338     }
339   }
340 
341   if (!f) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"MatProductSetFromOptions_AB for A %s and B %s is not supported",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
342   ierr = (*f)(mat);CHKERRQ(ierr);
343   PetscFunctionReturn(0);
344 }
345 
346 static PetscErrorCode MatProductSetFromOptions_AtB(Mat mat)
347 {
348   PetscErrorCode ierr;
349   Mat_Product    *product = mat->product;
350   Mat            A=product->A,B=product->B;
351   PetscBool      sametype;
352   PetscErrorCode (*fA)(Mat);
353   PetscErrorCode (*fB)(Mat);
354   PetscErrorCode (*f)(Mat)=NULL;
355 
356   PetscFunctionBegin;
357   /* Check matrix global sizes */
358   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);
359 
360   fA = A->ops->productsetfromoptions;
361   fB = B->ops->productsetfromoptions;
362 
363   ierr = PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);CHKERRQ(ierr);
364 
365   if (fB == fA && sametype) {
366     f = fB;
367   } else {
368     char      mtypes[256];
369     PetscBool istrans;
370     ierr = PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
371     if (!istrans) {
372       /* query MatProductSetFromOptions_Atype_Btype */
373       ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
374       ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
375       ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
376       ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
377       ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
378       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
379     } else {
380       Mat T = NULL;
381       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);
382 
383       ierr = MatTransposeGetMat(A,&T);CHKERRQ(ierr);
384       ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
385       ierr = PetscStrlcat(mtypes,((PetscObject)T)->type_name,sizeof(mtypes));CHKERRQ(ierr);
386       ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
387       ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
388       ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
389 
390       product->type = MATPRODUCT_AtB;
391       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
392     }
393 
394     if (!f) {
395       ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
396     }
397   }
398   if (!f) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"MatProductSetFromOptions_AB for A %s and B %s is not supported",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
399 
400   ierr = (*f)(mat);CHKERRQ(ierr);
401   PetscFunctionReturn(0);
402 }
403 
404 static PetscErrorCode MatProductSetFromOptions_ABt(Mat mat)
405 {
406   PetscErrorCode ierr;
407   Mat_Product    *product = mat->product;
408   Mat            A=product->A,B=product->B;
409   PetscBool      sametype;
410   PetscErrorCode (*fA)(Mat);
411   PetscErrorCode (*fB)(Mat);
412   PetscErrorCode (*f)(Mat)=NULL;
413 
414   PetscFunctionBegin;
415   /* Check matrix global sizes */
416   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);
417 
418   fA = A->ops->productsetfromoptions;
419   fB = B->ops->productsetfromoptions;
420 
421   ierr = PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);CHKERRQ(ierr);
422 
423   if (fB == fA && sametype) {
424     f = fB;
425   } else {
426     char      mtypes[256];
427     PetscBool istrans;
428     ierr = PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
429     if (!istrans) {
430       /* query MatProductSetFromOptions_Atype_Btype */
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       ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
436       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
437     } else {
438       Mat T = NULL;
439       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);
440 
441       ierr = MatTransposeGetMat(A,&T);CHKERRQ(ierr);
442       ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
443       ierr = PetscStrlcat(mtypes,((PetscObject)T)->type_name,sizeof(mtypes));CHKERRQ(ierr);
444       ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
445       ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
446       ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
447 
448       product->type = MATPRODUCT_ABt;
449       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
450     }
451 
452     if (!f) {
453       ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
454     }
455   }
456   if (!f) {
457     SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"MatProductSetFromOptions_AB for A %s and B %s is not supported",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
458   }
459 
460   ierr = (*f)(mat);CHKERRQ(ierr);
461   PetscFunctionReturn(0);
462 }
463 
464 static PetscErrorCode MatProductSetFromOptions_PtAP(Mat mat)
465 {
466   PetscErrorCode ierr;
467   Mat_Product    *product = mat->product;
468   Mat            A=product->A,B=product->B;
469   PetscBool      sametype;
470   PetscErrorCode (*fA)(Mat);
471   PetscErrorCode (*fB)(Mat);
472   PetscErrorCode (*f)(Mat)=NULL;
473 
474   PetscFunctionBegin;
475   /* Check matrix global sizes */
476   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);
477   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);
478 
479   fA = A->ops->productsetfromoptions;
480   fB = B->ops->productsetfromoptions;
481 
482   ierr = PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);CHKERRQ(ierr);
483   if (fB == fA && sametype) {
484     f = fB;
485   } else {
486     /* query MatProductSetFromOptions_Atype_Btype */
487     char  mtypes[256];
488     ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
489     ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
490     ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
491     ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
492     ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
493     ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
494 
495     if (!f) {
496       ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
497     }
498   }
499 
500   if (f) {
501     ierr = (*f)(mat);CHKERRQ(ierr);
502   } else {
503     mat->ops->productsymbolic = MatProductSymbolic_Basic;
504     PetscInfo2((PetscObject)mat, "MatProductSetFromOptions_PtAP for A %s, P %s uses MatProduct_Basic() implementation",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
505   }
506   PetscFunctionReturn(0);
507 }
508 
509 static PetscErrorCode MatProductSetFromOptions_RARt(Mat mat)
510 {
511   PetscErrorCode ierr;
512   Mat_Product    *product = mat->product;
513   Mat            A=product->A,B=product->B;
514   PetscBool      sametype;
515   PetscErrorCode (*fA)(Mat);
516   PetscErrorCode (*fB)(Mat);
517   PetscErrorCode (*f)(Mat)=NULL;
518 
519   PetscFunctionBegin;
520   /* Check matrix global sizes */
521   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);
522   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);
523 
524   fA = A->ops->productsetfromoptions;
525   fB = B->ops->productsetfromoptions;
526 
527   ierr = PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);CHKERRQ(ierr);
528   if (fB == fA && sametype) {
529     f = fB;
530   } else {
531     /* query MatProductSetFromOptions_Atype_Btype */
532     char  mtypes[256];
533     ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
534     ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
535     ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
536     ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
537     ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
538     ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
539 
540     if (!f) {
541       ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
542     }
543   }
544 
545   if (f) {
546     ierr = (*f)(mat);CHKERRQ(ierr);
547   } else {
548     mat->ops->productsymbolic = MatProductSymbolic_Basic;
549   }
550   PetscFunctionReturn(0);
551 }
552 
553 static PetscErrorCode MatProductSetFromOptions_ABC(Mat mat)
554 {
555   PetscErrorCode ierr;
556   Mat_Product    *product = mat->product;
557   Mat            A=product->A,B=product->B,C=product->C;
558   PetscErrorCode (*fA)(Mat);
559   PetscErrorCode (*fB)(Mat);
560   PetscErrorCode (*fC)(Mat);
561   PetscErrorCode (*f)(Mat)=NULL;
562 
563   PetscFunctionBegin;
564   /* Check matrix global sizes */
565   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);
566   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);
567 
568   fA = A->ops->productsetfromoptions;
569   fB = B->ops->productsetfromoptions;
570   fC = C->ops->productsetfromoptions;
571   if (fA == fB && fA == fC && fA) {
572     f = fA;
573   } else {
574     /* query MatProductSetFromOptions_Atype_Btype_Ctype */
575     char  mtypes[256];
576     ierr = PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));CHKERRQ(ierr);
577     ierr = PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));CHKERRQ(ierr);
578     ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
579     ierr = PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));CHKERRQ(ierr);
580     ierr = PetscStrlcat(mtypes,"_",sizeof(mtypes));CHKERRQ(ierr);
581     ierr = PetscStrlcat(mtypes,((PetscObject)C)->type_name,sizeof(mtypes));CHKERRQ(ierr);
582     ierr = PetscStrlcat(mtypes,"_C",sizeof(mtypes));CHKERRQ(ierr);
583 
584     ierr = PetscObjectQueryFunction((PetscObject)A,mtypes,&f);CHKERRQ(ierr);
585     if (!f) {
586       ierr = PetscObjectQueryFunction((PetscObject)B,mtypes,&f);CHKERRQ(ierr);
587     }
588     if (!f) {
589       ierr = PetscObjectQueryFunction((PetscObject)C,mtypes,&f);CHKERRQ(ierr);
590     }
591   }
592 
593   if (f) {
594     ierr = (*f)(mat);CHKERRQ(ierr);
595   } else { /* use MatProductSymbolic/Numeric_Basic() */
596     mat->ops->productsymbolic = MatProductSymbolic_Basic;
597   }
598   PetscFunctionReturn(0);
599 }
600 
601 /*@C
602    MatProductSetFromOptions - Creates a matrix product where the type, the algorithm etc are determined from the options database.
603 
604    Logically Collective on Mat
605 
606    Input Parameter:
607 .  mat - the matrix
608 
609    Level: beginner
610 
611 .seealso: MatSetFromOptions()
612 @*/
613 PetscErrorCode MatProductSetFromOptions(Mat mat)
614 {
615   PetscErrorCode ierr;
616 
617   PetscFunctionBegin;
618   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
619 
620   if (mat->ops->productsetfromoptions) {
621     ierr = (*mat->ops->productsetfromoptions)(mat);CHKERRQ(ierr);
622   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_NULL,"Call MatProductSetType() first");
623   PetscFunctionReturn(0);
624 }
625 
626 /* ----------------------------------------------- */
627 PetscErrorCode MatProductNumeric_AB(Mat mat)
628 {
629   PetscErrorCode ierr;
630   Mat_Product    *product = mat->product;
631   Mat            A=product->A,B=product->B;
632 
633   PetscFunctionBegin;
634   ierr = PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
635   ierr = (mat->ops->matmultnumeric)(A,B,mat);CHKERRQ(ierr);
636   ierr = PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
637   PetscFunctionReturn(0);
638 }
639 
640 PetscErrorCode MatProductNumeric_AtB(Mat mat)
641 {
642   PetscErrorCode ierr;
643   Mat_Product    *product = mat->product;
644   Mat            A=product->A,B=product->B;
645 
646   PetscFunctionBegin;
647   ierr = PetscLogEventBegin(MAT_TransposeMatMultNumeric,A,B,0,0);CHKERRQ(ierr);
648   ierr = (mat->ops->transposematmultnumeric)(A,B,mat);CHKERRQ(ierr);
649   ierr = PetscLogEventEnd(MAT_TransposeMatMultNumeric,A,B,0,0);CHKERRQ(ierr);
650   PetscFunctionReturn(0);
651 }
652 
653 PetscErrorCode MatProductNumeric_ABt(Mat mat)
654 {
655   PetscErrorCode ierr;
656   Mat_Product    *product = mat->product;
657   Mat            A=product->A,B=product->B;
658 
659   PetscFunctionBegin;
660   ierr = PetscLogEventBegin(MAT_MatTransposeMultNumeric,A,B,0,0);CHKERRQ(ierr);
661   ierr = (mat->ops->mattransposemultnumeric)(A,B,mat);CHKERRQ(ierr);
662   ierr = PetscLogEventEnd(MAT_MatTransposeMultNumeric,A,B,0,0);CHKERRQ(ierr);
663   PetscFunctionReturn(0);
664 }
665 
666 PetscErrorCode MatProductNumeric_PtAP(Mat mat)
667 {
668   PetscErrorCode ierr;
669   Mat_Product    *product = mat->product;
670   Mat            A=product->A,B=product->B;
671 
672   PetscFunctionBegin;
673   ierr = PetscLogEventBegin(MAT_PtAPNumeric,mat,0,0,0);CHKERRQ(ierr);
674   ierr = (mat->ops->ptapnumeric)(A,B,mat);CHKERRQ(ierr);
675   ierr = PetscLogEventEnd(MAT_PtAPNumeric,mat,0,0,0);CHKERRQ(ierr);
676   PetscFunctionReturn(0);
677 }
678 
679 PetscErrorCode MatProductNumeric_RARt(Mat mat)
680 {
681   PetscErrorCode ierr;
682   Mat_Product    *product = mat->product;
683   Mat            A=product->A,B=product->B;
684 
685   PetscFunctionBegin;
686   ierr = PetscLogEventBegin(MAT_RARtNumeric,A,B,0,0);CHKERRQ(ierr);
687   ierr = (mat->ops->rartnumeric)(A,B,mat);CHKERRQ(ierr);
688   ierr = PetscLogEventEnd(MAT_RARtNumeric,A,B,0,0);CHKERRQ(ierr);
689   PetscFunctionReturn(0);
690 }
691 
692 PetscErrorCode MatProductNumeric_ABC(Mat mat)
693 {
694   PetscErrorCode ierr;
695   Mat_Product    *product = mat->product;
696   Mat            A=product->A,B=product->B,C=product->C;
697 
698   PetscFunctionBegin;
699   ierr = PetscLogEventBegin(MAT_MatMatMultNumeric,A,B,C,0);CHKERRQ(ierr);
700   ierr = (mat->ops->matmatmultnumeric)(A,B,C,mat);CHKERRQ(ierr);
701   ierr = PetscLogEventEnd(MAT_MatMatMultNumeric,A,B,C,0);CHKERRQ(ierr);
702   PetscFunctionReturn(0);
703 }
704 
705 /*@
706    MatProductNumeric - Implement a matrix product with numerical values.
707 
708    Collective on Mat
709 
710    Input Parameters:
711 .  mat - the matrix to hold a product
712 
713    Output Parameters:
714 .  mat - the matrix product
715 
716    Level: intermediate
717 
718 .seealso: MatProductCreate(), MatSetType()
719 @*/
720 PetscErrorCode MatProductNumeric(Mat mat)
721 {
722   PetscErrorCode ierr;
723 
724   PetscFunctionBegin;
725   PetscValidPointer(mat,1);
726   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
727 
728   if (mat->ops->productnumeric) {
729     ierr = (*mat->ops->productnumeric)(mat);CHKERRQ(ierr);
730   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_USER,"Call MatProductSymbolic() first");
731   PetscFunctionReturn(0);
732 }
733 
734 /* ----------------------------------------------- */
735 PetscErrorCode MatProductSymbolic_AB(Mat mat)
736 {
737   PetscErrorCode ierr;
738   Mat_Product    *product = mat->product;
739   Mat            A=product->A,B=product->B;
740 
741   PetscFunctionBegin;
742   ierr = (mat->ops->matmultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr);
743   mat->ops->productnumeric = MatProductNumeric_AB;
744   PetscFunctionReturn(0);
745 }
746 
747 PetscErrorCode MatProductSymbolic_AtB(Mat mat)
748 {
749   PetscErrorCode ierr;
750   Mat_Product    *product = mat->product;
751   Mat            A=product->A,B=product->B;
752 
753   PetscFunctionBegin;
754   ierr = (mat->ops->transposematmultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr);
755   mat->ops->productnumeric = MatProductNumeric_AtB;
756   PetscFunctionReturn(0);
757 }
758 
759 PetscErrorCode MatProductSymbolic_ABt(Mat mat)
760 {
761   PetscErrorCode ierr;
762   Mat_Product    *product = mat->product;
763   Mat            A=product->A,B=product->B;
764 
765   PetscFunctionBegin;
766   ierr = (mat->ops->mattransposemultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr);
767   mat->ops->productnumeric = MatProductNumeric_ABt;
768   PetscFunctionReturn(0);
769 }
770 
771 PetscErrorCode MatProductSymbolic_ABC(Mat mat)
772 {
773   PetscErrorCode ierr;
774   Mat_Product    *product = mat->product;
775   Mat            A=product->A,B=product->B,C=product->C;
776 
777   PetscFunctionBegin;
778   ierr = (mat->ops->matmatmultsymbolic)(A,B,C,product->fill,mat);CHKERRQ(ierr);
779   mat->ops->productnumeric = MatProductNumeric_ABC;
780   PetscFunctionReturn(0);
781 }
782 
783 /*@
784    MatProductSymbolic - Perform the symbolic portion of a matrix product, this creates a data structure for use with the numerical produce.
785 
786    Collective on Mat
787 
788    Input Parameters:
789 .  mat - the matrix to hold a product
790 
791    Output Parameters:
792 .  mat - the matrix product data structure
793 
794    Level: intermediate
795 
796 .seealso: MatProductCreate(), MatSetType(), MatProductNumeric(), MatProductType, MatProductAlgorithm
797 @*/
798 PetscErrorCode MatProductSymbolic(Mat mat)
799 {
800   PetscErrorCode ierr;
801   Mat_Product    *product = mat->product;
802   MatProductType productype = product->type;
803   PetscLogEvent  eventtype=-1;
804 
805   PetscFunctionBegin;
806   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
807 
808   /* log event */
809   switch (productype) {
810   case MATPRODUCT_AB:
811     eventtype = MAT_MatMultSymbolic;
812     break;
813   case MATPRODUCT_AtB:
814     eventtype = MAT_TransposeMatMultSymbolic;
815     break;
816   case MATPRODUCT_ABt:
817     eventtype = MAT_MatTransposeMultSymbolic;
818     break;
819   case MATPRODUCT_PtAP:
820     eventtype = MAT_PtAPSymbolic;
821     break;
822   case MATPRODUCT_RARt:
823     eventtype = MAT_RARtSymbolic;
824     break;
825   case MATPRODUCT_ABC:
826     eventtype = MAT_MatMatMultSymbolic;
827     break;
828   default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"MATPRODUCT type is not supported");
829   }
830 
831   if (mat->ops->productsymbolic) {
832     ierr = PetscLogEventBegin(eventtype,mat,0,0,0);CHKERRQ(ierr);
833     ierr = (*mat->ops->productsymbolic)(mat);CHKERRQ(ierr);
834     ierr = PetscLogEventEnd(eventtype,mat,0,0,0);CHKERRQ(ierr);
835   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_USER,"Call MatProductSetFromOptions() first");
836   PetscFunctionReturn(0);
837 }
838 
839 /*@
840    MatProductSetFill - Set an expected fill of the matrix product.
841 
842    Collective on Mat
843 
844    Input Parameters:
845 +  mat - the matrix product
846 -  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.
847 
848    Level: intermediate
849 
850 .seealso: MatProductSetType(), MatProductSetAlgorithm(), MatProductCreate()
851 @*/
852 PetscErrorCode MatProductSetFill(Mat mat,PetscReal fill)
853 {
854   Mat_Product *product = mat->product;
855 
856   PetscFunctionBegin;
857   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
858 
859   if (!product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_NULL,"Data struc Mat_Product is not created, call MatProductCreate() first");
860   if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) {
861     product->fill = 2.0;
862   } else product->fill = fill;
863   PetscFunctionReturn(0);
864 }
865 
866 /*@
867    MatProductSetAlgorithm - Requests a particular algorithm for a matrix product implementation.
868 
869    Collective on Mat
870 
871    Input Parameters:
872 +  mat - the matrix product
873 -  alg - particular implementation algorithm of the matrix product, e.g., MATPRODUCTALGORITHM_DEFAULT.
874 
875    Level: intermediate
876 
877 .seealso: MatProductSetType(), MatProductSetFill(), MatProductCreate()
878 @*/
879 PetscErrorCode MatProductSetAlgorithm(Mat mat,MatProductAlgorithm alg)
880 {
881   Mat_Product *product = mat->product;
882 
883   PetscFunctionBegin;
884   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
885 
886   if (!product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_NULL,"Data struc Mat_Product is not created, call MatProductCreate() first");
887   product->alg = alg;
888   PetscFunctionReturn(0);
889 }
890 
891 /*@
892    MatProductSetType - Sets a particular matrix product type, for example Mat*Mat.
893 
894    Collective on Mat
895 
896    Input Parameters:
897 +  mat - the matrix
898 -  productype   - matrix product type, e.g., MATPRODUCT_AB,MATPRODUCT_AtB,MATPRODUCT_ABt,MATPRODUCT_PtAP,MATPRODUCT_RARt,MATPRODUCT_ABC.
899 
900    Level: intermediate
901 
902 .seealso: MatProductCreate(), MatProductType, MatProductAlgorithm
903 @*/
904 PetscErrorCode MatProductSetType(Mat mat,MatProductType productype)
905 {
906   PetscErrorCode ierr;
907   Mat_Product    *product = mat->product;
908   MPI_Comm       comm;
909 
910   PetscFunctionBegin;
911   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
912 
913   ierr = PetscObjectGetComm((PetscObject)mat,&comm);CHKERRQ(ierr);
914   if (!product) SETERRQ(comm,PETSC_ERR_ARG_NULL,"Data struc Mat_Product is not created, call MatProductCreate() first");
915   product->type = productype;
916 
917   switch (productype) {
918   case MATPRODUCT_AB:
919     mat->ops->productsetfromoptions = MatProductSetFromOptions_AB;
920     break;
921   case MATPRODUCT_AtB:
922     mat->ops->productsetfromoptions = MatProductSetFromOptions_AtB;
923     break;
924   case MATPRODUCT_ABt:
925     mat->ops->productsetfromoptions = MatProductSetFromOptions_ABt;
926     break;
927   case MATPRODUCT_PtAP:
928     mat->ops->productsetfromoptions = MatProductSetFromOptions_PtAP;
929     break;
930   case MATPRODUCT_RARt:
931     mat->ops->productsetfromoptions = MatProductSetFromOptions_RARt;
932     break;
933   case MATPRODUCT_ABC:
934     mat->ops->productsetfromoptions = MatProductSetFromOptions_ABC;
935     break;
936   default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType is not supported\n");
937   }
938   PetscFunctionReturn(0);
939 }
940 
941 /*@
942    MatProductClear - Clears matrix product internal structure.
943 
944    Collective on Mat
945 
946    Input Parameters:
947 .  mat - the product matrix
948 
949    Level: intermediate
950 @*/
951 PetscErrorCode MatProductClear(Mat mat)
952 {
953   PetscErrorCode ierr;
954   Mat_Product    *product = mat->product;
955 
956   PetscFunctionBegin;
957   if (product) {
958     /* release reference */
959     ierr = MatDestroy(&product->A);CHKERRQ(ierr);
960     ierr = MatDestroy(&product->B);CHKERRQ(ierr);
961     ierr = MatDestroy(&product->C);CHKERRQ(ierr);
962     ierr = MatDestroy(&product->Dwork);CHKERRQ(ierr);
963     ierr = PetscFree(mat->product);CHKERRQ(ierr);
964   }
965   PetscFunctionReturn(0);
966 }
967 
968 /* Create a supporting struct and attach it to the matrix product */
969 PetscErrorCode MatProductCreate_Private(Mat A,Mat B,Mat C,Mat D)
970 {
971   PetscErrorCode ierr;
972   Mat_Product    *product=NULL;
973 
974   PetscFunctionBegin;
975   ierr = PetscNewLog(D,&product);CHKERRQ(ierr);
976   product->A        = A;
977   product->B        = B;
978   product->C        = C;
979   product->Dwork    = NULL;
980   product->alg      = MATPRODUCTALGORITHM_DEFAULT;
981   product->fill     = 2.0; /* PETSC_DEFAULT */
982   product->Areplaced = PETSC_FALSE;
983   product->Breplaced = PETSC_FALSE;
984   product->api_user  = PETSC_FALSE;
985   D->product         = product;
986 
987   /* take ownership */
988   ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);
989   ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr);
990   ierr = PetscObjectReference((PetscObject)C);CHKERRQ(ierr);
991   PetscFunctionReturn(0);
992 }
993 
994 /*@
995    MatProductCreateWithMat - Setup a given matrix as a matrix product.
996 
997    Collective on Mat
998 
999    Input Parameters:
1000 +  A - the first matrix
1001 .  B - the second matrix
1002 .  C - the third matrix (optional)
1003 -  D - the matrix which will be used as a product
1004 
1005    Output Parameters:
1006 .  D - the product matrix
1007 
1008    Level: intermediate
1009 
1010 .seealso: MatProductCreate()
1011 @*/
1012 PetscErrorCode MatProductCreateWithMat(Mat A,Mat B,Mat C,Mat D)
1013 {
1014   PetscErrorCode ierr;
1015 
1016   PetscFunctionBegin;
1017   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1018   PetscValidType(A,1);
1019   MatCheckPreallocated(A,1);
1020   if (!A->assembled) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1021   if (A->factortype) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1022 
1023   PetscValidHeaderSpecific(B,MAT_CLASSID,2);
1024   PetscValidType(B,2);
1025   MatCheckPreallocated(B,2);
1026   if (!B->assembled) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1027   if (B->factortype) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1028 
1029   if (C) {
1030     PetscValidHeaderSpecific(C,MAT_CLASSID,3);
1031     PetscValidType(C,3);
1032     MatCheckPreallocated(C,3);
1033     if (!C->assembled) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1034     if (C->factortype) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1035   }
1036 
1037   PetscValidHeaderSpecific(D,MAT_CLASSID,4);
1038   PetscValidType(D,4);
1039   MatCheckPreallocated(D,4);
1040   if (!D->assembled) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1041   if (D->factortype) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1042 
1043   /* Create a supporting struct and attach it to D */
1044   ierr = MatProductCreate_Private(A,B,C,D);CHKERRQ(ierr);
1045   PetscFunctionReturn(0);
1046 }
1047 
1048 /*@
1049    MatProductCreate - create a matrix product object that can be used to compute various matrix times matrix operations.
1050 
1051    Collective on Mat
1052 
1053    Input Parameters:
1054 +  A - the first matrix
1055 .  B - the second matrix
1056 -  C - the third matrix (optional)
1057 
1058    Output Parameters:
1059 .  D - the product matrix
1060 
1061    Level: intermediate
1062 
1063 .seealso: MatProductCreateWithMat(), MatProductSetType(), MatProductSetAlgorithm()
1064 @*/
1065 PetscErrorCode MatProductCreate(Mat A,Mat B,Mat C,Mat *D)
1066 {
1067   PetscErrorCode ierr;
1068 
1069   PetscFunctionBegin;
1070   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1071   PetscValidType(A,1);
1072   MatCheckPreallocated(A,1);
1073   if (!A->assembled) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1074   if (A->factortype) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1075 
1076   PetscValidHeaderSpecific(B,MAT_CLASSID,2);
1077   PetscValidType(B,2);
1078   MatCheckPreallocated(B,2);
1079   if (!B->assembled) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1080   if (B->factortype) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1081 
1082   if (C) {
1083     PetscValidHeaderSpecific(C,MAT_CLASSID,3);
1084     PetscValidType(C,3);
1085     MatCheckPreallocated(C,3);
1086     if (!C->assembled) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1087     if (C->factortype) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1088   }
1089 
1090   PetscValidPointer(D,4);
1091 
1092   ierr = MatCreate(PetscObjectComm((PetscObject)A),D);CHKERRQ(ierr);
1093   ierr = MatProductCreate_Private(A,B,C,*D);CHKERRQ(ierr);
1094   PetscFunctionReturn(0);
1095 }
1096