xref: /petsc/src/mat/impls/aij/seq/matmatmult.c (revision 4482741e5b2e2bbc854fb1f8dba65221386520f2)
1 /*$Id: matmatmult.c,v 1.15 2001/09/07 20:04:44 buschelm Exp $*/
2 /*
3   Defines matrix-matrix product routines for pairs of SeqAIJ matrices
4           C = A * B
5 */
6 
7 #include "src/mat/impls/aij/seq/aij.h" /*I "petscmat.h" I*/
8 #include "src/mat/utils/freespace.h"
9 
10 static int logkey_matmatmult          = 0;
11 static int logkey_matmatmult_symbolic = 0;
12 static int logkey_matmatmult_numeric  = 0;
13 
14 #undef __FUNCT__
15 #define __FUNCT__ "MatMatMult"
16 /*@
17    MatMatMult - Performs Matrix-Matrix Multiplication C=A*B.
18 
19    Collective on Mat
20 
21    Input Parameters:
22 +  A - the left matrix
23 -  B - the right matrix
24 
25    Output Parameters:
26 .  C - the product matrix
27 
28    Notes:
29    C will be created and must be destroyed by the user with MatDestroy().
30 
31    This routine is currently only implemented for pairs of SeqAIJ matrices.
32 
33    Level: intermediate
34 
35 .seealso: MatMatMultSymbolic(),MatMatMultNumeric()
36 @*/
37 int MatMatMult(Mat A,Mat B, Mat *C) {
38   /* Perhaps this "interface" routine should be moved into the interface directory.*/
39   /* To facilitate implementations with varying types, QueryFunction is used.*/
40   /* It is assumed that implementations will be composed as "MatMatMult_<type of A><type of B>". */
41   int  ierr;
42   char funct[80];
43   int  (*mult)(Mat,Mat,Mat*);
44 
45   PetscFunctionBegin;
46   PetscValidHeaderSpecific(A,MAT_COOKIE,1);
47   PetscValidType(A);
48   MatPreallocated(A);
49   if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
50   if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
51 
52   PetscValidHeaderSpecific(B,MAT_COOKIE,2);
53   PetscValidType(B);
54   MatPreallocated(B);
55   if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
56   if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
57 
58   PetscValidPointer(C,3);
59 
60   if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N);
61 
62   ierr = PetscStrcpy(funct,"MatMatMult_");CHKERRQ(ierr);
63   ierr = PetscStrcat(funct,A->type_name);CHKERRQ(ierr);
64   ierr = PetscStrcat(funct,B->type_name);CHKERRQ(ierr);
65   ierr = PetscObjectQueryFunction((PetscObject)A,funct,(PetscVoidFunction)&mult);CHKERRQ(ierr);
66   if (!mult) SETERRQ2(PETSC_ERR_SUP,"C=A*B not implemented for A of type %s and B of type %s",
67                          A->type_name,B->type_name);
68   ierr = (*mult)(A,B,C);CHKERRQ(ierr);
69   PetscFunctionReturn(0);
70 }
71 
72 #undef __FUNCT__
73 #define __FUNCT__ "MatMatMult_SeqAIJ_SeqAIJ"
74 int MatMatMult_SeqAIJ_SeqAIJ(Mat A,Mat B, Mat *C) {
75   int ierr;
76   char symfunct[80],numfunct[80],types[80];
77   int (*symbolic)(Mat,Mat,Mat*),(*numeric)(Mat,Mat,Mat);
78 
79   PetscFunctionBegin;
80   ierr = PetscStrcpy(types,A->type_name);CHKERRQ(ierr);
81   ierr = PetscStrcat(types,B->type_name);CHKERRQ(ierr);
82   ierr = PetscStrcpy(symfunct,"MatMatMultSymbolic_");CHKERRQ(ierr);
83   ierr = PetscStrcat(symfunct,types);CHKERRQ(ierr);
84   ierr = PetscObjectQueryFunction((PetscObject)A,symfunct,(PetscVoidFunction)&symbolic);CHKERRQ(ierr);
85   if (!symbolic) SETERRQ2(PETSC_ERR_SUP,
86                          "C=A*B not implemented for A of type %s and B of type %s",
87                          A->type_name,B->type_name);
88   ierr = PetscStrcpy(numfunct,"MatMatMultNumeric_");CHKERRQ(ierr);
89   ierr = PetscStrcat(numfunct,types);CHKERRQ(ierr);
90   ierr = PetscObjectQueryFunction((PetscObject)A,numfunct,(PetscVoidFunction)&numeric);CHKERRQ(ierr);
91   if (!numeric) SETERRQ2(PETSC_ERR_SUP,
92                          "C=A*B not implemented for A of type %s and B of type %s",
93                          A->type_name,B->type_name);
94   ierr = PetscLogEventBegin(logkey_matmatmult,A,B,0,0);CHKERRQ(ierr);
95   ierr = (*symbolic)(A,B,C);CHKERRQ(ierr);
96   ierr = (*numeric)(A,B,*C);CHKERRQ(ierr);
97   ierr = PetscLogEventEnd(logkey_matmatmult,A,B,0,0);CHKERRQ(ierr);
98   PetscFunctionReturn(0);
99 }
100 
101 #undef __FUNCT__
102 #define __FUNCT__ "MatMatMultSymbolic"
103 /*@
104    MatMatMultSymbolic - Performs construction, preallocation, and computes the ij structure
105    of the matrix-matrix product C=A*B.  Call this routine before calling MatMatMultNumeric().
106 
107    Collective on Mat
108 
109    Input Parameters:
110 +  A - the left matrix
111 -  B - the right matrix
112 
113    Output Parameters:
114 .  C - the matrix containing the ij structure of product matrix
115 
116    Notes:
117    C will be created and must be destroyed by the user with MatDestroy().
118 
119    This routine is currently only implemented for SeqAIJ type matrices.
120 
121    Level: intermediate
122 
123 .seealso: MatMatMult(),MatMatMultNumeric()
124 @*/
125 int MatMatMultSymbolic(Mat A,Mat B,Mat *C) {
126   /* Perhaps this "interface" routine should be moved into the interface directory.*/
127   /* To facilitate implementations with varying types, QueryFunction is used.*/
128   /* It is assumed that implementations will be composed as "MatMatMultSymbolic_<type of A><type of B>". */
129   int  ierr;
130   char funct[80];
131   int  (*symbolic)(Mat,Mat,Mat *);
132 
133   PetscFunctionBegin;
134   PetscValidHeaderSpecific(A,MAT_COOKIE,1);
135   PetscValidType(A);
136   MatPreallocated(A);
137   if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
138   if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
139 
140   PetscValidHeaderSpecific(B,MAT_COOKIE,2);
141   PetscValidType(B);
142   MatPreallocated(B);
143   if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
144   if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
145   PetscValidPointer(C,3);
146 
147 
148   if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N);
149 
150   ierr = PetscStrcpy(funct,"MatMatMultSymbolic_");CHKERRQ(ierr);
151   ierr = PetscStrcat(funct,A->type_name);CHKERRQ(ierr);
152   ierr = PetscStrcat(funct,B->type_name);CHKERRQ(ierr);
153   ierr = PetscObjectQueryFunction((PetscObject)A,funct,(PetscVoidFunction)&symbolic);CHKERRQ(ierr);
154   if (!symbolic) SETERRQ2(PETSC_ERR_SUP,
155                          "C=A*B not implemented for A of type %s and B of type %s",
156                          A->type_name,B->type_name);
157   ierr = (*symbolic)(A,B,C);CHKERRQ(ierr);
158 
159   PetscFunctionReturn(0);
160 }
161 
162 #undef __FUNCT__
163 #define __FUNCT__ "MatMatMult_Symbolic_SeqAIJ_SeqAIJ"
164 int MatMatMult_Symbolic_SeqAIJ_SeqAIJ(Mat A,Mat B,Mat *C)
165 {
166   int            ierr;
167   FreeSpaceList  free_space=PETSC_NULL,current_space=PETSC_NULL;
168   Mat_SeqAIJ     *a=(Mat_SeqAIJ*)A->data,*b=(Mat_SeqAIJ*)B->data,*c;
169   int            *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j,*bjj;
170   int            *ci,*cj,*lnk,idx0,idx,bcol;
171   int            am=A->M,bn=B->N,bm=B->M;
172   int            i,j,k,anzi,brow,bnzj,cnzi;
173   MatScalar      *ca;
174 
175   PetscFunctionBegin;
176   /* Start timers */
177   ierr = PetscLogEventBegin(logkey_matmatmult_symbolic,A,B,0,0);CHKERRQ(ierr);
178 
179   /* Set up */
180   /* Allocate ci array, arrays for fill computation and */
181   /* free space for accumulating nonzero column info */
182   ierr = PetscMalloc(((am+1)+1)*sizeof(int),&ci);CHKERRQ(ierr);
183   ci[0] = 0;
184 
185   ierr = PetscMalloc((bn+1)*sizeof(int),&lnk);CHKERRQ(ierr);
186   for (i=0; i<bn; i++) lnk[i] = -1;
187 
188   /* Initial FreeSpace size is nnz(B)=4*bi[bm] */
189   ierr = GetMoreSpace(4*bi[bm],&free_space);CHKERRQ(ierr);
190   current_space = free_space;
191 
192   /* Determine symbolic info for each row of the product: */
193   for (i=0;i<am;i++) {
194     anzi = ai[i+1] - ai[i];
195     cnzi = 0;
196     lnk[bn] = bn;
197     for (j=0;j<anzi;j++) {
198       brow = *aj++;
199       bnzj = bi[brow+1] - bi[brow];
200       bjj  = bj + bi[brow];
201       idx  = bn;
202       for (k=0;k<bnzj;k++) {
203         bcol = bjj[k];
204         if (lnk[bcol] == -1) { /* new col */
205           if (k>0) idx = bjj[k-1];
206           do {
207             idx0 = idx;
208             idx  = lnk[idx0];
209           } while (bcol > idx);
210           lnk[idx0] = bcol;
211           lnk[bcol] = idx;
212           cnzi++;
213         }
214       }
215     }
216 
217     /* If free space is not available, make more free space */
218     /* Double the amount of total space in the list */
219     if (current_space->local_remaining<cnzi) {
220       printf("...%d -th row, double space ...\n",i);
221       ierr = GetMoreSpace(current_space->total_array_size,&current_space);CHKERRQ(ierr);
222     }
223 
224     /* Copy data into free space, and zero out denserow and lnk */
225     idx = bn;
226     for (j=0; j<cnzi; j++){
227       idx0 = idx;
228       idx  = lnk[idx0];
229       *current_space->array++ = idx;
230       lnk[idx0] = -1;
231     }
232     lnk[idx] = -1;
233 
234     current_space->local_used      += cnzi;
235     current_space->local_remaining -= cnzi;
236 
237     ci[i+1] = ci[i] + cnzi;
238   }
239 
240   /* Column indices are in the list of free space */
241   /* Allocate space for cj, initialize cj, and */
242   /* destroy list of free space and other temporary array(s) */
243   ierr = PetscMalloc((ci[am]+1)*sizeof(int),&cj);CHKERRQ(ierr);
244   ierr = MakeSpaceContiguous(&free_space,cj);CHKERRQ(ierr);
245   ierr = PetscFree(lnk);CHKERRQ(ierr);
246 
247   /* Allocate space for ca */
248   ierr = PetscMalloc((ci[am]+1)*sizeof(MatScalar),&ca);CHKERRQ(ierr);
249   ierr = PetscMemzero(ca,(ci[am]+1)*sizeof(MatScalar));CHKERRQ(ierr);
250 
251   /* put together the new matrix */
252   ierr = MatCreateSeqAIJWithArrays(A->comm,am,bn,ci,cj,ca,C);CHKERRQ(ierr);
253 
254   /* MatCreateSeqAIJWithArrays flags matrix so PETSc doesn't free the user's arrays. */
255   /* These are PETSc arrays, so change flags so arrays can be deleted by PETSc */
256   c = (Mat_SeqAIJ *)((*C)->data);
257   c->freedata = PETSC_TRUE;
258   c->nonew    = 0;
259 
260   ierr = PetscLogEventEnd(logkey_matmatmult_symbolic,A,B,0,0);CHKERRQ(ierr);
261   PetscFunctionReturn(0);
262 }
263 
264 #undef __FUNCT__
265 #define __FUNCT__ "MatMatMultNumeric"
266 /*@
267    MatMatMultNumeric - Performs the numeric matrix-matrix product.
268    Call this routine after first calling MatMatMultSymbolic().
269 
270    Collective on Mat
271 
272    Input Parameters:
273 +  A - the left matrix
274 -  B - the right matrix
275 
276    Output Parameters:
277 .  C - the product matrix, whose ij structure was defined from MatMatMultSymbolic().
278 
279    Notes:
280    C must have been created with MatMatMultSymbolic.
281 
282    This routine is currently only implemented for SeqAIJ type matrices.
283 
284    Level: intermediate
285 
286 .seealso: MatMatMult(),MatMatMultSymbolic()
287 @*/
288 int MatMatMultNumeric(Mat A,Mat B,Mat C){
289   /* Perhaps this "interface" routine should be moved into the interface directory.*/
290   /* To facilitate implementations with varying types, QueryFunction is used.*/
291   /* It is assumed that implementations will be composed as "MatMatMultNumeric_<type of A><type of B>". */
292   int ierr;
293   char funct[80];
294   int (*numeric)(Mat,Mat,Mat);
295 
296   PetscFunctionBegin;
297 
298   PetscValidHeaderSpecific(A,MAT_COOKIE,1);
299   PetscValidType(A);
300   MatPreallocated(A);
301   if (!A->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
302   if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
303 
304   PetscValidHeaderSpecific(B,MAT_COOKIE,2);
305   PetscValidType(B);
306   MatPreallocated(B);
307   if (!B->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
308   if (B->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
309 
310   PetscValidHeaderSpecific(C,MAT_COOKIE,3);
311   PetscValidType(C);
312   MatPreallocated(C);
313   if (!C->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
314   if (C->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
315 
316   if (B->N!=C->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->N,C->N);
317   if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N);
318   if (A->M!=C->M) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",A->M,C->M);
319 
320   /* Query A for ApplyPtAP implementation based on types of P */
321   ierr = PetscStrcpy(funct,"MatMatMultNumeric_");CHKERRQ(ierr);
322   ierr = PetscStrcat(funct,A->type_name);CHKERRQ(ierr);
323   ierr = PetscStrcat(funct,B->type_name);CHKERRQ(ierr);
324   ierr = PetscObjectQueryFunction((PetscObject)A,funct,(PetscVoidFunction)&numeric);CHKERRQ(ierr);
325   if (!numeric) SETERRQ2(PETSC_ERR_SUP,
326                          "C=A*B not implemented for A of type %s and B of type %s",
327                          A->type_name,B->type_name);
328   ierr = (*numeric)(A,B,C);CHKERRQ(ierr);
329 
330   PetscFunctionReturn(0);
331 }
332 
333 #undef __FUNCT__
334 #define __FUNCT__ "MatMatMult_Numeric_SeqAIJ_SeqAIJ"
335 int MatMatMult_Numeric_SeqAIJ_SeqAIJ(Mat A,Mat B,Mat C)
336 {
337   int        ierr,flops=0;
338   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
339   Mat_SeqAIJ *b = (Mat_SeqAIJ *)B->data;
340   Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data;
341   int        *ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j,*bjj,*ci=c->i,*cj=c->j;
342   int        am=A->M,cn=C->N;
343   int        i,j,k,anzi,bnzi,cnzi,brow;
344   MatScalar  *aa=a->a,*ba=b->a,*baj,*ca=c->a,*temp;
345 
346   PetscFunctionBegin;
347 
348   /* Start timers */
349   ierr = PetscLogEventBegin(logkey_matmatmult_numeric,A,B,C,0);CHKERRQ(ierr);
350 
351   /* Allocate temp accumulation space to avoid searching for nonzero columns in C */
352   ierr = PetscMalloc((cn+1)*sizeof(MatScalar),&temp);CHKERRQ(ierr);
353   ierr = PetscMemzero(temp,cn*sizeof(MatScalar));CHKERRQ(ierr);
354   /* Traverse A row-wise. */
355   /* Build the ith row in C by summing over nonzero columns in A, */
356   /* the rows of B corresponding to nonzeros of A. */
357   for (i=0;i<am;i++) {
358     anzi = ai[i+1] - ai[i];
359     for (j=0;j<anzi;j++) {
360       brow = *aj++;
361       bnzi = bi[brow+1] - bi[brow];
362       bjj  = bj + bi[brow];
363       baj  = ba + bi[brow];
364       for (k=0;k<bnzi;k++) {
365         temp[bjj[k]] += (*aa)*baj[k];
366       }
367       flops += 2*bnzi;
368       aa++;
369     }
370     /* Store row back into C, and re-zero temp */
371     cnzi = ci[i+1] - ci[i];
372     for (j=0;j<cnzi;j++) {
373       ca[j] = temp[cj[j]];
374       temp[cj[j]] = 0.0;
375     }
376     ca += cnzi;
377     cj += cnzi;
378   }
379   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
380   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
381 
382   /* Free temp */
383   ierr = PetscFree(temp);CHKERRQ(ierr);
384   ierr = PetscLogFlops(flops);CHKERRQ(ierr);
385   ierr = PetscLogEventEnd(logkey_matmatmult_numeric,A,B,C,0);CHKERRQ(ierr);
386   PetscFunctionReturn(0);
387 }
388 
389 #undef __FUNCT__
390 #define __FUNCT__ "RegisterMatMatMultRoutines_Private"
391 int RegisterMatMatMultRoutines_Private(Mat A) {
392   int ierr;
393 
394   PetscFunctionBegin;
395   if (!logkey_matmatmult) {
396     ierr = PetscLogEventRegister(&logkey_matmatmult,"MatMatMult",MAT_COOKIE);CHKERRQ(ierr);
397   }
398   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMatMult_seqaijseqaij",
399                                            "MatMatMult_SeqAIJ_SeqAIJ",
400                                            MatMatMult_SeqAIJ_SeqAIJ);CHKERRQ(ierr);
401   if (!logkey_matmatmult_symbolic) {
402     ierr = PetscLogEventRegister(&logkey_matmatmult_symbolic,"MatMatMult_Symbolic",MAT_COOKIE);CHKERRQ(ierr);
403   }
404   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMatMultSymbolic_seqaijseqaij",
405                                            "MatMatMult_Symbolic_SeqAIJ_SeqAIJ",
406                                            MatMatMult_Symbolic_SeqAIJ_SeqAIJ);CHKERRQ(ierr);
407   if (!logkey_matmatmult_numeric) {
408     ierr = PetscLogEventRegister(&logkey_matmatmult_numeric,"MatMatMult_Numeric",MAT_COOKIE);CHKERRQ(ierr);
409   }
410   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMatMultNumeric_seqaijseqaij",
411                                            "MatMatMult_Numeric_SeqAIJ_SeqAIJ",
412                                            MatMatMult_Numeric_SeqAIJ_SeqAIJ);CHKERRQ(ierr);
413   PetscFunctionReturn(0);
414 }
415