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