xref: /petsc/src/mat/impls/aij/seq/aij.c (revision 07425a8d4172ec73b7b53c5ce4d6ba1b92fe45cf)
1 /*
2     Defines the basic matrix operations for the AIJ (compressed row)
3   matrix storage format.
4 */
5 
6 #include <../src/mat/impls/aij/seq/aij.h> /*I "petscmat.h" I*/
7 #include <petscblaslapack.h>
8 #include <petscbt.h>
9 #include <petsc/private/kernels/blocktranspose.h>
10 
11 /* defines MatSetValues_Seq_Hash(), MatAssemblyEnd_Seq_Hash(), MatSetUp_Seq_Hash() */
12 #define TYPE AIJ
13 #define TYPE_BS
14 #include "../src/mat/impls/aij/seq/seqhashmatsetvalues.h"
15 #include "../src/mat/impls/aij/seq/seqhashmat.h"
16 #undef TYPE
17 #undef TYPE_BS
18 
19 static PetscErrorCode MatSeqAIJSetTypeFromOptions(Mat A)
20 {
21   PetscBool flg;
22   char      type[256];
23 
24   PetscFunctionBegin;
25   PetscObjectOptionsBegin((PetscObject)A);
26   PetscCall(PetscOptionsFList("-mat_seqaij_type", "Matrix SeqAIJ type", "MatSeqAIJSetType", MatSeqAIJList, "seqaij", type, 256, &flg));
27   if (flg) PetscCall(MatSeqAIJSetType(A, type));
28   PetscOptionsEnd();
29   PetscFunctionReturn(PETSC_SUCCESS);
30 }
31 
32 static PetscErrorCode MatGetColumnReductions_SeqAIJ(Mat A, PetscInt type, PetscReal *reductions)
33 {
34   PetscInt    i, m, n;
35   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
36 
37   PetscFunctionBegin;
38   PetscCall(MatGetSize(A, &m, &n));
39   PetscCall(PetscArrayzero(reductions, n));
40   if (type == NORM_2) {
41     for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscAbsScalar(aij->a[i] * aij->a[i]);
42   } else if (type == NORM_1) {
43     for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscAbsScalar(aij->a[i]);
44   } else if (type == NORM_INFINITY) {
45     for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] = PetscMax(PetscAbsScalar(aij->a[i]), reductions[aij->j[i]]);
46   } else if (type == REDUCTION_SUM_REALPART || type == REDUCTION_MEAN_REALPART) {
47     for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscRealPart(aij->a[i]);
48   } else if (type == REDUCTION_SUM_IMAGINARYPART || type == REDUCTION_MEAN_IMAGINARYPART) {
49     for (i = 0; i < aij->i[m]; i++) reductions[aij->j[i]] += PetscImaginaryPart(aij->a[i]);
50   } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Unknown reduction type");
51 
52   if (type == NORM_2) {
53     for (i = 0; i < n; i++) reductions[i] = PetscSqrtReal(reductions[i]);
54   } else if (type == REDUCTION_MEAN_REALPART || type == REDUCTION_MEAN_IMAGINARYPART) {
55     for (i = 0; i < n; i++) reductions[i] /= m;
56   }
57   PetscFunctionReturn(PETSC_SUCCESS);
58 }
59 
60 static PetscErrorCode MatFindOffBlockDiagonalEntries_SeqAIJ(Mat A, IS *is)
61 {
62   Mat_SeqAIJ     *a = (Mat_SeqAIJ *)A->data;
63   PetscInt        i, m = A->rmap->n, cnt = 0, bs = A->rmap->bs;
64   const PetscInt *jj = a->j, *ii = a->i;
65   PetscInt       *rows;
66 
67   PetscFunctionBegin;
68   for (i = 0; i < m; i++) {
69     if ((ii[i] != ii[i + 1]) && ((jj[ii[i]] < bs * (i / bs)) || (jj[ii[i + 1] - 1] > bs * ((i + bs) / bs) - 1))) cnt++;
70   }
71   PetscCall(PetscMalloc1(cnt, &rows));
72   cnt = 0;
73   for (i = 0; i < m; i++) {
74     if ((ii[i] != ii[i + 1]) && ((jj[ii[i]] < bs * (i / bs)) || (jj[ii[i + 1] - 1] > bs * ((i + bs) / bs) - 1))) {
75       rows[cnt] = i;
76       cnt++;
77     }
78   }
79   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cnt, rows, PETSC_OWN_POINTER, is));
80   PetscFunctionReturn(PETSC_SUCCESS);
81 }
82 
83 PetscErrorCode MatFindZeroDiagonals_SeqAIJ_Private(Mat A, PetscInt *nrows, PetscInt **zrows)
84 {
85   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
86   const MatScalar *aa;
87   PetscInt         i, m = A->rmap->n, cnt = 0;
88   const PetscInt  *ii = a->i, *jj = a->j, *diag;
89   PetscInt        *rows;
90 
91   PetscFunctionBegin;
92   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
93   PetscCall(MatMarkDiagonal_SeqAIJ(A));
94   diag = a->diag;
95   for (i = 0; i < m; i++) {
96     if ((diag[i] >= ii[i + 1]) || (jj[diag[i]] != i) || (aa[diag[i]] == 0.0)) cnt++;
97   }
98   PetscCall(PetscMalloc1(cnt, &rows));
99   cnt = 0;
100   for (i = 0; i < m; i++) {
101     if ((diag[i] >= ii[i + 1]) || (jj[diag[i]] != i) || (aa[diag[i]] == 0.0)) rows[cnt++] = i;
102   }
103   *nrows = cnt;
104   *zrows = rows;
105   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
106   PetscFunctionReturn(PETSC_SUCCESS);
107 }
108 
109 static PetscErrorCode MatFindZeroDiagonals_SeqAIJ(Mat A, IS *zrows)
110 {
111   PetscInt nrows, *rows;
112 
113   PetscFunctionBegin;
114   *zrows = NULL;
115   PetscCall(MatFindZeroDiagonals_SeqAIJ_Private(A, &nrows, &rows));
116   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrows, rows, PETSC_OWN_POINTER, zrows));
117   PetscFunctionReturn(PETSC_SUCCESS);
118 }
119 
120 static PetscErrorCode MatFindNonzeroRows_SeqAIJ(Mat A, IS *keptrows)
121 {
122   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
123   const MatScalar *aa;
124   PetscInt         m = A->rmap->n, cnt = 0;
125   const PetscInt  *ii;
126   PetscInt         n, i, j, *rows;
127 
128   PetscFunctionBegin;
129   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
130   *keptrows = NULL;
131   ii        = a->i;
132   for (i = 0; i < m; i++) {
133     n = ii[i + 1] - ii[i];
134     if (!n) {
135       cnt++;
136       goto ok1;
137     }
138     for (j = ii[i]; j < ii[i + 1]; j++) {
139       if (aa[j] != 0.0) goto ok1;
140     }
141     cnt++;
142   ok1:;
143   }
144   if (!cnt) {
145     PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
146     PetscFunctionReturn(PETSC_SUCCESS);
147   }
148   PetscCall(PetscMalloc1(A->rmap->n - cnt, &rows));
149   cnt = 0;
150   for (i = 0; i < m; i++) {
151     n = ii[i + 1] - ii[i];
152     if (!n) continue;
153     for (j = ii[i]; j < ii[i + 1]; j++) {
154       if (aa[j] != 0.0) {
155         rows[cnt++] = i;
156         break;
157       }
158     }
159   }
160   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
161   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cnt, rows, PETSC_OWN_POINTER, keptrows));
162   PetscFunctionReturn(PETSC_SUCCESS);
163 }
164 
165 PetscErrorCode MatDiagonalSet_SeqAIJ(Mat Y, Vec D, InsertMode is)
166 {
167   Mat_SeqAIJ        *aij = (Mat_SeqAIJ *)Y->data;
168   PetscInt           i, m = Y->rmap->n;
169   const PetscInt    *diag;
170   MatScalar         *aa;
171   const PetscScalar *v;
172   PetscBool          missing;
173 
174   PetscFunctionBegin;
175   if (Y->assembled) {
176     PetscCall(MatMissingDiagonal_SeqAIJ(Y, &missing, NULL));
177     if (!missing) {
178       diag = aij->diag;
179       PetscCall(VecGetArrayRead(D, &v));
180       PetscCall(MatSeqAIJGetArray(Y, &aa));
181       if (is == INSERT_VALUES) {
182         for (i = 0; i < m; i++) aa[diag[i]] = v[i];
183       } else {
184         for (i = 0; i < m; i++) aa[diag[i]] += v[i];
185       }
186       PetscCall(MatSeqAIJRestoreArray(Y, &aa));
187       PetscCall(VecRestoreArrayRead(D, &v));
188       PetscFunctionReturn(PETSC_SUCCESS);
189     }
190   }
191   PetscCall(MatDiagonalSet_Default(Y, D, is));
192   PetscFunctionReturn(PETSC_SUCCESS);
193 }
194 
195 PetscErrorCode MatGetRowIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *m, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
196 {
197   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
198   PetscInt    i, ishift;
199 
200   PetscFunctionBegin;
201   if (m) *m = A->rmap->n;
202   if (!ia) PetscFunctionReturn(PETSC_SUCCESS);
203   ishift = 0;
204   if (symmetric && A->structurally_symmetric != PETSC_BOOL3_TRUE) {
205     PetscCall(MatToSymmetricIJ_SeqAIJ(A->rmap->n, a->i, a->j, PETSC_TRUE, ishift, oshift, (PetscInt **)ia, (PetscInt **)ja));
206   } else if (oshift == 1) {
207     PetscInt *tia;
208     PetscInt  nz = a->i[A->rmap->n];
209     /* malloc space and  add 1 to i and j indices */
210     PetscCall(PetscMalloc1(A->rmap->n + 1, &tia));
211     for (i = 0; i < A->rmap->n + 1; i++) tia[i] = a->i[i] + 1;
212     *ia = tia;
213     if (ja) {
214       PetscInt *tja;
215       PetscCall(PetscMalloc1(nz + 1, &tja));
216       for (i = 0; i < nz; i++) tja[i] = a->j[i] + 1;
217       *ja = tja;
218     }
219   } else {
220     *ia = a->i;
221     if (ja) *ja = a->j;
222   }
223   PetscFunctionReturn(PETSC_SUCCESS);
224 }
225 
226 PetscErrorCode MatRestoreRowIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
227 {
228   PetscFunctionBegin;
229   if (!ia) PetscFunctionReturn(PETSC_SUCCESS);
230   if ((symmetric && A->structurally_symmetric != PETSC_BOOL3_TRUE) || oshift == 1) {
231     PetscCall(PetscFree(*ia));
232     if (ja) PetscCall(PetscFree(*ja));
233   }
234   PetscFunctionReturn(PETSC_SUCCESS);
235 }
236 
237 PetscErrorCode MatGetColumnIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *nn, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
238 {
239   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
240   PetscInt    i, *collengths, *cia, *cja, n = A->cmap->n, m = A->rmap->n;
241   PetscInt    nz = a->i[m], row, *jj, mr, col;
242 
243   PetscFunctionBegin;
244   *nn = n;
245   if (!ia) PetscFunctionReturn(PETSC_SUCCESS);
246   if (symmetric) {
247     PetscCall(MatToSymmetricIJ_SeqAIJ(A->rmap->n, a->i, a->j, PETSC_TRUE, 0, oshift, (PetscInt **)ia, (PetscInt **)ja));
248   } else {
249     PetscCall(PetscCalloc1(n, &collengths));
250     PetscCall(PetscMalloc1(n + 1, &cia));
251     PetscCall(PetscMalloc1(nz, &cja));
252     jj = a->j;
253     for (i = 0; i < nz; i++) collengths[jj[i]]++;
254     cia[0] = oshift;
255     for (i = 0; i < n; i++) cia[i + 1] = cia[i] + collengths[i];
256     PetscCall(PetscArrayzero(collengths, n));
257     jj = a->j;
258     for (row = 0; row < m; row++) {
259       mr = a->i[row + 1] - a->i[row];
260       for (i = 0; i < mr; i++) {
261         col = *jj++;
262 
263         cja[cia[col] + collengths[col]++ - oshift] = row + oshift;
264       }
265     }
266     PetscCall(PetscFree(collengths));
267     *ia = cia;
268     *ja = cja;
269   }
270   PetscFunctionReturn(PETSC_SUCCESS);
271 }
272 
273 PetscErrorCode MatRestoreColumnIJ_SeqAIJ(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
274 {
275   PetscFunctionBegin;
276   if (!ia) PetscFunctionReturn(PETSC_SUCCESS);
277 
278   PetscCall(PetscFree(*ia));
279   PetscCall(PetscFree(*ja));
280   PetscFunctionReturn(PETSC_SUCCESS);
281 }
282 
283 /*
284  MatGetColumnIJ_SeqAIJ_Color() and MatRestoreColumnIJ_SeqAIJ_Color() are customized from
285  MatGetColumnIJ_SeqAIJ() and MatRestoreColumnIJ_SeqAIJ() by adding an output
286  spidx[], index of a->a, to be used in MatTransposeColoringCreate_SeqAIJ() and MatFDColoringCreate_SeqXAIJ()
287 */
288 PetscErrorCode MatGetColumnIJ_SeqAIJ_Color(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *nn, const PetscInt *ia[], const PetscInt *ja[], PetscInt *spidx[], PetscBool *done)
289 {
290   Mat_SeqAIJ     *a = (Mat_SeqAIJ *)A->data;
291   PetscInt        i, *collengths, *cia, *cja, n = A->cmap->n, m = A->rmap->n;
292   PetscInt        nz = a->i[m], row, mr, col, tmp;
293   PetscInt       *cspidx;
294   const PetscInt *jj;
295 
296   PetscFunctionBegin;
297   *nn = n;
298   if (!ia) PetscFunctionReturn(PETSC_SUCCESS);
299 
300   PetscCall(PetscCalloc1(n, &collengths));
301   PetscCall(PetscMalloc1(n + 1, &cia));
302   PetscCall(PetscMalloc1(nz, &cja));
303   PetscCall(PetscMalloc1(nz, &cspidx));
304   jj = a->j;
305   for (i = 0; i < nz; i++) collengths[jj[i]]++;
306   cia[0] = oshift;
307   for (i = 0; i < n; i++) cia[i + 1] = cia[i] + collengths[i];
308   PetscCall(PetscArrayzero(collengths, n));
309   jj = a->j;
310   for (row = 0; row < m; row++) {
311     mr = a->i[row + 1] - a->i[row];
312     for (i = 0; i < mr; i++) {
313       col         = *jj++;
314       tmp         = cia[col] + collengths[col]++ - oshift;
315       cspidx[tmp] = a->i[row] + i; /* index of a->j */
316       cja[tmp]    = row + oshift;
317     }
318   }
319   PetscCall(PetscFree(collengths));
320   *ia    = cia;
321   *ja    = cja;
322   *spidx = cspidx;
323   PetscFunctionReturn(PETSC_SUCCESS);
324 }
325 
326 PetscErrorCode MatRestoreColumnIJ_SeqAIJ_Color(Mat A, PetscInt oshift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscInt *spidx[], PetscBool *done)
327 {
328   PetscFunctionBegin;
329   PetscCall(MatRestoreColumnIJ_SeqAIJ(A, oshift, symmetric, inodecompressed, n, ia, ja, done));
330   PetscCall(PetscFree(*spidx));
331   PetscFunctionReturn(PETSC_SUCCESS);
332 }
333 
334 static PetscErrorCode MatSetValuesRow_SeqAIJ(Mat A, PetscInt row, const PetscScalar v[])
335 {
336   Mat_SeqAIJ  *a  = (Mat_SeqAIJ *)A->data;
337   PetscInt    *ai = a->i;
338   PetscScalar *aa;
339 
340   PetscFunctionBegin;
341   PetscCall(MatSeqAIJGetArray(A, &aa));
342   PetscCall(PetscArraycpy(aa + ai[row], v, ai[row + 1] - ai[row]));
343   PetscCall(MatSeqAIJRestoreArray(A, &aa));
344   PetscFunctionReturn(PETSC_SUCCESS);
345 }
346 
347 /*
348     MatSeqAIJSetValuesLocalFast - An optimized version of MatSetValuesLocal() for SeqAIJ matrices with several assumptions
349 
350       -   a single row of values is set with each call
351       -   no row or column indices are negative or (in error) larger than the number of rows or columns
352       -   the values are always added to the matrix, not set
353       -   no new locations are introduced in the nonzero structure of the matrix
354 
355      This does NOT assume the global column indices are sorted
356 
357 */
358 
359 #include <petsc/private/isimpl.h>
360 PetscErrorCode MatSeqAIJSetValuesLocalFast(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is)
361 {
362   Mat_SeqAIJ     *a = (Mat_SeqAIJ *)A->data;
363   PetscInt        low, high, t, row, nrow, i, col, l;
364   const PetscInt *rp, *ai = a->i, *ailen = a->ilen, *aj = a->j;
365   PetscInt        lastcol = -1;
366   MatScalar      *ap, value, *aa;
367   const PetscInt *ridx = A->rmap->mapping->indices, *cidx = A->cmap->mapping->indices;
368 
369   PetscFunctionBegin;
370   PetscCall(MatSeqAIJGetArray(A, &aa));
371   row  = ridx[im[0]];
372   rp   = aj + ai[row];
373   ap   = aa + ai[row];
374   nrow = ailen[row];
375   low  = 0;
376   high = nrow;
377   for (l = 0; l < n; l++) { /* loop over added columns */
378     col   = cidx[in[l]];
379     value = v[l];
380 
381     if (col <= lastcol) low = 0;
382     else high = nrow;
383     lastcol = col;
384     while (high - low > 5) {
385       t = (low + high) / 2;
386       if (rp[t] > col) high = t;
387       else low = t;
388     }
389     for (i = low; i < high; i++) {
390       if (rp[i] == col) {
391         ap[i] += value;
392         low = i + 1;
393         break;
394       }
395     }
396   }
397   PetscCall(MatSeqAIJRestoreArray(A, &aa));
398   return PETSC_SUCCESS;
399 }
400 
401 PetscErrorCode MatSetValues_SeqAIJ(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is)
402 {
403   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
404   PetscInt   *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N;
405   PetscInt   *imax = a->imax, *ai = a->i, *ailen = a->ilen;
406   PetscInt   *aj = a->j, nonew = a->nonew, lastcol = -1;
407   MatScalar  *ap = NULL, value = 0.0, *aa;
408   PetscBool   ignorezeroentries = a->ignorezeroentries;
409   PetscBool   roworiented       = a->roworiented;
410 
411   PetscFunctionBegin;
412   PetscCall(MatSeqAIJGetArray(A, &aa));
413   for (k = 0; k < m; k++) { /* loop over added rows */
414     row = im[k];
415     if (row < 0) continue;
416     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);
417     rp = PetscSafePointerPlusOffset(aj, ai[row]);
418     if (!A->structure_only) ap = PetscSafePointerPlusOffset(aa, ai[row]);
419     rmax = imax[row];
420     nrow = ailen[row];
421     low  = 0;
422     high = nrow;
423     for (l = 0; l < n; l++) { /* loop over added columns */
424       if (in[l] < 0) continue;
425       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);
426       col = in[l];
427       if (v && !A->structure_only) value = roworiented ? v[l + k * n] : v[k + l * m];
428       if (!A->structure_only && value == 0.0 && ignorezeroentries && is == ADD_VALUES && row != col) continue;
429 
430       if (col <= lastcol) low = 0;
431       else high = nrow;
432       lastcol = col;
433       while (high - low > 5) {
434         t = (low + high) / 2;
435         if (rp[t] > col) high = t;
436         else low = t;
437       }
438       for (i = low; i < high; i++) {
439         if (rp[i] > col) break;
440         if (rp[i] == col) {
441           if (!A->structure_only) {
442             if (is == ADD_VALUES) {
443               ap[i] += value;
444               (void)PetscLogFlops(1.0);
445             } else ap[i] = value;
446           }
447           low = i + 1;
448           goto noinsert;
449         }
450       }
451       if (value == 0.0 && ignorezeroentries && row != col) goto noinsert;
452       if (nonew == 1) goto noinsert;
453       PetscCheck(nonew != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero at (%" PetscInt_FMT ",%" PetscInt_FMT ") in the matrix", row, col);
454       if (A->structure_only) {
455         MatSeqXAIJReallocateAIJ_structure_only(A, A->rmap->n, 1, nrow, row, col, rmax, ai, aj, rp, imax, nonew, MatScalar);
456       } else {
457         MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar);
458       }
459       N = nrow++ - 1;
460       a->nz++;
461       high++;
462       /* shift up all the later entries in this row */
463       PetscCall(PetscArraymove(rp + i + 1, rp + i, N - i + 1));
464       rp[i] = col;
465       if (!A->structure_only) {
466         PetscCall(PetscArraymove(ap + i + 1, ap + i, N - i + 1));
467         ap[i] = value;
468       }
469       low = i + 1;
470     noinsert:;
471     }
472     ailen[row] = nrow;
473   }
474   PetscCall(MatSeqAIJRestoreArray(A, &aa));
475   PetscFunctionReturn(PETSC_SUCCESS);
476 }
477 
478 static PetscErrorCode MatSetValues_SeqAIJ_SortedFullNoPreallocation(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is)
479 {
480   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
481   PetscInt   *rp, k, row;
482   PetscInt   *ai = a->i;
483   PetscInt   *aj = a->j;
484   MatScalar  *aa, *ap;
485 
486   PetscFunctionBegin;
487   PetscCheck(!A->was_assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot call on assembled matrix.");
488   PetscCheck(m * n + a->nz <= a->maxnz, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of entries in matrix will be larger than maximum nonzeros allocated for %" PetscInt_FMT " in MatSeqAIJSetTotalPreallocation()", a->maxnz);
489 
490   PetscCall(MatSeqAIJGetArray(A, &aa));
491   for (k = 0; k < m; k++) { /* loop over added rows */
492     row = im[k];
493     rp  = aj + ai[row];
494     ap  = PetscSafePointerPlusOffset(aa, ai[row]);
495 
496     PetscCall(PetscMemcpy(rp, in, n * sizeof(PetscInt)));
497     if (!A->structure_only) {
498       if (v) {
499         PetscCall(PetscMemcpy(ap, v, n * sizeof(PetscScalar)));
500         v += n;
501       } else {
502         PetscCall(PetscMemzero(ap, n * sizeof(PetscScalar)));
503       }
504     }
505     a->ilen[row]  = n;
506     a->imax[row]  = n;
507     a->i[row + 1] = a->i[row] + n;
508     a->nz += n;
509   }
510   PetscCall(MatSeqAIJRestoreArray(A, &aa));
511   PetscFunctionReturn(PETSC_SUCCESS);
512 }
513 
514 /*@
515   MatSeqAIJSetTotalPreallocation - Sets an upper bound on the total number of expected nonzeros in the matrix.
516 
517   Input Parameters:
518 + A       - the `MATSEQAIJ` matrix
519 - nztotal - bound on the number of nonzeros
520 
521   Level: advanced
522 
523   Notes:
524   This can be called if you will be provided the matrix row by row (from row zero) with sorted column indices for each row.
525   Simply call `MatSetValues()` after this call to provide the matrix entries in the usual manner. This matrix may be used
526   as always with multiple matrix assemblies.
527 
528 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MAT_SORTED_FULL`, `MatSetValues()`, `MatSeqAIJSetPreallocation()`
529 @*/
530 PetscErrorCode MatSeqAIJSetTotalPreallocation(Mat A, PetscInt nztotal)
531 {
532   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
533 
534   PetscFunctionBegin;
535   PetscCall(PetscLayoutSetUp(A->rmap));
536   PetscCall(PetscLayoutSetUp(A->cmap));
537   a->maxnz = nztotal;
538   if (!a->imax) PetscCall(PetscMalloc1(A->rmap->n, &a->imax));
539   if (!a->ilen) {
540     PetscCall(PetscMalloc1(A->rmap->n, &a->ilen));
541   } else {
542     PetscCall(PetscMemzero(a->ilen, A->rmap->n * sizeof(PetscInt)));
543   }
544 
545   /* allocate the matrix space */
546   PetscCall(PetscShmgetAllocateArray(A->rmap->n + 1, sizeof(PetscInt), (void **)&a->i));
547   PetscCall(PetscShmgetAllocateArray(nztotal, sizeof(PetscInt), (void **)&a->j));
548   a->free_ij = PETSC_TRUE;
549   if (A->structure_only) {
550     a->free_a = PETSC_FALSE;
551   } else {
552     PetscCall(PetscShmgetAllocateArray(nztotal, sizeof(PetscScalar), (void **)&a->a));
553     a->free_a = PETSC_TRUE;
554   }
555   a->i[0]           = 0;
556   A->ops->setvalues = MatSetValues_SeqAIJ_SortedFullNoPreallocation;
557   A->preallocated   = PETSC_TRUE;
558   PetscFunctionReturn(PETSC_SUCCESS);
559 }
560 
561 static PetscErrorCode MatSetValues_SeqAIJ_SortedFull(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode is)
562 {
563   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
564   PetscInt   *rp, k, row;
565   PetscInt   *ai = a->i, *ailen = a->ilen;
566   PetscInt   *aj = a->j;
567   MatScalar  *aa, *ap;
568 
569   PetscFunctionBegin;
570   PetscCall(MatSeqAIJGetArray(A, &aa));
571   for (k = 0; k < m; k++) { /* loop over added rows */
572     row = im[k];
573     PetscCheck(n <= a->imax[row], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Preallocation for row %" PetscInt_FMT " does not match number of columns provided", n);
574     rp = aj + ai[row];
575     ap = aa + ai[row];
576     if (!A->was_assembled) PetscCall(PetscMemcpy(rp, in, n * sizeof(PetscInt)));
577     if (!A->structure_only) {
578       if (v) {
579         PetscCall(PetscMemcpy(ap, v, n * sizeof(PetscScalar)));
580         v += n;
581       } else {
582         PetscCall(PetscMemzero(ap, n * sizeof(PetscScalar)));
583       }
584     }
585     ailen[row] = n;
586     a->nz += n;
587   }
588   PetscCall(MatSeqAIJRestoreArray(A, &aa));
589   PetscFunctionReturn(PETSC_SUCCESS);
590 }
591 
592 static PetscErrorCode MatGetValues_SeqAIJ(Mat A, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], PetscScalar v[])
593 {
594   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
595   PetscInt        *rp, k, low, high, t, row, nrow, i, col, l, *aj = a->j;
596   PetscInt        *ai = a->i, *ailen = a->ilen;
597   const MatScalar *ap, *aa;
598 
599   PetscFunctionBegin;
600   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
601   for (k = 0; k < m; k++) { /* loop over rows */
602     row = im[k];
603     if (row < 0) {
604       v += n;
605       continue;
606     } /* negative row */
607     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);
608     rp   = PetscSafePointerPlusOffset(aj, ai[row]);
609     ap   = PetscSafePointerPlusOffset(aa, ai[row]);
610     nrow = ailen[row];
611     for (l = 0; l < n; l++) { /* loop over columns */
612       if (in[l] < 0) {
613         v++;
614         continue;
615       } /* negative column */
616       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);
617       col  = in[l];
618       high = nrow;
619       low  = 0; /* assume unsorted */
620       while (high - low > 5) {
621         t = (low + high) / 2;
622         if (rp[t] > col) high = t;
623         else low = t;
624       }
625       for (i = low; i < high; i++) {
626         if (rp[i] > col) break;
627         if (rp[i] == col) {
628           *v++ = ap[i];
629           goto finished;
630         }
631       }
632       *v++ = 0.0;
633     finished:;
634     }
635   }
636   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
637   PetscFunctionReturn(PETSC_SUCCESS);
638 }
639 
640 static PetscErrorCode MatView_SeqAIJ_Binary(Mat mat, PetscViewer viewer)
641 {
642   Mat_SeqAIJ        *A = (Mat_SeqAIJ *)mat->data;
643   const PetscScalar *av;
644   PetscInt           header[4], M, N, m, nz, i;
645   PetscInt          *rowlens;
646 
647   PetscFunctionBegin;
648   PetscCall(PetscViewerSetUp(viewer));
649 
650   M  = mat->rmap->N;
651   N  = mat->cmap->N;
652   m  = mat->rmap->n;
653   nz = A->nz;
654 
655   /* write matrix header */
656   header[0] = MAT_FILE_CLASSID;
657   header[1] = M;
658   header[2] = N;
659   header[3] = nz;
660   PetscCall(PetscViewerBinaryWrite(viewer, header, 4, PETSC_INT));
661 
662   /* fill in and store row lengths */
663   PetscCall(PetscMalloc1(m, &rowlens));
664   for (i = 0; i < m; i++) rowlens[i] = A->i[i + 1] - A->i[i];
665   if (PetscDefined(USE_DEBUG)) {
666     PetscInt mnz = 0;
667 
668     for (i = 0; i < m; i++) mnz += rowlens[i];
669     PetscCheck(nz == mnz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Row lens %" PetscInt_FMT " do not sum to nz %" PetscInt_FMT, mnz, nz);
670   }
671   PetscCall(PetscViewerBinaryWrite(viewer, rowlens, m, PETSC_INT));
672   PetscCall(PetscFree(rowlens));
673   /* store column indices */
674   PetscCall(PetscViewerBinaryWrite(viewer, A->j, nz, PETSC_INT));
675   /* store nonzero values */
676   PetscCall(MatSeqAIJGetArrayRead(mat, &av));
677   PetscCall(PetscViewerBinaryWrite(viewer, av, nz, PETSC_SCALAR));
678   PetscCall(MatSeqAIJRestoreArrayRead(mat, &av));
679 
680   /* write block size option to the viewer's .info file */
681   PetscCall(MatView_Binary_BlockSizes(mat, viewer));
682   PetscFunctionReturn(PETSC_SUCCESS);
683 }
684 
685 static PetscErrorCode MatView_SeqAIJ_ASCII_structonly(Mat A, PetscViewer viewer)
686 {
687   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
688   PetscInt    i, k, m = A->rmap->N;
689 
690   PetscFunctionBegin;
691   PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
692   for (i = 0; i < m; i++) {
693     PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i));
694     for (k = a->i[i]; k < a->i[i + 1]; k++) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ") ", a->j[k]));
695     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
696   }
697   PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
698   PetscFunctionReturn(PETSC_SUCCESS);
699 }
700 
701 static PetscErrorCode MatView_SeqAIJ_ASCII(Mat A, PetscViewer viewer)
702 {
703   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
704   const PetscScalar *av;
705   PetscInt           i, j, m = A->rmap->n;
706   const char        *name;
707   PetscViewerFormat  format;
708 
709   PetscFunctionBegin;
710   if (A->structure_only) {
711     PetscCall(MatView_SeqAIJ_ASCII_structonly(A, viewer));
712     PetscFunctionReturn(PETSC_SUCCESS);
713   }
714 
715   PetscCall(PetscViewerGetFormat(viewer, &format));
716   // By petsc's rule, even PETSC_VIEWER_ASCII_INFO_DETAIL doesn't print matrix entries
717   if (format == PETSC_VIEWER_ASCII_FACTOR_INFO || format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(PETSC_SUCCESS);
718 
719   /* trigger copy to CPU if needed */
720   PetscCall(MatSeqAIJGetArrayRead(A, &av));
721   PetscCall(MatSeqAIJRestoreArrayRead(A, &av));
722   if (format == PETSC_VIEWER_ASCII_MATLAB) {
723     PetscInt nofinalvalue = 0;
724     if (m && ((a->i[m] == a->i[m - 1]) || (a->j[a->nz - 1] != A->cmap->n - 1))) {
725       /* Need a dummy value to ensure the dimension of the matrix. */
726       nofinalvalue = 1;
727     }
728     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
729     PetscCall(PetscViewerASCIIPrintf(viewer, "%% Size = %" PetscInt_FMT " %" PetscInt_FMT " \n", m, A->cmap->n));
730     PetscCall(PetscViewerASCIIPrintf(viewer, "%% Nonzeros = %" PetscInt_FMT " \n", a->nz));
731 #if defined(PETSC_USE_COMPLEX)
732     PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = zeros(%" PetscInt_FMT ",4);\n", a->nz + nofinalvalue));
733 #else
734     PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = zeros(%" PetscInt_FMT ",3);\n", a->nz + nofinalvalue));
735 #endif
736     PetscCall(PetscViewerASCIIPrintf(viewer, "zzz = [\n"));
737 
738     for (i = 0; i < m; i++) {
739       for (j = a->i[i]; j < a->i[i + 1]; j++) {
740 #if defined(PETSC_USE_COMPLEX)
741         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT "  %18.16e %18.16e\n", i + 1, a->j[j] + 1, (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j])));
742 #else
743         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT "  %18.16e\n", i + 1, a->j[j] + 1, (double)a->a[j]));
744 #endif
745       }
746     }
747     if (nofinalvalue) {
748 #if defined(PETSC_USE_COMPLEX)
749       PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT "  %18.16e %18.16e\n", m, A->cmap->n, 0., 0.));
750 #else
751       PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT "  %18.16e\n", m, A->cmap->n, 0.0));
752 #endif
753     }
754     PetscCall(PetscObjectGetName((PetscObject)A, &name));
755     PetscCall(PetscViewerASCIIPrintf(viewer, "];\n %s = spconvert(zzz);\n", name));
756     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
757   } else if (format == PETSC_VIEWER_ASCII_COMMON) {
758     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
759     for (i = 0; i < m; i++) {
760       PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i));
761       for (j = a->i[i]; j < a->i[i + 1]; j++) {
762 #if defined(PETSC_USE_COMPLEX)
763         if (PetscImaginaryPart(a->a[j]) > 0.0 && PetscRealPart(a->a[j]) != 0.0) {
764           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j])));
765         } else if (PetscImaginaryPart(a->a[j]) < 0.0 && PetscRealPart(a->a[j]) != 0.0) {
766           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)-PetscImaginaryPart(a->a[j])));
767         } else if (PetscRealPart(a->a[j]) != 0.0) {
768           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j])));
769         }
770 #else
771         if (a->a[j] != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j]));
772 #endif
773       }
774       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
775     }
776     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
777   } else if (format == PETSC_VIEWER_ASCII_SYMMODU) {
778     PetscInt nzd = 0, fshift = 1, *sptr;
779     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
780     PetscCall(PetscMalloc1(m + 1, &sptr));
781     for (i = 0; i < m; i++) {
782       sptr[i] = nzd + 1;
783       for (j = a->i[i]; j < a->i[i + 1]; j++) {
784         if (a->j[j] >= i) {
785 #if defined(PETSC_USE_COMPLEX)
786           if (PetscImaginaryPart(a->a[j]) != 0.0 || PetscRealPart(a->a[j]) != 0.0) nzd++;
787 #else
788           if (a->a[j] != 0.0) nzd++;
789 #endif
790         }
791       }
792     }
793     sptr[m] = nzd + 1;
794     PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT "\n\n", m, nzd));
795     for (i = 0; i < m + 1; i += 6) {
796       if (i + 4 < m) {
797         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3], sptr[i + 4], sptr[i + 5]));
798       } else if (i + 3 < m) {
799         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3], sptr[i + 4]));
800       } else if (i + 2 < m) {
801         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2], sptr[i + 3]));
802       } else if (i + 1 < m) {
803         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1], sptr[i + 2]));
804       } else if (i < m) {
805         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " %" PetscInt_FMT "\n", sptr[i], sptr[i + 1]));
806       } else {
807         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "\n", sptr[i]));
808       }
809     }
810     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
811     PetscCall(PetscFree(sptr));
812     for (i = 0; i < m; i++) {
813       for (j = a->i[i]; j < a->i[i + 1]; j++) {
814         if (a->j[j] >= i) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " ", a->j[j] + fshift));
815       }
816       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
817     }
818     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
819     for (i = 0; i < m; i++) {
820       for (j = a->i[i]; j < a->i[i + 1]; j++) {
821         if (a->j[j] >= i) {
822 #if defined(PETSC_USE_COMPLEX)
823           if (PetscImaginaryPart(a->a[j]) != 0.0 || PetscRealPart(a->a[j]) != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " %18.16e %18.16e ", (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j])));
824 #else
825           if (a->a[j] != 0.0) PetscCall(PetscViewerASCIIPrintf(viewer, " %18.16e ", (double)a->a[j]));
826 #endif
827         }
828       }
829       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
830     }
831     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
832   } else if (format == PETSC_VIEWER_ASCII_DENSE) {
833     PetscInt    cnt = 0, jcnt;
834     PetscScalar value;
835 #if defined(PETSC_USE_COMPLEX)
836     PetscBool realonly = PETSC_TRUE;
837 
838     for (i = 0; i < a->i[m]; i++) {
839       if (PetscImaginaryPart(a->a[i]) != 0.0) {
840         realonly = PETSC_FALSE;
841         break;
842       }
843     }
844 #endif
845 
846     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
847     for (i = 0; i < m; i++) {
848       jcnt = 0;
849       for (j = 0; j < A->cmap->n; j++) {
850         if (jcnt < a->i[i + 1] - a->i[i] && j == a->j[cnt]) {
851           value = a->a[cnt++];
852           jcnt++;
853         } else {
854           value = 0.0;
855         }
856 #if defined(PETSC_USE_COMPLEX)
857         if (realonly) {
858           PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e ", (double)PetscRealPart(value)));
859         } else {
860           PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e+%7.5e i ", (double)PetscRealPart(value), (double)PetscImaginaryPart(value)));
861         }
862 #else
863         PetscCall(PetscViewerASCIIPrintf(viewer, " %7.5e ", (double)value));
864 #endif
865       }
866       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
867     }
868     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
869   } else if (format == PETSC_VIEWER_ASCII_MATRIXMARKET) {
870     PetscInt fshift = 1;
871     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
872 #if defined(PETSC_USE_COMPLEX)
873     PetscCall(PetscViewerASCIIPrintf(viewer, "%%%%MatrixMarket matrix coordinate complex general\n"));
874 #else
875     PetscCall(PetscViewerASCIIPrintf(viewer, "%%%%MatrixMarket matrix coordinate real general\n"));
876 #endif
877     PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", m, A->cmap->n, a->nz));
878     for (i = 0; i < m; i++) {
879       for (j = a->i[i]; j < a->i[i + 1]; j++) {
880 #if defined(PETSC_USE_COMPLEX)
881         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %g %g\n", i + fshift, a->j[j] + fshift, (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j])));
882 #else
883         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " %" PetscInt_FMT " %g\n", i + fshift, a->j[j] + fshift, (double)a->a[j]));
884 #endif
885       }
886     }
887     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
888   } else {
889     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
890     if (A->factortype) {
891       for (i = 0; i < m; i++) {
892         PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i));
893         /* L part */
894         for (j = a->i[i]; j < a->i[i + 1]; j++) {
895 #if defined(PETSC_USE_COMPLEX)
896           if (PetscImaginaryPart(a->a[j]) > 0.0) {
897             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j])));
898           } else if (PetscImaginaryPart(a->a[j]) < 0.0) {
899             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)(-PetscImaginaryPart(a->a[j]))));
900           } else {
901             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j])));
902           }
903 #else
904           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j]));
905 #endif
906         }
907         /* diagonal */
908         j = a->diag[i];
909 #if defined(PETSC_USE_COMPLEX)
910         if (PetscImaginaryPart(a->a[j]) > 0.0) {
911           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(1 / a->a[j]), (double)PetscImaginaryPart(1 / a->a[j])));
912         } else if (PetscImaginaryPart(a->a[j]) < 0.0) {
913           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(1 / a->a[j]), (double)(-PetscImaginaryPart(1 / a->a[j]))));
914         } else {
915           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(1 / a->a[j])));
916         }
917 #else
918         PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)(1 / a->a[j])));
919 #endif
920 
921         /* U part */
922         for (j = a->diag[i + 1] + 1; j < a->diag[i]; j++) {
923 #if defined(PETSC_USE_COMPLEX)
924           if (PetscImaginaryPart(a->a[j]) > 0.0) {
925             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j])));
926           } else if (PetscImaginaryPart(a->a[j]) < 0.0) {
927             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)(-PetscImaginaryPart(a->a[j]))));
928           } else {
929             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j])));
930           }
931 #else
932           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j]));
933 #endif
934         }
935         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
936       }
937     } else {
938       for (i = 0; i < m; i++) {
939         PetscCall(PetscViewerASCIIPrintf(viewer, "row %" PetscInt_FMT ":", i));
940         for (j = a->i[i]; j < a->i[i + 1]; j++) {
941 #if defined(PETSC_USE_COMPLEX)
942           if (PetscImaginaryPart(a->a[j]) > 0.0) {
943             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g + %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)PetscImaginaryPart(a->a[j])));
944           } else if (PetscImaginaryPart(a->a[j]) < 0.0) {
945             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g - %g i)", a->j[j], (double)PetscRealPart(a->a[j]), (double)-PetscImaginaryPart(a->a[j])));
946           } else {
947             PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)PetscRealPart(a->a[j])));
948           }
949 #else
950           PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ", %g) ", a->j[j], (double)a->a[j]));
951 #endif
952         }
953         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
954       }
955     }
956     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
957   }
958   PetscCall(PetscViewerFlush(viewer));
959   PetscFunctionReturn(PETSC_SUCCESS);
960 }
961 
962 #include <petscdraw.h>
963 static PetscErrorCode MatView_SeqAIJ_Draw_Zoom(PetscDraw draw, void *Aa)
964 {
965   Mat                A = (Mat)Aa;
966   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
967   PetscInt           i, j, m = A->rmap->n;
968   int                color;
969   PetscReal          xl, yl, xr, yr, x_l, x_r, y_l, y_r;
970   PetscViewer        viewer;
971   PetscViewerFormat  format;
972   const PetscScalar *aa;
973 
974   PetscFunctionBegin;
975   PetscCall(PetscObjectQuery((PetscObject)A, "Zoomviewer", (PetscObject *)&viewer));
976   PetscCall(PetscViewerGetFormat(viewer, &format));
977   PetscCall(PetscDrawGetCoordinates(draw, &xl, &yl, &xr, &yr));
978 
979   /* loop over matrix elements drawing boxes */
980   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
981   if (format != PETSC_VIEWER_DRAW_CONTOUR) {
982     PetscDrawCollectiveBegin(draw);
983     /* Blue for negative, Cyan for zero and  Red for positive */
984     color = PETSC_DRAW_BLUE;
985     for (i = 0; i < m; i++) {
986       y_l = m - i - 1.0;
987       y_r = y_l + 1.0;
988       for (j = a->i[i]; j < a->i[i + 1]; j++) {
989         x_l = a->j[j];
990         x_r = x_l + 1.0;
991         if (PetscRealPart(aa[j]) >= 0.) continue;
992         PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color));
993       }
994     }
995     color = PETSC_DRAW_CYAN;
996     for (i = 0; i < m; i++) {
997       y_l = m - i - 1.0;
998       y_r = y_l + 1.0;
999       for (j = a->i[i]; j < a->i[i + 1]; j++) {
1000         x_l = a->j[j];
1001         x_r = x_l + 1.0;
1002         if (aa[j] != 0.) continue;
1003         PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color));
1004       }
1005     }
1006     color = PETSC_DRAW_RED;
1007     for (i = 0; i < m; i++) {
1008       y_l = m - i - 1.0;
1009       y_r = y_l + 1.0;
1010       for (j = a->i[i]; j < a->i[i + 1]; j++) {
1011         x_l = a->j[j];
1012         x_r = x_l + 1.0;
1013         if (PetscRealPart(aa[j]) <= 0.) continue;
1014         PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color));
1015       }
1016     }
1017     PetscDrawCollectiveEnd(draw);
1018   } else {
1019     /* use contour shading to indicate magnitude of values */
1020     /* first determine max of all nonzero values */
1021     PetscReal minv = 0.0, maxv = 0.0;
1022     PetscInt  nz = a->nz, count = 0;
1023     PetscDraw popup;
1024 
1025     for (i = 0; i < nz; i++) {
1026       if (PetscAbsScalar(aa[i]) > maxv) maxv = PetscAbsScalar(aa[i]);
1027     }
1028     if (minv >= maxv) maxv = minv + PETSC_SMALL;
1029     PetscCall(PetscDrawGetPopup(draw, &popup));
1030     PetscCall(PetscDrawScalePopup(popup, minv, maxv));
1031 
1032     PetscDrawCollectiveBegin(draw);
1033     for (i = 0; i < m; i++) {
1034       y_l = m - i - 1.0;
1035       y_r = y_l + 1.0;
1036       for (j = a->i[i]; j < a->i[i + 1]; j++) {
1037         x_l   = a->j[j];
1038         x_r   = x_l + 1.0;
1039         color = PetscDrawRealToColor(PetscAbsScalar(aa[count]), minv, maxv);
1040         PetscCall(PetscDrawRectangle(draw, x_l, y_l, x_r, y_r, color, color, color, color));
1041         count++;
1042       }
1043     }
1044     PetscDrawCollectiveEnd(draw);
1045   }
1046   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
1047   PetscFunctionReturn(PETSC_SUCCESS);
1048 }
1049 
1050 #include <petscdraw.h>
1051 static PetscErrorCode MatView_SeqAIJ_Draw(Mat A, PetscViewer viewer)
1052 {
1053   PetscDraw draw;
1054   PetscReal xr, yr, xl, yl, h, w;
1055   PetscBool isnull;
1056 
1057   PetscFunctionBegin;
1058   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
1059   PetscCall(PetscDrawIsNull(draw, &isnull));
1060   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
1061 
1062   xr = A->cmap->n;
1063   yr = A->rmap->n;
1064   h  = yr / 10.0;
1065   w  = xr / 10.0;
1066   xr += w;
1067   yr += h;
1068   xl = -w;
1069   yl = -h;
1070   PetscCall(PetscDrawSetCoordinates(draw, xl, yl, xr, yr));
1071   PetscCall(PetscObjectCompose((PetscObject)A, "Zoomviewer", (PetscObject)viewer));
1072   PetscCall(PetscDrawZoom(draw, MatView_SeqAIJ_Draw_Zoom, A));
1073   PetscCall(PetscObjectCompose((PetscObject)A, "Zoomviewer", NULL));
1074   PetscCall(PetscDrawSave(draw));
1075   PetscFunctionReturn(PETSC_SUCCESS);
1076 }
1077 
1078 PetscErrorCode MatView_SeqAIJ(Mat A, PetscViewer viewer)
1079 {
1080   PetscBool isascii, isbinary, isdraw;
1081 
1082   PetscFunctionBegin;
1083   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1084   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
1085   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
1086   if (isascii) PetscCall(MatView_SeqAIJ_ASCII(A, viewer));
1087   else if (isbinary) PetscCall(MatView_SeqAIJ_Binary(A, viewer));
1088   else if (isdraw) PetscCall(MatView_SeqAIJ_Draw(A, viewer));
1089   PetscCall(MatView_SeqAIJ_Inode(A, viewer));
1090   PetscFunctionReturn(PETSC_SUCCESS);
1091 }
1092 
1093 PetscErrorCode MatAssemblyEnd_SeqAIJ(Mat A, MatAssemblyType mode)
1094 {
1095   Mat_SeqAIJ *a      = (Mat_SeqAIJ *)A->data;
1096   PetscInt    fshift = 0, i, *ai = a->i, *aj = a->j, *imax = a->imax;
1097   PetscInt    m = A->rmap->n, *ip, N, *ailen = a->ilen, rmax = 0;
1098   MatScalar  *aa    = a->a, *ap;
1099   PetscReal   ratio = 0.6;
1100 
1101   PetscFunctionBegin;
1102   if (mode == MAT_FLUSH_ASSEMBLY) PetscFunctionReturn(PETSC_SUCCESS);
1103   if (A->was_assembled && A->ass_nonzerostate == A->nonzerostate) {
1104     /* we need to respect users asking to use or not the inodes routine in between matrix assemblies, e.g., via MatSetOption(A, MAT_USE_INODES, val) */
1105     PetscCall(MatAssemblyEnd_SeqAIJ_Inode(A, mode)); /* read the sparsity pattern */
1106     PetscFunctionReturn(PETSC_SUCCESS);
1107   }
1108 
1109   if (m) rmax = ailen[0]; /* determine row with most nonzeros */
1110   for (i = 1; i < m; i++) {
1111     /* move each row back by the amount of empty slots (fshift) before it*/
1112     fshift += imax[i - 1] - ailen[i - 1];
1113     rmax = PetscMax(rmax, ailen[i]);
1114     if (fshift) {
1115       ip = aj + ai[i];
1116       ap = aa + ai[i];
1117       N  = ailen[i];
1118       PetscCall(PetscArraymove(ip - fshift, ip, N));
1119       if (!A->structure_only) PetscCall(PetscArraymove(ap - fshift, ap, N));
1120     }
1121     ai[i] = ai[i - 1] + ailen[i - 1];
1122   }
1123   if (m) {
1124     fshift += imax[m - 1] - ailen[m - 1];
1125     ai[m] = ai[m - 1] + ailen[m - 1];
1126   }
1127   /* reset ilen and imax for each row */
1128   a->nonzerorowcnt = 0;
1129   if (A->structure_only) {
1130     PetscCall(PetscFree(a->imax));
1131     PetscCall(PetscFree(a->ilen));
1132   } else { /* !A->structure_only */
1133     for (i = 0; i < m; i++) {
1134       ailen[i] = imax[i] = ai[i + 1] - ai[i];
1135       a->nonzerorowcnt += ((ai[i + 1] - ai[i]) > 0);
1136     }
1137   }
1138   a->nz = ai[m];
1139   PetscCheck(!fshift || a->nounused != -1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unused space detected in matrix: %" PetscInt_FMT " X %" PetscInt_FMT ", %" PetscInt_FMT " unneeded", m, A->cmap->n, fshift);
1140   PetscCall(MatMarkDiagonal_SeqAIJ(A)); // since diagonal info is used a lot, it is helpful to set them up at the end of assembly
1141   PetscCall(PetscInfo(A, "Matrix size: %" PetscInt_FMT " X %" PetscInt_FMT "; storage space: %" PetscInt_FMT " unneeded,%" PetscInt_FMT " used\n", m, A->cmap->n, fshift, a->nz));
1142   PetscCall(PetscInfo(A, "Number of mallocs during MatSetValues() is %" PetscInt_FMT "\n", a->reallocs));
1143   PetscCall(PetscInfo(A, "Maximum nonzeros in any row is %" PetscInt_FMT "\n", rmax));
1144 
1145   A->info.mallocs += a->reallocs;
1146   a->reallocs         = 0;
1147   A->info.nz_unneeded = (PetscReal)fshift;
1148   a->rmax             = rmax;
1149 
1150   if (!A->structure_only) PetscCall(MatCheckCompressedRow(A, a->nonzerorowcnt, &a->compressedrow, a->i, m, ratio));
1151   PetscCall(MatAssemblyEnd_SeqAIJ_Inode(A, mode));
1152   PetscFunctionReturn(PETSC_SUCCESS);
1153 }
1154 
1155 static PetscErrorCode MatRealPart_SeqAIJ(Mat A)
1156 {
1157   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
1158   PetscInt    i, nz = a->nz;
1159   MatScalar  *aa;
1160 
1161   PetscFunctionBegin;
1162   PetscCall(MatSeqAIJGetArray(A, &aa));
1163   for (i = 0; i < nz; i++) aa[i] = PetscRealPart(aa[i]);
1164   PetscCall(MatSeqAIJRestoreArray(A, &aa));
1165   PetscFunctionReturn(PETSC_SUCCESS);
1166 }
1167 
1168 static PetscErrorCode MatImaginaryPart_SeqAIJ(Mat A)
1169 {
1170   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
1171   PetscInt    i, nz = a->nz;
1172   MatScalar  *aa;
1173 
1174   PetscFunctionBegin;
1175   PetscCall(MatSeqAIJGetArray(A, &aa));
1176   for (i = 0; i < nz; i++) aa[i] = PetscImaginaryPart(aa[i]);
1177   PetscCall(MatSeqAIJRestoreArray(A, &aa));
1178   PetscFunctionReturn(PETSC_SUCCESS);
1179 }
1180 
1181 PetscErrorCode MatZeroEntries_SeqAIJ(Mat A)
1182 {
1183   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
1184   MatScalar  *aa;
1185 
1186   PetscFunctionBegin;
1187   PetscCall(MatSeqAIJGetArrayWrite(A, &aa));
1188   PetscCall(PetscArrayzero(aa, a->i[A->rmap->n]));
1189   PetscCall(MatSeqAIJRestoreArrayWrite(A, &aa));
1190   PetscFunctionReturn(PETSC_SUCCESS);
1191 }
1192 
1193 static PetscErrorCode MatReset_SeqAIJ(Mat A)
1194 {
1195   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
1196 
1197   PetscFunctionBegin;
1198   if (A->hash_active) {
1199     A->ops[0] = a->cops;
1200     PetscCall(PetscHMapIJVDestroy(&a->ht));
1201     PetscCall(PetscFree(a->dnz));
1202     A->hash_active = PETSC_FALSE;
1203   }
1204 
1205   PetscCall(PetscLogObjectState((PetscObject)A, "Rows=%" PetscInt_FMT ", Cols=%" PetscInt_FMT ", NZ=%" PetscInt_FMT, A->rmap->n, A->cmap->n, a->nz));
1206   PetscCall(MatSeqXAIJFreeAIJ(A, &a->a, &a->j, &a->i));
1207   PetscCall(ISDestroy(&a->row));
1208   PetscCall(ISDestroy(&a->col));
1209   PetscCall(PetscFree(a->diag));
1210   PetscCall(PetscFree(a->ibdiag));
1211   PetscCall(PetscFree(a->imax));
1212   PetscCall(PetscFree(a->ilen));
1213   PetscCall(PetscFree(a->ipre));
1214   PetscCall(PetscFree3(a->idiag, a->mdiag, a->ssor_work));
1215   PetscCall(PetscFree(a->solve_work));
1216   PetscCall(ISDestroy(&a->icol));
1217   PetscCall(PetscFree(a->saved_values));
1218   a->compressedrow.use = PETSC_FALSE;
1219   PetscCall(PetscFree2(a->compressedrow.i, a->compressedrow.rindex));
1220   PetscCall(MatDestroy_SeqAIJ_Inode(A));
1221   PetscFunctionReturn(PETSC_SUCCESS);
1222 }
1223 
1224 static PetscErrorCode MatResetHash_SeqAIJ(Mat A)
1225 {
1226   PetscFunctionBegin;
1227   PetscCall(MatReset_SeqAIJ(A));
1228   PetscCall(MatCreate_SeqAIJ_Inode(A));
1229   PetscCall(MatSetUp_Seq_Hash(A));
1230   A->nonzerostate++;
1231   PetscFunctionReturn(PETSC_SUCCESS);
1232 }
1233 
1234 PetscErrorCode MatDestroy_SeqAIJ(Mat A)
1235 {
1236   PetscFunctionBegin;
1237   PetscCall(MatReset_SeqAIJ(A));
1238   PetscCall(PetscFree(A->data));
1239 
1240   /* MatMatMultNumeric_SeqAIJ_SeqAIJ_Sorted may allocate this.
1241      That function is so heavily used (sometimes in an hidden way through multnumeric function pointers)
1242      that is hard to properly add this data to the MatProduct data. We free it here to avoid
1243      users reusing the matrix object with different data to incur in obscure segmentation faults
1244      due to different matrix sizes */
1245   PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc__ab_dense", NULL));
1246 
1247   PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL));
1248   PetscCall(PetscObjectComposeFunction((PetscObject)A, "PetscMatlabEnginePut_C", NULL));
1249   PetscCall(PetscObjectComposeFunction((PetscObject)A, "PetscMatlabEngineGet_C", NULL));
1250   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetColumnIndices_C", NULL));
1251   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatStoreValues_C", NULL));
1252   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatRetrieveValues_C", NULL));
1253   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqsbaij_C", NULL));
1254   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqbaij_C", NULL));
1255   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijperm_C", NULL));
1256   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijsell_C", NULL));
1257 #if defined(PETSC_HAVE_MKL_SPARSE)
1258   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijmkl_C", NULL));
1259 #endif
1260 #if defined(PETSC_HAVE_CUDA)
1261   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijcusparse_C", NULL));
1262   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", NULL));
1263   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", NULL));
1264 #endif
1265 #if defined(PETSC_HAVE_HIP)
1266   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijhipsparse_C", NULL));
1267   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijhipsparse_seqaij_C", NULL));
1268   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaijhipsparse_C", NULL));
1269 #endif
1270 #if defined(PETSC_HAVE_KOKKOS_KERNELS)
1271   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijkokkos_C", NULL));
1272 #endif
1273   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijcrl_C", NULL));
1274 #if defined(PETSC_HAVE_ELEMENTAL)
1275   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_elemental_C", NULL));
1276 #endif
1277 #if defined(PETSC_HAVE_SCALAPACK) && (defined(PETSC_USE_REAL_SINGLE) || defined(PETSC_USE_REAL_DOUBLE))
1278   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_scalapack_C", NULL));
1279 #endif
1280 #if defined(PETSC_HAVE_HYPRE)
1281   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_hypre_C", NULL));
1282   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", NULL));
1283 #endif
1284   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqdense_C", NULL));
1285   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqsell_C", NULL));
1286   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_is_C", NULL));
1287   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatIsTranspose_C", NULL));
1288   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatIsHermitianTranspose_C", NULL));
1289   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetPreallocation_C", NULL));
1290   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatResetPreallocation_C", NULL));
1291   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatResetHash_C", NULL));
1292   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJSetPreallocationCSR_C", NULL));
1293   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatReorderForNonzeroDiagonal_C", NULL));
1294   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_is_seqaij_C", NULL));
1295   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqdense_seqaij_C", NULL));
1296   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaij_seqaij_C", NULL));
1297   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSeqAIJKron_C", NULL));
1298   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL));
1299   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL));
1300   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatFactorGetSolverType_C", NULL));
1301   /* these calls do not belong here: the subclasses Duplicate/Destroy are wrong */
1302   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaijsell_seqaij_C", NULL));
1303   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaijperm_seqaij_C", NULL));
1304   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_seqaij_seqaijviennacl_C", NULL));
1305   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijviennacl_seqdense_C", NULL));
1306   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_seqaijviennacl_seqaij_C", NULL));
1307   PetscFunctionReturn(PETSC_SUCCESS);
1308 }
1309 
1310 PetscErrorCode MatSetOption_SeqAIJ(Mat A, MatOption op, PetscBool flg)
1311 {
1312   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
1313 
1314   PetscFunctionBegin;
1315   switch (op) {
1316   case MAT_ROW_ORIENTED:
1317     a->roworiented = flg;
1318     break;
1319   case MAT_KEEP_NONZERO_PATTERN:
1320     a->keepnonzeropattern = flg;
1321     break;
1322   case MAT_NEW_NONZERO_LOCATIONS:
1323     a->nonew = (flg ? 0 : 1);
1324     break;
1325   case MAT_NEW_NONZERO_LOCATION_ERR:
1326     a->nonew = (flg ? -1 : 0);
1327     break;
1328   case MAT_NEW_NONZERO_ALLOCATION_ERR:
1329     a->nonew = (flg ? -2 : 0);
1330     break;
1331   case MAT_UNUSED_NONZERO_LOCATION_ERR:
1332     a->nounused = (flg ? -1 : 0);
1333     break;
1334   case MAT_IGNORE_ZERO_ENTRIES:
1335     a->ignorezeroentries = flg;
1336     break;
1337   case MAT_USE_INODES:
1338     PetscCall(MatSetOption_SeqAIJ_Inode(A, MAT_USE_INODES, flg));
1339     break;
1340   case MAT_SUBMAT_SINGLEIS:
1341     A->submat_singleis = flg;
1342     break;
1343   case MAT_SORTED_FULL:
1344     if (flg) A->ops->setvalues = MatSetValues_SeqAIJ_SortedFull;
1345     else A->ops->setvalues = MatSetValues_SeqAIJ;
1346     break;
1347   case MAT_FORM_EXPLICIT_TRANSPOSE:
1348     A->form_explicit_transpose = flg;
1349     break;
1350   default:
1351     break;
1352   }
1353   PetscFunctionReturn(PETSC_SUCCESS);
1354 }
1355 
1356 PETSC_INTERN PetscErrorCode MatGetDiagonal_SeqAIJ(Mat A, Vec v)
1357 {
1358   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
1359   PetscInt           i, j, n, *ai = a->i, *aj = a->j;
1360   PetscScalar       *x;
1361   const PetscScalar *aa;
1362 
1363   PetscFunctionBegin;
1364   PetscCall(VecGetLocalSize(v, &n));
1365   PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector");
1366   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
1367   if (A->factortype == MAT_FACTOR_ILU || A->factortype == MAT_FACTOR_LU) {
1368     PetscInt *diag = a->diag;
1369     PetscCall(VecGetArrayWrite(v, &x));
1370     for (i = 0; i < n; i++) x[i] = 1.0 / aa[diag[i]];
1371     PetscCall(VecRestoreArrayWrite(v, &x));
1372     PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
1373     PetscFunctionReturn(PETSC_SUCCESS);
1374   }
1375 
1376   PetscCall(VecGetArrayWrite(v, &x));
1377   for (i = 0; i < n; i++) {
1378     x[i] = 0.0;
1379     for (j = ai[i]; j < ai[i + 1]; j++) {
1380       if (aj[j] == i) {
1381         x[i] = aa[j];
1382         break;
1383       }
1384     }
1385   }
1386   PetscCall(VecRestoreArrayWrite(v, &x));
1387   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
1388   PetscFunctionReturn(PETSC_SUCCESS);
1389 }
1390 
1391 #include <../src/mat/impls/aij/seq/ftn-kernels/fmult.h>
1392 PetscErrorCode MatMultTransposeAdd_SeqAIJ(Mat A, Vec xx, Vec zz, Vec yy)
1393 {
1394   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
1395   const MatScalar   *aa;
1396   PetscScalar       *y;
1397   const PetscScalar *x;
1398   PetscInt           m = A->rmap->n;
1399 #if !defined(PETSC_USE_FORTRAN_KERNEL_MULTTRANSPOSEAIJ)
1400   const MatScalar  *v;
1401   PetscScalar       alpha;
1402   PetscInt          n, i, j;
1403   const PetscInt   *idx, *ii, *ridx = NULL;
1404   Mat_CompressedRow cprow    = a->compressedrow;
1405   PetscBool         usecprow = cprow.use;
1406 #endif
1407 
1408   PetscFunctionBegin;
1409   if (zz != yy) PetscCall(VecCopy(zz, yy));
1410   PetscCall(VecGetArrayRead(xx, &x));
1411   PetscCall(VecGetArray(yy, &y));
1412   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
1413 
1414 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTTRANSPOSEAIJ)
1415   fortranmulttransposeaddaij_(&m, x, a->i, a->j, aa, y);
1416 #else
1417   if (usecprow) {
1418     m    = cprow.nrows;
1419     ii   = cprow.i;
1420     ridx = cprow.rindex;
1421   } else {
1422     ii = a->i;
1423   }
1424   for (i = 0; i < m; i++) {
1425     idx = a->j + ii[i];
1426     v   = aa + ii[i];
1427     n   = ii[i + 1] - ii[i];
1428     if (usecprow) {
1429       alpha = x[ridx[i]];
1430     } else {
1431       alpha = x[i];
1432     }
1433     for (j = 0; j < n; j++) y[idx[j]] += alpha * v[j];
1434   }
1435 #endif
1436   PetscCall(PetscLogFlops(2.0 * a->nz));
1437   PetscCall(VecRestoreArrayRead(xx, &x));
1438   PetscCall(VecRestoreArray(yy, &y));
1439   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
1440   PetscFunctionReturn(PETSC_SUCCESS);
1441 }
1442 
1443 PetscErrorCode MatMultTranspose_SeqAIJ(Mat A, Vec xx, Vec yy)
1444 {
1445   PetscFunctionBegin;
1446   PetscCall(VecSet(yy, 0.0));
1447   PetscCall(MatMultTransposeAdd_SeqAIJ(A, xx, yy, yy));
1448   PetscFunctionReturn(PETSC_SUCCESS);
1449 }
1450 
1451 #include <../src/mat/impls/aij/seq/ftn-kernels/fmult.h>
1452 
1453 PetscErrorCode MatMult_SeqAIJ(Mat A, Vec xx, Vec yy)
1454 {
1455   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
1456   PetscScalar       *y;
1457   const PetscScalar *x;
1458   const MatScalar   *a_a;
1459   PetscInt           m = A->rmap->n;
1460   const PetscInt    *ii, *ridx = NULL;
1461   PetscBool          usecprow = a->compressedrow.use;
1462 
1463 #if defined(PETSC_HAVE_PRAGMA_DISJOINT)
1464   #pragma disjoint(*x, *y, *aa)
1465 #endif
1466 
1467   PetscFunctionBegin;
1468   if (a->inode.use && a->inode.checked) {
1469     PetscCall(MatMult_SeqAIJ_Inode(A, xx, yy));
1470     PetscFunctionReturn(PETSC_SUCCESS);
1471   }
1472   PetscCall(MatSeqAIJGetArrayRead(A, &a_a));
1473   PetscCall(VecGetArrayRead(xx, &x));
1474   PetscCall(VecGetArray(yy, &y));
1475   ii = a->i;
1476   if (usecprow) { /* use compressed row format */
1477     PetscCall(PetscArrayzero(y, m));
1478     m    = a->compressedrow.nrows;
1479     ii   = a->compressedrow.i;
1480     ridx = a->compressedrow.rindex;
1481     PetscPragmaUseOMPKernels(parallel for)
1482     for (PetscInt i = 0; i < m; i++) {
1483       PetscInt           n   = ii[i + 1] - ii[i];
1484       const PetscInt    *aj  = a->j + ii[i];
1485       const PetscScalar *aa  = a_a + ii[i];
1486       PetscScalar        sum = 0.0;
1487       PetscSparseDensePlusDot(sum, x, aa, aj, n);
1488       /* for (j=0; j<n; j++) sum += (*aa++)*x[*aj++]; */
1489       y[ridx[i]] = sum;
1490     }
1491   } else { /* do not use compressed row format */
1492 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTAIJ)
1493     fortranmultaij_(&m, x, ii, a->j, a_a, y);
1494 #else
1495     PetscPragmaUseOMPKernels(parallel for)
1496     for (PetscInt i = 0; i < m; i++) {
1497       PetscInt           n   = ii[i + 1] - ii[i];
1498       const PetscInt    *aj  = a->j + ii[i];
1499       const PetscScalar *aa  = a_a + ii[i];
1500       PetscScalar        sum = 0.0;
1501       PetscSparseDensePlusDot(sum, x, aa, aj, n);
1502       y[i] = sum;
1503     }
1504 #endif
1505   }
1506   PetscCall(PetscLogFlops(2.0 * a->nz - a->nonzerorowcnt));
1507   PetscCall(VecRestoreArrayRead(xx, &x));
1508   PetscCall(VecRestoreArray(yy, &y));
1509   PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a));
1510   PetscFunctionReturn(PETSC_SUCCESS);
1511 }
1512 
1513 // HACK!!!!! Used by src/mat/tests/ex170.c
1514 PETSC_EXTERN PetscErrorCode MatMultMax_SeqAIJ(Mat A, Vec xx, Vec yy)
1515 {
1516   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
1517   PetscScalar       *y;
1518   const PetscScalar *x;
1519   const MatScalar   *aa, *a_a;
1520   PetscInt           m = A->rmap->n;
1521   const PetscInt    *aj, *ii, *ridx   = NULL;
1522   PetscInt           n, i, nonzerorow = 0;
1523   PetscScalar        sum;
1524   PetscBool          usecprow = a->compressedrow.use;
1525 
1526 #if defined(PETSC_HAVE_PRAGMA_DISJOINT)
1527   #pragma disjoint(*x, *y, *aa)
1528 #endif
1529 
1530   PetscFunctionBegin;
1531   PetscCall(MatSeqAIJGetArrayRead(A, &a_a));
1532   PetscCall(VecGetArrayRead(xx, &x));
1533   PetscCall(VecGetArray(yy, &y));
1534   if (usecprow) { /* use compressed row format */
1535     m    = a->compressedrow.nrows;
1536     ii   = a->compressedrow.i;
1537     ridx = a->compressedrow.rindex;
1538     for (i = 0; i < m; i++) {
1539       n   = ii[i + 1] - ii[i];
1540       aj  = a->j + ii[i];
1541       aa  = a_a + ii[i];
1542       sum = 0.0;
1543       nonzerorow += (n > 0);
1544       PetscSparseDenseMaxDot(sum, x, aa, aj, n);
1545       /* for (j=0; j<n; j++) sum += (*aa++)*x[*aj++]; */
1546       y[*ridx++] = sum;
1547     }
1548   } else { /* do not use compressed row format */
1549     ii = a->i;
1550     for (i = 0; i < m; i++) {
1551       n   = ii[i + 1] - ii[i];
1552       aj  = a->j + ii[i];
1553       aa  = a_a + ii[i];
1554       sum = 0.0;
1555       nonzerorow += (n > 0);
1556       PetscSparseDenseMaxDot(sum, x, aa, aj, n);
1557       y[i] = sum;
1558     }
1559   }
1560   PetscCall(PetscLogFlops(2.0 * a->nz - nonzerorow));
1561   PetscCall(VecRestoreArrayRead(xx, &x));
1562   PetscCall(VecRestoreArray(yy, &y));
1563   PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a));
1564   PetscFunctionReturn(PETSC_SUCCESS);
1565 }
1566 
1567 // HACK!!!!! Used by src/mat/tests/ex170.c
1568 PETSC_EXTERN PetscErrorCode MatMultAddMax_SeqAIJ(Mat A, Vec xx, Vec yy, Vec zz)
1569 {
1570   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
1571   PetscScalar       *y, *z;
1572   const PetscScalar *x;
1573   const MatScalar   *aa, *a_a;
1574   PetscInt           m = A->rmap->n, *aj, *ii;
1575   PetscInt           n, i, *ridx = NULL;
1576   PetscScalar        sum;
1577   PetscBool          usecprow = a->compressedrow.use;
1578 
1579   PetscFunctionBegin;
1580   PetscCall(MatSeqAIJGetArrayRead(A, &a_a));
1581   PetscCall(VecGetArrayRead(xx, &x));
1582   PetscCall(VecGetArrayPair(yy, zz, &y, &z));
1583   if (usecprow) { /* use compressed row format */
1584     if (zz != yy) PetscCall(PetscArraycpy(z, y, m));
1585     m    = a->compressedrow.nrows;
1586     ii   = a->compressedrow.i;
1587     ridx = a->compressedrow.rindex;
1588     for (i = 0; i < m; i++) {
1589       n   = ii[i + 1] - ii[i];
1590       aj  = a->j + ii[i];
1591       aa  = a_a + ii[i];
1592       sum = y[*ridx];
1593       PetscSparseDenseMaxDot(sum, x, aa, aj, n);
1594       z[*ridx++] = sum;
1595     }
1596   } else { /* do not use compressed row format */
1597     ii = a->i;
1598     for (i = 0; i < m; i++) {
1599       n   = ii[i + 1] - ii[i];
1600       aj  = a->j + ii[i];
1601       aa  = a_a + ii[i];
1602       sum = y[i];
1603       PetscSparseDenseMaxDot(sum, x, aa, aj, n);
1604       z[i] = sum;
1605     }
1606   }
1607   PetscCall(PetscLogFlops(2.0 * a->nz));
1608   PetscCall(VecRestoreArrayRead(xx, &x));
1609   PetscCall(VecRestoreArrayPair(yy, zz, &y, &z));
1610   PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a));
1611   PetscFunctionReturn(PETSC_SUCCESS);
1612 }
1613 
1614 #include <../src/mat/impls/aij/seq/ftn-kernels/fmultadd.h>
1615 PetscErrorCode MatMultAdd_SeqAIJ(Mat A, Vec xx, Vec yy, Vec zz)
1616 {
1617   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
1618   PetscScalar       *y, *z;
1619   const PetscScalar *x;
1620   const MatScalar   *a_a;
1621   const PetscInt    *ii, *ridx = NULL;
1622   PetscInt           m        = A->rmap->n;
1623   PetscBool          usecprow = a->compressedrow.use;
1624 
1625   PetscFunctionBegin;
1626   if (a->inode.use && a->inode.checked) {
1627     PetscCall(MatMultAdd_SeqAIJ_Inode(A, xx, yy, zz));
1628     PetscFunctionReturn(PETSC_SUCCESS);
1629   }
1630   PetscCall(MatSeqAIJGetArrayRead(A, &a_a));
1631   PetscCall(VecGetArrayRead(xx, &x));
1632   PetscCall(VecGetArrayPair(yy, zz, &y, &z));
1633   if (usecprow) { /* use compressed row format */
1634     if (zz != yy) PetscCall(PetscArraycpy(z, y, m));
1635     m    = a->compressedrow.nrows;
1636     ii   = a->compressedrow.i;
1637     ridx = a->compressedrow.rindex;
1638     for (PetscInt i = 0; i < m; i++) {
1639       PetscInt           n   = ii[i + 1] - ii[i];
1640       const PetscInt    *aj  = a->j + ii[i];
1641       const PetscScalar *aa  = a_a + ii[i];
1642       PetscScalar        sum = y[*ridx];
1643       PetscSparseDensePlusDot(sum, x, aa, aj, n);
1644       z[*ridx++] = sum;
1645     }
1646   } else { /* do not use compressed row format */
1647     ii = a->i;
1648 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTADDAIJ)
1649     fortranmultaddaij_(&m, x, ii, a->j, a_a, y, z);
1650 #else
1651     PetscPragmaUseOMPKernels(parallel for)
1652     for (PetscInt i = 0; i < m; i++) {
1653       PetscInt           n   = ii[i + 1] - ii[i];
1654       const PetscInt    *aj  = a->j + ii[i];
1655       const PetscScalar *aa  = a_a + ii[i];
1656       PetscScalar        sum = y[i];
1657       PetscSparseDensePlusDot(sum, x, aa, aj, n);
1658       z[i] = sum;
1659     }
1660 #endif
1661   }
1662   PetscCall(PetscLogFlops(2.0 * a->nz));
1663   PetscCall(VecRestoreArrayRead(xx, &x));
1664   PetscCall(VecRestoreArrayPair(yy, zz, &y, &z));
1665   PetscCall(MatSeqAIJRestoreArrayRead(A, &a_a));
1666   PetscFunctionReturn(PETSC_SUCCESS);
1667 }
1668 
1669 /*
1670      Adds diagonal pointers to sparse matrix nonzero structure and determines if all diagonal entries are present
1671 */
1672 PetscErrorCode MatMarkDiagonal_SeqAIJ(Mat A)
1673 {
1674   Mat_SeqAIJ    *a = (Mat_SeqAIJ *)A->data;
1675   const PetscInt m = A->rmap->n;
1676 
1677   PetscFunctionBegin;
1678   if (a->diag && a->diagNonzeroState == A->nonzerostate) PetscFunctionReturn(PETSC_SUCCESS);
1679   if (!a->diag) PetscCall(PetscMalloc1(m, &a->diag));
1680   a->diagDense = PETSC_TRUE;
1681 
1682   for (PetscInt i = 0; i < A->rmap->n; i++) {
1683     PetscBool found = PETSC_FALSE;
1684 
1685     a->diag[i] = a->i[i + 1];
1686     for (PetscInt j = a->i[i]; j < a->i[i + 1]; j++) {
1687       if (a->j[j] == i) {
1688         a->diag[i] = j;
1689         found      = PETSC_TRUE;
1690         break;
1691       }
1692     }
1693     if (!found) a->diagDense = PETSC_FALSE;
1694   }
1695   a->diagNonzeroState = A->nonzerostate;
1696   PetscFunctionReturn(PETSC_SUCCESS);
1697 }
1698 
1699 static PetscErrorCode MatShift_SeqAIJ(Mat A, PetscScalar v)
1700 {
1701   Mat_SeqAIJ     *a    = (Mat_SeqAIJ *)A->data;
1702   const PetscInt *diag = (const PetscInt *)a->diag;
1703   const PetscInt *ii   = (const PetscInt *)a->i;
1704 
1705   PetscFunctionBegin;
1706   if (!A->preallocated || !a->nz) {
1707     PetscCall(MatSeqAIJSetPreallocation(A, 1, NULL));
1708     PetscCall(MatShift_Basic(A, v));
1709     PetscFunctionReturn(PETSC_SUCCESS);
1710   }
1711 
1712   if (a->diagDense) {
1713     PetscCall(MatShift_Basic(A, v));
1714   } else {
1715     PetscScalar       *olda = a->a; /* preserve pointers to current matrix nonzeros structure and values */
1716     PetscInt          *oldj = a->j, *oldi = a->i;
1717     PetscBool          free_a = a->free_a, free_ij = a->free_ij;
1718     const PetscScalar *Aa;
1719     PetscInt          *mdiag = NULL;
1720 
1721     PetscCall(PetscCalloc1(A->rmap->n, &mdiag));
1722     for (PetscInt i = 0; i < A->rmap->n; i++) {
1723       if (i < A->cmap->n && diag[i] >= ii[i + 1]) { /* 'out of range' rows never have diagonals */
1724         mdiag[i] = 1;
1725       }
1726     }
1727     PetscCall(MatSeqAIJGetArrayRead(A, &Aa)); // sync the host
1728     PetscCall(MatSeqAIJRestoreArrayRead(A, &Aa));
1729 
1730     a->a = NULL;
1731     a->j = NULL;
1732     a->i = NULL;
1733     /* increase the values in imax for each row where a diagonal is being inserted then reallocate the matrix data structures */
1734     for (PetscInt i = 0; i < PetscMin(A->rmap->n, A->cmap->n); i++) a->imax[i] += mdiag[i];
1735     PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(A, 0, a->imax));
1736 
1737     /* copy old values into new matrix data structure */
1738     for (PetscInt i = 0; i < A->rmap->n; i++) {
1739       PetscCall(MatSetValues(A, 1, &i, a->imax[i] - mdiag[i], &oldj[oldi[i]], &olda[oldi[i]], ADD_VALUES));
1740       if (i < A->cmap->n) PetscCall(MatSetValue(A, i, i, v, ADD_VALUES));
1741     }
1742     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1743     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1744     if (free_a) PetscCall(PetscShmgetDeallocateArray((void **)&olda));
1745     if (free_ij) PetscCall(PetscShmgetDeallocateArray((void **)&oldj));
1746     if (free_ij) PetscCall(PetscShmgetDeallocateArray((void **)&oldi));
1747     PetscCall(PetscFree(mdiag));
1748     PetscCall(MatMarkDiagonal_SeqAIJ(A));
1749   }
1750   PetscFunctionReturn(PETSC_SUCCESS);
1751 }
1752 
1753 /*
1754      Checks for missing diagonals
1755 */
1756 PetscErrorCode MatMissingDiagonal_SeqAIJ(Mat A, PetscBool *missing, PetscInt *d)
1757 {
1758   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
1759   PetscInt   *diag, *ii = a->i, i;
1760 
1761   PetscFunctionBegin;
1762   *missing = PETSC_FALSE;
1763   if (A->rmap->n > 0 && !ii) {
1764     *missing = PETSC_TRUE;
1765     if (d) *d = 0;
1766     PetscCall(PetscInfo(A, "Matrix has no entries therefore is missing diagonal\n"));
1767   } else {
1768     PetscInt n;
1769     n    = PetscMin(A->rmap->n, A->cmap->n);
1770     diag = a->diag;
1771     for (i = 0; i < n; i++) {
1772       if (diag[i] >= ii[i + 1]) {
1773         *missing = PETSC_TRUE;
1774         if (d) *d = i;
1775         PetscCall(PetscInfo(A, "Matrix is missing diagonal number %" PetscInt_FMT "\n", i));
1776         break;
1777       }
1778     }
1779   }
1780   PetscFunctionReturn(PETSC_SUCCESS);
1781 }
1782 
1783 #include <petscblaslapack.h>
1784 #include <petsc/private/kernels/blockinvert.h>
1785 
1786 /*
1787     Note that values is allocated externally by the PC and then passed into this routine
1788 */
1789 static PetscErrorCode MatInvertVariableBlockDiagonal_SeqAIJ(Mat A, PetscInt nblocks, const PetscInt *bsizes, PetscScalar *diag)
1790 {
1791   PetscInt        n = A->rmap->n, i, ncnt = 0, *indx, j, bsizemax = 0, *v_pivots;
1792   PetscBool       allowzeropivot, zeropivotdetected = PETSC_FALSE;
1793   const PetscReal shift = 0.0;
1794   PetscInt        ipvt[5];
1795   PetscCount      flops = 0;
1796   PetscScalar     work[25], *v_work;
1797 
1798   PetscFunctionBegin;
1799   allowzeropivot = PetscNot(A->erroriffailure);
1800   for (i = 0; i < nblocks; i++) ncnt += bsizes[i];
1801   PetscCheck(ncnt == n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total blocksizes %" PetscInt_FMT " doesn't match number matrix rows %" PetscInt_FMT, ncnt, n);
1802   for (i = 0; i < nblocks; i++) bsizemax = PetscMax(bsizemax, bsizes[i]);
1803   PetscCall(PetscMalloc1(bsizemax, &indx));
1804   if (bsizemax > 7) PetscCall(PetscMalloc2(bsizemax, &v_work, bsizemax, &v_pivots));
1805   ncnt = 0;
1806   for (i = 0; i < nblocks; i++) {
1807     for (j = 0; j < bsizes[i]; j++) indx[j] = ncnt + j;
1808     PetscCall(MatGetValues(A, bsizes[i], indx, bsizes[i], indx, diag));
1809     switch (bsizes[i]) {
1810     case 1:
1811       *diag = 1.0 / (*diag);
1812       break;
1813     case 2:
1814       PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected));
1815       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
1816       PetscCall(PetscKernel_A_gets_transpose_A_2(diag));
1817       break;
1818     case 3:
1819       PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected));
1820       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
1821       PetscCall(PetscKernel_A_gets_transpose_A_3(diag));
1822       break;
1823     case 4:
1824       PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected));
1825       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
1826       PetscCall(PetscKernel_A_gets_transpose_A_4(diag));
1827       break;
1828     case 5:
1829       PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected));
1830       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
1831       PetscCall(PetscKernel_A_gets_transpose_A_5(diag));
1832       break;
1833     case 6:
1834       PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected));
1835       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
1836       PetscCall(PetscKernel_A_gets_transpose_A_6(diag));
1837       break;
1838     case 7:
1839       PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected));
1840       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
1841       PetscCall(PetscKernel_A_gets_transpose_A_7(diag));
1842       break;
1843     default:
1844       PetscCall(PetscKernel_A_gets_inverse_A(bsizes[i], diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected));
1845       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
1846       PetscCall(PetscKernel_A_gets_transpose_A_N(diag, bsizes[i]));
1847     }
1848     ncnt += bsizes[i];
1849     diag += bsizes[i] * bsizes[i];
1850     flops += 2 * PetscPowInt64(bsizes[i], 3) / 3;
1851   }
1852   PetscCall(PetscLogFlops(flops));
1853   if (bsizemax > 7) PetscCall(PetscFree2(v_work, v_pivots));
1854   PetscCall(PetscFree(indx));
1855   PetscFunctionReturn(PETSC_SUCCESS);
1856 }
1857 
1858 /*
1859    Negative shift indicates do not generate an error if there is a zero diagonal, just invert it anyways
1860 */
1861 static PetscErrorCode MatInvertDiagonalForSOR_SeqAIJ(Mat A, PetscScalar omega, PetscScalar fshift)
1862 {
1863   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
1864   PetscInt         i, *diag, m = A->rmap->n;
1865   const MatScalar *v;
1866   PetscScalar     *idiag, *mdiag;
1867 
1868   PetscFunctionBegin;
1869   if (a->idiagState == ((PetscObject)A)->state && a->omega == omega && a->fshift == fshift) PetscFunctionReturn(PETSC_SUCCESS);
1870   PetscCall(MatMarkDiagonal_SeqAIJ(A));
1871   PetscCheck(a->diagDense, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Matrix must have all diagonal location to invert them");
1872   diag = a->diag;
1873   if (!a->idiag) PetscCall(PetscMalloc3(m, &a->idiag, m, &a->mdiag, m, &a->ssor_work));
1874 
1875   mdiag = a->mdiag;
1876   idiag = a->idiag;
1877   PetscCall(MatSeqAIJGetArrayRead(A, &v));
1878   if (omega == 1.0 && PetscRealPart(fshift) <= 0.0) {
1879     for (i = 0; i < m; i++) {
1880       mdiag[i] = v[diag[i]];
1881       if (!PetscAbsScalar(mdiag[i])) { /* zero diagonal */
1882         PetscCheck(PetscRealPart(fshift), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Zero diagonal on row %" PetscInt_FMT, i);
1883         PetscCall(PetscInfo(A, "Zero diagonal on row %" PetscInt_FMT "\n", i));
1884         A->factorerrortype             = MAT_FACTOR_NUMERIC_ZEROPIVOT;
1885         A->factorerror_zeropivot_value = 0.0;
1886         A->factorerror_zeropivot_row   = i;
1887       }
1888       idiag[i] = 1.0 / v[diag[i]];
1889     }
1890     PetscCall(PetscLogFlops(m));
1891   } else {
1892     for (i = 0; i < m; i++) {
1893       mdiag[i] = v[diag[i]];
1894       idiag[i] = omega / (fshift + v[diag[i]]);
1895     }
1896     PetscCall(PetscLogFlops(2.0 * m));
1897   }
1898   PetscCall(MatSeqAIJRestoreArrayRead(A, &v));
1899   a->idiagState = ((PetscObject)A)->state;
1900   a->omega      = omega;
1901   a->fshift     = fshift;
1902   PetscFunctionReturn(PETSC_SUCCESS);
1903 }
1904 
1905 PetscErrorCode MatSOR_SeqAIJ(Mat A, Vec bb, PetscReal omega, MatSORType flag, PetscReal fshift, PetscInt its, PetscInt lits, Vec xx)
1906 {
1907   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
1908   PetscScalar       *x, d, sum, *t, scale;
1909   const MatScalar   *v, *idiag = NULL, *mdiag, *aa;
1910   const PetscScalar *b, *bs, *xb, *ts;
1911   PetscInt           n, m = A->rmap->n, i;
1912   const PetscInt    *idx, *diag;
1913 
1914   PetscFunctionBegin;
1915   if (a->inode.use && a->inode.checked && omega == 1.0 && fshift == 0.0) {
1916     PetscCall(MatSOR_SeqAIJ_Inode(A, bb, omega, flag, fshift, its, lits, xx));
1917     PetscFunctionReturn(PETSC_SUCCESS);
1918   }
1919   its = its * lits;
1920   PetscCall(MatInvertDiagonalForSOR_SeqAIJ(A, omega, fshift));
1921   diag  = a->diag;
1922   t     = a->ssor_work;
1923   idiag = a->idiag;
1924   mdiag = a->mdiag;
1925 
1926   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
1927   PetscCall(VecGetArray(xx, &x));
1928   PetscCall(VecGetArrayRead(bb, &b));
1929   /* We count flops by assuming the upper triangular and lower triangular parts have the same number of nonzeros */
1930   if (flag == SOR_APPLY_UPPER) {
1931     /* apply (U + D/omega) to the vector */
1932     bs = b;
1933     for (i = 0; i < m; i++) {
1934       d   = fshift + mdiag[i];
1935       n   = a->i[i + 1] - diag[i] - 1;
1936       idx = a->j + diag[i] + 1;
1937       v   = aa + diag[i] + 1;
1938       sum = b[i] * d / omega;
1939       PetscSparseDensePlusDot(sum, bs, v, idx, n);
1940       x[i] = sum;
1941     }
1942     PetscCall(VecRestoreArray(xx, &x));
1943     PetscCall(VecRestoreArrayRead(bb, &b));
1944     PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
1945     PetscCall(PetscLogFlops(a->nz));
1946     PetscFunctionReturn(PETSC_SUCCESS);
1947   }
1948 
1949   PetscCheck(flag != SOR_APPLY_LOWER, PETSC_COMM_SELF, PETSC_ERR_SUP, "SOR_APPLY_LOWER is not implemented");
1950   if (flag & SOR_EISENSTAT) {
1951     /* Let  A = L + U + D; where L is lower triangular,
1952     U is upper triangular, E = D/omega; This routine applies
1953 
1954             (L + E)^{-1} A (U + E)^{-1}
1955 
1956     to a vector efficiently using Eisenstat's trick.
1957     */
1958     scale = (2.0 / omega) - 1.0;
1959 
1960     /*  x = (E + U)^{-1} b */
1961     for (i = m - 1; i >= 0; i--) {
1962       n   = a->i[i + 1] - diag[i] - 1;
1963       idx = a->j + diag[i] + 1;
1964       v   = aa + diag[i] + 1;
1965       sum = b[i];
1966       PetscSparseDenseMinusDot(sum, x, v, idx, n);
1967       x[i] = sum * idiag[i];
1968     }
1969 
1970     /*  t = b - (2*E - D)x */
1971     v = aa;
1972     for (i = 0; i < m; i++) t[i] = b[i] - scale * (v[*diag++]) * x[i];
1973 
1974     /*  t = (E + L)^{-1}t */
1975     ts   = t;
1976     diag = a->diag;
1977     for (i = 0; i < m; i++) {
1978       n   = diag[i] - a->i[i];
1979       idx = a->j + a->i[i];
1980       v   = aa + a->i[i];
1981       sum = t[i];
1982       PetscSparseDenseMinusDot(sum, ts, v, idx, n);
1983       t[i] = sum * idiag[i];
1984       /*  x = x + t */
1985       x[i] += t[i];
1986     }
1987 
1988     PetscCall(PetscLogFlops(6.0 * m - 1 + 2.0 * a->nz));
1989     PetscCall(VecRestoreArray(xx, &x));
1990     PetscCall(VecRestoreArrayRead(bb, &b));
1991     PetscFunctionReturn(PETSC_SUCCESS);
1992   }
1993   if (flag & SOR_ZERO_INITIAL_GUESS) {
1994     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) {
1995       for (i = 0; i < m; i++) {
1996         n   = diag[i] - a->i[i];
1997         idx = a->j + a->i[i];
1998         v   = aa + a->i[i];
1999         sum = b[i];
2000         PetscSparseDenseMinusDot(sum, x, v, idx, n);
2001         t[i] = sum;
2002         x[i] = sum * idiag[i];
2003       }
2004       xb = t;
2005       PetscCall(PetscLogFlops(a->nz));
2006     } else xb = b;
2007     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) {
2008       for (i = m - 1; i >= 0; i--) {
2009         n   = a->i[i + 1] - diag[i] - 1;
2010         idx = a->j + diag[i] + 1;
2011         v   = aa + diag[i] + 1;
2012         sum = xb[i];
2013         PetscSparseDenseMinusDot(sum, x, v, idx, n);
2014         if (xb == b) {
2015           x[i] = sum * idiag[i];
2016         } else {
2017           x[i] = (1 - omega) * x[i] + sum * idiag[i]; /* omega in idiag */
2018         }
2019       }
2020       PetscCall(PetscLogFlops(a->nz)); /* assumes 1/2 in upper */
2021     }
2022     its--;
2023   }
2024   while (its--) {
2025     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) {
2026       for (i = 0; i < m; i++) {
2027         /* lower */
2028         n   = diag[i] - a->i[i];
2029         idx = a->j + a->i[i];
2030         v   = aa + a->i[i];
2031         sum = b[i];
2032         PetscSparseDenseMinusDot(sum, x, v, idx, n);
2033         t[i] = sum; /* save application of the lower-triangular part */
2034         /* upper */
2035         n   = a->i[i + 1] - diag[i] - 1;
2036         idx = a->j + diag[i] + 1;
2037         v   = aa + diag[i] + 1;
2038         PetscSparseDenseMinusDot(sum, x, v, idx, n);
2039         x[i] = (1. - omega) * x[i] + sum * idiag[i]; /* omega in idiag */
2040       }
2041       xb = t;
2042       PetscCall(PetscLogFlops(2.0 * a->nz));
2043     } else xb = b;
2044     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) {
2045       for (i = m - 1; i >= 0; i--) {
2046         sum = xb[i];
2047         if (xb == b) {
2048           /* whole matrix (no checkpointing available) */
2049           n   = a->i[i + 1] - a->i[i];
2050           idx = a->j + a->i[i];
2051           v   = aa + a->i[i];
2052           PetscSparseDenseMinusDot(sum, x, v, idx, n);
2053           x[i] = (1. - omega) * x[i] + (sum + mdiag[i] * x[i]) * idiag[i];
2054         } else { /* lower-triangular part has been saved, so only apply upper-triangular */
2055           n   = a->i[i + 1] - diag[i] - 1;
2056           idx = a->j + diag[i] + 1;
2057           v   = aa + diag[i] + 1;
2058           PetscSparseDenseMinusDot(sum, x, v, idx, n);
2059           x[i] = (1. - omega) * x[i] + sum * idiag[i]; /* omega in idiag */
2060         }
2061       }
2062       if (xb == b) {
2063         PetscCall(PetscLogFlops(2.0 * a->nz));
2064       } else {
2065         PetscCall(PetscLogFlops(a->nz)); /* assumes 1/2 in upper */
2066       }
2067     }
2068   }
2069   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
2070   PetscCall(VecRestoreArray(xx, &x));
2071   PetscCall(VecRestoreArrayRead(bb, &b));
2072   PetscFunctionReturn(PETSC_SUCCESS);
2073 }
2074 
2075 static PetscErrorCode MatGetInfo_SeqAIJ(Mat A, MatInfoType flag, MatInfo *info)
2076 {
2077   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
2078 
2079   PetscFunctionBegin;
2080   info->block_size   = 1.0;
2081   info->nz_allocated = a->maxnz;
2082   info->nz_used      = a->nz;
2083   info->nz_unneeded  = (a->maxnz - a->nz);
2084   info->assemblies   = A->num_ass;
2085   info->mallocs      = A->info.mallocs;
2086   info->memory       = 0; /* REVIEW ME */
2087   if (A->factortype) {
2088     info->fill_ratio_given  = A->info.fill_ratio_given;
2089     info->fill_ratio_needed = A->info.fill_ratio_needed;
2090     info->factor_mallocs    = A->info.factor_mallocs;
2091   } else {
2092     info->fill_ratio_given  = 0;
2093     info->fill_ratio_needed = 0;
2094     info->factor_mallocs    = 0;
2095   }
2096   PetscFunctionReturn(PETSC_SUCCESS);
2097 }
2098 
2099 static PetscErrorCode MatZeroRows_SeqAIJ(Mat A, PetscInt N, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2100 {
2101   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
2102   PetscInt           i, m = A->rmap->n - 1;
2103   const PetscScalar *xx;
2104   PetscScalar       *bb, *aa;
2105   PetscInt           d = 0;
2106 
2107   PetscFunctionBegin;
2108   if (x && b) {
2109     PetscCall(VecGetArrayRead(x, &xx));
2110     PetscCall(VecGetArray(b, &bb));
2111     for (i = 0; i < N; i++) {
2112       PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]);
2113       if (rows[i] >= A->cmap->n) continue;
2114       bb[rows[i]] = diag * xx[rows[i]];
2115     }
2116     PetscCall(VecRestoreArrayRead(x, &xx));
2117     PetscCall(VecRestoreArray(b, &bb));
2118   }
2119 
2120   PetscCall(MatSeqAIJGetArray(A, &aa));
2121   if (a->keepnonzeropattern) {
2122     for (i = 0; i < N; i++) {
2123       PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]);
2124       PetscCall(PetscArrayzero(&aa[a->i[rows[i]]], a->ilen[rows[i]]));
2125     }
2126     if (diag != 0.0) {
2127       for (i = 0; i < N; i++) {
2128         d = rows[i];
2129         if (rows[i] >= A->cmap->n) continue;
2130         PetscCheck(a->diag[d] < a->i[d + 1], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Matrix is missing diagonal entry in the zeroed row %" PetscInt_FMT, d);
2131       }
2132       for (i = 0; i < N; i++) {
2133         if (rows[i] >= A->cmap->n) continue;
2134         aa[a->diag[rows[i]]] = diag;
2135       }
2136     }
2137   } else {
2138     if (diag != 0.0) {
2139       for (i = 0; i < N; i++) {
2140         PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]);
2141         if (a->ilen[rows[i]] > 0) {
2142           if (rows[i] >= A->cmap->n) {
2143             a->ilen[rows[i]] = 0;
2144           } else {
2145             a->ilen[rows[i]]    = 1;
2146             aa[a->i[rows[i]]]   = diag;
2147             a->j[a->i[rows[i]]] = rows[i];
2148           }
2149         } else if (rows[i] < A->cmap->n) { /* in case row was completely empty */
2150           PetscCall(MatSetValues_SeqAIJ(A, 1, &rows[i], 1, &rows[i], &diag, INSERT_VALUES));
2151         }
2152       }
2153     } else {
2154       for (i = 0; i < N; i++) {
2155         PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]);
2156         a->ilen[rows[i]] = 0;
2157       }
2158     }
2159     A->nonzerostate++;
2160   }
2161   PetscCall(MatSeqAIJRestoreArray(A, &aa));
2162   PetscUseTypeMethod(A, assemblyend, MAT_FINAL_ASSEMBLY);
2163   PetscFunctionReturn(PETSC_SUCCESS);
2164 }
2165 
2166 static PetscErrorCode MatZeroRowsColumns_SeqAIJ(Mat A, PetscInt N, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
2167 {
2168   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
2169   PetscInt           i, j, m = A->rmap->n - 1, d = 0;
2170   PetscBool          missing, *zeroed, vecs = PETSC_FALSE;
2171   const PetscScalar *xx;
2172   PetscScalar       *bb, *aa;
2173 
2174   PetscFunctionBegin;
2175   if (!N) PetscFunctionReturn(PETSC_SUCCESS);
2176   PetscCall(MatSeqAIJGetArray(A, &aa));
2177   if (x && b) {
2178     PetscCall(VecGetArrayRead(x, &xx));
2179     PetscCall(VecGetArray(b, &bb));
2180     vecs = PETSC_TRUE;
2181   }
2182   PetscCall(PetscCalloc1(A->rmap->n, &zeroed));
2183   for (i = 0; i < N; i++) {
2184     PetscCheck(rows[i] >= 0 && rows[i] <= m, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "row %" PetscInt_FMT " out of range", rows[i]);
2185     PetscCall(PetscArrayzero(PetscSafePointerPlusOffset(aa, a->i[rows[i]]), a->ilen[rows[i]]));
2186 
2187     zeroed[rows[i]] = PETSC_TRUE;
2188   }
2189   for (i = 0; i < A->rmap->n; i++) {
2190     if (!zeroed[i]) {
2191       for (j = a->i[i]; j < a->i[i + 1]; j++) {
2192         if (a->j[j] < A->rmap->n && zeroed[a->j[j]]) {
2193           if (vecs) bb[i] -= aa[j] * xx[a->j[j]];
2194           aa[j] = 0.0;
2195         }
2196       }
2197     } else if (vecs && i < A->cmap->N) bb[i] = diag * xx[i];
2198   }
2199   if (x && b) {
2200     PetscCall(VecRestoreArrayRead(x, &xx));
2201     PetscCall(VecRestoreArray(b, &bb));
2202   }
2203   PetscCall(PetscFree(zeroed));
2204   if (diag != 0.0) {
2205     PetscCall(MatMissingDiagonal_SeqAIJ(A, &missing, &d));
2206     if (missing) {
2207       for (i = 0; i < N; i++) {
2208         if (rows[i] >= A->cmap->N) continue;
2209         PetscCheck(!a->nonew || rows[i] < d, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Matrix is missing diagonal entry in row %" PetscInt_FMT " (%" PetscInt_FMT ")", d, rows[i]);
2210         PetscCall(MatSetValues_SeqAIJ(A, 1, &rows[i], 1, &rows[i], &diag, INSERT_VALUES));
2211       }
2212     } else {
2213       for (i = 0; i < N; i++) aa[a->diag[rows[i]]] = diag;
2214     }
2215   }
2216   PetscCall(MatSeqAIJRestoreArray(A, &aa));
2217   PetscUseTypeMethod(A, assemblyend, MAT_FINAL_ASSEMBLY);
2218   PetscFunctionReturn(PETSC_SUCCESS);
2219 }
2220 
2221 PetscErrorCode MatGetRow_SeqAIJ(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v)
2222 {
2223   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
2224   const PetscScalar *aa;
2225 
2226   PetscFunctionBegin;
2227   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
2228   *nz = a->i[row + 1] - a->i[row];
2229   if (v) *v = PetscSafePointerPlusOffset((PetscScalar *)aa, a->i[row]);
2230   if (idx) {
2231     if (*nz && a->j) *idx = a->j + a->i[row];
2232     else *idx = NULL;
2233   }
2234   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
2235   PetscFunctionReturn(PETSC_SUCCESS);
2236 }
2237 
2238 PetscErrorCode MatRestoreRow_SeqAIJ(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v)
2239 {
2240   PetscFunctionBegin;
2241   PetscFunctionReturn(PETSC_SUCCESS);
2242 }
2243 
2244 static PetscErrorCode MatNorm_SeqAIJ(Mat A, NormType type, PetscReal *nrm)
2245 {
2246   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
2247   const MatScalar *v;
2248   PetscReal        sum = 0.0;
2249   PetscInt         i, j;
2250 
2251   PetscFunctionBegin;
2252   PetscCall(MatSeqAIJGetArrayRead(A, &v));
2253   if (type == NORM_FROBENIUS) {
2254 #if defined(PETSC_USE_REAL___FP16)
2255     PetscBLASInt one = 1, nz = a->nz;
2256     PetscCallBLAS("BLASnrm2", *nrm = BLASnrm2_(&nz, v, &one));
2257 #else
2258     for (i = 0; i < a->nz; i++) {
2259       sum += PetscRealPart(PetscConj(*v) * (*v));
2260       v++;
2261     }
2262     *nrm = PetscSqrtReal(sum);
2263 #endif
2264     PetscCall(PetscLogFlops(2.0 * a->nz));
2265   } else if (type == NORM_1) {
2266     PetscReal *tmp;
2267     PetscInt  *jj = a->j;
2268     PetscCall(PetscCalloc1(A->cmap->n + 1, &tmp));
2269     *nrm = 0.0;
2270     for (j = 0; j < a->nz; j++) {
2271       tmp[*jj++] += PetscAbsScalar(*v);
2272       v++;
2273     }
2274     for (j = 0; j < A->cmap->n; j++) {
2275       if (tmp[j] > *nrm) *nrm = tmp[j];
2276     }
2277     PetscCall(PetscFree(tmp));
2278     PetscCall(PetscLogFlops(PetscMax(a->nz - 1, 0)));
2279   } else if (type == NORM_INFINITY) {
2280     *nrm = 0.0;
2281     for (j = 0; j < A->rmap->n; j++) {
2282       const PetscScalar *v2 = PetscSafePointerPlusOffset(v, a->i[j]);
2283       sum                   = 0.0;
2284       for (i = 0; i < a->i[j + 1] - a->i[j]; i++) {
2285         sum += PetscAbsScalar(*v2);
2286         v2++;
2287       }
2288       if (sum > *nrm) *nrm = sum;
2289     }
2290     PetscCall(PetscLogFlops(PetscMax(a->nz - 1, 0)));
2291   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for two norm");
2292   PetscCall(MatSeqAIJRestoreArrayRead(A, &v));
2293   PetscFunctionReturn(PETSC_SUCCESS);
2294 }
2295 
2296 static PetscErrorCode MatIsTranspose_SeqAIJ(Mat A, Mat B, PetscReal tol, PetscBool *f)
2297 {
2298   Mat_SeqAIJ      *aij = (Mat_SeqAIJ *)A->data, *bij = (Mat_SeqAIJ *)B->data;
2299   PetscInt        *adx, *bdx, *aii, *bii, *aptr, *bptr;
2300   const MatScalar *va, *vb;
2301   PetscInt         ma, na, mb, nb, i;
2302 
2303   PetscFunctionBegin;
2304   PetscCall(MatGetSize(A, &ma, &na));
2305   PetscCall(MatGetSize(B, &mb, &nb));
2306   if (ma != nb || na != mb) {
2307     *f = PETSC_FALSE;
2308     PetscFunctionReturn(PETSC_SUCCESS);
2309   }
2310   PetscCall(MatSeqAIJGetArrayRead(A, &va));
2311   PetscCall(MatSeqAIJGetArrayRead(B, &vb));
2312   aii = aij->i;
2313   bii = bij->i;
2314   adx = aij->j;
2315   bdx = bij->j;
2316   PetscCall(PetscMalloc1(ma, &aptr));
2317   PetscCall(PetscMalloc1(mb, &bptr));
2318   for (i = 0; i < ma; i++) aptr[i] = aii[i];
2319   for (i = 0; i < mb; i++) bptr[i] = bii[i];
2320 
2321   *f = PETSC_TRUE;
2322   for (i = 0; i < ma; i++) {
2323     while (aptr[i] < aii[i + 1]) {
2324       PetscInt    idc, idr;
2325       PetscScalar vc, vr;
2326       /* column/row index/value */
2327       idc = adx[aptr[i]];
2328       idr = bdx[bptr[idc]];
2329       vc  = va[aptr[i]];
2330       vr  = vb[bptr[idc]];
2331       if (i != idr || PetscAbsScalar(vc - vr) > tol) {
2332         *f = PETSC_FALSE;
2333         goto done;
2334       } else {
2335         aptr[i]++;
2336         if (B || i != idc) bptr[idc]++;
2337       }
2338     }
2339   }
2340 done:
2341   PetscCall(PetscFree(aptr));
2342   PetscCall(PetscFree(bptr));
2343   PetscCall(MatSeqAIJRestoreArrayRead(A, &va));
2344   PetscCall(MatSeqAIJRestoreArrayRead(B, &vb));
2345   PetscFunctionReturn(PETSC_SUCCESS);
2346 }
2347 
2348 static PetscErrorCode MatIsHermitianTranspose_SeqAIJ(Mat A, Mat B, PetscReal tol, PetscBool *f)
2349 {
2350   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data, *bij = (Mat_SeqAIJ *)B->data;
2351   PetscInt   *adx, *bdx, *aii, *bii, *aptr, *bptr;
2352   MatScalar  *va, *vb;
2353   PetscInt    ma, na, mb, nb, i;
2354 
2355   PetscFunctionBegin;
2356   PetscCall(MatGetSize(A, &ma, &na));
2357   PetscCall(MatGetSize(B, &mb, &nb));
2358   if (ma != nb || na != mb) {
2359     *f = PETSC_FALSE;
2360     PetscFunctionReturn(PETSC_SUCCESS);
2361   }
2362   aii = aij->i;
2363   bii = bij->i;
2364   adx = aij->j;
2365   bdx = bij->j;
2366   va  = aij->a;
2367   vb  = bij->a;
2368   PetscCall(PetscMalloc1(ma, &aptr));
2369   PetscCall(PetscMalloc1(mb, &bptr));
2370   for (i = 0; i < ma; i++) aptr[i] = aii[i];
2371   for (i = 0; i < mb; i++) bptr[i] = bii[i];
2372 
2373   *f = PETSC_TRUE;
2374   for (i = 0; i < ma; i++) {
2375     while (aptr[i] < aii[i + 1]) {
2376       PetscInt    idc, idr;
2377       PetscScalar vc, vr;
2378       /* column/row index/value */
2379       idc = adx[aptr[i]];
2380       idr = bdx[bptr[idc]];
2381       vc  = va[aptr[i]];
2382       vr  = vb[bptr[idc]];
2383       if (i != idr || PetscAbsScalar(vc - PetscConj(vr)) > tol) {
2384         *f = PETSC_FALSE;
2385         goto done;
2386       } else {
2387         aptr[i]++;
2388         if (B || i != idc) bptr[idc]++;
2389       }
2390     }
2391   }
2392 done:
2393   PetscCall(PetscFree(aptr));
2394   PetscCall(PetscFree(bptr));
2395   PetscFunctionReturn(PETSC_SUCCESS);
2396 }
2397 
2398 PetscErrorCode MatDiagonalScale_SeqAIJ(Mat A, Vec ll, Vec rr)
2399 {
2400   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
2401   const PetscScalar *l, *r;
2402   PetscScalar        x;
2403   MatScalar         *v;
2404   PetscInt           i, j, m = A->rmap->n, n = A->cmap->n, M, nz = a->nz;
2405   const PetscInt    *jj;
2406 
2407   PetscFunctionBegin;
2408   if (ll) {
2409     /* The local size is used so that VecMPI can be passed to this routine
2410        by MatDiagonalScale_MPIAIJ */
2411     PetscCall(VecGetLocalSize(ll, &m));
2412     PetscCheck(m == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Left scaling vector wrong length");
2413     PetscCall(VecGetArrayRead(ll, &l));
2414     PetscCall(MatSeqAIJGetArray(A, &v));
2415     for (i = 0; i < m; i++) {
2416       x = l[i];
2417       M = a->i[i + 1] - a->i[i];
2418       for (j = 0; j < M; j++) (*v++) *= x;
2419     }
2420     PetscCall(VecRestoreArrayRead(ll, &l));
2421     PetscCall(PetscLogFlops(nz));
2422     PetscCall(MatSeqAIJRestoreArray(A, &v));
2423   }
2424   if (rr) {
2425     PetscCall(VecGetLocalSize(rr, &n));
2426     PetscCheck(n == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Right scaling vector wrong length");
2427     PetscCall(VecGetArrayRead(rr, &r));
2428     PetscCall(MatSeqAIJGetArray(A, &v));
2429     jj = a->j;
2430     for (i = 0; i < nz; i++) (*v++) *= r[*jj++];
2431     PetscCall(MatSeqAIJRestoreArray(A, &v));
2432     PetscCall(VecRestoreArrayRead(rr, &r));
2433     PetscCall(PetscLogFlops(nz));
2434   }
2435   PetscFunctionReturn(PETSC_SUCCESS);
2436 }
2437 
2438 PetscErrorCode MatCreateSubMatrix_SeqAIJ(Mat A, IS isrow, IS iscol, PetscInt csize, MatReuse scall, Mat *B)
2439 {
2440   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data, *c;
2441   PetscInt          *smap, i, k, kstart, kend, oldcols = A->cmap->n, *lens;
2442   PetscInt           row, mat_i, *mat_j, tcol, first, step, *mat_ilen, sum, lensi;
2443   const PetscInt    *irow, *icol;
2444   const PetscScalar *aa;
2445   PetscInt           nrows, ncols;
2446   PetscInt          *starts, *j_new, *i_new, *aj = a->j, *ai = a->i, ii, *ailen = a->ilen;
2447   MatScalar         *a_new, *mat_a, *c_a;
2448   Mat                C;
2449   PetscBool          stride;
2450 
2451   PetscFunctionBegin;
2452   PetscCall(ISGetIndices(isrow, &irow));
2453   PetscCall(ISGetLocalSize(isrow, &nrows));
2454   PetscCall(ISGetLocalSize(iscol, &ncols));
2455 
2456   PetscCall(PetscObjectTypeCompare((PetscObject)iscol, ISSTRIDE, &stride));
2457   if (stride) {
2458     PetscCall(ISStrideGetInfo(iscol, &first, &step));
2459   } else {
2460     first = 0;
2461     step  = 0;
2462   }
2463   if (stride && step == 1) {
2464     /* special case of contiguous rows */
2465     PetscCall(PetscMalloc2(nrows, &lens, nrows, &starts));
2466     /* loop over new rows determining lens and starting points */
2467     for (i = 0; i < nrows; i++) {
2468       kstart    = ai[irow[i]];
2469       kend      = kstart + ailen[irow[i]];
2470       starts[i] = kstart;
2471       for (k = kstart; k < kend; k++) {
2472         if (aj[k] >= first) {
2473           starts[i] = k;
2474           break;
2475         }
2476       }
2477       sum = 0;
2478       while (k < kend) {
2479         if (aj[k++] >= first + ncols) break;
2480         sum++;
2481       }
2482       lens[i] = sum;
2483     }
2484     /* create submatrix */
2485     if (scall == MAT_REUSE_MATRIX) {
2486       PetscInt n_cols, n_rows;
2487       PetscCall(MatGetSize(*B, &n_rows, &n_cols));
2488       PetscCheck(n_rows == nrows && n_cols == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Reused submatrix wrong size");
2489       PetscCall(MatZeroEntries(*B));
2490       C = *B;
2491     } else {
2492       PetscInt rbs, cbs;
2493       PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
2494       PetscCall(MatSetSizes(C, nrows, ncols, PETSC_DETERMINE, PETSC_DETERMINE));
2495       PetscCall(ISGetBlockSize(isrow, &rbs));
2496       PetscCall(ISGetBlockSize(iscol, &cbs));
2497       PetscCall(MatSetBlockSizes(C, rbs, cbs));
2498       PetscCall(MatSetType(C, ((PetscObject)A)->type_name));
2499       PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(C, 0, lens));
2500     }
2501     c = (Mat_SeqAIJ *)C->data;
2502 
2503     /* loop over rows inserting into submatrix */
2504     PetscCall(MatSeqAIJGetArrayWrite(C, &a_new)); // Not 'a_new = c->a-new', since that raw usage ignores offload state of C
2505     j_new = c->j;
2506     i_new = c->i;
2507     PetscCall(MatSeqAIJGetArrayRead(A, &aa));
2508     for (i = 0; i < nrows; i++) {
2509       ii    = starts[i];
2510       lensi = lens[i];
2511       if (lensi) {
2512         for (k = 0; k < lensi; k++) *j_new++ = aj[ii + k] - first;
2513         PetscCall(PetscArraycpy(a_new, aa + starts[i], lensi));
2514         a_new += lensi;
2515       }
2516       i_new[i + 1] = i_new[i] + lensi;
2517       c->ilen[i]   = lensi;
2518     }
2519     PetscCall(MatSeqAIJRestoreArrayWrite(C, &a_new)); // Set C's offload state properly
2520     PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
2521     PetscCall(PetscFree2(lens, starts));
2522   } else {
2523     PetscCall(ISGetIndices(iscol, &icol));
2524     PetscCall(PetscCalloc1(oldcols, &smap));
2525     PetscCall(PetscMalloc1(1 + nrows, &lens));
2526     for (i = 0; i < ncols; i++) {
2527       PetscCheck(icol[i] < oldcols, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Requesting column beyond largest column icol[%" PetscInt_FMT "] %" PetscInt_FMT " >= A->cmap->n %" PetscInt_FMT, i, icol[i], oldcols);
2528       smap[icol[i]] = i + 1;
2529     }
2530 
2531     /* determine lens of each row */
2532     for (i = 0; i < nrows; i++) {
2533       kstart  = ai[irow[i]];
2534       kend    = kstart + a->ilen[irow[i]];
2535       lens[i] = 0;
2536       for (k = kstart; k < kend; k++) {
2537         if (smap[aj[k]]) lens[i]++;
2538       }
2539     }
2540     /* Create and fill new matrix */
2541     if (scall == MAT_REUSE_MATRIX) {
2542       PetscBool equal;
2543 
2544       c = (Mat_SeqAIJ *)((*B)->data);
2545       PetscCheck((*B)->rmap->n == nrows && (*B)->cmap->n == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Cannot reuse matrix. wrong size");
2546       PetscCall(PetscArraycmp(c->ilen, lens, (*B)->rmap->n, &equal));
2547       PetscCheck(equal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Cannot reuse matrix. wrong number of nonzeros");
2548       PetscCall(PetscArrayzero(c->ilen, (*B)->rmap->n));
2549       C = *B;
2550     } else {
2551       PetscInt rbs, cbs;
2552       PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
2553       PetscCall(MatSetSizes(C, nrows, ncols, PETSC_DETERMINE, PETSC_DETERMINE));
2554       PetscCall(ISGetBlockSize(isrow, &rbs));
2555       PetscCall(ISGetBlockSize(iscol, &cbs));
2556       if (rbs > 1 || cbs > 1) PetscCall(MatSetBlockSizes(C, rbs, cbs));
2557       PetscCall(MatSetType(C, ((PetscObject)A)->type_name));
2558       PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(C, 0, lens));
2559     }
2560     PetscCall(MatSeqAIJGetArrayRead(A, &aa));
2561 
2562     c = (Mat_SeqAIJ *)C->data;
2563     PetscCall(MatSeqAIJGetArrayWrite(C, &c_a)); // Not 'c->a', since that raw usage ignores offload state of C
2564     for (i = 0; i < nrows; i++) {
2565       row      = irow[i];
2566       kstart   = ai[row];
2567       kend     = kstart + a->ilen[row];
2568       mat_i    = c->i[i];
2569       mat_j    = PetscSafePointerPlusOffset(c->j, mat_i);
2570       mat_a    = PetscSafePointerPlusOffset(c_a, mat_i);
2571       mat_ilen = c->ilen + i;
2572       for (k = kstart; k < kend; k++) {
2573         if ((tcol = smap[a->j[k]])) {
2574           *mat_j++ = tcol - 1;
2575           *mat_a++ = aa[k];
2576           (*mat_ilen)++;
2577         }
2578       }
2579     }
2580     PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
2581     /* Free work space */
2582     PetscCall(ISRestoreIndices(iscol, &icol));
2583     PetscCall(PetscFree(smap));
2584     PetscCall(PetscFree(lens));
2585     /* sort */
2586     for (i = 0; i < nrows; i++) {
2587       PetscInt ilen;
2588 
2589       mat_i = c->i[i];
2590       mat_j = PetscSafePointerPlusOffset(c->j, mat_i);
2591       mat_a = PetscSafePointerPlusOffset(c_a, mat_i);
2592       ilen  = c->ilen[i];
2593       PetscCall(PetscSortIntWithScalarArray(ilen, mat_j, mat_a));
2594     }
2595     PetscCall(MatSeqAIJRestoreArrayWrite(C, &c_a));
2596   }
2597 #if defined(PETSC_HAVE_DEVICE)
2598   PetscCall(MatBindToCPU(C, A->boundtocpu));
2599 #endif
2600   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
2601   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
2602 
2603   PetscCall(ISRestoreIndices(isrow, &irow));
2604   *B = C;
2605   PetscFunctionReturn(PETSC_SUCCESS);
2606 }
2607 
2608 static PetscErrorCode MatGetMultiProcBlock_SeqAIJ(Mat mat, MPI_Comm subComm, MatReuse scall, Mat *subMat)
2609 {
2610   Mat B;
2611 
2612   PetscFunctionBegin;
2613   if (scall == MAT_INITIAL_MATRIX) {
2614     PetscCall(MatCreate(subComm, &B));
2615     PetscCall(MatSetSizes(B, mat->rmap->n, mat->cmap->n, mat->rmap->n, mat->cmap->n));
2616     PetscCall(MatSetBlockSizesFromMats(B, mat, mat));
2617     PetscCall(MatSetType(B, MATSEQAIJ));
2618     PetscCall(MatDuplicateNoCreate_SeqAIJ(B, mat, MAT_COPY_VALUES, PETSC_TRUE));
2619     *subMat = B;
2620   } else {
2621     PetscCall(MatCopy_SeqAIJ(mat, *subMat, SAME_NONZERO_PATTERN));
2622   }
2623   PetscFunctionReturn(PETSC_SUCCESS);
2624 }
2625 
2626 static PetscErrorCode MatILUFactor_SeqAIJ(Mat inA, IS row, IS col, const MatFactorInfo *info)
2627 {
2628   Mat_SeqAIJ *a = (Mat_SeqAIJ *)inA->data;
2629   Mat         outA;
2630   PetscBool   row_identity, col_identity;
2631 
2632   PetscFunctionBegin;
2633   PetscCheck(info->levels == 0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only levels=0 supported for in-place ilu");
2634 
2635   PetscCall(ISIdentity(row, &row_identity));
2636   PetscCall(ISIdentity(col, &col_identity));
2637 
2638   outA             = inA;
2639   outA->factortype = MAT_FACTOR_LU;
2640   PetscCall(PetscFree(inA->solvertype));
2641   PetscCall(PetscStrallocpy(MATSOLVERPETSC, &inA->solvertype));
2642 
2643   PetscCall(PetscObjectReference((PetscObject)row));
2644   PetscCall(ISDestroy(&a->row));
2645 
2646   a->row = row;
2647 
2648   PetscCall(PetscObjectReference((PetscObject)col));
2649   PetscCall(ISDestroy(&a->col));
2650 
2651   a->col = col;
2652 
2653   /* Create the inverse permutation so that it can be used in MatLUFactorNumeric() */
2654   PetscCall(ISDestroy(&a->icol));
2655   PetscCall(ISInvertPermutation(col, PETSC_DECIDE, &a->icol));
2656 
2657   if (!a->solve_work) { /* this matrix may have been factored before */
2658     PetscCall(PetscMalloc1(inA->rmap->n, &a->solve_work));
2659   }
2660 
2661   PetscCall(MatMarkDiagonal_SeqAIJ(inA));
2662   if (row_identity && col_identity) {
2663     PetscCall(MatLUFactorNumeric_SeqAIJ_inplace(outA, inA, info));
2664   } else {
2665     PetscCall(MatLUFactorNumeric_SeqAIJ_InplaceWithPerm(outA, inA, info));
2666   }
2667   PetscFunctionReturn(PETSC_SUCCESS);
2668 }
2669 
2670 PetscErrorCode MatScale_SeqAIJ(Mat inA, PetscScalar alpha)
2671 {
2672   Mat_SeqAIJ  *a = (Mat_SeqAIJ *)inA->data;
2673   PetscScalar *v;
2674   PetscBLASInt one = 1, bnz;
2675 
2676   PetscFunctionBegin;
2677   PetscCall(MatSeqAIJGetArray(inA, &v));
2678   PetscCall(PetscBLASIntCast(a->nz, &bnz));
2679   PetscCallBLAS("BLASscal", BLASscal_(&bnz, &alpha, v, &one));
2680   PetscCall(PetscLogFlops(a->nz));
2681   PetscCall(MatSeqAIJRestoreArray(inA, &v));
2682   PetscFunctionReturn(PETSC_SUCCESS);
2683 }
2684 
2685 PetscErrorCode MatDestroySubMatrix_Private(Mat_SubSppt *submatj)
2686 {
2687   PetscInt i;
2688 
2689   PetscFunctionBegin;
2690   if (!submatj->id) { /* delete data that are linked only to submats[id=0] */
2691     PetscCall(PetscFree4(submatj->sbuf1, submatj->ptr, submatj->tmp, submatj->ctr));
2692 
2693     for (i = 0; i < submatj->nrqr; ++i) PetscCall(PetscFree(submatj->sbuf2[i]));
2694     PetscCall(PetscFree3(submatj->sbuf2, submatj->req_size, submatj->req_source1));
2695 
2696     if (submatj->rbuf1) {
2697       PetscCall(PetscFree(submatj->rbuf1[0]));
2698       PetscCall(PetscFree(submatj->rbuf1));
2699     }
2700 
2701     for (i = 0; i < submatj->nrqs; ++i) PetscCall(PetscFree(submatj->rbuf3[i]));
2702     PetscCall(PetscFree3(submatj->req_source2, submatj->rbuf2, submatj->rbuf3));
2703     PetscCall(PetscFree(submatj->pa));
2704   }
2705 
2706 #if defined(PETSC_USE_CTABLE)
2707   PetscCall(PetscHMapIDestroy(&submatj->rmap));
2708   if (submatj->cmap_loc) PetscCall(PetscFree(submatj->cmap_loc));
2709   PetscCall(PetscFree(submatj->rmap_loc));
2710 #else
2711   PetscCall(PetscFree(submatj->rmap));
2712 #endif
2713 
2714   if (!submatj->allcolumns) {
2715 #if defined(PETSC_USE_CTABLE)
2716     PetscCall(PetscHMapIDestroy(&submatj->cmap));
2717 #else
2718     PetscCall(PetscFree(submatj->cmap));
2719 #endif
2720   }
2721   PetscCall(PetscFree(submatj->row2proc));
2722 
2723   PetscCall(PetscFree(submatj));
2724   PetscFunctionReturn(PETSC_SUCCESS);
2725 }
2726 
2727 PetscErrorCode MatDestroySubMatrix_SeqAIJ(Mat C)
2728 {
2729   Mat_SeqAIJ  *c       = (Mat_SeqAIJ *)C->data;
2730   Mat_SubSppt *submatj = c->submatis1;
2731 
2732   PetscFunctionBegin;
2733   PetscCall((*submatj->destroy)(C));
2734   PetscCall(MatDestroySubMatrix_Private(submatj));
2735   PetscFunctionReturn(PETSC_SUCCESS);
2736 }
2737 
2738 /* Note this has code duplication with MatDestroySubMatrices_SeqBAIJ() */
2739 static PetscErrorCode MatDestroySubMatrices_SeqAIJ(PetscInt n, Mat *mat[])
2740 {
2741   PetscInt     i;
2742   Mat          C;
2743   Mat_SeqAIJ  *c;
2744   Mat_SubSppt *submatj;
2745 
2746   PetscFunctionBegin;
2747   for (i = 0; i < n; i++) {
2748     C       = (*mat)[i];
2749     c       = (Mat_SeqAIJ *)C->data;
2750     submatj = c->submatis1;
2751     if (submatj) {
2752       if (--((PetscObject)C)->refct <= 0) {
2753         PetscCall(PetscFree(C->factorprefix));
2754         PetscCall((*submatj->destroy)(C));
2755         PetscCall(MatDestroySubMatrix_Private(submatj));
2756         PetscCall(PetscFree(C->defaultvectype));
2757         PetscCall(PetscFree(C->defaultrandtype));
2758         PetscCall(PetscLayoutDestroy(&C->rmap));
2759         PetscCall(PetscLayoutDestroy(&C->cmap));
2760         PetscCall(PetscHeaderDestroy(&C));
2761       }
2762     } else {
2763       PetscCall(MatDestroy(&C));
2764     }
2765   }
2766 
2767   /* Destroy Dummy submatrices created for reuse */
2768   PetscCall(MatDestroySubMatrices_Dummy(n, mat));
2769 
2770   PetscCall(PetscFree(*mat));
2771   PetscFunctionReturn(PETSC_SUCCESS);
2772 }
2773 
2774 static PetscErrorCode MatCreateSubMatrices_SeqAIJ(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *B[])
2775 {
2776   PetscInt i;
2777 
2778   PetscFunctionBegin;
2779   if (scall == MAT_INITIAL_MATRIX) PetscCall(PetscCalloc1(n + 1, B));
2780 
2781   for (i = 0; i < n; i++) PetscCall(MatCreateSubMatrix_SeqAIJ(A, irow[i], icol[i], PETSC_DECIDE, scall, &(*B)[i]));
2782   PetscFunctionReturn(PETSC_SUCCESS);
2783 }
2784 
2785 static PetscErrorCode MatIncreaseOverlap_SeqAIJ(Mat A, PetscInt is_max, IS is[], PetscInt ov)
2786 {
2787   Mat_SeqAIJ     *a = (Mat_SeqAIJ *)A->data;
2788   PetscInt        row, i, j, k, l, ll, m, n, *nidx, isz, val;
2789   const PetscInt *idx;
2790   PetscInt        start, end, *ai, *aj, bs = A->rmap->bs == A->cmap->bs ? A->rmap->bs : 1;
2791   PetscBT         table;
2792 
2793   PetscFunctionBegin;
2794   m  = A->rmap->n / bs;
2795   ai = a->i;
2796   aj = a->j;
2797 
2798   PetscCheck(ov >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "illegal negative overlap value used");
2799 
2800   PetscCall(PetscMalloc1(m + 1, &nidx));
2801   PetscCall(PetscBTCreate(m, &table));
2802 
2803   for (i = 0; i < is_max; i++) {
2804     /* Initialize the two local arrays */
2805     isz = 0;
2806     PetscCall(PetscBTMemzero(m, table));
2807 
2808     /* Extract the indices, assume there can be duplicate entries */
2809     PetscCall(ISGetIndices(is[i], &idx));
2810     PetscCall(ISGetLocalSize(is[i], &n));
2811 
2812     if (bs > 1) {
2813       /* Enter these into the temp arrays. I.e., mark table[row], enter row into new index */
2814       for (j = 0; j < n; ++j) {
2815         if (!PetscBTLookupSet(table, idx[j] / bs)) nidx[isz++] = idx[j] / bs;
2816       }
2817       PetscCall(ISRestoreIndices(is[i], &idx));
2818       PetscCall(ISDestroy(&is[i]));
2819 
2820       k = 0;
2821       for (j = 0; j < ov; j++) { /* for each overlap */
2822         n = isz;
2823         for (; k < n; k++) { /* do only those rows in nidx[k], which are not done yet */
2824           for (ll = 0; ll < bs; ll++) {
2825             row   = bs * nidx[k] + ll;
2826             start = ai[row];
2827             end   = ai[row + 1];
2828             for (l = start; l < end; l++) {
2829               val = aj[l] / bs;
2830               if (!PetscBTLookupSet(table, val)) nidx[isz++] = val;
2831             }
2832           }
2833         }
2834       }
2835       PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, isz, nidx, PETSC_COPY_VALUES, is + i));
2836     } else {
2837       /* Enter these into the temp arrays. I.e., mark table[row], enter row into new index */
2838       for (j = 0; j < n; ++j) {
2839         if (!PetscBTLookupSet(table, idx[j])) nidx[isz++] = idx[j];
2840       }
2841       PetscCall(ISRestoreIndices(is[i], &idx));
2842       PetscCall(ISDestroy(&is[i]));
2843 
2844       k = 0;
2845       for (j = 0; j < ov; j++) { /* for each overlap */
2846         n = isz;
2847         for (; k < n; k++) { /* do only those rows in nidx[k], which are not done yet */
2848           row   = nidx[k];
2849           start = ai[row];
2850           end   = ai[row + 1];
2851           for (l = start; l < end; l++) {
2852             val = aj[l];
2853             if (!PetscBTLookupSet(table, val)) nidx[isz++] = val;
2854           }
2855         }
2856       }
2857       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, isz, nidx, PETSC_COPY_VALUES, is + i));
2858     }
2859   }
2860   PetscCall(PetscBTDestroy(&table));
2861   PetscCall(PetscFree(nidx));
2862   PetscFunctionReturn(PETSC_SUCCESS);
2863 }
2864 
2865 static PetscErrorCode MatPermute_SeqAIJ(Mat A, IS rowp, IS colp, Mat *B)
2866 {
2867   Mat_SeqAIJ     *a = (Mat_SeqAIJ *)A->data;
2868   PetscInt        i, nz = 0, m = A->rmap->n, n = A->cmap->n;
2869   const PetscInt *row, *col;
2870   PetscInt       *cnew, j, *lens;
2871   IS              icolp, irowp;
2872   PetscInt       *cwork = NULL;
2873   PetscScalar    *vwork = NULL;
2874 
2875   PetscFunctionBegin;
2876   PetscCall(ISInvertPermutation(rowp, PETSC_DECIDE, &irowp));
2877   PetscCall(ISGetIndices(irowp, &row));
2878   PetscCall(ISInvertPermutation(colp, PETSC_DECIDE, &icolp));
2879   PetscCall(ISGetIndices(icolp, &col));
2880 
2881   /* determine lengths of permuted rows */
2882   PetscCall(PetscMalloc1(m + 1, &lens));
2883   for (i = 0; i < m; i++) lens[row[i]] = a->i[i + 1] - a->i[i];
2884   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
2885   PetscCall(MatSetSizes(*B, m, n, m, n));
2886   PetscCall(MatSetBlockSizesFromMats(*B, A, A));
2887   PetscCall(MatSetType(*B, ((PetscObject)A)->type_name));
2888   PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*B, 0, lens));
2889   PetscCall(PetscFree(lens));
2890 
2891   PetscCall(PetscMalloc1(n, &cnew));
2892   for (i = 0; i < m; i++) {
2893     PetscCall(MatGetRow_SeqAIJ(A, i, &nz, &cwork, &vwork));
2894     for (j = 0; j < nz; j++) cnew[j] = col[cwork[j]];
2895     PetscCall(MatSetValues_SeqAIJ(*B, 1, &row[i], nz, cnew, vwork, INSERT_VALUES));
2896     PetscCall(MatRestoreRow_SeqAIJ(A, i, &nz, &cwork, &vwork));
2897   }
2898   PetscCall(PetscFree(cnew));
2899 
2900   (*B)->assembled = PETSC_FALSE;
2901 
2902 #if defined(PETSC_HAVE_DEVICE)
2903   PetscCall(MatBindToCPU(*B, A->boundtocpu));
2904 #endif
2905   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
2906   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
2907   PetscCall(ISRestoreIndices(irowp, &row));
2908   PetscCall(ISRestoreIndices(icolp, &col));
2909   PetscCall(ISDestroy(&irowp));
2910   PetscCall(ISDestroy(&icolp));
2911   if (rowp == colp) PetscCall(MatPropagateSymmetryOptions(A, *B));
2912   PetscFunctionReturn(PETSC_SUCCESS);
2913 }
2914 
2915 PetscErrorCode MatCopy_SeqAIJ(Mat A, Mat B, MatStructure str)
2916 {
2917   PetscFunctionBegin;
2918   /* If the two matrices have the same copy implementation, use fast copy. */
2919   if (str == SAME_NONZERO_PATTERN && (A->ops->copy == B->ops->copy)) {
2920     Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
2921     Mat_SeqAIJ        *b = (Mat_SeqAIJ *)B->data;
2922     const PetscScalar *aa;
2923     PetscScalar       *bb;
2924 
2925     PetscCall(MatSeqAIJGetArrayRead(A, &aa));
2926     PetscCall(MatSeqAIJGetArrayWrite(B, &bb));
2927 
2928     PetscCheck(a->i[A->rmap->n] == b->i[B->rmap->n], PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of nonzeros in two matrices are different %" PetscInt_FMT " != %" PetscInt_FMT, a->i[A->rmap->n], b->i[B->rmap->n]);
2929     PetscCall(PetscArraycpy(bb, aa, a->i[A->rmap->n]));
2930     PetscCall(PetscObjectStateIncrease((PetscObject)B));
2931     PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
2932     PetscCall(MatSeqAIJRestoreArrayWrite(B, &bb));
2933   } else {
2934     PetscCall(MatCopy_Basic(A, B, str));
2935   }
2936   PetscFunctionReturn(PETSC_SUCCESS);
2937 }
2938 
2939 PETSC_INTERN PetscErrorCode MatSeqAIJGetArray_SeqAIJ(Mat A, PetscScalar *array[])
2940 {
2941   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
2942 
2943   PetscFunctionBegin;
2944   *array = a->a;
2945   PetscFunctionReturn(PETSC_SUCCESS);
2946 }
2947 
2948 PETSC_INTERN PetscErrorCode MatSeqAIJRestoreArray_SeqAIJ(Mat A, PetscScalar *array[])
2949 {
2950   PetscFunctionBegin;
2951   *array = NULL;
2952   PetscFunctionReturn(PETSC_SUCCESS);
2953 }
2954 
2955 /*
2956    Computes the number of nonzeros per row needed for preallocation when X and Y
2957    have different nonzero structure.
2958 */
2959 PetscErrorCode MatAXPYGetPreallocation_SeqX_private(PetscInt m, const PetscInt *xi, const PetscInt *xj, const PetscInt *yi, const PetscInt *yj, PetscInt *nnz)
2960 {
2961   PetscInt i, j, k, nzx, nzy;
2962 
2963   PetscFunctionBegin;
2964   /* Set the number of nonzeros in the new matrix */
2965   for (i = 0; i < m; i++) {
2966     const PetscInt *xjj = PetscSafePointerPlusOffset(xj, xi[i]), *yjj = PetscSafePointerPlusOffset(yj, yi[i]);
2967     nzx    = xi[i + 1] - xi[i];
2968     nzy    = yi[i + 1] - yi[i];
2969     nnz[i] = 0;
2970     for (j = 0, k = 0; j < nzx; j++) {                  /* Point in X */
2971       for (; k < nzy && yjj[k] < xjj[j]; k++) nnz[i]++; /* Catch up to X */
2972       if (k < nzy && yjj[k] == xjj[j]) k++;             /* Skip duplicate */
2973       nnz[i]++;
2974     }
2975     for (; k < nzy; k++) nnz[i]++;
2976   }
2977   PetscFunctionReturn(PETSC_SUCCESS);
2978 }
2979 
2980 PetscErrorCode MatAXPYGetPreallocation_SeqAIJ(Mat Y, Mat X, PetscInt *nnz)
2981 {
2982   PetscInt    m = Y->rmap->N;
2983   Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data;
2984   Mat_SeqAIJ *y = (Mat_SeqAIJ *)Y->data;
2985 
2986   PetscFunctionBegin;
2987   /* Set the number of nonzeros in the new matrix */
2988   PetscCall(MatAXPYGetPreallocation_SeqX_private(m, x->i, x->j, y->i, y->j, nnz));
2989   PetscFunctionReturn(PETSC_SUCCESS);
2990 }
2991 
2992 PetscErrorCode MatAXPY_SeqAIJ(Mat Y, PetscScalar a, Mat X, MatStructure str)
2993 {
2994   Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data, *y = (Mat_SeqAIJ *)Y->data;
2995 
2996   PetscFunctionBegin;
2997   if (str == UNKNOWN_NONZERO_PATTERN || (PetscDefined(USE_DEBUG) && str == SAME_NONZERO_PATTERN)) {
2998     PetscBool e = x->nz == y->nz ? PETSC_TRUE : PETSC_FALSE;
2999     if (e) {
3000       PetscCall(PetscArraycmp(x->i, y->i, Y->rmap->n + 1, &e));
3001       if (e) {
3002         PetscCall(PetscArraycmp(x->j, y->j, y->nz, &e));
3003         if (e) str = SAME_NONZERO_PATTERN;
3004       }
3005     }
3006     if (!e) PetscCheck(str != SAME_NONZERO_PATTERN, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatStructure is not SAME_NONZERO_PATTERN");
3007   }
3008   if (str == SAME_NONZERO_PATTERN) {
3009     const PetscScalar *xa;
3010     PetscScalar       *ya, alpha = a;
3011     PetscBLASInt       one = 1, bnz;
3012 
3013     PetscCall(PetscBLASIntCast(x->nz, &bnz));
3014     PetscCall(MatSeqAIJGetArray(Y, &ya));
3015     PetscCall(MatSeqAIJGetArrayRead(X, &xa));
3016     PetscCallBLAS("BLASaxpy", BLASaxpy_(&bnz, &alpha, xa, &one, ya, &one));
3017     PetscCall(MatSeqAIJRestoreArrayRead(X, &xa));
3018     PetscCall(MatSeqAIJRestoreArray(Y, &ya));
3019     PetscCall(PetscLogFlops(2.0 * bnz));
3020     PetscCall(PetscObjectStateIncrease((PetscObject)Y));
3021   } else if (str == SUBSET_NONZERO_PATTERN) { /* nonzeros of X is a subset of Y's */
3022     PetscCall(MatAXPY_Basic(Y, a, X, str));
3023   } else {
3024     Mat       B;
3025     PetscInt *nnz;
3026     PetscCall(PetscMalloc1(Y->rmap->N, &nnz));
3027     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &B));
3028     PetscCall(PetscObjectSetName((PetscObject)B, ((PetscObject)Y)->name));
3029     PetscCall(MatSetLayouts(B, Y->rmap, Y->cmap));
3030     PetscCall(MatSetType(B, ((PetscObject)Y)->type_name));
3031     PetscCall(MatAXPYGetPreallocation_SeqAIJ(Y, X, nnz));
3032     PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz));
3033     PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str));
3034     PetscCall(MatHeaderMerge(Y, &B));
3035     PetscCall(MatSeqAIJCheckInode(Y));
3036     PetscCall(PetscFree(nnz));
3037   }
3038   PetscFunctionReturn(PETSC_SUCCESS);
3039 }
3040 
3041 PETSC_INTERN PetscErrorCode MatConjugate_SeqAIJ(Mat mat)
3042 {
3043 #if defined(PETSC_USE_COMPLEX)
3044   Mat_SeqAIJ  *aij = (Mat_SeqAIJ *)mat->data;
3045   PetscInt     i, nz;
3046   PetscScalar *a;
3047 
3048   PetscFunctionBegin;
3049   nz = aij->nz;
3050   PetscCall(MatSeqAIJGetArray(mat, &a));
3051   for (i = 0; i < nz; i++) a[i] = PetscConj(a[i]);
3052   PetscCall(MatSeqAIJRestoreArray(mat, &a));
3053 #else
3054   PetscFunctionBegin;
3055 #endif
3056   PetscFunctionReturn(PETSC_SUCCESS);
3057 }
3058 
3059 static PetscErrorCode MatGetRowMaxAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[])
3060 {
3061   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
3062   PetscInt         i, j, m = A->rmap->n, *ai, *aj, ncols, n;
3063   PetscReal        atmp;
3064   PetscScalar     *x;
3065   const MatScalar *aa, *av;
3066 
3067   PetscFunctionBegin;
3068   PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3069   PetscCall(MatSeqAIJGetArrayRead(A, &av));
3070   aa = av;
3071   ai = a->i;
3072   aj = a->j;
3073 
3074   PetscCall(VecGetArrayWrite(v, &x));
3075   PetscCall(VecGetLocalSize(v, &n));
3076   PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector");
3077   for (i = 0; i < m; i++) {
3078     ncols = ai[1] - ai[0];
3079     ai++;
3080     x[i] = 0;
3081     for (j = 0; j < ncols; j++) {
3082       atmp = PetscAbsScalar(*aa);
3083       if (PetscAbsScalar(x[i]) < atmp) {
3084         x[i] = atmp;
3085         if (idx) idx[i] = *aj;
3086       }
3087       aa++;
3088       aj++;
3089     }
3090   }
3091   PetscCall(VecRestoreArrayWrite(v, &x));
3092   PetscCall(MatSeqAIJRestoreArrayRead(A, &av));
3093   PetscFunctionReturn(PETSC_SUCCESS);
3094 }
3095 
3096 static PetscErrorCode MatGetRowSumAbs_SeqAIJ(Mat A, Vec v)
3097 {
3098   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
3099   PetscInt         i, j, m = A->rmap->n, *ai, ncols, n;
3100   PetscScalar     *x;
3101   const MatScalar *aa, *av;
3102 
3103   PetscFunctionBegin;
3104   PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3105   PetscCall(MatSeqAIJGetArrayRead(A, &av));
3106   aa = av;
3107   ai = a->i;
3108 
3109   PetscCall(VecGetArrayWrite(v, &x));
3110   PetscCall(VecGetLocalSize(v, &n));
3111   PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector");
3112   for (i = 0; i < m; i++) {
3113     ncols = ai[1] - ai[0];
3114     ai++;
3115     x[i] = 0;
3116     for (j = 0; j < ncols; j++) {
3117       x[i] += PetscAbsScalar(*aa);
3118       aa++;
3119     }
3120   }
3121   PetscCall(VecRestoreArrayWrite(v, &x));
3122   PetscCall(MatSeqAIJRestoreArrayRead(A, &av));
3123   PetscFunctionReturn(PETSC_SUCCESS);
3124 }
3125 
3126 static PetscErrorCode MatGetRowMax_SeqAIJ(Mat A, Vec v, PetscInt idx[])
3127 {
3128   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
3129   PetscInt         i, j, m = A->rmap->n, *ai, *aj, ncols, n;
3130   PetscScalar     *x;
3131   const MatScalar *aa, *av;
3132 
3133   PetscFunctionBegin;
3134   PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3135   PetscCall(MatSeqAIJGetArrayRead(A, &av));
3136   aa = av;
3137   ai = a->i;
3138   aj = a->j;
3139 
3140   PetscCall(VecGetArrayWrite(v, &x));
3141   PetscCall(VecGetLocalSize(v, &n));
3142   PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector");
3143   for (i = 0; i < m; i++) {
3144     ncols = ai[1] - ai[0];
3145     ai++;
3146     if (ncols == A->cmap->n) { /* row is dense */
3147       x[i] = *aa;
3148       if (idx) idx[i] = 0;
3149     } else { /* row is sparse so already KNOW maximum is 0.0 or higher */
3150       x[i] = 0.0;
3151       if (idx) {
3152         for (j = 0; j < ncols; j++) { /* find first implicit 0.0 in the row */
3153           if (aj[j] > j) {
3154             idx[i] = j;
3155             break;
3156           }
3157         }
3158         /* in case first implicit 0.0 in the row occurs at ncols-th column */
3159         if (j == ncols && j < A->cmap->n) idx[i] = j;
3160       }
3161     }
3162     for (j = 0; j < ncols; j++) {
3163       if (PetscRealPart(x[i]) < PetscRealPart(*aa)) {
3164         x[i] = *aa;
3165         if (idx) idx[i] = *aj;
3166       }
3167       aa++;
3168       aj++;
3169     }
3170   }
3171   PetscCall(VecRestoreArrayWrite(v, &x));
3172   PetscCall(MatSeqAIJRestoreArrayRead(A, &av));
3173   PetscFunctionReturn(PETSC_SUCCESS);
3174 }
3175 
3176 static PetscErrorCode MatGetRowMinAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[])
3177 {
3178   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
3179   PetscInt         i, j, m = A->rmap->n, *ai, *aj, ncols, n;
3180   PetscScalar     *x;
3181   const MatScalar *aa, *av;
3182 
3183   PetscFunctionBegin;
3184   PetscCall(MatSeqAIJGetArrayRead(A, &av));
3185   aa = av;
3186   ai = a->i;
3187   aj = a->j;
3188 
3189   PetscCall(VecGetArrayWrite(v, &x));
3190   PetscCall(VecGetLocalSize(v, &n));
3191   PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector, %" PetscInt_FMT " vs. %" PetscInt_FMT " rows", m, n);
3192   for (i = 0; i < m; i++) {
3193     ncols = ai[1] - ai[0];
3194     ai++;
3195     if (ncols == A->cmap->n) { /* row is dense */
3196       x[i] = *aa;
3197       if (idx) idx[i] = 0;
3198     } else { /* row is sparse so already KNOW minimum is 0.0 or higher */
3199       x[i] = 0.0;
3200       if (idx) { /* find first implicit 0.0 in the row */
3201         for (j = 0; j < ncols; j++) {
3202           if (aj[j] > j) {
3203             idx[i] = j;
3204             break;
3205           }
3206         }
3207         /* in case first implicit 0.0 in the row occurs at ncols-th column */
3208         if (j == ncols && j < A->cmap->n) idx[i] = j;
3209       }
3210     }
3211     for (j = 0; j < ncols; j++) {
3212       if (PetscAbsScalar(x[i]) > PetscAbsScalar(*aa)) {
3213         x[i] = *aa;
3214         if (idx) idx[i] = *aj;
3215       }
3216       aa++;
3217       aj++;
3218     }
3219   }
3220   PetscCall(VecRestoreArrayWrite(v, &x));
3221   PetscCall(MatSeqAIJRestoreArrayRead(A, &av));
3222   PetscFunctionReturn(PETSC_SUCCESS);
3223 }
3224 
3225 static PetscErrorCode MatGetRowMin_SeqAIJ(Mat A, Vec v, PetscInt idx[])
3226 {
3227   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
3228   PetscInt         i, j, m = A->rmap->n, ncols, n;
3229   const PetscInt  *ai, *aj;
3230   PetscScalar     *x;
3231   const MatScalar *aa, *av;
3232 
3233   PetscFunctionBegin;
3234   PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3235   PetscCall(MatSeqAIJGetArrayRead(A, &av));
3236   aa = av;
3237   ai = a->i;
3238   aj = a->j;
3239 
3240   PetscCall(VecGetArrayWrite(v, &x));
3241   PetscCall(VecGetLocalSize(v, &n));
3242   PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector");
3243   for (i = 0; i < m; i++) {
3244     ncols = ai[1] - ai[0];
3245     ai++;
3246     if (ncols == A->cmap->n) { /* row is dense */
3247       x[i] = *aa;
3248       if (idx) idx[i] = 0;
3249     } else { /* row is sparse so already KNOW minimum is 0.0 or lower */
3250       x[i] = 0.0;
3251       if (idx) { /* find first implicit 0.0 in the row */
3252         for (j = 0; j < ncols; j++) {
3253           if (aj[j] > j) {
3254             idx[i] = j;
3255             break;
3256           }
3257         }
3258         /* in case first implicit 0.0 in the row occurs at ncols-th column */
3259         if (j == ncols && j < A->cmap->n) idx[i] = j;
3260       }
3261     }
3262     for (j = 0; j < ncols; j++) {
3263       if (PetscRealPart(x[i]) > PetscRealPart(*aa)) {
3264         x[i] = *aa;
3265         if (idx) idx[i] = *aj;
3266       }
3267       aa++;
3268       aj++;
3269     }
3270   }
3271   PetscCall(VecRestoreArrayWrite(v, &x));
3272   PetscCall(MatSeqAIJRestoreArrayRead(A, &av));
3273   PetscFunctionReturn(PETSC_SUCCESS);
3274 }
3275 
3276 static PetscErrorCode MatInvertBlockDiagonal_SeqAIJ(Mat A, const PetscScalar **values)
3277 {
3278   Mat_SeqAIJ     *a = (Mat_SeqAIJ *)A->data;
3279   PetscInt        i, bs = A->rmap->bs, mbs = A->rmap->n / bs, ipvt[5], bs2 = bs * bs, *v_pivots, ij[7], *IJ, j;
3280   MatScalar      *diag, work[25], *v_work;
3281   const PetscReal shift = 0.0;
3282   PetscBool       allowzeropivot, zeropivotdetected = PETSC_FALSE;
3283 
3284   PetscFunctionBegin;
3285   allowzeropivot = PetscNot(A->erroriffailure);
3286   if (a->ibdiagvalid) {
3287     if (values) *values = a->ibdiag;
3288     PetscFunctionReturn(PETSC_SUCCESS);
3289   }
3290   PetscCall(MatMarkDiagonal_SeqAIJ(A));
3291   if (!a->ibdiag) PetscCall(PetscMalloc1(bs2 * mbs, &a->ibdiag));
3292   diag = a->ibdiag;
3293   if (values) *values = a->ibdiag;
3294   /* factor and invert each block */
3295   switch (bs) {
3296   case 1:
3297     for (i = 0; i < mbs; i++) {
3298       PetscCall(MatGetValues(A, 1, &i, 1, &i, diag + i));
3299       if (PetscAbsScalar(diag[i] + shift) < PETSC_MACHINE_EPSILON) {
3300         PetscCheck(allowzeropivot, PETSC_COMM_SELF, PETSC_ERR_MAT_LU_ZRPVT, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON);
3301         A->factorerrortype             = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3302         A->factorerror_zeropivot_value = PetscAbsScalar(diag[i]);
3303         A->factorerror_zeropivot_row   = i;
3304         PetscCall(PetscInfo(A, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g\n", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON));
3305       }
3306       diag[i] = (PetscScalar)1.0 / (diag[i] + shift);
3307     }
3308     break;
3309   case 2:
3310     for (i = 0; i < mbs; i++) {
3311       ij[0] = 2 * i;
3312       ij[1] = 2 * i + 1;
3313       PetscCall(MatGetValues(A, 2, ij, 2, ij, diag));
3314       PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected));
3315       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3316       PetscCall(PetscKernel_A_gets_transpose_A_2(diag));
3317       diag += 4;
3318     }
3319     break;
3320   case 3:
3321     for (i = 0; i < mbs; i++) {
3322       ij[0] = 3 * i;
3323       ij[1] = 3 * i + 1;
3324       ij[2] = 3 * i + 2;
3325       PetscCall(MatGetValues(A, 3, ij, 3, ij, diag));
3326       PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected));
3327       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3328       PetscCall(PetscKernel_A_gets_transpose_A_3(diag));
3329       diag += 9;
3330     }
3331     break;
3332   case 4:
3333     for (i = 0; i < mbs; i++) {
3334       ij[0] = 4 * i;
3335       ij[1] = 4 * i + 1;
3336       ij[2] = 4 * i + 2;
3337       ij[3] = 4 * i + 3;
3338       PetscCall(MatGetValues(A, 4, ij, 4, ij, diag));
3339       PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected));
3340       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3341       PetscCall(PetscKernel_A_gets_transpose_A_4(diag));
3342       diag += 16;
3343     }
3344     break;
3345   case 5:
3346     for (i = 0; i < mbs; i++) {
3347       ij[0] = 5 * i;
3348       ij[1] = 5 * i + 1;
3349       ij[2] = 5 * i + 2;
3350       ij[3] = 5 * i + 3;
3351       ij[4] = 5 * i + 4;
3352       PetscCall(MatGetValues(A, 5, ij, 5, ij, diag));
3353       PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected));
3354       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3355       PetscCall(PetscKernel_A_gets_transpose_A_5(diag));
3356       diag += 25;
3357     }
3358     break;
3359   case 6:
3360     for (i = 0; i < mbs; i++) {
3361       ij[0] = 6 * i;
3362       ij[1] = 6 * i + 1;
3363       ij[2] = 6 * i + 2;
3364       ij[3] = 6 * i + 3;
3365       ij[4] = 6 * i + 4;
3366       ij[5] = 6 * i + 5;
3367       PetscCall(MatGetValues(A, 6, ij, 6, ij, diag));
3368       PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected));
3369       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3370       PetscCall(PetscKernel_A_gets_transpose_A_6(diag));
3371       diag += 36;
3372     }
3373     break;
3374   case 7:
3375     for (i = 0; i < mbs; i++) {
3376       ij[0] = 7 * i;
3377       ij[1] = 7 * i + 1;
3378       ij[2] = 7 * i + 2;
3379       ij[3] = 7 * i + 3;
3380       ij[4] = 7 * i + 4;
3381       ij[5] = 7 * i + 5;
3382       ij[6] = 7 * i + 6;
3383       PetscCall(MatGetValues(A, 7, ij, 7, ij, diag));
3384       PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected));
3385       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3386       PetscCall(PetscKernel_A_gets_transpose_A_7(diag));
3387       diag += 49;
3388     }
3389     break;
3390   default:
3391     PetscCall(PetscMalloc3(bs, &v_work, bs, &v_pivots, bs, &IJ));
3392     for (i = 0; i < mbs; i++) {
3393       for (j = 0; j < bs; j++) IJ[j] = bs * i + j;
3394       PetscCall(MatGetValues(A, bs, IJ, bs, IJ, diag));
3395       PetscCall(PetscKernel_A_gets_inverse_A(bs, diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected));
3396       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3397       PetscCall(PetscKernel_A_gets_transpose_A_N(diag, bs));
3398       diag += bs2;
3399     }
3400     PetscCall(PetscFree3(v_work, v_pivots, IJ));
3401   }
3402   a->ibdiagvalid = PETSC_TRUE;
3403   PetscFunctionReturn(PETSC_SUCCESS);
3404 }
3405 
3406 static PetscErrorCode MatSetRandom_SeqAIJ(Mat x, PetscRandom rctx)
3407 {
3408   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data;
3409   PetscScalar a, *aa;
3410   PetscInt    m, n, i, j, col;
3411 
3412   PetscFunctionBegin;
3413   if (!x->assembled) {
3414     PetscCall(MatGetSize(x, &m, &n));
3415     for (i = 0; i < m; i++) {
3416       for (j = 0; j < aij->imax[i]; j++) {
3417         PetscCall(PetscRandomGetValue(rctx, &a));
3418         col = (PetscInt)(n * PetscRealPart(a));
3419         PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES));
3420       }
3421     }
3422   } else {
3423     PetscCall(MatSeqAIJGetArrayWrite(x, &aa));
3424     for (i = 0; i < aij->nz; i++) PetscCall(PetscRandomGetValue(rctx, aa + i));
3425     PetscCall(MatSeqAIJRestoreArrayWrite(x, &aa));
3426   }
3427   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
3428   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
3429   PetscFunctionReturn(PETSC_SUCCESS);
3430 }
3431 
3432 /* Like MatSetRandom_SeqAIJ, but do not set values on columns in range of [low, high) */
3433 PetscErrorCode MatSetRandomSkipColumnRange_SeqAIJ_Private(Mat x, PetscInt low, PetscInt high, PetscRandom rctx)
3434 {
3435   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data;
3436   PetscScalar a;
3437   PetscInt    m, n, i, j, col, nskip;
3438 
3439   PetscFunctionBegin;
3440   nskip = high - low;
3441   PetscCall(MatGetSize(x, &m, &n));
3442   n -= nskip; /* shrink number of columns where nonzeros can be set */
3443   for (i = 0; i < m; i++) {
3444     for (j = 0; j < aij->imax[i]; j++) {
3445       PetscCall(PetscRandomGetValue(rctx, &a));
3446       col = (PetscInt)(n * PetscRealPart(a));
3447       if (col >= low) col += nskip; /* shift col rightward to skip the hole */
3448       PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES));
3449     }
3450   }
3451   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
3452   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
3453   PetscFunctionReturn(PETSC_SUCCESS);
3454 }
3455 
3456 static struct _MatOps MatOps_Values = {MatSetValues_SeqAIJ,
3457                                        MatGetRow_SeqAIJ,
3458                                        MatRestoreRow_SeqAIJ,
3459                                        MatMult_SeqAIJ,
3460                                        /*  4*/ MatMultAdd_SeqAIJ,
3461                                        MatMultTranspose_SeqAIJ,
3462                                        MatMultTransposeAdd_SeqAIJ,
3463                                        NULL,
3464                                        NULL,
3465                                        NULL,
3466                                        /* 10*/ NULL,
3467                                        MatLUFactor_SeqAIJ,
3468                                        NULL,
3469                                        MatSOR_SeqAIJ,
3470                                        MatTranspose_SeqAIJ,
3471                                        /* 15*/ MatGetInfo_SeqAIJ,
3472                                        MatEqual_SeqAIJ,
3473                                        MatGetDiagonal_SeqAIJ,
3474                                        MatDiagonalScale_SeqAIJ,
3475                                        MatNorm_SeqAIJ,
3476                                        /* 20*/ NULL,
3477                                        MatAssemblyEnd_SeqAIJ,
3478                                        MatSetOption_SeqAIJ,
3479                                        MatZeroEntries_SeqAIJ,
3480                                        /* 24*/ MatZeroRows_SeqAIJ,
3481                                        NULL,
3482                                        NULL,
3483                                        NULL,
3484                                        NULL,
3485                                        /* 29*/ MatSetUp_Seq_Hash,
3486                                        NULL,
3487                                        NULL,
3488                                        NULL,
3489                                        NULL,
3490                                        /* 34*/ MatDuplicate_SeqAIJ,
3491                                        NULL,
3492                                        NULL,
3493                                        MatILUFactor_SeqAIJ,
3494                                        NULL,
3495                                        /* 39*/ MatAXPY_SeqAIJ,
3496                                        MatCreateSubMatrices_SeqAIJ,
3497                                        MatIncreaseOverlap_SeqAIJ,
3498                                        MatGetValues_SeqAIJ,
3499                                        MatCopy_SeqAIJ,
3500                                        /* 44*/ MatGetRowMax_SeqAIJ,
3501                                        MatScale_SeqAIJ,
3502                                        MatShift_SeqAIJ,
3503                                        MatDiagonalSet_SeqAIJ,
3504                                        MatZeroRowsColumns_SeqAIJ,
3505                                        /* 49*/ MatSetRandom_SeqAIJ,
3506                                        MatGetRowIJ_SeqAIJ,
3507                                        MatRestoreRowIJ_SeqAIJ,
3508                                        MatGetColumnIJ_SeqAIJ,
3509                                        MatRestoreColumnIJ_SeqAIJ,
3510                                        /* 54*/ MatFDColoringCreate_SeqXAIJ,
3511                                        NULL,
3512                                        NULL,
3513                                        MatPermute_SeqAIJ,
3514                                        NULL,
3515                                        /* 59*/ NULL,
3516                                        MatDestroy_SeqAIJ,
3517                                        MatView_SeqAIJ,
3518                                        NULL,
3519                                        NULL,
3520                                        /* 64*/ MatMatMatMultNumeric_SeqAIJ_SeqAIJ_SeqAIJ,
3521                                        NULL,
3522                                        NULL,
3523                                        NULL,
3524                                        MatGetRowMaxAbs_SeqAIJ,
3525                                        /* 69*/ MatGetRowMinAbs_SeqAIJ,
3526                                        NULL,
3527                                        NULL,
3528                                        MatFDColoringApply_AIJ,
3529                                        NULL,
3530                                        /* 74*/ MatFindZeroDiagonals_SeqAIJ,
3531                                        NULL,
3532                                        NULL,
3533                                        NULL,
3534                                        MatLoad_SeqAIJ,
3535                                        /* 79*/ NULL,
3536                                        NULL,
3537                                        NULL,
3538                                        NULL,
3539                                        NULL,
3540                                        /* 84*/ NULL,
3541                                        MatMatMultNumeric_SeqAIJ_SeqAIJ,
3542                                        MatPtAPNumeric_SeqAIJ_SeqAIJ_SparseAxpy,
3543                                        NULL,
3544                                        MatMatTransposeMultNumeric_SeqAIJ_SeqAIJ,
3545                                        /* 90*/ NULL,
3546                                        MatProductSetFromOptions_SeqAIJ,
3547                                        NULL,
3548                                        NULL,
3549                                        MatConjugate_SeqAIJ,
3550                                        /* 94*/ NULL,
3551                                        MatSetValuesRow_SeqAIJ,
3552                                        MatRealPart_SeqAIJ,
3553                                        MatImaginaryPart_SeqAIJ,
3554                                        NULL,
3555                                        /* 99*/ NULL,
3556                                        MatMatSolve_SeqAIJ,
3557                                        NULL,
3558                                        MatGetRowMin_SeqAIJ,
3559                                        NULL,
3560                                        /*104*/ MatMissingDiagonal_SeqAIJ,
3561                                        NULL,
3562                                        NULL,
3563                                        NULL,
3564                                        NULL,
3565                                        /*109*/ NULL,
3566                                        NULL,
3567                                        NULL,
3568                                        NULL,
3569                                        NULL,
3570                                        /*114*/ MatGetMultiProcBlock_SeqAIJ,
3571                                        MatFindNonzeroRows_SeqAIJ,
3572                                        MatGetColumnReductions_SeqAIJ,
3573                                        MatInvertBlockDiagonal_SeqAIJ,
3574                                        MatInvertVariableBlockDiagonal_SeqAIJ,
3575                                        /*119*/ NULL,
3576                                        NULL,
3577                                        NULL,
3578                                        MatTransposeMatMultNumeric_SeqAIJ_SeqAIJ,
3579                                        MatTransposeColoringCreate_SeqAIJ,
3580                                        /*124*/ MatTransColoringApplySpToDen_SeqAIJ,
3581                                        MatTransColoringApplyDenToSp_SeqAIJ,
3582                                        MatRARtNumeric_SeqAIJ_SeqAIJ,
3583                                        NULL,
3584                                        NULL,
3585                                        /*129*/ MatFDColoringSetUp_SeqXAIJ,
3586                                        MatFindOffBlockDiagonalEntries_SeqAIJ,
3587                                        MatCreateMPIMatConcatenateSeqMat_SeqAIJ,
3588                                        MatDestroySubMatrices_SeqAIJ,
3589                                        NULL,
3590                                        /*134*/ NULL,
3591                                        MatCreateGraph_Simple_AIJ,
3592                                        MatTransposeSymbolic_SeqAIJ,
3593                                        MatEliminateZeros_SeqAIJ,
3594                                        MatGetRowSumAbs_SeqAIJ,
3595                                        /*139*/ NULL,
3596                                        NULL,
3597                                        NULL,
3598                                        MatCopyHashToXAIJ_Seq_Hash,
3599                                        NULL,
3600                                        NULL};
3601 
3602 static PetscErrorCode MatSeqAIJSetColumnIndices_SeqAIJ(Mat mat, PetscInt *indices)
3603 {
3604   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data;
3605   PetscInt    i, nz, n;
3606 
3607   PetscFunctionBegin;
3608   nz = aij->maxnz;
3609   n  = mat->rmap->n;
3610   for (i = 0; i < nz; i++) aij->j[i] = indices[i];
3611   aij->nz = nz;
3612   for (i = 0; i < n; i++) aij->ilen[i] = aij->imax[i];
3613   PetscFunctionReturn(PETSC_SUCCESS);
3614 }
3615 
3616 /*
3617  * Given a sparse matrix with global column indices, compact it by using a local column space.
3618  * The result matrix helps saving memory in other algorithms, such as MatPtAPSymbolic_MPIAIJ_MPIAIJ_scalable()
3619  */
3620 PetscErrorCode MatSeqAIJCompactOutExtraColumns_SeqAIJ(Mat mat, ISLocalToGlobalMapping *mapping)
3621 {
3622   Mat_SeqAIJ   *aij = (Mat_SeqAIJ *)mat->data;
3623   PetscHMapI    gid1_lid1;
3624   PetscHashIter tpos;
3625   PetscInt      gid, lid, i, ec, nz = aij->nz;
3626   PetscInt     *garray, *jj = aij->j;
3627 
3628   PetscFunctionBegin;
3629   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3630   PetscAssertPointer(mapping, 2);
3631   /* use a table */
3632   PetscCall(PetscHMapICreateWithSize(mat->rmap->n, &gid1_lid1));
3633   ec = 0;
3634   for (i = 0; i < nz; i++) {
3635     PetscInt data, gid1 = jj[i] + 1;
3636     PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &data));
3637     if (!data) {
3638       /* one based table */
3639       PetscCall(PetscHMapISet(gid1_lid1, gid1, ++ec));
3640     }
3641   }
3642   /* form array of columns we need */
3643   PetscCall(PetscMalloc1(ec, &garray));
3644   PetscHashIterBegin(gid1_lid1, tpos);
3645   while (!PetscHashIterAtEnd(gid1_lid1, tpos)) {
3646     PetscHashIterGetKey(gid1_lid1, tpos, gid);
3647     PetscHashIterGetVal(gid1_lid1, tpos, lid);
3648     PetscHashIterNext(gid1_lid1, tpos);
3649     gid--;
3650     lid--;
3651     garray[lid] = gid;
3652   }
3653   PetscCall(PetscSortInt(ec, garray)); /* sort, and rebuild */
3654   PetscCall(PetscHMapIClear(gid1_lid1));
3655   for (i = 0; i < ec; i++) PetscCall(PetscHMapISet(gid1_lid1, garray[i] + 1, i + 1));
3656   /* compact out the extra columns in B */
3657   for (i = 0; i < nz; i++) {
3658     PetscInt gid1 = jj[i] + 1;
3659     PetscCall(PetscHMapIGetWithDefault(gid1_lid1, gid1, 0, &lid));
3660     lid--;
3661     jj[i] = lid;
3662   }
3663   PetscCall(PetscLayoutDestroy(&mat->cmap));
3664   PetscCall(PetscHMapIDestroy(&gid1_lid1));
3665   PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)mat), ec, ec, 1, &mat->cmap));
3666   PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, mat->cmap->bs, mat->cmap->n, garray, PETSC_OWN_POINTER, mapping));
3667   PetscCall(ISLocalToGlobalMappingSetType(*mapping, ISLOCALTOGLOBALMAPPINGHASH));
3668   PetscFunctionReturn(PETSC_SUCCESS);
3669 }
3670 
3671 /*@
3672   MatSeqAIJSetColumnIndices - Set the column indices for all the rows
3673   in the matrix.
3674 
3675   Input Parameters:
3676 + mat     - the `MATSEQAIJ` matrix
3677 - indices - the column indices
3678 
3679   Level: advanced
3680 
3681   Notes:
3682   This can be called if you have precomputed the nonzero structure of the
3683   matrix and want to provide it to the matrix object to improve the performance
3684   of the `MatSetValues()` operation.
3685 
3686   You MUST have set the correct numbers of nonzeros per row in the call to
3687   `MatCreateSeqAIJ()`, and the columns indices MUST be sorted.
3688 
3689   MUST be called before any calls to `MatSetValues()`
3690 
3691   The indices should start with zero, not one.
3692 
3693 .seealso: [](ch_matrices), `Mat`, `MATSEQAIJ`
3694 @*/
3695 PetscErrorCode MatSeqAIJSetColumnIndices(Mat mat, PetscInt *indices)
3696 {
3697   PetscFunctionBegin;
3698   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3699   PetscAssertPointer(indices, 2);
3700   PetscUseMethod(mat, "MatSeqAIJSetColumnIndices_C", (Mat, PetscInt *), (mat, indices));
3701   PetscFunctionReturn(PETSC_SUCCESS);
3702 }
3703 
3704 static PetscErrorCode MatStoreValues_SeqAIJ(Mat mat)
3705 {
3706   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data;
3707   size_t      nz  = aij->i[mat->rmap->n];
3708 
3709   PetscFunctionBegin;
3710   PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first");
3711 
3712   /* allocate space for values if not already there */
3713   if (!aij->saved_values) PetscCall(PetscMalloc1(nz + 1, &aij->saved_values));
3714 
3715   /* copy values over */
3716   PetscCall(PetscArraycpy(aij->saved_values, aij->a, nz));
3717   PetscFunctionReturn(PETSC_SUCCESS);
3718 }
3719 
3720 /*@
3721   MatStoreValues - Stashes a copy of the matrix values; this allows reusing of the linear part of a Jacobian, while recomputing only the
3722   nonlinear portion.
3723 
3724   Logically Collect
3725 
3726   Input Parameter:
3727 . mat - the matrix (currently only `MATAIJ` matrices support this option)
3728 
3729   Level: advanced
3730 
3731   Example Usage:
3732 .vb
3733     Using SNES
3734     Create Jacobian matrix
3735     Set linear terms into matrix
3736     Apply boundary conditions to matrix, at this time matrix must have
3737       final nonzero structure (i.e. setting the nonlinear terms and applying
3738       boundary conditions again will not change the nonzero structure
3739     MatSetOption(mat, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE);
3740     MatStoreValues(mat);
3741     Call SNESSetJacobian() with matrix
3742     In your Jacobian routine
3743       MatRetrieveValues(mat);
3744       Set nonlinear terms in matrix
3745 
3746     Without `SNESSolve()`, i.e. when you handle nonlinear solve yourself:
3747     // build linear portion of Jacobian
3748     MatSetOption(mat, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE);
3749     MatStoreValues(mat);
3750     loop over nonlinear iterations
3751        MatRetrieveValues(mat);
3752        // call MatSetValues(mat,...) to set nonliner portion of Jacobian
3753        // call MatAssemblyBegin/End() on matrix
3754        Solve linear system with Jacobian
3755     endloop
3756 .ve
3757 
3758   Notes:
3759   Matrix must already be assembled before calling this routine
3760   Must set the matrix option `MatSetOption`(mat,`MAT_NEW_NONZERO_LOCATIONS`,`PETSC_FALSE`); before
3761   calling this routine.
3762 
3763   When this is called multiple times it overwrites the previous set of stored values
3764   and does not allocated additional space.
3765 
3766 .seealso: [](ch_matrices), `Mat`, `MatRetrieveValues()`
3767 @*/
3768 PetscErrorCode MatStoreValues(Mat mat)
3769 {
3770   PetscFunctionBegin;
3771   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3772   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3773   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3774   PetscUseMethod(mat, "MatStoreValues_C", (Mat), (mat));
3775   PetscFunctionReturn(PETSC_SUCCESS);
3776 }
3777 
3778 static PetscErrorCode MatRetrieveValues_SeqAIJ(Mat mat)
3779 {
3780   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data;
3781   PetscInt    nz  = aij->i[mat->rmap->n];
3782 
3783   PetscFunctionBegin;
3784   PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first");
3785   PetscCheck(aij->saved_values, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatStoreValues(A);first");
3786   /* copy values over */
3787   PetscCall(PetscArraycpy(aij->a, aij->saved_values, nz));
3788   PetscFunctionReturn(PETSC_SUCCESS);
3789 }
3790 
3791 /*@
3792   MatRetrieveValues - Retrieves the copy of the matrix values that was stored with `MatStoreValues()`
3793 
3794   Logically Collect
3795 
3796   Input Parameter:
3797 . mat - the matrix (currently only `MATAIJ` matrices support this option)
3798 
3799   Level: advanced
3800 
3801 .seealso: [](ch_matrices), `Mat`, `MatStoreValues()`
3802 @*/
3803 PetscErrorCode MatRetrieveValues(Mat mat)
3804 {
3805   PetscFunctionBegin;
3806   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3807   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3808   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3809   PetscUseMethod(mat, "MatRetrieveValues_C", (Mat), (mat));
3810   PetscFunctionReturn(PETSC_SUCCESS);
3811 }
3812 
3813 /*@
3814   MatCreateSeqAIJ - Creates a sparse matrix in `MATSEQAIJ` (compressed row) format
3815   (the default parallel PETSc format).  For good matrix assembly performance
3816   the user should preallocate the matrix storage by setting the parameter `nz`
3817   (or the array `nnz`).
3818 
3819   Collective
3820 
3821   Input Parameters:
3822 + comm - MPI communicator, set to `PETSC_COMM_SELF`
3823 . m    - number of rows
3824 . n    - number of columns
3825 . nz   - number of nonzeros per row (same for all rows)
3826 - nnz  - array containing the number of nonzeros in the various rows
3827          (possibly different for each row) or NULL
3828 
3829   Output Parameter:
3830 . A - the matrix
3831 
3832   Options Database Keys:
3833 + -mat_no_inode            - Do not use inodes
3834 - -mat_inode_limit <limit> - Sets inode limit (max limit=5)
3835 
3836   Level: intermediate
3837 
3838   Notes:
3839   It is recommend to use `MatCreateFromOptions()` instead of this routine
3840 
3841   If `nnz` is given then `nz` is ignored
3842 
3843   The `MATSEQAIJ` format, also called
3844   compressed row storage, is fully compatible with standard Fortran
3845   storage.  That is, the stored row and column indices can begin at
3846   either one (as in Fortran) or zero.
3847 
3848   Specify the preallocated storage with either `nz` or `nnz` (not both).
3849   Set `nz` = `PETSC_DEFAULT` and `nnz` = `NULL` for PETSc to control dynamic memory
3850   allocation.
3851 
3852   By default, this format uses inodes (identical nodes) when possible, to
3853   improve numerical efficiency of matrix-vector products and solves. We
3854   search for consecutive rows with the same nonzero structure, thereby
3855   reusing matrix information to achieve increased efficiency.
3856 
3857 .seealso: [](ch_matrices), `Mat`, [Sparse Matrix Creation](sec_matsparse), `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()`
3858 @*/
3859 PetscErrorCode MatCreateSeqAIJ(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt nz, const PetscInt nnz[], Mat *A)
3860 {
3861   PetscFunctionBegin;
3862   PetscCall(MatCreate(comm, A));
3863   PetscCall(MatSetSizes(*A, m, n, m, n));
3864   PetscCall(MatSetType(*A, MATSEQAIJ));
3865   PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*A, nz, nnz));
3866   PetscFunctionReturn(PETSC_SUCCESS);
3867 }
3868 
3869 /*@
3870   MatSeqAIJSetPreallocation - For good matrix assembly performance
3871   the user should preallocate the matrix storage by setting the parameter nz
3872   (or the array nnz).  By setting these parameters accurately, performance
3873   during matrix assembly can be increased by more than a factor of 50.
3874 
3875   Collective
3876 
3877   Input Parameters:
3878 + B   - The matrix
3879 . nz  - number of nonzeros per row (same for all rows)
3880 - nnz - array containing the number of nonzeros in the various rows
3881          (possibly different for each row) or NULL
3882 
3883   Options Database Keys:
3884 + -mat_no_inode            - Do not use inodes
3885 - -mat_inode_limit <limit> - Sets inode limit (max limit=5)
3886 
3887   Level: intermediate
3888 
3889   Notes:
3890   If `nnz` is given then `nz` is ignored
3891 
3892   The `MATSEQAIJ` format also called
3893   compressed row storage, is fully compatible with standard Fortran
3894   storage.  That is, the stored row and column indices can begin at
3895   either one (as in Fortran) or zero.  See the users' manual for details.
3896 
3897   Specify the preallocated storage with either `nz` or `nnz` (not both).
3898   Set nz = `PETSC_DEFAULT` and `nnz` = `NULL` for PETSc to control dynamic memory
3899   allocation.
3900 
3901   You can call `MatGetInfo()` to get information on how effective the preallocation was;
3902   for example the fields mallocs,nz_allocated,nz_used,nz_unneeded;
3903   You can also run with the option -info and look for messages with the string
3904   malloc in them to see if additional memory allocation was needed.
3905 
3906   Developer Notes:
3907   Use nz of `MAT_SKIP_ALLOCATION` to not allocate any space for the matrix
3908   entries or columns indices
3909 
3910   By default, this format uses inodes (identical nodes) when possible, to
3911   improve numerical efficiency of matrix-vector products and solves. We
3912   search for consecutive rows with the same nonzero structure, thereby
3913   reusing matrix information to achieve increased efficiency.
3914 
3915 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()`, `MatGetInfo()`,
3916           `MatSeqAIJSetTotalPreallocation()`
3917 @*/
3918 PetscErrorCode MatSeqAIJSetPreallocation(Mat B, PetscInt nz, const PetscInt nnz[])
3919 {
3920   PetscFunctionBegin;
3921   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
3922   PetscValidType(B, 1);
3923   PetscTryMethod(B, "MatSeqAIJSetPreallocation_C", (Mat, PetscInt, const PetscInt[]), (B, nz, nnz));
3924   PetscFunctionReturn(PETSC_SUCCESS);
3925 }
3926 
3927 PetscErrorCode MatSeqAIJSetPreallocation_SeqAIJ(Mat B, PetscInt nz, const PetscInt *nnz)
3928 {
3929   Mat_SeqAIJ *b              = (Mat_SeqAIJ *)B->data;
3930   PetscBool   skipallocation = PETSC_FALSE, realalloc = PETSC_FALSE;
3931   PetscInt    i;
3932 
3933   PetscFunctionBegin;
3934   if (B->hash_active) {
3935     B->ops[0] = b->cops;
3936     PetscCall(PetscHMapIJVDestroy(&b->ht));
3937     PetscCall(PetscFree(b->dnz));
3938     B->hash_active = PETSC_FALSE;
3939   }
3940   if (nz >= 0 || nnz) realalloc = PETSC_TRUE;
3941   if (nz == MAT_SKIP_ALLOCATION) {
3942     skipallocation = PETSC_TRUE;
3943     nz             = 0;
3944   }
3945   PetscCall(PetscLayoutSetUp(B->rmap));
3946   PetscCall(PetscLayoutSetUp(B->cmap));
3947 
3948   if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 5;
3949   PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nz cannot be less than 0: value %" PetscInt_FMT, nz);
3950   if (nnz) {
3951     for (i = 0; i < B->rmap->n; i++) {
3952       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]);
3953       PetscCheck(nnz[i] <= B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nnz cannot be greater than row length: local row %" PetscInt_FMT " value %" PetscInt_FMT " rowlength %" PetscInt_FMT, i, nnz[i], B->cmap->n);
3954     }
3955   }
3956 
3957   B->preallocated = PETSC_TRUE;
3958   if (!skipallocation) {
3959     if (!b->imax) PetscCall(PetscMalloc1(B->rmap->n, &b->imax));
3960     if (!b->ilen) {
3961       /* b->ilen will count nonzeros in each row so far. */
3962       PetscCall(PetscCalloc1(B->rmap->n, &b->ilen));
3963     } else {
3964       PetscCall(PetscMemzero(b->ilen, B->rmap->n * sizeof(PetscInt)));
3965     }
3966     if (!b->ipre) PetscCall(PetscMalloc1(B->rmap->n, &b->ipre));
3967     if (!nnz) {
3968       if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 10;
3969       else if (nz < 0) nz = 1;
3970       nz = PetscMin(nz, B->cmap->n);
3971       for (i = 0; i < B->rmap->n; i++) b->imax[i] = nz;
3972       PetscCall(PetscIntMultError(nz, B->rmap->n, &nz));
3973     } else {
3974       PetscInt64 nz64 = 0;
3975       for (i = 0; i < B->rmap->n; i++) {
3976         b->imax[i] = nnz[i];
3977         nz64 += nnz[i];
3978       }
3979       PetscCall(PetscIntCast(nz64, &nz));
3980     }
3981 
3982     /* allocate the matrix space */
3983     PetscCall(MatSeqXAIJFreeAIJ(B, &b->a, &b->j, &b->i));
3984     PetscCall(PetscShmgetAllocateArray(nz, sizeof(PetscInt), (void **)&b->j));
3985     PetscCall(PetscShmgetAllocateArray(B->rmap->n + 1, sizeof(PetscInt), (void **)&b->i));
3986     b->free_ij = PETSC_TRUE;
3987     if (B->structure_only) {
3988       b->free_a = PETSC_FALSE;
3989     } else {
3990       PetscCall(PetscShmgetAllocateArray(nz, sizeof(PetscScalar), (void **)&b->a));
3991       b->free_a = PETSC_TRUE;
3992     }
3993     b->i[0] = 0;
3994     for (i = 1; i < B->rmap->n + 1; i++) b->i[i] = b->i[i - 1] + b->imax[i - 1];
3995   } else {
3996     b->free_a  = PETSC_FALSE;
3997     b->free_ij = PETSC_FALSE;
3998   }
3999 
4000   if (b->ipre && nnz != b->ipre && b->imax) {
4001     /* reserve user-requested sparsity */
4002     PetscCall(PetscArraycpy(b->ipre, b->imax, B->rmap->n));
4003   }
4004 
4005   b->nz               = 0;
4006   b->maxnz            = nz;
4007   B->info.nz_unneeded = (double)b->maxnz;
4008   if (realalloc) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
4009   B->was_assembled = PETSC_FALSE;
4010   B->assembled     = PETSC_FALSE;
4011   /* We simply deem preallocation has changed nonzero state. Updating the state
4012      will give clients (like AIJKokkos) a chance to know something has happened.
4013   */
4014   B->nonzerostate++;
4015   PetscFunctionReturn(PETSC_SUCCESS);
4016 }
4017 
4018 PetscErrorCode MatResetPreallocation_SeqAIJ_Private(Mat A, PetscBool *memoryreset)
4019 {
4020   Mat_SeqAIJ *a;
4021   PetscInt    i;
4022   PetscBool   skipreset;
4023 
4024   PetscFunctionBegin;
4025   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
4026 
4027   PetscCheck(A->insertmode == NOT_SET_VALUES, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot reset preallocation after setting some values but not yet calling MatAssemblyBegin()/MatAssemblyEnd()");
4028   if (A->num_ass == 0) PetscFunctionReturn(PETSC_SUCCESS);
4029 
4030   /* Check local size. If zero, then return */
4031   if (!A->rmap->n) PetscFunctionReturn(PETSC_SUCCESS);
4032 
4033   a = (Mat_SeqAIJ *)A->data;
4034   /* if no saved info, we error out */
4035   PetscCheck(a->ipre, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "No saved preallocation info ");
4036 
4037   PetscCheck(a->i && a->imax && a->ilen, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Memory info is incomplete, and cannot reset preallocation ");
4038 
4039   PetscCall(PetscArraycmp(a->ipre, a->ilen, A->rmap->n, &skipreset));
4040   if (skipreset) PetscCall(MatZeroEntries(A));
4041   else {
4042     PetscCall(PetscArraycpy(a->imax, a->ipre, A->rmap->n));
4043     PetscCall(PetscArrayzero(a->ilen, A->rmap->n));
4044     a->i[0] = 0;
4045     for (i = 1; i < A->rmap->n + 1; i++) a->i[i] = a->i[i - 1] + a->imax[i - 1];
4046     A->preallocated     = PETSC_TRUE;
4047     a->nz               = 0;
4048     a->maxnz            = a->i[A->rmap->n];
4049     A->info.nz_unneeded = (double)a->maxnz;
4050     A->was_assembled    = PETSC_FALSE;
4051     A->assembled        = PETSC_FALSE;
4052     A->nonzerostate++;
4053     /* Log that the state of this object has changed; this will help guarantee that preconditioners get re-setup */
4054     PetscCall(PetscObjectStateIncrease((PetscObject)A));
4055   }
4056   if (memoryreset) *memoryreset = (PetscBool)!skipreset;
4057   PetscFunctionReturn(PETSC_SUCCESS);
4058 }
4059 
4060 static PetscErrorCode MatResetPreallocation_SeqAIJ(Mat A)
4061 {
4062   PetscFunctionBegin;
4063   PetscCall(MatResetPreallocation_SeqAIJ_Private(A, NULL));
4064   PetscFunctionReturn(PETSC_SUCCESS);
4065 }
4066 
4067 /*@
4068   MatSeqAIJSetPreallocationCSR - Allocates memory for a sparse sequential matrix in `MATSEQAIJ` format.
4069 
4070   Input Parameters:
4071 + B - the matrix
4072 . i - the indices into `j` for the start of each row (indices start with zero)
4073 . j - the column indices for each row (indices start with zero) these must be sorted for each row
4074 - v - optional values in the matrix, use `NULL` if not provided
4075 
4076   Level: developer
4077 
4078   Notes:
4079   The `i`,`j`,`v` values are COPIED with this routine; to avoid the copy use `MatCreateSeqAIJWithArrays()`
4080 
4081   This routine may be called multiple times with different nonzero patterns (or the same nonzero pattern). The nonzero
4082   structure will be the union of all the previous nonzero structures.
4083 
4084   Developer Notes:
4085   An optimization could be added to the implementation where it checks if the `i`, and `j` are identical to the current `i` and `j` and
4086   then just copies the `v` values directly with `PetscMemcpy()`.
4087 
4088   This routine could also take a `PetscCopyMode` argument to allow sharing the values instead of always copying them.
4089 
4090 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatSeqAIJSetPreallocation()`, `MATSEQAIJ`, `MatResetPreallocation()`
4091 @*/
4092 PetscErrorCode MatSeqAIJSetPreallocationCSR(Mat B, const PetscInt i[], const PetscInt j[], const PetscScalar v[])
4093 {
4094   PetscFunctionBegin;
4095   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
4096   PetscValidType(B, 1);
4097   PetscTryMethod(B, "MatSeqAIJSetPreallocationCSR_C", (Mat, const PetscInt[], const PetscInt[], const PetscScalar[]), (B, i, j, v));
4098   PetscFunctionReturn(PETSC_SUCCESS);
4099 }
4100 
4101 static PetscErrorCode MatSeqAIJSetPreallocationCSR_SeqAIJ(Mat B, const PetscInt Ii[], const PetscInt J[], const PetscScalar v[])
4102 {
4103   PetscInt  i;
4104   PetscInt  m, n;
4105   PetscInt  nz;
4106   PetscInt *nnz;
4107 
4108   PetscFunctionBegin;
4109   PetscCheck(Ii[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Ii[0] must be 0 it is %" PetscInt_FMT, Ii[0]);
4110 
4111   PetscCall(PetscLayoutSetUp(B->rmap));
4112   PetscCall(PetscLayoutSetUp(B->cmap));
4113 
4114   PetscCall(MatGetSize(B, &m, &n));
4115   PetscCall(PetscMalloc1(m + 1, &nnz));
4116   for (i = 0; i < m; i++) {
4117     nz = Ii[i + 1] - Ii[i];
4118     PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local row %" PetscInt_FMT " has a negative number of columns %" PetscInt_FMT, i, nz);
4119     nnz[i] = nz;
4120   }
4121   PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz));
4122   PetscCall(PetscFree(nnz));
4123 
4124   for (i = 0; i < m; i++) PetscCall(MatSetValues_SeqAIJ(B, 1, &i, Ii[i + 1] - Ii[i], J + Ii[i], PetscSafePointerPlusOffset(v, Ii[i]), INSERT_VALUES));
4125 
4126   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
4127   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
4128 
4129   PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE));
4130   PetscFunctionReturn(PETSC_SUCCESS);
4131 }
4132 
4133 /*@
4134   MatSeqAIJKron - Computes `C`, the Kronecker product of `A` and `B`.
4135 
4136   Input Parameters:
4137 + A     - left-hand side matrix
4138 . B     - right-hand side matrix
4139 - reuse - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
4140 
4141   Output Parameter:
4142 . C - Kronecker product of `A` and `B`
4143 
4144   Level: intermediate
4145 
4146   Note:
4147   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the product matrix has not changed from that last call to `MatSeqAIJKron()`.
4148 
4149 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATKAIJ`, `MatReuse`
4150 @*/
4151 PetscErrorCode MatSeqAIJKron(Mat A, Mat B, MatReuse reuse, Mat *C)
4152 {
4153   PetscFunctionBegin;
4154   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
4155   PetscValidType(A, 1);
4156   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
4157   PetscValidType(B, 2);
4158   PetscAssertPointer(C, 4);
4159   if (reuse == MAT_REUSE_MATRIX) {
4160     PetscValidHeaderSpecific(*C, MAT_CLASSID, 4);
4161     PetscValidType(*C, 4);
4162   }
4163   PetscTryMethod(A, "MatSeqAIJKron_C", (Mat, Mat, MatReuse, Mat *), (A, B, reuse, C));
4164   PetscFunctionReturn(PETSC_SUCCESS);
4165 }
4166 
4167 static PetscErrorCode MatSeqAIJKron_SeqAIJ(Mat A, Mat B, MatReuse reuse, Mat *C)
4168 {
4169   Mat                newmat;
4170   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
4171   Mat_SeqAIJ        *b = (Mat_SeqAIJ *)B->data;
4172   PetscScalar       *v;
4173   const PetscScalar *aa, *ba;
4174   PetscInt          *i, *j, m, n, p, q, nnz = 0, am = A->rmap->n, bm = B->rmap->n, an = A->cmap->n, bn = B->cmap->n;
4175   PetscBool          flg;
4176 
4177   PetscFunctionBegin;
4178   PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4179   PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4180   PetscCheck(!B->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4181   PetscCheck(B->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4182   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &flg));
4183   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatType %s", ((PetscObject)B)->type_name);
4184   PetscCheck(reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatReuse %d", (int)reuse);
4185   if (reuse == MAT_INITIAL_MATRIX) {
4186     PetscCall(PetscMalloc2(am * bm + 1, &i, a->i[am] * b->i[bm], &j));
4187     PetscCall(MatCreate(PETSC_COMM_SELF, &newmat));
4188     PetscCall(MatSetSizes(newmat, am * bm, an * bn, am * bm, an * bn));
4189     PetscCall(MatSetType(newmat, MATAIJ));
4190     i[0] = 0;
4191     for (m = 0; m < am; ++m) {
4192       for (p = 0; p < bm; ++p) {
4193         i[m * bm + p + 1] = i[m * bm + p] + (a->i[m + 1] - a->i[m]) * (b->i[p + 1] - b->i[p]);
4194         for (n = a->i[m]; n < a->i[m + 1]; ++n) {
4195           for (q = b->i[p]; q < b->i[p + 1]; ++q) j[nnz++] = a->j[n] * bn + b->j[q];
4196         }
4197       }
4198     }
4199     PetscCall(MatSeqAIJSetPreallocationCSR(newmat, i, j, NULL));
4200     *C = newmat;
4201     PetscCall(PetscFree2(i, j));
4202     nnz = 0;
4203   }
4204   PetscCall(MatSeqAIJGetArray(*C, &v));
4205   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
4206   PetscCall(MatSeqAIJGetArrayRead(B, &ba));
4207   for (m = 0; m < am; ++m) {
4208     for (p = 0; p < bm; ++p) {
4209       for (n = a->i[m]; n < a->i[m + 1]; ++n) {
4210         for (q = b->i[p]; q < b->i[p + 1]; ++q) v[nnz++] = aa[n] * ba[q];
4211       }
4212     }
4213   }
4214   PetscCall(MatSeqAIJRestoreArray(*C, &v));
4215   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
4216   PetscCall(MatSeqAIJRestoreArrayRead(B, &ba));
4217   PetscFunctionReturn(PETSC_SUCCESS);
4218 }
4219 
4220 #include <../src/mat/impls/dense/seq/dense.h>
4221 #include <petsc/private/kernels/petscaxpy.h>
4222 
4223 /*
4224     Computes (B'*A')' since computing B*A directly is untenable
4225 
4226                n                       p                          p
4227         [             ]       [             ]         [                 ]
4228       m [      A      ]  *  n [       B     ]   =   m [         C       ]
4229         [             ]       [             ]         [                 ]
4230 
4231 */
4232 PetscErrorCode MatMatMultNumeric_SeqDense_SeqAIJ(Mat A, Mat B, Mat C)
4233 {
4234   Mat_SeqDense      *sub_a = (Mat_SeqDense *)A->data;
4235   Mat_SeqAIJ        *sub_b = (Mat_SeqAIJ *)B->data;
4236   Mat_SeqDense      *sub_c = (Mat_SeqDense *)C->data;
4237   PetscInt           i, j, n, m, q, p;
4238   const PetscInt    *ii, *idx;
4239   const PetscScalar *b, *a, *a_q;
4240   PetscScalar       *c, *c_q;
4241   PetscInt           clda = sub_c->lda;
4242   PetscInt           alda = sub_a->lda;
4243 
4244   PetscFunctionBegin;
4245   m = A->rmap->n;
4246   n = A->cmap->n;
4247   p = B->cmap->n;
4248   a = sub_a->v;
4249   b = sub_b->a;
4250   c = sub_c->v;
4251   if (clda == m) {
4252     PetscCall(PetscArrayzero(c, m * p));
4253   } else {
4254     for (j = 0; j < p; j++)
4255       for (i = 0; i < m; i++) c[j * clda + i] = 0.0;
4256   }
4257   ii  = sub_b->i;
4258   idx = sub_b->j;
4259   for (i = 0; i < n; i++) {
4260     q = ii[i + 1] - ii[i];
4261     while (q-- > 0) {
4262       c_q = c + clda * (*idx);
4263       a_q = a + alda * i;
4264       PetscKernelAXPY(c_q, *b, a_q, m);
4265       idx++;
4266       b++;
4267     }
4268   }
4269   PetscFunctionReturn(PETSC_SUCCESS);
4270 }
4271 
4272 PetscErrorCode MatMatMultSymbolic_SeqDense_SeqAIJ(Mat A, Mat B, PetscReal fill, Mat C)
4273 {
4274   PetscInt  m = A->rmap->n, n = B->cmap->n;
4275   PetscBool cisdense;
4276 
4277   PetscFunctionBegin;
4278   PetscCheck(A->cmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "A->cmap->n %" PetscInt_FMT " != B->rmap->n %" PetscInt_FMT, A->cmap->n, B->rmap->n);
4279   PetscCall(MatSetSizes(C, m, n, m, n));
4280   PetscCall(MatSetBlockSizesFromMats(C, A, B));
4281   PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATSEQDENSECUDA, MATSEQDENSEHIP, ""));
4282   if (!cisdense) PetscCall(MatSetType(C, MATDENSE));
4283   PetscCall(MatSetUp(C));
4284 
4285   C->ops->matmultnumeric = MatMatMultNumeric_SeqDense_SeqAIJ;
4286   PetscFunctionReturn(PETSC_SUCCESS);
4287 }
4288 
4289 /*MC
4290    MATSEQAIJ - MATSEQAIJ = "seqaij" - A matrix type to be used for sequential sparse matrices,
4291    based on compressed sparse row format.
4292 
4293    Options Database Key:
4294 . -mat_type seqaij - sets the matrix type to "seqaij" during a call to MatSetFromOptions()
4295 
4296    Level: beginner
4297 
4298    Notes:
4299     `MatSetValues()` may be called for this matrix type with a `NULL` argument for the numerical values,
4300     in this case the values associated with the rows and columns one passes in are set to zero
4301     in the matrix
4302 
4303     `MatSetOptions`(,`MAT_STRUCTURE_ONLY`,`PETSC_TRUE`) may be called for this matrix type. In this no
4304     space is allocated for the nonzero entries and any entries passed with `MatSetValues()` are ignored
4305 
4306   Developer Note:
4307     It would be nice if all matrix formats supported passing `NULL` in for the numerical values
4308 
4309 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatSetFromOptions()`, `MatSetType()`, `MatCreate()`, `MatType`, `MATSELL`, `MATSEQSELL`, `MATMPISELL`
4310 M*/
4311 
4312 /*MC
4313    MATAIJ - MATAIJ = "aij" - A matrix type to be used for sparse matrices.
4314 
4315    This matrix type is identical to `MATSEQAIJ` when constructed with a single process communicator,
4316    and `MATMPIAIJ` otherwise.  As a result, for single process communicators,
4317    `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported
4318    for communicators controlling multiple processes.  It is recommended that you call both of
4319    the above preallocation routines for simplicity.
4320 
4321    Options Database Key:
4322 . -mat_type aij - sets the matrix type to "aij" during a call to `MatSetFromOptions()`
4323 
4324   Level: beginner
4325 
4326    Note:
4327    Subclasses include `MATAIJCUSPARSE`, `MATAIJPERM`, `MATAIJSELL`, `MATAIJMKL`, `MATAIJCRL`, and also automatically switches over to use inodes when
4328    enough exist.
4329 
4330 .seealso: [](ch_matrices), `Mat`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATMPIAIJ`, `MATSELL`, `MATSEQSELL`, `MATMPISELL`
4331 M*/
4332 
4333 /*MC
4334    MATAIJCRL - MATAIJCRL = "aijcrl" - A matrix type to be used for sparse matrices.
4335 
4336    Options Database Key:
4337 . -mat_type aijcrl - sets the matrix type to "aijcrl" during a call to `MatSetFromOptions()`
4338 
4339   Level: beginner
4340 
4341    Note:
4342    This matrix type is identical to `MATSEQAIJCRL` when constructed with a single process communicator,
4343    and `MATMPIAIJCRL` otherwise.  As a result, for single process communicators,
4344    `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported
4345    for communicators controlling multiple processes.  It is recommended that you call both of
4346    the above preallocation routines for simplicity.
4347 
4348 .seealso: [](ch_matrices), `Mat`, `MatCreateMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL`
4349 M*/
4350 
4351 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCRL(Mat, MatType, MatReuse, Mat *);
4352 #if defined(PETSC_HAVE_ELEMENTAL)
4353 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat, MatType, MatReuse, Mat *);
4354 #endif
4355 #if defined(PETSC_HAVE_SCALAPACK) && (defined(PETSC_USE_REAL_SINGLE) || defined(PETSC_USE_REAL_DOUBLE))
4356 PETSC_INTERN PetscErrorCode MatConvert_AIJ_ScaLAPACK(Mat, MatType, MatReuse, Mat *);
4357 #endif
4358 #if defined(PETSC_HAVE_HYPRE)
4359 PETSC_INTERN PetscErrorCode MatConvert_AIJ_HYPRE(Mat A, MatType, MatReuse, Mat *);
4360 #endif
4361 
4362 PETSC_EXTERN PetscErrorCode MatConvert_SeqAIJ_SeqSELL(Mat, MatType, MatReuse, Mat *);
4363 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat, MatType, MatReuse, Mat *);
4364 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat);
4365 
4366 /*@C
4367   MatSeqAIJGetArray - gives read/write access to the array where the data for a `MATSEQAIJ` matrix is stored
4368 
4369   Not Collective
4370 
4371   Input Parameter:
4372 . A - a `MATSEQAIJ` matrix
4373 
4374   Output Parameter:
4375 . array - pointer to the data
4376 
4377   Level: intermediate
4378 
4379 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArray()`
4380 @*/
4381 PetscErrorCode MatSeqAIJGetArray(Mat A, PetscScalar *array[])
4382 {
4383   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4384 
4385   PetscFunctionBegin;
4386   if (aij->ops->getarray) {
4387     PetscCall((*aij->ops->getarray)(A, array));
4388   } else {
4389     *array = aij->a;
4390   }
4391   PetscFunctionReturn(PETSC_SUCCESS);
4392 }
4393 
4394 /*@C
4395   MatSeqAIJRestoreArray - returns access to the array where the data for a `MATSEQAIJ` matrix is stored obtained by `MatSeqAIJGetArray()`
4396 
4397   Not Collective
4398 
4399   Input Parameters:
4400 + A     - a `MATSEQAIJ` matrix
4401 - array - pointer to the data
4402 
4403   Level: intermediate
4404 
4405 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`
4406 @*/
4407 PetscErrorCode MatSeqAIJRestoreArray(Mat A, PetscScalar *array[])
4408 {
4409   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4410 
4411   PetscFunctionBegin;
4412   if (aij->ops->restorearray) {
4413     PetscCall((*aij->ops->restorearray)(A, array));
4414   } else {
4415     *array = NULL;
4416   }
4417   PetscCall(PetscObjectStateIncrease((PetscObject)A));
4418   PetscFunctionReturn(PETSC_SUCCESS);
4419 }
4420 
4421 /*@C
4422   MatSeqAIJGetArrayRead - gives read-only access to the array where the data for a `MATSEQAIJ` matrix is stored
4423 
4424   Not Collective; No Fortran Support
4425 
4426   Input Parameter:
4427 . A - a `MATSEQAIJ` matrix
4428 
4429   Output Parameter:
4430 . array - pointer to the data
4431 
4432   Level: intermediate
4433 
4434 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()`
4435 @*/
4436 PetscErrorCode MatSeqAIJGetArrayRead(Mat A, const PetscScalar *array[])
4437 {
4438   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4439 
4440   PetscFunctionBegin;
4441   if (aij->ops->getarrayread) {
4442     PetscCall((*aij->ops->getarrayread)(A, array));
4443   } else {
4444     *array = aij->a;
4445   }
4446   PetscFunctionReturn(PETSC_SUCCESS);
4447 }
4448 
4449 /*@C
4450   MatSeqAIJRestoreArrayRead - restore the read-only access array obtained from `MatSeqAIJGetArrayRead()`
4451 
4452   Not Collective; No Fortran Support
4453 
4454   Input Parameter:
4455 . A - a `MATSEQAIJ` matrix
4456 
4457   Output Parameter:
4458 . array - pointer to the data
4459 
4460   Level: intermediate
4461 
4462 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()`
4463 @*/
4464 PetscErrorCode MatSeqAIJRestoreArrayRead(Mat A, const PetscScalar *array[])
4465 {
4466   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4467 
4468   PetscFunctionBegin;
4469   if (aij->ops->restorearrayread) {
4470     PetscCall((*aij->ops->restorearrayread)(A, array));
4471   } else {
4472     *array = NULL;
4473   }
4474   PetscFunctionReturn(PETSC_SUCCESS);
4475 }
4476 
4477 /*@C
4478   MatSeqAIJGetArrayWrite - gives write-only access to the array where the data for a `MATSEQAIJ` matrix is stored
4479 
4480   Not Collective; No Fortran Support
4481 
4482   Input Parameter:
4483 . A - a `MATSEQAIJ` matrix
4484 
4485   Output Parameter:
4486 . array - pointer to the data
4487 
4488   Level: intermediate
4489 
4490 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()`
4491 @*/
4492 PetscErrorCode MatSeqAIJGetArrayWrite(Mat A, PetscScalar *array[])
4493 {
4494   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4495 
4496   PetscFunctionBegin;
4497   if (aij->ops->getarraywrite) {
4498     PetscCall((*aij->ops->getarraywrite)(A, array));
4499   } else {
4500     *array = aij->a;
4501   }
4502   PetscCall(PetscObjectStateIncrease((PetscObject)A));
4503   PetscFunctionReturn(PETSC_SUCCESS);
4504 }
4505 
4506 /*@C
4507   MatSeqAIJRestoreArrayWrite - restore the read-only access array obtained from MatSeqAIJGetArrayRead
4508 
4509   Not Collective; No Fortran Support
4510 
4511   Input Parameter:
4512 . A - a MATSEQAIJ matrix
4513 
4514   Output Parameter:
4515 . array - pointer to the data
4516 
4517   Level: intermediate
4518 
4519 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()`
4520 @*/
4521 PetscErrorCode MatSeqAIJRestoreArrayWrite(Mat A, PetscScalar *array[])
4522 {
4523   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4524 
4525   PetscFunctionBegin;
4526   if (aij->ops->restorearraywrite) {
4527     PetscCall((*aij->ops->restorearraywrite)(A, array));
4528   } else {
4529     *array = NULL;
4530   }
4531   PetscFunctionReturn(PETSC_SUCCESS);
4532 }
4533 
4534 /*@C
4535   MatSeqAIJGetCSRAndMemType - Get the CSR arrays and the memory type of the `MATSEQAIJ` matrix
4536 
4537   Not Collective; No Fortran Support
4538 
4539   Input Parameter:
4540 . mat - a matrix of type `MATSEQAIJ` or its subclasses
4541 
4542   Output Parameters:
4543 + i     - row map array of the matrix
4544 . j     - column index array of the matrix
4545 . a     - data array of the matrix
4546 - mtype - memory type of the arrays
4547 
4548   Level: developer
4549 
4550   Notes:
4551   Any of the output parameters can be `NULL`, in which case the corresponding value is not returned.
4552   If mat is a device matrix, the arrays are on the device. Otherwise, they are on the host.
4553 
4554   One can call this routine on a preallocated but not assembled matrix to just get the memory of the CSR underneath the matrix.
4555   If the matrix is assembled, the data array `a` is guaranteed to have the latest values of the matrix.
4556 
4557 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()`
4558 @*/
4559 PetscErrorCode MatSeqAIJGetCSRAndMemType(Mat mat, const PetscInt *i[], const PetscInt *j[], PetscScalar *a[], PetscMemType *mtype)
4560 {
4561   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data;
4562 
4563   PetscFunctionBegin;
4564   PetscCheck(mat->preallocated, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "matrix is not preallocated");
4565   if (aij->ops->getcsrandmemtype) {
4566     PetscCall((*aij->ops->getcsrandmemtype)(mat, i, j, a, mtype));
4567   } else {
4568     if (i) *i = aij->i;
4569     if (j) *j = aij->j;
4570     if (a) *a = aij->a;
4571     if (mtype) *mtype = PETSC_MEMTYPE_HOST;
4572   }
4573   PetscFunctionReturn(PETSC_SUCCESS);
4574 }
4575 
4576 /*@
4577   MatSeqAIJGetMaxRowNonzeros - returns the maximum number of nonzeros in any row
4578 
4579   Not Collective
4580 
4581   Input Parameter:
4582 . A - a `MATSEQAIJ` matrix
4583 
4584   Output Parameter:
4585 . nz - the maximum number of nonzeros in any row
4586 
4587   Level: intermediate
4588 
4589 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArray()`
4590 @*/
4591 PetscErrorCode MatSeqAIJGetMaxRowNonzeros(Mat A, PetscInt *nz)
4592 {
4593   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4594 
4595   PetscFunctionBegin;
4596   *nz = aij->rmax;
4597   PetscFunctionReturn(PETSC_SUCCESS);
4598 }
4599 
4600 static PetscErrorCode MatCOOStructDestroy_SeqAIJ(void **data)
4601 {
4602   MatCOOStruct_SeqAIJ *coo = (MatCOOStruct_SeqAIJ *)*data;
4603 
4604   PetscFunctionBegin;
4605   PetscCall(PetscFree(coo->perm));
4606   PetscCall(PetscFree(coo->jmap));
4607   PetscCall(PetscFree(coo));
4608   PetscFunctionReturn(PETSC_SUCCESS);
4609 }
4610 
4611 PetscErrorCode MatSetPreallocationCOO_SeqAIJ(Mat mat, PetscCount coo_n, PetscInt coo_i[], PetscInt coo_j[])
4612 {
4613   MPI_Comm             comm;
4614   PetscInt            *i, *j;
4615   PetscInt             M, N, row, iprev;
4616   PetscCount           k, p, q, nneg, nnz, start, end; /* Index the coo array, so use PetscCount as their type */
4617   PetscInt            *Ai;                             /* Change to PetscCount once we use it for row pointers */
4618   PetscInt            *Aj;
4619   PetscScalar         *Aa;
4620   Mat_SeqAIJ          *seqaij = (Mat_SeqAIJ *)mat->data;
4621   MatType              rtype;
4622   PetscCount          *perm, *jmap;
4623   MatCOOStruct_SeqAIJ *coo;
4624   PetscBool            isorted;
4625   PetscBool            hypre;
4626 
4627   PetscFunctionBegin;
4628   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
4629   PetscCall(MatGetSize(mat, &M, &N));
4630   i = coo_i;
4631   j = coo_j;
4632   PetscCall(PetscMalloc1(coo_n, &perm));
4633 
4634   /* Ignore entries with negative row or col indices; at the same time, check if i[] is already sorted (e.g., MatConvert_AlJ_HYPRE results in this case) */
4635   isorted = PETSC_TRUE;
4636   iprev   = PETSC_INT_MIN;
4637   for (k = 0; k < coo_n; k++) {
4638     if (j[k] < 0) i[k] = -1;
4639     if (isorted) {
4640       if (i[k] < iprev) isorted = PETSC_FALSE;
4641       else iprev = i[k];
4642     }
4643     perm[k] = k;
4644   }
4645 
4646   /* Sort by row if not already */
4647   if (!isorted) PetscCall(PetscSortIntWithIntCountArrayPair(coo_n, i, j, perm));
4648   PetscCheck(coo_n == 0 || i[coo_n - 1] < M, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "COO row index %" PetscInt_FMT " is >= the matrix row size %" PetscInt_FMT, i[coo_n - 1], M);
4649 
4650   /* Advance k to the first row with a non-negative index */
4651   for (k = 0; k < coo_n; k++)
4652     if (i[k] >= 0) break;
4653   nneg = k;
4654   PetscCall(PetscMalloc1(coo_n - nneg + 1, &jmap)); /* +1 to make a CSR-like data structure. jmap[i] originally is the number of repeats for i-th nonzero */
4655   nnz = 0;                                          /* Total number of unique nonzeros to be counted */
4656   jmap++;                                           /* Inc jmap by 1 for convenience */
4657 
4658   PetscCall(PetscShmgetAllocateArray(M + 1, sizeof(PetscInt), (void **)&Ai)); /* CSR of A */
4659   PetscCall(PetscArrayzero(Ai, M + 1));
4660   PetscCall(PetscShmgetAllocateArray(coo_n - nneg, sizeof(PetscInt), (void **)&Aj)); /* We have at most coo_n-nneg unique nonzeros */
4661 
4662   PetscCall(PetscStrcmp("_internal_COO_mat_for_hypre", ((PetscObject)mat)->name, &hypre));
4663 
4664   /* In each row, sort by column, then unique column indices to get row length */
4665   Ai++;  /* Inc by 1 for convenience */
4666   q = 0; /* q-th unique nonzero, with q starting from 0 */
4667   while (k < coo_n) {
4668     PetscBool strictly_sorted; // this row is strictly sorted?
4669     PetscInt  jprev;
4670 
4671     /* get [start,end) indices for this row; also check if cols in this row are strictly sorted */
4672     row             = i[k];
4673     start           = k;
4674     jprev           = PETSC_INT_MIN;
4675     strictly_sorted = PETSC_TRUE;
4676     while (k < coo_n && i[k] == row) {
4677       if (strictly_sorted) {
4678         if (j[k] <= jprev) strictly_sorted = PETSC_FALSE;
4679         else jprev = j[k];
4680       }
4681       k++;
4682     }
4683     end = k;
4684 
4685     /* hack for HYPRE: swap min column to diag so that diagonal values will go first */
4686     if (hypre) {
4687       PetscInt  minj    = PETSC_INT_MAX;
4688       PetscBool hasdiag = PETSC_FALSE;
4689 
4690       if (strictly_sorted) { // fast path to swap the first and the diag
4691         PetscCount tmp;
4692         for (p = start; p < end; p++) {
4693           if (j[p] == row && p != start) {
4694             j[p]        = j[start]; // swap j[], so that the diagonal value will go first (manipulated by perm[])
4695             j[start]    = row;
4696             tmp         = perm[start];
4697             perm[start] = perm[p]; // also swap perm[] so we can save the call to PetscSortIntWithCountArray() below
4698             perm[p]     = tmp;
4699             break;
4700           }
4701         }
4702       } else {
4703         for (p = start; p < end; p++) {
4704           hasdiag = (PetscBool)(hasdiag || (j[p] == row));
4705           minj    = PetscMin(minj, j[p]);
4706         }
4707 
4708         if (hasdiag) {
4709           for (p = start; p < end; p++) {
4710             if (j[p] == minj) j[p] = row;
4711             else if (j[p] == row) j[p] = minj;
4712           }
4713         }
4714       }
4715     }
4716     // sort by columns in a row. perm[] indicates their original order
4717     if (!strictly_sorted) PetscCall(PetscSortIntWithCountArray(end - start, j + start, perm + start));
4718     PetscCheck(end == start || j[end - 1] < N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "COO column index %" PetscInt_FMT " is >= the matrix column size %" PetscInt_FMT, j[end - 1], N);
4719 
4720     if (strictly_sorted) { // fast path to set Aj[], jmap[], Ai[], nnz, q
4721       for (p = start; p < end; p++, q++) {
4722         Aj[q]   = j[p];
4723         jmap[q] = 1;
4724       }
4725       PetscCall(PetscIntCast(end - start, Ai + row));
4726       nnz += Ai[row]; // q is already advanced
4727     } else {
4728       /* Find number of unique col entries in this row */
4729       Aj[q]   = j[start]; /* Log the first nonzero in this row */
4730       jmap[q] = 1;        /* Number of repeats of this nonzero entry */
4731       Ai[row] = 1;
4732       nnz++;
4733 
4734       for (p = start + 1; p < end; p++) { /* Scan remaining nonzero in this row */
4735         if (j[p] != j[p - 1]) {           /* Meet a new nonzero */
4736           q++;
4737           jmap[q] = 1;
4738           Aj[q]   = j[p];
4739           Ai[row]++;
4740           nnz++;
4741         } else {
4742           jmap[q]++;
4743         }
4744       }
4745       q++; /* Move to next row and thus next unique nonzero */
4746     }
4747   }
4748 
4749   Ai--; /* Back to the beginning of Ai[] */
4750   for (k = 0; k < M; k++) Ai[k + 1] += Ai[k];
4751   jmap--; // Back to the beginning of jmap[]
4752   jmap[0] = 0;
4753   for (k = 0; k < nnz; k++) jmap[k + 1] += jmap[k];
4754 
4755   if (nnz < coo_n - nneg) { /* Reallocate with actual number of unique nonzeros */
4756     PetscCount *jmap_new;
4757     PetscInt   *Aj_new;
4758 
4759     PetscCall(PetscMalloc1(nnz + 1, &jmap_new));
4760     PetscCall(PetscArraycpy(jmap_new, jmap, nnz + 1));
4761     PetscCall(PetscFree(jmap));
4762     jmap = jmap_new;
4763 
4764     PetscCall(PetscShmgetAllocateArray(nnz, sizeof(PetscInt), (void **)&Aj_new));
4765     PetscCall(PetscArraycpy(Aj_new, Aj, nnz));
4766     PetscCall(PetscShmgetDeallocateArray((void **)&Aj));
4767     Aj = Aj_new;
4768   }
4769 
4770   if (nneg) { /* Discard heading entries with negative indices in perm[], as we'll access it from index 0 in MatSetValuesCOO */
4771     PetscCount *perm_new;
4772 
4773     PetscCall(PetscMalloc1(coo_n - nneg, &perm_new));
4774     PetscCall(PetscArraycpy(perm_new, perm + nneg, coo_n - nneg));
4775     PetscCall(PetscFree(perm));
4776     perm = perm_new;
4777   }
4778 
4779   PetscCall(MatGetRootType_Private(mat, &rtype));
4780   PetscCall(PetscShmgetAllocateArray(nnz, sizeof(PetscScalar), (void **)&Aa));
4781   PetscCall(PetscArrayzero(Aa, nnz));
4782   PetscCall(MatSetSeqAIJWithArrays_private(PETSC_COMM_SELF, M, N, Ai, Aj, Aa, rtype, mat));
4783 
4784   seqaij->free_a = seqaij->free_ij = PETSC_TRUE; /* Let newmat own Ai, Aj and Aa */
4785 
4786   // Put the COO struct in a container and then attach that to the matrix
4787   PetscCall(PetscMalloc1(1, &coo));
4788   PetscCall(PetscIntCast(nnz, &coo->nz));
4789   coo->n    = coo_n;
4790   coo->Atot = coo_n - nneg; // Annz is seqaij->nz, so no need to record that again
4791   coo->jmap = jmap;         // of length nnz+1
4792   coo->perm = perm;
4793   PetscCall(PetscObjectContainerCompose((PetscObject)mat, "__PETSc_MatCOOStruct_Host", coo, MatCOOStructDestroy_SeqAIJ));
4794   PetscFunctionReturn(PETSC_SUCCESS);
4795 }
4796 
4797 static PetscErrorCode MatSetValuesCOO_SeqAIJ(Mat A, const PetscScalar v[], InsertMode imode)
4798 {
4799   Mat_SeqAIJ          *aseq = (Mat_SeqAIJ *)A->data;
4800   PetscCount           i, j, Annz = aseq->nz;
4801   PetscCount          *perm, *jmap;
4802   PetscScalar         *Aa;
4803   PetscContainer       container;
4804   MatCOOStruct_SeqAIJ *coo;
4805 
4806   PetscFunctionBegin;
4807   PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_MatCOOStruct_Host", (PetscObject *)&container));
4808   PetscCheck(container, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not found MatCOOStruct on this matrix");
4809   PetscCall(PetscContainerGetPointer(container, (void **)&coo));
4810   perm = coo->perm;
4811   jmap = coo->jmap;
4812   PetscCall(MatSeqAIJGetArray(A, &Aa));
4813   for (i = 0; i < Annz; i++) {
4814     PetscScalar sum = 0.0;
4815     for (j = jmap[i]; j < jmap[i + 1]; j++) sum += v[perm[j]];
4816     Aa[i] = (imode == INSERT_VALUES ? 0.0 : Aa[i]) + sum;
4817   }
4818   PetscCall(MatSeqAIJRestoreArray(A, &Aa));
4819   PetscFunctionReturn(PETSC_SUCCESS);
4820 }
4821 
4822 #if defined(PETSC_HAVE_CUDA)
4823 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCUSPARSE(Mat, MatType, MatReuse, Mat *);
4824 #endif
4825 #if defined(PETSC_HAVE_HIP)
4826 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJHIPSPARSE(Mat, MatType, MatReuse, Mat *);
4827 #endif
4828 #if defined(PETSC_HAVE_KOKKOS_KERNELS)
4829 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJKokkos(Mat, MatType, MatReuse, Mat *);
4830 #endif
4831 
4832 PETSC_EXTERN PetscErrorCode MatCreate_SeqAIJ(Mat B)
4833 {
4834   Mat_SeqAIJ *b;
4835   PetscMPIInt size;
4836 
4837   PetscFunctionBegin;
4838   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size));
4839   PetscCheck(size <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Comm must be of size 1");
4840 
4841   PetscCall(PetscNew(&b));
4842 
4843   B->data   = (void *)b;
4844   B->ops[0] = MatOps_Values;
4845   if (B->sortedfull) B->ops->setvalues = MatSetValues_SeqAIJ_SortedFull;
4846 
4847   b->row                = NULL;
4848   b->col                = NULL;
4849   b->icol               = NULL;
4850   b->reallocs           = 0;
4851   b->ignorezeroentries  = PETSC_FALSE;
4852   b->roworiented        = PETSC_TRUE;
4853   b->nonew              = 0;
4854   b->diag               = NULL;
4855   b->solve_work         = NULL;
4856   B->spptr              = NULL;
4857   b->saved_values       = NULL;
4858   b->idiag              = NULL;
4859   b->mdiag              = NULL;
4860   b->ssor_work          = NULL;
4861   b->omega              = 1.0;
4862   b->fshift             = 0.0;
4863   b->ibdiagvalid        = PETSC_FALSE;
4864   b->keepnonzeropattern = PETSC_FALSE;
4865 
4866   PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ));
4867 #if defined(PETSC_HAVE_MATLAB)
4868   PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEnginePut_C", MatlabEnginePut_SeqAIJ));
4869   PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEngineGet_C", MatlabEngineGet_SeqAIJ));
4870 #endif
4871   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetColumnIndices_C", MatSeqAIJSetColumnIndices_SeqAIJ));
4872   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_SeqAIJ));
4873   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_SeqAIJ));
4874   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsbaij_C", MatConvert_SeqAIJ_SeqSBAIJ));
4875   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqbaij_C", MatConvert_SeqAIJ_SeqBAIJ));
4876   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijperm_C", MatConvert_SeqAIJ_SeqAIJPERM));
4877   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijsell_C", MatConvert_SeqAIJ_SeqAIJSELL));
4878 #if defined(PETSC_HAVE_MKL_SPARSE)
4879   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijmkl_C", MatConvert_SeqAIJ_SeqAIJMKL));
4880 #endif
4881 #if defined(PETSC_HAVE_CUDA)
4882   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcusparse_C", MatConvert_SeqAIJ_SeqAIJCUSPARSE));
4883   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", MatProductSetFromOptions_SeqAIJ));
4884   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", MatProductSetFromOptions_SeqAIJ));
4885 #endif
4886 #if defined(PETSC_HAVE_HIP)
4887   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijhipsparse_C", MatConvert_SeqAIJ_SeqAIJHIPSPARSE));
4888   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijhipsparse_seqaij_C", MatProductSetFromOptions_SeqAIJ));
4889   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijhipsparse_C", MatProductSetFromOptions_SeqAIJ));
4890 #endif
4891 #if defined(PETSC_HAVE_KOKKOS_KERNELS)
4892   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijkokkos_C", MatConvert_SeqAIJ_SeqAIJKokkos));
4893 #endif
4894   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcrl_C", MatConvert_SeqAIJ_SeqAIJCRL));
4895 #if defined(PETSC_HAVE_ELEMENTAL)
4896   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_elemental_C", MatConvert_SeqAIJ_Elemental));
4897 #endif
4898 #if defined(PETSC_HAVE_SCALAPACK) && (defined(PETSC_USE_REAL_SINGLE) || defined(PETSC_USE_REAL_DOUBLE))
4899   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_scalapack_C", MatConvert_AIJ_ScaLAPACK));
4900 #endif
4901 #if defined(PETSC_HAVE_HYPRE)
4902   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_hypre_C", MatConvert_AIJ_HYPRE));
4903   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", MatProductSetFromOptions_Transpose_AIJ_AIJ));
4904 #endif
4905   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqdense_C", MatConvert_SeqAIJ_SeqDense));
4906   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsell_C", MatConvert_SeqAIJ_SeqSELL));
4907   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_is_C", MatConvert_XAIJ_IS));
4908   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_SeqAIJ));
4909   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsHermitianTranspose_C", MatIsHermitianTranspose_SeqAIJ));
4910   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocation_C", MatSeqAIJSetPreallocation_SeqAIJ));
4911   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetPreallocation_C", MatResetPreallocation_SeqAIJ));
4912   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetHash_C", MatResetHash_SeqAIJ));
4913   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocationCSR_C", MatSeqAIJSetPreallocationCSR_SeqAIJ));
4914   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatReorderForNonzeroDiagonal_C", MatReorderForNonzeroDiagonal_SeqAIJ));
4915   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_is_seqaij_C", MatProductSetFromOptions_IS_XAIJ));
4916   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqdense_seqaij_C", MatProductSetFromOptions_SeqDense_SeqAIJ));
4917   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaij_C", MatProductSetFromOptions_SeqAIJ));
4918   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJKron_C", MatSeqAIJKron_SeqAIJ));
4919   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_SeqAIJ));
4920   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetValuesCOO_C", MatSetValuesCOO_SeqAIJ));
4921   PetscCall(MatCreate_SeqAIJ_Inode(B));
4922   PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ));
4923   PetscCall(MatSeqAIJSetTypeFromOptions(B)); /* this allows changing the matrix subtype to say MATSEQAIJPERM */
4924   PetscFunctionReturn(PETSC_SUCCESS);
4925 }
4926 
4927 /*
4928     Given a matrix generated with MatGetFactor() duplicates all the information in A into C
4929 */
4930 PetscErrorCode MatDuplicateNoCreate_SeqAIJ(Mat C, Mat A, MatDuplicateOption cpvalues, PetscBool mallocmatspace)
4931 {
4932   Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data, *a = (Mat_SeqAIJ *)A->data;
4933   PetscInt    m = A->rmap->n, i;
4934 
4935   PetscFunctionBegin;
4936   PetscCheck(A->assembled || cpvalues == MAT_DO_NOT_COPY_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot duplicate unassembled matrix");
4937 
4938   C->factortype = A->factortype;
4939   c->row        = NULL;
4940   c->col        = NULL;
4941   c->icol       = NULL;
4942   c->reallocs   = 0;
4943   c->diagDense  = a->diagDense;
4944 
4945   C->assembled = A->assembled;
4946 
4947   if (A->preallocated) {
4948     PetscCall(PetscLayoutReference(A->rmap, &C->rmap));
4949     PetscCall(PetscLayoutReference(A->cmap, &C->cmap));
4950 
4951     if (!A->hash_active) {
4952       PetscCall(PetscMalloc1(m, &c->imax));
4953       PetscCall(PetscMemcpy(c->imax, a->imax, m * sizeof(PetscInt)));
4954       PetscCall(PetscMalloc1(m, &c->ilen));
4955       PetscCall(PetscMemcpy(c->ilen, a->ilen, m * sizeof(PetscInt)));
4956 
4957       /* allocate the matrix space */
4958       if (mallocmatspace) {
4959         PetscCall(PetscShmgetAllocateArray(a->i[m], sizeof(PetscScalar), (void **)&c->a));
4960         PetscCall(PetscShmgetAllocateArray(a->i[m], sizeof(PetscInt), (void **)&c->j));
4961         PetscCall(PetscShmgetAllocateArray(m + 1, sizeof(PetscInt), (void **)&c->i));
4962         PetscCall(PetscArraycpy(c->i, a->i, m + 1));
4963         c->free_a  = PETSC_TRUE;
4964         c->free_ij = PETSC_TRUE;
4965         if (m > 0) {
4966           PetscCall(PetscArraycpy(c->j, a->j, a->i[m]));
4967           if (cpvalues == MAT_COPY_VALUES) {
4968             const PetscScalar *aa;
4969 
4970             PetscCall(MatSeqAIJGetArrayRead(A, &aa));
4971             PetscCall(PetscArraycpy(c->a, aa, a->i[m]));
4972             PetscCall(MatSeqAIJGetArrayRead(A, &aa));
4973           } else {
4974             PetscCall(PetscArrayzero(c->a, a->i[m]));
4975           }
4976         }
4977       }
4978       C->preallocated = PETSC_TRUE;
4979     } else {
4980       PetscCheck(mallocmatspace, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Cannot malloc matrix memory from a non-preallocated matrix");
4981       PetscCall(MatSetUp(C));
4982     }
4983 
4984     c->ignorezeroentries = a->ignorezeroentries;
4985     c->roworiented       = a->roworiented;
4986     c->nonew             = a->nonew;
4987     if (a->diag) {
4988       PetscCall(PetscMalloc1(m + 1, &c->diag));
4989       PetscCall(PetscMemcpy(c->diag, a->diag, m * sizeof(PetscInt)));
4990     } else c->diag = NULL;
4991 
4992     c->solve_work         = NULL;
4993     c->saved_values       = NULL;
4994     c->idiag              = NULL;
4995     c->ssor_work          = NULL;
4996     c->keepnonzeropattern = a->keepnonzeropattern;
4997 
4998     c->rmax  = a->rmax;
4999     c->nz    = a->nz;
5000     c->maxnz = a->nz; /* Since we allocate exactly the right amount */
5001 
5002     c->compressedrow.use   = a->compressedrow.use;
5003     c->compressedrow.nrows = a->compressedrow.nrows;
5004     if (a->compressedrow.use) {
5005       i = a->compressedrow.nrows;
5006       PetscCall(PetscMalloc2(i + 1, &c->compressedrow.i, i, &c->compressedrow.rindex));
5007       PetscCall(PetscArraycpy(c->compressedrow.i, a->compressedrow.i, i + 1));
5008       PetscCall(PetscArraycpy(c->compressedrow.rindex, a->compressedrow.rindex, i));
5009     } else {
5010       c->compressedrow.use    = PETSC_FALSE;
5011       c->compressedrow.i      = NULL;
5012       c->compressedrow.rindex = NULL;
5013     }
5014     c->nonzerorowcnt = a->nonzerorowcnt;
5015     C->nonzerostate  = A->nonzerostate;
5016 
5017     PetscCall(MatDuplicate_SeqAIJ_Inode(A, cpvalues, &C));
5018   }
5019   PetscCall(PetscFunctionListDuplicate(((PetscObject)A)->qlist, &((PetscObject)C)->qlist));
5020   PetscFunctionReturn(PETSC_SUCCESS);
5021 }
5022 
5023 PetscErrorCode MatDuplicate_SeqAIJ(Mat A, MatDuplicateOption cpvalues, Mat *B)
5024 {
5025   PetscFunctionBegin;
5026   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
5027   PetscCall(MatSetSizes(*B, A->rmap->n, A->cmap->n, A->rmap->n, A->cmap->n));
5028   if (!(A->rmap->n % A->rmap->bs) && !(A->cmap->n % A->cmap->bs)) PetscCall(MatSetBlockSizesFromMats(*B, A, A));
5029   PetscCall(MatSetType(*B, ((PetscObject)A)->type_name));
5030   PetscCall(MatDuplicateNoCreate_SeqAIJ(*B, A, cpvalues, PETSC_TRUE));
5031   PetscFunctionReturn(PETSC_SUCCESS);
5032 }
5033 
5034 PetscErrorCode MatLoad_SeqAIJ(Mat newMat, PetscViewer viewer)
5035 {
5036   PetscBool isbinary, ishdf5;
5037 
5038   PetscFunctionBegin;
5039   PetscValidHeaderSpecific(newMat, MAT_CLASSID, 1);
5040   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
5041   /* force binary viewer to load .info file if it has not yet done so */
5042   PetscCall(PetscViewerSetUp(viewer));
5043   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
5044   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
5045   if (isbinary) {
5046     PetscCall(MatLoad_SeqAIJ_Binary(newMat, viewer));
5047   } else if (ishdf5) {
5048 #if defined(PETSC_HAVE_HDF5)
5049     PetscCall(MatLoad_AIJ_HDF5(newMat, viewer));
5050 #else
5051     SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
5052 #endif
5053   } else {
5054     SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "Viewer type %s not yet supported for reading %s matrices", ((PetscObject)viewer)->type_name, ((PetscObject)newMat)->type_name);
5055   }
5056   PetscFunctionReturn(PETSC_SUCCESS);
5057 }
5058 
5059 PetscErrorCode MatLoad_SeqAIJ_Binary(Mat mat, PetscViewer viewer)
5060 {
5061   Mat_SeqAIJ *a = (Mat_SeqAIJ *)mat->data;
5062   PetscInt    header[4], *rowlens, M, N, nz, sum, rows, cols, i;
5063 
5064   PetscFunctionBegin;
5065   PetscCall(PetscViewerSetUp(viewer));
5066 
5067   /* read in matrix header */
5068   PetscCall(PetscViewerBinaryRead(viewer, header, 4, NULL, PETSC_INT));
5069   PetscCheck(header[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix object in file");
5070   M  = header[1];
5071   N  = header[2];
5072   nz = header[3];
5073   PetscCheck(M >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix row size (%" PetscInt_FMT ") in file is negative", M);
5074   PetscCheck(N >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix column size (%" PetscInt_FMT ") in file is negative", N);
5075   PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix stored in special format on disk, cannot load as SeqAIJ");
5076 
5077   /* set block sizes from the viewer's .info file */
5078   PetscCall(MatLoad_Binary_BlockSizes(mat, viewer));
5079   /* set local and global sizes if not set already */
5080   if (mat->rmap->n < 0) mat->rmap->n = M;
5081   if (mat->cmap->n < 0) mat->cmap->n = N;
5082   if (mat->rmap->N < 0) mat->rmap->N = M;
5083   if (mat->cmap->N < 0) mat->cmap->N = N;
5084   PetscCall(PetscLayoutSetUp(mat->rmap));
5085   PetscCall(PetscLayoutSetUp(mat->cmap));
5086 
5087   /* check if the matrix sizes are correct */
5088   PetscCall(MatGetSize(mat, &rows, &cols));
5089   PetscCheck(M == rows && N == cols, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix in file of different sizes (%" PetscInt_FMT ", %" PetscInt_FMT ") than the input matrix (%" PetscInt_FMT ", %" PetscInt_FMT ")", M, N, rows, cols);
5090 
5091   /* read in row lengths */
5092   PetscCall(PetscMalloc1(M, &rowlens));
5093   PetscCall(PetscViewerBinaryRead(viewer, rowlens, M, NULL, PETSC_INT));
5094   /* check if sum(rowlens) is same as nz */
5095   sum = 0;
5096   for (i = 0; i < M; i++) sum += rowlens[i];
5097   PetscCheck(sum == nz, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Inconsistent matrix data in file: nonzeros = %" PetscInt_FMT ", sum-row-lengths = %" PetscInt_FMT, nz, sum);
5098   /* preallocate and check sizes */
5099   PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(mat, 0, rowlens));
5100   PetscCall(MatGetSize(mat, &rows, &cols));
5101   PetscCheck(M == rows && N == cols, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix in file of different length (%" PetscInt_FMT ", %" PetscInt_FMT ") than the input matrix (%" PetscInt_FMT ", %" PetscInt_FMT ")", M, N, rows, cols);
5102   /* store row lengths */
5103   PetscCall(PetscArraycpy(a->ilen, rowlens, M));
5104   PetscCall(PetscFree(rowlens));
5105 
5106   /* fill in "i" row pointers */
5107   a->i[0] = 0;
5108   for (i = 0; i < M; i++) a->i[i + 1] = a->i[i] + a->ilen[i];
5109   /* read in "j" column indices */
5110   PetscCall(PetscViewerBinaryRead(viewer, a->j, nz, NULL, PETSC_INT));
5111   /* read in "a" nonzero values */
5112   PetscCall(PetscViewerBinaryRead(viewer, a->a, nz, NULL, PETSC_SCALAR));
5113 
5114   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
5115   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
5116   PetscFunctionReturn(PETSC_SUCCESS);
5117 }
5118 
5119 PetscErrorCode MatEqual_SeqAIJ(Mat A, Mat B, PetscBool *flg)
5120 {
5121   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data;
5122   const PetscScalar *aa, *ba;
5123 #if defined(PETSC_USE_COMPLEX)
5124   PetscInt k;
5125 #endif
5126 
5127   PetscFunctionBegin;
5128   /* If the  matrix dimensions are not equal,or no of nonzeros */
5129   if ((A->rmap->n != B->rmap->n) || (A->cmap->n != B->cmap->n) || (a->nz != b->nz)) {
5130     *flg = PETSC_FALSE;
5131     PetscFunctionReturn(PETSC_SUCCESS);
5132   }
5133 
5134   /* if the a->i are the same */
5135   PetscCall(PetscArraycmp(a->i, b->i, A->rmap->n + 1, flg));
5136   if (!*flg) PetscFunctionReturn(PETSC_SUCCESS);
5137 
5138   /* if a->j are the same */
5139   PetscCall(PetscArraycmp(a->j, b->j, a->nz, flg));
5140   if (!*flg) PetscFunctionReturn(PETSC_SUCCESS);
5141 
5142   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
5143   PetscCall(MatSeqAIJGetArrayRead(B, &ba));
5144   /* if a->a are the same */
5145 #if defined(PETSC_USE_COMPLEX)
5146   for (k = 0; k < a->nz; k++) {
5147     if (PetscRealPart(aa[k]) != PetscRealPart(ba[k]) || PetscImaginaryPart(aa[k]) != PetscImaginaryPart(ba[k])) {
5148       *flg = PETSC_FALSE;
5149       PetscFunctionReturn(PETSC_SUCCESS);
5150     }
5151   }
5152 #else
5153   PetscCall(PetscArraycmp(aa, ba, a->nz, flg));
5154 #endif
5155   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
5156   PetscCall(MatSeqAIJRestoreArrayRead(B, &ba));
5157   PetscFunctionReturn(PETSC_SUCCESS);
5158 }
5159 
5160 /*@
5161   MatCreateSeqAIJWithArrays - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in CSR format)
5162   provided by the user.
5163 
5164   Collective
5165 
5166   Input Parameters:
5167 + comm - must be an MPI communicator of size 1
5168 . m    - number of rows
5169 . n    - number of columns
5170 . i    - row indices; that is i[0] = 0, i[row] = i[row-1] + number of elements in that row of the matrix
5171 . j    - column indices
5172 - a    - matrix values
5173 
5174   Output Parameter:
5175 . mat - the matrix
5176 
5177   Level: intermediate
5178 
5179   Notes:
5180   The `i`, `j`, and `a` arrays are not copied by this routine, the user must free these arrays
5181   once the matrix is destroyed and not before
5182 
5183   You cannot set new nonzero locations into this matrix, that will generate an error.
5184 
5185   The `i` and `j` indices are 0 based
5186 
5187   The format which is used for the sparse matrix input, is equivalent to a
5188   row-major ordering.. i.e for the following matrix, the input data expected is
5189   as shown
5190 .vb
5191         1 0 0
5192         2 0 3
5193         4 5 6
5194 
5195         i =  {0,1,3,6}  [size = nrow+1  = 3+1]
5196         j =  {0,0,2,0,1,2}  [size = 6]; values must be sorted for each row
5197         v =  {1,2,3,4,5,6}  [size = 6]
5198 .ve
5199 
5200 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateMPIAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()`
5201 @*/
5202 PetscErrorCode MatCreateSeqAIJWithArrays(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat)
5203 {
5204   PetscInt    ii;
5205   Mat_SeqAIJ *aij;
5206   PetscInt    jj;
5207 
5208   PetscFunctionBegin;
5209   PetscCheck(m <= 0 || i[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "i (row indices) must start with 0");
5210   PetscCall(MatCreate(comm, mat));
5211   PetscCall(MatSetSizes(*mat, m, n, m, n));
5212   /* PetscCall(MatSetBlockSizes(*mat,,)); */
5213   PetscCall(MatSetType(*mat, MATSEQAIJ));
5214   PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, MAT_SKIP_ALLOCATION, NULL));
5215   aij = (Mat_SeqAIJ *)(*mat)->data;
5216   PetscCall(PetscMalloc1(m, &aij->imax));
5217   PetscCall(PetscMalloc1(m, &aij->ilen));
5218 
5219   aij->i       = i;
5220   aij->j       = j;
5221   aij->a       = a;
5222   aij->nonew   = -1; /*this indicates that inserting a new value in the matrix that generates a new nonzero is an error*/
5223   aij->free_a  = PETSC_FALSE;
5224   aij->free_ij = PETSC_FALSE;
5225 
5226   for (ii = 0, aij->nonzerorowcnt = 0, aij->rmax = 0; ii < m; ii++) {
5227     aij->ilen[ii] = aij->imax[ii] = i[ii + 1] - i[ii];
5228     if (PetscDefined(USE_DEBUG)) {
5229       PetscCheck(i[ii + 1] - i[ii] >= 0, 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]);
5230       for (jj = i[ii] + 1; jj < i[ii + 1]; jj++) {
5231         PetscCheck(j[jj] >= j[jj - 1], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column entry number %" PetscInt_FMT " (actual column %" PetscInt_FMT ") in row %" PetscInt_FMT " is not sorted", jj - i[ii], j[jj], ii);
5232         PetscCheck(j[jj] != j[jj - 1], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column entry number %" PetscInt_FMT " (actual column %" PetscInt_FMT ") in row %" PetscInt_FMT " is identical to previous entry", jj - i[ii], j[jj], ii);
5233       }
5234     }
5235   }
5236   if (PetscDefined(USE_DEBUG)) {
5237     for (ii = 0; ii < aij->i[m]; ii++) {
5238       PetscCheck(j[ii] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative column index at location = %" PetscInt_FMT " index = %" PetscInt_FMT, ii, j[ii]);
5239       PetscCheck(j[ii] <= n - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column index to large at location = %" PetscInt_FMT " index = %" PetscInt_FMT " last column = %" PetscInt_FMT, ii, j[ii], n - 1);
5240     }
5241   }
5242 
5243   PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY));
5244   PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY));
5245   PetscFunctionReturn(PETSC_SUCCESS);
5246 }
5247 
5248 /*@
5249   MatCreateSeqAIJFromTriple - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in COO format)
5250   provided by the user.
5251 
5252   Collective
5253 
5254   Input Parameters:
5255 + comm - must be an MPI communicator of size 1
5256 . m    - number of rows
5257 . n    - number of columns
5258 . i    - row indices
5259 . j    - column indices
5260 . a    - matrix values
5261 . nz   - number of nonzeros
5262 - idx  - if the `i` and `j` indices start with 1 use `PETSC_TRUE` otherwise use `PETSC_FALSE`
5263 
5264   Output Parameter:
5265 . mat - the matrix
5266 
5267   Level: intermediate
5268 
5269   Example:
5270   For the following matrix, the input data expected is as shown (using 0 based indexing)
5271 .vb
5272         1 0 0
5273         2 0 3
5274         4 5 6
5275 
5276         i =  {0,1,1,2,2,2}
5277         j =  {0,0,2,0,1,2}
5278         v =  {1,2,3,4,5,6}
5279 .ve
5280 
5281   Note:
5282   Instead of using this function, users should also consider `MatSetPreallocationCOO()` and `MatSetValuesCOO()`, which allow repeated or remote entries,
5283   and are particularly useful in iterative applications.
5284 
5285 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateSeqAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()`, `MatSetValuesCOO()`, `MatSetPreallocationCOO()`
5286 @*/
5287 PetscErrorCode MatCreateSeqAIJFromTriple(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat, PetscCount nz, PetscBool idx)
5288 {
5289   PetscInt ii, *nnz, one = 1, row, col;
5290 
5291   PetscFunctionBegin;
5292   PetscCall(PetscCalloc1(m, &nnz));
5293   for (ii = 0; ii < nz; ii++) nnz[i[ii] - !!idx] += 1;
5294   PetscCall(MatCreate(comm, mat));
5295   PetscCall(MatSetSizes(*mat, m, n, m, n));
5296   PetscCall(MatSetType(*mat, MATSEQAIJ));
5297   PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, 0, nnz));
5298   for (ii = 0; ii < nz; ii++) {
5299     if (idx) {
5300       row = i[ii] - 1;
5301       col = j[ii] - 1;
5302     } else {
5303       row = i[ii];
5304       col = j[ii];
5305     }
5306     PetscCall(MatSetValues(*mat, one, &row, one, &col, &a[ii], ADD_VALUES));
5307   }
5308   PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY));
5309   PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY));
5310   PetscCall(PetscFree(nnz));
5311   PetscFunctionReturn(PETSC_SUCCESS);
5312 }
5313 
5314 PetscErrorCode MatCreateMPIMatConcatenateSeqMat_SeqAIJ(MPI_Comm comm, Mat inmat, PetscInt n, MatReuse scall, Mat *outmat)
5315 {
5316   PetscFunctionBegin;
5317   PetscCall(MatCreateMPIMatConcatenateSeqMat_MPIAIJ(comm, inmat, n, scall, outmat));
5318   PetscFunctionReturn(PETSC_SUCCESS);
5319 }
5320 
5321 /*
5322  Permute A into C's *local* index space using rowemb,colemb.
5323  The embedding are supposed to be injections and the above implies that the range of rowemb is a subset
5324  of [0,m), colemb is in [0,n).
5325  If pattern == DIFFERENT_NONZERO_PATTERN, C is preallocated according to A.
5326  */
5327 PetscErrorCode MatSetSeqMat_SeqAIJ(Mat C, IS rowemb, IS colemb, MatStructure pattern, Mat B)
5328 {
5329   /* If making this function public, change the error returned in this function away from _PLIB. */
5330   Mat_SeqAIJ     *Baij;
5331   PetscBool       seqaij;
5332   PetscInt        m, n, *nz, i, j, count;
5333   PetscScalar     v;
5334   const PetscInt *rowindices, *colindices;
5335 
5336   PetscFunctionBegin;
5337   if (!B) PetscFunctionReturn(PETSC_SUCCESS);
5338   /* Check to make sure the target matrix (and embeddings) are compatible with C and each other. */
5339   PetscCall(PetscObjectBaseTypeCompare((PetscObject)B, MATSEQAIJ, &seqaij));
5340   PetscCheck(seqaij, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is of wrong type");
5341   if (rowemb) {
5342     PetscCall(ISGetLocalSize(rowemb, &m));
5343     PetscCheck(m == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Row IS of size %" PetscInt_FMT " is incompatible with matrix row size %" PetscInt_FMT, m, B->rmap->n);
5344   } else {
5345     PetscCheck(C->rmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is row-incompatible with the target matrix");
5346   }
5347   if (colemb) {
5348     PetscCall(ISGetLocalSize(colemb, &n));
5349     PetscCheck(n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Diag col IS of size %" PetscInt_FMT " is incompatible with input matrix col size %" PetscInt_FMT, n, B->cmap->n);
5350   } else {
5351     PetscCheck(C->cmap->n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is col-incompatible with the target matrix");
5352   }
5353 
5354   Baij = (Mat_SeqAIJ *)B->data;
5355   if (pattern == DIFFERENT_NONZERO_PATTERN) {
5356     PetscCall(PetscMalloc1(B->rmap->n, &nz));
5357     for (i = 0; i < B->rmap->n; i++) nz[i] = Baij->i[i + 1] - Baij->i[i];
5358     PetscCall(MatSeqAIJSetPreallocation(C, 0, nz));
5359     PetscCall(PetscFree(nz));
5360   }
5361   if (pattern == SUBSET_NONZERO_PATTERN) PetscCall(MatZeroEntries(C));
5362   count      = 0;
5363   rowindices = NULL;
5364   colindices = NULL;
5365   if (rowemb) PetscCall(ISGetIndices(rowemb, &rowindices));
5366   if (colemb) PetscCall(ISGetIndices(colemb, &colindices));
5367   for (i = 0; i < B->rmap->n; i++) {
5368     PetscInt row;
5369     row = i;
5370     if (rowindices) row = rowindices[i];
5371     for (j = Baij->i[i]; j < Baij->i[i + 1]; j++) {
5372       PetscInt col;
5373       col = Baij->j[count];
5374       if (colindices) col = colindices[col];
5375       v = Baij->a[count];
5376       PetscCall(MatSetValues(C, 1, &row, 1, &col, &v, INSERT_VALUES));
5377       ++count;
5378     }
5379   }
5380   /* FIXME: set C's nonzerostate correctly. */
5381   /* Assembly for C is necessary. */
5382   C->preallocated  = PETSC_TRUE;
5383   C->assembled     = PETSC_TRUE;
5384   C->was_assembled = PETSC_FALSE;
5385   PetscFunctionReturn(PETSC_SUCCESS);
5386 }
5387 
5388 PetscErrorCode MatEliminateZeros_SeqAIJ(Mat A, PetscBool keep)
5389 {
5390   Mat_SeqAIJ *a  = (Mat_SeqAIJ *)A->data;
5391   MatScalar  *aa = a->a;
5392   PetscInt    m = A->rmap->n, fshift = 0, fshift_prev = 0, i, k;
5393   PetscInt   *ailen = a->ilen, *imax = a->imax, *ai = a->i, *aj = a->j, rmax = 0;
5394 
5395   PetscFunctionBegin;
5396   PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot eliminate zeros for unassembled matrix");
5397   if (m) rmax = ailen[0]; /* determine row with most nonzeros */
5398   for (i = 1; i <= m; i++) {
5399     /* move each nonzero entry back by the amount of zero slots (fshift) before it*/
5400     for (k = ai[i - 1]; k < ai[i]; k++) {
5401       if (aa[k] == 0 && (aj[k] != i - 1 || !keep)) fshift++;
5402       else {
5403         if (aa[k] == 0 && aj[k] == i - 1) PetscCall(PetscInfo(A, "Keep the diagonal zero at row %" PetscInt_FMT "\n", i - 1));
5404         aa[k - fshift] = aa[k];
5405         aj[k - fshift] = aj[k];
5406       }
5407     }
5408     ai[i - 1] -= fshift_prev; // safe to update ai[i-1] now since it will not be used in the next iteration
5409     fshift_prev = fshift;
5410     /* reset ilen and imax for each row */
5411     ailen[i - 1] = imax[i - 1] = ai[i] - fshift - ai[i - 1];
5412     a->nonzerorowcnt += ((ai[i] - fshift - ai[i - 1]) > 0);
5413     rmax = PetscMax(rmax, ailen[i - 1]);
5414   }
5415   if (fshift) {
5416     if (m) {
5417       ai[m] -= fshift;
5418       a->nz = ai[m];
5419     }
5420     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));
5421     A->nonzerostate++;
5422     A->info.nz_unneeded += (PetscReal)fshift;
5423     a->rmax = rmax;
5424     if (a->inode.use && a->inode.checked) PetscCall(MatSeqAIJCheckInode(A));
5425     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
5426     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
5427   }
5428   PetscFunctionReturn(PETSC_SUCCESS);
5429 }
5430 
5431 PetscFunctionList MatSeqAIJList = NULL;
5432 
5433 /*@
5434   MatSeqAIJSetType - Converts a `MATSEQAIJ` matrix to a subtype
5435 
5436   Collective
5437 
5438   Input Parameters:
5439 + mat    - the matrix object
5440 - matype - matrix type
5441 
5442   Options Database Key:
5443 . -mat_seqaij_type  <method> - for example seqaijcrl
5444 
5445   Level: intermediate
5446 
5447 .seealso: [](ch_matrices), `Mat`, `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType`
5448 @*/
5449 PetscErrorCode MatSeqAIJSetType(Mat mat, MatType matype)
5450 {
5451   PetscBool sametype;
5452   PetscErrorCode (*r)(Mat, MatType, MatReuse, Mat *);
5453 
5454   PetscFunctionBegin;
5455   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5456   PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype));
5457   if (sametype) PetscFunctionReturn(PETSC_SUCCESS);
5458 
5459   PetscCall(PetscFunctionListFind(MatSeqAIJList, matype, &r));
5460   PetscCheck(r, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype);
5461   PetscCall((*r)(mat, matype, MAT_INPLACE_MATRIX, &mat));
5462   PetscFunctionReturn(PETSC_SUCCESS);
5463 }
5464 
5465 /*@C
5466   MatSeqAIJRegister -  - Adds a new sub-matrix type for sequential `MATSEQAIJ` matrices
5467 
5468   Not Collective, No Fortran Support
5469 
5470   Input Parameters:
5471 + sname    - name of a new user-defined matrix type, for example `MATSEQAIJCRL`
5472 - function - routine to convert to subtype
5473 
5474   Level: advanced
5475 
5476   Notes:
5477   `MatSeqAIJRegister()` may be called multiple times to add several user-defined solvers.
5478 
5479   Then, your matrix can be chosen with the procedural interface at runtime via the option
5480 .vb
5481   -mat_seqaij_type my_mat
5482 .ve
5483 
5484 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRegisterAll()`
5485 @*/
5486 PetscErrorCode MatSeqAIJRegister(const char sname[], PetscErrorCode (*function)(Mat, MatType, MatReuse, Mat *))
5487 {
5488   PetscFunctionBegin;
5489   PetscCall(MatInitializePackage());
5490   PetscCall(PetscFunctionListAdd(&MatSeqAIJList, sname, function));
5491   PetscFunctionReturn(PETSC_SUCCESS);
5492 }
5493 
5494 PetscBool MatSeqAIJRegisterAllCalled = PETSC_FALSE;
5495 
5496 /*@C
5497   MatSeqAIJRegisterAll - Registers all of the matrix subtypes of `MATSSEQAIJ`
5498 
5499   Not Collective
5500 
5501   Level: advanced
5502 
5503   Note:
5504   This registers the versions of `MATSEQAIJ` for GPUs
5505 
5506 .seealso: [](ch_matrices), `Mat`, `MatRegisterAll()`, `MatSeqAIJRegister()`
5507 @*/
5508 PetscErrorCode MatSeqAIJRegisterAll(void)
5509 {
5510   PetscFunctionBegin;
5511   if (MatSeqAIJRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
5512   MatSeqAIJRegisterAllCalled = PETSC_TRUE;
5513 
5514   PetscCall(MatSeqAIJRegister(MATSEQAIJCRL, MatConvert_SeqAIJ_SeqAIJCRL));
5515   PetscCall(MatSeqAIJRegister(MATSEQAIJPERM, MatConvert_SeqAIJ_SeqAIJPERM));
5516   PetscCall(MatSeqAIJRegister(MATSEQAIJSELL, MatConvert_SeqAIJ_SeqAIJSELL));
5517 #if defined(PETSC_HAVE_MKL_SPARSE)
5518   PetscCall(MatSeqAIJRegister(MATSEQAIJMKL, MatConvert_SeqAIJ_SeqAIJMKL));
5519 #endif
5520 #if defined(PETSC_HAVE_CUDA)
5521   PetscCall(MatSeqAIJRegister(MATSEQAIJCUSPARSE, MatConvert_SeqAIJ_SeqAIJCUSPARSE));
5522 #endif
5523 #if defined(PETSC_HAVE_HIP)
5524   PetscCall(MatSeqAIJRegister(MATSEQAIJHIPSPARSE, MatConvert_SeqAIJ_SeqAIJHIPSPARSE));
5525 #endif
5526 #if defined(PETSC_HAVE_KOKKOS_KERNELS)
5527   PetscCall(MatSeqAIJRegister(MATSEQAIJKOKKOS, MatConvert_SeqAIJ_SeqAIJKokkos));
5528 #endif
5529 #if defined(PETSC_HAVE_VIENNACL) && defined(PETSC_HAVE_VIENNACL_NO_CUDA)
5530   PetscCall(MatSeqAIJRegister(MATMPIAIJVIENNACL, MatConvert_SeqAIJ_SeqAIJViennaCL));
5531 #endif
5532   PetscFunctionReturn(PETSC_SUCCESS);
5533 }
5534 
5535 /*
5536     Special version for direct calls from Fortran
5537 */
5538 #if defined(PETSC_HAVE_FORTRAN_CAPS)
5539   #define matsetvaluesseqaij_ MATSETVALUESSEQAIJ
5540 #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE)
5541   #define matsetvaluesseqaij_ matsetvaluesseqaij
5542 #endif
5543 
5544 /* Change these macros so can be used in void function */
5545 
5546 /* Change these macros so can be used in void function */
5547 /* Identical to PetscCallVoid, except it assigns to *_ierr */
5548 #undef PetscCall
5549 #define PetscCall(...) \
5550   do { \
5551     PetscErrorCode ierr_msv_mpiaij = __VA_ARGS__; \
5552     if (PetscUnlikely(ierr_msv_mpiaij)) { \
5553       *_ierr = PetscError(PETSC_COMM_SELF, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr_msv_mpiaij, PETSC_ERROR_REPEAT, " "); \
5554       return; \
5555     } \
5556   } while (0)
5557 
5558 #undef SETERRQ
5559 #define SETERRQ(comm, ierr, ...) \
5560   do { \
5561     *_ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr, PETSC_ERROR_INITIAL, __VA_ARGS__); \
5562     return; \
5563   } while (0)
5564 
5565 PETSC_EXTERN void matsetvaluesseqaij_(Mat *AA, PetscInt *mm, const PetscInt im[], PetscInt *nn, const PetscInt in[], const PetscScalar v[], InsertMode *isis, PetscErrorCode *_ierr)
5566 {
5567   Mat         A = *AA;
5568   PetscInt    m = *mm, n = *nn;
5569   InsertMode  is = *isis;
5570   Mat_SeqAIJ *a  = (Mat_SeqAIJ *)A->data;
5571   PetscInt   *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N;
5572   PetscInt   *imax, *ai, *ailen;
5573   PetscInt   *aj, nonew = a->nonew, lastcol = -1;
5574   MatScalar  *ap, value, *aa;
5575   PetscBool   ignorezeroentries = a->ignorezeroentries;
5576   PetscBool   roworiented       = a->roworiented;
5577 
5578   PetscFunctionBegin;
5579   MatCheckPreallocated(A, 1);
5580   imax  = a->imax;
5581   ai    = a->i;
5582   ailen = a->ilen;
5583   aj    = a->j;
5584   aa    = a->a;
5585 
5586   for (k = 0; k < m; k++) { /* loop over added rows */
5587     row = im[k];
5588     if (row < 0) continue;
5589     PetscCheck(row < A->rmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large");
5590     rp   = aj + ai[row];
5591     ap   = aa + ai[row];
5592     rmax = imax[row];
5593     nrow = ailen[row];
5594     low  = 0;
5595     high = nrow;
5596     for (l = 0; l < n; l++) { /* loop over added columns */
5597       if (in[l] < 0) continue;
5598       PetscCheck(in[l] < A->cmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Column too large");
5599       col = in[l];
5600       if (roworiented) value = v[l + k * n];
5601       else value = v[k + l * m];
5602 
5603       if (value == 0.0 && ignorezeroentries && (is == ADD_VALUES)) continue;
5604 
5605       if (col <= lastcol) low = 0;
5606       else high = nrow;
5607       lastcol = col;
5608       while (high - low > 5) {
5609         t = (low + high) / 2;
5610         if (rp[t] > col) high = t;
5611         else low = t;
5612       }
5613       for (i = low; i < high; i++) {
5614         if (rp[i] > col) break;
5615         if (rp[i] == col) {
5616           if (is == ADD_VALUES) ap[i] += value;
5617           else ap[i] = value;
5618           goto noinsert;
5619         }
5620       }
5621       if (value == 0.0 && ignorezeroentries) goto noinsert;
5622       if (nonew == 1) goto noinsert;
5623       PetscCheck(nonew != -1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero in the matrix");
5624       MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar);
5625       N = nrow++ - 1;
5626       a->nz++;
5627       high++;
5628       /* shift up all the later entries in this row */
5629       for (ii = N; ii >= i; ii--) {
5630         rp[ii + 1] = rp[ii];
5631         ap[ii + 1] = ap[ii];
5632       }
5633       rp[i] = col;
5634       ap[i] = value;
5635     noinsert:;
5636       low = i + 1;
5637     }
5638     ailen[row] = nrow;
5639   }
5640   PetscFunctionReturnVoid();
5641 }
5642 /* Undefining these here since they were redefined from their original definition above! No
5643  * other PETSc functions should be defined past this point, as it is impossible to recover the
5644  * original definitions */
5645 #undef PetscCall
5646 #undef SETERRQ
5647