From f36cfb40ab5cd579652df31774d4d2e9d64bd8d6 Mon Sep 17 00:00:00 2001 From: Daan Huybrechs Date: Tue, 25 Feb 2020 10:29:22 +0100 Subject: [PATCH 1/4] support conversion to AbstractArray --- src/convert.jl | 6 ++++++ test/abstractarray.jl | 20 +++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/convert.jl b/src/convert.jl index 07f2d109..8f6b0ae8 100644 --- a/src/convert.jl +++ b/src/convert.jl @@ -11,6 +11,12 @@ @inline convert(::Type{SA}, sa::SA) where {SA<:StaticArray} = sa @inline convert(::Type{SA}, x::Tuple) where {SA<:StaticArray} = SA(x) # convert -> constructor. Hopefully no loops... +# support conversion to AbstractArray +AbstractArray{T}(sa::StaticArray{S,T}) where {S,T} = sa +AbstractArray{T,N}(sa::StaticArray{S,T,N}) where {S,T,N} = sa +AbstractArray{T}(sa::StaticArray{S,U}) where {S,T,U} = similar_type(typeof(sa),T,Size(sa))(Tuple(sa)) +AbstractArray{T,N}(sa::StaticArray{S,U,N}) where {S,T,U,N} = similar_type(typeof(sa),T,Size(sa))(Tuple(sa)) + # Constructing a Tuple from a StaticArray @inline Tuple(a::StaticArray) = unroll_tuple(a, Length(a)) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 41bd3478..228c2086 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -129,6 +129,25 @@ using StaticArrays, Test, LinearAlgebra m = MVector(1, 2, 3) @test @inferred(reverse(m))::typeof(m) == MVector(3, 2, 1) end + + @testset "Conversion to AbstractArray" begin + # Issue #746 + # conversion to AbstractArray changes the eltype from Int to Float64 + sv = SVector(1,2) + @test convert(AbstractArray{Float64}, sv) isa SVector{2,Float64} + @test convert(AbstractVector{Float64}, sv) isa SVector{2,Float64} + @test convert(AbstractArray{Float64}, sv) == sv + sm = SMatrix{2,2}(1,2,3,4) + @test convert(AbstractArray{Float64,2}, sm) isa SMatrix{2,2,Float64} + @test convert(AbstractArray{Float64,2}, sm) == sm + mv = MVector(1, 2, 3) + @test convert(AbstractArray{Float64}, mv) isa MVector{3,Float64} + @test convert(AbstractVector{Float64}, mv) isa MVector{3,Float64} + @test convert(AbstractArray{Float64}, mv) == mv + mm = MMatrix{2, 2}(1, 2, 3, 4) + @test convert(AbstractArray{Float64,2}, mm) isa MMatrix{2,2,Float64} + @test convert(AbstractArray{Float64,2}, mm) == mm + end end @testset "vcat() and hcat()" begin @@ -191,4 +210,3 @@ end @test @inferred(vcat(A, B)) === SMatrix{4, 2}([Matrix(A); Matrix(B)]) end end - From a86d3357daf00f8ca4fa875998ba483bf6c93459 Mon Sep 17 00:00:00 2001 From: Daan Huybrechs Date: Tue, 25 Feb 2020 13:56:34 +0100 Subject: [PATCH 2/4] improve test coverage --- test/abstractarray.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 228c2086..8b405182 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -137,16 +137,20 @@ using StaticArrays, Test, LinearAlgebra @test convert(AbstractArray{Float64}, sv) isa SVector{2,Float64} @test convert(AbstractVector{Float64}, sv) isa SVector{2,Float64} @test convert(AbstractArray{Float64}, sv) == sv + @test convert(AbstractArray{Int}, sv) === sv sm = SMatrix{2,2}(1,2,3,4) @test convert(AbstractArray{Float64,2}, sm) isa SMatrix{2,2,Float64} @test convert(AbstractArray{Float64,2}, sm) == sm + @test convert(AbstractArray{Int,2}, sm) === sm mv = MVector(1, 2, 3) @test convert(AbstractArray{Float64}, mv) isa MVector{3,Float64} @test convert(AbstractVector{Float64}, mv) isa MVector{3,Float64} @test convert(AbstractArray{Float64}, mv) == mv + @test convert(AbstractArray{Int}, mv) === mv mm = MMatrix{2, 2}(1, 2, 3, 4) @test convert(AbstractArray{Float64,2}, mm) isa MMatrix{2,2,Float64} @test convert(AbstractArray{Float64,2}, mm) == mm + @test convert(AbstractArray{Int,2}, mm) === mm end end From bc380cba622d2f2ef5a5c0bf60f36166e223017f Mon Sep 17 00:00:00 2001 From: Daan Huybrechs Date: Wed, 26 Feb 2020 16:00:31 +0100 Subject: [PATCH 3/4] expand conversion to abstractarray tests --- src/convert.jl | 4 ++-- test/abstractarray.jl | 38 ++++++++++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/convert.jl b/src/convert.jl index 8f6b0ae8..f653d3df 100644 --- a/src/convert.jl +++ b/src/convert.jl @@ -14,8 +14,8 @@ # support conversion to AbstractArray AbstractArray{T}(sa::StaticArray{S,T}) where {S,T} = sa AbstractArray{T,N}(sa::StaticArray{S,T,N}) where {S,T,N} = sa -AbstractArray{T}(sa::StaticArray{S,U}) where {S,T,U} = similar_type(typeof(sa),T,Size(sa))(Tuple(sa)) -AbstractArray{T,N}(sa::StaticArray{S,U,N}) where {S,T,U,N} = similar_type(typeof(sa),T,Size(sa))(Tuple(sa)) +AbstractArray{T}(sa::StaticArray{S,U}) where {S,T,U} = similar_type(typeof(sa),T,Size(sa))(sa) +AbstractArray{T,N}(sa::StaticArray{S,U,N}) where {S,T,U,N} = similar_type(typeof(sa),T,Size(sa))(sa) # Constructing a Tuple from a StaticArray @inline Tuple(a::StaticArray) = unroll_tuple(a, Length(a)) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 8b405182..c725b317 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -134,23 +134,49 @@ using StaticArrays, Test, LinearAlgebra # Issue #746 # conversion to AbstractArray changes the eltype from Int to Float64 sv = SVector(1,2) - @test convert(AbstractArray{Float64}, sv) isa SVector{2,Float64} - @test convert(AbstractVector{Float64}, sv) isa SVector{2,Float64} + @test @inferred(convert(AbstractArray{Float64}, sv)) isa SVector{2,Float64} + @test @inferred(convert(AbstractVector{Float64}, sv)) isa SVector{2,Float64} @test convert(AbstractArray{Float64}, sv) == sv @test convert(AbstractArray{Int}, sv) === sv sm = SMatrix{2,2}(1,2,3,4) - @test convert(AbstractArray{Float64,2}, sm) isa SMatrix{2,2,Float64} + @test @inferred(convert(AbstractArray{Float64,2}, sm)) isa SMatrix{2,2,Float64} @test convert(AbstractArray{Float64,2}, sm) == sm @test convert(AbstractArray{Int,2}, sm) === sm mv = MVector(1, 2, 3) - @test convert(AbstractArray{Float64}, mv) isa MVector{3,Float64} - @test convert(AbstractVector{Float64}, mv) isa MVector{3,Float64} + @test @inferred(convert(AbstractArray{Float64}, mv)) isa MVector{3,Float64} + @test @inferred(convert(AbstractVector{Float64}, mv)) isa MVector{3,Float64} @test convert(AbstractArray{Float64}, mv) == mv @test convert(AbstractArray{Int}, mv) === mv mm = MMatrix{2, 2}(1, 2, 3, 4) - @test convert(AbstractArray{Float64,2}, mm) isa MMatrix{2,2,Float64} + @test @inferred(convert(AbstractArray{Float64,2}, mm)) isa MMatrix{2,2,Float64} @test convert(AbstractArray{Float64,2}, mm) == mm @test convert(AbstractArray{Int,2}, mm) === mm + + # Test some of the types in StaticMatrixLike + sym = Symmetric(SA[1 2; 2 3]) + @test @inferred(convert(AbstractArray{Float64}, sym)) isa Symmetric{Float64,SMatrix{2,2,Float64,4}} + @test @inferred(convert(AbstractArray{Float64,2}, sym)) isa Symmetric{Float64,SMatrix{2,2,Float64,4}} + @test convert(AbstractArray{Float64}, sym) == sym + her = Hermitian(SA[1 2+im; 2-im 3]) + @test @inferred(convert(AbstractArray{ComplexF64}, her)) isa Hermitian{ComplexF64,SMatrix{2,2,ComplexF64,4}} + @test convert(AbstractArray{ComplexF64}, her) == her + diag = Diagonal(SVector(1,2)) + @test @inferred(convert(AbstractArray{Float64}, diag)) isa Diagonal{Float64,SVector{2,Float64}} + @test convert(AbstractArray{Float64}, diag) == diag + # The following cases currently convert the SMatrix into an MMatrix, because + # the constructor in Base invokes `similar`, rather than `convert`, on the static array + # trans = Transpose(SVector(1,2)) + # @test @inferred(convert(AbstractArray{Float64}, trans)) isa Transpose{Float64,SVector{2,Float64}} + # adj = Adjoint(SVector(1,2)) + # @test @inferred(convert(AbstractArray{Float64}, adj)) isa Adjoint{Float64,SVector{2,Float64}} + # uptri = UpperTriangular(SA[1 2; 0 3]) + # @test @inferred(convert(AbstractArray{Float64}, uptri)) isa UpperTriangular{Float64,SMatrix{2,2,Float64,4}} + # lotri = LowerTriangular(SA[1 0; 2 3]) + # @test @inferred(convert(AbstractArray{Float64}, lotri)) isa LowerTriangular{Float64,SMatrix{2,2,Float64,4}} + # unituptri = UnitUpperTriangular(SA[1 2; 0 1]) + # @test @inferred(convert(AbstractArray{Float64}, unituptri)) isa UnitUpperTriangular{Float64,SMatrix{2,2,Float64,4}} + # unitlotri = UnitLowerTriangular(SA[1 0; 2 1]) + # @test @inferred(convert(AbstractArray{Float64}, unitlotri)) isa UnitLowerTriangular{Float64,SMatrix{2,2,Float64,4}} end end From 057f68e2353a801e1689ce912cfe32e495a101e4 Mon Sep 17 00:00:00 2001 From: Daan Huybrechs Date: Wed, 4 Mar 2020 12:46:12 +0100 Subject: [PATCH 4/4] add test_broken to abstractarray conversion tests --- test/abstractarray.jl | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index c725b317..000b5189 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -165,18 +165,18 @@ using StaticArrays, Test, LinearAlgebra @test convert(AbstractArray{Float64}, diag) == diag # The following cases currently convert the SMatrix into an MMatrix, because # the constructor in Base invokes `similar`, rather than `convert`, on the static array - # trans = Transpose(SVector(1,2)) - # @test @inferred(convert(AbstractArray{Float64}, trans)) isa Transpose{Float64,SVector{2,Float64}} - # adj = Adjoint(SVector(1,2)) - # @test @inferred(convert(AbstractArray{Float64}, adj)) isa Adjoint{Float64,SVector{2,Float64}} - # uptri = UpperTriangular(SA[1 2; 0 3]) - # @test @inferred(convert(AbstractArray{Float64}, uptri)) isa UpperTriangular{Float64,SMatrix{2,2,Float64,4}} - # lotri = LowerTriangular(SA[1 0; 2 3]) - # @test @inferred(convert(AbstractArray{Float64}, lotri)) isa LowerTriangular{Float64,SMatrix{2,2,Float64,4}} - # unituptri = UnitUpperTriangular(SA[1 2; 0 1]) - # @test @inferred(convert(AbstractArray{Float64}, unituptri)) isa UnitUpperTriangular{Float64,SMatrix{2,2,Float64,4}} - # unitlotri = UnitLowerTriangular(SA[1 0; 2 1]) - # @test @inferred(convert(AbstractArray{Float64}, unitlotri)) isa UnitLowerTriangular{Float64,SMatrix{2,2,Float64,4}} + trans = Transpose(SVector(1,2)) + @test_broken @inferred(convert(AbstractArray{Float64}, trans)) isa Transpose{Float64,SVector{2,Float64}} + adj = Adjoint(SVector(1,2)) + @test_broken @inferred(convert(AbstractArray{Float64}, adj)) isa Adjoint{Float64,SVector{2,Float64}} + uptri = UpperTriangular(SA[1 2; 0 3]) + @test_broken @inferred(convert(AbstractArray{Float64}, uptri)) isa UpperTriangular{Float64,SMatrix{2,2,Float64,4}} + lotri = LowerTriangular(SA[1 0; 2 3]) + @test_broken @inferred(convert(AbstractArray{Float64}, lotri)) isa LowerTriangular{Float64,SMatrix{2,2,Float64,4}} + unituptri = UnitUpperTriangular(SA[1 2; 0 1]) + @test_broken @inferred(convert(AbstractArray{Float64}, unituptri)) isa UnitUpperTriangular{Float64,SMatrix{2,2,Float64,4}} + unitlotri = UnitLowerTriangular(SA[1 0; 2 1]) + @test_broken @inferred(convert(AbstractArray{Float64}, unitlotri)) isa UnitLowerTriangular{Float64,SMatrix{2,2,Float64,4}} end end