diff --git a/NEWS.md b/NEWS.md index ee9fae46..568a358e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.15.0] xx/xx/2023 +## [0.15.0] dd/mm/2023 ### Added @@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- `retract` now behaves like `exp` in the sense that it allocates early, + which reduces the amount of code to dispatch through levels 1-3 twice +- `inverse_retract` now behaves like `log` in the sense that it allocates early - `Requires.jl` is added as a dependency to facilitate loading some methods related to `ProductManifolds` on Julia 1.6 to 1.8. Later versions rely on package extensions. - `Documenter.jl` was updated to 1.0. - `PowerManifold` can now store its size either in a field or in a type, similarly to `DefaultManifold`. By default the size is stored in a field. diff --git a/Project.toml b/Project.toml index 2e4d8900..50c676ab 100644 --- a/Project.toml +++ b/Project.toml @@ -17,9 +17,9 @@ ManifoldsBaseRecursiveArrayToolsExt = "RecursiveArrayTools" [compat] DoubleFloats = ">= 0.9.2" +julia = "1.6" RecursiveArrayTools = "2" Requires = "1" -julia = "1.0" [extras] DoubleFloats = "497a8b3b-efae-58df-a0af-a86822472b78" diff --git a/docs/src/design.md b/docs/src/design.md index 28210e24..050272f7 100644 --- a/docs/src/design.md +++ b/docs/src/design.md @@ -20,6 +20,9 @@ also avoiding ambiguities in multiple dispatch using the [dispatch on one argume Since the central element for functions on a manifold is the manifold itself, it should always be the first parameter, even for in-place functions. Then the classical parameters of a function (for example a point and a tangent vector for the retraction) follow and the final part are parameters to further dispatch on, which usually have their defaults. +Besides this order the functions follow the scheme “allocate early”, i.e. to switch to the +mutating variant when reasonable, cf. [Mutating and allocating functions](@ref inplace-and-noninplace). + ## A 3-Layer architecture for dispatch The general architecture consists of three layers @@ -46,7 +49,6 @@ Note that all other parameters of a function should be as least typed as possibl With respect to the [dispatch on one argument at a time](https://docs.julialang.org/en/v1/manual/methods/#Dispatch-on-one-argument-at-a-time) paradigm, this layer dispatches the _manifold first_. We also stay as abstract as possible, for example on the [`AbstractManifold`](@ref) level if possible. - If a function has optional positional arguments, (like [`retract`](@ref)) their default values might be filled/provided on this layer. This layer ends usually in calling the same functions like [`retract`](@ref) but prefixed with a `_` to enter [Layer II](@ref design-layer2). @@ -83,24 +85,26 @@ To close this section, let‘s look at an example. The high level (or [Layer I](@ref design-layer1)) definition of the retraction is given by ```julia -retract(M::AbstractManifold, p, X, m::AbstractRetractionMethod=default_retraction_method(M, typeof(p))) = _retract(M, p, X, m) +retract!(M::AbstractManifold, q, p, X, m::AbstractRetractionMethod=default_retraction_method(M, typeof(p))) = _retract!(M, q, p, X, m) ``` +Note that the convenience function `retract(M, q, p, X, m)` first allocates a `q` before calling this function as well. + This level now dispatches on different retraction types `m`. It usually passes to specific functions implemented in [Layer III](@ref design-layer3), here for example ```julia -_retract(M::AbstractManifold, p, X, m::Exponentialretraction) = exp(M, p, X) -_retract(M::AbstractManifold, p, X, m::PolarRetraction) = retract_polar(M, p, X) +_retract!(M::AbstractManifold, q, p, X, m::Exponentialretraction) = exp(M, q, p, X) +_retract!(M::AbstractManifold, q, p, X, m::PolarRetraction) = retract_polar(M, q, p, X) ``` -where the [`ExponentialRetraction`](@ref) is resolved by again calling a function on [Layer I](@ref design-layer1) (to fill futher default values if these exist). The [`PolarRetraction`](@ref) is dispatched to [`retract_polar`](@ref ManifoldsBase.retract_polar), a function on [Layer III](@ref design-layer3). +where the [`ExponentialRetraction`](@ref) is resolved by again calling a function on [Layer I](@ref design-layer1) (to fill futher default values if these exist). The [`PolarRetraction`](@ref) is dispatched to [`retract_polar!`](@ref ManifoldsBase.retract_polar!), a function on [Layer III](@ref design-layer3). For further details and dispatches, see [retractions and inverse retractions](@ref sec-retractions) for an overview. !!! note The documentation should be attached to the high level functions, since this again fosters ease of use. - If you implement a polar retraction, you should write a method of function [`retract_polar`](@ref ManifoldsBase.retract_polar) but the doc string should be attached to `retract(::M, ::P, ::V, ::PolarRetraction)` for your types `::M, ::P, ::V` of the manifold, points and vectors, respectively. + If you implement a polar retraction, you should write a method of function [`retract_polar!`](@ref ManifoldsBase.retract_polar!) but the doc string should be attached to `retract(::M, ::P, ::V, ::PolarRetraction)` for your types `::M, ::P, ::V` of the manifold, points and vectors, respectively. To summarize, with respect to the [dispatch on one argument at a time](https://docs.julialang.org/en/v1/manual/methods/#Dispatch-on-one-argument-at-a-time) paradigm, this layer dispatches the (optional) _parameters second_. @@ -111,13 +115,13 @@ It should have as few as possible optional parameters and as concrete as possibl This means -* the function name should be similar to its high level parent (for example [`retract`](@ref) and [`retract_polar`](@ref ManifoldsBase.retract_polar) above) +* the function name should be similar to its high level parent (for example [`retract!`](@ref) and [`retract_polar!`](@ref ManifoldsBase.retract_polar!) above) * The manifold type in method signature should always be as narrow as possible. * The points/vectors should either be untyped (for the default representation or if there is only one implementation) or provide all type bounds (for second representations or when using [`AbstractManifoldPoint`](@ref) and [`TVector`](@ref TVector), respectively). The first step that often happens on this level is memory allocation and calling the in-place function. If faster, it might also implement the function at hand itself. -Usually functions from this layer are not exported, when they have an analogue on the first layer. For example the function [`retract_polar`](@ref ManifoldsBase.retract_polar)`(M, p, X)` is not exported, since when using the interface one would use the [`PolarRetraction`](@ref) or to be precise call [`retract`](@ref)`(M, p, X, PolarRetraction())`. +Usually functions from this layer are not exported, when they have an analogue on the first layer. For example the function [`retract_polar!`](@ref ManifoldsBase.retract_polar!)`(M, q, p, X)` is not exported, since when using the interface one would use the [`PolarRetraction`](@ref) or to be precise call [`retract!`](@ref)`(M, q, p, X, PolarRetraction())`. When implementing your own manifold, you have to import functions like these anyway. To summarize, with respect to the [dispatch on one argument at a time](https://docs.julialang.org/en/v1/manual/methods/#Dispatch-on-one-argument-at-a-time) paradigm, this layer dispatches the _concrete manifold and point/vector types last_. @@ -182,5 +186,5 @@ log(::M, ::P, ::P) but the return type would be ``V``, whose internal sizes (fields/arrays) will depend on the concrete type of one of the points. This is accomplished by implementing a method `allocate_result(::M, ::typeof(log), ::P, ::P)` that returns the concrete variable for the result. This way, even with specific types, one just has to implement `log!` and the one line for the allocation. !!! note - This dispatch from the allocating to the in-place variant happens in Layer III, that is, functions like `exp` or [`retract_polar`](@ref ManifoldsBase.retract_polar) (but not [`retract`](@ref) itself) allocate their result (using `::typeof(retract)` for the second function) - and call the in-place variant `exp!` and [`retract_polar!`](@ref ManifoldsBase.retract_polar!) afterwards. + This dispatch from the allocating to the in-place variant happens in Layer I (which changed in ManifoldsBase.jl 0.15), that is, functions like `exp` or [`retract`](@ref) allocate their result + and call the in-place variant [`exp!`](@ref) and [`retract!`](@ref ManifoldsBase.retract!) afterwards, where the ladder passes down to layer III to reach [`retract_polar!`](@ref ManifoldsBase.retract_polar!). diff --git a/docs/src/types.md b/docs/src/types.md index d99468d5..610aa50a 100644 --- a/docs/src/types.md +++ b/docs/src/types.md @@ -9,12 +9,7 @@ Throughout the documentation of `ManifoldsBase.jl` we might use the [Euclidean S AbstractManifold ``` -which should store information about the manifold, for example parameters inherent to the manifold. The parameters are stored in two possible ways, as a type parameter to dispatch on or as a field. For these the following internal functions exist - -```@docs -ManifoldsBase.wrap_type_parameter -ManifoldsBase.TypeParameter -``` +which should store information about the manifold, for example parameters inherent to the manifold. ## Points on a manifold @@ -63,3 +58,13 @@ Modules = [ManifoldsBase] Pages = ["numbers.jl"] Order = [:type, :function] ``` + +## [Type Parameter](@id type-parameter) + +Concrete [`AbstractManifold`](@ref)s usually correspond to families of manifolds that are parameterized by some numbers, for example determining their [`manifold_dimension`](@ref). Those numbers can either be stored in a field or as a type parameter of the structure. The [`TypeParameter`](@ref ManifoldsBase.TypeParameter) offers the flexibility +to have this parameter either as type parameter or a field. + +```@docs +ManifoldsBase.TypeParameter +ManifoldsBase.wrap_type_parameter +``` diff --git a/ext/ManifoldsBaseRecursiveArrayToolsExt/ManifoldsBaseRecursiveArrayToolsExt.jl b/ext/ManifoldsBaseRecursiveArrayToolsExt/ManifoldsBaseRecursiveArrayToolsExt.jl index 3afeff9f..6e4dc7dc 100644 --- a/ext/ManifoldsBaseRecursiveArrayToolsExt/ManifoldsBaseRecursiveArrayToolsExt.jl +++ b/ext/ManifoldsBaseRecursiveArrayToolsExt/ManifoldsBaseRecursiveArrayToolsExt.jl @@ -20,7 +20,6 @@ if isdefined(Base, :get_extension) parallel_transport_direction, parallel_transport_to, project, - _retract, riemann_tensor, submanifold_component, submanifold_components, diff --git a/ext/ManifoldsBaseRecursiveArrayToolsExt/ProductManifoldRecursiveArrayToolsExt.jl b/ext/ManifoldsBaseRecursiveArrayToolsExt/ProductManifoldRecursiveArrayToolsExt.jl index 44367ffe..e519fd4c 100644 --- a/ext/ManifoldsBaseRecursiveArrayToolsExt/ProductManifoldRecursiveArrayToolsExt.jl +++ b/ext/ManifoldsBaseRecursiveArrayToolsExt/ProductManifoldRecursiveArrayToolsExt.jl @@ -263,24 +263,6 @@ function Random.rand( end end -function _retract( - M::ProductManifold, - p::ArrayPartition, - X::ArrayPartition, - t::Number, - method::ProductRetraction, -) - return ArrayPartition( - map( - (N, pc, Xc, rm) -> retract(N, pc, Xc, t, rm), - M.manifolds, - submanifold_components(M, p), - submanifold_components(M, X), - method.retractions, - ), - ) -end - function riemann_tensor( M::ProductManifold, p::ArrayPartition, diff --git a/src/point_vector_fallbacks.jl b/src/point_vector_fallbacks.jl index 797e67cb..9d2e0e4d 100644 --- a/src/point_vector_fallbacks.jl +++ b/src/point_vector_fallbacks.jl @@ -190,7 +190,7 @@ macro default_manifold_fallbacks(TM, TP, TV, pfield::Symbol, vfield::Symbol) m::ExponentialRetraction, ) retract!(M, q.$pfield, p.$pfield, X.$vfield, m) - return X + return q end function ManifoldsBase.vector_transport_along!( @@ -249,16 +249,11 @@ macro default_manifold_fallbacks(TM, TP, TV, pfield::Symbol, vfield::Symbol) ) end end - # TODO forward retraction / inverse_retraction for f_postfix in [:polar, :project, :qr, :softmax] - ra = Symbol("retract_$(f_postfix)") rm = Symbol("retract_$(f_postfix)!") push!( block.args, quote - function ManifoldsBase.$ra(M::$TM, p::$TP, X::$TV, t::Number) - return $TP(ManifoldsBase.$ra(M, p.$pfield, X.$vfield, t)) - end function ManifoldsBase.$rm(M::$TM, q, p::$TP, X::$TV, t::Number) ManifoldsBase.$rm(M, q.$pfield, p.$pfield, X.$vfield, t) return q @@ -269,16 +264,6 @@ macro default_manifold_fallbacks(TM, TP, TV, pfield::Symbol, vfield::Symbol) push!( block.args, quote - function ManifoldsBase.retract_exp_ode( - M::$TM, - p::$TP, - X::$TV, - t::Number, - m::AbstractRetractionMethod, - B::ManifoldsBase.AbstractBasis, - ) - return $TP(ManifoldsBase.retract_exp_ode(M, p.$pfield, X.$vfield, t, m, B)) - end function ManifoldsBase.retract_exp_ode!( M::$TM, q::$TP, @@ -291,15 +276,6 @@ macro default_manifold_fallbacks(TM, TP, TV, pfield::Symbol, vfield::Symbol) ManifoldsBase.retract_exp_ode!(M, q.$pfield, p.$pfield, X.$vfield, t, m, B) return q end - function ManifoldsBase.retract_pade( - M::$TM, - p::$TP, - X::$TV, - t::Number, - m::PadeRetraction, - ) - return $TP(ManifoldsBase.retract_pade(M, p.$pfield, X.$vfield, t, m)) - end function ManifoldsBase.retract_pade!( M::$TM, q::$TP, @@ -311,15 +287,6 @@ macro default_manifold_fallbacks(TM, TP, TV, pfield::Symbol, vfield::Symbol) ManifoldsBase.retract_pade!(M, q.$pfield, p.$pfield, X.$vfield, t, m) return q end - function ManifoldsBase.retract_embedded( - M::$TM, - p::$TP, - X::$TV, - t::Number, - m::AbstractRetractionMethod, - ) - return $TP(ManifoldsBase.retract_embedded(M, p.$pfield, X.$vfield, t, m)) - end function ManifoldsBase.retract_embedded!( M::$TM, q::$TP, @@ -331,15 +298,6 @@ macro default_manifold_fallbacks(TM, TP, TV, pfield::Symbol, vfield::Symbol) ManifoldsBase.retract_embedded!(M, q.$pfield, p.$pfield, X.$vfield, t, m) return q end - function ManifoldsBase.retract_sasaki( - M::$TM, - p::$TP, - X::$TV, - t::Number, - m::SasakiRetraction, - ) - return $TP(ManifoldsBase.retract_sasaki(M, p.$pfield, X.$vfield, t, m)) - end function ManifoldsBase.retract_sasaki!( M::$TM, q::$TP, @@ -354,12 +312,8 @@ macro default_manifold_fallbacks(TM, TP, TV, pfield::Symbol, vfield::Symbol) end, ) for f_postfix in [:polar, :project, :qr, :softmax] - ra = Symbol("inverse_retract_$(f_postfix)") rm = Symbol("inverse_retract_$(f_postfix)!") push!(block.args, quote - function ManifoldsBase.$ra(M::$TM, p::$TP, q::$TP) - return $TV((ManifoldsBase.$ra)(M, p.$pfield, q.$pfield)) - end function ManifoldsBase.$rm(M::$TM, Y::$TV, p::$TP, q::$TP) ManifoldsBase.$rm(M, Y.$vfield, p.$pfield, q.$pfield) return Y @@ -369,16 +323,6 @@ macro default_manifold_fallbacks(TM, TP, TV, pfield::Symbol, vfield::Symbol) push!( block.args, quote - function ManifoldsBase.inverse_retract_embedded( - M::$TM, - p::$TP, - q::$TP, - m::AbstractInverseRetractionMethod, - ) - return $TV( - ManifoldsBase.inverse_retract_embedded(M, p.$pfield, q.$pfield, m), - ) - end function ManifoldsBase.inverse_retract_embedded!( M::$TM, X::$TV, @@ -395,16 +339,7 @@ macro default_manifold_fallbacks(TM, TP, TV, pfield::Symbol, vfield::Symbol) ) return X end - function ManifoldsBase.inverse_retract_nlsolve( - M::$TM, - p::$TP, - q::$TP, - m::NLSolveInverseRetraction, - ) - return $TV( - ManifoldsBase.inverse_retract_nlsolve(M, p.$pfield, q.$pfield, m), - ) - end + function ManifoldsBase.inverse_retract_nlsolve!( M::$TM, X::$TV, diff --git a/src/retractions.jl b/src/retractions.jl index 6721511e..e4320d63 100644 --- a/src/retractions.jl +++ b/src/retractions.jl @@ -115,8 +115,8 @@ for point and tangent vectors. !!! note "Technical Note" Though you would call e.g. [`retract`](@ref)`(M, p, X, PolarRetraction())`, - to implement a polar retraction, define [`retract_polar`](@ref)`(M, p, X, t)` - or [`retract_polar!`](@ref)`(M, q, p, X, t)` for your manifold `M`. + to implement a polar retraction, define [`retract_polar!`](@ref)`(M, q, p, X, t)` + for your manifold `M`. """ struct PolarRetraction <: AbstractRetractionMethod end @@ -127,8 +127,7 @@ Retractions that are based on projection and usually addition in the embedding. !!! note "Technical Note" Though you would call e.g. [`retract`](@ref)`(M, p, X, ProjectionRetraction())`, - to implement a projection retraction, define [`retract_project`](@ref)`(M, p, X, t)` - or [`retract_project!`](@ref)`(M, q, p, X, t)` for your manifold `M`. + to implement a projection retraction, define [`retract_project!`](@ref)`(M, q, p, X, t)` for your manifold `M`. """ struct ProjectionRetraction <: AbstractRetractionMethod end @@ -140,8 +139,7 @@ matrix / matrices for point and tangent vector on a [`AbstractManifold`](@ref) !!! note "Technical Note" Though you would call e.g. [`retract`](@ref)`(M, p, X, QRRetraction())`, - to implement a QR retraction, define [`retract_qr`](@ref)`(M, p, X, t)` - or [`retract_qr!`](@ref)`(M, q, p, X, t)` for your manifold `M`. + to implement a QR retraction, define [`retract_qr!`](@ref)`(M, q, p, X, t)` for your manifold `M`. """ struct QRRetraction <: AbstractRetractionMethod end @@ -204,8 +202,7 @@ Describes a retraction that is based on the softmax function. !!! note "Technical Note" Though you would call e.g. [`retract`](@ref)`(M, p, X, SoftmaxRetraction())`, - to implement a softmax retraction, define [`retract_softmax`](@ref)`(M, p, X, t)` - or [`retract_softmax!`](@ref)`(M, q, p, X, t)` for your manifold `M`. + to implement a softmax retraction, define [`retract_softmax!`](@ref)`(M, q, p, X, t)` for your manifold `M`. """ struct SoftmaxRetraction <: AbstractRetractionMethod end @@ -220,8 +217,7 @@ A retraction based on the Padé approximation of order ``m`` !!! note "Technical Note" Though you would call e.g. [`retract`](@ref)`(M, p, X, PadeRetraction(m))`, - to implement a Padé retraction, define [`retract_pade`](@ref)`(M, p, X, t, m)` - or [`retract_pade!`](@ref)`(M, q, p, X, t, m)` for your manifold `M`. + to implement a Padé retraction, define [`retract_pade!`](@ref)`(M, q, p, X, t, m)` for your manifold `M`. """ struct PadeRetraction{m} <: AbstractRetractionMethod end @@ -239,8 +235,7 @@ A retraction based on the Cayley transform, which is realized by using the !!! note "Technical Note" Though you would call e.g. [`retract`](@ref)`(M, p, X, CayleyRetraction())`, - to implement a caley retraction, define [`retract_cayley`](@ref)`(M, p, X, t)` - or [`retract_cayley!`](@ref)`(M, q, p, X, t)` for your manifold `M`. + to implement a caley retraction, define [`retract_cayley!`](@ref)`(M, q, p, X, t)` for your manifold `M`. By default both these functions fall back to calling a [`PadeRetraction`](@ref)`(1)`. """ const CayleyRetraction = PadeRetraction{1} @@ -277,8 +272,7 @@ An inverse retraction based on the Padé approximation of order ``m`` for the re !!! note "Technical Note" Though you would call e.g. [`inverse_retract`](@ref)`(M, p, q, PadeInverseRetraction(m))`, - to implement an inverse Padé retraction, define [`inverse_retract_pade`](@ref)`(M, p, q, m)` - or [`inverse_retract_pade!`](@ref)`(M, X, p, q, m)` for your manifold `M`. + to implement an inverse Padé retraction, define [`inverse_retract_pade!`](@ref)`(M, X, p, q, m)` for your manifold `M`. """ struct PadeInverseRetraction{m} <: AbstractInverseRetractionMethod end @@ -296,8 +290,7 @@ A retraction based on the Cayley transform, which is realized by using the !!! note "Technical Note" Though you would call e.g. [`inverse_retract`](@ref)`(M, p, q, CayleyInverseRetraction())`, - to implement an inverse caley retraction, define [`inverse_retract_cayley`](@ref)`(M, p, q)` - or [`inverse_retract_cayley!`](@ref)`(M, X, p, q)` for your manifold `M`. + to implement an inverse caley retraction, define [`inverse_retract_cayley!`](@ref)`(M, X, p, q)` for your manifold `M`. By default both these functions fall back to calling a [`PadeInverseRetraction`](@ref)`(1)`. """ const CayleyInverseRetraction = PadeInverseRetraction{1} @@ -310,8 +303,7 @@ matrix / matrices for point and tangent vector on a [`AbstractManifold`](@ref) !!! note "Technical Note" Though you would call e.g. [`inverse_retract`](@ref)`(M, p, q, PolarInverseRetraction())`, - to implement an inverse polar retraction, define [`inverse_retract_polar`](@ref)`(M, p, q)` - or [`inverse_retract_polar!`](@ref)`(M, X, p, q)` for your manifold `M`. + to implement an inverse polar retraction, define [`inverse_retract_polar!`](@ref)`(M, X, p, q)` for your manifold `M`. """ struct PolarInverseRetraction <: AbstractInverseRetractionMethod end @@ -322,8 +314,7 @@ Inverse retractions that are based on a projection (or its inversion). !!! note "Technical Note" Though you would call e.g. [`inverse_retract`](@ref)`(M, p, q, ProjectionInverseRetraction())`, - to implement an inverse projection retraction, define [`inverse_retract_project`](@ref)`(M, p, q)` - or [`inverse_retract_project!`](@ref)`(M, X, p, q)` for your manifold `M`. + to implement an inverse projection retraction, define [`inverse_retract_project!`](@ref)`(M, X, p, q)` for your manifold `M`. """ struct ProjectionInverseRetraction <: AbstractInverseRetractionMethod end @@ -335,8 +326,7 @@ matrix / matrices for point and tangent vector on a [`AbstractManifold`](@ref) !!! note "Technical Note" Though you would call e.g. [`inverse_retract`](@ref)`(M, p, q, QRInverseRetraction())`, - to implement an inverse QR retraction, define [`inverse_retract_qr`](@ref)`(M, p, q)` - or [`inverse_retract_qr!`](@ref)`(M, X, p, q)` for your manifold `M`. + to implement an inverse QR retraction, define [`inverse_retract_qr!`](@ref)`(M, X, p, q)` for your manifold `M`. """ struct QRInverseRetraction <: AbstractInverseRetractionMethod end @@ -429,8 +419,7 @@ Describes an inverse retraction that is based on the softmax function. !!! note "Technical Note" Though you would call e.g. [`inverse_retract`](@ref)`(M, p, q, SoftmaxInverseRetraction())`, - to implement an inverse softmax retraction, define [`inverse_retract_softmax`](@ref)`(M, p, q)` - or [`inverse_retract_softmax!`](@ref)`(M, X, p, q)` for your manifold `M`. + to implement an inverse softmax retraction, define [`inverse_retract_softmax!`](@ref)`(M, X, p, q)` for your manifold `M`. """ struct SoftmaxInverseRetraction <: AbstractInverseRetractionMethod end @@ -467,6 +456,36 @@ function default_retraction_method(M::AbstractManifold, ::Type{T}) where {T} return default_retraction_method(M) end +""" + inverse_retract(M::AbstractManifold, p, q) + inverse_retract(M::AbstractManifold, p, q, method::AbstractInverseRetractionMethod + +Compute the inverse retraction, a cheaper, approximate version of the +[`log`](@ref)arithmic map), of points `p` and `q` on the [`AbstractManifold`](@ref) `M`. + +Inverse retraction method can be specified by the last argument, defaulting to +[`default_inverse_retraction_method`](@ref)`(M)`. +For available inverse retractions on certain manifolds see the documentation on the +corresponding manifold. + +See also [`retract`](@ref). +""" +function inverse_retract( + M::AbstractManifold, + p, + q, + m::AbstractInverseRetractionMethod = default_inverse_retraction_method(M, typeof(p)), +) + return _inverse_retract(M, p, q, m) +end +function _inverse_retract(M::AbstractManifold, p, q, ::LogarithmicInverseRetraction) + return log(M, p, q) +end +function _inverse_retract(M::AbstractManifold, p, q, m::AbstractInverseRetractionMethod) + X = allocate_result(M, inverse_retract, p, q) + return inverse_retract!(M, X, p, q, m) +end + """ inverse_retract!(M::AbstractManifold, X, p, q[, method::AbstractInverseRetractionMethod]) @@ -676,191 +695,54 @@ inverse_retract_softmax!(M::AbstractManifold, X, p, q) function inverse_retract_softmax! end -""" - inverse_retract(M::AbstractManifold, p, q) - inverse_retract(M::AbstractManifold, p, q, method::AbstractInverseRetractionMethod - -Compute the inverse retraction, a cheaper, approximate version of the -[`log`](@ref)arithmic map), of points `p` and `q` on the [`AbstractManifold`](@ref) `M`. - -Inverse retraction method can be specified by the last argument, defaulting to -[`default_inverse_retraction_method`](@ref)`(M)`. -For available inverse retractions on certain manifolds see the documentation on the -corresponding manifold. - -See also [`retract`](@ref). -""" -function inverse_retract( - M::AbstractManifold, - p, - q, - m::AbstractInverseRetractionMethod = default_inverse_retraction_method(M, typeof(p)), -) - return _inverse_retract(M, p, q, m) -end -function _inverse_retract(M::AbstractManifold, p, q, ::CayleyInverseRetraction; kwargs...) - return inverse_retract_cayley(M, p, q; kwargs...) -end -function _inverse_retract( - M::AbstractManifold, - p, - q, - m::EmbeddedInverseRetraction; - kwargs..., -) - return inverse_retract_embedded(M, p, q, m.inverse_retraction; kwargs...) -end -function _inverse_retract( - M::AbstractManifold, - p, - q, - ::LogarithmicInverseRetraction; - kwargs..., -) - return log(M, p, q; kwargs...) -end -function _inverse_retract(M::AbstractManifold, p, q, m::NLSolveInverseRetraction; kwargs...) - return inverse_retract_nlsolve(M, p, q, m; kwargs...) -end -function _inverse_retract( - M::AbstractManifold, - p, - q, - ::PadeInverseRetraction{n}; - kwargs..., -) where {n} - return inverse_retract_pade(M, p, q, n; kwargs...) -end -function _inverse_retract(M::AbstractManifold, p, q, ::PolarInverseRetraction; kwargs...) - return inverse_retract_polar(M, p, q; kwargs...) -end -function _inverse_retract( - M::AbstractManifold, - p, - q, - ::ProjectionInverseRetraction; - kwargs..., -) - return inverse_retract_project(M, p, q; kwargs...) -end -function _inverse_retract(M::AbstractManifold, p, q, ::QRInverseRetraction; kwargs...) - return inverse_retract_qr(M, p, q; kwargs...) -end -function _inverse_retract( - M::AbstractManifold, - p, - q, - m::InverseRetractionWithKeywords; - kwargs..., -) - return _inverse_retract(M, p, q, m.inverse_retraction; kwargs..., m.kwargs...) -end -function _inverse_retract(M::AbstractManifold, p, q, ::SoftmaxInverseRetraction; kwargs...) - return inverse_retract_softmax(M, p, q; kwargs...) -end -""" - inverse_retract_embedded(M::AbstractManifold, p, q, m::AbstractInverseRetractionMethod) - -computes the allocating variant of the [`EmbeddedInverseRetraction`](@ref) using -the [`AbstractInverseRetractionMethod`](@ref) `m` in the embedding (see [`get_embedding`](@ref)) -and projecting the result back. -""" -function inverse_retract_embedded( - M::AbstractManifold, - p, - q, - m::AbstractInverseRetractionMethod, -) - return project( - M, - p, - inverse_retract( - get_embedding(M), - embed(get_embedding(M), p), - embed(get_embedding(M), q), - m, - ), - ) -end +@doc raw""" + retract(M::AbstractManifold, p, X, method::AbstractRetractionMethod=default_retraction_method(M, typeof(p))) + retract(M::AbstractManifold, p, X, t::Number=1, method::AbstractRetractionMethod=default_retraction_method(M, typeof(p))) -""" - inverse_retract_cayley(M::AbstractManifold, p, q) +Compute a retraction, a cheaper, approximate version of the [`exp`](@ref)onential map, +from `p` into direction `X`, scaled by `t`, on the [`AbstractManifold`](@ref) `M`. -computes the allocating variant of the [`CayleyInverseRetraction`](@ref), -which by default allocates and calls [`inverse_retract_cayley!`](@ref). -""" -function inverse_retract_cayley(M::AbstractManifold, p, q; kwargs...) - X = allocate_result(M, inverse_retract, p, q) - return inverse_retract_cayley!(M, X, p, q; kwargs...) -end -""" - inverse_retract_pade(M::AbstractManifold, p, q) +A retraction ``\operatorname{retr}_p: T_p\mathcal M → \mathcal M`` is a smooth map that fulfils -computes the allocating variant of the [`PadeInverseRetraction`](@ref)`(n)`, -which by default allocates and calls [`inverse_retract_pade!`](@ref ManifoldsBase.inverse_retract_pade!). -""" -function inverse_retract_pade(M::AbstractManifold, p, q, n; kwargs...) - X = allocate_result(M, inverse_retract, p, q) - return inverse_retract_pade!(M, X, p, q, n; kwargs...) -end +1. ``\operatorname{retr}_p(0) = p`` +2. ``D\operatorname{retr}_p(0): T_p\mathcal M \to T_p\mathcal M`` is the identity map, +i.e. ``D\operatorname{retr}_p(0)[X]=X`` holds for all ``X\in T_p\mathcal M``, -""" - inverse_retract_polar(M::AbstractManifold, p, q) +where ``D\operatorname{retr}_p`` denotes the differential of the retraction -computes the allocating variant of the [`PolarInverseRetraction`](@ref), -which by default allocates and calls [`inverse_retract_polar!`](@ref ManifoldsBase.inverse_retract_polar!). -""" -function inverse_retract_polar(M::AbstractManifold, p, q; kwargs...) - X = allocate_result(M, inverse_retract, p, q) - return inverse_retract_polar!(M, X, p, q; kwargs...) -end -""" - inverse_retract_project(M::AbstractManifold, p, q) +The retraction is called of second order if for all ``X`` the curves ``c(t) = R_p(tX)`` +have a zero acceleration at ``t=0``, i.e. ``c''(0) = 0``. -computes the allocating variant of the [`ProjectionInverseRetraction`](@ref), -which by default allocates and calls [`inverse_retract_project!`](@ref ManifoldsBase.inverse_retract_project!). -""" -function inverse_retract_project(M::AbstractManifold, p, q; kwargs...) - X = allocate_result(M, inverse_retract, p, q) - return inverse_retract_project!(M, X, p, q; kwargs...) -end -""" - inverse_retract_qr(M::AbstractManifold, p, q) +Retraction method can be specified by the last argument, defaulting to +[`default_retraction_method`](@ref)`(M)`. For further available retractions see the documentation of respective manifolds. -computes the allocating variant of the [`QRInverseRetraction`](@ref), -which by default allocates and calls [`inverse_retract_qr!`](@ref ManifoldsBase.inverse_retract_qr!). +Locally, the retraction is invertible. For the inverse operation, see [`inverse_retract`](@ref). """ -function inverse_retract_qr(M::AbstractManifold, p, q; kwargs...) - X = allocate_result(M, inverse_retract, p, q) - return inverse_retract_qr!(M, X, p, q; kwargs...) +function retract( + M::AbstractManifold, + p, + X, + m::AbstractRetractionMethod = default_retraction_method(M, typeof(p)), +) + return _retract(M, p, X, one(number_eltype(X)), m) end -""" - inverse_retract_nlsolve(M::AbstractManifold, p, q, m::NLSolveInverseRetraction) - -computes the allocating variant of the [`NLSolveInverseRetraction`](@ref) `m`, -which by default allocates and calls [`inverse_retract_nlsolve!`](@ref). -""" -function inverse_retract_nlsolve( +function retract( M::AbstractManifold, p, - q, - m::NLSolveInverseRetraction; - kwargs..., + X, + t::Number, + m::AbstractRetractionMethod = default_retraction_method(M, typeof(p)), ) - X = allocate_result(M, inverse_retract, p, q) - return inverse_retract_nlsolve!(M, X, p, q, m; kwargs...) + return _retract(M, p, X, t, m) end -""" - inverse_retract_softmax(M::AbstractManifold, p, q) -computes the allocating variant of the [`SoftmaxInverseRetraction`](@ref), -which by default allocates and calls [`inverse_retract_softmax!`](@ref ManifoldsBase.inverse_retract_softmax!). -""" -function inverse_retract_softmax(M::AbstractManifold, p, q; kwargs...) - X = allocate_result(M, inverse_retract, p, q) - return inverse_retract_softmax!(M, X, p, q; kwargs...) +function _retract(M::AbstractManifold, p, X, t::Number, ::ExponentialRetraction) + return exp(M, p, X, t) +end +function _retract(M::AbstractManifold, p, X, t, m::AbstractRetractionMethod) + q = allocate_result(M, retract, p, X) + return retract!(M, q, p, X, t, m) end - """ retract!(M::AbstractManifold, q, p, X) @@ -898,57 +780,25 @@ function retract!( return retract!(M, q, p, X, one(number_eltype(X)), method) end # dispatch to lower level -function _retract!(M::AbstractManifold, q, p, X, t::Number, ::CayleyRetraction; kwargs...) +function _retract!(M::AbstractManifold, q, p, X, t, ::CayleyRetraction; kwargs...) return retract_cayley!(M, q, p, X, t; kwargs...) end -function _retract!( - M::AbstractManifold, - q, - p, - X, - t::Number, - m::EmbeddedRetraction; - kwargs..., -) +function _retract!(M::AbstractManifold, q, p, X, t, m::EmbeddedRetraction; kwargs...) return retract_embedded!(M, q, p, X, t, m.retraction; kwargs...) end -function _retract!( - M::AbstractManifold, - q, - p, - X, - t::Number, - ::ExponentialRetraction; - kwargs..., -) +function _retract!(M::AbstractManifold, q, p, X, t, ::ExponentialRetraction; kwargs...) return exp!(M, q, p, X, t; kwargs...) end -function _retract!( - M::AbstractManifold, - q, - p, - X, - t::Number, - m::ODEExponentialRetraction; - kwargs..., -) +function _retract!(M::AbstractManifold, q, p, X, t, m::ODEExponentialRetraction; kwargs...) return retract_exp_ode!(M, q, p, X, t, m.retraction, m.basis; kwargs...) end -function _retract!(M::AbstractManifold, q, p, X, t::Number, ::PolarRetraction; kwargs...) +function _retract!(M::AbstractManifold, q, p, X, t, ::PolarRetraction; kwargs...) return retract_polar!(M, q, p, X, t; kwargs...) end -function _retract!( - M::AbstractManifold, - q, - p, - X, - t::Number, - ::ProjectionRetraction; - kwargs..., -) +function _retract!(M::AbstractManifold, q, p, X, t, ::ProjectionRetraction; kwargs...) return retract_project!(M, q, p, X, t; kwargs...) end -function _retract!(M::AbstractManifold, q, p, X, t::Number, ::QRRetraction; kwargs...) +function _retract!(M::AbstractManifold, q, p, X, t, ::QRRetraction; kwargs...) return retract_qr!(M, q, p, X, t; kwargs...) end function _retract!(M::AbstractManifold, q, p, X, t::Number, m::SasakiRetraction) @@ -957,23 +807,15 @@ end function _retract!(M::AbstractManifold, q, p, X, t::Number, ::SoftmaxRetraction; kwargs...) return retract_softmax!(M, q, p, X, t; kwargs...) end -function _retract!(M::AbstractManifold, q, p, X, t::Number, m::PadeRetraction; kwargs...) +function _retract!(M::AbstractManifold, q, p, X, t, m::PadeRetraction; kwargs...) return retract_pade!(M, q, p, X, t, m; kwargs...) end -function _retract!( - M::AbstractManifold, - q, - p, - X, - t::Number, - m::RetractionWithKeywords; - kwargs..., -) +function _retract!(M::AbstractManifold, q, p, X, t, m::RetractionWithKeywords; kwargs...) return _retract!(M, q, p, X, t, m.retraction; kwargs..., m.kwargs...) end """ - retract_embedded!(M::AbstractManifold, q, p, X, t::Number, m::AbstractRetractionMethod) + retract_embedded!(M::AbstractManifold, q, p, X, t, m::AbstractRetractionMethod) Compute the in-place variant of the [`EmbeddedRetraction`](@ref) using the [`AbstractRetractionMethod`](@ref) `m` in the embedding (see [`get_embedding`](@ref)) @@ -984,7 +826,7 @@ function retract_embedded!( q, p, X, - t::Number, + t, m::AbstractRetractionMethod; kwargs..., ) @@ -1003,76 +845,83 @@ function retract_embedded!( end """ - retract_cayley!(M::AbstractManifold, q, p, X, t::Number) + retract_cayley!(M::AbstractManifold, q, p, X, t) Compute the in-place variant of the [`CayleyRetraction`](@ref), which by default falls back to calling the first order [`PadeRetraction`](@ref). """ -function retract_cayley!(M::AbstractManifold, q, p, X, t::Number; kwargs...) +function retract_cayley!(M::AbstractManifold, q, p, X, t; kwargs...) return retract_pade!(M, q, p, X, t, PadeRetraction(1); kwargs...) end """ - retract_exp_ode!(M::AbstractManifold, q, p, X, t::Number, m::AbstractRetractionMethod, B::AbstractBasis) + retract_exp_ode!(M::AbstractManifold, q, p, X, t, m::AbstractRetractionMethod, B::AbstractBasis) Compute the in-place variant of the [`ODEExponentialRetraction`](@ref)`(m, B)`. """ -retract_exp_ode!( +function retract_exp_ode!( M::AbstractManifold, q, p, X, - t::Number, + t, m::AbstractRetractionMethod, B::AbstractBasis, ) - -function retract_exp_ode! end + return retract_exp_ode!( + M::AbstractManifold, + q, + p, + t * X, + m::AbstractRetractionMethod, + B::AbstractBasis, + ) +end """ - retract_pade!(M::AbstractManifold, q, p, X, t::Number, m::PadeRetraction) + retract_pade!(M::AbstractManifold, q, p, X, t, m::PadeRetraction) Compute the in-place variant of the [`PadeRetraction`](@ref) `m`. """ -retract_pade!(M::AbstractManifold, q, p, X, t::Number, m::PadeRetraction) - -function retract_pade! end +function retract_pade!(M::AbstractManifold, q, p, X, t, m::PadeRetraction) + return retract_pade!(M, q, p, t * X) +end """ - retract_project!(M::AbstractManifold, q, p, X, t::Number) + retract_project!(M::AbstractManifold, q, p, X, t) Compute the in-place variant of the [`ProjectionRetraction`](@ref). """ -retract_project!(M::AbstractManifold, q, p, X, t::Number) - -function retract_project! end +function retract_project!(M::AbstractManifold, q, p, X, t) + return retract_project!(M, q, p, t * X) +end """ - retract_polar!(M::AbstractManifold, q, p, X, t::Number) + retract_polar!(M::AbstractManifold, q, p, X, t) Compute the in-place variant of the [`PolarRetraction`](@ref). """ -retract_polar!(M::AbstractManifold, q, p, X, t::Number) - -function retract_polar! end +function retract_polar!(M::AbstractManifold, q, p, X, t) + return retract_polar!(M, q, p, t * X) +end """ - retract_qr!(M::AbstractManifold, q, p, X, t::Number) + retract_qr!(M::AbstractManifold, q, p, X, t) Compute the in-place variant of the [`QRRetraction`](@ref). """ -retract_qr!(M::AbstractManifold, q, p, X, t::Number) - -function retract_qr! end +function retract_qr!(M::AbstractManifold, q, p, X, t) + return retract_qr!(M, q, p, t * X) +end """ - retract_softmax!(M::AbstractManifold, q, p, X, t::Number) + retract_softmax!(M::AbstractManifold, q, p, X, t) Compute the in-place variant of the [`SoftmaxRetraction`](@ref). """ -retract_softmax!(M::AbstractManifold, q, p, X, t::Number) - -function retract_softmax! end +function retract_softmax!(M::AbstractManifold, q, p, X, t::Number) + return retract_softmax!(M, q, p, t * X) +end """ retract_sasaki!(M::AbstractManifold, q, p, X, t::Number, m::SasakiRetraction) @@ -1083,210 +932,5 @@ retract_sasaki!(M::AbstractManifold, q, p, X, t::Number, m::SasakiRetraction) function retract_sasaki! end -@doc raw""" - retract(M::AbstractManifold, p, X, method::AbstractRetractionMethod=default_retraction_method(M, typeof(p))) - retract(M::AbstractManifold, p, X, t::Number=1, method::AbstractRetractionMethod=default_retraction_method(M, typeof(p))) - -Compute a retraction, a cheaper, approximate version of the [`exp`](@ref)onential map, -from `p` into direction `X`, scaled by `t`, on the [`AbstractManifold`](@ref) `M`. - -A retraction ``\operatorname{retr}_p: T_p\mathcal M → \mathcal M`` is a smooth map that fulfils - -1. ``\operatorname{retr}_p(0) = p`` -2. ``D\operatorname{retr}_p(0): T_p\mathcal M \to T_p\mathcal M`` is the identity map, -i.e. ``D\operatorname{retr}_p(0)[X]=X`` holds for all ``X\in T_p\mathcal M``, - -where ``D\operatorname{retr}_p`` denotes the differential of the retraction - -The retraction is called of second order if for all ``X`` the curves ``c(t) = R_p(tX)`` -have a zero acceleration at ``t=0``, i.e. ``c''(0) = 0``. - -Retraction method can be specified by the last argument, defaulting to -[`default_retraction_method`](@ref)`(M)`. For further available retractions see the documentation of respective manifolds. - -Locally, the retraction is invertible. For the inverse operation, see [`inverse_retract`](@ref). -""" -function retract( - M::AbstractManifold, - p, - X, - m::AbstractRetractionMethod = default_retraction_method(M, typeof(p)), -) - return retract(M, p, X, one(number_eltype(X)), m) -end -function retract( - M::AbstractManifold, - p, - X, - t::Number, - m::AbstractRetractionMethod = default_retraction_method(M, typeof(p)), -) - return _retract(M, p, X, t, m) -end -function _retract(M::AbstractManifold, p, X, t::Number, m::EmbeddedRetraction; kwargs...) - return retract_embedded(M, p, X, t, m.retraction; kwargs...) -end -function _retract(M::AbstractManifold, p, X, t::Number, ::ExponentialRetraction; kwargs...) - return exp(M, p, X, t) -end -function _retract( - M::AbstractManifold, - p, - X, - t::Number, - m::ODEExponentialRetraction; - kwargs..., -) - return retract_exp_ode(M, p, X, t, m.retraction, m.basis) -end -function _retract(M::AbstractManifold, p, X, t::Number, ::PolarRetraction; kwargs...) - return retract_polar(M, p, X, t; kwargs...) -end -function _retract(M::AbstractManifold, p, X, t::Number, ::ProjectionRetraction; kwargs...) - return retract_project(M, p, X, t; kwargs...) -end -function _retract(M::AbstractManifold, p, X, t::Number, ::QRRetraction; kwargs...) - return retract_qr(M, p, X, t; kwargs...) -end -function _retract(M::AbstractManifold, p, X, t::Number, m::SasakiRetraction) - return retract_sasaki(M, p, X, t, m) -end -function _retract(M::AbstractManifold, p, X, t::Number, ::SoftmaxRetraction; kwargs...) - return retract_softmax(M, p, X, t; kwargs...) -end -function _retract(M::AbstractManifold, p, X, t::Number, ::CayleyRetraction; kwargs...) - return retract_cayley(M, p, X, t; kwargs...) -end -function _retract(M::AbstractManifold, p, X, t::Number, m::PadeRetraction; kwargs...) - return retract_pade(M, p, X, t, m; kwargs...) -end -function _retract( - M::AbstractManifold, - p, - X, - t::Number, - m::RetractionWithKeywords; - kwargs..., -) - return _retract(M, p, X, t, m.retraction; kwargs..., m.kwargs...) -end -""" - retract_embedded(M::AbstractManifold, p, X, t::Number, m::AbstractRetractionMethod) - -computes the allocating variant of the [`EmbeddedRetraction`](@ref) using -the [`AbstractRetractionMethod`](@ref) `m` in the embedding (see [`get_embedding`](@ref)) -and projecting the result back. -""" -function retract_embedded( - M::AbstractManifold, - p, - X, - t::Number, - m::AbstractRetractionMethod; - kwargs..., -) - return project( - M, - retract( - get_embedding(M), - embed(get_embedding(M), p), - embed(get_embedding(M), p, X), - t, - m; - kwargs..., - ), - ) -end -""" - retract_polar(M::AbstractManifold, p, X, t::Number) - -computes the allocating variant of the [`PolarRetraction`](@ref), -which by default allocates and calls [`retract_polar!`](@ref ManifoldsBase.retract_polar!). -""" -function retract_polar(M::AbstractManifold, p, X, t::Number; kwargs...) - q = allocate_result(M, retract, p, X) - return retract_polar!(M, q, p, X, t; kwargs...) -end -""" - retract_project(M::AbstractManifold, p, X, t::Number) - -Compute the allocating variant of the [`ProjectionRetraction`](@ref), -which by default allocates and calls [`retract_project!`](@ref ManifoldsBase.retract_project!). -""" -function retract_project(M::AbstractManifold, p, X, t::Number; kwargs...) - q = allocate_result(M, retract, p, X) - return retract_project!(M, q, p, X, t; kwargs...) -end -""" - retract_qr(M::AbstractManifold, p, X, t::Number) - -Compute the allocating variant of the [`QRRetraction`](@ref), -which by default allocates and calls [`retract_qr!`](@ref ManifoldsBase.retract_qr!). -""" -function retract_qr(M::AbstractManifold, p, X, t::Number; kwargs...) - q = allocate_result(M, retract, p, X, t::Number) - return retract_qr!(M, q, p, X, t; kwargs...) -end -""" - retract_exp_ode(M::AbstractManifold, p, q, m::AbstractRetractionMethod, B::AbstractBasis) - -Compute the allocating variant of the [`ODEExponentialRetraction`](@ref)`(m,B)`, -which by default allocates and calls [`retract_exp_ode!`](@ref ManifoldsBase.retract_exp_ode!). -""" -function retract_exp_ode( - M::AbstractManifold, - p, - X, - t::Number, - m::AbstractRetractionMethod, - B::AbstractBasis; - kwargs..., -) - q = allocate_result(M, retract, p, X) - return retract_exp_ode!(M, q, p, X, t, m, B; kwargs...) -end -""" - retract_softmax(M::AbstractManifold, p, X, t::Number) - -Compute the allocating variant of the [`SoftmaxRetraction`](@ref), -which by default allocates and calls [`retract_softmax!`](@ref ManifoldsBase.retract_softmax!). -""" -function retract_softmax(M::AbstractManifold, p, X, t::Number; kwargs...) - q = allocate_result(M, retract, p, X) - return retract_softmax!(M, q, p, X, t; kwargs...) -end - -""" - retract_cayley(M::AbstractManifold, p, X, t::Number) - -Compute the allocating variant of the [`CayleyRetraction`](@ref), -which by default allocates and calls [`retract_cayley!`](@ref ManifoldsBase.retract_cayley!). -""" -function retract_cayley(M::AbstractManifold, p, X, t::Number; kwargs...) - q = allocate_result(M, retract, p, X) - return retract_cayley!(M, q, p, X, t; kwargs...) -end -""" - retract_pade(M::AbstractManifold, p, X, t::Number, m::PadeRetraction) - -Compute the allocating variant of the [`PadeRetraction`](@ref) `m`, -which by default allocates and calls [`retract_pade!`](@ref ManifoldsBase.retract_pade!). -""" -function retract_pade(M::AbstractManifold, p, X, t::Number, m::PadeRetraction; kwargs...) - q = allocate_result(M, retract, p, X) - return retract_pade!(M, q, p, X, t, m; kwargs...) -end - -""" - retract_sasaki(M::AbstractManifold, p, X, t::Number, m::SasakiRetraction) - -Compute the allocating variant of the [`SasakiRetraction`](@ref), -which by default allocates and calls `retract_sasaki!`. -""" -function retract_sasaki(M::AbstractManifold, p, X, t::Number, m::SasakiRetraction) - q = allocate_result(M, retract, p, X) - return retract_sasaki!(M, q, p, X, t, m) -end - Base.show(io::IO, ::CayleyRetraction) = print(io, "CayleyRetraction()") Base.show(io::IO, ::PadeRetraction{m}) where {m} = print(io, "PadeRetraction($m)") diff --git a/src/shooting.jl b/src/shooting.jl index 384209a9..827388bd 100644 --- a/src/shooting.jl +++ b/src/shooting.jl @@ -39,20 +39,12 @@ end function _inverse_retract!(M::AbstractManifold, X, p, q, m::ShootingInverseRetraction) return inverse_retract_shooting!(M, X, p, q, m) end -function _inverse_retract(M::AbstractManifold, p, q, m::ShootingInverseRetraction) - return inverse_retract_shooting(M, p, q, m) -end """ - inverse_retract_shooting(M::AbstractManifold, p, q, m::ShootingInverseRetraction) + inverse_retract_shooting!(M::AbstractManifold, X, p, q, m::ShootingInverseRetraction) Approximate the inverse of a retraction using the shooting method. """ -function inverse_retract_shooting(M::AbstractManifold, p, q, m::ShootingInverseRetraction) - X = allocate_result(M, inverse_retract, p, q) - return inverse_retract_shooting!(M, X, p, q, m) -end - function inverse_retract_shooting!( M::AbstractManifold, X, diff --git a/src/vector_transport.jl b/src/vector_transport.jl index 4d9dc197..4083f297 100644 --- a/src/vector_transport.jl +++ b/src/vector_transport.jl @@ -402,7 +402,7 @@ Let $c = \gamma_{q,d}(\frac{1}{2})$ denote the mid point on the shortest geodesic connecting $q$ and the point $d$. Then Schild's ladder reads as ````math -\operatorname{Sl}(p,d,q) = \operatorname{retr}_x( 2\operatorname{retr}_p^{-1} c) +\operatorname{Sl}(p,d,q) = \operatorname{retr}_p( 2\operatorname{retr}_p^{-1} c) ```` Where the classical Schilds ladder employs $\operatorname{retr}_d=\exp_d$ diff --git a/test/default_manifold.jl b/test/default_manifold.jl index 4c8c1e22..e6b363cc 100644 --- a/test/default_manifold.jl +++ b/test/default_manifold.jl @@ -3,7 +3,7 @@ using ManifoldsBase: @manifold_element_forwards, @manifold_vector_forwards, @default_manifold_fallbacks using ManifoldsBase: DefaultManifold, AbstractNumbers, RealNumbers, ComplexNumbers import ManifoldsBase: - number_eltype, + allocate_result_type, check_point, distance, embed!, @@ -11,6 +11,7 @@ import ManifoldsBase: inner, isapprox, log!, + number_eltype, parallel_transport_to!, retract!, inverse_retract! @@ -37,8 +38,12 @@ end DefaultPoint(v::T) where {T} = DefaultPoint{T}(v) convert(::Type{DefaultPoint{T}}, v::T) where {T} = DefaultPoint(v) Base.size(p::DefaultPoint) = size(p.value) -Base.eltype(v::DefaultPoint) = eltype(v.value) - +Base.eltype(p::DefaultPoint) = eltype(p.value) +Base.length(p::DefaultPoint) = length(p.value) +function Base.copyto!(q::DefaultPoint, p::DefaultPoint) + copyto!(q.value, p.value) + return q +end struct DefaultTVector{T} <: TVector value::T end @@ -50,6 +55,20 @@ function Base.fill!(X::DefaultTVector, x) fill!(X.value, x) return X end +function ManifoldsBase.allocate_result_type( + ::DefaultManifold, + ::typeof(log), + ::Tuple{DefaultPoint,DefaultPoint}, +) + return DefaultTVector +end +function ManifoldsBase.allocate_result_type( + ::DefaultManifold, + ::typeof(inverse_retract), + ::Tuple{DefaultPoint,DefaultPoint}, +) + return DefaultTVector +end ManifoldsBase.@manifold_element_forwards DefaultPoint value ManifoldsBase.@manifold_vector_forwards DefaultTVector value @@ -58,37 +77,6 @@ ManifoldsBase.@default_manifold_fallbacks ManifoldsBase.DefaultManifold DefaultP function ManifoldsBase._injectivity_radius(::DefaultManifold, ::CustomDefinedRetraction) return 10.0 end -function ManifoldsBase._retract( - M::DefaultManifold, - p, - X, - t::Number, - ::CustomDefinedRetraction, -) - return retract_custom(M, p, X, t) -end -function retract_custom(::DefaultManifold, p::DefaultPoint, X::DefaultTVector, t::Number) - return DefaultPoint(2 .* p.value .+ t .* X.value) -end -function ManifoldsBase._retract( - M::DefaultManifold, - p, - X, - t::Number, - ::CustomDefinedKeywordRetraction; - kwargs..., -) - return retract_custom_kw(M, p, X, t; kwargs...) -end -function retract_custom_kw( - ::DefaultManifold, - p::DefaultPoint, - X::DefaultTVector, - t::Number; - scale = 2.0, -) - return DefaultPoint(scale .* p.value .+ t .* X.value) -end function ManifoldsBase._retract!( M::DefaultManifold, q, @@ -111,35 +99,6 @@ function retract_custom_kw!( q.value .= scale .* p.value .+ t .* X.value return q end - -function ManifoldsBase._inverse_retract( - M::DefaultManifold, - p, - q, - ::CustomDefinedInverseRetraction, -) - return inverse_retract_custom(M, p, q) -end -function inverse_retract_custom(::DefaultManifold, p::DefaultPoint, q::DefaultPoint) - return DefaultTVector(q.value - 2 * p.value) -end -function ManifoldsBase._inverse_retract( - M::DefaultManifold, - p, - q, - ::CustomDefinedKeywordInverseRetraction; - kwargs..., -) - return inverse_retract_custom_kw(M, p, q; kwargs...) -end -function inverse_retract_custom_kw( - ::DefaultManifold, - p::DefaultPoint, - q::DefaultPoint; - scale = 2.0, -) - return DefaultTVector(q.value - scale * p.value) -end function ManifoldsBase._inverse_retract!( M::DefaultManifold, X, @@ -161,6 +120,28 @@ function inverse_retract_custom_kw!( return X end +function ManifoldsBase.retract!( + ::DefaultManifold, + q::DefaultPoint, + p::DefaultPoint, + X::DefaultTVector, + t::Number, + ::CustomDefinedRetraction, +) + q.value .= 2 .* p.value .+ t * X.value + return q +end + +function ManifoldsBase.inverse_retract!( + ::DefaultManifold, + X::DefaultTVector, + p::DefaultPoint, + q::DefaultPoint, + ::CustomDefinedInverseRetraction, +) + X.value .= q.value .- 2 .* p.value + return X +end struct MatrixVectorTransport{T} <: AbstractVector{T} m::Matrix{T} @@ -180,7 +161,17 @@ function ManifoldsBase.retract_exp_ode!( ) return (q .= p .+ t .* X) end -ManifoldsBase.retract_pade!(::DefaultManifold, q, p, X, t::Number, i) = (q .= p .+ t .* X) + +function ManifoldsBase.retract_pade!( + ::DefaultManifold, + q, + p, + X, + t::Number, + m::PadeRetraction, +) + return (q .= p .+ t .* X) +end function ManifoldsBase.retract_sasaki!( ::DefaultManifold, q, diff --git a/tutorials/Project.toml b/tutorials/Project.toml index 53127daa..bca47ffb 100644 --- a/tutorials/Project.toml +++ b/tutorials/Project.toml @@ -1,11 +1,9 @@ [deps] IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" -Manifolds = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e" ManifoldsBase = "3362f125-f0bb-47a3-aa74-596ffd7ef2fb" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" [compat] IJulia = "1" -Manifolds = "0.8.46" -ManifoldsBase = "0.14.5" +ManifoldsBase = "0.14.11, 0.15" Plots = "1.38" diff --git a/tutorials/implement-a-manifold.qmd b/tutorials/implement-a-manifold.qmd index 5da80cd1..1aec6a2d 100644 --- a/tutorials/implement-a-manifold.qmd +++ b/tutorials/implement-a-manifold.qmd @@ -19,6 +19,8 @@ We start from the very beginning and cover the basic ideas of the interface prov using Pkg; cd(@__DIR__) Pkg.activate("."); # for reproducibility use the local tutorial environment. +# But for this version use here the most recent dev version from the parent folder +Pkg.develop(PackageSpec(; path=(@__DIR__) * "/../")) ``` ## Preliminaries @@ -276,8 +278,18 @@ default_retraction_method(::ScaledSphere) = ProjectionRetraction() ``` Then + ```{julia} default_retraction_method(M) ``` + and retract without a method specified would always fall back to using the projection retraction instead of the exponential map. Note that for compatibilty there is the [`AbstractRetractionMethod`](@ref) called [`ExponentialRetraction`](@ref) which makes [`retract`](@ref) fall back to calling [`exp`](@ref). + +## Technical Details + +This notebook was rendered with the following environment + +```{julia} +Pkg.status() +``` \ No newline at end of file