Actual source code: mcomposite.c
2: #include <private/matimpl.h> /*I "petscmat.h" I*/
4: typedef struct _Mat_CompositeLink *Mat_CompositeLink;
5: struct _Mat_CompositeLink {
6: Mat mat;
7: Vec work;
8: Mat_CompositeLink next,prev;
9: };
10:
11: typedef struct {
12: MatCompositeType type;
13: Mat_CompositeLink head,tail;
14: Vec work;
15: PetscScalar scale; /* scale factor supplied with MatScale() */
16: Vec left,right; /* left and right diagonal scaling provided with MatDiagonalScale() */
17: Vec leftwork,rightwork;
18: } Mat_Composite;
22: PetscErrorCode MatDestroy_Composite(Mat mat)
23: {
24: PetscErrorCode ierr;
25: Mat_Composite *shell = (Mat_Composite*)mat->data;
26: Mat_CompositeLink next = shell->head,oldnext;
29: while (next) {
30: MatDestroy(&next->mat);
31: if (next->work && (!next->next || next->work != next->next->work)) {
32: VecDestroy(&next->work);
33: }
34: oldnext = next;
35: next = next->next;
36: PetscFree(oldnext);
37: }
38: VecDestroy(&shell->work);
39: VecDestroy(&shell->left);
40: VecDestroy(&shell->right);
41: VecDestroy(&shell->leftwork);
42: VecDestroy(&shell->rightwork);
43: PetscFree(mat->data);
44: return(0);
45: }
49: PetscErrorCode MatMult_Composite_Multiplicative(Mat A,Vec x,Vec y)
50: {
51: Mat_Composite *shell = (Mat_Composite*)A->data;
52: Mat_CompositeLink next = shell->head;
53: PetscErrorCode ierr;
54: Vec in,out;
57: if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
58: in = x;
59: if (shell->right) {
60: if (!shell->rightwork) {
61: VecDuplicate(shell->right,&shell->rightwork);
62: }
63: VecPointwiseMult(shell->rightwork,shell->right,in);
64: in = shell->rightwork;
65: }
66: while (next->next) {
67: if (!next->work) { /* should reuse previous work if the same size */
68: MatGetVecs(next->mat,PETSC_NULL,&next->work);
69: }
70: out = next->work;
71: MatMult(next->mat,in,out);
72: in = out;
73: next = next->next;
74: }
75: MatMult(next->mat,in,y);
76: if (shell->left) {
77: VecPointwiseMult(y,shell->left,y);
78: }
79: VecScale(y,shell->scale);
80: return(0);
81: }
85: PetscErrorCode MatMultTranspose_Composite_Multiplicative(Mat A,Vec x,Vec y)
86: {
87: Mat_Composite *shell = (Mat_Composite*)A->data;
88: Mat_CompositeLink tail = shell->tail;
89: PetscErrorCode ierr;
90: Vec in,out;
93: if (!tail) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
94: in = x;
95: if (shell->left) {
96: if (!shell->leftwork) {
97: VecDuplicate(shell->left,&shell->leftwork);
98: }
99: VecPointwiseMult(shell->leftwork,shell->left,in);
100: in = shell->leftwork;
101: }
102: while (tail->prev) {
103: if (!tail->prev->work) { /* should reuse previous work if the same size */
104: MatGetVecs(tail->mat,PETSC_NULL,&tail->prev->work);
105: }
106: out = tail->prev->work;
107: MatMultTranspose(tail->mat,in,out);
108: in = out;
109: tail = tail->prev;
110: }
111: MatMultTranspose(tail->mat,in,y);
112: if (shell->right) {
113: VecPointwiseMult(y,shell->right,y);
114: }
115: VecScale(y,shell->scale);
116: return(0);
117: }
121: PetscErrorCode MatMult_Composite(Mat A,Vec x,Vec y)
122: {
123: Mat_Composite *shell = (Mat_Composite*)A->data;
124: Mat_CompositeLink next = shell->head;
125: PetscErrorCode ierr;
126: Vec in;
129: if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
130: in = x;
131: if (shell->right) {
132: if (!shell->rightwork) {
133: VecDuplicate(shell->right,&shell->rightwork);
134: }
135: VecPointwiseMult(shell->rightwork,shell->right,in);
136: in = shell->rightwork;
137: }
138: MatMult(next->mat,in,y);
139: while ((next = next->next)) {
140: MatMultAdd(next->mat,in,y,y);
141: }
142: if (shell->left) {
143: VecPointwiseMult(y,shell->left,y);
144: }
145: VecScale(y,shell->scale);
146: return(0);
147: }
151: PetscErrorCode MatMultTranspose_Composite(Mat A,Vec x,Vec y)
152: {
153: Mat_Composite *shell = (Mat_Composite*)A->data;
154: Mat_CompositeLink next = shell->head;
155: PetscErrorCode ierr;
156: Vec in;
159: if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
160: in = x;
161: if (shell->left) {
162: if (!shell->leftwork) {
163: VecDuplicate(shell->left,&shell->leftwork);
164: }
165: VecPointwiseMult(shell->leftwork,shell->left,in);
166: in = shell->leftwork;
167: }
168: MatMultTranspose(next->mat,in,y);
169: while ((next = next->next)) {
170: MatMultTransposeAdd(next->mat,in,y,y);
171: }
172: if (shell->right) {
173: VecPointwiseMult(y,shell->right,y);
174: }
175: VecScale(y,shell->scale);
176: return(0);
177: }
181: PetscErrorCode MatGetDiagonal_Composite(Mat A,Vec v)
182: {
183: Mat_Composite *shell = (Mat_Composite*)A->data;
184: Mat_CompositeLink next = shell->head;
185: PetscErrorCode ierr;
188: if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
189: if (shell->right || shell->left) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get diagonal if left or right scaling");
191: MatGetDiagonal(next->mat,v);
192: if (next->next && !shell->work) {
193: VecDuplicate(v,&shell->work);
194: }
195: while ((next = next->next)) {
196: MatGetDiagonal(next->mat,shell->work);
197: VecAXPY(v,1.0,shell->work);
198: }
199: VecScale(v,shell->scale);
200: return(0);
201: }
205: PetscErrorCode MatAssemblyEnd_Composite(Mat Y,MatAssemblyType t)
206: {
208: PetscBool flg = PETSC_FALSE;
211: PetscOptionsGetBool(((PetscObject)Y)->prefix,"-mat_composite_merge",&flg,PETSC_NULL);
212: if (flg) {
213: MatCompositeMerge(Y);
214: }
215: return(0);
216: }
220: PetscErrorCode MatScale_Composite(Mat inA,PetscScalar alpha)
221: {
222: Mat_Composite *a = (Mat_Composite*)inA->data;
225: a->scale *= alpha;
226: return(0);
227: }
231: PetscErrorCode MatDiagonalScale_Composite(Mat inA,Vec left,Vec right)
232: {
233: Mat_Composite *a = (Mat_Composite*)inA->data;
237: if (left) {
238: if (!a->left) {
239: VecDuplicate(left,&a->left);
240: VecCopy(left,a->left);
241: } else {
242: VecPointwiseMult(a->left,left,a->left);
243: }
244: }
245: if (right) {
246: if (!a->right) {
247: VecDuplicate(right,&a->right);
248: VecCopy(right,a->right);
249: } else {
250: VecPointwiseMult(a->right,right,a->right);
251: }
252: }
253: return(0);
254: }
256: static struct _MatOps MatOps_Values = {0,
257: 0,
258: 0,
259: MatMult_Composite,
260: 0,
261: /* 5*/ MatMultTranspose_Composite,
262: 0,
263: 0,
264: 0,
265: 0,
266: /*10*/ 0,
267: 0,
268: 0,
269: 0,
270: 0,
271: /*15*/ 0,
272: 0,
273: MatGetDiagonal_Composite,
274: MatDiagonalScale_Composite,
275: 0,
276: /*20*/ 0,
277: MatAssemblyEnd_Composite,
278: 0,
279: 0,
280: /*24*/ 0,
281: 0,
282: 0,
283: 0,
284: 0,
285: /*29*/ 0,
286: 0,
287: 0,
288: 0,
289: 0,
290: /*34*/ 0,
291: 0,
292: 0,
293: 0,
294: 0,
295: /*39*/ 0,
296: 0,
297: 0,
298: 0,
299: 0,
300: /*44*/ 0,
301: MatScale_Composite,
302: 0,
303: 0,
304: 0,
305: /*49*/ 0,
306: 0,
307: 0,
308: 0,
309: 0,
310: /*54*/ 0,
311: 0,
312: 0,
313: 0,
314: 0,
315: /*59*/ 0,
316: MatDestroy_Composite,
317: 0,
318: 0,
319: 0,
320: /*64*/ 0,
321: 0,
322: 0,
323: 0,
324: 0,
325: /*69*/ 0,
326: 0,
327: 0,
328: 0,
329: 0,
330: /*74*/ 0,
331: 0,
332: 0,
333: 0,
334: 0,
335: /*79*/ 0,
336: 0,
337: 0,
338: 0,
339: 0,
340: /*84*/ 0,
341: 0,
342: 0,
343: 0,
344: 0,
345: /*89*/ 0,
346: 0,
347: 0,
348: 0,
349: 0,
350: /*94*/ 0,
351: 0,
352: 0,
353: 0};
355: /*MC
356: MATCOMPOSITE - A matrix defined by the sum (or product) of one or more matrices (all matrices are of same size and parallel layout).
358: Notes: to use the product of the matrices call MatCompositeSetType(mat,MAT_COMPOSITE_MULTIPLICATIVE);
360: Level: advanced
362: .seealso: MatCreateComposite(), MatCompositeAddMat(), MatSetType(), MatCompositeMerge(), MatCompositeSetType(), MatCompositeType
363: M*/
368: PetscErrorCode MatCreate_Composite(Mat A)
369: {
370: Mat_Composite *b;
374: PetscNewLog(A,Mat_Composite,&b);
375: A->data = (void*)b;
376: PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));
378: PetscLayoutSetBlockSize(A->rmap,1);
379: PetscLayoutSetBlockSize(A->cmap,1);
380: PetscLayoutSetUp(A->rmap);
381: PetscLayoutSetUp(A->cmap);
383: A->assembled = PETSC_TRUE;
384: A->preallocated = PETSC_FALSE;
385: b->type = MAT_COMPOSITE_ADDITIVE;
386: b->scale = 1.0;
387: PetscObjectChangeTypeName((PetscObject)A,MATCOMPOSITE);
388: return(0);
389: }
394: /*@C
395: MatCreateComposite - Creates a matrix as the sum of zero or more matrices
397: Collective on MPI_Comm
399: Input Parameters:
400: + comm - MPI communicator
401: . nmat - number of matrices to put in
402: - mats - the matrices
404: Output Parameter:
405: . A - the matrix
407: Level: advanced
409: Notes:
410: Alternative construction
411: $ MatCreate(comm,&mat);
412: $ MatSetSizes(mat,m,n,M,N);
413: $ MatSetType(mat,MATCOMPOSITE);
414: $ MatCompositeAddMat(mat,mats[0]);
415: $ ....
416: $ MatCompositeAddMat(mat,mats[nmat-1]);
417: $ MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
418: $ MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
420: For the multiplicative form the product is mat[nmat-1]*mat[nmat-2]*....*mat[0]
422: .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCompositeMerge(), MatCompositeSetType(), MatCompositeType
424: @*/
425: PetscErrorCode MatCreateComposite(MPI_Comm comm,PetscInt nmat,const Mat *mats,Mat *mat)
426: {
428: PetscInt m,n,M,N,i;
429:
431: if (nmat < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must pass in at least one matrix");
434: MatGetLocalSize(mats[0],&m,&n);
435: MatGetSize(mats[0],&M,&N);
436: MatCreate(comm,mat);
437: MatSetSizes(*mat,m,n,M,N);
438: MatSetType(*mat,MATCOMPOSITE);
439: for (i=0; i<nmat; i++) {
440: MatCompositeAddMat(*mat,mats[i]);
441: }
442: MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);
443: MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);
444: return(0);
445: }
449: /*@
450: MatCompositeAddMat - add another matrix to a composite matrix
452: Collective on Mat
454: Input Parameters:
455: + mat - the composite matrix
456: - smat - the partial matrix
458: Level: advanced
460: .seealso: MatCreateComposite()
461: @*/
462: PetscErrorCode MatCompositeAddMat(Mat mat,Mat smat)
463: {
464: Mat_Composite *shell;
465: PetscErrorCode ierr;
466: Mat_CompositeLink ilink,next;
471: PetscNewLog(mat,struct _Mat_CompositeLink,&ilink);
472: ilink->next = 0;
473: PetscObjectReference((PetscObject)smat);
474: ilink->mat = smat;
476: shell = (Mat_Composite*)mat->data;
477: next = shell->head;
478: if (!next) {
479: shell->head = ilink;
480: } else {
481: while (next->next) {
482: next = next->next;
483: }
484: next->next = ilink;
485: ilink->prev = next;
486: }
487: shell->tail = ilink;
488: return(0);
489: }
493: /*@C
494: MatCompositeSetType - Indicates if the matrix is defined as the sum of a set of matrices or the product
496: Collective on MPI_Comm
498: Input Parameters:
499: . mat - the composite matrix
502: Level: advanced
504: Notes:
505: The MatType of the resulting matrix will be the same as the MatType of the FIRST
506: matrix in the composite matrix.
508: .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MATCOMPOSITE
510: @*/
511: PetscErrorCode MatCompositeSetType(Mat mat,MatCompositeType type)
512: {
513: Mat_Composite *b = (Mat_Composite*)mat->data;
514: PetscBool flg;
518: PetscTypeCompare((PetscObject)mat,MATCOMPOSITE,&flg);
519: if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Can only use with composite matrix");
520: if (type == MAT_COMPOSITE_MULTIPLICATIVE) {
521: mat->ops->getdiagonal = 0;
522: mat->ops->mult = MatMult_Composite_Multiplicative;
523: mat->ops->multtranspose = MatMultTranspose_Composite_Multiplicative;
524: b->type = MAT_COMPOSITE_MULTIPLICATIVE;
525: } else {
526: mat->ops->getdiagonal = MatGetDiagonal_Composite;
527: mat->ops->mult = MatMult_Composite;
528: mat->ops->multtranspose = MatMultTranspose_Composite;
529: b->type = MAT_COMPOSITE_ADDITIVE;
530: }
531: return(0);
532: }
537: /*@C
538: MatCompositeMerge - Given a composite matrix, replaces it with a "regular" matrix
539: by summing all the matrices inside the composite matrix.
541: Collective on MPI_Comm
543: Input Parameters:
544: . mat - the composite matrix
547: Options Database:
548: . -mat_composite_merge (you must call MatAssemblyBegin()/MatAssemblyEnd() to have this checked)
550: Level: advanced
552: Notes:
553: The MatType of the resulting matrix will be the same as the MatType of the FIRST
554: matrix in the composite matrix.
556: .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MATCOMPOSITE
558: @*/
559: PetscErrorCode MatCompositeMerge(Mat mat)
560: {
561: Mat_Composite *shell = (Mat_Composite*)mat->data;
562: Mat_CompositeLink next = shell->head, prev = shell->tail;
563: PetscErrorCode ierr;
564: Mat tmat,newmat;
567: if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
570: if (shell->type == MAT_COMPOSITE_ADDITIVE) {
571: MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);
572: while ((next = next->next)) {
573: MatAXPY(tmat,1.0,next->mat,DIFFERENT_NONZERO_PATTERN);
574: }
575: } else {
576: MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);
577: while ((prev = prev->prev)) {
578: MatMatMult(tmat,prev->mat,MAT_INITIAL_MATRIX,PETSC_DECIDE,&newmat);
579: MatDestroy(&tmat);
580: tmat = newmat;
581: }
582: }
583: MatHeaderReplace(mat,tmat);
584: MatDiagonalScale(mat,shell->left,shell->right);
585: MatScale(mat,shell->scale);
586: return(0);
587: }