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