Skip to content

RFC: Unify SArray,SMatrix,SVector #127

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 2 commits into from
Apr 2, 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
72 changes: 30 additions & 42 deletions src/MArray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,75 +20,63 @@ type MArray{Size, T, N, L} <: StaticArray{T, N}
data::NTuple{L,T}

function (::Type{MArray{Size,T,N,L}}){Size,T,N,L}(x::NTuple{L,T})
check_marray_parameters(Val{Size}, T, Val{N}, Val{L})
check_array_parameters(Size, T, Val{N}, Val{L})
new{Size,T,N,L}(x)
end

function (::Type{MArray{Size,T,N,L}}){Size,T,N,L}(x::NTuple{L,Any})
check_marray_parameters(Val{Size}, T, Val{N}, Val{L})
check_array_parameters(Size, T, Val{N}, Val{L})
new{Size,T,N,L}(convert_ntuple(T, x))
end

function (::Type{MArray{Size,T,N,L}}){Size,T,N,L}()
check_marray_parameters(Val{Size}, T, Val{N}, Val{L})
check_array_parameters(Size, T, Val{N}, Val{L})
new{Size,T,N,L}()
end
end

@generated function check_marray_parameters{Size,T,N,L}(::Type{Val{Size}}, ::Type{T}, ::Type{Val{N}}, ::Type{Val{L}})
if !(isa(Size, Tuple{Vararg{Int}}))
error("MArray parameter Size must be a tuple of Ints (e.g. `MArray{(3,3)}`)")
end

if L != prod(Size) || L < 0 || minimum(Size) < 0 || length(Size) != N
error("Size mismatch in MArray parameters. Got size $Size, dimension $N and length $L.")
end

return nothing
end

@generated function (::Type{MArray{Size,T,N}}){Size,T,N}(x::Tuple)
return quote
$(Expr(:meta, :inline))
MArray{Size,T,N,$(prod(Size))}(x)
MArray{Size,T,N,$(tuple_prod(Size))}(x)
end
end

@generated function (::Type{MArray{Size,T}}){Size,T}(x::Tuple)
return quote
$(Expr(:meta, :inline))
MArray{Size,T,$(length(Size)),$(prod(Size))}(x)
MArray{Size,T,$(tuple_length(Size)),$(tuple_prod(Size))}(x)
end
end

@generated function (::Type{MArray{Size}}){Size, T <: Tuple}(x::T)
return quote
$(Expr(:meta, :inline))
MArray{Size,$(promote_tuple_eltype(T)),$(length(Size)),$(prod(Size))}(x)
MArray{Size,$(promote_tuple_eltype(T)),$(tuple_length(Size)),$(tuple_prod(Size))}(x)
end
end

@generated function (::Type{MArray{Size,T,N}}){Size,T,N}()
return quote
$(Expr(:meta, :inline))
MArray{Size, T, N, $(prod(Size))}()
MArray{Size, T, N, $(tuple_prod(Size))}()
end
end

@generated function (::Type{MArray{Size,T}}){Size,T}()
return quote
$(Expr(:meta, :inline))
MArray{Size, T, $(length(Size)), $(prod(Size))}()
MArray{Size, T, $(tuple_length(Size)), $(tuple_prod(Size))}()
end
end

@inline MArray(a::StaticArray) = MArray{size(typeof(a))}(Tuple(a))
@inline MArray(a::StaticArray) = MArray{size_tuple(typeof(a))}(Tuple(a))
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 we lost size_tuple somehow...


# Some more advanced constructor-like functions
@inline one(::Type{MArray{S}}) where {S} = one(MArray{S,Float64,length(S)})
@inline eye(::Type{MArray{S}}) where {S} = eye(MArray{S,Float64,length(S)})
@inline one(::Type{MArray{S,T}}) where {S,T} = one(MArray{S,T,length(S)})
@inline eye(::Type{MArray{S,T}}) where {S,T} = eye(MArray{S,T,length(S)})
@inline one(::Type{MArray{S}}) where {S} = one(MArray{S,Float64,tuple_length(S)})
@inline eye(::Type{MArray{S}}) where {S} = eye(MArray{S,Float64,tuple_length(S)})
@inline one(::Type{MArray{S,T}}) where {S,T} = one(MArray{S,T,tuple_length(S)})
@inline eye(::Type{MArray{S,T}}) where {S,T} = eye(MArray{S,T,tuple_length(S)})

####################
## MArray methods ##
Expand Down Expand Up @@ -133,17 +121,17 @@ macro MArray(ex)
end

if ex.head == :vect # vector
return esc(Expr(:call, MArray{(length(ex.args),)}, Expr(:tuple, ex.args...)))
return esc(Expr(:call, MArray{Tuple{length(ex.args)}}, Expr(:tuple, ex.args...)))
elseif ex.head == :ref # typed, vector
return esc(Expr(:call, Expr(:curly, :MArray, ((length(ex.args)-1),), ex.args[1]), Expr(:tuple, ex.args[2:end]...)))
return esc(Expr(:call, Expr(:curly, :MArray, Tuple{length(ex.args)-1}, ex.args[1]), Expr(:tuple, ex.args[2:end]...)))
elseif ex.head == :hcat # 1 x n
s1 = 1
s2 = length(ex.args)
return esc(Expr(:call, MArray{(s1, s2)}, Expr(:tuple, ex.args...)))
return esc(Expr(:call, MArray{Tuple{s1, s2}}, Expr(:tuple, ex.args...)))
elseif ex.head == :typed_hcat # typed, 1 x n
s1 = 1
s2 = length(ex.args) - 1
return esc(Expr(:call, Expr(:curly, :MArray, (s1, s2), ex.args[1]), Expr(:tuple, ex.args[2:end]...)))
return esc(Expr(:call, Expr(:curly, :MArray, Tuple{s1, s2}, ex.args[1]), Expr(:tuple, ex.args[2:end]...)))
elseif ex.head == :vcat
if isa(ex.args[1], Expr) && ex.args[1].head == :row # n x m
# Validate
Expand All @@ -155,9 +143,9 @@ macro MArray(ex)
end

exprs = [ex.args[i].args[j] for i = 1:s1, j = 1:s2]
return esc(Expr(:call, MArray{(s1, s2)}, Expr(:tuple, exprs...)))
return esc(Expr(:call, MArray{Tuple{s1, s2}}, Expr(:tuple, exprs...)))
else # n x 1
return esc(Expr(:call, MArray{(length(ex.args), 1)}, Expr(:tuple, ex.args...)))
return esc(Expr(:call, MArray{Tuple{length(ex.args), 1}}, Expr(:tuple, ex.args...)))
end
elseif ex.head == :typed_vcat
if isa(ex.args[2], Expr) && ex.args[2].head == :row # typed, n x m
Expand All @@ -170,9 +158,9 @@ macro MArray(ex)
end

exprs = [ex.args[i+1].args[j] for i = 1:s1, j = 1:s2]
return esc(Expr(:call, Expr(:curly, :MArray, (s1, s2), ex.args[1]), Expr(:tuple, exprs...)))
return esc(Expr(:call, Expr(:curly, :MArray, Tuple{s1, s2}, ex.args[1]), Expr(:tuple, exprs...)))
else # typed, n x 1
return esc(Expr(:call, Expr(:curly, :MArray, (length(ex.args)-1, 1), ex.args[1]), Expr(:tuple, ex.args[2:end]...)))
return esc(Expr(:call, Expr(:curly, :MArray, Tuple{length(ex.args)-1, 1}, ex.args[1]), Expr(:tuple, ex.args[2:end]...)))
end
elseif isa(ex, Expr) && ex.head == :comprehension
if length(ex.args) != 1 || !isa(ex.args[1], Expr) || ex.args[1].head != :generator
Expand Down Expand Up @@ -210,7 +198,7 @@ macro MArray(ex)

return quote
$(esc(f_expr))
$(esc(Expr(:call, Expr(:curly, :MArray, (rng_lengths...)), Expr(:tuple, exprs...))))
$(esc(Expr(:call, Expr(:curly, :MArray, Tuple{rng_lengths...}), Expr(:tuple, exprs...))))
end
elseif isa(ex, Expr) && ex.head == :typed_comprehension
if length(ex.args) != 2 || !isa(ex.args[2], Expr) || ex.args[2].head != :generator
Expand Down Expand Up @@ -249,7 +237,7 @@ macro MArray(ex)

return quote
$(esc(f_expr))
$(esc(Expr(:call, Expr(:curly, :MArray, (rng_lengths...), T), Expr(:tuple, exprs...))))
$(esc(Expr(:call, Expr(:curly, :MArray, Tuple{rng_lengths...}, T), Expr(:tuple, exprs...))))
end
elseif isa(ex, Expr) && ex.head == :call
if ex.args[1] == :zeros || ex.args[1] == :ones || ex.args[1] == :rand || ex.args[1] == :randn
Expand All @@ -258,9 +246,9 @@ macro MArray(ex)
else
return quote
if isa($(esc(ex.args[2])), DataType)
$(ex.args[1])($(esc(Expr(:curly, MArray, Expr(:tuple, ex.args[3:end]...), ex.args[2]))))
$(ex.args[1])($(esc(Expr(:curly, MArray, Expr(:curly, Tuple, ex.args[3:end]...), ex.args[2]))))
else
$(ex.args[1])($(esc(Expr(:curly, MArray, Expr(:tuple, ex.args[2:end]...)))))
$(ex.args[1])($(esc(Expr(:curly, MArray, Expr(:curly, Tuple, ex.args[2:end]...)))))
end
end
end
Expand All @@ -271,26 +259,26 @@ macro MArray(ex)
error("@MArray got bad expression: $(ex.args[1])($(ex.args[2]))")
else
return quote
$(esc(ex.args[1]))($(esc(ex.args[2])), MArray{$(esc(Expr(:tuple, ex.args[3:end]...)))})
$(esc(ex.args[1]))($(esc(ex.args[2])), MArray{$(esc(Expr(:curly, Tuple, ex.args[3:end]...)))})
end
end
elseif ex.args[1] == :eye
if length(ex.args) == 2
return quote
eye(MArray{($(esc(ex.args[2])), $(esc(ex.args[2])))})
eye(MArray{Tuple{$(esc(ex.args[2])), $(esc(ex.args[2]))}})
end
elseif length(ex.args) == 3
# We need a branch, depending if the first argument is a type or a size.
return quote
if isa($(esc(ex.args[2])), DataType)
eye(MArray{($(esc(ex.args[3])), $(esc(ex.args[3]))), $(esc(ex.args[2]))})
eye(MArray{Tuple{$(esc(ex.args[3])), $(esc(ex.args[3]))}, $(esc(ex.args[2]))})
else
eye(MArray{($(esc(ex.args[2])), $(esc(ex.args[3])))})
eye(MArray{Tuple{$(esc(ex.args[2])), $(esc(ex.args[3]))}})
end
end
elseif length(ex.args) == 4
return quote
eye(MArray{($(esc(ex.args[3])), $(esc(ex.args[4]))), $(esc(ex.args[2]))})
eye(MArray{Tuple{$(esc(ex.args[3])), $(esc(ex.args[4]))}, $(esc(ex.args[2]))})
end
else
error("Bad eye() expression for @MArray")
Expand Down
35 changes: 1 addition & 34 deletions src/MMatrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,7 @@ Construct a statically-sized, mutable matrix of dimensions `S1 × S2` using the
`mat`. The parameters `S1` and `S2` are mandatory since the size of `mat` is
unknown to the compiler (the element type may optionally also be specified).
"""
type MMatrix{S1, S2, T, L} <: StaticMatrix{T}
data::NTuple{L, T}

function (::Type{MMatrix{S1,S2,T,L}}){S1,S2,T,L}(d::NTuple{L,T})
check_MMatrix_params(Val{S1}, Val{S2}, T, Val{L})
new{S1,S2,T,L}(d)
end

function (::Type{MMatrix{S1,S2,T,L}}){S1,S2,T,L}(d::NTuple{L,Any})
check_MMatrix_params(Val{S1}, Val{S2}, T, Val{L})
new{S1,S2,T,L}(convert_ntuple(T, d))
end

function (::Type{MMatrix{S1,S2,T,L}}){S1,S2,T,L}()
check_MMatrix_params(Val{S1}, Val{S2}, T, Val{L})
new{S1,S2,T,L}()
end
end

function check_MMatrix_params(::Type{Val{S1}}, ::Type{Val{S2}}, T, ::Type{Val{L}}) where {S1,S2,L}
throw(ArgumentError("MMatrix: Parameter T must be a Type. Got $T"))
end

@generated function check_MMatrix_params(::Type{Val{S1}}, ::Type{Val{S2}}, ::Type{T}, ::Type{Val{L}}) where {S1,S2,L,T}
if !isa(S1, Int) || !isa(S2, Int) || !isa(L, Int) || S1 < 0 || S2 < 0 || L < 0
throw(ArgumentError("MMatrix: Sizes must be positive integers. Got $S1 × $S2 ($L elements)"))
end

if S1*S2 == L
return nothing
else
throw(ArgumentError("Size mismatch in MMatrix. S1 = $S1, S2 = $S2, but recieved $L elements"))
end
end
const MMatrix{S1, S2, T, L} = MArray{Tuple{S1, S2}, T, 2, L}

@generated function (::Type{MMatrix{S1}}){S1,L}(x::NTuple{L})
S2 = div(L, S1)
Expand Down
20 changes: 1 addition & 19 deletions src/MVector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,7 @@ Construct a statically-sized, mutable vector of length `S` using the data from
`vec`. The parameter `S` is mandatory since the length of `vec` is unknown to the
compiler (the element type may optionally also be specified).
"""
type MVector{S, T} <: StaticVector{T}
data::NTuple{S, T}

function (::Type{MVector{S,T}}){S,T}(in::NTuple{S, T})
new{S,T}(in)
end

function (::Type{MVector{S,T}}){S,T}(in::NTuple{S, Any})
new{S,T}(convert_ntuple(T,in))
end

function (::Type{MVector{S,T}}){S,T}(in::T)
new{S,T}((in,))
end

function (::Type{MVector{S,T}}){S,T}()
new{S,T}()
end
end
const MVector{S, T} = MArray{Tuple{S}, T, 1, S}

@inline (::Type{MVector}){S}(x::NTuple{S,Any}) = MVector{S}(x)
@inline (::Type{MVector{S}}){S, T}(x::NTuple{S,T}) = MVector{S,T}(x)
Expand Down
Loading