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 MatRestoreRow_Diagonal(Mat A, PetscInt row, PetscInt *ncols, PetscInt **cols, PetscScalar **vals)
 78: {
 79:   PetscFunctionBegin;
 80:   PetscFunctionReturn(PETSC_SUCCESS);
 81: }

 83: static PetscErrorCode MatMult_Diagonal(Mat A, Vec x, Vec y)
 84: {
 85:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

 87:   PetscFunctionBegin;
 88:   PetscCall(MatDiagonalSetUpDiagonal(A));
 89:   PetscCall(VecPointwiseMult(y, ctx->diag, x));
 90:   PetscFunctionReturn(PETSC_SUCCESS);
 91: }

 93: static PetscErrorCode MatMultAdd_Diagonal(Mat mat, Vec v1, Vec v2, Vec v3)
 94: {
 95:   Mat_Diagonal *ctx = (Mat_Diagonal *)mat->data;

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

112: static PetscErrorCode MatNorm_Diagonal(Mat A, NormType type, PetscReal *nrm)
113: {
114:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

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

123: static PetscErrorCode MatDuplicate_Diagonal(Mat A, MatDuplicateOption op, Mat *B)
124: {
125:   Mat_Diagonal *actx = (Mat_Diagonal *)A->data;

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;

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

147: /*@
148:   MatDiagonalGetDiagonal - Get the diagonal of a `MATDIAGONAL`

150:   Input Parameter:
151: . A - the `MATDIAGONAL`

153:   Output Parameter:
154: . diag - the `Vec` that defines the diagonal

156:   Level: developer

158:   Note:
159:   The user must call
160:   `MatDiagonalRestoreDiagonal()` before using the matrix again.

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

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

166: .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalRestoreDiagonal()`, `MatDiagonalGetInverseDiagonal()`, `MatGetDiagonal()`
167: @*/
168: PetscErrorCode MatDiagonalGetDiagonal(Mat A, Vec *diag)
169: {
170:   PetscFunctionBegin;
172:   PetscAssertPointer(diag, 2);
173:   *diag = NULL;
174:   PetscUseMethod((PetscObject)A, "MatDiagonalGetDiagonal_C", (Mat, Vec *), (A, diag));
175:   PetscFunctionReturn(PETSC_SUCCESS);
176: }

178: static PetscErrorCode MatDiagonalGetDiagonal_Diagonal(Mat A, Vec *diag)
179: {
180:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

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

190: /*@
191:   MatDiagonalRestoreDiagonal - Restore the diagonal of a `MATDIAGONAL`

193:   Input Parameters:
194: + A    - the `MATDIAGONAL`
195: - diag - the `Vec` obtained from `MatDiagonalGetDiagonal()`

197:   Level: developer

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

202: .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalGetDiagonal()`
203: @*/
204: PetscErrorCode MatDiagonalRestoreDiagonal(Mat A, Vec *diag)
205: {
206:   PetscFunctionBegin;
208:   PetscAssertPointer(diag, 2);
209:   PetscUseMethod((PetscObject)A, "MatDiagonalRestoreDiagonal_C", (Mat, Vec *), (A, diag));
210:   PetscFunctionReturn(PETSC_SUCCESS);
211: }

213: static PetscErrorCode MatDiagonalRestoreDiagonal_Diagonal(Mat A, Vec *diag)
214: {
215:   Mat_Diagonal    *ctx = (Mat_Diagonal *)A->data;
216:   PetscObjectState diag_state;

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

230: /*@
231:   MatDiagonalGetInverseDiagonal - Get the inverse diagonal of a `MATDIAGONAL`

233:   Input Parameter:
234: . A - the `MATDIAGONAL`

236:   Output Parameter:
237: . inv_diag - the `Vec` that defines the inverse diagonal

239:   Level: developer

241:   Note:
242:   The user must call
243:   `MatDiagonalRestoreInverseDiagonal()` before using the matrix again.

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()`.

249: .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalRestoreInverseDiagonal()`, `MatDiagonalGetDiagonal()`, `MATLMVMBROYDEN`, `MatSolve()`
250: @*/
251: PetscErrorCode MatDiagonalGetInverseDiagonal(Mat A, Vec *inv_diag)
252: {
253:   PetscFunctionBegin;
255:   PetscAssertPointer(inv_diag, 2);
256:   *inv_diag = NULL;
257:   PetscUseMethod((PetscObject)A, "MatDiagonalGetInverseDiagonal_C", (Mat, Vec *), (A, inv_diag));
258:   PetscFunctionReturn(PETSC_SUCCESS);
259: }

261: static PetscErrorCode MatDiagonalGetInverseDiagonal_Diagonal(Mat A, Vec *inv_diag)
262: {
263:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

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

273: /*@
274:   MatDiagonalRestoreInverseDiagonal - Restore the inverse diagonal of a `MATDIAGONAL`

276:   Input Parameters:
277: + A        - the `MATDIAGONAL`
278: - inv_diag - the `Vec` obtained from `MatDiagonalGetInverseDiagonal()`

280:   Level: developer

282: .seealso: [](ch_matrices), `MATDIAGONAL`, `MatCreateDiagonal()`, `MatDiagonalGetInverseDiagonal()`
283: @*/
284: PetscErrorCode MatDiagonalRestoreInverseDiagonal(Mat A, Vec *inv_diag)
285: {
286:   PetscFunctionBegin;
288:   PetscAssertPointer(inv_diag, 2);
289:   PetscUseMethod((PetscObject)A, "MatDiagonalRestoreInverseDiagonal_C", (Mat, Vec *), (A, inv_diag));
290:   PetscFunctionReturn(PETSC_SUCCESS);
291: }

293: static PetscErrorCode MatDiagonalRestoreInverseDiagonal_Diagonal(Mat A, Vec *inv_diag)
294: {
295:   Mat_Diagonal    *ctx = (Mat_Diagonal *)A->data;
296:   PetscObjectState inv_diag_state;

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

310: static PetscErrorCode MatDestroy_Diagonal(Mat mat)
311: {
312:   Mat_Diagonal *ctx = (Mat_Diagonal *)mat->data;

314:   PetscFunctionBegin;
315:   PetscCall(VecDestroy(&ctx->diag));
316:   PetscCall(VecDestroy(&ctx->inv_diag));
317:   PetscCall(PetscFree(ctx->col));
318:   PetscCall(PetscFree(ctx->val));
319:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalGetDiagonal_C", NULL));
320:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalRestoreDiagonal_C", NULL));
321:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalGetInverseDiagonal_C", NULL));
322:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalRestoreInverseDiagonal_C", NULL));
323:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_diagonal_seqdense_C", NULL));
324:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_diagonal_mpidense_C", NULL));
325:   PetscCall(PetscFree(mat->data));
326:   mat->structural_symmetry_eternal = PETSC_FALSE;
327:   mat->symmetry_eternal            = PETSC_FALSE;
328:   PetscFunctionReturn(PETSC_SUCCESS);
329: }

331: static PetscErrorCode MatView_Diagonal(Mat J, PetscViewer viewer)
332: {
333:   Mat_Diagonal *ctx = (Mat_Diagonal *)J->data;
334:   PetscBool     iascii;

336:   PetscFunctionBegin;
337:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
338:   if (iascii) {
339:     PetscViewerFormat format;

341:     PetscCall(PetscViewerGetFormat(viewer, &format));
342:     if (format == PETSC_VIEWER_ASCII_FACTOR_INFO || format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS);
343:     PetscCall(MatDiagonalSetUpDiagonal(J));
344:     PetscCall(VecView(ctx->diag, viewer));
345:   }
346:   PetscFunctionReturn(PETSC_SUCCESS);
347: }

349: static PetscErrorCode MatGetDiagonal_Diagonal(Mat J, Vec x)
350: {
351:   Mat_Diagonal *ctx = (Mat_Diagonal *)J->data;

353:   PetscFunctionBegin;
354:   PetscCall(MatDiagonalSetUpDiagonal(J));
355:   PetscCall(VecCopy(ctx->diag, x));
356:   PetscFunctionReturn(PETSC_SUCCESS);
357: }

359: static PetscErrorCode MatDiagonalSet_Diagonal(Mat J, Vec D, InsertMode is)
360: {
361:   Mat_Diagonal *ctx = (Mat_Diagonal *)J->data;

363:   PetscFunctionBegin;
364:   switch (is) {
365:   case ADD_VALUES:
366:   case ADD_ALL_VALUES:
367:   case ADD_BC_VALUES:
368:     PetscCall(MatDiagonalSetUpDiagonal(J));
369:     PetscCall(VecAXPY(ctx->diag, 1.0, D));
370:     ctx->inv_diag_valid = PETSC_FALSE;
371:     break;
372:   case INSERT_VALUES:
373:   case INSERT_BC_VALUES:
374:   case INSERT_ALL_VALUES:
375:     PetscCall(MatSetUp(J));
376:     PetscCall(VecCopy(D, ctx->diag));
377:     ctx->diag_valid     = PETSC_TRUE;
378:     ctx->inv_diag_valid = PETSC_FALSE;
379:     break;
380:   case MAX_VALUES:
381:     PetscCall(MatDiagonalSetUpDiagonal(J));
382:     PetscCall(VecPointwiseMax(ctx->diag, D, ctx->diag));
383:     ctx->inv_diag_valid = PETSC_FALSE;
384:     break;
385:   case MIN_VALUES:
386:     PetscCall(MatDiagonalSetUpDiagonal(J));
387:     PetscCall(VecPointwiseMin(ctx->diag, D, ctx->diag));
388:     ctx->inv_diag_valid = PETSC_FALSE;
389:     break;
390:   case NOT_SET_VALUES:
391:     break;
392:   }
393:   PetscFunctionReturn(PETSC_SUCCESS);
394: }

396: static PetscErrorCode MatShift_Diagonal(Mat Y, PetscScalar a)
397: {
398:   Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data;

400:   PetscFunctionBegin;
401:   PetscCall(MatDiagonalSetUpDiagonal(Y));
402:   PetscCall(VecShift(ctx->diag, a));
403:   ctx->inv_diag_valid = PETSC_FALSE;
404:   PetscFunctionReturn(PETSC_SUCCESS);
405: }

407: static PetscErrorCode MatScale_Diagonal(Mat Y, PetscScalar a)
408: {
409:   Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data;

411:   PetscFunctionBegin;
412:   PetscCall(MatSetUp(Y));
413:   PetscCall(MatDiagonalSetUpDiagonal(Y));
414:   PetscCall(VecScale(ctx->diag, a));
415:   ctx->inv_diag_valid = PETSC_FALSE;
416:   PetscFunctionReturn(PETSC_SUCCESS);
417: }

419: static PetscErrorCode MatDiagonalScale_Diagonal(Mat Y, Vec l, Vec r)
420: {
421:   Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data;

423:   PetscFunctionBegin;
424:   PetscCall(MatDiagonalSetUpDiagonal(Y));
425:   if (l) {
426:     PetscCall(VecPointwiseMult(ctx->diag, ctx->diag, l));
427:     ctx->inv_diag_valid = PETSC_FALSE;
428:   }
429:   if (r) {
430:     PetscCall(VecPointwiseMult(ctx->diag, ctx->diag, r));
431:     ctx->inv_diag_valid = PETSC_FALSE;
432:   }
433:   PetscFunctionReturn(PETSC_SUCCESS);
434: }

436: static PetscErrorCode MatSetUp_Diagonal(Mat A)
437: {
438:   Mat_Diagonal *ctx = (Mat_Diagonal *)A->data;

440:   PetscFunctionBegin;
441:   if (!ctx->diag) {
442:     PetscCall(PetscLayoutSetUp(A->cmap));
443:     PetscCall(PetscLayoutSetUp(A->rmap));
444:     PetscCall(MatCreateVecs(A, &ctx->diag, NULL));
445:     PetscCall(VecDuplicate(ctx->diag, &ctx->inv_diag));
446:     PetscCall(VecZeroEntries(ctx->diag));
447:     ctx->diag_valid = PETSC_TRUE;
448:   }
449:   A->assembled = PETSC_TRUE;
450:   PetscFunctionReturn(PETSC_SUCCESS);
451: }

453: static PetscErrorCode MatZeroEntries_Diagonal(Mat Y)
454: {
455:   Mat_Diagonal *ctx = (Mat_Diagonal *)Y->data;

457:   PetscFunctionBegin;
458:   PetscCall(MatSetUp(Y));
459:   PetscCall(VecZeroEntries(ctx->diag));
460:   ctx->diag_valid     = PETSC_TRUE;
461:   ctx->inv_diag_valid = PETSC_FALSE;
462:   PetscFunctionReturn(PETSC_SUCCESS);
463: }

465: static PetscErrorCode MatSolve_Diagonal(Mat matin, Vec b, Vec x)
466: {
467:   Mat_Diagonal *ctx = (Mat_Diagonal *)matin->data;

469:   PetscFunctionBegin;
470:   PetscCall(MatDiagonalSetUpInverseDiagonal(matin));
471:   PetscCall(VecPointwiseMult(x, b, ctx->inv_diag));
472:   PetscFunctionReturn(PETSC_SUCCESS);
473: }

475: static PetscErrorCode MatGetInfo_Diagonal(Mat A, MatInfoType flag, MatInfo *info)
476: {
477:   PetscFunctionBegin;
478:   info->block_size        = 1.0;
479:   info->nz_allocated      = A->cmap->N;
480:   info->nz_used           = A->cmap->N;
481:   info->nz_unneeded       = 0.0;
482:   info->assemblies        = A->num_ass;
483:   info->mallocs           = 0.0;
484:   info->memory            = 0;
485:   info->fill_ratio_given  = 0;
486:   info->fill_ratio_needed = 0;
487:   info->factor_mallocs    = 0;
488:   PetscFunctionReturn(PETSC_SUCCESS);
489: }

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

494:   Collective

496:   Input Parameter:
497: . diag - vector for the diagonal

499:   Output Parameter:
500: . J - the diagonal matrix

502:   Level: advanced

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

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

510: .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `MATCONSTANTDIAGONAL`, `MatScale()`, `MatShift()`, `MatMult()`, `MatGetDiagonal()`, `MatSolve()`
511:           `MatDiagonalRestoreInverseDiagonal()`, `MatDiagonalGetDiagonal()`, `MatDiagonalRestoreDiagonal()`, `MatDiagonalGetInverseDiagonal()`
512: @*/
513: PetscErrorCode MatCreateDiagonal(Vec diag, Mat *J)
514: {
515:   PetscFunctionBegin;
517:   PetscCall(MatCreate(PetscObjectComm((PetscObject)diag), J));
518:   PetscInt m, M;
519:   PetscCall(VecGetLocalSize(diag, &m));
520:   PetscCall(VecGetSize(diag, &M));
521:   PetscCall(MatSetSizes(*J, m, m, M, M));
522:   PetscCall(MatSetType(*J, MATDIAGONAL));

524:   PetscLayout map;
525:   PetscCall(VecGetLayout(diag, &map));
526:   PetscCall(MatSetLayouts(*J, map, map));
527:   Mat_Diagonal *ctx = (Mat_Diagonal *)(*J)->data;
528:   PetscCall(PetscObjectReference((PetscObject)diag));
529:   PetscCall(VecDestroy(&ctx->diag));
530:   PetscCall(VecDestroy(&ctx->inv_diag));
531:   ctx->diag           = diag;
532:   ctx->diag_valid     = PETSC_TRUE;
533:   ctx->inv_diag_valid = PETSC_FALSE;
534:   VecType type;
535:   PetscCall(VecDuplicate(ctx->diag, &ctx->inv_diag));
536:   PetscCall(VecGetType(diag, &type));
537:   PetscCall(PetscFree((*J)->defaultvectype));
538:   PetscCall(PetscStrallocpy(type, &(*J)->defaultvectype));
539:   PetscCall(MatSetUp(*J));
540:   ctx->col = NULL;
541:   ctx->val = NULL;
542:   PetscFunctionReturn(PETSC_SUCCESS);
543: }

545: static PetscErrorCode MatProductNumeric_Diagonal_Dense(Mat C)
546: {
547:   Mat                A, B;
548:   Mat_Diagonal      *a;
549:   PetscScalar       *c;
550:   const PetscScalar *b, *alpha;
551:   PetscInt           ldb, ldc;

553:   PetscFunctionBegin;
554:   MatCheckProduct(C, 1);
555:   A = C->product->A;
556:   B = C->product->B;
557:   a = (Mat_Diagonal *)A->data;
558:   PetscCall(VecGetArrayRead(a->diag, &alpha));
559:   PetscCall(MatDenseGetLDA(B, &ldb));
560:   PetscCall(MatDenseGetLDA(C, &ldc));
561:   PetscCall(MatDenseGetArrayRead(B, &b));
562:   PetscCall(MatDenseGetArrayWrite(C, &c));
563:   for (PetscInt j = 0; j < B->cmap->N; j++)
564:     for (PetscInt i = 0; i < B->rmap->n; i++) c[i + j * ldc] = alpha[i] * b[i + j * ldb];
565:   PetscCall(MatDenseRestoreArrayWrite(C, &c));
566:   PetscCall(MatDenseRestoreArrayRead(B, &b));
567:   PetscCall(VecRestoreArrayRead(a->diag, &alpha));
568:   PetscCall(PetscLogFlops(B->cmap->N * B->rmap->n));
569:   PetscFunctionReturn(PETSC_SUCCESS);
570: }

572: static PetscErrorCode MatProductSymbolic_Diagonal_Dense(Mat C)
573: {
574:   Mat      A, B;
575:   PetscInt n, N, m, M;

577:   PetscFunctionBegin;
578:   MatCheckProduct(C, 1);
579:   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
580:   A = C->product->A;
581:   B = C->product->B;
582:   PetscCall(MatDiagonalSetUpDiagonal(A));
583:   PetscCall(MatGetLocalSize(C, &m, &n));
584:   PetscCall(MatGetSize(C, &M, &N));
585:   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
586:     PetscCall(MatGetLocalSize(B, NULL, &n));
587:     PetscCall(MatGetSize(B, NULL, &N));
588:     PetscCall(MatGetLocalSize(A, &m, NULL));
589:     PetscCall(MatGetSize(A, &M, NULL));
590:     PetscCall(MatSetSizes(C, m, n, M, N));
591:   }
592:   PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
593:   PetscCall(MatSetUp(C));
594:   C->ops->productnumeric = MatProductNumeric_Diagonal_Dense;
595:   PetscFunctionReturn(PETSC_SUCCESS);
596: }

598: static PetscErrorCode MatProductSetFromOptions_Diagonal_Dense_AB(Mat C)
599: {
600:   PetscFunctionBegin;
601:   C->ops->productsymbolic = MatProductSymbolic_Diagonal_Dense;
602:   PetscFunctionReturn(PETSC_SUCCESS);
603: }

605: static PetscErrorCode MatProductSetFromOptions_Diagonal_Dense(Mat C)
606: {
607:   Mat_Product *product = C->product;

609:   PetscFunctionBegin;
610:   if (product->type == MATPRODUCT_AB || product->type == MATPRODUCT_AtB) PetscCall(MatProductSetFromOptions_Diagonal_Dense_AB(C));
611:   PetscFunctionReturn(PETSC_SUCCESS);
612: }

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

618:   Level: advanced

620: .seealso: [](ch_matrices), `Mat`, `MatCreateDiagonal()`, `MatDiagonalRestoreInverseDiagonal()`, `MatDiagonalGetDiagonal()`, `MatDiagonalRestoreDiagonal()`, `MatDiagonalGetInverseDiagonal()`
621: M*/
622: PETSC_INTERN PetscErrorCode MatCreate_Diagonal(Mat A)
623: {
624:   Mat_Diagonal *ctx;

626:   PetscFunctionBegin;
627:   PetscCall(PetscNew(&ctx));
628:   A->data = (void *)ctx;

630:   A->structurally_symmetric      = PETSC_BOOL3_TRUE;
631:   A->structural_symmetry_eternal = PETSC_TRUE;
632:   A->symmetry_eternal            = PETSC_TRUE;
633:   A->symmetric                   = PETSC_BOOL3_TRUE;
634:   if (!PetscDefined(USE_COMPLEX)) A->hermitian = PETSC_BOOL3_TRUE;

636:   A->ops->getrow           = MatGetRow_Diagonal;
637:   A->ops->restorerow       = MatRestoreRow_Diagonal;
638:   A->ops->mult             = MatMult_Diagonal;
639:   A->ops->multadd          = MatMultAdd_Diagonal;
640:   A->ops->multtranspose    = MatMult_Diagonal;
641:   A->ops->multtransposeadd = MatMultAdd_Diagonal;
642:   A->ops->norm             = MatNorm_Diagonal;
643:   A->ops->duplicate        = MatDuplicate_Diagonal;
644:   A->ops->solve            = MatSolve_Diagonal;
645:   A->ops->solvetranspose   = MatSolve_Diagonal;
646:   A->ops->shift            = MatShift_Diagonal;
647:   A->ops->scale            = MatScale_Diagonal;
648:   A->ops->diagonalscale    = MatDiagonalScale_Diagonal;
649:   A->ops->getdiagonal      = MatGetDiagonal_Diagonal;
650:   A->ops->diagonalset      = MatDiagonalSet_Diagonal;
651:   A->ops->view             = MatView_Diagonal;
652:   A->ops->zeroentries      = MatZeroEntries_Diagonal;
653:   A->ops->destroy          = MatDestroy_Diagonal;
654:   A->ops->getinfo          = MatGetInfo_Diagonal;
655:   A->ops->axpy             = MatAXPY_Diagonal;
656:   A->ops->setup            = MatSetUp_Diagonal;

658:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalGetDiagonal_C", MatDiagonalGetDiagonal_Diagonal));
659:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalRestoreDiagonal_C", MatDiagonalRestoreDiagonal_Diagonal));
660:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalGetInverseDiagonal_C", MatDiagonalGetInverseDiagonal_Diagonal));
661:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatDiagonalRestoreInverseDiagonal_C", MatDiagonalRestoreInverseDiagonal_Diagonal));
662:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_diagonal_seqdense_C", MatProductSetFromOptions_Diagonal_Dense));
663:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_diagonal_mpidense_C", MatProductSetFromOptions_Diagonal_Dense));
664:   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATDIAGONAL));
665:   PetscFunctionReturn(PETSC_SUCCESS);
666: }