1 2 /* 3 Routines for matrix products. Calling procedure: 4 5 MatProductCreate(A,B,C,&D); or MatProductCreateWithMat(A,B,C,D) 6 MatProductSetType(D, MATPRODUCT_AB/AtB/ABt/PtAP/RARt/ABC) 7 MatProductSetAlgorithm(D, alg) 8 MatProductSetFill(D,fill) 9 MatProductSetFromOptions(D) 10 -> MatProductSetFromOptions_Private(D) 11 # Check matrix global sizes 12 if the matrices have the same setfromoptions routine, use it 13 if not, try: 14 -> Query MatProductSetFromOptions_Atype_Btype_Ctype_C(D) from A, B and C (in order) 15 if found -> run the specific setup that must set the symbolic operation (these callbacks should never fail) 16 if callback not found or no symbolic operation set 17 -> Query MatProductSetFromOptions_anytype_C(D) from A, B and C (in order) (e.g, matrices may have inner matrices like MATTRANSPOSEMAT) 18 if dispatch found but combination still not present do 19 -> check if B is dense and product type AtB or AB -> if true, basic looping of dense columns 20 -> check if triple product (PtAP, RARt or ABC) -> if true, set the Basic routines 21 22 # The setfromoptions calls MatProductSetFromOptions_Atype_Btype_Ctype should 23 # Check matrix local sizes for mpi matrices 24 # Set default algorithm 25 # Get runtime option 26 # Set D->ops->productsymbolic = MatProductSymbolic_productype_Atype_Btype_Ctype if found 27 28 MatProductSymbolic(D) 29 # Call MatProductSymbolic_productype_Atype_Btype_Ctype() 30 the callback must set the numeric phase D->ops->productnumeric = MatProductNumeric_productype_Atype_Btype_Ctype 31 32 MatProductNumeric(D) 33 # Call the numeric phase 34 35 # The symbolic phases are allowed to set extra data structures and attach those to the product 36 # this additional data can be reused between multiple numeric phases with the same matrices 37 # if not needed, call 38 MatProductClear(D) 39 */ 40 41 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 42 43 const char *const MatProductTypes[] = {"UNSPECIFIED", "AB", "AtB", "ABt", "PtAP", "RARt", "ABC"}; 44 45 /* these are basic implementations relying on the old function pointers 46 * they are dangerous and should be removed in the future */ 47 static PetscErrorCode MatProductNumeric_PtAP_Unsafe(Mat C) { 48 Mat_Product *product = C->product; 49 Mat P = product->B, AP = product->Dwork; 50 51 PetscFunctionBegin; 52 /* AP = A*P */ 53 PetscCall(MatProductNumeric(AP)); 54 /* C = P^T*AP */ 55 PetscCall((*C->ops->transposematmultnumeric)(P, AP, C)); 56 PetscFunctionReturn(0); 57 } 58 59 static PetscErrorCode MatProductSymbolic_PtAP_Unsafe(Mat C) { 60 Mat_Product *product = C->product; 61 Mat A = product->A, P = product->B, AP; 62 PetscReal fill = product->fill; 63 64 PetscFunctionBegin; 65 PetscCall(PetscInfo((PetscObject)C, "for A %s, P %s is used\n", ((PetscObject)product->A)->type_name, ((PetscObject)product->B)->type_name)); 66 /* AP = A*P */ 67 PetscCall(MatProductCreate(A, P, NULL, &AP)); 68 PetscCall(MatProductSetType(AP, MATPRODUCT_AB)); 69 PetscCall(MatProductSetAlgorithm(AP, MATPRODUCTALGORITHMDEFAULT)); 70 PetscCall(MatProductSetFill(AP, fill)); 71 PetscCall(MatProductSetFromOptions(AP)); 72 PetscCall(MatProductSymbolic(AP)); 73 74 /* C = P^T*AP */ 75 PetscCall(MatProductSetType(C, MATPRODUCT_AtB)); 76 PetscCall(MatProductSetAlgorithm(C, MATPRODUCTALGORITHMDEFAULT)); 77 product->A = P; 78 product->B = AP; 79 PetscCall(MatProductSetFromOptions(C)); 80 PetscCall(MatProductSymbolic(C)); 81 82 /* resume user's original input matrix setting for A and B */ 83 product->A = A; 84 product->B = P; 85 product->Dwork = AP; 86 87 C->ops->productnumeric = MatProductNumeric_PtAP_Unsafe; 88 PetscFunctionReturn(0); 89 } 90 91 static PetscErrorCode MatProductNumeric_RARt_Unsafe(Mat C) { 92 Mat_Product *product = C->product; 93 Mat R = product->B, RA = product->Dwork; 94 95 PetscFunctionBegin; 96 /* RA = R*A */ 97 PetscCall(MatProductNumeric(RA)); 98 /* C = RA*R^T */ 99 PetscCall((*C->ops->mattransposemultnumeric)(RA, R, C)); 100 PetscFunctionReturn(0); 101 } 102 103 static PetscErrorCode MatProductSymbolic_RARt_Unsafe(Mat C) { 104 Mat_Product *product = C->product; 105 Mat A = product->A, R = product->B, RA; 106 PetscReal fill = product->fill; 107 108 PetscFunctionBegin; 109 PetscCall(PetscInfo((PetscObject)C, "for A %s, R %s is used\n", ((PetscObject)product->A)->type_name, ((PetscObject)product->B)->type_name)); 110 /* RA = R*A */ 111 PetscCall(MatProductCreate(R, A, NULL, &RA)); 112 PetscCall(MatProductSetType(RA, MATPRODUCT_AB)); 113 PetscCall(MatProductSetAlgorithm(RA, MATPRODUCTALGORITHMDEFAULT)); 114 PetscCall(MatProductSetFill(RA, fill)); 115 PetscCall(MatProductSetFromOptions(RA)); 116 PetscCall(MatProductSymbolic(RA)); 117 118 /* C = RA*R^T */ 119 PetscCall(MatProductSetType(C, MATPRODUCT_ABt)); 120 PetscCall(MatProductSetAlgorithm(C, MATPRODUCTALGORITHMDEFAULT)); 121 product->A = RA; 122 PetscCall(MatProductSetFromOptions(C)); 123 PetscCall(MatProductSymbolic(C)); 124 125 /* resume user's original input matrix setting for A */ 126 product->A = A; 127 product->Dwork = RA; /* save here so it will be destroyed with product C */ 128 C->ops->productnumeric = MatProductNumeric_RARt_Unsafe; 129 PetscFunctionReturn(0); 130 } 131 132 static PetscErrorCode MatProductNumeric_ABC_Unsafe(Mat mat) { 133 Mat_Product *product = mat->product; 134 Mat A = product->A, BC = product->Dwork; 135 136 PetscFunctionBegin; 137 /* Numeric BC = B*C */ 138 PetscCall(MatProductNumeric(BC)); 139 /* Numeric mat = A*BC */ 140 PetscCall((*mat->ops->matmultnumeric)(A, BC, mat)); 141 PetscFunctionReturn(0); 142 } 143 144 static PetscErrorCode MatProductSymbolic_ABC_Unsafe(Mat mat) { 145 Mat_Product *product = mat->product; 146 Mat B = product->B, C = product->C, BC; 147 PetscReal fill = product->fill; 148 149 PetscFunctionBegin; 150 PetscCall(PetscInfo((PetscObject)mat, "for A %s, B %s, C %s is used\n", ((PetscObject)product->A)->type_name, ((PetscObject)product->B)->type_name, ((PetscObject)product->C)->type_name)); 151 /* Symbolic BC = B*C */ 152 PetscCall(MatProductCreate(B, C, NULL, &BC)); 153 PetscCall(MatProductSetType(BC, MATPRODUCT_AB)); 154 PetscCall(MatProductSetAlgorithm(BC, MATPRODUCTALGORITHMDEFAULT)); 155 PetscCall(MatProductSetFill(BC, fill)); 156 PetscCall(MatProductSetFromOptions(BC)); 157 PetscCall(MatProductSymbolic(BC)); 158 159 /* Symbolic mat = A*BC */ 160 PetscCall(MatProductSetType(mat, MATPRODUCT_AB)); 161 PetscCall(MatProductSetAlgorithm(mat, MATPRODUCTALGORITHMDEFAULT)); 162 product->B = BC; 163 product->Dwork = BC; 164 PetscCall(MatProductSetFromOptions(mat)); 165 PetscCall(MatProductSymbolic(mat)); 166 167 /* resume user's original input matrix setting for B */ 168 product->B = B; 169 mat->ops->productnumeric = MatProductNumeric_ABC_Unsafe; 170 PetscFunctionReturn(0); 171 } 172 173 static PetscErrorCode MatProductSymbolic_Unsafe(Mat mat) { 174 Mat_Product *product = mat->product; 175 176 PetscFunctionBegin; 177 switch (product->type) { 178 case MATPRODUCT_PtAP: PetscCall(MatProductSymbolic_PtAP_Unsafe(mat)); break; 179 case MATPRODUCT_RARt: PetscCall(MatProductSymbolic_RARt_Unsafe(mat)); break; 180 case MATPRODUCT_ABC: PetscCall(MatProductSymbolic_ABC_Unsafe(mat)); break; 181 default: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[product->type]); 182 } 183 PetscFunctionReturn(0); 184 } 185 186 /* ----------------------------------------------- */ 187 /*@C 188 MatProductReplaceMats - Replace input matrices for a matrix product. 189 190 Collective on Mat 191 192 Input Parameters: 193 + A - the matrix or NULL if not being replaced 194 . B - the matrix or NULL if not being replaced 195 . C - the matrix or NULL if not being replaced 196 - D - the matrix product 197 198 Level: intermediate 199 200 Notes: 201 To reuse the symbolic phase, input matrices must have exactly the same data structure as the replaced one. 202 If the type of any of the input matrices is different than what was previously used, or their symmetry flag changed but 203 the symbolic phase took advantage of their symmetry, the product is cleared and `MatProductSetFromOptions()` and `MatProductSymbolic()` are invoked again. 204 205 .seealso: `MatProductCreate()`, `MatProductSetFromOptions()`, `MatProductSymbolic().` `MatProductClear()` 206 @*/ 207 PetscErrorCode MatProductReplaceMats(Mat A, Mat B, Mat C, Mat D) { 208 Mat_Product *product; 209 PetscBool flgA = PETSC_TRUE, flgB = PETSC_TRUE, flgC = PETSC_TRUE, isset, issym; 210 211 PetscFunctionBegin; 212 PetscValidHeaderSpecific(D, MAT_CLASSID, 4); 213 MatCheckProduct(D, 4); 214 product = D->product; 215 if (A) { 216 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 217 PetscCall(PetscObjectReference((PetscObject)A)); 218 PetscCall(PetscObjectTypeCompare((PetscObject)product->A, ((PetscObject)A)->type_name, &flgA)); 219 PetscCall(MatIsSymmetricKnown(A, &isset, &issym)); 220 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 */ 221 flgA = PETSC_FALSE; 222 product->symbolic_used_the_fact_A_is_symmetric = PETSC_FALSE; /* reinit */ 223 } 224 PetscCall(MatDestroy(&product->A)); 225 product->A = A; 226 } 227 if (B) { 228 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 229 PetscCall(PetscObjectReference((PetscObject)B)); 230 PetscCall(PetscObjectTypeCompare((PetscObject)product->B, ((PetscObject)B)->type_name, &flgB)); 231 PetscCall(MatIsSymmetricKnown(B, &isset, &issym)); 232 if (product->symbolic_used_the_fact_B_is_symmetric && isset && !issym) { 233 flgB = PETSC_FALSE; 234 product->symbolic_used_the_fact_B_is_symmetric = PETSC_FALSE; /* reinit */ 235 } 236 PetscCall(MatDestroy(&product->B)); 237 product->B = B; 238 } 239 if (C) { 240 PetscValidHeaderSpecific(C, MAT_CLASSID, 3); 241 PetscCall(PetscObjectReference((PetscObject)C)); 242 PetscCall(PetscObjectTypeCompare((PetscObject)product->C, ((PetscObject)C)->type_name, &flgC)); 243 PetscCall(MatIsSymmetricKnown(C, &isset, &issym)); 244 if (product->symbolic_used_the_fact_C_is_symmetric && isset && !issym) { 245 flgC = PETSC_FALSE; 246 product->symbolic_used_the_fact_C_is_symmetric = PETSC_FALSE; /* reinit */ 247 } 248 PetscCall(MatDestroy(&product->C)); 249 product->C = C; 250 } 251 /* Any of the replaced mats is of a different type, reset */ 252 if (!flgA || !flgB || !flgC) { 253 if (D->product->destroy) PetscCall((*D->product->destroy)(D->product->data)); 254 D->product->destroy = NULL; 255 D->product->data = NULL; 256 if (D->ops->productnumeric || D->ops->productsymbolic) { 257 PetscCall(MatProductSetFromOptions(D)); 258 PetscCall(MatProductSymbolic(D)); 259 } 260 } 261 PetscFunctionReturn(0); 262 } 263 264 static PetscErrorCode MatProductNumeric_X_Dense(Mat C) { 265 Mat_Product *product = C->product; 266 Mat A = product->A, B = product->B; 267 PetscInt k, K = B->cmap->N; 268 PetscBool t = PETSC_TRUE, iscuda = PETSC_FALSE; 269 PetscBool Bcpu = PETSC_TRUE, Ccpu = PETSC_TRUE; 270 char *Btype = NULL, *Ctype = NULL; 271 272 PetscFunctionBegin; 273 switch (product->type) { 274 case MATPRODUCT_AB: t = PETSC_FALSE; 275 case MATPRODUCT_AtB: break; 276 default: SETERRQ(PetscObjectComm((PetscObject)C), PETSC_ERR_SUP, "MatProductNumeric type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name); 277 } 278 if (PetscDefined(HAVE_CUDA)) { 279 VecType vtype; 280 281 PetscCall(MatGetVecType(A, &vtype)); 282 PetscCall(PetscStrcmp(vtype, VECCUDA, &iscuda)); 283 if (!iscuda) PetscCall(PetscStrcmp(vtype, VECSEQCUDA, &iscuda)); 284 if (!iscuda) PetscCall(PetscStrcmp(vtype, VECMPICUDA, &iscuda)); 285 if (iscuda) { /* Make sure we have up-to-date data on the GPU */ 286 PetscCall(PetscStrallocpy(((PetscObject)B)->type_name, &Btype)); 287 PetscCall(PetscStrallocpy(((PetscObject)C)->type_name, &Ctype)); 288 PetscCall(MatConvert(B, MATDENSECUDA, MAT_INPLACE_MATRIX, &B)); 289 if (!C->assembled) { /* need to flag the matrix as assembled, otherwise MatConvert will complain */ 290 PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 291 PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 292 } 293 PetscCall(MatConvert(C, MATDENSECUDA, MAT_INPLACE_MATRIX, &C)); 294 } else { /* Make sure we have up-to-date data on the CPU */ 295 #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_VIENNACL) 296 Bcpu = B->boundtocpu; 297 Ccpu = C->boundtocpu; 298 #endif 299 PetscCall(MatBindToCPU(B, PETSC_TRUE)); 300 PetscCall(MatBindToCPU(C, PETSC_TRUE)); 301 } 302 } 303 for (k = 0; k < K; k++) { 304 Vec x, y; 305 306 PetscCall(MatDenseGetColumnVecRead(B, k, &x)); 307 PetscCall(MatDenseGetColumnVecWrite(C, k, &y)); 308 if (t) { 309 PetscCall(MatMultTranspose(A, x, y)); 310 } else { 311 PetscCall(MatMult(A, x, y)); 312 } 313 PetscCall(MatDenseRestoreColumnVecRead(B, k, &x)); 314 PetscCall(MatDenseRestoreColumnVecWrite(C, k, &y)); 315 } 316 PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 317 PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 318 if (PetscDefined(HAVE_CUDA)) { 319 if (iscuda) { 320 PetscCall(MatConvert(B, Btype, MAT_INPLACE_MATRIX, &B)); 321 PetscCall(MatConvert(C, Ctype, MAT_INPLACE_MATRIX, &C)); 322 } else { 323 PetscCall(MatBindToCPU(B, Bcpu)); 324 PetscCall(MatBindToCPU(C, Ccpu)); 325 } 326 } 327 PetscCall(PetscFree(Btype)); 328 PetscCall(PetscFree(Ctype)); 329 PetscFunctionReturn(0); 330 } 331 332 static PetscErrorCode MatProductSymbolic_X_Dense(Mat C) { 333 Mat_Product *product = C->product; 334 Mat A = product->A, B = product->B; 335 PetscBool isdense; 336 337 PetscFunctionBegin; 338 switch (product->type) { 339 case MATPRODUCT_AB: PetscCall(MatSetSizes(C, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N)); break; 340 case MATPRODUCT_AtB: PetscCall(MatSetSizes(C, A->cmap->n, B->cmap->n, A->cmap->N, B->cmap->N)); break; 341 default: SETERRQ(PetscObjectComm((PetscObject)C), PETSC_ERR_SUP, "MatProductSymbolic type %s not supported for %s and %s matrices", MatProductTypes[product->type], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name); 342 } 343 PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)C, &isdense, MATSEQDENSE, MATMPIDENSE, "")); 344 if (!isdense) { 345 PetscCall(MatSetType(C, ((PetscObject)B)->type_name)); 346 /* If matrix type of C was not set or not dense, we need to reset the pointer */ 347 C->ops->productsymbolic = MatProductSymbolic_X_Dense; 348 } 349 C->ops->productnumeric = MatProductNumeric_X_Dense; 350 PetscCall(MatSetUp(C)); 351 PetscFunctionReturn(0); 352 } 353 354 /* a single driver to query the dispatching */ 355 static PetscErrorCode MatProductSetFromOptions_Private(Mat mat) { 356 Mat_Product *product = mat->product; 357 PetscInt Am, An, Bm, Bn, Cm, Cn; 358 Mat A = product->A, B = product->B, C = product->C; 359 const char *const Bnames[] = {"B", "R", "P"}; 360 const char *bname; 361 PetscErrorCode (*fA)(Mat); 362 PetscErrorCode (*fB)(Mat); 363 PetscErrorCode (*fC)(Mat); 364 PetscErrorCode (*f)(Mat) = NULL; 365 366 PetscFunctionBegin; 367 mat->ops->productsymbolic = NULL; 368 mat->ops->productnumeric = NULL; 369 if (product->type == MATPRODUCT_UNSPECIFIED) PetscFunctionReturn(0); 370 PetscCheck(A, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing A mat"); 371 PetscCheck(B, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing B mat"); 372 PetscCheck(product->type != MATPRODUCT_ABC || C, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing C mat"); 373 if (product->type != MATPRODUCT_ABC) C = NULL; /* do not use C if not needed */ 374 if (product->type == MATPRODUCT_RARt) bname = Bnames[1]; 375 else if (product->type == MATPRODUCT_PtAP) bname = Bnames[2]; 376 else bname = Bnames[0]; 377 378 /* Check matrices sizes */ 379 Am = A->rmap->N; 380 An = A->cmap->N; 381 Bm = B->rmap->N; 382 Bn = B->cmap->N; 383 Cm = C ? C->rmap->N : 0; 384 Cn = C ? C->cmap->N : 0; 385 if (product->type == MATPRODUCT_RARt || product->type == MATPRODUCT_ABt) { 386 PetscInt t = Bn; 387 Bn = Bm; 388 Bm = t; 389 } 390 if (product->type == MATPRODUCT_AtB) { 391 PetscInt t = An; 392 An = Am; 393 Am = t; 394 } 395 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, 396 MatProductTypes[product->type], A->rmap->N, A->cmap->N, bname, B->rmap->N, B->cmap->N); 397 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, 398 MatProductTypes[product->type], B->rmap->N, B->cmap->N, Cm, Cn); 399 400 fA = A->ops->productsetfromoptions; 401 fB = B->ops->productsetfromoptions; 402 fC = C ? C->ops->productsetfromoptions : fA; 403 if (C) { 404 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)); 405 } else { 406 PetscCall(PetscInfo(mat, "MatProductType %s for A %s, %s %s\n", MatProductTypes[product->type], ((PetscObject)A)->type_name, bname, ((PetscObject)B)->type_name)); 407 } 408 if (fA == fB && fA == fC && fA) { 409 PetscCall(PetscInfo(mat, " matching op\n")); 410 PetscCall((*fA)(mat)); 411 } 412 /* We may have found f but it did not succeed */ 413 if (!mat->ops->productsymbolic) { /* query MatProductSetFromOptions_Atype_Btype_Ctype */ 414 char mtypes[256]; 415 PetscCall(PetscStrncpy(mtypes, "MatProductSetFromOptions_", sizeof(mtypes))); 416 PetscCall(PetscStrlcat(mtypes, ((PetscObject)A)->type_name, sizeof(mtypes))); 417 PetscCall(PetscStrlcat(mtypes, "_", sizeof(mtypes))); 418 PetscCall(PetscStrlcat(mtypes, ((PetscObject)B)->type_name, sizeof(mtypes))); 419 if (C) { 420 PetscCall(PetscStrlcat(mtypes, "_", sizeof(mtypes))); 421 PetscCall(PetscStrlcat(mtypes, ((PetscObject)C)->type_name, sizeof(mtypes))); 422 } 423 PetscCall(PetscStrlcat(mtypes, "_C", sizeof(mtypes))); 424 425 PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f)); 426 PetscCall(PetscInfo(mat, " querying %s from A? %p\n", mtypes, f)); 427 if (!f) { 428 PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f)); 429 PetscCall(PetscInfo(mat, " querying %s from %s? %p\n", mtypes, bname, f)); 430 } 431 if (!f && C) { 432 PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f)); 433 PetscCall(PetscInfo(mat, " querying %s from C? %p\n", mtypes, f)); 434 } 435 if (f) PetscCall((*f)(mat)); 436 437 /* We may have found f but it did not succeed */ 438 /* some matrices (i.e. MATTRANSPOSE, MATSHELL constructed from MatConvert), knows what to do with their inner matrices */ 439 if (!mat->ops->productsymbolic) { 440 PetscCall(PetscStrncpy(mtypes, "MatProductSetFromOptions_anytype_C", sizeof(mtypes))); 441 PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f)); 442 PetscCall(PetscInfo(mat, " querying %s from A? %p\n", mtypes, f)); 443 if (!f) { 444 PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f)); 445 PetscCall(PetscInfo(mat, " querying %s from %s? %p\n", mtypes, bname, f)); 446 } 447 if (!f && C) { 448 PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f)); 449 PetscCall(PetscInfo(mat, " querying %s from C? %p\n", mtypes, f)); 450 } 451 } 452 if (f) PetscCall((*f)(mat)); 453 } 454 455 /* We may have found f but it did not succeed */ 456 if (!mat->ops->productsymbolic) { 457 /* we can still compute the product if B is of type dense */ 458 if (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB) { 459 PetscBool isdense; 460 461 PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)B, &isdense, MATSEQDENSE, MATMPIDENSE, "")); 462 if (isdense) { 463 mat->ops->productsymbolic = MatProductSymbolic_X_Dense; 464 PetscCall(PetscInfo(mat, " using basic looping over columns of a dense matrix\n")); 465 } 466 } else if (product->type != MATPRODUCT_ABt) { /* use MatProductSymbolic/Numeric_Unsafe() for triple products only */ 467 /* 468 TODO: this should be changed to a proper setfromoptions, not setting the symbolic pointer here, because we do not know if 469 the combination will succeed. In order to be sure, we need MatProductGetProductType to return the type of the result 470 before computing the symbolic phase 471 */ 472 PetscCall(PetscInfo(mat, " symbolic product not supported, using MatProductSymbolic_Unsafe() implementation\n")); 473 mat->ops->productsymbolic = MatProductSymbolic_Unsafe; 474 } 475 } 476 if (!mat->ops->productsymbolic) PetscCall(PetscInfo(mat, " symbolic product is not supported\n")); 477 PetscFunctionReturn(0); 478 } 479 480 /*@C 481 MatProductSetFromOptions - Sets the options for the computation of a matrix product where the type, the algorithm etc are determined from the options database. 482 483 Logically Collective on Mat 484 485 Input Parameter: 486 . mat - the matrix 487 488 Options Database Keys: 489 . -mat_product_clear - Clear intermediate data structures after `MatProductNumeric()` has been called 490 491 Level: intermediate 492 493 .seealso: `MatSetFromOptions()`, `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductNumeric()`, `MatProductSetType()`, `MatProductSetAlgorithm()` 494 @*/ 495 PetscErrorCode MatProductSetFromOptions(Mat mat) { 496 PetscFunctionBegin; 497 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 498 MatCheckProduct(mat, 1); 499 PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot call MatProductSetFromOptions with already present data"); 500 PetscObjectOptionsBegin((PetscObject)mat); 501 PetscCall(PetscOptionsBool("-mat_product_clear", "Clear intermediate data structures after MatProductNumeric() has been called", "MatProductClear", mat->product->clear, &mat->product->clear, NULL)); 502 PetscCall(PetscOptionsDeprecated("-mat_freeintermediatedatastructures", "-mat_product_clear", "3.13", "Or call MatProductClear() after MatProductNumeric()")); 503 PetscOptionsEnd(); 504 PetscCall(MatProductSetFromOptions_Private(mat)); 505 PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing product after setup phase"); 506 PetscFunctionReturn(0); 507 } 508 509 /*@C 510 MatProductView - View the MatProduct algorithm object within a matrix 511 512 Logically Collective on Mat 513 514 Input Parameter: 515 . mat - the matrix obtained with `MatProductCreate()` or `MatProductCreateWithMat()` 516 517 Level: intermediate 518 519 .seealso: `MatView()`, `MatProductCreate()`, `MatProductCreateWithMat()` 520 @*/ 521 PetscErrorCode MatProductView(Mat mat, PetscViewer viewer) { 522 PetscFunctionBegin; 523 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 524 if (!mat->product) PetscFunctionReturn(0); 525 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer)); 526 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 527 PetscCheckSameComm(mat, 1, viewer, 2); 528 if (mat->product->view) PetscCall((*mat->product->view)(mat, viewer)); 529 PetscFunctionReturn(0); 530 } 531 532 /* ----------------------------------------------- */ 533 /* these are basic implementations relying on the old function pointers 534 * they are dangerous and should be removed in the future */ 535 PetscErrorCode MatProductNumeric_AB(Mat mat) { 536 Mat_Product *product = mat->product; 537 Mat A = product->A, B = product->B; 538 539 PetscFunctionBegin; 540 PetscCall((*mat->ops->matmultnumeric)(A, B, mat)); 541 PetscFunctionReturn(0); 542 } 543 544 PetscErrorCode MatProductNumeric_AtB(Mat mat) { 545 Mat_Product *product = mat->product; 546 Mat A = product->A, B = product->B; 547 548 PetscFunctionBegin; 549 PetscCall((*mat->ops->transposematmultnumeric)(A, B, mat)); 550 PetscFunctionReturn(0); 551 } 552 553 PetscErrorCode MatProductNumeric_ABt(Mat mat) { 554 Mat_Product *product = mat->product; 555 Mat A = product->A, B = product->B; 556 557 PetscFunctionBegin; 558 PetscCall((*mat->ops->mattransposemultnumeric)(A, B, mat)); 559 PetscFunctionReturn(0); 560 } 561 562 PetscErrorCode MatProductNumeric_PtAP(Mat mat) { 563 Mat_Product *product = mat->product; 564 Mat A = product->A, B = product->B; 565 566 PetscFunctionBegin; 567 PetscCall((*mat->ops->ptapnumeric)(A, B, mat)); 568 PetscFunctionReturn(0); 569 } 570 571 PetscErrorCode MatProductNumeric_RARt(Mat mat) { 572 Mat_Product *product = mat->product; 573 Mat A = product->A, B = product->B; 574 575 PetscFunctionBegin; 576 PetscCall((*mat->ops->rartnumeric)(A, B, mat)); 577 PetscFunctionReturn(0); 578 } 579 580 PetscErrorCode MatProductNumeric_ABC(Mat mat) { 581 Mat_Product *product = mat->product; 582 Mat A = product->A, B = product->B, C = product->C; 583 584 PetscFunctionBegin; 585 PetscCall((*mat->ops->matmatmultnumeric)(A, B, C, mat)); 586 PetscFunctionReturn(0); 587 } 588 589 /* ----------------------------------------------- */ 590 591 /*@ 592 MatProductNumeric - Implement a matrix product with numerical values. 593 594 Collective on Mat 595 596 Input/Output Parameter: 597 . mat - the matrix holding the product 598 599 Level: intermediate 600 601 Notes: `MatProductSymbolic()` must have been called on mat before calling this function 602 603 .seealso: `MatProductCreate()`, `MatSetType()`, `MatProductSymbolic()` 604 @*/ 605 PetscErrorCode MatProductNumeric(Mat mat) { 606 PetscLogEvent eventtype = -1; 607 PetscBool missing = PETSC_FALSE; 608 609 PetscFunctionBegin; 610 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 611 MatCheckProduct(mat, 1); 612 switch (mat->product->type) { 613 case MATPRODUCT_AB: eventtype = MAT_MatMultNumeric; break; 614 case MATPRODUCT_AtB: eventtype = MAT_TransposeMatMultNumeric; break; 615 case MATPRODUCT_ABt: eventtype = MAT_MatTransposeMultNumeric; break; 616 case MATPRODUCT_PtAP: eventtype = MAT_PtAPNumeric; break; 617 case MATPRODUCT_RARt: eventtype = MAT_RARtNumeric; break; 618 case MATPRODUCT_ABC: eventtype = MAT_MatMatMultNumeric; break; 619 default: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]); 620 } 621 622 if (mat->ops->productnumeric) { 623 PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0)); 624 PetscUseTypeMethod(mat, productnumeric); 625 PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0)); 626 } else missing = PETSC_TRUE; 627 628 if (missing || !mat->product) { 629 char errstr[256]; 630 631 if (mat->product->type == MATPRODUCT_ABC) { 632 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)); 633 } else { 634 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)); 635 } 636 PetscCheck(!missing, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified numeric phase for product %s", errstr); 637 PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after symbolic phase for product %s", errstr); 638 } 639 640 if (mat->product->clear) PetscCall(MatProductClear(mat)); 641 PetscCall(PetscObjectStateIncrease((PetscObject)mat)); 642 PetscFunctionReturn(0); 643 } 644 645 /* ----------------------------------------------- */ 646 /* these are basic implementations relying on the old function pointers 647 * they are dangerous and should be removed in the future */ 648 PetscErrorCode MatProductSymbolic_AB(Mat mat) { 649 Mat_Product *product = mat->product; 650 Mat A = product->A, B = product->B; 651 652 PetscFunctionBegin; 653 PetscCall((*mat->ops->matmultsymbolic)(A, B, product->fill, mat)); 654 mat->ops->productnumeric = MatProductNumeric_AB; 655 PetscFunctionReturn(0); 656 } 657 658 PetscErrorCode MatProductSymbolic_AtB(Mat mat) { 659 Mat_Product *product = mat->product; 660 Mat A = product->A, B = product->B; 661 662 PetscFunctionBegin; 663 PetscCall((*mat->ops->transposematmultsymbolic)(A, B, product->fill, mat)); 664 mat->ops->productnumeric = MatProductNumeric_AtB; 665 PetscFunctionReturn(0); 666 } 667 668 PetscErrorCode MatProductSymbolic_ABt(Mat mat) { 669 Mat_Product *product = mat->product; 670 Mat A = product->A, B = product->B; 671 672 PetscFunctionBegin; 673 PetscCall((*mat->ops->mattransposemultsymbolic)(A, B, product->fill, mat)); 674 mat->ops->productnumeric = MatProductNumeric_ABt; 675 PetscFunctionReturn(0); 676 } 677 678 PetscErrorCode MatProductSymbolic_ABC(Mat mat) { 679 Mat_Product *product = mat->product; 680 Mat A = product->A, B = product->B, C = product->C; 681 682 PetscFunctionBegin; 683 PetscCall((*mat->ops->matmatmultsymbolic)(A, B, C, product->fill, mat)); 684 mat->ops->productnumeric = MatProductNumeric_ABC; 685 PetscFunctionReturn(0); 686 } 687 688 /* ----------------------------------------------- */ 689 690 /*@ 691 MatProductSymbolic - Perform the symbolic portion of a matrix product, this creates a data structure for use with the numerical product done with 692 `MatProductNumeric()` 693 694 Collective on Mat 695 696 Input/Output Parameter: 697 . mat - the matrix to hold a product 698 699 Level: intermediate 700 701 Notes: `MatProductSetFromOptions()` must have been called on mat before calling this function 702 703 .seealso: `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductSetFromOptions()`, `MatProductNumeric()`, `MatProductSetType()`, `MatProductSetAlgorithm()` 704 @*/ 705 PetscErrorCode MatProductSymbolic(Mat mat) { 706 PetscLogEvent eventtype = -1; 707 PetscBool missing = PETSC_FALSE; 708 709 PetscFunctionBegin; 710 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 711 MatCheckProduct(mat, 1); 712 PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot run symbolic phase. Product data not empty"); 713 switch (mat->product->type) { 714 case MATPRODUCT_AB: eventtype = MAT_MatMultSymbolic; break; 715 case MATPRODUCT_AtB: eventtype = MAT_TransposeMatMultSymbolic; break; 716 case MATPRODUCT_ABt: eventtype = MAT_MatTransposeMultSymbolic; break; 717 case MATPRODUCT_PtAP: eventtype = MAT_PtAPSymbolic; break; 718 case MATPRODUCT_RARt: eventtype = MAT_RARtSymbolic; break; 719 case MATPRODUCT_ABC: eventtype = MAT_MatMatMultSymbolic; break; 720 default: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]); 721 } 722 mat->ops->productnumeric = NULL; 723 if (mat->ops->productsymbolic) { 724 PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0)); 725 PetscUseTypeMethod(mat, productsymbolic); 726 PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0)); 727 } else missing = PETSC_TRUE; 728 729 if (missing || !mat->product || !mat->ops->productnumeric) { 730 char errstr[256]; 731 732 if (mat->product->type == MATPRODUCT_ABC) { 733 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)); 734 } else { 735 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)); 736 } 737 PetscCheck(!missing, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified symbolic phase for product %s. Call MatProductSetFromOptions() first", errstr); 738 PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after symbolic phase for product %s", errstr); 739 } 740 PetscFunctionReturn(0); 741 } 742 743 /*@ 744 MatProductSetFill - Set an expected fill of the matrix product. 745 746 Collective on Mat 747 748 Input Parameters: 749 + mat - the matrix product 750 - fill - expected fill as ratio of nnz(mat)/(nnz(A) + nnz(B) + nnz(C)); use `PETSC_DEFAULT` if you do not have a good estimate. If the product is a dense matrix, this value is not used. 751 752 Level: intermediate 753 754 .seealso: `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()` 755 @*/ 756 PetscErrorCode MatProductSetFill(Mat mat, PetscReal fill) { 757 PetscFunctionBegin; 758 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 759 MatCheckProduct(mat, 1); 760 if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) mat->product->fill = 2.0; 761 else mat->product->fill = fill; 762 PetscFunctionReturn(0); 763 } 764 765 /*@ 766 MatProductSetAlgorithm - Requests a particular algorithm for a matrix product computation that will perform to compute the given matrix 767 768 Collective on Mat 769 770 Input Parameters: 771 + mat - the matrix product 772 - alg - particular implementation algorithm of the matrix product, e.g., `MATPRODUCTALGORITHMDEFAULT`. 773 774 Options Database Key: 775 . -mat_product_algorithm <algorithm> - Sets the algorithm; use -help for a list 776 of available algorithms (for instance, scalable, outerproduct, etc.) 777 778 Level: intermediate 779 780 .seealso: `MatProductSetType()`, `MatProductSetFill()`, `MatProductCreate()`, `MatProductAlgorithm` 781 @*/ 782 PetscErrorCode MatProductSetAlgorithm(Mat mat, MatProductAlgorithm alg) { 783 PetscFunctionBegin; 784 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 785 MatCheckProduct(mat, 1); 786 PetscCall(PetscFree(mat->product->alg)); 787 PetscCall(PetscStrallocpy(alg, &mat->product->alg)); 788 PetscFunctionReturn(0); 789 } 790 791 /*@ 792 MatProductSetType - Sets a particular matrix product type to be used to compute the given matrix 793 794 Collective on Mat 795 796 Input Parameters: 797 + mat - the matrix 798 - productype - matrix product type, e.g., `MATPRODUCT_AB`,`MATPRODUCT_AtB`,`MATPRODUCT_ABt`,`MATPRODUCT_PtAP`,`MATPRODUCT_RARt`,`MATPRODUCT_ABC`. 799 800 Level: intermediate 801 802 Note: 803 The small t represents the traspose operation. 804 805 .seealso: `MatProductCreate()`, `MatProductType` 806 @*/ 807 PetscErrorCode MatProductSetType(Mat mat, MatProductType productype) { 808 PetscFunctionBegin; 809 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 810 MatCheckProduct(mat, 1); 811 PetscValidLogicalCollectiveEnum(mat, productype, 2); 812 if (productype != mat->product->type) { 813 if (mat->product->destroy) PetscCall((*mat->product->destroy)(mat->product->data)); 814 mat->product->destroy = NULL; 815 mat->product->data = NULL; 816 mat->ops->productsymbolic = NULL; 817 mat->ops->productnumeric = NULL; 818 } 819 mat->product->type = productype; 820 PetscFunctionReturn(0); 821 } 822 823 /*@ 824 MatProductClear - Clears matrix product internal structure. 825 826 Collective on Mat 827 828 Input Parameters: 829 . mat - the product matrix 830 831 Level: intermediate 832 833 Notes: 834 This function should be called to remove any intermediate data used to compute the matrix to free up memory. 835 836 After having called this function, MatProduct operations can no longer be used on mat 837 838 .seealso: `MatProductCreate()` 839 @*/ 840 PetscErrorCode MatProductClear(Mat mat) { 841 Mat_Product *product = mat->product; 842 843 PetscFunctionBegin; 844 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 845 if (product) { 846 PetscCall(MatDestroy(&product->A)); 847 PetscCall(MatDestroy(&product->B)); 848 PetscCall(MatDestroy(&product->C)); 849 PetscCall(PetscFree(product->alg)); 850 PetscCall(MatDestroy(&product->Dwork)); 851 if (product->destroy) PetscCall((*product->destroy)(product->data)); 852 } 853 PetscCall(PetscFree(mat->product)); 854 mat->ops->productsymbolic = NULL; 855 mat->ops->productnumeric = NULL; 856 PetscFunctionReturn(0); 857 } 858 859 /* Create a supporting struct and attach it to the matrix product */ 860 PetscErrorCode MatProductCreate_Private(Mat A, Mat B, Mat C, Mat D) { 861 Mat_Product *product = NULL; 862 863 PetscFunctionBegin; 864 PetscValidHeaderSpecific(D, MAT_CLASSID, 4); 865 PetscCheck(!D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product already present"); 866 PetscCall(PetscNewLog(D, &product)); 867 product->A = A; 868 product->B = B; 869 product->C = C; 870 product->type = MATPRODUCT_UNSPECIFIED; 871 product->Dwork = NULL; 872 product->api_user = PETSC_FALSE; 873 product->clear = PETSC_FALSE; 874 D->product = product; 875 876 PetscCall(MatProductSetAlgorithm(D, MATPRODUCTALGORITHMDEFAULT)); 877 PetscCall(MatProductSetFill(D, PETSC_DEFAULT)); 878 879 PetscCall(PetscObjectReference((PetscObject)A)); 880 PetscCall(PetscObjectReference((PetscObject)B)); 881 PetscCall(PetscObjectReference((PetscObject)C)); 882 PetscFunctionReturn(0); 883 } 884 885 /*@ 886 MatProductCreateWithMat - Setup a given matrix as a matrix product of other matrices 887 888 Collective on Mat 889 890 Input Parameters: 891 + A - the first matrix 892 . B - the second matrix 893 . C - the third matrix (optional) 894 - D - the matrix which will be used as a product 895 896 Output Parameters: 897 . D - the product matrix 898 899 Notes: 900 Use `MatProductCreate()` if the matrix you wish computed (the D matrix) does not already exist 901 902 See `MatProductCreate()` for details on the usage of the MatProduct routines 903 904 Any product data currently attached to D will be cleared 905 906 Level: intermediate 907 908 .seealso: `MatProductCreate()`, `MatProductClear()` 909 @*/ 910 PetscErrorCode MatProductCreateWithMat(Mat A, Mat B, Mat C, Mat D) { 911 PetscFunctionBegin; 912 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 913 PetscValidType(A, 1); 914 MatCheckPreallocated(A, 1); 915 PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 916 PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 917 918 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 919 PetscValidType(B, 2); 920 MatCheckPreallocated(B, 2); 921 PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 922 PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 923 924 if (C) { 925 PetscValidHeaderSpecific(C, MAT_CLASSID, 3); 926 PetscValidType(C, 3); 927 MatCheckPreallocated(C, 3); 928 PetscCheck(C->assembled, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 929 PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 930 } 931 932 PetscValidHeaderSpecific(D, MAT_CLASSID, 4); 933 PetscValidType(D, 4); 934 MatCheckPreallocated(D, 4); 935 PetscCheck(D->assembled, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 936 PetscCheck(!D->factortype, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 937 938 /* Create a supporting struct and attach it to D */ 939 PetscCall(MatProductClear(D)); 940 PetscCall(MatProductCreate_Private(A, B, C, D)); 941 PetscFunctionReturn(0); 942 } 943 944 /*@ 945 MatProductCreate - create a matrix product object that can be used to compute various matrix times matrix operations such as A*B, R*A*P 946 947 Collective on Mat 948 949 Input Parameters: 950 + A - the first matrix 951 . B - the second matrix 952 - C - the third matrix (optional) 953 954 Output Parameters: 955 . D - the product matrix 956 957 Level: intermediate 958 959 Example of Usage: 960 .vb 961 `MatProductCreate`(A,B,C,&D); or `MatProductCreateWithMat`(A,B,C,D) 962 `MatProductSetType`(D, `MATPRODUCT_AB` or `MATPRODUCT_AtB` or `MATPRODUCT_ABt` or `MATPRODUCT_PtAP` or `MATPRODUCT_RARt` or `MATPRODUCT_ABC`) 963 `MatProductSetAlgorithm`(D, alg) 964 `MatProductSetFill`(D,fill) 965 `MatProductSetFromOptions`(D) 966 `MatProductSymbolic`(D) 967 `MatProductNumeric`(D) 968 Change numerical values in some of the matrices 969 `MatProductNumeric`(D) 970 .ve 971 972 Notes: 973 Use `MatProductCreateWithMat()` if the matrix you wish computed, the D matrix, already exists. 974 975 The information computed during the symbolic stage can be reused for new numerical computations with the same non-zero structure 976 977 Developer Notes: 978 It is undocumented what happens if the nonzero structure of the input matrices changes. Is the symbolic stage automatically redone? Does it crash? 979 Is there error checking for it? 980 981 .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductClear()` 982 @*/ 983 PetscErrorCode MatProductCreate(Mat A, Mat B, Mat C, Mat *D) { 984 PetscFunctionBegin; 985 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 986 PetscValidType(A, 1); 987 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 988 PetscValidType(B, 2); 989 PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix A"); 990 PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix B"); 991 992 if (C) { 993 PetscValidHeaderSpecific(C, MAT_CLASSID, 3); 994 PetscValidType(C, 3); 995 PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix C"); 996 } 997 998 PetscValidPointer(D, 4); 999 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), D)); 1000 PetscCall(MatProductCreate_Private(A, B, C, *D)); 1001 PetscFunctionReturn(0); 1002 } 1003 1004 /* 1005 These are safe basic implementations of ABC, RARt and PtAP 1006 that do not rely on mat->ops->matmatop function pointers. 1007 They only use the MatProduct API and are currently used by 1008 cuSPARSE and KOKKOS-KERNELS backends 1009 */ 1010 typedef struct { 1011 Mat BC; 1012 Mat ABC; 1013 } MatMatMatPrivate; 1014 1015 static PetscErrorCode MatDestroy_MatMatMatPrivate(void *data) { 1016 MatMatMatPrivate *mmdata = (MatMatMatPrivate *)data; 1017 1018 PetscFunctionBegin; 1019 PetscCall(MatDestroy(&mmdata->BC)); 1020 PetscCall(MatDestroy(&mmdata->ABC)); 1021 PetscCall(PetscFree(data)); 1022 PetscFunctionReturn(0); 1023 } 1024 1025 static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat) { 1026 Mat_Product *product = mat->product; 1027 MatMatMatPrivate *mmabc; 1028 1029 PetscFunctionBegin; 1030 MatCheckProduct(mat, 1); 1031 PetscCheck(mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data empty"); 1032 mmabc = (MatMatMatPrivate *)mat->product->data; 1033 PetscCheck(mmabc->BC->ops->productnumeric, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing numeric stage"); 1034 /* use function pointer directly to prevent logging */ 1035 PetscCall((*mmabc->BC->ops->productnumeric)(mmabc->BC)); 1036 /* swap ABC product stuff with that of ABC for the numeric phase on mat */ 1037 mat->product = mmabc->ABC->product; 1038 mat->ops->productnumeric = mmabc->ABC->ops->productnumeric; 1039 /* use function pointer directly to prevent logging */ 1040 PetscUseTypeMethod(mat, productnumeric); 1041 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1042 mat->product = product; 1043 PetscFunctionReturn(0); 1044 } 1045 1046 PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat) { 1047 Mat_Product *product = mat->product; 1048 Mat A, B, C; 1049 MatProductType p1, p2; 1050 MatMatMatPrivate *mmabc; 1051 const char *prefix; 1052 1053 PetscFunctionBegin; 1054 MatCheckProduct(mat, 1); 1055 PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data not empty"); 1056 PetscCall(MatGetOptionsPrefix(mat, &prefix)); 1057 PetscCall(PetscNew(&mmabc)); 1058 product->data = mmabc; 1059 product->destroy = MatDestroy_MatMatMatPrivate; 1060 switch (product->type) { 1061 case MATPRODUCT_PtAP: 1062 p1 = MATPRODUCT_AB; 1063 p2 = MATPRODUCT_AtB; 1064 A = product->B; 1065 B = product->A; 1066 C = product->B; 1067 break; 1068 case MATPRODUCT_RARt: 1069 p1 = MATPRODUCT_ABt; 1070 p2 = MATPRODUCT_AB; 1071 A = product->B; 1072 B = product->A; 1073 C = product->B; 1074 break; 1075 case MATPRODUCT_ABC: 1076 p1 = MATPRODUCT_AB; 1077 p2 = MATPRODUCT_AB; 1078 A = product->A; 1079 B = product->B; 1080 C = product->C; 1081 break; 1082 default: SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Not for ProductType %s", MatProductTypes[product->type]); 1083 } 1084 PetscCall(MatProductCreate(B, C, NULL, &mmabc->BC)); 1085 PetscCall(MatSetOptionsPrefix(mmabc->BC, prefix)); 1086 PetscCall(MatAppendOptionsPrefix(mmabc->BC, "P1_")); 1087 PetscCall(MatProductSetType(mmabc->BC, p1)); 1088 PetscCall(MatProductSetAlgorithm(mmabc->BC, MATPRODUCTALGORITHMDEFAULT)); 1089 PetscCall(MatProductSetFill(mmabc->BC, product->fill)); 1090 mmabc->BC->product->api_user = product->api_user; 1091 PetscCall(MatProductSetFromOptions(mmabc->BC)); 1092 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); 1093 /* use function pointer directly to prevent logging */ 1094 PetscCall((*mmabc->BC->ops->productsymbolic)(mmabc->BC)); 1095 1096 PetscCall(MatProductCreate(A, mmabc->BC, NULL, &mmabc->ABC)); 1097 PetscCall(MatSetOptionsPrefix(mmabc->ABC, prefix)); 1098 PetscCall(MatAppendOptionsPrefix(mmabc->ABC, "P2_")); 1099 PetscCall(MatProductSetType(mmabc->ABC, p2)); 1100 PetscCall(MatProductSetAlgorithm(mmabc->ABC, MATPRODUCTALGORITHMDEFAULT)); 1101 PetscCall(MatProductSetFill(mmabc->ABC, product->fill)); 1102 mmabc->ABC->product->api_user = product->api_user; 1103 PetscCall(MatProductSetFromOptions(mmabc->ABC)); 1104 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); 1105 /* swap ABC product stuff with that of ABC for the symbolic phase on mat */ 1106 mat->product = mmabc->ABC->product; 1107 mat->ops->productsymbolic = mmabc->ABC->ops->productsymbolic; 1108 /* use function pointer directly to prevent logging */ 1109 PetscUseTypeMethod(mat, productsymbolic); 1110 mmabc->ABC->ops->productnumeric = mat->ops->productnumeric; 1111 mat->ops->productsymbolic = MatProductSymbolic_ABC_Basic; 1112 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1113 mat->product = product; 1114 PetscFunctionReturn(0); 1115 } 1116 1117 /*@ 1118 MatProductGetType - Returns the type of the MatProduct. 1119 1120 Not collective 1121 1122 Input Parameter: 1123 . mat - the matrix 1124 1125 Output Parameter: 1126 . mtype - the MatProduct type 1127 1128 Level: intermediate 1129 1130 .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductCreate()`, `MatProductType` 1131 @*/ 1132 PetscErrorCode MatProductGetType(Mat mat, MatProductType *mtype) { 1133 PetscFunctionBegin; 1134 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1135 PetscValidPointer(mtype, 2); 1136 *mtype = MATPRODUCT_UNSPECIFIED; 1137 if (mat->product) *mtype = mat->product->type; 1138 PetscFunctionReturn(0); 1139 } 1140 1141 /*@ 1142 MatProductGetMats - Returns the matrices associated with the MatProduct. 1143 1144 Not collective 1145 1146 Input Parameter: 1147 . mat - the product matrix 1148 1149 Output Parameters: 1150 + A - the first matrix 1151 . B - the second matrix 1152 - C - the third matrix (optional) 1153 1154 Level: intermediate 1155 1156 .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()` 1157 @*/ 1158 PetscErrorCode MatProductGetMats(Mat mat, Mat *A, Mat *B, Mat *C) { 1159 PetscFunctionBegin; 1160 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1161 if (A) *A = mat->product ? mat->product->A : NULL; 1162 if (B) *B = mat->product ? mat->product->B : NULL; 1163 if (C) *C = mat->product ? mat->product->C : NULL; 1164 PetscFunctionReturn(0); 1165 } 1166