|
1 | 1 | # ZNIrrep: irreps of Z_N are labelled by integers mod N; do we ever want N > 64? |
2 | 2 | """ |
3 | | - struct ZNIrrep{N} <: AbstractIrrep{ℤ{N}} |
| 3 | + struct ZNIrrep{N, T <: Unsigned} <: AbstractIrrep{ℤ{N}} |
4 | 4 | ZNIrrep{N}(n::Integer) |
5 | 5 | Irrep[ℤ{N}](n::Integer) |
6 | 6 |
|
7 | | -Represents irreps of the group ``ℤ_N`` for some value of `N<64`. (We need 2*(N-1) <= 127 in |
8 | | -order for a ⊗ b to work correctly.) For `N` equals `2`, `3` or `4`, `ℤ{N}` can be replaced |
9 | | -by `ℤ₂`, `ℤ₃`, `ℤ₄`. An arbitrary `Integer` `n` can be provided to the constructor, but only |
10 | | -the value `mod(n, N)` is relevant. |
| 7 | +Represents irreps of the group ``ℤ_N`` for some value of `N`. |
| 8 | +For `N` equals `2`, `3` or `4`, `ℤ{N}` can be replaced by [`ℤ₂`](@ref), [`ℤ₃`](@ref), and [`ℤ₄`](@ref). |
| 9 | +An arbitrary `Integer` `n` can be provided to the constructor, but only the value `mod(n, N)` is relevant. |
| 10 | +
|
| 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 | +
|
| 14 | +See also [`charge`](@ref)` and [`modulus`](@ref) to extract the relevant data. |
11 | 15 |
|
12 | 16 | ## Fields |
13 | | -- `n::Int8`: the integer label of the irrep, modulo `N`. |
| 17 | +- `n::T`: the integer label of the irrep, modulo `N`. |
14 | 18 | """ |
15 | | -struct ZNIrrep{N} <: AbstractIrrep{ℤ{N}} |
16 | | - n::Int8 |
| 19 | +struct ZNIrrep{N, T <: Unsigned} <: AbstractIrrep{ℤ{N}} |
| 20 | + n::T |
17 | 21 | function ZNIrrep{N}(n::Integer) where {N} |
18 | | - @assert N < 64 |
19 | | - return new{N}(mod(n, N)) |
| 22 | + T = _integer_type(N) |
| 23 | + return new{N, T}(T(mod(n, N))) |
| 24 | + 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)) |
20 | 29 | end |
21 | 30 | end |
22 | | -Base.getindex(::IrrepTable, ::Type{ℤ{N}}) where {N} = ZNIrrep{N} |
| 31 | + |
| 32 | +""" |
| 33 | + modulus(c::ZNIrrep{N}) -> N |
| 34 | + modulus(::Type{<:ZNIrrep{N}}) -> N |
| 35 | +
|
| 36 | +The order of the cyclic group, or the modulus of the charge labels. |
| 37 | +""" |
| 38 | +modulus(c::ZNIrrep) = modulus(typeof(c)) |
| 39 | +modulus(::Type{<:ZNIrrep{N}}) where {N} = N |
| 40 | + |
| 41 | +""" |
| 42 | + charge(c::ZNIrrep) -> Int |
| 43 | +
|
| 44 | +The charge label of the irrep `c`. |
| 45 | +""" |
| 46 | +charge(c::ZNIrrep) = Int(c.n) |
| 47 | + |
| 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 |
| 56 | + |
| 57 | +Base.getindex(::IrrepTable, ::Type{ℤ{N}}) where {N} = ZNIrrep{N, _integer_type(N)} |
23 | 58 | Base.convert(Z::Type{<:ZNIrrep}, n::Real) = Z(n) |
24 | | -const Z2Irrep = ZNIrrep{2} |
25 | | -const Z3Irrep = ZNIrrep{3} |
26 | | -const Z4Irrep = ZNIrrep{4} |
27 | | - |
28 | | -unit(::Type{ZNIrrep{N}}) where {N} = ZNIrrep{N}(0) |
29 | | -dual(c::ZNIrrep{N}) where {N} = ZNIrrep{N}(-c.n) |
30 | | -⊗(c1::ZNIrrep{N}, c2::ZNIrrep{N}) where {N} = (ZNIrrep{N}(c1.n + c2.n),) |
31 | | - |
32 | | -Base.IteratorSize(::Type{SectorValues{ZNIrrep{N}}}) where {N} = HasLength() |
33 | | -Base.length(::SectorValues{ZNIrrep{N}}) where {N} = N |
34 | | -function Base.iterate(::SectorValues{ZNIrrep{N}}, i = 0) where {N} |
35 | | - return i == N ? nothing : (ZNIrrep{N}(i), i + 1) |
| 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)) |
| 64 | +# 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))),) |
| 67 | + |
| 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) |
36 | 72 | end |
37 | | -function Base.getindex(::SectorValues{ZNIrrep{N}}, i::Int) where {N} |
38 | | - return 1 <= i <= N ? ZNIrrep{N}(i - 1) : throw(BoundsError(values(ZNIrrep{N}), i)) |
| 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)) |
39 | 75 | end |
40 | | -findindex(::SectorValues{ZNIrrep{N}}, c::ZNIrrep{N}) where {N} = c.n + 1 |
| 76 | +findindex(::SectorValues{ZNIrrep{N, T}}, c::ZNIrrep{N, T}) where {N, T} = c.n + 1 |
| 77 | + |
| 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) |
41 | 80 |
|
42 | | -Base.hash(c::ZNIrrep{N}, h::UInt) where {N} = hash(c.n, h) |
43 | | -Base.isless(c1::ZNIrrep{N}, c2::ZNIrrep{N}) where {N} = isless(c1.n, c2.n) |
| 81 | +# ensure the printing uses `Int`. |
| 82 | +function Base.show(io::IO, c::ZNIrrep) |
| 83 | + I = typeof(c) |
| 84 | + print_type = get(io, :typeinfo, nothing) !== I |
| 85 | + print_type && print(io, type_repr(I), '(') |
| 86 | + print(io, charge(c)) |
| 87 | + print_type && print(io, ')') |
| 88 | + return nothing |
| 89 | +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