Actual source code: mcomposite.c
2: #include <petsc/private/matimpl.h>
4: const char *const MatCompositeMergeTypes[] = {"left", "right", "MatCompositeMergeType", "MAT_COMPOSITE_", NULL};
6: typedef struct _Mat_CompositeLink *Mat_CompositeLink;
7: struct _Mat_CompositeLink {
8: Mat mat;
9: Vec work;
10: Mat_CompositeLink next, prev;
11: };
13: typedef struct {
14: MatCompositeType type;
15: Mat_CompositeLink head, tail;
16: Vec work;
17: PetscScalar scale; /* scale factor supplied with MatScale() */
18: Vec left, right; /* left and right diagonal scaling provided with MatDiagonalScale() */
19: Vec leftwork, rightwork, leftwork2, rightwork2; /* Two pairs of working vectors */
20: PetscInt nmat;
21: PetscBool merge;
22: MatCompositeMergeType mergetype;
23: MatStructure structure;
25: PetscScalar *scalings;
26: PetscBool merge_mvctx; /* Whether need to merge mvctx of component matrices */
27: Vec *lvecs; /* [nmat] Basically, they are Mvctx->lvec of each component matrix */
28: PetscScalar *larray; /* [len] Data arrays of lvecs[] are stored consecutively in larray */
29: PetscInt len; /* Length of larray[] */
30: Vec gvec; /* Union of lvecs[] without duplicated entries */
31: PetscInt *location; /* A map that maps entries in garray[] to larray[] */
32: VecScatter Mvctx;
33: } Mat_Composite;
35: PetscErrorCode MatDestroy_Composite(Mat mat)
36: {
37: Mat_Composite *shell = (Mat_Composite *)mat->data;
38: Mat_CompositeLink next = shell->head, oldnext;
39: PetscInt i;
41: PetscFunctionBegin;
42: while (next) {
43: PetscCall(MatDestroy(&next->mat));
44: if (next->work && (!next->next || next->work != next->next->work)) PetscCall(VecDestroy(&next->work));
45: oldnext = next;
46: next = next->next;
47: PetscCall(PetscFree(oldnext));
48: }
49: PetscCall(VecDestroy(&shell->work));
50: PetscCall(VecDestroy(&shell->left));
51: PetscCall(VecDestroy(&shell->right));
52: PetscCall(VecDestroy(&shell->leftwork));
53: PetscCall(VecDestroy(&shell->rightwork));
54: PetscCall(VecDestroy(&shell->leftwork2));
55: PetscCall(VecDestroy(&shell->rightwork2));
57: if (shell->Mvctx) {
58: for (i = 0; i < shell->nmat; i++) PetscCall(VecDestroy(&shell->lvecs[i]));
59: PetscCall(PetscFree3(shell->location, shell->larray, shell->lvecs));
60: PetscCall(PetscFree(shell->larray));
61: PetscCall(VecDestroy(&shell->gvec));
62: PetscCall(VecScatterDestroy(&shell->Mvctx));
63: }
65: PetscCall(PetscFree(shell->scalings));
66: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeAddMat_C", NULL));
67: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetType_C", NULL));
68: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetType_C", NULL));
69: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetMergeType_C", NULL));
70: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetMatStructure_C", NULL));
71: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetMatStructure_C", NULL));
72: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeMerge_C", NULL));
73: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetNumberMat_C", NULL));
74: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetMat_C", NULL));
75: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetScalings_C", NULL));
76: PetscCall(PetscFree(mat->data));
77: PetscFunctionReturn(PETSC_SUCCESS);
78: }
80: PetscErrorCode MatMult_Composite_Multiplicative(Mat A, Vec x, Vec y)
81: {
82: Mat_Composite *shell = (Mat_Composite *)A->data;
83: Mat_CompositeLink next = shell->head;
84: Vec in, out;
85: PetscScalar scale;
86: PetscInt i;
88: PetscFunctionBegin;
89: PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
90: in = x;
91: if (shell->right) {
92: if (!shell->rightwork) PetscCall(VecDuplicate(shell->right, &shell->rightwork));
93: PetscCall(VecPointwiseMult(shell->rightwork, shell->right, in));
94: in = shell->rightwork;
95: }
96: while (next->next) {
97: if (!next->work) { /* should reuse previous work if the same size */
98: PetscCall(MatCreateVecs(next->mat, NULL, &next->work));
99: }
100: out = next->work;
101: PetscCall(MatMult(next->mat, in, out));
102: in = out;
103: next = next->next;
104: }
105: PetscCall(MatMult(next->mat, in, y));
106: if (shell->left) PetscCall(VecPointwiseMult(y, shell->left, y));
107: scale = shell->scale;
108: if (shell->scalings) {
109: for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
110: }
111: PetscCall(VecScale(y, scale));
112: PetscFunctionReturn(PETSC_SUCCESS);
113: }
115: PetscErrorCode MatMultTranspose_Composite_Multiplicative(Mat A, Vec x, Vec y)
116: {
117: Mat_Composite *shell = (Mat_Composite *)A->data;
118: Mat_CompositeLink tail = shell->tail;
119: Vec in, out;
120: PetscScalar scale;
121: PetscInt i;
123: PetscFunctionBegin;
124: PetscCheck(tail, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
125: in = x;
126: if (shell->left) {
127: if (!shell->leftwork) PetscCall(VecDuplicate(shell->left, &shell->leftwork));
128: PetscCall(VecPointwiseMult(shell->leftwork, shell->left, in));
129: in = shell->leftwork;
130: }
131: while (tail->prev) {
132: if (!tail->prev->work) { /* should reuse previous work if the same size */
133: PetscCall(MatCreateVecs(tail->mat, NULL, &tail->prev->work));
134: }
135: out = tail->prev->work;
136: PetscCall(MatMultTranspose(tail->mat, in, out));
137: in = out;
138: tail = tail->prev;
139: }
140: PetscCall(MatMultTranspose(tail->mat, in, y));
141: if (shell->right) PetscCall(VecPointwiseMult(y, shell->right, y));
143: scale = shell->scale;
144: if (shell->scalings) {
145: for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
146: }
147: PetscCall(VecScale(y, scale));
148: PetscFunctionReturn(PETSC_SUCCESS);
149: }
151: PetscErrorCode MatMult_Composite(Mat mat, Vec x, Vec y)
152: {
153: Mat_Composite *shell = (Mat_Composite *)mat->data;
154: Mat_CompositeLink cur = shell->head;
155: Vec in, y2, xin;
156: Mat A, B;
157: PetscInt i, j, k, n, nuniq, lo, hi, mid, *gindices, *buf, *tmp, tot;
158: const PetscScalar *vals;
159: const PetscInt *garray;
160: IS ix, iy;
161: PetscBool match;
163: PetscFunctionBegin;
164: PetscCheck(cur, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
165: in = x;
166: if (shell->right) {
167: if (!shell->rightwork) PetscCall(VecDuplicate(shell->right, &shell->rightwork));
168: PetscCall(VecPointwiseMult(shell->rightwork, shell->right, in));
169: in = shell->rightwork;
170: }
172: /* Try to merge Mvctx when instructed but not yet done. We did not do it in MatAssemblyEnd() since at that time
173: we did not know whether mat is ADDITIVE or MULTIPLICATIVE. Only now we are assured mat is ADDITIVE and
174: it is legal to merge Mvctx, because all component matrices have the same size.
175: */
176: if (shell->merge_mvctx && !shell->Mvctx) {
177: /* Currently only implemented for MATMPIAIJ */
178: for (cur = shell->head; cur; cur = cur->next) {
179: PetscCall(PetscObjectTypeCompare((PetscObject)cur->mat, MATMPIAIJ, &match));
180: if (!match) {
181: shell->merge_mvctx = PETSC_FALSE;
182: goto skip_merge_mvctx;
183: }
184: }
186: /* Go through matrices first time to count total number of nonzero off-diag columns (may have dups) */
187: tot = 0;
188: for (cur = shell->head; cur; cur = cur->next) {
189: PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, NULL));
190: PetscCall(MatGetLocalSize(B, NULL, &n));
191: tot += n;
192: }
193: PetscCall(PetscMalloc3(tot, &shell->location, tot, &shell->larray, shell->nmat, &shell->lvecs));
194: shell->len = tot;
196: /* Go through matrices second time to sort off-diag columns and remove dups */
197: PetscCall(PetscMalloc1(tot, &gindices)); /* No Malloc2() since we will give one to petsc and free the other */
198: PetscCall(PetscMalloc1(tot, &buf));
199: nuniq = 0; /* Number of unique nonzero columns */
200: for (cur = shell->head; cur; cur = cur->next) {
201: PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, &garray));
202: PetscCall(MatGetLocalSize(B, NULL, &n));
203: /* Merge pre-sorted garray[0,n) and gindices[0,nuniq) to buf[] */
204: i = j = k = 0;
205: while (i < n && j < nuniq) {
206: if (garray[i] < gindices[j]) buf[k++] = garray[i++];
207: else if (garray[i] > gindices[j]) buf[k++] = gindices[j++];
208: else {
209: buf[k++] = garray[i++];
210: j++;
211: }
212: }
213: /* Copy leftover in garray[] or gindices[] */
214: if (i < n) {
215: PetscCall(PetscArraycpy(buf + k, garray + i, n - i));
216: nuniq = k + n - i;
217: } else if (j < nuniq) {
218: PetscCall(PetscArraycpy(buf + k, gindices + j, nuniq - j));
219: nuniq = k + nuniq - j;
220: } else nuniq = k;
221: /* Swap gindices and buf to merge garray of the next matrix */
222: tmp = gindices;
223: gindices = buf;
224: buf = tmp;
225: }
226: PetscCall(PetscFree(buf));
228: /* Go through matrices third time to build a map from gindices[] to garray[] */
229: tot = 0;
230: for (cur = shell->head, j = 0; cur; cur = cur->next, j++) { /* j-th matrix */
231: PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, &garray));
232: PetscCall(MatGetLocalSize(B, NULL, &n));
233: PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, n, NULL, &shell->lvecs[j]));
234: /* This is an optimized PetscFindInt(garray[i],nuniq,gindices,&shell->location[tot+i]), using the fact that garray[] is also sorted */
235: lo = 0;
236: for (i = 0; i < n; i++) {
237: hi = nuniq;
238: while (hi - lo > 1) {
239: mid = lo + (hi - lo) / 2;
240: if (garray[i] < gindices[mid]) hi = mid;
241: else lo = mid;
242: }
243: shell->location[tot + i] = lo; /* gindices[lo] = garray[i] */
244: lo++; /* Since garray[i+1] > garray[i], we can safely advance lo */
245: }
246: tot += n;
247: }
249: /* Build merged Mvctx */
250: PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nuniq, gindices, PETSC_OWN_POINTER, &ix));
251: PetscCall(ISCreateStride(PETSC_COMM_SELF, nuniq, 0, 1, &iy));
252: PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)mat), 1, mat->cmap->n, mat->cmap->N, NULL, &xin));
253: PetscCall(VecCreateSeq(PETSC_COMM_SELF, nuniq, &shell->gvec));
254: PetscCall(VecScatterCreate(xin, ix, shell->gvec, iy, &shell->Mvctx));
255: PetscCall(VecDestroy(&xin));
256: PetscCall(ISDestroy(&ix));
257: PetscCall(ISDestroy(&iy));
258: }
260: skip_merge_mvctx:
261: PetscCall(VecSet(y, 0));
262: if (!shell->leftwork2) PetscCall(VecDuplicate(y, &shell->leftwork2));
263: y2 = shell->leftwork2;
265: if (shell->Mvctx) { /* Have a merged Mvctx */
266: /* Suppose we want to compute y = sMx, where s is the scaling factor and A, B are matrix M's diagonal/off-diagonal part. We could do
267: in y = s(Ax1 + Bx2) or y = sAx1 + sBx2. The former incurs less FLOPS than the latter, but the latter provides an opportunity to
268: overlap communication/computation since we can do sAx1 while communicating x2. Here, we use the former approach.
269: */
270: PetscCall(VecScatterBegin(shell->Mvctx, in, shell->gvec, INSERT_VALUES, SCATTER_FORWARD));
271: PetscCall(VecScatterEnd(shell->Mvctx, in, shell->gvec, INSERT_VALUES, SCATTER_FORWARD));
273: PetscCall(VecGetArrayRead(shell->gvec, &vals));
274: for (i = 0; i < shell->len; i++) shell->larray[i] = vals[shell->location[i]];
275: PetscCall(VecRestoreArrayRead(shell->gvec, &vals));
277: for (cur = shell->head, tot = i = 0; cur; cur = cur->next, i++) { /* i-th matrix */
278: PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, &A, &B, NULL));
279: PetscUseTypeMethod(A, mult, in, y2);
280: PetscCall(MatGetLocalSize(B, NULL, &n));
281: PetscCall(VecPlaceArray(shell->lvecs[i], &shell->larray[tot]));
282: PetscCall((*B->ops->multadd)(B, shell->lvecs[i], y2, y2));
283: PetscCall(VecResetArray(shell->lvecs[i]));
284: PetscCall(VecAXPY(y, (shell->scalings ? shell->scalings[i] : 1.0), y2));
285: tot += n;
286: }
287: } else {
288: if (shell->scalings) {
289: for (cur = shell->head, i = 0; cur; cur = cur->next, i++) {
290: PetscCall(MatMult(cur->mat, in, y2));
291: PetscCall(VecAXPY(y, shell->scalings[i], y2));
292: }
293: } else {
294: for (cur = shell->head; cur; cur = cur->next) PetscCall(MatMultAdd(cur->mat, in, y, y));
295: }
296: }
298: if (shell->left) PetscCall(VecPointwiseMult(y, shell->left, y));
299: PetscCall(VecScale(y, shell->scale));
300: PetscFunctionReturn(PETSC_SUCCESS);
301: }
303: PetscErrorCode MatMultTranspose_Composite(Mat A, Vec x, Vec y)
304: {
305: Mat_Composite *shell = (Mat_Composite *)A->data;
306: Mat_CompositeLink next = shell->head;
307: Vec in, y2 = NULL;
308: PetscInt i;
310: PetscFunctionBegin;
311: PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
312: in = x;
313: if (shell->left) {
314: if (!shell->leftwork) PetscCall(VecDuplicate(shell->left, &shell->leftwork));
315: PetscCall(VecPointwiseMult(shell->leftwork, shell->left, in));
316: in = shell->leftwork;
317: }
319: PetscCall(MatMultTranspose(next->mat, in, y));
320: if (shell->scalings) {
321: PetscCall(VecScale(y, shell->scalings[0]));
322: if (!shell->rightwork2) PetscCall(VecDuplicate(y, &shell->rightwork2));
323: y2 = shell->rightwork2;
324: }
325: i = 1;
326: while ((next = next->next)) {
327: if (!shell->scalings) PetscCall(MatMultTransposeAdd(next->mat, in, y, y));
328: else {
329: PetscCall(MatMultTranspose(next->mat, in, y2));
330: PetscCall(VecAXPY(y, shell->scalings[i++], y2));
331: }
332: }
333: if (shell->right) PetscCall(VecPointwiseMult(y, shell->right, y));
334: PetscCall(VecScale(y, shell->scale));
335: PetscFunctionReturn(PETSC_SUCCESS);
336: }
338: PetscErrorCode MatMultAdd_Composite(Mat A, Vec x, Vec y, Vec z)
339: {
340: Mat_Composite *shell = (Mat_Composite *)A->data;
342: PetscFunctionBegin;
343: if (y != z) {
344: PetscCall(MatMult(A, x, z));
345: PetscCall(VecAXPY(z, 1.0, y));
346: } else {
347: if (!shell->leftwork) PetscCall(VecDuplicate(z, &shell->leftwork));
348: PetscCall(MatMult(A, x, shell->leftwork));
349: PetscCall(VecCopy(y, z));
350: PetscCall(VecAXPY(z, 1.0, shell->leftwork));
351: }
352: PetscFunctionReturn(PETSC_SUCCESS);
353: }
355: PetscErrorCode MatMultTransposeAdd_Composite(Mat A, Vec x, Vec y, Vec z)
356: {
357: Mat_Composite *shell = (Mat_Composite *)A->data;
359: PetscFunctionBegin;
360: if (y != z) {
361: PetscCall(MatMultTranspose(A, x, z));
362: PetscCall(VecAXPY(z, 1.0, y));
363: } else {
364: if (!shell->rightwork) PetscCall(VecDuplicate(z, &shell->rightwork));
365: PetscCall(MatMultTranspose(A, x, shell->rightwork));
366: PetscCall(VecCopy(y, z));
367: PetscCall(VecAXPY(z, 1.0, shell->rightwork));
368: }
369: PetscFunctionReturn(PETSC_SUCCESS);
370: }
372: PetscErrorCode MatGetDiagonal_Composite(Mat A, Vec v)
373: {
374: Mat_Composite *shell = (Mat_Composite *)A->data;
375: Mat_CompositeLink next = shell->head;
376: PetscInt i;
378: PetscFunctionBegin;
379: PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
380: PetscCheck(!shell->right && !shell->left, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get diagonal if left or right scaling");
382: PetscCall(MatGetDiagonal(next->mat, v));
383: if (shell->scalings) PetscCall(VecScale(v, shell->scalings[0]));
385: if (next->next && !shell->work) PetscCall(VecDuplicate(v, &shell->work));
386: i = 1;
387: while ((next = next->next)) {
388: PetscCall(MatGetDiagonal(next->mat, shell->work));
389: PetscCall(VecAXPY(v, (shell->scalings ? shell->scalings[i++] : 1.0), shell->work));
390: }
391: PetscCall(VecScale(v, shell->scale));
392: PetscFunctionReturn(PETSC_SUCCESS);
393: }
395: PetscErrorCode MatAssemblyEnd_Composite(Mat Y, MatAssemblyType t)
396: {
397: Mat_Composite *shell = (Mat_Composite *)Y->data;
399: PetscFunctionBegin;
400: if (shell->merge) PetscCall(MatCompositeMerge(Y));
401: PetscFunctionReturn(PETSC_SUCCESS);
402: }
404: PetscErrorCode MatScale_Composite(Mat inA, PetscScalar alpha)
405: {
406: Mat_Composite *a = (Mat_Composite *)inA->data;
408: PetscFunctionBegin;
409: a->scale *= alpha;
410: PetscFunctionReturn(PETSC_SUCCESS);
411: }
413: PetscErrorCode MatDiagonalScale_Composite(Mat inA, Vec left, Vec right)
414: {
415: Mat_Composite *a = (Mat_Composite *)inA->data;
417: PetscFunctionBegin;
418: if (left) {
419: if (!a->left) {
420: PetscCall(VecDuplicate(left, &a->left));
421: PetscCall(VecCopy(left, a->left));
422: } else {
423: PetscCall(VecPointwiseMult(a->left, left, a->left));
424: }
425: }
426: if (right) {
427: if (!a->right) {
428: PetscCall(VecDuplicate(right, &a->right));
429: PetscCall(VecCopy(right, a->right));
430: } else {
431: PetscCall(VecPointwiseMult(a->right, right, a->right));
432: }
433: }
434: PetscFunctionReturn(PETSC_SUCCESS);
435: }
437: PetscErrorCode MatSetFromOptions_Composite(Mat A, PetscOptionItems *PetscOptionsObject)
438: {
439: Mat_Composite *a = (Mat_Composite *)A->data;
441: PetscFunctionBegin;
442: PetscOptionsHeadBegin(PetscOptionsObject, "MATCOMPOSITE options");
443: PetscCall(PetscOptionsBool("-mat_composite_merge", "Merge at MatAssemblyEnd", "MatCompositeMerge", a->merge, &a->merge, NULL));
444: PetscCall(PetscOptionsEnum("-mat_composite_merge_type", "Set composite merge direction", "MatCompositeSetMergeType", MatCompositeMergeTypes, (PetscEnum)a->mergetype, (PetscEnum *)&a->mergetype, NULL));
445: PetscCall(PetscOptionsBool("-mat_composite_merge_mvctx", "Merge MatMult() vecscat contexts", "MatCreateComposite", a->merge_mvctx, &a->merge_mvctx, NULL));
446: PetscOptionsHeadEnd();
447: PetscFunctionReturn(PETSC_SUCCESS);
448: }
450: /*@
451: MatCreateComposite - Creates a matrix as the sum or product of one or more matrices
453: Collective
455: Input Parameters:
456: + comm - MPI communicator
457: . nmat - number of matrices to put in
458: - mats - the matrices
460: Output Parameter:
461: . mat - the matrix
463: Options Database Keys:
464: + -mat_composite_merge - merge in `MatAssemblyEnd()`
465: . -mat_composite_merge_mvctx - merge Mvctx of component matrices to optimize communication in `MatMult()` for ADDITIVE matrices
466: - -mat_composite_merge_type - set merge direction
468: Level: advanced
470: Note:
471: Alternative construction
472: .vb
473: MatCreate(comm,&mat);
474: MatSetSizes(mat,m,n,M,N);
475: MatSetType(mat,MATCOMPOSITE);
476: MatCompositeAddMat(mat,mats[0]);
477: ....
478: MatCompositeAddMat(mat,mats[nmat-1]);
479: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
480: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
481: .ve
483: For the multiplicative form the product is mat[nmat-1]*mat[nmat-2]*....*mat[0]
485: .seealso: [](chapter_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCompositeGetMat()`, `MatCompositeMerge()`, `MatCompositeSetType()`, `MATCOMPOSITE`
486: @*/
487: PetscErrorCode MatCreateComposite(MPI_Comm comm, PetscInt nmat, const Mat *mats, Mat *mat)
488: {
489: PetscInt m, n, M, N, i;
491: PetscFunctionBegin;
492: PetscCheck(nmat >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must pass in at least one matrix");
495: PetscCall(MatGetLocalSize(mats[0], PETSC_IGNORE, &n));
496: PetscCall(MatGetLocalSize(mats[nmat - 1], &m, PETSC_IGNORE));
497: PetscCall(MatGetSize(mats[0], PETSC_IGNORE, &N));
498: PetscCall(MatGetSize(mats[nmat - 1], &M, PETSC_IGNORE));
499: PetscCall(MatCreate(comm, mat));
500: PetscCall(MatSetSizes(*mat, m, n, M, N));
501: PetscCall(MatSetType(*mat, MATCOMPOSITE));
502: for (i = 0; i < nmat; i++) PetscCall(MatCompositeAddMat(*mat, mats[i]));
503: PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY));
504: PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY));
505: PetscFunctionReturn(PETSC_SUCCESS);
506: }
508: static PetscErrorCode MatCompositeAddMat_Composite(Mat mat, Mat smat)
509: {
510: Mat_Composite *shell = (Mat_Composite *)mat->data;
511: Mat_CompositeLink ilink, next = shell->head;
513: PetscFunctionBegin;
514: PetscCall(PetscNew(&ilink));
515: ilink->next = NULL;
516: PetscCall(PetscObjectReference((PetscObject)smat));
517: ilink->mat = smat;
519: if (!next) shell->head = ilink;
520: else {
521: while (next->next) next = next->next;
522: next->next = ilink;
523: ilink->prev = next;
524: }
525: shell->tail = ilink;
526: shell->nmat += 1;
528: /* Retain the old scalings (if any) and expand it with a 1.0 for the newly added matrix */
529: if (shell->scalings) {
530: PetscCall(PetscRealloc(sizeof(PetscScalar) * shell->nmat, &shell->scalings));
531: shell->scalings[shell->nmat - 1] = 1.0;
532: }
533: PetscFunctionReturn(PETSC_SUCCESS);
534: }
536: /*@
537: MatCompositeAddMat - Add another matrix to a composite matrix.
539: Collective
541: Input Parameters:
542: + mat - the composite matrix
543: - smat - the partial matrix
545: Level: advanced
547: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetMat()`, `MATCOMPOSITE`
548: @*/
549: PetscErrorCode MatCompositeAddMat(Mat mat, Mat smat)
550: {
551: PetscFunctionBegin;
554: PetscUseMethod(mat, "MatCompositeAddMat_C", (Mat, Mat), (mat, smat));
555: PetscFunctionReturn(PETSC_SUCCESS);
556: }
558: static PetscErrorCode MatCompositeSetType_Composite(Mat mat, MatCompositeType type)
559: {
560: Mat_Composite *b = (Mat_Composite *)mat->data;
562: PetscFunctionBegin;
563: b->type = type;
564: if (type == MAT_COMPOSITE_MULTIPLICATIVE) {
565: mat->ops->getdiagonal = NULL;
566: mat->ops->mult = MatMult_Composite_Multiplicative;
567: mat->ops->multtranspose = MatMultTranspose_Composite_Multiplicative;
568: b->merge_mvctx = PETSC_FALSE;
569: } else {
570: mat->ops->getdiagonal = MatGetDiagonal_Composite;
571: mat->ops->mult = MatMult_Composite;
572: mat->ops->multtranspose = MatMultTranspose_Composite;
573: }
574: PetscFunctionReturn(PETSC_SUCCESS);
575: }
577: /*@
578: MatCompositeSetType - Indicates if the matrix is defined as the sum of a set of matrices or the product.
580: Logically Collective
582: Input Parameters:
583: . mat - the composite matrix
585: Level: advanced
587: .seealso: [](chapter_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCreateComposite()`, `MatCompositeGetType()`, `MATCOMPOSITE`
588: @*/
589: PetscErrorCode MatCompositeSetType(Mat mat, MatCompositeType type)
590: {
591: PetscFunctionBegin;
594: PetscUseMethod(mat, "MatCompositeSetType_C", (Mat, MatCompositeType), (mat, type));
595: PetscFunctionReturn(PETSC_SUCCESS);
596: }
598: static PetscErrorCode MatCompositeGetType_Composite(Mat mat, MatCompositeType *type)
599: {
600: Mat_Composite *b = (Mat_Composite *)mat->data;
602: PetscFunctionBegin;
603: *type = b->type;
604: PetscFunctionReturn(PETSC_SUCCESS);
605: }
607: /*@
608: MatCompositeGetType - Returns type of composite.
610: Not Collective
612: Input Parameter:
613: . mat - the composite matrix
615: Output Parameter:
616: . type - type of composite
618: Level: advanced
620: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetType()`, `MATCOMPOSITE`, `MatCompositeType`
621: @*/
622: PetscErrorCode MatCompositeGetType(Mat mat, MatCompositeType *type)
623: {
624: PetscFunctionBegin;
627: PetscUseMethod(mat, "MatCompositeGetType_C", (Mat, MatCompositeType *), (mat, type));
628: PetscFunctionReturn(PETSC_SUCCESS);
629: }
631: static PetscErrorCode MatCompositeSetMatStructure_Composite(Mat mat, MatStructure str)
632: {
633: Mat_Composite *b = (Mat_Composite *)mat->data;
635: PetscFunctionBegin;
636: b->structure = str;
637: PetscFunctionReturn(PETSC_SUCCESS);
638: }
640: /*@
641: MatCompositeSetMatStructure - Indicates structure of matrices in the composite matrix.
643: Not Collective
645: Input Parameters:
646: + mat - the composite matrix
647: - str - either `SAME_NONZERO_PATTERN`, `DIFFERENT_NONZERO_PATTERN` (default) or `SUBSET_NONZERO_PATTERN`
649: Level: advanced
651: Note:
652: Information about the matrices structure is used in `MatCompositeMerge()` for additive composite matrix.
654: .seealso: [](chapter_matrices), `Mat`, `MatAXPY()`, `MatCreateComposite()`, `MatCompositeMerge()` `MatCompositeGetMatStructure()`, `MATCOMPOSITE`
655: @*/
656: PetscErrorCode MatCompositeSetMatStructure(Mat mat, MatStructure str)
657: {
658: PetscFunctionBegin;
660: PetscUseMethod(mat, "MatCompositeSetMatStructure_C", (Mat, MatStructure), (mat, str));
661: PetscFunctionReturn(PETSC_SUCCESS);
662: }
664: static PetscErrorCode MatCompositeGetMatStructure_Composite(Mat mat, MatStructure *str)
665: {
666: Mat_Composite *b = (Mat_Composite *)mat->data;
668: PetscFunctionBegin;
669: *str = b->structure;
670: PetscFunctionReturn(PETSC_SUCCESS);
671: }
673: /*@
674: MatCompositeGetMatStructure - Returns the structure of matrices in the composite matrix.
676: Not Collective
678: Input Parameter:
679: . mat - the composite matrix
681: Output Parameter:
682: . str - structure of the matrices
684: Level: advanced
686: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetMatStructure()`, `MATCOMPOSITE`
687: @*/
688: PetscErrorCode MatCompositeGetMatStructure(Mat mat, MatStructure *str)
689: {
690: PetscFunctionBegin;
693: PetscUseMethod(mat, "MatCompositeGetMatStructure_C", (Mat, MatStructure *), (mat, str));
694: PetscFunctionReturn(PETSC_SUCCESS);
695: }
697: static PetscErrorCode MatCompositeSetMergeType_Composite(Mat mat, MatCompositeMergeType type)
698: {
699: Mat_Composite *shell = (Mat_Composite *)mat->data;
701: PetscFunctionBegin;
702: shell->mergetype = type;
703: PetscFunctionReturn(PETSC_SUCCESS);
704: }
706: /*@
707: MatCompositeSetMergeType - Sets order of `MatCompositeMerge()`.
709: Logically Collective
711: Input Parameters:
712: + mat - the composite matrix
713: - type - `MAT_COMPOSITE_MERGE RIGHT` (default) to start merge from right with the first added matrix (mat[0]),
714: `MAT_COMPOSITE_MERGE_LEFT` to start merge from left with the last added matrix (mat[nmat-1])
716: Level: advanced
718: Note:
719: The resulting matrix is the same regardless of the `MatCompositeMergeType`. Only the order of operation is changed.
720: If set to `MAT_COMPOSITE_MERGE_RIGHT` the order of the merge is mat[nmat-1]*(mat[nmat-2]*(...*(mat[1]*mat[0])))
721: otherwise the order is (((mat[nmat-1]*mat[nmat-2])*mat[nmat-3])*...)*mat[0].
723: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeMerge()`, `MATCOMPOSITE`
724: @*/
725: PetscErrorCode MatCompositeSetMergeType(Mat mat, MatCompositeMergeType type)
726: {
727: PetscFunctionBegin;
730: PetscUseMethod(mat, "MatCompositeSetMergeType_C", (Mat, MatCompositeMergeType), (mat, type));
731: PetscFunctionReturn(PETSC_SUCCESS);
732: }
734: static PetscErrorCode MatCompositeMerge_Composite(Mat mat)
735: {
736: Mat_Composite *shell = (Mat_Composite *)mat->data;
737: Mat_CompositeLink next = shell->head, prev = shell->tail;
738: Mat tmat, newmat;
739: Vec left, right;
740: PetscScalar scale;
741: PetscInt i;
743: PetscFunctionBegin;
744: PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
745: scale = shell->scale;
746: if (shell->type == MAT_COMPOSITE_ADDITIVE) {
747: if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
748: i = 0;
749: PetscCall(MatDuplicate(next->mat, MAT_COPY_VALUES, &tmat));
750: if (shell->scalings) PetscCall(MatScale(tmat, shell->scalings[i++]));
751: while ((next = next->next)) PetscCall(MatAXPY(tmat, (shell->scalings ? shell->scalings[i++] : 1.0), next->mat, shell->structure));
752: } else {
753: i = shell->nmat - 1;
754: PetscCall(MatDuplicate(prev->mat, MAT_COPY_VALUES, &tmat));
755: if (shell->scalings) PetscCall(MatScale(tmat, shell->scalings[i--]));
756: while ((prev = prev->prev)) PetscCall(MatAXPY(tmat, (shell->scalings ? shell->scalings[i--] : 1.0), prev->mat, shell->structure));
757: }
758: } else {
759: if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
760: PetscCall(MatDuplicate(next->mat, MAT_COPY_VALUES, &tmat));
761: while ((next = next->next)) {
762: PetscCall(MatMatMult(next->mat, tmat, MAT_INITIAL_MATRIX, PETSC_DECIDE, &newmat));
763: PetscCall(MatDestroy(&tmat));
764: tmat = newmat;
765: }
766: } else {
767: PetscCall(MatDuplicate(prev->mat, MAT_COPY_VALUES, &tmat));
768: while ((prev = prev->prev)) {
769: PetscCall(MatMatMult(tmat, prev->mat, MAT_INITIAL_MATRIX, PETSC_DECIDE, &newmat));
770: PetscCall(MatDestroy(&tmat));
771: tmat = newmat;
772: }
773: }
774: if (shell->scalings) {
775: for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
776: }
777: }
779: if ((left = shell->left)) PetscCall(PetscObjectReference((PetscObject)left));
780: if ((right = shell->right)) PetscCall(PetscObjectReference((PetscObject)right));
782: PetscCall(MatHeaderReplace(mat, &tmat));
784: PetscCall(MatDiagonalScale(mat, left, right));
785: PetscCall(MatScale(mat, scale));
786: PetscCall(VecDestroy(&left));
787: PetscCall(VecDestroy(&right));
788: PetscFunctionReturn(PETSC_SUCCESS);
789: }
791: /*@
792: MatCompositeMerge - Given a composite matrix, replaces it with a "regular" matrix
793: by summing or computing the product of all the matrices inside the composite matrix.
795: Collective
797: Input Parameter:
798: . mat - the composite matrix
800: Options Database Keys:
801: + -mat_composite_merge - merge in `MatAssemblyEnd()`
802: - -mat_composite_merge_type - set merge direction
804: Level: advanced
806: Note:
807: The `MatType` of the resulting matrix will be the same as the `MatType` of the FIRST matrix in the composite matrix.
809: .seealso: [](chapter_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCreateComposite()`, `MatCompositeSetMatStructure()`, `MatCompositeSetMergeType()`, `MATCOMPOSITE`
810: @*/
811: PetscErrorCode MatCompositeMerge(Mat mat)
812: {
813: PetscFunctionBegin;
815: PetscUseMethod(mat, "MatCompositeMerge_C", (Mat), (mat));
816: PetscFunctionReturn(PETSC_SUCCESS);
817: }
819: static PetscErrorCode MatCompositeGetNumberMat_Composite(Mat mat, PetscInt *nmat)
820: {
821: Mat_Composite *shell = (Mat_Composite *)mat->data;
823: PetscFunctionBegin;
824: *nmat = shell->nmat;
825: PetscFunctionReturn(PETSC_SUCCESS);
826: }
828: /*@
829: MatCompositeGetNumberMat - Returns the number of matrices in the composite matrix.
831: Not Collective
833: Input Parameter:
834: . mat - the composite matrix
836: Output Parameter:
837: . nmat - number of matrices in the composite matrix
839: Level: advanced
841: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetMat()`, `MATCOMPOSITE`
842: @*/
843: PetscErrorCode MatCompositeGetNumberMat(Mat mat, PetscInt *nmat)
844: {
845: PetscFunctionBegin;
848: PetscUseMethod(mat, "MatCompositeGetNumberMat_C", (Mat, PetscInt *), (mat, nmat));
849: PetscFunctionReturn(PETSC_SUCCESS);
850: }
852: static PetscErrorCode MatCompositeGetMat_Composite(Mat mat, PetscInt i, Mat *Ai)
853: {
854: Mat_Composite *shell = (Mat_Composite *)mat->data;
855: Mat_CompositeLink ilink;
856: PetscInt k;
858: PetscFunctionBegin;
859: PetscCheck(i < shell->nmat, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "index out of range: %" PetscInt_FMT " >= %" PetscInt_FMT, i, shell->nmat);
860: ilink = shell->head;
861: for (k = 0; k < i; k++) ilink = ilink->next;
862: *Ai = ilink->mat;
863: PetscFunctionReturn(PETSC_SUCCESS);
864: }
866: /*@
867: MatCompositeGetMat - Returns the ith matrix from the composite matrix.
869: Logically Collective
871: Input Parameters:
872: + mat - the composite matrix
873: - i - the number of requested matrix
875: Output Parameter:
876: . Ai - ith matrix in composite
878: Level: advanced
880: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetNumberMat()`, `MatCompositeAddMat()`, `MATCOMPOSITE`
881: @*/
882: PetscErrorCode MatCompositeGetMat(Mat mat, PetscInt i, Mat *Ai)
883: {
884: PetscFunctionBegin;
888: PetscUseMethod(mat, "MatCompositeGetMat_C", (Mat, PetscInt, Mat *), (mat, i, Ai));
889: PetscFunctionReturn(PETSC_SUCCESS);
890: }
892: PetscErrorCode MatCompositeSetScalings_Composite(Mat mat, const PetscScalar *scalings)
893: {
894: Mat_Composite *shell = (Mat_Composite *)mat->data;
895: PetscInt nmat;
897: PetscFunctionBegin;
898: PetscCall(MatCompositeGetNumberMat(mat, &nmat));
899: if (!shell->scalings) PetscCall(PetscMalloc1(nmat, &shell->scalings));
900: PetscCall(PetscArraycpy(shell->scalings, scalings, nmat));
901: PetscFunctionReturn(PETSC_SUCCESS);
902: }
904: /*@
905: MatCompositeSetScalings - Sets separate scaling factors for component matrices.
907: Logically Collective
909: Input Parameters:
910: + mat - the composite matrix
911: - scalings - array of scaling factors with scalings[i] being factor of i-th matrix, for i in [0, nmat)
913: Level: advanced
915: .seealso: [](chapter_matrices), `Mat`, `MatScale()`, `MatDiagonalScale()`, `MATCOMPOSITE`
916: @*/
917: PetscErrorCode MatCompositeSetScalings(Mat mat, const PetscScalar *scalings)
918: {
919: PetscFunctionBegin;
923: PetscUseMethod(mat, "MatCompositeSetScalings_C", (Mat, const PetscScalar *), (mat, scalings));
924: PetscFunctionReturn(PETSC_SUCCESS);
925: }
927: static struct _MatOps MatOps_Values = {NULL,
928: NULL,
929: NULL,
930: MatMult_Composite,
931: MatMultAdd_Composite,
932: /* 5*/ MatMultTranspose_Composite,
933: MatMultTransposeAdd_Composite,
934: NULL,
935: NULL,
936: NULL,
937: /* 10*/ NULL,
938: NULL,
939: NULL,
940: NULL,
941: NULL,
942: /* 15*/ NULL,
943: NULL,
944: MatGetDiagonal_Composite,
945: MatDiagonalScale_Composite,
946: NULL,
947: /* 20*/ NULL,
948: MatAssemblyEnd_Composite,
949: NULL,
950: NULL,
951: /* 24*/ NULL,
952: NULL,
953: NULL,
954: NULL,
955: NULL,
956: /* 29*/ NULL,
957: NULL,
958: NULL,
959: NULL,
960: NULL,
961: /* 34*/ NULL,
962: NULL,
963: NULL,
964: NULL,
965: NULL,
966: /* 39*/ NULL,
967: NULL,
968: NULL,
969: NULL,
970: NULL,
971: /* 44*/ NULL,
972: MatScale_Composite,
973: MatShift_Basic,
974: NULL,
975: NULL,
976: /* 49*/ NULL,
977: NULL,
978: NULL,
979: NULL,
980: NULL,
981: /* 54*/ NULL,
982: NULL,
983: NULL,
984: NULL,
985: NULL,
986: /* 59*/ NULL,
987: MatDestroy_Composite,
988: NULL,
989: NULL,
990: NULL,
991: /* 64*/ NULL,
992: NULL,
993: NULL,
994: NULL,
995: NULL,
996: /* 69*/ NULL,
997: NULL,
998: NULL,
999: NULL,
1000: NULL,
1001: /* 74*/ NULL,
1002: NULL,
1003: MatSetFromOptions_Composite,
1004: NULL,
1005: NULL,
1006: /* 79*/ NULL,
1007: NULL,
1008: NULL,
1009: NULL,
1010: NULL,
1011: /* 84*/ NULL,
1012: NULL,
1013: NULL,
1014: NULL,
1015: NULL,
1016: /* 89*/ NULL,
1017: NULL,
1018: NULL,
1019: NULL,
1020: NULL,
1021: /* 94*/ NULL,
1022: NULL,
1023: NULL,
1024: NULL,
1025: NULL,
1026: /*99*/ NULL,
1027: NULL,
1028: NULL,
1029: NULL,
1030: NULL,
1031: /*104*/ NULL,
1032: NULL,
1033: NULL,
1034: NULL,
1035: NULL,
1036: /*109*/ NULL,
1037: NULL,
1038: NULL,
1039: NULL,
1040: NULL,
1041: /*114*/ NULL,
1042: NULL,
1043: NULL,
1044: NULL,
1045: NULL,
1046: /*119*/ NULL,
1047: NULL,
1048: NULL,
1049: NULL,
1050: NULL,
1051: /*124*/ NULL,
1052: NULL,
1053: NULL,
1054: NULL,
1055: NULL,
1056: /*129*/ NULL,
1057: NULL,
1058: NULL,
1059: NULL,
1060: NULL,
1061: /*134*/ NULL,
1062: NULL,
1063: NULL,
1064: NULL,
1065: NULL,
1066: /*139*/ NULL,
1067: NULL,
1068: NULL,
1069: NULL,
1070: NULL,
1071: /*144*/ NULL,
1072: NULL,
1073: NULL,
1074: NULL,
1075: NULL,
1076: NULL,
1077: /*150*/ NULL,
1078: NULL};
1080: /*MC
1081: MATCOMPOSITE - A matrix defined by the sum (or product) of one or more matrices.
1082: The matrices need to have a correct size and parallel layout for the sum or product to be valid.
1084: Level: advanced
1086: Note:
1087: To use the product of the matrices call `MatCompositeSetType`(mat,`MAT_COMPOSITE_MULTIPLICATIVE`);
1089: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetScalings()`, `MatCompositeAddMat()`, `MatSetType()`, `MatCompositeSetType()`, `MatCompositeGetType()`,
1090: `MatCompositeSetMatStructure()`, `MatCompositeGetMatStructure()`, `MatCompositeMerge()`, `MatCompositeSetMergeType()`, `MatCompositeGetNumberMat()`, `MatCompositeGetMat()`
1091: M*/
1093: PETSC_EXTERN PetscErrorCode MatCreate_Composite(Mat A)
1094: {
1095: Mat_Composite *b;
1097: PetscFunctionBegin;
1098: PetscCall(PetscNew(&b));
1099: A->data = (void *)b;
1100: PetscCall(PetscMemcpy(A->ops, &MatOps_Values, sizeof(struct _MatOps)));
1102: PetscCall(PetscLayoutSetUp(A->rmap));
1103: PetscCall(PetscLayoutSetUp(A->cmap));
1105: A->assembled = PETSC_TRUE;
1106: A->preallocated = PETSC_TRUE;
1107: b->type = MAT_COMPOSITE_ADDITIVE;
1108: b->scale = 1.0;
1109: b->nmat = 0;
1110: b->merge = PETSC_FALSE;
1111: b->mergetype = MAT_COMPOSITE_MERGE_RIGHT;
1112: b->structure = DIFFERENT_NONZERO_PATTERN;
1113: b->merge_mvctx = PETSC_TRUE;
1115: PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeAddMat_C", MatCompositeAddMat_Composite));
1116: PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetType_C", MatCompositeSetType_Composite));
1117: PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetType_C", MatCompositeGetType_Composite));
1118: PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetMergeType_C", MatCompositeSetMergeType_Composite));
1119: PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetMatStructure_C", MatCompositeSetMatStructure_Composite));
1120: PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetMatStructure_C", MatCompositeGetMatStructure_Composite));
1121: PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeMerge_C", MatCompositeMerge_Composite));
1122: PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetNumberMat_C", MatCompositeGetNumberMat_Composite));
1123: PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetMat_C", MatCompositeGetMat_Composite));
1124: PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetScalings_C", MatCompositeSetScalings_Composite));
1126: PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATCOMPOSITE));
1127: PetscFunctionReturn(PETSC_SUCCESS);
1128: }