Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
f880019
`MultiFusionStyle` and its properties with itself and `FusionStyle`
borisdevos Sep 10, 2025
51740bc
`allones` for `Type{Sector}`
borisdevos Sep 10, 2025
6b13d0c
changes to `IsingBimodule`
borisdevos Sep 10, 2025
9d2821f
export them all
borisdevos Sep 10, 2025
2f7e183
`allones` tests
borisdevos Sep 10, 2025
ef985d7
fix `&` and make commutative for mixed case
borisdevos Sep 10, 2025
20f98b6
`MultiFusionStyle` tests
borisdevos Sep 10, 2025
7a3fb13
format
borisdevos Sep 10, 2025
7eca2d2
update `MultiFusionStyle` to only reflect the semisimplicity of the unit
borisdevos Sep 11, 2025
ce0d87b
update for `IsingBimodule`
borisdevos Sep 11, 2025
1b0aa9a
fix exports
borisdevos Sep 11, 2025
46a6ce5
fix tests
borisdevos Sep 11, 2025
1cd98d7
fix docstrings
borisdevos Sep 11, 2025
97fb36b
add `MultiFusionStyle` for product sectors + test
borisdevos Sep 16, 2025
d03cc5d
remove interplay `MultiFusionStyle`-`FusionStyle` + related tests
borisdevos Sep 16, 2025
ed31fd2
fix domain error of one of IsingBimodule
borisdevos Sep 16, 2025
0a215fd
introduce `allones` for all sectors
borisdevos Sep 16, 2025
08648f0
introduce generic `one` for type sector + remove for specific sectors
borisdevos Sep 16, 2025
b28941c
`allones` for productsector with tests
borisdevos Sep 16, 2025
5a313ef
have multifusionstyle fully depend on `allones`
borisdevos Sep 16, 2025
ccb4313
format
borisdevos Sep 16, 2025
5c5647f
change `one` to `unit` and have `Base.one` fall back to `unit` + rena…
borisdevos Sep 16, 2025
684d810
rename `MultiFusionStyle` to `UnitStyle`
borisdevos Sep 16, 2025
d6188d6
replace `Base.conj` with `dual` and have `dual` fall back to `Base.c…
borisdevos Sep 16, 2025
700cb1c
replacing more `conj` with `dual` + docstring changes
borisdevos Sep 16, 2025
182cb70
minor docstring fix
borisdevos Sep 16, 2025
4ac1073
more one to unit changes
borisdevos Sep 16, 2025
0658c5f
fix `allunits` of product sector to be type stable and return set
borisdevos Sep 16, 2025
77b6a5f
`allunits` for `NewSU2Irrep`
borisdevos Sep 16, 2025
23dc373
add imports for `NewSU2Irrep`
borisdevos Sep 16, 2025
78a888c
`allunits` for `TimeReversed`
borisdevos Sep 16, 2025
c6bcf98
remove some specific `unit`s I missed
borisdevos Sep 16, 2025
2401c7f
apply code suggestions
borisdevos Sep 22, 2025
a69806f
reverse roles of `unit` and `allunits` to make `unit` the entry point…
borisdevos Sep 22, 2025
f00d2c8
more `mapreduce`s
borisdevos Sep 22, 2025
35ae0d4
another `mapreduce` + format
borisdevos Sep 22, 2025
2ced6ff
use `SectorSet` for time reversed `allunits`
borisdevos Sep 22, 2025
7dd58d8
remove `_isreal` code
borisdevos Sep 22, 2025
3fd2d0c
derive `unit` from `one` for `GroupElement`
borisdevos Sep 23, 2025
c5fa94a
avoid string interpolations in error messages
borisdevos Sep 23, 2025
6eb8d8a
reduce specification
borisdevos Sep 23, 2025
6fb637a
make otimes output of time reversed a `SectorSet`
borisdevos Sep 23, 2025
2326b67
introduce `isunit` and change `isone` to `isunit` where relevant
borisdevos Sep 23, 2025
83e4313
bump version to 0.3.0
borisdevos Sep 23, 2025
4662db2
one last `isunit`
borisdevos Sep 23, 2025
02a8cab
change fib field name to `isunit`
borisdevos Sep 23, 2025
955f42f
`unit(::Type{<:AbstractGroupElement})`
lkdvos Sep 24, 2025
88e5025
noinline domainerror
lkdvos Sep 24, 2025
881cbe7
also update precompile
lkdvos Sep 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
3 changes: 2 additions & 1 deletion src/TensorKitSectors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ export dim, sqrtdim, invsqrtdim, frobeniusschur, twist, fusiontensor, dual
export otimes, deligneproduct, times
export FusionStyle, UniqueFusion, MultipleFusion, SimpleFusion, GenericFusion,
MultiplicityFreeFusion
export UnitStyle, SimpleUnit, GenericUnit
export BraidingStyle, NoBraiding, HasBraiding, SymmetricBraiding, Bosonic, Fermionic, Anyonic
export SectorSet, SectorValues, findindex
export rightone, leftone
export unit, rightunit, leftunit, allunits, isunit

export triangle_equation, pentagon_equation, hexagon_equation

Expand Down
34 changes: 17 additions & 17 deletions src/anyons.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ end
findindex(::SectorValues{PlanarTrivial}, c::PlanarTrivial) = 1
Base.isless(::PlanarTrivial, ::PlanarTrivial) = false

Base.one(::Type{PlanarTrivial}) = PlanarTrivial()
Base.conj(::PlanarTrivial) = PlanarTrivial()
unit(::Type{PlanarTrivial}) = PlanarTrivial()
dual(::PlanarTrivial) = PlanarTrivial()

FusionStyle(::Type{PlanarTrivial}) = UniqueFusion()
BraidingStyle(::Type{PlanarTrivial}) = NoBraiding()
Expand All @@ -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 the to 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)
Expand All @@ -68,14 +68,14 @@ 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)
Base.one(::Type{FibonacciAnyon}) = FibonacciAnyon(:I)
Base.conj(s::FibonacciAnyon) = s
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()
Expand All @@ -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)
Expand All @@ -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(
Expand Down Expand Up @@ -136,21 +136,21 @@ 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

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
"""
Expand Down Expand Up @@ -191,8 +191,8 @@ function findindex(::SectorValues{IsingAnyon}, a::IsingAnyon)
end

Base.convert(::Type{IsingAnyon}, s::Symbol) = IsingAnyon(s)
Base.one(::Type{IsingAnyon}) = IsingAnyon(:I)
Base.conj(s::IsingAnyon) = s
unit(::Type{IsingAnyon}) = IsingAnyon(:I)
dual(s::IsingAnyon) = s

dim(a::IsingAnyon) = a.s == :σ ? sqrt(2) : 1.0

Expand Down
4 changes: 2 additions & 2 deletions src/fermions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ function Base.getindex(::SectorValues{FermionParity}, i::Int)
end
findindex(::SectorValues{FermionParity}, f::FermionParity) = f.isodd ? 2 : 1

Base.one(::Type{FermionParity}) = FermionParity(false)
Base.conj(f::FermionParity) = f
unit(::Type{FermionParity}) = FermionParity(false)
dual(f::FermionParity) = f
dim(f::FermionParity) = 1

FusionStyle(::Type{FermionParity}) = UniqueFusion()
Expand Down
4 changes: 2 additions & 2 deletions src/groupelements.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ 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))
Base.conj(a::AbstractGroupElement) = inv(a)
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)
Expand Down
6 changes: 3 additions & 3 deletions src/irreps/cu1irrep.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ 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)
Base.conj(c::CU1Irrep) = c
unit(::Type{CU1Irrep}) = CU1Irrep(zero(HalfInt), 0)
dual(c::CU1Irrep) = c

struct CU1ProdIterator
a::CU1Irrep
Expand All @@ -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
Expand Down
6 changes: 3 additions & 3 deletions src/irreps/dnirrep.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ 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)
Base.conj(a::DNIrrep) = a
unit(::Type{DNIrrep{N}}) where {N} = DNIrrep{N}(0, false)
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)
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions src/irreps/su2irrep.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ Base.getindex(::IrrepTable, ::Type{SU₂}) = SU2Irrep
Base.convert(::Type{SU2Irrep}, j::Real) = SU2Irrep(j)

const _su2one = SU2Irrep(zero(HalfInt))
Base.one(::Type{SU2Irrep}) = _su2one
Base.conj(s::SU2Irrep) = s
unit(::Type{SU2Irrep}) = _su2one
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()
Expand Down
4 changes: 2 additions & 2 deletions src/irreps/u1irrep.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ end
Base.getindex(::IrrepTable, ::Type{U₁}) = U1Irrep
Base.convert(::Type{U1Irrep}, c::Real) = U1Irrep(c)

Base.one(::Type{U1Irrep}) = U1Irrep(0)
Base.conj(c::U1Irrep) = U1Irrep(-c.charge)
unit(::Type{U1Irrep}) = U1Irrep(0)
dual(c::U1Irrep) = U1Irrep(-c.charge)
⊗(c1::U1Irrep, c2::U1Irrep) = (U1Irrep(c1.charge + c2.charge),)

Base.IteratorSize(::Type{SectorValues{U1Irrep}}) = IsInfinite()
Expand Down
4 changes: 2 additions & 2 deletions src/irreps/znirrep.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ const Z2Irrep = ZNIrrep{2}
const Z3Irrep = ZNIrrep{3}
const Z4Irrep = ZNIrrep{4}

Base.one(::Type{ZNIrrep{N}}) where {N} = ZNIrrep{N}(0)
Base.conj(c::ZNIrrep{N}) where {N} = ZNIrrep{N}(-c.n)
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),)

Base.IteratorSize(::Type{SectorValues{ZNIrrep{N}}}) where {N} = HasLength()
Expand Down
18 changes: 9 additions & 9 deletions src/multifusion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,23 +74,23 @@ 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)

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("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

Base.isone(a::IsingBimodule) = leftone(a) == a == rightone(a)

function Base.one(::Type{IsingBimodule})
throw(ArgumentError("one of Type IsingBimodule doesn't exist"))
function unit(::Type{IsingBimodule})
throw(ArgumentError("unit of Type IsingBimodule doesn't exist"))
end

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))
end
Expand Down
2 changes: 2 additions & 0 deletions src/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
25 changes: 15 additions & 10 deletions src/product.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,16 @@ 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)})
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))
return SectorSet{ProductSector{T}}(Base.Iterators.product(iterators...))
end

Base.conj(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)...))),)
Expand Down Expand Up @@ -201,15 +205,16 @@ 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
function _isreal(T::Type{<:SectorTuple})
return isreal(Base.tuple_type_head(T)) && _isreal(Base.tuple_type_tail(T))
function Base.isreal(::Type{<:ProductSector{T}}) where {T <: SectorTuple}
return mapreduce(isreal, &, _sectors(T))
end

fermionparity(P::ProductSector) = mapreduce(fermionparity, xor, P.sectors)
Expand Down
Loading
Loading