-
Notifications
You must be signed in to change notification settings - Fork 56
/
group_operation_action.jl
210 lines (180 loc) · 6.56 KB
/
group_operation_action.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
@doc raw"""
GroupOperationAction{AD<:ActionDirection,AS<:GroupActionSide,G<:AbstractDecoratorManifold} <: AbstractGroupAction{AD}
Action of a group upon itself via left or right translation, either from left or right side.
An element `p` of the group can act upon another another element by either:
* left action from the left side: ``L_p: q ↦ p \circ q``,
* right action from the left side: ``L'_p: q ↦ p^{-1} \circ q``,
* right action from the right side: ``R_p: q ↦ q \circ p``,
* left action from the right side: ``R'_p: q ↦ q \circ p^{-1}``.
# Constructor
GroupOperationAction(group::AbstractDecoratorManifold, AD::ActionDirectionAndSide = LeftForwardAction())
"""
struct GroupOperationAction{
AD<:ActionDirection,
AS<:GroupActionSide,
G<:AbstractDecoratorManifold,
} <: AbstractGroupAction{AD}
group::G
end
function GroupOperationAction(
G::TM,
::TAD=LeftForwardAction(),
) where {TM<:AbstractDecoratorManifold,TAD<:ActionDirectionAndSide}
return GroupOperationAction{TAD.parameters[1],TAD.parameters[2],TM}(G)
end
"""
action_side(A::GroupOperationAction)
Return whether [`GroupOperationAction`](@ref) `A` acts on the [`LeftSide`](@ref) or
[`RightSide`](@ref).
"""
action_side(::GroupOperationAction{AD,AS}) where {AD<:ActionDirection,AS<:GroupActionSide} =
AS()
function direction_and_side(
::GroupOperationAction{AD,AS},
) where {AD<:ActionDirection,AS<:GroupActionSide}
return (AD(), AS())
end
function reverse_direction_and_side(
::GroupOperationAction{AD,AS},
) where {AD<:ActionDirection,AS<:GroupActionSide}
return (switch_direction(AD()), switch_side(AS()))
end
function Base.show(io::IO, A::GroupOperationAction)
return print(io, "GroupOperationAction($(A.group), $(direction_and_side(A)))")
end
base_group(A::GroupOperationAction) = A.group
group_manifold(A::GroupOperationAction) = A.group
function switch_direction(A::GroupOperationAction)
return GroupOperationAction(A.group, (switch_direction(direction(A)), action_side(A)))
end
function switch_direction_and_side(A::GroupOperationAction)
return GroupOperationAction(A.group, reverse_direction_and_side(A))
end
function adjoint_apply_diff_group(A::GroupOperationAction, a, X, p)
G = base_group(A)
if direction_and_side(A) === LeftForwardAction() ||
direction_and_side(A) === RightBackwardAction()
return inverse_translate_diff(G, a, p, X, reverse_direction_and_side(A))
else
return inverse_translate_diff(
G,
p,
a,
inv_diff(G, apply(A, a, p), X),
(direction(A), switch_side(action_side(A))),
)
end
end
function adjoint_apply_diff_group!(A::GroupOperationAction, Y, a, X, p)
G = base_group(A)
if direction_and_side(A) === LeftForwardAction() ||
direction_and_side(A) === RightBackwardAction()
return inverse_translate_diff!(G, Y, a, p, X, reverse_direction_and_side(A))
else
return inverse_translate_diff!(
G,
Y,
p,
a,
inv_diff(G, apply(A, a, p), X),
(direction(A), switch_side(action_side(A))),
)
end
end
apply(A::GroupOperationAction, a, p) = translate(A.group, a, p, direction_and_side(A))
function apply!(A::GroupOperationAction, q, a, p)
return translate!(A.group, q, a, p, direction_and_side(A))
end
function inverse_apply(A::GroupOperationAction, a, p)
return inverse_translate(A.group, a, p, direction_and_side(A))
end
function inverse_apply!(A::GroupOperationAction, q, a, p)
return inverse_translate!(A.group, q, a, p, direction_and_side(A))
end
function apply_diff(A::GroupOperationAction, a, p, X)
return translate_diff(A.group, a, p, X, direction_and_side(A))
end
function apply_diff!(A::GroupOperationAction, Y, a, p, X)
return translate_diff!(A.group, Y, a, p, X, direction_and_side(A))
end
@doc raw"""
apply_diff_group(A::GroupOperationAction, a, X, p)
Compute differential of [`GroupOperationAction`](@ref) `A` with respect to group element
at tangent vector `X`:
````math
(\mathrm{d}τ^p) : T_{a} \mathcal G → T_{τ_a p} \mathcal G
````
There are four cases:
* left action from the left side: ``L_a: p ↦ a \circ p``, where
````math
(\mathrm{d}L_a) : T_{a} \mathcal G → T_{a \circ p} \mathcal G.
````
* right action from the left side: ``L'_a: p ↦ a^{-1} \circ p``, where
````math
(\mathrm{d}L'_a) : T_{a} \mathcal G → T_{a^{-1} \circ p} \mathcal G.
````
* right action from the right side: ``R_a: p ↦ p \circ a``, where
````math
(\mathrm{d}R_a) : T_{a} \mathcal G → T_{p \circ a} \mathcal G.
````
* left action from the right side: ``R'_a: p ↦ p \circ a^{-1}``, where
````math
(\mathrm{d}R'_a) : T_{a} \mathcal G → T_{p \circ a^{-1}} \mathcal G.
````
"""
function apply_diff_group(A::GroupOperationAction, a, X, p)
G = base_group(A)
if direction_and_side(A) === LeftForwardAction() ||
direction_and_side(A) === RightBackwardAction()
return translate_diff(G, p, a, X, reverse_direction_and_side(A))
else
return translate_diff(
G,
p,
a,
inv_diff(G, a, X),
(direction(A), switch_side(action_side(A))),
)
end
end
function apply_diff_group!(A::GroupOperationAction, Y, a, X, p)
G = base_group(A)
if direction_and_side(A) === LeftForwardAction() ||
direction_and_side(A) === RightBackwardAction()
return translate_diff!(G, Y, p, a, X, reverse_direction_and_side(A))
else
return translate_diff!(
G,
Y,
p,
a,
inv_diff(G, a, X),
(direction(A), switch_side(action_side(A))),
)
end
end
function inverse_apply_diff(A::GroupOperationAction, a, p, X)
return inverse_translate_diff(A.group, a, p, X, direction_and_side(A))
end
function inverse_apply_diff!(A::GroupOperationAction, Y, a, p, X)
return inverse_translate_diff!(A.group, Y, a, p, X, direction_and_side(A))
end
function optimal_alignment(A::GroupOperationAction, p, q)
return inverse_apply(switch_direction_and_side(A), p, q)
end
function optimal_alignment!(A::GroupOperationAction, x, p, q)
return inverse_apply!(switch_direction_and_side(A), x, p, q)
end
function center_of_orbit(
A::GroupOperationAction,
pts::AbstractVector,
p,
mean_method::AbstractEstimationMethod,
)
μ = mean(A.group, pts, mean_method)
return inverse_apply(switch_direction_and_side(A), p, μ)
end
function center_of_orbit(A::GroupOperationAction, pts::AbstractVector, p)
μ = mean(A.group, pts)
return inverse_apply(switch_direction_and_side(A), p, μ)
end