From c59fa052e1b7cca5ba26546e7c97778556fedfff Mon Sep 17 00:00:00 2001 From: Hans Dembinski Date: Wed, 3 May 2017 00:05:19 +0200 Subject: [PATCH] fixing doc and renaming default_axes to builtin_axes --- README.md | 2 +- build/CMakeLists.txt | 15 ++++++ doc/guide.qbk | 31 ++++++------ examples/dynamic_axes.cpp | 13 +++++ examples/example_1d.cpp | 47 +++++++++++++++++++ examples/example_2d.cpp | 16 +++++++ include/boost/histogram/axis.hpp | 2 +- .../histogram/histogram_impl_dynamic.hpp | 8 ++-- src/python/histogram.cpp | 2 +- test/axis_test.cpp | 10 ++-- test/histogram_test.cpp | 4 +- test/speed_cpp.cpp | 16 +++---- 12 files changed, 129 insertions(+), 37 deletions(-) create mode 100644 examples/dynamic_axes.cpp create mode 100644 examples/example_1d.cpp create mode 100644 examples/example_2d.cpp diff --git a/README.md b/README.md index 308c0c73..d8a5c6c1 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Example 1: Fill a 1d-histogram in C++ int main(int, char**) { namespace bh = boost::histogram; - using boost::histogram::literals; // enables _c suffix + using namespace boost::histogram::literals; // enables _c suffix // create 1d-histogram with 10 equidistant bins from -1.0 to 2.0, // with axis of histogram labeled as "x" diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 05fa0668..0ff9b7cf 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -115,6 +115,21 @@ add_executable(histogram_test target_link_libraries(histogram_test ${LIBRARIES}) add_test(histogram_test histogram_test) +add_executable(example_1d + ../examples/example_1d.cpp) +target_link_libraries(example_1d ${LIBRARIES}) +add_test(example_1d example_1d) + +add_executable(example_2d + ../examples/example_2d.cpp) +target_link_libraries(example_2d ${LIBRARIES}) +add_test(example_2d example_2d) + +add_executable(dynamic_axes + ../examples/dynamic_axes.cpp) +target_link_libraries(dynamic_axes ${LIBRARIES}) +add_test(dynamic_axes dynamic_axes) + if(HAVE_PYTHON) configure_file(../test/python_suite_test.py.in python_suite_test.py) add_test(python_suite_test python_suite_test.py) diff --git a/doc/guide.qbk b/doc/guide.qbk index 166ff214..143dff03 100644 --- a/doc/guide.qbk +++ b/doc/guide.qbk @@ -4,16 +4,16 @@ Histograms are a basic tool in statistical analysis. They compactly represent a [section Create a histogram] -This library provides a class with a simple interface, which implements a general multi-dimensional histogram for multi-dimensional input values. The histogram class comes in two variants with a common interface, see the [link histogram.rationale.histogram_types rationale] for more information. If you are unsure, pick the [classref boost::histogram::histogram]. You need the [classref boost::histogram::histogram] if... +This library provides a class with a simple interface, which implements a general multi-dimensional histogram for multi-dimensional input values. The histogram class comes in two variants with a common interface, see the [link histogram.rationale.histogram_types rationale] for more information. If you are unsure, pick the [classref boost::histogram::histogram]. You need [classref boost::histogram::histogram] if... * you want to interoperate with Python, or -* you need a very flexible way to create various histogram configurations at runtime. +* you need a simple way to create various histogram configurations at runtime. To create histograms in default configuration, use the factory function [funcref boost::histogram::make_static_histogram] (or [funcref boost::histogram::make_dynamic_histogram], respectively). The default configuration makes sure that the histogram just works. It is fast, memory-efficient, and safe to use. [c++]`` -#include +#include namespace bh = boost::histogram; @@ -34,7 +34,7 @@ Check the class descriptions of [classref boost::histogram::regular_axis regular You can attach a label to any axis, which helps to remember what the axis is categorising. Example: you have census data and you want to investigate how yearly income correlates with age, you could do: [c++]`` -#include +#include namespace bh = boost::histogram; @@ -52,7 +52,7 @@ Without the labels it would be difficult to remember which axis was covering whi By default, axis objects add under- and overflow bins to the covered range. Therefore, if you create an axis with 20 bins, it will actually get 22 bins. The two extra bins are very useful and in most cases you want to have them. However, if you know for sure that the input is strictly covered by the axis, you can disable the extra bins: [c++]`` -#include +#include namespace bh = boost::histogram; @@ -72,7 +72,8 @@ Since the histogram has Python-bindings, and you can also create histograms in P import histogram as bh import complex_cpp_module -h = bh.histogram(bh.regular_axis(100, -1, 1)) +h = bh.histogram(bh.regular_axis(100, -1, 1), + bh.integer_axis(0, 10)) complex_cpp_module.process(h) # histogram is filled with input values @@ -84,21 +85,22 @@ In Python, you can straight-forwardly create a histogram object with a variable When you work with [classref boost::histogram::histogram], you can also create a histogram from a run-time compiled collection of axis objects: [c++]`` -#include +#include +#include namespace bh = boost::histogram; int main() { - using dhist = bh::histogram; + using dhist = decltype(bh::make_dynamic_histogram()); auto v = std::vector(); v.push_back(bh::regular_axis<>(100, -1, 1)); v.push_back(bh::integer_axis(1, 6)); - auto h = bh::dhist(v.begin(), v.end()); + auto h = dhist(v.begin(), v.end()); // do something with h } `` -[note In all these examples, memory for bin counters is allocated lazily, because [classref boost::histogram::adaptive_storage<>] is used. Allocation is deferred to the first call to `fill(...)`, which are described in the next section. Therefore memory allocation exceptions are not thrown when the histogram is created, but possibly later.] +[note In all these examples, memory for bin counters is allocated lazily, because the default policy [classref boost::histogram::adaptive_storage<>] is used. Allocation is deferred to the first call to `fill(...)`, which are described in the next section. Therefore memory allocation exceptions are not thrown when the histogram is created, but possibly later.] [endsect] @@ -108,20 +110,20 @@ The histogram (either type) supports two kinds of fills. * `fill(...)` initiates a normal fill, which increments a bin counter by one when a value is in the bin range -* `fill(..., weight(x))` initiates a weighted fill, which increment a bin counter by a weight `x` when a value is in the bin range. +* `fill(..., weight(x))` initiates a weighted fill, which increment a bin counter by a weight `x` (a real number) when a value is in the bin range. The need to support weighted fills is explained [link histogram.rationale.weights in the rationale]. Do not use the form `fill(..., weight(x))` if all your weights are equal to 1. Use `fill(...)` in this case, because it is way more efficient. You are free to mix the two calls, meaning, you can start calling `fill(...)` and later switch to `fill(..., weight(x))` on the same histogram or vice versa. Here is an example which fills a 2d-histogram with 1000 pairs of normal distributed numbers taken from a generator: [c++]`` -#include +#include #include #include int main() { using namespace boost; random::mt19937 gen; - random::normal_distribution<> norm(); + random::normal_distribution<> norm; auto h = histogram::make_static_histogram( histogram::regular_axis<>(100, -5, 5, "x"), histogram::regular_axis<>(100, -5, 5, "y") @@ -134,8 +136,9 @@ int main() { Here is a second example which using a weighted fill in a functional programming style. The input values are taken from a container: [c++]`` -#include +#include #include +#include int main() { namespace bh = boost::histogram; diff --git a/examples/dynamic_axes.cpp b/examples/dynamic_axes.cpp new file mode 100644 index 00000000..fe8a298f --- /dev/null +++ b/examples/dynamic_axes.cpp @@ -0,0 +1,13 @@ +#include +#include + +namespace bh = boost::histogram; + +int main() { + using dhist = decltype(bh::make_dynamic_histogram()); + auto v = std::vector(); + v.push_back(bh::regular_axis<>(100, -1, 1)); + v.push_back(bh::integer_axis(1, 6)); + auto h = dhist(v.begin(), v.end()); + // do something with h +} diff --git a/examples/example_1d.cpp b/examples/example_1d.cpp new file mode 100644 index 00000000..2ddbbe8b --- /dev/null +++ b/examples/example_1d.cpp @@ -0,0 +1,47 @@ +#include // proposed for inclusion in Boost +#include +#include + +int main(int, char**) { + namespace bh = boost::histogram; + using namespace boost::histogram::literals; // enables _c suffix + + // create 1d-histogram with 10 equidistant bins from -1.0 to 2.0, + // with axis of histogram labeled as "x" + auto h = bh::make_static_histogram(bh::regular_axis<>(10, -1.0, 2.0, "x")); + + // fill histogram with data + h.fill(-1.5); // put in underflow bin + h.fill(-1.0); // included in first bin, bin interval is semi-open + h.fill(-0.5); + h.fill(1.1); + h.fill(0.3); + h.fill(1.7); + h.fill(2.0); // put in overflow bin, bin interval is semi-open + h.fill(20.0); // put in overflow bin + h.fill(0.1, bh::weight(5)); // fill with a weighted entry, weight is 5 + + // iterate over bins, loop includes under- and overflow bin + for (const auto& bin : h.axis(0_c)) { + std::cout << "bin " << bin.idx + << " x in [" << bin.left << ", " << bin.right << "): " + << h.value(bin.idx) << " +/- " << std::sqrt(h.variance(bin.idx)) + << std::endl; + } + + /* program output: + + bin -1 x in [-inf, -1): 1 +/- 1 + bin 0 x in [-1, -0.7): 1 +/- 1 + bin 1 x in [-0.7, -0.4): 1 +/- 1 + bin 2 x in [-0.4, -0.1): 0 +/- 0 + bin 3 x in [-0.1, 0.2): 5 +/- 5 + bin 4 x in [0.2, 0.5): 1 +/- 1 + bin 5 x in [0.5, 0.8): 0 +/- 0 + bin 6 x in [0.8, 1.1): 0 +/- 0 + bin 7 x in [1.1, 1.4): 1 +/- 1 + bin 8 x in [1.4, 1.7): 0 +/- 0 + bin 9 x in [1.7, 2): 1 +/- 1 + bin 10 x in [2, inf): 2 +/- 1.41421 + */ +} diff --git a/examples/example_2d.cpp b/examples/example_2d.cpp new file mode 100644 index 00000000..b28d1e12 --- /dev/null +++ b/examples/example_2d.cpp @@ -0,0 +1,16 @@ +#include +#include +#include + +int main() { + using namespace boost; + random::mt19937 gen; + random::normal_distribution<> norm; + auto h = histogram::make_static_histogram( + histogram::regular_axis<>(100, -5, 5, "x"), + histogram::regular_axis<>(100, -5, 5, "y") + ); + for (int i = 0; i < 1000; ++i) + h.fill(norm(gen), norm(gen)); + // h is now filled +} diff --git a/include/boost/histogram/axis.hpp b/include/boost/histogram/axis.hpp index 5a799c7f..f326ac56 100644 --- a/include/boost/histogram/axis.hpp +++ b/include/boost/histogram/axis.hpp @@ -587,7 +587,7 @@ private: template void serialize(Archive &, unsigned); }; -using default_axes = mpl::vector, regular_axis, +using builtin_axes = mpl::vector, regular_axis, circular_axis, circular_axis, variable_axis, variable_axis, integer_axis, category_axis>::type; diff --git a/include/boost/histogram/histogram_impl_dynamic.hpp b/include/boost/histogram/histogram_impl_dynamic.hpp index 73895120..1b8235cf 100644 --- a/include/boost/histogram/histogram_impl_dynamic.hpp +++ b/include/boost/histogram/histogram_impl_dynamic.hpp @@ -330,21 +330,21 @@ private: template inline histogram< - Dynamic, typename detail::combine>::type> + Dynamic, typename detail::combine>::type> make_dynamic_histogram(Axes &&... axes) { return histogram>::type>( + builtin_axes, mpl::vector>::type>( std::forward(axes)...); } template inline histogram< - Dynamic, typename detail::combine>::type, + Dynamic, typename detail::combine>::type, Storage> make_dynamic_histogram_with(Axes &&... axes) { return histogram>::type, + builtin_axes, mpl::vector>::type, Storage>(std::forward(axes)...); } diff --git a/src/python/histogram.cpp b/src/python/histogram.cpp index 05303113..60663198 100644 --- a/src/python/histogram.cpp +++ b/src/python/histogram.cpp @@ -29,7 +29,7 @@ namespace boost { namespace histogram { -using dynamic_histogram = histogram>; +using dynamic_histogram = histogram>; } // namespace histogram namespace python { diff --git a/test/axis_test.cpp b/test/axis_test.cpp index 942ec052..c214177b 100644 --- a/test/axis_test.cpp +++ b/test/axis_test.cpp @@ -43,7 +43,7 @@ void test_axis_iterator(const Axis &a, int begin, int end) { int main() { using namespace boost::histogram; - using axis_t = typename boost::make_variant_over::type; + using axis_t = typename boost::make_variant_over::type; // bad_ctors { @@ -294,12 +294,10 @@ int main() { category_axis{"A", "B", "C"}}; std::vector, variable_axis<>>> std_vector3 = { - variable_axis<>{-1, 0, 1}, regular_axis<>{2, -1, 1} - }; + variable_axis<>{-1, 0, 1}, regular_axis<>{2, -1, 1}}; - std::vector,regular_axis<>>> std_vector4 = { - regular_axis<>{2, -1, 1}, variable_axis<>{-1, 0, 1} - }; + std::vector, regular_axis<>>> std_vector4 = { + regular_axis<>{2, -1, 1}, variable_axis<>{-1, 0, 1}}; BOOST_TEST(detail::axes_equal(std_vector1, std_vector2)); BOOST_TEST_NOT(detail::axes_equal(std_vector2, std_vector3)); diff --git a/test/histogram_test.cpp b/test/histogram_test.cpp index 012236f4..03ccf108 100644 --- a/test/histogram_test.cpp +++ b/test/histogram_test.cpp @@ -585,10 +585,10 @@ int main() { // init_6: special stuff that only works with Dynamic { - auto v = std::vector::axis_type>(); + auto v = std::vector::axis_type>(); v.push_back(regular_axis<>(100, -1, 1)); v.push_back(integer_axis(1, 6)); - auto h = histogram(v.begin(), v.end()); + auto h = histogram(v.begin(), v.end()); BOOST_TEST_EQ(h.axis(0_c), v[0]); BOOST_TEST_EQ(h.axis(1_c), v[1]); BOOST_TEST_EQ(h.axis(0), v[0]); diff --git a/test/speed_cpp.cpp b/test/speed_cpp.cpp index 345668d4..65d71279 100644 --- a/test/speed_cpp.cpp +++ b/test/speed_cpp.cpp @@ -116,11 +116,11 @@ int main() { compare_1d>, adaptive_storage<>>>(6000000, itype)); printf("hd_ss %.3f\n", - compare_1d>>>( 6000000, itype)); printf("hd_sd %.3f\n", - compare_1d>>( + compare_1d>>( 6000000, itype)); } @@ -139,11 +139,11 @@ int main() { mpl::vector, regular_axis<>>, adaptive_storage<>>>(6000000, itype)); printf("hd_ss %.3f\n", - compare_2d>>>( 6000000, itype)); printf("hd_sd %.3f\n", - compare_2d>>( + compare_2d>>( 6000000, itype)); } @@ -162,11 +162,11 @@ int main() { mpl::vector, regular_axis<>, regular_axis<>>, adaptive_storage<>>>(6000000, itype)); printf("hd_ss %.3f\n", - compare_3d>>>( 6000000, itype)); printf("hd_sd %.3f\n", - compare_3d>>( + compare_3d>>( 6000000, itype)); } @@ -187,11 +187,11 @@ int main() { regular_axis<>, regular_axis<>, regular_axis<>>, adaptive_storage<>>>(6000000, itype)); printf("hd_ss %.3f\n", - compare_6d>>>( 6000000, itype)); printf("hd_sd %.3f\n", - compare_6d>>( + compare_6d>>( 6000000, itype)); } }