1 /* 2 Defines projective product routines where A is a AIJ matrix 3 C = P^T * A * P 4 */ 5 6 #include "src/mat/impls/aij/seq/aij.h" /*I "petscmat.h" I*/ 7 #include "src/mat/utils/freespace.h" 8 #include "src/mat/impls/aij/mpi/mpiaij.h" 9 10 EXTERN int RegisterMatMatMultRoutines_Private(Mat); 11 12 static int MAT_PtAPSymbolic = 0; 13 static int MAT_PtAPNumeric = 0; 14 15 #undef __FUNCT__ 16 #define __FUNCT__ "MatPtAP" 17 /*@ 18 MatPtAP - Creates the matrix projection C = P^T * A * P 19 20 Collective on Mat 21 22 Input Parameters: 23 + A - the matrix 24 . P - the projection matrix 25 . scall - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX 26 - fill - expected fill as ratio of nnz(C)/(nnz(A) + nnz(P)) 27 28 Output Parameters: 29 . C - the product matrix 30 31 Notes: 32 C will be created and must be destroyed by the user with MatDestroy(). 33 34 This routine is currently only implemented for pairs of SeqAIJ matrices and classes 35 which inherit from SeqAIJ. C will be of type MATSEQAIJ. 36 37 Level: intermediate 38 39 .seealso: MatPtAPSymbolic(),MatPtAPNumeric(),MatMatMult() 40 @*/ 41 int MatPtAP(Mat A,Mat P,MatReuse scall,PetscReal fill,Mat *C) { 42 int ierr; 43 44 PetscFunctionBegin; 45 PetscValidHeaderSpecific(A,MAT_COOKIE,1); 46 PetscValidType(A,1); 47 MatPreallocated(A); 48 if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 49 if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 50 PetscValidHeaderSpecific(P,MAT_COOKIE,2); 51 PetscValidType(P,2); 52 MatPreallocated(P); 53 if (!P->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 54 if (P->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 55 PetscValidPointer(C,3); 56 if (P->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",P->M,A->N); 57 58 if (fill <=0.0) SETERRQ1(PETSC_ERR_ARG_SIZ,"fill=%g must be > 0.0",fill); 59 60 ierr = PetscLogEventBegin(MAT_PtAP,A,P,0,0);CHKERRQ(ierr); 61 ierr = (*A->ops->matptap)(A,P,scall,fill,C);CHKERRQ(ierr); 62 ierr = PetscLogEventEnd(MAT_PtAP,A,P,0,0);CHKERRQ(ierr); 63 PetscFunctionReturn(0); 64 } 65 66 #undef __FUNCT__ 67 #define __FUNCT__ "MatPtAP_SeqAIJ_SeqAIJ" 68 int MatPtAP_SeqAIJ_SeqAIJ(Mat A,Mat P,MatReuse scall,PetscReal fill,Mat *C) 69 { 70 int ierr; 71 PetscFunctionBegin; 72 if (scall == MAT_INITIAL_MATRIX){ 73 ierr = MatPtAPSymbolic_SeqAIJ_SeqAIJ(A,P,fill,C);CHKERRQ(ierr); 74 } 75 ierr = MatPtAPNumeric_SeqAIJ_SeqAIJ(A,P,*C);CHKERRQ(ierr); 76 PetscFunctionReturn(0); 77 } 78 79 #undef __FUNCT__ 80 #define __FUNCT__ "MatPtAPSymbolic" 81 /*@ 82 MatPtAPSymbolic - Creates the (i,j) structure of the matrix projection C = P^T * A * P 83 84 Collective on Mat 85 86 Input Parameters: 87 + A - the matrix 88 - P - the projection matrix 89 90 Output Parameters: 91 . C - the (i,j) structure of the product matrix 92 93 Notes: 94 C will be created and must be destroyed by the user with MatDestroy(). 95 96 This routine is currently only implemented for pairs of SeqAIJ matrices and classes 97 which inherit from SeqAIJ. C will be of type MATSEQAIJ. The product is computed using 98 this (i,j) structure by calling MatPtAPNumeric(). 99 100 Level: intermediate 101 102 .seealso: MatPtAP(),MatPtAPNumeric(),MatMatMultSymbolic() 103 @*/ 104 int MatPtAPSymbolic(Mat A,Mat P,PetscReal fill,Mat *C) { 105 int ierr; 106 char funct[80]; 107 int (*f)(Mat,Mat,Mat*); 108 109 PetscFunctionBegin; 110 111 PetscValidHeaderSpecific(A,MAT_COOKIE,1); 112 PetscValidType(A,1); 113 MatPreallocated(A); 114 if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 115 if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 116 117 PetscValidHeaderSpecific(P,MAT_COOKIE,2); 118 PetscValidType(P,2); 119 MatPreallocated(P); 120 if (!P->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 121 if (P->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 122 123 PetscValidPointer(C,3); 124 125 if (P->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",P->M,A->N); 126 if (A->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix 'A' must be square, %d != %d",A->M,A->N); 127 128 /* Currently only _seqaij_seqaij is implemented, so just query for it. */ 129 /* When other implementations exist, attack the multiple dispatch problem. */ 130 ierr = PetscStrcpy(funct,"MatPtAPSymbolic_seqaij_seqaij");CHKERRQ(ierr); 131 ierr = PetscObjectQueryFunction((PetscObject)P,funct,(PetscVoidFunction)&f);CHKERRQ(ierr); 132 if (!f) SETERRQ1(PETSC_ERR_SUP,"MatPtAPSymbolic is not supported for P of type %s",P->type_name); 133 ierr = PetscObjectQueryFunction((PetscObject)A,funct,(PetscVoidFunction)&f);CHKERRQ(ierr); 134 if (!f) SETERRQ1(PETSC_ERR_SUP,"MatPtAPSymbolic is not supported for A of type %s",A->type_name); 135 136 ierr = (*f)(A,P,C);CHKERRQ(ierr); 137 138 PetscFunctionReturn(0); 139 } 140 141 typedef struct { 142 Mat symAP; 143 } Mat_PtAPstruct; 144 145 #undef __FUNCT__ 146 #define __FUNCT__ "MatDestroy_SeqAIJ_PtAP" 147 int MatDestroy_SeqAIJ_PtAP(Mat A) 148 { 149 int ierr; 150 Mat_PtAPstruct *ptap=(Mat_PtAPstruct*)A->spptr; 151 152 PetscFunctionBegin; 153 ierr = MatDestroy(ptap->symAP);CHKERRQ(ierr); 154 ierr = PetscFree(ptap);CHKERRQ(ierr); 155 156 ierr = MatDestroy_SeqAIJ(A);CHKERRQ(ierr); 157 PetscFunctionReturn(0); 158 } 159 160 #undef __FUNCT__ 161 #define __FUNCT__ "MatPtAPSymbolic_SeqAIJ_SeqAIJ" 162 int MatPtAPSymbolic_SeqAIJ_SeqAIJ(Mat A,Mat P,PetscReal fill,Mat *C) { 163 int ierr,*pti,*ptj; 164 Mat Pt,AP; 165 Mat_PtAPstruct *ptap; 166 167 PetscFunctionBegin; 168 /* create symbolic Pt */ 169 ierr = MatGetSymbolicTranspose_SeqAIJ(P,&pti,&ptj);CHKERRQ(ierr); 170 ierr = MatCreateSeqAIJWithArrays(P->comm,P->N,P->M,pti,ptj,PETSC_NULL,&Pt);CHKERRQ(ierr); 171 172 /* get symbolic AP=A*P and C=Pt*AP */ 173 ierr = MatMatMultSymbolic_SeqAIJ_SeqAIJ(A,P,fill,&AP);CHKERRQ(ierr); 174 ierr = MatMatMultSymbolic_SeqAIJ_SeqAIJ(Pt,AP,fill,C);CHKERRQ(ierr); 175 176 /* clean up */ 177 ierr = MatRestoreSymbolicTranspose_SeqAIJ(Pt,&pti,&ptj);CHKERRQ(ierr); 178 ierr = MatDestroy(Pt);CHKERRQ(ierr); 179 180 /* save symbolic AP - to be used by MatPtAPNumeric_SeqAIJ_SeqAIJ() */ 181 ierr = PetscNew(Mat_PtAPstruct,&ptap);CHKERRQ(ierr); 182 ptap->symAP = AP; 183 (*C)->spptr = (void*)ptap; 184 (*C)->ops->destroy = MatDestroy_SeqAIJ_PtAP; 185 186 PetscFunctionReturn(0); 187 } 188 189 #include "src/mat/impls/maij/maij.h" 190 EXTERN_C_BEGIN 191 #undef __FUNCT__ 192 #define __FUNCT__ "MatPtAPSymbolic_SeqAIJ_SeqMAIJ" 193 int MatPtAPSymbolic_SeqAIJ_SeqMAIJ(Mat A,Mat PP,Mat *C) { 194 /* This routine requires testing -- I don't think it works. */ 195 int ierr; 196 FreeSpaceList free_space=PETSC_NULL,current_space=PETSC_NULL; 197 Mat_SeqMAIJ *pp=(Mat_SeqMAIJ*)PP->data; 198 Mat P=pp->AIJ; 199 Mat_SeqAIJ *a=(Mat_SeqAIJ*)A->data,*p=(Mat_SeqAIJ*)P->data,*c; 200 int *pti,*ptj,*ptJ,*ai=a->i,*aj=a->j,*ajj,*pi=p->i,*pj=p->j,*pjj; 201 int *ci,*cj,*denserow,*sparserow,*ptadenserow,*ptasparserow,*ptaj; 202 int an=A->N,am=A->M,pn=P->N,pm=P->M,ppdof=pp->dof; 203 int i,j,k,dof,pdof,ptnzi,arow,anzj,ptanzi,prow,pnzj,cnzi; 204 MatScalar *ca; 205 206 PetscFunctionBegin; 207 /* Start timer */ 208 ierr = PetscLogEventBegin(MAT_PtAPSymbolic,A,PP,0,0);CHKERRQ(ierr); 209 210 /* Get ij structure of P^T */ 211 ierr = MatGetSymbolicTranspose_SeqAIJ(P,&pti,&ptj);CHKERRQ(ierr); 212 213 /* Allocate ci array, arrays for fill computation and */ 214 /* free space for accumulating nonzero column info */ 215 ierr = PetscMalloc((pn+1)*sizeof(int),&ci);CHKERRQ(ierr); 216 ci[0] = 0; 217 218 ierr = PetscMalloc((2*pn+2*an+1)*sizeof(int),&ptadenserow);CHKERRQ(ierr); 219 ierr = PetscMemzero(ptadenserow,(2*pn+2*an+1)*sizeof(int));CHKERRQ(ierr); 220 ptasparserow = ptadenserow + an; 221 denserow = ptasparserow + an; 222 sparserow = denserow + pn; 223 224 /* Set initial free space to be nnz(A) scaled by aspect ratio of P. */ 225 /* This should be reasonable if sparsity of PtAP is similar to that of A. */ 226 ierr = GetMoreSpace((ai[am]/pm)*pn,&free_space); 227 current_space = free_space; 228 229 /* Determine symbolic info for each row of C: */ 230 for (i=0;i<pn/ppdof;i++) { 231 ptnzi = pti[i+1] - pti[i]; 232 ptanzi = 0; 233 ptJ = ptj + pti[i]; 234 for (dof=0;dof<ppdof;dof++) { 235 /* Determine symbolic row of PtA: */ 236 for (j=0;j<ptnzi;j++) { 237 arow = ptJ[j] + dof; 238 anzj = ai[arow+1] - ai[arow]; 239 ajj = aj + ai[arow]; 240 for (k=0;k<anzj;k++) { 241 if (!ptadenserow[ajj[k]]) { 242 ptadenserow[ajj[k]] = -1; 243 ptasparserow[ptanzi++] = ajj[k]; 244 } 245 } 246 } 247 /* Using symbolic info for row of PtA, determine symbolic info for row of C: */ 248 ptaj = ptasparserow; 249 cnzi = 0; 250 for (j=0;j<ptanzi;j++) { 251 pdof = *ptaj%dof; 252 prow = (*ptaj++)/dof; 253 pnzj = pi[prow+1] - pi[prow]; 254 pjj = pj + pi[prow]; 255 for (k=0;k<pnzj;k++) { 256 if (!denserow[pjj[k]+pdof]) { 257 denserow[pjj[k]+pdof] = -1; 258 sparserow[cnzi++] = pjj[k]+pdof; 259 } 260 } 261 } 262 263 /* sort sparserow */ 264 ierr = PetscSortInt(cnzi,sparserow);CHKERRQ(ierr); 265 266 /* If free space is not available, make more free space */ 267 /* Double the amount of total space in the list */ 268 if (current_space->local_remaining<cnzi) { 269 ierr = GetMoreSpace(current_space->total_array_size,¤t_space);CHKERRQ(ierr); 270 } 271 272 /* Copy data into free space, and zero out denserows */ 273 ierr = PetscMemcpy(current_space->array,sparserow,cnzi*sizeof(int));CHKERRQ(ierr); 274 current_space->array += cnzi; 275 current_space->local_used += cnzi; 276 current_space->local_remaining -= cnzi; 277 278 for (j=0;j<ptanzi;j++) { 279 ptadenserow[ptasparserow[j]] = 0; 280 } 281 for (j=0;j<cnzi;j++) { 282 denserow[sparserow[j]] = 0; 283 } 284 /* Aside: Perhaps we should save the pta info for the numerical factorization. */ 285 /* For now, we will recompute what is needed. */ 286 ci[i+1+dof] = ci[i+dof] + cnzi; 287 } 288 } 289 /* nnz is now stored in ci[ptm], column indices are in the list of free space */ 290 /* Allocate space for cj, initialize cj, and */ 291 /* destroy list of free space and other temporary array(s) */ 292 ierr = PetscMalloc((ci[pn]+1)*sizeof(int),&cj);CHKERRQ(ierr); 293 ierr = MakeSpaceContiguous(&free_space,cj);CHKERRQ(ierr); 294 ierr = PetscFree(ptadenserow);CHKERRQ(ierr); 295 296 /* Allocate space for ca */ 297 ierr = PetscMalloc((ci[pn]+1)*sizeof(MatScalar),&ca);CHKERRQ(ierr); 298 ierr = PetscMemzero(ca,(ci[pn]+1)*sizeof(MatScalar));CHKERRQ(ierr); 299 300 /* put together the new matrix */ 301 ierr = MatCreateSeqAIJWithArrays(A->comm,pn,pn,ci,cj,ca,C);CHKERRQ(ierr); 302 303 /* MatCreateSeqAIJWithArrays flags matrix so PETSc doesn't free the user's arrays. */ 304 /* Since these are PETSc arrays, change flags to free them as necessary. */ 305 c = (Mat_SeqAIJ *)((*C)->data); 306 c->freedata = PETSC_TRUE; 307 c->nonew = 0; 308 309 /* Clean up. */ 310 ierr = MatRestoreSymbolicTranspose_SeqAIJ(P,&pti,&ptj);CHKERRQ(ierr); 311 312 ierr = PetscLogEventEnd(MAT_PtAPSymbolic,A,PP,0,0);CHKERRQ(ierr); 313 PetscFunctionReturn(0); 314 } 315 EXTERN_C_END 316 317 #undef __FUNCT__ 318 #define __FUNCT__ "MatPtAPNumeric" 319 /*@ 320 MatPtAPNumeric - Computes the matrix projection C = P^T * A * P 321 322 Collective on Mat 323 324 Input Parameters: 325 + A - the matrix 326 - P - the projection matrix 327 328 Output Parameters: 329 . C - the product matrix 330 331 Notes: 332 C must have been created by calling MatPtAPSymbolic and must be destroyed by 333 the user using MatDeatroy(). 334 335 This routine is currently only implemented for pairs of SeqAIJ matrices and classes 336 which inherit from SeqAIJ. C will be of type MATSEQAIJ. 337 338 Level: intermediate 339 340 .seealso: MatPtAP(),MatPtAPSymbolic(),MatMatMultNumeric() 341 @*/ 342 int MatPtAPNumeric(Mat A,Mat P,Mat C) { 343 int ierr; 344 char funct[80]; 345 int (*f)(Mat,Mat,Mat); 346 347 PetscFunctionBegin; 348 349 PetscValidHeaderSpecific(A,MAT_COOKIE,1); 350 PetscValidType(A,1); 351 MatPreallocated(A); 352 if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 353 if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 354 355 PetscValidHeaderSpecific(P,MAT_COOKIE,2); 356 PetscValidType(P,2); 357 MatPreallocated(P); 358 if (!P->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 359 if (P->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 360 361 PetscValidHeaderSpecific(C,MAT_COOKIE,3); 362 PetscValidType(C,3); 363 MatPreallocated(C); 364 if (!C->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix"); 365 if (C->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix"); 366 367 if (P->N!=C->M) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",P->N,C->M); 368 if (P->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",P->M,A->N); 369 if (A->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix 'A' must be square, %d != %d",A->M,A->N); 370 if (P->N!=C->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",P->N,C->N); 371 372 /* Currently only _seqaij_seqaij is implemented, so just query for it. */ 373 /* When other implementations exist, attack the multiple dispatch problem. */ 374 ierr = PetscStrcpy(funct,"MatPtAPNumeric_seqaij_seqaij");CHKERRQ(ierr); 375 ierr = PetscObjectQueryFunction((PetscObject)P,funct,(PetscVoidFunction)&f);CHKERRQ(ierr); 376 if (!f) SETERRQ1(PETSC_ERR_SUP,"MatPtAPNumeric is not supported for P of type %s",P->type_name); 377 ierr = PetscObjectQueryFunction((PetscObject)A,funct,(PetscVoidFunction)&f);CHKERRQ(ierr); 378 if (!f) SETERRQ1(PETSC_ERR_SUP,"MatPtAPNumeric is not supported for A of type %s",A->type_name); 379 380 ierr = (*f)(A,P,C);CHKERRQ(ierr); 381 382 PetscFunctionReturn(0); 383 } 384 385 #undef __FUNCT__ 386 #define __FUNCT__ "MatPtAPNumeric_SeqAIJ_SeqAIJ" 387 int MatPtAPNumeric_SeqAIJ_SeqAIJ(Mat A,Mat P,Mat C) { 388 int ierr,flops=0; 389 Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data; 390 Mat_SeqAIJ *p = (Mat_SeqAIJ *) P->data; 391 Mat_SeqAIJ *c = (Mat_SeqAIJ *) C->data; 392 int *ai=a->i,*aj=a->j,*apjdense,*pi=p->i,*pj=p->j,*pJ=p->j,*pjj; 393 int *ci=c->i,*cj=c->j,*cjj; 394 int am=A->M,cn=C->N,cm=C->M; 395 int i,j,k,anzi,pnzi,apnzj,nextap,pnzj,prow,crow; 396 MatScalar *aa=a->a,*apa,*pa=p->a,*pA=p->a,*paj,*ca=c->a,*caj; 397 Mat_PtAPstruct *ptap=(Mat_PtAPstruct*)C->spptr; 398 Mat_SeqAIJ *ap = (Mat_SeqAIJ *)(ptap->symAP)->data; 399 int *api=ap->i,*apj=ap->j,apj_nextap; 400 401 PetscFunctionBegin; 402 /* Allocate temporary array for storage of one row of A*P */ 403 ierr = PetscMalloc(cn*sizeof(MatScalar),&apa);CHKERRQ(ierr); 404 ierr = PetscMemzero(apa,cn*sizeof(MatScalar));CHKERRQ(ierr); 405 406 /* Clear old values in C */ 407 ierr = PetscMemzero(ca,ci[cm]*sizeof(MatScalar));CHKERRQ(ierr); 408 409 for (i=0;i<am;i++) { 410 /* Get sparse values of A*P[i,:] */ 411 anzi = ai[i+1] - ai[i]; 412 apnzj = 0; 413 for (j=0;j<anzi;j++) { 414 prow = *aj++; 415 pnzj = pi[prow+1] - pi[prow]; 416 pjj = pj + pi[prow]; 417 paj = pa + pi[prow]; 418 for (k=0;k<pnzj;k++) { 419 apa[pjj[k]] += (*aa)*paj[k]; 420 } 421 flops += 2*pnzj; 422 aa++; 423 } 424 425 /* Compute P^T*A*P using outer product (P^T)[:,j]*(A*P)[j,:]. */ 426 apj = ap->j + api[i]; 427 apnzj = api[i+1] - api[i]; 428 pnzi = pi[i+1] - pi[i]; 429 for (j=0;j<pnzi;j++) { 430 nextap = 0; 431 crow = *pJ++; 432 cjj = cj + ci[crow]; 433 caj = ca + ci[crow]; 434 /* Perform sparse axpy operation. Note cjj includes apj. */ 435 for (k=0; nextap<apnzj; k++) { 436 apj_nextap = *(apj+nextap); 437 if (cjj[k]==apj_nextap) { 438 caj[k] += (*pA)*apa[apj_nextap]; 439 nextap++; 440 } 441 } 442 flops += 2*apnzj; 443 pA++; 444 } 445 446 /* Zero the current row values for A*P */ 447 for (j=0;j<apnzj;j++) apa[apj[j]] = 0.0; 448 } 449 450 /* Assemble the final matrix and clean up */ 451 ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 452 ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 453 ierr = PetscFree(apa);CHKERRQ(ierr); 454 ierr = PetscLogFlops(flops);CHKERRQ(ierr); 455 456 PetscFunctionReturn(0); 457 } 458 459 #undef __FUNCT__ 460 #define __FUNCT__ "RegisterPtAPRoutines_Private" 461 int RegisterPtAPRoutines_Private(Mat A) { 462 int ierr; 463 464 PetscFunctionBegin; 465 if (!MAT_PtAPSymbolic) { 466 ierr = PetscLogEventRegister(&MAT_PtAPSymbolic,"MatPtAPSymbolic",MAT_COOKIE);CHKERRQ(ierr); 467 } 468 if (!MAT_PtAPNumeric) { 469 ierr = PetscLogEventRegister(&MAT_PtAPNumeric,"MatPtAPNumeric",MAT_COOKIE);CHKERRQ(ierr); 470 } 471 ierr = RegisterMatMatMultRoutines_Private(A);CHKERRQ(ierr); 472 473 PetscFunctionReturn(0); 474 } 475