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,&current_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: }