diff --git a/Project.toml b/Project.toml index 7e30fd805..865f4dd0e 100644 --- a/Project.toml +++ b/Project.toml @@ -33,7 +33,7 @@ LinearAlgebra = "1" PackageExtensionCompat = "1" Random = "1" Strided = "2" -TensorKitSectors = "0.1.4, 0.2" +TensorKitSectors = "0.3" TensorOperations = "5.1" Test = "1" TestExtras = "0.2,0.3" diff --git a/docs/src/lib/spaces.md b/docs/src/lib/spaces.md index 83350156d..0eae17fe7 100644 --- a/docs/src/lib/spaces.md +++ b/docs/src/lib/spaces.md @@ -91,7 +91,7 @@ conj flip ⊕ zero(::ElementarySpace) -oneunit +unitspace supremum infimum ``` @@ -111,9 +111,9 @@ isisomorphic Inserting trivial space factors or removing such factors for `ProductSpace` instances can be done with the following methods. ```@docs -insertleftunit(::ProductSpace, ::Val{i}) where {i} -insertrightunit(::ProductSpace, ::Val{i}) where {i} -removeunit(::ProductSpace, ::Val{i}) where {i} +insertleftunitspace(::ProductSpace, ::Val{i}) where {i} +insertrightunitspace(::ProductSpace, ::Val{i}) where {i} +removeunitspace(::ProductSpace, ::Val{i}) where {i} ``` There are also specific methods for `HomSpace` instances, that are used in determining @@ -124,7 +124,7 @@ flip(W::HomSpace{S}, I) where {S} TensorKit.permute(::HomSpace{S}, ::Index2Tuple{N₁,N₂}) where {S,N₁,N₂} TensorKit.select(::HomSpace{S}, ::Index2Tuple{N₁,N₂}) where {S,N₁,N₂} TensorKit.compose(::HomSpace{S}, ::HomSpace{S}) where {S} -insertleftunit(::HomSpace, ::Val{i}) where {i} -insertrightunit(::HomSpace, ::Val{i}) where {i} -removeunit(::HomSpace, ::Val{i}) where {i} +insertleftunitspace(::HomSpace, ::Val{i}) where {i} +insertrightunitspace(::HomSpace, ::Val{i}) where {i} +removeunitspace(::HomSpace, ::Val{i}) where {i} ``` diff --git a/docs/src/lib/tensors.md b/docs/src/lib/tensors.md index 51b9bcf13..44f30dc27 100644 --- a/docs/src/lib/tensors.md +++ b/docs/src/lib/tensors.md @@ -184,9 +184,9 @@ transpose(::AbstractTensorMap, ::Index2Tuple) repartition(::AbstractTensorMap, ::Int, ::Int) flip(t::AbstractTensorMap, I) twist(::AbstractTensorMap, ::Int) -insertleftunit(::AbstractTensorMap, ::Val{i}) where {i} -insertrightunit(::AbstractTensorMap, ::Val{i}) where {i} -removeunit(::AbstractTensorMap, ::Val{i}) where {i} +insertleftunitspace(::AbstractTensorMap, ::Val{i}) where {i} +insertrightunitspace(::AbstractTensorMap, ::Val{i}) where {i} +removeunitspace(::AbstractTensorMap, ::Val{i}) where {i} ``` ```@docs diff --git a/docs/src/man/spaces.md b/docs/src/man/spaces.md index 503730bfe..ff2d5990f 100644 --- a/docs/src/man/spaces.md +++ b/docs/src/man/spaces.md @@ -316,19 +316,18 @@ flip(ℂ^4) == ℂ^4 ``` We also define the direct sum `V1` and `V2` as `V1 ⊕ V2`, where `⊕` is obtained by typing -`\oplus`+TAB. This is possible only if `isdual(V1) == isdual(V2)`. With a little pun on -Julia Base, `oneunit` applied to an elementary space (in the value or type domain) returns -the one-dimensional space, which is isomorphic to the scalar field of the space itself. Some -examples illustrate this better +`\oplus`+TAB. This is possible only if `isdual(V1) == isdual(V2)`. `unitspace` applied to an elementary space +(in the value or type domain) returns the one-dimensional space, which is isomorphic to the +scalar field of the space itself. Some examples illustrate this better. ```@repl tensorkit ℝ^5 ⊕ ℝ^3 ℂ^5 ⊕ ℂ^3 ℂ^5 ⊕ (ℂ^3)' -oneunit(ℝ^3) -ℂ^5 ⊕ oneunit(ComplexSpace) -oneunit((ℂ^3)') -(ℂ^5) ⊕ oneunit((ℂ^5)) -(ℂ^5)' ⊕ oneunit((ℂ^5)') +unitspace(ℝ^3) +ℂ^5 ⊕ unitspace(ComplexSpace) +unitspace((ℂ^3)') +(ℂ^5) ⊕ unitspace((ℂ^5)) +(ℂ^5)' ⊕ unitspace((ℂ^5)') ``` Finally, while spaces have a partial order, there is no unique infimum or supremum of a two diff --git a/src/TensorKit.jl b/src/TensorKit.jl index 96a579e25..b0cde57b9 100644 --- a/src/TensorKit.jl +++ b/src/TensorKit.jl @@ -11,13 +11,16 @@ module TensorKit export Sector, AbstractIrrep, Irrep export FusionStyle, UniqueFusion, MultipleFusion, MultiplicityFreeFusion, SimpleFusion, GenericFusion +export UnitStyle, SimpleUnit, GenericUnit export BraidingStyle, SymmetricBraiding, Bosonic, Fermionic, Anyonic, NoBraiding export Trivial, Z2Irrep, Z3Irrep, Z4Irrep, ZNIrrep, U1Irrep, SU2Irrep, CU1Irrep export ProductSector export FermionParity, FermionNumber, FermionSpin -export FibonacciAnyon, IsingAnyon +export FibonacciAnyon, IsingAnyon, IsingBimodule +export unit, rightunit, leftunit, allunits, isunit export VectorSpace, Field, ElementarySpace # abstract vector spaces +export unitspace, zerospace, leftunitspace, rightunitspace export InnerProductStyle, NoInnerProduct, HasInnerProduct, EuclideanInnerProduct export ComplexSpace, CartesianSpace, GeneralSpace, GradedSpace # concrete spaces export ZNSpace, Z2Space, Z3Space, Z4Space, U1Space, CU1Space, SU2Space @@ -32,7 +35,7 @@ export SpaceMismatch, SectorMismatch, IndexError # error types # general vector space methods export space, field, dual, dim, reduceddim, dims, fuse, flip, isdual, oplus, - insertleftunit, insertrightunit, removeunit + insertleftunitspace, insertrightunitspace, removeunitspace # partial order for vector spaces export infimum, supremum, isisomorphic, ismonomorphic, isepimorphic diff --git a/src/auxiliary/deprecate.jl b/src/auxiliary/deprecate.jl index fa7667b2b..efa83f0e7 100644 --- a/src/auxiliary/deprecate.jl +++ b/src/auxiliary/deprecate.jl @@ -56,6 +56,6 @@ end Base.@deprecate EuclideanProduct() EuclideanInnerProduct() -Base.@deprecate insertunit(P::ProductSpace, args...; kwargs...) insertleftunit(args...; kwargs...) +Base.@deprecate insertunit(P::ProductSpace, args...; kwargs...) insertleftunitspace(args...; kwargs...) #! format: on diff --git a/src/fusiontrees/fusiontrees.jl b/src/fusiontrees/fusiontrees.jl index 3e694e523..d90e2ec07 100644 --- a/src/fusiontrees/fusiontrees.jl +++ b/src/fusiontrees/fusiontrees.jl @@ -32,7 +32,7 @@ struct FusionTree{I<:Sector,N,M,L} vertices::NTuple{L,Int}) where {I<:Sector,N,M,L} # if N == 0 - # @assert coupled == one(coupled) + # @assert coupled == unit(coupled) # elseif N == 1 # @assert coupled == uncoupled[1] # elseif N == 2 @@ -78,7 +78,7 @@ function FusionTree(uncoupled::NTuple{N,I}, coupled::I, end end -function FusionTree{I}(uncoupled::NTuple{N}, coupled=one(I), +function FusionTree{I}(uncoupled::NTuple{N}, coupled=unit(I), isdual=ntuple(n -> false, N)) where {I<:Sector,N} FusionStyle(I) isa UniqueFusion || error("fusion tree requires inner lines if `FusionStyle(I) <: MultipleFusion`") @@ -90,7 +90,7 @@ function FusionTree(uncoupled::NTuple{N,I}, coupled::I, isdual=ntuple(n -> false, length(uncoupled))) where {N,I<:Sector} return FusionTree{I}(uncoupled, coupled, isdual) end -FusionTree(uncoupled::Tuple{I,Vararg{I}}) where {I<:Sector} = FusionTree(uncoupled, one(I)) +FusionTree(uncoupled::Tuple{I,Vararg{I}}) where {I<:Sector} = FusionTree(uncoupled, unit(I)) # Properties sectortype(::Type{<:FusionTree{I}}) where {I<:Sector} = I @@ -146,17 +146,17 @@ end # converting to actual array function Base.convert(A::Type{<:AbstractArray}, f::FusionTree{I,0}) where {I} - X = convert(A, fusiontensor(one(I), one(I), one(I)))[1, 1, :] + X = convert(A, fusiontensor(unit(I), unit(I), unit(I)))[1, 1, :] return X end function Base.convert(A::Type{<:AbstractArray}, f::FusionTree{I,1}) where {I} c = f.coupled if f.isdual[1] sqrtdc = sqrtdim(c) - Zcbartranspose = sqrtdc * convert(A, fusiontensor(conj(c), c, one(c)))[:, :, 1, 1] + Zcbartranspose = sqrtdc * convert(A, fusiontensor(dual(c), c, unit(c)))[:, :, 1, 1] X = conj!(Zcbartranspose) # we want Zcbar^† else - X = convert(A, fusiontensor(c, one(c), c))[:, 1, :, 1, 1] + X = convert(A, fusiontensor(c, unit(c), c))[:, 1, :, 1, 1] end return X end @@ -234,13 +234,13 @@ include("iterator.jl") # _abelianinner: generate the inner indices for given outer indices in the abelian case _abelianinner(outer::Tuple{}) = () function _abelianinner(outer::Tuple{I}) where {I<:Sector} - return isone(outer[1]) ? () : throw(SectorMismatch()) + return isunit(outer[1]) ? () : throw(SectorMismatch()) end function _abelianinner(outer::Tuple{I,I}) where {I<:Sector} return outer[1] == dual(outer[2]) ? () : throw(SectorMismatch()) end function _abelianinner(outer::Tuple{I,I,I}) where {I<:Sector} - return isone(first(⊗(outer...))) ? () : throw(SectorMismatch()) + return isunit(first(⊗(outer...))) ? () : throw(SectorMismatch()) end function _abelianinner(outer::Tuple{I,I,I,I,Vararg{I}}) where {I<:Sector} c = first(outer[1] ⊗ outer[2]) diff --git a/src/fusiontrees/iterator.jl b/src/fusiontrees/iterator.jl index 7e7106daf..6ebd8d965 100644 --- a/src/fusiontrees/iterator.jl +++ b/src/fusiontrees/iterator.jl @@ -1,6 +1,6 @@ """ fusiontrees(uncoupled::NTuple{N,I}[, - coupled::I=one(I)[, isdual::NTuple{N,Bool}=ntuple(n -> false, length(uncoupled))]]) + coupled::I=unit(I)[, isdual::NTuple{N,Bool}=ntuple(n -> false, length(uncoupled))]]) where {N,I<:Sector} -> FusionTreeIterator{I,N,I} Return an iterator over all fusion trees with a given coupled sector label `coupled` and @@ -16,7 +16,7 @@ function fusiontrees(uncoupled::Tuple{Vararg{I}}, coupled::I) where {I<:Sector} return fusiontrees(uncoupled, coupled, isdual) end function fusiontrees(uncoupled::Tuple{I,Vararg{I}}) where {I<:Sector} - coupled = one(I) + coupled = unit(I) isdual = ntuple(n -> false, length(uncoupled)) return fusiontrees(uncoupled, coupled, isdual) end @@ -37,7 +37,7 @@ Base.IteratorEltype(::FusionTreeIterator) = Base.HasEltype() Base.eltype(::Type{<:FusionTreeIterator{I,N}}) where {I<:Sector,N} = fusiontreetype(I, N) Base.length(iter::FusionTreeIterator) = _fusiondim(iter.uncouplediterators, iter.coupled) -_fusiondim(::Tuple{}, c::I) where {I<:Sector} = Int(isone(c)) +_fusiondim(::Tuple{}, c::I) where {I<:Sector} = Int(isunit(c)) _fusiondim(iters::NTuple{1}, c::I) where {I<:Sector} = Int(c ∈ iters[1]) function _fusiondim(iters::NTuple{2}, c::I) where {I<:Sector} d = 0 @@ -60,7 +60,7 @@ end # * Iterator methods: # Start with special cases: function Base.iterate(it::FusionTreeIterator{I,0}, - state=!isone(it.coupled)) where {I<:Sector} + state=!isunit(it.coupled)) where {I<:Sector} state && return nothing tree = FusionTree{I}((), it.coupled, (), (), ()) return tree, true diff --git a/src/fusiontrees/manipulations.jl b/src/fusiontrees/manipulations.jl index f19bb06ed..c47deb99d 100644 --- a/src/fusiontrees/manipulations.jl +++ b/src/fusiontrees/manipulations.jl @@ -165,7 +165,7 @@ operation is the inverse of `insertat` in the sense that if f₂ = FusionTree{I}(f.uncoupled, f.coupled, isdual2, f.innerlines, f.vertices) return f₁, f₂ elseif M === 0 - u = leftone(f.uncoupled[1]) + u = leftunit(f.uncoupled[1]) f₁ = FusionTree{I}((), u, (), ()) uncoupled2 = (u, f.uncoupled...) coupled2 = f.coupled @@ -290,7 +290,7 @@ function bendright(f₁::FusionTree{I,N₁}, f₂::FusionTree{I,N₂}) where {I< # map final splitting vertex (a, b)<-c to fusion vertex a<-(c, dual(b)) @assert N₁ > 0 c = f₁.coupled - a = N₁ == 1 ? leftone(f₁.uncoupled[1]) : + a = N₁ == 1 ? leftunit(f₁.uncoupled[1]) : (N₁ == 2 ? f₁.uncoupled[1] : f₁.innerlines[end]) b = f₁.uncoupled[N₁] @@ -362,7 +362,7 @@ function foldright(f₁::FusionTree{I,N₁}, f₂::FusionTree{I,N₂}) where {I< hasmultiplicities = FusionStyle(a) isa GenericFusion local newtrees if N₁ == 1 - cset = (leftone(c1),) # or rightone(a) + cset = (leftunit(c1),) # or rightunit(a) elseif N₁ == 2 cset = (f₁.uncoupled[2],) else @@ -373,7 +373,7 @@ function foldright(f₁::FusionTree{I,N₁}, f₂::FusionTree{I,N₂}) where {I< for μ in 1:Nsymbol(c1, c2, c) fc = FusionTree((c1, c2), c, (!isduala, false), (), (μ,)) for (fl′, coeff1) in insertat(fc, 2, f₁) - N₁ > 1 && !isone(fl′.innerlines[1]) && continue + N₁ > 1 && !isunit(fl′.innerlines[1]) && continue coupled = fl′.coupled uncoupled = Base.tail(Base.tail(fl′.uncoupled)) isdual = Base.tail(Base.tail(fl′.isdual)) @@ -718,7 +718,7 @@ corresponding coefficients. function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} (N > 1 && 1 <= i <= N) || throw(ArgumentError("Cannot trace outputs i=$i and i+1 out of only $N outputs")) - i < N || isone(f.coupled) || + i < N || isunit(f.coupled) || throw(ArgumentError("Cannot trace outputs i=$N and 1 of fusion tree that couples to non-trivial sector")) T = sectorscalartype(I) @@ -731,7 +731,7 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} # if trace is zero, return empty dict (b == dual(b′) && f.isdual[i] != f.isdual[j]) || return newtrees if i < N - inner_extended = (leftone(f.uncoupled[1]), f.uncoupled[1], f.innerlines..., + inner_extended = (leftunit(f.uncoupled[1]), f.uncoupled[1], f.innerlines..., f.coupled) a = inner_extended[i] d = inner_extended[i + 2] @@ -756,11 +756,11 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} if i > 1 c = f.innerlines[i - 1] if FusionStyle(I) isa MultiplicityFreeFusion - coeff *= Fsymbol(a, b, dual(b), a, c, rightone(a)) + coeff *= Fsymbol(a, b, dual(b), a, c, rightunit(a)) else μ = f.vertices[i - 1] ν = f.vertices[i] - coeff *= Fsymbol(a, b, dual(b), a, c, rightone(a))[μ, ν, 1, 1] + coeff *= Fsymbol(a, b, dual(b), a, c, rightunit(a))[μ, ν, 1, 1] end end if f.isdual[i] @@ -769,7 +769,7 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} push!(newtrees, f′ => coeff) return newtrees else # i == N - unit = leftone(b) + unit = leftunit(b) if N == 2 f′ = FusionTree{I}((), unit, (), (), ()) coeff = sqrtdim(b) @@ -786,13 +786,13 @@ function elementary_trace(f::FusionTree{I,N}, i) where {I<:Sector,N} vertices_ = TupleTools.front(f.vertices) f_ = FusionTree(uncoupled_, coupled_, isdual_, inner_, vertices_) fs = FusionTree((b,), b, (!f.isdual[1],), (), ()) - for (f_′, coeff) in merge(fs, f_, unit, 1) # coloring gets reversed here, should be the other unit + for (f_′, coeff) in merge(fs, f_, unit, 1) f_′.innerlines[1] == unit || continue uncoupled′ = Base.tail(Base.tail(f_′.uncoupled)) isdual′ = Base.tail(Base.tail(f_′.isdual)) inner′ = N <= 4 ? () : Base.tail(Base.tail(f_′.innerlines)) vertices′ = N <= 3 ? () : Base.tail(Base.tail(f_′.vertices)) - f′ = FusionTree(uncoupled′, unit, isdual′, inner′, vertices′) # and this one? + f′ = FusionTree(uncoupled′, unit, isdual′, inner′, vertices′) coeff *= sqrtdim(b) if !(f.isdual[N]) coeff *= conj(frobeniusschur(b)) @@ -835,13 +835,13 @@ function artin_braid(f::FusionTree{I,N}, i; inv::Bool=false) where {I<:Sector,N} vertices = f.vertices oneT = one(sectorscalartype(I)) - if isone(uncoupled[i]) || isone(uncoupled[i + 1]) + if isunit(a) || isunit(b) # braiding with trivial sector: simple and always possible inner′ = inner vertices′ = vertices if i > 1 # we also need to alter innerlines and vertices inner′ = TupleTools.setindex(inner, - inner_extended[isone(a) ? (i + 1) : (i - 1)], + inner_extended[isunit(a) ? (i + 1) : (i - 1)], i - 1) vertices′ = TupleTools.setindex(vertices′, vertices[i], i - 1) vertices′ = TupleTools.setindex(vertices′, vertices[i - 1], i) @@ -898,7 +898,7 @@ function artin_braid(f::FusionTree{I,N}, i; inv::Bool=false) where {I<:Sector,N} return fusiontreedict(I)(f′ => coeff) elseif FusionStyle(I) isa SimpleFusion local newtrees - for c′ in intersect(a ⊗ d, e ⊗ conj(b)) + for c′ in intersect(a ⊗ d, e ⊗ dual(b)) coeff = oftype(oneT, if inv conj(Rsymbol(d, c, e) * Fsymbol(d, a, b, e, c′, c)) * @@ -919,7 +919,7 @@ function artin_braid(f::FusionTree{I,N}, i; inv::Bool=false) where {I<:Sector,N} return newtrees else # GenericFusion local newtrees - for c′ in intersect(a ⊗ d, e ⊗ conj(b)) + for c′ in intersect(a ⊗ d, e ⊗ dual(b)) Rmat1 = inv ? Rsymbol(d, c, e)' : Rsymbol(c, d, e) Rmat2 = inv ? Rsymbol(d, a, c′)' : Rsymbol(a, d, c′) Fmat = Fsymbol(d, a, b, e, c′, c) diff --git a/src/spaces/cartesianspace.jl b/src/spaces/cartesianspace.jl index f29ed263d..7f27e86a6 100644 --- a/src/spaces/cartesianspace.jl +++ b/src/spaces/cartesianspace.jl @@ -47,8 +47,8 @@ hassector(V::CartesianSpace, ::Trivial) = dim(V) != 0 sectors(V::CartesianSpace) = OneOrNoneIterator(dim(V) != 0, Trivial()) sectortype(::Type{CartesianSpace}) = Trivial -Base.oneunit(::Type{CartesianSpace}) = CartesianSpace(1) -Base.zero(::Type{CartesianSpace}) = CartesianSpace(0) +unitspace(::Type{CartesianSpace}) = CartesianSpace(1) +zerospace(::Type{CartesianSpace}) = CartesianSpace(0) ⊕(V₁::CartesianSpace, V₂::CartesianSpace) = CartesianSpace(V₁.d + V₂.d) fuse(V₁::CartesianSpace, V₂::CartesianSpace) = CartesianSpace(V₁.d * V₂.d) flip(V::CartesianSpace) = V diff --git a/src/spaces/complexspace.jl b/src/spaces/complexspace.jl index ff05888b8..1ecdb46b7 100644 --- a/src/spaces/complexspace.jl +++ b/src/spaces/complexspace.jl @@ -48,8 +48,8 @@ sectortype(::Type{ComplexSpace}) = Trivial Base.conj(V::ComplexSpace) = ComplexSpace(dim(V), !isdual(V)) -Base.oneunit(::Type{ComplexSpace}) = ComplexSpace(1) -Base.zero(::Type{ComplexSpace}) = ComplexSpace(0) +unitspace(::Type{ComplexSpace}) = ComplexSpace(1) +zerospace(::Type{ComplexSpace}) = ComplexSpace(0) function ⊕(V₁::ComplexSpace, V₂::ComplexSpace) return isdual(V₁) == isdual(V₂) ? ComplexSpace(dim(V₁) + dim(V₂), isdual(V₁)) : diff --git a/src/spaces/deligne.jl b/src/spaces/deligne.jl index f9cc51c8e..27d5703be 100644 --- a/src/spaces/deligne.jl +++ b/src/spaces/deligne.jl @@ -23,7 +23,7 @@ function ⊠(V::GradedSpace, P₀::ProductSpace{<:ElementarySpace,0}) field(V) == field(P₀) || throw_incompatible_fields(V, P₀) I₁ = sectortype(V) I₂ = sectortype(P₀) - return Vect[I₁ ⊠ I₂](ifelse(isdual(V), dual(c), c) ⊠ one(I₂) => dim(V, c) + return Vect[I₁ ⊠ I₂](ifelse(isdual(V), dual(c), c) ⊠ unit(I₂) => dim(V, c) for c in sectors(V); dual=isdual(V)) end @@ -31,20 +31,20 @@ function ⊠(P₀::ProductSpace{<:ElementarySpace,0}, V::GradedSpace) field(P₀) == field(V) || throw_incompatible_fields(P₀, V) I₁ = sectortype(P₀) I₂ = sectortype(V) - return Vect[I₁ ⊠ I₂](one(I₁) ⊠ ifelse(isdual(V), dual(c), c) => dim(V, c) + return Vect[I₁ ⊠ I₂](unit(I₁) ⊠ ifelse(isdual(V), dual(c), c) => dim(V, c) for c in sectors(V); dual=isdual(V)) end function ⊠(V::ComplexSpace, P₀::ProductSpace{<:ElementarySpace,0}) field(V) == field(P₀) || throw_incompatible_fields(V, P₀) I₂ = sectortype(P₀) - return Vect[I₂](one(I₂) => dim(V); dual=isdual(V)) + return Vect[I₂](unit(I₂) => dim(V); dual=isdual(V)) end function ⊠(P₀::ProductSpace{<:ElementarySpace,0}, V::ComplexSpace) field(P₀) == field(V) || throw_incompatible_fields(P₀, V) I₁ = sectortype(P₀) - return Vect[I₁](one(I₁) => dim(V); dual=isdual(V)) + return Vect[I₁](unit(I₁) => dim(V); dual=isdual(V)) end function ⊠(P::ProductSpace{<:ElementarySpace,0}, P₀::ProductSpace{<:ElementarySpace,0}) diff --git a/src/spaces/generalspace.jl b/src/spaces/generalspace.jl index c72b55e70..4459db051 100644 --- a/src/spaces/generalspace.jl +++ b/src/spaces/generalspace.jl @@ -35,8 +35,8 @@ sectortype(::Type{<:GeneralSpace}) = Trivial field(::Type{GeneralSpace{𝔽}}) where {𝔽} = 𝔽 InnerProductStyle(::Type{<:GeneralSpace}) = NoInnerProduct() -Base.oneunit(::Type{GeneralSpace{𝔽}}) where {𝔽} = GeneralSpace{𝔽}(1, false, false) -Base.zero(::Type{GeneralSpace{𝔽}}) where {𝔽} = GeneralSpace{𝔽}(0, false, false) +unitspace(::Type{GeneralSpace{𝔽}}) where {𝔽} = GeneralSpace{𝔽}(1, false, false) +zerospace(::Type{GeneralSpace{𝔽}}) where {𝔽} = GeneralSpace{𝔽}(0, false, false) dual(V::GeneralSpace{𝔽}) where {𝔽} = GeneralSpace{𝔽}(dim(V), !isdual(V), isconj(V)) Base.conj(V::GeneralSpace{𝔽}) where {𝔽} = GeneralSpace{𝔽}(dim(V), isdual(V), !isconj(V)) diff --git a/src/spaces/gradedspace.jl b/src/spaces/gradedspace.jl index 63903a1ac..97c964361 100644 --- a/src/spaces/gradedspace.jl +++ b/src/spaces/gradedspace.jl @@ -91,8 +91,9 @@ Base.hash(V::GradedSpace, h::UInt) = hash(V.dual, hash(V.dims, h)) field(::Type{<:GradedSpace}) = ℂ InnerProductStyle(::Type{<:GradedSpace}) = EuclideanInnerProduct() function dim(V::GradedSpace) + T = Base.promote_op(*, Int, real(sectorscalartype(sectortype(V)))) #FIXME: doesn't work return reduce(+, dim(V, c) * dim(c) for c in sectors(V); - init=zero(dim(one(sectortype(V))))) + init=zero(T)) end function dim(V::GradedSpace{I,<:AbstractDict}, c::I) where {I<:Sector} return get(V.dims, isdual(V) ? dual(c) : c, 0) @@ -131,8 +132,58 @@ function Base.axes(V::GradedSpace{I}, c::I) where {I<:Sector} return (offset + 1):(offset + dim(c) * dim(V, c)) end -Base.oneunit(S::Type{<:GradedSpace{I}}) where {I<:Sector} = S(one(I) => 1) -Base.zero(S::Type{<:GradedSpace{I}}) where {I<:Sector} = S(one(I) => 0) +""" + leftunitspace(S::GradedSpace{I}) where {I<:Sector} -> GradedSpace{I} + +Return the corresponding vector space of type `GradedSpace{I}` that represents the trivial +one-dimensional space consisting of the left unit of the objects in `Sector` `I`. +""" +function leftunitspace(S::GradedSpace{I}) where {I<:Sector} + if UnitStyle(I) isa SimpleUnit + return unitspace(typeof(S)) + else + !isempty(sectors(S)) || throw(ArgumentError("Cannot determine type of empty space")) + allequal(a.row for a in sectors(S)) || + throw(ArgumentError("sectors of $S do not have the same left unit")) + + sector = leftunit(first(sectors(S))) + return spacetype(S)(sector => 1) + end +end + +""" + rightunitspace(S::GradedSpace{I}) where {I<:Sector} -> GradedSpace{I} + +Return the corresponding vector space of type `GradedSpace{I}` that represents the trivial +one-dimensional space consisting of the right unit of the objects in `Sector` `I`. +""" +function rightunitspace(S::GradedSpace{I}) where {I<:Sector} + if UnitStyle(I) isa SimpleUnit + return unitspace(typeof(S)) + else + !isempty(sectors(S)) || throw(ArgumentError("Cannot determine type of empty space")) + allequal(a.row for a in sectors(S)) || + throw(ArgumentError("sectors of $S do not have the same right unit")) + + sector = rightunit(first(sectors(S))) + return spacetype(S)(sector => 1) + end +end + +function unitspace(S::Type{<:GradedSpace{I}}) where {I<:Sector} + if UnitStyle(I) isa SimpleUnit + return S(unit(I) => 1) + else + return S(unit => 1 for unit in allunits(I)) + end +end +function zerospace(S::Type{<:GradedSpace{I}}) where {I<:Sector} + if UnitStyle(I) isa SimpleUnit + return S(unit(I) => 0) + else + return S(unit => 0 for unit in allunits(I)) + end +end # TODO: the following methods can probably be implemented more efficiently for # `FiniteGradedSpace`, but we don't expect them to be used often in hot loops, so diff --git a/src/spaces/homspace.jl b/src/spaces/homspace.jl index 92188b9ef..04f178770 100644 --- a/src/spaces/homspace.jl +++ b/src/spaces/homspace.jl @@ -22,7 +22,7 @@ end function HomSpace(codomain::S, domain::S) where {S<:ElementarySpace} return HomSpace(⊗(codomain), ⊗(domain)) end -HomSpace(codomain::VectorSpace) = HomSpace(codomain, zero(codomain)) +HomSpace(codomain::VectorSpace) = HomSpace(codomain, zerospace(codomain)) codomain(W::HomSpace) = W.codomain domain(W::HomSpace) = W.domain @@ -94,11 +94,16 @@ function blocksectors(W::HomSpace) N₁ = length(codom) N₂ = length(dom) I = sectortype(W) - # TODO: is sort! still necessary now that blocksectors of ProductSpace is sorted? - if N₂ <= N₁ - return sort!(filter!(c -> hasblock(codom, c), blocksectors(dom))) + if N₁ == 0 && N₂ == 0 + return allunits(I) + elseif N₁ == 0 + return filter!(isone, collect(blocksectors(dom))) # module space cannot end in empty space + elseif N₂ == 0 + return filter!(isone, collect(blocksectors(codom))) + elseif N₂ <= N₁ + return filter!(c -> hasblock(codom, c), collect(blocksectors(dom))) else - return sort!(filter!(c -> hasblock(dom, c), blocksectors(codom))) + return filter!(c -> hasblock(dom, c), collect(blocksectors(codom))) end end @@ -187,58 +192,58 @@ function compose(W::HomSpace{S}, V::HomSpace{S}) where {S} end """ - insertleftunit(W::HomSpace, i=numind(W) + 1; conj=false, dual=false) + insertleftunitspace(W::HomSpace, i=numind(W) + 1; conj=false, dual=false) Insert a trivial vector space, isomorphic to the underlying field, at position `i`, which can be specified as an `Int` or as `Val(i)` for improved type stability. More specifically, adds a left monoidal unit or its dual. -See also [`insertrightunit`](@ref insertrightunit(::HomSpace, ::Val{i}) where {i}), -[`removeunit`](@ref removeunit(::HomSpace, ::Val{i}) where {i}). +See also [`insertrightunitspace`](@ref insertrightunitspace(::HomSpace, ::Val{i}) where {i}), +[`removeunitspace`](@ref removeunitspace(::HomSpace, ::Val{i}) where {i}). """ -function insertleftunit(W::HomSpace, ::Val{i}=Val(numind(W) + 1); +function insertleftunitspace(W::HomSpace, ::Val{i}=Val(numind(W) + 1); conj::Bool=false, dual::Bool=false) where {i} if i ≤ numout(W) - return insertleftunit(codomain(W), Val(i); conj, dual) ← domain(W) + return insertleftunitspace(codomain(W), Val(i); conj, dual) ← domain(W) else - return codomain(W) ← insertleftunit(domain(W), Val(i - numout(W)); conj, dual) + return codomain(W) ← insertleftunitspace(domain(W), Val(i - numout(W)); conj, dual) end end """ - insertrightunit(W::HomSpace, i=numind(W); conj=false, dual=false) + insertrightunitspace(W::HomSpace, i=numind(W); conj=false, dual=false) Insert a trivial vector space, isomorphic to the underlying field, after position `i`, which can be specified as an `Int` or as `Val(i)` for improved type stability. More specifically, adds a right monoidal unit or its dual. -See also [`insertleftunit`](@ref insertleftunit(::HomSpace, ::Val{i}) where {i}), -[`removeunit`](@ref removeunit(::HomSpace, ::Val{i}) where {i}). +See also [`insertleftunitspace`](@ref insertleftunitspace(::HomSpace, ::Val{i}) where {i}), +[`removeunitspace`](@ref removeunitspace(::HomSpace, ::Val{i}) where {i}). """ -function insertrightunit(W::HomSpace, ::Val{i}=Val(numind(W)); +function insertrightunitspace(W::HomSpace, ::Val{i}=Val(numind(W)); conj::Bool=false, dual::Bool=false) where {i} if i ≤ numout(W) - return insertrightunit(codomain(W), Val(i); conj, dual) ← domain(W) + return insertrightunitspace(codomain(W), Val(i); conj, dual) ← domain(W) else - return codomain(W) ← insertrightunit(domain(W), Val(i - numout(W)); conj, dual) + return codomain(W) ← insertrightunitspace(domain(W), Val(i - numout(W)); conj, dual) end end """ - removeunit(P::HomSpace, i) + removeunitspace(P::HomSpace, i) This removes a trivial tensor product factor at position `1 ≤ i ≤ N`, where `i` can be specified as an `Int` or as `Val(i)` for improved type stability. For this to work, the space at position `i` has to be isomorphic to the field of scalars. -This operation undoes the work of [`insertleftunit`](@ref insertleftunit(::HomSpace, ::Val{i}) where {i}) -and [`insertrightunit`](@ref insertrightunit(::HomSpace, ::Val{i}) where {i}). +This operation undoes the work of [`insertleftunitspace`](@ref insertleftunitspace(::HomSpace, ::Val{i}) where {i}) +and [`insertrightunitspace`](@ref insertrightunitspace(::HomSpace, ::Val{i}) where {i}). """ -function removeunit(P::HomSpace, ::Val{i}) where {i} +function removeunitspace(P::HomSpace, ::Val{i}) where {i} if i ≤ numout(P) - return removeunit(codomain(P), Val(i)) ← domain(P) + return removeunitspace(codomain(P), Val(i)) ← domain(P) else - return codomain(P) ← removeunit(domain(P), Val(i - numout(P))) + return codomain(P) ← removeunitspace(domain(P), Val(i - numout(P))) end end diff --git a/src/spaces/productspace.jl b/src/spaces/productspace.jl index cda85381e..42956acec 100644 --- a/src/spaces/productspace.jl +++ b/src/spaces/productspace.jl @@ -148,7 +148,7 @@ function blocksectors(P::ProductSpace{S,N}) where {S,N} end bs = Vector{I}() if N == 0 - push!(bs, one(I)) + push!(bs, unit(I)) elseif N == 1 for s in sectors(P) push!(bs, first(s)) @@ -232,6 +232,7 @@ end Return a tensor product of zero spaces of type `S`, i.e. this is the unit object under the tensor product operation, such that `V ⊗ one(V) == V`. """ +#TODO: unit(V::S)? Base.one(V::VectorSpace) = one(typeof(V)) Base.one(::Type{<:ProductSpace{S}}) where {S<:ElementarySpace} = ProductSpace{S,0}(()) Base.one(::Type{S}) where {S<:ElementarySpace} = ProductSpace{S,0}(()) @@ -242,21 +243,29 @@ function Base.literal_pow(::typeof(^), V::ElementarySpace, p::Val{N}) where {N} return ProductSpace{typeof(V),N}(ntuple(n -> V, p)) end -fuse(P::ProductSpace{S,0}) where {S<:ElementarySpace} = oneunit(S) +fuse(P::ProductSpace{S,0}) where {S<:ElementarySpace} = unitspace(S) fuse(P::ProductSpace{S}) where {S<:ElementarySpace} = fuse(P.spaces...) """ - insertleftunit(P::ProductSpace, i::Int=length(P) + 1; conj=false, dual=false) + insertleftunitspace(P::ProductSpace, i::Int=length(P) + 1; conj=false, dual=false) Insert a trivial vector space, isomorphic to the underlying field, at position `i`, which can be specified as an `Int` or as `Val(i)` for improved type stability. More specifically, adds a left monoidal unit or its dual. -See also [`insertrightunit`](@ref insertrightunit(::ProductSpace, ::Val{i}) where {i}), [`removeunit`](@ref removeunit(::ProductSpace, ::Val{i}) where {i}). +See also [`insertrightunitspace`](@ref insertrightunitspace(::ProductSpace, ::Val{i}) where {i}), [`removeunitspace`](@ref removeunitspace(::ProductSpace, ::Val{i}) where {i}). """ -function insertleftunit(P::ProductSpace, ::Val{i}=Val(length(P) + 1); +function insertleftunitspace(P::ProductSpace, ::Val{i}=Val(length(P) + 1); conj::Bool=false, dual::Bool=false) where {i} - u = oneunit(spacetype(P)) + N = length(P) + I = sectortype(P) + if UnitStyle(I) isa SimpleUnit + u = unitspace(spacetype(P)) + else + N > 0 || throw(ArgumentError("cannot insert a sensible unit space in the empty product space")) + i > N && throw(DomainError((P, i), "cannot insert a sensible left unit space")) + u = leftunitspace(P[i]) + end if dual u = TensorKit.dual(u) end @@ -267,17 +276,25 @@ function insertleftunit(P::ProductSpace, ::Val{i}=Val(length(P) + 1); end """ - insertrightunit(P::ProductSpace, i=lenght(P); conj=false, dual=false) + insertrightunitspace(P::ProductSpace, i=length(P); conj=false, dual=false) Insert a trivial vector space, isomorphic to the underlying field, after position `i`, which can be specified as an `Int` or as `Val(i)` for improved type stability. More specifically, adds a right monoidal unit or its dual. -See also [`insertleftunit`](@ref insertleftunit(::ProductSpace, ::Val{i}) where {i}), [`removeunit`](@ref removeunit(::ProductSpace, ::Val{i}) where {i}). +See also [`insertleftunitspace`](@ref insertleftunitspace(::ProductSpace, ::Val{i}) where {i}), [`removeunitspace`](@ref removeunitspace(::ProductSpace, ::Val{i}) where {i}). """ -function insertrightunit(P::ProductSpace, ::Val{i}=Val(length(P)); +function insertrightunitspace(P::ProductSpace, ::Val{i}=Val(length(P)); conj::Bool=false, dual::Bool=false) where {i} - u = oneunit(spacetype(P)) + N = length(P) + I = sectortype(P) + if UnitStyle(I) isa SimpleUnit + u = unitspace(spacetype(P)) + else + N > 0 || throw(ArgumentError("cannot insert a sensible unit space in the empty product space")) + i == 0 && throw(DomainError((P, i), "cannot insert a sensible right unit space")) + u = rightunitspace(P[i]) + end if dual u = TensorKit.dual(u) end @@ -288,18 +305,18 @@ function insertrightunit(P::ProductSpace, ::Val{i}=Val(length(P)); end """ - removeunit(P::ProductSpace, i::Int) + removeunitspace(P::ProductSpace, i::Int) This removes a trivial tensor product factor at position `1 ≤ i ≤ N`, where `i` can be specified as an `Int` or as `Val(i)` for improved type stability. For this to work, that factor has to be isomorphic to the field of scalars. -This operation undoes the work of [`insertleftunit`](@ref insertleftunit(::ProductSpace, ::Val{i}) where {i}) -and [`insertrightunit`](@ref insertrightunit(::ProductSpace, ::Val{i}) where {i}). +This operation undoes the work of [`insertleftunitspace`](@ref insertleftunitspace(::ProductSpace, ::Val{i}) where {i}) +and [`insertrightunitspace`](@ref insertrightunitspace(::ProductSpace, ::Val{i}) where {i}). """ -function removeunit(P::ProductSpace, ::Val{i}) where {i} +function removeunitspace(P::ProductSpace, ::Val{i}) where {i} 1 ≤ i ≤ length(P) || _boundserror(P, i) - isisomorphic(P[i], oneunit(P[i])) || _nontrivialspaceerror(P, i) + isisomorphic(P[i], unitspace(P[i])) || _nontrivialspaceerror(P, i) return ProductSpace{spacetype(P)}(TupleTools.deleteat(P.spaces, i)) end @@ -326,7 +343,7 @@ function Base.promote_rule(::Type{S}, ::Type{<:ProductSpace{S}}) where {S<:Eleme end # ProductSpace to ElementarySpace -Base.convert(::Type{S}, P::ProductSpace{S,0}) where {S<:ElementarySpace} = oneunit(S) +Base.convert(::Type{S}, P::ProductSpace{S,0}) where {S<:ElementarySpace} = unitspace(S) Base.convert(::Type{S}, P::ProductSpace{S}) where {S<:ElementarySpace} = fuse(P.spaces...) # ElementarySpace to ProductSpace diff --git a/src/spaces/vectorspaces.jl b/src/spaces/vectorspaces.jl index 844da081f..5334153a7 100644 --- a/src/spaces/vectorspaces.jl +++ b/src/spaces/vectorspaces.jl @@ -80,7 +80,7 @@ Base.adjoint(V::VectorSpace) = dual(V) """ isdual(V::ElementarySpace) -> Bool -Return wether an ElementarySpace `V` is normal or rather a dual space. Always returns +Return whether an ElementarySpace `V` is normal or rather a dual space. Always returns `false` for spaces where `V == dual(V)`. """ function isdual end @@ -120,22 +120,27 @@ Return the sum of all degeneracy dimensions of the vector space `V`. reduceddim(V::ElementarySpace) = sum(Base.Fix1(dim, V), sectors(V); init=0) """ - oneunit(V::S) where {S<:ElementarySpace} -> S + unitspace(V::S) where {S<:ElementarySpace} -> S Return the corresponding vector space of type `S` that represents the trivial one-dimensional space, i.e. the space that is isomorphic to the corresponding field. Note that this is different from `one(V::S)`, which returns the empty product space -`ProductSpace{S,0}(())`. +`ProductSpace{S,0}(())`. `Base.oneunit` falls back to `unitspace`. """ -Base.oneunit(V::ElementarySpace) = oneunit(typeof(V)) +unitspace(V::ElementarySpace) = unitspace(typeof(V)) +Base.oneunit(V::ElementarySpace) = unitspace(V) +Base.oneunit(::Type{V}) where {V<:ElementarySpace} = unitspace(V) """ - zero(V::S) where {S<:ElementarySpace} -> S + zerospace(V::S) where {S<:ElementarySpace} -> S Return the corresponding vector space of type `S` that represents the zero-dimensional or empty space. -This is, with a slight abuse of notation, the zero element of the direct sum of vector spaces. +This is, with a slight abuse of notation, the zero element of the direct sum of vector spaces. +`Base.zero` falls back to `zerospace`. """ -Base.zero(V::ElementarySpace) = zero(typeof(V)) +zerospace(V::ElementarySpace) = zerospace(typeof(V)) +Base.zero(V::ElementarySpace) = zerospace(V) +Base.zero(::Type{V}) where {V<:ElementarySpace} = zerospace(V) """ ⊕(V₁::S, V₂::S, V₃::S...) where {S<:ElementarySpace} -> S @@ -204,14 +209,14 @@ end # In the following, X can be a ProductSpace, a HomSpace or an AbstractTensorMap # TODO: should we deprecate those in the future? -@constprop :aggressive function insertleftunit(X, i::Int; kwargs...) - return insertleftunit(X, Val(i); kwargs...) +@constprop :aggressive function insertleftunitspace(X, i::Int; kwargs...) + return insertleftunitspace(X, Val(i); kwargs...) end -@constprop :aggressive function insertrightunit(X, i::Int; kwargs...) - return insertrightunit(X, Val(i); kwargs...) +@constprop :aggressive function insertrightunitspace(X, i::Int; kwargs...) + return insertrightunitspace(X, Val(i); kwargs...) end -@constprop :aggressive function removeunit(X, i::Int; kwargs...) - return removeunit(X, Val(i); kwargs...) +@constprop :aggressive function removeunitspace(X, i::Int; kwargs...) + return removeunitspace(X, Val(i); kwargs...) end # trait to describe the inner product type of vector spaces diff --git a/src/tensors/braidingtensor.jl b/src/tensors/braidingtensor.jl index a4a184e5f..d10d00c7e 100644 --- a/src/tensors/braidingtensor.jl +++ b/src/tensors/braidingtensor.jl @@ -346,7 +346,7 @@ end # rmul!(C, β) # end # I = sectortype(B) -# u = one(I) +# u = unit(I) # f₀ = FusionTree{I}((), u, (), (), ()) # braidingtensor_levels = A.adjoint ? (1, 2, 2, 1) : (2, 1, 1, 2) # inv_braid = braidingtensor_levels[cindA[2]] > braidingtensor_levels[cindA[3]] @@ -414,7 +414,7 @@ end # rmul!(C, β) # end # I = sectortype(B) -# u = one(I) +# u = unit(I) # f₀ = FusionTree{I}((), u, (), (), ()) # braidingtensor_levels = B.adjoint ? (1, 2, 2, 1) : (2, 1, 1, 2) # inv_braid = braidingtensor_levels[cindB[2]] > braidingtensor_levels[cindB[3]] @@ -481,7 +481,7 @@ end # rmul!(C, β) # end # I = sectortype(B) -# u = one(I) +# u = unit(I) # braidingtensor_levels = A.adjoint ? (1, 2, 2, 1) : (2, 1, 1, 2) # inv_braid = braidingtensor_levels[cindA[2]] > braidingtensor_levels[cindA[3]] # for (f₁, f₂) in fusiontrees(B) @@ -543,7 +543,7 @@ end # rmul!(C, β) # end # I = sectortype(B) -# u = one(I) +# u = unit(I) # braidingtensor_levels = B.adjoint ? (1, 2, 2, 1) : (2, 1, 1, 2) # inv_braid = braidingtensor_levels[cindB[2]] > braidingtensor_levels[cindB[3]] # for (f₁, f₂) in fusiontrees(A) diff --git a/src/tensors/indexmanipulations.jl b/src/tensors/indexmanipulations.jl index c4e2b9228..9d972388c 100644 --- a/src/tensors/indexmanipulations.jl +++ b/src/tensors/indexmanipulations.jl @@ -303,7 +303,7 @@ twist(t::AbstractTensorMap, i; inv::Bool=false) = twist!(copy(t), i; inv) # Methods which change the number of indices, implement using `Val(i)` for type inference """ - insertleftunit(tsrc::AbstractTensorMap, i=numind(t) + 1; + insertleftunitspace(tsrc::AbstractTensorMap, i=numind(t) + 1; conj=false, dual=false, copy=false) -> tdst Insert a trivial vector space, isomorphic to the underlying field, at position `i`, @@ -312,12 +312,12 @@ More specifically, adds a left monoidal unit or its dual. If `copy=false`, `tdst` might share data with `tsrc` whenever possible. Otherwise, a copy is always made. -See also [`insertrightunit`](@ref insertrightunit(::AbstractTensorMap, ::Val{i}) where {i}), -[`removeunit`](@ref removeunit(::AbstractTensorMap, ::Val{i}) where {i}). +See also [`insertrightunitspace`](@ref insertrightunitspace(::AbstractTensorMap, ::Val{i}) where {i}), +[`removeunitspace`](@ref removeunitspace(::AbstractTensorMap, ::Val{i}) where {i}). """ -function insertleftunit(t::AbstractTensorMap, ::Val{i}=Val(numind(t) + 1); +function insertleftunitspace(t::AbstractTensorMap, ::Val{i}=Val(numind(t) + 1); copy::Bool=false, conj::Bool=false, dual::Bool=false) where {i} - W = insertleftunit(space(t), Val(i); conj, dual) + W = insertleftunitspace(space(t), Val(i); conj, dual) if t isa TensorMap return TensorMap{scalartype(t)}(copy ? Base.copy(t.data) : t.data, W) else @@ -330,7 +330,7 @@ function insertleftunit(t::AbstractTensorMap, ::Val{i}=Val(numind(t) + 1); end """ - insertrightunit(tsrc::AbstractTensorMap, i=numind(t); + insertrightunitspace(tsrc::AbstractTensorMap, i=numind(t); conj=false, dual=false, copy=false) -> tdst Insert a trivial vector space, isomorphic to the underlying field, after position `i`, @@ -339,12 +339,12 @@ More specifically, adds a right monoidal unit or its dual. If `copy=false`, `tdst` might share data with `tsrc` whenever possible. Otherwise, a copy is always made. -See also [`insertleftunit`](@ref insertleftunit(::AbstractTensorMap, ::Val{i}) where {i}), -[`removeunit`](@ref removeunit(::AbstractTensorMap, ::Val{i}) where {i}). +See also [`insertleftunitspace`](@ref insertleftunitspace(::AbstractTensorMap, ::Val{i}) where {i}), +[`removeunitspace`](@ref removeunitspace(::AbstractTensorMap, ::Val{i}) where {i}). """ -function insertrightunit(t::AbstractTensorMap, ::Val{i}=Val(numind(t)); +function insertrightunitspace(t::AbstractTensorMap, ::Val{i}=Val(numind(t)); copy::Bool=false, conj::Bool=false, dual::Bool=false) where {i} - W = insertrightunit(space(t), Val(i); conj, dual) + W = insertrightunitspace(space(t), Val(i); conj, dual) if t isa TensorMap return TensorMap{scalartype(t)}(copy ? Base.copy(t.data) : t.data, W) else @@ -357,7 +357,7 @@ function insertrightunit(t::AbstractTensorMap, ::Val{i}=Val(numind(t)); end """ - removeunit(tsrc::AbstractTensorMap, i; copy=false) -> tdst + removeunitspace(tsrc::AbstractTensorMap, i; copy=false) -> tdst This removes a trivial tensor product factor at position `1 ≤ i ≤ N`, where `i` can be specified as an `Int` or as `Val(i)` for improved type stability. @@ -365,11 +365,11 @@ For this to work, that factor has to be isomorphic to the field of scalars. If `copy=false`, `tdst` might share data with `tsrc` whenever possible. Otherwise, a copy is always made. -This operation undoes the work of [`insertleftunit`](@ref insertleftunit(::AbstractTensorMap, ::Val{i}) where {i}) -and [`insertrightunit`](@ref insertrightunit(::AbstractTensorMap, ::Val{i}) where {i}). +This operation undoes the work of [`insertleftunitspace`](@ref insertleftunitspace(::AbstractTensorMap, ::Val{i}) where {i}) +and [`insertrightunitspace`](@ref insertrightunitspace(::AbstractTensorMap, ::Val{i}) where {i}). """ -function removeunit(t::AbstractTensorMap, ::Val{i}; copy::Bool=false) where {i} - W = removeunit(space(t), Val(i)) +function removeunitspace(t::AbstractTensorMap, ::Val{i}; copy::Bool=false) where {i} + W = removeunitspace(space(t), Val(i)) if t isa TensorMap return TensorMap{scalartype(t)}(copy ? Base.copy(t.data) : t.data, W) else diff --git a/src/tensors/linalg.jl b/src/tensors/linalg.jl index 5eba8414c..5015a6dc0 100644 --- a/src/tensors/linalg.jl +++ b/src/tensors/linalg.jl @@ -558,10 +558,17 @@ function ⊗(t1::AbstractTensorMap, t2::AbstractTensorMap) throw(SpaceMismatch("spacetype(t1) ≠ spacetype(t2)")) cod1, cod2 = codomain(t1), codomain(t2) dom1, dom2 = domain(t1), domain(t2) - cod = cod1 ⊗ cod2 - dom = dom1 ⊗ dom2 + p12 = ((codomainind(t1)..., (codomainind(t2) .+ numind(t1))...), + (domainind(t1)..., (domainind(t2) .+ numind(t1))...)) + T = promote_type(scalartype(t1), scalartype(t2)) - t = zerovector!(similar(t1, T, cod ← dom)) + TC = promote_type(sectorscalartype(sectortype(t1)), T) + t = TO.tensoralloc_contract(TC, + t1, ((codomainind(t1)..., domainind(t1)...), ()), false, + t2, ((), (codomainind(t2)..., domainind(t2)...)), false, + p12, Val(false)) + + zerovector!(t) for (f1l, f1r) in fusiontrees(t1) for (f2l, f2r) in fusiontrees(t2) c1 = f1l.coupled # = f1r.coupled @@ -597,13 +604,13 @@ function ⊠(t1::AbstractTensorMap, t2::AbstractTensorMap) dom1 = domain(t1) ⊠ one(S2) t1′ = similar(t1, codom1 ← dom1) for (c, b) in blocks(t1) - copy!(block(t1′, c ⊠ one(I2)), b) + copy!(block(t1′, c ⊠ unit(I2)), b) end codom2 = one(S1) ⊠ codomain(t2) dom2 = one(S1) ⊠ domain(t2) t2′ = similar(t2, codom2 ← dom2) for (c, b) in blocks(t2) - copy!(block(t2′, one(I1) ⊠ c), b) + copy!(block(t2′, unit(I1) ⊠ c), b) end return t1′ ⊗ t2′ end diff --git a/src/tensors/tensor.jl b/src/tensors/tensor.jl index a918478c3..bfad6cf40 100644 --- a/src/tensors/tensor.jl +++ b/src/tensors/tensor.jl @@ -538,9 +538,9 @@ since it assumes a uniquely defined coupled charge. throw(ArgumentError("Number of sectors does not match.")) s₁ = TupleTools.getindices(sectors, codomainind(t)) s₂ = map(dual, TupleTools.getindices(sectors, domainind(t))) - c1 = length(s₁) == 0 ? one(I) : (length(s₁) == 1 ? s₁[1] : first(⊗(s₁...))) + c1 = length(s₁) == 0 ? unit(I) : (length(s₁) == 1 ? s₁[1] : first(⊗(s₁...))) @boundscheck begin - c2 = length(s₂) == 0 ? one(I) : (length(s₂) == 1 ? s₂[1] : first(⊗(s₂...))) + c2 = length(s₂) == 0 ? unit(I) : (length(s₂) == 1 ? s₂[1] : first(⊗(s₂...))) c2 == c1 || throw(SectorMismatch("Not a valid sector for this tensor")) hassector(codomain(t), s₁) && hassector(domain(t), s₂) end diff --git a/src/tensors/tensoroperations.jl b/src/tensors/tensoroperations.jl index 6110093b6..1c2e573fa 100644 --- a/src/tensors/tensoroperations.jl +++ b/src/tensors/tensoroperations.jl @@ -336,8 +336,9 @@ end # Scalar implementation #----------------------- -function scalar(t::AbstractTensorMap) - # TODO: should scalar only work if N₁ == N₂ == 0? - return dim(codomain(t)) == dim(domain(t)) == 1 ? - first(blocks(t))[2][1, 1] : throw(DimensionMismatch()) +function scalar(t::AbstractTensorMap{T, S, 0, 0}) where {T, S} + Bs = collect(blocks(t)) + inds = findall(!iszero ∘ last, Bs) + isempty(inds) && return zero(scalartype(t)) + return only(last(Bs[only(inds)])) end diff --git a/test/ad.jl b/test/ad.jl index e5e2d884d..efcc1d7bf 100644 --- a/test/ad.jl +++ b/test/ad.jl @@ -29,7 +29,7 @@ function ChainRulesTestUtils.test_approx(actual::AbstractTensorMap, end # make sure that norms are computed correctly: -function FiniteDifferences.to_vec(t::TensorKit.SectorDict) +function FiniteDifferences.to_vec(t::TK.SectorDict) T = scalartype(valtype(t)) vec = mapreduce(vcat, t; init=T[]) do (c, b) return reshape(b, :) .* sqrt(dim(c)) @@ -39,12 +39,12 @@ function FiniteDifferences.to_vec(t::TensorKit.SectorDict) function from_vec(x_real) x = T <: Real ? x_real : reinterpret(T, x_real) ctr = 0 - return TensorKit.SectorDict(c => (n = length(b); - b′ = reshape(view(x, ctr .+ (1:n)), size(b)) ./ - sqrt(dim(c)); - ctr += n; - b′) - for (c, b) in t) + return TK.SectorDict(c => (n = length(b); + b′ = reshape(view(x, ctr .+ (1:n)), size(b)) ./ + sqrt(dim(c)); + ctr += n; + b′) + for (c, b) in t) end return vec_real, from_vec end @@ -61,25 +61,25 @@ end # rrules for functions that destroy inputs # ---------------------------------------- -function ChainRulesCore.rrule(::typeof(TensorKit.tsvd), args...; kwargs...) +function ChainRulesCore.rrule(::typeof(TK.tsvd), args...; kwargs...) return ChainRulesCore.rrule(tsvd!, args...; kwargs...) end function ChainRulesCore.rrule(::typeof(LinearAlgebra.svdvals), args...; kwargs...) return ChainRulesCore.rrule(svdvals!, args...; kwargs...) end -function ChainRulesCore.rrule(::typeof(TensorKit.eig), args...; kwargs...) +function ChainRulesCore.rrule(::typeof(TK.eig), args...; kwargs...) return ChainRulesCore.rrule(eig!, args...; kwargs...) end -function ChainRulesCore.rrule(::typeof(TensorKit.eigh), args...; kwargs...) +function ChainRulesCore.rrule(::typeof(TK.eigh), args...; kwargs...) return ChainRulesCore.rrule(eigh!, args...; kwargs...) end function ChainRulesCore.rrule(::typeof(LinearAlgebra.eigvals), args...; kwargs...) return ChainRulesCore.rrule(eigvals!, args...; kwargs...) end -function ChainRulesCore.rrule(::typeof(TensorKit.leftorth), args...; kwargs...) +function ChainRulesCore.rrule(::typeof(TK.leftorth), args...; kwargs...) return ChainRulesCore.rrule(leftorth!, args...; kwargs...) end -function ChainRulesCore.rrule(::typeof(TensorKit.rightorth), args...; kwargs...) +function ChainRulesCore.rrule(::typeof(TK.rightorth), args...; kwargs...) return ChainRulesCore.rrule(rightorth!, args...; kwargs...) end @@ -134,8 +134,8 @@ Vlist = ((ℂ^2, (ℂ^3)', ℂ^3, ℂ^2, (ℂ^2)'), ℂ[FibonacciAnyon](:I => 2, :τ => 3), ℂ[FibonacciAnyon](:I => 2, :τ => 2))) -@timedtestset "Automatic Differentiation with spacetype $(TensorKit.type_repr(eltype(V)))" verbose = true for V in - Vlist +@timedtestset "Automatic Differentiation with spacetype $(TK.type_repr(eltype(V)))" verbose = true for V in + Vlist eltypes = isreal(sectortype(eltype(V))) ? (Float64, ComplexF64) : (ComplexF64,) symmetricbraiding = BraidingStyle(sectortype(eltype(V))) isa SymmetricBraiding @@ -149,9 +149,9 @@ Vlist = ((ℂ^2, (ℂ^3)', ℂ^3, ℂ^2, (ℂ^2)'), test_rrule(copy, T1) test_rrule(copy, T2) - test_rrule(TensorKit.copy_oftype, T1, ComplexF64) + test_rrule(TK.copy_oftype, T1, ComplexF64) if symmetricbraiding - test_rrule(TensorKit.permutedcopy_oftype, T1, ComplexF64, ((3, 1), (2, 4))) + test_rrule(TK.permutedcopy_oftype, T1, ComplexF64, ((3, 1), (2, 4))) test_rrule(convert, Array, T1) test_rrule(TensorMap, convert(Array, T1), codomain(T1), domain(T1); @@ -364,13 +364,13 @@ Vlist = ((ℂ^2, (ℂ^3)', ℂ^3, ℂ^2, (ℂ^2)'), H = (H + H') / 2 atol = precision(T) - for alg in (TensorKit.QR(), TensorKit.QRpos()) + for alg in (TK.QR(), TK.QRpos()) test_rrule(leftorth, A; fkwargs=(; alg=alg), atol) test_rrule(leftorth, B; fkwargs=(; alg=alg), atol) test_rrule(leftorth, C; fkwargs=(; alg=alg), atol) end - for alg in (TensorKit.LQ(), TensorKit.LQpos()) + for alg in (TK.LQ(), TK.LQpos()) test_rrule(rightorth, A; fkwargs=(; alg=alg), atol) test_rrule(rightorth, B; fkwargs=(; alg=alg), atol) test_rrule(rightorth, C; fkwargs=(; alg=alg), atol) @@ -428,8 +428,8 @@ Vlist = ((ℂ^2, (ℂ^3)', ℂ^3, ℂ^2, (ℂ^2)'), T <: Complex && remove_svdgauge_depence!(ΔU, ΔV, U, S, V) test_rrule(tsvd, B; atol, output_tangent=(ΔU, ΔS, ΔV, 0.0)) - Vtrunc = spacetype(S)(TensorKit.SectorDict(c => ceil(Int, size(b, 1) / 2) - for (c, b) in blocks(S))) + Vtrunc = spacetype(S)(TK.SectorDict(c => ceil(Int, size(b, 1) / 2) + for (c, b) in blocks(S))) U, S, V, ϵ = tsvd(B; trunc=truncspace(Vtrunc)) ΔU = randn(scalartype(U), space(U)) @@ -447,8 +447,8 @@ Vlist = ((ℂ^2, (ℂ^3)', ℂ^3, ℂ^2, (ℂ^2)'), T <: Complex && remove_svdgauge_depence!(ΔU, ΔV, U, S, V) test_rrule(tsvd, C; atol, output_tangent=(ΔU, ΔS, ΔV, 0.0)) - c, = TensorKit.MatrixAlgebra._argmax(x -> sqrt(dim(x[1])) * maximum(diag(x[2])), - blocks(S)) + c, = TK.MatrixAlgebra._argmax(x -> sqrt(dim(x[1])) * maximum(diag(x[2])), + blocks(S)) trunc = truncdim(round(Int, 2 * dim(c))) U, S, V, ϵ = tsvd(C; trunc) ΔU = randn(scalartype(U), space(U)) diff --git a/test/diagonal.jl b/test/diagonal.jl index e5fcaa430..3eebd2e58 100644 --- a/test/diagonal.jl +++ b/test/diagonal.jl @@ -30,7 +30,7 @@ diagspacelist = ((ℂ^4)', ℂ[Z2Irrep](0 => 2, 1 => 3), b2 = @constinferred block(t, first(blocksectors(t))) @test b1 == b2 @test eltype(bs) === Pair{typeof(c),typeof(b1)} - @test typeof(b1) === TensorKit.blocktype(t) + @test typeof(b1) === TK.blocktype(t) # basic linear algebra @test isa(@constinferred(norm(t)), real(T)) @test norm(t)^2 ≈ dot(t, t) @@ -201,7 +201,7 @@ diagspacelist = ((ℂ^4)', ℂ[Z2Irrep](0 => 2, 1 => 3), zip(values(LinearAlgebra.eigvals(D)), values(LinearAlgebra.eigvals(t)))) end - @testset "leftorth with $alg" for alg in (TensorKit.QR(), TensorKit.QL()) + @testset "leftorth with $alg" for alg in (TK.QR(), TK.QL()) Q, R = @constinferred leftorth(t; alg=alg) QdQ = Q' * Q @test QdQ ≈ one(QdQ) @@ -210,7 +210,7 @@ diagspacelist = ((ℂ^4)', ℂ[Z2Irrep](0 => 2, 1 => 3), @test isposdef(R) end end - @testset "rightorth with $alg" for alg in (TensorKit.RQ(), TensorKit.LQ()) + @testset "rightorth with $alg" for alg in (TK.RQ(), TK.LQ()) L, Q = @constinferred rightorth(t; alg=alg) QQd = Q * Q' @test QQd ≈ one(QQd) @@ -219,7 +219,7 @@ diagspacelist = ((ℂ^4)', ℂ[Z2Irrep](0 => 2, 1 => 3), @test isposdef(L) end end - @testset "tsvd with $alg" for alg in (TensorKit.SVD(), TensorKit.SDD()) + @testset "tsvd with $alg" for alg in (TK.SVD(), TK.SDD()) U, S, Vᴴ = @constinferred tsvd(t; alg=alg) UdU = U' * U @test UdU ≈ one(UdU) diff --git a/test/fusiontrees.jl b/test/fusiontrees.jl index d758f9a83..f2e71d602 100644 --- a/test/fusiontrees.jl +++ b/test/fusiontrees.jl @@ -2,9 +2,9 @@ println("------------------------------------") println("Fusion Trees") println("------------------------------------") ti = time() -@timedtestset "Fusion trees for $(TensorKit.type_repr(I))" verbose = true for I in - sectorlist - Istr = TensorKit.type_repr(I) +@timedtestset "Fusion trees for $(TK.type_repr(I))" verbose = true for I in + sectorlist + Istr = TK.type_repr(I) N = 5 out = ntuple(n -> randsector(I), N) isdual = ntuple(n -> rand(Bool), N) @@ -26,7 +26,7 @@ ti = time() @test eval(Meta.parse(sprint(show, f))) == f end @testset "Fusion tree $Istr: constructor properties" begin - u = one(I) + u = unit(I) @constinferred FusionTree((), u, (), (), ()) @constinferred FusionTree((u,), u, (false,), (), ()) @constinferred FusionTree((u, u), u, (false, false), (), (1,)) @@ -125,7 +125,7 @@ ti = time() outgoing = (s, dual(s), s, dual(s), s, dual(s)) for bool in (true, false) isdual = (bool, !bool, bool, !bool, bool, !bool) - for f in fusiontrees(outgoing, one(s), isdual) + for f in fusiontrees(outgoing, unit(s), isdual) af = convert(Array, f) T = eltype(af) @@ -211,7 +211,7 @@ ti = time() end end end - @testset "Fusion tree $Istr: elementy artin braid" begin + @testset "Fusion tree $Istr: elementary artin braid" begin N = length(out) isdual = ntuple(n -> rand(Bool), N) for in in ⊗(out...) @@ -268,7 +268,7 @@ ti = time() end end @testset "Fusion tree $Istr: braiding and permuting" begin - f = rand(collect(fusiontrees(out, in, isdual))) + f = rand(collect(it)) p = tuple(randperm(N)...) ip = invperm(p) @@ -379,7 +379,7 @@ ti = time() f1 = rand(collect(fusiontrees(out, incoming, ntuple(n -> rand(Bool), N)))) f2 = rand(collect(fusiontrees(out[randperm(N)], incoming, ntuple(n -> rand(Bool), N)))) - @testset "Double fusion tree $Istr: repartioning" begin + @testset "Double fusion tree $Istr: repartitioning" begin for n in 0:(2 * N) d = @constinferred TK.repartition(f1, f2, $n) @test dim(incoming) ≈ @@ -432,12 +432,12 @@ ti = time() ip = invperm(p) ip1, ip2 = ip[1:N], ip[(N + 1):(2N)] - d = @constinferred TensorKit.permute(f1, f2, p1, p2) + d = @constinferred TK.permute(f1, f2, p1, p2) @test dim(incoming) ≈ sum(abs2(coef) * dim(f1.coupled) for ((f1, f2), coef) in d) d2 = Dict{typeof((f1, f2)),valtype(d)}() for ((f1′, f2′), coeff) in d - d′ = TensorKit.permute(f1′, f2′, ip1, ip2) + d′ = TK.permute(f1′, f2′, ip1, ip2) for ((f1′′, f2′′), coeff2) in d′ d2[(f1′′, f2′′)] = get(d2, (f1′′, f2′′), zero(coeff)) + coeff2 * coeff @@ -548,7 +548,7 @@ ti = time() @testset "Double fusion tree $Istr: planar trace" begin d1 = transpose(f1, f1, (N + 1, 1:N..., ((2N):-1:(N + 3))...), (N + 2,)) f1front, = TK.split(f1, N - 1) - T = typeof(Fsymbol(one(I), one(I), one(I), one(I), one(I), one(I))[1, 1, 1, 1]) + T = sectorscalartype(I) d2 = Dict{typeof((f1front, f1front)),T}() for ((f1′, f2′), coeff′) in d1 for ((f1′′, f2′′), coeff′′) in @@ -566,7 +566,7 @@ ti = time() end end end - TensorKit.empty_globalcaches!() + TK.empty_globalcaches!() end tf = time() printstyled("Finished fusion tree tests in ", diff --git a/test/runtests.jl b/test/runtests.jl index 9fafa1d9f..88dbcd6cb 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,7 +3,7 @@ using TestExtras using Random using TensorKit using Combinatorics -using TensorKit: ProductSector, fusiontensor, pentagon_equation, hexagon_equation +using TensorKit: ProductSector, fusiontensor using TensorOperations using Base.Iterators: take, product # using SUNRepresentations: SUNIrrep @@ -33,14 +33,14 @@ end function randsector(::Type{I}) where {I<:Sector} s = collect(smallset(I)) a = rand(s) - while a == one(a) # don't use trivial label + while isunit(a) # don't use trivial label a = rand(s) end return a end function hasfusiontensor(I::Type{<:Sector}) try - fusiontensor(one(I), one(I), one(I)) + fusiontensor(unit(I), unit(I), unit(I)) return true catch e if e isa MethodError diff --git a/test/spaces.jl b/test/spaces.jl index 90d27d74e..050271c8f 100644 --- a/test/spaces.jl +++ b/test/spaces.jl @@ -64,18 +64,18 @@ println("------------------------------------") @test @constinferred(sectortype(V)) == Trivial @test ((@constinferred sectors(V))...,) == (Trivial(),) @test length(sectors(V)) == 1 - @test @constinferred(TensorKit.hassector(V, Trivial())) + @test @constinferred(TK.hassector(V, Trivial())) @test @constinferred(dim(V)) == d == @constinferred(dim(V, Trivial())) - @test dim(@constinferred(zero(V))) == 0 - @test (sectors(zero(V))...,) == () - @test @constinferred(TensorKit.axes(V)) == Base.OneTo(d) + @test dim(@constinferred(zerospace(V))) == 0 + @test (sectors(zerospace(V))...,) == () + @test @constinferred(TK.axes(V)) == Base.OneTo(d) @test ℝ^d == ℝ[](d) == CartesianSpace(d) == typeof(V)(d) W = @constinferred ℝ^1 - @test @constinferred(oneunit(V)) == W == oneunit(typeof(V)) - @test @constinferred(zero(V)) == ℝ^0 == zero(typeof(V)) - @test @constinferred(⊕(V, zero(V))) == V + @test @constinferred(unitspace(V)) == W == unitspace(typeof(V)) + @test @constinferred(zerospace(V)) == ℝ^0 == zerospace(typeof(V)) + @test @constinferred(⊕(V, zerospace(V))) == V @test @constinferred(⊕(V, V)) == ℝ^(2d) - @test @constinferred(⊕(V, oneunit(V))) == ℝ^(d + 1) + @test @constinferred(⊕(V, unitspace(V))) == ℝ^(d + 1) @test @constinferred(⊕(V, V, V, V)) == ℝ^(4d) @test @constinferred(fuse(V, V)) == ℝ^(d^2) @test @constinferred(fuse(V, V', V, V')) == ℝ^(d^4) @@ -111,16 +111,16 @@ println("------------------------------------") @test @constinferred(sectortype(V)) == Trivial @test ((@constinferred sectors(V))...,) == (Trivial(),) @test length(sectors(V)) == 1 - @test @constinferred(TensorKit.hassector(V, Trivial())) + @test @constinferred(TK.hassector(V, Trivial())) @test @constinferred(dim(V)) == d == @constinferred(dim(V, Trivial())) - @test dim(@constinferred(zero(V))) == 0 - @test (sectors(zero(V))...,) == () - @test @constinferred(TensorKit.axes(V)) == Base.OneTo(d) + @test dim(@constinferred(zerospace(V))) == 0 + @test (sectors(zerospace(V))...,) == () + @test @constinferred(TK.axes(V)) == Base.OneTo(d) @test ℂ^d == Vect[Trivial](d) == Vect[](Trivial() => d) == ℂ[](d) == typeof(V)(d) W = @constinferred ℂ^1 - @test @constinferred(oneunit(V)) == W == oneunit(typeof(V)) - @test @constinferred(zero(V)) == ℂ^0 == zero(typeof(V)) - @test @constinferred(⊕(V, zero(V))) == V + @test @constinferred(unitspace(V)) == W == unitspace(typeof(V)) + @test @constinferred(zerospace(V)) == ℂ^0 == zerospace(typeof(V)) + @test @constinferred(⊕(V, zerospace(V))) == V @test @constinferred(⊕(V, V)) == ℂ^(2d) @test_throws SpaceMismatch (⊕(V, V')) # promote_except = ErrorException("promotion of types $(typeof(ℝ^d)) and " * @@ -128,7 +128,7 @@ println("------------------------------------") # @test_throws promote_except (⊕(ℝ^d, ℂ^d)) @test_throws ErrorException (⊗(ℝ^d, ℂ^d)) @test @constinferred(⊕(V, V)) == ℂ^(2d) - @test @constinferred(⊕(V, oneunit(V))) == ℂ^(d + 1) + @test @constinferred(⊕(V, unitspace(V))) == ℂ^(d + 1) @test @constinferred(⊕(V, V, V, V)) == ℂ^(4d) @test @constinferred(fuse(V, V)) == ℂ^(d^2) @test @constinferred(fuse(V, V', V, V')) == ℂ^(d^4) @@ -153,10 +153,10 @@ println("------------------------------------") @test isdual(V') @test !isdual(conj(V)) @test isdual(conj(V')) - @test !TensorKit.isconj(V) - @test !TensorKit.isconj(V') - @test TensorKit.isconj(conj(V)) - @test TensorKit.isconj(conj(V')) + @test !TK.isconj(V) + @test !TK.isconj(V') + @test TK.isconj(conj(V)) + @test TK.isconj(conj(V')) @test isa(V, VectorSpace) @test isa(V, ElementarySpace) @test !isa(InnerProductStyle(V), HasInnerProduct) @@ -165,20 +165,20 @@ println("------------------------------------") @test @constinferred(dual(V)) != @constinferred(conj(V)) != V @test @constinferred(field(V)) == ℂ @test @constinferred(sectortype(V)) == Trivial - @test @constinferred(TensorKit.hassector(V, Trivial())) + @test @constinferred(TK.hassector(V, Trivial())) @test @constinferred(dim(V)) == d == @constinferred(dim(V, Trivial())) - @test @constinferred(TensorKit.axes(V)) == Base.OneTo(d) + @test @constinferred(TK.axes(V)) == Base.OneTo(d) end - @timedtestset "ElementarySpace: $(TensorKit.type_repr(Vect[I]))" for I in sectorlist + @timedtestset "ElementarySpace: $(TK.type_repr(Vect[I]))" for I in sectorlist if Base.IteratorSize(values(I)) === Base.IsInfinite() - set = unique(vcat(one(I), [randsector(I) for k in 1:10])) + set = unique(vcat(unit(I), [randsector(I) for k in 1:10])) gen = (c => 2 for c in set) else gen = (values(I)[k] => (k + 1) for k in 1:length(values(I))) end V = GradedSpace(gen) - @test eval(Meta.parse(TensorKit.type_repr(typeof(V)))) == typeof(V) + @test eval(Meta.parse(TK.type_repr(typeof(V)))) == typeof(V) @test eval(Meta.parse(sprint(show, V))) == V @test eval(Meta.parse(sprint(show, V'))) == V' @test V' == GradedSpace(gen; dual=true) @@ -204,14 +204,15 @@ println("------------------------------------") @test eval(Meta.parse(sprint(show, V))) == V @test eval(Meta.parse(sprint(show, typeof(V)))) == typeof(V) # space with no sectors - @test dim(@constinferred(zero(V))) == 0 + @test dim(@constinferred(zerospace(V))) == 0 # space with a single sector - W = @constinferred GradedSpace(one(I) => 1) - @test W == GradedSpace(one(I) => 1, randsector(I) => 0) - @test @constinferred(oneunit(V)) == W == oneunit(typeof(V)) - @test @constinferred(zero(V)) == GradedSpace(one(I) => 0) + W = @constinferred GradedSpace(unit(I) => 1) + @test W == GradedSpace(unit(I) => 1, randsector(I) => 0) + @test @constinferred(unitspace(V)) == W == unitspace(typeof(V)) + @test @constinferred(zerospace(V)) == GradedSpace(unit(I) => 0) # randsector never returns trivial sector, so this cannot error - @test_throws ArgumentError GradedSpace(one(I) => 1, randsector(I) => 0, one(I) => 3) + @test_throws ArgumentError GradedSpace(unit(I) => 1, randsector(I) => 0, + unit(I) => 3) @test eval(Meta.parse(sprint(show, W))) == W @test isa(V, VectorSpace) @test isa(V, ElementarySpace) @@ -224,19 +225,19 @@ println("------------------------------------") @test @constinferred(field(V)) == ℂ @test @constinferred(sectortype(V)) == I slist = @constinferred sectors(V) - @test @constinferred(TensorKit.hassector(V, first(slist))) + @test @constinferred(TK.hassector(V, first(slist))) @test @constinferred(dim(V)) == sum(dim(s) * dim(V, s) for s in slist) @test @constinferred(reduceddim(V)) == sum(dim(V, s) for s in slist) @constinferred dim(V, first(slist)) if hasfusiontensor(I) - @test @constinferred(TensorKit.axes(V)) == Base.OneTo(dim(V)) + @test @constinferred(TK.axes(V)) == Base.OneTo(dim(V)) end - @test @constinferred(⊕(V, zero(V))) == V + @test @constinferred(⊕(V, zerospace(V))) == V @test @constinferred(⊕(V, V)) == Vect[I](c => 2dim(V, c) for c in sectors(V)) @test @constinferred(⊕(V, V, V, V)) == Vect[I](c => 4dim(V, c) for c in sectors(V)) - @test @constinferred(⊕(V, oneunit(V))) == - Vect[I](c => isone(c) + dim(V, c) for c in sectors(V)) - @test @constinferred(fuse(V, oneunit(V))) == V + @test @constinferred(⊕(V, unitspace(V))) == + Vect[I](c => isunit(c) + dim(V, c) for c in sectors(V)) + @test @constinferred(fuse(V, unitspace(V))) == V d = Dict{I,Int}() for a in sectors(V), b in sectors(V) for c in a ⊗ b @@ -253,7 +254,7 @@ println("------------------------------------") @test V == @constinferred infimum(V, ⊕(V, V)) @test V ≺ ⊕(V, V) @test !(V ≻ ⊕(V, V)) - @test infimum(V, GradedSpace(one(I) => 3)) == GradedSpace(one(I) => 2) + @test infimum(V, GradedSpace(unit(I) => 3)) == GradedSpace(unit(I) => 2) @test_throws SpaceMismatch (⊕(V, V')) end @@ -278,10 +279,10 @@ println("------------------------------------") @test @constinferred(⊗(V1 ⊗ V2, V3 ⊗ V4)) == P @test @constinferred(⊗(V1, V2, V3 ⊗ V4)) == P @test @constinferred(⊗(V1, V2 ⊗ V3, V4)) == P - @test V1 * V2 * oneunit(V1) * V3 * V4 == - @constinferred(insertleftunit(P, 3)) == - @constinferred(insertrightunit(P, 2)) - @test @constinferred(removeunit(V1 * V2 * oneunit(V1)' * V3 * V4, 3)) == P + @test V1 * V2 * unitspace(V1) * V3 * V4 == + @constinferred(insertleftunitspace(P, 3)) == + @constinferred(insertrightunitspace(P, 2)) + @test @constinferred(removeunitspace(V1 * V2 * unitspace(V1)' * V3 * V4, 3)) == P @test fuse(V1, V2', V3) ≅ V1 ⊗ V2' ⊗ V3 @test fuse(V1, V2', V3) ≾ V1 ⊗ V2' ⊗ V3 @test fuse(V1, V2', V3) ≿ V1 ⊗ V2' ⊗ V3 @@ -342,10 +343,10 @@ println("------------------------------------") @test @constinferred(*(V1, V2, V3)) == P @test @constinferred(⊗(V1, V2, V3)) == P @test @constinferred(adjoint(P)) == dual(P) == V3' ⊗ V2' ⊗ V1' - @test V1 * V2 * oneunit(V1)' * V3 == - @constinferred(insertleftunit(P, 3; conj=true)) == - @constinferred(insertrightunit(P, 2; conj=true)) - @test P == @constinferred(removeunit(insertleftunit(P, 3), 3)) + @test V1 * V2 * unitspace(V1)' * V3 == + @constinferred(insertleftunitspace(P, 3; conj=true)) == + @constinferred(insertrightunitspace(P, 2; conj=true)) + @test P == @constinferred(removeunitspace(insertleftunitspace(P, 3), 3)) @test fuse(V1, V2', V3) ≅ V1 ⊗ V2' ⊗ V3 @test fuse(V1, V2', V3) ≾ V1 ⊗ V2' ⊗ V3 ≾ fuse(V1 ⊗ V2' ⊗ V3) @test fuse(V1, V2') ⊗ V3 ≾ V1 ⊗ V2' ⊗ V3 @@ -406,7 +407,7 @@ println("------------------------------------") @timedtestset "HomSpace" begin for (V1, V2, V3, V4, V5) in (Vtr, Vℤ₃, VSU₂) - W = TensorKit.HomSpace(V1 ⊗ V2, V3 ⊗ V4 ⊗ V5) + W = TK.HomSpace(V1 ⊗ V2, V3 ⊗ V4 ⊗ V5) @test W == (V3 ⊗ V4 ⊗ V5 → V1 ⊗ V2) @test W == (V1 ⊗ V2 ← V3 ⊗ V4 ⊗ V5) @test W' == (V1 ⊗ V2 → V3 ⊗ V4 ⊗ V5) @@ -423,25 +424,25 @@ println("------------------------------------") @test W == deepcopy(W) @test W == @constinferred permute(W, ((1, 2), (3, 4, 5))) @test permute(W, ((2, 4, 5), (3, 1))) == (V2 ⊗ V4' ⊗ V5' ← V3 ⊗ V1') - @test (V1 ⊗ V2 ← V1 ⊗ V2) == @constinferred TensorKit.compose(W, W') - @test (V1 ⊗ V2 ← V3 ⊗ V4 ⊗ V5 ⊗ oneunit(V5)) == - @constinferred(insertleftunit(W)) == - @constinferred(insertrightunit(W)) - @test @constinferred(removeunit(insertleftunit(W), $(numind(W) + 1))) == W - @test (V1 ⊗ V2 ← V3 ⊗ V4 ⊗ V5 ⊗ oneunit(V5)') == - @constinferred(insertleftunit(W; conj=true)) == - @constinferred(insertrightunit(W; conj=true)) - @test (oneunit(V1) ⊗ V1 ⊗ V2 ← V3 ⊗ V4 ⊗ V5) == - @constinferred(insertleftunit(W, 1)) == - @constinferred(insertrightunit(W, 0)) - @test (V1 ⊗ V2 ⊗ oneunit(V1) ← V3 ⊗ V4 ⊗ V5) == - @constinferred(insertrightunit(W, 2)) - @test (V1 ⊗ V2 ← oneunit(V1) ⊗ V3 ⊗ V4 ⊗ V5) == - @constinferred(insertleftunit(W, 3)) - @test @constinferred(removeunit(insertleftunit(W, 3), 3)) == W - @test @constinferred(insertrightunit(one(V1) ← V1, 0)) == (oneunit(V1) ← V1) - @test_throws BoundsError insertleftunit(one(V1) ← V1, 0) + @test (V1 ⊗ V2 ← V1 ⊗ V2) == @constinferred TK.compose(W, W') + @test (V1 ⊗ V2 ← V3 ⊗ V4 ⊗ V5 ⊗ unitspace(V5)) == + @constinferred(insertleftunitspace(W)) == + @constinferred(insertrightunitspace(W)) + @test @constinferred(removeunitspace(insertleftunitspace(W), $(numind(W) + 1))) == W + @test (V1 ⊗ V2 ← V3 ⊗ V4 ⊗ V5 ⊗ unitspace(V5)') == + @constinferred(insertleftunitspace(W; conj=true)) == + @constinferred(insertrightunitspace(W; conj=true)) + @test (unitspace(V1) ⊗ V1 ⊗ V2 ← V3 ⊗ V4 ⊗ V5) == + @constinferred(insertleftunitspace(W, 1)) == + @constinferred(insertrightunitspace(W, 0)) + @test (V1 ⊗ V2 ⊗ unitspace(V1) ← V3 ⊗ V4 ⊗ V5) == + @constinferred(insertrightunitspace(W, 2)) + @test (V1 ⊗ V2 ← unitspace(V1) ⊗ V3 ⊗ V4 ⊗ V5) == + @constinferred(insertleftunitspace(W, 3)) + @test @constinferred(removeunitspace(insertleftunitspace(W, 3), 3)) == W + @test @constinferred(insertrightunitspace(one(V1) ← V1, 0)) == (unitspace(V1) ← V1) + @test_throws BoundsError insertleftunitspace(one(V1) ← V1, 0) end end - TensorKit.empty_globalcaches!() + TK.empty_globalcaches!() end diff --git a/test/tensors.jl b/test/tensors.jl index 30526f2c1..2f46022b7 100644 --- a/test/tensors.jl +++ b/test/tensors.jl @@ -23,7 +23,7 @@ end for V in spacelist I = sectortype(first(V)) - Istr = TensorKit.type_repr(I) + Istr = TK.type_repr(I) println("---------------------------------------") println("Tensors with symmetry: $Istr") println("---------------------------------------") @@ -48,7 +48,7 @@ for V in spacelist b2 = @constinferred block(t, first(blocksectors(t))) @test b1 == b2 @test eltype(bs) === Pair{typeof(c),typeof(b1)} - @test typeof(b1) === TensorKit.blocktype(t) + @test typeof(b1) === TK.blocktype(t) @test typeof(c) === sectortype(t) end end @@ -86,7 +86,7 @@ for V in spacelist end end for T in (Int, Float32, ComplexF64) - t = randn(T, V1 ⊗ V2 ← zero(V1)) + t = randn(T, V1 ⊗ V2 ← zerospace(V1)) a = convert(Array, t) @test norm(a) == 0 end @@ -110,7 +110,7 @@ for V in spacelist b2 = @constinferred block(t', first(blocksectors(t'))) @test b1 == b2 @test eltype(bs) === Pair{typeof(c),typeof(b1)} - @test typeof(b1) === TensorKit.blocktype(t') + @test typeof(b1) === TK.blocktype(t') @test typeof(c) === sectortype(t) # linear algebra @test isa(@constinferred(norm(t)), real(T)) @@ -147,32 +147,32 @@ for V in spacelist W = V1 ⊗ V2 ⊗ V3 ← V4 ⊗ V5 for T in (Float32, ComplexF64) t = @constinferred rand(T, W) - t2 = @constinferred insertleftunit(t) - @test t2 == @constinferred insertrightunit(t) + t2 = @constinferred insertleftunitspace(t) + @test t2 == @constinferred insertrightunitspace(t) @test numind(t2) == numind(t) + 1 - @test space(t2) == insertleftunit(space(t)) + @test space(t2) == insertleftunitspace(space(t)) @test scalartype(t2) === T @test t.data === t2.data - @test @constinferred(removeunit(t2, $(numind(t2)))) == t - t3 = @constinferred insertleftunit(t; copy=true) - @test t3 == @constinferred insertrightunit(t; copy=true) + @test @constinferred(removeunitspace(t2, $(numind(t2)))) == t + t3 = @constinferred insertleftunitspace(t; copy=true) + @test t3 == @constinferred insertrightunitspace(t; copy=true) @test t.data !== t3.data for (c, b) in blocks(t) @test b == block(t3, c) end - @test @constinferred(removeunit(t3, $(numind(t3)))) == t - t4 = @constinferred insertrightunit(t, 3; dual=true) + @test @constinferred(removeunitspace(t3, $(numind(t3)))) == t + t4 = @constinferred insertrightunitspace(t, 3; dual=true) @test numin(t4) == numin(t) && numout(t4) == numout(t) + 1 for (c, b) in blocks(t) @test b == block(t4, c) end - @test @constinferred(removeunit(t4, 4)) == t - t5 = @constinferred insertleftunit(t, 4; dual=true) + @test @constinferred(removeunitspace(t4, 4)) == t + t5 = @constinferred insertleftunitspace(t, 4; dual=true) @test numin(t5) == numin(t) + 1 && numout(t5) == numout(t) for (c, b) in blocks(t) @test b == block(t5, c) end - @test @constinferred(removeunit(t5, 4)) == t + @test @constinferred(removeunitspace(t5, 4)) == t end end if hasfusiontensor(I) @@ -446,10 +446,10 @@ for V in spacelist ts = (rand(T, W), rand(T, W)') for t in ts @testset "leftorth with $alg" for alg in - (TensorKit.QR(), TensorKit.QRpos(), - TensorKit.QL(), TensorKit.QLpos(), - TensorKit.Polar(), TensorKit.SVD(), - TensorKit.SDD()) + (TK.QR(), TK.QRpos(), + TK.QL(), TK.QLpos(), + TK.Polar(), TK.SVD(), + TK.SDD()) Q, R = @constinferred leftorth(t, ((3, 4, 2), (1, 5)); alg=alg) QdQ = Q' * Q @test QdQ ≈ one(QdQ) @@ -460,8 +460,8 @@ for V in spacelist end end @testset "leftnull with $alg" for alg in - (TensorKit.QR(), TensorKit.SVD(), - TensorKit.SDD()) + (TK.QR(), TK.SVD(), + TK.SDD()) N = @constinferred leftnull(t, ((3, 4, 2), (1, 5)); alg=alg) NdN = N' * N @test NdN ≈ one(NdN) @@ -469,10 +469,10 @@ for V in spacelist 100 * eps(norm(t)) end @testset "rightorth with $alg" for alg in - (TensorKit.RQ(), TensorKit.RQpos(), - TensorKit.LQ(), TensorKit.LQpos(), - TensorKit.Polar(), TensorKit.SVD(), - TensorKit.SDD()) + (TK.RQ(), TK.RQpos(), + TK.LQ(), TK.LQpos(), + TK.Polar(), TK.SVD(), + TK.SDD()) L, Q = @constinferred rightorth(t, ((3, 4), (2, 1, 5)); alg=alg) QQd = Q * Q' @test QQd ≈ one(QQd) @@ -483,15 +483,15 @@ for V in spacelist end end @testset "rightnull with $alg" for alg in - (TensorKit.LQ(), TensorKit.SVD(), - TensorKit.SDD()) + (TK.LQ(), TK.SVD(), + TK.SDD()) M = @constinferred rightnull(t, ((3, 4), (2, 1, 5)); alg=alg) MMd = M * M' @test MMd ≈ one(MMd) @test norm(permute(t, ((3, 4), (2, 1, 5))) * M') < 100 * eps(norm(t)) end - @testset "tsvd with $alg" for alg in (TensorKit.SVD(), TensorKit.SDD()) + @testset "tsvd with $alg" for alg in (TK.SVD(), TK.SDD()) U, S, V = @constinferred tsvd(t, ((3, 4, 2), (1, 5)); alg=alg) UdU = U' * U @test UdU ≈ one(UdU) @@ -525,47 +525,47 @@ for V in spacelist end end @testset "empty tensor" begin - t = randn(T, V1 ⊗ V2, zero(V1)) + t = randn(T, V1 ⊗ V2, zerospace(V1)) @testset "leftorth with $alg" for alg in - (TensorKit.QR(), TensorKit.QRpos(), - TensorKit.QL(), TensorKit.QLpos(), - TensorKit.Polar(), TensorKit.SVD(), - TensorKit.SDD()) + (TK.QR(), TK.QRpos(), + TK.QL(), TK.QLpos(), + TK.Polar(), TK.SVD(), + TK.SDD()) Q, R = @constinferred leftorth(t; alg=alg) @test Q == t @test dim(Q) == dim(R) == 0 end @testset "leftnull with $alg" for alg in - (TensorKit.QR(), TensorKit.SVD(), - TensorKit.SDD()) + (TK.QR(), TK.SVD(), + TK.SDD()) N = @constinferred leftnull(t; alg=alg) @test N' * N ≈ id(domain(N)) @test N * N' ≈ id(codomain(N)) end @testset "rightorth with $alg" for alg in - (TensorKit.RQ(), TensorKit.RQpos(), - TensorKit.LQ(), TensorKit.LQpos(), - TensorKit.Polar(), TensorKit.SVD(), - TensorKit.SDD()) + (TK.RQ(), TK.RQpos(), + TK.LQ(), TK.LQpos(), + TK.Polar(), TK.SVD(), + TK.SDD()) L, Q = @constinferred rightorth(copy(t'); alg=alg) @test Q == t' @test dim(Q) == dim(L) == 0 end @testset "rightnull with $alg" for alg in - (TensorKit.LQ(), TensorKit.SVD(), - TensorKit.SDD()) + (TK.LQ(), TK.SVD(), + TK.SDD()) M = @constinferred rightnull(copy(t'); alg=alg) @test M * M' ≈ id(codomain(M)) @test M' * M ≈ id(domain(M)) end - @testset "tsvd with $alg" for alg in (TensorKit.SVD(), TensorKit.SDD()) + @testset "tsvd with $alg" for alg in (TK.SVD(), TK.SDD()) U, S, V = @constinferred tsvd(t; alg=alg) @test U == t @test dim(U) == dim(S) == dim(V) end @testset "cond and rank" begin @test rank(t) == 0 - W2 = zero(V1) * zero(V2) + W2 = zerospace(V1) * zerospace(V2) t2 = rand(W2, W2) @test rank(t2) == 0 @test cond(t2) == 0.0 @@ -761,7 +761,7 @@ for V in spacelist @test t3 ≈ t4 end end - TensorKit.empty_globalcaches!() + TK.empty_globalcaches!() end @timedtestset "Deligne tensor product: test via conversion" begin