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