Actual source code: matproduct.c
petsc-3.13.1 2020-05-02
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: }