diff options
Diffstat (limited to 'src/boost/libs/histogram/examples')
36 files changed, 1945 insertions, 0 deletions
diff --git a/src/boost/libs/histogram/examples/Jamfile b/src/boost/libs/histogram/examples/Jamfile new file mode 100644 index 000000000..c9d620aa8 --- /dev/null +++ b/src/boost/libs/histogram/examples/Jamfile @@ -0,0 +1,71 @@ +# Copyright (c) 2018 Mateusz Loskot <mateusz@loskot.net> +# Copyright (c) 2019 Hans Dembinski +# +# Use, modification and distribution is subject to 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) + +import testing ; +import ../../config/checks/config : requires ; + +project + : requirements + [ requires + cxx14_constexpr cxx14_decltype_auto cxx14_generic_lambdas cxx14_return_type_deduction cxx11_user_defined_literals + # list could go on... + ] + ; + +alias cxx14 : + [ run getting_started_listing_01.cpp ] + [ run getting_started_listing_02.cpp ] + [ run getting_started_listing_03.cpp ] + [ run getting_started_listing_04.cpp ] + [ run getting_started_listing_05.cpp ] + [ run guide_axis_basic_demo.cpp ] + [ run guide_axis_circular.cpp ] + [ run guide_axis_growing.cpp ] + [ run guide_axis_with_labels.cpp ] + [ run guide_axis_with_transform.cpp ] + [ run guide_axis_with_uoflow_off.cpp ] + [ run guide_custom_2d_axis.cpp ] + [ run guide_custom_accumulators_builtin.cpp ] + [ run guide_custom_accumulators_with_metadata.cpp ] + [ run guide_custom_accumulators_simple.cpp ] + [ run guide_custom_accumulators_advanced.cpp ] + [ run guide_custom_accumulators_ouroboros.cpp ] + [ run guide_custom_minimal_axis.cpp ] + [ run guide_custom_modified_axis.cpp ] + [ run guide_custom_storage.cpp ] + [ run guide_fill_histogram.cpp ] + [ run guide_fill_profile.cpp ] + [ run guide_fill_weighted_histogram.cpp ] + [ run guide_fill_weighted_profile.cpp ] + [ run guide_histogram_operators.cpp ] + [ run guide_histogram_reduction.cpp ] + [ run guide_histogram_projection.cpp ] + [ run guide_histogram_streaming.cpp ] + [ run guide_histogram_in_api.cpp ] + [ run guide_indexed_access.cpp ] + [ run guide_make_dynamic_histogram.cpp ] + [ run guide_make_static_histogram.cpp ] + [ run guide_stdlib_algorithms.cpp ] + ; + +alias threading : + [ run guide_parallel_filling.cpp ] : + <threading>multi + ; + +alias libserial : /boost/serialization//boost_serialization : <link>static ; + +alias serial : + [ run guide_histogram_serialization.cpp libserial ] + ; + +alias all : cxx14 threading serial ; + +explicit cxx14 ; +explicit threading ; +explicit libserial ; +explicit serial ; diff --git a/src/boost/libs/histogram/examples/getting_started_listing_01.cpp b/src/boost/libs/histogram/examples/getting_started_listing_01.cpp new file mode 100644 index 000000000..a83df68d7 --- /dev/null +++ b/src/boost/libs/histogram/examples/getting_started_listing_01.cpp @@ -0,0 +1,93 @@ +// Copyright 2015-2018 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) + +// clang-format off + +//[ getting_started_listing_01 + +#include <algorithm> // std::for_each +#include <boost/format.hpp> // only needed for printing +#include <boost/histogram.hpp> // make_histogram, regular, weight, indexed +#include <cassert> // assert (used to test this example for correctness) +#include <functional> // std::ref +#include <iostream> // std::cout, std::flush +#include <sstream> // std::ostringstream + +int main() { + using namespace boost::histogram; // strip the boost::histogram prefix + + /* + Create a 1d-histogram with a regular axis that has 6 equidistant bins on + the real line from -1.0 to 2.0, and label it as "x". A family of overloaded + factory functions called `make_histogram` makes creating histograms easy. + + A regular axis is a sequence of semi-open bins. Extra under- and overflow + bins extend the axis by default (this can be turned off). + + index : -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 + bin edges: -inf -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 inf + */ + auto h = make_histogram(axis::regular<>(6, -1.0, 2.0, "x")); + + /* + Let's fill a histogram with data, typically this happens in a loop. + + STL algorithms are supported. std::for_each is very convenient to fill a + histogram from an iterator range. Use std::ref in the call, if you don't + want std::for_each to make a copy of your histogram. + */ + auto data = {-0.5, 1.1, 0.3, 1.7}; + std::for_each(data.begin(), data.end(), std::ref(h)); + // let's fill some more values manually + h(-1.5); // is placed in underflow bin -1 + h(-1.0); // is placed in bin 0, bin interval is semi-open + h(2.0); // is placed in overflow bin 6, bin interval is semi-open + h(20.0); // is placed in overflow bin 6 + + /* + This does a weighted fill using the `weight` function as an additional + argument. It may appear at the beginning or end of the argument list. C++ + doesn't have keyword arguments like Python, this is the next-best thing. + */ + h(0.1, weight(1.0)); + + /* + Iterate over bins with the `indexed` range generator, which provides a + special accessor object, that can be used to obtain the current bin index, + and the current bin value by dereferncing (it acts like a pointer to the + value). Using `indexed` is convenient and gives you better performance than + looping over the histogram cells with hand-written for loops. By default, + under- and overflow bins are skipped. Passing `coverage::all` as the + optional second argument iterates over all bins. + + - Access the value with the dereference operator. + - Access the current index with `index(d)` method of the accessor. + - Access the corresponding bin interval view with `bin(d)`. + + The return type of `bin(d)` depends on the axis type (see the axis reference + for details). It usually is a class that represents a semi-open interval. + Edges can be accessed with methods `lower()` and `upper()`. + */ + + std::ostringstream os; + for (auto&& x : indexed(h, coverage::all)) { + os << boost::format("bin %2i [%4.1f, %4.1f): %i\n") + % x.index() % x.bin().lower() % x.bin().upper() % *x; + } + + std::cout << os.str() << std::flush; + + assert(os.str() == "bin -1 [-inf, -1.0): 1\n" + "bin 0 [-1.0, -0.5): 1\n" + "bin 1 [-0.5, -0.0): 1\n" + "bin 2 [-0.0, 0.5): 2\n" + "bin 3 [ 0.5, 1.0): 0\n" + "bin 4 [ 1.0, 1.5): 1\n" + "bin 5 [ 1.5, 2.0): 1\n" + "bin 6 [ 2.0, inf): 2\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/getting_started_listing_02.cpp b/src/boost/libs/histogram/examples/getting_started_listing_02.cpp new file mode 100644 index 000000000..cf5b3143a --- /dev/null +++ b/src/boost/libs/histogram/examples/getting_started_listing_02.cpp @@ -0,0 +1,83 @@ +// Copyright 2015-2018 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) + +// clang-format off + +//[ getting_started_listing_02 + +#include <boost/format.hpp> +#include <boost/histogram.hpp> +#include <cassert> +#include <iostream> +#include <sstream> +#include <string> + +int main() { + using namespace boost::histogram; + + /* + Create a histogram which can be configured dynamically at run-time. The axis + configuration is first collected in a vector of axis::variant type, which + can hold different axis types (those in its template argument list). Here, + we use a variant that can store a regular and a category axis. + */ + using reg = axis::regular<>; + using cat = axis::category<std::string>; + using variant = axis::variant<axis::regular<>, axis::category<std::string>>; + std::vector<variant> axes; + axes.emplace_back(cat({"red", "blue"})); + axes.emplace_back(reg(3, 0.0, 1.0, "x")); + axes.emplace_back(reg(3, 0.0, 1.0, "y")); + // passing an iterator range also works here + auto h = make_histogram(std::move(axes)); + + // fill histogram with data, usually this happens in a loop + h("red", 0.1, 0.2); + h("blue", 0.7, 0.3); + h("red", 0.3, 0.7); + h("red", 0.7, 0.7); + + /* + Print histogram by iterating over bins. + Since the [bin type] of the category axis cannot be converted into a double, + it cannot be handled by the polymorphic interface of axis::variant. We use + axis::get to "cast" the variant type to the actual category type. + */ + + // get reference to category axis, performs a run-time checked static cast + const auto& cat_axis = axis::get<cat>(h.axis(0)); + std::ostringstream os; + for (auto&& x : indexed(h)) { + os << boost::format("(%i, %i, %i) %4s [%3.1f, %3.1f) [%3.1f, %3.1f) %3.0f\n") + % x.index(0) % x.index(1) % x.index(2) + % cat_axis.bin(x.index(0)) + % x.bin(1).lower() % x.bin(1).upper() + % x.bin(2).lower() % x.bin(2).upper() + % *x; + } + + std::cout << os.str() << std::flush; + assert(os.str() == "(0, 0, 0) red [0.0, 0.3) [0.0, 0.3) 1\n" + "(1, 0, 0) blue [0.0, 0.3) [0.0, 0.3) 0\n" + "(0, 1, 0) red [0.3, 0.7) [0.0, 0.3) 0\n" + "(1, 1, 0) blue [0.3, 0.7) [0.0, 0.3) 0\n" + "(0, 2, 0) red [0.7, 1.0) [0.0, 0.3) 0\n" + "(1, 2, 0) blue [0.7, 1.0) [0.0, 0.3) 1\n" + "(0, 0, 1) red [0.0, 0.3) [0.3, 0.7) 0\n" + "(1, 0, 1) blue [0.0, 0.3) [0.3, 0.7) 0\n" + "(0, 1, 1) red [0.3, 0.7) [0.3, 0.7) 0\n" + "(1, 1, 1) blue [0.3, 0.7) [0.3, 0.7) 0\n" + "(0, 2, 1) red [0.7, 1.0) [0.3, 0.7) 0\n" + "(1, 2, 1) blue [0.7, 1.0) [0.3, 0.7) 0\n" + "(0, 0, 2) red [0.0, 0.3) [0.7, 1.0) 1\n" + "(1, 0, 2) blue [0.0, 0.3) [0.7, 1.0) 0\n" + "(0, 1, 2) red [0.3, 0.7) [0.7, 1.0) 0\n" + "(1, 1, 2) blue [0.3, 0.7) [0.7, 1.0) 0\n" + "(0, 2, 2) red [0.7, 1.0) [0.7, 1.0) 1\n" + "(1, 2, 2) blue [0.7, 1.0) [0.7, 1.0) 0\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/getting_started_listing_03.cpp b/src/boost/libs/histogram/examples/getting_started_listing_03.cpp new file mode 100644 index 000000000..f3ebfcd8c --- /dev/null +++ b/src/boost/libs/histogram/examples/getting_started_listing_03.cpp @@ -0,0 +1,54 @@ +// Copyright 2018 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) + +// clang-format off + +//[ getting_started_listing_03 + +#include <boost/format.hpp> +#include <boost/histogram.hpp> +#include <cassert> +#include <iostream> +#include <sstream> + +int main() { + using namespace boost::histogram; + + /* + Create a profile. Profiles does not only count entries in each cell, but + also compute the mean of a sample value in each cell. + */ + auto p = make_profile(axis::regular<>(5, 0.0, 1.0)); + + /* + Fill profile with data, usually this happens in a loop. You pass the sample + with the `sample` helper function. The sample can be the first or last + argument. + */ + p(0.1, sample(1)); + p(0.15, sample(3)); + p(0.2, sample(4)); + p(0.9, sample(5)); + + /* + Iterate over bins and print profile. + */ + std::ostringstream os; + for (auto&& x : indexed(p)) { + os << boost::format("bin %i [%3.1f, %3.1f) count %i mean %g\n") + % x.index() % x.bin().lower() % x.bin().upper() + % x->count() % x->value(); + } + + std::cout << os.str() << std::flush; + assert(os.str() == "bin 0 [0.0, 0.2) count 2 mean 2\n" + "bin 1 [0.2, 0.4) count 1 mean 4\n" + "bin 2 [0.4, 0.6) count 0 mean 0\n" + "bin 3 [0.6, 0.8) count 0 mean 0\n" + "bin 4 [0.8, 1.0) count 1 mean 5\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/getting_started_listing_04.cpp b/src/boost/libs/histogram/examples/getting_started_listing_04.cpp new file mode 100644 index 000000000..fe44b1f51 --- /dev/null +++ b/src/boost/libs/histogram/examples/getting_started_listing_04.cpp @@ -0,0 +1,60 @@ +// 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) + +// clang-format off + +//[ getting_started_listing_04 + +#include <algorithm> // std::max_element +#include <boost/format.hpp> // only needed for printing +#include <boost/histogram.hpp> // make_histogram, integer, indexed +#include <iostream> // std::cout, std::endl +#include <sstream> // std::ostringstream + +int main() { + using namespace boost::histogram; + using namespace boost::histogram::literals; + + /* + We make a 3d histogram for color values (r, g, b) in an image. We assume the values + are of type char. The value range then is [0, 256). The integer axis is perfect for + color values. + */ + auto h = make_histogram( + axis::integer<>(0, 256, "r"), + axis::integer<>(0, 256, "g"), + axis::integer<>(0, 256, "b") + ); + + /* + We don't have real image data, so fill some fake data. + */ + h(1, 2, 3); + h(1, 2, 3); + h(0, 1, 0); + + /* + Now let's say we want to know which color is most common. We can use std::max_element + on an indexed range for that. + */ + auto ind = indexed(h); + auto max_it = std::max_element(ind.begin(), ind.end()); + + /* + max_it is a special iterator to the histogram cell with the highest count. + This iterator allows one to access the cell value, bin indices, and bin values. + You need to twice dereference it to get to the cell value. + */ + std::ostringstream os; + os << boost::format("count=%i rgb=(%i, %i, %i)") + % **max_it % max_it->bin(0_c) % max_it->bin(1) % max_it->bin(2); + + std::cout << os.str() << std::endl; + + assert(os.str() == "count=2 rgb=(1, 2, 3)"); +} + +//] diff --git a/src/boost/libs/histogram/examples/getting_started_listing_05.cpp b/src/boost/libs/histogram/examples/getting_started_listing_05.cpp new file mode 100644 index 000000000..52706284b --- /dev/null +++ b/src/boost/libs/histogram/examples/getting_started_listing_05.cpp @@ -0,0 +1,65 @@ +// 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) + +// clang-format off + +//[ getting_started_listing_05 + +//////////////// Begin: put this in header file //////////////////// + +#include <algorithm> // std::max_element +#include <boost/format.hpp> // only needed for printing +#include <boost/histogram.hpp> // make_histogram, integer, indexed +#include <iostream> // std::cout, std::endl +#include <sstream> // std::ostringstream +#include <tuple> +#include <vector> + +// use this when axis configuration is fix to get highest performance +struct HolderOfStaticHistogram { + // put axis types here + using axes_t = std::tuple< + boost::histogram::axis::regular<>, + boost::histogram::axis::integer<> + >; + using hist_t = boost::histogram::histogram<axes_t>; + hist_t hist_; +}; + +// use this when axis configuration should be flexible +struct HolderOfDynamicHistogram { + // put all axis types here that you are going to use + using axis_t = boost::histogram::axis::variant< + boost::histogram::axis::regular<>, + boost::histogram::axis::variable<>, + boost::histogram::axis::integer<> + >; + using axes_t = std::vector<axis_t>; + using hist_t = boost::histogram::histogram<axes_t>; + hist_t hist_; +}; + +//////////////// End: put this in header file //////////////////// + +int main() { + using namespace boost::histogram; + + HolderOfStaticHistogram hs; + hs.hist_ = make_histogram(axis::regular<>(5, 0, 1), axis::integer<>(0, 3)); + // now assign a different histogram + hs.hist_ = make_histogram(axis::regular<>(3, 1, 2), axis::integer<>(4, 6)); + // hs.hist_ = make_histogram(axis::regular<>(5, 0, 1)); does not work; + // the static histogram cannot change the number or order of axis types + + HolderOfDynamicHistogram hd; + hd.hist_ = make_histogram(axis::regular<>(5, 0, 1), axis::integer<>(0, 3)); + // now assign a different histogram + hd.hist_ = make_histogram(axis::regular<>(3, -1, 2)); + // and assign another + hd.hist_ = make_histogram(axis::integer<>(0, 5), axis::integer<>(3, 5)); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_axis_basic_demo.cpp b/src/boost/libs/histogram/examples/guide_axis_basic_demo.cpp new file mode 100644 index 000000000..2612d043c --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_axis_basic_demo.cpp @@ -0,0 +1,82 @@ +// 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) + +//[ guide_axis_basic_demo + +#include <boost/histogram/axis.hpp> +#include <limits> + +int main() { + using namespace boost::histogram; + + // make a regular axis with 10 bins over interval from 1.5 to 2.5 + auto r = axis::regular<>{10, 1.5, 2.5}; + // `<>` is needed in C++14 because the axis is templated, + // in C++17 you can do: auto r = axis::regular{10, 1.5, 2.5}; + assert(r.size() == 10); + // alternatively, you can define the step size with the `step` marker + auto r_step = axis::regular<>{axis::step(0.1), 1.5, 2.5}; + assert(r_step == r); + + // histogram uses the `index` method to convert values to indices + // note: intervals of builtin axis types are always semi-open [a, b) + assert(r.index(1.5) == 0); + assert(r.index(1.6) == 1); + assert(r.index(2.4) == 9); + // index for a value below the start of the axis is always -1 + assert(r.index(1.0) == -1); + assert(r.index(-std::numeric_limits<double>::infinity()) == -1); + // index for a value below the above the end of the axis is always `size()` + assert(r.index(3.0) == 10); + assert(r.index(std::numeric_limits<double>::infinity()) == 10); + // index for not-a-number is also `size()` by convention + assert(r.index(std::numeric_limits<double>::quiet_NaN()) == 10); + + // make a variable axis with 3 bins [-1.5, 0.1), [0.1, 0.3), [0.3, 10) + auto v = axis::variable<>{-1.5, 0.1, 0.3, 10.}; + assert(v.index(-2.0) == -1); + assert(v.index(-1.5) == 0); + assert(v.index(0.1) == 1); + assert(v.index(0.3) == 2); + assert(v.index(10) == 3); + assert(v.index(20) == 3); + + // make an integer axis with 3 bins at -1, 0, 1 + auto i = axis::integer<>{-1, 2}; + assert(i.index(-2) == -1); + assert(i.index(-1) == 0); + assert(i.index(0) == 1); + assert(i.index(1) == 2); + assert(i.index(2) == 3); + + // make an integer axis called "foo" + auto i_with_label = axis::integer<>{-1, 2, "foo"}; + // all builtin axis types allow you to pass some optional metadata as the last + // argument in the constructor; a string by default, but can be any copyable type + + // two axis do not compare equal if they differ in their metadata + assert(i != i_with_label); + + // integer axis also work well with unscoped enums + enum { red, blue }; + auto i_for_enum = axis::integer<>{red, blue + 1}; + assert(i_for_enum.index(red) == 0); + assert(i_for_enum.index(blue) == 1); + + // make a category axis from a scoped enum and/or if the identifiers are not consecutive + enum class Bar { red = 12, blue = 6 }; + auto c = axis::category<Bar>{Bar::red, Bar::blue}; + assert(c.index(Bar::red) == 0); + assert(c.index(Bar::blue) == 1); + // c.index(12) is a compile-time error, since the argument must be of type `Bar` + + // category axis can be created for any copyable and equal-comparable type + auto c_str = axis::category<std::string>{"red", "blue"}; + assert(c_str.index("red") == 0); + assert(c_str.index("blue") == 1); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_axis_circular.cpp b/src/boost/libs/histogram/examples/guide_axis_circular.cpp new file mode 100644 index 000000000..b4b8b4941 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_axis_circular.cpp @@ -0,0 +1,43 @@ +// 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) + +//[ guide_axis_circular + +#include <boost/histogram/axis.hpp> +#include <limits> + +int main() { + using namespace boost::histogram; + + // make a circular regular axis ... [0, 180), [180, 360), [0, 180) .... + using opts = decltype(axis::option::overflow | axis::option::circular); + auto r = axis::regular<double, use_default, use_default, opts>{2, 0., 360.}; + assert(r.index(-180) == 1); + assert(r.index(0) == 0); + assert(r.index(180) == 1); + assert(r.index(360) == 0); + assert(r.index(540) == 1); + assert(r.index(720) == 0); + // special values are mapped to the overflow bin index + assert(r.index(std::numeric_limits<double>::infinity()) == 2); + assert(r.index(-std::numeric_limits<double>::infinity()) == 2); + assert(r.index(std::numeric_limits<double>::quiet_NaN()) == 2); + + // since the regular axis is the most common circular axis, there exists an alias + auto c = axis::circular<>{2, 0., 360.}; + assert(r == c); + + // make a circular integer axis + auto i = axis::integer<int, use_default, axis::option::circular_t>{1, 4}; + assert(i.index(0) == 2); + assert(i.index(1) == 0); + assert(i.index(2) == 1); + assert(i.index(3) == 2); + assert(i.index(4) == 0); + assert(i.index(5) == 1); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_axis_growing.cpp b/src/boost/libs/histogram/examples/guide_axis_growing.cpp new file mode 100644 index 000000000..5aed481b3 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_axis_growing.cpp @@ -0,0 +1,62 @@ +// 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) + +// clang-format off + +//[ guide_axis_growing + +#include <boost/histogram.hpp> +#include <cassert> + +#include <iostream> + +int main() { + using namespace boost::histogram; + + // make a growing regular axis + // - it grows new bins with its constant bin width until the value is covered + auto h1 = make_histogram(axis::regular<double, + use_default, + use_default, + axis::option::growth_t>{2, 0., 1.}); + // nothing special happens here + h1(0.1); + h1(0.9); + // state: [0, 0.5): 1, [0.5, 1.0): 1 + assert(h1.axis().size() == 2); + assert(h1.axis().bin(0).lower() == 0.0); + assert(h1.axis().bin(1).upper() == 1.0); + + // value below range: axis grows new bins until value is in range + h1(-0.3); + // state: [-0.5, 0.0): 1, [0, 0.5): 1, [0.5, 1.0): 1 + assert(h1.axis().size() == 3); + assert(h1.axis().bin(0).lower() == -0.5); + assert(h1.axis().bin(2).upper() == 1.0); + + h1(1.9); + // state: [-0.5, 0.0): 1, [0, 0.5): 1, [0.5, 1.0): 1, [1.0, 1.5): 0 [1.5, 2.0): 1 + assert(h1.axis().size() == 5); + assert(h1.axis().bin(0).lower() == -0.5); + assert(h1.axis().bin(4).upper() == 2.0); + + // make a growing category axis (here strings) + // - empty axis is allowed: very useful if categories are not known at the beginning + auto h2 = make_histogram(axis::category<std::string, + use_default, + axis::option::growth_t>()); + assert(h2.size() == 0); // histogram is empty + h2("foo"); // new bin foo, index 0 + assert(h2.size() == 1); + h2("bar"); // new bin bar, index 1 + assert(h2.size() == 2); + h2("foo"); + assert(h2.size() == 2); + assert(h2[0] == 2); + assert(h2[1] == 1); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_axis_with_labels.cpp b/src/boost/libs/histogram/examples/guide_axis_with_labels.cpp new file mode 100644 index 000000000..3f3ad8b54 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_axis_with_labels.cpp @@ -0,0 +1,21 @@ +// Copyright 2015-2018 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) + +//[ guide_axis_with_labels + +#include <boost/histogram.hpp> + +int main() { + using namespace boost::histogram; + + // create a 2d-histogram with an "age" and an "income" axis + auto h = make_histogram(axis::regular<>(20, 0.0, 100.0, "age in years"), + axis::regular<>(20, 0.0, 100.0, "yearly income in Thousands")); + + // do something with h +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_axis_with_transform.cpp b/src/boost/libs/histogram/examples/guide_axis_with_transform.cpp new file mode 100644 index 000000000..9b3412a7c --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_axis_with_transform.cpp @@ -0,0 +1,57 @@ +// 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) + +//[ guide_axis_with_transform + +#include <boost/histogram/axis/regular.hpp> +#include <limits> + +int main() { + using namespace boost::histogram; + + // make a regular axis with a log transform over [10, 100), [100, 1000), [1000, 10000) + axis::regular<double, axis::transform::log> r_log{3, 10., 10000.}; + // log transform: + // - useful when values vary dramatically in magnitude, like brightness of stars + // - edges are not exactly at 10, 100, 1000, because of finite floating point precision + // - values >= 0 but smaller than the starting value of the axis are mapped to -1 + // - values < 0 are mapped to `size()`, because the result of std::log(value) is NaN + assert(r_log.index(10.1) == 0); + assert(r_log.index(100.1) == 1); + assert(r_log.index(1000.1) == 2); + assert(r_log.index(1) == -1); + assert(r_log.index(0) == -1); + assert(r_log.index(-1) == 3); + + // make a regular axis with a sqrt transform over [4, 9), [9, 16), [16, 25) + axis::regular<double, axis::transform::sqrt> r_sqrt{3, 4., 25.}; + // sqrt transform: + // - bin widths are more mildly increasing compared to log transform + // - axis starting at value == 0 is ok, sqrt(0) == 0 unlike log transform + // - values < 0 are mapped to `size()`, because the result of std::sqrt(value) is NaN + assert(r_sqrt.index(0) == -1); + assert(r_sqrt.index(4.1) == 0); + assert(r_sqrt.index(9.1) == 1); + assert(r_sqrt.index(16.1) == 2); + assert(r_sqrt.index(25.1) == 3); + assert(r_sqrt.index(-1) == 3); + + // make a regular axis with a power transform x^1/3 over [1, 8), [8, 27), [27, 64) + using pow_trans = axis::transform::pow; + axis::regular<double, pow_trans> r_pow(pow_trans{1. / 3.}, 3, 1., 64.); + // pow transform: + // - generalization of the sqrt transform + // - starting the axis at value == 0 is ok for power p > 0, 0^p == 0 for p > 0 + // - values < 0 are mapped to `size()` if power p is not a positive integer + assert(r_pow.index(0) == -1); + assert(r_pow.index(1.1) == 0); + assert(r_pow.index(8.1) == 1); + assert(r_pow.index(27.1) == 2); + assert(r_pow.index(64.1) == 3); + assert(r_pow.index(-1) == 3); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_axis_with_uoflow_off.cpp b/src/boost/libs/histogram/examples/guide_axis_with_uoflow_off.cpp new file mode 100644 index 000000000..7fe96f5d7 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_axis_with_uoflow_off.cpp @@ -0,0 +1,30 @@ +// Copyright 2015-2018 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) + +//[ guide_axis_with_uoflow_off + +#include <boost/histogram.hpp> +#include <string> + +int main() { + using namespace boost::histogram; + + // create a 1d-histogram over integer values from 1 to 6 + auto h1 = make_histogram(axis::integer<int>(1, 7)); + // axis has size 6... + assert(h1.axis().size() == 6); + // ... but histogram has size 8, because of overflow and underflow bins + assert(h1.size() == 8); + + // create a 1d-histogram for throws of a six-sided die without extra bins, + // since the values cannot be smaller than 1 or larger than 6 + auto h2 = make_histogram(axis::integer<int, use_default, axis::option::none_t>(1, 7)); + // now size of axis and histogram is equal + assert(h2.axis().size() == 6); + assert(h2.size() == 6); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_custom_2d_axis.cpp b/src/boost/libs/histogram/examples/guide_custom_2d_axis.cpp new file mode 100644 index 000000000..6a952a659 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_custom_2d_axis.cpp @@ -0,0 +1,56 @@ +// Copyright 2018 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) + +//[ guide_custom_2d_axis + +#include <boost/histogram.hpp> +#include <cassert> + +int main() { + using namespace boost::histogram; + + // axis which returns 1 if the input falls inside the unit circle and zero otherwise + struct circle_axis { + // accepts a 2D point in form of a std::tuple + axis::index_type index(const std::tuple<double, double>& point) const { + const auto x = std::get<0>(point); + const auto y = std::get<1>(point); + return x * x + y * y <= 1.0; + } + + axis::index_type size() const { return 2; } + }; + + auto h1 = make_histogram(circle_axis()); + + // fill looks normal for a histogram which has only one Nd-axis + h1(0, 0); // in + h1(0, -1); // in + h1(0, 1); // in + h1(-1, 0); // in + h1(1, 0); // in + h1(1, 1); // out + h1(-1, -1); // out + + // 2D histogram, but only 1D index + assert(h1.at(0) == 2); // out + assert(h1.at(1) == 5); // in + + // other axes can be combined with a Nd-axis + auto h2 = make_histogram(circle_axis(), axis::category<std::string>({"red", "blue"})); + + // now we need to pass arguments for Nd-axis explicitly as std::tuple + h2(std::make_tuple(0, 0), "red"); + h2(std::make_tuple(1, 1), "blue"); + + // 3D histogram, but only 2D index + assert(h2.at(0, 0) == 0); // out, red + assert(h2.at(0, 1) == 1); // out, blue + assert(h2.at(1, 0) == 1); // in, red + assert(h2.at(1, 1) == 0); // in, blue +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_custom_accumulators_advanced.cpp b/src/boost/libs/histogram/examples/guide_custom_accumulators_advanced.cpp new file mode 100644 index 000000000..16ab559f2 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_custom_accumulators_advanced.cpp @@ -0,0 +1,52 @@ +// 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) + +//[ guide_custom_accumulators_advanced + +#include <boost/format.hpp> +#include <boost/histogram.hpp> +#include <iostream> +#include <sstream> + +int main() { + using namespace boost::histogram; + + // Accumulator accepts two samples and an optional weight and computes the mean of each. + struct multi_mean { + accumulators::mean<> mx, my; + + // called when no weight is passed + void operator()(double x, double y) { + mx(x); + my(y); + } + + // called when a weight is passed + void operator()(weight_type<double> w, double x, double y) { + mx(w, x); + my(w, y); + } + }; + // Note: The implementation can be made more efficient by sharing the sum of weights. + + // Create a 1D histogram that uses the custom accumulator. + auto h = make_histogram_with(dense_storage<multi_mean>(), axis::integer<>(0, 2)); + h(0, sample(1, 2)); // samples go to first cell + h(0, sample(3, 4)); // samples go to first cell + h(1, sample(5, 6), weight(2)); // samples go to second cell + h(1, sample(7, 8), weight(3)); // samples go to second cell + + std::ostringstream os; + for (auto&& bin : indexed(h)) { + os << boost::format("index %i mean-x %.1f mean-y %.1f\n") % bin.index() % + bin->mx.value() % bin->my.value(); + } + std::cout << os.str() << std::flush; + assert(os.str() == "index 0 mean-x 2.0 mean-y 3.0\n" + "index 1 mean-x 6.2 mean-y 7.2\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_custom_accumulators_builtin.cpp b/src/boost/libs/histogram/examples/guide_custom_accumulators_builtin.cpp new file mode 100644 index 000000000..59c1e1c7a --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_custom_accumulators_builtin.cpp @@ -0,0 +1,43 @@ +// Copyright 2018 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) + +//[ guide_custom_accumulators_builtin + +#include <boost/format.hpp> +#include <boost/histogram.hpp> +#include <cassert> +#include <iostream> +#include <sstream> + +int main() { + using namespace boost::histogram; + using mean = accumulators::mean<>; + + // Create a 1D-profile, which computes the mean of samples in each bin. + auto h = make_histogram_with(dense_storage<mean>(), axis::integer<>(0, 2)); + // The factory function `make_profile` is provided as a shorthand for this, so this is + // equivalent to the previous line: auto h = make_profile(axis::integer<>(0, 2)); + + // An argument marked as `sample` is passed to the accumulator. + h(0, sample(1)); // sample goes to first cell + h(0, sample(2)); // sample goes to first cell + h(1, sample(3)); // sample goes to second cell + h(1, sample(4)); // sample goes to second cell + + std::ostringstream os; + for (auto&& x : indexed(h)) { + // Accumulators usually have methods to access their state. Use the arrow + // operator to access them. Here, `count()` gives the number of samples, + // `value()` the mean, and `variance()` the variance estimate of the mean. + os << boost::format("index %i count %i mean %.1f variance %.1f\n") % x.index() % + x->count() % x->value() % x->variance(); + } + std::cout << os.str() << std::flush; + assert(os.str() == "index 0 count 2 mean 1.5 variance 0.5\n" + "index 1 count 2 mean 3.5 variance 0.5\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_custom_accumulators_ouroboros.cpp b/src/boost/libs/histogram/examples/guide_custom_accumulators_ouroboros.cpp new file mode 100644 index 000000000..5d7299e18 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_custom_accumulators_ouroboros.cpp @@ -0,0 +1,51 @@ +// 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) + +//[ guide_custom_accumulators_ouroboros + +#include <boost/histogram.hpp> +#include <cmath> +#include <iostream> +#include <sstream> +#include <string> + +int main() { + using namespace boost::histogram; + + // First we define the nested histogram type. + using axis_t = axis::category<int, axis::null_type, axis::option::growth_t>; + using base_t = histogram<std::tuple<axis_t>>; + + // Now we make an accumulator out of it by using inheritance. + // We only need to implement operator(). A matching version of operator() is actually + // present in base_t, but it is templated and this is not allowed by the accumulator + // concept. Initialization could also happen here. We don't need to initialize anything + // here, because the default constructor of base_t is called automatically and + // sufficient for this example. + struct hist_t : base_t { + void operator()(const double x) { base_t::operator()(x); } + }; + + auto h = make_histogram_with(dense_storage<hist_t>(), axis::integer<>(1, 4)); + + auto x = {1, 1, 2, 2}; + auto s = {1, 2, 3, 3}; // samples are filled into the nested histograms + h.fill(x, sample(s)); + + std::ostringstream os; + for (auto&& x : indexed(h)) { + os << x.bin() << " "; + for (auto&& y : indexed(*x)) { os << "(" << y.bin() << ": " << *y << ") "; } + os << "\n"; + } + + std::cout << os.str() << std::flush; + assert(os.str() == "1 (1: 1) (2: 1) \n" + "2 (3: 2) \n" + "3 \n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_custom_accumulators_simple.cpp b/src/boost/libs/histogram/examples/guide_custom_accumulators_simple.cpp new file mode 100644 index 000000000..3e8bec478 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_custom_accumulators_simple.cpp @@ -0,0 +1,44 @@ +// Copyright 2018 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) + +//[ guide_custom_accumulators_simple + +#include <boost/format.hpp> +#include <boost/histogram.hpp> +#include <cassert> +#include <iostream> +#include <sstream> + +int main() { + using namespace boost::histogram; + + // A custom accumulator which tracks the maximum of the samples. + // It must have a call operator that accepts the argument of the `sample` function. + struct maximum { + // return value is ignored, so we use void + void operator()(double x) { + if (x > value) value = x; + } + double value = 0; // value is public and initialized to zero + }; + + // Create 1D histogram that uses the custom accumulator. + auto h = make_histogram_with(dense_storage<maximum>(), axis::integer<>(0, 2)); + h(0, sample(1.0)); // sample goes to first cell + h(0, sample(2.0)); // sample goes to first cell + h(1, sample(3.0)); // sample goes to second cell + h(1, sample(4.0)); // sample goes to second cell + + std::ostringstream os; + for (auto&& x : indexed(h)) { + os << boost::format("index %i maximum %.1f\n") % x.index() % x->value; + } + std::cout << os.str() << std::flush; + assert(os.str() == "index 0 maximum 2.0\n" + "index 1 maximum 4.0\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_custom_accumulators_with_metadata.cpp b/src/boost/libs/histogram/examples/guide_custom_accumulators_with_metadata.cpp new file mode 100644 index 000000000..478f97842 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_custom_accumulators_with_metadata.cpp @@ -0,0 +1,47 @@ +// 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) + +//[ guide_custom_accumulators_with_metadata + +#include <boost/histogram.hpp> +#include <cmath> +#include <iostream> +#include <sstream> +#include <string> + +int main() { + using namespace boost::histogram; + + // derive custom accumulator from one of the builtins + struct accumulator_with_metadata : accumulators::count<> { + std::string meta; // custom meta data + + // arbitrary additional data and interface could be added here + }; + + // make 1D histogram with custom accmulator + auto h = make_histogram_with(dense_storage<accumulator_with_metadata>(), + axis::integer<>(1, 4)); + + // fill some weighted entries + auto x = {1, 0, 2, 1}; + h.fill(x); + + // assigning meta data to two bins + h[0].meta = "Foo"; + h[2].meta = "Bar"; + + std::ostringstream os; + for (auto&& x : indexed(h)) + os << x.bin() << " value " << x->value() << " meta " << x->meta << "\n"; + + std::cout << os.str() << std::flush; + assert(os.str() == "1 value 2 meta Foo\n" + "2 value 1 meta \n" + "3 value 0 meta Bar\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_custom_minimal_axis.cpp b/src/boost/libs/histogram/examples/guide_custom_minimal_axis.cpp new file mode 100644 index 000000000..21c5fd5ce --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_custom_minimal_axis.cpp @@ -0,0 +1,41 @@ +// Copyright 2015-2018 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) + +//[ guide_custom_minimal_axis + +#include <boost/histogram.hpp> +#include <cassert> + +int main() { + using namespace boost::histogram; + + // stateless axis which returns 1 if the input is even and 0 otherwise + struct even_odd_axis { + axis::index_type index(int x) const { return x % 2; } + axis::index_type size() const { return 2; } + }; + + // threshold axis which returns 1 if the input is above threshold + struct threshold_axis { + threshold_axis(double x) : thr(x) {} + axis::index_type index(double x) const { return x >= thr; } + axis::index_type size() const { return 2; } + double thr; + }; + + auto h = make_histogram(even_odd_axis(), threshold_axis(3.0)); + + h(0, 2.0); + h(1, 4.0); + h(2, 4.0); + + assert(h.at(0, 0) == 1); // even, below threshold + assert(h.at(0, 1) == 1); // even, above threshold + assert(h.at(1, 0) == 0); // odd, below threshold + assert(h.at(1, 1) == 1); // odd, above threshold +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_custom_modified_axis.cpp b/src/boost/libs/histogram/examples/guide_custom_modified_axis.cpp new file mode 100644 index 000000000..87e2aa094 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_custom_modified_axis.cpp @@ -0,0 +1,47 @@ +// Copyright 2015-2018 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) + +//[ guide_custom_modified_axis + +#include <boost/histogram.hpp> +#include <cassert> +#include <iostream> +#include <sstream> + +int main() { + using namespace boost::histogram; + + // custom axis, which adapts builtin integer axis + struct custom_axis : public axis::integer<> { + using value_type = const char*; // type that is fed to the axis + + using integer::integer; // inherit ctors of base + + // the customization point + // - accept const char* and convert to int + // - then call index method of base class + axis::index_type index(value_type s) const { return integer::index(std::atoi(s)); } + }; + + auto h = make_histogram(custom_axis(3, 6)); + h("-10"); + h("3"); + h("4"); + h("9"); + + std::ostringstream os; + for (auto&& b : indexed(h)) { + os << "bin " << b.index() << " [" << b.bin() << "] " << *b << "\n"; + } + + std::cout << os.str() << std::endl; + + assert(os.str() == "bin 0 [3] 1\n" + "bin 1 [4] 1\n" + "bin 2 [5] 0\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_custom_storage.cpp b/src/boost/libs/histogram/examples/guide_custom_storage.cpp new file mode 100644 index 000000000..6737df7e0 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_custom_storage.cpp @@ -0,0 +1,47 @@ +// Copyright 2015-2018 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) + +//[ guide_custom_storage + +#include <algorithm> // std::for_each +#include <array> +#include <boost/histogram.hpp> +#include <boost/histogram/algorithm/sum.hpp> +#include <functional> // std::ref +#include <unordered_map> +#include <vector> + +int main() { + using namespace boost::histogram; + const auto axis = axis::regular<>(10, 0.0, 1.0); + + auto data = {0.1, 0.3, 0.2, 0.7}; + + // Create static histogram with vector<int> as counter storage, you can use + // other arithmetic types as counters, e.g. double. + auto h1 = make_histogram_with(std::vector<int>(), axis); + std::for_each(data.begin(), data.end(), std::ref(h1)); + assert(algorithm::sum(h1) == 4); + + // Create static histogram with array<int, N> as counter storage which is + // allocated completely on the stack (this is very fast). N may be larger than + // the actual number of bins used; an exception is raised if N is too small to + // hold all bins. + auto h2 = make_histogram_with(std::array<int, 12>(), axis); + std::for_each(data.begin(), data.end(), std::ref(h2)); + assert(algorithm::sum(h2) == 4); + + // Create static histogram with unordered_map as counter storage; this + // generates a sparse histogram where only memory is allocated for bins that + // are non-zero. This sounds like a good idea for high-dimensional histograms, + // but maps come with a memory and run-time overhead. The default_storage + // usually performs better in high dimensions. + auto h3 = make_histogram_with(std::unordered_map<std::size_t, int>(), axis); + std::for_each(data.begin(), data.end(), std::ref(h3)); + assert(algorithm::sum(h3) == 4); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_fill_histogram.cpp b/src/boost/libs/histogram/examples/guide_fill_histogram.cpp new file mode 100644 index 000000000..172be66e0 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_fill_histogram.cpp @@ -0,0 +1,61 @@ +// Copyright 2015-2018 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) + +//[ guide_fill_histogram + +#include <boost/histogram.hpp> +#include <cassert> +#include <functional> +#include <numeric> +#include <utility> +#include <vector> + +int main() { + using namespace boost::histogram; + + auto h = make_histogram(axis::integer<>(0, 3), axis::regular<>(2, 0.0, 1.0)); + + // fill histogram, number of arguments must be equal to number of axes, + // types must be convertible to axis value type (here integer and double) + h(0, 0.2); // increase a cell value by one + h(2, 0.5); // increase another cell value by one + + // fills from a tuple are also supported; passing a tuple of wrong size + // causes an error at compile-time or an assertion at runtime in debug mode + auto xy = std::make_tuple(1, 0.3); + h(xy); + + // chunk-wise filling is also supported and more efficient, make some data... + std::vector<double> xy2[2] = {{0, 2, 5}, {0.8, 0.4, 0.7}}; + + // ... and call fill method + h.fill(xy2); + + // once histogram is filled, access individual cells using operator[] or at(...) + // - operator[] can only accept a single argument in the current version of C++, + // it is convenient when you have a 1D histogram + // - at(...) can accept several values, so use this by default + // - underflow bins are at index -1, overflow bins at index `size()` + // - passing an invalid index triggers a std::out_of_range exception + assert(h.at(0, 0) == 1); + assert(h.at(0, 1) == 1); + assert(h.at(1, 0) == 1); + assert(h.at(1, 1) == 0); + assert(h.at(2, 0) == 1); + assert(h.at(2, 1) == 1); + assert(h.at(-1, -1) == 0); // underflow for axis 0 and 1 + assert(h.at(-1, 0) == 0); // underflow for axis 0, normal bin for axis 1 + assert(h.at(-1, 2) == 0); // underflow for axis 0, overflow for axis 1 + assert(h.at(3, 1) == 1); // overflow for axis 0, normal bin for axis 1 + + // iteration over values works, but see next example for a better way + // - iteration using begin() and end() includes under- and overflow bins + // - iteration order is an implementation detail and should not be relied upon + const double sum = std::accumulate(h.begin(), h.end(), 0.0); + assert(sum == 6); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_fill_profile.cpp b/src/boost/libs/histogram/examples/guide_fill_profile.cpp new file mode 100644 index 000000000..55d650815 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_fill_profile.cpp @@ -0,0 +1,53 @@ +// 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) + +//[ guide_fill_profile + +#include <boost/format.hpp> +#include <boost/histogram.hpp> +#include <cassert> +#include <iostream> +#include <sstream> +#include <tuple> + +int main() { + using namespace boost::histogram; + + // make a profile, it computes the mean of the samples in each histogram cell + auto h = make_profile(axis::integer<>(0, 3)); + + // mean is computed from the values marked with the sample() helper function + h(0, sample(1)); // sample goes to cell 0 + h(0, sample(2)); // sample goes to cell 0 + h(1, sample(3)); // sample goes to cell 1 + h(sample(4), 1); // sample goes to cell 1; sample can be first or last argument + + // fills from tuples are also supported, 5 and 6 go to cell 2 + auto a = std::make_tuple(2, sample(5)); + auto b = std::make_tuple(sample(6), 2); + h(a); + h(b); + + // builtin accumulators have methods to access their state + std::ostringstream os; + for (auto&& x : indexed(h)) { + // use `.` to access methods of accessor, like `index()` + // use `->` to access methods of accumulator + const auto i = x.index(); + const auto n = x->count(); // how many samples are in this bin + const auto vl = x->value(); // mean value + const auto vr = x->variance(); // estimated variance of the mean value + os << boost::format("index %i count %i value %.1f variance %.1f\n") % i % n % vl % vr; + } + + std::cout << os.str() << std::flush; + + assert(os.str() == "index 0 count 2 value 1.5 variance 0.5\n" + "index 1 count 2 value 3.5 variance 0.5\n" + "index 2 count 2 value 5.5 variance 0.5\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_fill_weighted_histogram.cpp b/src/boost/libs/histogram/examples/guide_fill_weighted_histogram.cpp new file mode 100644 index 000000000..487e1c33a --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_fill_weighted_histogram.cpp @@ -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) + +//[ guide_fill_weighted_histogram + +#include <boost/histogram.hpp> +#include <cassert> + +int main() { + using namespace boost::histogram; + + // Create a histogram with weight counters that keep track of a variance estimate. + auto h = make_weighted_histogram(axis::regular<>(3, 0.0, 1.0)); + + h(0.0, weight(1)); // weight 1 goes to first bin + h(0.1, weight(2)); // weight 2 goes to first bin + h(0.4, weight(3)); // weight 3 goes to second bin + h(0.5, weight(4)); // weight 4 goes to second bin + + // chunk-wise filling is also supported + auto x = {0.2, 0.6}; + auto w = {5, 6}; + h.fill(x, weight(w)); + + // Weight counters have methods to access the value (sum of weights) and the variance + // (sum of weights squared, why this gives the variance is explained in the rationale) + assert(h[0].value() == 1 + 2 + 5); + assert(h[0].variance() == 1 * 1 + 2 * 2 + 5 * 5); + assert(h[1].value() == 3 + 4 + 6); + assert(h[1].variance() == 3 * 3 + 4 * 4 + 6 * 6); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_fill_weighted_profile.cpp b/src/boost/libs/histogram/examples/guide_fill_weighted_profile.cpp new file mode 100644 index 000000000..767bfad86 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_fill_weighted_profile.cpp @@ -0,0 +1,51 @@ +// 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) + +//[ guide_fill_weighted_profile + +#include <boost/format.hpp> +#include <boost/histogram.hpp> +#include <cassert> +#include <iostream> +#include <sstream> + +int main() { + using namespace boost::histogram; + using namespace boost::histogram::literals; // _c suffix creates compile-time numbers + + // make 2D weighted profile + auto h = make_weighted_profile(axis::integer<>(0, 2), axis::integer<>(0, 2)); + + // The mean is computed from the values marked with the sample() helper function. + // Weights can be passed as well. The `sample` and `weight` arguments can appear in any + // order, but they must be the first or last arguments. + h(0, 0, sample(1)); // sample goes to cell (0, 0); weight is 1 + h(0, 0, sample(2), weight(3)); // sample goes to cell (0, 0); weight is 3 + h(1, 0, sample(3)); // sample goes to cell (1, 0); weight is 1 + h(1, 0, sample(4)); // sample goes to cell (1, 0); weight is 1 + h(0, 1, sample(5)); // sample goes to cell (1, 0); weight is 1 + h(0, 1, sample(6)); // sample goes to cell (1, 0); weight is 1 + h(1, 1, weight(4), sample(7)); // sample goes to cell (1, 1); weight is 4 + h(weight(5), sample(8), 1, 1); // sample goes to cell (1, 1); weight is 5 + + std::ostringstream os; + for (auto&& x : indexed(h)) { + const auto i = x.index(0_c); + const auto j = x.index(1_c); + const auto m = x->value(); // weighted mean + const auto v = x->variance(); // estimated variance of weighted mean + os << boost::format("index %i,%i mean %.1f variance %.1f\n") % i % j % m % v; + } + + std::cout << os.str() << std::flush; + + assert(os.str() == "index 0,0 mean 1.8 variance 0.5\n" + "index 1,0 mean 3.5 variance 0.5\n" + "index 0,1 mean 5.5 variance 0.5\n" + "index 1,1 mean 7.6 variance 0.5\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_histogram_in_api.cpp b/src/boost/libs/histogram/examples/guide_histogram_in_api.cpp new file mode 100644 index 000000000..1011e6885 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_histogram_in_api.cpp @@ -0,0 +1,57 @@ +// Copyright 2020 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) + +//[ guide_histogram_in_api + +#include <boost/histogram.hpp> +#include <cassert> + +// function accepts any histogram and returns a copy +template <class Axes, class Storage> +boost::histogram::histogram<Axes, Storage> any_histogram( + boost::histogram::histogram<Axes, Storage>& h) { + return h; +} + +// function only accepts histograms with fixed axis types and returns a copy +template <class Storage, class... Axes> +boost::histogram::histogram<std::tuple<Axes...>, Storage> only_static_histogram( + boost::histogram::histogram<std::tuple<Axes...>, Storage>& h) { + return h; +} + +// function only accepts histograms with dynamic axis types and returns a copy +template <class Storage, class... Axes> +boost::histogram::histogram<std::vector<boost::histogram::axis::variant<Axes...>>, + Storage> +only_dynamic_histogram( + boost::histogram::histogram<std::vector<boost::histogram::axis::variant<Axes...>>, + Storage>& h) { + return h; +} + +int main() { + using namespace boost::histogram; + + auto histogram_with_static_axes = make_histogram(axis::regular<>(10, 0, 1)); + + using axis_variant = axis::variant<axis::regular<>, axis::integer<>>; + std::vector<axis_variant> axes; + axes.emplace_back(axis::regular<>(5, 0, 1)); + axes.emplace_back(axis::integer<>(0, 1)); + auto histogram_with_dynamic_axes = make_histogram(axes); + + assert(any_histogram(histogram_with_static_axes) == histogram_with_static_axes); + assert(any_histogram(histogram_with_dynamic_axes) == histogram_with_dynamic_axes); + assert(only_static_histogram(histogram_with_static_axes) == histogram_with_static_axes); + assert(only_dynamic_histogram(histogram_with_dynamic_axes) == + histogram_with_dynamic_axes); + + // does not compile: only_static_histogram(histogram_with_dynamic_axes) + // does not compile: only_dynamic_histogram(histogram_with_static_axes) +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_histogram_operators.cpp b/src/boost/libs/histogram/examples/guide_histogram_operators.cpp new file mode 100644 index 000000000..e4059edc5 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_histogram_operators.cpp @@ -0,0 +1,62 @@ +// Copyright 2015-2018 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) + +//[ guide_histogram_operators + +#include <boost/histogram.hpp> +#include <cassert> +#include <vector> + +int main() { + using namespace boost::histogram; + + // make two histograms + auto h1 = make_histogram(axis::regular<>(2, -1.0, 1.0)); + auto h2 = make_histogram(axis::regular<>(2, -1.0, 1.0)); + + h1(-0.5); // counts are: 1 0 + h2(0.5); // counts are: 0 1 + + // add them + auto h3 = h1; + h3 += h2; // counts are: 1 1 + + // adding multiple histograms at once is likely to be optimized by the compiler so that + // superfluous temporaries avoided, but no guarantees are given; use this equivalent + // code when you want to make sure: h4 = h1; h4 += h2; h4 += h3; + auto h4 = h1 + h2 + h3; // counts are: 2 2 + + assert(h4.at(0) == 2 && h4.at(1) == 2); + + // multiply by number, h4 *= 2 also works + auto h5 = h4 * 2; // counts are: 4 4 + + // divide by number; s4 /= 4 also works + auto h6 = h5 / 4; // counts are: 1 1 + + assert(h6.at(0) == 1 && h6.at(1) == 1); + assert(h6 != h5 && h5 == 4 * h6); + + // note the special effect of multiplication on weight_storage + auto h = make_histogram_with(weight_storage(), axis::regular<>(2, -1.0, 1.0)); + h(-0.5); + + // counts are: 1 0 + assert(h.at(0).value() == 1 && h.at(1).value() == 0); + + auto h_sum = h + h; + auto h_mul = 2 * h; + + // values are the same as expected... + assert(h_sum.at(0).value() == h_mul.at(0).value()); + // ... but variances differ + assert(h_sum.at(0).variance() == 2 && h_mul.at(0).variance() == 4); + + // equality operator checks variances, so histograms are not equal + assert(h_sum != h_mul); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_histogram_projection.cpp b/src/boost/libs/histogram/examples/guide_histogram_projection.cpp new file mode 100644 index 000000000..54f452125 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_histogram_projection.cpp @@ -0,0 +1,58 @@ +// Copyright 2015-2018 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) + +//[ guide_histogram_projection + +#include <boost/histogram.hpp> +#include <cassert> +#include <iostream> +#include <sstream> + +int main() { + using namespace boost::histogram; + using namespace literals; // enables _c suffix + + // make a 2d histogram + auto h = make_histogram(axis::regular<>(3, -1.0, 1.0), axis::integer<>(0, 2)); + + h(-0.9, 0); + h(0.9, 1); + h(0.1, 0); + + auto hr0 = algorithm::project(h, 0_c); // keep only first axis + auto hr1 = algorithm::project(h, 1_c); // keep only second axis + + // reduce does not remove counts; returned histograms are summed over + // the removed axes, so h, hr0, and hr1 have same number of total counts; + // we compute the sum of counts with the sum algorithm + assert(algorithm::sum(h) == 3 && algorithm::sum(hr0) == 3 && algorithm::sum(hr1) == 3); + + std::ostringstream os1; + for (auto&& x : indexed(h)) + os1 << "(" << x.index(0) << ", " << x.index(1) << "): " << *x << "\n"; + std::cout << os1.str() << std::flush; + assert(os1.str() == "(0, 0): 1\n" + "(1, 0): 1\n" + "(2, 0): 0\n" + "(0, 1): 0\n" + "(1, 1): 0\n" + "(2, 1): 1\n"); + + std::ostringstream os2; + for (auto&& x : indexed(hr0)) os2 << "(" << x.index(0) << ", -): " << *x << "\n"; + std::cout << os2.str() << std::flush; + assert(os2.str() == "(0, -): 1\n" + "(1, -): 1\n" + "(2, -): 1\n"); + + std::ostringstream os3; + for (auto&& x : indexed(hr1)) os3 << "(- ," << x.index(0) << "): " << *x << "\n"; + std::cout << os3.str() << std::flush; + assert(os3.str() == "(- ,0): 2\n" + "(- ,1): 1\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_histogram_reduction.cpp b/src/boost/libs/histogram/examples/guide_histogram_reduction.cpp new file mode 100644 index 000000000..677625305 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_histogram_reduction.cpp @@ -0,0 +1,48 @@ +// Copyright 2015-2018 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) + +//[ guide_histogram_reduction + +#include <boost/histogram.hpp> +#include <cassert> + +int main() { + using namespace boost::histogram; + // import reduce commands into local namespace to save typing + using algorithm::rebin; + using algorithm::shrink; + using algorithm::slice; + + // make a 2d histogram + auto h = make_histogram(axis::regular<>(4, 0.0, 4.0), axis::regular<>(4, -2.0, 2.0)); + + h(0, -0.9); + h(1, 0.9); + h(2, 0.1); + h(3, 0.1); + + // reduce takes positional commands which are applied to the axes in order + // - shrink is applied to the first axis; the new axis range is 0.0 to 3.0 + // - rebin is applied to the second axis; pairs of adjacent bins are merged + auto h2 = algorithm::reduce(h, shrink(0.0, 3.0), rebin(2)); + + assert(h2.axis(0) == axis::regular<>(3, 0.0, 3.0)); + assert(h2.axis(1) == axis::regular<>(2, -2.0, 2.0)); + + // reduce does not change the total count if the histogram has underflow/overflow bins + assert(algorithm::sum(h) == 4 && algorithm::sum(h2) == 4); + + // One can also explicitly specify the index of the axis in the histogram on which the + // command should act, by using this index as the the first parameter. The position of + // the command in the argument list of reduce is then ignored. We use this to slice only + // the second axis (axis has index 1 in the histogram) from bin index 2 to 4. + auto h3 = algorithm::reduce(h, slice(1, 2, 4)); + + assert(h3.axis(0) == h.axis(0)); // unchanged + assert(h3.axis(1) == axis::regular<>(2, 0.0, 2.0)); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_histogram_serialization.cpp b/src/boost/libs/histogram/examples/guide_histogram_serialization.cpp new file mode 100644 index 000000000..c00ef3cd6 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_histogram_serialization.cpp @@ -0,0 +1,47 @@ +// Copyright 2015-2018 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) + +//[ guide_histogram_serialization + +#include <boost/archive/text_iarchive.hpp> +#include <boost/archive/text_oarchive.hpp> +#include <boost/histogram.hpp> +#include <boost/histogram/serialization.hpp> // includes serialization code +#include <cassert> +#include <sstream> + +int main() { + using namespace boost::histogram; + + auto a = make_histogram(axis::regular<>(3, -1.0, 1.0, "axis 0"), + axis::integer<>(0, 2, "axis 1")); + a(0.5, 1); + + std::string buf; // to hold persistent representation + + // store histogram + { + std::ostringstream os; + boost::archive::text_oarchive oa(os); + oa << a; + buf = os.str(); + } + + auto b = decltype(a)(); // create a default-constructed second histogram + + assert(b != a); // b is empty, a is not + + // load histogram + { + std::istringstream is(buf); + boost::archive::text_iarchive ia(is); + ia >> b; + } + + assert(b == a); // now b is equal to a +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_histogram_streaming.cpp b/src/boost/libs/histogram/examples/guide_histogram_streaming.cpp new file mode 100644 index 000000000..52bf2b9d4 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_histogram_streaming.cpp @@ -0,0 +1,58 @@ +// Copyright 2015-2018 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) + +//[ guide_histogram_streaming + +#include <boost/histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <cassert> +#include <iostream> +#include <sstream> +#include <string> + +int main() { + using namespace boost::histogram; + + std::ostringstream os; + + auto h1 = make_histogram(axis::regular<>(5, -1.0, 1.0, "axis 1")); + h1.at(0) = 2; + h1.at(1) = 4; + h1.at(2) = 3; + h1.at(4) = 1; + + // 1D histograms are rendered as an ASCII drawing + os << h1; + + auto h2 = make_histogram(axis::regular<>(2, -1.0, 1.0, "axis 1"), + axis::category<std::string>({"red", "blue"}, "axis 2")); + + // higher dimensional histograms just have their cell counts listed + os << h2; + + std::cout << os.str() << std::endl; + + assert( + os.str() == + "histogram(regular(5, -1, 1, metadata=\"axis 1\", options=underflow | overflow))\n" + " +-------------------------------------------------------------+\n" + "[-inf, -1) 0 | |\n" + "[ -1, -0.6) 2 |============================== |\n" + "[-0.6, -0.2) 4 |============================================================ |\n" + "[-0.2, 0.2) 3 |============================================= |\n" + "[ 0.2, 0.6) 0 | |\n" + "[ 0.6, 1) 1 |=============== |\n" + "[ 1, inf) 0 | |\n" + " +-------------------------------------------------------------+\n" + "histogram(\n" + " regular(2, -1, 1, metadata=\"axis 1\", options=underflow | overflow)\n" + " category(\"red\", \"blue\", metadata=\"axis 2\", options=overflow)\n" + " (-1 0): 0 ( 0 0): 0 ( 1 0): 0 ( 2 0): 0 (-1 1): 0 ( 0 1): 0\n" + " ( 1 1): 0 ( 2 1): 0 (-1 2): 0 ( 0 2): 0 ( 1 2): 0 ( 2 2): 0\n" + ")"); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_indexed_access.cpp b/src/boost/libs/histogram/examples/guide_indexed_access.cpp new file mode 100644 index 000000000..5850c1d3c --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_indexed_access.cpp @@ -0,0 +1,78 @@ +// Copyright 2015-2018 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) + +//[ guide_indexed_access + +#include <boost/format.hpp> +#include <boost/histogram.hpp> +#include <cassert> +#include <iostream> +#include <numeric> // for std::accumulate +#include <sstream> + +using namespace boost::histogram; + +int main() { + // make histogram with 2 x 2 = 4 bins (not counting under-/overflow bins) + auto h = make_histogram(axis::regular<>(2, -1.0, 1.0), axis::regular<>(2, 2.0, 4.0)); + + h(weight(1), -0.5, 2.5); // bin index 0, 0 + h(weight(2), -0.5, 3.5); // bin index 0, 1 + h(weight(3), 0.5, 2.5); // bin index 1, 0 + h(weight(4), 0.5, 3.5); // bin index 1, 1 + + // use the `indexed` range adaptor to iterate over all bins; + // it is not only more convenient but also faster than a hand-crafted loop! + std::ostringstream os; + for (auto&& x : indexed(h)) { + // x is a special accessor object + const auto i = x.index(0); // current index along first axis + const auto j = x.index(1); // current index along second axis + const auto b0 = x.bin(0); // current bin interval along first axis + const auto b1 = x.bin(1); // current bin interval along second axis + const auto v = *x; // "dereference" to get the bin value + os << boost::format("%i %i [%2i, %i) [%2i, %i): %i\n") % i % j % b0.lower() % + b0.upper() % b1.lower() % b1.upper() % v; + } + + std::cout << os.str() << std::flush; + + assert(os.str() == "0 0 [-1, 0) [ 2, 3): 1\n" + "1 0 [ 0, 1) [ 2, 3): 3\n" + "0 1 [-1, 0) [ 3, 4): 2\n" + "1 1 [ 0, 1) [ 3, 4): 4\n"); + + // `indexed` skips underflow and overflow bins by default, but can be called + // with the second argument `coverage::all` to walk over all bins + std::ostringstream os2; + for (auto&& x : indexed(h, coverage::all)) { + os2 << boost::format("%2i %2i: %i\n") % x.index(0) % x.index(1) % *x; + } + + std::cout << os2.str() << std::flush; + + assert(os2.str() == "-1 -1: 0\n" + " 0 -1: 0\n" + " 1 -1: 0\n" + " 2 -1: 0\n" + + "-1 0: 0\n" + " 0 0: 1\n" + " 1 0: 3\n" + " 2 0: 0\n" + + "-1 1: 0\n" + " 0 1: 2\n" + " 1 1: 4\n" + " 2 1: 0\n" + + "-1 2: 0\n" + " 0 2: 0\n" + " 1 2: 0\n" + " 2 2: 0\n"); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_make_dynamic_histogram.cpp b/src/boost/libs/histogram/examples/guide_make_dynamic_histogram.cpp new file mode 100644 index 000000000..80ab025ee --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_make_dynamic_histogram.cpp @@ -0,0 +1,47 @@ +// Copyright 2015-2018 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) + +//[ guide_make_dynamic_histogram + +#include <boost/histogram.hpp> +#include <cassert> +#include <sstream> +#include <vector> + +const char* config = "4 1.0 2.0\n" + "5 3.0 4.0\n"; + +int main() { + using namespace boost::histogram; + + // read axis config from a config file (mocked here with std::istringstream) + // and create vector of regular axes, the number of axis is not known at compile-time + std::istringstream is(config); + auto v1 = std::vector<axis::regular<>>(); + while (is.good()) { + unsigned bins; + double start, stop; + is >> bins >> start >> stop; + v1.emplace_back(bins, start, stop); + } + + // create histogram from iterator range + // (copying or moving the vector also works, move is shown below) + auto h1 = make_histogram(v1.begin(), v1.end()); + assert(h1.rank() == v1.size()); + + // with a vector of axis::variant (polymorphic axis type that can hold any one of the + // template arguments at a time) the types and number of axis can vary at run-time + auto v2 = std::vector<axis::variant<axis::regular<>, axis::integer<>>>(); + v2.emplace_back(axis::regular<>(100, -1.0, 1.0)); + v2.emplace_back(axis::integer<>(1, 7)); + + // create dynamic histogram by moving the vector + auto h2 = make_histogram(std::move(v2)); + assert(h2.rank() == 2); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_make_static_histogram.cpp b/src/boost/libs/histogram/examples/guide_make_static_histogram.cpp new file mode 100644 index 000000000..55eb4b689 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_make_static_histogram.cpp @@ -0,0 +1,23 @@ +// Copyright 2015-2018 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) + +//[ guide_make_static_histogram + +#include <boost/histogram.hpp> +#include <cassert> + +int main() { + using namespace boost::histogram; + + // create a 1d-histogram in default configuration which + // covers the real line from -1 to 1 in 100 bins + auto h = make_histogram(axis::regular<>(100, -1.0, 1.0)); + + // rank is the number of axes + assert(h.rank() == 1); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_parallel_filling.cpp b/src/boost/libs/histogram/examples/guide_parallel_filling.cpp new file mode 100644 index 000000000..f4a23c9c7 --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_parallel_filling.cpp @@ -0,0 +1,50 @@ +// Copyright 2018-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) + +//[ guide_parallel_filling + +#include <boost/histogram.hpp> +#include <boost/histogram/algorithm/sum.hpp> +#include <cassert> +#include <functional> +#include <thread> +#include <vector> + +// dummy fill function, to be executed in parallel by several threads +template <typename Histogram> +void fill(Histogram& h) { + for (unsigned i = 0; i < 1000; ++i) { h(i % 10); } +} + +int main() { + using namespace boost::histogram; + + /* + Create histogram with container of thread-safe counters for parallel filling in + several threads. Only filling is thread-safe, other guarantees are not given. + */ + auto h = make_histogram_with(dense_storage<accumulators::thread_safe<unsigned>>(), + axis::integer<>(0, 10)); + + /* + Run the fill function in parallel from different threads. This is safe when a + thread-safe accumulator and a storage with thread-safe cell access are used. + */ + auto fill_h = [&h]() { fill(h); }; + std::thread t1(fill_h); + std::thread t2(fill_h); + std::thread t3(fill_h); + std::thread t4(fill_h); + t1.join(); + t2.join(); + t3.join(); + t4.join(); + + // Without a thread-safe accumulator, this number may be smaller. + assert(algorithm::sum(h) == 4000); +} + +//] diff --git a/src/boost/libs/histogram/examples/guide_stdlib_algorithms.cpp b/src/boost/libs/histogram/examples/guide_stdlib_algorithms.cpp new file mode 100644 index 000000000..52581787d --- /dev/null +++ b/src/boost/libs/histogram/examples/guide_stdlib_algorithms.cpp @@ -0,0 +1,67 @@ +// Copyright 2018 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) + +//[ guide_stdlib_algorithms + +#include <boost/histogram.hpp> +#include <cassert> + +#include <algorithm> // fill, any_of, min_element, max_element +#include <cmath> // sqrt +#include <numeric> // partial_sum, inner_product + +int main() { + using namespace boost::histogram; + + // make histogram that represents a probability density function (PDF) + auto h1 = make_histogram(axis::regular<>(4, 1.0, 3.0)); + + // make indexed range to skip underflow and overflow cells + auto ind = indexed(h1); + + // use std::fill to set all counters to 0.25 (except under- and overflow counters) + std::fill(ind.begin(), ind.end(), 0.25); + + // compute the cumulative density function (CDF), overriding cell values + std::partial_sum(ind.begin(), ind.end(), ind.begin()); + + assert(h1.at(-1) == 0.00); + assert(h1.at(0) == 0.25); + assert(h1.at(1) == 0.50); + assert(h1.at(2) == 0.75); + assert(h1.at(3) == 1.00); + assert(h1.at(4) == 0.00); + + // use any_of to check if any cell values are smaller than 0.1, + auto b = std::any_of(ind.begin(), ind.end(), [](const auto& x) { return x < 0.1; }); + assert(b == false); // under- and overflow cells are zero, but skipped + + // find minimum element + auto min_it = std::min_element(ind.begin(), ind.end()); + assert(*min_it == 0.25); // under- and overflow cells are skipped + + // find maximum element + auto max_it = std::max_element(ind.begin(), ind.end()); + assert(*max_it == 1.0); + + // make second PDF + auto h2 = make_histogram(axis::regular<>(4, 1.0, 4.0)); + h2.at(0) = 0.1; + h2.at(1) = 0.3; + h2.at(2) = 0.2; + h2.at(3) = 0.4; + + // computing cosine similiarity: cos(theta) = A dot B / sqrt((A dot A) * (B dot B)) + auto ind2 = indexed(h2); + const auto aa = std::inner_product(ind.begin(), ind.end(), ind.begin(), 0.0); + const auto bb = std::inner_product(ind2.begin(), ind2.end(), ind2.begin(), 0.0); + const auto ab = std::inner_product(ind.begin(), ind.end(), ind2.begin(), 0.0); + const auto cos_sim = ab / std::sqrt(aa * bb); + + assert(std::abs(cos_sim - 0.967) < 1e-2); +} + +//] |