-
-
Notifications
You must be signed in to change notification settings - Fork 67
Add code that gives an nice Array interface to a vector of arrays #2
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
Add code that gives an nice Array interface to a vector of arrays #2
Conversation
Codecov Report
@@ Coverage Diff @@
## master #2 +/- ##
==========================================
+ Coverage 62.36% 77.27% +14.9%
==========================================
Files 2 2
Lines 93 66 -27
==========================================
- Hits 58 51 -7
+ Misses 35 15 -20
Continue to review full report at Codecov.
|
Would it be difficult to check what the cost of the ragged flag is? I am hoping it's essentially zero, in which case that's awesome! If so, then let's make a What happens if you just put this on a |
Yeah I wanted to benchmark this. Do you have any examples of how I might best do this? Should I just make a couple of different sized arrays and check out the overhead of doing indexing (the part that scares me the most)? |
src/vector_of_array.jl
Outdated
Base.sizehint!{T, N}(S::AbstractVectorOfArray{T, N}, i) = sizehint!(S.data, i) | ||
|
||
function Base.push!{T, N}(S::AbstractVectorOfArray{T, N}, new_item::AbstractArray) | ||
if S.dims[1:(end - 1)] == size(new_item) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if S.ragged && S.dims[1] == size(new_item)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wait actually, this is for not ragged? I don't quite understand what's going on here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are updating the dims attribute if it matches the current shape of the other elements (we drop the last element as this is the length of the containing vector). Otherwise we make it ragged. But you show a bug, I need to check that it has already become ragged in which case I don't need to do anymore checking. Will fix this up.
src/vector_of_array.jl
Outdated
# Based on code from M. Bauman Stackexchange answer + Gitter discussion | ||
type VectorOfArray{T, N, A} <: AbstractVectorOfArray{T, N} | ||
data::A # A <: AbstractVector{<: AbstractArray{T, N - 1}} | ||
dims::NTuple{N, Int} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a tuple if it's changing with each push?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better as a Vector{Int}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I will make that change, I think I originally did this just to make it more Array like, but it clearly doesn't make sense as it is not static.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only issue is can I make the field readonly? Might cause strange issues if the user mutates the dim field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't worry about that. If a user does that, they deserve problems.
It would be good to know the numbers for the overhead of indexing, but since there really isn't much we can do about it (by design) it's moreso for understanding when someone should convert to a matrix/tensor. There are two things here. Speed of building and speed of indexing. Speed of building is first. I plan to swap out the current array that's used in each solver with a But then next is indexing. The solvers and event handlers only actually use the linear index, and that should stay the same speed because that's just passing through to indexing the vector. The more general indexing is only used on the user side. It's a convenience, and so is the conversion to a matrix function (maybe we should have it just be |
The timings your want make a lot of sense. I will get this rigged up, as it will be really good to know. |
I took a good look at this. I'm not sure that the extra fields are really worthwhile. The S.ragged && throw(BoundsError("A ragged VectorOfArray does not support Cartesian indexing")) But that's unnecessary: in many cases a Cartesian index still makes sense. For example, with this you can't do But that also means you can just take And then once you do this, the overhead it's a zero-overhead abstraction too. It would still be interesting to test the cost in indexing, but that would be a structural cost and not something you could improve at all. Even after you trim all of this back, I don't think you hit any of the functionality in the tests, which shows that it wasn't essential anyways. I rebased you to the current RecursiveArrayTools.jl since a bit has changed here. |
Okay this Friday I will look over this. I really hope that removing ragged and dims makes everything awesome, which makes sense! I never liked having the ragged check inside what would be a very commonly used indexing operation (at the user side). |
When you did your test did you remove the subtyping from AbstractArray? I am getting a bunch of issues from the dims not really being what we would want, since |
Why not just define dims? When it's subtyped as |
@gabrielgellner will you be available tomorrow? I would like to work through this and finish this up over the weekend. |
Saturday is my wife's birthday. But I plan to power through this on Sunday if that works. |
Sounds good. |
Remove ragged field, and go back to simple AbstractArray interface.
src/vector_of_array.jl
Outdated
@boundscheck checkbounds(S, I...) # is this needed? | ||
S.data[I[end]][Base.front(I)...] | ||
@inline function Base.getindex{T, N}(VA::VectorOfArray{T, N}, I::Vararg{Int, N}) | ||
@boundscheck checkbounds(VA, I...) # is this needed? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is needed
src/vector_of_array.jl
Outdated
#@assert all(size(vec[1]) == size(v) for v in vec) | ||
VectorOfArray(vec, (size(vec[1])..., length(vec))) | ||
end | ||
VectorOfArray{T, N}(vec::AbstractVector{T}, dims::NTuple{N}) = VectorOfArray{eltype(T), N, typeof(vec)}(vec) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this pure? Can this be inferred?
type VectorOfArray{T, N, A} <: AbstractArray{T, N}
data::A
end
VectorOfArray{T, N}(vec::AbstractVector{T}, dims::NTuple{N}) = VectorOfArray{eltype(T), N, typeof(vec)}(vec)
VectorOfArray(vec::AbstractVector) = VectorOfArray(vec, (size(vec[1])..., length(vec)))
A = rand(4)
@code_warntype VectorOfArray(A)
Variables:
#self#::Type{VectorOfArray}
vec::Array{Float64,1}
Body:
begin
(Base.arrayref)(vec::Array{Float64,1},1)::Float64
return $(Expr(:new, VectorOfArray{Float64,1,Array{Float64,1}}, :(vec)))
end::VectorOfArray{Float64,1,Array{Float64,1}} Great! That infers well. I think you cracked the code for how to make it type-inferably |
This is looking really good. I think we are close to done.
What do you think? From a quick search over DiffEq, it seems that re-defining length wouldn't be too disruptive (it was defined before on Other thing: this should all be written on some |
My gut feeling is that it should be over the container vector, as like you suggest I think of the
I really think these two things together are super convenient and nice. Also happy to make this all an Abstract type, though I don't have a great feeling over whether the diffeq solution should be a subtype. I guess it is likely a VectorOfArray with extra fields so it does make conceptual sense to me. |
One other thing I wanted feedback on. So when the array is not ragged we get sweet printing, just like it was a dense array. Once it is ragged the printing becomes meaningless. As a result I was planning on making our own print, that just gives that standard array of array view. Make sense? |
That makes sense to me. |
Okay I added the length behavior, and moved to use Abstract base type. |
So just the show methods now? |
Yup. Working on that now, and then should be ready to merge. |
I think the show methods can come in another PR. I like short PRs better anyways. I changed |
Nice. I will keep looking into how the display machinery works, and get this ready for a future PR. Once this is merged what do you need from me next? Should I start working on adding an interp output PR? |
I think that's the way to go next. |
Let me know what you need. My gitfu is weak.