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