Actual source code: matproduct.c

petsc-3.13.0 2020-03-29
Report Typos and Errors

  2: /*
  3:     Routines for matrix products. Calling procedure:

  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;

 19:     PetscLogEventBegin()
 20:     MatProductSymbolic(D):
 21:       # Call MatxxxSymbolic_Atype_Btype_Ctype();
 22:       # Set D->ops->productnumeric = MatProductNumeric_productype_Atype_Btype_Ctype;
 23:     PetscLogEventEnd()

 25:     PetscLogEventBegin()
 26:     MatProductNumeric(D);
 27:       # Call (D->ops->matxxxnumeric)();
 28:     PetscLogEventEnd()
 29: */

 31:  #include <petsc/private/matimpl.h>

 33: static PetscErrorCode MatProductNumeric_PtAP_Basic(Mat C)
 34: {
 36:   Mat_Product    *product = C->product;
 37:   Mat            P = product->B,AP = product->Dwork;

 40:   /* AP = A*P */
 41:   MatProductNumeric(AP);
 42:   /* C = P^T*AP */
 43:   (C->ops->transposematmultnumeric)(P,AP,C);
 44:   return(0);
 45: }

 47: static PetscErrorCode MatProductSymbolic_PtAP_Basic(Mat C)
 48: {
 50:   Mat_Product    *product = C->product;
 51:   Mat            A=product->A,P=product->B,AP;
 52:   PetscReal      fill=product->fill;

 55:   /* AP = A*P */
 56:   MatProductCreate(A,P,NULL,&AP);
 57:   MatProductSetType(AP,MATPRODUCT_AB);
 58:   MatProductSetAlgorithm(AP,"default");
 59:   MatProductSetFill(AP,fill);
 60:   MatProductSetFromOptions(AP);
 61:   MatProductSymbolic(AP);

 63:   /* C = P^T*AP */
 64:   MatProductSetType(C,MATPRODUCT_AtB);
 65:   product->alg = "default";
 66:   product->A   = P;
 67:   product->B   = AP;
 68:   MatProductSetFromOptions(C);
 69:   MatProductSymbolic(C);

 71:   /* resume user's original input matrix setting for A and B */
 72:   product->A     = A;
 73:   product->B     = P;
 74:   product->Dwork = AP;

 76:   C->ops->productnumeric = MatProductNumeric_PtAP_Basic;
 77:   return(0);
 78: }

 80: static PetscErrorCode MatProductNumeric_RARt_Basic(Mat C)
 81: {
 83:   Mat_Product    *product = C->product;
 84:   Mat            R=product->B,RA=product->Dwork;

 87:   /* RA = R*A */
 88:   MatProductNumeric(RA);
 89:   /* C = RA*R^T */
 90:   (C->ops->mattransposemultnumeric)(RA,R,C);
 91:   return(0);
 92: }

 94: static PetscErrorCode MatProductSymbolic_RARt_Basic(Mat C)
 95: {
 97:   Mat_Product    *product = C->product;
 98:   Mat            A=product->A,R=product->B,RA;
 99:   PetscReal      fill=product->fill;

102:   /* RA = R*A */
103:   MatProductCreate(R,A,NULL,&RA);
104:   MatProductSetType(RA,MATPRODUCT_AB);
105:   MatProductSetAlgorithm(RA,"default");
106:   MatProductSetFill(RA,fill);
107:   MatProductSetFromOptions(RA);
108:   MatProductSymbolic(RA);

110:   /* C = RA*R^T */
111:   MatProductSetType(C,MATPRODUCT_ABt);
112:   product->alg  = "default";
113:   product->A    = RA;
114:   MatProductSetFromOptions(C);
115:   MatProductSymbolic(C);

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:   return(0);
122: }

124: static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat)
125: {
127:   Mat_Product    *product = mat->product;
128:   Mat            A=product->A,BC=product->Dwork;

131:   /* Numeric BC = B*C */
132:   MatProductNumeric(BC);
133:   /* Numeric mat = A*BC */
134:   (mat->ops->matmultnumeric)(A,BC,mat);
135:   return(0);
136: }

138: static PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat)
139: {
141:   Mat_Product    *product = mat->product;
142:   Mat            B=product->B,C=product->C,BC;
143:   PetscReal      fill=product->fill;

146:   /* Symbolic BC = B*C */
147:   MatProductCreate(B,C,NULL,&BC);
148:   MatProductSetType(BC,MATPRODUCT_AB);
149:   MatProductSetAlgorithm(BC,"default");
150:   MatProductSetFill(BC,fill);
151:   MatProductSetFromOptions(BC);
152:   MatProductSymbolic(BC);

154:   /* Symbolic mat = A*BC */
155:   MatProductSetType(mat,MATPRODUCT_AB);
156:   product->alg   = "default";
157:   product->B     = BC;
158:   product->Dwork = BC;
159:   MatProductSetFromOptions(mat);
160:   MatProductSymbolic(mat);

162:   /* resume user's original input matrix setting for B */
163:   product->B = B;
164:   mat->ops->productnumeric = MatProductNumeric_ABC_Basic;
165:   return(0);
166: }

168: PetscErrorCode MatProductSymbolic_Basic(Mat mat)
169: {
171:   Mat_Product    *product = mat->product;

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:     MatProductSymbolic_PtAP_Basic(mat);
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:     MatProductSymbolic_RARt_Basic(mat);
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:     MatProductSymbolic_ABC_Basic(mat);
186:     break;
187:   default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType is not supported");
188:   }
189:   return(0);
190: }

192: /* ----------------------------------------------- */
193: /*@C
194:    MatProductReplaceMats - Replace input matrices for a matrix product.

196:    Collective on Mat

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

204:    Level: intermediate

206:    Notes:
207:      Input matrix must have exactly same data structure as replaced one.

209: .seealso: MatProductCreate()
210: @*/
211: PetscErrorCode MatProductReplaceMats(Mat A,Mat B,Mat C,Mat D)
212: {
213:   Mat_Product    *product=D->product;

216:   if (!product) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_NULL,"Mat D does not have struct 'product'. Call MatProductReplaceProduct(). \n");
217:   if (A) {
218:     if (!product->Areplaced) {
219:       product->A = A;
220:     } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"Matrix A was changed by a PETSc internal routine, cannot be replaced");
221:   }
222:   if (B) {
223:     if (!product->Breplaced) {
224:       product->B = B;
225:     } else SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"Matrix B was changed by a PETSc internal routine, cannot be replaced");
226:   }
227:   if (C) product->C = C;
228:   return(0);
229: }

231: /* ----------------------------------------------- */
232: static PetscErrorCode MatProductSetFromOptions_AB(Mat mat)
233: {
235:   Mat_Product    *product = mat->product;
236:   Mat            A=product->A,B=product->B;
237:   PetscBool      sametype;
238:   PetscErrorCode (*fA)(Mat);
239:   PetscErrorCode (*fB)(Mat);
240:   PetscErrorCode (*f)(Mat)=NULL;
241:   PetscBool      A_istrans,B_istrans;

244:   /* Check matrix global sizes */
245:   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);

247:   fA = A->ops->productsetfromoptions;
248:   fB = B->ops->productsetfromoptions;

250:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);
251:   PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&A_istrans);
252:   PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&B_istrans);

254:   if (fB == fA && sametype && (!A_istrans || !B_istrans)) {
255:     f = fB;
256:   } else {
257:     char      mtypes[256];
258:     PetscBool At_istrans=PETSC_TRUE,Bt_istrans=PETSC_TRUE;
259:     Mat       At = NULL,Bt = NULL;

261:     if (A_istrans && !B_istrans) {
262:       MatTransposeGetMat(A,&At);
263:       PetscObjectTypeCompare((PetscObject)At,MATTRANSPOSEMAT,&At_istrans);
264:       if (At_istrans) { /* mat = ATT * B */
265:         Mat Att = NULL;
266:         MatTransposeGetMat(At,&Att);
267:         A                  = Att;
268:         product->A         = Att; /* use Att for matproduct */
269:         product->Areplaced = PETSC_TRUE; /* Att = A, but has native matrix type */
270:       } else { /* !At_istrans: mat = At^T*B */
271:         A                  = At;
272:         product->A         = At;
273:         product->Areplaced = PETSC_TRUE;
274:         product->type      = MATPRODUCT_AtB;
275:       }
276:     } else if (!A_istrans && B_istrans) {
277:       MatTransposeGetMat(B,&Bt);
278:       PetscObjectTypeCompare((PetscObject)Bt,MATTRANSPOSEMAT,&Bt_istrans);
279:       if (Bt_istrans) { /* mat = A * BTT */
280:         Mat Btt = NULL;
281:         MatTransposeGetMat(Bt,&Btt);
282:         B                  = Btt;
283:         product->B         = Btt; /* use Btt for matproduct */
284:         product->Breplaced = PETSC_TRUE;
285:       } else { /* !Bt_istrans */
286:         /* mat = A*Bt^T */
287:         B                  = Bt;
288:         product->B         = Bt;
289:         product->Breplaced = PETSC_TRUE;
290:         product->type = MATPRODUCT_ABt;
291:       }
292:     } else if (A_istrans && B_istrans) { /* mat = At^T * Bt^T */
293:       MatTransposeGetMat(A,&At);
294:       PetscObjectTypeCompare((PetscObject)At,MATTRANSPOSEMAT,&At_istrans);
295:       MatTransposeGetMat(B,&Bt);
296:       PetscObjectTypeCompare((PetscObject)Bt,MATTRANSPOSEMAT,&Bt_istrans);
297:       if (At_istrans && Bt_istrans) {
298:         Mat Att= NULL,Btt = NULL;
299:         MatTransposeGetMat(At,&Att);
300:         MatTransposeGetMat(Bt,&Btt);
301:         A             = Att;
302:         product->A    = Att; product->Areplaced = PETSC_TRUE;
303:         B             = Btt;
304:         product->B    = Btt; product->Breplaced = PETSC_TRUE;
305:       } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Not supported yet");
306:     }

308:     /* query MatProductSetFromOptions_Atype_Btype */
309:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
310:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
311:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
312:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
313:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));
314:     PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
315:     if (!f) {
316:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
317:     }
318:   }

320:   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);
321:   (*f)(mat);
322:   return(0);
323: }

325: static PetscErrorCode MatProductSetFromOptions_AtB(Mat mat)
326: {
328:   Mat_Product    *product = mat->product;
329:   Mat            A=product->A,B=product->B;
330:   PetscBool      sametype;
331:   PetscErrorCode (*fA)(Mat);
332:   PetscErrorCode (*fB)(Mat);
333:   PetscErrorCode (*f)(Mat)=NULL;

336:   /* Check matrix global sizes */
337:   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);

339:   fA = A->ops->productsetfromoptions;
340:   fB = B->ops->productsetfromoptions;

342:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);

344:   if (fB == fA && sametype) {
345:     f = fB;
346:   } else {
347:     char      mtypes[256];
348:     PetscBool istrans;
349:     PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&istrans);
350:     if (!istrans) {
351:       /* query MatProductSetFromOptions_Atype_Btype */
352:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
353:       PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
354:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
355:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
356:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));
357:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
358:     } else {
359:       Mat T = NULL;
360:       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);

362:       MatTransposeGetMat(A,&T);
363:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
364:       PetscStrlcat(mtypes,((PetscObject)T)->type_name,sizeof(mtypes));
365:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
366:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
367:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));

369:       product->type = MATPRODUCT_AtB;
370:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
371:     }

373:     if (!f) {
374:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
375:     }
376:   }
377:   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);

379:   (*f)(mat);
380:   return(0);
381: }

383: static PetscErrorCode MatProductSetFromOptions_ABt(Mat mat)
384: {
386:   Mat_Product    *product = mat->product;
387:   Mat            A=product->A,B=product->B;
388:   PetscBool      sametype;
389:   PetscErrorCode (*fA)(Mat);
390:   PetscErrorCode (*fB)(Mat);
391:   PetscErrorCode (*f)(Mat)=NULL;

394:   /* Check matrix global sizes */
395:   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);

397:   fA = A->ops->productsetfromoptions;
398:   fB = B->ops->productsetfromoptions;

400:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);

402:   if (fB == fA && sametype) {
403:     f = fB;
404:   } else {
405:     char      mtypes[256];
406:     PetscBool istrans;
407:     PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&istrans);
408:     if (!istrans) {
409:       /* query MatProductSetFromOptions_Atype_Btype */
410:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
411:       PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
412:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
413:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
414:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));
415:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
416:     } else {
417:       Mat T = NULL;
418:       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);

420:       MatTransposeGetMat(A,&T);
421:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
422:       PetscStrlcat(mtypes,((PetscObject)T)->type_name,sizeof(mtypes));
423:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
424:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
425:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));

427:       product->type = MATPRODUCT_ABt;
428:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
429:     }

431:     if (!f) {
432:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
433:     }
434:   }
435:   if (!f) {
436:     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);
437:   }

439:   (*f)(mat);
440:   return(0);
441: }

443: static PetscErrorCode MatProductSetFromOptions_PtAP(Mat mat)
444: {
446:   Mat_Product    *product = mat->product;
447:   Mat            A=product->A,B=product->B;
448:   PetscBool      sametype;
449:   PetscErrorCode (*fA)(Mat);
450:   PetscErrorCode (*fB)(Mat);
451:   PetscErrorCode (*f)(Mat)=NULL;

454:   /* Check matrix global sizes */
455:   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);
456:   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);

458:   fA = A->ops->productsetfromoptions;
459:   fB = B->ops->productsetfromoptions;

461:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);
462:   if (fB == fA && sametype) {
463:     f = fB;
464:   } else {
465:     /* query MatProductSetFromOptions_Atype_Btype */
466:     char  mtypes[256];
467:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
468:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
469:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
470:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
471:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));
472:     PetscObjectQueryFunction((PetscObject)B,mtypes,&f);

474:     if (!f) {
475:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
476:     }
477:   }

479:   if (f) {
480:     (*f)(mat);
481:   } else {
482:     mat->ops->productsymbolic = MatProductSymbolic_Basic;
483:     PetscInfo2((PetscObject)mat, "MatProductSetFromOptions_PtAP for A %s, P %s uses MatProduct_Basic() implementation",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
484:   }
485:   return(0);
486: }

488: static PetscErrorCode MatProductSetFromOptions_RARt(Mat mat)
489: {
491:   Mat_Product    *product = mat->product;
492:   Mat            A=product->A,B=product->B;
493:   PetscBool      sametype;
494:   PetscErrorCode (*fA)(Mat);
495:   PetscErrorCode (*fB)(Mat);
496:   PetscErrorCode (*f)(Mat)=NULL;

499:   /* Check matrix global sizes */
500:   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);
501:   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);

503:   fA = A->ops->productsetfromoptions;
504:   fB = B->ops->productsetfromoptions;

506:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);
507:   if (fB == fA && sametype) {
508:     f = fB;
509:   } else {
510:     /* query MatProductSetFromOptions_Atype_Btype */
511:     char  mtypes[256];
512:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
513:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
514:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
515:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
516:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));
517:     PetscObjectQueryFunction((PetscObject)B,mtypes,&f);

519:     if (!f) {
520:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
521:     }
522:   }

524:   if (f) {
525:     (*f)(mat);
526:   } else {
527:     mat->ops->productsymbolic = MatProductSymbolic_Basic;
528:   }
529:   return(0);
530: }

532: static PetscErrorCode MatProductSetFromOptions_ABC(Mat mat)
533: {
535:   Mat_Product    *product = mat->product;
536:   Mat            A=product->A,B=product->B,C=product->C;
537:   PetscErrorCode (*fA)(Mat);
538:   PetscErrorCode (*fB)(Mat);
539:   PetscErrorCode (*fC)(Mat);
540:   PetscErrorCode (*f)(Mat)=NULL;

543:   /* Check matrix global sizes */
544:   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);
545:   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);

547:   fA = A->ops->productsetfromoptions;
548:   fB = B->ops->productsetfromoptions;
549:   fC = C->ops->productsetfromoptions;
550:   if (fA == fB && fA == fC && fA) {
551:     f = fA;
552:   } else {
553:     /* query MatProductSetFromOptions_Atype_Btype_Ctype */
554:     char  mtypes[256];
555:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
556:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
557:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
558:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
559:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
560:     PetscStrlcat(mtypes,((PetscObject)C)->type_name,sizeof(mtypes));
561:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));

563:     PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
564:     if (!f) {
565:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
566:     }
567:     if (!f) {
568:       PetscObjectQueryFunction((PetscObject)C,mtypes,&f);
569:     }
570:   }

572:   if (f) {
573:     (*f)(mat);
574:   } else { /* use MatProductSymbolic/Numeric_Basic() */
575:     mat->ops->productsymbolic = MatProductSymbolic_Basic;
576:   }
577:   return(0);
578: }

580: /*@C
581:    MatProductSetFromOptions - Creates a matrix product where the type, the algorithm etc are determined from the options database.

583:    Logically Collective on Mat

585:    Input Parameter:
586: .  mat - the matrix

588:    Level: beginner

590: .seealso: MatSetFromOptions()
591: @*/
592: PetscErrorCode MatProductSetFromOptions(Mat mat)
593: {


599:   if (mat->ops->productsetfromoptions) {
600:     (*mat->ops->productsetfromoptions)(mat);
601:   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_NULL,"Call MatProductSetType() first");
602:   return(0);
603: }

605: /* ----------------------------------------------- */
606: PetscErrorCode MatProductNumeric_AB(Mat mat)
607: {
609:   Mat_Product    *product = mat->product;
610:   Mat            A=product->A,B=product->B;

613:   PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);
614:   (mat->ops->matmultnumeric)(A,B,mat);
615:   PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);
616:   return(0);
617: }

619: PetscErrorCode MatProductNumeric_AtB(Mat mat)
620: {
622:   Mat_Product    *product = mat->product;
623:   Mat            A=product->A,B=product->B;

626:   PetscLogEventBegin(MAT_TransposeMatMultNumeric,A,B,0,0);
627:   (mat->ops->transposematmultnumeric)(A,B,mat);
628:   PetscLogEventEnd(MAT_TransposeMatMultNumeric,A,B,0,0);
629:   return(0);
630: }

632: PetscErrorCode MatProductNumeric_ABt(Mat mat)
633: {
635:   Mat_Product    *product = mat->product;
636:   Mat            A=product->A,B=product->B;

639:   PetscLogEventBegin(MAT_MatTransposeMultNumeric,A,B,0,0);
640:   (mat->ops->mattransposemultnumeric)(A,B,mat);
641:   PetscLogEventEnd(MAT_MatTransposeMultNumeric,A,B,0,0);
642:   return(0);
643: }

645: PetscErrorCode MatProductNumeric_PtAP(Mat mat)
646: {
648:   Mat_Product    *product = mat->product;
649:   Mat            A=product->A,B=product->B;

652:   PetscLogEventBegin(MAT_PtAPNumeric,mat,0,0,0);
653:   (mat->ops->ptapnumeric)(A,B,mat);
654:   PetscLogEventEnd(MAT_PtAPNumeric,mat,0,0,0);
655:   return(0);
656: }

658: PetscErrorCode MatProductNumeric_RARt(Mat mat)
659: {
661:   Mat_Product    *product = mat->product;
662:   Mat            A=product->A,B=product->B;

665:   PetscLogEventBegin(MAT_RARtNumeric,A,B,0,0);
666:   (mat->ops->rartnumeric)(A,B,mat);
667:   PetscLogEventEnd(MAT_RARtNumeric,A,B,0,0);
668:   return(0);
669: }

671: PetscErrorCode MatProductNumeric_ABC(Mat mat)
672: {
674:   Mat_Product    *product = mat->product;
675:   Mat            A=product->A,B=product->B,C=product->C;

678:   PetscLogEventBegin(MAT_MatMatMultNumeric,A,B,C,0);
679:   (mat->ops->matmatmultnumeric)(A,B,C,mat);
680:   PetscLogEventEnd(MAT_MatMatMultNumeric,A,B,C,0);
681:   return(0);
682: }

684: /*@
685:    MatProductNumeric - Implement a matrix product with numerical values.

687:    Collective on Mat

689:    Input Parameters:
690: .  mat - the matrix to hold a product

692:    Output Parameters:
693: .  mat - the matrix product

695:    Level: intermediate

697: .seealso: MatProductCreate(), MatSetType()
698: @*/
699: PetscErrorCode MatProductNumeric(Mat mat)
700: {


707:   if (mat->ops->productnumeric) {
708:     (*mat->ops->productnumeric)(mat);
709:   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_USER,"Call MatProductSymbolic() first");
710:   return(0);
711: }

713: /* ----------------------------------------------- */
714: PetscErrorCode MatProductSymbolic_AB(Mat mat)
715: {
717:   Mat_Product    *product = mat->product;
718:   Mat            A=product->A,B=product->B;

721:   (mat->ops->matmultsymbolic)(A,B,product->fill,mat);
722:   mat->ops->productnumeric = MatProductNumeric_AB;
723:   return(0);
724: }

726: PetscErrorCode MatProductSymbolic_AtB(Mat mat)
727: {
729:   Mat_Product    *product = mat->product;
730:   Mat            A=product->A,B=product->B;

733:   (mat->ops->transposematmultsymbolic)(A,B,product->fill,mat);
734:   mat->ops->productnumeric = MatProductNumeric_AtB;
735:   return(0);
736: }

738: PetscErrorCode MatProductSymbolic_ABt(Mat mat)
739: {
741:   Mat_Product    *product = mat->product;
742:   Mat            A=product->A,B=product->B;

745:   (mat->ops->mattransposemultsymbolic)(A,B,product->fill,mat);
746:   mat->ops->productnumeric = MatProductNumeric_ABt;
747:   return(0);
748: }

750: PetscErrorCode MatProductSymbolic_ABC(Mat mat)
751: {
753:   Mat_Product    *product = mat->product;
754:   Mat            A=product->A,B=product->B,C=product->C;

757:   (mat->ops->matmatmultsymbolic)(A,B,C,product->fill,mat);
758:   mat->ops->productnumeric = MatProductNumeric_ABC;
759:   return(0);
760: }

762: /*@
763:    MatProductSymbolic - Perform the symbolic portion of a matrix product, this creates a data structure for use with the numerical produce.

765:    Collective on Mat

767:    Input Parameters:
768: .  mat - the matrix to hold a product

770:    Output Parameters:
771: .  mat - the matrix product data structure

773:    Level: intermediate

775: .seealso: MatProductCreate(), MatSetType(), MatProductNumeric(), MatProductType, MatProductAlgorithm
776: @*/
777: PetscErrorCode MatProductSymbolic(Mat mat)
778: {
780:   Mat_Product    *product = mat->product;
781:   MatProductType productype = product->type;
782:   PetscLogEvent  eventtype=-1;


787:   /* log event */
788:   switch (productype) {
789:   case MATPRODUCT_AB:
790:     eventtype = MAT_MatMultSymbolic;
791:     break;
792:   case MATPRODUCT_AtB:
793:     eventtype = MAT_TransposeMatMultSymbolic;
794:     break;
795:   case MATPRODUCT_ABt:
796:     eventtype = MAT_MatTransposeMultSymbolic;
797:     break;
798:   case MATPRODUCT_PtAP:
799:     eventtype = MAT_PtAPSymbolic;
800:     break;
801:   case MATPRODUCT_RARt:
802:     eventtype = MAT_RARtSymbolic;
803:     break;
804:   case MATPRODUCT_ABC:
805:     eventtype = MAT_MatMatMultSymbolic;
806:     break;
807:   default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"MATPRODUCT type is not supported");
808:   }

810:   if (mat->ops->productsymbolic) {
811:     PetscLogEventBegin(eventtype,mat,0,0,0);
812:     (*mat->ops->productsymbolic)(mat);
813:     PetscLogEventEnd(eventtype,mat,0,0,0);
814:   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_USER,"Call MatProductSetFromOptions() first");
815:   return(0);
816: }

818: /*@
819:    MatProductSetFill - Set an expected fill of the matrix product.

821:    Collective on Mat

823:    Input Parameters:
824: +  mat - the matrix product
825: -  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.

827:    Level: intermediate

829: .seealso: MatProductSetType(), MatProductSetAlgorithm(), MatProductCreate()
830: @*/
831: PetscErrorCode MatProductSetFill(Mat mat,PetscReal fill)
832: {
833:   Mat_Product *product = mat->product;


838:   if (!product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_NULL,"Data struc Mat_Product is not created, call MatProductCreate() first");
839:   if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) {
840:     product->fill = 2.0;
841:   } else product->fill = fill;
842:   return(0);
843: }

845: /*@
846:    MatProductSetAlgorithm - Requests a particular algorithm for a matrix product implementation.

848:    Collective on Mat

850:    Input Parameters:
851: +  mat - the matrix product
852: -  alg - particular implementation algorithm of the matrix product, e.g., MATPRODUCTALGORITHM_DEFAULT.

854:    Level: intermediate

856: .seealso: MatProductSetType(), MatProductSetFill(), MatProductCreate()
857: @*/
858: PetscErrorCode MatProductSetAlgorithm(Mat mat,MatProductAlgorithm alg)
859: {
860:   Mat_Product *product = mat->product;


865:   if (!product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_NULL,"Data struc Mat_Product is not created, call MatProductCreate() first");
866:   product->alg = alg;
867:   return(0);
868: }

870: /*@
871:    MatProductSetType - Sets a particular matrix product type, for example Mat*Mat.

873:    Collective on Mat

875:    Input Parameters:
876: +  mat - the matrix
877: -  productype   - matrix product type, e.g., MATPRODUCT_AB,MATPRODUCT_AtB,MATPRODUCT_ABt,MATPRODUCT_PtAP,MATPRODUCT_RARt,MATPRODUCT_ABC.

879:    Level: intermediate

881: .seealso: MatProductCreate(), MatProductType, MatProductAlgorithm
882: @*/
883: PetscErrorCode MatProductSetType(Mat mat,MatProductType productype)
884: {
886:   Mat_Product    *product = mat->product;
887:   MPI_Comm       comm;


892:   PetscObjectGetComm((PetscObject)mat,&comm);
893:   if (!product) SETERRQ(comm,PETSC_ERR_ARG_NULL,"Data struc Mat_Product is not created, call MatProductCreate() first");
894:   product->type = productype;

896:   switch (productype) {
897:   case MATPRODUCT_AB:
898:     mat->ops->productsetfromoptions = MatProductSetFromOptions_AB;
899:     break;
900:   case MATPRODUCT_AtB:
901:     mat->ops->productsetfromoptions = MatProductSetFromOptions_AtB;
902:     break;
903:   case MATPRODUCT_ABt:
904:     mat->ops->productsetfromoptions = MatProductSetFromOptions_ABt;
905:     break;
906:   case MATPRODUCT_PtAP:
907:     mat->ops->productsetfromoptions = MatProductSetFromOptions_PtAP;
908:     break;
909:   case MATPRODUCT_RARt:
910:     mat->ops->productsetfromoptions = MatProductSetFromOptions_RARt;
911:     break;
912:   case MATPRODUCT_ABC:
913:     mat->ops->productsetfromoptions = MatProductSetFromOptions_ABC;
914:     break;
915:   default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType is not supported\n");
916:   }
917:   return(0);
918: }

920: /* Create a supporting struct and attach it to the matrix product */
921: static PetscErrorCode MatProductCreate_Private(Mat A,Mat B,Mat C,Mat D)
922: {
924:   Mat_Product    *product=NULL;

927:   PetscNewLog(D,&product);
928:   product->A        = A;
929:   product->B        = B;
930:   product->C        = C;
931:   product->Dwork    = NULL;
932:   product->alg      = MATPRODUCTALGORITHM_DEFAULT;
933:   product->fill     = 2.0; /* PETSC_DEFAULT */
934:   product->Areplaced = PETSC_FALSE;
935:   product->Breplaced = PETSC_FALSE;
936:   product->api_user  = PETSC_FALSE;
937:   D->product         = product;
938:   return(0);
939: }

941: /*@
942:    MatProductCreateWithMat - Setup a given matrix as a matrix product.

944:    Collective on Mat

946:    Input Parameters:
947: +  A - the first matrix
948: .  B - the second matrix
949: .  C - the third matrix (optional)
950: -  D - the matrix which will be used as a product

952:    Output Parameters:
953: .  D - the product matrix

955:    Level: intermediate

957: .seealso: MatProductCreate()
958: @*/
959: PetscErrorCode MatProductCreateWithMat(Mat A,Mat B,Mat C,Mat D)
960: {

966:   MatCheckPreallocated(A,1);
967:   if (!A->assembled) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
968:   if (A->factortype) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");

972:   MatCheckPreallocated(B,2);
973:   if (!B->assembled) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
974:   if (B->factortype) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");

976:   if (C) {
979:     MatCheckPreallocated(C,3);
980:     if (!C->assembled) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
981:     if (C->factortype) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
982:   }

986:   MatCheckPreallocated(D,4);
987:   if (!D->assembled) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
988:   if (D->factortype) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");

990:   /* Create a supporting struct and attach it to D */
991:   MatProductCreate_Private(A,B,C,D);
992:   return(0);
993: }

995: /*@
996:    MatProductCreate - create a matrix product object that can be used to compute various matrix times matrix operations.

998:    Collective on Mat

1000:    Input Parameters:
1001: +  A - the first matrix
1002: .  B - the second matrix
1003: -  C - the third matrix (optional)

1005:    Output Parameters:
1006: .  D - the product matrix

1008:    Level: intermediate

1010: .seealso: MatProductCreateWithMat(), MatProductSetType(), MatProductSetAlgorithm()
1011: @*/
1012: PetscErrorCode MatProductCreate(Mat A,Mat B,Mat C,Mat *D)
1013: {

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");

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");

1029:   if (C) {
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:   }


1039:   MatCreate(PetscObjectComm((PetscObject)A),D);
1040:   MatProductCreate_Private(A,B,C,*D);
1041:   return(0);
1042: }