-
Notifications
You must be signed in to change notification settings - Fork 108
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
[Enhancement] Add Cubic Spline Interpolator #632
Comments
If somebody read the initial issue before Monday Dec 30 |
@MothNik thanks for this contribution, it looks great at first sight! Indeed, we do have only pretty basic interpolation method so far... the main reason being that anything more complex requires more thinking when framed in a forward/adjoint setting like the one we require in PyLops (as you have probably realized writing your code); for example, spicy has nice interpolators but they only provide what we call the forward pass so they can't be incorporated easily (unless one writes the equivalent adjoint). Let me take a more detailed look in coming weeks and help you with incorporating this into the plops |
@mrava87 Thanks for the reply! Please let me know if you have any questions regarding the approach or implementation! I also noticed that the adjoints can be quite painful because they often have no real physical meaning. The cubic spline is a good example because it sums up values, solves a linear system, and then computes a derivative, all of which does not really make sense. I'm so glad I found your documentation of the Regarding the dimensionality: In the end, the piecewise third order polynomials in all dimensions always need to join on the knot points in a way that the value and the first two directional derivatives are continuous. That can probably be generalized and requires solving a sparse matrix with a less convenient sparsity pattern than being tridiagonal. I will let it simmer a bit more and hopefully come back with a solution. |
Hi @MothNik, A few comments/questions:
(everything else is unchanged...), and then add it as one of the options - i.e. add pylops/pylops/signalprocessing/interp.py Line 229 in 6c92032
_cubicsplineinterp.py and the just import the class in the interp file.
Feel free to have a go at it and make a PR, then we can help you finalize the code :) |
Edit$\mathbf{A}$ and thus also $\mathbf{D}$ and $\mathbf{Q}$ , but I fixed the explanations and the code. Now, the cubic spline really has second order derivatives of zero at the boundaries.
If somebody read this before Monday Dec 30
I made a mistake in the matrix formulation of
Motivation
Thank you very much for this amazing package! I'm still in the process of diving deeper into it, but I would like to apply it for problems that involve 1D-interpolation.
Unfortunately, the
pylops.signalprocessing.Interp
only offers interpolation methods which are either not accurate enough ("linear"
,"nearest"
) or too computationally expensive ("sinc"
).Proposed Feature
I would like to propose to incorporate a cubic spline interpolation into
Interp
which would be a good middle ground in terms of accuracy and computational load.While I managed to implement it, I don't know how easy this can be cast into the backend-agnostic nature of
pylops
. On top of that, I'm not 100% sure if this can easily be generalised to arbitrary dimensions, altough I think that a 1D-only implementation would already be great.Theoretical Background
I derived the following matrix notation from the German Wikipedia article on spline interpolation. It was a bit of tedious work with index-bookkeeping and reformulation of the equations, but I got it to work.
The matrix formulation for the interpolation would be
where
For natural boundary conditions (second derivative at the boundaries is zero), the matrix$\mathbf{Q}$ looks like
where
The matrix$\mathbf{A}$ is a tridiagonal strictly diagonally dominant (but not symmetric) matrix with the following structure:
The matrix$\mathbf{D}_{0+}$ is a second order finite difference matrix with the following structure:
Consequently, the transpose operation$\mathbf{O}^T$ looks like
In both the$\mathbf{O}$ and $\mathbf{O}^T$ case, the solution of $\mathbf{A}^{-1}$ and $\left(\mathbf{A}^{T}\right)^{-1}$ can be achieved very fast by using two separate banded LU decompositions.
Implementation
I would like to share my implementation that currently relies on
scipy.sparse.linalg.LinearOperator
because I didn't manage to inherit fromInterp
yet. Besides, it invokesscipy
further for handing the sparse matrixX
and solving the banded matrices with LAPACK.I also implemented a custom finite difference operator with Numba to be fast.
The code was written in a Jupyter notebook and all the
%magic
operations are commented out. The timing results can be found below.Edit$\mathbf{A}$ and $\mathbf{A}^{T}$ by invoking the LAPACK-wrappers for
I adapted the code so that it reuses the factorizations fo
gttrf
andgttrs
. So, intead of a factorization + solve call for every matrix-vector product, the factorization is only called once and the results are used in one solve per matrix-vector product.Results
Correctness and Timing
The timings for this test with a relatively large complex Array show that the cubic spline interpolation in this basic version is competitive. It passes
dottest
and its runtime is comparable to the linear interpolation.Timing PyLops Linear Interpolator Creation 2.04 ms ± 106 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) Matrix-Vector Multiplication 314 µs ± 4.53 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) Transpose Operation 218 µs ± 11.4 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) Timing PyLops Sinc Interpolator Creation 12.7 ms ± 228 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) Matrix-Vector Multiplication 3.67 ms ± 146 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) Transpose Operation 5.43 ms ± 389 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) Testing custom Spline Interpolator Passed! Timing custom Spline Interpolator Creation 750 µs ± 14.7 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) Matrix-Vector Multiplication 260 µs ± 12.1 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) Transpose Operation 290 µs ± 4.53 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
Visualisation
In one go, the real and imaginary part of the complex test data are interpolated separately as intended. For this example, the cubic spline gives higher accuracy than the linear method. Besides, it also does not suffer from the ringing introduces by the sinc-interpolation of the imaginary part.
The text was updated successfully, but these errors were encountered: