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