Actual source code: matproduct.c

petsc-3.13.1 2020-05-02
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: const char *const MatProductTypes[] = {"AB","AtB","ABt","PtAP","RARt","ABC","MatProductType","MAT_Product_",0};

 35: static PetscErrorCode MatProductNumeric_PtAP_Basic(Mat C)
 36: {
 38:   Mat_Product    *product = C->product;
 39:   Mat            P = product->B,AP = product->Dwork;

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

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

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

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

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

 78:   C->ops->productnumeric = MatProductNumeric_PtAP_Basic;
 79:   return(0);
 80: }

 82: static PetscErrorCode MatProductNumeric_RARt_Basic(Mat C)
 83: {
 85:   Mat_Product    *product = C->product;
 86:   Mat            R=product->B,RA=product->Dwork;

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

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

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

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

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

126: static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat)
127: {
129:   Mat_Product    *product = mat->product;
130:   Mat            A=product->A,BC=product->Dwork;

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

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

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

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

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

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

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

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

198:    Collective on Mat

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

206:    Level: intermediate

208:    Notes:
209:      Input matrix must have exactly same data structure as replaced one.

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

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:       PetscObjectReference((PetscObject)A); /* take ownership of input */
223:       MatDestroy(&product->A); /* 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:       PetscObjectReference((PetscObject)B); /* take ownership of input */
230:       MatDestroy(&product->B); /* 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:     PetscObjectReference((PetscObject)C); /* take ownership of input */
236:     MatDestroy(&product->C); /* release old reference */
237:     product->C = C;
238:   }
239:   return(0);
240: }

242: /* ----------------------------------------------- */
243: static PetscErrorCode MatProductSetFromOptions_AB(Mat mat)
244: {
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;

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

258:   fA = A->ops->productsetfromoptions;
259:   fB = B->ops->productsetfromoptions;

261:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);
262:   PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&A_istrans);
263:   PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&B_istrans);

265:   if (fB == fA && sametype && (!A_istrans || !B_istrans)) {
266:     f = fB;
267:   } else {
268:     char      mtypes[256];
269:     PetscBool At_istrans=PETSC_TRUE,Bt_istrans=PETSC_TRUE;
270:     Mat       At = NULL,Bt = NULL;

272:     if (A_istrans && !B_istrans) {
273:       MatTransposeGetMat(A,&At);
274:       PetscObjectTypeCompare((PetscObject)At,MATTRANSPOSEMAT,&At_istrans);
275:       if (At_istrans) { /* mat = ATT * B */
276:         Mat Att = NULL;
277:         MatTransposeGetMat(At,&Att);
278:         PetscObjectReference((PetscObject)Att);
279:         MatDestroy(&product->A);
280:         A                  = Att;
281:         product->A         = Att; /* use Att for matproduct */
282:         product->Areplaced = PETSC_TRUE; /* Att = A, but has native matrix type */
283:       } else { /* !At_istrans: mat = At^T*B */
284:         PetscObjectReference((PetscObject)At);
285:         MatDestroy(&product->A);
286:         A                  = At;
287:         product->A         = At;
288:         product->Areplaced = PETSC_TRUE;
289:         product->type      = MATPRODUCT_AtB;
290:       }
291:     } else if (!A_istrans && B_istrans) {
292:       MatTransposeGetMat(B,&Bt);
293:       PetscObjectTypeCompare((PetscObject)Bt,MATTRANSPOSEMAT,&Bt_istrans);
294:       if (Bt_istrans) { /* mat = A * BTT */
295:         Mat Btt = NULL;
296:         MatTransposeGetMat(Bt,&Btt);
297:         PetscObjectReference((PetscObject)Btt);
298:         MatDestroy(&product->B);
299:         B                  = Btt;
300:         product->B         = Btt; /* use Btt for matproduct */
301:         product->Breplaced = PETSC_TRUE;
302:       } else { /* !Bt_istrans */
303:         /* mat = A*Bt^T */
304:         PetscObjectReference((PetscObject)Bt);
305:         MatDestroy(&product->B);
306:         B                  = Bt;
307:         product->B         = Bt;
308:         product->Breplaced = PETSC_TRUE;
309:         product->type = MATPRODUCT_ABt;
310:       }
311:     } else if (A_istrans && B_istrans) { /* mat = At^T * Bt^T */
312:       MatTransposeGetMat(A,&At);
313:       PetscObjectTypeCompare((PetscObject)At,MATTRANSPOSEMAT,&At_istrans);
314:       MatTransposeGetMat(B,&Bt);
315:       PetscObjectTypeCompare((PetscObject)Bt,MATTRANSPOSEMAT,&Bt_istrans);
316:       if (At_istrans && Bt_istrans) {
317:         Mat Att= NULL,Btt = NULL;
318:         MatTransposeGetMat(At,&Att);
319:         MatTransposeGetMat(Bt,&Btt);
320:         PetscObjectReference((PetscObject)Att);
321:         PetscObjectReference((PetscObject)Btt);
322:         MatDestroy(&product->A);
323:         MatDestroy(&product->B);
324:         A             = Att;
325:         product->A    = Att; product->Areplaced = PETSC_TRUE;
326:         B             = Btt;
327:         product->B    = Btt; product->Breplaced = PETSC_TRUE;
328:       } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Not supported yet");
329:     }

331:     /* query MatProductSetFromOptions_Atype_Btype */
332:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
333:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
334:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
335:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
336:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));
337:     PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
338:     if (!f) {
339:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
340:     }
341:   }

343:   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);
344:   (*f)(mat);
345:   return(0);
346: }

348: static PetscErrorCode MatProductSetFromOptions_AtB(Mat mat)
349: {
351:   Mat_Product    *product = mat->product;
352:   Mat            A=product->A,B=product->B;
353:   PetscBool      sametype;
354:   PetscErrorCode (*fA)(Mat);
355:   PetscErrorCode (*fB)(Mat);
356:   PetscErrorCode (*f)(Mat)=NULL;

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

362:   fA = A->ops->productsetfromoptions;
363:   fB = B->ops->productsetfromoptions;

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

367:   if (fB == fA && sametype) {
368:     f = fB;
369:   } else {
370:     char      mtypes[256];
371:     PetscBool istrans;
372:     PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&istrans);
373:     if (!istrans) {
374:       /* query MatProductSetFromOptions_Atype_Btype */
375:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
376:       PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
377:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
378:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
379:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));
380:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
381:     } else {
382:       Mat T = NULL;
383:       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);

385:       MatTransposeGetMat(A,&T);
386:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
387:       PetscStrlcat(mtypes,((PetscObject)T)->type_name,sizeof(mtypes));
388:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
389:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
390:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));

392:       product->type = MATPRODUCT_AtB;
393:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
394:     }

396:     if (!f) {
397:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
398:     }
399:   }
400:   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);

402:   (*f)(mat);
403:   return(0);
404: }

406: static PetscErrorCode MatProductSetFromOptions_ABt(Mat mat)
407: {
409:   Mat_Product    *product = mat->product;
410:   Mat            A=product->A,B=product->B;
411:   PetscBool      sametype;
412:   PetscErrorCode (*fA)(Mat);
413:   PetscErrorCode (*fB)(Mat);
414:   PetscErrorCode (*f)(Mat)=NULL;

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

420:   fA = A->ops->productsetfromoptions;
421:   fB = B->ops->productsetfromoptions;

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

425:   if (fB == fA && sametype) {
426:     f = fB;
427:   } else {
428:     char      mtypes[256];
429:     PetscBool istrans;
430:     PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&istrans);
431:     if (!istrans) {
432:       /* query MatProductSetFromOptions_Atype_Btype */
433:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
434:       PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
435:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
436:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
437:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));
438:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
439:     } else {
440:       Mat T = NULL;
441:       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);

443:       MatTransposeGetMat(A,&T);
444:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
445:       PetscStrlcat(mtypes,((PetscObject)T)->type_name,sizeof(mtypes));
446:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
447:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
448:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));

450:       product->type = MATPRODUCT_ABt;
451:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
452:     }

454:     if (!f) {
455:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
456:     }
457:   }
458:   if (!f) {
459:     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);
460:   }

462:   (*f)(mat);
463:   return(0);
464: }

466: static PetscErrorCode MatProductSetFromOptions_PtAP(Mat mat)
467: {
469:   Mat_Product    *product = mat->product;
470:   Mat            A=product->A,B=product->B;
471:   PetscBool      sametype;
472:   PetscErrorCode (*fA)(Mat);
473:   PetscErrorCode (*fB)(Mat);
474:   PetscErrorCode (*f)(Mat)=NULL;

477:   /* Check matrix global sizes */
478:   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);
479:   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);

481:   fA = A->ops->productsetfromoptions;
482:   fB = B->ops->productsetfromoptions;

484:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);
485:   if (fB == fA && sametype) {
486:     f = fB;
487:   } else {
488:     /* query MatProductSetFromOptions_Atype_Btype */
489:     char  mtypes[256];
490:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
491:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
492:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
493:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
494:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));
495:     PetscObjectQueryFunction((PetscObject)B,mtypes,&f);

497:     if (!f) {
498:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
499:     }
500:   }

502:   if (f) {
503:     (*f)(mat);
504:   } else {
505:     mat->ops->productsymbolic = MatProductSymbolic_Basic;
506:     PetscInfo2((PetscObject)mat, "MatProductSetFromOptions_PtAP for A %s, P %s uses MatProduct_Basic() implementation",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
507:   }
508:   return(0);
509: }

511: static PetscErrorCode MatProductSetFromOptions_RARt(Mat mat)
512: {
514:   Mat_Product    *product = mat->product;
515:   Mat            A=product->A,B=product->B;
516:   PetscBool      sametype;
517:   PetscErrorCode (*fA)(Mat);
518:   PetscErrorCode (*fB)(Mat);
519:   PetscErrorCode (*f)(Mat)=NULL;

522:   /* Check matrix global sizes */
523:   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);
524:   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);

526:   fA = A->ops->productsetfromoptions;
527:   fB = B->ops->productsetfromoptions;

529:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);
530:   if (fB == fA && sametype) {
531:     f = fB;
532:   } else {
533:     /* query MatProductSetFromOptions_Atype_Btype */
534:     char  mtypes[256];
535:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
536:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
537:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
538:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
539:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));
540:     PetscObjectQueryFunction((PetscObject)B,mtypes,&f);

542:     if (!f) {
543:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
544:     }
545:   }

547:   if (f) {
548:     (*f)(mat);
549:   } else {
550:     mat->ops->productsymbolic = MatProductSymbolic_Basic;
551:   }
552:   return(0);
553: }

555: static PetscErrorCode MatProductSetFromOptions_ABC(Mat mat)
556: {
558:   Mat_Product    *product = mat->product;
559:   Mat            A=product->A,B=product->B,C=product->C;
560:   PetscErrorCode (*fA)(Mat);
561:   PetscErrorCode (*fB)(Mat);
562:   PetscErrorCode (*fC)(Mat);
563:   PetscErrorCode (*f)(Mat)=NULL;

566:   /* Check matrix global sizes */
567:   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);
568:   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);

570:   fA = A->ops->productsetfromoptions;
571:   fB = B->ops->productsetfromoptions;
572:   fC = C->ops->productsetfromoptions;
573:   if (fA == fB && fA == fC && fA) {
574:     f = fA;
575:   } else {
576:     /* query MatProductSetFromOptions_Atype_Btype_Ctype */
577:     char  mtypes[256];
578:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
579:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
580:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
581:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
582:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
583:     PetscStrlcat(mtypes,((PetscObject)C)->type_name,sizeof(mtypes));
584:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));

586:     PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
587:     if (!f) {
588:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
589:     }
590:     if (!f) {
591:       PetscObjectQueryFunction((PetscObject)C,mtypes,&f);
592:     }
593:   }

595:   if (f) {
596:     (*f)(mat);
597:   } else { /* use MatProductSymbolic/Numeric_Basic() */
598:     mat->ops->productsymbolic = MatProductSymbolic_Basic;
599:   }
600:   return(0);
601: }

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

606:    Logically Collective on Mat

608:    Input Parameter:
609: .  mat - the matrix

611:    Level: beginner

613: .seealso: MatSetFromOptions()
614: @*/
615: PetscErrorCode MatProductSetFromOptions(Mat mat)
616: {


622:   if (mat->ops->productsetfromoptions) {
623:     (*mat->ops->productsetfromoptions)(mat);
624:   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_NULL,"Call MatProductSetType() first");
625:   return(0);
626: }

628: /* ----------------------------------------------- */
629: PetscErrorCode MatProductNumeric_AB(Mat mat)
630: {
632:   Mat_Product    *product = mat->product;
633:   Mat            A=product->A,B=product->B;

636:   PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);
637:   (mat->ops->matmultnumeric)(A,B,mat);
638:   PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);
639:   return(0);
640: }

642: PetscErrorCode MatProductNumeric_AtB(Mat mat)
643: {
645:   Mat_Product    *product = mat->product;
646:   Mat            A=product->A,B=product->B;

649:   PetscLogEventBegin(MAT_TransposeMatMultNumeric,A,B,0,0);
650:   (mat->ops->transposematmultnumeric)(A,B,mat);
651:   PetscLogEventEnd(MAT_TransposeMatMultNumeric,A,B,0,0);
652:   return(0);
653: }

655: PetscErrorCode MatProductNumeric_ABt(Mat mat)
656: {
658:   Mat_Product    *product = mat->product;
659:   Mat            A=product->A,B=product->B;

662:   PetscLogEventBegin(MAT_MatTransposeMultNumeric,A,B,0,0);
663:   (mat->ops->mattransposemultnumeric)(A,B,mat);
664:   PetscLogEventEnd(MAT_MatTransposeMultNumeric,A,B,0,0);
665:   return(0);
666: }

668: PetscErrorCode MatProductNumeric_PtAP(Mat mat)
669: {
671:   Mat_Product    *product = mat->product;
672:   Mat            A=product->A,B=product->B;

675:   PetscLogEventBegin(MAT_PtAPNumeric,mat,0,0,0);
676:   (mat->ops->ptapnumeric)(A,B,mat);
677:   PetscLogEventEnd(MAT_PtAPNumeric,mat,0,0,0);
678:   return(0);
679: }

681: PetscErrorCode MatProductNumeric_RARt(Mat mat)
682: {
684:   Mat_Product    *product = mat->product;
685:   Mat            A=product->A,B=product->B;

688:   PetscLogEventBegin(MAT_RARtNumeric,A,B,0,0);
689:   (mat->ops->rartnumeric)(A,B,mat);
690:   PetscLogEventEnd(MAT_RARtNumeric,A,B,0,0);
691:   return(0);
692: }

694: PetscErrorCode MatProductNumeric_ABC(Mat mat)
695: {
697:   Mat_Product    *product = mat->product;
698:   Mat            A=product->A,B=product->B,C=product->C;

701:   PetscLogEventBegin(MAT_MatMatMultNumeric,A,B,C,0);
702:   (mat->ops->matmatmultnumeric)(A,B,C,mat);
703:   PetscLogEventEnd(MAT_MatMatMultNumeric,A,B,C,0);
704:   return(0);
705: }

707: /*@
708:    MatProductNumeric - Implement a matrix product with numerical values.

710:    Collective on Mat

712:    Input Parameters:
713: .  mat - the matrix to hold a product

715:    Output Parameters:
716: .  mat - the matrix product

718:    Level: intermediate

720: .seealso: MatProductCreate(), MatSetType()
721: @*/
722: PetscErrorCode MatProductNumeric(Mat mat)
723: {


730:   if (mat->ops->productnumeric) {
731:     (*mat->ops->productnumeric)(mat);
732:   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_USER,"Call MatProductSymbolic() first");
733:   return(0);
734: }

736: /* ----------------------------------------------- */
737: PetscErrorCode MatProductSymbolic_AB(Mat mat)
738: {
740:   Mat_Product    *product = mat->product;
741:   Mat            A=product->A,B=product->B;

744:   (mat->ops->matmultsymbolic)(A,B,product->fill,mat);
745:   mat->ops->productnumeric = MatProductNumeric_AB;
746:   return(0);
747: }

749: PetscErrorCode MatProductSymbolic_AtB(Mat mat)
750: {
752:   Mat_Product    *product = mat->product;
753:   Mat            A=product->A,B=product->B;

756:   (mat->ops->transposematmultsymbolic)(A,B,product->fill,mat);
757:   mat->ops->productnumeric = MatProductNumeric_AtB;
758:   return(0);
759: }

761: PetscErrorCode MatProductSymbolic_ABt(Mat mat)
762: {
764:   Mat_Product    *product = mat->product;
765:   Mat            A=product->A,B=product->B;

768:   (mat->ops->mattransposemultsymbolic)(A,B,product->fill,mat);
769:   mat->ops->productnumeric = MatProductNumeric_ABt;
770:   return(0);
771: }

773: PetscErrorCode MatProductSymbolic_ABC(Mat mat)
774: {
776:   Mat_Product    *product = mat->product;
777:   Mat            A=product->A,B=product->B,C=product->C;

780:   (mat->ops->matmatmultsymbolic)(A,B,C,product->fill,mat);
781:   mat->ops->productnumeric = MatProductNumeric_ABC;
782:   return(0);
783: }

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

788:    Collective on Mat

790:    Input Parameters:
791: .  mat - the matrix to hold a product

793:    Output Parameters:
794: .  mat - the matrix product data structure

796:    Level: intermediate

798: .seealso: MatProductCreate(), MatSetType(), MatProductNumeric(), MatProductType, MatProductAlgorithm
799: @*/
800: PetscErrorCode MatProductSymbolic(Mat mat)
801: {
803:   Mat_Product    *product = mat->product;
804:   MatProductType productype = product->type;
805:   PetscLogEvent  eventtype=-1;


810:   /* log event */
811:   switch (productype) {
812:   case MATPRODUCT_AB:
813:     eventtype = MAT_MatMultSymbolic;
814:     break;
815:   case MATPRODUCT_AtB:
816:     eventtype = MAT_TransposeMatMultSymbolic;
817:     break;
818:   case MATPRODUCT_ABt:
819:     eventtype = MAT_MatTransposeMultSymbolic;
820:     break;
821:   case MATPRODUCT_PtAP:
822:     eventtype = MAT_PtAPSymbolic;
823:     break;
824:   case MATPRODUCT_RARt:
825:     eventtype = MAT_RARtSymbolic;
826:     break;
827:   case MATPRODUCT_ABC:
828:     eventtype = MAT_MatMatMultSymbolic;
829:     break;
830:   default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"MATPRODUCT type is not supported");
831:   }

833:   if (mat->ops->productsymbolic) {
834:     PetscLogEventBegin(eventtype,mat,0,0,0);
835:     (*mat->ops->productsymbolic)(mat);
836:     PetscLogEventEnd(eventtype,mat,0,0,0);
837:   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_USER,"Call MatProductSetFromOptions() first");
838:   return(0);
839: }

841: /*@
842:    MatProductSetFill - Set an expected fill of the matrix product.

844:    Collective on Mat

846:    Input Parameters:
847: +  mat - the matrix product
848: -  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.

850:    Level: intermediate

852: .seealso: MatProductSetType(), MatProductSetAlgorithm(), MatProductCreate()
853: @*/
854: PetscErrorCode MatProductSetFill(Mat mat,PetscReal fill)
855: {
856:   Mat_Product *product = mat->product;


861:   if (!product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_NULL,"Data struc Mat_Product is not created, call MatProductCreate() first");
862:   if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) {
863:     product->fill = 2.0;
864:   } else product->fill = fill;
865:   return(0);
866: }

868: /*@
869:    MatProductSetAlgorithm - Requests a particular algorithm for a matrix product implementation.

871:    Collective on Mat

873:    Input Parameters:
874: +  mat - the matrix product
875: -  alg - particular implementation algorithm of the matrix product, e.g., MATPRODUCTALGORITHM_DEFAULT.

877:    Level: intermediate

879: .seealso: MatProductSetType(), MatProductSetFill(), MatProductCreate()
880: @*/
881: PetscErrorCode MatProductSetAlgorithm(Mat mat,MatProductAlgorithm alg)
882: {
883:   Mat_Product *product = mat->product;


888:   if (!product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_NULL,"Data struc Mat_Product is not created, call MatProductCreate() first");
889:   product->alg = alg;
890:   return(0);
891: }

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

896:    Collective on Mat

898:    Input Parameters:
899: +  mat - the matrix
900: -  productype   - matrix product type, e.g., MATPRODUCT_AB,MATPRODUCT_AtB,MATPRODUCT_ABt,MATPRODUCT_PtAP,MATPRODUCT_RARt,MATPRODUCT_ABC.

902:    Level: intermediate

904: .seealso: MatProductCreate(), MatProductType, MatProductAlgorithm
905: @*/
906: PetscErrorCode MatProductSetType(Mat mat,MatProductType productype)
907: {
909:   Mat_Product    *product = mat->product;
910:   MPI_Comm       comm;


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

919:   switch (productype) {
920:   case MATPRODUCT_AB:
921:     mat->ops->productsetfromoptions = MatProductSetFromOptions_AB;
922:     break;
923:   case MATPRODUCT_AtB:
924:     mat->ops->productsetfromoptions = MatProductSetFromOptions_AtB;
925:     break;
926:   case MATPRODUCT_ABt:
927:     mat->ops->productsetfromoptions = MatProductSetFromOptions_ABt;
928:     break;
929:   case MATPRODUCT_PtAP:
930:     mat->ops->productsetfromoptions = MatProductSetFromOptions_PtAP;
931:     break;
932:   case MATPRODUCT_RARt:
933:     mat->ops->productsetfromoptions = MatProductSetFromOptions_RARt;
934:     break;
935:   case MATPRODUCT_ABC:
936:     mat->ops->productsetfromoptions = MatProductSetFromOptions_ABC;
937:     break;
938:   default: SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[product->type]);
939:   }
940:   return(0);
941: }

943: /*@
944:    MatProductClear - Clears matrix product internal structure.

946:    Collective on Mat

948:    Input Parameters:
949: .  mat - the product matrix

951:    Level: intermediate
952: @*/
953: PetscErrorCode MatProductClear(Mat mat)
954: {
956:   Mat_Product    *product = mat->product;

959:   if (product) {
960:     /* release reference */
961:     MatDestroy(&product->A);
962:     MatDestroy(&product->B);
963:     MatDestroy(&product->C);
964:     MatDestroy(&product->Dwork);
965:     PetscFree(mat->product);
966:   }
967:   return(0);
968: }

970: /* Create a supporting struct and attach it to the matrix product */
971: PetscErrorCode MatProductCreate_Private(Mat A,Mat B,Mat C,Mat D)
972: {
974:   Mat_Product    *product=NULL;

977:   PetscNewLog(D,&product);
978:   product->A        = A;
979:   product->B        = B;
980:   product->C        = C;
981:   product->Dwork    = NULL;
982:   product->alg      = MATPRODUCTALGORITHM_DEFAULT;
983:   product->fill     = 2.0; /* PETSC_DEFAULT */
984:   product->Areplaced = PETSC_FALSE;
985:   product->Breplaced = PETSC_FALSE;
986:   product->api_user  = PETSC_FALSE;
987:   D->product         = product;

989:   /* take ownership */
990:   PetscObjectReference((PetscObject)A);
991:   PetscObjectReference((PetscObject)B);
992:   PetscObjectReference((PetscObject)C);
993:   return(0);
994: }

996: /*@
997:    MatProductCreateWithMat - Setup a given matrix as a matrix product.

999:    Collective on Mat

1001:    Input Parameters:
1002: +  A - the first matrix
1003: .  B - the second matrix
1004: .  C - the third matrix (optional)
1005: -  D - the matrix which will be used as a product

1007:    Output Parameters:
1008: .  D - the product matrix

1010:    Level: intermediate

1012: .seealso: MatProductCreate()
1013: @*/
1014: PetscErrorCode MatProductCreateWithMat(Mat A,Mat B,Mat C,Mat D)
1015: {

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

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

1031:   if (C) {
1034:     MatCheckPreallocated(C,3);
1035:     if (!C->assembled) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1036:     if (C->factortype) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1037:   }

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

1045:   /* Create a supporting struct and attach it to D */
1046:   MatProductCreate_Private(A,B,C,D);
1047:   return(0);
1048: }

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

1053:    Collective on Mat

1055:    Input Parameters:
1056: +  A - the first matrix
1057: .  B - the second matrix
1058: -  C - the third matrix (optional)

1060:    Output Parameters:
1061: .  D - the product matrix

1063:    Level: intermediate

1065: .seealso: MatProductCreateWithMat(), MatProductSetType(), MatProductSetAlgorithm()
1066: @*/
1067: PetscErrorCode MatProductCreate(Mat A,Mat B,Mat C,Mat *D)
1068: {

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

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

1084:   if (C) {
1087:     MatCheckPreallocated(C,3);
1088:     if (!C->assembled) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1089:     if (C->factortype) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1090:   }


1094:   MatCreate(PetscObjectComm((PetscObject)A),D);
1095:   MatProductCreate_Private(A,B,C,*D);
1096:   return(0);
1097: }