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