-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
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
This adds root finding to pchip as this is possible to do optimal because pchip is a monotonic interpolation. #3260
Conversation
pchip is a monotonic interpolation. Alternative would be fsolve and friends, but those would not use the known structure of pchip
It could be more efficient to convert We will probably eventually deprecate polyint.PiecewisePolynomial in favor of that. |
PPoly seems not optimal to use. It's not actually root finding but inversion, more like fsolve. You then know the interval. After all pchip is monotone, so you know there is one, and only one value that satisfies y=f(x). Would this real_roots be exposed? |
The root finding internal function is exposed as I see, the point is that you can find the correct interval fast via searchsorted in y. One could think about adding an additional argument "assume_monotonic" to |
I tried the other possible approach: add an inverse function that returns an interpolated object which is the inverse. This is not working however, too unstable. The numerical precision errors in solution values or inverse derivatives, are such that the inverse interpolated polynomial is very different over large intervals. So that approach is a no go, root finding will be the only acceptable approach. |
This should be reimplemented on top of current master branch, as gh-3267 converted Pchip to use BPoly. Actually, I think this PR would best be done by adding a method For |
If/when
|
@bmcage can you provide an example where the inverse interpolation gives unacceptable numerical errors? |
@ev-br I pushed my local branch with that test: https://github.com/bmcage/scipy/tree/monohermsplineinv |
Hmm... This example looks a bit artificial to me, is it actual data you're interpolating? What is the actual problem you're solving? |
I'm doing it logwise in reality. It's just a testcase which shows how it can fail dramatically. Rootfinding does not cause such errors. |
The test is taken from scipygh-3260.
The test is taken from scipygh-3260.
OK, I looked at this PR again, in gh-16147. Implementation details have changed a bit since this was first submitted, so here's a brief summary. Given a piecewise polynomial, The currently missing bit is that The discussion in #4356 (comment) claims that vectorizing Here's a problematic thing. Consider
Note that the number of solutions is different for different values of So, possible options are
Option 1 feels ugly. All in all, I fail to see an advantage over just manually looping over the input array in user code: @bmcage would appreciate your thoughts (I realize it's been a while) I'll also ping @AtsushiSakai and @mdhaber, maybe y'all have better ideas? maybe you would weigh in @pv? |
|
It's a loop this way or another. In the solve method it's likely this one: https://github.com/scipy/scipy/blob/main/scipy/interpolate/_interpolate.py#L1268
Following up the example above,
The intended usage AFAIU is exemplified by the tests in this PR, which are somewhat cleaned up and expanded in gh-16147. |
Personally, I like option 1 style output, because dtype stability is more important than nan filtering. I have no better ideas for ragged array representation. |
OK, so per review comments object arrays are not wanted; on the table there are only option 1 --- pad shorter arrays with nans --- and the unnumbered option of not accepting arrays at all and asking a user to do
On balance, I suggest we close this PR and gh-16147. I'm going to hit the red button in a couple of weeks, please comment if you prefer a different course of action. |
Alternative would be fsolve and friends, but those would not use the known structure of pchip.
A typical use for pchip is an interpolation that can be inverted. This adds a root finding to pchip that uses the pchip form to invert fast.
I am not sure this is the best way. It might be better to use phcip to obtain yi=f(xi) and yi' = f'(xi), then create the cubic monotonic interpolation through yi with derivatives yi' as self.pchipinv. This should be the correct f^-1.
Then when asking roots, one can use this self.pchipinv.
The algorithm proposed here works differently: search the cubic for the y value given, calculate the 3 cubic roots. As it is a monotonic function only 1 of the roots will be in the correct interval.
Some problems:
See the np.allclose(ires, 0., atol=1e-10) to discard this. -10 is hard coded
See the np.allclose(x1-rres, 0., atol=1e-10) to recognize this. -10 is hard coded
I believe this will be correct for the use cases possible