xref: /petsc/src/mat/impls/aij/seq/bas/spbas.c (revision 9c5460f9064ca60dd71a234a1f6faf93e7a6b0c9)
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