xref: /petsc/src/mat/impls/transpose/transm.c (revision f1769f9d415d9491324134ec5d493a36ebb01003)
1a1f56445SPierre Jolivet #include <../src/mat/impls/shell/shell.h> /*I "petscmat.h" I*/
285e3dda7SBarry Smith 
366976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Transpose(Mat N, Vec x, Vec y)
4d71ae5a4SJacob Faibussowitsch {
5bf477422SJose E. Roman   Mat A;
685e3dda7SBarry Smith 
785e3dda7SBarry Smith   PetscFunctionBegin;
8bf477422SJose E. Roman   PetscCall(MatShellGetContext(N, &A));
9bf477422SJose E. Roman   PetscCall(MatMultTranspose(A, x, y));
103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1185e3dda7SBarry Smith }
1285e3dda7SBarry Smith 
1366976f2fSJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Transpose(Mat N, Vec x, Vec y)
14d71ae5a4SJacob Faibussowitsch {
15bf477422SJose E. Roman   Mat A;
1647a9afc9SBarry Smith 
1747a9afc9SBarry Smith   PetscFunctionBegin;
18bf477422SJose E. Roman   PetscCall(MatShellGetContext(N, &A));
19bf477422SJose E. Roman   PetscCall(MatMult(A, x, y));
203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2147a9afc9SBarry Smith }
2247a9afc9SBarry Smith 
23*f1769f9dSJose E. Roman static PetscErrorCode MatSolve_Transpose_LU(Mat N, Vec b, Vec x)
24*f1769f9dSJose E. Roman {
25*f1769f9dSJose E. Roman   Mat A;
26*f1769f9dSJose E. Roman 
27*f1769f9dSJose E. Roman   PetscFunctionBegin;
28*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
29*f1769f9dSJose E. Roman   PetscCall(MatSolveTranspose(A, b, x));
30*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
31*f1769f9dSJose E. Roman }
32*f1769f9dSJose E. Roman 
33*f1769f9dSJose E. Roman static PetscErrorCode MatSolveAdd_Transpose_LU(Mat N, Vec b, Vec y, Vec x)
34*f1769f9dSJose E. Roman {
35*f1769f9dSJose E. Roman   Mat A;
36*f1769f9dSJose E. Roman 
37*f1769f9dSJose E. Roman   PetscFunctionBegin;
38*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
39*f1769f9dSJose E. Roman   PetscCall(MatSolveTransposeAdd(A, b, y, x));
40*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
41*f1769f9dSJose E. Roman }
42*f1769f9dSJose E. Roman 
43*f1769f9dSJose E. Roman static PetscErrorCode MatSolveTranspose_Transpose_LU(Mat N, Vec b, Vec x)
44*f1769f9dSJose E. Roman {
45*f1769f9dSJose E. Roman   Mat A;
46*f1769f9dSJose E. Roman 
47*f1769f9dSJose E. Roman   PetscFunctionBegin;
48*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
49*f1769f9dSJose E. Roman   PetscCall(MatSolve(A, b, x));
50*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
51*f1769f9dSJose E. Roman }
52*f1769f9dSJose E. Roman 
53*f1769f9dSJose E. Roman static PetscErrorCode MatSolveTransposeAdd_Transpose_LU(Mat N, Vec b, Vec y, Vec x)
54*f1769f9dSJose E. Roman {
55*f1769f9dSJose E. Roman   Mat A;
56*f1769f9dSJose E. Roman 
57*f1769f9dSJose E. Roman   PetscFunctionBegin;
58*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
59*f1769f9dSJose E. Roman   PetscCall(MatSolveAdd(A, b, y, x));
60*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
61*f1769f9dSJose E. Roman }
62*f1769f9dSJose E. Roman 
63*f1769f9dSJose E. Roman static PetscErrorCode MatMatSolve_Transpose_LU(Mat N, Mat B, Mat X)
64*f1769f9dSJose E. Roman {
65*f1769f9dSJose E. Roman   Mat A;
66*f1769f9dSJose E. Roman 
67*f1769f9dSJose E. Roman   PetscFunctionBegin;
68*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
69*f1769f9dSJose E. Roman   PetscCall(MatMatSolveTranspose(A, B, X));
70*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
71*f1769f9dSJose E. Roman }
72*f1769f9dSJose E. Roman 
73*f1769f9dSJose E. Roman static PetscErrorCode MatMatSolveTranspose_Transpose_LU(Mat N, Mat B, Mat X)
74*f1769f9dSJose E. Roman {
75*f1769f9dSJose E. Roman   Mat A;
76*f1769f9dSJose E. Roman 
77*f1769f9dSJose E. Roman   PetscFunctionBegin;
78*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
79*f1769f9dSJose E. Roman   PetscCall(MatMatSolve(A, B, X));
80*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
81*f1769f9dSJose E. Roman }
82*f1769f9dSJose E. Roman 
83*f1769f9dSJose E. Roman static PetscErrorCode MatLUFactor_Transpose(Mat N, IS row, IS col, const MatFactorInfo *minfo)
84*f1769f9dSJose E. Roman {
85*f1769f9dSJose E. Roman   Mat A;
86*f1769f9dSJose E. Roman 
87*f1769f9dSJose E. Roman   PetscFunctionBegin;
88*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
89*f1769f9dSJose E. Roman   PetscCall(MatLUFactor(A, col, row, minfo));
90*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_SOLVE, (void (*)(void))MatSolve_Transpose_LU));
91*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_ADD, (void (*)(void))MatSolveAdd_Transpose_LU));
92*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_TRANSPOSE, (void (*)(void))MatSolveTranspose_Transpose_LU));
93*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_TRANSPOSE_ADD, (void (*)(void))MatSolveTransposeAdd_Transpose_LU));
94*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_MAT_SOLVE, (void (*)(void))MatMatSolve_Transpose_LU));
95*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_MAT_SOLVE_TRANSPOSE, (void (*)(void))MatMatSolveTranspose_Transpose_LU));
96*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
97*f1769f9dSJose E. Roman }
98*f1769f9dSJose E. Roman 
99*f1769f9dSJose E. Roman static PetscErrorCode MatSolve_Transpose_Cholesky(Mat N, Vec b, Vec x)
100*f1769f9dSJose E. Roman {
101*f1769f9dSJose E. Roman   Mat A;
102*f1769f9dSJose E. Roman 
103*f1769f9dSJose E. Roman   PetscFunctionBegin;
104*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
105*f1769f9dSJose E. Roman   PetscCall(MatSolveTranspose(A, b, x));
106*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
107*f1769f9dSJose E. Roman }
108*f1769f9dSJose E. Roman 
109*f1769f9dSJose E. Roman static PetscErrorCode MatSolveAdd_Transpose_Cholesky(Mat N, Vec b, Vec y, Vec x)
110*f1769f9dSJose E. Roman {
111*f1769f9dSJose E. Roman   Mat A;
112*f1769f9dSJose E. Roman 
113*f1769f9dSJose E. Roman   PetscFunctionBegin;
114*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
115*f1769f9dSJose E. Roman   PetscCall(MatSolveTransposeAdd(A, b, y, x));
116*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
117*f1769f9dSJose E. Roman }
118*f1769f9dSJose E. Roman 
119*f1769f9dSJose E. Roman static PetscErrorCode MatSolveTranspose_Transpose_Cholesky(Mat N, Vec b, Vec x)
120*f1769f9dSJose E. Roman {
121*f1769f9dSJose E. Roman   Mat A;
122*f1769f9dSJose E. Roman 
123*f1769f9dSJose E. Roman   PetscFunctionBegin;
124*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
125*f1769f9dSJose E. Roman   PetscCall(MatSolve(A, b, x));
126*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
127*f1769f9dSJose E. Roman }
128*f1769f9dSJose E. Roman 
129*f1769f9dSJose E. Roman static PetscErrorCode MatSolveTransposeAdd_Transpose_Cholesky(Mat N, Vec b, Vec y, Vec x)
130*f1769f9dSJose E. Roman {
131*f1769f9dSJose E. Roman   Mat A;
132*f1769f9dSJose E. Roman 
133*f1769f9dSJose E. Roman   PetscFunctionBegin;
134*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
135*f1769f9dSJose E. Roman   PetscCall(MatSolveAdd(A, b, y, x));
136*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
137*f1769f9dSJose E. Roman }
138*f1769f9dSJose E. Roman 
139*f1769f9dSJose E. Roman static PetscErrorCode MatMatSolve_Transpose_Cholesky(Mat N, Mat B, Mat X)
140*f1769f9dSJose E. Roman {
141*f1769f9dSJose E. Roman   Mat A;
142*f1769f9dSJose E. Roman 
143*f1769f9dSJose E. Roman   PetscFunctionBegin;
144*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
145*f1769f9dSJose E. Roman   PetscCall(MatMatSolveTranspose(A, B, X));
146*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
147*f1769f9dSJose E. Roman }
148*f1769f9dSJose E. Roman 
149*f1769f9dSJose E. Roman static PetscErrorCode MatMatSolveTranspose_Transpose_Cholesky(Mat N, Mat B, Mat X)
150*f1769f9dSJose E. Roman {
151*f1769f9dSJose E. Roman   Mat A;
152*f1769f9dSJose E. Roman 
153*f1769f9dSJose E. Roman   PetscFunctionBegin;
154*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
155*f1769f9dSJose E. Roman   PetscCall(MatMatSolve(A, B, X));
156*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
157*f1769f9dSJose E. Roman }
158*f1769f9dSJose E. Roman 
159*f1769f9dSJose E. Roman static PetscErrorCode MatCholeskyFactor_Transpose(Mat N, IS perm, const MatFactorInfo *minfo)
160*f1769f9dSJose E. Roman {
161*f1769f9dSJose E. Roman   Mat A;
162*f1769f9dSJose E. Roman 
163*f1769f9dSJose E. Roman   PetscFunctionBegin;
164*f1769f9dSJose E. Roman   PetscCall(MatShellGetContext(N, &A));
165*f1769f9dSJose E. Roman   PetscCall(MatCholeskyFactor(A, perm, minfo));
166*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_SOLVE, (void (*)(void))MatSolve_Transpose_Cholesky));
167*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_ADD, (void (*)(void))MatSolveAdd_Transpose_Cholesky));
168*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_TRANSPOSE, (void (*)(void))MatSolveTranspose_Transpose_Cholesky));
169*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_SOLVE_TRANSPOSE_ADD, (void (*)(void))MatSolveTransposeAdd_Transpose_Cholesky));
170*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_MAT_SOLVE, (void (*)(void))MatMatSolve_Transpose_Cholesky));
171*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(N, MATOP_MAT_SOLVE_TRANSPOSE, (void (*)(void))MatMatSolveTranspose_Transpose_Cholesky));
172*f1769f9dSJose E. Roman   PetscFunctionReturn(PETSC_SUCCESS);
173*f1769f9dSJose E. Roman }
174*f1769f9dSJose E. Roman 
17566976f2fSJacob Faibussowitsch static PetscErrorCode MatDestroy_Transpose(Mat N)
176d71ae5a4SJacob Faibussowitsch {
177bf477422SJose E. Roman   Mat A;
17885e3dda7SBarry Smith 
17985e3dda7SBarry Smith   PetscFunctionBegin;
180bf477422SJose E. Roman   PetscCall(MatShellGetContext(N, &A));
181bf477422SJose E. Roman   PetscCall(MatDestroy(&A));
1829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatTransposeGetMat_C", NULL));
1839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatProductSetFromOptions_anytype_C", NULL));
184543844c4SJose E. Roman   PetscCall(PetscObjectComposeFunction((PetscObject)N, "MatShellSetContext_C", NULL));
1853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18685e3dda7SBarry Smith }
18785e3dda7SBarry Smith 
18866976f2fSJacob Faibussowitsch static PetscErrorCode MatDuplicate_Transpose(Mat N, MatDuplicateOption op, Mat *m)
189d71ae5a4SJacob Faibussowitsch {
190a1f56445SPierre Jolivet   Mat A, C;
191d0de2241SAndrew Spott 
192d0de2241SAndrew Spott   PetscFunctionBegin;
193bf477422SJose E. Roman   PetscCall(MatShellGetContext(N, &A));
194a1f56445SPierre Jolivet   PetscCall(MatDuplicate(A, op, &C));
195a1f56445SPierre Jolivet   PetscCall(MatCreateTranspose(C, m));
196*f1769f9dSJose E. Roman   if (op == MAT_COPY_VALUES) {
197*f1769f9dSJose E. Roman     PetscCall(MatCopy(N, *m, SAME_NONZERO_PATTERN));
198*f1769f9dSJose E. Roman     PetscCall(MatPropagateSymmetryOptions(A, C));
199*f1769f9dSJose E. Roman   }
200a1f56445SPierre Jolivet   PetscCall(MatDestroy(&C));
2013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
202d0de2241SAndrew Spott }
203d0de2241SAndrew Spott 
20466976f2fSJacob Faibussowitsch static PetscErrorCode MatHasOperation_Transpose(Mat mat, MatOperation op, PetscBool *has)
205d71ae5a4SJacob Faibussowitsch {
206bf477422SJose E. Roman   Mat A;
20752c5f739Sprj- 
208bf477422SJose E. Roman   PetscFunctionBegin;
209bf477422SJose E. Roman   PetscCall(MatShellGetContext(mat, &A));
21052c5f739Sprj-   *has = PETSC_FALSE;
211bf477422SJose E. Roman   if (op == MATOP_MULT || op == MATOP_MULT_ADD) {
212bf477422SJose E. Roman     PetscCall(MatHasOperation(A, MATOP_MULT_TRANSPOSE, has));
213bf477422SJose E. Roman   } else if (op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
214bf477422SJose E. Roman     PetscCall(MatHasOperation(A, MATOP_MULT, has));
2153c6db4c4SPierre Jolivet   } else if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
2163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21752c5f739Sprj- }
21852c5f739Sprj- 
219d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Transpose(Mat D)
220d71ae5a4SJacob Faibussowitsch {
2216718818eSStefano Zampini   Mat            A, B, C, Ain, Bin, Cin;
2226718818eSStefano Zampini   PetscBool      Aistrans, Bistrans, Cistrans;
2236718818eSStefano Zampini   PetscInt       Atrans, Btrans, Ctrans;
2246718818eSStefano Zampini   MatProductType ptype;
2256718818eSStefano Zampini 
2266718818eSStefano Zampini   PetscFunctionBegin;
2276718818eSStefano Zampini   MatCheckProduct(D, 1);
2286718818eSStefano Zampini   A = D->product->A;
2296718818eSStefano Zampini   B = D->product->B;
2306718818eSStefano Zampini   C = D->product->C;
231013e2dc7SBarry Smith   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATTRANSPOSEVIRTUAL, &Aistrans));
232013e2dc7SBarry Smith   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &Bistrans));
233013e2dc7SBarry Smith   PetscCall(PetscObjectTypeCompare((PetscObject)C, MATTRANSPOSEVIRTUAL, &Cistrans));
234aed4548fSBarry Smith   PetscCheck(Aistrans || Bistrans || Cistrans, PetscObjectComm((PetscObject)D), PETSC_ERR_PLIB, "This should not happen");
2356718818eSStefano Zampini   Atrans = 0;
2366718818eSStefano Zampini   Ain    = A;
2376718818eSStefano Zampini   while (Aistrans) {
2386718818eSStefano Zampini     Atrans++;
2399566063dSJacob Faibussowitsch     PetscCall(MatTransposeGetMat(Ain, &Ain));
240013e2dc7SBarry Smith     PetscCall(PetscObjectTypeCompare((PetscObject)Ain, MATTRANSPOSEVIRTUAL, &Aistrans));
2416718818eSStefano Zampini   }
2426718818eSStefano Zampini   Btrans = 0;
2436718818eSStefano Zampini   Bin    = B;
2446718818eSStefano Zampini   while (Bistrans) {
2456718818eSStefano Zampini     Btrans++;
2469566063dSJacob Faibussowitsch     PetscCall(MatTransposeGetMat(Bin, &Bin));
247013e2dc7SBarry Smith     PetscCall(PetscObjectTypeCompare((PetscObject)Bin, MATTRANSPOSEVIRTUAL, &Bistrans));
2486718818eSStefano Zampini   }
2496718818eSStefano Zampini   Ctrans = 0;
2506718818eSStefano Zampini   Cin    = C;
2516718818eSStefano Zampini   while (Cistrans) {
2526718818eSStefano Zampini     Ctrans++;
2539566063dSJacob Faibussowitsch     PetscCall(MatTransposeGetMat(Cin, &Cin));
254013e2dc7SBarry Smith     PetscCall(PetscObjectTypeCompare((PetscObject)Cin, MATTRANSPOSEVIRTUAL, &Cistrans));
2556718818eSStefano Zampini   }
2566718818eSStefano Zampini   Atrans = Atrans % 2;
2576718818eSStefano Zampini   Btrans = Btrans % 2;
2586718818eSStefano Zampini   Ctrans = Ctrans % 2;
2596718818eSStefano Zampini   ptype  = D->product->type; /* same product type by default */
260b94d7dedSBarry Smith   if (Ain->symmetric == PETSC_BOOL3_TRUE) Atrans = 0;
261b94d7dedSBarry Smith   if (Bin->symmetric == PETSC_BOOL3_TRUE) Btrans = 0;
262b94d7dedSBarry Smith   if (Cin && Cin->symmetric == PETSC_BOOL3_TRUE) Ctrans = 0;
2636718818eSStefano Zampini 
2646718818eSStefano Zampini   if (Atrans || Btrans || Ctrans) {
2656718818eSStefano Zampini     ptype = MATPRODUCT_UNSPECIFIED;
2666718818eSStefano Zampini     switch (D->product->type) {
2676718818eSStefano Zampini     case MATPRODUCT_AB:
2686718818eSStefano Zampini       if (Atrans && Btrans) { /* At * Bt we do not have support for this */
2696718818eSStefano Zampini         /* TODO custom implementation ? */
2706718818eSStefano Zampini       } else if (Atrans) { /* At * B */
2716718818eSStefano Zampini         ptype = MATPRODUCT_AtB;
2726718818eSStefano Zampini       } else { /* A * Bt */
2736718818eSStefano Zampini         ptype = MATPRODUCT_ABt;
2746718818eSStefano Zampini       }
2756718818eSStefano Zampini       break;
2766718818eSStefano Zampini     case MATPRODUCT_AtB:
2776718818eSStefano Zampini       if (Atrans && Btrans) { /* A * Bt */
2786718818eSStefano Zampini         ptype = MATPRODUCT_ABt;
2796718818eSStefano Zampini       } else if (Atrans) { /* A * B */
2806718818eSStefano Zampini         ptype = MATPRODUCT_AB;
2816718818eSStefano Zampini       } else { /* At * Bt we do not have support for this */
2826718818eSStefano Zampini         /* TODO custom implementation ? */
2836718818eSStefano Zampini       }
2846718818eSStefano Zampini       break;
2856718818eSStefano Zampini     case MATPRODUCT_ABt:
2866718818eSStefano Zampini       if (Atrans && Btrans) { /* At * B */
2876718818eSStefano Zampini         ptype = MATPRODUCT_AtB;
2886718818eSStefano Zampini       } else if (Atrans) { /* At * Bt we do not have support for this */
2896718818eSStefano Zampini         /* TODO custom implementation ? */
2906718818eSStefano Zampini       } else { /* A * B */
2916718818eSStefano Zampini         ptype = MATPRODUCT_AB;
2926718818eSStefano Zampini       }
2936718818eSStefano Zampini       break;
2946718818eSStefano Zampini     case MATPRODUCT_PtAP:
2956718818eSStefano Zampini       if (Atrans) { /* PtAtP */
2966718818eSStefano Zampini         /* TODO custom implementation ? */
2976718818eSStefano Zampini       } else { /* RARt */
2986718818eSStefano Zampini         ptype = MATPRODUCT_RARt;
2996718818eSStefano Zampini       }
3006718818eSStefano Zampini       break;
3016718818eSStefano Zampini     case MATPRODUCT_RARt:
3026718818eSStefano Zampini       if (Atrans) { /* RAtRt */
3036718818eSStefano Zampini         /* TODO custom implementation ? */
3046718818eSStefano Zampini       } else { /* PtAP */
3056718818eSStefano Zampini         ptype = MATPRODUCT_PtAP;
3066718818eSStefano Zampini       }
3076718818eSStefano Zampini       break;
3086718818eSStefano Zampini     case MATPRODUCT_ABC:
3096718818eSStefano Zampini       /* TODO custom implementation ? */
3106718818eSStefano Zampini       break;
311d71ae5a4SJacob Faibussowitsch     default:
312d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)D), PETSC_ERR_SUP, "ProductType %s is not supported", MatProductTypes[D->product->type]);
3136718818eSStefano Zampini     }
3146718818eSStefano Zampini   }
3159566063dSJacob Faibussowitsch   PetscCall(MatProductReplaceMats(Ain, Bin, Cin, D));
3169566063dSJacob Faibussowitsch   PetscCall(MatProductSetType(D, ptype));
3179566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(D));
3183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3196718818eSStefano Zampini }
3206718818eSStefano Zampini 
321bf477422SJose E. Roman static PetscErrorCode MatGetDiagonal_Transpose(Mat N, Vec v)
322d71ae5a4SJacob Faibussowitsch {
323bf477422SJose E. Roman   Mat A;
324a0eea678SPierre Jolivet 
325a0eea678SPierre Jolivet   PetscFunctionBegin;
326bf477422SJose E. Roman   PetscCall(MatShellGetContext(N, &A));
327bf477422SJose E. Roman   PetscCall(MatGetDiagonal(A, v));
3283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
329a0eea678SPierre Jolivet }
330a0eea678SPierre Jolivet 
331a1f56445SPierre Jolivet static PetscErrorCode MatCopy_Transpose(Mat A, Mat B, MatStructure str)
332a1f56445SPierre Jolivet {
333a1f56445SPierre Jolivet   Mat a, b;
334a1f56445SPierre Jolivet 
335a1f56445SPierre Jolivet   PetscFunctionBegin;
336a1f56445SPierre Jolivet   PetscCall(MatShellGetContext(A, &a));
337a1f56445SPierre Jolivet   PetscCall(MatShellGetContext(B, &b));
338a1f56445SPierre Jolivet   PetscCall(MatCopy(a, b, str));
339a1f56445SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
340a1f56445SPierre Jolivet }
341a1f56445SPierre Jolivet 
342bf477422SJose E. Roman static PetscErrorCode MatConvert_Transpose(Mat N, MatType newtype, MatReuse reuse, Mat *newmat)
343d71ae5a4SJacob Faibussowitsch {
344bf477422SJose E. Roman   Mat         A;
345b22c5e46SPierre Jolivet   PetscScalar vscale = 1.0, vshift = 0.0;
3466a4403aaSStefano Zampini   PetscBool   flg;
347a0eea678SPierre Jolivet 
348a0eea678SPierre Jolivet   PetscFunctionBegin;
349bf477422SJose E. Roman   PetscCall(MatShellGetContext(N, &A));
350bf477422SJose E. Roman   PetscCall(MatHasOperation(A, MATOP_TRANSPOSE, &flg));
351b22c5e46SPierre Jolivet   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 */
352b22c5e46SPierre Jolivet     PetscCheck(!((Mat_Shell *)N->data)->zrows && !((Mat_Shell *)N->data)->zcols, PetscObjectComm((PetscObject)N), PETSC_ERR_SUP, "Cannot call MatConvert() if MatZeroRows() or MatZeroRowsColumns() has been called on the input Mat");
353b22c5e46SPierre Jolivet     PetscCheck(!((Mat_Shell *)N->data)->axpy, PetscObjectComm((PetscObject)N), PETSC_ERR_SUP, "Cannot call MatConvert() if MatAXPY() has been called on the input Mat");
354b22c5e46SPierre Jolivet     PetscCheck(!((Mat_Shell *)N->data)->left && !((Mat_Shell *)N->data)->right, PetscObjectComm((PetscObject)N), PETSC_ERR_SUP, "Cannot call MatConvert() if MatDiagonalScale() has been called on the input Mat");
355b22c5e46SPierre Jolivet     PetscCheck(!((Mat_Shell *)N->data)->dshift, PetscObjectComm((PetscObject)N), PETSC_ERR_SUP, "Cannot call MatConvert() if MatDiagonalSet() has been called on the input Mat");
356b22c5e46SPierre Jolivet     vscale = ((Mat_Shell *)N->data)->vscale;
357b22c5e46SPierre Jolivet     vshift = ((Mat_Shell *)N->data)->vshift;
358b22c5e46SPierre Jolivet   }
3596a4403aaSStefano Zampini   if (flg) {
3606a4403aaSStefano Zampini     Mat B;
3616a4403aaSStefano Zampini 
362bf477422SJose E. Roman     PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &B));
363ff83db7bSPierre Jolivet     if (reuse != MAT_INPLACE_MATRIX) {
3649566063dSJacob Faibussowitsch       PetscCall(MatConvert(B, newtype, reuse, newmat));
3659566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&B));
366ff83db7bSPierre Jolivet     } else {
3679566063dSJacob Faibussowitsch       PetscCall(MatConvert(B, newtype, MAT_INPLACE_MATRIX, &B));
368bf477422SJose E. Roman       PetscCall(MatHeaderReplace(N, &B));
369ff83db7bSPierre Jolivet     }
3706a4403aaSStefano Zampini   } else { /* use basic converter as fallback */
371b22c5e46SPierre Jolivet     flg = (PetscBool)(N->ops->getrow != NULL);
372bf477422SJose E. Roman     PetscCall(MatConvert_Basic(N, newtype, reuse, newmat));
3736a4403aaSStefano Zampini   }
374b22c5e46SPierre Jolivet   if (flg) {
375b22c5e46SPierre Jolivet     PetscCall(MatScale(*newmat, vscale));
376b22c5e46SPierre Jolivet     PetscCall(MatShift(*newmat, vshift));
377b22c5e46SPierre Jolivet   }
3783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
379a0eea678SPierre Jolivet }
380a0eea678SPierre Jolivet 
381bf477422SJose E. Roman static PetscErrorCode MatTransposeGetMat_Transpose(Mat N, Mat *M)
382d71ae5a4SJacob Faibussowitsch {
3838060fb66Sstefano_zampini   PetscFunctionBegin;
384bf477422SJose E. Roman   PetscCall(MatShellGetContext(N, M));
3853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3868060fb66Sstefano_zampini }
3878060fb66Sstefano_zampini 
3888060fb66Sstefano_zampini /*@
389013e2dc7SBarry Smith   MatTransposeGetMat - Gets the `Mat` object stored inside a `MATTRANSPOSEVIRTUAL`
3908060fb66Sstefano_zampini 
39120f4b53cSBarry Smith   Logically Collective
3928060fb66Sstefano_zampini 
3938060fb66Sstefano_zampini   Input Parameter:
394013e2dc7SBarry Smith . A - the `MATTRANSPOSEVIRTUAL` matrix
3958060fb66Sstefano_zampini 
3968060fb66Sstefano_zampini   Output Parameter:
3972ef1f0ffSBarry Smith . M - the matrix object stored inside `A`
3988060fb66Sstefano_zampini 
3998060fb66Sstefano_zampini   Level: intermediate
4008060fb66Sstefano_zampini 
4011cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATTRANSPOSEVIRTUAL`, `MatCreateTranspose()`
4028060fb66Sstefano_zampini @*/
403d71ae5a4SJacob Faibussowitsch PetscErrorCode MatTransposeGetMat(Mat A, Mat *M)
404d71ae5a4SJacob Faibussowitsch {
4058060fb66Sstefano_zampini   PetscFunctionBegin;
4068060fb66Sstefano_zampini   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
4078060fb66Sstefano_zampini   PetscValidType(A, 1);
4084f572ea9SToby Isaac   PetscAssertPointer(M, 2);
409cac4c232SBarry Smith   PetscUseMethod(A, "MatTransposeGetMat_C", (Mat, Mat *), (A, M));
4103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4118060fb66Sstefano_zampini }
412d0de2241SAndrew Spott 
41311a5261eSBarry Smith /*MC
414013e2dc7SBarry Smith    MATTRANSPOSEVIRTUAL - "transpose" - A matrix type that represents a virtual transpose of a matrix
41585e3dda7SBarry Smith 
41611a5261eSBarry Smith   Level: advanced
41711a5261eSBarry Smith 
418a1f56445SPierre Jolivet   Developer Notes:
419543844c4SJose E. Roman   This is implemented on top of `MATSHELL` to get support for scaling and shifting without requiring duplicate code
420543844c4SJose E. Roman 
421543844c4SJose E. Roman   Users can not call `MatShellSetOperation()` operations on this class, there is some error checking for that incorrect usage
422543844c4SJose E. Roman 
4231cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATHERMITIANTRANSPOSEVIRTUAL`, `Mat`, `MatCreateHermitianTranspose()`, `MatCreateTranspose()`,
4242ef1f0ffSBarry Smith           `MATNORMALHERMITIAN`, `MATNORMAL`
42511a5261eSBarry Smith M*/
42611a5261eSBarry Smith 
42711a5261eSBarry Smith /*@
428013e2dc7SBarry Smith   MatCreateTranspose - Creates a new matrix `MATTRANSPOSEVIRTUAL` object that behaves like A'
42911a5261eSBarry Smith 
430c3339decSBarry Smith   Collective
43185e3dda7SBarry Smith 
43285e3dda7SBarry Smith   Input Parameter:
43385e3dda7SBarry Smith . A - the (possibly rectangular) matrix
43485e3dda7SBarry Smith 
43585e3dda7SBarry Smith   Output Parameter:
43685e3dda7SBarry Smith . N - the matrix that represents A'
43785e3dda7SBarry Smith 
43885e3dda7SBarry Smith   Level: intermediate
43985e3dda7SBarry Smith 
44011a5261eSBarry Smith   Note:
44195452b02SPatrick Sanan   The transpose A' is NOT actually formed! Rather the new matrix
44211a5261eSBarry Smith   object performs the matrix-vector product by using the `MatMultTranspose()` on
44385e3dda7SBarry Smith   the original matrix
44485e3dda7SBarry Smith 
4451cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATTRANSPOSEVIRTUAL`, `MatCreateNormal()`, `MatMult()`, `MatMultTranspose()`, `MatCreate()`,
4462ef1f0ffSBarry Smith           `MATNORMALHERMITIAN`
44785e3dda7SBarry Smith @*/
448d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateTranspose(Mat A, Mat *N)
449d71ae5a4SJacob Faibussowitsch {
450487d878eSStefano Zampini   VecType vtype;
45185e3dda7SBarry Smith 
45285e3dda7SBarry Smith   PetscFunctionBegin;
4539566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), N));
45487971105SStefano Zampini   PetscCall(PetscLayoutReference(A->rmap, &((*N)->cmap)));
45587971105SStefano Zampini   PetscCall(PetscLayoutReference(A->cmap, &((*N)->rmap)));
456bf477422SJose E. Roman   PetscCall(MatSetType(*N, MATSHELL));
457bf477422SJose E. Roman   PetscCall(MatShellSetContext(*N, A));
4589566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)A));
45985e3dda7SBarry Smith 
4609566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizes(*N, PetscAbs(A->cmap->bs), PetscAbs(A->rmap->bs)));
4619566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A, &vtype));
4629566063dSJacob Faibussowitsch   PetscCall(MatSetVecType(*N, vtype));
4632487f3f2SStefano Zampini #if defined(PETSC_HAVE_DEVICE)
4649566063dSJacob Faibussowitsch   PetscCall(MatBindToCPU(*N, A->boundtocpu));
4652487f3f2SStefano Zampini #endif
4669566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*N));
467bf477422SJose E. Roman 
468bf477422SJose E. Roman   PetscCall(MatShellSetOperation(*N, MATOP_DESTROY, (void (*)(void))MatDestroy_Transpose));
469bf477422SJose E. Roman   PetscCall(MatShellSetOperation(*N, MATOP_MULT, (void (*)(void))MatMult_Transpose));
470bf477422SJose E. Roman   PetscCall(MatShellSetOperation(*N, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_Transpose));
471*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(*N, MATOP_LUFACTOR, (void (*)(void))MatLUFactor_Transpose));
472*f1769f9dSJose E. Roman   PetscCall(MatShellSetOperation(*N, MATOP_CHOLESKYFACTOR, (void (*)(void))MatCholeskyFactor_Transpose));
473bf477422SJose E. Roman   PetscCall(MatShellSetOperation(*N, MATOP_DUPLICATE, (void (*)(void))MatDuplicate_Transpose));
474bf477422SJose E. Roman   PetscCall(MatShellSetOperation(*N, MATOP_HAS_OPERATION, (void (*)(void))MatHasOperation_Transpose));
475bf477422SJose E. Roman   PetscCall(MatShellSetOperation(*N, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_Transpose));
476a1f56445SPierre Jolivet   PetscCall(MatShellSetOperation(*N, MATOP_COPY, (void (*)(void))MatCopy_Transpose));
477bf477422SJose E. Roman   PetscCall(MatShellSetOperation(*N, MATOP_CONVERT, (void (*)(void))MatConvert_Transpose));
478bf477422SJose E. Roman 
479543844c4SJose E. Roman   PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatTransposeGetMat_C", MatTransposeGetMat_Transpose));
480543844c4SJose E. Roman   PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatProductSetFromOptions_anytype_C", MatProductSetFromOptions_Transpose));
481a1f56445SPierre Jolivet   PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatShellSetContext_C", MatShellSetContext_Immutable));
482a1f56445SPierre Jolivet   PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Immutable));
483a1f56445SPierre Jolivet   PetscCall(PetscObjectComposeFunction((PetscObject)*N, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Immutable));
484bf477422SJose E. Roman   PetscCall(PetscObjectChangeTypeName((PetscObject)*N, MATTRANSPOSEVIRTUAL));
4853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48685e3dda7SBarry Smith }
487