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