Skip to content

Commit af845df

Browse files
authored
Unbreak breaking change for ZNIrrep (#37)
* fix oopsie with ZNIrrep * bump version
1 parent c16e337 commit af845df

File tree

4 files changed

+71
-69
lines changed

4 files changed

+71
-69
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "TensorKitSectors"
22
uuid = "13a9c161-d5da-41f0-bcbd-e1a08ae0647f"
33
authors = ["Lukas Devos", "Jutho Haegeman"]
4-
version = "0.3.1"
4+
version = "0.3.2"
55

66
[deps]
77
HalfIntegers = "f0d1745a-41c9-11e9-1dd9-e5d34d218721"

src/TensorKitSectors.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export unit, rightunit, leftunit, allunits, isunit
1919
export triangle_equation, pentagon_equation, hexagon_equation
2020

2121
export Trivial
22-
export Z2Irrep, Z3Irrep, Z4Irrep, ZNIrrep, U1Irrep
22+
export Z2Irrep, Z3Irrep, Z4Irrep, ZNIrrep, LargeZNIrrep, U1Irrep
2323
export D3Irrep, D4Irrep, DNIrrep, CU1Irrep
2424
export SU2Irrep
2525
export ZNElement, Z2Element, Z3Element, Z4Element

src/irreps/znirrep.jl

Lines changed: 62 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,107 @@
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+
24
"""
3-
struct ZNIrrep{N, T <: Unsigned} <: AbstractIrrep{ℤ{N}}
5+
struct ZNIrrep{N} <: AbstractIrrep{ℤ{N}}
46
ZNIrrep{N}(n::Integer)
57
Irrep[ℤ{N}](n::Integer)
68
79
Represents irreps of the group ``ℤ_N`` for some value of `N`.
810
For `N` equals `2`, `3` or `4`, `ℤ{N}` can be replaced by [`ℤ₂`](@ref), [`ℤ₃`](@ref), and [`ℤ₄`](@ref).
911
An arbitrary `Integer` `n` can be provided to the constructor, but only the value `mod(n, N)` is relevant.
1012
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`.
1316
1417
See also [`charge`](@ref) and [`modulus`](@ref) to extract the relevant data.
1518
1619
## Fields
17-
- `n::T`: the integer label of the irrep, modulo `N`.
20+
- `n::UInt8`: the integer label of the irrep, modulo `N`.
1821
"""
19-
struct ZNIrrep{N, T <: Unsigned} <: AbstractIrrep{ℤ{N}}
20-
n::T
22+
struct ZNIrrep{N} <: AbstractIrrep{ℤ{N}}
23+
n::UInt8
2124
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)))
2427
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)))
2951
end
52+
3053
end
3154

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+
3260
"""
3361
modulus(c::ZNIrrep{N}) -> N
3462
modulus(::Type{<:ZNIrrep{N}}) -> N
3563
3664
The order of the cyclic group, or the modulus of the charge labels.
3765
"""
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
4068

4169
"""
4270
charge(c::ZNIrrep) -> Int
4371
4472
The charge label of the irrep `c`.
4573
"""
46-
charge(c::ZNIrrep) = Int(c.n)
74+
charge(c::AnyZNIrrep) = Int(c.n)
4775

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)
5678

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))
6481
# 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),)
6784

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))
7593
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
7795

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)
8098

8199
# ensure the printing uses `Int`.
82-
function Base.show(io::IO, c::ZNIrrep)
100+
function Base.show(io::IO, c::AnyZNIrrep)
83101
I = typeof(c)
84102
print_type = get(io, :typeinfo, nothing) !== I
85103
print_type && print(io, type_repr(I), '(')
86104
print(io, charge(c))
87105
print_type && print(io, ')')
88106
return nothing
89107
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

test/runtests.jl

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -100,20 +100,13 @@ end
100100
end
101101

102102
@testset "ZNIrrep edge cases" begin
103-
a = Irrep[Cyclic{255}](254)
104-
@test typeof(a) == ZNIrrep{255, UInt8}
105-
@test charge(dual(a)) == mod(-charge(a), 255)
106-
@test charge(only(a a)) == mod(charge(a) + charge(a), 255)
107-
108-
b = Irrep[Cyclic{256}](255)
109-
@test typeof(b) == ZNIrrep{256, UInt8}
110-
@test charge(dual(b)) == mod(-charge(b), 256)
111-
@test charge(only(b b)) == mod(charge(b) + charge(b), 256)
112-
113-
c = Irrep[Cyclic{257}](256)
114-
@test typeof(c) == ZNIrrep{257, UInt16}
115-
@test charge(dual(c)) == mod(-charge(c), 257)
116-
@test charge(only(c c)) == mod(charge(c) + charge(c), 257)
103+
for N in (127, 128, 129)
104+
a = Irrep[Cyclic{N}](-1)
105+
@test typeof(a) == ((N (typemax(UInt8) + 1) ÷ 2) ? ZNIrrep{N} : LargeZNIrrep{N})
106+
@test typeof(charge(a)) == Int
107+
@test charge(dual(a)) == mod(-charge(a), N)
108+
@test charge(only(a a)) == mod(charge(a) + charge(a), N)
109+
end
117110
end
118111

119112
include("multifusion.jl")

0 commit comments

Comments
 (0)