xref: /petsc/src/mat/impls/sbaij/seq/sbaij.c (revision 8e010fa18d00c25e58c23165efbc8aef665b8a2c)
1 
2 /*
3     Defines the basic matrix operations for the SBAIJ (compressed row)
4   matrix storage format.
5 */
6 #include <../src/mat/impls/baij/seq/baij.h> /*I "petscmat.h" I*/
7 #include <../src/mat/impls/sbaij/seq/sbaij.h>
8 #include <petscblaslapack.h>
9 
10 #include <../src/mat/impls/sbaij/seq/relax.h>
11 #define USESHORT
12 #include <../src/mat/impls/sbaij/seq/relax.h>
13 
14 /* defines MatSetValues_Seq_Hash(), MatAssemblyEnd_Seq_Hash(), MatSetUp_Seq_Hash() */
15 #define TYPE SBAIJ
16 #define TYPE_SBAIJ
17 #define TYPE_BS
18 #include "../src/mat/impls/aij/seq/seqhashmatsetvalues.h"
19 #undef TYPE_BS
20 #define TYPE_BS _BS
21 #define TYPE_BS_ON
22 #include "../src/mat/impls/aij/seq/seqhashmatsetvalues.h"
23 #undef TYPE_BS
24 #undef TYPE_SBAIJ
25 #include "../src/mat/impls/aij/seq/seqhashmat.h"
26 #undef TYPE
27 #undef TYPE_BS_ON
28 
29 #if defined(PETSC_HAVE_ELEMENTAL)
30 PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_Elemental(Mat, MatType, MatReuse, Mat *);
31 #endif
32 #if defined(PETSC_HAVE_SCALAPACK)
33 PETSC_INTERN PetscErrorCode MatConvert_SBAIJ_ScaLAPACK(Mat, MatType, MatReuse, Mat *);
34 #endif
35 PETSC_INTERN PetscErrorCode MatConvert_MPISBAIJ_Basic(Mat, MatType, MatReuse, Mat *);
36 
37 /*
38      Checks for missing diagonals
39 */
40 static PetscErrorCode MatMissingDiagonal_SeqSBAIJ(Mat A, PetscBool *missing, PetscInt *dd)
41 {
42   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
43   PetscInt     *diag, *ii = a->i, i;
44 
45   PetscFunctionBegin;
46   PetscCall(MatMarkDiagonal_SeqSBAIJ(A));
47   *missing = PETSC_FALSE;
48   if (A->rmap->n > 0 && !ii) {
49     *missing = PETSC_TRUE;
50     if (dd) *dd = 0;
51     PetscCall(PetscInfo(A, "Matrix has no entries therefore is missing diagonal\n"));
52   } else {
53     diag = a->diag;
54     for (i = 0; i < a->mbs; i++) {
55       if (diag[i] >= ii[i + 1]) {
56         *missing = PETSC_TRUE;
57         if (dd) *dd = i;
58         break;
59       }
60     }
61   }
62   PetscFunctionReturn(PETSC_SUCCESS);
63 }
64 
65 PetscErrorCode MatMarkDiagonal_SeqSBAIJ(Mat A)
66 {
67   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
68   PetscInt      i, j;
69 
70   PetscFunctionBegin;
71   if (!a->diag) {
72     PetscCall(PetscMalloc1(a->mbs, &a->diag));
73     a->free_diag = PETSC_TRUE;
74   }
75   for (i = 0; i < a->mbs; i++) {
76     a->diag[i] = a->i[i + 1];
77     for (j = a->i[i]; j < a->i[i + 1]; j++) {
78       if (a->j[j] == i) {
79         a->diag[i] = j;
80         break;
81       }
82     }
83   }
84   PetscFunctionReturn(PETSC_SUCCESS);
85 }
86 
87 static PetscErrorCode MatGetRowIJ_SeqSBAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool blockcompressed, PetscInt *nn, const PetscInt *inia[], const PetscInt *inja[], PetscBool *done)
88 {
89   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
90   PetscInt      i, j, n = a->mbs, nz = a->i[n], *tia, *tja, bs = A->rmap->bs, k, l, cnt;
91   PetscInt    **ia = (PetscInt **)inia, **ja = (PetscInt **)inja;
92 
93   PetscFunctionBegin;
94   *nn = n;
95   if (!ia) PetscFunctionReturn(PETSC_SUCCESS);
96   if (symmetric) {
97     PetscCall(MatToSymmetricIJ_SeqAIJ(n, a->i, a->j, PETSC_FALSE, 0, 0, &tia, &tja));
98     nz = tia[n];
99   } else {
100     tia = a->i;
101     tja = a->j;
102   }
103 
104   if (!blockcompressed && bs > 1) {
105     (*nn) *= bs;
106     /* malloc & create the natural set of indices */
107     PetscCall(PetscMalloc1((n + 1) * bs, ia));
108     if (n) {
109       (*ia)[0] = oshift;
110       for (j = 1; j < bs; j++) (*ia)[j] = (tia[1] - tia[0]) * bs + (*ia)[j - 1];
111     }
112 
113     for (i = 1; i < n; i++) {
114       (*ia)[i * bs] = (tia[i] - tia[i - 1]) * bs + (*ia)[i * bs - 1];
115       for (j = 1; j < bs; j++) (*ia)[i * bs + j] = (tia[i + 1] - tia[i]) * bs + (*ia)[i * bs + j - 1];
116     }
117     if (n) (*ia)[n * bs] = (tia[n] - tia[n - 1]) * bs + (*ia)[n * bs - 1];
118 
119     if (inja) {
120       PetscCall(PetscMalloc1(nz * bs * bs, ja));
121       cnt = 0;
122       for (i = 0; i < n; i++) {
123         for (j = 0; j < bs; j++) {
124           for (k = tia[i]; k < tia[i + 1]; k++) {
125             for (l = 0; l < bs; l++) (*ja)[cnt++] = bs * tja[k] + l;
126           }
127         }
128       }
129     }
130 
131     if (symmetric) { /* deallocate memory allocated in MatToSymmetricIJ_SeqAIJ() */
132       PetscCall(PetscFree(tia));
133       PetscCall(PetscFree(tja));
134     }
135   } else if (oshift == 1) {
136     if (symmetric) {
137       nz = tia[A->rmap->n / bs];
138       /*  add 1 to i and j indices */
139       for (i = 0; i < A->rmap->n / bs + 1; i++) tia[i] = tia[i] + 1;
140       *ia = tia;
141       if (ja) {
142         for (i = 0; i < nz; i++) tja[i] = tja[i] + 1;
143         *ja = tja;
144       }
145     } else {
146       nz = a->i[A->rmap->n / bs];
147       /* malloc space and  add 1 to i and j indices */
148       PetscCall(PetscMalloc1(A->rmap->n / bs + 1, ia));
149       for (i = 0; i < A->rmap->n / bs + 1; i++) (*ia)[i] = a->i[i] + 1;
150       if (ja) {
151         PetscCall(PetscMalloc1(nz, ja));
152         for (i = 0; i < nz; i++) (*ja)[i] = a->j[i] + 1;
153       }
154     }
155   } else {
156     *ia = tia;
157     if (ja) *ja = tja;
158   }
159   PetscFunctionReturn(PETSC_SUCCESS);
160 }
161 
162 static PetscErrorCode MatRestoreRowIJ_SeqSBAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool blockcompressed, PetscInt *nn, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
163 {
164   PetscFunctionBegin;
165   if (!ia) PetscFunctionReturn(PETSC_SUCCESS);
166   if ((!blockcompressed && A->rmap->bs > 1) || (symmetric || oshift == 1)) {
167     PetscCall(PetscFree(*ia));
168     if (ja) PetscCall(PetscFree(*ja));
169   }
170   PetscFunctionReturn(PETSC_SUCCESS);
171 }
172 
173 PetscErrorCode MatDestroy_SeqSBAIJ(Mat A)
174 {
175   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
176 
177   PetscFunctionBegin;
178   if (A->hash_active) {
179     PetscInt bs;
180     A->ops[0] = a->cops;
181     PetscCall(PetscHMapIJVDestroy(&a->ht));
182     PetscCall(MatGetBlockSize(A, &bs));
183     if (bs > 1) PetscCall(PetscHSetIJDestroy(&a->bht));
184     PetscCall(PetscFree(a->dnz));
185     PetscCall(PetscFree(a->bdnz));
186     A->hash_active = PETSC_FALSE;
187   }
188   PetscCall(PetscLogObjectState((PetscObject)A, "Rows=%" PetscInt_FMT ", NZ=%" PetscInt_FMT, A->rmap->N, a->nz));
189   PetscCall(MatSeqXAIJFreeAIJ(A, &a->a, &a->j, &a->i));
190   if (a->free_diag) PetscCall(PetscFree(a->diag));
191   PetscCall(ISDestroy(&a->row));
192   PetscCall(ISDestroy(&a->col));
193   PetscCall(ISDestroy(&a->icol));
194   PetscCall(PetscFree(a->idiag));
195   PetscCall(PetscFree(a->inode.size));
196   if (a->free_imax_ilen) PetscCall(PetscFree2(a->imax, a->ilen));
197   PetscCall(PetscFree(a->solve_work));
198   PetscCall(PetscFree(a->sor_work));
199   PetscCall(PetscFree(a->solves_work));
200   PetscCall(PetscFree(a->mult_work));
201   PetscCall(PetscFree(a->saved_values));
202   if (a->free_jshort) PetscCall(PetscFree(a->jshort));
203   PetscCall(PetscFree(a->inew));
204   PetscCall(MatDestroy(&a->parent));
205   PetscCall(PetscFree(A->data));
206 
207   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
208   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqSBAIJGetArray_C", NULL));
209   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqSBAIJRestoreArray_C", NULL));
210   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatStoreValues_C", NULL));
211   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatRetrieveValues_C", NULL));
212   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqSBAIJSetColumnIndices_C", NULL));
213   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqsbaij_seqaij_C", NULL));
214   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqsbaij_seqbaij_C", NULL));
215   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqSBAIJSetPreallocation_C", NULL));
216   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqSBAIJSetPreallocationCSR_C", NULL));
217 #if defined(PETSC_HAVE_ELEMENTAL)
218   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqsbaij_elemental_C", NULL));
219 #endif
220 #if defined(PETSC_HAVE_SCALAPACK)
221   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqsbaij_scalapack_C", NULL));
222 #endif
223   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatFactorGetSolverType_C", NULL));
224   PetscFunctionReturn(PETSC_SUCCESS);
225 }
226 
227 static PetscErrorCode MatSetOption_SeqSBAIJ(Mat A, MatOption op, PetscBool flg)
228 {
229   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
230 #if defined(PETSC_USE_COMPLEX)
231   PetscInt bs;
232 #endif
233 
234   PetscFunctionBegin;
235 #if defined(PETSC_USE_COMPLEX)
236   PetscCall(MatGetBlockSize(A, &bs));
237 #endif
238   switch (op) {
239   case MAT_ROW_ORIENTED:
240     a->roworiented = flg;
241     break;
242   case MAT_KEEP_NONZERO_PATTERN:
243     a->keepnonzeropattern = flg;
244     break;
245   case MAT_NEW_NONZERO_LOCATIONS:
246     a->nonew = (flg ? 0 : 1);
247     break;
248   case MAT_NEW_NONZERO_LOCATION_ERR:
249     a->nonew = (flg ? -1 : 0);
250     break;
251   case MAT_NEW_NONZERO_ALLOCATION_ERR:
252     a->nonew = (flg ? -2 : 0);
253     break;
254   case MAT_UNUSED_NONZERO_LOCATION_ERR:
255     a->nounused = (flg ? -1 : 0);
256     break;
257   case MAT_FORCE_DIAGONAL_ENTRIES:
258   case MAT_IGNORE_OFF_PROC_ENTRIES:
259   case MAT_USE_HASH_TABLE:
260   case MAT_SORTED_FULL:
261     PetscCall(PetscInfo(A, "Option %s ignored\n", MatOptions[op]));
262     break;
263   case MAT_HERMITIAN:
264 #if defined(PETSC_USE_COMPLEX)
265     if (flg) { /* disable transpose ops */
266       PetscCheck(bs <= 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for Hermitian with block size greater than 1");
267       A->ops->multtranspose    = NULL;
268       A->ops->multtransposeadd = NULL;
269       A->symmetric             = PETSC_BOOL3_FALSE;
270     }
271 #endif
272     break;
273   case MAT_SYMMETRIC:
274   case MAT_SPD:
275 #if defined(PETSC_USE_COMPLEX)
276     if (flg) { /* An hermitian and symmetric matrix has zero imaginary part (restore back transpose ops) */
277       A->ops->multtranspose    = A->ops->mult;
278       A->ops->multtransposeadd = A->ops->multadd;
279     }
280 #endif
281     break;
282     /* These options are handled directly by MatSetOption() */
283   case MAT_STRUCTURALLY_SYMMETRIC:
284   case MAT_SYMMETRY_ETERNAL:
285   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
286   case MAT_STRUCTURE_ONLY:
287   case MAT_SPD_ETERNAL:
288     /* These options are handled directly by MatSetOption() */
289     break;
290   case MAT_IGNORE_LOWER_TRIANGULAR:
291     a->ignore_ltriangular = flg;
292     break;
293   case MAT_ERROR_LOWER_TRIANGULAR:
294     a->ignore_ltriangular = flg;
295     break;
296   case MAT_GETROW_UPPERTRIANGULAR:
297     a->getrow_utriangular = flg;
298     break;
299   case MAT_SUBMAT_SINGLEIS:
300     break;
301   default:
302     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "unknown option %d", op);
303   }
304   PetscFunctionReturn(PETSC_SUCCESS);
305 }
306 
307 PetscErrorCode MatGetRow_SeqSBAIJ(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v)
308 {
309   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
310 
311   PetscFunctionBegin;
312   PetscCheck(!A || a->getrow_utriangular, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatGetRow is not supported for SBAIJ matrix format. Getting the upper triangular part of row, run with -mat_getrow_uppertriangular, call MatSetOption(mat,MAT_GETROW_UPPERTRIANGULAR,PETSC_TRUE) or MatGetRowUpperTriangular()");
313 
314   /* Get the upper triangular part of the row */
315   PetscCall(MatGetRow_SeqBAIJ_private(A, row, nz, idx, v, a->i, a->j, a->a));
316   PetscFunctionReturn(PETSC_SUCCESS);
317 }
318 
319 PetscErrorCode MatRestoreRow_SeqSBAIJ(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v)
320 {
321   PetscFunctionBegin;
322   if (nz) *nz = 0;
323   if (idx) PetscCall(PetscFree(*idx));
324   if (v) PetscCall(PetscFree(*v));
325   PetscFunctionReturn(PETSC_SUCCESS);
326 }
327 
328 static PetscErrorCode MatGetRowUpperTriangular_SeqSBAIJ(Mat A)
329 {
330   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
331 
332   PetscFunctionBegin;
333   a->getrow_utriangular = PETSC_TRUE;
334   PetscFunctionReturn(PETSC_SUCCESS);
335 }
336 
337 static PetscErrorCode MatRestoreRowUpperTriangular_SeqSBAIJ(Mat A)
338 {
339   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
340 
341   PetscFunctionBegin;
342   a->getrow_utriangular = PETSC_FALSE;
343   PetscFunctionReturn(PETSC_SUCCESS);
344 }
345 
346 static PetscErrorCode MatTranspose_SeqSBAIJ(Mat A, MatReuse reuse, Mat *B)
347 {
348   PetscFunctionBegin;
349   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
350   if (reuse == MAT_INITIAL_MATRIX) {
351     PetscCall(MatDuplicate(A, MAT_COPY_VALUES, B));
352   } else if (reuse == MAT_REUSE_MATRIX) {
353     PetscCall(MatCopy(A, *B, SAME_NONZERO_PATTERN));
354   }
355   PetscFunctionReturn(PETSC_SUCCESS);
356 }
357 
358 static PetscErrorCode MatView_SeqSBAIJ_ASCII(Mat A, PetscViewer viewer)
359 {
360   Mat_SeqSBAIJ     *a = (Mat_SeqSBAIJ *)A->data;
361   PetscInt          i, j, bs = A->rmap->bs, k, l, bs2 = a->bs2;
362   PetscViewerFormat format;
363   PetscInt         *diag;
364   const char       *matname;
365 
366   PetscFunctionBegin;
367   PetscCall(PetscViewerGetFormat(viewer, &format));
368   if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
369     PetscCall(PetscViewerASCIIPrintf(viewer, "  block size is %" PetscInt_FMT "\n", bs));
370   } else if (format == PETSC_VIEWER_ASCII_MATLAB) {
371     Mat aij;
372 
373     if (A->factortype && bs > 1) {
374       PetscCall(PetscPrintf(PETSC_COMM_SELF, "Warning: matrix is factored with bs>1. MatView() with PETSC_VIEWER_ASCII_MATLAB is not supported and ignored!\n"));
375       PetscFunctionReturn(PETSC_SUCCESS);
376     }
377     PetscCall(MatConvert(A, MATSEQAIJ, MAT_INITIAL_MATRIX, &aij));
378     if (((PetscObject)A)->name) PetscCall(PetscObjectGetName((PetscObject)A, &matname));
379     if (((PetscObject)A)->name) PetscCall(PetscObjectSetName((PetscObject)aij, matname));
380     PetscCall(MatView_SeqAIJ(aij, viewer));
381     PetscCall(MatDestroy(&aij));
382   } else if (format == PETSC_VIEWER_ASCII_COMMON) {
383     Mat B;
384 
385     PetscCall(MatConvert(A, MATSEQAIJ, MAT_INITIAL_MATRIX, &B));
386     if (((PetscObject)A)->name) PetscCall(PetscObjectGetName((PetscObject)A, &matname));
387     if (((PetscObject)A)->name) PetscCall(PetscObjectSetName((PetscObject)B, matname));
388     PetscCall(MatView_SeqAIJ(B, viewer));
389     PetscCall(MatDestroy(&B));
390   } else if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
391     PetscFunctionReturn(PETSC_SUCCESS);
392   } else {
393     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
394     if (A->factortype) { /* for factored matrix */
395       PetscCheck(bs <= 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "matrix is factored with bs>1. Not implemented yet");
396 
397       diag = a->diag;
398       for (i = 0; i < a->mbs; i++) { /* for row block i */
399         PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i));
400         /* diagonal entry */
401 #if defined(PETSC_USE_COMPLEX)
402         if (PetscImaginaryPart(a->a[diag[i]]) > 0.0) {
403           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i) ", a->j[diag[i]], (double)PetscRealPart(1.0 / a->a[diag[i]]), (double)PetscImaginaryPart(1.0 / a->a[diag[i]])));
404         } else if (PetscImaginaryPart(a->a[diag[i]]) < 0.0) {
405           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i) ", a->j[diag[i]], (double)PetscRealPart(1.0 / a->a[diag[i]]), -(double)PetscImaginaryPart(1.0 / a->a[diag[i]])));
406         } else {
407           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[diag[i]], (double)PetscRealPart(1.0 / a->a[diag[i]])));
408         }
409 #else
410         PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[diag[i]], (double)(1.0 / a->a[diag[i]])));
411 #endif
412         /* off-diagonal entries */
413         for (k = a->i[i]; k < a->i[i + 1] - 1; k++) {
414 #if defined(PETSC_USE_COMPLEX)
415           if (PetscImaginaryPart(a->a[k]) > 0.0) {
416             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i) ", bs * a->j[k], (double)PetscRealPart(a->a[k]), (double)PetscImaginaryPart(a->a[k])));
417           } else if (PetscImaginaryPart(a->a[k]) < 0.0) {
418             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i) ", bs * a->j[k], (double)PetscRealPart(a->a[k]), -(double)PetscImaginaryPart(a->a[k])));
419           } else {
420             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", bs * a->j[k], (double)PetscRealPart(a->a[k])));
421           }
422 #else
423           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[k], (double)a->a[k]));
424 #endif
425         }
426         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
427       }
428 
429     } else {                         /* for non-factored matrix */
430       for (i = 0; i < a->mbs; i++) { /* for row block i */
431         for (j = 0; j < bs; j++) {   /* for row bs*i + j */
432           PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i * bs + j));
433           for (k = a->i[i]; k < a->i[i + 1]; k++) { /* for column block */
434             for (l = 0; l < bs; l++) {              /* for column */
435 #if defined(PETSC_USE_COMPLEX)
436               if (PetscImaginaryPart(a->a[bs2 * k + l * bs + j]) > 0.0) {
437                 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i) ", bs * a->j[k] + l, (double)PetscRealPart(a->a[bs2 * k + l * bs + j]), (double)PetscImaginaryPart(a->a[bs2 * k + l * bs + j])));
438               } else if (PetscImaginaryPart(a->a[bs2 * k + l * bs + j]) < 0.0) {
439                 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i) ", bs * a->j[k] + l, (double)PetscRealPart(a->a[bs2 * k + l * bs + j]), -(double)PetscImaginaryPart(a->a[bs2 * k + l * bs + j])));
440               } else {
441                 PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", bs * a->j[k] + l, (double)PetscRealPart(a->a[bs2 * k + l * bs + j])));
442               }
443 #else
444               PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", bs * a->j[k] + l, (double)a->a[bs2 * k + l * bs + j]));
445 #endif
446             }
447           }
448           PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
449         }
450       }
451     }
452     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
453   }
454   PetscCall(PetscViewerFlush(viewer));
455   PetscFunctionReturn(PETSC_SUCCESS);
456 }
457 
458 #include <petscdraw.h>
459 static PetscErrorCode MatView_SeqSBAIJ_Draw_Zoom(PetscDraw draw, void *Aa)
460 {
461   Mat           A = (Mat)Aa;
462   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
463   PetscInt      row, i, j, k, l, mbs = a->mbs, color, bs = A->rmap->bs, bs2 = a->bs2;
464   PetscReal     xl, yl, xr, yr, x_l, x_r, y_l, y_r;
465   MatScalar    *aa;
466   PetscViewer   viewer;
467 
468   PetscFunctionBegin;
469   PetscCall(PetscObjectQuery((PetscObject)A, "Zoomviewer", (PetscObject *)&viewer));
470   PetscCall(PetscDrawGetCoordinates(draw, &xl, &yl, &xr, &yr));
471 
472   /* loop over matrix elements drawing boxes */
473 
474   PetscDrawCollectiveBegin(draw);
475   PetscCall(PetscDrawString(draw, .3 * (xl + xr), .3 * (yl + yr), PETSC_DRAW_BLACK, "symmetric"));
476   /* Blue for negative, Cyan for zero and  Red for positive */
477   color = PETSC_DRAW_BLUE;
478   for (i = 0, row = 0; i < mbs; i++, row += bs) {
479     for (j = a->i[i]; j < a->i[i + 1]; j++) {
480       y_l = A->rmap->N - row - 1.0;
481       y_r = y_l + 1.0;
482       x_l = a->j[j] * bs;
483       x_r = x_l + 1.0;
484       aa  = a->a + j * bs2;
485       for (k = 0; k < bs; k++) {
486         for (l = 0; l < bs; l++) {
487           if (PetscRealPart(*aa++) >= 0.) continue;
488           PetscCall(PetscDrawRectangle(draw, x_l + k, y_l - l, x_r + k, y_r - l, color, color, color, color));
489         }
490       }
491     }
492   }
493   color = PETSC_DRAW_CYAN;
494   for (i = 0, row = 0; i < mbs; i++, row += bs) {
495     for (j = a->i[i]; j < a->i[i + 1]; j++) {
496       y_l = A->rmap->N - row - 1.0;
497       y_r = y_l + 1.0;
498       x_l = a->j[j] * bs;
499       x_r = x_l + 1.0;
500       aa  = a->a + j * bs2;
501       for (k = 0; k < bs; k++) {
502         for (l = 0; l < bs; l++) {
503           if (PetscRealPart(*aa++) != 0.) continue;
504           PetscCall(PetscDrawRectangle(draw, x_l + k, y_l - l, x_r + k, y_r - l, color, color, color, color));
505         }
506       }
507     }
508   }
509   color = PETSC_DRAW_RED;
510   for (i = 0, row = 0; i < mbs; i++, row += bs) {
511     for (j = a->i[i]; j < a->i[i + 1]; j++) {
512       y_l = A->rmap->N - row - 1.0;
513       y_r = y_l + 1.0;
514       x_l = a->j[j] * bs;
515       x_r = x_l + 1.0;
516       aa  = a->a + j * bs2;
517       for (k = 0; k < bs; k++) {
518         for (l = 0; l < bs; l++) {
519           if (PetscRealPart(*aa++) <= 0.) continue;
520           PetscCall(PetscDrawRectangle(draw, x_l + k, y_l - l, x_r + k, y_r - l, color, color, color, color));
521         }
522       }
523     }
524   }
525   PetscDrawCollectiveEnd(draw);
526   PetscFunctionReturn(PETSC_SUCCESS);
527 }
528 
529 static PetscErrorCode MatView_SeqSBAIJ_Draw(Mat A, PetscViewer viewer)
530 {
531   PetscReal xl, yl, xr, yr, w, h;
532   PetscDraw draw;
533   PetscBool isnull;
534 
535   PetscFunctionBegin;
536   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
537   PetscCall(PetscDrawIsNull(draw, &isnull));
538   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
539 
540   xr = A->rmap->N;
541   yr = A->rmap->N;
542   h  = yr / 10.0;
543   w  = xr / 10.0;
544   xr += w;
545   yr += h;
546   xl = -w;
547   yl = -h;
548   PetscCall(PetscDrawSetCoordinates(draw, xl, yl, xr, yr));
549   PetscCall(PetscObjectCompose((PetscObject)A, "Zoomviewer", (PetscObject)viewer));
550   PetscCall(PetscDrawZoom(draw, MatView_SeqSBAIJ_Draw_Zoom, A));
551   PetscCall(PetscObjectCompose((PetscObject)A, "Zoomviewer", NULL));
552   PetscCall(PetscDrawSave(draw));
553   PetscFunctionReturn(PETSC_SUCCESS);
554 }
555 
556 /* Used for both MPIBAIJ and MPISBAIJ matrices */
557 #define MatView_SeqSBAIJ_Binary MatView_SeqBAIJ_Binary
558 
559 PetscErrorCode MatView_SeqSBAIJ(Mat A, PetscViewer viewer)
560 {
561   PetscBool iascii, isbinary, isdraw;
562 
563   PetscFunctionBegin;
564   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
565   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
566   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
567   if (iascii) {
568     PetscCall(MatView_SeqSBAIJ_ASCII(A, viewer));
569   } else if (isbinary) {
570     PetscCall(MatView_SeqSBAIJ_Binary(A, viewer));
571   } else if (isdraw) {
572     PetscCall(MatView_SeqSBAIJ_Draw(A, viewer));
573   } else {
574     Mat         B;
575     const char *matname;
576     PetscCall(MatConvert(A, MATSEQAIJ, MAT_INITIAL_MATRIX, &B));
577     if (((PetscObject)A)->name) PetscCall(PetscObjectGetName((PetscObject)A, &matname));
578     if (((PetscObject)A)->name) PetscCall(PetscObjectSetName((PetscObject)B, matname));
579     PetscCall(MatView(B, viewer));
580     PetscCall(MatDestroy(&B));
581   }
582   PetscFunctionReturn(PETSC_SUCCESS);
583 }
584 
585 PetscErrorCode MatGetValues_SeqSBAIJ(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], PetscScalar v[])
586 {
587   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
588   PetscInt     *rp, k, low, high, t, row, nrow, i, col, l, *aj = a->j;
589   PetscInt     *ai = a->i, *ailen = a->ilen;
590   PetscInt      brow, bcol, ridx, cidx, bs = A->rmap->bs, bs2 = a->bs2;
591   MatScalar    *ap, *aa = a->a;
592 
593   PetscFunctionBegin;
594   for (k = 0; k < m; k++) { /* loop over rows */
595     row  = im[k];
596     brow = row / bs;
597     if (row < 0) {
598       v += n;
599       continue;
600     } /* negative row */
601     PetscCheck(row < A->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, row, A->rmap->N - 1);
602     rp   = aj + ai[brow];
603     ap   = aa + bs2 * ai[brow];
604     nrow = ailen[brow];
605     for (l = 0; l < n; l++) { /* loop over columns */
606       if (in[l] < 0) {
607         v++;
608         continue;
609       } /* negative column */
610       PetscCheck(in[l] < A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, in[l], A->cmap->n - 1);
611       col  = in[l];
612       bcol = col / bs;
613       cidx = col % bs;
614       ridx = row % bs;
615       high = nrow;
616       low  = 0; /* assume unsorted */
617       while (high - low > 5) {
618         t = (low + high) / 2;
619         if (rp[t] > bcol) high = t;
620         else low = t;
621       }
622       for (i = low; i < high; i++) {
623         if (rp[i] > bcol) break;
624         if (rp[i] == bcol) {
625           *v++ = ap[bs2 * i + bs * cidx + ridx];
626           goto finished;
627         }
628       }
629       *v++ = 0.0;
630     finished:;
631     }
632   }
633   PetscFunctionReturn(PETSC_SUCCESS);
634 }
635 
636 static PetscErrorCode MatPermute_SeqSBAIJ(Mat A, IS rowp, IS colp, Mat *B)
637 {
638   Mat C;
639 
640   PetscFunctionBegin;
641   PetscCall(MatConvert(A, MATSEQBAIJ, MAT_INITIAL_MATRIX, &C));
642   PetscCall(MatPermute(C, rowp, colp, B));
643   PetscCall(MatDestroy(&C));
644   if (rowp == colp) PetscCall(MatConvert(*B, MATSEQSBAIJ, MAT_INPLACE_MATRIX, B));
645   PetscFunctionReturn(PETSC_SUCCESS);
646 }
647 
648 PetscErrorCode MatSetValuesBlocked_SeqSBAIJ(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is)
649 {
650   Mat_SeqSBAIJ      *a = (Mat_SeqSBAIJ *)A->data;
651   PetscInt          *rp, k, low, high, t, ii, jj, row, nrow, i, col, l, rmax, N, lastcol = -1;
652   PetscInt          *imax = a->imax, *ai = a->i, *ailen = a->ilen;
653   PetscInt          *aj = a->j, nonew = a->nonew, bs2 = a->bs2, bs = A->rmap->bs, stepval;
654   PetscBool          roworiented = a->roworiented;
655   const PetscScalar *value       = v;
656   MatScalar         *ap, *aa = a->a, *bap;
657 
658   PetscFunctionBegin;
659   if (roworiented) stepval = (n - 1) * bs;
660   else stepval = (m - 1) * bs;
661 
662   for (k = 0; k < m; k++) { /* loop over added rows */
663     row = im[k];
664     if (row < 0) continue;
665     PetscCheck(row < a->mbs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Block index row too large %" PetscInt_FMT " max %" PetscInt_FMT, row, a->mbs - 1);
666     rp   = aj + ai[row];
667     ap   = aa + bs2 * ai[row];
668     rmax = imax[row];
669     nrow = ailen[row];
670     low  = 0;
671     high = nrow;
672     for (l = 0; l < n; l++) { /* loop over added columns */
673       if (in[l] < 0) continue;
674       col = in[l];
675       PetscCheck(col < a->nbs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Block index column too large %" PetscInt_FMT " max %" PetscInt_FMT, col, a->nbs - 1);
676       if (col < row) {
677         if (a->ignore_ltriangular) continue; /* ignore lower triangular block */
678         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_USER, "Lower triangular value cannot be set for sbaij format. Ignoring these values, run with -mat_ignore_lower_triangular or call MatSetOption(mat,MAT_IGNORE_LOWER_TRIANGULAR,PETSC_TRUE)");
679       }
680       if (roworiented) value = v + k * (stepval + bs) * bs + l * bs;
681       else value = v + l * (stepval + bs) * bs + k * bs;
682 
683       if (col <= lastcol) low = 0;
684       else high = nrow;
685 
686       lastcol = col;
687       while (high - low > 7) {
688         t = (low + high) / 2;
689         if (rp[t] > col) high = t;
690         else low = t;
691       }
692       for (i = low; i < high; i++) {
693         if (rp[i] > col) break;
694         if (rp[i] == col) {
695           bap = ap + bs2 * i;
696           if (roworiented) {
697             if (is == ADD_VALUES) {
698               for (ii = 0; ii < bs; ii++, value += stepval) {
699                 for (jj = ii; jj < bs2; jj += bs) bap[jj] += *value++;
700               }
701             } else {
702               for (ii = 0; ii < bs; ii++, value += stepval) {
703                 for (jj = ii; jj < bs2; jj += bs) bap[jj] = *value++;
704               }
705             }
706           } else {
707             if (is == ADD_VALUES) {
708               for (ii = 0; ii < bs; ii++, value += stepval) {
709                 for (jj = 0; jj < bs; jj++) *bap++ += *value++;
710               }
711             } else {
712               for (ii = 0; ii < bs; ii++, value += stepval) {
713                 for (jj = 0; jj < bs; jj++) *bap++ = *value++;
714               }
715             }
716           }
717           goto noinsert2;
718         }
719       }
720       if (nonew == 1) goto noinsert2;
721       PetscCheck(nonew != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new block index nonzero block (%" PetscInt_FMT ", %" PetscInt_FMT ") in the matrix", row, col);
722       MatSeqXAIJReallocateAIJ(A, a->mbs, bs2, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar);
723       N = nrow++ - 1;
724       high++;
725       /* shift up all the later entries in this row */
726       PetscCall(PetscArraymove(rp + i + 1, rp + i, N - i + 1));
727       PetscCall(PetscArraymove(ap + bs2 * (i + 1), ap + bs2 * i, bs2 * (N - i + 1)));
728       PetscCall(PetscArrayzero(ap + bs2 * i, bs2));
729       rp[i] = col;
730       bap   = ap + bs2 * i;
731       if (roworiented) {
732         for (ii = 0; ii < bs; ii++, value += stepval) {
733           for (jj = ii; jj < bs2; jj += bs) bap[jj] = *value++;
734         }
735       } else {
736         for (ii = 0; ii < bs; ii++, value += stepval) {
737           for (jj = 0; jj < bs; jj++) *bap++ = *value++;
738         }
739       }
740     noinsert2:;
741       low = i;
742     }
743     ailen[row] = nrow;
744   }
745   PetscFunctionReturn(PETSC_SUCCESS);
746 }
747 
748 static PetscErrorCode MatAssemblyEnd_SeqSBAIJ(Mat A, MatAssemblyType mode)
749 {
750   Mat_SeqSBAIJ *a      = (Mat_SeqSBAIJ *)A->data;
751   PetscInt      fshift = 0, i, *ai = a->i, *aj = a->j, *imax = a->imax;
752   PetscInt      m = A->rmap->N, *ip, N, *ailen = a->ilen;
753   PetscInt      mbs = a->mbs, bs2 = a->bs2, rmax = 0;
754   MatScalar    *aa = a->a, *ap;
755 
756   PetscFunctionBegin;
757   if (mode == MAT_FLUSH_ASSEMBLY || (A->was_assembled && A->ass_nonzerostate == A->nonzerostate)) PetscFunctionReturn(PETSC_SUCCESS);
758 
759   if (m) rmax = ailen[0];
760   for (i = 1; i < mbs; i++) {
761     /* move each row back by the amount of empty slots (fshift) before it*/
762     fshift += imax[i - 1] - ailen[i - 1];
763     rmax = PetscMax(rmax, ailen[i]);
764     if (fshift) {
765       ip = aj + ai[i];
766       ap = aa + bs2 * ai[i];
767       N  = ailen[i];
768       PetscCall(PetscArraymove(ip - fshift, ip, N));
769       PetscCall(PetscArraymove(ap - bs2 * fshift, ap, bs2 * N));
770     }
771     ai[i] = ai[i - 1] + ailen[i - 1];
772   }
773   if (mbs) {
774     fshift += imax[mbs - 1] - ailen[mbs - 1];
775     ai[mbs] = ai[mbs - 1] + ailen[mbs - 1];
776   }
777   /* reset ilen and imax for each row */
778   for (i = 0; i < mbs; i++) ailen[i] = imax[i] = ai[i + 1] - ai[i];
779   a->nz = ai[mbs];
780 
781   /* diagonals may have moved, reset it */
782   if (a->diag) PetscCall(PetscArraycpy(a->diag, ai, mbs));
783   PetscCheck(!fshift || a->nounused != -1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unused space detected in matrix: %" PetscInt_FMT " X %" PetscInt_FMT " block size %" PetscInt_FMT ", %" PetscInt_FMT " unneeded", m, A->cmap->n, A->rmap->bs, fshift * bs2);
784 
785   PetscCall(PetscInfo(A, "Matrix size: %" PetscInt_FMT " X %" PetscInt_FMT ", block size %" PetscInt_FMT "; storage space: %" PetscInt_FMT " unneeded, %" PetscInt_FMT " used\n", m, A->rmap->N, A->rmap->bs, fshift * bs2, a->nz * bs2));
786   PetscCall(PetscInfo(A, "Number of mallocs during MatSetValues is %" PetscInt_FMT "\n", a->reallocs));
787   PetscCall(PetscInfo(A, "Most nonzeros blocks in any row is %" PetscInt_FMT "\n", rmax));
788 
789   A->info.mallocs += a->reallocs;
790   a->reallocs         = 0;
791   A->info.nz_unneeded = (PetscReal)fshift * bs2;
792   a->idiagvalid       = PETSC_FALSE;
793   a->rmax             = rmax;
794 
795   if (A->cmap->n < 65536 && A->cmap->bs == 1) {
796     if (a->jshort && a->free_jshort) {
797       /* when matrix data structure is changed, previous jshort must be replaced */
798       PetscCall(PetscFree(a->jshort));
799     }
800     PetscCall(PetscMalloc1(a->i[A->rmap->n], &a->jshort));
801     for (i = 0; i < a->i[A->rmap->n]; i++) a->jshort[i] = a->j[i];
802     A->ops->mult   = MatMult_SeqSBAIJ_1_ushort;
803     A->ops->sor    = MatSOR_SeqSBAIJ_ushort;
804     a->free_jshort = PETSC_TRUE;
805   }
806   PetscFunctionReturn(PETSC_SUCCESS);
807 }
808 
809 /* Only add/insert a(i,j) with i<=j (blocks).
810    Any a(i,j) with i>j input by user is ignored.
811 */
812 
813 PetscErrorCode MatSetValues_SeqSBAIJ(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is)
814 {
815   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
816   PetscInt     *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N, lastcol = -1;
817   PetscInt     *imax = a->imax, *ai = a->i, *ailen = a->ilen, roworiented = a->roworiented;
818   PetscInt     *aj = a->j, nonew = a->nonew, bs = A->rmap->bs, brow, bcol;
819   PetscInt      ridx, cidx, bs2                 = a->bs2;
820   MatScalar    *ap, value, *aa                  = a->a, *bap;
821 
822   PetscFunctionBegin;
823   for (k = 0; k < m; k++) { /* loop over added rows */
824     row  = im[k];           /* row number */
825     brow = row / bs;        /* block row number */
826     if (row < 0) continue;
827     PetscCheck(row < A->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, row, A->rmap->N - 1);
828     rp   = aj + ai[brow];       /*ptr to beginning of column value of the row block*/
829     ap   = aa + bs2 * ai[brow]; /*ptr to beginning of element value of the row block*/
830     rmax = imax[brow];          /* maximum space allocated for this row */
831     nrow = ailen[brow];         /* actual length of this row */
832     low  = 0;
833     high = nrow;
834     for (l = 0; l < n; l++) { /* loop over added columns */
835       if (in[l] < 0) continue;
836       PetscCheck(in[l] < A->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, in[l], A->cmap->N - 1);
837       col  = in[l];
838       bcol = col / bs; /* block col number */
839 
840       if (brow > bcol) {
841         if (a->ignore_ltriangular) continue; /* ignore lower triangular values */
842         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_USER, "Lower triangular value cannot be set for sbaij format. Ignoring these values, run with -mat_ignore_lower_triangular or call MatSetOption(mat,MAT_IGNORE_LOWER_TRIANGULAR,PETSC_TRUE)");
843       }
844 
845       ridx = row % bs;
846       cidx = col % bs; /*row and col index inside the block */
847       if ((brow == bcol && ridx <= cidx) || (brow < bcol)) {
848         /* element value a(k,l) */
849         if (roworiented) value = v[l + k * n];
850         else value = v[k + l * m];
851 
852         /* move pointer bap to a(k,l) quickly and add/insert value */
853         if (col <= lastcol) low = 0;
854         else high = nrow;
855 
856         lastcol = col;
857         while (high - low > 7) {
858           t = (low + high) / 2;
859           if (rp[t] > bcol) high = t;
860           else low = t;
861         }
862         for (i = low; i < high; i++) {
863           if (rp[i] > bcol) break;
864           if (rp[i] == bcol) {
865             bap = ap + bs2 * i + bs * cidx + ridx;
866             if (is == ADD_VALUES) *bap += value;
867             else *bap = value;
868             /* for diag block, add/insert its symmetric element a(cidx,ridx) */
869             if (brow == bcol && ridx < cidx) {
870               bap = ap + bs2 * i + bs * ridx + cidx;
871               if (is == ADD_VALUES) *bap += value;
872               else *bap = value;
873             }
874             goto noinsert1;
875           }
876         }
877 
878         if (nonew == 1) goto noinsert1;
879         PetscCheck(nonew != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero (%" PetscInt_FMT ", %" PetscInt_FMT ") in the matrix", row, col);
880         MatSeqXAIJReallocateAIJ(A, a->mbs, bs2, nrow, brow, bcol, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar);
881 
882         N = nrow++ - 1;
883         high++;
884         /* shift up all the later entries in this row */
885         PetscCall(PetscArraymove(rp + i + 1, rp + i, N - i + 1));
886         PetscCall(PetscArraymove(ap + bs2 * (i + 1), ap + bs2 * i, bs2 * (N - i + 1)));
887         PetscCall(PetscArrayzero(ap + bs2 * i, bs2));
888         rp[i]                          = bcol;
889         ap[bs2 * i + bs * cidx + ridx] = value;
890         /* for diag block, add/insert its symmetric element a(cidx,ridx) */
891         if (brow == bcol && ridx < cidx) ap[bs2 * i + bs * ridx + cidx] = value;
892         A->nonzerostate++;
893       noinsert1:;
894         low = i;
895       }
896     } /* end of loop over added columns */
897     ailen[brow] = nrow;
898   } /* end of loop over added rows */
899   PetscFunctionReturn(PETSC_SUCCESS);
900 }
901 
902 static PetscErrorCode MatICCFactor_SeqSBAIJ(Mat inA, IS row, const MatFactorInfo *info)
903 {
904   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)inA->data;
905   Mat           outA;
906   PetscBool     row_identity;
907 
908   PetscFunctionBegin;
909   PetscCheck(info->levels == 0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only levels=0 is supported for in-place icc");
910   PetscCall(ISIdentity(row, &row_identity));
911   PetscCheck(row_identity, PETSC_COMM_SELF, PETSC_ERR_SUP, "Matrix reordering is not supported");
912   PetscCheck(inA->rmap->bs == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Matrix block size %" PetscInt_FMT " is not supported", inA->rmap->bs); /* Need to replace MatCholeskyFactorSymbolic_SeqSBAIJ_MSR()! */
913 
914   outA            = inA;
915   inA->factortype = MAT_FACTOR_ICC;
916   PetscCall(PetscFree(inA->solvertype));
917   PetscCall(PetscStrallocpy(MATSOLVERPETSC, &inA->solvertype));
918 
919   PetscCall(MatMarkDiagonal_SeqSBAIJ(inA));
920   PetscCall(MatSeqSBAIJSetNumericFactorization_inplace(inA, row_identity));
921 
922   PetscCall(PetscObjectReference((PetscObject)row));
923   PetscCall(ISDestroy(&a->row));
924   a->row = row;
925   PetscCall(PetscObjectReference((PetscObject)row));
926   PetscCall(ISDestroy(&a->col));
927   a->col = row;
928 
929   /* Create the invert permutation so that it can be used in MatCholeskyFactorNumeric() */
930   if (a->icol) PetscCall(ISInvertPermutation(row, PETSC_DECIDE, &a->icol));
931 
932   if (!a->solve_work) PetscCall(PetscMalloc1(inA->rmap->N + inA->rmap->bs, &a->solve_work));
933 
934   PetscCall(MatCholeskyFactorNumeric(outA, inA, info));
935   PetscFunctionReturn(PETSC_SUCCESS);
936 }
937 
938 static PetscErrorCode MatSeqSBAIJSetColumnIndices_SeqSBAIJ(Mat mat, PetscInt *indices)
939 {
940   Mat_SeqSBAIJ *baij = (Mat_SeqSBAIJ *)mat->data;
941   PetscInt      i, nz, n;
942 
943   PetscFunctionBegin;
944   nz = baij->maxnz;
945   n  = mat->cmap->n;
946   for (i = 0; i < nz; i++) baij->j[i] = indices[i];
947 
948   baij->nz = nz;
949   for (i = 0; i < n; i++) baij->ilen[i] = baij->imax[i];
950 
951   PetscCall(MatSetOption(mat, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE));
952   PetscFunctionReturn(PETSC_SUCCESS);
953 }
954 
955 /*@
956   MatSeqSBAIJSetColumnIndices - Set the column indices for all the rows
957   in a `MATSEQSBAIJ` matrix.
958 
959   Input Parameters:
960 + mat     - the `MATSEQSBAIJ` matrix
961 - indices - the column indices
962 
963   Level: advanced
964 
965   Notes:
966   This can be called if you have precomputed the nonzero structure of the
967   matrix and want to provide it to the matrix object to improve the performance
968   of the `MatSetValues()` operation.
969 
970   You MUST have set the correct numbers of nonzeros per row in the call to
971   `MatCreateSeqSBAIJ()`, and the columns indices MUST be sorted.
972 
973   MUST be called before any calls to `MatSetValues()`
974 
975 .seealso: [](ch_matrices), `Mat`, `MATSEQSBAIJ`, `MatCreateSeqSBAIJ`
976 @*/
977 PetscErrorCode MatSeqSBAIJSetColumnIndices(Mat mat, PetscInt *indices)
978 {
979   PetscFunctionBegin;
980   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
981   PetscAssertPointer(indices, 2);
982   PetscUseMethod(mat, "MatSeqSBAIJSetColumnIndices_C", (Mat, PetscInt *), (mat, indices));
983   PetscFunctionReturn(PETSC_SUCCESS);
984 }
985 
986 static PetscErrorCode MatCopy_SeqSBAIJ(Mat A, Mat B, MatStructure str)
987 {
988   PetscBool isbaij;
989 
990   PetscFunctionBegin;
991   PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &isbaij, MATSEQSBAIJ, MATMPISBAIJ, ""));
992   PetscCheck(isbaij, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)B)->type_name);
993   /* If the two matrices have the same copy implementation and nonzero pattern, use fast copy. */
994   if (str == SAME_NONZERO_PATTERN && A->ops->copy == B->ops->copy) {
995     Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
996     Mat_SeqSBAIJ *b = (Mat_SeqSBAIJ *)B->data;
997 
998     PetscCheck(a->i[a->mbs] == b->i[b->mbs], PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of nonzeros in two matrices are different");
999     PetscCheck(a->mbs == b->mbs, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of rows in two matrices are different");
1000     PetscCheck(a->bs2 == b->bs2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Different block size");
1001     PetscCall(PetscArraycpy(b->a, a->a, a->bs2 * a->i[a->mbs]));
1002     PetscCall(PetscObjectStateIncrease((PetscObject)B));
1003   } else {
1004     PetscCall(MatGetRowUpperTriangular(A));
1005     PetscCall(MatCopy_Basic(A, B, str));
1006     PetscCall(MatRestoreRowUpperTriangular(A));
1007   }
1008   PetscFunctionReturn(PETSC_SUCCESS);
1009 }
1010 
1011 static PetscErrorCode MatSeqSBAIJGetArray_SeqSBAIJ(Mat A, PetscScalar *array[])
1012 {
1013   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
1014 
1015   PetscFunctionBegin;
1016   *array = a->a;
1017   PetscFunctionReturn(PETSC_SUCCESS);
1018 }
1019 
1020 static PetscErrorCode MatSeqSBAIJRestoreArray_SeqSBAIJ(Mat A, PetscScalar *array[])
1021 {
1022   PetscFunctionBegin;
1023   *array = NULL;
1024   PetscFunctionReturn(PETSC_SUCCESS);
1025 }
1026 
1027 PetscErrorCode MatAXPYGetPreallocation_SeqSBAIJ(Mat Y, Mat X, PetscInt *nnz)
1028 {
1029   PetscInt      bs = Y->rmap->bs, mbs = Y->rmap->N / bs;
1030   Mat_SeqSBAIJ *x = (Mat_SeqSBAIJ *)X->data;
1031   Mat_SeqSBAIJ *y = (Mat_SeqSBAIJ *)Y->data;
1032 
1033   PetscFunctionBegin;
1034   /* Set the number of nonzeros in the new matrix */
1035   PetscCall(MatAXPYGetPreallocation_SeqX_private(mbs, x->i, x->j, y->i, y->j, nnz));
1036   PetscFunctionReturn(PETSC_SUCCESS);
1037 }
1038 
1039 static PetscErrorCode MatAXPY_SeqSBAIJ(Mat Y, PetscScalar a, Mat X, MatStructure str)
1040 {
1041   Mat_SeqSBAIJ *x = (Mat_SeqSBAIJ *)X->data, *y = (Mat_SeqSBAIJ *)Y->data;
1042   PetscInt      bs = Y->rmap->bs, bs2 = bs * bs;
1043   PetscBLASInt  one = 1;
1044 
1045   PetscFunctionBegin;
1046   if (str == UNKNOWN_NONZERO_PATTERN || (PetscDefined(USE_DEBUG) && str == SAME_NONZERO_PATTERN)) {
1047     PetscBool e = x->nz == y->nz && x->mbs == y->mbs ? PETSC_TRUE : PETSC_FALSE;
1048     if (e) {
1049       PetscCall(PetscArraycmp(x->i, y->i, x->mbs + 1, &e));
1050       if (e) {
1051         PetscCall(PetscArraycmp(x->j, y->j, x->i[x->mbs], &e));
1052         if (e) str = SAME_NONZERO_PATTERN;
1053       }
1054     }
1055     if (!e) PetscCheck(str != SAME_NONZERO_PATTERN, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatStructure is not SAME_NONZERO_PATTERN");
1056   }
1057   if (str == SAME_NONZERO_PATTERN) {
1058     PetscScalar  alpha = a;
1059     PetscBLASInt bnz;
1060     PetscCall(PetscBLASIntCast(x->nz * bs2, &bnz));
1061     PetscCallBLAS("BLASaxpy", BLASaxpy_(&bnz, &alpha, x->a, &one, y->a, &one));
1062     PetscCall(PetscObjectStateIncrease((PetscObject)Y));
1063   } else if (str == SUBSET_NONZERO_PATTERN) { /* nonzeros of X is a subset of Y's */
1064     PetscCall(MatSetOption(X, MAT_GETROW_UPPERTRIANGULAR, PETSC_TRUE));
1065     PetscCall(MatAXPY_Basic(Y, a, X, str));
1066     PetscCall(MatSetOption(X, MAT_GETROW_UPPERTRIANGULAR, PETSC_FALSE));
1067   } else {
1068     Mat       B;
1069     PetscInt *nnz;
1070     PetscCheck(bs == X->rmap->bs, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Matrices must have same block size");
1071     PetscCall(MatGetRowUpperTriangular(X));
1072     PetscCall(MatGetRowUpperTriangular(Y));
1073     PetscCall(PetscMalloc1(Y->rmap->N, &nnz));
1074     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &B));
1075     PetscCall(PetscObjectSetName((PetscObject)B, ((PetscObject)Y)->name));
1076     PetscCall(MatSetSizes(B, Y->rmap->n, Y->cmap->n, Y->rmap->N, Y->cmap->N));
1077     PetscCall(MatSetBlockSizesFromMats(B, Y, Y));
1078     PetscCall(MatSetType(B, ((PetscObject)Y)->type_name));
1079     PetscCall(MatAXPYGetPreallocation_SeqSBAIJ(Y, X, nnz));
1080     PetscCall(MatSeqSBAIJSetPreallocation(B, bs, 0, nnz));
1081 
1082     PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str));
1083 
1084     PetscCall(MatHeaderMerge(Y, &B));
1085     PetscCall(PetscFree(nnz));
1086     PetscCall(MatRestoreRowUpperTriangular(X));
1087     PetscCall(MatRestoreRowUpperTriangular(Y));
1088   }
1089   PetscFunctionReturn(PETSC_SUCCESS);
1090 }
1091 
1092 static PetscErrorCode MatIsSymmetric_SeqSBAIJ(Mat A, PetscReal tol, PetscBool *flg)
1093 {
1094   PetscFunctionBegin;
1095   *flg = PETSC_TRUE;
1096   PetscFunctionReturn(PETSC_SUCCESS);
1097 }
1098 
1099 static PetscErrorCode MatIsStructurallySymmetric_SeqSBAIJ(Mat A, PetscBool *flg)
1100 {
1101   PetscFunctionBegin;
1102   *flg = PETSC_TRUE;
1103   PetscFunctionReturn(PETSC_SUCCESS);
1104 }
1105 
1106 static PetscErrorCode MatIsHermitian_SeqSBAIJ(Mat A, PetscReal tol, PetscBool *flg)
1107 {
1108   PetscFunctionBegin;
1109   *flg = PETSC_FALSE;
1110   PetscFunctionReturn(PETSC_SUCCESS);
1111 }
1112 
1113 static PetscErrorCode MatConjugate_SeqSBAIJ(Mat A)
1114 {
1115 #if defined(PETSC_USE_COMPLEX)
1116   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
1117   PetscInt      i, nz = a->bs2 * a->i[a->mbs];
1118   MatScalar    *aa = a->a;
1119 
1120   PetscFunctionBegin;
1121   for (i = 0; i < nz; i++) aa[i] = PetscConj(aa[i]);
1122 #else
1123   PetscFunctionBegin;
1124 #endif
1125   PetscFunctionReturn(PETSC_SUCCESS);
1126 }
1127 
1128 static PetscErrorCode MatRealPart_SeqSBAIJ(Mat A)
1129 {
1130   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
1131   PetscInt      i, nz = a->bs2 * a->i[a->mbs];
1132   MatScalar    *aa = a->a;
1133 
1134   PetscFunctionBegin;
1135   for (i = 0; i < nz; i++) aa[i] = PetscRealPart(aa[i]);
1136   PetscFunctionReturn(PETSC_SUCCESS);
1137 }
1138 
1139 static PetscErrorCode MatImaginaryPart_SeqSBAIJ(Mat A)
1140 {
1141   Mat_SeqSBAIJ *a = (Mat_SeqSBAIJ *)A->data;
1142   PetscInt      i, nz = a->bs2 * a->i[a->mbs];
1143   MatScalar    *aa = a->a;
1144 
1145   PetscFunctionBegin;
1146   for (i = 0; i < nz; i++) aa[i] = PetscImaginaryPart(aa[i]);
1147   PetscFunctionReturn(PETSC_SUCCESS);
1148 }
1149 
1150 static PetscErrorCode MatZeroRowsColumns_SeqSBAIJ(Mat A, PetscInt is_n, const PetscInt is_idx[], PetscScalar diag, Vec x, Vec b)
1151 {
1152   Mat_SeqSBAIJ      *baij = (Mat_SeqSBAIJ *)A->data;
1153   PetscInt           i, j, k, count;
1154   PetscInt           bs = A->rmap->bs, bs2 = baij->bs2, row, col;
1155   PetscScalar        zero = 0.0;
1156   MatScalar         *aa;
1157   const PetscScalar *xx;
1158   PetscScalar       *bb;
1159   PetscBool         *zeroed, vecs = PETSC_FALSE;
1160 
1161   PetscFunctionBegin;
1162   /* fix right hand side if needed */
1163   if (x && b) {
1164     PetscCall(VecGetArrayRead(x, &xx));
1165     PetscCall(VecGetArray(b, &bb));
1166     vecs = PETSC_TRUE;
1167   }
1168 
1169   /* zero the columns */
1170   PetscCall(PetscCalloc1(A->rmap->n, &zeroed));
1171   for (i = 0; i < is_n; i++) {
1172     PetscCheck(is_idx[i] >= 0 && is_idx[i] < A->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", is_idx[i]);
1173     zeroed[is_idx[i]] = PETSC_TRUE;
1174   }
1175   if (vecs) {
1176     for (i = 0; i < A->rmap->N; i++) {
1177       row = i / bs;
1178       for (j = baij->i[row]; j < baij->i[row + 1]; j++) {
1179         for (k = 0; k < bs; k++) {
1180           col = bs * baij->j[j] + k;
1181           if (col <= i) continue;
1182           aa = ((MatScalar *)(baij->a)) + j * bs2 + (i % bs) + bs * k;
1183           if (!zeroed[i] && zeroed[col]) bb[i] -= aa[0] * xx[col];
1184           if (zeroed[i] && !zeroed[col]) bb[col] -= aa[0] * xx[i];
1185         }
1186       }
1187     }
1188     for (i = 0; i < is_n; i++) bb[is_idx[i]] = diag * xx[is_idx[i]];
1189   }
1190 
1191   for (i = 0; i < A->rmap->N; i++) {
1192     if (!zeroed[i]) {
1193       row = i / bs;
1194       for (j = baij->i[row]; j < baij->i[row + 1]; j++) {
1195         for (k = 0; k < bs; k++) {
1196           col = bs * baij->j[j] + k;
1197           if (zeroed[col]) {
1198             aa    = ((MatScalar *)(baij->a)) + j * bs2 + (i % bs) + bs * k;
1199             aa[0] = 0.0;
1200           }
1201         }
1202       }
1203     }
1204   }
1205   PetscCall(PetscFree(zeroed));
1206   if (vecs) {
1207     PetscCall(VecRestoreArrayRead(x, &xx));
1208     PetscCall(VecRestoreArray(b, &bb));
1209   }
1210 
1211   /* zero the rows */
1212   for (i = 0; i < is_n; i++) {
1213     row   = is_idx[i];
1214     count = (baij->i[row / bs + 1] - baij->i[row / bs]) * bs;
1215     aa    = ((MatScalar *)(baij->a)) + baij->i[row / bs] * bs2 + (row % bs);
1216     for (k = 0; k < count; k++) {
1217       aa[0] = zero;
1218       aa += bs;
1219     }
1220     if (diag != 0.0) PetscUseTypeMethod(A, setvalues, 1, &row, 1, &row, &diag, INSERT_VALUES);
1221   }
1222   PetscCall(MatAssemblyEnd_SeqSBAIJ(A, MAT_FINAL_ASSEMBLY));
1223   PetscFunctionReturn(PETSC_SUCCESS);
1224 }
1225 
1226 static PetscErrorCode MatShift_SeqSBAIJ(Mat Y, PetscScalar a)
1227 {
1228   Mat_SeqSBAIJ *aij = (Mat_SeqSBAIJ *)Y->data;
1229 
1230   PetscFunctionBegin;
1231   if (!Y->preallocated || !aij->nz) PetscCall(MatSeqSBAIJSetPreallocation(Y, Y->rmap->bs, 1, NULL));
1232   PetscCall(MatShift_Basic(Y, a));
1233   PetscFunctionReturn(PETSC_SUCCESS);
1234 }
1235 
1236 PetscErrorCode MatEliminateZeros_SeqSBAIJ(Mat A, PetscBool keep)
1237 {
1238   Mat_SeqSBAIJ *a      = (Mat_SeqSBAIJ *)A->data;
1239   PetscInt      fshift = 0, fshift_prev = 0, i, *ai = a->i, *aj = a->j, *imax = a->imax, j, k;
1240   PetscInt      m = A->rmap->N, *ailen = a->ilen;
1241   PetscInt      mbs = a->mbs, bs2 = a->bs2, rmax = 0;
1242   MatScalar    *aa = a->a, *ap;
1243   PetscBool     zero;
1244 
1245   PetscFunctionBegin;
1246   PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot eliminate zeros for unassembled matrix");
1247   if (m) rmax = ailen[0];
1248   for (i = 1; i <= mbs; i++) {
1249     for (k = ai[i - 1]; k < ai[i]; k++) {
1250       zero = PETSC_TRUE;
1251       ap   = aa + bs2 * k;
1252       for (j = 0; j < bs2 && zero; j++) {
1253         if (ap[j] != 0.0) zero = PETSC_FALSE;
1254       }
1255       if (zero && (aj[k] != i - 1 || !keep)) fshift++;
1256       else {
1257         if (zero && aj[k] == i - 1) PetscCall(PetscInfo(A, "Keep the diagonal block at row %" PetscInt_FMT "\n", i - 1));
1258         aj[k - fshift] = aj[k];
1259         PetscCall(PetscArraymove(ap - bs2 * fshift, ap, bs2));
1260       }
1261     }
1262     ai[i - 1] -= fshift_prev;
1263     fshift_prev  = fshift;
1264     ailen[i - 1] = imax[i - 1] = ai[i] - fshift - ai[i - 1];
1265     a->nonzerorowcnt += ((ai[i] - fshift - ai[i - 1]) > 0);
1266     rmax = PetscMax(rmax, ailen[i - 1]);
1267   }
1268   if (fshift) {
1269     if (mbs) {
1270       ai[mbs] -= fshift;
1271       a->nz = ai[mbs];
1272     }
1273     PetscCall(PetscInfo(A, "Matrix size: %" PetscInt_FMT " X %" PetscInt_FMT "; zeros eliminated: %" PetscInt_FMT "; nonzeros left: %" PetscInt_FMT "\n", m, A->cmap->n, fshift, a->nz));
1274     A->nonzerostate++;
1275     A->info.nz_unneeded += (PetscReal)fshift;
1276     a->rmax = rmax;
1277     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1278     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1279   }
1280   PetscFunctionReturn(PETSC_SUCCESS);
1281 }
1282 
1283 static struct _MatOps MatOps_Values = {MatSetValues_SeqSBAIJ,
1284                                        MatGetRow_SeqSBAIJ,
1285                                        MatRestoreRow_SeqSBAIJ,
1286                                        MatMult_SeqSBAIJ_N,
1287                                        /*  4*/ MatMultAdd_SeqSBAIJ_N,
1288                                        MatMult_SeqSBAIJ_N, /* transpose versions are same as non-transpose versions */
1289                                        MatMultAdd_SeqSBAIJ_N,
1290                                        NULL,
1291                                        NULL,
1292                                        NULL,
1293                                        /* 10*/ NULL,
1294                                        NULL,
1295                                        MatCholeskyFactor_SeqSBAIJ,
1296                                        MatSOR_SeqSBAIJ,
1297                                        MatTranspose_SeqSBAIJ,
1298                                        /* 15*/ MatGetInfo_SeqSBAIJ,
1299                                        MatEqual_SeqSBAIJ,
1300                                        MatGetDiagonal_SeqSBAIJ,
1301                                        MatDiagonalScale_SeqSBAIJ,
1302                                        MatNorm_SeqSBAIJ,
1303                                        /* 20*/ NULL,
1304                                        MatAssemblyEnd_SeqSBAIJ,
1305                                        MatSetOption_SeqSBAIJ,
1306                                        MatZeroEntries_SeqSBAIJ,
1307                                        /* 24*/ NULL,
1308                                        NULL,
1309                                        NULL,
1310                                        NULL,
1311                                        NULL,
1312                                        /* 29*/ MatSetUp_Seq_Hash,
1313                                        NULL,
1314                                        NULL,
1315                                        NULL,
1316                                        NULL,
1317                                        /* 34*/ MatDuplicate_SeqSBAIJ,
1318                                        NULL,
1319                                        NULL,
1320                                        NULL,
1321                                        MatICCFactor_SeqSBAIJ,
1322                                        /* 39*/ MatAXPY_SeqSBAIJ,
1323                                        MatCreateSubMatrices_SeqSBAIJ,
1324                                        MatIncreaseOverlap_SeqSBAIJ,
1325                                        MatGetValues_SeqSBAIJ,
1326                                        MatCopy_SeqSBAIJ,
1327                                        /* 44*/ NULL,
1328                                        MatScale_SeqSBAIJ,
1329                                        MatShift_SeqSBAIJ,
1330                                        NULL,
1331                                        MatZeroRowsColumns_SeqSBAIJ,
1332                                        /* 49*/ NULL,
1333                                        MatGetRowIJ_SeqSBAIJ,
1334                                        MatRestoreRowIJ_SeqSBAIJ,
1335                                        NULL,
1336                                        NULL,
1337                                        /* 54*/ NULL,
1338                                        NULL,
1339                                        NULL,
1340                                        MatPermute_SeqSBAIJ,
1341                                        MatSetValuesBlocked_SeqSBAIJ,
1342                                        /* 59*/ MatCreateSubMatrix_SeqSBAIJ,
1343                                        NULL,
1344                                        NULL,
1345                                        NULL,
1346                                        NULL,
1347                                        /* 64*/ NULL,
1348                                        NULL,
1349                                        NULL,
1350                                        NULL,
1351                                        NULL,
1352                                        /* 69*/ MatGetRowMaxAbs_SeqSBAIJ,
1353                                        NULL,
1354                                        MatConvert_MPISBAIJ_Basic,
1355                                        NULL,
1356                                        NULL,
1357                                        /* 74*/ NULL,
1358                                        NULL,
1359                                        NULL,
1360                                        NULL,
1361                                        NULL,
1362                                        /* 79*/ NULL,
1363                                        NULL,
1364                                        NULL,
1365                                        MatGetInertia_SeqSBAIJ,
1366                                        MatLoad_SeqSBAIJ,
1367                                        /* 84*/ MatIsSymmetric_SeqSBAIJ,
1368                                        MatIsHermitian_SeqSBAIJ,
1369                                        MatIsStructurallySymmetric_SeqSBAIJ,
1370                                        NULL,
1371                                        NULL,
1372                                        /* 89*/ NULL,
1373                                        NULL,
1374                                        NULL,
1375                                        NULL,
1376                                        NULL,
1377                                        /* 94*/ NULL,
1378                                        NULL,
1379                                        NULL,
1380                                        NULL,
1381                                        NULL,
1382                                        /* 99*/ NULL,
1383                                        NULL,
1384                                        NULL,
1385                                        MatConjugate_SeqSBAIJ,
1386                                        NULL,
1387                                        /*104*/ NULL,
1388                                        MatRealPart_SeqSBAIJ,
1389                                        MatImaginaryPart_SeqSBAIJ,
1390                                        MatGetRowUpperTriangular_SeqSBAIJ,
1391                                        MatRestoreRowUpperTriangular_SeqSBAIJ,
1392                                        /*109*/ NULL,
1393                                        NULL,
1394                                        NULL,
1395                                        NULL,
1396                                        MatMissingDiagonal_SeqSBAIJ,
1397                                        /*114*/ NULL,
1398                                        NULL,
1399                                        NULL,
1400                                        NULL,
1401                                        NULL,
1402                                        /*119*/ NULL,
1403                                        NULL,
1404                                        NULL,
1405                                        NULL,
1406                                        NULL,
1407                                        /*124*/ NULL,
1408                                        NULL,
1409                                        NULL,
1410                                        NULL,
1411                                        NULL,
1412                                        /*129*/ NULL,
1413                                        NULL,
1414                                        NULL,
1415                                        NULL,
1416                                        NULL,
1417                                        /*134*/ NULL,
1418                                        NULL,
1419                                        NULL,
1420                                        NULL,
1421                                        NULL,
1422                                        /*139*/ MatSetBlockSizes_Default,
1423                                        NULL,
1424                                        NULL,
1425                                        NULL,
1426                                        NULL,
1427                                        /*144*/ MatCreateMPIMatConcatenateSeqMat_SeqSBAIJ,
1428                                        NULL,
1429                                        NULL,
1430                                        NULL,
1431                                        NULL,
1432                                        NULL,
1433                                        /*150*/ NULL,
1434                                        MatEliminateZeros_SeqSBAIJ};
1435 
1436 static PetscErrorCode MatStoreValues_SeqSBAIJ(Mat mat)
1437 {
1438   Mat_SeqSBAIJ *aij = (Mat_SeqSBAIJ *)mat->data;
1439   PetscInt      nz  = aij->i[mat->rmap->N] * mat->rmap->bs * aij->bs2;
1440 
1441   PetscFunctionBegin;
1442   PetscCheck(aij->nonew == 1, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first");
1443 
1444   /* allocate space for values if not already there */
1445   if (!aij->saved_values) PetscCall(PetscMalloc1(nz + 1, &aij->saved_values));
1446 
1447   /* copy values over */
1448   PetscCall(PetscArraycpy(aij->saved_values, aij->a, nz));
1449   PetscFunctionReturn(PETSC_SUCCESS);
1450 }
1451 
1452 static PetscErrorCode MatRetrieveValues_SeqSBAIJ(Mat mat)
1453 {
1454   Mat_SeqSBAIJ *aij = (Mat_SeqSBAIJ *)mat->data;
1455   PetscInt      nz  = aij->i[mat->rmap->N] * mat->rmap->bs * aij->bs2;
1456 
1457   PetscFunctionBegin;
1458   PetscCheck(aij->nonew == 1, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first");
1459   PetscCheck(aij->saved_values, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatStoreValues(A);first");
1460 
1461   /* copy values over */
1462   PetscCall(PetscArraycpy(aij->a, aij->saved_values, nz));
1463   PetscFunctionReturn(PETSC_SUCCESS);
1464 }
1465 
1466 static PetscErrorCode MatSeqSBAIJSetPreallocation_SeqSBAIJ(Mat B, PetscInt bs, PetscInt nz, PetscInt *nnz)
1467 {
1468   Mat_SeqSBAIJ *b = (Mat_SeqSBAIJ *)B->data;
1469   PetscInt      i, mbs, nbs, bs2;
1470   PetscBool     skipallocation = PETSC_FALSE, flg = PETSC_FALSE, realalloc = PETSC_FALSE;
1471 
1472   PetscFunctionBegin;
1473   if (B->hash_active) {
1474     PetscInt bs;
1475     B->ops[0] = b->cops;
1476     PetscCall(PetscHMapIJVDestroy(&b->ht));
1477     PetscCall(MatGetBlockSize(B, &bs));
1478     if (bs > 1) PetscCall(PetscHSetIJDestroy(&b->bht));
1479     PetscCall(PetscFree(b->dnz));
1480     PetscCall(PetscFree(b->bdnz));
1481     B->hash_active = PETSC_FALSE;
1482   }
1483   if (nz >= 0 || nnz) realalloc = PETSC_TRUE;
1484 
1485   PetscCall(MatSetBlockSize(B, PetscAbs(bs)));
1486   PetscCall(PetscLayoutSetUp(B->rmap));
1487   PetscCall(PetscLayoutSetUp(B->cmap));
1488   PetscCheck(B->rmap->N <= B->cmap->N, PETSC_COMM_SELF, PETSC_ERR_SUP, "SEQSBAIJ matrix cannot have more rows %" PetscInt_FMT " than columns %" PetscInt_FMT, B->rmap->N, B->cmap->N);
1489   PetscCall(PetscLayoutGetBlockSize(B->rmap, &bs));
1490 
1491   B->preallocated = PETSC_TRUE;
1492 
1493   mbs = B->rmap->N / bs;
1494   nbs = B->cmap->n / bs;
1495   bs2 = bs * bs;
1496 
1497   PetscCheck(mbs * bs == B->rmap->N && nbs * bs == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number rows, cols must be divisible by blocksize");
1498 
1499   if (nz == MAT_SKIP_ALLOCATION) {
1500     skipallocation = PETSC_TRUE;
1501     nz             = 0;
1502   }
1503 
1504   if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 3;
1505   PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nz cannot be less than 0: value %" PetscInt_FMT, nz);
1506   if (nnz) {
1507     for (i = 0; i < mbs; i++) {
1508       PetscCheck(nnz[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nnz cannot be less than 0: local row %" PetscInt_FMT " value %" PetscInt_FMT, i, nnz[i]);
1509       PetscCheck(nnz[i] <= nbs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nnz cannot be greater than block row length: local row %" PetscInt_FMT " value %" PetscInt_FMT " block rowlength %" PetscInt_FMT, i, nnz[i], nbs);
1510     }
1511   }
1512 
1513   B->ops->mult             = MatMult_SeqSBAIJ_N;
1514   B->ops->multadd          = MatMultAdd_SeqSBAIJ_N;
1515   B->ops->multtranspose    = MatMult_SeqSBAIJ_N;
1516   B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_N;
1517 
1518   PetscCall(PetscOptionsGetBool(((PetscObject)B)->options, ((PetscObject)B)->prefix, "-mat_no_unroll", &flg, NULL));
1519   if (!flg) {
1520     switch (bs) {
1521     case 1:
1522       B->ops->mult             = MatMult_SeqSBAIJ_1;
1523       B->ops->multadd          = MatMultAdd_SeqSBAIJ_1;
1524       B->ops->multtranspose    = MatMult_SeqSBAIJ_1;
1525       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_1;
1526       break;
1527     case 2:
1528       B->ops->mult             = MatMult_SeqSBAIJ_2;
1529       B->ops->multadd          = MatMultAdd_SeqSBAIJ_2;
1530       B->ops->multtranspose    = MatMult_SeqSBAIJ_2;
1531       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_2;
1532       break;
1533     case 3:
1534       B->ops->mult             = MatMult_SeqSBAIJ_3;
1535       B->ops->multadd          = MatMultAdd_SeqSBAIJ_3;
1536       B->ops->multtranspose    = MatMult_SeqSBAIJ_3;
1537       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_3;
1538       break;
1539     case 4:
1540       B->ops->mult             = MatMult_SeqSBAIJ_4;
1541       B->ops->multadd          = MatMultAdd_SeqSBAIJ_4;
1542       B->ops->multtranspose    = MatMult_SeqSBAIJ_4;
1543       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_4;
1544       break;
1545     case 5:
1546       B->ops->mult             = MatMult_SeqSBAIJ_5;
1547       B->ops->multadd          = MatMultAdd_SeqSBAIJ_5;
1548       B->ops->multtranspose    = MatMult_SeqSBAIJ_5;
1549       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_5;
1550       break;
1551     case 6:
1552       B->ops->mult             = MatMult_SeqSBAIJ_6;
1553       B->ops->multadd          = MatMultAdd_SeqSBAIJ_6;
1554       B->ops->multtranspose    = MatMult_SeqSBAIJ_6;
1555       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_6;
1556       break;
1557     case 7:
1558       B->ops->mult             = MatMult_SeqSBAIJ_7;
1559       B->ops->multadd          = MatMultAdd_SeqSBAIJ_7;
1560       B->ops->multtranspose    = MatMult_SeqSBAIJ_7;
1561       B->ops->multtransposeadd = MatMultAdd_SeqSBAIJ_7;
1562       break;
1563     }
1564   }
1565 
1566   b->mbs = mbs;
1567   b->nbs = nbs;
1568   if (!skipallocation) {
1569     if (!b->imax) {
1570       PetscCall(PetscMalloc2(mbs, &b->imax, mbs, &b->ilen));
1571 
1572       b->free_imax_ilen = PETSC_TRUE;
1573     }
1574     if (!nnz) {
1575       if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 5;
1576       else if (nz <= 0) nz = 1;
1577       nz = PetscMin(nbs, nz);
1578       for (i = 0; i < mbs; i++) b->imax[i] = nz;
1579       PetscCall(PetscIntMultError(nz, mbs, &nz));
1580     } else {
1581       PetscInt64 nz64 = 0;
1582       for (i = 0; i < mbs; i++) {
1583         b->imax[i] = nnz[i];
1584         nz64 += nnz[i];
1585       }
1586       PetscCall(PetscIntCast(nz64, &nz));
1587     }
1588     /* b->ilen will count nonzeros in each block row so far. */
1589     for (i = 0; i < mbs; i++) b->ilen[i] = 0;
1590     /* nz=(nz+mbs)/2; */ /* total diagonal and superdiagonal nonzero blocks */
1591 
1592     /* allocate the matrix space */
1593     PetscCall(MatSeqXAIJFreeAIJ(B, &b->a, &b->j, &b->i));
1594     PetscCall(PetscMalloc3(bs2 * nz, &b->a, nz, &b->j, B->rmap->N + 1, &b->i));
1595     PetscCall(PetscArrayzero(b->a, nz * bs2));
1596     PetscCall(PetscArrayzero(b->j, nz));
1597 
1598     b->singlemalloc = PETSC_TRUE;
1599 
1600     /* pointer to beginning of each row */
1601     b->i[0] = 0;
1602     for (i = 1; i < mbs + 1; i++) b->i[i] = b->i[i - 1] + b->imax[i - 1];
1603 
1604     b->free_a  = PETSC_TRUE;
1605     b->free_ij = PETSC_TRUE;
1606   } else {
1607     b->free_a  = PETSC_FALSE;
1608     b->free_ij = PETSC_FALSE;
1609   }
1610 
1611   b->bs2     = bs2;
1612   b->nz      = 0;
1613   b->maxnz   = nz;
1614   b->inew    = NULL;
1615   b->jnew    = NULL;
1616   b->anew    = NULL;
1617   b->a2anew  = NULL;
1618   b->permute = PETSC_FALSE;
1619 
1620   B->was_assembled = PETSC_FALSE;
1621   B->assembled     = PETSC_FALSE;
1622   if (realalloc) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
1623   PetscFunctionReturn(PETSC_SUCCESS);
1624 }
1625 
1626 static PetscErrorCode MatSeqSBAIJSetPreallocationCSR_SeqSBAIJ(Mat B, PetscInt bs, const PetscInt ii[], const PetscInt jj[], const PetscScalar V[])
1627 {
1628   PetscInt     i, j, m, nz, anz, nz_max = 0, *nnz;
1629   PetscScalar *values      = NULL;
1630   PetscBool    roworiented = ((Mat_SeqSBAIJ *)B->data)->roworiented;
1631 
1632   PetscFunctionBegin;
1633   PetscCheck(bs >= 1, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_OUTOFRANGE, "Invalid block size specified, must be positive but it is %" PetscInt_FMT, bs);
1634   PetscCall(PetscLayoutSetBlockSize(B->rmap, bs));
1635   PetscCall(PetscLayoutSetBlockSize(B->cmap, bs));
1636   PetscCall(PetscLayoutSetUp(B->rmap));
1637   PetscCall(PetscLayoutSetUp(B->cmap));
1638   PetscCall(PetscLayoutGetBlockSize(B->rmap, &bs));
1639   m = B->rmap->n / bs;
1640 
1641   PetscCheck(!ii[0], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "ii[0] must be 0 but it is %" PetscInt_FMT, ii[0]);
1642   PetscCall(PetscMalloc1(m + 1, &nnz));
1643   for (i = 0; i < m; i++) {
1644     nz = ii[i + 1] - ii[i];
1645     PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row %" PetscInt_FMT " has a negative number of columns %" PetscInt_FMT, i, nz);
1646     anz = 0;
1647     for (j = 0; j < nz; j++) {
1648       /* count only values on the diagonal or above */
1649       if (jj[ii[i] + j] >= i) {
1650         anz = nz - j;
1651         break;
1652       }
1653     }
1654     nz_max = PetscMax(nz_max, anz);
1655     nnz[i] = anz;
1656   }
1657   PetscCall(MatSeqSBAIJSetPreallocation(B, bs, 0, nnz));
1658   PetscCall(PetscFree(nnz));
1659 
1660   values = (PetscScalar *)V;
1661   if (!values) PetscCall(PetscCalloc1(bs * bs * nz_max, &values));
1662   for (i = 0; i < m; i++) {
1663     PetscInt        ncols = ii[i + 1] - ii[i];
1664     const PetscInt *icols = jj + ii[i];
1665     if (!roworiented || bs == 1) {
1666       const PetscScalar *svals = values + (V ? (bs * bs * ii[i]) : 0);
1667       PetscCall(MatSetValuesBlocked_SeqSBAIJ(B, 1, &i, ncols, icols, svals, INSERT_VALUES));
1668     } else {
1669       for (j = 0; j < ncols; j++) {
1670         const PetscScalar *svals = values + (V ? (bs * bs * (ii[i] + j)) : 0);
1671         PetscCall(MatSetValuesBlocked_SeqSBAIJ(B, 1, &i, 1, &icols[j], svals, INSERT_VALUES));
1672       }
1673     }
1674   }
1675   if (!V) PetscCall(PetscFree(values));
1676   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
1677   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
1678   PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE));
1679   PetscFunctionReturn(PETSC_SUCCESS);
1680 }
1681 
1682 /*
1683    This is used to set the numeric factorization for both Cholesky and ICC symbolic factorization
1684 */
1685 PetscErrorCode MatSeqSBAIJSetNumericFactorization_inplace(Mat B, PetscBool natural)
1686 {
1687   PetscBool flg = PETSC_FALSE;
1688   PetscInt  bs  = B->rmap->bs;
1689 
1690   PetscFunctionBegin;
1691   PetscCall(PetscOptionsGetBool(((PetscObject)B)->options, ((PetscObject)B)->prefix, "-mat_no_unroll", &flg, NULL));
1692   if (flg) bs = 8;
1693 
1694   if (!natural) {
1695     switch (bs) {
1696     case 1:
1697       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_1_inplace;
1698       break;
1699     case 2:
1700       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_2;
1701       break;
1702     case 3:
1703       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_3;
1704       break;
1705     case 4:
1706       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_4;
1707       break;
1708     case 5:
1709       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_5;
1710       break;
1711     case 6:
1712       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_6;
1713       break;
1714     case 7:
1715       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_7;
1716       break;
1717     default:
1718       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_N;
1719       break;
1720     }
1721   } else {
1722     switch (bs) {
1723     case 1:
1724       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_1_NaturalOrdering_inplace;
1725       break;
1726     case 2:
1727       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_2_NaturalOrdering;
1728       break;
1729     case 3:
1730       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_3_NaturalOrdering;
1731       break;
1732     case 4:
1733       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_4_NaturalOrdering;
1734       break;
1735     case 5:
1736       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_5_NaturalOrdering;
1737       break;
1738     case 6:
1739       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_6_NaturalOrdering;
1740       break;
1741     case 7:
1742       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_7_NaturalOrdering;
1743       break;
1744     default:
1745       B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqSBAIJ_N_NaturalOrdering;
1746       break;
1747     }
1748   }
1749   PetscFunctionReturn(PETSC_SUCCESS);
1750 }
1751 
1752 PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_SeqAIJ(Mat, MatType, MatReuse, Mat *);
1753 PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_SeqBAIJ(Mat, MatType, MatReuse, Mat *);
1754 static PetscErrorCode       MatFactorGetSolverType_petsc(Mat A, MatSolverType *type)
1755 {
1756   PetscFunctionBegin;
1757   *type = MATSOLVERPETSC;
1758   PetscFunctionReturn(PETSC_SUCCESS);
1759 }
1760 
1761 PETSC_INTERN PetscErrorCode MatGetFactor_seqsbaij_petsc(Mat A, MatFactorType ftype, Mat *B)
1762 {
1763   PetscInt n = A->rmap->n;
1764 
1765   PetscFunctionBegin;
1766 #if defined(PETSC_USE_COMPLEX)
1767   if ((ftype == MAT_FACTOR_CHOLESKY || ftype == MAT_FACTOR_ICC) && A->hermitian == PETSC_BOOL3_TRUE && A->symmetric != PETSC_BOOL3_TRUE) {
1768     PetscCall(PetscInfo(A, "Hermitian MAT_FACTOR_CHOLESKY or MAT_FACTOR_ICC are not supported. Use MAT_FACTOR_LU instead.\n"));
1769     *B = NULL;
1770     PetscFunctionReturn(PETSC_SUCCESS);
1771   }
1772 #endif
1773 
1774   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
1775   PetscCall(MatSetSizes(*B, n, n, n, n));
1776   if (ftype == MAT_FACTOR_CHOLESKY || ftype == MAT_FACTOR_ICC) {
1777     PetscCall(MatSetType(*B, MATSEQSBAIJ));
1778     PetscCall(MatSeqSBAIJSetPreallocation(*B, A->rmap->bs, MAT_SKIP_ALLOCATION, NULL));
1779 
1780     (*B)->ops->choleskyfactorsymbolic = MatCholeskyFactorSymbolic_SeqSBAIJ;
1781     (*B)->ops->iccfactorsymbolic      = MatICCFactorSymbolic_SeqSBAIJ;
1782     PetscCall(PetscStrallocpy(MATORDERINGNATURAL, (char **)&(*B)->preferredordering[MAT_FACTOR_CHOLESKY]));
1783     PetscCall(PetscStrallocpy(MATORDERINGNATURAL, (char **)&(*B)->preferredordering[MAT_FACTOR_ICC]));
1784   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Factor type not supported");
1785 
1786   (*B)->factortype     = ftype;
1787   (*B)->canuseordering = PETSC_TRUE;
1788   PetscCall(PetscFree((*B)->solvertype));
1789   PetscCall(PetscStrallocpy(MATSOLVERPETSC, &(*B)->solvertype));
1790   PetscCall(PetscObjectComposeFunction((PetscObject)*B, "MatFactorGetSolverType_C", MatFactorGetSolverType_petsc));
1791   PetscFunctionReturn(PETSC_SUCCESS);
1792 }
1793 
1794 /*@C
1795   MatSeqSBAIJGetArray - gives access to the array where the numerical data for a `MATSEQSBAIJ` matrix is stored
1796 
1797   Not Collective
1798 
1799   Input Parameter:
1800 . A - a `MATSEQSBAIJ` matrix
1801 
1802   Output Parameter:
1803 . array - pointer to the data
1804 
1805   Level: intermediate
1806 
1807 .seealso: [](ch_matrices), `Mat`, `MATSEQSBAIJ`, `MatSeqSBAIJRestoreArray()`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArray()`
1808 @*/
1809 PetscErrorCode MatSeqSBAIJGetArray(Mat A, PetscScalar **array)
1810 {
1811   PetscFunctionBegin;
1812   PetscUseMethod(A, "MatSeqSBAIJGetArray_C", (Mat, PetscScalar **), (A, array));
1813   PetscFunctionReturn(PETSC_SUCCESS);
1814 }
1815 
1816 /*@C
1817   MatSeqSBAIJRestoreArray - returns access to the array where the numerical data for a `MATSEQSBAIJ` matrix is stored obtained by `MatSeqSBAIJGetArray()`
1818 
1819   Not Collective
1820 
1821   Input Parameters:
1822 + A     - a `MATSEQSBAIJ` matrix
1823 - array - pointer to the data
1824 
1825   Level: intermediate
1826 
1827 .seealso: [](ch_matrices), `Mat`, `MATSEQSBAIJ`, `MatSeqSBAIJGetArray()`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArray()`
1828 @*/
1829 PetscErrorCode MatSeqSBAIJRestoreArray(Mat A, PetscScalar **array)
1830 {
1831   PetscFunctionBegin;
1832   PetscUseMethod(A, "MatSeqSBAIJRestoreArray_C", (Mat, PetscScalar **), (A, array));
1833   PetscFunctionReturn(PETSC_SUCCESS);
1834 }
1835 
1836 /*MC
1837   MATSEQSBAIJ - MATSEQSBAIJ = "seqsbaij" - A matrix type to be used for sequential symmetric block sparse matrices,
1838   based on block compressed sparse row format.  Only the upper triangular portion of the matrix is stored.
1839 
1840   For complex numbers by default this matrix is symmetric, NOT Hermitian symmetric. To make it Hermitian symmetric you
1841   can call `MatSetOption`(`Mat`, `MAT_HERMITIAN`).
1842 
1843   Options Database Key:
1844   . -mat_type seqsbaij - sets the matrix type to "seqsbaij" during a call to `MatSetFromOptions()`
1845 
1846   Level: beginner
1847 
1848   Notes:
1849     By default if you insert values into the lower triangular part of the matrix they are simply ignored (since they are not
1850      stored and it is assumed they symmetric to the upper triangular). If you call `MatSetOption`(`Mat`,`MAT_IGNORE_LOWER_TRIANGULAR`,`PETSC_FALSE`) or use
1851      the options database `-mat_ignore_lower_triangular` false it will generate an error if you try to set a value in the lower triangular portion.
1852 
1853     The number of rows in the matrix must be less than or equal to the number of columns
1854 
1855 .seealso: [](ch_matrices), `Mat`, `MATSEQSBAIJ`, `MatCreateSeqSBAIJ()`, `MatType`, `MATMPISBAIJ`
1856 M*/
1857 PETSC_EXTERN PetscErrorCode MatCreate_SeqSBAIJ(Mat B)
1858 {
1859   Mat_SeqSBAIJ *b;
1860   PetscMPIInt   size;
1861   PetscBool     no_unroll = PETSC_FALSE, no_inode = PETSC_FALSE;
1862 
1863   PetscFunctionBegin;
1864   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size));
1865   PetscCheck(size <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Comm must be of size 1");
1866 
1867   PetscCall(PetscNew(&b));
1868   B->data   = (void *)b;
1869   B->ops[0] = MatOps_Values;
1870 
1871   B->ops->destroy    = MatDestroy_SeqSBAIJ;
1872   B->ops->view       = MatView_SeqSBAIJ;
1873   b->row             = NULL;
1874   b->icol            = NULL;
1875   b->reallocs        = 0;
1876   b->saved_values    = NULL;
1877   b->inode.limit     = 5;
1878   b->inode.max_limit = 5;
1879 
1880   b->roworiented        = PETSC_TRUE;
1881   b->nonew              = 0;
1882   b->diag               = NULL;
1883   b->solve_work         = NULL;
1884   b->mult_work          = NULL;
1885   B->spptr              = NULL;
1886   B->info.nz_unneeded   = (PetscReal)b->maxnz * b->bs2;
1887   b->keepnonzeropattern = PETSC_FALSE;
1888 
1889   b->inew    = NULL;
1890   b->jnew    = NULL;
1891   b->anew    = NULL;
1892   b->a2anew  = NULL;
1893   b->permute = PETSC_FALSE;
1894 
1895   b->ignore_ltriangular = PETSC_TRUE;
1896 
1897   PetscCall(PetscOptionsGetBool(((PetscObject)B)->options, ((PetscObject)B)->prefix, "-mat_ignore_lower_triangular", &b->ignore_ltriangular, NULL));
1898 
1899   b->getrow_utriangular = PETSC_FALSE;
1900 
1901   PetscCall(PetscOptionsGetBool(((PetscObject)B)->options, ((PetscObject)B)->prefix, "-mat_getrow_uppertriangular", &b->getrow_utriangular, NULL));
1902 
1903   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqSBAIJGetArray_C", MatSeqSBAIJGetArray_SeqSBAIJ));
1904   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqSBAIJRestoreArray_C", MatSeqSBAIJRestoreArray_SeqSBAIJ));
1905   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_SeqSBAIJ));
1906   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_SeqSBAIJ));
1907   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqSBAIJSetColumnIndices_C", MatSeqSBAIJSetColumnIndices_SeqSBAIJ));
1908   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqsbaij_seqaij_C", MatConvert_SeqSBAIJ_SeqAIJ));
1909   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqsbaij_seqbaij_C", MatConvert_SeqSBAIJ_SeqBAIJ));
1910   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqSBAIJSetPreallocation_C", MatSeqSBAIJSetPreallocation_SeqSBAIJ));
1911   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqSBAIJSetPreallocationCSR_C", MatSeqSBAIJSetPreallocationCSR_SeqSBAIJ));
1912 #if defined(PETSC_HAVE_ELEMENTAL)
1913   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqsbaij_elemental_C", MatConvert_SeqSBAIJ_Elemental));
1914 #endif
1915 #if defined(PETSC_HAVE_SCALAPACK)
1916   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqsbaij_scalapack_C", MatConvert_SBAIJ_ScaLAPACK));
1917 #endif
1918 
1919   B->symmetry_eternal            = PETSC_TRUE;
1920   B->structural_symmetry_eternal = PETSC_TRUE;
1921   B->symmetric                   = PETSC_BOOL3_TRUE;
1922   B->structurally_symmetric      = PETSC_BOOL3_TRUE;
1923 #if defined(PETSC_USE_COMPLEX)
1924   B->hermitian = PETSC_BOOL3_FALSE;
1925 #else
1926   B->hermitian = PETSC_BOOL3_TRUE;
1927 #endif
1928 
1929   PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQSBAIJ));
1930 
1931   PetscOptionsBegin(PetscObjectComm((PetscObject)B), ((PetscObject)B)->prefix, "Options for SEQSBAIJ matrix", "Mat");
1932   PetscCall(PetscOptionsBool("-mat_no_unroll", "Do not optimize for inodes (slower)", NULL, no_unroll, &no_unroll, NULL));
1933   if (no_unroll) PetscCall(PetscInfo(B, "Not using Inode routines due to -mat_no_unroll\n"));
1934   PetscCall(PetscOptionsBool("-mat_no_inode", "Do not optimize for inodes (slower)", NULL, no_inode, &no_inode, NULL));
1935   if (no_inode) PetscCall(PetscInfo(B, "Not using Inode routines due to -mat_no_inode\n"));
1936   PetscCall(PetscOptionsInt("-mat_inode_limit", "Do not use inodes larger then this value", NULL, b->inode.limit, &b->inode.limit, NULL));
1937   PetscOptionsEnd();
1938   b->inode.use = (PetscBool)(!(no_unroll || no_inode));
1939   if (b->inode.limit > b->inode.max_limit) b->inode.limit = b->inode.max_limit;
1940   PetscFunctionReturn(PETSC_SUCCESS);
1941 }
1942 
1943 /*@C
1944   MatSeqSBAIJSetPreallocation - Creates a sparse symmetric matrix in block AIJ (block
1945   compressed row) `MATSEQSBAIJ` format.  For good matrix assembly performance the
1946   user should preallocate the matrix storage by setting the parameter `nz`
1947   (or the array `nnz`).
1948 
1949   Collective
1950 
1951   Input Parameters:
1952 + B   - the symmetric matrix
1953 . bs  - size of block, the blocks are ALWAYS square. One can use `MatSetBlockSizes()` to set a different row and column blocksize but the row
1954           blocksize always defines the size of the blocks. The column blocksize sets the blocksize of the vectors obtained with `MatCreateVecs()`
1955 . nz  - number of block nonzeros per block row (same for all rows)
1956 - nnz - array containing the number of block nonzeros in the upper triangular plus
1957          diagonal portion of each block (possibly different for each block row) or `NULL`
1958 
1959   Options Database Keys:
1960 + -mat_no_unroll  - uses code that does not unroll the loops in the
1961                      block calculations (much slower)
1962 - -mat_block_size - size of the blocks to use (only works if a negative bs is passed in
1963 
1964   Level: intermediate
1965 
1966   Notes:
1967   Specify the preallocated storage with either `nz` or `nnz` (not both).
1968   Set `nz` = `PETSC_DEFAULT` and `nnz` = `NULL` for PETSc to control dynamic memory
1969   allocation.  See [Sparse Matrices](sec_matsparse) for details.
1970 
1971   You can call `MatGetInfo()` to get information on how effective the preallocation was;
1972   for example the fields mallocs,nz_allocated,nz_used,nz_unneeded;
1973   You can also run with the option `-info` and look for messages with the string
1974   malloc in them to see if additional memory allocation was needed.
1975 
1976   If the `nnz` parameter is given then the `nz` parameter is ignored
1977 
1978 .seealso: [](ch_matrices), `Mat`, [Sparse Matrices](sec_matsparse), `MATSEQSBAIJ`, `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatCreateSBAIJ()`
1979 @*/
1980 PetscErrorCode MatSeqSBAIJSetPreallocation(Mat B, PetscInt bs, PetscInt nz, const PetscInt nnz[])
1981 {
1982   PetscFunctionBegin;
1983   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
1984   PetscValidType(B, 1);
1985   PetscValidLogicalCollectiveInt(B, bs, 2);
1986   PetscTryMethod(B, "MatSeqSBAIJSetPreallocation_C", (Mat, PetscInt, PetscInt, const PetscInt[]), (B, bs, nz, nnz));
1987   PetscFunctionReturn(PETSC_SUCCESS);
1988 }
1989 
1990 /*@C
1991   MatSeqSBAIJSetPreallocationCSR - Creates a sparse parallel matrix in `MATSEQSBAIJ` format using the given nonzero structure and (optional) numerical values
1992 
1993   Input Parameters:
1994 + B  - the matrix
1995 . bs - size of block, the blocks are ALWAYS square.
1996 . i  - the indices into j for the start of each local row (starts with zero)
1997 . j  - the column indices for each local row (starts with zero) these must be sorted for each row
1998 - v  - optional values in the matrix
1999 
2000   Level: advanced
2001 
2002   Notes:
2003   The order of the entries in values is specified by the `MatOption` `MAT_ROW_ORIENTED`.  For example, C programs
2004   may want to use the default `MAT_ROW_ORIENTED` = `PETSC_TRUE` and use an array v[nnz][bs][bs] where the second index is
2005   over rows within a block and the last index is over columns within a block row.  Fortran programs will likely set
2006   `MAT_ROW_ORIENTED` = `PETSC_FALSE` and use a Fortran array v(bs,bs,nnz) in which the first index is over rows within a
2007   block column and the second index is over columns within a block.
2008 
2009   Any entries below the diagonal are ignored
2010 
2011   Though this routine has Preallocation() in the name it also sets the exact nonzero locations of the matrix entries
2012   and usually the numerical values as well
2013 
2014 .seealso: [](ch_matrices), `Mat`, `MATSEQSBAIJ`, `MatCreate()`, `MatCreateSeqSBAIJ()`, `MatSetValuesBlocked()`, `MatSeqSBAIJSetPreallocation()`
2015 @*/
2016 PetscErrorCode MatSeqSBAIJSetPreallocationCSR(Mat B, PetscInt bs, const PetscInt i[], const PetscInt j[], const PetscScalar v[])
2017 {
2018   PetscFunctionBegin;
2019   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
2020   PetscValidType(B, 1);
2021   PetscValidLogicalCollectiveInt(B, bs, 2);
2022   PetscTryMethod(B, "MatSeqSBAIJSetPreallocationCSR_C", (Mat, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[]), (B, bs, i, j, v));
2023   PetscFunctionReturn(PETSC_SUCCESS);
2024 }
2025 
2026 /*@C
2027   MatCreateSeqSBAIJ - Creates a sparse symmetric matrix in (block
2028   compressed row) `MATSEQSBAIJ` format.  For good matrix assembly performance the
2029   user should preallocate the matrix storage by setting the parameter `nz`
2030   (or the array `nnz`).
2031 
2032   Collective
2033 
2034   Input Parameters:
2035 + comm - MPI communicator, set to `PETSC_COMM_SELF`
2036 . bs   - size of block, the blocks are ALWAYS square. One can use `MatSetBlockSizes()` to set a different row and column blocksize but the row
2037           blocksize always defines the size of the blocks. The column blocksize sets the blocksize of the vectors obtained with MatCreateVecs()
2038 . m    - number of rows
2039 . n    - number of columns
2040 . nz   - number of block nonzeros per block row (same for all rows)
2041 - nnz  - array containing the number of block nonzeros in the upper triangular plus
2042          diagonal portion of each block (possibly different for each block row) or `NULL`
2043 
2044   Output Parameter:
2045 . A - the symmetric matrix
2046 
2047   Options Database Keys:
2048 + -mat_no_unroll  - uses code that does not unroll the loops in the
2049                      block calculations (much slower)
2050 - -mat_block_size - size of the blocks to use
2051 
2052   Level: intermediate
2053 
2054   Notes:
2055   It is recommended that one use `MatCreateFromOptions()` or the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`,
2056   MatXXXXSetPreallocation() paradigm instead of this routine directly.
2057   [MatXXXXSetPreallocation() is, for example, `MatSeqAIJSetPreallocation()`]
2058 
2059   The number of rows and columns must be divisible by blocksize.
2060   This matrix type does not support complex Hermitian operation.
2061 
2062   Specify the preallocated storage with either `nz` or `nnz` (not both).
2063   Set `nz` = `PETSC_DEFAULT` and `nnz` = `NULL` for PETSc to control dynamic memory
2064   allocation.  See [Sparse Matrices](sec_matsparse) for details.
2065 
2066   If the `nnz` parameter is given then the `nz` parameter is ignored
2067 
2068 .seealso: [](ch_matrices), `Mat`, [Sparse Matrices](sec_matsparse), `MATSEQSBAIJ`, `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatCreateSBAIJ()`
2069 @*/
2070 PetscErrorCode MatCreateSeqSBAIJ(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt nz, const PetscInt nnz[], Mat *A)
2071 {
2072   PetscFunctionBegin;
2073   PetscCall(MatCreate(comm, A));
2074   PetscCall(MatSetSizes(*A, m, n, m, n));
2075   PetscCall(MatSetType(*A, MATSEQSBAIJ));
2076   PetscCall(MatSeqSBAIJSetPreallocation(*A, bs, nz, (PetscInt *)nnz));
2077   PetscFunctionReturn(PETSC_SUCCESS);
2078 }
2079 
2080 PetscErrorCode MatDuplicate_SeqSBAIJ(Mat A, MatDuplicateOption cpvalues, Mat *B)
2081 {
2082   Mat           C;
2083   Mat_SeqSBAIJ *c, *a  = (Mat_SeqSBAIJ *)A->data;
2084   PetscInt      i, mbs = a->mbs, nz = a->nz, bs2 = a->bs2;
2085 
2086   PetscFunctionBegin;
2087   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Cannot duplicate unassembled matrix");
2088   PetscCheck(a->i[mbs] == nz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Corrupt matrix");
2089 
2090   *B = NULL;
2091   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
2092   PetscCall(MatSetSizes(C, A->rmap->N, A->cmap->n, A->rmap->N, A->cmap->n));
2093   PetscCall(MatSetBlockSizesFromMats(C, A, A));
2094   PetscCall(MatSetType(C, MATSEQSBAIJ));
2095   c = (Mat_SeqSBAIJ *)C->data;
2096 
2097   C->preallocated       = PETSC_TRUE;
2098   C->factortype         = A->factortype;
2099   c->row                = NULL;
2100   c->icol               = NULL;
2101   c->saved_values       = NULL;
2102   c->keepnonzeropattern = a->keepnonzeropattern;
2103   C->assembled          = PETSC_TRUE;
2104 
2105   PetscCall(PetscLayoutReference(A->rmap, &C->rmap));
2106   PetscCall(PetscLayoutReference(A->cmap, &C->cmap));
2107   c->bs2 = a->bs2;
2108   c->mbs = a->mbs;
2109   c->nbs = a->nbs;
2110 
2111   if (cpvalues == MAT_SHARE_NONZERO_PATTERN) {
2112     c->imax           = a->imax;
2113     c->ilen           = a->ilen;
2114     c->free_imax_ilen = PETSC_FALSE;
2115   } else {
2116     PetscCall(PetscMalloc2((mbs + 1), &c->imax, (mbs + 1), &c->ilen));
2117     for (i = 0; i < mbs; i++) {
2118       c->imax[i] = a->imax[i];
2119       c->ilen[i] = a->ilen[i];
2120     }
2121     c->free_imax_ilen = PETSC_TRUE;
2122   }
2123 
2124   /* allocate the matrix space */
2125   if (cpvalues == MAT_SHARE_NONZERO_PATTERN) {
2126     PetscCall(PetscMalloc1(bs2 * nz, &c->a));
2127     c->i            = a->i;
2128     c->j            = a->j;
2129     c->singlemalloc = PETSC_FALSE;
2130     c->free_a       = PETSC_TRUE;
2131     c->free_ij      = PETSC_FALSE;
2132     c->parent       = A;
2133     PetscCall(PetscObjectReference((PetscObject)A));
2134     PetscCall(MatSetOption(A, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE));
2135     PetscCall(MatSetOption(C, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE));
2136   } else {
2137     PetscCall(PetscMalloc3(bs2 * nz, &c->a, nz, &c->j, mbs + 1, &c->i));
2138     PetscCall(PetscArraycpy(c->i, a->i, mbs + 1));
2139     c->singlemalloc = PETSC_TRUE;
2140     c->free_a       = PETSC_TRUE;
2141     c->free_ij      = PETSC_TRUE;
2142   }
2143   if (mbs > 0) {
2144     if (cpvalues != MAT_SHARE_NONZERO_PATTERN) PetscCall(PetscArraycpy(c->j, a->j, nz));
2145     if (cpvalues == MAT_COPY_VALUES) {
2146       PetscCall(PetscArraycpy(c->a, a->a, bs2 * nz));
2147     } else {
2148       PetscCall(PetscArrayzero(c->a, bs2 * nz));
2149     }
2150     if (a->jshort) {
2151       /* cannot share jshort, it is reallocated in MatAssemblyEnd_SeqSBAIJ() */
2152       /* if the parent matrix is reassembled, this child matrix will never notice */
2153       PetscCall(PetscMalloc1(nz, &c->jshort));
2154       PetscCall(PetscArraycpy(c->jshort, a->jshort, nz));
2155 
2156       c->free_jshort = PETSC_TRUE;
2157     }
2158   }
2159 
2160   c->roworiented = a->roworiented;
2161   c->nonew       = a->nonew;
2162 
2163   if (a->diag) {
2164     if (cpvalues == MAT_SHARE_NONZERO_PATTERN) {
2165       c->diag      = a->diag;
2166       c->free_diag = PETSC_FALSE;
2167     } else {
2168       PetscCall(PetscMalloc1(mbs, &c->diag));
2169       for (i = 0; i < mbs; i++) c->diag[i] = a->diag[i];
2170       c->free_diag = PETSC_TRUE;
2171     }
2172   }
2173   c->nz         = a->nz;
2174   c->maxnz      = a->nz; /* Since we allocate exactly the right amount */
2175   c->solve_work = NULL;
2176   c->mult_work  = NULL;
2177 
2178   *B = C;
2179   PetscCall(PetscFunctionListDuplicate(((PetscObject)A)->qlist, &((PetscObject)C)->qlist));
2180   PetscFunctionReturn(PETSC_SUCCESS);
2181 }
2182 
2183 /* Used for both SeqBAIJ and SeqSBAIJ matrices */
2184 #define MatLoad_SeqSBAIJ_Binary MatLoad_SeqBAIJ_Binary
2185 
2186 PetscErrorCode MatLoad_SeqSBAIJ(Mat mat, PetscViewer viewer)
2187 {
2188   PetscBool isbinary;
2189 
2190   PetscFunctionBegin;
2191   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
2192   PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Viewer type %s not yet supported for reading %s matrices", ((PetscObject)viewer)->type_name, ((PetscObject)mat)->type_name);
2193   PetscCall(MatLoad_SeqSBAIJ_Binary(mat, viewer));
2194   PetscFunctionReturn(PETSC_SUCCESS);
2195 }
2196 
2197 /*@
2198   MatCreateSeqSBAIJWithArrays - Creates an sequential `MATSEQSBAIJ` matrix using matrix elements
2199   (upper triangular entries in CSR format) provided by the user.
2200 
2201   Collective
2202 
2203   Input Parameters:
2204 + comm - must be an MPI communicator of size 1
2205 . bs   - size of block
2206 . m    - number of rows
2207 . n    - number of columns
2208 . i    - row indices; that is i[0] = 0, i[row] = i[row-1] + number of block elements in that row block row of the matrix
2209 . j    - column indices
2210 - a    - matrix values
2211 
2212   Output Parameter:
2213 . mat - the matrix
2214 
2215   Level: advanced
2216 
2217   Notes:
2218   The `i`, `j`, and `a` arrays are not copied by this routine, the user must free these arrays
2219   once the matrix is destroyed
2220 
2221   You cannot set new nonzero locations into this matrix, that will generate an error.
2222 
2223   The `i` and `j` indices are 0 based
2224 
2225   When block size is greater than 1 the matrix values must be stored using the `MATSBAIJ` storage format. For block size of 1
2226   it is the regular CSR format excluding the lower triangular elements.
2227 
2228 .seealso: [](ch_matrices), `Mat`, `MATSEQSBAIJ`, `MatCreate()`, `MatCreateSBAIJ()`, `MatCreateSeqSBAIJ()`
2229 @*/
2230 PetscErrorCode MatCreateSeqSBAIJWithArrays(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat)
2231 {
2232   PetscInt      ii;
2233   Mat_SeqSBAIJ *sbaij;
2234 
2235   PetscFunctionBegin;
2236   PetscCheck(bs == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "block size %" PetscInt_FMT " > 1 is not supported yet", bs);
2237   PetscCheck(m == 0 || i[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "i (row indices) must start with 0");
2238 
2239   PetscCall(MatCreate(comm, mat));
2240   PetscCall(MatSetSizes(*mat, m, n, m, n));
2241   PetscCall(MatSetType(*mat, MATSEQSBAIJ));
2242   PetscCall(MatSeqSBAIJSetPreallocation(*mat, bs, MAT_SKIP_ALLOCATION, NULL));
2243   sbaij = (Mat_SeqSBAIJ *)(*mat)->data;
2244   PetscCall(PetscMalloc2(m, &sbaij->imax, m, &sbaij->ilen));
2245 
2246   sbaij->i = i;
2247   sbaij->j = j;
2248   sbaij->a = a;
2249 
2250   sbaij->singlemalloc   = PETSC_FALSE;
2251   sbaij->nonew          = -1; /*this indicates that inserting a new value in the matrix that generates a new nonzero is an error*/
2252   sbaij->free_a         = PETSC_FALSE;
2253   sbaij->free_ij        = PETSC_FALSE;
2254   sbaij->free_imax_ilen = PETSC_TRUE;
2255 
2256   for (ii = 0; ii < m; ii++) {
2257     sbaij->ilen[ii] = sbaij->imax[ii] = i[ii + 1] - i[ii];
2258     PetscCheck(i[ii + 1] >= i[ii], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative row length in i (row indices) row = %" PetscInt_FMT " length = %" PetscInt_FMT, ii, i[ii + 1] - i[ii]);
2259   }
2260   if (PetscDefined(USE_DEBUG)) {
2261     for (ii = 0; ii < sbaij->i[m]; ii++) {
2262       PetscCheck(j[ii] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative column index at location = %" PetscInt_FMT " index = %" PetscInt_FMT, ii, j[ii]);
2263       PetscCheck(j[ii] < n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column index too large at location = %" PetscInt_FMT " index = %" PetscInt_FMT, ii, j[ii]);
2264     }
2265   }
2266 
2267   PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY));
2268   PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY));
2269   PetscFunctionReturn(PETSC_SUCCESS);
2270 }
2271 
2272 PetscErrorCode MatCreateMPIMatConcatenateSeqMat_SeqSBAIJ(MPI_Comm comm, Mat inmat, PetscInt n, MatReuse scall, Mat *outmat)
2273 {
2274   PetscFunctionBegin;
2275   PetscCall(MatCreateMPIMatConcatenateSeqMat_MPISBAIJ(comm, inmat, n, scall, outmat));
2276   PetscFunctionReturn(PETSC_SUCCESS);
2277 }
2278