Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // median.hpp Chris@16: // Chris@16: // Copyright 2006 Eric Niebler, Olivier Gygi. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_ACCUMULATORS_STATISTICS_MEDIAN_HPP_EAN_28_10_2005 Chris@16: #define BOOST_ACCUMULATORS_STATISTICS_MEDIAN_HPP_EAN_28_10_2005 Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { namespace accumulators Chris@16: { Chris@16: Chris@16: namespace impl Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // median_impl Chris@16: // Chris@16: /** Chris@16: @brief Median estimation based on the \f$P^2\f$ quantile estimator Chris@16: Chris@16: The \f$P^2\f$ algorithm is invoked with a quantile probability of 0.5. Chris@16: */ Chris@16: template Chris@16: struct median_impl Chris@16: : accumulator_base Chris@16: { Chris@16: // for boost::result_of Chris@16: typedef typename numeric::functional::fdiv::result_type result_type; Chris@16: Chris@16: median_impl(dont_care) {} Chris@16: Chris@16: template Chris@16: result_type result(Args const &args) const Chris@16: { Chris@16: return p_square_quantile_for_median(args); Chris@16: } Chris@16: }; Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // with_density_median_impl Chris@16: // Chris@16: /** Chris@16: @brief Median estimation based on the density estimator Chris@16: Chris@16: The algorithm determines the bin in which the \f$0.5*cnt\f$-th sample lies, \f$cnt\f$ being Chris@16: the total number of samples. It returns the approximate horizontal position of this sample, Chris@16: based on a linear interpolation inside the bin. Chris@16: */ Chris@16: template Chris@16: struct with_density_median_impl Chris@16: : accumulator_base Chris@16: { Chris@16: typedef typename numeric::functional::fdiv::result_type float_type; Chris@16: typedef std::vector > histogram_type; Chris@16: typedef iterator_range range_type; Chris@16: // for boost::result_of Chris@16: typedef float_type result_type; Chris@16: Chris@16: template Chris@16: with_density_median_impl(Args const &args) Chris@16: : sum(numeric::fdiv(args[sample | Sample()], (std::size_t)1)) Chris@16: , is_dirty(true) Chris@16: { Chris@16: } Chris@16: Chris@16: void operator ()(dont_care) Chris@16: { Chris@16: this->is_dirty = true; Chris@16: } Chris@16: Chris@16: Chris@16: template Chris@16: result_type result(Args const &args) const Chris@16: { Chris@16: if (this->is_dirty) Chris@16: { Chris@16: this->is_dirty = false; Chris@16: Chris@16: std::size_t cnt = count(args); Chris@16: range_type histogram = density(args); Chris@16: typename range_type::iterator it = histogram.begin(); Chris@16: while (this->sum < 0.5 * cnt) Chris@16: { Chris@16: this->sum += it->second * cnt; Chris@16: ++it; Chris@16: } Chris@16: --it; Chris@16: float_type over = numeric::fdiv(this->sum - 0.5 * cnt, it->second * cnt); Chris@16: this->median = it->first * over + (it + 1)->first * (1. - over); Chris@16: } Chris@16: Chris@16: return this->median; Chris@16: } Chris@16: Chris@16: private: Chris@16: mutable float_type sum; Chris@16: mutable bool is_dirty; Chris@16: mutable float_type median; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // with_p_square_cumulative_distribution_median_impl Chris@16: // Chris@16: /** Chris@16: @brief Median estimation based on the \f$P^2\f$ cumulative distribution estimator Chris@16: Chris@16: The algorithm determines the first (leftmost) bin with a height exceeding 0.5. It Chris@16: returns the approximate horizontal position of where the cumulative distribution Chris@16: equals 0.5, based on a linear interpolation inside the bin. Chris@16: */ Chris@16: template Chris@16: struct with_p_square_cumulative_distribution_median_impl Chris@16: : accumulator_base Chris@16: { Chris@16: typedef typename numeric::functional::fdiv::result_type float_type; Chris@16: typedef std::vector > histogram_type; Chris@16: typedef iterator_range range_type; Chris@16: // for boost::result_of Chris@16: typedef float_type result_type; Chris@16: Chris@16: with_p_square_cumulative_distribution_median_impl(dont_care) Chris@16: : is_dirty(true) Chris@16: { Chris@16: } Chris@16: Chris@16: void operator ()(dont_care) Chris@16: { Chris@16: this->is_dirty = true; Chris@16: } Chris@16: Chris@16: template Chris@16: result_type result(Args const &args) const Chris@16: { Chris@16: if (this->is_dirty) Chris@16: { Chris@16: this->is_dirty = false; Chris@16: Chris@16: range_type histogram = p_square_cumulative_distribution(args); Chris@16: typename range_type::iterator it = histogram.begin(); Chris@16: while (it->second < 0.5) Chris@16: { Chris@16: ++it; Chris@16: } Chris@16: float_type over = numeric::fdiv(it->second - 0.5, it->second - (it - 1)->second); Chris@16: this->median = it->first * over + (it + 1)->first * ( 1. - over ); Chris@16: } Chris@16: Chris@16: return this->median; Chris@16: } Chris@16: private: Chris@16: Chris@16: mutable bool is_dirty; Chris@16: mutable float_type median; Chris@16: }; Chris@16: Chris@16: } // namespace impl Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // tag::median Chris@16: // tag::with_densisty_median Chris@16: // tag::with_p_square_cumulative_distribution_median Chris@16: // Chris@16: namespace tag Chris@16: { Chris@16: struct median Chris@16: : depends_on Chris@16: { Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: typedef accumulators::impl::median_impl impl; Chris@16: }; Chris@16: struct with_density_median Chris@16: : depends_on Chris@16: { Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: typedef accumulators::impl::with_density_median_impl impl; Chris@16: }; Chris@16: struct with_p_square_cumulative_distribution_median Chris@16: : depends_on Chris@16: { Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: typedef accumulators::impl::with_p_square_cumulative_distribution_median_impl impl; Chris@16: }; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // extract::median Chris@16: // extract::with_density_median Chris@16: // extract::with_p_square_cumulative_distribution_median Chris@16: // Chris@16: namespace extract Chris@16: { Chris@16: extractor const median = {}; Chris@16: extractor const with_density_median = {}; Chris@16: extractor const with_p_square_cumulative_distribution_median = {}; Chris@16: Chris@16: BOOST_ACCUMULATORS_IGNORE_GLOBAL(median) Chris@16: BOOST_ACCUMULATORS_IGNORE_GLOBAL(with_density_median) Chris@16: BOOST_ACCUMULATORS_IGNORE_GLOBAL(with_p_square_cumulative_distribution_median) Chris@16: } Chris@16: Chris@16: using extract::median; Chris@16: using extract::with_density_median; Chris@16: using extract::with_p_square_cumulative_distribution_median; Chris@16: Chris@16: // median(with_p_square_quantile) -> median Chris@16: template<> Chris@16: struct as_feature Chris@16: { Chris@16: typedef tag::median type; Chris@16: }; Chris@16: Chris@16: // median(with_density) -> with_density_median Chris@16: template<> Chris@16: struct as_feature Chris@16: { Chris@16: typedef tag::with_density_median type; Chris@16: }; Chris@16: Chris@16: // median(with_p_square_cumulative_distribution) -> with_p_square_cumulative_distribution_median Chris@16: template<> Chris@16: struct as_feature Chris@16: { Chris@16: typedef tag::with_p_square_cumulative_distribution_median type; Chris@16: }; Chris@16: Chris@16: // for the purposes of feature-based dependency resolution, Chris@16: // with_density_median and with_p_square_cumulative_distribution_median Chris@16: // provide the same feature as median Chris@16: template<> Chris@16: struct feature_of Chris@16: : feature_of Chris@16: { Chris@16: }; Chris@16: Chris@16: template<> Chris@16: struct feature_of Chris@16: : feature_of Chris@16: { Chris@16: }; Chris@16: Chris@16: // So that median can be automatically substituted with Chris@16: // weighted_median when the weight parameter is non-void. Chris@16: template<> Chris@16: struct as_weighted_feature Chris@16: { Chris@16: typedef tag::weighted_median type; Chris@16: }; Chris@16: Chris@16: template<> Chris@16: struct feature_of Chris@16: : feature_of Chris@16: { Chris@16: }; Chris@16: Chris@16: // So that with_density_median can be automatically substituted with Chris@16: // with_density_weighted_median when the weight parameter is non-void. Chris@16: template<> Chris@16: struct as_weighted_feature Chris@16: { Chris@16: typedef tag::with_density_weighted_median type; Chris@16: }; Chris@16: Chris@16: template<> Chris@16: struct feature_of Chris@16: : feature_of Chris@16: { Chris@16: }; Chris@16: Chris@16: // So that with_p_square_cumulative_distribution_median can be automatically substituted with Chris@16: // with_p_square_cumulative_distribution_weighted_median when the weight parameter is non-void. Chris@16: template<> Chris@16: struct as_weighted_feature Chris@16: { Chris@16: typedef tag::with_p_square_cumulative_distribution_weighted_median type; Chris@16: }; Chris@16: Chris@16: template<> Chris@16: struct feature_of Chris@16: : feature_of Chris@16: { Chris@16: }; Chris@16: Chris@16: }} // namespace boost::accumulators Chris@16: Chris@16: #endif