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