From 4bcc3cd9a9d6f9584cd5d7e50d344bee4faad0e9 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 20 Jun 2025 15:57:13 -0400 Subject: [PATCH 1/9] Implement fast path for `svdvals(d::DiagonalTensorMap)` --- src/tensors/diagonal.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tensors/diagonal.jl b/src/tensors/diagonal.jl index a13918d03..0a67e1a2d 100644 --- a/src/tensors/diagonal.jl +++ b/src/tensors/diagonal.jl @@ -339,6 +339,13 @@ function _compute_svddata!(d::DiagonalTensorMap, alg::Union{SVD,SDD}) return SVDdata, dims end +function LinearAlgebra.svdvals(d::DiagonalTensorMap) + return SectorDict(c => LinearAlgebra.svdvals(b) for (c, b) in blocks(d)) +end +function LinearAlgebra.svdvals!(d::DiagonalTensorMap) + return SectorDict(c => LinearAlgebra.svdvals!(b) for (c, b) in blocks(d)) +end + # matrix functions for f in (:exp, :cos, :sin, :tan, :cot, :cosh, :sinh, :tanh, :coth, :atan, :acot, :asinh, :sqrt, From 8daf3b16bcb7549e8fa73ba79c502fa6ad52d2a0 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 20 Jun 2025 16:00:40 -0400 Subject: [PATCH 2/9] Add `lmul!` and `rmul!` for `DiagonalTensorMap` --- src/tensors/diagonal.jl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tensors/diagonal.jl b/src/tensors/diagonal.jl index 0a67e1a2d..2cf1a7021 100644 --- a/src/tensors/diagonal.jl +++ b/src/tensors/diagonal.jl @@ -265,6 +265,22 @@ function LinearAlgebra.mul!(dC::DiagonalTensorMap, return dC end +function LinearAlgebra.lmul!(D::DiagonalTensorMap, t::AbstractTensorMap) + domain(D) == codomain(t) || throw(SpaceMismatch()) + for (c, b) in blocks(t) + lmul!(block(D, c), b) + end + return t +end + +function LinearAlgebra.rmul!(t::AbstractTensorMap, D::DiagonalTensorMap) + codomain(D) == domain(t) || throw(SpaceMismatch()) + for (c, b) in blocks(t) + rmul!(b, block(D, c)) + end + return t +end + Base.inv(d::DiagonalTensorMap) = DiagonalTensorMap(inv.(d.data), d.domain) function Base.:\(d1::DiagonalTensorMap, d2::DiagonalTensorMap) d1.domain == d2.domain || throw(SpaceMismatch()) From 8164214fbdb6376aa9c9fd0bf5dd415c1b4bd0bc Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 20 Jun 2025 16:01:53 -0400 Subject: [PATCH 3/9] Add more convenience `DiagonalTensorMap` constructors --- src/tensors/diagonal.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/tensors/diagonal.jl b/src/tensors/diagonal.jl index 2cf1a7021..d5753f580 100644 --- a/src/tensors/diagonal.jl +++ b/src/tensors/diagonal.jl @@ -37,6 +37,16 @@ storagetype(::Type{<:DiagonalTensorMap{T,S,A}}) where {T,S,A<:DenseVector{T}} = Construct a `DiagonalTensorMap` with uninitialized data. """ +function DiagonalTensorMap{T}(::UndefInitializer, V::TensorMapSpace) where {T} + (numin(V) == numout(V) == 1 && domain(V) == codomain(V)) || + throw(SpaceMismatch("DiagonalTensorMap requires a space with equal domain and codomain and 2 indices")) + return DiagonalTensorMap{T}(undef, domain(V)) +end +function DiagonalTensorMap{T}(::UndefInitializer, V::ProductSpace) where {T} + length(V) == 1 || + throw(DimensionMismatch("DiagonalTensorMap requires `numin(d) == numout(d) == 1`")) + return DiagonalTensorMap{T}(undef, only(V)) +end function DiagonalTensorMap{T}(::UndefInitializer, V::S) where {T,S<:IndexSpace} return DiagonalTensorMap{T,S,Vector{T}}(undef, V) end From b4a1b2c556e0bc60392313c84219fc9e1fa9186b Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Fri, 20 Jun 2025 21:18:58 -0400 Subject: [PATCH 4/9] Remove unexisting `svdvals!` and add `cond` for `DiagonalTensorMap` --- src/tensors/diagonal.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tensors/diagonal.jl b/src/tensors/diagonal.jl index d5753f580..ce5ad2467 100644 --- a/src/tensors/diagonal.jl +++ b/src/tensors/diagonal.jl @@ -368,8 +368,9 @@ end function LinearAlgebra.svdvals(d::DiagonalTensorMap) return SectorDict(c => LinearAlgebra.svdvals(b) for (c, b) in blocks(d)) end -function LinearAlgebra.svdvals!(d::DiagonalTensorMap) - return SectorDict(c => LinearAlgebra.svdvals!(b) for (c, b) in blocks(d)) + +function LinearAlgebra.cond(d::DiagonalTensorMap, p::Real=2) + return LinearAlgebra.cond(Diagonal(d.data), p) end # matrix functions From 8c6804890c91ef15626ad0a7e43926f05249d7df Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sat, 21 Jun 2025 09:33:15 -0400 Subject: [PATCH 5/9] Add testcases for `eigvals` and `svdvals` --- test/diagonal.jl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/diagonal.jl b/test/diagonal.jl index e4b3f6225..14d032846 100644 --- a/test/diagonal.jl +++ b/test/diagonal.jl @@ -175,6 +175,12 @@ diagspacelist = ((ℂ^4)', ℂ[Z2Irrep](0 => 2, 1 => 3), VdV2 = V2' * V2 @test VdV2 ≈ one(VdV2) @test t2 * V2 ≈ V2 * D2 + + @test rank(D) ≈ rank(t) + @test cond(D) ≈ cond(t) + @test all(((s, t),) -> isapprox(s, t), + zip(values(LinearAlgebra.eigvals(D)), + values(LinearAlgebra.eigvals(t)))) end @testset "leftorth with $alg" for alg in (TensorKit.QR(), TensorKit.QL()) Q, R = @constinferred leftorth(t; alg=alg) @@ -201,6 +207,12 @@ diagspacelist = ((ℂ^4)', ℂ[Z2Irrep](0 => 2, 1 => 3), VdV = Vᴴ * Vᴴ' @test VdV ≈ one(VdV) @test U * S * Vᴴ ≈ t + + @test rank(S) ≈ rank(t) + @test cond(S) ≈ cond(t) + @test all(((s, t),) -> isapprox(s, t), + zip(values(LinearAlgebra.svdvals(S)), + values(LinearAlgebra.svdvals(t)))) end end end From 0c45d0e8593a85169c1d13efab68f86f877e1e53 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sat, 21 Jun 2025 09:41:51 -0400 Subject: [PATCH 6/9] Add tests `lmul!` and `rmul!` --- test/diagonal.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/diagonal.jl b/test/diagonal.jl index 14d032846..58e0b81df 100644 --- a/test/diagonal.jl +++ b/test/diagonal.jl @@ -135,6 +135,16 @@ diagspacelist = ((ℂ^4)', ℂ[Z2Irrep](0 => 2, 1 => 3), @test u / t1 ≈ u / TensorMap(t1) @test t1 * u' ≈ TensorMap(t1) * u' @test t1 \ u' ≈ TensorMap(t1) \ u' + + t3 = rand(Float64, V ← V^2) + t4 = rand(ComplexF64, V ← V^2) + @test t1 * t3 ≈ lmul!(t1, copy(t3)) + @test t2 * t4 ≈ lmul!(t2, copy(t4)) + + t3 = rand(Float64, V^2 ← V) + t4 = rand(ComplexF64, V^2 ← V) + @test t3 * t1 ≈ rmul!(copy(t3), t1) + @test t4 * t2 ≈ rmul!(copy(t4), t2) end @timedtestset "Tensor contraction" begin d = DiagonalTensorMap(rand(ComplexF64, reduceddim(V)), V) From 77c66a6e59cbd3ddaedbb8274caf3b71a131b74c Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sat, 21 Jun 2025 09:43:36 -0400 Subject: [PATCH 7/9] Add `eigvals` specialization --- src/tensors/diagonal.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tensors/diagonal.jl b/src/tensors/diagonal.jl index ce5ad2467..1b9e4267b 100644 --- a/src/tensors/diagonal.jl +++ b/src/tensors/diagonal.jl @@ -368,6 +368,10 @@ end function LinearAlgebra.svdvals(d::DiagonalTensorMap) return SectorDict(c => LinearAlgebra.svdvals(b) for (c, b) in blocks(d)) end +function LinearAlgebra.eigvals(d::DiagonalTensorMap) + return SectorDict(c => LinearAlgebra.eigvals(b) for (c, b) in blocks(d)) +end + function LinearAlgebra.cond(d::DiagonalTensorMap, p::Real=2) return LinearAlgebra.cond(Diagonal(d.data), p) From 19a7054a755800f96a75b8ded6ef07ff52aa2e08 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Sat, 21 Jun 2025 10:03:54 -0400 Subject: [PATCH 8/9] Format --- src/tensors/diagonal.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tensors/diagonal.jl b/src/tensors/diagonal.jl index 1b9e4267b..596c9d881 100644 --- a/src/tensors/diagonal.jl +++ b/src/tensors/diagonal.jl @@ -372,7 +372,6 @@ function LinearAlgebra.eigvals(d::DiagonalTensorMap) return SectorDict(c => LinearAlgebra.eigvals(b) for (c, b) in blocks(d)) end - function LinearAlgebra.cond(d::DiagonalTensorMap, p::Real=2) return LinearAlgebra.cond(Diagonal(d.data), p) end From ffac1961c298be166165ccf2b21f35825f557275 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Wed, 25 Jun 2025 09:46:08 -0400 Subject: [PATCH 9/9] Improve test coverage --- src/tensors/diagonal.jl | 4 ++-- test/diagonal.jl | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/tensors/diagonal.jl b/src/tensors/diagonal.jl index 596c9d881..88d0c3b25 100644 --- a/src/tensors/diagonal.jl +++ b/src/tensors/diagonal.jl @@ -39,12 +39,12 @@ Construct a `DiagonalTensorMap` with uninitialized data. """ function DiagonalTensorMap{T}(::UndefInitializer, V::TensorMapSpace) where {T} (numin(V) == numout(V) == 1 && domain(V) == codomain(V)) || - throw(SpaceMismatch("DiagonalTensorMap requires a space with equal domain and codomain and 2 indices")) + throw(ArgumentError("DiagonalTensorMap requires a space with equal domain and codomain and 2 indices")) return DiagonalTensorMap{T}(undef, domain(V)) end function DiagonalTensorMap{T}(::UndefInitializer, V::ProductSpace) where {T} length(V) == 1 || - throw(DimensionMismatch("DiagonalTensorMap requires `numin(d) == numout(d) == 1`")) + throw(ArgumentError("DiagonalTensorMap requires `numin(d) == numout(d) == 1`")) return DiagonalTensorMap{T}(undef, only(V)) end function DiagonalTensorMap{T}(::UndefInitializer, V::S) where {T,S<:IndexSpace} diff --git a/test/diagonal.jl b/test/diagonal.jl index 58e0b81df..b73597b78 100644 --- a/test/diagonal.jl +++ b/test/diagonal.jl @@ -5,8 +5,16 @@ diagspacelist = ((ℂ^4)', ℂ[Z2Irrep](0 => 2, 1 => 3), @testset "DiagonalTensor with domain $V" for V in diagspacelist @timedtestset "Basic properties and algebra" begin for T in (Float32, Float64, ComplexF32, ComplexF64, BigFloat) + # constructors t = @constinferred DiagonalTensorMap{T}(undef, V) t = @constinferred DiagonalTensorMap(rand(T, reduceddim(V)), V) + t2 = @constinferred DiagonalTensorMap{T}(undef, space(t)) + @test space(t2) == space(t) + @test_throws ArgumentError DiagonalTensorMap{T}(undef, V^2 ← V) + t2 = @constinferred DiagonalTensorMap{T}(undef, domain(t)) + @test space(t2) == space(t) + @test_throws ArgumentError DiagonalTensorMap{T}(undef, V^2) + # properties @test @constinferred(hash(t)) == hash(deepcopy(t)) @test scalartype(t) == T @test codomain(t) == ProductSpace(V)