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