xref: /petsc/src/mat/impls/composite/mcomposite.c (revision 7c4f633dc6bb6149cca88d301ead35a99e103cbb)
1 #define PETSCMAT_DLL
2 
3 #include "private/matimpl.h"        /*I "petscmat.h" I*/
4 
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 } Mat_Composite;
17 
18 #undef __FUNCT__
19 #define __FUNCT__ "MatDestroy_Composite"
20 PetscErrorCode MatDestroy_Composite(Mat mat)
21 {
22   PetscErrorCode   ierr;
23   Mat_Composite    *shell = (Mat_Composite*)mat->data;
24   Mat_CompositeLink next = shell->head,oldnext;
25 
26   PetscFunctionBegin;
27   while (next) {
28     ierr = MatDestroy(next->mat);CHKERRQ(ierr);
29     if (next->work && (!next->next || next->work != next->next->work)) {
30       ierr = VecDestroy(next->work);CHKERRQ(ierr);
31     }
32     oldnext = next;
33     next     = next->next;
34     ierr     = PetscFree(oldnext);CHKERRQ(ierr);
35   }
36   if (shell->work) {ierr = VecDestroy(shell->work);CHKERRQ(ierr);}
37   ierr      = PetscFree(shell);CHKERRQ(ierr);
38   mat->data = 0;
39   PetscFunctionReturn(0);
40 }
41 
42 #undef __FUNCT__
43 #define __FUNCT__ "MatMult_Composite_Multiplicative"
44 PetscErrorCode MatMult_Composite_Multiplicative(Mat A,Vec x,Vec y)
45 {
46   Mat_Composite     *shell = (Mat_Composite*)A->data;
47   Mat_CompositeLink next = shell->head;
48   PetscErrorCode    ierr;
49   Vec               in,out;
50 
51   PetscFunctionBegin;
52   if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
53   in = x;
54   while (next->next) {
55     if (!next->work) { /* should reuse previous work if the same size */
56       ierr = MatGetVecs(next->mat,PETSC_NULL,&next->work);CHKERRQ(ierr);
57     }
58     out = next->work;
59     ierr = MatMult(next->mat,in,out);CHKERRQ(ierr);
60     in   = out;
61     next = next->next;
62   }
63   ierr = MatMult(next->mat,in,y);CHKERRQ(ierr);
64   PetscFunctionReturn(0);
65 }
66 
67 #undef __FUNCT__
68 #define __FUNCT__ "MatMultTranspose_Composite_Multiplicative"
69 PetscErrorCode MatMultTranspose_Composite_Multiplicative(Mat A,Vec x,Vec y)
70 {
71   Mat_Composite     *shell = (Mat_Composite*)A->data;
72   Mat_CompositeLink tail = shell->tail;
73   PetscErrorCode    ierr;
74   Vec               in,out;
75 
76   PetscFunctionBegin;
77   if (!tail) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
78   in = x;
79   while (tail->prev) {
80     if (!tail->prev->work) { /* should reuse previous work if the same size */
81       ierr = MatGetVecs(tail->mat,PETSC_NULL,&tail->prev->work);CHKERRQ(ierr);
82     }
83     out = tail->prev->work;
84     ierr = MatMultTranspose(tail->mat,in,out);CHKERRQ(ierr);
85     in   = out;
86     tail = tail->prev;
87   }
88   ierr = MatMultTranspose(tail->mat,in,y);CHKERRQ(ierr);
89   PetscFunctionReturn(0);
90 }
91 
92 #undef __FUNCT__
93 #define __FUNCT__ "MatMult_Composite"
94 PetscErrorCode MatMult_Composite(Mat A,Vec x,Vec y)
95 {
96   Mat_Composite     *shell = (Mat_Composite*)A->data;
97   Mat_CompositeLink next = shell->head;
98   PetscErrorCode    ierr;
99 
100   PetscFunctionBegin;
101   if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
102   ierr = MatMult(next->mat,x,y);CHKERRQ(ierr);
103   while ((next = next->next)) {
104     ierr = MatMultAdd(next->mat,x,y,y);CHKERRQ(ierr);
105   }
106   PetscFunctionReturn(0);
107 }
108 
109 #undef __FUNCT__
110 #define __FUNCT__ "MatMultTranspose_Composite"
111 PetscErrorCode MatMultTranspose_Composite(Mat A,Vec x,Vec y)
112 {
113   Mat_Composite     *shell = (Mat_Composite*)A->data;
114   Mat_CompositeLink next = shell->head;
115   PetscErrorCode    ierr;
116 
117   PetscFunctionBegin;
118   if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
119   ierr = MatMultTranspose(next->mat,x,y);CHKERRQ(ierr);
120   while ((next = next->next)) {
121     ierr = MatMultTransposeAdd(next->mat,x,y,y);CHKERRQ(ierr);
122   }
123   PetscFunctionReturn(0);
124 }
125 
126 #undef __FUNCT__
127 #define __FUNCT__ "MatGetDiagonal_Composite"
128 PetscErrorCode MatGetDiagonal_Composite(Mat A,Vec v)
129 {
130   Mat_Composite     *shell = (Mat_Composite*)A->data;
131   Mat_CompositeLink next = shell->head;
132   PetscErrorCode    ierr;
133 
134   PetscFunctionBegin;
135   if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
136   ierr = MatGetDiagonal(next->mat,v);CHKERRQ(ierr);
137   if (next->next && !shell->work) {
138     ierr = VecDuplicate(v,&shell->work);CHKERRQ(ierr);
139   }
140   while ((next = next->next)) {
141     ierr = MatGetDiagonal(next->mat,shell->work);CHKERRQ(ierr);
142     ierr = VecAXPY(v,1.0,shell->work);CHKERRQ(ierr);
143   }
144   PetscFunctionReturn(0);
145 }
146 
147 #undef __FUNCT__
148 #define __FUNCT__ "MatAssemblyEnd_Composite"
149 PetscErrorCode MatAssemblyEnd_Composite(Mat Y,MatAssemblyType t)
150 {
151   PetscErrorCode ierr;
152   PetscTruth     flg;
153 
154   PetscFunctionBegin;
155   ierr = PetscOptionsHasName(((PetscObject)Y)->prefix,"-mat_composite_merge",&flg);CHKERRQ(ierr);
156   if (flg) {
157     ierr = MatCompositeMerge(Y);CHKERRQ(ierr);
158   }
159   PetscFunctionReturn(0);
160 }
161 
162 
163 static struct _MatOps MatOps_Values = {0,
164        0,
165        0,
166        MatMult_Composite,
167        0,
168 /* 5*/ MatMultTranspose_Composite,
169        0,
170        0,
171        0,
172        0,
173 /*10*/ 0,
174        0,
175        0,
176        0,
177        0,
178 /*15*/ 0,
179        0,
180        MatGetDiagonal_Composite,
181        0,
182        0,
183 /*20*/ 0,
184        MatAssemblyEnd_Composite,
185        0,
186        0,
187        0,
188 /*25*/ 0,
189        0,
190        0,
191        0,
192        0,
193 /*30*/ 0,
194        0,
195        0,
196        0,
197        0,
198 /*35*/ 0,
199        0,
200        0,
201        0,
202        0,
203 /*40*/ 0,
204        0,
205        0,
206        0,
207        0,
208 /*45*/ 0,
209        0,
210        0,
211        0,
212        0,
213 /*50*/ 0,
214        0,
215        0,
216        0,
217        0,
218 /*55*/ 0,
219        0,
220        0,
221        0,
222        0,
223 /*60*/ 0,
224        MatDestroy_Composite,
225        0,
226        0,
227        0,
228 /*65*/ 0,
229        0,
230        0,
231        0,
232        0,
233 /*70*/ 0,
234        0,
235        0,
236        0,
237        0,
238 /*75*/ 0,
239        0,
240        0,
241        0,
242        0,
243 /*80*/ 0,
244        0,
245        0,
246        0,
247        0,
248 /*85*/ 0,
249        0,
250        0,
251        0,
252        0,
253 /*90*/ 0,
254        0,
255        0,
256        0,
257        0,
258 /*95*/ 0,
259        0,
260        0,
261        0};
262 
263 /*MC
264    MATCOMPOSITE - A matrix defined by the sum (or product) of one or more matrices (all matrices are of same size and parallel layout).
265 
266    Notes: to use the product of the matrices call MatCompositeSetType(mat,MAT_COMPOSITE_MULTIPLICATIVE);
267 
268   Level: advanced
269 
270 .seealso: MatCreateComposite(), MatCompositeAddMat(), MatSetType(), MatCompositeMerge(), MatCompositeSetType(), MatCompositeType
271 M*/
272 
273 EXTERN_C_BEGIN
274 #undef __FUNCT__
275 #define __FUNCT__ "MatCreate_Composite"
276 PetscErrorCode PETSCMAT_DLLEXPORT MatCreate_Composite(Mat A)
277 {
278   Mat_Composite  *b;
279   PetscErrorCode ierr;
280 
281   PetscFunctionBegin;
282   ierr = PetscNewLog(A,Mat_Composite,&b);CHKERRQ(ierr);
283   A->data = (void*)b;
284   ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
285 
286   ierr = PetscMapSetBlockSize(A->rmap,1);CHKERRQ(ierr);
287   ierr = PetscMapSetBlockSize(A->cmap,1);CHKERRQ(ierr);
288   ierr = PetscMapSetUp(A->rmap);CHKERRQ(ierr);
289   ierr = PetscMapSetUp(A->cmap);CHKERRQ(ierr);
290 
291   A->assembled     = PETSC_TRUE;
292   A->preallocated  = PETSC_FALSE;
293   b->type          = MAT_COMPOSITE_ADDITIVE;
294   ierr = PetscObjectChangeTypeName((PetscObject)A,MATCOMPOSITE);CHKERRQ(ierr);
295   PetscFunctionReturn(0);
296 }
297 EXTERN_C_END
298 
299 #undef __FUNCT__
300 #define __FUNCT__ "MatCreateComposite"
301 /*@C
302    MatCreateComposite - Creates a matrix as the sum of zero or more matrices
303 
304   Collective on MPI_Comm
305 
306    Input Parameters:
307 +  comm - MPI communicator
308 .  nmat - number of matrices to put in
309 -  mats - the matrices
310 
311    Output Parameter:
312 .  A - the matrix
313 
314    Level: advanced
315 
316    Notes:
317      Alternative construction
318 $       MatCreate(comm,&mat);
319 $       MatSetSizes(mat,m,n,M,N);
320 $       MatSetType(mat,MATCOMPOSITE);
321 $       MatCompositeAddMat(mat,mats[0]);
322 $       ....
323 $       MatCompositeAddMat(mat,mats[nmat-1]);
324 $       MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
325 $       MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
326 
327      For the multiplicative form the product is mat[nmat-1]*mat[nmat-2]*....*mat[0]
328 
329 .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCompositeMerge(), MatCompositeSetType(), MatCompositeType
330 
331 @*/
332 PetscErrorCode PETSCMAT_DLLEXPORT MatCreateComposite(MPI_Comm comm,PetscInt nmat,const Mat *mats,Mat *mat)
333 {
334   PetscErrorCode ierr;
335   PetscInt       m,n,M,N,i;
336 
337   PetscFunctionBegin;
338   if (nmat < 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Must pass in at least one matrix");
339   PetscValidPointer(mat,3);
340 
341   ierr = MatGetLocalSize(mats[0],&m,&n);CHKERRQ(ierr);
342   ierr = MatGetSize(mats[0],&M,&N);CHKERRQ(ierr);
343   ierr = MatCreate(comm,mat);CHKERRQ(ierr);
344   ierr = MatSetSizes(*mat,m,n,M,N);CHKERRQ(ierr);
345   ierr = MatSetType(*mat,MATCOMPOSITE);CHKERRQ(ierr);
346   for (i=0; i<nmat; i++) {
347     ierr = MatCompositeAddMat(*mat,mats[i]);CHKERRQ(ierr);
348   }
349   ierr = MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
350   ierr = MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
351   PetscFunctionReturn(0);
352 }
353 
354 #undef __FUNCT__
355 #define __FUNCT__ "MatCompositeAddMat"
356 /*@
357     MatCompositeAddMat - add another matrix to a composite matrix
358 
359    Collective on Mat
360 
361     Input Parameters:
362 +   mat - the composite matrix
363 -   smat - the partial matrix
364 
365    Level: advanced
366 
367 .seealso: MatCreateComposite()
368 @*/
369 PetscErrorCode PETSCMAT_DLLEXPORT MatCompositeAddMat(Mat mat,Mat smat)
370 {
371   Mat_Composite     *shell;
372   PetscErrorCode    ierr;
373   Mat_CompositeLink ilink,next;
374 
375   PetscFunctionBegin;
376   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
377   PetscValidHeaderSpecific(smat,MAT_COOKIE,2);
378   ierr        = PetscNewLog(mat,struct _Mat_CompositeLink,&ilink);CHKERRQ(ierr);
379   ilink->next = 0;
380   ierr        = PetscObjectReference((PetscObject)smat);CHKERRQ(ierr);
381   ilink->mat  = smat;
382 
383   shell = (Mat_Composite*)mat->data;
384   next = shell->head;
385   if (!next) {
386     shell->head  = ilink;
387   } else {
388     while (next->next) {
389       next = next->next;
390     }
391     next->next      = ilink;
392     ilink->prev     = next;
393   }
394   shell->tail = ilink;
395   PetscFunctionReturn(0);
396 }
397 
398 #undef __FUNCT__
399 #define __FUNCT__ "MatCompositeSetType"
400 /*@C
401    MatCompositeSetType - Indicates if the matrix is defined as the sum of a set of matrices or the product
402 
403   Collective on MPI_Comm
404 
405    Input Parameters:
406 .  mat - the composite matrix
407 
408 
409    Level: advanced
410 
411    Notes:
412       The MatType of the resulting matrix will be the same as the MatType of the FIRST
413     matrix in the composite matrix.
414 
415 .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MATCOMPOSITE
416 
417 @*/
418 PetscErrorCode PETSCMAT_DLLEXPORT MatCompositeSetType(Mat mat,MatCompositeType type)
419 {
420   Mat_Composite  *b = (Mat_Composite*)mat->data;
421   PetscTruth     flg;
422   PetscErrorCode ierr;
423 
424   PetscFunctionBegin;
425   ierr = PetscTypeCompare((PetscObject)mat,MATCOMPOSITE,&flg);CHKERRQ(ierr);
426   if (!flg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Can only use with composite matrix");
427   if (type == MAT_COMPOSITE_MULTIPLICATIVE) {
428     mat->ops->getdiagonal   = 0;
429     mat->ops->mult          = MatMult_Composite_Multiplicative;
430     mat->ops->multtranspose = MatMultTranspose_Composite_Multiplicative;
431     b->type                 = MAT_COMPOSITE_MULTIPLICATIVE;
432   } else {
433     mat->ops->getdiagonal   = MatGetDiagonal_Composite;
434     mat->ops->mult          = MatMult_Composite;
435     mat->ops->multtranspose = MatMultTranspose_Composite;
436     b->type                 = MAT_COMPOSITE_ADDITIVE;
437   }
438   PetscFunctionReturn(0);
439 }
440 
441 
442 #undef __FUNCT__
443 #define __FUNCT__ "MatCompositeMerge"
444 /*@C
445    MatCompositeMerge - Given a composite matrix, replaces it with a "regular" matrix
446      by summing all the matrices inside the composite matrix.
447 
448   Collective on MPI_Comm
449 
450    Input Parameters:
451 .  mat - the composite matrix
452 
453 
454    Options Database:
455 .  -mat_composite_merge  (you must call MatAssemblyBegin()/MatAssemblyEnd() to have this checked)
456 
457    Level: advanced
458 
459    Notes:
460       The MatType of the resulting matrix will be the same as the MatType of the FIRST
461     matrix in the composite matrix.
462 
463 .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MATCOMPOSITE
464 
465 @*/
466 PetscErrorCode PETSCMAT_DLLEXPORT MatCompositeMerge(Mat mat)
467 {
468   Mat_Composite     *shell = (Mat_Composite*)mat->data;
469   Mat_CompositeLink next = shell->head, prev = shell->tail;
470   PetscErrorCode    ierr;
471   Mat               tmat,newmat;
472 
473   PetscFunctionBegin;
474   if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
475 
476   PetscFunctionBegin;
477   if (shell->type == MAT_COMPOSITE_ADDITIVE) {
478     ierr = MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);CHKERRQ(ierr);
479     while ((next = next->next)) {
480       ierr = MatAXPY(tmat,1.0,next->mat,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
481     }
482   } else {
483     ierr = MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);CHKERRQ(ierr);
484     while ((prev = prev->prev)) {
485       ierr = MatMatMult(tmat,prev->mat,MAT_INITIAL_MATRIX,PETSC_DECIDE,&newmat);CHKERRQ(ierr);
486       ierr = MatDestroy(tmat);CHKERRQ(ierr);
487       tmat = newmat;
488     }
489   }
490   ierr = MatHeaderReplace(mat,tmat);CHKERRQ(ierr);
491   PetscFunctionReturn(0);
492 }
493