xref: /petsc/src/mat/impls/aij/seq/matmatmult.c (revision cb00f4071c922a5916ef29698e67c15b1d98035d)
1d50806bdSBarry Smith /*
2a50f8bf6SHong Zhang   Defines matrix-matrix product routines for pairs of AIJ matrices
3d50806bdSBarry Smith           C = A * B
4d50806bdSBarry Smith */
5d50806bdSBarry Smith 
6c1f4806aSKris Buschelman #include "src/mat/impls/aij/seq/aij.h" /*I "petscmat.h" I*/
770f19b1fSKris Buschelman #include "src/mat/utils/freespace.h"
82d09714cSHong Zhang #include "src/mat/impls/aij/mpi/mpiaij.h"
9d50806bdSBarry Smith 
1026be0446SHong Zhang typedef struct { /* used by MatMatMult_MPIAIJ_MPIAIJ for reusing symbolic mat product */
1126be0446SHong Zhang   IS     isrowa,isrowb,iscolb;
1226be0446SHong Zhang   Mat    *aseq,*bseq,C_seq;
1326be0446SHong Zhang } Mat_MatMatMultMPI;
1426be0446SHong Zhang 
15c1f4806aSKris Buschelman #undef __FUNCT__
16c1f4806aSKris Buschelman #define __FUNCT__ "MatMatMult"
175c66b693SKris Buschelman /*@
185c66b693SKris Buschelman    MatMatMult - Performs Matrix-Matrix Multiplication C=A*B.
1994e3eecaSKris Buschelman 
205c66b693SKris Buschelman    Collective on Mat
21d50806bdSBarry Smith 
225c66b693SKris Buschelman    Input Parameters:
235c66b693SKris Buschelman +  A - the left matrix
241c741599SHong Zhang .  B - the right matrix
251c741599SHong Zhang .  scall - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX
26c5db241fSHong Zhang -  fill - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B))
275c66b693SKris Buschelman 
285c66b693SKris Buschelman    Output Parameters:
295c66b693SKris Buschelman .  C - the product matrix
305c66b693SKris Buschelman 
315c66b693SKris Buschelman    Notes:
325c66b693SKris Buschelman    C will be created and must be destroyed by the user with MatDestroy().
335c66b693SKris Buschelman 
344d3841fdSKris Buschelman    This routine is currently only implemented for pairs of SeqAIJ matrices and classes
354d3841fdSKris Buschelman    which inherit from SeqAIJ.  C will be of type MATSEQAIJ.
365c66b693SKris Buschelman 
375c66b693SKris Buschelman    Level: intermediate
385c66b693SKris Buschelman 
395c66b693SKris Buschelman .seealso: MatMatMultSymbolic(),MatMatMultNumeric()
405c66b693SKris Buschelman @*/
41dfbe8321SBarry Smith PetscErrorCode MatMatMult(Mat A,Mat B,MatReuse scall,PetscReal fill,Mat *C)
422d09714cSHong Zhang {
43dfbe8321SBarry Smith   PetscErrorCode ierr;
44*cb00f407SKris Buschelman   PetscErrorCode (*fA)(Mat,Mat,MatReuse,PetscReal,Mat*);
45*cb00f407SKris Buschelman   PetscErrorCode (*fB)(Mat,Mat,MatReuse,PetscReal,Mat*);
462d09714cSHong Zhang 
47d50806bdSBarry Smith   PetscFunctionBegin;
484482741eSBarry Smith   PetscValidHeaderSpecific(A,MAT_COOKIE,1);
49c9780b6fSBarry Smith   PetscValidType(A,1);
505c66b693SKris Buschelman   MatPreallocated(A);
515c66b693SKris Buschelman   if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
525c66b693SKris Buschelman   if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
534482741eSBarry Smith   PetscValidHeaderSpecific(B,MAT_COOKIE,2);
54c9780b6fSBarry Smith   PetscValidType(B,2);
555c66b693SKris Buschelman   MatPreallocated(B);
565c66b693SKris Buschelman   if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
575c66b693SKris Buschelman   if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
584482741eSBarry Smith   PetscValidPointer(C,3);
595c66b693SKris Buschelman   if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N);
60d50806bdSBarry Smith 
611c24bd37SHong Zhang   if (fill <=0.0) SETERRQ1(PETSC_ERR_ARG_SIZ,"fill=%g must be > 0.0",fill);
62c5db241fSHong Zhang 
63*cb00f407SKris Buschelman   /* For now, we do not dispatch based on the type of A and B */
64*cb00f407SKris Buschelman   /* When implementations like _SeqAIJ_MAIJ exist, attack the multiple dispatch problem. */
65*cb00f407SKris Buschelman   fA = A->ops->matmult;
66*cb00f407SKris Buschelman   if (!fA) SETERRQ1(PETSC_ERR_SUP,"MatMatMult not supported for A of type %s",A->type_name);
67*cb00f407SKris Buschelman   fB = B->ops->matmult;
68*cb00f407SKris Buschelman   if (!fB) SETERRQ1(PETSC_ERR_SUP,"MatMatMult not supported for B of type %s",B->type_name);
69*cb00f407SKris Buschelman   if (fB!=fA) SETERRQ2(PETSC_ERR_ARG_INCOMP,"MatMatMult requires A, %s, to be compatible with B, %s",A->type_name,B->type_name);
70*cb00f407SKris Buschelman 
716284ec50SHong Zhang   ierr = PetscLogEventBegin(MAT_MatMult,A,B,0,0);CHKERRQ(ierr);
721c741599SHong Zhang   ierr = (*A->ops->matmult)(A,B,scall,fill,C);CHKERRQ(ierr);
736284ec50SHong Zhang   ierr = PetscLogEventEnd(MAT_MatMult,A,B,0,0);CHKERRQ(ierr);
744d3841fdSKris Buschelman 
756284ec50SHong Zhang   PetscFunctionReturn(0);
766284ec50SHong Zhang }
776284ec50SHong Zhang 
786284ec50SHong Zhang #undef __FUNCT__
796284ec50SHong Zhang #define __FUNCT__ "MatMatMult_MPIAIJ_MPIAIJ"
80dfbe8321SBarry Smith PetscErrorCode MatMatMult_MPIAIJ_MPIAIJ(Mat A,Mat B,MatReuse scall,PetscReal fill, Mat *C)
812d09714cSHong Zhang {
82dfbe8321SBarry Smith   PetscErrorCode ierr;
836284ec50SHong Zhang 
846284ec50SHong Zhang   PetscFunctionBegin;
8526be0446SHong Zhang   if (scall == MAT_INITIAL_MATRIX){
86d6bb3c2dSHong Zhang     ierr = MatMatMultSymbolic_MPIAIJ_MPIAIJ(A,B,fill,C);CHKERRQ(ierr);/* numeric product is computed as well */
87d6bb3c2dSHong Zhang   } else if (scall == MAT_REUSE_MATRIX){
8826be0446SHong Zhang     ierr = MatMatMultNumeric_MPIAIJ_MPIAIJ(A,B,*C);CHKERRQ(ierr);
89d6bb3c2dSHong Zhang   } else {
90d6bb3c2dSHong Zhang     SETERRQ1(PETSC_ERR_ARG_WRONG,"Invalid MatReuse %d",scall);
91d6bb3c2dSHong Zhang   }
92d50806bdSBarry Smith   PetscFunctionReturn(0);
93d50806bdSBarry Smith }
945c66b693SKris Buschelman 
955c66b693SKris Buschelman #undef __FUNCT__
965c66b693SKris Buschelman #define __FUNCT__ "MatMatMult_SeqAIJ_SeqAIJ"
97dfbe8321SBarry Smith PetscErrorCode MatMatMult_SeqAIJ_SeqAIJ(Mat A,Mat B,MatReuse scall,PetscReal fill,Mat *C) {
98dfbe8321SBarry Smith   PetscErrorCode ierr;
995c66b693SKris Buschelman 
1005c66b693SKris Buschelman   PetscFunctionBegin;
10126be0446SHong Zhang   if (scall == MAT_INITIAL_MATRIX){
10226be0446SHong Zhang     ierr = MatMatMultSymbolic_SeqAIJ_SeqAIJ(A,B,fill,C);CHKERRQ(ierr);
10326be0446SHong Zhang   }
10426be0446SHong Zhang   ierr = MatMatMultNumeric_SeqAIJ_SeqAIJ(A,B,*C);CHKERRQ(ierr);
1055c66b693SKris Buschelman   PetscFunctionReturn(0);
1065c66b693SKris Buschelman }
1075c66b693SKris Buschelman 
108c1f4806aSKris Buschelman #undef __FUNCT__
109c1f4806aSKris Buschelman #define __FUNCT__ "MatMatMultSymbolic"
1105c66b693SKris Buschelman /*@
1115c66b693SKris Buschelman    MatMatMultSymbolic - Performs construction, preallocation, and computes the ij structure
1125c66b693SKris Buschelman    of the matrix-matrix product C=A*B.  Call this routine before calling MatMatMultNumeric().
1135c66b693SKris Buschelman 
1145c66b693SKris Buschelman    Collective on Mat
1155c66b693SKris Buschelman 
1165c66b693SKris Buschelman    Input Parameters:
1175c66b693SKris Buschelman +  A - the left matrix
118c5db241fSHong Zhang .  B - the right matrix
119c5db241fSHong Zhang -  fill - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B))
1205c66b693SKris Buschelman 
1215c66b693SKris Buschelman    Output Parameters:
1225c66b693SKris Buschelman .  C - the matrix containing the ij structure of product matrix
1235c66b693SKris Buschelman 
1245c66b693SKris Buschelman    Notes:
1254d3841fdSKris Buschelman    C will be created as a MATSEQAIJ matrix and must be destroyed by the user with MatDestroy().
1265c66b693SKris Buschelman 
1274d3841fdSKris Buschelman    This routine is currently only implemented for SeqAIJ matrices and classes which inherit from SeqAIJ.
1285c66b693SKris Buschelman 
1295c66b693SKris Buschelman    Level: intermediate
1305c66b693SKris Buschelman 
1315c66b693SKris Buschelman .seealso: MatMatMult(),MatMatMultNumeric()
1325c66b693SKris Buschelman @*/
133dfbe8321SBarry Smith PetscErrorCode MatMatMultSymbolic(Mat A,Mat B,PetscReal fill,Mat *C) {
134dfbe8321SBarry Smith   PetscErrorCode ierr;
135*cb00f407SKris Buschelman   PetscErrorCode (*Asymbolic)(Mat,Mat,PetscReal,Mat *);
136*cb00f407SKris Buschelman   PetscErrorCode (*Bsymbolic)(Mat,Mat,PetscReal,Mat *);
1375c66b693SKris Buschelman 
1385c66b693SKris Buschelman   PetscFunctionBegin;
1394482741eSBarry Smith   PetscValidHeaderSpecific(A,MAT_COOKIE,1);
140c9780b6fSBarry Smith   PetscValidType(A,1);
1415c66b693SKris Buschelman   MatPreallocated(A);
1425c66b693SKris Buschelman   if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1435c66b693SKris Buschelman   if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1445c66b693SKris Buschelman 
1454482741eSBarry Smith   PetscValidHeaderSpecific(B,MAT_COOKIE,2);
146c9780b6fSBarry Smith   PetscValidType(B,2);
1475c66b693SKris Buschelman   MatPreallocated(B);
1485c66b693SKris Buschelman   if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
1495c66b693SKris Buschelman   if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
1504482741eSBarry Smith   PetscValidPointer(C,3);
1514482741eSBarry Smith 
1525c66b693SKris Buschelman   if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N);
1531c24bd37SHong Zhang   if (fill <=0.0) SETERRQ1(PETSC_ERR_ARG_SIZ,"fill=%g must be > 0.0",fill);
1545c66b693SKris Buschelman 
155*cb00f407SKris Buschelman   /* For now, we do not dispatch based on the type of A and P */
156*cb00f407SKris Buschelman   /* When implementations like _SeqAIJ_MAIJ exist, attack the multiple dispatch problem. */
157*cb00f407SKris Buschelman   Asymbolic = A->ops->matmultsymbolic;
158*cb00f407SKris Buschelman   if (!Asymbolic) SETERRQ1(PETSC_ERR_SUP,"C=A*B not implemented for A of type %s",A->type_name);
159*cb00f407SKris Buschelman   Bsymbolic = B->ops->matmultsymbolic;
160*cb00f407SKris Buschelman   if (!Bsymbolic) SETERRQ1(PETSC_ERR_SUP,"C=A*B not implemented for B of type %s",B->type_name);
161*cb00f407SKris Buschelman   if (Bsymbolic!=Asymbolic) SETERRQ2(PETSC_ERR_ARG_INCOMP,"MatMatMultSymbolic requires A, %s, to be compatible with B, %s",A->type_name,B->type_name);
162*cb00f407SKris Buschelman 
163*cb00f407SKris Buschelman   ierr = PetscLogEventBegin(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr);
164*cb00f407SKris Buschelman   ierr = (*Asymbolic)(A,B,fill,C);CHKERRQ(ierr);
165*cb00f407SKris Buschelman   ierr = PetscLogEventEnd(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr);
1665c66b693SKris Buschelman 
1675c66b693SKris Buschelman   PetscFunctionReturn(0);
1685c66b693SKris Buschelman }
1691c24bd37SHong Zhang 
170dfbe8321SBarry Smith EXTERN PetscErrorCode MatDestroy_MPIAIJ(Mat);
17126be0446SHong Zhang #undef __FUNCT__
17226be0446SHong Zhang #define __FUNCT__ "MatDestroy_MPIAIJ_MatMatMult"
173dfbe8321SBarry Smith PetscErrorCode MatDestroy_MPIAIJ_MatMatMult(Mat A)
17426be0446SHong Zhang {
175dfbe8321SBarry Smith   PetscErrorCode ierr;
17626be0446SHong Zhang   Mat_MatMatMultMPI *mult=(Mat_MatMatMultMPI*)A->spptr;
17726be0446SHong Zhang 
17826be0446SHong Zhang   PetscFunctionBegin;
179d6bb3c2dSHong Zhang   ierr = ISDestroy(mult->isrowb);CHKERRQ(ierr);
180d6bb3c2dSHong Zhang   ierr = ISDestroy(mult->iscolb);CHKERRQ(ierr);
181d6bb3c2dSHong Zhang   ierr = ISDestroy(mult->isrowa);CHKERRQ(ierr);
182d6bb3c2dSHong Zhang   ierr = MatDestroyMatrices(1,&mult->aseq);CHKERRQ(ierr);
183d6bb3c2dSHong Zhang   ierr = MatDestroyMatrices(1,&mult->bseq);CHKERRQ(ierr);
184d6bb3c2dSHong Zhang   ierr = MatDestroy(mult->C_seq);CHKERRQ(ierr);
18526be0446SHong Zhang   ierr = PetscFree(mult);CHKERRQ(ierr);
186d6bb3c2dSHong Zhang 
18726be0446SHong Zhang   ierr = MatDestroy_MPIAIJ(A);CHKERRQ(ierr);
18826be0446SHong Zhang 
18926be0446SHong Zhang   PetscFunctionReturn(0);
19026be0446SHong Zhang }
19158c24d83SHong Zhang 
19258c24d83SHong Zhang #undef __FUNCT__
19326be0446SHong Zhang #define __FUNCT__ "MatMatMultSymbolic_MPIAIJ_MPIAIJ"
194dfbe8321SBarry Smith PetscErrorCode MatMatMultSymbolic_MPIAIJ_MPIAIJ(Mat A,Mat B,PetscReal fill,Mat *C)
19526be0446SHong Zhang {
19626be0446SHong Zhang   Mat_MPIAIJ        *a = (Mat_MPIAIJ*)A->data;
197dfbe8321SBarry Smith   PetscErrorCode ierr;
198dfbe8321SBarry Smith   int               *idx,i,start,end,ncols,imark,nzA,nzB,*cmap;
19926be0446SHong Zhang   Mat_MatMatMultMPI *mult;
20026be0446SHong Zhang 
20126be0446SHong Zhang   PetscFunctionBegin;
202d6bb3c2dSHong Zhang   ierr = PetscNew(Mat_MatMatMultMPI,&mult);CHKERRQ(ierr);
203d6bb3c2dSHong Zhang 
20426be0446SHong Zhang   /* create a seq matrix B_seq = submatrix of B by taking rows of B that equal to nonzero col of A */
20526be0446SHong Zhang   start = a->cstart;
20626be0446SHong Zhang   cmap  = a->garray;
20726be0446SHong Zhang   nzA   = a->A->n;
20826be0446SHong Zhang   nzB   = a->B->n;
20926be0446SHong Zhang   ierr  = PetscMalloc((nzA+nzB)*sizeof(int), &idx);CHKERRQ(ierr);
21026be0446SHong Zhang   ncols = 0;
21126be0446SHong Zhang   for (i=0; i<nzB; i++) {
21226be0446SHong Zhang     if (cmap[i] < start) idx[ncols++] = cmap[i];
21326be0446SHong Zhang     else break;
21426be0446SHong Zhang   }
21526be0446SHong Zhang   imark = i;
21626be0446SHong Zhang   for (i=0; i<nzA; i++) idx[ncols++] = start + i;
21726be0446SHong Zhang   for (i=imark; i<nzB; i++) idx[ncols++] = cmap[i];
218d6bb3c2dSHong Zhang   ierr = ISCreateGeneral(PETSC_COMM_SELF,ncols,idx,&mult->isrowb);CHKERRQ(ierr);
21926be0446SHong Zhang   ierr = PetscFree(idx);CHKERRQ(ierr);
220d6bb3c2dSHong Zhang   ierr = ISCreateStride(PETSC_COMM_SELF,B->N,0,1,&mult->iscolb);CHKERRQ(ierr);
221d6bb3c2dSHong Zhang   ierr = MatGetSubMatrices(B,1,&mult->isrowb,&mult->iscolb,MAT_INITIAL_MATRIX,&mult->bseq);CHKERRQ(ierr)
22226be0446SHong Zhang 
22326be0446SHong Zhang   /*  create a seq matrix A_seq = submatrix of A by taking all local rows of A */
22426be0446SHong Zhang   start = a->rstart; end = a->rend;
225d6bb3c2dSHong Zhang   ierr = ISCreateStride(PETSC_COMM_SELF,end-start,start,1,&mult->isrowa);CHKERRQ(ierr);
226d6bb3c2dSHong Zhang   ierr = MatGetSubMatrices(A,1,&mult->isrowa,&mult->isrowb,MAT_INITIAL_MATRIX,&mult->aseq);CHKERRQ(ierr);
22726be0446SHong Zhang 
22826be0446SHong Zhang   /* compute C_seq = A_seq * B_seq */
229d6bb3c2dSHong Zhang   ierr = MatMatMult_SeqAIJ_SeqAIJ(mult->aseq[0],mult->bseq[0],MAT_INITIAL_MATRIX,fill,&mult->C_seq);CHKERRQ(ierr);
23026be0446SHong Zhang 
23126be0446SHong Zhang   /* create mpi matrix C by concatinating C_seq */
232d6bb3c2dSHong Zhang   ierr = PetscObjectReference((PetscObject)mult->C_seq);CHKERRQ(ierr); /* prevent C_seq being destroyed by MatMerge() */
233d6bb3c2dSHong Zhang   ierr = MatMerge(A->comm,mult->C_seq,MAT_INITIAL_MATRIX,C);CHKERRQ(ierr);
23426be0446SHong Zhang 
23526be0446SHong Zhang   /* attach the supporting struct to C for reuse of symbolic C */
23626be0446SHong Zhang   (*C)->spptr         = (void*)mult;
23726be0446SHong Zhang   (*C)->ops->destroy  = MatDestroy_MPIAIJ_MatMatMult;
23826be0446SHong Zhang 
23926be0446SHong Zhang   PetscFunctionReturn(0);
24026be0446SHong Zhang }
24126be0446SHong Zhang 
24226be0446SHong Zhang #undef __FUNCT__
24326be0446SHong Zhang #define __FUNCT__ "MatMatMultSymbolic_SeqAIJ_SeqAIJ"
244dfbe8321SBarry Smith PetscErrorCode MatMatMultSymbolic_SeqAIJ_SeqAIJ(Mat A,Mat B,PetscReal fill,Mat *C)
24558c24d83SHong Zhang {
246dfbe8321SBarry Smith   PetscErrorCode ierr;
24758c24d83SHong Zhang   FreeSpaceList  free_space=PETSC_NULL,current_space=PETSC_NULL;
24858c24d83SHong Zhang   Mat_SeqAIJ     *a=(Mat_SeqAIJ*)A->data,*b=(Mat_SeqAIJ*)B->data,*c;
24958c24d83SHong Zhang   int            *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j,*bjj;
2501c24bd37SHong Zhang   int            *ci,*cj,*lnk;
2515c66b693SKris Buschelman   int            am=A->M,bn=B->N,bm=B->M;
252c5db241fSHong Zhang   int            i,j,anzi,brow,bnzj,cnzi,nlnk,lnk_init=-1,nspacedouble=0;
25358c24d83SHong Zhang   MatScalar      *ca;
25458c24d83SHong Zhang 
25558c24d83SHong Zhang   PetscFunctionBegin;
25658c24d83SHong Zhang   /* Set up */
25758c24d83SHong Zhang   /* Allocate ci array, arrays for fill computation and */
25858c24d83SHong Zhang   /* free space for accumulating nonzero column info */
25958c24d83SHong Zhang   ierr = PetscMalloc(((am+1)+1)*sizeof(int),&ci);CHKERRQ(ierr);
26058c24d83SHong Zhang   ci[0] = 0;
26158c24d83SHong Zhang 
26258c24d83SHong Zhang   ierr = PetscMalloc((bn+1)*sizeof(int),&lnk);CHKERRQ(ierr);
263f747e1aeSHong Zhang   nlnk = bn+1;
264f747e1aeSHong Zhang   ierr = PetscLLInitialize(lnk_init,nlnk,lnk);CHKERRQ(ierr);
26558c24d83SHong Zhang 
266c5db241fSHong Zhang   /* Initial FreeSpace size is fill*(nnz(A)+nnz(B)) */
267d6bb3c2dSHong Zhang   ierr = GetMoreSpace((int)(fill*(ai[am]+bi[bm])),&free_space);CHKERRQ(ierr);
26858c24d83SHong Zhang   current_space = free_space;
26958c24d83SHong Zhang 
27058c24d83SHong Zhang   /* Determine symbolic info for each row of the product: */
27158c24d83SHong Zhang   for (i=0;i<am;i++) {
27258c24d83SHong Zhang     anzi = ai[i+1] - ai[i];
27358c24d83SHong Zhang     cnzi = 0;
27458c24d83SHong Zhang     lnk[bn] = bn;
2752d09714cSHong Zhang     j       = anzi;
2762d09714cSHong Zhang     aj      = a->j + ai[i];
2772d09714cSHong Zhang     while (j){/* assume cols are almost in increasing order, starting from its end saves computation */
2782d09714cSHong Zhang       j--;
2792d09714cSHong Zhang       brow = *(aj + j);
28058c24d83SHong Zhang       bnzj = bi[brow+1] - bi[brow];
28158c24d83SHong Zhang       bjj  = bj + bi[brow];
2821c239cc6SHong Zhang       /* add non-zero cols of B into the sorted linked list lnk */
28345a8bf62SHong Zhang       ierr = PetscLLAdd(bnzj,bjj,bn,lnk_init,nlnk,lnk);CHKERRQ(ierr);
2841c239cc6SHong Zhang       cnzi += nlnk;
28558c24d83SHong Zhang     }
28658c24d83SHong Zhang 
28758c24d83SHong Zhang     /* If free space is not available, make more free space */
28858c24d83SHong Zhang     /* Double the amount of total space in the list */
28958c24d83SHong Zhang     if (current_space->local_remaining<cnzi) {
29026be0446SHong Zhang       /* printf("MatMatMultSymbolic_SeqAIJ_SeqAIJ()...%d -th row, double space ...\n",i);*/
29158c24d83SHong Zhang       ierr = GetMoreSpace(current_space->total_array_size,&current_space);CHKERRQ(ierr);
292c5db241fSHong Zhang       nspacedouble++;
29358c24d83SHong Zhang     }
29458c24d83SHong Zhang 
295c5db241fSHong Zhang     /* Copy data into free space, then initialize lnk */
29645a8bf62SHong Zhang     ierr = PetscLLClear(bn,lnk_init,cnzi,lnk,current_space->array);CHKERRQ(ierr);
297c5db241fSHong Zhang     current_space->array += cnzi;
29858c24d83SHong Zhang 
29958c24d83SHong Zhang     current_space->local_used      += cnzi;
30058c24d83SHong Zhang     current_space->local_remaining -= cnzi;
30158c24d83SHong Zhang 
30258c24d83SHong Zhang     ci[i+1] = ci[i] + cnzi;
30358c24d83SHong Zhang   }
30458c24d83SHong Zhang 
30558c24d83SHong Zhang   /* Column indices are in the list of free space */
30658c24d83SHong Zhang   /* Allocate space for cj, initialize cj, and */
30758c24d83SHong Zhang   /* destroy list of free space and other temporary array(s) */
30858c24d83SHong Zhang   ierr = PetscMalloc((ci[am]+1)*sizeof(int),&cj);CHKERRQ(ierr);
30958c24d83SHong Zhang   ierr = MakeSpaceContiguous(&free_space,cj);CHKERRQ(ierr);
31058c24d83SHong Zhang   ierr = PetscFree(lnk);CHKERRQ(ierr);
31158c24d83SHong Zhang 
31258c24d83SHong Zhang   /* Allocate space for ca */
31358c24d83SHong Zhang   ierr = PetscMalloc((ci[am]+1)*sizeof(MatScalar),&ca);CHKERRQ(ierr);
31458c24d83SHong Zhang   ierr = PetscMemzero(ca,(ci[am]+1)*sizeof(MatScalar));CHKERRQ(ierr);
31558c24d83SHong Zhang 
31626be0446SHong Zhang   /* put together the new symbolic matrix */
31758c24d83SHong Zhang   ierr = MatCreateSeqAIJWithArrays(A->comm,am,bn,ci,cj,ca,C);CHKERRQ(ierr);
31858c24d83SHong Zhang 
31958c24d83SHong Zhang   /* MatCreateSeqAIJWithArrays flags matrix so PETSc doesn't free the user's arrays. */
32058c24d83SHong Zhang   /* These are PETSc arrays, so change flags so arrays can be deleted by PETSc */
32158c24d83SHong Zhang   c = (Mat_SeqAIJ *)((*C)->data);
32258c24d83SHong Zhang   c->freedata = PETSC_TRUE;
32358c24d83SHong Zhang   c->nonew    = 0;
32458c24d83SHong Zhang 
325c5db241fSHong Zhang   PetscLogInfo((PetscObject)(*C),"Number of calls to GetMoreSpace(): %d\n",nspacedouble);
32658c24d83SHong Zhang   PetscFunctionReturn(0);
32758c24d83SHong Zhang }
328d50806bdSBarry Smith 
329c1f4806aSKris Buschelman #undef __FUNCT__
330c1f4806aSKris Buschelman #define __FUNCT__ "MatMatMultNumeric"
3315c66b693SKris Buschelman /*@
3325c66b693SKris Buschelman    MatMatMultNumeric - Performs the numeric matrix-matrix product.
3335c66b693SKris Buschelman    Call this routine after first calling MatMatMultSymbolic().
3345c66b693SKris Buschelman 
3355c66b693SKris Buschelman    Collective on Mat
3365c66b693SKris Buschelman 
3375c66b693SKris Buschelman    Input Parameters:
3385c66b693SKris Buschelman +  A - the left matrix
3395c66b693SKris Buschelman -  B - the right matrix
3405c66b693SKris Buschelman 
3415c66b693SKris Buschelman    Output Parameters:
3425c66b693SKris Buschelman .  C - the product matrix, whose ij structure was defined from MatMatMultSymbolic().
3435c66b693SKris Buschelman 
3445c66b693SKris Buschelman    Notes:
3455c66b693SKris Buschelman    C must have been created with MatMatMultSymbolic.
3465c66b693SKris Buschelman 
3475c66b693SKris Buschelman    This routine is currently only implemented for SeqAIJ type matrices.
3485c66b693SKris Buschelman 
3495c66b693SKris Buschelman    Level: intermediate
3505c66b693SKris Buschelman 
3515c66b693SKris Buschelman .seealso: MatMatMult(),MatMatMultSymbolic()
3525c66b693SKris Buschelman @*/
353dfbe8321SBarry Smith PetscErrorCode MatMatMultNumeric(Mat A,Mat B,Mat C){
354dfbe8321SBarry Smith   PetscErrorCode ierr;
355*cb00f407SKris Buschelman   PetscErrorCode (*Anumeric)(Mat,Mat,Mat);
356*cb00f407SKris Buschelman   PetscErrorCode (*Bnumeric)(Mat,Mat,Mat);
3575c66b693SKris Buschelman 
3585c66b693SKris Buschelman   PetscFunctionBegin;
3595c66b693SKris Buschelman 
3604482741eSBarry Smith   PetscValidHeaderSpecific(A,MAT_COOKIE,1);
361c9780b6fSBarry Smith   PetscValidType(A,1);
3625c66b693SKris Buschelman   MatPreallocated(A);
3635c66b693SKris Buschelman   if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
3645c66b693SKris Buschelman   if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
3655c66b693SKris Buschelman 
3664482741eSBarry Smith   PetscValidHeaderSpecific(B,MAT_COOKIE,2);
367c9780b6fSBarry Smith   PetscValidType(B,2);
3685c66b693SKris Buschelman   MatPreallocated(B);
3695c66b693SKris Buschelman   if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
3705c66b693SKris Buschelman   if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
3715c66b693SKris Buschelman 
3724482741eSBarry Smith   PetscValidHeaderSpecific(C,MAT_COOKIE,3);
373c9780b6fSBarry Smith   PetscValidType(C,3);
3745c66b693SKris Buschelman   MatPreallocated(C);
3755c66b693SKris Buschelman   if (!C->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
3765c66b693SKris Buschelman   if (C->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
3775c66b693SKris Buschelman 
3785c66b693SKris Buschelman   if (B->N!=C->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->N,C->N);
3795c66b693SKris Buschelman   if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N);
3805c66b693SKris Buschelman   if (A->M!=C->M) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",A->M,C->M);
3815c66b693SKris Buschelman 
382*cb00f407SKris Buschelman   /* For now, we do not dispatch based on the type of A and B */
383*cb00f407SKris Buschelman   /* When implementations like _SeqAIJ_MAIJ exist, attack the multiple dispatch problem. */
384*cb00f407SKris Buschelman   Anumeric = A->ops->matmultnumeric;
385*cb00f407SKris Buschelman   if (!Anumeric) SETERRQ1(PETSC_ERR_SUP,"MatMatMultNumeric not supported for A of type %s",A->type_name);
386*cb00f407SKris Buschelman   Bnumeric = B->ops->matmultnumeric;
387*cb00f407SKris Buschelman   if (!Bnumeric) SETERRQ1(PETSC_ERR_SUP,"MatMatMultNumeric not supported for B of type %s",B->type_name);
388*cb00f407SKris Buschelman   if (Bnumeric!=Anumeric) SETERRQ2(PETSC_ERR_ARG_INCOMP,"MatMatMultNumeric requires A, %s, to be compatible with B, %s",A->type_name,B->type_name);
3894d3841fdSKris Buschelman 
390*cb00f407SKris Buschelman   ierr = PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
391*cb00f407SKris Buschelman   ierr = (*Anumeric)(A,B,C);CHKERRQ(ierr);
392*cb00f407SKris Buschelman   ierr = PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
3935c66b693SKris Buschelman 
3945c66b693SKris Buschelman   PetscFunctionReturn(0);
3955c66b693SKris Buschelman }
3965c66b693SKris Buschelman 
397d6bb3c2dSHong Zhang /* This routine is called ONLY in the case of reusing previously computed symbolic C */
398d50806bdSBarry Smith #undef __FUNCT__
39926be0446SHong Zhang #define __FUNCT__ "MatMatMultNumeric_MPIAIJ_MPIAIJ"
400dfbe8321SBarry Smith PetscErrorCode MatMatMultNumeric_MPIAIJ_MPIAIJ(Mat A,Mat B,Mat C)
40126be0446SHong Zhang {
402dfbe8321SBarry Smith   PetscErrorCode ierr;
403d6bb3c2dSHong Zhang   Mat_MatMatMultMPI *mult=(Mat_MatMatMultMPI*)C->spptr;
404d6bb3c2dSHong Zhang 
40526be0446SHong Zhang   PetscFunctionBegin;
406d6bb3c2dSHong Zhang   ierr = MatGetSubMatrices(B,1,&mult->isrowb,&mult->iscolb,MAT_REUSE_MATRIX,&mult->bseq);CHKERRQ(ierr)
407d6bb3c2dSHong Zhang   ierr = MatGetSubMatrices(A,1,&mult->isrowa,&mult->isrowb,MAT_REUSE_MATRIX,&mult->aseq);CHKERRQ(ierr);
408d6bb3c2dSHong Zhang   ierr = MatMatMult_SeqAIJ_SeqAIJ(mult->aseq[0],mult->bseq[0],MAT_REUSE_MATRIX,0.0,&mult->C_seq);CHKERRQ(ierr);
409d6bb3c2dSHong Zhang 
410d6bb3c2dSHong Zhang   ierr = PetscObjectReference((PetscObject)mult->C_seq);CHKERRQ(ierr);
411d6bb3c2dSHong Zhang   ierr = MatMerge(A->comm,mult->C_seq,MAT_REUSE_MATRIX,&C);CHKERRQ(ierr);
412d6bb3c2dSHong Zhang 
41326be0446SHong Zhang   PetscFunctionReturn(0);
41426be0446SHong Zhang }
41526be0446SHong Zhang 
41626be0446SHong Zhang #undef __FUNCT__
41726be0446SHong Zhang #define __FUNCT__ "MatMatMultNumeric_SeqAIJ_SeqAIJ"
418dfbe8321SBarry Smith PetscErrorCode MatMatMultNumeric_SeqAIJ_SeqAIJ(Mat A,Mat B,Mat C)
419d50806bdSBarry Smith {
420dfbe8321SBarry Smith   PetscErrorCode ierr;
421dfbe8321SBarry Smith   int        flops=0;
422d50806bdSBarry Smith   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
423d50806bdSBarry Smith   Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data;
424d50806bdSBarry Smith   Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data;
425d50806bdSBarry Smith   int        *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j,*bjj,*ci=c->i,*cj=c->j;
4265c66b693SKris Buschelman   int        am=A->M,cn=C->N;
42794e3eecaSKris Buschelman   int        i,j,k,anzi,bnzi,cnzi,brow;
428d50806bdSBarry Smith   MatScalar  *aa=a->a,*ba=b->a,*baj,*ca=c->a,*temp;
429d50806bdSBarry Smith 
430d50806bdSBarry Smith   PetscFunctionBegin;
431d50806bdSBarry Smith 
432d50806bdSBarry Smith   /* Allocate temp accumulation space to avoid searching for nonzero columns in C */
433d50806bdSBarry Smith   ierr = PetscMalloc((cn+1)*sizeof(MatScalar),&temp);CHKERRQ(ierr);
434d50806bdSBarry Smith   ierr = PetscMemzero(temp,cn*sizeof(MatScalar));CHKERRQ(ierr);
435d50806bdSBarry Smith   /* Traverse A row-wise. */
436d50806bdSBarry Smith   /* Build the ith row in C by summing over nonzero columns in A, */
437d50806bdSBarry Smith   /* the rows of B corresponding to nonzeros of A. */
438d50806bdSBarry Smith   for (i=0;i<am;i++) {
439d50806bdSBarry Smith     anzi = ai[i+1] - ai[i];
440d50806bdSBarry Smith     for (j=0;j<anzi;j++) {
441d50806bdSBarry Smith       brow = *aj++;
442d50806bdSBarry Smith       bnzi = bi[brow+1] - bi[brow];
443d50806bdSBarry Smith       bjj  = bj + bi[brow];
444d50806bdSBarry Smith       baj  = ba + bi[brow];
445d50806bdSBarry Smith       for (k=0;k<bnzi;k++) {
446d50806bdSBarry Smith         temp[bjj[k]] += (*aa)*baj[k];
447d50806bdSBarry Smith       }
448d50806bdSBarry Smith       flops += 2*bnzi;
449d50806bdSBarry Smith       aa++;
450d50806bdSBarry Smith     }
451d50806bdSBarry Smith     /* Store row back into C, and re-zero temp */
452d50806bdSBarry Smith     cnzi = ci[i+1] - ci[i];
453d50806bdSBarry Smith     for (j=0;j<cnzi;j++) {
454d50806bdSBarry Smith       ca[j] = temp[cj[j]];
455d50806bdSBarry Smith       temp[cj[j]] = 0.0;
456d50806bdSBarry Smith     }
457d50806bdSBarry Smith     ca += cnzi;
458d50806bdSBarry Smith     cj += cnzi;
459d50806bdSBarry Smith   }
460716bacf3SKris Buschelman   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
461716bacf3SKris Buschelman   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
462716bacf3SKris Buschelman 
463d50806bdSBarry Smith   /* Free temp */
464d50806bdSBarry Smith   ierr = PetscFree(temp);CHKERRQ(ierr);
465d50806bdSBarry Smith   ierr = PetscLogFlops(flops);CHKERRQ(ierr);
466d50806bdSBarry Smith   PetscFunctionReturn(0);
467d50806bdSBarry Smith }
468d50806bdSBarry Smith 
469d50806bdSBarry Smith #undef __FUNCT__
4705c66b693SKris Buschelman #define __FUNCT__ "RegisterMatMatMultRoutines_Private"
471dfbe8321SBarry Smith PetscErrorCode RegisterMatMatMultRoutines_Private(Mat A)
472dfbe8321SBarry Smith {
473dfbe8321SBarry Smith   PetscErrorCode ierr;
474d50806bdSBarry Smith 
475d50806bdSBarry Smith   PetscFunctionBegin;
47694e3eecaSKris Buschelman   PetscFunctionReturn(0);
47794e3eecaSKris Buschelman }
478