Actual source code: matmatmult.c
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: */
7: #include src/mat/impls/aij/seq/aij.h
8: #include src/mat/utils/freespace.h
10: static int logkey_matmatmult = 0;
11: static int logkey_matmatmult_symbolic = 0;
12: static int logkey_matmatmult_numeric = 0;
16: /*@
17: MatMatMult - Performs Matrix-Matrix Multiplication C=A*B.
19: Collective on Mat
21: Input Parameters:
22: + A - the left matrix
23: - B - the right matrix
25: Output Parameters:
26: . C - the product matrix
28: Notes:
29: C will be created and must be destroyed by the user with MatDestroy().
31: This routine is currently only implemented for pairs of SeqAIJ matrices.
33: Level: intermediate
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*);
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");
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");
60: if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N);
62: PetscStrcpy(funct,"MatMatMult_");
63: PetscStrcat(funct,A->type_name);
64: PetscStrcat(funct,B->type_name);
65: PetscObjectQueryFunction((PetscObject)A,funct,(PetscVoidFunction)&mult);
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: (*mult)(A,B,C);
69: return(0);
70: }
74: int MatMatMult_SeqAIJ_SeqAIJ(Mat A,Mat B, Mat *C) {
76: char symfunct[80],numfunct[80],types[80];
77: int (*symbolic)(Mat,Mat,Mat*),(*numeric)(Mat,Mat,Mat);
80: PetscStrcpy(types,A->type_name);
81: PetscStrcat(types,B->type_name);
82: PetscStrcpy(symfunct,"MatMatMultSymbolic_");
83: PetscStrcat(symfunct,types);
84: PetscObjectQueryFunction((PetscObject)A,symfunct,(PetscVoidFunction)&symbolic);
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: PetscStrcpy(numfunct,"MatMatMultNumeric_");
89: PetscStrcat(numfunct,types);
90: PetscObjectQueryFunction((PetscObject)A,numfunct,(PetscVoidFunction)&numeric);
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: PetscLogEventBegin(logkey_matmatmult,A,B,0,0);
95: (*symbolic)(A,B,C);
96: (*numeric)(A,B,*C);
97: PetscLogEventEnd(logkey_matmatmult,A,B,0,0);
98: return(0);
99: }
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().
107: Collective on Mat
109: Input Parameters:
110: + A - the left matrix
111: - B - the right matrix
113: Output Parameters:
114: . C - the matrix containing the ij structure of product matrix
116: Notes:
117: C will be created and must be destroyed by the user with MatDestroy().
119: This routine is currently only implemented for SeqAIJ type matrices.
121: Level: intermediate
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 *);
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");
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");
148: if (B->M!=A->N) SETERRQ2(PETSC_ERR_ARG_SIZ,"Matrix dimensions are incompatible, %d != %d",B->M,A->N);
150: PetscStrcpy(funct,"MatMatMultSymbolic_");
151: PetscStrcat(funct,A->type_name);
152: PetscStrcat(funct,B->type_name);
153: PetscObjectQueryFunction((PetscObject)A,funct,(PetscVoidFunction)&symbolic);
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: (*symbolic)(A,B,C);
159: return(0);
160: }
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;
176: /* Start timers */
177: PetscLogEventBegin(logkey_matmatmult_symbolic,A,B,0,0);
179: /* Set up */
180: /* Allocate ci array, arrays for fill computation and */
181: /* free space for accumulating nonzero column info */
182: PetscMalloc(((am+1)+1)*sizeof(int),&ci);
183: ci[0] = 0;
184:
185: PetscMalloc((bn+1)*sizeof(int),&lnk);
186: for (i=0; i<bn; i++) lnk[i] = -1;
188: /* Initial FreeSpace size is nnz(B)=4*bi[bm] */
189: GetMoreSpace(4*bi[bm],&free_space);
190: current_space = free_space;
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: }
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: GetMoreSpace(current_space->total_array_size,¤t_space);
222: }
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;
234: current_space->local_used += cnzi;
235: current_space->local_remaining -= cnzi;
237: ci[i+1] = ci[i] + cnzi;
238: }
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: PetscMalloc((ci[am]+1)*sizeof(int),&cj);
244: MakeSpaceContiguous(&free_space,cj);
245: PetscFree(lnk);
246:
247: /* Allocate space for ca */
248: PetscMalloc((ci[am]+1)*sizeof(MatScalar),&ca);
249: PetscMemzero(ca,(ci[am]+1)*sizeof(MatScalar));
250:
251: /* put together the new matrix */
252: MatCreateSeqAIJWithArrays(A->comm,am,bn,ci,cj,ca,C);
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;
260: PetscLogEventEnd(logkey_matmatmult_symbolic,A,B,0,0);
261: return(0);
262: }
266: /*@
267: MatMatMultNumeric - Performs the numeric matrix-matrix product.
268: Call this routine after first calling MatMatMultSymbolic().
270: Collective on Mat
272: Input Parameters:
273: + A - the left matrix
274: - B - the right matrix
276: Output Parameters:
277: . C - the product matrix, whose ij structure was defined from MatMatMultSymbolic().
279: Notes:
280: C must have been created with MatMatMultSymbolic.
282: This routine is currently only implemented for SeqAIJ type matrices.
284: Level: intermediate
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>". */
293: char funct[80];
294: int (*numeric)(Mat,Mat,Mat);
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");
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");
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");
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);
320: /* Query A for ApplyPtAP implementation based on types of P */
321: PetscStrcpy(funct,"MatMatMultNumeric_");
322: PetscStrcat(funct,A->type_name);
323: PetscStrcat(funct,B->type_name);
324: PetscObjectQueryFunction((PetscObject)A,funct,(PetscVoidFunction)&numeric);
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: (*numeric)(A,B,C);
330: return(0);
331: }
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;
348: /* Start timers */
349: PetscLogEventBegin(logkey_matmatmult_numeric,A,B,C,0);
351: /* Allocate temp accumulation space to avoid searching for nonzero columns in C */
352: PetscMalloc((cn+1)*sizeof(MatScalar),&temp);
353: PetscMemzero(temp,cn*sizeof(MatScalar));
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: MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
380: MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);
381:
382: /* Free temp */
383: PetscFree(temp);
384: PetscLogFlops(flops);
385: PetscLogEventEnd(logkey_matmatmult_numeric,A,B,C,0);
386: return(0);
387: }
391: int RegisterMatMatMultRoutines_Private(Mat A) {
395: if (!logkey_matmatmult) {
396: PetscLogEventRegister(&logkey_matmatmult,"MatMatMult",MAT_COOKIE);
397: }
398: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMatMult_seqaijseqaij",
399: "MatMatMult_SeqAIJ_SeqAIJ",
400: MatMatMult_SeqAIJ_SeqAIJ);
401: if (!logkey_matmatmult_symbolic) {
402: PetscLogEventRegister(&logkey_matmatmult_symbolic,"MatMatMult_Symbolic",MAT_COOKIE);
403: }
404: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMatMultSymbolic_seqaijseqaij",
405: "MatMatMult_Symbolic_SeqAIJ_SeqAIJ",
406: MatMatMult_Symbolic_SeqAIJ_SeqAIJ);
407: if (!logkey_matmatmult_numeric) {
408: PetscLogEventRegister(&logkey_matmatmult_numeric,"MatMatMult_Numeric",MAT_COOKIE);
409: }
410: PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMatMultNumeric_seqaijseqaij",
411: "MatMatMult_Numeric_SeqAIJ_SeqAIJ",
412: MatMatMult_Numeric_SeqAIJ_SeqAIJ);
413: return(0);
414: }