1c6db04a5SJed Brown #include <../src/mat/impls/aij/seq/aij.h>
2c6db04a5SJed Brown #include <../src/mat/impls/aij/seq/bas/spbas.h>
3b2f1ab58SBarry Smith
4845006b9SBarry Smith /*MC
52692d6eeSBarry Smith MATSOLVERBAS - Provides ICC(k) with drop tolerance
6845006b9SBarry Smith
711a5261eSBarry Smith Works with `MATAIJ` matrices
8845006b9SBarry Smith
9845006b9SBarry Smith Options Database Keys:
100053dfc8SBarry Smith + -pc_factor_levels <l> - number of levels of fill
110053dfc8SBarry Smith - -pc_factor_drop_tolerance - is not currently hooked up to do anything
12845006b9SBarry Smith
130053dfc8SBarry Smith Level: intermediate
14845006b9SBarry Smith
15845006b9SBarry Smith Contributed by: Bas van 't Hof
16845006b9SBarry Smith
1711a5261eSBarry Smith Note:
1895452b02SPatrick Sanan Since this currently hooked up to use drop tolerance it should produce the same factors and hence convergence as the PETSc ICC, for higher
190053dfc8SBarry Smith levels of fill it does not. This needs to be investigated. Unless you are interested in drop tolerance ICC and willing to work through the code
200053dfc8SBarry Smith we recommend not using this functionality.
210053dfc8SBarry Smith
221cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `PCFactorSetMatSolverType()`, `MatSolverType`, `PCFactorSetLevels()`, `PCFactorSetDropTolerance()`
23845006b9SBarry Smith M*/
249ccc4a9bSBarry Smith
25b2f1ab58SBarry Smith /*
26b2f1ab58SBarry Smith spbas_memory_requirement:
2769d47153SPierre Jolivet Calculate the number of bytes needed to store the matrix
28b2f1ab58SBarry Smith */
spbas_memory_requirement(spbas_matrix matrix)29d71ae5a4SJacob Faibussowitsch size_t spbas_memory_requirement(spbas_matrix matrix)
30d71ae5a4SJacob Faibussowitsch {
313dfa2556SBarry Smith size_t memreq = 6 * sizeof(PetscInt) + /* nrows, ncols, nnz, n_alloc_icol, n_alloc_val, col_idx_type */
32ace3abfcSBarry Smith sizeof(PetscBool) + /* block_data */
33c328eeadSBarry Smith sizeof(PetscScalar **) + /* values */
34c328eeadSBarry Smith sizeof(PetscScalar *) + /* alloc_val */
353dfa2556SBarry Smith 2 * sizeof(PetscInt **) + /* icols, icols0 */
36c328eeadSBarry Smith 2 * sizeof(PetscInt *) + /* row_nnz, alloc_icol */
37c328eeadSBarry Smith matrix.nrows * sizeof(PetscInt) + /* row_nnz[*] */
38c328eeadSBarry Smith matrix.nrows * sizeof(PetscInt *); /* icols[*] */
39b2f1ab58SBarry Smith
40c328eeadSBarry Smith /* icol0[*] */
412205254eSKarl Rupp if (matrix.col_idx_type == SPBAS_OFFSET_ARRAY) memreq += matrix.nrows * sizeof(PetscInt);
42b2f1ab58SBarry Smith
43c328eeadSBarry Smith /* icols[*][*] */
442205254eSKarl Rupp if (matrix.block_data) memreq += matrix.n_alloc_icol * sizeof(PetscInt);
452205254eSKarl Rupp else memreq += matrix.nnz * sizeof(PetscInt);
46b2f1ab58SBarry Smith
474e1ff37aSBarry Smith if (matrix.values) {
48c328eeadSBarry Smith memreq += matrix.nrows * sizeof(PetscScalar *); /* values[*] */
49c328eeadSBarry Smith /* values[*][*] */
502205254eSKarl Rupp if (matrix.block_data) memreq += matrix.n_alloc_val * sizeof(PetscScalar);
512205254eSKarl Rupp else memreq += matrix.nnz * sizeof(PetscScalar);
52b2f1ab58SBarry Smith }
53b2f1ab58SBarry Smith return memreq;
54b2f1ab58SBarry Smith }
55b2f1ab58SBarry Smith
56b2f1ab58SBarry Smith /*
57b2f1ab58SBarry Smith spbas_allocate_pattern:
58b2f1ab58SBarry Smith allocate the pattern arrays row_nnz, icols and optionally values
59b2f1ab58SBarry Smith */
spbas_allocate_pattern(spbas_matrix * result,PetscBool do_values)60*ba38deedSJacob Faibussowitsch static PetscErrorCode spbas_allocate_pattern(spbas_matrix *result, PetscBool do_values)
61d71ae5a4SJacob Faibussowitsch {
62b2f1ab58SBarry Smith PetscInt nrows = result->nrows;
63b2f1ab58SBarry Smith PetscInt col_idx_type = result->col_idx_type;
64b2f1ab58SBarry Smith
65b2f1ab58SBarry Smith PetscFunctionBegin;
66c328eeadSBarry Smith /* Allocate sparseness pattern */
679566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nrows, &result->row_nnz));
689566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nrows, &result->icols));
69b2f1ab58SBarry Smith
70c328eeadSBarry Smith /* If offsets are given wrt an array, create array */
714e1ff37aSBarry Smith if (col_idx_type == SPBAS_OFFSET_ARRAY) {
729566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nrows, &result->icol0));
734e1ff37aSBarry Smith } else {
740298fd71SBarry Smith result->icol0 = NULL;
75b2f1ab58SBarry Smith }
76b2f1ab58SBarry Smith
77c328eeadSBarry Smith /* If values are given, allocate values array */
784e1ff37aSBarry Smith if (do_values) {
799566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nrows, &result->values));
804e1ff37aSBarry Smith } else {
810298fd71SBarry Smith result->values = NULL;
82b2f1ab58SBarry Smith }
833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
84b2f1ab58SBarry Smith }
85b2f1ab58SBarry Smith
86b2f1ab58SBarry Smith /*
87b2f1ab58SBarry Smith spbas_allocate_data:
88b2f1ab58SBarry Smith in case of block_data:
89b2f1ab58SBarry Smith Allocate the data arrays alloc_icol and optionally alloc_val,
90b2f1ab58SBarry Smith set appropriate pointers from icols and values;
91b2f1ab58SBarry Smith in case of !block_data:
92b2f1ab58SBarry Smith Allocate the arrays icols[i] and optionally values[i]
93b2f1ab58SBarry Smith */
spbas_allocate_data(spbas_matrix * result)94*ba38deedSJacob Faibussowitsch static PetscErrorCode spbas_allocate_data(spbas_matrix *result)
95d71ae5a4SJacob Faibussowitsch {
96b2f1ab58SBarry Smith PetscInt i;
97b2f1ab58SBarry Smith PetscInt nnz = result->nnz;
98b2f1ab58SBarry Smith PetscInt nrows = result->nrows;
99b2f1ab58SBarry Smith PetscInt r_nnz;
1006c4ed002SBarry Smith PetscBool do_values = (result->values) ? PETSC_TRUE : PETSC_FALSE;
101ace3abfcSBarry Smith PetscBool block_data = result->block_data;
102b2f1ab58SBarry Smith
103b2f1ab58SBarry Smith PetscFunctionBegin;
1044e1ff37aSBarry Smith if (block_data) {
105c328eeadSBarry Smith /* Allocate the column number array and point to it */
106b2f1ab58SBarry Smith result->n_alloc_icol = nnz;
1072205254eSKarl Rupp
1089566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &result->alloc_icol));
1092205254eSKarl Rupp
110b2f1ab58SBarry Smith result->icols[0] = result->alloc_icol;
111ad540459SPierre Jolivet for (i = 1; i < nrows; i++) result->icols[i] = result->icols[i - 1] + result->row_nnz[i - 1];
112b2f1ab58SBarry Smith
113c328eeadSBarry Smith /* Allocate the value array and point to it */
1144e1ff37aSBarry Smith if (do_values) {
115b2f1ab58SBarry Smith result->n_alloc_val = nnz;
1162205254eSKarl Rupp
1179566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &result->alloc_val));
1182205254eSKarl Rupp
119b2f1ab58SBarry Smith result->values[0] = result->alloc_val;
120ad540459SPierre Jolivet for (i = 1; i < nrows; i++) result->values[i] = result->values[i - 1] + result->row_nnz[i - 1];
121b2f1ab58SBarry Smith }
1224e1ff37aSBarry Smith } else {
1234e1ff37aSBarry Smith for (i = 0; i < nrows; i++) {
124b2f1ab58SBarry Smith r_nnz = result->row_nnz[i];
1259566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(r_nnz, &result->icols[i]));
126b2f1ab58SBarry Smith }
1274e1ff37aSBarry Smith if (do_values) {
1284e1ff37aSBarry Smith for (i = 0; i < nrows; i++) {
129b2f1ab58SBarry Smith r_nnz = result->row_nnz[i];
1309566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(r_nnz, &result->values[i]));
131b2f1ab58SBarry Smith }
132b2f1ab58SBarry Smith }
133b2f1ab58SBarry Smith }
1343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
135b2f1ab58SBarry Smith }
136b2f1ab58SBarry Smith
137b2f1ab58SBarry Smith /*
138b2f1ab58SBarry Smith spbas_row_order_icol
139b2f1ab58SBarry Smith determine if row i1 should come
140b2f1ab58SBarry Smith + before row i2 in the sorted rows (return -1),
141b2f1ab58SBarry Smith + after (return 1)
142b2f1ab58SBarry Smith + is identical (return 0).
143b2f1ab58SBarry Smith */
spbas_row_order_icol(PetscInt i1,PetscInt i2,PetscInt * irow_in,PetscInt * icol_in,PetscInt col_idx_type)144*ba38deedSJacob Faibussowitsch static int spbas_row_order_icol(PetscInt i1, PetscInt i2, PetscInt *irow_in, PetscInt *icol_in, PetscInt col_idx_type)
145d71ae5a4SJacob Faibussowitsch {
146b2f1ab58SBarry Smith PetscInt j;
147b2f1ab58SBarry Smith PetscInt nnz1 = irow_in[i1 + 1] - irow_in[i1];
148b2f1ab58SBarry Smith PetscInt nnz2 = irow_in[i2 + 1] - irow_in[i2];
149b2f1ab58SBarry Smith PetscInt *icol1 = &icol_in[irow_in[i1]];
150b2f1ab58SBarry Smith PetscInt *icol2 = &icol_in[irow_in[i2]];
151b2f1ab58SBarry Smith
1522205254eSKarl Rupp if (nnz1 < nnz2) return -1;
1532205254eSKarl Rupp if (nnz1 > nnz2) return 1;
154b2f1ab58SBarry Smith
1554e1ff37aSBarry Smith if (col_idx_type == SPBAS_COLUMN_NUMBERS) {
1564e1ff37aSBarry Smith for (j = 0; j < nnz1; j++) {
1572205254eSKarl Rupp if (icol1[j] < icol2[j]) return -1;
1582205254eSKarl Rupp if (icol1[j] > icol2[j]) return 1;
159b2f1ab58SBarry Smith }
1604e1ff37aSBarry Smith } else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) {
1614e1ff37aSBarry Smith for (j = 0; j < nnz1; j++) {
1622205254eSKarl Rupp if (icol1[j] - i1 < icol2[j] - i2) return -1;
1632205254eSKarl Rupp if (icol1[j] - i1 > icol2[j] - i2) return 1;
164b2f1ab58SBarry Smith }
1654e1ff37aSBarry Smith } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
1664e1ff37aSBarry Smith for (j = 1; j < nnz1; j++) {
1672205254eSKarl Rupp if (icol1[j] - icol1[0] < icol2[j] - icol2[0]) return -1;
1682205254eSKarl Rupp if (icol1[j] - icol1[0] > icol2[j] - icol2[0]) return 1;
169b2f1ab58SBarry Smith }
170b2f1ab58SBarry Smith }
171b2f1ab58SBarry Smith return 0;
172b2f1ab58SBarry Smith }
173b2f1ab58SBarry Smith
174b2f1ab58SBarry Smith /*
175b2f1ab58SBarry Smith spbas_mergesort_icols:
176b2f1ab58SBarry Smith return a sorting of the rows in which identical sparseness patterns are
177b2f1ab58SBarry Smith next to each other
178b2f1ab58SBarry Smith */
spbas_mergesort_icols(PetscInt nrows,PetscInt * irow_in,PetscInt * icol_in,PetscInt col_idx_type,PetscInt * isort)179*ba38deedSJacob Faibussowitsch static PetscErrorCode spbas_mergesort_icols(PetscInt nrows, PetscInt *irow_in, PetscInt *icol_in, PetscInt col_idx_type, PetscInt *isort)
180d71ae5a4SJacob Faibussowitsch {
181c328eeadSBarry Smith PetscInt istep; /* Chunk-sizes of already sorted parts of arrays */
182c328eeadSBarry Smith PetscInt i, i1, i2; /* Loop counters for (partly) sorted arrays */
183c328eeadSBarry Smith PetscInt istart, i1end, i2end; /* start of newly sorted array part, end of both parts */
184c328eeadSBarry Smith PetscInt *ialloc; /* Allocated arrays */
185c328eeadSBarry Smith PetscInt *iswap; /* auxiliary pointers for swapping */
186c328eeadSBarry Smith PetscInt *ihlp1; /* Pointers to new version of arrays, */
187c328eeadSBarry Smith PetscInt *ihlp2; /* Pointers to previous version of arrays, */
188b2f1ab58SBarry Smith
189b2f1ab58SBarry Smith PetscFunctionBegin;
1909566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nrows, &ialloc));
191b2f1ab58SBarry Smith
192b2f1ab58SBarry Smith ihlp1 = ialloc;
193b2f1ab58SBarry Smith ihlp2 = isort;
194b2f1ab58SBarry Smith
195c328eeadSBarry Smith /* Sorted array chunks are first 1 long, and increase until they are the complete array */
1964e1ff37aSBarry Smith for (istep = 1; istep < nrows; istep *= 2) {
197c328eeadSBarry Smith /*
198c328eeadSBarry Smith Combine sorted parts
199c328eeadSBarry Smith istart:istart+istep-1 and istart+istep-1:istart+2*istep-1
200c328eeadSBarry Smith of ihlp2 and vhlp2
201c328eeadSBarry Smith
202c328eeadSBarry Smith into one sorted part
203c328eeadSBarry Smith istart:istart+2*istep-1
204c328eeadSBarry Smith of ihlp1 and vhlp1
205c328eeadSBarry Smith */
2064e1ff37aSBarry Smith for (istart = 0; istart < nrows; istart += 2 * istep) {
207c328eeadSBarry Smith /* Set counters and bound array part endings */
2089371c9d4SSatish Balay i1 = istart;
2099371c9d4SSatish Balay i1end = i1 + istep;
2109371c9d4SSatish Balay if (i1end > nrows) i1end = nrows;
2119371c9d4SSatish Balay i2 = istart + istep;
2129371c9d4SSatish Balay i2end = i2 + istep;
2139371c9d4SSatish Balay if (i2end > nrows) i2end = nrows;
214b2f1ab58SBarry Smith
215c328eeadSBarry Smith /* Merge the two array parts */
2164e1ff37aSBarry Smith for (i = istart; i < i2end; i++) {
2174e1ff37aSBarry Smith if (i1 < i1end && i2 < i2end && spbas_row_order_icol(ihlp2[i1], ihlp2[i2], irow_in, icol_in, col_idx_type) < 0) {
218b2f1ab58SBarry Smith ihlp1[i] = ihlp2[i1];
219b2f1ab58SBarry Smith i1++;
2204e1ff37aSBarry Smith } else if (i2 < i2end) {
221b2f1ab58SBarry Smith ihlp1[i] = ihlp2[i2];
222b2f1ab58SBarry Smith i2++;
2234e1ff37aSBarry Smith } else {
224b2f1ab58SBarry Smith ihlp1[i] = ihlp2[i1];
225b2f1ab58SBarry Smith i1++;
226b2f1ab58SBarry Smith }
227b2f1ab58SBarry Smith }
228b2f1ab58SBarry Smith }
229b2f1ab58SBarry Smith
230c328eeadSBarry Smith /* Swap the two array sets */
2319371c9d4SSatish Balay iswap = ihlp2;
2329371c9d4SSatish Balay ihlp2 = ihlp1;
2339371c9d4SSatish Balay ihlp1 = iswap;
234b2f1ab58SBarry Smith }
235b2f1ab58SBarry Smith
236c328eeadSBarry Smith /* Copy one more time in case the sorted arrays are the temporary ones */
2374e1ff37aSBarry Smith if (ihlp2 != isort) {
2382205254eSKarl Rupp for (i = 0; i < nrows; i++) isort[i] = ihlp2[i];
239b2f1ab58SBarry Smith }
2409566063dSJacob Faibussowitsch PetscCall(PetscFree(ialloc));
2413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
242b2f1ab58SBarry Smith }
243b2f1ab58SBarry Smith
244b2f1ab58SBarry Smith /*
245b2f1ab58SBarry Smith spbas_compress_pattern:
246b2f1ab58SBarry Smith calculate a compressed sparseness pattern for a sparseness pattern
247b2f1ab58SBarry Smith given in compressed row storage. The compressed sparseness pattern may
248b2f1ab58SBarry Smith require (much) less memory.
249b2f1ab58SBarry Smith */
spbas_compress_pattern(PetscInt * irow_in,PetscInt * icol_in,PetscInt nrows,PetscInt ncols,PetscInt col_idx_type,spbas_matrix * B,PetscReal * mem_reduction)250d71ae5a4SJacob Faibussowitsch PetscErrorCode spbas_compress_pattern(PetscInt *irow_in, PetscInt *icol_in, PetscInt nrows, PetscInt ncols, PetscInt col_idx_type, spbas_matrix *B, PetscReal *mem_reduction)
251d71ae5a4SJacob Faibussowitsch {
252b2f1ab58SBarry Smith PetscInt nnz = irow_in[nrows];
2533dfa2556SBarry Smith size_t mem_orig = (nrows + nnz) * sizeof(PetscInt);
2543dfa2556SBarry Smith size_t mem_compressed;
255b2f1ab58SBarry Smith PetscInt *isort;
256b2f1ab58SBarry Smith PetscInt *icols;
257b2f1ab58SBarry Smith PetscInt row_nnz;
258b2f1ab58SBarry Smith PetscInt *ipoint;
259ace3abfcSBarry Smith PetscBool *used;
260b2f1ab58SBarry Smith PetscInt ptr;
261b2f1ab58SBarry Smith PetscInt i, j;
262ace3abfcSBarry Smith const PetscBool no_values = PETSC_FALSE;
263b2f1ab58SBarry Smith
264b2f1ab58SBarry Smith PetscFunctionBegin;
265c328eeadSBarry Smith /* Allocate the structure of the new matrix */
266b2f1ab58SBarry Smith B->nrows = nrows;
267b2f1ab58SBarry Smith B->ncols = ncols;
268b2f1ab58SBarry Smith B->nnz = nnz;
269b2f1ab58SBarry Smith B->col_idx_type = col_idx_type;
270b2f1ab58SBarry Smith B->block_data = PETSC_TRUE;
2712205254eSKarl Rupp
2729566063dSJacob Faibussowitsch PetscCall(spbas_allocate_pattern(B, no_values));
273b2f1ab58SBarry Smith
274c328eeadSBarry Smith /* When using an offset array, set it */
2754e1ff37aSBarry Smith if (col_idx_type == SPBAS_OFFSET_ARRAY) {
2762205254eSKarl Rupp for (i = 0; i < nrows; i++) B->icol0[i] = icol_in[irow_in[i]];
277b2f1ab58SBarry Smith }
278b2f1ab58SBarry Smith
279c328eeadSBarry Smith /* Allocate the ordering for the rows */
2809566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nrows, &isort));
2819566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nrows, &ipoint));
2829566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nrows, &used));
283b2f1ab58SBarry Smith
2844e1ff37aSBarry Smith for (i = 0; i < nrows; i++) {
285b2f1ab58SBarry Smith B->row_nnz[i] = irow_in[i + 1] - irow_in[i];
286b2f1ab58SBarry Smith isort[i] = i;
287b2f1ab58SBarry Smith ipoint[i] = i;
288b2f1ab58SBarry Smith }
289b2f1ab58SBarry Smith
290c328eeadSBarry Smith /* Sort the rows so that identical columns will be next to each other */
2919566063dSJacob Faibussowitsch PetscCall(spbas_mergesort_icols(nrows, irow_in, icol_in, col_idx_type, isort));
2929566063dSJacob Faibussowitsch PetscCall(PetscInfo(NULL, "Rows have been sorted for patterns\n"));
293b2f1ab58SBarry Smith
294c328eeadSBarry Smith /* Replace identical rows with the first one in the list */
2954e1ff37aSBarry Smith for (i = 1; i < nrows; i++) {
296ad540459SPierre Jolivet if (spbas_row_order_icol(isort[i - 1], isort[i], irow_in, icol_in, col_idx_type) == 0) ipoint[isort[i]] = ipoint[isort[i - 1]];
297b2f1ab58SBarry Smith }
298b2f1ab58SBarry Smith
299c328eeadSBarry Smith /* Collect the rows which are used*/
3002205254eSKarl Rupp for (i = 0; i < nrows; i++) used[ipoint[i]] = PETSC_TRUE;
301b2f1ab58SBarry Smith
302c328eeadSBarry Smith /* Calculate needed memory */
303b2f1ab58SBarry Smith B->n_alloc_icol = 0;
3044e1ff37aSBarry Smith for (i = 0; i < nrows; i++) {
3052205254eSKarl Rupp if (used[i]) B->n_alloc_icol += B->row_nnz[i];
306b2f1ab58SBarry Smith }
3079566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(B->n_alloc_icol, &B->alloc_icol));
308b2f1ab58SBarry Smith
309c328eeadSBarry Smith /* Fill in the diagonal offsets for the rows which store their own data */
310b2f1ab58SBarry Smith ptr = 0;
3114e1ff37aSBarry Smith for (i = 0; i < B->nrows; i++) {
3124e1ff37aSBarry Smith if (used[i]) {
313b2f1ab58SBarry Smith B->icols[i] = &B->alloc_icol[ptr];
314b2f1ab58SBarry Smith icols = &icol_in[irow_in[i]];
315b2f1ab58SBarry Smith row_nnz = B->row_nnz[i];
3164e1ff37aSBarry Smith if (col_idx_type == SPBAS_COLUMN_NUMBERS) {
317ad540459SPierre Jolivet for (j = 0; j < row_nnz; j++) B->icols[i][j] = icols[j];
3184e1ff37aSBarry Smith } else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) {
319ad540459SPierre Jolivet for (j = 0; j < row_nnz; j++) B->icols[i][j] = icols[j] - i;
3204e1ff37aSBarry Smith } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
321ad540459SPierre Jolivet for (j = 0; j < row_nnz; j++) B->icols[i][j] = icols[j] - icols[0];
322b2f1ab58SBarry Smith }
323b2f1ab58SBarry Smith ptr += B->row_nnz[i];
324b2f1ab58SBarry Smith }
325b2f1ab58SBarry Smith }
326b2f1ab58SBarry Smith
327c328eeadSBarry Smith /* Point to the right places for all data */
328ad540459SPierre Jolivet for (i = 0; i < nrows; i++) B->icols[i] = B->icols[ipoint[i]];
3299566063dSJacob Faibussowitsch PetscCall(PetscInfo(NULL, "Row patterns have been compressed\n"));
3309566063dSJacob Faibussowitsch PetscCall(PetscInfo(NULL, " (%g nonzeros per row)\n", (double)((PetscReal)nnz / (PetscReal)nrows)));
331b2f1ab58SBarry Smith
3329566063dSJacob Faibussowitsch PetscCall(PetscFree(isort));
3339566063dSJacob Faibussowitsch PetscCall(PetscFree(used));
3349566063dSJacob Faibussowitsch PetscCall(PetscFree(ipoint));
335b2f1ab58SBarry Smith
336b2f1ab58SBarry Smith mem_compressed = spbas_memory_requirement(*B);
3374e1ff37aSBarry Smith *mem_reduction = 100.0 * (PetscReal)(mem_orig - mem_compressed) / (PetscReal)mem_orig;
3383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
339b2f1ab58SBarry Smith }
340b2f1ab58SBarry Smith
341b2f1ab58SBarry Smith /*
342b2f1ab58SBarry Smith spbas_incomplete_cholesky
343b2f1ab58SBarry Smith Incomplete Cholesky decomposition
344b2f1ab58SBarry Smith */
345c6db04a5SJed Brown #include <../src/mat/impls/aij/seq/bas/spbas_cholesky.h>
346b2f1ab58SBarry Smith
347b2f1ab58SBarry Smith /*
348b2f1ab58SBarry Smith spbas_delete : de-allocate the arrays owned by this matrix
349b2f1ab58SBarry Smith */
spbas_delete(spbas_matrix matrix)350d71ae5a4SJacob Faibussowitsch PetscErrorCode spbas_delete(spbas_matrix matrix)
351d71ae5a4SJacob Faibussowitsch {
352b2f1ab58SBarry Smith PetscInt i;
3539ccc4a9bSBarry Smith
354b2f1ab58SBarry Smith PetscFunctionBegin;
3559ccc4a9bSBarry Smith if (matrix.block_data) {
3569566063dSJacob Faibussowitsch PetscCall(PetscFree(matrix.alloc_icol));
3579566063dSJacob Faibussowitsch if (matrix.values) PetscCall(PetscFree(matrix.alloc_val));
3589ccc4a9bSBarry Smith } else {
3599566063dSJacob Faibussowitsch for (i = 0; i < matrix.nrows; i++) PetscCall(PetscFree(matrix.icols[i]));
3609566063dSJacob Faibussowitsch PetscCall(PetscFree(matrix.icols));
3619ccc4a9bSBarry Smith if (matrix.values) {
3629566063dSJacob Faibussowitsch for (i = 0; i < matrix.nrows; i++) PetscCall(PetscFree(matrix.values[i]));
363b2f1ab58SBarry Smith }
364b2f1ab58SBarry Smith }
365b2f1ab58SBarry Smith
3669566063dSJacob Faibussowitsch PetscCall(PetscFree(matrix.row_nnz));
3679566063dSJacob Faibussowitsch PetscCall(PetscFree(matrix.icols));
3689566063dSJacob Faibussowitsch if (matrix.col_idx_type == SPBAS_OFFSET_ARRAY) PetscCall(PetscFree(matrix.icol0));
3699566063dSJacob Faibussowitsch PetscCall(PetscFree(matrix.values));
3703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
371b2f1ab58SBarry Smith }
372b2f1ab58SBarry Smith
373b2f1ab58SBarry Smith /*
374b2f1ab58SBarry Smith spbas_matrix_to_crs:
375b2f1ab58SBarry Smith Convert an spbas_matrix to compessed row storage
376b2f1ab58SBarry Smith */
spbas_matrix_to_crs(spbas_matrix matrix_A,MatScalar ** val_out,PetscInt ** irow_out,PetscInt ** icol_out)377d71ae5a4SJacob Faibussowitsch PetscErrorCode spbas_matrix_to_crs(spbas_matrix matrix_A, MatScalar **val_out, PetscInt **irow_out, PetscInt **icol_out)
378d71ae5a4SJacob Faibussowitsch {
379b2f1ab58SBarry Smith PetscInt nrows = matrix_A.nrows;
380b2f1ab58SBarry Smith PetscInt nnz = matrix_A.nnz;
381b2f1ab58SBarry Smith PetscInt i, j, r_nnz, i0;
382b2f1ab58SBarry Smith PetscInt *irow;
383b2f1ab58SBarry Smith PetscInt *icol;
384b2f1ab58SBarry Smith PetscInt *icol_A;
385b2f1ab58SBarry Smith MatScalar *val;
386b2f1ab58SBarry Smith PetscScalar *val_A;
387b2f1ab58SBarry Smith PetscInt col_idx_type = matrix_A.col_idx_type;
388ace3abfcSBarry Smith PetscBool do_values = matrix_A.values ? PETSC_TRUE : PETSC_FALSE;
389b2f1ab58SBarry Smith
390b2f1ab58SBarry Smith PetscFunctionBegin;
3919566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nrows + 1, &irow));
3929566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &icol));
3939ccc4a9bSBarry Smith *icol_out = icol;
3949ccc4a9bSBarry Smith *irow_out = irow;
3959ccc4a9bSBarry Smith if (do_values) {
3969566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &val));
3979371c9d4SSatish Balay *val_out = val;
3989371c9d4SSatish Balay *icol_out = icol;
3999371c9d4SSatish Balay *irow_out = irow;
400b2f1ab58SBarry Smith }
401b2f1ab58SBarry Smith
402b2f1ab58SBarry Smith irow[0] = 0;
4039ccc4a9bSBarry Smith for (i = 0; i < nrows; i++) {
404b2f1ab58SBarry Smith r_nnz = matrix_A.row_nnz[i];
405b2f1ab58SBarry Smith i0 = irow[i];
406b2f1ab58SBarry Smith irow[i + 1] = i0 + r_nnz;
407b2f1ab58SBarry Smith icol_A = matrix_A.icols[i];
408b2f1ab58SBarry Smith
4099ccc4a9bSBarry Smith if (do_values) {
410b2f1ab58SBarry Smith val_A = matrix_A.values[i];
4119ccc4a9bSBarry Smith for (j = 0; j < r_nnz; j++) {
412b2f1ab58SBarry Smith icol[i0 + j] = icol_A[j];
413b2f1ab58SBarry Smith val[i0 + j] = val_A[j];
414b2f1ab58SBarry Smith }
4159ccc4a9bSBarry Smith } else {
4162205254eSKarl Rupp for (j = 0; j < r_nnz; j++) icol[i0 + j] = icol_A[j];
417b2f1ab58SBarry Smith }
418b2f1ab58SBarry Smith
4199ccc4a9bSBarry Smith if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) {
4202205254eSKarl Rupp for (j = 0; j < r_nnz; j++) icol[i0 + j] += i;
4212205254eSKarl Rupp } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
422b2f1ab58SBarry Smith i0 = matrix_A.icol0[i];
4232205254eSKarl Rupp for (j = 0; j < r_nnz; j++) icol[i0 + j] += i0;
424b2f1ab58SBarry Smith }
425b2f1ab58SBarry Smith }
4263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
427b2f1ab58SBarry Smith }
428b2f1ab58SBarry Smith
429b2f1ab58SBarry Smith /*
430b2f1ab58SBarry Smith spbas_transpose
431b2f1ab58SBarry Smith return the transpose of a matrix
432b2f1ab58SBarry Smith */
spbas_transpose(spbas_matrix in_matrix,spbas_matrix * result)433d71ae5a4SJacob Faibussowitsch PetscErrorCode spbas_transpose(spbas_matrix in_matrix, spbas_matrix *result)
434d71ae5a4SJacob Faibussowitsch {
435b2f1ab58SBarry Smith PetscInt col_idx_type = in_matrix.col_idx_type;
436b2f1ab58SBarry Smith PetscInt nnz = in_matrix.nnz;
437b2f1ab58SBarry Smith PetscInt ncols = in_matrix.nrows;
438b2f1ab58SBarry Smith PetscInt nrows = in_matrix.ncols;
439b2f1ab58SBarry Smith PetscInt i, j, k;
440b2f1ab58SBarry Smith PetscInt r_nnz;
441b2f1ab58SBarry Smith PetscInt *irow;
4424efc9174SBarry Smith PetscInt icol0 = 0;
443b2f1ab58SBarry Smith PetscScalar *val;
4444e1ff37aSBarry Smith
445b2f1ab58SBarry Smith PetscFunctionBegin;
446c328eeadSBarry Smith /* Copy input values */
447b2f1ab58SBarry Smith result->nrows = nrows;
448b2f1ab58SBarry Smith result->ncols = ncols;
449b2f1ab58SBarry Smith result->nnz = nnz;
450b2f1ab58SBarry Smith result->col_idx_type = SPBAS_COLUMN_NUMBERS;
451b2f1ab58SBarry Smith result->block_data = PETSC_TRUE;
452b2f1ab58SBarry Smith
453c328eeadSBarry Smith /* Allocate sparseness pattern */
4549566063dSJacob Faibussowitsch PetscCall(spbas_allocate_pattern(result, in_matrix.values ? PETSC_TRUE : PETSC_FALSE));
455b2f1ab58SBarry Smith
456c328eeadSBarry Smith /* Count the number of nonzeros in each row */
4572205254eSKarl Rupp for (i = 0; i < nrows; i++) result->row_nnz[i] = 0;
458b2f1ab58SBarry Smith
4599ccc4a9bSBarry Smith for (i = 0; i < ncols; i++) {
460b2f1ab58SBarry Smith r_nnz = in_matrix.row_nnz[i];
461b2f1ab58SBarry Smith irow = in_matrix.icols[i];
4629ccc4a9bSBarry Smith if (col_idx_type == SPBAS_COLUMN_NUMBERS) {
4632205254eSKarl Rupp for (j = 0; j < r_nnz; j++) result->row_nnz[irow[j]]++;
4649ccc4a9bSBarry Smith } else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) {
4652205254eSKarl Rupp for (j = 0; j < r_nnz; j++) result->row_nnz[i + irow[j]]++;
4669ccc4a9bSBarry Smith } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
467b2f1ab58SBarry Smith icol0 = in_matrix.icol0[i];
4682205254eSKarl Rupp for (j = 0; j < r_nnz; j++) result->row_nnz[icol0 + irow[j]]++;
469b2f1ab58SBarry Smith }
470b2f1ab58SBarry Smith }
471b2f1ab58SBarry Smith
472c328eeadSBarry Smith /* Set the pointers to the data */
4739566063dSJacob Faibussowitsch PetscCall(spbas_allocate_data(result));
474b2f1ab58SBarry Smith
475c328eeadSBarry Smith /* Reset the number of nonzeros in each row */
4762205254eSKarl Rupp for (i = 0; i < nrows; i++) result->row_nnz[i] = 0;
477b2f1ab58SBarry Smith
478c328eeadSBarry Smith /* Fill the data arrays */
4799ccc4a9bSBarry Smith if (in_matrix.values) {
4809ccc4a9bSBarry Smith for (i = 0; i < ncols; i++) {
481b2f1ab58SBarry Smith r_nnz = in_matrix.row_nnz[i];
482b2f1ab58SBarry Smith irow = in_matrix.icols[i];
483b2f1ab58SBarry Smith val = in_matrix.values[i];
484b2f1ab58SBarry Smith
4852205254eSKarl Rupp if (col_idx_type == SPBAS_COLUMN_NUMBERS) icol0 = 0;
4862205254eSKarl Rupp else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) icol0 = i;
4872205254eSKarl Rupp else if (col_idx_type == SPBAS_OFFSET_ARRAY) icol0 = in_matrix.icol0[i];
4889ccc4a9bSBarry Smith for (j = 0; j < r_nnz; j++) {
489b2f1ab58SBarry Smith k = icol0 + irow[j];
490b2f1ab58SBarry Smith result->icols[k][result->row_nnz[k]] = i;
491b2f1ab58SBarry Smith result->values[k][result->row_nnz[k]] = val[j];
492b2f1ab58SBarry Smith result->row_nnz[k]++;
493b2f1ab58SBarry Smith }
494b2f1ab58SBarry Smith }
4959ccc4a9bSBarry Smith } else {
4969ccc4a9bSBarry Smith for (i = 0; i < ncols; i++) {
497b2f1ab58SBarry Smith r_nnz = in_matrix.row_nnz[i];
498b2f1ab58SBarry Smith irow = in_matrix.icols[i];
499b2f1ab58SBarry Smith
5002205254eSKarl Rupp if (col_idx_type == SPBAS_COLUMN_NUMBERS) icol0 = 0;
5012205254eSKarl Rupp else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) icol0 = i;
5022205254eSKarl Rupp else if (col_idx_type == SPBAS_OFFSET_ARRAY) icol0 = in_matrix.icol0[i];
503b2f1ab58SBarry Smith
5049ccc4a9bSBarry Smith for (j = 0; j < r_nnz; j++) {
505b2f1ab58SBarry Smith k = icol0 + irow[j];
506b2f1ab58SBarry Smith result->icols[k][result->row_nnz[k]] = i;
507b2f1ab58SBarry Smith result->row_nnz[k]++;
508b2f1ab58SBarry Smith }
509b2f1ab58SBarry Smith }
510b2f1ab58SBarry Smith }
5113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
512b2f1ab58SBarry Smith }
513b2f1ab58SBarry Smith
514b2f1ab58SBarry Smith /*
515b2f1ab58SBarry Smith spbas_mergesort
516b2f1ab58SBarry Smith
517bb42e86aSJed Brown mergesort for an array of integers and an array of associated
518b2f1ab58SBarry Smith reals
519b2f1ab58SBarry Smith
520b2f1ab58SBarry Smith on output, icol[0..nnz-1] is increasing;
521b2f1ab58SBarry Smith val[0..nnz-1] has undergone the same permutation as icol
522b2f1ab58SBarry Smith
5230298fd71SBarry Smith NB: val may be NULL: in that case, only the integers are sorted
524b2f1ab58SBarry Smith
525b2f1ab58SBarry Smith */
spbas_mergesort(PetscInt nnz,PetscInt * icol,PetscScalar * val)526*ba38deedSJacob Faibussowitsch static PetscErrorCode spbas_mergesort(PetscInt nnz, PetscInt *icol, PetscScalar *val)
527d71ae5a4SJacob Faibussowitsch {
528c328eeadSBarry Smith PetscInt istep; /* Chunk-sizes of already sorted parts of arrays */
529c328eeadSBarry Smith PetscInt i, i1, i2; /* Loop counters for (partly) sorted arrays */
530c328eeadSBarry Smith PetscInt istart, i1end, i2end; /* start of newly sorted array part, end of both parts */
531c328eeadSBarry Smith PetscInt *ialloc; /* Allocated arrays */
5320298fd71SBarry Smith PetscScalar *valloc = NULL;
533c328eeadSBarry Smith PetscInt *iswap; /* auxiliary pointers for swapping */
534b2f1ab58SBarry Smith PetscScalar *vswap;
535c328eeadSBarry Smith PetscInt *ihlp1; /* Pointers to new version of arrays, */
5360298fd71SBarry Smith PetscScalar *vhlp1 = NULL; /* (arrays under construction) */
537c328eeadSBarry Smith PetscInt *ihlp2; /* Pointers to previous version of arrays, */
5380298fd71SBarry Smith PetscScalar *vhlp2 = NULL;
539b2f1ab58SBarry Smith
540362febeeSStefano Zampini PetscFunctionBegin;
5419566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &ialloc));
542b2f1ab58SBarry Smith ihlp1 = ialloc;
543b2f1ab58SBarry Smith ihlp2 = icol;
544b2f1ab58SBarry Smith
5459ccc4a9bSBarry Smith if (val) {
5469566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &valloc));
547b2f1ab58SBarry Smith vhlp1 = valloc;
548b2f1ab58SBarry Smith vhlp2 = val;
549b2f1ab58SBarry Smith }
550b2f1ab58SBarry Smith
551c328eeadSBarry Smith /* Sorted array chunks are first 1 long, and increase until they are the complete array */
5529ccc4a9bSBarry Smith for (istep = 1; istep < nnz; istep *= 2) {
553c328eeadSBarry Smith /*
554c328eeadSBarry Smith Combine sorted parts
555c328eeadSBarry Smith istart:istart+istep-1 and istart+istep-1:istart+2*istep-1
556c328eeadSBarry Smith of ihlp2 and vhlp2
557c328eeadSBarry Smith
558c328eeadSBarry Smith into one sorted part
559c328eeadSBarry Smith istart:istart+2*istep-1
560c328eeadSBarry Smith of ihlp1 and vhlp1
561c328eeadSBarry Smith */
5629ccc4a9bSBarry Smith for (istart = 0; istart < nnz; istart += 2 * istep) {
563c328eeadSBarry Smith /* Set counters and bound array part endings */
5649371c9d4SSatish Balay i1 = istart;
5659371c9d4SSatish Balay i1end = i1 + istep;
5669371c9d4SSatish Balay if (i1end > nnz) i1end = nnz;
5679371c9d4SSatish Balay i2 = istart + istep;
5689371c9d4SSatish Balay i2end = i2 + istep;
5699371c9d4SSatish Balay if (i2end > nnz) i2end = nnz;
570b2f1ab58SBarry Smith
571c328eeadSBarry Smith /* Merge the two array parts */
5729ccc4a9bSBarry Smith if (val) {
5739ccc4a9bSBarry Smith for (i = istart; i < i2end; i++) {
5749ccc4a9bSBarry Smith if (i1 < i1end && i2 < i2end && ihlp2[i1] < ihlp2[i2]) {
575b2f1ab58SBarry Smith ihlp1[i] = ihlp2[i1];
576b2f1ab58SBarry Smith vhlp1[i] = vhlp2[i1];
577b2f1ab58SBarry Smith i1++;
5789ccc4a9bSBarry Smith } else if (i2 < i2end) {
579b2f1ab58SBarry Smith ihlp1[i] = ihlp2[i2];
580b2f1ab58SBarry Smith vhlp1[i] = vhlp2[i2];
581b2f1ab58SBarry Smith i2++;
5829ccc4a9bSBarry Smith } else {
583b2f1ab58SBarry Smith ihlp1[i] = ihlp2[i1];
584b2f1ab58SBarry Smith vhlp1[i] = vhlp2[i1];
585b2f1ab58SBarry Smith i1++;
586b2f1ab58SBarry Smith }
587b2f1ab58SBarry Smith }
5889ccc4a9bSBarry Smith } else {
5896322f4bdSBarry Smith for (i = istart; i < i2end; i++) {
5906322f4bdSBarry Smith if (i1 < i1end && i2 < i2end && ihlp2[i1] < ihlp2[i2]) {
591b2f1ab58SBarry Smith ihlp1[i] = ihlp2[i1];
592b2f1ab58SBarry Smith i1++;
5936322f4bdSBarry Smith } else if (i2 < i2end) {
594b2f1ab58SBarry Smith ihlp1[i] = ihlp2[i2];
595b2f1ab58SBarry Smith i2++;
5966322f4bdSBarry Smith } else {
597b2f1ab58SBarry Smith ihlp1[i] = ihlp2[i1];
598b2f1ab58SBarry Smith i1++;
599b2f1ab58SBarry Smith }
600b2f1ab58SBarry Smith }
601b2f1ab58SBarry Smith }
602b2f1ab58SBarry Smith }
603b2f1ab58SBarry Smith
604c328eeadSBarry Smith /* Swap the two array sets */
6059371c9d4SSatish Balay iswap = ihlp2;
6069371c9d4SSatish Balay ihlp2 = ihlp1;
6079371c9d4SSatish Balay ihlp1 = iswap;
6089371c9d4SSatish Balay vswap = vhlp2;
6099371c9d4SSatish Balay vhlp2 = vhlp1;
6109371c9d4SSatish Balay vhlp1 = vswap;
611b2f1ab58SBarry Smith }
612b2f1ab58SBarry Smith
613c328eeadSBarry Smith /* Copy one more time in case the sorted arrays are the temporary ones */
6146322f4bdSBarry Smith if (ihlp2 != icol) {
6152205254eSKarl Rupp for (i = 0; i < nnz; i++) icol[i] = ihlp2[i];
6166322f4bdSBarry Smith if (val) {
6172205254eSKarl Rupp for (i = 0; i < nnz; i++) val[i] = vhlp2[i];
618b2f1ab58SBarry Smith }
619b2f1ab58SBarry Smith }
620b2f1ab58SBarry Smith
6219566063dSJacob Faibussowitsch PetscCall(PetscFree(ialloc));
6229566063dSJacob Faibussowitsch if (val) PetscCall(PetscFree(valloc));
6233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
624b2f1ab58SBarry Smith }
625b2f1ab58SBarry Smith
626b2f1ab58SBarry Smith /*
627b2f1ab58SBarry Smith spbas_apply_reordering_rows:
628b2f1ab58SBarry Smith apply the given reordering to the rows: matrix_A = matrix_A(perm,:);
629b2f1ab58SBarry Smith */
spbas_apply_reordering_rows(spbas_matrix * matrix_A,const PetscInt * permutation)630*ba38deedSJacob Faibussowitsch static PetscErrorCode spbas_apply_reordering_rows(spbas_matrix *matrix_A, const PetscInt *permutation)
631d71ae5a4SJacob Faibussowitsch {
632b2f1ab58SBarry Smith PetscInt i, j, ip;
633b2f1ab58SBarry Smith PetscInt nrows = matrix_A->nrows;
634b2f1ab58SBarry Smith PetscInt *row_nnz;
635b2f1ab58SBarry Smith PetscInt **icols;
636ace3abfcSBarry Smith PetscBool do_values = matrix_A->values ? PETSC_TRUE : PETSC_FALSE;
6370298fd71SBarry Smith PetscScalar **vals = NULL;
638b2f1ab58SBarry Smith
639b2f1ab58SBarry Smith PetscFunctionBegin;
64008401ef6SPierre Jolivet PetscCheck(matrix_A->col_idx_type == SPBAS_DIAGONAL_OFFSETS, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "must have diagonal offsets in pattern");
641b2f1ab58SBarry Smith
64248a46eb9SPierre Jolivet if (do_values) PetscCall(PetscMalloc1(nrows, &vals));
6439566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nrows, &row_nnz));
6449566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nrows, &icols));
645b2f1ab58SBarry Smith
6466322f4bdSBarry Smith for (i = 0; i < nrows; i++) {
647b2f1ab58SBarry Smith ip = permutation[i];
6482205254eSKarl Rupp if (do_values) vals[i] = matrix_A->values[ip];
649b2f1ab58SBarry Smith icols[i] = matrix_A->icols[ip];
650b2f1ab58SBarry Smith row_nnz[i] = matrix_A->row_nnz[ip];
6512205254eSKarl Rupp for (j = 0; j < row_nnz[i]; j++) icols[i][j] += ip - i;
652b2f1ab58SBarry Smith }
653b2f1ab58SBarry Smith
6549566063dSJacob Faibussowitsch if (do_values) PetscCall(PetscFree(matrix_A->values));
6559566063dSJacob Faibussowitsch PetscCall(PetscFree(matrix_A->icols));
6569566063dSJacob Faibussowitsch PetscCall(PetscFree(matrix_A->row_nnz));
657b2f1ab58SBarry Smith
6582205254eSKarl Rupp if (do_values) matrix_A->values = vals;
659b2f1ab58SBarry Smith matrix_A->icols = icols;
660b2f1ab58SBarry Smith matrix_A->row_nnz = row_nnz;
6613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
662b2f1ab58SBarry Smith }
663b2f1ab58SBarry Smith
664b2f1ab58SBarry Smith /*
665b2f1ab58SBarry Smith spbas_apply_reordering_cols:
666b2f1ab58SBarry Smith apply the given reordering to the columns: matrix_A(:,perm) = matrix_A;
667b2f1ab58SBarry Smith */
spbas_apply_reordering_cols(spbas_matrix * matrix_A,const PetscInt * permutation)668*ba38deedSJacob Faibussowitsch static PetscErrorCode spbas_apply_reordering_cols(spbas_matrix *matrix_A, const PetscInt *permutation)
669d71ae5a4SJacob Faibussowitsch {
670b2f1ab58SBarry Smith PetscInt i, j;
671b2f1ab58SBarry Smith PetscInt nrows = matrix_A->nrows;
672b2f1ab58SBarry Smith PetscInt row_nnz;
673b2f1ab58SBarry Smith PetscInt *icols;
674ace3abfcSBarry Smith PetscBool do_values = matrix_A->values ? PETSC_TRUE : PETSC_FALSE;
6750298fd71SBarry Smith PetscScalar *vals = NULL;
676b2f1ab58SBarry Smith
677b2f1ab58SBarry Smith PetscFunctionBegin;
67808401ef6SPierre Jolivet PetscCheck(matrix_A->col_idx_type == SPBAS_DIAGONAL_OFFSETS, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "must have diagonal offsets in pattern");
679b2f1ab58SBarry Smith
6806322f4bdSBarry Smith for (i = 0; i < nrows; i++) {
681b2f1ab58SBarry Smith icols = matrix_A->icols[i];
682b2f1ab58SBarry Smith row_nnz = matrix_A->row_nnz[i];
6832205254eSKarl Rupp if (do_values) vals = matrix_A->values[i];
684b2f1ab58SBarry Smith
685ad540459SPierre Jolivet for (j = 0; j < row_nnz; j++) icols[j] = permutation[i + icols[j]] - i;
6869566063dSJacob Faibussowitsch PetscCall(spbas_mergesort(row_nnz, icols, vals));
687b2f1ab58SBarry Smith }
6883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
689b2f1ab58SBarry Smith }
690b2f1ab58SBarry Smith
691b2f1ab58SBarry Smith /*
692b2f1ab58SBarry Smith spbas_apply_reordering:
693b2f1ab58SBarry Smith apply the given reordering: matrix_A(perm,perm) = matrix_A;
694b2f1ab58SBarry Smith */
spbas_apply_reordering(spbas_matrix * matrix_A,const PetscInt * permutation,const PetscInt * inv_perm)695d71ae5a4SJacob Faibussowitsch PetscErrorCode spbas_apply_reordering(spbas_matrix *matrix_A, const PetscInt *permutation, const PetscInt *inv_perm)
696d71ae5a4SJacob Faibussowitsch {
697b2f1ab58SBarry Smith PetscFunctionBegin;
6989566063dSJacob Faibussowitsch PetscCall(spbas_apply_reordering_rows(matrix_A, inv_perm));
6999566063dSJacob Faibussowitsch PetscCall(spbas_apply_reordering_cols(matrix_A, permutation));
7003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
701b2f1ab58SBarry Smith }
702b2f1ab58SBarry Smith
spbas_pattern_only(PetscInt nrows,PetscInt ncols,PetscInt * ai,PetscInt * aj,spbas_matrix * result)703d71ae5a4SJacob Faibussowitsch PetscErrorCode spbas_pattern_only(PetscInt nrows, PetscInt ncols, PetscInt *ai, PetscInt *aj, spbas_matrix *result)
704d71ae5a4SJacob Faibussowitsch {
705b2f1ab58SBarry Smith spbas_matrix retval;
706b2f1ab58SBarry Smith PetscInt i, j, i0, r_nnz;
707b2f1ab58SBarry Smith
708b2f1ab58SBarry Smith PetscFunctionBegin;
709c328eeadSBarry Smith /* Copy input values */
710b2f1ab58SBarry Smith retval.nrows = nrows;
711b2f1ab58SBarry Smith retval.ncols = ncols;
712b2f1ab58SBarry Smith retval.nnz = ai[nrows];
713b2f1ab58SBarry Smith
714b2f1ab58SBarry Smith retval.block_data = PETSC_TRUE;
715b2f1ab58SBarry Smith retval.col_idx_type = SPBAS_DIAGONAL_OFFSETS;
716b2f1ab58SBarry Smith
717c328eeadSBarry Smith /* Allocate output matrix */
7189566063dSJacob Faibussowitsch PetscCall(spbas_allocate_pattern(&retval, PETSC_FALSE));
7192205254eSKarl Rupp for (i = 0; i < nrows; i++) retval.row_nnz[i] = ai[i + 1] - ai[i];
7209566063dSJacob Faibussowitsch PetscCall(spbas_allocate_data(&retval));
721c328eeadSBarry Smith /* Copy the structure */
7226322f4bdSBarry Smith for (i = 0; i < retval.nrows; i++) {
723b2f1ab58SBarry Smith i0 = ai[i];
724b2f1ab58SBarry Smith r_nnz = ai[i + 1] - i0;
725b2f1ab58SBarry Smith
726ad540459SPierre Jolivet for (j = 0; j < r_nnz; j++) retval.icols[i][j] = aj[i0 + j] - i;
727b2f1ab58SBarry Smith }
728b2f1ab58SBarry Smith *result = retval;
7293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
730b2f1ab58SBarry Smith }
731b2f1ab58SBarry Smith
732b2f1ab58SBarry Smith /*
733b2f1ab58SBarry Smith spbas_mark_row_power:
734b2f1ab58SBarry Smith Mark the columns in row 'row' which are nonzero in
735b2f1ab58SBarry Smith matrix^2log(marker).
736b2f1ab58SBarry Smith */
spbas_mark_row_power(PetscInt * iwork,PetscInt row,spbas_matrix * in_matrix,PetscInt marker,PetscInt minmrk,PetscInt maxmrk)737*ba38deedSJacob Faibussowitsch static PetscErrorCode spbas_mark_row_power(PetscInt *iwork, /* marker-vector */
738c328eeadSBarry Smith PetscInt row, /* row for which the columns are marked */
739c328eeadSBarry Smith spbas_matrix *in_matrix, /* matrix for which the power is being calculated */
740c328eeadSBarry Smith PetscInt marker, /* marker-value: 2^power */
741c328eeadSBarry Smith PetscInt minmrk, /* lower bound for marked points */
742c328eeadSBarry Smith PetscInt maxmrk) /* upper bound for marked points */
743b2f1ab58SBarry Smith {
744b2f1ab58SBarry Smith PetscInt i, j, nnz;
745b2f1ab58SBarry Smith
746b2f1ab58SBarry Smith PetscFunctionBegin;
747b2f1ab58SBarry Smith nnz = in_matrix->row_nnz[row];
748b2f1ab58SBarry Smith
749c328eeadSBarry Smith /* For higher powers, call this function recursively */
7506322f4bdSBarry Smith if (marker > 1) {
7516322f4bdSBarry Smith for (i = 0; i < nnz; i++) {
752b2f1ab58SBarry Smith j = row + in_matrix->icols[row][i];
7536322f4bdSBarry Smith if (minmrk <= j && j < maxmrk && iwork[j] < marker) {
7549566063dSJacob Faibussowitsch PetscCall(spbas_mark_row_power(iwork, row + in_matrix->icols[row][i], in_matrix, marker / 2, minmrk, maxmrk));
755b2f1ab58SBarry Smith iwork[j] |= marker;
756b2f1ab58SBarry Smith }
757b2f1ab58SBarry Smith }
7586322f4bdSBarry Smith } else {
759c328eeadSBarry Smith /* Mark the columns reached */
7606322f4bdSBarry Smith for (i = 0; i < nnz; i++) {
761b2f1ab58SBarry Smith j = row + in_matrix->icols[row][i];
7622205254eSKarl Rupp if (minmrk <= j && j < maxmrk) iwork[j] |= 1;
763b2f1ab58SBarry Smith }
764b2f1ab58SBarry Smith }
7653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
766b2f1ab58SBarry Smith }
767b2f1ab58SBarry Smith
768b2f1ab58SBarry Smith /*
769b2f1ab58SBarry Smith spbas_power
770b2f1ab58SBarry Smith Calculate sparseness patterns for incomplete Cholesky decompositions
771b2f1ab58SBarry Smith of a given order: (almost) all nonzeros of the matrix^(order+1) which
772b2f1ab58SBarry Smith are inside the band width are found and stored in the output sparseness
773b2f1ab58SBarry Smith pattern.
774b2f1ab58SBarry Smith */
spbas_power(spbas_matrix in_matrix,PetscInt power,spbas_matrix * result)775d71ae5a4SJacob Faibussowitsch PetscErrorCode spbas_power(spbas_matrix in_matrix, PetscInt power, spbas_matrix *result)
776d71ae5a4SJacob Faibussowitsch {
777b2f1ab58SBarry Smith spbas_matrix retval;
778b2f1ab58SBarry Smith PetscInt nrows = in_matrix.nrows;
779b2f1ab58SBarry Smith PetscInt ncols = in_matrix.ncols;
780b2f1ab58SBarry Smith PetscInt i, j, kend;
781b2f1ab58SBarry Smith PetscInt nnz, inz;
782b2f1ab58SBarry Smith PetscInt *iwork;
783b2f1ab58SBarry Smith PetscInt marker;
784b2f1ab58SBarry Smith PetscInt maxmrk = 0;
785b2f1ab58SBarry Smith
786b2f1ab58SBarry Smith PetscFunctionBegin;
78708401ef6SPierre Jolivet PetscCheck(in_matrix.col_idx_type == SPBAS_DIAGONAL_OFFSETS, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "must have diagonal offsets in pattern");
78808401ef6SPierre Jolivet PetscCheck(ncols == nrows, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Dimension error");
789aed4548fSBarry Smith PetscCheck(!in_matrix.values, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Input array must be sparseness pattern (no values)");
79008401ef6SPierre Jolivet PetscCheck(power > 0, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Power must be 1 or up");
791b2f1ab58SBarry Smith
792c328eeadSBarry Smith /* Copy input values*/
793b2f1ab58SBarry Smith retval.nrows = ncols;
794b2f1ab58SBarry Smith retval.ncols = nrows;
795b2f1ab58SBarry Smith retval.nnz = 0;
796b2f1ab58SBarry Smith retval.col_idx_type = SPBAS_DIAGONAL_OFFSETS;
797b2f1ab58SBarry Smith retval.block_data = PETSC_FALSE;
798b2f1ab58SBarry Smith
799c328eeadSBarry Smith /* Allocate sparseness pattern */
8009566063dSJacob Faibussowitsch PetscCall(spbas_allocate_pattern(&retval, in_matrix.values ? PETSC_TRUE : PETSC_FALSE));
801b2f1ab58SBarry Smith
802580bdb30SBarry Smith /* Allocate marker array: note sure the max needed so use the max of the two */
8039566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(PetscMax(ncols, nrows), &iwork));
804b2f1ab58SBarry Smith
805c328eeadSBarry Smith /* Calculate marker values */
8069371c9d4SSatish Balay marker = 1;
8079371c9d4SSatish Balay for (i = 1; i < power; i++) marker *= 2;
808b2f1ab58SBarry Smith
8096322f4bdSBarry Smith for (i = 0; i < nrows; i++) {
810c328eeadSBarry Smith /* Calculate the pattern for each row */
811b2f1ab58SBarry Smith
812b2f1ab58SBarry Smith nnz = in_matrix.row_nnz[i];
813b2f1ab58SBarry Smith kend = i + in_matrix.icols[i][nnz - 1];
8142205254eSKarl Rupp if (maxmrk <= kend) maxmrk = kend + 1;
8159566063dSJacob Faibussowitsch PetscCall(spbas_mark_row_power(iwork, i, &in_matrix, marker, i, maxmrk));
816b2f1ab58SBarry Smith
817c328eeadSBarry Smith /* Count the columns*/
818b2f1ab58SBarry Smith nnz = 0;
8192205254eSKarl Rupp for (j = i; j < maxmrk; j++) nnz += (iwork[j] != 0);
820b2f1ab58SBarry Smith
821c328eeadSBarry Smith /* Allocate the column indices */
822b2f1ab58SBarry Smith retval.row_nnz[i] = nnz;
8239566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &retval.icols[i]));
824b2f1ab58SBarry Smith
825c328eeadSBarry Smith /* Administrate the column indices */
826b2f1ab58SBarry Smith inz = 0;
8276322f4bdSBarry Smith for (j = i; j < maxmrk; j++) {
8286322f4bdSBarry Smith if (iwork[j]) {
829b2f1ab58SBarry Smith retval.icols[i][inz] = j - i;
830b2f1ab58SBarry Smith inz++;
831b2f1ab58SBarry Smith iwork[j] = 0;
832b2f1ab58SBarry Smith }
833b2f1ab58SBarry Smith }
834b2f1ab58SBarry Smith retval.nnz += nnz;
835a8f51744SPierre Jolivet }
8369566063dSJacob Faibussowitsch PetscCall(PetscFree(iwork));
837b2f1ab58SBarry Smith *result = retval;
8383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
839b2f1ab58SBarry Smith }
840b2f1ab58SBarry Smith
841b2f1ab58SBarry Smith /*
842b2f1ab58SBarry Smith spbas_keep_upper:
843b2f1ab58SBarry Smith remove the lower part of the matrix: keep the upper part
844b2f1ab58SBarry Smith */
spbas_keep_upper(spbas_matrix * inout_matrix)845d71ae5a4SJacob Faibussowitsch PetscErrorCode spbas_keep_upper(spbas_matrix *inout_matrix)
846d71ae5a4SJacob Faibussowitsch {
847b2f1ab58SBarry Smith PetscInt i, j;
848b2f1ab58SBarry Smith PetscInt jstart;
849b2f1ab58SBarry Smith
850b2f1ab58SBarry Smith PetscFunctionBegin;
8515f80ce2aSJacob Faibussowitsch PetscCheck(!inout_matrix->block_data, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Not yet for block data matrices");
8526322f4bdSBarry Smith for (i = 0; i < inout_matrix->nrows; i++) {
8536322f4bdSBarry Smith for (jstart = 0; (jstart < inout_matrix->row_nnz[i]) && (inout_matrix->icols[i][jstart] < 0); jstart++) { }
8546322f4bdSBarry Smith if (jstart > 0) {
855ad540459SPierre Jolivet for (j = 0; j < inout_matrix->row_nnz[i] - jstart; j++) inout_matrix->icols[i][j] = inout_matrix->icols[i][j + jstart];
856b2f1ab58SBarry Smith
8576322f4bdSBarry Smith if (inout_matrix->values) {
858ad540459SPierre Jolivet for (j = 0; j < inout_matrix->row_nnz[i] - jstart; j++) inout_matrix->values[i][j] = inout_matrix->values[i][j + jstart];
859b2f1ab58SBarry Smith }
860b2f1ab58SBarry Smith
861b2f1ab58SBarry Smith inout_matrix->row_nnz[i] -= jstart;
862b2f1ab58SBarry Smith
8636322f4bdSBarry Smith inout_matrix->icols[i] = (PetscInt *)realloc((void *)inout_matrix->icols[i], inout_matrix->row_nnz[i] * sizeof(PetscInt));
864b2f1ab58SBarry Smith
865ad540459SPierre Jolivet if (inout_matrix->values) inout_matrix->values[i] = (PetscScalar *)realloc((void *)inout_matrix->values[i], inout_matrix->row_nnz[i] * sizeof(PetscScalar));
866b2f1ab58SBarry Smith inout_matrix->nnz -= jstart;
867b2f1ab58SBarry Smith }
868b2f1ab58SBarry Smith }
8693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
870b2f1ab58SBarry Smith }
871