Adjust injectivity radii for (inverse) retractions on the Sphere (#900) - #915
Adjust injectivity radii for (inverse) retractions on the Sphere (#900)#915sblelong wants to merge 12 commits into
Conversation
…rojectionInverseRetraction on the Sphere
…ractSphere (external ref to `StabilizedInverseRetraction` is pending typo fix in ManifoldsBase)
kellertuer
left a comment
There was a problem hiding this comment.
Thanks for the start. Here are some first preliminary comments.
The test failure on CI does seem more related too SciML destroying something, so for comments on that we have to wait for that to work again (I wrote on their channel on slack)
| end | ||
|
|
||
| _doc_injectivity_radius_sphere = raw""" | ||
| injectivity_radius(M::AbstractSphere[, p, ::ExponentialRetraction]) |
There was a problem hiding this comment.
No. We can not do this.
If you replace ExponentialRetraction here with the Stabilized one, the function is now undefined for ExcponentialRetraction. Anyone relying on that because they use it (it is the standard even!) has their code breaking.
One thing we should always avoid is breaking other peoples code. Always under all circumstances. In 6 years (since we started 2019) we had 10 reasons to do so and we did also those only very carefully. So please do not delete the old variant.
You can for sure add a copy that does this for the stabilised one but I would even argue the stablized one just has a numerical check around so it could even just call infectivity radius on its inner retraction.
|
|
||
| Return the injectivity radius for the [`ProjectionRetraction`](@extref `ManifoldsBase.ProjectionRetraction`) on the | ||
| [`AbstractSphere`](@ref), which is globally ``\frac{π}{2}``. | ||
| [`AbstractSphere`](@ref), which is globally ``\infty``. |
There was a problem hiding this comment.
If we are here we should document this much more precise, what is injective here, we had a long discussion so lets also be precise here.
| function injectivity_radius(M::AbstractSphere, p, m::AbstractRetractionMethod) | ||
| return _injectivity_radius(M, p, m) | ||
| end | ||
| _injectivity_radius(::AbstractSphere, ::ExponentialRetraction) = π |
There was a problem hiding this comment.
Removing this definition here is what is actually breaking. Let's not do that, but as mentioned define the stabilised one to return the one of the retraction it stabilises .
There was a problem hiding this comment.
This does make much more sense. I will keep it Manifolds.jl so we can run tests before moving it to ManifoldsBase.jl where stabilized retractions are defined.
There was a problem hiding this comment.
That is our usual path. We introduce new features here in Manifolds.jl and once we notice they are good – well-designed and tested “in the real world”, we move them to ManifoldsBase
| end | ||
|
|
||
| function _injectivity_radius(M::AbstractSphere, m::LogarithmicInverseRetraction) | ||
| return injectivity_radius(M, StabilizedRetraction()) |
There was a problem hiding this comment.
No!
(a) Log is the mathematically most important thing, so that one should have the number it returns defined specifically
(b) the stabilised one is just a numerical thing
(c) why are you passing from an inverse retraction to a retraction? That looks at least misleading.
There was a problem hiding this comment.
(c) I thought this was the right way to implement your suggestion in this message: the injectivity radius for log calls the one for exp. But I agree this is misleading, I will change that.
| bijectivity_radius(::AbstractSphere, p, ::Union{AbstractRetractionMethod, AbstractInverseRetractionMethod}) | ||
|
|
||
| function bijectivity_radius(M::AbstractSphere, m::Union{AbstractRetractionMethod, AbstractInverseRetractionMethod}) | ||
| if m ∈ (StabilizedRetraction(), StabilizedInverseRetraction()) |
There was a problem hiding this comment.
This looks very strange and will often not yield what you want
(a) you compare instances. Even if someone comes along with an instance of the type, the instance might be a different one
(b) if you want to go for if you should check types, so that typeof(m) === StabilizedRetraction. The usually best way is – as all examples in the code before – to do that with dispatch.
(c) also here anything stabilised (since it is a computer/implementation/stability thing) should “pass” to the inner retraction (or inverse retraction) it stores.
| SoftmaxRetraction, | ||
| SoftmaxInverseRetraction, | ||
| StabilizedRetraction, | ||
| StabilizedInverseRetraction, |
There was a problem hiding this comment.
This is not defined in ManifoldsBase? How can you import it from there then?
| :InvalidVectors => [p], | ||
| :NormalVectors => [V], | ||
| :Covectors => [ξ], | ||
| :RetractionMethods => [ExponentialRetraction(), ProjectionRetraction()], |
There was a problem hiding this comment.
Sane as before – no. The sphere should absolutely be tested on the ExponentialRetraction. Stabilisation is something extra – and exp is still the default. If you want to test it, add it at the end.
|
|
||
| * `injectivity_radius(M, p, m)` and `injectivity_radius(M, m)` where `m` is an `AbstractInverseRetractionMethod` and `M` is a `Sphere` are introduced. | ||
| * `injectivity_radius(M, m)` where `M` is a `Sphere` and `m` is a `LogarithmicInverseRetraction` or a `ProjectionInverseRetraction`. | ||
| * `bijectivity_radius(M, p, m)` and `bijectivity_radius(M, m)` are defined for `Sphere`s. |
There was a problem hiding this comment.
You could also add tests for this?
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #915 +/- ##
===========================================
- Coverage 100.00% 7.97% -92.03%
===========================================
Files 98 98
Lines 9830 9712 -118
===========================================
- Hits 9830 775 -9055
- Misses 0 8937 +8937 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Thank you for this detailed feedback, I'll address all changes! |
|
As a concrete example – I could convince the tests a bit to run and this should never happen. You did not touch Stiefel at all, but something you changed made that fail now. You did change expected numbers in the tests (and whether that is breaking is something we should discuss/conclude in the end) – but nothing else should change – otherwise we have a breaking change. You can also test this locally. Do you know about development mode and |
|
I was indeed negligent with running tests locally: I ran the The error encountered in the CI brings an interesting question though: as soon as an inverse retraction is defined for a manifold, should we expect the injectivity radius for this inverse retraction to be implemented? |
|
No worries, errors are also always a good occasion to learn.
Yes, we made the possible on purpose, since the overall tests run for a while, one can focus on a single one of on does work only on these. You however also introduce a new signature globally!
That is an interesting point that affects the test suite (so not whether something is breaking) – For consistency, I think it would be good if it were implemented for all manifolds we have that now run the new tests, and I think a reasonable start is to set it to the same value as the retraction case – but explicitly to that number and add a doctoring to that implementation as well. The alternative is to make the new tests inactive by default and introduce a boolean keyword – though that might also lead to us “forgetting” to add these functions. But it is less work for sure. |
And that would have been a good reason for me to be more patient and run the tests entirely before opening the PR! One lesson learned. :)
That sounds feasible. I am available and will work on that in the upcoming days, while addressing the other issues raised in this PR. |
Nice, thanks! And no worries, a PR is nearly never a sprint, I always prefer thoroughness and completeness (and less bugs) over speed. |
Hi!
Here's a first attempt to address the issue raised in #900 about injectivity radii for retractions and their inverse.
I tried to follow the unit testing pattern on the sphere but I'm requesting approval before proceeding with tests for the
bijectivity_radius.