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