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