xref: /petsc/src/mat/interface/matproduct.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
14222ddf1SHong Zhang /*
24222ddf1SHong Zhang     Routines for matrix products. Calling procedure:
34222ddf1SHong Zhang 
46718818eSStefano Zampini     MatProductCreate(A,B,C,&D); or MatProductCreateWithMat(A,B,C,D)
56718818eSStefano Zampini     MatProductSetType(D, MATPRODUCT_AB/AtB/ABt/PtAP/RARt/ABC)
66718818eSStefano Zampini     MatProductSetAlgorithm(D, alg)
76718818eSStefano Zampini     MatProductSetFill(D,fill)
86718818eSStefano Zampini     MatProductSetFromOptions(D)
96718818eSStefano Zampini       -> MatProductSetFromOptions_Private(D)
104222ddf1SHong Zhang            # Check matrix global sizes
116718818eSStefano Zampini            if the matrices have the same setfromoptions routine, use it
126718818eSStefano Zampini            if not, try:
136718818eSStefano Zampini              -> Query MatProductSetFromOptions_Atype_Btype_Ctype_C(D) from A, B and C (in order)
146718818eSStefano Zampini              if found -> run the specific setup that must set the symbolic operation (these callbacks should never fail)
156718818eSStefano Zampini            if callback not found or no symbolic operation set
16013e2dc7SBarry Smith              -> Query MatProductSetFromOptions_anytype_C(D) from A, B and C (in order) (e.g, matrices may have inner matrices like MATTRANSPOSEVIRTUAL)
176718818eSStefano Zampini            if dispatch found but combination still not present do
186718818eSStefano Zampini              -> check if B is dense and product type AtB or AB -> if true, basic looping of dense columns
196718818eSStefano Zampini              -> check if triple product (PtAP, RARt or ABC) -> if true, set the Basic routines
206718818eSStefano Zampini 
216718818eSStefano Zampini     #  The setfromoptions calls MatProductSetFromOptions_Atype_Btype_Ctype should
224222ddf1SHong Zhang     #    Check matrix local sizes for mpi matrices
234222ddf1SHong Zhang     #    Set default algorithm
244222ddf1SHong Zhang     #    Get runtime option
256718818eSStefano Zampini     #    Set D->ops->productsymbolic = MatProductSymbolic_productype_Atype_Btype_Ctype if found
264222ddf1SHong Zhang 
276718818eSStefano Zampini     MatProductSymbolic(D)
286718818eSStefano Zampini       # Call MatProductSymbolic_productype_Atype_Btype_Ctype()
296718818eSStefano Zampini         the callback must set the numeric phase D->ops->productnumeric = MatProductNumeric_productype_Atype_Btype_Ctype
304222ddf1SHong Zhang 
316718818eSStefano Zampini     MatProductNumeric(D)
326718818eSStefano Zampini       # Call the numeric phase
336718818eSStefano Zampini 
346718818eSStefano Zampini     # The symbolic phases are allowed to set extra data structures and attach those to the product
356718818eSStefano Zampini     # this additional data can be reused between multiple numeric phases with the same matrices
366718818eSStefano Zampini     # if not needed, call
376718818eSStefano Zampini     MatProductClear(D)
384222ddf1SHong Zhang */
394222ddf1SHong Zhang 
404222ddf1SHong Zhang #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
414222ddf1SHong Zhang 
426718818eSStefano Zampini const char *const MatProductTypes[] = {"UNSPECIFIED", "AB", "AtB", "ABt", "PtAP", "RARt", "ABC"};
43544a5e07SHong Zhang 
446718818eSStefano Zampini /* these are basic implementations relying on the old function pointers
456718818eSStefano Zampini  * they are dangerous and should be removed in the future */
MatProductNumeric_PtAP_Unsafe(Mat C)46d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_PtAP_Unsafe(Mat C)
47d71ae5a4SJacob Faibussowitsch {
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 */
55fe47926eSStefano Zampini   product->type = MATPRODUCT_AtB;
569566063dSJacob Faibussowitsch   PetscCall((*C->ops->transposematmultnumeric)(P, AP, C));
57fe47926eSStefano Zampini   product->type = MATPRODUCT_PtAP;
583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
594222ddf1SHong Zhang }
604222ddf1SHong Zhang 
MatProductSymbolic_PtAP_Unsafe(Mat C)61d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_PtAP_Unsafe(Mat C)
62d71ae5a4SJacob Faibussowitsch {
634222ddf1SHong Zhang   Mat_Product *product = C->product;
644222ddf1SHong Zhang   Mat          A = product->A, P = product->B, AP;
654222ddf1SHong Zhang   PetscReal    fill = product->fill;
664222ddf1SHong Zhang 
674222ddf1SHong Zhang   PetscFunctionBegin;
68835f2295SStefano Zampini   PetscCall(PetscInfo(C, "for A %s, P %s is used\n", ((PetscObject)product->A)->type_name, ((PetscObject)product->B)->type_name));
694222ddf1SHong Zhang   /* AP = A*P */
709566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(A, P, NULL, &AP));
719566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(AP, MATPRODUCT_AB));
729566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(AP, MATPRODUCTALGORITHMDEFAULT));
739566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(AP, fill));
749566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(AP));
759566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(AP));
764222ddf1SHong Zhang 
774222ddf1SHong Zhang   /* C = P^T*AP */
789566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(C, MATPRODUCT_AtB));
799566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(C, MATPRODUCTALGORITHMDEFAULT));
804222ddf1SHong Zhang   product->A = P;
814222ddf1SHong Zhang   product->B = AP;
829566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(C));
839566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(C));
844222ddf1SHong Zhang 
854222ddf1SHong Zhang   /* resume user's original input matrix setting for A and B */
86fe47926eSStefano Zampini   product->type  = MATPRODUCT_PtAP;
874222ddf1SHong Zhang   product->A     = A;
884222ddf1SHong Zhang   product->B     = P;
894222ddf1SHong Zhang   product->Dwork = AP;
904222ddf1SHong Zhang 
915415d71bSStefano Zampini   C->ops->productnumeric = MatProductNumeric_PtAP_Unsafe;
923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
934222ddf1SHong Zhang }
944222ddf1SHong Zhang 
MatProductNumeric_RARt_Unsafe(Mat C)95d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_RARt_Unsafe(Mat C)
96d71ae5a4SJacob Faibussowitsch {
974222ddf1SHong Zhang   Mat_Product *product = C->product;
984222ddf1SHong Zhang   Mat          R = product->B, RA = product->Dwork;
994222ddf1SHong Zhang 
1004222ddf1SHong Zhang   PetscFunctionBegin;
1014222ddf1SHong Zhang   /* RA = R*A */
1029566063dSJacob Faibussowitsch   PetscCall(MatProductNumeric(RA));
1034222ddf1SHong Zhang   /* C = RA*R^T */
104fe47926eSStefano Zampini   product->type = MATPRODUCT_ABt;
1059566063dSJacob Faibussowitsch   PetscCall((*C->ops->mattransposemultnumeric)(RA, R, C));
106fe47926eSStefano Zampini   product->type = MATPRODUCT_RARt;
1073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1084222ddf1SHong Zhang }
1094222ddf1SHong Zhang 
MatProductSymbolic_RARt_Unsafe(Mat C)110d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_RARt_Unsafe(Mat C)
111d71ae5a4SJacob Faibussowitsch {
1124222ddf1SHong Zhang   Mat_Product *product = C->product;
1134222ddf1SHong Zhang   Mat          A = product->A, R = product->B, RA;
1144222ddf1SHong Zhang   PetscReal    fill = product->fill;
1154222ddf1SHong Zhang 
1164222ddf1SHong Zhang   PetscFunctionBegin;
117835f2295SStefano Zampini   PetscCall(PetscInfo(C, "for A %s, R %s is used\n", ((PetscObject)product->A)->type_name, ((PetscObject)product->B)->type_name));
1184222ddf1SHong Zhang   /* RA = R*A */
1199566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(R, A, NULL, &RA));
1209566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(RA, MATPRODUCT_AB));
1219566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(RA, MATPRODUCTALGORITHMDEFAULT));
1229566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(RA, fill));
1239566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(RA));
1249566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(RA));
1254222ddf1SHong Zhang 
1264222ddf1SHong Zhang   /* C = RA*R^T */
1279566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(C, MATPRODUCT_ABt));
1289566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(C, MATPRODUCTALGORITHMDEFAULT));
1294222ddf1SHong Zhang   product->A = RA;
1309566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(C));
1319566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(C));
1324222ddf1SHong Zhang 
1334222ddf1SHong Zhang   /* resume user's original input matrix setting for A */
134fe47926eSStefano Zampini   product->type          = MATPRODUCT_RARt;
1354222ddf1SHong Zhang   product->A             = A;
1364222ddf1SHong Zhang   product->Dwork         = RA; /* save here so it will be destroyed with product C */
1375415d71bSStefano Zampini   C->ops->productnumeric = MatProductNumeric_RARt_Unsafe;
1383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1394222ddf1SHong Zhang }
1404222ddf1SHong Zhang 
MatProductNumeric_ABC_Unsafe(Mat mat)141d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_ABC_Unsafe(Mat mat)
142d71ae5a4SJacob Faibussowitsch {
1434222ddf1SHong Zhang   Mat_Product *product = mat->product;
1444222ddf1SHong Zhang   Mat          A = product->A, BC = product->Dwork;
1454222ddf1SHong Zhang 
1464222ddf1SHong Zhang   PetscFunctionBegin;
1474222ddf1SHong Zhang   /* Numeric BC = B*C */
1489566063dSJacob Faibussowitsch   PetscCall(MatProductNumeric(BC));
1494222ddf1SHong Zhang   /* Numeric mat = A*BC */
150fe47926eSStefano Zampini   product->type = MATPRODUCT_AB;
1519566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmultnumeric)(A, BC, mat));
152fe47926eSStefano Zampini   product->type = MATPRODUCT_ABC;
1533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1544222ddf1SHong Zhang }
1554222ddf1SHong Zhang 
MatProductSymbolic_ABC_Unsafe(Mat mat)156d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_ABC_Unsafe(Mat mat)
157d71ae5a4SJacob Faibussowitsch {
1584222ddf1SHong Zhang   Mat_Product *product = mat->product;
1594222ddf1SHong Zhang   Mat          B = product->B, C = product->C, BC;
1604222ddf1SHong Zhang   PetscReal    fill = product->fill;
1614222ddf1SHong Zhang 
1624222ddf1SHong Zhang   PetscFunctionBegin;
163835f2295SStefano Zampini   PetscCall(PetscInfo(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));
1644222ddf1SHong Zhang   /* Symbolic BC = B*C */
1659566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(B, C, NULL, &BC));
1669566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(BC, MATPRODUCT_AB));
1679566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(BC, MATPRODUCTALGORITHMDEFAULT));
1689566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(BC, fill));
1699566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(BC));
1709566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(BC));
1714222ddf1SHong Zhang 
1724222ddf1SHong Zhang   /* Symbolic mat = A*BC */
1739566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(mat, MATPRODUCT_AB));
1749566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(mat, MATPRODUCTALGORITHMDEFAULT));
1754222ddf1SHong Zhang   product->B     = BC;
1764222ddf1SHong Zhang   product->Dwork = BC;
1779566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(mat));
1789566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(mat));
1794222ddf1SHong Zhang 
1804222ddf1SHong Zhang   /* resume user's original input matrix setting for B */
181fe47926eSStefano Zampini   product->type            = MATPRODUCT_ABC;
1824222ddf1SHong Zhang   product->B               = B;
1835415d71bSStefano Zampini   mat->ops->productnumeric = MatProductNumeric_ABC_Unsafe;
1843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1854222ddf1SHong Zhang }
1864222ddf1SHong Zhang 
MatProductSymbolic_Unsafe(Mat mat)187d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_Unsafe(Mat mat)
188d71ae5a4SJacob Faibussowitsch {
1894222ddf1SHong Zhang   Mat_Product *product = mat->product;
1904222ddf1SHong Zhang 
1914222ddf1SHong Zhang   PetscFunctionBegin;
1924222ddf1SHong Zhang   switch (product->type) {
193d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_PtAP:
194d71ae5a4SJacob Faibussowitsch     PetscCall(MatProductSymbolic_PtAP_Unsafe(mat));
195d71ae5a4SJacob Faibussowitsch     break;
196d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_RARt:
197d71ae5a4SJacob Faibussowitsch     PetscCall(MatProductSymbolic_RARt_Unsafe(mat));
198d71ae5a4SJacob Faibussowitsch     break;
199d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABC:
200d71ae5a4SJacob Faibussowitsch     PetscCall(MatProductSymbolic_ABC_Unsafe(mat));
201d71ae5a4SJacob Faibussowitsch     break;
202d71ae5a4SJacob Faibussowitsch   default:
203d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[product->type]);
2044222ddf1SHong Zhang   }
2053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2064222ddf1SHong Zhang }
2074222ddf1SHong Zhang 
208cb3ff29fSJose E. Roman /*@
20927430b45SBarry Smith   MatProductReplaceMats - Replace the input matrices for the matrix-matrix product operation inside the computed matrix
2104222ddf1SHong Zhang 
21127430b45SBarry Smith   Collective
2124222ddf1SHong Zhang 
2134222ddf1SHong Zhang   Input Parameters:
21427430b45SBarry Smith + A - the matrix or `NULL` if not being replaced
21527430b45SBarry Smith . B - the matrix or `NULL` if not being replaced
21627430b45SBarry Smith . C - the matrix or `NULL` if not being replaced
21727430b45SBarry Smith - D - the matrix whose values are computed via a matrix-matrix product operation
2184222ddf1SHong Zhang 
2194222ddf1SHong Zhang   Level: intermediate
2204222ddf1SHong Zhang 
22111a5261eSBarry Smith   Note:
22211a5261eSBarry Smith   To reuse the symbolic phase, the input matrices must have exactly the same data structure as the replaced one.
2231cdffd5eSHong Zhang   If the type of any of the input matrices is different than what was previously used, or their symmetry flag changed but
22427430b45SBarry Smith   the symbolic phase took advantage of their symmetry, the product is cleared and `MatProductSetFromOptions()`
22527430b45SBarry Smith   and `MatProductSymbolic()` are invoked again.
2264222ddf1SHong Zhang 
2270241b274SPierre Jolivet .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()`, `MatProductSetFromOptions()`, `MatProductSymbolic()`, `MatProductClear()`
2284222ddf1SHong Zhang @*/
MatProductReplaceMats(Mat A,Mat B,Mat C,Mat D)229d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductReplaceMats(Mat A, Mat B, Mat C, Mat D)
230d71ae5a4SJacob Faibussowitsch {
2316718818eSStefano Zampini   Mat_Product *product;
232b94d7dedSBarry Smith   PetscBool    flgA = PETSC_TRUE, flgB = PETSC_TRUE, flgC = PETSC_TRUE, isset, issym;
2334222ddf1SHong Zhang 
2344222ddf1SHong Zhang   PetscFunctionBegin;
2357a3c3d58SStefano Zampini   PetscValidHeaderSpecific(D, MAT_CLASSID, 4);
2366718818eSStefano Zampini   MatCheckProduct(D, 4);
2376718818eSStefano Zampini   product = D->product;
2384222ddf1SHong Zhang   if (A) {
2397a3c3d58SStefano Zampini     PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2409566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)A));
2419566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)product->A, ((PetscObject)A)->type_name, &flgA));
242b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(A, &isset, &issym));
243b94d7dedSBarry 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 */
244fa046f9fSJunchao Zhang       flgA                                           = PETSC_FALSE;
245fa046f9fSJunchao Zhang       product->symbolic_used_the_fact_A_is_symmetric = PETSC_FALSE; /* reinit */
246fa046f9fSJunchao Zhang     }
2479566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->A));
2484222ddf1SHong Zhang     product->A = A;
2494222ddf1SHong Zhang   }
2504222ddf1SHong Zhang   if (B) {
2517a3c3d58SStefano Zampini     PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
2529566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)B));
2539566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)product->B, ((PetscObject)B)->type_name, &flgB));
254b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(B, &isset, &issym));
255b94d7dedSBarry Smith     if (product->symbolic_used_the_fact_B_is_symmetric && isset && !issym) {
256fa046f9fSJunchao Zhang       flgB                                           = PETSC_FALSE;
257fa046f9fSJunchao Zhang       product->symbolic_used_the_fact_B_is_symmetric = PETSC_FALSE; /* reinit */
258fa046f9fSJunchao Zhang     }
2599566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->B));
2604222ddf1SHong Zhang     product->B = B;
2614222ddf1SHong Zhang   }
2624417c5e8SHong Zhang   if (C) {
2637a3c3d58SStefano Zampini     PetscValidHeaderSpecific(C, MAT_CLASSID, 3);
2649566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)C));
2659566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)product->C, ((PetscObject)C)->type_name, &flgC));
266b94d7dedSBarry Smith     PetscCall(MatIsSymmetricKnown(C, &isset, &issym));
267b94d7dedSBarry Smith     if (product->symbolic_used_the_fact_C_is_symmetric && isset && !issym) {
268fa046f9fSJunchao Zhang       flgC                                           = PETSC_FALSE;
269fa046f9fSJunchao Zhang       product->symbolic_used_the_fact_C_is_symmetric = PETSC_FALSE; /* reinit */
270fa046f9fSJunchao Zhang     }
2719566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->C));
2724417c5e8SHong Zhang     product->C = C;
2734417c5e8SHong Zhang   }
2746718818eSStefano Zampini   /* Any of the replaced mats is of a different type, reset */
2756718818eSStefano Zampini   if (!flgA || !flgB || !flgC) {
276cc1eb50dSBarry Smith     if (D->product->destroy) PetscCall((*D->product->destroy)(&D->product->data));
2776718818eSStefano Zampini     D->product->destroy = NULL;
2786718818eSStefano Zampini     D->product->data    = NULL;
2796718818eSStefano Zampini     if (D->ops->productnumeric || D->ops->productsymbolic) {
2809566063dSJacob Faibussowitsch       PetscCall(MatProductSetFromOptions(D));
2819566063dSJacob Faibussowitsch       PetscCall(MatProductSymbolic(D));
2826718818eSStefano Zampini     }
2836718818eSStefano Zampini   }
2843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2854222ddf1SHong Zhang }
2864222ddf1SHong Zhang 
MatProductNumeric_X_Dense(Mat C)287d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_X_Dense(Mat C)
288d71ae5a4SJacob Faibussowitsch {
2897a3c3d58SStefano Zampini   Mat_Product *product = C->product;
2907a3c3d58SStefano Zampini   Mat          A = product->A, B = product->B;
2917a3c3d58SStefano Zampini   PetscInt     k, K              = B->cmap->N;
2927a3c3d58SStefano Zampini   PetscBool    t = PETSC_TRUE, iscuda = PETSC_FALSE;
2937a3c3d58SStefano Zampini   PetscBool    Bcpu = PETSC_TRUE, Ccpu = PETSC_TRUE;
2947a3c3d58SStefano Zampini   char        *Btype = NULL, *Ctype = NULL;
2957a3c3d58SStefano Zampini 
2967a3c3d58SStefano Zampini   PetscFunctionBegin;
2977a3c3d58SStefano Zampini   switch (product->type) {
298d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AB:
299d71ae5a4SJacob Faibussowitsch     t = PETSC_FALSE;
300d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AtB:
301d71ae5a4SJacob Faibussowitsch     break;
302d71ae5a4SJacob Faibussowitsch   default:
303d71ae5a4SJacob Faibussowitsch     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);
3047a3c3d58SStefano Zampini   }
3057a3c3d58SStefano Zampini   if (PetscDefined(HAVE_CUDA)) {
3067a3c3d58SStefano Zampini     VecType vtype;
3077a3c3d58SStefano Zampini 
3089566063dSJacob Faibussowitsch     PetscCall(MatGetVecType(A, &vtype));
3099566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(vtype, VECCUDA, &iscuda));
31048a46eb9SPierre Jolivet     if (!iscuda) PetscCall(PetscStrcmp(vtype, VECSEQCUDA, &iscuda));
31148a46eb9SPierre Jolivet     if (!iscuda) PetscCall(PetscStrcmp(vtype, VECMPICUDA, &iscuda));
3127a3c3d58SStefano Zampini     if (iscuda) { /* Make sure we have up-to-date data on the GPU */
3139566063dSJacob Faibussowitsch       PetscCall(PetscStrallocpy(((PetscObject)B)->type_name, &Btype));
3149566063dSJacob Faibussowitsch       PetscCall(PetscStrallocpy(((PetscObject)C)->type_name, &Ctype));
3159566063dSJacob Faibussowitsch       PetscCall(MatConvert(B, MATDENSECUDA, MAT_INPLACE_MATRIX, &B));
3167a3c3d58SStefano Zampini       if (!C->assembled) { /* need to flag the matrix as assembled, otherwise MatConvert will complain */
3179566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
3189566063dSJacob Faibussowitsch         PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
3197a3c3d58SStefano Zampini       }
3209566063dSJacob Faibussowitsch       PetscCall(MatConvert(C, MATDENSECUDA, MAT_INPLACE_MATRIX, &C));
3217a3c3d58SStefano Zampini     } else { /* Make sure we have up-to-date data on the CPU */
3227a3c3d58SStefano Zampini #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_VIENNACL)
3237a3c3d58SStefano Zampini       Bcpu = B->boundtocpu;
3247a3c3d58SStefano Zampini       Ccpu = C->boundtocpu;
3257a3c3d58SStefano Zampini #endif
3269566063dSJacob Faibussowitsch       PetscCall(MatBindToCPU(B, PETSC_TRUE));
3279566063dSJacob Faibussowitsch       PetscCall(MatBindToCPU(C, PETSC_TRUE));
3287a3c3d58SStefano Zampini     }
3297a3c3d58SStefano Zampini   }
3307a3c3d58SStefano Zampini   for (k = 0; k < K; k++) {
3317a3c3d58SStefano Zampini     Vec x, y;
3327a3c3d58SStefano Zampini 
3339566063dSJacob Faibussowitsch     PetscCall(MatDenseGetColumnVecRead(B, k, &x));
3349566063dSJacob Faibussowitsch     PetscCall(MatDenseGetColumnVecWrite(C, k, &y));
3357a3c3d58SStefano Zampini     if (t) {
3369566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(A, x, y));
3377a3c3d58SStefano Zampini     } else {
3389566063dSJacob Faibussowitsch       PetscCall(MatMult(A, x, y));
3397a3c3d58SStefano Zampini     }
3409566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreColumnVecRead(B, k, &x));
3419566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreColumnVecWrite(C, k, &y));
3427a3c3d58SStefano Zampini   }
34367af85e8SPierre Jolivet   PetscCall(MatSetOption(C, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
3449566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
3459566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
3467a3c3d58SStefano Zampini   if (PetscDefined(HAVE_CUDA)) {
3477a3c3d58SStefano Zampini     if (iscuda) {
3489566063dSJacob Faibussowitsch       PetscCall(MatConvert(B, Btype, MAT_INPLACE_MATRIX, &B));
3499566063dSJacob Faibussowitsch       PetscCall(MatConvert(C, Ctype, MAT_INPLACE_MATRIX, &C));
3507a3c3d58SStefano Zampini     } else {
3519566063dSJacob Faibussowitsch       PetscCall(MatBindToCPU(B, Bcpu));
3529566063dSJacob Faibussowitsch       PetscCall(MatBindToCPU(C, Ccpu));
3537a3c3d58SStefano Zampini     }
3547a3c3d58SStefano Zampini   }
3559566063dSJacob Faibussowitsch   PetscCall(PetscFree(Btype));
3569566063dSJacob Faibussowitsch   PetscCall(PetscFree(Ctype));
3573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3587a3c3d58SStefano Zampini }
3597a3c3d58SStefano Zampini 
MatProductSymbolic_X_Dense(Mat C)360d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSymbolic_X_Dense(Mat C)
361d71ae5a4SJacob Faibussowitsch {
3627a3c3d58SStefano Zampini   Mat_Product *product = C->product;
3637a3c3d58SStefano Zampini   Mat          A = product->A, B = product->B;
3647a3c3d58SStefano Zampini   PetscBool    isdense;
3657a3c3d58SStefano Zampini 
3667a3c3d58SStefano Zampini   PetscFunctionBegin;
3677a3c3d58SStefano Zampini   switch (product->type) {
368d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AB:
369d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(C, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N));
370d71ae5a4SJacob Faibussowitsch     break;
371d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AtB:
372d71ae5a4SJacob Faibussowitsch     PetscCall(MatSetSizes(C, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N));
373d71ae5a4SJacob Faibussowitsch     break;
374d71ae5a4SJacob Faibussowitsch   default:
375d71ae5a4SJacob Faibussowitsch     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);
3767a3c3d58SStefano Zampini   }
3779566063dSJacob Faibussowitsch   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)C, &isdense, MATSEQDENSE, MATMPIDENSE, ""));
3787a3c3d58SStefano Zampini   if (!isdense) {
3799566063dSJacob Faibussowitsch     PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
3806718818eSStefano Zampini     /* If matrix type of C was not set or not dense, we need to reset the pointer */
3817a3c3d58SStefano Zampini     C->ops->productsymbolic = MatProductSymbolic_X_Dense;
3827a3c3d58SStefano Zampini   }
3836718818eSStefano Zampini   C->ops->productnumeric = MatProductNumeric_X_Dense;
3849566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
3853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3867a3c3d58SStefano Zampini }
3877a3c3d58SStefano Zampini 
3886718818eSStefano Zampini /* a single driver to query the dispatching */
MatProductSetFromOptions_Private(Mat mat)389d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Private(Mat mat)
390d71ae5a4SJacob Faibussowitsch {
3914222ddf1SHong Zhang   Mat_Product      *product = mat->product;
3926718818eSStefano Zampini   PetscInt          Am, An, Bm, Bn, Cm, Cn;
3934222ddf1SHong Zhang   Mat               A = product->A, B = product->B, C = product->C;
3946718818eSStefano Zampini   const char *const Bnames[] = {"B", "R", "P"};
3956718818eSStefano Zampini   const char       *bname;
3964222ddf1SHong Zhang   PetscErrorCode (*fA)(Mat);
3974222ddf1SHong Zhang   PetscErrorCode (*fB)(Mat);
3984222ddf1SHong Zhang   PetscErrorCode (*fC)(Mat);
3994222ddf1SHong Zhang   PetscErrorCode (*f)(Mat) = NULL;
4004222ddf1SHong Zhang 
4014222ddf1SHong Zhang   PetscFunctionBegin;
4026718818eSStefano Zampini   mat->ops->productsymbolic = NULL;
4036718818eSStefano Zampini   mat->ops->productnumeric  = NULL;
4043ba16761SJacob Faibussowitsch   if (product->type == MATPRODUCT_UNSPECIFIED) PetscFunctionReturn(PETSC_SUCCESS);
40528b400f6SJacob Faibussowitsch   PetscCheck(A, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing A mat");
40628b400f6SJacob Faibussowitsch   PetscCheck(B, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing B mat");
407072cda71SBarry Smith   PetscCheck(product->type != MATPRODUCT_ABC || C, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing C mat");
4086718818eSStefano Zampini   if (product->type != MATPRODUCT_ABC) C = NULL; /* do not use C if not needed */
4096718818eSStefano Zampini   if (product->type == MATPRODUCT_RARt) bname = Bnames[1];
4106718818eSStefano Zampini   else if (product->type == MATPRODUCT_PtAP) bname = Bnames[2];
4116718818eSStefano Zampini   else bname = Bnames[0];
4126718818eSStefano Zampini 
4136718818eSStefano Zampini   /* Check matrices sizes */
4146718818eSStefano Zampini   Am = A->rmap->N;
4156718818eSStefano Zampini   An = A->cmap->N;
4166718818eSStefano Zampini   Bm = B->rmap->N;
4176718818eSStefano Zampini   Bn = B->cmap->N;
4186718818eSStefano Zampini   Cm = C ? C->rmap->N : 0;
4196718818eSStefano Zampini   Cn = C ? C->cmap->N : 0;
4209371c9d4SSatish Balay   if (product->type == MATPRODUCT_RARt || product->type == MATPRODUCT_ABt) {
4219371c9d4SSatish Balay     PetscInt t = Bn;
4229371c9d4SSatish Balay     Bn         = Bm;
4239371c9d4SSatish Balay     Bm         = t;
4249371c9d4SSatish Balay   }
425dd460d27SBarry Smith   if (product->type == MATPRODUCT_AtB) An = Am;
426dd460d27SBarry Smith 
4279371c9d4SSatish 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,
4289371c9d4SSatish Balay              MatProductTypes[product->type], A->rmap->N, A->cmap->N, bname, B->rmap->N, B->cmap->N);
4299371c9d4SSatish 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,
4309371c9d4SSatish Balay              MatProductTypes[product->type], B->rmap->N, B->cmap->N, Cm, Cn);
4314222ddf1SHong Zhang 
4324222ddf1SHong Zhang   fA = A->ops->productsetfromoptions;
4334222ddf1SHong Zhang   fB = B->ops->productsetfromoptions;
4346718818eSStefano Zampini   fC = C ? C->ops->productsetfromoptions : fA;
4356718818eSStefano Zampini   if (C) {
4369566063dSJacob 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));
4376718818eSStefano Zampini   } else {
4389566063dSJacob Faibussowitsch     PetscCall(PetscInfo(mat, "MatProductType %s for A %s, %s %s\n", MatProductTypes[product->type], ((PetscObject)A)->type_name, bname, ((PetscObject)B)->type_name));
4396718818eSStefano Zampini   }
4404222ddf1SHong Zhang   if (fA == fB && fA == fC && fA) {
4419566063dSJacob Faibussowitsch     PetscCall(PetscInfo(mat, "  matching op\n"));
4429566063dSJacob Faibussowitsch     PetscCall((*fA)(mat));
4438d7b260cSStefano Zampini   }
4448d7b260cSStefano Zampini   /* We may have found f but it did not succeed */
4458d7b260cSStefano Zampini   if (!mat->ops->productsymbolic) { /* query MatProductSetFromOptions_Atype_Btype_Ctype */
4464222ddf1SHong Zhang     char mtypes[256];
4479566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(mtypes, "MatProductSetFromOptions_", sizeof(mtypes)));
4489566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(mtypes, ((PetscObject)A)->type_name, sizeof(mtypes)));
4499566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(mtypes, "_", sizeof(mtypes)));
4509566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(mtypes, ((PetscObject)B)->type_name, sizeof(mtypes)));
4516718818eSStefano Zampini     if (C) {
4529566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(mtypes, "_", sizeof(mtypes)));
4539566063dSJacob Faibussowitsch       PetscCall(PetscStrlcat(mtypes, ((PetscObject)C)->type_name, sizeof(mtypes)));
4546718818eSStefano Zampini     }
4559566063dSJacob Faibussowitsch     PetscCall(PetscStrlcat(mtypes, "_C", sizeof(mtypes)));
45615943bb8SPierre Jolivet #if defined(__clang__)
457a8f51744SPierre Jolivet     PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wformat-pedantic")
45815943bb8SPierre Jolivet #elif defined(__GNUC__) || defined(__GNUG__)
459a8f51744SPierre Jolivet     PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wformat")
46015943bb8SPierre Jolivet #endif
4619566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f));
4629566063dSJacob Faibussowitsch     PetscCall(PetscInfo(mat, "  querying %s from A? %p\n", mtypes, f));
4634222ddf1SHong Zhang     if (!f) {
4649566063dSJacob Faibussowitsch       PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f));
4659566063dSJacob Faibussowitsch       PetscCall(PetscInfo(mat, "  querying %s from %s? %p\n", mtypes, bname, f));
4664222ddf1SHong Zhang     }
4676718818eSStefano Zampini     if (!f && C) {
4689566063dSJacob Faibussowitsch       PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f));
4699566063dSJacob Faibussowitsch       PetscCall(PetscInfo(mat, "  querying %s from C? %p\n", mtypes, f));
4704222ddf1SHong Zhang     }
4719566063dSJacob Faibussowitsch     if (f) PetscCall((*f)(mat));
4726718818eSStefano Zampini 
4736718818eSStefano Zampini     /* We may have found f but it did not succeed */
474013e2dc7SBarry Smith     /* some matrices (i.e. MATTRANSPOSEVIRTUAL, MATSHELL constructed from MatConvert), knows what to do with their inner matrices */
4756718818eSStefano Zampini     if (!mat->ops->productsymbolic) {
4769566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(mtypes, "MatProductSetFromOptions_anytype_C", sizeof(mtypes)));
4779566063dSJacob Faibussowitsch       PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f));
4789566063dSJacob Faibussowitsch       PetscCall(PetscInfo(mat, "  querying %s from A? %p\n", mtypes, f));
4796718818eSStefano Zampini       if (!f) {
4809566063dSJacob Faibussowitsch         PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f));
4819566063dSJacob Faibussowitsch         PetscCall(PetscInfo(mat, "  querying %s from %s? %p\n", mtypes, bname, f));
4826718818eSStefano Zampini       }
4836718818eSStefano Zampini       if (!f && C) {
4849566063dSJacob Faibussowitsch         PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f));
4859566063dSJacob Faibussowitsch         PetscCall(PetscInfo(mat, "  querying %s from C? %p\n", mtypes, f));
4866718818eSStefano Zampini       }
4876718818eSStefano Zampini     }
4889566063dSJacob Faibussowitsch     if (f) PetscCall((*f)(mat));
4894222ddf1SHong Zhang   }
490a8f51744SPierre Jolivet   PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END()
4916718818eSStefano Zampini   /* We may have found f but it did not succeed */
4926718818eSStefano Zampini   if (!mat->ops->productsymbolic) {
4936718818eSStefano Zampini     /* we can still compute the product if B is of type dense */
4946718818eSStefano Zampini     if (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB) {
4956718818eSStefano Zampini       PetscBool isdense;
4966718818eSStefano Zampini 
4979566063dSJacob Faibussowitsch       PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)B, &isdense, MATSEQDENSE, MATMPIDENSE, ""));
4986718818eSStefano Zampini       if (isdense) {
4996718818eSStefano Zampini         mat->ops->productsymbolic = MatProductSymbolic_X_Dense;
5009566063dSJacob Faibussowitsch         PetscCall(PetscInfo(mat, "  using basic looping over columns of a dense matrix\n"));
5016718818eSStefano Zampini       }
5025415d71bSStefano Zampini     } else if (product->type != MATPRODUCT_ABt) { /* use MatProductSymbolic/Numeric_Unsafe() for triple products only */
5036718818eSStefano Zampini       /*
5046718818eSStefano Zampini          TODO: this should be changed to a proper setfromoptions, not setting the symbolic pointer here, because we do not know if
5058d7b260cSStefano Zampini                the combination will succeed. In order to be sure, we need MatProductGetProductType to return the type of the result
5066718818eSStefano Zampini                before computing the symbolic phase
5076718818eSStefano Zampini       */
5089566063dSJacob Faibussowitsch       PetscCall(PetscInfo(mat, "  symbolic product not supported, using MatProductSymbolic_Unsafe() implementation\n"));
5095415d71bSStefano Zampini       mat->ops->productsymbolic = MatProductSymbolic_Unsafe;
5104222ddf1SHong Zhang     }
5116718818eSStefano Zampini   }
51248a46eb9SPierre Jolivet   if (!mat->ops->productsymbolic) PetscCall(PetscInfo(mat, "  symbolic product is not supported\n"));
5133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5144222ddf1SHong Zhang }
5154222ddf1SHong Zhang 
516cb3ff29fSJose E. Roman /*@
51727430b45SBarry Smith   MatProductSetFromOptions - Sets the options for the computation of a matrix-matrix product operation where the type,
51827430b45SBarry Smith   the algorithm etc are determined from the options database.
5194222ddf1SHong Zhang 
52027430b45SBarry Smith   Logically Collective
5214222ddf1SHong Zhang 
5224222ddf1SHong Zhang   Input Parameter:
52327430b45SBarry Smith . mat - the matrix whose values are computed via a matrix-matrix product operation
5244222ddf1SHong Zhang 
5252ef1f0ffSBarry Smith   Options Database Keys:
5262ef1f0ffSBarry Smith + -mat_product_clear                 - Clear intermediate data structures after `MatProductNumeric()` has been called
5272ef1f0ffSBarry Smith . -mat_product_algorithm <algorithm> - Sets the algorithm, see `MatProductAlgorithm` for possible values
5282ef1f0ffSBarry Smith - -mat_product_algorithm_backend_cpu - Use the CPU to perform the computation even if the matrix is a GPU matrix
5294222ddf1SHong Zhang 
5306718818eSStefano Zampini   Level: intermediate
5316718818eSStefano Zampini 
53227430b45SBarry Smith   Note:
5332ef1f0ffSBarry Smith   The `-mat_product_clear` option reduces memory usage but means that the matrix cannot be re-used for a matrix-matrix product operation
53427430b45SBarry Smith 
5351cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatSetFromOptions()`, `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductNumeric()`,
5362ef1f0ffSBarry Smith           `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductAlgorithm`
5374222ddf1SHong Zhang @*/
MatProductSetFromOptions(Mat mat)538d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSetFromOptions(Mat mat)
539d71ae5a4SJacob Faibussowitsch {
5404222ddf1SHong Zhang   PetscFunctionBegin;
5414222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5426718818eSStefano Zampini   MatCheckProduct(mat, 1);
543a0228903SHong Zhang   PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot call MatProductSetFromOptions() with already present data");
544a0228903SHong Zhang   mat->product->setfromoptionscalled = PETSC_TRUE;
545d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)mat);
5469566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-mat_product_clear", "Clear intermediate data structures after MatProductNumeric() has been called", "MatProductClear", mat->product->clear, &mat->product->clear, NULL));
5479566063dSJacob Faibussowitsch   PetscCall(PetscOptionsDeprecated("-mat_freeintermediatedatastructures", "-mat_product_clear", "3.13", "Or call MatProductClear() after MatProductNumeric()"));
548d0609cedSBarry Smith   PetscOptionsEnd();
5499566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions_Private(mat));
55028b400f6SJacob Faibussowitsch   PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing product after setup phase");
5513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5526718818eSStefano Zampini }
5536718818eSStefano Zampini 
554ffeef943SBarry Smith /*@
55527430b45SBarry Smith   MatProductView - View the private matrix-matrix algorithm object within a matrix
5566718818eSStefano Zampini 
557c3339decSBarry Smith   Logically Collective
5586718818eSStefano Zampini 
55967be906fSBarry Smith   Input Parameters:
56067be906fSBarry Smith + mat    - the matrix obtained with `MatProductCreate()` or `MatProductCreateWithMat()`
5612ef1f0ffSBarry Smith - viewer - where the information on the matrix-matrix algorithm of `mat` should be reviewed
5626718818eSStefano Zampini 
5636718818eSStefano Zampini   Level: intermediate
5646718818eSStefano Zampini 
565ffeef943SBarry Smith   Developer Note:
566d7c1f440SPierre Jolivet   Shouldn't this information be printed from an appropriate `MatView()` with perhaps certain formats set?
567ffeef943SBarry Smith 
5681cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProductType`, `Mat`, `MatProductSetFromOptions()`, `MatView()`, `MatProductCreate()`, `MatProductCreateWithMat()`
5696718818eSStefano Zampini @*/
MatProductView(Mat mat,PetscViewer viewer)570d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductView(Mat mat, PetscViewer viewer)
571d71ae5a4SJacob Faibussowitsch {
5726718818eSStefano Zampini   PetscFunctionBegin;
5736718818eSStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5743ba16761SJacob Faibussowitsch   if (!mat->product) PetscFunctionReturn(PETSC_SUCCESS);
5759566063dSJacob Faibussowitsch   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer));
5766718818eSStefano Zampini   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
5776718818eSStefano Zampini   PetscCheckSameComm(mat, 1, viewer, 2);
5781baa6e33SBarry Smith   if (mat->product->view) PetscCall((*mat->product->view)(mat, viewer));
5793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5804222ddf1SHong Zhang }
5814222ddf1SHong Zhang 
5826718818eSStefano Zampini /* these are basic implementations relying on the old function pointers
5836718818eSStefano Zampini  * they are dangerous and should be removed in the future */
MatProductNumeric_AB(Mat mat)584d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductNumeric_AB(Mat mat)
585d71ae5a4SJacob Faibussowitsch {
5864222ddf1SHong Zhang   Mat_Product *product = mat->product;
5874222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
5884222ddf1SHong Zhang 
5894222ddf1SHong Zhang   PetscFunctionBegin;
5909566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmultnumeric)(A, B, mat));
5913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5924222ddf1SHong Zhang }
5934222ddf1SHong Zhang 
MatProductNumeric_AtB(Mat mat)594d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductNumeric_AtB(Mat mat)
595d71ae5a4SJacob Faibussowitsch {
5964222ddf1SHong Zhang   Mat_Product *product = mat->product;
5974222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
5984222ddf1SHong Zhang 
5994222ddf1SHong Zhang   PetscFunctionBegin;
6009566063dSJacob Faibussowitsch   PetscCall((*mat->ops->transposematmultnumeric)(A, B, mat));
6013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6024222ddf1SHong Zhang }
6034222ddf1SHong Zhang 
MatProductNumeric_ABt(Mat mat)604d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductNumeric_ABt(Mat mat)
605d71ae5a4SJacob Faibussowitsch {
6064222ddf1SHong Zhang   Mat_Product *product = mat->product;
6074222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
6084222ddf1SHong Zhang 
6094222ddf1SHong Zhang   PetscFunctionBegin;
6109566063dSJacob Faibussowitsch   PetscCall((*mat->ops->mattransposemultnumeric)(A, B, mat));
6113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6124222ddf1SHong Zhang }
6134222ddf1SHong Zhang 
MatProductNumeric_PtAP(Mat mat)614d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductNumeric_PtAP(Mat mat)
615d71ae5a4SJacob Faibussowitsch {
6164222ddf1SHong Zhang   Mat_Product *product = mat->product;
6174222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
6184222ddf1SHong Zhang 
6194222ddf1SHong Zhang   PetscFunctionBegin;
6209566063dSJacob Faibussowitsch   PetscCall((*mat->ops->ptapnumeric)(A, B, mat));
6213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6224222ddf1SHong Zhang }
6234222ddf1SHong Zhang 
MatProductNumeric_RARt(Mat mat)624d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductNumeric_RARt(Mat mat)
625d71ae5a4SJacob Faibussowitsch {
6264222ddf1SHong Zhang   Mat_Product *product = mat->product;
6274222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
6284222ddf1SHong Zhang 
6294222ddf1SHong Zhang   PetscFunctionBegin;
6309566063dSJacob Faibussowitsch   PetscCall((*mat->ops->rartnumeric)(A, B, mat));
6313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6324222ddf1SHong Zhang }
6334222ddf1SHong Zhang 
MatProductNumeric_ABC(Mat mat)634d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductNumeric_ABC(Mat mat)
635d71ae5a4SJacob Faibussowitsch {
6364222ddf1SHong Zhang   Mat_Product *product = mat->product;
6374222ddf1SHong Zhang   Mat          A = product->A, B = product->B, C = product->C;
6384222ddf1SHong Zhang 
6394222ddf1SHong Zhang   PetscFunctionBegin;
6409566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmatmultnumeric)(A, B, C, mat));
6413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6424222ddf1SHong Zhang }
6434222ddf1SHong Zhang 
6444222ddf1SHong Zhang /*@
6452ef1f0ffSBarry Smith   MatProductNumeric - Compute a matrix-matrix product operation with the numerical values
6464222ddf1SHong Zhang 
647c3339decSBarry Smith   Collective
6484222ddf1SHong Zhang 
6496718818eSStefano Zampini   Input/Output Parameter:
65027430b45SBarry Smith . mat - the matrix whose values are computed via a matrix-matrix product operation
6514222ddf1SHong Zhang 
6524222ddf1SHong Zhang   Level: intermediate
6534222ddf1SHong Zhang 
65411a5261eSBarry Smith   Note:
65527430b45SBarry Smith   `MatProductSymbolic()` must have been called on `mat` before calling this function
6566718818eSStefano Zampini 
6571cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductSetAlgorithm()`, `MatProductSetType()`, `MatProductCreate()`, `MatSetType()`, `MatProductSymbolic()`
6584222ddf1SHong Zhang @*/
MatProductNumeric(Mat mat)659d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductNumeric(Mat mat)
660d71ae5a4SJacob Faibussowitsch {
661e017e560SStefano Zampini   PetscLogEvent eventtype = -1;
6624222ddf1SHong Zhang 
6634222ddf1SHong Zhang   PetscFunctionBegin;
6644222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6656718818eSStefano Zampini   MatCheckProduct(mat, 1);
666e017e560SStefano Zampini   switch (mat->product->type) {
667d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AB:
668d71ae5a4SJacob Faibussowitsch     eventtype = MAT_MatMultNumeric;
669d71ae5a4SJacob Faibussowitsch     break;
670d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AtB:
671d71ae5a4SJacob Faibussowitsch     eventtype = MAT_TransposeMatMultNumeric;
672d71ae5a4SJacob Faibussowitsch     break;
673d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABt:
674d71ae5a4SJacob Faibussowitsch     eventtype = MAT_MatTransposeMultNumeric;
675d71ae5a4SJacob Faibussowitsch     break;
676d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_PtAP:
677d71ae5a4SJacob Faibussowitsch     eventtype = MAT_PtAPNumeric;
678d71ae5a4SJacob Faibussowitsch     break;
679d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_RARt:
680d71ae5a4SJacob Faibussowitsch     eventtype = MAT_RARtNumeric;
681d71ae5a4SJacob Faibussowitsch     break;
682d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABC:
683d71ae5a4SJacob Faibussowitsch     eventtype = MAT_MatMatMultNumeric;
684d71ae5a4SJacob Faibussowitsch     break;
685d71ae5a4SJacob Faibussowitsch   default:
686d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]);
687e017e560SStefano Zampini   }
6888d7b260cSStefano Zampini 
6894222ddf1SHong Zhang   if (mat->ops->productnumeric) {
6909566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0));
691dbbe0bcdSBarry Smith     PetscUseTypeMethod(mat, productnumeric);
6929566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0));
693cf3d31aeSPierre Jolivet   } else if (mat->product) {
6942e105a96SStefano Zampini     char errstr[256];
6952e105a96SStefano Zampini 
6962e105a96SStefano Zampini     if (mat->product->type == MATPRODUCT_ABC) {
6979566063dSJacob 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));
6982e105a96SStefano Zampini     } else {
6999566063dSJacob 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));
7002e105a96SStefano Zampini     }
701cf3d31aeSPierre Jolivet     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified numeric phase for product %s", errstr);
7022e105a96SStefano Zampini   }
703cf3d31aeSPierre Jolivet   PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after numeric phase for product");
7042e105a96SStefano Zampini 
7051baa6e33SBarry Smith   if (mat->product->clear) PetscCall(MatProductClear(mat));
7069566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
7073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7084222ddf1SHong Zhang }
7094222ddf1SHong Zhang 
7106718818eSStefano Zampini /* these are basic implementations relying on the old function pointers
7116718818eSStefano Zampini  * they are dangerous and should be removed in the future */
MatProductSymbolic_AB(Mat mat)712d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSymbolic_AB(Mat mat)
713d71ae5a4SJacob Faibussowitsch {
7144222ddf1SHong Zhang   Mat_Product *product = mat->product;
7154222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
7164222ddf1SHong Zhang 
7174222ddf1SHong Zhang   PetscFunctionBegin;
7189566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmultsymbolic)(A, B, product->fill, mat));
7194222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_AB;
7203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7214222ddf1SHong Zhang }
7224222ddf1SHong Zhang 
MatProductSymbolic_AtB(Mat mat)723d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSymbolic_AtB(Mat mat)
724d71ae5a4SJacob Faibussowitsch {
7254222ddf1SHong Zhang   Mat_Product *product = mat->product;
7264222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
7274222ddf1SHong Zhang 
7284222ddf1SHong Zhang   PetscFunctionBegin;
7299566063dSJacob Faibussowitsch   PetscCall((*mat->ops->transposematmultsymbolic)(A, B, product->fill, mat));
7304222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_AtB;
7313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7324222ddf1SHong Zhang }
7334222ddf1SHong Zhang 
MatProductSymbolic_ABt(Mat mat)734d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSymbolic_ABt(Mat mat)
735d71ae5a4SJacob Faibussowitsch {
7364222ddf1SHong Zhang   Mat_Product *product = mat->product;
7374222ddf1SHong Zhang   Mat          A = product->A, B = product->B;
7384222ddf1SHong Zhang 
7394222ddf1SHong Zhang   PetscFunctionBegin;
7409566063dSJacob Faibussowitsch   PetscCall((*mat->ops->mattransposemultsymbolic)(A, B, product->fill, mat));
7414222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_ABt;
7423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7434222ddf1SHong Zhang }
7444222ddf1SHong Zhang 
MatProductSymbolic_ABC(Mat mat)745d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSymbolic_ABC(Mat mat)
746d71ae5a4SJacob Faibussowitsch {
7474222ddf1SHong Zhang   Mat_Product *product = mat->product;
7484222ddf1SHong Zhang   Mat          A = product->A, B = product->B, C = product->C;
7494222ddf1SHong Zhang 
7504222ddf1SHong Zhang   PetscFunctionBegin;
7519566063dSJacob Faibussowitsch   PetscCall((*mat->ops->matmatmultsymbolic)(A, B, C, product->fill, mat));
7524222ddf1SHong Zhang   mat->ops->productnumeric = MatProductNumeric_ABC;
7533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7544222ddf1SHong Zhang }
7554222ddf1SHong Zhang 
7564222ddf1SHong Zhang /*@
7572ef1f0ffSBarry Smith   MatProductSymbolic - Perform the symbolic portion of a matrix-matrix product operation, this creates a data structure for use with the numerical
7582ef1f0ffSBarry Smith   product to be done with `MatProductNumeric()`
7594222ddf1SHong Zhang 
760c3339decSBarry Smith   Collective
7614222ddf1SHong Zhang 
7626718818eSStefano Zampini   Input/Output Parameter:
7632ef1f0ffSBarry Smith . mat - the matrix whose values are to be computed via a matrix-matrix product operation
7644222ddf1SHong Zhang 
7654222ddf1SHong Zhang   Level: intermediate
7664222ddf1SHong Zhang 
76711a5261eSBarry Smith   Note:
76827430b45SBarry Smith   `MatProductSetFromOptions()` must have been called on `mat` before calling this function
7696718818eSStefano Zampini 
7701cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductSetFromOptions()`, `MatProductNumeric()`, `MatProductSetType()`, `MatProductSetAlgorithm()`
7714222ddf1SHong Zhang @*/
MatProductSymbolic(Mat mat)772d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSymbolic(Mat mat)
773d71ae5a4SJacob Faibussowitsch {
7744222ddf1SHong Zhang   PetscLogEvent eventtype = -1;
7752e105a96SStefano Zampini   PetscBool     missing   = PETSC_FALSE;
77639cfb508SMark Adams   Mat_Product  *product   = mat->product;
77739cfb508SMark Adams   Mat           A         = product->A;
77839cfb508SMark Adams   Mat           B         = product->B;
77939cfb508SMark Adams   Mat           C         = product->C;
7804222ddf1SHong Zhang 
7814222ddf1SHong Zhang   PetscFunctionBegin;
7824222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7836718818eSStefano Zampini   MatCheckProduct(mat, 1);
78428b400f6SJacob Faibussowitsch   PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot run symbolic phase. Product data not empty");
7856718818eSStefano Zampini   switch (mat->product->type) {
786d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AB:
787d71ae5a4SJacob Faibussowitsch     eventtype = MAT_MatMultSymbolic;
788d71ae5a4SJacob Faibussowitsch     break;
789d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_AtB:
790d71ae5a4SJacob Faibussowitsch     eventtype = MAT_TransposeMatMultSymbolic;
791d71ae5a4SJacob Faibussowitsch     break;
792d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABt:
793d71ae5a4SJacob Faibussowitsch     eventtype = MAT_MatTransposeMultSymbolic;
794d71ae5a4SJacob Faibussowitsch     break;
795d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_PtAP:
796d71ae5a4SJacob Faibussowitsch     eventtype = MAT_PtAPSymbolic;
797d71ae5a4SJacob Faibussowitsch     break;
798d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_RARt:
799d71ae5a4SJacob Faibussowitsch     eventtype = MAT_RARtSymbolic;
800d71ae5a4SJacob Faibussowitsch     break;
801d71ae5a4SJacob Faibussowitsch   case MATPRODUCT_ABC:
802d71ae5a4SJacob Faibussowitsch     eventtype = MAT_MatMatMultSymbolic;
803d71ae5a4SJacob Faibussowitsch     break;
804d71ae5a4SJacob Faibussowitsch   default:
805d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]);
8064222ddf1SHong Zhang   }
8076718818eSStefano Zampini   mat->ops->productnumeric = NULL;
8084222ddf1SHong Zhang   if (mat->ops->productsymbolic) {
8099566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0));
810dbbe0bcdSBarry Smith     PetscUseTypeMethod(mat, productsymbolic);
8119566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0));
8122e105a96SStefano Zampini   } else missing = PETSC_TRUE;
8132e105a96SStefano Zampini   if (missing || !mat->product || !mat->ops->productnumeric) {
8142e105a96SStefano Zampini     char errstr[256];
8152e105a96SStefano Zampini 
8162e105a96SStefano Zampini     if (mat->product->type == MATPRODUCT_ABC) {
8179566063dSJacob 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));
8182e105a96SStefano Zampini     } else {
8199566063dSJacob 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));
8202e105a96SStefano Zampini     }
821a0228903SHong Zhang     PetscCheck(mat->product->setfromoptionscalled, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified symbolic phase for product %s. Call MatProductSetFromOptions() first", errstr);
822a0228903SHong Zhang     PetscCheck(!missing, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Unspecified symbolic phase for product %s. The product is not supported", errstr);
82328b400f6SJacob Faibussowitsch     PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after symbolic phase for product %s", errstr);
8242e105a96SStefano Zampini   }
8253742c8caSstefanozampini #if defined(PETSC_HAVE_DEVICE)
8263742c8caSstefanozampini   PetscBool bindingpropagates;
8273742c8caSstefanozampini   bindingpropagates = (PetscBool)((A->boundtocpu && A->bindingpropagates) || (B->boundtocpu && B->bindingpropagates));
8283742c8caSstefanozampini   if (C) bindingpropagates = (PetscBool)(bindingpropagates || (C->boundtocpu && C->bindingpropagates));
8293742c8caSstefanozampini   if (bindingpropagates) {
8303742c8caSstefanozampini     PetscCall(MatBindToCPU(mat, PETSC_TRUE));
8313742c8caSstefanozampini     PetscCall(MatSetBindingPropagates(mat, PETSC_TRUE));
8323742c8caSstefanozampini   }
8333742c8caSstefanozampini #endif
83439cfb508SMark Adams   /* set block sizes */
83539cfb508SMark Adams   switch (product->type) {
83639cfb508SMark Adams   case MATPRODUCT_PtAP:
83739cfb508SMark Adams     if (B->cmap->bs > 1) PetscCall(MatSetBlockSizes(mat, B->cmap->bs, B->cmap->bs));
83839cfb508SMark Adams     break;
83939cfb508SMark Adams   case MATPRODUCT_RARt:
84039cfb508SMark Adams     if (B->rmap->bs > 1) PetscCall(MatSetBlockSizes(mat, B->rmap->bs, B->rmap->bs));
84139cfb508SMark Adams     break;
84239cfb508SMark Adams   case MATPRODUCT_ABC:
84339cfb508SMark Adams     PetscCall(MatSetBlockSizesFromMats(mat, A, C));
84439cfb508SMark Adams     break;
84539cfb508SMark Adams   case MATPRODUCT_AB:
84639cfb508SMark Adams     PetscCall(MatSetBlockSizesFromMats(mat, A, B));
84739cfb508SMark Adams     break;
84839cfb508SMark Adams   case MATPRODUCT_AtB:
84939cfb508SMark Adams     if (A->cmap->bs > 1 || B->cmap->bs > 1) PetscCall(MatSetBlockSizes(mat, A->cmap->bs, B->cmap->bs));
85039cfb508SMark Adams     break;
85139cfb508SMark Adams   case MATPRODUCT_ABt:
85239cfb508SMark Adams     if (A->rmap->bs > 1 || B->rmap->bs > 1) PetscCall(MatSetBlockSizes(mat, A->rmap->bs, B->rmap->bs));
85339cfb508SMark Adams     break;
85439cfb508SMark Adams   default:
85539cfb508SMark Adams     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Not for ProductType %s", MatProductTypes[product->type]);
85639cfb508SMark Adams   }
8573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8584222ddf1SHong Zhang }
8594222ddf1SHong Zhang 
8604222ddf1SHong Zhang /*@
86127430b45SBarry Smith   MatProductSetFill - Set an expected fill of the matrix whose values are computed via a matrix-matrix product operation
8624222ddf1SHong Zhang 
86327430b45SBarry Smith   Collective
8644222ddf1SHong Zhang 
8654222ddf1SHong Zhang   Input Parameters:
8662ef1f0ffSBarry Smith + mat  - the matrix whose values are to be computed via a matrix-matrix product operation
867fb842aefSJose E. Roman - fill - expected fill as ratio of nnz(mat)/(nnz(A) + nnz(B) + nnz(C)); use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate.
86827430b45SBarry Smith          If the product is a dense matrix, this value is not used.
8694222ddf1SHong Zhang 
8704222ddf1SHong Zhang   Level: intermediate
8714222ddf1SHong Zhang 
872fb842aefSJose E. Roman   Notes:
873fb842aefSJose E. Roman   Use `fill` of `PETSC_DETERMINE` to use the default value.
874fb842aefSJose E. Roman 
875fb842aefSJose E. Roman   The deprecated `PETSC_DEFAULT` is also supported to mean use the current value.
876fb842aefSJose E. Roman 
877fb842aefSJose E. Roman .seealso: [](ch_matrices), `MatProduct`, `PETSC_DETERMINE`, `Mat`, `MatProductSetFromOptions()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()`
8784222ddf1SHong Zhang @*/
MatProductSetFill(Mat mat,PetscReal fill)879d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSetFill(Mat mat, PetscReal fill)
880d71ae5a4SJacob Faibussowitsch {
8814222ddf1SHong Zhang   PetscFunctionBegin;
8824222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8836718818eSStefano Zampini   MatCheckProduct(mat, 1);
884fb842aefSJose E. Roman   if (fill == (PetscReal)PETSC_DETERMINE) mat->product->fill = mat->product->default_fill;
885fb842aefSJose E. Roman   else if (fill != (PetscReal)PETSC_CURRENT) mat->product->fill = fill;
8863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8874222ddf1SHong Zhang }
8884222ddf1SHong Zhang 
8895d83a8b1SBarry Smith /*@
89027430b45SBarry Smith   MatProductSetAlgorithm - Requests a particular algorithm for a matrix-matrix product operation that will perform to compute the given matrix
8914222ddf1SHong Zhang 
892c3339decSBarry Smith   Collective
8934222ddf1SHong Zhang 
8944222ddf1SHong Zhang   Input Parameters:
89527430b45SBarry Smith + mat - the matrix whose values are computed via a matrix-matrix product operation
896f5368d60SBarry Smith - alg - particular implementation algorithm of the matrix product, e.g., `MATPRODUCTALGORITHMDEFAULT`.
8973e662e0bSHong Zhang 
8983e662e0bSHong Zhang   Options Database Key:
8992ef1f0ffSBarry Smith . -mat_product_algorithm <algorithm> - Sets the algorithm, see `MatProductAlgorithm`
9004222ddf1SHong Zhang 
9014222ddf1SHong Zhang   Level: intermediate
9024222ddf1SHong Zhang 
9038fcac130SJose E. Roman .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductClear()`, `MatProductSetType()`, `MatProductSetFill()`, `MatProductCreate()`, `MatProductAlgorithm`, `MatProductType`, `MatProductGetAlgorithm()`
9044222ddf1SHong Zhang @*/
MatProductSetAlgorithm(Mat mat,MatProductAlgorithm alg)905d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSetAlgorithm(Mat mat, MatProductAlgorithm alg)
906d71ae5a4SJacob Faibussowitsch {
9074222ddf1SHong Zhang   PetscFunctionBegin;
9084222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9096718818eSStefano Zampini   MatCheckProduct(mat, 1);
9109566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->product->alg));
9119566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(alg, &mat->product->alg));
9123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9134222ddf1SHong Zhang }
9144222ddf1SHong Zhang 
9155d83a8b1SBarry Smith /*@
9168fcac130SJose E. Roman   MatProductGetAlgorithm - Returns the selected algorithm for a matrix-matrix product operation
9178fcac130SJose E. Roman 
9188fcac130SJose E. Roman   Not Collective
9198fcac130SJose E. Roman 
9208fcac130SJose E. Roman   Input Parameter:
9218fcac130SJose E. Roman . mat - the matrix whose values are computed via a matrix-matrix product operation
9228fcac130SJose E. Roman 
9238fcac130SJose E. Roman   Output Parameter:
9248fcac130SJose E. Roman . alg - the selected algorithm of the matrix product, e.g., `MATPRODUCTALGORITHMDEFAULT`.
9258fcac130SJose E. Roman 
9268fcac130SJose E. Roman   Level: intermediate
9278fcac130SJose E. Roman 
9288fcac130SJose E. Roman .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductSetAlgorithm()`
9298fcac130SJose E. Roman @*/
MatProductGetAlgorithm(Mat mat,MatProductAlgorithm * alg)9308fcac130SJose E. Roman PetscErrorCode MatProductGetAlgorithm(Mat mat, MatProductAlgorithm *alg)
9318fcac130SJose E. Roman {
9328fcac130SJose E. Roman   PetscFunctionBegin;
9338fcac130SJose E. Roman   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9348fcac130SJose E. Roman   PetscAssertPointer(alg, 2);
9358fcac130SJose E. Roman   if (mat->product) *alg = mat->product->alg;
9368fcac130SJose E. Roman   else *alg = NULL;
9378fcac130SJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
9388fcac130SJose E. Roman }
9398fcac130SJose E. Roman 
9404222ddf1SHong Zhang /*@
94127430b45SBarry Smith   MatProductSetType - Sets a particular matrix-matrix product operation to be used to compute the values of the given matrix
9424222ddf1SHong Zhang 
943c3339decSBarry Smith   Collective
9444222ddf1SHong Zhang 
9454222ddf1SHong Zhang   Input Parameters:
94627430b45SBarry Smith + mat        - the matrix whose values are computed via a matrix-matrix product operation
9472ef1f0ffSBarry Smith - productype - matrix product type, e.g., `MATPRODUCT_AB`,`MATPRODUCT_AtB`,`MATPRODUCT_ABt`,`MATPRODUCT_PtAP`,`MATPRODUCT_RARt`,`MATPRODUCT_ABC`,
9482ef1f0ffSBarry Smith                see `MatProductType`
9494222ddf1SHong Zhang 
9504222ddf1SHong Zhang   Level: intermediate
9514222ddf1SHong Zhang 
952f5368d60SBarry Smith   Note:
95311a5261eSBarry Smith   The small t represents the transpose operation.
954f5368d60SBarry Smith 
955fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()`, `MatProductType`,
95611a5261eSBarry Smith           `MATPRODUCT_AB`, `MATPRODUCT_AtB`, `MATPRODUCT_ABt`, `MATPRODUCT_PtAP`, `MATPRODUCT_RARt`, `MATPRODUCT_ABC`
9574222ddf1SHong Zhang @*/
MatProductSetType(Mat mat,MatProductType productype)958d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSetType(Mat mat, MatProductType productype)
959d71ae5a4SJacob Faibussowitsch {
9604222ddf1SHong Zhang   PetscFunctionBegin;
9614222ddf1SHong Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9626718818eSStefano Zampini   MatCheckProduct(mat, 1);
9637a3c3d58SStefano Zampini   PetscValidLogicalCollectiveEnum(mat, productype, 2);
9646718818eSStefano Zampini   if (productype != mat->product->type) {
965cc1eb50dSBarry Smith     if (mat->product->destroy) PetscCall((*mat->product->destroy)(&mat->product->data));
9666718818eSStefano Zampini     mat->product->destroy     = NULL;
9676718818eSStefano Zampini     mat->product->data        = NULL;
9686718818eSStefano Zampini     mat->ops->productsymbolic = NULL;
9696718818eSStefano Zampini     mat->ops->productnumeric  = NULL;
9706718818eSStefano Zampini   }
9716718818eSStefano Zampini   mat->product->type = productype;
9723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9734222ddf1SHong Zhang }
9744222ddf1SHong Zhang 
9754417c5e8SHong Zhang /*@
9762ef1f0ffSBarry Smith   MatProductClear - Clears from the matrix any internal data structures related to the computation of the values of the matrix from matrix-matrix product operations
9774417c5e8SHong Zhang 
978c3339decSBarry Smith   Collective
9794417c5e8SHong Zhang 
9802fe279fdSBarry Smith   Input Parameter:
9812ef1f0ffSBarry Smith . mat - the matrix whose values are to be computed via a matrix-matrix product operation
98227430b45SBarry Smith 
98327430b45SBarry Smith   Options Database Key:
98427430b45SBarry Smith . -mat_product_clear - Clear intermediate data structures after `MatProductNumeric()` has been called
9854417c5e8SHong Zhang 
9864417c5e8SHong Zhang   Level: intermediate
9876718818eSStefano Zampini 
988f5368d60SBarry Smith   Notes:
989f5368d60SBarry Smith   This function should be called to remove any intermediate data used to compute the matrix to free up memory.
990f5368d60SBarry Smith 
99127430b45SBarry Smith   After having called this function, matrix-matrix product operations can no longer be used on `mat`
992f5368d60SBarry Smith 
9937da3f0dfSBarry Smith   Developer Note:
9947da3f0dfSBarry Smith   This frees the `Mat_Product` context that was attached to the matrix during `MatProductCreate()` or `MatProductCreateWithMat()`
9957da3f0dfSBarry Smith 
9961cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()`
9974417c5e8SHong Zhang @*/
MatProductClear(Mat mat)998d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductClear(Mat mat)
999d71ae5a4SJacob Faibussowitsch {
10004417c5e8SHong Zhang   Mat_Product *product = mat->product;
10014417c5e8SHong Zhang 
10024417c5e8SHong Zhang   PetscFunctionBegin;
10037a3c3d58SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10044417c5e8SHong Zhang   if (product) {
10059566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->A));
10069566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->B));
10079566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->C));
10089566063dSJacob Faibussowitsch     PetscCall(PetscFree(product->alg));
10099566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->Dwork));
1010cc1eb50dSBarry Smith     if (product->destroy) PetscCall((*product->destroy)(&product->data));
10116718818eSStefano Zampini   }
10129566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->product));
10136718818eSStefano Zampini   mat->ops->productsymbolic = NULL;
10146718818eSStefano Zampini   mat->ops->productnumeric  = NULL;
10153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10164417c5e8SHong Zhang }
10174417c5e8SHong Zhang 
10184222ddf1SHong Zhang /* Create a supporting struct and attach it to the matrix product */
MatProductCreate_Private(Mat A,Mat B,Mat C,Mat D)1019d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductCreate_Private(Mat A, Mat B, Mat C, Mat D)
1020d71ae5a4SJacob Faibussowitsch {
10214222ddf1SHong Zhang   Mat_Product *product = NULL;
10224222ddf1SHong Zhang 
10234222ddf1SHong Zhang   PetscFunctionBegin;
10246718818eSStefano Zampini   PetscValidHeaderSpecific(D, MAT_CLASSID, 4);
102528b400f6SJacob Faibussowitsch   PetscCheck(!D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product already present");
10264dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&product));
10274222ddf1SHong Zhang   product->A                    = A;
10284222ddf1SHong Zhang   product->B                    = B;
10294222ddf1SHong Zhang   product->C                    = C;
10306718818eSStefano Zampini   product->type                 = MATPRODUCT_UNSPECIFIED;
10314222ddf1SHong Zhang   product->Dwork                = NULL;
10324222ddf1SHong Zhang   product->api_user             = PETSC_FALSE;
10336718818eSStefano Zampini   product->clear                = PETSC_FALSE;
1034a0228903SHong Zhang   product->setfromoptionscalled = PETSC_FALSE;
1035fb842aefSJose E. Roman   PetscObjectParameterSetDefault(product, fill, 2);
10364222ddf1SHong Zhang   D->product = product;
10374417c5e8SHong Zhang 
10389566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(D, MATPRODUCTALGORITHMDEFAULT));
10399566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(D, PETSC_DEFAULT));
10407a3c3d58SStefano Zampini 
10419566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)A));
10429566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)B));
10439566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)C));
10443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10454222ddf1SHong Zhang }
10464222ddf1SHong Zhang 
10474222ddf1SHong Zhang /*@
10482ef1f0ffSBarry Smith   MatProductCreateWithMat - Set a given matrix to have its values computed via matrix-matrix operations on other matrices.
10494222ddf1SHong Zhang 
105027430b45SBarry Smith   Collective
10514222ddf1SHong Zhang 
10524222ddf1SHong Zhang   Input Parameters:
10534222ddf1SHong Zhang + A - the first matrix
10544222ddf1SHong Zhang . B - the second matrix
105567be906fSBarry Smith . C - the third matrix (optional, use `NULL` if not needed)
10562ef1f0ffSBarry Smith - D - the matrix whose values are to be computed via a matrix-matrix product operation
10574222ddf1SHong Zhang 
105867be906fSBarry Smith   Level: intermediate
10594222ddf1SHong Zhang 
10606718818eSStefano Zampini   Notes:
10617da3f0dfSBarry Smith   Use `MatProductCreate()` if the matrix you wish computed `D` does not exist
1062f5368d60SBarry Smith 
106327430b45SBarry Smith   See `MatProductCreate()` for details on the usage of the matrix-matrix product operations
1064f5368d60SBarry Smith 
10657da3f0dfSBarry Smith   Any product data currently attached to `D` will be freed
10666718818eSStefano Zampini 
10671cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductType`, `MatProductSetType()`, `MatProductAlgorithm`,
10682ef1f0ffSBarry Smith           `MatProductSetAlgorithm`, `MatProductCreate()`, `MatProductClear()`
10694222ddf1SHong Zhang @*/
MatProductCreateWithMat(Mat A,Mat B,Mat C,Mat D)1070d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductCreateWithMat(Mat A, Mat B, Mat C, Mat D)
1071d71ae5a4SJacob Faibussowitsch {
10724222ddf1SHong Zhang   PetscFunctionBegin;
10734222ddf1SHong Zhang   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
10744222ddf1SHong Zhang   PetscValidType(A, 1);
10754222ddf1SHong Zhang   MatCheckPreallocated(A, 1);
107628b400f6SJacob Faibussowitsch   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
107728b400f6SJacob Faibussowitsch   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10784222ddf1SHong Zhang 
10794222ddf1SHong Zhang   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
10804222ddf1SHong Zhang   PetscValidType(B, 2);
10814222ddf1SHong Zhang   MatCheckPreallocated(B, 2);
108228b400f6SJacob Faibussowitsch   PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
108328b400f6SJacob Faibussowitsch   PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10844222ddf1SHong Zhang 
10854222ddf1SHong Zhang   if (C) {
10864222ddf1SHong Zhang     PetscValidHeaderSpecific(C, MAT_CLASSID, 3);
10874222ddf1SHong Zhang     PetscValidType(C, 3);
10884222ddf1SHong Zhang     MatCheckPreallocated(C, 3);
108928b400f6SJacob Faibussowitsch     PetscCheck(C->assembled, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
109028b400f6SJacob Faibussowitsch     PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10914222ddf1SHong Zhang   }
10924222ddf1SHong Zhang 
10934222ddf1SHong Zhang   PetscValidHeaderSpecific(D, MAT_CLASSID, 4);
10944222ddf1SHong Zhang   PetscValidType(D, 4);
10954222ddf1SHong Zhang   MatCheckPreallocated(D, 4);
109628b400f6SJacob Faibussowitsch   PetscCheck(D->assembled, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
109728b400f6SJacob Faibussowitsch   PetscCheck(!D->factortype, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10984222ddf1SHong Zhang 
10994222ddf1SHong Zhang   /* Create a supporting struct and attach it to D */
11009566063dSJacob Faibussowitsch   PetscCall(MatProductClear(D));
11019566063dSJacob Faibussowitsch   PetscCall(MatProductCreate_Private(A, B, C, D));
11023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11034222ddf1SHong Zhang }
11044222ddf1SHong Zhang 
11054222ddf1SHong Zhang /*@
11067da3f0dfSBarry Smith   MatProductCreate - create a matrix to hold the result of a matrix-matrix (or matrix-matrix-matrix) product operation
11074222ddf1SHong Zhang 
110827430b45SBarry Smith   Collective
11094222ddf1SHong Zhang 
11104222ddf1SHong Zhang   Input Parameters:
11114222ddf1SHong Zhang + A - the first matrix
11124222ddf1SHong Zhang . B - the second matrix
11132ef1f0ffSBarry Smith - C - the third matrix (or `NULL`)
11144222ddf1SHong Zhang 
11152fe279fdSBarry Smith   Output Parameter:
11162ef1f0ffSBarry Smith . D - the matrix whose values are to be computed via a matrix-matrix product operation
11174222ddf1SHong Zhang 
11184222ddf1SHong Zhang   Level: intermediate
11194222ddf1SHong Zhang 
112027430b45SBarry Smith   Example:
1121f5368d60SBarry Smith .vb
112211a5261eSBarry Smith     MatProductCreate(A,B,C,&D); or MatProductCreateWithMat(A,B,C,D)
112311a5261eSBarry Smith     MatProductSetType(D, MATPRODUCT_AB or MATPRODUCT_AtB or MATPRODUCT_ABt or MATPRODUCT_PtAP or MATPRODUCT_RARt or MATPRODUCT_ABC)
112411a5261eSBarry Smith     MatProductSetAlgorithm(D, alg)
112511a5261eSBarry Smith     MatProductSetFill(D,fill)
112611a5261eSBarry Smith     MatProductSetFromOptions(D)
112711a5261eSBarry Smith     MatProductSymbolic(D)
112811a5261eSBarry Smith     MatProductNumeric(D)
1129f5368d60SBarry Smith     Change numerical values in some of the matrices
113011a5261eSBarry Smith     MatProductNumeric(D)
1131f5368d60SBarry Smith .ve
1132f5368d60SBarry Smith 
1133f5368d60SBarry Smith   Notes:
11347da3f0dfSBarry Smith   Use `MatProductCreateWithMat()` if `D` the matrix you wish computed already exists.
1135f5368d60SBarry Smith 
11367da3f0dfSBarry Smith   The information computed during the symbolic stage can be reused for new numerical computations with the same non-zero structure of the input matrices.
1137f5368d60SBarry Smith 
1138fe59aa6dSJacob Faibussowitsch   Developer Notes:
1139f5368d60SBarry Smith   It is undocumented what happens if the nonzero structure of the input matrices changes. Is the symbolic stage automatically redone? Does it crash?
1140f5368d60SBarry Smith   Is there error checking for it?
1141f5368d60SBarry Smith 
11427da3f0dfSBarry Smith   On this call, auxiliary data needed to compute the product is stored in `D` in a `Mat_Product` context. A call to `MatProductClear()` frees this
11437da3f0dfSBarry Smith   information.
11447da3f0dfSBarry Smith 
11457da3f0dfSBarry Smith   Each `MatProductAlgorithm` associated with a particular `MatType` stores additional data needed for the product computation
11467da3f0dfSBarry Smith   (generally this data is computed in `MatProductSymbolic()`) inside the `Mat_Product` context in a `MatProductCtx_XXX` data structure
11477da3f0dfSBarry Smith   and provides a `MatProductCtxDestroy_XXX()` routine to free that data. The `MatProductAlgorithm` and `MatType` specific destroy routine is called by
11487da3f0dfSBarry Smith   `MatProductClear()`.
11497da3f0dfSBarry Smith 
11507da3f0dfSBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductClear()`,
11517da3f0dfSBarry Smith           `MatProductSymbolic()`, `MatProductNumeric()`, `MatProductAlgorithm`, `MatProductType`
11524222ddf1SHong Zhang @*/
MatProductCreate(Mat A,Mat B,Mat C,Mat * D)1153d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductCreate(Mat A, Mat B, Mat C, Mat *D)
1154d71ae5a4SJacob Faibussowitsch {
11554222ddf1SHong Zhang   PetscFunctionBegin;
11564222ddf1SHong Zhang   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11574222ddf1SHong Zhang   PetscValidType(A, 1);
11584222ddf1SHong Zhang   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
11594222ddf1SHong Zhang   PetscValidType(B, 2);
116028b400f6SJacob Faibussowitsch   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix A");
116128b400f6SJacob Faibussowitsch   PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix B");
11624222ddf1SHong Zhang 
11634222ddf1SHong Zhang   if (C) {
11644222ddf1SHong Zhang     PetscValidHeaderSpecific(C, MAT_CLASSID, 3);
11654222ddf1SHong Zhang     PetscValidType(C, 3);
116628b400f6SJacob Faibussowitsch     PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix C");
11674222ddf1SHong Zhang   }
11684222ddf1SHong Zhang 
11694f572ea9SToby Isaac   PetscAssertPointer(D, 4);
11709566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), D));
117130203840SJunchao Zhang   /* Delay setting type of D to the MatProduct symbolic phase, as we allow sparse A and dense B */
11729566063dSJacob Faibussowitsch   PetscCall(MatProductCreate_Private(A, B, C, *D));
11733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11744222ddf1SHong Zhang }
11755415d71bSStefano Zampini 
11765415d71bSStefano Zampini /*
11775415d71bSStefano Zampini    These are safe basic implementations of ABC, RARt and PtAP
11785415d71bSStefano Zampini    that do not rely on mat->ops->matmatop function pointers.
11795415d71bSStefano Zampini    They only use the MatProduct API and are currently used by
11805415d71bSStefano Zampini    cuSPARSE and KOKKOS-KERNELS backends
11815415d71bSStefano Zampini */
1182ec446438SStefano Zampini typedef struct {
11835415d71bSStefano Zampini   Mat BC;
11845415d71bSStefano Zampini   Mat ABC;
1185cc1eb50dSBarry Smith } MatProductCtx_MatMatMatPrivate;
11865415d71bSStefano Zampini 
MatProductCtxDestroy_MatMatMatPrivate(PetscCtxRt data)1187*2a8381b2SBarry Smith static PetscErrorCode MatProductCtxDestroy_MatMatMatPrivate(PetscCtxRt data)
1188d71ae5a4SJacob Faibussowitsch {
1189cc1eb50dSBarry Smith   MatProductCtx_MatMatMatPrivate *mmdata = *(MatProductCtx_MatMatMatPrivate **)data;
11905415d71bSStefano Zampini 
11915415d71bSStefano Zampini   PetscFunctionBegin;
11929566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->BC));
11939566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->ABC));
1194*2a8381b2SBarry Smith   PetscCall(PetscFree(mmdata));
11953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11965415d71bSStefano Zampini }
11975415d71bSStefano Zampini 
MatProductNumeric_ABC_Basic(Mat mat)1198d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat)
1199d71ae5a4SJacob Faibussowitsch {
12005415d71bSStefano Zampini   Mat_Product                    *product = mat->product;
1201cc1eb50dSBarry Smith   MatProductCtx_MatMatMatPrivate *mmabc;
12025415d71bSStefano Zampini 
12035415d71bSStefano Zampini   PetscFunctionBegin;
12045415d71bSStefano Zampini   MatCheckProduct(mat, 1);
120528b400f6SJacob Faibussowitsch   PetscCheck(mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data empty");
1206cc1eb50dSBarry Smith   mmabc = (MatProductCtx_MatMatMatPrivate *)mat->product->data;
120728b400f6SJacob Faibussowitsch   PetscCheck(mmabc->BC->ops->productnumeric, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing numeric stage");
1208ec446438SStefano Zampini   /* use function pointer directly to prevent logging */
12099566063dSJacob Faibussowitsch   PetscCall((*mmabc->BC->ops->productnumeric)(mmabc->BC));
12105415d71bSStefano Zampini   /* swap ABC product stuff with that of ABC for the numeric phase on mat */
12115415d71bSStefano Zampini   mat->product             = mmabc->ABC->product;
12125415d71bSStefano Zampini   mat->ops->productnumeric = mmabc->ABC->ops->productnumeric;
1213ec446438SStefano Zampini   /* use function pointer directly to prevent logging */
1214dbbe0bcdSBarry Smith   PetscUseTypeMethod(mat, productnumeric);
12155415d71bSStefano Zampini   mat->ops->productnumeric = MatProductNumeric_ABC_Basic;
12165415d71bSStefano Zampini   mat->product             = product;
12173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12185415d71bSStefano Zampini }
12195415d71bSStefano Zampini 
MatProductSymbolic_ABC_Basic(Mat mat)1220d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat)
1221d71ae5a4SJacob Faibussowitsch {
12225415d71bSStefano Zampini   Mat_Product                    *product = mat->product;
12235415d71bSStefano Zampini   Mat                             A, B, C;
12245415d71bSStefano Zampini   MatProductType                  p1, p2;
1225cc1eb50dSBarry Smith   MatProductCtx_MatMatMatPrivate *mmabc;
122665e4b4d4SStefano Zampini   const char                     *prefix;
12275415d71bSStefano Zampini 
12285415d71bSStefano Zampini   PetscFunctionBegin;
12295415d71bSStefano Zampini   MatCheckProduct(mat, 1);
123028b400f6SJacob Faibussowitsch   PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data not empty");
12319566063dSJacob Faibussowitsch   PetscCall(MatGetOptionsPrefix(mat, &prefix));
12329566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mmabc));
12335415d71bSStefano Zampini   product->data    = mmabc;
1234cc1eb50dSBarry Smith   product->destroy = MatProductCtxDestroy_MatMatMatPrivate;
12355415d71bSStefano Zampini   switch (product->type) {
12365415d71bSStefano Zampini   case MATPRODUCT_PtAP:
12375415d71bSStefano Zampini     p1 = MATPRODUCT_AB;
12385415d71bSStefano Zampini     p2 = MATPRODUCT_AtB;
12395415d71bSStefano Zampini     A  = product->B;
12405415d71bSStefano Zampini     B  = product->A;
12415415d71bSStefano Zampini     C  = product->B;
124239cfb508SMark Adams     if (A->cmap->bs > 0 && C->cmap->bs > 0) PetscCall(MatSetBlockSizes(mat, A->cmap->bs, C->cmap->bs));
12435415d71bSStefano Zampini     break;
12445415d71bSStefano Zampini   case MATPRODUCT_RARt:
12455415d71bSStefano Zampini     p1 = MATPRODUCT_ABt;
12465415d71bSStefano Zampini     p2 = MATPRODUCT_AB;
12475415d71bSStefano Zampini     A  = product->B;
12485415d71bSStefano Zampini     B  = product->A;
12495415d71bSStefano Zampini     C  = product->B;
125039cfb508SMark Adams     if (A->rmap->bs > 0 && C->rmap->bs > 0) PetscCall(MatSetBlockSizes(mat, A->rmap->bs, C->rmap->bs));
12515415d71bSStefano Zampini     break;
12525415d71bSStefano Zampini   case MATPRODUCT_ABC:
12535415d71bSStefano Zampini     p1 = MATPRODUCT_AB;
12545415d71bSStefano Zampini     p2 = MATPRODUCT_AB;
12555415d71bSStefano Zampini     A  = product->A;
12565415d71bSStefano Zampini     B  = product->B;
12575415d71bSStefano Zampini     C  = product->C;
12580e6a1e94SMark Adams     PetscCall(MatSetBlockSizesFromMats(mat, A, C));
12595415d71bSStefano Zampini     break;
1260d71ae5a4SJacob Faibussowitsch   default:
1261d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Not for ProductType %s", MatProductTypes[product->type]);
12625415d71bSStefano Zampini   }
12639566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(B, C, NULL, &mmabc->BC));
12649566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(mmabc->BC, prefix));
12659566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(mmabc->BC, "P1_"));
12669566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(mmabc->BC, p1));
12679566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(mmabc->BC, MATPRODUCTALGORITHMDEFAULT));
12689566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(mmabc->BC, product->fill));
12695415d71bSStefano Zampini   mmabc->BC->product->api_user = product->api_user;
12709566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(mmabc->BC));
127128b400f6SJacob 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);
1272bfcc3627SStefano Zampini   /* use function pointer directly to prevent logging */
12739566063dSJacob Faibussowitsch   PetscCall((*mmabc->BC->ops->productsymbolic)(mmabc->BC));
12745415d71bSStefano Zampini 
12759566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(A, mmabc->BC, NULL, &mmabc->ABC));
12769566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(mmabc->ABC, prefix));
12779566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(mmabc->ABC, "P2_"));
12789566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(mmabc->ABC, p2));
12799566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(mmabc->ABC, MATPRODUCTALGORITHMDEFAULT));
12809566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(mmabc->ABC, product->fill));
12815415d71bSStefano Zampini   mmabc->ABC->product->api_user = product->api_user;
12829566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(mmabc->ABC));
128328b400f6SJacob 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);
12845415d71bSStefano Zampini   /* swap ABC product stuff with that of ABC for the symbolic phase on mat */
12855415d71bSStefano Zampini   mat->product              = mmabc->ABC->product;
12865415d71bSStefano Zampini   mat->ops->productsymbolic = mmabc->ABC->ops->productsymbolic;
1287bfcc3627SStefano Zampini   /* use function pointer directly to prevent logging */
1288dbbe0bcdSBarry Smith   PetscUseTypeMethod(mat, productsymbolic);
12895415d71bSStefano Zampini   mmabc->ABC->ops->productnumeric = mat->ops->productnumeric;
12905415d71bSStefano Zampini   mat->ops->productsymbolic       = MatProductSymbolic_ABC_Basic;
12915415d71bSStefano Zampini   mat->ops->productnumeric        = MatProductNumeric_ABC_Basic;
12925415d71bSStefano Zampini   mat->product                    = product;
12933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12945415d71bSStefano Zampini }
1295c600787bSStefano Zampini 
1296c600787bSStefano Zampini /*@
12972ef1f0ffSBarry Smith   MatProductGetType - Returns the type of matrix-matrix product associated with computing values for the given matrix
1298c600787bSStefano Zampini 
129927430b45SBarry Smith   Not Collective
1300c600787bSStefano Zampini 
1301c600787bSStefano Zampini   Input Parameter:
13022ef1f0ffSBarry Smith . mat - the matrix whose values are to be computed via a matrix-matrix product operation
1303c600787bSStefano Zampini 
1304c600787bSStefano Zampini   Output Parameter:
130511a5261eSBarry Smith . mtype - the `MatProductType`
1306c600787bSStefano Zampini 
1307c600787bSStefano Zampini   Level: intermediate
1308c600787bSStefano Zampini 
13091cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductCreate()`, `MatProductType`, `MatProductAlgorithm`
1310c600787bSStefano Zampini @*/
MatProductGetType(Mat mat,MatProductType * mtype)1311d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductGetType(Mat mat, MatProductType *mtype)
1312d71ae5a4SJacob Faibussowitsch {
1313c600787bSStefano Zampini   PetscFunctionBegin;
1314c600787bSStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
13154f572ea9SToby Isaac   PetscAssertPointer(mtype, 2);
1316c600787bSStefano Zampini   *mtype = MATPRODUCT_UNSPECIFIED;
1317c600787bSStefano Zampini   if (mat->product) *mtype = mat->product->type;
13183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1319c600787bSStefano Zampini }
1320c600787bSStefano Zampini 
1321c600787bSStefano Zampini /*@
13222ef1f0ffSBarry Smith   MatProductGetMats - Returns the matrices associated with the matrix-matrix product associated with computing values for the given matrix
1323c600787bSStefano Zampini 
132427430b45SBarry Smith   Not Collective
1325c600787bSStefano Zampini 
1326c600787bSStefano Zampini   Input Parameter:
13272ef1f0ffSBarry Smith . mat - the matrix whose values are to be computed via a matrix-matrix product operation
1328c600787bSStefano Zampini 
1329c600787bSStefano Zampini   Output Parameters:
1330c600787bSStefano Zampini + A - the first matrix
1331c600787bSStefano Zampini . B - the second matrix
13322ef1f0ffSBarry Smith - C - the third matrix (may be `NULL` for some `MatProductType`)
1333c600787bSStefano Zampini 
1334c600787bSStefano Zampini   Level: intermediate
1335c600787bSStefano Zampini 
13361cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()`
1337c600787bSStefano Zampini @*/
MatProductGetMats(Mat mat,Mat * A,Mat * B,Mat * C)1338d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductGetMats(Mat mat, Mat *A, Mat *B, Mat *C)
1339d71ae5a4SJacob Faibussowitsch {
1340c600787bSStefano Zampini   PetscFunctionBegin;
1341c600787bSStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1342c600787bSStefano Zampini   if (A) *A = mat->product ? mat->product->A : NULL;
1343c600787bSStefano Zampini   if (B) *B = mat->product ? mat->product->B : NULL;
1344c600787bSStefano Zampini   if (C) *C = mat->product ? mat->product->C : NULL;
13453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1346c600787bSStefano Zampini }
1347