xref: /petsc/src/mat/impls/aij/seq/aij.c (revision cf906205f1df435953e2a75894dc7795d3ff0aed)
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(PetscFree(C->defaultrandtype));
2705         PetscCall(PetscLayoutDestroy(&C->rmap));
2706         PetscCall(PetscLayoutDestroy(&C->cmap));
2707         PetscCall(PetscHeaderDestroy(&C));
2708       }
2709     } else {
2710       PetscCall(MatDestroy(&C));
2711     }
2712   }
2713 
2714   /* Destroy Dummy submatrices created for reuse */
2715   PetscCall(MatDestroySubMatrices_Dummy(n, mat));
2716 
2717   PetscCall(PetscFree(*mat));
2718   PetscFunctionReturn(0);
2719 }
2720 
2721 PetscErrorCode MatCreateSubMatrices_SeqAIJ(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *B[]) {
2722   PetscInt i;
2723 
2724   PetscFunctionBegin;
2725   if (scall == MAT_INITIAL_MATRIX) PetscCall(PetscCalloc1(n + 1, B));
2726 
2727   for (i = 0; i < n; i++) PetscCall(MatCreateSubMatrix_SeqAIJ(A, irow[i], icol[i], PETSC_DECIDE, scall, &(*B)[i]));
2728   PetscFunctionReturn(0);
2729 }
2730 
2731 PetscErrorCode MatIncreaseOverlap_SeqAIJ(Mat A, PetscInt is_max, IS is[], PetscInt ov) {
2732   Mat_SeqAIJ     *a = (Mat_SeqAIJ *)A->data;
2733   PetscInt        row, i, j, k, l, m, n, *nidx, isz, val;
2734   const PetscInt *idx;
2735   PetscInt        start, end, *ai, *aj;
2736   PetscBT         table;
2737 
2738   PetscFunctionBegin;
2739   m  = A->rmap->n;
2740   ai = a->i;
2741   aj = a->j;
2742 
2743   PetscCheck(ov >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "illegal negative overlap value used");
2744 
2745   PetscCall(PetscMalloc1(m + 1, &nidx));
2746   PetscCall(PetscBTCreate(m, &table));
2747 
2748   for (i = 0; i < is_max; i++) {
2749     /* Initialize the two local arrays */
2750     isz = 0;
2751     PetscCall(PetscBTMemzero(m, table));
2752 
2753     /* Extract the indices, assume there can be duplicate entries */
2754     PetscCall(ISGetIndices(is[i], &idx));
2755     PetscCall(ISGetLocalSize(is[i], &n));
2756 
2757     /* Enter these into the temp arrays. I.e., mark table[row], enter row into new index */
2758     for (j = 0; j < n; ++j) {
2759       if (!PetscBTLookupSet(table, idx[j])) nidx[isz++] = idx[j];
2760     }
2761     PetscCall(ISRestoreIndices(is[i], &idx));
2762     PetscCall(ISDestroy(&is[i]));
2763 
2764     k = 0;
2765     for (j = 0; j < ov; j++) { /* for each overlap */
2766       n = isz;
2767       for (; k < n; k++) { /* do only those rows in nidx[k], which are not done yet */
2768         row   = nidx[k];
2769         start = ai[row];
2770         end   = ai[row + 1];
2771         for (l = start; l < end; l++) {
2772           val = aj[l];
2773           if (!PetscBTLookupSet(table, val)) nidx[isz++] = val;
2774         }
2775       }
2776     }
2777     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, isz, nidx, PETSC_COPY_VALUES, (is + i)));
2778   }
2779   PetscCall(PetscBTDestroy(&table));
2780   PetscCall(PetscFree(nidx));
2781   PetscFunctionReturn(0);
2782 }
2783 
2784 /* -------------------------------------------------------------- */
2785 PetscErrorCode MatPermute_SeqAIJ(Mat A, IS rowp, IS colp, Mat *B) {
2786   Mat_SeqAIJ     *a = (Mat_SeqAIJ *)A->data;
2787   PetscInt        i, nz = 0, m = A->rmap->n, n = A->cmap->n;
2788   const PetscInt *row, *col;
2789   PetscInt       *cnew, j, *lens;
2790   IS              icolp, irowp;
2791   PetscInt       *cwork = NULL;
2792   PetscScalar    *vwork = NULL;
2793 
2794   PetscFunctionBegin;
2795   PetscCall(ISInvertPermutation(rowp, PETSC_DECIDE, &irowp));
2796   PetscCall(ISGetIndices(irowp, &row));
2797   PetscCall(ISInvertPermutation(colp, PETSC_DECIDE, &icolp));
2798   PetscCall(ISGetIndices(icolp, &col));
2799 
2800   /* determine lengths of permuted rows */
2801   PetscCall(PetscMalloc1(m + 1, &lens));
2802   for (i = 0; i < m; i++) lens[row[i]] = a->i[i + 1] - a->i[i];
2803   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
2804   PetscCall(MatSetSizes(*B, m, n, m, n));
2805   PetscCall(MatSetBlockSizesFromMats(*B, A, A));
2806   PetscCall(MatSetType(*B, ((PetscObject)A)->type_name));
2807   PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*B, 0, lens));
2808   PetscCall(PetscFree(lens));
2809 
2810   PetscCall(PetscMalloc1(n, &cnew));
2811   for (i = 0; i < m; i++) {
2812     PetscCall(MatGetRow_SeqAIJ(A, i, &nz, &cwork, &vwork));
2813     for (j = 0; j < nz; j++) cnew[j] = col[cwork[j]];
2814     PetscCall(MatSetValues_SeqAIJ(*B, 1, &row[i], nz, cnew, vwork, INSERT_VALUES));
2815     PetscCall(MatRestoreRow_SeqAIJ(A, i, &nz, &cwork, &vwork));
2816   }
2817   PetscCall(PetscFree(cnew));
2818 
2819   (*B)->assembled = PETSC_FALSE;
2820 
2821 #if defined(PETSC_HAVE_DEVICE)
2822   PetscCall(MatBindToCPU(*B, A->boundtocpu));
2823 #endif
2824   PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
2825   PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
2826   PetscCall(ISRestoreIndices(irowp, &row));
2827   PetscCall(ISRestoreIndices(icolp, &col));
2828   PetscCall(ISDestroy(&irowp));
2829   PetscCall(ISDestroy(&icolp));
2830   if (rowp == colp) PetscCall(MatPropagateSymmetryOptions(A, *B));
2831   PetscFunctionReturn(0);
2832 }
2833 
2834 PetscErrorCode MatCopy_SeqAIJ(Mat A, Mat B, MatStructure str) {
2835   PetscFunctionBegin;
2836   /* If the two matrices have the same copy implementation, use fast copy. */
2837   if (str == SAME_NONZERO_PATTERN && (A->ops->copy == B->ops->copy)) {
2838     Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
2839     Mat_SeqAIJ        *b = (Mat_SeqAIJ *)B->data;
2840     const PetscScalar *aa;
2841 
2842     PetscCall(MatSeqAIJGetArrayRead(A, &aa));
2843     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]);
2844     PetscCall(PetscArraycpy(b->a, aa, a->i[A->rmap->n]));
2845     PetscCall(PetscObjectStateIncrease((PetscObject)B));
2846     PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
2847   } else {
2848     PetscCall(MatCopy_Basic(A, B, str));
2849   }
2850   PetscFunctionReturn(0);
2851 }
2852 
2853 PetscErrorCode MatSetUp_SeqAIJ(Mat A) {
2854   PetscFunctionBegin;
2855   PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(A, PETSC_DEFAULT, NULL));
2856   PetscFunctionReturn(0);
2857 }
2858 
2859 PETSC_INTERN PetscErrorCode MatSeqAIJGetArray_SeqAIJ(Mat A, PetscScalar *array[]) {
2860   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
2861 
2862   PetscFunctionBegin;
2863   *array = a->a;
2864   PetscFunctionReturn(0);
2865 }
2866 
2867 PETSC_INTERN PetscErrorCode MatSeqAIJRestoreArray_SeqAIJ(Mat A, PetscScalar *array[]) {
2868   PetscFunctionBegin;
2869   *array = NULL;
2870   PetscFunctionReturn(0);
2871 }
2872 
2873 /*
2874    Computes the number of nonzeros per row needed for preallocation when X and Y
2875    have different nonzero structure.
2876 */
2877 PetscErrorCode MatAXPYGetPreallocation_SeqX_private(PetscInt m, const PetscInt *xi, const PetscInt *xj, const PetscInt *yi, const PetscInt *yj, PetscInt *nnz) {
2878   PetscInt i, j, k, nzx, nzy;
2879 
2880   PetscFunctionBegin;
2881   /* Set the number of nonzeros in the new matrix */
2882   for (i = 0; i < m; i++) {
2883     const PetscInt *xjj = xj + xi[i], *yjj = yj + yi[i];
2884     nzx    = xi[i + 1] - xi[i];
2885     nzy    = yi[i + 1] - yi[i];
2886     nnz[i] = 0;
2887     for (j = 0, k = 0; j < nzx; j++) {                  /* Point in X */
2888       for (; k < nzy && yjj[k] < xjj[j]; k++) nnz[i]++; /* Catch up to X */
2889       if (k < nzy && yjj[k] == xjj[j]) k++;             /* Skip duplicate */
2890       nnz[i]++;
2891     }
2892     for (; k < nzy; k++) nnz[i]++;
2893   }
2894   PetscFunctionReturn(0);
2895 }
2896 
2897 PetscErrorCode MatAXPYGetPreallocation_SeqAIJ(Mat Y, Mat X, PetscInt *nnz) {
2898   PetscInt    m = Y->rmap->N;
2899   Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data;
2900   Mat_SeqAIJ *y = (Mat_SeqAIJ *)Y->data;
2901 
2902   PetscFunctionBegin;
2903   /* Set the number of nonzeros in the new matrix */
2904   PetscCall(MatAXPYGetPreallocation_SeqX_private(m, x->i, x->j, y->i, y->j, nnz));
2905   PetscFunctionReturn(0);
2906 }
2907 
2908 PetscErrorCode MatAXPY_SeqAIJ(Mat Y, PetscScalar a, Mat X, MatStructure str) {
2909   Mat_SeqAIJ *x = (Mat_SeqAIJ *)X->data, *y = (Mat_SeqAIJ *)Y->data;
2910 
2911   PetscFunctionBegin;
2912   if (str == UNKNOWN_NONZERO_PATTERN || (PetscDefined(USE_DEBUG) && str == SAME_NONZERO_PATTERN)) {
2913     PetscBool e = x->nz == y->nz ? PETSC_TRUE : PETSC_FALSE;
2914     if (e) {
2915       PetscCall(PetscArraycmp(x->i, y->i, Y->rmap->n + 1, &e));
2916       if (e) {
2917         PetscCall(PetscArraycmp(x->j, y->j, y->nz, &e));
2918         if (e) str = SAME_NONZERO_PATTERN;
2919       }
2920     }
2921     if (!e) PetscCheck(str != SAME_NONZERO_PATTERN, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatStructure is not SAME_NONZERO_PATTERN");
2922   }
2923   if (str == SAME_NONZERO_PATTERN) {
2924     const PetscScalar *xa;
2925     PetscScalar       *ya, alpha = a;
2926     PetscBLASInt       one = 1, bnz;
2927 
2928     PetscCall(PetscBLASIntCast(x->nz, &bnz));
2929     PetscCall(MatSeqAIJGetArray(Y, &ya));
2930     PetscCall(MatSeqAIJGetArrayRead(X, &xa));
2931     PetscCallBLAS("BLASaxpy", BLASaxpy_(&bnz, &alpha, xa, &one, ya, &one));
2932     PetscCall(MatSeqAIJRestoreArrayRead(X, &xa));
2933     PetscCall(MatSeqAIJRestoreArray(Y, &ya));
2934     PetscCall(PetscLogFlops(2.0 * bnz));
2935     PetscCall(MatSeqAIJInvalidateDiagonal(Y));
2936     PetscCall(PetscObjectStateIncrease((PetscObject)Y));
2937   } else if (str == SUBSET_NONZERO_PATTERN) { /* nonzeros of X is a subset of Y's */
2938     PetscCall(MatAXPY_Basic(Y, a, X, str));
2939   } else {
2940     Mat       B;
2941     PetscInt *nnz;
2942     PetscCall(PetscMalloc1(Y->rmap->N, &nnz));
2943     PetscCall(MatCreate(PetscObjectComm((PetscObject)Y), &B));
2944     PetscCall(PetscObjectSetName((PetscObject)B, ((PetscObject)Y)->name));
2945     PetscCall(MatSetLayouts(B, Y->rmap, Y->cmap));
2946     PetscCall(MatSetType(B, ((PetscObject)Y)->type_name));
2947     PetscCall(MatAXPYGetPreallocation_SeqAIJ(Y, X, nnz));
2948     PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz));
2949     PetscCall(MatAXPY_BasicWithPreallocation(B, Y, a, X, str));
2950     PetscCall(MatHeaderMerge(Y, &B));
2951     PetscCall(MatSeqAIJCheckInode(Y));
2952     PetscCall(PetscFree(nnz));
2953   }
2954   PetscFunctionReturn(0);
2955 }
2956 
2957 PETSC_INTERN PetscErrorCode MatConjugate_SeqAIJ(Mat mat) {
2958 #if defined(PETSC_USE_COMPLEX)
2959   Mat_SeqAIJ  *aij = (Mat_SeqAIJ *)mat->data;
2960   PetscInt     i, nz;
2961   PetscScalar *a;
2962 
2963   PetscFunctionBegin;
2964   nz = aij->nz;
2965   PetscCall(MatSeqAIJGetArray(mat, &a));
2966   for (i = 0; i < nz; i++) a[i] = PetscConj(a[i]);
2967   PetscCall(MatSeqAIJRestoreArray(mat, &a));
2968 #else
2969   PetscFunctionBegin;
2970 #endif
2971   PetscFunctionReturn(0);
2972 }
2973 
2974 PetscErrorCode MatGetRowMaxAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[]) {
2975   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
2976   PetscInt         i, j, m = A->rmap->n, *ai, *aj, ncols, n;
2977   PetscReal        atmp;
2978   PetscScalar     *x;
2979   const MatScalar *aa, *av;
2980 
2981   PetscFunctionBegin;
2982   PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2983   PetscCall(MatSeqAIJGetArrayRead(A, &av));
2984   aa = av;
2985   ai = a->i;
2986   aj = a->j;
2987 
2988   PetscCall(VecSet(v, 0.0));
2989   PetscCall(VecGetArrayWrite(v, &x));
2990   PetscCall(VecGetLocalSize(v, &n));
2991   PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector");
2992   for (i = 0; i < m; i++) {
2993     ncols = ai[1] - ai[0];
2994     ai++;
2995     for (j = 0; j < ncols; j++) {
2996       atmp = PetscAbsScalar(*aa);
2997       if (PetscAbsScalar(x[i]) < atmp) {
2998         x[i] = atmp;
2999         if (idx) idx[i] = *aj;
3000       }
3001       aa++;
3002       aj++;
3003     }
3004   }
3005   PetscCall(VecRestoreArrayWrite(v, &x));
3006   PetscCall(MatSeqAIJRestoreArrayRead(A, &av));
3007   PetscFunctionReturn(0);
3008 }
3009 
3010 PetscErrorCode MatGetRowMax_SeqAIJ(Mat A, Vec v, PetscInt idx[]) {
3011   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
3012   PetscInt         i, j, m = A->rmap->n, *ai, *aj, ncols, n;
3013   PetscScalar     *x;
3014   const MatScalar *aa, *av;
3015 
3016   PetscFunctionBegin;
3017   PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3018   PetscCall(MatSeqAIJGetArrayRead(A, &av));
3019   aa = av;
3020   ai = a->i;
3021   aj = a->j;
3022 
3023   PetscCall(VecSet(v, 0.0));
3024   PetscCall(VecGetArrayWrite(v, &x));
3025   PetscCall(VecGetLocalSize(v, &n));
3026   PetscCheck(n == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector");
3027   for (i = 0; i < m; i++) {
3028     ncols = ai[1] - ai[0];
3029     ai++;
3030     if (ncols == A->cmap->n) { /* row is dense */
3031       x[i] = *aa;
3032       if (idx) idx[i] = 0;
3033     } else { /* row is sparse so already KNOW maximum is 0.0 or higher */
3034       x[i] = 0.0;
3035       if (idx) {
3036         for (j = 0; j < ncols; j++) { /* find first implicit 0.0 in the row */
3037           if (aj[j] > j) {
3038             idx[i] = j;
3039             break;
3040           }
3041         }
3042         /* in case first implicit 0.0 in the row occurs at ncols-th column */
3043         if (j == ncols && j < A->cmap->n) idx[i] = j;
3044       }
3045     }
3046     for (j = 0; j < ncols; j++) {
3047       if (PetscRealPart(x[i]) < PetscRealPart(*aa)) {
3048         x[i] = *aa;
3049         if (idx) idx[i] = *aj;
3050       }
3051       aa++;
3052       aj++;
3053     }
3054   }
3055   PetscCall(VecRestoreArrayWrite(v, &x));
3056   PetscCall(MatSeqAIJRestoreArrayRead(A, &av));
3057   PetscFunctionReturn(0);
3058 }
3059 
3060 PetscErrorCode MatGetRowMinAbs_SeqAIJ(Mat A, Vec v, PetscInt idx[]) {
3061   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
3062   PetscInt         i, j, m = A->rmap->n, *ai, *aj, ncols, n;
3063   PetscScalar     *x;
3064   const MatScalar *aa, *av;
3065 
3066   PetscFunctionBegin;
3067   PetscCall(MatSeqAIJGetArrayRead(A, &av));
3068   aa = av;
3069   ai = a->i;
3070   aj = a->j;
3071 
3072   PetscCall(VecSet(v, 0.0));
3073   PetscCall(VecGetArrayWrite(v, &x));
3074   PetscCall(VecGetLocalSize(v, &n));
3075   PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector, %" PetscInt_FMT " vs. %" PetscInt_FMT " rows", m, n);
3076   for (i = 0; i < m; i++) {
3077     ncols = ai[1] - ai[0];
3078     ai++;
3079     if (ncols == A->cmap->n) { /* row is dense */
3080       x[i] = *aa;
3081       if (idx) idx[i] = 0;
3082     } else { /* row is sparse so already KNOW minimum is 0.0 or higher */
3083       x[i] = 0.0;
3084       if (idx) { /* find first implicit 0.0 in the row */
3085         for (j = 0; j < ncols; j++) {
3086           if (aj[j] > j) {
3087             idx[i] = j;
3088             break;
3089           }
3090         }
3091         /* in case first implicit 0.0 in the row occurs at ncols-th column */
3092         if (j == ncols && j < A->cmap->n) idx[i] = j;
3093       }
3094     }
3095     for (j = 0; j < ncols; j++) {
3096       if (PetscAbsScalar(x[i]) > PetscAbsScalar(*aa)) {
3097         x[i] = *aa;
3098         if (idx) idx[i] = *aj;
3099       }
3100       aa++;
3101       aj++;
3102     }
3103   }
3104   PetscCall(VecRestoreArrayWrite(v, &x));
3105   PetscCall(MatSeqAIJRestoreArrayRead(A, &av));
3106   PetscFunctionReturn(0);
3107 }
3108 
3109 PetscErrorCode MatGetRowMin_SeqAIJ(Mat A, Vec v, PetscInt idx[]) {
3110   Mat_SeqAIJ      *a = (Mat_SeqAIJ *)A->data;
3111   PetscInt         i, j, m = A->rmap->n, ncols, n;
3112   const PetscInt  *ai, *aj;
3113   PetscScalar     *x;
3114   const MatScalar *aa, *av;
3115 
3116   PetscFunctionBegin;
3117   PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3118   PetscCall(MatSeqAIJGetArrayRead(A, &av));
3119   aa = av;
3120   ai = a->i;
3121   aj = a->j;
3122 
3123   PetscCall(VecSet(v, 0.0));
3124   PetscCall(VecGetArrayWrite(v, &x));
3125   PetscCall(VecGetLocalSize(v, &n));
3126   PetscCheck(n == m, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming matrix and vector");
3127   for (i = 0; i < m; i++) {
3128     ncols = ai[1] - ai[0];
3129     ai++;
3130     if (ncols == A->cmap->n) { /* row is dense */
3131       x[i] = *aa;
3132       if (idx) idx[i] = 0;
3133     } else { /* row is sparse so already KNOW minimum is 0.0 or lower */
3134       x[i] = 0.0;
3135       if (idx) { /* find first implicit 0.0 in the row */
3136         for (j = 0; j < ncols; j++) {
3137           if (aj[j] > j) {
3138             idx[i] = j;
3139             break;
3140           }
3141         }
3142         /* in case first implicit 0.0 in the row occurs at ncols-th column */
3143         if (j == ncols && j < A->cmap->n) idx[i] = j;
3144       }
3145     }
3146     for (j = 0; j < ncols; j++) {
3147       if (PetscRealPart(x[i]) > PetscRealPart(*aa)) {
3148         x[i] = *aa;
3149         if (idx) idx[i] = *aj;
3150       }
3151       aa++;
3152       aj++;
3153     }
3154   }
3155   PetscCall(VecRestoreArrayWrite(v, &x));
3156   PetscCall(MatSeqAIJRestoreArrayRead(A, &av));
3157   PetscFunctionReturn(0);
3158 }
3159 
3160 PetscErrorCode MatInvertBlockDiagonal_SeqAIJ(Mat A, const PetscScalar **values) {
3161   Mat_SeqAIJ     *a = (Mat_SeqAIJ *)A->data;
3162   PetscInt        i, bs = PetscAbs(A->rmap->bs), mbs = A->rmap->n / bs, ipvt[5], bs2 = bs * bs, *v_pivots, ij[7], *IJ, j;
3163   MatScalar      *diag, work[25], *v_work;
3164   const PetscReal shift = 0.0;
3165   PetscBool       allowzeropivot, zeropivotdetected = PETSC_FALSE;
3166 
3167   PetscFunctionBegin;
3168   allowzeropivot = PetscNot(A->erroriffailure);
3169   if (a->ibdiagvalid) {
3170     if (values) *values = a->ibdiag;
3171     PetscFunctionReturn(0);
3172   }
3173   PetscCall(MatMarkDiagonal_SeqAIJ(A));
3174   if (!a->ibdiag) {
3175     PetscCall(PetscMalloc1(bs2 * mbs, &a->ibdiag));
3176     PetscCall(PetscLogObjectMemory((PetscObject)A, bs2 * mbs * sizeof(PetscScalar)));
3177   }
3178   diag = a->ibdiag;
3179   if (values) *values = a->ibdiag;
3180   /* factor and invert each block */
3181   switch (bs) {
3182   case 1:
3183     for (i = 0; i < mbs; i++) {
3184       PetscCall(MatGetValues(A, 1, &i, 1, &i, diag + i));
3185       if (PetscAbsScalar(diag[i] + shift) < PETSC_MACHINE_EPSILON) {
3186         if (allowzeropivot) {
3187           A->factorerrortype             = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3188           A->factorerror_zeropivot_value = PetscAbsScalar(diag[i]);
3189           A->factorerror_zeropivot_row   = i;
3190           PetscCall(PetscInfo(A, "Zero pivot, row %" PetscInt_FMT " pivot %g tolerance %g\n", i, (double)PetscAbsScalar(diag[i]), (double)PETSC_MACHINE_EPSILON));
3191         } 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);
3192       }
3193       diag[i] = (PetscScalar)1.0 / (diag[i] + shift);
3194     }
3195     break;
3196   case 2:
3197     for (i = 0; i < mbs; i++) {
3198       ij[0] = 2 * i;
3199       ij[1] = 2 * i + 1;
3200       PetscCall(MatGetValues(A, 2, ij, 2, ij, diag));
3201       PetscCall(PetscKernel_A_gets_inverse_A_2(diag, shift, allowzeropivot, &zeropivotdetected));
3202       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3203       PetscCall(PetscKernel_A_gets_transpose_A_2(diag));
3204       diag += 4;
3205     }
3206     break;
3207   case 3:
3208     for (i = 0; i < mbs; i++) {
3209       ij[0] = 3 * i;
3210       ij[1] = 3 * i + 1;
3211       ij[2] = 3 * i + 2;
3212       PetscCall(MatGetValues(A, 3, ij, 3, ij, diag));
3213       PetscCall(PetscKernel_A_gets_inverse_A_3(diag, shift, allowzeropivot, &zeropivotdetected));
3214       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3215       PetscCall(PetscKernel_A_gets_transpose_A_3(diag));
3216       diag += 9;
3217     }
3218     break;
3219   case 4:
3220     for (i = 0; i < mbs; i++) {
3221       ij[0] = 4 * i;
3222       ij[1] = 4 * i + 1;
3223       ij[2] = 4 * i + 2;
3224       ij[3] = 4 * i + 3;
3225       PetscCall(MatGetValues(A, 4, ij, 4, ij, diag));
3226       PetscCall(PetscKernel_A_gets_inverse_A_4(diag, shift, allowzeropivot, &zeropivotdetected));
3227       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3228       PetscCall(PetscKernel_A_gets_transpose_A_4(diag));
3229       diag += 16;
3230     }
3231     break;
3232   case 5:
3233     for (i = 0; i < mbs; i++) {
3234       ij[0] = 5 * i;
3235       ij[1] = 5 * i + 1;
3236       ij[2] = 5 * i + 2;
3237       ij[3] = 5 * i + 3;
3238       ij[4] = 5 * i + 4;
3239       PetscCall(MatGetValues(A, 5, ij, 5, ij, diag));
3240       PetscCall(PetscKernel_A_gets_inverse_A_5(diag, ipvt, work, shift, allowzeropivot, &zeropivotdetected));
3241       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3242       PetscCall(PetscKernel_A_gets_transpose_A_5(diag));
3243       diag += 25;
3244     }
3245     break;
3246   case 6:
3247     for (i = 0; i < mbs; i++) {
3248       ij[0] = 6 * i;
3249       ij[1] = 6 * i + 1;
3250       ij[2] = 6 * i + 2;
3251       ij[3] = 6 * i + 3;
3252       ij[4] = 6 * i + 4;
3253       ij[5] = 6 * i + 5;
3254       PetscCall(MatGetValues(A, 6, ij, 6, ij, diag));
3255       PetscCall(PetscKernel_A_gets_inverse_A_6(diag, shift, allowzeropivot, &zeropivotdetected));
3256       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3257       PetscCall(PetscKernel_A_gets_transpose_A_6(diag));
3258       diag += 36;
3259     }
3260     break;
3261   case 7:
3262     for (i = 0; i < mbs; i++) {
3263       ij[0] = 7 * i;
3264       ij[1] = 7 * i + 1;
3265       ij[2] = 7 * i + 2;
3266       ij[3] = 7 * i + 3;
3267       ij[4] = 7 * i + 4;
3268       ij[5] = 7 * i + 5;
3269       ij[5] = 7 * i + 6;
3270       PetscCall(MatGetValues(A, 7, ij, 7, ij, diag));
3271       PetscCall(PetscKernel_A_gets_inverse_A_7(diag, shift, allowzeropivot, &zeropivotdetected));
3272       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3273       PetscCall(PetscKernel_A_gets_transpose_A_7(diag));
3274       diag += 49;
3275     }
3276     break;
3277   default:
3278     PetscCall(PetscMalloc3(bs, &v_work, bs, &v_pivots, bs, &IJ));
3279     for (i = 0; i < mbs; i++) {
3280       for (j = 0; j < bs; j++) IJ[j] = bs * i + j;
3281       PetscCall(MatGetValues(A, bs, IJ, bs, IJ, diag));
3282       PetscCall(PetscKernel_A_gets_inverse_A(bs, diag, v_pivots, v_work, allowzeropivot, &zeropivotdetected));
3283       if (zeropivotdetected) A->factorerrortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
3284       PetscCall(PetscKernel_A_gets_transpose_A_N(diag, bs));
3285       diag += bs2;
3286     }
3287     PetscCall(PetscFree3(v_work, v_pivots, IJ));
3288   }
3289   a->ibdiagvalid = PETSC_TRUE;
3290   PetscFunctionReturn(0);
3291 }
3292 
3293 static PetscErrorCode MatSetRandom_SeqAIJ(Mat x, PetscRandom rctx) {
3294   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data;
3295   PetscScalar a, *aa;
3296   PetscInt    m, n, i, j, col;
3297 
3298   PetscFunctionBegin;
3299   if (!x->assembled) {
3300     PetscCall(MatGetSize(x, &m, &n));
3301     for (i = 0; i < m; i++) {
3302       for (j = 0; j < aij->imax[i]; j++) {
3303         PetscCall(PetscRandomGetValue(rctx, &a));
3304         col = (PetscInt)(n * PetscRealPart(a));
3305         PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES));
3306       }
3307     }
3308   } else {
3309     PetscCall(MatSeqAIJGetArrayWrite(x, &aa));
3310     for (i = 0; i < aij->nz; i++) PetscCall(PetscRandomGetValue(rctx, aa + i));
3311     PetscCall(MatSeqAIJRestoreArrayWrite(x, &aa));
3312   }
3313   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
3314   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
3315   PetscFunctionReturn(0);
3316 }
3317 
3318 /* Like MatSetRandom_SeqAIJ, but do not set values on columns in range of [low, high) */
3319 PetscErrorCode MatSetRandomSkipColumnRange_SeqAIJ_Private(Mat x, PetscInt low, PetscInt high, PetscRandom rctx) {
3320   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)x->data;
3321   PetscScalar a;
3322   PetscInt    m, n, i, j, col, nskip;
3323 
3324   PetscFunctionBegin;
3325   nskip = high - low;
3326   PetscCall(MatGetSize(x, &m, &n));
3327   n -= nskip; /* shrink number of columns where nonzeros can be set */
3328   for (i = 0; i < m; i++) {
3329     for (j = 0; j < aij->imax[i]; j++) {
3330       PetscCall(PetscRandomGetValue(rctx, &a));
3331       col = (PetscInt)(n * PetscRealPart(a));
3332       if (col >= low) col += nskip; /* shift col rightward to skip the hole */
3333       PetscCall(MatSetValues(x, 1, &i, 1, &col, &a, ADD_VALUES));
3334     }
3335   }
3336   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
3337   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
3338   PetscFunctionReturn(0);
3339 }
3340 
3341 /* -------------------------------------------------------------------*/
3342 static struct _MatOps MatOps_Values = {MatSetValues_SeqAIJ,
3343                                        MatGetRow_SeqAIJ,
3344                                        MatRestoreRow_SeqAIJ,
3345                                        MatMult_SeqAIJ,
3346                                        /*  4*/ MatMultAdd_SeqAIJ,
3347                                        MatMultTranspose_SeqAIJ,
3348                                        MatMultTransposeAdd_SeqAIJ,
3349                                        NULL,
3350                                        NULL,
3351                                        NULL,
3352                                        /* 10*/ NULL,
3353                                        MatLUFactor_SeqAIJ,
3354                                        NULL,
3355                                        MatSOR_SeqAIJ,
3356                                        MatTranspose_SeqAIJ,
3357                                        /*1 5*/ MatGetInfo_SeqAIJ,
3358                                        MatEqual_SeqAIJ,
3359                                        MatGetDiagonal_SeqAIJ,
3360                                        MatDiagonalScale_SeqAIJ,
3361                                        MatNorm_SeqAIJ,
3362                                        /* 20*/ NULL,
3363                                        MatAssemblyEnd_SeqAIJ,
3364                                        MatSetOption_SeqAIJ,
3365                                        MatZeroEntries_SeqAIJ,
3366                                        /* 24*/ MatZeroRows_SeqAIJ,
3367                                        NULL,
3368                                        NULL,
3369                                        NULL,
3370                                        NULL,
3371                                        /* 29*/ MatSetUp_SeqAIJ,
3372                                        NULL,
3373                                        NULL,
3374                                        NULL,
3375                                        NULL,
3376                                        /* 34*/ MatDuplicate_SeqAIJ,
3377                                        NULL,
3378                                        NULL,
3379                                        MatILUFactor_SeqAIJ,
3380                                        NULL,
3381                                        /* 39*/ MatAXPY_SeqAIJ,
3382                                        MatCreateSubMatrices_SeqAIJ,
3383                                        MatIncreaseOverlap_SeqAIJ,
3384                                        MatGetValues_SeqAIJ,
3385                                        MatCopy_SeqAIJ,
3386                                        /* 44*/ MatGetRowMax_SeqAIJ,
3387                                        MatScale_SeqAIJ,
3388                                        MatShift_SeqAIJ,
3389                                        MatDiagonalSet_SeqAIJ,
3390                                        MatZeroRowsColumns_SeqAIJ,
3391                                        /* 49*/ MatSetRandom_SeqAIJ,
3392                                        MatGetRowIJ_SeqAIJ,
3393                                        MatRestoreRowIJ_SeqAIJ,
3394                                        MatGetColumnIJ_SeqAIJ,
3395                                        MatRestoreColumnIJ_SeqAIJ,
3396                                        /* 54*/ MatFDColoringCreate_SeqXAIJ,
3397                                        NULL,
3398                                        NULL,
3399                                        MatPermute_SeqAIJ,
3400                                        NULL,
3401                                        /* 59*/ NULL,
3402                                        MatDestroy_SeqAIJ,
3403                                        MatView_SeqAIJ,
3404                                        NULL,
3405                                        NULL,
3406                                        /* 64*/ NULL,
3407                                        MatMatMatMultNumeric_SeqAIJ_SeqAIJ_SeqAIJ,
3408                                        NULL,
3409                                        NULL,
3410                                        NULL,
3411                                        /* 69*/ MatGetRowMaxAbs_SeqAIJ,
3412                                        MatGetRowMinAbs_SeqAIJ,
3413                                        NULL,
3414                                        NULL,
3415                                        NULL,
3416                                        /* 74*/ NULL,
3417                                        MatFDColoringApply_AIJ,
3418                                        NULL,
3419                                        NULL,
3420                                        NULL,
3421                                        /* 79*/ MatFindZeroDiagonals_SeqAIJ,
3422                                        NULL,
3423                                        NULL,
3424                                        NULL,
3425                                        MatLoad_SeqAIJ,
3426                                        /* 84*/ MatIsSymmetric_SeqAIJ,
3427                                        MatIsHermitian_SeqAIJ,
3428                                        NULL,
3429                                        NULL,
3430                                        NULL,
3431                                        /* 89*/ NULL,
3432                                        NULL,
3433                                        MatMatMultNumeric_SeqAIJ_SeqAIJ,
3434                                        NULL,
3435                                        NULL,
3436                                        /* 94*/ MatPtAPNumeric_SeqAIJ_SeqAIJ_SparseAxpy,
3437                                        NULL,
3438                                        NULL,
3439                                        MatMatTransposeMultNumeric_SeqAIJ_SeqAIJ,
3440                                        NULL,
3441                                        /* 99*/ MatProductSetFromOptions_SeqAIJ,
3442                                        NULL,
3443                                        NULL,
3444                                        MatConjugate_SeqAIJ,
3445                                        NULL,
3446                                        /*104*/ MatSetValuesRow_SeqAIJ,
3447                                        MatRealPart_SeqAIJ,
3448                                        MatImaginaryPart_SeqAIJ,
3449                                        NULL,
3450                                        NULL,
3451                                        /*109*/ MatMatSolve_SeqAIJ,
3452                                        NULL,
3453                                        MatGetRowMin_SeqAIJ,
3454                                        NULL,
3455                                        MatMissingDiagonal_SeqAIJ,
3456                                        /*114*/ NULL,
3457                                        NULL,
3458                                        NULL,
3459                                        NULL,
3460                                        NULL,
3461                                        /*119*/ NULL,
3462                                        NULL,
3463                                        NULL,
3464                                        NULL,
3465                                        MatGetMultiProcBlock_SeqAIJ,
3466                                        /*124*/ MatFindNonzeroRows_SeqAIJ,
3467                                        MatGetColumnReductions_SeqAIJ,
3468                                        MatInvertBlockDiagonal_SeqAIJ,
3469                                        MatInvertVariableBlockDiagonal_SeqAIJ,
3470                                        NULL,
3471                                        /*129*/ NULL,
3472                                        NULL,
3473                                        NULL,
3474                                        MatTransposeMatMultNumeric_SeqAIJ_SeqAIJ,
3475                                        MatTransposeColoringCreate_SeqAIJ,
3476                                        /*134*/ MatTransColoringApplySpToDen_SeqAIJ,
3477                                        MatTransColoringApplyDenToSp_SeqAIJ,
3478                                        NULL,
3479                                        NULL,
3480                                        MatRARtNumeric_SeqAIJ_SeqAIJ,
3481                                        /*139*/ NULL,
3482                                        NULL,
3483                                        NULL,
3484                                        MatFDColoringSetUp_SeqXAIJ,
3485                                        MatFindOffBlockDiagonalEntries_SeqAIJ,
3486                                        MatCreateMPIMatConcatenateSeqMat_SeqAIJ,
3487                                        /*145*/ MatDestroySubMatrices_SeqAIJ,
3488                                        NULL,
3489                                        NULL,
3490                                        MatCreateGraph_Simple_AIJ,
3491                                        MatFilter_AIJ,
3492                                        /*150*/ MatTransposeSymbolic_SeqAIJ};
3493 
3494 PetscErrorCode MatSeqAIJSetColumnIndices_SeqAIJ(Mat mat, PetscInt *indices) {
3495   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data;
3496   PetscInt    i, nz, n;
3497 
3498   PetscFunctionBegin;
3499   nz = aij->maxnz;
3500   n  = mat->rmap->n;
3501   for (i = 0; i < nz; i++) aij->j[i] = indices[i];
3502   aij->nz = nz;
3503   for (i = 0; i < n; i++) aij->ilen[i] = aij->imax[i];
3504   PetscFunctionReturn(0);
3505 }
3506 
3507 /*
3508  * Given a sparse matrix with global column indices, compact it by using a local column space.
3509  * The result matrix helps saving memory in other algorithms, such as MatPtAPSymbolic_MPIAIJ_MPIAIJ_scalable()
3510  */
3511 PetscErrorCode MatSeqAIJCompactOutExtraColumns_SeqAIJ(Mat mat, ISLocalToGlobalMapping *mapping) {
3512   Mat_SeqAIJ        *aij = (Mat_SeqAIJ *)mat->data;
3513   PetscTable         gid1_lid1;
3514   PetscTablePosition tpos;
3515   PetscInt           gid, lid, i, ec, nz = aij->nz;
3516   PetscInt          *garray, *jj = aij->j;
3517 
3518   PetscFunctionBegin;
3519   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3520   PetscValidPointer(mapping, 2);
3521   /* use a table */
3522   PetscCall(PetscTableCreate(mat->rmap->n, mat->cmap->N + 1, &gid1_lid1));
3523   ec = 0;
3524   for (i = 0; i < nz; i++) {
3525     PetscInt data, gid1 = jj[i] + 1;
3526     PetscCall(PetscTableFind(gid1_lid1, gid1, &data));
3527     if (!data) {
3528       /* one based table */
3529       PetscCall(PetscTableAdd(gid1_lid1, gid1, ++ec, INSERT_VALUES));
3530     }
3531   }
3532   /* form array of columns we need */
3533   PetscCall(PetscMalloc1(ec, &garray));
3534   PetscCall(PetscTableGetHeadPosition(gid1_lid1, &tpos));
3535   while (tpos) {
3536     PetscCall(PetscTableGetNext(gid1_lid1, &tpos, &gid, &lid));
3537     gid--;
3538     lid--;
3539     garray[lid] = gid;
3540   }
3541   PetscCall(PetscSortInt(ec, garray)); /* sort, and rebuild */
3542   PetscCall(PetscTableRemoveAll(gid1_lid1));
3543   for (i = 0; i < ec; i++) PetscCall(PetscTableAdd(gid1_lid1, garray[i] + 1, i + 1, INSERT_VALUES));
3544   /* compact out the extra columns in B */
3545   for (i = 0; i < nz; i++) {
3546     PetscInt gid1 = jj[i] + 1;
3547     PetscCall(PetscTableFind(gid1_lid1, gid1, &lid));
3548     lid--;
3549     jj[i] = lid;
3550   }
3551   PetscCall(PetscLayoutDestroy(&mat->cmap));
3552   PetscCall(PetscTableDestroy(&gid1_lid1));
3553   PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)mat), ec, ec, 1, &mat->cmap));
3554   PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, mat->cmap->bs, mat->cmap->n, garray, PETSC_OWN_POINTER, mapping));
3555   PetscCall(ISLocalToGlobalMappingSetType(*mapping, ISLOCALTOGLOBALMAPPINGHASH));
3556   PetscFunctionReturn(0);
3557 }
3558 
3559 /*@
3560     MatSeqAIJSetColumnIndices - Set the column indices for all the rows
3561        in the matrix.
3562 
3563   Input Parameters:
3564 +  mat - the `MATSEQAIJ` matrix
3565 -  indices - the column indices
3566 
3567   Level: advanced
3568 
3569   Notes:
3570     This can be called if you have precomputed the nonzero structure of the
3571   matrix and want to provide it to the matrix object to improve the performance
3572   of the `MatSetValues()` operation.
3573 
3574     You MUST have set the correct numbers of nonzeros per row in the call to
3575   `MatCreateSeqAIJ()`, and the columns indices MUST be sorted.
3576 
3577     MUST be called before any calls to `MatSetValues()`
3578 
3579     The indices should start with zero, not one.
3580 
3581 @*/
3582 PetscErrorCode MatSeqAIJSetColumnIndices(Mat mat, PetscInt *indices) {
3583   PetscFunctionBegin;
3584   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3585   PetscValidIntPointer(indices, 2);
3586   PetscUseMethod(mat, "MatSeqAIJSetColumnIndices_C", (Mat, PetscInt *), (mat, indices));
3587   PetscFunctionReturn(0);
3588 }
3589 
3590 /* ----------------------------------------------------------------------------------------*/
3591 
3592 PetscErrorCode MatStoreValues_SeqAIJ(Mat mat) {
3593   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data;
3594   size_t      nz  = aij->i[mat->rmap->n];
3595 
3596   PetscFunctionBegin;
3597   PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first");
3598 
3599   /* allocate space for values if not already there */
3600   if (!aij->saved_values) {
3601     PetscCall(PetscMalloc1(nz + 1, &aij->saved_values));
3602     PetscCall(PetscLogObjectMemory((PetscObject)mat, (nz + 1) * sizeof(PetscScalar)));
3603   }
3604 
3605   /* copy values over */
3606   PetscCall(PetscArraycpy(aij->saved_values, aij->a, nz));
3607   PetscFunctionReturn(0);
3608 }
3609 
3610 /*@
3611     MatStoreValues - Stashes a copy of the matrix values; this allows, for
3612        example, reuse of the linear part of a Jacobian, while recomputing the
3613        nonlinear portion.
3614 
3615    Collect on mat
3616 
3617   Input Parameters:
3618 .  mat - the matrix (currently only `MATAIJ` matrices support this option)
3619 
3620   Level: advanced
3621 
3622   Common Usage, with `SNESSolve()`:
3623 $    Create Jacobian matrix
3624 $    Set linear terms into matrix
3625 $    Apply boundary conditions to matrix, at this time matrix must have
3626 $      final nonzero structure (i.e. setting the nonlinear terms and applying
3627 $      boundary conditions again will not change the nonzero structure
3628 $    ierr = MatSetOption(mat,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);
3629 $    ierr = MatStoreValues(mat);
3630 $    Call SNESSetJacobian() with matrix
3631 $    In your Jacobian routine
3632 $      ierr = MatRetrieveValues(mat);
3633 $      Set nonlinear terms in matrix
3634 
3635   Common Usage without SNESSolve(), i.e. when you handle nonlinear solve yourself:
3636 $    // build linear portion of Jacobian
3637 $    ierr = MatSetOption(mat,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);
3638 $    ierr = MatStoreValues(mat);
3639 $    loop over nonlinear iterations
3640 $       ierr = MatRetrieveValues(mat);
3641 $       // call MatSetValues(mat,...) to set nonliner portion of Jacobian
3642 $       // call MatAssemblyBegin/End() on matrix
3643 $       Solve linear system with Jacobian
3644 $    endloop
3645 
3646   Notes:
3647     Matrix must already be assemblied before calling this routine
3648     Must set the matrix option `MatSetOption`(mat,`MAT_NEW_NONZERO_LOCATIONS`,`PETSC_FALSE`); before
3649     calling this routine.
3650 
3651     When this is called multiple times it overwrites the previous set of stored values
3652     and does not allocated additional space.
3653 
3654 .seealso: `MatRetrieveValues()`
3655 @*/
3656 PetscErrorCode MatStoreValues(Mat mat) {
3657   PetscFunctionBegin;
3658   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3659   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3660   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3661   PetscUseMethod(mat, "MatStoreValues_C", (Mat), (mat));
3662   PetscFunctionReturn(0);
3663 }
3664 
3665 PetscErrorCode MatRetrieveValues_SeqAIJ(Mat mat) {
3666   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data;
3667   PetscInt    nz  = aij->i[mat->rmap->n];
3668 
3669   PetscFunctionBegin;
3670   PetscCheck(aij->nonew, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);first");
3671   PetscCheck(aij->saved_values, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call MatStoreValues(A);first");
3672   /* copy values over */
3673   PetscCall(PetscArraycpy(aij->a, aij->saved_values, nz));
3674   PetscFunctionReturn(0);
3675 }
3676 
3677 /*@
3678     MatRetrieveValues - Retrieves the copy of the matrix values; this allows, for
3679        example, reuse of the linear part of a Jacobian, while recomputing the
3680        nonlinear portion.
3681 
3682    Collect on mat
3683 
3684   Input Parameters:
3685 .  mat - the matrix (currently only `MATAIJ` matrices support this option)
3686 
3687   Level: advanced
3688 
3689 .seealso: `MatStoreValues()`
3690 @*/
3691 PetscErrorCode MatRetrieveValues(Mat mat) {
3692   PetscFunctionBegin;
3693   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3694   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3695   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3696   PetscUseMethod(mat, "MatRetrieveValues_C", (Mat), (mat));
3697   PetscFunctionReturn(0);
3698 }
3699 
3700 /* --------------------------------------------------------------------------------*/
3701 /*@C
3702    MatCreateSeqAIJ - Creates a sparse matrix in `MATSEQAIJ` (compressed row) format
3703    (the default parallel PETSc format).  For good matrix assembly performance
3704    the user should preallocate the matrix storage by setting the parameter nz
3705    (or the array nnz).  By setting these parameters accurately, performance
3706    during matrix assembly can be increased by more than a factor of 50.
3707 
3708    Collective
3709 
3710    Input Parameters:
3711 +  comm - MPI communicator, set to `PETSC_COMM_SELF`
3712 .  m - number of rows
3713 .  n - number of columns
3714 .  nz - number of nonzeros per row (same for all rows)
3715 -  nnz - array containing the number of nonzeros in the various rows
3716          (possibly different for each row) or NULL
3717 
3718    Output Parameter:
3719 .  A - the matrix
3720 
3721    It is recommended that one use the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`,
3722    MatXXXXSetPreallocation() paradigm instead of this routine directly.
3723    [MatXXXXSetPreallocation() is, for example, `MatSeqAIJSetPreallocation()`]
3724 
3725    Notes:
3726    If nnz is given then nz is ignored
3727 
3728    The AIJ format, also called
3729    compressed row storage, is fully compatible with standard Fortran 77
3730    storage.  That is, the stored row and column indices can begin at
3731    either one (as in Fortran) or zero.  See the users' manual for details.
3732 
3733    Specify the preallocated storage with either nz or nnz (not both).
3734    Set nz = `PETSC_DEFAULT` and nnz = NULL for PETSc to control dynamic memory
3735    allocation.  For large problems you MUST preallocate memory or you
3736    will get TERRIBLE performance, see the users' manual chapter on matrices.
3737 
3738    By default, this format uses inodes (identical nodes) when possible, to
3739    improve numerical efficiency of matrix-vector products and solves. We
3740    search for consecutive rows with the same nonzero structure, thereby
3741    reusing matrix information to achieve increased efficiency.
3742 
3743    Options Database Keys:
3744 +  -mat_no_inode  - Do not use inodes
3745 -  -mat_inode_limit <limit> - Sets inode limit (max limit=5)
3746 
3747    Level: intermediate
3748 
3749 .seealso: [Sparse Matrix Creation](sec_matsparse), `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()`
3750 @*/
3751 PetscErrorCode MatCreateSeqAIJ(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt nz, const PetscInt nnz[], Mat *A) {
3752   PetscFunctionBegin;
3753   PetscCall(MatCreate(comm, A));
3754   PetscCall(MatSetSizes(*A, m, n, m, n));
3755   PetscCall(MatSetType(*A, MATSEQAIJ));
3756   PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*A, nz, nnz));
3757   PetscFunctionReturn(0);
3758 }
3759 
3760 /*@C
3761    MatSeqAIJSetPreallocation - For good matrix assembly performance
3762    the user should preallocate the matrix storage by setting the parameter nz
3763    (or the array nnz).  By setting these parameters accurately, performance
3764    during matrix assembly can be increased by more than a factor of 50.
3765 
3766    Collective
3767 
3768    Input Parameters:
3769 +  B - The matrix
3770 .  nz - number of nonzeros per row (same for all rows)
3771 -  nnz - array containing the number of nonzeros in the various rows
3772          (possibly different for each row) or NULL
3773 
3774    Notes:
3775      If nnz is given then nz is ignored
3776 
3777     The `MATSEQAIJ` format also called
3778    compressed row storage, is fully compatible with standard Fortran 77
3779    storage.  That is, the stored row and column indices can begin at
3780    either one (as in Fortran) or zero.  See the users' manual for details.
3781 
3782    Specify the preallocated storage with either nz or nnz (not both).
3783    Set nz = `PETSC_DEFAULT` and nnz = NULL for PETSc to control dynamic memory
3784    allocation.  For large problems you MUST preallocate memory or you
3785    will get TERRIBLE performance, see the users' manual chapter on matrices.
3786 
3787    You can call `MatGetInfo()` to get information on how effective the preallocation was;
3788    for example the fields mallocs,nz_allocated,nz_used,nz_unneeded;
3789    You can also run with the option -info and look for messages with the string
3790    malloc in them to see if additional memory allocation was needed.
3791 
3792    Developer Notes:
3793    Use nz of `MAT_SKIP_ALLOCATION` to not allocate any space for the matrix
3794    entries or columns indices
3795 
3796    By default, this format uses inodes (identical nodes) when possible, to
3797    improve numerical efficiency of matrix-vector products and solves. We
3798    search for consecutive rows with the same nonzero structure, thereby
3799    reusing matrix information to achieve increased efficiency.
3800 
3801    Options Database Keys:
3802 +  -mat_no_inode  - Do not use inodes
3803 -  -mat_inode_limit <limit> - Sets inode limit (max limit=5)
3804 
3805    Level: intermediate
3806 
3807 .seealso: `MatCreate()`, `MatCreateAIJ()`, `MatSetValues()`, `MatSeqAIJSetColumnIndices()`, `MatCreateSeqAIJWithArrays()`, `MatGetInfo()`,
3808           `MatSeqAIJSetTotalPreallocation()`
3809 @*/
3810 PetscErrorCode MatSeqAIJSetPreallocation(Mat B, PetscInt nz, const PetscInt nnz[]) {
3811   PetscFunctionBegin;
3812   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
3813   PetscValidType(B, 1);
3814   PetscTryMethod(B, "MatSeqAIJSetPreallocation_C", (Mat, PetscInt, const PetscInt[]), (B, nz, nnz));
3815   PetscFunctionReturn(0);
3816 }
3817 
3818 PetscErrorCode MatSeqAIJSetPreallocation_SeqAIJ(Mat B, PetscInt nz, const PetscInt *nnz) {
3819   Mat_SeqAIJ *b;
3820   PetscBool   skipallocation = PETSC_FALSE, realalloc = PETSC_FALSE;
3821   PetscInt    i;
3822 
3823   PetscFunctionBegin;
3824   if (nz >= 0 || nnz) realalloc = PETSC_TRUE;
3825   if (nz == MAT_SKIP_ALLOCATION) {
3826     skipallocation = PETSC_TRUE;
3827     nz             = 0;
3828   }
3829   PetscCall(PetscLayoutSetUp(B->rmap));
3830   PetscCall(PetscLayoutSetUp(B->cmap));
3831 
3832   if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 5;
3833   PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nz cannot be less than 0: value %" PetscInt_FMT, nz);
3834   if (PetscUnlikelyDebug(nnz)) {
3835     for (i = 0; i < B->rmap->n; i++) {
3836       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]);
3837       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);
3838     }
3839   }
3840 
3841   B->preallocated = PETSC_TRUE;
3842 
3843   b = (Mat_SeqAIJ *)B->data;
3844 
3845   if (!skipallocation) {
3846     if (!b->imax) {
3847       PetscCall(PetscMalloc1(B->rmap->n, &b->imax));
3848       PetscCall(PetscLogObjectMemory((PetscObject)B, B->rmap->n * sizeof(PetscInt)));
3849     }
3850     if (!b->ilen) {
3851       /* b->ilen will count nonzeros in each row so far. */
3852       PetscCall(PetscCalloc1(B->rmap->n, &b->ilen));
3853       PetscCall(PetscLogObjectMemory((PetscObject)B, B->rmap->n * sizeof(PetscInt)));
3854     } else {
3855       PetscCall(PetscMemzero(b->ilen, B->rmap->n * sizeof(PetscInt)));
3856     }
3857     if (!b->ipre) {
3858       PetscCall(PetscMalloc1(B->rmap->n, &b->ipre));
3859       PetscCall(PetscLogObjectMemory((PetscObject)B, B->rmap->n * sizeof(PetscInt)));
3860     }
3861     if (!nnz) {
3862       if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 10;
3863       else if (nz < 0) nz = 1;
3864       nz = PetscMin(nz, B->cmap->n);
3865       for (i = 0; i < B->rmap->n; i++) b->imax[i] = nz;
3866       nz = nz * B->rmap->n;
3867     } else {
3868       PetscInt64 nz64 = 0;
3869       for (i = 0; i < B->rmap->n; i++) {
3870         b->imax[i] = nnz[i];
3871         nz64 += nnz[i];
3872       }
3873       PetscCall(PetscIntCast(nz64, &nz));
3874     }
3875 
3876     /* allocate the matrix space */
3877     /* FIXME: should B's old memory be unlogged? */
3878     PetscCall(MatSeqXAIJFreeAIJ(B, &b->a, &b->j, &b->i));
3879     if (B->structure_only) {
3880       PetscCall(PetscMalloc1(nz, &b->j));
3881       PetscCall(PetscMalloc1(B->rmap->n + 1, &b->i));
3882       PetscCall(PetscLogObjectMemory((PetscObject)B, (B->rmap->n + 1) * sizeof(PetscInt) + nz * sizeof(PetscInt)));
3883     } else {
3884       PetscCall(PetscMalloc3(nz, &b->a, nz, &b->j, B->rmap->n + 1, &b->i));
3885       PetscCall(PetscLogObjectMemory((PetscObject)B, (B->rmap->n + 1) * sizeof(PetscInt) + nz * (sizeof(PetscScalar) + sizeof(PetscInt))));
3886     }
3887     b->i[0] = 0;
3888     for (i = 1; i < B->rmap->n + 1; i++) b->i[i] = b->i[i - 1] + b->imax[i - 1];
3889     if (B->structure_only) {
3890       b->singlemalloc = PETSC_FALSE;
3891       b->free_a       = PETSC_FALSE;
3892     } else {
3893       b->singlemalloc = PETSC_TRUE;
3894       b->free_a       = PETSC_TRUE;
3895     }
3896     b->free_ij = PETSC_TRUE;
3897   } else {
3898     b->free_a  = PETSC_FALSE;
3899     b->free_ij = PETSC_FALSE;
3900   }
3901 
3902   if (b->ipre && nnz != b->ipre && b->imax) {
3903     /* reserve user-requested sparsity */
3904     PetscCall(PetscArraycpy(b->ipre, b->imax, B->rmap->n));
3905   }
3906 
3907   b->nz               = 0;
3908   b->maxnz            = nz;
3909   B->info.nz_unneeded = (double)b->maxnz;
3910   if (realalloc) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
3911   B->was_assembled = PETSC_FALSE;
3912   B->assembled     = PETSC_FALSE;
3913   /* We simply deem preallocation has changed nonzero state. Updating the state
3914      will give clients (like AIJKokkos) a chance to know something has happened.
3915   */
3916   B->nonzerostate++;
3917   PetscFunctionReturn(0);
3918 }
3919 
3920 PetscErrorCode MatResetPreallocation_SeqAIJ(Mat A) {
3921   Mat_SeqAIJ *a;
3922   PetscInt    i;
3923 
3924   PetscFunctionBegin;
3925   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3926 
3927   /* Check local size. If zero, then return */
3928   if (!A->rmap->n) PetscFunctionReturn(0);
3929 
3930   a = (Mat_SeqAIJ *)A->data;
3931   /* if no saved info, we error out */
3932   PetscCheck(a->ipre, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "No saved preallocation info ");
3933 
3934   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 ");
3935 
3936   PetscCall(PetscArraycpy(a->imax, a->ipre, A->rmap->n));
3937   PetscCall(PetscArrayzero(a->ilen, A->rmap->n));
3938   a->i[0] = 0;
3939   for (i = 1; i < A->rmap->n + 1; i++) a->i[i] = a->i[i - 1] + a->imax[i - 1];
3940   A->preallocated     = PETSC_TRUE;
3941   a->nz               = 0;
3942   a->maxnz            = a->i[A->rmap->n];
3943   A->info.nz_unneeded = (double)a->maxnz;
3944   A->was_assembled    = PETSC_FALSE;
3945   A->assembled        = PETSC_FALSE;
3946   PetscFunctionReturn(0);
3947 }
3948 
3949 /*@
3950    MatSeqAIJSetPreallocationCSR - Allocates memory for a sparse sequential matrix in `MATSEQAIJ` format.
3951 
3952    Input Parameters:
3953 +  B - the matrix
3954 .  i - the indices into j for the start of each row (starts with zero)
3955 .  j - the column indices for each row (starts with zero) these must be sorted for each row
3956 -  v - optional values in the matrix
3957 
3958    Level: developer
3959 
3960    Notes:
3961       The i,j,v values are COPIED with this routine; to avoid the copy use `MatCreateSeqAIJWithArrays()`
3962 
3963       This routine may be called multiple times with different nonzero patterns (or the same nonzero pattern). The nonzero
3964       structure will be the union of all the previous nonzero structures.
3965 
3966     Developer Notes:
3967       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
3968       then just copies the v values directly with `PetscMemcpy()`.
3969 
3970       This routine could also take a `PetscCopyMode` argument to allow sharing the values instead of always copying them.
3971 
3972 .seealso: `MatCreate()`, `MatCreateSeqAIJ()`, `MatSetValues()`, `MatSeqAIJSetPreallocation()`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MatResetPreallocation()`
3973 @*/
3974 PetscErrorCode MatSeqAIJSetPreallocationCSR(Mat B, const PetscInt i[], const PetscInt j[], const PetscScalar v[]) {
3975   PetscFunctionBegin;
3976   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
3977   PetscValidType(B, 1);
3978   PetscTryMethod(B, "MatSeqAIJSetPreallocationCSR_C", (Mat, const PetscInt[], const PetscInt[], const PetscScalar[]), (B, i, j, v));
3979   PetscFunctionReturn(0);
3980 }
3981 
3982 PetscErrorCode MatSeqAIJSetPreallocationCSR_SeqAIJ(Mat B, const PetscInt Ii[], const PetscInt J[], const PetscScalar v[]) {
3983   PetscInt  i;
3984   PetscInt  m, n;
3985   PetscInt  nz;
3986   PetscInt *nnz;
3987 
3988   PetscFunctionBegin;
3989   PetscCheck(Ii[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Ii[0] must be 0 it is %" PetscInt_FMT, Ii[0]);
3990 
3991   PetscCall(PetscLayoutSetUp(B->rmap));
3992   PetscCall(PetscLayoutSetUp(B->cmap));
3993 
3994   PetscCall(MatGetSize(B, &m, &n));
3995   PetscCall(PetscMalloc1(m + 1, &nnz));
3996   for (i = 0; i < m; i++) {
3997     nz = Ii[i + 1] - Ii[i];
3998     PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local row %" PetscInt_FMT " has a negative number of columns %" PetscInt_FMT, i, nz);
3999     nnz[i] = nz;
4000   }
4001   PetscCall(MatSeqAIJSetPreallocation(B, 0, nnz));
4002   PetscCall(PetscFree(nnz));
4003 
4004   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));
4005 
4006   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
4007   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
4008 
4009   PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE));
4010   PetscFunctionReturn(0);
4011 }
4012 
4013 /*@
4014    MatSeqAIJKron - Computes C, the Kronecker product of A and B.
4015 
4016    Input Parameters:
4017 +  A - left-hand side matrix
4018 .  B - right-hand side matrix
4019 -  reuse - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
4020 
4021    Output Parameter:
4022 .  C - Kronecker product of A and B
4023 
4024    Level: intermediate
4025 
4026    Note:
4027       `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the product matrix has not changed from that last call to `MatSeqAIJKron()`.
4028 
4029 .seealso: `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATKAIJ`, `MatReuse`
4030 @*/
4031 PetscErrorCode MatSeqAIJKron(Mat A, Mat B, MatReuse reuse, Mat *C) {
4032   PetscFunctionBegin;
4033   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
4034   PetscValidType(A, 1);
4035   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
4036   PetscValidType(B, 2);
4037   PetscValidPointer(C, 4);
4038   if (reuse == MAT_REUSE_MATRIX) {
4039     PetscValidHeaderSpecific(*C, MAT_CLASSID, 4);
4040     PetscValidType(*C, 4);
4041   }
4042   PetscTryMethod(A, "MatSeqAIJKron_C", (Mat, Mat, MatReuse, Mat *), (A, B, reuse, C));
4043   PetscFunctionReturn(0);
4044 }
4045 
4046 PetscErrorCode MatSeqAIJKron_SeqAIJ(Mat A, Mat B, MatReuse reuse, Mat *C) {
4047   Mat                newmat;
4048   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data;
4049   Mat_SeqAIJ        *b = (Mat_SeqAIJ *)B->data;
4050   PetscScalar       *v;
4051   const PetscScalar *aa, *ba;
4052   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;
4053   PetscBool          flg;
4054 
4055   PetscFunctionBegin;
4056   PetscCheck(!A->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4057   PetscCheck(A->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4058   PetscCheck(!B->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4059   PetscCheck(B->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4060   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &flg));
4061   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatType %s", ((PetscObject)B)->type_name);
4062   PetscCheck(reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatReuse %d", (int)reuse);
4063   if (reuse == MAT_INITIAL_MATRIX) {
4064     PetscCall(PetscMalloc2(am * bm + 1, &i, a->i[am] * b->i[bm], &j));
4065     PetscCall(MatCreate(PETSC_COMM_SELF, &newmat));
4066     PetscCall(MatSetSizes(newmat, am * bm, an * bn, am * bm, an * bn));
4067     PetscCall(MatSetType(newmat, MATAIJ));
4068     i[0] = 0;
4069     for (m = 0; m < am; ++m) {
4070       for (p = 0; p < bm; ++p) {
4071         i[m * bm + p + 1] = i[m * bm + p] + (a->i[m + 1] - a->i[m]) * (b->i[p + 1] - b->i[p]);
4072         for (n = a->i[m]; n < a->i[m + 1]; ++n) {
4073           for (q = b->i[p]; q < b->i[p + 1]; ++q) j[nnz++] = a->j[n] * bn + b->j[q];
4074         }
4075       }
4076     }
4077     PetscCall(MatSeqAIJSetPreallocationCSR(newmat, i, j, NULL));
4078     *C = newmat;
4079     PetscCall(PetscFree2(i, j));
4080     nnz = 0;
4081   }
4082   PetscCall(MatSeqAIJGetArray(*C, &v));
4083   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
4084   PetscCall(MatSeqAIJGetArrayRead(B, &ba));
4085   for (m = 0; m < am; ++m) {
4086     for (p = 0; p < bm; ++p) {
4087       for (n = a->i[m]; n < a->i[m + 1]; ++n) {
4088         for (q = b->i[p]; q < b->i[p + 1]; ++q) v[nnz++] = aa[n] * ba[q];
4089       }
4090     }
4091   }
4092   PetscCall(MatSeqAIJRestoreArray(*C, &v));
4093   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
4094   PetscCall(MatSeqAIJRestoreArrayRead(B, &ba));
4095   PetscFunctionReturn(0);
4096 }
4097 
4098 #include <../src/mat/impls/dense/seq/dense.h>
4099 #include <petsc/private/kernels/petscaxpy.h>
4100 
4101 /*
4102     Computes (B'*A')' since computing B*A directly is untenable
4103 
4104                n                       p                          p
4105         [             ]       [             ]         [                 ]
4106       m [      A      ]  *  n [       B     ]   =   m [         C       ]
4107         [             ]       [             ]         [                 ]
4108 
4109 */
4110 PetscErrorCode MatMatMultNumeric_SeqDense_SeqAIJ(Mat A, Mat B, Mat C) {
4111   Mat_SeqDense      *sub_a = (Mat_SeqDense *)A->data;
4112   Mat_SeqAIJ        *sub_b = (Mat_SeqAIJ *)B->data;
4113   Mat_SeqDense      *sub_c = (Mat_SeqDense *)C->data;
4114   PetscInt           i, j, n, m, q, p;
4115   const PetscInt    *ii, *idx;
4116   const PetscScalar *b, *a, *a_q;
4117   PetscScalar       *c, *c_q;
4118   PetscInt           clda = sub_c->lda;
4119   PetscInt           alda = sub_a->lda;
4120 
4121   PetscFunctionBegin;
4122   m = A->rmap->n;
4123   n = A->cmap->n;
4124   p = B->cmap->n;
4125   a = sub_a->v;
4126   b = sub_b->a;
4127   c = sub_c->v;
4128   if (clda == m) {
4129     PetscCall(PetscArrayzero(c, m * p));
4130   } else {
4131     for (j = 0; j < p; j++)
4132       for (i = 0; i < m; i++) c[j * clda + i] = 0.0;
4133   }
4134   ii  = sub_b->i;
4135   idx = sub_b->j;
4136   for (i = 0; i < n; i++) {
4137     q = ii[i + 1] - ii[i];
4138     while (q-- > 0) {
4139       c_q = c + clda * (*idx);
4140       a_q = a + alda * i;
4141       PetscKernelAXPY(c_q, *b, a_q, m);
4142       idx++;
4143       b++;
4144     }
4145   }
4146   PetscFunctionReturn(0);
4147 }
4148 
4149 PetscErrorCode MatMatMultSymbolic_SeqDense_SeqAIJ(Mat A, Mat B, PetscReal fill, Mat C) {
4150   PetscInt  m = A->rmap->n, n = B->cmap->n;
4151   PetscBool cisdense;
4152 
4153   PetscFunctionBegin;
4154   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);
4155   PetscCall(MatSetSizes(C, m, n, m, n));
4156   PetscCall(MatSetBlockSizesFromMats(C, A, B));
4157   PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATSEQDENSECUDA, ""));
4158   if (!cisdense) PetscCall(MatSetType(C, MATDENSE));
4159   PetscCall(MatSetUp(C));
4160 
4161   C->ops->matmultnumeric = MatMatMultNumeric_SeqDense_SeqAIJ;
4162   PetscFunctionReturn(0);
4163 }
4164 
4165 /* ----------------------------------------------------------------*/
4166 /*MC
4167    MATSEQAIJ - MATSEQAIJ = "seqaij" - A matrix type to be used for sequential sparse matrices,
4168    based on compressed sparse row format.
4169 
4170    Options Database Keys:
4171 . -mat_type seqaij - sets the matrix type to "seqaij" during a call to MatSetFromOptions()
4172 
4173    Level: beginner
4174 
4175    Notes:
4176     `MatSetValues()` may be called for this matrix type with a NULL argument for the numerical values,
4177     in this case the values associated with the rows and columns one passes in are set to zero
4178     in the matrix
4179 
4180     `MatSetOptions`(,`MAT_STRUCTURE_ONLY`,`PETSC_TRUE`) may be called for this matrix type. In this no
4181     space is allocated for the nonzero entries and any entries passed with `MatSetValues()` are ignored
4182 
4183   Developer Note:
4184     It would be nice if all matrix formats supported passing NULL in for the numerical values
4185 
4186 .seealso: `MatCreateSeqAIJ()`, `MatSetFromOptions()`, `MatSetType()`, `MatCreate()`, `MatType`, `MATSELL`, `MATSEQSELL`, `MATMPISELL`
4187 M*/
4188 
4189 /*MC
4190    MATAIJ - MATAIJ = "aij" - A matrix type to be used for sparse matrices.
4191 
4192    This matrix type is identical to `MATSEQAIJ` when constructed with a single process communicator,
4193    and `MATMPIAIJ` otherwise.  As a result, for single process communicators,
4194    `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported
4195    for communicators controlling multiple processes.  It is recommended that you call both of
4196    the above preallocation routines for simplicity.
4197 
4198    Options Database Keys:
4199 . -mat_type aij - sets the matrix type to "aij" during a call to `MatSetFromOptions()`
4200 
4201    Note:
4202    Subclasses include `MATAIJCUSPARSE`, `MATAIJPERM`, `MATAIJSELL`, `MATAIJMKL`, `MATAIJCRL`, and also automatically switches over to use inodes when
4203    enough exist.
4204 
4205   Level: beginner
4206 
4207 .seealso: `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MATSEQAIJ`, `MATMPIAIJ`, `MATSELL`, `MATSEQSELL`, `MATMPISELL`
4208 M*/
4209 
4210 /*MC
4211    MATAIJCRL - MATAIJCRL = "aijcrl" - A matrix type to be used for sparse matrices.
4212 
4213    This matrix type is identical to `MATSEQAIJCRL` when constructed with a single process communicator,
4214    and `MATMPIAIJCRL` otherwise.  As a result, for single process communicators,
4215    `MatSeqAIJSetPreallocation()` is supported, and similarly `MatMPIAIJSetPreallocation()` is supported
4216    for communicators controlling multiple processes.  It is recommended that you call both of
4217    the above preallocation routines for simplicity.
4218 
4219    Options Database Keys:
4220 . -mat_type aijcrl - sets the matrix type to "aijcrl" during a call to `MatSetFromOptions()`
4221 
4222   Level: beginner
4223 
4224 .seealso: `MatCreateMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL`, `MATSEQAIJCRL`, `MATMPIAIJCRL`
4225 M*/
4226 
4227 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCRL(Mat, MatType, MatReuse, Mat *);
4228 #if defined(PETSC_HAVE_ELEMENTAL)
4229 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat, MatType, MatReuse, Mat *);
4230 #endif
4231 #if defined(PETSC_HAVE_SCALAPACK)
4232 PETSC_INTERN PetscErrorCode MatConvert_AIJ_ScaLAPACK(Mat, MatType, MatReuse, Mat *);
4233 #endif
4234 #if defined(PETSC_HAVE_HYPRE)
4235 PETSC_INTERN PetscErrorCode MatConvert_AIJ_HYPRE(Mat A, MatType, MatReuse, Mat *);
4236 #endif
4237 
4238 PETSC_EXTERN PetscErrorCode MatConvert_SeqAIJ_SeqSELL(Mat, MatType, MatReuse, Mat *);
4239 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat, MatType, MatReuse, Mat *);
4240 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat);
4241 
4242 /*@C
4243    MatSeqAIJGetArray - gives read/write access to the array where the data for a `MATSEQAIJ` matrix is stored
4244 
4245    Not Collective
4246 
4247    Input Parameter:
4248 .  mat - a `MATSEQAIJ` matrix
4249 
4250    Output Parameter:
4251 .   array - pointer to the data
4252 
4253    Level: intermediate
4254 
4255 .seealso: `MatSeqAIJRestoreArray()`, `MatSeqAIJGetArrayF90()`
4256 @*/
4257 PetscErrorCode MatSeqAIJGetArray(Mat A, PetscScalar **array) {
4258   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4259 
4260   PetscFunctionBegin;
4261   if (aij->ops->getarray) {
4262     PetscCall((*aij->ops->getarray)(A, array));
4263   } else {
4264     *array = aij->a;
4265   }
4266   PetscFunctionReturn(0);
4267 }
4268 
4269 /*@C
4270    MatSeqAIJRestoreArray - returns access to the array where the data for a `MATSEQAIJ` matrix is stored obtained by `MatSeqAIJGetArray()`
4271 
4272    Not Collective
4273 
4274    Input Parameters:
4275 +  mat - a `MATSEQAIJ` matrix
4276 -  array - pointer to the data
4277 
4278    Level: intermediate
4279 
4280 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayF90()`
4281 @*/
4282 PetscErrorCode MatSeqAIJRestoreArray(Mat A, PetscScalar **array) {
4283   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4284 
4285   PetscFunctionBegin;
4286   if (aij->ops->restorearray) {
4287     PetscCall((*aij->ops->restorearray)(A, array));
4288   } else {
4289     *array = NULL;
4290   }
4291   PetscCall(MatSeqAIJInvalidateDiagonal(A));
4292   PetscCall(PetscObjectStateIncrease((PetscObject)A));
4293   PetscFunctionReturn(0);
4294 }
4295 
4296 /*@C
4297    MatSeqAIJGetArrayRead - gives read-only access to the array where the data for a `MATSEQAIJ` matrix is stored
4298 
4299    Not Collective
4300 
4301    Input Parameter:
4302 .  mat - a `MATSEQAIJ` matrix
4303 
4304    Output Parameter:
4305 .   array - pointer to the data
4306 
4307    Level: intermediate
4308 
4309 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()`
4310 @*/
4311 PetscErrorCode MatSeqAIJGetArrayRead(Mat A, const PetscScalar **array) {
4312   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4313 
4314   PetscFunctionBegin;
4315   if (aij->ops->getarrayread) {
4316     PetscCall((*aij->ops->getarrayread)(A, array));
4317   } else {
4318     *array = aij->a;
4319   }
4320   PetscFunctionReturn(0);
4321 }
4322 
4323 /*@C
4324    MatSeqAIJRestoreArrayRead - restore the read-only access array obtained from `MatSeqAIJGetArrayRead()`
4325 
4326    Not Collective
4327 
4328    Input Parameter:
4329 .  mat - a `MATSEQAIJ` matrix
4330 
4331    Output Parameter:
4332 .   array - pointer to the data
4333 
4334    Level: intermediate
4335 
4336 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()`
4337 @*/
4338 PetscErrorCode MatSeqAIJRestoreArrayRead(Mat A, const PetscScalar **array) {
4339   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4340 
4341   PetscFunctionBegin;
4342   if (aij->ops->restorearrayread) {
4343     PetscCall((*aij->ops->restorearrayread)(A, array));
4344   } else {
4345     *array = NULL;
4346   }
4347   PetscFunctionReturn(0);
4348 }
4349 
4350 /*@C
4351    MatSeqAIJGetArrayWrite - gives write-only access to the array where the data for a `MATSEQAIJ` matrix is stored
4352 
4353    Not Collective
4354 
4355    Input Parameter:
4356 .  mat - a `MATSEQAIJ` matrix
4357 
4358    Output Parameter:
4359 .   array - pointer to the data
4360 
4361    Level: intermediate
4362 
4363 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArrayRead()`
4364 @*/
4365 PetscErrorCode MatSeqAIJGetArrayWrite(Mat A, PetscScalar **array) {
4366   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4367 
4368   PetscFunctionBegin;
4369   if (aij->ops->getarraywrite) {
4370     PetscCall((*aij->ops->getarraywrite)(A, array));
4371   } else {
4372     *array = aij->a;
4373   }
4374   PetscCall(MatSeqAIJInvalidateDiagonal(A));
4375   PetscCall(PetscObjectStateIncrease((PetscObject)A));
4376   PetscFunctionReturn(0);
4377 }
4378 
4379 /*@C
4380    MatSeqAIJRestoreArrayWrite - restore the read-only access array obtained from MatSeqAIJGetArrayRead
4381 
4382    Not Collective
4383 
4384    Input Parameter:
4385 .  mat - a MATSEQAIJ matrix
4386 
4387    Output Parameter:
4388 .   array - pointer to the data
4389 
4390    Level: intermediate
4391 
4392 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()`
4393 @*/
4394 PetscErrorCode MatSeqAIJRestoreArrayWrite(Mat A, PetscScalar **array) {
4395   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4396 
4397   PetscFunctionBegin;
4398   if (aij->ops->restorearraywrite) {
4399     PetscCall((*aij->ops->restorearraywrite)(A, array));
4400   } else {
4401     *array = NULL;
4402   }
4403   PetscFunctionReturn(0);
4404 }
4405 
4406 /*@C
4407    MatSeqAIJGetCSRAndMemType - Get the CSR arrays and the memory type of the `MATSEQAIJ` matrix
4408 
4409    Not Collective
4410 
4411    Input Parameter:
4412 .  mat - a matrix of type `MATSEQAIJ` or its subclasses
4413 
4414    Output Parameters:
4415 +  i - row map array of the matrix
4416 .  j - column index array of the matrix
4417 .  a - data array of the matrix
4418 -  memtype - memory type of the arrays
4419 
4420   Notes:
4421    Any of the output parameters can be NULL, in which case the corresponding value is not returned.
4422    If mat is a device matrix, the arrays are on the device. Otherwise, they are on the host.
4423 
4424    One can call this routine on a preallocated but not assembled matrix to just get the memory of the CSR underneath the matrix.
4425    If the matrix is assembled, the data array 'a' is guaranteed to have the latest values of the matrix.
4426 
4427    Level: Developer
4428 
4429 .seealso: `MatSeqAIJGetArray()`, `MatSeqAIJGetArrayRead()`
4430 @*/
4431 PetscErrorCode MatSeqAIJGetCSRAndMemType(Mat mat, const PetscInt **i, const PetscInt **j, PetscScalar **a, PetscMemType *mtype) {
4432   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data;
4433 
4434   PetscFunctionBegin;
4435   PetscCheck(mat->preallocated, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "matrix is not preallocated");
4436   if (aij->ops->getcsrandmemtype) {
4437     PetscCall((*aij->ops->getcsrandmemtype)(mat, i, j, a, mtype));
4438   } else {
4439     if (i) *i = aij->i;
4440     if (j) *j = aij->j;
4441     if (a) *a = aij->a;
4442     if (mtype) *mtype = PETSC_MEMTYPE_HOST;
4443   }
4444   PetscFunctionReturn(0);
4445 }
4446 
4447 /*@C
4448    MatSeqAIJGetMaxRowNonzeros - returns the maximum number of nonzeros in any row
4449 
4450    Not Collective
4451 
4452    Input Parameter:
4453 .  mat - a `MATSEQAIJ` matrix
4454 
4455    Output Parameter:
4456 .   nz - the maximum number of nonzeros in any row
4457 
4458    Level: intermediate
4459 
4460 .seealso: `MatSeqAIJRestoreArray()`, `MatSeqAIJGetArrayF90()`
4461 @*/
4462 PetscErrorCode MatSeqAIJGetMaxRowNonzeros(Mat A, PetscInt *nz) {
4463   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)A->data;
4464 
4465   PetscFunctionBegin;
4466   *nz = aij->rmax;
4467   PetscFunctionReturn(0);
4468 }
4469 
4470 PetscErrorCode MatSetPreallocationCOO_SeqAIJ(Mat mat, PetscCount coo_n, PetscInt coo_i[], PetscInt coo_j[]) {
4471   MPI_Comm     comm;
4472   PetscInt    *i, *j;
4473   PetscInt     M, N, row;
4474   PetscCount   k, p, q, nneg, nnz, start, end; /* Index the coo array, so use PetscCount as their type */
4475   PetscInt    *Ai;                             /* Change to PetscCount once we use it for row pointers */
4476   PetscInt    *Aj;
4477   PetscScalar *Aa;
4478   Mat_SeqAIJ  *seqaij = (Mat_SeqAIJ *)(mat->data);
4479   MatType      rtype;
4480   PetscCount  *perm, *jmap;
4481 
4482   PetscFunctionBegin;
4483   PetscCall(MatResetPreallocationCOO_SeqAIJ(mat));
4484   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
4485   PetscCall(MatGetSize(mat, &M, &N));
4486   i = coo_i;
4487   j = coo_j;
4488   PetscCall(PetscMalloc1(coo_n, &perm));
4489   for (k = 0; k < coo_n; k++) { /* Ignore entries with negative row or col indices */
4490     if (j[k] < 0) i[k] = -1;
4491     perm[k] = k;
4492   }
4493 
4494   /* Sort by row */
4495   PetscCall(PetscSortIntWithIntCountArrayPair(coo_n, i, j, perm));
4496   for (k = 0; k < coo_n; k++) {
4497     if (i[k] >= 0) break;
4498   } /* Advance k to the first row with a non-negative index */
4499   nneg = k;
4500   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 */
4501   nnz = 0;                                          /* Total number of unique nonzeros to be counted */
4502   jmap++;                                           /* Inc jmap by 1 for convinience */
4503 
4504   PetscCall(PetscCalloc1(M + 1, &Ai));        /* CSR of A */
4505   PetscCall(PetscMalloc1(coo_n - nneg, &Aj)); /* We have at most coo_n-nneg unique nonzeros */
4506 
4507   /* In each row, sort by column, then unique column indices to get row length */
4508   Ai++;  /* Inc by 1 for convinience */
4509   q = 0; /* q-th unique nonzero, with q starting from 0 */
4510   while (k < coo_n) {
4511     row   = i[k];
4512     start = k; /* [start,end) indices for this row */
4513     while (k < coo_n && i[k] == row) k++;
4514     end = k;
4515     PetscCall(PetscSortIntWithCountArray(end - start, j + start, perm + start));
4516     /* Find number of unique col entries in this row */
4517     Aj[q]   = j[start]; /* Log the first nonzero in this row */
4518     jmap[q] = 1;        /* Number of repeats of this nozero entry */
4519     Ai[row] = 1;
4520     nnz++;
4521 
4522     for (p = start + 1; p < end; p++) { /* Scan remaining nonzero in this row */
4523       if (j[p] != j[p - 1]) {           /* Meet a new nonzero */
4524         q++;
4525         jmap[q] = 1;
4526         Aj[q]   = j[p];
4527         Ai[row]++;
4528         nnz++;
4529       } else {
4530         jmap[q]++;
4531       }
4532     }
4533     q++; /* Move to next row and thus next unique nonzero */
4534   }
4535 
4536   Ai--; /* Back to the beginning of Ai[] */
4537   for (k = 0; k < M; k++) Ai[k + 1] += Ai[k];
4538   jmap--; /* Back to the beginning of jmap[] */
4539   jmap[0] = 0;
4540   for (k = 0; k < nnz; k++) jmap[k + 1] += jmap[k];
4541   if (nnz < coo_n - nneg) { /* Realloc with actual number of unique nonzeros */
4542     PetscCount *jmap_new;
4543     PetscInt   *Aj_new;
4544 
4545     PetscCall(PetscMalloc1(nnz + 1, &jmap_new));
4546     PetscCall(PetscArraycpy(jmap_new, jmap, nnz + 1));
4547     PetscCall(PetscFree(jmap));
4548     jmap = jmap_new;
4549 
4550     PetscCall(PetscMalloc1(nnz, &Aj_new));
4551     PetscCall(PetscArraycpy(Aj_new, Aj, nnz));
4552     PetscCall(PetscFree(Aj));
4553     Aj = Aj_new;
4554   }
4555 
4556   if (nneg) { /* Discard heading entries with negative indices in perm[], as we'll access it from index 0 in MatSetValuesCOO */
4557     PetscCount *perm_new;
4558 
4559     PetscCall(PetscMalloc1(coo_n - nneg, &perm_new));
4560     PetscCall(PetscArraycpy(perm_new, perm + nneg, coo_n - nneg));
4561     PetscCall(PetscFree(perm));
4562     perm = perm_new;
4563   }
4564 
4565   PetscCall(MatGetRootType_Private(mat, &rtype));
4566   PetscCall(PetscCalloc1(nnz, &Aa)); /* Zero the matrix */
4567   PetscCall(MatSetSeqAIJWithArrays_private(PETSC_COMM_SELF, M, N, Ai, Aj, Aa, rtype, mat));
4568 
4569   seqaij->singlemalloc = PETSC_FALSE;            /* Ai, Aj and Aa are not allocated in one big malloc */
4570   seqaij->free_a = seqaij->free_ij = PETSC_TRUE; /* Let newmat own Ai, Aj and Aa */
4571   /* Record COO fields */
4572   seqaij->coo_n                    = coo_n;
4573   seqaij->Atot                     = coo_n - nneg; /* Annz is seqaij->nz, so no need to record that again */
4574   seqaij->jmap                     = jmap;         /* of length nnz+1 */
4575   seqaij->perm                     = perm;
4576   PetscFunctionReturn(0);
4577 }
4578 
4579 static PetscErrorCode MatSetValuesCOO_SeqAIJ(Mat A, const PetscScalar v[], InsertMode imode) {
4580   Mat_SeqAIJ  *aseq = (Mat_SeqAIJ *)A->data;
4581   PetscCount   i, j, Annz = aseq->nz;
4582   PetscCount  *perm = aseq->perm, *jmap = aseq->jmap;
4583   PetscScalar *Aa;
4584 
4585   PetscFunctionBegin;
4586   PetscCall(MatSeqAIJGetArray(A, &Aa));
4587   for (i = 0; i < Annz; i++) {
4588     PetscScalar sum = 0.0;
4589     for (j = jmap[i]; j < jmap[i + 1]; j++) sum += v[perm[j]];
4590     Aa[i] = (imode == INSERT_VALUES ? 0.0 : Aa[i]) + sum;
4591   }
4592   PetscCall(MatSeqAIJRestoreArray(A, &Aa));
4593   PetscFunctionReturn(0);
4594 }
4595 
4596 #if defined(PETSC_HAVE_CUDA)
4597 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJCUSPARSE(Mat, MatType, MatReuse, Mat *);
4598 #endif
4599 #if defined(PETSC_HAVE_KOKKOS_KERNELS)
4600 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_SeqAIJKokkos(Mat, MatType, MatReuse, Mat *);
4601 #endif
4602 
4603 PETSC_EXTERN PetscErrorCode MatCreate_SeqAIJ(Mat B) {
4604   Mat_SeqAIJ *b;
4605   PetscMPIInt size;
4606 
4607   PetscFunctionBegin;
4608   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size));
4609   PetscCheck(size <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Comm must be of size 1");
4610 
4611   PetscCall(PetscNewLog(B, &b));
4612 
4613   B->data = (void *)b;
4614 
4615   PetscCall(PetscMemcpy(B->ops, &MatOps_Values, sizeof(struct _MatOps)));
4616   if (B->sortedfull) B->ops->setvalues = MatSetValues_SeqAIJ_SortedFull;
4617 
4618   b->row                = NULL;
4619   b->col                = NULL;
4620   b->icol               = NULL;
4621   b->reallocs           = 0;
4622   b->ignorezeroentries  = PETSC_FALSE;
4623   b->roworiented        = PETSC_TRUE;
4624   b->nonew              = 0;
4625   b->diag               = NULL;
4626   b->solve_work         = NULL;
4627   B->spptr              = NULL;
4628   b->saved_values       = NULL;
4629   b->idiag              = NULL;
4630   b->mdiag              = NULL;
4631   b->ssor_work          = NULL;
4632   b->omega              = 1.0;
4633   b->fshift             = 0.0;
4634   b->idiagvalid         = PETSC_FALSE;
4635   b->ibdiagvalid        = PETSC_FALSE;
4636   b->keepnonzeropattern = PETSC_FALSE;
4637 
4638   PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ));
4639 #if defined(PETSC_HAVE_MATLAB_ENGINE)
4640   PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEnginePut_C", MatlabEnginePut_SeqAIJ));
4641   PetscCall(PetscObjectComposeFunction((PetscObject)B, "PetscMatlabEngineGet_C", MatlabEngineGet_SeqAIJ));
4642 #endif
4643   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetColumnIndices_C", MatSeqAIJSetColumnIndices_SeqAIJ));
4644   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_SeqAIJ));
4645   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_SeqAIJ));
4646   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsbaij_C", MatConvert_SeqAIJ_SeqSBAIJ));
4647   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqbaij_C", MatConvert_SeqAIJ_SeqBAIJ));
4648   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijperm_C", MatConvert_SeqAIJ_SeqAIJPERM));
4649   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijsell_C", MatConvert_SeqAIJ_SeqAIJSELL));
4650 #if defined(PETSC_HAVE_MKL_SPARSE)
4651   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijmkl_C", MatConvert_SeqAIJ_SeqAIJMKL));
4652 #endif
4653 #if defined(PETSC_HAVE_CUDA)
4654   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcusparse_C", MatConvert_SeqAIJ_SeqAIJCUSPARSE));
4655   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaijcusparse_seqaij_C", MatProductSetFromOptions_SeqAIJ));
4656   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaijcusparse_C", MatProductSetFromOptions_SeqAIJ));
4657 #endif
4658 #if defined(PETSC_HAVE_KOKKOS_KERNELS)
4659   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijkokkos_C", MatConvert_SeqAIJ_SeqAIJKokkos));
4660 #endif
4661   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqaijcrl_C", MatConvert_SeqAIJ_SeqAIJCRL));
4662 #if defined(PETSC_HAVE_ELEMENTAL)
4663   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_elemental_C", MatConvert_SeqAIJ_Elemental));
4664 #endif
4665 #if defined(PETSC_HAVE_SCALAPACK)
4666   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_scalapack_C", MatConvert_AIJ_ScaLAPACK));
4667 #endif
4668 #if defined(PETSC_HAVE_HYPRE)
4669   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_hypre_C", MatConvert_AIJ_HYPRE));
4670   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_transpose_seqaij_seqaij_C", MatProductSetFromOptions_Transpose_AIJ_AIJ));
4671 #endif
4672   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqdense_C", MatConvert_SeqAIJ_SeqDense));
4673   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_seqsell_C", MatConvert_SeqAIJ_SeqSELL));
4674   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_seqaij_is_C", MatConvert_XAIJ_IS));
4675   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_SeqAIJ));
4676   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsHermitianTranspose_C", MatIsTranspose_SeqAIJ));
4677   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocation_C", MatSeqAIJSetPreallocation_SeqAIJ));
4678   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatResetPreallocation_C", MatResetPreallocation_SeqAIJ));
4679   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJSetPreallocationCSR_C", MatSeqAIJSetPreallocationCSR_SeqAIJ));
4680   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatReorderForNonzeroDiagonal_C", MatReorderForNonzeroDiagonal_SeqAIJ));
4681   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_is_seqaij_C", MatProductSetFromOptions_IS_XAIJ));
4682   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqdense_seqaij_C", MatProductSetFromOptions_SeqDense_SeqAIJ));
4683   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatProductSetFromOptions_seqaij_seqaij_C", MatProductSetFromOptions_SeqAIJ));
4684   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSeqAIJKron_C", MatSeqAIJKron_SeqAIJ));
4685   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_SeqAIJ));
4686   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatSetValuesCOO_C", MatSetValuesCOO_SeqAIJ));
4687   PetscCall(MatCreate_SeqAIJ_Inode(B));
4688   PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATSEQAIJ));
4689   PetscCall(MatSeqAIJSetTypeFromOptions(B)); /* this allows changing the matrix subtype to say MATSEQAIJPERM */
4690   PetscFunctionReturn(0);
4691 }
4692 
4693 /*
4694     Given a matrix generated with MatGetFactor() duplicates all the information in A into C
4695 */
4696 PetscErrorCode MatDuplicateNoCreate_SeqAIJ(Mat C, Mat A, MatDuplicateOption cpvalues, PetscBool mallocmatspace) {
4697   Mat_SeqAIJ *c = (Mat_SeqAIJ *)C->data, *a = (Mat_SeqAIJ *)A->data;
4698   PetscInt    m = A->rmap->n, i;
4699 
4700   PetscFunctionBegin;
4701   PetscCheck(A->assembled || cpvalues == MAT_DO_NOT_COPY_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot duplicate unassembled matrix");
4702 
4703   C->factortype = A->factortype;
4704   c->row        = NULL;
4705   c->col        = NULL;
4706   c->icol       = NULL;
4707   c->reallocs   = 0;
4708 
4709   C->assembled    = A->assembled;
4710   C->preallocated = A->preallocated;
4711 
4712   if (A->preallocated) {
4713     PetscCall(PetscLayoutReference(A->rmap, &C->rmap));
4714     PetscCall(PetscLayoutReference(A->cmap, &C->cmap));
4715 
4716     PetscCall(PetscMalloc1(m, &c->imax));
4717     PetscCall(PetscMemcpy(c->imax, a->imax, m * sizeof(PetscInt)));
4718     PetscCall(PetscMalloc1(m, &c->ilen));
4719     PetscCall(PetscMemcpy(c->ilen, a->ilen, m * sizeof(PetscInt)));
4720     PetscCall(PetscLogObjectMemory((PetscObject)C, 2 * m * sizeof(PetscInt)));
4721 
4722     /* allocate the matrix space */
4723     if (mallocmatspace) {
4724       PetscCall(PetscMalloc3(a->i[m], &c->a, a->i[m], &c->j, m + 1, &c->i));
4725       PetscCall(PetscLogObjectMemory((PetscObject)C, a->i[m] * (sizeof(PetscScalar) + sizeof(PetscInt)) + (m + 1) * sizeof(PetscInt)));
4726 
4727       c->singlemalloc = PETSC_TRUE;
4728 
4729       PetscCall(PetscArraycpy(c->i, a->i, m + 1));
4730       if (m > 0) {
4731         PetscCall(PetscArraycpy(c->j, a->j, a->i[m]));
4732         if (cpvalues == MAT_COPY_VALUES) {
4733           const PetscScalar *aa;
4734 
4735           PetscCall(MatSeqAIJGetArrayRead(A, &aa));
4736           PetscCall(PetscArraycpy(c->a, aa, a->i[m]));
4737           PetscCall(MatSeqAIJGetArrayRead(A, &aa));
4738         } else {
4739           PetscCall(PetscArrayzero(c->a, a->i[m]));
4740         }
4741       }
4742     }
4743 
4744     c->ignorezeroentries = a->ignorezeroentries;
4745     c->roworiented       = a->roworiented;
4746     c->nonew             = a->nonew;
4747     if (a->diag) {
4748       PetscCall(PetscMalloc1(m + 1, &c->diag));
4749       PetscCall(PetscMemcpy(c->diag, a->diag, m * sizeof(PetscInt)));
4750       PetscCall(PetscLogObjectMemory((PetscObject)C, (m + 1) * sizeof(PetscInt)));
4751     } else c->diag = NULL;
4752 
4753     c->solve_work         = NULL;
4754     c->saved_values       = NULL;
4755     c->idiag              = NULL;
4756     c->ssor_work          = NULL;
4757     c->keepnonzeropattern = a->keepnonzeropattern;
4758     c->free_a             = PETSC_TRUE;
4759     c->free_ij            = PETSC_TRUE;
4760 
4761     c->rmax  = a->rmax;
4762     c->nz    = a->nz;
4763     c->maxnz = a->nz; /* Since we allocate exactly the right amount */
4764 
4765     c->compressedrow.use   = a->compressedrow.use;
4766     c->compressedrow.nrows = a->compressedrow.nrows;
4767     if (a->compressedrow.use) {
4768       i = a->compressedrow.nrows;
4769       PetscCall(PetscMalloc2(i + 1, &c->compressedrow.i, i, &c->compressedrow.rindex));
4770       PetscCall(PetscArraycpy(c->compressedrow.i, a->compressedrow.i, i + 1));
4771       PetscCall(PetscArraycpy(c->compressedrow.rindex, a->compressedrow.rindex, i));
4772     } else {
4773       c->compressedrow.use    = PETSC_FALSE;
4774       c->compressedrow.i      = NULL;
4775       c->compressedrow.rindex = NULL;
4776     }
4777     c->nonzerorowcnt = a->nonzerorowcnt;
4778     C->nonzerostate  = A->nonzerostate;
4779 
4780     PetscCall(MatDuplicate_SeqAIJ_Inode(A, cpvalues, &C));
4781   }
4782   PetscCall(PetscFunctionListDuplicate(((PetscObject)A)->qlist, &((PetscObject)C)->qlist));
4783   PetscFunctionReturn(0);
4784 }
4785 
4786 PetscErrorCode MatDuplicate_SeqAIJ(Mat A, MatDuplicateOption cpvalues, Mat *B) {
4787   PetscFunctionBegin;
4788   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B));
4789   PetscCall(MatSetSizes(*B, A->rmap->n, A->cmap->n, A->rmap->n, A->cmap->n));
4790   if (!(A->rmap->n % A->rmap->bs) && !(A->cmap->n % A->cmap->bs)) PetscCall(MatSetBlockSizesFromMats(*B, A, A));
4791   PetscCall(MatSetType(*B, ((PetscObject)A)->type_name));
4792   PetscCall(MatDuplicateNoCreate_SeqAIJ(*B, A, cpvalues, PETSC_TRUE));
4793   PetscFunctionReturn(0);
4794 }
4795 
4796 PetscErrorCode MatLoad_SeqAIJ(Mat newMat, PetscViewer viewer) {
4797   PetscBool isbinary, ishdf5;
4798 
4799   PetscFunctionBegin;
4800   PetscValidHeaderSpecific(newMat, MAT_CLASSID, 1);
4801   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
4802   /* force binary viewer to load .info file if it has not yet done so */
4803   PetscCall(PetscViewerSetUp(viewer));
4804   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
4805   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
4806   if (isbinary) {
4807     PetscCall(MatLoad_SeqAIJ_Binary(newMat, viewer));
4808   } else if (ishdf5) {
4809 #if defined(PETSC_HAVE_HDF5)
4810     PetscCall(MatLoad_AIJ_HDF5(newMat, viewer));
4811 #else
4812     SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
4813 #endif
4814   } else {
4815     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);
4816   }
4817   PetscFunctionReturn(0);
4818 }
4819 
4820 PetscErrorCode MatLoad_SeqAIJ_Binary(Mat mat, PetscViewer viewer) {
4821   Mat_SeqAIJ *a = (Mat_SeqAIJ *)mat->data;
4822   PetscInt    header[4], *rowlens, M, N, nz, sum, rows, cols, i;
4823 
4824   PetscFunctionBegin;
4825   PetscCall(PetscViewerSetUp(viewer));
4826 
4827   /* read in matrix header */
4828   PetscCall(PetscViewerBinaryRead(viewer, header, 4, NULL, PETSC_INT));
4829   PetscCheck(header[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix object in file");
4830   M  = header[1];
4831   N  = header[2];
4832   nz = header[3];
4833   PetscCheck(M >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix row size (%" PetscInt_FMT ") in file is negative", M);
4834   PetscCheck(N >= 0, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_UNEXPECTED, "Matrix column size (%" PetscInt_FMT ") in file is negative", N);
4835   PetscCheck(nz >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Matrix stored in special format on disk, cannot load as SeqAIJ");
4836 
4837   /* set block sizes from the viewer's .info file */
4838   PetscCall(MatLoad_Binary_BlockSizes(mat, viewer));
4839   /* set local and global sizes if not set already */
4840   if (mat->rmap->n < 0) mat->rmap->n = M;
4841   if (mat->cmap->n < 0) mat->cmap->n = N;
4842   if (mat->rmap->N < 0) mat->rmap->N = M;
4843   if (mat->cmap->N < 0) mat->cmap->N = N;
4844   PetscCall(PetscLayoutSetUp(mat->rmap));
4845   PetscCall(PetscLayoutSetUp(mat->cmap));
4846 
4847   /* check if the matrix sizes are correct */
4848   PetscCall(MatGetSize(mat, &rows, &cols));
4849   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);
4850 
4851   /* read in row lengths */
4852   PetscCall(PetscMalloc1(M, &rowlens));
4853   PetscCall(PetscViewerBinaryRead(viewer, rowlens, M, NULL, PETSC_INT));
4854   /* check if sum(rowlens) is same as nz */
4855   sum = 0;
4856   for (i = 0; i < M; i++) sum += rowlens[i];
4857   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);
4858   /* preallocate and check sizes */
4859   PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(mat, 0, rowlens));
4860   PetscCall(MatGetSize(mat, &rows, &cols));
4861   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);
4862   /* store row lengths */
4863   PetscCall(PetscArraycpy(a->ilen, rowlens, M));
4864   PetscCall(PetscFree(rowlens));
4865 
4866   /* fill in "i" row pointers */
4867   a->i[0] = 0;
4868   for (i = 0; i < M; i++) a->i[i + 1] = a->i[i] + a->ilen[i];
4869   /* read in "j" column indices */
4870   PetscCall(PetscViewerBinaryRead(viewer, a->j, nz, NULL, PETSC_INT));
4871   /* read in "a" nonzero values */
4872   PetscCall(PetscViewerBinaryRead(viewer, a->a, nz, NULL, PETSC_SCALAR));
4873 
4874   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
4875   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
4876   PetscFunctionReturn(0);
4877 }
4878 
4879 PetscErrorCode MatEqual_SeqAIJ(Mat A, Mat B, PetscBool *flg) {
4880   Mat_SeqAIJ        *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data;
4881   const PetscScalar *aa, *ba;
4882 #if defined(PETSC_USE_COMPLEX)
4883   PetscInt k;
4884 #endif
4885 
4886   PetscFunctionBegin;
4887   /* If the  matrix dimensions are not equal,or no of nonzeros */
4888   if ((A->rmap->n != B->rmap->n) || (A->cmap->n != B->cmap->n) || (a->nz != b->nz)) {
4889     *flg = PETSC_FALSE;
4890     PetscFunctionReturn(0);
4891   }
4892 
4893   /* if the a->i are the same */
4894   PetscCall(PetscArraycmp(a->i, b->i, A->rmap->n + 1, flg));
4895   if (!*flg) PetscFunctionReturn(0);
4896 
4897   /* if a->j are the same */
4898   PetscCall(PetscArraycmp(a->j, b->j, a->nz, flg));
4899   if (!*flg) PetscFunctionReturn(0);
4900 
4901   PetscCall(MatSeqAIJGetArrayRead(A, &aa));
4902   PetscCall(MatSeqAIJGetArrayRead(B, &ba));
4903   /* if a->a are the same */
4904 #if defined(PETSC_USE_COMPLEX)
4905   for (k = 0; k < a->nz; k++) {
4906     if (PetscRealPart(aa[k]) != PetscRealPart(ba[k]) || PetscImaginaryPart(aa[k]) != PetscImaginaryPart(ba[k])) {
4907       *flg = PETSC_FALSE;
4908       PetscFunctionReturn(0);
4909     }
4910   }
4911 #else
4912   PetscCall(PetscArraycmp(aa, ba, a->nz, flg));
4913 #endif
4914   PetscCall(MatSeqAIJRestoreArrayRead(A, &aa));
4915   PetscCall(MatSeqAIJRestoreArrayRead(B, &ba));
4916   PetscFunctionReturn(0);
4917 }
4918 
4919 /*@
4920      MatCreateSeqAIJWithArrays - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in CSR format)
4921               provided by the user.
4922 
4923       Collective
4924 
4925    Input Parameters:
4926 +   comm - must be an MPI communicator of size 1
4927 .   m - number of rows
4928 .   n - number of columns
4929 .   i - row indices; that is i[0] = 0, i[row] = i[row-1] + number of elements in that row of the matrix
4930 .   j - column indices
4931 -   a - matrix values
4932 
4933    Output Parameter:
4934 .   mat - the matrix
4935 
4936    Level: intermediate
4937 
4938    Notes:
4939        The i, j, and a arrays are not copied by this routine, the user must free these arrays
4940     once the matrix is destroyed and not before
4941 
4942        You cannot set new nonzero locations into this matrix, that will generate an error.
4943 
4944        The i and j indices are 0 based
4945 
4946        The format which is used for the sparse matrix input, is equivalent to a
4947     row-major ordering.. i.e for the following matrix, the input data expected is
4948     as shown
4949 
4950 $        1 0 0
4951 $        2 0 3
4952 $        4 5 6
4953 $
4954 $        i =  {0,1,3,6}  [size = nrow+1  = 3+1]
4955 $        j =  {0,0,2,0,1,2}  [size = 6]; values must be sorted for each row
4956 $        v =  {1,2,3,4,5,6}  [size = 6]
4957 
4958 .seealso: `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateMPIAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()`
4959 @*/
4960 PetscErrorCode MatCreateSeqAIJWithArrays(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat) {
4961   PetscInt    ii;
4962   Mat_SeqAIJ *aij;
4963   PetscInt    jj;
4964 
4965   PetscFunctionBegin;
4966   PetscCheck(m <= 0 || i[0] == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "i (row indices) must start with 0");
4967   PetscCall(MatCreate(comm, mat));
4968   PetscCall(MatSetSizes(*mat, m, n, m, n));
4969   /* PetscCall(MatSetBlockSizes(*mat,,)); */
4970   PetscCall(MatSetType(*mat, MATSEQAIJ));
4971   PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, MAT_SKIP_ALLOCATION, NULL));
4972   aij = (Mat_SeqAIJ *)(*mat)->data;
4973   PetscCall(PetscMalloc1(m, &aij->imax));
4974   PetscCall(PetscMalloc1(m, &aij->ilen));
4975 
4976   aij->i            = i;
4977   aij->j            = j;
4978   aij->a            = a;
4979   aij->singlemalloc = PETSC_FALSE;
4980   aij->nonew        = -1; /*this indicates that inserting a new value in the matrix that generates a new nonzero is an error*/
4981   aij->free_a       = PETSC_FALSE;
4982   aij->free_ij      = PETSC_FALSE;
4983 
4984   for (ii = 0, aij->nonzerorowcnt = 0, aij->rmax = 0; ii < m; ii++) {
4985     aij->ilen[ii] = aij->imax[ii] = i[ii + 1] - i[ii];
4986     if (PetscDefined(USE_DEBUG)) {
4987       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]);
4988       for (jj = i[ii] + 1; jj < i[ii + 1]; jj++) {
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 not sorted", jj - i[ii], j[jj], ii);
4990         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);
4991       }
4992     }
4993   }
4994   if (PetscDefined(USE_DEBUG)) {
4995     for (ii = 0; ii < aij->i[m]; ii++) {
4996       PetscCheck(j[ii] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative column index at location = %" PetscInt_FMT " index = %" PetscInt_FMT, ii, j[ii]);
4997       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]);
4998     }
4999   }
5000 
5001   PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY));
5002   PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY));
5003   PetscFunctionReturn(0);
5004 }
5005 
5006 /*@
5007      MatCreateSeqAIJFromTriple - Creates an sequential `MATSEQAIJ` matrix using matrix elements (in COO format)
5008               provided by the user.
5009 
5010       Collective
5011 
5012    Input Parameters:
5013 +   comm - must be an MPI communicator of size 1
5014 .   m   - number of rows
5015 .   n   - number of columns
5016 .   i   - row indices
5017 .   j   - column indices
5018 .   a   - matrix values
5019 .   nz  - number of nonzeros
5020 -   idx - if the i and j indices start with 1 use `PETSC_TRUE` otherwise use `PETSC_FALSE`
5021 
5022    Output Parameter:
5023 .   mat - the matrix
5024 
5025    Level: intermediate
5026 
5027    Example:
5028        For the following matrix, the input data expected is as shown (using 0 based indexing)
5029 .vb
5030         1 0 0
5031         2 0 3
5032         4 5 6
5033 
5034         i =  {0,1,1,2,2,2}
5035         j =  {0,0,2,0,1,2}
5036         v =  {1,2,3,4,5,6}
5037 .ve
5038 
5039 .seealso: `MatCreate()`, `MatCreateAIJ()`, `MatCreateSeqAIJ()`, `MatCreateSeqAIJWithArrays()`, `MatMPIAIJSetPreallocationCSR()`, `MatSetValuesCOO()`
5040 @*/
5041 PetscErrorCode MatCreateSeqAIJFromTriple(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt i[], PetscInt j[], PetscScalar a[], Mat *mat, PetscInt nz, PetscBool idx) {
5042   PetscInt ii, *nnz, one = 1, row, col;
5043 
5044   PetscFunctionBegin;
5045   PetscCall(PetscCalloc1(m, &nnz));
5046   for (ii = 0; ii < nz; ii++) nnz[i[ii] - !!idx] += 1;
5047   PetscCall(MatCreate(comm, mat));
5048   PetscCall(MatSetSizes(*mat, m, n, m, n));
5049   PetscCall(MatSetType(*mat, MATSEQAIJ));
5050   PetscCall(MatSeqAIJSetPreallocation_SeqAIJ(*mat, 0, nnz));
5051   for (ii = 0; ii < nz; ii++) {
5052     if (idx) {
5053       row = i[ii] - 1;
5054       col = j[ii] - 1;
5055     } else {
5056       row = i[ii];
5057       col = j[ii];
5058     }
5059     PetscCall(MatSetValues(*mat, one, &row, one, &col, &a[ii], ADD_VALUES));
5060   }
5061   PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY));
5062   PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY));
5063   PetscCall(PetscFree(nnz));
5064   PetscFunctionReturn(0);
5065 }
5066 
5067 PetscErrorCode MatSeqAIJInvalidateDiagonal(Mat A) {
5068   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data;
5069 
5070   PetscFunctionBegin;
5071   a->idiagvalid  = PETSC_FALSE;
5072   a->ibdiagvalid = PETSC_FALSE;
5073 
5074   PetscCall(MatSeqAIJInvalidateDiagonal_Inode(A));
5075   PetscFunctionReturn(0);
5076 }
5077 
5078 PetscErrorCode MatCreateMPIMatConcatenateSeqMat_SeqAIJ(MPI_Comm comm, Mat inmat, PetscInt n, MatReuse scall, Mat *outmat) {
5079   PetscFunctionBegin;
5080   PetscCall(MatCreateMPIMatConcatenateSeqMat_MPIAIJ(comm, inmat, n, scall, outmat));
5081   PetscFunctionReturn(0);
5082 }
5083 
5084 /*
5085  Permute A into C's *local* index space using rowemb,colemb.
5086  The embedding are supposed to be injections and the above implies that the range of rowemb is a subset
5087  of [0,m), colemb is in [0,n).
5088  If pattern == DIFFERENT_NONZERO_PATTERN, C is preallocated according to A.
5089  */
5090 PetscErrorCode MatSetSeqMat_SeqAIJ(Mat C, IS rowemb, IS colemb, MatStructure pattern, Mat B) {
5091   /* If making this function public, change the error returned in this function away from _PLIB. */
5092   Mat_SeqAIJ     *Baij;
5093   PetscBool       seqaij;
5094   PetscInt        m, n, *nz, i, j, count;
5095   PetscScalar     v;
5096   const PetscInt *rowindices, *colindices;
5097 
5098   PetscFunctionBegin;
5099   if (!B) PetscFunctionReturn(0);
5100   /* Check to make sure the target matrix (and embeddings) are compatible with C and each other. */
5101   PetscCall(PetscObjectBaseTypeCompare((PetscObject)B, MATSEQAIJ, &seqaij));
5102   PetscCheck(seqaij, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is of wrong type");
5103   if (rowemb) {
5104     PetscCall(ISGetLocalSize(rowemb, &m));
5105     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);
5106   } else {
5107     PetscCheck(C->rmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is row-incompatible with the target matrix");
5108   }
5109   if (colemb) {
5110     PetscCall(ISGetLocalSize(colemb, &n));
5111     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);
5112   } else {
5113     PetscCheck(C->cmap->n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Input matrix is col-incompatible with the target matrix");
5114   }
5115 
5116   Baij = (Mat_SeqAIJ *)(B->data);
5117   if (pattern == DIFFERENT_NONZERO_PATTERN) {
5118     PetscCall(PetscMalloc1(B->rmap->n, &nz));
5119     for (i = 0; i < B->rmap->n; i++) nz[i] = Baij->i[i + 1] - Baij->i[i];
5120     PetscCall(MatSeqAIJSetPreallocation(C, 0, nz));
5121     PetscCall(PetscFree(nz));
5122   }
5123   if (pattern == SUBSET_NONZERO_PATTERN) PetscCall(MatZeroEntries(C));
5124   count      = 0;
5125   rowindices = NULL;
5126   colindices = NULL;
5127   if (rowemb) PetscCall(ISGetIndices(rowemb, &rowindices));
5128   if (colemb) PetscCall(ISGetIndices(colemb, &colindices));
5129   for (i = 0; i < B->rmap->n; i++) {
5130     PetscInt row;
5131     row = i;
5132     if (rowindices) row = rowindices[i];
5133     for (j = Baij->i[i]; j < Baij->i[i + 1]; j++) {
5134       PetscInt col;
5135       col = Baij->j[count];
5136       if (colindices) col = colindices[col];
5137       v = Baij->a[count];
5138       PetscCall(MatSetValues(C, 1, &row, 1, &col, &v, INSERT_VALUES));
5139       ++count;
5140     }
5141   }
5142   /* FIXME: set C's nonzerostate correctly. */
5143   /* Assembly for C is necessary. */
5144   C->preallocated  = PETSC_TRUE;
5145   C->assembled     = PETSC_TRUE;
5146   C->was_assembled = PETSC_FALSE;
5147   PetscFunctionReturn(0);
5148 }
5149 
5150 PetscFunctionList MatSeqAIJList = NULL;
5151 
5152 /*@C
5153    MatSeqAIJSetType - Converts a `MATSEQAIJ` matrix to a subtype
5154 
5155    Collective on mat
5156 
5157    Input Parameters:
5158 +  mat      - the matrix object
5159 -  matype   - matrix type
5160 
5161    Options Database Key:
5162 .  -mat_seqai_type  <method> - for example seqaijcrl
5163 
5164   Level: intermediate
5165 
5166 .seealso: `PCSetType()`, `VecSetType()`, `MatCreate()`, `MatType`, `Mat`
5167 @*/
5168 PetscErrorCode MatSeqAIJSetType(Mat mat, MatType matype) {
5169   PetscBool sametype;
5170   PetscErrorCode (*r)(Mat, MatType, MatReuse, Mat *);
5171 
5172   PetscFunctionBegin;
5173   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5174   PetscCall(PetscObjectTypeCompare((PetscObject)mat, matype, &sametype));
5175   if (sametype) PetscFunctionReturn(0);
5176 
5177   PetscCall(PetscFunctionListFind(MatSeqAIJList, matype, &r));
5178   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown Mat type given: %s", matype);
5179   PetscCall((*r)(mat, matype, MAT_INPLACE_MATRIX, &mat));
5180   PetscFunctionReturn(0);
5181 }
5182 
5183 /*@C
5184   MatSeqAIJRegister -  - Adds a new sub-matrix type for sequential `MATSEQAIJ` matrices
5185 
5186    Not Collective
5187 
5188    Input Parameters:
5189 +  name - name of a new user-defined matrix type, for example `MATSEQAIJCRL`
5190 -  function - routine to convert to subtype
5191 
5192    Notes:
5193    `MatSeqAIJRegister()` may be called multiple times to add several user-defined solvers.
5194 
5195    Then, your matrix can be chosen with the procedural interface at runtime via the option
5196 $     -mat_seqaij_type my_mat
5197 
5198    Level: advanced
5199 
5200 .seealso: `MatSeqAIJRegisterAll()`
5201 @*/
5202 PetscErrorCode MatSeqAIJRegister(const char sname[], PetscErrorCode (*function)(Mat, MatType, MatReuse, Mat *)) {
5203   PetscFunctionBegin;
5204   PetscCall(MatInitializePackage());
5205   PetscCall(PetscFunctionListAdd(&MatSeqAIJList, sname, function));
5206   PetscFunctionReturn(0);
5207 }
5208 
5209 PetscBool MatSeqAIJRegisterAllCalled = PETSC_FALSE;
5210 
5211 /*@C
5212   MatSeqAIJRegisterAll - Registers all of the matrix subtypes of `MATSSEQAIJ`
5213 
5214   Not Collective
5215 
5216   Level: advanced
5217 
5218 .seealso: `MatRegisterAll()`, `MatSeqAIJRegister()`
5219 @*/
5220 PetscErrorCode MatSeqAIJRegisterAll(void) {
5221   PetscFunctionBegin;
5222   if (MatSeqAIJRegisterAllCalled) PetscFunctionReturn(0);
5223   MatSeqAIJRegisterAllCalled = PETSC_TRUE;
5224 
5225   PetscCall(MatSeqAIJRegister(MATSEQAIJCRL, MatConvert_SeqAIJ_SeqAIJCRL));
5226   PetscCall(MatSeqAIJRegister(MATSEQAIJPERM, MatConvert_SeqAIJ_SeqAIJPERM));
5227   PetscCall(MatSeqAIJRegister(MATSEQAIJSELL, MatConvert_SeqAIJ_SeqAIJSELL));
5228 #if defined(PETSC_HAVE_MKL_SPARSE)
5229   PetscCall(MatSeqAIJRegister(MATSEQAIJMKL, MatConvert_SeqAIJ_SeqAIJMKL));
5230 #endif
5231 #if defined(PETSC_HAVE_CUDA)
5232   PetscCall(MatSeqAIJRegister(MATSEQAIJCUSPARSE, MatConvert_SeqAIJ_SeqAIJCUSPARSE));
5233 #endif
5234 #if defined(PETSC_HAVE_KOKKOS_KERNELS)
5235   PetscCall(MatSeqAIJRegister(MATSEQAIJKOKKOS, MatConvert_SeqAIJ_SeqAIJKokkos));
5236 #endif
5237 #if defined(PETSC_HAVE_VIENNACL) && defined(PETSC_HAVE_VIENNACL_NO_CUDA)
5238   PetscCall(MatSeqAIJRegister(MATMPIAIJVIENNACL, MatConvert_SeqAIJ_SeqAIJViennaCL));
5239 #endif
5240   PetscFunctionReturn(0);
5241 }
5242 
5243 /*
5244     Special version for direct calls from Fortran
5245 */
5246 #include <petsc/private/fortranimpl.h>
5247 #if defined(PETSC_HAVE_FORTRAN_CAPS)
5248 #define matsetvaluesseqaij_ MATSETVALUESSEQAIJ
5249 #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE)
5250 #define matsetvaluesseqaij_ matsetvaluesseqaij
5251 #endif
5252 
5253 /* Change these macros so can be used in void function */
5254 
5255 /* Change these macros so can be used in void function */
5256 /* Identical to PetscCallVoid, except it assigns to *_ierr */
5257 #undef PetscCall
5258 #define PetscCall(...) \
5259   do { \
5260     PetscErrorCode ierr_msv_mpiaij = __VA_ARGS__; \
5261     if (PetscUnlikely(ierr_msv_mpiaij)) { \
5262       *_ierr = PetscError(PETSC_COMM_SELF, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr_msv_mpiaij, PETSC_ERROR_REPEAT, " "); \
5263       return; \
5264     } \
5265   } while (0)
5266 
5267 #undef SETERRQ
5268 #define SETERRQ(comm, ierr, ...) \
5269   do { \
5270     *_ierr = PetscError(comm, __LINE__, PETSC_FUNCTION_NAME, __FILE__, ierr, PETSC_ERROR_INITIAL, __VA_ARGS__); \
5271     return; \
5272   } while (0)
5273 
5274 PETSC_EXTERN void matsetvaluesseqaij_(Mat *AA, PetscInt *mm, const PetscInt im[], PetscInt *nn, const PetscInt in[], const PetscScalar v[], InsertMode *isis, PetscErrorCode *_ierr) {
5275   Mat         A = *AA;
5276   PetscInt    m = *mm, n = *nn;
5277   InsertMode  is = *isis;
5278   Mat_SeqAIJ *a  = (Mat_SeqAIJ *)A->data;
5279   PetscInt   *rp, k, low, high, t, ii, row, nrow, i, col, l, rmax, N;
5280   PetscInt   *imax, *ai, *ailen;
5281   PetscInt   *aj, nonew = a->nonew, lastcol = -1;
5282   MatScalar  *ap, value, *aa;
5283   PetscBool   ignorezeroentries = a->ignorezeroentries;
5284   PetscBool   roworiented       = a->roworiented;
5285 
5286   PetscFunctionBegin;
5287   MatCheckPreallocated(A, 1);
5288   imax  = a->imax;
5289   ai    = a->i;
5290   ailen = a->ilen;
5291   aj    = a->j;
5292   aa    = a->a;
5293 
5294   for (k = 0; k < m; k++) { /* loop over added rows */
5295     row = im[k];
5296     if (row < 0) continue;
5297     PetscCheck(row < A->rmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large");
5298     rp   = aj + ai[row];
5299     ap   = aa + ai[row];
5300     rmax = imax[row];
5301     nrow = ailen[row];
5302     low  = 0;
5303     high = nrow;
5304     for (l = 0; l < n; l++) { /* loop over added columns */
5305       if (in[l] < 0) continue;
5306       PetscCheck(in[l] < A->cmap->n, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Column too large");
5307       col = in[l];
5308       if (roworiented) value = v[l + k * n];
5309       else value = v[k + l * m];
5310 
5311       if (value == 0.0 && ignorezeroentries && (is == ADD_VALUES)) continue;
5312 
5313       if (col <= lastcol) low = 0;
5314       else high = nrow;
5315       lastcol = col;
5316       while (high - low > 5) {
5317         t = (low + high) / 2;
5318         if (rp[t] > col) high = t;
5319         else low = t;
5320       }
5321       for (i = low; i < high; i++) {
5322         if (rp[i] > col) break;
5323         if (rp[i] == col) {
5324           if (is == ADD_VALUES) ap[i] += value;
5325           else ap[i] = value;
5326           goto noinsert;
5327         }
5328       }
5329       if (value == 0.0 && ignorezeroentries) goto noinsert;
5330       if (nonew == 1) goto noinsert;
5331       PetscCheck(nonew != -1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero in the matrix");
5332       MatSeqXAIJReallocateAIJ(A, A->rmap->n, 1, nrow, row, col, rmax, aa, ai, aj, rp, ap, imax, nonew, MatScalar);
5333       N = nrow++ - 1;
5334       a->nz++;
5335       high++;
5336       /* shift up all the later entries in this row */
5337       for (ii = N; ii >= i; ii--) {
5338         rp[ii + 1] = rp[ii];
5339         ap[ii + 1] = ap[ii];
5340       }
5341       rp[i] = col;
5342       ap[i] = value;
5343       A->nonzerostate++;
5344     noinsert:;
5345       low = i + 1;
5346     }
5347     ailen[row] = nrow;
5348   }
5349   PetscFunctionReturnVoid();
5350 }
5351 /* Undefining these here since they were redefined from their original definition above! No
5352  * other PETSc functions should be defined past this point, as it is impossible to recover the
5353  * original definitions */
5354 #undef PetscCall
5355 #undef SETERRQ
5356