xref: /petsc/src/mat/impls/aij/seq/matptap.c (revision 534c1384a790e876391cbb8541980f0b12ff9287)
1eb9c0419SKris Buschelman /*
29af31e4aSHong Zhang   Defines projective product routines where A is a AIJ matrix
3eb9c0419SKris Buschelman           C = P^T * A * P
4eb9c0419SKris Buschelman */
5eb9c0419SKris Buschelman 
6231952e2SKris Buschelman #include "src/mat/impls/aij/seq/aij.h"   /*I "petscmat.h" I*/
7eb9c0419SKris Buschelman #include "src/mat/utils/freespace.h"
89af31e4aSHong Zhang #include "src/mat/impls/aij/mpi/mpiaij.h"
9eb9c0419SKris Buschelman 
10dfbe8321SBarry Smith EXTERN PetscErrorCode RegisterMatMatMultRoutines_Private(Mat);
11eb9c0419SKris Buschelman 
12eb9c0419SKris Buschelman #undef __FUNCT__
139af31e4aSHong Zhang #define __FUNCT__ "MatPtAP"
144d3841fdSKris Buschelman /*@
159af31e4aSHong Zhang    MatPtAP - Creates the matrix projection C = P^T * A * P
164d3841fdSKris Buschelman 
174d3841fdSKris Buschelman    Collective on Mat
184d3841fdSKris Buschelman 
194d3841fdSKris Buschelman    Input Parameters:
204d3841fdSKris Buschelman +  A - the matrix
21f747e1aeSHong Zhang .  P - the projection matrix
22f747e1aeSHong Zhang .  scall - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX
23f747e1aeSHong Zhang -  fill - expected fill as ratio of nnz(C)/(nnz(A) + nnz(P))
244d3841fdSKris Buschelman 
254d3841fdSKris Buschelman    Output Parameters:
264d3841fdSKris Buschelman .  C - the product matrix
274d3841fdSKris Buschelman 
284d3841fdSKris Buschelman    Notes:
294d3841fdSKris Buschelman    C will be created and must be destroyed by the user with MatDestroy().
304d3841fdSKris Buschelman 
314d3841fdSKris Buschelman    This routine is currently only implemented for pairs of SeqAIJ matrices and classes
324d3841fdSKris Buschelman    which inherit from SeqAIJ.  C will be of type MATSEQAIJ.
334d3841fdSKris Buschelman 
344d3841fdSKris Buschelman    Level: intermediate
354d3841fdSKris Buschelman 
369af31e4aSHong Zhang .seealso: MatPtAPSymbolic(),MatPtAPNumeric(),MatMatMult()
374d3841fdSKris Buschelman @*/
38dfbe8321SBarry Smith PetscErrorCode MatPtAP(Mat A,Mat P,MatReuse scall,PetscReal fill,Mat *C) {
39dfbe8321SBarry Smith   PetscErrorCode ierr;
40*534c1384SKris Buschelman   PetscErrorCode (*fA)(Mat,Mat,MatReuse,PetscReal,Mat *);
41*534c1384SKris Buschelman   PetscErrorCode (*fP)(Mat,Mat,MatReuse,PetscReal,Mat *);
42eb9c0419SKris Buschelman 
43eb9c0419SKris Buschelman   PetscFunctionBegin;
449af31e4aSHong Zhang   PetscValidHeaderSpecific(A,MAT_COOKIE,1);
459af31e4aSHong Zhang   PetscValidType(A,1);
469af31e4aSHong Zhang   MatPreallocated(A);
479af31e4aSHong Zhang   if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
489af31e4aSHong Zhang   if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
499af31e4aSHong Zhang   PetscValidHeaderSpecific(P,MAT_COOKIE,2);
509af31e4aSHong Zhang   PetscValidType(P,2);
519af31e4aSHong Zhang   MatPreallocated(P);
529af31e4aSHong Zhang   if (!P->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
539af31e4aSHong Zhang   if (P->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
549af31e4aSHong Zhang   PetscValidPointer(C,3);
55*534c1384SKris Buschelman 
569af31e4aSHong Zhang   if (P->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",P->M,A->N);
57eb9c0419SKris Buschelman 
589af31e4aSHong Zhang   if (fill <=0.0) SETERRQ1(PETSC_ERR_ARG_SIZ,"fill=%g must be > 0.0",fill);
59eb9c0419SKris Buschelman 
60*534c1384SKris Buschelman   /* For now, we do not dispatch based on the type of A and P */
61*534c1384SKris Buschelman   /* When implementations like _SeqAIJ_MAIJ exist, attack the multiple dispatch problem. */
62*534c1384SKris Buschelman   fA = A->ops->ptap;
63*534c1384SKris Buschelman   if (!fA) SETERRQ1(PETSC_ERR_SUP,"MatPtAP not supported for A of type %s",A->type_name);
64*534c1384SKris Buschelman   fP = P->ops->ptap;
65*534c1384SKris Buschelman   if (!fP) SETERRQ1(PETSC_ERR_SUP,"MatPtAP not supported for P of type %s",P->type_name);
66*534c1384SKris Buschelman   if (fP!=fA) SETERRQ2(PETSC_ERR_ARG_INCOMP,"MatPtAP requires A, %s, to be compatible with P, %s",A->type_name,P->type_name);
67*534c1384SKris Buschelman 
689af31e4aSHong Zhang   ierr = PetscLogEventBegin(MAT_PtAP,A,P,0,0);CHKERRQ(ierr);
69*534c1384SKris Buschelman   ierr = (*fA)(A,P,scall,fill,C);CHKERRQ(ierr);
709af31e4aSHong Zhang   ierr = PetscLogEventEnd(MAT_PtAP,A,P,0,0);CHKERRQ(ierr);
71eb9c0419SKris Buschelman   PetscFunctionReturn(0);
72eb9c0419SKris Buschelman }
73eb9c0419SKris Buschelman 
74eb9c0419SKris Buschelman #undef __FUNCT__
759af31e4aSHong Zhang #define __FUNCT__ "MatPtAP_SeqAIJ_SeqAIJ"
76dfbe8321SBarry Smith PetscErrorCode MatPtAP_SeqAIJ_SeqAIJ(Mat A,Mat P,MatReuse scall,PetscReal fill,Mat *C)
779af31e4aSHong Zhang {
78dfbe8321SBarry Smith   PetscErrorCode ierr;
799af31e4aSHong Zhang   PetscFunctionBegin;
809af31e4aSHong Zhang   if (scall == MAT_INITIAL_MATRIX){
819af31e4aSHong Zhang     ierr = MatPtAPSymbolic_SeqAIJ_SeqAIJ(A,P,fill,C);CHKERRQ(ierr);
829af31e4aSHong Zhang   }
839af31e4aSHong Zhang   ierr = MatPtAPNumeric_SeqAIJ_SeqAIJ(A,P,*C);CHKERRQ(ierr);
849af31e4aSHong Zhang   PetscFunctionReturn(0);
859af31e4aSHong Zhang }
869af31e4aSHong Zhang 
879af31e4aSHong Zhang #undef __FUNCT__
889af31e4aSHong Zhang #define __FUNCT__ "MatPtAPSymbolic"
896849ba73SBarry Smith /*
909af31e4aSHong Zhang    MatPtAPSymbolic - Creates the (i,j) structure of the matrix projection C = P^T * A * P
914d3841fdSKris Buschelman 
924d3841fdSKris Buschelman    Collective on Mat
934d3841fdSKris Buschelman 
944d3841fdSKris Buschelman    Input Parameters:
954d3841fdSKris Buschelman +  A - the matrix
964d3841fdSKris Buschelman -  P - the projection matrix
974d3841fdSKris Buschelman 
984d3841fdSKris Buschelman    Output Parameters:
994d3841fdSKris Buschelman .  C - the (i,j) structure of the product matrix
1004d3841fdSKris Buschelman 
1014d3841fdSKris Buschelman    Notes:
1024d3841fdSKris Buschelman    C will be created and must be destroyed by the user with MatDestroy().
1034d3841fdSKris Buschelman 
1044d3841fdSKris Buschelman    This routine is currently only implemented for pairs of SeqAIJ matrices and classes
1054d3841fdSKris Buschelman    which inherit from SeqAIJ.  C will be of type MATSEQAIJ.  The product is computed using
1069af31e4aSHong Zhang    this (i,j) structure by calling MatPtAPNumeric().
1074d3841fdSKris Buschelman 
1084d3841fdSKris Buschelman    Level: intermediate
1094d3841fdSKris Buschelman 
1109af31e4aSHong Zhang .seealso: MatPtAP(),MatPtAPNumeric(),MatMatMultSymbolic()
1116849ba73SBarry Smith */
112dfbe8321SBarry Smith PetscErrorCode MatPtAPSymbolic(Mat A,Mat P,PetscReal fill,Mat *C) {
113dfbe8321SBarry Smith   PetscErrorCode ierr;
114*534c1384SKris Buschelman   PetscErrorCode (*fA)(Mat,Mat,PetscReal,Mat*);
115*534c1384SKris Buschelman   PetscErrorCode (*fP)(Mat,Mat,PetscReal,Mat*);
116eb9c0419SKris Buschelman 
117eb9c0419SKris Buschelman   PetscFunctionBegin;
118eb9c0419SKris Buschelman 
1194482741eSBarry Smith   PetscValidHeaderSpecific(A,MAT_COOKIE,1);
120c9780b6fSBarry Smith   PetscValidType(A,1);
121eb9c0419SKris Buschelman   MatPreallocated(A);
122eb9c0419SKris Buschelman   if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
123eb9c0419SKris Buschelman   if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
124eb9c0419SKris Buschelman 
1254482741eSBarry Smith   PetscValidHeaderSpecific(P,MAT_COOKIE,2);
126c9780b6fSBarry Smith   PetscValidType(P,2);
127eb9c0419SKris Buschelman   MatPreallocated(P);
128eb9c0419SKris Buschelman   if (!P->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
129eb9c0419SKris Buschelman   if (P->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
130eb9c0419SKris Buschelman 
1314482741eSBarry Smith   PetscValidPointer(C,3);
1324482741eSBarry Smith 
133eb9c0419SKris Buschelman   if (P->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",P->M,A->N);
134eb9c0419SKris Buschelman   if (A->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix 'A' must be square, %d != %d",A->M,A->N);
135eb9c0419SKris Buschelman 
136*534c1384SKris Buschelman   /* For now, we do not dispatch based on the type of A and P */
137*534c1384SKris Buschelman   /* When implementations like _SeqAIJ_MAIJ exist, attack the multiple dispatch problem. */
138*534c1384SKris Buschelman   fA = A->ops->ptapsymbolic;
139*534c1384SKris Buschelman   if (!fA) SETERRQ1(PETSC_ERR_SUP,"MatPtAPSymbolic not supported for A of type %s",A->type_name);
140*534c1384SKris Buschelman   fP = P->ops->ptapsymbolic;
141*534c1384SKris Buschelman   if (!fP) SETERRQ1(PETSC_ERR_SUP,"MatPtAPSymbolic not supported for P of type %s",P->type_name);
142*534c1384SKris Buschelman   if (fP!=fA) SETERRQ2(PETSC_ERR_ARG_INCOMP,"MatPtAPSymbolic requires A, %s, to be compatible with P, %s",A->type_name,P->type_name);
1434d3841fdSKris Buschelman 
144*534c1384SKris Buschelman   ierr = PetscLogEventBegin(MAT_PtAPSymbolic,A,P,0,0);CHKERRQ(ierr);
145*534c1384SKris Buschelman   ierr = (*fA)(A,P,fill,C);CHKERRQ(ierr);
146*534c1384SKris Buschelman   ierr = PetscLogEventEnd(MAT_PtAPSymbolic,A,P,0,0);CHKERRQ(ierr);
147eb9c0419SKris Buschelman 
148eb9c0419SKris Buschelman   PetscFunctionReturn(0);
149eb9c0419SKris Buschelman }
150eb9c0419SKris Buschelman 
151f747e1aeSHong Zhang typedef struct {
152f747e1aeSHong Zhang   Mat    symAP;
153f747e1aeSHong Zhang } Mat_PtAPstruct;
154f747e1aeSHong Zhang 
15578a80504SBarry Smith EXTERN PetscErrorCode MatDestroy_SeqAIJ(Mat);
15678a80504SBarry Smith 
157f747e1aeSHong Zhang #undef __FUNCT__
158f747e1aeSHong Zhang #define __FUNCT__ "MatDestroy_SeqAIJ_PtAP"
159f4a850bbSBarry Smith PetscErrorCode MatDestroy_SeqAIJ_PtAP(Mat A)
160f747e1aeSHong Zhang {
161f4a850bbSBarry Smith   PetscErrorCode    ierr;
162f747e1aeSHong Zhang   Mat_PtAPstruct    *ptap=(Mat_PtAPstruct*)A->spptr;
163f747e1aeSHong Zhang 
164f747e1aeSHong Zhang   PetscFunctionBegin;
165f747e1aeSHong Zhang   ierr = MatDestroy(ptap->symAP);CHKERRQ(ierr);
166f747e1aeSHong Zhang   ierr = PetscFree(ptap);CHKERRQ(ierr);
16778a80504SBarry Smith   ierr = MatDestroy_SeqAIJ(A);CHKERRQ(ierr);
168f747e1aeSHong Zhang   PetscFunctionReturn(0);
169f747e1aeSHong Zhang }
170f747e1aeSHong Zhang 
171eb9c0419SKris Buschelman #undef __FUNCT__
1729af31e4aSHong Zhang #define __FUNCT__ "MatPtAPSymbolic_SeqAIJ_SeqAIJ"
173dfbe8321SBarry Smith PetscErrorCode MatPtAPSymbolic_SeqAIJ_SeqAIJ(Mat A,Mat P,PetscReal fill,Mat *C) {
174dfbe8321SBarry Smith   PetscErrorCode ierr;
175f4a850bbSBarry Smith   int            *pti,*ptj;
176f747e1aeSHong Zhang   Mat            Pt,AP;
177f747e1aeSHong Zhang   Mat_PtAPstruct *ptap;
178eb9c0419SKris Buschelman 
179eb9c0419SKris Buschelman   PetscFunctionBegin;
180f747e1aeSHong Zhang   /* create symbolic Pt */
181eb9c0419SKris Buschelman   ierr = MatGetSymbolicTranspose_SeqAIJ(P,&pti,&ptj);CHKERRQ(ierr);
182f747e1aeSHong Zhang   ierr = MatCreateSeqAIJWithArrays(P->comm,P->N,P->M,pti,ptj,PETSC_NULL,&Pt);CHKERRQ(ierr);
183eb9c0419SKris Buschelman 
184f747e1aeSHong Zhang   /* get symbolic AP=A*P and C=Pt*AP */
185f747e1aeSHong Zhang   ierr = MatMatMultSymbolic_SeqAIJ_SeqAIJ(A,P,fill,&AP);CHKERRQ(ierr);
186f747e1aeSHong Zhang   ierr = MatMatMultSymbolic_SeqAIJ_SeqAIJ(Pt,AP,fill,C);CHKERRQ(ierr);
187eb9c0419SKris Buschelman 
188f747e1aeSHong Zhang   /* clean up */
189f747e1aeSHong Zhang   ierr = MatRestoreSymbolicTranspose_SeqAIJ(Pt,&pti,&ptj);CHKERRQ(ierr);
190f747e1aeSHong Zhang   ierr = MatDestroy(Pt);CHKERRQ(ierr);
191eb9c0419SKris Buschelman 
192f747e1aeSHong Zhang   /* save symbolic AP - to be used by MatPtAPNumeric_SeqAIJ_SeqAIJ() */
193f747e1aeSHong Zhang   ierr = PetscNew(Mat_PtAPstruct,&ptap);CHKERRQ(ierr);
194f747e1aeSHong Zhang   ptap->symAP = AP;
195f747e1aeSHong Zhang   (*C)->spptr = (void*)ptap;
196f747e1aeSHong Zhang   (*C)->ops->destroy  = MatDestroy_SeqAIJ_PtAP;
197eb9c0419SKris Buschelman 
198eb9c0419SKris Buschelman   PetscFunctionReturn(0);
199eb9c0419SKris Buschelman }
200eb9c0419SKris Buschelman 
2013985e5eaSKris Buschelman #include "src/mat/impls/maij/maij.h"
2023985e5eaSKris Buschelman EXTERN_C_BEGIN
2033985e5eaSKris Buschelman #undef __FUNCT__
2049af31e4aSHong Zhang #define __FUNCT__ "MatPtAPSymbolic_SeqAIJ_SeqMAIJ"
205dfbe8321SBarry Smith PetscErrorCode MatPtAPSymbolic_SeqAIJ_SeqMAIJ(Mat A,Mat PP,Mat *C) {
2065c66b693SKris Buschelman   /* This routine requires testing -- I don't think it works. */
207dfbe8321SBarry Smith   PetscErrorCode ierr;
2083985e5eaSKris Buschelman   FreeSpaceList  free_space=PETSC_NULL,current_space=PETSC_NULL;
2093985e5eaSKris Buschelman   Mat_SeqMAIJ    *pp=(Mat_SeqMAIJ*)PP->data;
2103985e5eaSKris Buschelman   Mat            P=pp->AIJ;
2113985e5eaSKris Buschelman   Mat_SeqAIJ     *a=(Mat_SeqAIJ*)A->data,*p=(Mat_SeqAIJ*)P->data,*c;
2123985e5eaSKris Buschelman   int            *pti,*ptj,*ptJ,*ai=a->i,*aj=a->j,*ajj,*pi=p->i,*pj=p->j,*pjj;
2133985e5eaSKris Buschelman   int            *ci,*cj,*denserow,*sparserow,*ptadenserow,*ptasparserow,*ptaj;
2143985e5eaSKris Buschelman   int            an=A->N,am=A->M,pn=P->N,pm=P->M,ppdof=pp->dof;
215fe05a634SKris Buschelman   int            i,j,k,dof,pdof,ptnzi,arow,anzj,ptanzi,prow,pnzj,cnzi;
2163985e5eaSKris Buschelman   MatScalar      *ca;
2173985e5eaSKris Buschelman 
2183985e5eaSKris Buschelman   PetscFunctionBegin;
2193985e5eaSKris Buschelman   /* Start timer */
2209af31e4aSHong Zhang   ierr = PetscLogEventBegin(MAT_PtAPSymbolic,A,PP,0,0);CHKERRQ(ierr);
2213985e5eaSKris Buschelman 
2223985e5eaSKris Buschelman   /* Get ij structure of P^T */
2233985e5eaSKris Buschelman   ierr = MatGetSymbolicTranspose_SeqAIJ(P,&pti,&ptj);CHKERRQ(ierr);
2243985e5eaSKris Buschelman 
2253985e5eaSKris Buschelman   /* Allocate ci array, arrays for fill computation and */
2263985e5eaSKris Buschelman   /* free space for accumulating nonzero column info */
2273985e5eaSKris Buschelman   ierr = PetscMalloc((pn+1)*sizeof(int),&ci);CHKERRQ(ierr);
2283985e5eaSKris Buschelman   ci[0] = 0;
2293985e5eaSKris Buschelman 
2303985e5eaSKris Buschelman   ierr = PetscMalloc((2*pn+2*an+1)*sizeof(int),&ptadenserow);CHKERRQ(ierr);
2313985e5eaSKris Buschelman   ierr = PetscMemzero(ptadenserow,(2*pn+2*an+1)*sizeof(int));CHKERRQ(ierr);
2323985e5eaSKris Buschelman   ptasparserow = ptadenserow  + an;
2333985e5eaSKris Buschelman   denserow     = ptasparserow + an;
2343985e5eaSKris Buschelman   sparserow    = denserow     + pn;
2353985e5eaSKris Buschelman 
2363985e5eaSKris Buschelman   /* Set initial free space to be nnz(A) scaled by aspect ratio of P. */
2373985e5eaSKris Buschelman   /* This should be reasonable if sparsity of PtAP is similar to that of A. */
2383985e5eaSKris Buschelman   ierr          = GetMoreSpace((ai[am]/pm)*pn,&free_space);
2393985e5eaSKris Buschelman   current_space = free_space;
2403985e5eaSKris Buschelman 
2413985e5eaSKris Buschelman   /* Determine symbolic info for each row of C: */
2423985e5eaSKris Buschelman   for (i=0;i<pn/ppdof;i++) {
2433985e5eaSKris Buschelman     ptnzi  = pti[i+1] - pti[i];
2443985e5eaSKris Buschelman     ptanzi = 0;
2453985e5eaSKris Buschelman     ptJ    = ptj + pti[i];
2463985e5eaSKris Buschelman     for (dof=0;dof<ppdof;dof++) {
2473985e5eaSKris Buschelman     /* Determine symbolic row of PtA: */
2483985e5eaSKris Buschelman       for (j=0;j<ptnzi;j++) {
2493985e5eaSKris Buschelman         arow = ptJ[j] + dof;
2503985e5eaSKris Buschelman         anzj = ai[arow+1] - ai[arow];
2513985e5eaSKris Buschelman         ajj  = aj + ai[arow];
2523985e5eaSKris Buschelman         for (k=0;k<anzj;k++) {
2533985e5eaSKris Buschelman           if (!ptadenserow[ajj[k]]) {
2543985e5eaSKris Buschelman             ptadenserow[ajj[k]]    = -1;
2553985e5eaSKris Buschelman             ptasparserow[ptanzi++] = ajj[k];
2563985e5eaSKris Buschelman           }
2573985e5eaSKris Buschelman         }
2583985e5eaSKris Buschelman       }
2593985e5eaSKris Buschelman       /* Using symbolic info for row of PtA, determine symbolic info for row of C: */
2603985e5eaSKris Buschelman       ptaj = ptasparserow;
2613985e5eaSKris Buschelman       cnzi   = 0;
2623985e5eaSKris Buschelman       for (j=0;j<ptanzi;j++) {
263fe05a634SKris Buschelman         pdof = *ptaj%dof;
2643985e5eaSKris Buschelman         prow = (*ptaj++)/dof;
2653985e5eaSKris Buschelman         pnzj = pi[prow+1] - pi[prow];
2663985e5eaSKris Buschelman         pjj  = pj + pi[prow];
2673985e5eaSKris Buschelman         for (k=0;k<pnzj;k++) {
268fe05a634SKris Buschelman           if (!denserow[pjj[k]+pdof]) {
269fe05a634SKris Buschelman             denserow[pjj[k]+pdof] = -1;
270fe05a634SKris Buschelman             sparserow[cnzi++]     = pjj[k]+pdof;
2713985e5eaSKris Buschelman           }
2723985e5eaSKris Buschelman         }
2733985e5eaSKris Buschelman       }
2743985e5eaSKris Buschelman 
2753985e5eaSKris Buschelman       /* sort sparserow */
2763985e5eaSKris Buschelman       ierr = PetscSortInt(cnzi,sparserow);CHKERRQ(ierr);
2773985e5eaSKris Buschelman 
2783985e5eaSKris Buschelman       /* If free space is not available, make more free space */
2793985e5eaSKris Buschelman       /* Double the amount of total space in the list */
2803985e5eaSKris Buschelman       if (current_space->local_remaining<cnzi) {
2813985e5eaSKris Buschelman         ierr = GetMoreSpace(current_space->total_array_size,&current_space);CHKERRQ(ierr);
2823985e5eaSKris Buschelman       }
2833985e5eaSKris Buschelman 
2843985e5eaSKris Buschelman       /* Copy data into free space, and zero out denserows */
2853985e5eaSKris Buschelman       ierr = PetscMemcpy(current_space->array,sparserow,cnzi*sizeof(int));CHKERRQ(ierr);
2863985e5eaSKris Buschelman       current_space->array           += cnzi;
2873985e5eaSKris Buschelman       current_space->local_used      += cnzi;
2883985e5eaSKris Buschelman       current_space->local_remaining -= cnzi;
2893985e5eaSKris Buschelman 
2903985e5eaSKris Buschelman       for (j=0;j<ptanzi;j++) {
2913985e5eaSKris Buschelman         ptadenserow[ptasparserow[j]] = 0;
2923985e5eaSKris Buschelman       }
2933985e5eaSKris Buschelman       for (j=0;j<cnzi;j++) {
2943985e5eaSKris Buschelman         denserow[sparserow[j]] = 0;
2953985e5eaSKris Buschelman       }
2963985e5eaSKris Buschelman       /* Aside: Perhaps we should save the pta info for the numerical factorization. */
2973985e5eaSKris Buschelman       /*        For now, we will recompute what is needed. */
2983985e5eaSKris Buschelman       ci[i+1+dof] = ci[i+dof] + cnzi;
2993985e5eaSKris Buschelman     }
3003985e5eaSKris Buschelman   }
3013985e5eaSKris Buschelman   /* nnz is now stored in ci[ptm], column indices are in the list of free space */
3023985e5eaSKris Buschelman   /* Allocate space for cj, initialize cj, and */
3033985e5eaSKris Buschelman   /* destroy list of free space and other temporary array(s) */
3043985e5eaSKris Buschelman   ierr = PetscMalloc((ci[pn]+1)*sizeof(int),&cj);CHKERRQ(ierr);
3053985e5eaSKris Buschelman   ierr = MakeSpaceContiguous(&free_space,cj);CHKERRQ(ierr);
3063985e5eaSKris Buschelman   ierr = PetscFree(ptadenserow);CHKERRQ(ierr);
3073985e5eaSKris Buschelman 
3083985e5eaSKris Buschelman   /* Allocate space for ca */
3093985e5eaSKris Buschelman   ierr = PetscMalloc((ci[pn]+1)*sizeof(MatScalar),&ca);CHKERRQ(ierr);
3103985e5eaSKris Buschelman   ierr = PetscMemzero(ca,(ci[pn]+1)*sizeof(MatScalar));CHKERRQ(ierr);
3113985e5eaSKris Buschelman 
3123985e5eaSKris Buschelman   /* put together the new matrix */
3133985e5eaSKris Buschelman   ierr = MatCreateSeqAIJWithArrays(A->comm,pn,pn,ci,cj,ca,C);CHKERRQ(ierr);
3143985e5eaSKris Buschelman 
3153985e5eaSKris Buschelman   /* MatCreateSeqAIJWithArrays flags matrix so PETSc doesn't free the user's arrays. */
3163985e5eaSKris Buschelman   /* Since these are PETSc arrays, change flags to free them as necessary. */
3173985e5eaSKris Buschelman   c = (Mat_SeqAIJ *)((*C)->data);
3183985e5eaSKris Buschelman   c->freedata = PETSC_TRUE;
3193985e5eaSKris Buschelman   c->nonew    = 0;
3203985e5eaSKris Buschelman 
3213985e5eaSKris Buschelman   /* Clean up. */
3223985e5eaSKris Buschelman   ierr = MatRestoreSymbolicTranspose_SeqAIJ(P,&pti,&ptj);CHKERRQ(ierr);
3233985e5eaSKris Buschelman 
3249af31e4aSHong Zhang   ierr = PetscLogEventEnd(MAT_PtAPSymbolic,A,PP,0,0);CHKERRQ(ierr);
3253985e5eaSKris Buschelman   PetscFunctionReturn(0);
3263985e5eaSKris Buschelman }
3273985e5eaSKris Buschelman EXTERN_C_END
3283985e5eaSKris Buschelman 
329eb9c0419SKris Buschelman #undef __FUNCT__
3309af31e4aSHong Zhang #define __FUNCT__ "MatPtAPNumeric"
3316849ba73SBarry Smith /*
3329af31e4aSHong Zhang    MatPtAPNumeric - Computes the matrix projection C = P^T * A * P
3334d3841fdSKris Buschelman 
3344d3841fdSKris Buschelman    Collective on Mat
3354d3841fdSKris Buschelman 
3364d3841fdSKris Buschelman    Input Parameters:
3374d3841fdSKris Buschelman +  A - the matrix
3384d3841fdSKris Buschelman -  P - the projection matrix
3394d3841fdSKris Buschelman 
3404d3841fdSKris Buschelman    Output Parameters:
3414d3841fdSKris Buschelman .  C - the product matrix
3424d3841fdSKris Buschelman 
3434d3841fdSKris Buschelman    Notes:
3449af31e4aSHong Zhang    C must have been created by calling MatPtAPSymbolic and must be destroyed by
3454d3841fdSKris Buschelman    the user using MatDeatroy().
3464d3841fdSKris Buschelman 
3474d3841fdSKris Buschelman    This routine is currently only implemented for pairs of SeqAIJ matrices and classes
3484d3841fdSKris Buschelman    which inherit from SeqAIJ.  C will be of type MATSEQAIJ.
3494d3841fdSKris Buschelman 
3504d3841fdSKris Buschelman    Level: intermediate
3514d3841fdSKris Buschelman 
3529af31e4aSHong Zhang .seealso: MatPtAP(),MatPtAPSymbolic(),MatMatMultNumeric()
3536849ba73SBarry Smith */
354dfbe8321SBarry Smith PetscErrorCode MatPtAPNumeric(Mat A,Mat P,Mat C) {
355dfbe8321SBarry Smith   PetscErrorCode ierr;
356*534c1384SKris Buschelman   PetscErrorCode (*fA)(Mat,Mat,Mat);
357*534c1384SKris Buschelman   PetscErrorCode (*fP)(Mat,Mat,Mat);
358eb9c0419SKris Buschelman 
359eb9c0419SKris Buschelman   PetscFunctionBegin;
360eb9c0419SKris Buschelman 
3614482741eSBarry Smith   PetscValidHeaderSpecific(A,MAT_COOKIE,1);
362c9780b6fSBarry Smith   PetscValidType(A,1);
363eb9c0419SKris Buschelman   MatPreallocated(A);
364eb9c0419SKris Buschelman   if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
365eb9c0419SKris Buschelman   if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
366eb9c0419SKris Buschelman 
3674482741eSBarry Smith   PetscValidHeaderSpecific(P,MAT_COOKIE,2);
368c9780b6fSBarry Smith   PetscValidType(P,2);
369eb9c0419SKris Buschelman   MatPreallocated(P);
370eb9c0419SKris Buschelman   if (!P->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
371eb9c0419SKris Buschelman   if (P->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
372eb9c0419SKris Buschelman 
3734482741eSBarry Smith   PetscValidHeaderSpecific(C,MAT_COOKIE,3);
374c9780b6fSBarry Smith   PetscValidType(C,3);
375eb9c0419SKris Buschelman   MatPreallocated(C);
376eb9c0419SKris Buschelman   if (!C->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
377eb9c0419SKris Buschelman   if (C->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
378eb9c0419SKris Buschelman 
379eb9c0419SKris Buschelman   if (P->N!=C->M) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",P->N,C->M);
380eb9c0419SKris Buschelman   if (P->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",P->M,A->N);
381eb9c0419SKris Buschelman   if (A->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix 'A' must be square, %d != %d",A->M,A->N);
382eb9c0419SKris Buschelman   if (P->N!=C->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",P->N,C->N);
383eb9c0419SKris Buschelman 
384*534c1384SKris Buschelman   /* For now, we do not dispatch based on the type of A and P */
385*534c1384SKris Buschelman   /* When implementations like _SeqAIJ_MAIJ exist, attack the multiple dispatch problem. */
386*534c1384SKris Buschelman   fA = A->ops->ptapnumeric;
387*534c1384SKris Buschelman   if (!fA) SETERRQ1(PETSC_ERR_SUP,"MatPtAPNumeric not supported for A of type %s",A->type_name);
388*534c1384SKris Buschelman   fP = P->ops->ptapnumeric;
389*534c1384SKris Buschelman   if (!fP) SETERRQ1(PETSC_ERR_SUP,"MatPtAPNumeric not supported for P of type %s",P->type_name);
390*534c1384SKris Buschelman   if (fP!=fA) SETERRQ2(PETSC_ERR_ARG_INCOMP,"MatPtAPNumeric requires A, %s, to be compatible with P, %s",A->type_name,P->type_name);
3914d3841fdSKris Buschelman 
392*534c1384SKris Buschelman   ierr = PetscLogEventBegin(MAT_PtAPNumeric,A,P,0,0);CHKERRQ(ierr);
393*534c1384SKris Buschelman   ierr = (*fA)(A,P,C);CHKERRQ(ierr);
394*534c1384SKris Buschelman   ierr = PetscLogEventEnd(MAT_PtAPNumeric,A,P,0,0);CHKERRQ(ierr);
395eb9c0419SKris Buschelman 
396eb9c0419SKris Buschelman   PetscFunctionReturn(0);
397eb9c0419SKris Buschelman }
398eb9c0419SKris Buschelman 
399eb9c0419SKris Buschelman #undef __FUNCT__
4009af31e4aSHong Zhang #define __FUNCT__ "MatPtAPNumeric_SeqAIJ_SeqAIJ"
401dfbe8321SBarry Smith PetscErrorCode MatPtAPNumeric_SeqAIJ_SeqAIJ(Mat A,Mat P,Mat C)
402dfbe8321SBarry Smith {
403dfbe8321SBarry Smith   PetscErrorCode ierr;
404dfbe8321SBarry Smith   int        flops=0;
405eb9c0419SKris Buschelman   Mat_SeqAIJ *a  = (Mat_SeqAIJ *) A->data;
406eb9c0419SKris Buschelman   Mat_SeqAIJ *p  = (Mat_SeqAIJ *) P->data;
407eb9c0419SKris Buschelman   Mat_SeqAIJ *c  = (Mat_SeqAIJ *) C->data;
408f4a850bbSBarry Smith   int        *ai=a->i,*aj=a->j,*pi=p->i,*pj=p->j,*pJ=p->j,*pjj;
409eb9c0419SKris Buschelman   int        *ci=c->i,*cj=c->j,*cjj;
410eb9c0419SKris Buschelman   int        am=A->M,cn=C->N,cm=C->M;
411eb9c0419SKris Buschelman   int        i,j,k,anzi,pnzi,apnzj,nextap,pnzj,prow,crow;
412eb9c0419SKris Buschelman   MatScalar  *aa=a->a,*apa,*pa=p->a,*pA=p->a,*paj,*ca=c->a,*caj;
413f747e1aeSHong Zhang   Mat_PtAPstruct *ptap=(Mat_PtAPstruct*)C->spptr;
414f747e1aeSHong Zhang   Mat_SeqAIJ     *ap = (Mat_SeqAIJ *)(ptap->symAP)->data;
415f747e1aeSHong Zhang   int            *api=ap->i,*apj=ap->j,apj_nextap;
416eb9c0419SKris Buschelman 
417eb9c0419SKris Buschelman   PetscFunctionBegin;
418eb9c0419SKris Buschelman   /* Allocate temporary array for storage of one row of A*P */
419f747e1aeSHong Zhang   ierr = PetscMalloc(cn*sizeof(MatScalar),&apa);CHKERRQ(ierr);
420f747e1aeSHong Zhang   ierr = PetscMemzero(apa,cn*sizeof(MatScalar));CHKERRQ(ierr);
421eb9c0419SKris Buschelman 
422eb9c0419SKris Buschelman   /* Clear old values in C */
423eb9c0419SKris Buschelman   ierr = PetscMemzero(ca,ci[cm]*sizeof(MatScalar));CHKERRQ(ierr);
424eb9c0419SKris Buschelman 
425eb9c0419SKris Buschelman   for (i=0;i<am;i++) {
426f747e1aeSHong Zhang     /* Get sparse values of A*P[i,:] */
427eb9c0419SKris Buschelman     anzi  = ai[i+1] - ai[i];
428eb9c0419SKris Buschelman     apnzj = 0;
429eb9c0419SKris Buschelman     for (j=0;j<anzi;j++) {
430eb9c0419SKris Buschelman       prow = *aj++;
431eb9c0419SKris Buschelman       pnzj = pi[prow+1] - pi[prow];
432eb9c0419SKris Buschelman       pjj  = pj + pi[prow];
433eb9c0419SKris Buschelman       paj  = pa + pi[prow];
434eb9c0419SKris Buschelman       for (k=0;k<pnzj;k++) {
435eb9c0419SKris Buschelman         apa[pjj[k]] += (*aa)*paj[k];
436eb9c0419SKris Buschelman       }
437eb9c0419SKris Buschelman       flops += 2*pnzj;
438eb9c0419SKris Buschelman       aa++;
439eb9c0419SKris Buschelman     }
440eb9c0419SKris Buschelman 
441eb9c0419SKris Buschelman     /* Compute P^T*A*P using outer product (P^T)[:,j]*(A*P)[j,:]. */
442f747e1aeSHong Zhang     apj   = ap->j + api[i];
443f747e1aeSHong Zhang     apnzj = api[i+1] - api[i];
444eb9c0419SKris Buschelman     pnzi  = pi[i+1] - pi[i];
445eb9c0419SKris Buschelman     for (j=0;j<pnzi;j++) {
446eb9c0419SKris Buschelman       nextap = 0;
447eb9c0419SKris Buschelman       crow   = *pJ++;
448eb9c0419SKris Buschelman       cjj    = cj + ci[crow];
449eb9c0419SKris Buschelman       caj    = ca + ci[crow];
450eb9c0419SKris Buschelman       /* Perform sparse axpy operation.  Note cjj includes apj. */
451eb9c0419SKris Buschelman       for (k=0; nextap<apnzj; k++) {
452f747e1aeSHong Zhang         apj_nextap = *(apj+nextap);
453f747e1aeSHong Zhang         if (cjj[k]==apj_nextap) {
454f747e1aeSHong Zhang           caj[k] += (*pA)*apa[apj_nextap];
455f747e1aeSHong Zhang           nextap++;
456eb9c0419SKris Buschelman         }
457eb9c0419SKris Buschelman       }
458eb9c0419SKris Buschelman       flops += 2*apnzj;
459eb9c0419SKris Buschelman       pA++;
460eb9c0419SKris Buschelman     }
461eb9c0419SKris Buschelman 
462f747e1aeSHong Zhang     /* Zero the current row values for A*P */
463f747e1aeSHong Zhang     for (j=0;j<apnzj;j++) apa[apj[j]] = 0.0;
464eb9c0419SKris Buschelman   }
465eb9c0419SKris Buschelman 
466eb9c0419SKris Buschelman   /* Assemble the final matrix and clean up */
467eb9c0419SKris Buschelman   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
468eb9c0419SKris Buschelman   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
469eb9c0419SKris Buschelman   ierr = PetscFree(apa);CHKERRQ(ierr);
470eb9c0419SKris Buschelman   ierr = PetscLogFlops(flops);CHKERRQ(ierr);
471eb9c0419SKris Buschelman 
472eb9c0419SKris Buschelman   PetscFunctionReturn(0);
473eb9c0419SKris Buschelman }
474eb9c0419SKris Buschelman 
475eb9c0419SKris Buschelman #undef __FUNCT__
4769af31e4aSHong Zhang #define __FUNCT__ "RegisterPtAPRoutines_Private"
477dfbe8321SBarry Smith PetscErrorCode RegisterPtAPRoutines_Private(Mat A)
478dfbe8321SBarry Smith {
479dfbe8321SBarry Smith   PetscErrorCode ierr;
480eb9c0419SKris Buschelman 
481eb9c0419SKris Buschelman   PetscFunctionBegin;
4825c66b693SKris Buschelman   ierr = RegisterMatMatMultRoutines_Private(A);CHKERRQ(ierr);
4839af31e4aSHong Zhang 
484eb9c0419SKris Buschelman   PetscFunctionReturn(0);
485eb9c0419SKris Buschelman }
486