34template <
class Span>
consteval bool reduction_value_is_readable()
36 using span_type = std::remove_cvref_t<Span>;
37 return requires(
typename span_type::reference element) {
static_cast<typename span_type::value_type
>(element); };
40template <
class Output>
consteval bool reduction_output_is_column_major()
42 using output_type = std::remove_cvref_t<Output>;
44 return std::same_as<typename output_type::layout_type, stdex::layout_left>;
49template <
class Output,
class Index,
class Scalar, std::size_t... Axis>
50void write_reduction_output(Output& output, Index
const& index, Scalar
value, std::index_sequence<Axis...>)
54 using output_type = std::remove_cvref_t<Output>;
55 using index_type =
typename output_type::index_type;
60 static_assert(
sizeof...(Axis) == 0);
65template <
class Reference,
class... Others>
66void check_reduction_extents(Reference
const& reference, Others
const&... others)
68 if constexpr (
sizeof...(Others) > 0)
70 constexpr std::size_t rank = std::remove_cvref_t<Reference>::rank();
71 if constexpr (rank > 0)
73 auto check_one = [&](
auto const& other) {
74 for (std::size_t axis = 0; axis < rank; ++axis)
75 CHECK_EQUAL(reference.extent(axis), other.extent(axis));
77 (check_one(others), ...);
82template <
class Span,
class Index, std::size_t... Axis>
83decltype(
auto) reduction_element(Span&
span, Index
const& index, std::index_sequence<Axis...>)
85 using span_type = std::remove_cvref_t<Span>;
86 using index_type =
typename span_type::index_type;
90template <std::size_t Depth,
bool ColumnMajor,
class Axes,
class Accumulate,
class State,
class FirstSpan,
91 class InputIndex,
class... RestSpans>
92void accumulate_reduced_elements(Axes
const& axes, Accumulate& accumulate, State& state, FirstSpan& first,
93 InputIndex& input_index, RestSpans&... rest)
95 if constexpr (Depth == Axes::reduced_rank)
97 constexpr auto input_axes = std::make_index_sequence<Axes::input_rank>{};
98 std::invoke(accumulate, state, reduction_element(first, input_index, input_axes),
99 reduction_element(rest, input_index, input_axes)...);
103 constexpr std::size_t position =
ColumnMajor ? Axes::reduced_rank - Depth - 1 : Depth;
104 std::size_t
const axis = axes.reduced[position];
105 using index_type =
typename std::remove_cvref_t<FirstSpan>::index_type;
106 for (
index_type i = 0; i < static_cast<index_type>(first.extent(axis)); ++i)
108 input_index[axis] = i;
109 accumulate_reduced_elements<Depth + 1, ColumnMajor>(axes, accumulate, state, first, input_index, rest...);
114template <std::size_t Depth,
bool OutputColumnMajor,
bool InputColumnMajor,
class Output,
class Axes,
class Initialize,
115 class Accumulate,
class Finalize,
class OutputIndex,
class InputIndex,
class FirstSpan,
class... RestSpans>
116void emit_reduction_outputs(Output& output, Axes
const& axes, Initialize& initialize, Accumulate& accumulate,
117 Finalize& finalize, OutputIndex& output_index, InputIndex& input_index, FirstSpan& first,
120 if constexpr (Depth == Axes::output_rank)
122 auto state = std::invoke(initialize);
123 accumulate_reduced_elements<0, InputColumnMajor>(axes, accumulate, state, first, input_index, rest...);
124 auto value = std::invoke(finalize, state);
125 write_reduction_output(output, output_index, std::move(
value), std::make_index_sequence<Axes::output_rank>{});
129 constexpr std::size_t output_axis = OutputColumnMajor ? Axes::output_rank - Depth - 1 : Depth;
130 std::size_t
const input_axis = axes.surviving[output_axis];
131 using index_type =
typename std::remove_cvref_t<FirstSpan>::index_type;
132 for (
index_type i = 0; i < static_cast<index_type>(first.extent(input_axis)); ++i)
134 output_index[output_axis] = i;
135 input_index[input_axis] = i;
136 emit_reduction_outputs<Depth + 1, OutputColumnMajor, InputColumnMajor>(
137 output, axes, initialize, accumulate, finalize, output_index, input_index, first, rest...);
142template <
class Output, std::size_t InputRank, std::size_t ReducedRank,
class Initialize,
class Accumulate,
143 class Finalize,
class FirstSpan,
class... RestSpans>
144void reference_reduce_axes(Output& output, ReductionAxes<InputRank, ReducedRank>
const& axes, Initialize&& initialize,
145 Accumulate&& accumulate, Finalize&& finalize, FirstSpan& first, RestSpans&... rest)
147 using first_type = std::remove_cvref_t<FirstSpan>;
148 static_assert(first_type::rank() == InputRank);
149 static_assert(((std::remove_cvref_t<RestSpans>::rank() == InputRank) && ...));
151 static_assert(std::remove_cvref_t<Output>::rank() == InputRank - ReducedRank);
154 check_reduction_extents(first, rest...);
158 for (std::size_t output_axis = 0; output_axis < InputRank - ReducedRank; ++output_axis)
159 CHECK_EQUAL(output.extent(output_axis), first.extent(axes.surviving[output_axis]));
162 std::array<
typename first_type::index_type, InputRank - ReducedRank> output_index{};
163 std::array<typename first_type::index_type, InputRank> input_index{};
164 constexpr bool output_column_major = reduction_output_is_column_major<Output>();
165 constexpr bool input_column_major = std::same_as<typename first_type::layout_type, stdex::layout_left>;
166 auto initialize_operation = std::forward<Initialize>(initialize);
167 auto accumulate_operation = std::forward<Accumulate>(accumulate);
168 auto finalize_operation = std::forward<Finalize>(finalize);
169 emit_reduction_outputs<0, output_column_major, input_column_major>(output, axes, initialize_operation,
170 accumulate_operation, finalize_operation,
171 output_index, input_index, first, rest...);
174template <
class LhsSpan,
class RhsSpan>
consteval bool inner_product_inputs_are_supported()
176 using lhs_type = std::remove_cvref_t<LhsSpan>;
177 using rhs_type = std::remove_cvref_t<RhsSpan>;
178 using scalar_type =
typename lhs_type::value_type;
179 if constexpr (lhs_type::rank() != rhs_type::rank() || !std::same_as<scalar_type, typename rhs_type::value_type> ||
181 !reduction_value_is_readable<RhsSpan>())
187 return requires(scalar_type lhs, scalar_type rhs) {
189 backends::cpu::detail::CompensatedSum<scalar_type>{}.add(
uni20::conj(lhs) * rhs);
194template <
class Output,
class LhsSpan,
class RhsSpan>
195void reference_inner_product(Output& output, LhsSpan& lhs, RhsSpan& rhs)
197 using lhs_type = std::remove_cvref_t<LhsSpan>;
198 using scalar_type =
typename lhs_type::value_type;
199 using state_type = backends::cpu::detail::CompensatedSum<scalar_type>;
201 auto initialize = [] {
return state_type{}; };
202 auto accumulate = [](state_type& state,
auto&& lhs_element,
auto&& rhs_element) {
203 auto const lhs_value =
static_cast<scalar_type
>(lhs_element);
204 auto const rhs_value =
static_cast<scalar_type
>(rhs_element);
207 auto finalize = [](state_type
const& state) {
return state.value(); };
208 reference_reduce_axes(output,
all_reduction_axes<lhs_type::rank()>(), initialize, accumulate, finalize, lhs, rhs);
211template <
class Real>
void update_scaled_sum_of_squares(Real component, Real& scale, Real& sum_of_squares)
214 component =
abs(component);
215 if (component == Real{} || !(sum_of_squares == sum_of_squares))
return;
217 if (!(component == component))
219 sum_of_squares = component;
221 else if (component > scale)
227 else if (component == scale)
229 sum_of_squares +=
Real{1};
238template <
class InputSpan>
consteval bool norm_input_is_supported()
240 using input_type = std::remove_cvref_t<InputSpan>;
241 using scalar_type =
typename input_type::value_type;
253template <
class Real>
struct ScaledSumOfSquaresState
256 Real sum_of_squares{};
259template <
class Output,
class InputSpan>
void reference_norm(Output& output, InputSpan& input)
261 using input_type = std::remove_cvref_t<InputSpan>;
262 using scalar_type =
typename input_type::value_type;
264 using state_type = ScaledSumOfSquaresState<result_type>;
266 auto initialize = [] {
return state_type{}; };
267 auto accumulate = [](state_type& state,
auto&& element) {
268 auto const value =
static_cast<scalar_type
>(element);
271 update_scaled_sum_of_squares(
value.real(), state.scale, state.sum_of_squares);
272 update_scaled_sum_of_squares(
value.imag(), state.scale, state.sum_of_squares);
276 update_scaled_sum_of_squares(
value, state.scale, state.sum_of_squares);
279 auto finalize = [](state_type
const& state) {
280 if (!(state.sum_of_squares == state.sum_of_squares))
return state.sum_of_squares;
281 if (state.scale == result_type{})
return result_type{};
283 return state.scale *
sqrt(state.sum_of_squares);
285 reference_reduce_axes(output,
all_reduction_axes<input_type::rank()>(), initialize, accumulate, finalize, input);
288template <
class InputSpan>
consteval bool sum_input_is_supported()
290 using input_type = std::remove_cvref_t<InputSpan>;
291 using scalar_type =
typename input_type::value_type;
298 return requires(scalar_type
value) { backends::cpu::detail::CompensatedSum<scalar_type>{}.add(
value); };
302template <
class Output, std::
size_t InputRank, std::
size_t ReducedRank,
class InputSpan>
303void reference_sum(Output& output, sum_reduction_op<InputRank, ReducedRank>
const& operation, InputSpan& input)
305 using scalar_type =
typename std::remove_cvref_t<InputSpan>::value_type;
306 using state_type = backends::cpu::detail::CompensatedSum<scalar_type>;
308 auto initialize = [] {
return state_type{}; };
309 auto accumulate = [](state_type& state,
auto&& element) { state.add(
static_cast<scalar_type
>(element)); };
310 auto finalize = [](state_type
const& state) {
return state.value(); };
311 reference_reduce_axes(output, operation.axes, initialize, accumulate, finalize, input);
314template <
class Output,
class LhsSpan,
class RhsSpan>
consteval auto inner_product_acceptance()
316 using scalar_type =
typename LhsSpan::value_type;
317 if constexpr (inner_product_inputs_are_supported<LhsSpan, RhsSpan>() &&
318 reduction_detail::output_is_supported<Output, scalar_type, 0>())
324template <
class Output,
class InputSpan>
consteval auto norm_acceptance()
326 using scalar_type =
typename InputSpan::value_type;
328 if constexpr (norm_input_is_supported<InputSpan>() && reduction_detail::output_is_supported<Output, result_type, 0>())
334template <
class Output, std::
size_t InputRank, std::
size_t ReducedRank,
class InputSpan>
consteval auto sum_acceptance()
336 using input_type = std::remove_cvref_t<InputSpan>;
337 using scalar_type =
typename input_type::value_type;
338 if constexpr (input_type::rank() == InputRank && sum_input_is_supported<InputSpan>() &&
348template <
class Output, uni20::MdspecLike LhsMdspan, uni20::MdspecLike RhsMdspan>
357 constexpr auto acceptance = detail::inner_product_acceptance<output_type, lhs_span, rhs_span>();
365template <
class Output, uni20::MdspecLike LhsMdspan, uni20::MdspecLike RhsMdspan>
372 auto lhs_span = lhs_access.mdspan();
373 auto rhs_span = rhs_access.mdspan();
375 detail::reference_inner_product(resolved_output, lhs_span, rhs_span);
381template <
class Output, uni20::MdspecLike InputMdspan>
387 constexpr auto acceptance = detail::norm_acceptance<output_type, input_span>();
395template <
class Output, uni20::MdspecLike InputMdspan>
400 auto input_span = input_access.mdspan();
402 detail::reference_norm(resolved_output, input_span);
408template <
class Output, std::
size_t InputRank, std::
size_t ReducedRank, uni20::MdspecLike InputMdspan>
411 Output&, InputMdspan&)
415 constexpr auto acceptance = detail::sum_acceptance<output_type, InputRank, ReducedRank, input_span>();
423template <
class Output, std::
size_t InputRank, std::
size_t ReducedRank, uni20::MdspecLike InputMdspan>
429 auto input_span = input_access.mdspan();
432 detail::reference_sum(resolved_output, operation, input_span);
RAII leases that resolve device descriptors and tensor views to mdspans.
Concept for complex scalar types.
Definition scalar_concepts.hpp:75
Mdspec metadata supporting host read acquisition.
Definition access.hpp:688
A readable type implementing the mdspan observers and multidimensional subscript contract.
Definition mdspan/concepts.hpp:291
A mutable mdspan-like type with a specified static rank.
Definition mdspan/concepts.hpp:494
Concept for types that are either real or complex.
Definition scalar_concepts.hpp:87
locale_t value
Definition data_table.cpp:49
Operation-tag backend dispatch over tensor-view operands.
uni20::complex< T > conj(detail::standard_complex< T > x)
Returns the complex conjugate for complex-valued scalars.
Definition math.hpp:70
typename make_real< T >::type make_real_t
Alias for the underlying real-valued type of T.
Definition scalar_traits.hpp:168
Scalar math helper utilities.
Mdspan concept and accessor extensions for Uni20.
Runtime initialize(RuntimeConfig config)
Install and return a scoped process-wide CUDA runtime owner.
Definition runtime.cpp:807
R ratio(DiagnosticMagnitude< R > const &a, DiagnosticMagnitude< R > const &b)
Definition gmres_diagnostics.hpp:125
typename HostOutputType< Output >::type host_output_t
Resolved output type used by a host reduction backend probe.
Definition reduction_output.hpp:56
consteval bool output_is_supported()
Report whether an output can receive a reduction value of fixed rank.
Definition reduction_output.hpp:24
KernelAttempt with_host_output(Output &output, Function &&function)
Invoke a synchronous reduction with a resolved host output.
Definition reduction_output.hpp:68
Definition linalg/async.hpp:28
KernelAttempt try_kernel(BlasBackend, gemm_op const &, C &c, S const &alpha, A &a, B &b, S const &beta)
Pack logical host values and execute GEMM through value-preserving provider conversion.
Definition linalg/backends/blas/binary80.hpp:30
KernelAttempt
Result of one runtime kernel backend attempt.
Definition kernel_attempt.hpp:27
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
constexpr KernelAcceptance< KernelTypeAcceptance::no > kernel_types_no
Report that a backend rejects the argument types.
Definition dispatch_error.hpp:34
consteval auto kernel_accepts_types(BlasBackend, gemm_op const &, C &, S const &, A &, B &, S const &)
Accept host-readable native binary80 operands, including transforming accessors.
Definition linalg/backends/blas/binary80.hpp:19
constexpr KernelAcceptance< KernelTypeAcceptance::yes > kernel_types_yes
Report that a backend accepts every instance of the argument types.
Definition dispatch_error.hpp:40
constexpr auto abs(basic_half_int< T > value) -> basic_half_int< T >
Return the absolute value of a half-integer.
Definition half_int.hpp:431
exact_rational sqrt(X const &value)
Return the nonnegative rational square root, or require finite precision.
Definition exact_rational.hpp:355
std::remove_cvref_t< decltype(std::declval< detail::host_read_mdspan_lease_t< Mdspec > & >().mdspan())> host_read_mdspan_t
Read-only mdspan type resolved by host descriptor acquisition.
Definition access.hpp:679
stdex::layout_left ColumnMajor
Conventional column-major contiguous mdspan layout.
Definition tensor.hpp:33
auto acquire_host_read_access_sync(Mdspan const &mdspan)
Acquire a directly host-accessible read-only mdspan.
Definition access.hpp:616
std::ptrdiff_t index_type
Definition types.hpp:19
std::size_t span
Definition presentation.cpp:2017
Shared host-output handling for synchronous scalar reductions.
Backend value for the reference host CPU dense linalg oracle.
Definition backend_selector.hpp:55
Conjugate-linear-left tensor inner-product operation tag.
Definition operation_tags.hpp:105
Euclidean tensor norm operation tag.
Definition operation_tags.hpp:111
Sum reduction over one or more fixed-rank input axes.
Definition operation_tags.hpp:195
Concepts for tensor-level objects that resolve mdspan kernel operands.
#define CHECK(cond,...)
Definition trace.hpp:299
#define CHECK_EQUAL(a, b,...)
Definition trace.hpp:309