Mercurial > hg > octave-kai
changeset 17505:859bb108b9d1
ichol0jp.cc: changed indexing from Fortran to C++ style.
author | Kai T. Ohlhus <k.ohlhus@gmail.com> |
---|---|
date | Wed, 25 Sep 2013 22:31:21 +0200 |
parents | d7b3092df230 |
children | 5fb7fcd3c0e6 |
files | libinterp/dldfcn/ichol0jp.cc |
diffstat | 1 files changed, 88 insertions(+), 138 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/dldfcn/ichol0jp.cc +++ b/libinterp/dldfcn/ichol0jp.cc @@ -21,8 +21,7 @@ * This file implements the Incomplete Cholesky Factorization according to * the Jones and Plassmann strategy. * - * TODO: - remove Fortran indexing - * - implement MIC(0) + * TODO: - implement MIC(0) * - complex input handling */ @@ -34,77 +33,38 @@ #include "defun-dld.h" /** - * Sorts value_vec indirectly addressed by index_vec using heap sort. index_vec - * is arranged such that index_vec[1] addresses the largest element in - * value_vec, index_vec[2] the next largest, and so on. + * Helper class for sorting indirectly addressed values in a sparse matrix. * * @tparam data_t The type of the data operated on. In the real case it will * be "double". - * - * @param len Length of the vectors index_vec and value_vec to be sorted. - * @param value_vec Data to be sorted. - * @param index_vec Index vector of the data. */ -template < typename data_t > void -ihsort (octave_idx_type & len, octave_idx_type * index_vec, - data_t * value_vec) +template < typename data_t > class indexed_value_comperator { - // return if too small - if (len <= 1) - return; +private: + data_t * m_value_vec; +public: + /** + * Constructor. + * + * @param value_vec Vector with the indirectly addressed values. + */ + indexed_value_comperator (data_t * value_vec) + { + m_value_vec = value_vec; + } - // build the heap - octave_idx_type mid = len / 2; - for (octave_idx_type k = mid; k >= 1; k--) - { - octave_idx_type x = index_vec[k]; - octave_idx_type lheap = k; - octave_idx_type rheap = len; - octave_idx_type m = lheap * 2; - while (m <= rheap) - { - if (m < rheap) - if (std::abs (value_vec[index_vec[m]]) > - std::abs (value_vec[index_vec[m + 1]])) - m++; - if (std::abs (value_vec[x]) <= std::abs (value_vec[index_vec[m]])) - m = rheap + 1; - else - { - index_vec[lheap] = index_vec[m]; - lheap = m; - m = 2 * lheap; - } - } - index_vec[lheap] = x; - } - - // sort the heap - for (octave_idx_type k = len; k >= 2; k--) - { - octave_idx_type x = index_vec[k]; - index_vec[k] = index_vec[1]; - octave_idx_type lheap = 1; - octave_idx_type rheap = k - 1; - octave_idx_type m = 2; - while (m <= rheap) - { - if (m < rheap) - if (std::abs (value_vec[index_vec[m]]) > - std::abs (value_vec[index_vec[m + 1]])) - m++; - if (std::abs (value_vec[x]) <= std::abs (value_vec[index_vec[m]])) - m = rheap + 1; - else - { - index_vec[lheap] = index_vec[m]; - lheap = m; - m = 2 * lheap; - } - } - index_vec[lheap] = x; - } -} + /** + * Comparison function. + * + * @param a First indirect address to a value in value_vec. + * @param b Second indirect address to a value in value_vec. + * @return true, if abs(value_vec[a]) < abs (value_vec[b]), otherwise false. + */ + bool operator () (octave_idx_type a, octave_idx_type b) + { + return std::abs (m_value_vec[a]) < std::abs (m_value_vec[b]); + } +}; /** * Get the k largest non-zeros in value_vec indirectly addressed by index_vec. @@ -127,47 +87,41 @@ if ((n <= 1) || (k <= 0)) return; - // heap sort the first k elements of the vector - ihsort (k, index_vec, value_vec); + // create comperator for indirectly addressed values + indexed_value_comperator < data_t > cmp (value_vec); + + // sort the first k elements of the index vector + std::sort (index_vec, index_vec + k, cmp); // loop through the rest of the vector and find any elements that are larger // than any of the first k elements - data_t cur_min = std::abs (value_vec[index_vec[k]]); - for (octave_idx_type i = k + 1; i <= n; i++) + for (octave_idx_type i = k; i < n; i++) { - octave_idx_type itemp = index_vec[i]; - data_t new_value = std::abs (value_vec[itemp]); - if (new_value > cur_min) + // if there is a larger element + if (cmp (index_vec[k - 1], index_vec[i])) { - // find position for new value - octave_idx_type left = 1; - data_t lval = std::abs (value_vec[index_vec[1]]); - octave_idx_type cur_ptr = 1; - if (new_value <= lval) + // find position for new value (insert_idx) using bisection + octave_idx_type left_idx = 0; // left index of sorted k elements + octave_idx_type right_idx = k - 1; // right index of sorted k elements + octave_idx_type insert_idx = (left_idx + right_idx) / 2; // set to middle (not exact) + if (!cmp (index_vec[left_idx], index_vec[i])) { - octave_idx_type right = k; - cur_ptr = (k + 1) / 2; - while (right > left + 1) + while (left_idx + 1 < right_idx) { - data_t cur_val = std::abs (value_vec[index_vec[cur_ptr]]); - if (cur_val < new_value) - right = cur_ptr; + if (cmp (index_vec[insert_idx], index_vec[i])) + right_idx = insert_idx; else - { - left = cur_ptr; - lval = cur_val; - } - cur_ptr = (right + left) / 2; + left_idx = insert_idx; + insert_idx = (left_idx + right_idx) / 2; } - cur_ptr = right; + insert_idx = right_idx; } // shift sorted values and insert new value - index_vec[i] = index_vec[k]; - for (octave_idx_type j = k; j >= cur_ptr + 1; j--) + index_vec[i] = index_vec[k - 1]; + for (octave_idx_type j = k - 1; j > insert_idx; j--) index_vec[j] = index_vec[j - 1]; - index_vec[cur_ptr] = itemp; - cur_min = std::abs (value_vec[index_vec[k]]); + index_vec[insert_idx] = index_vec[i]; } } } @@ -210,42 +164,43 @@ octave_column_vector_t result_diag (n); octave_sparse_matrix_t result_A (n, n, nnz); - // Allocate working memory (Fortran indexing) - OCTAVE_LOCAL_BUFFER (data_t, diag, n + 1); - OCTAVE_LOCAL_BUFFER (data_t, off_data, nnz + 1); - OCTAVE_LOCAL_BUFFER (octave_idx_type, cidx, n + 2); - OCTAVE_LOCAL_BUFFER (octave_idx_type, ridx, nnz + 1); - OCTAVE_LOCAL_BUFFER (data_t, ta, n + 1); - OCTAVE_LOCAL_BUFFER (octave_idx_type, itcol, n + 1); - OCTAVE_LOCAL_BUFFER (octave_idx_type, ifirst, n + 1); - OCTAVE_LOCAL_BUFFER (octave_idx_type, list, n + 1); + // Define convenience pointers to the data structures + data_t *diag = result_diag.fortran_vec (); + data_t *off_data = result_A.data (); + octave_idx_type *cidx = result_A.cidx (); + octave_idx_type *ridx = result_A.ridx (); + + // Allocate working memory + OCTAVE_LOCAL_BUFFER (data_t, ta, n); + OCTAVE_LOCAL_BUFFER (octave_idx_type, itcol, n); + OCTAVE_LOCAL_BUFFER (octave_idx_type, ifirst, n); + OCTAVE_LOCAL_BUFFER (octave_idx_type, list, n); - // Copy input data to work and result data structures - for (octave_idx_type i = 1; i <= n; i++) - diag[i] = in_diag (i - 1); - for (octave_idx_type i = 1; i <= nnz; i++) - off_data[i] = in_A.data (i - 1); - for (octave_idx_type i = 1; i <= (n + 1); i++) + // Copy input data to result data structures + for (octave_idx_type i = 0; i < n; i++) + diag[i] = in_diag (i); + for (octave_idx_type i = 0; i < nnz; i++) + off_data[i] = in_A.data (i); + for (octave_idx_type i = 0; i < (n + 1); i++) { - cidx[i] = in_A.cidx (i - 1) + 1; - result_A.cidx (i - 1) = in_A.cidx (i - 1); + cidx[i] = in_A.cidx (i); } - for (octave_idx_type i = 1; i <= nnz; i++) - ridx[i] = in_A.ridx (i - 1) + 1; + for (octave_idx_type i = 0; i < nnz; i++) + ridx[i] = in_A.ridx (i); // Initialize data structures - for (octave_idx_type j = 1; j <= n; j++) + for (octave_idx_type j = 0; j < n; j++) { - ifirst[j] = 0; - list[j] = 0; + ifirst[j] = -1; + list[j] = -1; } // loop over all columns - for (octave_idx_type k = 1; k <= n; k++) + for (octave_idx_type k = 0; k < n; k++) { // load column k into working vector ta - octave_idx_type ta_len = 0; + octave_idx_type ta_len = -1; octave_idx_type col_k_start = cidx[k]; octave_idx_type col_k_end = cidx[k + 1] - 1; for (octave_idx_type j = col_k_start; j <= col_k_end; j++) @@ -254,7 +209,7 @@ ta[row] = off_data[j]; ta_len++; itcol[ta_len] = row; - ifirst[row] = 1; + ifirst[row] = 0; } // make sure the diagonal of k is okay and then take the sqrt @@ -268,7 +223,7 @@ // update column k using the previous columns octave_idx_type j = list[k]; - while (j != 0) + while (j != -1) { octave_idx_type col_j_start = ifirst[j]; octave_idx_type col_j_end = cidx[j + 1] - 1; @@ -287,11 +242,13 @@ for (octave_idx_type i = col_j_start; i <= col_j_end; i++) { octave_idx_type row = ridx[i]; - if (ifirst[row] != 0) - ta[row] -= lval * off_data[i]; + if (ifirst[row] != -1) + { + ta[row] -= lval * off_data[i]; + } else { - ifirst[row] = 1; + ifirst[row] = 0; ta_len++; itcol[ta_len] = row; ta[row] = -lval * off_data[i]; @@ -300,7 +257,7 @@ } // update remaining diagonals using column k - for (j = 1; j <= ta_len; j++) + for (j = 0; j <= ta_len; j++) { octave_idx_type row = itcol[j]; ta[row] /= diag[k]; @@ -308,12 +265,13 @@ } // find the largest elements in column k now - octave_idx_type count = std::min (col_k_end - col_k_start + 1, ta_len); + octave_idx_type count = + std::max (std::min (col_k_end - col_k_start + 1, ta_len), 0); ibsort (ta_len, count, ta, itcol); - std::sort (itcol + 1, itcol + 1 + count); + std::sort (itcol, itcol + count); // put the largest elements back into the sparse data structure - count = 1; + count = 0; for (j = col_k_start; j <= col_k_end; j++) { off_data[j] = ta[itcol[count]]; @@ -330,18 +288,10 @@ ifirst[k] = col_k_start; } - for (j = 1; j <= ta_len; j++) - ifirst[itcol[j]] = 0; + for (j = 0; j < ta_len; j++) + ifirst[itcol[j]] = -1; } - // Copy new data to result data structures - for (octave_idx_type i = 1; i <= n; i++) - result_diag (i - 1) = diag[i]; - for (octave_idx_type i = 1; i <= nnz; i++) - result_A.ridx (i - 1) = ridx[i] - 1; - for (octave_idx_type i = 1; i <= nnz; i++) - result_A.data (i - 1) = off_data[i]; - retval (1) = octave_value (result_diag); retval (0) = octave_value (result_A);