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