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(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(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(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 /*@ 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: [](ch_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(MatSetOption(C, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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) An = Am; 417 418 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, 419 MatProductTypes[product->type], A->rmap->N, A->cmap->N, bname, B->rmap->N, B->cmap->N); 420 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, 421 MatProductTypes[product->type], B->rmap->N, B->cmap->N, Cm, Cn); 422 423 fA = A->ops->productsetfromoptions; 424 fB = B->ops->productsetfromoptions; 425 fC = C ? C->ops->productsetfromoptions : fA; 426 if (C) { 427 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)); 428 } else { 429 PetscCall(PetscInfo(mat, "MatProductType %s for A %s, %s %s\n", MatProductTypes[product->type], ((PetscObject)A)->type_name, bname, ((PetscObject)B)->type_name)); 430 } 431 if (fA == fB && fA == fC && fA) { 432 PetscCall(PetscInfo(mat, " matching op\n")); 433 PetscCall((*fA)(mat)); 434 } 435 /* We may have found f but it did not succeed */ 436 if (!mat->ops->productsymbolic) { /* query MatProductSetFromOptions_Atype_Btype_Ctype */ 437 char mtypes[256]; 438 PetscCall(PetscStrncpy(mtypes, "MatProductSetFromOptions_", sizeof(mtypes))); 439 PetscCall(PetscStrlcat(mtypes, ((PetscObject)A)->type_name, sizeof(mtypes))); 440 PetscCall(PetscStrlcat(mtypes, "_", sizeof(mtypes))); 441 PetscCall(PetscStrlcat(mtypes, ((PetscObject)B)->type_name, sizeof(mtypes))); 442 if (C) { 443 PetscCall(PetscStrlcat(mtypes, "_", sizeof(mtypes))); 444 PetscCall(PetscStrlcat(mtypes, ((PetscObject)C)->type_name, sizeof(mtypes))); 445 } 446 PetscCall(PetscStrlcat(mtypes, "_C", sizeof(mtypes))); 447 #if defined(__clang__) 448 PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wformat-pedantic") 449 #elif defined(__GNUC__) || defined(__GNUG__) 450 PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wformat") 451 #endif 452 PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f)); 453 PetscCall(PetscInfo(mat, " querying %s from A? %p\n", mtypes, f)); 454 if (!f) { 455 PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f)); 456 PetscCall(PetscInfo(mat, " querying %s from %s? %p\n", mtypes, bname, f)); 457 } 458 if (!f && C) { 459 PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f)); 460 PetscCall(PetscInfo(mat, " querying %s from C? %p\n", mtypes, f)); 461 } 462 if (f) PetscCall((*f)(mat)); 463 464 /* We may have found f but it did not succeed */ 465 /* some matrices (i.e. MATTRANSPOSEVIRTUAL, MATSHELL constructed from MatConvert), knows what to do with their inner matrices */ 466 if (!mat->ops->productsymbolic) { 467 PetscCall(PetscStrncpy(mtypes, "MatProductSetFromOptions_anytype_C", sizeof(mtypes))); 468 PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f)); 469 PetscCall(PetscInfo(mat, " querying %s from A? %p\n", mtypes, f)); 470 if (!f) { 471 PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f)); 472 PetscCall(PetscInfo(mat, " querying %s from %s? %p\n", mtypes, bname, f)); 473 } 474 if (!f && C) { 475 PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f)); 476 PetscCall(PetscInfo(mat, " querying %s from C? %p\n", mtypes, f)); 477 } 478 } 479 if (f) PetscCall((*f)(mat)); 480 } 481 PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END() 482 /* We may have found f but it did not succeed */ 483 if (!mat->ops->productsymbolic) { 484 /* we can still compute the product if B is of type dense */ 485 if (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB) { 486 PetscBool isdense; 487 488 PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)B, &isdense, MATSEQDENSE, MATMPIDENSE, "")); 489 if (isdense) { 490 mat->ops->productsymbolic = MatProductSymbolic_X_Dense; 491 PetscCall(PetscInfo(mat, " using basic looping over columns of a dense matrix\n")); 492 } 493 } else if (product->type != MATPRODUCT_ABt) { /* use MatProductSymbolic/Numeric_Unsafe() for triple products only */ 494 /* 495 TODO: this should be changed to a proper setfromoptions, not setting the symbolic pointer here, because we do not know if 496 the combination will succeed. In order to be sure, we need MatProductGetProductType to return the type of the result 497 before computing the symbolic phase 498 */ 499 PetscCall(PetscInfo(mat, " symbolic product not supported, using MatProductSymbolic_Unsafe() implementation\n")); 500 mat->ops->productsymbolic = MatProductSymbolic_Unsafe; 501 } 502 } 503 if (!mat->ops->productsymbolic) PetscCall(PetscInfo(mat, " symbolic product is not supported\n")); 504 PetscFunctionReturn(PETSC_SUCCESS); 505 } 506 507 /*@ 508 MatProductSetFromOptions - Sets the options for the computation of a matrix-matrix product operation where the type, 509 the algorithm etc are determined from the options database. 510 511 Logically Collective 512 513 Input Parameter: 514 . mat - the matrix whose values are computed via a matrix-matrix product operation 515 516 Options Database Keys: 517 + -mat_product_clear - Clear intermediate data structures after `MatProductNumeric()` has been called 518 . -mat_product_algorithm <algorithm> - Sets the algorithm, see `MatProductAlgorithm` for possible values 519 - -mat_product_algorithm_backend_cpu - Use the CPU to perform the computation even if the matrix is a GPU matrix 520 521 Level: intermediate 522 523 Note: 524 The `-mat_product_clear` option reduces memory usage but means that the matrix cannot be re-used for a matrix-matrix product operation 525 526 .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatSetFromOptions()`, `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductNumeric()`, 527 `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductAlgorithm` 528 @*/ 529 PetscErrorCode MatProductSetFromOptions(Mat mat) 530 { 531 PetscFunctionBegin; 532 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 533 MatCheckProduct(mat, 1); 534 PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot call MatProductSetFromOptions() with already present data"); 535 mat->product->setfromoptionscalled = PETSC_TRUE; 536 PetscObjectOptionsBegin((PetscObject)mat); 537 PetscCall(PetscOptionsBool("-mat_product_clear", "Clear intermediate data structures after MatProductNumeric() has been called", "MatProductClear", mat->product->clear, &mat->product->clear, NULL)); 538 PetscCall(PetscOptionsDeprecated("-mat_freeintermediatedatastructures", "-mat_product_clear", "3.13", "Or call MatProductClear() after MatProductNumeric()")); 539 PetscOptionsEnd(); 540 PetscCall(MatProductSetFromOptions_Private(mat)); 541 PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing product after setup phase"); 542 PetscFunctionReturn(PETSC_SUCCESS); 543 } 544 545 /*@ 546 MatProductView - View the private matrix-matrix algorithm object within a matrix 547 548 Logically Collective 549 550 Input Parameters: 551 + mat - the matrix obtained with `MatProductCreate()` or `MatProductCreateWithMat()` 552 - viewer - where the information on the matrix-matrix algorithm of `mat` should be reviewed 553 554 Level: intermediate 555 556 Developer Note: 557 Shouldn't this information be printed from an appropriate `MatView()` with perhaps certain formats set? 558 559 .seealso: [](ch_matrices), `MatProductType`, `Mat`, `MatProductSetFromOptions()`, `MatView()`, `MatProductCreate()`, `MatProductCreateWithMat()` 560 @*/ 561 PetscErrorCode MatProductView(Mat mat, PetscViewer viewer) 562 { 563 PetscFunctionBegin; 564 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 565 if (!mat->product) PetscFunctionReturn(PETSC_SUCCESS); 566 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer)); 567 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 568 PetscCheckSameComm(mat, 1, viewer, 2); 569 if (mat->product->view) PetscCall((*mat->product->view)(mat, viewer)); 570 PetscFunctionReturn(PETSC_SUCCESS); 571 } 572 573 /* these are basic implementations relying on the old function pointers 574 * they are dangerous and should be removed in the future */ 575 PetscErrorCode MatProductNumeric_AB(Mat mat) 576 { 577 Mat_Product *product = mat->product; 578 Mat A = product->A, B = product->B; 579 580 PetscFunctionBegin; 581 PetscCall((*mat->ops->matmultnumeric)(A, B, mat)); 582 PetscFunctionReturn(PETSC_SUCCESS); 583 } 584 585 PetscErrorCode MatProductNumeric_AtB(Mat mat) 586 { 587 Mat_Product *product = mat->product; 588 Mat A = product->A, B = product->B; 589 590 PetscFunctionBegin; 591 PetscCall((*mat->ops->transposematmultnumeric)(A, B, mat)); 592 PetscFunctionReturn(PETSC_SUCCESS); 593 } 594 595 PetscErrorCode MatProductNumeric_ABt(Mat mat) 596 { 597 Mat_Product *product = mat->product; 598 Mat A = product->A, B = product->B; 599 600 PetscFunctionBegin; 601 PetscCall((*mat->ops->mattransposemultnumeric)(A, B, mat)); 602 PetscFunctionReturn(PETSC_SUCCESS); 603 } 604 605 PetscErrorCode MatProductNumeric_PtAP(Mat mat) 606 { 607 Mat_Product *product = mat->product; 608 Mat A = product->A, B = product->B; 609 610 PetscFunctionBegin; 611 PetscCall((*mat->ops->ptapnumeric)(A, B, mat)); 612 PetscFunctionReturn(PETSC_SUCCESS); 613 } 614 615 PetscErrorCode MatProductNumeric_RARt(Mat mat) 616 { 617 Mat_Product *product = mat->product; 618 Mat A = product->A, B = product->B; 619 620 PetscFunctionBegin; 621 PetscCall((*mat->ops->rartnumeric)(A, B, mat)); 622 PetscFunctionReturn(PETSC_SUCCESS); 623 } 624 625 PetscErrorCode MatProductNumeric_ABC(Mat mat) 626 { 627 Mat_Product *product = mat->product; 628 Mat A = product->A, B = product->B, C = product->C; 629 630 PetscFunctionBegin; 631 PetscCall((*mat->ops->matmatmultnumeric)(A, B, C, mat)); 632 PetscFunctionReturn(PETSC_SUCCESS); 633 } 634 635 /*@ 636 MatProductNumeric - Compute a matrix-matrix product operation with the numerical values 637 638 Collective 639 640 Input/Output Parameter: 641 . mat - the matrix whose values are computed via a matrix-matrix product operation 642 643 Level: intermediate 644 645 Note: 646 `MatProductSymbolic()` must have been called on `mat` before calling this function 647 648 .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductSetAlgorithm()`, `MatProductSetType()`, `MatProductCreate()`, `MatSetType()`, `MatProductSymbolic()` 649 @*/ 650 PetscErrorCode MatProductNumeric(Mat mat) 651 { 652 PetscLogEvent eventtype = -1; 653 654 PetscFunctionBegin; 655 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 656 MatCheckProduct(mat, 1); 657 switch (mat->product->type) { 658 case MATPRODUCT_AB: 659 eventtype = MAT_MatMultNumeric; 660 break; 661 case MATPRODUCT_AtB: 662 eventtype = MAT_TransposeMatMultNumeric; 663 break; 664 case MATPRODUCT_ABt: 665 eventtype = MAT_MatTransposeMultNumeric; 666 break; 667 case MATPRODUCT_PtAP: 668 eventtype = MAT_PtAPNumeric; 669 break; 670 case MATPRODUCT_RARt: 671 eventtype = MAT_RARtNumeric; 672 break; 673 case MATPRODUCT_ABC: 674 eventtype = MAT_MatMatMultNumeric; 675 break; 676 default: 677 SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]); 678 } 679 680 if (mat->ops->productnumeric) { 681 PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0)); 682 PetscUseTypeMethod(mat, productnumeric); 683 PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0)); 684 } else if (mat->product) { 685 char errstr[256]; 686 687 if (mat->product->type == MATPRODUCT_ABC) { 688 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)); 689 } else { 690 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)); 691 } 692 SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified numeric phase for product %s", errstr); 693 } 694 PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after numeric phase for product"); 695 696 if (mat->product->clear) PetscCall(MatProductClear(mat)); 697 PetscCall(PetscObjectStateIncrease((PetscObject)mat)); 698 PetscFunctionReturn(PETSC_SUCCESS); 699 } 700 701 /* these are basic implementations relying on the old function pointers 702 * they are dangerous and should be removed in the future */ 703 PetscErrorCode MatProductSymbolic_AB(Mat mat) 704 { 705 Mat_Product *product = mat->product; 706 Mat A = product->A, B = product->B; 707 708 PetscFunctionBegin; 709 PetscCall((*mat->ops->matmultsymbolic)(A, B, product->fill, mat)); 710 mat->ops->productnumeric = MatProductNumeric_AB; 711 PetscFunctionReturn(PETSC_SUCCESS); 712 } 713 714 PetscErrorCode MatProductSymbolic_AtB(Mat mat) 715 { 716 Mat_Product *product = mat->product; 717 Mat A = product->A, B = product->B; 718 719 PetscFunctionBegin; 720 PetscCall((*mat->ops->transposematmultsymbolic)(A, B, product->fill, mat)); 721 mat->ops->productnumeric = MatProductNumeric_AtB; 722 PetscFunctionReturn(PETSC_SUCCESS); 723 } 724 725 PetscErrorCode MatProductSymbolic_ABt(Mat mat) 726 { 727 Mat_Product *product = mat->product; 728 Mat A = product->A, B = product->B; 729 730 PetscFunctionBegin; 731 PetscCall((*mat->ops->mattransposemultsymbolic)(A, B, product->fill, mat)); 732 mat->ops->productnumeric = MatProductNumeric_ABt; 733 PetscFunctionReturn(PETSC_SUCCESS); 734 } 735 736 PetscErrorCode MatProductSymbolic_ABC(Mat mat) 737 { 738 Mat_Product *product = mat->product; 739 Mat A = product->A, B = product->B, C = product->C; 740 741 PetscFunctionBegin; 742 PetscCall((*mat->ops->matmatmultsymbolic)(A, B, C, product->fill, mat)); 743 mat->ops->productnumeric = MatProductNumeric_ABC; 744 PetscFunctionReturn(PETSC_SUCCESS); 745 } 746 747 /*@ 748 MatProductSymbolic - Perform the symbolic portion of a matrix-matrix product operation, this creates a data structure for use with the numerical 749 product to be done with `MatProductNumeric()` 750 751 Collective 752 753 Input/Output Parameter: 754 . mat - the matrix whose values are to be computed via a matrix-matrix product operation 755 756 Level: intermediate 757 758 Note: 759 `MatProductSetFromOptions()` must have been called on `mat` before calling this function 760 761 .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductSetFromOptions()`, `MatProductNumeric()`, `MatProductSetType()`, `MatProductSetAlgorithm()` 762 @*/ 763 PetscErrorCode MatProductSymbolic(Mat mat) 764 { 765 PetscLogEvent eventtype = -1; 766 PetscBool missing = PETSC_FALSE; 767 Mat_Product *product = mat->product; 768 Mat A = product->A; 769 Mat B = product->B; 770 Mat C = product->C; 771 772 PetscFunctionBegin; 773 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 774 MatCheckProduct(mat, 1); 775 PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot run symbolic phase. Product data not empty"); 776 switch (mat->product->type) { 777 case MATPRODUCT_AB: 778 eventtype = MAT_MatMultSymbolic; 779 break; 780 case MATPRODUCT_AtB: 781 eventtype = MAT_TransposeMatMultSymbolic; 782 break; 783 case MATPRODUCT_ABt: 784 eventtype = MAT_MatTransposeMultSymbolic; 785 break; 786 case MATPRODUCT_PtAP: 787 eventtype = MAT_PtAPSymbolic; 788 break; 789 case MATPRODUCT_RARt: 790 eventtype = MAT_RARtSymbolic; 791 break; 792 case MATPRODUCT_ABC: 793 eventtype = MAT_MatMatMultSymbolic; 794 break; 795 default: 796 SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]); 797 } 798 mat->ops->productnumeric = NULL; 799 if (mat->ops->productsymbolic) { 800 PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0)); 801 PetscUseTypeMethod(mat, productsymbolic); 802 PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0)); 803 } else missing = PETSC_TRUE; 804 if (missing || !mat->product || !mat->ops->productnumeric) { 805 char errstr[256]; 806 807 if (mat->product->type == MATPRODUCT_ABC) { 808 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)); 809 } else { 810 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)); 811 } 812 PetscCheck(mat->product->setfromoptionscalled, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified symbolic phase for product %s. Call MatProductSetFromOptions() first", errstr); 813 PetscCheck(!missing, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Unspecified symbolic phase for product %s. The product is not supported", errstr); 814 PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after symbolic phase for product %s", errstr); 815 } 816 #if defined(PETSC_HAVE_DEVICE) 817 PetscBool bindingpropagates; 818 bindingpropagates = (PetscBool)((A->boundtocpu && A->bindingpropagates) || (B->boundtocpu && B->bindingpropagates)); 819 if (C) bindingpropagates = (PetscBool)(bindingpropagates || (C->boundtocpu && C->bindingpropagates)); 820 if (bindingpropagates) { 821 PetscCall(MatBindToCPU(mat, PETSC_TRUE)); 822 PetscCall(MatSetBindingPropagates(mat, PETSC_TRUE)); 823 } 824 #endif 825 /* set block sizes */ 826 switch (product->type) { 827 case MATPRODUCT_PtAP: 828 if (B->cmap->bs > 1) PetscCall(MatSetBlockSizes(mat, B->cmap->bs, B->cmap->bs)); 829 break; 830 case MATPRODUCT_RARt: 831 if (B->rmap->bs > 1) PetscCall(MatSetBlockSizes(mat, B->rmap->bs, B->rmap->bs)); 832 break; 833 case MATPRODUCT_ABC: 834 PetscCall(MatSetBlockSizesFromMats(mat, A, C)); 835 break; 836 case MATPRODUCT_AB: 837 PetscCall(MatSetBlockSizesFromMats(mat, A, B)); 838 break; 839 case MATPRODUCT_AtB: 840 if (A->cmap->bs > 1 || B->cmap->bs > 1) PetscCall(MatSetBlockSizes(mat, A->cmap->bs, B->cmap->bs)); 841 break; 842 case MATPRODUCT_ABt: 843 if (A->rmap->bs > 1 || B->rmap->bs > 1) PetscCall(MatSetBlockSizes(mat, A->rmap->bs, B->rmap->bs)); 844 break; 845 default: 846 SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Not for ProductType %s", MatProductTypes[product->type]); 847 } 848 PetscFunctionReturn(PETSC_SUCCESS); 849 } 850 851 /*@ 852 MatProductSetFill - Set an expected fill of the matrix whose values are computed via a matrix-matrix product operation 853 854 Collective 855 856 Input Parameters: 857 + mat - the matrix whose values are to be computed via a matrix-matrix product operation 858 - fill - expected fill as ratio of nnz(mat)/(nnz(A) + nnz(B) + nnz(C)); use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate. 859 If the product is a dense matrix, this value is not used. 860 861 Level: intermediate 862 863 Notes: 864 Use `fill` of `PETSC_DETERMINE` to use the default value. 865 866 The deprecated `PETSC_DEFAULT` is also supported to mean use the current value. 867 868 .seealso: [](ch_matrices), `MatProduct`, `PETSC_DETERMINE`, `Mat`, `MatProductSetFromOptions()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()` 869 @*/ 870 PetscErrorCode MatProductSetFill(Mat mat, PetscReal fill) 871 { 872 PetscFunctionBegin; 873 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 874 MatCheckProduct(mat, 1); 875 if (fill == (PetscReal)PETSC_DETERMINE) mat->product->fill = mat->product->default_fill; 876 else if (fill != (PetscReal)PETSC_CURRENT) mat->product->fill = fill; 877 PetscFunctionReturn(PETSC_SUCCESS); 878 } 879 880 /*@ 881 MatProductSetAlgorithm - Requests a particular algorithm for a matrix-matrix product operation that will perform to compute 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 - alg - particular implementation algorithm of the matrix product, e.g., `MATPRODUCTALGORITHMDEFAULT`. 888 889 Options Database Key: 890 . -mat_product_algorithm <algorithm> - Sets the algorithm, see `MatProductAlgorithm` 891 892 Level: intermediate 893 894 .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductClear()`, `MatProductSetType()`, `MatProductSetFill()`, `MatProductCreate()`, `MatProductAlgorithm`, `MatProductType`, `MatProductGetAlgorithm()` 895 @*/ 896 PetscErrorCode MatProductSetAlgorithm(Mat mat, MatProductAlgorithm alg) 897 { 898 PetscFunctionBegin; 899 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 900 MatCheckProduct(mat, 1); 901 PetscCall(PetscFree(mat->product->alg)); 902 PetscCall(PetscStrallocpy(alg, &mat->product->alg)); 903 PetscFunctionReturn(PETSC_SUCCESS); 904 } 905 906 /*@ 907 MatProductGetAlgorithm - Returns the selected algorithm for a matrix-matrix product operation 908 909 Not Collective 910 911 Input Parameter: 912 . mat - the matrix whose values are computed via a matrix-matrix product operation 913 914 Output Parameter: 915 . alg - the selected algorithm of the matrix product, e.g., `MATPRODUCTALGORITHMDEFAULT`. 916 917 Level: intermediate 918 919 .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductSetAlgorithm()` 920 @*/ 921 PetscErrorCode MatProductGetAlgorithm(Mat mat, MatProductAlgorithm *alg) 922 { 923 PetscFunctionBegin; 924 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 925 PetscAssertPointer(alg, 2); 926 if (mat->product) *alg = mat->product->alg; 927 else *alg = NULL; 928 PetscFunctionReturn(PETSC_SUCCESS); 929 } 930 931 /*@ 932 MatProductSetType - Sets a particular matrix-matrix product operation to be used to compute the values of the given matrix 933 934 Collective 935 936 Input Parameters: 937 + mat - the matrix whose values are computed via a matrix-matrix product operation 938 - productype - matrix product type, e.g., `MATPRODUCT_AB`,`MATPRODUCT_AtB`,`MATPRODUCT_ABt`,`MATPRODUCT_PtAP`,`MATPRODUCT_RARt`,`MATPRODUCT_ABC`, 939 see `MatProductType` 940 941 Level: intermediate 942 943 Note: 944 The small t represents the transpose operation. 945 946 .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()`, `MatProductType`, 947 `MATPRODUCT_AB`, `MATPRODUCT_AtB`, `MATPRODUCT_ABt`, `MATPRODUCT_PtAP`, `MATPRODUCT_RARt`, `MATPRODUCT_ABC` 948 @*/ 949 PetscErrorCode MatProductSetType(Mat mat, MatProductType productype) 950 { 951 PetscFunctionBegin; 952 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 953 MatCheckProduct(mat, 1); 954 PetscValidLogicalCollectiveEnum(mat, productype, 2); 955 if (productype != mat->product->type) { 956 if (mat->product->destroy) PetscCall((*mat->product->destroy)(mat->product->data)); 957 mat->product->destroy = NULL; 958 mat->product->data = NULL; 959 mat->ops->productsymbolic = NULL; 960 mat->ops->productnumeric = NULL; 961 } 962 mat->product->type = productype; 963 PetscFunctionReturn(PETSC_SUCCESS); 964 } 965 966 /*@ 967 MatProductClear - Clears from the matrix any internal data structures related to the computation of the values of the matrix from matrix-matrix product operations 968 969 Collective 970 971 Input Parameter: 972 . mat - the matrix whose values are to be computed via a matrix-matrix product operation 973 974 Options Database Key: 975 . -mat_product_clear - Clear intermediate data structures after `MatProductNumeric()` has been called 976 977 Level: intermediate 978 979 Notes: 980 This function should be called to remove any intermediate data used to compute the matrix to free up memory. 981 982 After having called this function, matrix-matrix product operations can no longer be used on `mat` 983 984 .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreate()` 985 @*/ 986 PetscErrorCode MatProductClear(Mat mat) 987 { 988 Mat_Product *product = mat->product; 989 990 PetscFunctionBegin; 991 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 992 if (product) { 993 PetscCall(MatDestroy(&product->A)); 994 PetscCall(MatDestroy(&product->B)); 995 PetscCall(MatDestroy(&product->C)); 996 PetscCall(PetscFree(product->alg)); 997 PetscCall(MatDestroy(&product->Dwork)); 998 if (product->destroy) PetscCall((*product->destroy)(product->data)); 999 } 1000 PetscCall(PetscFree(mat->product)); 1001 mat->ops->productsymbolic = NULL; 1002 mat->ops->productnumeric = NULL; 1003 PetscFunctionReturn(PETSC_SUCCESS); 1004 } 1005 1006 /* Create a supporting struct and attach it to the matrix product */ 1007 PetscErrorCode MatProductCreate_Private(Mat A, Mat B, Mat C, Mat D) 1008 { 1009 Mat_Product *product = NULL; 1010 1011 PetscFunctionBegin; 1012 PetscValidHeaderSpecific(D, MAT_CLASSID, 4); 1013 PetscCheck(!D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product already present"); 1014 PetscCall(PetscNew(&product)); 1015 product->A = A; 1016 product->B = B; 1017 product->C = C; 1018 product->type = MATPRODUCT_UNSPECIFIED; 1019 product->Dwork = NULL; 1020 product->api_user = PETSC_FALSE; 1021 product->clear = PETSC_FALSE; 1022 product->setfromoptionscalled = PETSC_FALSE; 1023 PetscObjectParameterSetDefault(product, fill, 2); 1024 D->product = product; 1025 1026 PetscCall(MatProductSetAlgorithm(D, MATPRODUCTALGORITHMDEFAULT)); 1027 PetscCall(MatProductSetFill(D, PETSC_DEFAULT)); 1028 1029 PetscCall(PetscObjectReference((PetscObject)A)); 1030 PetscCall(PetscObjectReference((PetscObject)B)); 1031 PetscCall(PetscObjectReference((PetscObject)C)); 1032 PetscFunctionReturn(PETSC_SUCCESS); 1033 } 1034 1035 /*@ 1036 MatProductCreateWithMat - Set a given matrix to have its values computed via matrix-matrix operations on other matrices. 1037 1038 Collective 1039 1040 Input Parameters: 1041 + A - the first matrix 1042 . B - the second matrix 1043 . C - the third matrix (optional, use `NULL` if not needed) 1044 - D - the matrix whose values are to be computed via a matrix-matrix product operation 1045 1046 Level: intermediate 1047 1048 Notes: 1049 Use `MatProductCreate()` if the matrix you wish computed (the `D` matrix) does not already exist 1050 1051 See `MatProductCreate()` for details on the usage of the matrix-matrix product operations 1052 1053 Any product data currently attached to `D` will be cleared 1054 1055 .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductType`, `MatProductSetType()`, `MatProductAlgorithm`, 1056 `MatProductSetAlgorithm`, `MatProductCreate()`, `MatProductClear()` 1057 @*/ 1058 PetscErrorCode MatProductCreateWithMat(Mat A, Mat B, Mat C, Mat D) 1059 { 1060 PetscFunctionBegin; 1061 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1062 PetscValidType(A, 1); 1063 MatCheckPreallocated(A, 1); 1064 PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 1065 PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 1066 1067 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 1068 PetscValidType(B, 2); 1069 MatCheckPreallocated(B, 2); 1070 PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 1071 PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 1072 1073 if (C) { 1074 PetscValidHeaderSpecific(C, MAT_CLASSID, 3); 1075 PetscValidType(C, 3); 1076 MatCheckPreallocated(C, 3); 1077 PetscCheck(C->assembled, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 1078 PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 1079 } 1080 1081 PetscValidHeaderSpecific(D, MAT_CLASSID, 4); 1082 PetscValidType(D, 4); 1083 MatCheckPreallocated(D, 4); 1084 PetscCheck(D->assembled, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 1085 PetscCheck(!D->factortype, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 1086 1087 /* Create a supporting struct and attach it to D */ 1088 PetscCall(MatProductClear(D)); 1089 PetscCall(MatProductCreate_Private(A, B, C, D)); 1090 PetscFunctionReturn(PETSC_SUCCESS); 1091 } 1092 1093 /*@ 1094 MatProductCreate - create a matrix to hold the result of a matrix-matrix product operation 1095 1096 Collective 1097 1098 Input Parameters: 1099 + A - the first matrix 1100 . B - the second matrix 1101 - C - the third matrix (or `NULL`) 1102 1103 Output Parameter: 1104 . D - the matrix whose values are to be computed via a matrix-matrix product operation 1105 1106 Level: intermediate 1107 1108 Example: 1109 .vb 1110 MatProductCreate(A,B,C,&D); or MatProductCreateWithMat(A,B,C,D) 1111 MatProductSetType(D, MATPRODUCT_AB or MATPRODUCT_AtB or MATPRODUCT_ABt or MATPRODUCT_PtAP or MATPRODUCT_RARt or MATPRODUCT_ABC) 1112 MatProductSetAlgorithm(D, alg) 1113 MatProductSetFill(D,fill) 1114 MatProductSetFromOptions(D) 1115 MatProductSymbolic(D) 1116 MatProductNumeric(D) 1117 Change numerical values in some of the matrices 1118 MatProductNumeric(D) 1119 .ve 1120 1121 Notes: 1122 Use `MatProductCreateWithMat()` if the matrix you wish computed, the `D` matrix, already exists. 1123 1124 The information computed during the symbolic stage can be reused for new numerical computations with the same non-zero structure 1125 1126 Developer Notes: 1127 It is undocumented what happens if the nonzero structure of the input matrices changes. Is the symbolic stage automatically redone? Does it crash? 1128 Is there error checking for it? 1129 1130 .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductClear()` 1131 @*/ 1132 PetscErrorCode MatProductCreate(Mat A, Mat B, Mat C, Mat *D) 1133 { 1134 PetscFunctionBegin; 1135 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1136 PetscValidType(A, 1); 1137 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 1138 PetscValidType(B, 2); 1139 PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix A"); 1140 PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix B"); 1141 1142 if (C) { 1143 PetscValidHeaderSpecific(C, MAT_CLASSID, 3); 1144 PetscValidType(C, 3); 1145 PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix C"); 1146 } 1147 1148 PetscAssertPointer(D, 4); 1149 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), D)); 1150 /* Delay setting type of D to the MatProduct symbolic phase, as we allow sparse A and dense B */ 1151 PetscCall(MatProductCreate_Private(A, B, C, *D)); 1152 PetscFunctionReturn(PETSC_SUCCESS); 1153 } 1154 1155 /* 1156 These are safe basic implementations of ABC, RARt and PtAP 1157 that do not rely on mat->ops->matmatop function pointers. 1158 They only use the MatProduct API and are currently used by 1159 cuSPARSE and KOKKOS-KERNELS backends 1160 */ 1161 typedef struct { 1162 Mat BC; 1163 Mat ABC; 1164 } MatMatMatPrivate; 1165 1166 static PetscErrorCode MatDestroy_MatMatMatPrivate(void *data) 1167 { 1168 MatMatMatPrivate *mmdata = (MatMatMatPrivate *)data; 1169 1170 PetscFunctionBegin; 1171 PetscCall(MatDestroy(&mmdata->BC)); 1172 PetscCall(MatDestroy(&mmdata->ABC)); 1173 PetscCall(PetscFree(data)); 1174 PetscFunctionReturn(PETSC_SUCCESS); 1175 } 1176 1177 static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat) 1178 { 1179 Mat_Product *product = mat->product; 1180 MatMatMatPrivate *mmabc; 1181 1182 PetscFunctionBegin; 1183 MatCheckProduct(mat, 1); 1184 PetscCheck(mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data empty"); 1185 mmabc = (MatMatMatPrivate *)mat->product->data; 1186 PetscCheck(mmabc->BC->ops->productnumeric, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing numeric stage"); 1187 /* use function pointer directly to prevent logging */ 1188 PetscCall((*mmabc->BC->ops->productnumeric)(mmabc->BC)); 1189 /* swap ABC product stuff with that of ABC for the numeric phase on mat */ 1190 mat->product = mmabc->ABC->product; 1191 mat->ops->productnumeric = mmabc->ABC->ops->productnumeric; 1192 /* use function pointer directly to prevent logging */ 1193 PetscUseTypeMethod(mat, productnumeric); 1194 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1195 mat->product = product; 1196 PetscFunctionReturn(PETSC_SUCCESS); 1197 } 1198 1199 PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat) 1200 { 1201 Mat_Product *product = mat->product; 1202 Mat A, B, C; 1203 MatProductType p1, p2; 1204 MatMatMatPrivate *mmabc; 1205 const char *prefix; 1206 1207 PetscFunctionBegin; 1208 MatCheckProduct(mat, 1); 1209 PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data not empty"); 1210 PetscCall(MatGetOptionsPrefix(mat, &prefix)); 1211 PetscCall(PetscNew(&mmabc)); 1212 product->data = mmabc; 1213 product->destroy = MatDestroy_MatMatMatPrivate; 1214 switch (product->type) { 1215 case MATPRODUCT_PtAP: 1216 p1 = MATPRODUCT_AB; 1217 p2 = MATPRODUCT_AtB; 1218 A = product->B; 1219 B = product->A; 1220 C = product->B; 1221 if (A->cmap->bs > 0 && C->cmap->bs > 0) PetscCall(MatSetBlockSizes(mat, A->cmap->bs, C->cmap->bs)); 1222 break; 1223 case MATPRODUCT_RARt: 1224 p1 = MATPRODUCT_ABt; 1225 p2 = MATPRODUCT_AB; 1226 A = product->B; 1227 B = product->A; 1228 C = product->B; 1229 if (A->rmap->bs > 0 && C->rmap->bs > 0) PetscCall(MatSetBlockSizes(mat, A->rmap->bs, C->rmap->bs)); 1230 break; 1231 case MATPRODUCT_ABC: 1232 p1 = MATPRODUCT_AB; 1233 p2 = MATPRODUCT_AB; 1234 A = product->A; 1235 B = product->B; 1236 C = product->C; 1237 PetscCall(MatSetBlockSizesFromMats(mat, A, C)); 1238 break; 1239 default: 1240 SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Not for ProductType %s", MatProductTypes[product->type]); 1241 } 1242 PetscCall(MatProductCreate(B, C, NULL, &mmabc->BC)); 1243 PetscCall(MatSetOptionsPrefix(mmabc->BC, prefix)); 1244 PetscCall(MatAppendOptionsPrefix(mmabc->BC, "P1_")); 1245 PetscCall(MatProductSetType(mmabc->BC, p1)); 1246 PetscCall(MatProductSetAlgorithm(mmabc->BC, MATPRODUCTALGORITHMDEFAULT)); 1247 PetscCall(MatProductSetFill(mmabc->BC, product->fill)); 1248 mmabc->BC->product->api_user = product->api_user; 1249 PetscCall(MatProductSetFromOptions(mmabc->BC)); 1250 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); 1251 /* use function pointer directly to prevent logging */ 1252 PetscCall((*mmabc->BC->ops->productsymbolic)(mmabc->BC)); 1253 1254 PetscCall(MatProductCreate(A, mmabc->BC, NULL, &mmabc->ABC)); 1255 PetscCall(MatSetOptionsPrefix(mmabc->ABC, prefix)); 1256 PetscCall(MatAppendOptionsPrefix(mmabc->ABC, "P2_")); 1257 PetscCall(MatProductSetType(mmabc->ABC, p2)); 1258 PetscCall(MatProductSetAlgorithm(mmabc->ABC, MATPRODUCTALGORITHMDEFAULT)); 1259 PetscCall(MatProductSetFill(mmabc->ABC, product->fill)); 1260 mmabc->ABC->product->api_user = product->api_user; 1261 PetscCall(MatProductSetFromOptions(mmabc->ABC)); 1262 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); 1263 /* swap ABC product stuff with that of ABC for the symbolic phase on mat */ 1264 mat->product = mmabc->ABC->product; 1265 mat->ops->productsymbolic = mmabc->ABC->ops->productsymbolic; 1266 /* use function pointer directly to prevent logging */ 1267 PetscUseTypeMethod(mat, productsymbolic); 1268 mmabc->ABC->ops->productnumeric = mat->ops->productnumeric; 1269 mat->ops->productsymbolic = MatProductSymbolic_ABC_Basic; 1270 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1271 mat->product = product; 1272 PetscFunctionReturn(PETSC_SUCCESS); 1273 } 1274 1275 /*@ 1276 MatProductGetType - Returns the type of matrix-matrix product associated with computing values for the given matrix 1277 1278 Not Collective 1279 1280 Input Parameter: 1281 . mat - the matrix whose values are to be computed via a matrix-matrix product operation 1282 1283 Output Parameter: 1284 . mtype - the `MatProductType` 1285 1286 Level: intermediate 1287 1288 .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductCreate()`, `MatProductType`, `MatProductAlgorithm` 1289 @*/ 1290 PetscErrorCode MatProductGetType(Mat mat, MatProductType *mtype) 1291 { 1292 PetscFunctionBegin; 1293 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1294 PetscAssertPointer(mtype, 2); 1295 *mtype = MATPRODUCT_UNSPECIFIED; 1296 if (mat->product) *mtype = mat->product->type; 1297 PetscFunctionReturn(PETSC_SUCCESS); 1298 } 1299 1300 /*@ 1301 MatProductGetMats - Returns the matrices associated with the matrix-matrix product associated with computing values for the given matrix 1302 1303 Not Collective 1304 1305 Input Parameter: 1306 . mat - the matrix whose values are to be computed via a matrix-matrix product operation 1307 1308 Output Parameters: 1309 + A - the first matrix 1310 . B - the second matrix 1311 - C - the third matrix (may be `NULL` for some `MatProductType`) 1312 1313 Level: intermediate 1314 1315 .seealso: [](ch_matrices), `MatProduct`, `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()` 1316 @*/ 1317 PetscErrorCode MatProductGetMats(Mat mat, Mat *A, Mat *B, Mat *C) 1318 { 1319 PetscFunctionBegin; 1320 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1321 if (A) *A = mat->product ? mat->product->A : NULL; 1322 if (B) *B = mat->product ? mat->product->B : NULL; 1323 if (C) *C = mat->product ? mat->product->C : NULL; 1324 PetscFunctionReturn(PETSC_SUCCESS); 1325 } 1326