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: }