Skip to content

Commit d2010c1

Browse files
authored
Add sectorscalartype (#146)
* Add `Feltype` and `Reltype` * Simplify some manipulations in terms of `Feltype` and `Reltype` * Implement review comments * Change Fscalartype and Rscalartype to sectorscalartype
1 parent 54f2672 commit d2010c1

File tree

4 files changed

+63
-64
lines changed

4 files changed

+63
-64
lines changed

TensorKitSectors/src/TensorKitSectors.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export Sector, Group, AbstractIrrep
1010
export Irrep
1111

1212
export Nsymbol, Fsymbol, Rsymbol, Asymbol, Bsymbol
13+
export sectorscalartype
1314
export dim, sqrtdim, invsqrtdim, frobeniusschur, twist, fusiontensor, dual
1415
export otimes, deligneproduct, times
1516
export FusionStyle, UniqueFusion, MultipleFusion, SimpleFusion, GenericFusion,

TensorKitSectors/src/irreps.jl

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -197,22 +197,26 @@ findindex(::SectorValues{SU2Irrep}, s::SU2Irrep) = twice(s.j) + 1
197197
dim(s::SU2Irrep) = twice(s.j) + 1
198198

199199
FusionStyle(::Type{SU2Irrep}) = SimpleFusion()
200+
sectorscalartype(::Type{SU2Irrep}) = Float64
200201
Base.isreal(::Type{SU2Irrep}) = true
201202

202203
Nsymbol(sa::SU2Irrep, sb::SU2Irrep, sc::SU2Irrep) = WignerSymbols.δ(sa.j, sb.j, sc.j)
204+
203205
function Fsymbol(s1::SU2Irrep, s2::SU2Irrep, s3::SU2Irrep,
204206
s4::SU2Irrep, s5::SU2Irrep, s6::SU2Irrep)
205207
if all(==(_su2one), (s1, s2, s3, s4, s5, s6))
206208
return 1.0
207209
else
208210
return sqrtdim(s5) * sqrtdim(s6) *
209-
WignerSymbols.racahW(Float64, s1.j, s2.j,
211+
WignerSymbols.racahW(sectorscalartype(SU2Irrep), s1.j, s2.j,
210212
s4.j, s3.j, s5.j, s6.j)
211213
end
212214
end
215+
213216
function Rsymbol(sa::SU2Irrep, sb::SU2Irrep, sc::SU2Irrep)
214-
Nsymbol(sa, sb, sc) || return 0.0
215-
return iseven(convert(Int, sa.j + sb.j - sc.j)) ? 1.0 : -1.0
217+
Nsymbol(sa, sb, sc) || return zero(sectorscalartype(SU2Irrep))
218+
return iseven(convert(Int, sa.j + sb.j - sc.j)) ? one(sectorscalartype(SU2Irrep)) :
219+
-one(sectorscalartype(SU2Irrep))
216220
end
217221

218222
function fusiontensor(a::SU2Irrep, b::SU2Irrep, c::SU2Irrep)
@@ -341,59 +345,62 @@ Base.eltype(::Type{CU1ProdIterator}) = CU1Irrep
341345
dim(c::CU1Irrep) = ifelse(c.j == zero(HalfInt), 1, 2)
342346

343347
FusionStyle(::Type{CU1Irrep}) = SimpleFusion()
348+
sectorscalartype(::Type{CU1Irrep}) = Float64
344349
Base.isreal(::Type{CU1Irrep}) = true
345350

346351
function Nsymbol(a::CU1Irrep, b::CU1Irrep, c::CU1Irrep)
347352
return ifelse(c.s == 0, (a.j == b.j) & ((a.s == b.s == 2) | (a.s == b.s)),
348353
ifelse(c.s == 1, (a.j == b.j) & ((a.s == b.s == 2) | (a.s != b.s)),
349354
(c.j == a.j + b.j) | (c.j == abs(a.j - b.j))))
350355
end
356+
351357
function Fsymbol(a::CU1Irrep, b::CU1Irrep, c::CU1Irrep,
352358
d::CU1Irrep, e::CU1Irrep, f::CU1Irrep)
353359
Nabe = convert(Int, Nsymbol(a, b, e))
354360
Necd = convert(Int, Nsymbol(e, c, d))
355361
Nbcf = convert(Int, Nsymbol(b, c, f))
356362
Nafd = convert(Int, Nsymbol(a, f, d))
357363

358-
Nabe * Necd * Nbcf * Nafd == 0 && return 0.0
364+
T = sectorscalartype(CU1Irrep)
365+
Nabe * Necd * Nbcf * Nafd == 0 && return zero(T)
359366

360367
op = CU1Irrep(0, 0)
361368
om = CU1Irrep(0, 1)
362369

363370
if a == op || b == op || c == op
364-
return 1.0
371+
return one(T)
365372
end
366373
if (a == b == om) || (a == c == om) || (b == c == om)
367-
return 1.0
374+
return one(T)
368375
end
369376
if a == om
370377
if d.j == zero(HalfInt)
371-
return 1.0
378+
return one(T)
372379
else
373-
return (d.j == c.j - b.j) ? -1.0 : 1.0
380+
return (d.j == c.j - b.j) ? -one(T) : one(T)
374381
end
375382
end
376383
if b == om
377-
return (d.j == abs(a.j - c.j)) ? -1.0 : 1.0
384+
return (d.j == abs(a.j - c.j)) ? -one(T) : one(T)
378385
end
379386
if c == om
380-
return (d.j == a.j - b.j) ? -1.0 : 1.0
387+
return (d.j == a.j - b.j) ? -one(T) : one(T)
381388
end
382389
# from here on, a, b, c are neither 0+ or 0-
383-
s = sqrt(2) / 2
390+
s = T(sqrt(2) / 2)
384391
if a == b == c
385392
if d == a
386393
if e.j == 0
387394
if f.j == 0
388-
return f.s == 1 ? -0.5 : 0.5
395+
return f.s == 1 ? T(-1 // 2) : T(1 // 2)
389396
else
390397
return e.s == 1 ? -s : s
391398
end
392399
else
393-
return f.j == 0 ? s : 0.0
400+
return f.j == 0 ? s : zero(T)
394401
end
395402
else
396-
return 1.0
403+
return one(T)
397404
end
398405
end
399406
if a == b # != c
@@ -404,7 +411,7 @@ function Fsymbol(a::CU1Irrep, b::CU1Irrep, c::CU1Irrep,
404411
return s
405412
end
406413
else
407-
return 1.0
414+
return one(T)
408415
end
409416
end
410417
if b == c
@@ -415,27 +422,28 @@ function Fsymbol(a::CU1Irrep, b::CU1Irrep, c::CU1Irrep,
415422
return f.s == 1 ? -s : s
416423
end
417424
else
418-
return 1.0
425+
return one(T)
419426
end
420427
end
421428
if a == c
422429
if d == b
423430
if e.j == f.j
424-
return 0.0
431+
return zero(T)
425432
else
426-
return 1.0
433+
return one(T)
427434
end
428435
else
429-
return d.s == 1 ? -1.0 : 1.0
436+
return d.s == 1 ? -one(T) : one(T)
430437
end
431438
end
432439
if d == om
433-
return b.j == a.j + c.j ? -1.0 : 1.0
440+
return b.j == a.j + c.j ? -one(T) : one(T)
434441
end
435-
return 1.0
442+
return one(T)
436443
end
444+
437445
function Rsymbol(a::CU1Irrep, b::CU1Irrep, c::CU1Irrep)
438-
R = convert(Float64, Nsymbol(a, b, c))
446+
R = convert(sectorscalartype(CU1Irrep), Nsymbol(a, b, c))
439447
return c.s == 1 && a.j > 0 ? -R : R
440448
end
441449

TensorKitSectors/src/sectors.jl

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,28 @@ Return the conjugate label `conj(a)`.
7474
dual(a::Sector) = conj(a)
7575

7676
"""
77-
isreal(::Type{<:Sector}) -> Bool
77+
sectorscalartype(I::Type{<:Sector}) -> Type
7878
79-
Return whether the topological data (Fsymbol, Rsymbol) of the sector is real or not (in
80-
which case it is complex).
79+
Return the scalar type of the topological data (Fsymbol, Rsymbol) of the sector `I`.
8180
"""
82-
function Base.isreal(I::Type{<:Sector})
83-
u = one(I)
84-
if BraidingStyle(I) isa HasBraiding
85-
return (eltype(Fsymbol(u, u, u, u, u, u)) <: Real) &&
86-
(eltype(Rsymbol(u, u, u)) <: Real)
81+
function sectorscalartype(::Type{I}) where {I<:Sector}
82+
if BraidingStyle(I) isa NoBraiding
83+
return eltype(Core.Compiler.return_type(Fsymbol, NTuple{6,I}))
8784
else
88-
return (eltype(Fsymbol(u, u, u, u, u, u)) <: Real)
85+
Feltype = eltype(Core.Compiler.return_type(Fsymbol, NTuple{6,I}))
86+
Reltype = eltype(Core.Compiler.return_type(Rsymbol, NTuple{3,I}))
87+
return Base.promote_op(*, Feltype, Reltype)
8988
end
9089
end
9190

91+
"""
92+
isreal(::Type{<:Sector}) -> Bool
93+
94+
Return whether the topological data (Fsymbol, Rsymbol) of the sector is real or not (in
95+
which case it is complex).
96+
"""
97+
Base.isreal(I::Type{<:Sector}) = sectorscalartype(I) <: Real
98+
9299
# FusionStyle: the most important aspect of Sector
93100
#---------------------------------------------
94101
"""

src/fusiontrees/manipulations.jl

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function insertat(f₁::FusionTree{I}, i::Int, f₂::FusionTree{I,0}) where {I}
1717
# this actually removes uncoupled line i, which should be trivial
1818
(f₁.uncoupled[i] == f₂.coupled && !f₁.isdual[i]) ||
1919
throw(SectorMismatch("cannot connect $(f₂.uncoupled) to $(f₁.uncoupled[i])"))
20-
coeff = Fsymbol(one(I), one(I), one(I), one(I), one(I), one(I))[1, 1, 1, 1]
20+
coeff = one(sectorscalartype(I))
2121

2222
uncoupled = TupleTools.deleteat(f₁.uncoupled, i)
2323
coupled = f₁.coupled
@@ -39,7 +39,7 @@ function insertat(f₁::FusionTree{I}, i, f₂::FusionTree{I,1}) where {I}
3939
# identity operation
4040
(f₁.uncoupled[i] == f₂.coupled && !f₁.isdual[i]) ||
4141
throw(SectorMismatch("cannot connect $(f₂.uncoupled) to $(f₁.uncoupled[i])"))
42-
coeff = Fsymbol(one(I), one(I), one(I), one(I), one(I), one(I))[1, 1, 1, 1]
42+
coeff = one(sectorscalartype(I))
4343
isdual′ = TupleTools.setindex(f₁.isdual, f₂.isdual[1], i)
4444
f = FusionTree{I}(f₁.uncoupled, f₁.coupled, isdual′, f₁.innerlines, f₁.vertices)
4545
return fusiontreedict(I)(f => coeff)
@@ -59,7 +59,7 @@ function insertat(f₁::FusionTree{I}, i, f₂::FusionTree{I,2}) where {I}
5959
isdual′ = (isdualb, isdualc, tail(isdual)...)
6060
inner′ = (uncoupled[1], inner...)
6161
vertices′ = (f₂.vertices..., f₁.vertices...)
62-
coeff = Fsymbol(one(I), one(I), one(I), one(I), one(I), one(I))[1, 1, 1, 1]
62+
coeff = one(sectorscalartype(I))
6363
f′ = FusionTree(uncoupled′, coupled, isdual′, inner′, vertices′)
6464
return fusiontreedict(I)(f′ => coeff)
6565
end
@@ -110,8 +110,8 @@ function insertat(f₁::FusionTree{I,N₁}, i, f₂::FusionTree{I,N₂}) where {
110110
F = fusiontreetype(I, N₁ + N₂ - 1)
111111
(f₁.uncoupled[i] == f₂.coupled && !f₁.isdual[i]) ||
112112
throw(SectorMismatch("cannot connect $(f₂.uncoupled) to $(f₁.uncoupled[i])"))
113-
coeff = Fsymbol(one(I), one(I), one(I), one(I), one(I), one(I))[1, 1]
114-
T = typeof(coeff)
113+
T = sectorscalartype(I)
114+
coeff = one(T)
115115
if length(f₁) == 1
116116
return fusiontreedict(I){F,T}(f₂ => coeff)
117117
end
@@ -457,8 +457,8 @@ function _recursive_repartition(f₁::FusionTree{I,N₁},
457457
# precompute the parameters of the return type
458458
F₁ = fusiontreetype(I, N)
459459
F₂ = fusiontreetype(I, N₁ + N₂ - N)
460-
coeff = @inbounds Fsymbol(one(I), one(I), one(I), one(I), one(I), one(I))[1, 1, 1, 1]
461-
T = typeof(coeff)
460+
T = sectorscalartype(I)
461+
coeff = one(T)
462462
if N == N₁
463463
return fusiontreedict(I){Tuple{F₁,F₂},T}((f₁, f₂) => coeff)
464464
else
@@ -500,8 +500,7 @@ function Base.transpose(f₁::FusionTree{I}, f₂::FusionTree{I},
500500
p = linearizepermutation(p1, p2, length(f₁), length(f₂))
501501
@assert iscyclicpermutation(p)
502502
if usetransposecache[]
503-
u = one(I)
504-
T = eltype(Fsymbol(u, u, u, u, u, u))
503+
T = sectorscalartype(I)
505504
F₁ = fusiontreetype(I, N₁)
506505
F₂ = fusiontreetype(I, N₂)
507506
D = fusiontreedict(I){Tuple{F₁,F₂},T}
@@ -587,8 +586,7 @@ function planar_trace(f₁::FusionTree{I}, f₂::FusionTree{I},
587586
map(l -> l - count(l .> q′), TupleTools.getindices(linearindex, p2)))
588587
end
589588

590-
u = one(I)
591-
T = typeof(Fsymbol(u, u, u, u, u, u)[1, 1, 1, 1])
589+
T = sectorscalartype(I)
592590
F₁ = fusiontreetype(I, N₁)
593591
F₂ = fusiontreetype(I, N₂)
594592
newtrees = FusionTreeDict{Tuple{F₁,F₂},T}()
@@ -615,8 +613,7 @@ of output trees and corresponding coefficients.
615613
"""
616614
function planar_trace(f::FusionTree{I,N},
617615
q1::IndexTuple{N₃}, q2::IndexTuple{N₃}) where {I<:Sector,N,N₃}
618-
u = one(I)
619-
T = typeof(Fsymbol(u, u, u, u, u, u)[1, 1, 1, 1])
616+
T = sectorscalartype(I)
620617
F = fusiontreetype(I, N - 2 * N₃)
621618
newtrees = FusionTreeDict{F,T}()
622619
N₃ === 0 && return push!(newtrees, f => one(T))
@@ -673,8 +670,7 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N}
673670
i < N || f.coupled == one(I) ||
674671
throw(ArgumentError("Cannot trace outputs i=$N and 1 of fusion tree that couples to non-trivial sector"))
675672

676-
u = one(I)
677-
T = typeof(Fsymbol(u, u, u, u, u, u)[1, 1, 1, 1])
673+
T = sectorscalartype(I)
678674
F = fusiontreetype(I, N - 2)
679675
newtrees = FusionTreeDict{F,T}()
680676

@@ -786,12 +782,7 @@ function artin_braid(f::FusionTree{I,N}, i; inv::Bool=false) where {I<:Sector,N}
786782
inner_extended = (uncoupled[1], inner..., coupled′)
787783
vertices = f.vertices
788784
u = one(I)
789-
790-
if BraidingStyle(I) isa NoBraiding
791-
oneT = Fsymbol(u, u, u, u, u, u)[1, 1, 1, 1]
792-
else
793-
oneT = Rsymbol(u, u, u)[1, 1] * Fsymbol(u, u, u, u, u, u)[1, 1, 1, 1]
794-
end
785+
oneT = one(sectorscalartype(I))
795786

796787
if u in (uncoupled[i], uncoupled[i + 1])
797788
# braiding with trivial sector: simple and always possible
@@ -925,7 +916,7 @@ function braid(f::FusionTree{I,N},
925916
p::NTuple{N,Int}) where {I<:Sector,N}
926917
TupleTools.isperm(p) || throw(ArgumentError("not a valid permutation: $p"))
927918
if FusionStyle(I) isa UniqueFusion && BraidingStyle(I) isa SymmetricBraiding
928-
coeff = Rsymbol(one(I), one(I), one(I))
919+
coeff = one(sectorscalartype(I))
929920
for i in 1:N
930921
for j in 1:(i - 1)
931922
if p[j] > p[i]
@@ -940,10 +931,7 @@ function braid(f::FusionTree{I,N},
940931
f′ = FusionTree{I}(uncoupled′, coupled′, isdual′)
941932
return fusiontreedict(I)(f′ => coeff)
942933
else
943-
u = one(I)
944-
T = BraidingStyle(I) isa NoBraiding ?
945-
typeof(Fsymbol(u, u, u, u, u, u)[1, 1, 1, 1]) :
946-
typeof(Rsymbol(u, u, u)[1, 1] * Fsymbol(u, u, u, u, u, u)[1, 1, 1, 1])
934+
T = sectorscalartype(I)
947935
coeff = one(T)
948936
trees = FusionTreeDict(f => coeff)
949937
newtrees = empty(trees)
@@ -1009,8 +997,7 @@ function braid(f₁::FusionTree{I}, f₂::FusionTree{I},
1009997
if FusionStyle(f₁) isa UniqueFusion &&
1010998
BraidingStyle(f₁) isa SymmetricBraiding
1011999
if usebraidcache_abelian[]
1012-
u = one(I)
1013-
T = Int
1000+
T = Int # do we hardcode this ?
10141001
F₁ = fusiontreetype(I, N₁)
10151002
F₂ = fusiontreetype(I, N₂)
10161003
D = SingletonDict{Tuple{F₁,F₂},T}
@@ -1020,11 +1007,7 @@ function braid(f₁::FusionTree{I}, f₂::FusionTree{I},
10201007
end
10211008
else
10221009
if usebraidcache_nonabelian[]
1023-
u = one(I)
1024-
T = BraidingStyle(I) isa NoBraiding ?
1025-
typeof(Fsymbol(u, u, u, u, u, u)[1, 1, 1, 1]) :
1026-
typeof(sqrtdim(u) * Fsymbol(u, u, u, u, u, u)[1, 1, 1, 1] *
1027-
Rsymbol(u, u, u)[1, 1])
1010+
T = sectorscalartype(I)
10281011
F₁ = fusiontreetype(I, N₁)
10291012
F₂ = fusiontreetype(I, N₂)
10301013
D = FusionTreeDict{Tuple{F₁,F₂},T}

0 commit comments

Comments
 (0)