From 1d4d2fafa8d02dc3fabedf629e9099d79711cef7 Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Tue, 10 Oct 2023 13:29:38 +0200 Subject: [PATCH] restructure + some tests --- Project.toml | 2 +- src/ManifoldsBase.jl | 1 + src/TangentSpace.jl | 222 +++++++++++++++++++++++++++++++++++++++ src/VectorFiber.jl | 220 -------------------------------------- test/product_manifold.jl | 3 + 5 files changed, 227 insertions(+), 221 deletions(-) create mode 100644 src/TangentSpace.jl diff --git a/Project.toml b/Project.toml index 2e4d8900..67093211 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "ManifoldsBase" uuid = "3362f125-f0bb-47a3-aa74-596ffd7ef2fb" authors = ["Seth Axen ", "Mateusz Baran ", "Ronny Bergmann ", "Antoine Levitt "] -version = "0.15.0" +version = "0.14.30" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/src/ManifoldsBase.jl b/src/ManifoldsBase.jl index f997ab46..c7245100 100644 --- a/src/ManifoldsBase.jl +++ b/src/ManifoldsBase.jl @@ -969,6 +969,7 @@ include("nested_trait.jl") include("decorator_trait.jl") include("VectorFiber.jl") +include("TangentSpace.jl") include("ValidationManifold.jl") include("EmbeddedManifold.jl") include("DefaultManifold.jl") diff --git a/src/TangentSpace.jl b/src/TangentSpace.jl new file mode 100644 index 00000000..cad5f63e --- /dev/null +++ b/src/TangentSpace.jl @@ -0,0 +1,222 @@ + +@doc raw""" + TangentSpace{š”½,M} = Fiber{š”½,TangentSpaceType,M} where {š”½,M<:AbstractManifold{š”½}} + +A manifold for the tangent space ``T_p\mathcal M`` at a point ``p\in\mathcal M``. +This is modelled as an alias for [`VectorSpaceFiber`](@ref) corresponding to +[`TangentSpaceType`](@ref). + +# Constructor + + TangentSpace(M::AbstractManifold, p) + +Return the manifold (vector space) representing the tangent space ``T_p\mathcal M`` +at point `p`, ``p\in\mathcal M``. +""" +const TangentSpace{š”½,M} = Fiber{š”½,TangentSpaceType,M} where {š”½,M<:AbstractManifold{š”½}} + +TangentSpace(M::AbstractManifold, p) = Fiber(M, TangentSpaceType(), p) + +function allocate_result(M::TangentSpace, ::typeof(rand)) + return zero_vector(M.manifold, M.point) +end + +""" + distance(M::TangentSpace, p, q) + +Distance between vectors `p` and `q` from the vector space `M`. It is calculated as the norm +of their difference. +""" +function distance(M::TangentSpace, p, q) + return norm(M.manifold, M.point, q - p) +end + +function embed!(M::TangentSpace, q, p) + return embed!(M.manifold, q, M.point, p) +end +function embed!(M::TangentSpace, Y, p, X) + return embed!(M.manifold, Y, M.point, X) +end + +@doc raw""" + exp(M::TangentSpace, p, X) + +Exponential map of tangent vectors `X` and `p` from the tangent space `M`. It is +calculated as their sum. +""" +exp(::TangentSpace, ::Any, ::Any) + +function exp!(M::TangentSpace, q, p, X) + copyto!(M.manifold, q, p + X) + return q +end + +fiber_dimension(M::AbstractManifold, ::CotangentSpaceType) = manifold_dimension(M) +fiber_dimension(M::AbstractManifold, ::TangentSpaceType) = manifold_dimension(M) + +function get_basis(M::TangentSpace, p, B::CachedBasis) + return invoke( + get_basis, + Tuple{AbstractManifold,Any,CachedBasis}, + M.manifold, + M.point, + B, + ) +end +function get_basis(M::TangentSpace, p, B::AbstractBasis{<:Any,TangentSpaceType}) + return get_basis(M.manifold, M.point, B) +end + +function get_coordinates(M::TangentSpace, p, X, B::AbstractBasis) + return get_coordinates(M.manifold, M.point, X, B) +end + +function get_coordinates!(M::TangentSpace, Y, p, X, B::AbstractBasis) + return get_coordinates!(M.manifold, Y, M.point, X, B) +end + +function get_vector(M::TangentSpace, p, X, B::AbstractBasis) + return get_vector(M.manifold, M.point, X, B) +end + +function get_vector!(M::TangentSpace, Y, p, X, B::AbstractBasis) + return get_vector!(M.manifold, Y, M.point, X, B) +end + +function get_vectors(M::TangentSpace, p, B::CachedBasis) + return get_vectors(M.manifold, M.point, B) +end + +@doc raw""" + injectivity_radius(M::TangentSpace) + +Return the injectivity radius on the [`TangentSpace`](@ref) `M`, which is $āˆž$. +""" +injectivity_radius(::TangentSpace) = Inf + +@doc raw""" + inner(M::TangentSpace, X, Y, Z) + +For any ``XāˆˆT_p\mathcal M`` we identify the tangent space ``T_X(T_p\mathcal M)`` +with ``T_p\mathcal M`` again. Hence an inner product of ``Y,Z`` is just the inner product of +the tangent space itself. ``āŸØY,ZāŸ©_X = āŸØY,ZāŸ©_p``. +""" +function inner(M::TangentSpace, X, Y, Z) + return inner(M.manifold, M.point, Y, Z) +end + +""" + is_flat(::TangentSpace) + +Return true. [`TangentSpace`](@ref) is a flat manifold. +""" +is_flat(::TangentSpace) = true + +function _isapprox(M::TangentSpace, X, Y; kwargs...) + return isapprox(M.manifold, M.point, X, Y; kwargs...) +end + +""" + log(TpM::TangentSpace, p, q) + +Logarithmic map on the tangent space manifold `TpM`, calculated as the difference of tangent +vectors `q` and `p` from `TpM`. +""" +log(::TangentSpace, ::Any...) +function log!(::TangentSpace, X, p, q) + copyto!(X, q - p) + return X +end + +@doc raw""" + manifold_dimension(TpM::TangentSpace) + +Return the dimension of the tangent space ``T_p\mathcal M`` at ``pāˆˆ\mathcal M``, +which is the same as the dimension of the manifold ``\mathcal M``. +""" +function manifold_dimension(TpM::TangentSpace) + return manifold_dimension(TpM.manifold) +end + +@doc raw""" + parallel_transport_to(::TangentSpace, X, Z, Y) + +Transport the tangent vector ``Z āˆˆ T_X(T_p\mathcal M)`` from `X` to `Y`. +Since we identify ``T_X\mathcal M = T_p\mathcal M`` and the tangent space is a vector space, +parallel transport simplifies to the identity, so this function yield ``Z`` as a result. +""" +parallel_transport_to(TpM::TangentSpace, X, Z, Y) + +function parallel_transport_to!(TpM::TangentSpace, Y, p, X, q) + return copyto!(TpM.manifold, Y, p, X) +end + +@doc raw""" + project(M::TangentSpace, p) + +Project the point `p` from the tangent space `M`, that is project the vector `p` +tangent at `M.point`. +""" +project(::TangentSpace, ::Any) + +function project!(M::TangentSpace, q, p) + return project!(M.manifold, q, M.point, p) +end + +@doc raw""" + project(M::TangentSpace, p, X) + +Project the vector `X` from the tangent space `M`, that is project the vector `X` +tangent at `M.point`. +""" +project(::TangentSpace, ::Any, ::Any) + +function project!(M::TangentSpace, Y, p, X) + return project!(M.manifold, Y, M.point, X) +end + +function Random.rand!(M::TangentSpace, X; vector_at = nothing) + rand!(M.manifold, X; vector_at = M.point) + return X +end +function Random.rand!(rng::AbstractRNG, M::TangentSpace, X; vector_at = nothing) + rand!(rng, M.manifold, X; vector_at = M.point) + return X +end + +function representation_size(B::TangentSpace) + return representation_size(B.manifold) +end + +function Base.show(io::IO, ::MIME"text/plain", TpM::TangentSpace) + println(io, "Tangent space to the manifold $(base_manifold(TpM)) at point:") + pre = " " + sp = sprint(show, "text/plain", TpM.point; context = io, sizehint = 0) + sp = replace(sp, '\n' => "\n$(pre)") + return print(io, pre, sp) +end + +@doc raw""" + Y = Weingarten(M::TangentSpace, p, X, V) + Weingarten!(M::TangentSpace, Y, p, X, V) + +Compute the Weingarten map ``\mathcal W_p`` at `p` on the [`TangentSpace`](@ref) `M` with respect to the +tangent vector ``X \in T_p\mathcal M`` and the normal vector ``V \in N_p\mathcal M``. + +Since this a flat space by itself, the result is always the zero tangent vector. +""" +Weingarten(::TangentSpace, p, X, V) + +Weingarten!(::TangentSpace, Y, p, X, V) = fill!(Y, 0) + +@doc raw""" + zero_vector(M::TangentSpace, p) + +Zero tangent vector at point `p` from the tangent space `M`, that is the zero tangent vector +at point `M.point`. +""" +zero_vector(::TangentSpace, ::Any...) + +function zero_vector!(M::TangentSpace, X, p) + return zero_vector!(M.manifold, X, M.point) +end diff --git a/src/VectorFiber.jl b/src/VectorFiber.jl index 601d2ad2..8ca47973 100644 --- a/src/VectorFiber.jl +++ b/src/VectorFiber.jl @@ -7,224 +7,4 @@ Alias for [`Fiber`](@ref) when the fiber is a vector space. const VectorSpaceFiber{š”½,M,TSpaceType} = Fiber{š”½,TSpaceType,M} where {š”½,M<:AbstractManifold{š”½},TSpaceType<:VectorSpaceType} -@doc raw""" - TangentSpace{š”½,M} = Fiber{š”½,TangentSpaceType,M} where {š”½,M<:AbstractManifold{š”½}} - -A manifold for the tangent space ``T_p\mathcal M`` at a point ``p\in\mathcal M``. -This is modelled as an alias for [`VectorSpaceFiber`](@ref). - -# Constructor - - TangentSpace(M::AbstractManifold, p) - -Return the manifold (vector space) of the tangent space ``T_p\mathcal M`` at a point ``p\in\mathcal M``. -""" -const TangentSpace{š”½,M} = Fiber{š”½,TangentSpaceType,M} where {š”½,M<:AbstractManifold{š”½}} - -TangentSpace(M::AbstractManifold, p) = Fiber(M, TangentSpaceType(), p) - -function allocate_result(M::TangentSpace, ::typeof(rand)) - return zero_vector(M.manifold, M.point) -end - -""" - distance(M::TangentSpace, p, q) - -Distance between vectors `p` and `q` from the vector space `M`. It is calculated as the norm -of their difference. -""" -function distance(M::TangentSpace, p, q) - return norm(M.manifold, M.point, q - p) -end - -function embed!(M::TangentSpace, q, p) - return embed!(M.manifold, q, M.point, p) -end -function embed!(M::TangentSpace, Y, p, X) - return embed!(M.manifold, Y, M.point, X) -end - -@doc raw""" - exp(M::TangentSpace, p, X) - -Exponential map of tangent vectors `X` and `p` from the tangent space `M`. It is -calculated as their sum. -""" -exp(::TangentSpace, ::Any, ::Any) - -function exp!(M::TangentSpace, q, p, X) - copyto!(M.manifold, q, p + X) - return q -end - -fiber_dimension(M::AbstractManifold, ::CotangentSpaceType) = manifold_dimension(M) -fiber_dimension(M::AbstractManifold, ::TangentSpaceType) = manifold_dimension(M) - -function get_basis(M::TangentSpace, p, B::CachedBasis) - return invoke( - get_basis, - Tuple{AbstractManifold,Any,CachedBasis}, - M.manifold, - M.point, - B, - ) -end -function get_basis(M::TangentSpace, p, B::AbstractBasis{<:Any,TangentSpaceType}) - return get_basis(M.manifold, M.point, B) -end - -function get_coordinates(M::TangentSpace, p, X, B::AbstractBasis) - return get_coordinates(M.manifold, M.point, X, B) -end - -function get_coordinates!(M::TangentSpace, Y, p, X, B::AbstractBasis) - return get_coordinates!(M.manifold, Y, M.point, X, B) -end - -function get_vector(M::TangentSpace, p, X, B::AbstractBasis) - return get_vector(M.manifold, M.point, X, B) -end - -function get_vector!(M::TangentSpace, Y, p, X, B::AbstractBasis) - return get_vector!(M.manifold, Y, M.point, X, B) -end - -function get_vectors(M::TangentSpace, p, B::CachedBasis) - return get_vectors(M.manifold, M.point, B) -end - -@doc raw""" - injectivity_radius(M::TangentSpace) - -Return the injectivity radius on the [`TangentSpace`](@ref) `M`, which is $āˆž$. -""" -injectivity_radius(::TangentSpace) = Inf - -@doc raw""" - inner(M::TangentSpace, X, Y, Z) - -For any ``XāˆˆT_p\mathcal M`` we identify the tangent space ``T_X(T_p\mathcal M)`` -with ``T_p\mathcal M`` again. Hence an inner product of ``Y,Z`` is just the inner product of -the tangent space itself. ``āŸØY,ZāŸ©_X = āŸØY,ZāŸ©_p``. -""" -function inner(M::TangentSpace, X, Y, Z) - return inner(M.manifold, M.point, Y, Z) -end - -""" - is_flat(::TangentSpace) - -Return true. [`TangentSpace`](@ref) is a flat manifold. -""" -is_flat(::TangentSpace) = true - -function _isapprox(M::TangentSpace, X, Y; kwargs...) - return isapprox(M.manifold, M.point, X, Y; kwargs...) -end - -""" - log(TpM::TangentSpace, p, q) - -Logarithmic map on the tangent space manifold `TpM`, calculated as the difference of tangent -vectors `q` and `p` from `TpM`. -""" -log(::TangentSpace, ::Any...) -function log!(::TangentSpace, X, p, q) - copyto!(X, q - p) - return X -end - -@doc raw""" - manifold_dimension(TpM::TangentSpace) - -Return the dimension of the tangent space ``T_p\mathcal M`` at ``pāˆˆ\mathcal M``, -which is the same as the dimension of the manifold ``\mathcal M``. -""" -function manifold_dimension(TpM::TangentSpace) - return manifold_dimension(TpM.manifold) -end - LinearAlgebra.norm(M::VectorSpaceFiber, p, X) = norm(M.manifold, M.point, X) - -@doc raw""" - parallel_transport_to(::TangentSpace, X, Z, Y) - -Transport the tangent vector ``Z āˆˆ T_X(T_p\mathcal M)`` from `X` to `Y`. -Since we identify ``T_X\mathcal M = T_p\mathcal M`` and the tangent space is a vector space, -parallel transport simplifies to the identity, so this function yield ``Z`` as a result. -""" -parallel_transport_to(TpM::TangentSpace, X, Z, Y) - -function parallel_transport_to!(TpM::TangentSpace, Y, p, X, q) - return copyto!(TpM.manifold, Y, p, X) -end - -@doc raw""" - project(M::TangentSpace, p) - -Project the point `p` from the tangent space `M`, that is project the vector `p` -tangent at `M.point`. -""" -project(::TangentSpace, ::Any) - -function project!(M::TangentSpace, q, p) - return project!(M.manifold, q, M.point, p) -end - -@doc raw""" - project(M::TangentSpace, p, X) - -Project the vector `X` from the tangent space `M`, that is project the vector `X` -tangent at `M.point`. -""" -project(::TangentSpace, ::Any, ::Any) - -function project!(M::TangentSpace, Y, p, X) - return project!(M.manifold, Y, M.point, X) -end - -function Random.rand!(M::TangentSpace, X; vector_at = nothing) - rand!(M.manifold, X; vector_at = M.point) - return X -end -function Random.rand!(rng::AbstractRNG, M::TangentSpace, X; vector_at = nothing) - rand!(rng, M.manifold, X; vector_at = M.point) - return X -end - -function representation_size(B::TangentSpace) - return representation_size(B.manifold) -end - -function Base.show(io::IO, ::MIME"text/plain", TpM::TangentSpace) - println(io, "Tangent space to the manifold $(base_manifold(TpM)) at point:") - pre = " " - sp = sprint(show, "text/plain", TpM.point; context = io, sizehint = 0) - sp = replace(sp, '\n' => "\n$(pre)") - return print(io, pre, sp) -end - -@doc raw""" - Y = Weingarten(M::TangentSpace, p, X, V) - Weingarten!(M::TangentSpace, Y, p, X, V) - -Compute the Weingarten map ``\mathcal W_p`` at `p` on the [`TangentSpace`](@ref) `M` with respect to the -tangent vector ``X \in T_p\mathcal M`` and the normal vector ``V \in N_p\mathcal M``. - -Since this a flat space by itself, the result is always the zero tangent vector. -""" -Weingarten(::TangentSpace, p, X, V) - -Weingarten!(::TangentSpace, Y, p, X, V) = fill!(Y, 0) - -@doc raw""" - zero_vector(M::TangentSpace, p) - -Zero tangent vector at point `p` from the tangent space `M`, that is the zero tangent vector -at point `M.point`. -""" -zero_vector(::TangentSpace, ::Any...) - -function zero_vector!(M::TangentSpace, X, p) - return zero_vector!(M.manifold, X, M.point) -end diff --git a/test/product_manifold.jl b/test/product_manifold.jl index 15cbdc69..0c93cf08 100644 --- a/test/product_manifold.jl +++ b/test/product_manifold.jl @@ -69,6 +69,8 @@ include("test_sphere.jl") @test ManifoldsBase.default_retraction_method(M) === retraction_methods[1] @test ManifoldsBase.default_inverse_retraction_method(M) === inverse_retraction_methods[1] + @test ManifoldsBase.default_inverse_retraction_method(M, typeof(X1)) === + inverse_retraction_methods[1] @testset "get_component, set_component!, getindex and setindex!" begin @test get_component(M, p1, 1) == p1.x[1] @@ -306,6 +308,7 @@ include("test_sphere.jl") X = log(M, p1, p2) m = ProductVectorTransport(ParallelTransport(), ParallelTransport()) @test default_vector_transport_method(M) === m + @test default_vector_transport_method(M, typeof(X)) === m Y = vector_transport_to(M, p1, X, p2, m) Y2 = similar(Y) vector_transport_to!(M, Y2, p1, X, p2, m)