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