xref: /petsc/src/mat/interface/matproduct.c (revision 013e2dc7137d1d9dc4e6b44a828a8fb0f1bd6f29)
14222ddf1SHong Zhang 
24222ddf1SHong Zhang /*
34222ddf1SHong Zhang     Routines for matrix products. Calling procedure:
44222ddf1SHong Zhang 
56718818eSStefano Zampini     MatProductCreate(A,B,C,&D); or MatProductCreateWithMat(A,B,C,D)
66718818eSStefano Zampini     MatProductSetType(D, MATPRODUCT_AB/AtB/ABt/PtAP/RARt/ABC)
76718818eSStefano Zampini     MatProductSetAlgorithm(D, alg)
86718818eSStefano Zampini     MatProductSetFill(D,fill)
96718818eSStefano Zampini     MatProductSetFromOptions(D)
106718818eSStefano Zampini       -> MatProductSetFromOptions_Private(D)
114222ddf1SHong Zhang            # Check matrix global sizes
126718818eSStefano Zampini            if the matrices have the same setfromoptions routine, use it
136718818eSStefano Zampini            if not, try:
146718818eSStefano Zampini              -> Query MatProductSetFromOptions_Atype_Btype_Ctype_C(D) from A, B and C (in order)
156718818eSStefano Zampini              if found -> run the specific setup that must set the symbolic operation (these callbacks should never fail)
166718818eSStefano Zampini            if callback not found or no symbolic operation set
17*013e2dc7SBarry Smith              -> Query MatProductSetFromOptions_anytype_C(D) from A, B and C (in order) (e.g, matrices may have inner matrices like MATTRANSPOSEVIRTUAL)
186718818eSStefano Zampini            if dispatch found but combination still not present do
196718818eSStefano Zampini              -> check if B is dense and product type AtB or AB -> if true, basic looping of dense columns
206718818eSStefano Zampini              -> check if triple product (PtAP, RARt or ABC) -> if true, set the Basic routines
216718818eSStefano Zampini 
226718818eSStefano Zampini     #  The setfromoptions calls MatProductSetFromOptions_Atype_Btype_Ctype should
234222ddf1SHong Zhang     #    Check matrix local sizes for mpi matrices
244222ddf1SHong Zhang     #    Set default algorithm
254222ddf1SHong Zhang     #    Get runtime option
266718818eSStefano Zampini     #    Set D->ops->productsymbolic = MatProductSymbolic_productype_Atype_Btype_Ctype if found
274222ddf1SHong Zhang 
286718818eSStefano Zampini     MatProductSymbolic(D)
296718818eSStefano Zampini       # Call MatProductSymbolic_productype_Atype_Btype_Ctype()
306718818eSStefano Zampini         the callback must set the numeric phase D->ops->productnumeric = MatProductNumeric_productype_Atype_Btype_Ctype
314222ddf1SHong Zhang 
326718818eSStefano Zampini     MatProductNumeric(D)
336718818eSStefano Zampini       # Call the numeric phase
346718818eSStefano Zampini 
356718818eSStefano Zampini     # The symbolic phases are allowed to set extra data structures and attach those to the product
366718818eSStefano Zampini     # this additional data can be reused between multiple numeric phases with the same matrices
376718818eSStefano Zampini     # if not needed, call
386718818eSStefano Zampini     MatProductClear(D)
394222ddf1SHong Zhang */
404222ddf1SHong Zhang 
414222ddf1SHong Zhang #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
424222ddf1SHong Zhang 
436718818eSStefano Zampini const char *const MatProductTypes[] = {"UNSPECIFIED", "AB", "AtB", "ABt", "PtAP", "RARt", "ABC"};
44544a5e07SHong Zhang 
456718818eSStefano Zampini /* these are basic implementations relying on the old function pointers
466718818eSStefano Zampini  * they are dangerous and should be removed in the future */
479371c9d4SSatish Balay static PetscErrorCode MatProductNumeric_PtAP_Unsafe(Mat C) {
484222ddf1SHong Zhang   Mat_Product *product = C->product;
494222ddf1SHong Zhang   Mat          P = product->B, AP = product->Dwork;
504222ddf1SHong Zhang 
514222ddf1SHong Zhang   PetscFunctionBegin;
524222ddf1SHong Zhang   /* AP = A*P */
539566063dSJacob Faibussowitsch   PetscCall(MatProductNumeric(AP));
544222ddf1SHong Zhang   /* C = P^T*AP */
559566063dSJacob Faibussowitsch   PetscCall((*C->ops->transposematmultnumeric)(P, AP, C));
564222ddf1SHong Zhang   PetscFunctionReturn(0);
574222ddf1SHong Zhang }
584222ddf1SHong Zhang 
599371c9d4SSatish Balay static PetscErrorCode MatProductSymbolic_PtAP_Unsafe(Mat C) {
604222ddf1SHong Zhang   Mat_Product *product = C->product;
614222ddf1SHong Zhang   Mat          A = product->A, P = product->B, AP;
624222ddf1SHong Zhang   PetscReal    fill = product->fill;
634222ddf1SHong Zhang 
644222ddf1SHong Zhang   PetscFunctionBegin;
659566063dSJacob Faibussowitsch   PetscCall(PetscInfo((PetscObject)C, "for A %s, P %s is used\n", ((PetscObject)product->A)->type_name, ((PetscObject)product->B)->type_name));
664222ddf1SHong Zhang   /* AP = A*P */
679566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(A, P, NULL, &AP));
689566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(AP, MATPRODUCT_AB));
699566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(AP, MATPRODUCTALGORITHMDEFAULT));
709566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(AP, fill));
719566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(AP));
729566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(AP));
734222ddf1SHong Zhang 
744222ddf1SHong Zhang   /* C = P^T*AP */
759566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(C, MATPRODUCT_AtB));
769566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(C, MATPRODUCTALGORITHMDEFAULT));
774222ddf1SHong Zhang   product->A = P;
784222ddf1SHong Zhang   product->B = AP;
799566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(C));
809566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(C));
814222ddf1SHong Zhang 
824222ddf1SHong Zhang   /* resume user's original input matrix setting for A and B */
834222ddf1SHong Zhang   product->A     = A;
844222ddf1SHong Zhang   product->B     = P;
854222ddf1SHong Zhang   product->Dwork = AP;
864222ddf1SHong Zhang 
875415d71bSStefano Zampini   C->ops->productnumeric = MatProductNumeric_PtAP_Unsafe;
884222ddf1SHong Zhang   PetscFunctionReturn(0);
894222ddf1SHong Zhang }
904222ddf1SHong Zhang 
919371c9d4SSatish Balay static PetscErrorCode MatProductNumeric_RARt_Unsafe(Mat C) {
924222ddf1SHong Zhang   Mat_Product *product = C->product;
934222ddf1SHong Zhang   Mat          R = product->B, RA = product->Dwork;
944222ddf1SHong Zhang 
954222ddf1SHong Zhang   PetscFunctionBegin;
964222ddf1SHong Zhang   /* RA = R*A */
979566063dSJacob Faibussowitsch   PetscCall(MatProductNumeric(RA));
984222ddf1SHong Zhang   /* C = RA*R^T */
999566063dSJacob Faibussowitsch   PetscCall((*C->ops->mattransposemultnumeric)(RA, R, C));
1004222ddf1SHong Zhang   PetscFunctionReturn(0);
1014222ddf1SHong Zhang }
1024222ddf1SHong Zhang 
1039371c9d4SSatish Balay static PetscErrorCode MatProductSymbolic_RARt_Unsafe(Mat C) {
1044222ddf1SHong Zhang   Mat_Product *product = C->product;
1054222ddf1SHong Zhang   Mat          A = product->A, R = product->B, RA;
1064222ddf1SHong Zhang   PetscReal    fill = product->fill;
1074222ddf1SHong Zhang 
1084222ddf1SHong Zhang   PetscFunctionBegin;
1099566063dSJacob Faibussowitsch   PetscCall(PetscInfo((PetscObject)C, "for A %s, R %s is used\n", ((PetscObject)product->A)->type_name, ((PetscObject)product->B)->type_name));
1104222ddf1SHong Zhang   /* RA = R*A */
1119566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(R, A, NULL, &RA));
1129566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(RA, MATPRODUCT_AB));
1139566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(RA, MATPRODUCTALGORITHMDEFAULT));
1149566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(RA, fill));
1159566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(RA));
1169566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(RA));
1174222ddf1SHong Zhang 
1184222ddf1SHong Zhang   /* C = RA*R^T */
1199566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(C, MATPRODUCT_ABt));
1209566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(C, MATPRODUCTALGORITHMDEFAULT));
1214222ddf1SHong Zhang   product->A = RA;
1229566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(C));
1239566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(C));
1244222ddf1SHong Zhang 
1254222ddf1SHong Zhang   /* resume user's original input matrix setting for A */
1264222ddf1SHong Zhang   product->A             = A;
1274222ddf1SHong Zhang   product->Dwork         = RA; /* save here so it will be destroyed with product C */
1285415d71bSStefano Zampini   C->ops->productnumeric = MatProductNumeric_RARt_Unsafe;
1294222ddf1SHong Zhang   PetscFunctionReturn(0);
1304222ddf1SHong Zhang }
1314222ddf1SHong Zhang 
1329371c9d4SSatish Balay static PetscErrorCode MatProductNumeric_ABC_Unsafe(Mat mat) {
1334222ddf1SHong Zhang   Mat_Product *product = mat->product;
1344222ddf1SHong Zhang   Mat          A = product->A, BC = product->Dwork;
1354222ddf1SHong Zhang 
1364222ddf1SHong Zhang   PetscFunctionBegin;
1374222ddf1SHong Zhang   /* Numeric BC = B*C */
1389566063dSJacob Faibussowitsch   PetscCall(MatProductNumeric(BC));
1394222ddf1SHong Zhang   /* Numeric mat = A*BC */
1409566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmultnumeric)(A, BC, mat));
1414222ddf1SHong Zhang   PetscFunctionReturn(0);
1424222ddf1SHong Zhang }
1434222ddf1SHong Zhang 
1449371c9d4SSatish Balay static PetscErrorCode MatProductSymbolic_ABC_Unsafe(Mat mat) {
1454222ddf1SHong Zhang   Mat_Product *product = mat->product;
1464222ddf1SHong Zhang   Mat          B = product->B, C = product->C, BC;
1474222ddf1SHong Zhang   PetscReal    fill = product->fill;
1484222ddf1SHong Zhang 
1494222ddf1SHong Zhang   PetscFunctionBegin;
1509566063dSJacob Faibussowitsch   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));
1514222ddf1SHong Zhang   /* Symbolic BC = B*C */
1529566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(B, C, NULL, &BC));
1539566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(BC, MATPRODUCT_AB));
1549566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(BC, MATPRODUCTALGORITHMDEFAULT));
1559566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(BC, fill));
1569566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(BC));
1579566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(BC));
1584222ddf1SHong Zhang 
1594222ddf1SHong Zhang   /* Symbolic mat = A*BC */
1609566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(mat, MATPRODUCT_AB));
1619566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(mat, MATPRODUCTALGORITHMDEFAULT));
1624222ddf1SHong Zhang   product->B     = BC;
1634222ddf1SHong Zhang   product->Dwork = BC;
1649566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(mat));
1659566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(mat));
1664222ddf1SHong Zhang 
1674222ddf1SHong Zhang   /* resume user's original input matrix setting for B */
1684222ddf1SHong Zhang   product->B               = B;
1695415d71bSStefano Zampini   mat->ops->productnumeric = MatProductNumeric_ABC_Unsafe;
1704222ddf1SHong Zhang   PetscFunctionReturn(0);
1714222ddf1SHong Zhang }
1724222ddf1SHong Zhang 
1739371c9d4SSatish Balay static PetscErrorCode MatProductSymbolic_Unsafe(Mat mat) {
1744222ddf1SHong Zhang   Mat_Product *product = mat->product;
1754222ddf1SHong Zhang 
1764222ddf1SHong Zhang   PetscFunctionBegin;
1774222ddf1SHong Zhang   switch (product->type) {
1789371c9d4SSatish Balay   case MATPRODUCT_PtAP: PetscCall(MatProductSymbolic_PtAP_Unsafe(mat)); break;
1799371c9d4SSatish Balay   case MATPRODUCT_RARt: PetscCall(MatProductSymbolic_RARt_Unsafe(mat)); break;
1809371c9d4SSatish Balay   case MATPRODUCT_ABC: PetscCall(MatProductSymbolic_ABC_Unsafe(mat)); break;
18198921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[product->type]);
1824222ddf1SHong Zhang   }
1834222ddf1SHong Zhang   PetscFunctionReturn(0);
1844222ddf1SHong Zhang }
1854222ddf1SHong Zhang 
1864222ddf1SHong Zhang /* ----------------------------------------------- */
1874222ddf1SHong Zhang /*@C
1884222ddf1SHong Zhang    MatProductReplaceMats - Replace input matrices for a matrix product.
1894222ddf1SHong Zhang 
1904222ddf1SHong Zhang    Collective on Mat
1914222ddf1SHong Zhang 
1924222ddf1SHong Zhang    Input Parameters:
1934222ddf1SHong Zhang +  A - the matrix or NULL if not being replaced
1944222ddf1SHong Zhang .  B - the matrix or NULL if not being replaced
1954222ddf1SHong Zhang .  C - the matrix or NULL if not being replaced
1964222ddf1SHong Zhang -  D - the matrix product
1974222ddf1SHong Zhang 
1984222ddf1SHong Zhang    Level: intermediate
1994222ddf1SHong Zhang 
20011a5261eSBarry Smith    Note:
20111a5261eSBarry Smith      To reuse the symbolic phase, the input matrices must have exactly the same data structure as the replaced one.
2021cdffd5eSHong Zhang      If the type of any of the input matrices is different than what was previously used, or their symmetry flag changed but
203f5368d60SBarry Smith      the symbolic phase took advantage of their symmetry, the product is cleared and `MatProductSetFromOptions()` and `MatProductSymbolic()` are invoked again.
2044222ddf1SHong Zhang 
205db781477SPatrick Sanan .seealso: `MatProductCreate()`, `MatProductSetFromOptions()`, `MatProductSymbolic().` `MatProductClear()`
2064222ddf1SHong Zhang @*/
2079371c9d4SSatish Balay PetscErrorCode MatProductReplaceMats(Mat A, Mat B, Mat C, Mat D) {
2086718818eSStefano Zampini   Mat_Product *product;
209b94d7dedSBarry Smith   PetscBool    flgA = PETSC_TRUE, flgB = PETSC_TRUE, flgC = PETSC_TRUE, isset, issym;
2104222ddf1SHong Zhang 
2114222ddf1SHong Zhang   PetscFunctionBegin;
2127a3c3d58SStefano Zampini   PetscValidHeaderSpecific(D, MAT_CLASSID, 4);
2136718818eSStefano Zampini   MatCheckProduct(D, 4);
2146718818eSStefano Zampini   product = D->product;
2154222ddf1SHong Zhang   if (A) {
2167a3c3d58SStefano Zampini     PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2179566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)A));
2189566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)product->A, ((PetscObject)A)->type_name, &flgA));
219b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(A, &isset, &issym));
220b94d7dedSBarry Smith     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 */
221fa046f9fSJunchao Zhang       flgA                                           = PETSC_FALSE;
222fa046f9fSJunchao Zhang       product->symbolic_used_the_fact_A_is_symmetric = PETSC_FALSE; /* reinit */
223fa046f9fSJunchao Zhang     }
2249566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->A));
2254222ddf1SHong Zhang     product->A = A;
2264222ddf1SHong Zhang   }
2274222ddf1SHong Zhang   if (B) {
2287a3c3d58SStefano Zampini     PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
2299566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)B));
2309566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)product->B, ((PetscObject)B)->type_name, &flgB));
231b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(B, &isset, &issym));
232b94d7dedSBarry Smith     if (product->symbolic_used_the_fact_B_is_symmetric && isset && !issym) {
233fa046f9fSJunchao Zhang       flgB                                           = PETSC_FALSE;
234fa046f9fSJunchao Zhang       product->symbolic_used_the_fact_B_is_symmetric = PETSC_FALSE; /* reinit */
235fa046f9fSJunchao Zhang     }
2369566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->B));
2374222ddf1SHong Zhang     product->B = B;
2384222ddf1SHong Zhang   }
2394417c5e8SHong Zhang   if (C) {
2407a3c3d58SStefano Zampini     PetscValidHeaderSpecific(C, MAT_CLASSID, 3);
2419566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)C));
2429566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)product->C, ((PetscObject)C)->type_name, &flgC));
243b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(C, &isset, &issym));
244b94d7dedSBarry Smith     if (product->symbolic_used_the_fact_C_is_symmetric && isset && !issym) {
245fa046f9fSJunchao Zhang       flgC                                           = PETSC_FALSE;
246fa046f9fSJunchao Zhang       product->symbolic_used_the_fact_C_is_symmetric = PETSC_FALSE; /* reinit */
247fa046f9fSJunchao Zhang     }
2489566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->C));
2494417c5e8SHong Zhang     product->C = C;
2504417c5e8SHong Zhang   }
2516718818eSStefano Zampini   /* Any of the replaced mats is of a different type, reset */
2526718818eSStefano Zampini   if (!flgA || !flgB || !flgC) {
2531baa6e33SBarry Smith     if (D->product->destroy) PetscCall((*D->product->destroy)(D->product->data));
2546718818eSStefano Zampini     D->product->destroy = NULL;
2556718818eSStefano Zampini     D->product->data    = NULL;
2566718818eSStefano Zampini     if (D->ops->productnumeric || D->ops->productsymbolic) {
2579566063dSJacob Faibussowitsch       PetscCall(MatProductSetFromOptions(D));
2589566063dSJacob Faibussowitsch       PetscCall(MatProductSymbolic(D));
2596718818eSStefano Zampini     }
2606718818eSStefano Zampini   }
2614222ddf1SHong Zhang   PetscFunctionReturn(0);
2624222ddf1SHong Zhang }
2634222ddf1SHong Zhang 
2649371c9d4SSatish Balay static PetscErrorCode MatProductNumeric_X_Dense(Mat C) {
2657a3c3d58SStefano Zampini   Mat_Product *product = C->product;
2667a3c3d58SStefano Zampini   Mat          A = product->A, B = product->B;
2677a3c3d58SStefano Zampini   PetscInt     k, K              = B->cmap->N;
2687a3c3d58SStefano Zampini   PetscBool    t = PETSC_TRUE, iscuda = PETSC_FALSE;
2697a3c3d58SStefano Zampini   PetscBool    Bcpu = PETSC_TRUE, Ccpu = PETSC_TRUE;
2707a3c3d58SStefano Zampini   char        *Btype = NULL, *Ctype = NULL;
2717a3c3d58SStefano Zampini 
2727a3c3d58SStefano Zampini   PetscFunctionBegin;
2737a3c3d58SStefano Zampini   switch (product->type) {
2749371c9d4SSatish Balay   case MATPRODUCT_AB: t = PETSC_FALSE;
2759371c9d4SSatish Balay   case MATPRODUCT_AtB: break;
27698921bdaSJacob Faibussowitsch   default: 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);
2777a3c3d58SStefano Zampini   }
2787a3c3d58SStefano Zampini   if (PetscDefined(HAVE_CUDA)) {
2797a3c3d58SStefano Zampini     VecType vtype;
2807a3c3d58SStefano Zampini 
2819566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(A, &vtype));
2829566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(vtype, VECCUDA, &iscuda));
28348a46eb9SPierre Jolivet     if (!iscuda) PetscCall(PetscStrcmp(vtype, VECSEQCUDA, &iscuda));
28448a46eb9SPierre Jolivet     if (!iscuda) PetscCall(PetscStrcmp(vtype, VECMPICUDA, &iscuda));
2857a3c3d58SStefano Zampini     if (iscuda) { /* Make sure we have up-to-date data on the GPU */
2869566063dSJacob Faibussowitsch       PetscCall(PetscStrallocpy(((PetscObject)B)->type_name, &Btype));
2879566063dSJacob Faibussowitsch       PetscCall(PetscStrallocpy(((PetscObject)C)->type_name, &Ctype));
2889566063dSJacob Faibussowitsch       PetscCall(MatConvert(B, MATDENSECUDA, MAT_INPLACE_MATRIX, &B));
2897a3c3d58SStefano Zampini       if (!C->assembled) { /* need to flag the matrix as assembled, otherwise MatConvert will complain */
2909566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
2919566063dSJacob Faibussowitsch         PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
2927a3c3d58SStefano Zampini       }
2939566063dSJacob Faibussowitsch       PetscCall(MatConvert(C, MATDENSECUDA, MAT_INPLACE_MATRIX, &C));
2947a3c3d58SStefano Zampini     } else { /* Make sure we have up-to-date data on the CPU */
2957a3c3d58SStefano Zampini #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_VIENNACL)
2967a3c3d58SStefano Zampini       Bcpu = B->boundtocpu;
2977a3c3d58SStefano Zampini       Ccpu = C->boundtocpu;
2987a3c3d58SStefano Zampini #endif
2999566063dSJacob Faibussowitsch       PetscCall(MatBindToCPU(B, PETSC_TRUE));
3009566063dSJacob Faibussowitsch       PetscCall(MatBindToCPU(C, PETSC_TRUE));
3017a3c3d58SStefano Zampini     }
3027a3c3d58SStefano Zampini   }
3037a3c3d58SStefano Zampini   for (k = 0; k < K; k++) {
3047a3c3d58SStefano Zampini     Vec x, y;
3057a3c3d58SStefano Zampini 
3069566063dSJacob Faibussowitsch     PetscCall(MatDenseGetColumnVecRead(B, k, &x));
3079566063dSJacob Faibussowitsch     PetscCall(MatDenseGetColumnVecWrite(C, k, &y));
3087a3c3d58SStefano Zampini     if (t) {
3099566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(A, x, y));
3107a3c3d58SStefano Zampini     } else {
3119566063dSJacob Faibussowitsch       PetscCall(MatMult(A, x, y));
3127a3c3d58SStefano Zampini     }
3139566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreColumnVecRead(B, k, &x));
3149566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreColumnVecWrite(C, k, &y));
3157a3c3d58SStefano Zampini   }
3169566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
3179566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
3187a3c3d58SStefano Zampini   if (PetscDefined(HAVE_CUDA)) {
3197a3c3d58SStefano Zampini     if (iscuda) {
3209566063dSJacob Faibussowitsch       PetscCall(MatConvert(B, Btype, MAT_INPLACE_MATRIX, &B));
3219566063dSJacob Faibussowitsch       PetscCall(MatConvert(C, Ctype, MAT_INPLACE_MATRIX, &C));
3227a3c3d58SStefano Zampini     } else {
3239566063dSJacob Faibussowitsch       PetscCall(MatBindToCPU(B, Bcpu));
3249566063dSJacob Faibussowitsch       PetscCall(MatBindToCPU(C, Ccpu));
3257a3c3d58SStefano Zampini     }
3267a3c3d58SStefano Zampini   }
3279566063dSJacob Faibussowitsch   PetscCall(PetscFree(Btype));
3289566063dSJacob Faibussowitsch   PetscCall(PetscFree(Ctype));
3297a3c3d58SStefano Zampini   PetscFunctionReturn(0);
3307a3c3d58SStefano Zampini }
3317a3c3d58SStefano Zampini 
3329371c9d4SSatish Balay static PetscErrorCode MatProductSymbolic_X_Dense(Mat C) {
3337a3c3d58SStefano Zampini   Mat_Product *product = C->product;
3347a3c3d58SStefano Zampini   Mat          A = product->A, B = product->B;
3357a3c3d58SStefano Zampini   PetscBool    isdense;
3367a3c3d58SStefano Zampini 
3377a3c3d58SStefano Zampini   PetscFunctionBegin;
3387a3c3d58SStefano Zampini   switch (product->type) {
3399371c9d4SSatish Balay   case MATPRODUCT_AB: PetscCall(MatSetSizes(C, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N)); break;
3409371c9d4SSatish Balay   case MATPRODUCT_AtB: PetscCall(MatSetSizes(C, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N)); break;
34198921bdaSJacob Faibussowitsch   default: 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);
3427a3c3d58SStefano Zampini   }
3439566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)C, &isdense, MATSEQDENSE, MATMPIDENSE, ""));
3447a3c3d58SStefano Zampini   if (!isdense) {
3459566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
3466718818eSStefano Zampini     /* If matrix type of C was not set or not dense, we need to reset the pointer */
3477a3c3d58SStefano Zampini     C->ops->productsymbolic = MatProductSymbolic_X_Dense;
3487a3c3d58SStefano Zampini   }
3496718818eSStefano Zampini   C->ops->productnumeric = MatProductNumeric_X_Dense;
3509566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
3517a3c3d58SStefano Zampini   PetscFunctionReturn(0);
3527a3c3d58SStefano Zampini }
3537a3c3d58SStefano Zampini 
3546718818eSStefano Zampini /* a single driver to query the dispatching */
3559371c9d4SSatish Balay static PetscErrorCode MatProductSetFromOptions_Private(Mat mat) {
3564222ddf1SHong Zhang   Mat_Product      *product = mat->product;
3576718818eSStefano Zampini   PetscInt          Am, An, Bm, Bn, Cm, Cn;
3584222ddf1SHong Zhang   Mat               A = product->A, B = product->B, C = product->C;
3596718818eSStefano Zampini   const char *const Bnames[] = {"B", "R", "P"};
3606718818eSStefano Zampini   const char       *bname;
3614222ddf1SHong Zhang   PetscErrorCode (*fA)(Mat);
3624222ddf1SHong Zhang   PetscErrorCode (*fB)(Mat);
3634222ddf1SHong Zhang   PetscErrorCode (*fC)(Mat);
3644222ddf1SHong Zhang   PetscErrorCode (*f)(Mat) = NULL;
3654222ddf1SHong Zhang 
3664222ddf1SHong Zhang   PetscFunctionBegin;
3676718818eSStefano Zampini   mat->ops->productsymbolic = NULL;
3686718818eSStefano Zampini   mat->ops->productnumeric  = NULL;
3696718818eSStefano Zampini   if (product->type == MATPRODUCT_UNSPECIFIED) PetscFunctionReturn(0);
37028b400f6SJacob Faibussowitsch   PetscCheck(A, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing A mat");
37128b400f6SJacob Faibussowitsch   PetscCheck(B, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing B mat");
372072cda71SBarry Smith   PetscCheck(product->type != MATPRODUCT_ABC || C, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing C mat");
3736718818eSStefano Zampini   if (product->type != MATPRODUCT_ABC) C = NULL; /* do not use C if not needed */
3746718818eSStefano Zampini   if (product->type == MATPRODUCT_RARt) bname = Bnames[1];
3756718818eSStefano Zampini   else if (product->type == MATPRODUCT_PtAP) bname = Bnames[2];
3766718818eSStefano Zampini   else bname = Bnames[0];
3776718818eSStefano Zampini 
3786718818eSStefano Zampini   /* Check matrices sizes */
3796718818eSStefano Zampini   Am = A->rmap->N;
3806718818eSStefano Zampini   An = A->cmap->N;
3816718818eSStefano Zampini   Bm = B->rmap->N;
3826718818eSStefano Zampini   Bn = B->cmap->N;
3836718818eSStefano Zampini   Cm = C ? C->rmap->N : 0;
3846718818eSStefano Zampini   Cn = C ? C->cmap->N : 0;
3859371c9d4SSatish Balay   if (product->type == MATPRODUCT_RARt || product->type == MATPRODUCT_ABt) {
3869371c9d4SSatish Balay     PetscInt t = Bn;
3879371c9d4SSatish Balay     Bn         = Bm;
3889371c9d4SSatish Balay     Bm         = t;
3899371c9d4SSatish Balay   }
3909371c9d4SSatish Balay   if (product->type == MATPRODUCT_AtB) {
3919371c9d4SSatish Balay     PetscInt t = An;
3929371c9d4SSatish Balay     An         = Am;
3939371c9d4SSatish Balay     Am         = t;
3949371c9d4SSatish Balay   }
3959371c9d4SSatish Balay   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,
3969371c9d4SSatish Balay              MatProductTypes[product->type], A->rmap->N, A->cmap->N, bname, B->rmap->N, B->cmap->N);
3979371c9d4SSatish Balay   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,
3989371c9d4SSatish Balay              MatProductTypes[product->type], B->rmap->N, B->cmap->N, Cm, Cn);
3994222ddf1SHong Zhang 
4004222ddf1SHong Zhang   fA = A->ops->productsetfromoptions;
4014222ddf1SHong Zhang   fB = B->ops->productsetfromoptions;
4026718818eSStefano Zampini   fC = C ? C->ops->productsetfromoptions : fA;
4036718818eSStefano Zampini   if (C) {
4049566063dSJacob Faibussowitsch     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));
4056718818eSStefano Zampini   } else {
4069566063dSJacob Faibussowitsch     PetscCall(PetscInfo(mat, "MatProductType %s for A %s, %s %s\n", MatProductTypes[product->type], ((PetscObject)A)->type_name, bname, ((PetscObject)B)->type_name));
4076718818eSStefano Zampini   }
4084222ddf1SHong Zhang   if (fA == fB && fA == fC && fA) {
4099566063dSJacob Faibussowitsch     PetscCall(PetscInfo(mat, "  matching op\n"));
4109566063dSJacob Faibussowitsch     PetscCall((*fA)(mat));
4118d7b260cSStefano Zampini   }
4128d7b260cSStefano Zampini   /* We may have found f but it did not succeed */
4138d7b260cSStefano Zampini   if (!mat->ops->productsymbolic) { /* query MatProductSetFromOptions_Atype_Btype_Ctype */
4144222ddf1SHong Zhang     char mtypes[256];
4159566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(mtypes, "MatProductSetFromOptions_", sizeof(mtypes)));
4169566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(mtypes, ((PetscObject)A)->type_name, sizeof(mtypes)));
4179566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(mtypes, "_", sizeof(mtypes)));
4189566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(mtypes, ((PetscObject)B)->type_name, sizeof(mtypes)));
4196718818eSStefano Zampini     if (C) {
4209566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(mtypes, "_", sizeof(mtypes)));
4219566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(mtypes, ((PetscObject)C)->type_name, sizeof(mtypes)));
4226718818eSStefano Zampini     }
4239566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(mtypes, "_C", sizeof(mtypes)));
4244222ddf1SHong Zhang 
4259566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f));
4269566063dSJacob Faibussowitsch     PetscCall(PetscInfo(mat, "  querying %s from A? %p\n", mtypes, f));
4274222ddf1SHong Zhang     if (!f) {
4289566063dSJacob Faibussowitsch       PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f));
4299566063dSJacob Faibussowitsch       PetscCall(PetscInfo(mat, "  querying %s from %s? %p\n", mtypes, bname, f));
4304222ddf1SHong Zhang     }
4316718818eSStefano Zampini     if (!f && C) {
4329566063dSJacob Faibussowitsch       PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f));
4339566063dSJacob Faibussowitsch       PetscCall(PetscInfo(mat, "  querying %s from C? %p\n", mtypes, f));
4344222ddf1SHong Zhang     }
4359566063dSJacob Faibussowitsch     if (f) PetscCall((*f)(mat));
4366718818eSStefano Zampini 
4376718818eSStefano Zampini     /* We may have found f but it did not succeed */
438*013e2dc7SBarry Smith     /* some matrices (i.e. MATTRANSPOSEVIRTUAL, MATSHELL constructed from MatConvert), knows what to do with their inner matrices */
4396718818eSStefano Zampini     if (!mat->ops->productsymbolic) {
4409566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(mtypes, "MatProductSetFromOptions_anytype_C", sizeof(mtypes)));
4419566063dSJacob Faibussowitsch       PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f));
4429566063dSJacob Faibussowitsch       PetscCall(PetscInfo(mat, "  querying %s from A? %p\n", mtypes, f));
4436718818eSStefano Zampini       if (!f) {
4449566063dSJacob Faibussowitsch         PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f));
4459566063dSJacob Faibussowitsch         PetscCall(PetscInfo(mat, "  querying %s from %s? %p\n", mtypes, bname, f));
4466718818eSStefano Zampini       }
4476718818eSStefano Zampini       if (!f && C) {
4489566063dSJacob Faibussowitsch         PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f));
4499566063dSJacob Faibussowitsch         PetscCall(PetscInfo(mat, "  querying %s from C? %p\n", mtypes, f));
4506718818eSStefano Zampini       }
4516718818eSStefano Zampini     }
4529566063dSJacob Faibussowitsch     if (f) PetscCall((*f)(mat));
4534222ddf1SHong Zhang   }
4544222ddf1SHong Zhang 
4556718818eSStefano Zampini   /* We may have found f but it did not succeed */
4566718818eSStefano Zampini   if (!mat->ops->productsymbolic) {
4576718818eSStefano Zampini     /* we can still compute the product if B is of type dense */
4586718818eSStefano Zampini     if (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB) {
4596718818eSStefano Zampini       PetscBool isdense;
4606718818eSStefano Zampini 
4619566063dSJacob Faibussowitsch       PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)B, &isdense, MATSEQDENSE, MATMPIDENSE, ""));
4626718818eSStefano Zampini       if (isdense) {
4636718818eSStefano Zampini         mat->ops->productsymbolic = MatProductSymbolic_X_Dense;
4649566063dSJacob Faibussowitsch         PetscCall(PetscInfo(mat, "  using basic looping over columns of a dense matrix\n"));
4656718818eSStefano Zampini       }
4665415d71bSStefano Zampini     } else if (product->type != MATPRODUCT_ABt) { /* use MatProductSymbolic/Numeric_Unsafe() for triple products only */
4676718818eSStefano Zampini       /*
4686718818eSStefano Zampini          TODO: this should be changed to a proper setfromoptions, not setting the symbolic pointer here, because we do not know if
4698d7b260cSStefano Zampini                the combination will succeed. In order to be sure, we need MatProductGetProductType to return the type of the result
4706718818eSStefano Zampini                before computing the symbolic phase
4716718818eSStefano Zampini       */
4729566063dSJacob Faibussowitsch       PetscCall(PetscInfo(mat, "  symbolic product not supported, using MatProductSymbolic_Unsafe() implementation\n"));
4735415d71bSStefano Zampini       mat->ops->productsymbolic = MatProductSymbolic_Unsafe;
4744222ddf1SHong Zhang     }
4756718818eSStefano Zampini   }
47648a46eb9SPierre Jolivet   if (!mat->ops->productsymbolic) PetscCall(PetscInfo(mat, "  symbolic product is not supported\n"));
4774222ddf1SHong Zhang   PetscFunctionReturn(0);
4784222ddf1SHong Zhang }
4794222ddf1SHong Zhang 
4804222ddf1SHong Zhang /*@C
48111a5261eSBarry Smith    MatProductSetFromOptions - Sets the options for the computation of a matrix-matrix product where the type, the algorithm etc are determined from the options database.
4824222ddf1SHong Zhang 
4834222ddf1SHong Zhang    Logically Collective on Mat
4844222ddf1SHong Zhang 
4854222ddf1SHong Zhang    Input Parameter:
4864222ddf1SHong Zhang .  mat - the matrix
4874222ddf1SHong Zhang 
4886718818eSStefano Zampini    Options Database Keys:
489f5368d60SBarry Smith .    -mat_product_clear - Clear intermediate data structures after `MatProductNumeric()` has been called
4904222ddf1SHong Zhang 
4916718818eSStefano Zampini    Level: intermediate
4926718818eSStefano Zampini 
493f5368d60SBarry Smith .seealso: `MatSetFromOptions()`, `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductNumeric()`, `MatProductSetType()`, `MatProductSetAlgorithm()`
4944222ddf1SHong Zhang @*/
4959371c9d4SSatish Balay PetscErrorCode MatProductSetFromOptions(Mat mat) {
4964222ddf1SHong Zhang   PetscFunctionBegin;
4974222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4986718818eSStefano Zampini   MatCheckProduct(mat, 1);
49928b400f6SJacob Faibussowitsch   PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot call MatProductSetFromOptions with already present data");
500d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)mat);
5019566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-mat_product_clear", "Clear intermediate data structures after MatProductNumeric() has been called", "MatProductClear", mat->product->clear, &mat->product->clear, NULL));
5029566063dSJacob Faibussowitsch   PetscCall(PetscOptionsDeprecated("-mat_freeintermediatedatastructures", "-mat_product_clear", "3.13", "Or call MatProductClear() after MatProductNumeric()"));
503d0609cedSBarry Smith   PetscOptionsEnd();
5049566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions_Private(mat));
50528b400f6SJacob Faibussowitsch   PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing product after setup phase");
5066718818eSStefano Zampini   PetscFunctionReturn(0);
5076718818eSStefano Zampini }
5086718818eSStefano Zampini 
5096718818eSStefano Zampini /*@C
51011a5261eSBarry Smith    MatProductView - View the private `Mat_Product` algorithm object within a matrix
5116718818eSStefano Zampini 
51211a5261eSBarry Smith    Logically Collective on mat
5136718818eSStefano Zampini 
5146718818eSStefano Zampini    Input Parameter:
515f5368d60SBarry Smith .  mat - the matrix obtained with `MatProductCreate()` or `MatProductCreateWithMat()`
5166718818eSStefano Zampini 
5176718818eSStefano Zampini    Level: intermediate
5186718818eSStefano Zampini 
51911a5261eSBarry Smith .seealso: `MatProductSetFromOptions()`, `MatView()`, `MatProductCreate()`, `MatProductCreateWithMat()`
5206718818eSStefano Zampini @*/
5219371c9d4SSatish Balay PetscErrorCode MatProductView(Mat mat, PetscViewer viewer) {
5226718818eSStefano Zampini   PetscFunctionBegin;
5236718818eSStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5246718818eSStefano Zampini   if (!mat->product) PetscFunctionReturn(0);
5259566063dSJacob Faibussowitsch   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer));
5266718818eSStefano Zampini   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
5276718818eSStefano Zampini   PetscCheckSameComm(mat, 1, viewer, 2);
5281baa6e33SBarry Smith   if (mat->product->view) PetscCall((*mat->product->view)(mat, viewer));
5294222ddf1SHong Zhang   PetscFunctionReturn(0);
5304222ddf1SHong Zhang }
5314222ddf1SHong Zhang 
5324222ddf1SHong Zhang /* ----------------------------------------------- */
5336718818eSStefano Zampini /* these are basic implementations relying on the old function pointers
5346718818eSStefano Zampini  * they are dangerous and should be removed in the future */
5359371c9d4SSatish Balay PetscErrorCode MatProductNumeric_AB(Mat mat) {
5364222ddf1SHong Zhang   Mat_Product *product = mat->product;
5374222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
5384222ddf1SHong Zhang 
5394222ddf1SHong Zhang   PetscFunctionBegin;
5409566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmultnumeric)(A, B, mat));
5414222ddf1SHong Zhang   PetscFunctionReturn(0);
5424222ddf1SHong Zhang }
5434222ddf1SHong Zhang 
5449371c9d4SSatish Balay PetscErrorCode MatProductNumeric_AtB(Mat mat) {
5454222ddf1SHong Zhang   Mat_Product *product = mat->product;
5464222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
5474222ddf1SHong Zhang 
5484222ddf1SHong Zhang   PetscFunctionBegin;
5499566063dSJacob Faibussowitsch   PetscCall((*mat->ops->transposematmultnumeric)(A, B, mat));
5504222ddf1SHong Zhang   PetscFunctionReturn(0);
5514222ddf1SHong Zhang }
5524222ddf1SHong Zhang 
5539371c9d4SSatish Balay PetscErrorCode MatProductNumeric_ABt(Mat mat) {
5544222ddf1SHong Zhang   Mat_Product *product = mat->product;
5554222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
5564222ddf1SHong Zhang 
5574222ddf1SHong Zhang   PetscFunctionBegin;
5589566063dSJacob Faibussowitsch   PetscCall((*mat->ops->mattransposemultnumeric)(A, B, mat));
5594222ddf1SHong Zhang   PetscFunctionReturn(0);
5604222ddf1SHong Zhang }
5614222ddf1SHong Zhang 
5629371c9d4SSatish Balay PetscErrorCode MatProductNumeric_PtAP(Mat mat) {
5634222ddf1SHong Zhang   Mat_Product *product = mat->product;
5644222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
5654222ddf1SHong Zhang 
5664222ddf1SHong Zhang   PetscFunctionBegin;
5679566063dSJacob Faibussowitsch   PetscCall((*mat->ops->ptapnumeric)(A, B, mat));
5684222ddf1SHong Zhang   PetscFunctionReturn(0);
5694222ddf1SHong Zhang }
5704222ddf1SHong Zhang 
5719371c9d4SSatish Balay PetscErrorCode MatProductNumeric_RARt(Mat mat) {
5724222ddf1SHong Zhang   Mat_Product *product = mat->product;
5734222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
5744222ddf1SHong Zhang 
5754222ddf1SHong Zhang   PetscFunctionBegin;
5769566063dSJacob Faibussowitsch   PetscCall((*mat->ops->rartnumeric)(A, B, mat));
5774222ddf1SHong Zhang   PetscFunctionReturn(0);
5784222ddf1SHong Zhang }
5794222ddf1SHong Zhang 
5809371c9d4SSatish Balay PetscErrorCode MatProductNumeric_ABC(Mat mat) {
5814222ddf1SHong Zhang   Mat_Product *product = mat->product;
5824222ddf1SHong Zhang   Mat          A = product->A, B = product->B, C = product->C;
5834222ddf1SHong Zhang 
5844222ddf1SHong Zhang   PetscFunctionBegin;
5859566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmatmultnumeric)(A, B, C, mat));
5864222ddf1SHong Zhang   PetscFunctionReturn(0);
5874222ddf1SHong Zhang }
5884222ddf1SHong Zhang 
5896718818eSStefano Zampini /* ----------------------------------------------- */
5906718818eSStefano Zampini 
5914222ddf1SHong Zhang /*@
59211a5261eSBarry Smith    MatProductNumeric - Compute a matrix product with numerical values.
5934222ddf1SHong Zhang 
59411a5261eSBarry Smith    Collective on mat
5954222ddf1SHong Zhang 
5966718818eSStefano Zampini    Input/Output Parameter:
5976718818eSStefano Zampini .  mat - the matrix holding the product
5984222ddf1SHong Zhang 
5994222ddf1SHong Zhang    Level: intermediate
6004222ddf1SHong Zhang 
60111a5261eSBarry Smith    Note:
60211a5261eSBarry Smith    `MatProductSymbolic()` must have been called on mat before calling this function
6036718818eSStefano Zampini 
60411a5261eSBarry Smith .seealso: `MatProductSetAlgorithm()`, `MatProductSetType()`, `MatProductCreate()`, `MatSetType()`, `MatProductSymbolic()`
6054222ddf1SHong Zhang @*/
6069371c9d4SSatish Balay PetscErrorCode MatProductNumeric(Mat mat) {
607e017e560SStefano Zampini   PetscLogEvent eventtype = -1;
6082e105a96SStefano Zampini   PetscBool     missing   = PETSC_FALSE;
6094222ddf1SHong Zhang 
6104222ddf1SHong Zhang   PetscFunctionBegin;
6114222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6126718818eSStefano Zampini   MatCheckProduct(mat, 1);
613e017e560SStefano Zampini   switch (mat->product->type) {
6149371c9d4SSatish Balay   case MATPRODUCT_AB: eventtype = MAT_MatMultNumeric; break;
6159371c9d4SSatish Balay   case MATPRODUCT_AtB: eventtype = MAT_TransposeMatMultNumeric; break;
6169371c9d4SSatish Balay   case MATPRODUCT_ABt: eventtype = MAT_MatTransposeMultNumeric; break;
6179371c9d4SSatish Balay   case MATPRODUCT_PtAP: eventtype = MAT_PtAPNumeric; break;
6189371c9d4SSatish Balay   case MATPRODUCT_RARt: eventtype = MAT_RARtNumeric; break;
6199371c9d4SSatish Balay   case MATPRODUCT_ABC: eventtype = MAT_MatMatMultNumeric; break;
62098921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]);
621e017e560SStefano Zampini   }
6228d7b260cSStefano Zampini 
6234222ddf1SHong Zhang   if (mat->ops->productnumeric) {
6249566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0));
625dbbe0bcdSBarry Smith     PetscUseTypeMethod(mat, productnumeric);
6269566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0));
6272e105a96SStefano Zampini   } else missing = PETSC_TRUE;
6282e105a96SStefano Zampini 
6292e105a96SStefano Zampini   if (missing || !mat->product) {
6302e105a96SStefano Zampini     char errstr[256];
6312e105a96SStefano Zampini 
6322e105a96SStefano Zampini     if (mat->product->type == MATPRODUCT_ABC) {
6339566063dSJacob Faibussowitsch       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));
6342e105a96SStefano Zampini     } else {
6359566063dSJacob Faibussowitsch       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));
6362e105a96SStefano Zampini     }
63728b400f6SJacob Faibussowitsch     PetscCheck(!missing, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified numeric phase for product %s", errstr);
63828b400f6SJacob Faibussowitsch     PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after symbolic phase for product %s", errstr);
6392e105a96SStefano Zampini   }
6402e105a96SStefano Zampini 
6411baa6e33SBarry Smith   if (mat->product->clear) PetscCall(MatProductClear(mat));
6429566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6434222ddf1SHong Zhang   PetscFunctionReturn(0);
6444222ddf1SHong Zhang }
6454222ddf1SHong Zhang 
6464222ddf1SHong Zhang /* ----------------------------------------------- */
6476718818eSStefano Zampini /* these are basic implementations relying on the old function pointers
6486718818eSStefano Zampini  * they are dangerous and should be removed in the future */
6499371c9d4SSatish Balay PetscErrorCode MatProductSymbolic_AB(Mat mat) {
6504222ddf1SHong Zhang   Mat_Product *product = mat->product;
6514222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
6524222ddf1SHong Zhang 
6534222ddf1SHong Zhang   PetscFunctionBegin;
6549566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmultsymbolic)(A, B, product->fill, mat));
6554222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_AB;
6564222ddf1SHong Zhang   PetscFunctionReturn(0);
6574222ddf1SHong Zhang }
6584222ddf1SHong Zhang 
6599371c9d4SSatish Balay PetscErrorCode MatProductSymbolic_AtB(Mat mat) {
6604222ddf1SHong Zhang   Mat_Product *product = mat->product;
6614222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
6624222ddf1SHong Zhang 
6634222ddf1SHong Zhang   PetscFunctionBegin;
6649566063dSJacob Faibussowitsch   PetscCall((*mat->ops->transposematmultsymbolic)(A, B, product->fill, mat));
6654222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_AtB;
6664222ddf1SHong Zhang   PetscFunctionReturn(0);
6674222ddf1SHong Zhang }
6684222ddf1SHong Zhang 
6699371c9d4SSatish Balay PetscErrorCode MatProductSymbolic_ABt(Mat mat) {
6704222ddf1SHong Zhang   Mat_Product *product = mat->product;
6714222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
6724222ddf1SHong Zhang 
6734222ddf1SHong Zhang   PetscFunctionBegin;
6749566063dSJacob Faibussowitsch   PetscCall((*mat->ops->mattransposemultsymbolic)(A, B, product->fill, mat));
6754222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_ABt;
6764222ddf1SHong Zhang   PetscFunctionReturn(0);
6774222ddf1SHong Zhang }
6784222ddf1SHong Zhang 
6799371c9d4SSatish Balay PetscErrorCode MatProductSymbolic_ABC(Mat mat) {
6804222ddf1SHong Zhang   Mat_Product *product = mat->product;
6814222ddf1SHong Zhang   Mat          A = product->A, B = product->B, C = product->C;
6824222ddf1SHong Zhang 
6834222ddf1SHong Zhang   PetscFunctionBegin;
6849566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmatmultsymbolic)(A, B, C, product->fill, mat));
6854222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_ABC;
6864222ddf1SHong Zhang   PetscFunctionReturn(0);
6874222ddf1SHong Zhang }
6884222ddf1SHong Zhang 
6896718818eSStefano Zampini /* ----------------------------------------------- */
6906718818eSStefano Zampini 
6914222ddf1SHong Zhang /*@
692f5368d60SBarry Smith    MatProductSymbolic - Perform the symbolic portion of a matrix product, this creates a data structure for use with the numerical product done with
693f5368d60SBarry Smith   `MatProductNumeric()`
6944222ddf1SHong Zhang 
69511a5261eSBarry Smith    Collective on mat
6964222ddf1SHong Zhang 
6976718818eSStefano Zampini    Input/Output Parameter:
6984222ddf1SHong Zhang .  mat - the matrix to hold a product
6994222ddf1SHong Zhang 
7004222ddf1SHong Zhang    Level: intermediate
7014222ddf1SHong Zhang 
70211a5261eSBarry Smith    Note:
70311a5261eSBarry Smith    `MatProductSetFromOptions()` must have been called on mat before calling this function
7046718818eSStefano Zampini 
705db781477SPatrick Sanan .seealso: `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductSetFromOptions()`, `MatProductNumeric()`, `MatProductSetType()`, `MatProductSetAlgorithm()`
7064222ddf1SHong Zhang @*/
7079371c9d4SSatish Balay PetscErrorCode MatProductSymbolic(Mat mat) {
7084222ddf1SHong Zhang   PetscLogEvent eventtype = -1;
7092e105a96SStefano Zampini   PetscBool     missing   = PETSC_FALSE;
7104222ddf1SHong Zhang 
7114222ddf1SHong Zhang   PetscFunctionBegin;
7124222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7136718818eSStefano Zampini   MatCheckProduct(mat, 1);
71428b400f6SJacob Faibussowitsch   PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot run symbolic phase. Product data not empty");
7156718818eSStefano Zampini   switch (mat->product->type) {
7169371c9d4SSatish Balay   case MATPRODUCT_AB: eventtype = MAT_MatMultSymbolic; break;
7179371c9d4SSatish Balay   case MATPRODUCT_AtB: eventtype = MAT_TransposeMatMultSymbolic; break;
7189371c9d4SSatish Balay   case MATPRODUCT_ABt: eventtype = MAT_MatTransposeMultSymbolic; break;
7199371c9d4SSatish Balay   case MATPRODUCT_PtAP: eventtype = MAT_PtAPSymbolic; break;
7209371c9d4SSatish Balay   case MATPRODUCT_RARt: eventtype = MAT_RARtSymbolic; break;
7219371c9d4SSatish Balay   case MATPRODUCT_ABC: eventtype = MAT_MatMatMultSymbolic; break;
72298921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]);
7234222ddf1SHong Zhang   }
7246718818eSStefano Zampini   mat->ops->productnumeric = NULL;
7254222ddf1SHong Zhang   if (mat->ops->productsymbolic) {
7269566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0));
727dbbe0bcdSBarry Smith     PetscUseTypeMethod(mat, productsymbolic);
7289566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0));
7292e105a96SStefano Zampini   } else missing = PETSC_TRUE;
7302e105a96SStefano Zampini 
7312e105a96SStefano Zampini   if (missing || !mat->product || !mat->ops->productnumeric) {
7322e105a96SStefano Zampini     char errstr[256];
7332e105a96SStefano Zampini 
7342e105a96SStefano Zampini     if (mat->product->type == MATPRODUCT_ABC) {
7359566063dSJacob Faibussowitsch       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));
7362e105a96SStefano Zampini     } else {
7379566063dSJacob Faibussowitsch       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));
7382e105a96SStefano Zampini     }
73928b400f6SJacob Faibussowitsch     PetscCheck(!missing, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified symbolic phase for product %s. Call MatProductSetFromOptions() first", errstr);
74028b400f6SJacob Faibussowitsch     PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after symbolic phase for product %s", errstr);
7412e105a96SStefano Zampini   }
7424222ddf1SHong Zhang   PetscFunctionReturn(0);
7434222ddf1SHong Zhang }
7444222ddf1SHong Zhang 
7454222ddf1SHong Zhang /*@
7464222ddf1SHong Zhang    MatProductSetFill - Set an expected fill of the matrix product.
7474222ddf1SHong Zhang 
7484222ddf1SHong Zhang    Collective on Mat
7494222ddf1SHong Zhang 
7504222ddf1SHong Zhang    Input Parameters:
75111a5261eSBarry Smith +  mat - the matrix product result matrix
752f5368d60SBarry Smith -  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 value is not used.
7534222ddf1SHong Zhang 
7544222ddf1SHong Zhang    Level: intermediate
7554222ddf1SHong Zhang 
75611a5261eSBarry Smith .seealso: `MatProductSetFromOptions()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()`
7574222ddf1SHong Zhang @*/
7589371c9d4SSatish Balay PetscErrorCode MatProductSetFill(Mat mat, PetscReal fill) {
7594222ddf1SHong Zhang   PetscFunctionBegin;
7604222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7616718818eSStefano Zampini   MatCheckProduct(mat, 1);
7626718818eSStefano Zampini   if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) mat->product->fill = 2.0;
7636718818eSStefano Zampini   else mat->product->fill = fill;
7644222ddf1SHong Zhang   PetscFunctionReturn(0);
7654222ddf1SHong Zhang }
7664222ddf1SHong Zhang 
7674222ddf1SHong Zhang /*@
768f5368d60SBarry Smith    MatProductSetAlgorithm - Requests a particular algorithm for a matrix product computation that will perform to compute the given matrix
7694222ddf1SHong Zhang 
77011a5261eSBarry Smith    Collective on mat
7714222ddf1SHong Zhang 
7724222ddf1SHong Zhang    Input Parameters:
7734222ddf1SHong Zhang +  mat - the matrix product
774f5368d60SBarry Smith -  alg - particular implementation algorithm of the matrix product, e.g., `MATPRODUCTALGORITHMDEFAULT`.
7753e662e0bSHong Zhang 
7763e662e0bSHong Zhang    Options Database Key:
7773e662e0bSHong Zhang .  -mat_product_algorithm <algorithm> - Sets the algorithm; use -help for a list
7783e662e0bSHong Zhang     of available algorithms (for instance, scalable, outerproduct, etc.)
7794222ddf1SHong Zhang 
7804222ddf1SHong Zhang    Level: intermediate
7814222ddf1SHong Zhang 
78211a5261eSBarry Smith .seealso: `MatProductSetType()`, `MatProductSetFill()`, `MatProductCreate()`, `MatProductAlgorithm`, `MatProductType`
7834222ddf1SHong Zhang @*/
7849371c9d4SSatish Balay PetscErrorCode MatProductSetAlgorithm(Mat mat, MatProductAlgorithm alg) {
7854222ddf1SHong Zhang   PetscFunctionBegin;
7864222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7876718818eSStefano Zampini   MatCheckProduct(mat, 1);
7889566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->product->alg));
7899566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(alg, &mat->product->alg));
7904222ddf1SHong Zhang   PetscFunctionReturn(0);
7914222ddf1SHong Zhang }
7924222ddf1SHong Zhang 
7934222ddf1SHong Zhang /*@
794f5368d60SBarry Smith    MatProductSetType - Sets a particular matrix product type to be used to compute the given matrix
7954222ddf1SHong Zhang 
79611a5261eSBarry Smith    Collective on mat
7974222ddf1SHong Zhang 
7984222ddf1SHong Zhang    Input Parameters:
7994222ddf1SHong Zhang +  mat - the matrix
800f5368d60SBarry Smith -  productype   - matrix product type, e.g., `MATPRODUCT_AB`,`MATPRODUCT_AtB`,`MATPRODUCT_ABt`,`MATPRODUCT_PtAP`,`MATPRODUCT_RARt`,`MATPRODUCT_ABC`.
8014222ddf1SHong Zhang 
8024222ddf1SHong Zhang    Level: intermediate
8034222ddf1SHong Zhang 
804f5368d60SBarry Smith    Note:
80511a5261eSBarry Smith    The small t represents the transpose operation.
806f5368d60SBarry Smith 
80711a5261eSBarry Smith .seealso: `MatProductCreate()`, `MatProductType`, `MatProductType`,
80811a5261eSBarry Smith           `MATPRODUCT_AB`, `MATPRODUCT_AtB`, `MATPRODUCT_ABt`, `MATPRODUCT_PtAP`, `MATPRODUCT_RARt`, `MATPRODUCT_ABC`
8094222ddf1SHong Zhang @*/
8109371c9d4SSatish Balay PetscErrorCode MatProductSetType(Mat mat, MatProductType productype) {
8114222ddf1SHong Zhang   PetscFunctionBegin;
8124222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8136718818eSStefano Zampini   MatCheckProduct(mat, 1);
8147a3c3d58SStefano Zampini   PetscValidLogicalCollectiveEnum(mat, productype, 2);
8156718818eSStefano Zampini   if (productype != mat->product->type) {
8161baa6e33SBarry Smith     if (mat->product->destroy) PetscCall((*mat->product->destroy)(mat->product->data));
8176718818eSStefano Zampini     mat->product->destroy     = NULL;
8186718818eSStefano Zampini     mat->product->data        = NULL;
8196718818eSStefano Zampini     mat->ops->productsymbolic = NULL;
8206718818eSStefano Zampini     mat->ops->productnumeric  = NULL;
8216718818eSStefano Zampini   }
8226718818eSStefano Zampini   mat->product->type = productype;
8234222ddf1SHong Zhang   PetscFunctionReturn(0);
8244222ddf1SHong Zhang }
8254222ddf1SHong Zhang 
8264417c5e8SHong Zhang /*@
82711a5261eSBarry Smith    MatProductClear - Clears matrix product internal datastructures.
8284417c5e8SHong Zhang 
82911a5261eSBarry Smith    Collective on mat
8304417c5e8SHong Zhang 
8314417c5e8SHong Zhang    Input Parameters:
8324417c5e8SHong Zhang .  mat - the product matrix
8334417c5e8SHong Zhang 
8344417c5e8SHong Zhang    Level: intermediate
8356718818eSStefano Zampini 
836f5368d60SBarry Smith    Notes:
837f5368d60SBarry Smith    This function should be called to remove any intermediate data used to compute the matrix to free up memory.
838f5368d60SBarry Smith 
83911a5261eSBarry Smith    After having called this function, matrix-matrix operations can no longer be used on mat
840f5368d60SBarry Smith 
841f5368d60SBarry Smith .seealso: `MatProductCreate()`
8424417c5e8SHong Zhang @*/
8439371c9d4SSatish Balay PetscErrorCode MatProductClear(Mat mat) {
8444417c5e8SHong Zhang   Mat_Product *product = mat->product;
8454417c5e8SHong Zhang 
8464417c5e8SHong Zhang   PetscFunctionBegin;
8477a3c3d58SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8484417c5e8SHong Zhang   if (product) {
8499566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->A));
8509566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->B));
8519566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->C));
8529566063dSJacob Faibussowitsch     PetscCall(PetscFree(product->alg));
8539566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->Dwork));
8541baa6e33SBarry Smith     if (product->destroy) PetscCall((*product->destroy)(product->data));
8556718818eSStefano Zampini   }
8569566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->product));
8576718818eSStefano Zampini   mat->ops->productsymbolic = NULL;
8586718818eSStefano Zampini   mat->ops->productnumeric  = NULL;
8594417c5e8SHong Zhang   PetscFunctionReturn(0);
8604417c5e8SHong Zhang }
8614417c5e8SHong Zhang 
8624222ddf1SHong Zhang /* Create a supporting struct and attach it to the matrix product */
8639371c9d4SSatish Balay PetscErrorCode MatProductCreate_Private(Mat A, Mat B, Mat C, Mat D) {
8644222ddf1SHong Zhang   Mat_Product *product = NULL;
8654222ddf1SHong Zhang 
8664222ddf1SHong Zhang   PetscFunctionBegin;
8676718818eSStefano Zampini   PetscValidHeaderSpecific(D, MAT_CLASSID, 4);
86828b400f6SJacob Faibussowitsch   PetscCheck(!D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product already present");
8699566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(D, &product));
8704222ddf1SHong Zhang   product->A        = A;
8714222ddf1SHong Zhang   product->B        = B;
8724222ddf1SHong Zhang   product->C        = C;
8736718818eSStefano Zampini   product->type     = MATPRODUCT_UNSPECIFIED;
8744222ddf1SHong Zhang   product->Dwork    = NULL;
8754222ddf1SHong Zhang   product->api_user = PETSC_FALSE;
8766718818eSStefano Zampini   product->clear    = PETSC_FALSE;
8774222ddf1SHong Zhang   D->product        = product;
8784417c5e8SHong Zhang 
8799566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(D, MATPRODUCTALGORITHMDEFAULT));
8809566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(D, PETSC_DEFAULT));
8817a3c3d58SStefano Zampini 
8829566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)A));
8839566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)B));
8849566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)C));
8854222ddf1SHong Zhang   PetscFunctionReturn(0);
8864222ddf1SHong Zhang }
8874222ddf1SHong Zhang 
8884222ddf1SHong Zhang /*@
889f5368d60SBarry Smith    MatProductCreateWithMat - Setup a given matrix as a matrix product of other matrices
8904222ddf1SHong Zhang 
8914222ddf1SHong Zhang    Collective on Mat
8924222ddf1SHong Zhang 
8934222ddf1SHong Zhang    Input Parameters:
8944222ddf1SHong Zhang +  A - the first matrix
8954222ddf1SHong Zhang .  B - the second matrix
8964222ddf1SHong Zhang .  C - the third matrix (optional)
89711a5261eSBarry Smith -  D - the matrix which will be used to hold the product
8984222ddf1SHong Zhang 
8994222ddf1SHong Zhang    Output Parameters:
9004222ddf1SHong Zhang .  D - the product matrix
9014222ddf1SHong Zhang 
9026718818eSStefano Zampini    Notes:
903f5368d60SBarry Smith    Use `MatProductCreate()` if the matrix you wish computed (the D matrix) does not already exist
904f5368d60SBarry Smith 
905f5368d60SBarry Smith    See `MatProductCreate()` for details on the usage of the MatProduct routines
906f5368d60SBarry Smith 
907f5368d60SBarry Smith    Any product data currently attached to D will be cleared
9086718818eSStefano Zampini 
9094222ddf1SHong Zhang    Level: intermediate
9104222ddf1SHong Zhang 
911db781477SPatrick Sanan .seealso: `MatProductCreate()`, `MatProductClear()`
9124222ddf1SHong Zhang @*/
9139371c9d4SSatish Balay PetscErrorCode MatProductCreateWithMat(Mat A, Mat B, Mat C, Mat D) {
9144222ddf1SHong Zhang   PetscFunctionBegin;
9154222ddf1SHong Zhang   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9164222ddf1SHong Zhang   PetscValidType(A, 1);
9174222ddf1SHong Zhang   MatCheckPreallocated(A, 1);
91828b400f6SJacob Faibussowitsch   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
91928b400f6SJacob Faibussowitsch   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9204222ddf1SHong Zhang 
9214222ddf1SHong Zhang   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
9224222ddf1SHong Zhang   PetscValidType(B, 2);
9234222ddf1SHong Zhang   MatCheckPreallocated(B, 2);
92428b400f6SJacob Faibussowitsch   PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
92528b400f6SJacob Faibussowitsch   PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9264222ddf1SHong Zhang 
9274222ddf1SHong Zhang   if (C) {
9284222ddf1SHong Zhang     PetscValidHeaderSpecific(C, MAT_CLASSID, 3);
9294222ddf1SHong Zhang     PetscValidType(C, 3);
9304222ddf1SHong Zhang     MatCheckPreallocated(C, 3);
93128b400f6SJacob Faibussowitsch     PetscCheck(C->assembled, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
93228b400f6SJacob Faibussowitsch     PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9334222ddf1SHong Zhang   }
9344222ddf1SHong Zhang 
9354222ddf1SHong Zhang   PetscValidHeaderSpecific(D, MAT_CLASSID, 4);
9364222ddf1SHong Zhang   PetscValidType(D, 4);
9374222ddf1SHong Zhang   MatCheckPreallocated(D, 4);
93828b400f6SJacob Faibussowitsch   PetscCheck(D->assembled, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
93928b400f6SJacob Faibussowitsch   PetscCheck(!D->factortype, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9404222ddf1SHong Zhang 
9414222ddf1SHong Zhang   /* Create a supporting struct and attach it to D */
9429566063dSJacob Faibussowitsch   PetscCall(MatProductClear(D));
9439566063dSJacob Faibussowitsch   PetscCall(MatProductCreate_Private(A, B, C, D));
9444222ddf1SHong Zhang   PetscFunctionReturn(0);
9454222ddf1SHong Zhang }
9464222ddf1SHong Zhang 
9474222ddf1SHong Zhang /*@
94811a5261eSBarry Smith    MatProductCreate - create a matrix to hold the result of a matrix-matrix product operation
9494222ddf1SHong Zhang 
95011a5261eSBarry Smith    Collective on A
9514222ddf1SHong Zhang 
9524222ddf1SHong Zhang    Input Parameters:
9534222ddf1SHong Zhang +  A - the first matrix
9544222ddf1SHong Zhang .  B - the second matrix
9554222ddf1SHong Zhang -  C - the third matrix (optional)
9564222ddf1SHong Zhang 
9574222ddf1SHong Zhang    Output Parameters:
9584222ddf1SHong Zhang .  D - the product matrix
9594222ddf1SHong Zhang 
9604222ddf1SHong Zhang    Level: intermediate
9614222ddf1SHong Zhang 
962f5368d60SBarry Smith    Example of Usage:
963f5368d60SBarry Smith .vb
96411a5261eSBarry Smith     MatProductCreate(A,B,C,&D); or MatProductCreateWithMat(A,B,C,D)
96511a5261eSBarry Smith     MatProductSetType(D, MATPRODUCT_AB or MATPRODUCT_AtB or MATPRODUCT_ABt or MATPRODUCT_PtAP or MATPRODUCT_RARt or MATPRODUCT_ABC)
96611a5261eSBarry Smith     MatProductSetAlgorithm(D, alg)
96711a5261eSBarry Smith     MatProductSetFill(D,fill)
96811a5261eSBarry Smith     MatProductSetFromOptions(D)
96911a5261eSBarry Smith     MatProductSymbolic(D)
97011a5261eSBarry Smith     MatProductNumeric(D)
971f5368d60SBarry Smith     Change numerical values in some of the matrices
97211a5261eSBarry Smith     MatProductNumeric(D)
973f5368d60SBarry Smith .ve
974f5368d60SBarry Smith 
975f5368d60SBarry Smith    Notes:
976f5368d60SBarry Smith    Use `MatProductCreateWithMat()` if the matrix you wish computed, the D matrix, already exists.
977f5368d60SBarry Smith 
978f5368d60SBarry Smith    The information computed during the symbolic stage can be reused for new numerical computations with the same non-zero structure
979f5368d60SBarry Smith 
98011a5261eSBarry Smith    Developer Note:
981f5368d60SBarry Smith    It is undocumented what happens if the nonzero structure of the input matrices changes. Is the symbolic stage automatically redone? Does it crash?
982f5368d60SBarry Smith    Is there error checking for it?
983f5368d60SBarry Smith 
984f5368d60SBarry Smith .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductClear()`
9854222ddf1SHong Zhang @*/
9869371c9d4SSatish Balay PetscErrorCode MatProductCreate(Mat A, Mat B, Mat C, Mat *D) {
9874222ddf1SHong Zhang   PetscFunctionBegin;
9884222ddf1SHong Zhang   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9894222ddf1SHong Zhang   PetscValidType(A, 1);
9904222ddf1SHong Zhang   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
9914222ddf1SHong Zhang   PetscValidType(B, 2);
99228b400f6SJacob Faibussowitsch   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix A");
99328b400f6SJacob Faibussowitsch   PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix B");
9944222ddf1SHong Zhang 
9954222ddf1SHong Zhang   if (C) {
9964222ddf1SHong Zhang     PetscValidHeaderSpecific(C, MAT_CLASSID, 3);
9974222ddf1SHong Zhang     PetscValidType(C, 3);
99828b400f6SJacob Faibussowitsch     PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix C");
9994222ddf1SHong Zhang   }
10004222ddf1SHong Zhang 
10014222ddf1SHong Zhang   PetscValidPointer(D, 4);
10029566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), D));
10039566063dSJacob Faibussowitsch   PetscCall(MatProductCreate_Private(A, B, C, *D));
10044222ddf1SHong Zhang   PetscFunctionReturn(0);
10054222ddf1SHong Zhang }
10065415d71bSStefano Zampini 
10075415d71bSStefano Zampini /*
10085415d71bSStefano Zampini    These are safe basic implementations of ABC, RARt and PtAP
10095415d71bSStefano Zampini    that do not rely on mat->ops->matmatop function pointers.
10105415d71bSStefano Zampini    They only use the MatProduct API and are currently used by
10115415d71bSStefano Zampini    cuSPARSE and KOKKOS-KERNELS backends
10125415d71bSStefano Zampini */
1013ec446438SStefano Zampini typedef struct {
10145415d71bSStefano Zampini   Mat BC;
10155415d71bSStefano Zampini   Mat ABC;
10165415d71bSStefano Zampini } MatMatMatPrivate;
10175415d71bSStefano Zampini 
10189371c9d4SSatish Balay static PetscErrorCode MatDestroy_MatMatMatPrivate(void *data) {
10195415d71bSStefano Zampini   MatMatMatPrivate *mmdata = (MatMatMatPrivate *)data;
10205415d71bSStefano Zampini 
10215415d71bSStefano Zampini   PetscFunctionBegin;
10229566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->BC));
10239566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->ABC));
10249566063dSJacob Faibussowitsch   PetscCall(PetscFree(data));
10255415d71bSStefano Zampini   PetscFunctionReturn(0);
10265415d71bSStefano Zampini }
10275415d71bSStefano Zampini 
10289371c9d4SSatish Balay static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat) {
10295415d71bSStefano Zampini   Mat_Product      *product = mat->product;
10305415d71bSStefano Zampini   MatMatMatPrivate *mmabc;
10315415d71bSStefano Zampini 
10325415d71bSStefano Zampini   PetscFunctionBegin;
10335415d71bSStefano Zampini   MatCheckProduct(mat, 1);
103428b400f6SJacob Faibussowitsch   PetscCheck(mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data empty");
10355415d71bSStefano Zampini   mmabc = (MatMatMatPrivate *)mat->product->data;
103628b400f6SJacob Faibussowitsch   PetscCheck(mmabc->BC->ops->productnumeric, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing numeric stage");
1037ec446438SStefano Zampini   /* use function pointer directly to prevent logging */
10389566063dSJacob Faibussowitsch   PetscCall((*mmabc->BC->ops->productnumeric)(mmabc->BC));
10395415d71bSStefano Zampini   /* swap ABC product stuff with that of ABC for the numeric phase on mat */
10405415d71bSStefano Zampini   mat->product             = mmabc->ABC->product;
10415415d71bSStefano Zampini   mat->ops->productnumeric = mmabc->ABC->ops->productnumeric;
1042ec446438SStefano Zampini   /* use function pointer directly to prevent logging */
1043dbbe0bcdSBarry Smith   PetscUseTypeMethod(mat, productnumeric);
10445415d71bSStefano Zampini   mat->ops->productnumeric = MatProductNumeric_ABC_Basic;
10455415d71bSStefano Zampini   mat->product             = product;
10465415d71bSStefano Zampini   PetscFunctionReturn(0);
10475415d71bSStefano Zampini }
10485415d71bSStefano Zampini 
10499371c9d4SSatish Balay PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat) {
10505415d71bSStefano Zampini   Mat_Product      *product = mat->product;
10515415d71bSStefano Zampini   Mat               A, B, C;
10525415d71bSStefano Zampini   MatProductType    p1, p2;
10535415d71bSStefano Zampini   MatMatMatPrivate *mmabc;
105465e4b4d4SStefano Zampini   const char       *prefix;
10555415d71bSStefano Zampini 
10565415d71bSStefano Zampini   PetscFunctionBegin;
10575415d71bSStefano Zampini   MatCheckProduct(mat, 1);
105828b400f6SJacob Faibussowitsch   PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data not empty");
10599566063dSJacob Faibussowitsch   PetscCall(MatGetOptionsPrefix(mat, &prefix));
10609566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mmabc));
10615415d71bSStefano Zampini   product->data    = mmabc;
10625415d71bSStefano Zampini   product->destroy = MatDestroy_MatMatMatPrivate;
10635415d71bSStefano Zampini   switch (product->type) {
10645415d71bSStefano Zampini   case MATPRODUCT_PtAP:
10655415d71bSStefano Zampini     p1 = MATPRODUCT_AB;
10665415d71bSStefano Zampini     p2 = MATPRODUCT_AtB;
10675415d71bSStefano Zampini     A  = product->B;
10685415d71bSStefano Zampini     B  = product->A;
10695415d71bSStefano Zampini     C  = product->B;
10705415d71bSStefano Zampini     break;
10715415d71bSStefano Zampini   case MATPRODUCT_RARt:
10725415d71bSStefano Zampini     p1 = MATPRODUCT_ABt;
10735415d71bSStefano Zampini     p2 = MATPRODUCT_AB;
10745415d71bSStefano Zampini     A  = product->B;
10755415d71bSStefano Zampini     B  = product->A;
10765415d71bSStefano Zampini     C  = product->B;
10775415d71bSStefano Zampini     break;
10785415d71bSStefano Zampini   case MATPRODUCT_ABC:
10795415d71bSStefano Zampini     p1 = MATPRODUCT_AB;
10805415d71bSStefano Zampini     p2 = MATPRODUCT_AB;
10815415d71bSStefano Zampini     A  = product->A;
10825415d71bSStefano Zampini     B  = product->B;
10835415d71bSStefano Zampini     C  = product->C;
10845415d71bSStefano Zampini     break;
10859371c9d4SSatish Balay   default: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Not for ProductType %s", MatProductTypes[product->type]);
10865415d71bSStefano Zampini   }
10879566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(B, C, NULL, &mmabc->BC));
10889566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(mmabc->BC, prefix));
10899566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(mmabc->BC, "P1_"));
10909566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(mmabc->BC, p1));
10919566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(mmabc->BC, MATPRODUCTALGORITHMDEFAULT));
10929566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(mmabc->BC, product->fill));
10935415d71bSStefano Zampini   mmabc->BC->product->api_user = product->api_user;
10949566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(mmabc->BC));
109528b400f6SJacob Faibussowitsch   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);
1096bfcc3627SStefano Zampini   /* use function pointer directly to prevent logging */
10979566063dSJacob Faibussowitsch   PetscCall((*mmabc->BC->ops->productsymbolic)(mmabc->BC));
10985415d71bSStefano Zampini 
10999566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(A, mmabc->BC, NULL, &mmabc->ABC));
11009566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(mmabc->ABC, prefix));
11019566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(mmabc->ABC, "P2_"));
11029566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(mmabc->ABC, p2));
11039566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(mmabc->ABC, MATPRODUCTALGORITHMDEFAULT));
11049566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(mmabc->ABC, product->fill));
11055415d71bSStefano Zampini   mmabc->ABC->product->api_user = product->api_user;
11069566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(mmabc->ABC));
110728b400f6SJacob Faibussowitsch   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);
11085415d71bSStefano Zampini   /* swap ABC product stuff with that of ABC for the symbolic phase on mat */
11095415d71bSStefano Zampini   mat->product              = mmabc->ABC->product;
11105415d71bSStefano Zampini   mat->ops->productsymbolic = mmabc->ABC->ops->productsymbolic;
1111bfcc3627SStefano Zampini   /* use function pointer directly to prevent logging */
1112dbbe0bcdSBarry Smith   PetscUseTypeMethod(mat, productsymbolic);
11135415d71bSStefano Zampini   mmabc->ABC->ops->productnumeric = mat->ops->productnumeric;
11145415d71bSStefano Zampini   mat->ops->productsymbolic       = MatProductSymbolic_ABC_Basic;
11155415d71bSStefano Zampini   mat->ops->productnumeric        = MatProductNumeric_ABC_Basic;
11165415d71bSStefano Zampini   mat->product                    = product;
11175415d71bSStefano Zampini   PetscFunctionReturn(0);
11185415d71bSStefano Zampini }
1119c600787bSStefano Zampini 
1120c600787bSStefano Zampini /*@
112111a5261eSBarry Smith    MatProductGetType - Returns the type of matrix-matrix product associated with the given matrix.
1122c600787bSStefano Zampini 
1123c600787bSStefano Zampini    Not collective
1124c600787bSStefano Zampini 
1125c600787bSStefano Zampini    Input Parameter:
1126c600787bSStefano Zampini .  mat - the matrix
1127c600787bSStefano Zampini 
1128c600787bSStefano Zampini    Output Parameter:
112911a5261eSBarry Smith .  mtype - the `MatProductType`
1130c600787bSStefano Zampini 
1131c600787bSStefano Zampini    Level: intermediate
1132c600787bSStefano Zampini 
113311a5261eSBarry Smith .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductCreate()`, `MatProductType`, `MatProductAlgorithm`
1134c600787bSStefano Zampini @*/
11359371c9d4SSatish Balay PetscErrorCode MatProductGetType(Mat mat, MatProductType *mtype) {
1136c600787bSStefano Zampini   PetscFunctionBegin;
1137c600787bSStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1138c600787bSStefano Zampini   PetscValidPointer(mtype, 2);
1139c600787bSStefano Zampini   *mtype = MATPRODUCT_UNSPECIFIED;
1140c600787bSStefano Zampini   if (mat->product) *mtype = mat->product->type;
1141c600787bSStefano Zampini   PetscFunctionReturn(0);
1142c600787bSStefano Zampini }
1143c600787bSStefano Zampini 
1144c600787bSStefano Zampini /*@
114511a5261eSBarry Smith    MatProductGetMats - Returns the matrices associated with the matrix-matrix product this matrix can receive
1146c600787bSStefano Zampini 
1147c600787bSStefano Zampini    Not collective
1148c600787bSStefano Zampini 
1149c600787bSStefano Zampini    Input Parameter:
1150c600787bSStefano Zampini .  mat - the product matrix
1151c600787bSStefano Zampini 
1152c600787bSStefano Zampini    Output Parameters:
1153c600787bSStefano Zampini +  A - the first matrix
1154c600787bSStefano Zampini .  B - the second matrix
1155c600787bSStefano Zampini -  C - the third matrix (optional)
1156c600787bSStefano Zampini 
1157c600787bSStefano Zampini    Level: intermediate
1158c600787bSStefano Zampini 
1159f5368d60SBarry Smith .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()`
1160c600787bSStefano Zampini @*/
11619371c9d4SSatish Balay PetscErrorCode MatProductGetMats(Mat mat, Mat *A, Mat *B, Mat *C) {
1162c600787bSStefano Zampini   PetscFunctionBegin;
1163c600787bSStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1164c600787bSStefano Zampini   if (A) *A = mat->product ? mat->product->A : NULL;
1165c600787bSStefano Zampini   if (B) *B = mat->product ? mat->product->B : NULL;
1166c600787bSStefano Zampini   if (C) *C = mat->product ? mat->product->C : NULL;
1167c600787bSStefano Zampini   PetscFunctionReturn(0);
1168c600787bSStefano Zampini }
1169