-
Notifications
You must be signed in to change notification settings - Fork 110
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
Rewrite with clear separation of concerns (closes #2) #4
Conversation
CC @timholy I don't know if you get notifications on this without me mentioning you, but I'd love to hear your thougths on this =) |
I do get notifications (you can see who it watching by clicking on the 5 up at the top of this page). Don't have time to read it right now, but hope to soon. |
Check! No hurries =) In the meantime, I'll see if I can come up with a skeleton implementation using this architecture, so there is some code to look at as well. |
OK, there's a very simple example of the architecture I have in mind over in the rewrite branch |
It's looking more put-together, which is nice! But I'm still not sure I understand the mathematics you're proposing for extrapolation. If that's easier to write up as a LaTeX document, go for it. Presumably you also saw timholy/Grid.jl#53, which could be turned into a well-defined proposal for how to extrapolate. |
There - there's now a working implementation of constant and linear interpolation, as well as quadratic interpolation in 1D. The results look OK to me: this is one period of When looking at the prefiltering implementations in Also, I don't know if my thoughts about extrapolation became clearer now that there is some substantial code to look at as well. If not, please let me know and I'll try to clarify further. |
Oh, there's also an IJulia notebook which shows off the way to reproduce that graph. |
Yes, I agree that the custom iteration has to go. Now that Julia has Base.Cartesian (and in 0.4, easy-to-use iteration types), I suspect this should be quite feasible. By prefiltering you mean the whole |
Yeah, exactly. I basically copied the relevant
|
I don't think you committed |
I didn't initially - sorry about that - but I fixed it later. So now it's here 😄 |
Ah, I was looking at the While I admire the desire to make the inversions easier, I have to warn you it's nontrivial. Basically, the task in 2d is that you have to solve a tridiagonal system along each column, and then along each row. In 3d, think about a bundle of pencils all pointing in the same direction: each pencil represents a tridiagonal system of equations. Solve each pencil, then re-orient the entire bundle along a different axis and do it all over again. So if you have a KxMxN array, you solve The good news is that we have better tools now. Particularly, the combination of stagedfunctions and Base.Cartesian should make this more straightforward. BUT...it's not just that supporting arbitrary dimensions is a bit tricky; if we want it to be really fast, we may be in for a certain amount of pain. The version in Grid basically "snips out" a pencil (the Unfortunately, in terms of the order in which it visits elements, that's analogous to the version of the algorithm described under "write cache-friendly codes" introduced as "It is natural to implement this as follows:". (You could have replaced the inner loop in Dahua's illustrative example with a black-box I don't know how much of this is clear; I can try to explain any specific parts that are confusing. |
The pencils are a good analogy, so most of it is pretty clear. I too realize that this is very much nontrivial, so I guess I wasn't hoping for a quick "add a macro here" solution, but I think we could do this in several steps. First, obviously, we should to build something that works at all. I guess a naïve, cache-unfriendly version that might be slow but gets the job done is definitely good enough. A lot of work from Grid can probably be re-used here, but using When we have that in place, we can start thinking about ways to make it faster. A package with general-dimensional, cache-friendly versions of But since all of this matrix system solving is done only once for each interpolation object, I think it's more important to get indexing (and, eventually, also evaluation of derivatives) fast, and to implement as many useful interpolation types, boundary conditions etc as possible. |
After giving this another round of pondering on the subway ride to work, I think my main concern here is that I want to separate implementation details from the math as much as possible also in this part of the library, in the same way as we do with generation of the
I think the basic approach should be that when implementing a new interpolation type, the coder just provides an expression for the un-altered system (or re-uses one, if there is one already), and another expression for the alterations, and then there is some macro magic that takes those and, like for |
There, now I've generalized this to use macro-ized prefiltering. However, there is one problem: because of how I index into the coefficient matrix, the prefiltering isn't applied. If I understand how this works correctly, Is this behavior going to change in 0.4 (I'm testing on 0.3 atm...)? If not, how should I do this indexing to actually alter A in-place? Also, I realize that this is still not cache-friendly. However, I don't think there is a way to do this cache-friendlier, at least not without copying a lot of data between runs, since we want to do the matrix solving in all dimensions (thus being cache-un-friendly in some dimension regardless of which ones we start in...). If the matrix solving algorithm has a lot of cache misses, it might be benefitial to copy out the vector that we want to solve with, solve, and then copy back the result, but that will impose a copying cost instead, so I'm not sure what will be fastest. If this doesn't cut it, we'll have to profile and decide then. |
...and of course I had simplified the problem too much. That code, when altered to have the correct copy behavior, only works in 1D - anything higher, and there is no iteration over each row and column anymore, so most of the array is never filtered. I'm looking into it... |
On Julia 0.4, with the new SubArray work I just merged, I think it will become possible to rewrite julia's |
Voila! As far as I can tell, this works now for at least 1D and 2D interpolation (and none of the implementation is dimension specific, so I would assume that it carries to larger dimensions). I also re-worked the notebook into a sort-of tutorial that shows off and explains the currently implemented functionality. I haven't yet figured out a nice way to test all this stuff, so Travis will still complain. I'm thinking about stealing relevant parts of Grid.jl's test suite and adapting the interpolation constructors. @timholy, how do you feel about merging this and start building in smaller chunks from here? |
Rewrite with clear separation of concerns (closes #2)
promote_type_grid(T, x...) = promote_type(T, typeof(x)...) | ||
|
||
# This function gets specialized versions for interpolation types that need prefiltering | ||
prefilter(A::Array, it::InterpolationType) = copy(A) |
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 make a copy when, for nearest and linear, it's not necessary?
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.
For concistency.
Copying is necessary for higher orders (if we don't want to change the input array already on creation of the interpolation object...), so if we don't copy also for nearest and linear, interpolation objects of different degrees won't behave the same:
A = rand(10)
itp1 = Interpolation(A, Linear(OnGrid()), ExtrapError())
itp2 = Interpolation(A, Quadratic(ExtendInner(), OnCell()), ExtrapError())
A[3] = 5.0
Now, the coefficients of itp1
have changed, but not the coefficients of itp2
...
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 see your point. But for efficiency we might want to offer Interpolation!
that avoids making a copy (and in the quadratic case destroys the input).
Overall, this is looking really promising! |
I just started working on some documentation for how I envision the pieces of this library to fit together. Most of this is obviously just sketches and fairy tales at the moment, but at least it might give us something to discuss and improve on. I'm hoping that discussions around these documents can help finalize some decisions that are probably easier to make before writing macro-heavy code than after =)