xref: /petsc/src/mat/impls/aij/seq/bas/spbas.c (revision bb42e86ab3e4720245217a7cdcd02146569f06da)
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 
7845006b9SBarry 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 
170053dfc8SBarry Smith    Notes: Since this currently hooked up to use drop tolerance it should produce the same factors and hence convergence as the PETSc ICC, for higher
180053dfc8SBarry 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
190053dfc8SBarry Smith      we recommend not using this functionality.
200053dfc8SBarry Smith 
21b7c853c4SBarry Smith .seealso: PCFactorSetMatSolverPackage(), MatSolverPackage, PCFactorSetLevels(), PCFactorSetDropTolerance()
22845006b9SBarry Smith 
23845006b9SBarry Smith M*/
249ccc4a9bSBarry Smith 
25b2f1ab58SBarry Smith /*
26b2f1ab58SBarry Smith   spbas_memory_requirement:
27b2f1ab58SBarry Smith     Calculate the number of bytes needed to store tha matrix
28b2f1ab58SBarry Smith */
293dfa2556SBarry Smith size_t spbas_memory_requirement(spbas_matrix matrix)
30b2f1ab58SBarry Smith {
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 */
60ace3abfcSBarry Smith PetscErrorCode spbas_allocate_pattern(spbas_matrix * result, PetscBool do_values)
61b2f1ab58SBarry Smith {
62b2f1ab58SBarry Smith   PetscErrorCode ierr;
63b2f1ab58SBarry Smith   PetscInt       nrows        = result->nrows;
64b2f1ab58SBarry Smith   PetscInt       col_idx_type = result->col_idx_type;
65b2f1ab58SBarry Smith 
66b2f1ab58SBarry Smith   PetscFunctionBegin;
67c328eeadSBarry Smith   /* Allocate sparseness pattern */
68785e854fSJed Brown   ierr = PetscMalloc1(nrows,&result->row_nnz);CHKERRQ(ierr);
69785e854fSJed Brown   ierr = PetscMalloc1(nrows,&result->icols);CHKERRQ(ierr);
70b2f1ab58SBarry Smith 
71c328eeadSBarry Smith   /* If offsets are given wrt an array, create array */
724e1ff37aSBarry Smith   if (col_idx_type == SPBAS_OFFSET_ARRAY) {
73785e854fSJed Brown     ierr = PetscMalloc1(nrows,&result->icol0);CHKERRQ(ierr);
744e1ff37aSBarry Smith   } else  {
750298fd71SBarry Smith     result->icol0 = NULL;
76b2f1ab58SBarry Smith   }
77b2f1ab58SBarry Smith 
78c328eeadSBarry Smith   /* If values are given, allocate values array */
794e1ff37aSBarry Smith   if (do_values)  {
80785e854fSJed Brown     ierr = PetscMalloc1(nrows,&result->values);CHKERRQ(ierr);
814e1ff37aSBarry Smith   } else {
820298fd71SBarry Smith     result->values = NULL;
83b2f1ab58SBarry Smith   }
84b2f1ab58SBarry Smith   PetscFunctionReturn(0);
85b2f1ab58SBarry Smith }
86b2f1ab58SBarry Smith 
87b2f1ab58SBarry Smith /*
88b2f1ab58SBarry Smith spbas_allocate_data:
89b2f1ab58SBarry Smith    in case of block_data:
90b2f1ab58SBarry Smith        Allocate the data arrays alloc_icol and optionally alloc_val,
91b2f1ab58SBarry Smith        set appropriate pointers from icols and values;
92b2f1ab58SBarry Smith    in case of !block_data:
93b2f1ab58SBarry Smith        Allocate the arrays icols[i] and optionally values[i]
94b2f1ab58SBarry Smith */
95b2f1ab58SBarry Smith PetscErrorCode spbas_allocate_data(spbas_matrix * result)
96b2f1ab58SBarry Smith {
97b2f1ab58SBarry Smith   PetscInt       i;
98b2f1ab58SBarry Smith   PetscInt       nnz   = result->nnz;
99b2f1ab58SBarry Smith   PetscInt       nrows = result->nrows;
100b2f1ab58SBarry Smith   PetscInt       r_nnz;
101b2f1ab58SBarry Smith   PetscErrorCode ierr;
1026c4ed002SBarry Smith   PetscBool      do_values  = (result->values) ? PETSC_TRUE : PETSC_FALSE;
103ace3abfcSBarry Smith   PetscBool      block_data = result->block_data;
104b2f1ab58SBarry Smith 
105b2f1ab58SBarry Smith   PetscFunctionBegin;
1064e1ff37aSBarry Smith   if (block_data) {
107c328eeadSBarry Smith     /* Allocate the column number array and point to it */
108b2f1ab58SBarry Smith     result->n_alloc_icol = nnz;
1092205254eSKarl Rupp 
110785e854fSJed Brown     ierr = PetscMalloc1(nnz, &result->alloc_icol);CHKERRQ(ierr);
1112205254eSKarl Rupp 
112b2f1ab58SBarry Smith     result->icols[0] = result->alloc_icol;
1134e1ff37aSBarry Smith     for (i=1; i<nrows; i++)  {
114b2f1ab58SBarry Smith       result->icols[i] = result->icols[i-1] + result->row_nnz[i-1];
115b2f1ab58SBarry Smith     }
116b2f1ab58SBarry Smith 
117c328eeadSBarry Smith     /* Allocate the value array and point to it */
1184e1ff37aSBarry Smith     if (do_values) {
119b2f1ab58SBarry Smith       result->n_alloc_val = nnz;
1202205254eSKarl Rupp 
121785e854fSJed Brown       ierr = PetscMalloc1(nnz, &result->alloc_val);CHKERRQ(ierr);
1222205254eSKarl Rupp 
123b2f1ab58SBarry Smith       result->values[0] = result->alloc_val;
1244e1ff37aSBarry Smith       for (i=1; i<nrows; i++) {
125b2f1ab58SBarry Smith         result->values[i] = result->values[i-1] + result->row_nnz[i-1];
126b2f1ab58SBarry Smith       }
127b2f1ab58SBarry Smith     }
1284e1ff37aSBarry Smith   } else {
1294e1ff37aSBarry Smith     for (i=0; i<nrows; i++)   {
130b2f1ab58SBarry Smith       r_nnz = result->row_nnz[i];
131785e854fSJed Brown       ierr  = PetscMalloc1(r_nnz, &result->icols[i]);CHKERRQ(ierr);
132b2f1ab58SBarry Smith     }
1334e1ff37aSBarry Smith     if (do_values) {
1344e1ff37aSBarry Smith       for (i=0; i<nrows; i++)  {
135b2f1ab58SBarry Smith         r_nnz = result->row_nnz[i];
136785e854fSJed Brown         ierr  = PetscMalloc1(r_nnz, &result->values[i]);CHKERRQ(ierr);
137b2f1ab58SBarry Smith       }
138b2f1ab58SBarry Smith     }
139b2f1ab58SBarry Smith   }
140b2f1ab58SBarry Smith   PetscFunctionReturn(0);
141b2f1ab58SBarry Smith }
142b2f1ab58SBarry Smith 
143b2f1ab58SBarry Smith /*
144b2f1ab58SBarry Smith   spbas_row_order_icol
145b2f1ab58SBarry Smith      determine if row i1 should come
146b2f1ab58SBarry Smith        + before row i2 in the sorted rows (return -1),
147b2f1ab58SBarry Smith        + after (return 1)
148b2f1ab58SBarry Smith        + is identical (return 0).
149b2f1ab58SBarry Smith */
150b2f1ab58SBarry Smith int spbas_row_order_icol(PetscInt i1, PetscInt i2, PetscInt *irow_in, PetscInt *icol_in,PetscInt col_idx_type)
151b2f1ab58SBarry Smith {
152b2f1ab58SBarry Smith   PetscInt j;
153b2f1ab58SBarry Smith   PetscInt nnz1    = irow_in[i1+1] - irow_in[i1];
154b2f1ab58SBarry Smith   PetscInt nnz2    = irow_in[i2+1] - irow_in[i2];
155b2f1ab58SBarry Smith   PetscInt * icol1 = &icol_in[irow_in[i1]];
156b2f1ab58SBarry Smith   PetscInt * icol2 = &icol_in[irow_in[i2]];
157b2f1ab58SBarry Smith 
1582205254eSKarl Rupp   if (nnz1<nnz2) return -1;
1592205254eSKarl Rupp   if (nnz1>nnz2) return 1;
160b2f1ab58SBarry Smith 
1614e1ff37aSBarry Smith   if (col_idx_type == SPBAS_COLUMN_NUMBERS) {
1624e1ff37aSBarry Smith     for (j=0; j<nnz1; j++) {
1632205254eSKarl Rupp       if (icol1[j]< icol2[j]) return -1;
1642205254eSKarl Rupp       if (icol1[j]> icol2[j]) return 1;
165b2f1ab58SBarry Smith     }
1664e1ff37aSBarry Smith   } else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) {
1674e1ff37aSBarry Smith     for (j=0; j<nnz1; j++) {
1682205254eSKarl Rupp       if (icol1[j]-i1< icol2[j]-i2) return -1;
1692205254eSKarl Rupp       if (icol1[j]-i1> icol2[j]-i2) return 1;
170b2f1ab58SBarry Smith     }
1714e1ff37aSBarry Smith   } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
1724e1ff37aSBarry Smith     for (j=1; j<nnz1; j++) {
1732205254eSKarl Rupp       if (icol1[j]-icol1[0] < icol2[j]-icol2[0]) return -1;
1742205254eSKarl Rupp       if (icol1[j]-icol1[0] > icol2[j]-icol2[0]) return 1;
175b2f1ab58SBarry Smith     }
176b2f1ab58SBarry Smith   }
177b2f1ab58SBarry Smith   return 0;
178b2f1ab58SBarry Smith }
179b2f1ab58SBarry Smith 
180b2f1ab58SBarry Smith /*
181b2f1ab58SBarry Smith   spbas_mergesort_icols:
182b2f1ab58SBarry Smith     return a sorting of the rows in which identical sparseness patterns are
183b2f1ab58SBarry Smith     next to each other
184b2f1ab58SBarry Smith */
185b2f1ab58SBarry Smith PetscErrorCode spbas_mergesort_icols(PetscInt nrows, PetscInt * irow_in, PetscInt * icol_in,PetscInt col_idx_type, PetscInt *isort)
186b2f1ab58SBarry Smith {
187b2f1ab58SBarry Smith   PetscErrorCode ierr;
188c328eeadSBarry Smith   PetscInt       istep;       /* Chunk-sizes of already sorted parts of arrays */
189c328eeadSBarry Smith   PetscInt       i, i1, i2;   /* Loop counters for (partly) sorted arrays */
190c328eeadSBarry Smith   PetscInt       istart, i1end, i2end; /* start of newly sorted array part, end of both  parts */
191c328eeadSBarry Smith   PetscInt       *ialloc;     /* Allocated arrays */
192c328eeadSBarry Smith   PetscInt       *iswap;      /* auxiliary pointers for swapping */
193c328eeadSBarry Smith   PetscInt       *ihlp1;      /* Pointers to new version of arrays, */
194c328eeadSBarry Smith   PetscInt       *ihlp2;      /* Pointers to previous version of arrays, */
195b2f1ab58SBarry Smith 
196b2f1ab58SBarry Smith   PetscFunctionBegin;
197785e854fSJed Brown   ierr = PetscMalloc1(nrows,&ialloc);CHKERRQ(ierr);
198b2f1ab58SBarry Smith 
199b2f1ab58SBarry Smith   ihlp1 = ialloc;
200b2f1ab58SBarry Smith   ihlp2 = isort;
201b2f1ab58SBarry Smith 
202c328eeadSBarry Smith   /* Sorted array chunks are first 1 long, and increase until they are the complete array */
2034e1ff37aSBarry Smith   for (istep=1; istep<nrows; istep*=2) {
204c328eeadSBarry Smith     /*
205c328eeadSBarry Smith       Combine sorted parts
206c328eeadSBarry Smith           istart:istart+istep-1 and istart+istep-1:istart+2*istep-1
207c328eeadSBarry Smith       of ihlp2 and vhlp2
208c328eeadSBarry Smith 
209c328eeadSBarry Smith       into one sorted part
210c328eeadSBarry Smith           istart:istart+2*istep-1
211c328eeadSBarry Smith       of ihlp1 and vhlp1
212c328eeadSBarry Smith     */
2134e1ff37aSBarry Smith     for (istart=0; istart<nrows; istart+=2*istep) {
214c328eeadSBarry Smith       /* Set counters and bound array part endings */
2152205254eSKarl Rupp       i1=istart;        i1end = i1+istep;  if (i1end>nrows) i1end=nrows;
2162205254eSKarl Rupp       i2=istart+istep;  i2end = i2+istep;  if (i2end>nrows) i2end=nrows;
217b2f1ab58SBarry Smith 
218c328eeadSBarry Smith       /* Merge the two array parts */
2194e1ff37aSBarry Smith       for (i=istart; i<i2end; i++)  {
2204e1ff37aSBarry Smith         if (i1<i1end && i2<i2end && spbas_row_order_icol(ihlp2[i1], ihlp2[i2], irow_in, icol_in, col_idx_type) < 0) {
221b2f1ab58SBarry Smith           ihlp1[i] = ihlp2[i1];
222b2f1ab58SBarry Smith           i1++;
2234e1ff37aSBarry Smith         } else if (i2<i2end) {
224b2f1ab58SBarry Smith           ihlp1[i] = ihlp2[i2];
225b2f1ab58SBarry Smith           i2++;
2264e1ff37aSBarry Smith         } else {
227b2f1ab58SBarry Smith           ihlp1[i] = ihlp2[i1];
228b2f1ab58SBarry Smith           i1++;
229b2f1ab58SBarry Smith         }
230b2f1ab58SBarry Smith       }
231b2f1ab58SBarry Smith     }
232b2f1ab58SBarry Smith 
233c328eeadSBarry Smith     /* Swap the two array sets */
234b2f1ab58SBarry Smith     iswap = ihlp2; ihlp2 = ihlp1; ihlp1 = iswap;
235b2f1ab58SBarry Smith   }
236b2f1ab58SBarry Smith 
237c328eeadSBarry Smith   /* Copy one more time in case the sorted arrays are the temporary ones */
2384e1ff37aSBarry Smith   if (ihlp2 != isort) {
2392205254eSKarl Rupp     for (i=0; i<nrows; i++) isort[i] = ihlp2[i];
240b2f1ab58SBarry Smith   }
241b2f1ab58SBarry Smith   ierr = PetscFree(ialloc);CHKERRQ(ierr);
242b2f1ab58SBarry Smith   PetscFunctionReturn(0);
243b2f1ab58SBarry Smith }
244b2f1ab58SBarry Smith 
245b2f1ab58SBarry Smith 
246b2f1ab58SBarry Smith 
247b2f1ab58SBarry Smith /*
248b2f1ab58SBarry Smith   spbas_compress_pattern:
249b2f1ab58SBarry Smith      calculate a compressed sparseness pattern for a sparseness pattern
250b2f1ab58SBarry Smith      given in compressed row storage. The compressed sparseness pattern may
251b2f1ab58SBarry Smith      require (much) less memory.
252b2f1ab58SBarry Smith */
2534e1ff37aSBarry Smith PetscErrorCode spbas_compress_pattern(PetscInt *irow_in, PetscInt *icol_in, PetscInt nrows, PetscInt ncols, PetscInt col_idx_type, spbas_matrix *B,PetscReal *mem_reduction)
254b2f1ab58SBarry Smith {
255b2f1ab58SBarry Smith   PetscInt        nnz      = irow_in[nrows];
2563dfa2556SBarry Smith   size_t          mem_orig = (nrows + nnz) * sizeof(PetscInt);
2573dfa2556SBarry Smith   size_t          mem_compressed;
258b2f1ab58SBarry Smith   PetscErrorCode  ierr;
259b2f1ab58SBarry Smith   PetscInt        *isort;
260b2f1ab58SBarry Smith   PetscInt        *icols;
261b2f1ab58SBarry Smith   PetscInt        row_nnz;
262b2f1ab58SBarry Smith   PetscInt        *ipoint;
263ace3abfcSBarry Smith   PetscBool       *used;
264b2f1ab58SBarry Smith   PetscInt        ptr;
265b2f1ab58SBarry Smith   PetscInt        i,j;
266ace3abfcSBarry Smith   const PetscBool no_values = PETSC_FALSE;
267b2f1ab58SBarry Smith 
268b2f1ab58SBarry Smith   PetscFunctionBegin;
269c328eeadSBarry Smith   /* Allocate the structure of the new matrix */
270b2f1ab58SBarry Smith   B->nrows        = nrows;
271b2f1ab58SBarry Smith   B->ncols        = ncols;
272b2f1ab58SBarry Smith   B->nnz          = nnz;
273b2f1ab58SBarry Smith   B->col_idx_type = col_idx_type;
274b2f1ab58SBarry Smith   B->block_data   = PETSC_TRUE;
2752205254eSKarl Rupp 
276b2f1ab58SBarry Smith   ierr = spbas_allocate_pattern(B, no_values);CHKERRQ(ierr);
277b2f1ab58SBarry Smith 
278c328eeadSBarry Smith   /* When using an offset array, set it */
2794e1ff37aSBarry Smith   if (col_idx_type==SPBAS_OFFSET_ARRAY)  {
2802205254eSKarl Rupp     for (i=0; i<nrows; i++) B->icol0[i] = icol_in[irow_in[i]];
281b2f1ab58SBarry Smith   }
282b2f1ab58SBarry Smith 
283c328eeadSBarry Smith   /* Allocate the ordering for the rows */
284785e854fSJed Brown   ierr = PetscMalloc1(nrows,&isort);CHKERRQ(ierr);
285785e854fSJed Brown   ierr = PetscMalloc1(nrows,&ipoint);CHKERRQ(ierr);
286785e854fSJed Brown   ierr = PetscMalloc1(nrows,&used);CHKERRQ(ierr);
287b2f1ab58SBarry Smith 
288c328eeadSBarry Smith   /*  Initialize the sorting */
289ace3abfcSBarry Smith   ierr = PetscMemzero((void*) used, nrows*sizeof(PetscBool));CHKERRQ(ierr);
2904e1ff37aSBarry Smith   for (i = 0; i<nrows; i++)  {
291b2f1ab58SBarry Smith     B->row_nnz[i] = irow_in[i+1]-irow_in[i];
292b2f1ab58SBarry Smith     isort[i]      = i;
293b2f1ab58SBarry Smith     ipoint[i]     = i;
294b2f1ab58SBarry Smith   }
295b2f1ab58SBarry Smith 
296c328eeadSBarry Smith   /* Sort the rows so that identical columns will be next to each other */
297b2f1ab58SBarry Smith   ierr = spbas_mergesort_icols(nrows, irow_in, icol_in, col_idx_type, isort);CHKERRQ(ierr);
2980298fd71SBarry Smith   ierr = PetscInfo(NULL,"Rows have been sorted for patterns\n");CHKERRQ(ierr);
299b2f1ab58SBarry Smith 
300c328eeadSBarry Smith   /* Replace identical rows with the first one in the list */
3014e1ff37aSBarry Smith   for (i=1; i<nrows; i++) {
3024e1ff37aSBarry Smith     if (spbas_row_order_icol(isort[i-1], isort[i], irow_in, icol_in, col_idx_type) == 0) {
303b2f1ab58SBarry Smith       ipoint[isort[i]] = ipoint[isort[i-1]];
304b2f1ab58SBarry Smith     }
305b2f1ab58SBarry Smith   }
306b2f1ab58SBarry Smith 
307c328eeadSBarry Smith   /* Collect the rows which are used*/
3082205254eSKarl Rupp   for (i=0; i<nrows; i++) used[ipoint[i]] = PETSC_TRUE;
309b2f1ab58SBarry Smith 
310c328eeadSBarry Smith   /* Calculate needed memory */
311b2f1ab58SBarry Smith   B->n_alloc_icol = 0;
3124e1ff37aSBarry Smith   for (i=0; i<nrows; i++)  {
3132205254eSKarl Rupp     if (used[i]) B->n_alloc_icol += B->row_nnz[i];
314b2f1ab58SBarry Smith   }
315785e854fSJed Brown   ierr = PetscMalloc1(B->n_alloc_icol,&B->alloc_icol);CHKERRQ(ierr);
316b2f1ab58SBarry Smith 
317c328eeadSBarry Smith   /* Fill in the diagonal offsets for the rows which store their own data */
318b2f1ab58SBarry Smith   ptr = 0;
3194e1ff37aSBarry Smith   for (i=0; i<B->nrows; i++) {
3204e1ff37aSBarry Smith     if (used[i]) {
321b2f1ab58SBarry Smith       B->icols[i] = &B->alloc_icol[ptr];
322b2f1ab58SBarry Smith       icols = &icol_in[irow_in[i]];
323b2f1ab58SBarry Smith       row_nnz = B->row_nnz[i];
3244e1ff37aSBarry Smith       if (col_idx_type == SPBAS_COLUMN_NUMBERS) {
3254e1ff37aSBarry Smith         for (j=0; j<row_nnz; j++) {
326b2f1ab58SBarry Smith           B->icols[i][j] = icols[j];
327b2f1ab58SBarry Smith         }
3284e1ff37aSBarry Smith       } else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) {
3294e1ff37aSBarry Smith         for (j=0; j<row_nnz; j++) {
330b2f1ab58SBarry Smith           B->icols[i][j] = icols[j]-i;
331b2f1ab58SBarry Smith         }
3324e1ff37aSBarry Smith       } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
3334e1ff37aSBarry Smith         for (j=0; j<row_nnz; j++) {
334b2f1ab58SBarry Smith           B->icols[i][j] = icols[j]-icols[0];
335b2f1ab58SBarry Smith         }
336b2f1ab58SBarry Smith       }
337b2f1ab58SBarry Smith       ptr += B->row_nnz[i];
338b2f1ab58SBarry Smith     }
339b2f1ab58SBarry Smith   }
340b2f1ab58SBarry Smith 
341c328eeadSBarry Smith   /* Point to the right places for all data */
3424e1ff37aSBarry Smith   for (i=0; i<nrows; i++) {
343b2f1ab58SBarry Smith     B->icols[i] = B->icols[ipoint[i]];
344b2f1ab58SBarry Smith   }
3450298fd71SBarry Smith   ierr = PetscInfo(NULL,"Row patterns have been compressed\n");CHKERRQ(ierr);
34657622a8eSBarry Smith   ierr = PetscInfo1(NULL,"         (%g nonzeros per row)\n", (double) ((PetscReal) nnz / (PetscReal) nrows));CHKERRQ(ierr);
347b2f1ab58SBarry Smith 
348b2f1ab58SBarry Smith   ierr=PetscFree(isort);CHKERRQ(ierr);
349b2f1ab58SBarry Smith   ierr=PetscFree(used);CHKERRQ(ierr);
350b2f1ab58SBarry Smith   ierr=PetscFree(ipoint);CHKERRQ(ierr);
351b2f1ab58SBarry Smith 
352b2f1ab58SBarry Smith   mem_compressed = spbas_memory_requirement(*B);
3534e1ff37aSBarry Smith   *mem_reduction = 100.0 * (PetscReal)(mem_orig-mem_compressed)/ (PetscReal) mem_orig;
354b2f1ab58SBarry Smith   PetscFunctionReturn(0);
355b2f1ab58SBarry Smith }
356b2f1ab58SBarry Smith 
357b2f1ab58SBarry Smith /*
358b2f1ab58SBarry Smith    spbas_incomplete_cholesky
359b2f1ab58SBarry Smith        Incomplete Cholesky decomposition
360b2f1ab58SBarry Smith */
361c6db04a5SJed Brown #include <../src/mat/impls/aij/seq/bas/spbas_cholesky.h>
362b2f1ab58SBarry Smith 
363b2f1ab58SBarry Smith /*
364b2f1ab58SBarry Smith   spbas_delete : de-allocate the arrays owned by this matrix
365b2f1ab58SBarry Smith */
366b2f1ab58SBarry Smith PetscErrorCode spbas_delete(spbas_matrix matrix)
367b2f1ab58SBarry Smith {
368b2f1ab58SBarry Smith   PetscInt       i;
369b2f1ab58SBarry Smith   PetscErrorCode ierr;
3709ccc4a9bSBarry Smith 
371b2f1ab58SBarry Smith   PetscFunctionBegin;
3729ccc4a9bSBarry Smith   if (matrix.block_data) {
373cb9801acSJed Brown     ierr=PetscFree(matrix.alloc_icol);CHKERRQ(ierr);
374b2f1ab58SBarry Smith     if (matrix.values) {ierr=PetscFree(matrix.alloc_val);CHKERRQ(ierr);}
3759ccc4a9bSBarry Smith   } else {
3769ccc4a9bSBarry Smith     for (i=0; i<matrix.nrows; i++) { ierr=PetscFree(matrix.icols[i]);CHKERRQ(ierr);}
377b2f1ab58SBarry Smith     ierr = PetscFree(matrix.icols);CHKERRQ(ierr);
3789ccc4a9bSBarry Smith     if (matrix.values) {
3799ccc4a9bSBarry Smith       for (i=0; i<matrix.nrows; i++) { ierr=PetscFree(matrix.values[i]);CHKERRQ(ierr);}
380b2f1ab58SBarry Smith     }
381b2f1ab58SBarry Smith   }
382b2f1ab58SBarry Smith 
383b2f1ab58SBarry Smith   ierr=PetscFree(matrix.row_nnz);CHKERRQ(ierr);
384b2f1ab58SBarry Smith   ierr=PetscFree(matrix.icols);CHKERRQ(ierr);
3859ccc4a9bSBarry Smith   if (matrix.col_idx_type == SPBAS_OFFSET_ARRAY) {ierr=PetscFree(matrix.icol0);CHKERRQ(ierr);}
386c31cb41cSBarry Smith   ierr=PetscFree(matrix.values);CHKERRQ(ierr);
387b2f1ab58SBarry Smith   PetscFunctionReturn(0);
388b2f1ab58SBarry Smith }
389b2f1ab58SBarry Smith 
390b2f1ab58SBarry Smith /*
391b2f1ab58SBarry Smith spbas_matrix_to_crs:
392b2f1ab58SBarry Smith    Convert an spbas_matrix to compessed row storage
393b2f1ab58SBarry Smith */
394b2f1ab58SBarry Smith PetscErrorCode spbas_matrix_to_crs(spbas_matrix matrix_A,MatScalar **val_out, PetscInt **irow_out, PetscInt **icol_out)
395b2f1ab58SBarry Smith {
396b2f1ab58SBarry Smith   PetscInt       nrows = matrix_A.nrows;
397b2f1ab58SBarry Smith   PetscInt       nnz   = matrix_A.nnz;
398b2f1ab58SBarry Smith   PetscInt       i,j,r_nnz,i0;
399b2f1ab58SBarry Smith   PetscInt       *irow;
400b2f1ab58SBarry Smith   PetscInt       *icol;
401b2f1ab58SBarry Smith   PetscInt       *icol_A;
402b2f1ab58SBarry Smith   MatScalar      *val;
403b2f1ab58SBarry Smith   PetscScalar    *val_A;
404b2f1ab58SBarry Smith   PetscInt       col_idx_type = matrix_A.col_idx_type;
405ace3abfcSBarry Smith   PetscBool      do_values    = matrix_A.values ? PETSC_TRUE : PETSC_FALSE;
406b2f1ab58SBarry Smith   PetscErrorCode ierr;
407b2f1ab58SBarry Smith 
408b2f1ab58SBarry Smith   PetscFunctionBegin;
409854ce69bSBarry Smith   ierr      = PetscMalloc1(nrows+1, &irow);CHKERRQ(ierr);
410854ce69bSBarry Smith   ierr      = PetscMalloc1(nnz, &icol);CHKERRQ(ierr);
4119ccc4a9bSBarry Smith   *icol_out = icol;
4129ccc4a9bSBarry Smith   *irow_out = irow;
4139ccc4a9bSBarry Smith   if (do_values) {
414854ce69bSBarry Smith     ierr     = PetscMalloc1(nnz, &val);CHKERRQ(ierr);
415b2f1ab58SBarry Smith     *val_out = val; *icol_out = icol; *irow_out=irow;
416b2f1ab58SBarry Smith   }
417b2f1ab58SBarry Smith 
418b2f1ab58SBarry Smith   irow[0]=0;
4199ccc4a9bSBarry Smith   for (i=0; i<nrows; i++) {
420b2f1ab58SBarry Smith     r_nnz     = matrix_A.row_nnz[i];
421b2f1ab58SBarry Smith     i0        = irow[i];
422b2f1ab58SBarry Smith     irow[i+1] = i0 + r_nnz;
423b2f1ab58SBarry Smith     icol_A    = matrix_A.icols[i];
424b2f1ab58SBarry Smith 
4259ccc4a9bSBarry Smith     if (do_values) {
426b2f1ab58SBarry Smith       val_A = matrix_A.values[i];
4279ccc4a9bSBarry Smith       for (j=0; j<r_nnz; j++) {
428b2f1ab58SBarry Smith         icol[i0+j] = icol_A[j];
429b2f1ab58SBarry Smith         val[i0+j]  = val_A[j];
430b2f1ab58SBarry Smith       }
4319ccc4a9bSBarry Smith     } else {
4322205254eSKarl Rupp       for (j=0; j<r_nnz; j++) icol[i0+j] = icol_A[j];
433b2f1ab58SBarry Smith     }
434b2f1ab58SBarry Smith 
4359ccc4a9bSBarry Smith     if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) {
4362205254eSKarl Rupp       for (j=0; j<r_nnz; j++) icol[i0+j] += i;
4372205254eSKarl Rupp     } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
438b2f1ab58SBarry Smith       i0 = matrix_A.icol0[i];
4392205254eSKarl Rupp       for (j=0; j<r_nnz; j++) icol[i0+j] += i0;
440b2f1ab58SBarry Smith     }
441b2f1ab58SBarry Smith   }
442b2f1ab58SBarry Smith   PetscFunctionReturn(0);
443b2f1ab58SBarry Smith }
444b2f1ab58SBarry Smith 
445b2f1ab58SBarry Smith 
446b2f1ab58SBarry Smith /*
447b2f1ab58SBarry Smith     spbas_transpose
448b2f1ab58SBarry Smith        return the transpose of a matrix
449b2f1ab58SBarry Smith */
450b2f1ab58SBarry Smith PetscErrorCode spbas_transpose(spbas_matrix in_matrix, spbas_matrix * result)
451b2f1ab58SBarry Smith {
452b2f1ab58SBarry Smith   PetscInt       col_idx_type = in_matrix.col_idx_type;
453b2f1ab58SBarry Smith   PetscInt       nnz          = in_matrix.nnz;
454b2f1ab58SBarry Smith   PetscInt       ncols        = in_matrix.nrows;
455b2f1ab58SBarry Smith   PetscInt       nrows        = in_matrix.ncols;
456b2f1ab58SBarry Smith   PetscInt       i,j,k;
457b2f1ab58SBarry Smith   PetscInt       r_nnz;
458b2f1ab58SBarry Smith   PetscInt       *irow;
4594efc9174SBarry Smith   PetscInt       icol0 = 0;
460b2f1ab58SBarry Smith   PetscScalar    * val;
461b2f1ab58SBarry Smith   PetscErrorCode ierr;
4624e1ff37aSBarry Smith 
463b2f1ab58SBarry Smith   PetscFunctionBegin;
464c328eeadSBarry Smith   /* Copy input values */
465b2f1ab58SBarry Smith   result->nrows        = nrows;
466b2f1ab58SBarry Smith   result->ncols        = ncols;
467b2f1ab58SBarry Smith   result->nnz          = nnz;
468b2f1ab58SBarry Smith   result->col_idx_type = SPBAS_COLUMN_NUMBERS;
469b2f1ab58SBarry Smith   result->block_data   = PETSC_TRUE;
470b2f1ab58SBarry Smith 
471c328eeadSBarry Smith   /* Allocate sparseness pattern */
47271d55d18SBarry Smith   ierr =  spbas_allocate_pattern(result, in_matrix.values ? PETSC_TRUE : PETSC_FALSE);CHKERRQ(ierr);
473b2f1ab58SBarry Smith 
474c328eeadSBarry Smith   /*  Count the number of nonzeros in each row */
4752205254eSKarl Rupp   for (i = 0; i<nrows; i++) result->row_nnz[i] = 0;
476b2f1ab58SBarry Smith 
4779ccc4a9bSBarry Smith   for (i=0; i<ncols; i++) {
478b2f1ab58SBarry Smith     r_nnz = in_matrix.row_nnz[i];
479b2f1ab58SBarry Smith     irow  = in_matrix.icols[i];
4809ccc4a9bSBarry Smith     if (col_idx_type == SPBAS_COLUMN_NUMBERS)  {
4812205254eSKarl Rupp       for (j=0; j<r_nnz; j++) result->row_nnz[irow[j]]++;
4829ccc4a9bSBarry Smith     } else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS)  {
4832205254eSKarl Rupp       for (j=0; j<r_nnz; j++) result->row_nnz[i+irow[j]]++;
4849ccc4a9bSBarry Smith     } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
485b2f1ab58SBarry Smith       icol0=in_matrix.icol0[i];
4862205254eSKarl Rupp       for (j=0; j<r_nnz; j++) result->row_nnz[icol0+irow[j]]++;
487b2f1ab58SBarry Smith     }
488b2f1ab58SBarry Smith   }
489b2f1ab58SBarry Smith 
490c328eeadSBarry Smith   /* Set the pointers to the data */
491b2f1ab58SBarry Smith   ierr = spbas_allocate_data(result);CHKERRQ(ierr);
492b2f1ab58SBarry Smith 
493c328eeadSBarry Smith   /* Reset the number of nonzeros in each row */
4942205254eSKarl Rupp   for (i = 0; i<nrows; i++) result->row_nnz[i] = 0;
495b2f1ab58SBarry Smith 
496c328eeadSBarry Smith   /* Fill the data arrays */
4979ccc4a9bSBarry Smith   if (in_matrix.values) {
4989ccc4a9bSBarry Smith     for (i=0; i<ncols; i++) {
499b2f1ab58SBarry Smith       r_nnz = in_matrix.row_nnz[i];
500b2f1ab58SBarry Smith       irow  = in_matrix.icols[i];
501b2f1ab58SBarry Smith       val   = in_matrix.values[i];
502b2f1ab58SBarry Smith 
5032205254eSKarl Rupp       if      (col_idx_type == SPBAS_COLUMN_NUMBERS)   icol0 = 0;
5042205254eSKarl Rupp       else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) icol0 = i;
5052205254eSKarl Rupp       else if (col_idx_type == SPBAS_OFFSET_ARRAY)     icol0 = in_matrix.icol0[i];
5069ccc4a9bSBarry Smith       for (j=0; j<r_nnz; j++)  {
507b2f1ab58SBarry Smith         k = icol0 + irow[j];
508b2f1ab58SBarry Smith         result->icols[k][result->row_nnz[k]]  = i;
509b2f1ab58SBarry Smith         result->values[k][result->row_nnz[k]] = val[j];
510b2f1ab58SBarry Smith         result->row_nnz[k]++;
511b2f1ab58SBarry Smith       }
512b2f1ab58SBarry Smith     }
5139ccc4a9bSBarry Smith   } else {
5149ccc4a9bSBarry Smith     for (i=0; i<ncols; i++) {
515b2f1ab58SBarry Smith       r_nnz = in_matrix.row_nnz[i];
516b2f1ab58SBarry Smith       irow  = in_matrix.icols[i];
517b2f1ab58SBarry Smith 
5182205254eSKarl Rupp       if      (col_idx_type == SPBAS_COLUMN_NUMBERS)   icol0=0;
5192205254eSKarl Rupp       else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) icol0=i;
5202205254eSKarl Rupp       else if (col_idx_type == SPBAS_OFFSET_ARRAY)     icol0=in_matrix.icol0[i];
521b2f1ab58SBarry Smith 
5229ccc4a9bSBarry Smith       for (j=0; j<r_nnz; j++) {
523b2f1ab58SBarry Smith         k = icol0 + irow[j];
524b2f1ab58SBarry Smith         result->icols[k][result->row_nnz[k]] = i;
525b2f1ab58SBarry Smith         result->row_nnz[k]++;
526b2f1ab58SBarry Smith       }
527b2f1ab58SBarry Smith     }
528b2f1ab58SBarry Smith   }
529b2f1ab58SBarry Smith   PetscFunctionReturn(0);
530b2f1ab58SBarry Smith }
531b2f1ab58SBarry Smith 
532b2f1ab58SBarry Smith /*
533b2f1ab58SBarry Smith    spbas_mergesort
534b2f1ab58SBarry Smith 
535*bb42e86aSJed Brown       mergesort for an array of integers and an array of associated
536b2f1ab58SBarry Smith       reals
537b2f1ab58SBarry Smith 
538b2f1ab58SBarry Smith       on output, icol[0..nnz-1] is increasing;
539b2f1ab58SBarry Smith                   val[0..nnz-1] has undergone the same permutation as icol
540b2f1ab58SBarry Smith 
5410298fd71SBarry Smith       NB: val may be NULL: in that case, only the integers are sorted
542b2f1ab58SBarry Smith 
543b2f1ab58SBarry Smith */
544b2f1ab58SBarry Smith PetscErrorCode spbas_mergesort(PetscInt nnz, PetscInt *icol, PetscScalar *val)
545b2f1ab58SBarry Smith {
546c328eeadSBarry Smith   PetscInt       istep;       /* Chunk-sizes of already sorted parts of arrays */
547c328eeadSBarry Smith   PetscInt       i, i1, i2;   /* Loop counters for (partly) sorted arrays */
548c328eeadSBarry Smith   PetscInt       istart, i1end, i2end; /* start of newly sorted array part, end of both parts */
549c328eeadSBarry Smith   PetscInt       *ialloc;     /* Allocated arrays */
5500298fd71SBarry Smith   PetscScalar    *valloc=NULL;
551c328eeadSBarry Smith   PetscInt       *iswap;      /* auxiliary pointers for swapping */
552b2f1ab58SBarry Smith   PetscScalar    *vswap;
553c328eeadSBarry Smith   PetscInt       *ihlp1;      /* Pointers to new version of arrays, */
5540298fd71SBarry Smith   PetscScalar    *vhlp1=NULL;  /* (arrays under construction) */
555c328eeadSBarry Smith   PetscInt       *ihlp2;      /* Pointers to previous version of arrays, */
5560298fd71SBarry Smith   PetscScalar    *vhlp2=NULL;
557b2f1ab58SBarry Smith   PetscErrorCode ierr;
558b2f1ab58SBarry Smith 
559785e854fSJed Brown   ierr  = PetscMalloc1(nnz,&ialloc);CHKERRQ(ierr);
560b2f1ab58SBarry Smith   ihlp1 = ialloc;
561b2f1ab58SBarry Smith   ihlp2 = icol;
562b2f1ab58SBarry Smith 
5639ccc4a9bSBarry Smith   if (val) {
564785e854fSJed Brown     ierr  = PetscMalloc1(nnz,&valloc);CHKERRQ(ierr);
565b2f1ab58SBarry Smith     vhlp1 = valloc;
566b2f1ab58SBarry Smith     vhlp2 = val;
567b2f1ab58SBarry Smith   }
568b2f1ab58SBarry Smith 
569b2f1ab58SBarry Smith 
570c328eeadSBarry Smith   /* Sorted array chunks are first 1 long, and increase until they are the complete array */
5719ccc4a9bSBarry Smith   for (istep=1; istep<nnz; istep*=2) {
572c328eeadSBarry Smith     /*
573c328eeadSBarry Smith       Combine sorted parts
574c328eeadSBarry Smith           istart:istart+istep-1 and istart+istep-1:istart+2*istep-1
575c328eeadSBarry Smith       of ihlp2 and vhlp2
576c328eeadSBarry Smith 
577c328eeadSBarry Smith       into one sorted part
578c328eeadSBarry Smith           istart:istart+2*istep-1
579c328eeadSBarry Smith       of ihlp1 and vhlp1
580c328eeadSBarry Smith     */
5819ccc4a9bSBarry Smith     for (istart=0; istart<nnz; istart+=2*istep) {
582c328eeadSBarry Smith       /* Set counters and bound array part endings */
5832205254eSKarl Rupp       i1=istart;        i1end = i1+istep;  if (i1end>nnz) i1end=nnz;
5842205254eSKarl Rupp       i2=istart+istep;  i2end = i2+istep;  if (i2end>nnz) i2end=nnz;
585b2f1ab58SBarry Smith 
586c328eeadSBarry Smith       /* Merge the two array parts */
5879ccc4a9bSBarry Smith       if (val) {
5889ccc4a9bSBarry Smith         for (i=istart; i<i2end; i++) {
5899ccc4a9bSBarry Smith           if (i1<i1end && i2<i2end && ihlp2[i1] < ihlp2[i2]) {
590b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i1];
591b2f1ab58SBarry Smith             vhlp1[i] = vhlp2[i1];
592b2f1ab58SBarry Smith             i1++;
5939ccc4a9bSBarry Smith           } else if (i2<i2end) {
594b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i2];
595b2f1ab58SBarry Smith             vhlp1[i] = vhlp2[i2];
596b2f1ab58SBarry Smith             i2++;
5979ccc4a9bSBarry Smith           } else {
598b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i1];
599b2f1ab58SBarry Smith             vhlp1[i] = vhlp2[i1];
600b2f1ab58SBarry Smith             i1++;
601b2f1ab58SBarry Smith           }
602b2f1ab58SBarry Smith         }
6039ccc4a9bSBarry Smith       } else {
6046322f4bdSBarry Smith         for (i=istart; i<i2end; i++) {
6056322f4bdSBarry Smith           if (i1<i1end && i2<i2end && ihlp2[i1] < ihlp2[i2]) {
606b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i1];
607b2f1ab58SBarry Smith             i1++;
6086322f4bdSBarry Smith           } else if (i2<i2end) {
609b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i2];
610b2f1ab58SBarry Smith             i2++;
6116322f4bdSBarry Smith           } else {
612b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i1];
613b2f1ab58SBarry Smith             i1++;
614b2f1ab58SBarry Smith           }
615b2f1ab58SBarry Smith         }
616b2f1ab58SBarry Smith       }
617b2f1ab58SBarry Smith     }
618b2f1ab58SBarry Smith 
619c328eeadSBarry Smith     /* Swap the two array sets */
620b2f1ab58SBarry Smith     iswap = ihlp2; ihlp2 = ihlp1; ihlp1 = iswap;
621b2f1ab58SBarry Smith     vswap = vhlp2; vhlp2 = vhlp1; vhlp1 = vswap;
622b2f1ab58SBarry Smith   }
623b2f1ab58SBarry Smith 
624c328eeadSBarry Smith   /* Copy one more time in case the sorted arrays are the temporary ones */
6256322f4bdSBarry Smith   if (ihlp2 != icol) {
6262205254eSKarl Rupp     for (i=0; i<nnz; i++) icol[i] = ihlp2[i];
6276322f4bdSBarry Smith     if (val) {
6282205254eSKarl Rupp       for (i=0; i<nnz; i++) val[i] = vhlp2[i];
629b2f1ab58SBarry Smith     }
630b2f1ab58SBarry Smith   }
631b2f1ab58SBarry Smith 
632b2f1ab58SBarry Smith   ierr = PetscFree(ialloc);CHKERRQ(ierr);
633b2f1ab58SBarry Smith   if (val) {ierr = PetscFree(valloc);CHKERRQ(ierr);}
634b2f1ab58SBarry Smith   PetscFunctionReturn(0);
635b2f1ab58SBarry Smith }
636b2f1ab58SBarry Smith 
637b2f1ab58SBarry Smith /*
638b2f1ab58SBarry Smith   spbas_apply_reordering_rows:
639b2f1ab58SBarry Smith     apply the given reordering to the rows:  matrix_A = matrix_A(perm,:);
640b2f1ab58SBarry Smith */
641b2f1ab58SBarry Smith PetscErrorCode spbas_apply_reordering_rows(spbas_matrix *matrix_A, const PetscInt *permutation)
642b2f1ab58SBarry Smith {
643b2f1ab58SBarry Smith   PetscInt       i,j,ip;
644b2f1ab58SBarry Smith   PetscInt       nrows=matrix_A->nrows;
645b2f1ab58SBarry Smith   PetscInt       * row_nnz;
646b2f1ab58SBarry Smith   PetscInt       **icols;
647ace3abfcSBarry Smith   PetscBool      do_values = matrix_A->values ? PETSC_TRUE : PETSC_FALSE;
6480298fd71SBarry Smith   PetscScalar    **vals    = NULL;
649b2f1ab58SBarry Smith   PetscErrorCode ierr;
650b2f1ab58SBarry Smith 
651b2f1ab58SBarry Smith   PetscFunctionBegin;
652e32f2f54SBarry Smith   if (matrix_A->col_idx_type != SPBAS_DIAGONAL_OFFSETS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS,"must have diagonal offsets in pattern\n");
653b2f1ab58SBarry Smith 
6546322f4bdSBarry Smith   if (do_values) {
655854ce69bSBarry Smith     ierr = PetscMalloc1(nrows, &vals);CHKERRQ(ierr);
656b2f1ab58SBarry Smith   }
657854ce69bSBarry Smith   ierr = PetscMalloc1(nrows, &row_nnz);CHKERRQ(ierr);
658854ce69bSBarry Smith   ierr = PetscMalloc1(nrows, &icols);CHKERRQ(ierr);
659b2f1ab58SBarry Smith 
6606322f4bdSBarry Smith   for (i=0; i<nrows; i++) {
661b2f1ab58SBarry Smith     ip = permutation[i];
6622205254eSKarl Rupp     if (do_values) vals[i] = matrix_A->values[ip];
663b2f1ab58SBarry Smith     icols[i]   = matrix_A->icols[ip];
664b2f1ab58SBarry Smith     row_nnz[i] = matrix_A->row_nnz[ip];
6652205254eSKarl Rupp     for (j=0; j<row_nnz[i]; j++) icols[i][j] += ip-i;
666b2f1ab58SBarry Smith   }
667b2f1ab58SBarry Smith 
668b2f1ab58SBarry Smith   if (do_values) { ierr = PetscFree(matrix_A->values);CHKERRQ(ierr);}
669b2f1ab58SBarry Smith   ierr = PetscFree(matrix_A->icols);CHKERRQ(ierr);
670b2f1ab58SBarry Smith   ierr = PetscFree(matrix_A->row_nnz);CHKERRQ(ierr);
671b2f1ab58SBarry Smith 
6722205254eSKarl Rupp   if (do_values) matrix_A->values = vals;
673b2f1ab58SBarry Smith   matrix_A->icols   = icols;
674b2f1ab58SBarry Smith   matrix_A->row_nnz = row_nnz;
675b2f1ab58SBarry Smith   PetscFunctionReturn(0);
676b2f1ab58SBarry Smith }
677b2f1ab58SBarry Smith 
678b2f1ab58SBarry Smith 
679b2f1ab58SBarry Smith /*
680b2f1ab58SBarry Smith   spbas_apply_reordering_cols:
681b2f1ab58SBarry Smith     apply the given reordering to the columns:  matrix_A(:,perm) = matrix_A;
682b2f1ab58SBarry Smith */
683b2f1ab58SBarry Smith PetscErrorCode spbas_apply_reordering_cols(spbas_matrix *matrix_A,const PetscInt *permutation)
684b2f1ab58SBarry Smith {
685b2f1ab58SBarry Smith   PetscInt       i,j;
686b2f1ab58SBarry Smith   PetscInt       nrows=matrix_A->nrows;
687b2f1ab58SBarry Smith   PetscInt       row_nnz;
688b2f1ab58SBarry Smith   PetscInt       *icols;
689ace3abfcSBarry Smith   PetscBool      do_values = matrix_A->values ? PETSC_TRUE : PETSC_FALSE;
6900298fd71SBarry Smith   PetscScalar    *vals     = NULL;
691b2f1ab58SBarry Smith   PetscErrorCode ierr;
692b2f1ab58SBarry Smith 
693b2f1ab58SBarry Smith   PetscFunctionBegin;
694e32f2f54SBarry Smith   if (matrix_A->col_idx_type != SPBAS_DIAGONAL_OFFSETS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "must have diagonal offsets in pattern\n");
695b2f1ab58SBarry Smith 
6966322f4bdSBarry Smith   for (i=0; i<nrows; i++) {
697b2f1ab58SBarry Smith     icols   = matrix_A->icols[i];
698b2f1ab58SBarry Smith     row_nnz = matrix_A->row_nnz[i];
6992205254eSKarl Rupp     if (do_values) vals = matrix_A->values[i];
700b2f1ab58SBarry Smith 
7016322f4bdSBarry Smith     for (j=0; j<row_nnz; j++) {
702b2f1ab58SBarry Smith       icols[j] = permutation[i+icols[j]]-i;
703b2f1ab58SBarry Smith     }
704b2f1ab58SBarry Smith     ierr = spbas_mergesort(row_nnz, icols, vals);CHKERRQ(ierr);
705b2f1ab58SBarry Smith   }
706b2f1ab58SBarry Smith   PetscFunctionReturn(0);
707b2f1ab58SBarry Smith }
708b2f1ab58SBarry Smith 
709b2f1ab58SBarry Smith /*
710b2f1ab58SBarry Smith   spbas_apply_reordering:
711b2f1ab58SBarry Smith     apply the given reordering:  matrix_A(perm,perm) = matrix_A;
712b2f1ab58SBarry Smith */
713b2f1ab58SBarry Smith PetscErrorCode spbas_apply_reordering(spbas_matrix *matrix_A, const PetscInt *permutation, const PetscInt * inv_perm)
714b2f1ab58SBarry Smith {
715b2f1ab58SBarry Smith   PetscErrorCode ierr;
7165fd66863SKarl Rupp 
717b2f1ab58SBarry Smith   PetscFunctionBegin;
718b2f1ab58SBarry Smith   ierr = spbas_apply_reordering_rows(matrix_A, inv_perm);CHKERRQ(ierr);
719b2f1ab58SBarry Smith   ierr = spbas_apply_reordering_cols(matrix_A, permutation);CHKERRQ(ierr);
720b2f1ab58SBarry Smith   PetscFunctionReturn(0);
721b2f1ab58SBarry Smith }
722b2f1ab58SBarry Smith 
723b2f1ab58SBarry Smith PetscErrorCode spbas_pattern_only(PetscInt nrows, PetscInt ncols, PetscInt *ai, PetscInt *aj, spbas_matrix * result)
724b2f1ab58SBarry Smith {
725b2f1ab58SBarry Smith   spbas_matrix   retval;
726b2f1ab58SBarry Smith   PetscInt       i, j, i0, r_nnz;
727b2f1ab58SBarry Smith   PetscErrorCode ierr;
728b2f1ab58SBarry Smith 
729b2f1ab58SBarry Smith   PetscFunctionBegin;
730c328eeadSBarry Smith   /* Copy input values */
731b2f1ab58SBarry Smith   retval.nrows = nrows;
732b2f1ab58SBarry Smith   retval.ncols = ncols;
733b2f1ab58SBarry Smith   retval.nnz   = ai[nrows];
734b2f1ab58SBarry Smith 
735b2f1ab58SBarry Smith   retval.block_data   = PETSC_TRUE;
736b2f1ab58SBarry Smith   retval.col_idx_type = SPBAS_DIAGONAL_OFFSETS;
737b2f1ab58SBarry Smith 
738c328eeadSBarry Smith   /* Allocate output matrix */
739b2f1ab58SBarry Smith   ierr = spbas_allocate_pattern(&retval, PETSC_FALSE);CHKERRQ(ierr);
7402205254eSKarl Rupp   for (i=0; i<nrows; i++) retval.row_nnz[i] = ai[i+1]-ai[i];
741b2f1ab58SBarry Smith   ierr = spbas_allocate_data(&retval);CHKERRQ(ierr);
742c328eeadSBarry Smith   /* Copy the structure */
7436322f4bdSBarry Smith   for (i = 0; i<retval.nrows; i++)  {
744b2f1ab58SBarry Smith     i0    = ai[i];
745b2f1ab58SBarry Smith     r_nnz = ai[i+1]-i0;
746b2f1ab58SBarry Smith 
7476322f4bdSBarry Smith     for (j=0; j<r_nnz; j++) {
748b2f1ab58SBarry Smith       retval.icols[i][j] = aj[i0+j]-i;
749b2f1ab58SBarry Smith     }
750b2f1ab58SBarry Smith   }
751b2f1ab58SBarry Smith   *result = retval;
752b2f1ab58SBarry Smith   PetscFunctionReturn(0);
753b2f1ab58SBarry Smith }
754b2f1ab58SBarry Smith 
755b2f1ab58SBarry Smith 
756b2f1ab58SBarry Smith /*
757b2f1ab58SBarry Smith    spbas_mark_row_power:
758b2f1ab58SBarry Smith       Mark the columns in row 'row' which are nonzero in
759b2f1ab58SBarry Smith           matrix^2log(marker).
760b2f1ab58SBarry Smith */
761be332245SKarl Rupp PetscErrorCode spbas_mark_row_power(PetscInt *iwork,             /* marker-vector */
762c328eeadSBarry Smith                                     PetscInt row,                /* row for which the columns are marked */
763c328eeadSBarry Smith                                     spbas_matrix * in_matrix,    /* matrix for which the power is being  calculated */
764c328eeadSBarry Smith                                     PetscInt marker,             /* marker-value: 2^power */
765c328eeadSBarry Smith                                     PetscInt minmrk,             /* lower bound for marked points */
766c328eeadSBarry Smith                                     PetscInt maxmrk)             /* upper bound for marked points */
767b2f1ab58SBarry Smith {
768b2f1ab58SBarry Smith   PetscErrorCode ierr;
769b2f1ab58SBarry Smith   PetscInt       i,j, nnz;
770b2f1ab58SBarry Smith 
771b2f1ab58SBarry Smith   PetscFunctionBegin;
772b2f1ab58SBarry Smith   nnz = in_matrix->row_nnz[row];
773b2f1ab58SBarry Smith 
774c328eeadSBarry Smith   /* For higher powers, call this function recursively */
7756322f4bdSBarry Smith   if (marker>1) {
7766322f4bdSBarry Smith     for (i=0; i<nnz; i++) {
777b2f1ab58SBarry Smith       j = row + in_matrix->icols[row][i];
7786322f4bdSBarry Smith       if (minmrk<=j && j<maxmrk && iwork[j] < marker) {
77971d55d18SBarry Smith         ierr      = spbas_mark_row_power(iwork, row + in_matrix->icols[row][i],in_matrix, marker/2,minmrk,maxmrk);CHKERRQ(ierr);
780b2f1ab58SBarry Smith         iwork[j] |= marker;
781b2f1ab58SBarry Smith       }
782b2f1ab58SBarry Smith     }
7836322f4bdSBarry Smith   } else {
784c328eeadSBarry Smith     /*  Mark the columns reached */
7856322f4bdSBarry Smith     for (i=0; i<nnz; i++)  {
786b2f1ab58SBarry Smith       j = row + in_matrix->icols[row][i];
7872205254eSKarl Rupp       if (minmrk<=j && j<maxmrk) iwork[j] |= 1;
788b2f1ab58SBarry Smith     }
789b2f1ab58SBarry Smith   }
790b2f1ab58SBarry Smith   PetscFunctionReturn(0);
791b2f1ab58SBarry Smith }
792b2f1ab58SBarry Smith 
793b2f1ab58SBarry Smith 
794b2f1ab58SBarry Smith /*
795b2f1ab58SBarry Smith    spbas_power
796b2f1ab58SBarry Smith       Calculate sparseness patterns for incomplete Cholesky decompositions
797b2f1ab58SBarry Smith       of a given order: (almost) all nonzeros of the matrix^(order+1) which
798b2f1ab58SBarry Smith       are inside the band width are found and stored in the output sparseness
799b2f1ab58SBarry Smith       pattern.
800b2f1ab58SBarry Smith */
801b2f1ab58SBarry Smith PetscErrorCode spbas_power(spbas_matrix in_matrix,PetscInt power, spbas_matrix * result)
802b2f1ab58SBarry Smith {
803b2f1ab58SBarry Smith   spbas_matrix   retval;
804b2f1ab58SBarry Smith   PetscInt       nrows = in_matrix.nrows;
805b2f1ab58SBarry Smith   PetscInt       ncols = in_matrix.ncols;
806b2f1ab58SBarry Smith   PetscInt       i, j, kend;
807b2f1ab58SBarry Smith   PetscInt       nnz, inz;
808b2f1ab58SBarry Smith   PetscInt       *iwork;
809b2f1ab58SBarry Smith   PetscInt       marker;
810b2f1ab58SBarry Smith   PetscInt       maxmrk=0;
811b2f1ab58SBarry Smith   PetscErrorCode ierr;
812b2f1ab58SBarry Smith 
813b2f1ab58SBarry Smith   PetscFunctionBegin;
814e32f2f54SBarry Smith   if (in_matrix.col_idx_type != SPBAS_DIAGONAL_OFFSETS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS,"must have diagonal offsets in pattern\n");
815e32f2f54SBarry Smith   if (ncols != nrows) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Dimension error\n");
816e32f2f54SBarry Smith   if (in_matrix.values) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Input array must be sparseness pattern (no values)");
817e32f2f54SBarry Smith   if (power<=0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Power must be 1 or up");
818b2f1ab58SBarry Smith 
819c328eeadSBarry Smith   /* Copy input values*/
820b2f1ab58SBarry Smith   retval.nrows        = ncols;
821b2f1ab58SBarry Smith   retval.ncols        = nrows;
822b2f1ab58SBarry Smith   retval.nnz          = 0;
823b2f1ab58SBarry Smith   retval.col_idx_type = SPBAS_DIAGONAL_OFFSETS;
824b2f1ab58SBarry Smith   retval.block_data   = PETSC_FALSE;
825b2f1ab58SBarry Smith 
826c328eeadSBarry Smith   /* Allocate sparseness pattern */
82771d55d18SBarry Smith   ierr =  spbas_allocate_pattern(&retval, in_matrix.values ? PETSC_TRUE : PETSC_FALSE);CHKERRQ(ierr);
828b2f1ab58SBarry Smith 
829c328eeadSBarry Smith   /* Allocate marker array */
830785e854fSJed Brown   ierr = PetscMalloc1(nrows, &iwork);CHKERRQ(ierr);
831b2f1ab58SBarry Smith 
832c328eeadSBarry Smith   /* Erase the pattern for this row */
8334e1ff37aSBarry Smith   ierr = PetscMemzero((void*) iwork, retval.nrows*sizeof(PetscInt));CHKERRQ(ierr);
834b2f1ab58SBarry Smith 
835c328eeadSBarry Smith   /* Calculate marker values */
8362205254eSKarl Rupp   marker = 1; for (i=1; i<power; i++) marker*=2;
837b2f1ab58SBarry Smith 
8386322f4bdSBarry Smith   for (i=0; i<nrows; i++)  {
839c328eeadSBarry Smith     /* Calculate the pattern for each row */
840b2f1ab58SBarry Smith 
841b2f1ab58SBarry Smith     nnz  = in_matrix.row_nnz[i];
842b2f1ab58SBarry Smith     kend = i+in_matrix.icols[i][nnz-1];
8432205254eSKarl Rupp     if (maxmrk<=kend) maxmrk=kend+1;
84471d55d18SBarry Smith     ierr = spbas_mark_row_power(iwork, i, &in_matrix, marker, i, maxmrk);CHKERRQ(ierr);
845b2f1ab58SBarry Smith 
846c328eeadSBarry Smith     /* Count the columns*/
847b2f1ab58SBarry Smith     nnz = 0;
8482205254eSKarl Rupp     for (j=i; j<maxmrk; j++) nnz+= (iwork[j]!=0);
849b2f1ab58SBarry Smith 
850c328eeadSBarry Smith     /* Allocate the column indices */
851b2f1ab58SBarry Smith     retval.row_nnz[i] = nnz;
852785e854fSJed Brown     ierr = PetscMalloc1(nnz,&retval.icols[i]);CHKERRQ(ierr);
853b2f1ab58SBarry Smith 
854c328eeadSBarry Smith     /* Administrate the column indices */
855b2f1ab58SBarry Smith     inz = 0;
8566322f4bdSBarry Smith     for (j=i; j<maxmrk; j++) {
8576322f4bdSBarry Smith       if (iwork[j]) {
858b2f1ab58SBarry Smith         retval.icols[i][inz] = j-i;
859b2f1ab58SBarry Smith         inz++;
860b2f1ab58SBarry Smith         iwork[j]=0;
861b2f1ab58SBarry Smith       }
862b2f1ab58SBarry Smith     }
863b2f1ab58SBarry Smith     retval.nnz += nnz;
864b2f1ab58SBarry Smith   };
865b2f1ab58SBarry Smith   ierr    = PetscFree(iwork);CHKERRQ(ierr);
866b2f1ab58SBarry Smith   *result = retval;
867b2f1ab58SBarry Smith   PetscFunctionReturn(0);
868b2f1ab58SBarry Smith }
869b2f1ab58SBarry Smith 
870b2f1ab58SBarry Smith 
871b2f1ab58SBarry Smith 
872b2f1ab58SBarry Smith /*
873b2f1ab58SBarry Smith    spbas_keep_upper:
874b2f1ab58SBarry Smith       remove the lower part of the matrix: keep the upper part
875b2f1ab58SBarry Smith */
876b2f1ab58SBarry Smith PetscErrorCode spbas_keep_upper(spbas_matrix * inout_matrix)
877b2f1ab58SBarry Smith {
878b2f1ab58SBarry Smith   PetscInt i, j;
879b2f1ab58SBarry Smith   PetscInt jstart;
880b2f1ab58SBarry Smith 
881b2f1ab58SBarry Smith   PetscFunctionBegin;
882e32f2f54SBarry Smith   if (inout_matrix->block_data) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Not yet for block data matrices\n");
8836322f4bdSBarry Smith   for (i=0; i<inout_matrix->nrows; i++)  {
8846322f4bdSBarry Smith     for (jstart=0; (jstart<inout_matrix->row_nnz[i]) && (inout_matrix->icols[i][jstart]<0); jstart++) {}
8856322f4bdSBarry Smith     if (jstart>0) {
8866322f4bdSBarry Smith       for (j=0; j<inout_matrix->row_nnz[i]-jstart; j++) {
8876322f4bdSBarry Smith         inout_matrix->icols[i][j] = inout_matrix->icols[i][j+jstart];
888b2f1ab58SBarry Smith       }
889b2f1ab58SBarry Smith 
8906322f4bdSBarry Smith       if (inout_matrix->values) {
8916322f4bdSBarry Smith         for (j=0; j<inout_matrix->row_nnz[i]-jstart; j++) {
8926322f4bdSBarry Smith           inout_matrix->values[i][j] = inout_matrix->values[i][j+jstart];
893b2f1ab58SBarry Smith         }
894b2f1ab58SBarry Smith       }
895b2f1ab58SBarry Smith 
896b2f1ab58SBarry Smith       inout_matrix->row_nnz[i] -= jstart;
897b2f1ab58SBarry Smith 
8986322f4bdSBarry Smith       inout_matrix->icols[i] = (PetscInt*) realloc((void*) inout_matrix->icols[i], inout_matrix->row_nnz[i]*sizeof(PetscInt));
899b2f1ab58SBarry Smith 
9006322f4bdSBarry Smith       if (inout_matrix->values) {
9016322f4bdSBarry Smith         inout_matrix->values[i] = (PetscScalar*) realloc((void*) inout_matrix->values[i], inout_matrix->row_nnz[i]*sizeof(PetscScalar));
902b2f1ab58SBarry Smith       }
903b2f1ab58SBarry Smith       inout_matrix->nnz -= jstart;
904b2f1ab58SBarry Smith     }
905b2f1ab58SBarry Smith   }
906b2f1ab58SBarry Smith   PetscFunctionReturn(0);
907b2f1ab58SBarry Smith }
908b2f1ab58SBarry Smith 
909