From 620587d73672a6afbb143051cbc4c1afb2a6ecba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Tue, 1 Jul 2025 11:00:57 -0400 Subject: [PATCH 1/4] define real and imag --- src/fusiontensor/base_interface.jl | 10 ++++++++-- test/test_basics.jl | 14 +++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/fusiontensor/base_interface.jl b/src/fusiontensor/base_interface.jl index 4def6f8..322b886 100644 --- a/src/fusiontensor/base_interface.jl +++ b/src/fusiontensor/base_interface.jl @@ -73,14 +73,20 @@ function Base.getindex(ft::FusionTensor, f1::SectorFusionTree, f2::SectorFusionT return reshape(charge_matrix, charge_block_size(ft, f1, f2)) end +Base.imag(ft::FusionTensor{<:Real}) = ft # same object +Base.imag(ft::FusionTensor) = set_data_matrix(ft, imag(data_matrix(ft))) + +Base.permutedims(ft::FusionTensor, args...) = fusiontensor_permutedims(ft, args...) + +Base.real(ft::FusionTensor{<:Real}) = ft # same object +Base.real(ft::FusionTensor) = set_data_matrix(ft, real(data_matrix(ft))) + function Base.setindex!( ft::FusionTensor, a::AbstractArray, f1::SectorFusionTree, f2::SectorFusionTree ) return view(ft, f1, f2) .= a end -Base.permutedims(ft::FusionTensor, args...) = fusiontensor_permutedims(ft, args...) - function Base.similar(ft::FusionTensor, T::Type) # reuse trees_block_mapping diff --git a/test/test_basics.jl b/test/test_basics.jl index 295cfc0..def4c6c 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -238,7 +238,7 @@ end @test isnothing(check_sanity(ft4)) @test eltype(ft4) == Float64 - ft5 = 2.0im * ft3 + ft5 = (1.0 + 2.0im) * ft3 @test codomain_axes(ft5) === codomain_axes(ft3) @test domain_axes(ft5) === domain_axes(ft3) @test space_isequal(codomain_axis(ft5), codomain_axis(ft3)) @@ -246,8 +246,16 @@ end @test isnothing(check_sanity(ft4)) @test eltype(ft5) == ComplexF64 - ft4 = conj(ft3) - @test ft4 === ft3 # same object + @test conj(ft3) === ft3 # same object + @test real(ft3) === ft3 + @test norm(imag(ft3)) == 0.0 + + @test conj(ft5) isa FusionTensor{ComplexF64,4} + @test real(ft5) isa FusionTensor{Float64,4} + @test imag(ft3) isa FusionTensor{Float64,4} + @test conj(ft5) ≈ (1.0 - 2.0im) * ft3 + @test real(ft5) ≈ ft3 + @test imag(ft3) ≈ 2ft3 ft6 = conj(ft5) @test ft6 !== ft5 # different object From ebe680017de3ff4b33259bba2bf53304765e82c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Tue, 1 Jul 2025 11:01:23 -0400 Subject: [PATCH 2/4] bump version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index d5f94a7..d8cf8f5 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "FusionTensors" uuid = "e16ca583-1f51-4df0-8e12-57d32947d33e" authors = ["ITensor developers and contributors"] -version = "0.5.1" +version = "0.5.2" [deps] Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" From 0b31121519757516fb565b04abe6782cd1c23927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Tue, 1 Jul 2025 11:08:23 -0400 Subject: [PATCH 3/4] fix test --- test/test_basics.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_basics.jl b/test/test_basics.jl index def4c6c..2da9b5d 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -248,7 +248,7 @@ end @test conj(ft3) === ft3 # same object @test real(ft3) === ft3 - @test norm(imag(ft3)) == 0.0 + @test all(==(0.0), data_matrix(imag(ft3))) @test conj(ft5) isa FusionTensor{ComplexF64,4} @test real(ft5) isa FusionTensor{Float64,4} From 063a4c3f31472d6ce79fc8d2aa3b08c98fab62c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Tue, 1 Jul 2025 17:09:07 -0400 Subject: [PATCH 4/4] fix imag --- src/fusiontensor/base_interface.jl | 1 - test/test_basics.jl | 96 +++++++++++++++++------------- 2 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/fusiontensor/base_interface.jl b/src/fusiontensor/base_interface.jl index 322b886..ea3241d 100644 --- a/src/fusiontensor/base_interface.jl +++ b/src/fusiontensor/base_interface.jl @@ -73,7 +73,6 @@ function Base.getindex(ft::FusionTensor, f1::SectorFusionTree, f2::SectorFusionT return reshape(charge_matrix, charge_block_size(ft, f1, f2)) end -Base.imag(ft::FusionTensor{<:Real}) = ft # same object Base.imag(ft::FusionTensor) = set_data_matrix(ft, imag(data_matrix(ft))) Base.permutedims(ft::FusionTensor, args...) = fusiontensor_permutedims(ft, args...) diff --git a/test/test_basics.jl b/test/test_basics.jl index 2da9b5d..a575664 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -28,7 +28,7 @@ using GradedArrays: space_isequal using TensorAlgebra: tuplemortar using TensorProducts: tensor_product -using LinearAlgebra: LinearAlgebra +using LinearAlgebra: LinearAlgebra, norm using Random: Random include("setup.jl") @@ -184,12 +184,53 @@ end @test sector_type(ft3) === TrivialSector end +@testset "specific constructors" begin + g1 = gradedrange([U1(0) => 1, U1(1) => 2, U1(2) => 3]) + g2 = gradedrange([U1(0) => 2, U1(1) => 2, U1(3) => 1]) + g3 = gradedrange([U1(-1) => 1, U1(0) => 2, U1(1) => 1]) + g4 = gradedrange([U1(-1) => 1, U1(0) => 1, U1(1) => 1]) + + fta = FusionTensorAxes((g1,), (g2, g3)) + @test zeros(fta) isa FusionTensor{Float64,3} + @test zeros(ComplexF64, fta) isa FusionTensor{ComplexF64,3} + + rng = Random.default_rng() + ft1 = randn(rng, ComplexF64, fta) + @test ft1 isa FusionTensor{ComplexF64,3} + @test all(!=(0), data_matrix(ft1)[Block(1, 5)]) + @test randn(rng, fta) isa FusionTensor{Float64,3} + @test randn(ComplexF64, fta) isa FusionTensor{ComplexF64,3} + @test randn(fta) isa FusionTensor{Float64,3} + + ft2 = FusionTensor(LinearAlgebra.I, (g1, g2)) + @test ft2 isa FusionTensor{Float64,4} + @test axes(ft2) == FusionTensorAxes((g1, g2), dual.((g1, g2))) + @test collect(eachblockstoredindex(data_matrix(ft2))) == map(i -> Block(i, i), 1:6) + for i in 1:6 + m = data_matrix(ft2)[Block(i, i)] + @test m == LinearAlgebra.I(size(m, 1)) + end + + ft2 = FusionTensor(3 * LinearAlgebra.I, (g1, g2)) + @test ft2 isa FusionTensor{Float64,4} + @test axes(ft2) == FusionTensorAxes((g1, g2), dual.((g1, g2))) + @test collect(eachblockstoredindex(data_matrix(ft2))) == map(i -> Block(i, i), 1:6) + for i in 1:6 + m = data_matrix(ft2)[Block(i, i)] + @test m == 3 * LinearAlgebra.I(size(m, 1)) + end + + @test FusionTensor{ComplexF64}(LinearAlgebra.I, (g1, g2)) isa FusionTensor{ComplexF64,4} +end + @testset "Base operations" begin g1 = gradedrange([U1(0) => 1, U1(1) => 2, U1(2) => 3]) g2 = gradedrange([U1(0) => 2, U1(1) => 2, U1(3) => 1]) g3 = gradedrange([U1(-1) => 1, U1(0) => 2, U1(1) => 1]) g4 = gradedrange([U1(-1) => 1, U1(0) => 1, U1(1) => 1]) - ft3 = FusionTensor{Float64}(undef, (g1, g2), (g3, g4)) + ft3 = randn(FusionTensorAxes((g1, g2), (g3, g4))) + @test ft3 isa FusionTensor{Float64,4} + @test norm(ft3) ≉ 0 @test isnothing(check_sanity(ft3)) ft4 = +ft3 @@ -199,6 +240,8 @@ end @test isnothing(check_sanity(ft4)) @test codomain_axes(ft4) === codomain_axes(ft3) @test domain_axes(ft4) === domain_axes(ft3) + @test norm(ft4) ≈ norm(ft3) + @test norm(ft4 + ft3) ≈ 0.0 ft4 = ft3 + ft3 @test codomain_axes(ft4) === codomain_axes(ft3) @@ -206,6 +249,7 @@ end @test space_isequal(codomain_axis(ft4), codomain_axis(ft3)) @test space_isequal(domain_axis(ft4), domain_axis(ft3)) @test isnothing(check_sanity(ft4)) + @test norm(ft4) ≈ 2norm(ft3) ft4 = ft3 - ft3 @test codomain_axes(ft4) === codomain_axes(ft3) @@ -213,6 +257,7 @@ end @test space_isequal(codomain_axis(ft4), codomain_axis(ft3)) @test space_isequal(domain_axis(ft4), domain_axis(ft3)) @test isnothing(check_sanity(ft4)) + @test norm(ft4) ≈ 0.0 ft4 = 2 * ft3 @test codomain_axes(ft4) === codomain_axes(ft3) @@ -221,6 +266,7 @@ end @test space_isequal(domain_axis(ft4), domain_axis(ft3)) @test isnothing(check_sanity(ft4)) @test eltype(ft4) == Float64 + @test norm(ft4) ≈ 2norm(ft3) ft4 = 2.0 * ft3 @test codomain_axes(ft4) === codomain_axes(ft3) @@ -237,6 +283,7 @@ end @test space_isequal(domain_axis(ft4), domain_axis(ft3)) @test isnothing(check_sanity(ft4)) @test eltype(ft4) == Float64 + @test norm(ft4) ≈ norm(ft3) / 2.0 ft5 = (1.0 + 2.0im) * ft3 @test codomain_axes(ft5) === codomain_axes(ft3) @@ -245,17 +292,18 @@ end @test space_isequal(domain_axis(ft5), domain_axis(ft3)) @test isnothing(check_sanity(ft4)) @test eltype(ft5) == ComplexF64 + @test norm(ft5) ≈ √5 * norm(ft3) @test conj(ft3) === ft3 # same object @test real(ft3) === ft3 - @test all(==(0.0), data_matrix(imag(ft3))) + @test norm(imag(ft3)) == 0 @test conj(ft5) isa FusionTensor{ComplexF64,4} @test real(ft5) isa FusionTensor{Float64,4} @test imag(ft3) isa FusionTensor{Float64,4} @test conj(ft5) ≈ (1.0 - 2.0im) * ft3 @test real(ft5) ≈ ft3 - @test imag(ft3) ≈ 2ft3 + @test imag(ft5) ≈ 2ft3 ft6 = conj(ft5) @test ft6 !== ft5 # different object @@ -265,6 +313,7 @@ end @test space_isequal(codomain_axis(ft6), codomain_axis(ft5)) @test space_isequal(domain_axis(ft6), domain_axis(ft5)) @test eltype(ft6) == ComplexF64 + @test ft6 + ft5 ≈ 2 * real(ft5) ad = adjoint(ft3) @test ad isa FusionTensor @@ -282,45 +331,6 @@ end @test_throws ArgumentError ft7 * ft3 end -@testset "specific constructors" begin - g1 = gradedrange([U1(0) => 1, U1(1) => 2, U1(2) => 3]) - g2 = gradedrange([U1(0) => 2, U1(1) => 2, U1(3) => 1]) - g3 = gradedrange([U1(-1) => 1, U1(0) => 2, U1(1) => 1]) - g4 = gradedrange([U1(-1) => 1, U1(0) => 1, U1(1) => 1]) - - fta = FusionTensorAxes((g1,), (g2, g3)) - @test zeros(fta) isa FusionTensor{Float64,3} - @test zeros(ComplexF64, fta) isa FusionTensor{ComplexF64,3} - - rng = Random.default_rng() - ft1 = randn(rng, ComplexF64, fta) - @test ft1 isa FusionTensor{ComplexF64,3} - @test all(!=(0), data_matrix(ft1)[Block(1, 5)]) - @test randn(rng, fta) isa FusionTensor{Float64,3} - @test randn(ComplexF64, fta) isa FusionTensor{ComplexF64,3} - @test randn(fta) isa FusionTensor{Float64,3} - - ft2 = FusionTensor(LinearAlgebra.I, (g1, g2)) - @test ft2 isa FusionTensor{Float64,4} - @test axes(ft2) == FusionTensorAxes((g1, g2), dual.((g1, g2))) - @test collect(eachblockstoredindex(data_matrix(ft2))) == map(i -> Block(i, i), 1:6) - for i in 1:6 - m = data_matrix(ft2)[Block(i, i)] - @test m == LinearAlgebra.I(size(m, 1)) - end - - ft2 = FusionTensor(3 * LinearAlgebra.I, (g1, g2)) - @test ft2 isa FusionTensor{Float64,4} - @test axes(ft2) == FusionTensorAxes((g1, g2), dual.((g1, g2))) - @test collect(eachblockstoredindex(data_matrix(ft2))) == map(i -> Block(i, i), 1:6) - for i in 1:6 - m = data_matrix(ft2)[Block(i, i)] - @test m == 3 * LinearAlgebra.I(size(m, 1)) - end - - @test FusionTensor{ComplexF64}(LinearAlgebra.I, (g1, g2)) isa FusionTensor{ComplexF64,4} -end - @testset "missing SectorProduct" begin g1 = gradedrange([SectorProduct(U1(1)) => 1]) g2 = gradedrange([SectorProduct(U1(1), SU2(1//2)) => 1])