diff --git a/src/association_pmt.cpp b/src/association_pmt.cpp index 3856984f..2e8d79a5 100644 --- a/src/association_pmt.cpp +++ b/src/association_pmt.cpp @@ -2,18 +2,13 @@ using namespace Rcpp; -inline void association_do( - unsigned& i, +inline bool association_update( + PermuBar& bar, const NumericVector& x, const NumericVector& y, - const Function& statistic_func, - NumericVector& statistic_permu, - ProgressBar& bar) + const Function& statistic_func) { - statistic_permu[i] = as(statistic_func(x, y)); - - bar.update(i); - i++; + return bar.update(as(statistic_func(x, y))); } // [[Rcpp::export]] @@ -23,26 +18,21 @@ NumericVector association_pmt( const Function statistic_func, const unsigned n_permu) { - ProgressBar bar; - NumericVector statistic_permu; - - unsigned i = 0; if (n_permu == 0) { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permutation(y), true); + PermuBar bar(n_permutation(y), true); do { - association_do(i, x, y, statistic_func, statistic_permu, bar); + association_update(bar, x, y, statistic_func); } while (std::next_permutation(y.begin(), y.end())); + + return bar.statistic_permu; } else { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permu, false); + PermuBar bar(n_permu, false); - while (i < n_permu) { + do { random_shuffle(y); - association_do(i, x, y, statistic_func, statistic_permu, bar); - } - } - - bar.done(); + } while (association_update(bar, x, y, statistic_func)); - return statistic_permu; + return bar.statistic_permu; + } } diff --git a/src/ksample_pmt.cpp b/src/ksample_pmt.cpp index 26134319..3eec83f5 100644 --- a/src/ksample_pmt.cpp +++ b/src/ksample_pmt.cpp @@ -2,18 +2,13 @@ using namespace Rcpp; -inline void ksample_do( - unsigned& i, +inline bool ksample_update( + PermuBar& bar, const NumericVector& data, const IntegerVector& group, - const Function& statistic_func, - NumericVector& statistic_permu, - ProgressBar& bar) + const Function& statistic_func) { - statistic_permu[i] = as(statistic_func(data, group)); - - bar.update(i); - i++; + return bar.update(as(statistic_func(data, group))); } // [[Rcpp::export]] @@ -23,26 +18,22 @@ NumericVector ksample_pmt( const Function statistic_func, const unsigned n_permu) { - ProgressBar bar; - NumericVector statistic_permu; - unsigned i = 0; if (n_permu == 0) { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permutation(group), true); + PermuBar bar(n_permutation(group), true); do { - ksample_do(i, data, group, statistic_func, statistic_permu, bar); + ksample_update(bar, data, group, statistic_func); } while (std::next_permutation(group.begin(), group.end())); + + return bar.statistic_permu; } else { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permu, false); + PermuBar bar(n_permu, false); - while (i < n_permu) { + do { random_shuffle(group); - ksample_do(i, data, group, statistic_func, statistic_permu, bar); - } - } - - bar.done(); + } while (ksample_update(bar, data, group, statistic_func)); - return statistic_permu; + return bar.statistic_permu; + } } diff --git a/src/multicomp_pmt.cpp b/src/multicomp_pmt.cpp index 4b7381f7..b9c50416 100644 --- a/src/multicomp_pmt.cpp +++ b/src/multicomp_pmt.cpp @@ -2,28 +2,27 @@ using namespace Rcpp; -inline void multicomp_do( - unsigned& i, - const unsigned& n, +inline bool multicomp_update( + PermuBar& bar, const unsigned& n_pair, + const unsigned& n_group, const IntegerVector& group_i, const IntegerVector& group_j, const NumericVector& data, const IntegerVector& group, const Function& statistic_func, - NumericVector& statistic_permu, - ProgressBar& bar, List& split) + List& split) { - for (unsigned j = 1; j <= n; j++) { - split[j - 1] = data[group == j]; + for (unsigned i = 1; i <= n_group; i++) { + split[i - 1] = data[group == i]; } - for (unsigned k = 0; k < n_pair; k++) { - statistic_permu(k, i) = as(statistic_func(split[group_i[k]], split[group_j[k]], data, group)); + unsigned j; + for (j = 0; j < n_pair - 1; j++) { + bar.update(as(statistic_func(split[group_i[j]], split[group_j[j]], data, group))); } - bar.update(i); - i++; + return bar.update(as(statistic_func(split[group_i[j]], split[group_j[j]], data, group))); } // [[Rcpp::export]] @@ -35,30 +34,26 @@ NumericVector multicomp_pmt( const Function statistic_func, const unsigned n_permu) { - ProgressBar bar; - NumericVector statistic_permu; + unsigned n_group = group[group.size() - 1]; + unsigned n_pair = n_group * (n_group - 1) / 2; - unsigned n_pair = group_i.size(); - unsigned n = group[group.size() - 1]; - List split(n); + List split(n_group); - unsigned i = 0; if (n_permu == 0) { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permutation(group), true, n_pair); + PermuBar bar(n_permutation(group), true, n_pair); do { - multicomp_do(i, n, n_pair, group_i, group_j, data, group, statistic_func, statistic_permu, bar, split); + multicomp_update(bar, n_pair, n_group, group_i, group_j, data, group, statistic_func, split); } while (std::next_permutation(group.begin(), group.end())); + + return bar.statistic_permu; } else { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permu, false, n_pair); + PermuBar bar(n_permu, false, n_pair); - while (i < n_permu) { + do { random_shuffle(group); - multicomp_do(i, n, n_pair, group_i, group_j, data, group, statistic_func, statistic_permu, bar, split); - } - } + } while (multicomp_update(bar, n_pair, n_group, group_i, group_j, data, group, statistic_func, split)); - bar.done(); - - return statistic_permu; + return bar.statistic_permu; + } } diff --git a/src/paired_pmt.cpp b/src/paired_pmt.cpp index b8a312d2..5fb15541 100644 --- a/src/paired_pmt.cpp +++ b/src/paired_pmt.cpp @@ -2,22 +2,18 @@ using namespace Rcpp; -inline void paired_do( - unsigned& i, - const unsigned& k, +inline bool paired_update( + PermuBar& bar, + const unsigned& i, const unsigned& n, const Function& statistic_func, - NumericVector& statistic_permu, - ProgressBar& bar, LogicalVector& swapped) + LogicalVector& swapped) { for (unsigned j = 0; j < n; j++) { swapped[j] = ((i & (1 << j)) != 0); } - statistic_permu[i] = as(statistic_func(swapped)); - - bar.update(i); - i++; + return bar.update(as(statistic_func(swapped))); } // [[Rcpp::export]] @@ -26,28 +22,27 @@ NumericVector paired_pmt( const Function statistic_func, const unsigned n_permu) { - ProgressBar bar; - NumericVector statistic_permu; + unsigned total = (1 << n); LogicalVector swapped(n); - unsigned total = (1 << n); unsigned i = 0; if (n_permu == 0) { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(total, true); + PermuBar bar(total, true); - while (i < total) { - paired_do(i, i, n, statistic_func, statistic_permu, bar, swapped); - } - } else { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permu, false); + do { + paired_update(bar, i, n, statistic_func, swapped); + i++; + } while (i < total); - while (i < n_permu) { - paired_do(i, rand_int(total), n, statistic_func, statistic_permu, bar, swapped); - } - } + return bar.statistic_permu; + } else { + PermuBar bar(n_permu, false); - bar.done(); + do { + i = rand_int(total); + } while (paired_update(bar, i, n, statistic_func, swapped)); - return statistic_permu; + return bar.statistic_permu; + } } \ No newline at end of file diff --git a/src/rcbd_pmt.cpp b/src/rcbd_pmt.cpp index 39f6fa99..383c1d9a 100644 --- a/src/rcbd_pmt.cpp +++ b/src/rcbd_pmt.cpp @@ -2,17 +2,13 @@ using namespace Rcpp; -inline void rcbd_do( - unsigned& i, +inline bool rcbd_update( + PermuBar& bar, const NumericMatrix& data, - const Function& statistic_func, - NumericVector& statistic_permu, - ProgressBar& bar) + const Function& statistic_func + ) { - statistic_permu[i] = as(statistic_func(data)); - - bar.update(i); - i++; + return bar.update(as(statistic_func(data))); } // [[Rcpp::export]] @@ -21,43 +17,39 @@ NumericVector rcbd_pmt( const Function statistic_func, const unsigned n_permu) { - ProgressBar bar; - NumericVector statistic_permu; - unsigned n_col = data.ncol(); unsigned i = 0; - unsigned j = 0; if (n_permu == 0) { unsigned total = 1; - for (unsigned k = 0; k < n_col; k++) { - total *= n_permutation(data.column(k)); + for (unsigned j = 0; j < n_col; j++) { + total *= n_permutation(data.column(j)); } - std::tie(statistic_permu, bar) = statistic_permu_with_bar(total, true); - while (j < n_col) { - if (j == 0) { - rcbd_do(i, data, statistic_func, statistic_permu, bar); + PermuBar bar(total, true); + + while (i < n_col) { + if (i == 0) { + rcbd_update(bar, data, statistic_func); } - if (std::next_permutation(data.column(j).begin(), data.column(j).end())) { - j = 0; + if (std::next_permutation(data.column(i).begin(), data.column(i).end())) { + i = 0; } else { - j++; + i++; } } + + return bar.statistic_permu; } else { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permu, false); + PermuBar bar(n_permu, false); - while (i < n_permu) { - for (j = 0; j < n_col; j++) { - random_shuffle(data.column(j)); + do { + for (i = 0; i < n_col; i++) { + random_shuffle(data.column(i)); } - rcbd_do(i, data, statistic_func, statistic_permu, bar); - } - } + } while (rcbd_update(bar, data, statistic_func)); - bar.done(); - - return statistic_permu; + return bar.statistic_permu; + } } diff --git a/src/table_pmt.cpp b/src/table_pmt.cpp index bfb758ba..7e56420d 100644 --- a/src/table_pmt.cpp +++ b/src/table_pmt.cpp @@ -2,25 +2,21 @@ using namespace Rcpp; -inline void table_do( - unsigned& i, +inline bool table_update( + PermuBar& bar, const unsigned& n, const IntegerVector& row_loc, const IntegerVector& col_loc, const Function& statistic_func, - NumericVector& statistic_permu, - ProgressBar& bar, IntegerMatrix& data) + IntegerMatrix& data) { data.fill(0); - for (unsigned j = 0; j < n; j++) { - data(row_loc[j], col_loc[j])++; + for (unsigned i = 0; i < n; i++) { + data(row_loc[i], col_loc[i])++; } - statistic_permu[i] = as(statistic_func(data)); - - bar.update(i); - i++; + return bar.update(as(statistic_func(data))); } // [[Rcpp::export]] @@ -30,29 +26,25 @@ NumericVector table_pmt( const Function statistic_func, const unsigned n_permu) { - ProgressBar bar; - NumericVector statistic_permu; - unsigned n = row_loc.size(); - IntegerMatrix data(row_loc[n - 1] + 1, col_loc[n - 1] + 1); - unsigned i = 0; + IntegerMatrix data(no_init(row_loc[n - 1] + 1, col_loc[n - 1] + 1)); + if (n_permu == 0) { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permutation(row_loc), true); + PermuBar bar(n_permutation(row_loc), true); do { - table_do(i, n, row_loc, col_loc, statistic_func, statistic_permu, bar, data); + table_update(bar, n, row_loc, col_loc, statistic_func, data); } while (std::next_permutation(row_loc.begin(), row_loc.end())); + + return bar.statistic_permu; } else { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permu, false); + PermuBar bar(n_permu, false); - while (i < n_permu) { + do { random_shuffle(row_loc); - table_do(i, n, row_loc, col_loc, statistic_func, statistic_permu, bar, data); - } - } + } while (table_update(bar, n, row_loc, col_loc, statistic_func, data)); - bar.done(); - - return statistic_permu; + return bar.statistic_permu; + } } diff --git a/src/twosample_pmt.cpp b/src/twosample_pmt.cpp index 61c6cccd..f4f789da 100644 --- a/src/twosample_pmt.cpp +++ b/src/twosample_pmt.cpp @@ -2,18 +2,13 @@ using namespace Rcpp; -inline void twosample_do( - unsigned& i, +inline bool twosample_update( + PermuBar& bar, const NumericVector& data, const LogicalVector& where_y, - const Function& statistic_func, - NumericVector& statistic_permu, - ProgressBar& bar) + const Function& statistic_func) { - statistic_permu[i] = as(statistic_func(data[!where_y], data[where_y])); - - bar.update(i); - i++; + return bar.update(as(statistic_func(data[!where_y], data[where_y]))); } // [[Rcpp::export]] @@ -23,26 +18,21 @@ NumericVector twosample_pmt( const Function statistic_func, const unsigned n_permu) { - ProgressBar bar; - NumericVector statistic_permu; - - unsigned i = 0; if (n_permu == 0) { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permutation(where_y), true); + PermuBar bar(n_permutation(where_y), true); do { - twosample_do(i, data, where_y, statistic_func, statistic_permu, bar); + twosample_update(bar, data, where_y, statistic_func); } while (std::next_permutation(where_y.begin(), where_y.end())); + + return bar.statistic_permu; } else { - std::tie(statistic_permu, bar) = statistic_permu_with_bar(n_permu, false); + PermuBar bar(n_permu, false); - while (i < n_permu) { + do { random_shuffle(where_y); - twosample_do(i, data, where_y, statistic_func, statistic_permu, bar); - } - } - - bar.done(); + } while (twosample_update(bar, data, where_y, statistic_func)); - return statistic_permu; + return bar.statistic_permu; + } } diff --git a/src/utils.cpp b/src/utils.cpp deleted file mode 100644 index 53015824..00000000 --- a/src/utils.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "utils.h" - -std::tuple statistic_permu_with_bar( - const unsigned n, const bool exact, - const unsigned statistic_size) -{ - Environment base("package:base"); - Function interactive = base["interactive"]; - - ProgressBar bar(n, as(interactive())); - if (exact) { - bar.set_label("Building exact permutation distribution"); - } else { - bar.set_label("Sampling from exact permutation distribution"); - } - - NumericVector statistic_permu(no_init(n * statistic_size)); - if (statistic_size > 1) { - statistic_permu.attr("dim") = IntegerVector::create(statistic_size, n); - } - - return std::tuple(statistic_permu, bar); -} \ No newline at end of file diff --git a/src/utils.h b/src/utils.h index 4a65e7e9..277f6774 100644 --- a/src/utils.h +++ b/src/utils.h @@ -3,88 +3,20 @@ #include #include +#include #include -#include using namespace Rcpp; -// progress bar - -class ProgressBar { -private: - unsigned _end; - - unsigned _update_every; - - std::string _label; - - bool _appear; - -public: - ProgressBar() {} - - ProgressBar(unsigned n, bool appear) - { - _end = n - 1; - _update_every = 1 + _end / 100; - - _appear = appear; - } - - void set_label(std::string label) - { - _label = label; - } - - void done() - { - if (_appear) { - Rcout << "\015" << "\033[K" << "\033[0m"; - } - } - - void update(unsigned current) - { - if (_appear && (current % _update_every == 0)) { - Rcout << "\015"; - - unsigned percent = 100 * current / _end; - - Rcout << "\033[31m" << percent << "%"; - - Rcout << " "; - - Rcout << "\033[32m" << "["; - unsigned n_fill = percent >> 2; - unsigned i = 0; - while (i < n_fill) { - Rcout << "="; - i++; - } - while (i < 25) { - Rcout << " "; - i++; - } - Rcout << "]"; - - Rcout << " "; - - Rcout << "\033[34m" << _label; - } - } -}; - -std::tuple statistic_permu_with_bar( - const unsigned n, const bool exact, - const unsigned statistic_size = 1); - -// random shuffle (tied to the same RNG which R uses) +// runif(max = n) (tied to the same RNG which R uses) inline unsigned rand_int(const unsigned& n) { return floor(unif_rand() * n); } +// random shuffle + template void random_shuffle(T&& v) { @@ -96,7 +28,7 @@ void random_shuffle(T&& v) } } -// count +// number of permutations template unsigned n_permutation(T&& v) @@ -120,4 +52,114 @@ unsigned n_permutation(T&& v) return (unsigned)A; } +// progress bar + +class PermuBar { +private: + unsigned _total; + + unsigned _update_i = 0; + unsigned _update_every; + + NumericVector::iterator _iter; + NumericVector::iterator _end; + + std::string _label; + + bool _appear; + + void _print() + { + std::ostringstream buffer; + + buffer << "\015"; + + unsigned percent = 100 - 100 * (_end - _iter) / _total; + + buffer << "\033[31m" << percent << "%"; + + buffer << " "; + + buffer << "\033[32m" << "["; + unsigned n_fill = (percent >> 2); + unsigned i = 0; + while (i < n_fill) { + buffer << "="; + i++; + } + while (i < 25) { + buffer << " "; + i++; + } + buffer << "]"; + + buffer << " "; + + buffer << "\033[34m" << _label; + + Rcout << buffer.str(); + } + +public: + NumericVector statistic_permu; + + PermuBar(unsigned n_permu, bool exact, unsigned statistic_size = 1) + { + _total = n_permu * statistic_size; + + if (_total < 100) { + _update_every = 1; + } else { + _update_every = _total / 100; + } + + statistic_permu = NumericVector(no_init(_total)); + if (statistic_size > 1) { + statistic_permu.attr("dim") = IntegerVector::create(statistic_size, n_permu); + } + + _iter = statistic_permu.begin(); + _end = statistic_permu.end(); + + if (exact) { + _label = "Building exact permutation distribution"; + } else { + _label = "Sampling from exact permutation distribution"; + } + + Environment base = Environment::base_env(); + Function interactive = base["interactive"]; + _appear = as(interactive()); + + if (_appear) { + _print(); + } + } + + ~PermuBar() + { + if (_appear) { + _print(); + Rcout << "\015\033[K\033[0m"; + } + } + + bool update(double statistic) + { + *_iter = statistic; + + _update_i++; + if (_update_i == _update_every) { + _update_i = 0; + if (_appear) { + _print(); + } + } + + _iter++; + + return _iter != _end; + } +}; + #endif