Skip to content

bring back fixedsizearrays #138

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Apr 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 28 additions & 16 deletions src/FixedSizeArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,15 @@ end

macro fixed_vector(name, parent)
esc(quote
immutable $(name){S, T} <: $(parent){T}
immutable $(name){S, T} <: $(parent){S, T}
data::NTuple{S, T}

function $(name)(x::NTuple{S,T})
new(x)
function (::Type{$(name){S, T}}){S, T}(x::NTuple{S,T})
new{S, T}(x)
end
function $(name)(x::NTuple{S})
new(StaticArrays.convert_ntuple(T, x))

function (::Type{$(name){S, T}}){S, T}(x::NTuple{S,Any})
new{S, T}(StaticArrays.convert_ntuple(T, x))
end
end
# Array constructor
Expand Down Expand Up @@ -122,6 +123,19 @@ macro fixed_vector(name, parent)
@inline function (::Type{$(name){S}}){S, T <: Tuple}(x::T)
$(name){S, StaticArrays.promote_tuple_eltype(T)}(x)
end
(::Type{$(name){S, T}}){S, T}(x::StaticVector) = $(name){S, T}(Tuple(x))
@generated function (::Type{$(name){S, T}}){S, T}(x::$(name))
idx = [:(x[$i]) for i = 1:S]
quote
$($(name)){S, T}($(idx...))
end
end
@generated function convert{S, T}(::Type{$(name){S, T}}, x::$(name))
idx = [:(x[$i]) for i = 1:S]
quote
$($(name)){S, T}($(idx...))
end
end
@generated function (::Type{SV}){SV <: $(name)}(x::StaticVector)
len = size_or(SV, size(x))[1]
if length(x) == len
Expand All @@ -134,36 +148,34 @@ macro fixed_vector(name, parent)
end
end

Base.@pure StaticArrays.Size{S}(::Type{$(name){S}}) = Size(S)
Base.@pure StaticArrays.Size{S}(::Type{$(name){S, Any}}) = Size(S)
Base.@pure StaticArrays.Size{S,T}(::Type{$(name){S, T}}) = Size(S)

Base.@propagate_inbounds function Base.getindex(v::$(name), i::Integer)
Base.@propagate_inbounds function Base.getindex{S, T}(v::$(name){S, T}, i::Int)
v.data[i]
end
@inline Base.Tuple(v::$(name)) = v.data
@inline Base.convert{S, T}(::Type{$(name){S, T}}, x::NTuple{S, T}) = $(name){S, T}(x)
@inline Base.convert{SV <: $(name)}(::Type{SV}, x::StaticVector) = SV(x)
@inline Base.convert(::Type{$(name)}, x::StaticVector) = SV(x)
@inline function Base.convert{S, T}(::Type{$(name){S, T}}, x::Tuple)
$(name){S, T}(convert(NTuple{S, T}, x))
end

@generated function StaticArrays.similar_type{SV <: $(name), T,S}(::Type{SV}, ::Type{T}, s::Size{S})
@generated function StaticArrays.similar_type{SV <: $(name), T, S}(::Type{SV}, ::Type{T}, s::Size{S})
if length(S) === 1
$(name){S[1], T}
else
StaticArrays.default_similar_type(T,s(),Val{length(S)})
end
end


size_or(::Type{$(name)}, or) = or
eltype_or(::Type{$(name)}, or) = or
eltype_or{T}(::Type{$(name){TypeVar(:S), T}}, or) = T
eltype_or{S}(::Type{$(name){S, TypeVar(:T)}}, or) = or
eltype_or{T}(::Type{$(name){S, T} where S}, or) = T
eltype_or{S}(::Type{$(name){S, T} where T}, or) = or
eltype_or{S, T}(::Type{$(name){S, T}}, or) = T

size_or(::Type{$(name)}, or) = or
size_or{T}(::Type{$(name){TypeVar(:S), T}}, or) = or
size_or{S}(::Type{$(name){S, TypeVar(:T)}}, or) = (S,)
size_or{T}(::Type{$(name){S, T} where S}, or) = or
size_or{S}(::Type{$(name){S, T} where T}, or) = Size{(S,)}()
size_or{S, T}(::Type{$(name){S, T}}, or) = (S,)
end)
end
Expand Down
2 changes: 1 addition & 1 deletion src/StaticArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ include("eigen.jl")
include("cholesky.jl")
include("deque.jl")

#include("FixedSizeArrays.jl") # Currently defunct
include("FixedSizeArrays.jl")
include("ImmutableArrays.jl")

end # module
10 changes: 7 additions & 3 deletions src/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
_broadcast(f, broadcast_sizes(a...), a...)
end

@propagate_inbounds function broadcast{T}(f::Function, a::Type{T}, x::StaticArray)
_broadcast(f, (Size(), Size(x)), T, x)
end

@inline broadcast_sizes(a...) = _broadcast_sizes((), a...)
@inline _broadcast_sizes(t::Tuple) = t
@inline _broadcast_sizes(t::Tuple, a::StaticArray, as...) = _broadcast_sizes((t..., Size(a)), as...)
Expand All @@ -23,7 +27,7 @@ function broadcasted_index(oldsize, newindex)
return sub2ind(oldsize, index...)
end

@generated function _broadcast(f, s::Tuple{Vararg{Size}}, a::Union{Number, StaticArray}...)
@generated function _broadcast(f, s::Tuple{Vararg{Size}}, a...)
first_staticarray = 0
for i = 1:length(a)
if a[i] <: StaticArray
Expand Down Expand Up @@ -57,7 +61,7 @@ end
current_ind = ones(Int, length(newsize))

while more
exprs_vals = [(a[i] <: Number ? :(a[$i]) : :(a[$i][$(broadcasted_index(sizes[i], current_ind))])) for i = 1:length(sizes)]
exprs_vals = [(!(a[i] <: AbstractArray) ? :(a[$i]) : :(a[$i][$(broadcasted_index(sizes[i], current_ind))])) for i = 1:length(sizes)]
exprs[current_ind...] = :(f($(exprs_vals...)))

# increment current_ind (maybe use CartesianRange?)
Expand All @@ -77,7 +81,7 @@ end
end
end

eltype_exprs = [:(eltype($t)) for t ∈ a]
eltype_exprs = [t <: AbstractArray ? :($(eltype(t))) : :($t) for t ∈ a]
newtype_expr = :(Core.Inference.return_type(f, Tuple{$(eltype_exprs...)}))

return quote
Expand Down
2 changes: 2 additions & 0 deletions src/indexing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ end

@generated function _getindex_scalar(::Size{S}, a::StaticArray, inds::Int...) where S
stride = 1
ind_expr = :()
for i ∈ 1:length(inds)
if i == 1
ind_expr = :(inds[1])
Expand All @@ -34,6 +35,7 @@ end

@generated function _setindex!_scalar(::Size{S}, a::StaticArray, value, inds::Int...) where S
stride = 1
ind_expr = :()
for i ∈ 1:length(inds)
if i == 1
ind_expr = :(inds[1])
Expand Down
4 changes: 2 additions & 2 deletions src/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ end

@generated function check_array_parameters{Size,T,N,L}(::Type{Size}, ::Type{T}, ::Type{Val{N}}, ::Type{Val{L}})
if !all(x->isa(x, Int), Size.parameters)
throw(ArgumentError("Static Array parameter Size must be a tuple of Ints (e.g. `SArray{Tuple{3,3}}` or `SMatrix{3,3}`)."))
return :(throw(ArgumentError("Static Array parameter Size must be a tuple of Ints (e.g. `SArray{Tuple{3,3}}` or `SMatrix{3,3}`).")))
end

if L != tuple_prod(Size) || L < 0 || tuple_minimum(Size) < 0 || tuple_length(Size) != N
throw(ArgumentError("Size mismatch in Static Array parameters. Got size $Size, dimension $N and length $L."))
return :(throw(ArgumentError("Size mismatch in Static Array parameters. Got size $Size, dimension $N and length $L.")))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm still a bit confused about why this is absolutely necessary. But I'm not surprised that this is another concession required for the new @generated rules :-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also don't get why this helps... I had actually removed the quotes from the errors in most parts of the package because they seemed to not be required...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes arguably it's better to throw an error early rather than late (ie, in the generator rather than the generated code - so to leave this without the quotes). I just figured it was some funky new limitation of @generated... @SimonDanisch what exactly happens without this?

end

return nothing
Expand Down
58 changes: 29 additions & 29 deletions test/fixed_size_arrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,39 @@ using Base.Test
import StaticArrays.FixedSizeArrays: @fixed_vector


@compat const Vec1d = Vec{1, Float64}
@compat const Vec2d = Vec{2, Float64}
@compat const Vec3d = Vec{3, Float64}
@compat const Vec4d = Vec{4, Float64}
@compat const Vec3f = Vec{3, Float32}
const Vec1d = Vec{1, Float64}
const Vec2d = Vec{2, Float64}
const Vec3d = Vec{3, Float64}
const Vec4d = Vec{4, Float64}
const Vec3f = Vec{3, Float32}

@compat const Mat2d = Mat{2,2, Float64, 4}
@compat const Mat3d = Mat{3,3, Float64, 9}
@compat const Mat4d = Mat{4,4, Float64, 16}
const Mat2d = Mat{2,2, Float64, 4}
const Mat3d = Mat{3,3, Float64, 9}
const Mat4d = Mat{4,4, Float64, 16}

immutable RGB{T} <: FieldVector{T}
immutable RGB{T} <: FieldVector{3, T}
x::T
y::T
z::T
end

RGB{T}(x::T) = RGB{T}(x, x, x)
(::RGB{T}){T}(r, g, b) = RGB{T}(T(r), T(g), T(b))
(::RGB{T}){T}(r::Real) = RGB(T(r), T(r), T(r))
StaticArrays.similar_type{SV <: RGB, T}(::Type{SV}, ::Type{T}, ::Size{(3,)}) = RGB{T}

# TODO find equivalent in StaticArrays
# testset "scalar nan" begin
# for (p, r) in (
# (Point{2, Float32}(NaN, 1), true),
# (Point{2, Float64}(1, NaN), true),
# (Vec{11, Float64}(NaN), true),
# (Point{2, Float32}(1, 1), false),
# (RGB{Float32}(NaN), true),
# )
# @fact isnan(p) == r
# end
# end
@testset "scalar nan" begin
for (p, r) in (
(Point{2, Float32}(NaN, 1), true),
(Point{2, Float64}(1, NaN), true),
(Vec{11, Float64}(NaN), true),
(Point{2, Float32}(1, 1), false),
(RGB{Float32}(NaN, NaN, NaN), true),
)
@test any(isnan, p) == r
end
end

# methods I needed to define:

Expand Down Expand Up @@ -124,8 +125,8 @@ rand(Mat{4,2, Int})
@test typeof(rand(Mat{4,2, Int})) == Mat{4,2, Int, 8}
@test typeof(rand(Vec{7, Int})) == Vec{7, Int}

@test typeof(rand(-20f0:0.192f0:230f0, Mat4d)) == Mat4d
@test typeof(rand(-20f0:0.192f0:230f0, Mat{4,21,Float32})) == Mat{4,21,Float32, 4*21}
# @test typeof(rand(-20f0:0.192f0:230f0, Mat4d)) == Mat4d
# @test typeof(rand(-20f0:0.192f0:230f0, Mat{4,21,Float32})) == Mat{4,21,Float32, 4*21}

@test typeof(rand(Vec4d, 5,5)) == Matrix{Vec4d}
#end
Expand Down Expand Up @@ -206,13 +207,13 @@ map(-, Vec(1,2,3))
map(+, Vec(1,2,3), Vec(1,1, 1))
(+).(Vec(1,2,3), 1.0)
v1 = Vec3d(1,2,3)
@test v1[(2,1)] == Vec2d(2,1)
@test v1[Vec(2,1)] == Vec2d(2,1)

@test @inferred(-v1) == Vec(-1.0,-2.0,-3.0)
@test isa(-v1, Vec3d) == true
@test @inferred(v1 ./ v1) == Vec3d(1.0,1.0,1.0)
@test (<).(Vec(1,3), Vec(2,2)) === Vec{2,Bool}(true, false)

#
v1 = Vec(1.0,2.0,3.0)
v2 = Vec(6.0,5.0,4.0)
vi = Vec(1,2,3)
Expand Down Expand Up @@ -379,10 +380,9 @@ const unaryOps = (
# vec-vec and vec-scalar
const binaryOps = (

.+, .-, .*, ./, .\,
.==, .!=, .<, .<=, .>, .>=, +, -,
+, -, *, /, \,
==, !=, <, <=, >, >=,
min, max,

atan2, besselj, bessely, hankelh1, hankelh2,
besseli, besselk, beta, lbeta
)
Expand All @@ -400,7 +400,7 @@ const binaryOps = (
@testset "$op with $v1 and $v2" begin
try # really bad tests, but better than nothing...
if applicable(op, v1[1], v2[1]) && typeof(op(v1[1], v2[1])) == eltype(v1)
r = op(v1, v2)
r = op.(v1, v2)
for j=1:length(v1)
@test r[j] == op(v1[j], v2[j])
end
Expand All @@ -417,7 +417,7 @@ const binaryOps = (
@testset "$op with $t" begin
try
if applicable(op, t[1]) && typeof(op(t[1])) == eltype(t)
v = op(t)
v = op.(t)
for i=1:length(v)
@test v[i] == op(t[i])
end
Expand Down
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ using Base.Test
include("solve.jl") # Strange inference / world-age error
include("eigen.jl")
include("deque.jl")
#include("fixed_size_arrays.jl")
include("fixed_size_arrays.jl")
end