From ddb62d524e4fa072694d8ee8ddbfd13cc4273716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Tue, 8 Oct 2024 19:10:51 -0400 Subject: [PATCH] rename sectors product_sectors --- .../lib/SymmetrySectors/src/sector_product.jl | 157 +++++++++--------- .../test/test_sector_product.jl | 73 ++++---- 2 files changed, 120 insertions(+), 110 deletions(-) diff --git a/NDTensors/src/lib/SymmetrySectors/src/sector_product.jl b/NDTensors/src/lib/SymmetrySectors/src/sector_product.jl index 4bd9e930c2..5651fa82ab 100644 --- a/NDTensors/src/lib/SymmetrySectors/src/sector_product.jl +++ b/NDTensors/src/lib/SymmetrySectors/src/sector_product.jl @@ -7,38 +7,40 @@ using ..GradedAxes: AbstractGradedUnitRange, GradedAxes, dual # ===================================== Definition ======================================= struct SectorProduct{Sectors} <: AbstractSector - sectors::Sectors + product_sectors::Sectors global _SectorProduct(l) = new{typeof(l)}(l) end -SectorProduct(c::SectorProduct) = _SectorProduct(sectors(c)) +SectorProduct(c::SectorProduct) = _SectorProduct(product_sectors(c)) -sectors(s::SectorProduct) = s.sectors +product_sectors(s::SectorProduct) = s.product_sectors # ================================= Sectors interface ==================================== -SymmetryStyle(T::Type{<:SectorProduct}) = sectors_symmetrystyle(sectors_type(T)) +function SymmetryStyle(T::Type{<:SectorProduct}) + return product_sectors_symmetrystyle(product_sectors_type(T)) +end function quantum_dimension(::NotAbelianStyle, s::SectorProduct) - return mapreduce(quantum_dimension, *, sectors(s)) + return mapreduce(quantum_dimension, *, product_sectors(s)) end # use map instead of broadcast to support both Tuple and NamedTuple -GradedAxes.dual(s::SectorProduct) = SectorProduct(map(dual, sectors(s))) +GradedAxes.dual(s::SectorProduct) = SectorProduct(map(dual, product_sectors(s))) function trivial(type::Type{<:SectorProduct}) - return SectorProduct(sectors_trivial(sectors_type(type))) + return SectorProduct(product_sectors_trivial(product_sectors_type(type))) end # =================================== Base interface ===================================== function Base.:(==)(A::SectorProduct, B::SectorProduct) - return sectors_isequal(sectors(A), sectors(B)) + return product_sectors_isequal(product_sectors(A), product_sectors(B)) end function Base.show(io::IO, s::SectorProduct) - (length(sectors(s)) < 2) && print(io, "sector") + (length(product_sectors(s)) < 2) && print(io, "sector") print(io, "(") symbol = "" - for p in pairs(sectors(s)) + for p in pairs(product_sectors(s)) print(io, symbol) sector_show(io, p[1], p[2]) symbol = " × " @@ -50,7 +52,7 @@ sector_show(io::IO, ::Int, v) = print(io, v) sector_show(io::IO, k::Symbol, v) = print(io, "($k=$v,)") function Base.isless(s1::SectorProduct, s2::SectorProduct) - return sectors_isless(sectors(s1), sectors(s2)) + return product_sectors_isless(product_sectors(s1), product_sectors(s2)) end # ======================================= shared ========================================= @@ -58,67 +60,70 @@ end # - ordered-like with a Tuple # - dictionary-like with a NamedTuple -function sym_sectors_insert_unspecified(s1, s2) - return sectors_insert_unspecified(s1, s2), sectors_insert_unspecified(s2, s1) +function sym_product_sectors_insert_unspecified(s1, s2) + return product_sectors_insert_unspecified(s1, s2), + product_sectors_insert_unspecified(s2, s1) end -function sectors_isequal(s1, s2) - return ==(sym_sectors_insert_unspecified(s1, s2)...) +function product_sectors_isequal(s1, s2) + return ==(sym_product_sectors_insert_unspecified(s1, s2)...) end # get clean results when mixing implementations -function sectors_isequal(nt::NamedTuple, ::Tuple{}) - return sectors_isequal(nt, (;)) +function product_sectors_isequal(nt::NamedTuple, ::Tuple{}) + return product_sectors_isequal(nt, (;)) end -function sectors_isequal(::Tuple{}, nt::NamedTuple) - return sectors_isequal((;), nt) +function product_sectors_isequal(::Tuple{}, nt::NamedTuple) + return product_sectors_isequal((;), nt) end -function sectors_isequal(::NamedTuple{()}, t::Tuple) - return sectors_isequal((), t) +function product_sectors_isequal(::NamedTuple{()}, t::Tuple) + return product_sectors_isequal((), t) end -function sectors_isequal(t::Tuple, ::NamedTuple{()}) - return sectors_isequal(t, ()) +function product_sectors_isequal(t::Tuple, ::NamedTuple{()}) + return product_sectors_isequal(t, ()) end -sectors_isequal(::Tuple{}, ::NamedTuple{()}) = true -sectors_isequal(::NamedTuple{()}, ::Tuple{}) = true -sectors_isequal(::Tuple, ::NamedTuple) = false -sectors_isequal(::NamedTuple, ::Tuple) = false +product_sectors_isequal(::Tuple{}, ::NamedTuple{()}) = true +product_sectors_isequal(::NamedTuple{()}, ::Tuple{}) = true +product_sectors_isequal(::Tuple, ::NamedTuple) = false +product_sectors_isequal(::NamedTuple, ::Tuple) = false -function sectors_isless(nt::NamedTuple, ::Tuple{}) - return sectors_isless(nt, (;)) +function product_sectors_isless(nt::NamedTuple, ::Tuple{}) + return product_sectors_isless(nt, (;)) end -function sectors_isless(::Tuple{}, nt::NamedTuple) - return sectors_isless((;), nt) +function product_sectors_isless(::Tuple{}, nt::NamedTuple) + return product_sectors_isless((;), nt) end -function sectors_isless(::NamedTuple{()}, t::Tuple) - return sectors_isless((), t) +function product_sectors_isless(::NamedTuple{()}, t::Tuple) + return product_sectors_isless((), t) end -function sectors_isless(t::Tuple, ::NamedTuple{()}) - return sectors_isless(t, ()) +function product_sectors_isless(t::Tuple, ::NamedTuple{()}) + return product_sectors_isless(t, ()) end -function sectors_isless(s1, s2) - return isless(sym_sectors_insert_unspecified(s1, s2)...) +function product_sectors_isless(s1, s2) + return isless(sym_product_sectors_insert_unspecified(s1, s2)...) end -sectors_isless(::NamedTuple, ::Tuple) = throw(ArgumentError("Not implemented")) -sectors_isless(::Tuple, ::NamedTuple) = throw(ArgumentError("Not implemented")) +product_sectors_isless(::NamedTuple, ::Tuple) = throw(ArgumentError("Not implemented")) +product_sectors_isless(::Tuple, ::NamedTuple) = throw(ArgumentError("Not implemented")) -sectors_type(::Type{<:SectorProduct{T}}) where {T} = T +product_sectors_type(::Type{<:SectorProduct{T}}) where {T} = T -function sectors_fusion_rule(sects1, sects2) - shared_sect = shared_sectors_fusion_rule(sectors_common(sects1, sects2)...) - diff_sect = SectorProduct(sectors_diff(sects1, sects2)) +function product_sectors_fusion_rule(sects1, sects2) + shared_sect = shared_product_sectors_fusion_rule( + product_sectors_common(sects1, sects2)... + ) + diff_sect = SectorProduct(product_sectors_diff(sects1, sects2)) return shared_sect × diff_sect end -# edge case with empty sectors -sectors_fusion_rule(sects::Tuple, ::NamedTuple{()}) = SectorProduct(sects) -sectors_fusion_rule(::NamedTuple{()}, sects::Tuple) = SectorProduct(sects) -sectors_fusion_rule(sects::NamedTuple, ::Tuple{}) = SectorProduct(sects) -sectors_fusion_rule(::Tuple{}, sects::NamedTuple) = SectorProduct(sects) +# edge case with empty product_sectors +product_sectors_fusion_rule(sects::Tuple, ::NamedTuple{()}) = SectorProduct(sects) +product_sectors_fusion_rule(::NamedTuple{()}, sects::Tuple) = SectorProduct(sects) +product_sectors_fusion_rule(sects::NamedTuple, ::Tuple{}) = SectorProduct(sects) +product_sectors_fusion_rule(::Tuple{}, sects::NamedTuple) = SectorProduct(sects) function recover_style(T::Type, fused) - style = sectors_symmetrystyle(T) + style = product_sectors_symmetrystyle(T) return recover_sector_product_type(style, T, fused) end @@ -146,11 +151,11 @@ function recover_sector_product_type(T::Type, c::AbstractSector) end function recover_sector_product_type(T::Type, c::SectorProduct) - return recover_sector_product_type(T, sectors(c)) + return recover_sector_product_type(T, product_sectors(c)) end function recover_sector_product_type(T::Type{<:SectorProduct}, sects) - return recover_sector_product_type(sectors_type(T), sects) + return recover_sector_product_type(product_sectors_type(T), sects) end function recover_sector_product_type(T::Type, sects) @@ -160,7 +165,7 @@ end # ================================= Cartesian Product ==================================== ×(c1::AbstractSector, c2::AbstractSector) = ×(SectorProduct(c1), SectorProduct(c2)) function ×(p1::SectorProduct, p2::SectorProduct) - return SectorProduct(sectors_product(sectors(p1), sectors(p2))) + return SectorProduct(product_sectors_product(product_sectors(p1), product_sectors(p2))) end ×(a, g::AbstractUnitRange) = ×(to_gradedrange(a), g) @@ -194,12 +199,14 @@ end # generic case: fusion returns a GradedAxes, even for fusion with Empty function fusion_rule(::NotAbelianStyle, s1::SectorProduct, s2::SectorProduct) - return to_gradedrange(sectors_fusion_rule(sectors(s1), sectors(s2))) + return to_gradedrange( + product_sectors_fusion_rule(product_sectors(s1), product_sectors(s2)) + ) end # Abelian case: fusion returns SectorProduct function fusion_rule(::AbelianStyle, s1::SectorProduct, s2::SectorProduct) - return sectors_fusion_rule(sectors(s1), sectors(s2)) + return product_sectors_fusion_rule(product_sectors(s1), product_sectors(s2)) end # lift ambiguities for TrivialSector @@ -212,41 +219,41 @@ fusion_rule(::NotAbelianStyle, ::TrivialSector, c::SectorProduct) = to_gradedran SectorProduct(t::Tuple) = _SectorProduct(t) SectorProduct(sects::AbstractSector...) = SectorProduct(sects) -function sectors_symmetrystyle(T::Type{<:Tuple}) +function product_sectors_symmetrystyle(T::Type{<:Tuple}) return mapreduce(SymmetryStyle, combine_styles, fieldtypes(T); init=AbelianStyle()) end -sectors_product(::NamedTuple{()}, l1::Tuple) = l1 -sectors_product(l2::Tuple, ::NamedTuple{()}) = l2 -sectors_product(l1::Tuple, l2::Tuple) = (l1..., l2...) +product_sectors_product(::NamedTuple{()}, l1::Tuple) = l1 +product_sectors_product(l2::Tuple, ::NamedTuple{()}) = l2 +product_sectors_product(l1::Tuple, l2::Tuple) = (l1..., l2...) -sectors_trivial(type::Type{<:Tuple}) = trivial.(fieldtypes(type)) +product_sectors_trivial(type::Type{<:Tuple}) = trivial.(fieldtypes(type)) -function sectors_common(t1::Tuple, t2::Tuple) +function product_sectors_common(t1::Tuple, t2::Tuple) n = min(length(t1), length(t2)) return t1[begin:n], t2[begin:n] end -function sectors_diff(t1::Tuple, t2::Tuple) +function product_sectors_diff(t1::Tuple, t2::Tuple) n1 = length(t1) n2 = length(t2) return n1 < n2 ? t2[(n1 + 1):end] : t1[(n2 + 1):end] end -function shared_sectors_fusion_rule(shared1::T, shared2::T) where {T<:Tuple} +function shared_product_sectors_fusion_rule(shared1::T, shared2::T) where {T<:Tuple} fused = map(fusion_rule, shared1, shared2) return recover_style(T, fused) end -function sectors_insert_unspecified(t1::Tuple, t2::Tuple) +function product_sectors_insert_unspecified(t1::Tuple, t2::Tuple) n1 = length(t1) return (t1..., trivial.(t2[(n1 + 1):end])...) end # =========================== Dictionary-like implementation ============================= function SectorProduct(nt::NamedTuple) - sectors = sort_keys(nt) - return _SectorProduct(sectors) + product_sectors = sort_keys(nt) + return _SectorProduct(product_sectors) end SectorProduct(; kws...) = SectorProduct((; kws...)) @@ -257,38 +264,38 @@ function SectorProduct(pairs::Pair...) return SectorProduct(NamedTuple{keys}(vals)) end -function sectors_symmetrystyle(NT::Type{<:NamedTuple}) +function product_sectors_symmetrystyle(NT::Type{<:NamedTuple}) return mapreduce(SymmetryStyle, combine_styles, fieldtypes(NT); init=AbelianStyle()) end -function sectors_insert_unspecified(nt1::NamedTuple, nt2::NamedTuple) - diff1 = sectors_trivial(typeof(setdiff_keys(nt2, nt1))) +function product_sectors_insert_unspecified(nt1::NamedTuple, nt2::NamedTuple) + diff1 = product_sectors_trivial(typeof(setdiff_keys(nt2, nt1))) return sort_keys(union_keys(nt1, diff1)) end -sectors_product(l1::NamedTuple, ::Tuple{}) = l1 -sectors_product(::Tuple{}, l2::NamedTuple) = l2 -function sectors_product(l1::NamedTuple, l2::NamedTuple) +product_sectors_product(l1::NamedTuple, ::Tuple{}) = l1 +product_sectors_product(::Tuple{}, l2::NamedTuple) = l2 +function product_sectors_product(l1::NamedTuple, l2::NamedTuple) if length(intersect_keys(l1, l2)) > 0 throw(ArgumentError("Cannot define product of shared keys")) end return union_keys(l1, l2) end -function sectors_trivial(type::Type{<:NamedTuple{Keys}}) where {Keys} +function product_sectors_trivial(type::Type{<:NamedTuple{Keys}}) where {Keys} return NamedTuple{Keys}(trivial.(fieldtypes(type))) end -function sectors_common(nt1::NamedTuple, nt2::NamedTuple) +function product_sectors_common(nt1::NamedTuple, nt2::NamedTuple) # SectorProduct(nt::NamedTuple) sorts keys at init @assert issorted(keys(nt1)) @assert issorted(keys(nt2)) return intersect_keys(nt1, nt2), intersect_keys(nt2, nt1) end -sectors_diff(nt1::NamedTuple, nt2::NamedTuple) = symdiff_keys(nt1, nt2) +product_sectors_diff(nt1::NamedTuple, nt2::NamedTuple) = symdiff_keys(nt1, nt2) -function shared_sectors_fusion_rule(shared1::T, shared2::T) where {T<:NamedTuple} +function shared_product_sectors_fusion_rule(shared1::T, shared2::T) where {T<:NamedTuple} fused = map(fusion_rule, values(shared1), values(shared2)) return recover_style(T, fused) end diff --git a/NDTensors/src/lib/SymmetrySectors/test/test_sector_product.jl b/NDTensors/src/lib/SymmetrySectors/test/test_sector_product.jl index 56f84ac63a..034dfc460a 100644 --- a/NDTensors/src/lib/SymmetrySectors/test/test_sector_product.jl +++ b/NDTensors/src/lib/SymmetrySectors/test/test_sector_product.jl @@ -13,7 +13,7 @@ using NDTensors.SymmetrySectors: block_dimensions, quantum_dimension, recover_sector_product_type, - sectors, + product_sectors, trivial using NDTensors.GradedAxes: dual, fusion_product, space_isequal, gradedrange using Test: @inferred, @test, @testset, @test_throws @@ -28,42 +28,44 @@ end @testset "Test Ordered Products" begin @testset "Ordered Constructor" begin s = SectorProduct(U1(1)) - @test length(sectors(s)) == 1 + @test length(product_sectors(s)) == 1 @test (@inferred quantum_dimension(s)) == 1 @test (@inferred dual(s)) == SectorProduct(U1(-1)) - @test sectors(s)[1] == U1(1) + @test product_sectors(s)[1] == U1(1) @test (@inferred_latest trivial(s)) == SectorProduct(U1(0)) s = SectorProduct(U1(1), U1(2)) - @test length(sectors(s)) == 2 + @test length(product_sectors(s)) == 2 @test (@inferred quantum_dimension(s)) == 1 @test (@inferred dual(s)) == SectorProduct(U1(-1), U1(-2)) - @test sectors(s)[1] == U1(1) - @test sectors(s)[2] == U1(2) + @test product_sectors(s)[1] == U1(1) + @test product_sectors(s)[2] == U1(2) @test (@inferred_latest trivial(s)) == SectorProduct(U1(0), U1(0)) s = U1(1) × SU2(1//2) × U1(3) - @test length(sectors(s)) == 3 + @test length(product_sectors(s)) == 3 @test (@inferred quantum_dimension(s)) == 2 @test (@inferred dual(s)) == U1(-1) × SU2(1//2) × U1(-3) - @test sectors(s)[1] == U1(1) - @test sectors(s)[2] == SU2(1//2) - @test sectors(s)[3] == U1(3) + @test product_sectors(s)[1] == U1(1) + @test product_sectors(s)[2] == SU2(1//2) + @test product_sectors(s)[3] == U1(3) @test (@inferred_latest trivial(s)) == SectorProduct(U1(0), SU2(0), U1(0)) - @test (@inferred recover_sector_product_type(typeof(sectors(s)), sectors(s))) == s - @test (@inferred recover_sector_product_type(typeof(s), sectors(s))) == s + @test (@inferred recover_sector_product_type( + typeof(product_sectors(s)), product_sectors(s) + )) == s + @test (@inferred recover_sector_product_type(typeof(s), product_sectors(s))) == s s = U1(3) × SU2(1//2) × Fib("τ") - @test length(sectors(s)) == 3 + @test length(product_sectors(s)) == 3 @test (@inferred_latest quantum_dimension(s)) == 1.0 + √5 @test dual(s) == U1(-3) × SU2(1//2) × Fib("τ") - @test sectors(s)[1] == U1(3) - @test sectors(s)[2] == SU2(1//2) - @test sectors(s)[3] == Fib("τ") + @test product_sectors(s)[1] == U1(3) + @test product_sectors(s)[2] == SU2(1//2) + @test product_sectors(s)[3] == Fib("τ") @test (@inferred_latest trivial(s)) == SectorProduct(U1(0), SU2(0), Fib("1")) s = TrivialSector() × U1(3) × SU2(1 / 2) - @test length(sectors(s)) == 3 + @test length(product_sectors(s)) == 3 @test (@inferred_latest quantum_dimension(s)) == 2 @test dual(s) == TrivialSector() × U1(-3) × SU2(1//2) @test (@inferred_latest trivial(s)) == SectorProduct(TrivialSector(), U1(0), SU2(0)) @@ -71,7 +73,7 @@ end end @testset "Ordered comparisons" begin - # convention: missing sectors are filled with singlets + # convention: missing product_sectors are filled with singlets @test SectorProduct(U1(1), SU2(1)) == SectorProduct(U1(1), SU2(1)) @test SectorProduct(U1(1), SU2(0)) != SectorProduct(U1(1), SU2(1)) @test SectorProduct(U1(0), SU2(1)) != SectorProduct(U1(1), SU2(1)) @@ -297,28 +299,29 @@ end @testset "Test Named Sector Products" begin @testset "Construct from × of NamedTuples" begin s = (A=U1(1),) × (B=Z{2}(0),) - @test length(sectors(s)) == 2 - @test sectors(s)[:A] == U1(1) - @test sectors(s)[:B] == Z{2}(0) + @test length(product_sectors(s)) == 2 + @test product_sectors(s)[:A] == U1(1) + @test product_sectors(s)[:B] == Z{2}(0) @test (@inferred quantum_dimension(s)) == 1 @test (@inferred dual(s)) == (A=U1(-1),) × (B=Z{2}(0),) @test (@inferred_latest trivial(s)) == (A=U1(0),) × (B=Z{2}(0),) s = (A=U1(1),) × (B=SU2(2),) - @test length(sectors(s)) == 2 - @test sectors(s)[:A] == U1(1) - @test sectors(s)[:B] == SU2(2) + @test length(product_sectors(s)) == 2 + @test product_sectors(s)[:A] == U1(1) + @test product_sectors(s)[:B] == SU2(2) @test (@inferred quantum_dimension(s)) == 5 @test (@inferred dual(s)) == (A=U1(-1),) × (B=SU2(2),) @test (@inferred_latest trivial(s)) == (A=U1(0),) × (B=SU2(0),) - @test (@inferred recover_sector_product_type(typeof(sectors(s)), Tuple(sectors(s)))) == - s - @test (@inferred recover_sector_product_type(typeof(s), Tuple(sectors(s)))) == s + @test (@inferred recover_sector_product_type( + typeof(product_sectors(s)), Tuple(product_sectors(s)) + )) == s + @test (@inferred recover_sector_product_type(typeof(s), Tuple(product_sectors(s)))) == s @test s == (B=SU2(2),) × (A=U1(1),) s = s × (C=Ising("ψ"),) - @test length(sectors(s)) == 3 - @test sectors(s)[:C] == Ising("ψ") + @test length(product_sectors(s)) == 3 + @test product_sectors(s)[:C] == Ising("ψ") @test (@inferred_latest quantum_dimension(s)) == 5.0 @test (@inferred dual(s)) == (A=U1(-1),) × (B=SU2(2),) × (C=Ising("ψ"),) @@ -329,22 +332,22 @@ end @testset "Construct from Pairs" begin s = SectorProduct("A" => U1(2)) - @test length(sectors(s)) == 1 - @test sectors(s)[:A] == U1(2) + @test length(product_sectors(s)) == 1 + @test product_sectors(s)[:A] == U1(2) @test s == SectorProduct(; A=U1(2)) @test (@inferred quantum_dimension(s)) == 1 @test (@inferred dual(s)) == SectorProduct("A" => U1(-2)) @test (@inferred_latest trivial(s)) == SectorProduct(; A=U1(0)) s = SectorProduct("B" => Ising("ψ"), :C => Z{2}(1)) - @test length(sectors(s)) == 2 - @test sectors(s)[:B] == Ising("ψ") - @test sectors(s)[:C] == Z{2}(1) + @test length(product_sectors(s)) == 2 + @test product_sectors(s)[:B] == Ising("ψ") + @test product_sectors(s)[:C] == Z{2}(1) @test (@inferred_latest quantum_dimension(s)) == 1.0 end @testset "Comparisons with unspecified labels" begin - # convention: sectors evaluate as equal if unmatched labels are trivial + # convention: product_sectors evaluate as equal if unmatched labels are trivial # this is different from ordered tuple convention q2 = SectorProduct(; N=U1(2)) q20 = (N=U1(2),) × (J=SU2(0),)