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