xref: /petsc/src/mat/impls/diagonal/diagonal.c (revision e91c04dfc8a52dee1965211bb1cc8e5bf775178f)
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