[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
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 b-splines #3174

Merged
merged 39 commits into from
Oct 21, 2016
Merged

add b-splines #3174

merged 39 commits into from
Oct 21, 2016

Conversation

ev-br
Copy link
Member
@ev-br ev-br commented Dec 27, 2013

This PR implements a base class for evaluation of b-splines without fitpack.
Representation is compatible with splrep and splev though.

The plan is to have a base class with a sensible API usable by both human users and interpolation / fitting to data (the latter is on an immediate plan).

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling 8bfe266 on ev-br:bsplines into fde1826 on scipy:master.

@ev-br
Copy link
Member Author
ev-br commented Dec 30, 2013

The last commit fixes the out-of-bounds behavior to be almost consistent with the b-spline definition in the literature: the interpolation interval is closed, so that the spline is left-continuous at the right-hand endpoint; outside of the interval it is zero, unless extrapolation is requested.

A corner case is nan handling: at the moment, nan is not treated specially, so that b(nan)=0.

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling 28ec512 on ev-br:bsplines into fde1826 on scipy:master.


"""
def __init__(self, t, c, k, extrapolate=False):
super(BSpline, self).__init__()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line doesn't do anything. Leftover from some subclass?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is deliberate: super calls the next class in the MRO. Which can be anything if a user uses multiple inheritance (whether this is a good idea or not is a different question).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah OK. I'm not a big fan of multiple inheritance, but this line makes sense now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me neither.
Still, if a user decides to use it, leaving it out causes weird bugs: __init__s will not be called.

@rgommers
Copy link
Member

The from_fitpack_tck and get_fitpack_tck are potentially confusing. Does it make sense to have two incompatible tck representations? Can we have another naming convention for b-splines?

@rgommers
Copy link
Member

Have you considered how to replace the spline implementations in the signal and ndimage modules with this?

@rgommers
Copy link
Member

Have you seen this thread: http://thread.gmane.org/gmane.comp.python.scientific.devel/17349 ? Both @pv and @charris were also working on / thinking about b-splines.

@ev-br
Copy link
Member Author
ev-br commented Dec 31, 2013

@rgommers in fact this code heavily uses things done by Pauli, borderline shameless stealing.

Thanks for the link, I'll have w closer look --- I only saw gh-1408 and scattered older ML discussions. The point of this PR is mostly to provide a stab at an implementation and to have something concrete to discuss. I'll happily scrap all this if there's a better implementation and/or if there are objections to details of the format (tck padding etc).

I think this can be used for both replacing much of the fitpack in the interpolate module (interp1d, shudder), either as a replacement or making user-facing interp1d, UnivariateSpline use these under the hood. Same for cardinal splines in signal and ndimage.
Doing this all in a single PR is a bit too much, so for the moment I'm trying to concentrate on the low level functionality, then move on the interpolating splines and fitting (have bits and pieces, not ready for a PR), and then start replacing and consolidating the user-facing code. It all relies on a consensus on the basic format --- hence this PR.

I'll address your comments, but for the moment I've run out of time for today, time for a New Year :-).

@rgommers
Copy link
Member

Agreed that signal/ndimage is not for this PR. My question on tck is not an objection, more like something I was wondering about.

Happy New Year!

@ev-br
Copy link
Member Author
ev-br commented Dec 31, 2013

tck: it's ugly, I agree. The problem, as far as I understand it, is with how exactly to define a spline, esp at the edges of the knot vector. Dierckx's convention is probably documented is his book, which costs more than a hundred quid and is not widely available from what I can see. Extracting it from the fitpack code is fun :-). My convention here is, I think, compatible with the reference in the docstring. Will attempt at documenting it better. Whether this is acceptable/typical, I'd appreciate an input on.

Happy New Year!

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling e3a96ce on ev-br:bsplines into fde1826 on scipy:master.

@ev-br
Copy link
Member Author
ev-br commented Jan 4, 2014

Have added a couple of commits with improvements to documentation [shameless stealing from Pauli, again], small tweaks in the basis_element signature, and tests.

Also timed the evaluations (in a rather ad hoc way) against fitpack:
http://nbviewer.ipython.org/gist/ev-br/8260758
Have to admit, I don't really understand these timings. For scalar input, splev wins hands down (python overhead of BSpline.__call__?). For 1D input it seems to depend on whether the input is sorted: if it is, fitpack shines by a factor of 3--5; otherwise, it loses by a factor of about two. At the same time, cython evaluations are barely sensitive to the ordering of input.
Clearly, fitpack does something smart somewhere (and I do something dumb). Will try investigating.

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling 05bf090 on ev-br:bsplines into fde1826 on scipy:master.

@pv
Copy link
Member
pv commented Jan 11, 2014

Sorry for the delay. I have one bigger comment about the spline representation:

I really think we should go with the representation used in FITPACK. The argument for this is:

  • It's what was available previously, and we retain tck compatibility with splrep et al.
  • It's the simplest and most general representation (if you assume zero coefficients outside the array). The finite interval spline can be obtained by adding coinciding knots at the endpoints (which is what __init__ currently does).
  • The only small quirk of the FITPACK repr is that the c array is padded at the end to the same size as t rather than to the number len(t)-k-1 of the actual basis functions. (We could avoid this by allowing any size c array an assuming zero coefficients out of bounds.)
  • The assertion p = BSpline(t, c, k); assert_allclose(p.t, t); assert_allclose(p.c, c); assert_allclose(p.k, k) is retained, as for PPoly and BPoly. I think having this assertion be true is somewhat important in the general case.
  • We can drop the get_fitpack_* functions completely.

A separate constructor could be added for the finite interval case.

@charris
Copy link
Member
charris commented Jan 11, 2014

I'll just add a few comments about things that should be kept in mind for the future.

  • Tensor products. This will in general require several copies of tck.
  • Vector valued splines, needed for curves.
  • Periodic splines, needed for closed curves.

These can probably be built on top of 1D, scalar valued splines, but some thought up front may make that easier to do.

@pv
Copy link
Member
pv commented Jan 11, 2014

@charris: Tensor product support should be done similarly as for piecewise polynomials in gh-3104 (not merged yet, if you have ideas how to improve that, it would be appreciated).

This PR already supports vector-valued splines, if I understand what you mean correctly.

Periodic splines: for evaluation, does this mean that the knot set is treated as periodic, identifying t[0] and t[-1]?

@charris
Copy link
Member
charris commented Jan 11, 2014

Vector valued splines is essentially a stack of splines with the same knot points and end conditions, i.e., a map of a line segment into a multidimensional space. If they are already there, great. It also makes solving for multiple rhs more efficient.

Yes, the coefficients are periodic. This mostly affects the spline construction, it is a boundary condition. I've looked at the Sherman-Morrison formula and its generalizations for doing this in the uniform spline case, but I don't know what the current state of the art is.

@charris
Copy link
Member
charris commented Jan 11, 2014

I'll add that when I was looking at splines, my impression was that cubic splines were nearly optimal for most problems, apart from the results of differentiation and integration, and some boundary conditions -- not-a-knot, etc. -- made more sense with that restriction. So it might be worth while offering some options that are only available for cubic splines.

@pv pv added the PR label Feb 19, 2014
@ev-br
Copy link
Member Author
ev-br commented Apr 14, 2014

OK, time to stop this from bitrotting completely. Rebased, squashed, addressed the review comments.
This version has tck format directly compatible with fitpack.

Have also updated the notebook with timings (as crude as they are). Which indicate this is still very much WIP: being two to three times slower than fitpack is no good at all. The prime suspect is my half-baked evaluation routine, will investigate.

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling 980ef5f on ev-br:bsplines into 87df1db on scipy:master.

@ev-br
Copy link
Member Author
ev-br commented Jun 1, 2014

The last commit adds the constructor for interpolating splines. Several boundary conditions are supported (natural, not-a-knot, explicit derivatives, periodic). All linear algebra uses banded matrices. Still WIP: periodic boundary conditions need a bit more work.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.06%) when pulling 934a316 on ev-br:bsplines into 93656a8 on scipy:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.06%) when pulling 934a316 on ev-br:bsplines into 93656a8 on scipy:master.

@pv
Copy link
Member
pv commented Jun 1, 2014

Thanks. Brief look at the last commits seems to indicate that this is close to the minimal set of feature completeness. I'll hope to look at this closer soon(TM) (probably not within the next week however...)

@coveralls
Copy link

Coverage Status

Coverage increased (+0.09%) when pulling 97e111b on ev-br:bsplines into 93656a8 on scipy:master.

ev-br added 5 commits October 12, 2016 12:19
And use it in BSpline.basis_element.
Make splrep/splprep return tck-tuples for backwards compat, and make
other spl* functions accept either tck-tuples or BSplines.

Raise warnings when using spl*(Bspline, ...) with c.ndim > 1, as suggested
in the code review.
@ev-br
Copy link
Member Author
ev-br commented Oct 12, 2016

OK, pushed an update where I believe I addressed @pv's review comments. Apparently Github does not hide outdated comments anymore. Relevant commits start from e6c5b72.

The main change is that splrep and splprep again return tck tuples and not BSpline objects (0131d72). I've to say I actually like it more. The interface with spl*-functions is still not perfect for multidimentional splines, but at least the logic seems clear: splint(BSpline, ...) is consistent with BSpline.integrate(), and splint(tck, ...) is backwards compatible. So far I did not implement a keyword switch, as suggested in #3174 (comment), but it's easy to bolt on.

Also, tuple-like unpacking of BSplines is gone. This was needed for backwards compat if splrep returns a BSpline instance, to support legacy code which does t, c, k = splrep(x, y). But as long as we're not trying to sneak BSplines in place of tuples, I'd rather avoid that sort of magic. Knots, coefficients and the spline order are anyway available as b.tck or as individual attributes b.t, b.c b.k.

@pv
Copy link
Member
pv commented Oct 12, 2016

Ok, looks good to me currently, and OK to merge from my side.
If we come up with better names than make_* or other tweaks before 0.19.0, we can make those.

@ev-br
Copy link
Member Author
ev-br commented Oct 21, 2016

OK, I'm going to hit the green button in a couple of days, unless further comments.

@matthew-brett
Copy link
Contributor

Great - thanks very much for your persistence on this one.

@pv pv merged commit a247ff7 into scipy:master Oct 21, 2016
@pv
Copy link
Member
pv commented Oct 21, 2016

Thanks @ev-br, let's get it in!

@ev-br ev-br deleted the bsplines branch October 21, 2016 23:15
@ev-br
Copy link
Member Author
ev-br commented Oct 21, 2016

Thanks all for the code, for the reviews, for encouragement and for evolving this from where it started to a useful state!

@rgommers
Copy link
Member

Yay! Great job & persistence @ev-br.

Maybe a PR to say "this is the way of the future" and clarify some of the existing text on splines in the roadmap would be a good idea?

@ev-br
Copy link
Member Author
ev-br commented Oct 23, 2016

Here's a PR: #6715

@pv
Copy link
Member
pv commented Oct 24, 2016

@pv
Copy link
Member
pv commented Oct 24, 2016

Or more precisely, the slinear and zero in interp1d got slower --- the cubic and quadratic got faster (the previous scaling with full matrices was of course ridiculous :).
Maybe there's some trivial special casing possible.

@ev-br
Copy link
Member Author
ev-br commented Oct 24, 2016

Hmm, evaluations for slinear and zero got about an order of magnitude faster, (time_interpolate_eval benchmark), but construction (time_interpolate benchmark) got an order of magnitude slower, or am I misreading it?

@pv
Copy link
Member
pv commented Oct 25, 2016 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement A new feature or improvement scipy.interpolate
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants