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