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