Actual source code: mcomposite.c

  1: #define PETSCMAT_DLL

 3:  #include private/matimpl.h

  5: typedef struct _Mat_CompositeLink *Mat_CompositeLink;
  6: struct _Mat_CompositeLink {
  7:   Mat               mat;
  8:   Vec               work;
  9:   Mat_CompositeLink next,prev;
 10: };
 11: 
 12: typedef struct {
 13:   MatCompositeType  type;
 14:   Mat_CompositeLink head,tail;
 15:   Vec               work;
 16:   PetscScalar       scale;        /* scale factor supplied with MatScale() */
 17:   Vec               left,right;   /* left and right diagonal scaling provided with MatDiagonalScale() */
 18:   Vec               leftwork,rightwork;
 19: } Mat_Composite;

 23: PetscErrorCode MatDestroy_Composite(Mat mat)
 24: {
 25:   PetscErrorCode   ierr;
 26:   Mat_Composite    *shell = (Mat_Composite*)mat->data;
 27:   Mat_CompositeLink next = shell->head,oldnext;

 30:   while (next) {
 31:     MatDestroy(next->mat);
 32:     if (next->work && (!next->next || next->work != next->next->work)) {
 33:       VecDestroy(next->work);
 34:     }
 35:     oldnext = next;
 36:     next     = next->next;
 37:     PetscFree(oldnext);
 38:   }
 39:   if (shell->work) {VecDestroy(shell->work);}
 40:   if (shell->left) {VecDestroy(shell->left);}
 41:   if (shell->right) {VecDestroy(shell->right);}
 42:   if (shell->leftwork) {VecDestroy(shell->leftwork);}
 43:   if (shell->rightwork) {VecDestroy(shell->rightwork);}
 44:   PetscFree(shell);
 45:   mat->data = 0;
 46:   return(0);
 47: }

 51: PetscErrorCode MatMult_Composite_Multiplicative(Mat A,Vec x,Vec y)
 52: {
 53:   Mat_Composite     *shell = (Mat_Composite*)A->data;
 54:   Mat_CompositeLink next = shell->head;
 55:   PetscErrorCode    ierr;
 56:   Vec               in,out;

 59:   if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
 60:   in = x;
 61:   if (shell->right) {
 62:     if (!shell->rightwork) {
 63:       VecDuplicate(shell->right,&shell->rightwork);
 64:     }
 65:     VecPointwiseMult(shell->rightwork,shell->right,in);
 66:     in   = shell->rightwork;
 67:   }
 68:   while (next->next) {
 69:     if (!next->work) { /* should reuse previous work if the same size */
 70:       MatGetVecs(next->mat,PETSC_NULL,&next->work);
 71:     }
 72:     out = next->work;
 73:     MatMult(next->mat,in,out);
 74:     in   = out;
 75:     next = next->next;
 76:   }
 77:   MatMult(next->mat,in,y);
 78:   if (shell->left) {
 79:     VecPointwiseMult(y,shell->left,y);
 80:   }
 81:   VecScale(y,shell->scale);
 82:   return(0);
 83: }

 87: PetscErrorCode MatMultTranspose_Composite_Multiplicative(Mat A,Vec x,Vec y)
 88: {
 89:   Mat_Composite     *shell = (Mat_Composite*)A->data;
 90:   Mat_CompositeLink tail = shell->tail;
 91:   PetscErrorCode    ierr;
 92:   Vec               in,out;

 95:   if (!tail) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
 96:   in = x;
 97:   if (shell->left) {
 98:     if (!shell->leftwork) {
 99:       VecDuplicate(shell->left,&shell->leftwork);
100:     }
101:     VecPointwiseMult(shell->leftwork,shell->left,in);
102:     in   = shell->leftwork;
103:   }
104:   while (tail->prev) {
105:     if (!tail->prev->work) { /* should reuse previous work if the same size */
106:       MatGetVecs(tail->mat,PETSC_NULL,&tail->prev->work);
107:     }
108:     out = tail->prev->work;
109:     MatMultTranspose(tail->mat,in,out);
110:     in   = out;
111:     tail = tail->prev;
112:   }
113:   MatMultTranspose(tail->mat,in,y);
114:   if (shell->right) {
115:     VecPointwiseMult(y,shell->right,y);
116:   }
117:   VecScale(y,shell->scale);
118:   return(0);
119: }

123: PetscErrorCode MatMult_Composite(Mat A,Vec x,Vec y)
124: {
125:   Mat_Composite     *shell = (Mat_Composite*)A->data;
126:   Mat_CompositeLink next = shell->head;
127:   PetscErrorCode    ierr;
128:   Vec               in;

131:   if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
132:   in = x;
133:   if (shell->right) {
134:     if (!shell->rightwork) {
135:       VecDuplicate(shell->right,&shell->rightwork);
136:     }
137:     VecPointwiseMult(shell->rightwork,shell->right,in);
138:     in   = shell->rightwork;
139:   }
140:   MatMult(next->mat,in,y);
141:   while ((next = next->next)) {
142:     MatMultAdd(next->mat,in,y,y);
143:   }
144:   if (shell->left) {
145:     VecPointwiseMult(y,shell->left,y);
146:   }
147:   VecScale(y,shell->scale);
148:   return(0);
149: }

153: PetscErrorCode MatMultTranspose_Composite(Mat A,Vec x,Vec y)
154: {
155:   Mat_Composite     *shell = (Mat_Composite*)A->data;
156:   Mat_CompositeLink next = shell->head;
157:   PetscErrorCode    ierr;
158:   Vec               in;

161:   if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
162:   in = x;
163:   if (shell->left) {
164:     if (!shell->leftwork) {
165:       VecDuplicate(shell->left,&shell->leftwork);
166:     }
167:     VecPointwiseMult(shell->leftwork,shell->left,in);
168:     in   = shell->leftwork;
169:   }
170:   MatMultTranspose(next->mat,in,y);
171:   while ((next = next->next)) {
172:     MatMultTransposeAdd(next->mat,in,y,y);
173:   }
174:   if (shell->right) {
175:     VecPointwiseMult(y,shell->right,y);
176:   }
177:   VecScale(y,shell->scale);
178:   return(0);
179: }

183: PetscErrorCode MatGetDiagonal_Composite(Mat A,Vec v)
184: {
185:   Mat_Composite     *shell = (Mat_Composite*)A->data;
186:   Mat_CompositeLink next = shell->head;
187:   PetscErrorCode    ierr;

190:   if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
191:   if (shell->right || shell->left) SETERRQ(PETSC_ERR_SUP,"Cannot get diagonal if left or right scaling");

193:   MatGetDiagonal(next->mat,v);
194:   if (next->next && !shell->work) {
195:     VecDuplicate(v,&shell->work);
196:   }
197:   while ((next = next->next)) {
198:     MatGetDiagonal(next->mat,shell->work);
199:     VecAXPY(v,1.0,shell->work);
200:   }
201:   VecScale(v,shell->scale);
202:   return(0);
203: }

207: PetscErrorCode MatAssemblyEnd_Composite(Mat Y,MatAssemblyType t)
208: {
210:   PetscTruth     flg;

213:   PetscOptionsHasName(((PetscObject)Y)->prefix,"-mat_composite_merge",&flg);
214:   if (flg) {
215:     MatCompositeMerge(Y);
216:   }
217:   return(0);
218: }

222: PetscErrorCode MatScale_Composite(Mat inA,PetscScalar alpha)
223: {
224:   Mat_Composite  *a = (Mat_Composite*)inA->data;

227:   a->scale *= alpha;
228:   return(0);
229: }

233: PetscErrorCode MatDiagonalScale_Composite(Mat inA,Vec left,Vec right)
234: {
235:   Mat_Composite  *a = (Mat_Composite*)inA->data;

239:   if (left) {
240:     if (!a->left) {
241:       VecDuplicate(left,&a->left);
242:       VecCopy(left,a->left);
243:     } else {
244:       VecPointwiseMult(a->left,left,a->left);
245:     }
246:   }
247:   if (right) {
248:     if (!a->right) {
249:       VecDuplicate(right,&a->right);
250:       VecCopy(right,a->right);
251:     } else {
252:       VecPointwiseMult(a->right,right,a->right);
253:     }
254:   }
255:   return(0);
256: }

258: static struct _MatOps MatOps_Values = {0,
259:        0,
260:        0,
261:        MatMult_Composite,
262:        0,
263: /* 5*/ MatMultTranspose_Composite,
264:        0,
265:        0,
266:        0,
267:        0,
268: /*10*/ 0,
269:        0,
270:        0,
271:        0,
272:        0,
273: /*15*/ 0,
274:        0,
275:        MatGetDiagonal_Composite,
276:        MatDiagonalScale_Composite,
277:        0,
278: /*20*/ 0,
279:        MatAssemblyEnd_Composite,
280:        0,
281:        0,
282:        0,
283: /*25*/ 0,
284:        0,
285:        0,
286:        0,
287:        0,
288: /*30*/ 0,
289:        0,
290:        0,
291:        0,
292:        0,
293: /*35*/ 0,
294:        0,
295:        0,
296:        0,
297:        0,
298: /*40*/ 0,
299:        0,
300:        0,
301:        0,
302:        0,
303: /*45*/ 0,
304:        MatScale_Composite,
305:        0,
306:        0,
307:        0,
308: /*50*/ 0,
309:        0,
310:        0,
311:        0,
312:        0,
313: /*55*/ 0,
314:        0,
315:        0,
316:        0,
317:        0,
318: /*60*/ 0,
319:        MatDestroy_Composite,
320:        0,
321:        0,
322:        0,
323: /*65*/ 0,
324:        0,
325:        0,
326:        0,
327:        0,
328: /*70*/ 0,
329:        0,
330:        0,
331:        0,
332:        0,
333: /*75*/ 0,
334:        0,
335:        0,
336:        0,
337:        0,
338: /*80*/ 0,
339:        0,
340:        0,
341:        0,
342:        0,
343: /*85*/ 0,
344:        0,
345:        0,
346:        0,
347:        0,
348: /*90*/ 0,
349:        0,
350:        0,
351:        0,
352:        0,
353: /*95*/ 0,
354:        0,
355:        0,
356:        0};

358: /*MC
359:    MATCOMPOSITE - A matrix defined by the sum (or product) of one or more matrices (all matrices are of same size and parallel layout).

361:    Notes: to use the product of the matrices call MatCompositeSetType(mat,MAT_COMPOSITE_MULTIPLICATIVE);

363:   Level: advanced

365: .seealso: MatCreateComposite(), MatCompositeAddMat(), MatSetType(), MatCompositeMerge(), MatCompositeSetType(), MatCompositeType
366: M*/

371: PetscErrorCode  MatCreate_Composite(Mat A)
372: {
373:   Mat_Composite  *b;

377:   PetscNewLog(A,Mat_Composite,&b);
378:   A->data = (void*)b;
379:   PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));

381:   PetscMapSetBlockSize(A->rmap,1);
382:   PetscMapSetBlockSize(A->cmap,1);
383:   PetscMapSetUp(A->rmap);
384:   PetscMapSetUp(A->cmap);

386:   A->assembled     = PETSC_TRUE;
387:   A->preallocated  = PETSC_FALSE;
388:   b->type          = MAT_COMPOSITE_ADDITIVE;
389:   b->scale         = 1.0;
390:   PetscObjectChangeTypeName((PetscObject)A,MATCOMPOSITE);
391:   return(0);
392: }

397: /*@C
398:    MatCreateComposite - Creates a matrix as the sum of zero or more matrices

400:   Collective on MPI_Comm

402:    Input Parameters:
403: +  comm - MPI communicator
404: .  nmat - number of matrices to put in
405: -  mats - the matrices

407:    Output Parameter:
408: .  A - the matrix

410:    Level: advanced

412:    Notes:
413:      Alternative construction 
414: $       MatCreate(comm,&mat);
415: $       MatSetSizes(mat,m,n,M,N);
416: $       MatSetType(mat,MATCOMPOSITE);
417: $       MatCompositeAddMat(mat,mats[0]);
418: $       ....
419: $       MatCompositeAddMat(mat,mats[nmat-1]);
420: $       MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
421: $       MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);

423:      For the multiplicative form the product is mat[nmat-1]*mat[nmat-2]*....*mat[0]

425: .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCompositeMerge(), MatCompositeSetType(), MatCompositeType

427: @*/
428: PetscErrorCode  MatCreateComposite(MPI_Comm comm,PetscInt nmat,const Mat *mats,Mat *mat)
429: {
431:   PetscInt       m,n,M,N,i;
432: 
434:   if (nmat < 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Must pass in at least one matrix");

437:   MatGetLocalSize(mats[0],&m,&n);
438:   MatGetSize(mats[0],&M,&N);
439:   MatCreate(comm,mat);
440:   MatSetSizes(*mat,m,n,M,N);
441:   MatSetType(*mat,MATCOMPOSITE);
442:   for (i=0; i<nmat; i++) {
443:     MatCompositeAddMat(*mat,mats[i]);
444:   }
445:   MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);
446:   MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);
447:   return(0);
448: }

452: /*@
453:     MatCompositeAddMat - add another matrix to a composite matrix

455:    Collective on Mat

457:     Input Parameters:
458: +   mat - the composite matrix
459: -   smat - the partial matrix

461:    Level: advanced

463: .seealso: MatCreateComposite()
464: @*/
465: PetscErrorCode  MatCompositeAddMat(Mat mat,Mat smat)
466: {
467:   Mat_Composite     *shell;
468:   PetscErrorCode    ierr;
469:   Mat_CompositeLink ilink,next;

474:   PetscNewLog(mat,struct _Mat_CompositeLink,&ilink);
475:   ilink->next = 0;
476:   PetscObjectReference((PetscObject)smat);
477:   ilink->mat  = smat;

479:   shell = (Mat_Composite*)mat->data;
480:   next = shell->head;
481:   if (!next) {
482:     shell->head  = ilink;
483:   } else {
484:     while (next->next) {
485:       next = next->next;
486:     }
487:     next->next      = ilink;
488:     ilink->prev     = next;
489:   }
490:   shell->tail = ilink;
491:   return(0);
492: }

496: /*@C
497:    MatCompositeSetType - Indicates if the matrix is defined as the sum of a set of matrices or the product

499:   Collective on MPI_Comm

501:    Input Parameters:
502: .  mat - the composite matrix


505:    Level: advanced

507:    Notes:
508:       The MatType of the resulting matrix will be the same as the MatType of the FIRST
509:     matrix in the composite matrix.

511: .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MATCOMPOSITE

513: @*/
514: PetscErrorCode  MatCompositeSetType(Mat mat,MatCompositeType type)
515: {
516:   Mat_Composite  *b = (Mat_Composite*)mat->data;
517:   PetscTruth     flg;

521:   PetscTypeCompare((PetscObject)mat,MATCOMPOSITE,&flg);
522:   if (!flg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Can only use with composite matrix");
523:   if (type == MAT_COMPOSITE_MULTIPLICATIVE) {
524:     mat->ops->getdiagonal   = 0;
525:     mat->ops->mult          = MatMult_Composite_Multiplicative;
526:     mat->ops->multtranspose = MatMultTranspose_Composite_Multiplicative;
527:     b->type                 = MAT_COMPOSITE_MULTIPLICATIVE;
528:   } else {
529:     mat->ops->getdiagonal   = MatGetDiagonal_Composite;
530:     mat->ops->mult          = MatMult_Composite;
531:     mat->ops->multtranspose = MatMultTranspose_Composite;
532:     b->type                 = MAT_COMPOSITE_ADDITIVE;
533:   }
534:   return(0);
535: }


540: /*@C
541:    MatCompositeMerge - Given a composite matrix, replaces it with a "regular" matrix
542:      by summing all the matrices inside the composite matrix.

544:   Collective on MPI_Comm

546:    Input Parameters:
547: .  mat - the composite matrix


550:    Options Database:
551: .  -mat_composite_merge  (you must call MatAssemblyBegin()/MatAssemblyEnd() to have this checked)

553:    Level: advanced

555:    Notes:
556:       The MatType of the resulting matrix will be the same as the MatType of the FIRST
557:     matrix in the composite matrix.

559: .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MATCOMPOSITE

561: @*/
562: PetscErrorCode  MatCompositeMerge(Mat mat)
563: {
564:   Mat_Composite     *shell = (Mat_Composite*)mat->data;
565:   Mat_CompositeLink next = shell->head, prev = shell->tail;
566:   PetscErrorCode    ierr;
567:   Mat               tmat,newmat;

570:   if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");

573:   if (shell->type == MAT_COMPOSITE_ADDITIVE) {
574:     MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);
575:     while ((next = next->next)) {
576:       MatAXPY(tmat,1.0,next->mat,DIFFERENT_NONZERO_PATTERN);
577:     }
578:   } else {
579:     MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);
580:     while ((prev = prev->prev)) {
581:       MatMatMult(tmat,prev->mat,MAT_INITIAL_MATRIX,PETSC_DECIDE,&newmat);
582:       MatDestroy(tmat);
583:       tmat = newmat;
584:     }
585:   }
586:   MatHeaderReplace(mat,tmat);
587:   MatDiagonalScale(mat,shell->left,shell->right);
588:   MatScale(mat,shell->scale);
589:   return(0);
590: }