From 8d9e3d11ba6d640d3793aaff872ebb722e6d6ea6 Mon Sep 17 00:00:00 2001 From: Seth Axen Date: Sat, 21 Dec 2019 03:25:39 -0800 Subject: [PATCH] Update docstrings, format code, and a few additions (#16) * Standardize/fix docstrings * Use variable name method * Rename variable to y * Make local injectivity radius fall back to global * Fix docstrings * Run JuliaFormatter * Replace broadcast with explicit copy * Add AbstractEstimationMethod * Fix variable name * Remove space * Increment version number * Rewrap docstrings * Avoid hanging equals * Simplify check with equiv logic * Change variable name * Rephrase * Use active language and wrap * Add/remove whitespace * Rephrase * Remove unused variable names * Remove whitespace * Standardize error messages * Make injectivity_radius error by default * Increment version number * Add more decorator manifold tests * Add global testset * Rewrap at length 92 per BlueStyle * Ommit space between long and short form functions * Merge docstrings for similar signatures --- Project.toml | 4 +- src/ArrayManifold.jl | 150 +++++--- src/DefaultManifold.jl | 32 +- src/ManifoldsBase.jl | 701 +++++++++++++++++++------------------ test/array_manifold.jl | 2 + test/decorator_manifold.jl | 22 ++ test/default_manifold.jl | 2 +- test/empty_manifold.jl | 6 +- test/runtests.jl | 12 +- 9 files changed, 519 insertions(+), 412 deletions(-) create mode 100644 test/decorator_manifold.jl diff --git a/Project.toml b/Project.toml index 5d4b28f0..7b391e69 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.2.0" +authors = ["Seth Axen ", "Mateusz Baran ", "Ronny Bergmann ", "Antoine Levitt "] +version = "0.3.0" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/src/ArrayManifold.jl b/src/ArrayManifold.jl index f7626da8..cb11acd9 100644 --- a/src/ArrayManifold.jl +++ b/src/ArrayManifold.jl @@ -1,37 +1,42 @@ """ - ArrayManifold{M <: Manifold} <: Manifold + ArrayManifold{M<:Manifold} <: Manifold -A manifold to encapsulate manifolds working on array representations of -`MPoints` and `TVectors` in a transparent way, such that for these manifolds its -not necessary to introduce explicit types for the points and tangent vectors, -but they are encapsulated/stripped automatically when needed. +A manifold to encapsulate manifolds working on array representations of `MPoints` and +`TVectors` in a transparent way, such that for these manifolds it's not necessary to +introduce explicit types for the points and tangent vectors, but they are +encapsulated/stripped automatically when needed. -This manifold is a decorator for a manifold, i.e. it decorates a manifold `M` -with types points, vectors, and covectors. +This manifold is a decorator for a manifold, i.e. it decorates a manifold `M` with types +points, vectors, and covectors. """ -struct ArrayManifold{M <: Manifold} <: Manifold +struct ArrayManifold{M<:Manifold} <: Manifold manifold::M end -convert(::Type{M},m::ArrayManifold{M}) where M <: Manifold = m.manifold -convert(::Type{ArrayManifold{M}},m::M) where M <: Manifold = ArrayManifold(m) + +convert(::Type{M}, m::ArrayManifold{M}) where {M<:Manifold} = m.manifold +convert(::Type{ArrayManifold{M}}, m::M) where {M<:Manifold} = ArrayManifold(m) is_decorator_manifold(::ArrayManifold) = Val(true) """ ArrayMPoint <: MPoint -represent a point on an [`ArrayManifold`](@ref), i.e. on a manifold where data -can be represented by arrays. The array is stored internally and semantically -this distinguished the value from [`ArrayTVector`](@ref)s and [`ArrayCoTVector`](@ref)s +Represent a point on an [`ArrayManifold`](@ref), i.e. on a manifold where data can be +represented by arrays. The array is stored internally and semantically. This distinguished +the value from [`ArrayTVector`](@ref)s and [`ArrayCoTVector`](@ref)s. """ -struct ArrayMPoint{V <: AbstractArray{<:Number}} <: MPoint +struct ArrayMPoint{V<:AbstractArray{<:Number}} <: MPoint value::V end -convert(::Type{V},x::ArrayMPoint{V}) where V <: AbstractArray{<:Number} = x.value -convert(::Type{ArrayMPoint{V}},x::V) where V <: AbstractArray{<:Number} = ArrayMPoint{V}(x) -eltype(::Type{ArrayMPoint{V}}) where V = eltype(V) + +convert(::Type{V}, x::ArrayMPoint{V}) where {V<:AbstractArray{<:Number}} = x.value +convert(::Type{ArrayMPoint{V}}, x::V) where {V<:AbstractArray{<:Number}} = ArrayMPoint{V}(x) + +eltype(::Type{ArrayMPoint{V}}) where {V} = eltype(V) + similar(x::ArrayMPoint) = ArrayMPoint(similar(x.value)) -similar(x::ArrayMPoint, ::Type{T}) where T = ArrayMPoint(similar(x.value, T)) +similar(x::ArrayMPoint, ::Type{T}) where {T} = ArrayMPoint(similar(x.value, T)) + function copyto!(x::ArrayMPoint, y::ArrayMPoint) copyto!(x.value, y.value) return x @@ -40,18 +45,24 @@ end """ ArrayTVector <: TVector -represent a tangent vector an [`ArrayManifold`](@ref), i.e. on a manifold where data -can be represented by arrays. The array is stored internally and semantically -this distinguished the value from [`ArrayMPoint`](@ref)s and [`ArrayCoTVector`](@ref)s +Represent a tangent vector to a point on an [`ArrayManifold`](@ref), i.e. on a manifold +where data can be represented by arrays. The array is stored internally and semantically. +This distinguished the value from [`ArrayMPoint`](@ref)s and [`ArrayCoTVector`](@ref)s. """ -struct ArrayTVector{V <: AbstractArray{<:Number}} <: TVector +struct ArrayTVector{V<:AbstractArray{<:Number}} <: TVector value::V end -convert(::Type{V},v::ArrayTVector{V}) where V <: AbstractArray{<:Number} = v.value -convert(::Type{ArrayTVector{V}},v::V) where V <: AbstractArray{<:Number} = ArrayTVector{V}(v) -eltype(::Type{ArrayTVector{V}}) where V = eltype(V) + +convert(::Type{V}, v::ArrayTVector{V}) where {V<:AbstractArray{<:Number}} = v.value +function convert(::Type{ArrayTVector{V}}, v::V) where {V<:AbstractArray{<:Number}} + return ArrayTVector{V}(v) +end + +eltype(::Type{ArrayTVector{V}}) where {V} = eltype(V) + similar(x::ArrayTVector) = ArrayTVector(similar(x.value)) -similar(x::ArrayTVector, ::Type{T}) where T = ArrayTVector(similar(x.value, T)) +similar(x::ArrayTVector, ::Type{T}) where {T} = ArrayTVector(similar(x.value, T)) + function copyto!(x::ArrayTVector, y::ArrayTVector) copyto!(x.value, y.value) return x @@ -60,23 +71,29 @@ end (+)(v1::ArrayTVector, v2::ArrayTVector) = ArrayTVector(v1.value + v2.value) (-)(v1::ArrayTVector, v2::ArrayTVector) = ArrayTVector(v1.value - v2.value) (-)(v::ArrayTVector) = ArrayTVector(-v.value) -(*)(a::Number, v::ArrayTVector) = ArrayTVector(a*v.value) +(*)(a::Number, v::ArrayTVector) = ArrayTVector(a * v.value) """ ArrayCoTVector <: CoTVector -represent a cotangent vector an [`ArrayManifold`](@ref), i.e. on a manifold where data -can be represented by arrays. The array is stored internally and semantically -this distinguished the value from [`ArrayMPoint`](@ref)s and [`ArrayTVector`](@ref)s +Represent a cotangent vector to a point on an [`ArrayManifold`](@ref), i.e. on a manifold +where data can be represented by arrays. The array is stored internally and semantically. +This distinguished the value from [`ArrayMPoint`](@ref)s and [`ArrayTVector`](@ref)s. """ -struct ArrayCoTVector{V <: AbstractArray{<:Number}} <: TVector +struct ArrayCoTVector{V<:AbstractArray{<:Number}} <: TVector value::V end -convert(::Type{V},v::ArrayCoTVector{V}) where V <: AbstractArray{<:Number} = v.value -convert(::Type{ArrayCoTVector{V}},v::V) where V <: AbstractArray{<:Number} = ArrayCoTVector{V}(v) -eltype(::Type{ArrayCoTVector{V}}) where V = eltype(V) + +convert(::Type{V}, v::ArrayCoTVector{V}) where {V<:AbstractArray{<:Number}} = v.value +function convert(::Type{ArrayCoTVector{V}}, v::V) where {V<:AbstractArray{<:Number}} + return ArrayCoTVector{V}(v) +end + +eltype(::Type{ArrayCoTVector{V}}) where {V} = eltype(V) + similar(x::ArrayCoTVector) = ArrayCoTVector(similar(x.value)) -similar(x::ArrayCoTVector, ::Type{T}) where T = ArrayCoTVector(similar(x.value, T)) +similar(x::ArrayCoTVector, ::Type{T}) where {T} = ArrayCoTVector(similar(x.value, T)) + function copyto!(x::ArrayCoTVector, y::ArrayCoTVector) copyto!(x.value, y.value) return x @@ -85,21 +102,20 @@ end (+)(v1::ArrayCoTVector, v2::ArrayCoTVector) = ArrayCoTVector(v1.value + v2.value) (-)(v1::ArrayCoTVector, v2::ArrayCoTVector) = ArrayCoTVector(v1.value - v2.value) (-)(v::ArrayCoTVector) = ArrayCoTVector(-v.value) -(*)(a::Number, v::ArrayCoTVector) = ArrayCoTVector(a*v.value) +(*)(a::Number, v::ArrayCoTVector) = ArrayCoTVector(a * v.value) """ array_value(x) -returns the internal array value of a [`ArrayMPoint`](@ref), [`ArrayTVector`](@ref) -or [`ArrayCoTVector`](@ref) if the value `x` is encapsulated as such, otherwise -if `x` is already an array, it just returns `x` +Return the internal array value of a [`ArrayMPoint`](@ref), [`ArrayTVector`](@ref), or +[`ArrayCoTVector`](@ref) if the value `x` is encapsulated as such. Return `x` if it is +already an array. """ array_value(x::AbstractArray) = x array_value(x::ArrayMPoint) = x.value array_value(v::ArrayTVector) = v.value array_value(v::ArrayCoTVector) = v.value - function isapprox(M::ArrayManifold, x, y; kwargs...) is_manifold_point(M, x, true; kwargs...) is_manifold_point(M, y, true; kwargs...) @@ -179,31 +195,57 @@ function zero_tangent_vector(M::ArrayManifold, x; kwargs...) return w end -function vector_transport_to!(M::ArrayManifold, vto, x, v, y, m::AbstractVectorTransportMethod; kwargs...) +function vector_transport_to!( + M::ArrayManifold, + vto, + x, + v, + y, + m::AbstractVectorTransportMethod; + kwargs..., +) is_manifold_point(M, y, true; kwargs...) is_tangent_vector(M, x, v, true; kwargs...) - vector_transport_to!(M.manifold, - array_value(vto), - array_value(x), - array_value(v), - array_value(y), - m) + vector_transport_to!( + M.manifold, + array_value(vto), + array_value(x), + array_value(v), + array_value(y), + m, + ) is_tangent_vector(M, y, vto, true; kwargs...) return vto end -function vector_transport_along!(M::ArrayManifold, vto, x, v, c, m::AbstractVectorTransportMethod; kwargs...) +function vector_transport_along!( + M::ArrayManifold, + vto, + x, + v, + c, + m::AbstractVectorTransportMethod; + kwargs..., +) is_tangent_vector(M, x, v, true; kwargs...) - vector_transport_along!(M.manifold, - array_value(vto), - array_value(x), - array_value(v), - c, - m) + vector_transport_along!( + M.manifold, + array_value(vto), + array_value(x), + array_value(v), + c, + m, + ) is_tangent_vector(M, c(1), vto, true; kwargs...) return vto end +injectivity_radius(M::ArrayManifold) = injectivity_radius(M.manifold) +function injectivity_radius(M::ArrayManifold, x, args...; kwargs...) + is_manifold_point(M, x, true; kwargs...) + return injectivity_radius(M.manifold, array_value(x), args...) +end + function check_manifold_point(M::ArrayManifold, x::MPoint; kwargs...) return check_manifold_point(M.manifold, array_value(x); kwargs...) end diff --git a/src/DefaultManifold.jl b/src/DefaultManifold.jl index 102b0910..df4f9a9b 100644 --- a/src/DefaultManifold.jl +++ b/src/DefaultManifold.jl @@ -1,26 +1,28 @@ """ DefaultManifold <: Manifold -This default manifold illustrates the main features of the interface and provides -a good starting point for an own manifold. It is a simplified/shortened variant -of `Euclidean` from `Manifolds.jl`. +This default manifold illustrates the main features of the interface and provides a skeleton +to build one's own manifold. It is a simplified/shortened variant of `Euclidean` from +`Manifolds.jl`. -this manifold further illustrates, how to type your manifold points -and tangent vectors. Note that the interface does not require this, but it -might be handy in debugging and educative situations to verify correctness of -involved variabes. +This manifold further illustrates how to type your manifold points and tangent vectors. Note +that the interface does not require this, but it might be handy in debugging and educative +situations to verify correctness of involved variabes. """ struct DefaultManifold{T<:Tuple} <: Manifold where {T} end -DefaultManifold(n::Vararg{Int,N}) where N = DefaultManifold{Tuple{n...}}() +DefaultManifold(n::Vararg{Int,N}) where {N} = DefaultManifold{Tuple{n...}}() @generated representation_size(::DefaultManifold{T}) where {T} = Tuple(T.parameters...) @generated manifold_dimension(::DefaultManifold{T}) where {T} = *(T.parameters...) @inline inner(::DefaultManifold, x, v, w) = dot(v, w) -distance(::DefaultManifold, x, y) = norm(x-y) +distance(::DefaultManifold, x, y) = norm(x - y) norm(::DefaultManifold, x, v) = norm(v) -exp!(M::DefaultManifold, y, x, v) = (y .= x .+ v) -log!(M::DefaultManifold, v, x, y) = (v .= y .- x) -zero_tangent_vector!(M::DefaultManifold, v, x) = fill!(v, 0) -project_point!(M::DefaultManifold, y, x) = (y .= x) -project_tangent!(M::DefaultManifold, w, x, v) = (w .= v) -vector_transport_to!(M::DefaultManifold, vto, x, v, y, ::ParallelTransport) = (vto .= v) \ No newline at end of file +exp!(::DefaultManifold, y, x, v) = (y .= x .+ v) +log!(::DefaultManifold, v, x, y) = (v .= y .- x) +zero_tangent_vector!(::DefaultManifold, v, x) = fill!(v, 0) +project_point!(::DefaultManifold, y, x) = copyto!(y, x) +project_tangent!(::DefaultManifold, w, x, v) = copyto!(w, v) +function vector_transport_to!(::DefaultManifold, vto, x, v, y, ::ParallelTransport) + return copyto!(vto, v) +end +injectivity_radius(::DefaultManifold) = Inf diff --git a/src/ManifoldsBase.jl b/src/ManifoldsBase.jl index 79b526bb..7b11af03 100644 --- a/src/ManifoldsBase.jl +++ b/src/ManifoldsBase.jl @@ -1,23 +1,7 @@ module ManifoldsBase -import Base: isapprox, - exp, - log, - convert, - copyto!, - angle, - eltype, - similar, - +, - -, - * -import LinearAlgebra: dot, - norm, - det, - cross, - I, - UniformScaling, - Diagonal +import Base: isapprox, exp, log, convert, copyto!, angle, eltype, similar, +, -, * +import LinearAlgebra: dot, norm, det, cross, I, UniformScaling, Diagonal import Markdown: @doc_str using LinearAlgebra @@ -25,65 +9,66 @@ using LinearAlgebra """ Manifold -A manifold type. The `Manifold` is used to dispatch to different exponential -and logarithmic maps as well as other function on manifold. +A manifold type. The `Manifold` is used to dispatch to different functions on a manifold, +usually as the first argument of the function. Examples are the [`exp`](@ref)onential and +[`log`](@ref)arithmic maps as well as more general functions that are built on them like the +[`geodesic`](@ref). """ abstract type Manifold end """ MPoint -Type for a point on a manifold. While a [`Manifold`](@ref) not necessarily -requires this type, for example when it is implemented for `Vector`s or -`Matrix` type elements, this type can be used for more complicated -representations, semantic verification or even dispatch for different -representations of points on a manifold. +Type for a point on a manifold. While a [`Manifold`](@ref) does not necessarily require this +type, for example when it is implemented for `Vector`s or `Matrix` type elements, this type +can be used for more complicated representations, semantic verification, or even dispatch +for different representations of points on a manifold. """ abstract type MPoint end """ TVector -Type for a tangent vector of a manifold. While a [`Manifold`](@ref) not -necessarily requires this type, for example when it is implemented for `Vector`s -or `Matrix` type elements, this type can be used for more complicated -representations, semantic verification or even dispatch for different -representations of tangent vectors and their types on a manifold. +Type for a tangent vector of a manifold. While a [`Manifold`](@ref) does not necessarily +require this type, for example when it is implemented for `Vector`s or `Matrix` type +elements, this type can be used for more complicated representations, semantic verification, +or even dispatch for different representations of tangent vectors and their types on a +manifold. """ abstract type TVector end """ CoTVector -Type for a cotangent vector of a manifold. While a [`Manifold`](@ref) not -necessarily requires this type, for example when it is implemented for `Vector`s -or `Matrix` type elements, this type can be used for more complicated -representations, semantic verification or even dispatch for different -representations of cotangent vectors and their types on a manifold. +Type for a cotangent vector of a manifold. While a [`Manifold`](@ref) does not necessarily +require this type, for example when it is implemented for `Vector`s or `Matrix` type +elements, this type can be used for more complicated representations, semantic verification, +or even dispatch for different representations of cotangent vectors and their types on a +manifold. """ abstract type CoTVector end """ - is_decorator_manifold(M) + is_decorator_manifold(M::Manifold) -indicate whether a manifold is a decorator manifold, i.e. whether it encapsulates -a [`Manifold`](@ref) with additional features, and stores internally the original -manifold instance. An example is the [`ArrayManifold`](@ref). +Indicate whether a manifold is a decorator manifold, i.e. whether it encapsulates a +[`Manifold`](@ref) with additional features and stores internally the original manifold +instance. An example is the [`ArrayManifold`](@ref). -Using Tim Holys Traits Trick (THTT), certain functions are just calling themselves -on the internal manifold, and hence have not to be implemented for decorators -again, for example [`manifold_dimension`](@ref) and especially [`base_manifold`](@ref). -This also assumes, that the undecoratord (base) manifold is stored in `M.manifold`. +Certain functions are just calling themselves on the internal manifold and hence do not need +to be reimplemented for decorators again, for example [`manifold_dimension`](@ref) and +especially [`base_manifold`](@ref). +It is assumed that the undecorated (base) manifold is stored in `M.manifold`. Alternatively, +overload [`base_manifold`](@ref). """ -is_decorator_manifold(::T) where {T <: Manifold} = Val(false) +is_decorator_manifold(::Manifold) = Val(false) """ base_manifold(M::Manifold) -returns the internally stored manifold for decorated manifolds and the -base manifold for vector bundles or power manifolds. -For decorator manifolds it returns the dimension of the internally stored manifold. +Return the internally stored manifold for decorated manifolds and the base manifold for +vector bundles or power manifolds. """ base_manifold(M::Manifold) = base_manifold(M, is_decorator_manifold(M)) base_manifold(M::Manifold, ::Val{true}) = base_manifold(M.manifold) @@ -92,24 +77,25 @@ base_manifold(M::Manifold, ::Val{false}) = M @doc doc""" representation_size(M::Manifold) -The size of array representing a point on manifold `M`. -For decorator manifolds it returns the dimension of the internally stored manifold. +The size of an array representing a point on manifold `M`. """ representation_size(M::Manifold) = representation_size(M, is_decorator_manifold(M)) representation_size(M::Manifold, ::Val{true}) = representation_size(base_manifold(M)) -representation_size(M::Manifold, ::Val{false}) = error("representation_size not implemented for manifold $(typeof(M)).") - +function representation_size(M::Manifold, ::Val{false}) + error("representation_size not implemented for manifold $(typeof(M)).") +end @doc doc""" manifold_dimension(M::Manifold) -The dimension $n$ of real space $\mathbb R^n$ to which the neighborhood -of each point of the manifold is homeomorphic. -For decorator manifolds it returns the dimension of the internally stored manifold. +The dimension $n$ of real space $\mathbb R^n$ to which the neighborhood of each point of the +manifold is homeomorphic. """ manifold_dimension(M::Manifold) = manifold_dimension(M, is_decorator_manifold(M)) manifold_dimension(M::Manifold, ::Val{true}) = manifold_dimension(base_manifold(M)) -manifold_dimension(M::Manifold, ::Val{false}) = error("manifold_dimension not implemented for manifold $(typeof(M)).") +function manifold_dimension(M::Manifold, ::Val{false}) + error("manifold_dimension not implemented for manifold $(typeof(M)).") +end """ isapprox(M::Manifold, x, y; kwargs...) @@ -123,8 +109,7 @@ isapprox(M::Manifold, x, y; kwargs...) = isapprox(x, y; kwargs...) """ isapprox(M::Manifold, x, v, w; kwargs...) -Check if vectors `v` and `w` tangent at `x` from manifold `M` are -approximately equal. +Check if vectors `v` and `w` tangent at `x` from manifold `M` are approximately equal. Keyword arguments can be used to specify tolerances. """ @@ -133,11 +118,16 @@ isapprox(M::Manifold, x, v, w; kwargs...) = isapprox(v, w; kwargs...) """ OutOfInjectivityRadiusError -An error thrown when a function (for example logarithmic map or inverse -retraction) is given arguments outside of its injectivity radius. +An error thrown when a function (for example [`log`](@ref)arithmic map or +[`inverse_retract`](@ref)) is given arguments outside of its [`injectivity_radius`](@ref). """ struct OutOfInjectivityRadiusError <: Exception end +""" + AbstractRetractionMethod + +Abstract type for methods for [`retract`](@ref)ing a tangent vector to a manifold. +""" abstract type AbstractRetractionMethod end """ @@ -148,105 +138,119 @@ Retraction using the exponential map. struct ExponentialRetraction <: AbstractRetractionMethod end """ - retract!(M::Manifold, y, x, v, [t=1], [method::AbstractRetractionMethod=ExponentialRetraction()]) + retract!(M::Manifold, y, x, v[, t::Real=1]) + retract!(M::Manifold, y, x, v[, t::Real=1], method::AbstractRetractionMethod) -Retraction (cheaper, approximate version of exponential map) of tangent -vector `t*v` at point `x` from manifold `M`. -Result is saved to `y`. +Retraction (cheaper, approximate version of [`exp`](@ref)onential map) of tangent vector +`t*v` at point `x` from manifold `M`. Result is saved to `y`. -Retraction method can be specified by the last argument. Please look at the -documentation of respective manifolds for available methods. +Retraction method can be specified by the last argument, defaulting to +[`ExponentialRetraction`](@ref). See the documentation of respective manifolds for available +methods. """ -retract!(M::Manifold, y, x, v, method::ExponentialRetraction) = exp!(M, y, x, v) - retract!(M::Manifold, y, x, v) = retract!(M, y, x, v, ExponentialRetraction()) - -retract!(M::Manifold, y, x, v, t::Real) = retract!(M, y, x, t*v) - -retract!(M::Manifold, y, x, v, t::Real, method::AbstractRetractionMethod) = retract!(M, y, x, t*v, method) +retract!(M::Manifold, y, x, v, t::Real) = retract!(M, y, x, t * v) +retract!(M::Manifold, y, x, v, method::ExponentialRetraction) = exp!(M, y, x, v) +function retract!(M::Manifold, y, x, v, t::Real, method::AbstractRetractionMethod) + return retract!(M, y, x, t * v, method) +end """ - retract(M::Manifold, x, v, [t=1], [method::AbstractRetractionMethod]) + retract(M::Manifold, x, v[, t::Real=1]) + retract(M::Manifold, x, v[, t::Real=1], method::AbstractRetractionMethod) -Retraction (cheaper, approximate version of exponential map) of tangent -vector `t*v` at point `x` from manifold `M`. +Retraction (cheaper, approximate version of [`exp`](@ref)onential map) of tangent vector +`t*v` at point `x` from manifold `M`. + +Retraction method can be specified by the last argument, defaulting to +[`ExponentialRetraction`](@ref). See the documentation of respective manifolds for available +methods. """ -function retract(M::Manifold, x, v, method::AbstractRetractionMethod) +function retract(M::Manifold, x, v) xr = similar_result(M, retract, x, v) - retract!(M, xr, x, v, method) + retract!(M, xr, x, v) return xr end - -function retract(M::Manifold, x, v) +retract(M::Manifold, x, v, t::Real) = retract(M, x, t * v) +function retract(M::Manifold, x, v, method::AbstractRetractionMethod) xr = similar_result(M, retract, x, v) - retract!(M, xr, x, v) + retract!(M, xr, x, v, method) return xr end +function retract(M::Manifold, x, v, t::Real, method::AbstractRetractionMethod) + return retract(M, x, t * v, method) +end -retract(M::Manifold, x, v, t::Real) = retract(M, x, t*v) - -retract(M::Manifold, x, v, t::Real, method::AbstractRetractionMethod) = retract(M, x, t*v, method) +""" + AbstractInverseRetractionMethod +Abstract type for methods for inverting a retraction (see [`inverse_retract`](@ref)). +""" abstract type AbstractInverseRetractionMethod end """ LogarithmicInverseRetraction -Inverse retraction using the logarithmic map. +Inverse retraction using the [`log`](@ref)arithmic map. """ struct LogarithmicInverseRetraction <: AbstractInverseRetractionMethod end """ - inverse_retract!(M::Manifold, v, x, y, [method::AbstractInverseRetractionMethod=LogarithmicInverseRetraction()]) + inverse_retract!(M::Manifold, v, x, y[, method::AbstractInverseRetractionMethod]) -Inverse retraction (cheaper, approximate version of logarithmic map) of points -`x` and `y`. -Result is saved to `y`. +Inverse retraction (cheaper, approximate version of [`log`](@ref)arithmic map) of points `x` +and `y`. Result is saved to `v`. -Inverse retraction method can be specified by the last argument. Please look -at the documentation of respective manifolds for available methods. +Inverse retraction method can be specified by the last argument, defaulting to +[`LogarithmicInverseRetraction`](@ref). See the documentation of respective manifolds for +available methods. """ -inverse_retract!(M::Manifold, v, x, y, method::LogarithmicInverseRetraction) = log!(M, v, x, y) - -inverse_retract!(M::Manifold, v, x, y) = inverse_retract!(M, v, x, y, LogarithmicInverseRetraction()) +function inverse_retract!(M::Manifold, v, x, y) + return inverse_retract!(M, v, x, y, LogarithmicInverseRetraction()) +end +function inverse_retract!(M::Manifold, v, x, y, method::LogarithmicInverseRetraction) + return log!(M, v, x, y) +end """ - inverse_retract(M::Manifold, x, y, [method::AbstractInverseRetractionMethod]) + inverse_retract(M::Manifold, x, y) + inverse_retract(M::Manifold, x, y, method::AbstractInverseRetractionMethod -Inverse retraction (cheaper, approximate version of logarithmic map) of points -`x` and `y` from manifold `M`. +Inverse retraction (cheaper, approximate version of [`log`](@ref)arithmic map) of points `x` +and `y` from manifold `M`. -Inverse retraction method can be specified by the last argument. Please look -at the documentation of respective manifolds for available methods. +Inverse retraction method can be specified by the last argument, defaulting to +[`LogarithmicInverseRetraction`](@ref). See the documentation of respective manifolds +for available methods. """ -function inverse_retract(M::Manifold, x, y, method::AbstractInverseRetractionMethod) +function inverse_retract(M::Manifold, x, y) vr = similar_result(M, inverse_retract, x, y) - inverse_retract!(M, vr, x, y, method) + inverse_retract!(M, vr, x, y) return vr end - -function inverse_retract(M::Manifold, x, y) +function inverse_retract(M::Manifold, x, y, method::AbstractInverseRetractionMethod) vr = similar_result(M, inverse_retract, x, y) - inverse_retract!(M, vr, x, y) + inverse_retract!(M, vr, x, y, method) return vr end """ project_point!(M::Manifold, y, x) -Project point `x` from the ambient space onto the manifold `M`. -The point `y` is overwritten by the projection. -The function works only for selected embedded manifolds and -is *not* required to return the closest point. +Project point `x` from the ambient space onto the manifold `M`. The point `y` is overwritten +by the projection. The function works only for selected embedded manifolds and is *not* +required to return the closest point. """ -project_point!(M::Manifold, y, x) = error("project_point! not implemented for a $(typeof(M)) and points $(typeof(y)) and $(typeof(x)).") +function project_point!(M::Manifold, y, x) + error("project_point! not implemented for a $(typeof(M)) and points $(typeof(y)) and $(typeof(x)).") +end """ project_point(M::Manifold, x) -Project point from the ambient space onto the manifold `M`. The point `x` -is not modified. The function works only for selected embedded manifolds and -is *not* required to return the closest point. +Project point from the ambient space onto the manifold `M`. The point `x` is not modified. +The function works only for selected embedded manifolds and is *not* required to return the +closest point. """ function project_point(M::Manifold, x) y = similar_result(M, project_point, x) @@ -257,22 +261,24 @@ end """ project_tangent!(M::Manifold, w, x, v) -Project ambient space representation of a vector `v` to a tangent vector -at point `x` from the manifold `M`. The result is saved in vector `w`. +Project ambient space representation of a vector `v` to a tangent vector at point `x` from +the manifold `M`. The result is saved in vector `w`. -The function works only for selected embedded manifolds and -is *not* required to return the closest vector. +The function works only for selected embedded manifolds and is *not* required to return the +closest vector. """ -project_tangent!(M::Manifold, w, x, v) = error("project onto tangent space not implemented for a $(typeof(M)) and point $(typeof(x)) with input $(typeof(v)).") +function project_tangent!(M::Manifold, w, x, v) + error("project_tangent! not implemented for a $(typeof(M)) and point $(typeof(x)) with input $(typeof(v)).") +end """ project_tangent(M::Manifold, x, v) -Project ambient space representation of a vector `v` to a tangent vector -at point `x` from the manifold `M`. +Project ambient space representation of a vector `v` to a tangent vector at point `x` from +the manifold `M`. -The function works only for selected embedded manifolds and -is *not* required to return the closest vector. +The function works only for selected embedded manifolds and is *not* required to return the +closest vector. """ function project_tangent(M::Manifold, x, v) vt = similar_result(M, project_tangent, v, x) @@ -285,7 +291,9 @@ end Inner product of tangent vectors `v` and `w` at point `x` from manifold `M`. """ -inner(M::Manifold, x, v, w) = error("inner: Inner product not implemented on a $(typeof(M)) for input point $(typeof(x)) and tangent vectors $(typeof(v)) and $(typeof(w)).") +function inner(M::Manifold, x, v, w) + error("inner not implemented on a $(typeof(M)) for input point $(typeof(x)) and tangent vectors $(typeof(v)) and $(typeof(w)).") +end """ norm(M::Manifold, x, v) @@ -309,38 +317,45 @@ Angle between tangent vectors `v` and `w` at point `x` from manifold `M`. angle(M::Manifold, x, v, w) = acos(inner(M, x, v, w) / norm(M, x, v) / norm(M, x, w)) """ - exp!(M::Manifold, y, x, v, t=1) + exp!(M::Manifold, y, x, v, t::Real = 1) -Exponential map of tangent vector `t*v` at point `x` from manifold `M`. -Result is saved to `y`. +Exponential map of tangent vector `t*v` at point `x` from manifold `M`. Result is saved to +`y`. """ -exp!(M::Manifold, y, x, v, t::Real) = exp!(M, y, x, t*v) - -exp!(M::Manifold, y, x, v) = error("Exponential map not implemented on a $(typeof(M)) for input point $(x) and tangent vector $(v).") +function exp!(M::Manifold, y, x, v) + error("exp! not implemented on a $(typeof(M)) for input point $(x) and tangent vector $(v).") +end +exp!(M::Manifold, y, x, v, t::Real) = exp!(M, y, x, t * v) """ - exp(M::Manifold, x, v, t=1) + exp(M::Manifold, x, v, t::Real = 1) + exp(M::Manifold, x, v, T::AbstractVector) -> AbstractVector -Exponential map of tangent vector `t*v` at point `x` from manifold `M`. +Exponential map of tangent vector `t*v` at point `x` from manifold `M`. `t` may be a scalar +or elements of vector `T`. """ function exp(M::Manifold, x, v) - x2 = similar_result(M, exp, x, v) - exp!(M, x2, x, v) - return x2 + y = similar_result(M, exp, x, v) + exp!(M, y, x, v) + return y end - -exp(M::Manifold, x, v, t::Real) = exp(M, x, t*v) +exp(M::Manifold, x, v, t::Real) = exp(M, x, t * v) +exp(M::Manifold, x, v, T::AbstractVector) = map(geodesic(M, x, v), T) """ - exp(M::Manifold, x, v, T::AbstractVector) + log!(M::Manifold, v, x, y) -Exponential map of tangent vector `t*v` at point `x` from manifold `M` for -each `t` in `T`. +Logarithmic map of point `y` at base point `x` on Manifold `M`. Result is saved to `v`. """ -exp(M::Manifold, x, v, T::AbstractVector) = map(geodesic(M, x, v), T) +function log!(M::Manifold, v, x, y) + error("log! not implemented on $(typeof(M)) for points $(typeof(x)) and $(typeof(y))") +end -log!(M::Manifold, v, x, y) = error("Logarithmic map not implemented on $(typeof(M)) for points $(typeof(x)) and $(typeof(y))") +""" + log(M::Manifold, x, y) +Logarithmic map of point `y` at base point `x` on Manifold `M`. +""" function log(M::Manifold, x, y) v = similar_result(M, log, x, y) log!(M, v, x, y) @@ -348,66 +363,51 @@ function log(M::Manifold, x, y) end """ - geodesic(M::Manifold, x, v) + geodesic(M::Manifold, x, v) -> Function -Get the geodesic with initial point `x` and velocity `v`. The geodesic -is the curve of constant velocity that is locally distance-minimizing. This -function returns a function of time, which may be a `Real` or an -`AbstractVector`. -""" -geodesic(M::Manifold, x, v) = t -> exp(M, x, v, t) +Get the geodesic with initial point `x` and velocity `v`. The geodesic is the curve of +constant velocity that is locally distance-minimizing. This function returns a function of +time, which may be a `Real` or an `AbstractVector`. -""" - geodesic(M::Manifold, x, v, t) + geodesic(M::Manifold, x, v, t::Real) + geodesic(M::Manifold, x, v, T::AbstractVector) -> AbstractVector -Get the point at time `t` traveling from `x` along the geodesic with initial -point `x` and velocity `v`. +Return the point at time `t` or points at times `t` in `T` along the geodesic. """ +geodesic(M::Manifold, x, v) = t -> exp(M, x, v, t) geodesic(M::Manifold, x, v, t::Real) = exp(M, x, v, t) - -""" - geodesic(M::Manifold, x, v, T::AbstractVector) - -Get the points for each `t` in `T` traveling from `x` along the geodesic with -initial point `x` and velocity `v`. -""" geodesic(M::Manifold, x, v, T::AbstractVector) = exp(M, x, v, T) -""" - shortest_geodesic(M::Manifold, x, y) +@doc doc""" + shortest_geodesic(M::Manifold, x, y) -> Function -Get a geodesic with initial point `x` and point `y` at `t=1` whose length is -the shortest path between the two points. When there are multiple shortest -geodesics, there is no guarantee which will be returned. This function returns -a function of time, which may be a `Real` or an `AbstractVector`. -""" -shortest_geodesic(M::Manifold, x, y) = geodesic(M, x, log(M, x, y)) +Get a [`geodesic`](@ref) $\gamma_x(t)$ whose length is the shortest path between the points +$x$ and $y$, where $\gamma_x(0)=x$ and $\gamma_x(1)=y$. When there are multiple shortest +geodesics, there is no guarantee which will be returned. -""" - shortest_geodesic(M::Manifold, x, y, t) +This function returns a function of time, which may be a `Real` or an `AbstractVector`. -Get the point at time `t` traveling from `x` along a shortest geodesic -connecting `x` and `y`, where `y` is reached at `t=1`. + shortest_geodesic(M::Manifold, x, y, t::Real) + shortest_geodesic(M::Manifold, x, y, T::AbstractVector) -> AbstractVector + +Return the point at time $t$ or points at times $t$ in $T$ along the shortest geodesic. """ +shortest_geodesic(M::Manifold, x, y) = geodesic(M, x, log(M, x, y)) shortest_geodesic(M::Manifold, x, y, t::Real) = geodesic(M, x, log(M, x, y), t) +shortest_geodesic(M::Manifold, x, y, T::AbstractVector) = geodesic(M, x, log(M, x, y), T) """ - shortest_geodesic(M::Manifold, x, y, T::AbstractVector) + AbstractVectorTransportMethod -Get the points for each `t` in `T` traveling from `x` along a shortest geodesic -connecting `x` and `y`, where `y` is reached at `t=1`. +Abstract type for methods for transporting vectors. """ -function shortest_geodesic(M::Manifold, x, y, T::AbstractVector) - return geodesic(M, x, log(M, x, y), T) -end - abstract type AbstractVectorTransportMethod end """ ParallelTransport <: AbstractVectorTransportMethod Specify to use parallel transport as vector transport method within -[`vector_transport_to`](@ref), [`vector_transport_direction`](@ref) or +[`vector_transport_to`](@ref), [`vector_transport_direction`](@ref), or [`vector_transport_along`](@ref). """ struct ParallelTransport <: AbstractVectorTransportMethod end @@ -416,92 +416,131 @@ struct ParallelTransport <: AbstractVectorTransportMethod end ProjectionTransport <: AbstractVectorTransportMethod Specify to use projection onto tangent space as vector transport method within -[`vector_transport_to`](@ref), [`vector_transport_direction`](@ref) or +[`vector_transport_to`](@ref), [`vector_transport_direction`](@ref), or [`vector_transport_along`](@ref). See [`project_tangent`](@ref) for details. """ struct ProjectionTransport <: AbstractVectorTransportMethod end -""" - vector_transport_to!(M::Manifold, vto, x, v, y, m::AbstractVectorTransportMethod=ParallelTransport()) -Vector transport of vector `v` at point `x` to point `y`. The result is saved -to `vto`. By default, the method `m` is [`ParallelTransport`](@ref). """ -vector_transport_to!(M::Manifold, vto, x, v, y) = vector_transport_to!(M,vto,x,v,y,ParallelTransport()) + vector_transport_to!(M::Manifold, vto, x, v, y[, method::AbstractVectorTransportMethod]) +Vector transport of vector `v` at point `x` to point `y`. The result is saved to `vto`. By +default, the `method` is [`ParallelTransport`](@ref). """ - vector_transport_to!(M::Manifold, vto, x, v, y, ProjectionTransport()) +function vector_transport_to!(M::Manifold, vto, x, v, y) + return vector_transport_to!(M, vto, x, v, y, ParallelTransport()) +end -Implements a default projection based vector transport, that projects a tangent -vector `v` at `x` on a [`Manifold`](@ref) `M` onto the tangent space at `y` by -interperting `v` as an element of the embedding and projecting back. """ -vector_transport_to!(M::Manifold, vto, x, v, y, m::ProjectionTransport) = project_tangent!(M, vto, y, v) + vector_transport_to!(M::Manifold, vto, x, v, y, method::ProjectionTransport) -function vector_transport_to!(M::Manifold, vto, x, v, y, m::AbstractVectorTransportMethod) - error("vector transport from a point of type $(typeof(x)) to a type $(typeof(y)) on a $(typeof(M)) for a vector of type $(v) and the $(typeof(m)) not yet implemented.") +Transport a vector `v` in the tangent space at `x` on a [`Manifold`](@ref) `M` by +interpreting it as an element of the embedding and then projecting it onto the tangent space +at `y`. +""" +function vector_transport_to!(M::Manifold, vto, x, v, y, ::ProjectionTransport) + return project_tangent!(M, vto, y, v) +end +function vector_transport_to!( + M::Manifold, + vto, + x, + v, + y, + method::AbstractVectorTransportMethod, +) + error("vector_transport_to! not implemented from a point of type $(typeof(x)) to a type $(typeof(y)) on a $(typeof(M)) for a vector of type $(v) and the $(typeof(method)).") end - """ - vector_transport_to(M::Manifold, x, v, y, m::AbstractVectorTransportMethod=ParallelTransport()) + vector_transport_to(M::Manifold, x, v, y[, method::AbstractVectorTransportMethod]) -Vector transport of vector `v` at point `x` to point `y` using the method `m`, -which defaults to [`ParallelTransport`](@ref). +Transport a vector `v` at point `x` to point `y` using the `method`, which defaults to +[`ParallelTransport`](@ref). """ -vector_transport_to(M::Manifold, x, v, y) = vector_transport_to(M,x,v,y,ParallelTransport()) -function vector_transport_to(M::Manifold, x, v, y, m::AbstractVectorTransportMethod) +function vector_transport_to(M::Manifold, x, v, y) + return vector_transport_to(M, x, v, y, ParallelTransport()) +end +function vector_transport_to(M::Manifold, x, v, y, method::AbstractVectorTransportMethod) vto = similar_result(M, vector_transport_to, v, x, y) - vector_transport_to!(M, vto, x, v, y, m) + vector_transport_to!(M, vto, x, v, y, method) return vto end """ - vector_transport_direction!(M::Manifold, vto, x, v, vdir, m=::ParallelTransport]) + vector_transport_direction!(M::Manifold, vto, x, v, vdir[, method::AbstractVectorTransportMethod]) -Vector transport of vector `v` at point `x` in the direction indicated -by the tangent vector `vdir` at point `x`. The result is saved to `vto`. -By default, `exp` and `vector_transport_to!` are used with the method `m` which -defaults to [`ParallelTransport`](@ref). +Transport a vector `v` at point `x` in the direction indicated by the tangent vector `vdir` +at point `x`. The result is saved to `vto`. By default, [`exp`](@ref) and +[`vector_transport_to!`](@ref) are used with the `method`, which defaults to +[`ParallelTransport`](@ref). """ -vector_transport_direction!(M::Manifold, vto, x, v, vdir) = vector_transport_direction!(M,vto,x,v,vdir,ParallelTransport()) -function vector_transport_direction!(M::Manifold, vto, x, v, vdir,m::AbstractVectorTransportMethod) +function vector_transport_direction!(M::Manifold, vto, x, v, vdir) + return vector_transport_direction!(M, vto, x, v, vdir, ParallelTransport()) +end +function vector_transport_direction!( + M::Manifold, + vto, + x, + v, + vdir, + method::AbstractVectorTransportMethod, +) y = exp(M, x, vdir) - return vector_transport_to!(M, vto, x, v, y, m) + return vector_transport_to!(M, vto, x, v, y, method) end """ - vector_transport_direction(M::Manifold, x, v, vdir[, m=::ParallelTransport]) + vector_transport_direction(M::Manifold, x, v, vdir[, method::AbstractVectorTransportMethod]) -Vector transport of vector `v` at point `x` in the direction indicated -by the tangent vector `vdir` at point `x` using the method `m`, which defaults to [`ParallelTransport`](@ref). +Transport a vector `v` at point `x` in the direction indicated by the tangent vector `vdir` +at point `x` using the `method`, which defaults to [`ParallelTransport`](@ref). """ -vector_transport_direction(M::Manifold, x, v, vdir) = vector_transport_direction(M,x,v,vdir,ParallelTransport()) -function vector_transport_direction(M::Manifold, x, v, vdir, m::AbstractVectorTransportMethod) +function vector_transport_direction(M::Manifold, x, v, vdir) + return vector_transport_direction(M, x, v, vdir, ParallelTransport()) +end +function vector_transport_direction( + M::Manifold, + x, + v, + vdir, + method::AbstractVectorTransportMethod, +) vto = similar_result(M, vector_transport_direction, v, x, vdir) - vector_transport_direction!(M, vto, x, v, vdir,m) + vector_transport_direction!(M, vto, x, v, vdir, method) return vto end """ - vector_transport_along!(M::Manifold, vto, x, v, c[,m=::ParallelTransport]) + vector_transport_along!(M::Manifold, vto, x, v, c[, method::AbstractVectorTransportMethod]) -Vector transport of vector `v` at point `x` along the curve `c` such that -`c(0)` is equal to `x` to point `c(1)` using the method `m`, which defaults to -[`ParallelTransport`](@ref). The result is saved to `vto`. +Transport a vector `v` at point `x` along the curve `c` such that `c(0)` is equal to `x` to +point `c(1)` using the `method`, which defaults to [`ParallelTransport`](@ref). The result +is saved to `vto`. """ -vector_transport_along!(M::Manifold, vto, x, v, c) = vector_transport_along!(M, vto, x, v, c, ParallelTransport()) -function vector_transport_along!(M::Manifold, vto, x, v, c, m::AbstractVectorTransportMethod) - error("vector_transport_along! not implemented for manifold $(typeof(M)), vector $(typeof(vto)), point $(typeof(x)), vector $(typeof(v)) along curve $(typeof(c)) with method $(typeof(m)).") +function vector_transport_along!(M::Manifold, vto, x, v, c) + return vector_transport_along!(M, vto, x, v, c, ParallelTransport()) +end +function vector_transport_along!( + M::Manifold, + vto, + x, + v, + c, + method::AbstractVectorTransportMethod, +) + error("vector_transport_along! not implemented for manifold $(typeof(M)), vector $(typeof(vto)), point $(typeof(x)), vector $(typeof(v)) along curve $(typeof(c)) with method $(typeof(method)).") end """ - vector_transport_along(M::Manifold, x, v, c[,m]) + vector_transport_along(M::Manifold, x, v, c[, method::AbstractVectorTransportMethod]) -Vector transport of vector `v` at point `x` along the curve `c` such that -`c(0)` is equal to `x` to point `c(1)`. -The default method `m` used is [`ParallelTransport`](@ref). +Transport a vector `v` at point `x` along the curve `c` such that `c(0)` is equal to `x` to +point `c(1)`. The default `method` used is [`ParallelTransport`](@ref). """ -vector_transport_along(M::Manifold, x, v, c) = vector_transport_along(M,x,v,c,ParallelTransport()) +function vector_transport_along(M::Manifold, x, v, c) + return vector_transport_along(M, x, v, c, ParallelTransport()) +end function vector_transport_along(M::Manifold, x, v, c, m::AbstractVectorTransportMethod) vto = similar_result(M, vector_transport_along, v, x) vector_transport_along!(M, vto, x, v, c, m) @@ -511,41 +550,50 @@ end @doc doc""" injectivity_radius(M::Manifold, x) -Distance $d$ such that `exp(M, x, v)` is injective for all tangent -vectors shorter than $d$ (has a left inverse). -""" -injectivity_radius(M::Manifold, x) = Inf +Distance $d$ such that [`exp(M, x, v)`](@ref exp(::Manifold, ::Any, ::Any)) is injective for +all tangent vectors shorter than $d$ (i.e. has a left inverse). -@doc doc""" - injectivity_radius(M::Manifold, x, R::AbstractRetractionMethod) + injectivity_radius(M::Manifold) + +Infimum of the injectivity radius of all manifold points. -Distance $d$ such that `retract(M, x, v, R)` is injective for all tangent -vectors shorter than $d$ (has a left inverse). + injectivity_radius(M::Manifold, x, method::AbstractRetractionMethod) + +Distance $d$ such that +[`retract(M, x, v, method)`](@ref retract(::Manifold, ::Any, ::Any, ::AbstractRetractionMethod)) +is injective for all tangent vectors shorter than $d$ (i.e. has a left inverse). """ +function injectivity_radius(M::Manifold) + error("injectivity_radius not implemented for manifold $(typeof(M)).") +end +injectivity_radius(M::Manifold, x) = injectivity_radius(M) injectivity_radius(M::Manifold, x, ::AbstractRetractionMethod) = injectivity_radius(M, x) """ - injectivity_radius(M::Manifold) + zero_tangent_vector(M::Manifold, x) -Infimum of the injectivity radii of all manifold points. +Vector `v` such that retracting `v` to manifold `M` at `x` produces `x`. """ -injectivity_radius(M::Manifold) = Inf - function zero_tangent_vector(M::Manifold, x) v = similar_result(M, zero_tangent_vector, x) zero_tangent_vector!(M, v, x) return v end +""" + zero_tangent_vector!(M::Manifold, v, x) + +Save to `v` a vector such that retracting `v` to manifold `M` at `x` produces `x`. +""" zero_tangent_vector!(M::Manifold, v, x) = log!(M, v, x, x) """ similar_result_type(M::Manifold, f, args::NTuple{N,Any}) where N -Returns type of element of the array that will represent the result of -function `f` for manifold `M` on given arguments (passed at a tuple). +Return type of element of the array that will represent the result of function `f` for +manifold `M` on given arguments `args` (passed as a tuple). """ -function similar_result_type(M::Manifold, f, args::NTuple{N,Any}) where N +function similar_result_type(M::Manifold, f, args::NTuple{N,Any}) where {N} T = typeof(reduce(+, one(eltype(eti)) for eti ∈ args)) return T end @@ -553,12 +601,11 @@ end """ similar_result(M::Manifold, f, x...) -Allocates an array for the result of function `f` on manifold `M` -and arguments `x...` for implementing the non-modifying operation -using the modifying operation. +Allocate an array for the result of function `f` on manifold `M` and arguments `x...` for +implementing the non-modifying operation using the modifying operation. -Usefulness of passing a function is demonstrated by methods that allocate -results of musical isomorphisms. +Usefulness of passing a function is demonstrated by methods that allocate results of musical +isomorphisms. """ function similar_result(M::Manifold, f, x...) T = similar_result_type(M, f, x) @@ -566,134 +613,122 @@ function similar_result(M::Manifold, f, x...) end """ - check_manifold_point(M::Manifold, x; kwargs...) + check_manifold_point(M::Manifold, x; kwargs...) -> Union{Nothing,String} -Return `nothing` when `x` is a point on manifold `M`. -Otherwise, return a string with description why the point does not belong -to manifold `M`. +Return `nothing` when `x` is a point on manifold `M`. Otherwise, return a string with a +description why the point does not belong to manifold `M`. -By default, `check_manifold_point` returns `nothing`, i.e. if no checks are implmented, -the assumption is to be optimistic for point not deriving from the [`MPoint`](@ref) type. +By default, `check_manifold_point` returns `nothing`, i.e. if no checks are implemented, the +assumption is to be optimistic for a point not deriving from the [`MPoint`](@ref) type. """ -function check_manifold_point(M::Manifold, x; kwargs...) - return nothing -end - +check_manifold_point(M::Manifold, x; kwargs...) = nothing function check_manifold_point(M::Manifold, x::MPoint; kwargs...) error("check_manifold_point not implemented for manifold $(typeof(M)) and point $(typeof(x)).") end """ - is_manifold_point(M, x, throw_error = false; kwargs...) + is_manifold_point(M::Manifold, x, throw_error = false; kwargs...) -check, whether `x` is a valid point on the [`Manifold`](@ref) `M`. +Return whether `x` is a valid point on the [`Manifold`](@ref) `M`. -If `throw_error` is false, the function returns either `true` or `false`. -If `throw_error` if true, the function either returns `true` or throws an error. -By default the function calls [`check_manifold_point`](@ref)`(M, x; kwargs...)` -and checks whether the returned value is `nothing` or an error. +If `throw_error` is `false`, the function returns either `true` or `false`. If `throw_error` +is `true`, the function either returns `true` or throws an error. By default the function +calls [`check_manifold_point(M, x; kwargs...)`](@ref) and checks whether the returned value +is `nothing` or an error. """ function is_manifold_point(M::Manifold, x, throw_error = false; kwargs...) mpe = check_manifold_point(M, x; kwargs...) - if throw_error - if mpe !== nothing - throw(mpe) - end - return true - else - return mpe === nothing - end + mpe === nothing && return true + return throw_error ? throw(mpe) : false end """ - check_tangent_vector(M::Manifold, x, v; kwargs...) + check_tangent_vector(M::Manifold, x, v; kwargs...) -> Union{Nothing,String} -check, whether `v` is a valid tangent vector in the tangent plane of `x` on the -[`Manifold`](@ref) `M`. An implementation should first check -[`manifold_point_error`](@ref)`(M, x; kwargs...)` and then validate `v`. -If it is not a tangent vector error string should be returned. +Check whether `v` is a valid tangent vector in the tangent plane of `x` on the +[`Manifold`](@ref) `M`. An implementation should first call [`check_manifold_point(M, x; +kwargs...)`](@ref) and then validate `v`. If it is not a tangent vector, an error string +should be returned. -By default, `check_tangent_vector` returns `nothing`, i.e. if no checks are implmented, -the assumption is to be optimistic for tangent vectors not deriving from the [`TVector`](@ref) type. +By default, `check_tangent_vector` returns `nothing`, i.e. if no checks are implemented, the +assumption is to be optimistic for tangent vectors not deriving from the [`TVector`](@ref) +type. """ -function check_tangent_vector(M::Manifold, x, v; kwargs...) - return nothing -end - +check_tangent_vector(M::Manifold, x, v; kwargs...) = nothing function check_tangent_vector(M::Manifold, x::MPoint, v::TVector; kwargs...) error("check_tangent_vector not implemented for manifold $(typeof(M)), point $(typeof(x)) and vector $(typeof(v)).") end """ - is_tangent_vector(M, x, v, throw_error = false; kwargs...) + is_tangent_vector(M::Manifold, x, v, throw_error = false; kwargs...) -check, whether `v` is a valid tangent vector at point `x` on -the [`Manifold`](@ref) `M`. Returns either `true` or `false`. +Return whether `v` is a valid tangent vector at point `x` on the [`Manifold`](@ref) `M`. +Returns either `true` or `false`. -The default is to return `true`, i.e. if no checks are implmented, -the assumption is to be optimistic. +The default is to return `true`, i.e. if no checks are implemented, the assumption is to be +optimistic. """ function is_tangent_vector(M::Manifold, x, v, throw_error = false; kwargs...) mtve = check_tangent_vector(M, x, v; kwargs...) - if throw_error - if mtve !== nothing - throw(mtve) - end - return true - else - return mtve === nothing - end + mtve === nothing && return true + return throw_error ? throw(mtve) : false end +""" + AbstractEstimationMethod + +Abstract type for defining statistical estimation methods. +""" +abstract type AbstractEstimationMethod end + include("ArrayManifold.jl") include("DefaultManifold.jl") export Manifold, - MPoint, - TVector, - CoTVector, - ArrayManifold, - ArrayMPoint, - ArrayTVector, - ArrayCoTVector + MPoint, + TVector, + CoTVector, + ArrayManifold, + ArrayMPoint, + ArrayTVector, + ArrayCoTVector -export ParallelTransport, - ProjectionTransport +export ParallelTransport, ProjectionTransport export base_manifold, - check_manifold_point, - check_tangent_vector, - distance, - exp, - exp!, - geodesic, - shortest_geodesic, - injectivity_radius, - inner, - inverse_retract, - inverse_retract!, - isapprox, - is_manifold_point, - is_tangent_vector, - is_decorator_manifold, - log, - log!, - manifold_dimension, - norm, - project_point, - project_point!, - project_tangent, - project_tangent!, - representation_size, - retract, - retract!, - vector_transport_along, - vector_transport_along!, - vector_transport_direction, - vector_transport_direction!, - vector_transport_to, - vector_transport_to!, - zero_tangent_vector, - zero_tangent_vector! + check_manifold_point, + check_tangent_vector, + distance, + exp, + exp!, + geodesic, + shortest_geodesic, + injectivity_radius, + inner, + inverse_retract, + inverse_retract!, + isapprox, + is_manifold_point, + is_tangent_vector, + is_decorator_manifold, + log, + log!, + manifold_dimension, + norm, + project_point, + project_point!, + project_tangent, + project_tangent!, + representation_size, + retract, + retract!, + vector_transport_along, + vector_transport_along!, + vector_transport_direction, + vector_transport_direction!, + vector_transport_to, + vector_transport_to!, + zero_tangent_vector, + zero_tangent_vector! end # module diff --git a/test/array_manifold.jl b/test/array_manifold.jl index 234a7d67..c28a3849 100644 --- a/test/array_manifold.jl +++ b/test/array_manifold.jl @@ -73,5 +73,7 @@ using LinearAlgebra zero_tangent_vector!(A, v2s, x) @test isapprox(A, v2s, zero_tangent_vector(M,x)) @test_throws ErrorException vector_transport_along!(A,v2s,x2,v2,ParallelTransport()) + @test injectivity_radius(A) == Inf + @test injectivity_radius(A, x) == Inf end end diff --git a/test/decorator_manifold.jl b/test/decorator_manifold.jl new file mode 100644 index 00000000..e8edc661 --- /dev/null +++ b/test/decorator_manifold.jl @@ -0,0 +1,22 @@ +using ManifoldsBase +using Test + +@testset "Testing decorator manifold functions" begin + M = ManifoldsBase.DefaultManifold(3) + A = ArrayManifold(M) + + @test base_manifold(M) == M + @test base_manifold(M, Val(false)) == M + @test base_manifold(A) == M + @test base_manifold(A, Val(true)) == M + + @test representation_size(M) == (3,) + @test_throws ErrorException representation_size(M, Val(false)) + @test representation_size(A) == (3,) + @test representation_size(A, Val(true)) == (3,) + + @test manifold_dimension(M) == 3 + @test_throws ErrorException manifold_dimension(M, Val(false)) + @test manifold_dimension(A) == 3 + @test manifold_dimension(A, Val(true)) == 3 +end diff --git a/test/default_manifold.jl b/test/default_manifold.jl index 852c3f76..78c7f4d1 100644 --- a/test/default_manifold.jl +++ b/test/default_manifold.jl @@ -7,7 +7,7 @@ using ReverseDiff using StaticArrays using Test -@testset "Testting Default (Euclidean)" begin +@testset "Testing Default (Euclidean)" begin M = ManifoldsBase.DefaultManifold(3) types = [Vector{Float64}, SizedVector{3, Float64}, diff --git a/test/empty_manifold.jl b/test/empty_manifold.jl index 077b678e..a6ab8b31 100644 --- a/test/empty_manifold.jl +++ b/test/empty_manifold.jl @@ -101,9 +101,9 @@ struct NonCoTVector <: CoTVector end @test_throws ErrorException ManifoldsBase.vector_transport_along!(m, [0], [0], [0], x -> x) @test_throws ErrorException ManifoldsBase.vector_transport_along(m, [0], [0], x -> x) - @test injectivity_radius(m) === Inf - @test injectivity_radius(m, [0]) === Inf - @test injectivity_radius(m, [0], exp_retr) === Inf + @test_throws ErrorException injectivity_radius(m) + @test_throws ErrorException injectivity_radius(m, [0]) + @test_throws ErrorException injectivity_radius(m, [0], exp_retr) @test_throws ErrorException zero_tangent_vector!(m, [0], [0]) @test_throws ErrorException zero_tangent_vector(m, [0]) diff --git a/test/runtests.jl b/test/runtests.jl index c4612639..3d357b87 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,9 @@ +using Test -include("empty_manifold.jl") -include("default_manifold.jl") -include("array_manifold.jl") -include("domain_errors.jl") +@testset "ManifoldsBase" begin + include("decorator_manifold.jl") + include("empty_manifold.jl") + include("default_manifold.jl") + include("array_manifold.jl") + include("domain_errors.jl") +end