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