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