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