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