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