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