diff --git a/doc/getting_started.qbk b/doc/getting_started.qbk index b0dcf29b..1c202727 100644 --- a/doc/getting_started.qbk +++ b/doc/getting_started.qbk @@ -32,18 +32,8 @@ int main(int, char**) { h.fill(2.0); // put in overflow bin, bin interval is semi-open h.fill(20.0); // put in overflow bin - /* - use bh::count(N) if you would otherwise call h.fill(...) with - *same* argument N times, N is an integer argument - */ - h.fill(1.0, bh::count(4)); - /* do a weighted fill using bh::weight, which accepts a double - - don't mix this with bh::count, both have a different effect on the - variance (see Rationale for an explanation regarding weights) - - if you don't know what this is good for, use bh::count instead, - it is most likeliy what you want and it is more efficient */ h.fill(0.1, bh::weight(2.5)); @@ -230,7 +220,7 @@ h = hg.histogram(hg.axis.regular_log(5, 1e0, 1e5, "x")) # fill histogram with numbers for x in (2e0, 2e1, 2e2, 2e3, 2e4): - h.fill(x, count=2) + h.fill(x, weight=2) # iterate over bins and access bin counter for idx, (lower, upper) in enumerate(h.axis(0)): diff --git a/doc/guide.qbk b/doc/guide.qbk index 735ac994..8ceef4bf 100644 --- a/doc/guide.qbk +++ b/doc/guide.qbk @@ -144,8 +144,6 @@ int main() { // fill histogram, number of arguments must be equal to number of axes h.fill(0, 4.1); // increases bin counter by one - h.fill(1, 1.2, bh::count(3)); // increase bin counter by 3 - h.fill(bh::count(3), 2, 2.3); // the same as the previous call h.fill(3, 3.4, bh::weight(1.5)); // increase bin counter by weight 1.5 h.fill(bh::weight(1.5), 3, 3.4); // the same as the previous call @@ -213,9 +211,9 @@ int main() { // make histogram with 2 x 2 = 4 bins (not counting under-/overflow bins) auto h = bh::make_dynamic_histogram(bh::axis::regular<>(2, -1, 1), bh::axis::regular<>(2, 2, 4)); - h.fill(-0.5, 2.5, bh::count(1)); // low, low - h.fill(-0.5, 3.5, bh::count(2)); // low, high - h.fill( 0.5, 2.5, bh::count(3)); // high, low + h.fill(-0.5, 2.5, bh::weight(1)); // low, low + h.fill(-0.5, 3.5, bh::weight(2)); // low, high + h.fill( 0.5, 2.5, bh::weight(3)); // high, low h.fill( 0.5, 3.5, bh::weight(4)); // high, high // access value of bin count, number of arguments must be equal @@ -234,7 +232,7 @@ int main() { << h.variance(1, 1) // high, high << std::endl; - // prints: 1 2 3 16 + // prints: 1 4 9 16 // a dynamic histogram also supports access via an interator range, while // a static histogram does not allow it; using a range of wrong length @@ -511,7 +509,7 @@ h = hg.histogram(hg.axis.regular_log(5, 1e0, 1e5, "x")) # fill histogram with numbers for x in (2e0, 2e1, 2e2, 2e3, 2e4): - h.fill(x, count=4) # increment bin counter by 4 + h.fill(x, weight=4) # increment bin counter by 4 # iterate over bins and access bin counter for idx, (lower, upper) in enumerate(h.axis(0)): @@ -525,11 +523,11 @@ lo, up = h.axis(0)[5] print "overflow [{0}, {1}): {2} +/- {3}".format(lo, up, h.value(5), h.variance(5)) # prints: -# bin 0 x in [1.0, 10.0): 4.0 +/- 2.0 -# bin 1 x in [10.0, 100.0): 4.0 +/- 2.0 -# bin 2 x in [100.0, 1000.0): 4.0 +/- 2.0 -# bin 3 x in [1000.0, 10000.0): 4.0 +/- 2.0 -# bin 4 x in [10000.0, 100000.0): 4.0 +/- 2.0 +# bin 0 x in [1.0, 10.0): 4.0 +/- 4.0 +# bin 1 x in [10.0, 100.0): 4.0 +/- 4.0 +# bin 2 x in [100.0, 1000.0): 4.0 +/- 4.0 +# bin 3 x in [1000.0, 10000.0): 4.0 +/- 4.0 +# bin 4 x in [10000.0, 100000.0): 4.0 +/- 4.0 # underflow [0.0, 1.0): 0.0 +/- 0.0 # overflow [100000.0, inf): 0.0 +/- 0.0 `` diff --git a/include/boost/histogram/dynamic_histogram.hpp b/include/boost/histogram/dynamic_histogram.hpp index 405f3d29..40d80593 100644 --- a/include/boost/histogram/dynamic_histogram.hpp +++ b/include/boost/histogram/dynamic_histogram.hpp @@ -18,7 +18,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -129,16 +130,19 @@ public: return *this; } - template void fill(Args &&... args) { - using n_count = typename mpl::count, count>; - using n_weight = typename mpl::count, weight>; + template void fill(const Args &... args) { + using n_weight = typename mpl::count_if, detail::is_weight>; + using n_sample = typename mpl::count_if, detail::is_sample>; static_assert( - (n_count::value + n_weight::value) <= 1, - "arguments may contain at most one instance of type count or weight"); - if (dim() != sizeof...(args) - n_count::value - n_weight::value) + n_weight::value <= 1, + "more than one weight argument is not allowed"); + static_assert( + n_sample::value <= 1, + "more than one sample argument is not allowed"); + if (dim() != sizeof...(args) - n_weight::value - n_sample::value) throw std::invalid_argument( "fill arguments does not match histogram dimension"); - fill_impl(mpl::int_<(n_count::value + 2 * n_weight::value)>(), + fill_impl(mpl::bool_(), mpl::bool_(), args...); } @@ -154,20 +158,8 @@ public: } } - template > - void fill(Iterator begin, Iterator end, const count n) { - if (dim() != std::distance(begin, end)) - throw std::invalid_argument( - "fill iterator range does not match histogram dimension"); - std::size_t idx = 0, stride = 1; - xlin_iter(idx, stride, begin); - if (stride) { - storage_.add(idx, n.value); - } - } - - template > - void fill(Iterator begin, Iterator end, const weight w) { + template > + void fill(Iterator begin, Iterator end, const detail::weight_t& w) { if (dim() != std::distance(begin, end)) throw std::invalid_argument( "fill iterator range does not match histogram dimension"); @@ -311,32 +303,33 @@ private: } template - inline void fill_impl(mpl::int_<0>, Args &&... args) { + inline void fill_impl(mpl::false_, mpl::false_, const Args &... args) { std::size_t idx = 0, stride = 1; - xlin<0>(idx, stride, args...); + double w; + xlin<0>(idx, stride, w, args...); if (stride) { storage_.increase(idx); } } template - inline void fill_impl(mpl::int_<1>, Args &&... args) { + inline void fill_impl(mpl::true_, mpl::false_, const Args &... args) { std::size_t idx = 0, stride = 1; - unsigned n = 0; - xlin_n<0>(idx, stride, n, args...); + double w; + xlin<0>(idx, stride, w, args...); if (stride) { - storage_.add(idx, n); + storage_.increase_by_weight(idx, w); } } template - inline void fill_impl(mpl::int_<2>, Args &&... args) { - std::size_t idx = 0, stride = 1; - double w = 0.0; - xlin_w<0>(idx, stride, w, args...); - if (stride) { - storage_.increase_by_weight(idx, w); - } + inline void fill_impl(mpl::false_, mpl::true_, const Args &... args) { + // not implemented + } + + template + inline void fill_impl(mpl::true_, mpl::true_, const Args &... args) { + // not implemented } struct lin_visitor : public static_visitor { @@ -382,57 +375,25 @@ private: } }; - template inline void xlin(std::size_t &, std::size_t &) const {} + template inline void xlin(std::size_t &, std::size_t &, double&) const {} template - inline void xlin(std::size_t &idx, std::size_t &stride, const First &first, + inline void xlin(std::size_t &idx, std::size_t &stride, double& w, const First &first, const Rest &... rest) const { apply_visitor(xlin_visitor{idx, stride, first}, axes_[D]); - return xlin(idx, stride, rest...); + return xlin(idx, stride, w, rest...); } - template - inline void xlin_w(std::size_t &, std::size_t &, double &) const {} - - template - inline typename enable_if>::type - xlin_w(std::size_t &idx, std::size_t &stride, double &x, const First &first, + template + inline void xlin(std::size_t &idx, std::size_t &stride, double &w, + const detail::weight_t &first, const Rest &... rest) const { - x = first.value; - return xlin_w(idx, stride, x, rest...); - } - - template - inline typename disable_if>::type - xlin_w(std::size_t &idx, std::size_t &stride, double &x, const First &first, - const Rest &... rest) const { - apply_visitor(xlin_visitor{idx, stride, first}, - axes_[D]); - return xlin_w(idx, stride, x, rest...); - } - - template - inline void xlin_n(std::size_t &, std::size_t &, unsigned &) const {} - - template - inline typename enable_if>::type - xlin_n(std::size_t &idx, std::size_t &stride, unsigned &x, const First &first, - const Rest &... rest) const { - x = first.value; - return xlin_n(idx, stride, x, rest...); - } - - template - inline typename disable_if>::type - xlin_n(std::size_t &idx, std::size_t &stride, unsigned &x, const First &first, - const Rest &... rest) const { - apply_visitor(xlin_visitor{idx, stride, first}, - axes_[D]); - return xlin_n(idx, stride, x, rest...); + w = first.value; + return xlin(idx, stride, w, rest...); } template - void lin_iter(std::size_t &idx, std::size_t &stride, Iterator iter) const { + inline void lin_iter(std::size_t &idx, std::size_t &stride, Iterator iter) const { for (const auto &a : axes_) { apply_visitor(lin_visitor(idx, stride, *iter), a); ++iter; diff --git a/include/boost/histogram/histogram_fwd.hpp b/include/boost/histogram/histogram_fwd.hpp index 8a6b6fe2..f68e0f58 100644 --- a/include/boost/histogram/histogram_fwd.hpp +++ b/include/boost/histogram/histogram_fwd.hpp @@ -8,6 +8,7 @@ #define _BOOST_HISTOGRAM_HISTOGRAM_FWD_HPP_ #include +#include #include namespace boost { @@ -55,15 +56,27 @@ using dynamic_histogram = histogram; template using static_histogram = histogram; -struct weight { - weight(double w) : value(w) {} - double value; -}; +namespace detail { +template +struct weight_t { T value;}; +template +struct is_weight : mpl::false_ {}; +template +struct is_weight> : mpl::true_ {}; -struct count { - count(unsigned n) : value(n) {} - unsigned value; -}; +template +struct sample_t { T value; }; +template +struct is_sample : mpl::false_ {}; +template +struct is_sample> : mpl::true_ {}; +} // namespace detail + +template +detail::weight_t weight(T&& t) { return {t}; } + +template +detail::sample_t sample(T&& t) { return {t}; } } // namespace histogram } // namespace boost diff --git a/include/boost/histogram/static_histogram.hpp b/include/boost/histogram/static_histogram.hpp index 4bd80516..7502ef4a 100644 --- a/include/boost/histogram/static_histogram.hpp +++ b/include/boost/histogram/static_histogram.hpp @@ -26,10 +26,11 @@ #include #include #include -#include +#include #include #include #include +#include #include // forward declaration for serialization @@ -142,16 +143,18 @@ public: } template void fill(const Args &... args) { - using n_count = typename mpl::count, count>; - using n_weight = typename mpl::count, weight>; + using n_weight = typename mpl::count_if, detail::is_weight>; + using n_sample = typename mpl::count_if, detail::is_sample>; static_assert( - (n_count::value + n_weight::value) <= 1, - "arguments may contain at most one instance of type count or weight"); + n_weight::value <= 1, + "more than one weight argument is not allowed"); + static_assert( + n_sample::value <= 1, + "more than one sample argument is not allowed"); static_assert(sizeof...(args) == - (axes_size::value + n_count::value + n_weight::value), + (axes_size::value + n_weight::value + n_sample::value), "number of arguments does not match histogram dimension"); - fill_impl(mpl::int_<(n_count::value + 2 * n_weight::value)>(), - args...); + fill_impl(mpl::bool_(), mpl::bool_(), args...); } template value_type value(const Indices &... indices) const { @@ -263,31 +266,38 @@ private: } template - inline void fill_impl(mpl::int_<0>, const Args &... args) { + inline void fill_impl(mpl::false_, mpl::false_, + const Args &... args) { std::size_t idx = 0, stride = 1; - xlin<0>(idx, stride, args...); - if (stride) + double w; + xlin<0>(idx, stride, w, args...); + if (stride) { storage_.increase(idx); + } } template - inline void fill_impl(mpl::int_<1>, const Args &... args) { + inline void fill_impl(mpl::true_, mpl::false_, + const Args &... args) { std::size_t idx = 0, stride = 1; - unsigned n = 0; - xlin_n<0>(idx, stride, n, args...); - if (stride) - storage_.add(idx, n); - } - - template - inline void fill_impl(mpl::int_<2>, const Args &... args) { - std::size_t idx = 0, stride = 1; - double w = 0.0; - xlin_w<0>(idx, stride, w, args...); + double w; + xlin<0>(idx, stride, w, args...); if (stride) storage_.increase_by_weight(idx, w); } + template + inline void fill_impl(mpl::false_, mpl::true_, + const Args &... args) { + // not implemented + } + + template + inline void fill_impl(mpl::true_, mpl::true_, + const Args &... args) { + // not implemented + } + template inline void lin(std::size_t &, std::size_t &) const noexcept {} template @@ -297,51 +307,20 @@ private: return lin(idx, stride, rest...); } - template inline void xlin(std::size_t &, std::size_t &) const {} + template inline void xlin(std::size_t &, std::size_t &, double&) const {} template - inline void xlin(std::size_t &idx, std::size_t &stride, const First &first, - const Rest &... rest) const { + inline void xlin(std::size_t &idx, std::size_t &stride, double& w, + const First &first, const Rest &... rest) const { detail::xlin(idx, stride, fusion::at_c(axes_), first); - return xlin(idx, stride, rest...); + return xlin(idx, stride, w, rest...); } - template - inline void xlin_w(std::size_t &, std::size_t &, double &) const {} - - template - inline typename disable_if>::type - xlin_w(std::size_t &idx, std::size_t &stride, double &x, const First &first, - Rest &&... rest) const { - detail::xlin(idx, stride, fusion::at_c(axes_), first); - return xlin_w(idx, stride, x, rest...); - } - - template - inline typename enable_if>::type - xlin_w(std::size_t &idx, std::size_t &stride, double &x, const First &first, + template + inline void xlin(std::size_t &idx, std::size_t &stride, double &w, const detail::weight_t &first, const Rest &... rest) const { - x = first.value; - return xlin_w(idx, stride, x, rest...); - } - - template - inline void xlin_n(std::size_t &, std::size_t &, unsigned &) const {} - - template - inline typename disable_if>::type - xlin_n(std::size_t &idx, std::size_t &stride, unsigned &x, const First &first, - const Rest &... rest) const { - detail::xlin(idx, stride, fusion::at_c(axes_), first); - return xlin_n(idx, stride, x, rest...); - } - - template - inline typename enable_if>::type - xlin_n(std::size_t &idx, std::size_t &stride, unsigned &x, const First &first, - const Rest &... rest) const { - x = first.value; - return xlin_n(idx, stride, x, rest...); + w = first.value; + return xlin(idx, stride, w, rest...); } struct shape_assign_visitor { diff --git a/src/python/histogram.cpp b/src/python/histogram.cpp index de8d53bd..253a43b2 100644 --- a/src/python/histogram.cpp +++ b/src/python/histogram.cpp @@ -242,13 +242,11 @@ bp::object histogram_fill(bp::tuple args, bp::dict kwargs) { } fetcher fetch_weight; - fetcher fetch_count; const auto nkwargs = bp::len(kwargs); if (nkwargs > 0) { const bool use_weight = kwargs.has_key("weight"); - const bool use_count = kwargs.has_key("count"); - if (nkwargs > 1 || (use_weight == use_count)) { // may not be both true or false - PyErr_SetString(PyExc_RuntimeError, "only keyword weight or count allowed"); + if (nkwargs > use_weight) { // only one keyword allowed: weight + PyErr_SetString(PyExc_RuntimeError, "only keyword weight allowed"); bp::throw_error_already_set(); } @@ -262,17 +260,6 @@ bp::object histogram_fill(bp::tuple args, bp::dict kwargs) { n = fetch_weight.n; } } - - if (use_count) { - fetch_count.assign(kwargs.get("count")); - if (fetch_count.n > 0) { - if (n > 0 && fetch_count.n != n) { - PyErr_SetString(PyExc_ValueError, "length of count sequence does not match"); - bp::throw_error_already_set(); - } - n = fetch_count.n; - } - } } double v[BOOST_HISTOGRAM_AXIS_LIMIT]; @@ -282,8 +269,6 @@ bp::object histogram_fill(bp::tuple args, bp::dict kwargs) { v[d] = fetch[d][i]; if (fetch_weight.n >= 0) self.fill(v, v + dim, bh::weight(fetch_weight[i])); - else if (fetch_count.n >= 0) - self.fill(v, v + dim, bh::count(fetch_count[i])); else self.fill(v, v + dim); } @@ -398,7 +383,6 @@ void register_histogram() { .def("fill", bp::raw_function(histogram_fill), ":param double args: values (number must match dimension)" "\n:keyword double weight: optional weight" - "\n:keyword uint32_t count: optional count" "\n" "\nIf Numpy support is enabled, 1d-arrays can be passed instead of" "\nvalues, which must be equal in lenght. Arrays and values can" diff --git a/test/histogram_test.cpp b/test/histogram_test.cpp index 35c6bbcc..2860a4d4 100644 --- a/test/histogram_test.cpp +++ b/test/histogram_test.cpp @@ -243,25 +243,25 @@ template void run_tests() { h.fill(0); h.fill(0); h.fill(-1); - h.fill(10, count(10)); + h.fill(10); BOOST_TEST_EQ(h.dim(), 1); BOOST_TEST_EQ(h.axis(0_c).size(), 2); BOOST_TEST_EQ(h.axis(0_c).shape(), 4); - BOOST_TEST_EQ(h.sum(), 13); + BOOST_TEST_EQ(h.sum(), 4); BOOST_TEST_THROWS(h.value(-2), std::out_of_range); BOOST_TEST_EQ(h.value(-1), 1); BOOST_TEST_EQ(h.value(0), 2); BOOST_TEST_EQ(h.value(1), 0); - BOOST_TEST_EQ(h.value(2), 10); + BOOST_TEST_EQ(h.value(2), 1); BOOST_TEST_THROWS(h.value(3), std::out_of_range); BOOST_TEST_THROWS(h.variance(-2), std::out_of_range); BOOST_TEST_EQ(h.variance(-1), 1); BOOST_TEST_EQ(h.variance(0), 2); BOOST_TEST_EQ(h.variance(1), 0); - BOOST_TEST_EQ(h.variance(2), 10); + BOOST_TEST_EQ(h.variance(2), 1); BOOST_TEST_THROWS(h.variance(3), std::out_of_range); } @@ -272,7 +272,7 @@ template void run_tests() { h.fill(0); h.fill(-0); h.fill(-1); - h.fill(10, count(10)); + h.fill(10); BOOST_TEST_EQ(h.dim(), 1); BOOST_TEST_EQ(h.axis(0_c).size(), 2); @@ -297,7 +297,7 @@ template void run_tests() { h.fill("A"); h.fill("B"); h.fill("D"); - h.fill("E", count(10)); + h.fill("E"); BOOST_TEST_EQ(h.dim(), 1); BOOST_TEST_EQ(h.axis(0_c).size(), 2); @@ -323,7 +323,7 @@ template void run_tests() { h.fill(weight(0.5), -1); h.fill(-1); h.fill(-2); - h.fill(weight(5), 10); + h.fill(10, weight(5)); BOOST_TEST_EQ(h.sum(), 8.5); @@ -338,46 +338,6 @@ template void run_tests() { BOOST_TEST_EQ(h.variance(2), 25); } - // d1w2 - { - auto h = - make_histogram>(Type(), axis::regular<>(2, -1, 1)); - h.fill(0); - h.fill(weight(0.5), -1); - h.fill(-1); - h.fill(-2); - h.fill(count(5), 10); - - BOOST_TEST_EQ(h.sum(), 8.5); - - BOOST_TEST_EQ(h.value(-1), 1); - BOOST_TEST_EQ(h.value(0), 1.5); - BOOST_TEST_EQ(h.value(1), 1); - BOOST_TEST_EQ(h.value(2), 5); - } - - // d1w3 - { - auto h = make_histogram>>( - Type(), axis::regular<>(2, -1, 1)); - h.fill(0); - h.fill(weight(0.5), -1.0); - h.fill(-1.0); - h.fill(-2.0); - h.fill(count(5), 10.0); - - BOOST_TEST_EQ(h.sum(), 8.5); - - BOOST_TEST_EQ(h.value(-1), 1); - BOOST_TEST_EQ(h.variance(-1), 1); - BOOST_TEST_EQ(h.value(0), 1.5); - BOOST_TEST_EQ(h.variance(0), 1.25); - BOOST_TEST_EQ(h.value(1), 1); - BOOST_TEST_EQ(h.variance(1), 1); - BOOST_TEST_EQ(h.value(2), 5); - BOOST_TEST_EQ(h.variance(2), 5); - } - // d2 { auto h = make_histogram( diff --git a/test/python_suite_test.py b/test/python_suite_test.py index e05d8db3..38b50cba 100644 --- a/test/python_suite_test.py +++ b/test/python_suite_test.py @@ -680,27 +680,27 @@ class test_histogram(unittest.TestCase): @unittest.skipUnless(have_numpy, "requires build with numpy-support") def test_numpy_conversion_0(self): a = histogram(integer(0, 3, uoflow=False)) - for i in range(10): + a.fill(0) + for i in range(5): a.fill(1) - a.fill(1, count=90) c = numpy.array(a) # a copy v = numpy.asarray(a) # a view for t in (c, v): self.assertEqual(t.dtype, numpy.uint8) - self.assertTrue(numpy.all(t == numpy.array((0, 100, 0)))) + self.assertTrue(numpy.all(t == numpy.array((1, 5, 0)))) - for i in range(20): - a.fill(1) - a.fill(1, count=2 * numpy.ones(40, dtype=numpy.uint32)) + for i in range(10): + a.fill(2) # copy does not change, but view does - self.assertTrue(numpy.all(c == numpy.array((0, 100, 0)))) - self.assertTrue(numpy.all(v == numpy.array((0, 200, 0)))) + self.assertTrue(numpy.all(c == numpy.array((1, 5, 0)))) + self.assertTrue(numpy.all(v == numpy.array((1, 5, 10)))) - a.fill(1, count=100) + for i in range(255): + a.fill(1) c = numpy.array(a) self.assertEqual(c.dtype, numpy.uint16) - self.assertTrue(numpy.all(c == numpy.array((0, 300, 0)))) + self.assertTrue(numpy.all(c == numpy.array((1, 260, 10)))) # view does not follow underlying switch in word size self.assertFalse(numpy.all(c == v))