Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
block_tensor_repartition.hpp
Go to the documentation of this file.
1
7#pragma once
8
11
12#include <array>
13#include <concepts>
14#include <cstddef>
15#include <tuple>
16#include <type_traits>
17#include <utility>
18
19namespace uni20
20{
21
23enum class MorphismSide
24{
25 Domain,
27};
28
30enum class BoundaryEnd
31{
32 Left,
33 Right
34};
35
36namespace detail
37{
38
39template <MorphismSide Side, BoundaryEnd End, class Tensor> auto make_repartitioned_domain(Tensor const& tensor)
40{
41 using tensor_type = std::remove_cvref_t<Tensor>;
42 constexpr std::size_t domain_size = tensor_type::domain_type::size();
43 constexpr std::size_t codomain_size = tensor_type::codomain_type::size();
44 auto const domain_spaces = tensor.domain().spaces();
45
46 if constexpr (Side == MorphismSide::Domain)
47 {
48 if constexpr (End == BoundaryEnd::Left)
49 return domain_from_tuple(tuple_slice<1, domain_size - 1>(domain_spaces));
50 else
51 return domain_from_tuple(tuple_slice<0, domain_size - 1>(domain_spaces));
52 }
53 else
54 {
55 auto const codomain_spaces = tensor.codomain().spaces();
56 constexpr std::size_t moved_index = End == BoundaryEnd::Left ? 0 : codomain_size - 1;
57 auto moved = dual(std::get<moved_index>(codomain_spaces));
58 if constexpr (End == BoundaryEnd::Left)
59 return domain_from_tuple(std::tuple_cat(std::tuple{std::move(moved)}, domain_spaces));
60 else
61 return domain_from_tuple(std::tuple_cat(domain_spaces, std::tuple{std::move(moved)}));
62 }
63}
64
65template <MorphismSide Side, BoundaryEnd End, class Tensor> auto make_repartitioned_codomain(Tensor const& tensor)
66{
67 using tensor_type = std::remove_cvref_t<Tensor>;
68 constexpr std::size_t domain_size = tensor_type::domain_type::size();
69 constexpr std::size_t codomain_size = tensor_type::codomain_type::size();
70 auto const codomain_spaces = tensor.codomain().spaces();
71
72 if constexpr (Side == MorphismSide::Codomain)
73 {
74 if constexpr (End == BoundaryEnd::Left)
75 return codomain_from_tuple(tuple_slice<1, codomain_size - 1>(codomain_spaces));
76 else
77 return codomain_from_tuple(tuple_slice<0, codomain_size - 1>(codomain_spaces));
78 }
79 else
80 {
81 auto const domain_spaces = tensor.domain().spaces();
82 constexpr std::size_t moved_index = End == BoundaryEnd::Left ? 0 : domain_size - 1;
83 auto moved = dual(std::get<moved_index>(domain_spaces));
84 if constexpr (End == BoundaryEnd::Left)
85 return codomain_from_tuple(std::tuple_cat(std::tuple{std::move(moved)}, codomain_spaces));
86 else
87 return codomain_from_tuple(std::tuple_cat(codomain_spaces, std::tuple{std::move(moved)}));
88 }
89}
90
91template <class Tensor, MorphismSide Side>
92concept RepartitionSourceHasLeg =
93 BlockTensorView<Tensor> &&
94 ((Side == MorphismSide::Domain && std::remove_cvref_t<Tensor>::domain_type::size() > 0) ||
95 (Side == MorphismSide::Codomain && std::remove_cvref_t<Tensor>::codomain_type::size() > 0));
96
97template <MorphismSide Side, BoundaryEnd End, class Tensor>
98 requires RepartitionSourceHasLeg<Tensor, Side>
99consteval auto make_repartition_factor_permutation()
100{
101 using tensor_type = std::remove_cvref_t<Tensor>;
102 constexpr std::size_t domain_size = tensor_type::domain_type::size();
103 constexpr std::size_t codomain_size = tensor_type::codomain_type::size();
104 constexpr std::size_t order = tensor_type::order();
105 std::array<std::size_t, order> permutation{};
106 std::size_t output = 0;
107 auto append = [&](std::size_t first, std::size_t last) {
108 for (std::size_t axis = first; axis < last; ++axis)
109 permutation[output++] = axis;
110 };
111
112 if constexpr (Side == MorphismSide::Domain && End == BoundaryEnd::Left)
113 {
114 append(1, domain_size);
115 permutation[output++] = 0;
116 append(domain_size, order);
117 }
118 else if constexpr (Side == MorphismSide::Domain && End == BoundaryEnd::Right)
119 {
120 append(0, domain_size - 1);
121 append(domain_size, order);
122 permutation[output++] = domain_size - 1;
123 }
124 else if constexpr (Side == MorphismSide::Codomain && End == BoundaryEnd::Left)
125 {
126 permutation[output++] = domain_size;
127 append(0, domain_size);
128 append(domain_size + 1, order);
129 }
130 else
131 {
132 append(0, domain_size);
133 permutation[output++] = order - 1;
134 append(domain_size, order - 1);
135 }
136
137 if (output != order || codomain_size + domain_size != order) throw "invalid repartition factor permutation";
138 return permutation;
139}
140
141template <class SourceTensor, MorphismSide Side, BoundaryEnd End>
142 requires RepartitionSourceHasLeg<SourceTensor, Side>
143struct RepartitionViewTraits
144{
145 using source_tensor_type = std::remove_const_t<SourceTensor>;
146 using domain_type = decltype(make_repartitioned_domain<Side, End>(std::declval<source_tensor_type const&>()));
147 using codomain_type = decltype(make_repartitioned_codomain<Side, End>(std::declval<source_tensor_type const&>()));
148 static constexpr auto factor_permutation = make_repartition_factor_permutation<Side, End, source_tensor_type>();
149 static constexpr auto key_permutation =
150 make_filtered_axis_permutation<source_tensor_type, factor_permutation, false>();
151 static constexpr auto dense_permutation =
152 make_filtered_axis_permutation<source_tensor_type, factor_permutation, true>();
153 using type = BlockTensorMappedView<SourceTensor, domain_type, codomain_type, key_permutation, dense_permutation>;
154};
155
156} // namespace detail
157
167template <class SourceTensor, MorphismSide Side, BoundaryEnd End>
168 requires detail::RepartitionSourceHasLeg<SourceTensor, Side>
169using BlockTensorRepartitionView = typename detail::RepartitionViewTraits<SourceTensor, Side, End>::type;
170
184template <MorphismSide Side, BoundaryEnd End, class Tensor>
185 requires detail::RepartitionSourceHasLeg<Tensor, Side>
187{
189 return view_type(tensor, detail::make_repartitioned_domain<Side, End>(tensor),
190 detail::make_repartitioned_codomain<Side, End>(tensor));
191}
192
194template <MorphismSide Side, BoundaryEnd End, BorrowedBlockTensorView Tensor>
195 requires(!std::is_lvalue_reference_v<Tensor &&> && detail::RepartitionSourceHasLeg<Tensor, Side>)
196auto repartition(Tensor&& tensor)
197{
199 return view_type(tensor, detail::make_repartitioned_domain<Side, End>(tensor),
200 detail::make_repartitioned_codomain<Side, End>(tensor));
201}
202
203template <MorphismSide Side, BoundaryEnd End, class Tensor>
204 requires(!std::is_lvalue_reference_v<Tensor &&> && detail::RepartitionSourceHasLeg<Tensor, Side> &&
205 !BorrowedBlockTensorView<Tensor>)
206auto repartition(Tensor&&) = delete;
207
208} // namespace uni20
Concepts and associated types for BlockTensor-level views.
Defines shared zero-copy BlockTensor axis-mapping machinery.
Ordered codomain spaces of a tensor morphism.
Definition morphism_boundary.hpp:78
Ordered domain spaces of a tensor morphism.
Definition morphism_boundary.hpp:24
General-purpose owning tensor with immediate or deferred mdspan metadata.
Definition basic_tensor.hpp:109
Definition async/async.hpp:26
MorphismSide
Morphism side from which repartition bends one edge leg.
Definition block_tensor_repartition.hpp:24
auto repartition(Tensor &tensor) -> BlockTensorRepartitionView< Tensor, Side, End >
Bend one planar edge leg across a BlockTensor morphism boundary.
Definition block_tensor_repartition.hpp:186
auto dual(SpaceType const &space) -> Dual< std::remove_cvref_t< SpaceType > >
Construct an explicitly dual basis without changing occurrence order.
Definition dual_space.hpp:244
typename detail::RepartitionViewTraits< SourceTensor, Side, End >::type BlockTensorRepartitionView
Zero-copy view of one bosonic edge leg bent across a morphism boundary.
Definition block_tensor_repartition.hpp:169
BoundaryEnd
Planar boundary end at which repartition bends one leg.
Definition block_tensor_repartition.hpp:31