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()/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 - Creates 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()` 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 a MatProduct 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 produce. 750 751 Collective on Mat 752 753 Input/Output Parameter: 754 . mat - the matrix to hold a product 755 756 Level: intermediate 757 758 Notes: MatProductSetFromOptions() must have been called on mat before calling this function 759 760 .seealso: `MatProductCreate()`, `MatProductCreateWithMat()`, `MatProductSetFromOptions()`, `MatProductNumeric()`, `MatProductSetType()`, `MatProductSetAlgorithm()` 761 @*/ 762 PetscErrorCode MatProductSymbolic(Mat mat) 763 { 764 PetscLogEvent eventtype = -1; 765 PetscBool missing = PETSC_FALSE; 766 767 PetscFunctionBegin; 768 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 769 MatCheckProduct(mat,1); 770 PetscCheck(!mat->product->data,PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Cannot run symbolic phase. Product data not empty"); 771 switch (mat->product->type) { 772 case MATPRODUCT_AB: 773 eventtype = MAT_MatMultSymbolic; 774 break; 775 case MATPRODUCT_AtB: 776 eventtype = MAT_TransposeMatMultSymbolic; 777 break; 778 case MATPRODUCT_ABt: 779 eventtype = MAT_MatTransposeMultSymbolic; 780 break; 781 case MATPRODUCT_PtAP: 782 eventtype = MAT_PtAPSymbolic; 783 break; 784 case MATPRODUCT_RARt: 785 eventtype = MAT_RARtSymbolic; 786 break; 787 case MATPRODUCT_ABC: 788 eventtype = MAT_MatMatMultSymbolic; 789 break; 790 default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[mat->product->type]); 791 } 792 mat->ops->productnumeric = NULL; 793 if (mat->ops->productsymbolic) { 794 PetscCall(PetscLogEventBegin(eventtype,mat,0,0,0)); 795 PetscCall((*mat->ops->productsymbolic)(mat)); 796 PetscCall(PetscLogEventEnd(eventtype,mat,0,0,0)); 797 } else missing = PETSC_TRUE; 798 799 if (missing || !mat->product || !mat->ops->productnumeric) { 800 char errstr[256]; 801 802 if (mat->product->type == MATPRODUCT_ABC) { 803 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)); 804 } else { 805 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)); 806 } 807 PetscCheck(!missing,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Unspecified symbolic phase for product %s. Call MatProductSetFromOptions() first",errstr); 808 PetscCheck(mat->ops->productnumeric,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Unspecified numeric phase for product %s",errstr); 809 PetscCheck(mat->product,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing struct after symbolic phase for product %s",errstr); 810 } 811 PetscFunctionReturn(0); 812 } 813 814 /*@ 815 MatProductSetFill - Set an expected fill of the matrix product. 816 817 Collective on Mat 818 819 Input Parameters: 820 + mat - the matrix product 821 - 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 is irrelevant. 822 823 Level: intermediate 824 825 .seealso: `MatProductSetType()`, `MatProductSetAlgorithm()`, `MatProductCreate()` 826 @*/ 827 PetscErrorCode MatProductSetFill(Mat mat,PetscReal fill) 828 { 829 PetscFunctionBegin; 830 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 831 MatCheckProduct(mat,1); 832 if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) mat->product->fill = 2.0; 833 else mat->product->fill = fill; 834 PetscFunctionReturn(0); 835 } 836 837 /*@ 838 MatProductSetAlgorithm - Requests a particular algorithm for a matrix product implementation. 839 840 Collective on Mat 841 842 Input Parameters: 843 + mat - the matrix product 844 - alg - particular implementation algorithm of the matrix product, e.g., MATPRODUCTALGORITHMDEFAULT. 845 846 Options Database Key: 847 . -mat_product_algorithm <algorithm> - Sets the algorithm; use -help for a list 848 of available algorithms (for instance, scalable, outerproduct, etc.) 849 850 Level: intermediate 851 852 .seealso: `MatProductSetType()`, `MatProductSetFill()`, `MatProductCreate()`, `MatProductAlgorithm` 853 @*/ 854 PetscErrorCode MatProductSetAlgorithm(Mat mat,MatProductAlgorithm alg) 855 { 856 PetscFunctionBegin; 857 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 858 MatCheckProduct(mat,1); 859 PetscCall(PetscFree(mat->product->alg)); 860 PetscCall(PetscStrallocpy(alg,&mat->product->alg)); 861 PetscFunctionReturn(0); 862 } 863 864 /*@ 865 MatProductSetType - Sets a particular matrix product type 866 867 Collective on Mat 868 869 Input Parameters: 870 + mat - the matrix 871 - productype - matrix product type, e.g., MATPRODUCT_AB,MATPRODUCT_AtB,MATPRODUCT_ABt,MATPRODUCT_PtAP,MATPRODUCT_RARt,MATPRODUCT_ABC. 872 873 Level: intermediate 874 875 .seealso: `MatProductCreate()`, `MatProductType` 876 @*/ 877 PetscErrorCode MatProductSetType(Mat mat,MatProductType productype) 878 { 879 PetscFunctionBegin; 880 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 881 MatCheckProduct(mat,1); 882 PetscValidLogicalCollectiveEnum(mat,productype,2); 883 if (productype != mat->product->type) { 884 if (mat->product->destroy) PetscCall((*mat->product->destroy)(mat->product->data)); 885 mat->product->destroy = NULL; 886 mat->product->data = NULL; 887 mat->ops->productsymbolic = NULL; 888 mat->ops->productnumeric = NULL; 889 } 890 mat->product->type = productype; 891 PetscFunctionReturn(0); 892 } 893 894 /*@ 895 MatProductClear - Clears matrix product internal structure. 896 897 Collective on Mat 898 899 Input Parameters: 900 . mat - the product matrix 901 902 Level: intermediate 903 904 Notes: this function should be called to remove any intermediate data used by the product 905 After having called this function, MatProduct operations can no longer be used on mat 906 @*/ 907 PetscErrorCode MatProductClear(Mat mat) 908 { 909 Mat_Product *product = mat->product; 910 911 PetscFunctionBegin; 912 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 913 if (product) { 914 PetscCall(MatDestroy(&product->A)); 915 PetscCall(MatDestroy(&product->B)); 916 PetscCall(MatDestroy(&product->C)); 917 PetscCall(PetscFree(product->alg)); 918 PetscCall(MatDestroy(&product->Dwork)); 919 if (product->destroy) PetscCall((*product->destroy)(product->data)); 920 } 921 PetscCall(PetscFree(mat->product)); 922 mat->ops->productsymbolic = NULL; 923 mat->ops->productnumeric = NULL; 924 PetscFunctionReturn(0); 925 } 926 927 /* Create a supporting struct and attach it to the matrix product */ 928 PetscErrorCode MatProductCreate_Private(Mat A,Mat B,Mat C,Mat D) 929 { 930 Mat_Product *product=NULL; 931 932 PetscFunctionBegin; 933 PetscValidHeaderSpecific(D,MAT_CLASSID,4); 934 PetscCheck(!D->product,PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product already present"); 935 PetscCall(PetscNewLog(D,&product)); 936 product->A = A; 937 product->B = B; 938 product->C = C; 939 product->type = MATPRODUCT_UNSPECIFIED; 940 product->Dwork = NULL; 941 product->api_user = PETSC_FALSE; 942 product->clear = PETSC_FALSE; 943 D->product = product; 944 945 PetscCall(MatProductSetAlgorithm(D,MATPRODUCTALGORITHMDEFAULT)); 946 PetscCall(MatProductSetFill(D,PETSC_DEFAULT)); 947 948 PetscCall(PetscObjectReference((PetscObject)A)); 949 PetscCall(PetscObjectReference((PetscObject)B)); 950 PetscCall(PetscObjectReference((PetscObject)C)); 951 PetscFunctionReturn(0); 952 } 953 954 /*@ 955 MatProductCreateWithMat - Setup a given matrix as a matrix product. 956 957 Collective on Mat 958 959 Input Parameters: 960 + A - the first matrix 961 . B - the second matrix 962 . C - the third matrix (optional) 963 - D - the matrix which will be used as a product 964 965 Output Parameters: 966 . D - the product matrix 967 968 Notes: 969 Any product data attached to D will be cleared 970 971 Level: intermediate 972 973 .seealso: `MatProductCreate()`, `MatProductClear()` 974 @*/ 975 PetscErrorCode MatProductCreateWithMat(Mat A,Mat B,Mat C,Mat D) 976 { 977 PetscFunctionBegin; 978 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 979 PetscValidType(A,1); 980 MatCheckPreallocated(A,1); 981 PetscCheck(A->assembled,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 982 PetscCheck(!A->factortype,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 983 984 PetscValidHeaderSpecific(B,MAT_CLASSID,2); 985 PetscValidType(B,2); 986 MatCheckPreallocated(B,2); 987 PetscCheck(B->assembled,PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 988 PetscCheck(!B->factortype,PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 989 990 if (C) { 991 PetscValidHeaderSpecific(C,MAT_CLASSID,3); 992 PetscValidType(C,3); 993 MatCheckPreallocated(C,3); 994 PetscCheck(C->assembled,PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 995 PetscCheck(!C->factortype,PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 996 } 997 998 PetscValidHeaderSpecific(D,MAT_CLASSID,4); 999 PetscValidType(D,4); 1000 MatCheckPreallocated(D,4); 1001 PetscCheck(D->assembled,PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 1002 PetscCheck(!D->factortype,PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 1003 1004 /* Create a supporting struct and attach it to D */ 1005 PetscCall(MatProductClear(D)); 1006 PetscCall(MatProductCreate_Private(A,B,C,D)); 1007 PetscFunctionReturn(0); 1008 } 1009 1010 /*@ 1011 MatProductCreate - create a matrix product object that can be used to compute various matrix times matrix operations. 1012 1013 Collective on Mat 1014 1015 Input Parameters: 1016 + A - the first matrix 1017 . B - the second matrix 1018 - C - the third matrix (optional) 1019 1020 Output Parameters: 1021 . D - the product matrix 1022 1023 Level: intermediate 1024 1025 .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()` 1026 @*/ 1027 PetscErrorCode MatProductCreate(Mat A,Mat B,Mat C,Mat *D) 1028 { 1029 PetscFunctionBegin; 1030 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 1031 PetscValidType(A,1); 1032 PetscValidHeaderSpecific(B,MAT_CLASSID,2); 1033 PetscValidType(B,2); 1034 PetscCheck(!A->factortype,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix A"); 1035 PetscCheck(!B->factortype,PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix B"); 1036 1037 if (C) { 1038 PetscValidHeaderSpecific(C,MAT_CLASSID,3); 1039 PetscValidType(C,3); 1040 PetscCheck(!C->factortype,PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix C"); 1041 } 1042 1043 PetscValidPointer(D,4); 1044 PetscCall(MatCreate(PetscObjectComm((PetscObject)A),D)); 1045 PetscCall(MatProductCreate_Private(A,B,C,*D)); 1046 PetscFunctionReturn(0); 1047 } 1048 1049 /* 1050 These are safe basic implementations of ABC, RARt and PtAP 1051 that do not rely on mat->ops->matmatop function pointers. 1052 They only use the MatProduct API and are currently used by 1053 cuSPARSE and KOKKOS-KERNELS backends 1054 */ 1055 typedef struct { 1056 Mat BC; 1057 Mat ABC; 1058 } MatMatMatPrivate; 1059 1060 static PetscErrorCode MatDestroy_MatMatMatPrivate(void *data) 1061 { 1062 MatMatMatPrivate *mmdata = (MatMatMatPrivate *)data; 1063 1064 PetscFunctionBegin; 1065 PetscCall(MatDestroy(&mmdata->BC)); 1066 PetscCall(MatDestroy(&mmdata->ABC)); 1067 PetscCall(PetscFree(data)); 1068 PetscFunctionReturn(0); 1069 } 1070 1071 static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat) 1072 { 1073 Mat_Product *product = mat->product; 1074 MatMatMatPrivate *mmabc; 1075 1076 PetscFunctionBegin; 1077 MatCheckProduct(mat,1); 1078 PetscCheck(mat->product->data,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Product data empty"); 1079 mmabc = (MatMatMatPrivate *)mat->product->data; 1080 PetscCheck(mmabc->BC->ops->productnumeric,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric stage"); 1081 /* use function pointer directly to prevent logging */ 1082 PetscCall((*mmabc->BC->ops->productnumeric)(mmabc->BC)); 1083 /* swap ABC product stuff with that of ABC for the numeric phase on mat */ 1084 mat->product = mmabc->ABC->product; 1085 mat->ops->productnumeric = mmabc->ABC->ops->productnumeric; 1086 PetscCheck(mat->ops->productnumeric,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric stage"); 1087 /* use function pointer directly to prevent logging */ 1088 PetscCall((*mat->ops->productnumeric)(mat)); 1089 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1090 mat->product = product; 1091 PetscFunctionReturn(0); 1092 } 1093 1094 PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat) 1095 { 1096 Mat_Product *product = mat->product; 1097 Mat A, B ,C; 1098 MatProductType p1,p2; 1099 MatMatMatPrivate *mmabc; 1100 const char *prefix; 1101 1102 PetscFunctionBegin; 1103 MatCheckProduct(mat,1); 1104 PetscCheck(!mat->product->data,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Product data not empty"); 1105 PetscCall(MatGetOptionsPrefix(mat,&prefix)); 1106 PetscCall(PetscNew(&mmabc)); 1107 product->data = mmabc; 1108 product->destroy = MatDestroy_MatMatMatPrivate; 1109 switch (product->type) { 1110 case MATPRODUCT_PtAP: 1111 p1 = MATPRODUCT_AB; 1112 p2 = MATPRODUCT_AtB; 1113 A = product->B; 1114 B = product->A; 1115 C = product->B; 1116 break; 1117 case MATPRODUCT_RARt: 1118 p1 = MATPRODUCT_ABt; 1119 p2 = MATPRODUCT_AB; 1120 A = product->B; 1121 B = product->A; 1122 C = product->B; 1123 break; 1124 case MATPRODUCT_ABC: 1125 p1 = MATPRODUCT_AB; 1126 p2 = MATPRODUCT_AB; 1127 A = product->A; 1128 B = product->B; 1129 C = product->C; 1130 break; 1131 default: 1132 SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Not for ProductType %s",MatProductTypes[product->type]); 1133 } 1134 PetscCall(MatProductCreate(B,C,NULL,&mmabc->BC)); 1135 PetscCall(MatSetOptionsPrefix(mmabc->BC,prefix)); 1136 PetscCall(MatAppendOptionsPrefix(mmabc->BC,"P1_")); 1137 PetscCall(MatProductSetType(mmabc->BC,p1)); 1138 PetscCall(MatProductSetAlgorithm(mmabc->BC,MATPRODUCTALGORITHMDEFAULT)); 1139 PetscCall(MatProductSetFill(mmabc->BC,product->fill)); 1140 mmabc->BC->product->api_user = product->api_user; 1141 PetscCall(MatProductSetFromOptions(mmabc->BC)); 1142 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); 1143 /* use function pointer directly to prevent logging */ 1144 PetscCall((*mmabc->BC->ops->productsymbolic)(mmabc->BC)); 1145 1146 PetscCall(MatProductCreate(A,mmabc->BC,NULL,&mmabc->ABC)); 1147 PetscCall(MatSetOptionsPrefix(mmabc->ABC,prefix)); 1148 PetscCall(MatAppendOptionsPrefix(mmabc->ABC,"P2_")); 1149 PetscCall(MatProductSetType(mmabc->ABC,p2)); 1150 PetscCall(MatProductSetAlgorithm(mmabc->ABC,MATPRODUCTALGORITHMDEFAULT)); 1151 PetscCall(MatProductSetFill(mmabc->ABC,product->fill)); 1152 mmabc->ABC->product->api_user = product->api_user; 1153 PetscCall(MatProductSetFromOptions(mmabc->ABC)); 1154 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); 1155 /* swap ABC product stuff with that of ABC for the symbolic phase on mat */ 1156 mat->product = mmabc->ABC->product; 1157 mat->ops->productsymbolic = mmabc->ABC->ops->productsymbolic; 1158 /* use function pointer directly to prevent logging */ 1159 PetscCall((*mat->ops->productsymbolic)(mat)); 1160 mmabc->ABC->ops->productnumeric = mat->ops->productnumeric; 1161 mat->ops->productsymbolic = MatProductSymbolic_ABC_Basic; 1162 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1163 mat->product = product; 1164 PetscFunctionReturn(0); 1165 } 1166 1167 /*@ 1168 MatProductGetType - Returns the type of the MatProduct. 1169 1170 Not collective 1171 1172 Input Parameter: 1173 . mat - the matrix 1174 1175 Output Parameter: 1176 . mtype - the MatProduct type 1177 1178 Level: intermediate 1179 1180 .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductCreate()` 1181 @*/ 1182 PetscErrorCode MatProductGetType(Mat mat, MatProductType *mtype) 1183 { 1184 PetscFunctionBegin; 1185 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1186 PetscValidPointer(mtype,2); 1187 *mtype = MATPRODUCT_UNSPECIFIED; 1188 if (mat->product) *mtype = mat->product->type; 1189 PetscFunctionReturn(0); 1190 } 1191 1192 /*@ 1193 MatProductGetMats - Returns the matrices associated with the MatProduct. 1194 1195 Not collective 1196 1197 Input Parameter: 1198 . mat - the product matrix 1199 1200 Output Parameters: 1201 + A - the first matrix 1202 . B - the second matrix 1203 - C - the third matrix (optional) 1204 1205 Level: intermediate 1206 1207 .seealso: `MatProductCreateWithMat()`, `MatProductSetType()`, `MatProductSetAlgorithm()` 1208 @*/ 1209 PetscErrorCode MatProductGetMats(Mat mat, Mat *A, Mat *B, Mat *C) 1210 { 1211 PetscFunctionBegin; 1212 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1213 if (A) *A = mat->product ? mat->product->A : NULL; 1214 if (B) *B = mat->product ? mat->product->B : NULL; 1215 if (C) *C = mat->product ? mat->product->C : NULL; 1216 PetscFunctionReturn(0); 1217 } 1218