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