Actual source code: matproduct.c

petsc-3.13.6 2020-09-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: 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);
264:   PetscInfo2(mat,"for A %s, B %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);

266:   if (fB == fA && sametype && (!A_istrans || !B_istrans)) {
267:     PetscInfo(mat,"  sametype and matching op\n");
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;

274:     if (A_istrans && !B_istrans) {
275:       MatTransposeGetMat(A,&At);
276:       PetscObjectTypeCompare((PetscObject)At,MATTRANSPOSEMAT,&At_istrans);
277:       if (At_istrans) { /* mat = ATT * B */
278:         Mat Att = NULL;
279:         MatTransposeGetMat(At,&Att);
280:         PetscObjectReference((PetscObject)Att);
281:         MatDestroy(&product->A);
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:         PetscObjectReference((PetscObject)At);
287:         MatDestroy(&product->A);
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:       MatTransposeGetMat(B,&Bt);
295:       PetscObjectTypeCompare((PetscObject)Bt,MATTRANSPOSEMAT,&Bt_istrans);
296:       if (Bt_istrans) { /* mat = A * BTT */
297:         Mat Btt = NULL;
298:         MatTransposeGetMat(Bt,&Btt);
299:         PetscObjectReference((PetscObject)Btt);
300:         MatDestroy(&product->B);
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:         PetscObjectReference((PetscObject)Bt);
307:         MatDestroy(&product->B);
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:       MatTransposeGetMat(A,&At);
315:       PetscObjectTypeCompare((PetscObject)At,MATTRANSPOSEMAT,&At_istrans);
316:       MatTransposeGetMat(B,&Bt);
317:       PetscObjectTypeCompare((PetscObject)Bt,MATTRANSPOSEMAT,&Bt_istrans);
318:       if (At_istrans && Bt_istrans) {
319:         Mat Att= NULL,Btt = NULL;
320:         MatTransposeGetMat(At,&Att);
321:         MatTransposeGetMat(Bt,&Btt);
322:         PetscObjectReference((PetscObject)Att);
323:         PetscObjectReference((PetscObject)Btt);
324:         MatDestroy(&product->A);
325:         MatDestroy(&product->B);
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:     }

333:     /* query MatProductSetFromOptions_Atype_Btype */
334:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
335:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
336:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
337:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
338:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));
339:     PetscInfo1(mat,"  querying %s\n",f);
340:     PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
341:     if (!f) {
342:       PetscInfo1(mat,"  querying %s\n",f);
343:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
344:     }
345:   }

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:   (*f)(mat);
349:   return(0);
350: }

352: static PetscErrorCode MatProductSetFromOptions_AtB(Mat mat)
353: {
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;

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

366:   fA = A->ops->productsetfromoptions;
367:   fB = B->ops->productsetfromoptions;

369:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);
370:   PetscInfo2(mat,"for A %s, B %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);

372:   if (fB == fA && sametype) {
373:     PetscInfo(mat,"  sametype and matching op\n");
374:     f = fB;
375:   } else {
376:     char      mtypes[256];
377:     PetscBool istrans;
378:     PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&istrans);
379:     if (!istrans) {
380:       /* query MatProductSetFromOptions_Atype_Btype */
381:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
382:       PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
383:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
384:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
385:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));
386:       PetscInfo1(mat,"  querying %s\n",f);
387:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
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);

392:       MatTransposeGetMat(A,&T);
393:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
394:       PetscStrlcat(mtypes,((PetscObject)T)->type_name,sizeof(mtypes));
395:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
396:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
397:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));

399:       product->type = MATPRODUCT_AtB;
400:       PetscInfo1(mat,"  querying %s\n",f);
401:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
402:     }

404:     if (!f) {
405:       PetscInfo1(mat,"  querying %s\n",f);
406:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
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);

411:   (*f)(mat);
412:   return(0);
413: }

415: static PetscErrorCode MatProductSetFromOptions_ABt(Mat mat)
416: {
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;

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

429:   fA = A->ops->productsetfromoptions;
430:   fB = B->ops->productsetfromoptions;

432:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);
433:   PetscInfo2(mat,"for A %s, B %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
434:   if (fB == fA && sametype) {
435:     PetscInfo(mat,"  sametype and matching op\n");
436:     f = fB;
437:   } else {
438:     char      mtypes[256];
439:     PetscBool istrans;
440:     PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&istrans);
441:     if (!istrans) {
442:       /* query MatProductSetFromOptions_Atype_Btype */
443:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
444:       PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
445:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
446:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
447:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));
448:       PetscInfo1(mat,"  querying %s\n",f);
449:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
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);

454:       MatTransposeGetMat(A,&T);
455:       PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
456:       PetscStrlcat(mtypes,((PetscObject)T)->type_name,sizeof(mtypes));
457:       PetscStrlcat(mtypes,"_",sizeof(mtypes));
458:       PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
459:       PetscStrlcat(mtypes,"_C",sizeof(mtypes));

461:       product->type = MATPRODUCT_ABt;
462:       PetscInfo1(mat,"  querying %s (ABt)\n",f);
463:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
464:     }

466:     if (!f) {
467:       PetscInfo1(mat,"  querying %s\n",f);
468:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
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:   }

475:   (*f)(mat);
476:   return(0);
477: }

479: static PetscErrorCode MatProductSetFromOptions_PtAP(Mat mat)
480: {
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;

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

494:   fA = A->ops->productsetfromoptions;
495:   fB = B->ops->productsetfromoptions;

497:   PetscInfo2(mat,"for A %s, P %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
498:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);
499:   if (fB == fA && sametype) {
500:     PetscInfo(mat,"  sametype and matching op\n");
501:     f = fB;
502:   } else {
503:     /* query MatProductSetFromOptions_Atype_Btype */
504:     char  mtypes[256];
505:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
506:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
507:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
508:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
509:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));
510:     PetscInfo1(mat,"  querying %s\n",f);
511:     PetscObjectQueryFunction((PetscObject)B,mtypes,&f);

513:     if (!f) {
514:       PetscInfo1(mat,"  querying %s\n",f);
515:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
516:     }
517:   }

519:   if (f) {
520:     (*f)(mat);
521:   } else {
522:     mat->ops->productsymbolic = MatProductSymbolic_Basic;
523:     PetscInfo2(mat,"  for A %s, P %s uses MatProduct_Basic() implementation",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
524:   }
525:   return(0);
526: }

528: static PetscErrorCode MatProductSetFromOptions_RARt(Mat mat)
529: {
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;

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

543:   fA = A->ops->productsetfromoptions;
544:   fB = B->ops->productsetfromoptions;

546:   PetscStrcmp(((PetscObject)A)->type_name,((PetscObject)B)->type_name,&sametype);
547:   PetscInfo2(mat,"for A %s, B %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
548:   if (fB == fA && sametype) {
549:     PetscInfo(mat,"  sametype and matching op\n");
550:     f = fB;
551:   } else {
552:     /* query MatProductSetFromOptions_Atype_Btype */
553:     char  mtypes[256];
554:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
555:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
556:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
557:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
558:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));
559:     PetscInfo1(mat,"  querying %s\n",f);
560:     PetscObjectQueryFunction((PetscObject)B,mtypes,&f);

562:     if (!f) {
563:       PetscInfo1(mat,"  querying %s\n",f);
564:       PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
565:     }
566:   }

568:   if (f) {
569:     (*f)(mat);
570:   } else {
571:     PetscInfo2(mat,"  for A %s, P %s uses MatProduct_Basic() implementation",((PetscObject)A)->type_name,((PetscObject)B)->type_name);
572:     mat->ops->productsymbolic = MatProductSymbolic_Basic;
573:   }
574:   return(0);
575: }

577: static PetscErrorCode MatProductSetFromOptions_ABC(Mat mat)
578: {
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;

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

592:   fA = A->ops->productsetfromoptions;
593:   fB = B->ops->productsetfromoptions;
594:   fC = C->ops->productsetfromoptions;
595:   PetscInfo3(mat,"for A %s, B %s and C %s\n",((PetscObject)A)->type_name,((PetscObject)B)->type_name,((PetscObject)C)->type_name);
596:   if (fA == fB && fA == fC && fA) {
597:     PetscInfo(mat,"  matching op\n");
598:     f = fA;
599:   } else {
600:     /* query MatProductSetFromOptions_Atype_Btype_Ctype */
601:     char  mtypes[256];
602:     PetscStrncpy(mtypes,"MatProductSetFromOptions_",sizeof(mtypes));
603:     PetscStrlcat(mtypes,((PetscObject)A)->type_name,sizeof(mtypes));
604:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
605:     PetscStrlcat(mtypes,((PetscObject)B)->type_name,sizeof(mtypes));
606:     PetscStrlcat(mtypes,"_",sizeof(mtypes));
607:     PetscStrlcat(mtypes,((PetscObject)C)->type_name,sizeof(mtypes));
608:     PetscStrlcat(mtypes,"_C",sizeof(mtypes));

610:     PetscInfo1(mat,"  querying %s\n",f);
611:     PetscObjectQueryFunction((PetscObject)A,mtypes,&f);
612:     if (!f) {
613:       PetscInfo1(mat,"  querying %s\n",f);
614:       PetscObjectQueryFunction((PetscObject)B,mtypes,&f);
615:     }
616:     if (!f) {
617:       PetscInfo1(mat,"  querying %s\n",f);
618:       PetscObjectQueryFunction((PetscObject)C,mtypes,&f);
619:     }
620:   }

622:   if (f) {
623:     (*f)(mat);
624:   } else { /* use MatProductSymbolic/Numeric_Basic() */
625:     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);
626:     mat->ops->productsymbolic = MatProductSymbolic_Basic;
627:   }
628:   return(0);
629: }

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

634:    Logically Collective on Mat

636:    Input Parameter:
637: .  mat - the matrix

639:    Level: beginner

641: .seealso: MatSetFromOptions()
642: @*/
643: PetscErrorCode MatProductSetFromOptions(Mat mat)
644: {


650:   if (mat->ops->productsetfromoptions) {
651:     (*mat->ops->productsetfromoptions)(mat);
652:   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_NULL,"Call MatProductSetType() first");
653:   return(0);
654: }

656: /* ----------------------------------------------- */
657: PetscErrorCode MatProductNumeric_AB(Mat mat)
658: {
660:   Mat_Product    *product = mat->product;
661:   Mat            A=product->A,B=product->B;

664:   PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);
665:   (mat->ops->matmultnumeric)(A,B,mat);
666:   PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);
667:   return(0);
668: }

670: PetscErrorCode MatProductNumeric_AtB(Mat mat)
671: {
673:   Mat_Product    *product = mat->product;
674:   Mat            A=product->A,B=product->B;

677:   PetscLogEventBegin(MAT_TransposeMatMultNumeric,A,B,0,0);
678:   (mat->ops->transposematmultnumeric)(A,B,mat);
679:   PetscLogEventEnd(MAT_TransposeMatMultNumeric,A,B,0,0);
680:   return(0);
681: }

683: PetscErrorCode MatProductNumeric_ABt(Mat mat)
684: {
686:   Mat_Product    *product = mat->product;
687:   Mat            A=product->A,B=product->B;

690:   PetscLogEventBegin(MAT_MatTransposeMultNumeric,A,B,0,0);
691:   (mat->ops->mattransposemultnumeric)(A,B,mat);
692:   PetscLogEventEnd(MAT_MatTransposeMultNumeric,A,B,0,0);
693:   return(0);
694: }

696: PetscErrorCode MatProductNumeric_PtAP(Mat mat)
697: {
699:   Mat_Product    *product = mat->product;
700:   Mat            A=product->A,B=product->B;

703:   PetscLogEventBegin(MAT_PtAPNumeric,mat,0,0,0);
704:   (mat->ops->ptapnumeric)(A,B,mat);
705:   PetscLogEventEnd(MAT_PtAPNumeric,mat,0,0,0);
706:   return(0);
707: }

709: PetscErrorCode MatProductNumeric_RARt(Mat mat)
710: {
712:   Mat_Product    *product = mat->product;
713:   Mat            A=product->A,B=product->B;

716:   PetscLogEventBegin(MAT_RARtNumeric,A,B,0,0);
717:   (mat->ops->rartnumeric)(A,B,mat);
718:   PetscLogEventEnd(MAT_RARtNumeric,A,B,0,0);
719:   return(0);
720: }

722: PetscErrorCode MatProductNumeric_ABC(Mat mat)
723: {
725:   Mat_Product    *product = mat->product;
726:   Mat            A=product->A,B=product->B,C=product->C;

729:   PetscLogEventBegin(MAT_MatMatMultNumeric,A,B,C,0);
730:   (mat->ops->matmatmultnumeric)(A,B,C,mat);
731:   PetscLogEventEnd(MAT_MatMatMultNumeric,A,B,C,0);
732:   return(0);
733: }

735: /*@
736:    MatProductNumeric - Implement a matrix product with numerical values.

738:    Collective on Mat

740:    Input Parameters:
741: .  mat - the matrix to hold a product

743:    Output Parameters:
744: .  mat - the matrix product

746:    Level: intermediate

748: .seealso: MatProductCreate(), MatSetType()
749: @*/
750: PetscErrorCode MatProductNumeric(Mat mat)
751: {


758:   if (mat->ops->productnumeric) {
759:     (*mat->ops->productnumeric)(mat);
760:   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_USER,"Call MatProductSymbolic() first");
761:   return(0);
762: }

764: /* ----------------------------------------------- */
765: PetscErrorCode MatProductSymbolic_AB(Mat mat)
766: {
768:   Mat_Product    *product = mat->product;
769:   Mat            A=product->A,B=product->B;

772:   (mat->ops->matmultsymbolic)(A,B,product->fill,mat);
773:   mat->ops->productnumeric = MatProductNumeric_AB;
774:   return(0);
775: }

777: PetscErrorCode MatProductSymbolic_AtB(Mat mat)
778: {
780:   Mat_Product    *product = mat->product;
781:   Mat            A=product->A,B=product->B;

784:   (mat->ops->transposematmultsymbolic)(A,B,product->fill,mat);
785:   mat->ops->productnumeric = MatProductNumeric_AtB;
786:   return(0);
787: }

789: PetscErrorCode MatProductSymbolic_ABt(Mat mat)
790: {
792:   Mat_Product    *product = mat->product;
793:   Mat            A=product->A,B=product->B;

796:   (mat->ops->mattransposemultsymbolic)(A,B,product->fill,mat);
797:   mat->ops->productnumeric = MatProductNumeric_ABt;
798:   return(0);
799: }

801: PetscErrorCode MatProductSymbolic_ABC(Mat mat)
802: {
804:   Mat_Product    *product = mat->product;
805:   Mat            A=product->A,B=product->B,C=product->C;

808:   (mat->ops->matmatmultsymbolic)(A,B,C,product->fill,mat);
809:   mat->ops->productnumeric = MatProductNumeric_ABC;
810:   return(0);
811: }

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

816:    Collective on Mat

818:    Input Parameters:
819: .  mat - the matrix to hold a product

821:    Output Parameters:
822: .  mat - the matrix product data structure

824:    Level: intermediate

826: .seealso: MatProductCreate(), MatSetType(), MatProductNumeric(), MatProductType, MatProductAlgorithm
827: @*/
828: PetscErrorCode MatProductSymbolic(Mat mat)
829: {
831:   Mat_Product    *product = mat->product;
832:   MatProductType productype = product->type;
833:   PetscLogEvent  eventtype=-1;


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:   }

861:   if (mat->ops->productsymbolic) {
862:     PetscLogEventBegin(eventtype,mat,0,0,0);
863:     (*mat->ops->productsymbolic)(mat);
864:     PetscLogEventEnd(eventtype,mat,0,0,0);
865:   } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_USER,"Call MatProductSetFromOptions() first");
866:   return(0);
867: }

869: /*@
870:    MatProductSetFill - Set an expected fill of the matrix product.

872:    Collective on Mat

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.

878:    Level: intermediate

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


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

896: /*@
897:    MatProductSetAlgorithm - Requests a particular algorithm for a matrix product implementation.

899:    Collective on Mat

901:    Input Parameters:
902: +  mat - the matrix product
903: -  alg - particular implementation algorithm of the matrix product, e.g., MATPRODUCTALGORITHM_DEFAULT.

905:    Level: intermediate

907: .seealso: MatProductSetType(), MatProductSetFill(), MatProductCreate()
908: @*/
909: PetscErrorCode MatProductSetAlgorithm(Mat mat,MatProductAlgorithm alg)
910: {
911:   Mat_Product *product = mat->product;


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

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

924:    Collective on Mat

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.

930:    Level: intermediate

932: .seealso: MatProductCreate(), MatProductType, MatProductAlgorithm
933: @*/
934: PetscErrorCode MatProductSetType(Mat mat,MatProductType productype)
935: {
937:   Mat_Product    *product = mat->product;
938:   MPI_Comm       comm;


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

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

971: /*@
972:    MatProductClear - Clears matrix product internal structure.

974:    Collective on Mat

976:    Input Parameters:
977: .  mat - the product matrix

979:    Level: intermediate
980: @*/
981: PetscErrorCode MatProductClear(Mat mat)
982: {
984:   Mat_Product    *product = mat->product;

987:   if (product) {
988:     /* release reference */
989:     MatDestroy(&product->A);
990:     MatDestroy(&product->B);
991:     MatDestroy(&product->C);
992:     MatDestroy(&product->Dwork);
993:     PetscFree(mat->product);
994:   }
995:   return(0);
996: }

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: {
1002:   Mat_Product    *product=NULL;

1005:   PetscNewLog(D,&product);
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;

1017:   /* take ownership */
1018:   PetscObjectReference((PetscObject)A);
1019:   PetscObjectReference((PetscObject)B);
1020:   PetscObjectReference((PetscObject)C);
1021:   return(0);
1022: }

1024: /*@
1025:    MatProductCreateWithMat - Setup a given matrix as a matrix product.

1027:    Collective on Mat

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

1035:    Output Parameters:
1036: .  D - the product matrix

1038:    Level: intermediate

1040: .seealso: MatProductCreate()
1041: @*/
1042: PetscErrorCode MatProductCreateWithMat(Mat A,Mat B,Mat C,Mat D)
1043: {

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

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

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

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

1073:   /* Create a supporting struct and attach it to D */
1074:   MatProductCreate_Private(A,B,C,D);
1075:   return(0);
1076: }

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

1081:    Collective on Mat

1083:    Input Parameters:
1084: +  A - the first matrix
1085: .  B - the second matrix
1086: -  C - the third matrix (optional)

1088:    Output Parameters:
1089: .  D - the product matrix

1091:    Level: intermediate

1093: .seealso: MatProductCreateWithMat(), MatProductSetType(), MatProductSetAlgorithm()
1094: @*/
1095: PetscErrorCode MatProductCreate(Mat A,Mat B,Mat C,Mat *D)
1096: {

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

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

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


1122:   MatCreate(PetscObjectComm((PetscObject)A),D);
1123:   MatProductCreate_Private(A,B,C,*D);
1124:   return(0);
1125: }