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