Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
block_space.hpp
Go to the documentation of this file.
1
10#pragma once
11
17
18#include <algorithm>
19#include <concepts>
20#include <cstddef>
21#include <initializer_list>
22#include <numeric>
23#include <ranges>
24#include <span>
25#include <stdexcept>
26#include <string>
27#include <unordered_map>
28#include <unordered_set>
29#include <utility>
30#include <vector>
31
32namespace uni20
33{
34
39 public:
43 explicit BlockSpace(Symmetry sym, std::string label = {}) : sym_(sym), label_(std::move(label))
44 {
45 this->verify_symmetry();
46 }
47
52 BlockSpace(Symmetry sym, std::initializer_list<BlockSector> sectors, std::string label = {})
53 : BlockSpace(sym, std::move(label))
54 {
55 this->append_sectors(sectors);
56 this->canonicalize_sectors();
57 }
58
64 template <std::ranges::input_range Sectors>
65 requires std::constructible_from<BlockSector, std::ranges::range_reference_t<Sectors>>
66 BlockSpace(Symmetry sym, Sectors&& sectors, std::string label = {}) : BlockSpace(sym, std::move(label))
67 {
68 this->append_sectors(std::forward<Sectors>(sectors));
69 this->canonicalize_sectors();
70 }
71
74 auto symmetry() const -> Symmetry { return sym_; }
75
78 auto size() const -> std::size_t { return sectors_.size(); }
79
82 auto empty() const -> bool { return sectors_.empty(); }
83
86 auto total_dim() const -> std::size_t
87 {
88 return std::accumulate(sectors_.begin(), sectors_.end(), std::size_t{0},
89 [](std::size_t total, BlockSector const& sector) { return total + sector.dim; });
90 }
91
95 auto contains(QNum q) const -> bool
96 {
97 this->verify_symmetry(q);
98 return std::find_if(sectors_.begin(), sectors_.end(), [&](BlockSector const& sector) { return sector.q == q; }) !=
99 sectors_.end();
100 }
101
105 auto operator[](std::size_t index) const -> BlockSector const& { return sectors_[index]; }
106
109 auto sectors() const -> std::span<BlockSector const> { return sectors_; }
110
113 auto begin() const { return sectors_.begin(); }
114
117 auto end() const { return sectors_.end(); }
118
121 auto label() const -> std::string const& { return label_; }
122
125 void set_label(std::string label) { label_ = std::move(label); }
126
130 auto operator==(BlockSpace const& other) const -> bool = default;
131
132 private:
134 void verify_symmetry() const
135 {
136 if (!sym_.valid())
137 {
138 throw std::invalid_argument("BlockSpace requires a valid symmetry");
139 }
140 }
141
144 void verify_symmetry(QNum const& q) const
145 {
146 if (!q.valid() || q.symmetry() != sym_)
147 {
148 throw std::invalid_argument("BlockSpace sector has the wrong symmetry");
149 }
150 }
151
154 void verify_sector(BlockSector const& sector) const
155 {
156 this->verify_symmetry(sector.q);
157 if (sector.dim == 0)
158 {
159 throw std::invalid_argument("BlockSpace sectors must have positive dimension");
160 }
161 }
162
166 template <std::ranges::input_range Sectors> void append_sectors(Sectors&& sectors)
167 {
168 for (auto&& input : sectors)
169 {
170 BlockSector sector(std::forward<decltype(input)>(input));
171 this->verify_sector(sector);
172 sectors_.push_back(std::move(sector));
173 }
174 }
175
177 void canonicalize_sectors()
178 {
179 std::sort(sectors_.begin(), sectors_.end(),
180 [](BlockSector const& lhs, BlockSector const& rhs) { return lhs.q.raw_code() < rhs.q.raw_code(); });
181
182 auto const duplicate =
183 std::adjacent_find(sectors_.begin(), sectors_.end(),
184 [](BlockSector const& lhs, BlockSector const& rhs) { return lhs.q == rhs.q; });
185 if (duplicate != sectors_.end())
186 {
187 throw std::invalid_argument("BlockSpace sectors must have unique quantum numbers");
188 }
189 }
190
191 Symmetry sym_;
192 std::vector<BlockSector> sectors_;
193 std::string label_;
194};
195
196static_assert(SymmetrySpace<BlockSpace>);
197
200{
203
206
208 std::vector<std::size_t> block_index;
209
211 std::vector<std::size_t> block_offset;
212};
213
216{
219
222
224 std::vector<std::size_t> block_index;
225
227 std::vector<std::size_t> block_offset;
228};
229
232{
234 std::size_t block_index;
235
237 std::size_t first;
238
240 std::size_t last;
241
244 auto size() const -> std::size_t { return last - first; }
245
249 auto operator==(BlockRangeMapping const& other) const -> bool = default;
250};
251
254{
257
260
262 std::vector<BlockRangeMapping> block_mapping;
263};
264
265namespace detail
266{
267
272inline auto qnum_code_less(QNum const& lhs, QNum const& rhs) -> bool { return lhs.raw_code() < rhs.raw_code(); }
273
278template <typename Range> inline auto unique_qnums(Range const& range) -> std::vector<QNum>
279{
280 std::unordered_set<QNum> seen;
281 std::vector<QNum> qnums;
282 for (QNum const& q : range)
283 {
284 if (seen.insert(q).second)
285 {
286 qnums.push_back(q);
287 }
288 }
289 std::sort(qnums.begin(), qnums.end(), qnum_code_less);
290 return qnums;
291}
292
293} // namespace detail
294
298inline auto regularize(QNumList const& list) -> QNumListRegularization
299{
300 auto const qnums = detail::unique_qnums(list);
301
302 std::unordered_map<QNum, std::size_t> count_by_q;
303 for (QNum const& q : list)
304 {
305 count_by_q[q] += 1;
306 }
307
308 std::vector<BlockSector> sectors;
309 sectors.reserve(qnums.size());
310 for (QNum const& q : qnums)
311 {
312 sectors.push_back({q, count_by_q[q]});
313 }
314 BlockSpace regular(list.symmetry(), sectors);
315
316 std::unordered_map<QNum, std::size_t> index_by_q;
317 for (std::size_t index = 0; index < regular.size(); ++index)
318 {
319 index_by_q.emplace(regular[index].q, index);
320 }
321
322 std::unordered_map<QNum, std::size_t> offset_by_q;
323 std::vector<std::size_t> block_index;
324 std::vector<std::size_t> block_offset;
325 block_index.reserve(list.size());
326 block_offset.reserve(list.size());
327
328 for (QNum const& q : list)
329 {
330 block_index.push_back(index_by_q.at(q));
331 block_offset.push_back(offset_by_q[q]);
332 offset_by_q[q] += 1;
333 }
334
335 return {list, std::move(regular), std::move(block_index), std::move(block_offset)};
336}
337
342{
343 auto const qnums = detail::unique_qnums(space);
344
345 std::unordered_map<QNum, std::size_t> count_by_q;
346 for (QNum const& q : space)
347 {
348 count_by_q[q] += 1;
349 }
350
351 std::vector<BlockSector> sectors;
352 sectors.reserve(qnums.size());
353 for (QNum const& q : qnums)
354 {
355 sectors.push_back({q, count_by_q[q]});
356 }
357 BlockSpace regular(space.symmetry(), sectors, space.label());
358
359 std::unordered_map<QNum, std::size_t> index_by_q;
360 for (std::size_t index = 0; index < regular.size(); ++index)
361 {
362 index_by_q.emplace(regular[index].q, index);
363 }
364
365 std::unordered_map<QNum, std::size_t> offset_by_q;
366 std::vector<std::size_t> block_index;
367 std::vector<std::size_t> block_offset;
368 block_index.reserve(space.size());
369 block_offset.reserve(space.size());
370
371 for (QNum const& q : space)
372 {
373 block_index.push_back(index_by_q.at(q));
374 block_offset.push_back(offset_by_q[q]);
375 offset_by_q[q] += 1;
376 }
377
378 return {space, std::move(regular), std::move(block_index), std::move(block_offset)};
379}
380
385{
386 std::vector<QNum> original_qnums;
387 original_qnums.reserve(space.size());
388 for (BlockSector const& sector : space)
389 {
390 original_qnums.push_back(sector.q);
391 }
392 auto const qnums = detail::unique_qnums(original_qnums);
393
394 std::unordered_map<QNum, std::size_t> dim_by_q;
395 for (BlockSector const& sector : space)
396 {
397 dim_by_q[sector.q] += sector.dim;
398 }
399
400 std::vector<BlockSector> sectors;
401 sectors.reserve(qnums.size());
402 for (QNum const& q : qnums)
403 {
404 sectors.push_back({q, dim_by_q[q]});
405 }
406 BlockSpace regular(space.symmetry(), sectors, space.label());
407
408 std::unordered_map<QNum, std::size_t> index_by_q;
409 for (std::size_t index = 0; index < regular.size(); ++index)
410 {
411 index_by_q.emplace(regular[index].q, index);
412 }
413
414 std::unordered_map<QNum, std::size_t> offset_by_q;
415 std::vector<BlockRangeMapping> block_mapping;
416 block_mapping.reserve(space.size());
417 for (BlockSector const& sector : space)
418 {
419 auto& offset = offset_by_q[sector.q];
420 block_mapping.push_back({index_by_q.at(sector.q), offset, offset + sector.dim});
421 offset += sector.dim;
422 }
423
424 return {space, std::move(regular), std::move(block_mapping)};
425}
426
430inline auto to_block_space(QNumList const& list) -> BlockSpace { return regularize(list).regular; }
431
435inline auto to_block_space(LocalSpace const& space) -> BlockSpace { return regularize(space).regular; }
436
440inline auto to_block_space(IrregularSpace const& space) -> BlockSpace { return regularize(space).regular; }
441
442} // namespace uni20
Defines one quantum-number sector and its degeneracy dimension.
Immutable coalesced tensor space represented as unique symmetry blocks.
Definition block_space.hpp:38
auto total_dim() const -> std::size_t
Return the total dimension across all blocks.
Definition block_space.hpp:86
BlockSpace(Symmetry sym, std::string label={})
Construct an empty block space tied to one symmetry.
Definition block_space.hpp:43
BlockSpace(Symmetry sym, std::initializer_list< BlockSector > sectors, std::string label={})
Construct a block space from initial blocks.
Definition block_space.hpp:52
auto contains(QNum q) const -> bool
Return whether a block with the given quantum number exists.
Definition block_space.hpp:95
auto empty() const -> bool
Return whether the block space contains no blocks.
Definition block_space.hpp:82
void set_label(std::string label)
Replace the semantic leg label without changing sector structure.
Definition block_space.hpp:125
auto operator==(BlockSpace const &other) const -> bool=default
Compare two block spaces for exact equality.
auto size() const -> std::size_t
Return the number of stored blocks.
Definition block_space.hpp:78
auto operator[](std::size_t index) const -> BlockSector const &
Return indexed block access.
Definition block_space.hpp:105
auto begin() const
Return an iterator to the first block.
Definition block_space.hpp:113
auto symmetry() const -> Symmetry
Return the symmetry shared by all blocks.
Definition block_space.hpp:74
auto sectors() const -> std::span< BlockSector const >
Return the block list as a read-only span.
Definition block_space.hpp:109
auto label() const -> std::string const &
Return the semantic leg label.
Definition block_space.hpp:121
auto end() const
Return an iterator past the last block.
Definition block_space.hpp:117
BlockSpace(Symmetry sym, Sectors &&sectors, std::string label={})
Construct a block space from an input range.
Definition block_space.hpp:66
Ordered block space whose quantum-number sectors may repeat.
Definition irregular_space.hpp:30
Ordered local-state space whose quantum numbers may repeat.
Definition local_space.hpp:28
Explicit sparse tensor space represented as quantum numbers with one shared symmetry.
Definition qnum.hpp:102
One irrep label together with the symmetry context needed to interpret it.
Definition qnum.hpp:29
auto symmetry() const -> Symmetry
Return the symmetry context of this quantum number.
Definition qnum.hpp:51
auto valid() const -> bool
Return whether the quantum number carries a valid symmetry context.
Definition qnum.hpp:47
auto raw_code() const -> std::uint64_t
Return the inline packed irrep code.
Definition qnum.hpp:59
Public handle to a canonicalized direct-product symmetry specification.
Definition symmetry.hpp:24
auto valid() const -> bool
Return whether this handle refers to a valid symmetry.
Definition symmetry.hpp:44
Defines immutable ordered block spaces with repeated sectors.
Defines immutable ordered local-state spaces.
Definition qnum.hpp:403
Definition async/async.hpp:26
auto to_block_space(QNumList const &list) -> BlockSpace
Return the coalesced block-space representation of a sparse QNumList.
Definition block_space.hpp:430
auto regularize(QNumList const &list) -> QNumListRegularization
Regularize a sparse QNumList into one block per quantum number.
Definition block_space.hpp:298
std::size_t span
Definition presentation.cpp:2017
Defines packed quantum numbers and same-symmetry quantum-number containers.
Defines the common tensor-space concepts.
Destination range of one irregular block after regularization.
Definition block_space.hpp:232
std::size_t first
First offset occupied by the original block.
Definition block_space.hpp:237
std::size_t block_index
Index of the containing block in the regular BlockSpace.
Definition block_space.hpp:234
auto size() const -> std::size_t
Return the number of mapped degeneracy states.
Definition block_space.hpp:244
std::size_t last
One-past-the-end offset occupied by the original block.
Definition block_space.hpp:240
auto operator==(BlockRangeMapping const &other) const -> bool=default
Compare destination block and range.
One symmetry sector inside a block-structured space.
Definition block_sector.hpp:18
Result of regularizing an ordered segmented IrregularSpace.
Definition block_space.hpp:254
std::vector< BlockRangeMapping > block_mapping
Destination block and range for every original block.
Definition block_space.hpp:262
BlockSpace regular
Canonical space with one block per quantum number.
Definition block_space.hpp:259
IrregularSpace original
Original irregular space.
Definition block_space.hpp:256
Result of regularizing an immutable LocalSpace.
Definition block_space.hpp:216
LocalSpace original
Original ordered local space.
Definition block_space.hpp:218
std::vector< std::size_t > block_offset
For each local state, offset inside the containing block.
Definition block_space.hpp:227
BlockSpace regular
Coalesced block space with one block per quantum number.
Definition block_space.hpp:221
std::vector< std::size_t > block_index
For each local state, index of the containing block in regular.
Definition block_space.hpp:224
Result of regularizing a sparse QNumList into a coalesced BlockSpace.
Definition block_space.hpp:200
QNumList original
Original sparse space.
Definition block_space.hpp:202
BlockSpace regular
Coalesced block space with one block per quantum number.
Definition block_space.hpp:205
std::vector< std::size_t > block_index
For each sparse-space entry, index of the containing block in regular.
Definition block_space.hpp:208
std::vector< std::size_t > block_offset
For each sparse-space entry, offset inside the containing block.
Definition block_space.hpp:211