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