From ffee4eea68f9e03db0cb6f8edbcb41feab1eb198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Tue, 1 Apr 2025 17:17:08 -0400 Subject: [PATCH 1/9] more generic broadcast --- Project.toml | 2 +- src/blockedtuple.jl | 30 ++++++++++++++++++++++++++++-- test/test_blockedtuple.jl | 26 +++++++++++++++++++++++++- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/Project.toml b/Project.toml index 5d3d28f..bbd6420 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "TensorAlgebra" uuid = "68bd88dc-f39d-4e12-b2ca-f046b68fcc6a" authors = ["ITensor developers and contributors"] -version = "0.2.7" +version = "0.2.8" [deps] ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" diff --git a/src/blockedtuple.jl b/src/blockedtuple.jl index 5cf0c9a..f47f336 100644 --- a/src/blockedtuple.jl +++ b/src/blockedtuple.jl @@ -70,12 +70,38 @@ function Base.BroadcastStyle(T::Type{<:AbstractBlockTuple}) return AbstractBlockTupleBroadcastStyle{blocklengths(T),unspecify_type_parameters(T)}() end -# BroadcastStyle is not called for two identical styles +# BroadcastStyle(::Style1, ::Style2) is not called when Style1 == Style2 +# tuplemortar(((1,), (2,))) .== tuplemortar(((1,), (2,))) = tuplemortar(((true,), (true,))) +# tuplemortar(((1,), (2,))) .== tuplemortar(((1, 2),)) = (true, true) +# tuplemortar(((1,), (2,))) .== tuplemortar(((1,), (2,), (3,))) = error DimensionMismatch + function Base.BroadcastStyle( ::AbstractBlockTupleBroadcastStyle, ::AbstractBlockTupleBroadcastStyle ) - throw(DimensionMismatch("Incompatible blocks")) + return Base.Broadcast.Style{Tuple}() +end + +# tuplemortar(((1,), (2,))) .== (1, 2) = (true, true) +function Base.BroadcastStyle( + ::AbstractBlockTupleBroadcastStyle, ::Base.Broadcast.Style{Tuple} +) + return Base.Broadcast.Style{Tuple}() +end + +# tuplemortar(((1,), (2,))) .== 1 = (true, false) +function Base.BroadcastStyle( + ::Base.Broadcast.DefaultArrayStyle{0}, s::AbstractBlockTupleBroadcastStyle +) + return s end + +# tuplemortar(((1,), (2,))) .== [1, 1] = BlockVector([true, false], [1, 1]) +function Base.BroadcastStyle( + a::Base.Broadcast.AbstractArrayStyle, ::AbstractBlockTupleBroadcastStyle +) + return a +end + function Base.copy( bc::Broadcast.Broadcasted{AbstractBlockTupleBroadcastStyle{BlockLengths,BT}} ) where {BlockLengths,BT} diff --git a/test/test_blockedtuple.jl b/test/test_blockedtuple.jl index 5973f6f..5c6fe76 100644 --- a/test/test_blockedtuple.jl +++ b/test/test_blockedtuple.jl @@ -54,12 +54,36 @@ using TensorAlgebra: BlockedTuple, blockeachindex, tuplemortar BlockedTuple{3,blocklengths(bt)}(Tuple(bt) .+ 1) @test (@constinferred bt .+ tuplemortar(((1,), (1, 1), (1, 1)))) == BlockedTuple{3,blocklengths(bt)}(Tuple(bt) .+ 1) - @test_throws DimensionMismatch bt .+ tuplemortar(((1, 1), (1, 1), (1,))) + @test bt .+ tuplemortar(((1, 1), (1, 1), (1,))) isa NTuple{5,Int} + @test bt .+ tuplemortar(((1, 1), (1, 1), (1,))) == (2, 5, 3, 6, 4) bt = tuplemortar(((1:2, 1:2), (1:3,))) @test length.(bt) == tuplemortar(((2, 2), (3,))) @test length.(length.(bt)) == tuplemortar(((1, 1), (1,))) + bt = tuplemortar(((1,), (2,))) + @test (bt .== bt) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test (bt .== bt) == tuplemortar(((true,), (true,))) + @test (bt .== tuplemortar(((1, 2),))) isa Tuple{Bool,Bool} + @test (bt .== tuplemortar(((1, 2),))) == (true, true) + @test_throws DimensionMismatch bt .== tuplemortar(((1,), (2,), (3,))) + @test (bt .== (1, 2)) isa Tuple{Bool,Bool} + @test (bt .== (1, 2)) == (true, true) + @test_throws DimensionMismatch bt .== (1, 2, 3) + @test (bt .== 1) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test (bt .== 1) == tuplemortar(((true,), (false,))) + @test (bt .== [1, 1]) isa BlockVector{Bool} + @test blocks(bt .== [1, 1]) == [[true], [false]] + @test_throws DimensionMismatch bt .== [1, 2, 3] + + @test ((1, 2) .== bt) isa Tuple{Bool,Bool} + @test ((1, 2) .== bt) == (true, true) + @test_throws DimensionMismatch (1, 2, 3) .== bt + @test (1 .== bt) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test (1 .== bt) == tuplemortar(((true,), (false,))) + @test ([1, 1] .== bt) isa BlockVector{Bool} + @test blocks([1, 1] .== bt) == [[true], [false]] + # empty blocks bt = tuplemortar(((1,), (), (5, 3))) @test bt isa BlockedTuple{3} From 186186d123ca14aa54c7b6c928f7608be333a03e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Tue, 1 Apr 2025 17:27:35 -0400 Subject: [PATCH 2/9] fix test import --- test/test_blockedtuple.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_blockedtuple.jl b/test/test_blockedtuple.jl index 5c6fe76..c929d7f 100644 --- a/test/test_blockedtuple.jl +++ b/test/test_blockedtuple.jl @@ -1,6 +1,7 @@ using Test: @test, @test_throws -using BlockArrays: Block, blocklength, blocklengths, blockedrange, blockisequal, blocks +using BlockArrays: + Block, BlockVector, blocklength, blocklengths, blockedrange, blockisequal, blocks using TestExtras: @constinferred using TensorAlgebra: BlockedTuple, blockeachindex, tuplemortar From ee8bdf12b9a4f0ac15e72436036710a8838d5af8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Tue, 1 Apr 2025 17:37:44 -0400 Subject: [PATCH 3/9] typos --- src/blockedtuple.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/blockedtuple.jl b/src/blockedtuple.jl index f47f336..26fa926 100644 --- a/src/blockedtuple.jl +++ b/src/blockedtuple.jl @@ -10,7 +10,7 @@ using TypeParameterAccessors: unspecify_type_parameters # ================================== AbstractBlockTuple ================================== # # AbstractBlockTuple imposes BlockLength as first type parameter for easy dispatch -# it makes no assumotion on storage type +# it makes no assumption on storage type abstract type AbstractBlockTuple{BlockLength} end constructorof(type::Type{<:AbstractBlockTuple}) = unspecify_type_parameters(type) @@ -74,7 +74,6 @@ end # tuplemortar(((1,), (2,))) .== tuplemortar(((1,), (2,))) = tuplemortar(((true,), (true,))) # tuplemortar(((1,), (2,))) .== tuplemortar(((1, 2),)) = (true, true) # tuplemortar(((1,), (2,))) .== tuplemortar(((1,), (2,), (3,))) = error DimensionMismatch - function Base.BroadcastStyle( ::AbstractBlockTupleBroadcastStyle, ::AbstractBlockTupleBroadcastStyle ) From 7d26238e7b83b0d6f436f230bd7b9ada994a3673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Tue, 1 Apr 2025 19:16:55 -0400 Subject: [PATCH 4/9] preserve block structure --- src/blockedtuple.jl | 29 +++++++++++++++++++++++++---- test/test_blockedtuple.jl | 10 ++++++---- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/blockedtuple.jl b/src/blockedtuple.jl index 26fa926..986d340 100644 --- a/src/blockedtuple.jl +++ b/src/blockedtuple.jl @@ -4,7 +4,7 @@ using BlockArrays: Block, BlockArrays, BlockIndexRange, BlockRange, blockedrange -using TypeParameterAccessors: unspecify_type_parameters +using TypeParameterAccessors: type_parameters, unspecify_type_parameters # # ================================== AbstractBlockTuple ================================== @@ -72,12 +72,33 @@ end # BroadcastStyle(::Style1, ::Style2) is not called when Style1 == Style2 # tuplemortar(((1,), (2,))) .== tuplemortar(((1,), (2,))) = tuplemortar(((true,), (true,))) -# tuplemortar(((1,), (2,))) .== tuplemortar(((1, 2),)) = (true, true) +# tuplemortar(((1,), (2,))) .== tuplemortar(((1, 2),)) = tuplemortar(((true,), (true,))) # tuplemortar(((1,), (2,))) .== tuplemortar(((1,), (2,), (3,))) = error DimensionMismatch function Base.BroadcastStyle( - ::AbstractBlockTupleBroadcastStyle, ::AbstractBlockTupleBroadcastStyle + s1::AbstractBlockTupleBroadcastStyle, s2::AbstractBlockTupleBroadcastStyle ) - return Base.Broadcast.Style{Tuple}() + blocklengths1 = type_parameters(s1, 1) + blocklengths2 = type_parameters(s2, 1) + sum(blocklengths1) != sum(blocklengths2) && + throw(DimensionMismatch("blocked tuples could not be broadcast to a common size")) + new_blocklasts = static_mergesort(cumsum(blocklengths1), cumsum(blocklengths2)) + new_blocklengths = ( + first(new_blocklasts), Base.tail(new_blocklasts) .- Base.front(new_blocklasts)... + ) + return AbstractBlockTupleBroadcastStyle{new_blocklengths,type_parameters(s1, 2)}() +end + +static_mergesort(::Tuple{}, ::Tuple{}) = () +static_mergesort(a::Tuple, ::Tuple{}) = a +static_mergesort(::Tuple{}, b::Tuple) = b +function static_mergesort(a::Tuple, b::Tuple) + if first(a) == first(b) + return (first(a), static_mergesort(Base.tail(a), Base.tail(b))...) + end + if first(a) < first(b) + return (first(a), static_mergesort(Base.tail(a), b)...) + end + return (first(b), static_mergesort(a, Base.tail(b))...) end # tuplemortar(((1,), (2,))) .== (1, 2) = (true, true) diff --git a/test/test_blockedtuple.jl b/test/test_blockedtuple.jl index c929d7f..d71445d 100644 --- a/test/test_blockedtuple.jl +++ b/test/test_blockedtuple.jl @@ -55,8 +55,10 @@ using TensorAlgebra: BlockedTuple, blockeachindex, tuplemortar BlockedTuple{3,blocklengths(bt)}(Tuple(bt) .+ 1) @test (@constinferred bt .+ tuplemortar(((1,), (1, 1), (1, 1)))) == BlockedTuple{3,blocklengths(bt)}(Tuple(bt) .+ 1) - @test bt .+ tuplemortar(((1, 1), (1, 1), (1,))) isa NTuple{5,Int} - @test bt .+ tuplemortar(((1, 1), (1, 1), (1,))) == (2, 5, 3, 6, 4) + @test (@constinferred bt .+ tuplemortar(((1,), (1, 1, 1), (1,)))) isa + BlockedTuple{4,(1, 2, 1, 1),NTuple{5,Int64}} + @test bt .+ tuplemortar(((1,), (1, 1, 1), (1,))) == + tuplemortar(((2,), (5, 3), (6,), (4,))) bt = tuplemortar(((1:2, 1:2), (1:3,))) @test length.(bt) == tuplemortar(((2, 2), (3,))) @@ -65,8 +67,8 @@ using TensorAlgebra: BlockedTuple, blockeachindex, tuplemortar bt = tuplemortar(((1,), (2,))) @test (bt .== bt) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} @test (bt .== bt) == tuplemortar(((true,), (true,))) - @test (bt .== tuplemortar(((1, 2),))) isa Tuple{Bool,Bool} - @test (bt .== tuplemortar(((1, 2),))) == (true, true) + @test (bt .== tuplemortar(((1, 2),))) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test (bt .== tuplemortar(((1, 2),))) == tuplemortar(((true,), (true,))) @test_throws DimensionMismatch bt .== tuplemortar(((1,), (2,), (3,))) @test (bt .== (1, 2)) isa Tuple{Bool,Bool} @test (bt .== (1, 2)) == (true, true) From e6332704447de1e0967795ff11b619145e17d79d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Wed, 2 Apr 2025 10:49:29 -0400 Subject: [PATCH 5/9] fix axes with blocklength=0 --- src/blockedtuple.jl | 1 + test/test_blockedtuple.jl | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/blockedtuple.jl b/src/blockedtuple.jl index 986d340..cb77b45 100644 --- a/src/blockedtuple.jl +++ b/src/blockedtuple.jl @@ -23,6 +23,7 @@ end # Base interface Base.axes(bt::AbstractBlockTuple) = (blockedrange([blocklengths(bt)...]),) +Base.axes(::AbstractBlockTuple{0}) = (blockedrange(zeros(Int, 0)),) Base.deepcopy(bt::AbstractBlockTuple) = deepcopy.(bt) diff --git a/test/test_blockedtuple.jl b/test/test_blockedtuple.jl index d71445d..2c9d303 100644 --- a/test/test_blockedtuple.jl +++ b/test/test_blockedtuple.jl @@ -93,16 +93,19 @@ using TensorAlgebra: BlockedTuple, blockeachindex, tuplemortar @test Tuple(bt) == (1, 5, 3) @test blocklengths(bt) == (1, 0, 2) @test (@constinferred blocks(bt)) == ((1,), (), (5, 3)) + @test blockisequal(only(axes(bt)), blockedrange([1, 0, 2])) bt = tuplemortar(((), ())) @test bt isa BlockedTuple{2} @test Tuple(bt) == () @test blocklengths(bt) == (0, 0) @test (@constinferred blocks(bt)) == ((), ()) + @test blockisequal(only(axes(bt)), blockedrange([0, 0])) bt = tuplemortar(()) @test bt isa BlockedTuple{0} @test Tuple(bt) == () @test blocklengths(bt) == () @test (@constinferred blocks(bt)) == () + @test blockisequal(only(axes(bt)), blockedrange(zeros(Int, 0))) end From 28a528ed4e6ab5cce6b6b48934c6b3fc30d3defb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Wed, 2 Apr 2025 10:51:31 -0400 Subject: [PATCH 6/9] remove junk comment --- src/blockedtuple.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/blockedtuple.jl b/src/blockedtuple.jl index cb77b45..62fcc83 100644 --- a/src/blockedtuple.jl +++ b/src/blockedtuple.jl @@ -151,8 +151,6 @@ function BlockArrays.blocks(bt::AbstractBlockTuple) return ntuple(i -> Tuple(bt)[bf[i]:bl[i]], blocklength(bt)) end -# length(BlockLengths) != BlockLength && throw(DimensionMismatch("Invalid blocklength")) - # ===================================== BlockedTuple ===================================== # struct BlockedTuple{BlockLength,BlockLengths,Flat} <: AbstractBlockTuple{BlockLength} From 81ac06a8748454477bc4a4ed7aa5b3bcd8a7921e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Wed, 2 Apr 2025 17:28:56 -0400 Subject: [PATCH 7/9] fix broadcast type parameter --- src/blockedtuple.jl | 12 ++++++--- test/test_blockedpermutation.jl | 4 +++ test/test_blockedtuple.jl | 43 +++++++++++++++++++++------------ 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/blockedtuple.jl b/src/blockedtuple.jl index 62fcc83..be9744b 100644 --- a/src/blockedtuple.jl +++ b/src/blockedtuple.jl @@ -71,6 +71,9 @@ function Base.BroadcastStyle(T::Type{<:AbstractBlockTuple}) return AbstractBlockTupleBroadcastStyle{blocklengths(T),unspecify_type_parameters(T)}() end +# default +combine_types(::Type{<:AbstractBlockTuple}, ::Type{<:AbstractBlockTuple}) = BlockedTuple + # BroadcastStyle(::Style1, ::Style2) is not called when Style1 == Style2 # tuplemortar(((1,), (2,))) .== tuplemortar(((1,), (2,))) = tuplemortar(((true,), (true,))) # tuplemortar(((1,), (2,))) .== tuplemortar(((1, 2),)) = tuplemortar(((true,), (true,))) @@ -80,13 +83,14 @@ function Base.BroadcastStyle( ) blocklengths1 = type_parameters(s1, 1) blocklengths2 = type_parameters(s2, 1) - sum(blocklengths1) != sum(blocklengths2) && + sum(blocklengths1; init=0) != sum(blocklengths2; init=0) && throw(DimensionMismatch("blocked tuples could not be broadcast to a common size")) new_blocklasts = static_mergesort(cumsum(blocklengths1), cumsum(blocklengths2)) new_blocklengths = ( first(new_blocklasts), Base.tail(new_blocklasts) .- Base.front(new_blocklasts)... ) - return AbstractBlockTupleBroadcastStyle{new_blocklengths,type_parameters(s1, 2)}() + BT = combine_types(type_parameters(s1, 2), type_parameters(s2, 2)) + return AbstractBlockTupleBroadcastStyle{new_blocklengths,BT}() end static_mergesort(::Tuple{}, ::Tuple{}) = () @@ -104,9 +108,9 @@ end # tuplemortar(((1,), (2,))) .== (1, 2) = (true, true) function Base.BroadcastStyle( - ::AbstractBlockTupleBroadcastStyle, ::Base.Broadcast.Style{Tuple} + s::AbstractBlockTupleBroadcastStyle, ::Base.Broadcast.Style{Tuple} ) - return Base.Broadcast.Style{Tuple}() + return s end # tuplemortar(((1,), (2,))) .== 1 = (true, false) diff --git a/test/test_blockedpermutation.jl b/test/test_blockedpermutation.jl index e411540..e9198a9 100644 --- a/test/test_blockedpermutation.jl +++ b/test/test_blockedpermutation.jl @@ -77,6 +77,8 @@ using TensorAlgebra: @test (@constinferred BlockedTuple(p)) == bt @test (@constinferred map(identity, p)) == bt @test (@constinferred p .+ p) == tuplemortar(((6, 4), (), (2,))) + @test (@constinferred p .+ bt) == tuplemortar(((6, 4), (), (2,))) + @test (@constinferred bt .+ p) == tuplemortar(((6, 4), (), (2,))) @test (@constinferred blockedperm(p)) == p @test (@constinferred blockedperm(bt)) == p @@ -149,6 +151,8 @@ end @test (@constinferred blocks(tp)) == blocks(bt) @test (@constinferred map(identity, tp)) == bt @test (@constinferred tp .+ tp) == tuplemortar(((2, 4), (), (6,))) + @test (@constinferred tp .+ Tuple(tp)) == tuplemortar(((2, 4), (), (6,))) + @test (@constinferred tp .+ BlockedTuple(tp)) == tuplemortar(((2, 4), (), (6,))) @test (@constinferred blockedperm(tp)) == tp @test (@constinferred trivialperm(tp)) == tp @test (@constinferred trivialperm(bt)) == tp diff --git a/test/test_blockedtuple.jl b/test/test_blockedtuple.jl index 2c9d303..97728dd 100644 --- a/test/test_blockedtuple.jl +++ b/test/test_blockedtuple.jl @@ -65,25 +65,32 @@ using TensorAlgebra: BlockedTuple, blockeachindex, tuplemortar @test length.(length.(bt)) == tuplemortar(((1, 1), (1,))) bt = tuplemortar(((1,), (2,))) - @test (bt .== bt) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test (@constinferred bt .== bt) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} @test (bt .== bt) == tuplemortar(((true,), (true,))) - @test (bt .== tuplemortar(((1, 2),))) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test (@constinferred bt .== tuplemortar(((1, 2),))) isa + BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} @test (bt .== tuplemortar(((1, 2),))) == tuplemortar(((true,), (true,))) @test_throws DimensionMismatch bt .== tuplemortar(((1,), (2,), (3,))) - @test (bt .== (1, 2)) isa Tuple{Bool,Bool} - @test (bt .== (1, 2)) == (true, true) + @test (@constinferred bt .== (1, 2)) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test (bt .== (1, 2)) == tuplemortar(((true,), (true,))) @test_throws DimensionMismatch bt .== (1, 2, 3) - @test (bt .== 1) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test (@constinferred bt .== 1) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} @test (bt .== 1) == tuplemortar(((true,), (false,))) + @test (@constinferred bt .== (1,)) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test (bt .== (1,)) == tuplemortar(((true,), (false,))) + @test_broken @inferred bt .== [1, 1] @test (bt .== [1, 1]) isa BlockVector{Bool} @test blocks(bt .== [1, 1]) == [[true], [false]] @test_throws DimensionMismatch bt .== [1, 2, 3] - @test ((1, 2) .== bt) isa Tuple{Bool,Bool} - @test ((1, 2) .== bt) == (true, true) + @test (@constinferred (1, 2) .== bt) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test ((1, 2) .== bt) == tuplemortar(((true,), (true,))) @test_throws DimensionMismatch (1, 2, 3) .== bt - @test (1 .== bt) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test (@constinferred 1 .== bt) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} @test (1 .== bt) == tuplemortar(((true,), (false,))) + @test (@constinferred (1,) .== bt) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test ((1,) .== bt) == tuplemortar(((true,), (false,))) + @test_broken @inferred [1, 1] .== bt @test ([1, 1] .== bt) isa BlockVector{Bool} @test blocks([1, 1] .== bt) == [[true], [false]] @@ -101,11 +108,17 @@ using TensorAlgebra: BlockedTuple, blockeachindex, tuplemortar @test blocklengths(bt) == (0, 0) @test (@constinferred blocks(bt)) == ((), ()) @test blockisequal(only(axes(bt)), blockedrange([0, 0])) - - bt = tuplemortar(()) - @test bt isa BlockedTuple{0} - @test Tuple(bt) == () - @test blocklengths(bt) == () - @test (@constinferred blocks(bt)) == () - @test blockisequal(only(axes(bt)), blockedrange(zeros(Int, 0))) + @test bt == bt .+ bt + + bt0 = tuplemortar(()) + bt1 = tuplemortar(((),)) + @test bt0 isa BlockedTuple{0} + @test Tuple(bt0) == () + @test blocklengths(bt0) == () + @test (@constinferred blocks(bt0)) == () + @test blockisequal(only(axes(bt0)), blockedrange(zeros(Int, 0))) + @test bt0 == bt0 + @test bt != bt1 + @test (@constinferred bt0 .+ bt0) == bt0 + @test (@constinferred bt0 .+ bt1) == bt1 end From 085ffbe430ce735b0f9c055575a5e5c906dc95be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Thu, 3 Apr 2025 10:13:01 -0400 Subject: [PATCH 8/9] remove test_broken --- test/test_blockedtuple.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_blockedtuple.jl b/test/test_blockedtuple.jl index 97728dd..b19b8ab 100644 --- a/test/test_blockedtuple.jl +++ b/test/test_blockedtuple.jl @@ -1,4 +1,4 @@ -using Test: @test, @test_throws +using Test: @test, @test_throws, @testset using BlockArrays: Block, BlockVector, blocklength, blocklengths, blockedrange, blockisequal, blocks @@ -77,8 +77,9 @@ using TensorAlgebra: BlockedTuple, blockeachindex, tuplemortar @test (@constinferred bt .== 1) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} @test (bt .== 1) == tuplemortar(((true,), (false,))) @test (@constinferred bt .== (1,)) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} + @test (bt .== (1,)) == tuplemortar(((true,), (false,))) - @test_broken @inferred bt .== [1, 1] + # BlockedTuple .== AbstractVector is not type stable. Requires fix in BlockArrays @test (bt .== [1, 1]) isa BlockVector{Bool} @test blocks(bt .== [1, 1]) == [[true], [false]] @test_throws DimensionMismatch bt .== [1, 2, 3] @@ -90,7 +91,6 @@ using TensorAlgebra: BlockedTuple, blockeachindex, tuplemortar @test (1 .== bt) == tuplemortar(((true,), (false,))) @test (@constinferred (1,) .== bt) isa BlockedTuple{2,(1, 1),Tuple{Bool,Bool}} @test ((1,) .== bt) == tuplemortar(((true,), (false,))) - @test_broken @inferred [1, 1] .== bt @test ([1, 1] .== bt) isa BlockVector{Bool} @test blocks([1, 1] .== bt) == [[true], [false]] From 109db157f1ba31543a9df15c6fe32e791ad68c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Gauth=C3=A9?= Date: Thu, 3 Apr 2025 15:43:26 -0400 Subject: [PATCH 9/9] blockedrange(Int[]) --- src/blockedtuple.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blockedtuple.jl b/src/blockedtuple.jl index be9744b..30db0bd 100644 --- a/src/blockedtuple.jl +++ b/src/blockedtuple.jl @@ -23,7 +23,7 @@ end # Base interface Base.axes(bt::AbstractBlockTuple) = (blockedrange([blocklengths(bt)...]),) -Base.axes(::AbstractBlockTuple{0}) = (blockedrange(zeros(Int, 0)),) +Base.axes(::AbstractBlockTuple{0}) = (blockedrange(Int[]),) Base.deepcopy(bt::AbstractBlockTuple) = deepcopy.(bt)