xref: /petsc/src/mat/impls/transpose/transm.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
1 
2 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
3 
4 typedef struct {
5   Mat A;
6 } Mat_Transpose;
7 
8 PetscErrorCode MatMult_Transpose(Mat N, Vec x, Vec y) {
9   Mat_Transpose *Na = (Mat_Transpose *)N->data;
10 
11   PetscFunctionBegin;
12   PetscCall(MatMultTranspose(Na->A, x, y));
13   PetscFunctionReturn(0);
14 }
15 
16 PetscErrorCode MatMultAdd_Transpose(Mat N, Vec v1, Vec v2, Vec v3) {
17   Mat_Transpose *Na = (Mat_Transpose *)N->data;
18 
19   PetscFunctionBegin;
20   PetscCall(MatMultTransposeAdd(Na->A, v1, v2, v3));
21   PetscFunctionReturn(0);
22 }
23 
24 PetscErrorCode MatMultTranspose_Transpose(Mat N, Vec x, Vec y) {
25   Mat_Transpose *Na = (Mat_Transpose *)N->data;
26 
27   PetscFunctionBegin;
28   PetscCall(MatMult(Na->A, x, y));
29   PetscFunctionReturn(0);
30 }
31 
32 PetscErrorCode MatMultTransposeAdd_Transpose(Mat N, Vec v1, Vec v2, Vec v3) {
33   Mat_Transpose *Na = (Mat_Transpose *)N->data;
34 
35   PetscFunctionBegin;
36   PetscCall(MatMultAdd(Na->A, v1, v2, v3));
37   PetscFunctionReturn(0);
38 }
39 
40 PetscErrorCode MatDestroy_Transpose(Mat N) {
41   Mat_Transpose *Na = (Mat_Transpose *)N->data;
42 
43   PetscFunctionBegin;
44   PetscCall(MatDestroy(&Na->A));
45   PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatTransposeGetMat_C", NULL));
46   PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatProductSetFromOptions_anytype_C", NULL));
47   PetscCall(PetscFree(N->data));
48   PetscFunctionReturn(0);
49 }
50 
51 PetscErrorCode MatDuplicate_Transpose(Mat N, MatDuplicateOption op, Mat *m) {
52   Mat_Transpose *Na = (Mat_Transpose *)N->data;
53 
54   PetscFunctionBegin;
55   if (op == MAT_COPY_VALUES) {
56     PetscCall(MatTranspose(Na->A, MAT_INITIAL_MATRIX, m));
57   } else if (op == MAT_DO_NOT_COPY_VALUES) {
58     PetscCall(MatDuplicate(Na->A, MAT_DO_NOT_COPY_VALUES, m));
59     PetscCall(MatTranspose(*m, MAT_INPLACE_MATRIX, m));
60   } else SETERRQ(PetscObjectComm((PetscObject)N), PETSC_ERR_SUP, "MAT_SHARE_NONZERO_PATTERN not supported for this matrix type");
61   PetscFunctionReturn(0);
62 }
63 
64 PetscErrorCode MatCreateVecs_Transpose(Mat A, Vec *r, Vec *l) {
65   Mat_Transpose *Aa = (Mat_Transpose *)A->data;
66 
67   PetscFunctionBegin;
68   PetscCall(MatCreateVecs(Aa->A, l, r));
69   PetscFunctionReturn(0);
70 }
71 
72 PetscErrorCode MatAXPY_Transpose(Mat Y, PetscScalar a, Mat X, MatStructure str) {
73   Mat_Transpose *Ya = (Mat_Transpose *)Y->data;
74   Mat_Transpose *Xa = (Mat_Transpose *)X->data;
75   Mat            M  = Ya->A;
76   Mat            N  = Xa->A;
77 
78   PetscFunctionBegin;
79   PetscCall(MatAXPY(M, a, N, str));
80   PetscFunctionReturn(0);
81 }
82 
83 PetscErrorCode MatHasOperation_Transpose(Mat mat, MatOperation op, PetscBool *has) {
84   Mat_Transpose *X = (Mat_Transpose *)mat->data;
85   PetscFunctionBegin;
86 
87   *has = PETSC_FALSE;
88   if (op == MATOP_MULT) {
89     PetscCall(MatHasOperation(X->A, MATOP_MULT_TRANSPOSE, has));
90   } else if (op == MATOP_MULT_TRANSPOSE) {
91     PetscCall(MatHasOperation(X->A, MATOP_MULT, has));
92   } else if (op == MATOP_MULT_ADD) {
93     PetscCall(MatHasOperation(X->A, MATOP_MULT_TRANSPOSE_ADD, has));
94   } else if (op == MATOP_MULT_TRANSPOSE_ADD) {
95     PetscCall(MatHasOperation(X->A, MATOP_MULT_ADD, has));
96   } else if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
97   PetscFunctionReturn(0);
98 }
99 
100 /* used by hermitian transpose */
101 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Transpose(Mat D) {
102   Mat            A, B, C, Ain, Bin, Cin;
103   PetscBool      Aistrans, Bistrans, Cistrans;
104   PetscInt       Atrans, Btrans, Ctrans;
105   MatProductType ptype;
106 
107   PetscFunctionBegin;
108   MatCheckProduct(D, 1);
109   A = D->product->A;
110   B = D->product->B;
111   C = D->product->C;
112   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATTRANSPOSEMAT, &Aistrans));
113   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEMAT, &Bistrans));
114   PetscCall(PetscObjectTypeCompare((PetscObject)C, MATTRANSPOSEMAT, &Cistrans));
115   PetscCheck(Aistrans || Bistrans || Cistrans, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "This should not happen");
116   Atrans = 0;
117   Ain    = A;
118   while (Aistrans) {
119     Atrans++;
120     PetscCall(MatTransposeGetMat(Ain, &Ain));
121     PetscCall(PetscObjectTypeCompare((PetscObject)Ain, MATTRANSPOSEMAT, &Aistrans));
122   }
123   Btrans = 0;
124   Bin    = B;
125   while (Bistrans) {
126     Btrans++;
127     PetscCall(MatTransposeGetMat(Bin, &Bin));
128     PetscCall(PetscObjectTypeCompare((PetscObject)Bin, MATTRANSPOSEMAT, &Bistrans));
129   }
130   Ctrans = 0;
131   Cin    = C;
132   while (Cistrans) {
133     Ctrans++;
134     PetscCall(MatTransposeGetMat(Cin, &Cin));
135     PetscCall(PetscObjectTypeCompare((PetscObject)Cin, MATTRANSPOSEMAT, &Cistrans));
136   }
137   Atrans = Atrans % 2;
138   Btrans = Btrans % 2;
139   Ctrans = Ctrans % 2;
140   ptype  = D->product->type; /* same product type by default */
141   if (Ain->symmetric == PETSC_BOOL3_TRUE) Atrans = 0;
142   if (Bin->symmetric == PETSC_BOOL3_TRUE) Btrans = 0;
143   if (Cin && Cin->symmetric == PETSC_BOOL3_TRUE) Ctrans = 0;
144 
145   if (Atrans || Btrans || Ctrans) {
146     ptype = MATPRODUCT_UNSPECIFIED;
147     switch (D->product->type) {
148     case MATPRODUCT_AB:
149       if (Atrans && Btrans) { /* At * Bt we do not have support for this */
150         /* TODO custom implementation ? */
151       } else if (Atrans) { /* At * B */
152         ptype = MATPRODUCT_AtB;
153       } else { /* A * Bt */
154         ptype = MATPRODUCT_ABt;
155       }
156       break;
157     case MATPRODUCT_AtB:
158       if (Atrans && Btrans) { /* A * Bt */
159         ptype = MATPRODUCT_ABt;
160       } else if (Atrans) { /* A * B */
161         ptype = MATPRODUCT_AB;
162       } else { /* At * Bt we do not have support for this */
163         /* TODO custom implementation ? */
164       }
165       break;
166     case MATPRODUCT_ABt:
167       if (Atrans && Btrans) { /* At * B */
168         ptype = MATPRODUCT_AtB;
169       } else if (Atrans) { /* At * Bt we do not have support for this */
170         /* TODO custom implementation ? */
171       } else { /* A * B */
172         ptype = MATPRODUCT_AB;
173       }
174       break;
175     case MATPRODUCT_PtAP:
176       if (Atrans) { /* PtAtP */
177         /* TODO custom implementation ? */
178       } else { /* RARt */
179         ptype = MATPRODUCT_RARt;
180       }
181       break;
182     case MATPRODUCT_RARt:
183       if (Atrans) { /* RAtRt */
184         /* TODO custom implementation ? */
185       } else { /* PtAP */
186         ptype = MATPRODUCT_PtAP;
187       }
188       break;
189     case MATPRODUCT_ABC:
190       /* TODO custom implementation ? */
191       break;
192     default: SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[D->product->type]);
193     }
194   }
195   PetscCall(MatProductReplaceMats(Ain, Bin, Cin, D));
196   PetscCall(MatProductSetType(D, ptype));
197   PetscCall(MatProductSetFromOptions(D));
198   PetscFunctionReturn(0);
199 }
200 
201 PetscErrorCode MatGetDiagonal_Transpose(Mat A, Vec v) {
202   Mat_Transpose *Aa = (Mat_Transpose *)A->data;
203 
204   PetscFunctionBegin;
205   PetscCall(MatGetDiagonal(Aa->A, v));
206   PetscFunctionReturn(0);
207 }
208 
209 PetscErrorCode MatConvert_Transpose(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) {
210   Mat_Transpose *Aa = (Mat_Transpose *)A->data;
211   PetscBool      flg;
212 
213   PetscFunctionBegin;
214   PetscCall(MatHasOperation(Aa->A, MATOP_TRANSPOSE, &flg));
215   if (flg) {
216     Mat B;
217 
218     PetscCall(MatTranspose(Aa->A, MAT_INITIAL_MATRIX, &B));
219     if (reuse != MAT_INPLACE_MATRIX) {
220       PetscCall(MatConvert(B, newtype, reuse, newmat));
221       PetscCall(MatDestroy(&B));
222     } else {
223       PetscCall(MatConvert(B, newtype, MAT_INPLACE_MATRIX, &B));
224       PetscCall(MatHeaderReplace(A, &B));
225     }
226   } else { /* use basic converter as fallback */
227     PetscCall(MatConvert_Basic(A, newtype, reuse, newmat));
228   }
229   PetscFunctionReturn(0);
230 }
231 
232 PetscErrorCode MatTransposeGetMat_Transpose(Mat A, Mat *M) {
233   Mat_Transpose *Aa = (Mat_Transpose *)A->data;
234 
235   PetscFunctionBegin;
236   *M = Aa->A;
237   PetscFunctionReturn(0);
238 }
239 
240 /*@
241       MatTransposeGetMat - Gets the Mat object stored inside a MATTRANSPOSEMAT
242 
243    Logically collective on Mat
244 
245    Input Parameter:
246 .   A  - the MATTRANSPOSE matrix
247 
248    Output Parameter:
249 .   M - the matrix object stored inside A
250 
251    Level: intermediate
252 
253 .seealso: `MatCreateTranspose()`
254 
255 @*/
256 PetscErrorCode MatTransposeGetMat(Mat A, Mat *M) {
257   PetscFunctionBegin;
258   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
259   PetscValidType(A, 1);
260   PetscValidPointer(M, 2);
261   PetscUseMethod(A, "MatTransposeGetMat_C", (Mat, Mat *), (A, M));
262   PetscFunctionReturn(0);
263 }
264 
265 /*@
266       MatCreateTranspose - Creates a new matrix object that behaves like A'
267 
268    Collective on Mat
269 
270    Input Parameter:
271 .   A  - the (possibly rectangular) matrix
272 
273    Output Parameter:
274 .   N - the matrix that represents A'
275 
276    Level: intermediate
277 
278    Notes:
279     The transpose A' is NOT actually formed! Rather the new matrix
280           object performs the matrix-vector product by using the MatMultTranspose() on
281           the original matrix
282 
283 .seealso: `MatCreateNormal()`, `MatMult()`, `MatMultTranspose()`, `MatCreate()`
284 
285 @*/
286 PetscErrorCode MatCreateTranspose(Mat A, Mat *N) {
287   PetscInt       m, n;
288   Mat_Transpose *Na;
289   VecType        vtype;
290 
291   PetscFunctionBegin;
292   PetscCall(MatGetLocalSize(A, &m, &n));
293   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), N));
294   PetscCall(MatSetSizes(*N, n, m, PETSC_DECIDE, PETSC_DECIDE));
295   PetscCall(PetscLayoutSetUp((*N)->rmap));
296   PetscCall(PetscLayoutSetUp((*N)->cmap));
297   PetscCall(PetscObjectChangeTypeName((PetscObject)*N, MATTRANSPOSEMAT));
298 
299   PetscCall(PetscNewLog(*N, &Na));
300   (*N)->data = (void *)Na;
301   PetscCall(PetscObjectReference((PetscObject)A));
302   Na->A = A;
303 
304   (*N)->ops->destroy               = MatDestroy_Transpose;
305   (*N)->ops->mult                  = MatMult_Transpose;
306   (*N)->ops->multadd               = MatMultAdd_Transpose;
307   (*N)->ops->multtranspose         = MatMultTranspose_Transpose;
308   (*N)->ops->multtransposeadd      = MatMultTransposeAdd_Transpose;
309   (*N)->ops->duplicate             = MatDuplicate_Transpose;
310   (*N)->ops->getvecs               = MatCreateVecs_Transpose;
311   (*N)->ops->axpy                  = MatAXPY_Transpose;
312   (*N)->ops->hasoperation          = MatHasOperation_Transpose;
313   (*N)->ops->productsetfromoptions = MatProductSetFromOptions_Transpose;
314   (*N)->ops->getdiagonal           = MatGetDiagonal_Transpose;
315   (*N)->ops->convert               = MatConvert_Transpose;
316   (*N)->assembled                  = PETSC_TRUE;
317 
318   PetscCall(PetscObjectComposeFunction((PetscObject)(*N), "MatTransposeGetMat_C", MatTransposeGetMat_Transpose));
319   PetscCall(PetscObjectComposeFunction((PetscObject)(*N), "MatProductSetFromOptions_anytype_C", MatProductSetFromOptions_Transpose));
320   PetscCall(MatSetBlockSizes(*N, PetscAbs(A->cmap->bs), PetscAbs(A->rmap->bs)));
321   PetscCall(MatGetVecType(A, &vtype));
322   PetscCall(MatSetVecType(*N, vtype));
323 #if defined(PETSC_HAVE_DEVICE)
324   PetscCall(MatBindToCPU(*N, A->boundtocpu));
325 #endif
326   PetscCall(MatSetUp(*N));
327   PetscFunctionReturn(0);
328 }
329