From 00eb107e80e0a4abe1ed5da6e2b7e655c6b416dc Mon Sep 17 00:00:00 2001 From: Jutho Date: Thu, 19 Dec 2024 18:15:09 +0100 Subject: [PATCH] some cleanup for v0.14 (#191) * some cleanup for v0.14 * try to remove some constprop macros * bump version * restore constprop * remove unused compat entry --------- Co-authored-by: Lukas Devos --- Changelog.md | 17 +++++++++++++++++ Project.toml | 2 +- docs/src/lib/spaces.md | 1 + docs/src/lib/tensors.md | 1 + src/TensorKit.jl | 3 ++- src/auxiliary/auxiliary.jl | 9 --------- src/tensors/indexmanipulations.jl | 13 ++++++------- src/tensors/vectorinterface.jl | 21 +++++++++++++++++++-- 8 files changed, 47 insertions(+), 20 deletions(-) diff --git a/Changelog.md b/Changelog.md index 2f702c90..b6ea4c24 100644 --- a/Changelog.md +++ b/Changelog.md @@ -17,6 +17,23 @@ Features that are planned to be implemented before the release of v1.0.0, in no ## v0.14 +### Use `DiagonalTensorMap` for singular values and eigenvalues + +The diagonal (1,1) tensor that contains the singular values or eigenvalues of a tensor +are now explicitly represented as `DiagonalTensorMap` instances. + +### New index functionality +There are is new functionality for manipulating the spaces associated with a tensor: +* `flip(t, i)` changes the duality flag of the `i`th index of `t`, in such a way that flipping + a pair of contracted indices in an `@tensor` contraction does not affect the result. +* `insertleftunit(t, i)` and `insertrightunit(t, i)` insert a trivial unit space to the left + or to right of index `i`, whereas `removeunit(t, i)` removes such a trivial unit space. + +### SVD truncation change (breaking) +There is a subtle but breaking change in the truncation mechanism in SVD, where now it is +guaranteed that smaller singular values are removed first, irrespective of the (quantum) +dimension of the sector to which they belong + ### `DiagonalTensorMap` and `reduceddim` This adds a `DiagonalTensorMap` type for representing tensor maps in which all of the diff --git a/Project.toml b/Project.toml index 41d4f9cf..8d9a2fd4 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "TensorKit" uuid = "07d1fe3e-3e46-537d-9eac-e9e13d0d4cec" authors = ["Jutho Haegeman"] -version = "0.13.2" +version = "0.14" [deps] LRUCache = "8ac3fa9e-de4c-5943-b1dc-09c6b5f20637" diff --git a/docs/src/lib/spaces.md b/docs/src/lib/spaces.md index 244a85f5..e673997c 100644 --- a/docs/src/lib/spaces.md +++ b/docs/src/lib/spaces.md @@ -112,6 +112,7 @@ There are also specific methods for `HomSpace` instances, that are used in deter the resuling `HomSpace` after applying certain tensor operations. ```@docs +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} diff --git a/docs/src/lib/tensors.md b/docs/src/lib/tensors.md index 0ad8cf5a..2ab1e188 100644 --- a/docs/src/lib/tensors.md +++ b/docs/src/lib/tensors.md @@ -174,6 +174,7 @@ permute(::AbstractTensorMap, ::Index2Tuple{N₁,N₂}; ::Bool) where {N₁,N₂} braid(::AbstractTensorMap, ::Index2Tuple, ::IndexTuple; ::Bool) transpose(::AbstractTensorMap, ::Index2Tuple; ::Bool) repartition(::AbstractTensorMap, ::Int, ::Int; ::Bool) +flip(t::AbstractTensorMap, I) twist(::AbstractTensorMap, ::Int; ::Bool) insertleftunit(::AbstractTensorMap, ::Int) insertrightunit(::AbstractTensorMap, ::Int) diff --git a/src/TensorKit.jl b/src/TensorKit.jl index 3b103ea1..6882d10d 100644 --- a/src/TensorKit.jl +++ b/src/TensorKit.jl @@ -107,7 +107,8 @@ import TensorKitSectors: dim, BraidingStyle, FusionStyle, ⊠, ⊗ import TensorKitSectors: dual, type_repr import TensorKitSectors: twist -using Base: @boundscheck, @propagate_inbounds, OneTo, tail, front, +using Base: @boundscheck, @propagate_inbounds, @constprop, + OneTo, tail, front, tuple_type_head, tuple_type_tail, tuple_type_cons, SizeUnknown, HasLength, HasShape, IsInfinite, EltypeUnknown, HasEltype using Base.Iterators: product, filter diff --git a/src/auxiliary/auxiliary.jl b/src/auxiliary/auxiliary.jl index 297fd3ab..bda29d55 100644 --- a/src/auxiliary/auxiliary.jl +++ b/src/auxiliary/auxiliary.jl @@ -44,15 +44,6 @@ end @noinline _boundserror(P, i) = throw(BoundsError(P, i)) @noinline _nontrivialspaceerror(P, i) = throw(ArgumentError(lazy"Attempting to remove a non-trivial space $(P[i])")) -# Compat implementation: -@static if VERSION < v"1.7" - macro constprop(setting, ex) - return esc(ex) - end -else - using Base: @constprop -end - const VecOrNumber{T<:Number} = Union{DenseVector{T},T} """ diff --git a/src/tensors/indexmanipulations.jl b/src/tensors/indexmanipulations.jl index 55cbd64c..d1d16803 100644 --- a/src/tensors/indexmanipulations.jl +++ b/src/tensors/indexmanipulations.jl @@ -303,9 +303,9 @@ If `copy=false`, `tdst` might share data with `tsrc` whenever possible. Otherwis See also [`insertrightunit`](@ref) and [`removeunit`](@ref). """ -@constprop :aggressive function insertleftunit(t::AbstractTensorMap, - i::Int=numind(t) + 1; copy::Bool=true, - conj::Bool=false, dual::Bool=false) +@constprop :aggressive function insertleftunit(t::AbstractTensorMap, i::Int=numind(t) + 1; + copy::Bool=true, conj::Bool=false, + dual::Bool=false) W = insertleftunit(space(t), i; conj, dual) tdst = similar(t, W) for (c, b) in blocks(t) @@ -314,8 +314,8 @@ See also [`insertrightunit`](@ref) and [`removeunit`](@ref). return tdst end @constprop :aggressive function insertleftunit(t::TensorMap, i::Int=numind(t) + 1; - copy::Bool=false, - conj::Bool=false, dual::Bool=false) + copy::Bool=false, conj::Bool=false, + dual::Bool=false) W = insertleftunit(space(t), i; conj, dual) return TensorMap{scalartype(t)}(copy ? Base.copy(t.data) : t.data, W) end @@ -360,8 +360,7 @@ This operation undoes the work of [`insertunit`](@ref). W = removeunit(space(t), i) return TensorMap{scalartype(t)}(copy ? Base.copy(t.data) : t.data, W) end -@constprop :aggressive function removeunit(t::AbstractTensorMap, i::Int; - copy::Bool=true) +@constprop :aggressive function removeunit(t::AbstractTensorMap, i::Int; copy::Bool=true) W = removeunit(space(t), i) tdst = similar(t, W) for (c, b) in blocks(t) diff --git a/src/tensors/vectorinterface.jl b/src/tensors/vectorinterface.jl index 635eed66..92faa23b 100644 --- a/src/tensors/vectorinterface.jl +++ b/src/tensors/vectorinterface.jl @@ -102,8 +102,25 @@ function VectorInterface.inner(tx::AbstractTensorMap, ty::AbstractTensorMap) InnerProductStyle(tx) === EuclideanInnerProduct() || throw_invalid_innerproduct(:inner) T = VectorInterface.promote_inner(tx, ty) s = zero(T) - for c in blocksectors(tx) - s += convert(T, dim(c)) * inner(block(tx, c), block(ty, c)) + for ((cx, bx), (cy, by)) in zip(blocks(tx), blocks(ty)) + s += convert(T, dim(cx)) * inner(bx, by) end return s end +function VectorInterface.inner(tx::TensorMap, ty::TensorMap) + space(tx) == space(ty) || throw(SpaceMismatch("$(space(tx)) ≠ $(space(ty))")) + InnerProductStyle(tx) === EuclideanInnerProduct() || throw_invalid_innerproduct(:inner) + if FusionStyle(sectortype(tx)) isa UniqueFusion # all quantum dimensions are one + return inner(tx.data, ty.data) + else + T = VectorInterface.promote_inner(tx, ty) + s = zero(T) + for c in blocksectors(tx) + bx = parent(block(tx, c)) # matrix structure (reshape) does not matter + by = parent(block(ty, c)) # but does lead to slower path in inner + s += convert(T, dim(c)) * inner(bx, by) + end + end + return s +end +# TODO: do we need a fast path for `AdjointTensorMap` instances?