empirical_cumulative_distribution_function.hpp 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // Copyright Nick Thompson 2019.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MATH_DISTRIBUTIONS_EMPIRICAL_CUMULATIVE_DISTRIBUTION_FUNCTION_HPP
  6. #define BOOST_MATH_DISTRIBUTIONS_EMPIRICAL_CUMULATIVE_DISTRIBUTION_FUNCTION_HPP
  7. #include <algorithm>
  8. #include <iterator>
  9. #include <stdexcept>
  10. #include <type_traits>
  11. #include <utility>
  12. #include <boost/math/tools/is_standalone.hpp>
  13. #ifndef BOOST_MATH_STANDALONE
  14. #include <boost/config.hpp>
  15. #ifdef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
  16. #error "The header <boost/math/norms.hpp> can only be used in C++17 and later."
  17. #endif
  18. #endif
  19. namespace boost { namespace math{
  20. template<class RandomAccessContainer>
  21. class empirical_cumulative_distribution_function {
  22. using Real = typename RandomAccessContainer::value_type;
  23. public:
  24. empirical_cumulative_distribution_function(RandomAccessContainer && v, bool sorted = false)
  25. {
  26. if (v.size() == 0) {
  27. throw std::domain_error("At least one sample is required to compute an empirical CDF.");
  28. }
  29. m_v = std::move(v);
  30. if (!sorted) {
  31. std::sort(m_v.begin(), m_v.end());
  32. }
  33. }
  34. auto operator()(Real x) const {
  35. if constexpr (std::is_integral_v<Real>)
  36. {
  37. if (x < m_v[0]) {
  38. return static_cast<double>(0);
  39. }
  40. if (x >= m_v[m_v.size()-1]) {
  41. return static_cast<double>(1);
  42. }
  43. auto it = std::upper_bound(m_v.begin(), m_v.end(), x);
  44. return static_cast<double>(std::distance(m_v.begin(), it))/static_cast<double>(m_v.size());
  45. }
  46. else
  47. {
  48. if (x < m_v[0]) {
  49. return Real(0);
  50. }
  51. if (x >= m_v[m_v.size()-1]) {
  52. return Real(1);
  53. }
  54. auto it = std::upper_bound(m_v.begin(), m_v.end(), x);
  55. return static_cast<Real>(std::distance(m_v.begin(), it))/static_cast<Real>(m_v.size());
  56. }
  57. }
  58. RandomAccessContainer&& return_data() {
  59. return std::move(m_v);
  60. }
  61. private:
  62. RandomAccessContainer m_v;
  63. };
  64. }}
  65. #endif