-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
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
ENH: linear interpolation of complex values in lib.interp #6872
Conversation
Choosing complex vs. real interpolation via cast attempts on fp (using PyArray_ContiguousFromAny) was not catching the cast error and failing on some of the builds. I switched to passing in a flag (to compiled_interp), to choose the behaviour. |
Thanks @pec27 for the PR, and sorry it's taken a while to get to it. It looks like this gives a speedup of about 2x over the simple version you pasted, which is pretty good for a function I suspect people call repeatedly. I tested the PR with:
The code looks correct, however What I think would be the "ideal" version of this PR is a little bit more complicated than what you have done, but I think it wouldn't be too hard to do if you are interested, and I am happy to give pointers. It involves using numpy's "repeat" preprocessing, which is essentially a big macro system: It makes repeated copies of a block of code but varying the data types. To get an idea of what this means look at PR #7464 which generalize So essentially your work would be to take the two code paths you've already written, but instead of splitting them up using if statements you would split them up using some combination of switch and repeat (I think). |
Thanks @ahaldane for the looking over this! Suggestions on improving code re-use are always welcome, I imagine I may have missed some tricks with the numpy type system. Having said that my intention with this PR was to extend interpolation from the reals to the complex field whilst introducing no regressions, i.e. the interpolation precision is still float64 if you are doing interpolation with real values (which is also the precision of the interpolation of the components of the complex numbers). I can see the use-case of allowing different precisions, e.g. float16, float32 etc for interpolation, but potentially users were relying both on the accuracy and on the return type being float64, and then there is potential ambiguity with what to do if say x.dtype is float32 and fp.dtype is float16 (or even one or both being integer type - should integer interpolation of an integer be an integer? I think not but others may disagree). Given the potential regressions perhaps handling different precisions should go in a separate PR? |
That's a good point, users might be expecting In the case we only support double and cdouble, I still would like to think about whether there is a tidier way of writing this up. I feel like There are two alternate possibilities I am thikning about (besides leaving it as it is):
Or maybe there is a better way of tidying it using appropriate helper functions? I am leaning towards option 1 now - it is probably the easiest to do. Once it is written up in that form it it shouldn't be too much work if we ever want to adapt or generalize it in the future. Does that seem reasonable? |
Option 1 is pretty straightforward, as you point out the code is basically just switched in one big if statement so two functions is probably a little easier to read. I’ll update the PR and you can see what you think. If we had demand for a 3rd case then I’d definitely prefer something like |
Yeah, I'm happier with how this looks. Let's go with two functions. Some things to fix:
and then using After that I think we are pretty much done. |
The casting to p.s. How I wish all these |
This looks to be getting towards the end. Could you add a note to |
Py_XDECREF(ax); | ||
Py_XDECREF(af); | ||
return NULL; | ||
} |
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.
also, add a blank line here between functions
Thanks @ahaldane @mhvk I think I got all those changes in. @ahaldane - I’m not sure about squashing commits, is that still ok since they are pushed to github? Commit @charris is the release note request for me? Do I have access to that file? |
@pec27 you're right that changing history (eg by squashing commits) is a bad idea if anyone has already pulled your code, but in this case nobody has. When making a PR it is acceptable to rewrite the history of your copy before it is merged into our copy. Here's how I usually do it: After I've finished modifying the code, I do
to squash/amend the commits I want. You need to change the "6" to the number of previous commits you want to rebase over. After you squash it will ask you to rewrite the commit messages (which you should do). Then I do
to push to by github fork. |
Also, @charris indeed did ask you to add a release note to that file (it's in the numpy file tree). I think it would go under "new features", and you can just copy the style of the other features already there. Also, I don't think you've removed all the tabs yet, and it would be nice to undo any changes to |
Ah, I think I removed all the tabs and then merged them back in. Doh. I will fix and recommit. |
Oh and one more comment: Choosing how to squash/amend your commits is up to your judgement in general. In this case the changes are self contained enough that I would be satisfied if you simply squashed everything into a single commit, for example. |
Thanks for the tips on rebasing. About the |
@ahaldane: note that github nowadays has the "squash+merge" button that
squashes everything into one commit (be sure to write the desired commit
message to the msg box).
|
@pec27 To get the notes file, make sure your master branch is up to date, then checkout your branch and |
@@ -24,7 +24,7 @@ | |||
from numpy.lib.twodim_base import diag | |||
from .utils import deprecate | |||
from numpy.core.multiarray import _insert, add_docstring | |||
from numpy.core.multiarray import digitize, bincount, interp as compiled_interp | |||
from numpy.core.multiarray import digitize, bincount, interp as compiled_interp, interp_complex as compiled_interp_complex |
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 line is too long, it needs to be shortened like
from numpy.core.multiarray import (
digitize, bincount, interp as compiled_interp,
interp_complex as compiled_interp_complex
)
Hi @charris @ahaldane I rebased to master but github doesn’t seem happy - it thinks I am now trying to PR 693 commits. I’m not quite sure how to tell my github fork that I have rebased from upstream. Any advice from wiser heads welcome! If it helps I have so few changes that I should be able to re-apply everything manually... |
Hmm, I have no idea what you did, although it looks like you did a merge in there somewhere. The first thing to do is to recover to something sane. For that, run |
Thanks @charris, that restores me back to somewhere sane, I’ll try the rebase again tomorrow with fresh eyes. |
ccfeb6d
to
eaaa7e8
Compare
333ee7c
to
67295a0
Compare
lib.interp function now allows interpolation of complex fp with complex128 precision (i.e. equivalent to lib.interp on the real and imaginary parts). Tests are added for the non-periodic and periodic cases.
The rebase went smoothly today, I blame bit rot :-). I think I have covered everything (release note, squashed commit, numpy style conventions etc), @ahaldane could you take a look to see if it is pull-able? |
Looks nice and clean to me now! Thanks a lot for the PR @pec27, I'm going to go ahead and merge. |
I wanted to be able to do linear interpolation between complex values, i.e.
rather than
This could be just achieved with a wrapper for the above, detecting the complex case, but I thought I would reduce the double cache-misses by covering the complex case in compiled_base.c
This is my first pull request, please be gentle :-).