Skip to content

Commit 5b2fc41

Browse files
authored
Support conversion to AbstractArray (#747)
Julia Base defines conversion to the abstract types AbstractArray{T} and AbstractArray{T,N} by invoking their (abstract) constructors. These fail with an error for static vectors. This change defines the AbstractArray{T} and AbstractArray{T,N} constructors for static arrays in terms of similar_type.
1 parent c52ac6a commit 5b2fc41

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

src/convert.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
@inline convert(::Type{SA}, sa::SA) where {SA<:StaticArray} = sa
1212
@inline convert(::Type{SA}, x::Tuple) where {SA<:StaticArray} = SA(x) # convert -> constructor. Hopefully no loops...
1313

14+
# support conversion to AbstractArray
15+
AbstractArray{T}(sa::StaticArray{S,T}) where {S,T} = sa
16+
AbstractArray{T,N}(sa::StaticArray{S,T,N}) where {S,T,N} = sa
17+
AbstractArray{T}(sa::StaticArray{S,U}) where {S,T,U} = similar_type(typeof(sa),T,Size(sa))(sa)
18+
AbstractArray{T,N}(sa::StaticArray{S,U,N}) where {S,T,U,N} = similar_type(typeof(sa),T,Size(sa))(sa)
19+
1420
# Constructing a Tuple from a StaticArray
1521
@inline Tuple(a::StaticArray) = unroll_tuple(a, Length(a))
1622

test/abstractarray.jl

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,55 @@ using StaticArrays, Test, LinearAlgebra
129129
m = MVector(1, 2, 3)
130130
@test @inferred(reverse(m))::typeof(m) == MVector(3, 2, 1)
131131
end
132+
133+
@testset "Conversion to AbstractArray" begin
134+
# Issue #746
135+
# conversion to AbstractArray changes the eltype from Int to Float64
136+
sv = SVector(1,2)
137+
@test @inferred(convert(AbstractArray{Float64}, sv)) isa SVector{2,Float64}
138+
@test @inferred(convert(AbstractVector{Float64}, sv)) isa SVector{2,Float64}
139+
@test convert(AbstractArray{Float64}, sv) == sv
140+
@test convert(AbstractArray{Int}, sv) === sv
141+
sm = SMatrix{2,2}(1,2,3,4)
142+
@test @inferred(convert(AbstractArray{Float64,2}, sm)) isa SMatrix{2,2,Float64}
143+
@test convert(AbstractArray{Float64,2}, sm) == sm
144+
@test convert(AbstractArray{Int,2}, sm) === sm
145+
mv = MVector(1, 2, 3)
146+
@test @inferred(convert(AbstractArray{Float64}, mv)) isa MVector{3,Float64}
147+
@test @inferred(convert(AbstractVector{Float64}, mv)) isa MVector{3,Float64}
148+
@test convert(AbstractArray{Float64}, mv) == mv
149+
@test convert(AbstractArray{Int}, mv) === mv
150+
mm = MMatrix{2, 2}(1, 2, 3, 4)
151+
@test @inferred(convert(AbstractArray{Float64,2}, mm)) isa MMatrix{2,2,Float64}
152+
@test convert(AbstractArray{Float64,2}, mm) == mm
153+
@test convert(AbstractArray{Int,2}, mm) === mm
154+
155+
# Test some of the types in StaticMatrixLike
156+
sym = Symmetric(SA[1 2; 2 3])
157+
@test @inferred(convert(AbstractArray{Float64}, sym)) isa Symmetric{Float64,SMatrix{2,2,Float64,4}}
158+
@test @inferred(convert(AbstractArray{Float64,2}, sym)) isa Symmetric{Float64,SMatrix{2,2,Float64,4}}
159+
@test convert(AbstractArray{Float64}, sym) == sym
160+
her = Hermitian(SA[1 2+im; 2-im 3])
161+
@test @inferred(convert(AbstractArray{ComplexF64}, her)) isa Hermitian{ComplexF64,SMatrix{2,2,ComplexF64,4}}
162+
@test convert(AbstractArray{ComplexF64}, her) == her
163+
diag = Diagonal(SVector(1,2))
164+
@test @inferred(convert(AbstractArray{Float64}, diag)) isa Diagonal{Float64,SVector{2,Float64}}
165+
@test convert(AbstractArray{Float64}, diag) == diag
166+
# The following cases currently convert the SMatrix into an MMatrix, because
167+
# the constructor in Base invokes `similar`, rather than `convert`, on the static array
168+
trans = Transpose(SVector(1,2))
169+
@test_broken @inferred(convert(AbstractArray{Float64}, trans)) isa Transpose{Float64,SVector{2,Float64}}
170+
adj = Adjoint(SVector(1,2))
171+
@test_broken @inferred(convert(AbstractArray{Float64}, adj)) isa Adjoint{Float64,SVector{2,Float64}}
172+
uptri = UpperTriangular(SA[1 2; 0 3])
173+
@test_broken @inferred(convert(AbstractArray{Float64}, uptri)) isa UpperTriangular{Float64,SMatrix{2,2,Float64,4}}
174+
lotri = LowerTriangular(SA[1 0; 2 3])
175+
@test_broken @inferred(convert(AbstractArray{Float64}, lotri)) isa LowerTriangular{Float64,SMatrix{2,2,Float64,4}}
176+
unituptri = UnitUpperTriangular(SA[1 2; 0 1])
177+
@test_broken @inferred(convert(AbstractArray{Float64}, unituptri)) isa UnitUpperTriangular{Float64,SMatrix{2,2,Float64,4}}
178+
unitlotri = UnitLowerTriangular(SA[1 0; 2 1])
179+
@test_broken @inferred(convert(AbstractArray{Float64}, unitlotri)) isa UnitLowerTriangular{Float64,SMatrix{2,2,Float64,4}}
180+
end
132181
end
133182

134183
@testset "vcat() and hcat()" begin
@@ -191,4 +240,3 @@ end
191240
@test @inferred(vcat(A, B)) === SMatrix{4, 2}([Matrix(A); Matrix(B)])
192241
end
193242
end
194-

0 commit comments

Comments
 (0)