Skip to content

Commit

Permalink
Move ManifoldDiff extension here (#623)
Browse files Browse the repository at this point in the history
* Move ManifoldDiff extension here

* fix

* bumps

* fix ManifoldDiff imports

* test for some mutating methods
  • Loading branch information
mateuszbaran authored Jun 4, 2023
1 parent c6ec0a5 commit 16fe449
Show file tree
Hide file tree
Showing 15 changed files with 297 additions and 5 deletions.
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Manifolds"
uuid = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e"
authors = ["Seth Axen <[email protected]>", "Mateusz Baran <[email protected]>", "Ronny Bergmann <[email protected]>", "Antoine Levitt <[email protected]>"]
version = "0.8.68"
version = "0.8.69"

[deps]
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
Expand Down Expand Up @@ -48,7 +48,7 @@ Einsum = "0.4"
Graphs = "1.4"
HybridArrays = "0.4"
Kronecker = "0.4, 0.5"
ManifoldDiff = "0.2.1, 0.3"
ManifoldDiff = "0.3.3"
ManifoldsBase = "0.14.1"
MatrixEquations = "2.2"
OrdinaryDiffEq = "6.31"
Expand Down
14 changes: 11 additions & 3 deletions src/Manifolds.jl
Original file line number Diff line number Diff line change
Expand Up @@ -291,18 +291,26 @@ using ManifoldDiff:
jacobian,
_jacobian,
_jacobian!,
riemannian_gradient,
riemannian_gradient!,
set_default_differential_backend!
using ManifoldDiff:
AbstractDiffBackend,
AbstractRiemannianDiffBackend,
CoprojectorOntoVector,
ExplicitEmbeddedBackend,
IdentityProjector,
NoneDiffBackend,
ProjectorOntoVector,
RiemannianProjectionBackend,
TangentDiffBackend

import ManifoldDiff: riemannian_gradient, riemannian_gradient!
import ManifoldDiff:
adjoint_Jacobi_field,
adjoint_Jacobi_field!,
diagonalizing_projectors,
jacobi_field,
jacobi_field!,
riemannian_gradient,
riemannian_gradient!

using Markdown: @doc_str
using MatrixEquations: lyapc, sylvc
Expand Down
23 changes: 23 additions & 0 deletions src/groups/group.jl
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,29 @@ function adjoint_action!(
return Y
end

function ManifoldDiff.differential_exp_argument_lie_approx!(
M::AbstractManifold,
Z,
p,
X,
Y;
n=20,
)
tmp = copy(M, p, Y)
a = -1.0
zero_vector!(M, Z, p)
for k in 0:n
a *= -1 // (k + 1)
Z .+= a .* tmp
if k < n
copyto!(tmp, lie_bracket(M, X, tmp))
end
end
q = exp(M, p, X)
translate_diff!(M, Z, q, Identity(M), Z)
return Z
end

@doc raw"""
inv(G::AbstractDecoratorManifold, p)
Expand Down
14 changes: 14 additions & 0 deletions src/manifolds/Circle.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ struct Circle{𝔽} <: AbstractManifold{𝔽} end

Circle(𝔽::AbstractNumbers=ℝ) = Circle{𝔽}()

function adjoint_Jacobi_field(::Circle{ℝ}, p, q, t, X, β::Tβ) where {Tβ}
return X
end

@doc raw"""
check_point(M::Circle, p)
Expand Down Expand Up @@ -92,6 +96,12 @@ Compute the inner product of two (complex) numbers with in the complex plane.
complex_dot(a, b) = dot(map(real, a), map(real, b)) + dot(map(imag, a), map(imag, b))
complex_dot(a::Number, b::Number) = (real(a) * real(b) + imag(a) * imag(b))

function diagonalizing_projectors(M::Circle{ℝ}, p, X)
sbv = sign(X[])
proj = ProjectorOntoVector(M, p, @SVector [sbv == 0 ? one(sbv) : sbv])
return ((zero(number_eltype(p)), proj),)
end

@doc raw"""
distance(M::Circle, p, q)
Expand Down Expand Up @@ -266,6 +276,10 @@ Return true. [`Circle`](@ref) is a flat manifold.
"""
is_flat(M::Circle) = true

function jacobi_field(::Circle{ℝ}, p, q, t, X, β::Tβ) where {Tβ}
return X
end

@doc raw"""
log(M::Circle, p, q)
Expand Down
12 changes: 12 additions & 0 deletions src/manifolds/Euclidean.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ function active_traits(f, ::Euclidean, args...)
)
end

function adjoint_Jacobi_field(::Euclidean{Tuple{}}, p, q, t, X, β::Tβ) where {Tβ}
return X
end

Base.:^(𝔽::AbstractNumbers, n) = Euclidean(n...; field=𝔽)

Base.:^(M::Euclidean, n::Int) = ^(M, (n,))
Expand Down Expand Up @@ -93,6 +97,10 @@ function det_local_metric(
return one(eltype(p))
end

function diagonalizing_projectors(::Euclidean, p, X)
return ((zero(number_eltype(p)), IdentityProjector()),)
end

"""
distance(M::Euclidean, p, q)
Expand Down Expand Up @@ -390,6 +398,10 @@ Return true. [`Euclidean`](@ref) is a flat manifold.
"""
is_flat(M::Euclidean) = true

function jacobi_field(::Euclidean{Tuple{}}, p, q, t, X, β::Tβ) where {Tβ}
return X
end

function local_metric(
::MetricManifold{𝔽,<:AbstractManifold,EuclideanMetric},
p,
Expand Down
9 changes: 9 additions & 0 deletions src/manifolds/Hyperbolic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,15 @@ for (P, T) in zip(_HyperbolicPointTypes, _HyperbolicTangentTypes)
end
end

function diagonalizing_projectors(M::Hyperbolic, p, X)
X_norm = norm(M, p, X)
X_normed = X / X_norm
return (
(zero(number_eltype(p)), ProjectorOntoVector(M, p, X_normed)),
(-one(number_eltype(p)), CoprojectorOntoVector(M, p, X_normed)),
)
end

get_embedding(::Hyperbolic{N}) where {N} = Lorentz(N + 1, MinkowskiMetric())

embed(::Hyperbolic, p::AbstractArray) = p
Expand Down
68 changes: 68 additions & 0 deletions src/manifolds/ProductManifold.jl
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,40 @@ function active_traits(f, ::ProductManifold, args...)
return merge_traits(IsDefaultMetric(ProductMetric()))
end

function adjoint_Jacobi_field(
M::ProductManifold,
p::ArrayPartition,
q::ArrayPartition,
t,
X::ArrayPartition,
β::Tβ,
) where {Tβ}
return ArrayPartition(
map(
adjoint_Jacobi_field,
M.manifolds,
submanifold_components(M, p),
submanifold_components(M, q),
ntuple(_ -> t, length(M.manifolds)),
submanifold_components(M, X),
ntuple(_ -> β, length(M.manifolds)),
)...,
)
end
function adjoint_Jacobi_field!(M::ProductManifold, Y, p, q, t, X, β::Tβ) where {Tβ}
map(
adjoint_Jacobi_field!,
M.manifolds,
submanifold_components(M, Y),
submanifold_components(M, p),
submanifold_components(M, q),
ntuple(_ -> t, length(M.manifolds)),
submanifold_components(M, X),
ntuple(_ -> β, length(M.manifolds)),
)
return Y
end

function allocate_coordinates(M::AbstractManifold, p::ArrayPartition, T, n::Int)
return allocate_coordinates(M, p.x[1], T, n)
end
Expand Down Expand Up @@ -880,6 +914,40 @@ function Base.log(M::ProductManifold, p::ArrayPartition, q::ArrayPartition)
)
end

function jacobi_field(
M::ProductManifold,
p::ArrayPartition,
q::ArrayPartition,
t,
X::ArrayPartition,
β::Tβ,
) where {Tβ}
return ArrayPartition(
map(
jacobi_field,
M.manifolds,
submanifold_components(M, p),
submanifold_components(M, q),
ntuple(_ -> t, length(M.manifolds)),
submanifold_components(M, X),
ntuple(_ -> β, length(M.manifolds)),
)...,
)
end
function jacobi_field!(M::ProductManifold, Y, p, q, t, X, β::Tβ) where {Tβ}
map(
jacobi_field!,
M.manifolds,
submanifold_components(M, Y),
submanifold_components(M, p),
submanifold_components(M, q),
ntuple(_ -> t, length(M.manifolds)),
submanifold_components(M, X),
ntuple(_ -> β, length(M.manifolds)),
)
return Y
end

function log!(M::ProductManifold, X, p, q)
map(
log!,
Expand Down
9 changes: 9 additions & 0 deletions src/manifolds/Sphere.jl
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ function check_vector(M::AbstractSphere, p, X; kwargs...)
return nothing
end

function diagonalizing_projectors(M::AbstractSphere{ℝ}, p, X)
X_norm = norm(M, p, X)
X_normed = X / X_norm
return (
(zero(number_eltype(p)), ProjectorOntoVector(M, p, X_normed)),
(one(number_eltype(p)), CoprojectorOntoVector(M, p, X_normed)),
)
end

@doc raw"""
distance(M::AbstractSphere, p, q)
Expand Down
35 changes: 35 additions & 0 deletions test/groups/special_orthogonal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,39 @@ include("group_utils.jl")
@test !is_vector(G, gI, ones(n)) # wrong size
end
end

@testset "differentials" begin
G = SpecialOrthogonal(3)
p = Matrix(I, 3, 3)

ω = [[1.0, 2.0, 3.0], [3.0, 2.0, 1.0], [1.0, 3.0, 2.0]]
pts = [exp(G, p, hat(G, p, ωi)) for ωi in ω]
Xpts = [hat(G, p, [-1.0, 2.0, 0.5]), hat(G, p, [1.0, 0.0, 0.5])]

q2 = exp(G, pts[1], Xpts[2])
@test isapprox(
G,
q2,
ManifoldDiff.differential_exp_argument_lie_approx(
G,
pts[1],
Xpts[1],
Xpts[2];
n=0,
),
Xpts[2],
)
diff_ref = [
0.0 -0.7482721017619345 -0.508151233069837
0.7482721017619345 0.0 -0.10783358474129323
0.508151233069837 0.10783358474129323 0.0
]
@test isapprox(
G,
q2,
ManifoldDiff.differential_exp_argument_lie_approx(G, pts[1], Xpts[1], Xpts[2]),
diff_ref;
atol=1e-12,
)
end
end
20 changes: 20 additions & 0 deletions test/manifolds/circle.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,26 @@ using Manifolds: TFVector, CoTFVector
# isapprox for 1-element vectors
@test isapprox(M, [1.0], [1.0])
@test isapprox(M, [0.0], [1.0], [1.0])

# ManifoldDiff
@test ManifoldDiff.adjoint_Jacobi_field(
M,
0.0,
1.0,
0.5,
2.0,
ManifoldDiff.βdifferential_shortest_geodesic_startpoint,
) === 2.0
@test ManifoldDiff.diagonalizing_projectors(M, 0.0, 2.0) ==
((0.0, ManifoldDiff.ProjectorOntoVector(M, 0.0, SA[1.0])),)
@test ManifoldDiff.jacobi_field(
M,
0.0,
1.0,
0.5,
2.0,
ManifoldDiff.βdifferential_shortest_geodesic_startpoint,
) === 2.0
end
TEST_STATIC_SIZED && @testset "Real Circle and static sized arrays" begin
X = @MArray fill(0.0)
Expand Down
23 changes: 23 additions & 0 deletions test/manifolds/euclidean.jl
Original file line number Diff line number Diff line change
Expand Up @@ -342,4 +342,27 @@ using Manifolds: induced_basis
M = Euclidean(4)
@test_throws DimensionMismatch distance(M, [1, 2, 3, 4], [1 2; 3 4])
end

@testset "ManifoldDiff" begin
# ManifoldDiff
M0 = Euclidean()
@test ManifoldDiff.adjoint_Jacobi_field(
M0,
0.0,
1.0,
0.5,
2.0,
ManifoldDiff.βdifferential_shortest_geodesic_startpoint,
) === 2.0
@test ManifoldDiff.diagonalizing_projectors(M0, 0.0, 2.0) ==
((0.0, ManifoldDiff.IdentityProjector()),)
@test ManifoldDiff.jacobi_field(
M0,
0.0,
1.0,
0.5,
2.0,
ManifoldDiff.βdifferential_shortest_geodesic_startpoint,
) === 2.0
end
end
11 changes: 11 additions & 0 deletions test/manifolds/hyperbolic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -328,4 +328,15 @@ include("../utils.jl")
A = change_metric(M, MinkowskiMetric(), p, X)
@test A == X
end
@testset "ManifoldDiff" begin
# ManifoldDiff
M = Hyperbolic(2)
p = [1.0, 1.0, sqrt(3)]
X = [1.0, 2.0, sqrt(3)]
dpX = ManifoldDiff.diagonalizing_projectors(M, p, X)
@test dpX[1][1] == 0.0
@test dpX[1][2].X == 2 * normalize(X)
@test dpX[2][1] == -1.0
@test dpX[2][2].X == 2 * normalize(X)
end
end
Loading

2 comments on commit 16fe449

@mateuszbaran
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/84861

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.8.69 -m "<description of version>" 16fe449b5793efb8156c5397e3a641b03495e793
git push origin v0.8.69

Please sign in to comment.