Symmetry sectors an fusion trees

Type hierarchy

TensorKit.SectorType
abstract 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. Subtypes I<:Sector as the set of labels of a GradedSpace.

Every new I<:Sector should implement the following methods:

  • one(::Type{I}): unit element of I
  • conj(a::I): $a̅$, conjugate or dual label of $a$
  • ⊗(a::I, b::I): iterable with unique fusion outputs of $a ⊗ b$ (i.e. don't repeat in case of multiplicities)
  • Nsymbol(a::I, b::I, c::I): number of times c appears in a ⊗ b, i.e. the multiplicity
  • FusionStyle(::Type{I}): UniqueFusion(), SimpleFusion() or GenericFusion()
  • BraidingStyle(::Type{I}): Bosonic(), Fermionic(), Anyonic(), ...
  • Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I): F-symbol: scalar (in case of UniqueFusion/SimpleFusion) or matrix (in case of GenericFusion)
  • Rsymbol(a::I, b::I, c::I): R-symbol: scalar (in case of UniqueFusion/SimpleFusion) or matrix (in case of GenericFusion)

and optionally

  • dim(a::I): quantum dimension of sector a
  • frobeniusschur(a::I): Frobenius-Schur indicator of a
  • Bsymbol(a::I, b::I, c::I): B-symbol: scalar (in case of UniqueFusion/SimpleFusion) or matrix (in case of GenericFusion)
  • twist(a::I) -> twist of sector a

and optionally, if FusionStyle(I) isa GenericFusion

  • vertex_ind2label(i::Int, a::I, b::I, c::I) -> a custom label for the ith copy of c appearing in a ⊗ b

Furthermore, iterate and Base.IteratorSize should be made to work for the singleton type SectorValues{I}.

source
TensorKit.SectorValuesType
struct SectorValues{I<:Sector}

Singleton type to represent an iterator over the possible values of type I, whose instance is obtained as values(I). For a new I::Sector, the following should be defined

  • Base.iterate(::SectorValues{I}[, state]): iterate over the values
  • Base.IteratorSize(::Type{SectorValues{I}}): HasLenght(), SizeUnkown() or IsInfinite() depending on whether the number of values of type I is finite (and sufficiently small) or infinite; for a large number of values, SizeUnknown() is recommend because this will trigger the use of GenericGradedSpace.

If IteratorSize(I) == HasLength(), also the following must be implemented:

  • Base.length(::SectorValues{I}): the number of different values
  • Base.getindex(::SectorValues{I}, i::Int): a mapping between an index i and an instance of I
  • findindex(::SectorValues{I}, c::I): reverse mapping between a value c::I and an index i::Integer ∈ 1:length(values(I))
source
TensorKit.FusionStyleType
FusionStyle(a::Sector) -> ::FusionStyle
FusionStyle(I::Type{<:Sector}) -> ::FusionStyle

Return the type of fusion behavior of sectors of type I, which can be either

  • UniqueFusion(): single fusion output when fusing two sectors;
  • SimpleFusion(): multiple outputs, but every output occurs at most one, also known as multiplicity free (e.g. irreps of $SU(2)$);
  • GenericFusion(): multiple outputs that can occur more than once (e.g. irreps of $SU(3)$).

There is an abstract supertype MultipleFusion of which both SimpleFusion and GenericFusion are subtypes. Furthermore, there is a type alias MultiplicityFreeFusion for those fusion types which do not require muliplicity labels, i.e. MultiplicityFreeFusion = Union{UniqueFusion,SimpleFusion}.

source
TensorKit.BraidingStyleType
BraidingStyle(::Sector) -> ::BraidingStyle
BraidingStyle(I::Type{<:Sector}) -> ::BraidingStyle

Return the type of braiding and twist behavior of sectors of type I, 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 on SimpleFusion or GenericFusion 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: isone(Rsymbol(b,a,c)*Rsymbol(a,b,c)) == true) and permutations are uniquely defined.

source
TensorKit.AbstractIrrepType
abstract type AbstractIrrep{G<:Group} <: Sector end

Abstract supertype for sectors which corresponds to irreps (irreducible representations) of a group G. 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.

Actual concrete implementations of those irreps can be obtained as Irrep[G], or via their actual name, which generically takes the form (asciiG)Irrep, i.e. the ASCII spelling of the group name followed by Irrep.

All irreps have BraidingStyle equal to Bosonic() and thus trivial twists.

source
TensorKit.ZNIrrepType
ZNIrrep{N}(n::Integer)
Irrep[ℤ{N}](n::Integer)

Represents irreps of the group $ℤ_N$ for some value of N<64. (We need 2*(N-1) <= 127 in order for a ⊗ b to work correctly.) For N equals 2, 3 or 4, ℤ{N} can be replaced by ℤ₂, ℤ₃, ℤ₄, whereas Parity is a synonym for Irrep{ℤ₂}. An arbitrary Integer n can be provided to the constructor, but only the value mod(n, N) is relevant.

source
TensorKit.U1IrrepType
U1Irrep(j::Real)
Irrep[U₁](j::Real)

Represents irreps of the group $U₁$. 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 ofU₁subgroups ofSU₂, such as the Sz of spin-1/2 system. Hence, the charge is stored as aHalfIntfrom the package HalfIntegers.jl, but can be entered as arbitraryReal`. The sequence of the charges is: 0, 1/2, -1/2, 1, -1, ...

source
TensorKit.SU2IrrepType
SU2Irrep(j::Real)
Irrep[SU₂](j::Real)

Represents irreps of the group $SU₂$. 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.

source
TensorKit.CU1IrrepType
CU1Irrep(j, s = ifelse(j>zero(j), 2, 0))
Irrep[CU₁](j, s = ifelse(j>zero(j), 2, 0))

Represents irreps of the group $U₁ ⋊ C$ ($U₁$ and charge conjugation or reflection), which is also known as just 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) or s = 1 (non-trivial charge conjugation)
  • if j > 0, s = 2 (two-dimensional representation)
source
TensorKit.FibonacciAnyonType
struct FibonacciAnyon <: Sector
FibonacciAnyon(s::Symbol)

Represents the anyons (isomorphism classes of simple objects) of the Fibonacci fusion category. It can take two values, corresponding to the trivial sector FibonacciAnyon(:I) and the non-trivial sector FibonacciAnyon(:τ) with fusion rules $τ ⊗ τ = 1 ⊕ τ$.

source
TensorKit.FusionTreeType
struct FusionTree{I, N, M, L, T}

Represents a fusion tree of sectors of type I<:Sector, fusing (or splitting) N uncoupled sectors to a coupled sector. (It actually represents a splitting tree, but fusion tree is a more common term). The isdual field indicates whether an isomorphism is present (if the corresponding value is true) or not. The field uncoupled contains the sectors coming out of the splitting trees, before the possible 𝑍 isomorphism. This fusion tree has M=max(0, N-2) inner lines. Furthermore, for FusionStyle(I) isa GenericFusion, the L=max(0, N-1) corresponding vertices carry a label of type T. If FusionStyle(I) isa MultiplicityFreeFusion,T = Nothing`.

source

Useful constants

TensorKit.IrrepConstant
const Irrep

A constant of a singleton type used as Irrep[G] with G<:Group a type of group, to construct or obtain a concrete subtype of AbstractIrrep{G} that implements the data structure used to represent irreducible representations of the group G.

source

Methods for defining and characterizing Sector subtypes

Base.oneMethod
one(::Sector) -> Sector
one(::Type{<:Sector}) -> Sector

Return the unit element within this type of sector.

source
TensorKit.NsymbolFunction
Nsymbol(a::I, b::I, c::I) where {I<:Sector} -> Integer

Return an Integer representing the number of times c appears in the fusion product a ⊗ b. Could be a Bool if FusionStyle(I) == UniqueFusion() or SimpleFusion().

source
TensorKit.FsymbolFunction
Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I<: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                                             f
                                                          v
                                                      b-<-κ
                                                          ∨
                                                          c

If FusionStyle(I) is UniqueFusion or SimpleFusion, 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)).

source
TensorKit.RsymbolFunction
Rsymbol(a::I, b::I, c::I) where {I<:Sector}

Returns the R-symbol $R^{ab}_c$ that maps between $c → a ⊗ b$ and $c → b ⊗ a$ as in

a -<-μ-<- c                                 b -<-ν-<- c
     ∨          -> Rsymbol(a,b,c)[μ,ν]           v
     b                                           a

If FusionStyle(I) is UniqueFusion() or SimpleFusion(), 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).

source
TensorKit.BsymbolFunction
Bsymbol(a::I, b::I, c::I) where {I<: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(I) is UniqueFusion() or SimpleFusion(), 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).

source
Base.isrealMethod
isreal(::Type{<:Sector}) -> Bool

Return whether the topological data (Fsymbol, Rsymbol) of the sector is real or not (in which case it is complex).

source
TensorKit.vertex_ind2labelFunction
vertex_ind2label(k::Int, a::I, b::I, c::I) where {I<:Sector}

Convert the index k of the fusion vertex (a,b)->c into a label. For FusionStyle(I) == UniqueFusion() or FusionStyle(I) == MultipleFusion(), where every fusion output occurs only once and k == 1, the default is to suppress vertex labels by setting them equal to nothing. For FusionStyle(I) == GenericFusion(), the default is to just use k, unless a specialized method is provided.

source
TensorKit.:⊠Method
⊠(s₁::Sector, s₂::Sector)
deligneproduct(s₁::Sector, s₂::Sector)

Given two sectors s₁ and s₂, which label an isomorphism class of simple objects in a fusion category $C₁$ and $C₂$, s1 ⊠ s2 (obtained as oxtimes+TAB) labels the isomorphism class of simple objects in the Deligne tensor product category $C₁ ⊠ C₂$.

The Deligne tensor product also works in the type domain and for spaces and tensors. For group representations, we have Irrep[G₁] ⊠ Irrep[G₂] == Irrep[G₁ × G₂].

source

Methods for manipulating fusion trees or pairs of fusion-splitting trees

The main method for manipulating a fusion-splitting tree pair is

TensorKit.braidMethod
braid(f1::FusionTree{I}, f2::FusionTree{I},
        levels1::IndexTuple, levels2::IndexTuple,
        p1::IndexTuple{N₁}, p2::IndexTuple{N₂}) where {I<:Sector, N₁, N₂}
-> <:AbstractDict{Tuple{FusionTree{I, N₁}, FusionTree{I, 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.

source

which, for FusionStyle(G) isa SymmetricBraiding, simplifies to

TensorKit.permuteMethod
permute(f1::FusionTree{I}, f2::FusionTree{I},
        p1::NTuple{N₁, Int}, p2::NTuple{N₂, Int}) where {I, N₁, N₂}
-> <:AbstractDict{Tuple{FusionTree{I, N₁}, FusionTree{I, 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.

source

These operations are implemented by composing the following more elementary manipulations

TensorKit.braidMethod
braid(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 return the result as a <:AbstractDict of output trees and corresponding coefficients. The braiding is determined by specifying that the new sector at position k corresponds to the sector that was originally at the position i = p[k], and assigning to every index i of the original fusion tree 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.

source
TensorKit.permuteMethod
permute(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.

source
TensorKit.repartitionFunction
repartition(f1::FusionTree{I, N₁}, f2::FusionTree{I, N₂}, N::Int) where {I, N₁, N₂}
-> <:AbstractDict{Tuple{FusionTree{I, N}, FusionTree{I, 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.

source
TensorKit.artin_braidFunction
artin_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.

source

Finally, there are some additional manipulations for internal use

TensorKit.insertatFunction
insertat(f::FusionTree{I, N₁}, i::Int, f2::FusionTree{I, N₂})
-> <:AbstractDict{<:FusionTree{I, 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.

source
TensorKit.splitFunction
split(f::FusionTree{I, N}, M::Int)
-> (::FusionTree{I, M}, ::FusionTree{I, N-M+1})

Split a fusion tree into two. The first tree has as uncoupled sectors the first M uncoupled sectors of the input tree f, whereas its coupled sector corresponds to the internal sector between uncoupled sectors M and M+1 of the original tree f. The second tree has as first uncoupled sector that same internal sector of f, followed by remaining N-M uncoupled sectors of f. It couples to the same sector as f. This operation is the inverse of insertat in the sense that if f1, f2 = split(t, M) ⇒ f == insertat(f2, 1, f1).

source
TensorKit.mergeFunction
merge(f1::FusionTree{I, N₁}, f2::FusionTree{I, N₂}, c::I, μ = nothing)
-> <:AbstractDict{<:FusionTree{I, 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(I) == GenericFusion(), also a degeneracy label μ for the fusion of the coupled sectors of f1 and f2 to c needs to be specified.

source