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