From 8e7ffcb22cccb93e26fe11253f84c6f1df58f65a Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 22 Jul 2021 18:00:19 +0200 Subject: [PATCH 01/88] Initial sketch of type --- docs/src/manifolds/group.md | 2 +- src/Manifolds.jl | 3 - src/groups/array_manifold.jl | 5 +- src/groups/group.jl | 222 ++++------------------------------- 4 files changed, 28 insertions(+), 204 deletions(-) diff --git a/docs/src/manifolds/group.md b/docs/src/manifolds/group.md index 5420d7903e..9bb741dad2 100644 --- a/docs/src/manifolds/group.md +++ b/docs/src/manifolds/group.md @@ -17,7 +17,7 @@ Depth = 3 The following operations are available for group manifolds: -* [`identity`](@ref): get the identity of the group. +* [`Identity`](@ref): an allocation free representation of the identity element of the group. * [`inv`](@ref): get the inverse of a given element. * [`compose`](@ref): compose two given elements of a group. diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 5a761cd6b9..83f237ea85 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -585,8 +585,6 @@ export adjoint_action, group_log!, has_biinvariant_metric, has_invariant_metric, - identity, - identity!, inv, inv!, invariant_metric_dispatch, @@ -600,7 +598,6 @@ export adjoint_action, inverse_translate_diff!, lie_bracket, lie_bracket!, - make_identity, optimal_alignment, optimal_alignment!, screw_matrix, diff --git a/src/groups/array_manifold.jl b/src/groups/array_manifold.jl index 2f9c2411b4..ae98be891f 100644 --- a/src/groups/array_manifold.jl +++ b/src/groups/array_manifold.jl @@ -2,11 +2,10 @@ array_value(e::Identity) = Identity(e.group, array_value(e.p)) array_point(p) = ValidationMPoint(p) array_point(p::ValidationMPoint) = p -array_point(e::Identity) = Identity(e.group, array_point(e.p)) function adjoint_action(M::ValidationManifold, p, X; kwargs...) is_point(M, p, true; kwargs...) - eM = make_identity(M.manifold, array_value(p)) + eM = Identity(M.manifold) is_vector(M, eM, X, true; kwargs...) Y = ValidationTVector(adjoint_action(M.manifold, array_value(p), array_value(X))) is_vector(M, eM, Y, true; kwargs...) @@ -15,7 +14,7 @@ end function adjoint_action!(M::ValidationManifold, Y, p, X; kwargs...) is_point(M, p, true; kwargs...) - eM = make_identity(M.manifold, array_value(p)) + eM = Identity(M.manifold) is_vector(M, eM, X, true; kwargs...) adjoint_action!(M.manifold, array_value(Y), array_value(p), array_value(X)) is_vector(M, eM, Y, true; kwargs...) diff --git a/src/groups/group.jl b/src/groups/group.jl index da97201a82..dbb3922912 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -168,201 +168,46 @@ switch_direction(::RightAction) = LeftAction() ################################## @doc raw""" - Identity(G::AbstractGroupManifold, p) + Identity{<:AbstractGroupManifold} -The group identity element $e ∈ \mathcal{G}$ represented by point `p`. +The group identity element $e ∈ \mathcal{G}$ on an [`AbstractGroupManifold`](@ref) represented by point `p`. + +see also [`get_point`](@ref) on how to obtain the corresponding point/array representation. +""" +struct Identity{G<:AbstractGroupManifold} end + +@doc raw""" + get_point(G::GT,e::Identity{GT}) where {GT <: AbstractGroupManifold} + +return a point representation of the [`Identity`](@ref) `e` on the [`AbstractGroupManifold`](@ref) `G`. """ -struct Identity{G<:AbstractGroupManifold,PT} - group::G - p::PT +function get_point(G::AbstractGroupManifold, e::Identity) + return DomainError(e, "The identity element $(e) does not belong to $(G).") end -Identity(M::AbstractDecoratorManifold, p) = Identity(decorated_manifold(M), p) -function Identity(M::AbstractManifold, p) +Identity(::G) where {G<:AbstractGroupManifold} = Identity{G}() +Identity(M::AbstractDecoratorManifold) = Identity(decorated_manifold(M)) +function Identity(M::AbstractManifold) return error("Identity not implemented for manifold $(M) and point $(p).") end -function Base.:(==)(e1::Identity, e2::Identity) - return e1.p == e2.p && e1.group == e2.group +function Base.:(==)(::Identity{G1}, ::Identity{G2}) where {G1<:AbstractGroupManifold, G2<:AbstractGroupManifold} + return G1===G2 end -make_identity(M::AbstractManifold, p) = Identity(M, identity(M, p)) - -Base.show(io::IO, e::Identity) = print(io, "Identity($(e.group), $(e.p))") +Base.show(io::IO, ::Identity{G}) where {G} = print(io, "Identity{$G}") # To ensure allocate_result_type works number_eltype(::Identity) = Bool Base.copyto!(e::TE, ::TE) where {TE<:Identity} = e -Base.copyto!(p, ::TE) where {TE<:Identity} = copyto!(p, e.p) -Base.copyto!(p::AbstractArray, e::TE) where {TE<:Identity} = copyto!(p, e.p) - -Base.isapprox(p, e::E; kwargs...) where {E<:Identity} = isapprox(e, p; kwargs...) -Base.isapprox(e::E, p; kwargs...) where {E<:Identity} = isapprox(e.group, e, p; kwargs...) -Base.isapprox(e::E, ::E; kwargs...) where {E<:Identity} = true - -function allocate_result( - M::AbstractManifold, - f::typeof(get_coordinates), - e::Identity, - X, - B::AbstractBasis, -) - T = allocate_result_type(M, f, (e.p, X)) - return allocate(e.p, T, Size(number_of_coordinates(M, B))) -end - -function allocate_result(M::AbstractManifold, f::typeof(get_vector), e::Identity, Xⁱ) - is_group_decorator(M) && return allocate_result(base_group(M), f, e, Xⁱ) - return error( - "allocate_result not implemented for manifold $(M), function $(f), point $(e), and vector $(Xⁱ).", - ) -end -function allocate_result(M::AbstractGroupManifold, f::typeof(get_vector), e::Identity, Xⁱ) - return error( - "allocate_result not implemented for group manifold $(M), function $(f), $(e), and vector $(Xⁱ).", - ) -end -function allocate_result( - G::GT, - ::typeof(get_vector), - ::Identity{GT}, - Xⁱ, -) where {GT<:AbstractGroupManifold} - B = VectorBundleFibers(TangentSpace, G) - return allocate(Xⁱ, Size(representation_size(B))) -end - -function allocate_result( - M::AbstractDecoratorManifold, - f::typeof(get_coordinates), - e::Identity, - X, -) - is_group_decorator(M) && return allocate_result(base_group(M), f, e, X) - return error( - "allocate_result not implemented for manifold $(M), function $(f), point $(e), and vector $(X).", - ) -end -function allocate_result( - M::AbstractGroupManifold, - f::typeof(get_coordinates), - e::Identity, - X, -) - return error( - "allocate_result not implemented for group manifold $(M), function $(f), $(e), and vector $(X).", - ) -end -function allocate_result( - G::GT, - ::typeof(get_coordinates), - ::Identity{GT}, - X, -) where {GT<:AbstractGroupManifold} - return allocate(X, Size(manifold_dimension(G))) -end -function get_vector(M::AbstractGroupManifold, e::Identity, X, B::VeeOrthogonalBasis) - M != e.group && error("On $(M) the identity $(e) does not match to perform get_vector.") - return get_vector(decorated_manifold(M), e.p, X, B) -end -function get_vector(M::AbstractManifold, e::Identity, X, B::VeeOrthogonalBasis) - M != e.group.manifold && - error("On $(M) the identity $(e) does not match to perform get_vector.") - return get_vector(M, e.p, X, B) -end -for MT in GROUP_MANIFOLD_BASIS_DISAMBIGUATION - eval( - quote - @invoke_maker 1 AbstractManifold get_vector( - M::$MT, - e::Identity, - X, - B::VeeOrthogonalBasis, - ) - end, - ) -end -function get_vector!(M::AbstractGroupManifold, Y, e::Identity, X, B::VeeOrthogonalBasis) - M != e.group && error("On $(M) the identity $(e) does not match to perform get_vector!") - return get_vector!(decorated_manifold(M), Y, e.p, X, B) -end -function get_vector!(M::AbstractManifold, Y, e::Identity, X, B::VeeOrthogonalBasis) - M != e.group.manifold && - error("On $(M) the identity $(e) does not match to perform get_vector!") - return get_vector!(M, Y, e.p, X, B) -end -for MT in GROUP_MANIFOLD_BASIS_DISAMBIGUATION - eval( - quote - @invoke_maker 1 AbstractManifold get_vector!( - M::$MT, - Y, - e::Identity, - X, - B::VeeOrthogonalBasis, - ) - end, - ) -end - -function get_coordinates(M::AbstractGroupManifold, e::Identity, X, B::VeeOrthogonalBasis) - M != e.group && - error("On $(M) the identity $(e) does not match to perform get_coordinates") - return get_coordinates(decorated_manifold(M), e.p, X, B) -end -function get_coordinates(M::AbstractManifold, e::Identity, X, B::VeeOrthogonalBasis) - M != e.group.manifold && - error("On $(M) the identity $(e) does not match to perform get_coordinates") - return get_coordinates(M, e.p, X, B) -end -for MT in GROUP_MANIFOLD_BASIS_DISAMBIGUATION - eval( - quote - @invoke_maker 1 AbstractManifold get_coordinates( - M::$MT, - e::Identity, - X, - B::VeeOrthogonalBasis, - ) - end, - ) -end - -function get_coordinates!( - M::AbstractGroupManifold, - Y, - e::Identity, - X, - B::VeeOrthogonalBasis, -) - M != e.group && - error("On $(M) the identity $(e) does not match to perform get_coordinates!") - return get_coordinates!(decorated_manifold(M), Y, e.p, X, B) -end -function get_coordinates!(M::AbstractManifold, Y, e::Identity, X, B::VeeOrthogonalBasis) - M != e.group.manifold && - error("On $(M) the identity $(e) does not match to perform get_coordinates!") - return get_coordinates!(M, Y, e.p, X, B) -end -for MT in GROUP_MANIFOLD_BASIS_DISAMBIGUATION - eval( - quote - @invoke_maker 1 AbstractManifold get_coordinates!( - M::$MT, - Y, - e::Identity, - X, - B::VeeOrthogonalBasis, - ) - end, - ) -end manifold_dimension(G::GroupManifold) = manifold_dimension(G.manifold) +function check_point(G::GT, e::Identity{GT}; kwargs...) where {GT<:AbstractGroupManifold} + return nothing +end function check_point(G::AbstractGroupManifold, e::Identity; kwargs...) - e.group === G && return nothing return DomainError(e, "The identity element $(e) does not belong to $(G).") end @@ -394,15 +239,13 @@ adjoint_action(G::AbstractGroupManifold, p, X) p, Xₑ, ) - e = make_identity(G, p) - Xₚ = translate_diff(G, p, e, Xₑ, LeftAction()) + Xₚ = translate_diff(G, p, Identity(G), Xₑ, LeftAction()) Y = inverse_translate_diff(G, p, p, Xₚ, RightAction()) return Y end function adjoint_action!(G::AbstractGroupManifold, Y, p, Xₑ) - e = make_identity(G, p) - Xₚ = translate_diff(G, p, e, Xₑ, LeftAction()) + Xₚ = translate_diff(G, p, Identity(G), Xₑ, LeftAction()) inverse_translate_diff!(G, Y, p, p, Xₚ, RightAction()) return Y end @@ -424,28 +267,13 @@ end return inv!(G.manifold, q, p) end -@doc raw""" - identity(G::AbstractGroupManifold, p) - -Identity element $e ∈ \mathcal{G}$, such that for any element $p ∈ \mathcal{G}$, -$p \circ e = e \circ p = p$. -The returned element is of a similar type to `p`. -""" -identity(::AbstractGroupManifold, ::Any) -@decorator_transparent_function function Base.identity(G::AbstractGroupManifold, p) - y = allocate_result(G, identity, p) - return identity!(G, y, p) -end - -@decorator_transparent_signature identity!(G::AbstractDecoratorManifold, q, p) - function Base.isapprox( G::GT, e::Identity{GT}, p; kwargs..., ) where {GT<:AbstractGroupManifold} - return isapprox(G, e.p, p; kwargs...) + return isapprox(G, get_point( e.p, p; kwargs...) end function Base.isapprox( G::GT, From 677a7f09db9ecb6fc40548bbea579674a4f15b08 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 22 Jul 2021 18:35:43 +0200 Subject: [PATCH 02/88] Refactor Part I: remove make_identity, identity and identity! (also identity was something completely different to the Base identity method) --- src/groups/array_manifold.jl | 22 +++----------- src/groups/circle_group.jl | 6 ---- src/groups/group.jl | 30 ++++--------------- src/groups/product_group.jl | 22 ++------------ src/groups/semidirect_product_group.jl | 30 ++++++------------- src/groups/special_orthogonal.jl | 2 +- src/tests/tests_group.jl | 31 ++++++++++---------- test/groups/array_manifold.jl | 13 +++------ test/groups/circle_group.jl | 6 +--- test/groups/general_linear.jl | 8 +++--- test/groups/groups_general.jl | 38 ------------------------- test/groups/product_group.jl | 14 ++------- test/groups/semidirect_product_group.jl | 5 ---- test/groups/special_euclidean.jl | 13 ++++----- test/groups/special_linear.jl | 8 +++--- test/groups/special_orthogonal.jl | 10 +++---- 16 files changed, 63 insertions(+), 195 deletions(-) diff --git a/src/groups/array_manifold.jl b/src/groups/array_manifold.jl index ae98be891f..f8f26cb036 100644 --- a/src/groups/array_manifold.jl +++ b/src/groups/array_manifold.jl @@ -35,22 +35,8 @@ function inv!(M::ValidationManifold, q, p; kwargs...) return q end -function Base.identity(M::ValidationManifold, p; kwargs...) - is_point(M, p, true; kwargs...) - q = array_point(identity(M.manifold, array_value(p))) - is_point(M, q, true; kwargs...) - return q -end - -function identity!(M::ValidationManifold, q, p; kwargs...) - is_point(M, p, true; kwargs...) - identity!(M.manifold, array_value(q), array_value(p)) - is_point(M, q, true; kwargs...) - return q -end - function lie_bracket(M::ValidationManifold, X, Y) - eM = make_identity(M.manifold, array_value(X)) + eM = get_point(Identity(M.manifold)) is_vector(M, eM, X, true) is_vector(M, eM, Y, true) Z = ValidationTVector(lie_bracket(M.manifold, array_value(X), array_value(Y))) @@ -59,7 +45,7 @@ function lie_bracket(M::ValidationManifold, X, Y) end function lie_bracket!(M::ValidationManifold, Z, X, Y) - eM = make_identity(M.manifold, array_value(X)) + eM = get_point(Identity(M.manifold)) is_vector(M, eM, X, true) is_vector(M, eM, Y, true) lie_bracket!(M.manifold, array_value(Z), array_value(X), array_value(Y)) @@ -212,7 +198,7 @@ end function group_exp(M::ValidationManifold, X; kwargs...) is_vector( M, - make_identity(M.manifold, array_value(X)), + get_point(Identity(M.manifold)) array_value(X), true; check_base_point=false, @@ -226,7 +212,7 @@ end function group_exp!(M::ValidationManifold, q, X; kwargs...) is_vector( M, - make_identity(M.manifold, array_value(X)), + get_point(Identity(M.manifold)), array_value(X), true; check_base_point=false, diff --git a/src/groups/circle_group.jl b/src/groups/circle_group.jl index 2f82394086..b56497a8e0 100644 --- a/src/groups/circle_group.jl +++ b/src/groups/circle_group.jl @@ -24,12 +24,6 @@ end compose!(G::CircleGroup, x, p, q) = copyto!(x, compose(G, p, q)) -Base.identity(::CircleGroup, p::AbstractVector) = map(one, p) -Base.identity(G::GT, e::Identity{GT}) where {GT<:CircleGroup} = e - -identity!(::CircleGroup, q::AbstractVector, p) = copyto!(q, 1) -identity!(::GT, q::AbstractVector, ::Identity{GT}) where {GT<:CircleGroup} = copyto!(q, 1) - Base.inv(G::CircleGroup, p::AbstractVector) = map(inv, repeated(G), p) Base.inv(G::GT, e::Identity{GT}) where {GT<:CircleGroup} = e diff --git a/src/groups/group.jl b/src/groups/group.jl index dbb3922912..c2759f96e6 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -8,8 +8,6 @@ Abstract type for smooth binary operations $∘$ on elements of a Lie group $\ma An operation can be either defined for a specific [`AbstractGroupManifold`](@ref) over number system `𝔽` or in general, by defining for an operation `Op` the following methods: - identity!(::AbstractGroupManifold{𝔽,Op}, q, q) - identity(::AbstractGroupManifold{𝔽,Op}, p) inv!(::AbstractGroupManifold{𝔽,Op}, q, p) inv(::AbstractGroupManifold{𝔽,Op}, p) compose(::AbstractGroupManifold{𝔽,Op}, p, q) @@ -50,7 +48,7 @@ struct TransparentGroupDecoratorType <: AbstractGroupDecoratorType end Abstract type for a Lie group, a group that is also a smooth manifold with an [`AbstractGroupOperation`](@ref), a smooth binary operation. `AbstractGroupManifold`s must -implement at least [`inv`](@ref), [`identity`](@ref), [`compose`](@ref), and +implement at least [`inv`](@ref), [`compose`](@ref), and [`translate_diff`](@ref). """ abstract type AbstractGroupManifold{𝔽,O<:AbstractGroupOperation,T<:AbstractDecoratorType} <: @@ -254,7 +252,7 @@ end inv(G::AbstractGroupManifold, p) Inverse $p^{-1} ∈ \mathcal{G}$ of an element $p ∈ \mathcal{G}$, such that -$p \circ p^{-1} = p^{-1} \circ p = e ∈ \mathcal{G}$, where $e$ is the [`identity`](@ref) +$p \circ p^{-1} = p^{-1} \circ p = e ∈ \mathcal{G}$, where $e$ is the [`Identity`](@ref) element of $\mathcal{G}$. """ inv(::AbstractGroupManifold, ::Any...) @@ -273,7 +271,7 @@ function Base.isapprox( p; kwargs..., ) where {GT<:AbstractGroupManifold} - return isapprox(G, get_point( e.p, p; kwargs...) + return isapprox(G, get_point(G,e), p; kwargs...) end function Base.isapprox( G::GT, @@ -504,7 +502,7 @@ end Compute the group exponential of the Lie algebra element `X`. It is equivalent to the exponential map defined by the [`CartanSchoutenMinus`](@ref) connection. -Given an element $X ∈ 𝔤 = T_e \mathcal{G}$, where $e$ is the [`identity`](@ref) element of +Given an element $X ∈ 𝔤 = T_e \mathcal{G}$, where $e$ is the [`Identity`](@ref) element of the group $\mathcal{G}$, and $𝔤$ is its Lie algebra, the group exponential is the map ````math @@ -577,7 +575,7 @@ For `Number` and `AbstractMatrix` types of `q`, compute the usual numeric/matrix \log q = \operatorname{Log} q = \sum_{n=1}^∞ \frac{(-1)^{n+1}}{n} (q - e)^n, ```` -where $e$ here is the [`identity`](@ref) element, that is, $1$ for numeric $q$ or the +where $e$ here is the [`Identity`](@ref) element, that is, $1$ for numeric $q$ or the identity matrix $I_m$ for matrix $q ∈ ℝ^{m × m}$. """ group_log(::AbstractGroupManifold, ::Any...) @@ -746,10 +744,6 @@ adjoint_action!(::AdditionGroup, Y, p, X) = copyto!(Y, X) Base.zero(e::Identity{G}) where {G<:AdditionGroup} = e -Base.identity(::AdditionGroup, p) = zero(p) - -identity!(::AdditionGroup, q, p) = fill!(q, 0) - Base.inv(::AdditionGroup, p) = -p inv!(::AdditionGroup, q, p) = copyto!(q, -p) @@ -823,18 +817,8 @@ LinearAlgebra.det(::Identity{<:MultiplicationGroup}) = 1 LinearAlgebra.mul!(q, ::Identity{G}, p) where {G<:MultiplicationGroup} = copyto!(q, p) LinearAlgebra.mul!(q, p, ::Identity{G}) where {G<:MultiplicationGroup} = copyto!(q, p) function LinearAlgebra.mul!(q, e::E, ::E) where {G<:MultiplicationGroup,E<:Identity{G}} - return identity!(e.group, q, e) -end - -Base.identity(::MultiplicationGroup, p) = one(p) - -function identity!(G::GT, q, p) where {GT<:MultiplicationGroup} - isa(p, Identity{GT}) || return copyto!(q, one(p)) - return error( - "identity! not implemented on $(typeof(G)) for points $(typeof(q)) and $(typeof(p))", - ) + return get_point!(q,e) end -identity!(::MultiplicationGroup, q::AbstractMatrix, p) = copyto!(q, I) Base.inv(::MultiplicationGroup, p) = inv(p) @@ -943,8 +927,6 @@ for f in [ group_exp!, group_log, group_log!, - identity, - identity!, translate, translate!, translate_diff, diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 77da490cb1..2e48091d5e 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -79,26 +79,10 @@ function inv!(M::ProductManifold, q, p) return q end -Base.identity(G::ProductGroup, p) = identity(G.manifold, p) -Base.identity(::GT, e::Identity{GT}) where {GT<:ProductGroup} = e -function Base.identity(M::ProductManifold, p::ProductRepr) - return ProductRepr(map(identity, M.manifolds, submanifold_components(M, p))...) -end -function Base.identity(M::ProductManifold, p) - q = allocate_result(M, identity, p) - return identity!(M, q, p) -end - -identity!(G::ProductGroup, q, p) = identity!(G.manifold, q, p) -function identity!(M::ProductManifold, q, p) - map(identity!, M.manifolds, submanifold_components(M, q), submanifold_components(M, p)) - return q -end - compose(G::ProductGroup, p, q) = compose(G.manifold, p, q) -compose(G::GT, ::Identity{GT}, p) where {GT<:ProductGroup} = p -compose(G::GT, p, ::Identity{GT}) where {GT<:ProductGroup} = p -compose(G::GT, e::E, ::E) where {GT<:ProductGroup,E<:Identity{GT}} = e +compose(::GT, ::Identity{GT}, p) where {GT<:ProductGroup} = p +compose(::GT, p, ::Identity{GT}) where {GT<:ProductGroup} = p +compose(::GT, e::E, ::E) where {GT<:ProductGroup,E<:Identity{GT}} = e function compose(M::ProductManifold, p::ProductRepr, q::ProductRepr) return ProductRepr( map( diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index d874eaf873..d3c8b6eeb1 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -79,25 +79,11 @@ function inv!(G::SemidirectProductGroup, q, p) @inbounds _padpoint!(G, q) return q end -inv!(G::AG, p, e::Identity{AG}) where {AG<:SemidirectProductGroup} = identity!(G, p, e) +inv!(G::AG, p, e::Identity{AG}) where {AG<:SemidirectProductGroup} = copyto!(p, get_point(G,e)) -Base.identity(G::GT, e::Identity{GT}) where {GT<:SemidirectProductGroup} = e - -function identity!(G::SemidirectProductGroup, q, p) - M = base_manifold(G) - N, H = M.manifolds - np, hp = submanifold_components(G, p) - nq, hq = submanifold_components(G, q) - identity!(N, nq, np) - identity!(H, hq, hp) - @inbounds _padpoint!(G, q) - return q -end -identity!(G::GT, e::E, ::E) where {GT<:SemidirectProductGroup,E<:Identity{GT}} = e - -compose(G::GT, p, e::Identity{GT}) where {GT<:SemidirectProductGroup} = p -compose(G::GT, e::Identity{GT}, p) where {GT<:SemidirectProductGroup} = p -compose(G::GT, e::E, ::E) where {GT<:SemidirectProductGroup,E<:Identity{GT}} = e +compose(::GT, p, e::Identity{GT}) where {GT<:SemidirectProductGroup} = p +compose(::GT, e::Identity{GT}, p) where {GT<:SemidirectProductGroup} = p +compose(::GT, e::E, ::E) where {GT<:SemidirectProductGroup,E<:Identity{GT}} = e function compose!(G::SemidirectProductGroup, x, p, q) M = base_manifold(G) @@ -112,10 +98,10 @@ function compose!(G::SemidirectProductGroup, x, p, q) @inbounds _padpoint!(G, x) return x end -compose!(G::GT, x, ::Identity{GT}, q) where {GT<:SemidirectProductGroup} = copyto!(x, q) -compose!(G::GT, x, p, ::Identity{GT}) where {GT<:SemidirectProductGroup} = copyto!(x, p) +compose!(::GT, x, ::Identity{GT}, q) where {GT<:SemidirectProductGroup} = copyto!(x, q) +compose!(::GT, x, p, ::Identity{GT}) where {GT<:SemidirectProductGroup} = copyto!(x, p) function compose!(G::GT, x, e::E, ::E) where {GT<:SemidirectProductGroup,E<:Identity{GT}} - return identity!(G, x, e) + return copyto!(x, get_point(G,e)) end @doc raw""" @@ -247,7 +233,7 @@ function Base.isapprox( p; kwargs..., ) where {GT<:SemidirectProductGroup} - return isapprox(G, identity(G, p), p; kwargs...) + return isapprox(G, get_point(G, e), p; kwargs...) end function Base.isapprox( ::GT, diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index bcac52c625..eb045ddf52 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -45,7 +45,7 @@ group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, make_identity(G, q).p, X) group_log!(G::SpecialOrthogonal, X, q) = log!(G, X, make_identity(G, q).p, q) function group_log!(G::SpecialOrthogonal, X::AbstractMatrix, q::AbstractMatrix) - return log!(G, X, make_identity(G, q).p, q) + return log!(G, X, Identity(G), q) end function allocate_result( diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index bad48187ab..5646bafb8e 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -1,3 +1,4 @@ +using Base: IdentityUnitRange """ test_group( G, @@ -37,7 +38,7 @@ function test_group( test_adjoint_action=false, diff_convs=[(), (LeftAction(),), (RightAction(),)], ) - e = make_identity(G, g_pts[1]) + e = Identity(G) Test.@testset "Basic group properties" begin Test.@testset "Closed" begin @@ -64,7 +65,6 @@ function test_group( Test.@testset "Identity" begin Test.@test isapprox(G, e, e) - Test.@test identity(G, e) === e Test.@test compose(G, e, e) === e Test.@test copyto!(e, e) === e @@ -72,7 +72,7 @@ function test_group( Test.@test isapprox(G, compose(G, g, e), g) Test.@test isapprox(G, compose(G, e, g), g) - ge = identity(G, g) + ge = Identity(G) Test.@test isapprox(G, compose(G, g, ge), g) Test.@test isapprox(G, compose(G, ge, g), g) end @@ -87,7 +87,6 @@ function test_group( Test.@test isapprox(G, h, g) ge = allocate(g) - Test.@test identity!(G, ge, e) === ge Test.@test isapprox(G, compose(G, g, ge), g) Test.@test isapprox(G, compose(G, ge, g), g) @@ -288,16 +287,16 @@ function test_group( test_group_exp_log && Test.@testset "group exp/log properties" begin Test.@testset "e = exp(0)" begin - X = group_log(G, identity(G, g_pts[1])) + X = group_log(G, Identity(G)) g = group_exp(G, X) - Test.@test isapprox(G, make_identity(G, g_pts[1]), g; atol=atol) + Test.@test isapprox(G, Identity(G), g; atol=atol) test_mutating && Test.@testset "mutating" begin X = allocate(Xe_pts[1]) - Test.@test group_log!(G, X, identity(G, g_pts[1])) === X + Test.@test group_log!(G, X, Identity(G)) === X g = allocate(g_pts[1]) Test.@test group_exp!(G, g, X) === g - Test.@test isapprox(G, make_identity(G, g_pts[1]), g; atol=atol) + Test.@test isapprox(G, Identity(G), g; atol=atol) end end @@ -306,7 +305,7 @@ function test_group( g = group_exp(G, X) Test.@test is_point(G, g; atol=atol) X2 = group_log(G, g) - Test.@test isapprox(G, make_identity(G, g_pts[1]), X2, X; atol=atol) + Test.@test isapprox(G, Identity(G), X2, X; atol=atol) end test_mutating && Test.@testset "mutating" begin @@ -317,7 +316,7 @@ function test_group( Test.@test isapprox(G, g, group_exp(G, X); atol=atol) X2 = allocate(X) Test.@test group_log!(G, X2, g) === X2 - Test.@test isapprox(G, make_identity(G, g_pts[1]), X2, X; atol=atol) + Test.@test isapprox(G, Identity(G), X2, X; atol=atol) end end end @@ -415,7 +414,7 @@ function test_group( # linearity X = Xe_pts[1] Y = Xe_pts[2] - e = identity(G, X) + e = Identity(G) Test.@test isapprox( G, e, @@ -454,7 +453,7 @@ function test_group( # anticommutativity X = X_pts[1] Y = X_pts[2] - e = identity(G, X) + e = Identity(G) Test.@test isapprox(G, e, lie_bracket(G, X, Y), -lie_bracket(G, Y, X)) if test_mutating @@ -503,7 +502,7 @@ function test_action( ) G = base_group(A) M = g_manifold(A) - e = make_identity(G, a_pts[1]) + e = Identity(G) Test.@testset "Basic action properties" begin test_switch_direction && Test.@testset "Direction" begin @@ -576,7 +575,7 @@ function test_action( Test.@test isapprox(G, compose(A, a, e), a; atol=atol_ident_compose) Test.@test isapprox(G, compose(A, e, a), a; atol=atol_ident_compose) - ge = identity(G, a) + ge = Identity(G) Test.@test isapprox(G, compose(A, a, ge), a; atol=atol_ident_compose) Test.@test isapprox(G, compose(A, ge, a), a; atol=atol_ident_compose) @@ -597,11 +596,11 @@ function test_action( Test.@test compose!(A, h, e, a) === h Test.@test isapprox(G, h, a) - ge = identity(G, a) + ge = Identity(G) Test.@test isapprox(G, compose(A, a, ge), a) Test.@test isapprox(G, compose(A, ge, a), a) - ge = identity(G, a) + ge = Identity(G) Test.@test compose!(A, ge, e, e) === ge Test.@test isapprox(G, ge, e) diff --git a/test/groups/array_manifold.jl b/test/groups/array_manifold.jl index 2d3f25b36b..524239bea3 100644 --- a/test/groups/array_manifold.jl +++ b/test/groups/array_manifold.jl @@ -13,24 +13,19 @@ include("../utils.jl") p, q = [exp(M, eg, hat(M, eg, ωi)) for ωi in ω] X = hat(M, eg, [-1.0, 2.0, 0.5]) - e = make_identity(AG, p) + e = Identity(AG) @test Manifolds.array_value(e).p == Manifolds.array_value(e.p) @test Manifolds.array_point(e).p == e.p p2, q2 = ValidationMPoint(p), ValidationMPoint(q) @test q2 === Manifolds.array_point(q2) # test that double wraps are avoided. X2 = ValidationTVector(X) - @test identity(AG, p2) isa ValidationMPoint - @test isapprox(G, identity(AG, p2).value, identity(G, p)) - @test identity(AG, e) isa Identity - @test_throws DomainError identity(AG, Identity(TranslationGroup(3), ω[1])) + @test Identity(AG, e) isa Identity eg = allocate(p2) - identity!(AG, eg, p2) - @test isapprox(G, eg.value, identity(G, p)) + get_point!(G, eg, Identity(AG)) + @test isapprox(G, eg, Identity(G)) eg = allocate(p2) - identity!(AG, eg, e) - @test isapprox(G, eg.value, identity(G, p)) @test inv(AG, p2) isa ValidationMPoint @test isapprox(G, inv(AG, p2).value, inv(G, p)) diff --git a/test/groups/circle_group.jl b/test/groups/circle_group.jl index 9eb25ca23d..1c91cf7b8b 100644 --- a/test/groups/circle_group.jl +++ b/test/groups/circle_group.jl @@ -20,14 +20,10 @@ using Manifolds: invariant_metric_dispatch, default_metric_dispatch @test is_default_metric(MetricManifold(G, EuclideanMetric())) @testset "identity overloads" begin - ig = Identity(G, [Complex(1.0)]) - @test identity(G, ig) === ig + ig = Identity(G) @test inv(G, ig) === ig @test allocate_result(G, get_coordinates, ig, Complex(1.0), DefaultBasis()) isa Array{Complex{Float64},1} - y = [Complex(0.0)] - @test identity!(G, y, [Complex(1.0)]) === y - @test y == [Complex(1.0)] y = [1.0 * im] v = [Complex(0.5)] @test translate_diff(G, ig, y, v) === v diff --git a/test/groups/general_linear.jl b/test/groups/general_linear.jl index 1a9e3807d6..c7360c44c1 100644 --- a/test/groups/general_linear.jl +++ b/test/groups/general_linear.jl @@ -80,11 +80,11 @@ using NLsolve @test_throws DomainError is_point(G, Float64[0 0 0; 0 1 1; 1 1 1], true) @test_throws DomainError is_point( G, - make_identity(GeneralLinear(2), ones(2, 2)), + Identity(GeneralLinear(2)), true, ) @test is_point(G, Float64[0 0 1; 0 1 1; 1 1 1], true) - @test is_point(G, make_identity(G, ones(3, 3)), true) + @test is_point(G, Identity(G), true) @test_throws DomainError is_vector( G, Float64[0 1 1; 0 1 1; 1 0 0], @@ -159,11 +159,11 @@ using NLsolve @test_throws DomainError is_point(G, zeros(2, 2), true) @test_throws DomainError is_point(G, ComplexF64[1 im; 1 im], true) @test is_point(G, ComplexF64[1 1; im 1], true) - @test is_point(G, make_identity(G, ones(ComplexF64, 2, 2)), true) + @test is_point(G, Identity(G), true) @test_throws DomainError is_point(G, Float64[0 0 0; 0 1 1; 1 1 1], true) @test_throws DomainError is_point( G, - make_identity(GeneralLinear(3), ones(3, 3)), + Identity(GeneralLinear(3)), true, ) @test_throws DomainError is_vector( diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 81c65909c4..0b3f4e729e 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -97,8 +97,6 @@ include("group_utils.jl") @test copyto!(x, eg) === x @test isapprox(G, x, eg) - @test_throws ErrorException identity!(G, x, x) - @test_throws ErrorException identity(G, x) @test_throws ErrorException compose(G, x, x) @test_throws ErrorException compose(G, x, eg) @@ -153,8 +151,6 @@ include("group_utils.jl") for f in [get_vector, get_coordinates] @test Manifolds.decorator_transparent_dispatch(f, G) === Val{:parent}() end - @test Manifolds.decorator_transparent_dispatch(identity!, G, x, x) === - Val{:intransparent}() @test Manifolds.decorator_transparent_dispatch(isapprox, G, eg, x) === Val{:transparent}() @test Manifolds.decorator_transparent_dispatch(isapprox, G, x, eg) === @@ -210,11 +206,6 @@ include("group_utils.jl") @test zero(ge) == ge @test inv(G, x) ≈ -x @test inv(G, ge) === ge - @test identity(G, x) ≈ zero(x) - @test identity(G, ge) === ge - y = allocate(x) - identity!(G, y, x) - @test y ≈ zero(x) @test compose(G, x, x) ≈ x + x @test compose(G, x, ge) ≈ x @test compose(G, ge, x) ≈ x @@ -227,11 +218,6 @@ include("group_utils.jl") @test y ≈ x @test group_exp(G, v) === v @test group_log(G, x) === x - - y = identity(G, x) - @test isapprox(y, ge; atol=1e-10) - @test isapprox(ge, y; atol=1e-10) - @test isapprox(ge, ge) end @testset "Multiplication operation" begin @@ -279,11 +265,6 @@ include("group_utils.jl") @test ge.p ≈ one(x) @test inv(G, x) ≈ inv(x) @test inv(G, ge) === ge - @test identity(G, x) ≈ one(x) - @test identity(G, ge) === ge - y = allocate(x) - identity!(G, y, x) - @test y ≈ one(x) z = allocate(x) copyto!(G, z, x) z2 = allocate(x) @@ -296,7 +277,6 @@ include("group_utils.jl") copyto!(G.manifold, Y2, x, X) @test Y == Y2 - @test_throws ErrorException identity!(G, [0.0], ge) @test compose(G, x, x) ≈ x * x @test compose(G, x, ge) ≈ x @test compose(G, ge, x) ≈ x @@ -314,24 +294,6 @@ include("group_utils.jl") Y = allocate(X) @test group_log!(G, Y, y) === Y @test Y ≈ log(y) - - @testset "identity optimization" begin - x2 = copy(x) - identity!(G, x2, x) - x3 = copy(x) - invoke( - identity!, - Tuple{ - AbstractGroupManifold{ℝ,Manifolds.MultiplicationOperation}, - Any, - AbstractMatrix, - }, - G, - x3, - x, - ) - @test isapprox(G, x2, x3) - end end @testset "Identity on Group Manifolds" begin diff --git a/test/groups/product_group.jl b/test/groups/product_group.jl index 44b3af4780..a7f7e0eda6 100644 --- a/test/groups/product_group.jl +++ b/test/groups/product_group.jl @@ -26,16 +26,6 @@ include("group_utils.jl") shape_se = Manifolds.ShapeSpecification(Manifolds.ArrayReshaper(), M.manifolds...) e = Manifolds.prod_point(shape_se, eA...) - @testset "identity specializations" begin - @test inv(G, Identity(G, e)) === Identity(G, e) - @test identity(G, Identity(G, e)) === Identity(G, e) - @test submanifold_component(G, Identity(G, e), Val(1)) == Identity(SOn, x) - @test submanifold_component(G, Identity(G, e), Val(2)) == Identity(Tn, zeros(2)) - @test submanifold_components(G, Identity(G, e)) == - (Identity(SOn, x), Identity(Tn, zeros(2))) - @test compose(G, Identity(G, e), Identity(G, e)) === Identity(G, e) - end - @testset "product point" begin reshapers = (Manifolds.ArrayReshaper(), Manifolds.StaticReshaper()) for reshaper in reshapers @@ -47,7 +37,7 @@ include("group_utils.jl") test_group(G, pts, v_pts, v_pts; test_diff=true) @test isapprox( M, - identity(M, pts[1]), + Identity(M), group_exp(M, v_pts[1]), Manifolds.prod_point( shape_se, @@ -57,7 +47,7 @@ include("group_utils.jl") ) @test isapprox( M, - identity(M, pts[1]), + Identity(M), group_log(M, pts[1]), Manifolds.prod_point( shape_se, diff --git a/test/groups/semidirect_product_group.jl b/test/groups/semidirect_product_group.jl index f006ad0523..1fb2784042 100644 --- a/test/groups/semidirect_product_group.jl +++ b/test/groups/semidirect_product_group.jl @@ -31,11 +31,6 @@ include("group_utils.jl") @test norm(G, pts[1], Y) ≈ 0 @test norm(G, pts[1], Z) ≈ 0 - e = Identity(G, (zeros(2), zeros(2))) - @test inv(G, e) === e - @test identity(G, e) === e - @test identity!(G, e, e) === e - @test compose(G, e, pts[1]) == pts[1] @test compose(G, pts[1], e) == pts[1] @test compose(G, e, e) === e diff --git a/test/groups/special_euclidean.jl b/test/groups/special_euclidean.jl index 8c4a861462..4fcb602e86 100644 --- a/test/groups/special_euclidean.jl +++ b/test/groups/special_euclidean.jl @@ -62,7 +62,7 @@ using ManifoldsBase: VeeOrthogonalBasis Manifolds._padvector!(G, tmp) @test tmp == X_pts[1] - w = translate_diff(G, pts[1], make_identity(G, pts[1]), X_pts[1]) + w = translate_diff(G, pts[1], Identity(G), X_pts[1]) w2 = allocate(w) w2.parts[1] .= w.parts[1] w2.parts[2] .= pts[1].parts[2] * w.parts[2] @@ -92,10 +92,10 @@ using ManifoldsBase: VeeOrthogonalBasis g1g2mat = affine_matrix(G, g1g2) @test g1g2mat ≈ affine_matrix(G, g1) * affine_matrix(G, g2) @test affine_matrix(G, g1g2mat) === g1g2mat - @test affine_matrix(G, make_identity(G, pts[1])) isa SDiagonal{n,Float64} - @test affine_matrix(G, make_identity(G, pts[1])) == SDiagonal{n,Float64}(I) + @test affine_matrix(G, Identity(G)) isa SDiagonal{n,Float64} + @test affine_matrix(G, Identity(G)) == SDiagonal{n,Float64}(I) - w = translate_diff(G, pts[1], make_identity(G, pts[1]), X_pts[1]) + w = translate_diff(G, pts[1], Identity(G), X_pts[1]) w2 = allocate(w) w2.parts[1] .= w.parts[1] w2.parts[2] .= pts[1].parts[2] * w.parts[2] @@ -146,9 +146,8 @@ using ManifoldsBase: VeeOrthogonalBasis end G = SpecialEuclidean(11) - @test affine_matrix(G, make_identity(G, ones(12, 12))) isa - Diagonal{Float64,Vector{Float64}} - @test affine_matrix(G, make_identity(G, ones(12, 12))) == Diagonal(ones(11)) + @test affine_matrix(G, Identity(G)) isa Diagonal{Float64,Vector{Float64}} + @test affine_matrix(G, Identity(G)) == Diagonal(ones(11)) @testset "Explicit embedding in GL(n+1)" begin G = SpecialEuclidean(3) diff --git a/test/groups/special_linear.jl b/test/groups/special_linear.jl index d92dcdb531..82be3c42fe 100644 --- a/test/groups/special_linear.jl +++ b/test/groups/special_linear.jl @@ -55,11 +55,11 @@ using NLsolve @test_throws DomainError is_point(G, Float64[1 3 3; 1 1 2; 1 2 3], true) @test_throws DomainError is_point( G, - make_identity(SpecialLinear(2), ones(2, 2)), + Identity(SpecialLinear(2)), true, ) @test is_point(G, Float64[1 1 1; 2 2 1; 2 3 3], true) - @test is_point(G, make_identity(G, ones(3, 3)), true) + @test is_point(G, Identity(G), true) @test_throws DomainError is_vector( G, Float64[2 3 2; 3 1 2; 1 1 1], @@ -157,11 +157,11 @@ using NLsolve @test_throws DomainError is_point(G, ComplexF64[1 im; im 1], true) @test_throws DomainError is_point( G, - make_identity(SpecialLinear(2), ones(ComplexF64, 2, 2)), + Identity(SpecialLinear(2)), true, ) @test is_point(G, ComplexF64[im 1; -2 im], true) - @test is_point(G, make_identity(G, ones(3, 3)), true) + @test is_point(G, Identity(G), true) @test_throws DomainError is_vector( G, ComplexF64[-1+im -1; -im 1], diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index 744eada676..f79d851873 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -28,7 +28,7 @@ include("group_utils.jl") vpts = [hat(M, x, [-1.0, 2.0, 0.5]), hat(M, x, [1.0, 0.0, 0.5])] ge = allocate(pts[1]) - copyto!(ge, make_identity(G, pts[1])) + copyto!(ge, get_point(G, Identity(G))) @test isapprox(ge, I; atol=1e-10) gI = Identity(G, ge) @@ -65,7 +65,7 @@ include("group_utils.jl") @test base_group(DM) === G @test_throws DomainError is_point( DM, - make_identity(TranslationGroup(3), [1, 2, 3]), + Identity(TranslationGroup(3)), true, ) test_group(DM, pts, vpts, vpts; test_diff=true) @@ -136,12 +136,12 @@ include("group_utils.jl") @testset "vee/hat" begin X = vpts[1] - pe = identity(G, pts[1]) + pe = Identity(G) - Xⁱ = vee(G, make_identity(G, pts[1]), X) + Xⁱ = vee(G, get_point(G,pe), X) @test Xⁱ ≈ vee(G, pe, X) - X2 = hat(G, make_identity(G, pts[1]), Xⁱ) + X2 = hat(G, pts[1], Xⁱ) @test isapprox(M, pe, X2, hat(G, pe, Xⁱ); atol=1e-6) end @testset "Identity and get_vector/get_coordinates" begin From c5f32800e5def9a1fbce24d8544f856d28fc3f52 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 23 Jul 2021 12:03:03 +0200 Subject: [PATCH 03/88] Finish reduction of Identity to a plain non-parametric type. --- src/groups/array_manifold.jl | 6 +- src/groups/circle_group.jl | 15 +-- src/groups/general_linear.jl | 11 +- src/groups/group.jl | 139 ++++++++++--------------- src/groups/product_group.jl | 25 ++--- src/groups/semidirect_product_group.jl | 64 +----------- src/groups/special_euclidean.jl | 2 +- src/groups/special_linear.jl | 5 - src/groups/special_orthogonal.jl | 8 +- src/groups/translation_action.jl | 20 ++-- 10 files changed, 90 insertions(+), 205 deletions(-) diff --git a/src/groups/array_manifold.jl b/src/groups/array_manifold.jl index f8f26cb036..952eeb7a86 100644 --- a/src/groups/array_manifold.jl +++ b/src/groups/array_manifold.jl @@ -198,7 +198,7 @@ end function group_exp(M::ValidationManifold, X; kwargs...) is_vector( M, - get_point(Identity(M.manifold)) + get_point(Identity(M.manifold)), array_value(X), true; check_base_point=false, @@ -228,7 +228,7 @@ function group_log(M::ValidationManifold, q; kwargs...) X = ValidationTVector(group_log(M.manifold, array_value(q))) is_vector( M, - make_identity(M.manifold, array_value(X)), + get_point(Identity(M.manifold)), array_value(X), true; check_base_point=false, @@ -242,7 +242,7 @@ function group_log!(M::ValidationManifold, X, q; kwargs...) group_log!(M.manifold, array_value(X), array_value(q)) is_vector( M, - make_identity(M.manifold, array_value(X)), + get_point(Identity(M.manifold)), array_value(X), true; check_base_point=false, diff --git a/src/groups/circle_group.jl b/src/groups/circle_group.jl index b56497a8e0..686419e6c1 100644 --- a/src/groups/circle_group.jl +++ b/src/groups/circle_group.jl @@ -25,7 +25,6 @@ end compose!(G::CircleGroup, x, p, q) = copyto!(x, compose(G, p, q)) Base.inv(G::CircleGroup, p::AbstractVector) = map(inv, repeated(G), p) -Base.inv(G::GT, e::Identity{GT}) where {GT<:CircleGroup} = e function inverse_translate( ::CircleGroup, @@ -49,21 +48,13 @@ lie_bracket(::CircleGroup, X, Y) = zero(X) lie_bracket!(::CircleGroup, Z, X, Y) = fill!(Z, 0) translate_diff(::GT, p, q, X, ::ActionDirection) where {GT<:CircleGroup} = map(*, p, X) -function translate_diff( - ::GT, - ::Identity{GT}, - q, - X, - ::ActionDirection, -) where {GT<:CircleGroup} - return X -end +translate_diff(::CircleGroup, ::Identity, q, X, ::ActionDirection) = X function translate_diff!(G::CircleGroup, Y, p, q, X, conv::ActionDirection) return copyto!(Y, translate_diff(G, p, q, X, conv)) end -function group_exp(G::CircleGroup, X) +function group_exp(::CircleGroup, X) return map(X) do imθ θ = imag(imθ) sinθ, cosθ = sincos(θ) @@ -73,7 +64,7 @@ end group_exp!(G::CircleGroup, q, X) = (q .= group_exp(G, X)) -function group_log(G::CircleGroup, q) +function group_log(::CircleGroup, q) return map(q) do z cosθ, sinθ = reim(z) θ = atan(sinθ, cosθ) diff --git a/src/groups/general_linear.jl b/src/groups/general_linear.jl index 2421366668..3b13615bc5 100644 --- a/src/groups/general_linear.jl +++ b/src/groups/general_linear.jl @@ -37,11 +37,6 @@ function check_point(G::GeneralLinear, p; kwargs...) end return nothing end -check_point(::GT, ::Identity{GT}; kwargs...) where {GT<:GeneralLinear} = nothing -function check_point(G::GeneralLinear, e::Identity; kwargs...) - return DomainError(e, "The identity element $(e) does not belong to $(G).") -end - function check_vector(G::GeneralLinear, p, X; kwargs...) mpv = check_vector(decorated_manifold(G), p, X; kwargs...) mpv === nothing || return mpv @@ -198,7 +193,6 @@ log(::GeneralLinear, p, q) function log!(G::GeneralLinear{n,𝔽}, X, p, q) where {n,𝔽} pinvq = inverse_translate(G, p, q, LeftAction()) 𝔽 === ℝ && det(pinvq) ≤ 0 && throw(OutOfInjectivityRadiusError()) - e = Identity(G, pinvq) if isnormal(pinvq; atol=sqrt(eps(real(eltype(pinvq))))) log_safe!(X, pinvq) else @@ -207,13 +201,12 @@ function log!(G::GeneralLinear{n,𝔽}, X, p, q) where {n,𝔽} Gᵣ = GeneralLinear(real_dimension(𝔽) * n, ℝ) pinvqᵣ = realify(pinvq, 𝔽) Xᵣ = realify(X, 𝔽) - eᵣ = Identity(Gᵣ, pinvqᵣ) log_safe!(Xᵣ, _project_Un_S⁺(pinvqᵣ)) inverse_retraction = NLsolveInverseRetraction(ExponentialRetraction(), Xᵣ) - inverse_retract!(Gᵣ, Xᵣ, eᵣ, pinvqᵣ, inverse_retraction) + inverse_retract!(Gᵣ, Xᵣ, Identity(), pinvqᵣ, inverse_retraction) unrealify!(X, Xᵣ, 𝔽, n) end - translate_diff!(G, X, p, e, X, LeftAction()) + translate_diff!(G, X, p, Identity(), X, LeftAction()) return X end function log!(::GeneralLinear{1}, X, p, q) diff --git a/src/groups/group.jl b/src/groups/group.jl index c2759f96e6..fd068e1ba4 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -127,6 +127,8 @@ function (::Type{T})(M::AbstractManifold) where {T<:AbstractGroupOperation} return GroupManifold(M, T()) end +manifold_dimension(G::GroupManifold) = manifold_dimension(G.manifold) + ################### # Action directions ################### @@ -166,48 +168,36 @@ switch_direction(::RightAction) = LeftAction() ################################## @doc raw""" - Identity{<:AbstractGroupManifold} + Identity + +Represent the group identity element $e ∈ \mathcal{G}$ on an [`AbstractGroupManifold`](@ref) `G`. -The group identity element $e ∈ \mathcal{G}$ on an [`AbstractGroupManifold`](@ref) represented by point `p`. +Similar to the philosophy that points are agnostic of their group at hand, the identity +does not store the group ` g` it belongs to. -see also [`get_point`](@ref) on how to obtain the corresponding point/array representation. +see also [`get_point`](@ref) on how to obtain the corresponding [`AbstractManifoldPoint`](@ref) or array representation. """ -struct Identity{G<:AbstractGroupManifold} end +struct Identity end @doc raw""" - get_point(G::GT,e::Identity{GT}) where {GT <: AbstractGroupManifold} + get_point(G::AbstractGroupManifold,e::Identity) + get_point!(G::AbstractGroupManifold, p, e::Identity) -return a point representation of the [`Identity`](@ref) `e` on the [`AbstractGroupManifold`](@ref) `G`. +return a point representation of the [`Identity`](@ref) `e` on the [`AbstractGroupManifold`](@ref) `G` (in place of `p`) """ function get_point(G::AbstractGroupManifold, e::Identity) - return DomainError(e, "The identity element $(e) does not belong to $(G).") -end - -Identity(::G) where {G<:AbstractGroupManifold} = Identity{G}() -Identity(M::AbstractDecoratorManifold) = Identity(decorated_manifold(M)) -function Identity(M::AbstractManifold) - return error("Identity not implemented for manifold $(M) and point $(p).") -end - -function Base.:(==)(::Identity{G1}, ::Identity{G2}) where {G1<:AbstractGroupManifold, G2<:AbstractGroupManifold} - return G1===G2 + q = allocate_result(G, e) + return get_point!(G, q, e) end -Base.show(io::IO, ::Identity{G}) where {G} = print(io, "Identity{$G}") +Base.show(io::IO, ::Identity) = print(io, "Identity()") # To ensure allocate_result_type works number_eltype(::Identity) = Bool -Base.copyto!(e::TE, ::TE) where {TE<:Identity} = e - -manifold_dimension(G::GroupManifold) = manifold_dimension(G.manifold) +Base.copyto!(e::Identity, ::Identity) = e -function check_point(G::GT, e::Identity{GT}; kwargs...) where {GT<:AbstractGroupManifold} - return nothing -end -function check_point(G::AbstractGroupManifold, e::Identity; kwargs...) - return DomainError(e, "The identity element $(e) does not belong to $(G).") -end +check_point(G::AbstractGroupManifold, e::Identity; kwargs...) = nothing ########################## # Group-specific functions @@ -261,34 +251,23 @@ inv(::AbstractGroupManifold, ::Any...) return inv!(G, q, p) end +Base.inv(::AbstractGroupManifold, e::Identity) = e + @decorator_transparent_function function inv!(G::AbstractGroupManifold, q, p) return inv!(G.manifold, q, p) end -function Base.isapprox( - G::GT, - e::Identity{GT}, - p; - kwargs..., -) where {GT<:AbstractGroupManifold} +inv!(G::AbstractGroupManifold, q, e::Identity) = get_point!(G, q, e) + +function Base.isapprox(G::AbstractGroupManifold, e::Identity, p; kwargs...) return isapprox(G, get_point(G,e), p; kwargs...) end -function Base.isapprox( - G::GT, - p, - e::Identity{GT}; - kwargs..., -) where {GT<:AbstractGroupManifold} +function Base.isapprox(G::AbstractGroupManifold, p, e::Identity; kwargs...) return isapprox(G, e, p; kwargs...) end -function Base.isapprox( - ::GT, - ::E, - ::E; - kwargs..., -) where {GT<:AbstractGroupManifold,E<:Identity{GT}} - return true -end +Base.isapprox(::AbstractGroupManifold, ::Identity, ::Identity; kwargs...) = true + +Base.one(e::Identity) = e @doc raw""" compose(G::AbstractGroupManifold, p, q) @@ -303,6 +282,11 @@ end @decorator_transparent_signature compose!(M::AbstractDecoratorManifold, x, p, q) +compose!(::AbstractGroupManifold, q, p, ::Identity) = copyto!(q,p) +compose!(::AbstractGroupManifold, q, ::Identity, p) = copyto!(q,p) +compose!(G::AbstractGroupManifold, q, ::Identity, e::Identity) = copyto(q, get_point(G,e)) +compose!(::AbstractGroupManifold, e::Identity, ::Identity, ::Identity) = e + """ lie_bracket(G::AbstractGroupManifold, X, Y) @@ -722,28 +706,20 @@ struct AdditionOperation <: AbstractGroupOperation end const AdditionGroup = AbstractGroupManifold{𝔽,AdditionOperation} where {𝔽} -Base.:+(e::Identity{G}) where {G<:AdditionGroup} = e -Base.:+(p::Identity{G}, ::Identity{G}) where {G<:AdditionGroup} = p -Base.:+(::Identity{G}, p) where {G<:AdditionGroup} = p -Base.:+(p, ::Identity{G}) where {G<:AdditionGroup} = p -Base.:+(e::E, ::E) where {G<:AdditionGroup,E<:Identity{G}} = e - -Base.:-(e::Identity{G}) where {G<:AdditionGroup} = e -Base.:-(e::Identity{G}, ::Identity{G}) where {G<:AdditionGroup} = e -Base.:-(::Identity{G}, p) where {G<:AdditionGroup} = -p -Base.:-(p, ::Identity{G}) where {G<:AdditionGroup} = p -Base.:-(e::E, ::E) where {G<:AdditionGroup,E<:Identity{G}} = e +Base.:+(e::Identity) = e +Base.:+(e::Identity, ::Identity) = e +Base.:+(::Identity, p) = p +Base.:+(p, ::Identity) = p -Base.:*(e::Identity{G}, p) where {G<:AdditionGroup} = e -Base.:*(p, e::Identity{G}) where {G<:AdditionGroup} = e -Base.:*(e::E, ::E) where {G<:AdditionGroup,E<:Identity{G}} = e +Base.:-(e::Identity) = e +Base.:-(e::Identity, ::Identity) = e +Base.:-(::Identity, p) = -p +Base.:-(p, ::Identity) = p adjoint_action(::AdditionGroup, p, X) = X adjoint_action!(::AdditionGroup, Y, p, X) = copyto!(Y, X) -Base.zero(e::Identity{G}) where {G<:AdditionGroup} = e - Base.inv(::AdditionGroup, p) = -p inv!(::AdditionGroup, q, p) = copyto!(q, -p) @@ -792,33 +768,24 @@ struct MultiplicationOperation <: AbstractGroupOperation end const MultiplicationGroup = AbstractGroupManifold{𝔽,MultiplicationOperation} where {𝔽} -Base.:*(e::Identity{G}) where {G<:MultiplicationGroup} = e -Base.:*(::Identity{G}, p) where {G<:MultiplicationGroup} = p -Base.:*(p, ::Identity{G}) where {G<:MultiplicationGroup} = p -Base.:*(e::E, ::E) where {G<:MultiplicationGroup,E<:Identity{G}} = e -Base.:*(::Identity{<:MultiplicationGroup}, e::Identity{<:AdditionGroup}) = e - -Base.:/(p, ::Identity{G}) where {G<:MultiplicationGroup} = p -Base.:/(::Identity{G}, p) where {G<:MultiplicationGroup} = inv(p) -Base.:/(e::E, ::E) where {G<:MultiplicationGroup,E<:Identity{G}} = e - -Base.:\(p, ::Identity{G}) where {G<:MultiplicationGroup} = inv(p) -Base.:\(::Identity{G}, p) where {G<:MultiplicationGroup} = p -Base.:\(e::E, ::E) where {G<:MultiplicationGroup,E<:Identity{G}} = e +Base.:*(e::Identity) = e +Base.:*(::Identity, p) = p +Base.:*(p, ::Identity) = p +Base.:*(e::Identity, ::Identity) = e -Base.inv(e::Identity{G}) where {G<:MultiplicationGroup} = e +Base.:/(p, ::Identity) = p +Base.:/(::Identity, p) = inv(p) +Base.:/(e::Identity, ::Identity) = e -Base.one(e::Identity{G}) where {G<:MultiplicationGroup} = e +Base.:\(p, ::Identity) = inv(p) +Base.:\(::Identity, p) = p +Base.:\(e::Identity, ::Identity) = e -Base.transpose(e::Identity{G}) where {G<:MultiplicationGroup} = e +LinearAlgebra.det(::Identity) = 1 -LinearAlgebra.det(::Identity{<:MultiplicationGroup}) = 1 - -LinearAlgebra.mul!(q, ::Identity{G}, p) where {G<:MultiplicationGroup} = copyto!(q, p) -LinearAlgebra.mul!(q, p, ::Identity{G}) where {G<:MultiplicationGroup} = copyto!(q, p) -function LinearAlgebra.mul!(q, e::E, ::E) where {G<:MultiplicationGroup,E<:Identity{G}} - return get_point!(q,e) -end +LinearAlgebra.mul!(q, ::Identity, p) = copyto!(q, p) +LinearAlgebra.mul!(q, p, ::Identity) = copyto!(q, p) +LinearAlgebra.mul!(q, e::Identity, ::Identity) = get_point!(G, q, e) Base.inv(::MultiplicationGroup, p) = inv(p) diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 2e48091d5e..35a59fb743 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -50,21 +50,21 @@ end submanifold(G::ProductGroup, i) = submanifold(base_manifold(G), i) function submanifold_component( - e::Identity{GT}, - ::Val{I}, -) where {I,MT<:ProductManifold,𝔽,GT<:GroupManifold{𝔽,MT}} - return Identity(submanifold(e.group, I), submanifold_component(e.p, I)) + ::GroupManifold{𝔽,MT}, + ::Identity, + ::Val{I} +) where {I,MT<:ProductManifold,𝔽} + # the identity on a product manifold with is a group consists of a tuple of identities + return Identity() end function submanifold_components( - e::Identity{GT}, -) where {MT<:ProductManifold,𝔽,GT<:GroupManifold{𝔽,MT}} - M = base_manifold(e.group) - return map(Identity, M.manifolds, submanifold_components(e.group, e.p)) + G::GroupManifold{𝔽,MT}, + e::Identity, +) where {MT<:ProductManifold,𝔽} + M = base_manifold(G) + return [ Identity() for _ in M.manifolds ] end - -Base.inv(G::ProductGroup, p) = inv(G.manifold, p) -Base.inv(::GT, e::Identity{GT}) where {GT<:ProductGroup} = e function Base.inv(M::ProductManifold, x::ProductRepr) return ProductRepr(map(inv, M.manifolds, submanifold_components(M, x))...) end @@ -80,9 +80,6 @@ function inv!(M::ProductManifold, q, p) end compose(G::ProductGroup, p, q) = compose(G.manifold, p, q) -compose(::GT, ::Identity{GT}, p) where {GT<:ProductGroup} = p -compose(::GT, p, ::Identity{GT}) where {GT<:ProductGroup} = p -compose(::GT, e::E, ::E) where {GT<:ProductGroup,E<:Identity{GT}} = e function compose(M::ProductManifold, p::ProductRepr, q::ProductRepr) return ProductRepr( map( diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index d3c8b6eeb1..451b5239bb 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -61,11 +61,9 @@ end submanifold(G::SemidirectProductGroup, i) = submanifold(base_manifold(G), i) -_padpoint!(G::SemidirectProductGroup, q) = q +_padpoint!(::SemidirectProductGroup, q) = q -_padvector!(G::SemidirectProductGroup, X) = X - -Base.inv(G::GT, e::Identity{GT}) where {GT<:SemidirectProductGroup} = e +_padvector!(::SemidirectProductGroup, X) = X function inv!(G::SemidirectProductGroup, q, p) M = base_manifold(G) @@ -79,11 +77,6 @@ function inv!(G::SemidirectProductGroup, q, p) @inbounds _padpoint!(G, q) return q end -inv!(G::AG, p, e::Identity{AG}) where {AG<:SemidirectProductGroup} = copyto!(p, get_point(G,e)) - -compose(::GT, p, e::Identity{GT}) where {GT<:SemidirectProductGroup} = p -compose(::GT, e::Identity{GT}, p) where {GT<:SemidirectProductGroup} = p -compose(::GT, e::E, ::E) where {GT<:SemidirectProductGroup,E<:Identity{GT}} = e function compose!(G::SemidirectProductGroup, x, p, q) M = base_manifold(G) @@ -98,11 +91,6 @@ function compose!(G::SemidirectProductGroup, x, p, q) @inbounds _padpoint!(G, x) return x end -compose!(::GT, x, ::Identity{GT}, q) where {GT<:SemidirectProductGroup} = copyto!(x, q) -compose!(::GT, x, p, ::Identity{GT}) where {GT<:SemidirectProductGroup} = copyto!(x, p) -function compose!(G::GT, x, e::E, ::E) where {GT<:SemidirectProductGroup,E<:Identity{GT}} - return copyto!(x, get_point(G,e)) -end @doc raw""" translate_diff(G::SemidirectProductGroup, p, q, X, conX::LeftAction) @@ -152,17 +140,6 @@ function get_vector!(G::SemidirectProductGroup, Y, p, X, B::VeeOrthogonalBasis) @inbounds _padvector!(G, Y) return Y end -eval( - quote - @invoke_maker 1 AbstractManifold get_vector!( - M::SemidirectProductGroup, - Xⁱ, - e::Identity, - X, - B::VeeOrthogonalBasis, - ) - end, -) function get_coordinates!(G::SemidirectProductGroup, Y, p, X, B::VeeOrthogonalBasis) M = base_manifold(G) @@ -176,17 +153,6 @@ function get_coordinates!(G::SemidirectProductGroup, Y, p, X, B::VeeOrthogonalBa get_coordinates!(H, view(Y, (dimN + 1):(dimN + dimH)), hp, hY, B) return Y end -eval( - quote - @invoke_maker 1 AbstractManifold get_coordinates!( - M::SemidirectProductGroup, - Y, - e::Identity, - X, - B::VeeOrthogonalBasis, - ) - end, -) function zero_vector(G::SemidirectProductGroup, p) X = allocate_result(G, zero_vector, p) @@ -218,28 +184,4 @@ function Base.isapprox(G::SemidirectProductGroup, p, X, Y; kwargs...) nX, hX = submanifold_components(G, X) nY, hY = submanifold_components(G, Y) return isapprox(N, np, nX, nY; kwargs...) && isapprox(H, hp, hX, hY; kwargs...) -end -function Base.isapprox( - G::GT, - p, - e::Identity{GT}; - kwargs..., -) where {GT<:SemidirectProductGroup} - return isapprox(G, e, p; kwargs...) -end -function Base.isapprox( - G::GT, - e::Identity{GT}, - p; - kwargs..., -) where {GT<:SemidirectProductGroup} - return isapprox(G, get_point(G, e), p; kwargs...) -end -function Base.isapprox( - ::GT, - ::E, - ::E; - kwargs..., -) where {GT<:SemidirectProductGroup,E<:Identity{GT}} - return true -end +end \ No newline at end of file diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index 9c67cfa791..a73889b850 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -135,7 +135,7 @@ function affine_matrix(G::SpecialEuclidean{n}, p) where {n} return pmat end affine_matrix(::SpecialEuclidean{n}, p::AbstractMatrix) where {n} = p -function affine_matrix(::GT, ::Identity{GT}) where {n,GT<:SpecialEuclidean{n}} +function affine_matrix(::GT, ::Identity) where {n,GT<:SpecialEuclidean{n}} s = maybesize(Size(n, n)) s isa Size && return SDiagonal{n,Float64}(I) return Diagonal{Float64}(I, n) diff --git a/src/groups/special_linear.jl b/src/groups/special_linear.jl index d2a2541f74..c36ee8d761 100644 --- a/src/groups/special_linear.jl +++ b/src/groups/special_linear.jl @@ -38,11 +38,6 @@ function check_point(G::SpecialLinear{n,𝔽}, p; kwargs...) where {n,𝔽} end return nothing end -check_point(::GT, ::Identity{GT}; kwargs...) where {GT<:SpecialLinear} = nothing -function check_point(G::SpecialLinear, e::Identity; kwargs...) - return DomainError(e, "The identity element $(e) does not belong to $(G).") -end - function check_vector(G::SpecialLinear, p, X; kwargs...) mpv = check_vector(decorated_manifold(G), p, X; kwargs...) mpv === nothing || return mpv diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index eb045ddf52..15726b1888 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -41,9 +41,9 @@ function inverse_translate_diff!(G::SpecialOrthogonal, Y, p, q, X, conv::ActionD return copyto!(Y, inverse_translate_diff(G, p, q, X, conv)) end -group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, make_identity(G, q).p, X) +group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, Identity(G).p, X) -group_log!(G::SpecialOrthogonal, X, q) = log!(G, X, make_identity(G, q).p, q) +group_log!(G::SpecialOrthogonal, X, q) = log!(G, X, Identity(G).p, q) function group_log!(G::SpecialOrthogonal, X::AbstractMatrix, q::AbstractMatrix) return log!(G, X, Identity(G), q) end @@ -51,7 +51,7 @@ end function allocate_result( ::GT, ::typeof(exp), - ::Identity{GT}, + ::Identity, X, ) where {n,GT<:SpecialOrthogonal{n}} return allocate(X) @@ -59,7 +59,7 @@ end function allocate_result( ::GT, ::typeof(log), - ::Identity{GT}, + ::Identity, q, ) where {n,GT<:SpecialOrthogonal{n}} return allocate(q) diff --git a/src/groups/translation_action.jl b/src/groups/translation_action.jl index e410f1a2d6..5c7ca4a236 100644 --- a/src/groups/translation_action.jl +++ b/src/groups/translation_action.jl @@ -36,20 +36,20 @@ function switch_direction(A::TranslationAction{TM,TRN,TAD}) where {TM,TRN,TAD} return TranslationAction(A.manifold, A.Rn, switch_direction(TAD())) end -apply(A::TranslationAction, a, p) = p + a +apply(::TranslationAction, a, p) = p + a -apply!(A::TranslationAction{M,G}, q, a, p) where {M,G} = (q .= p .+ a) -apply!(A::TranslationAction{M,G}, q, e::Identity{G}, p) where {M,G} = copyto!(q, p) +apply!(::TranslationAction, q, a, p) = (q .= p .+ a) +apply!(::TranslationAction, q, e::Identity, p) = copyto!(q, p) -inverse_apply(A::TranslationAction, a, p) = p - a +inverse_apply(::TranslationAction, a, p) = p - a -inverse_apply!(A::TranslationAction{M,G}, q, a, p) where {M,G} = (q .= p .- a) -inverse_apply!(A::TranslationAction{M,G}, q, e::Identity{G}, p) where {M,G} = copyto!(q, p) +inverse_apply!(::TranslationAction, q, a, p) = (q .= p .- a) +inverse_apply!(::TranslationAction, q, e::Identity, p) = copyto!(q, p) -apply_diff(A::TranslationAction, a, p, X) = X +apply_diff(::TranslationAction, a, p, X) = X -apply_diff!(A::TranslationAction, Y, a, p, X) = copyto!(Y, X) +apply_diff!(::TranslationAction, Y, a, p, X) = copyto!(Y, X) -inverse_apply_diff(A::TranslationAction, a, p, X) = X +inverse_apply_diff(::TranslationAction, a, p, X) = X -inverse_apply_diff!(A::TranslationAction, Y, a, p, X) = copyto!(Y, X) +inverse_apply_diff!(::TranslationAction, Y, a, p, X) = copyto!(Y, X) From 4e67bf3faeef702ce81c97a85abdd72e2d2d84a7 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 23 Jul 2021 13:50:40 +0200 Subject: [PATCH 04/88] runs formatter. --- src/groups/group.jl | 8 ++++---- src/groups/product_group.jl | 4 ++-- src/groups/semidirect_product_group.jl | 2 +- test/groups/general_linear.jl | 12 ++---------- test/groups/special_linear.jl | 12 ++---------- test/groups/special_orthogonal.jl | 8 ++------ 6 files changed, 13 insertions(+), 33 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index fd068e1ba4..106bd06ca1 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -260,7 +260,7 @@ end inv!(G::AbstractGroupManifold, q, e::Identity) = get_point!(G, q, e) function Base.isapprox(G::AbstractGroupManifold, e::Identity, p; kwargs...) - return isapprox(G, get_point(G,e), p; kwargs...) + return isapprox(G, get_point(G, e), p; kwargs...) end function Base.isapprox(G::AbstractGroupManifold, p, e::Identity; kwargs...) return isapprox(G, e, p; kwargs...) @@ -282,9 +282,9 @@ end @decorator_transparent_signature compose!(M::AbstractDecoratorManifold, x, p, q) -compose!(::AbstractGroupManifold, q, p, ::Identity) = copyto!(q,p) -compose!(::AbstractGroupManifold, q, ::Identity, p) = copyto!(q,p) -compose!(G::AbstractGroupManifold, q, ::Identity, e::Identity) = copyto(q, get_point(G,e)) +compose!(::AbstractGroupManifold, q, p, ::Identity) = copyto!(q, p) +compose!(::AbstractGroupManifold, q, ::Identity, p) = copyto!(q, p) +compose!(G::AbstractGroupManifold, q, ::Identity, e::Identity) = copyto(q, get_point(G, e)) compose!(::AbstractGroupManifold, e::Identity, ::Identity, ::Identity) = e """ diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 35a59fb743..6de5adf137 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -52,7 +52,7 @@ submanifold(G::ProductGroup, i) = submanifold(base_manifold(G), i) function submanifold_component( ::GroupManifold{𝔽,MT}, ::Identity, - ::Val{I} + ::Val{I}, ) where {I,MT<:ProductManifold,𝔽} # the identity on a product manifold with is a group consists of a tuple of identities return Identity() @@ -63,7 +63,7 @@ function submanifold_components( e::Identity, ) where {MT<:ProductManifold,𝔽} M = base_manifold(G) - return [ Identity() for _ in M.manifolds ] + return [Identity() for _ in M.manifolds] end function Base.inv(M::ProductManifold, x::ProductRepr) return ProductRepr(map(inv, M.manifolds, submanifold_components(M, x))...) diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index 451b5239bb..38853757c9 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -184,4 +184,4 @@ function Base.isapprox(G::SemidirectProductGroup, p, X, Y; kwargs...) nX, hX = submanifold_components(G, X) nY, hY = submanifold_components(G, Y) return isapprox(N, np, nX, nY; kwargs...) && isapprox(H, hp, hX, hY; kwargs...) -end \ No newline at end of file +end diff --git a/test/groups/general_linear.jl b/test/groups/general_linear.jl index c7360c44c1..ab8d73c508 100644 --- a/test/groups/general_linear.jl +++ b/test/groups/general_linear.jl @@ -78,11 +78,7 @@ using NLsolve @test_throws DomainError is_point(G, randn(ComplexF64, 3, 3), true) @test_throws DomainError is_point(G, zeros(3, 3), true) @test_throws DomainError is_point(G, Float64[0 0 0; 0 1 1; 1 1 1], true) - @test_throws DomainError is_point( - G, - Identity(GeneralLinear(2)), - true, - ) + @test_throws DomainError is_point(G, Identity(GeneralLinear(2)), true) @test is_point(G, Float64[0 0 1; 0 1 1; 1 1 1], true) @test is_point(G, Identity(G), true) @test_throws DomainError is_vector( @@ -161,11 +157,7 @@ using NLsolve @test is_point(G, ComplexF64[1 1; im 1], true) @test is_point(G, Identity(G), true) @test_throws DomainError is_point(G, Float64[0 0 0; 0 1 1; 1 1 1], true) - @test_throws DomainError is_point( - G, - Identity(GeneralLinear(3)), - true, - ) + @test_throws DomainError is_point(G, Identity(GeneralLinear(3)), true) @test_throws DomainError is_vector( G, ComplexF64[im im; im im], diff --git a/test/groups/special_linear.jl b/test/groups/special_linear.jl index 82be3c42fe..23b540c696 100644 --- a/test/groups/special_linear.jl +++ b/test/groups/special_linear.jl @@ -53,11 +53,7 @@ using NLsolve @test_throws DomainError is_point(G, [1 0 im; im 0 0; 0 -1 0], true) @test_throws DomainError is_point(G, zeros(3, 3), true) @test_throws DomainError is_point(G, Float64[1 3 3; 1 1 2; 1 2 3], true) - @test_throws DomainError is_point( - G, - Identity(SpecialLinear(2)), - true, - ) + @test_throws DomainError is_point(G, Identity(SpecialLinear(2)), true) @test is_point(G, Float64[1 1 1; 2 2 1; 2 3 3], true) @test is_point(G, Identity(G), true) @test_throws DomainError is_vector( @@ -155,11 +151,7 @@ using NLsolve @test_throws DomainError is_point(G, randn(2, 2), true) @test_throws DomainError is_point(G, ComplexF64[1 0 im; im 0 0; 0 -1 0], true) @test_throws DomainError is_point(G, ComplexF64[1 im; im 1], true) - @test_throws DomainError is_point( - G, - Identity(SpecialLinear(2)), - true, - ) + @test_throws DomainError is_point(G, Identity(SpecialLinear(2)), true) @test is_point(G, ComplexF64[im 1; -2 im], true) @test is_point(G, Identity(G), true) @test_throws DomainError is_vector( diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index f79d851873..f7a7df1666 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -63,11 +63,7 @@ include("group_utils.jl") @test (@inferred Manifolds.decorator_group_dispatch(DM)) === Val(true) @test Manifolds.is_group_decorator(DM) @test base_group(DM) === G - @test_throws DomainError is_point( - DM, - Identity(TranslationGroup(3)), - true, - ) + @test_throws DomainError is_point(DM, Identity(TranslationGroup(3)), true) test_group(DM, pts, vpts, vpts; test_diff=true) end @@ -138,7 +134,7 @@ include("group_utils.jl") X = vpts[1] pe = Identity(G) - Xⁱ = vee(G, get_point(G,pe), X) + Xⁱ = vee(G, get_point(G, pe), X) @test Xⁱ ≈ vee(G, pe, X) X2 = hat(G, pts[1], Xⁱ) From e4ccf431748e2c2249fa010af4cadbbd9442161d Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 23 Jul 2021 21:59:25 +0200 Subject: [PATCH 05/88] Further fixes, excluding parameters in identity construction. --- src/groups/array_manifold.jl | 18 ++++++++-------- src/groups/connections.jl | 2 +- src/groups/group.jl | 8 ++++---- src/groups/metric.jl | 4 ++-- src/groups/special_euclidean.jl | 4 ++-- src/groups/special_orthogonal.jl | 6 +++--- src/tests/tests_group.jl | 28 ++++++++++++------------- test/groups/array_manifold.jl | 12 +++++------ test/groups/circle_group.jl | 2 +- test/groups/connections.jl | 8 ++++---- test/groups/general_linear.jl | 6 ++---- test/groups/groups_general.jl | 34 ++++++------------------------- test/groups/metric.jl | 12 +++++------ test/groups/product_group.jl | 12 +++++------ test/groups/special_euclidean.jl | 14 ++++++------- test/groups/special_linear.jl | 6 ++---- test/groups/special_orthogonal.jl | 11 +++++----- 17 files changed, 80 insertions(+), 107 deletions(-) diff --git a/src/groups/array_manifold.jl b/src/groups/array_manifold.jl index 952eeb7a86..5fa3368008 100644 --- a/src/groups/array_manifold.jl +++ b/src/groups/array_manifold.jl @@ -1,11 +1,11 @@ -array_value(e::Identity) = Identity(e.group, array_value(e.p)) +array_value(e::Identity) = e array_point(p) = ValidationMPoint(p) array_point(p::ValidationMPoint) = p function adjoint_action(M::ValidationManifold, p, X; kwargs...) is_point(M, p, true; kwargs...) - eM = Identity(M.manifold) + eM = Identity() is_vector(M, eM, X, true; kwargs...) Y = ValidationTVector(adjoint_action(M.manifold, array_value(p), array_value(X))) is_vector(M, eM, Y, true; kwargs...) @@ -14,7 +14,7 @@ end function adjoint_action!(M::ValidationManifold, Y, p, X; kwargs...) is_point(M, p, true; kwargs...) - eM = Identity(M.manifold) + eM = Identity() is_vector(M, eM, X, true; kwargs...) adjoint_action!(M.manifold, array_value(Y), array_value(p), array_value(X)) is_vector(M, eM, Y, true; kwargs...) @@ -36,7 +36,7 @@ function inv!(M::ValidationManifold, q, p; kwargs...) end function lie_bracket(M::ValidationManifold, X, Y) - eM = get_point(Identity(M.manifold)) + eM = get_point(Identity()) is_vector(M, eM, X, true) is_vector(M, eM, Y, true) Z = ValidationTVector(lie_bracket(M.manifold, array_value(X), array_value(Y))) @@ -45,7 +45,7 @@ function lie_bracket(M::ValidationManifold, X, Y) end function lie_bracket!(M::ValidationManifold, Z, X, Y) - eM = get_point(Identity(M.manifold)) + eM = get_point(Identity()) is_vector(M, eM, X, true) is_vector(M, eM, Y, true) lie_bracket!(M.manifold, array_value(Z), array_value(X), array_value(Y)) @@ -198,7 +198,7 @@ end function group_exp(M::ValidationManifold, X; kwargs...) is_vector( M, - get_point(Identity(M.manifold)), + get_point(Identity()), array_value(X), true; check_base_point=false, @@ -212,7 +212,7 @@ end function group_exp!(M::ValidationManifold, q, X; kwargs...) is_vector( M, - get_point(Identity(M.manifold)), + get_point(Identity()), array_value(X), true; check_base_point=false, @@ -228,7 +228,7 @@ function group_log(M::ValidationManifold, q; kwargs...) X = ValidationTVector(group_log(M.manifold, array_value(q))) is_vector( M, - get_point(Identity(M.manifold)), + get_point(Identity()), array_value(X), true; check_base_point=false, @@ -242,7 +242,7 @@ function group_log!(M::ValidationManifold, X, q; kwargs...) group_log!(M.manifold, array_value(X), array_value(q)) is_vector( M, - get_point(Identity(M.manifold)), + get_point(Identity()), array_value(X), true; check_base_point=false, diff --git a/src/groups/connections.jl b/src/groups/connections.jl index 8fcee83d33..f22e436ab2 100644 --- a/src/groups/connections.jl +++ b/src/groups/connections.jl @@ -88,7 +88,7 @@ function log!( ) where {𝔽} pinvq = compose(M.manifold, inv(M.manifold, p), q) group_log!(M.manifold, Y, pinvq) - return translate_diff!(M.manifold, Y, p, Identity(M.manifold, p), Y) + return translate_diff!(M.manifold, Y, p, Identity(), Y) end """ diff --git a/src/groups/group.jl b/src/groups/group.jl index 106bd06ca1..0902bb1564 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -227,13 +227,13 @@ adjoint_action(G::AbstractGroupManifold, p, X) p, Xₑ, ) - Xₚ = translate_diff(G, p, Identity(G), Xₑ, LeftAction()) + Xₚ = translate_diff(G, p, Identity(), Xₑ, LeftAction()) Y = inverse_translate_diff(G, p, p, Xₚ, RightAction()) return Y end function adjoint_action!(G::AbstractGroupManifold, Y, p, Xₑ) - Xₚ = translate_diff(G, p, Identity(G), Xₑ, LeftAction()) + Xₚ = translate_diff(G, p, Identity(), Xₑ, LeftAction()) inverse_translate_diff!(G, Y, p, p, Xₚ, RightAction()) return Y end @@ -677,7 +677,7 @@ function inverse_retract(G::GroupManifold, p, q, method::GroupLogarithmicInverse conv = direction(method) pinvq = inverse_translate(G, p, q, conv) Xₑ = group_log(G, pinvq) - return translate_diff(G, p, Identity(G, p), Xₑ, conv) + return translate_diff(G, p, Identity(), Xₑ, conv) end function inverse_retract!( @@ -690,7 +690,7 @@ function inverse_retract!( conv = direction(method) pinvq = inverse_translate(G, p, q, conv) Xₑ = group_log(G, pinvq) - return translate_diff!(G, X, p, Identity(G, p), Xₑ, conv) + return translate_diff!(G, X, p, Identity(), Xₑ, conv) end ################################# diff --git a/src/groups/metric.jl b/src/groups/metric.jl index e26079f7b4..2d3ccbbfdc 100644 --- a/src/groups/metric.jl +++ b/src/groups/metric.jl @@ -191,7 +191,7 @@ function inner(M::MetricManifold{𝔽,<:AbstractManifold,<:InvariantMetric}, p, N = MetricManifold(M.manifold, imetric.metric) Xₑ = inverse_translate_diff(M, p, p, X, conv) Yₑ = inverse_translate_diff(M, p, p, Y, conv) - return inner(N, Identity(N, p), Xₑ, Yₑ) + return inner(N, Identity(), Xₑ, Yₑ) end function default_metric_dispatch( @@ -232,7 +232,7 @@ function LinearAlgebra.norm( conv = direction(imetric) N = MetricManifold(M.manifold, imetric.metric) Xₑ = inverse_translate_diff(M, p, p, X, conv) - return norm(N, Identity(N, p), Xₑ) + return norm(N, Identity(), Xₑ) end function Base.show(io::IO, metric::LeftInvariantMetric) diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index a73889b850..0a940ca7cd 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -258,7 +258,7 @@ function group_exp!(G::SpecialEuclidean{2}, q, X) @assert size(t) == (2,) @assert size(b) == (2,) - θ = vee(SO2, Identity(SO2, Ω), Ω)[1] + θ = vee(SO2, Identity(), Ω)[1] sinθ, cosθ = sincos(θ) if θ ≈ 0 α = 1 - θ^2 / 6 @@ -286,7 +286,7 @@ function group_exp!(G::SpecialEuclidean{3}, q, X) @assert size(R) == (3, 3) @assert size(t) == (3,) - θ = norm(SO3, Identity(SO3, Ω), Ω) / sqrt(2) + θ = norm(SO3, Identity(), Ω) / sqrt(2) θ² = θ^2 if θ ≈ 0 α = 1 - θ² / 6 diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index 15726b1888..e644186668 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -41,11 +41,11 @@ function inverse_translate_diff!(G::SpecialOrthogonal, Y, p, q, X, conv::ActionD return copyto!(Y, inverse_translate_diff(G, p, q, X, conv)) end -group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, Identity(G).p, X) +group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, Identity().p, X) -group_log!(G::SpecialOrthogonal, X, q) = log!(G, X, Identity(G).p, q) +group_log!(G::SpecialOrthogonal, X, q) = log!(G, X, Identity().p, q) function group_log!(G::SpecialOrthogonal, X::AbstractMatrix, q::AbstractMatrix) - return log!(G, X, Identity(G), q) + return log!(G, X, Identity(), q) end function allocate_result( diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index 5646bafb8e..fdbcfce7b3 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -38,7 +38,7 @@ function test_group( test_adjoint_action=false, diff_convs=[(), (LeftAction(),), (RightAction(),)], ) - e = Identity(G) + e = Identity() Test.@testset "Basic group properties" begin Test.@testset "Closed" begin @@ -72,7 +72,7 @@ function test_group( Test.@test isapprox(G, compose(G, g, e), g) Test.@test isapprox(G, compose(G, e, g), g) - ge = Identity(G) + ge = Identity() Test.@test isapprox(G, compose(G, g, ge), g) Test.@test isapprox(G, compose(G, ge, g), g) end @@ -287,16 +287,16 @@ function test_group( test_group_exp_log && Test.@testset "group exp/log properties" begin Test.@testset "e = exp(0)" begin - X = group_log(G, Identity(G)) + X = group_log(G, Identity()) g = group_exp(G, X) - Test.@test isapprox(G, Identity(G), g; atol=atol) + Test.@test isapprox(G, Identity(), g; atol=atol) test_mutating && Test.@testset "mutating" begin X = allocate(Xe_pts[1]) - Test.@test group_log!(G, X, Identity(G)) === X + Test.@test group_log!(G, X, Identity()) === X g = allocate(g_pts[1]) Test.@test group_exp!(G, g, X) === g - Test.@test isapprox(G, Identity(G), g; atol=atol) + Test.@test isapprox(G, Identity(), g; atol=atol) end end @@ -305,7 +305,7 @@ function test_group( g = group_exp(G, X) Test.@test is_point(G, g; atol=atol) X2 = group_log(G, g) - Test.@test isapprox(G, Identity(G), X2, X; atol=atol) + Test.@test isapprox(G, Identity(), X2, X; atol=atol) end test_mutating && Test.@testset "mutating" begin @@ -316,7 +316,7 @@ function test_group( Test.@test isapprox(G, g, group_exp(G, X); atol=atol) X2 = allocate(X) Test.@test group_log!(G, X2, g) === X2 - Test.@test isapprox(G, Identity(G), X2, X; atol=atol) + Test.@test isapprox(G, Identity(), X2, X; atol=atol) end end end @@ -414,7 +414,7 @@ function test_group( # linearity X = Xe_pts[1] Y = Xe_pts[2] - e = Identity(G) + e = Identity() Test.@test isapprox( G, e, @@ -453,7 +453,7 @@ function test_group( # anticommutativity X = X_pts[1] Y = X_pts[2] - e = Identity(G) + e = Identity() Test.@test isapprox(G, e, lie_bracket(G, X, Y), -lie_bracket(G, Y, X)) if test_mutating @@ -502,7 +502,7 @@ function test_action( ) G = base_group(A) M = g_manifold(A) - e = Identity(G) + e = Identity() Test.@testset "Basic action properties" begin test_switch_direction && Test.@testset "Direction" begin @@ -575,7 +575,7 @@ function test_action( Test.@test isapprox(G, compose(A, a, e), a; atol=atol_ident_compose) Test.@test isapprox(G, compose(A, e, a), a; atol=atol_ident_compose) - ge = Identity(G) + ge = Identity() Test.@test isapprox(G, compose(A, a, ge), a; atol=atol_ident_compose) Test.@test isapprox(G, compose(A, ge, a), a; atol=atol_ident_compose) @@ -596,11 +596,11 @@ function test_action( Test.@test compose!(A, h, e, a) === h Test.@test isapprox(G, h, a) - ge = Identity(G) + ge = Identity() Test.@test isapprox(G, compose(A, a, ge), a) Test.@test isapprox(G, compose(A, ge, a), a) - ge = Identity(G) + ge = Identity() Test.@test compose!(A, ge, e, e) === ge Test.@test isapprox(G, ge, e) diff --git a/test/groups/array_manifold.jl b/test/groups/array_manifold.jl index 524239bea3..9a943e96d9 100644 --- a/test/groups/array_manifold.jl +++ b/test/groups/array_manifold.jl @@ -13,24 +13,24 @@ include("../utils.jl") p, q = [exp(M, eg, hat(M, eg, ωi)) for ωi in ω] X = hat(M, eg, [-1.0, 2.0, 0.5]) - e = Identity(AG) - @test Manifolds.array_value(e).p == Manifolds.array_value(e.p) + e = Identity() + @test Manifolds.array_value(e) == get_point(AG, e) @test Manifolds.array_point(e).p == e.p p2, q2 = ValidationMPoint(p), ValidationMPoint(q) @test q2 === Manifolds.array_point(q2) # test that double wraps are avoided. X2 = ValidationTVector(X) - @test Identity(AG, e) isa Identity + @test Identity() isa Identity eg = allocate(p2) - get_point!(G, eg, Identity(AG)) - @test isapprox(G, eg, Identity(G)) + get_point!(G, eg, Identity()) + @test isapprox(G, eg, Identity()) eg = allocate(p2) @test inv(AG, p2) isa ValidationMPoint @test isapprox(G, inv(AG, p2).value, inv(G, p)) @test inv(AG, e) isa Identity - @test_throws DomainError inv(AG, Identity(TranslationGroup(3), ω[1])) + @test_throws DomainError inv(AG, Identity()) pinvq = allocate(p2) inv!(AG, pinvq, p2) diff --git a/test/groups/circle_group.jl b/test/groups/circle_group.jl index 1c91cf7b8b..6459f2e8c1 100644 --- a/test/groups/circle_group.jl +++ b/test/groups/circle_group.jl @@ -20,7 +20,7 @@ using Manifolds: invariant_metric_dispatch, default_metric_dispatch @test is_default_metric(MetricManifold(G, EuclideanMetric())) @testset "identity overloads" begin - ig = Identity(G) + ig = Identity() @test inv(G, ig) === ig @test allocate_result(G, get_coordinates, ig, Complex(1.0), DefaultBasis()) isa Array{Complex{Float64},1} diff --git a/test/groups/connections.jl b/test/groups/connections.jl index 0a32c3ecb3..55e4f9897f 100644 --- a/test/groups/connections.jl +++ b/test/groups/connections.jl @@ -10,10 +10,10 @@ using Manifolds: connection SO3zero = ConnectionManifold(SO3, CartanSchoutenZero()) e = Matrix{Float64}(I, 3, 3) - p = exp(hat(SO3, Identity(SO3, e), [1.0, 2.0, 3.0])) - q = exp(hat(SO3, Identity(SO3, e), [3.0, 4.0, 1.0])) - X = hat(SO3, Identity(SO3, e), [2.0, 3.0, 4.0]) - SO3e = Identity(SO3, e) + p = exp(hat(SO3, Identity(), [1.0, 2.0, 3.0])) + q = exp(hat(SO3, Identity(), [3.0, 4.0, 1.0])) + X = hat(SO3, Identity(), [2.0, 3.0, 4.0]) + SO3e = Identity() @testset "connection" begin @test connection(SO3minus) === CartanSchoutenMinus() diff --git a/test/groups/general_linear.jl b/test/groups/general_linear.jl index ab8d73c508..bbf417b53d 100644 --- a/test/groups/general_linear.jl +++ b/test/groups/general_linear.jl @@ -78,9 +78,8 @@ using NLsolve @test_throws DomainError is_point(G, randn(ComplexF64, 3, 3), true) @test_throws DomainError is_point(G, zeros(3, 3), true) @test_throws DomainError is_point(G, Float64[0 0 0; 0 1 1; 1 1 1], true) - @test_throws DomainError is_point(G, Identity(GeneralLinear(2)), true) @test is_point(G, Float64[0 0 1; 0 1 1; 1 1 1], true) - @test is_point(G, Identity(G), true) + @test is_point(G, Identity(), true) @test_throws DomainError is_vector( G, Float64[0 1 1; 0 1 1; 1 0 0], @@ -155,9 +154,8 @@ using NLsolve @test_throws DomainError is_point(G, zeros(2, 2), true) @test_throws DomainError is_point(G, ComplexF64[1 im; 1 im], true) @test is_point(G, ComplexF64[1 1; im 1], true) - @test is_point(G, Identity(G), true) + @test is_point(G, Identity(), true) @test_throws DomainError is_point(G, Float64[0 0 0; 0 1 1; 1 1 1], true) - @test_throws DomainError is_point(G, Identity(GeneralLinear(3)), true) @test_throws DomainError is_vector( G, ComplexF64[im im; im im], diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 0b3f4e729e..6a8718376b 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -14,13 +14,13 @@ include("group_utils.jl") "GroupManifold(NotImplementedManifold(), NotImplementedOperation())" x = [1.0, 2.0] v = [2.0, 3.0] - eg = Identity(G, [0.0, 0.0]) - @test repr(eg) === "Identity($(G), $([0.0, 0.0]))" + eg = Identity() + @test repr(eg) === "Identity()" @test number_eltype(eg) == Bool @test is_point(G, eg) # identity transparent p = similar(x) copyto!(p, eg) - @test p == eg.p + @test p == get_point(G, eg) @test isapprox(G, eg, p) @test isapprox(G, p, eg) @test isapprox(G, eg, eg) @@ -56,24 +56,6 @@ include("group_utils.jl") @test NotImplementedOperation(NotImplementedManifold()) === G @test (NotImplementedOperation())(NotImplementedManifold()) === G - @test_throws ErrorException allocate_result( - G, - get_vector, - Identity(SpecialOrthogonal(3), x), - v, - ) - @test_throws ErrorException allocate_result( - G, - get_coordinates, - Identity(SpecialOrthogonal(3), x), - v, - ) - @test_throws ErrorException allocate_result( - ValidationManifold(NotImplementedManifold()), - get_coordinates, - Identity(SpecialOrthogonal(3), x), - v, - ) @test_throws ErrorException base_group( MetricManifold(Euclidean(3), EuclideanMetric()), ) @@ -89,7 +71,6 @@ include("group_utils.jl") eg, [1, 2, 3], ) - @test_throws ErrorException Identity(Euclidean(3), [0, 0, 0]) @test_throws ErrorException inv!(G, x, x) @test_throws ErrorException inv!(G, x, eg) @@ -182,8 +163,7 @@ include("group_utils.jl") x = [1.0, 2.0] v = [3.0, 4.0] - ge = Identity(G, [0.0, 0.0]) - @test zero(ge) === ge + ge = Identity() @test number_eltype(ge) == Bool @test copyto!(ge, ge) === ge y = allocate(x) @@ -195,10 +175,8 @@ include("group_utils.jl") @test ge + x ≈ x @test x + ge ≈ x @test ge + ge === ge - @test ge + Identity(G, 1) === ge @test -(ge) === ge @test +(ge) === ge - @test ge - Identity(G, 1) === ge @test ge * 1 === ge @test 1 * ge === ge @test ge * ge === ge @@ -231,7 +209,7 @@ include("group_utils.jl") ) x = [2.0 1.0; 2.0 3.0] - ge = Identity(G, [1.0 0.0; 0.0 1.0]) + ge = Identity() @test number_eltype(ge) == Bool @test copyto!(ge, ge) === ge y = allocate(x) @@ -298,7 +276,7 @@ include("group_utils.jl") @testset "Identity on Group Manifolds" begin G = TranslationGroup(3) - e = Identity(G, zeros(3)) + e = Identity() @test get_vector(G, e, ones(3), DefaultOrthogonalBasis()) == ones(3) @test e - e == e @test ones(3) + e == ones(3) diff --git a/test/groups/metric.jl b/test/groups/metric.jl index 0741c34724..c581ad7db4 100644 --- a/test/groups/metric.jl +++ b/test/groups/metric.jl @@ -100,14 +100,14 @@ invariant_metric_dispatch(::TestDefaultInvariantMetricManifold, ::RightAction) = e = Matrix{Float64}(I, 3, 3) @testset "inner/norm" begin SO3 = SpecialOrthogonal(3) - p = exp(hat(SO3, Identity(SO3, e), [1.0, 2.0, 3.0])) + p = exp(hat(SO3, Identity(), [1.0, 2.0, 3.0])) B = DefaultOrthonormalBasis() fX = ManifoldsBase.TFVector([2.0, 3.0, 4.0], B) fY = ManifoldsBase.TFVector([3.0, 4.0, 1.0], B) - X = hat(SO3, Identity(SO3, e), fX.data) - Y = hat(SO3, Identity(SO3, e), fY.data) + X = hat(SO3, Identity(), fX.data) + Y = hat(SO3, Identity(), fY.data) G = MetricManifold(SO3, lmetric) @test inner(G, p, fX, fY) ≈ dot(fX.data, Diagonal([1.0, 2.0, 3.0]) * fY.data) @@ -121,9 +121,9 @@ invariant_metric_dispatch(::TestDefaultInvariantMetricManifold, ::RightAction) = @testset "log/exp bi-invariant" begin SO3 = SpecialOrthogonal(3) - p = exp(hat(SO3, Identity(SO3, e), [1.0, 2.0, 3.0])) - q = exp(hat(SO3, Identity(SO3, e), [3.0, 4.0, 1.0])) - X = hat(SO3, Identity(SO3, e), [2.0, 3.0, 4.0]) + p = exp(hat(SO3, Identity(), [1.0, 2.0, 3.0])) + q = exp(hat(SO3, Identity(), [3.0, 4.0, 1.0])) + X = hat(SO3, Identity(), [2.0, 3.0, 4.0]) G = MetricManifold(SO3, InvariantMetric(TestBiInvariantMetricBase(), LeftAction())) @test isapprox(SO3, exp(G, p, X), exp(SO3, p, X)) diff --git a/test/groups/product_group.jl b/test/groups/product_group.jl index a7f7e0eda6..fa0441cab4 100644 --- a/test/groups/product_group.jl +++ b/test/groups/product_group.jl @@ -32,12 +32,12 @@ include("group_utils.jl") shape_se = Manifolds.ShapeSpecification(reshaper, M.manifolds...) pts = [Manifolds.prod_point(shape_se, tp...) for tp in tuple_pts] v_pts = [Manifolds.prod_point(shape_se, tuple_v...)] - @test compose(G, pts[1], Identity(G, e)) == pts[1] - @test compose(G, Identity(G, e), pts[1]) == pts[1] + @test compose(G, pts[1], Identity()) == pts[1] + @test compose(G, Identity(), pts[1]) == pts[1] test_group(G, pts, v_pts, v_pts; test_diff=true) @test isapprox( M, - Identity(M), + Identity(), group_exp(M, v_pts[1]), Manifolds.prod_point( shape_se, @@ -47,7 +47,7 @@ include("group_utils.jl") ) @test isapprox( M, - Identity(M), + Identity(), group_log(M, pts[1]), Manifolds.prod_point( shape_se, @@ -61,8 +61,8 @@ include("group_utils.jl") @testset "product repr" begin pts = [ProductRepr(tp...) for tp in tuple_pts] v_pts = [ProductRepr(tuple_v...)] - @test compose(G, pts[1], Identity(G, e)) == pts[1] - @test compose(G, Identity(G, e), pts[1]) == pts[1] + @test compose(G, pts[1], Identity()) == pts[1] + @test compose(G, Identity(), pts[1]) == pts[1] test_group(G, pts, v_pts, v_pts; test_diff=true, test_mutating=false) @test isapprox( M, diff --git a/test/groups/special_euclidean.jl b/test/groups/special_euclidean.jl index 4fcb602e86..c3a1488f7c 100644 --- a/test/groups/special_euclidean.jl +++ b/test/groups/special_euclidean.jl @@ -62,7 +62,7 @@ using ManifoldsBase: VeeOrthogonalBasis Manifolds._padvector!(G, tmp) @test tmp == X_pts[1] - w = translate_diff(G, pts[1], Identity(G), X_pts[1]) + w = translate_diff(G, pts[1], Identity(), X_pts[1]) w2 = allocate(w) w2.parts[1] .= w.parts[1] w2.parts[2] .= pts[1].parts[2] * w.parts[2] @@ -92,10 +92,10 @@ using ManifoldsBase: VeeOrthogonalBasis g1g2mat = affine_matrix(G, g1g2) @test g1g2mat ≈ affine_matrix(G, g1) * affine_matrix(G, g2) @test affine_matrix(G, g1g2mat) === g1g2mat - @test affine_matrix(G, Identity(G)) isa SDiagonal{n,Float64} - @test affine_matrix(G, Identity(G)) == SDiagonal{n,Float64}(I) + @test affine_matrix(G, Identity()) isa SDiagonal{n,Float64} + @test affine_matrix(G, Identity()) == SDiagonal{n,Float64}(I) - w = translate_diff(G, pts[1], Identity(G), X_pts[1]) + w = translate_diff(G, pts[1], Identity(), X_pts[1]) w2 = allocate(w) w2.parts[1] .= w.parts[1] w2.parts[2] .= pts[1].parts[2] * w.parts[2] @@ -146,8 +146,8 @@ using ManifoldsBase: VeeOrthogonalBasis end G = SpecialEuclidean(11) - @test affine_matrix(G, Identity(G)) isa Diagonal{Float64,Vector{Float64}} - @test affine_matrix(G, Identity(G)) == Diagonal(ones(11)) + @test affine_matrix(G, Identity()) isa Diagonal{Float64,Vector{Float64}} + @test affine_matrix(G, Identity()) == Diagonal(ones(11)) @testset "Explicit embedding in GL(n+1)" begin G = SpecialEuclidean(3) @@ -197,7 +197,7 @@ using ManifoldsBase: VeeOrthogonalBasis G, pts_gl[1], X_gl, - translate_diff(G, Identity(G, pts_gl[1]), pts_gl[1], X_gl, conv), + translate_diff(G, Identity(), pts_gl[1], X_gl, conv), ) end end diff --git a/test/groups/special_linear.jl b/test/groups/special_linear.jl index 23b540c696..5c58eb9e23 100644 --- a/test/groups/special_linear.jl +++ b/test/groups/special_linear.jl @@ -53,9 +53,8 @@ using NLsolve @test_throws DomainError is_point(G, [1 0 im; im 0 0; 0 -1 0], true) @test_throws DomainError is_point(G, zeros(3, 3), true) @test_throws DomainError is_point(G, Float64[1 3 3; 1 1 2; 1 2 3], true) - @test_throws DomainError is_point(G, Identity(SpecialLinear(2)), true) @test is_point(G, Float64[1 1 1; 2 2 1; 2 3 3], true) - @test is_point(G, Identity(G), true) + @test is_point(G, Identity(), true) @test_throws DomainError is_vector( G, Float64[2 3 2; 3 1 2; 1 1 1], @@ -151,9 +150,8 @@ using NLsolve @test_throws DomainError is_point(G, randn(2, 2), true) @test_throws DomainError is_point(G, ComplexF64[1 0 im; im 0 0; 0 -1 0], true) @test_throws DomainError is_point(G, ComplexF64[1 im; im 1], true) - @test_throws DomainError is_point(G, Identity(SpecialLinear(2)), true) @test is_point(G, ComplexF64[im 1; -2 im], true) - @test is_point(G, Identity(G), true) + @test is_point(G, Identity(), true) @test_throws DomainError is_vector( G, ComplexF64[-1+im -1; -im 1], diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index f7a7df1666..2abb94ef5a 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -28,10 +28,10 @@ include("group_utils.jl") vpts = [hat(M, x, [-1.0, 2.0, 0.5]), hat(M, x, [1.0, 0.0, 0.5])] ge = allocate(pts[1]) - copyto!(ge, get_point(G, Identity(G))) + copyto!(ge, get_point(G, Identity())) @test isapprox(ge, I; atol=1e-10) - gI = Identity(G, ge) + gI = Identity() gT = allocate_result(G, exp, gI, log(G, pts[1], pts[2])) @test size(gT) == size(ge) @test eltype(gT) == eltype(ge) @@ -63,7 +63,6 @@ include("group_utils.jl") @test (@inferred Manifolds.decorator_group_dispatch(DM)) === Val(true) @test Manifolds.is_group_decorator(DM) @test base_group(DM) === G - @test_throws DomainError is_point(DM, Identity(TranslationGroup(3)), true) test_group(DM, pts, vpts, vpts; test_diff=true) end @@ -132,7 +131,7 @@ include("group_utils.jl") @testset "vee/hat" begin X = vpts[1] - pe = Identity(G) + pe = Identity() Xⁱ = vee(G, get_point(G, pe), X) @test Xⁱ ≈ vee(G, pe, X) @@ -141,7 +140,7 @@ include("group_utils.jl") @test isapprox(M, pe, X2, hat(G, pe, Xⁱ); atol=1e-6) end @testset "Identity and get_vector/get_coordinates" begin - e = Identity(G, Matrix{Float64}(I, 3, 3)) + e = Identity() gT = allocate_result(G, get_coordinates, e, pts[1]) @test size(gT) == (manifold_dimension(M),) @test eltype(gT) == eltype(e.p) @@ -153,7 +152,7 @@ include("group_utils.jl") copyto!(eT, e) @test eT == e.p - eF = Identity(SpecialEuclidean(3), 1) + eF = Identity() c = [1.0, 0.0, 0.0] Y = zeros(representation_size(G)) get_vector!(G, Y, e, c, Manifolds.VeeOrthogonalBasis()) From 860adfcf113df9e87c613e6573d0bd43070c034b Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 24 Jul 2021 00:35:51 +0200 Subject: [PATCH 06/88] further work on allocation. --- src/Manifolds.jl | 16 ++++++++--- src/groups/group.jl | 35 ++++++++++++++----------- src/groups/semidirect_product_group.jl | 13 +++++++++ src/groups/special_linear.jl | 7 +++++ src/groups/translation_group.jl | 2 ++ src/tests/tests_group.jl | 7 +++-- test/groups/metric.jl | 6 +++-- test/groups/semidirect_product_group.jl | 3 +++ 8 files changed, 64 insertions(+), 25 deletions(-) diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 83f237ea85..be5b2c3586 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -138,6 +138,18 @@ using StatsBase: AbstractWeights include("utils.jl") +@doc raw""" + Identity + +Represent the group identity element $e ∈ \mathcal{G}$ on an [`AbstractGroupManifold`](@ref) `G`. + +Similar to the philosophy that points are agnostic of their group at hand, the identity +does not store the group ` g` it belongs to. + +see also [`get_point`](@ref) on how to obtain the corresponding [`AbstractManifoldPoint`](@ref) or array representation. +""" +struct Identity end + include("product_representations.jl") include("differentiation.jl") include("riemannian_diff.jl") @@ -147,9 +159,6 @@ include("manifolds/ConnectionManifold.jl") include("manifolds/MetricManifold.jl") include("manifolds/VectorBundle.jl") -# It's included early to ensure visibility of `Identity` -include("groups/group.jl") - # Features I: Which are extended on Meta Manifolds include("distributions.jl") include("projected_distribution.jl") @@ -173,6 +182,7 @@ METAMANIFOLDS = [ # Features II: That require metas include("atlases.jl") include("cotangent_space.jl") +include("groups/group.jl") # Meta Manifolds II: Power Manifolds include("manifolds/PowerManifold.jl") diff --git a/src/groups/group.jl b/src/groups/group.jl index 0902bb1564..c130a1d0ad 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -167,17 +167,17 @@ switch_direction(::RightAction) = LeftAction() # General Identity element methods ################################## -@doc raw""" - Identity - -Represent the group identity element $e ∈ \mathcal{G}$ on an [`AbstractGroupManifold`](@ref) `G`. +function allocate_result_type(::AbstractGroupManifold{𝔽}, f, args::NTuple{N,<:Identity}) where {𝔽,N} + return (𝔽 == ℂ) ? ComplexF64 : Float64 +end -Similar to the philosophy that points are agnostic of their group at hand, the identity -does not store the group ` g` it belongs to. +# To ensure allocate_result_type works in general if idenitty apears in the tuple +number_eltype(::Identity) = Bool -see also [`get_point`](@ref) on how to obtain the corresponding [`AbstractManifoldPoint`](@ref) or array representation. -""" -struct Identity end +function allocate_result(M::AbstractGroupManifold, f::typeof(get_point), e::Identity) + T = allocate_result_type(M, f, (e,)) + return allocate(Array{T}, T, representation_size(M)...) +end @doc raw""" get_point(G::AbstractGroupManifold,e::Identity) @@ -186,15 +186,12 @@ struct Identity end return a point representation of the [`Identity`](@ref) `e` on the [`AbstractGroupManifold`](@ref) `G` (in place of `p`) """ function get_point(G::AbstractGroupManifold, e::Identity) - q = allocate_result(G, e) + q = allocate_result(G, get_point, e) return get_point!(G, q, e) end Base.show(io::IO, ::Identity) = print(io, "Identity()") -# To ensure allocate_result_type works -number_eltype(::Identity) = Bool - Base.copyto!(e::Identity, ::Identity) = e check_point(G::AbstractGroupManifold, e::Identity; kwargs...) = nothing @@ -721,14 +718,19 @@ adjoint_action(::AdditionGroup, p, X) = X adjoint_action!(::AdditionGroup, Y, p, X) = copyto!(Y, X) Base.inv(::AdditionGroup, p) = -p +Base.inv(::AdditionGroup, e::Identity) = e inv!(::AdditionGroup, q, p) = copyto!(q, -p) +inv!(G::AdditionGroup, q, e::Identity) = get_point!(G, q, e) +inv!(::AdditionGroup, q::Identity, e::Identity) = q compose(::AdditionGroup, p, q) = p + q -function compose!(::GT, x, p, q) where {GT<:AdditionGroup} - p isa Identity{GT} && return copyto!(x, q) - q isa Identity{GT} && return copyto!(x, p) +compose!(::AdditionGroup, x, p, ::Identity) = copyto!(x, p) +compose!(::AdditionGroup, x, ::Identity, q) = copyto!(x, q) +compose!(G::AdditionGroup, x, ::Identity, q::Identity) = copyto!(x, get_point(G, q)) +compose!(::AdditionGroup, x::Identity, ::Identity, ::Identity) = x +function compose!(::AdditionGroup, x, p, q) x .= p .+ q return x end @@ -750,6 +752,7 @@ group_exp!(::AdditionGroup, q, X) = copyto!(q, X) group_log(::AdditionGroup, q) = q group_log!(::AdditionGroup, X, q) = copyto!(X, q) +group_log!(::AdditionGroup, X, e::Identity) = X lie_bracket(::AdditionGroup, X, Y) = zero(X) diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index 38853757c9..488d66445e 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -52,6 +52,16 @@ function SemidirectProductGroup( return GroupManifold(M, op) end +function get_point!(G::SemidirectProductGroup, q, e::Identity) + M = base_manifold(G) + N, H = M.manifolds + nq, hq = submanifold_components(G, q) + get_point!(N,nq,e) + get_point!(H,hq,e) + @inbounds _padpoint!(G, q) + return q +end + function Base.show(io::IO, G::SemidirectProductGroup) M = base_manifold(G) N, H = M.manifolds @@ -78,6 +88,9 @@ function inv!(G::SemidirectProductGroup, q, p) return q end +compose!(::SemidirectProductGroup, q, ::Identity, p) = copyto!(q, p) +compose!(G::SemidirectProductGroup, q, ::Identity, e::Identity) = copyto(q, get_point(G, e)) +compose!(::SemidirectProductGroup, e::Identity, ::Identity, ::Identity) = e function compose!(G::SemidirectProductGroup, x, p, q) M = base_manifold(G) N, H = M.manifolds diff --git a/src/groups/special_linear.jl b/src/groups/special_linear.jl index c36ee8d761..cc3ad4e64c 100644 --- a/src/groups/special_linear.jl +++ b/src/groups/special_linear.jl @@ -25,6 +25,13 @@ function allocation_promotion_function(::SpecialLinear{n,ℂ}, f, args::Tuple) w return complex end +function get_point!(::SpecialLinear{n,𝔽}, p, ::Identity) where {n,𝔽} + T = (𝔽 == ℂ) ? ComplexF64 : Float64 + copyto(p, Matrix{T}(I,n,n)) + return p +end + + function check_point(G::SpecialLinear{n,𝔽}, p; kwargs...) where {n,𝔽} mpv = check_point(Euclidean(n, n; field=𝔽), p; kwargs...) mpv === nothing || return mpv diff --git a/src/groups/translation_group.jl b/src/groups/translation_group.jl index 6bf7f03e0d..39a23906b5 100644 --- a/src/groups/translation_group.jl +++ b/src/groups/translation_group.jl @@ -18,6 +18,8 @@ function TranslationGroup(n::Int...; field::AbstractNumbers=ℝ) ) end +get_point!(::TranslationGroup, p, ::Identity) = fill!(p, 0) + invariant_metric_dispatch(::TranslationGroup, ::ActionDirection) = Val(true) function default_metric_dispatch( diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index fdbcfce7b3..77e1491794 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -86,11 +86,10 @@ function test_group( Test.@test compose!(G, h, e, g) === h Test.@test isapprox(G, h, g) - ge = allocate(g) - Test.@test isapprox(G, compose(G, g, ge), g) - Test.@test isapprox(G, compose(G, ge, g), g) + ge = Identity() + Test.@test isapprox(G, compose(G, g, e), g) + Test.@test isapprox(G, compose(G, e, g), g) - ge = allocate(g) Test.@test compose!(G, ge, e, e) === ge Test.@test isapprox(G, ge, e) end diff --git a/test/groups/metric.jl b/test/groups/metric.jl index c581ad7db4..f3063103a2 100644 --- a/test/groups/metric.jl +++ b/test/groups/metric.jl @@ -121,8 +121,10 @@ invariant_metric_dispatch(::TestDefaultInvariantMetricManifold, ::RightAction) = @testset "log/exp bi-invariant" begin SO3 = SpecialOrthogonal(3) - p = exp(hat(SO3, Identity(), [1.0, 2.0, 3.0])) - q = exp(hat(SO3, Identity(), [3.0, 4.0, 1.0])) + e = Identity() + pe = get_point(SO3, e) + p = exp(hat(SO3, pe, [1.0, 2.0, 3.0])) + q = exp(hat(SO3, pe, [3.0, 4.0, 1.0])) X = hat(SO3, Identity(), [2.0, 3.0, 4.0]) G = MetricManifold(SO3, InvariantMetric(TestBiInvariantMetricBase(), LeftAction())) diff --git a/test/groups/semidirect_product_group.jl b/test/groups/semidirect_product_group.jl index 1fb2784042..34a4952410 100644 --- a/test/groups/semidirect_product_group.jl +++ b/test/groups/semidirect_product_group.jl @@ -31,6 +31,9 @@ include("group_utils.jl") @test norm(G, pts[1], Y) ≈ 0 @test norm(G, pts[1], Z) ≈ 0 + e = Identity() + @test inv(G, e) === e + @test compose(G, e, pts[1]) == pts[1] @test compose(G, pts[1], e) == pts[1] @test compose(G, e, e) === e From 7b838bb6d51e81f19efb3e7be102c0201c830d57 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 25 Jul 2021 12:53:34 +0200 Subject: [PATCH 07/88] Introduce identity, identity! and is_identity --- src/Manifolds.jl | 16 ++---- src/groups/group.jl | 72 ++++++++++++++++++++++---- src/groups/semidirect_product_group.jl | 4 +- src/groups/special_linear.jl | 3 +- 4 files changed, 67 insertions(+), 28 deletions(-) diff --git a/src/Manifolds.jl b/src/Manifolds.jl index be5b2c3586..bc9a395b17 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -138,18 +138,6 @@ using StatsBase: AbstractWeights include("utils.jl") -@doc raw""" - Identity - -Represent the group identity element $e ∈ \mathcal{G}$ on an [`AbstractGroupManifold`](@ref) `G`. - -Similar to the philosophy that points are agnostic of their group at hand, the identity -does not store the group ` g` it belongs to. - -see also [`get_point`](@ref) on how to obtain the corresponding [`AbstractManifoldPoint`](@ref) or array representation. -""" -struct Identity end - include("product_representations.jl") include("differentiation.jl") include("riemannian_diff.jl") @@ -158,6 +146,7 @@ include("riemannian_diff.jl") include("manifolds/ConnectionManifold.jl") include("manifolds/MetricManifold.jl") include("manifolds/VectorBundle.jl") +include("groups/group.jl") # Features I: Which are extended on Meta Manifolds include("distributions.jl") @@ -182,7 +171,6 @@ METAMANIFOLDS = [ # Features II: That require metas include("atlases.jl") include("cotangent_space.jl") -include("groups/group.jl") # Meta Manifolds II: Power Manifolds include("manifolds/PowerManifold.jl") @@ -595,6 +583,8 @@ export adjoint_action, group_log!, has_biinvariant_metric, has_invariant_metric, + identity, + identity!, inv, inv!, invariant_metric_dispatch, diff --git a/src/groups/group.jl b/src/groups/group.jl index c130a1d0ad..e5e492d387 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -167,29 +167,79 @@ switch_direction(::RightAction) = LeftAction() # General Identity element methods ################################## -function allocate_result_type(::AbstractGroupManifold{𝔽}, f, args::NTuple{N,<:Identity}) where {𝔽,N} - return (𝔽 == ℂ) ? ComplexF64 : Float64 +@doc raw""" + Identity + +Represent the group identity element $e ∈ \mathcal{G}$ on an [`AbstractGroupManifold`](@ref) `G`. + +Similar to the philosophy that points are agnostic of their group at hand, the identity +does not store the group ` g` it belongs to. + +see also [`get_point`](@ref) on how to obtain the corresponding [`AbstractManifoldPoint`](@ref) or array representation. +""" +struct Identity{O<:AbstractGroupOperation} end + +function Identity(::AbstractGroupManifold{𝔽,M,O}) where {𝔽,M,O<:AbstractGroupOperation} + return Identity{O}() end +Identity(::O) where {O<:AbstractGroupOperation} = Identity{O}() # To ensure allocate_result_type works in general if idenitty apears in the tuple number_eltype(::Identity) = Bool -function allocate_result(M::AbstractGroupManifold, f::typeof(get_point), e::Identity) - T = allocate_result_type(M, f, (e,)) - return allocate(Array{T}, T, representation_size(M)...) +@doc raw""" + identity(G::AbstractGroupManifold) + +return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G`. +by default this representation is default array representation. +It should return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if points are not represented by arrays. +""" +function identity(G::AbstractGroupManifold) + q = zeros(representation_size(G)...) + return identity!(G, q) end @doc raw""" - get_point(G::AbstractGroupManifold,e::Identity) - get_point!(G::AbstractGroupManifold, p, e::Identity) + is_identity(G,q; kwargs) -return a point representation of the [`Identity`](@ref) `e` on the [`AbstractGroupManifold`](@ref) `G` (in place of `p`) +Check, whether `q` is the identity on the [`AbstractGroupManifold`](@ref) `G`, i.e. it is either +the [`Identity`](@ref)`{O}` with the corresponding [`AbstractGroupOperation`](@ref) `O`, or +(approximately) the correct point representation. """ -function get_point(G::AbstractGroupManifold, e::Identity) - q = allocate_result(G, get_point, e) - return get_point!(G, q, e) +is_identity(G::AbstractGroupManifold, q) + +function is_identity(G::AbstractGroupManifold, q; kwargs...) + return isapprox(G, q, identity(G, q); kwargs...) end +function is_identity( + ::AbstractGroupManifold{𝔽,M,O}, + ::Identity{O}; + kwargs..., +) where {𝔽,M,O<:AbstractGroupOperation} + return true +end +is_identity(::AbstractGroupManifold, ::Identity; kwargs...) = false + +@doc raw""" + identity(G::AbstractGroupManifold, p) + +return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G` (in place of `p`). +by default this representation is default array representation. +It rhoudl return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if points are not represented by arrays. +""" +function identity(G::AbstractGroupManifold, p) + q = allocate_result(G, identity, p) + return identity!(G, q) +end + +@doc raw""" + identity!(G::AbstractGroupManifold, p) + +return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G` in place of `p`. +""" +identity!(G::AbstractGroupManifold, p) + Base.show(io::IO, ::Identity) = print(io, "Identity()") Base.copyto!(e::Identity, ::Identity) = e diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index 488d66445e..89b4259877 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -56,8 +56,8 @@ function get_point!(G::SemidirectProductGroup, q, e::Identity) M = base_manifold(G) N, H = M.manifolds nq, hq = submanifold_components(G, q) - get_point!(N,nq,e) - get_point!(H,hq,e) + get_point!(N, nq, e) + get_point!(H, hq, e) @inbounds _padpoint!(G, q) return q end diff --git a/src/groups/special_linear.jl b/src/groups/special_linear.jl index cc3ad4e64c..45f02fc861 100644 --- a/src/groups/special_linear.jl +++ b/src/groups/special_linear.jl @@ -27,11 +27,10 @@ end function get_point!(::SpecialLinear{n,𝔽}, p, ::Identity) where {n,𝔽} T = (𝔽 == ℂ) ? ComplexF64 : Float64 - copyto(p, Matrix{T}(I,n,n)) + copyto(p, Matrix{T}(I, n, n)) return p end - function check_point(G::SpecialLinear{n,𝔽}, p; kwargs...) where {n,𝔽} mpv = check_point(Euclidean(n, n; field=𝔽), p; kwargs...) mpv === nothing || return mpv From cc5d94984e78816d980214c8b81c9fc72a2aee81 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 25 Jul 2021 13:33:54 +0200 Subject: [PATCH 08/88] refactor identity to be parametrised by AbstractGroupOperation --- src/Manifolds.jl | 2 +- src/groups/connections.jl | 2 +- src/groups/group.jl | 40 +++++++++++++------ src/groups/metric.jl | 4 +- src/groups/product_group.jl | 12 +++--- src/groups/special_euclidean.jl | 4 +- src/groups/special_orthogonal.jl | 6 +-- ...{array_manifold.jl => validation_group.jl} | 37 +++++++++-------- src/tests/tests_group.jl | 30 +++++++------- test/groups/circle_group.jl | 2 +- test/groups/general_linear.jl | 4 +- test/groups/groups_general.jl | 8 ++-- test/groups/metric.jl | 10 ++--- test/groups/product_group.jl | 8 ++-- test/groups/semidirect_product_group.jl | 2 +- test/groups/special_euclidean.jl | 14 +++---- test/groups/special_linear.jl | 4 +- test/groups/special_orthogonal.jl | 2 +- ...{array_manifold.jl => validation_group.jl} | 8 ++-- 19 files changed, 110 insertions(+), 89 deletions(-) rename src/groups/{array_manifold.jl => validation_group.jl} (87%) rename test/groups/{array_manifold.jl => validation_group.jl} (96%) diff --git a/src/Manifolds.jl b/src/Manifolds.jl index bc9a395b17..7abe922704 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -226,7 +226,7 @@ include("groups/connections.jl") include("groups/metric.jl") include("groups/group_action.jl") include("groups/group_operation_action.jl") -include("groups/array_manifold.jl") +include("groups/validation_group.jl") include("groups/product_group.jl") include("groups/semidirect_product_group.jl") diff --git a/src/groups/connections.jl b/src/groups/connections.jl index f22e436ab2..729fc30c87 100644 --- a/src/groups/connections.jl +++ b/src/groups/connections.jl @@ -88,7 +88,7 @@ function log!( ) where {𝔽} pinvq = compose(M.manifold, inv(M.manifold, p), q) group_log!(M.manifold, Y, pinvq) - return translate_diff!(M.manifold, Y, p, Identity(), Y) + return translate_diff!(M.manifold, Y, p, Identity(M.manifold), Y) end """ diff --git a/src/groups/group.jl b/src/groups/group.jl index e5e492d387..036f011cae 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -168,21 +168,30 @@ switch_direction(::RightAction) = LeftAction() ################################## @doc raw""" - Identity + Identity{O<:AbstractGroupOperation} Represent the group identity element $e ∈ \mathcal{G}$ on an [`AbstractGroupManifold`](@ref) `G`. Similar to the philosophy that points are agnostic of their group at hand, the identity -does not store the group ` g` it belongs to. +does not store the group `g` it belongs to. HOwever it depends on the type of the [`AbstractGroupOperation`](@ref) used. -see also [`get_point`](@ref) on how to obtain the corresponding [`AbstractManifoldPoint`](@ref) or array representation. +see also [`identity`](@ref) on how to obtain the corresponding [`AbstractManifoldPoint`](@ref) or array representation. + +# Constructors + +Identity(G::AbstractGroupManifold{𝔽,O}) +Identity(o::O) +Identity(::Type{O}) + +create the identity of the corresponding subtype `O<:`[`AbstractGroupOperation`](@ref) """ struct Identity{O<:AbstractGroupOperation} end -function Identity(::AbstractGroupManifold{𝔽,M,O}) where {𝔽,M,O<:AbstractGroupOperation} +function Identity(::AbstractGroupManifold{𝔽,O}) where {𝔽,O<:AbstractGroupOperation} return Identity{O}() end -Identity(::O) where {O<:AbstractGroupOperation} = Identity{O}() +Identity(::O) where {O<:AbstractGroupOperation} = Identity(O) +Identity(::Type{O}) where {O<:AbstractGroupOperation} = Identity{O}() # To ensure allocate_result_type works in general if idenitty apears in the tuple number_eltype(::Identity) = Bool @@ -240,11 +249,18 @@ return a point representation of the [`Identity`](@ref) on the [`AbstractGroupMa """ identity!(G::AbstractGroupManifold, p) -Base.show(io::IO, ::Identity) = print(io, "Identity()") +Base.show(io::IO, ::Identity{O}) where {O}= print(io, "Identity($O)") -Base.copyto!(e::Identity, ::Identity) = e +Base.copyto!(e::Identity{O}, ::Identity{O}) where {O} = e -check_point(G::AbstractGroupManifold, e::Identity; kwargs...) = nothing +check_point(G::AbstractGroupManifold{𝔽,M,O}, e::Identity{O}; kwargs...) where {𝔽,M,O} = nothing + +function check_point(G::AbstractGroupManifold{𝔽,M,O1}, e::Identity{O2}; kwargs...) where {𝔽,M,O1,O2} + return DomainError( + e, + "The Identity $e does not lie on $M, since its the identity with respect to $O2 and not $O1.", + ) +end ########################## # Group-specific functions @@ -274,13 +290,13 @@ adjoint_action(G::AbstractGroupManifold, p, X) p, Xₑ, ) - Xₚ = translate_diff(G, p, Identity(), Xₑ, LeftAction()) + Xₚ = translate_diff(G, p, Identity(G), Xₑ, LeftAction()) Y = inverse_translate_diff(G, p, p, Xₚ, RightAction()) return Y end function adjoint_action!(G::AbstractGroupManifold, Y, p, Xₑ) - Xₚ = translate_diff(G, p, Identity(), Xₑ, LeftAction()) + Xₚ = translate_diff(G, p, Identity(G), Xₑ, LeftAction()) inverse_translate_diff!(G, Y, p, p, Xₚ, RightAction()) return Y end @@ -724,7 +740,7 @@ function inverse_retract(G::GroupManifold, p, q, method::GroupLogarithmicInverse conv = direction(method) pinvq = inverse_translate(G, p, q, conv) Xₑ = group_log(G, pinvq) - return translate_diff(G, p, Identity(), Xₑ, conv) + return translate_diff(G, p, Identity(G), Xₑ, conv) end function inverse_retract!( @@ -737,7 +753,7 @@ function inverse_retract!( conv = direction(method) pinvq = inverse_translate(G, p, q, conv) Xₑ = group_log(G, pinvq) - return translate_diff!(G, X, p, Identity(), Xₑ, conv) + return translate_diff!(G, X, p, Identity(G), Xₑ, conv) end ################################# diff --git a/src/groups/metric.jl b/src/groups/metric.jl index 2d3ccbbfdc..987b16ead1 100644 --- a/src/groups/metric.jl +++ b/src/groups/metric.jl @@ -191,7 +191,7 @@ function inner(M::MetricManifold{𝔽,<:AbstractManifold,<:InvariantMetric}, p, N = MetricManifold(M.manifold, imetric.metric) Xₑ = inverse_translate_diff(M, p, p, X, conv) Yₑ = inverse_translate_diff(M, p, p, Y, conv) - return inner(N, Identity(), Xₑ, Yₑ) + return inner(N, Identity(G), Xₑ, Yₑ) end function default_metric_dispatch( @@ -232,7 +232,7 @@ function LinearAlgebra.norm( conv = direction(imetric) N = MetricManifold(M.manifold, imetric.metric) Xₑ = inverse_translate_diff(M, p, p, X, conv) - return norm(N, Identity(), Xₑ) + return norm(N, Identity(G), Xₑ) end function Base.show(io::IO, metric::LeftInvariantMetric) diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 6de5adf137..6df518c3cc 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -50,20 +50,20 @@ end submanifold(G::ProductGroup, i) = submanifold(base_manifold(G), i) function submanifold_component( - ::GroupManifold{𝔽,MT}, + ::GroupManifold{𝔽,MT,O}, ::Identity, ::Val{I}, -) where {I,MT<:ProductManifold,𝔽} +) where {I,MT<:ProductManifold,𝔽,O} # the identity on a product manifold with is a group consists of a tuple of identities - return Identity() + return Identity{O}() end function submanifold_components( - G::GroupManifold{𝔽,MT}, + G::GroupManifold{𝔽,MT,O}, e::Identity, -) where {MT<:ProductManifold,𝔽} +) where {MT<:ProductManifold,𝔽,O<:AbstractGroupOperation} M = base_manifold(G) - return [Identity() for _ in M.manifolds] + return [Identity(O) for N in M.manifolds] end function Base.inv(M::ProductManifold, x::ProductRepr) return ProductRepr(map(inv, M.manifolds, submanifold_components(M, x))...) diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index 0a940ca7cd..a2c690993e 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -258,7 +258,7 @@ function group_exp!(G::SpecialEuclidean{2}, q, X) @assert size(t) == (2,) @assert size(b) == (2,) - θ = vee(SO2, Identity(), Ω)[1] + θ = vee(SO2, Identity(SO2), Ω)[1] sinθ, cosθ = sincos(θ) if θ ≈ 0 α = 1 - θ^2 / 6 @@ -286,7 +286,7 @@ function group_exp!(G::SpecialEuclidean{3}, q, X) @assert size(R) == (3, 3) @assert size(t) == (3,) - θ = norm(SO3, Identity(), Ω) / sqrt(2) + θ = norm(SO3, Identity(SO3), Ω) / sqrt(2) θ² = θ^2 if θ ≈ 0 α = 1 - θ² / 6 diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index e644186668..99691c35c0 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -41,11 +41,11 @@ function inverse_translate_diff!(G::SpecialOrthogonal, Y, p, q, X, conv::ActionD return copyto!(Y, inverse_translate_diff(G, p, q, X, conv)) end -group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, Identity().p, X) +group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, Identity(G).p, X) -group_log!(G::SpecialOrthogonal, X, q) = log!(G, X, Identity().p, q) +group_log!(G::SpecialOrthogonal, X, q) = log!(G, X, Identity(G), q) function group_log!(G::SpecialOrthogonal, X::AbstractMatrix, q::AbstractMatrix) - return log!(G, X, Identity(), q) + return log!(G, X, Identity(G), q) end function allocate_result( diff --git a/src/groups/array_manifold.jl b/src/groups/validation_group.jl similarity index 87% rename from src/groups/array_manifold.jl rename to src/groups/validation_group.jl index 5fa3368008..54aee81ad4 100644 --- a/src/groups/array_manifold.jl +++ b/src/groups/validation_group.jl @@ -1,42 +1,47 @@ +# +# Interaction of GrooupManifold with a ValidationaManifold +# array_value(e::Identity) = e array_point(p) = ValidationMPoint(p) array_point(p::ValidationMPoint) = p -function adjoint_action(M::ValidationManifold, p, X; kwargs...) +const ValidationGroup{𝔽} = ValidationManifold{𝔽,G} where {G<:AbstractGroupManifold} + +function adjoint_action(M::ValidationGroup, p, X; kwargs...) is_point(M, p, true; kwargs...) - eM = Identity() + eM = Identity(M.manifold) is_vector(M, eM, X, true; kwargs...) Y = ValidationTVector(adjoint_action(M.manifold, array_value(p), array_value(X))) is_vector(M, eM, Y, true; kwargs...) return Y end -function adjoint_action!(M::ValidationManifold, Y, p, X; kwargs...) +function adjoint_action!(M::ValidationGroup, Y, p, X; kwargs...) is_point(M, p, true; kwargs...) - eM = Identity() + eM = Identity(M.manifold) is_vector(M, eM, X, true; kwargs...) adjoint_action!(M.manifold, array_value(Y), array_value(p), array_value(X)) is_vector(M, eM, Y, true; kwargs...) return Y end -function Base.inv(M::ValidationManifold, p; kwargs...) +function Base.inv(M::ValidationGroup, p; kwargs...) is_point(M, p, true; kwargs...) q = array_point(inv(M.manifold, array_value(p))) is_point(M, q, true; kwargs...) return q end -function inv!(M::ValidationManifold, q, p; kwargs...) +function inv!(M::ValidationGroup, q, p; kwargs...) is_point(M, p, true; kwargs...) inv!(M.manifold, array_value(q), array_value(p)) is_point(M, q, true; kwargs...) return q end -function lie_bracket(M::ValidationManifold, X, Y) - eM = get_point(Identity()) +function lie_bracket(M::ValidationGroup, X, Y) + eM = Identity(M.manifold) is_vector(M, eM, X, true) is_vector(M, eM, Y, true) Z = ValidationTVector(lie_bracket(M.manifold, array_value(X), array_value(Y))) @@ -44,8 +49,8 @@ function lie_bracket(M::ValidationManifold, X, Y) return Z end -function lie_bracket!(M::ValidationManifold, Z, X, Y) - eM = get_point(Identity()) +function lie_bracket!(M::ValidationGroup, Z, X, Y) + eM = Identity(M.manifold) is_vector(M, eM, X, true) is_vector(M, eM, Y, true) lie_bracket!(M.manifold, array_value(Z), array_value(X), array_value(Y)) @@ -53,7 +58,7 @@ function lie_bracket!(M::ValidationManifold, Z, X, Y) return Z end -function compose(M::ValidationManifold, p, q; kwargs...) +function compose(M::ValidationGroup, p, q; kwargs...) is_point(M, p, true; kwargs...) is_point(M, q, true; kwargs...) x = array_point(compose(M.manifold, array_value(p), array_value(q))) @@ -61,7 +66,7 @@ function compose(M::ValidationManifold, p, q; kwargs...) return x end -function compose!(M::ValidationManifold, x, p, q; kwargs...) +function compose!(M::ValidationGroup, x, p, q; kwargs...) is_point(M, p, true; kwargs...) is_point(M, q, true; kwargs...) compose!(M.manifold, array_value(x), array_value(p), array_value(q)) @@ -198,7 +203,7 @@ end function group_exp(M::ValidationManifold, X; kwargs...) is_vector( M, - get_point(Identity()), + Identity(M.manifold), array_value(X), true; check_base_point=false, @@ -212,7 +217,7 @@ end function group_exp!(M::ValidationManifold, q, X; kwargs...) is_vector( M, - get_point(Identity()), + Identity(M.manifold), array_value(X), true; check_base_point=false, @@ -228,7 +233,7 @@ function group_log(M::ValidationManifold, q; kwargs...) X = ValidationTVector(group_log(M.manifold, array_value(q))) is_vector( M, - get_point(Identity()), + Identity(M.manifold), array_value(X), true; check_base_point=false, @@ -242,7 +247,7 @@ function group_log!(M::ValidationManifold, X, q; kwargs...) group_log!(M.manifold, array_value(X), array_value(q)) is_vector( M, - get_point(Identity()), + Identity(M.manifold), array_value(X), true; check_base_point=false, diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index 77e1491794..c347745e60 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -38,7 +38,7 @@ function test_group( test_adjoint_action=false, diff_convs=[(), (LeftAction(),), (RightAction(),)], ) - e = Identity() + e = Identity(G) Test.@testset "Basic group properties" begin Test.@testset "Closed" begin @@ -72,7 +72,7 @@ function test_group( Test.@test isapprox(G, compose(G, g, e), g) Test.@test isapprox(G, compose(G, e, g), g) - ge = Identity() + ge = Identity(G) Test.@test isapprox(G, compose(G, g, ge), g) Test.@test isapprox(G, compose(G, ge, g), g) end @@ -86,7 +86,7 @@ function test_group( Test.@test compose!(G, h, e, g) === h Test.@test isapprox(G, h, g) - ge = Identity() + ge = Identity(G) Test.@test isapprox(G, compose(G, g, e), g) Test.@test isapprox(G, compose(G, e, g), g) @@ -286,16 +286,16 @@ function test_group( test_group_exp_log && Test.@testset "group exp/log properties" begin Test.@testset "e = exp(0)" begin - X = group_log(G, Identity()) + X = group_log(G, Identity(G)) g = group_exp(G, X) - Test.@test isapprox(G, Identity(), g; atol=atol) + Test.@test isapprox(G, Identity(G), g; atol=atol) test_mutating && Test.@testset "mutating" begin X = allocate(Xe_pts[1]) - Test.@test group_log!(G, X, Identity()) === X + Test.@test group_log!(G, X, Identity(G)) === X g = allocate(g_pts[1]) Test.@test group_exp!(G, g, X) === g - Test.@test isapprox(G, Identity(), g; atol=atol) + Test.@test isapprox(G, Identity(G), g; atol=atol) end end @@ -304,7 +304,7 @@ function test_group( g = group_exp(G, X) Test.@test is_point(G, g; atol=atol) X2 = group_log(G, g) - Test.@test isapprox(G, Identity(), X2, X; atol=atol) + Test.@test isapprox(G, Identity(G), X2, X; atol=atol) end test_mutating && Test.@testset "mutating" begin @@ -315,7 +315,7 @@ function test_group( Test.@test isapprox(G, g, group_exp(G, X); atol=atol) X2 = allocate(X) Test.@test group_log!(G, X2, g) === X2 - Test.@test isapprox(G, Identity(), X2, X; atol=atol) + Test.@test isapprox(G, Identity(G), X2, X; atol=atol) end end end @@ -413,7 +413,7 @@ function test_group( # linearity X = Xe_pts[1] Y = Xe_pts[2] - e = Identity() + e = Identity(G) Test.@test isapprox( G, e, @@ -452,7 +452,7 @@ function test_group( # anticommutativity X = X_pts[1] Y = X_pts[2] - e = Identity() + e = Identity(G) Test.@test isapprox(G, e, lie_bracket(G, X, Y), -lie_bracket(G, Y, X)) if test_mutating @@ -501,7 +501,7 @@ function test_action( ) G = base_group(A) M = g_manifold(A) - e = Identity() + e = Identity(G) Test.@testset "Basic action properties" begin test_switch_direction && Test.@testset "Direction" begin @@ -574,7 +574,7 @@ function test_action( Test.@test isapprox(G, compose(A, a, e), a; atol=atol_ident_compose) Test.@test isapprox(G, compose(A, e, a), a; atol=atol_ident_compose) - ge = Identity() + ge = Identity(G) Test.@test isapprox(G, compose(A, a, ge), a; atol=atol_ident_compose) Test.@test isapprox(G, compose(A, ge, a), a; atol=atol_ident_compose) @@ -595,11 +595,11 @@ function test_action( Test.@test compose!(A, h, e, a) === h Test.@test isapprox(G, h, a) - ge = Identity() + ge = Identity(G) Test.@test isapprox(G, compose(A, a, ge), a) Test.@test isapprox(G, compose(A, ge, a), a) - ge = Identity() + ge = Identity(G) Test.@test compose!(A, ge, e, e) === ge Test.@test isapprox(G, ge, e) diff --git a/test/groups/circle_group.jl b/test/groups/circle_group.jl index 6459f2e8c1..1c91cf7b8b 100644 --- a/test/groups/circle_group.jl +++ b/test/groups/circle_group.jl @@ -20,7 +20,7 @@ using Manifolds: invariant_metric_dispatch, default_metric_dispatch @test is_default_metric(MetricManifold(G, EuclideanMetric())) @testset "identity overloads" begin - ig = Identity() + ig = Identity(G) @test inv(G, ig) === ig @test allocate_result(G, get_coordinates, ig, Complex(1.0), DefaultBasis()) isa Array{Complex{Float64},1} diff --git a/test/groups/general_linear.jl b/test/groups/general_linear.jl index bbf417b53d..f43e01e741 100644 --- a/test/groups/general_linear.jl +++ b/test/groups/general_linear.jl @@ -79,7 +79,7 @@ using NLsolve @test_throws DomainError is_point(G, zeros(3, 3), true) @test_throws DomainError is_point(G, Float64[0 0 0; 0 1 1; 1 1 1], true) @test is_point(G, Float64[0 0 1; 0 1 1; 1 1 1], true) - @test is_point(G, Identity(), true) + @test is_point(G, Identity(G), true) @test_throws DomainError is_vector( G, Float64[0 1 1; 0 1 1; 1 0 0], @@ -154,7 +154,7 @@ using NLsolve @test_throws DomainError is_point(G, zeros(2, 2), true) @test_throws DomainError is_point(G, ComplexF64[1 im; 1 im], true) @test is_point(G, ComplexF64[1 1; im 1], true) - @test is_point(G, Identity(), true) + @test is_point(G, Identity(G), true) @test_throws DomainError is_point(G, Float64[0 0 0; 0 1 1; 1 1 1], true) @test_throws DomainError is_vector( G, diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 6a8718376b..9fd20b9aad 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -14,8 +14,8 @@ include("group_utils.jl") "GroupManifold(NotImplementedManifold(), NotImplementedOperation())" x = [1.0, 2.0] v = [2.0, 3.0] - eg = Identity() - @test repr(eg) === "Identity()" + eg = Identity(G) + @test repr(eg) === "Identity(NotImplementedOperation)" @test number_eltype(eg) == Bool @test is_point(G, eg) # identity transparent p = similar(x) @@ -163,7 +163,7 @@ include("group_utils.jl") x = [1.0, 2.0] v = [3.0, 4.0] - ge = Identity() + ge = Identity(G) @test number_eltype(ge) == Bool @test copyto!(ge, ge) === ge y = allocate(x) @@ -209,7 +209,7 @@ include("group_utils.jl") ) x = [2.0 1.0; 2.0 3.0] - ge = Identity() + ge = Identity(G) @test number_eltype(ge) == Bool @test copyto!(ge, ge) === ge y = allocate(x) diff --git a/test/groups/metric.jl b/test/groups/metric.jl index f3063103a2..bdfd0f14c9 100644 --- a/test/groups/metric.jl +++ b/test/groups/metric.jl @@ -100,14 +100,14 @@ invariant_metric_dispatch(::TestDefaultInvariantMetricManifold, ::RightAction) = e = Matrix{Float64}(I, 3, 3) @testset "inner/norm" begin SO3 = SpecialOrthogonal(3) - p = exp(hat(SO3, Identity(), [1.0, 2.0, 3.0])) + p = exp(hat(SO3, Identity(SO3), [1.0, 2.0, 3.0])) B = DefaultOrthonormalBasis() fX = ManifoldsBase.TFVector([2.0, 3.0, 4.0], B) fY = ManifoldsBase.TFVector([3.0, 4.0, 1.0], B) - X = hat(SO3, Identity(), fX.data) - Y = hat(SO3, Identity(), fY.data) + X = hat(SO3, Identity(SO3), fX.data) + Y = hat(SO3, Identity(SO3), fY.data) G = MetricManifold(SO3, lmetric) @test inner(G, p, fX, fY) ≈ dot(fX.data, Diagonal([1.0, 2.0, 3.0]) * fY.data) @@ -121,11 +121,11 @@ invariant_metric_dispatch(::TestDefaultInvariantMetricManifold, ::RightAction) = @testset "log/exp bi-invariant" begin SO3 = SpecialOrthogonal(3) - e = Identity() + e = Identity(SO3) pe = get_point(SO3, e) p = exp(hat(SO3, pe, [1.0, 2.0, 3.0])) q = exp(hat(SO3, pe, [3.0, 4.0, 1.0])) - X = hat(SO3, Identity(), [2.0, 3.0, 4.0]) + X = hat(SO3, e, [2.0, 3.0, 4.0]) G = MetricManifold(SO3, InvariantMetric(TestBiInvariantMetricBase(), LeftAction())) @test isapprox(SO3, exp(G, p, X), exp(SO3, p, X)) diff --git a/test/groups/product_group.jl b/test/groups/product_group.jl index fa0441cab4..93a34fe079 100644 --- a/test/groups/product_group.jl +++ b/test/groups/product_group.jl @@ -32,12 +32,12 @@ include("group_utils.jl") shape_se = Manifolds.ShapeSpecification(reshaper, M.manifolds...) pts = [Manifolds.prod_point(shape_se, tp...) for tp in tuple_pts] v_pts = [Manifolds.prod_point(shape_se, tuple_v...)] - @test compose(G, pts[1], Identity()) == pts[1] - @test compose(G, Identity(), pts[1]) == pts[1] + @test compose(G, pts[1], Identity(G)) == pts[1] + @test compose(G, Identity(G), pts[1]) == pts[1] test_group(G, pts, v_pts, v_pts; test_diff=true) @test isapprox( M, - Identity(), + Identity(G), group_exp(M, v_pts[1]), Manifolds.prod_point( shape_se, @@ -47,7 +47,7 @@ include("group_utils.jl") ) @test isapprox( M, - Identity(), + Identity(G), group_log(M, pts[1]), Manifolds.prod_point( shape_se, diff --git a/test/groups/semidirect_product_group.jl b/test/groups/semidirect_product_group.jl index 34a4952410..65e5be6631 100644 --- a/test/groups/semidirect_product_group.jl +++ b/test/groups/semidirect_product_group.jl @@ -31,7 +31,7 @@ include("group_utils.jl") @test norm(G, pts[1], Y) ≈ 0 @test norm(G, pts[1], Z) ≈ 0 - e = Identity() + e = Identity(G) @test inv(G, e) === e @test compose(G, e, pts[1]) == pts[1] diff --git a/test/groups/special_euclidean.jl b/test/groups/special_euclidean.jl index c3a1488f7c..b3788f37f3 100644 --- a/test/groups/special_euclidean.jl +++ b/test/groups/special_euclidean.jl @@ -62,7 +62,7 @@ using ManifoldsBase: VeeOrthogonalBasis Manifolds._padvector!(G, tmp) @test tmp == X_pts[1] - w = translate_diff(G, pts[1], Identity(), X_pts[1]) + w = translate_diff(G, pts[1], Identity(G), X_pts[1]) w2 = allocate(w) w2.parts[1] .= w.parts[1] w2.parts[2] .= pts[1].parts[2] * w.parts[2] @@ -92,10 +92,10 @@ using ManifoldsBase: VeeOrthogonalBasis g1g2mat = affine_matrix(G, g1g2) @test g1g2mat ≈ affine_matrix(G, g1) * affine_matrix(G, g2) @test affine_matrix(G, g1g2mat) === g1g2mat - @test affine_matrix(G, Identity()) isa SDiagonal{n,Float64} - @test affine_matrix(G, Identity()) == SDiagonal{n,Float64}(I) + @test affine_matrix(G, Identity(G)) isa SDiagonal{n,Float64} + @test affine_matrix(G, Identity(G)) == SDiagonal{n,Float64}(I) - w = translate_diff(G, pts[1], Identity(), X_pts[1]) + w = translate_diff(G, pts[1], Identity(G), X_pts[1]) w2 = allocate(w) w2.parts[1] .= w.parts[1] w2.parts[2] .= pts[1].parts[2] * w.parts[2] @@ -146,8 +146,8 @@ using ManifoldsBase: VeeOrthogonalBasis end G = SpecialEuclidean(11) - @test affine_matrix(G, Identity()) isa Diagonal{Float64,Vector{Float64}} - @test affine_matrix(G, Identity()) == Diagonal(ones(11)) + @test affine_matrix(G, Identity(G)) isa Diagonal{Float64,Vector{Float64}} + @test affine_matrix(G, Identity(G)) == Diagonal(ones(11)) @testset "Explicit embedding in GL(n+1)" begin G = SpecialEuclidean(3) @@ -197,7 +197,7 @@ using ManifoldsBase: VeeOrthogonalBasis G, pts_gl[1], X_gl, - translate_diff(G, Identity(), pts_gl[1], X_gl, conv), + translate_diff(G, Identity(G), pts_gl[1], X_gl, conv), ) end end diff --git a/test/groups/special_linear.jl b/test/groups/special_linear.jl index 5c58eb9e23..75f9223776 100644 --- a/test/groups/special_linear.jl +++ b/test/groups/special_linear.jl @@ -54,7 +54,7 @@ using NLsolve @test_throws DomainError is_point(G, zeros(3, 3), true) @test_throws DomainError is_point(G, Float64[1 3 3; 1 1 2; 1 2 3], true) @test is_point(G, Float64[1 1 1; 2 2 1; 2 3 3], true) - @test is_point(G, Identity(), true) + @test is_point(G, Identity(G), true) @test_throws DomainError is_vector( G, Float64[2 3 2; 3 1 2; 1 1 1], @@ -151,7 +151,7 @@ using NLsolve @test_throws DomainError is_point(G, ComplexF64[1 0 im; im 0 0; 0 -1 0], true) @test_throws DomainError is_point(G, ComplexF64[1 im; im 1], true) @test is_point(G, ComplexF64[im 1; -2 im], true) - @test is_point(G, Identity(), true) + @test is_point(G, Identity(G), true) @test_throws DomainError is_vector( G, ComplexF64[-1+im -1; -im 1], diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index 2abb94ef5a..7cae53ff72 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -28,7 +28,7 @@ include("group_utils.jl") vpts = [hat(M, x, [-1.0, 2.0, 0.5]), hat(M, x, [1.0, 0.0, 0.5])] ge = allocate(pts[1]) - copyto!(ge, get_point(G, Identity())) + copyto!(ge, get_point(G, Identity(G))) @test isapprox(ge, I; atol=1e-10) gI = Identity() diff --git a/test/groups/array_manifold.jl b/test/groups/validation_group.jl similarity index 96% rename from test/groups/array_manifold.jl rename to test/groups/validation_group.jl index 9a943e96d9..5aa32da92b 100644 --- a/test/groups/array_manifold.jl +++ b/test/groups/validation_group.jl @@ -13,18 +13,18 @@ include("../utils.jl") p, q = [exp(M, eg, hat(M, eg, ωi)) for ωi in ω] X = hat(M, eg, [-1.0, 2.0, 0.5]) - e = Identity() + e = Identity(G) @test Manifolds.array_value(e) == get_point(AG, e) @test Manifolds.array_point(e).p == e.p p2, q2 = ValidationMPoint(p), ValidationMPoint(q) @test q2 === Manifolds.array_point(q2) # test that double wraps are avoided. X2 = ValidationTVector(X) - @test Identity() isa Identity + @test Identity(G) isa Identity eg = allocate(p2) - get_point!(G, eg, Identity()) - @test isapprox(G, eg, Identity()) + get_point!(G, eg, Identity(G)) + @test isapprox(G, eg, Identity(G)) eg = allocate(p2) @test inv(AG, p2) isa ValidationMPoint From 8c3f8cd4e90d2b6377fc727baf88dd68c866198c Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 25 Jul 2021 14:28:40 +0200 Subject: [PATCH 09/88] fix a few renaming issues and ambiguities. --- src/Manifolds.jl | 19 +++++-- src/groups/general_linear.jl | 9 +++- src/groups/group.jl | 90 ++++++++++++++++++++----------- src/groups/special_euclidean.jl | 4 +- src/groups/special_linear.jl | 11 ++-- test/groups/connections.jl | 8 +-- test/groups/groups_general.jl | 2 +- test/groups/special_orthogonal.jl | 8 +-- test/groups/validation_group.jl | 2 +- test/runtests.jl | 2 +- 10 files changed, 103 insertions(+), 52 deletions(-) diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 7abe922704..a4dca76e43 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -63,7 +63,17 @@ import ManifoldsBase: CotangentSpace, TangentSpace import Base: - copyto!, convert, foreach, in, isapprox, isempty, length, ndims, showerror, size + copyto!, + convert, + foreach, + identity, + in, + isapprox, + isempty, + length, + ndims, + showerror, + size using Base.Iterators: repeated using Distributions @@ -466,6 +476,8 @@ export ×, get_embedding, hat, hat!, + identity, + identity!, induced_basis, incident_log, injectivity_radius, @@ -474,10 +486,11 @@ export ×, inverse_retract, inverse_retract!, isapprox, - is_group_decorator, is_decorator_transparent, - is_default_metric, is_default_decorator, + is_default_metric, + is_group_decorator, + is_identity, is_point, is_vector, isapprox, diff --git a/src/groups/general_linear.jl b/src/groups/general_linear.jl index 3b13615bc5..d548aaa47c 100644 --- a/src/groups/general_linear.jl +++ b/src/groups/general_linear.jl @@ -37,6 +37,11 @@ function check_point(G::GeneralLinear, p; kwargs...) end return nothing end +check_point(::GeneralLinear, ::Identity{MultiplicationOperation}) = nothing +function check_point(G::GeneralLinear, e::Identity{O}; kwargs...) where {O} + return invoke(check_point, Tuple{AbstractGroupManifold,typeof(e)}, G, e; kwargs...) +end + function check_vector(G::GeneralLinear, p, X; kwargs...) mpv = check_vector(decorated_manifold(G), p, X; kwargs...) mpv === nothing || return mpv @@ -203,10 +208,10 @@ function log!(G::GeneralLinear{n,𝔽}, X, p, q) where {n,𝔽} Xᵣ = realify(X, 𝔽) log_safe!(Xᵣ, _project_Un_S⁺(pinvqᵣ)) inverse_retraction = NLsolveInverseRetraction(ExponentialRetraction(), Xᵣ) - inverse_retract!(Gᵣ, Xᵣ, Identity(), pinvqᵣ, inverse_retraction) + inverse_retract!(Gᵣ, Xᵣ, Identity(G), pinvqᵣ, inverse_retraction) unrealify!(X, Xᵣ, 𝔽, n) end - translate_diff!(G, X, p, Identity(), X, LeftAction()) + translate_diff!(G, X, p, Identity(G), X, LeftAction()) return X end function log!(::GeneralLinear{1}, X, p, q) diff --git a/src/groups/group.jl b/src/groups/group.jl index 036f011cae..460a8cfeb3 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -249,13 +249,23 @@ return a point representation of the [`Identity`](@ref) on the [`AbstractGroupMa """ identity!(G::AbstractGroupManifold, p) -Base.show(io::IO, ::Identity{O}) where {O}= print(io, "Identity($O)") +Base.show(io::IO, ::Identity{O}) where {O} = print(io, "Identity($O)") Base.copyto!(e::Identity{O}, ::Identity{O}) where {O} = e -check_point(G::AbstractGroupManifold{𝔽,M,O}, e::Identity{O}; kwargs...) where {𝔽,M,O} = nothing +function check_point( + G::AbstractGroupManifold{𝔽,M,O}, + e::Identity{O}; + kwargs..., +) where {𝔽,M,O} + return nothing +end -function check_point(G::AbstractGroupManifold{𝔽,M,O1}, e::Identity{O2}; kwargs...) where {𝔽,M,O1,O2} +function check_point( + G::AbstractGroupManifold{𝔽,M,O1}, + e::Identity{O2}; + kwargs..., +) where {𝔽,M,O1,O2} return DomainError( e, "The Identity $e does not lie on $M, since its the identity with respect to $O2 and not $O1.", @@ -769,15 +779,15 @@ struct AdditionOperation <: AbstractGroupOperation end const AdditionGroup = AbstractGroupManifold{𝔽,AdditionOperation} where {𝔽} -Base.:+(e::Identity) = e -Base.:+(e::Identity, ::Identity) = e -Base.:+(::Identity, p) = p -Base.:+(p, ::Identity) = p +Base.:+(e::Identity{AdditionOperation}) = e +Base.:+(e::Identity{AdditionOperation}, ::Identity{AdditionOperation}) = e +Base.:+(::Identity{AdditionOperation}, p) = p +Base.:+(p, ::Identity{AdditionOperation}) = p -Base.:-(e::Identity) = e -Base.:-(e::Identity, ::Identity) = e -Base.:-(::Identity, p) = -p -Base.:-(p, ::Identity) = p +Base.:-(e::Identity{AdditionOperation}) = e +Base.:-(e::Identity{AdditionOperation}, ::Identity{AdditionOperation}) = e +Base.:-(::Identity{AdditionOperation}, p) = -p +Base.:-(p, ::Identity{AdditionOperation}) = p adjoint_action(::AdditionGroup, p, X) = X @@ -787,14 +797,21 @@ Base.inv(::AdditionGroup, p) = -p Base.inv(::AdditionGroup, e::Identity) = e inv!(::AdditionGroup, q, p) = copyto!(q, -p) -inv!(G::AdditionGroup, q, e::Identity) = get_point!(G, q, e) +inv!(G::AdditionGroup, q, ::Identity) = identity(G, q) inv!(::AdditionGroup, q::Identity, e::Identity) = q compose(::AdditionGroup, p, q) = p + q -compose!(::AdditionGroup, x, p, ::Identity) = copyto!(x, p) -compose!(::AdditionGroup, x, ::Identity, q) = copyto!(x, q) -compose!(G::AdditionGroup, x, ::Identity, q::Identity) = copyto!(x, get_point(G, q)) +compose!(::AdditionGroup, x, p, ::Identity{AdditionOperation}) = copyto!(x, p) +compose!(::AdditionGroup, x, ::Identity{AdditionOperation}, q) = copyto!(x, q) +function compose!( + G::AdditionGroup, + x, + ::Identity{AdditionOperation}, + q::Identity{AdditionOperation}, +) + return identity!(G, x) +end compose!(::AdditionGroup, x::Identity, ::Identity, ::Identity) = x function compose!(::AdditionGroup, x, p, q) x .= p .+ q @@ -818,7 +835,7 @@ group_exp!(::AdditionGroup, q, X) = copyto!(q, X) group_log(::AdditionGroup, q) = q group_log!(::AdditionGroup, X, q) = copyto!(X, q) -group_log!(::AdditionGroup, X, e::Identity) = X +group_log!(::AdditionGroup, X, e::Identity{AdditionOperation}) = X lie_bracket(::AdditionGroup, X, Y) = zero(X) @@ -837,24 +854,37 @@ struct MultiplicationOperation <: AbstractGroupOperation end const MultiplicationGroup = AbstractGroupManifold{𝔽,MultiplicationOperation} where {𝔽} -Base.:*(e::Identity) = e -Base.:*(::Identity, p) = p -Base.:*(p, ::Identity) = p -Base.:*(e::Identity, ::Identity) = e +Base.:*(e::Identity{MultiplicationOperation}) = e +Base.:*(::Identity{MultiplicationOperation}, p) = p +Base.:*(p, ::Identity{MultiplicationOperation}) = p +Base.:*(e::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation}) = e -Base.:/(p, ::Identity) = p -Base.:/(::Identity, p) = inv(p) -Base.:/(e::Identity, ::Identity) = e +Base.:/(p, ::Identity{MultiplicationOperation}) = p +Base.:/(::Identity{MultiplicationOperation}, p) = inv(p) +Base.:/(e::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation}) = e -Base.:\(p, ::Identity) = inv(p) -Base.:\(::Identity, p) = p -Base.:\(e::Identity, ::Identity) = e +Base.:\(p, ::Identity{MultiplicationOperation}) = inv(p) +Base.:\(::Identity{MultiplicationOperation}, p) = p +Base.:\(e::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation}) = e -LinearAlgebra.det(::Identity) = 1 +LinearAlgebra.det(::Identity{MultiplicationOperation}) = 1 -LinearAlgebra.mul!(q, ::Identity, p) = copyto!(q, p) -LinearAlgebra.mul!(q, p, ::Identity) = copyto!(q, p) -LinearAlgebra.mul!(q, e::Identity, ::Identity) = get_point!(G, q, e) +LinearAlgebra.mul!(q, ::Identity{MultiplicationOperation}, p) = copyto!(q, p) +LinearAlgebra.mul!(q, p, ::Identity{MultiplicationOperation}) = copyto!(q, p) +function LinearAlgebra.mul!( + q, + ::Identity{MultiplicationOperation}, + ::Identity{MultiplicationOperation}, +) + return identity!(G, q) +end +function LinearAlgebra.mul!( + q::Identity{MultiplicationOperation}, + ::Identity{MultiplicationOperation}, + ::Identity{MultiplicationOperation}, +) + return q +end Base.inv(::MultiplicationGroup, p) = inv(p) diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index a2c690993e..bd3ae6cbcb 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -169,10 +169,10 @@ function screw_matrix(G::SpecialEuclidean{n}, X) where {n} end screw_matrix(::SpecialEuclidean{n}, X::AbstractMatrix) where {n} = X -function allocate_result(G::SpecialEuclidean{n}, f::typeof(affine_matrix), p...) where {n} +function allocate_result(::SpecialEuclidean{n}, f::typeof(affine_matrix), p...) where {n} return allocate(p[1], Size(n + 1, n + 1)) end -function allocate_result(G::SpecialEuclidean{n}, f::typeof(screw_matrix), X...) where {n} +function allocate_result(::SpecialEuclidean{n}, f::typeof(screw_matrix), X...) where {n} return allocate(X[1], Size(n + 1, n + 1)) end diff --git a/src/groups/special_linear.jl b/src/groups/special_linear.jl index 45f02fc861..998cc6aa05 100644 --- a/src/groups/special_linear.jl +++ b/src/groups/special_linear.jl @@ -25,10 +25,8 @@ function allocation_promotion_function(::SpecialLinear{n,ℂ}, f, args::Tuple) w return complex end -function get_point!(::SpecialLinear{n,𝔽}, p, ::Identity) where {n,𝔽} - T = (𝔽 == ℂ) ? ComplexF64 : Float64 - copyto(p, Matrix{T}(I, n, n)) - return p +function identity!(::SpecialLinear, q) where {n,𝔽} + return copyto!(q, one(q)) end function check_point(G::SpecialLinear{n,𝔽}, p; kwargs...) where {n,𝔽} @@ -44,6 +42,11 @@ function check_point(G::SpecialLinear{n,𝔽}, p; kwargs...) where {n,𝔽} end return nothing end +check_point(G::SpecialLinear, ::Identity{MultiplicationOperation}; kwargs...) = nothing +function check_point(G::SpecialLinear, e::Identity{O}; kwargs...) where {O} + return invoke(check_point, Tuple{AbstractGroupManifold,typeof(e)}, G, e; kwargs...) +end + function check_vector(G::SpecialLinear, p, X; kwargs...) mpv = check_vector(decorated_manifold(G), p, X; kwargs...) mpv === nothing || return mpv diff --git a/test/groups/connections.jl b/test/groups/connections.jl index 55e4f9897f..5f60cebf5a 100644 --- a/test/groups/connections.jl +++ b/test/groups/connections.jl @@ -10,10 +10,10 @@ using Manifolds: connection SO3zero = ConnectionManifold(SO3, CartanSchoutenZero()) e = Matrix{Float64}(I, 3, 3) - p = exp(hat(SO3, Identity(), [1.0, 2.0, 3.0])) - q = exp(hat(SO3, Identity(), [3.0, 4.0, 1.0])) - X = hat(SO3, Identity(), [2.0, 3.0, 4.0]) - SO3e = Identity() + p = exp(hat(SO3, Identity(SO3), [1.0, 2.0, 3.0])) + q = exp(hat(SO3, Identity(SO3), [3.0, 4.0, 1.0])) + X = hat(SO3, Identity(SO3), [2.0, 3.0, 4.0]) + SO3e = Identity(SO3) @testset "connection" begin @test connection(SO3minus) === CartanSchoutenMinus() diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 9fd20b9aad..71714b6f74 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -276,7 +276,7 @@ include("group_utils.jl") @testset "Identity on Group Manifolds" begin G = TranslationGroup(3) - e = Identity() + e = Identity(G) @test get_vector(G, e, ones(3), DefaultOrthogonalBasis()) == ones(3) @test e - e == e @test ones(3) + e == ones(3) diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index 7cae53ff72..651dfceced 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -31,7 +31,7 @@ include("group_utils.jl") copyto!(ge, get_point(G, Identity(G))) @test isapprox(ge, I; atol=1e-10) - gI = Identity() + gI = Identity(G) gT = allocate_result(G, exp, gI, log(G, pts[1], pts[2])) @test size(gT) == size(ge) @test eltype(gT) == eltype(ge) @@ -131,7 +131,7 @@ include("group_utils.jl") @testset "vee/hat" begin X = vpts[1] - pe = Identity() + pe = Identity(G) Xⁱ = vee(G, get_point(G, pe), X) @test Xⁱ ≈ vee(G, pe, X) @@ -140,7 +140,7 @@ include("group_utils.jl") @test isapprox(M, pe, X2, hat(G, pe, Xⁱ); atol=1e-6) end @testset "Identity and get_vector/get_coordinates" begin - e = Identity() + e = Identity(G, Matrix{Float64}(I, 3, 3)) gT = allocate_result(G, get_coordinates, e, pts[1]) @test size(gT) == (manifold_dimension(M),) @test eltype(gT) == eltype(e.p) @@ -152,7 +152,7 @@ include("group_utils.jl") copyto!(eT, e) @test eT == e.p - eF = Identity() + eF = Identity(SpecialEuclidean(3), 1) c = [1.0, 0.0, 0.0] Y = zeros(representation_size(G)) get_vector!(G, Y, e, c, Manifolds.VeeOrthogonalBasis()) diff --git a/test/groups/validation_group.jl b/test/groups/validation_group.jl index 5aa32da92b..772850fe2e 100644 --- a/test/groups/validation_group.jl +++ b/test/groups/validation_group.jl @@ -30,7 +30,7 @@ include("../utils.jl") @test inv(AG, p2) isa ValidationMPoint @test isapprox(G, inv(AG, p2).value, inv(G, p)) @test inv(AG, e) isa Identity - @test_throws DomainError inv(AG, Identity()) + @test_throws DomainError inv(AG, Identity(AG)) pinvq = allocate(p2) inv!(AG, pinvq, p2) diff --git a/test/runtests.jl b/test/runtests.jl index 61d172e2fd..91859d5616 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -144,7 +144,7 @@ include("utils.jl") # Lie groups and actions include_test("groups/groups_general.jl") - include_test("groups/array_manifold.jl") + include_test("groups/validation_group.jl") include_test("groups/circle_group.jl") include_test("groups/translation_group.jl") include_test("groups/general_linear.jl") From 4e0879f881d33a378667fb1e541e0d577854e70a Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 25 Jul 2021 14:45:25 +0200 Subject: [PATCH 10/88] change some old ooccurences ot get_point/get_point! to the new identity/identity! --- src/groups/group.jl | 6 +++--- src/groups/semidirect_product_group.jl | 8 ++++---- src/groups/special_orthogonal.jl | 2 ++ src/groups/translation_group.jl | 2 +- test/groups/groups_general.jl | 2 +- test/groups/metric.jl | 2 +- test/groups/product_group.jl | 4 ++-- test/groups/special_orthogonal.jl | 4 ++-- 8 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index 460a8cfeb3..57b32a9ba0 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -330,10 +330,10 @@ Base.inv(::AbstractGroupManifold, e::Identity) = e return inv!(G.manifold, q, p) end -inv!(G::AbstractGroupManifold, q, e::Identity) = get_point!(G, q, e) +inv!(G::AbstractGroupManifold, q, ::Identity) = identity!(G, q) function Base.isapprox(G::AbstractGroupManifold, e::Identity, p; kwargs...) - return isapprox(G, get_point(G, e), p; kwargs...) + return isapprox(G, identity(G, p), p; kwargs...) end function Base.isapprox(G::AbstractGroupManifold, p, e::Identity; kwargs...) return isapprox(G, e, p; kwargs...) @@ -357,7 +357,7 @@ end compose!(::AbstractGroupManifold, q, p, ::Identity) = copyto!(q, p) compose!(::AbstractGroupManifold, q, ::Identity, p) = copyto!(q, p) -compose!(G::AbstractGroupManifold, q, ::Identity, e::Identity) = copyto(q, get_point(G, e)) +compose!(G::AbstractGroupManifold, q, ::Identity, e::Identity) = identity!(G, q) compose!(::AbstractGroupManifold, e::Identity, ::Identity, ::Identity) = e """ diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index 89b4259877..520d7d91e9 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -52,12 +52,12 @@ function SemidirectProductGroup( return GroupManifold(M, op) end -function get_point!(G::SemidirectProductGroup, q, e::Identity) +function identity!(G::SemidirectProductGroup, q) M = base_manifold(G) N, H = M.manifolds nq, hq = submanifold_components(G, q) - get_point!(N, nq, e) - get_point!(H, hq, e) + identity!(N, nq) + identity!(H, hq) @inbounds _padpoint!(G, q) return q end @@ -89,7 +89,7 @@ function inv!(G::SemidirectProductGroup, q, p) end compose!(::SemidirectProductGroup, q, ::Identity, p) = copyto!(q, p) -compose!(G::SemidirectProductGroup, q, ::Identity, e::Identity) = copyto(q, get_point(G, e)) +compose!(G::SemidirectProductGroup, q, ::Identity, e::Identity) = identity!(G, q) compose!(::SemidirectProductGroup, e::Identity, ::Identity, ::Identity) = e function compose!(G::SemidirectProductGroup, x, p, q) M = base_manifold(G) diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index 99691c35c0..1b2de37fe2 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -17,6 +17,8 @@ function default_metric_dispatch( end default_metric_dispatch(::SpecialOrthogonal, ::EuclideanMetric) = Val(true) +identity!(::SpecialOrthogonal, q) = copyto!(q, one(q)) + SpecialOrthogonal(n) = SpecialOrthogonal{n}(Rotations(n), MultiplicationOperation()) Base.show(io::IO, ::SpecialOrthogonal{n}) where {n} = print(io, "SpecialOrthogonal($(n))") diff --git a/src/groups/translation_group.jl b/src/groups/translation_group.jl index 39a23906b5..55b20399ef 100644 --- a/src/groups/translation_group.jl +++ b/src/groups/translation_group.jl @@ -18,7 +18,7 @@ function TranslationGroup(n::Int...; field::AbstractNumbers=ℝ) ) end -get_point!(::TranslationGroup, p, ::Identity) = fill!(p, 0) +identity!(::TranslationGroup, p) = fill!(p, 0) invariant_metric_dispatch(::TranslationGroup, ::ActionDirection) = Val(true) diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 71714b6f74..5589cba9ac 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -20,7 +20,7 @@ include("group_utils.jl") @test is_point(G, eg) # identity transparent p = similar(x) copyto!(p, eg) - @test p == get_point(G, eg) + @test p == identity(G) @test isapprox(G, eg, p) @test isapprox(G, p, eg) @test isapprox(G, eg, eg) diff --git a/test/groups/metric.jl b/test/groups/metric.jl index bdfd0f14c9..56dee8c188 100644 --- a/test/groups/metric.jl +++ b/test/groups/metric.jl @@ -122,7 +122,7 @@ invariant_metric_dispatch(::TestDefaultInvariantMetricManifold, ::RightAction) = @testset "log/exp bi-invariant" begin SO3 = SpecialOrthogonal(3) e = Identity(SO3) - pe = get_point(SO3, e) + pe = identity(SO3) p = exp(hat(SO3, pe, [1.0, 2.0, 3.0])) q = exp(hat(SO3, pe, [3.0, 4.0, 1.0])) X = hat(SO3, e, [2.0, 3.0, 4.0]) diff --git a/test/groups/product_group.jl b/test/groups/product_group.jl index 93a34fe079..a6357793e2 100644 --- a/test/groups/product_group.jl +++ b/test/groups/product_group.jl @@ -61,8 +61,8 @@ include("group_utils.jl") @testset "product repr" begin pts = [ProductRepr(tp...) for tp in tuple_pts] v_pts = [ProductRepr(tuple_v...)] - @test compose(G, pts[1], Identity()) == pts[1] - @test compose(G, Identity(), pts[1]) == pts[1] + @test compose(G, pts[1], Identity(G)) == pts[1] + @test compose(G, Identity(G), pts[1]) == pts[1] test_group(G, pts, v_pts, v_pts; test_diff=true, test_mutating=false) @test isapprox( M, diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index 651dfceced..97b853945b 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -28,7 +28,7 @@ include("group_utils.jl") vpts = [hat(M, x, [-1.0, 2.0, 0.5]), hat(M, x, [1.0, 0.0, 0.5])] ge = allocate(pts[1]) - copyto!(ge, get_point(G, Identity(G))) + identity!(G, de) @test isapprox(ge, I; atol=1e-10) gI = Identity(G) @@ -133,7 +133,7 @@ include("group_utils.jl") X = vpts[1] pe = Identity(G) - Xⁱ = vee(G, get_point(G, pe), X) + Xⁱ = vee(G, identity(G), X) @test Xⁱ ≈ vee(G, pe, X) X2 = hat(G, pts[1], Xⁱ) From c82e6814d617e30247c671355fb380e64d135f27 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 25 Jul 2021 15:51:38 +0200 Subject: [PATCH 11/88] reduce ambiguities. --- src/groups/group.jl | 22 ++++++++++++++++++++++ test/groups/validation_group.jl | 4 +--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index 57b32a9ba0..aedcaf353f 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -793,6 +793,8 @@ adjoint_action(::AdditionGroup, p, X) = X adjoint_action!(::AdditionGroup, Y, p, X) = copyto!(Y, X) +identity!(::AbstractGroupManifold{𝔽,<:AdditionOperation}, p) where {𝔽} = copyto!(p, zero(p)) + Base.inv(::AdditionGroup, p) = -p Base.inv(::AdditionGroup, e::Identity) = e @@ -801,6 +803,9 @@ inv!(G::AdditionGroup, q, ::Identity) = identity(G, q) inv!(::AdditionGroup, q::Identity, e::Identity) = q compose(::AdditionGroup, p, q) = p + q +compose(::AdditionGroup, p, ::Identity{AdditionOperation}) = p +compose(::AdditionGroup, ::Identity{AdditionOperation}, q) = q +compose(::AdditionGroup, e::Identity{AdditionOperation}, ::Identity{AdditionOperation}) = e compose!(::AdditionGroup, x, p, ::Identity{AdditionOperation}) = copyto!(x, p) compose!(::AdditionGroup, x, ::Identity{AdditionOperation}, q) = copyto!(x, q) @@ -869,6 +874,10 @@ Base.:\(e::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation LinearAlgebra.det(::Identity{MultiplicationOperation}) = 1 +function identity!(::AbstractGroupManifold{𝔽,<:MultiplicationOperation}, p) where {𝔽} + return copyto!(p, one(p)) +end + LinearAlgebra.mul!(q, ::Identity{MultiplicationOperation}, p) = copyto!(q, p) LinearAlgebra.mul!(q, p, ::Identity{MultiplicationOperation}) = copyto!(q, p) function LinearAlgebra.mul!( @@ -891,8 +900,21 @@ Base.inv(::MultiplicationGroup, p) = inv(p) inv!(G::MultiplicationGroup, q, p) = copyto!(q, inv(G, p)) compose(::MultiplicationGroup, p, q) = p * q +compose(::MultiplicationGroup, p, ::Identity{MultiplicationOperation}) = p +compose(::MultiplicationGroup, ::Identity{MultiplicationOperation}, q) = q +function compose( + ::MultiplicationGroup, + e::Identity{MultiplicationOperation}, + ::Identity{MultiplicationOperation}, +) + return e +end compose!(::MultiplicationGroup, x, p, q) = mul!_safe(x, p, q) +compose!(::MultiplicationGroup, q, p, ::Identity) = copyto!(q, p) +compose!(::MultiplicationGroup, q, ::Identity, p) = copyto!(q, p) +compose!(G::MultiplicationGroup, q, ::Identity, e::Identity) = identity!(G, q) +compose!(::MultiplicationGroup, e::Identity, ::Identity, ::Identity) = e inverse_translate(::MultiplicationGroup, p, q, ::LeftAction) = p \ q inverse_translate(::MultiplicationGroup, p, q, ::RightAction) = q / p diff --git a/test/groups/validation_group.jl b/test/groups/validation_group.jl index 772850fe2e..49ecd57be6 100644 --- a/test/groups/validation_group.jl +++ b/test/groups/validation_group.jl @@ -14,8 +14,6 @@ include("../utils.jl") X = hat(M, eg, [-1.0, 2.0, 0.5]) e = Identity(G) - @test Manifolds.array_value(e) == get_point(AG, e) - @test Manifolds.array_point(e).p == e.p p2, q2 = ValidationMPoint(p), ValidationMPoint(q) @test q2 === Manifolds.array_point(q2) # test that double wraps are avoided. X2 = ValidationTVector(X) @@ -23,7 +21,7 @@ include("../utils.jl") @test Identity(G) isa Identity eg = allocate(p2) - get_point!(G, eg, Identity(G)) + identity!(G, eg) @test isapprox(G, eg, Identity(G)) eg = allocate(p2) From 6ee0e57cc9c5cdf1c75dbde12ea17ea75752536d Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 25 Jul 2021 16:56:17 +0200 Subject: [PATCH 12/88] add another special case. --- src/groups/special_orthogonal.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index 1b2de37fe2..df96be5749 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -24,6 +24,7 @@ SpecialOrthogonal(n) = SpecialOrthogonal{n}(Rotations(n), MultiplicationOperatio Base.show(io::IO, ::SpecialOrthogonal{n}) where {n} = print(io, "SpecialOrthogonal($(n))") Base.inv(::SpecialOrthogonal, p) = transpose(p) +Base.inv(::SpecialOrthogonal, e::Identity) = e inverse_translate(G::SpecialOrthogonal, p, q, ::LeftAction) = inv(G, p) * q inverse_translate(G::SpecialOrthogonal, p, q, ::RightAction) = q * inv(G, p) From 0d18fdb3fb4dc5f6f1db9624334f3c1053c7fce6 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 25 Jul 2021 17:29:21 +0200 Subject: [PATCH 13/88] Fix two further errors. --- src/groups/group.jl | 2 +- src/groups/rotation_action.jl | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index aedcaf353f..f5e727878a 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -817,7 +817,7 @@ function compose!( ) return identity!(G, x) end -compose!(::AdditionGroup, x::Identity, ::Identity, ::Identity) = x +compose!(::AdditionGroup, x::Identity{AdditionOperation}, ::Identity{AdditionOperation}, ::Identity{AdditionOperation}) = x function compose!(::AdditionGroup, x, p, q) x .= p .+ q return x diff --git a/src/groups/rotation_action.jl b/src/groups/rotation_action.jl index fc50876b52..a4310d3f71 100644 --- a/src/groups/rotation_action.jl +++ b/src/groups/rotation_action.jl @@ -52,7 +52,8 @@ function inverse_apply(A::RotationActionOnVector{N,F,LeftAction}, a, p) where {N end inverse_apply(A::RotationActionOnVector{N,F,RightAction}, a, p) where {N,F} = a * p -apply_diff(A::RotationActionOnVector{N,F,LeftAction}, a, p, X) where {N,F} = a * X +apply_diff(::RotationActionOnVector{N,F,LeftAction}, a, p, X) where {N,F} = a * X +apply_diff(::RotationActionOnVector{N,F,LeftAction}, ::Identity, p, X) where {N,F} = X function apply_diff(A::RotationActionOnVector{N,F,RightAction}, a, p, X) where {N,F} return inv(base_group(A), a) * X end From b79384af4e0f55d264cfc4a9aba7b8e747a406ba Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Mon, 26 Jul 2021 12:41:10 +0200 Subject: [PATCH 14/88] removing some ambiguities --- src/groups/circle_group.jl | 12 ++++ src/groups/group.jl | 86 ++++++++++++++++---------- src/groups/semidirect_product_group.jl | 8 +-- src/groups/special_linear.jl | 4 +- src/groups/special_orthogonal.jl | 2 +- src/groups/translation_group.jl | 2 +- test/groups/circle_group.jl | 2 - test/groups/groups_general.jl | 2 +- test/groups/metric.jl | 2 +- test/groups/special_orthogonal.jl | 4 +- test/groups/validation_group.jl | 2 +- test/utils.jl | 4 +- 12 files changed, 79 insertions(+), 51 deletions(-) diff --git a/src/groups/circle_group.jl b/src/groups/circle_group.jl index 686419e6c1..15e1234391 100644 --- a/src/groups/circle_group.jl +++ b/src/groups/circle_group.jl @@ -23,6 +23,17 @@ function compose(G::CircleGroup, p::AbstractVector, q::AbstractVector) end compose!(G::CircleGroup, x, p, q) = copyto!(x, compose(G, p, q)) +compose!(G::CircleGroup, x, p, ::Identity) = copyto!(x, p) +compose!(G::CircleGroup, x, ::Identity, p) = copyto!(x, p) +compose!(G::CircleGroup, e::Identity, ::Identity, ::Identity) = e + +identity_element(G::CircleGroup) = 1.0 +identity_element(::CircleGroup, p::Number) = one(p) +identity_element(::CircleGroup, p::AbstractArray) = map(i -> one(eltype(p)), p) + +function identity_element!(::CircleGroup, p) + return fill!(p, one(eltype(p))) +end Base.inv(G::CircleGroup, p::AbstractVector) = map(inv, repeated(G), p) @@ -71,5 +82,6 @@ function group_log(::CircleGroup, q) return θ * im end end +group_log(::CircleGroup, e::Identity{MultiplicationOperation}) = 0.0 * im group_log!(G::CircleGroup, X::AbstractVector, q::AbstractVector) = (X .= group_log(G, q)) diff --git a/src/groups/group.jl b/src/groups/group.jl index aedcaf353f..4fe4ad8c4b 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -197,19 +197,38 @@ Identity(::Type{O}) where {O<:AbstractGroupOperation} = Identity{O}() number_eltype(::Identity) = Bool @doc raw""" - identity(G::AbstractGroupManifold) + identity_element(G::AbstractGroupManifold) return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G`. by default this representation is default array representation. It should return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if points are not represented by arrays. """ -function identity(G::AbstractGroupManifold) +function identity_element(G::AbstractGroupManifold) q = zeros(representation_size(G)...) - return identity!(G, q) + return identity_element!(G, q) end @doc raw""" - is_identity(G,q; kwargs) + identity_element(G::AbstractGroupManifold, p) + +return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G` (in place of `p`). +by default this representation is default array representation. +It rhoudl return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if points are not represented by arrays. +""" +function identity_element(G::AbstractGroupManifold, p) + q = allocate_result(G, identity_element, p) + return identity_element!(G, q) +end + +@doc raw""" + identity_element!(G::AbstractGroupManifold, p) + +return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G` in place of `p`. +""" +identity_element!(G::AbstractGroupManifold, p) + +@doc raw""" + is_identity(G, q; kwargs) Check, whether `q` is the identity on the [`AbstractGroupManifold`](@ref) `G`, i.e. it is either the [`Identity`](@ref)`{O}` with the corresponding [`AbstractGroupOperation`](@ref) `O`, or @@ -218,7 +237,7 @@ the [`Identity`](@ref)`{O}` with the corresponding [`AbstractGroupOperation`](@r is_identity(G::AbstractGroupManifold, q) function is_identity(G::AbstractGroupManifold, q; kwargs...) - return isapprox(G, q, identity(G, q); kwargs...) + return isapprox(G, q, identity_element(G, q); kwargs...) end function is_identity( @@ -230,25 +249,6 @@ function is_identity( end is_identity(::AbstractGroupManifold, ::Identity; kwargs...) = false -@doc raw""" - identity(G::AbstractGroupManifold, p) - -return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G` (in place of `p`). -by default this representation is default array representation. -It rhoudl return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if points are not represented by arrays. -""" -function identity(G::AbstractGroupManifold, p) - q = allocate_result(G, identity, p) - return identity!(G, q) -end - -@doc raw""" - identity!(G::AbstractGroupManifold, p) - -return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G` in place of `p`. -""" -identity!(G::AbstractGroupManifold, p) - Base.show(io::IO, ::Identity{O}) where {O} = print(io, "Identity($O)") Base.copyto!(e::Identity{O}, ::Identity{O}) where {O} = e @@ -330,10 +330,10 @@ Base.inv(::AbstractGroupManifold, e::Identity) = e return inv!(G.manifold, q, p) end -inv!(G::AbstractGroupManifold, q, ::Identity) = identity!(G, q) +inv!(G::AbstractGroupManifold, q, ::Identity) = identity_element!(G, q) function Base.isapprox(G::AbstractGroupManifold, e::Identity, p; kwargs...) - return isapprox(G, identity(G, p), p; kwargs...) + return isapprox(G, identity_element(G, p), p; kwargs...) end function Base.isapprox(G::AbstractGroupManifold, p, e::Identity; kwargs...) return isapprox(G, e, p; kwargs...) @@ -357,7 +357,7 @@ end compose!(::AbstractGroupManifold, q, p, ::Identity) = copyto!(q, p) compose!(::AbstractGroupManifold, q, ::Identity, p) = copyto!(q, p) -compose!(G::AbstractGroupManifold, q, ::Identity, e::Identity) = identity!(G, q) +compose!(G::AbstractGroupManifold, q, ::Identity, e::Identity) = identity_element!(G, q) compose!(::AbstractGroupManifold, e::Identity, ::Identity, ::Identity) = e """ @@ -640,9 +640,23 @@ group_log(::AbstractGroupManifold, ::Any...) X = allocate_result(G, group_log, q) return group_log!(G, X, q) end +function group_log( + G::AbstractGroupManifold{𝔽,Op}, + ::Identity{Op}, +) where {𝔽,Op<:AbstractGroupOperation} + return zero_vector(G, identity_element(G)) +end @decorator_transparent_signature group_log!(M::AbstractDecoratorManifold, X, q) +function group_log!( + G::AbstractGroupManifold{𝔽,Op}, + X, + ::Identity{Op}, +) where {𝔽,Op<:AbstractGroupOperation} + return zero_vector!(G, X, identity_element(G)) +end + ############################ # Group-specific Retractions ############################ @@ -793,13 +807,15 @@ adjoint_action(::AdditionGroup, p, X) = X adjoint_action!(::AdditionGroup, Y, p, X) = copyto!(Y, X) -identity!(::AbstractGroupManifold{𝔽,<:AdditionOperation}, p) where {𝔽} = copyto!(p, zero(p)) +function identity_element!(::AbstractGroupManifold{𝔽,<:AdditionOperation}, p) where {𝔽} + return fill!(p, zero(eltype(p))) +end Base.inv(::AdditionGroup, p) = -p Base.inv(::AdditionGroup, e::Identity) = e inv!(::AdditionGroup, q, p) = copyto!(q, -p) -inv!(G::AdditionGroup, q, ::Identity) = identity(G, q) +inv!(G::AdditionGroup, q, ::Identity) = identity_element!(G, q) inv!(::AdditionGroup, q::Identity, e::Identity) = q compose(::AdditionGroup, p, q) = p + q @@ -815,7 +831,7 @@ function compose!( ::Identity{AdditionOperation}, q::Identity{AdditionOperation}, ) - return identity!(G, x) + return identity_element!(G, x) end compose!(::AdditionGroup, x::Identity, ::Identity, ::Identity) = x function compose!(::AdditionGroup, x, p, q) @@ -874,8 +890,8 @@ Base.:\(e::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation LinearAlgebra.det(::Identity{MultiplicationOperation}) = 1 -function identity!(::AbstractGroupManifold{𝔽,<:MultiplicationOperation}, p) where {𝔽} - return copyto!(p, one(p)) +function identity_element!(::MultiplicationGroup, p) + return copyto!(p, I) end LinearAlgebra.mul!(q, ::Identity{MultiplicationOperation}, p) = copyto!(q, p) @@ -885,7 +901,7 @@ function LinearAlgebra.mul!( ::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation}, ) - return identity!(G, q) + return identity_element!(G, q) end function LinearAlgebra.mul!( q::Identity{MultiplicationOperation}, @@ -896,8 +912,10 @@ function LinearAlgebra.mul!( end Base.inv(::MultiplicationGroup, p) = inv(p) +Base.inv(::MultiplicationGroup, e::Identity) = e inv!(G::MultiplicationGroup, q, p) = copyto!(q, inv(G, p)) +inv!(G::MultiplicationGroup, q, ::Identity) = identity_element!(G, q) compose(::MultiplicationGroup, p, q) = p * q compose(::MultiplicationGroup, p, ::Identity{MultiplicationOperation}) = p @@ -913,7 +931,7 @@ end compose!(::MultiplicationGroup, x, p, q) = mul!_safe(x, p, q) compose!(::MultiplicationGroup, q, p, ::Identity) = copyto!(q, p) compose!(::MultiplicationGroup, q, ::Identity, p) = copyto!(q, p) -compose!(G::MultiplicationGroup, q, ::Identity, e::Identity) = identity!(G, q) +compose!(G::MultiplicationGroup, q, ::Identity, e::Identity) = identity_element!(G, q) compose!(::MultiplicationGroup, e::Identity, ::Identity, ::Identity) = e inverse_translate(::MultiplicationGroup, p, q, ::LeftAction) = p \ q diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index 520d7d91e9..f2f69e27ee 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -52,12 +52,12 @@ function SemidirectProductGroup( return GroupManifold(M, op) end -function identity!(G::SemidirectProductGroup, q) +function identity_element!(G::SemidirectProductGroup, q) M = base_manifold(G) N, H = M.manifolds nq, hq = submanifold_components(G, q) - identity!(N, nq) - identity!(H, hq) + identity_element!(N, nq) + identity_element!(H, hq) @inbounds _padpoint!(G, q) return q end @@ -89,7 +89,7 @@ function inv!(G::SemidirectProductGroup, q, p) end compose!(::SemidirectProductGroup, q, ::Identity, p) = copyto!(q, p) -compose!(G::SemidirectProductGroup, q, ::Identity, e::Identity) = identity!(G, q) +compose!(G::SemidirectProductGroup, q, ::Identity, e::Identity) = identity_element!(G, q) compose!(::SemidirectProductGroup, e::Identity, ::Identity, ::Identity) = e function compose!(G::SemidirectProductGroup, x, p, q) M = base_manifold(G) diff --git a/src/groups/special_linear.jl b/src/groups/special_linear.jl index 998cc6aa05..f53c23ecba 100644 --- a/src/groups/special_linear.jl +++ b/src/groups/special_linear.jl @@ -25,8 +25,8 @@ function allocation_promotion_function(::SpecialLinear{n,ℂ}, f, args::Tuple) w return complex end -function identity!(::SpecialLinear, q) where {n,𝔽} - return copyto!(q, one(q)) +function identity_element!(::SpecialLinear, q) where {n,𝔽} + return copyto!(q, I) end function check_point(G::SpecialLinear{n,𝔽}, p; kwargs...) where {n,𝔽} diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index 1b2de37fe2..396f66c951 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -17,7 +17,7 @@ function default_metric_dispatch( end default_metric_dispatch(::SpecialOrthogonal, ::EuclideanMetric) = Val(true) -identity!(::SpecialOrthogonal, q) = copyto!(q, one(q)) +identity_element!(::SpecialOrthogonal, q) = copyto!(q, one(q)) SpecialOrthogonal(n) = SpecialOrthogonal{n}(Rotations(n), MultiplicationOperation()) diff --git a/src/groups/translation_group.jl b/src/groups/translation_group.jl index 55b20399ef..bc60a2612d 100644 --- a/src/groups/translation_group.jl +++ b/src/groups/translation_group.jl @@ -18,7 +18,7 @@ function TranslationGroup(n::Int...; field::AbstractNumbers=ℝ) ) end -identity!(::TranslationGroup, p) = fill!(p, 0) +identity_element!(::TranslationGroup, p) = fill!(p, 0) invariant_metric_dispatch(::TranslationGroup, ::ActionDirection) = Val(true) diff --git a/test/groups/circle_group.jl b/test/groups/circle_group.jl index 1c91cf7b8b..7333492d13 100644 --- a/test/groups/circle_group.jl +++ b/test/groups/circle_group.jl @@ -22,8 +22,6 @@ using Manifolds: invariant_metric_dispatch, default_metric_dispatch @testset "identity overloads" begin ig = Identity(G) @test inv(G, ig) === ig - @test allocate_result(G, get_coordinates, ig, Complex(1.0), DefaultBasis()) isa - Array{Complex{Float64},1} y = [1.0 * im] v = [Complex(0.5)] @test translate_diff(G, ig, y, v) === v diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 5589cba9ac..5875b66178 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -20,7 +20,7 @@ include("group_utils.jl") @test is_point(G, eg) # identity transparent p = similar(x) copyto!(p, eg) - @test p == identity(G) + @test p == identity_element(G) @test isapprox(G, eg, p) @test isapprox(G, p, eg) @test isapprox(G, eg, eg) diff --git a/test/groups/metric.jl b/test/groups/metric.jl index 56dee8c188..f435a670f0 100644 --- a/test/groups/metric.jl +++ b/test/groups/metric.jl @@ -122,7 +122,7 @@ invariant_metric_dispatch(::TestDefaultInvariantMetricManifold, ::RightAction) = @testset "log/exp bi-invariant" begin SO3 = SpecialOrthogonal(3) e = Identity(SO3) - pe = identity(SO3) + pe = identity_element(SO3) p = exp(hat(SO3, pe, [1.0, 2.0, 3.0])) q = exp(hat(SO3, pe, [3.0, 4.0, 1.0])) X = hat(SO3, e, [2.0, 3.0, 4.0]) diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index 97b853945b..9cc4368bcd 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -28,7 +28,7 @@ include("group_utils.jl") vpts = [hat(M, x, [-1.0, 2.0, 0.5]), hat(M, x, [1.0, 0.0, 0.5])] ge = allocate(pts[1]) - identity!(G, de) + identity_element!(G, de) @test isapprox(ge, I; atol=1e-10) gI = Identity(G) @@ -133,7 +133,7 @@ include("group_utils.jl") X = vpts[1] pe = Identity(G) - Xⁱ = vee(G, identity(G), X) + Xⁱ = vee(G, identity_element(G), X) @test Xⁱ ≈ vee(G, pe, X) X2 = hat(G, pts[1], Xⁱ) diff --git a/test/groups/validation_group.jl b/test/groups/validation_group.jl index 49ecd57be6..f9b9789666 100644 --- a/test/groups/validation_group.jl +++ b/test/groups/validation_group.jl @@ -21,7 +21,7 @@ include("../utils.jl") @test Identity(G) isa Identity eg = allocate(p2) - identity!(G, eg) + identity_element!(G, eg) @test isapprox(G, eg, Identity(G)) eg = allocate(p2) diff --git a/test/utils.jl b/test/utils.jl index 41fe424cbe..5ebe93579e 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -25,8 +25,8 @@ function include_test(path) @time include(path) # show basic timing, (this will print a newline at end) end -function our_base_ambiguities() - ambigs = Test.detect_ambiguities(Base) +function our_ambiguities(m=Base) + ambigs = Test.detect_ambiguities(m) modules_we_care_about = [Base, LinearAlgebra, Manifolds, ManifoldsBase, StaticArrays, Statistics, StatsBase] our_ambigs = filter(ambigs) do (m1, m2) From 7a2d769e0eb5e273d44c746cc1c477cd4c7a4cc8 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 26 Jul 2021 15:30:24 +0200 Subject: [PATCH 15/88] export adapted to new names. --- src/Manifolds.jl | 4 ++-- src/groups/special_orthogonal.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Manifolds.jl b/src/Manifolds.jl index a4dca76e43..4d2e0eb32c 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -596,8 +596,8 @@ export adjoint_action, group_log!, has_biinvariant_metric, has_invariant_metric, - identity, - identity!, + identity_element, + identity_element!, inv, inv!, invariant_metric_dispatch, diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index 396f66c951..540dc5cdce 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -43,7 +43,7 @@ function inverse_translate_diff!(G::SpecialOrthogonal, Y, p, q, X, conv::ActionD return copyto!(Y, inverse_translate_diff(G, p, q, X, conv)) end -group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, Identity(G).p, X) +group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, Identity(G), X) group_log!(G::SpecialOrthogonal, X, q) = log!(G, X, Identity(G), q) function group_log!(G::SpecialOrthogonal, X::AbstractMatrix, q::AbstractMatrix) From ece25db6b7a8201f216b697d9b01b4da941fadfd Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Mon, 26 Jul 2021 18:56:24 +0200 Subject: [PATCH 16/88] a bunch of improvements --- src/groups/circle_group.jl | 7 +- src/groups/group.jl | 141 +++++++++++++++++-------- src/groups/product_group.jl | 34 ++++-- src/groups/semidirect_product_group.jl | 12 ++- src/groups/special_euclidean.jl | 6 +- src/groups/special_orthogonal.jl | 12 ++- src/tests/tests_group.jl | 14 ++- test/groups/special_orthogonal.jl | 2 +- 8 files changed, 146 insertions(+), 82 deletions(-) diff --git a/src/groups/circle_group.jl b/src/groups/circle_group.jl index 15e1234391..650b07b02e 100644 --- a/src/groups/circle_group.jl +++ b/src/groups/circle_group.jl @@ -18,14 +18,11 @@ adjoint_action(::CircleGroup, p, X) = X adjoint_action!(::CircleGroup, Y, p, X) = copyto!(Y, X) -function compose(G::CircleGroup, p::AbstractVector, q::AbstractVector) +function _compose(G::CircleGroup, p::AbstractVector, q::AbstractVector) return map(compose, repeated(G), p, q) end -compose!(G::CircleGroup, x, p, q) = copyto!(x, compose(G, p, q)) -compose!(G::CircleGroup, x, p, ::Identity) = copyto!(x, p) -compose!(G::CircleGroup, x, ::Identity, p) = copyto!(x, p) -compose!(G::CircleGroup, e::Identity, ::Identity, ::Identity) = e +_compose!(G::CircleGroup, x, p, q) = copyto!(x, compose(G, p, q)) identity_element(G::CircleGroup) = 1.0 identity_element(::CircleGroup, p::Number) = one(p) diff --git a/src/groups/group.jl b/src/groups/group.jl index 4fe4ad8c4b..39362710d0 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -10,8 +10,8 @@ number system `𝔽` or in general, by defining for an operation `Op` the follow inv!(::AbstractGroupManifold{𝔽,Op}, q, p) inv(::AbstractGroupManifold{𝔽,Op}, p) - compose(::AbstractGroupManifold{𝔽,Op}, p, q) - compose!(::AbstractGroupManifold{𝔽,Op}, x, p, q) + _compose(::AbstractGroupManifold{𝔽,Op}, p, q) + _compose!(::AbstractGroupManifold{𝔽,Op}, x, p, q) Note that a manifold is connected with an operation by wrapping it with a decorator, [`AbstractGroupManifold`](@ref). In typical cases the concrete wrapper @@ -236,10 +236,6 @@ the [`Identity`](@ref)`{O}` with the corresponding [`AbstractGroupOperation`](@r """ is_identity(G::AbstractGroupManifold, q) -function is_identity(G::AbstractGroupManifold, q; kwargs...) - return isapprox(G, q, identity_element(G, q); kwargs...) -end - function is_identity( ::AbstractGroupManifold{𝔽,M,O}, ::Identity{O}; @@ -345,20 +341,78 @@ Base.one(e::Identity) = e @doc raw""" compose(G::AbstractGroupManifold, p, q) -Compose elements $p,q ∈ \mathcal{G}$ using the group operation $p \circ q$. +Compose elements ``p,q ∈ \mathcal{G}`` using the group operation ``p \circ q``. + +For implementing composition on a new group manifold, please overload [`_compose`](@ref) +instead so that methods with [`Identity`] arguments are not ambiguous. """ compose(::AbstractGroupManifold, ::Any...) -@decorator_transparent_function function compose(G::AbstractGroupManifold, p, q) + +function compose(G::AbstractGroupManifold{𝔽,Op}, p, q) where {𝔽,Op<:AbstractGroupOperation} + return _compose(G, p, q) +end +function compose( + ::AbstractGroupManifold{𝔽,Op}, + ::Identity{Op}, + p, +) where {𝔽,Op<:AbstractGroupOperation} + return p +end +function compose( + ::AbstractGroupManifold{𝔽,Op}, + p, + ::Identity{Op}, +) where {𝔽,Op<:AbstractGroupOperation} + return p +end +function compose( + ::AbstractGroupManifold{𝔽,Op}, + e::Identity{Op}, + ::Identity{Op}, +) where {𝔽,Op<:AbstractGroupOperation} + return e +end + +@decorator_transparent_function function _compose(G::AbstractGroupManifold, p, q) x = allocate_result(G, compose, p, q) - return compose!(G, x, p, q) + return _compose!(G, x, p, q) end @decorator_transparent_signature compose!(M::AbstractDecoratorManifold, x, p, q) -compose!(::AbstractGroupManifold, q, p, ::Identity) = copyto!(q, p) -compose!(::AbstractGroupManifold, q, ::Identity, p) = copyto!(q, p) -compose!(G::AbstractGroupManifold, q, ::Identity, e::Identity) = identity_element!(G, q) -compose!(::AbstractGroupManifold, e::Identity, ::Identity, ::Identity) = e +compose!(G::AbstractGroupManifold, x, q, p) = _compose!(G, x, q, p) +function compose!( + ::AbstractGroupManifold{𝔽,Op}, + q, + p, + ::Identity{Op}, +) where {𝔽,Op<:AbstractGroupOperation} + return copyto!(q, p) +end +function compose!( + ::AbstractGroupManifold{𝔽,Op}, + q, + ::Identity{Op}, + p, +) where {𝔽,Op<:AbstractGroupOperation} + return copyto!(q, p) +end +function compose!( + G::AbstractGroupManifold{𝔽,Op}, + q, + ::Identity{Op}, + e::Identity{Op}, +) where {𝔽,Op<:AbstractGroupOperation} + return identity_element!(G, q) +end +function compose!( + ::AbstractGroupManifold{𝔽,Op}, + e::Identity{Op}, + ::Identity{Op}, + ::Identity{Op}, +) where {𝔽,Op<:AbstractGroupOperation} + return e +end """ lie_bracket(G::AbstractGroupManifold, X, Y) @@ -803,6 +857,10 @@ Base.:-(e::Identity{AdditionOperation}, ::Identity{AdditionOperation}) = e Base.:-(::Identity{AdditionOperation}, p) = -p Base.:-(p, ::Identity{AdditionOperation}) = p +Base.:*(e::Identity{AdditionOperation}, p) = e +Base.:*(p, e::Identity{AdditionOperation}) = e +Base.:*(e::Identity{AdditionOperation}, ::Identity{AdditionOperation}) = e + adjoint_action(::AdditionGroup, p, X) = X adjoint_action!(::AdditionGroup, Y, p, X) = copyto!(Y, X) @@ -818,23 +876,13 @@ inv!(::AdditionGroup, q, p) = copyto!(q, -p) inv!(G::AdditionGroup, q, ::Identity) = identity_element!(G, q) inv!(::AdditionGroup, q::Identity, e::Identity) = q -compose(::AdditionGroup, p, q) = p + q -compose(::AdditionGroup, p, ::Identity{AdditionOperation}) = p -compose(::AdditionGroup, ::Identity{AdditionOperation}, q) = q -compose(::AdditionGroup, e::Identity{AdditionOperation}, ::Identity{AdditionOperation}) = e - -compose!(::AdditionGroup, x, p, ::Identity{AdditionOperation}) = copyto!(x, p) -compose!(::AdditionGroup, x, ::Identity{AdditionOperation}, q) = copyto!(x, q) -function compose!( - G::AdditionGroup, - x, - ::Identity{AdditionOperation}, - q::Identity{AdditionOperation}, -) - return identity_element!(G, x) +function is_identity(G::AdditionGroup, q; kwargs...) + return isapprox(G, q, zero(q); kwargs...) end -compose!(::AdditionGroup, x::Identity, ::Identity, ::Identity) = x -function compose!(::AdditionGroup, x, p, q) + +_compose(::AdditionGroup, p, q) = p + q + +function _compose!(::AdditionGroup, x, p, q) x .= p .+ q return x end @@ -879,6 +927,8 @@ Base.:*(e::Identity{MultiplicationOperation}) = e Base.:*(::Identity{MultiplicationOperation}, p) = p Base.:*(p, ::Identity{MultiplicationOperation}) = p Base.:*(e::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation}) = e +Base.:*(::Identity{MultiplicationOperation}, e::Identity{AdditionOperation}) = e +Base.:*(e::Identity{AdditionOperation}, ::Identity{MultiplicationOperation}) = e Base.:/(p, ::Identity{MultiplicationOperation}) = p Base.:/(::Identity{MultiplicationOperation}, p) = inv(p) @@ -894,6 +944,16 @@ function identity_element!(::MultiplicationGroup, p) return copyto!(p, I) end +function is_identity(G::MultiplicationGroup, q::Number; kwargs...) + return isapprox(G, q, one(q); kwargs...) +end +function is_identity(G::MultiplicationGroup, q::AbstractVector; kwargs...) + return length(q) == 1 && isapprox(G, q[], one(q[]); kwargs...) +end +function is_identity(G::MultiplicationGroup, q::AbstractMatrix; kwargs...) + return isapprox(G, q, I; kwargs...) +end + LinearAlgebra.mul!(q, ::Identity{MultiplicationOperation}, p) = copyto!(q, p) LinearAlgebra.mul!(q, p, ::Identity{MultiplicationOperation}) = copyto!(q, p) function LinearAlgebra.mul!( @@ -912,27 +972,16 @@ function LinearAlgebra.mul!( end Base.inv(::MultiplicationGroup, p) = inv(p) -Base.inv(::MultiplicationGroup, e::Identity) = e +Base.inv(::MultiplicationGroup, e::Identity{MultiplicationOperation}) = e inv!(G::MultiplicationGroup, q, p) = copyto!(q, inv(G, p)) -inv!(G::MultiplicationGroup, q, ::Identity) = identity_element!(G, q) - -compose(::MultiplicationGroup, p, q) = p * q -compose(::MultiplicationGroup, p, ::Identity{MultiplicationOperation}) = p -compose(::MultiplicationGroup, ::Identity{MultiplicationOperation}, q) = q -function compose( - ::MultiplicationGroup, - e::Identity{MultiplicationOperation}, - ::Identity{MultiplicationOperation}, -) - return e +function inv!(G::MultiplicationGroup, q, ::Identity{MultiplicationOperation}) + return identity_element!(G, q) end -compose!(::MultiplicationGroup, x, p, q) = mul!_safe(x, p, q) -compose!(::MultiplicationGroup, q, p, ::Identity) = copyto!(q, p) -compose!(::MultiplicationGroup, q, ::Identity, p) = copyto!(q, p) -compose!(G::MultiplicationGroup, q, ::Identity, e::Identity) = identity_element!(G, q) -compose!(::MultiplicationGroup, e::Identity, ::Identity, ::Identity) = e +_compose(::MultiplicationGroup, p, q) = p * q + +_compose!(::MultiplicationGroup, x, p, q) = mul!_safe(x, p, q) inverse_translate(::MultiplicationGroup, p, q, ::LeftAction) = p \ q inverse_translate(::MultiplicationGroup, p, q, ::RightAction) = q / p diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 6df518c3cc..9b4750adc1 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -34,6 +34,20 @@ function decorator_transparent_dispatch(::typeof(group_log!), M::ProductGroup, X return Val(:transparent) end +function identity_element(G::ProductGroup) + return ProductRepr(map(identity_element, G.manifolds)) +end +function identity_element!(G::ProductGroup, p) + pes = submanifold_components(G, p) + map(identity_element!, G.manifolds, pes) + return p +end + +function is_identity(G::ProductGroup, p; kwargs...) + pes = submanifold_components(G, p) + return all(map((M, pe) -> is_identity(M, pe; kwargs...), G.manifolds, pes)) +end + function Base.show(io::IO, ::MIME"text/plain", G::ProductGroup) print( io, @@ -50,20 +64,20 @@ end submanifold(G::ProductGroup, i) = submanifold(base_manifold(G), i) function submanifold_component( - ::GroupManifold{𝔽,MT,O}, - ::Identity, + G::GroupManifold{𝔽,MT,O}, + ::Identity{O}, ::Val{I}, ) where {I,MT<:ProductManifold,𝔽,O} # the identity on a product manifold with is a group consists of a tuple of identities - return Identity{O}() + return Identity(G.manifolds[I]) end function submanifold_components( G::GroupManifold{𝔽,MT,O}, - e::Identity, + ::Identity{O}, ) where {MT<:ProductManifold,𝔽,O<:AbstractGroupOperation} M = base_manifold(G) - return [Identity(O) for N in M.manifolds] + return map(N -> Identity(N), M.manifolds) end function Base.inv(M::ProductManifold, x::ProductRepr) return ProductRepr(map(inv, M.manifolds, submanifold_components(M, x))...) @@ -79,8 +93,8 @@ function inv!(M::ProductManifold, q, p) return q end -compose(G::ProductGroup, p, q) = compose(G.manifold, p, q) -function compose(M::ProductManifold, p::ProductRepr, q::ProductRepr) +_compose(G::ProductGroup, p, q) = _compose(G.manifold, p, q) +function _compose(M::ProductManifold, p::ProductRepr, q::ProductRepr) return ProductRepr( map( compose, @@ -90,13 +104,13 @@ function compose(M::ProductManifold, p::ProductRepr, q::ProductRepr) )..., ) end -function compose(M::ProductManifold, p, q) +function _compose(M::ProductManifold, p, q) x = allocate_result(M, compose, p, q) return compose!(M, x, p, q) end -compose!(G::ProductGroup, x, p, q) = compose!(G.manifold, x, p, q) -function compose!(M::ProductManifold, x, p, q) +_compose!(G::ProductGroup, x, p, q) = compose!(G.manifold, x, p, q) +function _compose!(M::ProductManifold, x, p, q) map( compose!, M.manifolds, diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index f2f69e27ee..ff0e03b958 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -62,6 +62,13 @@ function identity_element!(G::SemidirectProductGroup, q) return q end +function is_identity(G::SemidirectProductGroup, p; kwargs...) + M = base_manifold(G) + N, H = M.manifolds + nq, hq = submanifold_components(G, p) + return is_identity(N, nq; kwargs...) && is_identity(H, hq; kwargs...) +end + function Base.show(io::IO, G::SemidirectProductGroup) M = base_manifold(G) N, H = M.manifolds @@ -88,10 +95,7 @@ function inv!(G::SemidirectProductGroup, q, p) return q end -compose!(::SemidirectProductGroup, q, ::Identity, p) = copyto!(q, p) -compose!(G::SemidirectProductGroup, q, ::Identity, e::Identity) = identity_element!(G, q) -compose!(::SemidirectProductGroup, e::Identity, ::Identity, ::Identity) = e -function compose!(G::SemidirectProductGroup, x, p, q) +function _compose!(G::SemidirectProductGroup, x, p, q) M = base_manifold(G) N, H = M.manifolds A = G.op.action diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index bd3ae6cbcb..a0b35273db 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -176,9 +176,9 @@ function allocate_result(::SpecialEuclidean{n}, f::typeof(screw_matrix), X...) w return allocate(X[1], Size(n + 1, n + 1)) end -compose(::SpecialEuclidean, p::AbstractMatrix, q::AbstractMatrix) = p * q +_compose(::SpecialEuclidean, p::AbstractMatrix, q::AbstractMatrix) = p * q -function compose!( +function _compose!( ::SpecialEuclidean, x::AbstractMatrix, p::AbstractMatrix, @@ -258,7 +258,7 @@ function group_exp!(G::SpecialEuclidean{2}, q, X) @assert size(t) == (2,) @assert size(b) == (2,) - θ = vee(SO2, Identity(SO2), Ω)[1] + θ = vee(SO2, identity_element(SO2, R), Ω)[1] sinθ, cosθ = sincos(θ) if θ ≈ 0 α = 1 - θ^2 / 6 diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index 540dc5cdce..20df79dee4 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -17,13 +17,12 @@ function default_metric_dispatch( end default_metric_dispatch(::SpecialOrthogonal, ::EuclideanMetric) = Val(true) -identity_element!(::SpecialOrthogonal, q) = copyto!(q, one(q)) - SpecialOrthogonal(n) = SpecialOrthogonal{n}(Rotations(n), MultiplicationOperation()) Base.show(io::IO, ::SpecialOrthogonal{n}) where {n} = print(io, "SpecialOrthogonal($(n))") Base.inv(::SpecialOrthogonal, p) = transpose(p) +Base.inv(::SpecialOrthogonal, e::Identity{MultiplicationOperation}) = e inverse_translate(G::SpecialOrthogonal, p, q, ::LeftAction) = inv(G, p) * q inverse_translate(G::SpecialOrthogonal, p, q, ::RightAction) = q * inv(G, p) @@ -43,11 +42,14 @@ function inverse_translate_diff!(G::SpecialOrthogonal, Y, p, q, X, conv::ActionD return copyto!(Y, inverse_translate_diff(G, p, q, X, conv)) end -group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, Identity(G), X) +group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, identity_element(G, q), X) -group_log!(G::SpecialOrthogonal, X, q) = log!(G, X, Identity(G), q) +group_log!(G::SpecialOrthogonal, X, q) = log!(G, X, identity_element(G, q), q) function group_log!(G::SpecialOrthogonal, X::AbstractMatrix, q::AbstractMatrix) - return log!(G, X, Identity(G), q) + return log!(G, X, identity_element(G, q), q) +end +function group_log!(::SpecialOrthogonal, X, ::Identity{MultiplicationOperation}) + return fill!(X, zero(eltype(X))) end function allocate_result( diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index c347745e60..ba1aec6f95 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -99,22 +99,20 @@ function test_group( Test.@testset "Inverse" begin for g in g_pts ginv = inv(G, g) - Test.@test isapprox(G, compose(G, g, ginv), e; atol=atol) - Test.@test isapprox(G, compose(G, ginv, g), e; atol=atol) - Test.@test isapprox(G, e, compose(G, g, ginv); atol=atol) - Test.@test isapprox(G, e, compose(G, ginv, g); atol=atol) + Test.@test is_identity(G, compose(G, g, ginv); atol=atol) + Test.@test is_identity(G, compose(G, ginv, g); atol=atol) Test.@test inv(G, e) === e test_mutating && Test.@testset "mutating" begin ginv = allocate(g) Test.@test inv!(G, ginv, g) === ginv - Test.@test isapprox(G, compose(G, g, ginv), e; atol=atol) - Test.@test isapprox(G, compose(G, ginv, g), e; atol=atol) + Test.@test is_identity(G, compose(G, g, ginv); atol=atol) + Test.@test is_identity(G, compose(G, ginv, g); atol=atol) Test.@test inv(G, e) === e geinv = allocate(g) Test.@test inv!(G, geinv, e) === geinv - Test.@test isapprox(G, geinv, e; atol=atol) + Test.@test is_identity(G, geinv; atol=atol) end end end @@ -295,7 +293,7 @@ function test_group( Test.@test group_log!(G, X, Identity(G)) === X g = allocate(g_pts[1]) Test.@test group_exp!(G, g, X) === g - Test.@test isapprox(G, Identity(G), g; atol=atol) + Test.@test is_identity(G, g; atol=atol) end end diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index 9cc4368bcd..cee5df26ce 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -28,7 +28,7 @@ include("group_utils.jl") vpts = [hat(M, x, [-1.0, 2.0, 0.5]), hat(M, x, [1.0, 0.0, 0.5])] ge = allocate(pts[1]) - identity_element!(G, de) + identity_element!(G, ge) @test isapprox(ge, I; atol=1e-10) gI = Identity(G) From 6c10e554fbb07c3edc70f98d67b6f1c502214dfe Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 27 Jul 2021 19:23:09 +0200 Subject: [PATCH 17/88] Trying to fix things made more things error :/ and we have a problem with mul! which seems to have to know about the group its on. --- src/Manifolds.jl | 4 ++-- src/groups/group.jl | 17 +++++++++-------- src/tests/tests_group.jl | 2 +- test/groups/groups_general.jl | 21 ++++++++++----------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 4d2e0eb32c..8e32642d96 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -476,8 +476,8 @@ export ×, get_embedding, hat, hat!, - identity, - identity!, + identity_element, + identity_element!, induced_basis, incident_log, injectivity_radius, diff --git a/src/groups/group.jl b/src/groups/group.jl index 39362710d0..abf4898934 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -237,20 +237,18 @@ the [`Identity`](@ref)`{O}` with the corresponding [`AbstractGroupOperation`](@r is_identity(G::AbstractGroupManifold, q) function is_identity( - ::AbstractGroupManifold{𝔽,M,O}, + ::AbstractGroupManifold{𝔽,O}, ::Identity{O}; kwargs..., -) where {𝔽,M,O<:AbstractGroupOperation} +) where {𝔽,O<:AbstractGroupOperation} return true end is_identity(::AbstractGroupManifold, ::Identity; kwargs...) = false Base.show(io::IO, ::Identity{O}) where {O} = print(io, "Identity($O)") -Base.copyto!(e::Identity{O}, ::Identity{O}) where {O} = e - function check_point( - G::AbstractGroupManifold{𝔽,M,O}, + G::AbstractGroupManifold{𝔽,O}, e::Identity{O}; kwargs..., ) where {𝔽,M,O} @@ -258,7 +256,7 @@ function check_point( end function check_point( - G::AbstractGroupManifold{𝔽,M,O1}, + G::AbstractGroupManifold{𝔽,O1}, e::Identity{O2}; kwargs..., ) where {𝔽,M,O1,O2} @@ -338,6 +336,9 @@ Base.isapprox(::AbstractGroupManifold, ::Identity, ::Identity; kwargs...) = true Base.one(e::Identity) = e +Base.copyto!(::AbstractGroupManifold{𝔽,M,O}, e::Identity{O}, ::Identity{O}) where {𝔽,M,O} = e +Base.copyto!(G::AbstractGroupManifold{𝔽,M,O}, p, ::Identity{O}) where {𝔽,M,O} = identity_element!(G,p) + @doc raw""" compose(G::AbstractGroupManifold, p, q) @@ -958,10 +959,10 @@ LinearAlgebra.mul!(q, ::Identity{MultiplicationOperation}, p) = copyto!(q, p) LinearAlgebra.mul!(q, p, ::Identity{MultiplicationOperation}) = copyto!(q, p) function LinearAlgebra.mul!( q, - ::Identity{MultiplicationOperation}, + e::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation}, ) - return identity_element!(G, q) + return identity_element!(G,q) # Here we have a problem with mul, since we do not know G. end function LinearAlgebra.mul!( q::Identity{MultiplicationOperation}, diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index ba1aec6f95..d1010b5726 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -66,7 +66,7 @@ function test_group( Test.@testset "Identity" begin Test.@test isapprox(G, e, e) Test.@test compose(G, e, e) === e - Test.@test copyto!(e, e) === e + Test.@test copyto!(G, e, e) === e for g in g_pts Test.@test isapprox(G, compose(G, g, e), g) diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 5875b66178..d0868ae545 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -1,3 +1,4 @@ +using StaticArrays: identity_perm using Manifolds: decorator_transparent_dispatch using Base: decode_overlong @@ -17,9 +18,9 @@ include("group_utils.jl") eg = Identity(G) @test repr(eg) === "Identity(NotImplementedOperation)" @test number_eltype(eg) == Bool - @test is_point(G, eg) # identity transparent + @test is_identity(G, eg) # identity transparent p = similar(x) - copyto!(p, eg) + copyto!(G, p, e) @test p == identity_element(G) @test isapprox(G, eg, p) @test isapprox(G, p, eg) @@ -51,7 +52,7 @@ include("group_utils.jl") ) === Val{:intransparent}() @test base_group(G) === G z = similar(x) - copyto!(z, eg) + copyto!(G, z, eg) @test z == eg.p @test NotImplementedOperation(NotImplementedManifold()) === G @test (NotImplementedOperation())(NotImplementedManifold()) === G @@ -76,7 +77,7 @@ include("group_utils.jl") @test_throws ErrorException inv!(G, x, eg) @test_throws ErrorException inv(G, x) - @test copyto!(x, eg) === x + @test copyto!(G, x, eg) === x @test isapprox(G, x, eg) @test_throws ErrorException compose(G, x, x) @@ -156,7 +157,6 @@ include("group_utils.jl") G, Identity( GroupManifold(NotImplementedManifold(), NotImplementedOperation()), - [0.0, 0.0], ), true, ) @@ -165,9 +165,8 @@ include("group_utils.jl") v = [3.0, 4.0] ge = Identity(G) @test number_eltype(ge) == Bool - @test copyto!(ge, ge) === ge y = allocate(x) - copyto!(y, ge) + copyto!(G, y, ge) @test y ≈ zero(x) @test ge - x == -x @test x - ge === x @@ -213,7 +212,7 @@ include("group_utils.jl") @test number_eltype(ge) == Bool @test copyto!(ge, ge) === ge y = allocate(x) - copyto!(y, ge) + identity_element!(G, y) @test y ≈ one(x) @test one(ge) === ge @test transpose(ge) === ge @@ -221,15 +220,15 @@ include("group_utils.jl") @test ge * x ≈ x @test x * ge ≈ x @test ge * ge === ge - @test inv(ge) === ge + @test inv(G, ge) === ge @test *(ge) === ge @test x / ge ≈ x @test ge \ x ≈ x @test ge / ge === ge @test ge \ ge === ge - @test ge / x ≈ inv(x) - @test x \ ge ≈ inv(x) + @test ge / x ≈ inv(G, x) + @test x \ ge ≈ inv(G, x) y = allocate(x) @test LinearAlgebra.mul!(y, x, ge) === y @test y ≈ x From 85e931bc3ddeacb52c3554fddef7832c4c60cf16 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 27 Jul 2021 19:23:44 +0200 Subject: [PATCH 18/88] Forgot to run formatter. --- test/groups/groups_general.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index d0868ae545..fd8dd75bf1 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -155,9 +155,7 @@ include("group_utils.jl") @test_throws DomainError is_point( G, - Identity( - GroupManifold(NotImplementedManifold(), NotImplementedOperation()), - ), + Identity(GroupManifold(NotImplementedManifold(), NotImplementedOperation())), true, ) From 56ec32c9bfc9bee80cbfa369c8f31cb66af26108 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 27 Jul 2021 19:28:57 +0200 Subject: [PATCH 19/88] Runs formatter again after updating formatter locally... --- src/groups/group.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index abf4898934..a322092c07 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -336,8 +336,8 @@ Base.isapprox(::AbstractGroupManifold, ::Identity, ::Identity; kwargs...) = true Base.one(e::Identity) = e -Base.copyto!(::AbstractGroupManifold{𝔽,M,O}, e::Identity{O}, ::Identity{O}) where {𝔽,M,O} = e -Base.copyto!(G::AbstractGroupManifold{𝔽,M,O}, p, ::Identity{O}) where {𝔽,M,O} = identity_element!(G,p) +Base.copyto!(::AbstractGroupManifold{𝔽,O}, e::Identity{O}, ::Identity{O}) where {𝔽,O} = e +Base.copyto!(G::AbstractGroupManifold{𝔽,O}, p, ::Identity{O}) where {𝔽,O} = identity_element!(G,p) @doc raw""" compose(G::AbstractGroupManifold, p, q) From fdbc608178258011f2279bc451d0f79692c87eb3 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 27 Jul 2021 19:29:29 +0200 Subject: [PATCH 20/88] Runs formatter again, after I do not know what now changed. --- src/groups/group.jl | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index a322092c07..16c73090be 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -247,11 +247,7 @@ is_identity(::AbstractGroupManifold, ::Identity; kwargs...) = false Base.show(io::IO, ::Identity{O}) where {O} = print(io, "Identity($O)") -function check_point( - G::AbstractGroupManifold{𝔽,O}, - e::Identity{O}; - kwargs..., -) where {𝔽,M,O} +function check_point(G::AbstractGroupManifold{𝔽,O}, e::Identity{O}; kwargs...) where {𝔽,M,O} return nothing end @@ -337,7 +333,9 @@ Base.isapprox(::AbstractGroupManifold, ::Identity, ::Identity; kwargs...) = true Base.one(e::Identity) = e Base.copyto!(::AbstractGroupManifold{𝔽,O}, e::Identity{O}, ::Identity{O}) where {𝔽,O} = e -Base.copyto!(G::AbstractGroupManifold{𝔽,O}, p, ::Identity{O}) where {𝔽,O} = identity_element!(G,p) +function Base.copyto!(G::AbstractGroupManifold{𝔽,O}, p, ::Identity{O}) where {𝔽,O} + return identity_element!(G, p) +end @doc raw""" compose(G::AbstractGroupManifold, p, q) @@ -962,7 +960,7 @@ function LinearAlgebra.mul!( e::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation}, ) - return identity_element!(G,q) # Here we have a problem with mul, since we do not know G. + return identity_element!(G, q) # Here we have a problem with mul, since we do not know G. end function LinearAlgebra.mul!( q::Identity{MultiplicationOperation}, From 431f71ecb7f044b8e0613356d59274101df46540 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 27 Jul 2021 21:57:31 +0200 Subject: [PATCH 21/88] fixes mul! --- src/groups/group.jl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index 16c73090be..0de24d22cb 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -956,11 +956,18 @@ end LinearAlgebra.mul!(q, ::Identity{MultiplicationOperation}, p) = copyto!(q, p) LinearAlgebra.mul!(q, p, ::Identity{MultiplicationOperation}) = copyto!(q, p) function LinearAlgebra.mul!( - q, - e::Identity{MultiplicationOperation}, + q::AbstractMatrix, + ::Identity{MultiplicationOperation}, + ::Identity{MultiplicationOperation}, +) + return copyto!(q, I) +end +function LinearAlgebra.mul!( + q::Number, + ::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation}, ) - return identity_element!(G, q) # Here we have a problem with mul, since we do not know G. + return copyto!(q, one(eltype(q))) end function LinearAlgebra.mul!( q::Identity{MultiplicationOperation}, From adc304bec85517ea361cea1ac3da036ce1895202 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 28 Jul 2021 11:08:32 +0200 Subject: [PATCH 22/88] Fixes a few tests. --- src/groups/group.jl | 18 +++++++++++++----- src/groups/semidirect_product_group.jl | 17 +++++++++++++++++ test/groups/groups_general.jl | 9 ++------- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index 0de24d22cb..f5004319ef 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -74,8 +74,8 @@ end Base.show(io::IO, G::GroupManifold) = print(io, "GroupManifold($(G.manifold), $(G.op))") -Base.copyto!(M::GroupManifold, q, p) = copyto!(M.manifold, q, p) -Base.copyto!(M::GroupManifold, Y, p, X) = copyto!(M.manifold, Y, p, X) +Base.copyto!(G::GroupManifold{𝔽,M,O}, q, p) where {𝔽,M,O}= copyto!(G.manifold, q, p) +Base.copyto!(G::GroupManifold{𝔽,M,O}, Y, p, X) where {𝔽,M,O} = copyto!(G.manifold, Y, p, X) const GROUP_MANIFOLD_BASIS_DISAMBIGUATION = [AbstractDecoratorManifold, ValidationManifold, VectorBundle] @@ -204,10 +204,12 @@ by default this representation is default array representation. It should return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if points are not represented by arrays. """ function identity_element(G::AbstractGroupManifold) - q = zeros(representation_size(G)...) + q = allocate_result(G, identity_element) return identity_element!(G, q) end +allocate_result(G::AbstractGroupManifold, ::typeof(identity_element)) = zeros(representation_size(G)...) + @doc raw""" identity_element(G::AbstractGroupManifold, p) @@ -258,10 +260,15 @@ function check_point( ) where {𝔽,M,O1,O2} return DomainError( e, - "The Identity $e does not lie on $M, since its the identity with respect to $O2 and not $O1.", + "The Identity $e does not lie on $G, since its the identity with respect to $O2 and not $O1.", ) end +Base.copyto!(::GroupManifold{𝔽,M,O}, e::Identity{O}, ::Identity{O}) where {𝔽,M,O} = e +function Base.copyto!(G::GroupManifold{𝔽,M,O}, p, ::Identity{O}) where {𝔽,M,O} + return identity_element!(G, p) +end + ########################## # Group-specific functions ########################## @@ -901,9 +908,10 @@ group_exp(::AdditionGroup, X) = X group_exp!(::AdditionGroup, q, X) = copyto!(q, X) group_log(::AdditionGroup, q) = q +group_log(G::AdditionGroup, ::Identity{AdditionOperation}) = zero_vector(G, identity_element(G)) group_log!(::AdditionGroup, X, q) = copyto!(X, q) -group_log!(::AdditionGroup, X, e::Identity{AdditionOperation}) = X +group_log!(G::AdditionGroup, X, ::Identity{AdditionOperation}) = zero_vector!(G,X, identity_element(G)) lie_bracket(::AdditionGroup, X, Y) = zero(X) diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index ff0e03b958..7d215b02d8 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -52,6 +52,15 @@ function SemidirectProductGroup( return GroupManifold(M, op) end +function allocate_result(G::SemidirectProductGroup, ::typeof(identity_element)) + M = base_manifold(G) + N, H = M.manifolds + np = allocate_result(N, identity_element) + hp = allocate_result(H, identity_element) + reshaper = ShapeSpecification(StaticReshaper(), M.manifolds...) + return prod_point(reshaper, np,hp) +end + function identity_element!(G::SemidirectProductGroup, q) M = base_manifold(G) N, H = M.manifolds @@ -194,6 +203,14 @@ function Base.isapprox(G::SemidirectProductGroup, p, q; kwargs...) nq, hq = submanifold_components(G, q) return isapprox(N, np, nq; kwargs...) && isapprox(H, hp, hq; kwargs...) end +function Base.isapprox(G::SemidirectProductGroup, e::Identity, p; kwargs...) + return isapprox(G, identity_element(G, p), p; kwargs...) +end +function Base.isapprox(G::SemidirectProductGroup, p, e::Identity; kwargs...) + return isapprox(G, e, p; kwargs...) +end +Base.isapprox(::SemidirectProductGroup, ::Identity, ::Identity; kwargs...) = true + function Base.isapprox(G::SemidirectProductGroup, p, X, Y; kwargs...) M = base_manifold(G) N, H = M.manifolds diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index fd8dd75bf1..7213817630 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -19,11 +19,7 @@ include("group_utils.jl") @test repr(eg) === "Identity(NotImplementedOperation)" @test number_eltype(eg) == Bool @test is_identity(G, eg) # identity transparent - p = similar(x) - copyto!(G, p, e) - @test p == identity_element(G) - @test isapprox(G, eg, p) - @test isapprox(G, p, eg) + @test_throws MethodError identity_element(G) # but for a NotImplOp there is no concrete id. @test isapprox(G, eg, eg) @test length(methods(is_group_decorator)) == 1 @@ -177,8 +173,7 @@ include("group_utils.jl") @test ge * 1 === ge @test 1 * ge === ge @test ge * ge === ge - @test ge.p ≈ zero(x) - @test zero(ge) == ge + @test identity_element(G) ≈ zero(x) @test inv(G, x) ≈ -x @test inv(G, ge) === ge @test compose(G, x, x) ≈ x + x From f7495ceea9752a6c69d7136ec767789d2b32b449 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 28 Jul 2021 11:11:20 +0200 Subject: [PATCH 23/88] Formatter -.- ... --- src/groups/group.jl | 14 ++++++++++---- src/groups/semidirect_product_group.jl | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index f5004319ef..5569beb92a 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -74,7 +74,7 @@ end Base.show(io::IO, G::GroupManifold) = print(io, "GroupManifold($(G.manifold), $(G.op))") -Base.copyto!(G::GroupManifold{𝔽,M,O}, q, p) where {𝔽,M,O}= copyto!(G.manifold, q, p) +Base.copyto!(G::GroupManifold{𝔽,M,O}, q, p) where {𝔽,M,O} = copyto!(G.manifold, q, p) Base.copyto!(G::GroupManifold{𝔽,M,O}, Y, p, X) where {𝔽,M,O} = copyto!(G.manifold, Y, p, X) const GROUP_MANIFOLD_BASIS_DISAMBIGUATION = @@ -208,7 +208,9 @@ function identity_element(G::AbstractGroupManifold) return identity_element!(G, q) end -allocate_result(G::AbstractGroupManifold, ::typeof(identity_element)) = zeros(representation_size(G)...) +function allocate_result(G::AbstractGroupManifold, ::typeof(identity_element)) + return zeros(representation_size(G)...) +end @doc raw""" identity_element(G::AbstractGroupManifold, p) @@ -908,10 +910,14 @@ group_exp(::AdditionGroup, X) = X group_exp!(::AdditionGroup, q, X) = copyto!(q, X) group_log(::AdditionGroup, q) = q -group_log(G::AdditionGroup, ::Identity{AdditionOperation}) = zero_vector(G, identity_element(G)) +function group_log(G::AdditionGroup, ::Identity{AdditionOperation}) + return zero_vector(G, identity_element(G)) +end group_log!(::AdditionGroup, X, q) = copyto!(X, q) -group_log!(G::AdditionGroup, X, ::Identity{AdditionOperation}) = zero_vector!(G,X, identity_element(G)) +function group_log!(G::AdditionGroup, X, ::Identity{AdditionOperation}) + return zero_vector!(G, X, identity_element(G)) +end lie_bracket(::AdditionGroup, X, Y) = zero(X) diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index 7d215b02d8..c053c0a10c 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -58,7 +58,7 @@ function allocate_result(G::SemidirectProductGroup, ::typeof(identity_element)) np = allocate_result(N, identity_element) hp = allocate_result(H, identity_element) reshaper = ShapeSpecification(StaticReshaper(), M.manifolds...) - return prod_point(reshaper, np,hp) + return prod_point(reshaper, np, hp) end function identity_element!(G::SemidirectProductGroup, q) From cf0988ada5ddb820017e39041ec481a461ca503c Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 28 Jul 2021 11:42:11 +0200 Subject: [PATCH 24/88] rename group_exp/log to log/exp_lie --- src/Manifolds.jl | 8 +-- src/groups/circle_group.jl | 10 ++-- src/groups/connections.jl | 8 +-- src/groups/general_linear.jl | 6 +-- src/groups/group.jl | 84 ++++++++++++++++---------------- src/groups/product_group.jl | 32 ++++++------ src/groups/special_euclidean.jl | 42 ++++++++-------- src/groups/special_orthogonal.jl | 8 +-- src/groups/validation_group.jl | 16 +++--- src/tests/tests_group.jl | 36 +++++++------- test/groups/general_linear.jl | 8 +-- test/groups/groups_general.jl | 26 +++++----- test/groups/product_group.jl | 24 ++++----- test/groups/validation_group.jl | 16 +++--- 14 files changed, 162 insertions(+), 162 deletions(-) diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 8e32642d96..129b82f874 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -590,10 +590,10 @@ export adjoint_action, compose!, direction, g_manifold, - group_exp, - group_exp!, - group_log, - group_log!, + exp_lie, + exp_lie!, + log_lie, + log_lie!, has_biinvariant_metric, has_invariant_metric, identity_element, diff --git a/src/groups/circle_group.jl b/src/groups/circle_group.jl index 650b07b02e..f1ce1b523b 100644 --- a/src/groups/circle_group.jl +++ b/src/groups/circle_group.jl @@ -62,7 +62,7 @@ function translate_diff!(G::CircleGroup, Y, p, q, X, conv::ActionDirection) return copyto!(Y, translate_diff(G, p, q, X, conv)) end -function group_exp(::CircleGroup, X) +function exp_lie(::CircleGroup, X) return map(X) do imθ θ = imag(imθ) sinθ, cosθ = sincos(θ) @@ -70,15 +70,15 @@ function group_exp(::CircleGroup, X) end end -group_exp!(G::CircleGroup, q, X) = (q .= group_exp(G, X)) +exp_lie!(G::CircleGroup, q, X) = (q .= exp_lie(G, X)) -function group_log(::CircleGroup, q) +function log_lie(::CircleGroup, q) return map(q) do z cosθ, sinθ = reim(z) θ = atan(sinθ, cosθ) return θ * im end end -group_log(::CircleGroup, e::Identity{MultiplicationOperation}) = 0.0 * im +log_lie(::CircleGroup, e::Identity{MultiplicationOperation}) = 0.0 * im -group_log!(G::CircleGroup, X::AbstractVector, q::AbstractVector) = (X .= group_log(G, q)) +log_lie!(G::CircleGroup, X::AbstractVector, q::AbstractVector) = (X .= log_lie(G, q)) diff --git a/src/groups/connections.jl b/src/groups/connections.jl index 729fc30c87..8d36f44756 100644 --- a/src/groups/connections.jl +++ b/src/groups/connections.jl @@ -65,7 +65,7 @@ function exp!( X, ) where {𝔽} Y = inverse_translate_diff(M.manifold, q, p, X) - return compose!(M.manifold, q, p, group_exp(M.manifold, Y)) + return compose!(M.manifold, q, p, exp_lie(M.manifold, Y)) end """ @@ -87,7 +87,7 @@ function log!( q, ) where {𝔽} pinvq = compose(M.manifold, inv(M.manifold, p), q) - group_log!(M.manifold, Y, pinvq) + log_lie!(M.manifold, Y, pinvq) return translate_diff!(M.manifold, Y, p, Identity(M.manifold), Y) end @@ -156,7 +156,7 @@ function vector_transport_direction!( d, ::ParallelTransport, ) - dexp_half = group_exp(M.manifold, d / 2) + dexp_half = exp_lie(M.manifold, d / 2) translate_diff!(M.manifold, Y, dexp_half, p, X, RightAction()) return translate_diff!(M.manifold, Y, dexp_half, p, Y, LeftAction()) end @@ -177,6 +177,6 @@ function vector_transport_to!( q, m::ParallelTransport, ) - d = group_log(M.manifold, q) + d = log_lie(M.manifold, q) return vector_transport_direction!(M, Y, p, X, d, m) end diff --git a/src/groups/general_linear.jl b/src/groups/general_linear.jl index d548aaa47c..533f3efa05 100644 --- a/src/groups/general_linear.jl +++ b/src/groups/general_linear.jl @@ -146,13 +146,13 @@ function get_vector!( return copyto!(X, Xⁱ) end -function group_exp!(::GeneralLinear{1}, q, X) +function exp_lie!(::GeneralLinear{1}, q, X) q[1] = exp(X[1]) return q end -group_exp!(::GeneralLinear{2}, q, X) = copyto!(q, exp(SizedMatrix{2,2}(X))) +exp_lie!(::GeneralLinear{2}, q, X) = copyto!(q, exp(SizedMatrix{2,2}(X))) -function group_log!(::GeneralLinear{1}, X::AbstractMatrix, p::AbstractMatrix) +function log_lie!(::GeneralLinear{1}, X::AbstractMatrix, p::AbstractMatrix) X[1] = log(p[1]) return X end diff --git a/src/groups/group.jl b/src/groups/group.jl index 5569beb92a..1faf10f6f5 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -616,7 +616,7 @@ end end @doc raw""" - group_exp(G::AbstractGroupManifold, X) + exp_lie(G::AbstractGroupManifold, X) Compute the group exponential of the Lie algebra element `X`. It is equivalent to the exponential map defined by the [`CartanSchoutenMinus`](@ref) connection. @@ -644,12 +644,12 @@ following properties: [`exp`](@ref). ``` -group_exp(G::AbstractGroupManifold{𝔽,AdditionOperation}, X) where {𝔽} +exp_lie(G::AbstractGroupManifold{𝔽,AdditionOperation}, X) where {𝔽} ``` Compute $q = X$. - group_exp(G::AbstractGroupManifold{𝔽,MultiplicationOperation}, X) where {𝔽} + exp_lie(G::AbstractGroupManifold{𝔽,MultiplicationOperation}, X) where {𝔽} For `Number` and `AbstractMatrix` types of `X`, compute the usual numeric/matrix exponential, @@ -658,22 +658,22 @@ exponential, \exp X = \operatorname{Exp} X = \sum_{n=0}^∞ \frac{1}{n!} X^n. ```` """ -group_exp(::AbstractGroupManifold, ::Any...) -@decorator_transparent_function function group_exp(G::AbstractGroupManifold, X) - q = allocate_result(G, group_exp, X) - return group_exp!(G, q, X) +exp_lie(::AbstractGroupManifold, ::Any...) +@decorator_transparent_function function exp_lie(G::AbstractGroupManifold, X) + q = allocate_result(G, exp_lie, X) + return exp_lie!(G, q, X) end -@decorator_transparent_signature group_exp!(M::AbstractDecoratorManifold, q, X) +@decorator_transparent_signature exp_lie!(M::AbstractDecoratorManifold, q, X) @doc raw""" - group_log(G::AbstractGroupManifold, q) + log_lie(G::AbstractGroupManifold, q) Compute the group logarithm of the group element `q`. It is equivalent to the logarithmic map defined by the [`CartanSchoutenMinus`](@ref) connection. Given an element $q ∈ \mathcal{G}$, compute the right inverse of the group exponential map -[`group_exp`](@ref), that is, the element $\log q = X ∈ 𝔤 = T_e \mathcal{G}$, such that +[`exp_lie`](@ref), that is, the element $\log q = X ∈ 𝔤 = T_e \mathcal{G}$, such that $q = \exp X$ !!! note @@ -681,12 +681,12 @@ $q = \exp X$ [`log`](@ref). ``` -group_log(G::AbstractGroupManifold{𝔽,AdditionOperation}, q) where {𝔽} +log_lie(G::AbstractGroupManifold{𝔽,AdditionOperation}, q) where {𝔽} ``` Compute $X = q$. - group_log(G::AbstractGroupManifold{𝔽,MultiplicationOperation}, q) where {𝔽} + log_lie(G::AbstractGroupManifold{𝔽,MultiplicationOperation}, q) where {𝔽} For `Number` and `AbstractMatrix` types of `q`, compute the usual numeric/matrix logarithm: @@ -697,21 +697,21 @@ For `Number` and `AbstractMatrix` types of `q`, compute the usual numeric/matrix where $e$ here is the [`Identity`](@ref) element, that is, $1$ for numeric $q$ or the identity matrix $I_m$ for matrix $q ∈ ℝ^{m × m}$. """ -group_log(::AbstractGroupManifold, ::Any...) -@decorator_transparent_function function group_log(G::AbstractGroupManifold, q) - X = allocate_result(G, group_log, q) - return group_log!(G, X, q) +log_lie(::AbstractGroupManifold, ::Any...) +@decorator_transparent_function function log_lie(G::AbstractGroupManifold, q) + X = allocate_result(G, log_lie, q) + return log_lie!(G, X, q) end -function group_log( +function log_lie( G::AbstractGroupManifold{𝔽,Op}, ::Identity{Op}, ) where {𝔽,Op<:AbstractGroupOperation} return zero_vector(G, identity_element(G)) end -@decorator_transparent_signature group_log!(M::AbstractDecoratorManifold, X, q) +@decorator_transparent_signature log_lie!(M::AbstractDecoratorManifold, X, q) -function group_log!( +function log_lie!( G::AbstractGroupManifold{𝔽,Op}, X, ::Identity{Op}, @@ -726,7 +726,7 @@ end """ GroupExponentialRetraction{D<:ActionDirection} <: AbstractRetractionMethod -Retraction using the group exponential [`group_exp`](@ref) "translated" to any point on the +Retraction using the group exponential [`exp_lie`](@ref) "translated" to any point on the manifold. For more details, see @@ -745,7 +745,7 @@ end """ GroupLogarithmicInverseRetraction{D<:ActionDirection} <: AbstractInverseRetractionMethod -Retraction using the group logarithm [`group_log`](@ref) "translated" to any point on the +Retraction using the group logarithm [`log_lie`](@ref) "translated" to any point on the manifold. For more details, see @@ -773,7 +773,7 @@ direction(::GroupLogarithmicInverseRetraction{D}) where {D} = D() method::GroupExponentialRetraction{<:ActionDirection}, ) -Compute the retraction using the group exponential [`group_exp`](@ref) "translated" to any +Compute the retraction using the group exponential [`exp_lie`](@ref) "translated" to any point on the manifold. With a group translation ([`translate`](@ref)) $τ_p$ in a specified direction, the retraction is @@ -782,14 +782,14 @@ retraction is \operatorname{retr}_p = τ_p \circ \exp \circ (\mathrm{d}τ_p^{-1})_p, ```` -where $\exp$ is the group exponential ([`group_exp`](@ref)), and $(\mathrm{d}τ_p^{-1})_p$ is +where $\exp$ is the group exponential ([`exp_lie`](@ref)), and $(\mathrm{d}τ_p^{-1})_p$ is the action of the differential of inverse translation $τ_p^{-1}$ evaluated at $p$ (see [`inverse_translate_diff`](@ref)). """ function retract(G::AbstractGroupManifold, p, X, method::GroupExponentialRetraction) conv = direction(method) Xₑ = inverse_translate_diff(G, p, p, X, conv) - pinvq = group_exp(G, Xₑ) + pinvq = exp_lie(G, Xₑ) q = translate(G, p, pinvq, conv) return q end @@ -797,7 +797,7 @@ end function retract!(G::AbstractGroupManifold, q, p, X, method::GroupExponentialRetraction) conv = direction(method) Xₑ = inverse_translate_diff(G, p, p, X, conv) - pinvq = group_exp(G, Xₑ) + pinvq = exp_lie(G, Xₑ) return translate!(G, q, p, pinvq, conv) end @@ -809,7 +809,7 @@ end method::GroupLogarithmicInverseRetraction{<:ActionDirection}, ) -Compute the inverse retraction using the group logarithm [`group_log`](@ref) "translated" +Compute the inverse retraction using the group logarithm [`log_lie`](@ref) "translated" to any point on the manifold. With a group translation ([`translate`](@ref)) $τ_p$ in a specified direction, the retraction is @@ -818,14 +818,14 @@ retraction is \operatorname{retr}_p^{-1} = (\mathrm{d}τ_p)_e \circ \log \circ τ_p^{-1}, ```` -where $\log$ is the group logarithm ([`group_log`](@ref)), and $(\mathrm{d}τ_p)_e$ is the +where $\log$ is the group logarithm ([`log_lie`](@ref)), and $(\mathrm{d}τ_p)_e$ is the action of the differential of translation $τ_p$ evaluated at the identity element $e$ (see [`translate_diff`](@ref)). """ function inverse_retract(G::GroupManifold, p, q, method::GroupLogarithmicInverseRetraction) conv = direction(method) pinvq = inverse_translate(G, p, q, conv) - Xₑ = group_log(G, pinvq) + Xₑ = log_lie(G, pinvq) return translate_diff(G, p, Identity(G), Xₑ, conv) end @@ -838,7 +838,7 @@ function inverse_retract!( ) conv = direction(method) pinvq = inverse_translate(G, p, q, conv) - Xₑ = group_log(G, pinvq) + Xₑ = log_lie(G, pinvq) return translate_diff!(G, X, p, Identity(G), Xₑ, conv) end @@ -905,17 +905,17 @@ function inverse_translate_diff!(::AdditionGroup, Y, p, q, X, ::ActionDirection) return copyto!(Y, X) end -group_exp(::AdditionGroup, X) = X +exp_lie(::AdditionGroup, X) = X -group_exp!(::AdditionGroup, q, X) = copyto!(q, X) +exp_lie!(::AdditionGroup, q, X) = copyto!(q, X) -group_log(::AdditionGroup, q) = q -function group_log(G::AdditionGroup, ::Identity{AdditionOperation}) +log_lie(::AdditionGroup, q) = q +function log_lie(G::AdditionGroup, ::Identity{AdditionOperation}) return zero_vector(G, identity_element(G)) end -group_log!(::AdditionGroup, X, q) = copyto!(X, q) -function group_log!(G::AdditionGroup, X, ::Identity{AdditionOperation}) +log_lie!(::AdditionGroup, X, q) = copyto!(X, q) +function log_lie!(G::AdditionGroup, X, ::Identity{AdditionOperation}) return zero_vector!(G, X, identity_element(G)) end @@ -1010,14 +1010,14 @@ function inverse_translate!(G::MultiplicationGroup, x, p, q, conv::ActionDirecti return copyto!(x, inverse_translate(G, p, q, conv)) end -function group_exp!(G::MultiplicationGroup, q, X) +function exp_lie!(G::MultiplicationGroup, q, X) X isa Union{Number,AbstractMatrix} && return copyto!(q, exp(X)) return error( - "group_exp! not implemented on $(typeof(G)) for vector $(typeof(X)) and element $(typeof(q)).", + "exp_lie! not implemented on $(typeof(G)) for vector $(typeof(X)) and element $(typeof(q)).", ) end -group_log!(::MultiplicationGroup, X::AbstractMatrix, q::AbstractMatrix) = log_safe!(X, q) +log_lie!(::MultiplicationGroup, X::AbstractMatrix, q::AbstractMatrix) = log_safe!(X, q) lie_bracket(::MultiplicationGroup, X, Y) = mul!(X * Y, Y, X, -1, true) @@ -1098,10 +1098,10 @@ end for f in [ compose, compose!, - group_exp, - group_exp!, - group_log, - group_log!, + exp_lie, + exp_lie!, + log_lie, + log_lie!, translate, translate!, translate_diff, diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 9b4750adc1..380e9b8734 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -27,10 +27,10 @@ function ProductGroup(manifold::ProductManifold{𝔽}) where {𝔽} return GroupManifold(manifold, op) end -function decorator_transparent_dispatch(::typeof(group_exp!), M::ProductGroup, q, X) +function decorator_transparent_dispatch(::typeof(exp_lie!), M::ProductGroup, q, X) return Val(:transparent) end -function decorator_transparent_dispatch(::typeof(group_log!), M::ProductGroup, X, q) +function decorator_transparent_dispatch(::typeof(log_lie!), M::ProductGroup, X, q) return Val(:transparent) end @@ -281,28 +281,28 @@ function inverse_translate_diff!(M::ProductManifold, Y, p, q, X, conv::ActionDir return Y end -function group_exp(M::ProductManifold, X::ProductRepr) - return ProductRepr(map(group_exp, M.manifolds, submanifold_components(M, X))...) +function exp_lie(M::ProductManifold, X::ProductRepr) + return ProductRepr(map(exp_lie, M.manifolds, submanifold_components(M, X))...) end -function group_exp(M::ProductManifold, X) - q = allocate_result(M, group_exp, X) - return group_exp!(M, q, X) +function exp_lie(M::ProductManifold, X) + q = allocate_result(M, exp_lie, X) + return exp_lie!(M, q, X) end -function group_exp!(M::ProductManifold, q, X) - map(group_exp!, M.manifolds, submanifold_components(M, q), submanifold_components(M, X)) +function exp_lie!(M::ProductManifold, q, X) + map(exp_lie!, M.manifolds, submanifold_components(M, q), submanifold_components(M, X)) return q end -function group_log(M::ProductManifold, q::ProductRepr) - return ProductRepr(map(group_log, M.manifolds, submanifold_components(M, q))...) +function log_lie(M::ProductManifold, q::ProductRepr) + return ProductRepr(map(log_lie, M.manifolds, submanifold_components(M, q))...) end -function group_log(M::ProductManifold, q) - X = allocate_result(M, group_log, q) - return group_log!(M, X, q) +function log_lie(M::ProductManifold, q) + X = allocate_result(M, log_lie, q) + return log_lie!(M, X, q) end -function group_log!(M::ProductManifold, X, q) - map(group_log!, M.manifolds, submanifold_components(M, X), submanifold_components(M, q)) +function log_lie!(M::ProductManifold, X, q) + map(log_lie!, M.manifolds, submanifold_components(M, X), submanifold_components(M, q)) return X end diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index a0b35273db..865b8c3e01 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -188,7 +188,7 @@ function _compose!( end @doc raw""" - group_exp(G::SpecialEuclidean{n}, X) + exp_lie(G::SpecialEuclidean{n}, X) Compute the group exponential of $X = (b, Ω) ∈ 𝔰𝔢(n)$, where $b ∈ 𝔱(n)$ and $Ω ∈ 𝔰𝔬(n)$: @@ -199,12 +199,12 @@ Compute the group exponential of $X = (b, Ω) ∈ 𝔰𝔢(n)$, where $b ∈ where $t ∈ \mathrm{T}(n)$ and $R = \exp Ω$ is the group exponential on $\mathrm{SO}(n)$. In the [`screw_matrix`](@ref) representation, the group exponential is the matrix -exponential (see [`group_exp`](@ref)). +exponential (see [`exp_lie`](@ref)). """ -group_exp(::SpecialEuclidean, ::Any) +exp_lie(::SpecialEuclidean, ::Any) @doc raw""" - group_exp(G::SpecialEuclidean{2}, X) + exp_lie(G::SpecialEuclidean{2}, X) Compute the group exponential of $X = (b, Ω) ∈ 𝔰𝔢(2)$, where $b ∈ 𝔱(2)$ and $Ω ∈ 𝔰𝔬(2)$: @@ -221,10 +221,10 @@ U(θ) = \frac{\sin θ}{θ} I_2 + \frac{1 - \cos θ}{θ^2} Ω, and $θ = \frac{1}{\sqrt{2}} \lVert Ω \rVert_e$ (see [`norm`](@ref norm(M::Rotations, p, X))) is the angle of the rotation. """ -group_exp(::SpecialEuclidean{2}, ::Any) +exp_lie(::SpecialEuclidean{2}, ::Any) @doc raw""" - group_exp(G::SpecialEuclidean{3}, X) + exp_lie(G::SpecialEuclidean{3}, X) Compute the group exponential of $X = (b, Ω) ∈ 𝔰𝔢(3)$, where $b ∈ 𝔱(3)$ and $Ω ∈ 𝔰𝔬(3)$: @@ -241,16 +241,16 @@ U(θ) = I_3 + \frac{1 - \cos θ}{θ^2} Ω + \frac{θ - \sin θ}{θ^3} Ω^2, and $θ = \frac{1}{\sqrt{2}} \lVert Ω \rVert_e$ (see [`norm`](@ref norm(M::Rotations, p, X))) is the angle of the rotation. """ -group_exp(::SpecialEuclidean{3}, ::Any) +exp_lie(::SpecialEuclidean{3}, ::Any) -function group_exp!(G::SpecialEuclidean, q, X) +function exp_lie!(G::SpecialEuclidean, q, X) Xmat = screw_matrix(G, X) qmat = exp(Xmat) map(copyto!, submanifold_components(G, q), submanifold_components(G, qmat)) _padpoint!(G, q) return q end -function group_exp!(G::SpecialEuclidean{2}, q, X) +function exp_lie!(G::SpecialEuclidean{2}, q, X) SO2 = submanifold(G, 2) b, Ω = submanifold_components(G, X) t, R = submanifold_components(G, q) @@ -279,7 +279,7 @@ function group_exp!(G::SpecialEuclidean{2}, q, X) end return q end -function group_exp!(G::SpecialEuclidean{3}, q, X) +function exp_lie!(G::SpecialEuclidean{3}, q, X) SO3 = submanifold(G, 2) b, Ω = submanifold_components(G, X) t, R = submanifold_components(G, q) @@ -308,7 +308,7 @@ function group_exp!(G::SpecialEuclidean{3}, q, X) end @doc raw""" - group_log(G::SpecialEuclidean{n}, p) where {n} + log_lie(G::SpecialEuclidean{n}, p) where {n} Compute the group logarithm of $p = (t, R) ∈ \mathrm{SE}(n)$, where $t ∈ \mathrm{T}(n)$ and $R ∈ \mathrm{SO}(n)$: @@ -320,12 +320,12 @@ and $R ∈ \mathrm{SO}(n)$: where $b ∈ 𝔱(n)$ and $Ω = \log R ∈ 𝔰𝔬(n)$ is the group logarithm on $\mathrm{SO}(n)$. In the [`affine_matrix`](@ref) representation, the group logarithm is the matrix logarithm -(see [`group_log`](@ref)): +(see [`log_lie`](@ref)): """ -group_log(::SpecialEuclidean, ::Any) +log_lie(::SpecialEuclidean, ::Any) @doc raw""" - group_log(G::SpecialEuclidean{2}, p) + log_lie(G::SpecialEuclidean{2}, p) Compute the group logarithm of $p = (t, R) ∈ \mathrm{SE}(2)$, where $t ∈ \mathrm{T}(2)$ and $R ∈ \mathrm{SO}(2)$: @@ -343,10 +343,10 @@ U(θ) = \frac{\sin θ}{θ} I_2 + \frac{1 - \cos θ}{θ^2} Ω, and $θ = \frac{1}{\sqrt{2}} \lVert Ω \rVert_e$ (see [`norm`](@ref norm(M::Rotations, p, X))) is the angle of the rotation. """ -group_log(::SpecialEuclidean{2}, ::Any) +log_lie(::SpecialEuclidean{2}, ::Any) @doc raw""" - group_log(G::SpecialEuclidean{3}, p) + log_lie(G::SpecialEuclidean{3}, p) Compute the group logarithm of $p = (t, R) ∈ \mathrm{SE}(3)$, where $t ∈ \mathrm{T}(3)$ and $R ∈ \mathrm{SO}(3)$: @@ -364,22 +364,22 @@ U(θ) = I_3 + \frac{1 - \cos θ}{θ^2} Ω + \frac{θ - \sin θ}{θ^3} Ω^2, and $θ = \frac{1}{\sqrt{2}} \lVert Ω \rVert_e$ (see [`norm`](@ref norm(M::Rotations, p, X))) is the angle of the rotation. """ -group_log(::SpecialEuclidean{3}, ::Any) +log_lie(::SpecialEuclidean{3}, ::Any) -function group_log!(G::SpecialEuclidean, X, q) +function log_lie!(G::SpecialEuclidean, X, q) qmat = affine_matrix(G, q) Xmat = real(log_safe(qmat)) map(copyto!, submanifold_components(G, X), submanifold_components(G, Xmat)) _padvector!(G, X) return X end -function group_log!(G::SpecialEuclidean{2}, X, q) +function log_lie!(G::SpecialEuclidean{2}, X, q) SO2 = submanifold(G, 2) b, Ω = submanifold_components(G, X) t, R = submanifold_components(G, q) @assert size(b) == (2,) - group_log!(SO2, Ω, R) + log_lie!(SO2, Ω, R) @inbounds θ = Ω[2] β = θ / 2 α = θ ≈ 0 ? 1 - β^2 / 3 : β * cot(β) @@ -391,7 +391,7 @@ function group_log!(G::SpecialEuclidean{2}, X, q) end return X end -function group_log!(G::SpecialEuclidean{3}, X, q) +function log_lie!(G::SpecialEuclidean{3}, X, q) b, Ω = submanifold_components(G, X) t, R = submanifold_components(G, q) @assert size(Ω) == (3, 3) diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index 20df79dee4..789ee7eeee 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -42,13 +42,13 @@ function inverse_translate_diff!(G::SpecialOrthogonal, Y, p, q, X, conv::ActionD return copyto!(Y, inverse_translate_diff(G, p, q, X, conv)) end -group_exp!(G::SpecialOrthogonal, q, X) = exp!(G, q, identity_element(G, q), X) +exp_lie!(G::SpecialOrthogonal, q, X) = exp!(G, q, identity_element(G, q), X) -group_log!(G::SpecialOrthogonal, X, q) = log!(G, X, identity_element(G, q), q) -function group_log!(G::SpecialOrthogonal, X::AbstractMatrix, q::AbstractMatrix) +log_lie!(G::SpecialOrthogonal, X, q) = log!(G, X, identity_element(G, q), q) +function log_lie!(G::SpecialOrthogonal, X::AbstractMatrix, q::AbstractMatrix) return log!(G, X, identity_element(G, q), q) end -function group_log!(::SpecialOrthogonal, X, ::Identity{MultiplicationOperation}) +function log_lie!(::SpecialOrthogonal, X, ::Identity{MultiplicationOperation}) return fill!(X, zero(eltype(X))) end diff --git a/src/groups/validation_group.jl b/src/groups/validation_group.jl index 54aee81ad4..6068951784 100644 --- a/src/groups/validation_group.jl +++ b/src/groups/validation_group.jl @@ -200,7 +200,7 @@ function inverse_translate_diff!( return Y end -function group_exp(M::ValidationManifold, X; kwargs...) +function exp_lie(M::ValidationManifold, X; kwargs...) is_vector( M, Identity(M.manifold), @@ -209,12 +209,12 @@ function group_exp(M::ValidationManifold, X; kwargs...) check_base_point=false, kwargs..., ) - q = array_point(group_exp(M.manifold, array_value(X))) + q = array_point(exp_lie(M.manifold, array_value(X))) is_point(M, q, true; kwargs...) return q end -function group_exp!(M::ValidationManifold, q, X; kwargs...) +function exp_lie!(M::ValidationManifold, q, X; kwargs...) is_vector( M, Identity(M.manifold), @@ -223,14 +223,14 @@ function group_exp!(M::ValidationManifold, q, X; kwargs...) check_base_point=false, kwargs..., ) - group_exp!(M.manifold, array_value(q), array_value(X)) + exp_lie!(M.manifold, array_value(q), array_value(X)) is_point(M, q, true; kwargs...) return q end -function group_log(M::ValidationManifold, q; kwargs...) +function log_lie(M::ValidationManifold, q; kwargs...) is_point(M, q, true; kwargs...) - X = ValidationTVector(group_log(M.manifold, array_value(q))) + X = ValidationTVector(log_lie(M.manifold, array_value(q))) is_vector( M, Identity(M.manifold), @@ -242,9 +242,9 @@ function group_log(M::ValidationManifold, q; kwargs...) return X end -function group_log!(M::ValidationManifold, X, q; kwargs...) +function log_lie!(M::ValidationManifold, X, q; kwargs...) is_point(M, q, true; kwargs...) - group_log!(M.manifold, array_value(X), array_value(q)) + log_lie!(M.manifold, array_value(X), array_value(q)) is_vector( M, Identity(M.manifold), diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index d1010b5726..dacac25e07 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -7,7 +7,7 @@ using Base: IdentityUnitRange Xe_pts::AbstractVector = []; atol = 1e-10, test_mutating = true, - test_group_exp_log = true, + test_exp_lie_log = true, test_diff = false, test_invariance = false, test_lie_bracket=false, @@ -31,7 +31,7 @@ function test_group( Xe_pts::AbstractVector=[]; atol=1e-10, test_mutating=true, - test_group_exp_log=true, + test_exp_lie_log=true, test_diff=false, test_invariance=false, test_lie_bracket=false, @@ -282,37 +282,37 @@ function test_group( end end - test_group_exp_log && Test.@testset "group exp/log properties" begin + test_exp_lie_log && Test.@testset "group exp/log properties" begin Test.@testset "e = exp(0)" begin - X = group_log(G, Identity(G)) - g = group_exp(G, X) + X = log_lie(G, Identity(G)) + g = exp_lie(G, X) Test.@test isapprox(G, Identity(G), g; atol=atol) test_mutating && Test.@testset "mutating" begin X = allocate(Xe_pts[1]) - Test.@test group_log!(G, X, Identity(G)) === X + Test.@test log_lie!(G, X, Identity(G)) === X g = allocate(g_pts[1]) - Test.@test group_exp!(G, g, X) === g + Test.@test exp_lie!(G, g, X) === g Test.@test is_identity(G, g; atol=atol) end end Test.@testset "X = log(exp(X))" begin for X in Xe_pts - g = group_exp(G, X) + g = exp_lie(G, X) Test.@test is_point(G, g; atol=atol) - X2 = group_log(G, g) + X2 = log_lie(G, g) Test.@test isapprox(G, Identity(G), X2, X; atol=atol) end test_mutating && Test.@testset "mutating" begin for X in Xe_pts g = allocate(g_pts[1]) - Test.@test group_exp!(G, g, X) === g + Test.@test exp_lie!(G, g, X) === g Test.@test is_point(G, g; atol=atol) - Test.@test isapprox(G, g, group_exp(G, X); atol=atol) + Test.@test isapprox(G, g, exp_lie(G, X); atol=atol) X2 = allocate(X) - Test.@test group_log!(G, X2, g) === X2 + Test.@test log_lie!(G, X2, g) === X2 Test.@test isapprox(G, Identity(G), X2, X; atol=atol) end end @@ -320,15 +320,15 @@ function test_group( Test.@testset "inv(g) = exp(-log(g))" begin g = g_pts[1] - X = group_log(G, g) - ginv = group_exp(G, -X) + X = log_lie(G, g) + ginv = exp_lie(G, -X) Test.@test isapprox(G, ginv, inv(G, g); atol=atol) end Test.@testset "exp(sX)∘exp(tX) = exp((s+t)X)" begin - g1 = group_exp(G, 0.2 * Xe_pts[1]) - g2 = group_exp(G, 0.3 * Xe_pts[1]) - g12 = group_exp(G, 0.5 * Xe_pts[1]) + g1 = exp_lie(G, 0.2 * Xe_pts[1]) + g2 = exp_lie(G, 0.3 * Xe_pts[1]) + g12 = exp_lie(G, 0.5 * Xe_pts[1]) g1_g2 = compose(G, g1, g2) g2_g1 = compose(G, g2, g1) isapprox(G, g1_g2, g12; atol=atol) @@ -336,7 +336,7 @@ function test_group( end end - test_group_exp_log && + test_exp_lie_log && test_diff && Test.@testset "exp/log retract/inverse_retract" begin for conv in diff_convs diff --git a/test/groups/general_linear.jl b/test/groups/general_linear.jl index f43e01e741..05ba9a07ad 100644 --- a/test/groups/general_linear.jl +++ b/test/groups/general_linear.jl @@ -54,8 +54,8 @@ using NLsolve q = exp(G, p, X) Y = log(G, p, q) @test Y ≈ X - @test group_exp(G, X) ≈ exp(X) - @test group_log(G, exp(X)) ≈ X + @test exp_lie(G, X) ≈ exp(X) + @test log_lie(G, exp(X)) ≈ X end @testset "complex" begin G = GeneralLinear(1, ℂ) @@ -65,8 +65,8 @@ using NLsolve q = exp(G, p, X) Y = log(G, p, q) @test Y ≈ X - @test group_exp(G, X) ≈ exp(X) - @test group_log(G, exp(X)) ≈ X + @test exp_lie(G, X) ≈ exp(X) + @test log_lie(G, exp(X)) ≈ X end end diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 7213817630..b853b27932 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -33,9 +33,9 @@ include("group_utils.jl") Val{:intransparent}() @test Manifolds.decorator_transparent_dispatch(compose!, G, x, x, x) === Val{:intransparent}() - @test Manifolds.decorator_transparent_dispatch(group_exp, G, x, x) === + @test Manifolds.decorator_transparent_dispatch(exp_lie, G, x, x) === Val{:intransparent}() - @test Manifolds.decorator_transparent_dispatch(group_log, G, x, x) === + @test Manifolds.decorator_transparent_dispatch(log_lie, G, x, x) === Val{:intransparent}() @test Manifolds.decorator_transparent_dispatch( translate_diff!, @@ -111,10 +111,10 @@ include("group_utils.jl") @test_throws ErrorException inverse_translate_diff!(G, v, x, x, v, LeftAction()) @test_throws ErrorException inverse_translate_diff!(G, v, x, x, v, RightAction()) - @test_throws ErrorException group_exp(G, v) - @test_throws ErrorException group_exp!(G, x, v) - @test_throws ErrorException group_log(G, x) - @test_throws ErrorException group_log!(G, v, x) + @test_throws ErrorException exp_lie(G, v) + @test_throws ErrorException exp_lie!(G, x, v) + @test_throws ErrorException log_lie(G, x) + @test_throws ErrorException log_lie!(G, v, x) for f in [translate, translate!] @test Manifolds.decorator_transparent_dispatch(f, G) === Val{:intransparent}() @@ -122,7 +122,7 @@ include("group_utils.jl") for f in [inverse_translate_diff!, inverse_translate_diff] @test Manifolds.decorator_transparent_dispatch(f, G) === Val{:transparent}() end - for f in [group_exp!, group_exp, group_log, group_log!] + for f in [exp_lie!, exp_lie, log_lie, log_lie!] @test Manifolds.decorator_transparent_dispatch(f, G, x, x) === Val{:intransparent}() end @@ -186,8 +186,8 @@ include("group_utils.jl") @test y ≈ x compose!(G, y, ge, x) @test y ≈ x - @test group_exp(G, v) === v - @test group_log(G, x) === x + @test exp_lie(G, v) === v + @test log_lie(G, x) === x end @testset "Multiplication operation" begin @@ -197,7 +197,7 @@ include("group_utils.jl") [[2.0 1.0; 3.0 4.0], [3.0 2.0; 4.0 5.0], [4.0 3.0; 5.0 6.0]], [], [[1.0 2.0; 3.0 4.0]]; - test_group_exp_log=true, + test_exp_lie_log=true, ) x = [2.0 1.0; 2.0 3.0] @@ -258,11 +258,11 @@ include("group_utils.jl") compose!(G, y, ge, x) @test y ≈ x X = [1.0 2.0; 3.0 4.0] - @test group_exp!(G, y, X) === y - @test_throws ErrorException group_exp!(G, y, :a) + @test exp_lie!(G, y, X) === y + @test_throws ErrorException exp_lie!(G, y, :a) @test y ≈ exp(X) Y = allocate(X) - @test group_log!(G, Y, y) === Y + @test log_lie!(G, Y, y) === Y @test Y ≈ log(y) end diff --git a/test/groups/product_group.jl b/test/groups/product_group.jl index a6357793e2..bac2f8a71c 100644 --- a/test/groups/product_group.jl +++ b/test/groups/product_group.jl @@ -15,7 +15,7 @@ include("group_utils.jl") @test sprint(show, G) == "ProductGroup($(SOn), $(Tn))" @test sprint(show, "text/plain", G) == "ProductGroup with 2 subgroups:\n $(SOn)\n $(Tn)" x = Matrix{Float64}(I, 3, 3) - for f in [group_exp!, group_log!] + for f in [exp_lie!, log_lie!] @test Manifolds.decorator_transparent_dispatch(f, G, x, x) === Val{:transparent}() end t = Vector{Float64}.([1:2, 2:3, 3:4]) @@ -38,21 +38,21 @@ include("group_utils.jl") @test isapprox( M, Identity(G), - group_exp(M, v_pts[1]), + exp_lie(M, v_pts[1]), Manifolds.prod_point( shape_se, - group_exp(SOn, v_pts[1].parts[1]), - group_exp(Tn, v_pts[1].parts[2]), + exp_lie(SOn, v_pts[1].parts[1]), + exp_lie(Tn, v_pts[1].parts[2]), ), ) @test isapprox( M, Identity(G), - group_log(M, pts[1]), + log_lie(M, pts[1]), Manifolds.prod_point( shape_se, - group_log(SOn, pts[1].parts[1]), - group_log(Tn, pts[1].parts[2]), + log_lie(SOn, pts[1].parts[1]), + log_lie(Tn, pts[1].parts[2]), ), ) end @@ -66,16 +66,16 @@ include("group_utils.jl") test_group(G, pts, v_pts, v_pts; test_diff=true, test_mutating=false) @test isapprox( M, - group_exp(M, v_pts[1]), + exp_lie(M, v_pts[1]), ProductRepr( - group_exp(SOn, v_pts[1].parts[1]), - group_exp(Tn, v_pts[1].parts[2]), + exp_lie(SOn, v_pts[1].parts[1]), + exp_lie(Tn, v_pts[1].parts[2]), ), ) @test isapprox( M, - group_log(M, pts[1]), - ProductRepr(group_log(SOn, pts[1].parts[1]), group_log(Tn, pts[1].parts[2])), + log_lie(M, pts[1]), + ProductRepr(log_lie(SOn, pts[1].parts[1]), log_lie(Tn, pts[1].parts[2])), ) end @test sprint(show, "text/plain", G) === """ diff --git a/test/groups/validation_group.jl b/test/groups/validation_group.jl index f9b9789666..08287aa053 100644 --- a/test/groups/validation_group.jl +++ b/test/groups/validation_group.jl @@ -52,17 +52,17 @@ include("../utils.jl") compose!(AG, pq, p2, e) @test isapprox(G, pq.value, compose(G, p, e)) - @test group_exp(AG, X2) isa ValidationMPoint - @test isapprox(G, group_exp(AG, X2).value, group_exp(G, X)) + @test exp_lie(AG, X2) isa ValidationMPoint + @test isapprox(G, exp_lie(AG, X2).value, exp_lie(G, X)) expX = allocate(p2) - group_exp!(AG, expX, X2) - @test isapprox(G, expX.value, group_exp(G, X)) + exp_lie!(AG, expX, X2) + @test isapprox(G, expX.value, exp_lie(G, X)) - @test group_log(AG, p2) isa ValidationTVector - @test isapprox(G, e, group_log(AG, p2).value, group_log(G, p)) + @test log_lie(AG, p2) isa ValidationTVector + @test isapprox(G, e, log_lie(AG, p2).value, log_lie(G, p)) logp = allocate(X2) - group_log!(AG, logp, p2) - @test isapprox(G, e, logp.value, group_log(G, p)) + log_lie!(AG, logp, p2) + @test isapprox(G, e, logp.value, log_lie(G, p)) @test lie_bracket(AG, X, X2) isa ValidationTVector Xlb = allocate(X2) From e7cb6ca4766db80aacafff3fd847e47def9e1899 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 28 Jul 2021 11:53:55 +0200 Subject: [PATCH 25/88] introduce get coordinates and vectors on the Lie algebra with a different name than the original one to avoid ambiguities. --- src/Manifolds.jl | 11 ++++++++--- src/groups/group.jl | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 129b82f874..95382f683a 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -1,5 +1,6 @@ module Manifolds +using Base: IdentityUnitRange import ManifoldsBase: _access_nested, _read, @@ -589,11 +590,13 @@ export adjoint_action, compose, compose!, direction, - g_manifold, exp_lie, exp_lie!, - log_lie, - log_lie!, + g_manifold, + get_coordinates_lie, + get_coordinates_lie!, + get_vector_lie, + get_vector_lie!, has_biinvariant_metric, has_invariant_metric, identity_element, @@ -611,6 +614,8 @@ export adjoint_action, inverse_translate_diff!, lie_bracket, lie_bracket!, + log_lie, + log_lie!, optimal_alignment, optimal_alignment!, screw_matrix, diff --git a/src/groups/group.jl b/src/groups/group.jl index 1faf10f6f5..386111f164 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -1027,6 +1027,32 @@ function lie_bracket!(::MultiplicationGroup, Z, X, Y) return Z end +@doc raw""" + get_vector_lie(G::AbstractGroupManifold, a, B::AbstractBasis) + +Reconstruct a tangent vector from the Lie algebra of `G` from cooordinates `a` of a basis `B`. +This is similar to calling [`get_vector`](@ref) at the `p=`[`Identity`]('ref)`(G)` +""" +function get_vector_lie(G::AbstractGroupManifold, X, B::AbstractBasis) + return get_vector(G, Identity(G), X, B) +end +function get_vector_lie!(G::AbstractGroupManifold, Y, X, B::AbstractBasis) + return get_vector!(G, Y, Identity(G), X, B) +end + +@doc raw""" + get_coordinates_lie(G::AbstractGroupManifold, X, B::AbstractBasis) + +Get the coordinates of an element `X` from the Lie algebra og `G` with respect to a basis `B`. +This is similar to calling [`get_coordinates`](@ref) at the `p=`[`Identity`]('ref)`G` +""" +function get_coordinates_lie(G::AbstractGroupManifold, X, B::AbstractBasis) + return get_coordinates(G, Identity(G), X, B) +end +function get_coordinates_lie!(G::AbstractGroupManifold, a, X, B::AbstractBasis) + return get_coordinates!(G, a, Identity(G), X, B) +end + # (a) changes / parent. for f in [ embed, From 4207ee5653a2ad8867d175f4e3997454066722cd Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 28 Jul 2021 12:02:26 +0200 Subject: [PATCH 26/88] runs formatter. --- test/groups/product_group.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/groups/product_group.jl b/test/groups/product_group.jl index bac2f8a71c..2f100f3c24 100644 --- a/test/groups/product_group.jl +++ b/test/groups/product_group.jl @@ -67,10 +67,7 @@ include("group_utils.jl") @test isapprox( M, exp_lie(M, v_pts[1]), - ProductRepr( - exp_lie(SOn, v_pts[1].parts[1]), - exp_lie(Tn, v_pts[1].parts[2]), - ), + ProductRepr(exp_lie(SOn, v_pts[1].parts[1]), exp_lie(Tn, v_pts[1].parts[2])), ) @test isapprox( M, From 1240b5e17edbf91921e8ff6aaeb5f73551744783 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 28 Jul 2021 12:12:25 +0200 Subject: [PATCH 27/88] tests are shorter with the new method since one can not call get_vector with a wrong identity anymore. --- test/groups/special_orthogonal.jl | 48 ++++++------------------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index cee5df26ce..9df14ab85e 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -140,58 +140,26 @@ include("group_utils.jl") @test isapprox(M, pe, X2, hat(G, pe, Xⁱ); atol=1e-6) end @testset "Identity and get_vector/get_coordinates" begin - e = Identity(G, Matrix{Float64}(I, 3, 3)) - gT = allocate_result(G, get_coordinates, e, pts[1]) - @test size(gT) == (manifold_dimension(M),) - @test eltype(gT) == eltype(e.p) - @test_throws ErrorException allocate_result(M, get_vector, e, pts[1]) - gT = allocate_result(G, get_vector, e, pts[1]) - @test size(gT) == size(e.p) - @test eltype(gT) == eltype(e.p) - eT = similar(e.p) - copyto!(eT, e) - @test eT == e.p + e = Identity(G) eF = Identity(SpecialEuclidean(3), 1) c = [1.0, 0.0, 0.0] Y = zeros(representation_size(G)) - get_vector!(G, Y, e, c, Manifolds.VeeOrthogonalBasis()) - @test Y ≈ get_vector(decorated_manifold(G), e.p, c, Manifolds.VeeOrthogonalBasis()) - @test_throws ErrorException get_vector!(G, Y, eF, c, Manifolds.VeeOrthogonalBasis()) - get_vector!(M, Y, e, c, Manifolds.VeeOrthogonalBasis()) - @test Y ≈ get_vector(decorated_manifold(G), e.p, c, Manifolds.VeeOrthogonalBasis()) - @test_throws ErrorException get_vector!(M, Y, eF, c, Manifolds.VeeOrthogonalBasis()) + get_vector_lie!(G, Y, c, Manifolds.VeeOrthogonalBasis()) + @test Y ≈ get_vector(M, identity(G), c, Manifolds.VeeOrthogonalBasis()) + get_vector!(M, Y, identity(G), c, Manifolds.VeeOrthogonalBasis()) + @test Y ≈ get_vector(M, identity(G), c, Manifolds.VeeOrthogonalBasis()) @test get_coordinates( decorated_manifold(G), - e, + identity(G), Y, Manifolds.VeeOrthogonalBasis(), ) == c - @test_throws ErrorException get_coordinates( - M, - eF, - c, - Manifolds.VeeOrthogonalBasis(), - ) c2 = similar(c) - get_coordinates!(G, c2, e, Y, Manifolds.VeeOrthogonalBasis()) + get_coordinates_lie!(G, c2, Y, Manifolds.VeeOrthogonalBasis()) @test c == c2 - @test_throws ErrorException get_coordinates!( - G, - c2, - eF, - Y, - Manifolds.VeeOrthogonalBasis(), - ) - get_coordinates!(M, c2, e, Y, Manifolds.VeeOrthogonalBasis()) + get_coordinates!(M, c2, identity(G), Y, Manifolds.VeeOrthogonalBasis()) @test c == c2 - @test_throws ErrorException get_coordinates!( - M, - c2, - eF, - Y, - Manifolds.VeeOrthogonalBasis(), - ) end end From 17a0f72c3d15c8f18e5defd88a53590515615a52 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 28 Jul 2021 17:13:50 +0200 Subject: [PATCH 28/88] introduce hat/vee on group manifolds, reintroduce transpose --- src/Manifolds.jl | 7 ++- src/groups/group.jl | 84 +++++++++++++++++++++++++++++++++-- test/groups/groups_general.jl | 59 ++++++++++++------------ 3 files changed, 115 insertions(+), 35 deletions(-) diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 95382f683a..df29d8a5df 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -33,6 +33,8 @@ import ManifoldsBase: get_vector!, get_vectors, gram_schmidt, + hat, + hat!, injectivity_radius, inner, inner__intransparent, @@ -59,6 +61,8 @@ import ManifoldsBase: vector_transport_direction!, vector_transport_to, vector_transport_to!, + vee, + vee!, zero_vector, zero_vector!, CotangentSpace, @@ -74,7 +78,8 @@ import Base: length, ndims, showerror, - size + size, + transpose using Base.Iterators: repeated using Distributions diff --git a/src/groups/group.jl b/src/groups/group.jl index 386111f164..b554243038 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -422,6 +422,82 @@ function compose!( return e end +transpose(e::Identity) = e + +@doc raw""" + hat(M::AbstractGroupManifold{𝔽,O}, ::Identity{O}, Xⁱ) where {𝔽,O<:AbstractGroupOperation} + +Given a basis $e_i$ on the tangent space at a the [`Identity`}(@ref) and tangent +component vector ``X^i``, compute the equivalent vector representation +``X=X^i e_i**, where Einstein summation notation is used: + +````math +∧ : X^i ↦ X^i e_i +```` + +For array manifolds, this converts a vector representation of the tangent +vector to an array representation. The [`vee`](@ref) map is the `hat` map's +inverse. +""" +function hat( + G::AbstractGroupManifold{𝔽,O}, + ::Identity{O}, + X, +) where {𝔽,O<:AbstractGroupOperation} + return get_vector_lie(G, X, VeeOrthogonalBasis()) +end +function hat!( + G::AbstractGroupManifold{𝔽,O}, + Y, + ::Identity{O}, + X, +) where {𝔽,O<:AbstractGroupOperation} + return get_vector_lie!(G, Y, X, VeeOrthogonalBasis()) +end +function hat(M::AbstractManifold, e::Identity, ::Any) + return throw(ErrorException("On $M there exsists no identity $e")) +end +function hat!(M::AbstractManifold, ::Any, e::Identity, ::Any) + return throw(ErrorException("On $M there exsists no identity $e")) +end + +@doc raw""" + vee(M::AbstractManifold, p, X) + +Given a basis $e_i$ on the tangent space at a point `p` and tangent +vector `X`, compute the vector components $X^i$, such that $X = X^i e_i$, where +Einstein summation notation is used: + +````math +\vee : X^i e_i ↦ X^i +```` + +For array manifolds, this converts an array representation of the tangent +vector to a vector representation. The [`hat`](@ref) map is the `vee` map's +inverse. +""" +function vee( + M::AbstractGroupManifold{𝔽,O}, + ::Identity{O}, + X, +) where {𝔽,O<:AbstractGroupOperation} + return get_coordinates_lie(M, X, VeeOrthogonalBasis()) +end +function vee!( + M::AbstractGroupManifold{𝔽,O}, + Y, + ::Identity{O}, + X, +) where {𝔽,O<:AbstractGroupOperation} + return get_coordinates_lie!(M, Y, X, VeeOrthogonalBasis()) +end +function vee(M::AbstractManifold, e::Identity, ::Any) + return throw(ErrorException("On $M there exsists no identity $e")) +end +function vee!(M::AbstractManifold, ::Any, e::Identity, ::Any) + return throw(ErrorException("On $M there exsists no identity $e")) +end + """ lie_bracket(G::AbstractGroupManifold, X, Y) @@ -1034,10 +1110,10 @@ Reconstruct a tangent vector from the Lie algebra of `G` from cooordinates `a` o This is similar to calling [`get_vector`](@ref) at the `p=`[`Identity`]('ref)`(G)` """ function get_vector_lie(G::AbstractGroupManifold, X, B::AbstractBasis) - return get_vector(G, Identity(G), X, B) + return get_vector(G, identity_element(G), X, B) end function get_vector_lie!(G::AbstractGroupManifold, Y, X, B::AbstractBasis) - return get_vector!(G, Y, Identity(G), X, B) + return get_vector!(G, Y, identity_element(G), X, B) end @doc raw""" @@ -1047,10 +1123,10 @@ Get the coordinates of an element `X` from the Lie algebra og `G` with respect t This is similar to calling [`get_coordinates`](@ref) at the `p=`[`Identity`]('ref)`G` """ function get_coordinates_lie(G::AbstractGroupManifold, X, B::AbstractBasis) - return get_coordinates(G, Identity(G), X, B) + return get_coordinates(G, identity_element(G), X, B) end function get_coordinates_lie!(G::AbstractGroupManifold, a, X, B::AbstractBasis) - return get_coordinates!(G, a, Identity(G), X, B) + return get_coordinates!(G, a, identity_element(G), X, B) end # (a) changes / parent. diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index b853b27932..46ab9c9e14 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -47,9 +47,6 @@ include("group_utils.jl") x, ) === Val{:intransparent}() @test base_group(G) === G - z = similar(x) - copyto!(G, z, eg) - @test z == eg.p @test NotImplementedOperation(NotImplementedManifold()) === G @test (NotImplementedOperation())(NotImplementedManifold()) === G @@ -57,38 +54,42 @@ include("group_utils.jl") MetricManifold(Euclidean(3), EuclideanMetric()), ) @test_throws ErrorException hat(Rotations(3), eg, [1, 2, 3]) - @test_throws ErrorException hat( + # If you force it, you get a not that readable MethodError + @test_throws MethodError hat( GroupManifold(Rotations(3), NotImplementedOperation()), eg, [1, 2, 3], ) @test_throws ErrorException vee(Rotations(3), eg, [1, 2, 3]) - @test_throws ErrorException vee( + @test_throws MethodError vee( GroupManifold(Rotations(3), NotImplementedOperation()), eg, [1, 2, 3], ) @test_throws ErrorException inv!(G, x, x) - @test_throws ErrorException inv!(G, x, eg) + @test_throws MethodError inv!(G, x, eg) @test_throws ErrorException inv(G, x) - @test copyto!(G, x, eg) === x - @test isapprox(G, x, eg) + # no function defined to return the identity array representation + @test_throws MethodError copyto!(G, x, eg) - @test_throws ErrorException compose(G, x, x) - @test_throws ErrorException compose(G, x, eg) - @test_throws ErrorException compose!(G, x, eg, x) - @test_throws ErrorException compose!(G, x, x, eg) - @test_throws ErrorException compose!(G, x, x, x) - @test_throws ErrorException compose!(G, x, eg, eg) + @test_throws MethodError compose(G, x, x) + @test compose(G, x, eg) == x + xO = deepcopy(x) + compose!(G, x, eg, x) + @test xO == x + compose!(G, x, x, eg) + @test xO == x + @test_throws MethodError compose!(G, x, x, x) + @test_throws MethodError compose!(G, x, eg, eg) - @test_throws ErrorException translate(G, x, x) - @test_throws ErrorException translate(G, x, x, LeftAction()) - @test_throws ErrorException translate(G, x, x, RightAction()) - @test_throws ErrorException translate!(G, x, x, x) - @test_throws ErrorException translate!(G, x, x, x, LeftAction()) - @test_throws ErrorException translate!(G, x, x, x, RightAction()) + @test_throws MethodError translate(G, x, x) + @test_throws MethodError translate(G, x, x, LeftAction()) + @test_throws MethodError translate(G, x, x, RightAction()) + @test_throws MethodError translate!(G, x, x, x) + @test_throws MethodError translate!(G, x, x, x, LeftAction()) + @test_throws MethodError translate!(G, x, x, x, RightAction()) @test_throws ErrorException inverse_translate(G, x, x) @test_throws ErrorException inverse_translate(G, x, x, LeftAction()) @@ -147,12 +148,12 @@ include("group_utils.jl") @testset "Addition operation" begin G = GroupManifold(NotImplementedManifold(), Manifolds.AdditionOperation()) - test_group(G, [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], [], [[1.0, 2.0]]) - - @test_throws DomainError is_point( + test_group( G, - Identity(GroupManifold(NotImplementedManifold(), NotImplementedOperation())), - true, + [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], + [], + [[1.0, 2.0]]; + test_exp_lie_log=false, # there is no identity element so log/exp on Lie do not work ) x = [1.0, 2.0] @@ -173,7 +174,6 @@ include("group_utils.jl") @test ge * 1 === ge @test 1 * ge === ge @test ge * ge === ge - @test identity_element(G) ≈ zero(x) @test inv(G, x) ≈ -x @test inv(G, ge) === ge @test compose(G, x, x) ≈ x + x @@ -197,13 +197,13 @@ include("group_utils.jl") [[2.0 1.0; 3.0 4.0], [3.0 2.0; 4.0 5.0], [4.0 3.0; 5.0 6.0]], [], [[1.0 2.0; 3.0 4.0]]; - test_exp_lie_log=true, + test_exp_lie_log=false, # no identity available as array ) x = [2.0 1.0; 2.0 3.0] ge = Identity(G) @test number_eltype(ge) == Bool - @test copyto!(ge, ge) === ge + @test copyto!(G, ge, ge) === ge y = allocate(x) identity_element!(G, y) @test y ≈ one(x) @@ -232,7 +232,6 @@ include("group_utils.jl") @test LinearAlgebra.mul!(y, ge, ge) === y @test y ≈ one(y) - @test ge.p ≈ one(x) @test inv(G, x) ≈ inv(x) @test inv(G, ge) === ge z = allocate(x) @@ -269,7 +268,7 @@ include("group_utils.jl") @testset "Identity on Group Manifolds" begin G = TranslationGroup(3) e = Identity(G) - @test get_vector(G, e, ones(3), DefaultOrthogonalBasis()) == ones(3) + @test get_vector_lie(G, ones(3), DefaultOrthogonalBasis()) == ones(3) @test e - e == e @test ones(3) + e == ones(3) end From 9f511e837c1948fdea3754f25cab5e5f36bc05ff Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 28 Jul 2021 17:39:42 +0200 Subject: [PATCH 29/88] Fix ValidationGroup --- src/groups/validation_group.jl | 3 +++ test/groups/validation_group.jl | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/groups/validation_group.jl b/src/groups/validation_group.jl index 6068951784..025c77a25c 100644 --- a/src/groups/validation_group.jl +++ b/src/groups/validation_group.jl @@ -26,6 +26,9 @@ function adjoint_action!(M::ValidationGroup, Y, p, X; kwargs...) return Y end +Identity(M::ValidationGroup) = array_point(Identity(M.manifold)) +identity_element!(M::ValidationGroup, p) = identity_element!(M.manifold, array_value(p)) + function Base.inv(M::ValidationGroup, p; kwargs...) is_point(M, p, true; kwargs...) q = array_point(inv(M.manifold, array_value(p))) diff --git a/test/groups/validation_group.jl b/test/groups/validation_group.jl index 08287aa053..eaacfb369b 100644 --- a/test/groups/validation_group.jl +++ b/test/groups/validation_group.jl @@ -20,15 +20,17 @@ include("../utils.jl") @test Identity(G) isa Identity - eg = allocate(p2) + eg = allocate(p) identity_element!(G, eg) - @test isapprox(G, eg, Identity(G)) + eg2 = allocate(p2) + identity_element!(AG, eg2) + @test eg2.value == eg eg = allocate(p2) @test inv(AG, p2) isa ValidationMPoint @test isapprox(G, inv(AG, p2).value, inv(G, p)) - @test inv(AG, e) isa Identity - @test_throws DomainError inv(AG, Identity(AG)) + @test inv(AG, e) isa ValidationMPoint{<:Identity} + @test inv(AG, Identity(AG)) == inv(AG, e) pinvq = allocate(p2) inv!(AG, pinvq, p2) From 81efabb1fcd47412b977fce4d620dfe6851c9bb8 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 28 Jul 2021 18:17:47 +0200 Subject: [PATCH 30/88] fixes another metric test. --- src/groups/group.jl | 6 +++++- src/groups/metric.jl | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index b554243038..db8ae9f9a3 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -190,6 +190,7 @@ struct Identity{O<:AbstractGroupOperation} end function Identity(::AbstractGroupManifold{𝔽,O}) where {𝔽,O<:AbstractGroupOperation} return Identity{O}() end +Identity(M::AbstractDecoratorManifold) = Identity(base_group(M)) Identity(::O) where {O<:AbstractGroupOperation} = Identity(O) Identity(::Type{O}) where {O<:AbstractGroupOperation} = Identity{O}() @@ -203,11 +204,14 @@ return a point representation of the [`Identity`](@ref) on the [`AbstractGroupMa by default this representation is default array representation. It should return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if points are not represented by arrays. """ -function identity_element(G::AbstractGroupManifold) +identity_element(G::AbstractGroupManifold) +@decorator_transparent_function function identity_element(G::AbstractGroupManifold) q = allocate_result(G, identity_element) return identity_element!(G, q) end +@decorator_transparent_signature identity_element!(G::AbstractGroupManifold, p) + function allocate_result(G::AbstractGroupManifold, ::typeof(identity_element)) return zeros(representation_size(G)...) end diff --git a/src/groups/metric.jl b/src/groups/metric.jl index 987b16ead1..5a01d6b3a5 100644 --- a/src/groups/metric.jl +++ b/src/groups/metric.jl @@ -191,7 +191,7 @@ function inner(M::MetricManifold{𝔽,<:AbstractManifold,<:InvariantMetric}, p, N = MetricManifold(M.manifold, imetric.metric) Xₑ = inverse_translate_diff(M, p, p, X, conv) Yₑ = inverse_translate_diff(M, p, p, Y, conv) - return inner(N, Identity(G), Xₑ, Yₑ) + return inner(N, Identity(N), Xₑ, Yₑ) end function default_metric_dispatch( @@ -232,7 +232,7 @@ function LinearAlgebra.norm( conv = direction(imetric) N = MetricManifold(M.manifold, imetric.metric) Xₑ = inverse_translate_diff(M, p, p, X, conv) - return norm(N, Identity(G), Xₑ) + return norm(N, identity_element(N), Xₑ) end function Base.show(io::IO, metric::LeftInvariantMetric) From 432bb08d17043b8a82a88c2b8ca9bfe6cd92bd5d Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 10:50:53 +0200 Subject: [PATCH 31/88] fixes a few more fixes. --- src/groups/circle_group.jl | 2 +- src/groups/general_linear.jl | 2 +- src/groups/group.jl | 54 +++++++---- src/groups/product_group.jl | 150 +++++++++++-------------------- src/groups/special_euclidean.jl | 6 +- src/groups/special_orthogonal.jl | 8 +- 6 files changed, 98 insertions(+), 124 deletions(-) diff --git a/src/groups/circle_group.jl b/src/groups/circle_group.jl index f1ce1b523b..813403c90e 100644 --- a/src/groups/circle_group.jl +++ b/src/groups/circle_group.jl @@ -81,4 +81,4 @@ function log_lie(::CircleGroup, q) end log_lie(::CircleGroup, e::Identity{MultiplicationOperation}) = 0.0 * im -log_lie!(G::CircleGroup, X::AbstractVector, q::AbstractVector) = (X .= log_lie(G, q)) +_log_lie!(G::CircleGroup, X, q) = (X .= log_lie(G, q)) diff --git a/src/groups/general_linear.jl b/src/groups/general_linear.jl index 533f3efa05..fa1a9fff23 100644 --- a/src/groups/general_linear.jl +++ b/src/groups/general_linear.jl @@ -152,7 +152,7 @@ function exp_lie!(::GeneralLinear{1}, q, X) end exp_lie!(::GeneralLinear{2}, q, X) = copyto!(q, exp(SizedMatrix{2,2}(X))) -function log_lie!(::GeneralLinear{1}, X::AbstractMatrix, p::AbstractMatrix) +function _log_lie!(::GeneralLinear{1}, X::AbstractMatrix, p::AbstractMatrix) X[1] = log(p[1]) return X end diff --git a/src/groups/group.jl b/src/groups/group.jl index 386111f164..43c8d1ce36 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -247,8 +247,35 @@ function is_identity( ) where {𝔽,O<:AbstractGroupOperation} return true end +function is_identity(G::AbstractGroupManifold, q; kwargs...) + return isapprox(G, identity_element(G), q; kwargs...) +end is_identity(::AbstractGroupManifold, ::Identity; kwargs...) = false +function isapprox(G::AbstractGroupManifold{𝔽,O}, p::Identity{O}, q; kwargs...) where {𝔽,O} + return isapprox(G, identity_element(G), q; kwargs...) +end +function isapprox(G::AbstractGroupManifold{𝔽,O}, p, q::Identity{O}; kwargs...) where {𝔽,O} + return isapprox(G, p, identity_element(G); kwargs...) +end +function isapprox( + G::AbstractGroupManifold{𝔽,O}, + p::Identity{O}, + q::Identity{O}; + kwargs..., +) where {𝔽,O} + return isapprox(G, p, identity_element(G); kwargs...) +end +function isapprox( + G::AbstractGroupManifold{𝔽,O}, + p::Identity{O}, + X, + Y; + kwargs..., +) where {𝔽,O} + return isapprox(G, identity_element(G), X, Y; kwargs...) +end + Base.show(io::IO, ::Identity{O}) where {O} = print(io, "Identity($O)") function check_point(G::AbstractGroupManifold{𝔽,O}, e::Identity{O}; kwargs...) where {𝔽,M,O} @@ -668,8 +695,9 @@ end @doc raw""" log_lie(G::AbstractGroupManifold, q) + log_lie!(G::AbstractGroupManifold, X, q) -Compute the group logarithm of the group element `q`. It is equivalent to the +Compute the Lie group logarithm of the Lie group element `q`. It is equivalent to the logarithmic map defined by the [`CartanSchoutenMinus`](@ref) connection. Given an element $q ∈ \mathcal{G}$, compute the right inverse of the group exponential map @@ -680,15 +708,7 @@ $q = \exp X$ In general, the group logarithm map is distinct from the Riemannian logarithm map [`log`](@ref). -``` -log_lie(G::AbstractGroupManifold{𝔽,AdditionOperation}, q) where {𝔽} -``` - -Compute $X = q$. - - log_lie(G::AbstractGroupManifold{𝔽,MultiplicationOperation}, q) where {𝔽} - -For `Number` and `AbstractMatrix` types of `q`, compute the usual numeric/matrix logarithm: + For matrix Llie groups this is equal to the (matrix) logarithm: ````math \log q = \operatorname{Log} q = \sum_{n=1}^∞ \frac{(-1)^{n+1}}{n} (q - e)^n, @@ -696,11 +716,14 @@ For `Number` and `AbstractMatrix` types of `q`, compute the usual numeric/matrix where $e$ here is the [`Identity`](@ref) element, that is, $1$ for numeric $q$ or the identity matrix $I_m$ for matrix $q ∈ ℝ^{m × m}$. + +Since this function handles [`Identity`](@ref) arguments, the preferred function to override +is `_log_lie!`. """ log_lie(::AbstractGroupManifold, ::Any...) @decorator_transparent_function function log_lie(G::AbstractGroupManifold, q) X = allocate_result(G, log_lie, q) - return log_lie!(G, X, q) + return _log_lie!(G, X, q) end function log_lie( G::AbstractGroupManifold{𝔽,Op}, @@ -709,7 +732,9 @@ function log_lie( return zero_vector(G, identity_element(G)) end -@decorator_transparent_signature log_lie!(M::AbstractDecoratorManifold, X, q) +@decorator_transparent_function function log_lie!(G::AbstractGroupManifold, X, q) + return _log_lie!(G, X, q) +end function log_lie!( G::AbstractGroupManifold{𝔽,Op}, @@ -914,10 +939,7 @@ function log_lie(G::AdditionGroup, ::Identity{AdditionOperation}) return zero_vector(G, identity_element(G)) end -log_lie!(::AdditionGroup, X, q) = copyto!(X, q) -function log_lie!(G::AdditionGroup, X, ::Identity{AdditionOperation}) - return zero_vector!(G, X, identity_element(G)) -end +_log_lie!(::AdditionGroup, X, q) = copyto!(X, q) lie_bracket(::AdditionGroup, X, Y) = zero(X) diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 380e9b8734..42b6836f40 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -35,17 +35,20 @@ function decorator_transparent_dispatch(::typeof(log_lie!), M::ProductGroup, X, end function identity_element(G::ProductGroup) - return ProductRepr(map(identity_element, G.manifolds)) + M = G.manifold + return ProductRepr(map(identity_element, M.manifolds)) end function identity_element!(G::ProductGroup, p) pes = submanifold_components(G, p) - map(identity_element!, G.manifolds, pes) + M = G.manifold + map(identity_element!, M.manifolds, pes) return p end function is_identity(G::ProductGroup, p; kwargs...) pes = submanifold_components(G, p) - return all(map((M, pe) -> is_identity(M, pe; kwargs...), G.manifolds, pes)) + M = G.manifold # Inner prodct manifold (of groups) + return all(map((M, pe) -> is_identity(M, pe; kwargs...), M.manifolds, pes)) end function Base.show(io::IO, ::MIME"text/plain", G::ProductGroup) @@ -79,17 +82,11 @@ function submanifold_components( M = base_manifold(G) return map(N -> Identity(N), M.manifolds) end -function Base.inv(M::ProductManifold, x::ProductRepr) - return ProductRepr(map(inv, M.manifolds, submanifold_components(M, x))...) -end -function Base.inv(M::ProductManifold, p) - q = allocate_result(M, inv, p) - return inv!(M, q, p) -end -inv!(G::ProductGroup, q, p) = inv!(G.manifold, q, p) -function inv!(M::ProductManifold, q, p) - map(inv!, M.manifolds, submanifold_components(M, q), submanifold_components(M, p)) +inv!(G::ProductGroup, q, ::Identity) = identity_element!(G, q) +function inv!(G::ProductGroup, q, p) + M = G.manifold + map(inv!, M.manifolds, submanifold_components(G, q), submanifold_components(G, p)) return q end @@ -106,10 +103,10 @@ function _compose(M::ProductManifold, p::ProductRepr, q::ProductRepr) end function _compose(M::ProductManifold, p, q) x = allocate_result(M, compose, p, q) - return compose!(M, x, p, q) + return _compose!(M, x, p, q) end -_compose!(G::ProductGroup, x, p, q) = compose!(G.manifold, x, p, q) +_compose!(G::ProductGroup, x, p, q) = _compose!(G.manifold, x, p, q) function _compose!(M::ProductManifold, x, p, q) map( compose!, @@ -159,150 +156,111 @@ function translate!(M::ProductManifold, x, p, q, conv::ActionDirection) end function inverse_translate(G::ProductGroup, p, q, conv::ActionDirection) - return inverse_translate(G.manifold, p, q, conv) -end -function inverse_translate( - M::ProductManifold, - p::ProductRepr, - q::ProductRepr, - conv::ActionDirection, -) + M = G.manifold return ProductRepr( map( inverse_translate, M.manifolds, - submanifold_components(M, p), - submanifold_components(M, q), + submanifold_components(G, p), + submanifold_components(G, q), repeated(conv), )..., ) end -function inverse_translate(M::ProductManifold, p, q, conv::ActionDirection) - x = allocate_result(M, inverse_translate, p, q) - return inverse_translate!(M, x, p, q, conv) -end function inverse_translate!(G::ProductGroup, x, p, q, conv::ActionDirection) - return inverse_translate!(G.manifold, x, p, q, conv) -end -function inverse_translate!(M::ProductManifold, x, p, q, conv::ActionDirection) + M = G.manifold map( inverse_translate!, M.manifolds, - submanifold_components(M, x), - submanifold_components(M, p), - submanifold_components(M, q), + submanifold_components(G, x), + submanifold_components(G, p), + submanifold_components(G, q), repeated(conv), ) return x end function translate_diff(G::ProductGroup, p, q, X, conv::ActionDirection) - return translate_diff(G.manifold, p, q, X, conv) -end -function translate_diff( - M::ProductManifold, - p::ProductRepr, - q::ProductRepr, - X::ProductRepr, - conv::ActionDirection, -) + M = G.manifold return ProductRepr( map( translate_diff, M.manifolds, - submanifold_components(M, p), - submanifold_components(M, q), - submanifold_components(M, X), + submanifold_components(G, p), + submanifold_components(G, q), + submanifold_components(G, X), repeated(conv), )..., ) end -function translate_diff(M::ProductManifold, p, q, X, conv::ActionDirection) - Y = allocate_result(M, translate_diff, X, p, q) - return translate_diff!(M, Y, p, q, X, conv) -end function translate_diff!(G::ProductGroup, Y, p, q, X, conv::ActionDirection) - return translate_diff!(G.manifold, Y, p, q, X, conv) -end -function translate_diff!(M::ProductManifold, Y, p, q, X, conv::ActionDirection) + M = G.manifold map( translate_diff!, M.manifolds, - submanifold_components(M, Y), - submanifold_components(M, p), - submanifold_components(M, q), - submanifold_components(M, X), + submanifold_components(G, Y), + submanifold_components(G, p), + submanifold_components(G, q), + submanifold_components(G, X), repeated(conv), ) return Y end function inverse_translate_diff(G::ProductGroup, p, q, X, conv::ActionDirection) - return inverse_translate_diff(G.manifold, p, q, X, conv) -end -function inverse_translate_diff( - M::ProductManifold, - p::ProductRepr, - q::ProductRepr, - X::ProductRepr, - conv::ActionDirection, -) + M = G.manifold return ProductRepr( map( inverse_translate_diff, M.manifolds, - submanifold_components(M, p), - submanifold_components(M, q), - submanifold_components(M, X), + submanifold_components(G, p), + submanifold_components(G, q), + submanifold_components(G, X), repeated(conv), )..., ) end -function inverse_translate_diff(M::ProductManifold, p, q, X, conv::ActionDirection) - Y = allocate_result(M, inverse_translate_diff, X, p, q) - return inverse_translate_diff!(M, Y, p, q, X, conv) -end function inverse_translate_diff!(G::ProductGroup, Y, p, q, X, conv::ActionDirection) - return inverse_translate_diff!(G.manifold, Y, p, q, X, conv) -end -function inverse_translate_diff!(M::ProductManifold, Y, p, q, X, conv::ActionDirection) + M = G.manifold map( inverse_translate_diff!, M.manifolds, - submanifold_components(M, Y), - submanifold_components(M, p), - submanifold_components(M, q), - submanifold_components(M, X), + submanifold_components(G, Y), + submanifold_components(G, p), + submanifold_components(G, q), + submanifold_components(G, X), repeated(conv), ) return Y end -function exp_lie(M::ProductManifold, X::ProductRepr) - return ProductRepr(map(exp_lie, M.manifolds, submanifold_components(M, X))...) +function exp_lie(G::ProductGroup, X::ProductRepr) + M = G.manifold + return ProductRepr(map(exp_lie, M.manifolds, submanifold_components(G, X))...) end -function exp_lie(M::ProductManifold, X) - q = allocate_result(M, exp_lie, X) - return exp_lie!(M, q, X) +function exp_lie(G::ProductGroup, X) + q = allocate_result(G, exp_lie, X) + return exp_lie!(G, q, X) end -function exp_lie!(M::ProductManifold, q, X) - map(exp_lie!, M.manifolds, submanifold_components(M, q), submanifold_components(M, X)) +function exp_lie!(G::ProductGroup, q, X) + M = G.manifold + map(exp_lie!, M.manifolds, submanifold_components(G, q), submanifold_components(G, X)) return q end -function log_lie(M::ProductManifold, q::ProductRepr) - return ProductRepr(map(log_lie, M.manifolds, submanifold_components(M, q))...) -end -function log_lie(M::ProductManifold, q) - X = allocate_result(M, log_lie, q) - return log_lie!(M, X, q) +#overwrite identity case to avoid allocating identity too early. +function log_lie!(G::ProductGroup, X, q::Identity{<:ProductOperation}) + M = G.manifold + map(log_lie!, M.manifolds, submanifold_components(G, X), submanifold_components(G, q)) + return X end -function log_lie!(M::ProductManifold, X, q) - map(log_lie!, M.manifolds, submanifold_components(M, X), submanifold_components(M, q)) +function _log_lie!(G::ProductGroup, X, q) + M = G.manifold + map(_log_lie!, M.manifolds, submanifold_components(G, X), submanifold_components(G, q)) return X end diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index 865b8c3e01..5288f9b6a8 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -366,14 +366,14 @@ and $θ = \frac{1}{\sqrt{2}} \lVert Ω \rVert_e$ """ log_lie(::SpecialEuclidean{3}, ::Any) -function log_lie!(G::SpecialEuclidean, X, q) +function _log_lie!(G::SpecialEuclidean, X, q) qmat = affine_matrix(G, q) Xmat = real(log_safe(qmat)) map(copyto!, submanifold_components(G, X), submanifold_components(G, Xmat)) _padvector!(G, X) return X end -function log_lie!(G::SpecialEuclidean{2}, X, q) +function _log_lie!(G::SpecialEuclidean{2}, X, q) SO2 = submanifold(G, 2) b, Ω = submanifold_components(G, X) t, R = submanifold_components(G, q) @@ -391,7 +391,7 @@ function log_lie!(G::SpecialEuclidean{2}, X, q) end return X end -function log_lie!(G::SpecialEuclidean{3}, X, q) +function _log_lie!(G::SpecialEuclidean{3}, X, q) b, Ω = submanifold_components(G, X) t, R = submanifold_components(G, q) @assert size(Ω) == (3, 3) diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index 789ee7eeee..05bcbb9e00 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -44,13 +44,7 @@ end exp_lie!(G::SpecialOrthogonal, q, X) = exp!(G, q, identity_element(G, q), X) -log_lie!(G::SpecialOrthogonal, X, q) = log!(G, X, identity_element(G, q), q) -function log_lie!(G::SpecialOrthogonal, X::AbstractMatrix, q::AbstractMatrix) - return log!(G, X, identity_element(G, q), q) -end -function log_lie!(::SpecialOrthogonal, X, ::Identity{MultiplicationOperation}) - return fill!(X, zero(eltype(X))) -end +_log_lie!(G::SpecialOrthogonal, X, q) = log!(G, X, identity_element(G, q), q) function allocate_result( ::GT, From 3575c1c49a015c543e60dd9a5f8a5fc506bfbda5 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 11:36:29 +0200 Subject: [PATCH 32/88] Fix special orthogonal (after JuliaManifolds/ManifoldsBase.jl#81 is finished) --- src/groups/group.jl | 14 +++++++++----- src/groups/product_group.jl | 5 +++++ test/groups/special_orthogonal.jl | 20 ++++++++------------ 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index 5743691c1c..ce6582ce75 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -244,6 +244,9 @@ the [`Identity`](@ref)`{O}` with the corresponding [`AbstractGroupOperation`](@r """ is_identity(G::AbstractGroupManifold, q) +@decorator_transparent_function function is_identity(G::AbstractGroupManifold, q; kwargs...) + return isapprox(G, identity_element(G), q; kwargs...) +end function is_identity( ::AbstractGroupManifold{𝔽,O}, ::Identity{O}; @@ -251,9 +254,6 @@ function is_identity( ) where {𝔽,O<:AbstractGroupOperation} return true end -function is_identity(G::AbstractGroupManifold, q; kwargs...) - return isapprox(G, identity_element(G), q; kwargs...) -end is_identity(::AbstractGroupManifold, ::Identity; kwargs...) = false function isapprox(G::AbstractGroupManifold{𝔽,O}, p::Identity{O}, q; kwargs...) where {𝔽,O} @@ -387,7 +387,11 @@ instead so that methods with [`Identity`] arguments are not ambiguous. """ compose(::AbstractGroupManifold, ::Any...) -function compose(G::AbstractGroupManifold{𝔽,Op}, p, q) where {𝔽,Op<:AbstractGroupOperation} +@decorator_transparent_function function compose( + G::AbstractGroupManifold{𝔽,Op}, + p, + q, +) where {𝔽,Op<:AbstractGroupOperation} return _compose(G, p, q) end function compose( @@ -412,7 +416,7 @@ function compose( return e end -@decorator_transparent_function function _compose(G::AbstractGroupManifold, p, q) +function _compose(G::AbstractGroupManifold, p, q) x = allocate_result(G, compose, p, q) return _compose!(G, x, p, q) end diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 42b6836f40..11418c5ff6 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -252,6 +252,11 @@ function exp_lie!(G::ProductGroup, q, X) return q end +function _log_lie!(G::ProductGroup, q) + M = G.manifold + return ProductRepr(map(_log_lie!, M.manifolds, submanifold_components(G, q))...) +end + #overwrite identity case to avoid allocating identity too early. function log_lie!(G::ProductGroup, X, q::Identity{<:ProductOperation}) M = G.manifold diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index 9df14ab85e..e71ced78d2 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -142,24 +142,20 @@ include("group_utils.jl") @testset "Identity and get_vector/get_coordinates" begin e = Identity(G) - eF = Identity(SpecialEuclidean(3), 1) + eF = Identity(SpecialEuclidean(3)) c = [1.0, 0.0, 0.0] Y = zeros(representation_size(G)) get_vector_lie!(G, Y, c, Manifolds.VeeOrthogonalBasis()) - @test Y ≈ get_vector(M, identity(G), c, Manifolds.VeeOrthogonalBasis()) - get_vector!(M, Y, identity(G), c, Manifolds.VeeOrthogonalBasis()) - @test Y ≈ get_vector(M, identity(G), c, Manifolds.VeeOrthogonalBasis()) - - @test get_coordinates( - decorated_manifold(G), - identity(G), - Y, - Manifolds.VeeOrthogonalBasis(), - ) == c + @test Y ≈ get_vector_lie(G, c, Manifolds.VeeOrthogonalBasis()) + get_vector!(M, Y, identity_element(G), c, Manifolds.VeeOrthogonalBasis()) + @test Y ≈ get_vector(M, identity_element(G), c, Manifolds.VeeOrthogonalBasis()) + + @test get_coordinates(M, identity_element(G), Y, Manifolds.VeeOrthogonalBasis()) == + c c2 = similar(c) get_coordinates_lie!(G, c2, Y, Manifolds.VeeOrthogonalBasis()) @test c == c2 - get_coordinates!(M, c2, identity(G), Y, Manifolds.VeeOrthogonalBasis()) + get_coordinates!(M, c2, identity_element(G), Y, Manifolds.VeeOrthogonalBasis()) @test c == c2 end end From c476a588b06647a617f484b3a2a93a9cdbbfb950 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 12:07:42 +0200 Subject: [PATCH 33/88] Fix special Euclidean. --- src/groups/semidirect_product_group.jl | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index c053c0a10c..f797d473ff 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -103,6 +103,10 @@ function inv!(G::SemidirectProductGroup, q, p) @inbounds _padpoint!(G, q) return q end +inv!(G::SemidirectProductGroup, q, ::Identity) = identity_element!(G, q) + + + function _compose!(G::SemidirectProductGroup, x, p, q) M = base_manifold(G) @@ -219,3 +223,12 @@ function Base.isapprox(G::SemidirectProductGroup, p, X, Y; kwargs...) nY, hY = submanifold_components(G, Y) return isapprox(N, np, nX, nY; kwargs...) && isapprox(H, hp, hX, hY; kwargs...) end +function isapprox( + G::SemidirectProductGroup, + p::Identity{O}, + X, + Y; + kwargs..., +) where {𝔽,O} + return isapprox(G, identity_element(G), X, Y; kwargs...) +end \ No newline at end of file From 2609aad13cc9045d6ce0edecfa03f2a79647204c Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 12:11:20 +0200 Subject: [PATCH 34/88] runs formatter. --- src/groups/semidirect_product_group.jl | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index f797d473ff..2e178e0011 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -105,9 +105,6 @@ function inv!(G::SemidirectProductGroup, q, p) end inv!(G::SemidirectProductGroup, q, ::Identity) = identity_element!(G, q) - - - function _compose!(G::SemidirectProductGroup, x, p, q) M = base_manifold(G) N, H = M.manifolds @@ -223,12 +220,6 @@ function Base.isapprox(G::SemidirectProductGroup, p, X, Y; kwargs...) nY, hY = submanifold_components(G, Y) return isapprox(N, np, nX, nY; kwargs...) && isapprox(H, hp, hX, hY; kwargs...) end -function isapprox( - G::SemidirectProductGroup, - p::Identity{O}, - X, - Y; - kwargs..., -) where {𝔽,O} +function isapprox(G::SemidirectProductGroup, p::Identity{O}, X, Y; kwargs...) where {𝔽,O} return isapprox(G, identity_element(G), X, Y; kwargs...) -end \ No newline at end of file +end From f32a3ec34c506006738e9445c11b78bd5bf7b60b Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 14:02:29 +0200 Subject: [PATCH 35/88] Fix metric (by avoiding allocation of concrete identity) --- src/groups/metric.jl | 4 ++-- src/groups/semidirect_product_group.jl | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/groups/metric.jl b/src/groups/metric.jl index 5a01d6b3a5..9304f33f46 100644 --- a/src/groups/metric.jl +++ b/src/groups/metric.jl @@ -179,7 +179,7 @@ function invariant_metric_dispatch( direction(metric(M)) === conv && return Val(true) return invoke(invariant_metric_dispatch, Tuple{MetricManifold,typeof(conv)}, M, conv) end -invariant_metric_dispatch(M::AbstractManifold, ::ActionDirection) = Val(false) +invariant_metric_dispatch(::AbstractManifold, ::ActionDirection) = Val(false) function has_invariant_metric(M::AbstractManifold, conv::ActionDirection) return _extract_val(invariant_metric_dispatch(M, conv)) @@ -232,7 +232,7 @@ function LinearAlgebra.norm( conv = direction(imetric) N = MetricManifold(M.manifold, imetric.metric) Xₑ = inverse_translate_diff(M, p, p, X, conv) - return norm(N, identity_element(N), Xₑ) + return norm(N, Identity(N), Xₑ) end function Base.show(io::IO, metric::LeftInvariantMetric) diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index 2e178e0011..661603fbe8 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -103,7 +103,9 @@ function inv!(G::SemidirectProductGroup, q, p) @inbounds _padpoint!(G, q) return q end -inv!(G::SemidirectProductGroup, q, ::Identity) = identity_element!(G, q) +function inv!(G::SemidirectProductGroup, q, p::Identity{<:SemidirectProductOperation}) + return identity_element!(G, q) +end function _compose!(G::SemidirectProductGroup, x, p, q) M = base_manifold(G) From 407e638772f48d075e3ea000e597816bc5d106ae Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 15:33:44 +0200 Subject: [PATCH 36/88] resolves further errors in product group --- src/groups/product_group.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 11418c5ff6..f8ab77b9db 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -252,9 +252,11 @@ function exp_lie!(G::ProductGroup, q, X) return q end -function _log_lie!(G::ProductGroup, q) +# on this meta level we first pass down before we resolve identity. +function log_lie!(G::ProductGroup, X, q) M = G.manifold - return ProductRepr(map(_log_lie!, M.manifolds, submanifold_components(G, q))...) + map(log_lie!, M.manifolds, submanifold_components(G, X), submanifold_components(G, q)) + return X end #overwrite identity case to avoid allocating identity too early. From 11ff63b719bcff68f014769b9e5455c1023a2388 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 16:09:10 +0200 Subject: [PATCH 37/88] Fix two further tests and a docstring --- src/manifolds/FixedRankMatrices.jl | 2 +- test/groups/groups_general.jl | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/manifolds/FixedRankMatrices.jl b/src/manifolds/FixedRankMatrices.jl index 6c81ba4ab8..0e96b5778e 100644 --- a/src/manifolds/FixedRankMatrices.jl +++ b/src/manifolds/FixedRankMatrices.jl @@ -1,5 +1,5 @@ @doc raw""" - FixedRankMatrices{m,n,k,𝔽} <: AbstractManifold{𝔽} + FixedRankMatrices{m,n,k,𝔽} <: AbstractEmbeddedManifold{𝔽,DefaultEmbeddingType} The manifold of ``m × n`` real-valued or complex-valued matrices of fixed rank ``k``, i.e. ````math diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 46ab9c9e14..b395107fa8 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -114,8 +114,9 @@ include("group_utils.jl") @test_throws ErrorException exp_lie(G, v) @test_throws ErrorException exp_lie!(G, x, v) - @test_throws ErrorException log_lie(G, x) - @test_throws ErrorException log_lie!(G, v, x) + # no transparency error, but _log_lie missing + @test_throws MethodError log_lie(G, x) + @test_throws MethodError log_lie!(G, v, x) for f in [translate, translate!] @test Manifolds.decorator_transparent_dispatch(f, G) === Val{:intransparent}() From f5b986f76749ffa82557cf6e64f2bc17d8c5eb04 Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Thu, 29 Jul 2021 16:10:31 +0200 Subject: [PATCH 38/88] minor fixes to product_group.jl --- src/groups/product_group.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 11418c5ff6..6f051a3c93 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -237,7 +237,7 @@ function inverse_translate_diff!(G::ProductGroup, Y, p, q, X, conv::ActionDirect return Y end -function exp_lie(G::ProductGroup, X::ProductRepr) +function exp_lie(G::ProductGroup, X::Union{ProductRepr,ProductArray}) M = G.manifold return ProductRepr(map(exp_lie, M.manifolds, submanifold_components(G, X))...) end @@ -252,9 +252,9 @@ function exp_lie!(G::ProductGroup, q, X) return q end -function _log_lie!(G::ProductGroup, q) +function _log_lie(G::ProductGroup, q) M = G.manifold - return ProductRepr(map(_log_lie!, M.manifolds, submanifold_components(G, q))...) + return ProductRepr(map(_log_lie, M.manifolds, submanifold_components(G, q))...) end #overwrite identity case to avoid allocating identity too early. From 793cffede0f63130e7952cc2b770be3803d61a0f Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 16:18:37 +0200 Subject: [PATCH 39/88] fix an error the merge introduced. --- src/groups/product_group.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 2bb07fde44..5a6435e60d 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -257,6 +257,7 @@ function log_lie!(G::ProductGroup, X, q) M = G.manifold map(log_lie!, M.manifolds, submanifold_components(G, X), submanifold_components(G, q)) return X +end function _log_lie(G::ProductGroup, q) M = G.manifold return ProductRepr(map(_log_lie, M.manifolds, submanifold_components(G, q))...) From 6dbf449731e3d2ff96bfe6a68570f3c844201a9f Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 17:53:08 +0200 Subject: [PATCH 40/88] Adapt product manifold to the more strict log_lie (only working on ProductGroup but not on ProductManifold due to identity) --- test/groups/product_group.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/groups/product_group.jl b/test/groups/product_group.jl index 2f100f3c24..18a61e6caa 100644 --- a/test/groups/product_group.jl +++ b/test/groups/product_group.jl @@ -36,9 +36,9 @@ include("group_utils.jl") @test compose(G, Identity(G), pts[1]) == pts[1] test_group(G, pts, v_pts, v_pts; test_diff=true) @test isapprox( - M, + G, Identity(G), - exp_lie(M, v_pts[1]), + exp_lie(G, v_pts[1]), Manifolds.prod_point( shape_se, exp_lie(SOn, v_pts[1].parts[1]), @@ -46,9 +46,9 @@ include("group_utils.jl") ), ) @test isapprox( - M, + G, Identity(G), - log_lie(M, pts[1]), + log_lie(G, pts[1]), Manifolds.prod_point( shape_se, log_lie(SOn, pts[1].parts[1]), @@ -65,13 +65,13 @@ include("group_utils.jl") @test compose(G, Identity(G), pts[1]) == pts[1] test_group(G, pts, v_pts, v_pts; test_diff=true, test_mutating=false) @test isapprox( - M, - exp_lie(M, v_pts[1]), + G, + exp_lie(G, v_pts[1]), ProductRepr(exp_lie(SOn, v_pts[1].parts[1]), exp_lie(Tn, v_pts[1].parts[2])), ) @test isapprox( - M, - log_lie(M, pts[1]), + G, + log_lie(G, pts[1]), ProductRepr(log_lie(SOn, pts[1].parts[1]), log_lie(Tn, pts[1].parts[2])), ) end From 777ba690cd528182d56015d11c0feec9a453e86e Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 19:10:15 +0200 Subject: [PATCH 41/88] use the right copyto! internally. Maybe this also fixes copyto together with the accompanying PR. --- src/groups/group.jl | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index ce6582ce75..634adea383 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -74,9 +74,6 @@ end Base.show(io::IO, G::GroupManifold) = print(io, "GroupManifold($(G.manifold), $(G.op))") -Base.copyto!(G::GroupManifold{𝔽,M,O}, q, p) where {𝔽,M,O} = copyto!(G.manifold, q, p) -Base.copyto!(G::GroupManifold{𝔽,M,O}, Y, p, X) where {𝔽,M,O} = copyto!(G.manifold, Y, p, X) - const GROUP_MANIFOLD_BASIS_DISAMBIGUATION = [AbstractDecoratorManifold, ValidationManifold, VectorBundle] @@ -425,20 +422,20 @@ end compose!(G::AbstractGroupManifold, x, q, p) = _compose!(G, x, q, p) function compose!( - ::AbstractGroupManifold{𝔽,Op}, + G::AbstractGroupManifold{𝔽,Op}, q, p, ::Identity{Op}, ) where {𝔽,Op<:AbstractGroupOperation} - return copyto!(q, p) + return copyto!(G, q, p) end function compose!( - ::AbstractGroupManifold{𝔽,Op}, + G::AbstractGroupManifold{𝔽,Op}, q, ::Identity{Op}, p, ) where {𝔽,Op<:AbstractGroupOperation} - return copyto!(q, p) + return copyto!(G, q, p) end function compose!( G::AbstractGroupManifold{𝔽,Op}, @@ -980,7 +977,7 @@ Base.:*(e::Identity{AdditionOperation}, ::Identity{AdditionOperation}) = e adjoint_action(::AdditionGroup, p, X) = X -adjoint_action!(::AdditionGroup, Y, p, X) = copyto!(Y, X) +adjoint_action!(G::AdditionGroup, Y, p, X) = copyto!(G, p, Y, X) function identity_element!(::AbstractGroupManifold{𝔽,<:AdditionOperation}, p) where {𝔽} return fill!(p, zero(eltype(p))) @@ -989,7 +986,7 @@ end Base.inv(::AdditionGroup, p) = -p Base.inv(::AdditionGroup, e::Identity) = e -inv!(::AdditionGroup, q, p) = copyto!(q, -p) +inv!(G::AdditionGroup, q, p) = copyto!(G, q, -p) inv!(G::AdditionGroup, q, ::Identity) = identity_element!(G, q) inv!(::AdditionGroup, q::Identity, e::Identity) = q @@ -1011,19 +1008,19 @@ translate_diff!(::AdditionGroup, Y, p, q, X, ::ActionDirection) = copyto!(Y, X) inverse_translate_diff(::AdditionGroup, p, q, X, ::ActionDirection) = X function inverse_translate_diff!(::AdditionGroup, Y, p, q, X, ::ActionDirection) - return copyto!(Y, X) + return copyto!(G, p, Y, X) end exp_lie(::AdditionGroup, X) = X -exp_lie!(::AdditionGroup, q, X) = copyto!(q, X) +exp_lie!(G::AdditionGroup, q, X) = copyto!(G, q, X) log_lie(::AdditionGroup, q) = q function log_lie(G::AdditionGroup, ::Identity{AdditionOperation}) return zero_vector(G, identity_element(G)) end -_log_lie!(::AdditionGroup, X, q) = copyto!(X, q) +_log_lie!(G::AdditionGroup, X, q) = copyto!(G, X, q) lie_bracket(::AdditionGroup, X, Y) = zero(X) @@ -1192,6 +1189,8 @@ end for f in [ check_point, check_vector, + copy, + copyto!, distance, exp, exp!, From 3ce5c46847d921338f405aa1a21d931917596fc2 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 21:01:57 +0200 Subject: [PATCH 42/88] it seems that copyto! with a group does not always work. --- src/groups/group.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index 634adea383..c2b4d39223 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -427,7 +427,7 @@ function compose!( p, ::Identity{Op}, ) where {𝔽,Op<:AbstractGroupOperation} - return copyto!(G, q, p) + return copyto!(q, p) end function compose!( G::AbstractGroupManifold{𝔽,Op}, @@ -435,7 +435,7 @@ function compose!( ::Identity{Op}, p, ) where {𝔽,Op<:AbstractGroupOperation} - return copyto!(G, q, p) + return copyto!(q, p) end function compose!( G::AbstractGroupManifold{𝔽,Op}, @@ -977,7 +977,7 @@ Base.:*(e::Identity{AdditionOperation}, ::Identity{AdditionOperation}) = e adjoint_action(::AdditionGroup, p, X) = X -adjoint_action!(G::AdditionGroup, Y, p, X) = copyto!(G, p, Y, X) +adjoint_action!(::AdditionGroup, Y, ::Any, X) = copyto!(Y, X) function identity_element!(::AbstractGroupManifold{𝔽,<:AdditionOperation}, p) where {𝔽} return fill!(p, zero(eltype(p))) @@ -986,7 +986,7 @@ end Base.inv(::AdditionGroup, p) = -p Base.inv(::AdditionGroup, e::Identity) = e -inv!(G::AdditionGroup, q, p) = copyto!(G, q, -p) +inv!(::AdditionGroup, q, p) = copyto!(q, -p) inv!(G::AdditionGroup, q, ::Identity) = identity_element!(G, q) inv!(::AdditionGroup, q::Identity, e::Identity) = q @@ -1007,20 +1007,20 @@ translate_diff!(::AdditionGroup, Y, p, q, X, ::ActionDirection) = copyto!(Y, X) inverse_translate_diff(::AdditionGroup, p, q, X, ::ActionDirection) = X -function inverse_translate_diff!(::AdditionGroup, Y, p, q, X, ::ActionDirection) - return copyto!(G, p, Y, X) +function inverse_translate_diff!(::AdditionGroup, Y, ::Any, ::Any, ::ActionDirection) + return copyto!(Y, X) end exp_lie(::AdditionGroup, X) = X -exp_lie!(G::AdditionGroup, q, X) = copyto!(G, q, X) +exp_lie!(G::AdditionGroup, q, X) = copyto!(q, X) log_lie(::AdditionGroup, q) = q function log_lie(G::AdditionGroup, ::Identity{AdditionOperation}) return zero_vector(G, identity_element(G)) end -_log_lie!(G::AdditionGroup, X, q) = copyto!(G, X, q) +_log_lie!(::AdditionGroup, X, q) = copyto!(X, q) lie_bracket(::AdditionGroup, X, Y) = zero(X) From 9348fa0a64b3361382a9b66bef4cd04fe727bc8f Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 21:03:40 +0200 Subject: [PATCH 43/88] better imports. --- src/Manifolds.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Manifolds.jl b/src/Manifolds.jl index df29d8a5df..e9390b9ff8 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -14,6 +14,8 @@ import ManifoldsBase: check_point, check_point__transparent, check_vector, + copy, + copyto!, decorated_manifold, decorator_transparent_dispatch, default_decorator_dispatch, @@ -21,6 +23,7 @@ import ManifoldsBase: dual_basis, embed, embed!, + exp, exp!, exp!__intransparent, get_basis, From 894e5ea3c7b0d544d25c91d50b28d80a0fa44fe3 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 29 Jul 2021 22:35:00 +0200 Subject: [PATCH 44/88] switch to group copies to be more flexible. --- src/groups/group.jl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index c2b4d39223..cadab52211 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -427,7 +427,7 @@ function compose!( p, ::Identity{Op}, ) where {𝔽,Op<:AbstractGroupOperation} - return copyto!(q, p) + return copyto!(G, q, p) end function compose!( G::AbstractGroupManifold{𝔽,Op}, @@ -435,7 +435,7 @@ function compose!( ::Identity{Op}, p, ) where {𝔽,Op<:AbstractGroupOperation} - return copyto!(q, p) + return copyto!(G, q, p) end function compose!( G::AbstractGroupManifold{𝔽,Op}, @@ -977,7 +977,7 @@ Base.:*(e::Identity{AdditionOperation}, ::Identity{AdditionOperation}) = e adjoint_action(::AdditionGroup, p, X) = X -adjoint_action!(::AdditionGroup, Y, ::Any, X) = copyto!(Y, X) +adjoint_action!(G::AdditionGroup, Y, p, X) = copyto!(G, Y, p, X) function identity_element!(::AbstractGroupManifold{𝔽,<:AdditionOperation}, p) where {𝔽} return fill!(p, zero(eltype(p))) @@ -986,7 +986,7 @@ end Base.inv(::AdditionGroup, p) = -p Base.inv(::AdditionGroup, e::Identity) = e -inv!(::AdditionGroup, q, p) = copyto!(q, -p) +inv!(G::AdditionGroup, q, p) = copyto!(G, q, -p) inv!(G::AdditionGroup, q, ::Identity) = identity_element!(G, q) inv!(::AdditionGroup, q::Identity, e::Identity) = q @@ -1003,24 +1003,24 @@ end translate_diff(::AdditionGroup, p, q, X, ::ActionDirection) = X -translate_diff!(::AdditionGroup, Y, p, q, X, ::ActionDirection) = copyto!(Y, X) +translate_diff!(G::AdditionGroup, Y, p, q, X, ::ActionDirection) = copyto!(G, Y, p, X) inverse_translate_diff(::AdditionGroup, p, q, X, ::ActionDirection) = X -function inverse_translate_diff!(::AdditionGroup, Y, ::Any, ::Any, ::ActionDirection) - return copyto!(Y, X) +function inverse_translate_diff!(G::AdditionGroup, Y, p, q, X, ::ActionDirection) + return copyto!(G, Y, p, X) end exp_lie(::AdditionGroup, X) = X -exp_lie!(G::AdditionGroup, q, X) = copyto!(q, X) +exp_lie!(G::AdditionGroup, q, X) = copyto!(G, q, X) log_lie(::AdditionGroup, q) = q function log_lie(G::AdditionGroup, ::Identity{AdditionOperation}) return zero_vector(G, identity_element(G)) end -_log_lie!(::AdditionGroup, X, q) = copyto!(X, q) +_log_lie!(G::AdditionGroup, X, q) = copyto!(G, X, q) lie_bracket(::AdditionGroup, X, Y) = zero(X) From 9ba25bea14bfda004d19d412c262538a62925d13 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 30 Jul 2021 07:04:10 +0200 Subject: [PATCH 45/88] fix the inner `log_lie!`call. --- src/groups/group.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index cadab52211..41b5ab7096 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -804,7 +804,7 @@ is `_log_lie!`. log_lie(::AbstractGroupManifold, ::Any...) @decorator_transparent_function function log_lie(G::AbstractGroupManifold, q) X = allocate_result(G, log_lie, q) - return _log_lie!(G, X, q) + return log_lie!(G, X, q) end function log_lie( G::AbstractGroupManifold{𝔽,Op}, From ba364eb2dcf34e65fea53aecb0efb20b5caf7dfa Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 30 Jul 2021 08:22:34 +0200 Subject: [PATCH 46/88] bump dependenciess & version --- Project.toml | 4 ++-- docs/Project.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index 80d6387aab..f6ba1961ac 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Manifolds" uuid = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e" authors = ["Seth Axen ", "Mateusz Baran ", "Ronny Bergmann ", "Antoine Levitt "] -version = "0.5.12" +version = "0.5.13" [deps] Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" @@ -32,7 +32,7 @@ FiniteDifferences = "0.12" HybridArrays = "0.4" Kronecker = "0.4" LightGraphs = "1" -ManifoldsBase = "0.12.1" +ManifoldsBase = "0.12.4" Plots = "~1.6, =1.10.5" RecipesBase = "1.1" Requires = "0.5, 1" diff --git a/docs/Project.toml b/docs/Project.toml index e14a6f58aa..cd99d19b42 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -16,7 +16,7 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] Documenter = "0.24, 0.25, 0.26" HybridArrays = "0.4" -ManifoldsBase = "0.12" +ManifoldsBase = "0.12.4" Plots = "= 1.10.5" PyPlot = "2.9" StaticArrays = "1.0" From d877317772c8b58c25834429081e59d4def9a9fa Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Fri, 30 Jul 2021 09:52:25 +0200 Subject: [PATCH 47/88] a test for `is_point` and identity element --- src/tests/tests_group.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index dacac25e07..04bf2c4b85 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -64,6 +64,13 @@ function test_group( end Test.@testset "Identity" begin + Test.@test is_point(G, e) + wrong_e = if e === Identity(MultiplicationOperation()) + Identity(AdditionOperation()) + else + Identity(MultiplicationOperation()) + end + Test.@test !is_point(G, wrong_e) Test.@test isapprox(G, e, e) Test.@test compose(G, e, e) === e Test.@test copyto!(G, e, e) === e From 4eeb7e50188b1e1deec750ada930053cf4ca3ab1 Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Fri, 30 Jul 2021 09:58:05 +0200 Subject: [PATCH 48/88] One more test and docstring updates --- src/groups/group.jl | 19 +++++++++++-------- src/tests/tests_group.jl | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index 41b5ab7096..da2029dd07 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -197,9 +197,10 @@ number_eltype(::Identity) = Bool @doc raw""" identity_element(G::AbstractGroupManifold) -return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G`. -by default this representation is default array representation. -It should return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if points are not represented by arrays. +Return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G`. +By default this representation is the default array or number representation. +It should return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if +points are not represented by arrays. """ identity_element(G::AbstractGroupManifold) @decorator_transparent_function function identity_element(G::AbstractGroupManifold) @@ -216,9 +217,10 @@ end @doc raw""" identity_element(G::AbstractGroupManifold, p) -return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G` (in place of `p`). -by default this representation is default array representation. -It rhoudl return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if points are not represented by arrays. +Return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G` +(in place of `p`). By default this representation is default array or number representation. +It rhoudl return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if +points are not represented by arrays or numbers. """ function identity_element(G::AbstractGroupManifold, p) q = allocate_result(G, identity_element, p) @@ -228,14 +230,15 @@ end @doc raw""" identity_element!(G::AbstractGroupManifold, p) -return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G` in place of `p`. +Return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G` +in place of `p`. """ identity_element!(G::AbstractGroupManifold, p) @doc raw""" is_identity(G, q; kwargs) -Check, whether `q` is the identity on the [`AbstractGroupManifold`](@ref) `G`, i.e. it is either +Check whether `q` is the identity on the [`AbstractGroupManifold`](@ref) `G`, i.e. it is either the [`Identity`](@ref)`{O}` with the corresponding [`AbstractGroupOperation`](@ref) `O`, or (approximately) the correct point representation. """ diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index 04bf2c4b85..5604058ba1 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -71,6 +71,7 @@ function test_group( Identity(MultiplicationOperation()) end Test.@test !is_point(G, wrong_e) + Test.@test !is_identity(G, wrong_e) Test.@test isapprox(G, e, e) Test.@test compose(G, e, e) === e Test.@test copyto!(G, e, e) === e From b383500d065501dadad9af547dd9e2db256f22fb Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 30 Jul 2021 10:10:08 +0200 Subject: [PATCH 49/88] Apply suggestions from code review Co-authored-by: Mateusz Baran --- Project.toml | 2 +- src/Manifolds.jl | 1 - src/groups/group.jl | 9 +++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Project.toml b/Project.toml index f6ba1961ac..b91199e495 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Manifolds" uuid = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e" authors = ["Seth Axen ", "Mateusz Baran ", "Ronny Bergmann ", "Antoine Levitt "] -version = "0.5.13" +version = "0.6.0" [deps] Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" diff --git a/src/Manifolds.jl b/src/Manifolds.jl index e9390b9ff8..76fd3259f0 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -1,6 +1,5 @@ module Manifolds -using Base: IdentityUnitRange import ManifoldsBase: _access_nested, _read, diff --git a/src/groups/group.jl b/src/groups/group.jl index da2029dd07..a0809a4d3b 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -167,12 +167,13 @@ switch_direction(::RightAction) = LeftAction() @doc raw""" Identity{O<:AbstractGroupOperation} -Represent the group identity element $e ∈ \mathcal{G}$ on an [`AbstractGroupManifold`](@ref) `G`. +Represent the group identity element ``e ∈ \mathcal{G}`` on an [`AbstractGroupManifold`](@ref) `G` +with [`AbstractGroupOperation`](@ref) of type `O`. Similar to the philosophy that points are agnostic of their group at hand, the identity -does not store the group `g` it belongs to. HOwever it depends on the type of the [`AbstractGroupOperation`](@ref) used. +does not store the group `g` it belongs to. However it depends on the type of the [`AbstractGroupOperation`](@ref) used. -see also [`identity`](@ref) on how to obtain the corresponding [`AbstractManifoldPoint`](@ref) or array representation. +See also [`identity_element`](@ref) on how to obtain the corresponding [`AbstractManifoldPoint`](@ref) or array representation. # Constructors @@ -268,7 +269,7 @@ function isapprox( q::Identity{O}; kwargs..., ) where {𝔽,O} - return isapprox(G, p, identity_element(G); kwargs...) + return true end function isapprox( G::AbstractGroupManifold{𝔽,O}, From ed53c177d7a89a6b351fc830bff5d18524689c62 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 30 Jul 2021 10:10:26 +0200 Subject: [PATCH 50/88] Update docs/src/manifolds/group.md Co-authored-by: Mateusz Baran --- docs/src/manifolds/group.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/manifolds/group.md b/docs/src/manifolds/group.md index 9bb741dad2..d2c31b59aa 100644 --- a/docs/src/manifolds/group.md +++ b/docs/src/manifolds/group.md @@ -17,7 +17,7 @@ Depth = 3 The following operations are available for group manifolds: -* [`Identity`](@ref): an allocation free representation of the identity element of the group. +* [`Identity`](@ref): an allocation-free representation of the identity element of the group. * [`inv`](@ref): get the inverse of a given element. * [`compose`](@ref): compose two given elements of a group. From b84a3bf4e0b82dca977dc9e3a0cee95005deb914 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 30 Jul 2021 10:10:35 +0200 Subject: [PATCH 51/88] Update docs/src/manifolds/group.md Co-authored-by: Mateusz Baran --- docs/src/manifolds/group.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/manifolds/group.md b/docs/src/manifolds/group.md index d2c31b59aa..40a7c2c5df 100644 --- a/docs/src/manifolds/group.md +++ b/docs/src/manifolds/group.md @@ -20,6 +20,7 @@ The following operations are available for group manifolds: * [`Identity`](@ref): an allocation-free representation of the identity element of the group. * [`inv`](@ref): get the inverse of a given element. * [`compose`](@ref): compose two given elements of a group. +* [`identity_element`](@ref) get the identity element of the group, in the representation used by other points from the group. ### Group manifold From d3eba66019e3c210782fc2aa453ebc3787291e2f Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Fri, 30 Jul 2021 10:11:38 +0200 Subject: [PATCH 52/88] parametrizing some Identity types --- src/groups/circle_group.jl | 10 +++++++- src/groups/product_group.jl | 2 +- src/groups/rotation_action.jl | 9 ++++++- src/groups/semidirect_product_group.jl | 33 ++++++++++++++++++++++---- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/groups/circle_group.jl b/src/groups/circle_group.jl index 813403c90e..f94ada6455 100644 --- a/src/groups/circle_group.jl +++ b/src/groups/circle_group.jl @@ -56,7 +56,15 @@ lie_bracket(::CircleGroup, X, Y) = zero(X) lie_bracket!(::CircleGroup, Z, X, Y) = fill!(Z, 0) translate_diff(::GT, p, q, X, ::ActionDirection) where {GT<:CircleGroup} = map(*, p, X) -translate_diff(::CircleGroup, ::Identity, q, X, ::ActionDirection) = X +function translate_diff( + ::CircleGroup, + ::Identity{MultiplicationOperation}, + q, + X, + ::ActionDirection, +) + return X +end function translate_diff!(G::CircleGroup, Y, p, q, X, conv::ActionDirection) return copyto!(Y, translate_diff(G, p, q, X, conv)) diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 5a6435e60d..7ff702d354 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -83,7 +83,7 @@ function submanifold_components( return map(N -> Identity(N), M.manifolds) end -inv!(G::ProductGroup, q, ::Identity) = identity_element!(G, q) +inv!(G::ProductGroup, q, ::Identity{ProductOperation}) = identity_element!(G, q) function inv!(G::ProductGroup, q, p) M = G.manifold map(inv!, M.manifolds, submanifold_components(G, q), submanifold_components(G, p)) diff --git a/src/groups/rotation_action.jl b/src/groups/rotation_action.jl index a4310d3f71..dd297cc1d1 100644 --- a/src/groups/rotation_action.jl +++ b/src/groups/rotation_action.jl @@ -53,7 +53,14 @@ end inverse_apply(A::RotationActionOnVector{N,F,RightAction}, a, p) where {N,F} = a * p apply_diff(::RotationActionOnVector{N,F,LeftAction}, a, p, X) where {N,F} = a * X -apply_diff(::RotationActionOnVector{N,F,LeftAction}, ::Identity, p, X) where {N,F} = X +function apply_diff( + ::RotationActionOnVector{N,F,LeftAction}, + ::Identity{MultiplicationOperation}, + p, + X, +) where {N,F} + return X +end function apply_diff(A::RotationActionOnVector{N,F,RightAction}, a, p, X) where {N,F} return inv(base_group(A), a) * X end diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index 661603fbe8..bfd8c145b1 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -103,7 +103,7 @@ function inv!(G::SemidirectProductGroup, q, p) @inbounds _padpoint!(G, q) return q end -function inv!(G::SemidirectProductGroup, q, p::Identity{<:SemidirectProductOperation}) +function inv!(G::SemidirectProductGroup, q, ::Identity{<:SemidirectProductOperation}) return identity_element!(G, q) end @@ -206,13 +206,30 @@ function Base.isapprox(G::SemidirectProductGroup, p, q; kwargs...) nq, hq = submanifold_components(G, q) return isapprox(N, np, nq; kwargs...) && isapprox(H, hp, hq; kwargs...) end -function Base.isapprox(G::SemidirectProductGroup, e::Identity, p; kwargs...) +function Base.isapprox( + G::SemidirectProductGroup, + e::Identity{<:SemidirectProductOperation}, + p; + kwargs..., +) return isapprox(G, identity_element(G, p), p; kwargs...) end -function Base.isapprox(G::SemidirectProductGroup, p, e::Identity; kwargs...) +function Base.isapprox( + G::SemidirectProductGroup, + p, + e::Identity{<:SemidirectProductOperation}; + kwargs..., +) return isapprox(G, e, p; kwargs...) end -Base.isapprox(::SemidirectProductGroup, ::Identity, ::Identity; kwargs...) = true +function Base.isapprox( + ::SemidirectProductGroup, + ::Identity{<:SemidirectProductOperation}, + ::Identity{<:SemidirectProductOperation}; + kwargs..., +) + return true +end function Base.isapprox(G::SemidirectProductGroup, p, X, Y; kwargs...) M = base_manifold(G) @@ -222,6 +239,12 @@ function Base.isapprox(G::SemidirectProductGroup, p, X, Y; kwargs...) nY, hY = submanifold_components(G, Y) return isapprox(N, np, nX, nY; kwargs...) && isapprox(H, hp, hX, hY; kwargs...) end -function isapprox(G::SemidirectProductGroup, p::Identity{O}, X, Y; kwargs...) where {𝔽,O} +function isapprox( + G::SemidirectProductGroup, + ::Identity{<:SemidirectProductOperation}, + X, + Y; + kwargs..., +) return isapprox(G, identity_element(G), X, Y; kwargs...) end From 5896129f948e00c93aeedbc681e6eb27741b91b1 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 30 Jul 2021 10:15:14 +0200 Subject: [PATCH 53/88] readd identity_element but remove the nonmutating variants from the docstring list. --- src/groups/group.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/groups/group.jl b/src/groups/group.jl index a0809a4d3b..e420e403a1 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -8,6 +8,8 @@ Abstract type for smooth binary operations $∘$ on elements of a Lie group $\ma An operation can be either defined for a specific [`AbstractGroupManifold`](@ref) over number system `𝔽` or in general, by defining for an operation `Op` the following methods: + identity_element!(::AbstractGroupManifold{𝔽,Op}, q, q) + identity_element(::AbstractGroupManifold{𝔽,Op} [, q]) inv!(::AbstractGroupManifold{𝔽,Op}, q, p) inv(::AbstractGroupManifold{𝔽,Op}, p) _compose(::AbstractGroupManifold{𝔽,Op}, p, q) From b8e11ba0ed0cf1b4f4fd5f3a7bd9e78df94a892a Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Fri, 30 Jul 2021 10:24:13 +0200 Subject: [PATCH 54/88] a few more identity type parameters --- src/groups/special_euclidean.jl | 8 ++++---- src/groups/translation_action.jl | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index 5288f9b6a8..906ddfc461 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -135,7 +135,7 @@ function affine_matrix(G::SpecialEuclidean{n}, p) where {n} return pmat end affine_matrix(::SpecialEuclidean{n}, p::AbstractMatrix) where {n} = p -function affine_matrix(::GT, ::Identity) where {n,GT<:SpecialEuclidean{n}} +function affine_matrix(::GT, ::Identity{<:SemidirectProductOperation}) where {n,GT<:SpecialEuclidean{n}} s = maybesize(Size(n, n)) s isa Size && return SDiagonal{n,Float64}(I) return Diagonal{Float64}(I, n) @@ -469,12 +469,12 @@ function translate_diff!(G::SpecialEuclidean, Y, p, q, X, ::RightAction) @inbounds _padvector!(G, Y) return Y end -function translate_diff!(G::SpecialEuclidean, Y, ::Identity, q, X, ::RightAction) +function translate_diff!(G::SpecialEuclidean, Y, ::Identity{<:SemidirectProductOperation}, q, X, ::RightAction) copyto!(G, Y, X) @inbounds _padvector!(G, Y) return Y end -function translate_diff!(G::SpecialEuclidean, Y, p, ::Identity, X, ::RightAction) +function translate_diff!(G::SpecialEuclidean, Y, p, ::Identity{<:SemidirectProductOperation}, X, ::RightAction) np, hp = submanifold_components(G, p) nX, hX = submanifold_components(G, X) nY, hY = submanifold_components(G, Y) @@ -482,7 +482,7 @@ function translate_diff!(G::SpecialEuclidean, Y, p, ::Identity, X, ::RightAction copyto!(nY, hX * np + nX) @inbounds _padvector!(G, Y) end -function translate_diff!(G::SpecialEuclidean, Y, ::Identity, ::Identity, X, ::RightAction) +function translate_diff!(G::SpecialEuclidean, Y, ::Identity{Op}, ::Identity{Op}, X, ::RightAction) where {Op<:SemidirectProductOperation} copyto!(G, Y, X) @inbounds _padvector!(G, Y) return Y diff --git a/src/groups/translation_action.jl b/src/groups/translation_action.jl index 5c7ca4a236..970e81461e 100644 --- a/src/groups/translation_action.jl +++ b/src/groups/translation_action.jl @@ -39,12 +39,12 @@ end apply(::TranslationAction, a, p) = p + a apply!(::TranslationAction, q, a, p) = (q .= p .+ a) -apply!(::TranslationAction, q, e::Identity, p) = copyto!(q, p) +apply!(::TranslationAction, q, e::Identity{AdditionOperation}, p) = copyto!(q, p) inverse_apply(::TranslationAction, a, p) = p - a inverse_apply!(::TranslationAction, q, a, p) = (q .= p .- a) -inverse_apply!(::TranslationAction, q, e::Identity, p) = copyto!(q, p) +inverse_apply!(::TranslationAction, q, e::Identity{AdditionOperation}, p) = copyto!(q, p) apply_diff(::TranslationAction, a, p, X) = X From 02801a6358a2f57a534e141066b90cfe7443e9ab Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Fri, 30 Jul 2021 10:25:03 +0200 Subject: [PATCH 55/88] formatting --- src/groups/special_euclidean.jl | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index 906ddfc461..548ba3deb6 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -135,7 +135,10 @@ function affine_matrix(G::SpecialEuclidean{n}, p) where {n} return pmat end affine_matrix(::SpecialEuclidean{n}, p::AbstractMatrix) where {n} = p -function affine_matrix(::GT, ::Identity{<:SemidirectProductOperation}) where {n,GT<:SpecialEuclidean{n}} +function affine_matrix( + ::GT, + ::Identity{<:SemidirectProductOperation}, +) where {n,GT<:SpecialEuclidean{n}} s = maybesize(Size(n, n)) s isa Size && return SDiagonal{n,Float64}(I) return Diagonal{Float64}(I, n) @@ -469,12 +472,26 @@ function translate_diff!(G::SpecialEuclidean, Y, p, q, X, ::RightAction) @inbounds _padvector!(G, Y) return Y end -function translate_diff!(G::SpecialEuclidean, Y, ::Identity{<:SemidirectProductOperation}, q, X, ::RightAction) +function translate_diff!( + G::SpecialEuclidean, + Y, + ::Identity{<:SemidirectProductOperation}, + q, + X, + ::RightAction, +) copyto!(G, Y, X) @inbounds _padvector!(G, Y) return Y end -function translate_diff!(G::SpecialEuclidean, Y, p, ::Identity{<:SemidirectProductOperation}, X, ::RightAction) +function translate_diff!( + G::SpecialEuclidean, + Y, + p, + ::Identity{<:SemidirectProductOperation}, + X, + ::RightAction, +) np, hp = submanifold_components(G, p) nX, hX = submanifold_components(G, X) nY, hY = submanifold_components(G, Y) @@ -482,7 +499,14 @@ function translate_diff!(G::SpecialEuclidean, Y, p, ::Identity{<:SemidirectProdu copyto!(nY, hX * np + nX) @inbounds _padvector!(G, Y) end -function translate_diff!(G::SpecialEuclidean, Y, ::Identity{Op}, ::Identity{Op}, X, ::RightAction) where {Op<:SemidirectProductOperation} +function translate_diff!( + G::SpecialEuclidean, + Y, + ::Identity{Op}, + ::Identity{Op}, + X, + ::RightAction, +) where {Op<:SemidirectProductOperation} copyto!(G, Y, X) @inbounds _padvector!(G, Y) return Y From badac33081f3e924924c7d059e2fb3c81cb6b1fb Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Fri, 30 Jul 2021 10:33:12 +0200 Subject: [PATCH 56/88] disambiguation --- src/groups/semidirect_product_group.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index bfd8c145b1..d8ac79aab7 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -77,6 +77,9 @@ function is_identity(G::SemidirectProductGroup, p; kwargs...) nq, hq = submanifold_components(G, p) return is_identity(N, nq; kwargs...) && is_identity(H, hq; kwargs...) end +function is_identity(G::SemidirectProductGroup, e::Identity; kwargs...) + return invoke(is_identity, Tuple{AbstractGroupManifold,typeof(e)}, G, e; kwargs...) +end function Base.show(io::IO, G::SemidirectProductGroup) M = base_manifold(G) From 2a31b147b8fe56c7a5673647768984da56efd20e Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Fri, 30 Jul 2021 13:14:45 +0200 Subject: [PATCH 57/88] a bit more testing --- src/groups/group.jl | 84 +++++++++--- test/groups/groups_general.jl | 244 +++++++++++++++++----------------- 2 files changed, 186 insertions(+), 142 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index e420e403a1..36b82b0ff0 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -259,10 +259,20 @@ function is_identity( end is_identity(::AbstractGroupManifold, ::Identity; kwargs...) = false -function isapprox(G::AbstractGroupManifold{𝔽,O}, p::Identity{O}, q; kwargs...) where {𝔽,O} +function isapprox( + G::AbstractGroupManifold{𝔽,O}, + p::Identity{O}, + q; + kwargs..., +) where {𝔽,O<:AbstractGroupOperation} return isapprox(G, identity_element(G), q; kwargs...) end -function isapprox(G::AbstractGroupManifold{𝔽,O}, p, q::Identity{O}; kwargs...) where {𝔽,O} +function isapprox( + G::AbstractGroupManifold{𝔽,O}, + p, + q::Identity{O}; + kwargs..., +) where {𝔽,O<:AbstractGroupOperation} return isapprox(G, p, identity_element(G); kwargs...) end function isapprox( @@ -270,7 +280,7 @@ function isapprox( p::Identity{O}, q::Identity{O}; kwargs..., -) where {𝔽,O} +) where {𝔽,O<:AbstractGroupOperation} return true end function isapprox( @@ -279,13 +289,19 @@ function isapprox( X, Y; kwargs..., -) where {𝔽,O} +) where {𝔽,O<:AbstractGroupOperation} return isapprox(G, identity_element(G), X, Y; kwargs...) end -Base.show(io::IO, ::Identity{O}) where {O} = print(io, "Identity($O)") +function Base.show(io::IO, ::Identity{O}) where {O<:AbstractGroupOperation} + return print(io, "Identity($O)") +end -function check_point(G::AbstractGroupManifold{𝔽,O}, e::Identity{O}; kwargs...) where {𝔽,M,O} +function check_point( + G::AbstractGroupManifold{𝔽,O}, + e::Identity{O}; + kwargs..., +) where {𝔽,M,O<:AbstractGroupOperation} return nothing end @@ -293,18 +309,13 @@ function check_point( G::AbstractGroupManifold{𝔽,O1}, e::Identity{O2}; kwargs..., -) where {𝔽,M,O1,O2} +) where {𝔽,M,O1<:AbstractGroupOperation,O2<:AbstractGroupOperation} return DomainError( e, "The Identity $e does not lie on $G, since its the identity with respect to $O2 and not $O1.", ) end -Base.copyto!(::GroupManifold{𝔽,M,O}, e::Identity{O}, ::Identity{O}) where {𝔽,M,O} = e -function Base.copyto!(G::GroupManifold{𝔽,M,O}, p, ::Identity{O}) where {𝔽,M,O} - return identity_element!(G, p) -end - ########################## # Group-specific functions ########################## @@ -363,20 +374,47 @@ Base.inv(::AbstractGroupManifold, e::Identity) = e return inv!(G.manifold, q, p) end -inv!(G::AbstractGroupManifold, q, ::Identity) = identity_element!(G, q) +function inv!( + G::AbstractGroupManifold{𝔽,O}, + q, + ::Identity{O}, +) where {𝔽,O<:AbstractGroupOperation} + return identity_element!(G, q) +end -function Base.isapprox(G::AbstractGroupManifold, e::Identity, p; kwargs...) +function Base.isapprox( + G::AbstractGroupManifold{𝔽,O}, + e::Identity{O}, + p; + kwargs..., +) where {𝔽,O<:AbstractGroupOperation} return isapprox(G, identity_element(G, p), p; kwargs...) end function Base.isapprox(G::AbstractGroupManifold, p, e::Identity; kwargs...) return isapprox(G, e, p; kwargs...) end -Base.isapprox(::AbstractGroupManifold, ::Identity, ::Identity; kwargs...) = true - -Base.one(e::Identity) = e +function Base.isapprox( + ::AbstractGroupManifold{𝔽,O}, + ::Identity{O}, + ::Identity{O}; + kwargs..., +) where {𝔽,O<:AbstractGroupOperation} + return true +end +Base.isapprox(::AbstractGroupManifold, ::Identity, ::Identity; kwargs...) = false -Base.copyto!(::AbstractGroupManifold{𝔽,O}, e::Identity{O}, ::Identity{O}) where {𝔽,O} = e -function Base.copyto!(G::AbstractGroupManifold{𝔽,O}, p, ::Identity{O}) where {𝔽,O} +function Base.copyto!( + ::AbstractGroupManifold{𝔽,O}, + e::Identity{O}, + ::Identity{O}, +) where {𝔽,O<:AbstractGroupOperation} + return e +end +function Base.copyto!( + G::AbstractGroupManifold{𝔽,O}, + p, + ::Identity{O}, +) where {𝔽,O<:AbstractGroupOperation} return identity_element!(G, p) end @@ -999,6 +1037,9 @@ inv!(::AdditionGroup, q::Identity, e::Identity) = q function is_identity(G::AdditionGroup, q; kwargs...) return isapprox(G, q, zero(q); kwargs...) end +function is_identity(G::AdditionGroup, e::Identity; kwargs...) + return invoke(is_identity, Tuple{AbstractGroupManifold,typeof(e)}, G, e; kwargs...) +end _compose(::AdditionGroup, p, q) = p + q @@ -1075,6 +1116,9 @@ end function is_identity(G::MultiplicationGroup, q::AbstractMatrix; kwargs...) return isapprox(G, q, I; kwargs...) end +function is_identity(G::MultiplicationGroup, e::Identity; kwargs...) + return invoke(is_identity, Tuple{AbstractGroupManifold,typeof(e)}, G, e; kwargs...) +end LinearAlgebra.mul!(q, ::Identity{MultiplicationOperation}, p) = copyto!(q, p) LinearAlgebra.mul!(q, p, ::Identity{MultiplicationOperation}) = copyto!(q, p) @@ -1100,6 +1144,8 @@ function LinearAlgebra.mul!( return q end +Base.one(e::Identity{MultiplicationOperation}) = e + Base.inv(::MultiplicationGroup, p) = inv(p) Base.inv(::MultiplicationGroup, e::Identity{MultiplicationOperation}) = e diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index b395107fa8..22d6d3ad8b 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -13,8 +13,8 @@ include("group_utils.jl") G = GroupManifold(NotImplementedManifold(), NotImplementedOperation()) @test repr(G) == "GroupManifold(NotImplementedManifold(), NotImplementedOperation())" - x = [1.0, 2.0] - v = [2.0, 3.0] + p = [1.0, 2.0] + X = [2.0, 3.0] eg = Identity(G) @test repr(eg) === "Identity(NotImplementedOperation)" @test number_eltype(eg) == Bool @@ -23,29 +23,27 @@ include("group_utils.jl") @test isapprox(G, eg, eg) @test length(methods(is_group_decorator)) == 1 + @test Identity(NotImplementedOperation()) === eg + @test Identity(NotImplementedOperation) === eg + @test !is_point(G, Identity(AdditionOperation())) + @test !isapprox(G, eg, Identity(AdditionOperation())) + @test Manifolds.is_group_decorator(G) @test Manifolds.decorator_group_dispatch(G) === Val{true}() @test Manifolds.default_decorator_dispatch(G) === Val{false}() @test !Manifolds.is_group_decorator(NotImplementedManifold()) @test Manifolds.decorator_group_dispatch(NotImplementedManifold()) === Val{false}() - @test Manifolds.decorator_transparent_dispatch(compose, G, x, x, x) === + @test Manifolds.decorator_transparent_dispatch(compose, G, p, p, p) === Val{:intransparent}() - @test Manifolds.decorator_transparent_dispatch(compose!, G, x, x, x) === + @test Manifolds.decorator_transparent_dispatch(compose!, G, p, p, p) === Val{:intransparent}() - @test Manifolds.decorator_transparent_dispatch(exp_lie, G, x, x) === + @test Manifolds.decorator_transparent_dispatch(exp_lie, G, p, p) === Val{:intransparent}() - @test Manifolds.decorator_transparent_dispatch(log_lie, G, x, x) === + @test Manifolds.decorator_transparent_dispatch(log_lie, G, p, p) === + Val{:intransparent}() + @test Manifolds.decorator_transparent_dispatch(translate_diff!, G, X, p, p, X) === Val{:intransparent}() - @test Manifolds.decorator_transparent_dispatch( - translate_diff!, - G, - x, - x, - x, - x, - x, - ) === Val{:intransparent}() @test base_group(G) === G @test NotImplementedOperation(NotImplementedManifold()) === G @test (NotImplementedOperation())(NotImplementedManifold()) === G @@ -67,56 +65,56 @@ include("group_utils.jl") [1, 2, 3], ) - @test_throws ErrorException inv!(G, x, x) - @test_throws MethodError inv!(G, x, eg) - @test_throws ErrorException inv(G, x) + @test_throws ErrorException inv!(G, p, p) + @test_throws MethodError inv!(G, p, eg) + @test_throws ErrorException inv(G, p) # no function defined to return the identity array representation - @test_throws MethodError copyto!(G, x, eg) + @test_throws MethodError copyto!(G, p, eg) - @test_throws MethodError compose(G, x, x) - @test compose(G, x, eg) == x - xO = deepcopy(x) - compose!(G, x, eg, x) - @test xO == x - compose!(G, x, x, eg) - @test xO == x - @test_throws MethodError compose!(G, x, x, x) - @test_throws MethodError compose!(G, x, eg, eg) + @test_throws MethodError compose(G, p, p) + @test compose(G, p, eg) == p + xO = deepcopy(p) + compose!(G, p, eg, p) + @test xO == p + compose!(G, p, p, eg) + @test xO == p + @test_throws MethodError compose!(G, p, p, p) + @test_throws MethodError compose!(G, p, eg, eg) - @test_throws MethodError translate(G, x, x) - @test_throws MethodError translate(G, x, x, LeftAction()) - @test_throws MethodError translate(G, x, x, RightAction()) - @test_throws MethodError translate!(G, x, x, x) - @test_throws MethodError translate!(G, x, x, x, LeftAction()) - @test_throws MethodError translate!(G, x, x, x, RightAction()) + @test_throws MethodError translate(G, p, p) + @test_throws MethodError translate(G, p, p, LeftAction()) + @test_throws MethodError translate(G, p, p, RightAction()) + @test_throws MethodError translate!(G, p, p, p) + @test_throws MethodError translate!(G, p, p, p, LeftAction()) + @test_throws MethodError translate!(G, p, p, p, RightAction()) - @test_throws ErrorException inverse_translate(G, x, x) - @test_throws ErrorException inverse_translate(G, x, x, LeftAction()) - @test_throws ErrorException inverse_translate(G, x, x, RightAction()) - @test_throws ErrorException inverse_translate!(G, x, x, x) - @test_throws ErrorException inverse_translate!(G, x, x, x, LeftAction()) - @test_throws ErrorException inverse_translate!(G, x, x, x, RightAction()) + @test_throws ErrorException inverse_translate(G, p, p) + @test_throws ErrorException inverse_translate(G, p, p, LeftAction()) + @test_throws ErrorException inverse_translate(G, p, p, RightAction()) + @test_throws ErrorException inverse_translate!(G, p, p, p) + @test_throws ErrorException inverse_translate!(G, p, p, p, LeftAction()) + @test_throws ErrorException inverse_translate!(G, p, p, p, RightAction()) - @test_throws ErrorException translate_diff(G, x, x, v) - @test_throws ErrorException translate_diff(G, x, x, v, LeftAction()) - @test_throws ErrorException translate_diff(G, x, x, v, RightAction()) - @test_throws ErrorException translate_diff!(G, v, x, x, v) - @test_throws ErrorException translate_diff!(G, v, x, x, v, LeftAction()) - @test_throws ErrorException translate_diff!(G, v, x, x, v, RightAction()) + @test_throws ErrorException translate_diff(G, p, p, X) + @test_throws ErrorException translate_diff(G, p, p, X, LeftAction()) + @test_throws ErrorException translate_diff(G, p, p, X, RightAction()) + @test_throws ErrorException translate_diff!(G, X, p, p, X) + @test_throws ErrorException translate_diff!(G, X, p, p, X, LeftAction()) + @test_throws ErrorException translate_diff!(G, X, p, p, X, RightAction()) - @test_throws ErrorException inverse_translate_diff(G, x, x, v) - @test_throws ErrorException inverse_translate_diff(G, x, x, v, LeftAction()) - @test_throws ErrorException inverse_translate_diff(G, x, x, v, RightAction()) - @test_throws ErrorException inverse_translate_diff!(G, v, x, x, v) - @test_throws ErrorException inverse_translate_diff!(G, v, x, x, v, LeftAction()) - @test_throws ErrorException inverse_translate_diff!(G, v, x, x, v, RightAction()) + @test_throws ErrorException inverse_translate_diff(G, p, p, X) + @test_throws ErrorException inverse_translate_diff(G, p, p, X, LeftAction()) + @test_throws ErrorException inverse_translate_diff(G, p, p, X, RightAction()) + @test_throws ErrorException inverse_translate_diff!(G, X, p, p, X) + @test_throws ErrorException inverse_translate_diff!(G, X, p, p, X, LeftAction()) + @test_throws ErrorException inverse_translate_diff!(G, X, p, p, X, RightAction()) - @test_throws ErrorException exp_lie(G, v) - @test_throws ErrorException exp_lie!(G, x, v) + @test_throws ErrorException exp_lie(G, X) + @test_throws ErrorException exp_lie!(G, p, X) # no transparency error, but _log_lie missing - @test_throws MethodError log_lie(G, x) - @test_throws MethodError log_lie!(G, v, x) + @test_throws MethodError log_lie(G, p) + @test_throws MethodError log_lie!(G, X, p) for f in [translate, translate!] @test Manifolds.decorator_transparent_dispatch(f, G) === Val{:intransparent}() @@ -125,15 +123,15 @@ include("group_utils.jl") @test Manifolds.decorator_transparent_dispatch(f, G) === Val{:transparent}() end for f in [exp_lie!, exp_lie, log_lie, log_lie!] - @test Manifolds.decorator_transparent_dispatch(f, G, x, x) === + @test Manifolds.decorator_transparent_dispatch(f, G, p, p) === Val{:intransparent}() end for f in [get_vector, get_coordinates] @test Manifolds.decorator_transparent_dispatch(f, G) === Val{:parent}() end - @test Manifolds.decorator_transparent_dispatch(isapprox, G, eg, x) === + @test Manifolds.decorator_transparent_dispatch(isapprox, G, eg, p) === Val{:transparent}() - @test Manifolds.decorator_transparent_dispatch(isapprox, G, x, eg) === + @test Manifolds.decorator_transparent_dispatch(isapprox, G, p, eg) === Val{:transparent}() @test Manifolds.decorator_transparent_dispatch(isapprox, G, eg, eg) === Val{:transparent}() @@ -157,38 +155,38 @@ include("group_utils.jl") test_exp_lie_log=false, # there is no identity element so log/exp on Lie do not work ) - x = [1.0, 2.0] - v = [3.0, 4.0] + p = [1.0, 2.0] + X = [3.0, 4.0] ge = Identity(G) @test number_eltype(ge) == Bool - y = allocate(x) + y = allocate(p) copyto!(G, y, ge) - @test y ≈ zero(x) - @test ge - x == -x - @test x - ge === x + @test y ≈ zero(p) + @test ge - p == -p + @test p - ge === p @test ge - ge === ge - @test ge + x ≈ x - @test x + ge ≈ x + @test ge + p ≈ p + @test p + ge ≈ p @test ge + ge === ge @test -(ge) === ge @test +(ge) === ge @test ge * 1 === ge @test 1 * ge === ge @test ge * ge === ge - @test inv(G, x) ≈ -x + @test inv(G, p) ≈ -p @test inv(G, ge) === ge - @test compose(G, x, x) ≈ x + x - @test compose(G, x, ge) ≈ x - @test compose(G, ge, x) ≈ x + @test compose(G, p, p) ≈ p + p + @test compose(G, p, ge) ≈ p + @test compose(G, ge, p) ≈ p @test compose(G, ge, ge) == ge - compose!(G, y, x, x) - @test y ≈ x + x - compose!(G, y, x, ge) - @test y ≈ x - compose!(G, y, ge, x) - @test y ≈ x - @test exp_lie(G, v) === v - @test log_lie(G, x) === x + compose!(G, y, p, p) + @test y ≈ p + p + compose!(G, y, p, ge) + @test y ≈ p + compose!(G, y, ge, p) + @test y ≈ p + @test exp_lie(G, X) === X + @test log_lie(G, p) === p end @testset "Multiplication operation" begin @@ -201,62 +199,62 @@ include("group_utils.jl") test_exp_lie_log=false, # no identity available as array ) - x = [2.0 1.0; 2.0 3.0] + p = [2.0 1.0; 2.0 3.0] ge = Identity(G) @test number_eltype(ge) == Bool @test copyto!(G, ge, ge) === ge - y = allocate(x) + y = allocate(p) identity_element!(G, y) - @test y ≈ one(x) + @test y ≈ one(p) @test one(ge) === ge @test transpose(ge) === ge @test det(ge) == 1 - @test ge * x ≈ x - @test x * ge ≈ x + @test ge * p ≈ p + @test p * ge ≈ p @test ge * ge === ge @test inv(G, ge) === ge @test *(ge) === ge - @test x / ge ≈ x - @test ge \ x ≈ x + @test p / ge ≈ p + @test ge \ p ≈ p @test ge / ge === ge @test ge \ ge === ge - @test ge / x ≈ inv(G, x) - @test x \ ge ≈ inv(G, x) - y = allocate(x) - @test LinearAlgebra.mul!(y, x, ge) === y - @test y ≈ x - y = allocate(x) - @test LinearAlgebra.mul!(y, ge, x) === y - @test y ≈ x - y = allocate(x) + @test ge / p ≈ inv(G, p) + @test p \ ge ≈ inv(G, p) + y = allocate(p) + @test LinearAlgebra.mul!(y, p, ge) === y + @test y ≈ p + y = allocate(p) + @test LinearAlgebra.mul!(y, ge, p) === y + @test y ≈ p + y = allocate(p) @test LinearAlgebra.mul!(y, ge, ge) === y @test y ≈ one(y) - @test inv(G, x) ≈ inv(x) + @test inv(G, p) ≈ inv(p) @test inv(G, ge) === ge - z = allocate(x) - copyto!(G, z, x) - z2 = allocate(x) - copyto!(G.manifold, z2, x) + z = allocate(p) + copyto!(G, z, p) + z2 = allocate(p) + copyto!(G.manifold, z2, p) @test z == z2 X = zeros(2, 2) Y = allocate(X) - copyto!(G, Y, x, X) + copyto!(G, Y, p, X) Y2 = allocate(X) - copyto!(G.manifold, Y2, x, X) + copyto!(G.manifold, Y2, p, X) @test Y == Y2 - @test compose(G, x, x) ≈ x * x - @test compose(G, x, ge) ≈ x - @test compose(G, ge, x) ≈ x + @test compose(G, p, p) ≈ p * p + @test compose(G, p, ge) ≈ p + @test compose(G, ge, p) ≈ p @test compose(G, ge, ge) == ge - compose!(G, y, x, x) - @test y ≈ x * x - compose!(G, y, x, ge) - @test y ≈ x - compose!(G, y, ge, x) - @test y ≈ x + compose!(G, y, p, p) + @test y ≈ p * p + compose!(G, y, p, ge) + @test y ≈ p + compose!(G, y, ge, p) + @test y ≈ p X = [1.0 2.0; 3.0 4.0] @test exp_lie!(G, y, X) === y @test_throws ErrorException exp_lie!(G, y, :a) @@ -300,23 +298,23 @@ struct NotImplementedAction <: AbstractGroupAction{LeftAction} end @testset "General group action tests" begin @testset "Not implemented operations" begin A = NotImplementedAction() - x = [1.0, 2.0] + p = [1.0, 2.0] a = [1.0, 2.0] - v = [1.0, 2.0] + X = [1.0, 2.0] @test_throws ErrorException base_group(A) @test_throws ErrorException g_manifold(A) - @test_throws ErrorException apply(A, a, x) - @test_throws ErrorException apply!(A, x, a, x) - @test_throws ErrorException inverse_apply(A, a, x) - @test_throws ErrorException inverse_apply!(A, x, a, x) - @test_throws ErrorException apply_diff(A, a, x, v) - @test_throws ErrorException apply_diff!(A, v, x, a, v) - @test_throws ErrorException inverse_apply_diff(A, a, x, v) - @test_throws ErrorException inverse_apply_diff!(A, v, x, a, v) + @test_throws ErrorException apply(A, a, p) + @test_throws ErrorException apply!(A, p, a, p) + @test_throws ErrorException inverse_apply(A, a, p) + @test_throws ErrorException inverse_apply!(A, p, a, p) + @test_throws ErrorException apply_diff(A, a, p, X) + @test_throws ErrorException apply_diff!(A, X, p, a, X) + @test_throws ErrorException inverse_apply_diff(A, a, p, X) + @test_throws ErrorException inverse_apply_diff!(A, X, p, a, X) @test_throws ErrorException compose(A, a, a) @test_throws ErrorException compose!(A, a, a, a) - @test_throws ErrorException optimal_alignment(A, x, x) - @test_throws ErrorException optimal_alignment!(A, a, x, x) + @test_throws ErrorException optimal_alignment(A, p, p) + @test_throws ErrorException optimal_alignment!(A, a, p, p) end end From a23dfeba19d03e4657efb831fc7bf5412c0472ea Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Fri, 30 Jul 2021 13:22:34 +0200 Subject: [PATCH 58/88] group isapprox cleanup --- src/groups/group.jl | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index 36b82b0ff0..ac5e2ea3e8 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -292,6 +292,10 @@ function isapprox( ) where {𝔽,O<:AbstractGroupOperation} return isapprox(G, identity_element(G), X, Y; kwargs...) end +function Base.isapprox(G::AbstractGroupManifold, p, e::Identity; kwargs...) + return isapprox(G, e, p; kwargs...) +end +Base.isapprox(::AbstractGroupManifold, ::Identity, ::Identity; kwargs...) = false function Base.show(io::IO, ::Identity{O}) where {O<:AbstractGroupOperation} return print(io, "Identity($O)") @@ -382,27 +386,6 @@ function inv!( return identity_element!(G, q) end -function Base.isapprox( - G::AbstractGroupManifold{𝔽,O}, - e::Identity{O}, - p; - kwargs..., -) where {𝔽,O<:AbstractGroupOperation} - return isapprox(G, identity_element(G, p), p; kwargs...) -end -function Base.isapprox(G::AbstractGroupManifold, p, e::Identity; kwargs...) - return isapprox(G, e, p; kwargs...) -end -function Base.isapprox( - ::AbstractGroupManifold{𝔽,O}, - ::Identity{O}, - ::Identity{O}; - kwargs..., -) where {𝔽,O<:AbstractGroupOperation} - return true -end -Base.isapprox(::AbstractGroupManifold, ::Identity, ::Identity; kwargs...) = false - function Base.copyto!( ::AbstractGroupManifold{𝔽,O}, e::Identity{O}, From 3577cab3da74e43de7483309eb21ff9d25775346 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 30 Jul 2021 13:30:20 +0200 Subject: [PATCH 59/88] fix docs. --- src/groups/group.jl | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index e420e403a1..85f8820975 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -9,10 +9,7 @@ An operation can be either defined for a specific [`AbstractGroupManifold`](@ref number system `𝔽` or in general, by defining for an operation `Op` the following methods: identity_element!(::AbstractGroupManifold{𝔽,Op}, q, q) - identity_element(::AbstractGroupManifold{𝔽,Op} [, q]) inv!(::AbstractGroupManifold{𝔽,Op}, q, p) - inv(::AbstractGroupManifold{𝔽,Op}, p) - _compose(::AbstractGroupManifold{𝔽,Op}, p, q) _compose!(::AbstractGroupManifold{𝔽,Op}, x, p, q) Note that a manifold is connected with an operation by wrapping it with a decorator, @@ -179,9 +176,9 @@ See also [`identity_element`](@ref) on how to obtain the corresponding [`Abstrac # Constructors -Identity(G::AbstractGroupManifold{𝔽,O}) -Identity(o::O) -Identity(::Type{O}) + Identity(G::AbstractGroupManifold{𝔽,O}) + Identity(o::O) + Identity(::Type{O}) create the identity of the corresponding subtype `O<:`[`AbstractGroupOperation`](@ref) """ @@ -220,10 +217,8 @@ end @doc raw""" identity_element(G::AbstractGroupManifold, p) -Return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G` -(in place of `p`). By default this representation is default array or number representation. -It rhoudl return the corresponding [`AbstractManifoldPoint`](@ref) of points on `G` if -points are not represented by arrays or numbers. +Return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G`, +where `p` indicates the type to represent the identity. """ function identity_element(G::AbstractGroupManifold, p) q = allocate_result(G, identity_element, p) From 4dd71725526a8f8991548c7ba4adaf562179fadf Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Fri, 30 Jul 2021 14:45:44 +0200 Subject: [PATCH 60/88] fixing some Identity bugs --- src/groups/general_linear.jl | 6 +++++- src/groups/group.jl | 4 ++-- src/groups/product_group.jl | 3 +++ src/groups/special_linear.jl | 6 +++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/groups/general_linear.jl b/src/groups/general_linear.jl index fa1a9fff23..722ba2cbe4 100644 --- a/src/groups/general_linear.jl +++ b/src/groups/general_linear.jl @@ -38,7 +38,11 @@ function check_point(G::GeneralLinear, p; kwargs...) return nothing end check_point(::GeneralLinear, ::Identity{MultiplicationOperation}) = nothing -function check_point(G::GeneralLinear, e::Identity{O}; kwargs...) where {O} +function check_point( + G::GeneralLinear, + e::Identity{O}; + kwargs..., +) where {O<:AbstractGroupOperation} return invoke(check_point, Tuple{AbstractGroupManifold,typeof(e)}, G, e; kwargs...) end diff --git a/src/groups/group.jl b/src/groups/group.jl index 6356fb71b7..deff09451d 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -260,7 +260,7 @@ function isapprox( q; kwargs..., ) where {𝔽,O<:AbstractGroupOperation} - return isapprox(G, identity_element(G), q; kwargs...) + return is_identity(G, q; kwargs...) end function isapprox( G::AbstractGroupManifold{𝔽,O}, @@ -268,7 +268,7 @@ function isapprox( q::Identity{O}; kwargs..., ) where {𝔽,O<:AbstractGroupOperation} - return isapprox(G, p, identity_element(G); kwargs...) + return is_identity(G, p; kwargs...) end function isapprox( G::AbstractGroupManifold{𝔽,O}, diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 7ff702d354..12b9c77c20 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -50,6 +50,9 @@ function is_identity(G::ProductGroup, p; kwargs...) M = G.manifold # Inner prodct manifold (of groups) return all(map((M, pe) -> is_identity(M, pe; kwargs...), M.manifolds, pes)) end +function is_identity(G::ProductGroup, e::Identity; kwargs...) + return invoke(is_identity, Tuple{AbstractGroupManifold,typeof(e)}, G, e; kwargs...) +end function Base.show(io::IO, ::MIME"text/plain", G::ProductGroup) print( diff --git a/src/groups/special_linear.jl b/src/groups/special_linear.jl index f53c23ecba..543577ebb1 100644 --- a/src/groups/special_linear.jl +++ b/src/groups/special_linear.jl @@ -43,7 +43,11 @@ function check_point(G::SpecialLinear{n,𝔽}, p; kwargs...) where {n,𝔽} return nothing end check_point(G::SpecialLinear, ::Identity{MultiplicationOperation}; kwargs...) = nothing -function check_point(G::SpecialLinear, e::Identity{O}; kwargs...) where {O} +function check_point( + G::SpecialLinear, + e::Identity{O}; + kwargs..., +) where {O<:AbstractGroupOperation} return invoke(check_point, Tuple{AbstractGroupManifold,typeof(e)}, G, e; kwargs...) end From ca9c1fc45906c691fce60166de4db7e0bff1e92b Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Fri, 30 Jul 2021 22:17:11 +0200 Subject: [PATCH 61/88] more tests --- src/groups/group.jl | 13 ++++++++++--- src/tests/tests_group.jl | 5 +++-- test/groups/circle_group.jl | 4 ++++ test/groups/groups_general.jl | 5 +++++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index deff09451d..f28d2f653c 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -1009,8 +1009,8 @@ Base.inv(::AdditionGroup, p) = -p Base.inv(::AdditionGroup, e::Identity) = e inv!(G::AdditionGroup, q, p) = copyto!(G, q, -p) -inv!(G::AdditionGroup, q, ::Identity) = identity_element!(G, q) -inv!(::AdditionGroup, q::Identity, e::Identity) = q +inv!(G::AdditionGroup, q, ::Identity{AdditionOperation}) = identity_element!(G, q) +inv!(::AdditionGroup, q::Identity{AdditionOperation}, e::Identity{AdditionOperation}) = q function is_identity(G::AdditionGroup, q; kwargs...) return isapprox(G, q, zero(q); kwargs...) @@ -1081,7 +1081,7 @@ Base.:\(e::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation LinearAlgebra.det(::Identity{MultiplicationOperation}) = 1 -function identity_element!(::MultiplicationGroup, p) +function identity_element!(::MultiplicationGroup, p::AbstractMatrix) return copyto!(p, I) end @@ -1131,6 +1131,13 @@ inv!(G::MultiplicationGroup, q, p) = copyto!(q, inv(G, p)) function inv!(G::MultiplicationGroup, q, ::Identity{MultiplicationOperation}) return identity_element!(G, q) end +function inv!( + ::MultiplicationGroup, + q::Identity{MultiplicationOperation}, + e::Identity{MultiplicationOperation}, +) + return q +end _compose(::MultiplicationGroup, p, q) = p * q diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index 5604058ba1..05b1842db6 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -112,6 +112,7 @@ function test_group( Test.@test inv(G, e) === e test_mutating && Test.@testset "mutating" begin + Test.@test inv!(G, e, e) === e ginv = allocate(g) Test.@test inv!(G, ginv, g) === ginv Test.@test is_identity(G, compose(G, g, ginv); atol=atol) @@ -601,11 +602,11 @@ function test_action( Test.@test compose!(A, h, e, a) === h Test.@test isapprox(G, h, a) - ge = Identity(G) + ge = identity_element(G, a) Test.@test isapprox(G, compose(A, a, ge), a) Test.@test isapprox(G, compose(A, ge, a), a) - ge = Identity(G) + ge = allocate(a) Test.@test compose!(A, ge, e, e) === ge Test.@test isapprox(G, ge, e) diff --git a/test/groups/circle_group.jl b/test/groups/circle_group.jl index 7333492d13..2d159c403c 100644 --- a/test/groups/circle_group.jl +++ b/test/groups/circle_group.jl @@ -25,6 +25,10 @@ using Manifolds: invariant_metric_dispatch, default_metric_dispatch y = [1.0 * im] v = [Complex(0.5)] @test translate_diff(G, ig, y, v) === v + + @test identity_element(G) === 1.0 + @test identity_element(G, 1.0f0) === 1.0f0 + @test identity_element(G, [1.0f0]) == [1.0f0] end @testset "scalar points" begin diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 22d6d3ad8b..ecc6432523 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -270,6 +270,11 @@ include("group_utils.jl") @test get_vector_lie(G, ones(3), DefaultOrthogonalBasis()) == ones(3) @test e - e == e @test ones(3) + e == ones(3) + e_add = Identity(AdditionOperation) + e_mul = Identity(MultiplicationOperation) + @test e_add * e_mul === e_add + @test e_mul * e_add === e_add + @test mul!(e_mul, e_mul, e_mul) === e_mul end @testset "Transparency tests" begin From e130a00a53247487034e9416f40584ce4ef13e68 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 30 Jul 2021 22:25:31 +0200 Subject: [PATCH 62/88] More product manifold identity tests. --- src/groups/product_group.jl | 3 ++- test/groups/product_group.jl | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 12b9c77c20..1b5853045b 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -74,8 +74,9 @@ function submanifold_component( ::Identity{O}, ::Val{I}, ) where {I,MT<:ProductManifold,𝔽,O} + M = G.manifold # the identity on a product manifold with is a group consists of a tuple of identities - return Identity(G.manifolds[I]) + return Identity(M.manifolds[I]) end function submanifold_components( diff --git a/test/groups/product_group.jl b/test/groups/product_group.jl index 18a61e6caa..63be54928d 100644 --- a/test/groups/product_group.jl +++ b/test/groups/product_group.jl @@ -26,6 +26,13 @@ include("group_utils.jl") shape_se = Manifolds.ShapeSpecification(Manifolds.ArrayReshaper(), M.manifolds...) e = Manifolds.prod_point(shape_se, eA...) + @testset "Product Identity" begin + i = Identity(G) + @test submanifold_components(G, i) == (Identity(SOn), Identity(Tn)) + @test submanifold_component(G, i, 1) == Identity(SOn) + @test submanifold_component(G, i, 2) == Identity(Tn) + end + @testset "product point" begin reshapers = (Manifolds.ArrayReshaper(), Manifolds.StaticReshaper()) for reshaper in reshapers From 2b6e88118c95254a95aa99c04821fa304d22219c Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 31 Jul 2021 07:58:12 +0200 Subject: [PATCH 63/88] remove an ambiguous function, that is now implemented a level higher. --- src/groups/special_linear.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/groups/special_linear.jl b/src/groups/special_linear.jl index 543577ebb1..2e8b17646c 100644 --- a/src/groups/special_linear.jl +++ b/src/groups/special_linear.jl @@ -25,10 +25,6 @@ function allocation_promotion_function(::SpecialLinear{n,ℂ}, f, args::Tuple) w return complex end -function identity_element!(::SpecialLinear, q) where {n,𝔽} - return copyto!(q, I) -end - function check_point(G::SpecialLinear{n,𝔽}, p; kwargs...) where {n,𝔽} mpv = check_point(Euclidean(n, n; field=𝔽), p; kwargs...) mpv === nothing || return mpv From 162b7540b257af3335b22bf12a630de3d9186354 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 31 Jul 2021 08:06:28 +0200 Subject: [PATCH 64/88] add a case that I thought was covered for the abstract case, but it was not. --- src/groups/semidirect_product_group.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index d8ac79aab7..572bd04f48 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -109,6 +109,13 @@ end function inv!(G::SemidirectProductGroup, q, ::Identity{<:SemidirectProductOperation}) return identity_element!(G, q) end +function inv!( + G::SemidirectProductGroup, + q::Identity{<:SemidirectProductOperation}, + ::Identity{<:SemidirectProductOperation}, +) + return q +end function _compose!(G::SemidirectProductGroup, x, p, q) M = base_manifold(G) From 8423fbddd51bd5c9f2d86d222bbeb53cd0c2b3bb Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 31 Jul 2021 08:23:57 +0200 Subject: [PATCH 65/88] Fix another special case that I thought was handled already a level higher. --- src/groups/product_group.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 1b5853045b..8a2b3775bb 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -93,6 +93,7 @@ function inv!(G::ProductGroup, q, p) map(inv!, M.manifolds, submanifold_components(G, q), submanifold_components(G, p)) return q end +inv!(::ProductGroup, q::Identity{ProductOperation}, ::Identity{ProductOperation}) = q _compose(G::ProductGroup, p, q) = _compose(G.manifold, p, q) function _compose(M::ProductManifold, p::ProductRepr, q::ProductRepr) From fdbd03e0ca39da1d60f9c49a2f4a9af805ea0364 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 31 Jul 2021 23:10:41 +0200 Subject: [PATCH 66/88] removes a few unreached functions and increases coverage for the rest. --- src/groups/general_linear.jl | 2 +- src/groups/product_group.jl | 12 +----------- src/groups/semidirect_product_group.jl | 8 ++++---- test/groups/general_linear.jl | 2 ++ test/groups/product_group.jl | 16 ++++++++++++++++ test/groups/semidirect_product_group.jl | 7 +++++++ 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/groups/general_linear.jl b/src/groups/general_linear.jl index 722ba2cbe4..d9b8b92906 100644 --- a/src/groups/general_linear.jl +++ b/src/groups/general_linear.jl @@ -156,7 +156,7 @@ function exp_lie!(::GeneralLinear{1}, q, X) end exp_lie!(::GeneralLinear{2}, q, X) = copyto!(q, exp(SizedMatrix{2,2}(X))) -function _log_lie!(::GeneralLinear{1}, X::AbstractMatrix, p::AbstractMatrix) +function _log_lie!(::GeneralLinear{1}, X, p) X[1] = log(p[1]) return X end diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 8a2b3775bb..969fa2fb2d 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -263,20 +263,10 @@ function log_lie!(G::ProductGroup, X, q) map(log_lie!, M.manifolds, submanifold_components(G, X), submanifold_components(G, q)) return X end -function _log_lie(G::ProductGroup, q) - M = G.manifold - return ProductRepr(map(_log_lie, M.manifolds, submanifold_components(G, q))...) -end #overwrite identity case to avoid allocating identity too early. -function log_lie!(G::ProductGroup, X, q::Identity{<:ProductOperation}) +function log_lie!(G::ProductGroup, X, q::Identity{ProductOperation}) M = G.manifold map(log_lie!, M.manifolds, submanifold_components(G, X), submanifold_components(G, q)) return X end - -function _log_lie!(G::ProductGroup, X, q) - M = G.manifold - map(_log_lie!, M.manifolds, submanifold_components(G, X), submanifold_components(G, q)) - return X -end diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index 572bd04f48..21f615a433 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -25,10 +25,10 @@ const SemidirectProductGroup{𝔽,N,H,A} = @doc raw""" SemidirectProductGroup(N::GroupManifold, H::GroupManifold, A::AbstractGroupAction) -A group that is the semidirect product of a normal group $\mathcal{N}$ and a subgroup -$\mathcal{H}$, written $\mathcal{G} = \mathcal{N} ⋊_θ \mathcal{H}$, where -$θ: \mathcal{H} × \mathcal{N} → \mathcal{N}$ is an automorphism action of $\mathcal{H}$ on -$\mathcal{N}$. The group $\mathcal{G}$ has the composition rule +A group that is the semidirect product of a normal group ``\mathcal{N}`` and a subgroup +``\mathcal{H}``, written ``\mathcal{G} = \mathcal{N} ⋊_θ \mathcal{H}``, where +``θ: \mathcal{H} × \mathcal{N} → \mathcal{N}`` is an automorphism action of ``\mathcal{H}`` on +``\mathcal{N}``. The group ``\mathcal{G}`` has the composition rule ````math g \circ g' = (n, h) \circ (n', h') = (n \circ θ_h(n'), h \circ h') diff --git a/test/groups/general_linear.jl b/test/groups/general_linear.jl index 05ba9a07ad..df3b464624 100644 --- a/test/groups/general_linear.jl +++ b/test/groups/general_linear.jl @@ -56,6 +56,8 @@ using NLsolve @test Y ≈ X @test exp_lie(G, X) ≈ exp(X) @test log_lie(G, exp(X)) ≈ X + @test log_lie(G, [1.0]) == zeros(1) # vector to vector + log_lie(G, Identity(G)) == zeros(1, 1) # Matrix to matrix end @testset "complex" begin G = GeneralLinear(1, ℂ) diff --git a/test/groups/product_group.jl b/test/groups/product_group.jl index 63be54928d..f53ada520b 100644 --- a/test/groups/product_group.jl +++ b/test/groups/product_group.jl @@ -62,6 +62,22 @@ include("group_utils.jl") log_lie(Tn, pts[1].parts[2]), ), ) + X = log_lie(G, pts[1]) + Z = zero_vector(G, pts[1]) + log_lie!(G, Z, pts[1]) + @test isapprox(G, pts[1], X, Z) + p = exp_lie(G, X) + q = identity_element(G) + exp_lie!(G, q, X) + @test isapprox(G, p, q) + log_lie!(G, Z, Identity(G)) + @test isapprox(G, Identity(G), Z, zero_vector(G, identity_element(G))) + @test isapprox( + G, + Identity(G), + log_lie(G, Identity(G)), + zero_vector(G, identity_element(G)), + ) end end diff --git a/test/groups/semidirect_product_group.jl b/test/groups/semidirect_product_group.jl index 65e5be6631..54b20d74ee 100644 --- a/test/groups/semidirect_product_group.jl +++ b/test/groups/semidirect_product_group.jl @@ -37,4 +37,11 @@ include("group_utils.jl") @test compose(G, e, pts[1]) == pts[1] @test compose(G, pts[1], e) == pts[1] @test compose(G, e, e) === e + + eA = identity_element(G) + @test isapprox(G, eA, e) + @test isapprox(G, e, eA) + W = log(G, eA, pts[1]) + Z = log(G, eA, pts[1]) + @test isapprox(G, e, X, Z) end From b57b8c511fb81a4f954d75fb78518576577a6e2a Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 1 Aug 2021 07:17:31 +0200 Subject: [PATCH 67/88] Fix a typo. --- test/groups/semidirect_product_group.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/groups/semidirect_product_group.jl b/test/groups/semidirect_product_group.jl index 54b20d74ee..e04f2298fc 100644 --- a/test/groups/semidirect_product_group.jl +++ b/test/groups/semidirect_product_group.jl @@ -43,5 +43,5 @@ include("group_utils.jl") @test isapprox(G, e, eA) W = log(G, eA, pts[1]) Z = log(G, eA, pts[1]) - @test isapprox(G, e, X, Z) + @test isapprox(G, e, W, Z) end From 553ea13583bc11e32eea31502207d29637da0c6d Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Sun, 1 Aug 2021 11:00:42 +0200 Subject: [PATCH 68/88] one more test --- src/tests/tests_group.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index b826d194c2..98fb2f33c6 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -296,6 +296,8 @@ function test_group( X = log_lie(G, Identity(G)) g = exp_lie(G, X) Test.@test isapprox(G, Identity(G), g; atol=atol) + ep = identity_element(G, g) + Test.@test isapprox(G, ep, zero_vector(G, ep), log_lie(G, ep); atol=atol) test_mutating && Test.@testset "mutating" begin X = allocate(Xe_pts[1]) From a255de03f59b9c53773701fbe60fa5520542e3e6 Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Sun, 1 Aug 2021 14:18:14 +0200 Subject: [PATCH 69/88] forwarding of `identity_element` --- src/groups/group.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index f28d2f653c..542be2448e 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -220,7 +220,8 @@ end Return a point representation of the [`Identity`](@ref) on the [`AbstractGroupManifold`](@ref) `G`, where `p` indicates the type to represent the identity. """ -function identity_element(G::AbstractGroupManifold, p) +identity_element(G::AbstractGroupManifold, p) +@decorator_transparent_function function identity_element(G::AbstractGroupManifold, p) q = allocate_result(G, identity_element, p) return identity_element!(G, q) end From 3620105e78ce0e44c7d69c697272c282bf68187b Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 1 Aug 2021 16:59:36 +0200 Subject: [PATCH 70/88] remove a case that is already handles in 266+ --- src/groups/group.jl | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index 542be2448e..de6ed227d3 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -288,9 +288,6 @@ function isapprox( ) where {𝔽,O<:AbstractGroupOperation} return isapprox(G, identity_element(G), X, Y; kwargs...) end -function Base.isapprox(G::AbstractGroupManifold, p, e::Identity; kwargs...) - return isapprox(G, e, p; kwargs...) -end Base.isapprox(::AbstractGroupManifold, ::Identity, ::Identity; kwargs...) = false function Base.show(io::IO, ::Identity{O}) where {O<:AbstractGroupOperation} From c49a725cd80a9b330947adbf338a579250fd0edc Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 1 Aug 2021 16:59:50 +0200 Subject: [PATCH 71/88] increase test coverage. --- test/groups/general_linear.jl | 5 +++++ test/groups/groups_general.jl | 1 + test/groups/product_group.jl | 3 +++ test/groups/special_euclidean.jl | 22 ++++++++++++++++++++++ test/groups/special_orthogonal.jl | 6 ++++++ 5 files changed, 37 insertions(+) diff --git a/test/groups/general_linear.jl b/test/groups/general_linear.jl index df3b464624..e79e8678a9 100644 --- a/test/groups/general_linear.jl +++ b/test/groups/general_linear.jl @@ -43,6 +43,11 @@ using NLsolve ) ) === Val(true) @test Manifolds.allocation_promotion_function(Gc, exp!, (1,)) === complex + + q = identity_element(G) + @test is_identity(G, q) + @test isapprox(G, q, Identity(G)) + @test isapprox(G, Identity(G), q) end @testset "GL(1,𝔽) special cases" begin diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index ecc6432523..cf176ec0e6 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -20,6 +20,7 @@ include("group_utils.jl") @test number_eltype(eg) == Bool @test is_identity(G, eg) # identity transparent @test_throws MethodError identity_element(G) # but for a NotImplOp there is no concrete id. + @test_trows MethodError is_directed(G, 1) # same rror as before i.e. dispatch isapprox works @test isapprox(G, eg, eg) @test length(methods(is_group_decorator)) == 1 diff --git a/test/groups/product_group.jl b/test/groups/product_group.jl index f53ada520b..c61b31b99c 100644 --- a/test/groups/product_group.jl +++ b/test/groups/product_group.jl @@ -68,6 +68,9 @@ include("group_utils.jl") @test isapprox(G, pts[1], X, Z) p = exp_lie(G, X) q = identity_element(G) + @test is_identity(G, q) + @test isapprox(G, q, Identity(G)) + @test isapprox(G, Identity(G), q) exp_lie!(G, q, X) @test isapprox(G, p, q) log_lie!(G, Z, Identity(G)) diff --git a/test/groups/special_euclidean.jl b/test/groups/special_euclidean.jl index 9094568102..ef55617b51 100644 --- a/test/groups/special_euclidean.jl +++ b/test/groups/special_euclidean.jl @@ -146,6 +146,11 @@ using ManifoldsBase: VeeOrthogonalBasis p2[1:n, end] .= p[1:n, end] p2[end, end] = p[end, end] @test_throws CompositeManifoldError is_point(G, p2, true) + # exp/log_lie for ProductGroup on arrays + X = copy(G, p, X_pts[1]) + p3 = exp_lie(G, X) + X3 = log_lie(G, p3) + isapprox(G, Identity(G), X, X3) end @testset "hat/vee" begin @@ -161,6 +166,23 @@ using ManifoldsBase: VeeOrthogonalBasis v = vee(G, affine_matrix(G, p), screw_matrix(G, V)) @test v ≈ vexp @test hat(G, affine_matrix(G, p), v) ≈ screw_matrix(G, V) + + e = Identity(G) + Ve = log_lie(G, p) + v = vee(G, e, Ve) + @test_throws ErrorException vee(M, e, Ve) + w = similar(v) + vee!(G, w, e, Ve) + @test isapprox(v, w) + @test_throws ErrorException vee!(M, w, e, Ve) + + We = hat(G, e, v) + @test_throws ErrorException hat(M, e, v) + isapprox(G, e, Ve, We) + We2 = copy(G, p, V) + hat!(G, We2, e, v) + @test_throws ErrorException hat!(M, We, e, v) + @test isapprox(G, e, We, We2) end end diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index e71ced78d2..348655c75a 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -157,5 +157,11 @@ include("group_utils.jl") @test c == c2 get_coordinates!(M, c2, identity_element(G), Y, Manifolds.VeeOrthogonalBasis()) @test c == c2 + + q = zeros(3, 3) + mul!(q, e, e) + @test isone(q) + e2 = Identity(G) + @test mul!(e2, e, e) === e2 end end From 57ed3e6ba85b3112dad0ff9601719e1420c5cfa6 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 1 Aug 2021 17:13:51 +0200 Subject: [PATCH 72/88] delete exp_lie and log_lie for special orthogonal since these are already covered on the MultiplicationOperation level more generally. --- src/groups/special_orthogonal.jl | 4 ---- test/groups/groups_general.jl | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/groups/special_orthogonal.jl b/src/groups/special_orthogonal.jl index 05bcbb9e00..2987f461c8 100644 --- a/src/groups/special_orthogonal.jl +++ b/src/groups/special_orthogonal.jl @@ -42,10 +42,6 @@ function inverse_translate_diff!(G::SpecialOrthogonal, Y, p, q, X, conv::ActionD return copyto!(Y, inverse_translate_diff(G, p, q, X, conv)) end -exp_lie!(G::SpecialOrthogonal, q, X) = exp!(G, q, identity_element(G, q), X) - -_log_lie!(G::SpecialOrthogonal, X, q) = log!(G, X, identity_element(G, q), q) - function allocate_result( ::GT, ::typeof(exp), diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index cf176ec0e6..03d478362e 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -20,7 +20,7 @@ include("group_utils.jl") @test number_eltype(eg) == Bool @test is_identity(G, eg) # identity transparent @test_throws MethodError identity_element(G) # but for a NotImplOp there is no concrete id. - @test_trows MethodError is_directed(G, 1) # same rror as before i.e. dispatch isapprox works + @test_throws MethodError is_directed(G, 1) # same rror as before i.e. dispatch isapprox works @test isapprox(G, eg, eg) @test length(methods(is_group_decorator)) == 1 From e6934d96d875a68754c4633cb8302413a681ccfa Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Sun, 1 Aug 2021 20:39:45 +0200 Subject: [PATCH 73/88] resolving ambiguities --- src/groups/circle_group.jl | 4 --- src/groups/group.jl | 26 +++++++++++------ src/groups/special_euclidean.jl | 50 +++++---------------------------- src/manifolds/Circle.jl | 11 -------- src/tests/tests_group.jl | 6 ++-- test/groups/groups_general.jl | 1 + 6 files changed, 28 insertions(+), 70 deletions(-) diff --git a/src/groups/circle_group.jl b/src/groups/circle_group.jl index f94ada6455..932bfe6035 100644 --- a/src/groups/circle_group.jl +++ b/src/groups/circle_group.jl @@ -28,10 +28,6 @@ identity_element(G::CircleGroup) = 1.0 identity_element(::CircleGroup, p::Number) = one(p) identity_element(::CircleGroup, p::AbstractArray) = map(i -> one(eltype(p)), p) -function identity_element!(::CircleGroup, p) - return fill!(p, one(eltype(p))) -end - Base.inv(G::CircleGroup, p::AbstractVector) = map(inv, repeated(G), p) function inverse_translate( diff --git a/src/groups/group.jl b/src/groups/group.jl index de6ed227d3..c13a4fcfbe 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -365,7 +365,12 @@ inv(::AbstractGroupManifold, ::Any...) return inv!(G, q, p) end -Base.inv(::AbstractGroupManifold, e::Identity) = e +function Base.inv( + ::AbstractGroupManifold{𝔽,O}, + e::Identity{O}, +) where {𝔽,O<:AbstractGroupOperation} + return e +end @decorator_transparent_function function inv!(G::AbstractGroupManifold, q, p) return inv!(G.manifold, q, p) @@ -1077,12 +1082,22 @@ Base.:\(p, ::Identity{MultiplicationOperation}) = inv(p) Base.:\(::Identity{MultiplicationOperation}, p) = p Base.:\(e::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation}) = e -LinearAlgebra.det(::Identity{MultiplicationOperation}) = 1 +LinearAlgebra.det(::Identity{MultiplicationOperation}) = true +LinearAlgebra.adjoint(e::Identity{MultiplicationOperation}) = e function identity_element!(::MultiplicationGroup, p::AbstractMatrix) return copyto!(p, I) end +function identity_element!(G::MultiplicationGroup, p::AbstractArray) + if length(p) == 1 + fill!(p, one(eltype(p))) + else + throw(DimensionMismatch("Array $p cannot be set to identity element of group $G")) + end + return p +end + function is_identity(G::MultiplicationGroup, q::Number; kwargs...) return isapprox(G, q, one(q); kwargs...) end @@ -1105,13 +1120,6 @@ function LinearAlgebra.mul!( ) return copyto!(q, I) end -function LinearAlgebra.mul!( - q::Number, - ::Identity{MultiplicationOperation}, - ::Identity{MultiplicationOperation}, -) - return copyto!(q, one(eltype(q))) -end function LinearAlgebra.mul!( q::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation}, diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index 29bdc4e301..e31f37f920 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -39,6 +39,12 @@ function SpecialEuclidean(n) return SemidirectProductGroup(Tn, SOn, A) end +const SpecialEuclideanIdentity{N} = Identity{ + SemidirectProductOperation{ + RotationAction{TranslationGroup{Tuple{N},ℝ},SpecialOrthogonal{N},LeftAction}, + }, +} + Base.show(io::IO, ::SpecialEuclidean{n}) where {n} = print(io, "SpecialEuclidean($(n))") Base.@propagate_inbounds function submanifold_component( @@ -135,10 +141,7 @@ function affine_matrix(G::SpecialEuclidean{n}, p) where {n} return pmat end affine_matrix(::SpecialEuclidean{n}, p::AbstractMatrix) where {n} = p -function affine_matrix( - ::GT, - ::Identity{<:SemidirectProductOperation}, -) where {n,GT<:SpecialEuclidean{n}} +function affine_matrix(::SpecialEuclidean{n}, ::SpecialEuclideanIdentity{n}) where {n} s = maybesize(Size(n, n)) s isa Size && return SDiagonal{n,Float64}(I) return Diagonal{Float64}(I, n) @@ -530,45 +533,6 @@ function translate_diff!(G::SpecialEuclidean, Y, p, q, X, ::RightAction) @inbounds _padvector!(G, Y) return Y end -function translate_diff!( - G::SpecialEuclidean, - Y, - ::Identity{<:SemidirectProductOperation}, - q, - X, - ::RightAction, -) - copyto!(G, Y, X) - @inbounds _padvector!(G, Y) - return Y -end -function translate_diff!( - G::SpecialEuclidean, - Y, - p, - ::Identity{<:SemidirectProductOperation}, - X, - ::RightAction, -) - np, hp = submanifold_components(G, p) - nX, hX = submanifold_components(G, X) - nY, hY = submanifold_components(G, Y) - hY .= hp' * hX * hp - copyto!(nY, hX * np + nX) - @inbounds _padvector!(G, Y) -end -function translate_diff!( - G::SpecialEuclidean, - Y, - ::Identity{Op}, - ::Identity{Op}, - X, - ::RightAction, -) where {Op<:SemidirectProductOperation} - copyto!(G, Y, X) - @inbounds _padvector!(G, Y) - return Y -end @doc raw""" SpecialEuclideanInGeneralLinear diff --git a/src/manifolds/Circle.jl b/src/manifolds/Circle.jl index 4b59a85252..109b5da6fd 100644 --- a/src/manifolds/Circle.jl +++ b/src/manifolds/Circle.jl @@ -143,17 +143,6 @@ function get_coordinates( return @SVector [Xⁱ] end -eval( - quote - @invoke_maker 1 AbstractManifold get_coordinates( - M::Circle, - e::Identity, - X, - B::VeeOrthogonalBasis, - ) - end, -) - function get_coordinates!( M::Circle, Y::AbstractArray, diff --git a/src/tests/tests_group.jl b/src/tests/tests_group.jl index 98fb2f33c6..4036f5bec0 100644 --- a/src/tests/tests_group.jl +++ b/src/tests/tests_group.jl @@ -76,11 +76,11 @@ function test_group( Test.@test compose(G, e, e) === e Test.@test copyto!(G, e, e) === e + ge = identity_element(G, g_pts[1]) for g in g_pts Test.@test isapprox(G, compose(G, g, e), g) Test.@test isapprox(G, compose(G, e, g), g) - ge = Identity(G) Test.@test isapprox(G, compose(G, g, ge), g) Test.@test isapprox(G, compose(G, ge, g), g) end @@ -105,11 +105,11 @@ function test_group( end Test.@testset "Inverse" begin + Test.@test inv(G, e) === e for g in g_pts ginv = inv(G, g) Test.@test is_identity(G, compose(G, g, ginv); atol=atol) Test.@test is_identity(G, compose(G, ginv, g); atol=atol) - Test.@test inv(G, e) === e test_mutating && Test.@testset "mutating" begin Test.@test inv!(G, e, e) === e @@ -583,7 +583,7 @@ function test_action( Test.@test isapprox(G, compose(A, a, e), a; atol=atol_ident_compose) Test.@test isapprox(G, compose(A, e, a), a; atol=atol_ident_compose) - ge = Identity(G) + ge = identity_element(G, a) Test.@test isapprox(G, compose(A, a, ge), a; atol=atol_ident_compose) Test.@test isapprox(G, compose(A, ge, a), a; atol=atol_ident_compose) diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 03d478362e..7bc5e22085 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -206,6 +206,7 @@ include("group_utils.jl") @test copyto!(G, ge, ge) === ge y = allocate(p) identity_element!(G, y) + @test_throws DimensionMismatch identity_element!(G, [1, 2, 3]) @test y ≈ one(p) @test one(ge) === ge @test transpose(ge) === ge From b3bb59381b41c34f80bdb96c95d2cf49bb1beb77 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 2 Aug 2021 16:48:49 +0200 Subject: [PATCH 74/88] increase test coverage. --- src/groups/group.jl | 8 +++++++- test/groups/groups_general.jl | 2 +- test/groups/translation_group.jl | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index c13a4fcfbe..15d7579f2c 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -1120,6 +1120,13 @@ function LinearAlgebra.mul!( ) return copyto!(q, I) end +function LinearAlgebra.mul!( + q, + ::Identity{MultiplicationOperation}, + ::Identity{MultiplicationOperation}, +) + return copyto!(q, one(q)) +end function LinearAlgebra.mul!( q::Identity{MultiplicationOperation}, ::Identity{MultiplicationOperation}, @@ -1127,7 +1134,6 @@ function LinearAlgebra.mul!( ) return q end - Base.one(e::Identity{MultiplicationOperation}) = e Base.inv(::MultiplicationGroup, p) = inv(p) diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 7bc5e22085..06e7c48e91 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -20,8 +20,8 @@ include("group_utils.jl") @test number_eltype(eg) == Bool @test is_identity(G, eg) # identity transparent @test_throws MethodError identity_element(G) # but for a NotImplOp there is no concrete id. - @test_throws MethodError is_directed(G, 1) # same rror as before i.e. dispatch isapprox works @test isapprox(G, eg, eg) + @test_throws MethodError is_identity(G, 1) # same rror as before i.e. dispatch isapprox works @test length(methods(is_group_decorator)) == 1 @test Identity(NotImplementedOperation()) === eg diff --git a/test/groups/translation_group.jl b/test/groups/translation_group.jl index 65b2b3323f..7bf87c28e2 100644 --- a/test/groups/translation_group.jl +++ b/test/groups/translation_group.jl @@ -15,7 +15,7 @@ include("group_utils.jl") Val{true}() types = [Matrix{Float64}] @test base_manifold(G) === Euclidean(2, 3) - + @test log_lie(G, Identity(G)) == zeros(2, 3) # log_lie with Identity on Addition group. pts = [reshape(i:(i + 5), (2, 3)) for i in 1:3] vpts = [reshape(-2:3, (2, 3)), reshape(-1:4, (2, 3))] for T in types From fe9c5397bac3234118da1adfa103ec827efc9852 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 3 Aug 2021 09:38:04 +0200 Subject: [PATCH 75/88] Set exp_lie and log_lie to parent on group manifolds (they are transparent on other decorators) --- src/groups/group.jl | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/groups/group.jl b/src/groups/group.jl index 15d7579f2c..dbea3150ef 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -1299,6 +1299,19 @@ for f in [ end, ) end +for f in [exp_lie, log_lie] + eval( + quote + function decorator_transparent_dispatch( + ::typeof($f), + ::AbstractGroupManifold{𝔽,O}, + X, + ) where {𝔽,O} + return Val(:parent) + end + end, + ) +end # (d) specials for f in [vector_transport_along!, vector_transport_direction!, vector_transport_to!] eval( From b33932a47f8dab56b8e99f57049cd9f4e11d9e18 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 3 Aug 2021 11:33:00 +0200 Subject: [PATCH 76/88] =?UTF-8?q?remove=20some=20overspecific=20parents=20?= =?UTF-8?q?=E2=80=93=20and=20an=20unnecessary=20special=20dispatch=20case.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/groups/group.jl | 13 ------------- src/groups/product_group.jl | 6 +----- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/groups/group.jl b/src/groups/group.jl index dbea3150ef..15d7579f2c 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -1299,19 +1299,6 @@ for f in [ end, ) end -for f in [exp_lie, log_lie] - eval( - quote - function decorator_transparent_dispatch( - ::typeof($f), - ::AbstractGroupManifold{𝔽,O}, - X, - ) where {𝔽,O} - return Val(:parent) - end - end, - ) -end # (d) specials for f in [vector_transport_along!, vector_transport_direction!, vector_transport_to!] eval( diff --git a/src/groups/product_group.jl b/src/groups/product_group.jl index 969fa2fb2d..c7256351f2 100644 --- a/src/groups/product_group.jl +++ b/src/groups/product_group.jl @@ -242,14 +242,10 @@ function inverse_translate_diff!(G::ProductGroup, Y, p, q, X, conv::ActionDirect return Y end -function exp_lie(G::ProductGroup, X::Union{ProductRepr,ProductArray}) +function exp_lie(G::ProductGroup, X) M = G.manifold return ProductRepr(map(exp_lie, M.manifolds, submanifold_components(G, X))...) end -function exp_lie(G::ProductGroup, X) - q = allocate_result(G, exp_lie, X) - return exp_lie!(G, q, X) -end function exp_lie!(G::ProductGroup, q, X) M = G.manifold From d035d0c6493aa1727a90cb93869e0f94c1e85bd5 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 3 Aug 2021 13:48:00 +0200 Subject: [PATCH 77/88] add a test for mul! with an AbstractManifoldPoint that has a `one` operation. --- test/groups/groups_general.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 06e7c48e91..6f8e976526 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -264,6 +264,11 @@ include("group_utils.jl") Y = allocate(X) @test log_lie!(G, Y, y) === Y @test Y ≈ log(y) + + q2 = SVDMPoint(2 * Matrix{Float64}(I, 3, 3)) + mul!(q2, ge, ge) + qT = SVDMPoint(Matrix{Float64}(I, 3, 3)) + @test isapprox(FixedRankMatrices(3, 3, 3), q2, qT) end @testset "Identity on Group Manifolds" begin From e7d6f6918eda741d5c51a35bcb84d096d8b5eb73 Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Tue, 3 Aug 2021 16:39:00 +0200 Subject: [PATCH 78/88] fewer isapprox ambiguities --- src/groups/semidirect_product_group.jl | 39 ++++++-------------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index 21f615a433..cde603c2ff 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -209,39 +209,15 @@ function zero_vector!(G::SemidirectProductGroup, X, p) return X end -function Base.isapprox(G::SemidirectProductGroup, p, q; kwargs...) +function Base.isapprox(G::SemidirectProductGroup, p::AbstractArray, q::AbstractArray; kwargs...) M = base_manifold(G) N, H = M.manifolds np, hp = submanifold_components(G, p) nq, hq = submanifold_components(G, q) return isapprox(N, np, nq; kwargs...) && isapprox(H, hp, hq; kwargs...) end -function Base.isapprox( - G::SemidirectProductGroup, - e::Identity{<:SemidirectProductOperation}, - p; - kwargs..., -) - return isapprox(G, identity_element(G, p), p; kwargs...) -end -function Base.isapprox( - G::SemidirectProductGroup, - p, - e::Identity{<:SemidirectProductOperation}; - kwargs..., -) - return isapprox(G, e, p; kwargs...) -end -function Base.isapprox( - ::SemidirectProductGroup, - ::Identity{<:SemidirectProductOperation}, - ::Identity{<:SemidirectProductOperation}; - kwargs..., -) - return true -end -function Base.isapprox(G::SemidirectProductGroup, p, X, Y; kwargs...) +function Base.isapprox(G::SemidirectProductGroup, p, X::AbstractMatrix, Y::AbstractMatrix; kwargs...) M = base_manifold(G) N, H = M.manifolds np, hp = submanifold_components(G, p) @@ -250,11 +226,12 @@ function Base.isapprox(G::SemidirectProductGroup, p, X, Y; kwargs...) return isapprox(N, np, nX, nY; kwargs...) && isapprox(H, hp, hX, hY; kwargs...) end function isapprox( - G::SemidirectProductGroup, - ::Identity{<:SemidirectProductOperation}, - X, - Y; + G::SemidirectProductGroup{𝔽,N,H,A}, + ::Identity{SemidirectProductOperation{A}}, + X::AbstractMatrix, + Y::AbstractMatrix; kwargs..., -) +) where{𝔽,N<:AbstractManifold,H<:AbstractManifold,A<:AbstractGroupAction} return isapprox(G, identity_element(G), X, Y; kwargs...) end + From fb85f0496a5e6a1d05748c4d97b46d12413fb936 Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Tue, 3 Aug 2021 16:42:10 +0200 Subject: [PATCH 79/88] formatting --- src/groups/semidirect_product_group.jl | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/groups/semidirect_product_group.jl b/src/groups/semidirect_product_group.jl index cde603c2ff..13c8545376 100644 --- a/src/groups/semidirect_product_group.jl +++ b/src/groups/semidirect_product_group.jl @@ -209,7 +209,12 @@ function zero_vector!(G::SemidirectProductGroup, X, p) return X end -function Base.isapprox(G::SemidirectProductGroup, p::AbstractArray, q::AbstractArray; kwargs...) +function Base.isapprox( + G::SemidirectProductGroup, + p::AbstractArray, + q::AbstractArray; + kwargs..., +) M = base_manifold(G) N, H = M.manifolds np, hp = submanifold_components(G, p) @@ -217,7 +222,13 @@ function Base.isapprox(G::SemidirectProductGroup, p::AbstractArray, q::AbstractA return isapprox(N, np, nq; kwargs...) && isapprox(H, hp, hq; kwargs...) end -function Base.isapprox(G::SemidirectProductGroup, p, X::AbstractMatrix, Y::AbstractMatrix; kwargs...) +function Base.isapprox( + G::SemidirectProductGroup, + p, + X::AbstractMatrix, + Y::AbstractMatrix; + kwargs..., +) M = base_manifold(G) N, H = M.manifolds np, hp = submanifold_components(G, p) @@ -231,7 +242,6 @@ function isapprox( X::AbstractMatrix, Y::AbstractMatrix; kwargs..., -) where{𝔽,N<:AbstractManifold,H<:AbstractManifold,A<:AbstractGroupAction} +) where {𝔽,N<:AbstractManifold,H<:AbstractManifold,A<:AbstractGroupAction} return isapprox(G, identity_element(G), X, Y; kwargs...) end - From dd5e1c1defe223c52a8f19e98ec9634c247fb140 Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Tue, 3 Aug 2021 18:51:09 +0200 Subject: [PATCH 80/88] trying to make SE(n) tests less random --- test/groups/special_euclidean.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/groups/special_euclidean.jl b/test/groups/special_euclidean.jl index ef55617b51..d0bd0340fb 100644 --- a/test/groups/special_euclidean.jl +++ b/test/groups/special_euclidean.jl @@ -3,6 +3,8 @@ include("group_utils.jl") using ManifoldsBase: VeeOrthogonalBasis +Random.seed!(10) + @testset "Special Euclidean group" begin @testset "SpecialEuclidean($n)" for n in (2, 3, 4) G = SpecialEuclidean(n) From a7fb7732ba97e9a8f33079c8ee80f3219885c9f1 Mon Sep 17 00:00:00 2001 From: Mateusz Baran Date: Tue, 3 Aug 2021 22:08:38 +0200 Subject: [PATCH 81/88] testing some utilities --- test/runtests.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 91859d5616..25e841c377 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -95,6 +95,14 @@ include("utils.jl") x3r = Manifolds.realify(x3, ℂ) @test x2 * x3 ≈ Manifolds.unrealify!(similar(x2), x2r * x3r, ℂ) end + @testset "allocation" begin + @test allocate([1 2; 3 4], Float64, Size(3, 3)) isa Matrix{Float64} + @test allocate(SA[1 2; 3 4], Float64, Size(3, 3)) isa MMatrix{3,3,Float64} + end + @testset "eigen_safe" begin + @test Manifolds.eigen_safe(SA[1.0 0.0; 0.0 1.0]) isa + Eigen{Float64,Float64,<:SizedMatrix{2,2},<:SizedVector{2}} + end end include_test("groups/group_utils.jl") From be376617483516c4fb0f3e4fa9fad64a9e4b0fce Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 4 Aug 2021 14:53:04 +0200 Subject: [PATCH 82/88] Comment out all VisualRegression tests, might still code cover plot recipes line, since plots are still called. --- Project.toml | 2 +- docs/Project.toml | 2 +- test/recipes.jl | 217 +++++++++++++++++++++++----------------------- 3 files changed, 112 insertions(+), 109 deletions(-) diff --git a/Project.toml b/Project.toml index b91199e495..9931e265e0 100644 --- a/Project.toml +++ b/Project.toml @@ -33,7 +33,7 @@ HybridArrays = "0.4" Kronecker = "0.4" LightGraphs = "1" ManifoldsBase = "0.12.4" -Plots = "~1.6, =1.10.5" +Plots = "=1.11" RecipesBase = "1.1" Requires = "0.5, 1" SimpleWeightedGraphs = "1" diff --git a/docs/Project.toml b/docs/Project.toml index cd99d19b42..283393f092 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -17,6 +17,6 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Documenter = "0.24, 0.25, 0.26" HybridArrays = "0.4" ManifoldsBase = "0.12.4" -Plots = "= 1.10.5" +Plots = "= 1.11" PyPlot = "2.9" StaticArrays = "1.0" diff --git a/test/recipes.jl b/test/recipes.jl index 5000f232c0..c819623463 100644 --- a/test/recipes.jl +++ b/test/recipes.jl @@ -8,130 +8,133 @@ include("utils.jl") @testset "2D Recipes in GR" begin ENV["GKSwstype"] = "100" gr() - function Hyp2PB_plot() - M = Hyperbolic(2) - p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) - p2 = convert.(Ref(PoincareBallPoint), p) - return plot(M, p2) - end - @plottest Hyp2PB_plot joinpath(references_folder, "Hyp2PBPlot.png") false + # function Hyp2PB_plot() + M = Hyperbolic(2) + p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) + p2 = convert.(Ref(PoincareBallPoint), p) + # return + plot(M, p2) + # end + # @plottest Hyp2PB_plot joinpath(references_folder, "Hyp2PBPlot.png") false - function Hyp2PB_plot_geo() - M = Hyperbolic(2) - p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) - p2 = convert.(Ref(PoincareBallPoint), p) - return plot(M, p2; geodesic_interpolation=80) - end - @plottest Hyp2PB_plot_geo joinpath(references_folder, "Hyp2PBPlotGeo.png") false + # function Hyp2PB_plot_geo() + M = Hyperbolic(2) + p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) + p2 = convert.(Ref(PoincareBallPoint), p) + # return + plot(M, p2; geodesic_interpolation=80) + # end + # @plottest Hyp2PB_plot_geo joinpath(references_folder, "Hyp2PBPlotGeo.png") false - function Hyp2PB_quiver() - M = Hyperbolic(2) - p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 0.0], [0.0, 1.0]]) - p2 = convert.(Ref(PoincareBallPoint), p) - X = [log(M, p2[2], p2[1]), log(M, p2[1], p2[3])] - return plot(M, [p2[2], p2[1]], X) - end - @plottest Hyp2PB_quiver joinpath(references_folder, "Hyp2PBQuiver.png") false + # function Hyp2PB_quiver() + M = Hyperbolic(2) + p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 0.0], [0.0, 1.0]]) + p2 = convert.(Ref(PoincareBallPoint), p) + X = [log(M, p2[2], p2[1]), log(M, p2[1], p2[3])] + # return + plot(M, [p2[2], p2[1]], X) + # end + # @plottest Hyp2PB_quiver joinpath(references_folder, "Hyp2PBQuiver.png") false - function Hyp2PH_plot() - M = Hyperbolic(2) - p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) - p2 = convert.(Ref(PoincareHalfSpacePoint), p) - return plot(M, p2) - end - @plottest Hyp2PH_plot joinpath(references_folder, "Hyp2PHPlot.png") false + # function Hyp2PH_plot() + M = Hyperbolic(2) + p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) + p2 = convert.(Ref(PoincareHalfSpacePoint), p) + # return + plot(M, p2) + # end + # @plottest Hyp2PH_plot joinpath(references_folder, "Hyp2PHPlot.png") false - function Hyp2PH_plot_geo() - M = Hyperbolic(2) - p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) - p2 = convert.(Ref(PoincareHalfSpacePoint), p) - return plot(M, p2; geodesic_interpolation=80) - end - @plottest Hyp2PH_plot_geo joinpath(references_folder, "Hyp2PHPlotGeo.png") false + # function Hyp2PH_plot_geo() + M = Hyperbolic(2) + p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) + p2 = convert.(Ref(PoincareHalfSpacePoint), p) + # return + plot(M, p2; geodesic_interpolation=80) + # end + # @plottest Hyp2PH_plot_geo joinpath(references_folder, "Hyp2PHPlotGeo.png") false - function Hyp2PH_quiver() - M = Hyperbolic(2) - p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 0.0], [0.0, 1.0]]) - p2 = convert.(Ref(PoincareHalfSpacePoint), p) - X = [log(M, p2[2], p2[1]), log(M, p2[1], p2[3])] - return plot(M, [p2[2], p2[1]], X) - end - @plottest Hyp2PH_quiver joinpath(references_folder, "Hyp2PHQuiver.png") false + # function Hyp2PH_quiver() + M = Hyperbolic(2) + p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 0.0], [0.0, 1.0]]) + p2 = convert.(Ref(PoincareHalfSpacePoint), p) + X = [log(M, p2[2], p2[1]), log(M, p2[1], p2[3])] + # return + plot(M, [p2[2], p2[1]], X) + # end + # @plottest Hyp2PH_quiver joinpath(references_folder, "Hyp2PHQuiver.png") false end @testset "3D Recipes in GR" begin ENV["GKSwstype"] = "100" gr() - function Hyp2_plot() - M = Hyperbolic(2) - p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) - return plot(M, p) - end - @plottest Hyp2_plot joinpath(references_folder, "Hyp2Plot.png") false + # function Hyp2_plot() + M = Hyperbolic(2) + p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) + # return + plot(M, p) + # end + # @plottest Hyp2_plot joinpath(references_folder, "Hyp2Plot.png") false - function Hyp2_surfplot() - M = Hyperbolic(2) - p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) - return plot(M, p; surface=true) - end - @plottest Hyp2_surfplot joinpath(references_folder, "Hyp2SurfPlot.png") false + # function Hyp2_surfplot() + M = Hyperbolic(2) + p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) + # return + plot(M, p; surface=true) + #end + #@plottest Hyp2_surfplot joinpath(references_folder, "Hyp2SurfPlot.png") false - function Hyp2_plot_geo() - M = Hyperbolic(2) - p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) - return plot(M, p; geodesic_interpolation=80) - end - @plottest Hyp2_plot_geo joinpath(references_folder, "Hyp2PlotGeo.png") false + # function Hyp2_plot_geo() + M = Hyperbolic(2) + p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 1.0]]) + # return + plot(M, p; geodesic_interpolation=80) + # end + #@plottest Hyp2_plot_geo joinpath(references_folder, "Hyp2PlotGeo.png") false - function Hyp2_quiver() - M = Hyperbolic(2) - p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 0.0], [0.0, 1.0]]) - X = [log(M, p[2], p[1]), log(M, p[1], p[3])] - return plot(M, [p[2], p[1]], X) - end - @plottest Hyp2_quiver joinpath(references_folder, "Hyp2Quiver.png") false + # function Hyp2_quiver() + M = Hyperbolic(2) + p = Manifolds._hyperbolize.(Ref(M), [[1.0, 0.0], [0.0, 0.0], [0.0, 1.0]]) + X = [log(M, p[2], p[1]), log(M, p[1], p[3])] + # return + plot(M, [p[2], p[1]], X) + # end + # @plottest Hyp2_quiver joinpath(references_folder, "Hyp2Quiver.png") false end @testset "3D Recipes in pyplot" begin pyplot() - function Sphere2_plot() - M = Sphere(2) - pts = [[1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0]] - return plot(M, pts; wireframe_color=colorant"#CCCCCC", markersize=10) - end - @plottest Sphere2_plot joinpath(references_folder, "Sphere2Plot.png") false + # function Sphere2_plot() + M = Sphere(2) + pts = [[1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0]] + # return + plot(M, pts; wireframe_color=colorant"#CCCCCC", markersize=10) + # end + # @plottest Sphere2_plot joinpath(references_folder, "Sphere2Plot.png") false - function Sphere2_surfplot() - M = Sphere(2) - pts = [[1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0]] - return plot( - M, - pts; - surface=true, - wireframe_color=colorant"#CCCCCC", - markersize=10, - ) - end - @plottest Sphere2_surfplot joinpath(references_folder, "Sphere2SurfPlot.png") false + # function Sphere2_surfplot() + M = Sphere(2) + pts = [[1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0]] + # return + plot(M, pts; surface=true, wireframe_color=colorant"#CCCCCC", markersize=10) + # end + # @plottest Sphere2_surfplot joinpath(references_folder, "Sphere2SurfPlot.png") false - function Sphere2_plot_geo() - M = Sphere(2) - pts = [[1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0]] - return Plots.plot( - M, - pts; - wireframe_color=colorant"#CCCCCC", - geodesic_interpolation=80, - ) - end - @plottest Sphere2_plot_geo joinpath(references_folder, "Sphere2PlotGeo.png") false + # function Sphere2_plot_geo() + M = Sphere(2) + pts = [[1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0]] + # return + Plots.plot(M, pts; wireframe_color=colorant"#CCCCCC", geodesic_interpolation=80) + # end + # @plottest Sphere2_plot_geo joinpath(references_folder, "Sphere2PlotGeo.png") false - function Sphere2_quiver() - pyplot() - M = Sphere(2) - pts2 = [[1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]] - p3 = 1 / sqrt(3) .* [1.0, -1.0, 1.0] - vecs = log.(Ref(M), pts2, Ref(p3)) - return plot(M, pts2, vecs; wireframe_color=colorant"#CCCCCC", linewidth=1.5) - end - @plottest Sphere2_quiver joinpath(references_folder, "Sphere2Quiver.png") false + # function Sphere2_quiver() + pyplot() + M = Sphere(2) + pts2 = [[1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]] + p3 = 1 / sqrt(3) .* [1.0, -1.0, 1.0] + vecs = log.(Ref(M), pts2, Ref(p3)) + # return + plot(M, pts2, vecs; wireframe_color=colorant"#CCCCCC", linewidth=1.5) + # end + # @plottest Sphere2_quiver joinpath(references_folder, "Sphere2Quiver.png") false end end From 2c32608e0d1e7a95f833e9d28b4bdf41948e685d Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 4 Aug 2021 14:57:39 +0200 Subject: [PATCH 83/88] Remove VisualRegressiontests for now. --- Project.toml | 2 +- test/recipes.jl | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 9931e265e0..47d2ed5572 100644 --- a/Project.toml +++ b/Project.toml @@ -62,4 +62,4 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92" [targets] -test = ["Test", "Colors", "DoubleFloats", "FiniteDiff", "ForwardDiff", "Gtk", "ImageIO", "ImageMagick", "OrdinaryDiffEq", "NLsolve", "Plots", "PyPlot", "Quaternions", "QuartzImageIO", "RecipesBase", "ReverseDiff", "VisualRegressionTests"] +test = ["Test", "Colors", "DoubleFloats", "FiniteDiff", "ForwardDiff", "Gtk", "ImageIO", "ImageMagick", "OrdinaryDiffEq", "NLsolve", "Plots", "PyPlot", "Quaternions", "QuartzImageIO", "RecipesBase", "ReverseDiff"] diff --git a/test/recipes.jl b/test/recipes.jl index c819623463..f95ce37f6a 100644 --- a/test/recipes.jl +++ b/test/recipes.jl @@ -1,4 +1,5 @@ -using RecipesBase, VisualRegressionTests, Plots, Colors +using RecipesBase, Plots, Colors +#using VisualRegressionTests, include("utils.jl") # Note that the `false`s avoid popups and the tests directly fail. # If you have changed something and need to recreate the reference in the test avoids to start Gtk From 1f9a429aa6399f6b15baf8e5698773d930f3ecdf Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 4 Aug 2021 15:07:52 +0200 Subject: [PATCH 84/88] my bad. --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 47d2ed5572..f6842d343b 100644 --- a/Project.toml +++ b/Project.toml @@ -33,7 +33,7 @@ HybridArrays = "0.4" Kronecker = "0.4" LightGraphs = "1" ManifoldsBase = "0.12.4" -Plots = "=1.11" +Plots = "1.11" RecipesBase = "1.1" Requires = "0.5, 1" SimpleWeightedGraphs = "1" From 313d357ec61e528079160f6fbe627b5308747ea7 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 4 Aug 2021 15:18:15 +0200 Subject: [PATCH 85/88] Loosen compat for plots. --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index f6842d343b..1e396ad3a0 100644 --- a/Project.toml +++ b/Project.toml @@ -33,7 +33,7 @@ HybridArrays = "0.4" Kronecker = "0.4" LightGraphs = "1" ManifoldsBase = "0.12.4" -Plots = "1.11" +Plots = "1" RecipesBase = "1.1" Requires = "0.5, 1" SimpleWeightedGraphs = "1" From 8449100a7492c9e93db799c94cdbc0197f650d61 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 4 Aug 2021 15:30:07 +0200 Subject: [PATCH 86/88] bump documenter to run on Julia 1.6 --- .github/workflows/documenter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documenter.yml b/.github/workflows/documenter.yml index e90ae42d61..eb66151e97 100644 --- a/.github/workflows/documenter.yml +++ b/.github/workflows/documenter.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@latest with: - version: 1.5 + version: 1.6 - uses: julia-actions/julia-docdeploy@v1 env: PYTHON: "" From 5f3602d8d314c9043459d35481bf077809b4d4f8 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 4 Aug 2021 15:40:41 +0200 Subject: [PATCH 87/88] ... --- docs/Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Project.toml b/docs/Project.toml index 283393f092..ca9df85c2a 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -17,6 +17,6 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Documenter = "0.24, 0.25, 0.26" HybridArrays = "0.4" ManifoldsBase = "0.12.4" -Plots = "= 1.11" +Plots = "1" PyPlot = "2.9" StaticArrays = "1.0" From 725aa4843cc8f6b0c3c594677c37dca3371f8f56 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 4 Aug 2021 16:14:01 +0200 Subject: [PATCH 88/88] Update docs/Project.toml Co-authored-by: Mateusz Baran --- docs/Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Project.toml b/docs/Project.toml index ca9df85c2a..d4acdcbbf0 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -14,7 +14,7 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] -Documenter = "0.24, 0.25, 0.26" +Documenter = "0.24, 0.25, 0.26, 0.27" HybridArrays = "0.4" ManifoldsBase = "0.12.4" Plots = "1"