23concept ReductionAxis = std::integral<std::remove_cvref_t<T>> && (!std::same_as<std::remove_cvref_t<T>,
bool>);
29template <std::
size_t InputRank, std::
size_t ReducedRank>
struct ReductionAxes
31 static_assert(ReducedRank <= InputRank);
35 static constexpr std::size_t
output_rank = InputRank - ReducedRank;
37 std::array<std::size_t, reduced_rank>
reduced{};
44template <std::
size_t InputRank, ReductionAxis Axis>
45[[nodiscard]]
auto normalize_reduction_axis(Axis axis) -> std::size_t
47 using axis_type = std::remove_cvref_t<Axis>;
48 if constexpr (std::signed_integral<axis_type>)
52 using unsigned_axis = std::make_unsigned_t<axis_type>;
53 unsigned_axis magnitude =
static_cast<unsigned_axis
>(-(axis + 1));
55 ERROR_IF(std::cmp_greater(magnitude, InputRank),
"reduction axis is out of range");
56 return InputRank -
static_cast<std::size_t
>(magnitude);
60 ERROR_IF(std::cmp_greater_equal(axis, InputRank),
"reduction axis is out of range");
61 return static_cast<std::size_t
>(axis);
67template <std::
size_t InputRank, std::
size_t ReducedRank>
70 std::array<bool, InputRank> present{};
71 std::size_t previous = 0;
72 bool have_previous =
false;
74 for (std::size_t axis : axes.reduced)
76 if (axis >= InputRank || present[axis] || (have_previous && axis <= previous))
return false;
83 have_previous =
false;
84 for (std::size_t axis : axes.surviving)
86 if (axis >= InputRank || present[axis] || (have_previous && axis <= previous))
return false;
92 return std::ranges::all_of(present, [](
bool value) {
return value; });
98template <std::size_t InputRank, ReductionAxis... Axes>
101 static_assert(
sizeof...(Axes) <= InputRank);
103 result.
reduced = {detail::normalize_reduction_axis<InputRank>(requested_axes)...};
104 std::ranges::sort(result.reduced);
106 for (std::size_t index = 1; index < result.reduced.size(); ++index)
107 ERROR_IF(result.reduced[index - 1] == result.reduced[index],
"reduction axes must be unique");
109 std::size_t reduced_index = 0;
110 std::size_t surviving_index = 0;
111 for (std::size_t axis = 0; axis < InputRank; ++axis)
113 if (reduced_index < result.reduced.size() && result.reduced[reduced_index] == axis)
116 result.surviving[surviving_index++] = axis;
124template <std::
size_t InputRank>
128 for (std::size_t axis = 0; axis < InputRank; ++axis)
Integral runtime axis accepted by reduction front ends.
Definition reduction_axes.hpp:23
locale_t value
Definition data_table.cpp:49
Definition linalg/async.hpp:28
auto make_reduction_axes(Axes... requested_axes) -> ReductionAxes< InputRank, sizeof...(Axes)>
Normalize and validate a runtime reduction-axis pack.
Definition reduction_axes.hpp:99
constexpr bool reduction_axes_are_valid(ReductionAxes< InputRank, ReducedRank > const &axes) noexcept
Return whether a reduction-axis descriptor partitions every input axis.
Definition reduction_axes.hpp:68
constexpr auto all_reduction_axes() -> ReductionAxes< InputRank, InputRank >
Construct the full-reduction descriptor for a fixed input rank.
Definition reduction_axes.hpp:125
Normalized axes for reducing a fixed-rank input.
Definition reduction_axes.hpp:30
std::array< std::size_t, output_rank > surviving
Definition reduction_axes.hpp:38
static constexpr std::size_t output_rank
Definition reduction_axes.hpp:35
static constexpr std::size_t input_rank
Definition reduction_axes.hpp:33
static constexpr std::size_t reduced_rank
Definition reduction_axes.hpp:34
std::array< std::size_t, reduced_rank > reduced
Definition reduction_axes.hpp:37
#define CHECK(cond,...)
Definition trace.hpp:299
#define ERROR_IF(cond,...)
Definition trace.hpp:389