20#if UNI20_BACKEND_CUBLAS
33template <
class LhsSpan,
class RhsSpan>
34concept CompatibleInnerProductSpans = MdspanLike<LhsSpan> && MdspanLike<RhsSpan> &&
35 (std::remove_cvref_t<LhsSpan>::rank() == std::remove_cvref_t<RhsSpan>::rank()) &&
36 std::same_as<
typename std::remove_cvref_t<LhsSpan>::value_type,
37 typename std::remove_cvref_t<RhsSpan>::value_type> &&
38 RealOrComplex<
typename std::remove_cvref_t<LhsSpan>::value_type>;
40template <
class LhsTensor,
class RhsTensor>
41concept CompatibleInnerProductTensors = TensorView<LhsTensor> && TensorView<RhsTensor> &&
42 (tensor_mdspec_t<LhsTensor>::rank() == tensor_mdspec_t<RhsTensor>::rank()) &&
43 std::same_as<tensor_element_t<LhsTensor>, tensor_element_t<RhsTensor>> &&
44 RealOrComplex<tensor_element_t<LhsTensor>>;
46template <
class Tensor>
47concept ReductionStorageTypedTensor =
48 TensorView<Tensor> &&
requires {
typename std::remove_cvref_t<Tensor>::storage_policy; };
50template <
class... Inputs>
struct reduction_result_storage
52 using selected_type = linalg::detail::first_backend_bound_storage_t<Inputs...>;
53 using type = std::conditional_t<std::is_void_v<selected_type>, HostStorage, selected_type>;
56template <
class... Inputs>
using reduction_result_storage_t =
typename reduction_result_storage<Inputs...>::type;
58template <
class Element,
class... Inputs>
59concept ReductionResultAvailable = (ReductionStorageTypedTensor<Inputs> && ...) &&
requires {
60 typename reduction_result_storage_t<Inputs...>::template storage_t<Element>;
63template <TensorView InputTensor, std::
size_t ReducedRank>
64using sum_reduction_layout_t = std::conditional_t<tensor_mdspec_t<InputTensor>::rank() == ReducedRank,
ColumnMajor,
65 materialized_layout_t<void, tensor_mdspec_t<InputTensor>>>;
67template <TensorView InputTensor, std::
size_t ReducedRank>
68using sum_reduction_result_t =
69 Tensor<tensor_element_t<InputTensor>, tensor_mdspec_t<InputTensor>::rank() - ReducedRank,
70 reduction_result_storage_t<InputTensor>, sum_reduction_layout_t<InputTensor, ReducedRank>>;
72template <TensorView InputTensor, std::size_t InputRank, std::size_t ReducedRank, std::size_t... OutputAxis>
73[[nodiscard]]
auto reduction_output_extents(InputTensor
const& input,
74 linalg::ReductionAxes<InputRank, ReducedRank>
const& axes,
75 std::index_sequence<OutputAxis...>)
78 return extents_type{
static_cast<uni20::index_type>(input.extent(axes.surviving[OutputAxis]))...};
81template <TensorView InputTensor, std::
size_t InputRank, std::
size_t ReducedRank>
82[[nodiscard]]
auto reduction_output_extents(InputTensor
const& input,
83 linalg::ReductionAxes<InputRank, ReducedRank>
const& axes)
85 return reduction_output_extents(input, axes, std::make_index_sequence<InputRank - ReducedRank>{});
88template <
class BackendSelector,
class OutputSpan,
class InputSpan, std::
size_t InputRank, std::
size_t ReducedRank>
89void dispatch_sum(BackendSelector&& selector, OutputSpan&& output, InputSpan&& input,
90 linalg::ReductionAxes<InputRank, ReducedRank> axes)
92 auto operation = linalg::sum_reduction_op<InputRank, ReducedRank>{.axes = std::move(axes)};
94 std::forward<OutputSpan>(output), std::forward<InputSpan>(input));
97template <
class Reference,
class... Others>
98void require_reduction_extents(Reference
const& reference, Others
const&... others)
100 constexpr std::size_t rank = tensor_mdspec_t<Reference>::rank();
101 if constexpr (rank > 0)
103 auto require_one = [&](
auto const& other) {
104 for (std::size_t axis = 0; axis < rank; ++axis)
105 ERROR_IF(reference.extent(axis) != other.extent(axis),
"reduction operands have different extents");
107 (require_one(others), ...);
116template <linalg::KernelBackendSelector BackendSelector, MutableRankedMdspanLike<0> OutputSpan, MdspanLike InputSpan>
117 requires RealOrComplex<typename std::remove_cvref_t<InputSpan>::value_type> &&
118 std::same_as<typename std::remove_cvref_t<OutputSpan>::value_type,
119 typename std::remove_cvref_t<InputSpan>::value_type>
120void sum(BackendSelector&& selector, OutputSpan&& output, InputSpan&& input)
122 using input_type = std::remove_cvref_t<InputSpan>;
123 auto output_descriptor = std::forward<OutputSpan>(output);
125 detail::dispatch_sum(std::forward<BackendSelector>(selector), output_descriptor, input_descriptor,
132template <linalg::KernelBackendSelector BackendSelector, MutableMdspanLike OutputSpan, MdspanLike InputSpan,
133 linalg::ReductionAxis FirstAxis, linalg::ReductionAxis... RestAxes>
134 requires RealOrComplex<typename std::remove_cvref_t<InputSpan>::value_type> &&
135 std::same_as<typename std::remove_cvref_t<OutputSpan>::value_type,
136 typename std::remove_cvref_t<InputSpan>::value_type> &&
137 (1 +
sizeof...(RestAxes) <= std::remove_cvref_t<InputSpan>::rank()) &&
138 (std::remove_cvref_t<OutputSpan>::rank() + 1 +
sizeof...(RestAxes) == std::remove_cvref_t<InputSpan>::rank())
139void sum(BackendSelector&& selector, OutputSpan&& output, InputSpan&& input, FirstAxis first_axis,
140 RestAxes... rest_axes)
142 using input_type = std::remove_cvref_t<InputSpan>;
143 auto axes = linalg::make_reduction_axes<input_type::rank()>(first_axis, rest_axes...);
144 auto output_descriptor = std::forward<OutputSpan>(output);
146 detail::dispatch_sum(std::forward<BackendSelector>(selector), output_descriptor, input_descriptor, std::move(axes));
150template <linalg::KernelBackendSelector BackendSelector, MdspanLike InputSpan>
151 requires RealOrComplex<typename std::remove_cvref_t<InputSpan>::value_type>
152[[nodiscard]]
auto sum_host(BackendSelector&& selector, InputSpan&& input) ->
153 typename std::remove_cvref_t<InputSpan>::value_type
155 using input_type = std::remove_cvref_t<InputSpan>;
156 using result_type =
typename input_type::value_type;
157 result_type result{};
159 detail::dispatch_sum(std::forward<BackendSelector>(selector), result, input_descriptor,
165template <linalg::KernelBackendSelector BackendSelector, MutableScalarTensorView OutputTensor, TensorView InputTensor>
166 requires RealOrComplex<tensor_element_t<InputTensor>> &&
167 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<InputTensor>>
168void sum(BackendSelector&& selector, OutputTensor&& output, InputTensor
const& input)
171 auto output_descriptor =
mdspec_of(output);
172 auto input_descriptor =
mdspec_of(input);
173 detail::dispatch_sum(std::forward<BackendSelector>(selector), output_descriptor, input_descriptor,
174 linalg::all_reduction_axes<input_rank>());
178template <MutableScalarTensorView OutputTensor, TensorView InputTensor>
179 requires RealOrComplex<tensor_element_t<InputTensor>> &&
180 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<InputTensor>>
181void sum(OutputTensor&& output, InputTensor
const& input)
186 auto output_descriptor =
mdspec_of(output);
187 auto input_descriptor =
mdspec_of(input);
188 detail::dispatch_sum(selector, output_descriptor, input_descriptor, operation.axes);
192template <linalg::KernelBackendSelector BackendSelector, MutableTensorView OutputTensor, TensorView InputTensor,
193 linalg::ReductionAxis FirstAxis, linalg::ReductionAxis... RestAxes>
194 requires RealOrComplex<tensor_element_t<InputTensor>> &&
195 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<InputTensor>> &&
196 (1 +
sizeof...(RestAxes) <= tensor_mdspec_t<InputTensor>::rank()) &&
197 (tensor_mdspec_t<OutputTensor>::rank() + 1 +
sizeof...(RestAxes) == tensor_mdspec_t<InputTensor>::rank())
198void sum(BackendSelector&& selector, OutputTensor&& output, InputTensor
const& input, FirstAxis first_axis,
199 RestAxes... rest_axes)
202 auto axes = linalg::make_reduction_axes<input_rank>(first_axis, rest_axes...);
203 prepare_output(output, detail::reduction_output_extents(input, axes));
204 auto output_descriptor =
mdspec_of(output);
205 auto input_descriptor =
mdspec_of(input);
206 detail::dispatch_sum(std::forward<BackendSelector>(selector), output_descriptor, input_descriptor, std::move(axes));
210template <MutableTensorView OutputTensor, TensorView InputTensor, linalg::ReductionAxis FirstAxis,
211 linalg::ReductionAxis... RestAxes>
212 requires RealOrComplex<tensor_element_t<InputTensor>> &&
213 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<InputTensor>> &&
214 (1 +
sizeof...(RestAxes) <= tensor_mdspec_t<InputTensor>::rank()) &&
215 (tensor_mdspec_t<OutputTensor>::rank() + 1 +
sizeof...(RestAxes) == tensor_mdspec_t<InputTensor>::rank())
216void sum(OutputTensor&& output, InputTensor
const& input, FirstAxis first_axis, RestAxes... rest_axes)
219 auto axes = linalg::make_reduction_axes<input_rank>(first_axis, rest_axes...);
222 prepare_output(output, detail::reduction_output_extents(input, axes));
223 auto output_descriptor =
mdspec_of(output);
224 auto input_descriptor =
mdspec_of(input);
225 detail::dispatch_sum(selector, output_descriptor, input_descriptor, std::move(axes));
229template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor>
230 requires RealOrComplex<tensor_element_t<InputTensor>> &&
231 detail::ReductionResultAvailable<tensor_element_t<InputTensor>, InputTensor>
232[[nodiscard]]
auto sum(BackendSelector&& selector, InputTensor
const& input)
236 sum(std::forward<BackendSelector>(selector), result, input);
241template <TensorView InputTensor>
242 requires RealOrComplex<tensor_element_t<InputTensor>> &&
243 detail::ReductionResultAvailable<tensor_element_t<InputTensor>, InputTensor>
244[[nodiscard]]
auto sum(InputTensor
const& input)
249 return sum(selector, input);
253template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor, linalg::ReductionAxis FirstAxis,
254 linalg::ReductionAxis... RestAxes>
255 requires RealOrComplex<tensor_element_t<InputTensor>> &&
256 (1 +
sizeof...(RestAxes) <= tensor_mdspec_t<InputTensor>::rank()) &&
257 detail::ReductionResultAvailable<tensor_element_t<InputTensor>, InputTensor>
258[[nodiscard]]
auto sum(BackendSelector&& selector, InputTensor
const& input, FirstAxis first_axis,
259 RestAxes... rest_axes)
262 constexpr std::size_t reduced_rank = 1 +
sizeof...(RestAxes);
263 auto axes = linalg::make_reduction_axes<input_rank>(first_axis, rest_axes...);
265 result_type result(
uninitialized, detail::reduction_output_extents(input, axes));
266 auto output_descriptor =
mdspec_of(result);
267 auto input_descriptor =
mdspec_of(input);
268 detail::dispatch_sum(std::forward<BackendSelector>(selector), output_descriptor, input_descriptor, std::move(axes));
273template <TensorView InputTensor, linalg::ReductionAxis FirstAxis, linalg::ReductionAxis... RestAxes>
274 requires RealOrComplex<tensor_element_t<InputTensor>> &&
275 (1 +
sizeof...(RestAxes) <= tensor_mdspec_t<InputTensor>::rank()) &&
276 detail::ReductionResultAvailable<tensor_element_t<InputTensor>, InputTensor>
277[[nodiscard]]
auto sum(InputTensor
const& input, FirstAxis first_axis, RestAxes... rest_axes)
280 auto axes = linalg::make_reduction_axes<input_rank>(first_axis, rest_axes...);
283 return sum(selector, input, first_axis, rest_axes...);
287template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor>
288 requires RealOrComplex<tensor_element_t<InputTensor>>
293 result_type result{};
294 auto input_descriptor =
mdspec_of(input);
295 detail::dispatch_sum(std::forward<BackendSelector>(selector), result, input_descriptor,
296 linalg::all_reduction_axes<input_rank>());
301template <TensorView InputTensor>
302 requires RealOrComplex<tensor_element_t<InputTensor>>
314template <
class BackendSelector, MutableRankedMdspanLike<0> OutputSpan,
class LhsSpan,
class RhsSpan>
315 requires detail::CompatibleInnerProductSpans<LhsSpan, RhsSpan> &&
316 std::same_as<typename std::remove_cvref_t<OutputSpan>::value_type,
317 typename std::remove_cvref_t<LhsSpan>::value_type>
318void inner_product(BackendSelector&& selector, OutputSpan&& output, LhsSpan&& lhs, RhsSpan&& rhs)
320 auto output_descriptor = std::forward<OutputSpan>(output);
324 lhs_descriptor, rhs_descriptor);
330template <
class BackendSelector,
class LhsSpan,
class RhsSpan>
331 requires detail::CompatibleInnerProductSpans<LhsSpan, RhsSpan>
333 typename std::remove_cvref_t<LhsSpan>::value_type
335 using result_type =
typename std::remove_cvref_t<LhsSpan>::value_type;
336 result_type result{};
345template <
class BackendSelector, MutableScalarTensorView OutputTensor,
class LhsTensor,
class RhsTensor>
346 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor> &&
347 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<LhsTensor>>
348void inner_product(BackendSelector&& selector, OutputTensor&& output, LhsTensor
const& lhs, RhsTensor
const& rhs)
350 detail::require_reduction_extents(lhs, rhs);
351 auto output_descriptor =
mdspec_of(output);
355 lhs_descriptor, rhs_descriptor);
359template <MutableScalarTensorView OutputTensor,
class LhsTensor,
class RhsTensor>
360 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor> &&
361 std::same_as<tensor_element_t<OutputTensor>, tensor_element_t<LhsTensor>>
362void inner_product(OutputTensor&& output, LhsTensor
const& lhs, RhsTensor
const& rhs)
364 detail::require_reduction_extents(lhs, rhs);
370template <
class BackendSelector,
class LhsTensor,
class RhsTensor>
371 requires(!TensorView<BackendSelector>) && detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor> &&
372 detail::ReductionResultAvailable<tensor_element_t<LhsTensor>, LhsTensor, RhsTensor>
373[[nodiscard]]
auto inner_product(BackendSelector&& selector, LhsTensor
const& lhs, RhsTensor
const& rhs)
378 inner_product(std::forward<BackendSelector>(selector), result, lhs, rhs);
383template <
class LhsTensor,
class RhsTensor>
384 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor> &&
385 detail::ReductionResultAvailable<tensor_element_t<LhsTensor>, LhsTensor, RhsTensor>
388 detail::require_reduction_extents(lhs, rhs);
394template <
class BackendSelector,
class LhsTensor,
class RhsTensor>
395 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor>
399 detail::require_reduction_extents(lhs, rhs);
401 result_type result{};
410template <
class LhsTensor,
class RhsTensor>
411 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor>
414 detail::require_reduction_extents(lhs, rhs);
420template <
class BackendSelector, MutableRankedMdspanLike<0> OutputSpan, MdspanLike InputSpan>
421 requires RealOrComplex<typename std::remove_cvref_t<InputSpan>::value_type> &&
422 std::same_as<typename std::remove_cvref_t<OutputSpan>::value_type,
423 make_real_t<typename std::remove_cvref_t<InputSpan>::value_type>>
424void norm(BackendSelector&& selector, OutputSpan&& output, InputSpan&& input)
426 auto output_descriptor = std::forward<OutputSpan>(output);
433template <
class BackendSelector, MdspanLike InputSpan>
434 requires RealOrComplex<typename std::remove_cvref_t<InputSpan>::value_type>
439 result_type result{};
446template <
class BackendSelector, MutableScalarTensorView OutputTensor, TensorView InputTensor>
447 requires RealOrComplex<tensor_element_t<InputTensor>> &&
448 std::same_as<tensor_element_t<OutputTensor>, make_real_t<tensor_element_t<InputTensor>>>
449void norm(BackendSelector&& selector, OutputTensor&& output, InputTensor
const& input)
451 auto output_descriptor =
mdspec_of(output);
452 auto input_descriptor =
mdspec_of(input);
458template <MutableScalarTensorView OutputTensor, TensorView InputTensor>
459 requires RealOrComplex<tensor_element_t<InputTensor>> &&
460 std::same_as<tensor_element_t<OutputTensor>, make_real_t<tensor_element_t<InputTensor>>>
461void norm(OutputTensor&& output, InputTensor
const& input)
464 norm(selector, output, input);
468template <
class BackendSelector, TensorView InputTensor>
469 requires(!TensorView<BackendSelector>) && RealOrComplex<tensor_element_t<InputTensor>> &&
470 detail::ReductionResultAvailable<
make_real_t<tensor_element_t<InputTensor>>, InputTensor>
471[[nodiscard]]
auto norm(BackendSelector&& selector, InputTensor
const& input)
476 norm(std::forward<BackendSelector>(selector), result, input);
481template <TensorView InputTensor>
482 requires RealOrComplex<tensor_element_t<InputTensor>> &&
483 detail::ReductionResultAvailable<make_real_t<tensor_element_t<InputTensor>>, InputTensor>
484[[nodiscard]]
auto norm(InputTensor
const& input)
487 return norm(selector, input);
491template <
class BackendSelector, TensorView InputTensor>
492 requires RealOrComplex<tensor_element_t<InputTensor>>
497 result_type result{};
498 auto input_descriptor =
mdspec_of(input);
504template <TensorView InputTensor>
505 requires RealOrComplex<tensor_element_t<InputTensor>>
Ordered backend selector values shared by tensor storage and linalg dispatch.
General-purpose owning tensor with immediate or deferred mdspan metadata.
Definition basic_tensor.hpp:109
Operation-tag backend dispatch over tensor-view operands.
typename make_real< T >::type make_real_t
Alias for the underlying real-valued type of T.
Definition scalar_traits.hpp:168
Reference CPU tensor reduction kernels.
cuBLAS full inner-product and Euclidean-norm reductions.
Mdspan concept and accessor extensions for Uni20.
constexpr auto all_reduction_axes() -> ReductionAxes< InputRank, InputRank >
Construct the full-reduction descriptor for a fixed input rank.
Definition reduction_axes.hpp:125
constexpr auto select_backend(Operation const &operation, FirstTensor const &, RestTensors const &...)
Select the default backend list for an operation on Tensor operands.
Definition backend_selector.hpp:252
void dispatch_kernel(BackendSelector &&selector, Op op, Args &&... args)
Normalize a selector and dispatch or report that every eligible backend declined.
Definition dispatch.hpp:374
Definition async/async.hpp:26
constexpr uninitialized_t uninitialized
Explicit allocation tag for overwrite outputs and scratch space.
Definition common/initialization.hpp:22
void sum(BackendSelector selector, async::Async< OutputTensor > &output, async::Async< InputTensor > const &input)
Schedule a full sum into an explicit async scalar tensor.
Definition linalg/async/reductions.hpp:309
auto sum_host(BackendSelector selector, async::Async< InputTensor > const &input)
Return a nonblocking async host C++ scalar sum through an explicit selector.
Definition linalg/async/reductions.hpp:433
void inner_product(BackendSelector selector, async::Async< OutputTensor > &output, async::Async< LhsTensor > const &lhs, async::Async< RhsTensor > const &rhs)
Schedule an inner product into an explicit async scalar Tensor.
Definition linalg/async/reductions.hpp:455
Output & prepare_output(Output &output, RequiredExtents const &required)
Prepare a mutable tensor output with the specified shape.
Definition tensor/output.hpp:104
stdex::layout_left ColumnMajor
Conventional column-major contiguous mdspan layout.
Definition tensor.hpp:33
mpreal norm(mpcomplex const &z)
Definition mpcomplex.hpp:494
auto inner_product_host(BackendSelector selector, async::Async< LhsTensor > const &lhs, async::Async< RhsTensor > const &rhs)
Return a nonblocking async host C++ scalar inner product through an explicit selector.
Definition linalg/async/reductions.hpp:496
constexpr decltype(auto) mdspec_of(Tensor &tensor) noexcept(noexcept(tensor.mdspec()))
Return a tensor's immediate or descriptor-backed multidimensional metadata.
Definition tensor/concepts.hpp:50
auto norm_host(BackendSelector selector, async::Async< InputTensor > const &input)
Return a nonblocking async host C++ scalar norm through an explicit selector.
Definition linalg/async/reductions.hpp:554
std::remove_cv_t< typename tensor_mdspec_t< T >::element_type > tensor_element_t
Scalar value type exposed by a tensor-level object.
Definition tensor/concepts.hpp:126
std::ptrdiff_t index_type
Definition types.hpp:19
std::remove_cvref_t< detail::normalized_const_mdspec_t< T > > tensor_mdspec_t
Normalized readable MdspecLike type exposed by a tensor-level object.
Definition tensor/concepts.hpp:123
constexpr auto make_const_mdspan(Span const &span)
Build a read-only mdspan descriptor over the same storage and mapping.
Definition mdspan/concepts.hpp:372
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
ReductionAxes< InputRank, ReducedRank > axes
Definition operation_tags.hpp:197
Concepts for tensor-level objects that resolve mdspan kernel operands.
General-purpose owning tensors with runtime extents.
#define ERROR_IF(cond,...)
Definition trace.hpp:389