xref: /petsc/src/mat/impls/aij/seq/bas/spbas.c (revision 95452b02e12c0ee11232c7ff2b24b568a8e07e43)
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 
17*95452b02SPatrick Sanan    Notes:
18*95452b02SPatrick 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 
223ca39a21SBarry Smith .seealso: PCFactorSetMatSolverType(), MatSolverType, PCFactorSetLevels(), PCFactorSetDropTolerance()
23845006b9SBarry Smith 
24845006b9SBarry Smith M*/
259ccc4a9bSBarry Smith 
26b2f1ab58SBarry Smith /*
27b2f1ab58SBarry Smith   spbas_memory_requirement:
28b2f1ab58SBarry Smith     Calculate the number of bytes needed to store tha matrix
29b2f1ab58SBarry Smith */
303dfa2556SBarry Smith size_t spbas_memory_requirement(spbas_matrix matrix)
31b2f1ab58SBarry Smith {
323dfa2556SBarry Smith   size_t memreq = 6 * sizeof(PetscInt)  + /* nrows, ncols, nnz, n_alloc_icol, n_alloc_val, col_idx_type */
33ace3abfcSBarry Smith                     sizeof(PetscBool)               + /* block_data */
34c328eeadSBarry Smith                     sizeof(PetscScalar**)           + /* values */
35c328eeadSBarry Smith                     sizeof(PetscScalar*)            + /* alloc_val */
363dfa2556SBarry Smith                     2 * sizeof(PetscInt**)          + /* icols, icols0 */
37c328eeadSBarry Smith                     2 * sizeof(PetscInt*)           + /* row_nnz, alloc_icol */
38c328eeadSBarry Smith                     matrix.nrows * sizeof(PetscInt) + /* row_nnz[*] */
39c328eeadSBarry Smith                     matrix.nrows * sizeof(PetscInt*); /* icols[*] */
40b2f1ab58SBarry Smith 
41c328eeadSBarry Smith   /* icol0[*] */
422205254eSKarl Rupp   if (matrix.col_idx_type == SPBAS_OFFSET_ARRAY) memreq += matrix.nrows * sizeof(PetscInt);
43b2f1ab58SBarry Smith 
44c328eeadSBarry Smith   /* icols[*][*] */
452205254eSKarl Rupp   if (matrix.block_data) memreq += matrix.n_alloc_icol * sizeof(PetscInt);
462205254eSKarl Rupp   else memreq += matrix.nnz * sizeof(PetscInt);
47b2f1ab58SBarry Smith 
484e1ff37aSBarry Smith   if (matrix.values) {
49c328eeadSBarry Smith     memreq += matrix.nrows * sizeof(PetscScalar*); /* values[*] */
50c328eeadSBarry Smith     /* values[*][*] */
512205254eSKarl Rupp     if (matrix.block_data) memreq += matrix.n_alloc_val  * sizeof(PetscScalar);
522205254eSKarl Rupp     else memreq += matrix.nnz * sizeof(PetscScalar);
53b2f1ab58SBarry Smith   }
54b2f1ab58SBarry Smith   return memreq;
55b2f1ab58SBarry Smith }
56b2f1ab58SBarry Smith 
57b2f1ab58SBarry Smith /*
58b2f1ab58SBarry Smith   spbas_allocate_pattern:
59b2f1ab58SBarry Smith     allocate the pattern arrays row_nnz, icols and optionally values
60b2f1ab58SBarry Smith */
61ace3abfcSBarry Smith PetscErrorCode spbas_allocate_pattern(spbas_matrix * result, PetscBool do_values)
62b2f1ab58SBarry Smith {
63b2f1ab58SBarry Smith   PetscErrorCode ierr;
64b2f1ab58SBarry Smith   PetscInt       nrows        = result->nrows;
65b2f1ab58SBarry Smith   PetscInt       col_idx_type = result->col_idx_type;
66b2f1ab58SBarry Smith 
67b2f1ab58SBarry Smith   PetscFunctionBegin;
68c328eeadSBarry Smith   /* Allocate sparseness pattern */
69785e854fSJed Brown   ierr = PetscMalloc1(nrows,&result->row_nnz);CHKERRQ(ierr);
70785e854fSJed Brown   ierr = PetscMalloc1(nrows,&result->icols);CHKERRQ(ierr);
71b2f1ab58SBarry Smith 
72c328eeadSBarry Smith   /* If offsets are given wrt an array, create array */
734e1ff37aSBarry Smith   if (col_idx_type == SPBAS_OFFSET_ARRAY) {
74785e854fSJed Brown     ierr = PetscMalloc1(nrows,&result->icol0);CHKERRQ(ierr);
754e1ff37aSBarry Smith   } else  {
760298fd71SBarry Smith     result->icol0 = NULL;
77b2f1ab58SBarry Smith   }
78b2f1ab58SBarry Smith 
79c328eeadSBarry Smith   /* If values are given, allocate values array */
804e1ff37aSBarry Smith   if (do_values)  {
81785e854fSJed Brown     ierr = PetscMalloc1(nrows,&result->values);CHKERRQ(ierr);
824e1ff37aSBarry Smith   } else {
830298fd71SBarry Smith     result->values = NULL;
84b2f1ab58SBarry Smith   }
85b2f1ab58SBarry Smith   PetscFunctionReturn(0);
86b2f1ab58SBarry Smith }
87b2f1ab58SBarry Smith 
88b2f1ab58SBarry Smith /*
89b2f1ab58SBarry Smith spbas_allocate_data:
90b2f1ab58SBarry Smith    in case of block_data:
91b2f1ab58SBarry Smith        Allocate the data arrays alloc_icol and optionally alloc_val,
92b2f1ab58SBarry Smith        set appropriate pointers from icols and values;
93b2f1ab58SBarry Smith    in case of !block_data:
94b2f1ab58SBarry Smith        Allocate the arrays icols[i] and optionally values[i]
95b2f1ab58SBarry Smith */
96b2f1ab58SBarry Smith PetscErrorCode spbas_allocate_data(spbas_matrix * result)
97b2f1ab58SBarry Smith {
98b2f1ab58SBarry Smith   PetscInt       i;
99b2f1ab58SBarry Smith   PetscInt       nnz   = result->nnz;
100b2f1ab58SBarry Smith   PetscInt       nrows = result->nrows;
101b2f1ab58SBarry Smith   PetscInt       r_nnz;
102b2f1ab58SBarry Smith   PetscErrorCode ierr;
1036c4ed002SBarry Smith   PetscBool      do_values  = (result->values) ? PETSC_TRUE : PETSC_FALSE;
104ace3abfcSBarry Smith   PetscBool      block_data = result->block_data;
105b2f1ab58SBarry Smith 
106b2f1ab58SBarry Smith   PetscFunctionBegin;
1074e1ff37aSBarry Smith   if (block_data) {
108c328eeadSBarry Smith     /* Allocate the column number array and point to it */
109b2f1ab58SBarry Smith     result->n_alloc_icol = nnz;
1102205254eSKarl Rupp 
111785e854fSJed Brown     ierr = PetscMalloc1(nnz, &result->alloc_icol);CHKERRQ(ierr);
1122205254eSKarl Rupp 
113b2f1ab58SBarry Smith     result->icols[0] = result->alloc_icol;
1144e1ff37aSBarry Smith     for (i=1; i<nrows; i++)  {
115b2f1ab58SBarry Smith       result->icols[i] = result->icols[i-1] + result->row_nnz[i-1];
116b2f1ab58SBarry Smith     }
117b2f1ab58SBarry Smith 
118c328eeadSBarry Smith     /* Allocate the value array and point to it */
1194e1ff37aSBarry Smith     if (do_values) {
120b2f1ab58SBarry Smith       result->n_alloc_val = nnz;
1212205254eSKarl Rupp 
122785e854fSJed Brown       ierr = PetscMalloc1(nnz, &result->alloc_val);CHKERRQ(ierr);
1232205254eSKarl Rupp 
124b2f1ab58SBarry Smith       result->values[0] = result->alloc_val;
1254e1ff37aSBarry Smith       for (i=1; i<nrows; i++) {
126b2f1ab58SBarry Smith         result->values[i] = result->values[i-1] + result->row_nnz[i-1];
127b2f1ab58SBarry Smith       }
128b2f1ab58SBarry Smith     }
1294e1ff37aSBarry Smith   } else {
1304e1ff37aSBarry Smith     for (i=0; i<nrows; i++)   {
131b2f1ab58SBarry Smith       r_nnz = result->row_nnz[i];
132785e854fSJed Brown       ierr  = PetscMalloc1(r_nnz, &result->icols[i]);CHKERRQ(ierr);
133b2f1ab58SBarry Smith     }
1344e1ff37aSBarry Smith     if (do_values) {
1354e1ff37aSBarry Smith       for (i=0; i<nrows; i++)  {
136b2f1ab58SBarry Smith         r_nnz = result->row_nnz[i];
137785e854fSJed Brown         ierr  = PetscMalloc1(r_nnz, &result->values[i]);CHKERRQ(ierr);
138b2f1ab58SBarry Smith       }
139b2f1ab58SBarry Smith     }
140b2f1ab58SBarry Smith   }
141b2f1ab58SBarry Smith   PetscFunctionReturn(0);
142b2f1ab58SBarry Smith }
143b2f1ab58SBarry Smith 
144b2f1ab58SBarry Smith /*
145b2f1ab58SBarry Smith   spbas_row_order_icol
146b2f1ab58SBarry Smith      determine if row i1 should come
147b2f1ab58SBarry Smith        + before row i2 in the sorted rows (return -1),
148b2f1ab58SBarry Smith        + after (return 1)
149b2f1ab58SBarry Smith        + is identical (return 0).
150b2f1ab58SBarry Smith */
151b2f1ab58SBarry Smith int spbas_row_order_icol(PetscInt i1, PetscInt i2, PetscInt *irow_in, PetscInt *icol_in,PetscInt col_idx_type)
152b2f1ab58SBarry Smith {
153b2f1ab58SBarry Smith   PetscInt j;
154b2f1ab58SBarry Smith   PetscInt nnz1    = irow_in[i1+1] - irow_in[i1];
155b2f1ab58SBarry Smith   PetscInt nnz2    = irow_in[i2+1] - irow_in[i2];
156b2f1ab58SBarry Smith   PetscInt * icol1 = &icol_in[irow_in[i1]];
157b2f1ab58SBarry Smith   PetscInt * icol2 = &icol_in[irow_in[i2]];
158b2f1ab58SBarry Smith 
1592205254eSKarl Rupp   if (nnz1<nnz2) return -1;
1602205254eSKarl Rupp   if (nnz1>nnz2) return 1;
161b2f1ab58SBarry Smith 
1624e1ff37aSBarry Smith   if (col_idx_type == SPBAS_COLUMN_NUMBERS) {
1634e1ff37aSBarry Smith     for (j=0; j<nnz1; j++) {
1642205254eSKarl Rupp       if (icol1[j]< icol2[j]) return -1;
1652205254eSKarl Rupp       if (icol1[j]> icol2[j]) return 1;
166b2f1ab58SBarry Smith     }
1674e1ff37aSBarry Smith   } else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) {
1684e1ff37aSBarry Smith     for (j=0; j<nnz1; j++) {
1692205254eSKarl Rupp       if (icol1[j]-i1< icol2[j]-i2) return -1;
1702205254eSKarl Rupp       if (icol1[j]-i1> icol2[j]-i2) return 1;
171b2f1ab58SBarry Smith     }
1724e1ff37aSBarry Smith   } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
1734e1ff37aSBarry Smith     for (j=1; j<nnz1; j++) {
1742205254eSKarl Rupp       if (icol1[j]-icol1[0] < icol2[j]-icol2[0]) return -1;
1752205254eSKarl Rupp       if (icol1[j]-icol1[0] > icol2[j]-icol2[0]) return 1;
176b2f1ab58SBarry Smith     }
177b2f1ab58SBarry Smith   }
178b2f1ab58SBarry Smith   return 0;
179b2f1ab58SBarry Smith }
180b2f1ab58SBarry Smith 
181b2f1ab58SBarry Smith /*
182b2f1ab58SBarry Smith   spbas_mergesort_icols:
183b2f1ab58SBarry Smith     return a sorting of the rows in which identical sparseness patterns are
184b2f1ab58SBarry Smith     next to each other
185b2f1ab58SBarry Smith */
186b2f1ab58SBarry Smith PetscErrorCode spbas_mergesort_icols(PetscInt nrows, PetscInt * irow_in, PetscInt * icol_in,PetscInt col_idx_type, PetscInt *isort)
187b2f1ab58SBarry Smith {
188b2f1ab58SBarry Smith   PetscErrorCode ierr;
189c328eeadSBarry Smith   PetscInt       istep;       /* Chunk-sizes of already sorted parts of arrays */
190c328eeadSBarry Smith   PetscInt       i, i1, i2;   /* Loop counters for (partly) sorted arrays */
191c328eeadSBarry Smith   PetscInt       istart, i1end, i2end; /* start of newly sorted array part, end of both  parts */
192c328eeadSBarry Smith   PetscInt       *ialloc;     /* Allocated arrays */
193c328eeadSBarry Smith   PetscInt       *iswap;      /* auxiliary pointers for swapping */
194c328eeadSBarry Smith   PetscInt       *ihlp1;      /* Pointers to new version of arrays, */
195c328eeadSBarry Smith   PetscInt       *ihlp2;      /* Pointers to previous version of arrays, */
196b2f1ab58SBarry Smith 
197b2f1ab58SBarry Smith   PetscFunctionBegin;
198785e854fSJed Brown   ierr = PetscMalloc1(nrows,&ialloc);CHKERRQ(ierr);
199b2f1ab58SBarry Smith 
200b2f1ab58SBarry Smith   ihlp1 = ialloc;
201b2f1ab58SBarry Smith   ihlp2 = isort;
202b2f1ab58SBarry Smith 
203c328eeadSBarry Smith   /* Sorted array chunks are first 1 long, and increase until they are the complete array */
2044e1ff37aSBarry Smith   for (istep=1; istep<nrows; istep*=2) {
205c328eeadSBarry Smith     /*
206c328eeadSBarry Smith       Combine sorted parts
207c328eeadSBarry Smith           istart:istart+istep-1 and istart+istep-1:istart+2*istep-1
208c328eeadSBarry Smith       of ihlp2 and vhlp2
209c328eeadSBarry Smith 
210c328eeadSBarry Smith       into one sorted part
211c328eeadSBarry Smith           istart:istart+2*istep-1
212c328eeadSBarry Smith       of ihlp1 and vhlp1
213c328eeadSBarry Smith     */
2144e1ff37aSBarry Smith     for (istart=0; istart<nrows; istart+=2*istep) {
215c328eeadSBarry Smith       /* Set counters and bound array part endings */
2162205254eSKarl Rupp       i1=istart;        i1end = i1+istep;  if (i1end>nrows) i1end=nrows;
2172205254eSKarl Rupp       i2=istart+istep;  i2end = i2+istep;  if (i2end>nrows) i2end=nrows;
218b2f1ab58SBarry Smith 
219c328eeadSBarry Smith       /* Merge the two array parts */
2204e1ff37aSBarry Smith       for (i=istart; i<i2end; i++)  {
2214e1ff37aSBarry Smith         if (i1<i1end && i2<i2end && spbas_row_order_icol(ihlp2[i1], ihlp2[i2], irow_in, icol_in, col_idx_type) < 0) {
222b2f1ab58SBarry Smith           ihlp1[i] = ihlp2[i1];
223b2f1ab58SBarry Smith           i1++;
2244e1ff37aSBarry Smith         } else if (i2<i2end) {
225b2f1ab58SBarry Smith           ihlp1[i] = ihlp2[i2];
226b2f1ab58SBarry Smith           i2++;
2274e1ff37aSBarry Smith         } else {
228b2f1ab58SBarry Smith           ihlp1[i] = ihlp2[i1];
229b2f1ab58SBarry Smith           i1++;
230b2f1ab58SBarry Smith         }
231b2f1ab58SBarry Smith       }
232b2f1ab58SBarry Smith     }
233b2f1ab58SBarry Smith 
234c328eeadSBarry Smith     /* Swap the two array sets */
235b2f1ab58SBarry Smith     iswap = ihlp2; ihlp2 = ihlp1; ihlp1 = iswap;
236b2f1ab58SBarry Smith   }
237b2f1ab58SBarry Smith 
238c328eeadSBarry Smith   /* Copy one more time in case the sorted arrays are the temporary ones */
2394e1ff37aSBarry Smith   if (ihlp2 != isort) {
2402205254eSKarl Rupp     for (i=0; i<nrows; i++) isort[i] = ihlp2[i];
241b2f1ab58SBarry Smith   }
242b2f1ab58SBarry Smith   ierr = PetscFree(ialloc);CHKERRQ(ierr);
243b2f1ab58SBarry Smith   PetscFunctionReturn(0);
244b2f1ab58SBarry Smith }
245b2f1ab58SBarry Smith 
246b2f1ab58SBarry Smith 
247b2f1ab58SBarry Smith 
248b2f1ab58SBarry Smith /*
249b2f1ab58SBarry Smith   spbas_compress_pattern:
250b2f1ab58SBarry Smith      calculate a compressed sparseness pattern for a sparseness pattern
251b2f1ab58SBarry Smith      given in compressed row storage. The compressed sparseness pattern may
252b2f1ab58SBarry Smith      require (much) less memory.
253b2f1ab58SBarry Smith */
2544e1ff37aSBarry 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)
255b2f1ab58SBarry Smith {
256b2f1ab58SBarry Smith   PetscInt        nnz      = irow_in[nrows];
2573dfa2556SBarry Smith   size_t          mem_orig = (nrows + nnz) * sizeof(PetscInt);
2583dfa2556SBarry Smith   size_t          mem_compressed;
259b2f1ab58SBarry Smith   PetscErrorCode  ierr;
260b2f1ab58SBarry Smith   PetscInt        *isort;
261b2f1ab58SBarry Smith   PetscInt        *icols;
262b2f1ab58SBarry Smith   PetscInt        row_nnz;
263b2f1ab58SBarry Smith   PetscInt        *ipoint;
264ace3abfcSBarry Smith   PetscBool       *used;
265b2f1ab58SBarry Smith   PetscInt        ptr;
266b2f1ab58SBarry Smith   PetscInt        i,j;
267ace3abfcSBarry Smith   const PetscBool no_values = PETSC_FALSE;
268b2f1ab58SBarry Smith 
269b2f1ab58SBarry Smith   PetscFunctionBegin;
270c328eeadSBarry Smith   /* Allocate the structure of the new matrix */
271b2f1ab58SBarry Smith   B->nrows        = nrows;
272b2f1ab58SBarry Smith   B->ncols        = ncols;
273b2f1ab58SBarry Smith   B->nnz          = nnz;
274b2f1ab58SBarry Smith   B->col_idx_type = col_idx_type;
275b2f1ab58SBarry Smith   B->block_data   = PETSC_TRUE;
2762205254eSKarl Rupp 
277b2f1ab58SBarry Smith   ierr = spbas_allocate_pattern(B, no_values);CHKERRQ(ierr);
278b2f1ab58SBarry Smith 
279c328eeadSBarry Smith   /* When using an offset array, set it */
2804e1ff37aSBarry Smith   if (col_idx_type==SPBAS_OFFSET_ARRAY)  {
2812205254eSKarl Rupp     for (i=0; i<nrows; i++) B->icol0[i] = icol_in[irow_in[i]];
282b2f1ab58SBarry Smith   }
283b2f1ab58SBarry Smith 
284c328eeadSBarry Smith   /* Allocate the ordering for the rows */
285785e854fSJed Brown   ierr = PetscMalloc1(nrows,&isort);CHKERRQ(ierr);
286785e854fSJed Brown   ierr = PetscMalloc1(nrows,&ipoint);CHKERRQ(ierr);
287785e854fSJed Brown   ierr = PetscMalloc1(nrows,&used);CHKERRQ(ierr);
288b2f1ab58SBarry Smith 
289c328eeadSBarry Smith   /*  Initialize the sorting */
290ace3abfcSBarry Smith   ierr = PetscMemzero((void*) used, nrows*sizeof(PetscBool));CHKERRQ(ierr);
2914e1ff37aSBarry Smith   for (i = 0; i<nrows; i++)  {
292b2f1ab58SBarry Smith     B->row_nnz[i] = irow_in[i+1]-irow_in[i];
293b2f1ab58SBarry Smith     isort[i]      = i;
294b2f1ab58SBarry Smith     ipoint[i]     = i;
295b2f1ab58SBarry Smith   }
296b2f1ab58SBarry Smith 
297c328eeadSBarry Smith   /* Sort the rows so that identical columns will be next to each other */
298b2f1ab58SBarry Smith   ierr = spbas_mergesort_icols(nrows, irow_in, icol_in, col_idx_type, isort);CHKERRQ(ierr);
2990298fd71SBarry Smith   ierr = PetscInfo(NULL,"Rows have been sorted for patterns\n");CHKERRQ(ierr);
300b2f1ab58SBarry Smith 
301c328eeadSBarry Smith   /* Replace identical rows with the first one in the list */
3024e1ff37aSBarry Smith   for (i=1; i<nrows; i++) {
3034e1ff37aSBarry Smith     if (spbas_row_order_icol(isort[i-1], isort[i], irow_in, icol_in, col_idx_type) == 0) {
304b2f1ab58SBarry Smith       ipoint[isort[i]] = ipoint[isort[i-1]];
305b2f1ab58SBarry Smith     }
306b2f1ab58SBarry Smith   }
307b2f1ab58SBarry Smith 
308c328eeadSBarry Smith   /* Collect the rows which are used*/
3092205254eSKarl Rupp   for (i=0; i<nrows; i++) used[ipoint[i]] = PETSC_TRUE;
310b2f1ab58SBarry Smith 
311c328eeadSBarry Smith   /* Calculate needed memory */
312b2f1ab58SBarry Smith   B->n_alloc_icol = 0;
3134e1ff37aSBarry Smith   for (i=0; i<nrows; i++)  {
3142205254eSKarl Rupp     if (used[i]) B->n_alloc_icol += B->row_nnz[i];
315b2f1ab58SBarry Smith   }
316785e854fSJed Brown   ierr = PetscMalloc1(B->n_alloc_icol,&B->alloc_icol);CHKERRQ(ierr);
317b2f1ab58SBarry Smith 
318c328eeadSBarry Smith   /* Fill in the diagonal offsets for the rows which store their own data */
319b2f1ab58SBarry Smith   ptr = 0;
3204e1ff37aSBarry Smith   for (i=0; i<B->nrows; i++) {
3214e1ff37aSBarry Smith     if (used[i]) {
322b2f1ab58SBarry Smith       B->icols[i] = &B->alloc_icol[ptr];
323b2f1ab58SBarry Smith       icols = &icol_in[irow_in[i]];
324b2f1ab58SBarry Smith       row_nnz = B->row_nnz[i];
3254e1ff37aSBarry Smith       if (col_idx_type == SPBAS_COLUMN_NUMBERS) {
3264e1ff37aSBarry Smith         for (j=0; j<row_nnz; j++) {
327b2f1ab58SBarry Smith           B->icols[i][j] = icols[j];
328b2f1ab58SBarry Smith         }
3294e1ff37aSBarry Smith       } else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) {
3304e1ff37aSBarry Smith         for (j=0; j<row_nnz; j++) {
331b2f1ab58SBarry Smith           B->icols[i][j] = icols[j]-i;
332b2f1ab58SBarry Smith         }
3334e1ff37aSBarry Smith       } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
3344e1ff37aSBarry Smith         for (j=0; j<row_nnz; j++) {
335b2f1ab58SBarry Smith           B->icols[i][j] = icols[j]-icols[0];
336b2f1ab58SBarry Smith         }
337b2f1ab58SBarry Smith       }
338b2f1ab58SBarry Smith       ptr += B->row_nnz[i];
339b2f1ab58SBarry Smith     }
340b2f1ab58SBarry Smith   }
341b2f1ab58SBarry Smith 
342c328eeadSBarry Smith   /* Point to the right places for all data */
3434e1ff37aSBarry Smith   for (i=0; i<nrows; i++) {
344b2f1ab58SBarry Smith     B->icols[i] = B->icols[ipoint[i]];
345b2f1ab58SBarry Smith   }
3460298fd71SBarry Smith   ierr = PetscInfo(NULL,"Row patterns have been compressed\n");CHKERRQ(ierr);
34757622a8eSBarry Smith   ierr = PetscInfo1(NULL,"         (%g nonzeros per row)\n", (double) ((PetscReal) nnz / (PetscReal) nrows));CHKERRQ(ierr);
348b2f1ab58SBarry Smith 
349b2f1ab58SBarry Smith   ierr=PetscFree(isort);CHKERRQ(ierr);
350b2f1ab58SBarry Smith   ierr=PetscFree(used);CHKERRQ(ierr);
351b2f1ab58SBarry Smith   ierr=PetscFree(ipoint);CHKERRQ(ierr);
352b2f1ab58SBarry Smith 
353b2f1ab58SBarry Smith   mem_compressed = spbas_memory_requirement(*B);
3544e1ff37aSBarry Smith   *mem_reduction = 100.0 * (PetscReal)(mem_orig-mem_compressed)/ (PetscReal) mem_orig;
355b2f1ab58SBarry Smith   PetscFunctionReturn(0);
356b2f1ab58SBarry Smith }
357b2f1ab58SBarry Smith 
358b2f1ab58SBarry Smith /*
359b2f1ab58SBarry Smith    spbas_incomplete_cholesky
360b2f1ab58SBarry Smith        Incomplete Cholesky decomposition
361b2f1ab58SBarry Smith */
362c6db04a5SJed Brown #include <../src/mat/impls/aij/seq/bas/spbas_cholesky.h>
363b2f1ab58SBarry Smith 
364b2f1ab58SBarry Smith /*
365b2f1ab58SBarry Smith   spbas_delete : de-allocate the arrays owned by this matrix
366b2f1ab58SBarry Smith */
367b2f1ab58SBarry Smith PetscErrorCode spbas_delete(spbas_matrix matrix)
368b2f1ab58SBarry Smith {
369b2f1ab58SBarry Smith   PetscInt       i;
370b2f1ab58SBarry Smith   PetscErrorCode ierr;
3719ccc4a9bSBarry Smith 
372b2f1ab58SBarry Smith   PetscFunctionBegin;
3739ccc4a9bSBarry Smith   if (matrix.block_data) {
374cb9801acSJed Brown     ierr=PetscFree(matrix.alloc_icol);CHKERRQ(ierr);
375b2f1ab58SBarry Smith     if (matrix.values) {ierr=PetscFree(matrix.alloc_val);CHKERRQ(ierr);}
3769ccc4a9bSBarry Smith   } else {
3779ccc4a9bSBarry Smith     for (i=0; i<matrix.nrows; i++) { ierr=PetscFree(matrix.icols[i]);CHKERRQ(ierr);}
378b2f1ab58SBarry Smith     ierr = PetscFree(matrix.icols);CHKERRQ(ierr);
3799ccc4a9bSBarry Smith     if (matrix.values) {
3809ccc4a9bSBarry Smith       for (i=0; i<matrix.nrows; i++) { ierr=PetscFree(matrix.values[i]);CHKERRQ(ierr);}
381b2f1ab58SBarry Smith     }
382b2f1ab58SBarry Smith   }
383b2f1ab58SBarry Smith 
384b2f1ab58SBarry Smith   ierr=PetscFree(matrix.row_nnz);CHKERRQ(ierr);
385b2f1ab58SBarry Smith   ierr=PetscFree(matrix.icols);CHKERRQ(ierr);
3869ccc4a9bSBarry Smith   if (matrix.col_idx_type == SPBAS_OFFSET_ARRAY) {ierr=PetscFree(matrix.icol0);CHKERRQ(ierr);}
387c31cb41cSBarry Smith   ierr=PetscFree(matrix.values);CHKERRQ(ierr);
388b2f1ab58SBarry Smith   PetscFunctionReturn(0);
389b2f1ab58SBarry Smith }
390b2f1ab58SBarry Smith 
391b2f1ab58SBarry Smith /*
392b2f1ab58SBarry Smith spbas_matrix_to_crs:
393b2f1ab58SBarry Smith    Convert an spbas_matrix to compessed row storage
394b2f1ab58SBarry Smith */
395b2f1ab58SBarry Smith PetscErrorCode spbas_matrix_to_crs(spbas_matrix matrix_A,MatScalar **val_out, PetscInt **irow_out, PetscInt **icol_out)
396b2f1ab58SBarry Smith {
397b2f1ab58SBarry Smith   PetscInt       nrows = matrix_A.nrows;
398b2f1ab58SBarry Smith   PetscInt       nnz   = matrix_A.nnz;
399b2f1ab58SBarry Smith   PetscInt       i,j,r_nnz,i0;
400b2f1ab58SBarry Smith   PetscInt       *irow;
401b2f1ab58SBarry Smith   PetscInt       *icol;
402b2f1ab58SBarry Smith   PetscInt       *icol_A;
403b2f1ab58SBarry Smith   MatScalar      *val;
404b2f1ab58SBarry Smith   PetscScalar    *val_A;
405b2f1ab58SBarry Smith   PetscInt       col_idx_type = matrix_A.col_idx_type;
406ace3abfcSBarry Smith   PetscBool      do_values    = matrix_A.values ? PETSC_TRUE : PETSC_FALSE;
407b2f1ab58SBarry Smith   PetscErrorCode ierr;
408b2f1ab58SBarry Smith 
409b2f1ab58SBarry Smith   PetscFunctionBegin;
410854ce69bSBarry Smith   ierr      = PetscMalloc1(nrows+1, &irow);CHKERRQ(ierr);
411854ce69bSBarry Smith   ierr      = PetscMalloc1(nnz, &icol);CHKERRQ(ierr);
4129ccc4a9bSBarry Smith   *icol_out = icol;
4139ccc4a9bSBarry Smith   *irow_out = irow;
4149ccc4a9bSBarry Smith   if (do_values) {
415854ce69bSBarry Smith     ierr     = PetscMalloc1(nnz, &val);CHKERRQ(ierr);
416b2f1ab58SBarry Smith     *val_out = val; *icol_out = icol; *irow_out=irow;
417b2f1ab58SBarry Smith   }
418b2f1ab58SBarry Smith 
419b2f1ab58SBarry Smith   irow[0]=0;
4209ccc4a9bSBarry Smith   for (i=0; i<nrows; i++) {
421b2f1ab58SBarry Smith     r_nnz     = matrix_A.row_nnz[i];
422b2f1ab58SBarry Smith     i0        = irow[i];
423b2f1ab58SBarry Smith     irow[i+1] = i0 + r_nnz;
424b2f1ab58SBarry Smith     icol_A    = matrix_A.icols[i];
425b2f1ab58SBarry Smith 
4269ccc4a9bSBarry Smith     if (do_values) {
427b2f1ab58SBarry Smith       val_A = matrix_A.values[i];
4289ccc4a9bSBarry Smith       for (j=0; j<r_nnz; j++) {
429b2f1ab58SBarry Smith         icol[i0+j] = icol_A[j];
430b2f1ab58SBarry Smith         val[i0+j]  = val_A[j];
431b2f1ab58SBarry Smith       }
4329ccc4a9bSBarry Smith     } else {
4332205254eSKarl Rupp       for (j=0; j<r_nnz; j++) icol[i0+j] = icol_A[j];
434b2f1ab58SBarry Smith     }
435b2f1ab58SBarry Smith 
4369ccc4a9bSBarry Smith     if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) {
4372205254eSKarl Rupp       for (j=0; j<r_nnz; j++) icol[i0+j] += i;
4382205254eSKarl Rupp     } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
439b2f1ab58SBarry Smith       i0 = matrix_A.icol0[i];
4402205254eSKarl Rupp       for (j=0; j<r_nnz; j++) icol[i0+j] += i0;
441b2f1ab58SBarry Smith     }
442b2f1ab58SBarry Smith   }
443b2f1ab58SBarry Smith   PetscFunctionReturn(0);
444b2f1ab58SBarry Smith }
445b2f1ab58SBarry Smith 
446b2f1ab58SBarry Smith 
447b2f1ab58SBarry Smith /*
448b2f1ab58SBarry Smith     spbas_transpose
449b2f1ab58SBarry Smith        return the transpose of a matrix
450b2f1ab58SBarry Smith */
451b2f1ab58SBarry Smith PetscErrorCode spbas_transpose(spbas_matrix in_matrix, spbas_matrix * result)
452b2f1ab58SBarry Smith {
453b2f1ab58SBarry Smith   PetscInt       col_idx_type = in_matrix.col_idx_type;
454b2f1ab58SBarry Smith   PetscInt       nnz          = in_matrix.nnz;
455b2f1ab58SBarry Smith   PetscInt       ncols        = in_matrix.nrows;
456b2f1ab58SBarry Smith   PetscInt       nrows        = in_matrix.ncols;
457b2f1ab58SBarry Smith   PetscInt       i,j,k;
458b2f1ab58SBarry Smith   PetscInt       r_nnz;
459b2f1ab58SBarry Smith   PetscInt       *irow;
4604efc9174SBarry Smith   PetscInt       icol0 = 0;
461b2f1ab58SBarry Smith   PetscScalar    * val;
462b2f1ab58SBarry Smith   PetscErrorCode ierr;
4634e1ff37aSBarry Smith 
464b2f1ab58SBarry Smith   PetscFunctionBegin;
465c328eeadSBarry Smith   /* Copy input values */
466b2f1ab58SBarry Smith   result->nrows        = nrows;
467b2f1ab58SBarry Smith   result->ncols        = ncols;
468b2f1ab58SBarry Smith   result->nnz          = nnz;
469b2f1ab58SBarry Smith   result->col_idx_type = SPBAS_COLUMN_NUMBERS;
470b2f1ab58SBarry Smith   result->block_data   = PETSC_TRUE;
471b2f1ab58SBarry Smith 
472c328eeadSBarry Smith   /* Allocate sparseness pattern */
47371d55d18SBarry Smith   ierr =  spbas_allocate_pattern(result, in_matrix.values ? PETSC_TRUE : PETSC_FALSE);CHKERRQ(ierr);
474b2f1ab58SBarry Smith 
475c328eeadSBarry Smith   /*  Count the number of nonzeros in each row */
4762205254eSKarl Rupp   for (i = 0; i<nrows; i++) result->row_nnz[i] = 0;
477b2f1ab58SBarry Smith 
4789ccc4a9bSBarry Smith   for (i=0; i<ncols; i++) {
479b2f1ab58SBarry Smith     r_nnz = in_matrix.row_nnz[i];
480b2f1ab58SBarry Smith     irow  = in_matrix.icols[i];
4819ccc4a9bSBarry Smith     if (col_idx_type == SPBAS_COLUMN_NUMBERS)  {
4822205254eSKarl Rupp       for (j=0; j<r_nnz; j++) result->row_nnz[irow[j]]++;
4839ccc4a9bSBarry Smith     } else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS)  {
4842205254eSKarl Rupp       for (j=0; j<r_nnz; j++) result->row_nnz[i+irow[j]]++;
4859ccc4a9bSBarry Smith     } else if (col_idx_type == SPBAS_OFFSET_ARRAY) {
486b2f1ab58SBarry Smith       icol0=in_matrix.icol0[i];
4872205254eSKarl Rupp       for (j=0; j<r_nnz; j++) result->row_nnz[icol0+irow[j]]++;
488b2f1ab58SBarry Smith     }
489b2f1ab58SBarry Smith   }
490b2f1ab58SBarry Smith 
491c328eeadSBarry Smith   /* Set the pointers to the data */
492b2f1ab58SBarry Smith   ierr = spbas_allocate_data(result);CHKERRQ(ierr);
493b2f1ab58SBarry Smith 
494c328eeadSBarry Smith   /* Reset the number of nonzeros in each row */
4952205254eSKarl Rupp   for (i = 0; i<nrows; i++) result->row_nnz[i] = 0;
496b2f1ab58SBarry Smith 
497c328eeadSBarry Smith   /* Fill the data arrays */
4989ccc4a9bSBarry Smith   if (in_matrix.values) {
4999ccc4a9bSBarry Smith     for (i=0; i<ncols; i++) {
500b2f1ab58SBarry Smith       r_nnz = in_matrix.row_nnz[i];
501b2f1ab58SBarry Smith       irow  = in_matrix.icols[i];
502b2f1ab58SBarry Smith       val   = in_matrix.values[i];
503b2f1ab58SBarry Smith 
5042205254eSKarl Rupp       if      (col_idx_type == SPBAS_COLUMN_NUMBERS)   icol0 = 0;
5052205254eSKarl Rupp       else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) icol0 = i;
5062205254eSKarl Rupp       else if (col_idx_type == SPBAS_OFFSET_ARRAY)     icol0 = in_matrix.icol0[i];
5079ccc4a9bSBarry Smith       for (j=0; j<r_nnz; j++)  {
508b2f1ab58SBarry Smith         k = icol0 + irow[j];
509b2f1ab58SBarry Smith         result->icols[k][result->row_nnz[k]]  = i;
510b2f1ab58SBarry Smith         result->values[k][result->row_nnz[k]] = val[j];
511b2f1ab58SBarry Smith         result->row_nnz[k]++;
512b2f1ab58SBarry Smith       }
513b2f1ab58SBarry Smith     }
5149ccc4a9bSBarry Smith   } else {
5159ccc4a9bSBarry Smith     for (i=0; i<ncols; i++) {
516b2f1ab58SBarry Smith       r_nnz = in_matrix.row_nnz[i];
517b2f1ab58SBarry Smith       irow  = in_matrix.icols[i];
518b2f1ab58SBarry Smith 
5192205254eSKarl Rupp       if      (col_idx_type == SPBAS_COLUMN_NUMBERS)   icol0=0;
5202205254eSKarl Rupp       else if (col_idx_type == SPBAS_DIAGONAL_OFFSETS) icol0=i;
5212205254eSKarl Rupp       else if (col_idx_type == SPBAS_OFFSET_ARRAY)     icol0=in_matrix.icol0[i];
522b2f1ab58SBarry Smith 
5239ccc4a9bSBarry Smith       for (j=0; j<r_nnz; j++) {
524b2f1ab58SBarry Smith         k = icol0 + irow[j];
525b2f1ab58SBarry Smith         result->icols[k][result->row_nnz[k]] = i;
526b2f1ab58SBarry Smith         result->row_nnz[k]++;
527b2f1ab58SBarry Smith       }
528b2f1ab58SBarry Smith     }
529b2f1ab58SBarry Smith   }
530b2f1ab58SBarry Smith   PetscFunctionReturn(0);
531b2f1ab58SBarry Smith }
532b2f1ab58SBarry Smith 
533b2f1ab58SBarry Smith /*
534b2f1ab58SBarry Smith    spbas_mergesort
535b2f1ab58SBarry Smith 
536bb42e86aSJed Brown       mergesort for an array of integers and an array of associated
537b2f1ab58SBarry Smith       reals
538b2f1ab58SBarry Smith 
539b2f1ab58SBarry Smith       on output, icol[0..nnz-1] is increasing;
540b2f1ab58SBarry Smith                   val[0..nnz-1] has undergone the same permutation as icol
541b2f1ab58SBarry Smith 
5420298fd71SBarry Smith       NB: val may be NULL: in that case, only the integers are sorted
543b2f1ab58SBarry Smith 
544b2f1ab58SBarry Smith */
545b2f1ab58SBarry Smith PetscErrorCode spbas_mergesort(PetscInt nnz, PetscInt *icol, PetscScalar *val)
546b2f1ab58SBarry Smith {
547c328eeadSBarry Smith   PetscInt       istep;       /* Chunk-sizes of already sorted parts of arrays */
548c328eeadSBarry Smith   PetscInt       i, i1, i2;   /* Loop counters for (partly) sorted arrays */
549c328eeadSBarry Smith   PetscInt       istart, i1end, i2end; /* start of newly sorted array part, end of both parts */
550c328eeadSBarry Smith   PetscInt       *ialloc;     /* Allocated arrays */
5510298fd71SBarry Smith   PetscScalar    *valloc=NULL;
552c328eeadSBarry Smith   PetscInt       *iswap;      /* auxiliary pointers for swapping */
553b2f1ab58SBarry Smith   PetscScalar    *vswap;
554c328eeadSBarry Smith   PetscInt       *ihlp1;      /* Pointers to new version of arrays, */
5550298fd71SBarry Smith   PetscScalar    *vhlp1=NULL;  /* (arrays under construction) */
556c328eeadSBarry Smith   PetscInt       *ihlp2;      /* Pointers to previous version of arrays, */
5570298fd71SBarry Smith   PetscScalar    *vhlp2=NULL;
558b2f1ab58SBarry Smith   PetscErrorCode ierr;
559b2f1ab58SBarry Smith 
560785e854fSJed Brown   ierr  = PetscMalloc1(nnz,&ialloc);CHKERRQ(ierr);
561b2f1ab58SBarry Smith   ihlp1 = ialloc;
562b2f1ab58SBarry Smith   ihlp2 = icol;
563b2f1ab58SBarry Smith 
5649ccc4a9bSBarry Smith   if (val) {
565785e854fSJed Brown     ierr  = PetscMalloc1(nnz,&valloc);CHKERRQ(ierr);
566b2f1ab58SBarry Smith     vhlp1 = valloc;
567b2f1ab58SBarry Smith     vhlp2 = val;
568b2f1ab58SBarry Smith   }
569b2f1ab58SBarry Smith 
570b2f1ab58SBarry Smith 
571c328eeadSBarry Smith   /* Sorted array chunks are first 1 long, and increase until they are the complete array */
5729ccc4a9bSBarry Smith   for (istep=1; istep<nnz; istep*=2) {
573c328eeadSBarry Smith     /*
574c328eeadSBarry Smith       Combine sorted parts
575c328eeadSBarry Smith           istart:istart+istep-1 and istart+istep-1:istart+2*istep-1
576c328eeadSBarry Smith       of ihlp2 and vhlp2
577c328eeadSBarry Smith 
578c328eeadSBarry Smith       into one sorted part
579c328eeadSBarry Smith           istart:istart+2*istep-1
580c328eeadSBarry Smith       of ihlp1 and vhlp1
581c328eeadSBarry Smith     */
5829ccc4a9bSBarry Smith     for (istart=0; istart<nnz; istart+=2*istep) {
583c328eeadSBarry Smith       /* Set counters and bound array part endings */
5842205254eSKarl Rupp       i1=istart;        i1end = i1+istep;  if (i1end>nnz) i1end=nnz;
5852205254eSKarl Rupp       i2=istart+istep;  i2end = i2+istep;  if (i2end>nnz) i2end=nnz;
586b2f1ab58SBarry Smith 
587c328eeadSBarry Smith       /* Merge the two array parts */
5889ccc4a9bSBarry Smith       if (val) {
5899ccc4a9bSBarry Smith         for (i=istart; i<i2end; i++) {
5909ccc4a9bSBarry Smith           if (i1<i1end && i2<i2end && ihlp2[i1] < ihlp2[i2]) {
591b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i1];
592b2f1ab58SBarry Smith             vhlp1[i] = vhlp2[i1];
593b2f1ab58SBarry Smith             i1++;
5949ccc4a9bSBarry Smith           } else if (i2<i2end) {
595b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i2];
596b2f1ab58SBarry Smith             vhlp1[i] = vhlp2[i2];
597b2f1ab58SBarry Smith             i2++;
5989ccc4a9bSBarry Smith           } else {
599b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i1];
600b2f1ab58SBarry Smith             vhlp1[i] = vhlp2[i1];
601b2f1ab58SBarry Smith             i1++;
602b2f1ab58SBarry Smith           }
603b2f1ab58SBarry Smith         }
6049ccc4a9bSBarry Smith       } else {
6056322f4bdSBarry Smith         for (i=istart; i<i2end; i++) {
6066322f4bdSBarry Smith           if (i1<i1end && i2<i2end && ihlp2[i1] < ihlp2[i2]) {
607b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i1];
608b2f1ab58SBarry Smith             i1++;
6096322f4bdSBarry Smith           } else if (i2<i2end) {
610b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i2];
611b2f1ab58SBarry Smith             i2++;
6126322f4bdSBarry Smith           } else {
613b2f1ab58SBarry Smith             ihlp1[i] = ihlp2[i1];
614b2f1ab58SBarry Smith             i1++;
615b2f1ab58SBarry Smith           }
616b2f1ab58SBarry Smith         }
617b2f1ab58SBarry Smith       }
618b2f1ab58SBarry Smith     }
619b2f1ab58SBarry Smith 
620c328eeadSBarry Smith     /* Swap the two array sets */
621b2f1ab58SBarry Smith     iswap = ihlp2; ihlp2 = ihlp1; ihlp1 = iswap;
622b2f1ab58SBarry Smith     vswap = vhlp2; vhlp2 = vhlp1; vhlp1 = vswap;
623b2f1ab58SBarry Smith   }
624b2f1ab58SBarry Smith 
625c328eeadSBarry Smith   /* Copy one more time in case the sorted arrays are the temporary ones */
6266322f4bdSBarry Smith   if (ihlp2 != icol) {
6272205254eSKarl Rupp     for (i=0; i<nnz; i++) icol[i] = ihlp2[i];
6286322f4bdSBarry Smith     if (val) {
6292205254eSKarl Rupp       for (i=0; i<nnz; i++) val[i] = vhlp2[i];
630b2f1ab58SBarry Smith     }
631b2f1ab58SBarry Smith   }
632b2f1ab58SBarry Smith 
633b2f1ab58SBarry Smith   ierr = PetscFree(ialloc);CHKERRQ(ierr);
634b2f1ab58SBarry Smith   if (val) {ierr = PetscFree(valloc);CHKERRQ(ierr);}
635b2f1ab58SBarry Smith   PetscFunctionReturn(0);
636b2f1ab58SBarry Smith }
637b2f1ab58SBarry Smith 
638b2f1ab58SBarry Smith /*
639b2f1ab58SBarry Smith   spbas_apply_reordering_rows:
640b2f1ab58SBarry Smith     apply the given reordering to the rows:  matrix_A = matrix_A(perm,:);
641b2f1ab58SBarry Smith */
642b2f1ab58SBarry Smith PetscErrorCode spbas_apply_reordering_rows(spbas_matrix *matrix_A, const PetscInt *permutation)
643b2f1ab58SBarry Smith {
644b2f1ab58SBarry Smith   PetscInt       i,j,ip;
645b2f1ab58SBarry Smith   PetscInt       nrows=matrix_A->nrows;
646b2f1ab58SBarry Smith   PetscInt       * row_nnz;
647b2f1ab58SBarry Smith   PetscInt       **icols;
648ace3abfcSBarry Smith   PetscBool      do_values = matrix_A->values ? PETSC_TRUE : PETSC_FALSE;
6490298fd71SBarry Smith   PetscScalar    **vals    = NULL;
650b2f1ab58SBarry Smith   PetscErrorCode ierr;
651b2f1ab58SBarry Smith 
652b2f1ab58SBarry Smith   PetscFunctionBegin;
653e32f2f54SBarry 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");
654b2f1ab58SBarry Smith 
6556322f4bdSBarry Smith   if (do_values) {
656854ce69bSBarry Smith     ierr = PetscMalloc1(nrows, &vals);CHKERRQ(ierr);
657b2f1ab58SBarry Smith   }
658854ce69bSBarry Smith   ierr = PetscMalloc1(nrows, &row_nnz);CHKERRQ(ierr);
659854ce69bSBarry Smith   ierr = PetscMalloc1(nrows, &icols);CHKERRQ(ierr);
660b2f1ab58SBarry Smith 
6616322f4bdSBarry Smith   for (i=0; i<nrows; i++) {
662b2f1ab58SBarry Smith     ip = permutation[i];
6632205254eSKarl Rupp     if (do_values) vals[i] = matrix_A->values[ip];
664b2f1ab58SBarry Smith     icols[i]   = matrix_A->icols[ip];
665b2f1ab58SBarry Smith     row_nnz[i] = matrix_A->row_nnz[ip];
6662205254eSKarl Rupp     for (j=0; j<row_nnz[i]; j++) icols[i][j] += ip-i;
667b2f1ab58SBarry Smith   }
668b2f1ab58SBarry Smith 
669b2f1ab58SBarry Smith   if (do_values) { ierr = PetscFree(matrix_A->values);CHKERRQ(ierr);}
670b2f1ab58SBarry Smith   ierr = PetscFree(matrix_A->icols);CHKERRQ(ierr);
671b2f1ab58SBarry Smith   ierr = PetscFree(matrix_A->row_nnz);CHKERRQ(ierr);
672b2f1ab58SBarry Smith 
6732205254eSKarl Rupp   if (do_values) matrix_A->values = vals;
674b2f1ab58SBarry Smith   matrix_A->icols   = icols;
675b2f1ab58SBarry Smith   matrix_A->row_nnz = row_nnz;
676b2f1ab58SBarry Smith   PetscFunctionReturn(0);
677b2f1ab58SBarry Smith }
678b2f1ab58SBarry Smith 
679b2f1ab58SBarry Smith 
680b2f1ab58SBarry Smith /*
681b2f1ab58SBarry Smith   spbas_apply_reordering_cols:
682b2f1ab58SBarry Smith     apply the given reordering to the columns:  matrix_A(:,perm) = matrix_A;
683b2f1ab58SBarry Smith */
684b2f1ab58SBarry Smith PetscErrorCode spbas_apply_reordering_cols(spbas_matrix *matrix_A,const PetscInt *permutation)
685b2f1ab58SBarry Smith {
686b2f1ab58SBarry Smith   PetscInt       i,j;
687b2f1ab58SBarry Smith   PetscInt       nrows=matrix_A->nrows;
688b2f1ab58SBarry Smith   PetscInt       row_nnz;
689b2f1ab58SBarry Smith   PetscInt       *icols;
690ace3abfcSBarry Smith   PetscBool      do_values = matrix_A->values ? PETSC_TRUE : PETSC_FALSE;
6910298fd71SBarry Smith   PetscScalar    *vals     = NULL;
692b2f1ab58SBarry Smith   PetscErrorCode ierr;
693b2f1ab58SBarry Smith 
694b2f1ab58SBarry Smith   PetscFunctionBegin;
695e32f2f54SBarry 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");
696b2f1ab58SBarry Smith 
6976322f4bdSBarry Smith   for (i=0; i<nrows; i++) {
698b2f1ab58SBarry Smith     icols   = matrix_A->icols[i];
699b2f1ab58SBarry Smith     row_nnz = matrix_A->row_nnz[i];
7002205254eSKarl Rupp     if (do_values) vals = matrix_A->values[i];
701b2f1ab58SBarry Smith 
7026322f4bdSBarry Smith     for (j=0; j<row_nnz; j++) {
703b2f1ab58SBarry Smith       icols[j] = permutation[i+icols[j]]-i;
704b2f1ab58SBarry Smith     }
705b2f1ab58SBarry Smith     ierr = spbas_mergesort(row_nnz, icols, vals);CHKERRQ(ierr);
706b2f1ab58SBarry Smith   }
707b2f1ab58SBarry Smith   PetscFunctionReturn(0);
708b2f1ab58SBarry Smith }
709b2f1ab58SBarry Smith 
710b2f1ab58SBarry Smith /*
711b2f1ab58SBarry Smith   spbas_apply_reordering:
712b2f1ab58SBarry Smith     apply the given reordering:  matrix_A(perm,perm) = matrix_A;
713b2f1ab58SBarry Smith */
714b2f1ab58SBarry Smith PetscErrorCode spbas_apply_reordering(spbas_matrix *matrix_A, const PetscInt *permutation, const PetscInt * inv_perm)
715b2f1ab58SBarry Smith {
716b2f1ab58SBarry Smith   PetscErrorCode ierr;
7175fd66863SKarl Rupp 
718b2f1ab58SBarry Smith   PetscFunctionBegin;
719b2f1ab58SBarry Smith   ierr = spbas_apply_reordering_rows(matrix_A, inv_perm);CHKERRQ(ierr);
720b2f1ab58SBarry Smith   ierr = spbas_apply_reordering_cols(matrix_A, permutation);CHKERRQ(ierr);
721b2f1ab58SBarry Smith   PetscFunctionReturn(0);
722b2f1ab58SBarry Smith }
723b2f1ab58SBarry Smith 
724b2f1ab58SBarry Smith PetscErrorCode spbas_pattern_only(PetscInt nrows, PetscInt ncols, PetscInt *ai, PetscInt *aj, spbas_matrix * result)
725b2f1ab58SBarry Smith {
726b2f1ab58SBarry Smith   spbas_matrix   retval;
727b2f1ab58SBarry Smith   PetscInt       i, j, i0, r_nnz;
728b2f1ab58SBarry Smith   PetscErrorCode ierr;
729b2f1ab58SBarry Smith 
730b2f1ab58SBarry Smith   PetscFunctionBegin;
731c328eeadSBarry Smith   /* Copy input values */
732b2f1ab58SBarry Smith   retval.nrows = nrows;
733b2f1ab58SBarry Smith   retval.ncols = ncols;
734b2f1ab58SBarry Smith   retval.nnz   = ai[nrows];
735b2f1ab58SBarry Smith 
736b2f1ab58SBarry Smith   retval.block_data   = PETSC_TRUE;
737b2f1ab58SBarry Smith   retval.col_idx_type = SPBAS_DIAGONAL_OFFSETS;
738b2f1ab58SBarry Smith 
739c328eeadSBarry Smith   /* Allocate output matrix */
740b2f1ab58SBarry Smith   ierr = spbas_allocate_pattern(&retval, PETSC_FALSE);CHKERRQ(ierr);
7412205254eSKarl Rupp   for (i=0; i<nrows; i++) retval.row_nnz[i] = ai[i+1]-ai[i];
742b2f1ab58SBarry Smith   ierr = spbas_allocate_data(&retval);CHKERRQ(ierr);
743c328eeadSBarry Smith   /* Copy the structure */
7446322f4bdSBarry Smith   for (i = 0; i<retval.nrows; i++)  {
745b2f1ab58SBarry Smith     i0    = ai[i];
746b2f1ab58SBarry Smith     r_nnz = ai[i+1]-i0;
747b2f1ab58SBarry Smith 
7486322f4bdSBarry Smith     for (j=0; j<r_nnz; j++) {
749b2f1ab58SBarry Smith       retval.icols[i][j] = aj[i0+j]-i;
750b2f1ab58SBarry Smith     }
751b2f1ab58SBarry Smith   }
752b2f1ab58SBarry Smith   *result = retval;
753b2f1ab58SBarry Smith   PetscFunctionReturn(0);
754b2f1ab58SBarry Smith }
755b2f1ab58SBarry Smith 
756b2f1ab58SBarry Smith 
757b2f1ab58SBarry Smith /*
758b2f1ab58SBarry Smith    spbas_mark_row_power:
759b2f1ab58SBarry Smith       Mark the columns in row 'row' which are nonzero in
760b2f1ab58SBarry Smith           matrix^2log(marker).
761b2f1ab58SBarry Smith */
762be332245SKarl Rupp PetscErrorCode spbas_mark_row_power(PetscInt *iwork,             /* marker-vector */
763c328eeadSBarry Smith                                     PetscInt row,                /* row for which the columns are marked */
764c328eeadSBarry Smith                                     spbas_matrix * in_matrix,    /* matrix for which the power is being  calculated */
765c328eeadSBarry Smith                                     PetscInt marker,             /* marker-value: 2^power */
766c328eeadSBarry Smith                                     PetscInt minmrk,             /* lower bound for marked points */
767c328eeadSBarry Smith                                     PetscInt maxmrk)             /* upper bound for marked points */
768b2f1ab58SBarry Smith {
769b2f1ab58SBarry Smith   PetscErrorCode ierr;
770b2f1ab58SBarry Smith   PetscInt       i,j, nnz;
771b2f1ab58SBarry Smith 
772b2f1ab58SBarry Smith   PetscFunctionBegin;
773b2f1ab58SBarry Smith   nnz = in_matrix->row_nnz[row];
774b2f1ab58SBarry Smith 
775c328eeadSBarry Smith   /* For higher powers, call this function recursively */
7766322f4bdSBarry Smith   if (marker>1) {
7776322f4bdSBarry Smith     for (i=0; i<nnz; i++) {
778b2f1ab58SBarry Smith       j = row + in_matrix->icols[row][i];
7796322f4bdSBarry Smith       if (minmrk<=j && j<maxmrk && iwork[j] < marker) {
78071d55d18SBarry Smith         ierr      = spbas_mark_row_power(iwork, row + in_matrix->icols[row][i],in_matrix, marker/2,minmrk,maxmrk);CHKERRQ(ierr);
781b2f1ab58SBarry Smith         iwork[j] |= marker;
782b2f1ab58SBarry Smith       }
783b2f1ab58SBarry Smith     }
7846322f4bdSBarry Smith   } else {
785c328eeadSBarry Smith     /*  Mark the columns reached */
7866322f4bdSBarry Smith     for (i=0; i<nnz; i++)  {
787b2f1ab58SBarry Smith       j = row + in_matrix->icols[row][i];
7882205254eSKarl Rupp       if (minmrk<=j && j<maxmrk) iwork[j] |= 1;
789b2f1ab58SBarry Smith     }
790b2f1ab58SBarry Smith   }
791b2f1ab58SBarry Smith   PetscFunctionReturn(0);
792b2f1ab58SBarry Smith }
793b2f1ab58SBarry Smith 
794b2f1ab58SBarry Smith 
795b2f1ab58SBarry Smith /*
796b2f1ab58SBarry Smith    spbas_power
797b2f1ab58SBarry Smith       Calculate sparseness patterns for incomplete Cholesky decompositions
798b2f1ab58SBarry Smith       of a given order: (almost) all nonzeros of the matrix^(order+1) which
799b2f1ab58SBarry Smith       are inside the band width are found and stored in the output sparseness
800b2f1ab58SBarry Smith       pattern.
801b2f1ab58SBarry Smith */
802b2f1ab58SBarry Smith PetscErrorCode spbas_power(spbas_matrix in_matrix,PetscInt power, spbas_matrix * result)
803b2f1ab58SBarry Smith {
804b2f1ab58SBarry Smith   spbas_matrix   retval;
805b2f1ab58SBarry Smith   PetscInt       nrows = in_matrix.nrows;
806b2f1ab58SBarry Smith   PetscInt       ncols = in_matrix.ncols;
807b2f1ab58SBarry Smith   PetscInt       i, j, kend;
808b2f1ab58SBarry Smith   PetscInt       nnz, inz;
809b2f1ab58SBarry Smith   PetscInt       *iwork;
810b2f1ab58SBarry Smith   PetscInt       marker;
811b2f1ab58SBarry Smith   PetscInt       maxmrk=0;
812b2f1ab58SBarry Smith   PetscErrorCode ierr;
813b2f1ab58SBarry Smith 
814b2f1ab58SBarry Smith   PetscFunctionBegin;
815e32f2f54SBarry 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");
816e32f2f54SBarry Smith   if (ncols != nrows) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Dimension error\n");
817e32f2f54SBarry Smith   if (in_matrix.values) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Input array must be sparseness pattern (no values)");
818e32f2f54SBarry Smith   if (power<=0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Power must be 1 or up");
819b2f1ab58SBarry Smith 
820c328eeadSBarry Smith   /* Copy input values*/
821b2f1ab58SBarry Smith   retval.nrows        = ncols;
822b2f1ab58SBarry Smith   retval.ncols        = nrows;
823b2f1ab58SBarry Smith   retval.nnz          = 0;
824b2f1ab58SBarry Smith   retval.col_idx_type = SPBAS_DIAGONAL_OFFSETS;
825b2f1ab58SBarry Smith   retval.block_data   = PETSC_FALSE;
826b2f1ab58SBarry Smith 
827c328eeadSBarry Smith   /* Allocate sparseness pattern */
82871d55d18SBarry Smith   ierr =  spbas_allocate_pattern(&retval, in_matrix.values ? PETSC_TRUE : PETSC_FALSE);CHKERRQ(ierr);
829b2f1ab58SBarry Smith 
830c328eeadSBarry Smith   /* Allocate marker array */
831785e854fSJed Brown   ierr = PetscMalloc1(nrows, &iwork);CHKERRQ(ierr);
832b2f1ab58SBarry Smith 
833c328eeadSBarry Smith   /* Erase the pattern for this row */
8344e1ff37aSBarry Smith   ierr = PetscMemzero((void*) iwork, retval.nrows*sizeof(PetscInt));CHKERRQ(ierr);
835b2f1ab58SBarry Smith 
836c328eeadSBarry Smith   /* Calculate marker values */
8372205254eSKarl Rupp   marker = 1; for (i=1; i<power; i++) marker*=2;
838b2f1ab58SBarry Smith 
8396322f4bdSBarry Smith   for (i=0; i<nrows; i++)  {
840c328eeadSBarry Smith     /* Calculate the pattern for each row */
841b2f1ab58SBarry Smith 
842b2f1ab58SBarry Smith     nnz  = in_matrix.row_nnz[i];
843b2f1ab58SBarry Smith     kend = i+in_matrix.icols[i][nnz-1];
8442205254eSKarl Rupp     if (maxmrk<=kend) maxmrk=kend+1;
84571d55d18SBarry Smith     ierr = spbas_mark_row_power(iwork, i, &in_matrix, marker, i, maxmrk);CHKERRQ(ierr);
846b2f1ab58SBarry Smith 
847c328eeadSBarry Smith     /* Count the columns*/
848b2f1ab58SBarry Smith     nnz = 0;
8492205254eSKarl Rupp     for (j=i; j<maxmrk; j++) nnz+= (iwork[j]!=0);
850b2f1ab58SBarry Smith 
851c328eeadSBarry Smith     /* Allocate the column indices */
852b2f1ab58SBarry Smith     retval.row_nnz[i] = nnz;
853785e854fSJed Brown     ierr = PetscMalloc1(nnz,&retval.icols[i]);CHKERRQ(ierr);
854b2f1ab58SBarry Smith 
855c328eeadSBarry Smith     /* Administrate the column indices */
856b2f1ab58SBarry Smith     inz = 0;
8576322f4bdSBarry Smith     for (j=i; j<maxmrk; j++) {
8586322f4bdSBarry Smith       if (iwork[j]) {
859b2f1ab58SBarry Smith         retval.icols[i][inz] = j-i;
860b2f1ab58SBarry Smith         inz++;
861b2f1ab58SBarry Smith         iwork[j]=0;
862b2f1ab58SBarry Smith       }
863b2f1ab58SBarry Smith     }
864b2f1ab58SBarry Smith     retval.nnz += nnz;
865b2f1ab58SBarry Smith   };
866b2f1ab58SBarry Smith   ierr    = PetscFree(iwork);CHKERRQ(ierr);
867b2f1ab58SBarry Smith   *result = retval;
868b2f1ab58SBarry Smith   PetscFunctionReturn(0);
869b2f1ab58SBarry Smith }
870b2f1ab58SBarry Smith 
871b2f1ab58SBarry Smith 
872b2f1ab58SBarry Smith 
873b2f1ab58SBarry Smith /*
874b2f1ab58SBarry Smith    spbas_keep_upper:
875b2f1ab58SBarry Smith       remove the lower part of the matrix: keep the upper part
876b2f1ab58SBarry Smith */
877b2f1ab58SBarry Smith PetscErrorCode spbas_keep_upper(spbas_matrix * inout_matrix)
878b2f1ab58SBarry Smith {
879b2f1ab58SBarry Smith   PetscInt i, j;
880b2f1ab58SBarry Smith   PetscInt jstart;
881b2f1ab58SBarry Smith 
882b2f1ab58SBarry Smith   PetscFunctionBegin;
883e32f2f54SBarry Smith   if (inout_matrix->block_data) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Not yet for block data matrices\n");
8846322f4bdSBarry Smith   for (i=0; i<inout_matrix->nrows; i++)  {
8856322f4bdSBarry Smith     for (jstart=0; (jstart<inout_matrix->row_nnz[i]) && (inout_matrix->icols[i][jstart]<0); jstart++) {}
8866322f4bdSBarry Smith     if (jstart>0) {
8876322f4bdSBarry Smith       for (j=0; j<inout_matrix->row_nnz[i]-jstart; j++) {
8886322f4bdSBarry Smith         inout_matrix->icols[i][j] = inout_matrix->icols[i][j+jstart];
889b2f1ab58SBarry Smith       }
890b2f1ab58SBarry Smith 
8916322f4bdSBarry Smith       if (inout_matrix->values) {
8926322f4bdSBarry Smith         for (j=0; j<inout_matrix->row_nnz[i]-jstart; j++) {
8936322f4bdSBarry Smith           inout_matrix->values[i][j] = inout_matrix->values[i][j+jstart];
894b2f1ab58SBarry Smith         }
895b2f1ab58SBarry Smith       }
896b2f1ab58SBarry Smith 
897b2f1ab58SBarry Smith       inout_matrix->row_nnz[i] -= jstart;
898b2f1ab58SBarry Smith 
8996322f4bdSBarry Smith       inout_matrix->icols[i] = (PetscInt*) realloc((void*) inout_matrix->icols[i], inout_matrix->row_nnz[i]*sizeof(PetscInt));
900b2f1ab58SBarry Smith 
9016322f4bdSBarry Smith       if (inout_matrix->values) {
9026322f4bdSBarry Smith         inout_matrix->values[i] = (PetscScalar*) realloc((void*) inout_matrix->values[i], inout_matrix->row_nnz[i]*sizeof(PetscScalar));
903b2f1ab58SBarry Smith       }
904b2f1ab58SBarry Smith       inout_matrix->nnz -= jstart;
905b2f1ab58SBarry Smith     }
906b2f1ab58SBarry Smith   }
907b2f1ab58SBarry Smith   PetscFunctionReturn(0);
908b2f1ab58SBarry Smith }
909b2f1ab58SBarry Smith 
910