-
Notifications
You must be signed in to change notification settings - Fork 20
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
Immutable field slicing #59
Comments
@PaulBellette behold, field slicing crazyness. It's not quite the syntax |
Ah yeah, I definitely want to have this as well. Especially, when we decide to use Cool, this is faster than it looks :) |
Hah, please don't take the implementation above too seriously :-) Now that I know it makes sense to someone other than myself, I'm a bit keener to spend time making it actually work. Some thoughts/questions:
|
Taking the function Base.getindex{V<:FixedVector,I}(a::Array{V}, ::Type{Val{I}}, inds...)
squeeze(reinterpret(eltype(V), a, (length(V), size(a)...))[I, inds...], 1)
end
function Base.setindex!{V<:FixedVector,I}(a::Array{V}, rhs, ::Type{Val{I}}, inds...)
reinterpret(eltype(V), a, (length(V), size(a)...))[I, inds...] = rhs
end Example usage: julia> v = [Vec(i,j,0) for i = 1:4, j = 1:4]
4x4 Array{FixedSizeArrays.Vec{3,Int64},2}:
Vec(1,1,0) Vec(1,2,0) Vec(1,3,0) Vec(1,4,0)
Vec(2,1,0) Vec(2,2,0) Vec(2,3,0) Vec(2,4,0)
Vec(3,1,0) Vec(3,2,0) Vec(3,3,0) Vec(3,4,0)
Vec(4,1,0) Vec(4,2,0) Vec(4,3,0) Vec(4,4,0)
julia> v[Val{1}, :, :] = 1
1
julia> v
4x4 Array{FixedSizeArrays.Vec{3,Int64},2}:
Vec(1,1,0) Vec(1,2,0) Vec(1,3,0) Vec(1,4,0)
Vec(1,1,0) Vec(1,2,0) Vec(1,3,0) Vec(1,4,0)
Vec(1,1,0) Vec(1,2,0) Vec(1,3,0) Vec(1,4,0)
Vec(1,1,0) Vec(1,2,0) Vec(1,3,0) Vec(1,4,0) |
Pretty cool. Yeah using FixedSizeArrays
abstract Unit{T}
immutable X{T} <: Unit{T}
val::T
end
immutable Y{T} <: Unit{T}
val::T
end
immutable Z{T} <: Unit{T}
val::T
end
type2index{T <: X}(::Type{T}) = 1
type2index{T <: Y}(::Type{T}) = 2
type2index{T <: Z}(::Type{T}) = 3
function Base.getindex{V<:FixedVector,I<:Unit}(a::Array{V}, ::Type{I}, inds...)
squeeze(reinterpret(eltype(V), a, (length(V), size(a)...))[type2index(I), inds...], 1)
end
function Base.setindex!{V<:FixedVector,I<:Unit}(a::Array{V}, rhs::I, inds...)
reinterpret(eltype(V), a, (length(V), size(a)...))[type2index(I), inds...] = rhs.val
end
v = [Vec(i,j,0) for i = 1:4, j = 1:4]
v[:, :] = X(1)
4x4 Array{FixedSizeArrays.Vec{3,Int64},2}:
Vec(1,1,0) Vec(1,2,0) Vec(1,3,0) Vec(1,4,0)
Vec(1,1,0) Vec(1,2,0) Vec(1,3,0) Vec(1,4,0)
Vec(1,1,0) Vec(1,2,0) Vec(1,3,0) Vec(1,4,0)
Vec(1,1,0) Vec(1,2,0) Vec(1,3,0) Vec(1,4,0)
v[X, :, :]
4x4 Array{Int64,2}:
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1 The last case should return |
I had a bit more of a think about the right way to approach this today. With respect to The general question I'd really like a good answer to, is how to consistently slice an Or maybe the idea of slicing arrays of immutable types to modify them is just inconsistent (they're meant to be immutable after all, they're not value types even though I keep thinking of them that way...) Is there some need for some kind of hybrid |
I just came across JuliaLang/julia#11902, which is obviously relevant to the design problems here. In particular, Keno's suggestions around a new |
Yup, that's one of the most wanted features for FixedSizeArrays! ;) |
Right, makes sense. I tried implementing a Unfortunately I think there may be a need for some syntax to separate the fixed dimensions from the usual array dimensions. Using a macro I managed to abuse a semicolon for this:
After some thought I quite like the semicolon for this, other than its visual similarity to the colon. If slicing of general immutables became a standard feature, maybe the parser would need some syntactical way of figuring out when to lower the ref syntax to Implementation: # Place holder type for dispatch to function which slices along dimensions of
# fixed size elements of an Array.
immutable SliceElements; end
# Turn A[1,2; 3,4] into A[SliceElements(), 1,2,3,4]
function wrapinds(expr)
if expr.head == :(=)
return Expr(expr.head, wrapinds(expr.args[1]), expr.args[2:end]...)
end
@assert expr.head == :typed_vcat
@assert expr.args[2].head == :parameters # what?
extrainds = expr.args[3:end]
normalinds = expr.args[2].args
Expr(:ref, expr.args[1], SliceElements(), extrainds..., normalinds...)
end
"""
Slice along dimensions of fixed sized arrays inside an array container, using
the syntax
@fslice a[i,j; k,l]
where a is an array of `F<:FixedArray`. i and j slice the dimensions of F; k
and l slice along the usual dimensions of the container a.
"""
macro fslice(expr)
wrapinds(expr)
end
function Base.getindex{F<:FixedArray}(a::Array{F}, ::SliceElements, inds...)
SIZE = size(F)
T = eltype(F)
reinterpret(T, a, (SIZE..., size(a)...))[inds...]
end
function Base.setindex!{F<:FixedArray}(a::Array{F}, val, ::SliceElements, inds...)
SIZE = size(F)
T = eltype(F)
reinterpret(T, a, (SIZE..., size(a)...))[inds...] = val
end |
Darn, |
Ok, I think I'm converging on something useful - I'll prepare a proper PR for it, hopefully tonight. |
In #62 I tried an It turns out that it's possible without a macro, but getting the dispatch working correctly seems to require some nasty hacks. Basically I'd like to get julia's dispatch system to call my special purpose implementation of @generated function getindex_impl{F<:FixedArray,N}(a::Array{F,N}, inds...)
if length(inds) == ndims(F) + N
quote
destructure(a)[inds...]
end
else
quote
# Hack: Need to call Base implementation detail to avoid infinite
# recursion of getindex(::Array{F<:FixedArray}) calling itself.
Base._getindex(linearindexing(a), a, inds...)
end
end
end
# Hack: several definitions to avoid ambiguity warnings vs underlying Array implementation
Base.getindex{F<:FixedArray}(a::Array{F}, ind::Real) = getindex_impl(a, ind)
Base.getindex{F<:FixedArray}(a::Array{F}, ind::UnitRange{Int64}) = getindex_impl(a, ind)
Base.getindex{F<:FixedArray}(a::Array{F}, ind::Colon) = getindex_impl(a, ind)
Base.getindex{F<:FixedArray,T<:Real}(a::Array{F}, ind::Range{T}) = getindex_impl(a, ind)
Base.getindex{F<:FixedArray}(a::Array{F}, inds...) = getindex_impl(a, inds...) |
Hmm, I'm still not fully satisfied by any of the above (particularly the |
I guess #62 addresses this well enough, we'll see :) |
When using arrays of small immutable types, I commonly find myself wanting to slice along the "field name dimension". Say I have an array of boring old
Vec3
type:Now I want all the
x
coordinates... darn, am I going to need a comprehension or something equally verbose and inflexible? (Possibly not, I'm a newcomer toFixedSizeArrays
as of today.)What I'd really like is to "slice along the x field dimension", thus:
v[:x, :, :]
. Here's an interesting proof of concept which seems to work (please excuse the hacky reshape junk, it's just a proof of concept):Now I can do things like
Good idea or terrible idea? It sure seems super handy.
The text was updated successfully, but these errors were encountered: