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 MATTRANPOSEMAT) 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 if (!C->ops->transposematmultnumeric) SETERRQ(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 = PetscInfo2((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,MATPRODUCTALGORITHM_DEFAULT);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,MATPRODUCTALGORITHM_DEFAULT);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 if (!C->ops->mattransposemultnumeric) SETERRQ(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 = PetscInfo2((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,MATPRODUCTALGORITHM_DEFAULT);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,MATPRODUCTALGORITHM_DEFAULT);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 if (!mat->ops->transposematmultnumeric) SETERRQ(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 = PetscInfo3((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,MATPRODUCTALGORITHM_DEFAULT);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,MATPRODUCTALGORITHM_DEFAULT);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: SETERRQ1(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: SETERRQ3(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: SETERRQ3(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 if (!A) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing A mat"); 411 if (!B) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing B mat"); 412 if (product->type == MATPRODUCT_ABC && !C) SETERRQ(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 if (An != Bm) SETERRQ7(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_SIZ,"Matrix dimensions of A and %s are incompatible for MatProductType %s: A %Dx%D, %s %Dx%D",bname,MatProductTypes[product->type],A->rmap->N,A->cmap->N,bname,B->rmap->N,B->cmap->N); 428 if (Cm && Cm != Bn) SETERRQ5(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_SIZ,"Matrix dimensions of B and C are incompatible for MatProductType %s: B %Dx%D, C %Dx%D",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 = PetscInfo5(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 = PetscInfo4(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 = PetscInfo2(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 = PetscInfo3(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 = PetscInfo2(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 = PetscInfo2(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 = PetscInfo3(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 = PetscInfo2(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 if (mat->product->data) SETERRQ(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 if (!mat->product) SETERRQ(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 if (!mat->ops->matmultnumeric) SETERRQ2(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 if (!mat->ops->transposematmultnumeric) SETERRQ2(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 if (!mat->ops->mattransposemultnumeric) SETERRQ2(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 if (!mat->ops->ptapnumeric) SETERRQ2(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 if (!mat->ops->rartnumeric) SETERRQ2(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 if (!mat->ops->matmatmultnumeric) SETERRQ2(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 669 PetscFunctionBegin; 670 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 671 MatCheckProduct(mat,1); 672 /* log event */ 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: SETERRQ1(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 SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Call MatProductSymbolic() first"); 700 if (!mat->product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing product after numeric phase"); 701 if (mat->product->clear) { 702 ierr = MatProductClear(mat);CHKERRQ(ierr); 703 } 704 ierr = PetscObjectStateIncrease((PetscObject)mat);CHKERRQ(ierr); 705 PetscFunctionReturn(0); 706 } 707 708 /* ----------------------------------------------- */ 709 /* these are basic implementations relying on the old function pointers 710 * they are dangerous and should be removed in the future */ 711 PetscErrorCode MatProductSymbolic_AB(Mat mat) 712 { 713 PetscErrorCode ierr; 714 Mat_Product *product = mat->product; 715 Mat A=product->A,B=product->B; 716 717 PetscFunctionBegin; 718 if (!mat->ops->matmultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]); 719 ierr = (*mat->ops->matmultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr); 720 mat->ops->productnumeric = MatProductNumeric_AB; 721 PetscFunctionReturn(0); 722 } 723 724 PetscErrorCode MatProductSymbolic_AtB(Mat mat) 725 { 726 PetscErrorCode ierr; 727 Mat_Product *product = mat->product; 728 Mat A=product->A,B=product->B; 729 730 PetscFunctionBegin; 731 if (!mat->ops->transposematmultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]); 732 ierr = (*mat->ops->transposematmultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr); 733 mat->ops->productnumeric = MatProductNumeric_AtB; 734 PetscFunctionReturn(0); 735 } 736 737 PetscErrorCode MatProductSymbolic_ABt(Mat mat) 738 { 739 PetscErrorCode ierr; 740 Mat_Product *product = mat->product; 741 Mat A=product->A,B=product->B; 742 743 PetscFunctionBegin; 744 if (!mat->ops->mattransposemultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]); 745 ierr = (*mat->ops->mattransposemultsymbolic)(A,B,product->fill,mat);CHKERRQ(ierr); 746 mat->ops->productnumeric = MatProductNumeric_ABt; 747 PetscFunctionReturn(0); 748 } 749 750 PetscErrorCode MatProductSymbolic_ABC(Mat mat) 751 { 752 PetscErrorCode ierr; 753 Mat_Product *product = mat->product; 754 Mat A=product->A,B=product->B,C=product->C; 755 756 PetscFunctionBegin; 757 if (!mat->ops->matmatmultsymbolic) SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing symbolic implementation of product %s",MatProductTypes[product->type]); 758 ierr = (*mat->ops->matmatmultsymbolic)(A,B,C,product->fill,mat);CHKERRQ(ierr); 759 mat->ops->productnumeric = MatProductNumeric_ABC; 760 PetscFunctionReturn(0); 761 } 762 763 /* ----------------------------------------------- */ 764 765 /*@ 766 MatProductSymbolic - Perform the symbolic portion of a matrix product, this creates a data structure for use with the numerical produce. 767 768 Collective on Mat 769 770 Input/Output Parameter: 771 . mat - the matrix to hold a product 772 773 Level: intermediate 774 775 Notes: MatProductSetFromOptions() must have been called on mat before calling this function 776 777 .seealso: MatProductCreate(), MatProductCreateWithMat(), MatProductSetFromOptions(), MatProductNumeric(), MatProductSetType(), MatProductSetAlgorithm() 778 @*/ 779 PetscErrorCode MatProductSymbolic(Mat mat) 780 { 781 PetscErrorCode ierr; 782 PetscLogEvent eventtype=-1; 783 784 PetscFunctionBegin; 785 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 786 MatCheckProduct(mat,1); 787 if (mat->product->data) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Cannot run symbolic phase. Product data not empty"); 788 /* log event */ 789 switch (mat->product->type) { 790 case MATPRODUCT_AB: 791 eventtype = MAT_MatMultSymbolic; 792 break; 793 case MATPRODUCT_AtB: 794 eventtype = MAT_TransposeMatMultSymbolic; 795 break; 796 case MATPRODUCT_ABt: 797 eventtype = MAT_MatTransposeMultSymbolic; 798 break; 799 case MATPRODUCT_PtAP: 800 eventtype = MAT_PtAPSymbolic; 801 break; 802 case MATPRODUCT_RARt: 803 eventtype = MAT_RARtSymbolic; 804 break; 805 case MATPRODUCT_ABC: 806 eventtype = MAT_MatMatMultSymbolic; 807 break; 808 default: SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[mat->product->type]); 809 } 810 811 mat->ops->productnumeric = NULL; 812 if (mat->ops->productsymbolic) { 813 ierr = PetscLogEventBegin(eventtype,mat,0,0,0);CHKERRQ(ierr); 814 ierr = (*mat->ops->productsymbolic)(mat);CHKERRQ(ierr); 815 ierr = PetscLogEventEnd(eventtype,mat,0,0,0);CHKERRQ(ierr); 816 } else SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_ORDER,"Call MatProductSetFromOptions() first"); 817 if (!mat->product) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing product after symbolic phase"); 818 if (!mat->ops->productnumeric) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Symbolic phase did not specify the numeric phase"); 819 PetscFunctionReturn(0); 820 } 821 822 /*@ 823 MatProductSetFill - Set an expected fill of the matrix product. 824 825 Collective on Mat 826 827 Input Parameters: 828 + mat - the matrix product 829 - 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. 830 831 Level: intermediate 832 833 .seealso: MatProductSetType(), MatProductSetAlgorithm(), MatProductCreate() 834 @*/ 835 PetscErrorCode MatProductSetFill(Mat mat,PetscReal fill) 836 { 837 PetscFunctionBegin; 838 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 839 MatCheckProduct(mat,1); 840 if (fill == PETSC_DEFAULT || fill == PETSC_DECIDE) mat->product->fill = 2.0; 841 else mat->product->fill = fill; 842 PetscFunctionReturn(0); 843 } 844 845 /*@ 846 MatProductSetAlgorithm - Requests a particular algorithm for a matrix product implementation. 847 848 Collective on Mat 849 850 Input Parameters: 851 + mat - the matrix product 852 - alg - particular implementation algorithm of the matrix product, e.g., MATPRODUCTALGORITHM_DEFAULT. 853 854 Level: intermediate 855 856 .seealso: MatProductSetType(), MatProductSetFill(), MatProductCreate(), MatProductAlgorithm 857 @*/ 858 PetscErrorCode MatProductSetAlgorithm(Mat mat,MatProductAlgorithm alg) 859 { 860 PetscErrorCode ierr; 861 862 PetscFunctionBegin; 863 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 864 MatCheckProduct(mat,1); 865 ierr = PetscFree(mat->product->alg);CHKERRQ(ierr); 866 ierr = PetscStrallocpy(alg,&mat->product->alg);CHKERRQ(ierr); 867 PetscFunctionReturn(0); 868 } 869 870 /*@ 871 MatProductSetType - Sets a particular matrix product type 872 873 Collective on Mat 874 875 Input Parameters: 876 + mat - the matrix 877 - productype - matrix product type, e.g., MATPRODUCT_AB,MATPRODUCT_AtB,MATPRODUCT_ABt,MATPRODUCT_PtAP,MATPRODUCT_RARt,MATPRODUCT_ABC. 878 879 Level: intermediate 880 881 .seealso: MatProductCreate(), MatProductType 882 @*/ 883 PetscErrorCode MatProductSetType(Mat mat,MatProductType productype) 884 { 885 PetscErrorCode ierr; 886 887 PetscFunctionBegin; 888 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 889 MatCheckProduct(mat,1); 890 PetscValidLogicalCollectiveEnum(mat,productype,2); 891 if (productype != mat->product->type) { 892 if (mat->product->destroy) { 893 ierr = (*mat->product->destroy)(mat->product->data);CHKERRQ(ierr); 894 } 895 mat->product->destroy = NULL; 896 mat->product->data = NULL; 897 mat->ops->productsymbolic = NULL; 898 mat->ops->productnumeric = NULL; 899 } 900 mat->product->type = productype; 901 PetscFunctionReturn(0); 902 } 903 904 /*@ 905 MatProductClear - Clears matrix product internal structure. 906 907 Collective on Mat 908 909 Input Parameters: 910 . mat - the product matrix 911 912 Level: intermediate 913 914 Notes: this function should be called to remove any intermediate data used by the product 915 After having called this function, MatProduct operations can no longer be used on mat 916 @*/ 917 PetscErrorCode MatProductClear(Mat mat) 918 { 919 PetscErrorCode ierr; 920 Mat_Product *product = mat->product; 921 922 PetscFunctionBegin; 923 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 924 if (product) { 925 ierr = MatDestroy(&product->A);CHKERRQ(ierr); 926 ierr = MatDestroy(&product->B);CHKERRQ(ierr); 927 ierr = MatDestroy(&product->C);CHKERRQ(ierr); 928 ierr = PetscFree(product->alg);CHKERRQ(ierr); 929 ierr = MatDestroy(&product->Dwork);CHKERRQ(ierr); 930 if (product->destroy) { 931 ierr = (*product->destroy)(product->data);CHKERRQ(ierr); 932 } 933 } 934 ierr = PetscFree(mat->product);CHKERRQ(ierr); 935 mat->ops->productsymbolic = NULL; 936 mat->ops->productnumeric = NULL; 937 PetscFunctionReturn(0); 938 } 939 940 /* Create a supporting struct and attach it to the matrix product */ 941 PetscErrorCode MatProductCreate_Private(Mat A,Mat B,Mat C,Mat D) 942 { 943 PetscErrorCode ierr; 944 Mat_Product *product=NULL; 945 946 PetscFunctionBegin; 947 PetscValidHeaderSpecific(D,MAT_CLASSID,4); 948 if (D->product) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"Product already present"); 949 ierr = PetscNewLog(D,&product);CHKERRQ(ierr); 950 product->A = A; 951 product->B = B; 952 product->C = C; 953 product->type = MATPRODUCT_UNSPECIFIED; 954 product->Dwork = NULL; 955 product->api_user = PETSC_FALSE; 956 product->clear = PETSC_FALSE; 957 D->product = product; 958 959 ierr = MatProductSetAlgorithm(D,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr); 960 ierr = MatProductSetFill(D,PETSC_DEFAULT);CHKERRQ(ierr); 961 962 ierr = PetscObjectReference((PetscObject)A);CHKERRQ(ierr); 963 ierr = PetscObjectReference((PetscObject)B);CHKERRQ(ierr); 964 ierr = PetscObjectReference((PetscObject)C);CHKERRQ(ierr); 965 PetscFunctionReturn(0); 966 } 967 968 /*@ 969 MatProductCreateWithMat - Setup a given matrix as a matrix product. 970 971 Collective on Mat 972 973 Input Parameters: 974 + A - the first matrix 975 . B - the second matrix 976 . C - the third matrix (optional) 977 - D - the matrix which will be used as a product 978 979 Output Parameters: 980 . D - the product matrix 981 982 Notes: 983 Any product data attached to D will be cleared 984 985 Level: intermediate 986 987 .seealso: MatProductCreate(), MatProductClear() 988 @*/ 989 PetscErrorCode MatProductCreateWithMat(Mat A,Mat B,Mat C,Mat D) 990 { 991 PetscErrorCode ierr; 992 993 PetscFunctionBegin; 994 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 995 PetscValidType(A,1); 996 MatCheckPreallocated(A,1); 997 if (!A->assembled) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 998 if (A->factortype) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 999 1000 PetscValidHeaderSpecific(B,MAT_CLASSID,2); 1001 PetscValidType(B,2); 1002 MatCheckPreallocated(B,2); 1003 if (!B->assembled) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 1004 if (B->factortype) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 1005 1006 if (C) { 1007 PetscValidHeaderSpecific(C,MAT_CLASSID,3); 1008 PetscValidType(C,3); 1009 MatCheckPreallocated(C,3); 1010 if (!C->assembled) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 1011 if (C->factortype) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 1012 } 1013 1014 PetscValidHeaderSpecific(D,MAT_CLASSID,4); 1015 PetscValidType(D,4); 1016 MatCheckPreallocated(D,4); 1017 if (!D->assembled) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 1018 if (D->factortype) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 1019 1020 /* Create a supporting struct and attach it to D */ 1021 ierr = MatProductClear(D);CHKERRQ(ierr); 1022 ierr = MatProductCreate_Private(A,B,C,D);CHKERRQ(ierr); 1023 PetscFunctionReturn(0); 1024 } 1025 1026 /*@ 1027 MatProductCreate - create a matrix product object that can be used to compute various matrix times matrix operations. 1028 1029 Collective on Mat 1030 1031 Input Parameters: 1032 + A - the first matrix 1033 . B - the second matrix 1034 - C - the third matrix (optional) 1035 1036 Output Parameters: 1037 . D - the product matrix 1038 1039 Level: intermediate 1040 1041 .seealso: MatProductCreateWithMat(), MatProductSetType(), MatProductSetAlgorithm() 1042 @*/ 1043 PetscErrorCode MatProductCreate(Mat A,Mat B,Mat C,Mat *D) 1044 { 1045 PetscErrorCode ierr; 1046 1047 PetscFunctionBegin; 1048 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 1049 PetscValidType(A,1); 1050 PetscValidHeaderSpecific(B,MAT_CLASSID,2); 1051 PetscValidType(B,2); 1052 if (A->factortype) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix A"); 1053 if (B->factortype) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix B"); 1054 1055 if (C) { 1056 PetscValidHeaderSpecific(C,MAT_CLASSID,3); 1057 PetscValidType(C,3); 1058 if (C->factortype) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix C"); 1059 } 1060 1061 PetscValidPointer(D,4); 1062 ierr = MatCreate(PetscObjectComm((PetscObject)A),D);CHKERRQ(ierr); 1063 ierr = MatProductCreate_Private(A,B,C,*D);CHKERRQ(ierr); 1064 PetscFunctionReturn(0); 1065 } 1066 1067 /* 1068 These are safe basic implementations of ABC, RARt and PtAP 1069 that do not rely on mat->ops->matmatop function pointers. 1070 They only use the MatProduct API and are currently used by 1071 cuSPARSE and KOKKOS-KERNELS backends 1072 */ 1073 typedef struct { 1074 Mat BC; 1075 Mat ABC; 1076 } MatMatMatPrivate; 1077 1078 static PetscErrorCode MatDestroy_MatMatMatPrivate(void *data) 1079 { 1080 PetscErrorCode ierr; 1081 MatMatMatPrivate *mmdata = (MatMatMatPrivate *)data; 1082 1083 PetscFunctionBegin; 1084 ierr = MatDestroy(&mmdata->BC);CHKERRQ(ierr); 1085 ierr = MatDestroy(&mmdata->ABC);CHKERRQ(ierr); 1086 ierr = PetscFree(data);CHKERRQ(ierr); 1087 PetscFunctionReturn(0); 1088 } 1089 1090 static PetscErrorCode MatProductNumeric_ABC_Basic(Mat mat) 1091 { 1092 PetscErrorCode ierr; 1093 Mat_Product *product = mat->product; 1094 MatMatMatPrivate *mmabc; 1095 1096 PetscFunctionBegin; 1097 MatCheckProduct(mat,1); 1098 if (!mat->product->data) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Product data empty"); 1099 mmabc = (MatMatMatPrivate *)mat->product->data; 1100 if (!mmabc->BC->ops->productnumeric) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric stage"); 1101 /* use function pointer directly to prevent logging */ 1102 ierr = (*mmabc->BC->ops->productnumeric)(mmabc->BC);CHKERRQ(ierr); 1103 /* swap ABC product stuff with that of ABC for the numeric phase on mat */ 1104 mat->product = mmabc->ABC->product; 1105 mat->ops->productnumeric = mmabc->ABC->ops->productnumeric; 1106 if (!mat->ops->productnumeric) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Missing numeric stage"); 1107 /* use function pointer directly to prevent logging */ 1108 ierr = (*mat->ops->productnumeric)(mat);CHKERRQ(ierr); 1109 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1110 mat->product = product; 1111 PetscFunctionReturn(0); 1112 } 1113 1114 PetscErrorCode MatProductSymbolic_ABC_Basic(Mat mat) 1115 { 1116 PetscErrorCode ierr; 1117 Mat_Product *product = mat->product; 1118 Mat A, B ,C; 1119 MatProductType p1,p2; 1120 MatMatMatPrivate *mmabc; 1121 const char *prefix; 1122 1123 PetscFunctionBegin; 1124 MatCheckProduct(mat,1); 1125 if (mat->product->data) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Product data not empty"); 1126 ierr = MatGetOptionsPrefix(mat,&prefix);CHKERRQ(ierr); 1127 ierr = PetscNew(&mmabc);CHKERRQ(ierr); 1128 product->data = mmabc; 1129 product->destroy = MatDestroy_MatMatMatPrivate; 1130 switch (product->type) { 1131 case MATPRODUCT_PtAP: 1132 p1 = MATPRODUCT_AB; 1133 p2 = MATPRODUCT_AtB; 1134 A = product->B; 1135 B = product->A; 1136 C = product->B; 1137 break; 1138 case MATPRODUCT_RARt: 1139 p1 = MATPRODUCT_ABt; 1140 p2 = MATPRODUCT_AB; 1141 A = product->B; 1142 B = product->A; 1143 C = product->B; 1144 break; 1145 case MATPRODUCT_ABC: 1146 p1 = MATPRODUCT_AB; 1147 p2 = MATPRODUCT_AB; 1148 A = product->A; 1149 B = product->B; 1150 C = product->C; 1151 break; 1152 default: 1153 SETERRQ1(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"Not for ProductType %s",MatProductTypes[product->type]); 1154 } 1155 ierr = MatProductCreate(B,C,NULL,&mmabc->BC);CHKERRQ(ierr); 1156 ierr = MatSetOptionsPrefix(mmabc->BC,prefix);CHKERRQ(ierr); 1157 ierr = MatAppendOptionsPrefix(mmabc->BC,"P1_");CHKERRQ(ierr); 1158 ierr = MatProductSetType(mmabc->BC,p1);CHKERRQ(ierr); 1159 ierr = MatProductSetAlgorithm(mmabc->BC,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr); 1160 ierr = MatProductSetFill(mmabc->BC,product->fill);CHKERRQ(ierr); 1161 mmabc->BC->product->api_user = product->api_user; 1162 ierr = MatProductSetFromOptions(mmabc->BC);CHKERRQ(ierr); 1163 if (!mmabc->BC->ops->productsymbolic) SETERRQ3(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); 1164 /* use function pointer directly to prevent logging */ 1165 ierr = (*mmabc->BC->ops->productsymbolic)(mmabc->BC);CHKERRQ(ierr); 1166 1167 ierr = MatProductCreate(A,mmabc->BC,NULL,&mmabc->ABC);CHKERRQ(ierr); 1168 ierr = MatSetOptionsPrefix(mmabc->ABC,prefix);CHKERRQ(ierr); 1169 ierr = MatAppendOptionsPrefix(mmabc->ABC,"P2_");CHKERRQ(ierr); 1170 ierr = MatProductSetType(mmabc->ABC,p2);CHKERRQ(ierr); 1171 ierr = MatProductSetAlgorithm(mmabc->ABC,MATPRODUCTALGORITHM_DEFAULT);CHKERRQ(ierr); 1172 ierr = MatProductSetFill(mmabc->ABC,product->fill);CHKERRQ(ierr); 1173 mmabc->ABC->product->api_user = product->api_user; 1174 ierr = MatProductSetFromOptions(mmabc->ABC);CHKERRQ(ierr); 1175 if (!mmabc->ABC->ops->productsymbolic) SETERRQ3(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); 1176 /* swap ABC product stuff with that of ABC for the symbolic phase on mat */ 1177 mat->product = mmabc->ABC->product; 1178 mat->ops->productsymbolic = mmabc->ABC->ops->productsymbolic; 1179 /* use function pointer directly to prevent logging */ 1180 ierr = (*mat->ops->productsymbolic)(mat);CHKERRQ(ierr); 1181 mmabc->ABC->ops->productnumeric = mat->ops->productnumeric; 1182 mat->ops->productsymbolic = MatProductSymbolic_ABC_Basic; 1183 mat->ops->productnumeric = MatProductNumeric_ABC_Basic; 1184 mat->product = product; 1185 PetscFunctionReturn(0); 1186 } 1187