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