accumulators_test.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // Copyright 2015-2018 Hans Dembinski
  2. //
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #include <boost/core/lightweight_test.hpp>
  7. #include <boost/histogram/accumulators/mean.hpp>
  8. #include <boost/histogram/accumulators/ostream.hpp>
  9. #include <boost/histogram/accumulators/sum.hpp>
  10. #include <boost/histogram/accumulators/thread_safe.hpp>
  11. #include <boost/histogram/accumulators/weighted_mean.hpp>
  12. #include <boost/histogram/accumulators/weighted_sum.hpp>
  13. #include <boost/histogram/weight.hpp>
  14. #include <sstream>
  15. #include "is_close.hpp"
  16. #include "throw_exception.hpp"
  17. using namespace boost::histogram;
  18. using namespace std::literals;
  19. template <class T>
  20. auto str(const T& t, int w = 0, bool left = true) {
  21. std::ostringstream os;
  22. os.width(w);
  23. if (left)
  24. os << std::left;
  25. else
  26. os << std::right;
  27. os << t;
  28. return os.str();
  29. }
  30. int main() {
  31. {
  32. using w_t = accumulators::weighted_sum<double>;
  33. w_t w;
  34. BOOST_TEST_EQ(str(w), "weighted_sum(0, 0)"s);
  35. BOOST_TEST_EQ(str(w, 20, false), " weighted_sum(0, 0)"s);
  36. BOOST_TEST_EQ(str(w, 20, true), "weighted_sum(0, 0) "s);
  37. BOOST_TEST_EQ(w, w_t{});
  38. BOOST_TEST_EQ(w, w_t(0));
  39. BOOST_TEST_NE(w, w_t(1));
  40. w = w_t(1);
  41. BOOST_TEST_EQ(w.value(), 1);
  42. BOOST_TEST_EQ(w.variance(), 1);
  43. BOOST_TEST_EQ(w, 1);
  44. BOOST_TEST_NE(w, 2);
  45. w += 2;
  46. BOOST_TEST_EQ(w.value(), 3);
  47. BOOST_TEST_EQ(w.variance(), 5);
  48. BOOST_TEST_EQ(w, w_t(3, 5));
  49. BOOST_TEST_NE(w, w_t(3));
  50. w += w_t(1, 2);
  51. BOOST_TEST_EQ(w.value(), 4);
  52. BOOST_TEST_EQ(w.variance(), 7);
  53. // consistency: a weighted counter increased by weight 1 multiplied
  54. // by 2 must be the same as a weighted counter increased by weight 2
  55. w_t u(0);
  56. ++u;
  57. u *= 2;
  58. BOOST_TEST_EQ(u, w_t(2, 4));
  59. w_t v(0);
  60. v += 2;
  61. BOOST_TEST_EQ(u, v);
  62. // conversion to RealType
  63. w_t y(1, 2);
  64. BOOST_TEST_NE(y, 1);
  65. BOOST_TEST_EQ(static_cast<double>(y), 1);
  66. BOOST_TEST_EQ(w_t() += w_t(), w_t());
  67. }
  68. {
  69. using m_t = accumulators::mean<double>;
  70. m_t a;
  71. BOOST_TEST_EQ(a.count(), 0);
  72. BOOST_TEST_EQ(a, m_t{});
  73. a(4);
  74. a(7);
  75. a(13);
  76. a(16);
  77. BOOST_TEST_EQ(a.count(), 4);
  78. BOOST_TEST_EQ(a.value(), 10);
  79. BOOST_TEST_EQ(a.variance(), 30);
  80. BOOST_TEST_EQ(str(a), "mean(4, 10, 30)"s);
  81. BOOST_TEST_EQ(str(a, 20, false), " mean(4, 10, 30)"s);
  82. BOOST_TEST_EQ(str(a, 20, true), "mean(4, 10, 30) "s);
  83. m_t b;
  84. b(1e8 + 4);
  85. b(1e8 + 7);
  86. b(1e8 + 13);
  87. b(1e8 + 16);
  88. BOOST_TEST_EQ(b.count(), 4);
  89. BOOST_TEST_EQ(b.value(), 1e8 + 10);
  90. BOOST_TEST_EQ(b.variance(), 30);
  91. auto c = a;
  92. c += a; // same as feeding all samples twice
  93. BOOST_TEST_EQ(c.count(), 8);
  94. BOOST_TEST_EQ(c.value(), 10);
  95. BOOST_TEST_IS_CLOSE(c.variance(), 25.714, 1e-3);
  96. // also same as feeding all samples twice
  97. m_t d;
  98. d(weight(2), 4);
  99. d(weight(2), 7);
  100. d(weight(2), 13);
  101. d(weight(2), 16);
  102. BOOST_TEST_EQ(d, c);
  103. BOOST_TEST_EQ(m_t() += m_t(), m_t());
  104. BOOST_TEST_EQ(m_t(1, 2, 3) += m_t(), m_t(1, 2, 3));
  105. BOOST_TEST_EQ(m_t() += m_t(1, 2, 3), m_t(1, 2, 3));
  106. }
  107. {
  108. using m_t = accumulators::weighted_mean<double>;
  109. m_t a;
  110. BOOST_TEST_EQ(a.sum_of_weights(), 0);
  111. BOOST_TEST_EQ(a, m_t{});
  112. a(weight(0.5), 1);
  113. a(weight(1.0), 2);
  114. a(weight(0.5), 3);
  115. BOOST_TEST_EQ(a.sum_of_weights(), 2);
  116. BOOST_TEST_EQ(a.sum_of_weights_squared(), 1.5);
  117. BOOST_TEST_EQ(a.value(), 2);
  118. BOOST_TEST_IS_CLOSE(a.variance(), 0.8, 1e-3);
  119. BOOST_TEST_EQ(str(a), "weighted_mean(2, 2, 0.8)"s);
  120. BOOST_TEST_EQ(str(a, 25, false), " weighted_mean(2, 2, 0.8)"s);
  121. BOOST_TEST_EQ(str(a, 25, true), "weighted_mean(2, 2, 0.8) "s);
  122. auto b = a;
  123. b += a; // same as feeding all samples twice
  124. BOOST_TEST_EQ(b.sum_of_weights(), 4);
  125. BOOST_TEST_EQ(b.value(), 2);
  126. BOOST_TEST_IS_CLOSE(b.variance(), 0.615, 1e-3);
  127. BOOST_TEST_EQ(m_t() += m_t(), m_t());
  128. BOOST_TEST_EQ(m_t(1, 2, 3, 4) += m_t(), m_t(1, 2, 3, 4));
  129. BOOST_TEST_EQ(m_t() += m_t(1, 2, 3, 4), m_t(1, 2, 3, 4));
  130. }
  131. {
  132. double bad_sum = 0;
  133. bad_sum += 1;
  134. bad_sum += 1e100;
  135. bad_sum += 1;
  136. bad_sum += -1e100;
  137. BOOST_TEST_EQ(bad_sum, 0); // instead of 2
  138. using s_t = accumulators::sum<double>;
  139. s_t sum;
  140. ++sum;
  141. BOOST_TEST_EQ(sum.large(), 1);
  142. BOOST_TEST_EQ(sum.small(), 0);
  143. BOOST_TEST_EQ(str(sum), "sum(1 + 0)"s);
  144. BOOST_TEST_EQ(str(sum, 15, false), " sum(1 + 0)"s);
  145. BOOST_TEST_EQ(str(sum, 15, true), "sum(1 + 0) "s);
  146. sum += 1e100;
  147. BOOST_TEST_EQ(str(sum), "sum(1e+100 + 1)"s);
  148. ++sum;
  149. BOOST_TEST_EQ(str(sum), "sum(1e+100 + 2)"s);
  150. sum += -1e100;
  151. BOOST_TEST_EQ(str(sum), "sum(0 + 2)"s);
  152. BOOST_TEST_EQ(sum, 2); // correct answer
  153. BOOST_TEST_EQ(sum.large(), 0);
  154. BOOST_TEST_EQ(sum.small(), 2);
  155. accumulators::sum<double> a(3), b(2), c(3);
  156. BOOST_TEST_LT(b, c);
  157. BOOST_TEST_LE(b, c);
  158. BOOST_TEST_LE(a, c);
  159. BOOST_TEST_GT(a, b);
  160. BOOST_TEST_GE(a, b);
  161. BOOST_TEST_GE(a, c);
  162. BOOST_TEST_EQ(s_t() += s_t(), s_t());
  163. }
  164. {
  165. using s_t = accumulators::weighted_sum<accumulators::sum<double>>;
  166. s_t w;
  167. ++w;
  168. w += 1e100;
  169. ++w;
  170. w += -1e100;
  171. BOOST_TEST_EQ(w.value(), 2);
  172. BOOST_TEST_EQ(w.variance(), 2e200);
  173. BOOST_TEST_EQ(s_t() += s_t(), s_t());
  174. }
  175. {
  176. using ts_t = accumulators::thread_safe<int>;
  177. ts_t i;
  178. ++i;
  179. i += 1000;
  180. BOOST_TEST_EQ(i, 1001);
  181. BOOST_TEST_EQ(str(i), "1001"s);
  182. BOOST_TEST_EQ(ts_t() += ts_t(), ts_t());
  183. }
  184. return boost::report_errors();
  185. }