Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bases and rand for InvertibleMatrices and HeisenbergMatrices #777

Merged
merged 3 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.10.11] - unreleased

### Added

* Bases and rand for `HeisenbergMatrices` and `InvertibleMatrices`.

## [0.10.10] - 2024-12-20

### Added
Expand Down
2 changes: 1 addition & 1 deletion 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.10.10"
version = "0.10.11"

[deps]
Einsum = "b7d42ee7-0b51-5a75-98ca-779d3107e4c0"
Expand Down
105 changes: 105 additions & 0 deletions src/manifolds/HeisenbergMatrices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ function HeisenbergMatrices(n::Int; parameter::Symbol=:type)
return HeisenbergMatrices{typeof(size)}(size)
end

function _heisenberg_a_view(M::HeisenbergMatrices, p)
n = get_parameter(M.size)[1]
return view(p, 1, 2:(n + 1))
end
function _heisenberg_b_view(M::HeisenbergMatrices, p)
n = get_parameter(M.size)[1]
return view(p, 2:(n + 1), n + 2)
end

function active_traits(f, ::HeisenbergMatrices, args...)
return merge_traits(IsEmbeddedSubmanifold())
end
Expand Down Expand Up @@ -97,6 +106,33 @@ end
embed(::HeisenbergMatrices, p) = p
embed(::HeisenbergMatrices, p, X) = X

@doc raw"""
get_coordinates(M::HeisenbergMatrices, p, X, ::DefaultOrthonormalBasis{ℝ,TangentSpaceType})

Get coordinates of tangent vector `X` at point `p` from the [`HeisenbergMatrices`](@ref) `M`.
Given a matrix
```math
\begin{bmatrix} 1 & \mathbf{a} & c \\
\mathbf{0} & I_n & \mathbf{b} \\
0 & \mathbf{0} & 1 \end{bmatrix}
```
the coordinates are concatenated vectors ``\mathbf{a}``, ``\mathbf{b}``, and number ``c``.
"""
get_coordinates(::HeisenbergMatrices, p, X, ::DefaultOrthonormalBasis{ℝ,TangentSpaceType})

function get_coordinates_orthonormal(M::HeisenbergMatrices, p, X, ::RealNumbers)
n = get_parameter(M.size)[1]
return vcat(_heisenberg_a_view(M, X), _heisenberg_b_view(M, X), X[1, n + 2])
end

function get_coordinates_orthonormal!(M::HeisenbergMatrices, Xⁱ, p, X, ::RealNumbers)
n = get_parameter(M.size)[1]
Xⁱ[1:n] .= _heisenberg_a_view(M, X)
Xⁱ[(n + 1):(2 * n)] .= _heisenberg_b_view(M, X)
Xⁱ[2 * n + 1] = X[1, n + 2]
return Xⁱ
end

function get_embedding(::HeisenbergMatrices{TypeParameter{Tuple{n}}}) where {n}
return Euclidean(n + 2, n + 2)
end
Expand All @@ -105,6 +141,37 @@ function get_embedding(M::HeisenbergMatrices{Tuple{Int}})
return Euclidean(n + 2, n + 2; parameter=:field)
end

@doc raw"""
get_vector(M::HeisenbergMatrices, p, Xⁱ, ::DefaultOrthonormalBasis{ℝ,TangentSpaceType})

Get tangent vector with coordinates `Xⁱ` at point `p` from the [`HeisenbergMatrices`](@ref) `M`.
Given a vector of coordinates ``\begin{bmatrix}\mathbb{a} & \mathbb{b} & c\end{bmatrix}`` the tangent vector is equal to
```math
\begin{bmatrix} 1 & \mathbf{a} & c \\
\mathbf{0} & I_n & \mathbf{b} \\
0 & \mathbf{0} & 1 \end{bmatrix}
```
"""
get_vector(M::HeisenbergMatrices, p, c, ::DefaultOrthonormalBasis{ℝ,TangentSpaceType})

function get_vector_orthonormal(M::HeisenbergMatrices, p, Xⁱ, ::RealNumbers)
n = get_parameter(M.size)[1]
return [
0 Xⁱ[1:n] Xⁱ[2 * n + 1]
zeros(n, n + 1) Xⁱ[(n + 1):(2 * n)]'
zeros(1, n + 2)
]
end

function get_vector_orthonormal!(M::HeisenbergMatrices, X, p, Xⁱ, ::RealNumbers)
n = get_parameter(M.size)[1]
fill!(X, 0)
X[1, 2:(n + 1)] .= Xⁱ[1:n]
X[2:(n + 1), n + 2] .= Xⁱ[(n + 1):(2 * n)]
X[1, n + 2] = Xⁱ[2 * n + 1]
return X
end

"""
is_flat(::HeisenbergMatrices)

Expand All @@ -119,6 +186,44 @@ Return the dimension of [`HeisenbergMatrices`](@ref)`(n)`, which is equal to ``2
"""
manifold_dimension(M::HeisenbergMatrices) = 2 * get_parameter(M.size)[1] + 1

@doc raw"""
Random.rand(M::HeisenbergMatrices; vector_at = nothing, σ::Real=1.0)

If `vector_at` is `nothing`, return a random point on the [`HeisenbergMatrices`](@ref) `M`
by sampling elements of the first row and the last column from the normal distribution with
mean 0 and standard deviation `σ`.

If `vector_at` is not `nothing`, return a random tangent vector from the tangent space of
the point `vector_at` on the [`HeisenbergMatrices`](@ref) by using a normal distribution with
mean 0 and standard deviation `σ`.
"""
rand(M::HeisenbergMatrices; vector_at=nothing, σ::Real=1.0)

function Random.rand!(
rng::AbstractRNG,
M::HeisenbergMatrices,
pX;
σ::Real=one(eltype(pX)),
vector_at=nothing,
)
n = ManifoldsBase.get_parameter(M.size)[1]
if vector_at === nothing
copyto!(pX, I)
va = view(pX, 1, 2:(n + 2))
randn!(rng, va)
va .*= σ
vb = view(pX, 2:(n + 1), n + 2)
randn!(rng, vb)
vb .*= σ
else
fill!(pX, 0)
randn!(rng, view(pX, 1, 2:(n + 2)))
randn!(rng, view(pX, 2:(n + 1), n + 2))
pX .*= σ
end
return pX
end

function Base.show(io::IO, ::HeisenbergMatrices{TypeParameter{Tuple{n}}}) where {n}
return print(io, "HeisenbergMatrices($(n))")
end
Expand Down
41 changes: 41 additions & 0 deletions src/manifolds/InvertibleMatrices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@
return Euclidean(n, n; field=𝔽, parameter=:field)
end

function get_vector(

Check warning on line 70 in src/manifolds/InvertibleMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/InvertibleMatrices.jl#L70

Added line #L70 was not covered by tests
M::InvertibleMatrices{<:Any,ℝ},
p,
Xⁱ,
::DefaultOrthonormalBasis{ℝ,TangentSpaceType},
)
n = get_parameter(M.size)[1]
return reshape(Xⁱ, n, n)

Check warning on line 77 in src/manifolds/InvertibleMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/InvertibleMatrices.jl#L76-L77

Added lines #L76 - L77 were not covered by tests
end

function get_vector!(

Check warning on line 80 in src/manifolds/InvertibleMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/InvertibleMatrices.jl#L80

Added line #L80 was not covered by tests
::InvertibleMatrices{<:Any,ℝ},
X,
p,
Xⁱ,
::DefaultOrthonormalBasis{ℝ,TangentSpaceType},
)
return copyto!(X, Xⁱ)

Check warning on line 87 in src/manifolds/InvertibleMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/InvertibleMatrices.jl#L87

Added line #L87 was not covered by tests
end

"""
is_flat(::InvertibleMatrices)

Expand All @@ -84,6 +104,27 @@
return manifold_dimension(get_embedding(M))
end

@doc raw"""
Random.rand(M::InvertibleMatrices; vector_at=nothing, kwargs...)

If `vector_at` is `nothing`, return a random point on the [`InvertibleMatrices`](@ref)
manifold `M` by using `rand` in the embedding.

If `vector_at` is not `nothing`, return a random tangent vector from the tangent space of
the point `vector_at` on the [`InvertibleMatrices`](@ref) by using by using `rand` in the
embedding.
"""
rand(M::InvertibleMatrices; kwargs...)

function Random.rand!(M::InvertibleMatrices, pX; kwargs...)
rand!(get_embedding(M), pX; kwargs...)
return pX
end
function Random.rand!(rng::AbstractRNG, M::InvertibleMatrices, pX; kwargs...)
rand!(rng, get_embedding(M), pX; kwargs...)
return pX

Check warning on line 125 in src/manifolds/InvertibleMatrices.jl

View check run for this annotation

Codecov / codecov/patch

src/manifolds/InvertibleMatrices.jl#L123-L125

Added lines #L123 - L125 were not covered by tests
end

function Base.show(io::IO, ::InvertibleMatrices{𝔽,TypeParameter{Tuple{n}}}) where {n,𝔽}
return print(io, "InvertibleMatrices($(n), $(𝔽))")
end
Expand Down
3 changes: 3 additions & 0 deletions test/manifolds/heisenberg_matrices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ using LinearAlgebra, Manifolds, ManifoldsBase, Test
test_manifold(
M,
pts;
basis_types_to_from=(DefaultOrthonormalBasis(),),
parallel_transport=true,
test_injectivity_radius=true,
test_musical_isomorphisms=false,
test_rand_point=true,
test_rand_tvector=true,
)

@test all(
Expand Down
3 changes: 3 additions & 0 deletions test/manifolds/invertible_matrices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ using LinearAlgebra, Manifolds, ManifoldsBase, Test
@test embed(M, A, A) === A
@test manifold_dimension(M) == 9
@test Weingarten(M, A, A, A) == zero(A)

@test is_point(M, rand(M))
@test is_vector(M, A, rand(M; vector_at=A))
end
@testset "Complex invertible matrices" begin
@test repr(Mc) == "InvertibleMatrices(3, ℂ)"
Expand Down
Loading