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