Date: 2025-03-29T05:58:34+00:00

Actual source code: diagonal.c

      1: #include <petsc/private/matimpl.h>

      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;

     13: static PetscErrorCode MatDiagonalSetUpDiagonal(Mat A)
     14: {
     15:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

     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: }

     27: static PetscErrorCode MatDiagonalSetUpInverseDiagonal(Mat A)
     28: {
     29:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

     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: }

     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;

     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: }

     54: static PetscErrorCode MatGetRow_Diagonal(Mat A, PetscInt row, PetscInt *ncols, PetscInt **cols, PetscScalar **vals)
     55: {
     56:   Mat_Diagonal *mat = (Mat_Diagonal *)A->data;

     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;

     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: }

     77: static PetscErrorCode MatMult_Diagonal(Mat A, Vec x, Vec y)
     78: {
     79:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

     81:   PetscFunctionBegin;
     82:   PetscCall(MatDiagonalSetUpDiagonal(A));
     83:   PetscCall(VecPointwiseMult(y, ctx->diag, x));
     84:   PetscFunctionReturn(PETSC_SUCCESS);
     85: }

     87: static PetscErrorCode MatMultAdd_Diagonal(Mat mat, Vec v1, Vec v2, Vec v3)
     88: {
     89:   Mat_Diagonal *ctx = (Mat_Diagonal *)mat->data;

     91:   PetscFunctionBegin;
     92:   PetscCall(MatDiagonalSetUpDiagonal(mat));
     93:   if (v2 != v3) {
     94:     PetscCall(VecPointwiseMult(v3, ctx->diag, v1));
     95:     PetscCall(VecAXPY(v3, 1.0, v2));
     96:   } else {
     97:     Vec w;
     98:     PetscCall(VecDuplicate(v3, &w));
     99:     PetscCall(VecPointwiseMult(w, ctx->diag, v1));
    100:     PetscCall(VecAXPY(v3, 1.0, w));
    101:     PetscCall(VecDestroy(&w));
    102:   }
    103:   PetscFunctionReturn(PETSC_SUCCESS);
    104: }

    106: static PetscErrorCode MatNorm_Diagonal(Mat A, NormType type, PetscReal *nrm)
    107: {
    108:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

    110:   PetscFunctionBegin;
    111:   PetscCall(MatDiagonalSetUpDiagonal(A));
    112:   type = (type == NORM_FROBENIUS) ? NORM_2 : NORM_INFINITY;
    113:   PetscCall(VecNorm(ctx->diag, type, nrm));
    114:   PetscFunctionReturn(PETSC_SUCCESS);
    115: }

    117: static PetscErrorCode MatDuplicate_Diagonal(Mat A, MatDuplicateOption op, Mat *B)
    118: {
    119:   Mat_Diagonal *actx = (Mat_Diagonal *)A->data;

    121:   PetscFunctionBegin;
    122:   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
    123:   PetscCall(MatSetSizes(*B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
    124:   PetscCall(MatSetBlockSizesFromMats(*B, A, A));
    125:   PetscCall(MatSetType(*B, MATDIAGONAL));
    126:   PetscCall(PetscLayoutReference(A->rmap, &(*B)->rmap));
    127:   PetscCall(PetscLayoutReference(A->cmap, &(*B)->cmap));
    128:   if (op == MAT_COPY_VALUES) {
    129:     Mat_Diagonal *bctx = (Mat_Diagonal *)(*B)->data;

    131:     PetscCall(MatSetUp(A));
    132:     PetscCall(MatSetUp(*B));
    133:     PetscCall(VecCopy(actx->diag, bctx->diag));
    134:     PetscCall(VecCopy(actx->inv_diag, bctx->inv_diag));
    135:     bctx->diag_valid     = actx->diag_valid;
    136:     bctx->inv_diag_valid = actx->inv_diag_valid;
    137:   }
    138:   PetscFunctionReturn(PETSC_SUCCESS);
    139: }

    141: /*@
    142:   MatDiagonalGetDiagonal - Get the diagonal of a `MATDIAGONAL`

    144:   Input Parameter:
    145: . A - the `MATDIAGONAL`

    147:   Output Parameter:
    148: . diag - the `Vec` that defines the diagonal

    150:   Level: developer

    152:   Note:
    153:   The user must call
    154:   `MatDiagonalRestoreDiagonal()` before using the matrix again.

    156:   For a copy of the diagonal values, rather than a reference, use `MatGetDiagonal()`

    158:   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()`

    160: .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalRestoreDiagonal()`, `MatDiagonalGetInverseDiagonal()`, `MatGetDiagonal()`
    161: @*/
    162: PetscErrorCode MatDiagonalGetDiagonal(Mat A, Vec *diag)
    163: {
    164:   PetscFunctionBegin;
    166:   PetscAssertPointer(diag, 2);
    167:   *diag = NULL;
    168:   PetscUseMethod(A, "MatDiagonalGetDiagonal_C", (Mat, Vec *), (A, diag));
    169:   PetscFunctionReturn(PETSC_SUCCESS);
    170: }

    172: static PetscErrorCode MatDiagonalGetDiagonal_Diagonal(Mat A, Vec *diag)
    173: {
    174:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

    176:   PetscFunctionBegin;
    177:   PetscCall(MatSetUp(A));
    178:   PetscCall(MatDiagonalSetUpDiagonal(A));
    179:   *diag = ctx->diag;
    180:   PetscCall(PetscObjectStateGet((PetscObject)*diag, &ctx->diag_state));
    181:   PetscFunctionReturn(PETSC_SUCCESS);
    182: }

    184: /*@
    185:   MatDiagonalRestoreDiagonal - Restore the diagonal of a `MATDIAGONAL`

    187:   Input Parameters:
    188: + A    - the `MATDIAGONAL`
    189: - diag - the `Vec` obtained from `MatDiagonalGetDiagonal()`

    191:   Level: developer

    193:   Note:
    194:   Use `MatDiagonalSet()` to change the values by copy, rather than reference.

    196: .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalGetDiagonal()`
    197: @*/
    198: PetscErrorCode MatDiagonalRestoreDiagonal(Mat A, Vec *diag)
    199: {
    200:   PetscFunctionBegin;
    202:   PetscAssertPointer(diag, 2);
    203:   PetscUseMethod(A, "MatDiagonalRestoreDiagonal_C", (Mat, Vec *), (A, diag));
    204:   PetscFunctionReturn(PETSC_SUCCESS);
    205: }

    207: static PetscErrorCode MatDiagonalRestoreDiagonal_Diagonal(Mat A, Vec *diag)
    208: {
    209:   Mat_Diagonal    *ctx = (Mat_Diagonal *)A->data;
    210:   PetscObjectState diag_state;

    212:   PetscFunctionBegin;
    213:   PetscCheck(ctx->diag == *diag, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Restored a different diagonal vector");
    214:   ctx->diag_valid = PETSC_TRUE;
    215:   PetscCall(PetscObjectStateGet((PetscObject)*diag, &diag_state));
    216:   if (ctx->diag_state != diag_state) {
    217:     PetscCall(PetscObjectStateIncrease((PetscObject)A));
    218:     ctx->inv_diag_valid = PETSC_FALSE;
    219:   }
    220:   *diag = NULL;
    221:   PetscFunctionReturn(PETSC_SUCCESS);
    222: }

    224: /*@
    225:   MatDiagonalGetInverseDiagonal - Get the inverse diagonal of a `MATDIAGONAL`

    227:   Input Parameter:
    228: . A - the `MATDIAGONAL`

    230:   Output Parameter:
    231: . inv_diag - the `Vec` that defines the inverse diagonal

    233:   Level: developer

    235:   Note:
    236:   The user must call
    237:   `MatDiagonalRestoreInverseDiagonal()` before using the matrix again.

    239:   If a matrix is created only to call `MatSolve()` (which happens for `MATLMVMDIAGBROYDEN`),
    240:   using `MatDiagonalGetInverseDiagonal()` and `MatDiagonalRestoreInverseDiagonal()` avoids copies
    241:   and avoids any call to `VecReciprocal()`.

    243: .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalRestoreInverseDiagonal()`, `MatDiagonalGetDiagonal()`, `MATLMVMBROYDEN`, `MatSolve()`
    244: @*/
    245: PetscErrorCode MatDiagonalGetInverseDiagonal(Mat A, Vec *inv_diag)
    246: {
    247:   PetscFunctionBegin;
    249:   PetscAssertPointer(inv_diag, 2);
    250:   *inv_diag = NULL;
    251:   PetscUseMethod(A, "MatDiagonalGetInverseDiagonal_C", (Mat, Vec *), (A, inv_diag));
    252:   PetscFunctionReturn(PETSC_SUCCESS);
    253: }

    255: static PetscErrorCode MatDiagonalGetInverseDiagonal_Diagonal(Mat A, Vec *inv_diag)
    256: {
    257:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

    259:   PetscFunctionBegin;
    260:   PetscCall(MatSetUp(A));
    261:   PetscCall(MatDiagonalSetUpInverseDiagonal(A));
    262:   *inv_diag = ctx->inv_diag;
    263:   PetscCall(PetscObjectStateGet((PetscObject)*inv_diag, &ctx->inv_diag_state));
    264:   PetscFunctionReturn(PETSC_SUCCESS);
    265: }

    267: /*@
    268:   MatDiagonalRestoreInverseDiagonal - Restore the inverse diagonal of a `MATDIAGONAL`

    270:   Input Parameters:
    271: + A        - the `MATDIAGONAL`
    272: - inv_diag - the `Vec` obtained from `MatDiagonalGetInverseDiagonal()`

    274:   Level: developer

    276: .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalGetInverseDiagonal()`
    277: @*/
    278: PetscErrorCode MatDiagonalRestoreInverseDiagonal(Mat A, Vec *inv_diag)
    279: {
    280:   PetscFunctionBegin;
    282:   PetscAssertPointer(inv_diag, 2);
    283:   PetscUseMethod(A, "MatDiagonalRestoreInverseDiagonal_C", (Mat, Vec *), (A, inv_diag));
    284:   PetscFunctionReturn(PETSC_SUCCESS);
    285: }

    287: static PetscErrorCode MatDiagonalRestoreInverseDiagonal_Diagonal(Mat A, Vec *inv_diag)
    288: {
    289:   Mat_Diagonal    *ctx = (Mat_Diagonal *)A->data;
    290:   PetscObjectState inv_diag_state;

    292:   PetscFunctionBegin;
    293:   PetscCheck(ctx->inv_diag == *inv_diag, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Restored a different diagonal vector");
    294:   ctx->inv_diag_valid = PETSC_TRUE;
    295:   PetscCall(PetscObjectStateGet((PetscObject)*inv_diag, &inv_diag_state));
    296:   if (ctx->inv_diag_state != inv_diag_state) {
    297:     PetscCall(PetscObjectStateIncrease((PetscObject)A));
    298:     ctx->diag_valid = PETSC_FALSE;
    299:   }
    300:   *inv_diag = NULL;
    301:   PetscFunctionReturn(PETSC_SUCCESS);
    302: }

    304: static PetscErrorCode MatPermute_Diagonal(Mat A, IS rowp, IS colp, Mat *B)
    305: {
    306:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;
    307:   Vec           v;

    309:   PetscFunctionBegin;
    310:   PetscCheck(rowp == colp, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Row permutation and column permutation must be the same");
    311:   PetscCall(VecDuplicate(ctx->diag, &v));
    312:   PetscCall(VecCopy(ctx->diag, v));
    313:   PetscCall(VecPermute(v, rowp, PETSC_FALSE));
    314:   PetscCall(MatCreateDiagonal(v, B));
    315:   PetscCall(VecDestroy(&v));
    316:   PetscFunctionReturn(PETSC_SUCCESS);
    317: }

    319: static PetscErrorCode MatDestroy_Diagonal(Mat mat)
    320: {
    321:   Mat_Diagonal *ctx = (Mat_Diagonal *)mat->data;

    323:   PetscFunctionBegin;
    324:   PetscCall(VecDestroy(&ctx->diag));
    325:   PetscCall(VecDestroy(&ctx->inv_diag));
    326:   PetscCall(PetscFree(ctx->col));
    327:   PetscCall(PetscFree(ctx->val));
    328:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalGetDiagonal_C", NULL));
    329:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalRestoreDiagonal_C", NULL));
    330:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalGetInverseDiagonal_C", NULL));
    331:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalRestoreInverseDiagonal_C", NULL));
    332:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_diagonal_seqdense_C", NULL));
    333:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_diagonal_mpidense_C", NULL));
    334:   PetscCall(PetscFree(mat->data));
    335:   mat->structural_symmetry_eternal = PETSC_FALSE;
    336:   mat->symmetry_eternal            = PETSC_FALSE;
    337:   PetscFunctionReturn(PETSC_SUCCESS);
    338: }

    340: static PetscErrorCode MatView_Diagonal(Mat J, PetscViewer viewer)
    341: {
    342:   Mat_Diagonal *ctx = (Mat_Diagonal *)J->data;
    343:   PetscBool     iascii;

    345:   PetscFunctionBegin;
    346:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    347:   if (iascii) {
    348:     PetscViewerFormat format;

    350:     PetscCall(PetscViewerGetFormat(viewer, &format));
    351:     if (format == PETSC_VIEWER_ASCII_FACTOR_INFO || format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS);
    352:     PetscCall(MatDiagonalSetUpDiagonal(J));
    353:     PetscCall(VecView(ctx->diag, viewer));
    354:   }
    355:   PetscFunctionReturn(PETSC_SUCCESS);
    356: }

    358: static PetscErrorCode MatGetDiagonal_Diagonal(Mat J, Vec x)
    359: {
    360:   Mat_Diagonal *ctx = (Mat_Diagonal *)J->data;

    362:   PetscFunctionBegin;
    363:   PetscCall(MatDiagonalSetUpDiagonal(J));
    364:   PetscCall(VecCopy(ctx->diag, x));
    365:   PetscFunctionReturn(PETSC_SUCCESS);
    366: }

    368: static PetscErrorCode MatDiagonalSet_Diagonal(Mat J, Vec D, InsertMode is)
    369: {
    370:   Mat_Diagonal *ctx = (Mat_Diagonal *)J->data;

    372:   PetscFunctionBegin;
    373:   switch (is) {
    374:   case ADD_VALUES:
    375:   case ADD_ALL_VALUES:
    376:   case ADD_BC_VALUES:
    377:     PetscCall(MatDiagonalSetUpDiagonal(J));
    378:     PetscCall(VecAXPY(ctx->diag, 1.0, D));
    379:     ctx->inv_diag_valid = PETSC_FALSE;
    380:     break;
    381:   case INSERT_VALUES:
    382:   case INSERT_BC_VALUES:
    383:   case INSERT_ALL_VALUES:
    384:     PetscCall(MatSetUp(J));
    385:     PetscCall(VecCopy(D, ctx->diag));
    386:     ctx->diag_valid     = PETSC_TRUE;
    387:     ctx->inv_diag_valid = PETSC_FALSE;
    388:     break;
    389:   case MAX_VALUES:
    390:     PetscCall(MatDiagonalSetUpDiagonal(J));
    391:     PetscCall(VecPointwiseMax(ctx->diag, D, ctx->diag));
    392:     ctx->inv_diag_valid = PETSC_FALSE;
    393:     break;
    394:   case MIN_VALUES:
    395:     PetscCall(MatDiagonalSetUpDiagonal(J));
    396:     PetscCall(VecPointwiseMin(ctx->diag, D, ctx->diag));
    397:     ctx->inv_diag_valid = PETSC_FALSE;
    398:     break;
    399:   case NOT_SET_VALUES:
    400:     break;
    401:   }
    402:   PetscFunctionReturn(PETSC_SUCCESS);
    403: }

    405: static PetscErrorCode MatShift_Diagonal(Mat Y, PetscScalar a)
    406: {
    407:   Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data;

    409:   PetscFunctionBegin;
    410:   PetscCall(MatDiagonalSetUpDiagonal(Y));
    411:   PetscCall(VecShift(ctx->diag, a));
    412:   ctx->inv_diag_valid = PETSC_FALSE;
    413:   PetscFunctionReturn(PETSC_SUCCESS);
    414: }

    416: static PetscErrorCode MatScale_Diagonal(Mat Y, PetscScalar a)
    417: {
    418:   Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data;

    420:   PetscFunctionBegin;
    421:   PetscCall(MatSetUp(Y));
    422:   PetscCall(MatDiagonalSetUpDiagonal(Y));
    423:   PetscCall(VecScale(ctx->diag, a));
    424:   ctx->inv_diag_valid = PETSC_FALSE;
    425:   PetscFunctionReturn(PETSC_SUCCESS);
    426: }

    428: static PetscErrorCode MatDiagonalScale_Diagonal(Mat Y, Vec l, Vec r)
    429: {
    430:   Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data;

    432:   PetscFunctionBegin;
    433:   PetscCall(MatDiagonalSetUpDiagonal(Y));
    434:   if (l) {
    435:     PetscCall(VecPointwiseMult(ctx->diag, ctx->diag, l));
    436:     ctx->inv_diag_valid = PETSC_FALSE;
    437:   }
    438:   if (r) {
    439:     PetscCall(VecPointwiseMult(ctx->diag, ctx->diag, r));
    440:     ctx->inv_diag_valid = PETSC_FALSE;
    441:   }
    442:   PetscFunctionReturn(PETSC_SUCCESS);
    443: }

    445: static PetscErrorCode MatSetUp_Diagonal(Mat A)
    446: {
    447:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

    449:   PetscFunctionBegin;
    450:   if (!ctx->diag) {
    451:     PetscCall(PetscLayoutSetUp(A->cmap));
    452:     PetscCall(PetscLayoutSetUp(A->rmap));
    453:     PetscCall(MatCreateVecs(A, &ctx->diag, NULL));
    454:     PetscCall(VecDuplicate(ctx->diag, &ctx->inv_diag));
    455:     PetscCall(VecZeroEntries(ctx->diag));
    456:     ctx->diag_valid = PETSC_TRUE;
    457:   }
    458:   A->assembled = PETSC_TRUE;
    459:   PetscFunctionReturn(PETSC_SUCCESS);
    460: }

    462: static PetscErrorCode MatZeroEntries_Diagonal(Mat Y)
    463: {
    464:   Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data;

    466:   PetscFunctionBegin;
    467:   PetscCall(MatSetUp(Y));
    468:   PetscCall(VecZeroEntries(ctx->diag));
    469:   ctx->diag_valid     = PETSC_TRUE;
    470:   ctx->inv_diag_valid = PETSC_FALSE;
    471:   PetscFunctionReturn(PETSC_SUCCESS);
    472: }

    474: static PetscErrorCode MatSolve_Diagonal(Mat matin, Vec b, Vec x)
    475: {
    476:   Mat_Diagonal *ctx = (Mat_Diagonal *)matin->data;

    478:   PetscFunctionBegin;
    479:   PetscCall(MatDiagonalSetUpInverseDiagonal(matin));
    480:   PetscCall(VecPointwiseMult(x, b, ctx->inv_diag));
    481:   PetscFunctionReturn(PETSC_SUCCESS);
    482: }

    484: static PetscErrorCode MatGetInfo_Diagonal(Mat A, MatInfoType flag, MatInfo *info)
    485: {
    486:   PetscFunctionBegin;
    487:   info->block_size        = 1.0;
    488:   info->nz_allocated      = A->cmap->N;
    489:   info->nz_used           = A->cmap->N;
    490:   info->nz_unneeded       = 0.0;
    491:   info->assemblies        = A->num_ass;
    492:   info->mallocs           = 0.0;
    493:   info->memory            = 0;
    494:   info->fill_ratio_given  = 0;
    495:   info->fill_ratio_needed = 0;
    496:   info->factor_mallocs    = 0;
    497:   PetscFunctionReturn(PETSC_SUCCESS);
    498: }

    500: /*@
    501:   MatCreateDiagonal - Creates a matrix defined by a given vector along its diagonal.

    503:   Collective

    505:   Input Parameter:
    506: . diag - vector for the diagonal

    508:   Output Parameter:
    509: . J - the diagonal matrix

    511:   Level: advanced

    513:   Notes:
    514:   Only supports square matrices with the same number of local rows and columns.

    516:   The input vector `diag` will be referenced internally: any changes to `diag`
    517:   will affect the matrix `J`.

    519: .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `MATCONSTANTDIAGONAL`, `MatScale()`, `MatShift()`, `MatMult()`, `MatGetDiagonal()`, `MatSolve()`
    520:           `MatDiagonalRestoreInverseDiagonal()`, `MatDiagonalGetDiagonal()`, `MatDiagonalRestoreDiagonal()`, `MatDiagonalGetInverseDiagonal()`
    521: @*/
    522: PetscErrorCode MatCreateDiagonal(Vec diag, Mat *J)
    523: {
    524:   PetscFunctionBegin;
    526:   PetscCall(MatCreate(PetscObjectComm((PetscObject)diag), J));
    527:   PetscInt m, M;
    528:   PetscCall(VecGetLocalSize(diag, &m));
    529:   PetscCall(VecGetSize(diag, &M));
    530:   PetscCall(MatSetSizes(*J, m, m, M, M));
    531:   PetscCall(MatSetType(*J, MATDIAGONAL));

    533:   PetscLayout map;
    534:   PetscCall(VecGetLayout(diag, &map));
    535:   PetscCall(MatSetLayouts(*J, map, map));
    536:   Mat_Diagonal *ctx = (Mat_Diagonal *)(*J)->data;
    537:   PetscCall(PetscObjectReference((PetscObject)diag));
    538:   PetscCall(VecDestroy(&ctx->diag));
    539:   PetscCall(VecDestroy(&ctx->inv_diag));
    540:   ctx->diag           = diag;
    541:   ctx->diag_valid     = PETSC_TRUE;
    542:   ctx->inv_diag_valid = PETSC_FALSE;
    543:   VecType type;
    544:   PetscCall(VecDuplicate(ctx->diag, &ctx->inv_diag));
    545:   PetscCall(VecGetType(diag, &type));
    546:   PetscCall(PetscFree((*J)->defaultvectype));
    547:   PetscCall(PetscStrallocpy(type, &(*J)->defaultvectype));
    548:   PetscCall(MatSetUp(*J));
    549:   ctx->col = NULL;
    550:   ctx->val = NULL;
    551:   PetscFunctionReturn(PETSC_SUCCESS);
    552: }

    554: static PetscErrorCode MatProductNumeric_Diagonal_Dense(Mat C)
    555: {
    556:   Mat                A, B;
    557:   Mat_Diagonal      *a;
    558:   PetscScalar       *c;
    559:   const PetscScalar *b, *alpha;
    560:   PetscInt           ldb, ldc;

    562:   PetscFunctionBegin;
    563:   MatCheckProduct(C, 1);
    564:   A = C->product->A;
    565:   B = C->product->B;
    566:   a = (Mat_Diagonal *)A->data;
    567:   PetscCall(VecGetArrayRead(a->diag, &alpha));
    568:   PetscCall(MatDenseGetLDA(B, &ldb));
    569:   PetscCall(MatDenseGetLDA(C, &ldc));
    570:   PetscCall(MatDenseGetArrayRead(B, &b));
    571:   PetscCall(MatDenseGetArrayWrite(C, &c));
    572:   for (PetscInt j = 0; j < B->cmap->N; j++)
    573:     for (PetscInt i = 0; i < B->rmap->n; i++) c[i + j * ldc] = alpha[i] * b[i + j * ldb];
    574:   PetscCall(MatDenseRestoreArrayWrite(C, &c));
    575:   PetscCall(MatDenseRestoreArrayRead(B, &b));
    576:   PetscCall(VecRestoreArrayRead(a->diag, &alpha));
    577:   PetscCall(PetscLogFlops(B->cmap->N * B->rmap->n));
    578:   PetscFunctionReturn(PETSC_SUCCESS);
    579: }

    581: static PetscErrorCode MatProductSymbolic_Diagonal_Dense(Mat C)
    582: {
    583:   Mat      A, B;
    584:   PetscInt n, N, m, M;

    586:   PetscFunctionBegin;
    587:   MatCheckProduct(C, 1);
    588:   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
    589:   A = C->product->A;
    590:   B = C->product->B;
    591:   PetscCall(MatDiagonalSetUpDiagonal(A));
    592:   PetscCall(MatGetLocalSize(C, &m, &n));
    593:   PetscCall(MatGetSize(C, &M, &N));
    594:   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
    595:     PetscCall(MatGetLocalSize(B, NULL, &n));
    596:     PetscCall(MatGetSize(B, NULL, &N));
    597:     PetscCall(MatGetLocalSize(A, &m, NULL));
    598:     PetscCall(MatGetSize(A, &M, NULL));
    599:     PetscCall(MatSetSizes(C, m, n, M, N));
    600:   }
    601:   PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
    602:   PetscCall(MatSetUp(C));
    603:   C->ops->productnumeric = MatProductNumeric_Diagonal_Dense;
    604:   PetscFunctionReturn(PETSC_SUCCESS);
    605: }

    607: static PetscErrorCode MatProductSetFromOptions_Diagonal_Dense_AB(Mat C)
    608: {
    609:   PetscFunctionBegin;
    610:   C->ops->productsymbolic = MatProductSymbolic_Diagonal_Dense;
    611:   PetscFunctionReturn(PETSC_SUCCESS);
    612: }

    614: static PetscErrorCode MatProductSetFromOptions_Diagonal_Dense(Mat C)
    615: {
    616:   Mat_Product *product = C->product;

    618:   PetscFunctionBegin;
    619:   if (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB) PetscCall(MatProductSetFromOptions_Diagonal_Dense_AB(C));
    620:   PetscFunctionReturn(PETSC_SUCCESS);
    621: }

    623: /*MC
    624:    MATDIAGONAL - MATDIAGONAL = "diagonal" - A diagonal matrix type with the diagonal implemented as a `Vec`.  Useful for
    625:    cases where `VecPointwiseMult()` or `VecPointwiseDivide()` should be thought of as the actions of a linear operator.

    627:   Level: advanced

    629: .seealso: [](ch_matrices), `Mat`, `MatCreateDiagonal()`, `MatDiagonalRestoreInverseDiagonal()`, `MatDiagonalGetDiagonal()`, `MatDiagonalRestoreDiagonal()`, `MatDiagonalGetInverseDiagonal()`
    630: M*/
    631: PETSC_INTERN PetscErrorCode MatCreate_Diagonal(Mat A)
    632: {
    633:   Mat_Diagonal *ctx;

    635:   PetscFunctionBegin;
    636:   PetscCall(PetscNew(&ctx));
    637:   A->data = (void *)ctx;

    639:   A->structurally_symmetric      = PETSC_BOOL3_TRUE;
    640:   A->structural_symmetry_eternal = PETSC_TRUE;
    641:   A->symmetry_eternal            = PETSC_TRUE;
    642:   A->symmetric                   = PETSC_BOOL3_TRUE;
    643:   if (!PetscDefined(USE_COMPLEX)) A->hermitian = PETSC_BOOL3_TRUE;

    645:   A->ops->getrow           = MatGetRow_Diagonal;
    646:   A->ops->mult             = MatMult_Diagonal;
    647:   A->ops->multadd          = MatMultAdd_Diagonal;
    648:   A->ops->multtranspose    = MatMult_Diagonal;
    649:   A->ops->multtransposeadd = MatMultAdd_Diagonal;
    650:   A->ops->norm             = MatNorm_Diagonal;
    651:   A->ops->duplicate        = MatDuplicate_Diagonal;
    652:   A->ops->solve            = MatSolve_Diagonal;
    653:   A->ops->solvetranspose   = MatSolve_Diagonal;
    654:   A->ops->shift            = MatShift_Diagonal;
    655:   A->ops->scale            = MatScale_Diagonal;
    656:   A->ops->diagonalscale    = MatDiagonalScale_Diagonal;
    657:   A->ops->getdiagonal      = MatGetDiagonal_Diagonal;
    658:   A->ops->diagonalset      = MatDiagonalSet_Diagonal;
    659:   A->ops->view             = MatView_Diagonal;
    660:   A->ops->zeroentries      = MatZeroEntries_Diagonal;
    661:   A->ops->destroy          = MatDestroy_Diagonal;
    662:   A->ops->getinfo          = MatGetInfo_Diagonal;
    663:   A->ops->axpy             = MatAXPY_Diagonal;
    664:   A->ops->setup            = MatSetUp_Diagonal;
    665:   A->ops->permute          = MatPermute_Diagonal;

    667:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalGetDiagonal_C", MatDiagonalGetDiagonal_Diagonal));
    668:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalRestoreDiagonal_C", MatDiagonalRestoreDiagonal_Diagonal));
    669:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalGetInverseDiagonal_C", MatDiagonalGetInverseDiagonal_Diagonal));
    670:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalRestoreInverseDiagonal_C", MatDiagonalRestoreInverseDiagonal_Diagonal));
    671:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_diagonal_seqdense_C", MatProductSetFromOptions_Diagonal_Dense));
    672:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_diagonal_mpidense_C", MatProductSetFromOptions_Diagonal_Dense));
    673:   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATDIAGONAL));
    674:   PetscFunctionReturn(PETSC_SUCCESS);
    675: }