-
Notifications
You must be signed in to change notification settings - Fork 56
/
QuotientManifold.jl
190 lines (146 loc) · 6.42 KB
/
QuotientManifold.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
"""
IsQuotientManifold <: AbstractTrait
Specify that a certain decorated manifold is a quotient manifold in the sense that it provides
implicitly (or explicitly through [`QuotientManifold`](@ref) properties of a quotient manifold.
See [`QuotientManifold`](@ref) for more details.
"""
struct IsQuotientManifold <: AbstractTrait end
#
# (Explicit) Quotient manifolds
#
@doc raw"""
QuotientManifold{M <: AbstractManifold{𝔽}, N} <: AbstractManifold{𝔽}
Equip a manifold ``\mathcal M`` explicitly with the property of being a quotient manifold.
A manifold ``\mathcal M`` is then a a quotient manifold of another manifold ``\mathcal N``,
i.e. for an [equivalence relation](https://en.wikipedia.org/wiki/Equivalence_relation) ``∼``
on ``\mathcal N`` we have
```math
\mathcal M = \mathcal N / ∼ = \bigl\{ [p] : p ∈ \mathcal N \bigr\},
```
where ``[p] ≔ \{ q ∈ \mathcal N : q ∼ p\}`` denotes the equivalence class containing ``p``.
For more details see Subsection 3.4.1 [AbsilMahonySepulchre:2008](@cite).
This manifold type models an explicit quotient structure.
This should be done if either the default implementation of ``\mathcal M``
uses another representation different from the quotient structure or if
it provides a (default) quotient structure that is different from the one introduced here.
# Fields
* `manifold` – the manifold ``\mathcal M`` in the introduction above.
* `total_space` – the manifold ``\mathcal N`` in the introduction above.
# Constructor
QuotientManifold(M,N)
Create a manifold where `M` is the quotient manifold and `N`is its total space.
"""
struct QuotientManifold{𝔽,MT<:AbstractManifold{𝔽},NT<:AbstractManifold} <:
AbstractDecoratorManifold{𝔽}
manifold::MT
total_space::NT
end
@inline active_traits(f, ::QuotientManifold, ::Any...) = merge_traits(IsQuotientManifold())
@doc raw"""
canonical_project(M, p)
Compute the canonical projection ``π`` on a manifold ``\mathcal M`` that
[`IsQuotientManifold`](@ref), e.g. a [`QuotientManifold`](@ref).
The canonical (or natural) projection ``π`` from the total space ``\mathcal N``
onto ``\mathcal M`` given by
```math
π = π_{\mathcal N, \mathcal M} : \mathcal N → \mathcal M, p ↦ π_{\mathcal N, \mathcal M}(p) = [p].
```
in other words, this function implicitly assumes, that the total space ``\mathcal N`` is given,
for example explicitly when `M` is a [`QuotientManifold`](@ref) and `p` is a point on `N`.
"""
function canonical_project(M::AbstractManifold, p)
q = allocate_result(M, canonical_project, p)
return canonical_project!(M, q, p)
end
@doc raw"""
canonical_project!(M, q, p)
Compute the canonical projection ``π`` on a manifold ``\mathcal M`` that
[`IsQuotientManifold`](@ref), e.g. a [`QuotientManifold`](@ref) in place of `q`.
See [`canonical_project`](@ref) for more details.
"""
canonical_project!(M::AbstractManifold, q, p)
decorated_manifold(M::QuotientManifold) = M.manifold
@doc raw"""
differential_canonical_project(M, p, X)
Compute the differential of the canonical projection ``π`` on a manifold ``\mathcal M`` that
[`IsQuotientManifold`](@ref), e.g. a [`QuotientManifold`](@ref).
The canonical (or natural) projection ``π`` from the total space ``\mathcal N``
onto ``\mathcal M``, such that its differential
```math
Dπ(p) : T_p\mathcal N → T_{π(p)}\mathcal M
```
where again the total space might be implicitly assumed, or explicitly when using a
[`QuotientManifold`](@ref) `M`. So here `p` is a point on `N` and `X` is from ``T_p\mathcal N``.
"""
function differential_canonical_project(M::AbstractManifold, p, X)
q = allocate_result(M, differential_canonical_project, p, X)
return differential_canonical_project!(M, q, p, X)
end
@doc raw"""
differential_canonical_project!(M, Y, p, X)
Compute the differential of the canonical projection ``π`` on a manifold ``\mathcal M`` that
[`IsQuotientManifold`](@ref), e.g. a [`QuotientManifold`](@ref). See [`differential_canonical_project`](@ref) for details.
"""
differential_canonical_project!(M::AbstractManifold, q, p)
@doc raw"""
get_total_space(M::AbstractDecoratorManifold)
Return the total space of a manifold that [`IsQuotientManifold`](@ref), e.g.
a [`QuotientManifold`](@ref).
"""
get_total_space(::AbstractManifold)
get_total_space(M::QuotientManifold) = M.total_space
@doc raw"""
get_orbit_action(M::AbstractDecoratorManifold)
Return the group action that generates the orbit of an equivalence class of the quotient manifold `M`
for which equivalence classes are orbits of an action of a Lie group. For the case that
```math
\mathcal M = \mathcal N / \mathcal O,
```
where ``\mathcal O`` is a Lie group with its group action generating the orbit.
"""
get_orbit_action(::AbstractManifold)
@doc raw"""
horizontal_lift(N::AbstractManifold, q, X)
horizontal_lift(::QuotientManifold{𝔽,MT<:AbstractManifold{𝔽},NT<:AbstractManifold}, p, X) where {𝔽}
Given a point `q` in total space of quotient manifold `N` such that ``p=π(q)`` is a point on
a quotient manifold `M` (implicitly given for the first case) and a tangent vector `X` this
method computes a tangent vector `Y` on the horizontal space of ``T_q\mathcal N``,
i.e. the subspace that is orthogonal to the kernel of ``Dπ(q)``.
"""
function horizontal_lift(N::AbstractManifold, q, X)
Y = zero_vector(N, q)
return horizontal_lift!(N, Y, q, X)
end
@doc raw"""
horizontal_lift!(N, Y, q, X)
horizontal_lift!(QuotientManifold{M,N}, Y, p, X)
Compute the [`horizontal_lift`](@ref) of `X` from ``T_p\mathcal M``, ``p=π(q)``.
to ``T_q\mathcal N` in place of `Y`.
"""
horizontal_lift!(N::AbstractManifold, Y, q, X)
"""
horizontal_component(N::AbstractManifold, p, X)
Compute the horizontal component of tangent vector `X` at point `p`
in the total space of quotient manifold `N`.
"""
function horizontal_component(N::AbstractManifold, p, X)
Y = allocate_result(N, horizontal_component, X, p)
return horizontal_component!(N, Y, p, X)
end
function Base.show(io::IO, M::QuotientManifold)
return print(io, "QuotientManifold($(M.manifold), $(M.total_space))")
end
"""
vertical_component(N::AbstractManifold, p, X)
Compute the vertical component of tangent vector `X` at point `p`
in the total space of quotient manifold `N`.
"""
function vertical_component(N::AbstractManifold, p, X)
return X - horizontal_component(N, p, X)
end
function vertical_component!(N::AbstractManifold, Y, p, X)
horizontal_component!(N, Y, p, X)
Y .*= -1
Y .+= X
return Y
end