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

Implement translate_diff and inv_diff for all groups (#679) #683

Closed
Closed
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1301240
Implement `translate_diff` and `inv_diff` for all groups (#679)
olivierverdier Nov 13, 2023
63e0b6c
implement a general `inv_diff`
olivierverdier Nov 13, 2023
eb7f283
fixing the SpecialEuclidean case (mostly)
olivierverdier Nov 13, 2023
dcf79ee
changelog
olivierverdier Nov 13, 2023
b5748d2
formatting
olivierverdier Nov 13, 2023
6f57baf
translate_diff for product/power groups
olivierverdier Nov 15, 2023
b2a826d
Merge branch 'master' into translate_diff
mateuszbaran Nov 18, 2023
cb30114
fix CircleGroup
mateuszbaran Nov 18, 2023
e42dc91
adjoint_action fallback for all groups
olivierverdier Jun 4, 2024
fe2c5df
translate_diff is always defined from adjoint_action
olivierverdier Jun 4, 2024
f1372a6
semidirect products: remove specific translate_diff implementations
olivierverdier Jun 4, 2024
588bf2c
special_euclidean: implement adjoint action
olivierverdier Jun 4, 2024
28070e1
fix trivial adjoint action for commutative groups
olivierverdier Jun 4, 2024
7762b9b
left invariant storage for special_euclidean
olivierverdier Jun 4, 2024
a53834e
Generic implementation of exp and log for all groups
olivierverdier Jun 4, 2024
533e5f0
special_euclidean: Remove specific log/exp implementations
olivierverdier Jun 4, 2024
72bedb4
special_euclidean: Remove some failing tests
olivierverdier Jun 4, 2024
a161c7c
special_linear: tighter test points
olivierverdier Jun 4, 2024
5e560ee
News update
olivierverdier Jun 4, 2024
5ac062a
Merge remote-tracking branch 'origin/master' into translate_diff
olivierverdier Jun 4, 2024
4e1afd8
Formatting
olivierverdier Jun 4, 2024
2a6933f
Update NEWS
olivierverdier Jun 5, 2024
f1afec9
Merge remote-tracking branch 'origin/master' into translate_diff
olivierverdier Jul 26, 2024
ba2900f
adjoint_action: more tests
olivierverdier Jul 26, 2024
ee8b33b
Format
olivierverdier Jul 26, 2024
df7f69a
Test: more translate_diff tests
olivierverdier Jul 26, 2024
189424b
Test: inv_diff!
olivierverdier Jul 26, 2024
402c49b
Tests: adjoint_action
olivierverdier Jul 26, 2024
5c2c619
Fromat
olivierverdier Jul 26, 2024
b0e8df9
Fixup to 402c49bb
olivierverdier Jul 26, 2024
0b90174
Redundant method
olivierverdier Jul 26, 2024
74ef0d5
Doc: adjoint_action direction
olivierverdier Jul 26, 2024
52bd4cb
Rewrite: avoid inv
olivierverdier Jul 27, 2024
fa4cac7
Doc: move code comments to docstrings
olivierverdier Jul 27, 2024
373a378
Doc: remove allocate TODOs
olivierverdier Jul 27, 2024
b020239
Doc: storage of tangent vectors on Lie groups
olivierverdier Jul 27, 2024
2bb5131
Doc: tangent vector storage -> representation
olivierverdier Jul 27, 2024
8548037
special_linear: remove nonsensical method
olivierverdier Aug 5, 2024
3dfde35
Format
olivierverdier Aug 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [0.9.21] – unreleased

### Changed

* `translate_diff`, `inv_diff` and thus `apply_diff_group`, are available for all the groups
* `adjoint_action` takes a direction argument
* `adjoint_action!` is the necessary method to implement in any given group for the above to work properly
* On groups, `exp` and `log` are based on `exp_lie` and `log_lie` and thus group invariant
* fixed a few typos in the doc string of the SPD fixed determinant description.

## [0.9.20] – 2024-06-17

### Added
Expand Down
50 changes: 50 additions & 0 deletions docs/src/manifolds/group.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,56 @@ Pages = ["groups/GroupManifold.jl"]
Order = [:constant, :type, :function]
```

### Default Storage of Tangent Vectors

In most groups, the storage of a tangent vector
kellertuer marked this conversation as resolved.
Show resolved Hide resolved
``X`` at the point ``p ∈ \mathcal{G}`` is stored
as a vector ``Y ∈ \mathfrak{g}``.
This helps to compute the derivatives of the composition and inverse.

To explain this, let us assume that *the group consists of matrices* (this is always possible).
The storage of a tangent vector
``X`` at the point ``p ∈ \mathcal{G}`` is stored
as the vector ``Y ∈ \mathfrak{g}`` given by
```math
X = pY
```

#### Derivative of the Group Composition on the Left

The derivative of the composition ``pq`` with respect to ``p`` in
the direction ``X``, tangent at ``p`` is given by
```math
Xq = pYq = pq(q^{-1}Yq)
```
We see that with this storage convention, this derivative is just the
adjoint action of ``q^{-1}`` on the vector ``Y``.

#### Derivative of the Group Composition on the Right

For the derivative with respect to ``q`` of the composition ``pq`` at a tangent vector ``X`` at ``q``
stored as ``Y`` with ``X = qY``, we have similarly
```math
pX = pqY
```
With the storage convention above, this derivative is just the identity.

#### Derivative of the Group Inverse

Finally, we look at the derivative of the inverse ``p^{-1}`` at a point ``p`` in a tangent direction ``X``
at ``p`` with ``X = pY``.
The result is a tangent vector at ``p^{-1}`` given by
```math
-p^{-1}Xp^{-1} = - Yp^{-1} = -p^{-1}(p Y p^{-1})
```
With the storage convention above, this derivative is thus ``-pYp^{-1}``, that is, the opposite of the adjoint action of ``p`` on the vector ``Y``.

#### Implication for Creating New Groups

When you create a new group,
defining the adjoint action alone ([`adjoint_action`](@ref))
automatically defines all the relevant derivatives above.

### Generic Operations

For groups based on an addition operation or a group operation, several default implementations are provided.
Expand Down
31 changes: 30 additions & 1 deletion ext/ManifoldsTestExt/tests_group.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,13 @@
test_adjoint_action::Bool=false,
test_inv_diff::Bool=false,
test_adjoint_inv_diff::Bool=false,
diff_convs=[(), (LeftForwardAction(),), (RightBackwardAction(),)],
diff_convs=[
(),
(LeftForwardAction(),),
(RightBackwardAction(),),
(LeftBackwardAction(),),
(RightForwardAction(),),
],
test_log_from_identity::Bool=false,
test_exp_from_identity::Bool=false,
test_vee_hat_from_identity::Bool=false,
Expand Down Expand Up @@ -379,6 +385,12 @@
Test.@testset "test_inv_diff" for side in [LeftSide(), RightSide()]
test_inv_diff_fn(G, g_pts[1], X_pts[1], side)
end # COV_EXCL_LINE
if test_mutating
Y = inv_diff(G, e, Xe_pts[1])
Z = allocate(Y)
inv_diff!(G, Z, e, Xe_pts[1])
Test.@test isapprox(TangentSpace(G, e), Y, Z)

Check warning on line 392 in ext/ManifoldsTestExt/tests_group.jl

View check run for this annotation

Codecov / codecov/patch

ext/ManifoldsTestExt/tests_group.jl#L388-L392

Added lines #L388 - L392 were not covered by tests
end
end
test_adjoint_inv_diff && Test.@testset "Differential of inverse" begin # COV_EXCL_LINE
Test.@test isapprox(adjoint_inv_diff(G, e, Xe_pts[1]), -Xe_pts[1]; atol=atol)
Expand Down Expand Up @@ -534,10 +546,27 @@
adjoint_action(G, g_pts[2], adjoint_action(G, inv(G, g_pts[2]), X)),
X,
)
# right adjoint action
Test.@test isapprox(

Check warning on line 550 in ext/ManifoldsTestExt/tests_group.jl

View check run for this annotation

Codecov / codecov/patch

ext/ManifoldsTestExt/tests_group.jl#L550

Added line #L550 was not covered by tests
G,
e,
adjoint_action(G, g_pts[2], adjoint_action(G, g_pts[2], X, RightAction())),
X,
)
# adjoint action at identity
for conv in [LeftAction(), RightAction()]
isapprox(

Check warning on line 558 in ext/ManifoldsTestExt/tests_group.jl

View check run for this annotation

Codecov / codecov/patch

ext/ManifoldsTestExt/tests_group.jl#L557-L558

Added lines #L557 - L558 were not covered by tests
TangentSpace(G, identity_element(G)),
adjoint_action(G, e, Xe_pts[1], conv),
Xe_pts[1],
)
end

Check warning on line 563 in ext/ManifoldsTestExt/tests_group.jl

View check run for this annotation

Codecov / codecov/patch

ext/ManifoldsTestExt/tests_group.jl#L563

Added line #L563 was not covered by tests
if test_mutating
Z = allocate(X)
adjoint_action!(G, Z, g_pts[2], X)
Test.@test isapprox(G, e, Z, adjoint_action(G, g_pts[2], X))
adjoint_action!(G, Z, g_pts[2], X, RightAction())
Test.@test isapprox(G, e, Z, adjoint_action(G, g_pts[2], X, RightAction()))

Check warning on line 569 in ext/ManifoldsTestExt/tests_group.jl

View check run for this annotation

Codecov / codecov/patch

ext/ManifoldsTestExt/tests_group.jl#L568-L569

Added lines #L568 - L569 were not covered by tests
end

# interaction with Lie bracket
Expand Down
43 changes: 10 additions & 33 deletions src/groups/addition_operation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,16 @@

const AdditionGroupTrait = TraitList{<:IsGroupManifold{AdditionOperation}}

adjoint_action(::AdditionGroupTrait, G::AbstractDecoratorManifold, p, X) = X
adjoint_action(::AdditionGroupTrait, G::AbstractDecoratorManifold, p, X, ::LeftAction) = X

Check warning on line 25 in src/groups/addition_operation.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/addition_operation.jl#L25

Added line #L25 was not covered by tests

function adjoint_action!(::AdditionGroupTrait, G::AbstractDecoratorManifold, Y, p, X)
function adjoint_action!(

Check warning on line 27 in src/groups/addition_operation.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/addition_operation.jl#L27

Added line #L27 was not covered by tests
::AdditionGroupTrait,
G::AbstractDecoratorManifold,
Y,
p,
X,
::LeftAction,
)
return copyto!(G, Y, p, X)
end

Expand Down Expand Up @@ -74,14 +81,7 @@

Compute the value of differential of additive matrix inversion ``p ↦ -p`` at ``X``, i.e. ``-X``.
"""
function inv_diff(::AdditionGroupTrait, G::AbstractDecoratorManifold, p, X)
return -X
end
function inv_diff!(::AdditionGroupTrait, G::AbstractDecoratorManifold, Y, p, X)
Y .= X
Y .*= -1
return Y
end
inv_diff(::AdditionGroupTrait, G::AbstractDecoratorManifold, p, X)

function is_identity(
::AdditionGroupTrait,
Expand Down Expand Up @@ -165,26 +165,3 @@
lie_bracket(::AdditionGroupTrait, G::AbstractDecoratorManifold, X, Y) = zero(X)

lie_bracket!(::AdditionGroupTrait, G::AbstractDecoratorManifold, Z, X, Y) = fill!(Z, 0)

function translate_diff(
::AdditionGroupTrait,
G::AbstractDecoratorManifold,
p,
q,
X,
::ActionDirectionAndSide,
)
return X
end

function translate_diff!(
::AdditionGroupTrait,
G::AbstractDecoratorManifold,
Y,
p,
q,
X,
::ActionDirectionAndSide,
)
return copyto!(G, Y, p, X)
end
79 changes: 64 additions & 15 deletions src/groups/circle_group.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@

Base.show(io::IO, ::CircleGroup) = print(io, "CircleGroup()")

adjoint_action(::CircleGroup, p, X) = X
adjoint_action(::CircleGroup, p, X, ::LeftAction) = X
kellertuer marked this conversation as resolved.
Show resolved Hide resolved
adjoint_action(::CircleGroup, ::Identity, X, ::LeftAction) = X
adjoint_action(::CircleGroup, p, X, ::RightAction) = X
adjoint_action(::CircleGroup, ::Identity, X, ::RightAction) = X

Check warning on line 30 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L27-L30

Added lines #L27 - L30 were not covered by tests

adjoint_action!(::CircleGroup, Y, p, X) = copyto!(Y, X)
adjoint_action!(::CircleGroup, Y, p, X, ::LeftAction) = copyto!(Y, X)
adjoint_action!(::CircleGroup, Y, p, X, ::RightAction) = copyto!(Y, X)

Check warning on line 33 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L32-L33

Added lines #L32 - L33 were not covered by tests

function compose(
::MultiplicationGroupTrait,
Expand Down Expand Up @@ -77,21 +81,37 @@

lie_bracket!(::CircleGroup, Z, X, Y) = fill!(Z, 0)

function translate_diff(::GT, p, q, X, ::ActionDirectionAndSide) where {GT<:CircleGroup}
return map(*, p, X)
end
function translate_diff(
::CircleGroup,
::Identity{MultiplicationOperation},
q,
X,
::ActionDirectionAndSide,
)
return X
translate_diff(::CircleGroup, p, q, X) = map(*, p, X)
translate_diff(::CircleGroup, p::Identity{MultiplicationOperation}, q, X) = X

Check warning on line 85 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L84-L85

Added lines #L84 - L85 were not covered by tests
for AD in [LeftForwardAction, RightForwardAction, LeftBackwardAction, RightBackwardAction]
@eval begin
function translate_diff(G::CircleGroup, p, q, X, ::$AD)
return translate_diff(G, p, q, X)

Check warning on line 89 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L88-L89

Added lines #L88 - L89 were not covered by tests
end
function translate_diff(

Check warning on line 91 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L91

Added line #L91 was not covered by tests
::CircleGroup,
::Identity{MultiplicationOperation},
q,
X,
::$AD,
)
return X

Check warning on line 98 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L98

Added line #L98 was not covered by tests
end
end
end

function translate_diff!(G::CircleGroup, Y, p, q, X, conv::ActionDirectionAndSide)
return copyto!(Y, translate_diff(G, p, q, X, conv))
_common_translate_diff!(G, Y, p, q, X, conv) = copyto!(Y, translate_diff(G, p, q, X, conv))
function translate_diff!(G::CircleGroup, Y, p, q, X, conv::LeftForwardAction)
return _common_translate_diff!(G, Y, p, q, X, conv)

Check warning on line 105 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L103-L105

Added lines #L103 - L105 were not covered by tests
end
function translate_diff!(G::CircleGroup, Y, p, q, X, conv::RightForwardAction)
return _common_translate_diff!(G, Y, p, q, X, conv)

Check warning on line 108 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L107-L108

Added lines #L107 - L108 were not covered by tests
end
function translate_diff!(G::CircleGroup, Y, p, q, X, conv::LeftBackwardAction)
return _common_translate_diff!(G, Y, p, q, X, conv)

Check warning on line 111 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L110-L111

Added lines #L110 - L111 were not covered by tests
end
function translate_diff!(G::CircleGroup, Y, p, q, X, conv::RightBackwardAction)
return _common_translate_diff!(G, Y, p, q, X, conv)

Check warning on line 114 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L113-L114

Added lines #L113 - L114 were not covered by tests
end

function exp_lie(::CircleGroup, X)
Expand Down Expand Up @@ -143,6 +163,17 @@
end
end

adjoint_action(::RealCircleGroup, p, X, ::LeftAction) = X
adjoint_action(::RealCircleGroup, p, X, ::RightAction) = X
adjoint_action(::RealCircleGroup, ::Identity, X, ::LeftAction) = X
adjoint_action(::RealCircleGroup, ::Identity, X, ::RightAction) = X

Check warning on line 169 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L166-L169

Added lines #L166 - L169 were not covered by tests

for AD in [LeftAction, RightAction]
@eval begin
adjoint_action!(::RealCircleGroup, Y, p, X, ::$AD) = copyto!(Y, X)

Check warning on line 173 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L173

Added line #L173 was not covered by tests
end
end

Base.show(io::IO, ::RealCircleGroup) = print(io, "RealCircleGroup()")

is_default_metric(::RealCircleGroup, ::EuclideanMetric) = true
Expand Down Expand Up @@ -198,3 +229,21 @@
end

exp_lie!(::RealCircleGroup, q, X) = (q .= sym_rem(X))

translate_diff(::RealCircleGroup, p, q, X) = X

Check warning on line 233 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L233

Added line #L233 was not covered by tests
for AD in [LeftForwardAction, RightForwardAction, LeftBackwardAction, RightBackwardAction]
@eval begin
function translate_diff(::RealCircleGroup, p, q, X, ::$AD)
return X

Check warning on line 237 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L236-L237

Added lines #L236 - L237 were not covered by tests
end
function translate_diff(

Check warning on line 239 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L239

Added line #L239 was not covered by tests
::RealCircleGroup,
::Identity{AdditionOperation},
q,
X,
::$AD,
)
return X

Check warning on line 246 in src/groups/circle_group.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/circle_group.jl#L246

Added line #L246 was not covered by tests
end
end
end
9 changes: 3 additions & 6 deletions src/groups/general_linear.jl
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,6 @@
return print(io, "GeneralLinear($n, $(𝔽); parameter=:field)")
end

translate_diff(::GeneralLinear, p, q, X, ::LeftForwardAction) = X
translate_diff(::GeneralLinear, p, q, X, ::RightBackwardAction) = p \ X * p

function translate_diff!(G::GeneralLinear, Y, p, q, X, conv::ActionDirectionAndSide)
return copyto!(Y, translate_diff(G, p, q, X, conv))
end
# note: this implementation is not optimal
adjoint_action!(::GeneralLinear, Y, p, X, ::LeftAction) = copyto!(Y, p * X * inv(p))

Check warning on line 279 in src/groups/general_linear.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/general_linear.jl#L279

Added line #L279 was not covered by tests
adjoint_action!(::GeneralLinear, Y, p, X, ::RightAction) = copyto!(Y, p \ X * p)
44 changes: 9 additions & 35 deletions src/groups/general_unitary_groups.jl
Original file line number Diff line number Diff line change
Expand Up @@ -287,46 +287,20 @@
return manifold_volume(M.manifold)
end

function translate_diff!(
G::GeneralUnitaryMultiplicationGroup,
Y,
p,
q,
X,
::LeftForwardAction,
)
return copyto!(G, Y, X)
function Random.rand!(G::GeneralUnitaryMultiplicationGroup, pX; kwargs...)
rand!(G.manifold, pX; kwargs...)
return pX

Check warning on line 292 in src/groups/general_unitary_groups.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/general_unitary_groups.jl#L290-L292

Added lines #L290 - L292 were not covered by tests
end
function translate_diff!(
G::GeneralUnitaryMultiplicationGroup,
Y,
p,
q,
X,
::RightForwardAction,
)
copyto!(G, Y, X)
return Y
function Random.rand!(rng::AbstractRNG, G::GeneralUnitaryMultiplicationGroup, pX; kwargs...)
rand!(rng, G.manifold, pX; kwargs...)
return pX

Check warning on line 296 in src/groups/general_unitary_groups.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/general_unitary_groups.jl#L294-L296

Added lines #L294 - L296 were not covered by tests
end
function translate_diff!(
G::GeneralUnitaryMultiplicationGroup,
Y,
p,
q,
X,
::LeftBackwardAction,
)

function adjoint_action!(G::GeneralUnitaryMultiplicationGroup, Y, p, X, ::LeftAction)

Check warning on line 299 in src/groups/general_unitary_groups.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/general_unitary_groups.jl#L299

Added line #L299 was not covered by tests
copyto!(G, Y, p * X * inv(G, p))
return Y
end
function translate_diff!(
G::GeneralUnitaryMultiplicationGroup,
Y,
p,
q,
X,
::RightBackwardAction,
)
function adjoint_action!(G::GeneralUnitaryMultiplicationGroup, Y, p, X, ::RightAction)

Check warning on line 303 in src/groups/general_unitary_groups.jl

View check run for this annotation

Codecov / codecov/patch

src/groups/general_unitary_groups.jl#L303

Added line #L303 was not covered by tests
return copyto!(G, Y, inv(G, p) * X * p)
end

Expand Down
Loading
Loading