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 /*@C 201 MatProductReplaceMats - Replace the input matrices for the matrix-matrix product operation inside the computed matrix 202 203 Collective 204 205 Input Parameters: 206 + A - the matrix or `NULL` if not being replaced 207 . B - the matrix or `NULL` if not being replaced 208 . C - the matrix or `NULL` if not being replaced 209 - D - the matrix whose values are computed via a matrix-matrix product operation 210 211 Level: intermediate 212 213 Note: 214 To reuse the symbolic phase, the input matrices must have exactly the same data structure as the replaced one. 215 If the type of any of the input matrices is different than what was previously used, or their symmetry flag changed but 216 the symbolic phase took advantage of their symmetry, the product is cleared and `MatProductSetFromOptions()` 217 and `MatProductSymbolic()` are invoked again. 218 219 .seealso: `Mat`, `MatProductCreate()`, `MatProductSetFromOptions()`, `MatProductSymbolic().` `MatProductClear()` 220 @*/ 221 PetscErrorCode MatProductReplaceMats(Mat A, Mat B, Mat C, Mat D) 222 { 223 Mat_Product *product; 224 PetscBool flgA = PETSC_TRUE, flgB = PETSC_TRUE, flgC = PETSC_TRUE, isset, issym; 225 226 PetscFunctionBegin; 227 PetscValidHeaderSpecific(D, MAT_CLASSID, 4); 228 MatCheckProduct(D, 4); 229 product = D->product; 230 if (A) { 231 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 232 PetscCall(PetscObjectReference((PetscObject)A)); 233 PetscCall(PetscObjectTypeCompare((PetscObject)product->A, ((PetscObject)A)->type_name, &flgA)); 234 PetscCall(MatIsSymmetricKnown(A, &isset, &issym)); 235 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 */ 236 flgA = PETSC_FALSE; 237 product->symbolic_used_the_fact_A_is_symmetric = PETSC_FALSE; /* reinit */ 238 } 239 PetscCall(MatDestroy(&product->A)); 240 product->A = A; 241 } 242 if (B) { 243 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 244 PetscCall(PetscObjectReference((PetscObject)B)); 245 PetscCall(PetscObjectTypeCompare((PetscObject)product->B, ((PetscObject)B)->type_name, &flgB)); 246 PetscCall(MatIsSymmetricKnown(B, &isset, &issym)); 247 if (product->symbolic_used_the_fact_B_is_symmetric && isset && !issym) { 248 flgB = PETSC_FALSE; 249 product->symbolic_used_the_fact_B_is_symmetric = PETSC_FALSE; /* reinit */ 250 } 251 PetscCall(MatDestroy(&product->B)); 252 product->B = B; 253 } 254 if (C) { 255 PetscValidHeaderSpecific(C, MAT_CLASSID, 3); 256 PetscCall(PetscObjectReference((PetscObject)C)); 257 PetscCall(PetscObjectTypeCompare((PetscObject)product->C, ((PetscObject)C)->type_name, &flgC)); 258 PetscCall(MatIsSymmetricKnown(C, &isset, &issym)); 259 if (product->symbolic_used_the_fact_C_is_symmetric && isset && !issym) { 260 flgC = PETSC_FALSE; 261 product->symbolic_used_the_fact_C_is_symmetric = PETSC_FALSE; /* reinit */ 262 } 263 PetscCall(MatDestroy(&product->C)); 264 product->C = C; 265 } 266 /* Any of the replaced mats is of a different type, reset */ 267 if (!flgA || !flgB || !flgC) { 268 if (D->product->destroy) PetscCall((*D->product->destroy)(D->product->data)); 269 D->product->destroy = NULL; 270 D->product->data = NULL; 271 if (D->ops->productnumeric || D->ops->productsymbolic) { 272 PetscCall(MatProductSetFromOptions(D)); 273 PetscCall(MatProductSymbolic(D)); 274 } 275 } 276 PetscFunctionReturn(PETSC_SUCCESS); 277 } 278 279 static PetscErrorCode MatProductNumeric_X_Dense(Mat C) 280 { 281 Mat_Product *product = C->product; 282 Mat A = product->A, B = product->B; 283 PetscInt k, K = B->cmap->N; 284 PetscBool t = PETSC_TRUE, iscuda = PETSC_FALSE; 285 PetscBool Bcpu = PETSC_TRUE, Ccpu = PETSC_TRUE; 286 char *Btype = NULL, *Ctype = NULL; 287 288 PetscFunctionBegin; 289 switch (product->type) { 290 case MATPRODUCT_AB: 291 t = PETSC_FALSE; 292 case MATPRODUCT_AtB: 293 break; 294 default: 295 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); 296 } 297 if (PetscDefined(HAVE_CUDA)) { 298 VecType vtype; 299 300 PetscCall(MatGetVecType(A, &vtype)); 301 PetscCall(PetscStrcmp(vtype, VECCUDA, &iscuda)); 302 if (!iscuda) PetscCall(PetscStrcmp(vtype, VECSEQCUDA, &iscuda)); 303 if (!iscuda) PetscCall(PetscStrcmp(vtype, VECMPICUDA, &iscuda)); 304 if (iscuda) { /* Make sure we have up-to-date data on the GPU */ 305 PetscCall(PetscStrallocpy(((PetscObject)B)->type_name, &Btype)); 306 PetscCall(PetscStrallocpy(((PetscObject)C)->type_name, &Ctype)); 307 PetscCall(MatConvert(B, MATDENSECUDA, MAT_INPLACE_MATRIX, &B)); 308 if (!C->assembled) { /* need to flag the matrix as assembled, otherwise MatConvert will complain */ 309 PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 310 PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 311 } 312 PetscCall(MatConvert(C, MATDENSECUDA, MAT_INPLACE_MATRIX, &C)); 313 } else { /* Make sure we have up-to-date data on the CPU */ 314 #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_VIENNACL) 315 Bcpu = B->boundtocpu; 316 Ccpu = C->boundtocpu; 317 #endif 318 PetscCall(MatBindToCPU(B, PETSC_TRUE)); 319 PetscCall(MatBindToCPU(C, PETSC_TRUE)); 320 } 321 } 322 for (k = 0; k < K; k++) { 323 Vec x, y; 324 325 PetscCall(MatDenseGetColumnVecRead(B, k, &x)); 326 PetscCall(MatDenseGetColumnVecWrite(C, k, &y)); 327 if (t) { 328 PetscCall(MatMultTranspose(A, x, y)); 329 } else { 330 PetscCall(MatMult(A, x, y)); 331 } 332 PetscCall(MatDenseRestoreColumnVecRead(B, k, &x)); 333 PetscCall(MatDenseRestoreColumnVecWrite(C, k, &y)); 334 } 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 #pragma clang diagnostic push 452 #pragma clang diagnostic ignored "-Wformat-pedantic" 453 #elif defined(__GNUC__) || defined(__GNUG__) 454 #pragma GCC diagnostic push 455 #pragma GCC diagnostic ignored "-Wformat" 456 #endif 457 PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f)); 458 PetscCall(PetscInfo(mat, " querying %s from A? %p\n", mtypes, f)); 459 if (!f) { 460 PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f)); 461 PetscCall(PetscInfo(mat, " querying %s from %s? %p\n", mtypes, bname, f)); 462 } 463 if (!f && C) { 464 PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f)); 465 PetscCall(PetscInfo(mat, " querying %s from C? %p\n", mtypes, f)); 466 } 467 if (f) PetscCall((*f)(mat)); 468 469 /* We may have found f but it did not succeed */ 470 /* some matrices (i.e. MATTRANSPOSEVIRTUAL, MATSHELL constructed from MatConvert), knows what to do with their inner matrices */ 471 if (!mat->ops->productsymbolic) { 472 PetscCall(PetscStrncpy(mtypes, "MatProductSetFromOptions_anytype_C", sizeof(mtypes))); 473 PetscCall(PetscObjectQueryFunction((PetscObject)A, mtypes, &f)); 474 PetscCall(PetscInfo(mat, " querying %s from A? %p\n", mtypes, f)); 475 if (!f) { 476 PetscCall(PetscObjectQueryFunction((PetscObject)B, mtypes, &f)); 477 PetscCall(PetscInfo(mat, " querying %s from %s? %p\n", mtypes, bname, f)); 478 } 479 if (!f && C) { 480 PetscCall(PetscObjectQueryFunction((PetscObject)C, mtypes, &f)); 481 PetscCall(PetscInfo(mat, " querying %s from C? %p\n", mtypes, f)); 482 } 483 } 484 if (f) PetscCall((*f)(mat)); 485 } 486 #if defined(__clang__) 487 #pragma clang diagnostic pop 488 #elif defined(__GNUC__) || defined(__GNUG__) 489 #pragma GCC diagnostic pop 490 #endif 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 /*@C 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 Key: 526 . -mat_product_clear - Clear intermediate data structures after `MatProductNumeric()` has been called 527 528 Level: intermediate 529 530 Note: 531 This reduces memory usage but means that the matrix cannot be re-used for a matrix-matrix product operation 532 533 .seealso: `Mat`, `MatSetFromOptions()`, `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductNumeric()`, `MatProductSetType()`, `MatProductSetAlgorithm()` 534 @*/ 535 PetscErrorCode MatProductSetFromOptions(Mat mat) 536 { 537 PetscFunctionBegin; 538 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 539 MatCheckProduct(mat, 1); 540 PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot call MatProductSetFromOptions with already present data"); 541 PetscObjectOptionsBegin((PetscObject)mat); 542 PetscCall(PetscOptionsBool("-mat_product_clear", "Clear intermediate data structures after MatProductNumeric() has been called", "MatProductClear", mat->product->clear, &mat->product->clear, NULL)); 543 PetscCall(PetscOptionsDeprecated("-mat_freeintermediatedatastructures", "-mat_product_clear", "3.13", "Or call MatProductClear() after MatProductNumeric()")); 544 PetscOptionsEnd(); 545 PetscCall(MatProductSetFromOptions_Private(mat)); 546 PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing product after setup phase"); 547 PetscFunctionReturn(PETSC_SUCCESS); 548 } 549 550 /*@C 551 MatProductView - View the private matrix-matrix algorithm object within a matrix 552 553 Logically Collective 554 555 Input Parameters: 556 + mat - the matrix obtained with `MatProductCreate()` or `MatProductCreateWithMat()` 557 - viewer - where `mat` should be reviewed 558 559 Level: intermediate 560 561 .seealso: `Mat`, `MatProductSetFromOptions()`, `MatView()`, `MatProductCreate()`, `MatProductCreateWithMat()` 562 @*/ 563 PetscErrorCode MatProductView(Mat mat, PetscViewer viewer) 564 { 565 PetscFunctionBegin; 566 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 567 if (!mat->product) PetscFunctionReturn(PETSC_SUCCESS); 568 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer)); 569 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 570 PetscCheckSameComm(mat, 1, viewer, 2); 571 if (mat->product->view) PetscCall((*mat->product->view)(mat, viewer)); 572 PetscFunctionReturn(PETSC_SUCCESS); 573 } 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 640 /*@ 641 MatProductNumeric - Compute a matrix-matrix product operation with numerical values. 642 643 Collective 644 645 Input/Output Parameter: 646 . mat - the matrix whose values are computed via a matrix-matrix product operation 647 648 Level: intermediate 649 650 Note: 651 `MatProductSymbolic()` must have been called on `mat` before calling this function 652 653 .seealso: `Mat`, `MatProductSetAlgorithm()`, `MatProductSetType()`, `MatProductCreate()`, `MatSetType()`, `MatProductSymbolic()` 654 @*/ 655 PetscErrorCode MatProductNumeric(Mat mat) 656 { 657 PetscLogEvent eventtype = -1; 658 PetscBool missing = PETSC_FALSE; 659 660 PetscFunctionBegin; 661 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 662 MatCheckProduct(mat, 1); 663 switch (mat->product->type) { 664 case MATPRODUCT_AB: 665 eventtype = MAT_MatMultNumeric; 666 break; 667 case MATPRODUCT_AtB: 668 eventtype = MAT_TransposeMatMultNumeric; 669 break; 670 case MATPRODUCT_ABt: 671 eventtype = MAT_MatTransposeMultNumeric; 672 break; 673 case MATPRODUCT_PtAP: 674 eventtype = MAT_PtAPNumeric; 675 break; 676 case MATPRODUCT_RARt: 677 eventtype = MAT_RARtNumeric; 678 break; 679 case MATPRODUCT_ABC: 680 eventtype = MAT_MatMatMultNumeric; 681 break; 682 default: 683 SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]); 684 } 685 686 if (mat->ops->productnumeric) { 687 PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0)); 688 PetscUseTypeMethod(mat, productnumeric); 689 PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0)); 690 } else missing = PETSC_TRUE; 691 692 if (missing || !mat->product) { 693 char errstr[256]; 694 695 if (mat->product->type == MATPRODUCT_ABC) { 696 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)); 697 } else { 698 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)); 699 } 700 PetscCheck(!missing, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified numeric phase for product %s", errstr); 701 PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after symbolic phase for product %s", errstr); 702 } 703 704 if (mat->product->clear) PetscCall(MatProductClear(mat)); 705 PetscCall(PetscObjectStateIncrease((PetscObject)mat)); 706 PetscFunctionReturn(PETSC_SUCCESS); 707 } 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 758 /*@ 759 MatProductSymbolic - Perform the symbolic portion of a matrix-matrix product operation, this creates a data structure for use with the numerical product done with 760 `MatProductNumeric()` 761 762 Collective 763 764 Input/Output Parameter: 765 . mat - the matrix whose values are computed via a matrix-matrix product operation 766 767 Level: intermediate 768 769 Note: 770 `MatProductSetFromOptions()` must have been called on `mat` before calling this function 771 772 .seealso: `Mat`, `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductSetFromOptions()`, `MatProductNumeric()`, `MatProductSetType()`, `MatProductSetAlgorithm()` 773 @*/ 774 PetscErrorCode MatProductSymbolic(Mat mat) 775 { 776 PetscLogEvent eventtype = -1; 777 PetscBool missing = PETSC_FALSE; 778 779 PetscFunctionBegin; 780 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 781 MatCheckProduct(mat, 1); 782 PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Cannot run symbolic phase. Product data not empty"); 783 switch (mat->product->type) { 784 case MATPRODUCT_AB: 785 eventtype = MAT_MatMultSymbolic; 786 break; 787 case MATPRODUCT_AtB: 788 eventtype = MAT_TransposeMatMultSymbolic; 789 break; 790 case MATPRODUCT_ABt: 791 eventtype = MAT_MatTransposeMultSymbolic; 792 break; 793 case MATPRODUCT_PtAP: 794 eventtype = MAT_PtAPSymbolic; 795 break; 796 case MATPRODUCT_RARt: 797 eventtype = MAT_RARtSymbolic; 798 break; 799 case MATPRODUCT_ABC: 800 eventtype = MAT_MatMatMultSymbolic; 801 break; 802 default: 803 SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[mat->product->type]); 804 } 805 mat->ops->productnumeric = NULL; 806 if (mat->ops->productsymbolic) { 807 PetscCall(PetscLogEventBegin(eventtype, mat, 0, 0, 0)); 808 PetscUseTypeMethod(mat, productsymbolic); 809 PetscCall(PetscLogEventEnd(eventtype, mat, 0, 0, 0)); 810 } else missing = PETSC_TRUE; 811 812 if (missing || !mat->product || !mat->ops->productnumeric) { 813 char errstr[256]; 814 815 if (mat->product->type == MATPRODUCT_ABC) { 816 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)); 817 } else { 818 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)); 819 } 820 PetscCheck(!missing, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Unspecified symbolic phase for product %s. Call MatProductSetFromOptions() first", errstr); 821 PetscCheck(mat->product, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing struct after symbolic phase for product %s", errstr); 822 } 823 PetscFunctionReturn(PETSC_SUCCESS); 824 } 825 826 /*@ 827 MatProductSetFill - Set an expected fill of the matrix whose values are computed via a matrix-matrix product operation 828 829 Collective 830 831 Input Parameters: 832 + mat - the matrix whose values are computed via a matrix-matrix product operation 833 - fill - expected fill as ratio of nnz(mat)/(nnz(A) + nnz(B) + nnz(C)); use `PETSC_DEFAULT` if you do not have a good estimate. 834 If the product is a dense matrix, this value is not used. 835 836 Level: intermediate 837 838 .seealso: `Mat`, `MatProductSetFromOptions()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()` 839 @*/ 840 PetscErrorCode MatProductSetFill(Mat mat, PetscReal fill) 841 { 842 PetscFunctionBegin; 843 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 844 MatCheckProduct(mat, 1); 845 if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) mat->product->fill = 2.0; 846 else mat->product->fill = fill; 847 PetscFunctionReturn(PETSC_SUCCESS); 848 } 849 850 /*@ 851 MatProductSetAlgorithm - Requests a particular algorithm for a matrix-matrix product operation that will perform to compute the given matrix 852 853 Collective 854 855 Input Parameters: 856 + mat - the matrix whose values are computed via a matrix-matrix product operation 857 - alg - particular implementation algorithm of the matrix product, e.g., `MATPRODUCTALGORITHMDEFAULT`. 858 859 Options Database Key: 860 . -mat_product_algorithm <algorithm> - Sets the algorithm; use -help for a list 861 of available algorithms (for instance, scalable, outerproduct, etc.) 862 863 Level: intermediate 864 865 .seealso: `Mat`, `MatProductClear()`, `MatProductSetType()`, `MatProductSetFill()`, `MatProductCreate()`, `MatProductAlgorithm`, `MatProductType` 866 @*/ 867 PetscErrorCode MatProductSetAlgorithm(Mat mat, MatProductAlgorithm alg) 868 { 869 PetscFunctionBegin; 870 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 871 MatCheckProduct(mat, 1); 872 PetscCall(PetscFree(mat->product->alg)); 873 PetscCall(PetscStrallocpy(alg, &mat->product->alg)); 874 PetscFunctionReturn(PETSC_SUCCESS); 875 } 876 877 /*@ 878 MatProductSetType - Sets a particular matrix-matrix product operation to be used to compute the values of the given matrix 879 880 Collective 881 882 Input Parameters: 883 + mat - the matrix whose values are computed via a matrix-matrix product operation 884 - productype - matrix product type, e.g., `MATPRODUCT_AB`,`MATPRODUCT_AtB`,`MATPRODUCT_ABt`,`MATPRODUCT_PtAP`,`MATPRODUCT_RARt`,`MATPRODUCT_ABC`. 885 886 Level: intermediate 887 888 Note: 889 The small t represents the transpose operation. 890 891 .seealso: `Mat`, `MatProductCreate()`, `MatProductType`, `MatProductType`, 892 `MATPRODUCT_AB`, `MATPRODUCT_AtB`, `MATPRODUCT_ABt`, `MATPRODUCT_PtAP`, `MATPRODUCT_RARt`, `MATPRODUCT_ABC` 893 @*/ 894 PetscErrorCode MatProductSetType(Mat mat, MatProductType productype) 895 { 896 PetscFunctionBegin; 897 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 898 MatCheckProduct(mat, 1); 899 PetscValidLogicalCollectiveEnum(mat, productype, 2); 900 if (productype != mat->product->type) { 901 if (mat->product->destroy) PetscCall((*mat->product->destroy)(mat->product->data)); 902 mat->product->destroy = NULL; 903 mat->product->data = NULL; 904 mat->ops->productsymbolic = NULL; 905 mat->ops->productnumeric = NULL; 906 } 907 mat->product->type = productype; 908 PetscFunctionReturn(PETSC_SUCCESS); 909 } 910 911 /*@ 912 MatProductClear - Clears matrix product internal datastructures. 913 914 Collective 915 916 Input Parameters: 917 . mat - the matrix whose values are computed via a matrix-matrix product operation 918 919 Options Database Key: 920 . -mat_product_clear - Clear intermediate data structures after `MatProductNumeric()` has been called 921 922 Level: intermediate 923 924 Notes: 925 This function should be called to remove any intermediate data used to compute the matrix to free up memory. 926 927 After having called this function, matrix-matrix product operations can no longer be used on `mat` 928 929 .seealso: `Mat`, `MatProductCreate()` 930 @*/ 931 PetscErrorCode MatProductClear(Mat mat) 932 { 933 Mat_Product *product = mat->product; 934 935 PetscFunctionBegin; 936 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 937 if (product) { 938 PetscCall(MatDestroy(&product->A)); 939 PetscCall(MatDestroy(&product->B)); 940 PetscCall(MatDestroy(&product->C)); 941 PetscCall(PetscFree(product->alg)); 942 PetscCall(MatDestroy(&product->Dwork)); 943 if (product->destroy) PetscCall((*product->destroy)(product->data)); 944 } 945 PetscCall(PetscFree(mat->product)); 946 mat->ops->productsymbolic = NULL; 947 mat->ops->productnumeric = NULL; 948 PetscFunctionReturn(PETSC_SUCCESS); 949 } 950 951 /* Create a supporting struct and attach it to the matrix product */ 952 PetscErrorCode MatProductCreate_Private(Mat A, Mat B, Mat C, Mat D) 953 { 954 Mat_Product *product = NULL; 955 956 PetscFunctionBegin; 957 PetscValidHeaderSpecific(D, MAT_CLASSID, 4); 958 PetscCheck(!D->product, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product already present"); 959 PetscCall(PetscNew(&product)); 960 product->A = A; 961 product->B = B; 962 product->C = C; 963 product->type = MATPRODUCT_UNSPECIFIED; 964 product->Dwork = NULL; 965 product->api_user = PETSC_FALSE; 966 product->clear = PETSC_FALSE; 967 D->product = product; 968 969 PetscCall(MatProductSetAlgorithm(D, MATPRODUCTALGORITHMDEFAULT)); 970 PetscCall(MatProductSetFill(D, PETSC_DEFAULT)); 971 972 PetscCall(PetscObjectReference((PetscObject)A)); 973 PetscCall(PetscObjectReference((PetscObject)B)); 974 PetscCall(PetscObjectReference((PetscObject)C)); 975 PetscFunctionReturn(PETSC_SUCCESS); 976 } 977 978 /*@ 979 MatProductCreateWithMat - Setup a given matrix as a matrix product of other matrices 980 981 Collective 982 983 Input Parameters: 984 + A - the first matrix 985 . B - the second matrix 986 . C - the third matrix (optional, use `NULL` if not needed) 987 - D - the matrix whose values are computed via a matrix-matrix product operation 988 989 Level: intermediate 990 991 Notes: 992 Use `MatProductCreate()` if the matrix you wish computed (the `D` matrix) does not already exist 993 994 See `MatProductCreate()` for details on the usage of the matrix-matrix product operations 995 996 Any product data currently attached to `D` will be cleared 997 998 .seealso: `Mat`, `MatProductCreate()`, `MatProductClear()` 999 @*/ 1000 PetscErrorCode MatProductCreateWithMat(Mat A, Mat B, Mat C, Mat D) 1001 { 1002 PetscFunctionBegin; 1003 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1004 PetscValidType(A, 1); 1005 MatCheckPreallocated(A, 1); 1006 PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 1007 PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 1008 1009 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 1010 PetscValidType(B, 2); 1011 MatCheckPreallocated(B, 2); 1012 PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 1013 PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 1014 1015 if (C) { 1016 PetscValidHeaderSpecific(C, MAT_CLASSID, 3); 1017 PetscValidType(C, 3); 1018 MatCheckPreallocated(C, 3); 1019 PetscCheck(C->assembled, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 1020 PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 1021 } 1022 1023 PetscValidHeaderSpecific(D, MAT_CLASSID, 4); 1024 PetscValidType(D, 4); 1025 MatCheckPreallocated(D, 4); 1026 PetscCheck(D->assembled, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix"); 1027 PetscCheck(!D->factortype, PetscObjectComm((PetscObject)D), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix"); 1028 1029 /* Create a supporting struct and attach it to D */ 1030 PetscCall(MatProductClear(D)); 1031 PetscCall(MatProductCreate_Private(A, B, C, D)); 1032 PetscFunctionReturn(PETSC_SUCCESS); 1033 } 1034 1035 /*@ 1036 MatProductCreate - create a matrix to hold the result of a matrix-matrix product operation 1037 1038 Collective 1039 1040 Input Parameters: 1041 + A - the first matrix 1042 . B - the second matrix 1043 - C - the third matrix (optional) 1044 1045 Output Parameters: 1046 . D - the matrix whose values are computed via a matrix-matrix product operation 1047 1048 Level: intermediate 1049 1050 Example: 1051 .vb 1052 MatProductCreate(A,B,C,&D); or MatProductCreateWithMat(A,B,C,D) 1053 MatProductSetType(D, MATPRODUCT_AB or MATPRODUCT_AtB or MATPRODUCT_ABt or MATPRODUCT_PtAP or MATPRODUCT_RARt or MATPRODUCT_ABC) 1054 MatProductSetAlgorithm(D, alg) 1055 MatProductSetFill(D,fill) 1056 MatProductSetFromOptions(D) 1057 MatProductSymbolic(D) 1058 MatProductNumeric(D) 1059 Change numerical values in some of the matrices 1060 MatProductNumeric(D) 1061 .ve 1062 1063 Notes: 1064 Use `MatProductCreateWithMat()` if the matrix you wish computed, the `D` matrix, already exists. 1065 1066 The information computed during the symbolic stage can be reused for new numerical computations with the same non-zero structure 1067 1068 Developer Note: 1069 It is undocumented what happens if the nonzero structure of the input matrices changes. Is the symbolic stage automatically redone? Does it crash? 1070 Is there error checking for it? 1071 1072 .seealso: `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductClear()` 1073 @*/ 1074 PetscErrorCode MatProductCreate(Mat A, Mat B, Mat C, Mat *D) 1075 { 1076 PetscFunctionBegin; 1077 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1078 PetscValidType(A, 1); 1079 PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 1080 PetscValidType(B, 2); 1081 PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix A"); 1082 PetscCheck(!B->factortype, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix B"); 1083 1084 if (C) { 1085 PetscValidHeaderSpecific(C, MAT_CLASSID, 3); 1086 PetscValidType(C, 3); 1087 PetscCheck(!C->factortype, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix C"); 1088 } 1089 1090 PetscValidPointer(D, 4); 1091 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), D)); 1092 /* Delay setting type of D to the MatProduct symbolic phase, as we allow sparse A and dense B */ 1093 PetscCall(MatProductCreate_Private(A, B, C, *D)); 1094 PetscFunctionReturn(PETSC_SUCCESS); 1095 } 1096 1097 /* 1098 These are safe basic implementations of ABC, RARt and PtAP 1099 that do not rely on mat->ops->matmatop function pointers. 1100 They only use the MatProduct API and are currently used by 1101 cuSPARSE and KOKKOS-KERNELS backends 1102 */ 1103 typedef struct { 1104 Mat BC; 1105 Mat ABC; 1106 } MatMatMatPrivate; 1107 1108 static PetscErrorCode MatDestroy_MatMatMatPrivate(void *data) 1109 { 1110 MatMatMatPrivate *mmdata = (MatMatMatPrivate *)data; 1111 1112 PetscFunctionBegin; 1113 PetscCall(MatDestroy(&mmdata->BC)); 1114 PetscCall(MatDestroy(&mmdata->ABC)); 1115 PetscCall(PetscFree(data)); 1116 PetscFunctionReturn(PETSC_SUCCESS); 1117 } 1118 1119 static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat) 1120 { 1121 Mat_Product *product = mat->product; 1122 MatMatMatPrivate *mmabc; 1123 1124 PetscFunctionBegin; 1125 MatCheckProduct(mat, 1); 1126 PetscCheck(mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data empty"); 1127 mmabc = (MatMatMatPrivate *)mat->product->data; 1128 PetscCheck(mmabc->BC->ops->productnumeric, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Missing numeric stage"); 1129 /* use function pointer directly to prevent logging */ 1130 PetscCall((*mmabc->BC->ops->productnumeric)(mmabc->BC)); 1131 /* swap ABC product stuff with that of ABC for the numeric phase on mat */ 1132 mat->product = mmabc->ABC->product; 1133 mat->ops->productnumeric = mmabc->ABC->ops->productnumeric; 1134 /* use function pointer directly to prevent logging */ 1135 PetscUseTypeMethod(mat, productnumeric); 1136 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1137 mat->product = product; 1138 PetscFunctionReturn(PETSC_SUCCESS); 1139 } 1140 1141 PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat) 1142 { 1143 Mat_Product *product = mat->product; 1144 Mat A, B, C; 1145 MatProductType p1, p2; 1146 MatMatMatPrivate *mmabc; 1147 const char *prefix; 1148 1149 PetscFunctionBegin; 1150 MatCheckProduct(mat, 1); 1151 PetscCheck(!mat->product->data, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Product data not empty"); 1152 PetscCall(MatGetOptionsPrefix(mat, &prefix)); 1153 PetscCall(PetscNew(&mmabc)); 1154 product->data = mmabc; 1155 product->destroy = MatDestroy_MatMatMatPrivate; 1156 switch (product->type) { 1157 case MATPRODUCT_PtAP: 1158 p1 = MATPRODUCT_AB; 1159 p2 = MATPRODUCT_AtB; 1160 A = product->B; 1161 B = product->A; 1162 C = product->B; 1163 break; 1164 case MATPRODUCT_RARt: 1165 p1 = MATPRODUCT_ABt; 1166 p2 = MATPRODUCT_AB; 1167 A = product->B; 1168 B = product->A; 1169 C = product->B; 1170 break; 1171 case MATPRODUCT_ABC: 1172 p1 = MATPRODUCT_AB; 1173 p2 = MATPRODUCT_AB; 1174 A = product->A; 1175 B = product->B; 1176 C = product->C; 1177 break; 1178 default: 1179 SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Not for ProductType %s", MatProductTypes[product->type]); 1180 } 1181 PetscCall(MatProductCreate(B, C, NULL, &mmabc->BC)); 1182 PetscCall(MatSetOptionsPrefix(mmabc->BC, prefix)); 1183 PetscCall(MatAppendOptionsPrefix(mmabc->BC, "P1_")); 1184 PetscCall(MatProductSetType(mmabc->BC, p1)); 1185 PetscCall(MatProductSetAlgorithm(mmabc->BC, MATPRODUCTALGORITHMDEFAULT)); 1186 PetscCall(MatProductSetFill(mmabc->BC, product->fill)); 1187 mmabc->BC->product->api_user = product->api_user; 1188 PetscCall(MatProductSetFromOptions(mmabc->BC)); 1189 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); 1190 /* use function pointer directly to prevent logging */ 1191 PetscCall((*mmabc->BC->ops->productsymbolic)(mmabc->BC)); 1192 1193 PetscCall(MatProductCreate(A, mmabc->BC, NULL, &mmabc->ABC)); 1194 PetscCall(MatSetOptionsPrefix(mmabc->ABC, prefix)); 1195 PetscCall(MatAppendOptionsPrefix(mmabc->ABC, "P2_")); 1196 PetscCall(MatProductSetType(mmabc->ABC, p2)); 1197 PetscCall(MatProductSetAlgorithm(mmabc->ABC, MATPRODUCTALGORITHMDEFAULT)); 1198 PetscCall(MatProductSetFill(mmabc->ABC, product->fill)); 1199 mmabc->ABC->product->api_user = product->api_user; 1200 PetscCall(MatProductSetFromOptions(mmabc->ABC)); 1201 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); 1202 /* swap ABC product stuff with that of ABC for the symbolic phase on mat */ 1203 mat->product = mmabc->ABC->product; 1204 mat->ops->productsymbolic = mmabc->ABC->ops->productsymbolic; 1205 /* use function pointer directly to prevent logging */ 1206 PetscUseTypeMethod(mat, productsymbolic); 1207 mmabc->ABC->ops->productnumeric = mat->ops->productnumeric; 1208 mat->ops->productsymbolic = MatProductSymbolic_ABC_Basic; 1209 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1210 mat->product = product; 1211 PetscFunctionReturn(PETSC_SUCCESS); 1212 } 1213 1214 /*@ 1215 MatProductGetType - Returns the type of matrix-matrix product associated with the given matrix. 1216 1217 Not Collective 1218 1219 Input Parameter: 1220 . mat - the matrix whose values are computed via a matrix-matrix product operation 1221 1222 Output Parameter: 1223 . mtype - the `MatProductType` 1224 1225 Level: intermediate 1226 1227 .seealso: `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductCreate()`, `MatProductType`, `MatProductAlgorithm` 1228 @*/ 1229 PetscErrorCode MatProductGetType(Mat mat, MatProductType *mtype) 1230 { 1231 PetscFunctionBegin; 1232 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1233 PetscValidPointer(mtype, 2); 1234 *mtype = MATPRODUCT_UNSPECIFIED; 1235 if (mat->product) *mtype = mat->product->type; 1236 PetscFunctionReturn(PETSC_SUCCESS); 1237 } 1238 1239 /*@ 1240 MatProductGetMats - Returns the matrices associated with the matrix-matrix product operation this matrix can receive 1241 1242 Not Collective 1243 1244 Input Parameter: 1245 . mat - the matrix whose values are computed via a matrix-matrix product operation 1246 1247 Output Parameters: 1248 + A - the first matrix 1249 . B - the second matrix 1250 - C - the third matrix (optional) 1251 1252 Level: intermediate 1253 1254 .seealso: `Mat`, `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()` 1255 @*/ 1256 PetscErrorCode MatProductGetMats(Mat mat, Mat *A, Mat *B, Mat *C) 1257 { 1258 PetscFunctionBegin; 1259 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 1260 if (A) *A = mat->product ? mat->product->A : NULL; 1261 if (B) *B = mat->product ? mat->product->B : NULL; 1262 if (C) *C = mat->product ? mat->product->C : NULL; 1263 PetscFunctionReturn(PETSC_SUCCESS); 1264 } 1265