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