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