diff --git a/docs/src/manifolds/group.md b/docs/src/manifolds/group.md index 1fbb247352..4ae63967f9 100644 --- a/docs/src/manifolds/group.md +++ b/docs/src/manifolds/group.md @@ -187,14 +187,14 @@ The following operations are available: * [`apply`](@ref): performs given action of an element of the group on an object of compatible type. * [`apply_diff`](@ref): differential of [`apply`](@ref) with respect to the object it acts upon. -* [`direction`](@ref): tells whether a given action is [`LeftAction`](@ref) or [`RightAction`](@ref). +* [`direction`](@ref): tells whether a given action is [`LeftForwardAction`](@ref), [`RightForwardAction`](@ref), [`LeftBackwardAction`](@ref) or [`RightBackwardAction`](@ref). * [`inverse_apply`](@ref): performs given action of the inverse of an element of the group on an object of compatible type. By default inverts the element and calls [`apply`](@ref) but it may be have a faster implementation for some actions. * [`inverse_apply_diff`](@ref): counterpart of [`apply_diff`](@ref) for [`inverse_apply`](@ref). * [`optimal_alignment`](@ref): determine the element of a group that, when it acts upon a point, produces the element closest to another given point in the metric of the G-manifold. Furthermore, group operation action features the following: -* [`translate`](@ref Main.Manifolds.translate): an operation that performs either left ([`LeftAction`](@ref)) or right ([`RightAction`](@ref)) translation. This is by default performed by calling [`compose`](@ref) with appropriate order of arguments. This function is separated from `compose` mostly to easily represent its differential, [`translate_diff`](@ref). +* [`translate`](@ref Main.Manifolds.translate): an operation that performs either left ([`LeftForwardAction`](@ref)) or right ([`RightBackwardAction`](@ref)) translation, or actions by inverses of elements ([`RightForwardAction`](@ref) and [`LeftBackwardAction`](@ref)). This is by default performed by calling [`compose`](@ref) with appropriate order of arguments. This function is separated from `compose` mostly to easily represent its differential, [`translate_diff`](@ref). * [`translate_diff`](@ref): differential of [`translate`](@ref Main.Manifolds.translate) with respect to the point being translated. * [`adjoint_action`](@ref): adjoint action of a given element of a Lie group on an element of its Lie algebra. * [`lie_bracket`](@ref): Lie bracket of two vectors from a Lie algebra corresponding to a given group. diff --git a/ext/ManifoldsTestExt/tests_group.jl b/ext/ManifoldsTestExt/tests_group.jl index 1c87dc0010..5c833e0445 100644 --- a/ext/ManifoldsTestExt/tests_group.jl +++ b/ext/ManifoldsTestExt/tests_group.jl @@ -12,7 +12,7 @@ using Base: IdentityUnitRange test_invariance = false, test_lie_bracket=false, test_adjoint_action=false, - diff_convs = [(), (LeftAction(),), (RightAction(),)], + diff_convs = [(), (LeftForwardAction(),), (RightBackwardAction(),)], ) Tests general properties of the group `G`, given at least three different points @@ -37,14 +37,14 @@ function test_group( test_invariance=false, test_lie_bracket=false, test_adjoint_action=false, - diff_convs=[(), (LeftAction(),), (RightAction(),)], + diff_convs=[(), (LeftForwardAction(),), (RightBackwardAction(),)], test_log_from_identity=false, test_exp_from_identity=false, test_vee_hat_from_identity=false, ) e = Identity(G) - Test.@testset "Basic group properties" begin + Test.@testset "Basic group properties" begin # COV_EXCL_LINE Test.@testset "Closed" begin for g1 in g_pts, g2 in g_pts g3 = compose(G, g1, g2) @@ -52,7 +52,7 @@ function test_group( end end - Test.@testset "Associative" begin + Test.@testset "Associative" begin # COV_EXCL_LINE g12_3 = compose(G, compose(G, g_pts[1], g_pts[2]), g_pts[3]) g1_23 = compose(G, g_pts[1], compose(G, g_pts[2], g_pts[3])) Test.@test isapprox(G, g12_3, g1_23; atol=atol) @@ -67,7 +67,7 @@ function test_group( end end - Test.@testset "Identity" begin + Test.@testset "Identity" begin # COV_EXCL_LINE Test.@test is_point(G, e) wrong_e = if e === Identity(MultiplicationOperation()) Identity(AdditionOperation()) @@ -109,7 +109,7 @@ function test_group( end end - Test.@testset "Inverse" begin + Test.@testset "Inverse" begin # COV_EXCL_LINE Test.@test inv(G, e) === e for g in g_pts ginv = inv(G, g) @@ -132,8 +132,8 @@ function test_group( end end - Test.@testset "translation" begin - convs = ((), (LeftAction(),), (RightAction(),)) + Test.@testset "translation" begin # COV_EXCL_LINE + convs = ((), (LeftForwardAction(),), (RightBackwardAction(),)) Test.@test isapprox( G, @@ -143,13 +143,13 @@ function test_group( ) Test.@test isapprox( G, - translate(G, g_pts[1], g_pts[2], LeftAction()), + translate(G, g_pts[1], g_pts[2], LeftForwardAction()), compose(G, g_pts[1], g_pts[2]); atol=atol, ) Test.@test isapprox( G, - translate(G, g_pts[1], g_pts[2], RightAction()), + translate(G, g_pts[1], g_pts[2], RightBackwardAction()), compose(G, g_pts[2], g_pts[1]); atol=atol, ) @@ -211,20 +211,20 @@ function test_group( G, g12, translate_diff(G, g_pts[2], g_pts[1], X), - translate_diff(G, g_pts[2], g_pts[1], X, LeftAction()); + translate_diff(G, g_pts[2], g_pts[1], X, LeftForwardAction()); atol=atol, ) Test.@test is_vector( G, g12, - translate_diff(G, g_pts[2], g_pts[1], X, LeftAction()), + translate_diff(G, g_pts[2], g_pts[1], X, LeftForwardAction()), true; atol=atol, ) - RightAction() in diff_convs && Test.@test is_vector( + RightBackwardAction() in diff_convs && Test.@test is_vector( G, g21, - translate_diff(G, g_pts[2], g_pts[1], X, RightAction()), + translate_diff(G, g_pts[2], g_pts[1], X, RightBackwardAction()), true; atol=atol, ) @@ -334,14 +334,14 @@ function test_group( end end - Test.@testset "inv(g) = exp(-log(g))" begin + Test.@testset "inv(g) = exp(-log(g))" begin # COV_EXCL_LINE g = g_pts[1] X = log_lie(G, g) ginv = exp_lie(G, -X) Test.@test isapprox(G, ginv, inv(G, g); atol=atol) end - Test.@testset "exp(sX)∘exp(tX) = exp((s+t)X)" begin + Test.@testset "exp(sX)∘exp(tX) = exp((s+t)X)" begin # COV_EXCL_LINE g1 = exp_lie(G, 0.2 * Xe_pts[1]) g2 = exp_lie(G, 0.3 * Xe_pts[1]) g12 = exp_lie(G, 0.5 * Xe_pts[1]) @@ -354,7 +354,7 @@ function test_group( test_exp_lie_log && test_diff && - Test.@testset "exp/log retract/inverse_retract" begin + Test.@testset "exp/log retract/inverse_retract" begin # COV_EXCL_LINE for conv in diff_convs y = retract( G, @@ -397,27 +397,27 @@ function test_group( end test_invariance && Test.@testset "metric invariance" begin - if has_invariant_metric(G, LeftAction()) - Test.@testset "left-invariant" begin + if has_invariant_metric(G, LeftForwardAction()) + Test.@testset "left-invariant" begin # COV_EXCL_LINE Test.@test has_approx_invariant_metric( G, g_pts[1], X_pts[1], X_pts[end], g_pts, - LeftAction(), + LeftForwardAction(), ) end end - if has_invariant_metric(G, RightAction()) - Test.@testset "right-invariant" begin + if has_invariant_metric(G, RightBackwardAction()) + Test.@testset "right-invariant" begin # COV_EXCL_LINE Test.@test has_approx_invariant_metric( G, g_pts[1], X_pts[1], X_pts[end], g_pts, - RightAction(), + RightBackwardAction(), ) end end @@ -476,7 +476,7 @@ function test_group( end end - Test.@testset "Metric operations with Identity" begin + Test.@testset "Metric operations with Identity" begin # COV_EXCL_LINE if test_log_from_identity pe = identity_element(G) Test.@test isapprox(G, pe, log(G, e, g_pts[1]), log(G, pe, g_pts[1])) @@ -516,6 +516,8 @@ function test_group( return nothing end +_direction_from_type(::AbstractGroupAction{TD}) where {TD<:ActionDirection} = TD() + """ test_action( A::AbstractGroupAction, @@ -550,34 +552,29 @@ function test_action( test_mutating_group=true, test_mutating_action=true, test_diff=false, - test_switch_direction=true, + test_switch_direction=Manifolds.LeftRightSwitch(), ) G = base_group(A) M = group_manifold(A) e = Identity(G) - Test.@testset "Basic action properties" begin - test_switch_direction && Test.@testset "Direction" begin + Test.@testset "Basic action properties" begin # COV_EXCL_LINE + test_switch_direction !== false && Test.@testset "Direction" begin Aswitch = switch_direction(A) - if isa(A, AbstractGroupAction{LeftAction}) - Test.@test direction(A) === LeftAction() - Test.@test isa(Aswitch, AbstractGroupAction{RightAction}) - Test.@test direction(Aswitch) === RightAction() - else - Test.@test direction(A) === RightAction() - Test.@test isa(Aswitch, AbstractGroupAction{LeftAction}) - Test.@test direction(Aswitch) === LeftAction() - end - end - Test.@testset "Closed" begin - Test.@testset "over actions" begin + Test.@test direction(A) === _direction_from_type(A) + sd = switch_direction(_direction_from_type(A), test_switch_direction) + Test.@test isa(Aswitch, AbstractGroupAction{typeof(sd)}) + Test.@test direction(Aswitch) === sd + end + Test.@testset "Closed" begin # COV_EXCL_LINE + Test.@testset "over actions" begin # COV_EXCL_LINE for a1 in a_pts, a2 in a_pts a3 = compose(A, a1, a2) Test.@test is_point(G, a3, true; atol=atol) end end - Test.@testset "over g-manifold" begin + Test.@testset "over g-manifold" begin # COV_EXCL_LINE for a in a_pts, m in m_pts Test.@test is_point(M, apply(A, a, m), true; atol=atol) Test.@test is_point(M, inverse_apply(A, a, m), true; atol=atol) @@ -585,17 +582,17 @@ function test_action( end end - Test.@testset "Associative" begin + Test.@testset "Associative" begin # COV_EXCL_LINE a12 = compose(A, a_pts[1], a_pts[2]) a23 = compose(A, a_pts[2], a_pts[3]) - Test.@testset "over compose" begin + Test.@testset "over compose" begin # COV_EXCL_LINE a12_a3 = compose(A, a12, a_pts[3]) a1_a23 = compose(A, a_pts[1], a23) Test.@test isapprox(G, a12_a3, a1_a23; atol=atol) end - Test.@testset "over apply" begin + Test.@testset "over apply" begin # COV_EXCL_LINE for m in m_pts a12_a3_m = apply(A, a12, apply(A, a_pts[3], m)) a1_a23_m = apply(A, a_pts[1], apply(A, a23, m)) @@ -621,7 +618,7 @@ function test_action( end end - Test.@testset "Identity" begin + Test.@testset "Identity" begin # COV_EXCL_LINE Test.@test compose(A, e, e) === e for a in a_pts @@ -675,7 +672,7 @@ function test_action( end end - Test.@testset "Inverse" begin + Test.@testset "Inverse" begin # COV_EXCL_LINE for a in a_pts ainv = inv(G, a) Test.@test isapprox(G, compose(A, a, ainv), e; atol=atol) diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 27ee81279f..647e2f2717 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -866,6 +866,8 @@ export AbstractGroupAction, Identity, InvariantMetric, LeftAction, + LeftBackwardAction, + LeftForwardAction, LeftInvariantMetric, MultiplicationOperation, Orthogonal, @@ -874,6 +876,8 @@ export AbstractGroupAction, ProductOperation, RealCircleGroup, RightAction, + RightBackwardAction, + RightForwardAction, RightInvariantMetric, RotationAction, SemidirectProductGroup, diff --git a/src/groups/circle_group.jl b/src/groups/circle_group.jl index a1c6bda83d..cb057778b6 100644 --- a/src/groups/circle_group.jl +++ b/src/groups/circle_group.jl @@ -57,7 +57,7 @@ function inverse_translate( ::CircleGroup, p::AbstractArray{<:Any,0}, q::AbstractArray{<:Any,0}, - ::LeftAction, + ::LeftForwardAction, ) return map(/, q, p) end @@ -65,7 +65,7 @@ function inverse_translate( ::CircleGroup, p::AbstractArray{<:Any,0}, q::AbstractArray{<:Any,0}, - ::RightAction, + ::RightBackwardAction, ) return map(/, q, p) end @@ -175,7 +175,7 @@ function inverse_translate( ::RealCircleGroup, p::AbstractArray{<:Any,0}, q::AbstractArray{<:Any,0}, - ::LeftAction, + ::LeftForwardAction, ) return map((x, y) -> sym_rem(x - y), q, p) end @@ -183,7 +183,7 @@ function inverse_translate( ::RealCircleGroup, p::AbstractArray{<:Any,0}, q::AbstractArray{<:Any,0}, - ::RightAction, + ::RightBackwardAction, ) return map((x, y) -> sym_rem(x - y), q, p) end diff --git a/src/groups/connections.jl b/src/groups/connections.jl index 1ca5ae210a..5f8f5acd93 100644 --- a/src/groups/connections.jl +++ b/src/groups/connections.jl @@ -61,7 +61,7 @@ function exp( p, X, ) where {𝔽} - Y = inverse_translate_diff(M.manifold, p, p, X, LeftAction()) + Y = inverse_translate_diff(M.manifold, p, p, X, LeftForwardAction()) return compose(M.manifold, p, exp_lie(M.manifold, Y)) end function exp( @@ -87,7 +87,7 @@ function exp!( p, X, ) where {𝔽} - Y = inverse_translate_diff(M.manifold, p, p, X, LeftAction()) + Y = inverse_translate_diff(M.manifold, p, p, X, LeftForwardAction()) return compose!(M.manifold, q, p, exp_lie(M.manifold, Y)) end @@ -122,7 +122,7 @@ function log( ) where {𝔽} pinvq = compose(M.manifold, inv(M.manifold, p), q) Y = log_lie(M.manifold, pinvq) - return translate_diff(M.manifold, p, Identity(M.manifold), Y, LeftAction()) + return translate_diff(M.manifold, p, Identity(M.manifold), Y, LeftForwardAction()) end function log!( @@ -147,11 +147,11 @@ Transport tangent vector `X` at point `p` on the group manifold `M` with the [`CartanSchoutenMinus`](@ref) connection to point `q`. See [^Pennec2020] for details. """ function parallel_transport_to(M::CartanSchoutenMinusGroup, p, X, q) - return inverse_translate_diff(M.manifold, q, p, X, LeftAction()) + return inverse_translate_diff(M.manifold, q, p, X, LeftForwardAction()) end function parallel_transport_to!(M::CartanSchoutenMinusGroup, Y, p, X, q) - return inverse_translate_diff!(M.manifold, Y, q, p, X, LeftAction()) + return inverse_translate_diff!(M.manifold, Y, q, p, X, LeftForwardAction()) end """ @@ -163,7 +163,7 @@ Transport tangent vector `X` at point `p` on the group manifold `M` with the parallel_transport_to(M::CartanSchoutenPlusGroup, p, X, q) function parallel_transport_to!(M::CartanSchoutenPlusGroup, Y, p, X, q) - return inverse_translate_diff!(M.manifold, Y, q, p, X, RightAction()) + return inverse_translate_diff!(M.manifold, Y, q, p, X, RightBackwardAction()) end """ @@ -174,14 +174,14 @@ Transport tangent vector `X` at identity on the group manifold with the """ function parallel_transport_direction(M::CartanSchoutenZeroGroup, p::Identity, X, d) dexp_half = exp_lie(M.manifold, d / 2) - Y = translate_diff(M.manifold, dexp_half, p, X, RightAction()) - return translate_diff(M.manifold, dexp_half, p, Y, LeftAction()) + Y = translate_diff(M.manifold, dexp_half, p, X, RightBackwardAction()) + return translate_diff(M.manifold, dexp_half, p, Y, LeftForwardAction()) end function parallel_transport_direction!(M::CartanSchoutenZeroGroup, Y, p::Identity, X, d) dexp_half = exp_lie(M.manifold, d / 2) - translate_diff!(M.manifold, Y, dexp_half, p, X, RightAction()) - return translate_diff!(M.manifold, Y, dexp_half, p, Y, LeftAction()) + translate_diff!(M.manifold, Y, dexp_half, p, X, RightBackwardAction()) + return translate_diff!(M.manifold, Y, dexp_half, p, Y, LeftForwardAction()) end """ diff --git a/src/groups/general_linear.jl b/src/groups/general_linear.jl index c8f171bf65..9e69dbf2ff 100644 --- a/src/groups/general_linear.jl +++ b/src/groups/general_linear.jl @@ -165,8 +165,8 @@ exp_lie!(::GeneralLinear{2}, q, X) = copyto!(q, exp(SizedMatrix{2,2}(X))) inner(::GeneralLinear, p, X, Y) = dot(X, Y) -inverse_translate_diff(::GeneralLinear, p, q, X, ::LeftAction) = X -inverse_translate_diff(::GeneralLinear, p, q, X, ::RightAction) = p * X / p +inverse_translate_diff(::GeneralLinear, p, q, X, ::LeftForwardAction) = X +inverse_translate_diff(::GeneralLinear, p, q, X, ::RightBackwardAction) = p * X / p function inverse_translate_diff!(G::GeneralLinear, Y, p, q, X, conv::ActionDirection) return copyto!(Y, inverse_translate_diff(G, p, q, X, conv)) @@ -203,7 +203,7 @@ function log(M::GeneralLinear, p, q) end function log!(G::GeneralLinear{n,𝔽}, X, p, q) where {n,𝔽} - pinvq = inverse_translate(G, p, q, LeftAction()) + pinvq = inverse_translate(G, p, q, LeftForwardAction()) 𝔽 === ℝ && det(pinvq) ≀ 0 && throw(OutOfInjectivityRadiusError()) if isnormal(pinvq; atol=sqrt(eps(real(eltype(pinvq))))) log_safe!(X, pinvq) @@ -218,7 +218,7 @@ function log!(G::GeneralLinear{n,𝔽}, X, p, q) where {n,𝔽} inverse_retract!(Gα΅£, Xα΅£, Identity(G), pinvqα΅£, inverse_retraction) unrealify!(X, Xα΅£, 𝔽, n) end - translate_diff!(G, X, p, Identity(G), X, LeftAction()) + translate_diff!(G, X, p, Identity(G), X, LeftForwardAction()) return X end function log!(::GeneralLinear{1}, X, p, q) @@ -268,8 +268,8 @@ end Base.show(io::IO, ::GeneralLinear{n,𝔽}) where {n,𝔽} = print(io, "GeneralLinear($n, $𝔽)") -translate_diff(::GeneralLinear, p, q, X, ::LeftAction) = X -translate_diff(::GeneralLinear, p, q, X, ::RightAction) = p \ X * p +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::ActionDirection) return copyto!(Y, translate_diff(G, p, q, X, conv)) diff --git a/src/groups/general_unitary_groups.jl b/src/groups/general_unitary_groups.jl index ba22702444..04ec75eb41 100644 --- a/src/groups/general_unitary_groups.jl +++ b/src/groups/general_unitary_groups.jl @@ -144,13 +144,34 @@ function exp_lie!(::GeneralUnitaryMultiplicationGroup{4,ℝ}, q, X) return q end -inverse_translate(G::GeneralUnitaryMultiplicationGroup, p, q, ::LeftAction) = inv(G, p) * q -inverse_translate(G::GeneralUnitaryMultiplicationGroup, p, q, ::RightAction) = q * inv(G, p) +function inverse_translate(G::GeneralUnitaryMultiplicationGroup, p, q, ::LeftForwardAction) + return inv(G, p) * q +end +function inverse_translate( + G::GeneralUnitaryMultiplicationGroup, + p, + q, + ::RightBackwardAction, +) + return q * inv(G, p) +end -function inverse_translate!(G::GeneralUnitaryMultiplicationGroup, x, p, q, ::LeftAction) +function inverse_translate!( + G::GeneralUnitaryMultiplicationGroup, + x, + p, + q, + ::LeftForwardAction, +) return mul!(x, inv(G, p), q) end -function inverse_translate!(G::GeneralUnitaryMultiplicationGroup, x, p, q, ::RightAction) +function inverse_translate!( + G::GeneralUnitaryMultiplicationGroup, + x, + p, + q, + ::RightBackwardAction, +) return mul!(x, q, inv(G, p)) end @@ -267,9 +288,43 @@ function Random.rand!(rng::AbstractRNG, G::GeneralUnitaryMultiplicationGroup, pX return pX end -function translate_diff!(G::GeneralUnitaryMultiplicationGroup, Y, p, q, X, ::LeftAction) - return copyto!(G, Y, p, X) +function translate_diff!( + G::GeneralUnitaryMultiplicationGroup, + Y, + p, + q, + X, + ::LeftForwardAction, +) + return copyto!(G, Y, X) end -function translate_diff!(G::GeneralUnitaryMultiplicationGroup, Y, p, q, X, ::RightAction) - return copyto!(G, Y, p, inv(G, p) * X * p) +function translate_diff!( + G::GeneralUnitaryMultiplicationGroup, + Y, + p, + q, + X, + ::RightForwardAction, +) + return copyto!(G, Y, X) +end +function translate_diff!( + G::GeneralUnitaryMultiplicationGroup, + Y, + p, + q, + X, + ::LeftBackwardAction, +) + return copyto!(G, Y, p * X * inv(G, p)) +end +function translate_diff!( + G::GeneralUnitaryMultiplicationGroup, + Y, + p, + q, + X, + ::RightBackwardAction, +) + return copyto!(G, Y, inv(G, p) * X * p) end diff --git a/src/groups/group.jl b/src/groups/group.jl index 586052d5d3..5ef80603f1 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -50,8 +50,8 @@ Specify that a certain the metric of a [`GroupManifold`](@ref) is a left-invaria """ struct HasLeftInvariantMetric <: AbstractInvarianceTrait end -direction(::HasLeftInvariantMetric) = LeftAction() -direction(::Type{HasLeftInvariantMetric}) = LeftAction() +direction(::HasLeftInvariantMetric) = LeftForwardAction() +direction(::Type{HasLeftInvariantMetric}) = LeftForwardAction() """ HasRightInvariantMetric <: AbstractInvarianceTrait @@ -60,8 +60,8 @@ Specify that a certain the metric of a [`GroupManifold`](@ref) is a right-invari """ struct HasRightInvariantMetric <: AbstractInvarianceTrait end -direction(::HasRightInvariantMetric) = RightAction() -direction(::Type{HasRightInvariantMetric}) = RightAction() +direction(::HasRightInvariantMetric) = RightBackwardAction() +direction(::Type{HasRightInvariantMetric}) = RightBackwardAction() """ HasBiinvariantMetric <: AbstractInvarianceTrait @@ -107,32 +107,112 @@ base_group(M::AbstractDecoratorManifold) = M """ ActionDirection -Direction of action on a manifold, either [`LeftAction`](@ref) or [`RightAction`](@ref). +Direction of action on a manifold, either [`LeftForwardAction`](@ref), +[`LeftBackwardAction`](@ref), [`RightForwardAction`](@ref) or [`RightBackwardAction`](@ref). """ abstract type ActionDirection end +@doc raw""" + LeftForwardAction() + +Left action of a group on a manifold. For an action ``Ξ±: G Γ— X β†’ X`` it is characterized by +```math +Ξ±(g, Ξ±(h, x)) = Ξ±(gh, x) +``` +for all ``g, h ∈ G`` and ``x ∈ X``. """ - LeftAction() +struct LeftForwardAction <: ActionDirection end + +@doc raw""" + LeftBackwardAction() -Left action of a group on a manifold. +Left action of a group on a manifold. For an action ``Ξ±: X Γ— G β†’ X`` it is characterized by +```math +Ξ±(Ξ±(x, h), g) = Ξ±(x, gh) +``` +for all ``g, h ∈ G`` and ``x ∈ X``. + +Note that a left action may still act from the right side in an expression. """ -struct LeftAction <: ActionDirection end +struct LeftBackwardAction <: ActionDirection end + +const LeftAction = LeftForwardAction """ - RightAction() + RightForwardAction() -Right action of a group on a manifold. +Right action of a group on a manifold. For an action ``Ξ±: G Γ— X β†’ X`` it is characterized by +```math +Ξ±(g, Ξ±(h, x)) = Ξ±(hg, x) +``` +for all ``g, h ∈ G`` and ``x ∈ X``. + +Note that a right action may still act from the left side in an expression. """ -struct RightAction <: ActionDirection end +struct RightForwardAction <: ActionDirection end """ - switch_direction(::ActionDirection) + RightBackwardAction() -Returns a [`RightAction`](@ref) when given a [`LeftAction`](@ref) and vice versa. +Right action of a group on a manifold. For an action ``Ξ±: X Γ— G β†’ X`` it is characterized by +```math +Ξ±(Ξ±(x, h), g) = Ξ±(x, hg) +``` +for all ``g, h ∈ G`` and ``x ∈ X``. + +Note that a right action may still act from the left side in an expression. """ -switch_direction(::ActionDirection) -switch_direction(::LeftAction) = RightAction() -switch_direction(::RightAction) = LeftAction() +struct RightBackwardAction <: ActionDirection end + +const RightAction = RightBackwardAction + +abstract type AbstractDirectionSwitchType end + +""" + struct LeftRightSwitch <: AbstractDirectionSwitchType end + +Switch between left and right action, maintaining forward/backward direction. +""" +struct LeftRightSwitch <: AbstractDirectionSwitchType end + +""" + struct ForwardBackwardSwitch <: AbstractDirectionSwitchType end + +Switch between forward and backward action, maintaining left/right direction. +""" +struct ForwardBackwardSwitch <: AbstractDirectionSwitchType end + +""" + struct LeftRightSwitch <: AbstractDirectionSwitchType end + +Simultaneously switch left/right and forward/backward directions. +""" +struct SimultaneousSwitch <: AbstractDirectionSwitchType end + +""" + switch_direction(::ActionDirection, type::AbstractDirectionSwitchType = SimultaneousSwitch()) + +Returns type of action between left and right, forward or backward, or both at the same type, +depending on `type`, which is either of `LeftRightSwitch`, `ForwardBackwardSwitch` or +`SimultaneousSwitch`. +""" +switch_direction(::ActionDirection, type::AbstractDirectionSwitchType) +switch_direction(AD::ActionDirection) = switch_direction(AD, SimultaneousSwitch()) + +switch_direction(::LeftForwardAction, ::LeftRightSwitch) = RightForwardAction() +switch_direction(::LeftBackwardAction, ::LeftRightSwitch) = RightBackwardAction() +switch_direction(::RightForwardAction, ::LeftRightSwitch) = LeftForwardAction() +switch_direction(::RightBackwardAction, ::LeftRightSwitch) = LeftBackwardAction() + +switch_direction(::LeftForwardAction, ::ForwardBackwardSwitch) = LeftBackwardAction() +switch_direction(::LeftBackwardAction, ::ForwardBackwardSwitch) = LeftForwardAction() +switch_direction(::RightForwardAction, ::ForwardBackwardSwitch) = RightBackwardAction() +switch_direction(::RightBackwardAction, ::ForwardBackwardSwitch) = RightForwardAction() + +switch_direction(::LeftForwardAction, ::SimultaneousSwitch) = RightBackwardAction() +switch_direction(::LeftBackwardAction, ::SimultaneousSwitch) = RightForwardAction() +switch_direction(::RightForwardAction, ::SimultaneousSwitch) = LeftBackwardAction() +switch_direction(::RightBackwardAction, ::SimultaneousSwitch) = LeftForwardAction() @doc raw""" Identity{O<:AbstractGroupOperation} @@ -374,8 +454,8 @@ Notably the adjoint representation of SO(2) is trivial. adjoint_action(G::AbstractDecoratorManifold, p, X) @trait_function adjoint_action(G::AbstractDecoratorManifold, p, Xβ‚‘) function adjoint_action(::TraitList{<:IsGroupManifold}, G::AbstractDecoratorManifold, p, Xβ‚‘) - Xβ‚š = translate_diff(G, p, Identity(G), Xβ‚‘, LeftAction()) - Y = inverse_translate_diff(G, p, p, Xβ‚š, RightAction()) + Xβ‚š = translate_diff(G, p, Identity(G), Xβ‚‘, LeftForwardAction()) + Y = inverse_translate_diff(G, p, p, Xβ‚š, RightBackwardAction()) return Y end @@ -387,8 +467,8 @@ function adjoint_action!( p, Xβ‚‘, ) - Xβ‚š = translate_diff(G, p, Identity(G), Xβ‚‘, LeftAction()) - inverse_translate_diff!(G, Y, p, p, Xβ‚š, RightAction()) + Xβ‚š = translate_diff(G, p, Identity(G), Xβ‚‘, LeftForwardAction()) + inverse_translate_diff!(G, Y, p, p, Xβ‚š, RightBackwardAction()) return Y end @@ -656,18 +736,23 @@ lie_bracket(G::AbstractDecoratorManifold, X, Y) @trait_function lie_bracket!(M::AbstractDecoratorManifold, Z, X, Y) -_action_order(p, q, ::LeftAction) = (p, q) -_action_order(p, q, ::RightAction) = (q, p) +_action_order(BG::AbstractDecoratorManifold, p, q, ::LeftForwardAction) = (p, q) +_action_order(BG::AbstractDecoratorManifold, p, q, ::LeftBackwardAction) = (q, inv(BG, p)) +_action_order(BG::AbstractDecoratorManifold, p, q, ::RightForwardAction) = (inv(BG, p), q) +_action_order(BG::AbstractDecoratorManifold, p, q, ::RightBackwardAction) = (q, p) @doc raw""" - translate(G::AbstractDecoratorManifold, p, q, conv::ActionDirection=LeftAction()]) + translate(G::AbstractDecoratorManifold, p, q, conv::ActionDirection=LeftForwardAction()]) Translate group element $q$ by $p$ with the translation $Ο„_p$ with the specified -`conv`ention, either left ($L_p$) or right ($R_p$), defined as +`conv`ention, either left forward ($L_p$), left backward ($R'_p$), right backward ($R_p$) +or right forward ($L'_p$), defined as ```math \begin{aligned} L_p &: q ↦ p \circ q\\ -R_p &: q ↦ q \circ p. +L'_p &: q ↦ p^{-1} \circ q\\ +R_p &: q ↦ q \circ p\\ +R'_p &: q ↦ q \circ p^{-1}. \end{aligned} ``` """ @@ -676,7 +761,7 @@ translate(::AbstractDecoratorManifold, ::Any...) G::AbstractDecoratorManifold, p, q, - conv::ActionDirection=LeftAction(), + conv::ActionDirection=LeftForwardAction(), ) function translate( ::TraitList{<:IsGroupManifold}, @@ -686,7 +771,7 @@ function translate( conv::ActionDirection, ) BG = base_group(G) - return compose(BG, _action_order(p, q, conv)...) + return compose(BG, _action_order(BG, p, q, conv)...) end @trait_function translate!( @@ -694,7 +779,7 @@ end X, p, q, - conv::ActionDirection=LeftAction(), + conv::ActionDirection=LeftForwardAction(), ) function translate!( ::TraitList{<:IsGroupManifold}, @@ -705,11 +790,11 @@ function translate!( conv::ActionDirection, ) BG = base_group(G) - return compose!(BG, X, _action_order(p, q, conv)...) + return compose!(BG, X, _action_order(BG, p, q, conv)...) end @doc raw""" - inverse_translate(G::AbstractDecoratorManifold, p, q, conv::ActionDirection=LeftAction()) + inverse_translate(G::AbstractDecoratorManifold, p, q, conv::ActionDirection=LeftForwardAction()) Inverse translate group element $q$ by $p$ with the inverse translation $Ο„_p^{-1}$ with the specified `conv`ention, either left ($L_p^{-1}$) or right ($R_p^{-1}$), defined as @@ -725,7 +810,7 @@ inverse_translate(::AbstractDecoratorManifold, ::Any...) G::AbstractDecoratorManifold, p, q, - conv::ActionDirection=LeftAction(), + conv::ActionDirection=LeftForwardAction(), ) function inverse_translate( ::TraitList{<:IsGroupManifold}, @@ -743,7 +828,7 @@ end X, p, q, - conv::ActionDirection=LeftAction(), + conv::ActionDirection=LeftForwardAction(), ) function inverse_translate!( ::TraitList{<:IsGroupManifold}, @@ -758,7 +843,7 @@ function inverse_translate!( end @doc raw""" - translate_diff(G::AbstractDecoratorManifold, p, q, X, conv::ActionDirection=LeftAction()) + translate_diff(G::AbstractDecoratorManifold, p, q, X, conv::ActionDirection=LeftForwardAction()) For group elements $p, q ∈ \mathcal{G}$ and tangent vector $X ∈ T_q \mathcal{G}$, compute the action of the differential of the translation $Ο„_p$ by $p$ on $X$, with the specified @@ -773,7 +858,7 @@ translate_diff(::AbstractDecoratorManifold, ::Any...) p, q, X, - conv::ActionDirection=LeftAction(), + conv::ActionDirection=LeftForwardAction(), ) function translate_diff( ::TraitList{<:IsGroupManifold}, @@ -794,11 +879,11 @@ end p, q, X, - conv::ActionDirection=LeftAction(), + conv::ActionDirection=LeftForwardAction(), ) @doc raw""" - inverse_translate_diff(G::AbstractDecoratorManifold, p, q, X, conv::ActionDirection=LeftAction()) + inverse_translate_diff(G::AbstractDecoratorManifold, p, q, X, conv::ActionDirection=LeftForwardAction()) For group elements $p, q ∈ \mathcal{G}$ and tangent vector $X ∈ T_q \mathcal{G}$, compute the action on $X$ of the differential of the inverse translation $Ο„_p$ by $p$, with the @@ -813,7 +898,7 @@ inverse_translate_diff(::AbstractDecoratorManifold, ::Any...) p, q, X, - conv::ActionDirection=LeftAction(), + conv::ActionDirection=LeftForwardAction(), ) function inverse_translate_diff( ::TraitList{<:IsGroupManifold}, @@ -833,7 +918,7 @@ end p, q, X, - conv::ActionDirection=LeftAction(), + conv::ActionDirection=LeftForwardAction(), ) function inverse_translate_diff!( ::TraitList{<:IsGroupManifold}, @@ -977,11 +1062,11 @@ For more details, see # Constructor - GroupExponentialRetraction(conv::ActionDirection = LeftAction()) + GroupExponentialRetraction(conv::ActionDirection = LeftForwardAction()) """ struct GroupExponentialRetraction{D<:ActionDirection} <: AbstractRetractionMethod end -function GroupExponentialRetraction(conv::ActionDirection=LeftAction()) +function GroupExponentialRetraction(conv::ActionDirection=LeftForwardAction()) return GroupExponentialRetraction{typeof(conv)}() end @@ -996,12 +1081,12 @@ For more details, see # Constructor - GroupLogarithmicInverseRetraction(conv::ActionDirection = LeftAction()) + GroupLogarithmicInverseRetraction(conv::ActionDirection = LeftForwardAction()) """ struct GroupLogarithmicInverseRetraction{D<:ActionDirection} <: AbstractInverseRetractionMethod end -function GroupLogarithmicInverseRetraction(conv::ActionDirection=LeftAction()) +function GroupLogarithmicInverseRetraction(conv::ActionDirection=LeftForwardAction()) return GroupLogarithmicInverseRetraction{typeof(conv)}() end diff --git a/src/groups/group_action.jl b/src/groups/group_action.jl index 7419e5ae6c..6060dae02d 100644 --- a/src/groups/group_action.jl +++ b/src/groups/group_action.jl @@ -65,14 +65,14 @@ end Apply action `a` to the point `p` with the rule specified by `A`. The result is saved in `q`. """ -function apply!(A::AbstractGroupAction{LeftAction}, q, a, p) +function apply!(A::AbstractGroupAction{LeftForwardAction}, q, a, p) return error( "apply! not implemented for action $(typeof(A)) and points $(typeof(q)), $(typeof(p)) and $(typeof(a)).", ) end -function apply!(A::AbstractGroupAction{RightAction}, q, a, p) +function apply!(A::AbstractGroupAction{RightForwardAction}, q, a, p) ainv = inv(base_group(A), a) - apply!(switch_direction(A), q, ainv, p) + apply!(switch_direction(A, LeftRightSwitch()), q, ainv, p) return q end @@ -166,11 +166,37 @@ function inverse_apply_diff!(A::AbstractGroupAction, Y, a, p, X) return apply_diff!(A, Y, inv(base_group(A), a), p, X) end -compose(A::AbstractGroupAction{LeftAction}, a, b) = compose(base_group(A), a, b) -compose(A::AbstractGroupAction{RightAction}, a, b) = compose(base_group(A), b, a) +function compose( + A::AbstractGroupAction{<:Union{LeftForwardAction,LeftBackwardAction}}, + a, + b, +) + return compose(base_group(A), a, b) +end +function compose( + A::AbstractGroupAction{<:Union{RightForwardAction,RightBackwardAction}}, + a, + b, +) + return compose(base_group(A), b, a) +end -compose!(A::AbstractGroupAction{LeftAction}, q, a, b) = compose!(base_group(A), q, a, b) -compose!(A::AbstractGroupAction{RightAction}, q, a, b) = compose!(base_group(A), q, b, a) +function compose!( + A::AbstractGroupAction{<:Union{LeftForwardAction,LeftBackwardAction}}, + q, + a, + b, +) + return compose!(base_group(A), q, a, b) +end +function compose!( + A::AbstractGroupAction{<:Union{RightForwardAction,RightBackwardAction}}, + q, + a, + b, +) + return compose!(base_group(A), q, b, a) +end @doc raw""" optimal_alignment(A::AbstractGroupAction, p, q) diff --git a/src/groups/group_operation_action.jl b/src/groups/group_operation_action.jl index 50400ef059..3963d5135b 100644 --- a/src/groups/group_operation_action.jl +++ b/src/groups/group_operation_action.jl @@ -1,5 +1,5 @@ @doc raw""" - GroupOperationAction(group::AbstractDecoratorManifold, AD::ActionDirection = LeftAction()) + GroupOperationAction(group::AbstractDecoratorManifold, AD::ActionDirection = LeftForwardAction()) Action of a group upon itself via left or right translation. """ @@ -9,7 +9,7 @@ end function GroupOperationAction( G::TM, - ::TAD=LeftAction(), + ::TAD=LeftForwardAction(), ) where {TM<:AbstractDecoratorManifold,TAD<:ActionDirection} return GroupOperationAction{TM,TAD}(G) end diff --git a/src/groups/heisenberg.jl b/src/groups/heisenberg.jl index e9c737d36c..2c7cfa2608 100644 --- a/src/groups/heisenberg.jl +++ b/src/groups/heisenberg.jl @@ -392,8 +392,8 @@ end Base.show(io::IO, ::HeisenbergGroup{n}) where {n} = print(io, "HeisenbergGroup($n)") -translate_diff(::HeisenbergGroup, p, q, X, ::LeftAction) = X -translate_diff(::HeisenbergGroup, p, q, X, ::RightAction) = p \ X * p +translate_diff(::HeisenbergGroup, p, q, X, ::LeftForwardAction) = X +translate_diff(::HeisenbergGroup, p, q, X, ::RightBackwardAction) = p \ X * p function translate_diff!(G::HeisenbergGroup, Y, p, q, X, conv::ActionDirection) return copyto!(Y, translate_diff(G, p, q, X, conv)) diff --git a/src/groups/metric.jl b/src/groups/metric.jl index b399542c88..19a946dfd9 100644 --- a/src/groups/metric.jl +++ b/src/groups/metric.jl @@ -5,7 +5,7 @@ X, Y, qs::AbstractVector, - conv::ActionDirection = LeftAction(); + conv::ActionDirection = LeftForwardAction(); kwargs..., ) -> Bool @@ -29,7 +29,7 @@ has_approx_invariant_metric(::AbstractDecoratorManifold, p, X, Y, qs, ::ActionDi X, Y, qs, - conv::ActionDirection=LeftAction(); + conv::ActionDirection=LeftForwardAction(); kwargs..., ) function has_approx_invariant_metric( @@ -61,12 +61,16 @@ direction(::AbstractDecoratorManifold) @trait_function direction(M::AbstractDecoratorManifold) -direction(::TraitList{HasLeftInvariantMetric}, ::AbstractDecoratorManifold) = LeftAction() +function direction(::TraitList{HasLeftInvariantMetric}, ::AbstractDecoratorManifold) + return LeftForwardAction() +end -direction(::TraitList{HasRightInvariantMetric}, ::AbstractDecoratorManifold) = RightAction() +function direction(::TraitList{HasRightInvariantMetric}, ::AbstractDecoratorManifold) + return RightBackwardAction() +end function exp(::TraitList{HasLeftInvariantMetric}, M::AbstractDecoratorManifold, p, X) - return retract(M, p, X, GroupExponentialRetraction(LeftAction())) + return retract(M, p, X, GroupExponentialRetraction(LeftForwardAction())) end function exp( ::TraitList{HasLeftInvariantMetric}, @@ -75,10 +79,10 @@ function exp( X, t::Number, ) - return retract(M, p, X, t, GroupExponentialRetraction(LeftAction())) + return retract(M, p, X, t, GroupExponentialRetraction(LeftForwardAction())) end function exp!(::TraitList{HasLeftInvariantMetric}, M::AbstractDecoratorManifold, q, p, X) - return retract!(M, q, p, X, GroupExponentialRetraction(LeftAction())) + return retract!(M, q, p, X, GroupExponentialRetraction(LeftForwardAction())) end function exp!( ::TraitList{HasLeftInvariantMetric}, @@ -88,10 +92,10 @@ function exp!( X, t::Number, ) - return retract!(M, q, p, X, t, GroupExponentialRetraction(LeftAction())) + return retract!(M, q, p, X, t, GroupExponentialRetraction(LeftForwardAction())) end function exp(::TraitList{HasRightInvariantMetric}, M::AbstractDecoratorManifold, p, X) - return retract(M, p, X, GroupExponentialRetraction(RightAction())) + return retract(M, p, X, GroupExponentialRetraction(RightBackwardAction())) end function exp( ::TraitList{HasRightInvariantMetric}, @@ -100,10 +104,10 @@ function exp( X, t::Number, ) - return retract(M, p, X, t, GroupExponentialRetraction(RightAction())) + return retract(M, p, X, t, GroupExponentialRetraction(RightBackwardAction())) end function exp!(::TraitList{HasRightInvariantMetric}, M::AbstractDecoratorManifold, q, p, X) - return retract!(M, q, p, X, GroupExponentialRetraction(RightAction())) + return retract!(M, q, p, X, GroupExponentialRetraction(RightBackwardAction())) end function exp!( ::TraitList{HasRightInvariantMetric}, @@ -113,7 +117,7 @@ function exp!( X, t::Number, ) - return retract!(M, q, p, X, t, GroupExponentialRetraction(RightAction())) + return retract!(M, q, p, X, t, GroupExponentialRetraction(RightBackwardAction())) end function exp(::TraitList{HasBiinvariantMetric}, M::MetricManifold, p, X) return exp(M.manifold, p, X) @@ -183,14 +187,14 @@ has_invariant_metric(::AbstractManifold, op::ActionDirection) = false function has_invariant_metric( ::TraitList{<:HasLeftInvariantMetric}, ::AbstractDecoratorManifold, - ::LeftAction, + ::LeftForwardAction, ) return true end function has_invariant_metric( ::TraitList{<:HasRightInvariantMetric}, ::AbstractDecoratorManifold, - ::RightAction, + ::RightBackwardAction, ) return true end @@ -251,16 +255,33 @@ function inverse_translate_diff!( end function log(::TraitList{HasLeftInvariantMetric}, M::AbstractDecoratorManifold, p, q) - return inverse_retract(M, p, q, GroupLogarithmicInverseRetraction(LeftAction())) + return inverse_retract(M, p, q, GroupLogarithmicInverseRetraction(LeftForwardAction())) end function log!(::TraitList{HasLeftInvariantMetric}, M::AbstractDecoratorManifold, X, p, q) - return inverse_retract!(M, X, p, q, GroupLogarithmicInverseRetraction(LeftAction())) + return inverse_retract!( + M, + X, + p, + q, + GroupLogarithmicInverseRetraction(LeftForwardAction()), + ) end function log(::TraitList{HasRightInvariantMetric}, M::AbstractDecoratorManifold, p, q) - return inverse_retract(M, p, q, GroupLogarithmicInverseRetraction(RightAction())) + return inverse_retract( + M, + p, + q, + GroupLogarithmicInverseRetraction(RightBackwardAction()), + ) end function log!(::TraitList{HasRightInvariantMetric}, M::AbstractDecoratorManifold, X, p, q) - return inverse_retract!(M, X, p, q, GroupLogarithmicInverseRetraction(RightAction())) + return inverse_retract!( + M, + X, + p, + q, + GroupLogarithmicInverseRetraction(RightBackwardAction()), + ) end function log(::TraitList{HasBiinvariantMetric}, M::MetricManifold, p, q) return log(M.manifold, p, q) diff --git a/src/groups/multiplication_operation.jl b/src/groups/multiplication_operation.jl index f1a3c3e880..689a134c1b 100644 --- a/src/groups/multiplication_operation.jl +++ b/src/groups/multiplication_operation.jl @@ -135,7 +135,7 @@ function inverse_translate( G::AbstractDecoratorManifold, p, q, - ::LeftAction, + ::LeftForwardAction, ) return p \ q end @@ -144,7 +144,7 @@ function inverse_translate( G::AbstractDecoratorManifold, p, q, - ::RightAction, + ::RightBackwardAction, ) return q / p end diff --git a/src/groups/rotation_action.jl b/src/groups/rotation_action.jl index 4de69b3a87..a601d3e568 100644 --- a/src/groups/rotation_action.jl +++ b/src/groups/rotation_action.jl @@ -2,7 +2,7 @@ RotationAction( M::AbstractManifold, SOn::SpecialOrthogonal, - AD::ActionDirection = LeftAction(), + AD::ActionDirection = LeftForwardAction(), ) Space of actions of the [`SpecialOrthogonal`](@ref) group $\mathrm{SO}(n)$ on a @@ -17,7 +17,7 @@ end function RotationAction( M::AbstractManifold, SOn::SpecialOrthogonal, - ::TAD=LeftAction(), + ::TAD=LeftForwardAction(), ) where {TAD<:ActionDirection} return RotationAction{typeof(M),typeof(SOn),TAD}(M, SOn) end @@ -36,44 +36,59 @@ base_group(A::RotationAction) = A.SOn group_manifold(A::RotationAction) = A.manifold -function switch_direction(A::RotationAction{TM,TSO,TAD}) where {TM,TSO,TAD} - return RotationAction(A.manifold, A.SOn, switch_direction(TAD())) +function switch_direction( + A::RotationAction{TM,TSO,TAD}, + ::LeftRightSwitch=LeftRightSwitch(), +) where {TM<:AbstractManifold,TSO<:SpecialOrthogonal,TAD<:ActionDirection} + return RotationAction(A.manifold, A.SOn, switch_direction(TAD(), LeftRightSwitch())) end -apply(::RotationActionOnVector{N,F,LeftAction}, a, p) where {N,F} = a * p -function apply(A::RotationActionOnVector{N,F,RightAction}, a, p) where {N,F} +apply(::RotationActionOnVector{N,F,LeftForwardAction}, a, p) where {N,F} = a * p +function apply(A::RotationActionOnVector{N,F,RightForwardAction}, a, p) where {N,F} return inv(base_group(A), a) * p end -apply!(::RotationActionOnVector{N,F,LeftAction}, q, a, p) where {N,F} = mul!(q, a, p) +apply!(::RotationActionOnVector{N,F,LeftForwardAction}, q, a, p) where {N,F} = mul!(q, a, p) -function inverse_apply(A::RotationActionOnVector{N,F,LeftAction}, a, p) where {N,F} +function inverse_apply(A::RotationActionOnVector{N,F,LeftForwardAction}, a, p) where {N,F} return inv(base_group(A), a) * p end -inverse_apply(::RotationActionOnVector{N,F,RightAction}, a, p) where {N,F} = a * p +inverse_apply(::RotationActionOnVector{N,F,RightForwardAction}, a, p) where {N,F} = a * p -apply_diff(::RotationActionOnVector{N,F,LeftAction}, a, p, X) where {N,F} = a * X +apply_diff(::RotationActionOnVector{N,F,LeftForwardAction}, a, p, X) where {N,F} = a * X function apply_diff( - ::RotationActionOnVector{N,F,LeftAction}, + ::RotationActionOnVector{N,F,LeftForwardAction}, ::Identity{MultiplicationOperation}, p, X, ) where {N,F} return X end -function apply_diff(A::RotationActionOnVector{N,F,RightAction}, a, p, X) where {N,F} +function apply_diff(A::RotationActionOnVector{N,F,RightForwardAction}, a, p, X) where {N,F} return inv(base_group(A), a) * X end -function apply_diff!(::RotationActionOnVector{N,F,LeftAction}, Y, a, p, X) where {N,F} +function apply_diff!( + ::RotationActionOnVector{N,F,LeftForwardAction}, + Y, + a, + p, + X, +) where {N,F} return mul!(Y, a, X) end -function apply_diff!(A::RotationActionOnVector{N,F,RightAction}, Y, a, p, X) where {N,F} +function apply_diff!( + A::RotationActionOnVector{N,F,RightForwardAction}, + Y, + a, + p, + X, +) where {N,F} return mul!(Y, inv(base_group(A), a), X) end function apply_diff_group( - ::RotationActionOnVector{N,F,LeftAction}, + ::RotationActionOnVector{N,F,LeftForwardAction}, ::Identity, X, p, @@ -82,7 +97,7 @@ function apply_diff_group( end function apply_diff_group!( - ::RotationActionOnVector{N,F,LeftAction}, + ::RotationActionOnVector{N,F,LeftForwardAction}, Y, ::Identity, X, @@ -92,12 +107,28 @@ function apply_diff_group!( return Y end -function inverse_apply_diff(A::RotationActionOnVector{N,F,LeftAction}, a, p, X) where {N,F} +function inverse_apply_diff( + A::RotationActionOnVector{N,F,LeftForwardAction}, + a, + p, + X, +) where {N,F} return inv(base_group(A), a) * X end -inverse_apply_diff(A::RotationActionOnVector{N,F,RightAction}, a, p, X) where {N,F} = a * X +function inverse_apply_diff( + A::RotationActionOnVector{N,F,RightForwardAction}, + a, + p, + X, +) where {N,F} + return a * X +end -function optimal_alignment(::RotationActionOnVector{N,T,LeftAction}, p, q) where {N,T} +function optimal_alignment( + ::RotationActionOnVector{N,T,LeftForwardAction}, + p, + q, +) where {N,T} Xmul = p * transpose(q) F = svd(Xmul) L = size(Xmul)[2] @@ -105,7 +136,11 @@ function optimal_alignment(::RotationActionOnVector{N,T,LeftAction}, p, q) where Ostar = det(UVt) β‰₯ 0 ? UVt : F.U * Diagonal([i < L ? 1 : -1 for i in 1:L]) * F.Vt return convert(typeof(Xmul), Ostar) end -function optimal_alignment(A::RotationActionOnVector{N,T,RightAction}, p, q) where {N,T} +function optimal_alignment( + A::RotationActionOnVector{N,T,RightForwardAction}, + p, + q, +) where {N,T} return optimal_alignment(switch_direction(A), q, p) end @@ -114,7 +149,8 @@ end Space of actions of the circle group [`RealCircleGroup`](@ref) on $ℝ^3$ around given `axis`. """ -struct RotationAroundAxisAction{TA<:AbstractVector} <: AbstractGroupAction{LeftAction} +struct RotationAroundAxisAction{TA<:AbstractVector} <: + AbstractGroupAction{LeftForwardAction} axis::TA end @@ -168,7 +204,7 @@ of type `On` columns of points on a matrix manifold `M`. RowwiseMultiplicationAction( M::AbstractManifold, On::GeneralUnitaryMultiplicationGroup, - AD::ActionDirection = LeftAction(), + AD::ActionDirection = LeftForwardAction(), ) """ struct RowwiseMultiplicationAction{ @@ -183,7 +219,7 @@ end function RowwiseMultiplicationAction( M::AbstractManifold, On::GeneralUnitaryMultiplicationGroup, - ::TAD=LeftAction(), + ::TAD=LeftForwardAction(), ) where {TAD<:ActionDirection} return RowwiseMultiplicationAction{typeof(M),typeof(On),TAD}(M, On) end @@ -191,7 +227,7 @@ end const LeftRowwiseMultiplicationAction{ TM<:AbstractManifold, TO<:GeneralUnitaryMultiplicationGroup, -} = RowwiseMultiplicationAction{TM,TO,LeftAction} +} = RowwiseMultiplicationAction{TM,TO,LeftForwardAction} function apply(::LeftRowwiseMultiplicationAction, a, p) return (a * p')' @@ -229,7 +265,7 @@ of type `On` columns of points on a matrix manifold `M`. ColumnwiseMultiplicationAction( M::AbstractManifold, On::GeneralUnitaryMultiplicationGroup, - AD::ActionDirection = LeftAction(), + AD::ActionDirection = LeftForwardAction(), ) """ struct ColumnwiseMultiplicationAction{ @@ -244,7 +280,7 @@ end function ColumnwiseMultiplicationAction( M::AbstractManifold, On::GeneralUnitaryMultiplicationGroup, - ::TAD=LeftAction(), + ::TAD=LeftForwardAction(), ) where {TAD<:ActionDirection} return ColumnwiseMultiplicationAction{typeof(M),typeof(On),TAD}(M, On) end @@ -252,7 +288,7 @@ end const LeftColumnwiseMultiplicationAction{ TM<:AbstractManifold, TO<:GeneralUnitaryMultiplicationGroup, -} = ColumnwiseMultiplicationAction{TM,TO,LeftAction} +} = ColumnwiseMultiplicationAction{TM,TO,LeftForwardAction} function apply(::LeftColumnwiseMultiplicationAction, a, p) return a * p diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index e6ee76dd2d..f144bc7ebb 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -136,7 +136,7 @@ function _compose!(G::SemidirectProductGroup, x, p, q) end @doc raw""" - translate_diff(G::SemidirectProductGroup, p, q, X, conX::LeftAction) + translate_diff(G::SemidirectProductGroup, p, q, X, conX::LeftForwardAction) Perform differential of the left translation on the semidirect product group `G`. @@ -152,9 +152,9 @@ then its differential can be computed as \mathrm{d}L_{(n', h')}(X_n, X_h) = ( \mathrm{d}L_{n'} (\mathrm{d}ΞΈ_{h'}(X_n)), \mathrm{d}L_{h'} X_h). ```` """ -translate_diff(G::SemidirectProductGroup, p, q, X, conX::LeftAction) +translate_diff(G::SemidirectProductGroup, p, q, X, conX::LeftForwardAction) -function translate_diff!(G::SemidirectProductGroup, Y, p, q, X, conX::LeftAction) +function translate_diff!(G::SemidirectProductGroup, Y, p, q, X, conX::LeftForwardAction) M = base_manifold(G) N, H = M.manifolds A = G.op.action diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index 7ebdfe136c..4733702056 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -29,7 +29,7 @@ const SpecialEuclidean{N} = SemidirectProductGroup{ ℝ, TranslationGroup{Tuple{N},ℝ}, SpecialOrthogonal{N}, - RotationAction{TranslationGroup{Tuple{N},ℝ},SpecialOrthogonal{N},LeftAction}, + RotationAction{TranslationGroup{Tuple{N},ℝ},SpecialOrthogonal{N},LeftForwardAction}, } const SpecialEuclideanManifold{N} = @@ -43,7 +43,7 @@ function SpecialEuclidean(n) end const SpecialEuclideanOperation{N} = SemidirectProductOperation{ - RotationAction{TranslationGroup{Tuple{N},ℝ},SpecialOrthogonal{N},LeftAction}, + RotationAction{TranslationGroup{Tuple{N},ℝ},SpecialOrthogonal{N},LeftForwardAction}, } const SpecialEuclideanIdentity{N} = Identity{SpecialEuclideanOperation{N}} @@ -585,7 +585,7 @@ function lie_bracket!(G::SpecialEuclidean, Z, X, Y) end """ - translate_diff(G::SpecialEuclidean, p, q, X, ::RightAction) + translate_diff(G::SpecialEuclidean, p, q, X, ::RightBackwardAction) Differential of the right action of the [`SpecialEuclidean`](@ref) group on itself. The formula for the rotation part is the differential of the right rotation action, while @@ -596,9 +596,9 @@ R_qβ‹…X_Rβ‹…t_p + X_t where ``R_q`` is the rotation part of `q`, ``X_R`` is the rotation part of `X`, ``t_p`` is the translation part of `p` and ``X_t`` is the translation part of `X`. """ -translate_diff(G::SpecialEuclidean, p, q, X, ::RightAction) +translate_diff(G::SpecialEuclidean, p, q, X, ::RightBackwardAction) -function translate_diff!(G::SpecialEuclidean, Y, p, q, X, ::RightAction) +function translate_diff!(G::SpecialEuclidean, Y, p, q, X, ::RightBackwardAction) np, hp = submanifold_components(G, p) nq, hq = submanifold_components(G, q) nX, hX = submanifold_components(G, X) diff --git a/src/groups/special_linear.jl b/src/groups/special_linear.jl index 02f2853188..7d2f848d99 100644 --- a/src/groups/special_linear.jl +++ b/src/groups/special_linear.jl @@ -45,7 +45,7 @@ function check_point(G::SpecialLinear{n,𝔽}, p; kwargs...) where {n,𝔽} end function check_vector(G::SpecialLinear, p, X; kwargs...) - trX = tr(inverse_translate_diff(G, p, p, X, LeftAction())) + trX = tr(inverse_translate_diff(G, p, p, X, LeftForwardAction())) if !isapprox(trX, 0; kwargs...) return DomainError( trX, @@ -61,8 +61,8 @@ embed(::SpecialLinear, p, X) = X get_embedding(::SpecialLinear{n,𝔽}) where {n,𝔽} = GeneralLinear(n, 𝔽) -inverse_translate_diff(::SpecialLinear, p, q, X, ::LeftAction) = X -inverse_translate_diff(::SpecialLinear, p, q, X, ::RightAction) = p * X / p +inverse_translate_diff(::SpecialLinear, p, q, X, ::LeftForwardAction) = X +inverse_translate_diff(::SpecialLinear, p, q, X, ::RightBackwardAction) = p * X / p function inverse_translate_diff!(G::SpecialLinear, Y, p, q, X, conv::ActionDirection) return copyto!(Y, inverse_translate_diff(G, p, q, X, conv)) @@ -120,16 +120,16 @@ where the last expression uses the tangent space representation as the Lie algeb project(::SpecialLinear, p, X) function project!(G::SpecialLinear{n}, Y, p, X) where {n} - inverse_translate_diff!(G, Y, p, p, X, LeftAction()) + inverse_translate_diff!(G, Y, p, p, X, LeftForwardAction()) Y[diagind(n, n)] .-= tr(Y) / n - translate_diff!(G, Y, p, p, Y, LeftAction()) + translate_diff!(G, Y, p, p, Y, LeftForwardAction()) return Y end Base.show(io::IO, ::SpecialLinear{n,𝔽}) where {n,𝔽} = print(io, "SpecialLinear($n, $𝔽)") -translate_diff(::SpecialLinear, p, q, X, ::LeftAction) = X -translate_diff(::SpecialLinear, p, q, X, ::RightAction) = p \ X * p +translate_diff(::SpecialLinear, p, q, X, ::LeftForwardAction) = X +translate_diff(::SpecialLinear, p, q, X, ::RightBackwardAction) = p \ X * p function translate_diff!(G::SpecialLinear, Y, p, q, X, conv::ActionDirection) return copyto!(Y, translate_diff(G, p, q, X, conv)) diff --git a/src/groups/special_unitary.jl b/src/groups/special_unitary.jl index 9cef98aef6..7e69e22de8 100644 --- a/src/groups/special_unitary.jl +++ b/src/groups/special_unitary.jl @@ -64,10 +64,10 @@ function project!(::SpecialUnitary{n}, q, p) where {n} return q end function project!(G::SpecialUnitary{n}, Y, p, X) where {n} - inverse_translate_diff!(G, Y, p, p, X, LeftAction()) + inverse_translate_diff!(G, Y, p, p, X, LeftForwardAction()) project!(SkewHermitianMatrices(n, β„‚), Y, Y) Y[diagind(n, n)] .-= tr(Y) / n - translate_diff!(G, Y, p, p, Y, LeftAction()) + translate_diff!(G, Y, p, p, Y, LeftForwardAction()) return Y end diff --git a/src/groups/translation_action.jl b/src/groups/translation_action.jl index 557e969e9c..53b493bee7 100644 --- a/src/groups/translation_action.jl +++ b/src/groups/translation_action.jl @@ -2,7 +2,7 @@ TranslationAction( M::AbstractManifold, Rn::TranslationGroup, - AD::ActionDirection = LeftAction(), + AD::ActionDirection = LeftForwardAction(), ) Space of actions of the [`TranslationGroup`](@ref) $\mathrm{T}(n)$ on a Euclidean-like @@ -19,7 +19,7 @@ end function TranslationAction( M::AbstractManifold, Rn::TranslationGroup, - ::TAD=LeftAction(), + ::TAD=LeftForwardAction(), ) where {TAD<:ActionDirection} return TranslationAction{typeof(M),typeof(Rn),TAD}(M, Rn) end @@ -32,8 +32,11 @@ base_group(A::TranslationAction) = A.Rn group_manifold(A::TranslationAction) = A.manifold -function switch_direction(A::TranslationAction{TM,TRN,TAD}) where {TM,TRN,TAD} - return TranslationAction(A.manifold, A.Rn, switch_direction(TAD())) +function switch_direction( + A::TranslationAction{TM,TSO,TAD}, + ::LeftRightSwitch=LeftRightSwitch(), +) where {TM<:AbstractManifold,TSO<:TranslationGroup,TAD<:ActionDirection} + return TranslationAction(A.manifold, A.Rn, switch_direction(TAD(), LeftRightSwitch())) end adjoint_apply_diff_group(::TranslationAction, a, X, p) = X @@ -62,11 +65,17 @@ function apply_diff!(A::TranslationAction, Y, a, p, X) return copyto!(A.manifold, Y, p, X) end -function apply_diff_group(::TranslationAction{N,F,LeftAction}, a, X, p) where {N,F} +function apply_diff_group(::TranslationAction{N,F,LeftForwardAction}, a, X, p) where {N,F} return X end -function apply_diff_group!(A::TranslationAction{N,F,LeftAction}, Y, a, X, p) where {N,F} +function apply_diff_group!( + A::TranslationAction{N,F,LeftForwardAction}, + Y, + a, + X, + p, +) where {N,F} copyto!(A.manifold, Y, p, X) return Y end diff --git a/test/groups/circle_group.jl b/test/groups/circle_group.jl index 513a5ad2b8..48b6435d88 100644 --- a/test/groups/circle_group.jl +++ b/test/groups/circle_group.jl @@ -11,8 +11,8 @@ include("group_utils.jl") @test base_manifold(G) === Circle{β„‚}() - @test has_invariant_metric(G, LeftAction()) - @test has_invariant_metric(G, RightAction()) + @test has_invariant_metric(G, LeftForwardAction()) + @test has_invariant_metric(G, RightBackwardAction()) @test has_biinvariant_metric(G) @test is_default_metric(MetricManifold(G, EuclideanMetric())) @test is_group_manifold(G) @@ -94,8 +94,8 @@ end @test base_manifold(G) === Circle{ℝ}() - @test has_invariant_metric(G, LeftAction()) - @test has_invariant_metric(G, RightAction()) + @test has_invariant_metric(G, LeftForwardAction()) + @test has_invariant_metric(G, RightBackwardAction()) @test has_biinvariant_metric(G) @test is_default_metric(MetricManifold(G, EuclideanMetric())) diff --git a/test/groups/general_linear.jl b/test/groups/general_linear.jl index 9462273c99..b41ca1abd4 100644 --- a/test/groups/general_linear.jl +++ b/test/groups/general_linear.jl @@ -88,13 +88,13 @@ using NLsolve vpts = [[-1 -2 0; -2 1 -2; 2 0 2], [1 1 1; 0 0 -2; 2 0 0]] retraction_methods = [ - Manifolds.GroupExponentialRetraction(LeftAction()), - Manifolds.GroupExponentialRetraction(RightAction()), + Manifolds.GroupExponentialRetraction(LeftForwardAction()), + Manifolds.GroupExponentialRetraction(RightBackwardAction()), ] inverse_retraction_methods = [ - Manifolds.GroupLogarithmicInverseRetraction(LeftAction()), - Manifolds.GroupLogarithmicInverseRetraction(RightAction()), + Manifolds.GroupLogarithmicInverseRetraction(LeftForwardAction()), + Manifolds.GroupLogarithmicInverseRetraction(RightBackwardAction()), ] basis_types = [DefaultOrthonormalBasis(), ProjectedOrthonormalBasis(:svd)] @@ -164,13 +164,13 @@ using NLsolve vpts = [[1+0im -2-1im; -1-2im -4+1im], [-2+2im -1-1im; -1-1im -3+0im]] retraction_methods = [ - Manifolds.GroupExponentialRetraction(LeftAction()), - Manifolds.GroupExponentialRetraction(RightAction()), + Manifolds.GroupExponentialRetraction(LeftForwardAction()), + Manifolds.GroupExponentialRetraction(RightBackwardAction()), ] inverse_retraction_methods = [ - Manifolds.GroupLogarithmicInverseRetraction(LeftAction()), - Manifolds.GroupLogarithmicInverseRetraction(RightAction()), + Manifolds.GroupLogarithmicInverseRetraction(LeftForwardAction()), + Manifolds.GroupLogarithmicInverseRetraction(RightBackwardAction()), ] for T in types diff --git a/test/groups/group_operation_action.jl b/test/groups/group_operation_action.jl index 7aa2896976..d32bddd68c 100644 --- a/test/groups/group_operation_action.jl +++ b/test/groups/group_operation_action.jl @@ -4,18 +4,20 @@ include("group_utils.jl") @testset "Group operation action" begin G = GroupManifold(NotImplementedManifold(), Manifolds.MultiplicationOperation()) - A_left = GroupOperationAction(G) - A_right = GroupOperationAction(G, RightAction()) + A_left_fwd = GroupOperationAction(G) + A_left_back = GroupOperationAction(G, LeftBackwardAction()) + A_right_fwd = GroupOperationAction(G, RightForwardAction()) + A_right_back = GroupOperationAction(G, RightBackwardAction()) types = [Matrix{Float64}] - @test group_manifold(A_left) === G - @test base_group(A_left) == G - @test repr(A_left) == "GroupOperationAction($(repr(G)), LeftAction())" - @test repr(A_right) == "GroupOperationAction($(repr(G)), RightAction())" + @test group_manifold(A_left_fwd) === G + @test base_group(A_left_fwd) == G + @test repr(A_left_fwd) == "GroupOperationAction($(repr(G)), LeftForwardAction())" + @test repr(A_right_back) == "GroupOperationAction($(repr(G)), RightBackwardAction())" - @test switch_direction(LeftAction()) == RightAction() - @test switch_direction(RightAction()) == LeftAction() + @test switch_direction(LeftForwardAction()) === RightBackwardAction() + @test switch_direction(RightBackwardAction()) === LeftForwardAction() for type in types a_pts = convert.(type, [reshape(i:(i + 3), 2, 2) for i in 1:3]) @@ -24,28 +26,32 @@ include("group_utils.jl") atol = eltype(m_pts[1]) == Float32 ? 1e-5 : 1e-10 test_action( - A_left, + A_left_fwd, a_pts, m_pts; test_optimal_alignment=false, test_diff=false, atol=atol, + test_switch_direction=Manifolds.SimultaneousSwitch(), ) test_action( - A_right, + A_right_back, a_pts, m_pts; test_optimal_alignment=false, test_diff=false, atol=atol, + test_switch_direction=Manifolds.SimultaneousSwitch(), ) end G = SpecialOrthogonal(3) M = Rotations(3) - A_left = GroupOperationAction(G) - A_right = GroupOperationAction(G, RightAction()) + A_left_fwd = GroupOperationAction(G) + A_left_back = GroupOperationAction(G, LeftBackwardAction()) + A_right_fwd = GroupOperationAction(G, RightForwardAction()) + A_right_back = GroupOperationAction(G, RightBackwardAction()) p = Matrix{Float64}(I, 3, 3) aΟ‰ = [[1.0, 2.0, 3.0], [3.0, 2.0, 1.0], [1.0, 3.0, 2.0]] @@ -58,26 +64,63 @@ include("group_utils.jl") hat(M, p, [0.5, 0.5, 0.5]), ] - @test group_manifold(A_left) === G - @test base_group(A_left) == G - @test repr(A_left) == "GroupOperationAction($(repr(G)), LeftAction())" - @test repr(A_right) == "GroupOperationAction($(repr(G)), RightAction())" - - test_action(A_left, a_pts, m_pts, X_pts; test_optimal_alignment=true, test_diff=true) - - test_action(A_right, a_pts, m_pts, X_pts; test_optimal_alignment=true, test_diff=true) + @test group_manifold(A_left_fwd) === G + @test base_group(A_left_fwd) == G + @test repr(A_left_fwd) == "GroupOperationAction($(repr(G)), LeftForwardAction())" + @test repr(A_right_back) == "GroupOperationAction($(repr(G)), RightBackwardAction())" + + test_action( + A_left_fwd, + a_pts, + m_pts, + X_pts; + test_optimal_alignment=true, + test_diff=true, + test_switch_direction=Manifolds.SimultaneousSwitch(), + ) + + test_action( + A_left_back, + a_pts, + m_pts, + X_pts; + test_optimal_alignment=true, + test_diff=true, + test_switch_direction=Manifolds.SimultaneousSwitch(), + ) + + test_action( + A_right_fwd, + a_pts, + m_pts, + X_pts; + test_optimal_alignment=true, + test_diff=true, + test_switch_direction=Manifolds.SimultaneousSwitch(), + ) + + test_action( + A_right_back, + a_pts, + m_pts, + X_pts; + test_optimal_alignment=true, + test_diff=true, + test_switch_direction=Manifolds.SimultaneousSwitch(), + ) @testset "apply_diff_group" begin - @test apply_diff_group(A_left, a_pts[1], X_pts[1], m_pts[1]) β‰ˆ - translate_diff(G, m_pts[1], a_pts[1], X_pts[1], RightAction()) + @test apply_diff_group(A_left_fwd, a_pts[1], X_pts[1], m_pts[1]) β‰ˆ + translate_diff(G, m_pts[1], a_pts[1], X_pts[1], RightBackwardAction()) Y = similar(X_pts[1]) - apply_diff_group!(A_left, Y, a_pts[1], X_pts[1], m_pts[1]) - @test Y β‰ˆ translate_diff(G, m_pts[1], a_pts[1], X_pts[1], RightAction()) + apply_diff_group!(A_left_fwd, Y, a_pts[1], X_pts[1], m_pts[1]) + @test Y β‰ˆ translate_diff(G, m_pts[1], a_pts[1], X_pts[1], RightBackwardAction()) - @test adjoint_apply_diff_group(A_left, a_pts[1], X_pts[1], m_pts[1]) β‰ˆ - inverse_translate_diff(G, a_pts[1], m_pts[1], X_pts[1], RightAction()) + @test adjoint_apply_diff_group(A_left_fwd, a_pts[1], X_pts[1], m_pts[1]) β‰ˆ + inverse_translate_diff(G, a_pts[1], m_pts[1], X_pts[1], RightBackwardAction()) Y = similar(X_pts[1]) - adjoint_apply_diff_group!(A_left, Y, a_pts[1], X_pts[1], m_pts[1]) - @test Y β‰ˆ inverse_translate_diff(G, a_pts[1], m_pts[1], X_pts[1], RightAction()) + adjoint_apply_diff_group!(A_left_fwd, Y, a_pts[1], X_pts[1], m_pts[1]) + @test Y β‰ˆ + inverse_translate_diff(G, a_pts[1], m_pts[1], X_pts[1], RightBackwardAction()) end end diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 713f4802e0..5ca867fa9f 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -84,32 +84,39 @@ include("group_utils.jl") @test_throws MethodError compose!(G, p, eg, eg) @test_throws MethodError translate(G, p, p) - @test_throws MethodError translate(G, p, p, LeftAction()) - @test_throws MethodError translate(G, p, p, RightAction()) + @test_throws MethodError translate(G, p, p, LeftForwardAction()) + @test_throws MethodError translate(G, p, p, RightBackwardAction()) @test_throws MethodError translate!(G, p, p, p) - @test_throws MethodError translate!(G, p, p, p, LeftAction()) - @test_throws MethodError translate!(G, p, p, p, RightAction()) + @test_throws MethodError translate!(G, p, p, p, LeftForwardAction()) + @test_throws MethodError translate!(G, p, p, p, RightBackwardAction()) @test_throws MethodError inverse_translate(G, p, p) - @test_throws MethodError inverse_translate(G, p, p, LeftAction()) - @test_throws MethodError inverse_translate(G, p, p, RightAction()) + @test_throws MethodError inverse_translate(G, p, p, LeftForwardAction()) + @test_throws MethodError inverse_translate(G, p, p, RightBackwardAction()) @test_throws MethodError inverse_translate!(G, p, p, p) - @test_throws MethodError inverse_translate!(G, p, p, p, LeftAction()) - @test_throws MethodError inverse_translate!(G, p, p, p, RightAction()) + @test_throws MethodError inverse_translate!(G, p, p, p, LeftForwardAction()) + @test_throws MethodError inverse_translate!(G, p, p, p, RightBackwardAction()) @test_throws MethodError translate_diff(G, p, p, X) - @test_throws MethodError translate_diff(G, p, p, X, LeftAction()) - @test_throws MethodError translate_diff(G, p, p, X, RightAction()) + @test_throws MethodError translate_diff(G, p, p, X, LeftForwardAction()) + @test_throws MethodError translate_diff(G, p, p, X, RightBackwardAction()) @test_throws MethodError translate_diff!(G, X, p, p, X) - @test_throws MethodError translate_diff!(G, X, p, p, X, LeftAction()) - @test_throws MethodError translate_diff!(G, X, p, p, X, RightAction()) + @test_throws MethodError translate_diff!(G, X, p, p, X, LeftForwardAction()) + @test_throws MethodError translate_diff!(G, X, p, p, X, RightBackwardAction()) @test_throws MethodError inverse_translate_diff(G, p, p, X) - @test_throws MethodError inverse_translate_diff(G, p, p, X, LeftAction()) - @test_throws MethodError inverse_translate_diff(G, p, p, X, RightAction()) + @test_throws MethodError inverse_translate_diff(G, p, p, X, LeftForwardAction()) + @test_throws MethodError inverse_translate_diff(G, p, p, X, RightBackwardAction()) @test_throws MethodError inverse_translate_diff!(G, X, p, p, X) - @test_throws MethodError inverse_translate_diff!(G, X, p, p, X, LeftAction()) - @test_throws MethodError inverse_translate_diff!(G, X, p, p, X, RightAction()) + @test_throws MethodError inverse_translate_diff!(G, X, p, p, X, LeftForwardAction()) + @test_throws MethodError inverse_translate_diff!( + G, + X, + p, + p, + X, + RightBackwardAction(), + ) @test_throws MethodError exp_lie(G, X) @test_throws MethodError exp_lie!(G, p, X) @@ -119,11 +126,32 @@ include("group_utils.jl") end @testset "Action direction" begin - @test switch_direction(LeftAction()) == RightAction() - @test switch_direction(RightAction()) == LeftAction() + @test switch_direction(LeftBackwardAction()) === RightForwardAction() + @test switch_direction(LeftForwardAction()) === RightBackwardAction() + @test switch_direction(RightBackwardAction()) === LeftForwardAction() + @test switch_direction(RightForwardAction()) === LeftBackwardAction() + + @test switch_direction(LeftBackwardAction(), Manifolds.LeftRightSwitch()) === + RightBackwardAction() + @test switch_direction(LeftForwardAction(), Manifolds.LeftRightSwitch()) === + RightForwardAction() + @test switch_direction(RightBackwardAction(), Manifolds.LeftRightSwitch()) === + LeftBackwardAction() + @test switch_direction(RightForwardAction(), Manifolds.LeftRightSwitch()) === + LeftForwardAction() - @test Manifolds._action_order(1, 2, LeftAction()) === (1, 2) - @test Manifolds._action_order(1, 2, RightAction()) === (2, 1) + @test switch_direction(LeftBackwardAction(), Manifolds.ForwardBackwardSwitch()) === + LeftForwardAction() + @test switch_direction(LeftForwardAction(), Manifolds.ForwardBackwardSwitch()) === + LeftBackwardAction() + @test switch_direction(RightBackwardAction(), Manifolds.ForwardBackwardSwitch()) === + RightForwardAction() + @test switch_direction(RightForwardAction(), Manifolds.ForwardBackwardSwitch()) === + RightBackwardAction() + + G = GroupManifold(NotImplementedManifold(), NotImplementedOperation()) + @test Manifolds._action_order(G, 1, 2, LeftForwardAction()) === (1, 2) + @test Manifolds._action_order(G, 1, 2, RightBackwardAction()) === (2, 1) end @testset "Addition operation" begin @@ -268,7 +296,7 @@ include("group_utils.jl") end end -struct NotImplementedAction <: AbstractGroupAction{LeftAction} end +struct NotImplementedAction <: AbstractGroupAction{LeftForwardAction} end @testset "General group action tests" begin @testset "Not implemented operations" begin diff --git a/test/groups/metric.jl b/test/groups/metric.jl index e4abe5dc5c..793c7333cb 100644 --- a/test/groups/metric.jl +++ b/test/groups/metric.jl @@ -108,23 +108,28 @@ end @test !isapprox(G, e, Identity(AdditionOperation())) @test has_biinvariant_metric(G) @test !has_biinvariant_metric(Sphere(2)) - Z = translate_diff(G, p, q, X, LeftAction()) - @test isapprox(SO3, q, Z, translate_diff(SO3, p, q, X, LeftAction())) + Z = translate_diff(G, p, q, X, LeftForwardAction()) + @test isapprox(SO3, q, Z, translate_diff(SO3, p, q, X, LeftForwardAction())) Z2 = similar(Z) - translate_diff!(G, Z2, p, q, X, LeftAction()) + translate_diff!(G, Z2, p, q, X, LeftForwardAction()) @test isapprox(SO3, q, Z, Z2) - Z3 = inverse_translate_diff(G, p, q, X, LeftAction()) - @test isapprox(SO3, q, Z3, inverse_translate_diff(SO3, p, q, X, LeftAction())) + Z3 = inverse_translate_diff(G, p, q, X, LeftForwardAction()) + @test isapprox( + SO3, + q, + Z3, + inverse_translate_diff(SO3, p, q, X, LeftForwardAction()), + ) Z4 = similar(Z3) - inverse_translate_diff!(G, Z4, p, q, X, LeftAction()) + inverse_translate_diff!(G, Z4, p, q, X, LeftForwardAction()) @test isapprox(SO3, q, Z3, Z4) end @testset "invariant metric direction" begin - @test direction(HasRightInvariantMetric()) === RightAction() - @test direction(HasLeftInvariantMetric()) === LeftAction() - @test direction(HasRightInvariantMetric) === RightAction() - @test direction(HasLeftInvariantMetric) === LeftAction() + @test direction(HasRightInvariantMetric()) === RightBackwardAction() + @test direction(HasLeftInvariantMetric()) === LeftForwardAction() + @test direction(HasRightInvariantMetric) === RightBackwardAction() + @test direction(HasLeftInvariantMetric) === LeftForwardAction() end @testset "invariant metrics on SE(3)" begin @@ -162,7 +167,7 @@ end test_diff=true, test_lie_bracket=true, test_adjoint_action=true, - diff_convs=[(), (LeftAction(),), (RightAction(),)], + diff_convs=[(), (LeftForwardAction(),), (RightBackwardAction(),)], ) test_manifold( G, diff --git a/test/groups/rotation_action.jl b/test/groups/rotation_action.jl index 71be2acd73..725b4a0f26 100644 --- a/test/groups/rotation_action.jl +++ b/test/groups/rotation_action.jl @@ -6,11 +6,12 @@ include("group_utils.jl") M = Rotations(2) G = SpecialOrthogonal(2) A_left = RotationAction(Euclidean(2), G) - A_right = RotationAction(Euclidean(2), G, RightAction()) + A_right = RotationAction(Euclidean(2), G, RightForwardAction()) - @test repr(A_left) == "RotationAction($(repr(Euclidean(2))), $(repr(G)), LeftAction())" + @test repr(A_left) == + "RotationAction($(repr(Euclidean(2))), $(repr(G)), LeftForwardAction())" @test repr(A_right) == - "RotationAction($(repr(Euclidean(2))), $(repr(G)), RightAction())" + "RotationAction($(repr(Euclidean(2))), $(repr(G)), RightForwardAction())" types_a = [Matrix{Float64}] @@ -18,7 +19,7 @@ include("group_utils.jl") @test group_manifold(A_left) == Euclidean(2) @test base_group(A_left) == G - @test isa(A_left, AbstractGroupAction{LeftAction}) + @test isa(A_left, AbstractGroupAction{<:LeftForwardAction}) @test base_manifold(G) == M for (i, T_A, T_M) in zip(1:length(types_a), types_a, types_m) @@ -75,7 +76,7 @@ end @test group_manifold(A) == Euclidean(3) @test base_group(A) == G - @test isa(A, AbstractGroupAction{LeftAction}) + @test isa(A, AbstractGroupAction{LeftForwardAction}) @test base_manifold(G) == M for (i, T_A, T_M) in zip(1:length(types_a), types_a, types_m) diff --git a/test/groups/special_euclidean.jl b/test/groups/special_euclidean.jl index 3dddf9a810..d9aa56e845 100644 --- a/test/groups/special_euclidean.jl +++ b/test/groups/special_euclidean.jl @@ -95,7 +95,7 @@ Random.seed!(10) test_exp_from_identity=true, test_log_from_identity=true, test_vee_hat_from_identity=true, - diff_convs=[(), (LeftAction(),), (RightAction(),)], + diff_convs=[(), (LeftForwardAction(),), (RightBackwardAction(),)], ) test_manifold( G, @@ -121,7 +121,11 @@ Random.seed!(10) test_diff=true, test_lie_bracket=true, test_adjoint_action=true, - diff_convs=[(), (LeftAction(),), (RightAction(),)], + diff_convs=[ + (), + (LeftForwardAction(),), + (RightBackwardAction(),), + ], ) test_manifold( @@ -147,7 +151,11 @@ Random.seed!(10) test_diff=true, test_lie_bracket=true, test_adjoint_action=true, - diff_convs=[(), (LeftAction(),), (RightAction(),)], + diff_convs=[ + (), + (LeftForwardAction(),), + (RightBackwardAction(),), + ], ) test_manifold( @@ -181,7 +189,7 @@ Random.seed!(10) X_pts; test_diff=true, test_lie_bracket=true, - diff_convs=[(), (LeftAction(),), (RightAction(),)], + diff_convs=[(), (LeftForwardAction(),), (RightBackwardAction(),)], atol=1e-9, ) test_manifold( @@ -301,7 +309,7 @@ Random.seed!(10) project!(SEGL, X2, pts_gl[1], X_gl) @test isapprox(G, pts[1], X, X2) - for conv in [LeftAction(), RightAction()] + for conv in [LeftForwardAction(), RightBackwardAction()] tpgl = translate(GL, pts_gl[2], pts_gl[1], conv) tXgl = translate_diff(GL, pts_gl[2], pts_gl[1], X_gl, conv) tpse = translate(G, pts[2], pts[1], conv) diff --git a/test/groups/special_linear.jl b/test/groups/special_linear.jl index 7e30722dab..dc1651081f 100644 --- a/test/groups/special_linear.jl +++ b/test/groups/special_linear.jl @@ -65,13 +65,13 @@ using NLsolve vpts = [[0 -1 -5; 1 2 0; 1 2 -2], [0 -2 1; -2 1 2; -4 2 -1]] retraction_methods = [ - Manifolds.GroupExponentialRetraction(LeftAction()), - Manifolds.GroupExponentialRetraction(RightAction()), + Manifolds.GroupExponentialRetraction(LeftForwardAction()), + Manifolds.GroupExponentialRetraction(RightBackwardAction()), ] inverse_retraction_methods = [ - Manifolds.GroupLogarithmicInverseRetraction(LeftAction()), - Manifolds.GroupLogarithmicInverseRetraction(RightAction()), + Manifolds.GroupLogarithmicInverseRetraction(LeftForwardAction()), + Manifolds.GroupLogarithmicInverseRetraction(RightBackwardAction()), ] for T in types @@ -167,13 +167,13 @@ using NLsolve vpts = [[0-1im -1+1im; -1+0im 0+1im], [1+1im 0+0im; 0+1im -1-1im]] retraction_methods = [ - Manifolds.GroupExponentialRetraction(LeftAction()), - Manifolds.GroupExponentialRetraction(RightAction()), + Manifolds.GroupExponentialRetraction(LeftForwardAction()), + Manifolds.GroupExponentialRetraction(RightBackwardAction()), ] inverse_retraction_methods = [ - Manifolds.GroupLogarithmicInverseRetraction(LeftAction()), - Manifolds.GroupLogarithmicInverseRetraction(RightAction()), + Manifolds.GroupLogarithmicInverseRetraction(LeftForwardAction()), + Manifolds.GroupLogarithmicInverseRetraction(RightBackwardAction()), ] for T in types diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index 3fcae91036..9f3f0faa06 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -39,8 +39,9 @@ include("group_utils.jl") gpts = convert.(T, pts) Xgpts = convert.(T, Xpts) @test compose(G, gpts[1], gpts[2]) β‰ˆ gpts[1] * gpts[2] - @test translate_diff(G, gpts[2], gpts[1], Xgpts[1], LeftAction()) β‰ˆ Xgpts[1] - @test translate_diff(G, gpts[2], gpts[1], Xgpts[1], RightAction()) β‰ˆ + @test translate_diff(G, gpts[2], gpts[1], Xgpts[1], LeftForwardAction()) β‰ˆ + Xgpts[1] + @test translate_diff(G, gpts[2], gpts[1], Xgpts[1], RightBackwardAction()) β‰ˆ transpose(gpts[2]) * Xgpts[1] * gpts[2] test_group( G, @@ -70,15 +71,15 @@ include("group_utils.jl") retraction_methods = [ Manifolds.PolarRetraction(), Manifolds.QRRetraction(), - Manifolds.GroupExponentialRetraction(LeftAction()), - Manifolds.GroupExponentialRetraction(RightAction()), + Manifolds.GroupExponentialRetraction(LeftForwardAction()), + Manifolds.GroupExponentialRetraction(RightBackwardAction()), ] inverse_retraction_methods = [ Manifolds.PolarInverseRetraction(), Manifolds.QRInverseRetraction(), - Manifolds.GroupLogarithmicInverseRetraction(LeftAction()), - Manifolds.GroupLogarithmicInverseRetraction(RightAction()), + Manifolds.GroupLogarithmicInverseRetraction(LeftForwardAction()), + Manifolds.GroupLogarithmicInverseRetraction(RightBackwardAction()), ] test_manifold( diff --git a/test/groups/translation_action.jl b/test/groups/translation_action.jl index 1348759b93..a278f323e4 100644 --- a/test/groups/translation_action.jl +++ b/test/groups/translation_action.jl @@ -7,9 +7,9 @@ include("group_utils.jl") G = TranslationGroup(2, 3) A = TranslationAction(Euclidean(2, 3), G) - @test repr(A) == "TranslationAction($(repr(M)), $(repr(G)), LeftAction())" + @test repr(A) == "TranslationAction($(repr(M)), $(repr(G)), LeftForwardAction())" @test repr(switch_direction(A)) == - "TranslationAction($(repr(M)), $(repr(G)), RightAction())" + "TranslationAction($(repr(M)), $(repr(G)), RightForwardAction())" types_a = [Matrix{Float64}] diff --git a/test/groups/translation_group.jl b/test/groups/translation_group.jl index b7db1085b4..07fac5d3b2 100644 --- a/test/groups/translation_group.jl +++ b/test/groups/translation_group.jl @@ -7,8 +7,8 @@ include("group_utils.jl") @test repr(G) == "TranslationGroup(2, 3; field = ℝ)" @test repr(TranslationGroup(2, 3; field=β„‚)) == "TranslationGroup(2, 3; field = β„‚)" - @test has_invariant_metric(G, LeftAction()) - @test has_invariant_metric(G, RightAction()) + @test has_invariant_metric(G, LeftForwardAction()) + @test has_invariant_metric(G, RightBackwardAction()) @test has_biinvariant_metric(G) @test is_default_metric(MetricManifold(G, EuclideanMetric())) === true @test is_group_manifold(G) diff --git a/test/groups/validation_group.jl b/test/groups/validation_group.jl index ba35e1e695..1c8db47dbb 100644 --- a/test/groups/validation_group.jl +++ b/test/groups/validation_group.jl @@ -74,7 +74,7 @@ include("../utils.jl") adjoint_action!(AG, Xaa, p, X2) @test isapprox(G, e, Xaa.value, adjoint_action(G, p, X2.value)) - for conv in (LeftAction(), RightAction()) + for conv in (LeftForwardAction(), RightBackwardAction()) @test translate(AG, p2, q2, conv) isa ValidationMPoint @test isapprox(G, translate(AG, p2, q2, conv).value, translate(G, p, q, conv)) @@ -94,7 +94,7 @@ include("../utils.jl") @test isapprox(G, pinvq.value, inverse_translate(G, p, q, conv)) end - for conv in (LeftAction(), RightAction()) + for conv in (LeftForwardAction(), RightBackwardAction()) @test translate_diff(AG, q2, p2, X2, conv; atol=1e-10) isa ValidationTVector @test isapprox( G,