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