Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
reduction_axes.hpp
Go to the documentation of this file.
1#pragma once
2
10
11#include <algorithm>
12#include <array>
13#include <concepts>
14#include <cstddef>
15#include <type_traits>
16#include <utility>
17
18namespace uni20::linalg
19{
20
22template <class T>
23concept ReductionAxis = std::integral<std::remove_cvref_t<T>> && (!std::same_as<std::remove_cvref_t<T>, bool>);
24
29template <std::size_t InputRank, std::size_t ReducedRank> struct ReductionAxes
30{
31 static_assert(ReducedRank <= InputRank);
32
33 static constexpr std::size_t input_rank = InputRank;
34 static constexpr std::size_t reduced_rank = ReducedRank;
35 static constexpr std::size_t output_rank = InputRank - ReducedRank;
36
37 std::array<std::size_t, reduced_rank> reduced{};
38 std::array<std::size_t, output_rank> surviving{};
39};
40
41namespace detail
42{
43
44template <std::size_t InputRank, ReductionAxis Axis>
45[[nodiscard]] auto normalize_reduction_axis(Axis axis) -> std::size_t
46{
47 using axis_type = std::remove_cvref_t<Axis>;
48 if constexpr (std::signed_integral<axis_type>)
49 {
50 if (axis < 0)
51 {
52 using unsigned_axis = std::make_unsigned_t<axis_type>;
53 unsigned_axis magnitude = static_cast<unsigned_axis>(-(axis + 1));
54 ++magnitude;
55 ERROR_IF(std::cmp_greater(magnitude, InputRank), "reduction axis is out of range");
56 return InputRank - static_cast<std::size_t>(magnitude);
57 }
58 }
59
60 ERROR_IF(std::cmp_greater_equal(axis, InputRank), "reduction axis is out of range");
61 return static_cast<std::size_t>(axis);
62}
63
64} // namespace detail
65
67template <std::size_t InputRank, std::size_t ReducedRank>
68[[nodiscard]] constexpr bool reduction_axes_are_valid(ReductionAxes<InputRank, ReducedRank> const& axes) noexcept
69{
70 std::array<bool, InputRank> present{};
71 std::size_t previous = 0;
72 bool have_previous = false;
73
74 for (std::size_t axis : axes.reduced)
75 {
76 if (axis >= InputRank || present[axis] || (have_previous && axis <= previous)) return false;
77 present[axis] = true;
78 previous = axis;
79 have_previous = true;
80 }
81
82 previous = 0;
83 have_previous = false;
84 for (std::size_t axis : axes.surviving)
85 {
86 if (axis >= InputRank || present[axis] || (have_previous && axis <= previous)) return false;
87 present[axis] = true;
88 previous = axis;
89 have_previous = true;
90 }
91
92 return std::ranges::all_of(present, [](bool value) { return value; });
93}
94
98template <std::size_t InputRank, ReductionAxis... Axes>
99[[nodiscard]] auto make_reduction_axes(Axes... requested_axes) -> ReductionAxes<InputRank, sizeof...(Axes)>
100{
101 static_assert(sizeof...(Axes) <= InputRank);
102 ReductionAxes<InputRank, sizeof...(Axes)> result;
103 result.reduced = {detail::normalize_reduction_axis<InputRank>(requested_axes)...};
104 std::ranges::sort(result.reduced);
105
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");
108
109 std::size_t reduced_index = 0;
110 std::size_t surviving_index = 0;
111 for (std::size_t axis = 0; axis < InputRank; ++axis)
112 {
113 if (reduced_index < result.reduced.size() && result.reduced[reduced_index] == axis)
114 ++reduced_index;
115 else
116 result.surviving[surviving_index++] = axis;
117 }
118
120 return result;
121}
122
124template <std::size_t InputRank>
126{
128 for (std::size_t axis = 0; axis < InputRank; ++axis)
129 result.reduced[axis] = axis;
130 return result;
131}
132
133} // namespace uni20::linalg
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