xref: /petsc/src/mat/interface/matproduct.c (revision cc1eb50d5a4d6061e906552df09a79d2d9d16af2)
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 */
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 
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 
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 
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 
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 
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 
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 @*/
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) {
276*cc1eb50dSBarry 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 
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 
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 */
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 @*/
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 @*/
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 */
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 
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 
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 
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 
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 
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 @*/
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 */
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 
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 
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 
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 @*/
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 @*/
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 @*/
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 @*/
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 @*/
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) {
965*cc1eb50dSBarry 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 
9931cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()`
9944417c5e8SHong Zhang @*/
995d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductClear(Mat mat)
996d71ae5a4SJacob Faibussowitsch {
9974417c5e8SHong Zhang   Mat_Product *product = mat->product;
9984417c5e8SHong Zhang 
9994417c5e8SHong Zhang   PetscFunctionBegin;
10007a3c3d58SStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10014417c5e8SHong Zhang   if (product) {
10029566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->A));
10039566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->B));
10049566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->C));
10059566063dSJacob Faibussowitsch     PetscCall(PetscFree(product->alg));
10069566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&product->Dwork));
1007*cc1eb50dSBarry Smith     if (product->destroy) PetscCall((*product->destroy)(&product->data));
10086718818eSStefano Zampini   }
10099566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->product));
10106718818eSStefano Zampini   mat->ops->productsymbolic = NULL;
10116718818eSStefano Zampini   mat->ops->productnumeric  = NULL;
10123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10134417c5e8SHong Zhang }
10144417c5e8SHong Zhang 
10154222ddf1SHong Zhang /* Create a supporting struct and attach it to the matrix product */
1016d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductCreate_Private(Mat A, Mat B, Mat C, Mat D)
1017d71ae5a4SJacob Faibussowitsch {
10184222ddf1SHong Zhang   Mat_Product *product = NULL;
10194222ddf1SHong Zhang 
10204222ddf1SHong Zhang   PetscFunctionBegin;
10216718818eSStefano Zampini   PetscValidHeaderSpecific(D, MAT_CLASSID, 4);
102228b400f6SJacob Faibussowitsch   PetscCheck(!D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product already present");
10234dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&product));
10244222ddf1SHong Zhang   product->A                    = A;
10254222ddf1SHong Zhang   product->B                    = B;
10264222ddf1SHong Zhang   product->C                    = C;
10276718818eSStefano Zampini   product->type                 = MATPRODUCT_UNSPECIFIED;
10284222ddf1SHong Zhang   product->Dwork                = NULL;
10294222ddf1SHong Zhang   product->api_user             = PETSC_FALSE;
10306718818eSStefano Zampini   product->clear                = PETSC_FALSE;
1031a0228903SHong Zhang   product->setfromoptionscalled = PETSC_FALSE;
1032fb842aefSJose E. Roman   PetscObjectParameterSetDefault(product, fill, 2);
10334222ddf1SHong Zhang   D->product = product;
10344417c5e8SHong Zhang 
10359566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(D, MATPRODUCTALGORITHMDEFAULT));
10369566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(D, PETSC_DEFAULT));
10377a3c3d58SStefano Zampini 
10389566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)A));
10399566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)B));
10409566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)C));
10413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10424222ddf1SHong Zhang }
10434222ddf1SHong Zhang 
10444222ddf1SHong Zhang /*@
10452ef1f0ffSBarry Smith   MatProductCreateWithMat - Set a given matrix to have its values computed via matrix-matrix operations on other matrices.
10464222ddf1SHong Zhang 
104727430b45SBarry Smith   Collective
10484222ddf1SHong Zhang 
10494222ddf1SHong Zhang   Input Parameters:
10504222ddf1SHong Zhang + A - the first matrix
10514222ddf1SHong Zhang . B - the second matrix
105267be906fSBarry Smith . C - the third matrix (optional, use `NULL` if not needed)
10532ef1f0ffSBarry Smith - D - the matrix whose values are to be computed via a matrix-matrix product operation
10544222ddf1SHong Zhang 
105567be906fSBarry Smith   Level: intermediate
10564222ddf1SHong Zhang 
10576718818eSStefano Zampini   Notes:
105827430b45SBarry Smith   Use `MatProductCreate()` if the matrix you wish computed (the `D` matrix) does not already exist
1059f5368d60SBarry Smith 
106027430b45SBarry Smith   See `MatProductCreate()` for details on the usage of the matrix-matrix product operations
1061f5368d60SBarry Smith 
106267be906fSBarry Smith   Any product data currently attached to `D` will be cleared
10636718818eSStefano Zampini 
10641cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductType`, `MatProductSetType()`, `MatProductAlgorithm`,
10652ef1f0ffSBarry Smith           `MatProductSetAlgorithm`, `MatProductCreate()`, `MatProductClear()`
10664222ddf1SHong Zhang @*/
1067d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductCreateWithMat(Mat A, Mat B, Mat C, Mat D)
1068d71ae5a4SJacob Faibussowitsch {
10694222ddf1SHong Zhang   PetscFunctionBegin;
10704222ddf1SHong Zhang   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
10714222ddf1SHong Zhang   PetscValidType(A, 1);
10724222ddf1SHong Zhang   MatCheckPreallocated(A, 1);
107328b400f6SJacob Faibussowitsch   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
107428b400f6SJacob Faibussowitsch   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10754222ddf1SHong Zhang 
10764222ddf1SHong Zhang   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
10774222ddf1SHong Zhang   PetscValidType(B, 2);
10784222ddf1SHong Zhang   MatCheckPreallocated(B, 2);
107928b400f6SJacob Faibussowitsch   PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
108028b400f6SJacob Faibussowitsch   PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10814222ddf1SHong Zhang 
10824222ddf1SHong Zhang   if (C) {
10834222ddf1SHong Zhang     PetscValidHeaderSpecific(C, MAT_CLASSID, 3);
10844222ddf1SHong Zhang     PetscValidType(C, 3);
10854222ddf1SHong Zhang     MatCheckPreallocated(C, 3);
108628b400f6SJacob Faibussowitsch     PetscCheck(C->assembled, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
108728b400f6SJacob Faibussowitsch     PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10884222ddf1SHong Zhang   }
10894222ddf1SHong Zhang 
10904222ddf1SHong Zhang   PetscValidHeaderSpecific(D, MAT_CLASSID, 4);
10914222ddf1SHong Zhang   PetscValidType(D, 4);
10924222ddf1SHong Zhang   MatCheckPreallocated(D, 4);
109328b400f6SJacob Faibussowitsch   PetscCheck(D->assembled, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
109428b400f6SJacob Faibussowitsch   PetscCheck(!D->factortype, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10954222ddf1SHong Zhang 
10964222ddf1SHong Zhang   /* Create a supporting struct and attach it to D */
10979566063dSJacob Faibussowitsch   PetscCall(MatProductClear(D));
10989566063dSJacob Faibussowitsch   PetscCall(MatProductCreate_Private(A, B, C, D));
10993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11004222ddf1SHong Zhang }
11014222ddf1SHong Zhang 
11024222ddf1SHong Zhang /*@
110311a5261eSBarry Smith   MatProductCreate - create a matrix to hold the result of a matrix-matrix product operation
11044222ddf1SHong Zhang 
110527430b45SBarry Smith   Collective
11064222ddf1SHong Zhang 
11074222ddf1SHong Zhang   Input Parameters:
11084222ddf1SHong Zhang + A - the first matrix
11094222ddf1SHong Zhang . B - the second matrix
11102ef1f0ffSBarry Smith - C - the third matrix (or `NULL`)
11114222ddf1SHong Zhang 
11122fe279fdSBarry Smith   Output Parameter:
11132ef1f0ffSBarry Smith . D - the matrix whose values are to be computed via a matrix-matrix product operation
11144222ddf1SHong Zhang 
11154222ddf1SHong Zhang   Level: intermediate
11164222ddf1SHong Zhang 
111727430b45SBarry Smith   Example:
1118f5368d60SBarry Smith .vb
111911a5261eSBarry Smith     MatProductCreate(A,B,C,&D); or MatProductCreateWithMat(A,B,C,D)
112011a5261eSBarry Smith     MatProductSetType(D, MATPRODUCT_AB or MATPRODUCT_AtB or MATPRODUCT_ABt or MATPRODUCT_PtAP or MATPRODUCT_RARt or MATPRODUCT_ABC)
112111a5261eSBarry Smith     MatProductSetAlgorithm(D, alg)
112211a5261eSBarry Smith     MatProductSetFill(D,fill)
112311a5261eSBarry Smith     MatProductSetFromOptions(D)
112411a5261eSBarry Smith     MatProductSymbolic(D)
112511a5261eSBarry Smith     MatProductNumeric(D)
1126f5368d60SBarry Smith     Change numerical values in some of the matrices
112711a5261eSBarry Smith     MatProductNumeric(D)
1128f5368d60SBarry Smith .ve
1129f5368d60SBarry Smith 
1130f5368d60SBarry Smith   Notes:
113127430b45SBarry Smith   Use `MatProductCreateWithMat()` if the matrix you wish computed, the `D` matrix, already exists.
1132f5368d60SBarry Smith 
1133f5368d60SBarry Smith   The information computed during the symbolic stage can be reused for new numerical computations with the same non-zero structure
1134f5368d60SBarry Smith 
1135fe59aa6dSJacob Faibussowitsch   Developer Notes:
1136f5368d60SBarry Smith   It is undocumented what happens if the nonzero structure of the input matrices changes. Is the symbolic stage automatically redone? Does it crash?
1137f5368d60SBarry Smith   Is there error checking for it?
1138f5368d60SBarry Smith 
11391cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductClear()`
11404222ddf1SHong Zhang @*/
1141d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductCreate(Mat A, Mat B, Mat C, Mat *D)
1142d71ae5a4SJacob Faibussowitsch {
11434222ddf1SHong Zhang   PetscFunctionBegin;
11444222ddf1SHong Zhang   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11454222ddf1SHong Zhang   PetscValidType(A, 1);
11464222ddf1SHong Zhang   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
11474222ddf1SHong Zhang   PetscValidType(B, 2);
114828b400f6SJacob Faibussowitsch   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix A");
114928b400f6SJacob Faibussowitsch   PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix B");
11504222ddf1SHong Zhang 
11514222ddf1SHong Zhang   if (C) {
11524222ddf1SHong Zhang     PetscValidHeaderSpecific(C, MAT_CLASSID, 3);
11534222ddf1SHong Zhang     PetscValidType(C, 3);
115428b400f6SJacob Faibussowitsch     PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix C");
11554222ddf1SHong Zhang   }
11564222ddf1SHong Zhang 
11574f572ea9SToby Isaac   PetscAssertPointer(D, 4);
11589566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), D));
115930203840SJunchao Zhang   /* Delay setting type of D to the MatProduct symbolic phase, as we allow sparse A and dense B */
11609566063dSJacob Faibussowitsch   PetscCall(MatProductCreate_Private(A, B, C, *D));
11613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11624222ddf1SHong Zhang }
11635415d71bSStefano Zampini 
11645415d71bSStefano Zampini /*
11655415d71bSStefano Zampini    These are safe basic implementations of ABC, RARt and PtAP
11665415d71bSStefano Zampini    that do not rely on mat->ops->matmatop function pointers.
11675415d71bSStefano Zampini    They only use the MatProduct API and are currently used by
11685415d71bSStefano Zampini    cuSPARSE and KOKKOS-KERNELS backends
11695415d71bSStefano Zampini */
1170ec446438SStefano Zampini typedef struct {
11715415d71bSStefano Zampini   Mat BC;
11725415d71bSStefano Zampini   Mat ABC;
1173*cc1eb50dSBarry Smith } MatProductCtx_MatMatMatPrivate;
11745415d71bSStefano Zampini 
1175*cc1eb50dSBarry Smith static PetscErrorCode MatProductCtxDestroy_MatMatMatPrivate(void **data)
1176d71ae5a4SJacob Faibussowitsch {
1177*cc1eb50dSBarry Smith   MatProductCtx_MatMatMatPrivate *mmdata = *(MatProductCtx_MatMatMatPrivate **)data;
11785415d71bSStefano Zampini 
11795415d71bSStefano Zampini   PetscFunctionBegin;
11809566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->BC));
11819566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mmdata->ABC));
1182*cc1eb50dSBarry Smith   PetscCall(PetscFree(*data));
11833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11845415d71bSStefano Zampini }
11855415d71bSStefano Zampini 
1186d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat)
1187d71ae5a4SJacob Faibussowitsch {
11885415d71bSStefano Zampini   Mat_Product                    *product = mat->product;
1189*cc1eb50dSBarry Smith   MatProductCtx_MatMatMatPrivate *mmabc;
11905415d71bSStefano Zampini 
11915415d71bSStefano Zampini   PetscFunctionBegin;
11925415d71bSStefano Zampini   MatCheckProduct(mat, 1);
119328b400f6SJacob Faibussowitsch   PetscCheck(mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data empty");
1194*cc1eb50dSBarry Smith   mmabc = (MatProductCtx_MatMatMatPrivate *)mat->product->data;
119528b400f6SJacob Faibussowitsch   PetscCheck(mmabc->BC->ops->productnumeric, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing numeric stage");
1196ec446438SStefano Zampini   /* use function pointer directly to prevent logging */
11979566063dSJacob Faibussowitsch   PetscCall((*mmabc->BC->ops->productnumeric)(mmabc->BC));
11985415d71bSStefano Zampini   /* swap ABC product stuff with that of ABC for the numeric phase on mat */
11995415d71bSStefano Zampini   mat->product             = mmabc->ABC->product;
12005415d71bSStefano Zampini   mat->ops->productnumeric = mmabc->ABC->ops->productnumeric;
1201ec446438SStefano Zampini   /* use function pointer directly to prevent logging */
1202dbbe0bcdSBarry Smith   PetscUseTypeMethod(mat, productnumeric);
12035415d71bSStefano Zampini   mat->ops->productnumeric = MatProductNumeric_ABC_Basic;
12045415d71bSStefano Zampini   mat->product             = product;
12053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12065415d71bSStefano Zampini }
12075415d71bSStefano Zampini 
1208d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat)
1209d71ae5a4SJacob Faibussowitsch {
12105415d71bSStefano Zampini   Mat_Product                    *product = mat->product;
12115415d71bSStefano Zampini   Mat                             A, B, C;
12125415d71bSStefano Zampini   MatProductType                  p1, p2;
1213*cc1eb50dSBarry Smith   MatProductCtx_MatMatMatPrivate *mmabc;
121465e4b4d4SStefano Zampini   const char                     *prefix;
12155415d71bSStefano Zampini 
12165415d71bSStefano Zampini   PetscFunctionBegin;
12175415d71bSStefano Zampini   MatCheckProduct(mat, 1);
121828b400f6SJacob Faibussowitsch   PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data not empty");
12199566063dSJacob Faibussowitsch   PetscCall(MatGetOptionsPrefix(mat, &prefix));
12209566063dSJacob Faibussowitsch   PetscCall(PetscNew(&mmabc));
12215415d71bSStefano Zampini   product->data    = mmabc;
1222*cc1eb50dSBarry Smith   product->destroy = MatProductCtxDestroy_MatMatMatPrivate;
12235415d71bSStefano Zampini   switch (product->type) {
12245415d71bSStefano Zampini   case MATPRODUCT_PtAP:
12255415d71bSStefano Zampini     p1 = MATPRODUCT_AB;
12265415d71bSStefano Zampini     p2 = MATPRODUCT_AtB;
12275415d71bSStefano Zampini     A  = product->B;
12285415d71bSStefano Zampini     B  = product->A;
12295415d71bSStefano Zampini     C  = product->B;
123039cfb508SMark Adams     if (A->cmap->bs > 0 && C->cmap->bs > 0) PetscCall(MatSetBlockSizes(mat, A->cmap->bs, C->cmap->bs));
12315415d71bSStefano Zampini     break;
12325415d71bSStefano Zampini   case MATPRODUCT_RARt:
12335415d71bSStefano Zampini     p1 = MATPRODUCT_ABt;
12345415d71bSStefano Zampini     p2 = MATPRODUCT_AB;
12355415d71bSStefano Zampini     A  = product->B;
12365415d71bSStefano Zampini     B  = product->A;
12375415d71bSStefano Zampini     C  = product->B;
123839cfb508SMark Adams     if (A->rmap->bs > 0 && C->rmap->bs > 0) PetscCall(MatSetBlockSizes(mat, A->rmap->bs, C->rmap->bs));
12395415d71bSStefano Zampini     break;
12405415d71bSStefano Zampini   case MATPRODUCT_ABC:
12415415d71bSStefano Zampini     p1 = MATPRODUCT_AB;
12425415d71bSStefano Zampini     p2 = MATPRODUCT_AB;
12435415d71bSStefano Zampini     A  = product->A;
12445415d71bSStefano Zampini     B  = product->B;
12455415d71bSStefano Zampini     C  = product->C;
12460e6a1e94SMark Adams     PetscCall(MatSetBlockSizesFromMats(mat, A, C));
12475415d71bSStefano Zampini     break;
1248d71ae5a4SJacob Faibussowitsch   default:
1249d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Not for ProductType %s", MatProductTypes[product->type]);
12505415d71bSStefano Zampini   }
12519566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(B, C, NULL, &mmabc->BC));
12529566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(mmabc->BC, prefix));
12539566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(mmabc->BC, "P1_"));
12549566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(mmabc->BC, p1));
12559566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(mmabc->BC, MATPRODUCTALGORITHMDEFAULT));
12569566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(mmabc->BC, product->fill));
12575415d71bSStefano Zampini   mmabc->BC->product->api_user = product->api_user;
12589566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(mmabc->BC));
125928b400f6SJacob 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);
1260bfcc3627SStefano Zampini   /* use function pointer directly to prevent logging */
12619566063dSJacob Faibussowitsch   PetscCall((*mmabc->BC->ops->productsymbolic)(mmabc->BC));
12625415d71bSStefano Zampini 
12639566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(A, mmabc->BC, NULL, &mmabc->ABC));
12649566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(mmabc->ABC, prefix));
12659566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(mmabc->ABC, "P2_"));
12669566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(mmabc->ABC, p2));
12679566063dSJacob Faibussowitsch   PetscCall(MatProductSetAlgorithm(mmabc->ABC, MATPRODUCTALGORITHMDEFAULT));
12689566063dSJacob Faibussowitsch   PetscCall(MatProductSetFill(mmabc->ABC, product->fill));
12695415d71bSStefano Zampini   mmabc->ABC->product->api_user = product->api_user;
12709566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(mmabc->ABC));
127128b400f6SJacob 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);
12725415d71bSStefano Zampini   /* swap ABC product stuff with that of ABC for the symbolic phase on mat */
12735415d71bSStefano Zampini   mat->product              = mmabc->ABC->product;
12745415d71bSStefano Zampini   mat->ops->productsymbolic = mmabc->ABC->ops->productsymbolic;
1275bfcc3627SStefano Zampini   /* use function pointer directly to prevent logging */
1276dbbe0bcdSBarry Smith   PetscUseTypeMethod(mat, productsymbolic);
12775415d71bSStefano Zampini   mmabc->ABC->ops->productnumeric = mat->ops->productnumeric;
12785415d71bSStefano Zampini   mat->ops->productsymbolic       = MatProductSymbolic_ABC_Basic;
12795415d71bSStefano Zampini   mat->ops->productnumeric        = MatProductNumeric_ABC_Basic;
12805415d71bSStefano Zampini   mat->product                    = product;
12813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12825415d71bSStefano Zampini }
1283c600787bSStefano Zampini 
1284c600787bSStefano Zampini /*@
12852ef1f0ffSBarry Smith   MatProductGetType - Returns the type of matrix-matrix product associated with computing values for the given matrix
1286c600787bSStefano Zampini 
128727430b45SBarry Smith   Not Collective
1288c600787bSStefano Zampini 
1289c600787bSStefano Zampini   Input Parameter:
12902ef1f0ffSBarry Smith . mat - the matrix whose values are to be computed via a matrix-matrix product operation
1291c600787bSStefano Zampini 
1292c600787bSStefano Zampini   Output Parameter:
129311a5261eSBarry Smith . mtype - the `MatProductType`
1294c600787bSStefano Zampini 
1295c600787bSStefano Zampini   Level: intermediate
1296c600787bSStefano Zampini 
12971cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductCreate()`, `MatProductType`, `MatProductAlgorithm`
1298c600787bSStefano Zampini @*/
1299d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductGetType(Mat mat, MatProductType *mtype)
1300d71ae5a4SJacob Faibussowitsch {
1301c600787bSStefano Zampini   PetscFunctionBegin;
1302c600787bSStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
13034f572ea9SToby Isaac   PetscAssertPointer(mtype, 2);
1304c600787bSStefano Zampini   *mtype = MATPRODUCT_UNSPECIFIED;
1305c600787bSStefano Zampini   if (mat->product) *mtype = mat->product->type;
13063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1307c600787bSStefano Zampini }
1308c600787bSStefano Zampini 
1309c600787bSStefano Zampini /*@
13102ef1f0ffSBarry Smith   MatProductGetMats - Returns the matrices associated with the matrix-matrix product associated with computing values for the given matrix
1311c600787bSStefano Zampini 
131227430b45SBarry Smith   Not Collective
1313c600787bSStefano Zampini 
1314c600787bSStefano Zampini   Input Parameter:
13152ef1f0ffSBarry Smith . mat - the matrix whose values are to be computed via a matrix-matrix product operation
1316c600787bSStefano Zampini 
1317c600787bSStefano Zampini   Output Parameters:
1318c600787bSStefano Zampini + A - the first matrix
1319c600787bSStefano Zampini . B - the second matrix
13202ef1f0ffSBarry Smith - C - the third matrix (may be `NULL` for some `MatProductType`)
1321c600787bSStefano Zampini 
1322c600787bSStefano Zampini   Level: intermediate
1323c600787bSStefano Zampini 
13241cc06b55SBarry Smith .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()`
1325c600787bSStefano Zampini @*/
1326d71ae5a4SJacob Faibussowitsch PetscErrorCode MatProductGetMats(Mat mat, Mat *A, Mat *B, Mat *C)
1327d71ae5a4SJacob Faibussowitsch {
1328c600787bSStefano Zampini   PetscFunctionBegin;
1329c600787bSStefano Zampini   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1330c600787bSStefano Zampini   if (A) *A = mat->product ? mat->product->A : NULL;
1331c600787bSStefano Zampini   if (B) *B = mat->product ? mat->product->B : NULL;
1332c600787bSStefano Zampini   if (C) *C = mat->product ? mat->product->C : NULL;
13333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1334c600787bSStefano Zampini }
1335