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