Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
c4ef220
alternating group
borisdevos Nov 12, 2025
7005e04
start of ANIrrep
borisdevos Nov 12, 2025
2b2c351
rename file
borisdevos Nov 13, 2025
71364b3
get fusion working
borisdevos Nov 13, 2025
5b565d6
show and export
borisdevos Nov 13, 2025
4f8bcf4
fusion tensor
borisdevos Nov 13, 2025
073a097
start of hardcoding fusion tensors
borisdevos Nov 13, 2025
5fe37f4
remove trace in Fsymbol
borisdevos Nov 14, 2025
c73027a
bosonic braiding
borisdevos Nov 14, 2025
987409b
fix show
borisdevos Nov 14, 2025
77dda09
keep product iterator to unique outputs
borisdevos Nov 14, 2025
90e2ba9
remove aliases for N < 4
borisdevos Nov 14, 2025
2cc41b3
remove show method for `ANIrrep`
borisdevos Nov 16, 2025
d1cde78
fix length of product iterator
borisdevos Nov 16, 2025
68375f6
make `Fsymbol` type-stable
borisdevos Nov 16, 2025
237212e
fix length of iterator
borisdevos Nov 17, 2025
00817e3
fix rsymbol
borisdevos Nov 17, 2025
6f6b09d
minor code suggestions
borisdevos Nov 17, 2025
55b9608
fix some things to be clear N < 5 isn't available
borisdevos Nov 17, 2025
feb600d
fix Rsymbol
borisdevos Nov 17, 2025
9fe524a
rename fusion tensor help functions
borisdevos Nov 17, 2025
5fe2841
format
borisdevos Nov 17, 2025
fc4f1c2
generalise orthogonality of fusion tensor check for `GenericFusion`
borisdevos Nov 18, 2025
acdfa00
add to sectorlist in tests
borisdevos Nov 18, 2025
bddd5c7
Merge branch 'main' into bd/repa4
borisdevos Nov 18, 2025
78cd1c0
Merge branch 'main' into bd/repa4
borisdevos Nov 26, 2025
f779b40
clean up and shorten code
borisdevos Nov 27, 2025
45ef41a
add docstring for `fusiontensor`
borisdevos Nov 27, 2025
05404bd
code suggestions
borisdevos Nov 27, 2025
f7aa50b
fix counting number of irreps of A_N
borisdevos Nov 27, 2025
ccea126
replace more partitions by irreps
borisdevos Nov 27, 2025
27df99b
bring back sectorscalartype
borisdevos Nov 27, 2025
5ab34f9
minor cleanup
borisdevos Nov 28, 2025
dc64831
some more cleanup
lkdvos Nov 29, 2025
4a694bb
remove stray ANIrrep
borisdevos Dec 1, 2025
e793ae7
Merge branch 'main' of https://github.com/QuantumKitHub/TensorKitSect…
borisdevos Dec 1, 2025
164e3aa
add source to motivate choice of basis
borisdevos Dec 9, 2025
99f6d4b
Merge branch 'main' into bd/repa4
borisdevos Dec 9, 2025
099bca6
reduce allocations
borisdevos Dec 9, 2025
ef61de0
Update src/irreps/irreps.jl
borisdevos Dec 9, 2025
b9e74b5
intertwiner check
borisdevos Dec 10, 2025
d23381d
Merge branch 'bd/repa4' of https://github.com/QuantumKitHub/TensorKit…
borisdevos Dec 10, 2025
71cae58
move intertwiner test to run it
borisdevos Dec 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/TensorKitSectors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export triangle_equation, pentagon_equation, hexagon_equation
export Trivial
export Z2Irrep, Z3Irrep, Z4Irrep, ZNIrrep, LargeZNIrrep, U1Irrep
export D3Irrep, D4Irrep, DNIrrep, CU1Irrep
export A4Irrep
export SU2Irrep
export ZNElement, Z2Element, Z3Element, Z4Element
export ProductSector, TimeReversed
Expand All @@ -35,6 +36,7 @@ export charge, modulus
# ---------------
export ⊠, ⊗, ×
export Cyclic, ℤ, ℤ₂, ℤ₃, ℤ₄, U₁, SU, SU₂, Dihedral, D₃, D₄, CU₁
export Alternating, A₄
export fℤ₂, fU₁, fSU₂

# public
Expand Down
10 changes: 10 additions & 0 deletions src/groups.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ group.
"""
abstract type Dihedral{N} <: Group end

"""
abstract type Alternating{N} <: Group

Type to represent the alternating group of order `N!/2`, which is the group
of even permutations on `N` elements.
"""
abstract type Alternating{N} <: Group end


"""
abstract type U₁ <: AbelianGroup
Expand Down Expand Up @@ -72,6 +80,7 @@ const ℤ₃ = ℤ{3}
const ℤ₄ = ℤ{4}
const D₃ = Dihedral{3}
const D₄ = Dihedral{4}
const A₄ = Alternating{4}
const SU₂ = SU{2}

type_repr(::Type{ℤ₂}) = "ℤ₂"
Expand All @@ -80,6 +89,7 @@ type_repr(::Type{ℤ₄}) = "ℤ₄"
type_repr(::Type{ℤ{N}}) where {N} = "ℤ{$N}"
type_repr(::Type{D₃}) = "D₃"
type_repr(::Type{D₄}) = "D₄"
type_repr(::Type{A₄}) = "A₄"
type_repr(::Type{SU₂}) = "SU₂"
type_repr(::Type{U₁}) = "U₁"
type_repr(::Type{CU₁}) = "CU₁"
Expand Down
164 changes: 164 additions & 0 deletions src/irreps/a4irrep.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
"""
struct A4Irrep <: AbstractIrrep{A₄}
A4Irrep(n::Integer)
Irrep[A₄](n::Integer)

Represents irreps of the alternating group ``A₄``.

## Fields

- `n::Int8`: the label of the irrep, corresponding to ``1``, ``1′``, ``1″`` and ``3``.
"""
struct A4Irrep <: AbstractIrrep{A₄}
n::Int8
function A4Irrep(n::Integer)
0 ≤ n < 4 || throw(ArgumentError("A4Irrep only has irrep labels in `0:3`"))
return new(n)
end
end

FusionStyle(::Type{A4Irrep}) = GenericFusion()
sectorscalartype(::Type{A4Irrep}) = Float64

unit(::Type{A4Irrep}) = A4Irrep(0)
dual(a::A4Irrep) = a.n == 3 ? a : A4Irrep((3 - a.n) % 3)

Base.hash(a::A4Irrep, h::UInt) = hash(a.n, h)
Base.convert(::Type{A4Irrep}, n::Integer) = A4Irrep(n)

Base.getindex(::IrrepTable, ::Type{A₄}) = A4Irrep
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that here you could in principle also register the lower order alternating group versions, something like

Base.getindex(::IrrepTable, ::Type{Alternating{3}}) = ZNIrrep{3}

though that might be more confusing than helpful?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though I started with including the lower degree groups, and whether or not it's confusing or helpful, I don't think that making these identifications is particularly useful.



# Sector iterator
# ---------------
Base.isless(a::A4Irrep, b::A4Irrep) = isless(a.n, b.n)
Base.IteratorSize(::Type{SectorValues{A4Irrep}}) = Base.HasLength()
Base.length(::SectorValues{A4Irrep}) = 4

Base.iterate(v::SectorValues{A4Irrep}, i = 1) = i > length(v) ? nothing : (v[i], i + 1)

@inline function Base.getindex(v::SectorValues{A4Irrep}, i::Int)
@boundscheck 1 <= i <= length(v) || throw(BoundsError(v, i))
return A4Irrep(i - 1)
end

findindex(::SectorValues{A4Irrep}, a::A4Irrep) = a.n + 1

# Product iterator
# ----------------

const A4IrrepProdIterator = SectorProductIterator{A4Irrep}
⊗(a::A4Irrep, b::A4Irrep) = SectorProductIterator((a <= b ? (a, b) : (b, a))...)

Base.IteratorSize(::Type{A4IrrepProdIterator}) = Base.HasLength()
Base.length(x::A4IrrepProdIterator) = (x.a == x.b == A4Irrep(3)) ? 4 : 1

function Base.iterate(p::A4IrrepProdIterator, state::Int = 1)
a, b = p.a, p.b
if state == 1
a.n == b.n == 3 && return (A4Irrep(state - 1), state + 1) # 3 ⊗ 3
b.n == 3 && return (b, 5) # x ⊗ 3 = 3
return (A4Irrep((a.n + b.n) % 3), 5) # 1d irreps ≡ Z3
elseif state < 5 # a == b == 3
return (A4Irrep(state - 1), state + 1)
else
return nothing
end
end

# Topological data
# ----------------
dim(a::A4Irrep) = a.n == 3 ? 3 : 1

function Nsymbol(a::A4Irrep, b::A4Irrep, c::A4Irrep)
# 3d irreps
a.n == b.n == 3 && return 1 + (c.n == 3)
(a.n == 3 || b.n == 3) && return Int(c.n == 3)
# 1d irreps
return Int((a.n + b.n) % 3 == c.n)
end


function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: A4Irrep}
T = sectorscalartype(I)
Nabe = Nsymbol(a, b, e)
Necd = Nsymbol(e, c, d)
Nbcf = Nsymbol(b, c, f)
Nafd = Nsymbol(a, f, d)

Nabe > 0 && Necd > 0 && Nbcf > 0 && Nafd > 0 ||
return zeros(T, Nabe, Necd, Nbcf, Nafd)

# fallback through fusiontensor for A4Irrep
A = fusiontensor(a, b, e)
B = fusiontensor(e, c, d)[:, :, 1, :]
C = fusiontensor(b, c, f)
D = fusiontensor(a, f, d)[:, :, 1, :]
@tensor F[-1, -2, -3, -4] := conj(D[1, 5, -4]) * conj(C[2, 4, 5, -3]) *
A[1, 2, 3, -1] * B[3, 4, -2]

return F
end

# bosonic
function Rsymbol(a::I, b::I, c::I) where {I <: A4Irrep}
Nabc = Nsymbol(a, b, c)
R = zeros(sectorscalartype(I), Nabc, Nabc)
Nabc == 0 && return R
if a == b == c == A4Irrep(3)
R[1, 1] = -1
R[2, 2] = 1
else
R[1, 1] = 1
end
return R
end

# choice of basis: https://journals.aps.org/rmp/pdf/10.1103/RevModPhys.82.2701
# triplet is a real representation -> can make all representation matrices real
function fusiontensor(a::I, b::I, c::I) where {I <: A4Irrep}
T = sectorscalartype(I)
Nabc = Nsymbol(a, b, c)
C = zeros(T, dim(a), dim(b), dim(c), Nabc)
isempty(C) && return C

ω = cis(2π / 3)

if a.n == b.n == 3 # 3 ⊗ 3
if c.n != 3 # singlets
invsqrt3 = 1 / sqrt(3.0)
for i in 1:3
j = 4 - mod1(i - c.n - 1, 3)
C[i, j, 1, 1] = invsqrt3
end
else # triplet: eq 38 in above reference
s2 = 1 / sqrt(2.0)
s6 = 1 / sqrt(6.0)

# antisymmetric channel
C[:, :, 1, 1] .= [0 0 0; 0 0 s2; 0 -s2 0]
C[:, :, 2, 1] .= [0 s2 0; -s2 0 0; 0 0 0]
C[:, :, 3, 1] .= [0 0 -s2; 0 0 0; s2 0 0]

# symmetric channel
C[:, :, 1, 2] .= [-2 * s6 0 0; 0 0 s6; 0 s6 0]
C[:, :, 2, 2] .= [0 s6 0; s6 0 0; 0 0 -2 * s6]
C[:, :, 3, 2] .= [0 0 s6; 0 -2 * s6 0; s6 0 0]
end
else
if a.n != 3 && b.n != 3 # 1d x 1d
C[1, 1, 1] = one(T)
elseif a.n == 3 && b.n != 3 # 3 x 1d
for i in 1:3
j = mod1(i - b.n, 3)
C[j, 1, i, 1] = one(T)
end
else # 1d x 3: reshape of 3 x 1d
for i in 1:3
j = mod1(i - a.n, 3)
C[1, j, i, 1] = one(T)
end
end
end
return C
end
1 change: 1 addition & 0 deletions src/irreps/irreps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,4 @@ include("u1irrep.jl")
include("dnirrep.jl")
include("cu1irrep.jl")
include("su2irrep.jl")
include("a4irrep.jl")
27 changes: 25 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,21 @@ const sectorlist = (
Trivial, PlanarTrivial,
Z2Irrep, Z3Irrep, Z4Irrep, Irrep[ℤ{200}], U1Irrep,
DNIrrep{3}, DNIrrep{4}, DNIrrep{5}, CU1Irrep,
SU2Irrep, NewSU2Irrep,
A4Irrep, SU2Irrep, NewSU2Irrep,
FibonacciAnyon, IsingAnyon, FermionParity,
FermionParity ⊠ FermionParity,
Z3Irrep ⊠ Z4Irrep, FermionParity ⊠ U1Irrep ⊠ SU2Irrep,
FermionParity ⊠ SU2Irrep ⊠ SU2Irrep, NewSU2Irrep ⊠ NewSU2Irrep,
NewSU2Irrep ⊠ SU2Irrep, FermionParity ⊠ SU2Irrep ⊠ NewSU2Irrep,
FibonacciAnyon ⊠ FibonacciAnyon ⊠ Z2Irrep,
A4Irrep ⊠ Z2Irrep, A4Irrep ⊠ SU2Irrep,
Z2Element{0}, Z2Element{1},
Z3Element{0}, Z3Element{1}, Z3Element{2},
Z4Element{0}, Z4Element{1}, Z4Element{2},
Z3Element{1} ⊠ SU2Irrep,
FibonacciAnyon ⊠ Z4Element{3},
TimeReversed{Z2Irrep},
TimeReversed{Z3Irrep}, TimeReversed{Z4Irrep},
TimeReversed{Z3Irrep}, TimeReversed{Z4Irrep}, TimeReversed{A4Irrep},
TimeReversed{U1Irrep}, TimeReversed{CU1Irrep}, TimeReversed{SU2Irrep},
TimeReversed{FibonacciAnyon}, TimeReversed{IsingAnyon},
TimeReversed{FermionParity},
Expand All @@ -46,6 +47,28 @@ using .SectorTestSuite
end
end

@testset "Intertwiner relation for A4Irrep" begin
ω = cis(2π / 3)
T3 = [1 0 0; 0 ω 0; 0 0 ω^2]
T(a::Int8) = (a == 3) ? T3 : hcat(ω^(a))
S3 = 1 / 3 * [-1 2 2; 2 -1 2; 2 2 -1]
S(a::Int8) = (a == 3) ? S3 : hcat(1)
for a in smallset(A4Irrep), b in smallset(A4Irrep)
for c in ⊗(a, b)
C = fusiontensor(a, b, c)
Ta, Tb, Tc = T(a.n), T(b.n), T(c.n)
Sa, Sb, Sc = S(a.n), S(b.n), S(c.n)
for μ in 1:Nsymbol(a, b, c)
Cmat = reshape(view(C, :, :, :, μ), (dim(a) * dim(b), dim(c)))
L_T = Cmat' * kron(Ta, Tb) * Cmat
L_S = Cmat' * kron(Sa, Sb) * Cmat
@test isapprox(L_T, Tc; atol = 1.0e-12)
@test isapprox(L_S, Sc; atol = 1.0e-12)
end
end
end
end

@testset "Deligne product" begin
sectorlist′ = (Trivial, sectorlist...)
for I1 in sectorlist′, I2 in sectorlist′
Expand Down