xref: /petsc/src/mat/interface/matproduct.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
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
177301b172SPierre Jolivet              -> Query MatProductSetFromOptions_anytype_C(D) from A, B and C (in order) (e.g, matrices may have inner matrices like MATTRANSPOSEMAT)
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 
2004222ddf1SHong Zhang    Notes:
2016718818eSStefano Zampini      To reuse the symbolic phase, 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));
283*48a46eb9SPierre Jolivet     if (!iscuda) PetscCall(PetscStrcmp(vtype, VECSEQCUDA, &iscuda));
284*48a46eb9SPierre 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 */
4386718818eSStefano Zampini     /* some matrices (i.e. MATTRANSPOSE, 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   }
476*48a46eb9SPierre 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
481f5368d60SBarry Smith    MatProductSetFromOptions - Sets the options for the computation of a 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
510f5368d60SBarry Smith    MatProductView - View the MatProduct algorithm object within a matrix
5116718818eSStefano Zampini 
5126718818eSStefano Zampini    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 
519db781477SPatrick Sanan .seealso: `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 /*@
5924222ddf1SHong Zhang    MatProductNumeric - Implement a matrix product with numerical values.
5934222ddf1SHong Zhang 
5944222ddf1SHong Zhang    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 
601f5368d60SBarry Smith    Notes: `MatProductSymbolic()` must have been called on mat before calling this function
6026718818eSStefano Zampini 
603db781477SPatrick Sanan .seealso: `MatProductCreate()`, `MatSetType()`, `MatProductSymbolic()`
6044222ddf1SHong Zhang @*/
6059371c9d4SSatish Balay PetscErrorCode MatProductNumeric(Mat mat) {
606e017e560SStefano Zampini   PetscLogEvent eventtype = -1;
6072e105a96SStefano Zampini   PetscBool     missing   = PETSC_FALSE;
6084222ddf1SHong Zhang 
6094222ddf1SHong Zhang   PetscFunctionBegin;
6104222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6116718818eSStefano Zampini   MatCheckProduct(mat, 1);
612e017e560SStefano Zampini   switch (mat->product->type) {
6139371c9d4SSatish Balay   case MATPRODUCT_AB: eventtype = MAT_MatMultNumeric; break;
6149371c9d4SSatish Balay   case MATPRODUCT_AtB: eventtype = MAT_TransposeMatMultNumeric; break;
6159371c9d4SSatish Balay   case MATPRODUCT_ABt: eventtype = MAT_MatTransposeMultNumeric; break;
6169371c9d4SSatish Balay   case MATPRODUCT_PtAP: eventtype = MAT_PtAPNumeric; break;
6179371c9d4SSatish Balay   case MATPRODUCT_RARt: eventtype = MAT_RARtNumeric; break;
6189371c9d4SSatish Balay   case MATPRODUCT_ABC: eventtype = MAT_MatMatMultNumeric; break;
61998921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]);
620e017e560SStefano Zampini   }
6218d7b260cSStefano Zampini 
6224222ddf1SHong Zhang   if (mat->ops->productnumeric) {
6239566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0));
624dbbe0bcdSBarry Smith     PetscUseTypeMethod(mat, productnumeric);
6259566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0));
6262e105a96SStefano Zampini   } else missing = PETSC_TRUE;
6272e105a96SStefano Zampini 
6282e105a96SStefano Zampini   if (missing || !mat->product) {
6292e105a96SStefano Zampini     char errstr[256];
6302e105a96SStefano Zampini 
6312e105a96SStefano Zampini     if (mat->product->type == MATPRODUCT_ABC) {
6329566063dSJacob 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));
6332e105a96SStefano Zampini     } else {
6349566063dSJacob 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));
6352e105a96SStefano Zampini     }
63628b400f6SJacob Faibussowitsch     PetscCheck(!missing, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified numeric phase for product %s", errstr);
63728b400f6SJacob Faibussowitsch     PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after symbolic phase for product %s", errstr);
6382e105a96SStefano Zampini   }
6392e105a96SStefano Zampini 
6401baa6e33SBarry Smith   if (mat->product->clear) PetscCall(MatProductClear(mat));
6419566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6424222ddf1SHong Zhang   PetscFunctionReturn(0);
6434222ddf1SHong Zhang }
6444222ddf1SHong Zhang 
6454222ddf1SHong Zhang /* ----------------------------------------------- */
6466718818eSStefano Zampini /* these are basic implementations relying on the old function pointers
6476718818eSStefano Zampini  * they are dangerous and should be removed in the future */
6489371c9d4SSatish Balay PetscErrorCode MatProductSymbolic_AB(Mat mat) {
6494222ddf1SHong Zhang   Mat_Product *product = mat->product;
6504222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
6514222ddf1SHong Zhang 
6524222ddf1SHong Zhang   PetscFunctionBegin;
6539566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmultsymbolic)(A, B, product->fill, mat));
6544222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_AB;
6554222ddf1SHong Zhang   PetscFunctionReturn(0);
6564222ddf1SHong Zhang }
6574222ddf1SHong Zhang 
6589371c9d4SSatish Balay PetscErrorCode MatProductSymbolic_AtB(Mat mat) {
6594222ddf1SHong Zhang   Mat_Product *product = mat->product;
6604222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
6614222ddf1SHong Zhang 
6624222ddf1SHong Zhang   PetscFunctionBegin;
6639566063dSJacob Faibussowitsch   PetscCall((*mat->ops->transposematmultsymbolic)(A, B, product->fill, mat));
6644222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_AtB;
6654222ddf1SHong Zhang   PetscFunctionReturn(0);
6664222ddf1SHong Zhang }
6674222ddf1SHong Zhang 
6689371c9d4SSatish Balay PetscErrorCode MatProductSymbolic_ABt(Mat mat) {
6694222ddf1SHong Zhang   Mat_Product *product = mat->product;
6704222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
6714222ddf1SHong Zhang 
6724222ddf1SHong Zhang   PetscFunctionBegin;
6739566063dSJacob Faibussowitsch   PetscCall((*mat->ops->mattransposemultsymbolic)(A, B, product->fill, mat));
6744222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_ABt;
6754222ddf1SHong Zhang   PetscFunctionReturn(0);
6764222ddf1SHong Zhang }
6774222ddf1SHong Zhang 
6789371c9d4SSatish Balay PetscErrorCode MatProductSymbolic_ABC(Mat mat) {
6794222ddf1SHong Zhang   Mat_Product *product = mat->product;
6804222ddf1SHong Zhang   Mat          A = product->A, B = product->B, C = product->C;
6814222ddf1SHong Zhang 
6824222ddf1SHong Zhang   PetscFunctionBegin;
6839566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmatmultsymbolic)(A, B, C, product->fill, mat));
6844222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_ABC;
6854222ddf1SHong Zhang   PetscFunctionReturn(0);
6864222ddf1SHong Zhang }
6874222ddf1SHong Zhang 
6886718818eSStefano Zampini /* ----------------------------------------------- */
6896718818eSStefano Zampini 
6904222ddf1SHong Zhang /*@
691f5368d60SBarry Smith    MatProductSymbolic - Perform the symbolic portion of a matrix product, this creates a data structure for use with the numerical product done with
692f5368d60SBarry Smith   `MatProductNumeric()`
6934222ddf1SHong Zhang 
6944222ddf1SHong Zhang    Collective on Mat
6954222ddf1SHong Zhang 
6966718818eSStefano Zampini    Input/Output Parameter:
6974222ddf1SHong Zhang .  mat - the matrix to hold a product
6984222ddf1SHong Zhang 
6994222ddf1SHong Zhang    Level: intermediate
7004222ddf1SHong Zhang 
701f5368d60SBarry Smith    Notes: `MatProductSetFromOptions()` must have been called on mat before calling this function
7026718818eSStefano Zampini 
703db781477SPatrick Sanan .seealso: `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductSetFromOptions()`, `MatProductNumeric()`, `MatProductSetType()`, `MatProductSetAlgorithm()`
7044222ddf1SHong Zhang @*/
7059371c9d4SSatish Balay PetscErrorCode MatProductSymbolic(Mat mat) {
7064222ddf1SHong Zhang   PetscLogEvent eventtype = -1;
7072e105a96SStefano Zampini   PetscBool     missing   = PETSC_FALSE;
7084222ddf1SHong Zhang 
7094222ddf1SHong Zhang   PetscFunctionBegin;
7104222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7116718818eSStefano Zampini   MatCheckProduct(mat, 1);
71228b400f6SJacob Faibussowitsch   PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot run symbolic phase. Product data not empty");
7136718818eSStefano Zampini   switch (mat->product->type) {
7149371c9d4SSatish Balay   case MATPRODUCT_AB: eventtype = MAT_MatMultSymbolic; break;
7159371c9d4SSatish Balay   case MATPRODUCT_AtB: eventtype = MAT_TransposeMatMultSymbolic; break;
7169371c9d4SSatish Balay   case MATPRODUCT_ABt: eventtype = MAT_MatTransposeMultSymbolic; break;
7179371c9d4SSatish Balay   case MATPRODUCT_PtAP: eventtype = MAT_PtAPSymbolic; break;
7189371c9d4SSatish Balay   case MATPRODUCT_RARt: eventtype = MAT_RARtSymbolic; break;
7199371c9d4SSatish Balay   case MATPRODUCT_ABC: eventtype = MAT_MatMatMultSymbolic; break;
72098921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]);
7214222ddf1SHong Zhang   }
7226718818eSStefano Zampini   mat->ops->productnumeric = NULL;
7234222ddf1SHong Zhang   if (mat->ops->productsymbolic) {
7249566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0));
725dbbe0bcdSBarry Smith     PetscUseTypeMethod(mat, productsymbolic);
7269566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0));
7272e105a96SStefano Zampini   } else missing = PETSC_TRUE;
7282e105a96SStefano Zampini 
7292e105a96SStefano Zampini   if (missing || !mat->product || !mat->ops->productnumeric) {
7302e105a96SStefano Zampini     char errstr[256];
7312e105a96SStefano Zampini 
7322e105a96SStefano Zampini     if (mat->product->type == MATPRODUCT_ABC) {
7339566063dSJacob 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));
7342e105a96SStefano Zampini     } else {
7359566063dSJacob 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));
7362e105a96SStefano Zampini     }
73728b400f6SJacob Faibussowitsch     PetscCheck(!missing, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified symbolic phase for product %s. Call MatProductSetFromOptions() first", errstr);
73828b400f6SJacob Faibussowitsch     PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after symbolic phase for product %s", errstr);
7392e105a96SStefano Zampini   }
7404222ddf1SHong Zhang   PetscFunctionReturn(0);
7414222ddf1SHong Zhang }
7424222ddf1SHong Zhang 
7434222ddf1SHong Zhang /*@
7444222ddf1SHong Zhang    MatProductSetFill - Set an expected fill of the matrix product.
7454222ddf1SHong Zhang 
7464222ddf1SHong Zhang    Collective on Mat
7474222ddf1SHong Zhang 
7484222ddf1SHong Zhang    Input Parameters:
7494222ddf1SHong Zhang +  mat - the matrix product
750f5368d60SBarry 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.
7514222ddf1SHong Zhang 
7524222ddf1SHong Zhang    Level: intermediate
7534222ddf1SHong Zhang 
754db781477SPatrick Sanan .seealso: `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()`
7554222ddf1SHong Zhang @*/
7569371c9d4SSatish Balay PetscErrorCode MatProductSetFill(Mat mat, PetscReal fill) {
7574222ddf1SHong Zhang   PetscFunctionBegin;
7584222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7596718818eSStefano Zampini   MatCheckProduct(mat, 1);
7606718818eSStefano Zampini   if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) mat->product->fill = 2.0;
7616718818eSStefano Zampini   else mat->product->fill = fill;
7624222ddf1SHong Zhang   PetscFunctionReturn(0);
7634222ddf1SHong Zhang }
7644222ddf1SHong Zhang 
7654222ddf1SHong Zhang /*@
766f5368d60SBarry Smith    MatProductSetAlgorithm - Requests a particular algorithm for a matrix product computation that will perform to compute the given matrix
7674222ddf1SHong Zhang 
7684222ddf1SHong Zhang    Collective on Mat
7694222ddf1SHong Zhang 
7704222ddf1SHong Zhang    Input Parameters:
7714222ddf1SHong Zhang +  mat - the matrix product
772f5368d60SBarry Smith -  alg - particular implementation algorithm of the matrix product, e.g., `MATPRODUCTALGORITHMDEFAULT`.
7733e662e0bSHong Zhang 
7743e662e0bSHong Zhang    Options Database Key:
7753e662e0bSHong Zhang .  -mat_product_algorithm <algorithm> - Sets the algorithm; use -help for a list
7763e662e0bSHong Zhang     of available algorithms (for instance, scalable, outerproduct, etc.)
7774222ddf1SHong Zhang 
7784222ddf1SHong Zhang    Level: intermediate
7794222ddf1SHong Zhang 
780db781477SPatrick Sanan .seealso: `MatProductSetType()`, `MatProductSetFill()`, `MatProductCreate()`, `MatProductAlgorithm`
7814222ddf1SHong Zhang @*/
7829371c9d4SSatish Balay PetscErrorCode MatProductSetAlgorithm(Mat mat, MatProductAlgorithm alg) {
7834222ddf1SHong Zhang   PetscFunctionBegin;
7844222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7856718818eSStefano Zampini   MatCheckProduct(mat, 1);
7869566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->product->alg));
7879566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(alg, &mat->product->alg));
7884222ddf1SHong Zhang   PetscFunctionReturn(0);
7894222ddf1SHong Zhang }
7904222ddf1SHong Zhang 
7914222ddf1SHong Zhang /*@
792f5368d60SBarry Smith    MatProductSetType - Sets a particular matrix product type to be used to compute the given matrix
7934222ddf1SHong Zhang 
7944222ddf1SHong Zhang    Collective on Mat
7954222ddf1SHong Zhang 
7964222ddf1SHong Zhang    Input Parameters:
7974222ddf1SHong Zhang +  mat - the matrix
798f5368d60SBarry Smith -  productype   - matrix product type, e.g., `MATPRODUCT_AB`,`MATPRODUCT_AtB`,`MATPRODUCT_ABt`,`MATPRODUCT_PtAP`,`MATPRODUCT_RARt`,`MATPRODUCT_ABC`.
7994222ddf1SHong Zhang 
8004222ddf1SHong Zhang    Level: intermediate
8014222ddf1SHong Zhang 
802f5368d60SBarry Smith    Note:
803f5368d60SBarry Smith    The small t represents the traspose operation.
804f5368d60SBarry Smith 
805db781477SPatrick Sanan .seealso: `MatProductCreate()`, `MatProductType`
8064222ddf1SHong Zhang @*/
8079371c9d4SSatish Balay PetscErrorCode MatProductSetType(Mat mat, MatProductType productype) {
8084222ddf1SHong Zhang   PetscFunctionBegin;
8094222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8106718818eSStefano Zampini   MatCheckProduct(mat, 1);
8117a3c3d58SStefano Zampini   PetscValidLogicalCollectiveEnum(mat, productype, 2);
8126718818eSStefano Zampini   if (productype != mat->product->type) {
8131baa6e33SBarry Smith     if (mat->product->destroy) PetscCall((*mat->product->destroy)(mat->product->data));
8146718818eSStefano Zampini     mat->product->destroy     = NULL;
8156718818eSStefano Zampini     mat->product->data        = NULL;
8166718818eSStefano Zampini     mat->ops->productsymbolic = NULL;
8176718818eSStefano Zampini     mat->ops->productnumeric  = NULL;
8186718818eSStefano Zampini   }
8196718818eSStefano Zampini   mat->product->type = productype;
8204222ddf1SHong Zhang   PetscFunctionReturn(0);
8214222ddf1SHong Zhang }
8224222ddf1SHong Zhang 
8234417c5e8SHong Zhang /*@
8244417c5e8SHong Zhang    MatProductClear - Clears matrix product internal structure.
8254417c5e8SHong Zhang 
8264417c5e8SHong Zhang    Collective on Mat
8274417c5e8SHong Zhang 
8284417c5e8SHong Zhang    Input Parameters:
8294417c5e8SHong Zhang .  mat - the product matrix
8304417c5e8SHong Zhang 
8314417c5e8SHong Zhang    Level: intermediate
8326718818eSStefano Zampini 
833f5368d60SBarry Smith    Notes:
834f5368d60SBarry Smith    This function should be called to remove any intermediate data used to compute the matrix to free up memory.
835f5368d60SBarry Smith 
8366718818eSStefano Zampini    After having called this function, MatProduct operations can no longer be used on mat
837f5368d60SBarry Smith 
838f5368d60SBarry Smith .seealso: `MatProductCreate()`
8394417c5e8SHong Zhang @*/
8409371c9d4SSatish Balay PetscErrorCode MatProductClear(Mat mat) {
8414417c5e8SHong Zhang   Mat_Product *product = mat->product;
8424417c5e8SHong Zhang 
8434417c5e8SHong Zhang   PetscFunctionBegin;
8447a3c3d58SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8454417c5e8SHong Zhang   if (product) {
8469566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->A));
8479566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->B));
8489566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->C));
8499566063dSJacob Faibussowitsch     PetscCall(PetscFree(product->alg));
8509566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->Dwork));
8511baa6e33SBarry Smith     if (product->destroy) PetscCall((*product->destroy)(product->data));
8526718818eSStefano Zampini   }
8539566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->product));
8546718818eSStefano Zampini   mat->ops->productsymbolic = NULL;
8556718818eSStefano Zampini   mat->ops->productnumeric  = NULL;
8564417c5e8SHong Zhang   PetscFunctionReturn(0);
8574417c5e8SHong Zhang }
8584417c5e8SHong Zhang 
8594222ddf1SHong Zhang /* Create a supporting struct and attach it to the matrix product */
8609371c9d4SSatish Balay PetscErrorCode MatProductCreate_Private(Mat A, Mat B, Mat C, Mat D) {
8614222ddf1SHong Zhang   Mat_Product *product = NULL;
8624222ddf1SHong Zhang 
8634222ddf1SHong Zhang   PetscFunctionBegin;
8646718818eSStefano Zampini   PetscValidHeaderSpecific(D, MAT_CLASSID, 4);
86528b400f6SJacob Faibussowitsch   PetscCheck(!D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product already present");
8669566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(D, &product));
8674222ddf1SHong Zhang   product->A        = A;
8684222ddf1SHong Zhang   product->B        = B;
8694222ddf1SHong Zhang   product->C        = C;
8706718818eSStefano Zampini   product->type     = MATPRODUCT_UNSPECIFIED;
8714222ddf1SHong Zhang   product->Dwork    = NULL;
8724222ddf1SHong Zhang   product->api_user = PETSC_FALSE;
8736718818eSStefano Zampini   product->clear    = PETSC_FALSE;
8744222ddf1SHong Zhang   D->product        = product;
8754417c5e8SHong Zhang 
8769566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(D, MATPRODUCTALGORITHMDEFAULT));
8779566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(D, PETSC_DEFAULT));
8787a3c3d58SStefano Zampini 
8799566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)A));
8809566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)B));
8819566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)C));
8824222ddf1SHong Zhang   PetscFunctionReturn(0);
8834222ddf1SHong Zhang }
8844222ddf1SHong Zhang 
8854222ddf1SHong Zhang /*@
886f5368d60SBarry Smith    MatProductCreateWithMat - Setup a given matrix as a matrix product of other matrices
8874222ddf1SHong Zhang 
8884222ddf1SHong Zhang    Collective on Mat
8894222ddf1SHong Zhang 
8904222ddf1SHong Zhang    Input Parameters:
8914222ddf1SHong Zhang +  A - the first matrix
8924222ddf1SHong Zhang .  B - the second matrix
8934222ddf1SHong Zhang .  C - the third matrix (optional)
8944222ddf1SHong Zhang -  D - the matrix which will be used as a product
8954222ddf1SHong Zhang 
8964222ddf1SHong Zhang    Output Parameters:
8974222ddf1SHong Zhang .  D - the product matrix
8984222ddf1SHong Zhang 
8996718818eSStefano Zampini    Notes:
900f5368d60SBarry Smith    Use `MatProductCreate()` if the matrix you wish computed (the D matrix) does not already exist
901f5368d60SBarry Smith 
902f5368d60SBarry Smith    See `MatProductCreate()` for details on the usage of the MatProduct routines
903f5368d60SBarry Smith 
904f5368d60SBarry Smith    Any product data currently attached to D will be cleared
9056718818eSStefano Zampini 
9064222ddf1SHong Zhang    Level: intermediate
9074222ddf1SHong Zhang 
908db781477SPatrick Sanan .seealso: `MatProductCreate()`, `MatProductClear()`
9094222ddf1SHong Zhang @*/
9109371c9d4SSatish Balay PetscErrorCode MatProductCreateWithMat(Mat A, Mat B, Mat C, Mat D) {
9114222ddf1SHong Zhang   PetscFunctionBegin;
9124222ddf1SHong Zhang   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9134222ddf1SHong Zhang   PetscValidType(A, 1);
9144222ddf1SHong Zhang   MatCheckPreallocated(A, 1);
91528b400f6SJacob Faibussowitsch   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
91628b400f6SJacob Faibussowitsch   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9174222ddf1SHong Zhang 
9184222ddf1SHong Zhang   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
9194222ddf1SHong Zhang   PetscValidType(B, 2);
9204222ddf1SHong Zhang   MatCheckPreallocated(B, 2);
92128b400f6SJacob Faibussowitsch   PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
92228b400f6SJacob Faibussowitsch   PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9234222ddf1SHong Zhang 
9244222ddf1SHong Zhang   if (C) {
9254222ddf1SHong Zhang     PetscValidHeaderSpecific(C, MAT_CLASSID, 3);
9264222ddf1SHong Zhang     PetscValidType(C, 3);
9274222ddf1SHong Zhang     MatCheckPreallocated(C, 3);
92828b400f6SJacob Faibussowitsch     PetscCheck(C->assembled, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
92928b400f6SJacob Faibussowitsch     PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9304222ddf1SHong Zhang   }
9314222ddf1SHong Zhang 
9324222ddf1SHong Zhang   PetscValidHeaderSpecific(D, MAT_CLASSID, 4);
9334222ddf1SHong Zhang   PetscValidType(D, 4);
9344222ddf1SHong Zhang   MatCheckPreallocated(D, 4);
93528b400f6SJacob Faibussowitsch   PetscCheck(D->assembled, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
93628b400f6SJacob Faibussowitsch   PetscCheck(!D->factortype, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9374222ddf1SHong Zhang 
9384222ddf1SHong Zhang   /* Create a supporting struct and attach it to D */
9399566063dSJacob Faibussowitsch   PetscCall(MatProductClear(D));
9409566063dSJacob Faibussowitsch   PetscCall(MatProductCreate_Private(A, B, C, D));
9414222ddf1SHong Zhang   PetscFunctionReturn(0);
9424222ddf1SHong Zhang }
9434222ddf1SHong Zhang 
9444222ddf1SHong Zhang /*@
945f5368d60SBarry Smith    MatProductCreate - create a matrix product object that can be used to compute various matrix times matrix operations such as A*B, R*A*P
9464222ddf1SHong Zhang 
9474222ddf1SHong Zhang    Collective on Mat
9484222ddf1SHong Zhang 
9494222ddf1SHong Zhang    Input Parameters:
9504222ddf1SHong Zhang +  A - the first matrix
9514222ddf1SHong Zhang .  B - the second matrix
9524222ddf1SHong Zhang -  C - the third matrix (optional)
9534222ddf1SHong Zhang 
9544222ddf1SHong Zhang    Output Parameters:
9554222ddf1SHong Zhang .  D - the product matrix
9564222ddf1SHong Zhang 
9574222ddf1SHong Zhang    Level: intermediate
9584222ddf1SHong Zhang 
959f5368d60SBarry Smith    Example of Usage:
960f5368d60SBarry Smith .vb
961f5368d60SBarry Smith     `MatProductCreate`(A,B,C,&D); or `MatProductCreateWithMat`(A,B,C,D)
962f5368d60SBarry Smith     `MatProductSetType`(D, `MATPRODUCT_AB` or `MATPRODUCT_AtB` or `MATPRODUCT_ABt` or `MATPRODUCT_PtAP` or `MATPRODUCT_RARt` or `MATPRODUCT_ABC`)
963f5368d60SBarry Smith     `MatProductSetAlgorithm`(D, alg)
964f5368d60SBarry Smith     `MatProductSetFill`(D,fill)
965f5368d60SBarry Smith     `MatProductSetFromOptions`(D)
966f5368d60SBarry Smith     `MatProductSymbolic`(D)
967f5368d60SBarry Smith     `MatProductNumeric`(D)
968f5368d60SBarry Smith     Change numerical values in some of the matrices
969f5368d60SBarry Smith     `MatProductNumeric`(D)
970f5368d60SBarry Smith .ve
971f5368d60SBarry Smith 
972f5368d60SBarry Smith    Notes:
973f5368d60SBarry Smith    Use `MatProductCreateWithMat()` if the matrix you wish computed, the D matrix, already exists.
974f5368d60SBarry Smith 
975f5368d60SBarry Smith    The information computed during the symbolic stage can be reused for new numerical computations with the same non-zero structure
976f5368d60SBarry Smith 
977f5368d60SBarry Smith    Developer Notes:
978f5368d60SBarry Smith    It is undocumented what happens if the nonzero structure of the input matrices changes. Is the symbolic stage automatically redone? Does it crash?
979f5368d60SBarry Smith    Is there error checking for it?
980f5368d60SBarry Smith 
981f5368d60SBarry Smith .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductClear()`
9824222ddf1SHong Zhang @*/
9839371c9d4SSatish Balay PetscErrorCode MatProductCreate(Mat A, Mat B, Mat C, Mat *D) {
9844222ddf1SHong Zhang   PetscFunctionBegin;
9854222ddf1SHong Zhang   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9864222ddf1SHong Zhang   PetscValidType(A, 1);
9874222ddf1SHong Zhang   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
9884222ddf1SHong Zhang   PetscValidType(B, 2);
98928b400f6SJacob Faibussowitsch   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix A");
99028b400f6SJacob Faibussowitsch   PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix B");
9914222ddf1SHong Zhang 
9924222ddf1SHong Zhang   if (C) {
9934222ddf1SHong Zhang     PetscValidHeaderSpecific(C, MAT_CLASSID, 3);
9944222ddf1SHong Zhang     PetscValidType(C, 3);
99528b400f6SJacob Faibussowitsch     PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix C");
9964222ddf1SHong Zhang   }
9974222ddf1SHong Zhang 
9984222ddf1SHong Zhang   PetscValidPointer(D, 4);
9999566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), D));
10009566063dSJacob Faibussowitsch   PetscCall(MatProductCreate_Private(A, B, C, *D));
10014222ddf1SHong Zhang   PetscFunctionReturn(0);
10024222ddf1SHong Zhang }
10035415d71bSStefano Zampini 
10045415d71bSStefano Zampini /*
10055415d71bSStefano Zampini    These are safe basic implementations of ABC, RARt and PtAP
10065415d71bSStefano Zampini    that do not rely on mat->ops->matmatop function pointers.
10075415d71bSStefano Zampini    They only use the MatProduct API and are currently used by
10085415d71bSStefano Zampini    cuSPARSE and KOKKOS-KERNELS backends
10095415d71bSStefano Zampini */
1010ec446438SStefano Zampini typedef struct {
10115415d71bSStefano Zampini   Mat BC;
10125415d71bSStefano Zampini   Mat ABC;
10135415d71bSStefano Zampini } MatMatMatPrivate;
10145415d71bSStefano Zampini 
10159371c9d4SSatish Balay static PetscErrorCode MatDestroy_MatMatMatPrivate(void *data) {
10165415d71bSStefano Zampini   MatMatMatPrivate *mmdata = (MatMatMatPrivate *)data;
10175415d71bSStefano Zampini 
10185415d71bSStefano Zampini   PetscFunctionBegin;
10199566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->BC));
10209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->ABC));
10219566063dSJacob Faibussowitsch   PetscCall(PetscFree(data));
10225415d71bSStefano Zampini   PetscFunctionReturn(0);
10235415d71bSStefano Zampini }
10245415d71bSStefano Zampini 
10259371c9d4SSatish Balay static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat) {
10265415d71bSStefano Zampini   Mat_Product      *product = mat->product;
10275415d71bSStefano Zampini   MatMatMatPrivate *mmabc;
10285415d71bSStefano Zampini 
10295415d71bSStefano Zampini   PetscFunctionBegin;
10305415d71bSStefano Zampini   MatCheckProduct(mat, 1);
103128b400f6SJacob Faibussowitsch   PetscCheck(mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data empty");
10325415d71bSStefano Zampini   mmabc = (MatMatMatPrivate *)mat->product->data;
103328b400f6SJacob Faibussowitsch   PetscCheck(mmabc->BC->ops->productnumeric, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing numeric stage");
1034ec446438SStefano Zampini   /* use function pointer directly to prevent logging */
10359566063dSJacob Faibussowitsch   PetscCall((*mmabc->BC->ops->productnumeric)(mmabc->BC));
10365415d71bSStefano Zampini   /* swap ABC product stuff with that of ABC for the numeric phase on mat */
10375415d71bSStefano Zampini   mat->product             = mmabc->ABC->product;
10385415d71bSStefano Zampini   mat->ops->productnumeric = mmabc->ABC->ops->productnumeric;
1039ec446438SStefano Zampini   /* use function pointer directly to prevent logging */
1040dbbe0bcdSBarry Smith   PetscUseTypeMethod(mat, productnumeric);
10415415d71bSStefano Zampini   mat->ops->productnumeric = MatProductNumeric_ABC_Basic;
10425415d71bSStefano Zampini   mat->product             = product;
10435415d71bSStefano Zampini   PetscFunctionReturn(0);
10445415d71bSStefano Zampini }
10455415d71bSStefano Zampini 
10469371c9d4SSatish Balay PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat) {
10475415d71bSStefano Zampini   Mat_Product      *product = mat->product;
10485415d71bSStefano Zampini   Mat               A, B, C;
10495415d71bSStefano Zampini   MatProductType    p1, p2;
10505415d71bSStefano Zampini   MatMatMatPrivate *mmabc;
105165e4b4d4SStefano Zampini   const char       *prefix;
10525415d71bSStefano Zampini 
10535415d71bSStefano Zampini   PetscFunctionBegin;
10545415d71bSStefano Zampini   MatCheckProduct(mat, 1);
105528b400f6SJacob Faibussowitsch   PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data not empty");
10569566063dSJacob Faibussowitsch   PetscCall(MatGetOptionsPrefix(mat, &prefix));
10579566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mmabc));
10585415d71bSStefano Zampini   product->data    = mmabc;
10595415d71bSStefano Zampini   product->destroy = MatDestroy_MatMatMatPrivate;
10605415d71bSStefano Zampini   switch (product->type) {
10615415d71bSStefano Zampini   case MATPRODUCT_PtAP:
10625415d71bSStefano Zampini     p1 = MATPRODUCT_AB;
10635415d71bSStefano Zampini     p2 = MATPRODUCT_AtB;
10645415d71bSStefano Zampini     A  = product->B;
10655415d71bSStefano Zampini     B  = product->A;
10665415d71bSStefano Zampini     C  = product->B;
10675415d71bSStefano Zampini     break;
10685415d71bSStefano Zampini   case MATPRODUCT_RARt:
10695415d71bSStefano Zampini     p1 = MATPRODUCT_ABt;
10705415d71bSStefano Zampini     p2 = MATPRODUCT_AB;
10715415d71bSStefano Zampini     A  = product->B;
10725415d71bSStefano Zampini     B  = product->A;
10735415d71bSStefano Zampini     C  = product->B;
10745415d71bSStefano Zampini     break;
10755415d71bSStefano Zampini   case MATPRODUCT_ABC:
10765415d71bSStefano Zampini     p1 = MATPRODUCT_AB;
10775415d71bSStefano Zampini     p2 = MATPRODUCT_AB;
10785415d71bSStefano Zampini     A  = product->A;
10795415d71bSStefano Zampini     B  = product->B;
10805415d71bSStefano Zampini     C  = product->C;
10815415d71bSStefano Zampini     break;
10829371c9d4SSatish Balay   default: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Not for ProductType %s", MatProductTypes[product->type]);
10835415d71bSStefano Zampini   }
10849566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(B, C, NULL, &mmabc->BC));
10859566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(mmabc->BC, prefix));
10869566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(mmabc->BC, "P1_"));
10879566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(mmabc->BC, p1));
10889566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(mmabc->BC, MATPRODUCTALGORITHMDEFAULT));
10899566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(mmabc->BC, product->fill));
10905415d71bSStefano Zampini   mmabc->BC->product->api_user = product->api_user;
10919566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(mmabc->BC));
109228b400f6SJacob 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);
1093bfcc3627SStefano Zampini   /* use function pointer directly to prevent logging */
10949566063dSJacob Faibussowitsch   PetscCall((*mmabc->BC->ops->productsymbolic)(mmabc->BC));
10955415d71bSStefano Zampini 
10969566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(A, mmabc->BC, NULL, &mmabc->ABC));
10979566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(mmabc->ABC, prefix));
10989566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(mmabc->ABC, "P2_"));
10999566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(mmabc->ABC, p2));
11009566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(mmabc->ABC, MATPRODUCTALGORITHMDEFAULT));
11019566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(mmabc->ABC, product->fill));
11025415d71bSStefano Zampini   mmabc->ABC->product->api_user = product->api_user;
11039566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(mmabc->ABC));
110428b400f6SJacob 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);
11055415d71bSStefano Zampini   /* swap ABC product stuff with that of ABC for the symbolic phase on mat */
11065415d71bSStefano Zampini   mat->product              = mmabc->ABC->product;
11075415d71bSStefano Zampini   mat->ops->productsymbolic = mmabc->ABC->ops->productsymbolic;
1108bfcc3627SStefano Zampini   /* use function pointer directly to prevent logging */
1109dbbe0bcdSBarry Smith   PetscUseTypeMethod(mat, productsymbolic);
11105415d71bSStefano Zampini   mmabc->ABC->ops->productnumeric = mat->ops->productnumeric;
11115415d71bSStefano Zampini   mat->ops->productsymbolic       = MatProductSymbolic_ABC_Basic;
11125415d71bSStefano Zampini   mat->ops->productnumeric        = MatProductNumeric_ABC_Basic;
11135415d71bSStefano Zampini   mat->product                    = product;
11145415d71bSStefano Zampini   PetscFunctionReturn(0);
11155415d71bSStefano Zampini }
1116c600787bSStefano Zampini 
1117c600787bSStefano Zampini /*@
1118c600787bSStefano Zampini    MatProductGetType - Returns the type of the MatProduct.
1119c600787bSStefano Zampini 
1120c600787bSStefano Zampini    Not collective
1121c600787bSStefano Zampini 
1122c600787bSStefano Zampini    Input Parameter:
1123c600787bSStefano Zampini .  mat - the matrix
1124c600787bSStefano Zampini 
1125c600787bSStefano Zampini    Output Parameter:
1126c600787bSStefano Zampini .  mtype - the MatProduct type
1127c600787bSStefano Zampini 
1128c600787bSStefano Zampini    Level: intermediate
1129c600787bSStefano Zampini 
1130f5368d60SBarry Smith .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductCreate()`, `MatProductType`
1131c600787bSStefano Zampini @*/
11329371c9d4SSatish Balay PetscErrorCode MatProductGetType(Mat mat, MatProductType *mtype) {
1133c600787bSStefano Zampini   PetscFunctionBegin;
1134c600787bSStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1135c600787bSStefano Zampini   PetscValidPointer(mtype, 2);
1136c600787bSStefano Zampini   *mtype = MATPRODUCT_UNSPECIFIED;
1137c600787bSStefano Zampini   if (mat->product) *mtype = mat->product->type;
1138c600787bSStefano Zampini   PetscFunctionReturn(0);
1139c600787bSStefano Zampini }
1140c600787bSStefano Zampini 
1141c600787bSStefano Zampini /*@
1142c600787bSStefano Zampini    MatProductGetMats - Returns the matrices associated with the MatProduct.
1143c600787bSStefano Zampini 
1144c600787bSStefano Zampini    Not collective
1145c600787bSStefano Zampini 
1146c600787bSStefano Zampini    Input Parameter:
1147c600787bSStefano Zampini .  mat - the product matrix
1148c600787bSStefano Zampini 
1149c600787bSStefano Zampini    Output Parameters:
1150c600787bSStefano Zampini +  A - the first matrix
1151c600787bSStefano Zampini .  B - the second matrix
1152c600787bSStefano Zampini -  C - the third matrix (optional)
1153c600787bSStefano Zampini 
1154c600787bSStefano Zampini    Level: intermediate
1155c600787bSStefano Zampini 
1156f5368d60SBarry Smith .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()`
1157c600787bSStefano Zampini @*/
11589371c9d4SSatish Balay PetscErrorCode MatProductGetMats(Mat mat, Mat *A, Mat *B, Mat *C) {
1159c600787bSStefano Zampini   PetscFunctionBegin;
1160c600787bSStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1161c600787bSStefano Zampini   if (A) *A = mat->product ? mat->product->A : NULL;
1162c600787bSStefano Zampini   if (B) *B = mat->product ? mat->product->B : NULL;
1163c600787bSStefano Zampini   if (C) *C = mat->product ? mat->product->C : NULL;
1164c600787bSStefano Zampini   PetscFunctionReturn(0);
1165c600787bSStefano Zampini }
1166