1 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/ 2 3 typedef struct { 4 Vec diag; 5 PetscBool diag_valid; 6 Vec inv_diag; 7 PetscBool inv_diag_valid; 8 PetscObjectState diag_state, inv_diag_state; 9 PetscInt *col; 10 PetscScalar *val; 11 } Mat_Diagonal; 12 13 static PetscErrorCode MatDiagonalSetUpDiagonal(Mat A) 14 { 15 Mat_Diagonal *ctx = (Mat_Diagonal *)A->data; 16 17 PetscFunctionBegin; 18 if (!ctx->diag_valid) { 19 PetscAssert(ctx->inv_diag_valid, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Neither diagonal nor inverse diagonal is in a valid state"); 20 PetscCall(VecCopy(ctx->inv_diag, ctx->diag)); 21 PetscCall(VecReciprocal(ctx->diag)); 22 ctx->diag_valid = PETSC_TRUE; 23 } 24 PetscFunctionReturn(PETSC_SUCCESS); 25 } 26 27 static PetscErrorCode MatDiagonalSetUpInverseDiagonal(Mat A) 28 { 29 Mat_Diagonal *ctx = (Mat_Diagonal *)A->data; 30 31 PetscFunctionBegin; 32 if (!ctx->inv_diag_valid) { 33 PetscAssert(ctx->diag_valid, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Neither diagonal nor inverse diagonal is in a valid state"); 34 PetscCall(VecCopy(ctx->diag, ctx->inv_diag)); 35 PetscCall(VecReciprocal(ctx->inv_diag)); 36 ctx->inv_diag_valid = PETSC_TRUE; 37 } 38 PetscFunctionReturn(PETSC_SUCCESS); 39 } 40 41 static PetscErrorCode MatAXPY_Diagonal(Mat Y, PetscScalar a, Mat X, MatStructure str) 42 { 43 Mat_Diagonal *yctx = (Mat_Diagonal *)Y->data; 44 Mat_Diagonal *xctx = (Mat_Diagonal *)X->data; 45 46 PetscFunctionBegin; 47 PetscCall(MatDiagonalSetUpDiagonal(Y)); 48 PetscCall(MatDiagonalSetUpDiagonal(X)); 49 PetscCall(VecAXPY(yctx->diag, a, xctx->diag)); 50 yctx->inv_diag_valid = PETSC_FALSE; 51 PetscFunctionReturn(PETSC_SUCCESS); 52 } 53 54 static PetscErrorCode MatGetRow_Diagonal(Mat A, PetscInt row, PetscInt *ncols, PetscInt **cols, PetscScalar **vals) 55 { 56 Mat_Diagonal *mat = (Mat_Diagonal *)A->data; 57 58 PetscFunctionBegin; 59 if (ncols) *ncols = 1; 60 if (cols) { 61 if (!mat->col) PetscCall(PetscMalloc1(1, &mat->col)); 62 *mat->col = row; 63 *cols = mat->col; 64 } 65 if (vals) { 66 const PetscScalar *v; 67 68 if (!mat->val) PetscCall(PetscMalloc1(1, &mat->val)); 69 PetscCall(VecGetArrayRead(mat->diag, &v)); 70 *mat->val = v[row]; 71 *vals = mat->val; 72 PetscCall(VecRestoreArrayRead(mat->diag, &v)); 73 } 74 PetscFunctionReturn(PETSC_SUCCESS); 75 } 76 77 static PetscErrorCode MatRestoreRow_Diagonal(Mat A, PetscInt row, PetscInt *ncols, PetscInt **cols, PetscScalar **vals) 78 { 79 PetscFunctionBegin; 80 PetscFunctionReturn(PETSC_SUCCESS); 81 } 82 83 static PetscErrorCode MatMult_Diagonal(Mat A, Vec x, Vec y) 84 { 85 Mat_Diagonal *ctx = (Mat_Diagonal *)A->data; 86 87 PetscFunctionBegin; 88 PetscCall(MatDiagonalSetUpDiagonal(A)); 89 PetscCall(VecPointwiseMult(y, ctx->diag, x)); 90 PetscFunctionReturn(PETSC_SUCCESS); 91 } 92 93 static PetscErrorCode MatMultAdd_Diagonal(Mat mat, Vec v1, Vec v2, Vec v3) 94 { 95 Mat_Diagonal *ctx = (Mat_Diagonal *)mat->data; 96 97 PetscFunctionBegin; 98 PetscCall(MatDiagonalSetUpDiagonal(mat)); 99 if (v2 != v3) { 100 PetscCall(VecPointwiseMult(v3, ctx->diag, v1)); 101 PetscCall(VecAXPY(v3, 1.0, v2)); 102 } else { 103 Vec w; 104 PetscCall(VecDuplicate(v3, &w)); 105 PetscCall(VecPointwiseMult(w, ctx->diag, v1)); 106 PetscCall(VecAXPY(v3, 1.0, w)); 107 PetscCall(VecDestroy(&w)); 108 } 109 PetscFunctionReturn(PETSC_SUCCESS); 110 } 111 112 static PetscErrorCode MatNorm_Diagonal(Mat A, NormType type, PetscReal *nrm) 113 { 114 Mat_Diagonal *ctx = (Mat_Diagonal *)A->data; 115 116 PetscFunctionBegin; 117 PetscCall(MatDiagonalSetUpDiagonal(A)); 118 type = (type == NORM_FROBENIUS) ? NORM_2 : NORM_INFINITY; 119 PetscCall(VecNorm(ctx->diag, type, nrm)); 120 PetscFunctionReturn(PETSC_SUCCESS); 121 } 122 123 static PetscErrorCode MatDuplicate_Diagonal(Mat A, MatDuplicateOption op, Mat *B) 124 { 125 Mat_Diagonal *actx = (Mat_Diagonal *)A->data; 126 127 PetscFunctionBegin; 128 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 129 PetscCall(MatSetSizes(*B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N)); 130 PetscCall(MatSetBlockSizesFromMats(*B, A, A)); 131 PetscCall(MatSetType(*B, MATDIAGONAL)); 132 PetscCall(PetscLayoutReference(A->rmap, &(*B)->rmap)); 133 PetscCall(PetscLayoutReference(A->cmap, &(*B)->cmap)); 134 if (op == MAT_COPY_VALUES) { 135 Mat_Diagonal *bctx = (Mat_Diagonal *)(*B)->data; 136 137 PetscCall(MatSetUp(A)); 138 PetscCall(MatSetUp(*B)); 139 PetscCall(VecCopy(actx->diag, bctx->diag)); 140 PetscCall(VecCopy(actx->inv_diag, bctx->inv_diag)); 141 bctx->diag_valid = actx->diag_valid; 142 bctx->inv_diag_valid = actx->inv_diag_valid; 143 } 144 PetscFunctionReturn(PETSC_SUCCESS); 145 } 146 147 /*@ 148 MatDiagonalGetDiagonal - Get the diagonal of a `MATDIAGONAL` 149 150 Input Parameter: 151 . A - the `MATDIAGONAL` 152 153 Output Parameter: 154 . diag - the `Vec` that defines the diagonal 155 156 Level: developer 157 158 Note: 159 The user must call 160 `MatDiagonalRestoreDiagonal()` before using the matrix again. 161 162 For a copy of the diagonal values, rather than a reference, use `MatGetDiagonal()` 163 164 Any changes to the obtained vector immediately change the action of the `Mat`. The matrix can be changed more efficiently by accessing this vector and changing its values, instead of filling a work vector and using `MatDiagonalSet()` 165 166 .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalRestoreDiagonal()`, `MatDiagonalGetInverseDiagonal()`, `MatGetDiagonal()` 167 @*/ 168 PetscErrorCode MatDiagonalGetDiagonal(Mat A, Vec *diag) 169 { 170 PetscFunctionBegin; 171 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 172 PetscAssertPointer(diag, 2); 173 *diag = NULL; 174 PetscUseMethod(A, "MatDiagonalGetDiagonal_C", (Mat, Vec *), (A, diag)); 175 PetscFunctionReturn(PETSC_SUCCESS); 176 } 177 178 static PetscErrorCode MatDiagonalGetDiagonal_Diagonal(Mat A, Vec *diag) 179 { 180 Mat_Diagonal *ctx = (Mat_Diagonal *)A->data; 181 182 PetscFunctionBegin; 183 PetscCall(MatSetUp(A)); 184 PetscCall(MatDiagonalSetUpDiagonal(A)); 185 *diag = ctx->diag; 186 PetscCall(PetscObjectStateGet((PetscObject)*diag, &ctx->diag_state)); 187 PetscFunctionReturn(PETSC_SUCCESS); 188 } 189 190 /*@ 191 MatDiagonalRestoreDiagonal - Restore the diagonal of a `MATDIAGONAL` 192 193 Input Parameters: 194 + A - the `MATDIAGONAL` 195 - diag - the `Vec` obtained from `MatDiagonalGetDiagonal()` 196 197 Level: developer 198 199 Note: 200 Use `MatDiagonalSet()` to change the values by copy, rather than reference. 201 202 .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalGetDiagonal()` 203 @*/ 204 PetscErrorCode MatDiagonalRestoreDiagonal(Mat A, Vec *diag) 205 { 206 PetscFunctionBegin; 207 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 208 PetscAssertPointer(diag, 2); 209 PetscUseMethod(A, "MatDiagonalRestoreDiagonal_C", (Mat, Vec *), (A, diag)); 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 static PetscErrorCode MatDiagonalRestoreDiagonal_Diagonal(Mat A, Vec *diag) 214 { 215 Mat_Diagonal *ctx = (Mat_Diagonal *)A->data; 216 PetscObjectState diag_state; 217 218 PetscFunctionBegin; 219 PetscCheck(ctx->diag == *diag, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Restored a different diagonal vector"); 220 ctx->diag_valid = PETSC_TRUE; 221 PetscCall(PetscObjectStateGet((PetscObject)*diag, &diag_state)); 222 if (ctx->diag_state != diag_state) { 223 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 224 ctx->inv_diag_valid = PETSC_FALSE; 225 } 226 *diag = NULL; 227 PetscFunctionReturn(PETSC_SUCCESS); 228 } 229 230 /*@ 231 MatDiagonalGetInverseDiagonal - Get the inverse diagonal of a `MATDIAGONAL` 232 233 Input Parameter: 234 . A - the `MATDIAGONAL` 235 236 Output Parameter: 237 . inv_diag - the `Vec` that defines the inverse diagonal 238 239 Level: developer 240 241 Note: 242 The user must call 243 `MatDiagonalRestoreInverseDiagonal()` before using the matrix again. 244 245 If a matrix is created only to call `MatSolve()` (which happens for `MATLMVMDIAGBROYDEN`), 246 using `MatDiagonalGetInverseDiagonal()` and `MatDiagonalRestoreInverseDiagonal()` avoids copies 247 and avoids any call to `VecReciprocal()`. 248 249 .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalRestoreInverseDiagonal()`, `MatDiagonalGetDiagonal()`, `MATLMVMBROYDEN`, `MatSolve()` 250 @*/ 251 PetscErrorCode MatDiagonalGetInverseDiagonal(Mat A, Vec *inv_diag) 252 { 253 PetscFunctionBegin; 254 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 255 PetscAssertPointer(inv_diag, 2); 256 *inv_diag = NULL; 257 PetscUseMethod(A, "MatDiagonalGetInverseDiagonal_C", (Mat, Vec *), (A, inv_diag)); 258 PetscFunctionReturn(PETSC_SUCCESS); 259 } 260 261 static PetscErrorCode MatDiagonalGetInverseDiagonal_Diagonal(Mat A, Vec *inv_diag) 262 { 263 Mat_Diagonal *ctx = (Mat_Diagonal *)A->data; 264 265 PetscFunctionBegin; 266 PetscCall(MatSetUp(A)); 267 PetscCall(MatDiagonalSetUpInverseDiagonal(A)); 268 *inv_diag = ctx->inv_diag; 269 PetscCall(PetscObjectStateGet((PetscObject)*inv_diag, &ctx->inv_diag_state)); 270 PetscFunctionReturn(PETSC_SUCCESS); 271 } 272 273 /*@ 274 MatDiagonalRestoreInverseDiagonal - Restore the inverse diagonal of a `MATDIAGONAL` 275 276 Input Parameters: 277 + A - the `MATDIAGONAL` 278 - inv_diag - the `Vec` obtained from `MatDiagonalGetInverseDiagonal()` 279 280 Level: developer 281 282 .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalGetInverseDiagonal()` 283 @*/ 284 PetscErrorCode MatDiagonalRestoreInverseDiagonal(Mat A, Vec *inv_diag) 285 { 286 PetscFunctionBegin; 287 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 288 PetscAssertPointer(inv_diag, 2); 289 PetscUseMethod(A, "MatDiagonalRestoreInverseDiagonal_C", (Mat, Vec *), (A, inv_diag)); 290 PetscFunctionReturn(PETSC_SUCCESS); 291 } 292 293 static PetscErrorCode MatDiagonalRestoreInverseDiagonal_Diagonal(Mat A, Vec *inv_diag) 294 { 295 Mat_Diagonal *ctx = (Mat_Diagonal *)A->data; 296 PetscObjectState inv_diag_state; 297 298 PetscFunctionBegin; 299 PetscCheck(ctx->inv_diag == *inv_diag, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Restored a different diagonal vector"); 300 ctx->inv_diag_valid = PETSC_TRUE; 301 PetscCall(PetscObjectStateGet((PetscObject)*inv_diag, &inv_diag_state)); 302 if (ctx->inv_diag_state != inv_diag_state) { 303 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 304 ctx->diag_valid = PETSC_FALSE; 305 } 306 *inv_diag = NULL; 307 PetscFunctionReturn(PETSC_SUCCESS); 308 } 309 310 static PetscErrorCode MatPermute_Diagonal(Mat A, IS rowp, IS colp, Mat *B) 311 { 312 Mat_Diagonal *ctx = (Mat_Diagonal *)A->data; 313 Vec v; 314 315 PetscFunctionBegin; 316 PetscCheck(rowp == colp, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Row permutation and column permutation must be the same"); 317 PetscCall(VecDuplicate(ctx->diag, &v)); 318 PetscCall(VecCopy(ctx->diag, v)); 319 PetscCall(VecPermute(v, rowp, PETSC_FALSE)); 320 PetscCall(MatCreateDiagonal(v, B)); 321 PetscCall(VecDestroy(&v)); 322 PetscFunctionReturn(PETSC_SUCCESS); 323 } 324 325 static PetscErrorCode MatDestroy_Diagonal(Mat mat) 326 { 327 Mat_Diagonal *ctx = (Mat_Diagonal *)mat->data; 328 329 PetscFunctionBegin; 330 PetscCall(VecDestroy(&ctx->diag)); 331 PetscCall(VecDestroy(&ctx->inv_diag)); 332 PetscCall(PetscFree(ctx->col)); 333 PetscCall(PetscFree(ctx->val)); 334 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalGetDiagonal_C", NULL)); 335 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalRestoreDiagonal_C", NULL)); 336 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalGetInverseDiagonal_C", NULL)); 337 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalRestoreInverseDiagonal_C", NULL)); 338 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_diagonal_seqdense_C", NULL)); 339 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_diagonal_mpidense_C", NULL)); 340 PetscCall(PetscFree(mat->data)); 341 mat->structural_symmetry_eternal = PETSC_FALSE; 342 mat->symmetry_eternal = PETSC_FALSE; 343 PetscFunctionReturn(PETSC_SUCCESS); 344 } 345 346 static PetscErrorCode MatView_Diagonal(Mat J, PetscViewer viewer) 347 { 348 Mat_Diagonal *ctx = (Mat_Diagonal *)J->data; 349 PetscBool iascii; 350 351 PetscFunctionBegin; 352 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 353 if (iascii) { 354 PetscViewerFormat format; 355 356 PetscCall(PetscViewerGetFormat(viewer, &format)); 357 if (format == PETSC_VIEWER_ASCII_FACTOR_INFO || format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS); 358 PetscCall(MatDiagonalSetUpDiagonal(J)); 359 PetscCall(VecView(ctx->diag, viewer)); 360 } 361 PetscFunctionReturn(PETSC_SUCCESS); 362 } 363 364 static PetscErrorCode MatGetDiagonal_Diagonal(Mat J, Vec x) 365 { 366 Mat_Diagonal *ctx = (Mat_Diagonal *)J->data; 367 368 PetscFunctionBegin; 369 PetscCall(MatDiagonalSetUpDiagonal(J)); 370 PetscCall(VecCopy(ctx->diag, x)); 371 PetscFunctionReturn(PETSC_SUCCESS); 372 } 373 374 static PetscErrorCode MatDiagonalSet_Diagonal(Mat J, Vec D, InsertMode is) 375 { 376 Mat_Diagonal *ctx = (Mat_Diagonal *)J->data; 377 378 PetscFunctionBegin; 379 switch (is) { 380 case ADD_VALUES: 381 case ADD_ALL_VALUES: 382 case ADD_BC_VALUES: 383 PetscCall(MatDiagonalSetUpDiagonal(J)); 384 PetscCall(VecAXPY(ctx->diag, 1.0, D)); 385 ctx->inv_diag_valid = PETSC_FALSE; 386 break; 387 case INSERT_VALUES: 388 case INSERT_BC_VALUES: 389 case INSERT_ALL_VALUES: 390 PetscCall(MatSetUp(J)); 391 PetscCall(VecCopy(D, ctx->diag)); 392 ctx->diag_valid = PETSC_TRUE; 393 ctx->inv_diag_valid = PETSC_FALSE; 394 break; 395 case MAX_VALUES: 396 PetscCall(MatDiagonalSetUpDiagonal(J)); 397 PetscCall(VecPointwiseMax(ctx->diag, D, ctx->diag)); 398 ctx->inv_diag_valid = PETSC_FALSE; 399 break; 400 case MIN_VALUES: 401 PetscCall(MatDiagonalSetUpDiagonal(J)); 402 PetscCall(VecPointwiseMin(ctx->diag, D, ctx->diag)); 403 ctx->inv_diag_valid = PETSC_FALSE; 404 break; 405 case NOT_SET_VALUES: 406 break; 407 } 408 PetscFunctionReturn(PETSC_SUCCESS); 409 } 410 411 static PetscErrorCode MatShift_Diagonal(Mat Y, PetscScalar a) 412 { 413 Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data; 414 415 PetscFunctionBegin; 416 PetscCall(MatDiagonalSetUpDiagonal(Y)); 417 PetscCall(VecShift(ctx->diag, a)); 418 ctx->inv_diag_valid = PETSC_FALSE; 419 PetscFunctionReturn(PETSC_SUCCESS); 420 } 421 422 static PetscErrorCode MatScale_Diagonal(Mat Y, PetscScalar a) 423 { 424 Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data; 425 426 PetscFunctionBegin; 427 PetscCall(MatSetUp(Y)); 428 PetscCall(MatDiagonalSetUpDiagonal(Y)); 429 PetscCall(VecScale(ctx->diag, a)); 430 ctx->inv_diag_valid = PETSC_FALSE; 431 PetscFunctionReturn(PETSC_SUCCESS); 432 } 433 434 static PetscErrorCode MatDiagonalScale_Diagonal(Mat Y, Vec l, Vec r) 435 { 436 Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data; 437 438 PetscFunctionBegin; 439 PetscCall(MatDiagonalSetUpDiagonal(Y)); 440 if (l) { 441 PetscCall(VecPointwiseMult(ctx->diag, ctx->diag, l)); 442 ctx->inv_diag_valid = PETSC_FALSE; 443 } 444 if (r) { 445 PetscCall(VecPointwiseMult(ctx->diag, ctx->diag, r)); 446 ctx->inv_diag_valid = PETSC_FALSE; 447 } 448 PetscFunctionReturn(PETSC_SUCCESS); 449 } 450 451 static PetscErrorCode MatSetUp_Diagonal(Mat A) 452 { 453 Mat_Diagonal *ctx = (Mat_Diagonal *)A->data; 454 455 PetscFunctionBegin; 456 if (!ctx->diag) { 457 PetscCall(PetscLayoutSetUp(A->cmap)); 458 PetscCall(PetscLayoutSetUp(A->rmap)); 459 PetscCall(MatCreateVecs(A, &ctx->diag, NULL)); 460 PetscCall(VecDuplicate(ctx->diag, &ctx->inv_diag)); 461 PetscCall(VecZeroEntries(ctx->diag)); 462 ctx->diag_valid = PETSC_TRUE; 463 } 464 A->assembled = PETSC_TRUE; 465 PetscFunctionReturn(PETSC_SUCCESS); 466 } 467 468 static PetscErrorCode MatZeroEntries_Diagonal(Mat Y) 469 { 470 Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data; 471 472 PetscFunctionBegin; 473 PetscCall(MatSetUp(Y)); 474 PetscCall(VecZeroEntries(ctx->diag)); 475 ctx->diag_valid = PETSC_TRUE; 476 ctx->inv_diag_valid = PETSC_FALSE; 477 PetscFunctionReturn(PETSC_SUCCESS); 478 } 479 480 static PetscErrorCode MatSolve_Diagonal(Mat matin, Vec b, Vec x) 481 { 482 Mat_Diagonal *ctx = (Mat_Diagonal *)matin->data; 483 484 PetscFunctionBegin; 485 PetscCall(MatDiagonalSetUpInverseDiagonal(matin)); 486 PetscCall(VecPointwiseMult(x, b, ctx->inv_diag)); 487 PetscFunctionReturn(PETSC_SUCCESS); 488 } 489 490 static PetscErrorCode MatGetInfo_Diagonal(Mat A, MatInfoType flag, MatInfo *info) 491 { 492 PetscFunctionBegin; 493 info->block_size = 1.0; 494 info->nz_allocated = A->cmap->N; 495 info->nz_used = A->cmap->N; 496 info->nz_unneeded = 0.0; 497 info->assemblies = A->num_ass; 498 info->mallocs = 0.0; 499 info->memory = 0; 500 info->fill_ratio_given = 0; 501 info->fill_ratio_needed = 0; 502 info->factor_mallocs = 0; 503 PetscFunctionReturn(PETSC_SUCCESS); 504 } 505 506 /*@ 507 MatCreateDiagonal - Creates a matrix defined by a given vector along its diagonal. 508 509 Collective 510 511 Input Parameter: 512 . diag - vector for the diagonal 513 514 Output Parameter: 515 . J - the diagonal matrix 516 517 Level: advanced 518 519 Notes: 520 Only supports square matrices with the same number of local rows and columns. 521 522 The input vector `diag` will be referenced internally: any changes to `diag` 523 will affect the matrix `J`. 524 525 .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `MATCONSTANTDIAGONAL`, `MatScale()`, `MatShift()`, `MatMult()`, `MatGetDiagonal()`, `MatSolve()` 526 `MatDiagonalRestoreInverseDiagonal()`, `MatDiagonalGetDiagonal()`, `MatDiagonalRestoreDiagonal()`, `MatDiagonalGetInverseDiagonal()` 527 @*/ 528 PetscErrorCode MatCreateDiagonal(Vec diag, Mat *J) 529 { 530 PetscFunctionBegin; 531 PetscValidHeaderSpecific(diag, VEC_CLASSID, 1); 532 PetscCall(MatCreate(PetscObjectComm((PetscObject)diag), J)); 533 PetscInt m, M; 534 PetscCall(VecGetLocalSize(diag, &m)); 535 PetscCall(VecGetSize(diag, &M)); 536 PetscCall(MatSetSizes(*J, m, m, M, M)); 537 PetscCall(MatSetType(*J, MATDIAGONAL)); 538 539 PetscLayout map; 540 PetscCall(VecGetLayout(diag, &map)); 541 PetscCall(MatSetLayouts(*J, map, map)); 542 Mat_Diagonal *ctx = (Mat_Diagonal *)(*J)->data; 543 PetscCall(PetscObjectReference((PetscObject)diag)); 544 PetscCall(VecDestroy(&ctx->diag)); 545 PetscCall(VecDestroy(&ctx->inv_diag)); 546 ctx->diag = diag; 547 ctx->diag_valid = PETSC_TRUE; 548 ctx->inv_diag_valid = PETSC_FALSE; 549 VecType type; 550 PetscCall(VecDuplicate(ctx->diag, &ctx->inv_diag)); 551 PetscCall(VecGetType(diag, &type)); 552 PetscCall(PetscFree((*J)->defaultvectype)); 553 PetscCall(PetscStrallocpy(type, &(*J)->defaultvectype)); 554 PetscCall(MatSetUp(*J)); 555 ctx->col = NULL; 556 ctx->val = NULL; 557 PetscFunctionReturn(PETSC_SUCCESS); 558 } 559 560 static PetscErrorCode MatProductNumeric_Diagonal_Dense(Mat C) 561 { 562 Mat A, B; 563 Mat_Diagonal *a; 564 PetscScalar *c; 565 const PetscScalar *b, *alpha; 566 PetscInt ldb, ldc; 567 568 PetscFunctionBegin; 569 MatCheckProduct(C, 1); 570 A = C->product->A; 571 B = C->product->B; 572 a = (Mat_Diagonal *)A->data; 573 PetscCall(VecGetArrayRead(a->diag, &alpha)); 574 PetscCall(MatDenseGetLDA(B, &ldb)); 575 PetscCall(MatDenseGetLDA(C, &ldc)); 576 PetscCall(MatDenseGetArrayRead(B, &b)); 577 PetscCall(MatDenseGetArrayWrite(C, &c)); 578 for (PetscInt j = 0; j < B->cmap->N; j++) 579 for (PetscInt i = 0; i < B->rmap->n; i++) c[i + j * ldc] = alpha[i] * b[i + j * ldb]; 580 PetscCall(MatDenseRestoreArrayWrite(C, &c)); 581 PetscCall(MatDenseRestoreArrayRead(B, &b)); 582 PetscCall(VecRestoreArrayRead(a->diag, &alpha)); 583 PetscCall(PetscLogFlops(B->cmap->N * B->rmap->n)); 584 PetscFunctionReturn(PETSC_SUCCESS); 585 } 586 587 static PetscErrorCode MatProductSymbolic_Diagonal_Dense(Mat C) 588 { 589 Mat A, B; 590 PetscInt n, N, m, M; 591 592 PetscFunctionBegin; 593 MatCheckProduct(C, 1); 594 PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty"); 595 A = C->product->A; 596 B = C->product->B; 597 PetscCall(MatDiagonalSetUpDiagonal(A)); 598 PetscCall(MatGetLocalSize(C, &m, &n)); 599 PetscCall(MatGetSize(C, &M, &N)); 600 if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) { 601 PetscCall(MatGetLocalSize(B, NULL, &n)); 602 PetscCall(MatGetSize(B, NULL, &N)); 603 PetscCall(MatGetLocalSize(A, &m, NULL)); 604 PetscCall(MatGetSize(A, &M, NULL)); 605 PetscCall(MatSetSizes(C, m, n, M, N)); 606 } 607 PetscCall(MatSetType(C, ((PetscObject)B)->type_name)); 608 PetscCall(MatSetUp(C)); 609 C->ops->productnumeric = MatProductNumeric_Diagonal_Dense; 610 PetscFunctionReturn(PETSC_SUCCESS); 611 } 612 613 static PetscErrorCode MatProductSetFromOptions_Diagonal_Dense_AB(Mat C) 614 { 615 PetscFunctionBegin; 616 C->ops->productsymbolic = MatProductSymbolic_Diagonal_Dense; 617 PetscFunctionReturn(PETSC_SUCCESS); 618 } 619 620 static PetscErrorCode MatProductSetFromOptions_Diagonal_Dense(Mat C) 621 { 622 Mat_Product *product = C->product; 623 624 PetscFunctionBegin; 625 if (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB) PetscCall(MatProductSetFromOptions_Diagonal_Dense_AB(C)); 626 PetscFunctionReturn(PETSC_SUCCESS); 627 } 628 629 /*MC 630 MATDIAGONAL - MATDIAGONAL = "diagonal" - A diagonal matrix type with the diagonal implemented as a `Vec`. Useful for 631 cases where `VecPointwiseMult()` or `VecPointwiseDivide()` should be thought of as the actions of a linear operator. 632 633 Level: advanced 634 635 .seealso: [](ch_matrices), `Mat`, `MatCreateDiagonal()`, `MatDiagonalRestoreInverseDiagonal()`, `MatDiagonalGetDiagonal()`, `MatDiagonalRestoreDiagonal()`, `MatDiagonalGetInverseDiagonal()` 636 M*/ 637 PETSC_INTERN PetscErrorCode MatCreate_Diagonal(Mat A) 638 { 639 Mat_Diagonal *ctx; 640 641 PetscFunctionBegin; 642 PetscCall(PetscNew(&ctx)); 643 A->data = (void *)ctx; 644 645 A->structurally_symmetric = PETSC_BOOL3_TRUE; 646 A->structural_symmetry_eternal = PETSC_TRUE; 647 A->symmetry_eternal = PETSC_TRUE; 648 A->symmetric = PETSC_BOOL3_TRUE; 649 if (!PetscDefined(USE_COMPLEX)) A->hermitian = PETSC_BOOL3_TRUE; 650 651 A->ops->getrow = MatGetRow_Diagonal; 652 A->ops->restorerow = MatRestoreRow_Diagonal; 653 A->ops->mult = MatMult_Diagonal; 654 A->ops->multadd = MatMultAdd_Diagonal; 655 A->ops->multtranspose = MatMult_Diagonal; 656 A->ops->multtransposeadd = MatMultAdd_Diagonal; 657 A->ops->norm = MatNorm_Diagonal; 658 A->ops->duplicate = MatDuplicate_Diagonal; 659 A->ops->solve = MatSolve_Diagonal; 660 A->ops->solvetranspose = MatSolve_Diagonal; 661 A->ops->shift = MatShift_Diagonal; 662 A->ops->scale = MatScale_Diagonal; 663 A->ops->diagonalscale = MatDiagonalScale_Diagonal; 664 A->ops->getdiagonal = MatGetDiagonal_Diagonal; 665 A->ops->diagonalset = MatDiagonalSet_Diagonal; 666 A->ops->view = MatView_Diagonal; 667 A->ops->zeroentries = MatZeroEntries_Diagonal; 668 A->ops->destroy = MatDestroy_Diagonal; 669 A->ops->getinfo = MatGetInfo_Diagonal; 670 A->ops->axpy = MatAXPY_Diagonal; 671 A->ops->setup = MatSetUp_Diagonal; 672 A->ops->permute = MatPermute_Diagonal; 673 674 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalGetDiagonal_C", MatDiagonalGetDiagonal_Diagonal)); 675 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalRestoreDiagonal_C", MatDiagonalRestoreDiagonal_Diagonal)); 676 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalGetInverseDiagonal_C", MatDiagonalGetInverseDiagonal_Diagonal)); 677 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalRestoreInverseDiagonal_C", MatDiagonalRestoreInverseDiagonal_Diagonal)); 678 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_diagonal_seqdense_C", MatProductSetFromOptions_Diagonal_Dense)); 679 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_diagonal_mpidense_C", MatProductSetFromOptions_Diagonal_Dense)); 680 PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATDIAGONAL)); 681 PetscFunctionReturn(PETSC_SUCCESS); 682 } 683