xref: /petsc/src/mat/impls/nest/matnest.c (revision f8b9f887efa5534f423807e37a1fe2e87d779bac)
1 #include <../src/mat/impls/nest/matnestimpl.h> /*I   "petscmat.h"   I*/
2 #include <../src/mat/impls/aij/seq/aij.h>
3 #include <../src/mat/impls/shell/shell.h>
4 #include <petscsf.h>
5 
6 static PetscErrorCode MatSetUp_NestIS_Private(Mat, PetscInt, const IS[], PetscInt, const IS[]);
7 static PetscErrorCode MatCreateVecs_Nest(Mat, Vec *, Vec *);
8 static PetscErrorCode MatReset_Nest(Mat);
9 
10 PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat, MatType, MatReuse, Mat *);
11 
12 /* private functions */
13 static PetscErrorCode MatNestGetSizes_Private(Mat A, PetscInt *m, PetscInt *n, PetscInt *M, PetscInt *N)
14 {
15   Mat_Nest *bA = (Mat_Nest *)A->data;
16   PetscInt  i, j;
17 
18   PetscFunctionBegin;
19   *m = *n = *M = *N = 0;
20   for (i = 0; i < bA->nr; i++) { /* rows */
21     PetscInt sm, sM;
22     PetscCall(ISGetLocalSize(bA->isglobal.row[i], &sm));
23     PetscCall(ISGetSize(bA->isglobal.row[i], &sM));
24     *m += sm;
25     *M += sM;
26   }
27   for (j = 0; j < bA->nc; j++) { /* cols */
28     PetscInt sn, sN;
29     PetscCall(ISGetLocalSize(bA->isglobal.col[j], &sn));
30     PetscCall(ISGetSize(bA->isglobal.col[j], &sN));
31     *n += sn;
32     *N += sN;
33   }
34   PetscFunctionReturn(PETSC_SUCCESS);
35 }
36 
37 /* operations */
38 static PetscErrorCode MatMult_Nest(Mat A, Vec x, Vec y)
39 {
40   Mat_Nest *bA = (Mat_Nest *)A->data;
41   Vec      *bx = bA->right, *by = bA->left;
42   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
43 
44   PetscFunctionBegin;
45   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by[i]));
46   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i]));
47   for (i = 0; i < nr; i++) {
48     PetscCall(VecZeroEntries(by[i]));
49     for (j = 0; j < nc; j++) {
50       if (!bA->m[i][j]) continue;
51       /* y[i] <- y[i] + A[i][j] * x[j] */
52       PetscCall(MatMultAdd(bA->m[i][j], bx[j], by[i], by[i]));
53     }
54   }
55   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by[i]));
56   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i]));
57   PetscFunctionReturn(PETSC_SUCCESS);
58 }
59 
60 static PetscErrorCode MatMultAdd_Nest(Mat A, Vec x, Vec y, Vec z)
61 {
62   Mat_Nest *bA = (Mat_Nest *)A->data;
63   Vec      *bx = bA->right, *bz = bA->left;
64   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
65 
66   PetscFunctionBegin;
67   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(z, bA->isglobal.row[i], &bz[i]));
68   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i]));
69   for (i = 0; i < nr; i++) {
70     if (y != z) {
71       Vec by;
72       PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by));
73       PetscCall(VecCopy(by, bz[i]));
74       PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by));
75     }
76     for (j = 0; j < nc; j++) {
77       if (!bA->m[i][j]) continue;
78       /* y[i] <- y[i] + A[i][j] * x[j] */
79       PetscCall(MatMultAdd(bA->m[i][j], bx[j], bz[i], bz[i]));
80     }
81   }
82   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.row[i], &bz[i]));
83   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i]));
84   PetscFunctionReturn(PETSC_SUCCESS);
85 }
86 
87 typedef struct {
88   Mat         *workC;      /* array of Mat with specific containers depending on the underlying MatMatMult implementation */
89   PetscScalar *tarray;     /* buffer for storing all temporary products A[i][j] B[j] */
90   PetscInt    *dm, *dn, k; /* displacements and number of submatrices */
91 } Nest_Dense;
92 
93 static PetscErrorCode MatProductNumeric_Nest_Dense(Mat C)
94 {
95   Mat_Nest          *bA;
96   Nest_Dense        *contents;
97   Mat                viewB, viewC, productB, workC;
98   const PetscScalar *barray;
99   PetscScalar       *carray;
100   PetscInt           i, j, M, N, nr, nc, ldb, ldc;
101   Mat                A, B;
102 
103   PetscFunctionBegin;
104   MatCheckProduct(C, 1);
105   A = C->product->A;
106   B = C->product->B;
107   PetscCall(MatGetSize(B, NULL, &N));
108   if (!N) {
109     PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
110     PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
111     PetscFunctionReturn(PETSC_SUCCESS);
112   }
113   contents = (Nest_Dense *)C->product->data;
114   PetscCheck(contents, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty");
115   bA = (Mat_Nest *)A->data;
116   nr = bA->nr;
117   nc = bA->nc;
118   PetscCall(MatDenseGetLDA(B, &ldb));
119   PetscCall(MatDenseGetLDA(C, &ldc));
120   PetscCall(MatZeroEntries(C));
121   PetscCall(MatDenseGetArrayRead(B, &barray));
122   PetscCall(MatDenseGetArray(C, &carray));
123   for (i = 0; i < nr; i++) {
124     PetscCall(ISGetSize(bA->isglobal.row[i], &M));
125     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset(carray, contents->dm[i]), &viewC));
126     PetscCall(MatDenseSetLDA(viewC, ldc));
127     for (j = 0; j < nc; j++) {
128       if (!bA->m[i][j]) continue;
129       PetscCall(ISGetSize(bA->isglobal.col[j], &M));
130       PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB));
131       PetscCall(MatDenseSetLDA(viewB, ldb));
132 
133       /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */
134       workC             = contents->workC[i * nc + j];
135       productB          = workC->product->B;
136       workC->product->B = viewB; /* use newly created dense matrix viewB */
137       PetscCall(MatProductNumeric(workC));
138       PetscCall(MatDestroy(&viewB));
139       workC->product->B = productB; /* resume original B */
140 
141       /* C[i] <- workC + C[i] */
142       PetscCall(MatAXPY(viewC, 1.0, contents->workC[i * nc + j], SAME_NONZERO_PATTERN));
143     }
144     PetscCall(MatDestroy(&viewC));
145   }
146   PetscCall(MatDenseRestoreArray(C, &carray));
147   PetscCall(MatDenseRestoreArrayRead(B, &barray));
148 
149   PetscCall(MatSetOption(C, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
150   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
151   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
152   PetscFunctionReturn(PETSC_SUCCESS);
153 }
154 
155 static PetscErrorCode MatNest_DenseDestroy(void *ctx)
156 {
157   Nest_Dense *contents = (Nest_Dense *)ctx;
158   PetscInt    i;
159 
160   PetscFunctionBegin;
161   PetscCall(PetscFree(contents->tarray));
162   for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i));
163   PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC));
164   PetscCall(PetscFree(contents));
165   PetscFunctionReturn(PETSC_SUCCESS);
166 }
167 
168 static PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C)
169 {
170   Mat_Nest          *bA;
171   Mat                viewB, workC;
172   const PetscScalar *barray;
173   PetscInt           i, j, M, N, m, n, nr, nc, maxm = 0, ldb;
174   Nest_Dense        *contents = NULL;
175   PetscBool          cisdense;
176   Mat                A, B;
177   PetscReal          fill;
178 
179   PetscFunctionBegin;
180   MatCheckProduct(C, 1);
181   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
182   A    = C->product->A;
183   B    = C->product->B;
184   fill = C->product->fill;
185   bA   = (Mat_Nest *)A->data;
186   nr   = bA->nr;
187   nc   = bA->nc;
188   PetscCall(MatGetLocalSize(C, &m, &n));
189   PetscCall(MatGetSize(C, &M, &N));
190   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
191     PetscCall(MatGetLocalSize(B, NULL, &n));
192     PetscCall(MatGetSize(B, NULL, &N));
193     PetscCall(MatGetLocalSize(A, &m, NULL));
194     PetscCall(MatGetSize(A, &M, NULL));
195     PetscCall(MatSetSizes(C, m, n, M, N));
196   }
197   PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, ""));
198   if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name));
199   PetscCall(MatSetUp(C));
200   if (!N) {
201     C->ops->productnumeric = MatProductNumeric_Nest_Dense;
202     PetscFunctionReturn(PETSC_SUCCESS);
203   }
204 
205   PetscCall(PetscNew(&contents));
206   C->product->data    = contents;
207   C->product->destroy = MatNest_DenseDestroy;
208   PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC));
209   contents->k = nr * nc;
210   for (i = 0; i < nr; i++) {
211     PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1));
212     maxm = PetscMax(maxm, contents->dm[i + 1]);
213     contents->dm[i + 1] += contents->dm[i];
214   }
215   for (i = 0; i < nc; i++) {
216     PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1));
217     contents->dn[i + 1] += contents->dn[i];
218   }
219   PetscCall(PetscMalloc1(maxm * N, &contents->tarray));
220   PetscCall(MatDenseGetLDA(B, &ldb));
221   PetscCall(MatGetSize(B, NULL, &N));
222   PetscCall(MatDenseGetArrayRead(B, &barray));
223   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
224   for (j = 0; j < nc; j++) {
225     PetscCall(ISGetSize(bA->isglobal.col[j], &M));
226     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB));
227     PetscCall(MatDenseSetLDA(viewB, ldb));
228     for (i = 0; i < nr; i++) {
229       if (!bA->m[i][j]) continue;
230       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
231 
232       PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j]));
233       workC = contents->workC[i * nc + j];
234       PetscCall(MatProductSetType(workC, MATPRODUCT_AB));
235       PetscCall(MatProductSetAlgorithm(workC, "default"));
236       PetscCall(MatProductSetFill(workC, fill));
237       PetscCall(MatProductSetFromOptions(workC));
238       PetscCall(MatProductSymbolic(workC));
239 
240       /* since tarray will be shared by all Mat */
241       PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray));
242       PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray));
243     }
244     PetscCall(MatDestroy(&viewB));
245   }
246   PetscCall(MatDenseRestoreArrayRead(B, &barray));
247 
248   C->ops->productnumeric = MatProductNumeric_Nest_Dense;
249   PetscFunctionReturn(PETSC_SUCCESS);
250 }
251 
252 static PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C)
253 {
254   Mat_Product *product = C->product;
255 
256   PetscFunctionBegin;
257   if (product->type == MATPRODUCT_AB) C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
258   PetscFunctionReturn(PETSC_SUCCESS);
259 }
260 
261 static PetscErrorCode MatMultTransposeKernel_Nest(Mat A, Vec x, Vec y, PetscBool herm)
262 {
263   Mat_Nest *bA = (Mat_Nest *)A->data;
264   Vec      *bx = bA->left, *by = bA->right;
265   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
266 
267   PetscFunctionBegin;
268   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
269   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i]));
270   for (j = 0; j < nc; j++) {
271     PetscCall(VecZeroEntries(by[j]));
272     for (i = 0; i < nr; i++) {
273       if (!bA->m[i][j]) continue;
274       if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); /* y[j] <- y[j] + (A[i][j])^H * x[i] */
275       else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j]));               /* y[j] <- y[j] + (A[i][j])^T * x[i] */
276     }
277   }
278   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
279   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i]));
280   PetscFunctionReturn(PETSC_SUCCESS);
281 }
282 
283 static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y)
284 {
285   PetscFunctionBegin;
286   PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_FALSE));
287   PetscFunctionReturn(PETSC_SUCCESS);
288 }
289 
290 static PetscErrorCode MatMultHermitianTranspose_Nest(Mat A, Vec x, Vec y)
291 {
292   PetscFunctionBegin;
293   PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_TRUE));
294   PetscFunctionReturn(PETSC_SUCCESS);
295 }
296 
297 static PetscErrorCode MatMultTransposeAddKernel_Nest(Mat A, Vec x, Vec y, Vec z, PetscBool herm)
298 {
299   Mat_Nest *bA = (Mat_Nest *)A->data;
300   Vec      *bx = bA->left, *bz = bA->right;
301   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
302 
303   PetscFunctionBegin;
304   for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i]));
305   for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i]));
306   for (j = 0; j < nc; j++) {
307     if (y != z) {
308       Vec by;
309       PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by));
310       PetscCall(VecCopy(by, bz[j]));
311       PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by));
312     }
313     for (i = 0; i < nr; i++) {
314       if (!bA->m[i][j]) continue;
315       if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); /* z[j] <- y[j] + (A[i][j])^H * x[i] */
316       else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j]));               /* z[j] <- y[j] + (A[i][j])^T * x[i] */
317     }
318   }
319   for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i]));
320   for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i]));
321   PetscFunctionReturn(PETSC_SUCCESS);
322 }
323 
324 static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z)
325 {
326   PetscFunctionBegin;
327   PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_FALSE));
328   PetscFunctionReturn(PETSC_SUCCESS);
329 }
330 
331 static PetscErrorCode MatMultHermitianTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z)
332 {
333   PetscFunctionBegin;
334   PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_TRUE));
335   PetscFunctionReturn(PETSC_SUCCESS);
336 }
337 
338 static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B)
339 {
340   Mat_Nest *bA = (Mat_Nest *)A->data, *bC;
341   Mat       C;
342   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
343 
344   PetscFunctionBegin;
345   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
346   PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place");
347 
348   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
349     Mat *subs;
350     IS  *is_row, *is_col;
351 
352     PetscCall(PetscCalloc1(nr * nc, &subs));
353     PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col));
354     PetscCall(MatNestGetISs(A, is_row, is_col));
355     if (reuse == MAT_INPLACE_MATRIX) {
356       for (i = 0; i < nr; i++) {
357         for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j];
358       }
359     }
360 
361     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C));
362     PetscCall(PetscFree(subs));
363     PetscCall(PetscFree2(is_row, is_col));
364   } else {
365     C = *B;
366   }
367 
368   bC = (Mat_Nest *)C->data;
369   for (i = 0; i < nr; i++) {
370     for (j = 0; j < nc; j++) {
371       if (bA->m[i][j]) {
372         PetscCall(MatTranspose(bA->m[i][j], reuse, &bC->m[j][i]));
373       } else {
374         bC->m[j][i] = NULL;
375       }
376     }
377   }
378 
379   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
380     *B = C;
381   } else {
382     PetscCall(MatHeaderMerge(A, &C));
383   }
384   PetscFunctionReturn(PETSC_SUCCESS);
385 }
386 
387 static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list)
388 {
389   IS      *lst = *list;
390   PetscInt i;
391 
392   PetscFunctionBegin;
393   if (!lst) PetscFunctionReturn(PETSC_SUCCESS);
394   for (i = 0; i < n; i++)
395     if (lst[i]) PetscCall(ISDestroy(&lst[i]));
396   PetscCall(PetscFree(lst));
397   *list = NULL;
398   PetscFunctionReturn(PETSC_SUCCESS);
399 }
400 
401 static PetscErrorCode MatReset_Nest(Mat A)
402 {
403   Mat_Nest *vs = (Mat_Nest *)A->data;
404   PetscInt  i, j;
405 
406   PetscFunctionBegin;
407   /* release the matrices and the place holders */
408   PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row));
409   PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col));
410   PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row));
411   PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col));
412 
413   PetscCall(PetscFree(vs->row_len));
414   PetscCall(PetscFree(vs->col_len));
415   PetscCall(PetscFree(vs->nnzstate));
416 
417   PetscCall(PetscFree2(vs->left, vs->right));
418 
419   /* release the matrices and the place holders */
420   if (vs->m) {
421     for (i = 0; i < vs->nr; i++) {
422       for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j]));
423     }
424     PetscCall(PetscFree(vs->m[0]));
425     PetscCall(PetscFree(vs->m));
426   }
427 
428   /* restore defaults */
429   vs->nr            = 0;
430   vs->nc            = 0;
431   vs->splitassembly = PETSC_FALSE;
432   PetscFunctionReturn(PETSC_SUCCESS);
433 }
434 
435 static PetscErrorCode MatDestroy_Nest(Mat A)
436 {
437   PetscFunctionBegin;
438   PetscCall(MatReset_Nest(A));
439   PetscCall(PetscFree(A->data));
440   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL));
441   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL));
442   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL));
443   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL));
444   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL));
445   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL));
446   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL));
447   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL));
448   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL));
449   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL));
450   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL));
451   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL));
452   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL));
453   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL));
454   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL));
455   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL));
456   PetscFunctionReturn(PETSC_SUCCESS);
457 }
458 
459 static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd)
460 {
461   Mat_Nest *vs = (Mat_Nest *)mat->data;
462   PetscInt  i;
463 
464   PetscFunctionBegin;
465   if (dd) *dd = 0;
466   if (!vs->nr) {
467     *missing = PETSC_TRUE;
468     PetscFunctionReturn(PETSC_SUCCESS);
469   }
470   *missing = PETSC_FALSE;
471   for (i = 0; i < vs->nr && !*missing; i++) {
472     *missing = PETSC_TRUE;
473     if (vs->m[i][i]) {
474       PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL));
475       PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented");
476     }
477   }
478   PetscFunctionReturn(PETSC_SUCCESS);
479 }
480 
481 static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type)
482 {
483   Mat_Nest *vs = (Mat_Nest *)A->data;
484   PetscInt  i, j;
485   PetscBool nnzstate = PETSC_FALSE;
486 
487   PetscFunctionBegin;
488   for (i = 0; i < vs->nr; i++) {
489     for (j = 0; j < vs->nc; j++) {
490       PetscObjectState subnnzstate = 0;
491       if (vs->m[i][j]) {
492         PetscCall(MatAssemblyBegin(vs->m[i][j], type));
493         if (!vs->splitassembly) {
494           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
495            * sub-block). This could be fixed by adding a flag to Mat so that there was a way to check if a Mat was
496            * already performing an assembly, but the result would by more complicated and appears to offer less
497            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
498            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
499            */
500           PetscCall(MatAssemblyEnd(vs->m[i][j], type));
501           PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate));
502         }
503       }
504       nnzstate                     = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate);
505       vs->nnzstate[i * vs->nc + j] = subnnzstate;
506     }
507   }
508   if (nnzstate) A->nonzerostate++;
509   PetscFunctionReturn(PETSC_SUCCESS);
510 }
511 
512 static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
513 {
514   Mat_Nest *vs = (Mat_Nest *)A->data;
515   PetscInt  i, j;
516 
517   PetscFunctionBegin;
518   for (i = 0; i < vs->nr; i++) {
519     for (j = 0; j < vs->nc; j++) {
520       if (vs->m[i][j]) {
521         if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type));
522       }
523     }
524   }
525   PetscFunctionReturn(PETSC_SUCCESS);
526 }
527 
528 static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B)
529 {
530   Mat_Nest *vs = (Mat_Nest *)A->data;
531   PetscInt  j;
532   Mat       sub;
533 
534   PetscFunctionBegin;
535   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
536   for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j];
537   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
538   *B = sub;
539   PetscFunctionReturn(PETSC_SUCCESS);
540 }
541 
542 static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B)
543 {
544   Mat_Nest *vs = (Mat_Nest *)A->data;
545   PetscInt  i;
546   Mat       sub;
547 
548   PetscFunctionBegin;
549   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
550   for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col];
551   if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */
552   *B = sub;
553   PetscFunctionReturn(PETSC_SUCCESS);
554 }
555 
556 static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end)
557 {
558   PetscInt  i, j, size, m;
559   PetscBool flg;
560   IS        out, concatenate[2];
561 
562   PetscFunctionBegin;
563   PetscAssertPointer(list, 3);
564   PetscValidHeaderSpecific(is, IS_CLASSID, 4);
565   if (begin) {
566     PetscAssertPointer(begin, 5);
567     *begin = -1;
568   }
569   if (end) {
570     PetscAssertPointer(end, 6);
571     *end = -1;
572   }
573   for (i = 0; i < n; i++) {
574     if (!list[i]) continue;
575     PetscCall(ISEqualUnsorted(list[i], is, &flg));
576     if (flg) {
577       if (begin) *begin = i;
578       if (end) *end = i + 1;
579       PetscFunctionReturn(PETSC_SUCCESS);
580     }
581   }
582   PetscCall(ISGetSize(is, &size));
583   for (i = 0; i < n - 1; i++) {
584     if (!list[i]) continue;
585     m = 0;
586     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out));
587     PetscCall(ISGetSize(out, &m));
588     for (j = i + 2; j < n && m < size; j++) {
589       if (list[j]) {
590         concatenate[0] = out;
591         concatenate[1] = list[j];
592         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out));
593         PetscCall(ISDestroy(concatenate));
594         PetscCall(ISGetSize(out, &m));
595       }
596     }
597     if (m == size) {
598       PetscCall(ISEqualUnsorted(out, is, &flg));
599       if (flg) {
600         if (begin) *begin = i;
601         if (end) *end = j;
602         PetscCall(ISDestroy(&out));
603         PetscFunctionReturn(PETSC_SUCCESS);
604       }
605     }
606     PetscCall(ISDestroy(&out));
607   }
608   PetscFunctionReturn(PETSC_SUCCESS);
609 }
610 
611 static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B)
612 {
613   Mat_Nest *vs = (Mat_Nest *)A->data;
614   PetscInt  lr, lc;
615 
616   PetscFunctionBegin;
617   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
618   PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr));
619   PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc));
620   PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE));
621   PetscCall(MatSetType(*B, MATAIJ));
622   PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL));
623   PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL));
624   PetscCall(MatSetUp(*B));
625   PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
626   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
627   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
628   PetscFunctionReturn(PETSC_SUCCESS);
629 }
630 
631 static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B)
632 {
633   Mat_Nest  *vs = (Mat_Nest *)A->data;
634   Mat       *a;
635   PetscInt   i, j, k, l, nr = rend - rbegin, nc = cend - cbegin;
636   char       keyname[256];
637   PetscBool *b;
638   PetscBool  flg;
639 
640   PetscFunctionBegin;
641   *B = NULL;
642   PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend));
643   PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B));
644   if (*B) PetscFunctionReturn(PETSC_SUCCESS);
645 
646   PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b));
647   for (i = 0; i < nr; i++) {
648     for (j = 0; j < nc; j++) {
649       a[i * nc + j] = vs->m[rbegin + i][cbegin + j];
650       b[i * nc + j] = PETSC_FALSE;
651     }
652   }
653   if (nc != vs->nc && nr != vs->nr) {
654     for (i = 0; i < nr; i++) {
655       for (j = 0; j < nc; j++) {
656         flg = PETSC_FALSE;
657         for (k = 0; (k < nr && !flg); k++) {
658           if (a[j + k * nc]) flg = PETSC_TRUE;
659         }
660         if (flg) {
661           flg = PETSC_FALSE;
662           for (l = 0; (l < nc && !flg); l++) {
663             if (a[i * nc + l]) flg = PETSC_TRUE;
664           }
665         }
666         if (!flg) {
667           b[i * nc + j] = PETSC_TRUE;
668           PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j));
669         }
670       }
671     }
672   }
673   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B));
674   for (i = 0; i < nr; i++) {
675     for (j = 0; j < nc; j++) {
676       if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j));
677     }
678   }
679   PetscCall(PetscFree2(a, b));
680   (*B)->assembled = A->assembled;
681   PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B));
682   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
683   PetscFunctionReturn(PETSC_SUCCESS);
684 }
685 
686 static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B)
687 {
688   Mat_Nest *vs = (Mat_Nest *)A->data;
689   PetscInt  rbegin, rend, cbegin, cend;
690 
691   PetscFunctionBegin;
692   PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend));
693   PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend));
694   if (rend == rbegin + 1 && cend == cbegin + 1) {
695     if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin));
696     *B = vs->m[rbegin][cbegin];
697   } else if (rbegin != -1 && cbegin != -1) {
698     PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B));
699   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set");
700   PetscFunctionReturn(PETSC_SUCCESS);
701 }
702 
703 /*
704    TODO: This does not actually returns a submatrix we can modify
705 */
706 static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B)
707 {
708   Mat_Nest *vs = (Mat_Nest *)A->data;
709   Mat       sub;
710 
711   PetscFunctionBegin;
712   PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub));
713   switch (reuse) {
714   case MAT_INITIAL_MATRIX:
715     if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
716     *B = sub;
717     break;
718   case MAT_REUSE_MATRIX:
719     PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call");
720     break;
721   case MAT_IGNORE_MATRIX: /* Nothing to do */
722     break;
723   case MAT_INPLACE_MATRIX: /* Nothing to do */
724     SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet");
725   }
726   PetscFunctionReturn(PETSC_SUCCESS);
727 }
728 
729 static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
730 {
731   Mat_Nest *vs = (Mat_Nest *)A->data;
732   Mat       sub;
733 
734   PetscFunctionBegin;
735   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
736   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
737   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
738   *B = sub;
739   PetscFunctionReturn(PETSC_SUCCESS);
740 }
741 
742 static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B)
743 {
744   Mat_Nest *vs = (Mat_Nest *)A->data;
745   Mat       sub;
746 
747   PetscFunctionBegin;
748   PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub));
749   PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten");
750   if (sub) {
751     PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times");
752     PetscCall(MatDestroy(B));
753   }
754   PetscFunctionReturn(PETSC_SUCCESS);
755 }
756 
757 static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v)
758 {
759   Mat_Nest *bA = (Mat_Nest *)A->data;
760   PetscInt  i;
761 
762   PetscFunctionBegin;
763   for (i = 0; i < bA->nr; i++) {
764     Vec bv;
765     PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv));
766     if (bA->m[i][i]) {
767       PetscCall(MatGetDiagonal(bA->m[i][i], bv));
768     } else {
769       PetscCall(VecSet(bv, 0.0));
770     }
771     PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv));
772   }
773   PetscFunctionReturn(PETSC_SUCCESS);
774 }
775 
776 static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r)
777 {
778   Mat_Nest *bA = (Mat_Nest *)A->data;
779   Vec       bl, *br;
780   PetscInt  i, j;
781 
782   PetscFunctionBegin;
783   PetscCall(PetscCalloc1(bA->nc, &br));
784   if (r) {
785     for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j]));
786   }
787   bl = NULL;
788   for (i = 0; i < bA->nr; i++) {
789     if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl));
790     for (j = 0; j < bA->nc; j++) {
791       if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j]));
792     }
793     if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl));
794   }
795   if (r) {
796     for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j]));
797   }
798   PetscCall(PetscFree(br));
799   PetscFunctionReturn(PETSC_SUCCESS);
800 }
801 
802 static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a)
803 {
804   Mat_Nest *bA = (Mat_Nest *)A->data;
805   PetscInt  i, j;
806 
807   PetscFunctionBegin;
808   for (i = 0; i < bA->nr; i++) {
809     for (j = 0; j < bA->nc; j++) {
810       if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a));
811     }
812   }
813   PetscFunctionReturn(PETSC_SUCCESS);
814 }
815 
816 static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a)
817 {
818   Mat_Nest *bA = (Mat_Nest *)A->data;
819   PetscInt  i;
820   PetscBool nnzstate = PETSC_FALSE;
821 
822   PetscFunctionBegin;
823   for (i = 0; i < bA->nr; i++) {
824     PetscObjectState subnnzstate = 0;
825     PetscCheck(bA->m[i][i], PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "No support for shifting an empty diagonal block, insert a matrix in block (%" PetscInt_FMT ",%" PetscInt_FMT ")", i, i);
826     PetscCall(MatShift(bA->m[i][i], a));
827     PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
828     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
829     bA->nnzstate[i * bA->nc + i] = subnnzstate;
830   }
831   if (nnzstate) A->nonzerostate++;
832   PetscFunctionReturn(PETSC_SUCCESS);
833 }
834 
835 static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is)
836 {
837   Mat_Nest *bA = (Mat_Nest *)A->data;
838   PetscInt  i;
839   PetscBool nnzstate = PETSC_FALSE;
840 
841   PetscFunctionBegin;
842   for (i = 0; i < bA->nr; i++) {
843     PetscObjectState subnnzstate = 0;
844     Vec              bv;
845     PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv));
846     if (bA->m[i][i]) {
847       PetscCall(MatDiagonalSet(bA->m[i][i], bv, is));
848       PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate));
849     }
850     PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv));
851     nnzstate                     = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate);
852     bA->nnzstate[i * bA->nc + i] = subnnzstate;
853   }
854   if (nnzstate) A->nonzerostate++;
855   PetscFunctionReturn(PETSC_SUCCESS);
856 }
857 
858 static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx)
859 {
860   Mat_Nest *bA = (Mat_Nest *)A->data;
861   PetscInt  i, j;
862 
863   PetscFunctionBegin;
864   for (i = 0; i < bA->nr; i++) {
865     for (j = 0; j < bA->nc; j++) {
866       if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx));
867     }
868   }
869   PetscFunctionReturn(PETSC_SUCCESS);
870 }
871 
872 static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left)
873 {
874   Mat_Nest *bA = (Mat_Nest *)A->data;
875   Vec      *L, *R;
876   MPI_Comm  comm;
877   PetscInt  i, j;
878 
879   PetscFunctionBegin;
880   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
881   if (right) {
882     /* allocate R */
883     PetscCall(PetscMalloc1(bA->nc, &R));
884     /* Create the right vectors */
885     for (j = 0; j < bA->nc; j++) {
886       for (i = 0; i < bA->nr; i++) {
887         if (bA->m[i][j]) {
888           PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL));
889           break;
890         }
891       }
892       PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
893     }
894     PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right));
895     /* hand back control to the nest vector */
896     for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j]));
897     PetscCall(PetscFree(R));
898   }
899 
900   if (left) {
901     /* allocate L */
902     PetscCall(PetscMalloc1(bA->nr, &L));
903     /* Create the left vectors */
904     for (i = 0; i < bA->nr; i++) {
905       for (j = 0; j < bA->nc; j++) {
906         if (bA->m[i][j]) {
907           PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i]));
908           break;
909         }
910       }
911       PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
912     }
913 
914     PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left));
915     for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i]));
916 
917     PetscCall(PetscFree(L));
918   }
919   PetscFunctionReturn(PETSC_SUCCESS);
920 }
921 
922 static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer)
923 {
924   Mat_Nest *bA = (Mat_Nest *)A->data;
925   PetscBool isascii, viewSub = PETSC_FALSE;
926   PetscInt  i, j;
927 
928   PetscFunctionBegin;
929   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
930   if (isascii) {
931     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL));
932     PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object:\n"));
933     PetscCall(PetscViewerASCIIPushTab(viewer));
934     PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", bA->nr, bA->nc));
935 
936     PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure:\n"));
937     for (i = 0; i < bA->nr; i++) {
938       for (j = 0; j < bA->nc; j++) {
939         MatType   type;
940         char      name[256] = "", prefix[256] = "";
941         PetscInt  NR, NC;
942         PetscBool isNest = PETSC_FALSE;
943 
944         if (!bA->m[i][j]) {
945           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j));
946           continue;
947         }
948         PetscCall(MatGetSize(bA->m[i][j], &NR, &NC));
949         PetscCall(MatGetType(bA->m[i][j], &type));
950         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name));
951         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix));
952         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest));
953 
954         PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : %s%stype=%s, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", i, j, name, prefix, type, NR, NC));
955 
956         if (isNest || viewSub) {
957           PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */
958           PetscCall(MatView(bA->m[i][j], viewer));
959           PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */
960         }
961       }
962     }
963     PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */
964   }
965   PetscFunctionReturn(PETSC_SUCCESS);
966 }
967 
968 static PetscErrorCode MatZeroEntries_Nest(Mat A)
969 {
970   Mat_Nest *bA = (Mat_Nest *)A->data;
971   PetscInt  i, j;
972 
973   PetscFunctionBegin;
974   for (i = 0; i < bA->nr; i++) {
975     for (j = 0; j < bA->nc; j++) {
976       if (!bA->m[i][j]) continue;
977       PetscCall(MatZeroEntries(bA->m[i][j]));
978     }
979   }
980   PetscFunctionReturn(PETSC_SUCCESS);
981 }
982 
983 static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str)
984 {
985   Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data;
986   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
987   PetscBool nnzstate = PETSC_FALSE;
988 
989   PetscFunctionBegin;
990   PetscCheck(nr == bB->nr && nc == bB->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Cannot copy a Mat_Nest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ") to a Mat_Nest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ")", bB->nr, bB->nc, nr, nc);
991   for (i = 0; i < nr; i++) {
992     for (j = 0; j < nc; j++) {
993       PetscObjectState subnnzstate = 0;
994       if (bA->m[i][j] && bB->m[i][j]) {
995         PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str));
996       } else PetscCheck(!bA->m[i][j] && !bB->m[i][j], PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT, i, j);
997       PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
998       nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
999       bB->nnzstate[i * nc + j] = subnnzstate;
1000     }
1001   }
1002   if (nnzstate) B->nonzerostate++;
1003   PetscFunctionReturn(PETSC_SUCCESS);
1004 }
1005 
1006 static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str)
1007 {
1008   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
1009   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
1010   PetscBool nnzstate = PETSC_FALSE;
1011 
1012   PetscFunctionBegin;
1013   PetscCheck(nr == bX->nr && nc == bX->nc, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_INCOMP, "Cannot AXPY a MatNest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ") with a MatNest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ")", bX->nr, bX->nc, nr, nc);
1014   for (i = 0; i < nr; i++) {
1015     for (j = 0; j < nc; j++) {
1016       PetscObjectState subnnzstate = 0;
1017       if (bY->m[i][j] && bX->m[i][j]) {
1018         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
1019       } else if (bX->m[i][j]) {
1020         Mat M;
1021 
1022         PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j);
1023         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
1024         PetscCall(MatNestSetSubMat(Y, i, j, M));
1025         PetscCall(MatDestroy(&M));
1026       }
1027       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
1028       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
1029       bY->nnzstate[i * nc + j] = subnnzstate;
1030     }
1031   }
1032   if (nnzstate) Y->nonzerostate++;
1033   PetscFunctionReturn(PETSC_SUCCESS);
1034 }
1035 
1036 static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B)
1037 {
1038   Mat_Nest *bA = (Mat_Nest *)A->data;
1039   Mat      *b;
1040   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
1041 
1042   PetscFunctionBegin;
1043   PetscCall(PetscMalloc1(nr * nc, &b));
1044   for (i = 0; i < nr; i++) {
1045     for (j = 0; j < nc; j++) {
1046       if (bA->m[i][j]) {
1047         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
1048       } else {
1049         b[i * nc + j] = NULL;
1050       }
1051     }
1052   }
1053   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
1054   /* Give the new MatNest exclusive ownership */
1055   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
1056   PetscCall(PetscFree(b));
1057 
1058   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
1059   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
1060   PetscFunctionReturn(PETSC_SUCCESS);
1061 }
1062 
1063 /* nest api */
1064 static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat)
1065 {
1066   Mat_Nest *bA = (Mat_Nest *)A->data;
1067 
1068   PetscFunctionBegin;
1069   PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1);
1070   PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1);
1071   *mat = bA->m[idxm][jdxm];
1072   PetscFunctionReturn(PETSC_SUCCESS);
1073 }
1074 
1075 /*@
1076   MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1077 
1078   Not Collective
1079 
1080   Input Parameters:
1081 + A    - `MATNEST` matrix
1082 . idxm - index of the matrix within the nest matrix
1083 - jdxm - index of the matrix within the nest matrix
1084 
1085   Output Parameter:
1086 . sub - matrix at index `idxm`, `jdxm` within the nest matrix
1087 
1088   Level: developer
1089 
1090 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`,
1091           `MatNestGetLocalISs()`, `MatNestGetISs()`
1092 @*/
1093 PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub)
1094 {
1095   PetscFunctionBegin;
1096   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1097   PetscValidLogicalCollectiveInt(A, idxm, 2);
1098   PetscValidLogicalCollectiveInt(A, jdxm, 3);
1099   PetscAssertPointer(sub, 4);
1100   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
1101   PetscFunctionReturn(PETSC_SUCCESS);
1102 }
1103 
1104 static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat)
1105 {
1106   Mat_Nest *bA = (Mat_Nest *)A->data;
1107   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
1108 
1109   PetscFunctionBegin;
1110   PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1);
1111   PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1);
1112   if (mat) {
1113     PetscCall(MatGetLocalSize(mat, &m, &n));
1114     PetscCall(MatGetSize(mat, &M, &N));
1115     PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
1116     PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
1117     PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
1118     PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1119     PetscCheck(M == Mi && N == Ni, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_INCOMP, "Submatrix dimension (%" PetscInt_FMT ",%" PetscInt_FMT ") incompatible with nest block (%" PetscInt_FMT ",%" PetscInt_FMT ")", M, N, Mi, Ni);
1120     PetscCheck(m == mi && n == ni, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_INCOMP, "Submatrix local dimension (%" PetscInt_FMT ",%" PetscInt_FMT ") incompatible with nest block (%" PetscInt_FMT ",%" PetscInt_FMT ")", m, n, mi, ni);
1121   }
1122 
1123   /* do not increase object state */
1124   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS);
1125 
1126   PetscCall(PetscObjectReference((PetscObject)mat));
1127   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
1128   bA->m[idxm][jdxm] = mat;
1129   PetscCall(PetscObjectStateIncrease((PetscObject)A));
1130   if (mat) PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
1131   else bA->nnzstate[idxm * bA->nc + jdxm] = 0;
1132   A->nonzerostate++;
1133   PetscFunctionReturn(PETSC_SUCCESS);
1134 }
1135 
1136 /*@
1137   MatNestSetSubMat - Set a single submatrix in the `MATNEST`
1138 
1139   Logically Collective
1140 
1141   Input Parameters:
1142 + A    - `MATNEST` matrix
1143 . idxm - index of the matrix within the nest matrix
1144 . jdxm - index of the matrix within the nest matrix
1145 - sub  - matrix at index `idxm`, `jdxm` within the nest matrix
1146 
1147   Level: developer
1148 
1149   Notes:
1150   The new submatrix must have the same size and communicator as that block of the nest.
1151 
1152   This increments the reference count of the submatrix.
1153 
1154 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1155           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
1156 @*/
1157 PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub)
1158 {
1159   PetscFunctionBegin;
1160   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1161   PetscValidLogicalCollectiveInt(A, idxm, 2);
1162   PetscValidLogicalCollectiveInt(A, jdxm, 3);
1163   if (sub) PetscValidHeaderSpecific(sub, MAT_CLASSID, 4);
1164   PetscTryMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
1165   PetscFunctionReturn(PETSC_SUCCESS);
1166 }
1167 
1168 static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1169 {
1170   Mat_Nest *bA = (Mat_Nest *)A->data;
1171 
1172   PetscFunctionBegin;
1173   if (M) *M = bA->nr;
1174   if (N) *N = bA->nc;
1175   if (mat) *mat = bA->m;
1176   PetscFunctionReturn(PETSC_SUCCESS);
1177 }
1178 
1179 /*@C
1180   MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1181 
1182   Not Collective
1183 
1184   Input Parameter:
1185 . A - nest matrix
1186 
1187   Output Parameters:
1188 + M   - number of submatrix rows in the nest matrix
1189 . N   - number of submatrix columns in the nest matrix
1190 - mat - array of matrices
1191 
1192   Level: developer
1193 
1194   Note:
1195   The user should not free the array `mat`.
1196 
1197   Fortran Notes:
1198   This routine has a calling sequence `call MatNestGetSubMats(A, M, N, mat, ierr)`
1199   where the space allocated for the optional argument `mat` is assumed large enough (if provided).
1200   Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example.
1201 
1202 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1203           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1204 @*/
1205 PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1206 {
1207   PetscFunctionBegin;
1208   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1209   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
1210   PetscFunctionReturn(PETSC_SUCCESS);
1211 }
1212 
1213 static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N)
1214 {
1215   Mat_Nest *bA = (Mat_Nest *)A->data;
1216 
1217   PetscFunctionBegin;
1218   if (M) *M = bA->nr;
1219   if (N) *N = bA->nc;
1220   PetscFunctionReturn(PETSC_SUCCESS);
1221 }
1222 
1223 /*@
1224   MatNestGetSize - Returns the size of the `MATNEST` matrix.
1225 
1226   Not Collective
1227 
1228   Input Parameter:
1229 . A - `MATNEST` matrix
1230 
1231   Output Parameters:
1232 + M - number of rows in the nested mat
1233 - N - number of cols in the nested mat
1234 
1235   Level: developer
1236 
1237   Note:
1238   `size` refers to the number of submatrices in the row and column directions of the nested matrix
1239 
1240 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1241           `MatNestGetISs()`
1242 @*/
1243 PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N)
1244 {
1245   PetscFunctionBegin;
1246   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1247   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
1248   PetscFunctionReturn(PETSC_SUCCESS);
1249 }
1250 
1251 static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[])
1252 {
1253   Mat_Nest *vs = (Mat_Nest *)A->data;
1254   PetscInt  i;
1255 
1256   PetscFunctionBegin;
1257   if (rows)
1258     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
1259   if (cols)
1260     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
1261   PetscFunctionReturn(PETSC_SUCCESS);
1262 }
1263 
1264 /*@
1265   MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1266 
1267   Not Collective
1268 
1269   Input Parameter:
1270 . A - `MATNEST` matrix
1271 
1272   Output Parameters:
1273 + rows - array of row index sets (pass `NULL` to ignore)
1274 - cols - array of column index sets (pass `NULL` to ignore)
1275 
1276   Level: advanced
1277 
1278   Note:
1279   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1280 
1281 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`,
1282           `MatCreateNest()`, `MatNestSetSubMats()`
1283 @*/
1284 PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[])
1285 {
1286   PetscFunctionBegin;
1287   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1288   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
1289   PetscFunctionReturn(PETSC_SUCCESS);
1290 }
1291 
1292 static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[])
1293 {
1294   Mat_Nest *vs = (Mat_Nest *)A->data;
1295   PetscInt  i;
1296 
1297   PetscFunctionBegin;
1298   if (rows)
1299     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
1300   if (cols)
1301     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
1302   PetscFunctionReturn(PETSC_SUCCESS);
1303 }
1304 
1305 /*@
1306   MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1307 
1308   Not Collective
1309 
1310   Input Parameter:
1311 . A - `MATNEST` matrix
1312 
1313   Output Parameters:
1314 + rows - array of row index sets (pass `NULL` to ignore)
1315 - cols - array of column index sets (pass `NULL` to ignore)
1316 
1317   Level: advanced
1318 
1319   Note:
1320   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1321 
1322 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1323           `MatNestSetSubMats()`, `MatNestSetSubMat()`
1324 @*/
1325 PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[])
1326 {
1327   PetscFunctionBegin;
1328   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1329   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
1330   PetscFunctionReturn(PETSC_SUCCESS);
1331 }
1332 
1333 static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype)
1334 {
1335   PetscBool flg;
1336 
1337   PetscFunctionBegin;
1338   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1339   /* In reality, this only distinguishes VECNEST and "other" */
1340   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
1341   else A->ops->getvecs = NULL;
1342   PetscFunctionReturn(PETSC_SUCCESS);
1343 }
1344 
1345 /*@
1346   MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1347 
1348   Not Collective
1349 
1350   Input Parameters:
1351 + A     - `MATNEST` matrix
1352 - vtype - `VecType` to use for creating vectors
1353 
1354   Level: developer
1355 
1356 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType`
1357 @*/
1358 PetscErrorCode MatNestSetVecType(Mat A, VecType vtype)
1359 {
1360   PetscFunctionBegin;
1361   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1362   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
1363   PetscFunctionReturn(PETSC_SUCCESS);
1364 }
1365 
1366 static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1367 {
1368   Mat_Nest *s = (Mat_Nest *)A->data;
1369   PetscInt  i, j, m, n, M, N;
1370   PetscBool cong, isstd, sametype = PETSC_FALSE;
1371   VecType   vtype, type;
1372 
1373   PetscFunctionBegin;
1374   PetscCall(MatReset_Nest(A));
1375 
1376   s->nr = nr;
1377   s->nc = nc;
1378 
1379   /* Create space for submatrices */
1380   PetscCall(PetscMalloc1(nr, &s->m));
1381   PetscCall(PetscMalloc1(nr * nc, &s->m[0]));
1382   for (i = 0; i < nr; i++) {
1383     s->m[i] = s->m[0] + i * nc;
1384     for (j = 0; j < nc; j++) {
1385       s->m[i][j] = a ? a[i * nc + j] : NULL;
1386       PetscCall(PetscObjectReference((PetscObject)s->m[i][j]));
1387     }
1388   }
1389   PetscCall(MatGetVecType(A, &vtype));
1390   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
1391   if (isstd) {
1392     /* check if all blocks have the same vectype */
1393     vtype = NULL;
1394     for (i = 0; i < nr; i++) {
1395       for (j = 0; j < nc; j++) {
1396         if (s->m[i][j]) {
1397           if (!vtype) { /* first visited block */
1398             PetscCall(MatGetVecType(s->m[i][j], &vtype));
1399             sametype = PETSC_TRUE;
1400           } else if (sametype) {
1401             PetscCall(MatGetVecType(s->m[i][j], &type));
1402             PetscCall(PetscStrcmp(vtype, type, &sametype));
1403           }
1404         }
1405       }
1406     }
1407     if (sametype) { /* propagate vectype */
1408       PetscCall(MatSetVecType(A, vtype));
1409     }
1410   }
1411 
1412   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1413 
1414   PetscCall(PetscMalloc1(nr, &s->row_len));
1415   PetscCall(PetscMalloc1(nc, &s->col_len));
1416   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1417   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1418 
1419   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
1420   for (i = 0; i < nr; i++) {
1421     for (j = 0; j < nc; j++) {
1422       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
1423     }
1424   }
1425 
1426   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1427 
1428   PetscCall(PetscLayoutSetSize(A->rmap, M));
1429   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
1430   PetscCall(PetscLayoutSetSize(A->cmap, N));
1431   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1432 
1433   PetscCall(PetscLayoutSetUp(A->rmap));
1434   PetscCall(PetscLayoutSetUp(A->cmap));
1435 
1436   /* disable operations that are not supported for non-square matrices,
1437      or matrices for which is_row != is_col  */
1438   PetscCall(MatHasCongruentLayouts(A, &cong));
1439   if (cong && nr != nc) cong = PETSC_FALSE;
1440   if (cong) {
1441     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
1442   }
1443   if (!cong) {
1444     A->ops->missingdiagonal = NULL;
1445     A->ops->getdiagonal     = NULL;
1446     A->ops->shift           = NULL;
1447     A->ops->diagonalset     = NULL;
1448   }
1449 
1450   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
1451   PetscCall(PetscObjectStateIncrease((PetscObject)A));
1452   A->nonzerostate++;
1453   PetscFunctionReturn(PETSC_SUCCESS);
1454 }
1455 
1456 /*@
1457   MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1458 
1459   Collective
1460 
1461   Input Parameters:
1462 + A      - `MATNEST` matrix
1463 . nr     - number of nested row blocks
1464 . is_row - index sets for each nested row block, or `NULL` to make contiguous
1465 . nc     - number of nested column blocks
1466 . is_col - index sets for each nested column block, or `NULL` to make contiguous
1467 - a      - array of nr*nc submatrices, or `NULL`
1468 
1469   Level: advanced
1470 
1471   Notes:
1472   This always resets any block matrix information previously set.
1473 
1474   Pass `NULL` in the corresponding entry of `a` for an empty block.
1475 
1476   In both C and Fortran, `a` must be a row-major order array containing the matrices. See
1477   `MatCreateNest()` for an example.
1478 
1479 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1480 @*/
1481 PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1482 {
1483   PetscFunctionBegin;
1484   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1485   PetscValidLogicalCollectiveInt(A, nr, 2);
1486   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1487   if (nr && is_row) {
1488     PetscAssertPointer(is_row, 3);
1489     for (PetscInt i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1490   }
1491   PetscValidLogicalCollectiveInt(A, nc, 4);
1492   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
1493   if (nc && is_col) {
1494     PetscAssertPointer(is_col, 5);
1495     for (PetscInt i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1496   }
1497   PetscTryMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
1498   PetscFunctionReturn(PETSC_SUCCESS);
1499 }
1500 
1501 static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog)
1502 {
1503   PetscBool flg;
1504   PetscInt  i, j, m, mi, *ix;
1505 
1506   PetscFunctionBegin;
1507   *ltog = NULL;
1508   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
1509     if (islocal[i]) {
1510       PetscCall(ISGetLocalSize(islocal[i], &mi));
1511       flg = PETSC_TRUE; /* We found a non-trivial entry */
1512     } else {
1513       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1514     }
1515     m += mi;
1516   }
1517   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
1518 
1519   PetscCall(PetscMalloc1(m, &ix));
1520   for (i = 0, m = 0; i < n; i++) {
1521     ISLocalToGlobalMapping smap = NULL;
1522     Mat                    sub  = NULL;
1523     PetscSF                sf;
1524     PetscLayout            map;
1525     const PetscInt        *ix2;
1526 
1527     if (!colflg) {
1528       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1529     } else {
1530       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
1531     }
1532     if (sub) {
1533       if (!colflg) {
1534         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1535       } else {
1536         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1537       }
1538     }
1539     /*
1540        Now we need to extract the monolithic global indices that correspond to the given split global indices.
1541        In many/most cases, we only want MatGetLocalSubMatrix() to work, in which case we only need to know the size of the local spaces.
1542     */
1543     PetscCall(ISGetIndices(isglobal[i], &ix2));
1544     if (islocal[i]) {
1545       PetscInt *ilocal, *iremote;
1546       PetscInt  mil, nleaves;
1547 
1548       PetscCall(ISGetLocalSize(islocal[i], &mi));
1549       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1550       for (j = 0; j < mi; j++) ix[m + j] = j;
1551       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1552 
1553       /* PetscSFSetGraphLayout does not like negative indices */
1554       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1555       for (j = 0, nleaves = 0; j < mi; j++) {
1556         if (ix[m + j] < 0) continue;
1557         ilocal[nleaves]  = j;
1558         iremote[nleaves] = ix[m + j];
1559         nleaves++;
1560       }
1561       PetscCall(ISGetLocalSize(isglobal[i], &mil));
1562       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
1563       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
1564       PetscCall(PetscLayoutSetLocalSize(map, mil));
1565       PetscCall(PetscLayoutSetUp(map));
1566       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
1567       PetscCall(PetscLayoutDestroy(&map));
1568       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
1569       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
1570       PetscCall(PetscSFDestroy(&sf));
1571       PetscCall(PetscFree2(ilocal, iremote));
1572     } else {
1573       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1574       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1575     }
1576     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
1577     m += mi;
1578   }
1579   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
1580   PetscFunctionReturn(PETSC_SUCCESS);
1581 }
1582 
1583 /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1584 /*
1585   nprocessors = NP
1586   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1587        proc 0: => (g_0,h_0,)
1588        proc 1: => (g_1,h_1,)
1589        ...
1590        proc nprocs-1: => (g_NP-1,h_NP-1,)
1591 
1592             proc 0:                      proc 1:                    proc nprocs-1:
1593     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1594 
1595             proc 0:
1596     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1597             proc 1:
1598     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1599 
1600             proc NP-1:
1601     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1602 */
1603 static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[])
1604 {
1605   Mat_Nest *vs = (Mat_Nest *)A->data;
1606   PetscInt  i, j, offset, n, nsum, bs;
1607   Mat       sub = NULL;
1608 
1609   PetscFunctionBegin;
1610   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
1611   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1612   if (is_row) { /* valid IS is passed in */
1613     /* refs on is[] are incremented */
1614     for (i = 0; i < vs->nr; i++) {
1615       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
1616       vs->isglobal.row[i] = is_row[i];
1617     }
1618   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
1619     nsum = 0;
1620     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
1621       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1622       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
1623       PetscCall(MatGetLocalSize(sub, &n, NULL));
1624       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
1625       nsum += n;
1626     }
1627     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
1628     offset -= nsum;
1629     for (i = 0; i < vs->nr; i++) {
1630       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1631       PetscCall(MatGetLocalSize(sub, &n, NULL));
1632       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
1633       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
1634       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
1635       offset += n;
1636     }
1637   }
1638 
1639   if (is_col) { /* valid IS is passed in */
1640     /* refs on is[] are incremented */
1641     for (j = 0; j < vs->nc; j++) {
1642       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
1643       vs->isglobal.col[j] = is_col[j];
1644     }
1645   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
1646     offset = A->cmap->rstart;
1647     nsum   = 0;
1648     for (j = 0; j < vs->nc; j++) {
1649       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
1650       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
1651       PetscCall(MatGetLocalSize(sub, NULL, &n));
1652       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
1653       nsum += n;
1654     }
1655     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
1656     offset -= nsum;
1657     for (j = 0; j < vs->nc; j++) {
1658       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
1659       PetscCall(MatGetLocalSize(sub, NULL, &n));
1660       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
1661       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
1662       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
1663       offset += n;
1664     }
1665   }
1666 
1667   /* Set up the local ISs */
1668   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
1669   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1670   for (i = 0, offset = 0; i < vs->nr; i++) {
1671     IS                     isloc;
1672     ISLocalToGlobalMapping rmap = NULL;
1673     PetscInt               nlocal, bs;
1674     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1675     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1676     if (rmap) {
1677       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
1678       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
1679       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
1680       PetscCall(ISSetBlockSize(isloc, bs));
1681     } else {
1682       nlocal = 0;
1683       isloc  = NULL;
1684     }
1685     vs->islocal.row[i] = isloc;
1686     offset += nlocal;
1687   }
1688   for (i = 0, offset = 0; i < vs->nc; i++) {
1689     IS                     isloc;
1690     ISLocalToGlobalMapping cmap = NULL;
1691     PetscInt               nlocal, bs;
1692     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
1693     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1694     if (cmap) {
1695       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
1696       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
1697       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
1698       PetscCall(ISSetBlockSize(isloc, bs));
1699     } else {
1700       nlocal = 0;
1701       isloc  = NULL;
1702     }
1703     vs->islocal.col[i] = isloc;
1704     offset += nlocal;
1705   }
1706 
1707   /* Set up the aggregate ISLocalToGlobalMapping */
1708   {
1709     ISLocalToGlobalMapping rmap, cmap;
1710     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
1711     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
1712     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
1713     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
1714     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
1715   }
1716 
1717   if (PetscDefined(USE_DEBUG)) {
1718     for (i = 0; i < vs->nr; i++) {
1719       for (j = 0; j < vs->nc; j++) {
1720         PetscInt m, n, M, N, mi, ni, Mi, Ni;
1721         Mat      B = vs->m[i][j];
1722         if (!B) continue;
1723         PetscCall(MatGetSize(B, &M, &N));
1724         PetscCall(MatGetLocalSize(B, &m, &n));
1725         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
1726         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
1727         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
1728         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1729         PetscCheck(M == Mi && N == Ni, PetscObjectComm((PetscObject)sub), PETSC_ERR_ARG_INCOMP, "Global sizes (%" PetscInt_FMT ",%" PetscInt_FMT ") of nested submatrix (%" PetscInt_FMT ",%" PetscInt_FMT ") do not agree with space defined by index sets (%" PetscInt_FMT ",%" PetscInt_FMT ")", M, N, i, j, Mi, Ni);
1730         PetscCheck(m == mi && n == ni, PetscObjectComm((PetscObject)sub), PETSC_ERR_ARG_INCOMP, "Local sizes (%" PetscInt_FMT ",%" PetscInt_FMT ") of nested submatrix (%" PetscInt_FMT ",%" PetscInt_FMT ") do not agree with space defined by index sets (%" PetscInt_FMT ",%" PetscInt_FMT ")", m, n, i, j, mi, ni);
1731       }
1732     }
1733   }
1734 
1735   /* Set A->assembled if all non-null blocks are currently assembled */
1736   for (i = 0; i < vs->nr; i++) {
1737     for (j = 0; j < vs->nc; j++) {
1738       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS);
1739     }
1740   }
1741   A->assembled = PETSC_TRUE;
1742   PetscFunctionReturn(PETSC_SUCCESS);
1743 }
1744 
1745 /*@C
1746   MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1747 
1748   Collective
1749 
1750   Input Parameters:
1751 + comm   - Communicator for the new `MATNEST`
1752 . nr     - number of nested row blocks
1753 . is_row - index sets for each nested row block, or `NULL` to make contiguous
1754 . nc     - number of nested column blocks
1755 . is_col - index sets for each nested column block, or `NULL` to make contiguous
1756 - a      - array of nr*nc submatrices, empty submatrices can be passed using `NULL`
1757 
1758   Output Parameter:
1759 . B - new matrix
1760 
1761   Note:
1762   In both C and Fortran, `a` must be a row-major order array holding references to the matrices.
1763   For instance, to represent the matrix
1764   $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$
1765   one should use `Mat a[4]={A11,A12,A21,A22}`.
1766 
1767   Level: advanced
1768 
1769 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`,
1770           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1771           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1772 @*/
1773 PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) PeNSS
1774 {
1775   PetscFunctionBegin;
1776   PetscCall(MatCreate(comm, B));
1777   PetscCall(MatSetType(*B, MATNEST));
1778   (*B)->preallocated = PETSC_TRUE;
1779   PetscCall(MatNestSetSubMats(*B, nr, is_row, nc, is_col, a));
1780   PetscFunctionReturn(PETSC_SUCCESS);
1781 }
1782 
1783 static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1784 {
1785   Mat_Nest     *nest = (Mat_Nest *)A->data;
1786   Mat          *trans;
1787   PetscScalar **avv;
1788   PetscScalar  *vv;
1789   PetscInt    **aii, **ajj;
1790   PetscInt     *ii, *jj, *ci;
1791   PetscInt      nr, nc, nnz, i, j;
1792   PetscBool     done;
1793 
1794   PetscFunctionBegin;
1795   PetscCall(MatGetSize(A, &nr, &nc));
1796   if (reuse == MAT_REUSE_MATRIX) {
1797     PetscInt rnr;
1798 
1799     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
1800     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
1801     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
1802     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1803   }
1804   /* extract CSR for nested SeqAIJ matrices */
1805   nnz = 0;
1806   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1807   for (i = 0; i < nest->nr; ++i) {
1808     for (j = 0; j < nest->nc; ++j) {
1809       Mat B = nest->m[i][j];
1810       if (B) {
1811         PetscScalar *naa;
1812         PetscInt    *nii, *njj, nnr;
1813         PetscBool    istrans;
1814 
1815         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
1816         if (istrans) {
1817           Mat Bt;
1818 
1819           PetscCall(MatTransposeGetMat(B, &Bt));
1820           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1821           B = trans[i * nest->nc + j];
1822         } else {
1823           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1824           if (istrans) {
1825             Mat Bt;
1826 
1827             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1828             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1829             B = trans[i * nest->nc + j];
1830           }
1831         }
1832         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
1833         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
1834         PetscCall(MatSeqAIJGetArray(B, &naa));
1835         nnz += nii[nnr];
1836 
1837         aii[i * nest->nc + j] = nii;
1838         ajj[i * nest->nc + j] = njj;
1839         avv[i * nest->nc + j] = naa;
1840       }
1841     }
1842   }
1843   if (reuse != MAT_REUSE_MATRIX) {
1844     PetscCall(PetscMalloc1(nr + 1, &ii));
1845     PetscCall(PetscMalloc1(nnz, &jj));
1846     PetscCall(PetscMalloc1(nnz, &vv));
1847   } else {
1848     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1849   }
1850 
1851   /* new row pointer */
1852   PetscCall(PetscArrayzero(ii, nr + 1));
1853   for (i = 0; i < nest->nr; ++i) {
1854     PetscInt ncr, rst;
1855 
1856     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
1857     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1858     for (j = 0; j < nest->nc; ++j) {
1859       if (aii[i * nest->nc + j]) {
1860         PetscInt *nii = aii[i * nest->nc + j];
1861         PetscInt  ir;
1862 
1863         for (ir = rst; ir < ncr + rst; ++ir) {
1864           ii[ir + 1] += nii[1] - nii[0];
1865           nii++;
1866         }
1867       }
1868     }
1869   }
1870   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1871 
1872   /* construct CSR for the new matrix */
1873   PetscCall(PetscCalloc1(nr, &ci));
1874   for (i = 0; i < nest->nr; ++i) {
1875     PetscInt ncr, rst;
1876 
1877     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
1878     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1879     for (j = 0; j < nest->nc; ++j) {
1880       if (aii[i * nest->nc + j]) {
1881         PetscScalar *nvv = avv[i * nest->nc + j], vscale = 1.0, vshift = 0.0;
1882         PetscInt    *nii = aii[i * nest->nc + j];
1883         PetscInt    *njj = ajj[i * nest->nc + j];
1884         PetscInt     ir, cst;
1885 
1886         if (trans[i * nest->nc + j]) {
1887           vscale = ((Mat_Shell *)nest->m[i][j]->data)->vscale;
1888           vshift = ((Mat_Shell *)nest->m[i][j]->data)->vshift;
1889         }
1890         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1891         for (ir = rst; ir < ncr + rst; ++ir) {
1892           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1893 
1894           for (ij = 0; ij < rsize; ij++) {
1895             jj[ist + ij] = *njj + cst;
1896             vv[ist + ij] = vscale * *nvv;
1897             if (PetscUnlikely(vshift != 0.0 && *njj == ir - rst)) vv[ist + ij] += vshift;
1898             njj++;
1899             nvv++;
1900           }
1901           ci[ir] += rsize;
1902           nii++;
1903         }
1904       }
1905     }
1906   }
1907   PetscCall(PetscFree(ci));
1908 
1909   /* restore info */
1910   for (i = 0; i < nest->nr; ++i) {
1911     for (j = 0; j < nest->nc; ++j) {
1912       Mat B = nest->m[i][j];
1913       if (B) {
1914         PetscInt nnr = 0, k = i * nest->nc + j;
1915 
1916         B = (trans[k] ? trans[k] : B);
1917         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
1918         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
1919         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
1920         PetscCall(MatDestroy(&trans[k]));
1921       }
1922     }
1923   }
1924   PetscCall(PetscFree4(aii, ajj, avv, trans));
1925 
1926   /* finalize newmat */
1927   if (reuse == MAT_INITIAL_MATRIX) {
1928     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1929   } else if (reuse == MAT_INPLACE_MATRIX) {
1930     Mat B;
1931 
1932     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
1933     PetscCall(MatHeaderReplace(A, &B));
1934   }
1935   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
1936   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1937   {
1938     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1939     a->free_a     = PETSC_TRUE;
1940     a->free_ij    = PETSC_TRUE;
1941   }
1942   PetscFunctionReturn(PETSC_SUCCESS);
1943 }
1944 
1945 PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X)
1946 {
1947   Mat_Nest *nest = (Mat_Nest *)X->data;
1948   PetscInt  i, j, k, rstart;
1949   PetscBool flg;
1950 
1951   PetscFunctionBegin;
1952   /* Fill by row */
1953   for (j = 0; j < nest->nc; ++j) {
1954     /* Using global column indices and ISAllGather() is not scalable. */
1955     IS              bNis;
1956     PetscInt        bN;
1957     const PetscInt *bNindices;
1958     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
1959     PetscCall(ISGetSize(bNis, &bN));
1960     PetscCall(ISGetIndices(bNis, &bNindices));
1961     for (i = 0; i < nest->nr; ++i) {
1962       Mat             B = nest->m[i][j], D = NULL;
1963       PetscInt        bm, br;
1964       const PetscInt *bmindices;
1965       if (!B) continue;
1966       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1967       if (flg) {
1968         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1969         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
1970         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1971         B = D;
1972       }
1973       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
1974       if (flg) {
1975         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
1976         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
1977         B = D;
1978       }
1979       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
1980       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
1981       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
1982       for (br = 0; br < bm; ++br) {
1983         PetscInt           row = bmindices[br], brncols, *cols;
1984         const PetscInt    *brcols;
1985         const PetscScalar *brcoldata;
1986         PetscScalar       *vals = NULL;
1987         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
1988         PetscCall(PetscMalloc1(brncols, &cols));
1989         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
1990         /*
1991           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1992           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1993          */
1994         if (a != 1.0) {
1995           PetscCall(PetscMalloc1(brncols, &vals));
1996           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
1997           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
1998           PetscCall(PetscFree(vals));
1999         } else {
2000           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
2001         }
2002         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
2003         PetscCall(PetscFree(cols));
2004       }
2005       if (D) PetscCall(MatDestroy(&D));
2006       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2007     }
2008     PetscCall(ISRestoreIndices(bNis, &bNindices));
2009     PetscCall(ISDestroy(&bNis));
2010   }
2011   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
2012   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
2013   PetscFunctionReturn(PETSC_SUCCESS);
2014 }
2015 
2016 static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2017 {
2018   Mat_Nest   *nest = (Mat_Nest *)A->data;
2019   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend;
2020   PetscMPIInt size;
2021   Mat         C;
2022 
2023   PetscFunctionBegin;
2024   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
2025   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
2026     PetscInt  nf;
2027     PetscBool fast;
2028 
2029     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
2030     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
2031     for (i = 0; i < nest->nr && fast; ++i) {
2032       for (j = 0; j < nest->nc && fast; ++j) {
2033         Mat B = nest->m[i][j];
2034         if (B) {
2035           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
2036           if (!fast) {
2037             PetscBool istrans;
2038 
2039             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
2040             if (istrans) {
2041               Mat Bt;
2042 
2043               PetscCall(MatTransposeGetMat(B, &Bt));
2044               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2045             } else {
2046               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
2047               if (istrans) {
2048                 Mat Bt;
2049 
2050                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
2051                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2052               }
2053             }
2054             if (fast) fast = (PetscBool)(!((Mat_Shell *)B->data)->zrows && !((Mat_Shell *)B->data)->zcols && !((Mat_Shell *)B->data)->axpy && !((Mat_Shell *)B->data)->left && !((Mat_Shell *)B->data)->right && !((Mat_Shell *)B->data)->dshift);
2055           }
2056         }
2057       }
2058     }
2059     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
2060       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
2061       if (fast) {
2062         PetscInt f, s;
2063 
2064         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
2065         if (f != nf || s != 1) {
2066           fast = PETSC_FALSE;
2067         } else {
2068           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
2069           nf += f;
2070         }
2071       }
2072     }
2073     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
2074       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
2075       if (fast) {
2076         PetscInt f, s;
2077 
2078         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
2079         if (f != nf || s != 1) {
2080           fast = PETSC_FALSE;
2081         } else {
2082           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
2083           nf += f;
2084         }
2085       }
2086     }
2087     if (fast) {
2088       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
2089       PetscFunctionReturn(PETSC_SUCCESS);
2090     }
2091   }
2092   PetscCall(MatGetSize(A, &M, &N));
2093   PetscCall(MatGetLocalSize(A, &m, &n));
2094   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
2095   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2096   else {
2097     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
2098     PetscCall(MatSetType(C, newtype));
2099     PetscCall(MatSetSizes(C, m, n, M, N));
2100   }
2101   PetscCall(PetscMalloc1(2 * m, &dnnz));
2102   if (m) {
2103     onnz = dnnz + m;
2104     for (k = 0; k < m; k++) {
2105       dnnz[k] = 0;
2106       onnz[k] = 0;
2107     }
2108   }
2109   for (j = 0; j < nest->nc; ++j) {
2110     IS              bNis;
2111     PetscInt        bN;
2112     const PetscInt *bNindices;
2113     PetscBool       flg;
2114     /* Using global column indices and ISAllGather() is not scalable. */
2115     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
2116     PetscCall(ISGetSize(bNis, &bN));
2117     PetscCall(ISGetIndices(bNis, &bNindices));
2118     for (i = 0; i < nest->nr; ++i) {
2119       PetscSF         bmsf;
2120       PetscSFNode    *iremote;
2121       Mat             B = nest->m[i][j], D = NULL;
2122       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2123       const PetscInt *bmindices;
2124       if (!B) continue;
2125       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
2126       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
2127       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
2128       PetscCall(PetscMalloc1(bm, &iremote));
2129       PetscCall(PetscMalloc1(bm, &sub_dnnz));
2130       PetscCall(PetscMalloc1(bm, &sub_onnz));
2131       for (k = 0; k < bm; ++k) {
2132         sub_dnnz[k] = 0;
2133         sub_onnz[k] = 0;
2134       }
2135       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
2136       if (flg) {
2137         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2138         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2139         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2140         B = D;
2141       }
2142       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2143       if (flg) {
2144         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2145         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2146         B = D;
2147       }
2148       /*
2149        Locate the owners for all of the locally-owned global row indices for this row block.
2150        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2151        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2152        */
2153       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2154       for (br = 0; br < bm; ++br) {
2155         PetscInt        row = bmindices[br], brncols, col;
2156         const PetscInt *brcols;
2157         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2158         PetscMPIInt     rowowner = 0;
2159         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2160         /* how many roots  */
2161         iremote[br].rank  = rowowner;
2162         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2163         /* get nonzero pattern */
2164         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2165         for (k = 0; k < brncols; k++) {
2166           col = bNindices[brcols[k]];
2167           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2168             sub_dnnz[br]++;
2169           } else {
2170             sub_onnz[br]++;
2171           }
2172         }
2173         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2174       }
2175       if (D) PetscCall(MatDestroy(&D));
2176       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2177       /* bsf will have to take care of disposing of bedges. */
2178       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
2179       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
2180       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
2181       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
2182       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
2183       PetscCall(PetscFree(sub_dnnz));
2184       PetscCall(PetscFree(sub_onnz));
2185       PetscCall(PetscSFDestroy(&bmsf));
2186     }
2187     PetscCall(ISRestoreIndices(bNis, &bNindices));
2188     PetscCall(ISDestroy(&bNis));
2189   }
2190   /* Resize preallocation if overestimated */
2191   for (i = 0; i < m; i++) {
2192     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
2193     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2194   }
2195   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
2196   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
2197   PetscCall(PetscFree(dnnz));
2198   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2199   if (reuse == MAT_INPLACE_MATRIX) {
2200     PetscCall(MatHeaderReplace(A, &C));
2201   } else *newmat = C;
2202   PetscFunctionReturn(PETSC_SUCCESS);
2203 }
2204 
2205 static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2206 {
2207   Mat      B;
2208   PetscInt m, n, M, N;
2209 
2210   PetscFunctionBegin;
2211   PetscCall(MatGetSize(A, &M, &N));
2212   PetscCall(MatGetLocalSize(A, &m, &n));
2213   if (reuse == MAT_REUSE_MATRIX) {
2214     B = *newmat;
2215     PetscCall(MatZeroEntries(B));
2216   } else {
2217     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2218   }
2219   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2220   if (reuse == MAT_INPLACE_MATRIX) {
2221     PetscCall(MatHeaderReplace(A, &B));
2222   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
2223   PetscFunctionReturn(PETSC_SUCCESS);
2224 }
2225 
2226 static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has)
2227 {
2228   Mat_Nest    *bA = (Mat_Nest *)mat->data;
2229   MatOperation opAdd;
2230   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
2231   PetscBool    flg;
2232 
2233   PetscFunctionBegin;
2234   *has = PETSC_FALSE;
2235   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
2236     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
2237     for (j = 0; j < nc; j++) {
2238       for (i = 0; i < nr; i++) {
2239         if (!bA->m[i][j]) continue;
2240         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
2241         if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
2242       }
2243     }
2244   }
2245   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
2246   PetscFunctionReturn(PETSC_SUCCESS);
2247 }
2248 
2249 /*MC
2250   MATNEST -  "nest" - Matrix type consisting of nested submatrices, each stored separately.
2251 
2252   Level: intermediate
2253 
2254   Notes:
2255   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2256   It allows the use of symmetric and block formats for parts of multi-physics simulations.
2257   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2258 
2259   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
2260   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
2261   than the nest matrix.
2262 
2263 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2264           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2265           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2266 M*/
2267 PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2268 {
2269   Mat_Nest *s;
2270 
2271   PetscFunctionBegin;
2272   PetscCall(PetscNew(&s));
2273   A->data = (void *)s;
2274 
2275   s->nr            = -1;
2276   s->nc            = -1;
2277   s->m             = NULL;
2278   s->splitassembly = PETSC_FALSE;
2279 
2280   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
2281 
2282   A->ops->mult                      = MatMult_Nest;
2283   A->ops->multadd                   = MatMultAdd_Nest;
2284   A->ops->multtranspose             = MatMultTranspose_Nest;
2285   A->ops->multtransposeadd          = MatMultTransposeAdd_Nest;
2286   A->ops->transpose                 = MatTranspose_Nest;
2287   A->ops->multhermitiantranspose    = MatMultHermitianTranspose_Nest;
2288   A->ops->multhermitiantransposeadd = MatMultHermitianTransposeAdd_Nest;
2289   A->ops->assemblybegin             = MatAssemblyBegin_Nest;
2290   A->ops->assemblyend               = MatAssemblyEnd_Nest;
2291   A->ops->zeroentries               = MatZeroEntries_Nest;
2292   A->ops->copy                      = MatCopy_Nest;
2293   A->ops->axpy                      = MatAXPY_Nest;
2294   A->ops->duplicate                 = MatDuplicate_Nest;
2295   A->ops->createsubmatrix           = MatCreateSubMatrix_Nest;
2296   A->ops->destroy                   = MatDestroy_Nest;
2297   A->ops->view                      = MatView_Nest;
2298   A->ops->getvecs                   = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2299   A->ops->getlocalsubmatrix         = MatGetLocalSubMatrix_Nest;
2300   A->ops->restorelocalsubmatrix     = MatRestoreLocalSubMatrix_Nest;
2301   A->ops->getdiagonal               = MatGetDiagonal_Nest;
2302   A->ops->diagonalscale             = MatDiagonalScale_Nest;
2303   A->ops->scale                     = MatScale_Nest;
2304   A->ops->shift                     = MatShift_Nest;
2305   A->ops->diagonalset               = MatDiagonalSet_Nest;
2306   A->ops->setrandom                 = MatSetRandom_Nest;
2307   A->ops->hasoperation              = MatHasOperation_Nest;
2308   A->ops->missingdiagonal           = MatMissingDiagonal_Nest;
2309 
2310   A->spptr     = NULL;
2311   A->assembled = PETSC_FALSE;
2312 
2313   /* expose Nest api's */
2314   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
2315   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
2316   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
2317   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
2318   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
2319   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
2320   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
2321   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
2322   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
2323   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
2324   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
2325   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
2326   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
2327   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
2328   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
2329   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
2330 
2331   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
2332   PetscFunctionReturn(PETSC_SUCCESS);
2333 }
2334