From f8800195b9ce33f541dd07618087343105d37080 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 10 Sep 2025 16:31:14 +0100 Subject: [PATCH 01/49] `MultiFusionStyle` and its properties with itself and `FusionStyle` --- src/sectors.jl | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/sectors.jl b/src/sectors.jl index c78c340..99b2d45 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -220,6 +220,54 @@ Base.:&(::SimpleFusion, ::UniqueFusion) = SimpleFusion() Base.:&(::GenericFusion, ::UniqueFusion) = GenericFusion() Base.:&(::GenericFusion, ::SimpleFusion) = GenericFusion() +# similar, but for multifusion categories +""" + MultiFusionStyle(::Sector) + MultiFusionStyle(I::Type{<:Sector}) + +Trait to describe the fusion behavior of multifusion sectors of type `I`, +which is based on the most general fusion behavior of the subcategories in +the multifusion category. For all allowed fusions, the following types are possible: +* `UniqueMultiFusion()`: single fusion output; +* `SimpleMultiFusion()`: multiple outputs, but every output occurs at most once; +* `GenericMultiFusion()`: multiple outputs that can occur more than once. + +There is a type alias `MultiplicityFreeMultiFusion` +for those fusion types which do not require muliplicity labels, i.e. +`MultiplicityFreeMultiFusion = Union{UniqueMultiFusion,SimpleMultiFusion}`. +""" +abstract type MultiFusionStyle end +MultiFusionStyle(a::Sector) = MultiFusionStyle(typeof(a)) + +struct UniqueMultiFusion <: MultiFusionStyle end +struct SimpleMultiFusion <: MultiFusionStyle end +struct GenericMultiFusion <: MultiFusionStyle end +const MultiplicityFreeMultiFusion = Union{UniqueMultiFusion, SimpleMultiFusion} + +# combine fusion properties of tensor products of multifusion sectors +Base.:&(f::F, ::F) where {F <: MultiFusionStyle} = f +Base.:&(f₁::MultiFusionStyle, f₂::MultiFusionStyle) = f₂ & f₁ + +Base.:&(::SimpleMultiFusion, ::UniqueMultiFusion) = SimpleMultiFusion() +Base.:&(::GenericMultiFusion, ::UniqueMultiFusion) = GenericMultiFusion() +Base.:&(::GenericMultiFusion, ::SimpleMultiFusion) = GenericMultiFusion() + +# combine fusion properties of tensor products between fusion and multifusion sectors +# lift FusionStyle to MultiFusionStyle +Base.:&(f::F, ::G) where {F <: MultiFusionStyle, G <: FusionStyle} = f + +function Base.:&(f::MultiFusionStyle, g::FusionStyle) + if f isa GenericMultiFusion || g isa GenericFusion + return GenericMultiFusion() + elseif f isa SimpleMultiFusion # g isa MultiplicityFreeFusion + return SimpleMultiFusion() + elseif g isa SimpleFusion # f isa UniqueMultiFusion + return SimpleMultiFusion() + else + return UniqueMultiFusion() + end +end + """ Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I<:Sector} From 51740bc990b81da1915bef42ff00b8640e2110b9 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 10 Sep 2025 16:33:11 +0100 Subject: [PATCH 02/49] `allones` for `Type{Sector}` --- src/sectors.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sectors.jl b/src/sectors.jl index 99b2d45..c283895 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -109,6 +109,14 @@ See also [`leftone`](@ref) and [`Base.one`](@ref). """ rightone(a::Sector) = one(a) +""" + allones(I::Type{<:Sector}) -> Tuple{I} + +Return a tuple with all unit elements of the sector type `I`. +For fusion categories, this will contain only one element. +""" +allones(I::Type{<:Sector}) = (one(I),) + """ dual(a::Sector) -> Sector From 6b13d0ca80d2dd14484979b7ecaf7e0a4cf87948 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 10 Sep 2025 16:33:48 +0100 Subject: [PATCH 03/49] changes to `IsingBimodule` --- src/multifusion.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/multifusion.jl b/src/multifusion.jl index 43b245d..4de9ae1 100644 --- a/src/multifusion.jl +++ b/src/multifusion.jl @@ -54,7 +54,7 @@ function Base.convert(::Type{IsingAnyon}, a::IsingBimodule) # identify RepZ2 ⊕ return IsingAnyon(a.label == 0 ? :I : :ψ) end -FusionStyle(::Type{IsingBimodule}) = SimpleFusion() # no multiplicities +MultiFusionStyle(::Type{IsingBimodule}) = SimpleMultiFusion() # no multiplicities BraidingStyle(::Type{IsingBimodule}) = NoBraiding() # because of module categories function Nsymbol(a::IsingBimodule, b::IsingBimodule, c::IsingBimodule) @@ -91,6 +91,8 @@ function Base.one(::Type{IsingBimodule}) throw(ArgumentError("one of Type IsingBimodule doesn't exist")) end +allones(::Type{IsingBimodule}) = (IsingBimodule(1, 1, 0), IsingBimodule(2, 2, 0)) + function Base.isless(a::IsingBimodule, b::IsingBimodule) return isless((a.col, a.row, a.label), (b.col, b.row, b.label)) end From 9d2821f50f61d333e5bb692d2183d4573b3118a2 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 10 Sep 2025 16:34:06 +0100 Subject: [PATCH 04/49] export them all --- src/TensorKitSectors.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/TensorKitSectors.jl b/src/TensorKitSectors.jl index 40b8bbc..349ebcd 100644 --- a/src/TensorKitSectors.jl +++ b/src/TensorKitSectors.jl @@ -11,9 +11,11 @@ export dim, sqrtdim, invsqrtdim, frobeniusschur, twist, fusiontensor, dual export otimes, deligneproduct, times export FusionStyle, UniqueFusion, MultipleFusion, SimpleFusion, GenericFusion, MultiplicityFreeFusion +export MultiFusionStyle, UniqueMultiFusion, SimpleMultiFusion, GenericMultiFusion, + MultiplicityFreeMultiFusion export BraidingStyle, NoBraiding, HasBraiding, SymmetricBraiding, Bosonic, Fermionic, Anyonic export SectorSet, SectorValues, findindex -export rightone, leftone +export rightone, leftone, allones export triangle_equation, pentagon_equation, hexagon_equation From 2f7e183110220dda63993e630f0d9ca418fcf769 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 10 Sep 2025 16:39:47 +0100 Subject: [PATCH 05/49] `allones` tests --- test/multifusion.jl | 3 +++ test/sectors.jl | 1 + 2 files changed, 4 insertions(+) diff --git a/test/multifusion.jl b/test/multifusion.jl index 08bbd64..0a30262 100644 --- a/test/multifusion.jl +++ b/test/multifusion.jl @@ -27,6 +27,9 @@ Istr = TensorKitSectors.type_repr(I) @test isone(D0) @test !isone(C1) && !isone(D1) && !isone(M) && !isone(Mop) + @test length(allones(I)) == 2 + @test allones(I) == (C0, D0) + @test eval(Meta.parse(sprint(show, s))) == s @test @constinferred(hash(s)) == hash(deepcopy(s)) @constinferred dual(s) diff --git a/test/sectors.jl b/test/sectors.jl index ccfc7a0..88092c3 100644 --- a/test/sectors.jl +++ b/test/sectors.jl @@ -40,6 +40,7 @@ end i >= 10 && break end @test one(I) == first(values(I)) + @test length(allones(I)) == 1 @test (@constinferred findindex(values(I), one(I))) == 1 for s in smallset(I) @test (@constinferred values(I)[findindex(values(I), s)]) == s From ef985d7b9a78f5c8c27ff2e31f7a0f03b83dd5f5 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 10 Sep 2025 17:04:33 +0100 Subject: [PATCH 06/49] fix `&` and make commutative for mixed case --- src/sectors.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sectors.jl b/src/sectors.jl index c283895..94b9344 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -262,9 +262,10 @@ Base.:&(::GenericMultiFusion, ::SimpleMultiFusion) = GenericMultiFusion() # combine fusion properties of tensor products between fusion and multifusion sectors # lift FusionStyle to MultiFusionStyle -Base.:&(f::F, ::G) where {F <: MultiFusionStyle, G <: FusionStyle} = f -function Base.:&(f::MultiFusionStyle, g::FusionStyle) +Base.:&(g::G, f::F) where {F <: MultiFusionStyle, G <: FusionStyle} = f & g + +function Base.:&(f::F, g::G) where {F <: MultiFusionStyle, G <: FusionStyle} if f isa GenericMultiFusion || g isa GenericFusion return GenericMultiFusion() elseif f isa SimpleMultiFusion # g isa MultiplicityFreeFusion From 20f98b6d4e9a2b86edf0b9bd9300e3faf8dcb17e Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 10 Sep 2025 17:13:19 +0100 Subject: [PATCH 07/49] `MultiFusionStyle` tests --- test/multifusion.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/multifusion.jl b/test/multifusion.jl index 0a30262..df70c92 100644 --- a/test/multifusion.jl +++ b/test/multifusion.jl @@ -4,6 +4,10 @@ Istr = TensorKitSectors.type_repr(I) @testset "Basic type properties" begin @test eval(Meta.parse(sprint(show, I))) == I @test eval(Meta.parse(TensorKitSectors.type_repr(I))) == I + + @test MultiFusionStyle(I) isa MultiplicityFreeMultiFusion + @test MultiFusionStyle(I) & GenericFusion() isa GenericMultiFusion + @test MultiFusionStyle(I) & SimpleFusion() == SimpleFusion() & MultiFusionStyle(I) end M = IsingBimodule(1, 2, 0) From 7a3fb13fc825bb7838d6caec2ddd1fc55f65824f Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Wed, 10 Sep 2025 17:15:52 +0100 Subject: [PATCH 08/49] format --- src/sectors.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sectors.jl b/src/sectors.jl index 94b9344..4ba569a 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -272,7 +272,7 @@ function Base.:&(f::F, g::G) where {F <: MultiFusionStyle, G <: FusionStyle} return SimpleMultiFusion() elseif g isa SimpleFusion # f isa UniqueMultiFusion return SimpleMultiFusion() - else + else return UniqueMultiFusion() end end From 7eca2d2e8d955a37da55930e9cb3932750710f79 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 11 Sep 2025 16:32:53 +0100 Subject: [PATCH 09/49] update `MultiFusionStyle` to only reflect the semisimplicity of the unit --- src/sectors.jl | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/sectors.jl b/src/sectors.jl index 4ba569a..7977a7a 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -247,34 +247,22 @@ for those fusion types which do not require muliplicity labels, i.e. abstract type MultiFusionStyle end MultiFusionStyle(a::Sector) = MultiFusionStyle(typeof(a)) -struct UniqueMultiFusion <: MultiFusionStyle end struct SimpleMultiFusion <: MultiFusionStyle end struct GenericMultiFusion <: MultiFusionStyle end -const MultiplicityFreeMultiFusion = Union{UniqueMultiFusion, SimpleMultiFusion} + +MultiFusionStyle(::Type{<:Sector}) = SimpleMultiFusion() # default is simple unit # combine fusion properties of tensor products of multifusion sectors Base.:&(f::F, ::F) where {F <: MultiFusionStyle} = f Base.:&(f₁::MultiFusionStyle, f₂::MultiFusionStyle) = f₂ & f₁ -Base.:&(::SimpleMultiFusion, ::UniqueMultiFusion) = SimpleMultiFusion() -Base.:&(::GenericMultiFusion, ::UniqueMultiFusion) = GenericMultiFusion() Base.:&(::GenericMultiFusion, ::SimpleMultiFusion) = GenericMultiFusion() # combine fusion properties of tensor products between fusion and multifusion sectors -# lift FusionStyle to MultiFusionStyle - Base.:&(g::G, f::F) where {F <: MultiFusionStyle, G <: FusionStyle} = f & g -function Base.:&(f::F, g::G) where {F <: MultiFusionStyle, G <: FusionStyle} - if f isa GenericMultiFusion || g isa GenericFusion - return GenericMultiFusion() - elseif f isa SimpleMultiFusion # g isa MultiplicityFreeFusion - return SimpleMultiFusion() - elseif g isa SimpleFusion # f isa UniqueMultiFusion - return SimpleMultiFusion() - else - return UniqueMultiFusion() - end +function Base.:&(::F, ::G) where {F <: MultiFusionStyle, G <: FusionStyle} + return F == GenericMultiFusion ? GenericMultiFusion() : SimpleMultiFusion() end """ From ce0d87bf65e2fbfa7a598174e1696531a5da61a3 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 11 Sep 2025 16:33:05 +0100 Subject: [PATCH 10/49] update for `IsingBimodule` --- src/multifusion.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/multifusion.jl b/src/multifusion.jl index 4de9ae1..00cfe29 100644 --- a/src/multifusion.jl +++ b/src/multifusion.jl @@ -54,7 +54,8 @@ function Base.convert(::Type{IsingAnyon}, a::IsingBimodule) # identify RepZ2 ⊕ return IsingAnyon(a.label == 0 ? :I : :ψ) end -MultiFusionStyle(::Type{IsingBimodule}) = SimpleMultiFusion() # no multiplicities +FusionStyle(::Type{IsingBimodule}) = SimpleFusion() # no multiplicities +MultiFusionStyle(::Type{IsingBimodule}) = GenericMultiFusion() # multiple units BraidingStyle(::Type{IsingBimodule}) = NoBraiding() # because of module categories function Nsymbol(a::IsingBimodule, b::IsingBimodule, c::IsingBimodule) From 1b0aa9a0d8b0710da5809a64f2136467a1a1b57d Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 11 Sep 2025 16:33:11 +0100 Subject: [PATCH 11/49] fix exports --- src/TensorKitSectors.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/TensorKitSectors.jl b/src/TensorKitSectors.jl index 349ebcd..7b2179b 100644 --- a/src/TensorKitSectors.jl +++ b/src/TensorKitSectors.jl @@ -11,8 +11,7 @@ export dim, sqrtdim, invsqrtdim, frobeniusschur, twist, fusiontensor, dual export otimes, deligneproduct, times export FusionStyle, UniqueFusion, MultipleFusion, SimpleFusion, GenericFusion, MultiplicityFreeFusion -export MultiFusionStyle, UniqueMultiFusion, SimpleMultiFusion, GenericMultiFusion, - MultiplicityFreeMultiFusion +export MultiFusionStyle, SimpleMultiFusion, GenericMultiFusion export BraidingStyle, NoBraiding, HasBraiding, SymmetricBraiding, Bosonic, Fermionic, Anyonic export SectorSet, SectorValues, findindex export rightone, leftone, allones From 46a6ce54ada1ba2172a541af6406ba390a9d1f4f Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 11 Sep 2025 16:35:12 +0100 Subject: [PATCH 12/49] fix tests --- test/multifusion.jl | 5 ++--- test/sectors.jl | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/multifusion.jl b/test/multifusion.jl index df70c92..bf2719e 100644 --- a/test/multifusion.jl +++ b/test/multifusion.jl @@ -5,9 +5,8 @@ Istr = TensorKitSectors.type_repr(I) @test eval(Meta.parse(sprint(show, I))) == I @test eval(Meta.parse(TensorKitSectors.type_repr(I))) == I - @test MultiFusionStyle(I) isa MultiplicityFreeMultiFusion - @test MultiFusionStyle(I) & GenericFusion() isa GenericMultiFusion - @test MultiFusionStyle(I) & SimpleFusion() == SimpleFusion() & MultiFusionStyle(I) + @test MultiFusionStyle(I) & UniqueFusion() isa GenericMultiFusion + @test MultiFusionStyle(I) & FusionStyle(I) == FusionStyle(I) & MultiFusionStyle(I) end M = IsingBimodule(1, 2, 0) diff --git a/test/sectors.jl b/test/sectors.jl index 88092c3..a4d6dca 100644 --- a/test/sectors.jl +++ b/test/sectors.jl @@ -12,6 +12,7 @@ Istr = TKS.type_repr(I) @constinferred Nsymbol(s...) B = @constinferred Bsymbol(s...) F = @constinferred Fsymbol(s..., s...) + @test MultiFusionStyle(I) & FusionStyle(I) isa SimpleMultiFusion if BraidingStyle(I) isa HasBraiding R = @constinferred Rsymbol(s...) if FusionStyle(I) === SimpleFusion() From 1cd98d7d12e7fb3f78e82af7d05a22c582bbc94c Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Thu, 11 Sep 2025 17:42:04 +0100 Subject: [PATCH 13/49] fix docstrings --- src/sectors.jl | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/sectors.jl b/src/sectors.jl index 7977a7a..4768b76 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -112,7 +112,7 @@ rightone(a::Sector) = one(a) """ allones(I::Type{<:Sector}) -> Tuple{I} -Return a tuple with all unit elements of the sector type `I`. +Return a tuple with all units of the sector type `I`. For fusion categories, this will contain only one element. """ allones(I::Type{<:Sector}) = (one(I),) @@ -233,16 +233,10 @@ Base.:&(::GenericFusion, ::SimpleFusion) = GenericFusion() MultiFusionStyle(::Sector) MultiFusionStyle(I::Type{<:Sector}) -Trait to describe the fusion behavior of multifusion sectors of type `I`, -which is based on the most general fusion behavior of the subcategories in -the multifusion category. For all allowed fusions, the following types are possible: -* `UniqueMultiFusion()`: single fusion output; -* `SimpleMultiFusion()`: multiple outputs, but every output occurs at most once; -* `GenericMultiFusion()`: multiple outputs that can occur more than once. - -There is a type alias `MultiplicityFreeMultiFusion` -for those fusion types which do not require muliplicity labels, i.e. -`MultiplicityFreeMultiFusion = Union{UniqueMultiFusion,SimpleMultiFusion}`. +Trait to describe the semisimplicity of the unit sector of type `I`. +This can be either +* `SimpleMultiFusion()`: the unit is simple (e.g. fusion categories); +* `GenericMultiFusion()`: the unit is semisimple. """ abstract type MultiFusionStyle end MultiFusionStyle(a::Sector) = MultiFusionStyle(typeof(a)) From 97fb36bcb943e80afeec74465b8356ad59f12964 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 11:29:05 +0200 Subject: [PATCH 14/49] add `MultiFusionStyle` for product sectors + test --- src/product.jl | 3 +++ test/multifusion.jl | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/product.jl b/src/product.jl index 5088a3a..8a72b68 100644 --- a/src/product.jl +++ b/src/product.jl @@ -203,6 +203,9 @@ end function FusionStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} return Base.:&(map(FusionStyle, _sectors(T))...) end +function MultiFusionStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} + return Base.:&(map(MultiFusionStyle, _sectors(T))...) +end function BraidingStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} return Base.:&(map(BraidingStyle, _sectors(T))...) end diff --git a/test/multifusion.jl b/test/multifusion.jl index bf2719e..c2f99b6 100644 --- a/test/multifusion.jl +++ b/test/multifusion.jl @@ -7,6 +7,10 @@ Istr = TensorKitSectors.type_repr(I) @test MultiFusionStyle(I) & UniqueFusion() isa GenericMultiFusion @test MultiFusionStyle(I) & FusionStyle(I) == FusionStyle(I) & MultiFusionStyle(I) + + prodsec = I ⊠ Z2Irrep + @test MultiFusionStyle(prodsec) isa GenericMultiFusion + @test FusionStyle(prodsec) isa SimpleFusion end M = IsingBimodule(1, 2, 0) From d03cc5dffbaa150e8e09c9925ef2d24ca75b34a8 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 11:33:43 +0200 Subject: [PATCH 15/49] remove interplay `MultiFusionStyle`-`FusionStyle` + related tests --- src/sectors.jl | 7 ------- test/multifusion.jl | 3 --- test/sectors.jl | 1 - 3 files changed, 11 deletions(-) diff --git a/src/sectors.jl b/src/sectors.jl index 4768b76..32d59d5 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -252,13 +252,6 @@ Base.:&(f₁::MultiFusionStyle, f₂::MultiFusionStyle) = f₂ & f₁ Base.:&(::GenericMultiFusion, ::SimpleMultiFusion) = GenericMultiFusion() -# combine fusion properties of tensor products between fusion and multifusion sectors -Base.:&(g::G, f::F) where {F <: MultiFusionStyle, G <: FusionStyle} = f & g - -function Base.:&(::F, ::G) where {F <: MultiFusionStyle, G <: FusionStyle} - return F == GenericMultiFusion ? GenericMultiFusion() : SimpleMultiFusion() -end - """ Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I<:Sector} diff --git a/test/multifusion.jl b/test/multifusion.jl index c2f99b6..265f93e 100644 --- a/test/multifusion.jl +++ b/test/multifusion.jl @@ -5,9 +5,6 @@ Istr = TensorKitSectors.type_repr(I) @test eval(Meta.parse(sprint(show, I))) == I @test eval(Meta.parse(TensorKitSectors.type_repr(I))) == I - @test MultiFusionStyle(I) & UniqueFusion() isa GenericMultiFusion - @test MultiFusionStyle(I) & FusionStyle(I) == FusionStyle(I) & MultiFusionStyle(I) - prodsec = I ⊠ Z2Irrep @test MultiFusionStyle(prodsec) isa GenericMultiFusion @test FusionStyle(prodsec) isa SimpleFusion diff --git a/test/sectors.jl b/test/sectors.jl index a4d6dca..88092c3 100644 --- a/test/sectors.jl +++ b/test/sectors.jl @@ -12,7 +12,6 @@ Istr = TKS.type_repr(I) @constinferred Nsymbol(s...) B = @constinferred Bsymbol(s...) F = @constinferred Fsymbol(s..., s...) - @test MultiFusionStyle(I) & FusionStyle(I) isa SimpleMultiFusion if BraidingStyle(I) isa HasBraiding R = @constinferred Rsymbol(s...) if FusionStyle(I) === SimpleFusion() From ed31fd2a62cf057d13c2bfe4f56599fb8ce6ee60 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 12:07:41 +0200 Subject: [PATCH 16/49] fix domain error of one of IsingBimodule --- src/multifusion.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multifusion.jl b/src/multifusion.jl index 00cfe29..4ad3d88 100644 --- a/src/multifusion.jl +++ b/src/multifusion.jl @@ -82,7 +82,7 @@ leftone(a::IsingBimodule) = IsingBimodule(a.row, a.row, 0) function Base.one(a::IsingBimodule) a.row == a.col || - throw(DomainError("unit of module category ($(a.row), $(a.col)) doesn't exist")) + throw(DomainError(a, "unit of module category ($(a.row), $(a.col)) doesn't exist")) return IsingBimodule(a.row, a.col, 0) end From 0a215fd6cc5fbe4fe98092207a11175d28a17c1f Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 12:11:05 +0200 Subject: [PATCH 17/49] introduce `allones` for all sectors --- src/anyons.jl | 3 +++ src/fermions.jl | 1 + src/groupelements.jl | 2 ++ src/irreps/cu1irrep.jl | 1 + src/irreps/dnirrep.jl | 1 + src/irreps/su2irrep.jl | 1 + src/irreps/u1irrep.jl | 1 + src/irreps/znirrep.jl | 1 + src/sectors.jl | 4 ++-- 9 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/anyons.jl b/src/anyons.jl index 30d9642..3a8d472 100644 --- a/src/anyons.jl +++ b/src/anyons.jl @@ -22,6 +22,7 @@ findindex(::SectorValues{PlanarTrivial}, c::PlanarTrivial) = 1 Base.isless(::PlanarTrivial, ::PlanarTrivial) = false Base.one(::Type{PlanarTrivial}) = PlanarTrivial() +allones(::Type{PlanarTrivial}) = (PlanarTrivial(),) Base.conj(::PlanarTrivial) = PlanarTrivial() FusionStyle(::Type{PlanarTrivial}) = UniqueFusion() @@ -72,6 +73,7 @@ findindex(::SectorValues{FibonacciAnyon}, s::FibonacciAnyon) = 2 - s.isone Base.convert(::Type{FibonacciAnyon}, s::Symbol) = FibonacciAnyon(s) Base.one(::Type{FibonacciAnyon}) = FibonacciAnyon(:I) +allones(::Type{FibonacciAnyon}) = (FibonacciAnyon(:I),) Base.conj(s::FibonacciAnyon) = s const _goldenratio = Float64(MathConstants.golden) @@ -192,6 +194,7 @@ end Base.convert(::Type{IsingAnyon}, s::Symbol) = IsingAnyon(s) Base.one(::Type{IsingAnyon}) = IsingAnyon(:I) +allones(::Type{IsingAnyon}) = (IsingAnyon(:I),) Base.conj(s::IsingAnyon) = s dim(a::IsingAnyon) = a.s == :σ ? sqrt(2) : 1.0 diff --git a/src/fermions.jl b/src/fermions.jl index 5e3718b..4619eea 100644 --- a/src/fermions.jl +++ b/src/fermions.jl @@ -29,6 +29,7 @@ end findindex(::SectorValues{FermionParity}, f::FermionParity) = f.isodd ? 2 : 1 Base.one(::Type{FermionParity}) = FermionParity(false) +allones(::Type{FermionParity}) = (FermionParity(false),) Base.conj(f::FermionParity) = f dim(f::FermionParity) = 1 diff --git a/src/groupelements.jl b/src/groupelements.jl index 0a13351..b482fc1 100644 --- a/src/groupelements.jl +++ b/src/groupelements.jl @@ -35,6 +35,7 @@ BraidingStyle(::Type{<:AbstractGroupElement}) = NoBraiding() cocycle(a::I, b::I, c::I) where {I <: AbstractGroupElement} = 1 ⊗(a::I, b::I) where {I <: AbstractGroupElement} = (a * b,) Base.one(a::AbstractGroupElement) = one(typeof(a)) +allones(a::Type{<:AbstractGroupElement}) = (one(a),) Base.conj(a::AbstractGroupElement) = inv(a) Nsymbol(a::I, b::I, c::I) where {I <: AbstractGroupElement} = c == a * b function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: AbstractGroupElement} @@ -125,6 +126,7 @@ const Z3Element{p} = ZNElement{3, p} const Z4Element{p} = ZNElement{4, p} Base.one(::Type{Z}) where {Z <: ZNElement} = Z(0) +allones(::Type{Z}) where {Z <: ZNElement} = (Z(0),) Base.inv(c::ZNElement) = typeof(c)(-c.n) Base.:*(c1::ZNElement{N, p}, c2::ZNElement{N, p}) where {N, p} = ZNElement{N, p}(mod(c1.n + c2.n, N)) diff --git a/src/irreps/cu1irrep.jl b/src/irreps/cu1irrep.jl index d98278f..a17eb17 100644 --- a/src/irreps/cu1irrep.jl +++ b/src/irreps/cu1irrep.jl @@ -67,6 +67,7 @@ Base.convert(::Type{CU1Irrep}, j::Real) = CU1Irrep(j) Base.convert(::Type{CU1Irrep}, js::Tuple{Real, Int}) = CU1Irrep(js...) Base.one(::Type{CU1Irrep}) = CU1Irrep(zero(HalfInt), 0) +allones(::Type{CU1Irrep}) = (CU1Irrep(zero(HalfInt), 0),) Base.conj(c::CU1Irrep) = c struct CU1ProdIterator diff --git a/src/irreps/dnirrep.jl b/src/irreps/dnirrep.jl index 6c669a7..749473b 100644 --- a/src/irreps/dnirrep.jl +++ b/src/irreps/dnirrep.jl @@ -48,6 +48,7 @@ sectorscalartype(::Type{DNIrrep{N}}) where {N} = Float64 Base.isreal(::Type{DNIrrep{N}}) where {N} = true Base.one(::Type{DNIrrep{N}}) where {N} = DNIrrep{N}(0, false) +allones(::Type{DNIrrep{N}}) where {N} = (DNIrrep{N}(0, false),) Base.conj(a::DNIrrep) = a Base.hash(a::DNIrrep, h::UInt) = hash(a.data, h) diff --git a/src/irreps/su2irrep.jl b/src/irreps/su2irrep.jl index 5666805..5f5c129 100644 --- a/src/irreps/su2irrep.jl +++ b/src/irreps/su2irrep.jl @@ -31,6 +31,7 @@ Base.convert(::Type{SU2Irrep}, j::Real) = SU2Irrep(j) const _su2one = SU2Irrep(zero(HalfInt)) Base.one(::Type{SU2Irrep}) = _su2one +allones(::Type{SU2Irrep}) = (_su2one,) Base.conj(s::SU2Irrep) = s ⊗(s1::SU2Irrep, s2::SU2Irrep) = SectorSet{SU2Irrep}(abs(s1.j - s2.j):(s1.j + s2.j)) diff --git a/src/irreps/u1irrep.jl b/src/irreps/u1irrep.jl index 5c9cf06..259f5a6 100644 --- a/src/irreps/u1irrep.jl +++ b/src/irreps/u1irrep.jl @@ -20,6 +20,7 @@ Base.getindex(::IrrepTable, ::Type{U₁}) = U1Irrep Base.convert(::Type{U1Irrep}, c::Real) = U1Irrep(c) Base.one(::Type{U1Irrep}) = U1Irrep(0) +allones(::Type{U1Irrep}) = (U1Irrep(0),) Base.conj(c::U1Irrep) = U1Irrep(-c.charge) ⊗(c1::U1Irrep, c2::U1Irrep) = (U1Irrep(c1.charge + c2.charge),) diff --git a/src/irreps/znirrep.jl b/src/irreps/znirrep.jl index c176a63..f60bd65 100644 --- a/src/irreps/znirrep.jl +++ b/src/irreps/znirrep.jl @@ -26,6 +26,7 @@ const Z3Irrep = ZNIrrep{3} const Z4Irrep = ZNIrrep{4} Base.one(::Type{ZNIrrep{N}}) where {N} = ZNIrrep{N}(0) +allones(::Type{ZNIrrep{N}}) where {N} = (ZNIrrep{N}(0),) Base.conj(c::ZNIrrep{N}) where {N} = ZNIrrep{N}(-c.n) ⊗(c1::ZNIrrep{N}, c2::ZNIrrep{N}) where {N} = (ZNIrrep{N}(c1.n + c2.n),) diff --git a/src/sectors.jl b/src/sectors.jl index 32d59d5..1756ff6 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -91,7 +91,7 @@ end Return the unit element within this type of sector. """ -Base.one(a::Sector) = one(typeof(a)) +Base.one(a::Sector) = only(allones(typeof(a))) #TODO: add for type """ leftone(a::Sector) -> Sector @@ -115,7 +115,7 @@ rightone(a::Sector) = one(a) Return a tuple with all units of the sector type `I`. For fusion categories, this will contain only one element. """ -allones(I::Type{<:Sector}) = (one(I),) +allones(I::Type{<:Sector}) = (one(I),) # do we need/want this fallback? or change it to evaluate a sector? """ dual(a::Sector) -> Sector From 08648f037dc18d768fdae40b1364d9773951db92 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 12:17:51 +0200 Subject: [PATCH 18/49] introduce generic `one` for type sector + remove for specific sectors --- src/anyons.jl | 1 - src/fermions.jl | 1 - src/groupelements.jl | 2 -- src/irreps/cu1irrep.jl | 1 - src/irreps/dnirrep.jl | 1 - src/irreps/su2irrep.jl | 1 - src/irreps/u1irrep.jl | 1 - src/irreps/znirrep.jl | 1 - src/sectors.jl | 3 ++- 9 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/anyons.jl b/src/anyons.jl index 3a8d472..41cf486 100644 --- a/src/anyons.jl +++ b/src/anyons.jl @@ -193,7 +193,6 @@ function findindex(::SectorValues{IsingAnyon}, a::IsingAnyon) end Base.convert(::Type{IsingAnyon}, s::Symbol) = IsingAnyon(s) -Base.one(::Type{IsingAnyon}) = IsingAnyon(:I) allones(::Type{IsingAnyon}) = (IsingAnyon(:I),) Base.conj(s::IsingAnyon) = s diff --git a/src/fermions.jl b/src/fermions.jl index 4619eea..071151b 100644 --- a/src/fermions.jl +++ b/src/fermions.jl @@ -28,7 +28,6 @@ function Base.getindex(::SectorValues{FermionParity}, i::Int) end findindex(::SectorValues{FermionParity}, f::FermionParity) = f.isodd ? 2 : 1 -Base.one(::Type{FermionParity}) = FermionParity(false) allones(::Type{FermionParity}) = (FermionParity(false),) Base.conj(f::FermionParity) = f dim(f::FermionParity) = 1 diff --git a/src/groupelements.jl b/src/groupelements.jl index b482fc1..4a3be1f 100644 --- a/src/groupelements.jl +++ b/src/groupelements.jl @@ -34,7 +34,6 @@ BraidingStyle(::Type{<:AbstractGroupElement}) = NoBraiding() cocycle(a::I, b::I, c::I) where {I <: AbstractGroupElement} = 1 ⊗(a::I, b::I) where {I <: AbstractGroupElement} = (a * b,) -Base.one(a::AbstractGroupElement) = one(typeof(a)) allones(a::Type{<:AbstractGroupElement}) = (one(a),) Base.conj(a::AbstractGroupElement) = inv(a) Nsymbol(a::I, b::I, c::I) where {I <: AbstractGroupElement} = c == a * b @@ -125,7 +124,6 @@ const Z2Element{p} = ZNElement{2, p} const Z3Element{p} = ZNElement{3, p} const Z4Element{p} = ZNElement{4, p} -Base.one(::Type{Z}) where {Z <: ZNElement} = Z(0) allones(::Type{Z}) where {Z <: ZNElement} = (Z(0),) Base.inv(c::ZNElement) = typeof(c)(-c.n) Base.:*(c1::ZNElement{N, p}, c2::ZNElement{N, p}) where {N, p} = diff --git a/src/irreps/cu1irrep.jl b/src/irreps/cu1irrep.jl index a17eb17..1a0aa5b 100644 --- a/src/irreps/cu1irrep.jl +++ b/src/irreps/cu1irrep.jl @@ -66,7 +66,6 @@ end Base.convert(::Type{CU1Irrep}, j::Real) = CU1Irrep(j) Base.convert(::Type{CU1Irrep}, js::Tuple{Real, Int}) = CU1Irrep(js...) -Base.one(::Type{CU1Irrep}) = CU1Irrep(zero(HalfInt), 0) allones(::Type{CU1Irrep}) = (CU1Irrep(zero(HalfInt), 0),) Base.conj(c::CU1Irrep) = c diff --git a/src/irreps/dnirrep.jl b/src/irreps/dnirrep.jl index 749473b..6116ce9 100644 --- a/src/irreps/dnirrep.jl +++ b/src/irreps/dnirrep.jl @@ -47,7 +47,6 @@ FusionStyle(::Type{DNIrrep{N}}) where {N} = N < 3 ? UniqueFusion() : SimpleFusio sectorscalartype(::Type{DNIrrep{N}}) where {N} = Float64 Base.isreal(::Type{DNIrrep{N}}) where {N} = true -Base.one(::Type{DNIrrep{N}}) where {N} = DNIrrep{N}(0, false) allones(::Type{DNIrrep{N}}) where {N} = (DNIrrep{N}(0, false),) Base.conj(a::DNIrrep) = a diff --git a/src/irreps/su2irrep.jl b/src/irreps/su2irrep.jl index 5f5c129..5a332c3 100644 --- a/src/irreps/su2irrep.jl +++ b/src/irreps/su2irrep.jl @@ -30,7 +30,6 @@ Base.getindex(::IrrepTable, ::Type{SU₂}) = SU2Irrep Base.convert(::Type{SU2Irrep}, j::Real) = SU2Irrep(j) const _su2one = SU2Irrep(zero(HalfInt)) -Base.one(::Type{SU2Irrep}) = _su2one allones(::Type{SU2Irrep}) = (_su2one,) Base.conj(s::SU2Irrep) = s ⊗(s1::SU2Irrep, s2::SU2Irrep) = SectorSet{SU2Irrep}(abs(s1.j - s2.j):(s1.j + s2.j)) diff --git a/src/irreps/u1irrep.jl b/src/irreps/u1irrep.jl index 259f5a6..e557cf7 100644 --- a/src/irreps/u1irrep.jl +++ b/src/irreps/u1irrep.jl @@ -19,7 +19,6 @@ end Base.getindex(::IrrepTable, ::Type{U₁}) = U1Irrep Base.convert(::Type{U1Irrep}, c::Real) = U1Irrep(c) -Base.one(::Type{U1Irrep}) = U1Irrep(0) allones(::Type{U1Irrep}) = (U1Irrep(0),) Base.conj(c::U1Irrep) = U1Irrep(-c.charge) ⊗(c1::U1Irrep, c2::U1Irrep) = (U1Irrep(c1.charge + c2.charge),) diff --git a/src/irreps/znirrep.jl b/src/irreps/znirrep.jl index f60bd65..3ab8b65 100644 --- a/src/irreps/znirrep.jl +++ b/src/irreps/znirrep.jl @@ -25,7 +25,6 @@ const Z2Irrep = ZNIrrep{2} const Z3Irrep = ZNIrrep{3} const Z4Irrep = ZNIrrep{4} -Base.one(::Type{ZNIrrep{N}}) where {N} = ZNIrrep{N}(0) allones(::Type{ZNIrrep{N}}) where {N} = (ZNIrrep{N}(0),) Base.conj(c::ZNIrrep{N}) where {N} = ZNIrrep{N}(-c.n) ⊗(c1::ZNIrrep{N}, c2::ZNIrrep{N}) where {N} = (ZNIrrep{N}(c1.n + c2.n),) diff --git a/src/sectors.jl b/src/sectors.jl index 1756ff6..87bf4d6 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -91,7 +91,8 @@ end Return the unit element within this type of sector. """ -Base.one(a::Sector) = only(allones(typeof(a))) #TODO: add for type +Base.one(a::Sector) = only(allones(typeof(a))) +Base.one(::Type{I}) where {I <: Sector} = only(allones(I)) """ leftone(a::Sector) -> Sector From b28941c6816f4e0362b2c1276b831277d766e5e4 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 13:39:48 +0200 Subject: [PATCH 19/49] `allones` for productsector with tests --- src/product.jl | 14 ++++++++++++-- test/multifusion.jl | 2 ++ test/runtests.jl | 2 ++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/product.jl b/src/product.jl index 8a72b68..64c32e4 100644 --- a/src/product.jl +++ b/src/product.jl @@ -60,9 +60,19 @@ function Base.convert(::Type{ProductSector{T}}, t::Tuple) where {T <: SectorTupl return ProductSector{T}(convert(T, t)) end -Base.one(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I}} = ProductSector((one(I),)) function Base.one(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} - return one(I) ⊠ one(ProductSector{Base.tuple_type_tail(T)}) + reduce(&, map(MultiFusionStyle, _sectors(T))) == GenericMultiFusion() && + throw(DomainError(ProductSector{T}, "ProductSector $T has multiple units, use `allones` instead of `one`")) + + return only(allones(ProductSector{T})) +end +function allones(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} + head, rest = Base.tuple_type_head(T), Base.tuple_type_tail(T) + if rest == Tuple{} + return allones(head) + else + return (h ⊠ r for h in allones(head), r in allones(ProductSector{rest})) |> Tuple + end end Base.conj(p::ProductSector) = ProductSector(map(conj, p.sectors)) diff --git a/test/multifusion.jl b/test/multifusion.jl index 265f93e..639bbae 100644 --- a/test/multifusion.jl +++ b/test/multifusion.jl @@ -8,6 +8,8 @@ Istr = TensorKitSectors.type_repr(I) prodsec = I ⊠ Z2Irrep @test MultiFusionStyle(prodsec) isa GenericMultiFusion @test FusionStyle(prodsec) isa SimpleFusion + @test_throws DomainError one(prodsec) + @test length(allones(prodsec)) == 2 end M = IsingBimodule(1, 2, 0) diff --git a/test/runtests.jl b/test/runtests.jl index 42b7488..bacc0f0 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -60,6 +60,8 @@ end @constinferred a ⊠ b ⊠ a ⊠ b @constinferred I1 ⊠ I2 @test typeof(a ⊠ b) == I1 ⊠ I2 + + @test @constinferred(length(allones(I1 ⊠ I2))) == 1 end @test @constinferred(Tuple(SU2Irrep(1) ⊠ U1Irrep(0))) == (SU2Irrep(1), U1Irrep(0)) @test @constinferred(length(FermionParity(1) ⊠ SU2Irrep(1 // 2) ⊠ U1Irrep(1))) == 3 From 5a313ef8567df847e1f9e556a322fadb0839444b Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 13:42:28 +0200 Subject: [PATCH 20/49] have multifusionstyle fully depend on `allones` --- src/multifusion.jl | 1 - src/sectors.jl | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/multifusion.jl b/src/multifusion.jl index 4ad3d88..53d1406 100644 --- a/src/multifusion.jl +++ b/src/multifusion.jl @@ -55,7 +55,6 @@ function Base.convert(::Type{IsingAnyon}, a::IsingBimodule) # identify RepZ2 ⊕ end FusionStyle(::Type{IsingBimodule}) = SimpleFusion() # no multiplicities -MultiFusionStyle(::Type{IsingBimodule}) = GenericMultiFusion() # multiple units BraidingStyle(::Type{IsingBimodule}) = NoBraiding() # because of module categories function Nsymbol(a::IsingBimodule, b::IsingBimodule, c::IsingBimodule) diff --git a/src/sectors.jl b/src/sectors.jl index 87bf4d6..d8c572b 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -245,7 +245,7 @@ MultiFusionStyle(a::Sector) = MultiFusionStyle(typeof(a)) struct SimpleMultiFusion <: MultiFusionStyle end struct GenericMultiFusion <: MultiFusionStyle end -MultiFusionStyle(::Type{<:Sector}) = SimpleMultiFusion() # default is simple unit +MultiFusionStyle(::Type{I}) where {I<:Sector} = length(allones(I)) == 1 ? SimpleMultiFusion() : GenericMultiFusion() # combine fusion properties of tensor products of multifusion sectors Base.:&(f::F, ::F) where {F <: MultiFusionStyle} = f From ccb43131776013cd3a2d8d711f741aa029c72e10 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 13:59:23 +0200 Subject: [PATCH 21/49] format --- src/sectors.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sectors.jl b/src/sectors.jl index d8c572b..b6fa70c 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -245,7 +245,7 @@ MultiFusionStyle(a::Sector) = MultiFusionStyle(typeof(a)) struct SimpleMultiFusion <: MultiFusionStyle end struct GenericMultiFusion <: MultiFusionStyle end -MultiFusionStyle(::Type{I}) where {I<:Sector} = length(allones(I)) == 1 ? SimpleMultiFusion() : GenericMultiFusion() +MultiFusionStyle(::Type{I}) where {I <: Sector} = length(allones(I)) == 1 ? SimpleMultiFusion() : GenericMultiFusion() # combine fusion properties of tensor products of multifusion sectors Base.:&(f::F, ::F) where {F <: MultiFusionStyle} = f From 5c5647f4edfb39ca1eb20c0942ff6972df7dc28e Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 15:19:10 +0200 Subject: [PATCH 22/49] change `one` to `unit` and have `Base.one` fall back to `unit` + rename to `left/rightunit` and `allunits` --- src/TensorKitSectors.jl | 2 +- src/anyons.jl | 10 ++++---- src/fermions.jl | 2 +- src/groupelements.jl | 6 ++--- src/irreps/cu1irrep.jl | 4 +-- src/irreps/dnirrep.jl | 2 +- src/irreps/su2irrep.jl | 2 +- src/irreps/u1irrep.jl | 2 +- src/irreps/znirrep.jl | 2 +- src/multifusion.jl | 12 ++++----- src/product.jl | 12 ++++----- src/sectors.jl | 57 ++++++++++++++++++++++------------------- src/trivial.jl | 2 +- test/multifusion.jl | 18 ++++++------- test/newsectors.jl | 2 +- test/runtests.jl | 2 +- test/sectors.jl | 2 +- 17 files changed, 71 insertions(+), 68 deletions(-) diff --git a/src/TensorKitSectors.jl b/src/TensorKitSectors.jl index 7b2179b..0c2132c 100644 --- a/src/TensorKitSectors.jl +++ b/src/TensorKitSectors.jl @@ -14,7 +14,7 @@ export FusionStyle, UniqueFusion, MultipleFusion, SimpleFusion, GenericFusion, export MultiFusionStyle, SimpleMultiFusion, GenericMultiFusion export BraidingStyle, NoBraiding, HasBraiding, SymmetricBraiding, Bosonic, Fermionic, Anyonic export SectorSet, SectorValues, findindex -export rightone, leftone, allones +export unit, rightunit, leftunit, allunits export triangle_equation, pentagon_equation, hexagon_equation diff --git a/src/anyons.jl b/src/anyons.jl index 41cf486..fc900c3 100644 --- a/src/anyons.jl +++ b/src/anyons.jl @@ -21,8 +21,8 @@ end findindex(::SectorValues{PlanarTrivial}, c::PlanarTrivial) = 1 Base.isless(::PlanarTrivial, ::PlanarTrivial) = false -Base.one(::Type{PlanarTrivial}) = PlanarTrivial() -allones(::Type{PlanarTrivial}) = (PlanarTrivial(),) +unit(::Type{PlanarTrivial}) = PlanarTrivial() +allunits(::Type{PlanarTrivial}) = (PlanarTrivial(),) Base.conj(::PlanarTrivial) = PlanarTrivial() FusionStyle(::Type{PlanarTrivial}) = UniqueFusion() @@ -72,8 +72,8 @@ end findindex(::SectorValues{FibonacciAnyon}, s::FibonacciAnyon) = 2 - s.isone Base.convert(::Type{FibonacciAnyon}, s::Symbol) = FibonacciAnyon(s) -Base.one(::Type{FibonacciAnyon}) = FibonacciAnyon(:I) -allones(::Type{FibonacciAnyon}) = (FibonacciAnyon(:I),) +unit(::Type{FibonacciAnyon}) = FibonacciAnyon(:I) +allunits(::Type{FibonacciAnyon}) = (FibonacciAnyon(:I),) Base.conj(s::FibonacciAnyon) = s const _goldenratio = Float64(MathConstants.golden) @@ -193,7 +193,7 @@ function findindex(::SectorValues{IsingAnyon}, a::IsingAnyon) end Base.convert(::Type{IsingAnyon}, s::Symbol) = IsingAnyon(s) -allones(::Type{IsingAnyon}) = (IsingAnyon(:I),) +allunits(::Type{IsingAnyon}) = (IsingAnyon(:I),) Base.conj(s::IsingAnyon) = s dim(a::IsingAnyon) = a.s == :σ ? sqrt(2) : 1.0 diff --git a/src/fermions.jl b/src/fermions.jl index 071151b..acaf684 100644 --- a/src/fermions.jl +++ b/src/fermions.jl @@ -28,7 +28,7 @@ function Base.getindex(::SectorValues{FermionParity}, i::Int) end findindex(::SectorValues{FermionParity}, f::FermionParity) = f.isodd ? 2 : 1 -allones(::Type{FermionParity}) = (FermionParity(false),) +allunits(::Type{FermionParity}) = (FermionParity(false),) Base.conj(f::FermionParity) = f dim(f::FermionParity) = 1 diff --git a/src/groupelements.jl b/src/groupelements.jl index 4a3be1f..347f14f 100644 --- a/src/groupelements.jl +++ b/src/groupelements.jl @@ -18,7 +18,7 @@ For the fusion structure, a specific `SomeGroupElement<:AbstractGroupElement{Som should only implement the following methods ```julia Base.:*(c1::GroupElement, c2::GroupElement) -> GroupElement -Base.one(::Type{GroupElement}) -> GroupElement +unit(::Type{GroupElement}) -> GroupElement Base.inv(c::GroupElement) -> GroupElement # and optionally TensorKitSectors.cocycle(c1::GroupElement, c2::GroupElement, c3::GroupElement) -> Number @@ -34,7 +34,7 @@ BraidingStyle(::Type{<:AbstractGroupElement}) = NoBraiding() cocycle(a::I, b::I, c::I) where {I <: AbstractGroupElement} = 1 ⊗(a::I, b::I) where {I <: AbstractGroupElement} = (a * b,) -allones(a::Type{<:AbstractGroupElement}) = (one(a),) +allunits(a::Type{<:AbstractGroupElement}) = (unit(a),) Base.conj(a::AbstractGroupElement) = inv(a) Nsymbol(a::I, b::I, c::I) where {I <: AbstractGroupElement} = c == a * b function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: AbstractGroupElement} @@ -124,7 +124,7 @@ const Z2Element{p} = ZNElement{2, p} const Z3Element{p} = ZNElement{3, p} const Z4Element{p} = ZNElement{4, p} -allones(::Type{Z}) where {Z <: ZNElement} = (Z(0),) +allunits(::Type{Z}) where {Z <: ZNElement} = (Z(0),) Base.inv(c::ZNElement) = typeof(c)(-c.n) Base.:*(c1::ZNElement{N, p}, c2::ZNElement{N, p}) where {N, p} = ZNElement{N, p}(mod(c1.n + c2.n, N)) diff --git a/src/irreps/cu1irrep.jl b/src/irreps/cu1irrep.jl index 1a0aa5b..c4a3546 100644 --- a/src/irreps/cu1irrep.jl +++ b/src/irreps/cu1irrep.jl @@ -66,7 +66,7 @@ end Base.convert(::Type{CU1Irrep}, j::Real) = CU1Irrep(j) Base.convert(::Type{CU1Irrep}, js::Tuple{Real, Int}) = CU1Irrep(js...) -allones(::Type{CU1Irrep}) = (CU1Irrep(zero(HalfInt), 0),) +allunits(::Type{CU1Irrep}) = (CU1Irrep(zero(HalfInt), 0),) Base.conj(c::CU1Irrep) = c struct CU1ProdIterator @@ -82,7 +82,7 @@ function Base.iterate(p::CU1ProdIterator, s::Int = 1) elseif p.b.j == zero(HalfInt) return p.a, 4 elseif p.a == p.b # != zero - return one(CU1Irrep), 2 + return unit(CU1Irrep), 2 else return CU1Irrep(abs(p.a.j - p.b.j)), 3 end diff --git a/src/irreps/dnirrep.jl b/src/irreps/dnirrep.jl index 6116ce9..542bc3d 100644 --- a/src/irreps/dnirrep.jl +++ b/src/irreps/dnirrep.jl @@ -47,7 +47,7 @@ FusionStyle(::Type{DNIrrep{N}}) where {N} = N < 3 ? UniqueFusion() : SimpleFusio sectorscalartype(::Type{DNIrrep{N}}) where {N} = Float64 Base.isreal(::Type{DNIrrep{N}}) where {N} = true -allones(::Type{DNIrrep{N}}) where {N} = (DNIrrep{N}(0, false),) +allunits(::Type{DNIrrep{N}}) where {N} = (DNIrrep{N}(0, false),) Base.conj(a::DNIrrep) = a Base.hash(a::DNIrrep, h::UInt) = hash(a.data, h) diff --git a/src/irreps/su2irrep.jl b/src/irreps/su2irrep.jl index 5a332c3..f51f15c 100644 --- a/src/irreps/su2irrep.jl +++ b/src/irreps/su2irrep.jl @@ -30,7 +30,7 @@ Base.getindex(::IrrepTable, ::Type{SU₂}) = SU2Irrep Base.convert(::Type{SU2Irrep}, j::Real) = SU2Irrep(j) const _su2one = SU2Irrep(zero(HalfInt)) -allones(::Type{SU2Irrep}) = (_su2one,) +allunits(::Type{SU2Irrep}) = (_su2one,) Base.conj(s::SU2Irrep) = s ⊗(s1::SU2Irrep, s2::SU2Irrep) = SectorSet{SU2Irrep}(abs(s1.j - s2.j):(s1.j + s2.j)) diff --git a/src/irreps/u1irrep.jl b/src/irreps/u1irrep.jl index e557cf7..1685e43 100644 --- a/src/irreps/u1irrep.jl +++ b/src/irreps/u1irrep.jl @@ -19,7 +19,7 @@ end Base.getindex(::IrrepTable, ::Type{U₁}) = U1Irrep Base.convert(::Type{U1Irrep}, c::Real) = U1Irrep(c) -allones(::Type{U1Irrep}) = (U1Irrep(0),) +allunits(::Type{U1Irrep}) = (U1Irrep(0),) Base.conj(c::U1Irrep) = U1Irrep(-c.charge) ⊗(c1::U1Irrep, c2::U1Irrep) = (U1Irrep(c1.charge + c2.charge),) diff --git a/src/irreps/znirrep.jl b/src/irreps/znirrep.jl index 3ab8b65..551cb66 100644 --- a/src/irreps/znirrep.jl +++ b/src/irreps/znirrep.jl @@ -25,7 +25,7 @@ const Z2Irrep = ZNIrrep{2} const Z3Irrep = ZNIrrep{3} const Z4Irrep = ZNIrrep{4} -allones(::Type{ZNIrrep{N}}) where {N} = (ZNIrrep{N}(0),) +allunits(::Type{ZNIrrep{N}}) where {N} = (ZNIrrep{N}(0),) Base.conj(c::ZNIrrep{N}) where {N} = ZNIrrep{N}(-c.n) ⊗(c1::ZNIrrep{N}, c2::ZNIrrep{N}) where {N} = (ZNIrrep{N}(c1.n + c2.n),) diff --git a/src/multifusion.jl b/src/multifusion.jl index 53d1406..aa1bd56 100644 --- a/src/multifusion.jl +++ b/src/multifusion.jl @@ -76,22 +76,22 @@ end # ℳ ↔ ℳop when conjugating elements within these Base.conj(a::IsingBimodule) = IsingBimodule(a.col, a.row, a.label) -rightone(a::IsingBimodule) = IsingBimodule(a.col, a.col, 0) -leftone(a::IsingBimodule) = IsingBimodule(a.row, a.row, 0) +rightunit(a::IsingBimodule) = IsingBimodule(a.col, a.col, 0) +leftunit(a::IsingBimodule) = IsingBimodule(a.row, a.row, 0) -function Base.one(a::IsingBimodule) +function unit(a::IsingBimodule) a.row == a.col || throw(DomainError(a, "unit of module category ($(a.row), $(a.col)) doesn't exist")) return IsingBimodule(a.row, a.col, 0) end -Base.isone(a::IsingBimodule) = leftone(a) == a == rightone(a) +Base.isone(a::IsingBimodule) = leftunit(a) == a == rightunit(a) -function Base.one(::Type{IsingBimodule}) +function unit(::Type{IsingBimodule}) throw(ArgumentError("one of Type IsingBimodule doesn't exist")) end -allones(::Type{IsingBimodule}) = (IsingBimodule(1, 1, 0), IsingBimodule(2, 2, 0)) +allunits(::Type{IsingBimodule}) = (IsingBimodule(1, 1, 0), IsingBimodule(2, 2, 0)) function Base.isless(a::IsingBimodule, b::IsingBimodule) return isless((a.col, a.row, a.label), (b.col, b.row, b.label)) diff --git a/src/product.jl b/src/product.jl index 64c32e4..5829e38 100644 --- a/src/product.jl +++ b/src/product.jl @@ -60,18 +60,18 @@ function Base.convert(::Type{ProductSector{T}}, t::Tuple) where {T <: SectorTupl return ProductSector{T}(convert(T, t)) end -function Base.one(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} +function unit(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} reduce(&, map(MultiFusionStyle, _sectors(T))) == GenericMultiFusion() && - throw(DomainError(ProductSector{T}, "ProductSector $T has multiple units, use `allones` instead of `one`")) + throw(DomainError(ProductSector{T}, "ProductSector $T has multiple units, use `allunits` instead of `one`")) - return only(allones(ProductSector{T})) + return only(allunits(ProductSector{T})) end -function allones(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} +function allunits(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} head, rest = Base.tuple_type_head(T), Base.tuple_type_tail(T) if rest == Tuple{} - return allones(head) + return allunits(head) else - return (h ⊠ r for h in allones(head), r in allones(ProductSector{rest})) |> Tuple + return (h ⊠ r for h in allunits(head), r in allunits(ProductSector{rest})) |> Tuple end end diff --git a/src/sectors.jl b/src/sectors.jl index b6fa70c..9dd6161 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -6,7 +6,7 @@ and pivotal) (pre-)fusion categories, e.g. the irreducible representations of a 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` +* `unit(::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) @@ -86,37 +86,40 @@ function findindex(v::SectorValues{I}, c::I) where {I <: Sector} end """ - one(::Sector) -> Sector - one(::Type{<:Sector}) -> Sector + unit(::Sector) -> Sector + unit(::Type{<:Sector}) -> Sector Return the unit element within this type of sector. """ -Base.one(a::Sector) = only(allones(typeof(a))) -Base.one(::Type{I}) where {I <: Sector} = only(allones(I)) +unit(a::Sector) = only(allunits(typeof(a))) +unit(::Type{I}) where {I <: Sector} = only(allunits(I)) +Base.one(a::Sector) = unit(a) +Base.one(::Type{I}) where {I <: Sector} = unit(I) + +#TODO: define isunit function with isone fallback? """ - leftone(a::Sector) -> Sector + leftunit(a::Sector) -> Sector Return the left unit element within this type of sector. -See also [`rightone`](@ref) and [`Base.one`](@ref). +See also [`rightunit`](@ref) and [`unit`](@ref). """ -leftone(a::Sector) = one(a) +leftunit(a::Sector) = unit(a) """ - rightone(a::Sector) -> Sector + rightunit(a::Sector) -> Sector Return the right unit element within this type of sector. -See also [`leftone`](@ref) and [`Base.one`](@ref). +See also [`leftunit`](@ref) and [`unit`](@ref). """ -rightone(a::Sector) = one(a) +rightunit(a::Sector) = unit(a) """ - allones(I::Type{<:Sector}) -> Tuple{I} + allunits(I::Type{<:Sector}) -> Tuple{I} Return a tuple with all units of the sector type `I`. For fusion categories, this will contain only one element. """ -allones(I::Type{<:Sector}) = (one(I),) # do we need/want this fallback? or change it to evaluate a sector? """ dual(a::Sector) -> Sector @@ -239,13 +242,13 @@ This can be either * `SimpleMultiFusion()`: the unit is simple (e.g. fusion categories); * `GenericMultiFusion()`: the unit is semisimple. """ -abstract type MultiFusionStyle end +abstract type MultiFusionStyle end #TODO: rename MultiFusionStyle(a::Sector) = MultiFusionStyle(typeof(a)) struct SimpleMultiFusion <: MultiFusionStyle end struct GenericMultiFusion <: MultiFusionStyle end -MultiFusionStyle(::Type{I}) where {I <: Sector} = length(allones(I)) == 1 ? SimpleMultiFusion() : GenericMultiFusion() +MultiFusionStyle(::Type{I}) where {I <: Sector} = length(allunits(I)) == 1 ? SimpleMultiFusion() : GenericMultiFusion() # combine fusion properties of tensor products of multifusion sectors Base.:&(f::F, ::F) where {F <: MultiFusionStyle} = f @@ -285,9 +288,9 @@ function dim(a::Sector) return if FusionStyle(a) isa UniqueFusion 1 elseif FusionStyle(a) isa SimpleFusion - abs(1 / Fsymbol(a, conj(a), a, a, leftone(a), rightone(a))) + abs(1 / Fsymbol(a, conj(a), a, a, leftunit(a), rightunit(a))) else - abs(1 / Fsymbol(a, conj(a), a, a, leftone(a), rightone(a))[1]) + abs(1 / Fsymbol(a, conj(a), a, a, leftunit(a), rightunit(a))[1]) end end sqrtdim(a::Sector) = (FusionStyle(a) isa UniqueFusion) ? 1 : sqrt(dim(a)) @@ -300,9 +303,9 @@ Return the Frobenius-Schur indicator of a sector `a`. """ function frobeniusschur(a::Sector) return if FusionStyle(a) isa UniqueFusion || FusionStyle(a) isa SimpleFusion - sign(Fsymbol(a, conj(a), a, a, leftone(a), rightone(a))) + sign(Fsymbol(a, conj(a), a, a, leftunit(a), rightunit(a))) else - sign(Fsymbol(a, conj(a), a, a, leftone(a), rightone(a))[1]) + sign(Fsymbol(a, conj(a), a, a, leftunit(a), rightunit(a))[1]) end end @@ -310,11 +313,11 @@ end function Asymbol(a::I, b::I, c::I) where {I <: Sector} return if FusionStyle(I) isa UniqueFusion || FusionStyle(I) isa SimpleFusion (sqrtdim(a) * sqrtdim(b) * invsqrtdim(c)) * - conj(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftone(a), c)) + conj(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftunit(a), c)) else reshape( (sqrtdim(a) * sqrtdim(b) * invsqrtdim(c)) * - conj(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftone(a), c)), + conj(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftunit(a), c)), (Nsymbol(a, b, c), Nsymbol(dual(a), c, b)) ) end @@ -336,10 +339,10 @@ number. Otherwise it is a square matrix with row and column size """ function Bsymbol(a::I, b::I, c::I) where {I <: Sector} return if FusionStyle(I) isa UniqueFusion || FusionStyle(I) isa SimpleFusion - (sqrtdim(a) * sqrtdim(b) * invsqrtdim(c)) * Fsymbol(a, b, dual(b), a, c, rightone(a)) + (sqrtdim(a) * sqrtdim(b) * invsqrtdim(c)) * Fsymbol(a, b, dual(b), a, c, rightunit(a)) else reshape( - (sqrtdim(a) * sqrtdim(b) * invsqrtdim(c)) * Fsymbol(a, b, dual(b), a, c, rightone(a)), + (sqrtdim(a) * sqrtdim(b) * invsqrtdim(c)) * Fsymbol(a, b, dual(b), a, c, rightunit(a)), (Nsymbol(a, b, c), Nsymbol(c, dual(b), a)) ) end @@ -411,9 +414,9 @@ twist(a::Sector) = sum(dim(b) / dim(a) * tr(Rsymbol(a, a, b)) for b in a ⊗ a) # requirement that certain F-moves involving unit objects are trivial function triangle_equation(a::I, b::I; kwargs...) where {I <: Sector} for c in ⊗(a, b) - F1 = Fsymbol(leftone(a), a, b, c, a, c) - F2 = Fsymbol(a, rightone(a), b, c, a, b) - F3 = Fsymbol(a, b, rightone(b), c, c, b) + F1 = Fsymbol(leftunit(a), a, b, c, a, c) + F2 = Fsymbol(a, rightunit(a), b, c, a, b) + F3 = Fsymbol(a, b, rightunit(b), c, c, b) isapproxone(F) = isapprox(F, one(F); kwargs...) if FusionStyle(I) isa MultiplicityFreeFusion @@ -550,7 +553,7 @@ function Rsymbol( return adjoint(Rsymbol(a.a, b.a, c.a)) end -Base.one(::Type{TimeReversed{I}}) where {I <: Sector} = TimeReversed{I}(one(I)) +unit(::Type{TimeReversed{I}}) where {I <: Sector} = TimeReversed{I}(unit(I)) Base.conj(c::TimeReversed{I}) where {I <: Sector} = TimeReversed{I}(conj(c.a)) function ⊗(c1::TimeReversed{I}, c2::TimeReversed{I}) where {I <: Sector} return Iterators.map(TimeReversed{I}, c1.a ⊗ c2.a) diff --git a/src/trivial.jl b/src/trivial.jl index 53cb4d4..ab156e6 100644 --- a/src/trivial.jl +++ b/src/trivial.jl @@ -19,7 +19,7 @@ end findindex(::SectorValues{Trivial}, c::Trivial) = 1 # basic properties -Base.one(::Type{Trivial}) = Trivial() +allunits(::Type{Trivial}) = (Trivial(),) Base.conj(::Trivial) = Trivial() Base.isreal(::Type{Trivial}) = true diff --git a/test/multifusion.jl b/test/multifusion.jl index 639bbae..e8443ff 100644 --- a/test/multifusion.jl +++ b/test/multifusion.jl @@ -8,8 +8,8 @@ Istr = TensorKitSectors.type_repr(I) prodsec = I ⊠ Z2Irrep @test MultiFusionStyle(prodsec) isa GenericMultiFusion @test FusionStyle(prodsec) isa SimpleFusion - @test_throws DomainError one(prodsec) - @test length(allones(prodsec)) == 2 + @test_throws DomainError unit(prodsec) + @test length(allunits(prodsec)) == 2 end M = IsingBimodule(1, 2, 0) @@ -23,18 +23,18 @@ Istr = TensorKitSectors.type_repr(I) s = rand((M, Mop, C, D)) @testset "Basic properties" begin - @test @constinferred(one(C1)) == @constinferred(leftone(C1)) == - @constinferred(rightone(C1)) - @test one(D1) == leftone(D1) == rightone(D1) - @test one(C1) == leftone(M) == rightone(Mop) - @test one(D1) == rightone(M) == leftone(Mop) + @test @constinferred(unit(C1)) == @constinferred(leftunit(C1)) == + @constinferred(rightunit(C1)) + @test unit(D1) == leftunit(D1) == rightunit(D1) + @test unit(C1) == leftunit(M) == rightunit(Mop) + @test unit(D1) == rightunit(M) == leftunit(Mop) @test @constinferred(isone(C0)) @test isone(D0) @test !isone(C1) && !isone(D1) && !isone(M) && !isone(Mop) - @test length(allones(I)) == 2 - @test allones(I) == (C0, D0) + @test length(allunits(I)) == 2 + @test allunits(I) == (C0, D0) @test eval(Meta.parse(sprint(show, s))) == s @test @constinferred(hash(s)) == hash(deepcopy(s)) diff --git a/test/newsectors.jl b/test/newsectors.jl index 8dd1a0f..f9054bf 100644 --- a/test/newsectors.jl +++ b/test/newsectors.jl @@ -25,7 +25,7 @@ end Base.convert(::Type{NewSU2Irrep}, j::Real) = NewSU2Irrep(j) const _su2one = NewSU2Irrep(zero(HalfInt)) -Base.one(::Type{NewSU2Irrep}) = _su2one +unit(::Type{NewSU2Irrep}) = _su2one Base.conj(s::NewSU2Irrep) = s function ⊗(s1::NewSU2Irrep, s2::NewSU2Irrep) return SectorSet{NewSU2Irrep}(abs(s1.j - s2.j):(s1.j + s2.j)) diff --git a/test/runtests.jl b/test/runtests.jl index bacc0f0..513727b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -61,7 +61,7 @@ end @constinferred I1 ⊠ I2 @test typeof(a ⊠ b) == I1 ⊠ I2 - @test @constinferred(length(allones(I1 ⊠ I2))) == 1 + @test @constinferred(length(allunits(I1 ⊠ I2))) == 1 end @test @constinferred(Tuple(SU2Irrep(1) ⊠ U1Irrep(0))) == (SU2Irrep(1), U1Irrep(0)) @test @constinferred(length(FermionParity(1) ⊠ SU2Irrep(1 // 2) ⊠ U1Irrep(1))) == 3 diff --git a/test/sectors.jl b/test/sectors.jl index 88092c3..66d2f68 100644 --- a/test/sectors.jl +++ b/test/sectors.jl @@ -40,7 +40,7 @@ end i >= 10 && break end @test one(I) == first(values(I)) - @test length(allones(I)) == 1 + @test length(allunits(I)) == 1 @test (@constinferred findindex(values(I), one(I))) == 1 for s in smallset(I) @test (@constinferred values(I)[findindex(values(I), s)]) == s From 684d810e59dbaf13d256462f4dfb8e616899fd4b Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 15:23:50 +0200 Subject: [PATCH 23/49] rename `MultiFusionStyle` to `UnitStyle` --- src/TensorKitSectors.jl | 2 +- src/product.jl | 6 +++--- src/sectors.jl | 24 ++++++++++++------------ test/multifusion.jl | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/TensorKitSectors.jl b/src/TensorKitSectors.jl index 0c2132c..0ebe216 100644 --- a/src/TensorKitSectors.jl +++ b/src/TensorKitSectors.jl @@ -11,7 +11,7 @@ export dim, sqrtdim, invsqrtdim, frobeniusschur, twist, fusiontensor, dual export otimes, deligneproduct, times export FusionStyle, UniqueFusion, MultipleFusion, SimpleFusion, GenericFusion, MultiplicityFreeFusion -export MultiFusionStyle, SimpleMultiFusion, GenericMultiFusion +export UnitStyle, SimpleUnit, GenericUnit export BraidingStyle, NoBraiding, HasBraiding, SymmetricBraiding, Bosonic, Fermionic, Anyonic export SectorSet, SectorValues, findindex export unit, rightunit, leftunit, allunits diff --git a/src/product.jl b/src/product.jl index 5829e38..7005ea0 100644 --- a/src/product.jl +++ b/src/product.jl @@ -61,7 +61,7 @@ function Base.convert(::Type{ProductSector{T}}, t::Tuple) where {T <: SectorTupl end function unit(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} - reduce(&, map(MultiFusionStyle, _sectors(T))) == GenericMultiFusion() && + reduce(&, map(UnitStyle, _sectors(T))) == GenericUnit() && throw(DomainError(ProductSector{T}, "ProductSector $T has multiple units, use `allunits` instead of `one`")) return only(allunits(ProductSector{T})) @@ -213,8 +213,8 @@ end function FusionStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} return Base.:&(map(FusionStyle, _sectors(T))...) end -function MultiFusionStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} - return Base.:&(map(MultiFusionStyle, _sectors(T))...) +function UnitStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} + return Base.:&(map(UnitStyle, _sectors(T))...) end function BraidingStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} return Base.:&(map(BraidingStyle, _sectors(T))...) diff --git a/src/sectors.jl b/src/sectors.jl index 9dd6161..6659226 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -234,27 +234,27 @@ Base.:&(::GenericFusion, ::SimpleFusion) = GenericFusion() # similar, but for multifusion categories """ - MultiFusionStyle(::Sector) - MultiFusionStyle(I::Type{<:Sector}) + UnitStyle(::Sector) + UnitStyle(I::Type{<:Sector}) Trait to describe the semisimplicity of the unit sector of type `I`. This can be either -* `SimpleMultiFusion()`: the unit is simple (e.g. fusion categories); -* `GenericMultiFusion()`: the unit is semisimple. +* `SimpleUnit()`: the unit is simple (e.g. fusion categories); +* `GenericUnit()`: the unit is semisimple. """ -abstract type MultiFusionStyle end #TODO: rename -MultiFusionStyle(a::Sector) = MultiFusionStyle(typeof(a)) +abstract type UnitStyle end #TODO: rename +UnitStyle(a::Sector) = UnitStyle(typeof(a)) -struct SimpleMultiFusion <: MultiFusionStyle end -struct GenericMultiFusion <: MultiFusionStyle end +struct SimpleUnit <: UnitStyle end +struct GenericUnit <: UnitStyle end -MultiFusionStyle(::Type{I}) where {I <: Sector} = length(allunits(I)) == 1 ? SimpleMultiFusion() : GenericMultiFusion() +UnitStyle(::Type{I}) where {I <: Sector} = length(allunits(I)) == 1 ? SimpleUnit() : GenericUnit() # combine fusion properties of tensor products of multifusion sectors -Base.:&(f::F, ::F) where {F <: MultiFusionStyle} = f -Base.:&(f₁::MultiFusionStyle, f₂::MultiFusionStyle) = f₂ & f₁ +Base.:&(f::F, ::F) where {F <: UnitStyle} = f +Base.:&(f₁::UnitStyle, f₂::UnitStyle) = f₂ & f₁ -Base.:&(::GenericMultiFusion, ::SimpleMultiFusion) = GenericMultiFusion() +Base.:&(::GenericUnit, ::SimpleUnit) = GenericUnit() """ Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I<:Sector} diff --git a/test/multifusion.jl b/test/multifusion.jl index e8443ff..ac3e35e 100644 --- a/test/multifusion.jl +++ b/test/multifusion.jl @@ -6,7 +6,7 @@ Istr = TensorKitSectors.type_repr(I) @test eval(Meta.parse(TensorKitSectors.type_repr(I))) == I prodsec = I ⊠ Z2Irrep - @test MultiFusionStyle(prodsec) isa GenericMultiFusion + @test UnitStyle(prodsec) isa GenericUnit @test FusionStyle(prodsec) isa SimpleFusion @test_throws DomainError unit(prodsec) @test length(allunits(prodsec)) == 2 From d6188d6dbc5453d5d5d7882c70882d4abbd178eb Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 15:31:41 +0200 Subject: [PATCH 24/49] replace `Base.conj` with `dual` and have `dual` fall back to `Base.conj` --- src/anyons.jl | 6 +++--- src/fermions.jl | 2 +- src/groupelements.jl | 2 +- src/irreps/cu1irrep.jl | 2 +- src/irreps/dnirrep.jl | 2 +- src/irreps/su2irrep.jl | 2 +- src/irreps/u1irrep.jl | 2 +- src/irreps/znirrep.jl | 2 +- src/multifusion.jl | 2 +- src/product.jl | 2 +- src/sectors.jl | 11 ++++++----- src/trivial.jl | 2 +- test/newsectors.jl | 2 +- 13 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/anyons.jl b/src/anyons.jl index fc900c3..b556f50 100644 --- a/src/anyons.jl +++ b/src/anyons.jl @@ -23,7 +23,7 @@ Base.isless(::PlanarTrivial, ::PlanarTrivial) = false unit(::Type{PlanarTrivial}) = PlanarTrivial() allunits(::Type{PlanarTrivial}) = (PlanarTrivial(),) -Base.conj(::PlanarTrivial) = PlanarTrivial() +dual(::PlanarTrivial) = PlanarTrivial() FusionStyle(::Type{PlanarTrivial}) = UniqueFusion() BraidingStyle(::Type{PlanarTrivial}) = NoBraiding() @@ -74,7 +74,7 @@ findindex(::SectorValues{FibonacciAnyon}, s::FibonacciAnyon) = 2 - s.isone Base.convert(::Type{FibonacciAnyon}, s::Symbol) = FibonacciAnyon(s) unit(::Type{FibonacciAnyon}) = FibonacciAnyon(:I) allunits(::Type{FibonacciAnyon}) = (FibonacciAnyon(:I),) -Base.conj(s::FibonacciAnyon) = s +dual(s::FibonacciAnyon) = s const _goldenratio = Float64(MathConstants.golden) dim(a::FibonacciAnyon) = isone(a) ? one(_goldenratio) : _goldenratio @@ -194,7 +194,7 @@ end Base.convert(::Type{IsingAnyon}, s::Symbol) = IsingAnyon(s) allunits(::Type{IsingAnyon}) = (IsingAnyon(:I),) -Base.conj(s::IsingAnyon) = s +dual(s::IsingAnyon) = s dim(a::IsingAnyon) = a.s == :σ ? sqrt(2) : 1.0 diff --git a/src/fermions.jl b/src/fermions.jl index acaf684..24d0d7f 100644 --- a/src/fermions.jl +++ b/src/fermions.jl @@ -29,7 +29,7 @@ end findindex(::SectorValues{FermionParity}, f::FermionParity) = f.isodd ? 2 : 1 allunits(::Type{FermionParity}) = (FermionParity(false),) -Base.conj(f::FermionParity) = f +dual(f::FermionParity) = f dim(f::FermionParity) = 1 FusionStyle(::Type{FermionParity}) = UniqueFusion() diff --git a/src/groupelements.jl b/src/groupelements.jl index 347f14f..98b6bbf 100644 --- a/src/groupelements.jl +++ b/src/groupelements.jl @@ -35,7 +35,7 @@ BraidingStyle(::Type{<:AbstractGroupElement}) = NoBraiding() cocycle(a::I, b::I, c::I) where {I <: AbstractGroupElement} = 1 ⊗(a::I, b::I) where {I <: AbstractGroupElement} = (a * b,) allunits(a::Type{<:AbstractGroupElement}) = (unit(a),) -Base.conj(a::AbstractGroupElement) = inv(a) +dual(a::AbstractGroupElement) = inv(a) Nsymbol(a::I, b::I, c::I) where {I <: AbstractGroupElement} = c == a * b function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: AbstractGroupElement} ω = cocycle(a, b, c) diff --git a/src/irreps/cu1irrep.jl b/src/irreps/cu1irrep.jl index c4a3546..7fc2277 100644 --- a/src/irreps/cu1irrep.jl +++ b/src/irreps/cu1irrep.jl @@ -67,7 +67,7 @@ Base.convert(::Type{CU1Irrep}, j::Real) = CU1Irrep(j) Base.convert(::Type{CU1Irrep}, js::Tuple{Real, Int}) = CU1Irrep(js...) allunits(::Type{CU1Irrep}) = (CU1Irrep(zero(HalfInt), 0),) -Base.conj(c::CU1Irrep) = c +dual(c::CU1Irrep) = c struct CU1ProdIterator a::CU1Irrep diff --git a/src/irreps/dnirrep.jl b/src/irreps/dnirrep.jl index 542bc3d..8cb7d4d 100644 --- a/src/irreps/dnirrep.jl +++ b/src/irreps/dnirrep.jl @@ -48,7 +48,7 @@ sectorscalartype(::Type{DNIrrep{N}}) where {N} = Float64 Base.isreal(::Type{DNIrrep{N}}) where {N} = true allunits(::Type{DNIrrep{N}}) where {N} = (DNIrrep{N}(0, false),) -Base.conj(a::DNIrrep) = a +dual(a::DNIrrep) = a Base.hash(a::DNIrrep, h::UInt) = hash(a.data, h) Base.convert(::Type{DNIrrep{N}}, (j, n)::Tuple{Integer, Bool}) where {N} = DNIrrep{N}(j, n) diff --git a/src/irreps/su2irrep.jl b/src/irreps/su2irrep.jl index f51f15c..457eba9 100644 --- a/src/irreps/su2irrep.jl +++ b/src/irreps/su2irrep.jl @@ -31,7 +31,7 @@ Base.convert(::Type{SU2Irrep}, j::Real) = SU2Irrep(j) const _su2one = SU2Irrep(zero(HalfInt)) allunits(::Type{SU2Irrep}) = (_su2one,) -Base.conj(s::SU2Irrep) = s +dual(s::SU2Irrep) = s ⊗(s1::SU2Irrep, s2::SU2Irrep) = SectorSet{SU2Irrep}(abs(s1.j - s2.j):(s1.j + s2.j)) Base.IteratorSize(::Type{SectorValues{SU2Irrep}}) = IsInfinite() diff --git a/src/irreps/u1irrep.jl b/src/irreps/u1irrep.jl index 1685e43..78a7d2f 100644 --- a/src/irreps/u1irrep.jl +++ b/src/irreps/u1irrep.jl @@ -20,7 +20,7 @@ Base.getindex(::IrrepTable, ::Type{U₁}) = U1Irrep Base.convert(::Type{U1Irrep}, c::Real) = U1Irrep(c) allunits(::Type{U1Irrep}) = (U1Irrep(0),) -Base.conj(c::U1Irrep) = U1Irrep(-c.charge) +dual(c::U1Irrep) = U1Irrep(-c.charge) ⊗(c1::U1Irrep, c2::U1Irrep) = (U1Irrep(c1.charge + c2.charge),) Base.IteratorSize(::Type{SectorValues{U1Irrep}}) = IsInfinite() diff --git a/src/irreps/znirrep.jl b/src/irreps/znirrep.jl index 551cb66..9569243 100644 --- a/src/irreps/znirrep.jl +++ b/src/irreps/znirrep.jl @@ -26,7 +26,7 @@ const Z3Irrep = ZNIrrep{3} const Z4Irrep = ZNIrrep{4} allunits(::Type{ZNIrrep{N}}) where {N} = (ZNIrrep{N}(0),) -Base.conj(c::ZNIrrep{N}) where {N} = ZNIrrep{N}(-c.n) +dual(c::ZNIrrep{N}) where {N} = ZNIrrep{N}(-c.n) ⊗(c1::ZNIrrep{N}, c2::ZNIrrep{N}) where {N} = (ZNIrrep{N}(c1.n + c2.n),) Base.IteratorSize(::Type{SectorValues{ZNIrrep{N}}}) where {N} = HasLength() diff --git a/src/multifusion.jl b/src/multifusion.jl index aa1bd56..0eda78a 100644 --- a/src/multifusion.jl +++ b/src/multifusion.jl @@ -74,7 +74,7 @@ function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: IsingBimodule} end # ℳ ↔ ℳop when conjugating elements within these -Base.conj(a::IsingBimodule) = IsingBimodule(a.col, a.row, a.label) +dual(a::IsingBimodule) = IsingBimodule(a.col, a.row, a.label) rightunit(a::IsingBimodule) = IsingBimodule(a.col, a.col, 0) leftunit(a::IsingBimodule) = IsingBimodule(a.row, a.row, 0) diff --git a/src/product.jl b/src/product.jl index 7005ea0..291d57c 100644 --- a/src/product.jl +++ b/src/product.jl @@ -75,7 +75,7 @@ function allunits(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Va end end -Base.conj(p::ProductSector) = ProductSector(map(conj, p.sectors)) +dual(p::ProductSector) = ProductSector(map(conj, p.sectors)) function ⊗(p1::P, p2::P) where {P <: ProductSector} if FusionStyle(P) isa UniqueFusion (P(first(product(map(⊗, p1.sectors, p2.sectors)...))),) diff --git a/src/sectors.jl b/src/sectors.jl index 6659226..25237aa 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -6,8 +6,8 @@ and pivotal) (pre-)fusion categories, e.g. the irreducible representations of a compact group. Subtypes `I<:Sector` as the set of labels of a `GradedSpace`. Every new `I<:Sector` should implement the following methods: -* `unit(::Type{I})`: unit element of `I` -* `conj(a::I)`: ``a̅``, conjugate or dual label of ``a`` +* `unit(::Type{I})`: unit element of `I` #TODO: change to allunits +* `dual(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 @@ -124,9 +124,10 @@ For fusion categories, this will contain only one element. """ dual(a::Sector) -> Sector -Return the conjugate label `conj(a)`. +Return the dual label of `a`, i.e. the unique label `a^*` such that +Nsymbol(a, a^*, leftunit(a)) = 1 and Nsymbol(a^*, a, rightunit(a)) = 1. """ -dual(a::Sector) = conj(a) +Base.conj(a::Sector) = dual(a) """ sectorscalartype(I::Type{<:Sector}) -> Type @@ -554,7 +555,7 @@ function Rsymbol( end unit(::Type{TimeReversed{I}}) where {I <: Sector} = TimeReversed{I}(unit(I)) -Base.conj(c::TimeReversed{I}) where {I <: Sector} = TimeReversed{I}(conj(c.a)) +dual(c::TimeReversed{I}) where {I <: Sector} = TimeReversed{I}(conj(c.a)) function ⊗(c1::TimeReversed{I}, c2::TimeReversed{I}) where {I <: Sector} return Iterators.map(TimeReversed{I}, c1.a ⊗ c2.a) end diff --git a/src/trivial.jl b/src/trivial.jl index ab156e6..020418e 100644 --- a/src/trivial.jl +++ b/src/trivial.jl @@ -20,7 +20,7 @@ findindex(::SectorValues{Trivial}, c::Trivial) = 1 # basic properties allunits(::Type{Trivial}) = (Trivial(),) -Base.conj(::Trivial) = Trivial() +dual(::Trivial) = Trivial() Base.isreal(::Type{Trivial}) = true Base.isless(::Trivial, ::Trivial) = false diff --git a/test/newsectors.jl b/test/newsectors.jl index f9054bf..1f06f3c 100644 --- a/test/newsectors.jl +++ b/test/newsectors.jl @@ -26,7 +26,7 @@ Base.convert(::Type{NewSU2Irrep}, j::Real) = NewSU2Irrep(j) const _su2one = NewSU2Irrep(zero(HalfInt)) unit(::Type{NewSU2Irrep}) = _su2one -Base.conj(s::NewSU2Irrep) = s +dual(s::NewSU2Irrep) = s function ⊗(s1::NewSU2Irrep, s2::NewSU2Irrep) return SectorSet{NewSU2Irrep}(abs(s1.j - s2.j):(s1.j + s2.j)) end From 700cb1c8d744748f3106ebfce8b66a6dc7bb7727 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 16:19:32 +0200 Subject: [PATCH 25/49] replacing more `conj` with `dual` + docstring changes --- src/sectors.jl | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/sectors.jl b/src/sectors.jl index 25237aa..8a62c6d 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -6,7 +6,7 @@ and pivotal) (pre-)fusion categories, e.g. the irreducible representations of a compact group. Subtypes `I<:Sector` as the set of labels of a `GradedSpace`. Every new `I<:Sector` should implement the following methods: -* `unit(::Type{I})`: unit element of `I` #TODO: change to allunits +* `allunits(::Type{I})`: collection of unit elements of `I` * `dual(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) @@ -85,6 +85,14 @@ function findindex(v::SectorValues{I}, c::I) where {I <: Sector} throw(ArgumentError(lazy"Cannot locate sector $c")) end + +""" + allunits(I::Type{<:Sector}) -> Tuple{I} + +Return a tuple with all units of the sector type `I`. +For fusion categories, this will contain only one element. +""" + """ unit(::Sector) -> Sector unit(::Type{<:Sector}) -> Sector @@ -114,13 +122,6 @@ See also [`leftunit`](@ref) and [`unit`](@ref). """ rightunit(a::Sector) = unit(a) -""" - allunits(I::Type{<:Sector}) -> Tuple{I} - -Return a tuple with all units of the sector type `I`. -For fusion categories, this will contain only one element. -""" - """ dual(a::Sector) -> Sector @@ -289,9 +290,9 @@ function dim(a::Sector) return if FusionStyle(a) isa UniqueFusion 1 elseif FusionStyle(a) isa SimpleFusion - abs(1 / Fsymbol(a, conj(a), a, a, leftunit(a), rightunit(a))) + abs(1 / Fsymbol(a, dual(a), a, a, leftunit(a), rightunit(a))) else - abs(1 / Fsymbol(a, conj(a), a, a, leftunit(a), rightunit(a))[1]) + abs(1 / Fsymbol(a, dual(a), a, a, leftunit(a), rightunit(a))[1]) end end sqrtdim(a::Sector) = (FusionStyle(a) isa UniqueFusion) ? 1 : sqrt(dim(a)) @@ -304,9 +305,9 @@ Return the Frobenius-Schur indicator of a sector `a`. """ function frobeniusschur(a::Sector) return if FusionStyle(a) isa UniqueFusion || FusionStyle(a) isa SimpleFusion - sign(Fsymbol(a, conj(a), a, a, leftunit(a), rightunit(a))) + sign(Fsymbol(a, dual(a), a, a, leftunit(a), rightunit(a))) else - sign(Fsymbol(a, conj(a), a, a, leftunit(a), rightunit(a))[1]) + sign(Fsymbol(a, dual(a), a, a, leftunit(a), rightunit(a))[1]) end end @@ -314,11 +315,11 @@ end function Asymbol(a::I, b::I, c::I) where {I <: Sector} return if FusionStyle(I) isa UniqueFusion || FusionStyle(I) isa SimpleFusion (sqrtdim(a) * sqrtdim(b) * invsqrtdim(c)) * - conj(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftunit(a), c)) + dual(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftunit(a), c)) else reshape( (sqrtdim(a) * sqrtdim(b) * invsqrtdim(c)) * - conj(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftunit(a), c)), + dual(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftunit(a), c)), (Nsymbol(a, b, c), Nsymbol(dual(a), c, b)) ) end @@ -555,7 +556,7 @@ function Rsymbol( end unit(::Type{TimeReversed{I}}) where {I <: Sector} = TimeReversed{I}(unit(I)) -dual(c::TimeReversed{I}) where {I <: Sector} = TimeReversed{I}(conj(c.a)) +dual(c::TimeReversed{I}) where {I <: Sector} = TimeReversed{I}(dual(c.a)) function ⊗(c1::TimeReversed{I}, c2::TimeReversed{I}) where {I <: Sector} return Iterators.map(TimeReversed{I}, c1.a ⊗ c2.a) end From 182cb70fbeaa0bb493f4b431205d3f9ed61e72a7 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 16:24:24 +0200 Subject: [PATCH 26/49] minor docstring fix --- src/anyons.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/anyons.jl b/src/anyons.jl index b556f50..df54be2 100644 --- a/src/anyons.jl +++ b/src/anyons.jl @@ -44,7 +44,7 @@ corresponding to the trivial sector `FibonacciAnyon(:I)` and the non-trivial sec `FibonacciAnyon(:τ)` with fusion rules ``τ ⊗ τ = 1 ⊕ τ``. ## Fields -- `isone::Bool`: indicates whether the sector corresponds the to trivial anyon `:I` +- `isone::Bool`: indicates whether the sector corresponds to the trivial anyon `:I` (`true`), or the non-trivial anyon `:τ` (`false`). """ struct FibonacciAnyon <: Sector From 4ac10735130ce355a4652dc1fb82ea97419011a5 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 16:24:57 +0200 Subject: [PATCH 27/49] more one to unit changes --- src/multifusion.jl | 2 +- src/product.jl | 2 +- test/multifusion.jl | 8 ++++---- test/sectors.jl | 8 ++++---- test/testsetup.jl | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/multifusion.jl b/src/multifusion.jl index 0eda78a..15f39e4 100644 --- a/src/multifusion.jl +++ b/src/multifusion.jl @@ -88,7 +88,7 @@ end Base.isone(a::IsingBimodule) = leftunit(a) == a == rightunit(a) function unit(::Type{IsingBimodule}) - throw(ArgumentError("one of Type IsingBimodule doesn't exist")) + throw(ArgumentError("unit of Type IsingBimodule doesn't exist")) end allunits(::Type{IsingBimodule}) = (IsingBimodule(1, 1, 0), IsingBimodule(2, 2, 0)) diff --git a/src/product.jl b/src/product.jl index 291d57c..579d9b3 100644 --- a/src/product.jl +++ b/src/product.jl @@ -62,7 +62,7 @@ end function unit(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} reduce(&, map(UnitStyle, _sectors(T))) == GenericUnit() && - throw(DomainError(ProductSector{T}, "ProductSector $T has multiple units, use `allunits` instead of `one`")) + throw(DomainError(ProductSector{T}, "ProductSector $T has multiple units, use `allunits` instead of `unit`")) return only(allunits(ProductSector{T})) end diff --git a/test/multifusion.jl b/test/multifusion.jl index ac3e35e..5b78a88 100644 --- a/test/multifusion.jl +++ b/test/multifusion.jl @@ -50,7 +50,7 @@ Istr = TensorKitSectors.type_repr(I) @testset "$Istr: Value iterator" begin @test eltype(values(I)) == I - @test_throws ArgumentError one(I) + @test_throws ArgumentError unit(I) sprev = C0 # first in SectorValues for (i, s) in enumerate(values(I)) @test !isless(s, sprev) # confirm compatibility with sort order @@ -71,8 +71,8 @@ Istr = TensorKitSectors.type_repr(I) @test eval(Meta.parse(sprint(show, M))) == M @test eval(Meta.parse(sprint(show, Mop))) == Mop @test eval(Meta.parse(sprint(show, D))) == D - @test_throws DomainError one(M) - @test_throws DomainError one(Mop) + @test_throws DomainError unit(M) + @test_throws DomainError unit(Mop) end @testset "$Istr Fusion rules and F-symbols" begin @@ -88,7 +88,7 @@ Istr = TensorKitSectors.type_repr(I) @test !isempty(⊗(obs...)) end - @test Nsymbol(C, C, one(C)) == Nsymbol(D, D, one(D)) == 1 + @test Nsymbol(C, C, unit(C)) == Nsymbol(D, D, unit(D)) == 1 @test Nsymbol(C, M, M) == Nsymbol(Mop, C, Mop) == 1 @test Nsymbol(M, D, M) == Nsymbol(D, Mop, Mop) == 1 diff --git a/test/sectors.jl b/test/sectors.jl index 66d2f68..9bcd195 100644 --- a/test/sectors.jl +++ b/test/sectors.jl @@ -5,7 +5,7 @@ Istr = TKS.type_repr(I) @test eval(Meta.parse(TKS.type_repr(I))) == I @test eval(Meta.parse(sprint(show, s[1]))) == s[1] @test @constinferred(hash(s[1])) == hash(deepcopy(s[1])) - @test @constinferred(one(s[1])) == @constinferred(one(I)) + @test @constinferred(unit(s[1])) == @constinferred(unit(I)) @constinferred dual(s[1]) @constinferred dim(s[1]) @constinferred frobeniusschur(s[1]) @@ -31,7 +31,7 @@ Istr = TKS.type_repr(I) end @testset "Sector $Istr: Value iterator" begin @test eltype(values(I)) == I - sprev = one(I) + sprev = unit(I) for (i, s) in enumerate(values(I)) @test !isless(s, sprev) # confirm compatibility with sort order @test s == @constinferred (values(I)[i]) @@ -39,9 +39,9 @@ end sprev = s i >= 10 && break end - @test one(I) == first(values(I)) + @test unit(I) == first(values(I)) @test length(allunits(I)) == 1 - @test (@constinferred findindex(values(I), one(I))) == 1 + @test (@constinferred findindex(values(I), unit(I))) == 1 for s in smallset(I) @test (@constinferred values(I)[findindex(values(I), s)]) == s end diff --git a/test/testsetup.jl b/test/testsetup.jl index fdfa845..3ae76ca 100644 --- a/test/testsetup.jl +++ b/test/testsetup.jl @@ -25,14 +25,14 @@ end function randsector(::Type{I}) where {I <: Sector} s = collect(smallset(I)) a = rand(s) - while a == one(a) # don't use trivial label + while a == unit(a) # don't use trivial label a = rand(s) end return a end function hasfusiontensor(I::Type{<:Sector}) try - fusiontensor(one(I), one(I), one(I)) + fusiontensor(unit(I), unit(I), unit(I)) return true catch e if e isa MethodError From 0658c5fa1a77f60945aade6b2d147a8edc0762a8 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 16:40:33 +0200 Subject: [PATCH 28/49] fix `allunits` of product sector to be type stable and return set --- src/product.jl | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/product.jl b/src/product.jl index 579d9b3..3986397 100644 --- a/src/product.jl +++ b/src/product.jl @@ -67,12 +67,8 @@ function unit(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg return only(allunits(ProductSector{T})) end function allunits(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} - head, rest = Base.tuple_type_head(T), Base.tuple_type_tail(T) - if rest == Tuple{} - return allunits(head) - else - return (h ⊠ r for h in allunits(head), r in allunits(ProductSector{rest})) |> Tuple - end + iterators = map(allunits, _sectors(T)) + return SectorSet{ProductSector{T}}(Base.Iterators.product(iterators...)) end dual(p::ProductSector) = ProductSector(map(conj, p.sectors)) From 77b6a5f3cfefe83e8dcb279db8565be0f358b6cb Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 16:46:28 +0200 Subject: [PATCH 29/49] `allunits` for `NewSU2Irrep` --- test/newsectors.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/newsectors.jl b/test/newsectors.jl index 1f06f3c..ed80dd1 100644 --- a/test/newsectors.jl +++ b/test/newsectors.jl @@ -25,7 +25,7 @@ end Base.convert(::Type{NewSU2Irrep}, j::Real) = NewSU2Irrep(j) const _su2one = NewSU2Irrep(zero(HalfInt)) -unit(::Type{NewSU2Irrep}) = _su2one +allunits(::Type{NewSU2Irrep}) = (_su2one,) dual(s::NewSU2Irrep) = s function ⊗(s1::NewSU2Irrep, s2::NewSU2Irrep) return SectorSet{NewSU2Irrep}(abs(s1.j - s2.j):(s1.j + s2.j)) From 23dc373d0125a117503482e8668a1cb54ad0dcb0 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 17:03:34 +0200 Subject: [PATCH 30/49] add imports for `NewSU2Irrep` --- test/newsectors.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/newsectors.jl b/test/newsectors.jl index ed80dd1..d6760cc 100644 --- a/test/newsectors.jl +++ b/test/newsectors.jl @@ -13,7 +13,7 @@ using WignerSymbols using TensorKitSectors import TensorKitSectors: FusionStyle, BraidingStyle, Nsymbol, Fsymbol, Rsymbol, dim, - fusiontensor, ⊗ + fusiontensor, ⊗, allunits, dual struct NewSU2Irrep <: Sector j::HalfInt From 78a888cfd8fa612968834413abfdb452e74d7c49 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 17:10:57 +0200 Subject: [PATCH 31/49] `allunits` for `TimeReversed` --- src/sectors.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sectors.jl b/src/sectors.jl index 8a62c6d..2096d0a 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -555,7 +555,7 @@ function Rsymbol( return adjoint(Rsymbol(a.a, b.a, c.a)) end -unit(::Type{TimeReversed{I}}) where {I <: Sector} = TimeReversed{I}(unit(I)) +allunits(::Type{TimeReversed{I}}) where {I <: Sector} = (TimeReversed{I}(u) for u in allunits(I)) dual(c::TimeReversed{I}) where {I <: Sector} = TimeReversed{I}(dual(c.a)) function ⊗(c1::TimeReversed{I}, c2::TimeReversed{I}) where {I <: Sector} return Iterators.map(TimeReversed{I}, c1.a ⊗ c2.a) From c6bcf9818ca8f7d22b8f2006e0df60c51c3da840 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 16 Sep 2025 17:21:20 +0200 Subject: [PATCH 32/49] remove some specific `unit`s I missed --- src/anyons.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/anyons.jl b/src/anyons.jl index df54be2..4267239 100644 --- a/src/anyons.jl +++ b/src/anyons.jl @@ -21,7 +21,6 @@ end findindex(::SectorValues{PlanarTrivial}, c::PlanarTrivial) = 1 Base.isless(::PlanarTrivial, ::PlanarTrivial) = false -unit(::Type{PlanarTrivial}) = PlanarTrivial() allunits(::Type{PlanarTrivial}) = (PlanarTrivial(),) dual(::PlanarTrivial) = PlanarTrivial() @@ -72,7 +71,6 @@ end findindex(::SectorValues{FibonacciAnyon}, s::FibonacciAnyon) = 2 - s.isone Base.convert(::Type{FibonacciAnyon}, s::Symbol) = FibonacciAnyon(s) -unit(::Type{FibonacciAnyon}) = FibonacciAnyon(:I) allunits(::Type{FibonacciAnyon}) = (FibonacciAnyon(:I),) dual(s::FibonacciAnyon) = s From 2401c7ff3f6882adef7f902dbd1e30d24834bddb Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 22 Sep 2025 14:16:52 +0200 Subject: [PATCH 33/49] apply code suggestions --- src/product.jl | 6 +++--- src/sectors.jl | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/product.jl b/src/product.jl index 3986397..13147eb 100644 --- a/src/product.jl +++ b/src/product.jl @@ -61,7 +61,7 @@ function Base.convert(::Type{ProductSector{T}}, t::Tuple) where {T <: SectorTupl end function unit(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} - reduce(&, map(UnitStyle, _sectors(T))) == GenericUnit() && + any(c -> UnitStyle(c) == GenericUnit(), _sectors(T)) && throw(DomainError(ProductSector{T}, "ProductSector $T has multiple units, use `allunits` instead of `unit`")) return only(allunits(ProductSector{T})) @@ -71,7 +71,7 @@ function allunits(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Va return SectorSet{ProductSector{T}}(Base.Iterators.product(iterators...)) end -dual(p::ProductSector) = ProductSector(map(conj, p.sectors)) +dual(p::ProductSector) = ProductSector(map(dual, p.sectors)) function ⊗(p1::P, p2::P) where {P <: ProductSector} if FusionStyle(P) isa UniqueFusion (P(first(product(map(⊗, p1.sectors, p2.sectors)...))),) @@ -210,7 +210,7 @@ function FusionStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} return Base.:&(map(FusionStyle, _sectors(T))...) end function UnitStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} - return Base.:&(map(UnitStyle, _sectors(T))...) + return mapreduce(UnitStyle, &, _sectors(T)) end function BraidingStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} return Base.:&(map(BraidingStyle, _sectors(T))...) diff --git a/src/sectors.jl b/src/sectors.jl index 2096d0a..e72e205 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -315,11 +315,11 @@ end function Asymbol(a::I, b::I, c::I) where {I <: Sector} return if FusionStyle(I) isa UniqueFusion || FusionStyle(I) isa SimpleFusion (sqrtdim(a) * sqrtdim(b) * invsqrtdim(c)) * - dual(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftunit(a), c)) + conj(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftunit(a), c)) else reshape( (sqrtdim(a) * sqrtdim(b) * invsqrtdim(c)) * - dual(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftunit(a), c)), + conj(frobeniusschur(a) * Fsymbol(dual(a), a, b, b, leftunit(a), c)), (Nsymbol(a, b, c), Nsymbol(dual(a), c, b)) ) end From a69806f7bfcda1841b04571623ff27fe03f75af3 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 22 Sep 2025 14:49:46 +0200 Subject: [PATCH 34/49] reverse roles of `unit` and `allunits` to make `unit` the entry point of a sector --- src/anyons.jl | 6 +++--- src/fermions.jl | 2 +- src/groupelements.jl | 3 +-- src/irreps/cu1irrep.jl | 2 +- src/irreps/dnirrep.jl | 2 +- src/irreps/su2irrep.jl | 2 +- src/irreps/u1irrep.jl | 2 +- src/irreps/znirrep.jl | 2 +- src/sectors.jl | 8 +++++--- src/trivial.jl | 2 +- test/newsectors.jl | 4 ++-- 11 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/anyons.jl b/src/anyons.jl index 4267239..b723947 100644 --- a/src/anyons.jl +++ b/src/anyons.jl @@ -21,7 +21,7 @@ end findindex(::SectorValues{PlanarTrivial}, c::PlanarTrivial) = 1 Base.isless(::PlanarTrivial, ::PlanarTrivial) = false -allunits(::Type{PlanarTrivial}) = (PlanarTrivial(),) +unit(::Type{PlanarTrivial}) = PlanarTrivial() dual(::PlanarTrivial) = PlanarTrivial() FusionStyle(::Type{PlanarTrivial}) = UniqueFusion() @@ -71,7 +71,7 @@ end findindex(::SectorValues{FibonacciAnyon}, s::FibonacciAnyon) = 2 - s.isone Base.convert(::Type{FibonacciAnyon}, s::Symbol) = FibonacciAnyon(s) -allunits(::Type{FibonacciAnyon}) = (FibonacciAnyon(:I),) +unit(::Type{FibonacciAnyon}) = FibonacciAnyon(:I) dual(s::FibonacciAnyon) = s const _goldenratio = Float64(MathConstants.golden) @@ -191,7 +191,7 @@ function findindex(::SectorValues{IsingAnyon}, a::IsingAnyon) end Base.convert(::Type{IsingAnyon}, s::Symbol) = IsingAnyon(s) -allunits(::Type{IsingAnyon}) = (IsingAnyon(:I),) +unit(::Type{IsingAnyon}) = IsingAnyon(:I) dual(s::IsingAnyon) = s dim(a::IsingAnyon) = a.s == :σ ? sqrt(2) : 1.0 diff --git a/src/fermions.jl b/src/fermions.jl index 24d0d7f..590000f 100644 --- a/src/fermions.jl +++ b/src/fermions.jl @@ -28,7 +28,7 @@ function Base.getindex(::SectorValues{FermionParity}, i::Int) end findindex(::SectorValues{FermionParity}, f::FermionParity) = f.isodd ? 2 : 1 -allunits(::Type{FermionParity}) = (FermionParity(false),) +unit(::Type{FermionParity}) = FermionParity(false) dual(f::FermionParity) = f dim(f::FermionParity) = 1 diff --git a/src/groupelements.jl b/src/groupelements.jl index 98b6bbf..be4a3f5 100644 --- a/src/groupelements.jl +++ b/src/groupelements.jl @@ -34,7 +34,6 @@ BraidingStyle(::Type{<:AbstractGroupElement}) = NoBraiding() cocycle(a::I, b::I, c::I) where {I <: AbstractGroupElement} = 1 ⊗(a::I, b::I) where {I <: AbstractGroupElement} = (a * b,) -allunits(a::Type{<:AbstractGroupElement}) = (unit(a),) dual(a::AbstractGroupElement) = inv(a) Nsymbol(a::I, b::I, c::I) where {I <: AbstractGroupElement} = c == a * b function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: AbstractGroupElement} @@ -124,7 +123,7 @@ const Z2Element{p} = ZNElement{2, p} const Z3Element{p} = ZNElement{3, p} const Z4Element{p} = ZNElement{4, p} -allunits(::Type{Z}) where {Z <: ZNElement} = (Z(0),) +unit(::Type{Z}) where {Z <: ZNElement} = Z(0) Base.inv(c::ZNElement) = typeof(c)(-c.n) Base.:*(c1::ZNElement{N, p}, c2::ZNElement{N, p}) where {N, p} = ZNElement{N, p}(mod(c1.n + c2.n, N)) diff --git a/src/irreps/cu1irrep.jl b/src/irreps/cu1irrep.jl index 7fc2277..43ba0ff 100644 --- a/src/irreps/cu1irrep.jl +++ b/src/irreps/cu1irrep.jl @@ -66,7 +66,7 @@ end Base.convert(::Type{CU1Irrep}, j::Real) = CU1Irrep(j) Base.convert(::Type{CU1Irrep}, js::Tuple{Real, Int}) = CU1Irrep(js...) -allunits(::Type{CU1Irrep}) = (CU1Irrep(zero(HalfInt), 0),) +unit(::Type{CU1Irrep}) = CU1Irrep(zero(HalfInt), 0) dual(c::CU1Irrep) = c struct CU1ProdIterator diff --git a/src/irreps/dnirrep.jl b/src/irreps/dnirrep.jl index 8cb7d4d..bd1329f 100644 --- a/src/irreps/dnirrep.jl +++ b/src/irreps/dnirrep.jl @@ -47,7 +47,7 @@ FusionStyle(::Type{DNIrrep{N}}) where {N} = N < 3 ? UniqueFusion() : SimpleFusio sectorscalartype(::Type{DNIrrep{N}}) where {N} = Float64 Base.isreal(::Type{DNIrrep{N}}) where {N} = true -allunits(::Type{DNIrrep{N}}) where {N} = (DNIrrep{N}(0, false),) +unit(::Type{DNIrrep{N}}) where {N} = DNIrrep{N}(0, false) dual(a::DNIrrep) = a Base.hash(a::DNIrrep, h::UInt) = hash(a.data, h) diff --git a/src/irreps/su2irrep.jl b/src/irreps/su2irrep.jl index 457eba9..73e8dc7 100644 --- a/src/irreps/su2irrep.jl +++ b/src/irreps/su2irrep.jl @@ -30,7 +30,7 @@ Base.getindex(::IrrepTable, ::Type{SU₂}) = SU2Irrep Base.convert(::Type{SU2Irrep}, j::Real) = SU2Irrep(j) const _su2one = SU2Irrep(zero(HalfInt)) -allunits(::Type{SU2Irrep}) = (_su2one,) +unit(::Type{SU2Irrep}) = _su2one dual(s::SU2Irrep) = s ⊗(s1::SU2Irrep, s2::SU2Irrep) = SectorSet{SU2Irrep}(abs(s1.j - s2.j):(s1.j + s2.j)) diff --git a/src/irreps/u1irrep.jl b/src/irreps/u1irrep.jl index 78a7d2f..dc4abb9 100644 --- a/src/irreps/u1irrep.jl +++ b/src/irreps/u1irrep.jl @@ -19,7 +19,7 @@ end Base.getindex(::IrrepTable, ::Type{U₁}) = U1Irrep Base.convert(::Type{U1Irrep}, c::Real) = U1Irrep(c) -allunits(::Type{U1Irrep}) = (U1Irrep(0),) +unit(::Type{U1Irrep}) = U1Irrep(0) dual(c::U1Irrep) = U1Irrep(-c.charge) ⊗(c1::U1Irrep, c2::U1Irrep) = (U1Irrep(c1.charge + c2.charge),) diff --git a/src/irreps/znirrep.jl b/src/irreps/znirrep.jl index 9569243..1bcf688 100644 --- a/src/irreps/znirrep.jl +++ b/src/irreps/znirrep.jl @@ -25,7 +25,7 @@ const Z2Irrep = ZNIrrep{2} const Z3Irrep = ZNIrrep{3} const Z4Irrep = ZNIrrep{4} -allunits(::Type{ZNIrrep{N}}) where {N} = (ZNIrrep{N}(0),) +unit(::Type{ZNIrrep{N}}) where {N} = ZNIrrep{N}(0) dual(c::ZNIrrep{N}) where {N} = ZNIrrep{N}(-c.n) ⊗(c1::ZNIrrep{N}, c2::ZNIrrep{N}) where {N} = (ZNIrrep{N}(c1.n + c2.n),) diff --git a/src/sectors.jl b/src/sectors.jl index e72e205..f9d8366 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -6,7 +6,8 @@ and pivotal) (pre-)fusion categories, e.g. the irreducible representations of a compact group. Subtypes `I<:Sector` as the set of labels of a `GradedSpace`. Every new `I<:Sector` should implement the following methods: -* `allunits(::Type{I})`: collection of unit elements of `I` +* `unit(::Type{I})`: unit element of `I`. If there are multiple, implement `allunits(::Type{I})` + instead. * `dual(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) @@ -92,6 +93,7 @@ end Return a tuple with all units of the sector type `I`. For fusion categories, this will contain only one element. """ +allunits(::Type{I}) where {I <: Sector} = (unit(I),) """ unit(::Sector) -> Sector @@ -99,8 +101,7 @@ For fusion categories, this will contain only one element. Return the unit element within this type of sector. """ -unit(a::Sector) = only(allunits(typeof(a))) -unit(::Type{I}) where {I <: Sector} = only(allunits(I)) +unit(a::Sector) = unit(typeof(a)) Base.one(a::Sector) = unit(a) Base.one(::Type{I}) where {I <: Sector} = unit(I) @@ -555,6 +556,7 @@ function Rsymbol( return adjoint(Rsymbol(a.a, b.a, c.a)) end +unit(::Type{TimeReversed{I}}) where {I <: Sector} = TimeReversed{I}(unit(I)) allunits(::Type{TimeReversed{I}}) where {I <: Sector} = (TimeReversed{I}(u) for u in allunits(I)) dual(c::TimeReversed{I}) where {I <: Sector} = TimeReversed{I}(dual(c.a)) function ⊗(c1::TimeReversed{I}, c2::TimeReversed{I}) where {I <: Sector} diff --git a/src/trivial.jl b/src/trivial.jl index 020418e..ff79373 100644 --- a/src/trivial.jl +++ b/src/trivial.jl @@ -19,7 +19,7 @@ end findindex(::SectorValues{Trivial}, c::Trivial) = 1 # basic properties -allunits(::Type{Trivial}) = (Trivial(),) +unit(::Type{Trivial}) = Trivial() dual(::Trivial) = Trivial() Base.isreal(::Type{Trivial}) = true diff --git a/test/newsectors.jl b/test/newsectors.jl index d6760cc..6381627 100644 --- a/test/newsectors.jl +++ b/test/newsectors.jl @@ -13,7 +13,7 @@ using WignerSymbols using TensorKitSectors import TensorKitSectors: FusionStyle, BraidingStyle, Nsymbol, Fsymbol, Rsymbol, dim, - fusiontensor, ⊗, allunits, dual + fusiontensor, ⊗, unit, dual struct NewSU2Irrep <: Sector j::HalfInt @@ -25,7 +25,7 @@ end Base.convert(::Type{NewSU2Irrep}, j::Real) = NewSU2Irrep(j) const _su2one = NewSU2Irrep(zero(HalfInt)) -allunits(::Type{NewSU2Irrep}) = (_su2one,) +unit(::Type{NewSU2Irrep}) = _su2one dual(s::NewSU2Irrep) = s function ⊗(s1::NewSU2Irrep, s2::NewSU2Irrep) return SectorSet{NewSU2Irrep}(abs(s1.j - s2.j):(s1.j + s2.j)) From f00d2c82a4a284772306650b3185515ce7b91195 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 22 Sep 2025 15:39:08 +0200 Subject: [PATCH 35/49] more `mapreduce`s --- src/product.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/product.jl b/src/product.jl index 13147eb..4728e21 100644 --- a/src/product.jl +++ b/src/product.jl @@ -207,13 +207,13 @@ function fusiontensor(a::P, b::P, c::P) where {P <: ProductSector{<:Tuple{Sector end function FusionStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} - return Base.:&(map(FusionStyle, _sectors(T))...) + return mapreduce(FusionStyle, &, _sectors(T)) end function UnitStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} return mapreduce(UnitStyle, &, _sectors(T)) end function BraidingStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} - return Base.:&(map(BraidingStyle, _sectors(T))...) + return mapreduce(BraidingStyle, &, _sectors(T)) end Base.isreal(::Type{<:ProductSector{T}}) where {T <: SectorTuple} = _isreal(T) _isreal(::Type{Tuple{}}) = true From 35ae0d4cf72e9b8f378baf6a54136de7c7740671 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 22 Sep 2025 15:46:27 +0200 Subject: [PATCH 36/49] another `mapreduce` + format --- src/product.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/product.jl b/src/product.jl index 4728e21..bb0184c 100644 --- a/src/product.jl +++ b/src/product.jl @@ -213,9 +213,11 @@ function UnitStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} return mapreduce(UnitStyle, &, _sectors(T)) end function BraidingStyle(::Type{<:ProductSector{T}}) where {T <: SectorTuple} - return mapreduce(BraidingStyle, &, _sectors(T)) + return mapreduce(BraidingStyle, &, _sectors(T)) +end +function Base.isreal(::Type{<:ProductSector{T}}) where {T <: SectorTuple} + return mapreduce(isreal, &, _sectors(T)) end -Base.isreal(::Type{<:ProductSector{T}}) where {T <: SectorTuple} = _isreal(T) _isreal(::Type{Tuple{}}) = true function _isreal(T::Type{<:SectorTuple}) return isreal(Base.tuple_type_head(T)) && _isreal(Base.tuple_type_tail(T)) From 2ced6ff1e5dfd4c98762182819e5d25ef4f13eb7 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 22 Sep 2025 15:49:43 +0200 Subject: [PATCH 37/49] use `SectorSet` for time reversed `allunits` --- src/sectors.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sectors.jl b/src/sectors.jl index f9d8366..3aa91ee 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -557,7 +557,7 @@ function Rsymbol( end unit(::Type{TimeReversed{I}}) where {I <: Sector} = TimeReversed{I}(unit(I)) -allunits(::Type{TimeReversed{I}}) where {I <: Sector} = (TimeReversed{I}(u) for u in allunits(I)) +allunits(::Type{TimeReversed{I}}) where {I <: Sector} = SectorSet{TimeReversed{I}}(TimeReversed{I}, allunits(I)) dual(c::TimeReversed{I}) where {I <: Sector} = TimeReversed{I}(dual(c.a)) function ⊗(c1::TimeReversed{I}, c2::TimeReversed{I}) where {I <: Sector} return Iterators.map(TimeReversed{I}, c1.a ⊗ c2.a) From 7dd58d8e876ba14c4ae0dc1f875a026ddbf467a7 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Mon, 22 Sep 2025 16:17:59 +0200 Subject: [PATCH 38/49] remove `_isreal` code --- src/product.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/product.jl b/src/product.jl index bb0184c..29c0e44 100644 --- a/src/product.jl +++ b/src/product.jl @@ -218,10 +218,6 @@ end function Base.isreal(::Type{<:ProductSector{T}}) where {T <: SectorTuple} return mapreduce(isreal, &, _sectors(T)) end -_isreal(::Type{Tuple{}}) = true -function _isreal(T::Type{<:SectorTuple}) - return isreal(Base.tuple_type_head(T)) && _isreal(Base.tuple_type_tail(T)) -end fermionparity(P::ProductSector) = mapreduce(fermionparity, xor, P.sectors) From 3fd2d0cf0f385404916d85f89b31162e95f40454 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 23 Sep 2025 13:58:25 +0200 Subject: [PATCH 39/49] derive `unit` from `one` for `GroupElement` --- src/groupelements.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/groupelements.jl b/src/groupelements.jl index be4a3f5..91a9b1f 100644 --- a/src/groupelements.jl +++ b/src/groupelements.jl @@ -18,7 +18,7 @@ For the fusion structure, a specific `SomeGroupElement<:AbstractGroupElement{Som should only implement the following methods ```julia Base.:*(c1::GroupElement, c2::GroupElement) -> GroupElement -unit(::Type{GroupElement}) -> GroupElement +Base.one(::Type{GroupElement}) -> GroupElement Base.inv(c::GroupElement) -> GroupElement # and optionally TensorKitSectors.cocycle(c1::GroupElement, c2::GroupElement, c3::GroupElement) -> Number @@ -123,7 +123,8 @@ const Z2Element{p} = ZNElement{2, p} const Z3Element{p} = ZNElement{3, p} const Z4Element{p} = ZNElement{4, p} -unit(::Type{Z}) where {Z <: ZNElement} = Z(0) +unit(::Type{Z}) where {Z <: ZNElement} = one(Z) +Base.one(::Type{Z}) where {Z <: ZNElement} = Z(0) Base.inv(c::ZNElement) = typeof(c)(-c.n) Base.:*(c1::ZNElement{N, p}, c2::ZNElement{N, p}) where {N, p} = ZNElement{N, p}(mod(c1.n + c2.n, N)) From c5fa94abd45f711bb615bc9d0edf15896ac496f2 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 23 Sep 2025 13:59:39 +0200 Subject: [PATCH 40/49] avoid string interpolations in error messages --- src/multifusion.jl | 2 +- src/product.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/multifusion.jl b/src/multifusion.jl index 15f39e4..e4ed7ee 100644 --- a/src/multifusion.jl +++ b/src/multifusion.jl @@ -81,7 +81,7 @@ leftunit(a::IsingBimodule) = IsingBimodule(a.row, a.row, 0) function unit(a::IsingBimodule) a.row == a.col || - throw(DomainError(a, "unit of module category ($(a.row), $(a.col)) doesn't exist")) + throw(DomainError(a, "unit of a module category is not defined")) return IsingBimodule(a.row, a.col, 0) end diff --git a/src/product.jl b/src/product.jl index 29c0e44..9e5fa01 100644 --- a/src/product.jl +++ b/src/product.jl @@ -62,7 +62,7 @@ end function unit(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} any(c -> UnitStyle(c) == GenericUnit(), _sectors(T)) && - throw(DomainError(ProductSector{T}, "ProductSector $T has multiple units, use `allunits` instead of `unit`")) + throw(DomainError(ProductSector{T}, "ProductSector has multiple units, use `allunits` instead of `unit`")) return only(allunits(ProductSector{T})) end From 6eb8d8a45de43eee80fa66464516a40e36aa4760 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 23 Sep 2025 14:58:32 +0200 Subject: [PATCH 41/49] reduce specification --- src/product.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/product.jl b/src/product.jl index 9e5fa01..7c5db92 100644 --- a/src/product.jl +++ b/src/product.jl @@ -66,7 +66,7 @@ function unit(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg return only(allunits(ProductSector{T})) end -function allunits(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} +function allunits(::Type{ProductSector{T}}) where {T} iterators = map(allunits, _sectors(T)) return SectorSet{ProductSector{T}}(Base.Iterators.product(iterators...)) end From 6fb637a94412a22aa4ce5a4130b984070cd54eef Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 23 Sep 2025 15:03:51 +0200 Subject: [PATCH 42/49] make otimes output of time reversed a `SectorSet` --- src/sectors.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sectors.jl b/src/sectors.jl index 3aa91ee..038dfcf 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -560,7 +560,7 @@ unit(::Type{TimeReversed{I}}) where {I <: Sector} = TimeReversed{I}(unit(I)) allunits(::Type{TimeReversed{I}}) where {I <: Sector} = SectorSet{TimeReversed{I}}(TimeReversed{I}, allunits(I)) dual(c::TimeReversed{I}) where {I <: Sector} = TimeReversed{I}(dual(c.a)) function ⊗(c1::TimeReversed{I}, c2::TimeReversed{I}) where {I <: Sector} - return Iterators.map(TimeReversed{I}, c1.a ⊗ c2.a) + return SectorSet{TimeReversed{I}}(TimeReversed{I}, c1.a ⊗ c2.a) end function Base.IteratorSize(::Type{SectorValues{TimeReversed{I}}}) where {I <: Sector} return Base.IteratorSize(values(I)) From 2326b67d3bd6d00a55d84fc28a873381cc046786 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 23 Sep 2025 15:16:26 +0200 Subject: [PATCH 43/49] introduce `isunit` and change `isone` to `isunit` where relevant --- src/TensorKitSectors.jl | 2 +- src/anyons.jl | 12 ++++++------ src/irreps/dnirrep.jl | 2 +- src/multifusion.jl | 2 -- src/sectors.jl | 14 +++++++++++++- test/multifusion.jl | 6 +++--- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/TensorKitSectors.jl b/src/TensorKitSectors.jl index 0ebe216..47ba9ba 100644 --- a/src/TensorKitSectors.jl +++ b/src/TensorKitSectors.jl @@ -14,7 +14,7 @@ export FusionStyle, UniqueFusion, MultipleFusion, SimpleFusion, GenericFusion, export UnitStyle, SimpleUnit, GenericUnit export BraidingStyle, NoBraiding, HasBraiding, SymmetricBraiding, Bosonic, Fermionic, Anyonic export SectorSet, SectorValues, findindex -export unit, rightunit, leftunit, allunits +export unit, rightunit, leftunit, allunits, isunit export triangle_equation, pentagon_equation, hexagon_equation diff --git a/src/anyons.jl b/src/anyons.jl index b723947..9805de1 100644 --- a/src/anyons.jl +++ b/src/anyons.jl @@ -75,7 +75,7 @@ unit(::Type{FibonacciAnyon}) = FibonacciAnyon(:I) dual(s::FibonacciAnyon) = s const _goldenratio = Float64(MathConstants.golden) -dim(a::FibonacciAnyon) = isone(a) ? one(_goldenratio) : _goldenratio +dim(a::FibonacciAnyon) = isunit(a) ? one(_goldenratio) : _goldenratio FusionStyle(::Type{FibonacciAnyon}) = SimpleFusion() BraidingStyle(::Type{FibonacciAnyon}) = Anyonic() @@ -89,7 +89,7 @@ struct FibonacciIterator end Base.IteratorSize(::Type{FibonacciIterator}) = Base.HasLength() Base.IteratorEltype(::Type{FibonacciIterator}) = Base.HasEltype() -Base.length(iter::FibonacciIterator) = (isone(iter.a) || isone(iter.b)) ? 1 : 2 +Base.length(iter::FibonacciIterator) = (isunit(iter.a) || isunit(iter.b)) ? 1 : 2 Base.eltype(::Type{FibonacciIterator}) = FibonacciAnyon function Base.iterate(iter::FibonacciIterator, state = 1) I = FibonacciAnyon(:I) @@ -107,7 +107,7 @@ function Base.iterate(iter::FibonacciIterator, state = 1) end function Nsymbol(a::FibonacciAnyon, b::FibonacciAnyon, c::FibonacciAnyon) - return isone(a) + isone(b) + isone(c) != 2 + return isunit(a) + isunit(b) + isunit(c) != 2 end # zero if one tau and two ones function Fsymbol( @@ -136,15 +136,15 @@ end function Rsymbol(a::FibonacciAnyon, b::FibonacciAnyon, c::FibonacciAnyon) Nsymbol(a, b, c) || return 0 * cispi(0 / 1) - if isone(a) || isone(b) + if isunit(a) || isunit(b) return cispi(0 / 1) else - return isone(c) ? cispi(4 / 5) : cispi(-3 / 5) + return isunit(c) ? cispi(4 / 5) : cispi(-3 / 5) end end function Base.show(io::IO, a::FibonacciAnyon) - s = isone(a) ? ":I" : ":τ" + s = isunit(a) ? ":I" : ":τ" return get(io, :typeinfo, nothing) === FibonacciAnyon ? print(io, s) : print(io, "FibonacciAnyon(", s, ")") end diff --git a/src/irreps/dnirrep.jl b/src/irreps/dnirrep.jl index bd1329f..52d9016 100644 --- a/src/irreps/dnirrep.jl +++ b/src/irreps/dnirrep.jl @@ -195,7 +195,7 @@ function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {N, I <: DNIrrep{N}} (Nsymbol(a, b, e) & Nsymbol(e, c, d) & Nsymbol(b, c, f) & Nsymbol(a, f, d)) || return zero(T) # tensoring with units gives 1 - (isone(a) || isone(b) || isone(c)) && return one(T) + (isunit(a) || isunit(b) || isunit(c)) && return one(T) # fallback through fusiontensor A = fusiontensor(a, b, e) diff --git a/src/multifusion.jl b/src/multifusion.jl index e4ed7ee..6d6b578 100644 --- a/src/multifusion.jl +++ b/src/multifusion.jl @@ -85,8 +85,6 @@ function unit(a::IsingBimodule) return IsingBimodule(a.row, a.col, 0) end -Base.isone(a::IsingBimodule) = leftunit(a) == a == rightunit(a) - function unit(::Type{IsingBimodule}) throw(ArgumentError("unit of Type IsingBimodule doesn't exist")) end diff --git a/src/sectors.jl b/src/sectors.jl index 038dfcf..14bc592 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -105,7 +105,19 @@ unit(a::Sector) = unit(typeof(a)) Base.one(a::Sector) = unit(a) Base.one(::Type{I}) where {I <: Sector} = unit(I) -#TODO: define isunit function with isone fallback? +""" + isunit(::Sector) -> Bool + +Return whether the sector is a unit element. +""" +function isunit(a::Sector) + return if UnitStyle(a) === SimpleUnit() + a == unit(a) + else + leftunit(a) == a == rightunit(a) + end +end +Base.isone(a::Sector) = isunit(a) """ leftunit(a::Sector) -> Sector diff --git a/test/multifusion.jl b/test/multifusion.jl index 5b78a88..ab3fe33 100644 --- a/test/multifusion.jl +++ b/test/multifusion.jl @@ -29,9 +29,9 @@ Istr = TensorKitSectors.type_repr(I) @test unit(C1) == leftunit(M) == rightunit(Mop) @test unit(D1) == rightunit(M) == leftunit(Mop) - @test @constinferred(isone(C0)) - @test isone(D0) - @test !isone(C1) && !isone(D1) && !isone(M) && !isone(Mop) + @test @constinferred(isunit(C0)) + @test isunit(D0) + @test !isunit(C1) && !isunit(D1) && !isunit(M) && !isunit(Mop) @test length(allunits(I)) == 2 @test allunits(I) == (C0, D0) From 83e431321cd67a5a97a8cc18917d7fc2108a1e60 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 23 Sep 2025 15:17:23 +0200 Subject: [PATCH 44/49] bump version to 0.3.0 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 0b49fc4..700d3a0 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "TensorKitSectors" uuid = "13a9c161-d5da-41f0-bcbd-e1a08ae0647f" authors = ["Lukas Devos", "Jutho Haegeman"] -version = "0.2.1" +version = "0.3.0" [deps] HalfIntegers = "f0d1745a-41c9-11e9-1dd9-e5d34d218721" From 4662db2df297b561ebac2906f28e48c0b8d525d9 Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 23 Sep 2025 15:18:11 +0200 Subject: [PATCH 45/49] one last `isunit` --- test/testsetup.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testsetup.jl b/test/testsetup.jl index 3ae76ca..a78efa5 100644 --- a/test/testsetup.jl +++ b/test/testsetup.jl @@ -25,7 +25,7 @@ end function randsector(::Type{I}) where {I <: Sector} s = collect(smallset(I)) a = rand(s) - while a == unit(a) # don't use trivial label + while isunit(a) # don't use trivial label a = rand(s) end return a From 02a8cab704e239889ed013ef52aeb7006d5bdf5a Mon Sep 17 00:00:00 2001 From: Boris De Vos Date: Tue, 23 Sep 2025 16:47:37 +0200 Subject: [PATCH 46/49] change fib field name to `isunit` --- src/anyons.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/anyons.jl b/src/anyons.jl index 9805de1..2add18e 100644 --- a/src/anyons.jl +++ b/src/anyons.jl @@ -43,11 +43,11 @@ corresponding to the trivial sector `FibonacciAnyon(:I)` and the non-trivial sec `FibonacciAnyon(:τ)` with fusion rules ``τ ⊗ τ = 1 ⊕ τ``. ## Fields -- `isone::Bool`: indicates whether the sector corresponds to the trivial anyon `:I` +- `isunit::Bool`: indicates whether the sector corresponds to the trivial anyon `:I` (`true`), or the non-trivial anyon `:τ` (`false`). """ struct FibonacciAnyon <: Sector - isone::Bool + isunit::Bool function FibonacciAnyon(s::Symbol) s in (:I, :τ, :tau) || throw(ArgumentError("Unknown FibonacciAnyon $s.")) return new(s === :I) @@ -68,7 +68,7 @@ function Base.getindex(S::SectorValues{FibonacciAnyon}, i::Int) throw(BoundsError(S, i)) end end -findindex(::SectorValues{FibonacciAnyon}, s::FibonacciAnyon) = 2 - s.isone +findindex(::SectorValues{FibonacciAnyon}, s::FibonacciAnyon) = 2 - s.isunit Base.convert(::Type{FibonacciAnyon}, s::Symbol) = FibonacciAnyon(s) unit(::Type{FibonacciAnyon}) = FibonacciAnyon(:I) @@ -149,8 +149,8 @@ function Base.show(io::IO, a::FibonacciAnyon) print(io, s) : print(io, "FibonacciAnyon(", s, ")") end -Base.hash(a::FibonacciAnyon, h::UInt) = hash(a.isone, h) -Base.isless(a::FibonacciAnyon, b::FibonacciAnyon) = isless(!a.isone, !b.isone) +Base.hash(a::FibonacciAnyon, h::UInt) = hash(a.isunit, h) +Base.isless(a::FibonacciAnyon, b::FibonacciAnyon) = isless(!a.isunit, !b.isunit) # IsingAnyons """ From 955f42f3e6508b019c0e009924ae5f8991d1fb27 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 23 Sep 2025 20:28:22 -0400 Subject: [PATCH 47/49] `unit(::Type{<:AbstractGroupElement})` --- src/groupelements.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/groupelements.jl b/src/groupelements.jl index 91a9b1f..2aa7057 100644 --- a/src/groupelements.jl +++ b/src/groupelements.jl @@ -35,6 +35,7 @@ BraidingStyle(::Type{<:AbstractGroupElement}) = NoBraiding() cocycle(a::I, b::I, c::I) where {I <: AbstractGroupElement} = 1 ⊗(a::I, b::I) where {I <: AbstractGroupElement} = (a * b,) dual(a::AbstractGroupElement) = inv(a) +unit(::Type{I}) where {I <: AbstractGroupElement} = one(I) Nsymbol(a::I, b::I, c::I) where {I <: AbstractGroupElement} = c == a * b function Fsymbol(a::I, b::I, c::I, d::I, e::I, f::I) where {I <: AbstractGroupElement} ω = cocycle(a, b, c) @@ -123,7 +124,6 @@ const Z2Element{p} = ZNElement{2, p} const Z3Element{p} = ZNElement{3, p} const Z4Element{p} = ZNElement{4, p} -unit(::Type{Z}) where {Z <: ZNElement} = one(Z) Base.one(::Type{Z}) where {Z <: ZNElement} = Z(0) Base.inv(c::ZNElement) = typeof(c)(-c.n) Base.:*(c1::ZNElement{N, p}, c2::ZNElement{N, p}) where {N, p} = From 88e50256e990d4b95a90688d2cda35cebe1638d9 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 23 Sep 2025 20:44:26 -0400 Subject: [PATCH 48/49] noinline domainerror --- src/product.jl | 8 +++----- src/sectors.jl | 4 ++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/product.jl b/src/product.jl index 7c5db92..d154db7 100644 --- a/src/product.jl +++ b/src/product.jl @@ -60,11 +60,9 @@ function Base.convert(::Type{ProductSector{T}}, t::Tuple) where {T <: SectorTupl return ProductSector{T}(convert(T, t)) end -function unit(::Type{ProductSector{T}}) where {I <: Sector, T <: Tuple{I, Vararg{Sector}}} - any(c -> UnitStyle(c) == GenericUnit(), _sectors(T)) && - throw(DomainError(ProductSector{T}, "ProductSector has multiple units, use `allunits` instead of `unit`")) - - return only(allunits(ProductSector{T})) +function unit(::Type{T}) where {T <: ProductSector} + UnitStyle(T) === GenericUnit() && throw_genericunit_error(T) + return only(allunits(T)) end function allunits(::Type{ProductSector{T}}) where {T} iterators = map(allunits, _sectors(T)) diff --git a/src/sectors.jl b/src/sectors.jl index 14bc592..cd6c80a 100644 --- a/src/sectors.jl +++ b/src/sectors.jl @@ -265,6 +265,10 @@ struct GenericUnit <: UnitStyle end UnitStyle(::Type{I}) where {I <: Sector} = length(allunits(I)) == 1 ? SimpleUnit() : GenericUnit() +@noinline function throw_genericunit_error(I) + throw(DomainError(I, "Sector has multiple units, use `allunits` instead of `unit`")) +end + # combine fusion properties of tensor products of multifusion sectors Base.:&(f::F, ::F) where {F <: UnitStyle} = f Base.:&(f₁::UnitStyle, f₂::UnitStyle) = f₂ & f₁ From 881cbe789a52e2d73cef03beed37cf1de38df0f7 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 23 Sep 2025 21:16:06 -0400 Subject: [PATCH 49/49] also update precompile --- src/precompile.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/precompile.jl b/src/precompile.jl index 37a82c4..172d3d1 100644 --- a/src/precompile.jl +++ b/src/precompile.jl @@ -22,6 +22,8 @@ function precompile_sector(::Type{I}) where {I <: Sector} precompile(sqrtdim, (I,)) precompile(invsqrtdim, (I,)) precompile(dual, (I,)) + precompile(unit, (I,)) + precompile(allunits, (I,)) precompile(twist, (I,)) precompile(frobeniusschur, (I,)) precompile(fusiontensor, (I, I, I))