diff --git a/Project.toml b/Project.toml index 7e82876c5..53accbf67 100644 --- a/Project.toml +++ b/Project.toml @@ -54,7 +54,7 @@ Random = "1" SafeTestsets = "0.1" ScopedValues = "1.3.0" Strided = "2" -TensorKitSectors = "0.3.5" +TensorKitSectors = "0.3.7" TensorOperations = "5.1" Test = "1" TestExtras = "0.2,0.3" diff --git a/src/TensorKit.jl b/src/TensorKit.jl index 688e7363c..ce92ad447 100644 --- a/src/TensorKit.jl +++ b/src/TensorKit.jl @@ -8,11 +8,12 @@ module TensorKit # Exports #--------- # Reexport common sector types: -export Sector, AbstractIrrep, Irrep +export Sector, AbstractIrrep, Irrep, GroupElement, TimeReversed export FusionStyle, UniqueFusion, MultipleFusion, MultiplicityFreeFusion, SimpleFusion, GenericFusion export UnitStyle, SimpleUnit, GenericUnit export BraidingStyle, SymmetricBraiding, Bosonic, Fermionic, Anyonic, NoBraiding, HasBraiding -export Trivial, Z2Irrep, Z3Irrep, Z4Irrep, ZNIrrep, U1Irrep, SU2Irrep, CU1Irrep +export Trivial, Z2Irrep, Z3Irrep, Z4Irrep, ZNIrrep, LargeZNIrrep +export ZNElement, Z2Element, Z3Element, Z4Element, DNIrrep, A4Irrep, U1Irrep, SU2Irrep, CU1Irrep export ProductSector, TimeReversed export FermionParity, FermionNumber, FermionSpin export FibonacciAnyon, IsingAnyon, IsingBimodule @@ -42,7 +43,8 @@ export infimum, supremum, isisomorphic, ismonomorphic, isepimorphic # Reexport methods for sectors and properties thereof export sectortype, sectors, hassector export unit, rightunit, leftunit, allunits, isunit, otimes -export Nsymbol, Fsymbol, Rsymbol, Bsymbol, frobenius_schur_phase, frobenius_schur_indicator, twist, sectorscalartype, deligneproduct +export Nsymbol, Fsymbol, Rsymbol, Bsymbol, frobenius_schur_phase, frobenius_schur_indicator, twist, fusiontensor +export sectorscalartype, deligneproduct # Export methods for fusion trees export fusiontrees, braid, permute, transpose @@ -52,7 +54,7 @@ export fusiontrees, braid, permute, transpose # some unicode export ⊕, ⊗, ⊖, ×, ⊠, ℂ, ℝ, ℤ, ←, →, ≾, ≿, ≅, ≺, ≻ -export ℤ₂, ℤ₃, ℤ₄, U₁, SU, SU₂, CU₁ +export ℤ₂, ℤ₃, ℤ₄, D₃, D₄, A₄, U₁, SU, SU₂, CU₁ export fℤ₂, fU₁, fSU₂ export ℤ₂Space, ℤ₃Space, ℤ₄Space, U₁Space, CU₁Space, SU₂Space diff --git a/src/auxiliary/dicts.jl b/src/auxiliary/dicts.jl index f43838010..8ce6c4532 100644 --- a/src/auxiliary/dicts.jl +++ b/src/auxiliary/dicts.jl @@ -21,84 +21,6 @@ Base.get(d::SingletonDict, key, default) = isequal(d.key, key) ? d.value : defau Base.iterate(d::SingletonDict, s = true) = s ? ((d.key => d.value), false) : nothing -struct VectorDict{K, V} <: AbstractDict{K, V} - keys::Vector{K} - values::Vector{V} -end -VectorDict{K, V}() where {K, V} = VectorDict{K, V}(Vector{K}(), Vector{V}()) -VectorDict() = VectorDict{Any, Any}() - -function VectorDict{K, V}(kvs) where {K, V} - keys = Vector{K}() - values = Vector{V}() - if Base.IteratorSize(kv) !== SizeUnknown() - sizehint!(keys, length(kvs)) - sizehint!(values, length(kvs)) - end - for (k, v) in kvs - push!(keys, k) - push!(values, v) - end - return VectorDict{K, V}(keys, values) -end -VectorDict(kv1::Pair{K, V}, kvs::Pair{K, V}...) where {K, V} = VectorDict{K, V}((kv1, kvs...)) -VectorDict(g::Base.Generator) = VectorDict(g...) - -Base.length(d::VectorDict) = length(d.keys) -function Base.sizehint!(d::VectorDict, newsz) - (sizehint!(d.keys, newsz); sizehint!(d.values, newsz); return d) -end - -@propagate_inbounds getpair(d::VectorDict, i::Integer) = d.keys[i] => d.values[i] - -Base.copy(d::VectorDict) = VectorDict(copy(d.keys), copy(d.values)) -Base.empty(::VectorDict, ::Type{K}, ::Type{V}) where {K, V} = VectorDict{K, V}() -Base.empty!(d::VectorDict) = (empty!(d.keys); empty!(d.values); return d) - -function Base.delete!(d::VectorDict, key) - i = findfirst(isequal(key), d.keys) - if !(i === nothing || i == 0) - deleteat!(d.keys, i) - deleteat!(d.values, i) - end - return d -end - -Base.keys(d::VectorDict) = d.keys -Base.values(d::VectorDict) = d.values -Base.haskey(d::VectorDict, key) = key in d.keys -function Base.getindex(d::VectorDict, key) - i = findfirst(isequal(key), d.keys) - @inbounds begin - return i !== nothing ? d.values[i] : throw(KeyError(key)) - end -end -function Base.setindex!(d::VectorDict, v, key) - i = findfirst(isequal(key), d.keys) - if i === nothing - push!(d.keys, key) - push!(d.values, v) - else - d.values[i] = v - end - return d -end - -function Base.get(d::VectorDict, key, default) - i = findfirst(isequal(key), d.keys) - @inbounds begin - return i !== nothing ? d.values[i] : default - end -end - -function Base.iterate(d::VectorDict, s = 1) - @inbounds if s > length(d) - return nothing - else - return (d.keys[s] => d.values[s]), s + 1 - end -end - struct SortedVectorDict{K, V} <: AbstractDict{K, V} keys::Vector{K} values::Vector{V} diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index 3cc6a16b6..764696f66 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -351,9 +351,21 @@ function foldright(f₁::FusionTree{I, N₁}, f₂::FusionTree{I, N₂}) where { isdual = Base.tail(f₁.isdual) if FusionStyle(I) isa UniqueFusion c = first(c1 ⊗ c2) - fl = FusionTree{I}(Base.tail(f₁.uncoupled), c, Base.tail(f₁.isdual)) - fr = FusionTree{I}((c1, f₂.uncoupled...), c, (!isduala, f₂.isdual...)) - return fusiontreedict(I)((fl, fr) => factor) + cvalid = N₁ == 1 ? leftunit(c1) : only(⊗(uncoupled...)) + @assert c == cvalid + fc = FusionTree((c1, c2), c, (!isduala, false)) + fl′, coeff1 = only(insertat(fc, 2, f₁)) # this coeff is not always 1 + N₁ > 1 && @assert isunit(fl′.innerlines[1]) + + coupled = fl′.coupled + uncoupled = Base.tail(Base.tail(fl′.uncoupled)) + isdual = Base.tail(Base.tail(fl′.isdual)) + inner = N₁ <= 3 ? () : Base.tail(Base.tail(fl′.innerlines)) + vertices = N₁ <= 2 ? () : Base.tail(Base.tail(fl′.vertices)) + fl = FusionTree{I}(uncoupled, coupled, isdual, inner, vertices) + fr, coeff2 = only(insertat(fc, 2, f₂)) # same here + coeff = factor * coeff1 * conj(coeff2) + return fusiontreedict(I)((fl, fr) => coeff) else hasmultiplicities = FusionStyle(a) isa GenericFusion local newtrees diff --git a/src/tensors/abstracttensor.jl b/src/tensors/abstracttensor.jl index 2d7239460..b53dbf7ed 100644 --- a/src/tensors/abstracttensor.jl +++ b/src/tensors/abstracttensor.jl @@ -212,7 +212,6 @@ See also [`domain`](@ref) and [`space`](@ref). codomain(t::AbstractTensorMap) = codomain(space(t)) codomain(t::AbstractTensorMap, i) = codomain(t)[i] -target(t::AbstractTensorMap) = codomain(t) # categorical terminology @doc """ domain(t::AbstractTensorMap{T,S,N₁,N₂}) -> ProductSpace{S,N₂} @@ -226,7 +225,6 @@ See also [`codomain`](@ref) and [`space`](@ref). domain(t::AbstractTensorMap) = domain(space(t)) domain(t::AbstractTensorMap, i) = domain(t)[i] -source(t::AbstractTensorMap) = domain(t) # categorical terminology @doc """ numout(x) -> Int diff --git a/test/cuda/factorizations.jl b/test/cuda/factorizations.jl index 1b46cb646..46e5ee2b5 100644 --- a/test/cuda/factorizations.jl +++ b/test/cuda/factorizations.jl @@ -17,14 +17,14 @@ using .TestSetup spacelist = if get(ENV, "CI", "false") == "true" println("Detected running on CI") if Sys.iswindows() - (Vtr, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VIB_diag) + (Vtr, Vℤ₃, VA₄, Vfib, VU₁, VfU₁, VCU₁, VSU₂, VIB_diag) elseif Sys.isapple() - (Vtr, Vℤ₃, VfU₁, VfSU₂, VIB_M) + (Vtr, Vℤ₃, VA₄, Vfib, VfU₁, VfSU₂, VIB_M) else - (Vtr, VU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M) + (Vtr, VA₄, VU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M) end else - (Vtr, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M) + (Vtr, Vℤ₃, VA₄, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M) end eltypes = (Float32, ComplexF64) diff --git a/test/cuda/tensors.jl b/test/cuda/tensors.jl index 0fad13473..4d4da9825 100644 --- a/test/cuda/tensors.jl +++ b/test/cuda/tensors.jl @@ -13,7 +13,7 @@ using CUDA: rand as curand, rand! as curand!, randn as curandn, randn! as curand @isdefined(TestSetup) || include("../setup.jl") using .TestSetup -for V in (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂) #, VSU₃) +for V in (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VA₄, Vfib, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂) #, VSU₃) V1, V2, V3, V4, V5 = V @assert V3 * V4 * V2 ≿ V1' * V5' # necessary for leftorth tests @assert V3 * V4 ≾ V1' * V2' * V5' # necessary for rightorth tests @@ -23,17 +23,17 @@ spacelist = try if ENV["CI"] == "true" println("Detected running on CI") if Sys.iswindows() - (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂) + (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VA₄, VU₁, VfU₁, VCU₁, VSU₂) elseif Sys.isapple() - (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VfU₁, VfSU₂) #, VSU₃) + (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VA₄, Vfib, VfU₁, VfSU₂) #, VSU₃) else - (Vtr, Vℤ₂, Vfℤ₂, VU₁, VCU₁, VSU₂, VfSU₂) #, VSU₃) + (Vtr, Vℤ₂, Vfℤ₂, VA₄, Vfib, VU₁, VCU₁, VSU₂, VfSU₂) #, VSU₃) end else - (Vtr, VU₁, VSU₂, Vfℤ₂) + (Vtr, VU₁, VSU₂, Vfℤ₂, VA₄) end catch - (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂) #, VSU₃) + (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VA₄, Vfib, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂) #, VSU₃) end for V in spacelist diff --git a/test/setup.jl b/test/setup.jl index c99fbdad1..e84100195 100644 --- a/test/setup.jl +++ b/test/setup.jl @@ -78,9 +78,9 @@ function randsector(::Type{I}) where {I <: Sector} return a end function hasfusiontensor(I::Type{<:Sector}) - isa(UnitStyle(I), GenericUnit) && return false try - TensorKit.fusiontensor(unit(I), unit(I), unit(I)) + u = first(allunits(I)) + TensorKit.fusiontensor(u, u, u) return true catch e if e isa MethodError @@ -145,14 +145,30 @@ function test_dim_isapprox(V::ProductSpace, d::Int) return @test max(0, d - dim_c_max) ≤ dim(V) ≤ d + dim_c_max end -sectorlist = ( +uniquefusionsectorlist = ( Z2Irrep, Z3Irrep, Z4Irrep, Z3Irrep ⊠ Z4Irrep, - U1Irrep, CU1Irrep, SU2Irrep, - FermionParity, FermionParity ⊠ FermionParity, - FermionParity ⊠ U1Irrep ⊠ SU2Irrep, FermionParity ⊠ SU2Irrep ⊠ SU2Irrep, # Hubbard-like - FibonacciAnyon, IsingAnyon, - Z2Irrep ⊠ FibonacciAnyon ⊠ FibonacciAnyon, + U1Irrep, FermionParity, FermionParity ⊠ FermionParity, FermionNumber, + Z3Element{1}, Z4Element{2}, ZNElement{5, 2}, +) +simplefusionsectorlist = ( + CU1Irrep, SU2Irrep, FibonacciAnyon, IsingAnyon, + FermionParity ⊠ U1Irrep ⊠ SU2Irrep, FermionParity ⊠ SU2Irrep ⊠ SU2Irrep, + Z3Element{1} ⊠ FibonacciAnyon ⊠ FibonacciAnyon, +) +genericfusionsectorlist = ( + A4Irrep, A4Irrep ⊠ FermionParity, A4Irrep ⊠ SU2Irrep, + A4Irrep ⊠ Z3Element{2}, A4Irrep ⊠ A4Irrep, +) +multifusionsectorlist = ( IsingBimodule, IsingBimodule ⊠ SU2Irrep, IsingBimodule ⊠ IsingBimodule, + IsingBimodule ⊠ Z3Element{1}, IsingBimodule ⊠ FibonacciAnyon ⊠ A4Irrep, +) + +sectorlist = ( + uniquefusionsectorlist..., + simplefusionsectorlist..., + genericfusionsectorlist..., + multifusionsectorlist..., ) # spaces @@ -178,6 +194,20 @@ Vℤ₃ = ( Vect[Z3Irrep](0 => 1, 1 => 2, 2 => 3), Vect[Z3Irrep](0 => 1, 1 => 3, 2 => 3)', ) +VZ2ω = ( + Vect[Z2Element{1}](0 => 2, 1 => 1), + Vect[Z2Element{1}](0 => 1, 1 => 2)', + Vect[Z2Element{1}](0 => 2, 1 => 1)', + Vect[Z2Element{1}](0 => 2, 1 => 3), + Vect[Z2Element{1}](0 => 2, 1 => 5), +) +VA₄ = ( + Vect[A4Irrep](0 => 1, 1 => 1, 2 => 1, 3 => 3), # dim large enough for truncated factorization tests + Vect[A4Irrep](0 => 1, 1 => 2, 2 => 1, 3 => 1), + Vect[A4Irrep](0 => 1, 1 => 1, 2 => 2, 3 => 1)', + Vect[A4Irrep](0 => 1, 1 => 2, 2 => 2, 3 => 2), + Vect[A4Irrep](0 => 1, 1 => 2, 2 => 2, 3 => 3)', +) VU₁ = ( Vect[U1Irrep](0 => 1, 1 => 2, -1 => 2), Vect[U1Irrep](0 => 3, 1 => 1, -1 => 1), @@ -224,7 +254,7 @@ VSU₂U₁ = ( Vect[SU2Irrep ⊠ U1Irrep]((0, 0) => 1, (1 // 2, 1) => 1)', ) Vfib = ( - Vect[FibonacciAnyon](:I => 1, :τ => 1), + Vect[FibonacciAnyon](:I => 2, :τ => 1), Vect[FibonacciAnyon](:I => 1, :τ => 2)', Vect[FibonacciAnyon](:I => 3, :τ => 2)', Vect[FibonacciAnyon](:I => 2, :τ => 3), diff --git a/test/symmetries/fusiontrees.jl b/test/symmetries/fusiontrees.jl index e5dbf8132..737a15049 100644 --- a/test/symmetries/fusiontrees.jl +++ b/test/symmetries/fusiontrees.jl @@ -105,7 +105,7 @@ using .TestSetup @test length(TK.insertat(f1b, 1, f1a)) == 1 @test first(TK.insertat(f1b, 1, f1a)) == (f1 => 1) - if UnitStyle(I) isa SimpleUnit + if UnitStyle(I) isa SimpleUnit && BraidingStyle(I) isa HasBraiding levels = ntuple(identity, N) function _reinsert_partial_tree(t, f) (t′, c′) = first(TK.insertat(t, 1, f)) diff --git a/test/tensors/diagonal.jl b/test/tensors/diagonal.jl index 76862a6f1..b3e634a7e 100644 --- a/test/tensors/diagonal.jl +++ b/test/tensors/diagonal.jl @@ -4,9 +4,13 @@ using TensorKit diagspacelist = ( (ℂ^4)', Vect[Z2Irrep](0 => 2, 1 => 3), + Vect[Z3Element{1}](0 => 2, 1 => 3, 2 => 1), + Vect[A4Irrep](0 => 1, 1 => 2, 2 => 2, 3 => 2), Vect[FermionNumber](0 => 2, 1 => 2, -1 => 1), Vect[SU2Irrep](0 => 2, 1 => 1)', Vect[FibonacciAnyon](:I => 2, :τ => 2), + Vect[Z3Element{1}](0 => 2, 1 => 2, 2 => 1), + Vect[IsingBimodule](C0 => 2, C1 => 3), ) @testset "DiagonalTensor with domain $V" for V in diagspacelist diff --git a/test/tensors/factorizations.jl b/test/tensors/factorizations.jl index 48dfaf6f1..a786f65ae 100644 --- a/test/tensors/factorizations.jl +++ b/test/tensors/factorizations.jl @@ -10,17 +10,17 @@ spacelist = try if ENV["CI"] == "true" println("Detected running on CI") if Sys.iswindows() - (Vtr, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VIB_diag) + (Vtr, Vℤ₃, VA₄, VU₁, VfU₁, VZ2ω, VCU₁, VSU₂, VIB_diag) elseif Sys.isapple() - (Vtr, Vℤ₃, VfU₁, VfSU₂, VIB_M) + (Vtr, Vℤ₃, VA₄, Vfib, VZ2ω, VfU₁, VfSU₂, VIB_M) else - (Vtr, VU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M) + (Vtr, VA₄, Vfib, VU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M) end else - (Vtr, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M) + (Vtr, Vℤ₃, VA₄, Vfib, VZ2ω, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M) end catch - (Vtr, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M) + (Vtr, Vℤ₃, VA₄, Vfib, VZ2ω, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M) end eltypes = (Float32, ComplexF64) diff --git a/test/tensors/tensors.jl b/test/tensors/tensors.jl index 813c25ea5..c6b639d21 100644 --- a/test/tensors/tensors.jl +++ b/test/tensors/tensors.jl @@ -11,17 +11,17 @@ spacelist = try if get(ENV, "CI", "false") == "true" println("Detected running on CI") if Sys.iswindows() - (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VIB_diag) + (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VA₄, VU₁, VfU₁, VCU₁, VSU₂, VIB_diag) elseif Sys.isapple() - (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VfU₁, VfSU₂, VSU₂U₁, VIB_M) #, VSU₃) + (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VA₄, VfU₁, VfSU₂, VSU₂U₁, VIB_M) else - (Vtr, Vℤ₂, Vfℤ₂, VU₁, VCU₁, VSU₂, VfSU₂, VSU₂U₁, VIB_diag, VIB_M) #, VSU₃) + (Vtr, Vℤ₂, Vfℤ₂, VA₄, VU₁, VCU₁, VSU₂, VfSU₂, VSU₂U₁, VIB_diag, VIB_M) end else - (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VSU₂U₁, VIB_diag, VIB_M) #, VSU₃) + (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VA₄, Vfib, VZ2ω, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VSU₂U₁, VIB_diag, VIB_M) end catch - (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VSU₂U₁, VIB_diag, VIB_M) #, VSU₃) + (Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VA₄, Vfib, VZ2ω, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VSU₂U₁, VIB_diag, VIB_M) end for V in spacelist @@ -53,6 +53,8 @@ for V in spacelist @test space(t) == (W ← one(W)) @test domain(t) == one(W) @test typeof(t) == TensorMap{T, spacetype(t), 5, 0, Vector{T}} + @test complex(t) == real(t) + im * imag(t) + @test T <: Real ? real(t) == t : complex(t) == t # blocks bs = @constinferred blocks(t) if !isempty(blocksectors(t)) # multifusion space ending on module gives empty data @@ -157,6 +159,21 @@ for V in spacelist @test dim(w) == 2 * dim(V1 ← V1) @test w' * w == id(Vector{T}, V1) @test w * w' == (w * w')^2 + + # concatenation + t3 = rand(T, V1 ⊗ V2 ← V2) + t3data2 = T[] + for c in blocksectors(t3) + append!(t3data2, repeat(block(t3, c), 1, 2)) + end + @test @constinferred(catdomain(t3, t3)) == TensorMap(t3data2, V1 ⊗ V2 ← V2 ⊕ V2) + + t4 = rand(T, V2 ← V1 ⊗ V2) + t4data2 = T[] + for c in blocksectors(t4) + append!(t4data2, repeat(block(t4, c), 2, 1)) + end + @test @constinferred(catcodomain(t4, t4)) == TensorMap(t4data2, V2 ⊕ V2 ← V1 ⊗ V2) end end @timedtestset "Trivial space insertion and removal" begin @@ -242,13 +259,14 @@ for V in spacelist @test Base.promote_typeof(tc, t) == typeof(tc + t) end symmetricbraiding && @timedtestset "Permutations: test via inner product invariance" begin - W = V1 ⊗ V2 ⊗ V3 ⊗ V4 ⊗ V5 + W = V1 ⊗ V2 ⊗ V3 ⊗ V4 + n = length(W) t = rand(ComplexF64, W) t′ = randn!(similar(t)) - for k in 0:5 - for p in permutations(1:5) + for k in 0:n + for p in permutations(1:n) p1 = ntuple(n -> p[n], k) - p2 = ntuple(n -> p[k + n], 5 - k) + p2 = ntuple(n -> p[k + n], n - k) t2 = @constinferred permute(t, (p1, p2)) @test norm(t2) ≈ norm(t) t2′ = permute(t′, (p1, p2)) @@ -264,24 +282,25 @@ for V in spacelist end if BraidingStyle(I) isa Bosonic && hasfusiontensor(I) @timedtestset "Permutations: test via conversion" begin - W = V1 ⊗ V2 ⊗ V3 ⊗ V4 ⊗ V5 + W = V1 ⊗ V2 ⊗ V3 ⊗ V4 + N = length(W) t = rand(ComplexF64, W) a = convert(Array, t) - for k in 0:5 - for p in permutations(1:5) + for k in 0:N + for p in permutations(1:N) p1 = ntuple(n -> p[n], k) - p2 = ntuple(n -> p[k + n], 5 - k) + p2 = ntuple(n -> p[k + n], N - k) t2 = permute(t, (p1, p2)) a2 = convert(Array, t2) @test a2 ≈ permutedims(a, (p1..., p2...)) @test convert(Array, transpose(t2)) ≈ - permutedims(a2, (5, 4, 3, 2, 1)) + permutedims(a2, reverse(ntuple(i -> i, N))) end t3 = repartition(t, k) a3 = convert(Array, t3) @test a3 ≈ permutedims( - a, (ntuple(identity, k)..., reverse(ntuple(i -> i + k, 5 - k))...) + a, (ntuple(identity, k)..., reverse(ntuple(i -> i + k, N - k))...) ) end end @@ -545,9 +564,17 @@ for V in spacelist if UnitStyle(I) isa SimpleUnit || !isempty(blocksectors(V2 ⊗ V1)) t1 = rand(T, V2 ⊗ V3 ⊗ V1, V1 ⊗ V2) t2 = rand(T, V2 ⊗ V1 ⊗ V3, V1 ⊗ V1) + if dim(t1) * dim(t2) > 1.0e7 # make t1⊗t2 factor dim(V3)^2 smaller + t1 = rand(T, V2 ⊗ V1, V1 ⊗ V2) + t2 = rand(T, V2 ⊗ V1, V1 ⊗ V1) + end else t1 = rand(T, V3 ⊗ V4 ⊗ V5, V1 ⊗ V2) t2 = rand(T, V5' ⊗ V4' ⊗ V3', V2' ⊗ V1') + if dim(t1) * dim(t2) > 1.0e7 # make t1⊗t2 factor dim(V5)^2 smaller + t1 = rand(T, V3 ⊗ V4, V1 ⊗ V2) + t2 = rand(T, V4' ⊗ V3', V2' ⊗ V1') + end end t = @constinferred (t1 ⊗ t2) @test norm(t) ≈ norm(t1) * norm(t2)