Skip to content

Conversation

@vnmabus
Copy link
Member

@vnmabus vnmabus commented Jun 22, 2025

Describe the proposed changes

Adds a new implementation of the dynamic programming (DP) algorithm used in elastic registration. The new implementation is written in pure Python, with no dependencies on fdasrsf. Unfortunately, it is around 8-10 times slower for large data, so we still keep fdasrsf as an optional dependency, for those that really need the performance. If fdasrsf is present it will be used.

Additional information

There are several benefits to have our own implementation independent of fdasrsf:

  • Convenience: fdasrsf had a lot of problems to compile when Python versions change, or BLAS libraries are not easily found. This was disrupting for both our users and our continuous integration, even when these users do not need to use elastic registration.
  • Learning: having a pure Python implementation makes easier for people to read and understand the algorithm.
  • Maintenance: as the algorithm is easier to understand now, it should be also easier to modify, fix and optimize.
  • Web availability: a medium-term goal of scikit-fda is to be able be used into the web using Pyodide. This opens the door to a lot
    of possible uses, including having interactive documentation. However, non-mainstream libraries that are written in C (including fdasrsf) are not available in Pyodide. After removing this dependency, I think the only missing thing would be to remove the dependency on Numba.
  • Future extensions: a long-term goal of scikit-fda is to be able to support all arrays that conform to the array API standard. Having our own implementation in Python will make easier to support other arrays in the future.

All of these make having a Python implementation useful, even if it is (currently) not as performant as the one in fdasrsf.

Checklist before requesting a review

  • I have performed a self-review of my code
  • The code conforms to the style used in this package
  • The code is fully documented and typed (type-checked with Mypy)
  • I have added thorough tests for the new/changed functionality

vnmabus added 24 commits June 19, 2025 17:53
Add functionality to implement the DP algorithm for warping alignment
(used in elastic registration) in pure Python. This would allow us to
remove the dependency on fdasrsf, have a more clear and maintainable
implementation, and implement elastic registration for more array types
in the future.
Add penalty term to L2 energy function in the DP algorithm.
Add ASV benchmark for testing the time it takes to compute the
Fisher-Rao elastic registration.
In order for elastic registration to be tractable with a high number of
points, we can now reduce the grid used, so that only the energy of
direct lines from near grid points are computed. This should not alter
much the result (lines with far away points can be approximated with
more line segments), but can drastically improve performance.

We now use trapezoid quadrature to compute the integrals that appear in
the energy computation. The reason for that change is that it is easier
to compute the right quadrature weights when integrals with different
domains are computed in a vectorized way.
Scaling by the square root of the slope is necessary when we work with
the SRSF of the curves instead of with the curves themselves.
In addition, the code has been simplified to use the abstractions in
scikit-fda.
In almost-constant parts of the function our implementation of line
energies computation can obtain different results than the reference
(fdasrsf), because we use a different quadrature (trapezoidal instead
of rectangular).

This can be fixed adding a small bit of regularization.
The penalty term was not integrated, as it should be.
Use the newly implemented DP algorithm everywhere.
In particular the evaluation has been optimized using always linear
interpolation. This optimization should probably be applied in the
future to normal evaluation too in the default case.
Some values could be computed once, or once per row.
Unfortunatly, even with these the algorithm is 3 times slower than the
reference implementation.
Line energies are not computed inside the Python loop anymore,
achieving potentially higher performance.
Here we try to use Numba to compute the expensive part of the DP
algorithm, but without changing much the code.
It is about three times *slower* than the equivalent NumPy-only code.
Use spline interpolation, which is faster, and einsum.
Einsum is not optimized, as optimized one is slower, even with
einsum_path.
We try a vectorization over columns, which is faster than over cells
and consumes less memory (and is also faster) than computing all line
energies at once.

This is still 8 times slower than the reference implementation.
The fdasrsf library is no longer a mandatory dependency, but can still
be used to achieve better performance.
@codecov
Copy link

codecov bot commented Jun 22, 2025

Codecov Report

Attention: Patch coverage is 89.04110% with 16 lines in your changes missing coverage. Please review.

Project coverage is 87.03%. Comparing base (e44d8e5) to head (1f62e9f).
Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
skfda/_utils/_utils.py 8.33% 11 Missing ⚠️
skfda/_utils/_warping.py 95.68% 5 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #700      +/-   ##
===========================================
- Coverage    87.04%   87.03%   -0.01%     
===========================================
  Files          199      199              
  Lines        14639    14754     +115     
===========================================
+ Hits         12742    12841      +99     
- Misses        1897     1913      +16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@vnmabus vnmabus marked this pull request as draft June 22, 2025 18:29
vnmabus added 2 commits July 6, 2025 19:42
There was a problem with the accuracy of the line integrals in the DP
algorithm: the times after the warping where the curve change slope are
not guaranteed to correspond with the original ones. Thus, if the
warping compresses the time, the integral could not take into account
many details of the warped function. This was specially noticeable with
non-smooth curves, such as in the Berkely Growth dataset.

As a temporary solution, we increase the number of points used in the
discretization of the curves, by a factor of `dim_grim` (which roughly
corresponfs to the maximum slope). This improves accuracy, but makes
the algorithm slower again.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants