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