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