Actual source code: matproduct.c
1: /*
2: Routines for matrix products. Calling procedure:
4: MatProductCreate(A,B,C,&D); or MatProductCreateWithMat(A,B,C,D)
5: MatProductSetType(D, MATPRODUCT_AB/AtB/ABt/PtAP/RARt/ABC)
6: MatProductSetAlgorithm(D, alg)
7: MatProductSetFill(D,fill)
8: MatProductSetFromOptions(D)
9: -> MatProductSetFromOptions_Private(D)
10: # Check matrix global sizes
11: if the matrices have the same setfromoptions routine, use it
12: if not, try:
13: -> Query MatProductSetFromOptions_Atype_Btype_Ctype_C(D) from A, B and C (in order)
14: if found -> run the specific setup that must set the symbolic operation (these callbacks should never fail)
15: if callback not found or no symbolic operation set
16: -> Query MatProductSetFromOptions_anytype_C(D) from A, B and C (in order) (e.g, matrices may have inner matrices like MATTRANSPOSEVIRTUAL)
17: if dispatch found but combination still not present do
18: -> check if B is dense and product type AtB or AB -> if true, basic looping of dense columns
19: -> check if triple product (PtAP, RARt or ABC) -> if true, set the Basic routines
21: # The setfromoptions calls MatProductSetFromOptions_Atype_Btype_Ctype should
22: # Check matrix local sizes for mpi matrices
23: # Set default algorithm
24: # Get runtime option
25: # Set D->ops->productsymbolic = MatProductSymbolic_productype_Atype_Btype_Ctype if found
27: MatProductSymbolic(D)
28: # Call MatProductSymbolic_productype_Atype_Btype_Ctype()
29: the callback must set the numeric phase D->ops->productnumeric = MatProductNumeric_productype_Atype_Btype_Ctype
31: MatProductNumeric(D)
32: # Call the numeric phase
34: # The symbolic phases are allowed to set extra data structures and attach those to the product
35: # this additional data can be reused between multiple numeric phases with the same matrices
36: # if not needed, call
37: MatProductClear(D)
38: */
40: #include <petsc/private/matimpl.h>
42: const char *const MatProductTypes[] = {"UNSPECIFIED", "AB", "AtB", "ABt", "PtAP", "RARt", "ABC"};
44: /* these are basic implementations relying on the old function pointers
45: * they are dangerous and should be removed in the future */
46: static PetscErrorCode MatProductNumeric_PtAP_Unsafe(Mat C)
47: {
48: Mat_Product *product = C->product;
49: Mat P = product->B, AP = product->Dwork;
51: PetscFunctionBegin;
52: /* AP = A*P */
53: PetscCall(MatProductNumeric(AP));
54: /* C = P^T*AP */
55: PetscCall((*C->ops->transposematmultnumeric)(P, AP, C));
56: PetscFunctionReturn(PETSC_SUCCESS);
57: }
59: static PetscErrorCode MatProductSymbolic_PtAP_Unsafe(Mat C)
60: {
61: Mat_Product *product = C->product;
62: Mat A = product->A, P = product->B, AP;
63: PetscReal fill = product->fill;
65: PetscFunctionBegin;
66: PetscCall(PetscInfo((PetscObject)C, "for A %s, P %s is used\n", ((PetscObject)product->A)->type_name, ((PetscObject)product->B)->type_name));
67: /* AP = A*P */
68: PetscCall(MatProductCreate(A, P, NULL, &AP));
69: PetscCall(MatProductSetType(AP, MATPRODUCT_AB));
70: PetscCall(MatProductSetAlgorithm(AP, MATPRODUCTALGORITHMDEFAULT));
71: PetscCall(MatProductSetFill(AP, fill));
72: PetscCall(MatProductSetFromOptions(AP));
73: PetscCall(MatProductSymbolic(AP));
75: /* C = P^T*AP */
76: PetscCall(MatProductSetType(C, MATPRODUCT_AtB));
77: PetscCall(MatProductSetAlgorithm(C, MATPRODUCTALGORITHMDEFAULT));
78: product->A = P;
79: product->B = AP;
80: PetscCall(MatProductSetFromOptions(C));
81: PetscCall(MatProductSymbolic(C));
83: /* resume user's original input matrix setting for A and B */
84: product->A = A;
85: product->B = P;
86: product->Dwork = AP;
88: C->ops->productnumeric = MatProductNumeric_PtAP_Unsafe;
89: PetscFunctionReturn(PETSC_SUCCESS);
90: }
92: static PetscErrorCode MatProductNumeric_RARt_Unsafe(Mat C)
93: {
94: Mat_Product *product = C->product;
95: Mat R = product->B, RA = product->Dwork;
97: PetscFunctionBegin;
98: /* RA = R*A */
99: PetscCall(MatProductNumeric(RA));
100: /* C = RA*R^T */
101: PetscCall((*C->ops->mattransposemultnumeric)(RA, R, C));
102: PetscFunctionReturn(PETSC_SUCCESS);
103: }
105: static PetscErrorCode MatProductSymbolic_RARt_Unsafe(Mat C)
106: {
107: Mat_Product *product = C->product;
108: Mat A = product->A, R = product->B, RA;
109: PetscReal fill = product->fill;
111: PetscFunctionBegin;
112: PetscCall(PetscInfo((PetscObject)C, "for A %s, R %s is used\n", ((PetscObject)product->A)->type_name, ((PetscObject)product->B)->type_name));
113: /* RA = R*A */
114: PetscCall(MatProductCreate(R, A, NULL, &RA));
115: PetscCall(MatProductSetType(RA, MATPRODUCT_AB));
116: PetscCall(MatProductSetAlgorithm(RA, MATPRODUCTALGORITHMDEFAULT));
117: PetscCall(MatProductSetFill(RA, fill));
118: PetscCall(MatProductSetFromOptions(RA));
119: PetscCall(MatProductSymbolic(RA));
121: /* C = RA*R^T */
122: PetscCall(MatProductSetType(C, MATPRODUCT_ABt));
123: PetscCall(MatProductSetAlgorithm(C, MATPRODUCTALGORITHMDEFAULT));
124: product->A = RA;
125: PetscCall(MatProductSetFromOptions(C));
126: PetscCall(MatProductSymbolic(C));
128: /* resume user's original input matrix setting for A */
129: product->A = A;
130: product->Dwork = RA; /* save here so it will be destroyed with product C */
131: C->ops->productnumeric = MatProductNumeric_RARt_Unsafe;
132: PetscFunctionReturn(PETSC_SUCCESS);
133: }
135: static PetscErrorCode MatProductNumeric_ABC_Unsafe(Mat mat)
136: {
137: Mat_Product *product = mat->product;
138: Mat A = product->A, BC = product->Dwork;
140: PetscFunctionBegin;
141: /* Numeric BC = B*C */
142: PetscCall(MatProductNumeric(BC));
143: /* Numeric mat = A*BC */
144: PetscCall((*mat->ops->matmultnumeric)(A, BC, mat));
145: PetscFunctionReturn(PETSC_SUCCESS);
146: }
148: static PetscErrorCode MatProductSymbolic_ABC_Unsafe(Mat mat)
149: {
150: Mat_Product *product = mat->product;
151: Mat B = product->B, C = product->C, BC;
152: PetscReal fill = product->fill;
154: PetscFunctionBegin;
155: PetscCall(PetscInfo((PetscObject)mat, "for A %s, B %s, C %s is used\n", ((PetscObject)product->A)->type_name, ((PetscObject)product->B)->type_name, ((PetscObject)product->C)->type_name));
156: /* Symbolic BC = B*C */
157: PetscCall(MatProductCreate(B, C, NULL, &BC));
158: PetscCall(MatProductSetType(BC, MATPRODUCT_AB));
159: PetscCall(MatProductSetAlgorithm(BC, MATPRODUCTALGORITHMDEFAULT));
160: PetscCall(MatProductSetFill(BC, fill));
161: PetscCall(MatProductSetFromOptions(BC));
162: PetscCall(MatProductSymbolic(BC));
164: /* Symbolic mat = A*BC */
165: PetscCall(MatProductSetType(mat, MATPRODUCT_AB));
166: PetscCall(MatProductSetAlgorithm(mat, MATPRODUCTALGORITHMDEFAULT));
167: product->B = BC;
168: product->Dwork = BC;
169: PetscCall(MatProductSetFromOptions(mat));
170: PetscCall(MatProductSymbolic(mat));
172: /* resume user's original input matrix setting for B */
173: product->B = B;
174: mat->ops->productnumeric = MatProductNumeric_ABC_Unsafe;
175: PetscFunctionReturn(PETSC_SUCCESS);
176: }
178: static PetscErrorCode MatProductSymbolic_Unsafe(Mat mat)
179: {
180: Mat_Product *product = mat->product;
182: PetscFunctionBegin;
183: switch (product->type) {
184: case MATPRODUCT_PtAP:
185: PetscCall(MatProductSymbolic_PtAP_Unsafe(mat));
186: break;
187: case MATPRODUCT_RARt:
188: PetscCall(MatProductSymbolic_RARt_Unsafe(mat));
189: break;
190: case MATPRODUCT_ABC:
191: PetscCall(MatProductSymbolic_ABC_Unsafe(mat));
192: break;
193: default:
194: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[product->type]);
195: }
196: PetscFunctionReturn(PETSC_SUCCESS);
197: }
199: /*@
200: MatProductReplaceMats - Replace the input matrices for the matrix-matrix product operation inside the computed matrix
202: Collective
204: Input Parameters:
205: + A - the matrix or `NULL` if not being replaced
206: . B - the matrix or `NULL` if not being replaced
207: . C - the matrix or `NULL` if not being replaced
208: - D - the matrix whose values are computed via a matrix-matrix product operation
210: Level: intermediate
212: Note:
213: To reuse the symbolic phase, the input matrices must have exactly the same data structure as the replaced one.
214: If the type of any of the input matrices is different than what was previously used, or their symmetry flag changed but
215: the symbolic phase took advantage of their symmetry, the product is cleared and `MatProductSetFromOptions()`
216: and `MatProductSymbolic()` are invoked again.
218: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()`, `MatProductSetFromOptions()`, `MatProductSymbolic()`, `MatProductClear()`
219: @*/
220: PetscErrorCode MatProductReplaceMats(Mat A, Mat B, Mat C, Mat D)
221: {
222: Mat_Product *product;
223: PetscBool flgA = PETSC_TRUE, flgB = PETSC_TRUE, flgC = PETSC_TRUE, isset, issym;
225: PetscFunctionBegin;
227: MatCheckProduct(D, 4);
228: product = D->product;
229: if (A) {
231: PetscCall(PetscObjectReference((PetscObject)A));
232: PetscCall(PetscObjectTypeCompare((PetscObject)product->A, ((PetscObject)A)->type_name, &flgA));
233: PetscCall(MatIsSymmetricKnown(A, &isset, &issym));
234: if (product->symbolic_used_the_fact_A_is_symmetric && isset && !issym) { /* symbolic was built around a symmetric A, but the new A is not anymore */
235: flgA = PETSC_FALSE;
236: product->symbolic_used_the_fact_A_is_symmetric = PETSC_FALSE; /* reinit */
237: }
238: PetscCall(MatDestroy(&product->A));
239: product->A = A;
240: }
241: if (B) {
243: PetscCall(PetscObjectReference((PetscObject)B));
244: PetscCall(PetscObjectTypeCompare((PetscObject)product->B, ((PetscObject)B)->type_name, &flgB));
245: PetscCall(MatIsSymmetricKnown(B, &isset, &issym));
246: if (product->symbolic_used_the_fact_B_is_symmetric && isset && !issym) {
247: flgB = PETSC_FALSE;
248: product->symbolic_used_the_fact_B_is_symmetric = PETSC_FALSE; /* reinit */
249: }
250: PetscCall(MatDestroy(&product->B));
251: product->B = B;
252: }
253: if (C) {
255: PetscCall(PetscObjectReference((PetscObject)C));
256: PetscCall(PetscObjectTypeCompare((PetscObject)product->C, ((PetscObject)C)->type_name, &flgC));
257: PetscCall(MatIsSymmetricKnown(C, &isset, &issym));
258: if (product->symbolic_used_the_fact_C_is_symmetric && isset && !issym) {
259: flgC = PETSC_FALSE;
260: product->symbolic_used_the_fact_C_is_symmetric = PETSC_FALSE; /* reinit */
261: }
262: PetscCall(MatDestroy(&product->C));
263: product->C = C;
264: }
265: /* Any of the replaced mats is of a different type, reset */
266: if (!flgA || !flgB || !flgC) {
267: if (D->product->destroy) PetscCall((*D->product->destroy)(D->product->data));
268: D->product->destroy = NULL;
269: D->product->data = NULL;
270: if (D->ops->productnumeric || D->ops->productsymbolic) {
271: PetscCall(MatProductSetFromOptions(D));
272: PetscCall(MatProductSymbolic(D));
273: }
274: }
275: PetscFunctionReturn(PETSC_SUCCESS);
276: }
278: static PetscErrorCode MatProductNumeric_X_Dense(Mat C)
279: {
280: Mat_Product *product = C->product;
281: Mat A = product->A, B = product->B;
282: PetscInt k, K = B->cmap->N;
283: PetscBool t = PETSC_TRUE, iscuda = PETSC_FALSE;
284: PetscBool Bcpu = PETSC_TRUE, Ccpu = PETSC_TRUE;
285: char *Btype = NULL, *Ctype = NULL;
287: PetscFunctionBegin;
288: switch (product->type) {
289: case MATPRODUCT_AB:
290: t = PETSC_FALSE;
291: case MATPRODUCT_AtB:
292: break;
293: default:
294: SETERRQ(PetscObjectComm((PetscObject)C), PETSC_ERR_SUP, "MatProductNumeric type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name);
295: }
296: if (PetscDefined(HAVE_CUDA)) {
297: VecType vtype;
299: PetscCall(MatGetVecType(A, &vtype));
300: PetscCall(PetscStrcmp(vtype, VECCUDA, &iscuda));
301: if (!iscuda) PetscCall(PetscStrcmp(vtype, VECSEQCUDA, &iscuda));
302: if (!iscuda) PetscCall(PetscStrcmp(vtype, VECMPICUDA, &iscuda));
303: if (iscuda) { /* Make sure we have up-to-date data on the GPU */
304: PetscCall(PetscStrallocpy(((PetscObject)B)->type_name, &Btype));
305: PetscCall(PetscStrallocpy(((PetscObject)C)->type_name, &Ctype));
306: PetscCall(MatConvert(B, MATDENSECUDA, MAT_INPLACE_MATRIX, &B));
307: if (!C->assembled) { /* need to flag the matrix as assembled, otherwise MatConvert will complain */
308: PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
309: PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
310: }
311: PetscCall(MatConvert(C, MATDENSECUDA, MAT_INPLACE_MATRIX, &C));
312: } else { /* Make sure we have up-to-date data on the CPU */
313: #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_VIENNACL)
314: Bcpu = B->boundtocpu;
315: Ccpu = C->boundtocpu;
316: #endif
317: PetscCall(MatBindToCPU(B, PETSC_TRUE));
318: PetscCall(MatBindToCPU(C, PETSC_TRUE));
319: }
320: }
321: for (k = 0; k < K; k++) {
322: Vec x, y;
324: PetscCall(MatDenseGetColumnVecRead(B, k, &x));
325: PetscCall(MatDenseGetColumnVecWrite(C, k, &y));
326: if (t) {
327: PetscCall(MatMultTranspose(A, x, y));
328: } else {
329: PetscCall(MatMult(A, x, y));
330: }
331: PetscCall(MatDenseRestoreColumnVecRead(B, k, &x));
332: PetscCall(MatDenseRestoreColumnVecWrite(C, k, &y));
333: }
334: PetscCall(MatSetOption(C, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
335: PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
336: PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
337: if (PetscDefined(HAVE_CUDA)) {
338: if (iscuda) {
339: PetscCall(MatConvert(B, Btype, MAT_INPLACE_MATRIX, &B));
340: PetscCall(MatConvert(C, Ctype, MAT_INPLACE_MATRIX, &C));
341: } else {
342: PetscCall(MatBindToCPU(B, Bcpu));
343: PetscCall(MatBindToCPU(C, Ccpu));
344: }
345: }
346: PetscCall(PetscFree(Btype));
347: PetscCall(PetscFree(Ctype));
348: PetscFunctionReturn(PETSC_SUCCESS);
349: }
351: static PetscErrorCode MatProductSymbolic_X_Dense(Mat C)
352: {
353: Mat_Product *product = C->product;
354: Mat A = product->A, B = product->B;
355: PetscBool isdense;
357: PetscFunctionBegin;
358: switch (product->type) {
359: case MATPRODUCT_AB:
360: PetscCall(MatSetSizes(C, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N));
361: break;
362: case MATPRODUCT_AtB:
363: PetscCall(MatSetSizes(C, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N));
364: break;
365: default:
366: SETERRQ(PetscObjectComm((PetscObject)C), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name);
367: }
368: PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)C, &isdense, MATSEQDENSE, MATMPIDENSE, ""));
369: if (!isdense) {
370: PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
371: /* If matrix type of C was not set or not dense, we need to reset the pointer */
372: C->ops->productsymbolic = MatProductSymbolic_X_Dense;
373: }
374: C->ops->productnumeric = MatProductNumeric_X_Dense;
375: PetscCall(MatSetUp(C));
376: PetscFunctionReturn(PETSC_SUCCESS);
377: }
379: /* a single driver to query the dispatching */
380: static PetscErrorCode MatProductSetFromOptions_Private(Mat mat)
381: {
382: Mat_Product *product = mat->product;
383: PetscInt Am, An, Bm, Bn, Cm, Cn;
384: Mat A = product->A, B = product->B, C = product->C;
385: const char *const Bnames[] = {"B", "R", "P"};
386: const char *bname;
387: PetscErrorCode (*fA)(Mat);
388: PetscErrorCode (*fB)(Mat);
389: PetscErrorCode (*fC)(Mat);
390: PetscErrorCode (*f)(Mat) = NULL;
392: PetscFunctionBegin;
393: mat->ops->productsymbolic = NULL;
394: mat->ops->productnumeric = NULL;
395: if (product->type == MATPRODUCT_UNSPECIFIED) PetscFunctionReturn(PETSC_SUCCESS);
396: PetscCheck(A, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing A mat");
397: PetscCheck(B, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing B mat");
398: PetscCheck(product->type != MATPRODUCT_ABC || C, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing C mat");
399: if (product->type != MATPRODUCT_ABC) C = NULL; /* do not use C if not needed */
400: if (product->type == MATPRODUCT_RARt) bname = Bnames[1];
401: else if (product->type == MATPRODUCT_PtAP) bname = Bnames[2];
402: else bname = Bnames[0];
404: /* Check matrices sizes */
405: Am = A->rmap->N;
406: An = A->cmap->N;
407: Bm = B->rmap->N;
408: Bn = B->cmap->N;
409: Cm = C ? C->rmap->N : 0;
410: Cn = C ? C->cmap->N : 0;
411: if (product->type == MATPRODUCT_RARt || product->type == MATPRODUCT_ABt) {
412: PetscInt t = Bn;
413: Bn = Bm;
414: Bm = t;
415: }
416: if (product->type == MATPRODUCT_AtB) An = Am;
418: PetscCheck(An == Bm, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Matrix dimensions of A and %s are incompatible for MatProductType %s: A %" PetscInt_FMT "x%" PetscInt_FMT ", %s %" PetscInt_FMT "x%" PetscInt_FMT, bname,
419: MatProductTypes[product->type], A->rmap->N, A->cmap->N, bname, B->rmap->N, B->cmap->N);
420: PetscCheck(!Cm || Cm == Bn, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Matrix dimensions of B and C are incompatible for MatProductType %s: B %" PetscInt_FMT "x%" PetscInt_FMT ", C %" PetscInt_FMT "x%" PetscInt_FMT,
421: MatProductTypes[product->type], B->rmap->N, B->cmap->N, Cm, Cn);
423: fA = A->ops->productsetfromoptions;
424: fB = B->ops->productsetfromoptions;
425: fC = C ? C->ops->productsetfromoptions : fA;
426: if (C) {
427: PetscCall(PetscInfo(mat, "MatProductType %s for A %s, %s %s, C %s\n", MatProductTypes[product->type], ((PetscObject)A)->type_name, bname, ((PetscObject)B)->type_name, ((PetscObject)C)->type_name));
428: } else {
429: PetscCall(PetscInfo(mat, "MatProductType %s for A %s, %s %s\n", MatProductTypes[product->type], ((PetscObject)A)->type_name, bname, ((PetscObject)B)->type_name));
430: }
431: if (fA == fB && fA == fC && fA) {
432: PetscCall(PetscInfo(mat, " matching op\n"));
433: PetscCall((*fA)(mat));
434: }
435: /* We may have found f but it did not succeed */
436: if (!mat->ops->productsymbolic) { /* query MatProductSetFromOptions_Atype_Btype_Ctype */
437: char mtypes[256];
438: PetscCall(PetscStrncpy(mtypes, "MatProductSetFromOptions_", sizeof(mtypes)));
439: PetscCall(PetscStrlcat(mtypes, ((PetscObject)A)->type_name, sizeof(mtypes)));
440: PetscCall(PetscStrlcat(mtypes, "_", sizeof(mtypes)));
441: PetscCall(PetscStrlcat(mtypes, ((PetscObject)B)->type_name, sizeof(mtypes)));
442: if (C) {
443: PetscCall(PetscStrlcat(mtypes, "_", sizeof(mtypes)));
444: PetscCall(PetscStrlcat(mtypes, ((PetscObject)C)->type_name, sizeof(mtypes)));
445: }
446: PetscCall(PetscStrlcat(mtypes, "_C", sizeof(mtypes)));
447: #if defined(__clang__)
448: PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wformat-pedantic")
449: #elif defined(__GNUC__) || defined(__GNUG__)
450: PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wformat")
451: #endif
452: PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f));
453: PetscCall(PetscInfo(mat, " querying %s from A? %p\n", mtypes, f));
454: if (!f) {
455: PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f));
456: PetscCall(PetscInfo(mat, " querying %s from %s? %p\n", mtypes, bname, f));
457: }
458: if (!f && C) {
459: PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f));
460: PetscCall(PetscInfo(mat, " querying %s from C? %p\n", mtypes, f));
461: }
462: if (f) PetscCall((*f)(mat));
464: /* We may have found f but it did not succeed */
465: /* some matrices (i.e. MATTRANSPOSEVIRTUAL, MATSHELL constructed from MatConvert), knows what to do with their inner matrices */
466: if (!mat->ops->productsymbolic) {
467: PetscCall(PetscStrncpy(mtypes, "MatProductSetFromOptions_anytype_C", sizeof(mtypes)));
468: PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f));
469: PetscCall(PetscInfo(mat, " querying %s from A? %p\n", mtypes, f));
470: if (!f) {
471: PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f));
472: PetscCall(PetscInfo(mat, " querying %s from %s? %p\n", mtypes, bname, f));
473: }
474: if (!f && C) {
475: PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f));
476: PetscCall(PetscInfo(mat, " querying %s from C? %p\n", mtypes, f));
477: }
478: }
479: if (f) PetscCall((*f)(mat));
480: }
481: PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END()
482: /* We may have found f but it did not succeed */
483: if (!mat->ops->productsymbolic) {
484: /* we can still compute the product if B is of type dense */
485: if (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB) {
486: PetscBool isdense;
488: PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)B, &isdense, MATSEQDENSE, MATMPIDENSE, ""));
489: if (isdense) {
490: mat->ops->productsymbolic = MatProductSymbolic_X_Dense;
491: PetscCall(PetscInfo(mat, " using basic looping over columns of a dense matrix\n"));
492: }
493: } else if (product->type != MATPRODUCT_ABt) { /* use MatProductSymbolic/Numeric_Unsafe() for triple products only */
494: /*
495: TODO: this should be changed to a proper setfromoptions, not setting the symbolic pointer here, because we do not know if
496: the combination will succeed. In order to be sure, we need MatProductGetProductType to return the type of the result
497: before computing the symbolic phase
498: */
499: PetscCall(PetscInfo(mat, " symbolic product not supported, using MatProductSymbolic_Unsafe() implementation\n"));
500: mat->ops->productsymbolic = MatProductSymbolic_Unsafe;
501: }
502: }
503: if (!mat->ops->productsymbolic) PetscCall(PetscInfo(mat, " symbolic product is not supported\n"));
504: PetscFunctionReturn(PETSC_SUCCESS);
505: }
507: /*@
508: MatProductSetFromOptions - Sets the options for the computation of a matrix-matrix product operation where the type,
509: the algorithm etc are determined from the options database.
511: Logically Collective
513: Input Parameter:
514: . mat - the matrix whose values are computed via a matrix-matrix product operation
516: Options Database Keys:
517: + -mat_product_clear - Clear intermediate data structures after `MatProductNumeric()` has been called
518: . -mat_product_algorithm <algorithm> - Sets the algorithm, see `MatProductAlgorithm` for possible values
519: - -mat_product_algorithm_backend_cpu - Use the CPU to perform the computation even if the matrix is a GPU matrix
521: Level: intermediate
523: Note:
524: The `-mat_product_clear` option reduces memory usage but means that the matrix cannot be re-used for a matrix-matrix product operation
526: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatSetFromOptions()`, `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductNumeric()`,
527: `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductAlgorithm`
528: @*/
529: PetscErrorCode MatProductSetFromOptions(Mat mat)
530: {
531: PetscFunctionBegin;
533: MatCheckProduct(mat, 1);
534: PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot call MatProductSetFromOptions() with already present data");
535: mat->product->setfromoptionscalled = PETSC_TRUE;
536: PetscObjectOptionsBegin((PetscObject)mat);
537: PetscCall(PetscOptionsBool("-mat_product_clear", "Clear intermediate data structures after MatProductNumeric() has been called", "MatProductClear", mat->product->clear, &mat->product->clear, NULL));
538: PetscCall(PetscOptionsDeprecated("-mat_freeintermediatedatastructures", "-mat_product_clear", "3.13", "Or call MatProductClear() after MatProductNumeric()"));
539: PetscOptionsEnd();
540: PetscCall(MatProductSetFromOptions_Private(mat));
541: PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing product after setup phase");
542: PetscFunctionReturn(PETSC_SUCCESS);
543: }
545: /*@
546: MatProductView - View the private matrix-matrix algorithm object within a matrix
548: Logically Collective
550: Input Parameters:
551: + mat - the matrix obtained with `MatProductCreate()` or `MatProductCreateWithMat()`
552: - viewer - where the information on the matrix-matrix algorithm of `mat` should be reviewed
554: Level: intermediate
556: Developer Note:
557: Shouldn't this information be printed from an appropriate `MatView()` with perhaps certain formats set?
559: .seealso: [](ch_matrices), `MatProductType`, `Mat`, `MatProductSetFromOptions()`, `MatView()`, `MatProductCreate()`, `MatProductCreateWithMat()`
560: @*/
561: PetscErrorCode MatProductView(Mat mat, PetscViewer viewer)
562: {
563: PetscFunctionBegin;
565: if (!mat->product) PetscFunctionReturn(PETSC_SUCCESS);
566: if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer));
568: PetscCheckSameComm(mat, 1, viewer, 2);
569: if (mat->product->view) PetscCall((*mat->product->view)(mat, viewer));
570: PetscFunctionReturn(PETSC_SUCCESS);
571: }
573: /* these are basic implementations relying on the old function pointers
574: * they are dangerous and should be removed in the future */
575: PetscErrorCode MatProductNumeric_AB(Mat mat)
576: {
577: Mat_Product *product = mat->product;
578: Mat A = product->A, B = product->B;
580: PetscFunctionBegin;
581: PetscCall((*mat->ops->matmultnumeric)(A, B, mat));
582: PetscFunctionReturn(PETSC_SUCCESS);
583: }
585: PetscErrorCode MatProductNumeric_AtB(Mat mat)
586: {
587: Mat_Product *product = mat->product;
588: Mat A = product->A, B = product->B;
590: PetscFunctionBegin;
591: PetscCall((*mat->ops->transposematmultnumeric)(A, B, mat));
592: PetscFunctionReturn(PETSC_SUCCESS);
593: }
595: PetscErrorCode MatProductNumeric_ABt(Mat mat)
596: {
597: Mat_Product *product = mat->product;
598: Mat A = product->A, B = product->B;
600: PetscFunctionBegin;
601: PetscCall((*mat->ops->mattransposemultnumeric)(A, B, mat));
602: PetscFunctionReturn(PETSC_SUCCESS);
603: }
605: PetscErrorCode MatProductNumeric_PtAP(Mat mat)
606: {
607: Mat_Product *product = mat->product;
608: Mat A = product->A, B = product->B;
610: PetscFunctionBegin;
611: PetscCall((*mat->ops->ptapnumeric)(A, B, mat));
612: PetscFunctionReturn(PETSC_SUCCESS);
613: }
615: PetscErrorCode MatProductNumeric_RARt(Mat mat)
616: {
617: Mat_Product *product = mat->product;
618: Mat A = product->A, B = product->B;
620: PetscFunctionBegin;
621: PetscCall((*mat->ops->rartnumeric)(A, B, mat));
622: PetscFunctionReturn(PETSC_SUCCESS);
623: }
625: PetscErrorCode MatProductNumeric_ABC(Mat mat)
626: {
627: Mat_Product *product = mat->product;
628: Mat A = product->A, B = product->B, C = product->C;
630: PetscFunctionBegin;
631: PetscCall((*mat->ops->matmatmultnumeric)(A, B, C, mat));
632: PetscFunctionReturn(PETSC_SUCCESS);
633: }
635: /*@
636: MatProductNumeric - Compute a matrix-matrix product operation with the numerical values
638: Collective
640: Input/Output Parameter:
641: . mat - the matrix whose values are computed via a matrix-matrix product operation
643: Level: intermediate
645: Note:
646: `MatProductSymbolic()` must have been called on `mat` before calling this function
648: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductSetAlgorithm()`, `MatProductSetType()`, `MatProductCreate()`, `MatSetType()`, `MatProductSymbolic()`
649: @*/
650: PetscErrorCode MatProductNumeric(Mat mat)
651: {
652: PetscLogEvent eventtype = -1;
654: PetscFunctionBegin;
656: MatCheckProduct(mat, 1);
657: switch (mat->product->type) {
658: case MATPRODUCT_AB:
659: eventtype = MAT_MatMultNumeric;
660: break;
661: case MATPRODUCT_AtB:
662: eventtype = MAT_TransposeMatMultNumeric;
663: break;
664: case MATPRODUCT_ABt:
665: eventtype = MAT_MatTransposeMultNumeric;
666: break;
667: case MATPRODUCT_PtAP:
668: eventtype = MAT_PtAPNumeric;
669: break;
670: case MATPRODUCT_RARt:
671: eventtype = MAT_RARtNumeric;
672: break;
673: case MATPRODUCT_ABC:
674: eventtype = MAT_MatMatMultNumeric;
675: break;
676: default:
677: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]);
678: }
680: if (mat->ops->productnumeric) {
681: PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0));
682: PetscUseTypeMethod(mat, productnumeric);
683: PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0));
684: } else if (mat->product) {
685: char errstr[256];
687: if (mat->product->type == MATPRODUCT_ABC) {
688: PetscCall(PetscSNPrintf(errstr, 256, "%s with A %s, B %s, C %s", MatProductTypes[mat->product->type], ((PetscObject)mat->product->A)->type_name, ((PetscObject)mat->product->B)->type_name, ((PetscObject)mat->product->C)->type_name));
689: } else {
690: PetscCall(PetscSNPrintf(errstr, 256, "%s with A %s, B %s", MatProductTypes[mat->product->type], ((PetscObject)mat->product->A)->type_name, ((PetscObject)mat->product->B)->type_name));
691: }
692: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified numeric phase for product %s", errstr);
693: }
694: PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after numeric phase for product");
696: if (mat->product->clear) PetscCall(MatProductClear(mat));
697: PetscCall(PetscObjectStateIncrease((PetscObject)mat));
698: PetscFunctionReturn(PETSC_SUCCESS);
699: }
701: /* these are basic implementations relying on the old function pointers
702: * they are dangerous and should be removed in the future */
703: PetscErrorCode MatProductSymbolic_AB(Mat mat)
704: {
705: Mat_Product *product = mat->product;
706: Mat A = product->A, B = product->B;
708: PetscFunctionBegin;
709: PetscCall((*mat->ops->matmultsymbolic)(A, B, product->fill, mat));
710: mat->ops->productnumeric = MatProductNumeric_AB;
711: PetscFunctionReturn(PETSC_SUCCESS);
712: }
714: PetscErrorCode MatProductSymbolic_AtB(Mat mat)
715: {
716: Mat_Product *product = mat->product;
717: Mat A = product->A, B = product->B;
719: PetscFunctionBegin;
720: PetscCall((*mat->ops->transposematmultsymbolic)(A, B, product->fill, mat));
721: mat->ops->productnumeric = MatProductNumeric_AtB;
722: PetscFunctionReturn(PETSC_SUCCESS);
723: }
725: PetscErrorCode MatProductSymbolic_ABt(Mat mat)
726: {
727: Mat_Product *product = mat->product;
728: Mat A = product->A, B = product->B;
730: PetscFunctionBegin;
731: PetscCall((*mat->ops->mattransposemultsymbolic)(A, B, product->fill, mat));
732: mat->ops->productnumeric = MatProductNumeric_ABt;
733: PetscFunctionReturn(PETSC_SUCCESS);
734: }
736: PetscErrorCode MatProductSymbolic_ABC(Mat mat)
737: {
738: Mat_Product *product = mat->product;
739: Mat A = product->A, B = product->B, C = product->C;
741: PetscFunctionBegin;
742: PetscCall((*mat->ops->matmatmultsymbolic)(A, B, C, product->fill, mat));
743: mat->ops->productnumeric = MatProductNumeric_ABC;
744: PetscFunctionReturn(PETSC_SUCCESS);
745: }
747: /*@
748: MatProductSymbolic - Perform the symbolic portion of a matrix-matrix product operation, this creates a data structure for use with the numerical
749: product to be done with `MatProductNumeric()`
751: Collective
753: Input/Output Parameter:
754: . mat - the matrix whose values are to be computed via a matrix-matrix product operation
756: Level: intermediate
758: Note:
759: `MatProductSetFromOptions()` must have been called on `mat` before calling this function
761: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductSetFromOptions()`, `MatProductNumeric()`, `MatProductSetType()`, `MatProductSetAlgorithm()`
762: @*/
763: PetscErrorCode MatProductSymbolic(Mat mat)
764: {
765: PetscLogEvent eventtype = -1;
766: PetscBool missing = PETSC_FALSE;
768: PetscFunctionBegin;
770: MatCheckProduct(mat, 1);
771: PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot run symbolic phase. Product data not empty");
772: switch (mat->product->type) {
773: case MATPRODUCT_AB:
774: eventtype = MAT_MatMultSymbolic;
775: break;
776: case MATPRODUCT_AtB:
777: eventtype = MAT_TransposeMatMultSymbolic;
778: break;
779: case MATPRODUCT_ABt:
780: eventtype = MAT_MatTransposeMultSymbolic;
781: break;
782: case MATPRODUCT_PtAP:
783: eventtype = MAT_PtAPSymbolic;
784: break;
785: case MATPRODUCT_RARt:
786: eventtype = MAT_RARtSymbolic;
787: break;
788: case MATPRODUCT_ABC:
789: eventtype = MAT_MatMatMultSymbolic;
790: break;
791: default:
792: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]);
793: }
794: mat->ops->productnumeric = NULL;
795: if (mat->ops->productsymbolic) {
796: PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0));
797: PetscUseTypeMethod(mat, productsymbolic);
798: PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0));
799: } else missing = PETSC_TRUE;
801: if (missing || !mat->product || !mat->ops->productnumeric) {
802: char errstr[256];
804: if (mat->product->type == MATPRODUCT_ABC) {
805: PetscCall(PetscSNPrintf(errstr, 256, "%s with A %s, B %s, C %s", MatProductTypes[mat->product->type], ((PetscObject)mat->product->A)->type_name, ((PetscObject)mat->product->B)->type_name, ((PetscObject)mat->product->C)->type_name));
806: } else {
807: PetscCall(PetscSNPrintf(errstr, 256, "%s with A %s, B %s", MatProductTypes[mat->product->type], ((PetscObject)mat->product->A)->type_name, ((PetscObject)mat->product->B)->type_name));
808: }
809: PetscCheck(mat->product->setfromoptionscalled, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified symbolic phase for product %s. Call MatProductSetFromOptions() first", errstr);
810: PetscCheck(!missing, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Unspecified symbolic phase for product %s. The product is not supported", errstr);
811: PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after symbolic phase for product %s", errstr);
812: }
814: #if defined(PETSC_HAVE_DEVICE)
815: Mat A = mat->product->A;
816: Mat B = mat->product->B;
817: Mat C = mat->product->C;
818: PetscBool bindingpropagates;
819: bindingpropagates = (PetscBool)((A->boundtocpu && A->bindingpropagates) || (B->boundtocpu && B->bindingpropagates));
820: if (C) bindingpropagates = (PetscBool)(bindingpropagates || (C->boundtocpu && C->bindingpropagates));
821: if (bindingpropagates) {
822: PetscCall(MatBindToCPU(mat, PETSC_TRUE));
823: PetscCall(MatSetBindingPropagates(mat, PETSC_TRUE));
824: }
825: #endif
826: PetscFunctionReturn(PETSC_SUCCESS);
827: }
829: /*@
830: MatProductSetFill - Set an expected fill of the matrix whose values are computed via a matrix-matrix product operation
832: Collective
834: Input Parameters:
835: + mat - the matrix whose values are to be computed via a matrix-matrix product operation
836: - fill - expected fill as ratio of nnz(mat)/(nnz(A) + nnz(B) + nnz(C)); use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate.
837: If the product is a dense matrix, this value is not used.
839: Level: intermediate
841: Notes:
842: Use `fill` of `PETSC_DETERMINE` to use the default value.
844: The deprecated `PETSC_DEFAULT` is also supported to mean use the current value.
846: .seealso: [](ch_matrices), `MatProduct`, `PETSC_DETERMINE`, `Mat`, `MatProductSetFromOptions()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()`
847: @*/
848: PetscErrorCode MatProductSetFill(Mat mat, PetscReal fill)
849: {
850: PetscFunctionBegin;
852: MatCheckProduct(mat, 1);
853: if (fill == (PetscReal)PETSC_DETERMINE) mat->product->fill = mat->product->default_fill;
854: else if (fill != (PetscReal)PETSC_CURRENT) mat->product->fill = fill;
855: PetscFunctionReturn(PETSC_SUCCESS);
856: }
858: /*@
859: MatProductSetAlgorithm - Requests a particular algorithm for a matrix-matrix product operation that will perform to compute the given matrix
861: Collective
863: Input Parameters:
864: + mat - the matrix whose values are computed via a matrix-matrix product operation
865: - alg - particular implementation algorithm of the matrix product, e.g., `MATPRODUCTALGORITHMDEFAULT`.
867: Options Database Key:
868: . -mat_product_algorithm <algorithm> - Sets the algorithm, see `MatProductAlgorithm`
870: Level: intermediate
872: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductClear()`, `MatProductSetType()`, `MatProductSetFill()`, `MatProductCreate()`, `MatProductAlgorithm`, `MatProductType`, `MatProductGetAlgorithm()`
873: @*/
874: PetscErrorCode MatProductSetAlgorithm(Mat mat, MatProductAlgorithm alg)
875: {
876: PetscFunctionBegin;
878: MatCheckProduct(mat, 1);
879: PetscCall(PetscFree(mat->product->alg));
880: PetscCall(PetscStrallocpy(alg, &mat->product->alg));
881: PetscFunctionReturn(PETSC_SUCCESS);
882: }
884: /*@
885: MatProductGetAlgorithm - Returns the selected algorithm for a matrix-matrix product operation
887: Not Collective
889: Input Parameter:
890: . mat - the matrix whose values are computed via a matrix-matrix product operation
892: Output Parameter:
893: . alg - the selected algorithm of the matrix product, e.g., `MATPRODUCTALGORITHMDEFAULT`.
895: Level: intermediate
897: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductSetAlgorithm()`
898: @*/
899: PetscErrorCode MatProductGetAlgorithm(Mat mat, MatProductAlgorithm *alg)
900: {
901: PetscFunctionBegin;
903: PetscAssertPointer(alg, 2);
904: if (mat->product) *alg = mat->product->alg;
905: else *alg = NULL;
906: PetscFunctionReturn(PETSC_SUCCESS);
907: }
909: /*@
910: MatProductSetType - Sets a particular matrix-matrix product operation to be used to compute the values of the given matrix
912: Collective
914: Input Parameters:
915: + mat - the matrix whose values are computed via a matrix-matrix product operation
916: - productype - matrix product type, e.g., `MATPRODUCT_AB`,`MATPRODUCT_AtB`,`MATPRODUCT_ABt`,`MATPRODUCT_PtAP`,`MATPRODUCT_RARt`,`MATPRODUCT_ABC`,
917: see `MatProductType`
919: Level: intermediate
921: Note:
922: The small t represents the transpose operation.
924: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()`, `MatProductType`,
925: `MATPRODUCT_AB`, `MATPRODUCT_AtB`, `MATPRODUCT_ABt`, `MATPRODUCT_PtAP`, `MATPRODUCT_RARt`, `MATPRODUCT_ABC`
926: @*/
927: PetscErrorCode MatProductSetType(Mat mat, MatProductType productype)
928: {
929: PetscFunctionBegin;
931: MatCheckProduct(mat, 1);
933: if (productype != mat->product->type) {
934: if (mat->product->destroy) PetscCall((*mat->product->destroy)(mat->product->data));
935: mat->product->destroy = NULL;
936: mat->product->data = NULL;
937: mat->ops->productsymbolic = NULL;
938: mat->ops->productnumeric = NULL;
939: }
940: mat->product->type = productype;
941: PetscFunctionReturn(PETSC_SUCCESS);
942: }
944: /*@
945: MatProductClear - Clears from the matrix any internal data structures related to the computation of the values of the matrix from matrix-matrix product operations
947: Collective
949: Input Parameter:
950: . mat - the matrix whose values are to be computed via a matrix-matrix product operation
952: Options Database Key:
953: . -mat_product_clear - Clear intermediate data structures after `MatProductNumeric()` has been called
955: Level: intermediate
957: Notes:
958: This function should be called to remove any intermediate data used to compute the matrix to free up memory.
960: After having called this function, matrix-matrix product operations can no longer be used on `mat`
962: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()`
963: @*/
964: PetscErrorCode MatProductClear(Mat mat)
965: {
966: Mat_Product *product = mat->product;
968: PetscFunctionBegin;
970: if (product) {
971: PetscCall(MatDestroy(&product->A));
972: PetscCall(MatDestroy(&product->B));
973: PetscCall(MatDestroy(&product->C));
974: PetscCall(PetscFree(product->alg));
975: PetscCall(MatDestroy(&product->Dwork));
976: if (product->destroy) PetscCall((*product->destroy)(product->data));
977: }
978: PetscCall(PetscFree(mat->product));
979: mat->ops->productsymbolic = NULL;
980: mat->ops->productnumeric = NULL;
981: PetscFunctionReturn(PETSC_SUCCESS);
982: }
984: /* Create a supporting struct and attach it to the matrix product */
985: PetscErrorCode MatProductCreate_Private(Mat A, Mat B, Mat C, Mat D)
986: {
987: Mat_Product *product = NULL;
989: PetscFunctionBegin;
991: PetscCheck(!D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product already present");
992: PetscCall(PetscNew(&product));
993: product->A = A;
994: product->B = B;
995: product->C = C;
996: product->type = MATPRODUCT_UNSPECIFIED;
997: product->Dwork = NULL;
998: product->api_user = PETSC_FALSE;
999: product->clear = PETSC_FALSE;
1000: product->setfromoptionscalled = PETSC_FALSE;
1001: PetscObjectParameterSetDefault(product, fill, 2);
1002: D->product = product;
1004: PetscCall(MatProductSetAlgorithm(D, MATPRODUCTALGORITHMDEFAULT));
1005: PetscCall(MatProductSetFill(D, PETSC_DEFAULT));
1007: PetscCall(PetscObjectReference((PetscObject)A));
1008: PetscCall(PetscObjectReference((PetscObject)B));
1009: PetscCall(PetscObjectReference((PetscObject)C));
1010: PetscFunctionReturn(PETSC_SUCCESS);
1011: }
1013: /*@
1014: MatProductCreateWithMat - Set a given matrix to have its values computed via matrix-matrix operations on other matrices.
1016: Collective
1018: Input Parameters:
1019: + A - the first matrix
1020: . B - the second matrix
1021: . C - the third matrix (optional, use `NULL` if not needed)
1022: - D - the matrix whose values are to be computed via a matrix-matrix product operation
1024: Level: intermediate
1026: Notes:
1027: Use `MatProductCreate()` if the matrix you wish computed (the `D` matrix) does not already exist
1029: See `MatProductCreate()` for details on the usage of the matrix-matrix product operations
1031: Any product data currently attached to `D` will be cleared
1033: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductType`, `MatProductSetType()`, `MatProductAlgorithm`,
1034: `MatProductSetAlgorithm`, `MatProductCreate()`, `MatProductClear()`
1035: @*/
1036: PetscErrorCode MatProductCreateWithMat(Mat A, Mat B, Mat C, Mat D)
1037: {
1038: PetscFunctionBegin;
1041: MatCheckPreallocated(A, 1);
1042: PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
1043: PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1047: MatCheckPreallocated(B, 2);
1048: PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
1049: PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1051: if (C) {
1054: MatCheckPreallocated(C, 3);
1055: PetscCheck(C->assembled, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
1056: PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1057: }
1061: MatCheckPreallocated(D, 4);
1062: PetscCheck(D->assembled, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
1063: PetscCheck(!D->factortype, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1065: /* Create a supporting struct and attach it to D */
1066: PetscCall(MatProductClear(D));
1067: PetscCall(MatProductCreate_Private(A, B, C, D));
1068: PetscFunctionReturn(PETSC_SUCCESS);
1069: }
1071: /*@
1072: MatProductCreate - create a matrix to hold the result of a matrix-matrix product operation
1074: Collective
1076: Input Parameters:
1077: + A - the first matrix
1078: . B - the second matrix
1079: - C - the third matrix (or `NULL`)
1081: Output Parameter:
1082: . D - the matrix whose values are to be computed via a matrix-matrix product operation
1084: Level: intermediate
1086: Example:
1087: .vb
1088: MatProductCreate(A,B,C,&D); or MatProductCreateWithMat(A,B,C,D)
1089: MatProductSetType(D, MATPRODUCT_AB or MATPRODUCT_AtB or MATPRODUCT_ABt or MATPRODUCT_PtAP or MATPRODUCT_RARt or MATPRODUCT_ABC)
1090: MatProductSetAlgorithm(D, alg)
1091: MatProductSetFill(D,fill)
1092: MatProductSetFromOptions(D)
1093: MatProductSymbolic(D)
1094: MatProductNumeric(D)
1095: Change numerical values in some of the matrices
1096: MatProductNumeric(D)
1097: .ve
1099: Notes:
1100: Use `MatProductCreateWithMat()` if the matrix you wish computed, the `D` matrix, already exists.
1102: The information computed during the symbolic stage can be reused for new numerical computations with the same non-zero structure
1104: Developer Notes:
1105: It is undocumented what happens if the nonzero structure of the input matrices changes. Is the symbolic stage automatically redone? Does it crash?
1106: Is there error checking for it?
1108: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductClear()`
1109: @*/
1110: PetscErrorCode MatProductCreate(Mat A, Mat B, Mat C, Mat *D)
1111: {
1112: PetscFunctionBegin;
1117: PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix A");
1118: PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix B");
1120: if (C) {
1123: PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix C");
1124: }
1126: PetscAssertPointer(D, 4);
1127: PetscCall(MatCreate(PetscObjectComm((PetscObject)A), D));
1128: /* Delay setting type of D to the MatProduct symbolic phase, as we allow sparse A and dense B */
1129: PetscCall(MatProductCreate_Private(A, B, C, *D));
1130: PetscFunctionReturn(PETSC_SUCCESS);
1131: }
1133: /*
1134: These are safe basic implementations of ABC, RARt and PtAP
1135: that do not rely on mat->ops->matmatop function pointers.
1136: They only use the MatProduct API and are currently used by
1137: cuSPARSE and KOKKOS-KERNELS backends
1138: */
1139: typedef struct {
1140: Mat BC;
1141: Mat ABC;
1142: } MatMatMatPrivate;
1144: static PetscErrorCode MatDestroy_MatMatMatPrivate(void *data)
1145: {
1146: MatMatMatPrivate *mmdata = (MatMatMatPrivate *)data;
1148: PetscFunctionBegin;
1149: PetscCall(MatDestroy(&mmdata->BC));
1150: PetscCall(MatDestroy(&mmdata->ABC));
1151: PetscCall(PetscFree(data));
1152: PetscFunctionReturn(PETSC_SUCCESS);
1153: }
1155: static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat)
1156: {
1157: Mat_Product *product = mat->product;
1158: MatMatMatPrivate *mmabc;
1160: PetscFunctionBegin;
1161: MatCheckProduct(mat, 1);
1162: PetscCheck(mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data empty");
1163: mmabc = (MatMatMatPrivate *)mat->product->data;
1164: PetscCheck(mmabc->BC->ops->productnumeric, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing numeric stage");
1165: /* use function pointer directly to prevent logging */
1166: PetscCall((*mmabc->BC->ops->productnumeric)(mmabc->BC));
1167: /* swap ABC product stuff with that of ABC for the numeric phase on mat */
1168: mat->product = mmabc->ABC->product;
1169: mat->ops->productnumeric = mmabc->ABC->ops->productnumeric;
1170: /* use function pointer directly to prevent logging */
1171: PetscUseTypeMethod(mat, productnumeric);
1172: mat->ops->productnumeric = MatProductNumeric_ABC_Basic;
1173: mat->product = product;
1174: PetscFunctionReturn(PETSC_SUCCESS);
1175: }
1177: PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat)
1178: {
1179: Mat_Product *product = mat->product;
1180: Mat A, B, C;
1181: MatProductType p1, p2;
1182: MatMatMatPrivate *mmabc;
1183: const char *prefix;
1185: PetscFunctionBegin;
1186: MatCheckProduct(mat, 1);
1187: PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data not empty");
1188: PetscCall(MatGetOptionsPrefix(mat, &prefix));
1189: PetscCall(PetscNew(&mmabc));
1190: product->data = mmabc;
1191: product->destroy = MatDestroy_MatMatMatPrivate;
1192: switch (product->type) {
1193: case MATPRODUCT_PtAP:
1194: p1 = MATPRODUCT_AB;
1195: p2 = MATPRODUCT_AtB;
1196: A = product->B;
1197: B = product->A;
1198: C = product->B;
1199: break;
1200: case MATPRODUCT_RARt:
1201: p1 = MATPRODUCT_ABt;
1202: p2 = MATPRODUCT_AB;
1203: A = product->B;
1204: B = product->A;
1205: C = product->B;
1206: break;
1207: case MATPRODUCT_ABC:
1208: p1 = MATPRODUCT_AB;
1209: p2 = MATPRODUCT_AB;
1210: A = product->A;
1211: B = product->B;
1212: C = product->C;
1213: break;
1214: default:
1215: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Not for ProductType %s", MatProductTypes[product->type]);
1216: }
1217: PetscCall(MatProductCreate(B, C, NULL, &mmabc->BC));
1218: PetscCall(MatSetOptionsPrefix(mmabc->BC, prefix));
1219: PetscCall(MatAppendOptionsPrefix(mmabc->BC, "P1_"));
1220: PetscCall(MatProductSetType(mmabc->BC, p1));
1221: PetscCall(MatProductSetAlgorithm(mmabc->BC, MATPRODUCTALGORITHMDEFAULT));
1222: PetscCall(MatProductSetFill(mmabc->BC, product->fill));
1223: mmabc->BC->product->api_user = product->api_user;
1224: PetscCall(MatProductSetFromOptions(mmabc->BC));
1225: PetscCheck(mmabc->BC->ops->productsymbolic, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Symbolic ProductType %s not supported with %s and %s", MatProductTypes[p1], ((PetscObject)B)->type_name, ((PetscObject)C)->type_name);
1226: /* use function pointer directly to prevent logging */
1227: PetscCall((*mmabc->BC->ops->productsymbolic)(mmabc->BC));
1229: PetscCall(MatProductCreate(A, mmabc->BC, NULL, &mmabc->ABC));
1230: PetscCall(MatSetOptionsPrefix(mmabc->ABC, prefix));
1231: PetscCall(MatAppendOptionsPrefix(mmabc->ABC, "P2_"));
1232: PetscCall(MatProductSetType(mmabc->ABC, p2));
1233: PetscCall(MatProductSetAlgorithm(mmabc->ABC, MATPRODUCTALGORITHMDEFAULT));
1234: PetscCall(MatProductSetFill(mmabc->ABC, product->fill));
1235: mmabc->ABC->product->api_user = product->api_user;
1236: PetscCall(MatProductSetFromOptions(mmabc->ABC));
1237: PetscCheck(mmabc->ABC->ops->productsymbolic, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Symbolic ProductType %s not supported with %s and %s", MatProductTypes[p2], ((PetscObject)A)->type_name, ((PetscObject)mmabc->BC)->type_name);
1238: /* swap ABC product stuff with that of ABC for the symbolic phase on mat */
1239: mat->product = mmabc->ABC->product;
1240: mat->ops->productsymbolic = mmabc->ABC->ops->productsymbolic;
1241: /* use function pointer directly to prevent logging */
1242: PetscUseTypeMethod(mat, productsymbolic);
1243: mmabc->ABC->ops->productnumeric = mat->ops->productnumeric;
1244: mat->ops->productsymbolic = MatProductSymbolic_ABC_Basic;
1245: mat->ops->productnumeric = MatProductNumeric_ABC_Basic;
1246: mat->product = product;
1247: PetscFunctionReturn(PETSC_SUCCESS);
1248: }
1250: /*@
1251: MatProductGetType - Returns the type of matrix-matrix product associated with computing values for the given matrix
1253: Not Collective
1255: Input Parameter:
1256: . mat - the matrix whose values are to be computed via a matrix-matrix product operation
1258: Output Parameter:
1259: . mtype - the `MatProductType`
1261: Level: intermediate
1263: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductCreate()`, `MatProductType`, `MatProductAlgorithm`
1264: @*/
1265: PetscErrorCode MatProductGetType(Mat mat, MatProductType *mtype)
1266: {
1267: PetscFunctionBegin;
1269: PetscAssertPointer(mtype, 2);
1270: *mtype = MATPRODUCT_UNSPECIFIED;
1271: if (mat->product) *mtype = mat->product->type;
1272: PetscFunctionReturn(PETSC_SUCCESS);
1273: }
1275: /*@
1276: MatProductGetMats - Returns the matrices associated with the matrix-matrix product associated with computing values for the given matrix
1278: Not Collective
1280: Input Parameter:
1281: . mat - the matrix whose values are to be computed via a matrix-matrix product operation
1283: Output Parameters:
1284: + A - the first matrix
1285: . B - the second matrix
1286: - C - the third matrix (may be `NULL` for some `MatProductType`)
1288: Level: intermediate
1290: .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()`
1291: @*/
1292: PetscErrorCode MatProductGetMats(Mat mat, Mat *A, Mat *B, Mat *C)
1293: {
1294: PetscFunctionBegin;
1296: if (A) *A = mat->product ? mat->product->A : NULL;
1297: if (B) *B = mat->product ? mat->product->B : NULL;
1298: if (C) *C = mat->product ? mat->product->C : NULL;
1299: PetscFunctionReturn(PETSC_SUCCESS);
1300: }