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