Skip to content

Commit 7f98183

Browse files
committed
define TrivialSector
1 parent f3f6b96 commit 7f98183

File tree

6 files changed

+121
-37
lines changed

6 files changed

+121
-37
lines changed

NDTensors/src/lib/Sectors/src/Sectors.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ include("abstractcategory.jl")
55
include("category_definitions/fib.jl")
66
include("category_definitions/ising.jl")
77
include("category_definitions/o2.jl")
8+
include("category_definitions/trivial.jl")
89
include("category_definitions/su.jl")
910
include("category_definitions/su2k.jl")
1011
include("category_definitions/u1.jl")
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#
2+
# Trivial sector
3+
#
4+
5+
using ...GradedAxes: GradedAxes
6+
7+
# Trivial is special as it does not have a label
8+
struct TrivialSector <: AbstractCategory end
9+
10+
SymmetryStyle(::Type{TrivialSector}) = AbelianStyle()
11+
12+
trivial(::Type{TrivialSector}) = TrivialSector()
13+
14+
GradedAxes.dual(::TrivialSector) = TrivialSector()
15+
16+
Base.isless(::TrivialSector, ::TrivialSector) = false # bypass default that calls label
17+
18+
# TrivialSector acts as trivial on any AbstractCategory
19+
function fusion_rule(::NotAbelianStyle, ::TrivialSector, c::AbstractCategory)
20+
return to_gradedrange(c)
21+
end
22+
function fusion_rule(::NotAbelianStyle, c::AbstractCategory, ::TrivialSector)
23+
return to_gradedrange(c)
24+
end
25+
26+
# abelian case: return Category
27+
fusion_rule(::AbelianStyle, c::AbstractCategory, ::TrivialSector) = c
28+
fusion_rule(::AbelianStyle, ::TrivialSector, c::AbstractCategory) = c
29+
fusion_rule(::AbelianStyle, ::TrivialSector, ::TrivialSector) = TrivialSector()
30+
31+
# any trivial sector equals TrivialSector
32+
Base.:(==)(c::AbstractCategory, ::TrivialSector) = istrivial(c)
33+
Base.:(==)(::TrivialSector, c::AbstractCategory) = istrivial(c)
34+
Base.:(==)(::TrivialSector, ::TrivialSector) = true

NDTensors/src/lib/Sectors/src/category_product.jl

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ CategoryProduct(c::CategoryProduct) = _CategoryProduct(categories(c))
1515

1616
categories(s::CategoryProduct) = s.cats
1717

18-
const TrivialSector{Categories<:Union{Tuple{},NamedTuple{()}}} = CategoryProduct{Categories}
19-
TrivialSector() = CategoryProduct(())
20-
2118
# ================================= Sectors interface ====================================
2219
SymmetryStyle(T::Type{<:CategoryProduct}) = categories_symmetrystyle(categories_type(T))
2320

@@ -99,6 +96,12 @@ function categories_fusion_rule(cats1, cats2)
9996
return shared_cat × diff_cat
10097
end
10198

99+
# edge case with empty categories
100+
categories_fusion_rule(cats::Tuple, ::NamedTuple{()}) = CategoryProduct(cats)
101+
categories_fusion_rule(::NamedTuple{()}, cats::Tuple) = CategoryProduct(cats)
102+
categories_fusion_rule(cats::NamedTuple, ::Tuple{}) = CategoryProduct(cats)
103+
categories_fusion_rule(::Tuple{}, cats::NamedTuple) = CategoryProduct(cats)
104+
102105
function recover_style(T::Type, fused)
103106
style = categories_symmetrystyle(T)
104107
return recover_category_product_type(style, T, fused)
@@ -166,6 +169,14 @@ function ×(g1::AbstractUnitRange, g2::AbstractUnitRange)
166169
end
167170

168171
# ==================================== Fusion rules ======================================
172+
# cast AbstractCategory to CategoryProduct
173+
function fusion_rule(style::SymmetryStyle, c1::CategoryProduct, c2::AbstractCategory)
174+
return fusion_rule(style, c1, CategoryProduct(c2))
175+
end
176+
function fusion_rule(style::SymmetryStyle, c1::AbstractCategory, c2::CategoryProduct)
177+
return fusion_rule(style, CategoryProduct(c1), c2)
178+
end
179+
169180
# generic case: fusion returns a GradedAxes, even for fusion with Empty
170181
function fusion_rule(::NotAbelianStyle, s1::CategoryProduct, s2::CategoryProduct)
171182
return to_gradedrange(categories_fusion_rule(categories(s1), categories(s2)))
@@ -176,30 +187,11 @@ function fusion_rule(::AbelianStyle, s1::CategoryProduct, s2::CategoryProduct)
176187
return categories_fusion_rule(categories(s1), categories(s2))
177188
end
178189

179-
# Empty case
180-
function fusion_rule(::AbelianStyle, ::TrivialSector, ::TrivialSector)
181-
return CategoryProduct(())
182-
end
183-
184-
# TrivialSector acts as trivial on any AbstractCategory, not just CategoryProduct
185-
function fusion_rule(::NotAbelianStyle, ::TrivialSector, c::AbstractCategory)
186-
return to_gradedrange(c)
187-
end
188-
function fusion_rule(::NotAbelianStyle, c::AbstractCategory, ::TrivialSector)
189-
return to_gradedrange(c)
190-
end
191-
function fusion_rule(::NotAbelianStyle, ::TrivialSector, c::CategoryProduct)
192-
return to_gradedrange(c)
193-
end
194-
function fusion_rule(::NotAbelianStyle, c::CategoryProduct, ::TrivialSector)
195-
return to_gradedrange(c)
196-
end
197-
198-
# abelian case: return Category
199-
fusion_rule(::AbelianStyle, c::AbstractCategory, ::TrivialSector) = c
200-
fusion_rule(::AbelianStyle, ::TrivialSector, c::AbstractCategory) = c
190+
# lift ambiguities for TrivialSector
201191
fusion_rule(::AbelianStyle, c::CategoryProduct, ::TrivialSector) = c
202192
fusion_rule(::AbelianStyle, ::TrivialSector, c::CategoryProduct) = c
193+
fusion_rule(::NotAbelianStyle, c::CategoryProduct, ::TrivialSector) = to_gradedrange(c)
194+
fusion_rule(::NotAbelianStyle, ::TrivialSector, c::CategoryProduct) = to_gradedrange(c)
203195

204196
# =============================== Ordered implementation =================================
205197
CategoryProduct(t::Tuple) = _CategoryProduct(t)

NDTensors/src/lib/Sectors/test/test_category_product.jl

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ using NDTensors.Sectors:
77
Ising,
88
SU,
99
SU2,
10-
U1,
1110
TrivialSector,
11+
U1,
1212
Z,
1313
block_dimensions,
1414
categories,
@@ -62,6 +62,13 @@ end
6262
@test categories(s)[2] == SU2(1//2)
6363
@test categories(s)[3] == Fib("τ")
6464
@test (@inferred_latest trivial(s)) == CategoryProduct(U1(0), SU2(0), Fib("1"))
65+
66+
s = TrivialSector() × U1(3) × SU2(1 / 2)
67+
@test length(categories(s)) == 3
68+
@test (@inferred_latest quantum_dimension(s)) == 2
69+
@test dual(s) == TrivialSector() × U1(-3) × SU2(1//2)
70+
@test (@inferred_latest trivial(s)) == CategoryProduct(TrivialSector(), U1(0), SU2(0))
71+
@test s > trivial(s)
6572
end
6673

6774
@testset "Ordered comparisons" begin
@@ -70,6 +77,7 @@ end
7077
@test CategoryProduct(U1(1), SU2(0)) != CategoryProduct(U1(1), SU2(1))
7178
@test CategoryProduct(U1(0), SU2(1)) != CategoryProduct(U1(1), SU2(1))
7279
@test CategoryProduct(U1(1)) != CategoryProduct(U1(1), U1(0))
80+
@test CategoryProduct(U1(0), SU2(0)) == TrivialSector()
7381

7482
# convention: categories must have same length to be compared
7583
@test CategoryProduct(U1(0)) < CategoryProduct((U1(1)))
@@ -135,6 +143,8 @@ end
135143
@testset "Fusion of Abelian products" begin
136144
p1 = CategoryProduct(U1(1))
137145
p2 = CategoryProduct(U1(2))
146+
@test (@inferred p1 TrivialSector()) == p1
147+
@test (@inferred TrivialSector() p2) == p2
138148
@test (@inferred_latest p1 p2) == CategoryProduct(U1(3))
139149

140150
p11 = U1(1) × U1(1)
@@ -151,7 +161,12 @@ end
151161
@testset "Fusion of NonAbelian products" begin
152162
p0 = CategoryProduct(SU2(0))
153163
ph = CategoryProduct(SU2(1//2))
154-
@test space_isequal((@inferred p0 ph), gradedrange([CategoryProduct(SU2(1//2)) => 1]))
164+
@test space_isequal(
165+
(@inferred p0 TrivialSector()), gradedrange([CategoryProduct(SU2(0)) => 1])
166+
)
167+
@test space_isequal(
168+
(@inferred TrivialSector() ph), gradedrange([CategoryProduct(SU2(1//2)) => 1])
169+
)
155170

156171
phh = SU2(1//2) × SU2(1//2)
157172
@test space_isequal(
@@ -397,7 +412,7 @@ end
397412
end
398413

399414
@testset "Fusion of Abelian products" begin
400-
q00 = TrivialSector()
415+
q00 = CategoryProduct(;)
401416
q10 = CategoryProduct(; A=U1(1))
402417
q01 = CategoryProduct(; B=U1(1))
403418
q11 = CategoryProduct(; A=U1(1), B=U1(1))
@@ -418,7 +433,7 @@ end
418433
end
419434

420435
@testset "Fusion of NonAbelian products" begin
421-
p0 = TrivialSector()
436+
p0 = CategoryProduct(;)
422437
pha = CategoryProduct(; A=SU2(1//2))
423438
phb = CategoryProduct(; B=SU2(1//2))
424439
phab = CategoryProduct(; A=SU2(1//2), B=SU2(1//2))
@@ -543,6 +558,7 @@ end
543558

544559
@testset "Empty category" begin
545560
for s in (CategoryProduct(()), CategoryProduct((;)))
561+
@test s == TrivialSector()
546562
@test s == CategoryProduct(())
547563
@test s == CategoryProduct((;))
548564
@test (@inferred dual(s)) == s
@@ -561,13 +577,12 @@ end
561577
@test (@inferred CategoryProduct(U1(1)) × s) == CategoryProduct(U1(1))
562578
@test (@inferred CategoryProduct(; A=U1(1)) × s) == CategoryProduct(; A=U1(1))
563579

564-
# Empty acts as trivial
565-
@test (@inferred_latest U1(1) s) == U1(1)
566-
@test (@inferred SU2(0) s) == gradedrange([SU2(0) => 1])
567-
@test (@inferred Fib("τ") s) == gradedrange([Fib("τ") => 1])
568-
@test (@inferred_latest s U1(1)) == U1(1)
569-
@test (@inferred s SU2(0)) == gradedrange([SU2(0) => 1])
570-
@test (@inferred s Fib("τ")) == gradedrange([Fib("τ") => 1])
580+
@test (@inferred_latest U1(1) s) == CategoryProduct(U1(1))
581+
@test (@inferred SU2(0) s) == gradedrange([CategoryProduct(SU2(0)) => 1])
582+
@test (@inferred Fib("τ") s) == gradedrange([CategoryProduct(Fib("τ")) => 1])
583+
@test (@inferred_latest s U1(1)) == CategoryProduct(U1(1))
584+
@test (@inferred s SU2(0)) == gradedrange([CategoryProduct(SU2(0)) => 1])
585+
@test (@inferred s Fib("τ")) == gradedrange([CategoryProduct(Fib("τ")) => 1])
571586

572587
@test (@inferred_latest CategoryProduct(U1(1)) s) == CategoryProduct(U1(1))
573588
@test (@inferred_latest CategoryProduct(SU2(0)) s) ==

NDTensors/src/lib/Sectors/test/test_fusion_rules.jl

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@
22
using NDTensors.GradedAxes:
33
dual, fusion_product, space_isequal, gradedrange, flip, tensor_product
44
using NDTensors.Sectors:
5-
, Fib, Ising, O2, SU, SU2, U1, Z, block_dimensions, quantum_dimension, trivial
5+
,
6+
Fib,
7+
Ising,
8+
O2,
9+
SU,
10+
SU2,
11+
TrivialSector,
12+
U1,
13+
Z,
14+
block_dimensions,
15+
quantum_dimension,
16+
trivial
617
using Test: @inferred, @test, @testset, @test_throws
718

819
@testset "Simple object fusion rules" begin
@@ -15,6 +26,11 @@ using Test: @inferred, @test, @testset, @test_throws
1526
@test z1 z1 == z0
1627
@test (@inferred z0 z0) == z0 # no better way, see Julia PR 23426
1728

29+
q = TrivialSector()
30+
@test (@inferred q q) == q
31+
@test (@inferred q z0) == z0
32+
@test (@inferred z1 q) == z1
33+
1834
# using GradedAxes interface
1935
@test space_isequal(fusion_product(z0, z0), gradedrange([z0 => 1]))
2036
@test space_isequal(fusion_product(z0, z1), gradedrange([z1 => 1]))
@@ -42,6 +58,10 @@ using Test: @inferred, @test, @testset, @test_throws
4258
s12 = O2(1//2)
4359
s1 = O2(1)
4460

61+
q = TrivialSector()
62+
@test space_isequal((@inferred s0e q), gradedrange([s0e => 1]))
63+
@test space_isequal((@inferred q s0o), gradedrange([s0o => 1]))
64+
4565
@test space_isequal((@inferred s0e s0e), gradedrange([s0e => 1]))
4666
@test space_isequal((@inferred s0o s0e), gradedrange([s0o => 1]))
4767
@test space_isequal((@inferred s0o s0e), gradedrange([s0o => 1]))

NDTensors/src/lib/Sectors/test/test_simple_categories.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ using NDTensors.Sectors:
66
O2,
77
SU,
88
SU2,
9+
TrivialSector,
910
U1,
1011
Z,
1112
adjoint,
@@ -15,6 +16,18 @@ using NDTensors.Sectors:
1516
trivial
1617
using Test: @inferred, @test, @testset, @test_throws
1718
@testset "Test Category Types" begin
19+
@testset "TrivialSector" begin
20+
q = TrivialSector()
21+
22+
@test (@inferred quantum_dimension(q)) == 1
23+
@test q == q
24+
@test trivial(q) == q
25+
@test istrivial(q)
26+
27+
@test dual(q) == q
28+
@test !isless(q, q)
29+
end
30+
1831
@testset "U(1)" begin
1932
q1 = U1(1)
2033
q2 = U1(2)
@@ -27,6 +40,8 @@ using Test: @inferred, @test, @testset, @test_throws
2740
@test trivial(q1) == U1(0)
2841
@test trivial(U1) == U1(0)
2942
@test istrivial(U1(0))
43+
@test U1(0) == TrivialSector()
44+
@test TrivialSector() == U1(0)
3045

3146
@test dual(U1(2)) == U1(-2)
3247
@test isless(U1(1), U1(2))
@@ -39,6 +54,7 @@ using Test: @inferred, @test, @testset, @test_throws
3954

4055
@test trivial(Z{2}) == Z{2}(0)
4156
@test istrivial(Z{2}(0))
57+
@test Z{2}(0) == TrivialSector()
4258

4359
@test quantum_dimension(z0) == 1
4460
@test quantum_dimension(z1) == 1
@@ -60,6 +76,7 @@ using Test: @inferred, @test, @testset, @test_throws
6076

6177
@test trivial(O2) == s0e
6278
@test istrivial(s0e)
79+
@test s0e == TrivialSector()
6380

6481
@test (@inferred quantum_dimension(s0e)) == 1
6582
@test (@inferred quantum_dimension(s0o)) == 1
@@ -90,6 +107,7 @@ using Test: @inferred, @test, @testset, @test_throws
90107

91108
@test trivial(SU{2}) == SU2(0)
92109
@test istrivial(SU2(0))
110+
@test SU2(0) == TrivialSector()
93111

94112
@test fundamental(SU{2}) == SU2(1//2)
95113
@test adjoint(SU{2}) == SU2(1)
@@ -116,6 +134,8 @@ using Test: @inferred, @test, @testset, @test_throws
116134
@test istrivial(SU{3}((0, 0)))
117135
@test trivial(SU{4}) == SU{4}((0, 0, 0))
118136
@test istrivial(SU{4}((0, 0, 0)))
137+
@test SU{3}((0, 0)) == TrivialSector()
138+
@test SU{4}((0, 0, 0)) == TrivialSector()
119139

120140
@test fundamental(SU{3}) == f3
121141
@test adjoint(SU{3}) == ad3
@@ -144,6 +164,7 @@ using Test: @inferred, @test, @testset, @test_throws
144164

145165
@test trivial(Fib) == ı
146166
@test istrivial(ı)
167+
@test ı == TrivialSector()
147168

148169
@test dual(ı) == ı
149170
@test dual(τ) == τ
@@ -159,6 +180,7 @@ using Test: @inferred, @test, @testset, @test_throws
159180

160181
@test trivial(Ising) == ı
161182
@test istrivial(ı)
183+
@test ı == TrivialSector()
162184

163185
@test dual(ı) == ı
164186
@test dual(σ) == σ

0 commit comments

Comments
 (0)