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 Diffeo abstraction #1904

Merged
merged 21 commits into from
Nov 29, 2023
Merged

Add Diffeo abstraction #1904

merged 21 commits into from
Nov 29, 2023

Conversation

luisfpereira
Copy link
Collaborator

Following the ideas started in #1863, this PR brings in the notion of Diffeo.

Additionally, it refactors discrete_curves (done with @alebrigant). This happens together, because this module is heavily dependent on the Diffeo abstraction: SRVTransform, and FTransform.

Design of Diffeo

(This part may interest you @ymontmarin.)

Most of it results from what was already implemented in PullbackDiffeoMetric.

In particular, diffeomorphism, and inverse_diffeomorphism keep the same signature, while tangent_diffeomorphism, and inverse_tangent_diffeomorphism have an additional image_point or base_point due to reasons specified in the docstrings of the abstract class.

We've also decided to split the autodiff part in a new class called AutodiffDiffeo. While Diffeo is purely abstract, AutodiffDiffeo (a child of Diffeo) brings in implementations for tangent_diffeomorphism and inverse_tangent_diffeomorphism given implementations of diffeomorphism and inverse_diffeomorphism through automatic differentiation. I think this split makes sense both from a conceptual and coding point of view, as AutodiffDiffeo defines several methods that are required almost exclusively for the automatic differentiation (e.g. jacobian_diffeomorphism) and are usually not considered outside of this scope. (This also simplifies implementations as the ones mentioned below)

Moving these methods out of PullbackDiffeoMetric to a new abstraction (Diffeo) also allows to bring in new implementations that build on top of the new class. In particular, ReversedDiffeo just converts a Diffeo from $M \to N$ in a diffeo from $N \to M$. More interestingly, ComposedDiffeo takes several diffeos (e.g. $M \to N \to P$) and creates a (composed) diffeo between the first and last manifold (e.g. $M \to P$). This may be useful to avoid creating unnecessary intermediate representations, while still keeping the possibility of using such representations without code duplication if wanted.

Affected modules

While several modules were affected by this change, the main changes were done in spd_matrices/hpd_matrices, and discrete_curves.

spd_matrices/hpd_matrices

(This part may interest you @YannCabanes, as hpd_matrices has changed similarly to spd_matrices.)

We've created the diffeomorphisms LogDiffeo, PowerDiffeo, and CholeskyMap. This hugely simplifies SPDMatrices API. I've also transformed some methods into functions due to wide use (logmh, expm, powermh). The intention is to move them to the backend afterwards.

Due to the new LogDiffeo, we've implemented SPDLogEuclideanMetricas a PullbackDiffeoMetric.

Due to the new PowerDiffeo, we've removed power_affine, and power_euclidean from SPDAffineMetric, and SPDEuclideanMetric, respectively, as this metric can be obtained with SPDPowerMetric (which takes advantage both from PullbackDiffeoMetric and ScalarProductMetric) with much simpler (and complete) code, without any performance degradation. For example, SPDEuclideanMetric.parallel_transport would raise a NotImplementedError for power_euclidean != 1, whereas now it works properly.

discrete_curves

(This part may interest you @MMalikT)

(with @alebrigant )

We've decided, for the moment, to focus only on DiscreteCurvesStartingAtOrigin, which are discrete curves modulo translation.

The method projection takes a DiscreteCurve and removes translation and origin (@alebrigant, we may need to iterate on this, but for now, not having the origin in the point representation is much more convenient in order to take advantage of existing implementations, such as NFoldManifold). This method is widely used in the already existing notebooks to keep the previous behavior. Within the notebooks we've added back the origin before plotting.

We've implemented SRVTransform and FTransform. The corresponding pullback metrics (ElasticTranslationMetric and SRVTranslationMetric) simply inherit from PullbackDiffeoMetric without overriding any code.

For the quotienting by reparameterizations, we've divide the algorithms we have to align curves into two classes (IterativeHorizontalGeodesic, and DynamicProgrammingAligner). This follows an idea we were already pursuing in graph_space and deeply simplifies the implementation of SRVTranslationReparametrizationBundle (we simply need to pass an aligner - or accept the default one) and SRVTranslationReparametrizationQuotientMetric (the implementation is independent of the algorithm). Both algorithms are still fragile and their implementations need to be improved.

Several auxiliar methods were added to (conceptually) simplify the implementations, such as forward_difference, centered_difference, and so on. A next step is to extend this notions to ambient manifolds other than the Euclidean space.

We've fully removed ClosedDiscreteCurves because the implementation is not consistent with the changes. We need to revisit this afterwards.

Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

Copy link

codecov bot commented Nov 21, 2023

Codecov Report

Attention: 45 lines in your changes are missing coverage. Please review.

Comparison is base (6512703) 91.00% compared to head (6ee1f91) 91.47%.

Files Patch % Lines
geomstats/geometry/diffeo.py 66.67% 28 Missing ⚠️
geomstats/geometry/hermitian_matrices.py 84.85% 5 Missing ⚠️
geomstats/geometry/spd_matrices.py 98.14% 3 Missing ⚠️
geomstats/geometry/nfold_manifold.py 77.78% 2 Missing ⚠️
geomstats/geometry/connection.py 93.75% 1 Missing ⚠️
geomstats/geometry/fiber_bundle.py 66.67% 1 Missing ⚠️
geomstats/geometry/landmarks.py 66.67% 1 Missing ⚠️
geomstats/geometry/pullback_metric.py 98.12% 1 Missing ⚠️
geomstats/geometry/quotient_metric.py 95.46% 1 Missing ⚠️
geomstats/test_cases/geometry/fiber_bundle.py 95.24% 1 Missing ⚠️
... and 1 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1904      +/-   ##
==========================================
+ Coverage   91.00%   91.47%   +0.48%     
==========================================
  Files         220      222       +2     
  Lines       18868    18983     +115     
==========================================
+ Hits        17168    17363     +195     
+ Misses       1700     1620      -80     
Flag Coverage Δ
autograd ?
numpy 90.16% <90.63%> (+0.44%) ⬆️
pytorch 86.93% <92.90%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

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

@ymontmarin
Copy link
Collaborator

@luisfpereira Hi Luis, thank you for letting me know ! I just read the new classes and think is great! It unify the structure of the notions. Also the subclass for autodiff behavior is way more elegant !

Copy link
Collaborator

@alebrigant alebrigant left a comment

Choose a reason for hiding this comment

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

Great work, this makes discrete curves so much cleaner. The way you simplified the code for the fiber bundle structure in particular is very nice. Thanks !! I just put some comments on a few docstrings.

geomstats/geometry/diffeo.py Outdated Show resolved Hide resolved
geomstats/geometry/diffeo.py Outdated Show resolved Hide resolved
geomstats/geometry/diffeo.py Outdated Show resolved Hide resolved
geomstats/geometry/diffeo.py Outdated Show resolved Hide resolved
geomstats/geometry/diffeo.py Outdated Show resolved Hide resolved
geomstats/geometry/diffeo.py Outdated Show resolved Hide resolved
geomstats/geometry/diffeo.py Outdated Show resolved Hide resolved
geomstats/geometry/discrete_curves.py Outdated Show resolved Hide resolved
geomstats/geometry/discrete_curves.py Show resolved Hide resolved
geomstats/geometry/discrete_curves.py Show resolved Hide resolved
Copy link

review-notebook-app bot commented Nov 27, 2023

View / edit / reply to this conversation on ReviewNB

alebrigant commented on 2023-11-27T12:15:38Z
----------------------------------------------------------------

I would remove "(together with translation)" because it sounds like translation is not quotiented out here.


Copy link
Collaborator

@ninamiolane ninamiolane left a comment

Choose a reason for hiding this comment

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

This is fantastic, thank you very much! I've left minor comments.

geomstats/test_cases/geometry/fiber_bundle.py Show resolved Hide resolved
for n_times in [20]:
data.extend([dict(n_points=n_points, n_times=n_times) for n_points in [1]])
return self.generate_tests(data)
class AlignerCmpTestData(TestData):
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is "Cmp"? Is AlignedCmp a class in the codebase? Can you leave a docstring explaining why it deserves to have a spcial TestData?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

"Cmp" stands for comparison. This is a kind of test I've recently added that compares the outputs of two objects that do the same job. e.g. in this case it compares the outputs of the two algorithms we have for alignment.

I've implemented a similar comparison for metrics: if we have two different ways of implementing a given metric, it is very powerful to compare the results both provide as it would be very unlikely two independent ways of doing the same thing give the same results in random data.


space.equip_with_group_action("reparametrizations")
space.equip_with_quotient_structure()
aligner = IterativeHorizontalGeodesic()
Copy link
Collaborator

Choose a reason for hiding this comment

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

NIT: this class' name should probably end with Aligner, to match the logic of line 178.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

tests/tests_geomstats/test_geometry/test_spd_matrices.py Outdated Show resolved Hide resolved
@luisfpereira luisfpereira merged commit 5637fbc into geomstats:main Nov 29, 2023
14 of 15 checks passed
@luisfpereira luisfpereira deleted the new-diffeo branch November 29, 2023 17:57
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.

None yet

4 participants