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