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