-
Notifications
You must be signed in to change notification settings - Fork 6
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
Improve indexing to support table behavior #44
base: master
Are you sure you want to change the base?
Conversation
Codecov Report
@@ Coverage Diff @@
## master #44 +/- ##
==========================================
+ Coverage 79.88% 82.91% +3.02%
==========================================
Files 4 4
Lines 174 199 +25
==========================================
+ Hits 139 165 +26
+ Misses 35 34 -1
Continue to review full report at Codecov.
|
@rafaqz This is ready for feedback. |
The allocation test that is failing on CI passes on my system (Julia 1.6), so it must be a compiler version issue. |
@rafaqz Do you have any thoughts on what to do about this version-dependent test failure? |
So its allocating on 1.3 but not 1.6? You can put that test in a version specific conditional, or we can stop supporting 1.3 |
I like the version-specific conditional idea. Let's see if it works now. |
Also, since this changes indexing behavior (although should be non-breaking for most things...?), we should probably bump the minor version. |
Finally all green! Let me know when you've looked at it, @rafaqz . I'm not 100% happy with the way it turned out... I think the dispatch graph for |
Ok I'll try to have a look tonight. |
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.
This looks like a huge improvement, thanks for putting the time in.
src/model.jl
Outdated
@inline Base.setindex(m::AbstractModel, xs, i::Integer, ::Colon) = Base.setindex(m, xs, i, filter(!_isreserved, keys(m))) | ||
@inline Base.setindex(m::AbstractModel, xs, i::Integer, ::Type{Val{col}}) where col = _setindex(m, xs, i, Val{col}) | ||
@inline function Base.setindex(m::AbstractModel, xs, i, cols::Union{Tuple,AbstractVector}) | ||
for col in cols |
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.
What is the performance of this like? Could cols
be a mixed-type tuple?
src/model.jl
Outdated
end | ||
end | ||
@inline Base.setindex!(m::AbstractModel, xs, col::Union{Symbol,Type{Val}}) = setindex!(m, xs, :, col) | ||
@inline Base.setindex!(m::AbstractModel, xs, i) = setindex!(m, xs, i, :) |
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.
It makes me a little uneasy guessing row/col like this based on type. Can you do this with any other tables?
And should we maybe make i::Union{Int,Colon,AbstractVector}
?
@rafaqz Do you have any other blocking concerns or can we go ahead and merge this? We could make an issue about potential performance concerns. |
Normally we would resolve those two open questions first? One is performance and the other is syntax, which would mean a second breaking change if we change that later. |
At the moment, there are no breaking changes. The syntax question is really whether or not it's worth it to make such a breaking change in order to be consistent with other table interfaces. The performance issue is low priority, at least for my use case. |
The performance issue will take 5 minutes to fix... But the general idea is I wouldn't ask that question in a review if I didn't want to discuss it before merging. |
It doesn't look that easy to me, but maybe I am missing something. In any case, if you already know how to improve it, please feel free to suggest a solution. |
Just use |
No. There is a loop there for a reason. As I pointed out in the other comment, it iteratively reconstructs |
That's a fold.... |
Ok, I'll try |
It makes it type stable but does not have any substantial impact on performance, at least on this test case that I tried: m = Model(s1)
xs = Tables.columns([(val=5.0,bounds=nothing),(val=4.0,bounds=nothing)])
idxs = [1,2]
cols = (:val,:bounds)
@btime Base.setindex($m, $xs, $idxs, $cols)
# before: 26.140 μs (404 allocations: 23.39 KiB)
@btime Base.setindex($m, $xs, $idxs, $cols)
# after: 25.525 μs (404 allocations: 23.39 KiB) Using 24.250 μs (395 allocations: 22.61 KiB) |
It's also worth noting that indexing tables with |
Co-authored-by: Rafael Schouten <rafaelschouten@gmail.com>
3893a37
to
a19832c
Compare
Ah right, maybe we should remove it instead. |
Also how is the ttfx for this stuff? Seems that type stability and allocations from it might also take a while to compile. |
I just started using this branch in my "real world" use case and it's.... not good. Like almost a full minute to compile on a deeply nested model with about 50 parameters. This is with several calls to |
Yeah... the type stability is probably more important for that than for runtime speed. Have a look with |
It's probably going to be |
I guess we should come back to this at some point.... I am no longer convinced that there is a strong enough use case for type-stable table updates that is worth the insanely high compilation cost. Maybe we should just accept type instability here? |
This is a major overhaul of the model interface to better support Table-like indexing behavior, most importantly through
setindex
.The basic idea is that
AbstractModel
s should allow Cartesian indexing, i.e.m[i,j]
for bothsetindex!
as well asgetindex
in order to really act like a table.This PR refactors the existing implementations of
getindex
andsetindex!
to accomplish this, and in the process, expands the functionality ofsetindex!
(andBase.setindex
for the immutable case) to permit row indices.The implementations of
update
/update!
are simplified to be simple wrappers aroundsetindex
. In addition,update
now provides an additional dispatch which permits the application of filtering rules to generate row indices viado
syntax:This allows the user to apply filters to only update subsets of parameters. This is also possible via
setindex!
using row indices:This is a draft PR at the moment. More clean up needs to be done and docstrings added at the minimum. There are also some behavioral issues that need to be addressed, like how to handle broadcasting.Current limitations:
getindex
is not supported, since it's not clear what the return value should be (named tuples?). It is supported bysetindex
, however.getindex
/setindex
on subsets of rows are not in general type stable or allocation free. I think this is acceptable for now given the likely use cases.Resolves #41
Resolves #21