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