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