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