xref: /petsc/src/mat/impls/nest/matnest.c (revision 7e1a0bbe36d2be40a00a95404ece00db4857f70d)
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     PetscViewerFormat format;
932 
933     PetscCall(PetscViewerGetFormat(viewer, &format));
934     if (format == PETSC_VIEWER_ASCII_MATLAB) {
935       Mat T;
936 
937       PetscCall(MatConvert(A, MATAIJ, MAT_INITIAL_MATRIX, &T));
938       PetscCall(MatView(T, viewer));
939       PetscCall(MatDestroy(&T));
940       PetscFunctionReturn(PETSC_SUCCESS);
941     }
942     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL));
943     PetscCall(PetscViewerASCIIPushTab(viewer));
944     PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", structure:\n", bA->nr, bA->nc));
945     for (i = 0; i < bA->nr; i++) {
946       for (j = 0; j < bA->nc; j++) {
947         MatType   type;
948         char      name[256] = "", prefix[256] = "";
949         PetscInt  NR, NC;
950         PetscBool isNest = PETSC_FALSE;
951 
952         if (!bA->m[i][j]) {
953           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j));
954           continue;
955         }
956         PetscCall(MatGetSize(bA->m[i][j], &NR, &NC));
957         PetscCall(MatGetType(bA->m[i][j], &type));
958         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name));
959         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix));
960         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest));
961 
962         PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : %s%stype=%s, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", i, j, name, prefix, type, NR, NC));
963 
964         if (isNest || viewSub) {
965           PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */
966           PetscCall(MatView(bA->m[i][j], viewer));
967           PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */
968         }
969       }
970     }
971     PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */
972   }
973   PetscFunctionReturn(PETSC_SUCCESS);
974 }
975 
976 static PetscErrorCode MatZeroEntries_Nest(Mat A)
977 {
978   Mat_Nest *bA = (Mat_Nest *)A->data;
979   PetscInt  i, j;
980 
981   PetscFunctionBegin;
982   for (i = 0; i < bA->nr; i++) {
983     for (j = 0; j < bA->nc; j++) {
984       if (!bA->m[i][j]) continue;
985       PetscCall(MatZeroEntries(bA->m[i][j]));
986     }
987   }
988   PetscFunctionReturn(PETSC_SUCCESS);
989 }
990 
991 static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str)
992 {
993   Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data;
994   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
995   PetscBool nnzstate = PETSC_FALSE;
996 
997   PetscFunctionBegin;
998   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);
999   for (i = 0; i < nr; i++) {
1000     for (j = 0; j < nc; j++) {
1001       PetscObjectState subnnzstate = 0;
1002       if (bA->m[i][j] && bB->m[i][j]) {
1003         PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str));
1004         PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate));
1005         nnzstate                 = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate);
1006         bB->nnzstate[i * nc + j] = subnnzstate;
1007       } else if (bA->m[i][j]) { // bB->m[i][j] is NULL
1008         Mat M;
1009 
1010         PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j);
1011         PetscCall(MatDuplicate(bA->m[i][j], MAT_COPY_VALUES, &M));
1012         PetscCall(MatNestSetSubMat(B, i, j, M));
1013         PetscCall(MatDestroy(&M));
1014       } else if (bB->m[i][j]) { // bA->m[i][j] is NULL
1015         PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == SUBSET_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN, SUBSET_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j);
1016         PetscCall(MatNestSetSubMat(B, i, j, NULL));
1017       }
1018     }
1019   }
1020   if (nnzstate) B->nonzerostate++;
1021   PetscFunctionReturn(PETSC_SUCCESS);
1022 }
1023 
1024 static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str)
1025 {
1026   Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data;
1027   PetscInt  i, j, nr = bY->nr, nc = bY->nc;
1028   PetscBool nnzstate = PETSC_FALSE;
1029 
1030   PetscFunctionBegin;
1031   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);
1032   for (i = 0; i < nr; i++) {
1033     for (j = 0; j < nc; j++) {
1034       PetscObjectState subnnzstate = 0;
1035       if (bY->m[i][j] && bX->m[i][j]) {
1036         PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str));
1037       } else if (bX->m[i][j]) {
1038         Mat M;
1039 
1040         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);
1041         PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M));
1042         PetscCall(MatNestSetSubMat(Y, i, j, M));
1043         PetscCall(MatDestroy(&M));
1044       }
1045       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate));
1046       nnzstate                 = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate);
1047       bY->nnzstate[i * nc + j] = subnnzstate;
1048     }
1049   }
1050   if (nnzstate) Y->nonzerostate++;
1051   PetscFunctionReturn(PETSC_SUCCESS);
1052 }
1053 
1054 static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B)
1055 {
1056   Mat_Nest *bA = (Mat_Nest *)A->data;
1057   Mat      *b;
1058   PetscInt  i, j, nr = bA->nr, nc = bA->nc;
1059 
1060   PetscFunctionBegin;
1061   PetscCall(PetscMalloc1(nr * nc, &b));
1062   for (i = 0; i < nr; i++) {
1063     for (j = 0; j < nc; j++) {
1064       if (bA->m[i][j]) {
1065         PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j]));
1066       } else {
1067         b[i * nc + j] = NULL;
1068       }
1069     }
1070   }
1071   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B));
1072   /* Give the new MatNest exclusive ownership */
1073   for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i]));
1074   PetscCall(PetscFree(b));
1075 
1076   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
1077   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
1078   PetscFunctionReturn(PETSC_SUCCESS);
1079 }
1080 
1081 /* nest api */
1082 static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat)
1083 {
1084   Mat_Nest *bA = (Mat_Nest *)A->data;
1085 
1086   PetscFunctionBegin;
1087   PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1);
1088   PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1);
1089   *mat = bA->m[idxm][jdxm];
1090   PetscFunctionReturn(PETSC_SUCCESS);
1091 }
1092 
1093 /*@
1094   MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST`
1095 
1096   Not Collective
1097 
1098   Input Parameters:
1099 + A    - `MATNEST` matrix
1100 . idxm - index of the matrix within the nest matrix
1101 - jdxm - index of the matrix within the nest matrix
1102 
1103   Output Parameter:
1104 . sub - matrix at index `idxm`, `jdxm` within the nest matrix
1105 
1106   Level: developer
1107 
1108 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`,
1109           `MatNestGetLocalISs()`, `MatNestGetISs()`
1110 @*/
1111 PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub)
1112 {
1113   PetscFunctionBegin;
1114   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1115   PetscValidLogicalCollectiveInt(A, idxm, 2);
1116   PetscValidLogicalCollectiveInt(A, jdxm, 3);
1117   PetscAssertPointer(sub, 4);
1118   PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub));
1119   PetscFunctionReturn(PETSC_SUCCESS);
1120 }
1121 
1122 static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat)
1123 {
1124   Mat_Nest *bA = (Mat_Nest *)A->data;
1125   PetscInt  m, n, M, N, mi, ni, Mi, Ni;
1126 
1127   PetscFunctionBegin;
1128   PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1);
1129   PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1);
1130   if (mat) {
1131     PetscCall(MatGetLocalSize(mat, &m, &n));
1132     PetscCall(MatGetSize(mat, &M, &N));
1133     PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi));
1134     PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi));
1135     PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni));
1136     PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni));
1137     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);
1138     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);
1139   }
1140 
1141   /* do not increase object state */
1142   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS);
1143 
1144   PetscCall(PetscObjectReference((PetscObject)mat));
1145   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
1146   bA->m[idxm][jdxm] = mat;
1147   PetscCall(PetscObjectStateIncrease((PetscObject)A));
1148   if (mat) PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm]));
1149   else bA->nnzstate[idxm * bA->nc + jdxm] = 0;
1150   A->nonzerostate++;
1151   PetscFunctionReturn(PETSC_SUCCESS);
1152 }
1153 
1154 /*@
1155   MatNestSetSubMat - Set a single submatrix in the `MATNEST`
1156 
1157   Logically Collective
1158 
1159   Input Parameters:
1160 + A    - `MATNEST` matrix
1161 . idxm - index of the matrix within the nest matrix
1162 . jdxm - index of the matrix within the nest matrix
1163 - sub  - matrix at index `idxm`, `jdxm` within the nest matrix
1164 
1165   Level: developer
1166 
1167   Notes:
1168   The new submatrix must have the same size and communicator as that block of the nest.
1169 
1170   This increments the reference count of the submatrix.
1171 
1172 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1173           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
1174 @*/
1175 PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub)
1176 {
1177   PetscFunctionBegin;
1178   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1179   PetscValidLogicalCollectiveInt(A, idxm, 2);
1180   PetscValidLogicalCollectiveInt(A, jdxm, 3);
1181   if (sub) PetscValidHeaderSpecific(sub, MAT_CLASSID, 4);
1182   PetscTryMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub));
1183   PetscFunctionReturn(PETSC_SUCCESS);
1184 }
1185 
1186 static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1187 {
1188   Mat_Nest *bA = (Mat_Nest *)A->data;
1189 
1190   PetscFunctionBegin;
1191   if (M) *M = bA->nr;
1192   if (N) *N = bA->nc;
1193   if (mat) *mat = bA->m;
1194   PetscFunctionReturn(PETSC_SUCCESS);
1195 }
1196 
1197 /*@C
1198   MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix.
1199 
1200   Not Collective
1201 
1202   Input Parameter:
1203 . A - nest matrix
1204 
1205   Output Parameters:
1206 + M   - number of submatrix rows in the nest matrix
1207 . N   - number of submatrix columns in the nest matrix
1208 - mat - array of matrices
1209 
1210   Level: developer
1211 
1212   Note:
1213   The user should not free the array `mat`.
1214 
1215   Fortran Notes:
1216   This routine has a calling sequence `call MatNestGetSubMats(A, M, N, mat, ierr)`
1217   where the space allocated for the optional argument `mat` is assumed large enough (if provided).
1218   Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example.
1219 
1220 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`,
1221           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1222 @*/
1223 PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat)
1224 {
1225   PetscFunctionBegin;
1226   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1227   PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat));
1228   PetscFunctionReturn(PETSC_SUCCESS);
1229 }
1230 
1231 static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N)
1232 {
1233   Mat_Nest *bA = (Mat_Nest *)A->data;
1234 
1235   PetscFunctionBegin;
1236   if (M) *M = bA->nr;
1237   if (N) *N = bA->nc;
1238   PetscFunctionReturn(PETSC_SUCCESS);
1239 }
1240 
1241 /*@
1242   MatNestGetSize - Returns the size of the `MATNEST` matrix.
1243 
1244   Not Collective
1245 
1246   Input Parameter:
1247 . A - `MATNEST` matrix
1248 
1249   Output Parameters:
1250 + M - number of rows in the nested mat
1251 - N - number of cols in the nested mat
1252 
1253   Level: developer
1254 
1255   Note:
1256   `size` refers to the number of submatrices in the row and column directions of the nested matrix
1257 
1258 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1259           `MatNestGetISs()`
1260 @*/
1261 PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N)
1262 {
1263   PetscFunctionBegin;
1264   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1265   PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N));
1266   PetscFunctionReturn(PETSC_SUCCESS);
1267 }
1268 
1269 static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[])
1270 {
1271   Mat_Nest *vs = (Mat_Nest *)A->data;
1272   PetscInt  i;
1273 
1274   PetscFunctionBegin;
1275   if (rows)
1276     for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i];
1277   if (cols)
1278     for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i];
1279   PetscFunctionReturn(PETSC_SUCCESS);
1280 }
1281 
1282 /*@
1283   MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1284 
1285   Not Collective
1286 
1287   Input Parameter:
1288 . A - `MATNEST` matrix
1289 
1290   Output Parameters:
1291 + rows - array of row index sets (pass `NULL` to ignore)
1292 - cols - array of column index sets (pass `NULL` to ignore)
1293 
1294   Level: advanced
1295 
1296   Note:
1297   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1298 
1299 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`,
1300           `MatCreateNest()`, `MatNestSetSubMats()`
1301 @*/
1302 PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[])
1303 {
1304   PetscFunctionBegin;
1305   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1306   PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols));
1307   PetscFunctionReturn(PETSC_SUCCESS);
1308 }
1309 
1310 static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[])
1311 {
1312   Mat_Nest *vs = (Mat_Nest *)A->data;
1313   PetscInt  i;
1314 
1315   PetscFunctionBegin;
1316   if (rows)
1317     for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i];
1318   if (cols)
1319     for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i];
1320   PetscFunctionReturn(PETSC_SUCCESS);
1321 }
1322 
1323 /*@
1324   MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST`
1325 
1326   Not Collective
1327 
1328   Input Parameter:
1329 . A - `MATNEST` matrix
1330 
1331   Output Parameters:
1332 + rows - array of row index sets (pass `NULL` to ignore)
1333 - cols - array of column index sets (pass `NULL` to ignore)
1334 
1335   Level: advanced
1336 
1337   Note:
1338   The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s.
1339 
1340 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1341           `MatNestSetSubMats()`, `MatNestSetSubMat()`
1342 @*/
1343 PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[])
1344 {
1345   PetscFunctionBegin;
1346   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1347   PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols));
1348   PetscFunctionReturn(PETSC_SUCCESS);
1349 }
1350 
1351 static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype)
1352 {
1353   PetscBool flg;
1354 
1355   PetscFunctionBegin;
1356   PetscCall(PetscStrcmp(vtype, VECNEST, &flg));
1357   /* In reality, this only distinguishes VECNEST and "other" */
1358   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
1359   else A->ops->getvecs = NULL;
1360   PetscFunctionReturn(PETSC_SUCCESS);
1361 }
1362 
1363 /*@
1364   MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()`
1365 
1366   Not Collective
1367 
1368   Input Parameters:
1369 + A     - `MATNEST` matrix
1370 - vtype - `VecType` to use for creating vectors
1371 
1372   Level: developer
1373 
1374 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType`
1375 @*/
1376 PetscErrorCode MatNestSetVecType(Mat A, VecType vtype)
1377 {
1378   PetscFunctionBegin;
1379   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1380   PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype));
1381   PetscFunctionReturn(PETSC_SUCCESS);
1382 }
1383 
1384 static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[])
1385 {
1386   Mat_Nest *s = (Mat_Nest *)A->data;
1387   PetscInt  i, j, m, n, M, N;
1388   PetscBool cong, isstd, sametype = PETSC_FALSE;
1389   VecType   vtype, type;
1390 
1391   PetscFunctionBegin;
1392   PetscCall(MatReset_Nest(A));
1393 
1394   s->nr = nr;
1395   s->nc = nc;
1396 
1397   /* Create space for submatrices */
1398   PetscCall(PetscMalloc1(nr, &s->m));
1399   PetscCall(PetscMalloc1(nr * nc, &s->m[0]));
1400   for (i = 0; i < nr; i++) {
1401     s->m[i] = s->m[0] + i * nc;
1402     for (j = 0; j < nc; j++) {
1403       s->m[i][j] = a ? a[i * nc + j] : NULL;
1404       PetscCall(PetscObjectReference((PetscObject)s->m[i][j]));
1405     }
1406   }
1407   PetscCall(MatGetVecType(A, &vtype));
1408   PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd));
1409   if (isstd) {
1410     /* check if all blocks have the same vectype */
1411     vtype = NULL;
1412     for (i = 0; i < nr; i++) {
1413       for (j = 0; j < nc; j++) {
1414         if (s->m[i][j]) {
1415           if (!vtype) { /* first visited block */
1416             PetscCall(MatGetVecType(s->m[i][j], &vtype));
1417             sametype = PETSC_TRUE;
1418           } else if (sametype) {
1419             PetscCall(MatGetVecType(s->m[i][j], &type));
1420             PetscCall(PetscStrcmp(vtype, type, &sametype));
1421           }
1422         }
1423       }
1424     }
1425     if (sametype) { /* propagate vectype */
1426       PetscCall(MatSetVecType(A, vtype));
1427     }
1428   }
1429 
1430   PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col));
1431 
1432   PetscCall(PetscMalloc1(nr, &s->row_len));
1433   PetscCall(PetscMalloc1(nc, &s->col_len));
1434   for (i = 0; i < nr; i++) s->row_len[i] = -1;
1435   for (j = 0; j < nc; j++) s->col_len[j] = -1;
1436 
1437   PetscCall(PetscCalloc1(nr * nc, &s->nnzstate));
1438   for (i = 0; i < nr; i++) {
1439     for (j = 0; j < nc; j++) {
1440       if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j]));
1441     }
1442   }
1443 
1444   PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N));
1445 
1446   PetscCall(PetscLayoutSetSize(A->rmap, M));
1447   PetscCall(PetscLayoutSetLocalSize(A->rmap, m));
1448   PetscCall(PetscLayoutSetSize(A->cmap, N));
1449   PetscCall(PetscLayoutSetLocalSize(A->cmap, n));
1450 
1451   PetscCall(PetscLayoutSetUp(A->rmap));
1452   PetscCall(PetscLayoutSetUp(A->cmap));
1453 
1454   /* disable operations that are not supported for non-square matrices,
1455      or matrices for which is_row != is_col  */
1456   PetscCall(MatHasCongruentLayouts(A, &cong));
1457   if (cong && nr != nc) cong = PETSC_FALSE;
1458   if (cong) {
1459     for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong));
1460   }
1461   if (!cong) {
1462     A->ops->missingdiagonal = NULL;
1463     A->ops->getdiagonal     = NULL;
1464     A->ops->shift           = NULL;
1465     A->ops->diagonalset     = NULL;
1466   }
1467 
1468   PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right));
1469   PetscCall(PetscObjectStateIncrease((PetscObject)A));
1470   A->nonzerostate++;
1471   PetscFunctionReturn(PETSC_SUCCESS);
1472 }
1473 
1474 /*@
1475   MatNestSetSubMats - Sets the nested submatrices in a `MATNEST`
1476 
1477   Collective
1478 
1479   Input Parameters:
1480 + A      - `MATNEST` matrix
1481 . nr     - number of nested row blocks
1482 . is_row - index sets for each nested row block, or `NULL` to make contiguous
1483 . nc     - number of nested column blocks
1484 . is_col - index sets for each nested column block, or `NULL` to make contiguous
1485 - a      - array of $ nr \times nc$ submatrices, or `NULL`
1486 
1487   Level: advanced
1488 
1489   Notes:
1490   This always resets any block matrix information previously set.
1491 
1492   Pass `NULL` in the corresponding entry of `a` for an empty block.
1493 
1494   In both C and Fortran, `a` must be a one-dimensional array representing a two-dimensional row-major order array containing the matrices. See
1495   `MatCreateNest()` for an example.
1496 
1497   Fortran Note:
1498   Pass `PETSC_NULL_MAT` in the corresponding entry of `a` for an empty block
1499 
1500 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1501 @*/
1502 PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) PeNSS
1503 {
1504   PetscFunctionBegin;
1505   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1506   PetscValidLogicalCollectiveInt(A, nr, 2);
1507   PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative");
1508   if (nr && is_row) {
1509     PetscAssertPointer(is_row, 3);
1510     for (PetscInt i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3);
1511   }
1512   PetscValidLogicalCollectiveInt(A, nc, 4);
1513   PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative");
1514   if (nc && is_col) {
1515     PetscAssertPointer(is_col, 5);
1516     for (PetscInt i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5);
1517   }
1518   PetscTryMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a));
1519   PetscFunctionReturn(PETSC_SUCCESS);
1520 }
1521 
1522 static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog)
1523 {
1524   PetscBool flg;
1525   PetscInt  i, j, m, mi, *ix;
1526 
1527   PetscFunctionBegin;
1528   *ltog = NULL;
1529   for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) {
1530     if (islocal[i]) {
1531       PetscCall(ISGetLocalSize(islocal[i], &mi));
1532       flg = PETSC_TRUE; /* We found a non-trivial entry */
1533     } else {
1534       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1535     }
1536     m += mi;
1537   }
1538   if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
1539 
1540   PetscCall(PetscMalloc1(m, &ix));
1541   for (i = 0, m = 0; i < n; i++) {
1542     ISLocalToGlobalMapping smap = NULL;
1543     Mat                    sub  = NULL;
1544     PetscSF                sf;
1545     PetscLayout            map;
1546     const PetscInt        *ix2;
1547 
1548     if (!colflg) {
1549       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1550     } else {
1551       PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
1552     }
1553     if (sub) {
1554       if (!colflg) {
1555         PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL));
1556       } else {
1557         PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap));
1558       }
1559     }
1560     /*
1561        Now we need to extract the monolithic global indices that correspond to the given split global indices.
1562        In many/most cases, we only want MatGetLocalSubMatrix() to work, in which case we only need to know the size of the local spaces.
1563     */
1564     PetscCall(ISGetIndices(isglobal[i], &ix2));
1565     if (islocal[i]) {
1566       PetscInt *ilocal, *iremote;
1567       PetscInt  mil, nleaves;
1568 
1569       PetscCall(ISGetLocalSize(islocal[i], &mi));
1570       PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map");
1571       for (j = 0; j < mi; j++) ix[m + j] = j;
1572       PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m));
1573 
1574       /* PetscSFSetGraphLayout does not like negative indices */
1575       PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote));
1576       for (j = 0, nleaves = 0; j < mi; j++) {
1577         if (ix[m + j] < 0) continue;
1578         ilocal[nleaves]  = j;
1579         iremote[nleaves] = ix[m + j];
1580         nleaves++;
1581       }
1582       PetscCall(ISGetLocalSize(isglobal[i], &mil));
1583       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf));
1584       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map));
1585       PetscCall(PetscLayoutSetLocalSize(map, mil));
1586       PetscCall(PetscLayoutSetUp(map));
1587       PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote));
1588       PetscCall(PetscLayoutDestroy(&map));
1589       PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
1590       PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE));
1591       PetscCall(PetscSFDestroy(&sf));
1592       PetscCall(PetscFree2(ilocal, iremote));
1593     } else {
1594       PetscCall(ISGetLocalSize(isglobal[i], &mi));
1595       for (j = 0; j < mi; j++) ix[m + j] = ix2[i];
1596     }
1597     PetscCall(ISRestoreIndices(isglobal[i], &ix2));
1598     m += mi;
1599   }
1600   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog));
1601   PetscFunctionReturn(PETSC_SUCCESS);
1602 }
1603 
1604 /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1605 /*
1606   nprocessors = NP
1607   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1608        proc 0: => (g_0,h_0,)
1609        proc 1: => (g_1,h_1,)
1610        ...
1611        proc nprocs-1: => (g_NP-1,h_NP-1,)
1612 
1613             proc 0:                      proc 1:                    proc nprocs-1:
1614     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1615 
1616             proc 0:
1617     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1618             proc 1:
1619     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1620 
1621             proc NP-1:
1622     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1623 */
1624 static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[])
1625 {
1626   Mat_Nest *vs = (Mat_Nest *)A->data;
1627   PetscInt  i, j, offset, n, nsum, bs;
1628   Mat       sub = NULL;
1629 
1630   PetscFunctionBegin;
1631   PetscCall(PetscMalloc1(nr, &vs->isglobal.row));
1632   PetscCall(PetscMalloc1(nc, &vs->isglobal.col));
1633   if (is_row) { /* valid IS is passed in */
1634     /* refs on is[] are incremented */
1635     for (i = 0; i < vs->nr; i++) {
1636       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
1637       vs->isglobal.row[i] = is_row[i];
1638     }
1639   } else { /* Create the ISs by inspecting sizes of a submatrix in each row */
1640     nsum = 0;
1641     for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */
1642       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1643       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i);
1644       PetscCall(MatGetLocalSize(sub, &n, NULL));
1645       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
1646       nsum += n;
1647     }
1648     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
1649     offset -= nsum;
1650     for (i = 0; i < vs->nr; i++) {
1651       PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1652       PetscCall(MatGetLocalSize(sub, &n, NULL));
1653       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
1654       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i]));
1655       PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs));
1656       offset += n;
1657     }
1658   }
1659 
1660   if (is_col) { /* valid IS is passed in */
1661     /* refs on is[] are incremented */
1662     for (j = 0; j < vs->nc; j++) {
1663       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
1664       vs->isglobal.col[j] = is_col[j];
1665     }
1666   } else { /* Create the ISs by inspecting sizes of a submatrix in each column */
1667     offset = A->cmap->rstart;
1668     nsum   = 0;
1669     for (j = 0; j < vs->nc; j++) {
1670       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
1671       PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i);
1672       PetscCall(MatGetLocalSize(sub, NULL, &n));
1673       PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix");
1674       nsum += n;
1675     }
1676     PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A)));
1677     offset -= nsum;
1678     for (j = 0; j < vs->nc; j++) {
1679       PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub));
1680       PetscCall(MatGetLocalSize(sub, NULL, &n));
1681       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
1682       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j]));
1683       PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs));
1684       offset += n;
1685     }
1686   }
1687 
1688   /* Set up the local ISs */
1689   PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row));
1690   PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col));
1691   for (i = 0, offset = 0; i < vs->nr; i++) {
1692     IS                     isloc;
1693     ISLocalToGlobalMapping rmap = NULL;
1694     PetscInt               nlocal, bs;
1695     PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub));
1696     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL));
1697     if (rmap) {
1698       PetscCall(MatGetBlockSizes(sub, &bs, NULL));
1699       PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal));
1700       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
1701       PetscCall(ISSetBlockSize(isloc, bs));
1702     } else {
1703       nlocal = 0;
1704       isloc  = NULL;
1705     }
1706     vs->islocal.row[i] = isloc;
1707     offset += nlocal;
1708   }
1709   for (i = 0, offset = 0; i < vs->nc; i++) {
1710     IS                     isloc;
1711     ISLocalToGlobalMapping cmap = NULL;
1712     PetscInt               nlocal, bs;
1713     PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub));
1714     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap));
1715     if (cmap) {
1716       PetscCall(MatGetBlockSizes(sub, NULL, &bs));
1717       PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal));
1718       PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc));
1719       PetscCall(ISSetBlockSize(isloc, bs));
1720     } else {
1721       nlocal = 0;
1722       isloc  = NULL;
1723     }
1724     vs->islocal.col[i] = isloc;
1725     offset += nlocal;
1726   }
1727 
1728   /* Set up the aggregate ISLocalToGlobalMapping */
1729   {
1730     ISLocalToGlobalMapping rmap, cmap;
1731     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap));
1732     PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap));
1733     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
1734     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
1735     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
1736   }
1737 
1738   if (PetscDefined(USE_DEBUG)) {
1739     for (i = 0; i < vs->nr; i++) {
1740       for (j = 0; j < vs->nc; j++) {
1741         PetscInt m, n, M, N, mi, ni, Mi, Ni;
1742         Mat      B = vs->m[i][j];
1743         if (!B) continue;
1744         PetscCall(MatGetSize(B, &M, &N));
1745         PetscCall(MatGetLocalSize(B, &m, &n));
1746         PetscCall(ISGetSize(vs->isglobal.row[i], &Mi));
1747         PetscCall(ISGetSize(vs->isglobal.col[j], &Ni));
1748         PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi));
1749         PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni));
1750         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);
1751         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);
1752       }
1753     }
1754   }
1755 
1756   /* Set A->assembled if all non-null blocks are currently assembled */
1757   for (i = 0; i < vs->nr; i++) {
1758     for (j = 0; j < vs->nc; j++) {
1759       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS);
1760     }
1761   }
1762   A->assembled = PETSC_TRUE;
1763   PetscFunctionReturn(PETSC_SUCCESS);
1764 }
1765 
1766 /*@C
1767   MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately
1768 
1769   Collective
1770 
1771   Input Parameters:
1772 + comm   - Communicator for the new `MATNEST`
1773 . nr     - number of nested row blocks
1774 . is_row - index sets for each nested row block, or `NULL` to make contiguous
1775 . nc     - number of nested column blocks
1776 . is_col - index sets for each nested column block, or `NULL` to make contiguous
1777 - a      - array of $nr \times nc$ submatrices, empty submatrices can be passed using `NULL`
1778 
1779   Output Parameter:
1780 . B - new matrix
1781 
1782   Level: advanced
1783 
1784   Note:
1785   In both C and Fortran, `a` must be a one-dimensional array representing a two-dimensional row-major order array holding references to the matrices.
1786   For instance, to represent the matrix
1787   $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$
1788   one should use `Mat a[4]={A11,A12,A21,A22}`.
1789 
1790   Fortran Note:
1791   Pass `PETSC_NULL_MAT` in the corresponding entry of `a` for an empty block
1792 
1793 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`,
1794           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1795           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1796 @*/
1797 PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) PeNSS
1798 {
1799   PetscFunctionBegin;
1800   PetscCall(MatCreate(comm, B));
1801   PetscCall(MatSetType(*B, MATNEST));
1802   (*B)->preallocated = PETSC_TRUE;
1803   PetscCall(MatNestSetSubMats(*B, nr, is_row, nc, is_col, a));
1804   PetscFunctionReturn(PETSC_SUCCESS);
1805 }
1806 
1807 static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1808 {
1809   Mat_Nest     *nest = (Mat_Nest *)A->data;
1810   Mat          *trans;
1811   PetscScalar **avv;
1812   PetscScalar  *vv;
1813   PetscInt    **aii, **ajj;
1814   PetscInt     *ii, *jj, *ci;
1815   PetscInt      nr, nc, nnz, i, j;
1816   PetscBool     done;
1817 
1818   PetscFunctionBegin;
1819   PetscCall(MatGetSize(A, &nr, &nc));
1820   if (reuse == MAT_REUSE_MATRIX) {
1821     PetscInt rnr;
1822 
1823     PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done));
1824     PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ");
1825     PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows");
1826     PetscCall(MatSeqAIJGetArray(*newmat, &vv));
1827   }
1828   /* extract CSR for nested SeqAIJ matrices */
1829   nnz = 0;
1830   PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans));
1831   for (i = 0; i < nest->nr; ++i) {
1832     for (j = 0; j < nest->nc; ++j) {
1833       Mat B = nest->m[i][j];
1834       if (B) {
1835         PetscScalar *naa;
1836         PetscInt    *nii, *njj, nnr;
1837         PetscBool    istrans;
1838 
1839         PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
1840         if (istrans) {
1841           Mat Bt;
1842 
1843           PetscCall(MatTransposeGetMat(B, &Bt));
1844           PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1845           B = trans[i * nest->nc + j];
1846         } else {
1847           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
1848           if (istrans) {
1849             Mat Bt;
1850 
1851             PetscCall(MatHermitianTransposeGetMat(B, &Bt));
1852             PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j]));
1853             B = trans[i * nest->nc + j];
1854           }
1855         }
1856         PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done));
1857         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ");
1858         PetscCall(MatSeqAIJGetArray(B, &naa));
1859         nnz += nii[nnr];
1860 
1861         aii[i * nest->nc + j] = nii;
1862         ajj[i * nest->nc + j] = njj;
1863         avv[i * nest->nc + j] = naa;
1864       }
1865     }
1866   }
1867   if (reuse != MAT_REUSE_MATRIX) {
1868     PetscCall(PetscMalloc1(nr + 1, &ii));
1869     PetscCall(PetscMalloc1(nnz, &jj));
1870     PetscCall(PetscMalloc1(nnz, &vv));
1871   } else {
1872     PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros");
1873   }
1874 
1875   /* new row pointer */
1876   PetscCall(PetscArrayzero(ii, nr + 1));
1877   for (i = 0; i < nest->nr; ++i) {
1878     PetscInt ncr, rst;
1879 
1880     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
1881     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1882     for (j = 0; j < nest->nc; ++j) {
1883       if (aii[i * nest->nc + j]) {
1884         PetscInt *nii = aii[i * nest->nc + j];
1885         PetscInt  ir;
1886 
1887         for (ir = rst; ir < ncr + rst; ++ir) {
1888           ii[ir + 1] += nii[1] - nii[0];
1889           nii++;
1890         }
1891       }
1892     }
1893   }
1894   for (i = 0; i < nr; i++) ii[i + 1] += ii[i];
1895 
1896   /* construct CSR for the new matrix */
1897   PetscCall(PetscCalloc1(nr, &ci));
1898   for (i = 0; i < nest->nr; ++i) {
1899     PetscInt ncr, rst;
1900 
1901     PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL));
1902     PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr));
1903     for (j = 0; j < nest->nc; ++j) {
1904       if (aii[i * nest->nc + j]) {
1905         PetscScalar *nvv = avv[i * nest->nc + j], vscale = 1.0, vshift = 0.0;
1906         PetscInt    *nii = aii[i * nest->nc + j];
1907         PetscInt    *njj = ajj[i * nest->nc + j];
1908         PetscInt     ir, cst;
1909 
1910         if (trans[i * nest->nc + j]) {
1911           vscale = ((Mat_Shell *)nest->m[i][j]->data)->vscale;
1912           vshift = ((Mat_Shell *)nest->m[i][j]->data)->vshift;
1913         }
1914         PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL));
1915         for (ir = rst; ir < ncr + rst; ++ir) {
1916           PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir];
1917 
1918           for (ij = 0; ij < rsize; ij++) {
1919             jj[ist + ij] = *njj + cst;
1920             vv[ist + ij] = vscale * *nvv;
1921             if (PetscUnlikely(vshift != 0.0 && *njj == ir - rst)) vv[ist + ij] += vshift;
1922             njj++;
1923             nvv++;
1924           }
1925           ci[ir] += rsize;
1926           nii++;
1927         }
1928       }
1929     }
1930   }
1931   PetscCall(PetscFree(ci));
1932 
1933   /* restore info */
1934   for (i = 0; i < nest->nr; ++i) {
1935     for (j = 0; j < nest->nc; ++j) {
1936       Mat B = nest->m[i][j];
1937       if (B) {
1938         PetscInt nnr = 0, k = i * nest->nc + j;
1939 
1940         B = (trans[k] ? trans[k] : B);
1941         PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done));
1942         PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ");
1943         PetscCall(MatSeqAIJRestoreArray(B, &avv[k]));
1944         PetscCall(MatDestroy(&trans[k]));
1945       }
1946     }
1947   }
1948   PetscCall(PetscFree4(aii, ajj, avv, trans));
1949 
1950   /* finalize newmat */
1951   if (reuse == MAT_INITIAL_MATRIX) {
1952     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat));
1953   } else if (reuse == MAT_INPLACE_MATRIX) {
1954     Mat B;
1955 
1956     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B));
1957     PetscCall(MatHeaderReplace(A, &B));
1958   }
1959   PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY));
1960   PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY));
1961   {
1962     Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data);
1963     a->free_a     = PETSC_TRUE;
1964     a->free_ij    = PETSC_TRUE;
1965   }
1966   PetscFunctionReturn(PETSC_SUCCESS);
1967 }
1968 
1969 PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X)
1970 {
1971   Mat_Nest *nest = (Mat_Nest *)X->data;
1972   PetscInt  i, j, k, rstart;
1973   PetscBool flg;
1974 
1975   PetscFunctionBegin;
1976   /* Fill by row */
1977   for (j = 0; j < nest->nc; ++j) {
1978     /* Using global column indices and ISAllGather() is not scalable. */
1979     IS              bNis;
1980     PetscInt        bN;
1981     const PetscInt *bNindices;
1982     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
1983     PetscCall(ISGetSize(bNis, &bN));
1984     PetscCall(ISGetIndices(bNis, &bNindices));
1985     for (i = 0; i < nest->nr; ++i) {
1986       Mat             B = nest->m[i][j], D = NULL;
1987       PetscInt        bm, br;
1988       const PetscInt *bmindices;
1989       if (!B) continue;
1990       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
1991       if (flg) {
1992         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
1993         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
1994         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
1995         B = D;
1996       }
1997       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
1998       if (flg) {
1999         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2000         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2001         B = D;
2002       }
2003       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
2004       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
2005       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2006       for (br = 0; br < bm; ++br) {
2007         PetscInt           row = bmindices[br], brncols, *cols;
2008         const PetscInt    *brcols;
2009         const PetscScalar *brcoldata;
2010         PetscScalar       *vals = NULL;
2011         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata));
2012         PetscCall(PetscMalloc1(brncols, &cols));
2013         for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]];
2014         /*
2015           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
2016           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
2017          */
2018         if (a != 1.0) {
2019           PetscCall(PetscMalloc1(brncols, &vals));
2020           for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k];
2021           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES));
2022           PetscCall(PetscFree(vals));
2023         } else {
2024           PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES));
2025         }
2026         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata));
2027         PetscCall(PetscFree(cols));
2028       }
2029       if (D) PetscCall(MatDestroy(&D));
2030       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2031     }
2032     PetscCall(ISRestoreIndices(bNis, &bNindices));
2033     PetscCall(ISDestroy(&bNis));
2034   }
2035   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
2036   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
2037   PetscFunctionReturn(PETSC_SUCCESS);
2038 }
2039 
2040 static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2041 {
2042   Mat_Nest   *nest = (Mat_Nest *)A->data;
2043   PetscInt    m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend;
2044   PetscMPIInt size;
2045   Mat         C;
2046 
2047   PetscFunctionBegin;
2048   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
2049   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
2050     PetscInt  nf;
2051     PetscBool fast;
2052 
2053     PetscCall(PetscStrcmp(newtype, MATAIJ, &fast));
2054     if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast));
2055     for (i = 0; i < nest->nr && fast; ++i) {
2056       for (j = 0; j < nest->nc && fast; ++j) {
2057         Mat B = nest->m[i][j];
2058         if (B) {
2059           PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast));
2060           if (!fast) {
2061             PetscBool istrans;
2062 
2063             PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans));
2064             if (istrans) {
2065               Mat Bt;
2066 
2067               PetscCall(MatTransposeGetMat(B, &Bt));
2068               PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2069             } else {
2070               PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans));
2071               if (istrans) {
2072                 Mat Bt;
2073 
2074                 PetscCall(MatHermitianTransposeGetMat(B, &Bt));
2075                 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast));
2076               }
2077             }
2078             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);
2079           }
2080         }
2081       }
2082     }
2083     for (i = 0, nf = 0; i < nest->nr && fast; ++i) {
2084       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast));
2085       if (fast) {
2086         PetscInt f, s;
2087 
2088         PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s));
2089         if (f != nf || s != 1) {
2090           fast = PETSC_FALSE;
2091         } else {
2092           PetscCall(ISGetSize(nest->isglobal.row[i], &f));
2093           nf += f;
2094         }
2095       }
2096     }
2097     for (i = 0, nf = 0; i < nest->nc && fast; ++i) {
2098       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast));
2099       if (fast) {
2100         PetscInt f, s;
2101 
2102         PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s));
2103         if (f != nf || s != 1) {
2104           fast = PETSC_FALSE;
2105         } else {
2106           PetscCall(ISGetSize(nest->isglobal.col[i], &f));
2107           nf += f;
2108         }
2109       }
2110     }
2111     if (fast) {
2112       PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat));
2113       PetscFunctionReturn(PETSC_SUCCESS);
2114     }
2115   }
2116   PetscCall(MatGetSize(A, &M, &N));
2117   PetscCall(MatGetLocalSize(A, &m, &n));
2118   PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend));
2119   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2120   else {
2121     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
2122     PetscCall(MatSetType(C, newtype));
2123     PetscCall(MatSetSizes(C, m, n, M, N));
2124   }
2125   PetscCall(PetscMalloc1(2 * m, &dnnz));
2126   if (m) {
2127     onnz = dnnz + m;
2128     for (k = 0; k < m; k++) {
2129       dnnz[k] = 0;
2130       onnz[k] = 0;
2131     }
2132   }
2133   for (j = 0; j < nest->nc; ++j) {
2134     IS              bNis;
2135     PetscInt        bN;
2136     const PetscInt *bNindices;
2137     PetscBool       flg;
2138     /* Using global column indices and ISAllGather() is not scalable. */
2139     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
2140     PetscCall(ISGetSize(bNis, &bN));
2141     PetscCall(ISGetIndices(bNis, &bNindices));
2142     for (i = 0; i < nest->nr; ++i) {
2143       PetscSF         bmsf;
2144       PetscSFNode    *iremote;
2145       Mat             B = nest->m[i][j], D = NULL;
2146       PetscInt        bm, *sub_dnnz, *sub_onnz, br;
2147       const PetscInt *bmindices;
2148       if (!B) continue;
2149       PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm));
2150       PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices));
2151       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
2152       PetscCall(PetscMalloc1(bm, &iremote));
2153       PetscCall(PetscMalloc1(bm, &sub_dnnz));
2154       PetscCall(PetscMalloc1(bm, &sub_onnz));
2155       for (k = 0; k < bm; ++k) {
2156         sub_dnnz[k] = 0;
2157         sub_onnz[k] = 0;
2158       }
2159       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, ""));
2160       if (flg) {
2161         PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D));
2162         PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D));
2163         PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D));
2164         B = D;
2165       }
2166       PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
2167       if (flg) {
2168         if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D));
2169         else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D));
2170         B = D;
2171       }
2172       /*
2173        Locate the owners for all of the locally-owned global row indices for this row block.
2174        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2175        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2176        */
2177       PetscCall(MatGetOwnershipRange(B, &rstart, NULL));
2178       for (br = 0; br < bm; ++br) {
2179         PetscInt        row = bmindices[br], brncols, col;
2180         const PetscInt *brcols;
2181         PetscInt        rowrel   = 0; /* row's relative index on its owner rank */
2182         PetscMPIInt     rowowner = 0;
2183         PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel));
2184         /* how many roots  */
2185         iremote[br].rank  = rowowner;
2186         iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */
2187         /* get nonzero pattern */
2188         PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL));
2189         for (k = 0; k < brncols; k++) {
2190           col = bNindices[brcols[k]];
2191           if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) {
2192             sub_dnnz[br]++;
2193           } else {
2194             sub_onnz[br]++;
2195           }
2196         }
2197         PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL));
2198       }
2199       if (D) PetscCall(MatDestroy(&D));
2200       PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices));
2201       /* bsf will have to take care of disposing of bedges. */
2202       PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
2203       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
2204       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM));
2205       PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
2206       PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM));
2207       PetscCall(PetscFree(sub_dnnz));
2208       PetscCall(PetscFree(sub_onnz));
2209       PetscCall(PetscSFDestroy(&bmsf));
2210     }
2211     PetscCall(ISRestoreIndices(bNis, &bNindices));
2212     PetscCall(ISDestroy(&bNis));
2213   }
2214   /* Resize preallocation if overestimated */
2215   for (i = 0; i < m; i++) {
2216     dnnz[i] = PetscMin(dnnz[i], A->cmap->n);
2217     onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n);
2218   }
2219   PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz));
2220   PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz));
2221   PetscCall(PetscFree(dnnz));
2222   PetscCall(MatAXPY_Dense_Nest(C, 1.0, A));
2223   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &C));
2224   else *newmat = C;
2225   PetscFunctionReturn(PETSC_SUCCESS);
2226 }
2227 
2228 static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
2229 {
2230   Mat      B;
2231   PetscInt m, n, M, N;
2232 
2233   PetscFunctionBegin;
2234   PetscCall(MatGetSize(A, &M, &N));
2235   PetscCall(MatGetLocalSize(A, &m, &n));
2236   if (reuse == MAT_REUSE_MATRIX) {
2237     B = *newmat;
2238     PetscCall(MatZeroEntries(B));
2239   } else {
2240     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B));
2241   }
2242   PetscCall(MatAXPY_Dense_Nest(B, 1.0, A));
2243   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B));
2244   else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
2245   PetscFunctionReturn(PETSC_SUCCESS);
2246 }
2247 
2248 static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has)
2249 {
2250   Mat_Nest    *bA = (Mat_Nest *)mat->data;
2251   MatOperation opAdd;
2252   PetscInt     i, j, nr = bA->nr, nc = bA->nc;
2253   PetscBool    flg;
2254 
2255   PetscFunctionBegin;
2256   *has = PETSC_FALSE;
2257   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
2258     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
2259     for (j = 0; j < nc; j++) {
2260       for (i = 0; i < nr; i++) {
2261         if (!bA->m[i][j]) continue;
2262         PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg));
2263         if (!flg) PetscFunctionReturn(PETSC_SUCCESS);
2264       }
2265     }
2266   }
2267   if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
2268   PetscFunctionReturn(PETSC_SUCCESS);
2269 }
2270 
2271 /*MC
2272   MATNEST -  "nest" - Matrix type consisting of nested submatrices, each stored separately.
2273 
2274   Level: intermediate
2275 
2276   Notes:
2277   This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices.
2278   It allows the use of symmetric and block formats for parts of multi-physics simulations.
2279   It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()`
2280 
2281   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
2282   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
2283   than the nest matrix.
2284 
2285 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2286           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2287           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2288 M*/
2289 PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2290 {
2291   Mat_Nest *s;
2292 
2293   PetscFunctionBegin;
2294   PetscCall(PetscNew(&s));
2295   A->data = (void *)s;
2296 
2297   s->nr            = -1;
2298   s->nc            = -1;
2299   s->m             = NULL;
2300   s->splitassembly = PETSC_FALSE;
2301 
2302   PetscCall(PetscMemzero(A->ops, sizeof(*A->ops)));
2303 
2304   A->ops->mult                      = MatMult_Nest;
2305   A->ops->multadd                   = MatMultAdd_Nest;
2306   A->ops->multtranspose             = MatMultTranspose_Nest;
2307   A->ops->multtransposeadd          = MatMultTransposeAdd_Nest;
2308   A->ops->transpose                 = MatTranspose_Nest;
2309   A->ops->multhermitiantranspose    = MatMultHermitianTranspose_Nest;
2310   A->ops->multhermitiantransposeadd = MatMultHermitianTransposeAdd_Nest;
2311   A->ops->assemblybegin             = MatAssemblyBegin_Nest;
2312   A->ops->assemblyend               = MatAssemblyEnd_Nest;
2313   A->ops->zeroentries               = MatZeroEntries_Nest;
2314   A->ops->copy                      = MatCopy_Nest;
2315   A->ops->axpy                      = MatAXPY_Nest;
2316   A->ops->duplicate                 = MatDuplicate_Nest;
2317   A->ops->createsubmatrix           = MatCreateSubMatrix_Nest;
2318   A->ops->destroy                   = MatDestroy_Nest;
2319   A->ops->view                      = MatView_Nest;
2320   A->ops->getvecs                   = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2321   A->ops->getlocalsubmatrix         = MatGetLocalSubMatrix_Nest;
2322   A->ops->restorelocalsubmatrix     = MatRestoreLocalSubMatrix_Nest;
2323   A->ops->getdiagonal               = MatGetDiagonal_Nest;
2324   A->ops->diagonalscale             = MatDiagonalScale_Nest;
2325   A->ops->scale                     = MatScale_Nest;
2326   A->ops->shift                     = MatShift_Nest;
2327   A->ops->diagonalset               = MatDiagonalSet_Nest;
2328   A->ops->setrandom                 = MatSetRandom_Nest;
2329   A->ops->hasoperation              = MatHasOperation_Nest;
2330   A->ops->missingdiagonal           = MatMissingDiagonal_Nest;
2331 
2332   A->spptr     = NULL;
2333   A->assembled = PETSC_FALSE;
2334 
2335   /* expose Nest api's */
2336   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest));
2337   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest));
2338   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest));
2339   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest));
2340   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest));
2341   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest));
2342   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest));
2343   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest));
2344   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ));
2345   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ));
2346   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ));
2347   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS));
2348   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense));
2349   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense));
2350   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense));
2351   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense));
2352 
2353   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST));
2354   PetscFunctionReturn(PETSC_SUCCESS);
2355 }
2356