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 PetscCheckFalse(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 PetscCheckFalse(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 PetscCheckFalse(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 PetscErrorCode ierr; 520 521 PetscFunctionBegin; 522 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 523 MatCheckProduct(mat,1); 524 PetscCheck(!mat->product->data,PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Cannot call MatProductSetFromOptions with already present data"); 525 ierr = PetscObjectOptionsBegin((PetscObject)mat);PetscCall(ierr); 526 PetscCall(PetscOptionsBool("-mat_product_clear","Clear intermediate data structures after MatProductNumeric() has been called","MatProductClear",mat->product->clear,&mat->product->clear,NULL)); 527 PetscCall(PetscOptionsDeprecated("-mat_freeintermediatedatastructures","-mat_product_clear","3.13","Or call MatProductClear() after MatProductNumeric()")); 528 ierr = PetscOptionsEnd();PetscCall(ierr); 529 PetscCall(MatProductSetFromOptions_Private(mat)); 530 PetscCheck(mat->product,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing product after setup phase"); 531 PetscFunctionReturn(0); 532 } 533 534 /*@C 535 MatProductView - View a MatProduct 536 537 Logically Collective on Mat 538 539 Input Parameter: 540 . mat - the matrix obtained with MatProductCreate() or MatProductCreateWithMat() 541 542 Level: intermediate 543 544 .seealso: MatView(), MatProductCreate(), MatProductCreateWithMat() 545 @*/ 546 PetscErrorCode MatProductView(Mat mat, PetscViewer viewer) 547 { 548 PetscFunctionBegin; 549 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 550 if (!mat->product) PetscFunctionReturn(0); 551 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat),&viewer)); 552 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 553 PetscCheckSameComm(mat,1,viewer,2); 554 if (mat->product->view) { 555 PetscCall((*mat->product->view)(mat,viewer)); 556 } 557 PetscFunctionReturn(0); 558 } 559 560 /* ----------------------------------------------- */ 561 /* these are basic implementations relying on the old function pointers 562 * they are dangerous and should be removed in the future */ 563 PetscErrorCode MatProductNumeric_AB(Mat mat) 564 { 565 Mat_Product *product = mat->product; 566 Mat A=product->A,B=product->B; 567 568 PetscFunctionBegin; 569 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); 570 PetscCall((*mat->ops->matmultnumeric)(A,B,mat)); 571 PetscFunctionReturn(0); 572 } 573 574 PetscErrorCode MatProductNumeric_AtB(Mat mat) 575 { 576 Mat_Product *product = mat->product; 577 Mat A=product->A,B=product->B; 578 579 PetscFunctionBegin; 580 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); 581 PetscCall((*mat->ops->transposematmultnumeric)(A,B,mat)); 582 PetscFunctionReturn(0); 583 } 584 585 PetscErrorCode MatProductNumeric_ABt(Mat mat) 586 { 587 Mat_Product *product = mat->product; 588 Mat A=product->A,B=product->B; 589 590 PetscFunctionBegin; 591 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); 592 PetscCall((*mat->ops->mattransposemultnumeric)(A,B,mat)); 593 PetscFunctionReturn(0); 594 } 595 596 PetscErrorCode MatProductNumeric_PtAP(Mat mat) 597 { 598 Mat_Product *product = mat->product; 599 Mat A=product->A,B=product->B; 600 601 PetscFunctionBegin; 602 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); 603 PetscCall((*mat->ops->ptapnumeric)(A,B,mat)); 604 PetscFunctionReturn(0); 605 } 606 607 PetscErrorCode MatProductNumeric_RARt(Mat mat) 608 { 609 Mat_Product *product = mat->product; 610 Mat A=product->A,B=product->B; 611 612 PetscFunctionBegin; 613 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); 614 PetscCall((*mat->ops->rartnumeric)(A,B,mat)); 615 PetscFunctionReturn(0); 616 } 617 618 PetscErrorCode MatProductNumeric_ABC(Mat mat) 619 { 620 Mat_Product *product = mat->product; 621 Mat A=product->A,B=product->B,C=product->C; 622 623 PetscFunctionBegin; 624 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); 625 PetscCall((*mat->ops->matmatmultnumeric)(A,B,C,mat)); 626 PetscFunctionReturn(0); 627 } 628 629 /* ----------------------------------------------- */ 630 631 /*@ 632 MatProductNumeric - Implement a matrix product with numerical values. 633 634 Collective on Mat 635 636 Input/Output Parameter: 637 . mat - the matrix holding the product 638 639 Level: intermediate 640 641 Notes: MatProductSymbolic() must have been called on mat before calling this function 642 643 .seealso: MatProductCreate(), MatSetType(), MatProductSymbolic() 644 @*/ 645 PetscErrorCode MatProductNumeric(Mat mat) 646 { 647 PetscLogEvent eventtype = -1; 648 PetscBool missing = PETSC_FALSE; 649 650 PetscFunctionBegin; 651 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 652 MatCheckProduct(mat,1); 653 switch (mat->product->type) { 654 case MATPRODUCT_AB: 655 eventtype = MAT_MatMultNumeric; 656 break; 657 case MATPRODUCT_AtB: 658 eventtype = MAT_TransposeMatMultNumeric; 659 break; 660 case MATPRODUCT_ABt: 661 eventtype = MAT_MatTransposeMultNumeric; 662 break; 663 case MATPRODUCT_PtAP: 664 eventtype = MAT_PtAPNumeric; 665 break; 666 case MATPRODUCT_RARt: 667 eventtype = MAT_RARtNumeric; 668 break; 669 case MATPRODUCT_ABC: 670 eventtype = MAT_MatMatMultNumeric; 671 break; 672 default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[mat->product->type]); 673 } 674 675 if (mat->ops->productnumeric) { 676 PetscCall(PetscLogEventBegin(eventtype,mat,0,0,0)); 677 PetscCall((*mat->ops->productnumeric)(mat)); 678 PetscCall(PetscLogEventEnd(eventtype,mat,0,0,0)); 679 } else missing = PETSC_TRUE; 680 681 if (missing || !mat->product) { 682 char errstr[256]; 683 684 if (mat->product->type == MATPRODUCT_ABC) { 685 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)); 686 } else { 687 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)); 688 } 689 PetscCheck(!missing,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Unspecified numeric phase for product %s",errstr); 690 PetscCheck(mat->product,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing struct after symbolic phase for product %s",errstr); 691 } 692 693 if (mat->product->clear) { 694 PetscCall(MatProductClear(mat)); 695 } 696 PetscCall(PetscObjectStateIncrease((PetscObject)mat)); 697 PetscFunctionReturn(0); 698 } 699 700 /* ----------------------------------------------- */ 701 /* these are basic implementations relying on the old function pointers 702 * they are dangerous and should be removed in the future */ 703 PetscErrorCode MatProductSymbolic_AB(Mat mat) 704 { 705 Mat_Product *product = mat->product; 706 Mat A=product->A,B=product->B; 707 708 PetscFunctionBegin; 709 PetscCheck(mat->ops->matmultsymbolic,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]); 710 PetscCall((*mat->ops->matmultsymbolic)(A,B,product->fill,mat)); 711 mat->ops->productnumeric = MatProductNumeric_AB; 712 PetscFunctionReturn(0); 713 } 714 715 PetscErrorCode MatProductSymbolic_AtB(Mat mat) 716 { 717 Mat_Product *product = mat->product; 718 Mat A=product->A,B=product->B; 719 720 PetscFunctionBegin; 721 PetscCheck(mat->ops->transposematmultsymbolic,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]); 722 PetscCall((*mat->ops->transposematmultsymbolic)(A,B,product->fill,mat)); 723 mat->ops->productnumeric = MatProductNumeric_AtB; 724 PetscFunctionReturn(0); 725 } 726 727 PetscErrorCode MatProductSymbolic_ABt(Mat mat) 728 { 729 Mat_Product *product = mat->product; 730 Mat A=product->A,B=product->B; 731 732 PetscFunctionBegin; 733 PetscCheck(mat->ops->mattransposemultsymbolic,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]); 734 PetscCall((*mat->ops->mattransposemultsymbolic)(A,B,product->fill,mat)); 735 mat->ops->productnumeric = MatProductNumeric_ABt; 736 PetscFunctionReturn(0); 737 } 738 739 PetscErrorCode MatProductSymbolic_ABC(Mat mat) 740 { 741 Mat_Product *product = mat->product; 742 Mat A=product->A,B=product->B,C=product->C; 743 744 PetscFunctionBegin; 745 PetscCheck(mat->ops->matmatmultsymbolic,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]); 746 PetscCall((*mat->ops->matmatmultsymbolic)(A,B,C,product->fill,mat)); 747 mat->ops->productnumeric = MatProductNumeric_ABC; 748 PetscFunctionReturn(0); 749 } 750 751 /* ----------------------------------------------- */ 752 753 /*@ 754 MatProductSymbolic - Perform the symbolic portion of a matrix product, this creates a data structure for use with the numerical produce. 755 756 Collective on Mat 757 758 Input/Output Parameter: 759 . mat - the matrix to hold a product 760 761 Level: intermediate 762 763 Notes: MatProductSetFromOptions() must have been called on mat before calling this function 764 765 .seealso: MatProductCreate(), MatProductCreateWithMat(), MatProductSetFromOptions(), MatProductNumeric(), MatProductSetType(), MatProductSetAlgorithm() 766 @*/ 767 PetscErrorCode MatProductSymbolic(Mat mat) 768 { 769 PetscLogEvent eventtype = -1; 770 PetscBool missing = PETSC_FALSE; 771 772 PetscFunctionBegin; 773 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 774 MatCheckProduct(mat,1); 775 PetscCheck(!mat->product->data,PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Cannot run symbolic phase. Product data not empty"); 776 switch (mat->product->type) { 777 case MATPRODUCT_AB: 778 eventtype = MAT_MatMultSymbolic; 779 break; 780 case MATPRODUCT_AtB: 781 eventtype = MAT_TransposeMatMultSymbolic; 782 break; 783 case MATPRODUCT_ABt: 784 eventtype = MAT_MatTransposeMultSymbolic; 785 break; 786 case MATPRODUCT_PtAP: 787 eventtype = MAT_PtAPSymbolic; 788 break; 789 case MATPRODUCT_RARt: 790 eventtype = MAT_RARtSymbolic; 791 break; 792 case MATPRODUCT_ABC: 793 eventtype = MAT_MatMatMultSymbolic; 794 break; 795 default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[mat->product->type]); 796 } 797 mat->ops->productnumeric = NULL; 798 if (mat->ops->productsymbolic) { 799 PetscCall(PetscLogEventBegin(eventtype,mat,0,0,0)); 800 PetscCall((*mat->ops->productsymbolic)(mat)); 801 PetscCall(PetscLogEventEnd(eventtype,mat,0,0,0)); 802 } else missing = PETSC_TRUE; 803 804 if (missing || !mat->product || !mat->ops->productnumeric) { 805 char errstr[256]; 806 807 if (mat->product->type == MATPRODUCT_ABC) { 808 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)); 809 } else { 810 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)); 811 } 812 PetscCheck(!missing,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Unspecified symbolic phase for product %s. Call MatProductSetFromOptions() first",errstr); 813 PetscCheck(mat->ops->productnumeric,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Unspecified numeric phase for product %s",errstr); 814 PetscCheck(mat->product,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing struct after symbolic phase for product %s",errstr); 815 } 816 PetscFunctionReturn(0); 817 } 818 819 /*@ 820 MatProductSetFill - Set an expected fill of the matrix product. 821 822 Collective on Mat 823 824 Input Parameters: 825 + mat - the matrix product 826 - 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. 827 828 Level: intermediate 829 830 .seealso: MatProductSetType(), MatProductSetAlgorithm(), MatProductCreate() 831 @*/ 832 PetscErrorCode MatProductSetFill(Mat mat,PetscReal fill) 833 { 834 PetscFunctionBegin; 835 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 836 MatCheckProduct(mat,1); 837 if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) mat->product->fill = 2.0; 838 else mat->product->fill = fill; 839 PetscFunctionReturn(0); 840 } 841 842 /*@ 843 MatProductSetAlgorithm - Requests a particular algorithm for a matrix product implementation. 844 845 Collective on Mat 846 847 Input Parameters: 848 + mat - the matrix product 849 - alg - particular implementation algorithm of the matrix product, e.g., MATPRODUCTALGORITHMDEFAULT. 850 851 Options Database Key: 852 . -mat_product_algorithm <algorithm> - Sets the algorithm; use -help for a list 853 of available algorithms (for instance, scalable, outerproduct, etc.) 854 855 Level: intermediate 856 857 .seealso: MatProductSetType(), MatProductSetFill(), MatProductCreate(), MatProductAlgorithm 858 @*/ 859 PetscErrorCode MatProductSetAlgorithm(Mat mat,MatProductAlgorithm alg) 860 { 861 PetscFunctionBegin; 862 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 863 MatCheckProduct(mat,1); 864 PetscCall(PetscFree(mat->product->alg)); 865 PetscCall(PetscStrallocpy(alg,&mat->product->alg)); 866 PetscFunctionReturn(0); 867 } 868 869 /*@ 870 MatProductSetType - Sets a particular matrix product type 871 872 Collective on Mat 873 874 Input Parameters: 875 + mat - the matrix 876 - productype - matrix product type, e.g., MATPRODUCT_AB,MATPRODUCT_AtB,MATPRODUCT_ABt,MATPRODUCT_PtAP,MATPRODUCT_RARt,MATPRODUCT_ABC. 877 878 Level: intermediate 879 880 .seealso: MatProductCreate(), MatProductType 881 @*/ 882 PetscErrorCode MatProductSetType(Mat mat,MatProductType productype) 883 { 884 PetscFunctionBegin; 885 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 886 MatCheckProduct(mat,1); 887 PetscValidLogicalCollectiveEnum(mat,productype,2); 888 if (productype != mat->product->type) { 889 if (mat->product->destroy) { 890 PetscCall((*mat->product->destroy)(mat->product->data)); 891 } 892 mat->product->destroy = NULL; 893 mat->product->data = NULL; 894 mat->ops->productsymbolic = NULL; 895 mat->ops->productnumeric = NULL; 896 } 897 mat->product->type = productype; 898 PetscFunctionReturn(0); 899 } 900 901 /*@ 902 MatProductClear - Clears matrix product internal structure. 903 904 Collective on Mat 905 906 Input Parameters: 907 . mat - the product matrix 908 909 Level: intermediate 910 911 Notes: this function should be called to remove any intermediate data used by the product 912 After having called this function, MatProduct operations can no longer be used on mat 913 @*/ 914 PetscErrorCode MatProductClear(Mat mat) 915 { 916 Mat_Product *product = mat->product; 917 918 PetscFunctionBegin; 919 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 920 if (product) { 921 PetscCall(MatDestroy(&product->A)); 922 PetscCall(MatDestroy(&product->B)); 923 PetscCall(MatDestroy(&product->C)); 924 PetscCall(PetscFree(product->alg)); 925 PetscCall(MatDestroy(&product->Dwork)); 926 if (product->destroy) { 927 PetscCall((*product->destroy)(product->data)); 928 } 929 } 930 PetscCall(PetscFree(mat->product)); 931 mat->ops->productsymbolic = NULL; 932 mat->ops->productnumeric = NULL; 933 PetscFunctionReturn(0); 934 } 935 936 /* Create a supporting struct and attach it to the matrix product */ 937 PetscErrorCode MatProductCreate_Private(Mat A,Mat B,Mat C,Mat D) 938 { 939 Mat_Product *product=NULL; 940 941 PetscFunctionBegin; 942 PetscValidHeaderSpecific(D,MAT_CLASSID,4); 943 PetscCheck(!D->product,PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product already present"); 944 PetscCall(PetscNewLog(D,&product)); 945 product->A = A; 946 product->B = B; 947 product->C = C; 948 product->type = MATPRODUCT_UNSPECIFIED; 949 product->Dwork = NULL; 950 product->api_user = PETSC_FALSE; 951 product->clear = PETSC_FALSE; 952 D->product = product; 953 954 PetscCall(MatProductSetAlgorithm(D,MATPRODUCTALGORITHMDEFAULT)); 955 PetscCall(MatProductSetFill(D,PETSC_DEFAULT)); 956 957 PetscCall(PetscObjectReference((PetscObject)A)); 958 PetscCall(PetscObjectReference((PetscObject)B)); 959 PetscCall(PetscObjectReference((PetscObject)C)); 960 PetscFunctionReturn(0); 961 } 962 963 /*@ 964 MatProductCreateWithMat - Setup a given matrix as a matrix product. 965 966 Collective on Mat 967 968 Input Parameters: 969 + A - the first matrix 970 . B - the second matrix 971 . C - the third matrix (optional) 972 - D - the matrix which will be used as a product 973 974 Output Parameters: 975 . D - the product matrix 976 977 Notes: 978 Any product data attached to D will be cleared 979 980 Level: intermediate 981 982 .seealso: MatProductCreate(), MatProductClear() 983 @*/ 984 PetscErrorCode MatProductCreateWithMat(Mat A,Mat B,Mat C,Mat D) 985 { 986 PetscFunctionBegin; 987 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 988 PetscValidType(A,1); 989 MatCheckPreallocated(A,1); 990 PetscCheck(A->assembled,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 991 PetscCheck(!A->factortype,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 992 993 PetscValidHeaderSpecific(B,MAT_CLASSID,2); 994 PetscValidType(B,2); 995 MatCheckPreallocated(B,2); 996 PetscCheck(B->assembled,PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 997 PetscCheck(!B->factortype,PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 998 999 if (C) { 1000 PetscValidHeaderSpecific(C,MAT_CLASSID,3); 1001 PetscValidType(C,3); 1002 MatCheckPreallocated(C,3); 1003 PetscCheck(C->assembled,PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 1004 PetscCheck(!C->factortype,PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 1005 } 1006 1007 PetscValidHeaderSpecific(D,MAT_CLASSID,4); 1008 PetscValidType(D,4); 1009 MatCheckPreallocated(D,4); 1010 PetscCheck(D->assembled,PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 1011 PetscCheck(!D->factortype,PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 1012 1013 /* Create a supporting struct and attach it to D */ 1014 PetscCall(MatProductClear(D)); 1015 PetscCall(MatProductCreate_Private(A,B,C,D)); 1016 PetscFunctionReturn(0); 1017 } 1018 1019 /*@ 1020 MatProductCreate - create a matrix product object that can be used to compute various matrix times matrix operations. 1021 1022 Collective on Mat 1023 1024 Input Parameters: 1025 + A - the first matrix 1026 . B - the second matrix 1027 - C - the third matrix (optional) 1028 1029 Output Parameters: 1030 . D - the product matrix 1031 1032 Level: intermediate 1033 1034 .seealso: MatProductCreateWithMat(), MatProductSetType(), MatProductSetAlgorithm() 1035 @*/ 1036 PetscErrorCode MatProductCreate(Mat A,Mat B,Mat C,Mat *D) 1037 { 1038 PetscFunctionBegin; 1039 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 1040 PetscValidType(A,1); 1041 PetscValidHeaderSpecific(B,MAT_CLASSID,2); 1042 PetscValidType(B,2); 1043 PetscCheck(!A->factortype,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix A"); 1044 PetscCheck(!B->factortype,PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix B"); 1045 1046 if (C) { 1047 PetscValidHeaderSpecific(C,MAT_CLASSID,3); 1048 PetscValidType(C,3); 1049 PetscCheck(!C->factortype,PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix C"); 1050 } 1051 1052 PetscValidPointer(D,4); 1053 PetscCall(MatCreate(PetscObjectComm((PetscObject)A),D)); 1054 PetscCall(MatProductCreate_Private(A,B,C,*D)); 1055 PetscFunctionReturn(0); 1056 } 1057 1058 /* 1059 These are safe basic implementations of ABC, RARt and PtAP 1060 that do not rely on mat->ops->matmatop function pointers. 1061 They only use the MatProduct API and are currently used by 1062 cuSPARSE and KOKKOS-KERNELS backends 1063 */ 1064 typedef struct { 1065 Mat BC; 1066 Mat ABC; 1067 } MatMatMatPrivate; 1068 1069 static PetscErrorCode MatDestroy_MatMatMatPrivate(void *data) 1070 { 1071 MatMatMatPrivate *mmdata = (MatMatMatPrivate *)data; 1072 1073 PetscFunctionBegin; 1074 PetscCall(MatDestroy(&mmdata->BC)); 1075 PetscCall(MatDestroy(&mmdata->ABC)); 1076 PetscCall(PetscFree(data)); 1077 PetscFunctionReturn(0); 1078 } 1079 1080 static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat) 1081 { 1082 Mat_Product *product = mat->product; 1083 MatMatMatPrivate *mmabc; 1084 1085 PetscFunctionBegin; 1086 MatCheckProduct(mat,1); 1087 PetscCheck(mat->product->data,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Product data empty"); 1088 mmabc = (MatMatMatPrivate *)mat->product->data; 1089 PetscCheck(mmabc->BC->ops->productnumeric,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric stage"); 1090 /* use function pointer directly to prevent logging */ 1091 PetscCall((*mmabc->BC->ops->productnumeric)(mmabc->BC)); 1092 /* swap ABC product stuff with that of ABC for the numeric phase on mat */ 1093 mat->product = mmabc->ABC->product; 1094 mat->ops->productnumeric = mmabc->ABC->ops->productnumeric; 1095 PetscCheck(mat->ops->productnumeric,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric stage"); 1096 /* use function pointer directly to prevent logging */ 1097 PetscCall((*mat->ops->productnumeric)(mat)); 1098 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1099 mat->product = product; 1100 PetscFunctionReturn(0); 1101 } 1102 1103 PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat) 1104 { 1105 Mat_Product *product = mat->product; 1106 Mat A, B ,C; 1107 MatProductType p1,p2; 1108 MatMatMatPrivate *mmabc; 1109 const char *prefix; 1110 1111 PetscFunctionBegin; 1112 MatCheckProduct(mat,1); 1113 PetscCheck(!mat->product->data,PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Product data not empty"); 1114 PetscCall(MatGetOptionsPrefix(mat,&prefix)); 1115 PetscCall(PetscNew(&mmabc)); 1116 product->data = mmabc; 1117 product->destroy = MatDestroy_MatMatMatPrivate; 1118 switch (product->type) { 1119 case MATPRODUCT_PtAP: 1120 p1 = MATPRODUCT_AB; 1121 p2 = MATPRODUCT_AtB; 1122 A = product->B; 1123 B = product->A; 1124 C = product->B; 1125 break; 1126 case MATPRODUCT_RARt: 1127 p1 = MATPRODUCT_ABt; 1128 p2 = MATPRODUCT_AB; 1129 A = product->B; 1130 B = product->A; 1131 C = product->B; 1132 break; 1133 case MATPRODUCT_ABC: 1134 p1 = MATPRODUCT_AB; 1135 p2 = MATPRODUCT_AB; 1136 A = product->A; 1137 B = product->B; 1138 C = product->C; 1139 break; 1140 default: 1141 SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Not for ProductType %s",MatProductTypes[product->type]); 1142 } 1143 PetscCall(MatProductCreate(B,C,NULL,&mmabc->BC)); 1144 PetscCall(MatSetOptionsPrefix(mmabc->BC,prefix)); 1145 PetscCall(MatAppendOptionsPrefix(mmabc->BC,"P1_")); 1146 PetscCall(MatProductSetType(mmabc->BC,p1)); 1147 PetscCall(MatProductSetAlgorithm(mmabc->BC,MATPRODUCTALGORITHMDEFAULT)); 1148 PetscCall(MatProductSetFill(mmabc->BC,product->fill)); 1149 mmabc->BC->product->api_user = product->api_user; 1150 PetscCall(MatProductSetFromOptions(mmabc->BC)); 1151 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); 1152 /* use function pointer directly to prevent logging */ 1153 PetscCall((*mmabc->BC->ops->productsymbolic)(mmabc->BC)); 1154 1155 PetscCall(MatProductCreate(A,mmabc->BC,NULL,&mmabc->ABC)); 1156 PetscCall(MatSetOptionsPrefix(mmabc->ABC,prefix)); 1157 PetscCall(MatAppendOptionsPrefix(mmabc->ABC,"P2_")); 1158 PetscCall(MatProductSetType(mmabc->ABC,p2)); 1159 PetscCall(MatProductSetAlgorithm(mmabc->ABC,MATPRODUCTALGORITHMDEFAULT)); 1160 PetscCall(MatProductSetFill(mmabc->ABC,product->fill)); 1161 mmabc->ABC->product->api_user = product->api_user; 1162 PetscCall(MatProductSetFromOptions(mmabc->ABC)); 1163 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); 1164 /* swap ABC product stuff with that of ABC for the symbolic phase on mat */ 1165 mat->product = mmabc->ABC->product; 1166 mat->ops->productsymbolic = mmabc->ABC->ops->productsymbolic; 1167 /* use function pointer directly to prevent logging */ 1168 PetscCall((*mat->ops->productsymbolic)(mat)); 1169 mmabc->ABC->ops->productnumeric = mat->ops->productnumeric; 1170 mat->ops->productsymbolic = MatProductSymbolic_ABC_Basic; 1171 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1172 mat->product = product; 1173 PetscFunctionReturn(0); 1174 } 1175 1176 /*@ 1177 MatProductGetType - Returns the type of the MatProduct. 1178 1179 Not collective 1180 1181 Input Parameter: 1182 . mat - the matrix 1183 1184 Output Parameter: 1185 . mtype - the MatProduct type 1186 1187 Level: intermediate 1188 1189 .seealso: MatProductCreateWithMat(), MatProductSetType(), MatProductCreate() 1190 @*/ 1191 PetscErrorCode MatProductGetType(Mat mat, MatProductType *mtype) 1192 { 1193 PetscFunctionBegin; 1194 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1195 PetscValidPointer(mtype,2); 1196 *mtype = MATPRODUCT_UNSPECIFIED; 1197 if (mat->product) *mtype = mat->product->type; 1198 PetscFunctionReturn(0); 1199 } 1200 1201 /*@ 1202 MatProductGetMats - Returns the matrices associated with the MatProduct. 1203 1204 Not collective 1205 1206 Input Parameter: 1207 . mat - the product matrix 1208 1209 Output Parameters: 1210 + A - the first matrix 1211 . B - the second matrix 1212 - C - the third matrix (optional) 1213 1214 Level: intermediate 1215 1216 .seealso: MatProductCreateWithMat(), MatProductSetType(), MatProductSetAlgorithm() 1217 @*/ 1218 PetscErrorCode MatProductGetMats(Mat mat, Mat *A, Mat *B, Mat *C) 1219 { 1220 PetscFunctionBegin; 1221 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 1222 if (A) *A = mat->product ? mat->product->A : NULL; 1223 if (B) *B = mat->product ? mat->product->B : NULL; 1224 if (C) *C = mat->product ? mat->product->C : NULL; 1225 PetscFunctionReturn(0); 1226 } 1227