Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
linalg/ops/contract.hpp
Go to the documentation of this file.
1#pragma once
2
18
19#include <array>
20#include <concepts>
21#include <cstddef>
22#include <memory>
23#include <tuple>
24#include <type_traits>
25#include <utility>
26
27namespace uni20::linalg
28{
29
30namespace detail
31{
32
33template <KernelBackendSelector ExecutionSelector>
34[[nodiscard]] auto make_contraction_backend_selector(ExecutionSelector execution_selector)
35{
36 auto direct_selector = execution_selector;
37 auto looped_selector = execution_selector;
38 auto fallback_selector = normalize_backend_selector(std::move(execution_selector));
39 return std::apply(
40 [&]<class... FallbackBackends>(FallbackBackends&&... fallback_backends) {
41 return backend_list{DirectGemmContractionBackend{std::move(direct_selector)},
42 LoopedGemmContractionBackend{std::move(looped_selector)},
43 std::forward<FallbackBackends>(fallback_backends)...};
44 },
45 std::move(fallback_selector.entries));
46}
47
48} // namespace detail
49
54template <std::size_t LhsRank, std::size_t RhsRank, std::size_t ContractedRank, class StoragePolicy>
55struct backend_selector_default<contract_op<LhsRank, RhsRank, ContractedRank>, StoragePolicy>
56{
57 template <class StorageSelector>
58 static auto select(contract_op<LhsRank, RhsRank, ContractedRank> const&, StorageSelector storage_selector)
59 {
60 return detail::make_contraction_backend_selector(std::move(storage_selector));
61 }
62};
63
64namespace detail
65{
66
67template <class OutputTensor, class InputTensor>
68[[nodiscard]] constexpr bool is_obvious_contraction_alias(OutputTensor& output, InputTensor const& input) noexcept
69{
70 if constexpr (std::same_as<std::remove_cvref_t<OutputTensor>, std::remove_cvref_t<InputTensor>>)
71 {
72 return static_cast<void const*>(std::addressof(output)) == static_cast<void const*>(std::addressof(input));
73 }
74 return false;
75}
76
77template <class OutputTensor, class LhsTensor, class RhsTensor>
78concept CompatibleContractionTensors =
85 };
86
87template <class OutputTensor, class LhsTensor, class RhsTensor>
88void validate_contraction_aliasing(OutputTensor& output, LhsTensor const& lhs, RhsTensor const& rhs)
89{
90 ERROR_IF(is_obvious_contraction_alias(output, lhs) || is_obvious_contraction_alias(output, rhs),
91 "tensor contraction output must not alias an input tensor");
92}
93
94} // namespace detail
95
103template <class BackendSelector, class OutputTensor, class LhsTensor, class RhsTensor, std::size_t LhsRank,
104 std::size_t RhsRank, std::size_t ContractedRank>
105 requires detail::CompatibleContractionTensors<OutputTensor, LhsTensor, RhsTensor> &&
109void contract(BackendSelector&& selector, OutputTensor&& output, uni20::tensor_element_t<OutputTensor> alpha,
110 LhsTensor const& lhs, RhsTensor const& rhs, ContractionAxes<LhsRank, RhsRank, ContractedRank> axes,
112{
113 detail::validate_contraction_aliasing(output, lhs, rhs);
114 auto const required_extents = contraction_output_extents(lhs, rhs, axes);
115 uni20::require_output(output, required_extents);
116
117 auto output_descriptor = uni20::mdspec_of(output);
118 auto lhs_descriptor = uni20::mdspec_of(lhs);
119 auto rhs_descriptor = uni20::mdspec_of(rhs);
120 auto operation = contract_op<LhsRank, RhsRank, ContractedRank>{.axes = std::move(axes)};
121 dispatch_kernel(std::forward<BackendSelector>(selector), std::move(operation), output_descriptor, alpha,
122 lhs_descriptor, rhs_descriptor, beta);
123}
124
126template <class OutputTensor, class LhsTensor, class RhsTensor, std::size_t LhsRank, std::size_t RhsRank,
127 std::size_t ContractedRank>
128 requires detail::CompatibleContractionTensors<OutputTensor, LhsTensor, RhsTensor> &&
132void contract(OutputTensor&& output, uni20::tensor_element_t<OutputTensor> alpha, LhsTensor const& lhs,
133 RhsTensor const& rhs, ContractionAxes<LhsRank, RhsRank, ContractedRank> axes,
135{
136 auto operation = contract_op<LhsRank, RhsRank, ContractedRank>{.axes = axes};
137 auto selector = select_backend(operation, output, lhs, rhs);
138 contract(std::move(selector), std::forward<OutputTensor>(output), alpha, lhs, rhs, std::move(axes), beta);
139}
140
142template <class BackendSelector, class OutputTensor, class LhsTensor, class RhsTensor, std::size_t ContractedRank>
143 requires detail::CompatibleContractionTensors<OutputTensor, LhsTensor, RhsTensor> &&
144 (ContractedRank <= uni20::tensor_mdspec_t<LhsTensor>::rank()) &&
145 (ContractedRank <= uni20::tensor_mdspec_t<RhsTensor>::rank()) &&
148void contract(BackendSelector&& selector, OutputTensor&& output, uni20::tensor_element_t<OutputTensor> alpha,
149 LhsTensor const& lhs, RhsTensor const& rhs,
150 std::array<std::pair<std::size_t, std::size_t>, ContractedRank> requested_axes,
152{
153 constexpr std::size_t lhs_rank = uni20::tensor_mdspec_t<LhsTensor>::rank();
154 constexpr std::size_t rhs_rank = uni20::tensor_mdspec_t<RhsTensor>::rank();
155 auto axes = make_contraction_axes<lhs_rank, rhs_rank>(std::move(requested_axes));
156 contract(std::forward<BackendSelector>(selector), std::forward<OutputTensor>(output), alpha, lhs, rhs,
157 std::move(axes), beta);
158}
159
161template <class OutputTensor, class LhsTensor, class RhsTensor, std::size_t ContractedRank>
162 requires detail::CompatibleContractionTensors<OutputTensor, LhsTensor, RhsTensor> &&
163 (ContractedRank <= uni20::tensor_mdspec_t<LhsTensor>::rank()) &&
164 (ContractedRank <= uni20::tensor_mdspec_t<RhsTensor>::rank()) &&
167void contract(OutputTensor&& output, uni20::tensor_element_t<OutputTensor> alpha, LhsTensor const& lhs,
168 RhsTensor const& rhs, std::array<std::pair<std::size_t, std::size_t>, ContractedRank> requested_axes,
170{
171 constexpr std::size_t lhs_rank = uni20::tensor_mdspec_t<LhsTensor>::rank();
172 constexpr std::size_t rhs_rank = uni20::tensor_mdspec_t<RhsTensor>::rank();
173 auto axes = make_contraction_axes<lhs_rank, rhs_rank>(std::move(requested_axes));
174 contract(std::forward<OutputTensor>(output), alpha, lhs, rhs, std::move(axes), beta);
175}
176
177} // namespace uni20::linalg
MutableTensorView with a specified static rank.
Definition tensor/concepts.hpp:166
TensorView whose writable mdspec supports eventual element assignment.
Definition tensor/concepts.hpp:133
TensorView whose readable mdspec has a specified static rank.
Definition tensor/concepts.hpp:149
Concept for numeric scalar types (integer, real, or complex).
Definition scalar_concepts.hpp:81
Tensor-level object exposing readable multidimensional metadata and a backend selector.
Definition tensor/concepts.hpp:82
Normalized axis metadata for fixed-rank pairwise tensor contractions.
Operation-tag backend dispatch over tensor-view operands.
Reference CPU backend for pairwise tensor contraction dispatch.
Direct single-GEMM backend for pairwise tensor contraction.
Residual-axis looped GEMM backend for pairwise tensor contraction.
Definition linalg/async.hpp:28
DirectGemmContractionBackend(GemmSelector) -> DirectGemmContractionBackend< std::remove_cvref_t< GemmSelector > >
void contract(BackendSelector selector, async::Async< OutputTensor > &output, Alpha &&alpha, async::Async< LhsTensor > const &lhs, async::Async< RhsTensor > const &rhs, ContractionAxes< LhsRank, RhsRank, ContractedRank > axes, Beta &&beta)
Schedule a fixed-output pairwise contraction through an explicit selector.
Definition linalg/async/contract.hpp:84
backend_list(Backends...) -> backend_list< std::remove_cvref_t< Backends >... >
auto contraction_output_extents(Lhs const &lhs, Rhs const &rhs, ContractionAxes< LhsRank, RhsRank, ContractedRank > const &axes) -> stdex::dextents< uni20::index_type, ContractionAxes< LhsRank, RhsRank, ContractedRank >::output_rank >
Validate paired extents and return the canonical contraction output shape.
Definition contraction_axes.hpp:141
constexpr auto normalize_backend_selector(backend_list< Backends... > selector) -> backend_list< Backends... >
Return an explicit backend list unchanged.
Definition backend_selector.hpp:259
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
LoopedGemmContractionBackend(GemmSelector) -> LoopedGemmContractionBackend< std::remove_cvref_t< GemmSelector > >
void require_output(Output const &output, RequiredExtents const &required)
Require an existing tensor output to have the specified shape.
Definition tensor/output.hpp:84
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
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
mpreal beta(mpreal const &a, mpreal const &x)
Real Beta function; positive rational/integer pairs retain exact values.
Definition mpreal_special.hpp:164
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
Backend-independent operation values used with normalized kernel operands.
Canonical contracted and surviving axes for two fixed-rank operands.
Definition contraction_axes.hpp:26
static constexpr std::size_t output_rank
Definition contraction_axes.hpp:35
static auto select(contract_op< LhsRank, RhsRank, ContractedRank > const &, StorageSelector storage_selector)
Definition linalg/ops/contract.hpp:58
Uni20-owned operation-specific default for a storage policy.
Definition backend_selector.hpp:105
Fixed-output pairwise tensor contraction operation.
Definition operation_tags.hpp:98
ContractionAxes< LhsRank, RhsRank, ContractedRank > axes
Definition operation_tags.hpp:100
Concepts for tensor-level objects that resolve mdspan kernel operands.
Shape preparation contracts for tensor operation outputs.
#define ERROR_IF(cond,...)
Definition trace.hpp:389