|
1 | | -# ZNIrrep: irreps of Z_N are labelled by integers mod N; do we ever want N > 64? |
| 1 | +# ZNIrrep: irreps of Z_N are labelled by integers mod N; stored as UInt or UInt8 |
| 2 | +const SMALL_ZN_CUTOFF = (typemax(UInt8) + 1) ÷ 2 |
| 3 | + |
2 | 4 | """ |
3 | | - struct ZNIrrep{N, T <: Unsigned} <: AbstractIrrep{ℤ{N}} |
| 5 | + struct ZNIrrep{N} <: AbstractIrrep{ℤ{N}} |
4 | 6 | ZNIrrep{N}(n::Integer) |
5 | 7 | Irrep[ℤ{N}](n::Integer) |
6 | 8 |
|
7 | 9 | Represents irreps of the group ``ℤ_N`` for some value of `N`. |
8 | 10 | For `N` equals `2`, `3` or `4`, `ℤ{N}` can be replaced by [`ℤ₂`](@ref), [`ℤ₃`](@ref), and [`ℤ₄`](@ref). |
9 | 11 | An arbitrary `Integer` `n` can be provided to the constructor, but only the value `mod(n, N)` is relevant. |
10 | 12 |
|
11 | | -The type of the stored integer `T` can either be explicitly provided, or will automatically be determined |
12 | | -to be the smallest unsigned integer type that fits all possible irreps for the given `N`. |
| 13 | +The type of the stored integer (`UInt8`) requires `N ≤ $SMALL_ZN_CUTOFF`. |
| 14 | +Larger values of `N` should use the [`LargeZNIrrep`](@ref) instead. |
| 15 | +The constructor `Irrep[ℤ{N}]` should be preferred, as it will automatically select the most efficient storage type for a given value of `N`. |
13 | 16 |
|
14 | 17 | See also [`charge`](@ref) and [`modulus`](@ref) to extract the relevant data. |
15 | 18 |
|
16 | 19 | ## Fields |
17 | | -- `n::T`: the integer label of the irrep, modulo `N`. |
| 20 | +- `n::UInt8`: the integer label of the irrep, modulo `N`. |
18 | 21 | """ |
19 | | -struct ZNIrrep{N, T <: Unsigned} <: AbstractIrrep{ℤ{N}} |
20 | | - n::T |
| 22 | +struct ZNIrrep{N} <: AbstractIrrep{ℤ{N}} |
| 23 | + n::UInt8 |
21 | 24 | function ZNIrrep{N}(n::Integer) where {N} |
22 | | - T = _integer_type(N) |
23 | | - return new{N, T}(T(mod(n, N))) |
| 25 | + N ≤ SMALL_ZN_CUTOFF || throw(DomainError(N, "N exceeds the maximal value, use `LargeZNIrrep` instead")) |
| 26 | + return new{N}(UInt8(mod(n, N))) |
24 | 27 | end |
25 | | - function ZNIrrep{N, T}(n::Integer) where {N, T <: Unsigned} |
26 | | - N ≤ typemax(T) + 1 || |
27 | | - throw(TypeError(:ZNIrrep, ZNIrrep{N, T}, ZNIrrep{N, _integer_type(N)})) |
28 | | - return new{N, T}(mod(n, N)) |
| 28 | +end |
| 29 | + |
| 30 | +""" |
| 31 | + struct LargeZNIrrep{N} <: AbstractIrrep{ℤ{N}} |
| 32 | + LargeZNIrrep{N}(n::Integer) |
| 33 | + Irrep[ℤ{N}](n::Integer) |
| 34 | +
|
| 35 | +Represents irreps of the group ``ℤ_N`` for some value of `N`, which is typically larger than $SMALL_ZN_CUTOFF. |
| 36 | +For smaller values of `N`, the [`ZNIrrep}`](@ref) sector type should be used instead. |
| 37 | +An arbitrary `Integer` `n` can be provided to the constructor, but only the value `mod(n, N)` is relevant. |
| 38 | +
|
| 39 | +The constructor `Irrep[ℤ{N}]` should be preferred, as it will automatically select the most efficient storage type for a given value of `N`. |
| 40 | +
|
| 41 | +See also [`charge`](@ref) and [`modulus`](@ref) to extract the relevant data. |
| 42 | +
|
| 43 | +## Fields |
| 44 | +- `n::UInt`: the integer label of the irrep, modulo `N`. |
| 45 | +""" |
| 46 | +struct LargeZNIrrep{N} <: AbstractIrrep{ℤ{N}} |
| 47 | + n::UInt |
| 48 | + function LargeZNIrrep{N}(n::Integer) where {N} |
| 49 | + N ≤ (typemax(UInt) ÷ 2) || throw(DomainError(N, "N exceeds the maximal value")) |
| 50 | + return new{N}(UInt(mod(n, N))) |
29 | 51 | end |
| 52 | + |
30 | 53 | end |
31 | 54 |
|
| 55 | +const AnyZNIrrep{N} = Union{ZNIrrep{N}, LargeZNIrrep{N}} |
| 56 | +const Z2Irrep = ZNIrrep{2} |
| 57 | +const Z3Irrep = ZNIrrep{3} |
| 58 | +const Z4Irrep = ZNIrrep{4} |
| 59 | + |
32 | 60 | """ |
33 | 61 | modulus(c::ZNIrrep{N}) -> N |
34 | 62 | modulus(::Type{<:ZNIrrep{N}}) -> N |
35 | 63 |
|
36 | 64 | The order of the cyclic group, or the modulus of the charge labels. |
37 | 65 | """ |
38 | | -modulus(c::ZNIrrep) = modulus(typeof(c)) |
39 | | -modulus(::Type{<:ZNIrrep{N}}) where {N} = N |
| 66 | +modulus(c::AnyZNIrrep) = modulus(typeof(c)) |
| 67 | +modulus(::Type{<:AnyZNIrrep{N}}) where {N} = N |
40 | 68 |
|
41 | 69 | """ |
42 | 70 | charge(c::ZNIrrep) -> Int |
43 | 71 |
|
44 | 72 | The charge label of the irrep `c`. |
45 | 73 | """ |
46 | | -charge(c::ZNIrrep) = Int(c.n) |
| 74 | +charge(c::AnyZNIrrep) = Int(c.n) |
47 | 75 |
|
48 | | -Base.@assume_effects :foldable function _integer_type(N::Integer) |
49 | | - N <= 0 && throw(DomainError(N, "N should be positive")) |
50 | | - for T in (UInt8, UInt16, UInt32, UInt64) |
51 | | - # T needs to fit a |
52 | | - N ≤ (typemax(T) + 1) && return T |
53 | | - end |
54 | | - throw(DomainError(N, "N is too large")) |
55 | | -end |
| 76 | +Base.getindex(::IrrepTable, ::Type{ℤ{N}}) where {N} = N ≤ SMALL_ZN_CUTOFF ? ZNIrrep{N} : LargeZNIrrep{N} |
| 77 | +Base.convert(Z::Type{<:AnyZNIrrep}, n::Real) = Z(n) |
56 | 78 |
|
57 | | -Base.getindex(::IrrepTable, ::Type{ℤ{N}}) where {N} = ZNIrrep{N, _integer_type(N)} |
58 | | -Base.convert(Z::Type{<:ZNIrrep}, n::Real) = Z(n) |
59 | | -const Z2Irrep = ZNIrrep{2, UInt8} |
60 | | -const Z3Irrep = ZNIrrep{3, UInt8} |
61 | | -const Z4Irrep = ZNIrrep{4, UInt8} |
62 | | - |
63 | | -unit(::Type{ZNIrrep{N, T}}) where {N, T} = ZNIrrep{N, T}(zero(T)) |
| 79 | +unit(::Type{ZNIrrep{N}}) where {N} = ZNIrrep{N}(zero(UInt8)) |
| 80 | +unit(::Type{LargeZNIrrep{N}}) where {N} = LargeZNIrrep{N}(zero(UInt)) |
64 | 81 | # be careful with `-` for unsigned integers! |
65 | | -dual(c::ZNIrrep{N, T}) where {N, T} = ZNIrrep{N, T}(N - c.n) |
66 | | -⊗(c1::ZNIrrep{N, T}, c2::ZNIrrep{N, T}) where {N, T} = (ZNIrrep{N, T}(modular_add(c1.n, c2.n, Val(N))),) |
| 82 | +dual(c::AnyZNIrrep{N}) where {N} = typeof(c)(N - c.n) |
| 83 | +⊗(c1::I, c2::I) where {I <: AnyZNIrrep} = (I(c1.n + c2.n),) |
67 | 84 |
|
68 | | -Base.IteratorSize(::Type{SectorValues{ZNIrrep{N, T}}}) where {N, T} = HasLength() |
69 | | -Base.length(::SectorValues{ZNIrrep{N, T}}) where {N, T} = N |
70 | | -function Base.iterate(::SectorValues{ZNIrrep{N, T}}, i = 0) where {N, T} |
71 | | - return i == N ? nothing : (ZNIrrep{N, T}(i), i + 1) |
72 | | -end |
73 | | -function Base.getindex(::SectorValues{ZNIrrep{N, T}}, i::Int) where {N, T} |
74 | | - return 1 <= i <= N ? ZNIrrep{N, T}(i - 1) : throw(BoundsError(values(ZNIrrep{N}), i)) |
| 85 | +Base.IteratorSize(::Type{SectorValues{<:ZNIrrep}}) = HasLength() |
| 86 | +# for larger values it doesn't make sense to store the sectors as a tuple |
| 87 | +Base.IteratorSize(::Type{SectorValues{<:LargeZNIrrep}}) = SizeUnknown() |
| 88 | + |
| 89 | +Base.length(::SectorValues{I}) where {I <: AnyZNIrrep} = modulus(I) |
| 90 | +Base.iterate(::SectorValues{I}, i = 0) where {I <: AnyZNIrrep} = i == modulus(I) ? nothing : (I(i), i + 1) |
| 91 | +function Base.getindex(::SectorValues{I}, i::Int) where {I <: AnyZNIrrep} |
| 92 | + return 1 <= i <= modulus(I) ? I(i - 1) : throw(BoundsError(values(I), i)) |
75 | 93 | end |
76 | | -findindex(::SectorValues{ZNIrrep{N, T}}, c::ZNIrrep{N, T}) where {N, T} = c.n + 1 |
| 94 | +findindex(::SectorValues{I}, c::I) where {I <: AnyZNIrrep} = charge(c) + 1 |
77 | 95 |
|
78 | | -Base.hash(c::ZNIrrep{N, T}, h::UInt) where {N, T} = hash(c.n, h) |
79 | | -Base.isless(c1::ZNIrrep{N, T}, c2::ZNIrrep{N, T}) where {N, T} = isless(c1.n, c2.n) |
| 96 | +Base.hash(c::AnyZNIrrep, h::UInt) = hash(c.n, h) |
| 97 | +Base.isless(c1::I, c2::I) where {I <: AnyZNIrrep} = isless(c1.n, c2.n) |
80 | 98 |
|
81 | 99 | # ensure the printing uses `Int`. |
82 | | -function Base.show(io::IO, c::ZNIrrep) |
| 100 | +function Base.show(io::IO, c::AnyZNIrrep) |
83 | 101 | I = typeof(c) |
84 | 102 | print_type = get(io, :typeinfo, nothing) !== I |
85 | 103 | print_type && print(io, type_repr(I), '(') |
86 | 104 | print(io, charge(c)) |
87 | 105 | print_type && print(io, ')') |
88 | 106 | return nothing |
89 | 107 | end |
90 | | - |
91 | | -# compute x + y mod N, requires 0 <= x < N and 0 <= y < N (unchecked!) |
92 | | -function modular_add(x::T, y::T, ::Val{N}) where {T <: Unsigned, N} |
93 | | - Tmax = typemax(T) + 1 |
94 | | - 0 < N ≤ Tmax || throw(DomainError(N, "N is too large")) |
95 | | - N ≤ (typemax(T) + 1) ÷ 2 && return x + y |
96 | | - r, flag = Base.add_with_overflow(x, y) |
97 | | - return ifelse(flag, (Tmax - N) + r, r) |
98 | | -end |
|
0 commit comments