27 #ifndef TOMOGRAPHER_MHRW_BIN_ERR_H
28 #define TOMOGRAPHER_MHRW_BIN_ERR_H
35 #include <boost/math/constants/constants.hpp>
49 namespace tomo_internal {
53 template<
int NumLevels,
bool calculate>
54 struct helper_samples_size {
56 value = Eigen::Dynamic
59 template<
int NumLevels>
60 struct helper_samples_size<NumLevels,true> {
62 value = (1 << NumLevels)
106 template<
typename ValueType_,
int NumTrackValues_ = Eigen::Dynamic,
int NumLevels_ = Eigen::Dynamic,
107 bool StoreBinSums_ =
true,
typename CountIntType_ =
int>
118 static constexpr
int NumTrackValuesCTime = NumTrackValues_;
120 static constexpr
int NumLevelsCTime = NumLevels_;
122 static constexpr
int NumLevelsPlusOneCTime = (NumLevelsCTime == Eigen::Dynamic
124 : (NumLevelsCTime + 1));
147 static constexpr
int SamplesSizeCTime =
148 tomo_internal::helper_samples_size<NumLevelsCTime, (NumLevelsCTime > 0 && NumLevelsCTime < 7)>::value;
155 static constexpr
bool StoreBinSums = StoreBinSums_;
184 UNKNOWN_CONVERGENCE = 0,
248 template<
typename Params,
typename LoggerType_>
260 static constexpr
int NumTrackValuesCTime = Params::NumTrackValuesCTime;
264 static constexpr
int NumLevelsCTime = Params::NumLevelsCTime;
268 static constexpr
int NumLevelsPlusOneCTime = Params::NumLevelsPlusOneCTime;
272 static constexpr
int SamplesSizeCTime = Params::SamplesSizeCTime;
276 static constexpr
bool StoreBinSums = Params::StoreBinSums;
321 UNKNOWN_CONVERGENCE = Params::UNKNOWN_CONVERGENCE,
323 CONVERGED = Params::CONVERGED,
325 NOT_CONVERGED = Params::NOT_CONVERGED
341 SamplesArray samples;
349 CountIntType n_samples;
355 CountIntType n_flushes;
376 BinSumSqArray bin_sumsq;
394 : num_track_values(num_track_values_),
395 num_levels(num_levels_),
396 samples_size(1 << num_levels()),
397 samples(num_track_values(), samples_size()),
399 bin_sum(BinSumArray::Zero(num_track_values())),
400 bin_sumsq(BinSumSqArray::Zero(num_track_values(), num_levels()+1)),
405 assert( (1<<num_levels()) == samples_size() );
419 helper_reset_bin_sum();
420 bin_sumsq = BinSumSqArray::Zero(num_track_values(), num_levels()+1);
421 logger.longdebug(
"BinningAnalysis::reset()",
"ready to go.");
434 template<
typename Derived>
437 const int ninbin = n_samples % samples_size();
441 eigen_assert(vals.rows() == num_track_values());
442 eigen_assert(vals.cols() == 1);
445 samples.col(ninbin) = vals;
448 helper_update_bin_sum(samples.col(ninbin));
451 if ( ninbin == samples_size() - 1 ) {
455 logger.longdebug(
"BinningAnalysis::process_new_values()", [&](
std::ostream & str) {
456 str <<
"n_samples is now " << n_samples <<
"; flushing bins. samples_size() = " << samples_size();
462 for (
int level = 0; level <= num_levels(); ++level) {
464 const int binnedsize = 1 << (num_levels()-level);
466 logger.longdebug(
"BinningAnalysis::process_new_values()", [&](
std::ostream & str) {
467 str <<
"Processing binning level = " << level <<
": binnedsize="<<binnedsize
468 <<
"; n_flushes=" << n_flushes <<
"\n";
469 str <<
"\tbinned samples = \n" << samples.block(0,0,num_track_values(),binnedsize);
472 for (
int ksample = 0; ksample < binnedsize; ++ksample) {
473 bin_sumsq.
col(level) += samples.col(ksample).cwiseProduct(samples.col(ksample));
474 if (ksample % 2 == 0 && binnedsize > 1) {
475 samples.col(ksample/2) = boost::math::constants::half<ValueType>() *
476 (samples.col(ksample) + samples.col(ksample+1));
482 logger.longdebug(
"BinningAnalysis::process_new_values()", [&](
std::ostream & str) {
483 str <<
"Flushing #" << n_flushes <<
" done. bin_sum is = \n" << bin_sum <<
"\n"
484 <<
"\tbin_sumsq is = \n" << bin_sumsq <<
"\n";
497 template<
typename CalcValType, TOMOGRAPHER_ENABLED_IF_TMPL(NumTrackValuesCTime == 1)>
509 TOMOGRAPHER_ENABLED_IF(StoreBinSums)
510 inline
void helper_reset_bin_sum()
512 bin_sum.value = BinSumArray::Zero(num_track_values());
514 TOMOGRAPHER_ENABLED_IF(!StoreBinSums)
515 inline
void helper_reset_bin_sum() { }
517 TOMOGRAPHER_ENABLED_IF(StoreBinSums)
518 inline
void helper_update_bin_sum(const
Eigen::Ref<const
Eigen::Array<ValueType, NumTrackValuesCTime, 1> > &
521 bin_sum.value += new_samples;
523 template<
typename Derived,
524 TOMOGRAPHER_ENABLED_IF_TMPL(!StoreBinSums)>
542 TOMOGRAPHER_ENABLED_IF(StoreBinSums)
543 inline auto get_bin_means() const
544 #ifndef TOMOGRAPHER_PARSED_BY_DOXYGEN
545 -> decltype(BinSumArray() / ValueType(n_samples))
548 return bin_sum.value / ValueType(n_samples);
558 #ifndef TOMOGRAPHER_PARSED_BY_DOXYGEN
560 bin_sumsq.cwiseQuotient(n_flushes * replicated<NumTrackValuesCTime,1>(
562 .transpose().reverse(),
564 num_track_values(), 1
569 return bin_sumsq.cwiseQuotient(n_flushes * replicated<NumTrackValuesCTime,1>(
571 .transpose().reverse(),
573 num_track_values(), 1
582 TOMOGRAPHER_ENABLED_IF(StoreBinSums)
583 inline const BinSumArray & get_bin_sum()
const {
return bin_sum.value; }
606 template<
typename Derived>
609 eigen_assert(means.rows() == num_track_values());
610 eigen_assert(means.cols() == 1);
611 const int n_levels_plus_one = num_levels()+1;
612 const int n_track_values = num_track_values();
619 get_bin_sqmeans() - replicated<1,NumLevelsPlusOneCTime>(
624 ).cwiseMax(0).cwiseQuotient(
626 replicated<NumTrackValuesCTime,1>(
628 .transpose().reverse(),
633 num_track_values(), num_levels()+1,
651 template<
typename Derived>
653 eigen_assert(means.rows() == num_track_values());
654 eigen_assert(means.cols() == 1);
656 bin_sumsq.col(num_levels()) / ValueType(n_flushes) - means.
cwiseProduct(means).template cast<ValueType>()
657 ).cwiseMax(0).cwiseSqrt() /
std::sqrt(ValueType(n_flushes-1));
671 TOMOGRAPHER_ENABLED_IF(StoreBinSums)
672 inline BinSumSqArray calc_error_levels()
const {
673 BinSumArray means = get_bin_means();
674 return calc_error_levels(means);
689 TOMOGRAPHER_ENABLED_IF(StoreBinSums)
690 inline BinSumArray calc_error_lastlevel()
const {
691 BinSumArray means = get_bin_means();
692 return calc_error_lastlevel(means);
709 Eigen::ArrayXi converged_status(num_track_values());
711 eigen_assert(error_levels.rows() == num_track_values());
712 eigen_assert(error_levels.cols() == num_levels() + 1);
714 logger.longdebug(
"BinningAnalysis::determine_error_convergence", [&](
std::ostream & str) {
715 str <<
"error_levels = \n" << error_levels <<
"\n";
722 if (num_levels() < range-1) {
724 converged_status = Eigen::ArrayXi::Constant(num_track_values(), UNKNOWN_CONVERGENCE);
728 converged_status = Eigen::ArrayXi::Constant(num_track_values(), CONVERGED);
730 const auto & errors = error_levels.col(num_levels());
732 for (
int level = num_levels()+1 - range; level < num_levels(); ++level) {
734 const auto & errors_thislevel = error_levels.col(level);
736 logger.longdebug(
"BinningAnalysis::determine_error_convergence", [&](
std::ostream & str) {
737 str <<
"About to study level " << level <<
": at this point, converged_status = \n"
738 << converged_status <<
"\nand errors_thislevel = \n" << errors_thislevel;
741 for (
int val_it = 0; val_it < num_track_values(); ++val_it) {
742 if (errors_thislevel(val_it) >= errors(val_it) &&
743 converged_status(val_it) != NOT_CONVERGED) {
744 converged_status(val_it) = CONVERGED;
745 }
else if (errors_thislevel(val_it) < 0.824 * errors(val_it)) {
746 converged_status(val_it) = NOT_CONVERGED;
747 }
else if ((errors_thislevel(val_it) < 0.9 * errors(val_it)) &&
748 converged_status(val_it) != NOT_CONVERGED) {
749 converged_status(val_it) = UNKNOWN_CONVERGENCE;
757 logger.longdebug(
"BinningAnalysis::determine_error_convergence", [&](
std::ostream & str) {
758 str <<
"Done. converged_status [0=UNNOWN,1=CONVERGED,2=NOT CONVERGED] = \n"
762 return converged_status;
Eigen::ArrayXi determine_error_convergence(const Eigen::Ref< const BinSumSqArray > &error_levels) const
Attempt to determine if the error bars have converged.
Params::BinSumSqArray BinSumSqArray
Type used to store the sum of squares of values at each binning level. See BinningAnalysisParams::Bin...
CountIntType get_n_flushes() const
Return the number of times the collected samples were flushed.
Base namespace for the Tomographer project.
Group template parameters for BinningAnalysis.
BinSumSqArray calc_error_levels(const Eigen::ArrayBase< Derived > &means) const
Calculate the error bars of samples at different binning levels.
Eigen::Array< ValueType, NumTrackValuesCTime, 1 > BinSumArray
Type used to store the sum of values.
Params::CountIntType CountIntType
Type used to count the number of samples. See BinningAnalysisParams::CountIntType.
The error bars appear to have converged.
auto powers_of_two(IndexTypes...sizes) -> const Eigen::CwiseNullaryOp< tomo_internal::powers_of_two_generator< typename Eigen::internal::traits< Der >::Scalar >, Der >
Expression for a 1-D expression of powers of two.
const BinSumSqArray & get_bin_sumsq() const
Get the raw sums of the squared values observed, at each binning level.
Params::ValueType ValueType
Type of the value(s) for which we are calculating error bars. See BinningAnalysisParams::ValueType.
const CwiseBinaryOp< internal::scalar_product_op< typename Derived::Scalar, typename OtherDerived::Scalar >, const Derived, const OtherDerived > cwiseProduct(const Eigen::ArrayBase< OtherDerived > &other) const
BinSumArray calc_error_lastlevel(const Eigen::ArrayBase< Derived > &means) const
Calculate the error bar of samples (from the last binning level).
ValueType_ ValueType
Type of the value which we are calculating error bars for. Also the type of the error bars themselves...
const Tools::static_or_dynamic< int, NumTrackValuesCTime > num_track_values
The number of functions being tracked/analyzed.
void reset()
Reset this object and start again as if freshly constructed.
const Tools::static_or_dynamic< int, NumLevelsCTime > num_levels
The number of levels in the binning analysis.
void process_new_value(const CalcValType val)
Process a new value (if we're tracking a single function only)
Params::SamplesArray SamplesArray
Type of the internal buffer for the raw samples. See BinningAnalysisParams::SamplesArray.
Params::BinSumArray BinSumArray
Type used to store the sum of values. See BinningAnalysisParams::BinSumArray.
Simple binning analysis for determining error bars.
LoggerType_ LoggerType
Type of the logger we will be logging debugging messages to.
BinningAnalysis(int num_track_values_, int num_levels_, LoggerType &logger_)
Constructor.
Eigen::Array< ValueType, NumTrackValuesCTime, NumLevelsPlusOneCTime > BinSumSqArray
Type used to store the sum of squares of values at each binning level.
void process_new_values(const Eigen::DenseBase< Derived > &vals)
Process new raw samples.
Eigen::Array< ValueType, NumTrackValuesCTime, SamplesSizeCTime > SamplesArray
Type of the internal buffer for the raw samples.
const Tools::static_or_dynamic< CountIntType, SamplesSizeCTime > samples_size
The size of our samples buffer. (avoid using, might change in the future)
CountIntType_ CountIntType
Type used to count the number of samples. Usually int is fine, except if you are really taking a LOT ...
Basic utilities for dealing with Eigen matrices and other types.
Utilities for logging messages.
auto get_bin_sqmeans() const
Get the raw average of the squared values observed, for each binning level.