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