Skip to content

Commit

Permalink
Make switch_direction consistent (#639)
Browse files Browse the repository at this point in the history
* Make `switch_direction` consistent

* making rotation action more consistent

* fix

* fix 2

* extend group operation action direction support

* docs on directions

* fix
  • Loading branch information
mateuszbaran authored Jul 7, 2023
1 parent 4b80c6e commit 6168554
Show file tree
Hide file tree
Showing 31 changed files with 619 additions and 300 deletions.
4 changes: 2 additions & 2 deletions docs/src/manifolds/group.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
87 changes: 42 additions & 45 deletions ext/ManifoldsTestExt/tests_group.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -37,22 +37,22 @@ 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)
Test.@test is_point(G, g3, true; atol=atol)
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)
Expand All @@ -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())
Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -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,
)
Expand Down Expand Up @@ -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,
)
Expand Down Expand Up @@ -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])
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]))
Expand Down Expand Up @@ -516,6 +516,8 @@ function test_group(
return nothing
end

_direction_from_type(::AbstractGroupAction{TD}) where {TD<:ActionDirection} = TD()

"""
test_action(
A::AbstractGroupAction,
Expand Down Expand Up @@ -550,52 +552,47 @@ 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)
end
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))
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions src/Manifolds.jl
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,8 @@ export AbstractGroupAction,
Identity,
InvariantMetric,
LeftAction,
LeftBackwardAction,
LeftForwardAction,
LeftInvariantMetric,
MultiplicationOperation,
Orthogonal,
Expand All @@ -874,6 +876,8 @@ export AbstractGroupAction,
ProductOperation,
RealCircleGroup,
RightAction,
RightBackwardAction,
RightForwardAction,
RightInvariantMetric,
RotationAction,
SemidirectProductGroup,
Expand Down
8 changes: 4 additions & 4 deletions src/groups/circle_group.jl
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ function inverse_translate(
::CircleGroup,
p::AbstractArray{<:Any,0},
q::AbstractArray{<:Any,0},
::LeftAction,
::LeftForwardAction,
)
return map(/, q, p)
end
function inverse_translate(
::CircleGroup,
p::AbstractArray{<:Any,0},
q::AbstractArray{<:Any,0},
::RightAction,
::RightBackwardAction,
)
return map(/, q, p)
end
Expand Down Expand Up @@ -175,15 +175,15 @@ 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
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
Expand Down
Loading

2 comments on commit 6168554

@mateuszbaran
Copy link
Member Author

Choose a reason for hiding this comment

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

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

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

Registration pull request created: JuliaRegistries/General/87062

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.8.73 -m "<description of version>" 616855447996fb1ee7dfb2a779341b962a1323f8
git push origin v0.8.73

Please sign in to comment.