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