Symmetry sectors an fusion trees
Type hierarchy
TensorKit.Sector
— Typeabstract type Sector end
Abstract type for representing the (isomorphism classes of) simple objects in (unitary and pivotal) (pre-)fusion categories, e.g. the irreducible representations of a finite or compact group.
Every new G<:Sector
should implement the following methods:
one(::Type{G})
: unit element ofG
conj(a::G)
: $a̅$, conjugate or dual label of $a$⊗(a::G, b::G)
: iterable with unique fusion outputs of $a ⊗ b$ (i.e. don't repeat in case of multiplicities)Nsymbol(a::G, b::G, c::G)
: number of timesc
appears ina ⊗ b
, i.e. the multiplicityFusionStyle(::Type{G})
:Abelian()
,SimpleNonAbelian()
orDegenerateNonAbelian()
BraidingStyle(::Type{G})
:Bosonic()
,Fermionic()
,Anyonic()
, ...Fsymbol(a::G, b::G, c::G, d::G, e::G, f::G)
: F-symbol: scalar (in case ofAbelian
/SimpleNonAbelian
) or matrix (in case ofDegenerateNonAbelian
)Rsymbol(a::G, b::G, c::G)
: R-symbol: scalar (in case ofAbelian
/SimpleNonAbelian
) or matrix (in case ofDegenerateNonAbelian
)
and optionally
dim(a::G)
: quantum dimension of sectora
frobeniusschur(a::G)
: Frobenius-Schur indicator ofa
Bsymbol(a::G, b::G, c::G)
: B-symbol: scalar (in case ofAbelian
/SimpleNonAbelian
) or matrix (in case ofDegenerateNonAbelian
)twist(a::G)
-> twist of sectora
and optionally, if FusionStyle(G) isa DegenerateNonAbelian
vertex_ind2label(i::Int, a::G, b::G, c::G)
-> a custom label for thei
th copy ofc
appearing ina ⊗ b
Furthermore, iterate
and Base.IteratorSize
should be made to work for the singleton type SectorValues{G}
.
TensorKit.SectorValues
— Typestruct SectorValues{G<:Sector}
Singleton type to represent an iterator over the possible values of type G
, whose instance is obtained as values(G)
. For a new G::Sector
, the following should be defined
Base.iterate(::SectorValues{G}[, state])
: iterate over the valuesBase.IteratorSize(::Type{SectorValues{G}})
:HasLenght()
,SizeUnkown()
orIsInfinite()
depending on whether the number of values of typeG
is finite (and sufficiently small) or infinite; for a large number of values,SizeUnknown()
is recommend because this will trigger the use ofGenericRepresentationSpace
.
If IteratorSize(G) == HasLength()
, also the following must be implemented:
Base.length(::SectorValues{G})
: the number of different valuesBase.getindex(::SectorValues{G}, i::Int)
: a mapping between an indexi
and an instance ofG
findindex(::SectorValues{G}, c::G)
: reverse mapping between a valuec::G
and an indexi::Integer ∈ 1:length(values(G))
TensorKit.FusionStyle
— TypeFusionStyle(a::Sector) -> ::FusionStyle
FusionStyle(G::Type{<:Sector}) -> ::FusionStyle
Return the type of fusion behavior of sectors of type G, which can be either
Abelian()
: single fusion output when fusing two sectors;SimpleNonAbelian()
: multiple outputs, but every output occurs at most one, also known as multiplicity free (e.g. irreps of $SU(2)$);DegenerateNonAbelian()
: multiple outputs that can occur more than once (e.g. irreps of $SU(3)$).
There is an abstract supertype NonAbelian
of which both SimpleNonAbelian
and DegenerateNonAbelian
are subtypes.
TensorKit.BraidingStyle
— TypeBraidingStyle(::Sector) -> ::BraidingStyle
BraidingStyle(G::Type{<:Sector}) -> ::BraidingStyle
Return the type of braiding and twist behavior of sectors of type G
, which can be either
Bosonic()
: symmetric braiding with trivial twist (i.e. identity)Fermionic()
: symmetric braiding with non-trivial twist (squares to identity)Anyonic()
: general $R_(a,b)^c$ phase or matrix (depending onSimpleNonAbelian
orDegenerateNonAbelian
fusion) and arbitrary twists
Note that Bosonic
and Fermionic
are subtypes of SymmetricBraiding
, which means that braids are in fact equivalent to crossings (i.e. braiding twice is an identity: Rsymbol(b,a,c)*Rsymbol(a,b,c) = I
) and permutations are uniquely defined.
TensorKit.Irrep
— Typeabstract type Irrep <: Sector end
Abstract supertype for sectors which corresponds to irreps (irreducible representations) of groups. As we assume unitary representations, these would be finite groups or compact Lie groups. Note that this could also include projective rather than linear representations.
All irreps have BraidingStyle
equal to Bosonic()
and thus trivial twists. A fermionic sector can be created using Fermion
.
TensorKit.AbelianIrrep
— Typeabstract type AbelianIrrep <: Irrep end
Abstract supertype for sectors which corresponds to irreps (irreducible representations) of abelian groups. They all have FusionStyle
equal to Abelian()
and thus trivial topological data, which is real valued.
TensorKit.ZNIrrep
— Typestruct ZNIrrep{N} <: AbelianIrrep
ZNIrrep(n::Integer)
Represents irreps of the group $ℤ_N$ for some value of N<64
. Unicode synonyms are available for the cases N=2,3,4
as ℤ₂
, ℤ₃
, ℤ₄
. Also the name Parity
can be used as synonym for ℤ₂
. An arbitrary Integer
n
can be provided to the constructor, but only the value mod(n, N)
is relevant.
TensorKit.U1Irrep
— Typestruct U1Irrep <: AbelianIrrep
U1Irrep(j::Real)
Represents irreps of the group U₁ == SO₂
, both of which are valid unicode synonyms. The irrep is labelled by a charge, which should be an integer for a linear representation. However, it is often useful to allow half integers to represent irreps of U₁
subgroups of $SU₂$. Hence, the charge is stored as a HalfInt
from the package HalfIntegers.jl, but can be entered as arbitrary Real
.
TensorKit.SU2Irrep
— Typestruct SU2Irrep <: Irrep
SU2Irrep(j::Real)
Represents irreps of the group SU₂
, which is also a valid unicode synonym. The irrep is labelled by a half integer j
which can be entered as an abitrary Real
, but is stored as a HalfInt
from the HalfIntegers.jl package. Half-integer and integer irreps of SU₂
are also projective and linear representation of SO₃
, which is another valid unicode synonym.
TensorKit.CU1Irrep
— Typestruct CU1Irrep <: Irrep
j::HalfInt # value of the U1 charge
s::Int # rep of charge conjugation:
end
Represents irreps of the group $U₁ ⋉ C$ ($U₁$ and charge conjugation or reflection), which is also known as just O₂
. Unicode synomyms are thus CU₁
or O₂
. The irrep is labelled by a positive half integer j
(the $U₁$ charge) and an integer s
indicating the behaviour under charge conjugation. They take values:
- if
j == 0
,s = 0
(trivial charge conjugation) ors = 1
(non-trivial charge conjugation) - if
j > 0
,s = 2
(two-dimensional representation)
TensorKit.FibonacciAnyon
— Typestruct FibonacciAnyon <: Sector
FibonacciAnyon(s::Union{Symbol,Integer})
Represents the Fibonacci fusion category. It can take two values, corresponding to the trivial sector FibonacciAnyon(:I) == FibonacciAnyon(0)
and the non-trivial sector FibonacciAnyon(:τ) = FibonacciAnyon(1)
with fusion rules $τ ⊗ τ = 1 ⊕ τ$.
TensorKit.FusionTree
— Typestruct FusionTree{G,N,M,L,T}
Represents a fusion tree of sectors of type G<:Sector
, fusing (or splitting) N
uncoupled sectors to a coupled sector. This fusion tree has M=max(0,N-2)
inner lines. Furthermore, for FusionStyle(G) isa DegenerateNonAbelian
, the L=max(0,N-1)
corresponding vertices carry a label of type T
. If FusionStyle(G) isa Union{Abelian,SimpleNonAbelian}
, T = Nothing
.
Methods for characterizing Sector
subtypes
Base.one
— Methodone(::Sector) -> Sector
one(::Type{<:Sector}) -> Sector
Return the unit element within this type of sector.
TensorKit.dual
— Methoddual(a::Sector) -> Sector
Return the conjugate label conj(a)
.
TensorKit.Nsymbol
— FunctionNsymbol(a::G, b::G, c::G) where {G<:Sector} -> Integer
Return an Integer
representing the number of times c
appears in the fusion product a ⊗ b
. Could be a Bool
if FusionStyle(G) == Abelian()
or SimpleNonAbelian()
.
TensorKit.Fsymbol
— FunctionFsymbol(a::G, b::G, c::G, d::G, e::G, f::G) where {G<:Sector}
Return the F-symbol $F^{abc}_d$ that associates the two different fusion orders of sectors a
, b
and c
into an ouput sector d
, using either an intermediate sector $a ⊗ b → e$ or $b ⊗ c → f$:
a-<-μ-<-e-<-ν-<-d a-<-λ-<-d
∨ ∨ -> Fsymbol(a,b,c,d,e,f)[μ,ν,κ,λ] ∨
b c b-<-κ
∨
c
If FusionStyle(G)
is Abelian
or SimpleNonAbelian
, the F-symbol is a number. Otherwise it is a rank 4 array of size (Nsymbol(a,b,e), Nsymbol(e,c,d), Nsymbol(b,c,f), Nsymbol(a,f,d))
.
TensorKit.Rsymbol
— FunctionRsymbol(a::G, b::G, c::G) where {G<:Sector}
Returns the R-symbol $R^{ab}_c$ that maps between $a ⊗ b → c$ and $b ⊗ a → c$ as in
a -<-μ-<- c b -<-ν-<- c
∨ -> Rsymbol(a,b,c)[μ,ν] ∧
b a
If FusionStyle(G)
is Abelian()
or SimpleNonAbelian()
, the R-symbol is a number. Otherwise it is a square matrix with row and column size Nsymbol(a,b,c) == Nsymbol(b,a,c)
.
TensorKit.Bsymbol
— FunctionBsymbol(a::G, b::G, c::G) where {G<:Sector}
Return the value of $B^{ab}_c$ which appears in transforming a splitting vertex into a fusion vertex using the transformation
a -<-μ-<- c a -<-ν-<- c
∨ -> √(dim(c)/dim(a)) * Bsymbol(a,b,c)[μ,ν] ∧
b dual(b)
If FusionStyle(G)
is Abelian()
or SimpleNonAbelian()
, the B-symbol is a number. Otherwise it is a square matrix with row and column size Nsymbol(a, b, c) == Nsymbol(c, dual(b), a)
.
TensorKit.dim
— Methoddim(a::Sector)
Return the (quantum) dimension of the sector a
.
TensorKit.frobeniusschur
— Functionfrobeniusschur(a::Sector)
Return the Frobenius-Schur indicator of a sector a
.
TensorKit.twist
— Functiontwist(a::Sector)
Return the twist of a sector a
Base.isreal
— Methodisreal(::Type{<:Sector}) -> Bool
Return whether the topological data (Fsymbol, Rsymbol) of the sector is real or not (in which case it is complex).
TensorKit.vertex_labeltype
— Functionvertex_labeltype(G::Type{<:Sector}) -> Type
Return the type of labels for the fusion vertices of sectors of type G
.
TensorKit.vertex_ind2label
— Functionvertex_ind2label(i::Int, a::G, b::G, c::G) where {G<:Sector}
Convert the index i of the fusion vertex (a,b)->c into a label. For FusionStyle(G) == Abelian()
or FusionStyle(G) == NonAbelian()
, where every fusion output occurs only once and i == 1
, the default is to suppress vertex labels by setting them equal to nothing
. For FusionStyle(G) == DegenerateNonAbelian()
, the default is to just use i
, unless a specialized method is provided.
Methods for manipulating fusion trees or pairs of fusion-splitting trees
The main method for manipulating a fusion-splitting tree pair is
TensorKit.braid
— Methodbraid(f1::FusionTree{G}, f2::FusionTree{G},
levels1::IndexTuple, levels2::IndexTuple,
p1::IndexTuple{N₁}, p2::IndexTuple{N₂}) where {G<:Sector,N₁,N₂}
-> <:AbstractDict{Tuple{FusionTree{G,N₁}, FusionTree{G,N₂}},<:Number}
Input is a fusion-splitting tree pair that describes the fusion of a set of incoming uncoupled sectors to a set of outgoing uncoupled sectors, represented using the splitting tree f1
and fusion tree f2
, such that the incoming sectors f2.uncoupled
are fused to f1.coupled == f2.coupled
and then to the outgoing sectors f1.uncoupled
. Compute new trees and corresponding coefficients obtained from repartitioning and braiding the tree such that sectors p1
become outgoing and sectors p2
become incoming. The uncoupled indices in splitting tree f1
and fusion tree f2
have levels (or depths) levels1
and levels2
respectively, which determines how indices braid. In particular, if i
and j
cross, $τ_{i,j}$ is applied if levels[i] < levels[j]
and $τ_{j,i}^{-1}$ if levels[i] > levels[j]
. This does not allow to encode the most general braid, but a general braid can be obtained by combining such operations.
which, for FusionStyle(G) isa SymmetricBraiding
, simplifies to
TensorKit.permute
— Methodpermute(f1::FusionTree{G}, f2::FusionTree{G},
p1::NTuple{N₁,Int}, p2::NTuple{N₂,Int}) where {G,N₁,N₂}
-> <:AbstractDict{Tuple{FusionTree{G,N₁}, FusionTree{G,N₂}},<:Number}
Input is a double fusion tree that describes the fusion of a set of incoming uncoupled sectors to a set of outgoing uncoupled sectors, represented using the individual trees of outgoing (t1
) and incoming sectors (t2
) respectively (with identical coupled sector t1.coupled == t2.coupled
). Computes new trees and corresponding coefficients obtained from repartitioning and permuting the tree such that sectors p1
become outgoing and sectors p2
become incoming.
These operations are implemented by composing the following more elementary manipulations
TensorKit.braid
— Methodbraid(f::FusionTree{<:Sector,N}, levels::NTuple{N,Int}, p::NTuple{N,Int})
-> <:AbstractDict{typeof(t),<:Number}
Perform a braiding of the uncoupled indices of the fusion tree f
and returns the result as a <:AbstractDict
of output trees and corresponding coefficients. The braiding is specified by specifying that index i
goes to position perm[i]
and assinging to every index a distinct level or depth levels[i]
. This permutation is then decomposed into elementary swaps between neighbouring indices, where the swaps are applied as braids such that if i
and j
cross, $τ_{i,j}$ is applied if levels[i] < levels[j]
and $τ_{j,i}^{-1}$ if levels[i] > levels[j]
. This does not allow to encode the most general braid, but a general braid can be obtained by combining such operations.
TensorKit.permute
— Methodpermute(f::FusionTree, p::NTuple{N,Int}) -> <:AbstractDict{typeof(t),<:Number}
Perform a permutation of the uncoupled indices of the fusion tree f
and returns the result as a <:AbstractDict
of output trees and corresponding coefficients; this requires that BraidingStyle(sectortype(f)) isa SymmetricBraiding
.
TensorKit.repartition
— Functionrepartition(f1::FusionTree{G,N₁}, f2::FusionTree{G,N₂},
::StaticLength{N}) where {G,N₁,N₂,N}
-> <:AbstractDict{Tuple{FusionTree{G,N}, FusionTree{G,N₁+N₂-N}},<:Number}
Input is a double fusion tree that describes the fusion of a set of incoming uncoupled sectors to a set of outgoing uncoupled sectors, represented using the individual trees of outgoing (f1
) and incoming sectors (f2
) respectively (with identical coupled sector f1.coupled == f2.coupled
). Computes new trees and corresponding coefficients obtained from repartitioning the tree by bending incoming to outgoing sectors (or vice versa) in order to have N
outgoing sectors.
TensorKit.artin_braid
— Functionartin_braid(f::FusionTree, i; inv::Bool = false) -> <:AbstractDict{typeof(t),<:Number}
Perform an elementary braid (Artin generator) of neighbouring uncoupled indices i
and i+1
on a fusion tree f
, and returns the result as a dictionary of output trees and corresponding coefficients.
The keyword inv
determines whether index i
will braid above or below index i+1
, i.e. applying artin_braid(f′, i; inv = true)
to all the outputs f′
of artin_braid(f, i; inv = false)
and collecting the results should yield a single fusion tree with non-zero coefficient, namely f
with coefficient 1
. This keyword has no effect if BraidingStyle(sectortype(f)) isa SymmetricBraiding
.
Finally, there are some additional manipulations for internal use
TensorKit.insertat
— Functioninsertat(f::FusionTree{G,N₁}, i, f2::FusionTree{G,N₂})
-> <:AbstractDict{<:FusionTree{G,N₁+N₂-1},<:Number}
Attach a fusion tree f2
to the uncoupled leg i
of the fusion tree f1
and bring it into a linear combination of fusion trees in standard form. This requires that f2.coupled == f1.uncoupled[i]
and f1.isdual[i] == false
.
TensorKit.split
— Functionsplit(f::FusionTree{G,N}, ::StaticLength(M))
-> (::FusionTree{G,M}, ::FusionTree{G,N-M+1})
Split a fusion tree with the first M outgoing indices, and an incoming index corresponding to the internal fusion tree index between outgoing indices N and N+1 of the original tree f
; and a second fusion tree whose first outgoing index is that same internal index. Its remaining outgoing indices are the N-M outgoing indices of the original tree f
, and also the incoming index is the same. This is in the inverse of insertat
in the sense that if f1, f2 = split(t, StaticLength(M)) ⇒ f == insertat(f2, 1, f1)
.
TensorKit.merge
— Functionmerge(f1::FusionTree{G,N₁}, f2::FusionTree{G,N₂}, c::G, μ = nothing)
-> <:AbstractDict{<:FusionTree{G,N₁+N₂},<:Number}
Merge two fusion trees together to a linear combination of fusion trees whose uncoupled sectors are those of f1
followed by those of f2
, and where the two coupled sectors of f1
and f2
are further fused to c
. In case of FusionStyle(G) == DegenerateNonAbelian()
, also a degeneracy label μ
for the fusion of the coupled sectors of f1
and f2
to c
needs to be specified.