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