Fusion trees

Type hierarchy

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

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.

Fields

  • uncoupled::NTuple{N,I}: the uncoupled sectors coming out of the splitting tree, before the possible 𝑍 isomorphism (see isdual).
  • coupled::I: the coupled sector.
  • isdual::NTuple{N,Bool}: indicates whether a 𝑍 isomorphism is present (true) or not (false) for each uncoupled sector.
  • innerlines::NTuple{M,I}: the labels of the M=max(0, N-2) inner lines of the splitting tree.
  • vertices::NTuple{L,Int}: the integer values of the L=max(0, N-1) vertices of the splitting tree. If FusionStyle(I) isa MultiplicityFreeFusion, then vertices is simply equal to the constant value ntuple(n->1, L).
source

Methods for defining and generating fusion trees

TensorKit.fusiontreesMethod
fusiontrees(uncoupled::NTuple{N,I}[,
    coupled::I=unit(I)[, isdual::NTuple{N,Bool}=ntuple(n -> false, length(uncoupled))]])
    where {N,I<:Sector} -> FusionTreeIterator{I,N,I}

Return an iterator over all fusion trees with a given coupled sector label coupled and uncoupled sector labels and isomorphisms uncoupled and isdual respectively.

source

Methods for manipulating fusion trees

For manipulating single fusion trees, the following internal methods are defined:

TensorKit.insertatFunction
insertat(f::FusionTree{I, N₁}, i::Int, f₂::FusionTree{I, N₂})
-> <:AbstractDict{<:FusionTree{I, N₁+N₂-1}, <:Number}

Attach a fusion tree f₂ to the uncoupled leg i of the fusion tree f₁ and bring it into a linear combination of fusion trees in standard form. This requires that f₂.coupled == f₁.uncoupled[i] and f₁.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 join in the sense that if f == join(split(f, M)...) holds for all M between 0 and N, where N is the number of uncoupled sectors of f.

See also join and insertat.

Examples

julia> f = FusionTree{Z2Irrep}((1, 1, 0), 0, (false, false, false));

julia> f₁, f₂ = TensorKit.split(f, 2)
(FusionTree{Irrep[ℤ₂]}((1, 1), 0, (false, false), ()), FusionTree{Irrep[ℤ₂]}((0, 0), 0, (false, false), ()))

julia> TensorKit.join(f₁, f₂) == f
true
source
TensorKit.joinFunction
join(f₁::FusionTree{I, N₁}, f₂::FusionTree{I, N₂}) where {I, N₁, N₂}
-> (::FusionTree{I, N₁ + N₂ - 1})

Join fusion trees f₁ and f₂ by connecting the coupled sector of f₁ to the first uncoupled sector of f₂. The resulting tree has uncoupled sectors given by those of f₁ followed the remaining uncoupled sectors (except for the first) of f₂. This requires that f₁.coupled == f₂.uncoupled[1] and f₂.isdual[1] == false. This operation is the inverse of split, in the sense that f == join(split(f, M)...) holds for all M between 0 and N, where N is the number of uncoupled sectors of f.

See also split and insertat.

Examples

julia> f₁ = FusionTree{Z2Irrep}((1, 1), 0, (false, false));

julia> f₂ = FusionTree{Z2Irrep}((0, 0), 0, (false, false));

julia> f = TensorKit.join(f₁, f₂)
FusionTree{Irrep[ℤ₂]}((1, 1, 0), 0, (false, false, false), (0,))
source
TensorKit.mergeFunction
merge(f₁::FusionTree{I, N₁}, f₂::FusionTree{I, N₂}, c::I, μ = 1)
-> <:AbstractDict{<:FusionTree{I, N₁+N₂}, <:Number}

Merge two fusion trees together to a linear combination of fusion trees whose uncoupled sectors are those of f₁ followed by those of f₂, and where the two coupled sectors of f₁ and f₂ are further fused to c. In case of FusionStyle(I) == GenericFusion(), also a degeneracy label μ for the fusion of the coupled sectors of f₁ and f₂ to c needs to be specified.

source
TensorKit.elementary_traceFunction
elementary_trace(f::FusionTree{I, N}, i) where {I,N} -> <:AbstractDict{FusionTree{I,N-2}, <:Number}

Perform an elementary trace 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.

source
TensorKit.planar_traceMethod
planar_trace(f::FusionTree, (q₁, q₂)::Index2Tuple)
    -> <:AbstractDict{<:FusionTree, <:Number}

Perform a planar trace of the uncoupled indices of the fusion tree f at q₁ with those at q₂, where q₁[i] is connected to q₂[i] for all i. The result is returned as a dictionary of output trees and corresponding coefficients.

source
TensorKit.artin_braidFunction
artin_braid(f::FusionTree, i; inv::Bool = false) -> <:AbstractDict{typeof(f), <: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
TensorKit.braidMethod
braid(f::FusionTree{<:Sector, N}, p::NTuple{N, Int}, levels::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

These can be composed to implement elementary manipulations of fusion-splitting tree pairs, according to the following methods

TensorKit.bendrightFunction
bendright((f₁, f₂)::FusionTreePair) -> (f₃, f₄) => coeff
bendright(src::FusionTreeBlock) -> dst => coeffs

Map the final splitting vertex a ⊗ b ← c of src to a fusion vertex a ← c ⊗ dual(b) in dst. For FusionStyle(src) === UniqueFusion(), both src and dst are simple FusionTreePairs, and the transformation consists of a single coefficient coeff. For generic FusionStyles, the input and output consist of FusionTreeBlocks that bundle together all trees with the same uncoupled charges, and coeffs now forms a transformation matrix.

    ╰─┬─╯ |  | |   ╰─┬─╯ |  |  |
      ╰─┬─╯  | |     ╰─┬─╯  |  |
        ╰ ⋯ ┬╯ |       ╰ ⋯ ┬╯  |
            |  | →         ╰─┬─╯
        ╭ ⋯ ┴╮ |         ╭ ⋯ ╯
      ╭─┴─╮  | |       ╭─┴─╮
    ╭─┴─╮ |  ╰─╯     ╭─┴─╮ |

See also bendleft.

source
TensorKit.bendleftFunction
bendleft((f₁, f₂)::FusionTreePair) -> (f₃, f₄) => coeff
bendleft(src::FusionTreeBlock) -> dst => coeffs

Map the final fusion vertex a ← c ⊗ dual(b) of src to a splitting vertex a ⊗ b ← c in dst. For FusionStyle(src) === UniqueFusion(), both src and dst are simple FusionTreePairs, and the transformation consists of a single coefficient coeff. For generic FusionStyles, the input and output consist of FusionTreeBlocks that bundle together all trees with the same uncoupled charges, and coeffs now forms a transformation matrix.

    ╰─┬─╯ |  ╭─╮     ╰─┬─╯ |
      ╰─┬─╯  | |       ╰─┬─╯ 
        ╰ ⋯ ┬╯ |         ╰ ⋯ ╮
            |  | →         ╭─┴─╮
        ╭ ⋯ ┴╮ |       ╭ ⋯ ┴╮  |
      ╭─┴─╮  | |     ╭─┴─╮  |  |
    ╭─┴─╮ |  | |   ╭─┴─╮ |  |  |

See also bendright.

source
TensorKit.foldrightFunction
foldright((f₁, f₂)::FusionTreePair) -> (f₃, f₄) => coeff
foldright(src::FusionTreeBlock) -> dst => coeffs

Map the first splitting vertex a ⊗ b ← c of src to a fusion vertex b ← dual(a) ⊗ c, and reexpress as a linear combination of standard basis trees. For FusionStyle(src) === UniqueFusion(), both src and dst are simple FusionTreePairs, and the transformation consists of a single coefficient coeff. For generic FusionStyles, the input and output consist of FusionTreeBlocks that bundle together all trees with the same uncoupled charges, and coeffs now forms a transformation matrix.

    | ╰─┬─╯ |  |   ╰─┬─╯ | |  |
    |   ╰─┬─╯  |     ╰─┬─╯ |  |
    |     ╰ ⋯ ┬╯       ╰─┬─╯  |
    |         |  →       ╰ ⋯ ┬╯
    |     ╭ ⋯ ┴╮             |
    |   ╭─┴─╮  |        ╭─ ⋯ ┴╮
    ╰───┴─╮ |  |      ╭─┴─╮   |

See also foldleft.

source
TensorKit.foldleftFunction
foldleft((f₁, f₂)::FusionTreePair) -> (f₃, f₄) => coeff
foldleft(src::FusionTreeBlock) -> dst => coeffs

Map the first fusion vertex a ← c ⊗ dual(b) of src to a splitting vertex a ⊗ b ← c in dst. For FusionStyle(src) === UniqueFusion(), both src and dst are simple FusionTreePairs, and the transformation consists of a single coefficient coeff. For generic FusionStyles, the input and output consist of FusionTreeBlocks that bundle together all trees with the same uncoupled charges, and coeffs now forms a transformation matrix.

    ╭───┬─╯ |  |       ╰─┬─╯  |
    |   ╰─┬─╯  |         ╰ ⋯ ┬╯ 
    |     ╰ ⋯ ┬╯             |
    |         |  →       ╭ ⋯ ┴╮
    |     ╭ ⋯ ┴╮       ╭─┴─╮  |
    |   ╭─┴─╮  |     ╭─┴─╮ |  |
    | ╭─┴─╮ |  |   ╭─┴─╮ | |  |

See also foldright.

source

Finally, these are used to define large manipulations of fusion-splitting tree pairs, which are then used in the index manipulation of AbstractTensorMap objects. The following methods defined on fusion splitting tree pairs have an associated definition for tensors.

TensorKit.repartitionMethod
repartition((f₁, f₂)::FusionTreePair{I, N₁, N₂}, N::Int) where {I, N₁, N₂}
    -> <:AbstractDict{<:FusionTreePair{I, N, 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 (f₁) and incoming sectors (f₂) respectively (with identical coupled sector f₁.coupled == f₂.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
Base.transposeMethod
transpose((f₁, f₂)::FusionTreePair{I}, p::Index2Tuple{N₁, N₂}) where {I, N₁, N₂}
    -> <:AbstractDict{<:FusionTreePair{I, 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 (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
TensorKit.braidMethod
braid((f₁, f₂)::FusionTreePair, (p1, p2)::Index2Tuple, (levels1, levels2)::Index2Tuple)
    -> <:AbstractDict{<:FusionTreePair{I, N₁, 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 f₁ and fusion tree f₂, such that the incoming sectors f₂.uncoupled are fused to f₁.coupled == f₂.coupled and then to the outgoing sectors f₁.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 f₁ and fusion tree f₂ 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
TensorKit.permuteMethod
permute((f₁, f₂)::FusionTreePair, (p1, p2)::Index2Tuple)
    -> <:AbstractDict{<:FusionTreePair{I, 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 (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