From 74b66f4c978d6d55bbb97c74b8c5eb07a6530ca8 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 7 Sep 2023 12:14:16 +0200 Subject: [PATCH 01/19] =?UTF-8?q?Initial=20rework=20to=20unify=20exp/retra?= =?UTF-8?q?ct=20and=20log/inverse=5Fretract=20to=20=E2=80=9Callocate=20fir?= =?UTF-8?q?st=E2=80=9D.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/retractions.jl | 457 ++++++++------------------------------------- 1 file changed, 77 insertions(+), 380 deletions(-) diff --git a/src/retractions.jl b/src/retractions.jl index 4892db13..151a09df 100644 --- a/src/retractions.jl +++ b/src/retractions.jl @@ -443,6 +443,30 @@ 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)), +) + 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]) @@ -652,192 +676,49 @@ 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 - -""" - inverse_retract_cayley(M::AbstractManifold, p, q) +@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))) -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) +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 [`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 +A retraction ``\operatorname{retr}_p: T_p\mathcal M → \mathcal M`` is a smooth map that fulfils -""" - inverse_retract_polar(M::AbstractManifold, p, q) +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``, -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) +where ``D\operatorname{retr}_p`` denotes the differential of the retraction -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) +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 [`QRInverseRetraction`](@ref), -which by default allocates and calls [`inverse_retract_qr!`](@ref ManifoldsBase.inverse_retract_qr!). -""" -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...) -end -""" - inverse_retract_nlsolve(M::AbstractManifold, p, q, m::NLSolveInverseRetraction) +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 [`NLSolveInverseRetraction`](@ref) `m`, -which by default allocates and calls [`inverse_retract_nlsolve!`](@ref). +Locally, the retraction is invertible. For the inverse operation, see [`inverse_retract`](@ref). """ -function inverse_retract_nlsolve( +function retract( M::AbstractManifold, p, - q, - m::NLSolveInverseRetraction; - kwargs..., + X, + 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...) + q = allocate_result(M, retract, p, X) + return retract!(M, q, p, X, 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, + m::AbstractRetractionMethod = default_retraction_method(M, typeof(p)), +) + q = allocate_result(M, retract, p, X) + return retract!(M, q, p, X, t, m) end - """ retract!(M::AbstractManifold, q, p, X) retract!(M::AbstractManifold, q, p, X, t::Real=1) @@ -990,7 +871,7 @@ end Compute the in-place variant of the [`ODEExponentialRetraction`](@ref)`(m, B)`. """ -retract_exp_ode!( +function retract_exp_ode!( M::AbstractManifold, q, p, @@ -999,243 +880,59 @@ retract_exp_ode!( 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) 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::Number, m::PadeRetraction) + return retract_pade!(M, q, p, t * X) +end """ retract_project!(M::AbstractManifold, q, p, X, t::Number) 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::Number) + return retract_project!(M, q, p, t * X) +end """ retract_polar!(M::AbstractManifold, q, p, X, t::Number) 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::Number) + return retract_polar!(M, q, p, t * X) +end """ retract_qr!(M::AbstractManifold, q, p, X, t::Number) 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::Number) + return retract_qr!(M, q, p, t * X) +end """ retract_softmax!(M::AbstractManifold, q, p, X, t::Number) Compute the in-place variant of the [`SoftmaxRetraction`](@ref). """ -retract_softmax!(M::AbstractManifold, q, p, X, t::Number) - -function retract_softmax! 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, ::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...) +function retract_softmax!(M::AbstractManifold, q, p, X, t::Number) + return retract_softmax!(M, q, p, t * X) end Base.show(io::IO, ::CayleyRetraction) = print(io, "CayleyRetraction()") From 8e0937ff9538936668e52cde5fa73d81f6d87392 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 7 Sep 2023 12:21:06 +0200 Subject: [PATCH 02/19] bump version, since this is breaking. --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c9f15b84..c8003fee 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.14.11" +version = "0.15" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" From c0cf2201f303a85ccb938baf34e654faf5efd649 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 7 Sep 2023 12:31:18 +0200 Subject: [PATCH 03/19] remove further parts of the allocating dispatch tree. --- src/point_vector_fallbacks.jl | 58 +-------------------------------- test/default_manifold.jl | 61 ----------------------------------- 2 files changed, 1 insertion(+), 118 deletions(-) diff --git a/src/point_vector_fallbacks.jl b/src/point_vector_fallbacks.jl index 5b36dab5..3156fdc6 100644 --- a/src/point_vector_fallbacks.jl +++ b/src/point_vector_fallbacks.jl @@ -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, @@ -334,12 +301,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 @@ -349,16 +312,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, @@ -375,16 +328,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/test/default_manifold.jl b/test/default_manifold.jl index 73e34b3f..6aca52f8 100644 --- a/test/default_manifold.jl +++ b/test/default_manifold.jl @@ -58,37 +58,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 +80,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,7 +101,6 @@ function inverse_retract_custom_kw!( return X end - struct MatrixVectorTransport{T} <: AbstractVector{T} m::Matrix{T} end From 213973280d5a1f7008f65bb4abbe92e1c03a8b53 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 8 Sep 2023 07:57:00 +0200 Subject: [PATCH 04/19] Update Project.toml Co-authored-by: Mateusz Baran --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c8003fee..5f6fa20c 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "ManifoldsBase" uuid = "3362f125-f0bb-47a3-aa74-596ffd7ef2fb" authors = ["Seth Axen ", "Mateusz Baran ", "Ronny Bergmann ", "Antoine Levitt "] -version = "0.15" +version = "0.15.0" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" From b4c69a82182d71b01bb07c7dc9a65bfda00faec1 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 8 Sep 2023 19:00:10 +0200 Subject: [PATCH 05/19] Fix a serious bug in type forward retract. --- src/point_vector_fallbacks.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/point_vector_fallbacks.jl b/src/point_vector_fallbacks.jl index 3156fdc6..8d8c654c 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!( From 8bb2f597274c0f98cfc54bcd861bf97f82e320e3 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 8 Sep 2023 19:22:23 +0200 Subject: [PATCH 06/19] fix tests, by actually just being a lit more correct / not even more precise necessarily. --- src/vector_transport.jl | 2 +- test/default_manifold.jl | 72 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/vector_transport.jl b/src/vector_transport.jl index 42996b92..30759136 100644 --- a/src/vector_transport.jl +++ b/src/vector_transport.jl @@ -425,7 +425,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 6aca52f8..422d1bb1 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 @@ -100,6 +119,38 @@ function inverse_retract_custom_kw!( X.value .= q.value - scale * p.value return X end +function ManifoldsBase.log!( + ::DefaultManifold, + Y::DefaultTVector, + p::DefaultPoint, + q::DefaultPoint, +) + Y.value .= q.value .- p.value + return Y +end + +function ManifoldsBase.retract!( + ::DefaultManifold, + q::DefaultPoint, + p::DefaultPoint, + X::DefaultTVector, + t::Number, + ::CustomDefinedRetraction, +) + q.value .= p.value .+ t * X.value + return q +end + +function ManifoldsBase.inverse_retract!( + ::DefaultManifold, + X::DefaultTVector, + p::DefaultPoint, + q::DefaultPoint, + ::CustomDefinedInverseRetraction, +) + X.value .= q.value .- p.value + return X +end struct MatrixVectorTransport{T} <: AbstractVector{T} m::Matrix{T} @@ -119,7 +170,16 @@ 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 ManifoldsBase.retract_softmax!(::DefaultManifold, q, p, X, t::Number) = (q .= p .+ t .* X) ManifoldsBase.get_embedding(M::DefaultManifold) = M # dummy embedding ManifoldsBase.inverse_retract_polar!(::DefaultManifold, Y, p, q) = (Y .= q .- p) @@ -692,8 +752,8 @@ Base.size(x::MatrixVectorTransport) = (size(x.m, 2),) @test X3 == log(M, p, q) @test log!(M, X3, p, q) == log(M, p, q) @test X3 == log(M, p, q) - @test inverse_retract(M, p, q, CustomDefinedInverseRetraction()) == -2 * Y - @test distance(M, p, q, CustomDefinedInverseRetraction()) == 2.0 + @test inverse_retract(M, p, q, CustomDefinedInverseRetraction()) == -Y + @test distance(M, p, q, CustomDefinedInverseRetraction()) == 1.0 X4 = ManifoldsBase.allocate_result(M, inverse_retract, p, q) @test inverse_retract!(M, X4, p, q) == inverse_retract(M, p, q) @test X4 == inverse_retract(M, p, q) From d3e8fed3ed8a009e232ece505237a13694574158 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 8 Sep 2023 19:38:40 +0200 Subject: [PATCH 07/19] bump doc dependencies, remove unneeded code. --- docs/Project.toml | 2 +- src/shooting.jl | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index 9629fb2c..5082e04b 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -6,4 +6,4 @@ ManifoldsBase = "3362f125-f0bb-47a3-aa74-596ffd7ef2fb" [compat] CondaPkg = "0.2" Documenter = "0.27" -ManifoldsBase = "0.14" +ManifoldsBase = "0.15" 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, From 90792d32fa0e07d39122f5f4a83f069d74008429 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 9 Sep 2023 09:30:17 +0200 Subject: [PATCH 08/19] Back to the previous custom retraction. --- docs/src/design.md | 4 +++- test/default_manifold.jl | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/src/design.md b/docs/src/design.md index 28210e24..c25063f5 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). diff --git a/test/default_manifold.jl b/test/default_manifold.jl index 422d1bb1..40a9434b 100644 --- a/test/default_manifold.jl +++ b/test/default_manifold.jl @@ -137,7 +137,7 @@ function ManifoldsBase.retract!( t::Number, ::CustomDefinedRetraction, ) - q.value .= p.value .+ t * X.value + q.value .= 2 .* p.value .+ t * X.value return q end @@ -148,7 +148,7 @@ function ManifoldsBase.inverse_retract!( q::DefaultPoint, ::CustomDefinedInverseRetraction, ) - X.value .= q.value .- p.value + X.value .= q.value .- 2 .* p.value return X end @@ -752,8 +752,8 @@ Base.size(x::MatrixVectorTransport) = (size(x.m, 2),) @test X3 == log(M, p, q) @test log!(M, X3, p, q) == log(M, p, q) @test X3 == log(M, p, q) - @test inverse_retract(M, p, q, CustomDefinedInverseRetraction()) == -Y - @test distance(M, p, q, CustomDefinedInverseRetraction()) == 1.0 + @test inverse_retract(M, p, q, CustomDefinedInverseRetraction()) == -2 * Y + @test distance(M, p, q, CustomDefinedInverseRetraction()) == 2.0 X4 = ManifoldsBase.allocate_result(M, inverse_retract, p, q) @test inverse_retract!(M, X4, p, q) == inverse_retract(M, p, q) @test X4 == inverse_retract(M, p, q) From dbf2a6873fea1c97a24d0f406a3c0925f9972aeb Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 9 Sep 2023 10:00:39 +0200 Subject: [PATCH 09/19] Improve documentation. --- docs/src/design.md | 20 +++-- docs/src/types.md | 11 +++ src/retractions.jl | 129 +++++++++-------------------- tutorials/Project.toml | 4 +- tutorials/implement-a-manifold.qmd | 12 +++ 5 files changed, 74 insertions(+), 102 deletions(-) diff --git a/docs/src/design.md b/docs/src/design.md index c25063f5..050272f7 100644 --- a/docs/src/design.md +++ b/docs/src/design.md @@ -85,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_. @@ -113,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_. @@ -184,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 ab94a674..a6271184 100644 --- a/docs/src/types.md +++ b/docs/src/types.md @@ -58,3 +58,14 @@ Modules = [ManifoldsBase] Pages = ["numbers.jl"] Order = [:type, :function] ``` + +## [Type Parameter](@id type-parameter) + +An [`AbstractManifold`](@ref) usually has a type parameter that determines e.g. its siye or +more precisely the [`manifold_dimension`](@ref). 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/src/retractions.jl b/src/retractions.jl index 151a09df..39d35e17 100644 --- a/src/retractions.jl +++ b/src/retractions.jl @@ -114,8 +114,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 @@ -126,8 +126,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 @@ -139,8 +138,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 @@ -180,8 +178,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 @@ -196,8 +193,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 @@ -215,8 +211,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} @@ -253,8 +248,7 @@ An inverse retraction based on the Padé approximation of order $m$ for the retr !!! 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 @@ -272,8 +266,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} @@ -286,8 +279,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 @@ -298,8 +290,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 @@ -311,8 +302,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 @@ -405,8 +395,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 @@ -755,79 +744,39 @@ 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, ::SoftmaxRetraction; kwargs...) +function _retract!(M::AbstractManifold, q, p, X, t, ::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)) @@ -838,7 +787,7 @@ function retract_embedded!( q, p, X, - t::Number, + t, m::AbstractRetractionMethod; kwargs..., ) @@ -857,17 +806,17 @@ 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)`. """ @@ -876,7 +825,7 @@ function retract_exp_ode!( q, p, X, - t::Number, + t, m::AbstractRetractionMethod, B::AbstractBasis, ) @@ -891,47 +840,47 @@ function retract_exp_ode!( 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`. """ -function retract_pade!(M::AbstractManifold, q, p, X, t::Number, m::PadeRetraction) +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). """ -function retract_project!(M::AbstractManifold, q, p, X, t::Number) +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). """ -function retract_polar!(M::AbstractManifold, q, p, X, t::Number) +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). """ -function retract_qr!(M::AbstractManifold, q, p, X, t::Number) +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). """ -function retract_softmax!(M::AbstractManifold, q, p, X, t::Number) +function retract_softmax!(M::AbstractManifold, q, p, X, t) return retract_softmax!(M, q, p, t * X) end 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 From ef69bcc2f209094229a0183d707b634511181bc0 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 10 Sep 2023 16:52:03 +0200 Subject: [PATCH 10/19] remove an unnecessary definition. --- test/default_manifold.jl | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/default_manifold.jl b/test/default_manifold.jl index 422d1bb1..d628722e 100644 --- a/test/default_manifold.jl +++ b/test/default_manifold.jl @@ -119,15 +119,6 @@ function inverse_retract_custom_kw!( X.value .= q.value - scale * p.value return X end -function ManifoldsBase.log!( - ::DefaultManifold, - Y::DefaultTVector, - p::DefaultPoint, - q::DefaultPoint, -) - Y.value .= q.value .- p.value - return Y -end function ManifoldsBase.retract!( ::DefaultManifold, From 546c301ac03ba7f5d4ece2103fd98dc9e4ba0cca Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 10 Sep 2023 17:02:49 +0200 Subject: [PATCH 11/19] Remove a mid point method since it was no longer called? --- src/ManifoldsBase.jl | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/ManifoldsBase.jl b/src/ManifoldsBase.jl index d3d6e6c1..b33f92c7 100644 --- a/src/ManifoldsBase.jl +++ b/src/ManifoldsBase.jl @@ -797,18 +797,6 @@ function mid_point!(M::AbstractManifold, q, p1, p2) return exp!(M, q, p1, X / 2) end -@static if VERSION <= v"1.1" - function mid_point!( - M::AbstractManifold, - q::AbstractArray{T1,0}, - p1::AbstractArray{T2,0}, - p2::AbstractArray{T3,0}, - ) where {T1,T2,T3} - X = log(M, p1, p2) - return exp!(M, q, p1, fill(X / 2)) - end -end - """ norm(M::AbstractManifold, p, X) From 102f49f7f67392463f71da3f570b9e22f81a349f Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 11 Sep 2023 08:36:58 +0200 Subject: [PATCH 12/19] drop support for Julia 1.0 --- .github/workflows/ci.yml | 2 +- Project.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20622f0f..4f450389 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - julia-version: ["1.0", "1.6", "1.9"] + julia-version: ["1.6", "1.9"] os: [ubuntu-latest, macOS-latest, windows-latest] exclude: - os: macOS-latest diff --git a/Project.toml b/Project.toml index 5f6fa20c..b1524630 100644 --- a/Project.toml +++ b/Project.toml @@ -10,7 +10,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [compat] DoubleFloats = ">= 0.9.2" -julia = "1.0" +julia = "1.6" [extras] DoubleFloats = "497a8b3b-efae-58df-a0af-a86822472b78" From 9ac2a34d0e9e1249697a6e560707b8129f5508ce Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 11 Sep 2023 12:24:39 +0200 Subject: [PATCH 13/19] Update news.md --- NEWS.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/NEWS.md b/NEWS.md index 5627adaa..3c97e86f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,14 @@ 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] dd/mm/2023 + +### 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 + ## [0.14.11] 25/08/2023 ### Added From 0cab22632a5449384219146ad6b1b5ffa86cef77 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 16 Oct 2023 10:45:06 +0200 Subject: [PATCH 14/19] Update docs/src/types.md Co-authored-by: Mateusz Baran --- docs/src/types.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/src/types.md b/docs/src/types.md index 11a7d9ea..e7ac0a18 100644 --- a/docs/src/types.md +++ b/docs/src/types.md @@ -66,9 +66,8 @@ Order = [:type, :function] ## [Type Parameter](@id type-parameter) -An [`AbstractManifold`](@ref) usually has a type parameter that determines e.g. its siye or -more precisely the [`manifold_dimension`](@ref). The [`TypeParameter`](@ref ManifoldsBase.TypeParameter) offers the flexibility -to have this parameter either as type parameter or a field +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 From 3387c62f705f631ac81e6dc76c1a1564262fd818 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 16 Oct 2023 11:16:39 +0200 Subject: [PATCH 15/19] Acidentally introduced the old retract-dispatch tree additionally to the new one. Remove it again. --- src/retractions.jl | 205 --------------------------------------------- 1 file changed, 205 deletions(-) diff --git a/src/retractions.jl b/src/retractions.jl index 49ce06f5..1f629eae 100644 --- a/src/retractions.jl +++ b/src/retractions.jl @@ -920,210 +920,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)") From 5381040b9f7f26d66d85d41d07c74c2e67f6f915 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 16 Oct 2023 11:18:49 +0200 Subject: [PATCH 16/19] Remove unnecessary code. --- .../ProductManifoldRecursiveArrayToolsExt.jl | 18 ------------------ src/point_vector_fallbacks.jl | 9 --------- 2 files changed, 27 deletions(-) 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 a305a583..9d2e0e4d 100644 --- a/src/point_vector_fallbacks.jl +++ b/src/point_vector_fallbacks.jl @@ -298,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, From 0ee777fb97dab84c480d7cb59571d6f4e34abdbe Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 16 Oct 2023 11:21:21 +0200 Subject: [PATCH 17/19] Fix docs. --- docs/src/types.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/src/types.md b/docs/src/types.md index e7ac0a18..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 From 347ad6909fbcaa97458b6abd2a273a1bcbb07887 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 16 Oct 2023 11:30:39 +0200 Subject: [PATCH 18/19] Do not import `retract_`, since it no longer exists. --- .../ManifoldsBaseRecursiveArrayToolsExt.jl | 1 - 1 file changed, 1 deletion(-) 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, From b37bb31c33fe913ed325b8be6b005d144f284d81 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 16 Oct 2023 16:06:15 +0200 Subject: [PATCH 19/19] Introduce back half-a-layer-2 for the allocatiing functions. --- src/retractions.jl | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/retractions.jl b/src/retractions.jl index 1f629eae..e4320d63 100644 --- a/src/retractions.jl +++ b/src/retractions.jl @@ -476,6 +476,12 @@ function inverse_retract( 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 @@ -718,8 +724,7 @@ function retract( X, m::AbstractRetractionMethod = default_retraction_method(M, typeof(p)), ) - q = allocate_result(M, retract, p, X) - return retract!(M, q, p, X, m) + return _retract(M, p, X, one(number_eltype(X)), m) end function retract( M::AbstractManifold, @@ -728,6 +733,13 @@ function retract( 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, ::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