Skip to content

Commit

Permalink
Merge pull request #29 from JuliaManifolds/bugfix-bases
Browse files Browse the repository at this point in the history
Fixes a bug, where if both number_systems (manifold and base) are equal an error occured.
  • Loading branch information
kellertuer authored Mar 25, 2020
2 parents 8bb9a30 + 162838d commit 41929a0
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 63 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "ManifoldsBase"
uuid = "3362f125-f0bb-47a3-aa74-596ffd7ef2fb"
authors = ["Seth Axen <[email protected]>", "Mateusz Baran <[email protected]>", "Ronny Bergmann <[email protected]>", "Antoine Levitt <[email protected]>"]
version = "0.7.1"
version = "0.7.2"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand Down
26 changes: 14 additions & 12 deletions src/EmbeddedManifold.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,18 +147,6 @@ function check_tangent_vector(M::AbstractEmbeddedManifold, p, X; check_base_poin
kwargs...
)
end
"""
embed(M::AbstractEmbeddedManifold, p)
return the embedded representation of a point `p` on the [`AbstractEmbeddedManifold`](@ref)
`M`.
embed(M::AbstractEmbeddedManifold, p, X)
return the embedded representation of a tangent vector `X` at point `p` on the
[`AbstractEmbeddedManifold`](@ref) `M`.
"""
embed(::AbstractEmbeddedManifold, ::Any...)

decorated_manifold(M::AbstractEmbeddedManifold) = M.embedding

Expand Down Expand Up @@ -265,13 +253,27 @@ function decorator_transparent_dispatch(
)
return Val(:parent)
end
function decorator_transparent_dispatch(
::typeof(get_coordinates!),
::AbstractEmbeddedManifold,
args...,
)
return Val(:parent)
end
function decorator_transparent_dispatch(
::typeof(get_vector),
::AbstractEmbeddedManifold,
args...,
)
return Val(:parent)
end
function decorator_transparent_dispatch(
::typeof(get_vector!),
::AbstractEmbeddedManifold,
args...,
)
return Val(:parent)
end
function decorator_transparent_dispatch(
::typeof(inner),
::AbstractEmbeddedManifold,
Expand Down
90 changes: 69 additions & 21 deletions src/ManifoldsBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,13 @@ distance(M::Manifold, p, q) = norm(M, p, log(M, p, q))
embed(M::Manifold, p)
Embed point `p` from the [`Manifold`](@ref) `M` into the ambient space.
The function works only for selected embedded manifolds.
This method is only available for manifolds where implicitly an embedding or ambient space
is given.
Additionally, `embed` includes changing data representation, if applicable, i.e.
if the points on `M` are not represented in the same way as points on the embedding,
the representation is changed accordingly.
See also: [`EmbeddedManifold`](@ref), [`project`](@ref project(M::Manifold,p))
"""
function embed(M::Manifold, p)
q = allocate_result(M, embed, p)
Expand All @@ -277,10 +283,16 @@ function embed(M::Manifold, p)
end

"""
project!(M::Manifold, q, p)
embed!(M::Manifold, q, p)
Embed point `p` from the [`Manifold`](@ref) `M` into the ambient space. The point `q` is
overwritten by the embedded point. The function works only for selected embedded manifolds.
Embed point `p` from the [`Manifold`](@ref) `M` into the ambient space and return the result in `q`.
This method is only available for manifolds where implicitly an embedding or ambient space
is given.
Additionally, `embed` includes changing data representation, if applicable, i.e.
if the points on `M` are not represented in the same way as points on the embedding,
the representation is changed accordingly.
See also: [`EmbeddedManifold`](@ref), [`project!`](@ref project!(M::Manifold, q, p))
"""
function embed!(M::Manifold, q, p)
error(manifold_function_not_implemented_message(M, embed!, q, p))
Expand All @@ -289,10 +301,16 @@ end
"""
embed(M::Manifold, p, X)
Embed a tangent vector `X` at a point `p` on the [`Manifold`](@ref) `M` into the manifolds
ambient space.
Embed a tangent vector `X` at a point `p` on the [`Manifold`](@ref) `M` into the ambient space.
This method is only available for manifolds where implicitly an embedding or ambient space
is given.
Additionally, `embed` includes changing data representation, if applicable, i.e.
if the tangents on `M` are not represented in the same way as tangents on the embedding,
the representation is changed accordingly. This is the case for example for Lie groups,
when tangent vectors are represented in the Lie algebra. The embedded tangents are then in
the tangent spaces of the embedded base points.
The function works only for selected embedded manifolds.
See also: [`EmbeddedManifold`](@ref), [`project`](@ref project(M::Manifold, p, X))
"""
function embed(M::Manifold, p, X)
Y = allocate_result(M, embed, X, p)
Expand All @@ -303,10 +321,17 @@ end
"""
embed!(M::Manifold, Y, p, X)
Embed a tangent vector `X` at a point `p` on the [`Manifold`](@ref) `M` into the manifolds
ambient space. The result is saved in vector `Y`.
Embed a tangent vector `X` at a point `p` on the [`Manifold`](@ref) `M` into the ambient
space and return the result in `Y`.
This method is only available for manifolds where implicitly an embedding or ambient space
is given.
Additionally, `embed!` includes changing data representation, if applicable, i.e.
if the tangents on `M` are not represented in the same way as tangents on the embedding,
the representation is changed accordingly. This is the case for example for Lie groups,
when tangent vectors are represented in the Lie algebra. The embedded tangents are then in
the tangent spaces of the embedded base points.
The function works only for selected embedded manifolds.
See also: [`EmbeddedManifold`](@ref), [`project!`](@ref project!(M::Manifold, Y, p, X))
"""
function embed!(M::Manifold, Y, p, X)
error(manifold_function_not_implemented_message(M, embed!, Y, p, X))
Expand Down Expand Up @@ -390,6 +415,8 @@ injectivity_radius(M::Manifold, ::ExponentialRetraction) = injectivity_radius(M)
Compute the inner product of tangent vectors `X` and `Y` at point `p` from the
[`Manifold`](@ref) `M`.
See also: [`MetricManifold`](@ref)
"""
function inner(M::Manifold, p, X, Y)
error(manifold_function_not_implemented_message(M, inner, p, X, Y))
Expand Down Expand Up @@ -553,9 +580,13 @@ end
"""
project(M::Manifold, p)
Project point `p`from the ambient space onto the [`Manifold`](@ref) `M`.
The function works only for selected embedded manifolds and is *not* required to return the
closest point.
Project point `p` from the ambient space of the [`Manifold`](@ref) `M` to `M`.
This method is only available for manifolds where implicitly an embedding or ambient space
is given. Additionally, the projection includes changing data representation, if applicable,
i.e. if the points on `M` are not represented in the same array data, the data is changed
accordingly.
See also: [`EmbeddedManifold`](@ref), [`embed`](@ref embed(M::Manifold, p))
"""
function project(M::Manifold, p)
q = allocate_result(M, project, p)
Expand All @@ -566,9 +597,14 @@ end
"""
project!(M::Manifold, q, p)
Project point `p` from the ambient space onto the [`Manifold`](@ref) `M`. The point `q` is
overwritten by the projection. The function works only for selected embedded manifolds and
is *not* required to return the closest point.
Project point `p` from the ambient space onto the [`Manifold`](@ref) `M`. The result is
storedin `q`.
This method is only available for manifolds where implicitly an embedding or ambient space
is given. Additionally, the projection includes changing data representation, if applicable,
i.e. if the points on `M` are not represented in the same array data, the data is changed
accordingly.
See also: [`EmbeddedManifold`](@ref), [`embed!`](@ref embed!(M::Manifold, q, p))
"""
function project!(M::Manifold, q, p)
error(manifold_function_not_implemented_message(M, project!, q, p))
Expand All @@ -579,9 +615,15 @@ end
Project ambient space representation of a vector `X` to a tangent vector at point `p` on
the [`Manifold`](@ref) `M`.
This method is only available for manifolds where implicitly an embedding or ambient space
is given.
Additionally, `project` includes changing data representation, if applicable, i.e.
if the tangents on `M` are not represented in the same way as points on the embedding,
the representation is changed accordingly. This is the case for example for Lie groups,
when tangent vectors are represented in the Lie algebra. after projection the change to the
Lie algebra is perfomed, too.
The function works only for selected embedded manifolds and is *not* required to return the
closest vector.
See also: [`EmbeddedManifold`](@ref), [`embed`](@ref embed(M::Manifold, p, X))
"""
function project(M::Manifold, p, X)
Y = allocate_result(M, project, X, p)
Expand All @@ -594,9 +636,15 @@ end
Project ambient space representation of a vector `X` to a tangent vector at point `p` on
the [`Manifold`](@ref) `M`. The result is saved in vector `Y`.
The function works only for selected embedded manifolds and is *not* required to return the
closest vector.
This method is only available for manifolds where implicitly an embedding or ambient space
is given.
Additionally, `project!` includes changing data representation, if applicable, i.e.
if the tangents on `M` are not represented in the same way as points on the embedding,
the representation is changed accordingly. This is the case for example for Lie groups,
when tangent vectors are represented in the Lie algebra. after projection the change to the
Lie algebra is perfomed, too.
See also: [`EmbeddedManifold`](@ref), [`embed!`](@ref embed!(M::Manifold, Y, p, X))
"""
function project!(M::Manifold, Y, p, X)
error(manifold_function_not_implemented_message(M, project!, Y, p, X))
Expand Down
30 changes: 14 additions & 16 deletions src/bases.jl
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ const DefaultOrDiagonalizingBasis =
struct CachedBasis{B,V,𝔽} <: AbstractBasis{𝔽} where {BT<:AbstractBasis,V}
data::V
end
function CachedBasis(basis::B, data::V, 𝔽::AbstractNumbers =) where {V,B<:AbstractBasis}
function CachedBasis(basis::B, data::V) where {V,𝔽,B<:AbstractBasis{𝔽}}
return CachedBasis{B,V,𝔽}(data)
end
function CachedBasis(basis::CachedBasis) # avoid double encapsulation
Expand All @@ -131,10 +131,9 @@ function CachedBasis(
basis::DiagonalizingOrthonormalBasis,
eigenvalues::ET,
vectors::T,
𝔽::AbstractNumbers = ℝ,
) where {ET<:AbstractVector,T<:AbstractVector}
data = DiagonalizingBasisData(basis.frame_direction, eigenvalues, vectors)
return CachedBasis(basis, data, 𝔽)
return CachedBasis(basis, data)
end

# forward declarations
Expand All @@ -145,9 +144,9 @@ const all_uncached_bases = Union{AbstractBasis, DefaultBasis, DefaultOrthogonalB
const DISAMBIGUATION_BASIS_TYPES = [
CachedBasis,
CachedBasis{<:AbstractBasis{ℝ}},
CachedBasis{<:AbstractBasis{ℂ}},
CachedBasis{<:AbstractOrthogonalBasis{ℝ}},
CachedBasis{<:AbstractOrthonormalBasis{ℝ}},
CachedBasis{<:AbstractBasis{ℂ}},
DefaultBasis,
DefaultOrthonormalBasis,
DefaultOrthogonalBasis,
Expand Down Expand Up @@ -284,11 +283,11 @@ function get_basis(
end
push!(Ξ, Ξₙ)
K += 1
K * real_dimension(number_system(B)) == dim && return CachedBasis(B, Ξ, ℝ)
K * real_dimension(number_system(B)) == dim && return CachedBasis(B, Ξ)
@label skip
end
if return_incomplete_set
return CachedBasis(B, Ξ, ℝ)
return CachedBasis(B, Ξ)
else
error("get_basis with bases $(typeof(B)) only found $(K) orthonormal basis vectors, but manifold dimension is $(dim).")
end
Expand Down Expand Up @@ -347,17 +346,16 @@ function get_coordinates!(
Y,
p,
X,
B::CachedBasis{BT},
) where {BT<:AbstractBasis{ℝ}}
map!(vb -> inner(M, p, X, vb), Y, get_vectors(M, p, B))
return Y
end
function get_coordinates!(M::Manifold, Y, p, X, B::CachedBasis{<:AbstractBasis{ℂ}})
map!(vb -> conj(inner(M, p, X, vb)), Y, get_vectors(M, p, B))
B::CachedBasis,
)
if number_system(M) === number_system(B)
map!(vb -> real(inner(M, p, X, vb)), Y, get_vectors(M, p, B))
else
map!(vb -> conj(inner(M, p, X, vb)), Y, get_vectors(M, p, B))
end
return Y
end


"""
get_vector(M::Manifold, p, X, B::AbstractBasis)
Expand Down Expand Up @@ -511,7 +509,7 @@ end
function show(io::IO, mime::MIME"text/plain", onb::DiagonalizingOrthonormalBasis)
println(
io,
"DiagonalizingOrthonormalBasis($(number_system(onb))) and eigenvalue 0 in direction:",
"DiagonalizingOrthonormalBasis($(number_system(onb))) with eigenvalue 0 in direction:",
)
sk = sprint(show, "text/plain", onb.frame_direction, context = io, sizehint = 0)
sk = replace(sk, '\n' => "\n ")
Expand All @@ -525,7 +523,7 @@ function show(
print(
io,

"$(T()) and $(length(_get_vectors(B))) basis vector$(length(_get_vectors(B)) == 1 ? "" : "s"):",
"$(T()) with $(length(_get_vectors(B))) basis vector$(length(_get_vectors(B)) == 1 ? "" : "s"):",
)
_show_basis_vector_range_noheader(
io,
Expand Down
30 changes: 18 additions & 12 deletions test/bases.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using LinearAlgebra
using ManifoldsBase
using ManifoldsBase: DefaultManifold
using ManifoldsBase: DefaultManifold, ℝ, ℂ
using Test
import Base: +, -, *, copyto!, isapprox

Expand Down Expand Up @@ -252,15 +252,21 @@ DiagonalizingBasisProxy() = DiagonalizingOrthonormalBasis([1.0, 0.0, 0.0])
end
end

@testset "Complex Cached Basis" begin
M = ManifoldsBase.DefaultManifold(3; field = ManifoldsBase.ℂ)
@testset "Complex DeaultManifold with real and complex Cached Bases" begin
M = ManifoldsBase.DefaultManifold(3; field = ℂ)
p = [1.0, 2.0im, 3.0]
X = [1.2, 2.2im, 2.3im]
b = [Matrix{Float64}(I,3,3)[:,i] for i=1:3]
B = CachedBasis(DefaultOrthonormalBasis{ManifoldsBase.ℂ}(),b,ManifoldsBase.ℂ)
a = get_coordinates(M,p,X,B)
Y = get_vector(M,p,a,B)
@test Y X
Bℝ = CachedBasis(DefaultOrthonormalBasis{ℝ}(),b)
aℝ = get_coordinates(M,p,X,Bℝ)
Yℝ = get_vector(M,p,aℝ,Bℝ)
@test Yℝ X

bℂ = [b...,(b.*1im)...]
Bℂ = CachedBasis(DefaultOrthonormalBasis{ℂ}(), bℂ)
aℂ = get_coordinates(M,p,X,Bℂ)
Yℂ = get_vector(M,p,aℂ,Bℂ)
@test Yℂ X
end

@testset "Basis show methods" begin
Expand All @@ -272,7 +278,7 @@ end
@test sprint(show, ProjectedOrthonormalBasis(:gram_schmidt, ℂ)) == "ProjectedOrthonormalBasis(:gram_schmidt, ℂ)"

@test sprint(show, "text/plain", DiagonalizingOrthonormalBasis(Float64[1, 2, 3])) == """
DiagonalizingOrthonormalBasis(ℝ) and eigenvalue 0 in direction:
DiagonalizingOrthonormalBasis(ℝ) with eigenvalue 0 in direction:
3-element Array{Float64,1}:
1.0
2.0
Expand All @@ -282,7 +288,7 @@ end
x = collect(reshape(1.0:6.0, (2, 3)))
pb = get_basis(M, x, DefaultOrthonormalBasis())
@test sprint(show, "text/plain", pb) == """
DefaultOrthonormalBasis(ℝ) and 6 basis vectors:
DefaultOrthonormalBasis(ℝ) with 6 basis vectors:
E1 =
2×3 Array{Float64,2}:
1.0 0.0 0.0
Expand All @@ -303,7 +309,7 @@ end
b = DiagonalizingOrthonormalBasis(get_vectors(M, x, pb)[1])
dpb = CachedBasis(b, Float64[1, 2, 3, 4, 5, 6], get_vectors(M, x, pb))
@test sprint(show, "text/plain", dpb) == """
DiagonalizingOrthonormalBasis(ℝ) and eigenvalue 0 in direction:
DiagonalizingOrthonormalBasis(ℝ) with eigenvalue 0 in direction:
2×3 Array{Float64,2}:
1.0 0.0 0.0
0.0 0.0 0.0
Expand Down Expand Up @@ -339,15 +345,15 @@ end
x = reshape(Float64[1], (1, 1, 1))
pb = get_basis(M, x, DefaultOrthonormalBasis())
@test sprint(show, "text/plain", pb) == """
DefaultOrthonormalBasis(ℝ) and 1 basis vector:
DefaultOrthonormalBasis(ℝ) with 1 basis vector:
E1 =
1×1×1 Array{Float64,3}:
[:, :, 1] =
1.0"""

dpb = CachedBasis(DiagonalizingOrthonormalBasis(get_vectors(M, x, pb)), Float64[1], get_vectors(M, x, pb))
@test sprint(show, "text/plain", dpb) == """
DiagonalizingOrthonormalBasis(ℝ) and eigenvalue 0 in direction:
DiagonalizingOrthonormalBasis(ℝ) with eigenvalue 0 in direction:
1-element Array{Array{Float64,3},1}:
[1.0]
and 1 basis vector.
Expand Down
2 changes: 1 addition & 1 deletion test/embedded_manifold.jl
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ struct NotImplementedEmbeddedManifold3 <: AbstractEmbeddedManifold{DefaultEmbedd
for f in [embed, exp, get_basis, get_coordinates, get_vector, inverse_retract, log]
@test ManifoldsBase.decorator_transparent_dispatch(f,AM) === Val{:parent}()
end
for f in [project, retract, inverse_retract!, retract!]
for f in [project, retract, inverse_retract!, retract!, get_coordinates!, get_vector!]
@test ManifoldsBase.decorator_transparent_dispatch(f,AM) === Val{:parent}()
end
for f in [vector_transport_along, vector_transport_direction, vector_transport_to]
Expand Down

2 comments on commit 41929a0

@kellertuer
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/11538

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.7.2 -m "<description of version>" 41929a0335b86dbb5e90180c4ab23e426f8f0a49
git push origin v0.7.2

Please sign in to comment.