Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
tensor/reductions.hpp
Go to the documentation of this file.
1#pragma once
2
19
20#if UNI20_BACKEND_CUBLAS
22#endif
23
24#include <cstddef>
25#include <type_traits>
26#include <utility>
27
28namespace uni20
29{
30namespace detail
31{
32
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>;
39
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>>;
45
46template <class Tensor>
47concept ReductionStorageTypedTensor =
48 TensorView<Tensor> && requires { typename std::remove_cvref_t<Tensor>::storage_policy; };
49
50template <class... Inputs> struct reduction_result_storage
51{
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>;
54};
55
56template <class... Inputs> using reduction_result_storage_t = typename reduction_result_storage<Inputs...>::type;
57
58template <class Element, class... Inputs>
59concept ReductionResultAvailable = (ReductionStorageTypedTensor<Inputs> && ...) && requires {
60 typename reduction_result_storage_t<Inputs...>::template storage_t<Element>;
61};
62
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>>>;
66
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>>;
71
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...>)
76{
77 using extents_type = stdex::dextents<uni20::index_type, InputRank - ReducedRank>;
78 return extents_type{static_cast<uni20::index_type>(input.extent(axes.surviving[OutputAxis]))...};
79}
80
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)
84{
85 return reduction_output_extents(input, axes, std::make_index_sequence<InputRank - ReducedRank>{});
86}
87
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)
91{
92 auto operation = linalg::sum_reduction_op<InputRank, ReducedRank>{.axes = std::move(axes)};
93 linalg::dispatch_kernel(std::forward<BackendSelector>(selector), std::move(operation),
94 std::forward<OutputSpan>(output), std::forward<InputSpan>(input));
95}
96
97template <class Reference, class... Others>
98void require_reduction_extents(Reference const& reference, Others const&... others)
99{
100 constexpr std::size_t rank = tensor_mdspec_t<Reference>::rank();
101 if constexpr (rank > 0)
102 {
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");
106 };
107 (require_one(others), ...);
108 }
109}
110
111} // namespace detail
112
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)
121{
122 using input_type = std::remove_cvref_t<InputSpan>;
123 auto output_descriptor = std::forward<OutputSpan>(output);
124 auto input_descriptor = make_const_mdspan(input);
125 detail::dispatch_sum(std::forward<BackendSelector>(selector), output_descriptor, input_descriptor,
126 linalg::all_reduction_axes<input_type::rank()>());
127}
128
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)
141{
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);
145 auto input_descriptor = make_const_mdspan(input);
146 detail::dispatch_sum(std::forward<BackendSelector>(selector), output_descriptor, input_descriptor, std::move(axes));
147}
148
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
154{
155 using input_type = std::remove_cvref_t<InputSpan>;
156 using result_type = typename input_type::value_type;
157 result_type result{};
158 auto input_descriptor = make_const_mdspan(input);
159 detail::dispatch_sum(std::forward<BackendSelector>(selector), result, input_descriptor,
160 linalg::all_reduction_axes<input_type::rank()>());
161 return result;
162}
163
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)
169{
170 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
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>());
175}
176
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)
182{
183 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
184 auto operation = linalg::sum_reduction_op<input_rank, input_rank>{.axes = linalg::all_reduction_axes<input_rank>()};
185 auto selector = linalg::select_backend(operation, output, 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);
189}
190
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)
200{
201 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
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));
207}
208
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)
217{
218 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
219 auto axes = linalg::make_reduction_axes<input_rank>(first_axis, rest_axes...);
220 auto operation = linalg::sum_reduction_op<input_rank, 1 + sizeof...(RestAxes)>{.axes = axes};
221 auto selector = linalg::select_backend(operation, output, input);
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));
226}
227
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)
233{
234 using result_type = ScalarTensor<tensor_element_t<InputTensor>, detail::reduction_result_storage_t<InputTensor>>;
235 result_type result(uninitialized);
236 sum(std::forward<BackendSelector>(selector), result, input);
237 return result;
238}
239
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)
245{
246 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
247 auto operation = linalg::sum_reduction_op<input_rank, input_rank>{.axes = linalg::all_reduction_axes<input_rank>()};
248 auto selector = linalg::select_backend(operation, input);
249 return sum(selector, input);
250}
251
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)
260{
261 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
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));
269 return result;
270}
271
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)
278{
279 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
280 auto axes = linalg::make_reduction_axes<input_rank>(first_axis, rest_axes...);
281 auto operation = linalg::sum_reduction_op<input_rank, 1 + sizeof...(RestAxes)>{.axes = axes};
282 auto selector = linalg::select_backend(operation, input);
283 return sum(selector, input, first_axis, rest_axes...);
284}
285
287template <linalg::KernelBackendSelector BackendSelector, TensorView InputTensor>
288 requires RealOrComplex<tensor_element_t<InputTensor>>
289[[nodiscard]] auto sum_host(BackendSelector&& selector, InputTensor const& input) -> tensor_element_t<InputTensor>
290{
291 using result_type = tensor_element_t<InputTensor>;
292 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
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>());
297 return result;
298}
299
301template <TensorView InputTensor>
302 requires RealOrComplex<tensor_element_t<InputTensor>>
303[[nodiscard]] auto sum_host(InputTensor const& input) -> tensor_element_t<InputTensor>
304{
305 constexpr std::size_t input_rank = tensor_mdspec_t<InputTensor>::rank();
306 auto operation = linalg::sum_reduction_op<input_rank, input_rank>{.axes = linalg::all_reduction_axes<input_rank>()};
307 auto selector = linalg::select_backend(operation, input);
308 return sum_host(selector, input);
309}
310
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)
319{
320 auto output_descriptor = std::forward<OutputSpan>(output);
321 auto lhs_descriptor = make_const_mdspan(lhs);
322 auto rhs_descriptor = make_const_mdspan(rhs);
323 linalg::dispatch_kernel(std::forward<BackendSelector>(selector), linalg::inner_product_op{}, output_descriptor,
324 lhs_descriptor, rhs_descriptor);
325}
326
330template <class BackendSelector, class LhsSpan, class RhsSpan>
331 requires detail::CompatibleInnerProductSpans<LhsSpan, RhsSpan>
332[[nodiscard]] auto inner_product_host(BackendSelector&& selector, LhsSpan&& lhs, RhsSpan&& rhs) ->
333 typename std::remove_cvref_t<LhsSpan>::value_type
334{
335 using result_type = typename std::remove_cvref_t<LhsSpan>::value_type;
336 result_type result{};
337 auto lhs_descriptor = make_const_mdspan(lhs);
338 auto rhs_descriptor = make_const_mdspan(rhs);
339 linalg::dispatch_kernel(std::forward<BackendSelector>(selector), linalg::inner_product_op{}, result, lhs_descriptor,
340 rhs_descriptor);
341 return result;
342}
343
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)
349{
350 detail::require_reduction_extents(lhs, rhs);
351 auto output_descriptor = mdspec_of(output);
352 auto lhs_descriptor = mdspec_of(lhs);
353 auto rhs_descriptor = mdspec_of(rhs);
354 linalg::dispatch_kernel(std::forward<BackendSelector>(selector), linalg::inner_product_op{}, output_descriptor,
355 lhs_descriptor, rhs_descriptor);
356}
357
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)
363{
364 detail::require_reduction_extents(lhs, rhs);
365 auto selector = linalg::select_backend(linalg::inner_product_op{}, output, lhs, rhs);
366 inner_product(selector, output, lhs, rhs);
367}
368
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)
374{
375 using result_type =
376 ScalarTensor<tensor_element_t<LhsTensor>, detail::reduction_result_storage_t<LhsTensor, RhsTensor>>;
377 result_type result(uninitialized);
378 inner_product(std::forward<BackendSelector>(selector), result, lhs, rhs);
379 return result;
380}
381
383template <class LhsTensor, class RhsTensor>
384 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor> &&
385 detail::ReductionResultAvailable<tensor_element_t<LhsTensor>, LhsTensor, RhsTensor>
386[[nodiscard]] auto inner_product(LhsTensor const& lhs, RhsTensor const& rhs)
387{
388 detail::require_reduction_extents(lhs, rhs);
389 auto selector = linalg::select_backend(linalg::inner_product_op{}, lhs, rhs);
390 return inner_product(selector, lhs, rhs);
391}
392
394template <class BackendSelector, class LhsTensor, class RhsTensor>
395 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor>
396[[nodiscard]] auto inner_product_host(BackendSelector&& selector, LhsTensor const& lhs,
397 RhsTensor const& rhs) -> tensor_element_t<LhsTensor>
398{
399 detail::require_reduction_extents(lhs, rhs);
400 using result_type = tensor_element_t<LhsTensor>;
401 result_type result{};
402 auto lhs_descriptor = mdspec_of(lhs);
403 auto rhs_descriptor = mdspec_of(rhs);
404 linalg::dispatch_kernel(std::forward<BackendSelector>(selector), linalg::inner_product_op{}, result, lhs_descriptor,
405 rhs_descriptor);
406 return result;
407}
408
410template <class LhsTensor, class RhsTensor>
411 requires detail::CompatibleInnerProductTensors<LhsTensor, RhsTensor>
412[[nodiscard]] auto inner_product_host(LhsTensor const& lhs, RhsTensor const& rhs) -> tensor_element_t<LhsTensor>
413{
414 detail::require_reduction_extents(lhs, rhs);
415 auto selector = linalg::select_backend(linalg::inner_product_op{}, lhs, rhs);
416 return inner_product_host(selector, lhs, rhs);
417}
418
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)
425{
426 auto output_descriptor = std::forward<OutputSpan>(output);
427 auto input_descriptor = make_const_mdspan(input);
428 linalg::dispatch_kernel(std::forward<BackendSelector>(selector), linalg::norm_op{}, output_descriptor,
429 input_descriptor);
430}
431
433template <class BackendSelector, MdspanLike InputSpan>
434 requires RealOrComplex<typename std::remove_cvref_t<InputSpan>::value_type>
435[[nodiscard]] auto norm_host(BackendSelector&& selector,
437{
439 result_type result{};
440 auto input_descriptor = make_const_mdspan(input);
441 linalg::dispatch_kernel(std::forward<BackendSelector>(selector), linalg::norm_op{}, result, input_descriptor);
442 return result;
443}
444
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)
450{
451 auto output_descriptor = mdspec_of(output);
452 auto input_descriptor = mdspec_of(input);
453 linalg::dispatch_kernel(std::forward<BackendSelector>(selector), linalg::norm_op{}, output_descriptor,
454 input_descriptor);
455}
456
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)
462{
463 auto selector = linalg::select_backend(linalg::norm_op{}, output, input);
464 norm(selector, output, input);
465}
466
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)
472{
473 using result_type =
474 ScalarTensor<make_real_t<tensor_element_t<InputTensor>>, detail::reduction_result_storage_t<InputTensor>>;
475 result_type result(uninitialized);
476 norm(std::forward<BackendSelector>(selector), result, input);
477 return result;
478}
479
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)
485{
486 auto selector = linalg::select_backend(linalg::norm_op{}, input);
487 return norm(selector, input);
488}
489
491template <class BackendSelector, TensorView InputTensor>
492 requires RealOrComplex<tensor_element_t<InputTensor>>
493[[nodiscard]] auto norm_host(BackendSelector&& selector,
494 InputTensor const& input) -> make_real_t<tensor_element_t<InputTensor>>
495{
497 result_type result{};
498 auto input_descriptor = mdspec_of(input);
499 linalg::dispatch_kernel(std::forward<BackendSelector>(selector), linalg::norm_op{}, result, input_descriptor);
500 return result;
501}
502
504template <TensorView InputTensor>
505 requires RealOrComplex<tensor_element_t<InputTensor>>
506[[nodiscard]] auto norm_host(InputTensor const& input) -> make_real_t<tensor_element_t<InputTensor>>
507{
508 auto selector = linalg::select_backend(linalg::norm_op{}, input);
509 return norm_host(selector, input);
510}
511
512} // namespace uni20
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
Backend-independent operation values used with normalized kernel operands.
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