xref: /petsc/src/mat/impls/transpose/transm.c (revision 607e733f3db3ee7f6f605a13295c517df8dbb9c9)
1 #include <../src/mat/impls/shell/shell.h> /*I "petscmat.h" I*/
2 
3 static PetscErrorCode MatMult_Transpose(Mat N, Vec x, Vec y)
4 {
5   Mat A;
6 
7   PetscFunctionBegin;
8   PetscCall(MatShellGetContext(N, &A));
9   PetscCall(MatMultTranspose(A, x, y));
10   PetscFunctionReturn(PETSC_SUCCESS);
11 }
12 
13 static PetscErrorCode MatMultTranspose_Transpose(Mat N, Vec x, Vec y)
14 {
15   Mat A;
16 
17   PetscFunctionBegin;
18   PetscCall(MatShellGetContext(N, &A));
19   PetscCall(MatMult(A, x, y));
20   PetscFunctionReturn(PETSC_SUCCESS);
21 }
22 
23 static PetscErrorCode MatSolve_Transpose_LU(Mat N, Vec b, Vec x)
24 {
25   Mat A;
26 
27   PetscFunctionBegin;
28   PetscCall(MatShellGetContext(N, &A));
29   PetscCall(MatSolveTranspose(A, b, x));
30   PetscFunctionReturn(PETSC_SUCCESS);
31 }
32 
33 static PetscErrorCode MatSolveAdd_Transpose_LU(Mat N, Vec b, Vec y, Vec x)
34 {
35   Mat A;
36 
37   PetscFunctionBegin;
38   PetscCall(MatShellGetContext(N, &A));
39   PetscCall(MatSolveTransposeAdd(A, b, y, x));
40   PetscFunctionReturn(PETSC_SUCCESS);
41 }
42 
43 static PetscErrorCode MatSolveTranspose_Transpose_LU(Mat N, Vec b, Vec x)
44 {
45   Mat A;
46 
47   PetscFunctionBegin;
48   PetscCall(MatShellGetContext(N, &A));
49   PetscCall(MatSolve(A, b, x));
50   PetscFunctionReturn(PETSC_SUCCESS);
51 }
52 
53 static PetscErrorCode MatSolveTransposeAdd_Transpose_LU(Mat N, Vec b, Vec y, Vec x)
54 {
55   Mat A;
56 
57   PetscFunctionBegin;
58   PetscCall(MatShellGetContext(N, &A));
59   PetscCall(MatSolveAdd(A, b, y, x));
60   PetscFunctionReturn(PETSC_SUCCESS);
61 }
62 
63 static PetscErrorCode MatMatSolve_Transpose_LU(Mat N, Mat B, Mat X)
64 {
65   Mat A;
66 
67   PetscFunctionBegin;
68   PetscCall(MatShellGetContext(N, &A));
69   PetscCall(MatMatSolveTranspose(A, B, X));
70   PetscFunctionReturn(PETSC_SUCCESS);
71 }
72 
73 static PetscErrorCode MatMatSolveTranspose_Transpose_LU(Mat N, Mat B, Mat X)
74 {
75   Mat A;
76 
77   PetscFunctionBegin;
78   PetscCall(MatShellGetContext(N, &A));
79   PetscCall(MatMatSolve(A, B, X));
80   PetscFunctionReturn(PETSC_SUCCESS);
81 }
82 
83 static PetscErrorCode MatLUFactor_Transpose(Mat N, IS row, IS col, const MatFactorInfo *minfo)
84 {
85   Mat A;
86 
87   PetscFunctionBegin;
88   PetscCall(MatShellGetContext(N, &A));
89   PetscCall(MatLUFactor(A, col, row, minfo));
90   PetscCall(MatShellSetOperation(N, MATOP_SOLVE, (PetscErrorCodeFn *)MatSolve_Transpose_LU));
91   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_ADD, (PetscErrorCodeFn *)MatSolveAdd_Transpose_LU));
92   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_TRANSPOSE, (PetscErrorCodeFn *)MatSolveTranspose_Transpose_LU));
93   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_TRANSPOSE_ADD, (PetscErrorCodeFn *)MatSolveTransposeAdd_Transpose_LU));
94   PetscCall(MatShellSetOperation(N, MATOP_MAT_SOLVE, (PetscErrorCodeFn *)MatMatSolve_Transpose_LU));
95   PetscCall(MatShellSetOperation(N, MATOP_MAT_SOLVE_TRANSPOSE, (PetscErrorCodeFn *)MatMatSolveTranspose_Transpose_LU));
96   PetscFunctionReturn(PETSC_SUCCESS);
97 }
98 
99 static PetscErrorCode MatSolve_Transpose_Cholesky(Mat N, Vec b, Vec x)
100 {
101   Mat A;
102 
103   PetscFunctionBegin;
104   PetscCall(MatShellGetContext(N, &A));
105   PetscCall(MatSolveTranspose(A, b, x));
106   PetscFunctionReturn(PETSC_SUCCESS);
107 }
108 
109 static PetscErrorCode MatSolveAdd_Transpose_Cholesky(Mat N, Vec b, Vec y, Vec x)
110 {
111   Mat A;
112 
113   PetscFunctionBegin;
114   PetscCall(MatShellGetContext(N, &A));
115   PetscCall(MatSolveTransposeAdd(A, b, y, x));
116   PetscFunctionReturn(PETSC_SUCCESS);
117 }
118 
119 static PetscErrorCode MatSolveTranspose_Transpose_Cholesky(Mat N, Vec b, Vec x)
120 {
121   Mat A;
122 
123   PetscFunctionBegin;
124   PetscCall(MatShellGetContext(N, &A));
125   PetscCall(MatSolve(A, b, x));
126   PetscFunctionReturn(PETSC_SUCCESS);
127 }
128 
129 static PetscErrorCode MatSolveTransposeAdd_Transpose_Cholesky(Mat N, Vec b, Vec y, Vec x)
130 {
131   Mat A;
132 
133   PetscFunctionBegin;
134   PetscCall(MatShellGetContext(N, &A));
135   PetscCall(MatSolveAdd(A, b, y, x));
136   PetscFunctionReturn(PETSC_SUCCESS);
137 }
138 
139 static PetscErrorCode MatMatSolve_Transpose_Cholesky(Mat N, Mat B, Mat X)
140 {
141   Mat A;
142 
143   PetscFunctionBegin;
144   PetscCall(MatShellGetContext(N, &A));
145   PetscCall(MatMatSolveTranspose(A, B, X));
146   PetscFunctionReturn(PETSC_SUCCESS);
147 }
148 
149 static PetscErrorCode MatMatSolveTranspose_Transpose_Cholesky(Mat N, Mat B, Mat X)
150 {
151   Mat A;
152 
153   PetscFunctionBegin;
154   PetscCall(MatShellGetContext(N, &A));
155   PetscCall(MatMatSolve(A, B, X));
156   PetscFunctionReturn(PETSC_SUCCESS);
157 }
158 
159 static PetscErrorCode MatCholeskyFactor_Transpose(Mat N, IS perm, const MatFactorInfo *minfo)
160 {
161   Mat A;
162 
163   PetscFunctionBegin;
164   PetscCall(MatShellGetContext(N, &A));
165   PetscCall(MatCholeskyFactor(A, perm, minfo));
166   PetscCall(MatShellSetOperation(N, MATOP_SOLVE, (PetscErrorCodeFn *)MatSolve_Transpose_Cholesky));
167   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_ADD, (PetscErrorCodeFn *)MatSolveAdd_Transpose_Cholesky));
168   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_TRANSPOSE, (PetscErrorCodeFn *)MatSolveTranspose_Transpose_Cholesky));
169   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_TRANSPOSE_ADD, (PetscErrorCodeFn *)MatSolveTransposeAdd_Transpose_Cholesky));
170   PetscCall(MatShellSetOperation(N, MATOP_MAT_SOLVE, (PetscErrorCodeFn *)MatMatSolve_Transpose_Cholesky));
171   PetscCall(MatShellSetOperation(N, MATOP_MAT_SOLVE_TRANSPOSE, (PetscErrorCodeFn *)MatMatSolveTranspose_Transpose_Cholesky));
172   PetscFunctionReturn(PETSC_SUCCESS);
173 }
174 
175 static PetscErrorCode MatLUFactorNumeric_Transpose(Mat F, Mat N, const MatFactorInfo *info)
176 {
177   Mat A, FA;
178 
179   PetscFunctionBegin;
180   PetscCall(MatShellGetContext(N, &A));
181   PetscCall(MatShellGetContext(F, &FA));
182   PetscCall(MatLUFactorNumeric(FA, A, info));
183   PetscCall(MatShellSetOperation(F, MATOP_SOLVE, (PetscErrorCodeFn *)MatSolve_Transpose_LU));
184   PetscCall(MatShellSetOperation(F, MATOP_SOLVE_ADD, (PetscErrorCodeFn *)MatSolveAdd_Transpose_LU));
185   PetscCall(MatShellSetOperation(F, MATOP_SOLVE_TRANSPOSE, (PetscErrorCodeFn *)MatSolveTranspose_Transpose_LU));
186   PetscCall(MatShellSetOperation(F, MATOP_SOLVE_TRANSPOSE_ADD, (PetscErrorCodeFn *)MatSolveTransposeAdd_Transpose_LU));
187   PetscCall(MatShellSetOperation(F, MATOP_MAT_SOLVE, (PetscErrorCodeFn *)MatMatSolve_Transpose_LU));
188   PetscCall(MatShellSetOperation(F, MATOP_MAT_SOLVE_TRANSPOSE, (PetscErrorCodeFn *)MatMatSolveTranspose_Transpose_LU));
189   PetscFunctionReturn(PETSC_SUCCESS);
190 }
191 
192 static PetscErrorCode MatLUFactorSymbolic_Transpose(Mat F, Mat N, IS row, IS col, const MatFactorInfo *info)
193 {
194   Mat A, FA;
195 
196   PetscFunctionBegin;
197   PetscCall(MatShellGetContext(N, &A));
198   PetscCall(MatShellGetContext(F, &FA));
199   PetscCall(MatLUFactorSymbolic(FA, A, row, col, info));
200   PetscCall(MatShellSetOperation(F, MATOP_LUFACTOR_NUMERIC, (PetscErrorCodeFn *)MatLUFactorNumeric_Transpose));
201   PetscFunctionReturn(PETSC_SUCCESS);
202 }
203 
204 static PetscErrorCode MatCholeskyFactorNumeric_Transpose(Mat F, Mat N, const MatFactorInfo *info)
205 {
206   Mat A, FA;
207 
208   PetscFunctionBegin;
209   PetscCall(MatShellGetContext(N, &A));
210   PetscCall(MatShellGetContext(F, &FA));
211   PetscCall(MatCholeskyFactorNumeric(FA, A, info));
212   PetscCall(MatShellSetOperation(F, MATOP_SOLVE, (PetscErrorCodeFn *)MatSolve_Transpose_Cholesky));
213   PetscCall(MatShellSetOperation(F, MATOP_SOLVE_ADD, (PetscErrorCodeFn *)MatSolveAdd_Transpose_Cholesky));
214   PetscCall(MatShellSetOperation(F, MATOP_SOLVE_TRANSPOSE, (PetscErrorCodeFn *)MatSolveTranspose_Transpose_Cholesky));
215   PetscCall(MatShellSetOperation(F, MATOP_SOLVE_TRANSPOSE_ADD, (PetscErrorCodeFn *)MatSolveTransposeAdd_Transpose_Cholesky));
216   PetscCall(MatShellSetOperation(F, MATOP_MAT_SOLVE, (PetscErrorCodeFn *)MatMatSolve_Transpose_Cholesky));
217   PetscCall(MatShellSetOperation(F, MATOP_MAT_SOLVE_TRANSPOSE, (PetscErrorCodeFn *)MatMatSolveTranspose_Transpose_Cholesky));
218   PetscFunctionReturn(PETSC_SUCCESS);
219 }
220 
221 static PetscErrorCode MatCholeskyFactorSymbolic_Transpose(Mat F, Mat N, IS perm, const MatFactorInfo *info)
222 {
223   Mat A, FA;
224 
225   PetscFunctionBegin;
226   PetscCall(MatShellGetContext(N, &A));
227   PetscCall(MatShellGetContext(F, &FA));
228   PetscCall(MatCholeskyFactorSymbolic(FA, A, perm, info));
229   PetscCall(MatShellSetOperation(F, MATOP_CHOLESKY_FACTOR_NUMERIC, (PetscErrorCodeFn *)MatCholeskyFactorNumeric_Transpose));
230   PetscFunctionReturn(PETSC_SUCCESS);
231 }
232 
233 static PetscErrorCode MatGetFactor_Transpose(Mat N, MatSolverType type, MatFactorType ftype, Mat *F)
234 {
235   Mat A, FA;
236 
237   PetscFunctionBegin;
238   PetscCall(MatShellGetContext(N, &A));
239   PetscCall(MatGetFactor(A, type, ftype, &FA));
240   PetscCall(MatCreateTranspose(FA, F));
241   if (ftype == MAT_FACTOR_LU) PetscCall(MatShellSetOperation(*F, MATOP_LUFACTOR_SYMBOLIC, (PetscErrorCodeFn *)MatLUFactorSymbolic_Transpose));
242   else if (ftype == MAT_FACTOR_CHOLESKY) {
243     PetscCall(MatShellSetOperation(*F, MATOP_CHOLESKY_FACTOR_SYMBOLIC, (PetscErrorCodeFn *)MatCholeskyFactorSymbolic_Transpose));
244     PetscCall(MatPropagateSymmetryOptions(A, FA));
245   } else SETERRQ(PetscObjectComm((PetscObject)N), PETSC_ERR_SUP, "Support for factor type %s not implemented in MATTRANSPOSEVIRTUAL", MatFactorTypes[ftype]);
246   (*F)->factortype = ftype;
247   PetscCall(MatDestroy(&FA));
248   PetscFunctionReturn(PETSC_SUCCESS);
249 }
250 
251 static PetscErrorCode MatDestroy_Transpose(Mat N)
252 {
253   Mat A;
254 
255   PetscFunctionBegin;
256   PetscCall(MatShellGetContext(N, &A));
257   PetscCall(MatDestroy(&A));
258   PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatTransposeGetMat_C", NULL));
259   PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatProductSetFromOptions_anytype_C", NULL));
260   PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatShellSetContext_C", NULL));
261   PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatFactorGetSolverType_C", NULL));
262   PetscFunctionReturn(PETSC_SUCCESS);
263 }
264 
265 static PetscErrorCode MatGetInfo_Transpose(Mat N, MatInfoType flag, MatInfo *info)
266 {
267   Mat A;
268 
269   PetscFunctionBegin;
270   PetscCall(MatShellGetContext(N, &A));
271   PetscCall(MatGetInfo(A, flag, info));
272   PetscFunctionReturn(PETSC_SUCCESS);
273 }
274 
275 static PetscErrorCode MatFactorGetSolverType_Transpose(Mat N, MatSolverType *type)
276 {
277   Mat A;
278 
279   PetscFunctionBegin;
280   PetscCall(MatShellGetContext(N, &A));
281   PetscCall(MatFactorGetSolverType(A, type));
282   PetscFunctionReturn(PETSC_SUCCESS);
283 }
284 
285 static PetscErrorCode MatDuplicate_Transpose(Mat N, MatDuplicateOption op, Mat *m)
286 {
287   Mat A, C;
288 
289   PetscFunctionBegin;
290   PetscCall(MatShellGetContext(N, &A));
291   PetscCall(MatDuplicate(A, op, &C));
292   PetscCall(MatCreateTranspose(C, m));
293   if (op == MAT_COPY_VALUES) PetscCall(MatCopy(N, *m, SAME_NONZERO_PATTERN));
294   PetscCall(MatDestroy(&C));
295   PetscFunctionReturn(PETSC_SUCCESS);
296 }
297 
298 static PetscErrorCode MatHasOperation_Transpose(Mat mat, MatOperation op, PetscBool *has)
299 {
300   Mat A;
301 
302   PetscFunctionBegin;
303   PetscCall(MatShellGetContext(mat, &A));
304   *has = PETSC_FALSE;
305   if (op == MATOP_MULT || op == MATOP_MULT_ADD) {
306     PetscCall(MatHasOperation(A, MATOP_MULT_TRANSPOSE, has));
307   } else if (op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
308     PetscCall(MatHasOperation(A, MATOP_MULT, has));
309   } else if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
310   PetscFunctionReturn(PETSC_SUCCESS);
311 }
312 
313 typedef struct {
314   PetscErrorCode (*numeric)(Mat);
315   PetscCtxDestroyFn *destroy;
316   PetscScalar        scale;
317   PetscContainer     container;
318   void              *data;
319 } MatProductCtx_Transpose;
320 
321 static PetscErrorCode MatProductCtxDestroy_Transpose(PetscCtxRt ptr)
322 {
323   MatProductCtx_Transpose *data = *(MatProductCtx_Transpose **)ptr;
324 
325   PetscFunctionBegin;
326   if (data->data) PetscCall((*data->destroy)(&data->data));
327   PetscCall(PetscContainerDestroy(&data->container));
328   PetscCall(PetscFree(data));
329   PetscFunctionReturn(PETSC_SUCCESS);
330 }
331 
332 static PetscErrorCode MatProductNumeric_Transpose(Mat D)
333 {
334   Mat_Product             *product;
335   MatProductCtx_Transpose *data;
336   PetscContainer           container;
337 
338   PetscFunctionBegin;
339   MatCheckProduct(D, 1);
340   PetscCheck(D->product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data empty");
341   product = D->product;
342   PetscCall(PetscObjectQuery((PetscObject)D, "MatProductCtx_Transpose", (PetscObject *)&container));
343   PetscCheck(container, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "MatProductCtx_Transpose missing");
344   PetscCall(PetscContainerGetPointer(container, &data));
345   data          = (MatProductCtx_Transpose *)product->data;
346   product->data = data->data;
347   PetscCall((*data->numeric)(D));
348   PetscCall(MatScale(D, data->scale));
349   product->data = data;
350   PetscFunctionReturn(PETSC_SUCCESS);
351 }
352 
353 static PetscErrorCode MatProductSymbolic_Transpose(Mat D)
354 {
355   Mat_Product             *product;
356   MatProductCtx_Transpose *data;
357   PetscContainer           container;
358 
359   PetscFunctionBegin;
360   MatCheckProduct(D, 1);
361   product = D->product;
362   if (D->ops->productsymbolic == MatProductSymbolic_Transpose) {
363     PetscCheck(!product->data, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "Product data not empty");
364     PetscCall(PetscObjectQuery((PetscObject)D, "MatProductCtx_Transpose", (PetscObject *)&container));
365     PetscCheck(container, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "MatProductCtx_Transpose missing");
366     PetscCall(PetscContainerGetPointer(container, &data));
367     PetscCall(MatProductSetFromOptions(D));
368     PetscCall(MatProductSymbolic(D));
369     data->numeric          = D->ops->productnumeric;
370     data->destroy          = product->destroy;
371     data->data             = product->data;
372     D->ops->productnumeric = MatProductNumeric_Transpose;
373     product->destroy       = MatProductCtxDestroy_Transpose;
374     product->data          = data;
375   }
376   PetscFunctionReturn(PETSC_SUCCESS);
377 }
378 
379 static PetscErrorCode MatProductSetFromOptions_Transpose(Mat D)
380 {
381   Mat                      A, B, C, Ain, Bin, Cin;
382   PetscScalar              scale = 1.0, vscale;
383   PetscBool                Aistrans, Bistrans, Cistrans;
384   PetscInt                 Atrans, Btrans, Ctrans;
385   PetscContainer           container = NULL;
386   MatProductCtx_Transpose *data;
387   MatProductType           ptype;
388 
389   PetscFunctionBegin;
390   MatCheckProduct(D, 1);
391   A = D->product->A;
392   B = D->product->B;
393   C = D->product->C;
394   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATTRANSPOSEVIRTUAL, &Aistrans));
395   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &Bistrans));
396   PetscCall(PetscObjectTypeCompare((PetscObject)C, MATTRANSPOSEVIRTUAL, &Cistrans));
397   PetscCheck(Aistrans || Bistrans || Cistrans, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "This should not happen");
398   Atrans = 0;
399   Ain    = A;
400   while (Aistrans) {
401     Atrans++;
402     PetscCall(MatShellGetScalingShifts(Ain, (PetscScalar *)MAT_SHELL_NOT_ALLOWED, &vscale, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
403     scale *= vscale;
404     PetscCall(MatTransposeGetMat(Ain, &Ain));
405     PetscCall(PetscObjectTypeCompare((PetscObject)Ain, MATTRANSPOSEVIRTUAL, &Aistrans));
406   }
407   Btrans = 0;
408   Bin    = B;
409   while (Bistrans) {
410     Btrans++;
411     PetscCall(MatShellGetScalingShifts(Bin, (PetscScalar *)MAT_SHELL_NOT_ALLOWED, &vscale, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
412     scale *= vscale;
413     PetscCall(MatTransposeGetMat(Bin, &Bin));
414     PetscCall(PetscObjectTypeCompare((PetscObject)Bin, MATTRANSPOSEVIRTUAL, &Bistrans));
415   }
416   Ctrans = 0;
417   Cin    = C;
418   while (Cistrans) {
419     Ctrans++;
420     PetscCall(MatShellGetScalingShifts(Cin, (PetscScalar *)MAT_SHELL_NOT_ALLOWED, &vscale, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
421     scale *= vscale;
422     PetscCall(MatTransposeGetMat(Cin, &Cin));
423     PetscCall(PetscObjectTypeCompare((PetscObject)Cin, MATTRANSPOSEVIRTUAL, &Cistrans));
424   }
425   Atrans = Atrans % 2;
426   Btrans = Btrans % 2;
427   Ctrans = Ctrans % 2;
428   ptype  = D->product->type; /* same product type by default */
429   if (Ain->symmetric == PETSC_BOOL3_TRUE) Atrans = 0;
430   if (Bin->symmetric == PETSC_BOOL3_TRUE) Btrans = 0;
431   if (Cin && Cin->symmetric == PETSC_BOOL3_TRUE) Ctrans = 0;
432 
433   if (Atrans || Btrans || Ctrans) {
434     if (scale != 1.0) {
435       PetscCall(PetscObjectQuery((PetscObject)D, "MatProductCtx_Transpose", (PetscObject *)&container));
436       if (!container) {
437         PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)D), &container));
438         PetscCall(PetscNew(&data));
439         PetscCall(PetscContainerSetPointer(container, data));
440         PetscCall(PetscObjectCompose((PetscObject)D, "MatProductCtx_Transpose", (PetscObject)container));
441       } else PetscCall(PetscContainerGetPointer(container, &data));
442       data->scale     = scale;
443       data->container = container;
444     }
445     ptype = MATPRODUCT_UNSPECIFIED;
446     switch (D->product->type) {
447     case MATPRODUCT_AB:
448       if (Atrans && Btrans) { /* At * Bt we do not have support for this */
449         /* TODO custom implementation ? */
450       } else if (Atrans) { /* At * B */
451         ptype = MATPRODUCT_AtB;
452       } else { /* A * Bt */
453         ptype = MATPRODUCT_ABt;
454       }
455       break;
456     case MATPRODUCT_AtB:
457       if (Atrans && Btrans) { /* A * Bt */
458         ptype = MATPRODUCT_ABt;
459       } else if (Atrans) { /* A * B */
460         ptype = MATPRODUCT_AB;
461       } else { /* At * Bt we do not have support for this */
462         /* TODO custom implementation ? */
463       }
464       break;
465     case MATPRODUCT_ABt:
466       if (Atrans && Btrans) { /* At * B */
467         ptype = MATPRODUCT_AtB;
468       } else if (Atrans) { /* At * Bt we do not have support for this */
469         /* TODO custom implementation ? */
470       } else { /* A * B */
471         ptype = MATPRODUCT_AB;
472       }
473       break;
474     case MATPRODUCT_PtAP:
475       if (Atrans) { /* PtAtP */
476         /* TODO custom implementation ? */
477       } else { /* RARt */
478         ptype = MATPRODUCT_RARt;
479       }
480       break;
481     case MATPRODUCT_RARt:
482       if (Atrans) { /* RAtRt */
483         /* TODO custom implementation ? */
484       } else { /* PtAP */
485         ptype = MATPRODUCT_PtAP;
486       }
487       break;
488     case MATPRODUCT_ABC:
489       /* TODO custom implementation ? */
490       break;
491     default:
492       SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[D->product->type]);
493     }
494   }
495   PetscCall(MatProductReplaceMats(Ain, Bin, Cin, D));
496   PetscCall(MatProductSetType(D, ptype));
497   if (container) D->ops->productsymbolic = MatProductSymbolic_Transpose;
498   else PetscCall(MatProductSetFromOptions(D));
499   PetscFunctionReturn(PETSC_SUCCESS);
500 }
501 
502 static PetscErrorCode MatGetDiagonal_Transpose(Mat N, Vec v)
503 {
504   Mat A;
505 
506   PetscFunctionBegin;
507   PetscCall(MatShellGetContext(N, &A));
508   PetscCall(MatGetDiagonal(A, v));
509   PetscFunctionReturn(PETSC_SUCCESS);
510 }
511 
512 static PetscErrorCode MatCopy_Transpose(Mat A, Mat B, MatStructure str)
513 {
514   Mat a, b;
515 
516   PetscFunctionBegin;
517   PetscCall(MatShellGetContext(A, &a));
518   PetscCall(MatShellGetContext(B, &b));
519   PetscCall(MatCopy(a, b, str));
520   PetscFunctionReturn(PETSC_SUCCESS);
521 }
522 
523 static PetscErrorCode MatConvert_Transpose(Mat N, MatType newtype, MatReuse reuse, Mat *newmat)
524 {
525   Mat         A;
526   PetscScalar vscale = 1.0, vshift = 0.0;
527   PetscBool   flg;
528 
529   PetscFunctionBegin;
530   PetscCall(MatShellGetContext(N, &A));
531   PetscCall(MatHasOperation(A, MATOP_TRANSPOSE, &flg));
532   if (flg || N->ops->getrow) { /* if this condition is false, MatConvert_Shell() will be called in MatConvert_Basic(), so the following checks are not needed */
533     PetscCall(MatShellGetScalingShifts(N, &vshift, &vscale, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Vec *)MAT_SHELL_NOT_ALLOWED, (Mat *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED, (IS *)MAT_SHELL_NOT_ALLOWED));
534   }
535   if (flg) {
536     Mat B;
537 
538     PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &B));
539     if (reuse != MAT_INPLACE_MATRIX) {
540       PetscCall(MatConvert(B, newtype, reuse, newmat));
541       PetscCall(MatDestroy(&B));
542     } else {
543       PetscCall(MatConvert(B, newtype, MAT_INPLACE_MATRIX, &B));
544       PetscCall(MatHeaderReplace(N, &B));
545     }
546   } else { /* use basic converter as fallback */
547     flg = (PetscBool)(N->ops->getrow != NULL);
548     PetscCall(MatConvert_Basic(N, newtype, reuse, newmat));
549   }
550   if (flg) {
551     PetscCall(MatScale(*newmat, vscale));
552     PetscCall(MatShift(*newmat, vshift));
553   }
554   PetscFunctionReturn(PETSC_SUCCESS);
555 }
556 
557 static PetscErrorCode MatTransposeGetMat_Transpose(Mat N, Mat *M)
558 {
559   PetscFunctionBegin;
560   PetscCall(MatShellGetContext(N, M));
561   PetscFunctionReturn(PETSC_SUCCESS);
562 }
563 
564 /*@
565   MatTransposeGetMat - Gets the `Mat` object stored inside a `MATTRANSPOSEVIRTUAL`
566 
567   Logically Collective
568 
569   Input Parameter:
570 . A - the `MATTRANSPOSEVIRTUAL` matrix
571 
572   Output Parameter:
573 . M - the matrix object stored inside `A`
574 
575   Level: intermediate
576 
577 .seealso: [](ch_matrices), `Mat`, `MATTRANSPOSEVIRTUAL`, `MatCreateTranspose()`
578 @*/
579 PetscErrorCode MatTransposeGetMat(Mat A, Mat *M)
580 {
581   PetscFunctionBegin;
582   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
583   PetscValidType(A, 1);
584   PetscAssertPointer(M, 2);
585   PetscUseMethod(A, "MatTransposeGetMat_C", (Mat, Mat *), (A, M));
586   PetscFunctionReturn(PETSC_SUCCESS);
587 }
588 
589 /*MC
590    MATTRANSPOSEVIRTUAL - "transpose" - A matrix type that represents a virtual transpose of a matrix
591 
592   Level: advanced
593 
594   Developer Notes:
595   This is implemented on top of `MATSHELL` to get support for scaling and shifting without requiring duplicate code
596 
597   Users can not call `MatShellSetOperation()` operations on this class, there is some error checking for that incorrect usage
598 
599 .seealso: [](ch_matrices), `Mat`, `MATHERMITIANTRANSPOSEVIRTUAL`, `Mat`, `MatCreateHermitianTranspose()`, `MatCreateTranspose()`,
600           `MATNORMALHERMITIAN`, `MATNORMAL`
601 M*/
602 
603 /*@
604   MatCreateTranspose - Creates a new matrix `MATTRANSPOSEVIRTUAL` object that behaves like A'
605 
606   Collective
607 
608   Input Parameter:
609 . A - the (possibly rectangular) matrix
610 
611   Output Parameter:
612 . N - the matrix that represents A'
613 
614   Level: intermediate
615 
616   Note:
617   The transpose A' is NOT actually formed! Rather the new matrix
618   object performs the matrix-vector product by using the `MatMultTranspose()` on
619   the original matrix
620 
621 .seealso: [](ch_matrices), `Mat`, `MATTRANSPOSEVIRTUAL`, `MatCreateNormal()`, `MatMult()`, `MatMultTranspose()`, `MatCreate()`,
622           `MATNORMALHERMITIAN`
623 @*/
624 PetscErrorCode MatCreateTranspose(Mat A, Mat *N)
625 {
626   VecType vtype;
627 
628   PetscFunctionBegin;
629   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), N));
630   PetscCall(PetscLayoutReference(A->rmap, &((*N)->cmap)));
631   PetscCall(PetscLayoutReference(A->cmap, &((*N)->rmap)));
632   PetscCall(MatSetType(*N, MATSHELL));
633   PetscCall(MatShellSetContext(*N, A));
634   PetscCall(PetscObjectReference((PetscObject)A));
635 
636   PetscCall(MatSetBlockSizes(*N, A->cmap->bs, A->rmap->bs));
637   PetscCall(MatGetVecType(A, &vtype));
638   PetscCall(MatSetVecType(*N, vtype));
639 #if defined(PETSC_HAVE_DEVICE)
640   PetscCall(MatBindToCPU(*N, A->boundtocpu));
641 #endif
642   PetscCall(MatSetUp(*N));
643 
644   PetscCall(MatShellSetOperation(*N, MATOP_DESTROY, (PetscErrorCodeFn *)MatDestroy_Transpose));
645   PetscCall(MatShellSetOperation(*N, MATOP_MULT, (PetscErrorCodeFn *)MatMult_Transpose));
646   PetscCall(MatShellSetOperation(*N, MATOP_MULT_TRANSPOSE, (PetscErrorCodeFn *)MatMultTranspose_Transpose));
647   PetscCall(MatShellSetOperation(*N, MATOP_LUFACTOR, (PetscErrorCodeFn *)MatLUFactor_Transpose));
648   PetscCall(MatShellSetOperation(*N, MATOP_CHOLESKYFACTOR, (PetscErrorCodeFn *)MatCholeskyFactor_Transpose));
649   PetscCall(MatShellSetOperation(*N, MATOP_GET_FACTOR, (PetscErrorCodeFn *)MatGetFactor_Transpose));
650   PetscCall(MatShellSetOperation(*N, MATOP_GETINFO, (PetscErrorCodeFn *)MatGetInfo_Transpose));
651   PetscCall(MatShellSetOperation(*N, MATOP_DUPLICATE, (PetscErrorCodeFn *)MatDuplicate_Transpose));
652   PetscCall(MatShellSetOperation(*N, MATOP_HAS_OPERATION, (PetscErrorCodeFn *)MatHasOperation_Transpose));
653   PetscCall(MatShellSetOperation(*N, MATOP_GET_DIAGONAL, (PetscErrorCodeFn *)MatGetDiagonal_Transpose));
654   PetscCall(MatShellSetOperation(*N, MATOP_COPY, (PetscErrorCodeFn *)MatCopy_Transpose));
655   PetscCall(MatShellSetOperation(*N, MATOP_CONVERT, (PetscErrorCodeFn *)MatConvert_Transpose));
656 
657   PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatTransposeGetMat_C", MatTransposeGetMat_Transpose));
658   PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatProductSetFromOptions_anytype_C", MatProductSetFromOptions_Transpose));
659   PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatFactorGetSolverType_C", MatFactorGetSolverType_Transpose));
660   PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatShellSetContext_C", MatShellSetContext_Immutable));
661   PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Immutable));
662   PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Immutable));
663   PetscCall(PetscObjectChangeTypeName((PetscObject)*N, MATTRANSPOSEVIRTUAL));
664   PetscFunctionReturn(PETSC_SUCCESS);
665 }
666