Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
dual_space.hpp
Go to the documentation of this file.
1
7#pragma once
8
12
13#include <concepts>
14#include <cstddef>
15#include <iterator>
16#include <ranges>
17#include <stdexcept>
18#include <string>
19#include <type_traits>
20#include <utility>
21
22namespace uni20
23{
24
25template <class SpaceType> class Dual;
26
27namespace detail
28{
29
30template <class T> struct IsDualSpace : std::false_type
31{};
32
33template <class SpaceType> struct IsDualSpace<Dual<SpaceType>> : std::true_type
34{};
35
36template <class T> struct PrimalSpaceType
37{
38 using type = std::remove_cvref_t<T>;
39};
40
41template <class SpaceType> struct PrimalSpaceType<Dual<SpaceType>>
42{
43 using type = SpaceType;
44};
45
46inline auto dual_space_entry(QNum const& q) -> QNum { return dual(q); }
47
48inline auto dual_space_entry(BlockSector const& sector) -> BlockSector
49{
50 return BlockSector{dual(sector.q), sector.dim};
51}
52
53template <std::input_iterator Iterator> class DualSpaceIterator {
54 public:
55 using iterator_concept = std::input_iterator_tag;
56 using iterator_category = std::input_iterator_tag;
57 using difference_type = std::iter_difference_t<Iterator>;
58 using value_type = std::remove_cvref_t<decltype(dual_space_entry(*std::declval<Iterator const&>()))>;
59
60 DualSpaceIterator()
61 requires std::default_initializable<Iterator>
62 = default;
63
64 explicit DualSpaceIterator(Iterator iterator) : iterator_(std::move(iterator)) {}
65
66 auto operator*() const -> value_type { return dual_space_entry(*iterator_); }
67
68 auto operator++() -> DualSpaceIterator&
69 {
70 ++iterator_;
71 return *this;
72 }
73
74 void operator++(int) { ++iterator_; }
75
76 auto operator==(DualSpaceIterator const&) const -> bool = default;
77
78 private:
79 Iterator iterator_;
80};
81
82} // namespace detail
83
89template <class SpaceType> class Dual {
90 static_assert(Space<SpaceType>, "Dual requires a tensor-space value");
91 static_assert(!detail::IsDualSpace<std::remove_cvref_t<SpaceType>>::value,
92 "use dual(Dual<S>) to recover S instead of nesting Dual adaptors");
93
94 public:
95 using base_space_type = SpaceType;
96
99 explicit Dual(base_space_type space) : space_(std::move(space)) {}
100
102 auto base() const& noexcept -> base_space_type const& { return space_; }
103
105 auto symmetry() const -> Symmetry
107 {
108 return space_.symmetry();
109 }
110
112 auto label() const -> std::string const& { return space_.label(); }
113
116 void set_label(std::string label) { space_.set_label(std::move(label)); }
117
119 auto size() const -> std::size_t
120 requires requires(base_space_type const& space) {
121 { space.size() } -> std::same_as<std::size_t>;
122 }
123 {
124 return space_.size();
125 }
126
128 auto empty() const -> bool
129 requires requires(base_space_type const& space) {
130 { space.empty() } -> std::convertible_to<bool>;
131 }
132 {
133 return space_.empty();
134 }
135
137 auto total_dim() const -> std::size_t
138 requires requires(base_space_type const& space) {
139 { space.total_dim() } -> std::same_as<std::size_t>;
140 }
141 {
142 return space_.total_dim();
143 }
144
146 auto extent() const -> std::size_t
147 requires requires(base_space_type const& space) {
148 { space.extent() } -> std::same_as<std::size_t>;
149 }
150 {
151 return space_.extent();
152 }
153
155 auto qnum() const -> QNum
156 requires requires(base_space_type const& space) {
157 { space.qnum() } -> std::convertible_to<QNum>;
158 }
159 {
160 return dual(space_.qnum());
161 }
162
165 auto operator[](std::size_t index) const
166 requires requires(base_space_type const& space) { space[index]; }
167 {
168 using entry_type = std::remove_cvref_t<decltype(space_[index])>;
169 static_assert(std::same_as<entry_type, QNum> || std::same_as<entry_type, BlockSector>,
170 "indexed Dual-space access currently supports QNum and BlockSector entries");
171 return detail::dual_space_entry(space_[index]);
172 }
173
175 auto begin() const
176 requires requires(base_space_type const& space) { space.begin(); }
177 {
178 return detail::DualSpaceIterator(space_.begin());
179 }
180
182 auto end() const
183 requires requires(base_space_type const& space) { space.end(); }
184 {
185 return detail::DualSpaceIterator(space_.end());
186 }
187
189 auto qnums() const
190 requires requires(base_space_type const& space) { space.qnums(); }
191 {
192 return space_.qnums() | std::views::transform([](QNum const& q) { return dual(q); });
193 }
194
196 auto sectors() const
197 requires requires(base_space_type const& space) { space.sectors(); }
198 {
199 return space_.sectors() |
200 std::views::transform([](BlockSector const& sector) { return BlockSector{dual(sector.q), sector.dim}; });
201 }
202
205 auto contains(QNum q) const -> bool
206 requires SymmetrySpace<base_space_type> && requires(base_space_type const& space, QNum value) {
207 { space.contains(value) } -> std::convertible_to<bool>;
208 }
209 {
210 if (!q.valid() || q.symmetry() != this->symmetry())
211 {
212 throw std::invalid_argument("Dual-space query has the wrong symmetry");
213 }
214 return space_.contains(dual(q));
215 }
216
218 auto operator==(Dual const& other) const -> bool = default;
219
221 auto release_base() && -> base_space_type { return std::move(space_); }
222
223 private:
224 base_space_type space_;
225};
226
227template <class SpaceType> Dual(SpaceType&&) -> Dual<std::remove_cvref_t<SpaceType>>;
228
231template <class T>
232concept DualSpace = Space<T> && detail::IsDualSpace<std::remove_cvref_t<T>>::value;
233
236template <class T> using primal_space_t = typename detail::PrimalSpaceType<std::remove_cvref_t<T>>::type;
237
242template <Space SpaceType>
243 requires(!DualSpace<SpaceType>)
244auto dual(SpaceType const& space) -> Dual<std::remove_cvref_t<SpaceType>>
245{
247}
248
253template <Space SpaceType>
254 requires(!DualSpace<SpaceType>)
255auto dual(SpaceType&& space) -> Dual<std::remove_cvref_t<SpaceType>>
256{
257 return Dual<std::remove_cvref_t<SpaceType>>(std::forward<SpaceType>(space));
258}
259
264template <class SpaceType> auto dual(Dual<SpaceType> const& space) -> SpaceType { return space.base(); }
265
270template <class SpaceType> auto dual(Dual<SpaceType>&& space) -> SpaceType { return std::move(space).release_base(); }
271
272} // namespace uni20
Defines one quantum-number sector and its degeneracy dimension.
Tensor space represented in an explicitly dual basis.
Definition dual_space.hpp:89
Dual(base_space_type space)
Construct a dual adaptor from its primal-basis value.
Definition dual_space.hpp:99
auto symmetry() const -> Symmetry
Return the symmetry shared with the underlying space.
Definition dual_space.hpp:105
auto contains(QNum q) const -> bool
Return whether the exposed dual basis contains an irrep.
Definition dual_space.hpp:205
auto qnum() const -> QNum
Return the dual of a fixed irrep label.
Definition dual_space.hpp:155
auto empty() const -> bool
Forward whether the underlying space is empty.
Definition dual_space.hpp:128
auto operator==(Dual const &other) const -> bool=default
Compare explicit dual-basis space values.
auto release_base() &&-> base_space_type
Transfer the underlying primal-basis value out of this adaptor.
Definition dual_space.hpp:221
auto qnums() const
Return a lazy range of dualized local-state quantum numbers.
Definition dual_space.hpp:189
auto operator[](std::size_t index) const
Return one dualized basis occurrence without changing its index.
Definition dual_space.hpp:165
auto label() const -> std::string const &
Return the semantic leg label.
Definition dual_space.hpp:112
void set_label(std::string label)
Replace the semantic leg label without changing the basis.
Definition dual_space.hpp:116
auto total_dim() const -> std::size_t
Forward the total degeneracy dimension.
Definition dual_space.hpp:137
auto size() const -> std::size_t
Forward the number of structural basis occurrences.
Definition dual_space.hpp:119
auto end() const
Return the end iterator for dualized basis occurrences.
Definition dual_space.hpp:182
auto begin() const
Return an iterator which dualizes each observed basis occurrence.
Definition dual_space.hpp:175
auto sectors() const
Return a lazy range of dualized block sectors.
Definition dual_space.hpp:196
auto extent() const -> std::size_t
Forward a symmetry-neutral dense extent.
Definition dual_space.hpp:146
SpaceType base_space_type
Definition dual_space.hpp:95
auto base() const &noexcept -> base_space_type const &
Return the underlying primal-basis space.
Definition dual_space.hpp:102
One irrep label together with the symmetry context needed to interpret it.
Definition qnum.hpp:29
Public handle to a canonicalized direct-product symmetry specification.
Definition symmetry.hpp:24
Space value whose object basis is explicitly dual.
Definition dual_space.hpp:232
Tensor-space value with a mutable semantic leg label.
Definition space.hpp:22
Space whose structure is interpreted in one explicit symmetry context.
Definition space.hpp:31
locale_t value
Definition data_table.cpp:49
Definition qnum.hpp:403
Var< T > operator*(T x, Var< T > y)
Computes x * y with reverse-mode gradient propagation.
Definition var_toys.hpp:176
typename optional_traits< T >::value_type value_type
Definition data_table.hpp:42
Definition async/async.hpp:26
typename detail::PrimalSpaceType< std::remove_cvref_t< T > >::type primal_space_t
Remove one explicit dual-space adaptor from a space type.
Definition dual_space.hpp:236
bool operator==(exact_rational const &a, exact_rational const &b)
Definition exact_rational.hpp:284
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
Dual(SpaceType &&) -> Dual< std::remove_cvref_t< SpaceType > >
Defines packed quantum numbers and same-symmetry quantum-number containers.
Defines the common tensor-space concepts.
One symmetry sector inside a block-structured space.
Definition block_sector.hpp:18
QNum q
Quantum number carried by the block.
Definition block_sector.hpp:20
std::size_t dim
Degeneracy / number of states in the block.
Definition block_sector.hpp:23