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