Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 1 addition & 1 deletion src/TensorKitSectors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export Irrep, GroupElement
export Nsymbol, Fsymbol, Rsymbol, Asymbol, Bsymbol
export sectorscalartype, fusionscalartype, braidingscalartype, dimscalartype
export dim, sqrtdim, invsqrtdim, frobenius_schur_indicator, frobenius_schur_phase, twist, fusiontensor, dual
export topological_spin, hopflink, Tmatrix, Smatrix, ismodular, topological_central_charge
export topological_spin, hopflink, Tmatrix, Smatrix, ismodular, hassymmetricbraiding, istransparent, centralizer, topological_central_charge
export otimes, deligneproduct, times
export FusionStyle, UniqueFusion, MultipleFusion, SimpleFusion, GenericFusion, MultiplicityFreeFusion
export BraidingStyle, NoBraiding, HasBraiding, SymmetricBraiding, Bosonic, Fermionic, Anyonic
Expand Down
36 changes: 32 additions & 4 deletions src/sectors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -691,15 +691,15 @@ hopflink(a::I, b::I) where {I <: Sector} = sum(dim(c) * tr(Rsymbol(a, b, c) * Rs
"""
Smatrix(::Type{I}) where {I <: Sector}

Return the S-matrix of the sector type `I`, which is a matrix containing the hopflinks of all pairs of sectors of type `I`.
Return the S-matrix of the sector type `I`, which is a matrix containing the hopflinks of all pairs of sectors of type `I`, with the second sector being taken dual.
The S-matrix is not normalized by the total quantum dimension here.
"""
function Smatrix(::Type{I}) where {I <: Sector}
Base.IteratorSize(values(I)) isa Base.IsInfinite &&
throw(ArgumentError("Only defined for sectors with a finite number of simple objects"))
vals = values(I)
l = length(vals)
return reshape([hopflink(a, b) for a in vals, b in vals], (l, l))
return reshape([hopflink(a, dual(b)) for a in vals, b in vals], (l, l))
end

"""
Expand All @@ -712,15 +712,43 @@ function ismodular(::Type{II}; kwargs...) where {II <: Sector}
return isapprox(s' * s, dim(II)^2 * I(size(s)[1]); kwargs...)
end

"""
hassymmetricbraiding(::Type{I}; kwargs...) where {I <: Sector}

Check whether a sector type `I` is symmetric, i.e. the S-matrix is fully degenerate.
"""
function hassymmetricbraiding(::Type{I}; kwargs...) where {I <: Sector}
@assert BraidingStyle(I) isa HasBraiding "The sector type $I is not braided"
if BraidingStyle(I) isa SymmetricBraiding
return true
else
return all(a -> istransparent(a; kwargs...), values(I))
end
end

"""
istransparent(a::I; kwargs...) where {I <: Sector}

Check whether a sector `a` in the sector type `I` braids trivially with other sectors in `I`.
"""
istransparent(a::I; kwargs...) where {I <: Sector} = all(b -> isapprox(hopflink(a, b), dim(a) * dim(b); kwargs...), values(I))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could this also check that Rsymbol == I directly, or is that not sufficient/required?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I see, I should mean double braiding trivial. Therefore a fermion is also accounted as transparent, because its braid with another fermion in the front or not is not important.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Half braiding is a gauge choice, while double braiding, then taking trace, is gauge independent.

@Chenqitrg Chenqitrg Apr 23, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The Corollary 2.14 of the same paper https://arxiv.org/abs/math/0201017 states that:
a simple object $X$ is central (called transparent here) if and only if for every simple object $Y$, the S matrix element $S_{XY}$ can be factorized into a product of two quantum dimensions $d_Xd_Y$.


"""
centralizer(::Type{I}; kwargs...) where {I <: Sector}

Collect all transparent sectors in the sector type `I`.
"""
centralizer(::Type{I}; kwargs...) where {I <: Sector} = vec(collect(filter(obj -> istransparent(obj; kwargs...), values(I))))

"""
topological_central_charge(::Type{I}) where {I <: Sector}

Return the topological central charge c of the modular sector type `I`, where c is determined mod 8.
Return the topological central charge c of the braided sector type `I`, where c is determined mod 8.
We choose convention by restrict the returning value as rational numbers in (-4, 4].
"""
function topological_central_charge(::Type{I}) where {I <: Sector}
ξ = sum(dim(a)^2 * twist(a) for a in values(I)) / dim(I)
@assert isapprox(abs(ξ), 1) "Sector $I is not modular"
isapprox(abs(ξ), 0) && return missing # For non-modular categories, central charge is also meaningful. See https://arxiv.org/pdf/1602.05946. For super modular category, Gauss sum vanishes, and its central charge needs to be defined in another manner: https://arxiv.org/pdf/1603.09294.
Comment thread
Chenqitrg marked this conversation as resolved.
c_float = angle(ξ) * 8 / (2π)

isapprox(c_float, -4) && return 4 // 1
Expand Down
47 changes: 37 additions & 10 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -265,16 +265,43 @@ end
end
end

@testset "Ismodular" begin
@test !ismodular(Z2Irrep)
@test !ismodular(Z3Irrep)
@test !ismodular(FermionParity)
@test !ismodular(A4Irrep)
@test !ismodular(IsingAnyon ⊠ Z2Irrep)
@test ismodular(IsingAnyon)
@test ismodular(FibonacciAnyon)
@test ismodular(TimeReversed{IsingAnyon})
@test ismodular(IsingAnyon ⊠ TimeReversed{IsingAnyon})
@testset "Ismodular, issymmetric, istransparent and Müger_centralizier" begin
Tannakian_list = [Z2Irrep, Z3Irrep, FermionParity, A4Irrep, D3Irrep, D4Irrep, Z2Irrep ⊠ D4Irrep, D3Irrep ⊠ A4Irrep]
Super_Tannakian_list = [FermionParity, FermionParity ⊠ A4Irrep, FermionParity ⊠ Z3Irrep, D4Irrep ⊠ FermionParity]
UMTC_list = [
IsingAnyon, FibonacciAnyon, TimeReversed{IsingAnyon}, TimeReversed{FibonacciAnyon},
FibonacciAnyon ⊠ FibonacciAnyon, FibonacciAnyon ⊠ IsingAnyon, IsingAnyon ⊠ TimeReversed{IsingAnyon},
TimeReversed{FibonacciAnyon} ⊠ IsingAnyon, IsingAnyon ⊠ IsingAnyon ⊠ IsingAnyon,
IsingAnyon ⊠ FibonacciAnyon ⊠ IsingAnyon ⊠ TimeReversed{IsingAnyon} ⊠ TimeReversed{FibonacciAnyon},
]
UMTC_over_RepG_list = [Z2Irrep ⊠ IsingAnyon, Z3Irrep ⊠ FibonacciAnyon, D3Irrep ⊠ TimeReversed{IsingAnyon}, A4Irrep ⊠ FibonacciAnyon ⊠ TimeReversed{IsingAnyon}]

for sect in [Tannakian_list..., Super_Tannakian_list...]
@test !ismodular(sect)
@test issymmetric(sect)
for charge in values(sect)
@test istransparent(charge)
end
@test centralizier(sect) == vec(collect(values(sect)))
end

for sect in UMTC_list
@test ismodular(sect)
@test !issymmetric(sect)
for anyon in values(sect)
anyon == unit(sect) && continue
@test !istransparent(anyon)
end
@test centralizier(sect) == [unit(sect)]
end

for sect in UMTC_over_RepG_list
charge_part = (TensorKitSectors._sectors)(sect)[1]
@test !ismodular(sect)
@test !issymmetric(sect)
@test map(x -> x[1], centralizier(sect)) == collect(values(charge_part))
end

end

@testset "Total quantum dimension" begin
Expand Down
Loading