diff --git a/src/TensorKitSectors.jl b/src/TensorKitSectors.jl index bceb3f88..553486b2 100644 --- a/src/TensorKitSectors.jl +++ b/src/TensorKitSectors.jl @@ -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 diff --git a/src/sectors.jl b/src/sectors.jl index 4234abdb..b3284a73 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -691,7 +691,7 @@ 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} @@ -699,7 +699,7 @@ function Smatrix(::Type{I}) where {I <: Sector} 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 """ @@ -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)) + +""" + 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. c_float = angle(ξ) * 8 / (2π) isapprox(c_float, -4) && return 4 // 1 diff --git a/test/runtests.jl b/test/runtests.jl index 86addc51..289cdfce 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -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