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