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