From fb4693f2ecabc344d88bc925cbfbc2d2e174ad92 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 17 Mar 2025 17:58:28 +0100 Subject: [PATCH 01/34] add todo for function split --- src/fusiontrees/manipulations.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index fa9ccad39..6b5475aef 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -165,8 +165,9 @@ operation is the inverse of `insertat` in the sense that if f₂ = FusionTree{I}(f.uncoupled, f.coupled, isdual2, f.innerlines, f.vertices) return f₁, f₂ elseif M === 0 - f₁ = FusionTree{I}((), one(I), (), ()) - uncoupled2 = (one(I), f.uncoupled...) + # TODO: evaluate diagrams to see which unit is used here + f₁ = FusionTree{I}((), one(I), (), ()) + uncoupled2 = (one(I), f.uncoupled...) coupled2 = f.coupled isdual2 = (false, f.isdual...) innerlines2 = N >= 2 ? (f.uncoupled[1], f.innerlines...) : () From 13bcf823ff7a0095da09c06b03f17cf41b2a0163 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 17 Mar 2025 17:58:53 +0100 Subject: [PATCH 02/34] add comment for possible change in function merge --- src/fusiontrees/manipulations.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index 6b5475aef..8c02c1741 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -231,7 +231,7 @@ function merge(f₁::FusionTree{I,N₁}, f₂::FusionTree{I,N₂}, return insertat(f, N₁ + 1, f₂) end function merge(f₁::FusionTree{I,0}, f₂::FusionTree{I,0}, c::I, μ) where {I} - isone(c) || + isone(c) || # I had this as Nsymbol(f₁.coupled, f₂.coupled, c) > 0, valid? throw(SectorMismatch("cannot fuse sectors $(f₁.coupled) and $(f₂.coupled) to $c")) return fusiontreedict(I)(f₁ => Fsymbol(c, c, c, c, c, c)[1, 1, 1, 1]) end From 09467c63e1982b0e90f87a36f8b616001c213af7 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 17 Mar 2025 17:59:16 +0100 Subject: [PATCH 03/34] change one to leftone in bendright --- src/fusiontrees/manipulations.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index 8c02c1741..218e2fa05 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -268,7 +268,7 @@ function bendright(f₁::FusionTree{I,N₁}, f₂::FusionTree{I,N₂}) where {I< # map final splitting vertex (a, b)<-c to fusion vertex a<-(c, dual(b)) @assert N₁ > 0 c = f₁.coupled - a = N₁ == 1 ? one(I) : (N₁ == 2 ? f₁.uncoupled[1] : f₁.innerlines[end]) + a = N₁ == 1 ? leftone(f₁.uncoupled[1]) : (N₁ == 2 ? f₁.uncoupled[1] : f₁.innerlines[end]) b = f₁.uncoupled[N₁] uncoupled1 = TupleTools.front(f₁.uncoupled) From 2878e082e671bc264552bb16d30c96adba061b0d Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 17 Mar 2025 17:59:38 +0100 Subject: [PATCH 04/34] change one to leftone in foldright --- src/fusiontrees/manipulations.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index 218e2fa05..00a5d5027 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -339,7 +339,7 @@ function foldright(f₁::FusionTree{I,N₁}, f₂::FusionTree{I,N₂}) where {I< hasmultiplicities = FusionStyle(a) isa GenericFusion local newtrees if N₁ == 1 - cset = (one(c1),) + cset = (leftone(c1),) # or rightone(a) elseif N₁ == 2 cset = (f₁.uncoupled[2],) else From 10744b2d6540ce2039f3f071123ee6d9cc267d8b Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 17 Mar 2025 18:00:25 +0100 Subject: [PATCH 05/34] change one to f.coupled in elementary_trace --- src/fusiontrees/manipulations.jl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index 00a5d5027..3fd29fd62 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -701,6 +701,7 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} T = sectorscalartype(I) F = fusiontreetype(I, N - 2) newtrees = FusionTreeDict{F,T}() + _one = f.coupled # otherwise ArgumentError above thrown j = mod1(i + 1, N) b = f.uncoupled[i] @@ -708,7 +709,7 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} # if trace is zero, return empty dict (b == dual(b′) && f.isdual[i] != f.isdual[j]) || return newtrees if i < N - inner_extended = (one(I), f.uncoupled[1], f.innerlines..., f.coupled) + inner_extended = (_one, f.uncoupled[1], f.innerlines..., f.coupled) a = inner_extended[i] d = inner_extended[i + 2] a == d || return newtrees @@ -732,11 +733,11 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} if i > 1 c = f.innerlines[i - 1] if FusionStyle(I) isa MultiplicityFreeFusion - coeff *= Fsymbol(a, b, dual(b), a, c, one(I)) + coeff *= Fsymbol(a, b, dual(b), a, c, _one) else μ = f.vertices[i - 1] ν = f.vertices[i] - coeff *= Fsymbol(a, b, dual(b), a, c, one(I))[μ, ν, 1, 1] + coeff *= Fsymbol(a, b, dual(b), a, c, _one)[μ, ν, 1, 1] end end if f.isdual[i] @@ -746,7 +747,7 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} return newtrees else # i == N if N == 2 - f′ = FusionTree{I}((), one(I), (), (), ()) + f′ = FusionTree{I}((), _one, (), (), ()) coeff = sqrtdim(b) if !(f.isdual[N]) coeff *= conj(frobeniusschur(b)) @@ -762,13 +763,13 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} vertices_ = TupleTools.front(f.vertices) f_ = FusionTree(uncoupled_, coupled_, isdual_, inner_, vertices_) fs = FusionTree((b,), b, (!f.isdual[1],), (), ()) - for (f_′, coeff) in merge(fs, f_, one(I), 1) - f_′.innerlines[1] == one(I) || continue + for (f_′, coeff) in merge(fs, f_, _one, 1) + f_′.innerlines[1] == _one || continue uncoupled′ = Base.tail(Base.tail(f_′.uncoupled)) isdual′ = Base.tail(Base.tail(f_′.isdual)) inner′ = N <= 4 ? () : Base.tail(Base.tail(f_′.innerlines)) vertices′ = N <= 3 ? () : Base.tail(Base.tail(f_′.vertices)) - f′ = FusionTree(uncoupled′, one(I), isdual′, inner′, vertices′) + f′ = FusionTree(uncoupled′, _one, isdual′, inner′, vertices′) coeff *= sqrtdim(b) if !(f.isdual[N]) coeff *= conj(frobeniusschur(b)) From 1ed1ed1bccc5fa107514605dff21bccbcfb4acf6 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 25 Mar 2025 14:10:46 +0100 Subject: [PATCH 06/34] progress on correct units in trace --- src/fusiontrees/manipulations.jl | 40 +++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index 3fd29fd62..2cef01436 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -551,6 +551,9 @@ const TransposeKey{I<:Sector,N₁,N₂} = Tuple{<:FusionTree{I},<:FusionTree{I}, function _transpose((f₁, f₂, p1, p2)::TransposeKey{I,N₁,N₂}) where {I<:Sector,N₁,N₂} N = N₁ + N₂ p = linearizepermutation(p1, p2, length(f₁), length(f₂)) + @info "_transpose" + @show f₁ + @show f₂ newtrees = repartition(f₁, f₂, N₁) length(p) == 0 && return newtrees i1 = findfirst(==(1), p) @@ -619,8 +622,14 @@ function planar_trace(f₁::FusionTree{I}, f₂::FusionTree{I}, F₂ = fusiontreetype(I, N₂) newtrees = FusionTreeDict{Tuple{F₁,F₂},T}() for ((f₁′, f₂′), coeff′) in repartition(f₁, f₂, N) - for (f₁′′, coeff′′) in planar_trace(f₁′, q1′, q2′) - for (f12′′′, coeff′′′) in transpose(f₁′′, f₂′, p1′, p2′) + for (f₁′′, coeff′′) in planar_trace(f₁′, q1′, q2′) # errors in this planar_trace first + @info "planar_trace" + @show f₁ + @show f₂ + @show f₁′ + @show f₁′′ + @show f₂′ + for (f12′′′, coeff′′′) in transpose(f₁′′, f₂′, p1′, p2′) # for a different unit errors here coeff = coeff′ * coeff′′ * coeff′′′ if !iszero(coeff) newtrees[f12′′′] = get(newtrees, f12′′′, zero(coeff)) + coeff @@ -673,7 +682,7 @@ function planar_trace(f::FusionTree{I,N}, q2′ = let i = i, j = j map(l -> (l - (l > i) - (l > j)), TupleTools.deleteat(q2, k)) end - for (f′, coeff′) in elementary_trace(f, i) + for (f′, coeff′) in elementary_trace(f, i) # errors then here for (f′′, coeff′′) in planar_trace(f′, q1′, q2′) coeff = coeff′ * coeff′′ if !iszero(coeff) @@ -702,6 +711,8 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} F = fusiontreetype(I, N - 2) newtrees = FusionTreeDict{F,T}() _one = f.coupled # otherwise ArgumentError above thrown + @info "elementary_trace" + @show f j = mod1(i + 1, N) b = f.uncoupled[i] @@ -709,7 +720,8 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} # if trace is zero, return empty dict (b == dual(b′) && f.isdual[i] != f.isdual[j]) || return newtrees if i < N - inner_extended = (_one, f.uncoupled[1], f.innerlines..., f.coupled) + @info "elementary_trace: i < N" + inner_extended = (leftone(f.uncoupled[1]), f.uncoupled[1], f.innerlines..., f.coupled) a = inner_extended[i] d = inner_extended[i + 2] a == d || return newtrees @@ -733,21 +745,23 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} if i > 1 c = f.innerlines[i - 1] if FusionStyle(I) isa MultiplicityFreeFusion - coeff *= Fsymbol(a, b, dual(b), a, c, _one) + coeff *= Fsymbol(a, b, dual(b), a, c, rightone(a)) else μ = f.vertices[i - 1] ν = f.vertices[i] - coeff *= Fsymbol(a, b, dual(b), a, c, _one)[μ, ν, 1, 1] + coeff *= Fsymbol(a, b, dual(b), a, c, rightone(a))[μ, ν, 1, 1] end end if f.isdual[i] coeff *= frobeniusschur(b) end + @show f′ push!(newtrees, f′ => coeff) return newtrees else # i == N + @info "elementary_trace: i == N" if N == 2 - f′ = FusionTree{I}((), _one, (), (), ()) + f′ = FusionTree{I}((), _one, (), (), ()) # or leftone(f.uncoupled[1]) == rightone(f.uncoupled[2]) coeff = sqrtdim(b) if !(f.isdual[N]) coeff *= conj(frobeniusschur(b)) @@ -758,18 +772,22 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} uncoupled_ = TupleTools.front(f.uncoupled) inner_ = TupleTools.front(f.innerlines) coupled_ = f.innerlines[end] - @assert coupled_ == dual(b) + @assert coupled_ == dual(b) # isn't this always true at this point? isdual_ = TupleTools.front(f.isdual) vertices_ = TupleTools.front(f.vertices) f_ = FusionTree(uncoupled_, coupled_, isdual_, inner_, vertices_) fs = FusionTree((b,), b, (!f.isdual[1],), (), ()) - for (f_′, coeff) in merge(fs, f_, _one, 1) - f_′.innerlines[1] == _one || continue + @show f_ + @show fs + unit = leftone(fs.coupled) + for (f_′, coeff) in merge(fs, f_, unit, 1) # coloring gets reversed here, should be the other unit + f_′.innerlines[1] == unit || continue # is this one valid? uncoupled′ = Base.tail(Base.tail(f_′.uncoupled)) isdual′ = Base.tail(Base.tail(f_′.isdual)) inner′ = N <= 4 ? () : Base.tail(Base.tail(f_′.innerlines)) vertices′ = N <= 3 ? () : Base.tail(Base.tail(f_′.vertices)) - f′ = FusionTree(uncoupled′, _one, isdual′, inner′, vertices′) + f′ = FusionTree(uncoupled′, unit, isdual′, inner′, vertices′) # and this one? + @show f′ coeff *= sqrtdim(b) if !(f.isdual[N]) coeff *= conj(frobeniusschur(b)) From c31b99c7a0cf80aa4e91afe97987f9fcabe82a67 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 25 Mar 2025 17:27:11 +0100 Subject: [PATCH 07/34] change dim of GradedSpace to not evaluate one --- src/spaces/gradedspace.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spaces/gradedspace.jl b/src/spaces/gradedspace.jl index 00f97c962..8233a0833 100644 --- a/src/spaces/gradedspace.jl +++ b/src/spaces/gradedspace.jl @@ -90,9 +90,9 @@ Base.hash(V::GradedSpace, h::UInt) = hash(V.dual, hash(V.dims, h)) # properties field(::Type{<:GradedSpace}) = ℂ InnerProductStyle(::Type{<:GradedSpace}) = EuclideanInnerProduct() -function dim(V::GradedSpace) +function dim(V::GradedSpace{I}) where {I<:Sector} return reduce(+, dim(V, c) * dim(c) for c in sectors(V); - init=zero(dim(one(sectortype(V))))) + init=zero(TensorKitSectors._Fscalartype(I))) end function dim(V::GradedSpace{I,<:AbstractDict}, c::I) where {I<:Sector} return get(V.dims, isdual(V) ? dual(c) : c, 0) From a33d0287ae699c24dc3602c3141a87f3fb04f9e5 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 26 Mar 2025 09:27:25 +0100 Subject: [PATCH 08/34] use a function that's actually exported in dimension of `GradedSpace` --- src/spaces/gradedspace.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spaces/gradedspace.jl b/src/spaces/gradedspace.jl index 8233a0833..82c1a41c7 100644 --- a/src/spaces/gradedspace.jl +++ b/src/spaces/gradedspace.jl @@ -92,7 +92,7 @@ field(::Type{<:GradedSpace}) = ℂ InnerProductStyle(::Type{<:GradedSpace}) = EuclideanInnerProduct() function dim(V::GradedSpace{I}) where {I<:Sector} return reduce(+, dim(V, c) * dim(c) for c in sectors(V); - init=zero(TensorKitSectors._Fscalartype(I))) + init=zero(sectorscalartype(I))) end function dim(V::GradedSpace{I,<:AbstractDict}, c::I) where {I<:Sector} return get(V.dims, isdual(V) ? dual(c) : c, 0) From 0e3c5dfcb9f583cb216ddccafe1f83efb7ddd142 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Thu, 10 Apr 2025 13:47:13 -0400 Subject: [PATCH 09/34] update TensorOperations scalartype determination --- src/tensors/tensoroperations.jl | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tensors/tensoroperations.jl b/src/tensors/tensoroperations.jl index cf977690f..6f59ed699 100644 --- a/src/tensors/tensoroperations.jl +++ b/src/tensors/tensoroperations.jl @@ -52,7 +52,8 @@ end function TO.tensoradd_type(TC, A::AbstractTensorMap, ::Index2Tuple{N₁,N₂}, ::Bool) where {N₁,N₂} - M = similarstoragetype(A, TC) + Tnew = VectorInterface.promote_add(TC, scalartype(A), sectorscalartype(sectortype(A))) + M = similarstoragetype(A, Tnew) return tensormaptype(spacetype(A), N₁, N₂, M) end @@ -113,9 +114,12 @@ function TO.tensorcontract_type(TC, A::AbstractTensorMap, ::Index2Tuple, ::Bool, B::AbstractTensorMap, ::Index2Tuple, ::Bool, ::Index2Tuple{N₁,N₂}) where {N₁,N₂} - M = similarstoragetype(A, TC) - M == similarstoragetype(B, TC) || - throw(ArgumentError("incompatible storage types:\n$(M) ≠ $(similarstoragetype(B, TC))")) + Tnew = TensorOperations.promote_contract(TC, scalartype(A), + sectorscalartype(sectortype(A)), + scalartype(B), sectorscalartype(sectortype(B))) + M = similarstoragetype(A, Tnew) + M == similarstoragetype(B, Tnew) || + throw(ArgumentError("incompatible storage types:\n$(M) ≠ $(similarstoragetype(B, Tnew))")) spacetype(A) == spacetype(B) || throw(SpaceMismatch("incompatible space types")) return tensormaptype(spacetype(A), N₁, N₂, M) end From 963536225a1e94a07a3a0c4f9980d9ca96ae9328 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 14 Apr 2025 17:11:39 +0200 Subject: [PATCH 10/34] Revert "use a function that's actually exported in dimension of `GradedSpace`" This reverts commit a33d0287ae699c24dc3602c3141a87f3fb04f9e5. --- src/spaces/gradedspace.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spaces/gradedspace.jl b/src/spaces/gradedspace.jl index 82c1a41c7..8233a0833 100644 --- a/src/spaces/gradedspace.jl +++ b/src/spaces/gradedspace.jl @@ -92,7 +92,7 @@ field(::Type{<:GradedSpace}) = ℂ InnerProductStyle(::Type{<:GradedSpace}) = EuclideanInnerProduct() function dim(V::GradedSpace{I}) where {I<:Sector} return reduce(+, dim(V, c) * dim(c) for c in sectors(V); - init=zero(sectorscalartype(I))) + init=zero(TensorKitSectors._Fscalartype(I))) end function dim(V::GradedSpace{I,<:AbstractDict}, c::I) where {I<:Sector} return get(V.dims, isdual(V) ? dual(c) : c, 0) From 4bc1e7c38b4b84661f409789e2ba62b3a28efe46 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 14 Apr 2025 17:11:46 +0200 Subject: [PATCH 11/34] Revert "change dim of GradedSpace to not evaluate one" This reverts commit c31b99c7a0cf80aa4e91afe97987f9fcabe82a67. --- src/spaces/gradedspace.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spaces/gradedspace.jl b/src/spaces/gradedspace.jl index 8233a0833..00f97c962 100644 --- a/src/spaces/gradedspace.jl +++ b/src/spaces/gradedspace.jl @@ -90,9 +90,9 @@ Base.hash(V::GradedSpace, h::UInt) = hash(V.dual, hash(V.dims, h)) # properties field(::Type{<:GradedSpace}) = ℂ InnerProductStyle(::Type{<:GradedSpace}) = EuclideanInnerProduct() -function dim(V::GradedSpace{I}) where {I<:Sector} +function dim(V::GradedSpace) return reduce(+, dim(V, c) * dim(c) for c in sectors(V); - init=zero(TensorKitSectors._Fscalartype(I))) + init=zero(dim(one(sectortype(V))))) end function dim(V::GradedSpace{I,<:AbstractDict}, c::I) where {I<:Sector} return get(V.dims, isdual(V) ? dual(c) : c, 0) From 24be2ea1e8618c81600dc4c6fd990148c2d9e11d Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 16 Apr 2025 16:57:32 +0200 Subject: [PATCH 12/34] irrelevant typos, but must be corrected --- src/spaces/gradedspace.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/spaces/gradedspace.jl b/src/spaces/gradedspace.jl index 00f97c962..cd43a4529 100644 --- a/src/spaces/gradedspace.jl +++ b/src/spaces/gradedspace.jl @@ -189,16 +189,16 @@ end function Base.show(io::IO, V::GradedSpace{I}) where {I<:Sector} print(io, type_repr(typeof(V)), "(") - seperator = "" + separator = "" comma = ", " io2 = IOContext(io, :typeinfo => I) for c in sectors(V) if isdual(V) - print(io2, seperator, dual(c), "=>", dim(V, c)) + print(io2, separator, dual(c), "=>", dim(V, c)) else - print(io2, seperator, c, "=>", dim(V, c)) + print(io2, separator, c, "=>", dim(V, c)) end - seperator = comma + separator = comma end print(io, ")") V.dual && print(io, "'") From 13af986e5beac9c5092120f6ad0143e632df7758 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 16 Apr 2025 17:00:37 +0200 Subject: [PATCH 13/34] another minor typo --- src/spaces/gradedspace.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spaces/gradedspace.jl b/src/spaces/gradedspace.jl index cd43a4529..7aa746076 100644 --- a/src/spaces/gradedspace.jl +++ b/src/spaces/gradedspace.jl @@ -12,7 +12,7 @@ isomorphism classes of simple objects of a unitary and pivotal (pre-)fusion cate Here `dims` represents the degeneracy or multiplicity of every sector. -The data structure `D` of `dims` will depend on the result `Base.IteratorElsize(values(I))`; +The data structure `D` of `dims` will depend on the result `Base.IteratorSize(values(I))`; if the result is of type `HasLength` or `HasShape`, `dims` will be stored in a `NTuple{N,Int}` with `N = length(values(I))`. This requires that a sector `s::I` can be transformed into an index via `s == getindex(values(I), i)` and From 095dcda200596e68dea6e5893767d401e775cae0 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 6 May 2025 14:54:03 +0200 Subject: [PATCH 14/34] minor typos --- docs/src/man/spaces.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/man/spaces.md b/docs/src/man/spaces.md index df59733ee..9091aaa0e 100644 --- a/docs/src/man/spaces.md +++ b/docs/src/man/spaces.md @@ -297,8 +297,8 @@ corresponding spaces, but in general none of those will be canonical. There are also a number of convenience functions to create isomorphic spaces. The function `fuse(V1, V2, ...)` or `fuse(V1 ⊗ V2 ⊗ ...)` returns an elementary space that is isomorphic to `V1 ⊗ V2 ⊗ ...`. The function `flip(V::ElementarySpace)` returns a space that is -isomorphic to `V` but has `isdual(flip(V)) == isdual(V')`, i.e. if `V` is a normal space -than `flip(V)` is a dual space. `flip(V)` is different from `dual(V)` in the case of +isomorphic to `V` but has `isdual(flip(V)) == isdual(V')`, i.e., if `V` is a normal space, +then `flip(V)` is a dual space. `flip(V)` is different from `dual(V)` in the case of [`GradedSpace`](@ref). It is useful to flip a tensor index from a ket to a bra (or vice versa), by contracting that index with a unitary map from `V1` to `flip(V1)`. We refer to the reference on [vector space methods](@ref s_spacemethods) for further information. From fbfb56418f9edd979b716a0e5cfa51c463d61c44 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 6 May 2025 15:37:54 +0200 Subject: [PATCH 15/34] then vs than is hard --- docs/src/man/sectors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/man/sectors.md b/docs/src/man/sectors.md index 81dbfd35d..b0a1bd27d 100644 --- a/docs/src/man/sectors.md +++ b/docs/src/man/sectors.md @@ -771,7 +771,7 @@ groups. Other methods for `ElementarySpace`, such as [`dual`](@ref), [`fuse`](@ref) and [`flip`](@ref) also work. In fact, `GradedSpace` is the reason `flip` exists, cause -in this case it is different then `dual`. The existence of flip originates from the +in this case it is different than `dual`. The existence of flip originates from the non-trivial isomorphism between ``R_{\overline{a}}`` and ``R_{a}^*``, i.e. the representation space of the dual ``\overline{a}`` of sector ``a`` and the dual of the representation space of sector ``a``. In order for `flip(V)` to be isomorphic to `V`, it is From d7cae4fc4e83be12c5a8ace099168980639126c2 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 7 May 2025 11:14:53 +0200 Subject: [PATCH 16/34] remove debug elements --- src/fusiontrees/manipulations.jl | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index 2cef01436..1a62c0a14 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -551,9 +551,6 @@ const TransposeKey{I<:Sector,N₁,N₂} = Tuple{<:FusionTree{I},<:FusionTree{I}, function _transpose((f₁, f₂, p1, p2)::TransposeKey{I,N₁,N₂}) where {I<:Sector,N₁,N₂} N = N₁ + N₂ p = linearizepermutation(p1, p2, length(f₁), length(f₂)) - @info "_transpose" - @show f₁ - @show f₂ newtrees = repartition(f₁, f₂, N₁) length(p) == 0 && return newtrees i1 = findfirst(==(1), p) @@ -623,12 +620,6 @@ function planar_trace(f₁::FusionTree{I}, f₂::FusionTree{I}, newtrees = FusionTreeDict{Tuple{F₁,F₂},T}() for ((f₁′, f₂′), coeff′) in repartition(f₁, f₂, N) for (f₁′′, coeff′′) in planar_trace(f₁′, q1′, q2′) # errors in this planar_trace first - @info "planar_trace" - @show f₁ - @show f₂ - @show f₁′ - @show f₁′′ - @show f₂′ for (f12′′′, coeff′′′) in transpose(f₁′′, f₂′, p1′, p2′) # for a different unit errors here coeff = coeff′ * coeff′′ * coeff′′′ if !iszero(coeff) @@ -711,8 +702,6 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} F = fusiontreetype(I, N - 2) newtrees = FusionTreeDict{F,T}() _one = f.coupled # otherwise ArgumentError above thrown - @info "elementary_trace" - @show f j = mod1(i + 1, N) b = f.uncoupled[i] @@ -720,7 +709,6 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} # if trace is zero, return empty dict (b == dual(b′) && f.isdual[i] != f.isdual[j]) || return newtrees if i < N - @info "elementary_trace: i < N" inner_extended = (leftone(f.uncoupled[1]), f.uncoupled[1], f.innerlines..., f.coupled) a = inner_extended[i] d = inner_extended[i + 2] @@ -755,11 +743,9 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} if f.isdual[i] coeff *= frobeniusschur(b) end - @show f′ push!(newtrees, f′ => coeff) return newtrees else # i == N - @info "elementary_trace: i == N" if N == 2 f′ = FusionTree{I}((), _one, (), (), ()) # or leftone(f.uncoupled[1]) == rightone(f.uncoupled[2]) coeff = sqrtdim(b) @@ -777,8 +763,6 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} vertices_ = TupleTools.front(f.vertices) f_ = FusionTree(uncoupled_, coupled_, isdual_, inner_, vertices_) fs = FusionTree((b,), b, (!f.isdual[1],), (), ()) - @show f_ - @show fs unit = leftone(fs.coupled) for (f_′, coeff) in merge(fs, f_, unit, 1) # coloring gets reversed here, should be the other unit f_′.innerlines[1] == unit || continue # is this one valid? @@ -787,7 +771,6 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} inner′ = N <= 4 ? () : Base.tail(Base.tail(f_′.innerlines)) vertices′ = N <= 3 ? () : Base.tail(Base.tail(f_′.vertices)) f′ = FusionTree(uncoupled′, unit, isdual′, inner′, vertices′) # and this one? - @show f′ coeff *= sqrtdim(b) if !(f.isdual[N]) coeff *= conj(frobeniusschur(b)) From 4fe82f967b30e8e418a952318e987a12c31c49f7 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 8 May 2025 15:00:51 +0200 Subject: [PATCH 17/34] change TensorOperations scalartype promotion to base off field of numbers --- src/tensors/tensoroperations.jl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/tensors/tensoroperations.jl b/src/tensors/tensoroperations.jl index 6f59ed699..221213204 100644 --- a/src/tensors/tensoroperations.jl +++ b/src/tensors/tensoroperations.jl @@ -52,7 +52,8 @@ end function TO.tensoradd_type(TC, A::AbstractTensorMap, ::Index2Tuple{N₁,N₂}, ::Bool) where {N₁,N₂} - Tnew = VectorInterface.promote_add(TC, scalartype(A), sectorscalartype(sectortype(A))) + sst = sectorscalartype(sectortype(A)) + Tnew = sst <: Real ? TC : VectorInterface.promote_add(TC, scalartype(A), sst) M = similarstoragetype(A, Tnew) return tensormaptype(spacetype(A), N₁, N₂, M) end @@ -114,9 +115,10 @@ function TO.tensorcontract_type(TC, A::AbstractTensorMap, ::Index2Tuple, ::Bool, B::AbstractTensorMap, ::Index2Tuple, ::Bool, ::Index2Tuple{N₁,N₂}) where {N₁,N₂} - Tnew = TensorOperations.promote_contract(TC, scalartype(A), - sectorscalartype(sectortype(A)), - scalartype(B), sectorscalartype(sectortype(B))) + sst(x) = sectorscalartype(sectortype(x)) + Tnew = (sst(A) <: Real && sst(B) <: Real) ? TC : + TO.promote_contract(TC, scalartype(A), sst(A), + scalartype(B), sst(B)) M = similarstoragetype(A, Tnew) M == similarstoragetype(B, Tnew) || throw(ArgumentError("incompatible storage types:\n$(M) ≠ $(similarstoragetype(B, Tnew))")) From 55a00c02284597ef66c23bd76d78d9d5669fee34 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Fri, 13 Jun 2025 15:08:47 +0200 Subject: [PATCH 18/34] typo in docs --- docs/src/man/categories.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/man/categories.md b/docs/src/man/categories.md index a6efcc85c..3515af5d4 100644 --- a/docs/src/man/categories.md +++ b/docs/src/man/categories.md @@ -225,7 +225,7 @@ morphism from ``I`` to ``V``. To map morphisms from ``\mathrm{Hom}(W,V)`` to ele ``V ⊗ W^*``, i.e. morphisms in ``\mathrm{Hom}(I, V ⊗ W^*)``, we use another morphism ``\mathrm{Hom}(I, W ⊗ W^*)`` which can be considered as the inverse of the evaluation map. -Hence, duality in a monoidal category is defined via an *exact paring*, i.e. two families +Hence, duality in a monoidal category is defined via an *exact pairing*, i.e. two families of non-degenerate morphisms, the evaluation (or co-unit) ``ϵ_V: {}^{∨}V ⊗ V → I`` and the coevaluation (or unit) ``η_V: I → V ⊗ {}^{∨}V`` which satisfy the "snake rules": From 0113f7396a6b9323066ca5480aca03473c1b0fb2 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Fri, 13 Jun 2025 22:06:37 +0200 Subject: [PATCH 19/34] remove some debug comments --- src/fusiontrees/manipulations.jl | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index 44edca111..5016dbafe 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -166,8 +166,8 @@ operation is the inverse of `insertat` in the sense that if return f₁, f₂ elseif M === 0 # TODO: evaluate diagrams to see which unit is used here - f₁ = FusionTree{I}((), one(I), (), ()) - uncoupled2 = (one(I), f.uncoupled...) + f₁ = FusionTree{I}((), one(I), (), ()) + uncoupled2 = (one(I), f.uncoupled...) coupled2 = f.coupled isdual2 = (false, f.isdual...) innerlines2 = N >= 2 ? (f.uncoupled[1], f.innerlines...) : () @@ -290,7 +290,8 @@ function bendright(f₁::FusionTree{I,N₁}, f₂::FusionTree{I,N₂}) where {I< # map final splitting vertex (a, b)<-c to fusion vertex a<-(c, dual(b)) @assert N₁ > 0 c = f₁.coupled - a = N₁ == 1 ? leftone(f₁.uncoupled[1]) : (N₁ == 2 ? f₁.uncoupled[1] : f₁.innerlines[end]) + a = N₁ == 1 ? leftone(f₁.uncoupled[1]) : + (N₁ == 2 ? f₁.uncoupled[1] : f₁.innerlines[end]) b = f₁.uncoupled[N₁] uncoupled1 = TupleTools.front(f₁.uncoupled) @@ -641,8 +642,8 @@ function planar_trace(f₁::FusionTree{I}, f₂::FusionTree{I}, F₂ = fusiontreetype(I, N₂) newtrees = FusionTreeDict{Tuple{F₁,F₂},T}() for ((f₁′, f₂′), coeff′) in repartition(f₁, f₂, N) - for (f₁′′, coeff′′) in planar_trace(f₁′, q1′, q2′) # errors in this planar_trace first - for (f12′′′, coeff′′′) in transpose(f₁′′, f₂′, p1′, p2′) # for a different unit errors here + for (f₁′′, coeff′′) in planar_trace(f₁′, q1′, q2′) + for (f12′′′, coeff′′′) in transpose(f₁′′, f₂′, p1′, p2′) coeff = coeff′ * coeff′′ * coeff′′′ if !iszero(coeff) newtrees[f12′′′] = get(newtrees, f12′′′, zero(coeff)) + coeff @@ -695,7 +696,7 @@ function planar_trace(f::FusionTree{I,N}, q2′ = let i = i, j = j map(l -> (l - (l > i) - (l > j)), TupleTools.deleteat(q2, k)) end - for (f′, coeff′) in elementary_trace(f, i) # errors then here + for (f′, coeff′) in elementary_trace(f, i) for (f′′, coeff′′) in planar_trace(f′, q1′, q2′) coeff = coeff′ * coeff′′ if !iszero(coeff) @@ -723,7 +724,7 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} T = sectorscalartype(I) F = fusiontreetype(I, N - 2) newtrees = FusionTreeDict{F,T}() - _one = f.coupled # otherwise ArgumentError above thrown + _one = f.coupled j = mod1(i + 1, N) b = f.uncoupled[i] @@ -731,7 +732,8 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} # if trace is zero, return empty dict (b == dual(b′) && f.isdual[i] != f.isdual[j]) || return newtrees if i < N - inner_extended = (leftone(f.uncoupled[1]), f.uncoupled[1], f.innerlines..., f.coupled) + inner_extended = (leftone(f.uncoupled[1]), f.uncoupled[1], f.innerlines..., + f.coupled) a = inner_extended[i] d = inner_extended[i + 2] a == d || return newtrees From 8e8b76087378e84be7f7a09073957a924ad0b21b Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 18 Jun 2025 10:25:02 +0200 Subject: [PATCH 20/34] more rigorous check in `merge` --- src/fusiontrees/manipulations.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index 5016dbafe..e5f2241ab 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -231,7 +231,7 @@ function merge(f₁::FusionTree{I,N₁}, f₂::FusionTree{I,N₂}, return insertat(f, N₁ + 1, f₂) end function merge(f₁::FusionTree{I,0}, f₂::FusionTree{I,0}, c::I, μ) where {I} - isone(c) || # I had this as Nsymbol(f₁.coupled, f₂.coupled, c) > 0, valid? + Nsymbol(f₁.coupled, f₂.coupled, c) == μ == 1 || throw(SectorMismatch("cannot fuse sectors $(f₁.coupled) and $(f₂.coupled) to $c")) return fusiontreedict(I)(f₁ => Fsymbol(c, c, c, c, c, c)[1, 1, 1, 1]) end From 78b135e318ff3b1dfd30fa0f343d45bbd7c0b1ce Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 18 Jun 2025 10:48:54 +0200 Subject: [PATCH 21/34] replace `one` evaluation in `split` with `leftone` --- src/fusiontrees/manipulations.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index e5f2241ab..2ad8a5252 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -165,9 +165,8 @@ operation is the inverse of `insertat` in the sense that if f₂ = FusionTree{I}(f.uncoupled, f.coupled, isdual2, f.innerlines, f.vertices) return f₁, f₂ elseif M === 0 - # TODO: evaluate diagrams to see which unit is used here - f₁ = FusionTree{I}((), one(I), (), ()) - uncoupled2 = (one(I), f.uncoupled...) + f₁ = FusionTree{I}((), leftone(f.uncoupled[1]), (), ()) + uncoupled2 = (leftone(f.uncoupled[1]), f.uncoupled...) coupled2 = f.coupled isdual2 = (false, f.isdual...) innerlines2 = N >= 2 ? (f.uncoupled[1], f.innerlines...) : () From 440b42b80cfb97f8603742434b8dda5e5aa3c62d Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 18 Jun 2025 10:51:30 +0200 Subject: [PATCH 22/34] typos in docs --- docs/src/man/sectors.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/man/sectors.md b/docs/src/man/sectors.md index b0a1bd27d..f771bc792 100644 --- a/docs/src/man/sectors.md +++ b/docs/src/man/sectors.md @@ -894,7 +894,7 @@ for the specific case ``N_1=4`` and ``N_2=3``. We can separate this tree into th part ``(b_1⊗b_2)⊗b_3 → c`` and the splitting part ``c→(((a_1⊗a_2)⊗a_3)⊗a_4)``. Given that the fusion tree can be considered to be the adjoint of a corresponding splitting tree ``c→(b_1⊗b_2)⊗b_3``, we now first consider splitting trees in isolation. A splitting tree -which goes from one coupled sectors ``c`` to ``N`` uncoupled sectors ``a_1``, ``a_2``, …, +which goes from one coupled sector ``c`` to ``N`` uncoupled sectors ``a_1``, ``a_2``, …, ``a_N`` needs ``N-2`` additional internal sector labels ``e_1``, …, ``e_{N-2}``, and, if `FusionStyle(I) isa GenericFusion`, ``N-1`` additional multiplicity labels ``μ_1``, …, ``μ_{N-1}``. We henceforth refer to them as vertex labels, as they are associated with @@ -908,7 +908,7 @@ the orthogonality condition which now forces all internal lines ``e_k`` and vertex labels ``μ_l`` to be the same. There is one subtle remark that we have so far ignored. Within the specific subtypes of -`Sector`, we do not explicitly distinguish between ``R_a^*`` (simply denoted as ``a`^*`` +`Sector`, we do not explicitly distinguish between ``R_a^*`` (simply denoted as ``a^*`` and graphically depicted as an upgoing arrow ``a``) and ``R_{\bar{a}}`` (simply denoted as ``\bar{a}`` and depicted with a downgoing arrow), i.e. between the dual space of ``R_a`` on which the conjugated irrep acts, or the irrep ``\bar{a}`` to which the complex conjugate of From 00825afad7717ec8dbe75296fa1e9aed00bda752 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 18 Jun 2025 16:47:19 +0200 Subject: [PATCH 23/34] typo in `_fusiontree_iterate` --- src/fusiontrees/iterator.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fusiontrees/iterator.jl b/src/fusiontrees/iterator.jl index a225b31b9..7e7106daf 100644 --- a/src/fusiontrees/iterator.jl +++ b/src/fusiontrees/iterator.jl @@ -157,7 +157,7 @@ function _fusiontree_iterate(uncoupledsectors::NTuple{N}, nextout = iterate(outiterN, outstateN) nextout === nothing && return nothing b, outstateN = nextout - vertexiterN = c ⊗ dual(b) + vertexiterN = coupled ⊗ dual(b) nextline = iterate(vertexiterN) end a, vertexstateN = nextline From aad8fc80740905b1547dddf64783c8842ce3e276 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Fri, 4 Jul 2025 18:06:22 +0200 Subject: [PATCH 24/34] apply suggestions related to tensor types --- src/tensors/tensoroperations.jl | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/tensors/tensoroperations.jl b/src/tensors/tensoroperations.jl index 221213204..aab2b67cf 100644 --- a/src/tensors/tensoroperations.jl +++ b/src/tensors/tensoroperations.jl @@ -52,9 +52,8 @@ end function TO.tensoradd_type(TC, A::AbstractTensorMap, ::Index2Tuple{N₁,N₂}, ::Bool) where {N₁,N₂} - sst = sectorscalartype(sectortype(A)) - Tnew = sst <: Real ? TC : VectorInterface.promote_add(TC, scalartype(A), sst) - M = similarstoragetype(A, Tnew) + I = sectortype(A) + M = similarstoragetype(A, sectorscalartype(I) <: Real ? TC : complex(TC)) return tensormaptype(spacetype(A), N₁, N₂, M) end @@ -115,14 +114,11 @@ function TO.tensorcontract_type(TC, A::AbstractTensorMap, ::Index2Tuple, ::Bool, B::AbstractTensorMap, ::Index2Tuple, ::Bool, ::Index2Tuple{N₁,N₂}) where {N₁,N₂} - sst(x) = sectorscalartype(sectortype(x)) - Tnew = (sst(A) <: Real && sst(B) <: Real) ? TC : - TO.promote_contract(TC, scalartype(A), sst(A), - scalartype(B), sst(B)) - M = similarstoragetype(A, Tnew) - M == similarstoragetype(B, Tnew) || - throw(ArgumentError("incompatible storage types:\n$(M) ≠ $(similarstoragetype(B, Tnew))")) spacetype(A) == spacetype(B) || throw(SpaceMismatch("incompatible space types")) + I = sectortype(A) + M = similarstoragetype(A, sectorscalartype(I) <: Real ? TC : complex(TC)) + MB = similarstoragetype(B, sectorscalartype(I) <: Real ? TC : complex(TC)) + M == MB || throw(ArgumentError("incompatible storage types:\n$(M) ≠ $(MB)")) return tensormaptype(spacetype(A), N₁, N₂, M) end From c0ef01ead2050e7be28c94b24c45e4df38db6826 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Fri, 4 Jul 2025 18:12:07 +0200 Subject: [PATCH 25/34] remove excess variable --- src/fusiontrees/manipulations.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index 2ad8a5252..b53f60377 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -723,7 +723,6 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} T = sectorscalartype(I) F = fusiontreetype(I, N - 2) newtrees = FusionTreeDict{F,T}() - _one = f.coupled j = mod1(i + 1, N) b = f.uncoupled[i] @@ -770,7 +769,7 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} return newtrees else # i == N if N == 2 - f′ = FusionTree{I}((), _one, (), (), ()) # or leftone(f.uncoupled[1]) == rightone(f.uncoupled[2]) + f′ = FusionTree{I}((), f.coupled, (), (), ()) # or leftone(f.uncoupled[1]) == rightone(f.uncoupled[2]) coeff = sqrtdim(b) if !(f.isdual[N]) coeff *= conj(frobeniusschur(b)) From c189284b609a8ff99c61dccd2f2042eb06e7ad4e Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Fri, 4 Jul 2025 18:13:37 +0200 Subject: [PATCH 26/34] apply `split` suggestion --- src/fusiontrees/manipulations.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index b53f60377..219a77789 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -165,8 +165,9 @@ operation is the inverse of `insertat` in the sense that if f₂ = FusionTree{I}(f.uncoupled, f.coupled, isdual2, f.innerlines, f.vertices) return f₁, f₂ elseif M === 0 - f₁ = FusionTree{I}((), leftone(f.uncoupled[1]), (), ()) - uncoupled2 = (leftone(f.uncoupled[1]), f.uncoupled...) + u = leftone(f.uncoupled[1]) + f₁ = FusionTree{I}((), u, (), ()) + uncoupled2 = (u, f.uncoupled...) coupled2 = f.coupled isdual2 = (false, f.isdual...) innerlines2 = N >= 2 ? (f.uncoupled[1], f.innerlines...) : () From bdbd2e61cb17ab767a212149f83a24b55e5bb556 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 7 Jul 2025 13:55:03 +0200 Subject: [PATCH 27/34] format --- src/tensors/tensoroperations.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tensors/tensoroperations.jl b/src/tensors/tensoroperations.jl index aab2b67cf..6110093b6 100644 --- a/src/tensors/tensoroperations.jl +++ b/src/tensors/tensoroperations.jl @@ -52,7 +52,7 @@ end function TO.tensoradd_type(TC, A::AbstractTensorMap, ::Index2Tuple{N₁,N₂}, ::Bool) where {N₁,N₂} - I = sectortype(A) + I = sectortype(A) M = similarstoragetype(A, sectorscalartype(I) <: Real ? TC : complex(TC)) return tensormaptype(spacetype(A), N₁, N₂, M) end From e23e092c8e79921ddefc84def517fc1a7ad06559 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 15 Jul 2025 14:28:05 +0200 Subject: [PATCH 28/34] change units in `elementary_trace` --- src/fusiontrees/manipulations.jl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index 219a77789..7f7fa28b2 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -769,8 +769,9 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} push!(newtrees, f′ => coeff) return newtrees else # i == N + unit = leftone(b) if N == 2 - f′ = FusionTree{I}((), f.coupled, (), (), ()) # or leftone(f.uncoupled[1]) == rightone(f.uncoupled[2]) + f′ = FusionTree{I}((), unit, (), (), ()) coeff = sqrtdim(b) if !(f.isdual[N]) coeff *= conj(frobeniusschur(b)) @@ -781,14 +782,12 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} uncoupled_ = TupleTools.front(f.uncoupled) inner_ = TupleTools.front(f.innerlines) coupled_ = f.innerlines[end] - @assert coupled_ == dual(b) # isn't this always true at this point? isdual_ = TupleTools.front(f.isdual) vertices_ = TupleTools.front(f.vertices) f_ = FusionTree(uncoupled_, coupled_, isdual_, inner_, vertices_) fs = FusionTree((b,), b, (!f.isdual[1],), (), ()) - unit = leftone(fs.coupled) for (f_′, coeff) in merge(fs, f_, unit, 1) # coloring gets reversed here, should be the other unit - f_′.innerlines[1] == unit || continue # is this one valid? + f_′.innerlines[1] == unit || continue uncoupled′ = Base.tail(Base.tail(f_′.uncoupled)) isdual′ = Base.tail(Base.tail(f_′.isdual)) inner′ = N <= 4 ? () : Base.tail(Base.tail(f_′.innerlines)) From 8ec577eb6092e894ac1f664e2728acbc6105871b Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Wed, 16 Jul 2025 09:48:59 -0400 Subject: [PATCH 29/34] correct `eltype` for `BlockIterator` --- src/tensors/blockiterator.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tensors/blockiterator.jl b/src/tensors/blockiterator.jl index b4ec4b87b..b26c31296 100644 --- a/src/tensors/blockiterator.jl +++ b/src/tensors/blockiterator.jl @@ -10,6 +10,6 @@ end Base.IteratorSize(::BlockIterator) = Base.HasLength() Base.IteratorEltype(::BlockIterator) = Base.HasEltype() -Base.eltype(::Type{<:BlockIterator{T}}) where {T} = blocktype(T) +Base.eltype(::Type{<:BlockIterator{T}}) where {T} = Pair{sectortype(T),blocktype(T)} Base.length(iter::BlockIterator) = length(iter.structure) Base.isdone(iter::BlockIterator, state...) = Base.isdone(iter.structure, state...) From d9152738e5087439e605e7b6e5c964865ad838eb Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Wed, 16 Jul 2025 17:15:44 -0400 Subject: [PATCH 30/34] Remove `isdone` --- src/tensors/blockiterator.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tensors/blockiterator.jl b/src/tensors/blockiterator.jl index b26c31296..7929b5d19 100644 --- a/src/tensors/blockiterator.jl +++ b/src/tensors/blockiterator.jl @@ -12,4 +12,3 @@ Base.IteratorSize(::BlockIterator) = Base.HasLength() Base.IteratorEltype(::BlockIterator) = Base.HasEltype() Base.eltype(::Type{<:BlockIterator{T}}) where {T} = Pair{sectortype(T),blocktype(T)} Base.length(iter::BlockIterator) = length(iter.structure) -Base.isdone(iter::BlockIterator, state...) = Base.isdone(iter.structure, state...) From 301780aacbb58c1d460c27d200fa59a68b555e99 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Wed, 16 Jul 2025 17:17:14 -0400 Subject: [PATCH 31/34] Adapt tests to `eltype(blocks)` --- test/tensors.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/tensors.jl b/test/tensors.jl index cf4f53aba..71a8abc56 100644 --- a/test/tensors.jl +++ b/test/tensors.jl @@ -47,7 +47,8 @@ for V in spacelist next = @constinferred Nothing iterate(bs, state) b2 = @constinferred block(t, first(blocksectors(t))) @test b1 == b2 - @test eltype(bs) === typeof(b1) === TensorKit.blocktype(t) + @test eltype(bs) === Pair{typeof(c),typeof(b1)} + @test typeof(b1) === TensorKit.blocktype(t) end end @timedtestset "Tensor Dict conversion" begin From f9cede3464eece8ac76e060bfcecb883b1a3973e Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Wed, 16 Jul 2025 17:28:59 -0400 Subject: [PATCH 32/34] More test fixes --- test/tensors.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/tensors.jl b/test/tensors.jl index 71a8abc56..d9a121c7f 100644 --- a/test/tensors.jl +++ b/test/tensors.jl @@ -49,6 +49,7 @@ for V in spacelist @test b1 == b2 @test eltype(bs) === Pair{typeof(c),typeof(b1)} @test typeof(b1) === TensorKit.blocktype(t) + @test typeof(c) === sectortype(t) end end @timedtestset "Tensor Dict conversion" begin @@ -108,7 +109,9 @@ for V in spacelist next = @constinferred Nothing iterate(bs, state) b2 = @constinferred block(t', first(blocksectors(t'))) @test b1 == b2 - @test eltype(bs) === typeof(b1) === TensorKit.blocktype(t') + @test eltype(bs) === Pair{typeof(c), typeof(b1)} + @test typeof(b1) === TensorKit.blocktype(t') + @test typeof(c) === sectortype(t) # linear algebra @test isa(@constinferred(norm(t)), real(T)) @test norm(t)^2 ≈ dot(t, t) From baf18246133ac34e85b882bb57a56e7743087926 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 17 Jul 2025 09:17:19 +0200 Subject: [PATCH 33/34] even more test fixes --- test/diagonal.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/diagonal.jl b/test/diagonal.jl index e4b3f6225..813d85f72 100644 --- a/test/diagonal.jl +++ b/test/diagonal.jl @@ -21,7 +21,8 @@ diagspacelist = ((ℂ^4)', ℂ[Z2Irrep](0 => 2, 1 => 3), next = @constinferred Nothing iterate(bs, state) b2 = @constinferred block(t, first(blocksectors(t))) @test b1 == b2 - @test eltype(bs) === typeof(b1) === TensorKit.blocktype(t) + @test eltype(bs) === Pair{typeof(c), typeof(b1)} + @test typeof(b1) === TensorKit.blocktype(t) # basic linear algebra @test isa(@constinferred(norm(t)), real(T)) @test norm(t)^2 ≈ dot(t, t) From 9d543ee1435d7bd5335c8c417b871acda6ee322a Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 17 Jul 2025 10:20:44 +0200 Subject: [PATCH 34/34] format --- test/diagonal.jl | 2 +- test/tensors.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/diagonal.jl b/test/diagonal.jl index 813d85f72..ca4816d6a 100644 --- a/test/diagonal.jl +++ b/test/diagonal.jl @@ -21,7 +21,7 @@ diagspacelist = ((ℂ^4)', ℂ[Z2Irrep](0 => 2, 1 => 3), next = @constinferred Nothing iterate(bs, state) b2 = @constinferred block(t, first(blocksectors(t))) @test b1 == b2 - @test eltype(bs) === Pair{typeof(c), typeof(b1)} + @test eltype(bs) === Pair{typeof(c),typeof(b1)} @test typeof(b1) === TensorKit.blocktype(t) # basic linear algebra @test isa(@constinferred(norm(t)), real(T)) diff --git a/test/tensors.jl b/test/tensors.jl index d9a121c7f..45f2511cf 100644 --- a/test/tensors.jl +++ b/test/tensors.jl @@ -109,7 +109,7 @@ for V in spacelist next = @constinferred Nothing iterate(bs, state) b2 = @constinferred block(t', first(blocksectors(t'))) @test b1 == b2 - @test eltype(bs) === Pair{typeof(c), typeof(b1)} + @test eltype(bs) === Pair{typeof(c),typeof(b1)} @test typeof(b1) === TensorKit.blocktype(t') @test typeof(c) === sectortype(t) # linear algebra