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