From 51a312411bea791391c66829596160f3a2cbd402 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 16 Mar 2026 15:30:09 +0100 Subject: [PATCH 1/6] fallbacks for product sectors involving fusion tensors --- src/product.jl | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/src/product.jl b/src/product.jl index 41411114..cf193910 100644 --- a/src/product.jl +++ b/src/product.jl @@ -117,6 +117,36 @@ function Fsymbol( ) where {I <: ProductSector{<:Tuple{Sector}}} return Fsymbol(map(_firstsector, (a, b, c, d, e, f))...) end +function Fsymbol_from_fusiontensor(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector} + heads = map(_firstsector, (a, b, c, d, e, f)) + tails = map(_tailsector, (a, b, c, d, e, f)) + F₁ = Fsymbol_from_fusiontensor(heads...) + F₂ = Fsymbol_from_fusiontensor(tails...) + if F₁ isa Number && F₂ isa Number + return F₁ * F₂ + elseif F₁ isa Number + a₁, b₁, c₁, d₁, e₁, f₁ = heads + sz₁ = ( + Nsymbol(a₁, b₁, e₁), Nsymbol(e₁, c₁, d₁), Nsymbol(b₁, c₁, f₁), Nsymbol(a₁, f₁, d₁), + ) + F₁′ = fill(F₁, sz₁) + return _kron(F₁′, F₂) + elseif F₂ isa Number + a₂, b₂, c₂, d₂, e₂, f₂ = tails + sz₂ = ( + Nsymbol(a₂, b₂, e₂), Nsymbol(e₂, c₂, d₂), Nsymbol(b₂, c₂, f₂), Nsymbol(a₂, f₂, d₂), + ) + F₂′ = fill(F₂, sz₂) + return _kron(F₁, F₂′) + else + return _kron(F₁, F₂) + end +end +function Fsymbol_from_fusiontensor( + a::I, b::I, c::I, d::I, e::I, f::I + ) where {I <: ProductSector{<:Tuple{Sector}}} + return Fsymbol_from_fusiontensor(map(_firstsector, (a, b, c, d, e, f))...) +end function Rsymbol(a::I, b::I, c::I) where {I <: ProductSector} heads = map(_firstsector, (a, b, c)) @@ -142,6 +172,30 @@ end function Rsymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Rsymbol(map(_firstsector, (a, b, c))...) end +function Rsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} + heads = map(_firstsector, (a, b, c)) + tails = map(_tailsector, (a, b, c)) + R₁ = Rsymbol_from_fusiontensor(heads...) + R₂ = Rsymbol_from_fusiontensor(tails...) + if R₁ isa Number && R₂ isa Number + R₁ * R₂ + elseif R₁ isa Number + a₁, b₁, c₁ = heads + sz₁ = (Nsymbol(a₁, b₁, c₁), Nsymbol(b₁, a₁, c₁)) # 0 x 0 or 1 x 1 + R₁′ = fill(R₁, sz₁) + return _kron(R₁′, R₂) + elseif R₂ isa Number + a₂, b₂, c₂ = tails + sz₂ = (Nsymbol(a₂, b₂, c₂), Nsymbol(b₂, a₂, c₂)) # 0 x 0 or 1 x 1 + R₂′ = fill(R₂, sz₂) + return _kron(R₁, R₂′) + else + return _kron(R₁, R₂) + end +end +function Rsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} + return Rsymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) +end function Bsymbol(a::I, b::I, c::I) where {I <: ProductSector} heads = map(_firstsector, (a, b, c)) @@ -167,6 +221,30 @@ end function Bsymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Bsymbol(map(_firstsector, (a, b, c))...) end +function Bsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} + heads = map(_firstsector, (a, b, c)) + tails = map(_tailsector, (a, b, c)) + B₁ = Bsymbol_from_fusiontensor(heads...) + B₂ = Bsymbol_from_fusiontensor(tails...) + if B₁ isa Number && B₂ isa Number + B₁ * B₂ + elseif B₁ isa Number + a₁, b₁, c₁ = heads + sz₁ = (Nsymbol(a₁, b₁, c₁), Nsymbol(c₁, dual(b₁), a₁)) # 0 x 0 or 1 x 1 + B₁′ = fill(B₁, sz₁) + return _kron(B₁′, B₂) + elseif B₂ isa Number + a₂, b₂, c₂ = tails + sz₂ = (Nsymbol(a₂, b₂, c₂), Nsymbol(c₂, dual(b₂), a₂)) # 0 x 0 or 1 x 1 + B₂′ = fill(B₂, sz₂) + return _kron(B₁, B₂′) + else + return _kron(B₁, B₂) + end +end +function Bsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} + return Bsymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) +end function Asymbol(a::I, b::I, c::I) where {I <: ProductSector} heads = map(_firstsector, (a, b, c)) @@ -192,6 +270,30 @@ end function Asymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Asymbol(map(_firstsector, (a, b, c))...) end +function Asymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} + heads = map(_firstsector, (a, b, c)) + tails = map(_tailsector, (a, b, c)) + A₁ = Asymbol_from_fusiontensor(heads...) + A₂ = Asymbol_from_fusiontensor(tails...) + if A₁ isa Number && A₂ isa Number + A₁ * A₂ + elseif A₁ isa Number + a₁, b₁, c₁ = heads + sz₁ = (Nsymbol(a₁, b₁, c₁), Nsymbol(dual(a₁), c₁, b₁)) # 0 x 0 or 1 x 1 + A₁′ = fill(A₁, sz₁) + return _kron(A₁′, A₂) + elseif A₂ isa Number + a₂, b₂, c₂ = tails + sz₂ = (Nsymbol(a₂, b₂, c₂), Nsymbol(dual(a₂), c₂, b₂)) # 0 x 0 or 1 x 1 + A₂′ = fill(A₂, sz₂) + return _kron(A₁, A₂′) + else + return _kron(A₁, A₂) + end +end +function Asymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} + return Asymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) +end frobenius_schur_phase(p::ProductSector) = prod(frobenius_schur_phase, p.sectors) frobenius_schur_indicator(p::ProductSector) = prod(frobenius_schur_indicator, p.sectors) From c5a743fe6f0c3321fb7357c8496acc90723e7696 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 19 Mar 2026 15:09:32 +0100 Subject: [PATCH 2/6] attempt at refactor --- src/TensorKitSectors.jl | 2 +- src/auxiliary.jl | 35 +++++++++++ src/product.jl | 136 +++------------------------------------- 3 files changed, 44 insertions(+), 129 deletions(-) diff --git a/src/TensorKitSectors.jl b/src/TensorKitSectors.jl index 0743cb18..b09095b4 100644 --- a/src/TensorKitSectors.jl +++ b/src/TensorKitSectors.jl @@ -67,8 +67,8 @@ using WignerSymbols # includes # -------- -include("auxiliary.jl") include("sectors.jl") +include("auxiliary.jl") include("trivial.jl") include("groups.jl") include("irreps/irreps.jl") # irreps of symmetry groups, with bosonic braiding diff --git a/src/auxiliary.jl b/src/auxiliary.jl index 4b2f6a6b..adbaa9d6 100644 --- a/src/auxiliary.jl +++ b/src/auxiliary.jl @@ -13,6 +13,41 @@ function _kron(A, B) end return C end +function _kron_promote(A₁, B₁, sz₁::Function, sz₂::Function) + if A₁ isa Number && B₁ isa Number + return A₁ * B₁ + end + A₂ = A₁ isa Number ? fill(A₁, sz₁()) : A₁ + B₂ = B₁ isa Number ? fill(B₁, sz₂()) : B₁ + return _kron(A₂, B₂) +end + +function _array_size_functions(t₁::NTuple{6, I₁}, t₂::NTuple{6, I₂}) where {I₁ <: Sector, I₂ <: Sector} # for F-symbols + size₁ = () -> begin + a₁, b₁, c₁, d₁, e₁, f₁ = t₁ + (Nsymbol(a₁, b₁, e₁), Nsymbol(e₁, c₁, d₁), Nsymbol(b₁, c₁, f₁), Nsymbol(a₁, f₁, d₁)) + end + size₂ = () -> begin + a₂, b₂, c₂, d₂, e₂, f₂ = t₂ + (Nsymbol(a₂, b₂, e₂), Nsymbol(e₂, c₂, d₂), Nsymbol(b₂, c₂, f₂), Nsymbol(a₂, f₂, d₂)) + end + return size₁, size₂ +end + +# handles R-, A- and B-symbols correctly because of Frobenius reciprocity +# i.e. Nsymbol(a, b, c) = Nsymbol(c, dual(b), a) = Nsymbol(dual(a), c, b) +# and for braided categories Nsymbol(a, b, c) = Nsymbol(b, a, c) +function _matrix_size_functions(t₁::NTuple{3, I₁}, t₂::NTuple{3, I₂}) where {I₁ <: Sector, I₂ <: Sector} + size₁ = () -> begin + a₁, b₁, c₁ = t₁ + (Nsymbol(a₁, b₁, c₁), Nsymbol(a₁, b₁, c₁)) + end + size₂ = () -> begin + a₂, b₂, c₂ = t₂ + (Nsymbol(a₂, b₂, c₂), Nsymbol(a₂, b₂, c₂)) + end + return size₁, size₂ +end # Manhattan based distance enumeration: I is supposed to be one-based index # TODO: is there any way to make this faster? diff --git a/src/product.jl b/src/product.jl index cf193910..f2467c3c 100644 --- a/src/product.jl +++ b/src/product.jl @@ -92,25 +92,7 @@ function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector} tails = map(_tailsector, (a, b, c, d, e, f)) F₁ = Fsymbol(heads...) F₂ = Fsymbol(tails...) - if F₁ isa Number && F₂ isa Number - return F₁ * F₂ - elseif F₁ isa Number - a₁, b₁, c₁, d₁, e₁, f₁ = heads - sz₁ = ( - Nsymbol(a₁, b₁, e₁), Nsymbol(e₁, c₁, d₁), Nsymbol(b₁, c₁, f₁), Nsymbol(a₁, f₁, d₁), - ) - F₁′ = fill(F₁, sz₁) - return _kron(F₁′, F₂) - elseif F₂ isa Number - a₂, b₂, c₂, d₂, e₂, f₂ = tails - sz₂ = ( - Nsymbol(a₂, b₂, e₂), Nsymbol(e₂, c₂, d₂), Nsymbol(b₂, c₂, f₂), Nsymbol(a₂, f₂, d₂), - ) - F₂′ = fill(F₂, sz₂) - return _kron(F₁, F₂′) - else - return _kron(F₁, F₂) - end + return _kron_promote(F₁, F₂, _array_size_functions(heads, tails)...) end function Fsymbol( a::I, b::I, c::I, d::I, e::I, f::I @@ -122,25 +104,7 @@ function Fsymbol_from_fusiontensor(a::I, b::I, c::I, d::I, e::I, f::I) where {I tails = map(_tailsector, (a, b, c, d, e, f)) F₁ = Fsymbol_from_fusiontensor(heads...) F₂ = Fsymbol_from_fusiontensor(tails...) - if F₁ isa Number && F₂ isa Number - return F₁ * F₂ - elseif F₁ isa Number - a₁, b₁, c₁, d₁, e₁, f₁ = heads - sz₁ = ( - Nsymbol(a₁, b₁, e₁), Nsymbol(e₁, c₁, d₁), Nsymbol(b₁, c₁, f₁), Nsymbol(a₁, f₁, d₁), - ) - F₁′ = fill(F₁, sz₁) - return _kron(F₁′, F₂) - elseif F₂ isa Number - a₂, b₂, c₂, d₂, e₂, f₂ = tails - sz₂ = ( - Nsymbol(a₂, b₂, e₂), Nsymbol(e₂, c₂, d₂), Nsymbol(b₂, c₂, f₂), Nsymbol(a₂, f₂, d₂), - ) - F₂′ = fill(F₂, sz₂) - return _kron(F₁, F₂′) - else - return _kron(F₁, F₂) - end + return _kron_promote(F₁, F₂, _array_size_functions(heads, tails)...) end function Fsymbol_from_fusiontensor( a::I, b::I, c::I, d::I, e::I, f::I @@ -153,21 +117,7 @@ function Rsymbol(a::I, b::I, c::I) where {I <: ProductSector} tails = map(_tailsector, (a, b, c)) R₁ = Rsymbol(heads...) R₂ = Rsymbol(tails...) - if R₁ isa Number && R₂ isa Number - R₁ * R₂ - elseif R₁ isa Number - a₁, b₁, c₁ = heads - sz₁ = (Nsymbol(a₁, b₁, c₁), Nsymbol(b₁, a₁, c₁)) # 0 x 0 or 1 x 1 - R₁′ = fill(R₁, sz₁) - return _kron(R₁′, R₂) - elseif R₂ isa Number - a₂, b₂, c₂ = tails - sz₂ = (Nsymbol(a₂, b₂, c₂), Nsymbol(b₂, a₂, c₂)) # 0 x 0 or 1 x 1 - R₂′ = fill(R₂, sz₂) - return _kron(R₁, R₂′) - else - return _kron(R₁, R₂) - end + return _kron_promote(R₁, R₂, _matrix_size_functions(heads, tails)...) end function Rsymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Rsymbol(map(_firstsector, (a, b, c))...) @@ -177,21 +127,7 @@ function Rsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} tails = map(_tailsector, (a, b, c)) R₁ = Rsymbol_from_fusiontensor(heads...) R₂ = Rsymbol_from_fusiontensor(tails...) - if R₁ isa Number && R₂ isa Number - R₁ * R₂ - elseif R₁ isa Number - a₁, b₁, c₁ = heads - sz₁ = (Nsymbol(a₁, b₁, c₁), Nsymbol(b₁, a₁, c₁)) # 0 x 0 or 1 x 1 - R₁′ = fill(R₁, sz₁) - return _kron(R₁′, R₂) - elseif R₂ isa Number - a₂, b₂, c₂ = tails - sz₂ = (Nsymbol(a₂, b₂, c₂), Nsymbol(b₂, a₂, c₂)) # 0 x 0 or 1 x 1 - R₂′ = fill(R₂, sz₂) - return _kron(R₁, R₂′) - else - return _kron(R₁, R₂) - end + return _kron_promote(R₁, R₂, _matrix_size_functions(heads, tails)...) end function Rsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Rsymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) @@ -202,21 +138,7 @@ function Bsymbol(a::I, b::I, c::I) where {I <: ProductSector} tails = map(_tailsector, (a, b, c)) B₁ = Bsymbol(heads...) B₂ = Bsymbol(tails...) - if B₁ isa Number && B₂ isa Number - B₁ * B₂ - elseif B₁ isa Number - a₁, b₁, c₁ = heads - sz₁ = (Nsymbol(a₁, b₁, c₁), Nsymbol(c₁, dual(b₁), a₁)) # 0 x 0 or 1 x 1 - B₁′ = fill(B₁, sz₁) - return _kron(B₁′, B₂) - elseif B₂ isa Number - a₂, b₂, c₂ = tails - sz₂ = (Nsymbol(a₂, b₂, c₂), Nsymbol(c₂, dual(b₂), a₂)) # 0 x 0 or 1 x 1 - B₂′ = fill(B₂, sz₂) - return _kron(B₁, B₂′) - else - return _kron(B₁, B₂) - end + return _kron_promote(B₁, B₂, _matrix_size_functions(heads, tails)...) end function Bsymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Bsymbol(map(_firstsector, (a, b, c))...) @@ -226,21 +148,7 @@ function Bsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} tails = map(_tailsector, (a, b, c)) B₁ = Bsymbol_from_fusiontensor(heads...) B₂ = Bsymbol_from_fusiontensor(tails...) - if B₁ isa Number && B₂ isa Number - B₁ * B₂ - elseif B₁ isa Number - a₁, b₁, c₁ = heads - sz₁ = (Nsymbol(a₁, b₁, c₁), Nsymbol(c₁, dual(b₁), a₁)) # 0 x 0 or 1 x 1 - B₁′ = fill(B₁, sz₁) - return _kron(B₁′, B₂) - elseif B₂ isa Number - a₂, b₂, c₂ = tails - sz₂ = (Nsymbol(a₂, b₂, c₂), Nsymbol(c₂, dual(b₂), a₂)) # 0 x 0 or 1 x 1 - B₂′ = fill(B₂, sz₂) - return _kron(B₁, B₂′) - else - return _kron(B₁, B₂) - end + return _kron_promote(B₁, B₂, _matrix_size_functions(heads, tails)...) end function Bsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Bsymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) @@ -251,21 +159,7 @@ function Asymbol(a::I, b::I, c::I) where {I <: ProductSector} tails = map(_tailsector, (a, b, c)) A₁ = Asymbol(heads...) A₂ = Asymbol(tails...) - if A₁ isa Number && A₂ isa Number - A₁ * A₂ - elseif A₁ isa Number - a₁, b₁, c₁ = heads - sz₁ = (Nsymbol(a₁, b₁, c₁), Nsymbol(dual(a₁), c₁, b₁)) # 0 x 0 or 1 x 1 - A₁′ = fill(A₁, sz₁) - return _kron(A₁′, A₂) - elseif A₂ isa Number - a₂, b₂, c₂ = tails - sz₂ = (Nsymbol(a₂, b₂, c₂), Nsymbol(dual(a₂), c₂, b₂)) # 0 x 0 or 1 x 1 - A₂′ = fill(A₂, sz₂) - return _kron(A₁, A₂′) - else - return _kron(A₁, A₂) - end + return _kron_promote(A₁, A₂, _matrix_size_functions(heads, tails)...) end function Asymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Asymbol(map(_firstsector, (a, b, c))...) @@ -275,21 +169,7 @@ function Asymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} tails = map(_tailsector, (a, b, c)) A₁ = Asymbol_from_fusiontensor(heads...) A₂ = Asymbol_from_fusiontensor(tails...) - if A₁ isa Number && A₂ isa Number - A₁ * A₂ - elseif A₁ isa Number - a₁, b₁, c₁ = heads - sz₁ = (Nsymbol(a₁, b₁, c₁), Nsymbol(dual(a₁), c₁, b₁)) # 0 x 0 or 1 x 1 - A₁′ = fill(A₁, sz₁) - return _kron(A₁′, A₂) - elseif A₂ isa Number - a₂, b₂, c₂ = tails - sz₂ = (Nsymbol(a₂, b₂, c₂), Nsymbol(dual(a₂), c₂, b₂)) # 0 x 0 or 1 x 1 - A₂′ = fill(A₂, sz₂) - return _kron(A₁, A₂′) - else - return _kron(A₁, A₂) - end + return _kron_promote(A₁, A₂, _matrix_size_functions(heads, tails)...) end function Asymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Asymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) From 6bda8ce4b86269e42668cf0e5357f91badbcae9a Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 27 May 2026 18:10:04 +0200 Subject: [PATCH 3/6] apply suggested change --- src/auxiliary.jl | 35 ++++-------------------- src/product.jl | 71 ++++++++++++++++-------------------------------- 2 files changed, 28 insertions(+), 78 deletions(-) diff --git a/src/auxiliary.jl b/src/auxiliary.jl index adbaa9d6..170253dc 100644 --- a/src/auxiliary.jl +++ b/src/auxiliary.jl @@ -13,41 +13,16 @@ function _kron(A, B) end return C end -function _kron_promote(A₁, B₁, sz₁::Function, sz₂::Function) - if A₁ isa Number && B₁ isa Number - return A₁ * B₁ - end - A₂ = A₁ isa Number ? fill(A₁, sz₁()) : A₁ - B₂ = B₁ isa Number ? fill(B₁, sz₂()) : B₁ - return _kron(A₂, B₂) -end - -function _array_size_functions(t₁::NTuple{6, I₁}, t₂::NTuple{6, I₂}) where {I₁ <: Sector, I₂ <: Sector} # for F-symbols - size₁ = () -> begin - a₁, b₁, c₁, d₁, e₁, f₁ = t₁ - (Nsymbol(a₁, b₁, e₁), Nsymbol(e₁, c₁, d₁), Nsymbol(b₁, c₁, f₁), Nsymbol(a₁, f₁, d₁)) - end - size₂ = () -> begin - a₂, b₂, c₂, d₂, e₂, f₂ = t₂ - (Nsymbol(a₂, b₂, e₂), Nsymbol(e₂, c₂, d₂), Nsymbol(b₂, c₂, f₂), Nsymbol(a₂, f₂, d₂)) - end - return size₁, size₂ +_kron_promote(A::Number, B::Number, _, _) = A * B +function _kron_promote(A₁, B₁, sz₁, sz₂) + return _kron(A₁ isa Number ? fill(A₁, sz₁) : A₁, B₁ isa Number ? fill(B₁, sz₂) : B₁) end # handles R-, A- and B-symbols correctly because of Frobenius reciprocity # i.e. Nsymbol(a, b, c) = Nsymbol(c, dual(b), a) = Nsymbol(dual(a), c, b) # and for braided categories Nsymbol(a, b, c) = Nsymbol(b, a, c) -function _matrix_size_functions(t₁::NTuple{3, I₁}, t₂::NTuple{3, I₂}) where {I₁ <: Sector, I₂ <: Sector} - size₁ = () -> begin - a₁, b₁, c₁ = t₁ - (Nsymbol(a₁, b₁, c₁), Nsymbol(a₁, b₁, c₁)) - end - size₂ = () -> begin - a₂, b₂, c₂ = t₂ - (Nsymbol(a₂, b₂, c₂), Nsymbol(a₂, b₂, c₂)) - end - return size₁, size₂ -end +_symbol_size((a, b, c)::NTuple{3, Sector}) = (n = Nsymbol(a, b, c); (n, n)) +_symbol_size((a, b, c, d, e, f)::NTuple{6, Sector}) = (Nsymbol(a, b, e), Nsymbol(e, c, d), Nsymbol(b, c, f), Nsymbol(a, f, d)) # Manhattan based distance enumeration: I is supposed to be one-based index # TODO: is there any way to make this faster? diff --git a/src/product.jl b/src/product.jl index 9fbcee09..82a2b660 100644 --- a/src/product.jl +++ b/src/product.jl @@ -87,89 +87,64 @@ end _firstsector(x::ProductSector) = x.sectors[1] _tailsector(x::ProductSector) = ProductSector(Base.tail(x.sectors)) +@inline function _product_symbol(symbol_func, sectors) + heads = map(_firstsector, sectors) + V₁ = symbol_func(heads...) + sz₁ = _symbol_size(heads) + + tails = map(_tailsector, sectors) + V₂ = symbol_func(tails...) + sz₂ = _symbol_size(tails) + return _kron_promote(V₁, V₂, sz₁, sz₂) +end + function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector} - heads = map(_firstsector, (a, b, c, d, e, f)) - tails = map(_tailsector, (a, b, c, d, e, f)) - F₁ = Fsymbol(heads...) - F₂ = Fsymbol(tails...) - return _kron_promote(F₁, F₂, _array_size_functions(heads, tails)...) -end -function Fsymbol( - a::I, b::I, c::I, d::I, e::I, f::I - ) where {I <: ProductSector{<:Tuple{Sector}}} + return _product_symbol(Fsymbol, (a, b, c, d, e, f)) +end +function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector{<:Tuple{Sector}}} return Fsymbol(map(_firstsector, (a, b, c, d, e, f))...) end function Fsymbol_from_fusiontensor(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector} - heads = map(_firstsector, (a, b, c, d, e, f)) - tails = map(_tailsector, (a, b, c, d, e, f)) - F₁ = Fsymbol_from_fusiontensor(heads...) - F₂ = Fsymbol_from_fusiontensor(tails...) - return _kron_promote(F₁, F₂, _array_size_functions(heads, tails)...) -end -function Fsymbol_from_fusiontensor( - a::I, b::I, c::I, d::I, e::I, f::I - ) where {I <: ProductSector{<:Tuple{Sector}}} + return _product_symbol(Fsymbol_from_fusiontensor, (a, b, c, d, e, f)) +end +function Fsymbol_from_fusiontensor(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector{<:Tuple{Sector}}} return Fsymbol_from_fusiontensor(map(_firstsector, (a, b, c, d, e, f))...) end function Rsymbol(a::I, b::I, c::I) where {I <: ProductSector} - heads = map(_firstsector, (a, b, c)) - tails = map(_tailsector, (a, b, c)) - R₁ = Rsymbol(heads...) - R₂ = Rsymbol(tails...) - return _kron_promote(R₁, R₂, _matrix_size_functions(heads, tails)...) + return _product_symbol(Rsymbol, (a, b, c)) end function Rsymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Rsymbol(map(_firstsector, (a, b, c))...) end function Rsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} - heads = map(_firstsector, (a, b, c)) - tails = map(_tailsector, (a, b, c)) - R₁ = Rsymbol_from_fusiontensor(heads...) - R₂ = Rsymbol_from_fusiontensor(tails...) - return _kron_promote(R₁, R₂, _matrix_size_functions(heads, tails)...) + return _product_symbol(Rsymbol_from_fusiontensor, (a, b, c)) end function Rsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Rsymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) end function Bsymbol(a::I, b::I, c::I) where {I <: ProductSector} - heads = map(_firstsector, (a, b, c)) - tails = map(_tailsector, (a, b, c)) - B₁ = Bsymbol(heads...) - B₂ = Bsymbol(tails...) - return _kron_promote(B₁, B₂, _matrix_size_functions(heads, tails)...) + return _product_symbol(Bsymbol, (a, b, c)) end function Bsymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Bsymbol(map(_firstsector, (a, b, c))...) end function Bsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} - heads = map(_firstsector, (a, b, c)) - tails = map(_tailsector, (a, b, c)) - B₁ = Bsymbol_from_fusiontensor(heads...) - B₂ = Bsymbol_from_fusiontensor(tails...) - return _kron_promote(B₁, B₂, _matrix_size_functions(heads, tails)...) + return _product_symbol(Bsymbol_from_fusiontensor, (a, b, c)) end function Bsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Bsymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) end function Asymbol(a::I, b::I, c::I) where {I <: ProductSector} - heads = map(_firstsector, (a, b, c)) - tails = map(_tailsector, (a, b, c)) - A₁ = Asymbol(heads...) - A₂ = Asymbol(tails...) - return _kron_promote(A₁, A₂, _matrix_size_functions(heads, tails)...) + return _product_symbol(Asymbol, (a, b, c)) end function Asymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Asymbol(map(_firstsector, (a, b, c))...) end function Asymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} - heads = map(_firstsector, (a, b, c)) - tails = map(_tailsector, (a, b, c)) - A₁ = Asymbol_from_fusiontensor(heads...) - A₂ = Asymbol_from_fusiontensor(tails...) - return _kron_promote(A₁, A₂, _matrix_size_functions(heads, tails)...) + return _product_symbol(Asymbol_from_fusiontensor, (a, b, c)) end function Asymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Asymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) From aba4f3b839c58a52338008bd51aa5b0641ffcadc Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 28 May 2026 10:37:02 +0200 Subject: [PATCH 4/6] attempt to make v1.10 inference happy --- src/product.jl | 51 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/src/product.jl b/src/product.jl index 82a2b660..8b88b44c 100644 --- a/src/product.jl +++ b/src/product.jl @@ -87,64 +87,85 @@ end _firstsector(x::ProductSector) = x.sectors[1] _tailsector(x::ProductSector) = ProductSector(Base.tail(x.sectors)) -@inline function _product_symbol(symbol_func, sectors) +@inline function _kron_promote_inputs(sectors) heads = map(_firstsector, sectors) - V₁ = symbol_func(heads...) - sz₁ = _symbol_size(heads) - tails = map(_tailsector, sectors) - V₂ = symbol_func(tails...) - sz₂ = _symbol_size(tails) - return _kron_promote(V₁, V₂, sz₁, sz₂) + sz₁ = _symbol_size(heads...) + sz₂ = _symbol_size(tails...) + return heads, tails, sz₁, sz₂ end function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector} - return _product_symbol(Fsymbol, (a, b, c, d, e, f)) + heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c, d, e, f)) + V₁ = Fsymbol(heads...) + V₂ = Fsymbol(tails...) + return _kron_promote(V₁, V₂, sz₁, sz₂) end function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector{<:Tuple{Sector}}} return Fsymbol(map(_firstsector, (a, b, c, d, e, f))...) end function Fsymbol_from_fusiontensor(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector} - return _product_symbol(Fsymbol_from_fusiontensor, (a, b, c, d, e, f)) + heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c, d, e, f)) + V₁ = Fsymbol_from_fusiontensor(heads...) + V₂ = Fsymbol_from_fusiontensor(tails...) + return _kron_promote(V₁, V₂, sz₁, sz₂) end function Fsymbol_from_fusiontensor(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: ProductSector{<:Tuple{Sector}}} return Fsymbol_from_fusiontensor(map(_firstsector, (a, b, c, d, e, f))...) end function Rsymbol(a::I, b::I, c::I) where {I <: ProductSector} - return _product_symbol(Rsymbol, (a, b, c)) + heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + V₁ = Rsymbol(heads...) + V₂ = Rsymbol(tails...) + return _kron_promote(V₁, V₂, sz₁, sz₂) end function Rsymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Rsymbol(map(_firstsector, (a, b, c))...) end function Rsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} - return _product_symbol(Rsymbol_from_fusiontensor, (a, b, c)) + heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + V₁ = Rsymbol_from_fusiontensor(heads...) + V₂ = Rsymbol_from_fusiontensor(tails...) + return _kron_promote(V₁, V₂, sz₁, sz₂) end function Rsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Rsymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) end function Bsymbol(a::I, b::I, c::I) where {I <: ProductSector} - return _product_symbol(Bsymbol, (a, b, c)) + heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + V₁ = Bsymbol(heads...) + V₂ = Bsymbol(tails...) + return _kron_promote(V₁, V₂, sz₁, sz₂) end function Bsymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Bsymbol(map(_firstsector, (a, b, c))...) end function Bsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} - return _product_symbol(Bsymbol_from_fusiontensor, (a, b, c)) + heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + V₁ = Bsymbol_from_fusiontensor(heads...) + V₂ = Bsymbol_from_fusiontensor(tails...) + return _kron_promote(V₁, V₂, sz₁, sz₂) end function Bsymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Bsymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) end function Asymbol(a::I, b::I, c::I) where {I <: ProductSector} - return _product_symbol(Asymbol, (a, b, c)) + heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + V₁ = Asymbol(heads...) + V₂ = Asymbol(tails...) + return _kron_promote(V₁, V₂, sz₁, sz₂) end function Asymbol(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Asymbol(map(_firstsector, (a, b, c))...) end function Asymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector} - return _product_symbol(Asymbol_from_fusiontensor, (a, b, c)) + heads, tails, sz₁, sz₂ = _kron_promote_inputs((a, b, c)) + V₁ = Asymbol_from_fusiontensor(heads...) + V₂ = Asymbol_from_fusiontensor(tails...) + return _kron_promote(V₁, V₂, sz₁, sz₂) end function Asymbol_from_fusiontensor(a::I, b::I, c::I) where {I <: ProductSector{<:Tuple{Sector}}} return Asymbol_from_fusiontensor(map(_firstsector, (a, b, c))...) From 37c19f4a7445ac5d7456973bd060a3900c126b28 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 28 May 2026 11:09:22 +0200 Subject: [PATCH 5/6] potato brain moment --- src/product.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/product.jl b/src/product.jl index 8b88b44c..1007860e 100644 --- a/src/product.jl +++ b/src/product.jl @@ -90,8 +90,8 @@ _tailsector(x::ProductSector) = ProductSector(Base.tail(x.sectors)) @inline function _kron_promote_inputs(sectors) heads = map(_firstsector, sectors) tails = map(_tailsector, sectors) - sz₁ = _symbol_size(heads...) - sz₂ = _symbol_size(tails...) + sz₁ = _symbol_size(heads) + sz₂ = _symbol_size(tails) return heads, tails, sz₁, sz₂ end From 58aed2308e4754e88993bd79a8c8a75fc6f3d9c4 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 28 May 2026 16:01:01 +0200 Subject: [PATCH 6/6] move around auxiliary functions --- src/TensorKitSectors.jl | 2 +- src/auxiliary.jl | 6 ------ src/product.jl | 6 ++++++ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/TensorKitSectors.jl b/src/TensorKitSectors.jl index abc22e51..bceb3f88 100644 --- a/src/TensorKitSectors.jl +++ b/src/TensorKitSectors.jl @@ -68,8 +68,8 @@ using WignerSymbols # includes # -------- -include("sectors.jl") include("auxiliary.jl") +include("sectors.jl") include("trivial.jl") include("groups.jl") include("irreps/irreps.jl") # irreps of symmetry groups, with bosonic braiding diff --git a/src/auxiliary.jl b/src/auxiliary.jl index 170253dc..6ed53605 100644 --- a/src/auxiliary.jl +++ b/src/auxiliary.jl @@ -18,12 +18,6 @@ function _kron_promote(A₁, B₁, sz₁, sz₂) return _kron(A₁ isa Number ? fill(A₁, sz₁) : A₁, B₁ isa Number ? fill(B₁, sz₂) : B₁) end -# handles R-, A- and B-symbols correctly because of Frobenius reciprocity -# i.e. Nsymbol(a, b, c) = Nsymbol(c, dual(b), a) = Nsymbol(dual(a), c, b) -# and for braided categories Nsymbol(a, b, c) = Nsymbol(b, a, c) -_symbol_size((a, b, c)::NTuple{3, Sector}) = (n = Nsymbol(a, b, c); (n, n)) -_symbol_size((a, b, c, d, e, f)::NTuple{6, Sector}) = (Nsymbol(a, b, e), Nsymbol(e, c, d), Nsymbol(b, c, f), Nsymbol(a, f, d)) - # Manhattan based distance enumeration: I is supposed to be one-based index # TODO: is there any way to make this faster? diff --git a/src/product.jl b/src/product.jl index 1007860e..b0ed5554 100644 --- a/src/product.jl +++ b/src/product.jl @@ -87,6 +87,12 @@ end _firstsector(x::ProductSector) = x.sectors[1] _tailsector(x::ProductSector) = ProductSector(Base.tail(x.sectors)) +# handles R-, A- and B-symbols correctly because of Frobenius reciprocity +# i.e. Nsymbol(a, b, c) = Nsymbol(c, dual(b), a) = Nsymbol(dual(a), c, b) +# and for braided categories Nsymbol(a, b, c) = Nsymbol(b, a, c) +_symbol_size((a, b, c)::NTuple{3, Sector}) = (n = Nsymbol(a, b, c); (n, n)) +_symbol_size((a, b, c, d, e, f)::NTuple{6, Sector}) = (Nsymbol(a, b, e), Nsymbol(e, c, d), Nsymbol(b, c, f), Nsymbol(a, f, d)) + @inline function _kron_promote_inputs(sectors) heads = map(_firstsector, sectors) tails = map(_tailsector, sectors)