#include <boost/assert.hpp>
#include <boost/histogram/axis/traits.hpp>
#include <boost/histogram/detail/axes.hpp>
-#include <boost/histogram/detail/cat.hpp>
#include <boost/histogram/detail/make_default.hpp>
#include <boost/histogram/detail/static_if.hpp>
-#include <boost/histogram/detail/type_name.hpp>
#include <boost/histogram/fwd.hpp>
#include <boost/histogram/indexed.hpp>
#include <boost/histogram/unsafe_access.hpp>
#include <cmath>
#include <initializer_list>
#include <stdexcept>
+#include <string>
namespace boost {
namespace histogram {
/**
Shrink option to be used in reduce().
+ The shrink is inclusive. The bin which contains the first value starts the range of bins
+ to keep. The bin which contains the second value is the last included in that range.
+ When the second value is exactly equal to a lower bin edge, then the previous bin is
+ the last in the range.
+
@param iaxis which axis to operate on.
- @param lower lowest bound that should be kept.
- @param upper highest bound that should be kept. If upper is inside bin interval, the
- whole interval is removed.
+ @param lower bin which contains lower is first to be kept.
+ @param upper bin which contains upper is last to be kept, except if upper is equal to
+ the lower edge.
*/
inline reduce_option shrink(unsigned iaxis, double lower, double upper) {
return shrink_and_rebin(iaxis, lower, upper, 1);
}
/**
- Shrink and rebin option to be used in reduce() (onvenience overload for
+ Shrink and rebin option to be used in reduce() (convenience overload for
single axis).
@param lower lowest bound that should be kept.
o_out.begin = o_in.begin;
o_out.end = o_in.end;
}
- o_out.merge = std::max(o_in.merge, o_out.merge);
+ o_out.merge = (std::max)(o_in.merge, o_out.merge);
}
// make new axes container with default-constructed axis instances
detail::static_if_c<axis::traits::is_reducible<A>::value>(
[&o](auto&& aout, const auto& ain) {
using A = std::decay_t<decltype(ain)>;
- if (o.indices_set) {
- o.begin = std::max(0, o.begin);
- o.end = std::min(o.end, ain.size());
- } else {
+ if (!o.indices_set && !o.values_set) {
o.begin = 0;
o.end = ain.size();
+ } else {
if (o.values_set) {
- if (o.lower < o.upper) {
- while (o.begin != o.end && ain.value(o.begin) < o.lower) ++o.begin;
- while (o.end != o.begin && ain.value(o.end - 1) >= o.upper) --o.end;
- } else if (o.lower > o.upper) {
- // for inverted axis::regular
- while (o.begin != o.end && ain.value(o.begin) > o.lower) ++o.begin;
- while (o.end != o.begin && ain.value(o.end - 1) <= o.upper) --o.end;
- }
+ o.begin = axis::traits::index(ain, o.lower);
+ o.end = axis::traits::index(ain, o.upper);
+ if (axis::traits::value_as<double>(ain, o.end) != o.upper) ++o.end;
}
+ o.begin = (std::max)(0, o.begin);
+ o.end = (std::min)(o.end, ain.size());
}
o.end -= (o.end - o.begin) % o.merge;
aout = A(ain, o.begin, o.end, o.merge);
},
- [](auto&&, const auto& ain) {
- using A = std::decay_t<decltype(ain)>;
- BOOST_THROW_EXCEPTION(std::invalid_argument(
- detail::cat(detail::type_name<A>(), " is not reducible")));
+ [iaxis](auto&&, const auto&) {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("axis " + std::to_string(iaxis) +
+ " is not reducible"));
},
axis::get<A>(detail::axis_get(axes, iaxis)), a);
} else {