diff --git a/include/boost/histogram/accumulators/mean.hpp b/include/boost/histogram/accumulators/mean.hpp index 18dc84ba..f814fc04 100644 --- a/include/boost/histogram/accumulators/mean.hpp +++ b/include/boost/histogram/accumulators/mean.hpp @@ -37,11 +37,11 @@ public: sum_of_deltas_squared_ += delta * (x - mean_); } - void operator()(const RealType& w, const RealType& x) noexcept { - sum_ += w; + void operator()(const weight_type& w, const RealType& x) noexcept { + sum_ += w.value; const auto delta = x - mean_; - mean_ += w * delta / sum_; - sum_of_deltas_squared_ += w * delta * (x - mean_); + mean_ += w.value * delta / sum_; + sum_of_deltas_squared_ += w.value * delta * (x - mean_); } template diff --git a/include/boost/histogram/accumulators/weighted_mean.hpp b/include/boost/histogram/accumulators/weighted_mean.hpp index 8bcc447d..6e4657f4 100644 --- a/include/boost/histogram/accumulators/weighted_mean.hpp +++ b/include/boost/histogram/accumulators/weighted_mean.hpp @@ -10,6 +10,7 @@ #include #include #include // for weighted_mean<> +#include #include namespace boost { @@ -34,14 +35,14 @@ public: , sum_of_weighted_deltas_squared_( variance * (sum_of_weights_ - sum_of_weights_squared_ / sum_of_weights_)) {} - void operator()(const RealType& x) { operator()(1, x); } + void operator()(const RealType& x) { operator()(weight(1), x); } - void operator()(const RealType& w, const RealType& x) { - sum_of_weights_ += w; - sum_of_weights_squared_ += w * w; + void operator()(const weight_type& w, const RealType& x) { + sum_of_weights_ += w.value; + sum_of_weights_squared_ += w.value * w.value; const auto delta = x - weighted_mean_; - weighted_mean_ += w * delta / sum_of_weights_; - sum_of_weighted_deltas_squared_ += w * delta * (x - weighted_mean_); + weighted_mean_ += w.value * delta / sum_of_weights_; + sum_of_weighted_deltas_squared_ += w.value * delta * (x - weighted_mean_); } template diff --git a/include/boost/histogram/detail/fill.hpp b/include/boost/histogram/detail/fill.hpp index 3281532e..fbb04532 100644 --- a/include/boost/histogram/detail/fill.hpp +++ b/include/boost/histogram/detail/fill.hpp @@ -123,7 +123,7 @@ void fill_storage_4(mp11::mp_true, T&& t) noexcept { template void fill_storage_4(mp11::mp_true, T&& t, U&& w) noexcept { - t += w; + t += w.value; } template @@ -136,7 +136,7 @@ template void fill_storage_2(IW, IS, T&& t, U&& u) noexcept { mp11::tuple_apply( [&](auto&&... args) { - fill_storage_3(std::forward(t), std::get(u).value, args...); + fill_storage_3(std::forward(t), std::get(u), args...); }, std::get(u).value); } @@ -150,7 +150,7 @@ void fill_storage_2(mp11::mp_int<-1>, IS, T&& t, const U& u) noexcept { template void fill_storage_2(IW, mp11::mp_int<-1>, T&& t, const U& u) noexcept { - fill_storage_3(std::forward(t), std::get(u).value); + fill_storage_3(std::forward(t), std::get(u)); } template diff --git a/include/boost/histogram/detail/fill_n.hpp b/include/boost/histogram/detail/fill_n.hpp index 9f63534b..35580b49 100644 --- a/include/boost/histogram/detail/fill_n.hpp +++ b/include/boost/histogram/detail/fill_n.hpp @@ -153,6 +153,17 @@ void fill_n_storage(S& s, const Index idx, Ts&&... p) noexcept { fold((p.second > 1 ? ++p.first : 0)...); } +template +void fill_n_storage(S& s, const Index idx, weight_type&& w, Ts&&... ps) noexcept { + if (is_valid(idx)) { + BOOST_ASSERT(idx < s.size()); + fill_storage_3(s[idx], weight_type{*w.value.first}, + *ps.first...); + } + if (w.value.second > 1) ++w.value.first; + fold((ps.second > 1 ? ++ps.first : 0)...); +} + // general Nd treatment template void fill_n_nd(const std::size_t offset, S& storage, A& axes, const std::size_t vsize, @@ -259,6 +270,11 @@ void fill_n_check_extra_args(std::size_t n, Ts&&... ts) { fold(check(ts)...); } +template +void fill_n_check_extra_args(std::size_t n, weight_type&& w, Ts&&... ts) { + fill_n_check_extra_args(n, w.value, std::forward(ts)...); +} + inline void fill_n_check_extra_args(std::size_t) noexcept {} template diff --git a/include/boost/histogram/histogram.hpp b/include/boost/histogram/histogram.hpp index b86f49c7..f30b6328 100644 --- a/include/boost/histogram/histogram.hpp +++ b/include/boost/histogram/histogram.hpp @@ -15,8 +15,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -214,7 +216,7 @@ public: void fill(const Iterable& args, const weight_type& weights) { std::lock_guard guard{mutex_base_t::get()}; detail::fill_n(offset_, storage_, axes_, detail::make_span(args), - detail::to_ptr_size(weights.value)); + weight(detail::to_ptr_size(weights.value))); } /** Fill histogram with several values and weights at once. @@ -260,7 +262,7 @@ public: mp11::tuple_apply( [&](const auto&... sargs) { detail::fill_n(offset_, storage_, axes_, detail::make_span(args), - detail::to_ptr_size(weights.value), + weight(detail::to_ptr_size(weights.value)), detail::to_ptr_size(sargs)...); }, samples.value); @@ -597,34 +599,6 @@ histogram(Iterable, S) #endif -/** Helper function to mark argument as weight. - - @param t argument to be forward to the histogram. -*/ -template -auto weight(T&& t) noexcept { - return weight_type{std::forward(t)}; -} - -/** Helper function to mark arguments as sample. - - @param ts arguments to be forwarded to the accumulator. -*/ -template -auto sample(Ts&&... ts) noexcept { - return sample_type>{std::forward_as_tuple(std::forward(ts)...)}; -} - -template -struct weight_type { - T value; -}; - -template -struct sample_type { - T value; -}; - } // namespace histogram } // namespace boost diff --git a/include/boost/histogram/sample.hpp b/include/boost/histogram/sample.hpp new file mode 100644 index 00000000..6289bd31 --- /dev/null +++ b/include/boost/histogram/sample.hpp @@ -0,0 +1,33 @@ +// Copyright 2019 Hans Dembinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_HISTOGRAM_SAMPLE_HPP +#define BOOST_HISTOGRAM_SAMPLE_HPP + +#include +#include + +namespace boost { +namespace histogram { + +template +struct sample_type { + T value; +}; + +/** Helper function to mark arguments as sample. + + @param ts arguments to be forwarded to the accumulator. +*/ +template +auto sample(Ts&&... ts) noexcept { + return sample_type>{std::forward_as_tuple(std::forward(ts)...)}; +} + +} // namespace histogram +} // namespace boost + +#endif diff --git a/include/boost/histogram/weight.hpp b/include/boost/histogram/weight.hpp new file mode 100644 index 00000000..4054e469 --- /dev/null +++ b/include/boost/histogram/weight.hpp @@ -0,0 +1,36 @@ +// Copyright 2019 Hans Dembinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_HISTOGRAM_WEIGHT_HPP +#define BOOST_HISTOGRAM_WEIGHT_HPP + +#include + +namespace boost { +namespace histogram { + +template +struct weight_type { + T value; + template + operator weight_type() const { + return weight_type{static_cast(value)}; + } +}; + +/** Helper function to mark argument as weight. + + @param t argument to be forward to the histogram. +*/ +template +auto weight(T&& t) noexcept { + return weight_type{std::forward(t)}; +} + +} // namespace histogram +} // namespace boost + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index debac596..b81847b2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -54,6 +54,18 @@ boost_test(TYPE compile-fail SOURCES make_histogram_fail0.cpp boost_test(TYPE compile-fail SOURCES make_histogram_fail1.cpp LIBRARIES Boost::histogram ) +boost_test(TYPE compile-fail SOURCES profile_fail0.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES profile_fail1.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES profile_fail2.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES profile_fail3.cpp + LIBRARIES Boost::histogram +) boost_test(TYPE run SOURCES accumulators_test.cpp LIBRARIES Boost::histogram Boost::core) boost_test(TYPE run SOURCES algorithm_project_test.cpp diff --git a/test/Jamfile b/test/Jamfile index 5616e585..72586691 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -101,6 +101,10 @@ alias failure : [ compile-fail axis_variable_fail1.cpp ] [ compile-fail make_histogram_fail0.cpp ] [ compile-fail make_histogram_fail1.cpp ] + [ compile-fail profile_fail0.cpp ] + [ compile-fail profile_fail1.cpp ] + [ compile-fail profile_fail2.cpp ] + [ compile-fail profile_fail3.cpp ] ; alias threading : diff --git a/test/accumulators_serialization_test.cpp b/test/accumulators_serialization_test.cpp index 50530503..b97ff6bf 100644 --- a/test/accumulators_serialization_test.cpp +++ b/test/accumulators_serialization_test.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "throw_exception.hpp" #include "utility_serialization.hpp" @@ -31,7 +32,7 @@ int main(int argc, char** argv) { const auto filename = join(argv[1], "accumulators_serialization_test_mean.xml"); accumulators::mean<> a; a(1); - a(0.5, 2); + a(weight(0.5), 2); a(3); print_xml(filename, a); @@ -61,7 +62,7 @@ int main(int argc, char** argv) { join(argv[1], "accumulators_serialization_test_weighted_mean.xml"); accumulators::weighted_mean<> a; a(1); - a(0.5, 2); + a(weight(0.5), 2); a(3); print_xml(filename, a); diff --git a/test/accumulators_test.cpp b/test/accumulators_test.cpp index 511b82e2..69177685 100644 --- a/test/accumulators_test.cpp +++ b/test/accumulators_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "is_close.hpp" #include "throw_exception.hpp" @@ -114,10 +115,10 @@ int main() { // also same as feeding all samples twice m_t d; - d(2, 4); - d(2, 7); - d(2, 13); - d(2, 16); + d(weight(2), 4); + d(weight(2), 7); + d(weight(2), 13); + d(weight(2), 16); BOOST_TEST_EQ(d, c); @@ -132,9 +133,9 @@ int main() { BOOST_TEST_EQ(a.sum_of_weights(), 0); BOOST_TEST_EQ(a, m_t{}); - a(0.5, 1); - a(1.0, 2); - a(0.5, 3); + a(weight(0.5), 1); + a(weight(1.0), 2); + a(weight(0.5), 3); BOOST_TEST_EQ(a.sum_of_weights(), 2); BOOST_TEST_EQ(a.sum_of_weights_squared(), 1.5); diff --git a/test/algorithm_empty_test.cpp b/test/algorithm_empty_test.cpp index 0c15894e..f3787f04 100644 --- a/test/algorithm_empty_test.cpp +++ b/test/algorithm_empty_test.cpp @@ -21,92 +21,40 @@ template void run_tests() { auto ax = axis::integer<>(0, 10); - auto h1 = make(Tag(), ax); - BOOST_TEST(empty(h1, coverage::all)); - BOOST_TEST(empty(h1, coverage::inner)); - for (int i = -1; i < 11; ++i) { - h1.reset(); - h1(i); - BOOST_TEST(!empty(h1, coverage::all)); - if (i == -1 || i == 10) { - BOOST_TEST(empty(h1, coverage::inner)); - } else { - BOOST_TEST(!empty(h1, coverage::inner)); - } - } - - auto h2 = make_s(Tag(), std::vector(), ax, ax); - BOOST_TEST(empty(h2, coverage::all)); - BOOST_TEST(empty(h2, coverage::inner)); - for (int i = -1; i < 11; ++i) { - for (int j = -1; j < 11; ++j) { - h2.reset(); - h2(i, j); - BOOST_TEST(!empty(h2, coverage::all)); - - if ((i == -1 || i == 10) || (j == -1 || j == 10)) { - BOOST_TEST(empty(h2, coverage::inner)); + { + auto h = make(Tag(), ax); + BOOST_TEST(empty(h, coverage::all)); + BOOST_TEST(empty(h, coverage::inner)); + for (int i = -1; i < 11; ++i) { + h.reset(); + h(i); + BOOST_TEST(!empty(h, coverage::all)); + if (i == -1 || i == 10) { + BOOST_TEST(empty(h, coverage::inner)); } else { - BOOST_TEST(!empty(h2, coverage::inner)); + BOOST_TEST(!empty(h, coverage::inner)); } } } - /* BROKEN, SEE https://github.com/boostorg/histogram/issues/244 - auto h3 = make_s(Tag(), std::array(), ax); - BOOST_TEST(empty(h3, coverage::all)); - BOOST_TEST(empty(h3, coverage::inner)); - h3(-2); - BOOST_TEST(!empty(h3, coverage::all)); - BOOST_TEST(empty(h3, coverage::inner)); - h3(2); - BOOST_TEST(!empty(h3, coverage::all)); - BOOST_TEST(!empty(h3, coverage::inner)); - */ - - auto h4 = make_s(Tag(), std::unordered_map(), ax); - BOOST_TEST(empty(h4, coverage::all)); - BOOST_TEST(empty(h4, coverage::inner)); - h4(-2); - BOOST_TEST(!empty(h4, coverage::all)); - BOOST_TEST(empty(h4, coverage::inner)); - h4(2); - BOOST_TEST(!empty(h4, coverage::all)); - BOOST_TEST(!empty(h4, coverage::inner)); - - auto h5 = make_s(Tag(), std::vector>(), - axis::integer<>(0, 10), axis::integer<>(0, 10)); - BOOST_TEST(empty(h5, coverage::all)); - BOOST_TEST(empty(h5, coverage::inner)); - h5.reset(); - h5(weight(2), -2, -4); - BOOST_TEST(!empty(h5, coverage::all)); - BOOST_TEST(empty(h5, coverage::inner)); - h5.reset(); - h5(weight(1), -4, 2); - BOOST_TEST(!empty(h5, coverage::all)); - BOOST_TEST(empty(h5, coverage::inner)); - h5.reset(); - h5(weight(3), 3, 5); - BOOST_TEST(!empty(h5, coverage::all)); - BOOST_TEST(!empty(h5, coverage::inner)); - - auto h6 = make_s(Tag(), std::vector>(), - axis::integer<>(0, 10), axis::integer<>(0, 10)); - BOOST_TEST(empty(h6, coverage::all)); - BOOST_TEST(empty(h6, coverage::inner)); - h6.reset(); - h6(weight(2), -2, -4); - BOOST_TEST(!empty(h6, coverage::all)); - BOOST_TEST(empty(h6, coverage::inner)); - h6.reset(); - h6(weight(1), -4, 2); - BOOST_TEST(!empty(h6, coverage::all)); - BOOST_TEST(empty(h6, coverage::inner)); - h6.reset(); - h6(weight(3), 3, 5); - BOOST_TEST(!empty(h6, coverage::all)); - BOOST_TEST(!empty(h6, coverage::inner)); + { + auto h = make_s(Tag(), std::vector>(), + axis::integer<>(0, 10), axis::integer<>(0, 10)); + BOOST_TEST(empty(h, coverage::all)); + BOOST_TEST(empty(h, coverage::inner)); + h.reset(); + h(weight(2), -2, -4, sample(3)); + BOOST_TEST(!empty(h, coverage::all)); + BOOST_TEST(empty(h, coverage::inner)); + h.reset(); + h(weight(1), -4, 2, sample(2)); + BOOST_TEST(!empty(h, coverage::all)); + BOOST_TEST(empty(h, coverage::inner)); + h.reset(); + h(weight(3), 3, 5, sample(1)); + BOOST_TEST(!empty(h, coverage::all)); + BOOST_TEST(!empty(h, coverage::inner)); + } } int main() { diff --git a/test/profile_fail0.cpp b/test/profile_fail0.cpp new file mode 100644 index 00000000..d0d79b50 --- /dev/null +++ b/test/profile_fail0.cpp @@ -0,0 +1,14 @@ +// Copyright 2019 Hans Dembinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +int main() { + using namespace boost::histogram; + auto h = make_profile(axis::integer<>(0, 5)); + h(0, weight(1)); // profile requires a sample +} diff --git a/test/profile_fail1.cpp b/test/profile_fail1.cpp new file mode 100644 index 00000000..2c9ea11f --- /dev/null +++ b/test/profile_fail1.cpp @@ -0,0 +1,14 @@ +// Copyright 2019 Hans Dembinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +int main() { + using namespace boost::histogram; + auto h = make_profile(axis::integer<>(0, 5)); + h(0, sample(1, 2)); // profile requires one sample +} diff --git a/test/profile_fail2.cpp b/test/profile_fail2.cpp new file mode 100644 index 00000000..485f0a51 --- /dev/null +++ b/test/profile_fail2.cpp @@ -0,0 +1,14 @@ +// Copyright 2019 Hans Dembinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +int main() { + using namespace boost::histogram; + auto h = make_weighted_profile(axis::integer<>(0, 5)); + h(0); // weighted profile requires a sample +} diff --git a/test/profile_fail3.cpp b/test/profile_fail3.cpp new file mode 100644 index 00000000..f9fc61a5 --- /dev/null +++ b/test/profile_fail3.cpp @@ -0,0 +1,14 @@ +// Copyright 2019 Hans Dembinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +int main() { + using namespace boost::histogram; + auto h = make_profile(axis::integer<>(0, 5)); + h(0, sample(1, 2)); // weighted profile requires one sample +} diff --git a/test/storage_adaptor_test.cpp b/test/storage_adaptor_test.cpp index 4b99cab3..6f8e01f5 100644 --- a/test/storage_adaptor_test.cpp +++ b/test/storage_adaptor_test.cpp @@ -8,9 +8,9 @@ #include #include #include -#include "throw_exception.hpp" #include #include +#include #include #include #include @@ -18,6 +18,7 @@ #include #include #include "is_close.hpp" +#include "throw_exception.hpp" #include "utility_allocator.hpp" using namespace boost::histogram; @@ -230,7 +231,7 @@ int main() { auto a = storage_adaptor>>(); a.reset(1); a[0](/* sample */ 1); - a[0](/* weight */ 2, /* sample */ 2); + a[0](weight(2), /* sample */ 2); a[0] += accumulators::weighted_mean<>(1, 0, 0, 0); BOOST_TEST_EQ(a[0].sum_of_weights(), 4); BOOST_TEST_IS_CLOSE(a[0].value(), 1.25, 1e-3);