17#include <initializer_list>
37 explicit QNum(
Symmetry sym, std::uint64_t code) : sym_(sym.impl()), code_(code)
39 if (code_ > detail::qnum_inline_code_max)
41 throw std::overflow_error(
"QNum code uses the reserved out-of-line tag bit");
47 auto valid() const ->
bool {
return sym_ !=
nullptr; }
78 friend auto qdim(
QNum const&) -> double;
87 void ensure_valid()
const
91 throw std::logic_error(
"QNum is not initialized");
95 detail::SymmetryImpl
const* sym_ =
nullptr;
97 std::uint64_t code_ = 0;
113 for (
QNum const& q : values_)
115 this->verify_symmetry(q);
125 auto size() const ->
std::
size_t {
return values_.size(); }
129 auto empty() const ->
bool {
return values_.empty(); }
135 this->verify_symmetry(q);
136 values_.push_back(q);
147 this->verify_symmetry(q);
148 return std::find(values_.begin(), values_.end(), q) != values_.end();
154 std::sort(values_.begin(), values_.end(),
155 [](
QNum const& lhs,
QNum const& rhs) { return lhs.raw_code() < rhs.raw_code(); });
162 values_.erase(std::unique(values_.begin(), values_.end()), values_.end());
168 auto operator[](std::size_t index)
const ->
QNum const& {
return values_[index]; }
172 auto begin()
const {
return values_.begin(); }
176 auto end()
const {
return values_.end(); }
186 void verify_symmetry(
QNum const& q)
const
190 throw std::invalid_argument(
"QNumList element has the wrong symmetry");
195 std::vector<QNum> values_;
204 auto const* impl = sym.impl();
205 std::vector<std::uint64_t> codes(impl->factor_count(), 0);
206 std::vector<bool> seen(impl->factor_count(),
false);
208 for (
auto const& [name,
value] : values)
210 auto const index = impl->find_factor(name);
211 if (!index.has_value())
213 throw std::invalid_argument(
"unknown symmetry component name: " + std::string{name});
217 throw std::invalid_argument(
"duplicate symmetry component assignment: " + std::string{name});
221 auto const& factor = impl->factors()[*index];
222 auto const* typed_factor =
dynamic_cast<detail::SymmetryFactor<U1> const*
>(factor.factor);
223 if (typed_factor ==
nullptr)
225 throw std::invalid_argument(
"make_qnum(U1) used with a non-U(1) symmetry component");
227 codes[*index] = typed_factor->encode(
value);
230 return QNum(sym, impl->pack(codes));
238 auto const* impl = q.sym_;
239 auto codes = impl->unpack(q.code_);
240 for (std::size_t i = 0; i < codes.size(); ++i)
242 codes[i] = impl->factors()[i].factor->dual_code(codes[i]);
244 return QNum(q.symmetry(), impl->pack(codes));
257 auto const* impl = q.sym_;
258 auto const codes = impl->unpack(q.code_);
260 for (std::size_t i = 0; i < codes.size(); ++i)
262 result *= impl->factors()[i].factor->qdim_code(codes[i]);
272 auto const* impl = q.sym_;
273 auto const codes = impl->unpack(q.code_);
275 for (std::size_t i = 0; i < codes.size(); ++i)
277 result *= impl->factors()[i].factor->degree_code(codes[i]);
288 auto const* impl = q.sym_;
289 auto const index = impl->find_factor(name);
290 if (!index.has_value())
292 throw std::invalid_argument(
"unknown symmetry component name: " + std::string{name});
295 auto const& factor = impl->factors()[*index];
296 auto const* typed_factor =
dynamic_cast<detail::SymmetryFactor<U1> const*
>(factor.factor);
297 if (typed_factor ==
nullptr)
299 throw std::invalid_argument(
"requested U(1) component from a non-U(1) factor");
302 auto const codes = impl->unpack(q.code_);
303 return typed_factor->decode(codes[*index]);
313 if (source == target)
318 auto const* source_impl = source.impl();
319 auto const* target_impl = target.impl();
320 auto const source_codes = source_impl->unpack(q.code_);
322 std::vector<std::uint64_t> target_codes(target_impl->factor_count(), 0);
323 for (std::size_t i = 0; i < target_impl->factor_count(); ++i)
325 auto const& target_factor = target_impl->factors()[i];
326 auto const source_index = source_impl->find_factor(target_factor.name);
327 if (!source_index.has_value())
333 auto const& source_factor = source_impl->factors()[*source_index];
334 if (source_factor.factor != target_factor.factor)
336 throw std::invalid_argument(
"cannot coerce between differently typed symmetry components");
338 target_codes[i] = source_codes[*source_index];
341 for (std::size_t i = 0; i < source_impl->factor_count(); ++i)
343 auto const& source_factor = source_impl->factors()[i];
344 auto const target_index = target_impl->find_factor(source_factor.name);
345 if (!target_index.has_value() && source_codes[i] != 0)
347 throw std::invalid_argument(
"cannot drop a non-identity symmetry component during coercion");
351 return QNum(target, target_impl->pack(target_codes));
360 if (lhs.symmetry() != rhs.symmetry())
362 throw std::invalid_argument(
"QNum operator+ requires identical symmetry contexts");
365 auto const* impl = lhs.sym_;
366 auto const lhs_codes = impl->unpack(lhs.code_);
367 auto const rhs_codes = impl->unpack(rhs.code_);
368 std::vector<std::uint64_t> out_codes(impl->factor_count(), 0);
370 for (std::size_t i = 0; i < out_codes.size(); ++i)
372 auto const* factor = impl->factors()[i].factor;
373 out_codes[i] = factor->add_codes(lhs_codes[i], rhs_codes[i]);
376 return QNum(lhs.symmetry(), impl->pack(out_codes));
384 auto const* impl = q.sym_;
385 auto const codes = impl->unpack(q.code_);
387 for (std::size_t i = 0; i < codes.size(); ++i)
393 result += impl->factors()[i].name;
395 result += impl->factors()[i].factor->format_code(codes[i]);
404template <>
struct hash<
uni20::QNum>
409 auto operator()(
uni20::QNum const& q)
const noexcept -> std::size_t
411 auto const sym_hash = std::hash<void const*>{}(q.
valid() ? q.
symmetry().impl() :
nullptr);
412 auto const code_hash = std::hash<std::uint64_t>{}(q.
valid() ? q.
raw_code() : 0);
413 return sym_hash ^ (code_hash + 0x9e3779b97f4a7c15ULL + (sym_hash << 6) + (sym_hash >> 2));
Explicit sparse tensor space represented as quantum numbers with one shared symmetry.
Definition qnum.hpp:102
auto size() const -> std::size_t
Return the number of stored quantum numbers.
Definition qnum.hpp:125
QNumList(Symmetry sym)
Construct an empty list tied to one symmetry.
Definition qnum.hpp:106
auto operator==(QNumList const &other) const -> bool=default
Compare two sparse irrep lists for exact equality.
void push_back(QNum q)
Append a quantum number with the matching symmetry.
Definition qnum.hpp:133
void normalize()
Sort entries and remove duplicates.
Definition qnum.hpp:159
auto empty() const -> bool
Return whether the list is empty.
Definition qnum.hpp:129
auto end() const
Return an iterator past the last element.
Definition qnum.hpp:176
auto contains(QNum q) const -> bool
Return whether the list already contains the given quantum number.
Definition qnum.hpp:145
QNumList(Symmetry sym, std::initializer_list< QNum > values)
Construct a list from initial values.
Definition qnum.hpp:111
auto operator[](std::size_t index) const -> QNum const &
Return indexed element access.
Definition qnum.hpp:168
void sort()
Sort entries by canonical packed order.
Definition qnum.hpp:152
void clear()
Remove all quantum numbers while keeping the list symmetry.
Definition qnum.hpp:140
auto symmetry() const -> Symmetry
Return the symmetry shared by all entries.
Definition qnum.hpp:121
auto begin() const
Return an iterator to the first element.
Definition qnum.hpp:172
One irrep label together with the symmetry context needed to interpret it.
Definition qnum.hpp:29
friend auto degree(QNum const &) -> int
Return the integral degree of a quantum number.
Definition qnum.hpp:270
friend auto qdim(QNum const &) -> double
Return the quantum dimension of a quantum number.
Definition qnum.hpp:255
QNum(Symmetry sym, std::uint64_t code)
Construct from a symmetry handle and a 63-bit inline packed code.
Definition qnum.hpp:37
friend auto to_string(QNum const &) -> std::string
Format a quantum number as comma-separated named components.
Definition qnum.hpp:382
friend auto coerce(QNum const &, Symmetry) -> QNum
Coerce a quantum number into a related symmetry by named components.
Definition qnum.hpp:310
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
QNum()=default
Construct an invalid quantum number.
friend auto make_qnum(Symmetry, std::initializer_list< std::pair< std::string_view, U1 > >) -> QNum
Construct a packed QNum from named U(1) component values.
Definition qnum.hpp:202
auto operator==(QNum const &other) const -> bool=default
Compare two quantum numbers for exact identity.
friend auto dual(QNum const &) -> QNum
Return the dual irrep of a quantum number.
Definition qnum.hpp:236
friend auto u1_component(QNum const &, std::string_view) -> U1
Read one named U(1) component from a quantum number.
Definition qnum.hpp:286
friend auto operator+(QNum const &, QNum const &) -> QNum
Add two quantum numbers when the fusion result is uniquely defined.
Definition qnum.hpp:358
friend auto is_identity(QNum const &) -> bool
Return whether a quantum number is the identity irrep.
Definition qnum.hpp:250
auto raw_code() const -> std::uint64_t
Return the inline packed irrep code.
Definition qnum.hpp:59
static auto identity(Symmetry sym) -> QNum
Return the identity irrep of a given symmetry.
Definition qnum.hpp:73
Public handle to a canonicalized direct-product symmetry specification.
Definition symmetry.hpp:24
Value-level quantum number type representing one U(1) irrep.
Definition u1.hpp:29
locale_t value
Definition data_table.cpp:49
Definition async/async.hpp:26
auto u1_component(QNum const &q, std::string_view name) -> U1
Read one named U(1) component from a quantum number.
Definition qnum.hpp:286
auto degree(QNum const &q) -> int
Return the integral degree of a quantum number.
Definition qnum.hpp:270
auto qdim(QNum const &q) -> double
Return the quantum dimension of a quantum number.
Definition qnum.hpp:255
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
auto coerce(QNum const &q, Symmetry target) -> QNum
Coerce a quantum number into a related symmetry by named components.
Definition qnum.hpp:310
auto to_string(basic_half_int< T > value) -> std::string
Format a half-integer as an integer or decimal .5.
Definition half_int.hpp:477
auto is_identity(QNum const &q) -> bool
Return whether a quantum number is the identity irrep.
Definition qnum.hpp:250
auto make_qnum(Symmetry sym, std::initializer_list< std::pair< std::string_view, U1 > > values) -> QNum
Construct a packed QNum from named U(1) component values.
Definition qnum.hpp:202
Defines the lightweight public handle for canonicalized direct-product symmetries.