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