-
Notifications
You must be signed in to change notification settings - Fork 56
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
Implement translate_diff
and inv_diff
for all groups (#679)
#683
Implement translate_diff
and inv_diff
for all groups (#679)
#683
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #683 +/- ##
==========================================
- Coverage 99.58% 99.40% -0.18%
==========================================
Files 114 114
Lines 11244 11320 +76
==========================================
+ Hits 11197 11253 +56
- Misses 47 67 +20 ☔ View full report in Codecov by Sentry. |
what remains to be fixed is if it is wrapped in a `MetricManifold`, or a `ConnectionManifold`, for instance. In that case, the wrong `translate_diff` methods are called.
The PR is mostly implemented although it doesn't pass all the tests. Two problems essentially remain, which I'm not sure how I can fix:
|
Hi, I just saw that the format check failed. If you install
to format the code according to our rules. Actually the Formatter check does nothing else than that and checks whether the run changed the code (and if it changed on CI, it complains). |
The other test that is currently not passed is the one that checked, that every PR changes the |
I can add the missing erroring method (task 5), but I leave the remaining tasks to you (explained in more details above), since I'm not really sure how to proceed. |
That is one reason why I asked you to start working on this, only when working on this, one notices the remaining gaps in the ideas. I personally usually try to find some time nearly every day to work on these packages here, but for the next few weeks, also called semester end time, this will not be possible from my side, due to too many other duties. |
I’d be happy to finish this myself if you give me pointers as to how to proceed, that’s all I’m asking. |
Thank you for this work, I will try to help finish this. I need to clarify a couple of things first. If I understand correctly, adjoint_action for the left action is differential of
I will fix that myself. |
Thank you, that's much appreciated!
Yes, exactly. Let's fix
Excellent point, I made a mistake there. It would only work if all the group use the left-invariant storage, which shouldn't be assume indeed.
Thanks a lot! |
I've tried to rectify that in 6f57baf. However, the fact that the tests didn't catch that indicates that all the tests for product/power manifolds never involve groups with no left-invariant storage, so it could be an idea to add such tests? |
Unless I am mistaken, |
just to aim for the same precision as you do – software wise we try to split for some time, to have first manifolds (e.g. power manifold and product manifold) and have the Lie part as an add-on (not yet 100% consistent, since some time all new stuff is, cf. rotations and their split from SO(n)). So with that in mind, please implement |
Yes, I meant "product/power group", as For the record, before this PR, |
Sure, sometimes we (a) might not have implemented existing methods for a new manifold directly or (b) when implementing a new method we might not have taken the whole ecosystem under revision; both cases might espcially happen, when a method is still new and needs more experience or an “external contributor“ started them. |
Thanks for clarification, I should have some time tomorrow to work on this PR. |
I've fixed |
HI @olivierverdier, I think in the long run it would be really great to move the Lie group parts to a dedicated |
No, I don't have plans to work on this. The main issue is that some of the groups store tangent vectors differently than others (I think it is My personal solution: I'm running my own version of |
That is interesting to know. I think the reason here might be that until now we often inherited the representation from the manifold – which for some manifolds might not make sense, you are right. I think switching to your variant might also be a good idea, with the small caveat, that this would be breaking. |
If you do not plan to propose a breaking change here, we should maybe see how we can adapt this PR (maybe @mateuszbaran you can take a look)? And we should close this PR. |
- at Identity - remove some unused adjoint_action! implementations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your thorough contribution – much appreciated.
I looked through the code, and I added a few small questions.
besides that it would maybe be great to document the left-right-action thing on group.md
a bit more so an only midly-Lie-group-experienced person like me has a chance to read up on the detail fixed here?
If that would be possible that'd be great.
I agree. I'll try to do that. |
The implementation is still not optimal
Done. Let me know if it is understandable. |
I'm going to merge this PR into #732 next week and then make necessary adaptations there. Thank you again for this contribution 👍 |
By the way, I've already merged this PR into #732 and I will polish it there. |
@@ -1121,6 +1200,35 @@ end | |||
direction_and_side(::GroupExponentialRetraction{D}) where {D} = D() | |||
direction_and_side(::GroupLogarithmicInverseRetraction{D}) where {D} = D() | |||
|
|||
function log(::TraitList{<:IsGroupManifold}, G::AbstractDecoratorManifold, p, q) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my PR I've restricted these log
and exp
methods to semidirect product groups with with left-invariant tangent vector representation. On many groups we have optimized implementation on the manifold so I'd prefer to have that to be picked up first before this relatively generic fallback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The solution here is to call the exponential/logarithms defined in groups/connections.jl
. It's the only acceptable exp
and log
on a group manifold. This way, it will work for all groups, regardless of the tangent vector representation. Should I fix this in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know your solution is correct, this is mostly about performance (and a bit about consistency, see the next paragraph). Substantial amount of work has been put to make practically relevant calls fast but unfortunately it's not gathered in an easy to run benchmark suite, so verifying what could have been slowed down and fixing issues would take me hours. So, unless you know of a case where my solution gives a wrong result for an existing group, I'd prefer to keep it like that for now.
Additionally, considering your implementation here makes me rethink our entire group -> manifold pass-through and it's not really something I'd like to do in the near future. If we don't pass exp and log to the manifold, why do we pass vector transports, inner product, retractions, inverse retractions, Riemann tensor, affine connection and so on? Maybe the current solution is not ideal but reworking it would take a very long time and I just don't see enough benefits.
Should I fix this in this PR?
Since I've already merged your branch, it would be easier for me if you made any further fixes on top of the branch from #732 .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vector transport and retractions (and their inverses) are still valid, at least after turning back to tangent vectors in tangent spaces (not 100% sure about Lie algebra things); but it might be beneficial to maybe not pass through exp/log. But I agree that that is something that has to be considered carefully and in the near future I do not have the capacity for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your feedback and explanations! I hope I did not completely misunderstand.
-
Before my PR, the
exp
that was used was not necessary the group exponential (the one ingroups/connections.jl
). For instance, for semidirect products, the exponential of the underlying product manifold was used, which was wrong, because it was not invariant. My implementation fixed that, but was also flawed since it assumed left invariant representation. This is easily fixed as I mentioned above. I'd be happy to do that. -
I'm not sure I understand the implications of what you call the "pass through" here... I'd be happy to be enlightened.
As far as speed is concerned,exp
is always an expensive operation, and I doubt that the overhead of function calls makes any difference. Am I wrong to assume that? -
The only optimized
exp
that I can find in the code is that ofGeneralLinear
. It comes from a choice of left invariant metric, and I'm pretty sure it is not the same as the invariant exponential ingroups/connections.jl
. (So that optimized exponential is not invariant, unless I am mistaken) Have I missed any other optimizedexp
implementation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think exp_inv
and log_inv
would also be good ideas – they would be a bit more specific than wrapping the manifold in a metric (as I proposed in my last comment) and dispatch with exp
on that. I would be fine with both. Maybe the wrapping idea avoids introducing (yet) another function name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get it now (I think): you want exp
to be defined from a metric connection.
If exp
is defined from a nonmetric connection, you are quite sure that something is going to break (because Lie groups are built on top of metric manifolds).
We could add a keyword argument to
LIeGroup
that says: I want to have the Olivier-approach (name to be found still) Then the manifold that is passed would be wrapped in a MetricManifold with the corresponding metric (the one that is the best one in Oliviers sense) and on that dispatch the default from Olivier would work.
Yes, that would be nice, but it may not be possible, since the invariant connection is not necessarily metric (example: GL, semidirect products).
It isn't entirely accurate; the connection is currently arbitrary but I'm open to changing that, just in a consistent manner.
For a metric connection, there is no consistent solutions, your solution is as good as any other. If you agree with (possibly) nonmetric connections, the invariant one is the only consistent choice across all Lie groups.
You made an incorrect assumption about how Manifolds.jl operates and refuse to adjust your expectations despite my detailed explanations.
I guess I did. Sorry for that.
Whenever I was talking about changing the logic, I meant
exp
not corresponding to the connection chosen for a group. This is the fundamental logic ofexp
. If you don't like it, don't useexp
. This is one part where I see no point in changing anything about Manifolds.jl:exp
must come from a consistent choice of connection. We can change which connection it is but invariance is not a requirement forexp
.
You mean a metric connection. Tu sum it up, you prefer a metric noninvariant connection over an invariant nonmetric connection.
This is our disagreement in a nutshell.
Maybe a good way to resolve this disagreement would be to introduce
exp_inv
andlog_inv
(invariant exp and invariant log) which would be implemented in the exact way you described?
Yes, that would be very nice. I think those two functions deserve to be defined somewhere.
- Do you want to convince us that we are stupid? I feel your tone if often quite agressive
It's just a misunderstanding, a disagreement. I like to understand things. I didn't and it's my fault, I'm slow, it makes me sound aggressive. But I think I get it now. Nobody is stupid here, or maybe we're all stupid in the face of maths.
I would really recommend to start Liegroups.jl and “do Lie Groups right” following your arguments and use Manifolds.jl as a kind of backend (for example for point checks or such).
I am even on board helping with that a bit, setting everything up here in JuliaManifolds, CI / docs / ... / review PRs.
I really appreciate that. I kind of already started actually. I'll let you know how it goes.
Tell me if we finally understand each other (i.e.: you only want exp
defined from a metric connections, otherwise you know something will break). If we do, we can resolve this conversation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am fine with us all being stupid ;)
Sorry your tone (and repetition as it came across to me) was getting to me as agressive – thanks for clarifying that this was not meant like that.
My main problem until now was, that to me this thread slowly read like we are repeating arguments again and again.
But if you are fine with the exp_inv
/lie_inv
approach, that is fine with me as well. And yes, I think we by now understand each other, what we want from exp and why that is different fro yours.
For the LieGroups.jl
idea; I think a nice thing would also be that we do not “overcrowd” Manifolds.jl
but modularise features a bit. If you want and have done some work on that, as I said, I am very happy to help with all technical details in setting that up; I would prefer that in JuliaManifolds/ – just to not have a package in a persons namespace – but you would be admin of that package as well of course.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get it now (I think): you want
exp
to be defined from a metric connection.
Yes, we chose the connections for GL and SL because we prefer the defaults to be metric non-invariant connections over non-metric invariant connections. Not all exp
methods come from a metric connection but we generally prefer metric connections because they give more rich structure required by certain optimization or statistical algorithms; moreover, not all manifolds are Lie groups.
You mean a metric connection. Tu sum it up, you prefer a metric noninvariant connection over an invariant nonmetric connection.
This is our disagreement in a nutshell.
Yes, that's correct.
Yes, that would be very nice. I think those two functions deserve to be defined somewhere.
OK, great, then I will add them in my PR and mention in the new tutorial.
- Do you want to convince us that we are stupid? I feel your tone if often quite agressive
It's just a misunderstanding, a disagreement. I like to understand things. I didn't and it's my fault, I'm slow, it makes me sound aggressive. But I think I get it now. Nobody is stupid here, or maybe we're all stupid in the face of maths.
For me developing this library is a great learning opportunity. I'm not a mathematician, and primarily see various branches of differential geometry and Lie groups as a nice language for generalizing classical numerical algorithms. I'm sometimes wrong, but when someone shows me why I'm wrong I can learn something new. There are definitely dozens of people who would do much better job developing JuliaManifolds but they are too busy with more important stuff.
I'm happy when people find JuliaManifolds useful and I generally consider any suggestions regarding interface and functionality of libraries. However, it's impossible to satisfy everyone and we have to set some priorities.
I generally don't mind the tone of messages I get about JuliaManifolds, either yours and from other people. I know it's sometimes a real hassle to express in a positive way, even more so if someone is not a native speaker.
Tell me if we finally understand each other (i.e.: you only want
exp
defined from a metric connections, otherwise you know something will break). If we do, we can resolve this conversation.
Yes, we prefer metric connections if they are available; I think we've managed to resolve the misunderstanding here finally 🙂 .
For the
LieGroups.jl
idea; I think a nice thing would also be that we do not “overcrowd”Manifolds.jl
but modularise features a bit. If you want and have done some work on that, as I said, I am very happy to help with all technical details in setting that up; I would prefer that in JuliaManifolds/ – just to not have a package in a persons namespace – but you would be admin of that package as well of course.
Not-so-fun fact: https://github.com/yuehhua/LieGroups.jl already exists, is registered and looks abandoned. I think it would be fine to develop Lie groups in a separate package but currently we have a bunch of functionality here and maybe some part of it should be moved there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I did not see that package, well, if ours gets a bit more serious we could reach out to hopefully take over the name, if that is abandoned. It also seems to not cover many (only one?) Lie group.
I realised I forgot to redefine inverse_translate_diff!(G, Y, ::Any, ::Any, X, ::LeftForwardAction,) = copyto!(G, Y, X)
inverse_translate_diff!(G, Y, ::Any, ::Any, X, ::RightForwardAction,) = copyto!(G, Y, X)
inverse_translate_diff!(G, Y, p, ::Any, X, ::LeftBackwardAction,) = adjoint_action!(G, Y, p, X, RIghtAction())
inverse_translate_diff!(G, Y, p, ::Any, X, ::RightBackwardAction,) = adjoint_action!(G, Y, p, X, LeftAction()) The current definition is not wrong, and it works for all representations, but it is very inefficient, as it potentially inverts a matrix three times instead of once, or once instead of zero. This change does not have to occur within the scope of this PR, it can be done later, maybe in a separate issue. |
We coudls surely still ad it to the 0.10 PR that is still open? |
Thanks, I will add that to the 0.10 PR. |
Uh, it seems to cause lots of ambiguities, so maybe let's resolve that in a new PR since it not breaking. Anyway, here is the adapted code: function inverse_translate_diff!(
::TraitList{<:IsGroupManifold{<:AbstractGroupOperation,LeftInvariantRepresentation}},
G::AbstractDecoratorManifold,
Y,
::Any,
::Any,
X,
::LeftForwardAction,
)
return copyto!(G, Y, X)
end
function inverse_translate_diff!(
::TraitList{<:IsGroupManifold{<:AbstractGroupOperation,LeftInvariantRepresentation}},
G::AbstractDecoratorManifold,
Y,
::Any,
::Any,
X,
::RightForwardAction,
)
return copyto!(G, Y, X)
end
function inverse_translate_diff!(
::TraitList{<:IsGroupManifold{<:AbstractGroupOperation,LeftInvariantRepresentation}},
G::AbstractDecoratorManifold,
Y,
p,
::Any,
X,
::LeftBackwardAction,
)
return adjoint_action!(G, Y, p, X, RightAction())
end
function inverse_translate_diff!(
::TraitList{<:IsGroupManifold{<:AbstractGroupOperation,LeftInvariantRepresentation}},
G::AbstractDecoratorManifold,
Y,
p,
::Any,
X,
::RightBackwardAction,
)
return adjoint_action!(G, Y, p, X, LeftAction())
end |
I've merged #732 so this PR is already merged indirectly into master. |
The main work of implementing
translate_diff
for all groups is done.The main method that has to be implemented on any given group is
adjoint_action!
, the rest is done automatically.translate_diff
byadjoint_action
inv_diff
as wellRealCircleGroup
SpecialEuclidean
Add the extra erroring methods for(no longer necessary)SemiDirectProductGroup
SpecialEuclidean
cases (for instance,ConnectionManifold(SpecialEuclidean(2), CartanSchoutenMinus())
)Implement(no longer necessary)inv_diff
for Product/PowermanifoldsgroupsAdd tests with a product/power(no longer necessary)manifoldgroups containing aSpecialEuclidean
orCircleGroup
, two groups which do not use the left-invariant storage of tangent vectorsadjoint_action
forSpecialEuclidean
SpecialEuclidean
exp
andlog
for Lie group based onexp_lie
andlog_lie