mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-11 13:14:06 +00:00
switched to lazy interval_view to improve performance
This commit is contained in:
parent
8cb08efa7b
commit
fe4bd1701d
@ -7,10 +7,10 @@
|
||||
#ifndef _BOOST_HISTOGRAM_AXIS_ANY_HPP_
|
||||
#define _BOOST_HISTOGRAM_AXIS_ANY_HPP_
|
||||
|
||||
#include <boost/histogram/axis/interval.hpp>
|
||||
#include <boost/histogram/axis/iterator.hpp>
|
||||
#include <boost/histogram/detail/axis_visitor.hpp>
|
||||
#include <boost/histogram/detail/cat.hpp>
|
||||
#include <boost/histogram/interval.hpp>
|
||||
#include <boost/mpl/contains.hpp>
|
||||
#include <boost/utility/string_view.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
@ -54,36 +54,47 @@ struct set_label : public static_visitor<void> {
|
||||
template <typename A> void operator()(A &a) const { a.label(label); }
|
||||
};
|
||||
|
||||
template <typename T> struct index : public static_visitor<int> {
|
||||
const T &t;
|
||||
explicit index(const T &arg) : t(arg) {}
|
||||
struct index : public static_visitor<int> {
|
||||
const double x;
|
||||
explicit index(const double arg) : x(arg) {}
|
||||
template <typename Axis> int operator()(const Axis &a) const {
|
||||
return impl(std::is_convertible<T, typename Axis::value_type>(), a);
|
||||
return impl(std::is_convertible<double, typename Axis::value_type>(), a);
|
||||
}
|
||||
template <typename Axis> int impl(std::true_type, const Axis &a) const {
|
||||
return a.index(t);
|
||||
return a.index(x);
|
||||
}
|
||||
template <typename Axis> int impl(std::false_type, const Axis &) const {
|
||||
throw std::runtime_error(::boost::histogram::detail::cat(
|
||||
"fill argument not convertible to axis value type: ",
|
||||
boost::typeindex::type_id<Axis>().pretty_name(), ", ",
|
||||
boost::typeindex::type_id<T>().pretty_name()));
|
||||
"cannot convert value_type ",
|
||||
boost::typeindex::type_id<typename Axis::value_type>().pretty_name(),
|
||||
" of ",
|
||||
boost::typeindex::type_id<Axis>().pretty_name(),
|
||||
" to double")
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct bin : public static_visitor<axis::interval<double>> {
|
||||
using double_interval = axis::interval<double>;
|
||||
const int i;
|
||||
bin(const int v) : i(v) {}
|
||||
template <typename A> double_interval operator()(const A &a) const {
|
||||
return impl(is_convertible<typename A::bin_type, double_interval>(),
|
||||
std::forward<typename A::bin_type>(a[i]));
|
||||
struct eval : public static_visitor<std::function<double(int)>> {
|
||||
template <typename Axis> std::function<double(int)> operator()(const Axis &a) const {
|
||||
return impl(std::integral_constant<bool,
|
||||
(std::is_convertible<typename Axis::value_type, double>::value &&
|
||||
std::is_same<
|
||||
typename Axis::bin_type,
|
||||
interval_view<typename Axis::value_type>
|
||||
>::value)
|
||||
>(), a);
|
||||
}
|
||||
template <typename B> double_interval impl(true_type, B &&b) const {
|
||||
return b;
|
||||
template <typename Axis> std::function<double(int)> impl(std::true_type, const Axis &a) const {
|
||||
return [&a](int i) -> double { return a[i].lower(); } ;
|
||||
}
|
||||
template <typename B> double_interval impl(false_type, B &&) const {
|
||||
throw std::runtime_error("cannot convert bin_type to interval<double>");
|
||||
template <typename Axis> std::function<double(int)> impl(std::false_type, const Axis &) const {
|
||||
throw std::runtime_error(::boost::histogram::detail::cat(
|
||||
"cannot convert bin_type ",
|
||||
boost::typeindex::type_id<typename Axis::bin_type>().pretty_name(),
|
||||
" of ",
|
||||
boost::typeindex::type_id<Axis>().pretty_name(),
|
||||
" to interval_view<double>")
|
||||
);
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
@ -95,7 +106,7 @@ template <typename Axes> class any : public make_variant_over<Axes>::type {
|
||||
public:
|
||||
using types = typename base_type::types;
|
||||
using value_type = double;
|
||||
using bin_type = interval<double>;
|
||||
using bin_type = interval_view<double>;
|
||||
using const_iterator = iterator_over<any>;
|
||||
using const_reverse_iterator = reverse_iterator_over<any>;
|
||||
|
||||
@ -112,15 +123,15 @@ public:
|
||||
template <typename T, typename = typename std::enable_if<
|
||||
mpl::contains<types, T>::value>::type>
|
||||
any &operator=(const T &t) {
|
||||
// ugly workaround for compiler bug
|
||||
return reinterpret_cast<any &>(base_type::operator=(t));
|
||||
base_type::operator=(t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<
|
||||
mpl::contains<types, T>::value>::type>
|
||||
any &operator=(T &&t) {
|
||||
// ugly workaround for compiler bug
|
||||
return reinterpret_cast<any &>(base_type::operator=(std::move(t)));
|
||||
base_type::operator=(std::move(t));
|
||||
return *this;
|
||||
}
|
||||
|
||||
int size() const { return apply_visitor(detail::size(), *this); }
|
||||
@ -131,7 +142,7 @@ public:
|
||||
|
||||
// note: this only works for axes with compatible value type
|
||||
int index(const value_type x) const {
|
||||
return apply_visitor(detail::index<value_type>(x), *this);
|
||||
return apply_visitor(detail::index(x), *this);
|
||||
}
|
||||
|
||||
string_view label() const {
|
||||
@ -143,9 +154,10 @@ public:
|
||||
}
|
||||
|
||||
// this only works for axes with compatible bin type
|
||||
// and will raise an error otherwise
|
||||
// and will throw a runtime_error otherwise
|
||||
bin_type operator[](const int i) const {
|
||||
return apply_visitor(detail::bin(i), *this);
|
||||
auto eval = apply_visitor(detail::eval(), *this);
|
||||
return bin_type(i, eval);
|
||||
}
|
||||
|
||||
bool operator==(const any &rhs) const {
|
||||
|
@ -9,9 +9,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/bimap.hpp>
|
||||
#include <boost/histogram/axis/interval.hpp>
|
||||
#include <boost/histogram/axis/iterator.hpp>
|
||||
#include <boost/histogram/detail/meta.hpp>
|
||||
#include <boost/histogram/interval.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <boost/utility/string_view.hpp>
|
||||
#include <cmath>
|
||||
@ -36,7 +36,7 @@ namespace axis {
|
||||
|
||||
enum class uoflow { off = false, on = true };
|
||||
|
||||
/// Base class for all axes, uses CRTP.
|
||||
/// Base class for all axes, uses CRTP to inject iterator logic.
|
||||
template <typename Derived> class axis_base {
|
||||
public:
|
||||
using const_iterator = iterator_over<Derived>;
|
||||
@ -102,7 +102,7 @@ private:
|
||||
template <class Archive> void serialize(Archive &, unsigned);
|
||||
};
|
||||
|
||||
/// Base class for axes with overflow/underflow bins, uses CRTP.
|
||||
/// Base class for axes with optional under-/overflow bins, uses CRTP.
|
||||
template <typename Derived> class axis_base_uoflow : public axis_base<Derived> {
|
||||
using base_type = axis_base<Derived>;
|
||||
|
||||
@ -114,7 +114,7 @@ public:
|
||||
|
||||
protected:
|
||||
axis_base_uoflow(unsigned n, string_view label, enum uoflow uo)
|
||||
: base_type(n, label), shape_(n + 2u * static_cast<unsigned>(uo)) {}
|
||||
: base_type(n, label), shape_(n + 2 * static_cast<int>(uo)) {}
|
||||
|
||||
axis_base_uoflow() = default;
|
||||
axis_base_uoflow(const axis_base_uoflow &) = default;
|
||||
@ -202,7 +202,7 @@ class regular : public axis_base_uoflow<regular<RealType, Transform>>,
|
||||
|
||||
public:
|
||||
using value_type = RealType;
|
||||
using bin_type = interval<value_type>;
|
||||
using bin_type = interval_view<value_type>;
|
||||
|
||||
/** Construct axis with n bins over real range [lower, upper).
|
||||
*
|
||||
@ -241,9 +241,9 @@ public:
|
||||
: -1;
|
||||
}
|
||||
|
||||
/// Returns the starting edge of the bin.
|
||||
/// Returns the bin interval.
|
||||
bin_type operator[](int idx) const noexcept {
|
||||
auto eval = [this](int i) {
|
||||
return bin_type(idx, [this](int i) {
|
||||
const auto n = base_type::size();
|
||||
if (i < 0)
|
||||
return this->inverse(-std::numeric_limits<value_type>::infinity());
|
||||
@ -251,8 +251,7 @@ public:
|
||||
return this->inverse(std::numeric_limits<value_type>::infinity());
|
||||
const auto z = value_type(i) / n;
|
||||
return this->inverse((1.0 - z) * min_ + z * (min_ + delta_ * n));
|
||||
};
|
||||
return {eval(idx), eval(idx + 1)};
|
||||
});
|
||||
}
|
||||
|
||||
bool operator==(const regular &o) const noexcept {
|
||||
@ -260,6 +259,7 @@ public:
|
||||
min_ == o.min_ && delta_ == o.delta_;
|
||||
}
|
||||
|
||||
/// Access properties of the transform.
|
||||
const Transform &transform() const noexcept {
|
||||
return static_cast<const Transform &>(*this);
|
||||
}
|
||||
@ -283,7 +283,7 @@ class circular : public axis_base<circular<RealType>> {
|
||||
|
||||
public:
|
||||
using value_type = RealType;
|
||||
using bin_type = interval<value_type>;
|
||||
using bin_type = interval_view<value_type>;
|
||||
|
||||
/** Constructor for n bins with an optional offset.
|
||||
*
|
||||
@ -313,11 +313,10 @@ public:
|
||||
|
||||
/// Returns the starting edge of the bin.
|
||||
bin_type operator[](int idx) const {
|
||||
auto eval = [this](int i) {
|
||||
return bin_type(idx, [this](int i) {
|
||||
const value_type z = value_type(i) / base_type::size();
|
||||
return z * perimeter_ + phase_;
|
||||
};
|
||||
return {eval(idx), eval(idx + 1)};
|
||||
});
|
||||
}
|
||||
|
||||
bool operator==(const circular &o) const noexcept {
|
||||
@ -346,7 +345,7 @@ class variable : public axis_base_uoflow<variable<RealType>> {
|
||||
|
||||
public:
|
||||
using value_type = RealType;
|
||||
using bin_type = interval<value_type>;
|
||||
using bin_type = interval_view<value_type>;
|
||||
|
||||
/** Construct an axis from bin edges.
|
||||
*
|
||||
@ -397,7 +396,7 @@ public:
|
||||
|
||||
/// Returns the starting edge of the bin.
|
||||
bin_type operator[](int idx) const {
|
||||
auto eval = [this](int i) {
|
||||
return bin_type(idx, [this](int i) {
|
||||
if (i < 0) {
|
||||
return -std::numeric_limits<value_type>::infinity();
|
||||
}
|
||||
@ -405,8 +404,7 @@ public:
|
||||
return std::numeric_limits<value_type>::infinity();
|
||||
}
|
||||
return x_[i];
|
||||
};
|
||||
return {eval(idx), eval(idx + 1)};
|
||||
});
|
||||
}
|
||||
|
||||
bool operator==(const variable &o) const noexcept {
|
||||
@ -434,7 +432,7 @@ class integer : public axis_base_uoflow<integer<IntType>> {
|
||||
|
||||
public:
|
||||
using value_type = IntType;
|
||||
using bin_type = interval<value_type>;
|
||||
using bin_type = interval_view<value_type>;
|
||||
|
||||
/** Construct axis over a semi-open integer interval [lower, upper).
|
||||
*
|
||||
@ -465,7 +463,7 @@ public:
|
||||
|
||||
/// Returns the integer that is mapped to the bin index.
|
||||
bin_type operator[](int idx) const {
|
||||
auto eval = [this](int i) {
|
||||
return bin_type(idx, [this](int i) {
|
||||
if (i < 0) {
|
||||
return -std::numeric_limits<value_type>::max();
|
||||
}
|
||||
@ -473,8 +471,7 @@ public:
|
||||
return std::numeric_limits<value_type>::max();
|
||||
}
|
||||
return min_ + i;
|
||||
};
|
||||
return {eval(idx), eval(idx + 1)};
|
||||
});
|
||||
}
|
||||
|
||||
bool operator==(const integer &o) const noexcept {
|
||||
|
46
include/boost/histogram/axis/interval.hpp
Normal file
46
include/boost/histogram/axis/interval.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2015-2017 Hans Dembinski
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef _BOOST_HISTOGRAM_AXIS_INTERVAL_HPP_
|
||||
#define _BOOST_HISTOGRAM_AXIS_INTERVAL_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace axis {
|
||||
|
||||
template <typename T> class interval_view {
|
||||
public:
|
||||
interval_view(int idx, std::function<T(int)> eval) : idx_(idx), eval_(eval) {}
|
||||
|
||||
interval_view(const interval_view &) = default;
|
||||
interval_view &operator=(const interval_view &) = default;
|
||||
interval_view(interval_view &&) = default;
|
||||
interval_view &operator=(interval_view &&) = default;
|
||||
|
||||
T lower() const noexcept { return eval_(idx_); }
|
||||
T upper() const noexcept { return eval_(idx_ + 1); }
|
||||
T width() const noexcept { return upper() - lower(); }
|
||||
|
||||
bool operator==(const interval_view &rhs) const noexcept {
|
||||
return lower() == rhs.lower() && upper() == rhs.upper();
|
||||
}
|
||||
bool operator!=(const interval_view &rhs) const noexcept {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
const int idx_;
|
||||
const std::function<T(int)> eval_;
|
||||
};
|
||||
|
||||
} // namespace axis
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
@ -10,8 +10,8 @@
|
||||
#define _BOOST_HISTOGRAM_AXIS_OSTREAM_OPERATORS_HPP_
|
||||
|
||||
#include <boost/histogram/axis/axis.hpp>
|
||||
#include <boost/histogram/axis/interval.hpp>
|
||||
#include <boost/histogram/detail/utility.hpp>
|
||||
#include <boost/histogram/interval.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <ostream>
|
||||
|
||||
@ -26,6 +26,12 @@ inline string_view to_string(const transform::sqrt &) { return {"_sqrt", 5}; }
|
||||
inline string_view to_string(const transform::cos &) { return {"_cos", 4}; }
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
inline std::ostream &operator<<(std::ostream &os, const interval_view<T> &i) {
|
||||
os << "[" << i.lower() << ", " << i.upper() << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename RealType, typename Transform>
|
||||
inline std::ostream &operator<<(std::ostream &os,
|
||||
const regular<RealType, Transform> &a) {
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <boost/fusion/include/is_sequence.hpp>
|
||||
#include <boost/fusion/include/size.hpp>
|
||||
#include <boost/fusion/support/is_sequence.hpp>
|
||||
#include <boost/histogram/interval.hpp>
|
||||
#include <boost/histogram/axis/interval.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/mpl/contains.hpp>
|
||||
#include <boost/variant/get.hpp>
|
||||
|
@ -1,46 +0,0 @@
|
||||
// Copyright 2015-2017 Hans Dembinski
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef _BOOST_HISTOGRAM_INTERVAL_HPP_
|
||||
#define _BOOST_HISTOGRAM_INTERVAL_HPP_
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace axis {
|
||||
|
||||
template <typename T> class interval {
|
||||
public:
|
||||
interval() = default;
|
||||
interval(const interval &) = default;
|
||||
interval &operator=(const interval &) = default;
|
||||
interval(interval &&) = default;
|
||||
interval &operator=(interval &&) = default;
|
||||
|
||||
interval(const T &x, const T &y) : a(x), b(y) {}
|
||||
interval(T &&x, T &&y) : a(std::move(x)), b(std::move(y)) {}
|
||||
|
||||
template <typename U>
|
||||
interval(const interval<U> &i) : a(i.lower()), b(i.upper()) {}
|
||||
|
||||
const T &lower() const noexcept { return a; }
|
||||
const T &upper() const noexcept { return b; }
|
||||
|
||||
bool operator==(const interval &i) const noexcept {
|
||||
return a == i.a && b == i.b;
|
||||
}
|
||||
bool operator!=(const interval &i) const noexcept { return !operator==(i); }
|
||||
|
||||
private:
|
||||
T a, b;
|
||||
};
|
||||
|
||||
} // namespace axis
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
@ -55,25 +55,14 @@ generic_iterator make_generic_iterator(bp::object self) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct axis_interval_to_python
|
||||
struct axis_interval_view_to_python
|
||||
{
|
||||
static PyObject* convert(const bha::interval<T> &i)
|
||||
static PyObject* convert(const bha::interval_view<T> &i)
|
||||
{
|
||||
return bp::incref(bp::make_tuple(i.lower(), i.upper()).ptr());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct pair_int_axis_interval_to_python
|
||||
{
|
||||
static PyObject* convert(const std::pair<int, bha::interval<T>> &p)
|
||||
{
|
||||
return bp::incref(bp::make_tuple(
|
||||
p.first, bp::make_tuple(p.second.lower(), p.second.upper())
|
||||
).ptr());
|
||||
}
|
||||
};
|
||||
|
||||
bp::object variable_init(bp::tuple args, bp::dict kwargs) {
|
||||
bp::object self = args[0];
|
||||
|
||||
@ -263,23 +252,13 @@ void register_axis_types() {
|
||||
docstring_options dopt(true, true, false);
|
||||
|
||||
to_python_converter<
|
||||
bha::interval<int>,
|
||||
axis_interval_to_python<int>
|
||||
bha::interval_view<int>,
|
||||
axis_interval_view_to_python<int>
|
||||
>();
|
||||
|
||||
to_python_converter<
|
||||
bha::interval<double>,
|
||||
axis_interval_to_python<double>
|
||||
>();
|
||||
|
||||
to_python_converter<
|
||||
std::pair<int, bha::interval<int>>,
|
||||
pair_int_axis_interval_to_python<int>
|
||||
>();
|
||||
|
||||
to_python_converter<
|
||||
std::pair<int, bha::interval<double>>,
|
||||
pair_int_axis_interval_to_python<double>
|
||||
bha::interval_view<double>,
|
||||
axis_interval_view_to_python<double>
|
||||
>();
|
||||
|
||||
class_<generic_iterator>("generic_iterator", init<object>())
|
||||
|
@ -23,18 +23,6 @@
|
||||
#define BOOST_TEST_NOT(expr) BOOST_TEST(!(expr))
|
||||
#define BOOST_TEST_IS_CLOSE(a, b, eps) BOOST_TEST(std::abs(a - b) < eps)
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace axis {
|
||||
template <typename T>
|
||||
std::ostream &operator<<(std::ostream &os, const interval<T> &i) {
|
||||
os << "[" << i.lower() << ", " << i.upper() << ")";
|
||||
return os;
|
||||
}
|
||||
} // namespace axis
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
template <typename Axis>
|
||||
void test_axis_iterator(const Axis &a, int begin, int end) {
|
||||
auto it = a.begin();
|
||||
@ -239,6 +227,7 @@ int main() {
|
||||
test_axis_iterator(axis::integer<>(0, 4, ""), 0, 4);
|
||||
test_axis_iterator(axis::category<>({A, B, C}, ""), 0, 3);
|
||||
test_axis_iterator(any_axis_type(axis::regular<>(5, 0, 1)), 0, 5);
|
||||
BOOST_TEST_THROWS(any_axis_type(axis::category<>({A, B, C}))[0], std::runtime_error);
|
||||
}
|
||||
|
||||
// any_axis_type_copyable
|
||||
|
@ -882,8 +882,7 @@ int main() {
|
||||
{
|
||||
enum { A, B };
|
||||
auto c = make_dynamic_histogram(axis::category<>({A, B}));
|
||||
BOOST_TEST_THROWS(c.axis()[0].lower(), std::runtime_error);
|
||||
BOOST_TEST_THROWS(c.axis()[0].upper(), std::runtime_error);
|
||||
BOOST_TEST_THROWS(c.axis()[0], std::runtime_error);
|
||||
}
|
||||
|
||||
// reduce
|
||||
|
Loading…
x
Reference in New Issue
Block a user