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