-
Notifications
You must be signed in to change notification settings - Fork 56
/
Oblique.jl
87 lines (70 loc) · 3.33 KB
/
Oblique.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
@doc raw"""
Oblique{T,𝔽,S} <: AbstractPowerManifold{𝔽}
The oblique manifold $\mathcal{OB}(n,m)$ is the set of 𝔽-valued matrices with unit norm
column endowed with the metric from the embedding. This yields exactly the same metric as
considering the product metric of the unit norm vectors, i.e. [`PowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.PowerManifold) of the
$(n-1)$-dimensional [`Sphere`](@ref).
The [`Sphere`](@ref) is stored internally within `M.manifold`, such that all functions of
[`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) can be used directly.
# Constructor
Oblique(n::Int, m::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type)
Generate the manifold of matrices $\mathbb R^{n × m}$ such that the $m$ columns are unit
vectors, i.e. from the [`Sphere`](@ref)`(n-1)`.
"""
struct Oblique{T,𝔽,S} <: AbstractPowerManifold{𝔽,Sphere{S,𝔽},ArrayPowerRepresentation}
size::T
manifold::Sphere{S,𝔽}
end
function Oblique(n::Int, m::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type)
sphere = Sphere(n - 1, field; parameter=parameter)
size = wrap_type_parameter(parameter, (n, m))
return Oblique{typeof(size),field,typeof(sphere).parameters[1]}(size, sphere)
end
function Base.:^(::Sphere{TypeParameter{Tuple{N}},𝔽}, m::Int) where {N,𝔽}
return Oblique(N + 1, m, 𝔽)
end
function Base.:^(M::Sphere{Tuple{Int},𝔽}, m::Int) where {𝔽}
N = M.size[1]
return Oblique(N + 1, m, 𝔽; parameter=:field)
end
@doc raw"""
check_point(M::Oblique, p)
Checks whether `p` is a valid point on the [`Oblique`](@ref)`{m,n}` `M`, i.e. is a matrix
of `m` unit columns from $\mathbb R^{n}$, i.e. each column is a point from
[`Sphere`](@ref)`(n-1)`.
"""
check_point(::Oblique, ::Any)
function check_point(M::Oblique, p; kwargs...)
n, m = get_parameter(M.size)
return check_point(PowerManifold(M.manifold, m), p; kwargs...)
end
@doc raw"""
check_vector(M::Oblique p, X; kwargs...)
Checks whether `X` is a valid tangent vector to `p` on the [`Oblique`](@ref) `M`.
This means, that `p` is valid, that `X` is of correct dimension and columnswise
a tangent vector to the columns of `p` on the [`Sphere`](@ref).
"""
function check_vector(M::Oblique, p, X; kwargs...)
n, m = get_parameter(M.size)
return check_vector(PowerManifold(M.manifold, m), p, X; kwargs...)
end
get_iterator(M::Oblique) = Base.OneTo(get_parameter(M.size)[2])
function manifold_dimension(M::Oblique{<:Any,𝔽}) where {𝔽}
n, m = get_parameter(M.size)
return (n * real_dimension(𝔽) - 1) * m
end
power_dimensions(M::Oblique) = get_parameter(M.size)[2]
representation_size(M::Oblique) = get_parameter(M.size)
@doc raw"""
parallel_transport_to(M::Oblique, p, X, q)
Compute the parallel transport on the [`Oblique`](@ref) manifold by
doing a column wise parallel transport on the [`Sphere`](@ref)
"""
parallel_transport_to(::Oblique, p, X, q)
function Base.show(io::IO, ::Oblique{TypeParameter{Tuple{n,m}},𝔽}) where {n,m,𝔽}
return print(io, "Oblique($(n), $(m); field=$(𝔽))")
end
function Base.show(io::IO, M::Oblique{Tuple{Int,Int},𝔽}) where {𝔽}
n, m = get_parameter(M.size)
return print(io, "Oblique($(n), $(m); field=$(𝔽), parameter=:field)")
end