Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / histogram / algorithm / reduce.hpp
index ba71cb7..a9d6c02 100644 (file)
 #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>
@@ -21,6 +19,7 @@
 #include <cmath>
 #include <initializer_list>
 #include <stdexcept>
+#include <string>
 
 namespace boost {
 namespace histogram {
@@ -81,10 +80,15 @@ inline reduce_option slice_and_rebin(unsigned iaxis, axis::index_type begin,
 /**
   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);
@@ -113,7 +117,7 @@ inline reduce_option rebin(unsigned iaxis, unsigned merge) {
 }
 
 /**
-  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.
@@ -206,7 +210,7 @@ decltype(auto) reduce(const Histogram& hist, const Iterable& options) {
       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
@@ -230,30 +234,24 @@ decltype(auto) reduce(const Histogram& hist, const Iterable& options) {
       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 {