From 592e3a0085c8c6f41be243a8706c982b015b1e89 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 23 Dec 2023 18:18:09 +0100 Subject: [PATCH 01/65] Start documentation of the symplectic Grassmann. --- NEWS.md | 148 ++++++++++++++------------- src/manifolds/Grassmann.jl | 2 +- src/manifolds/SymplecticGrassmann.jl | 77 ++++++++++++++ src/manifolds/SymplecticStiefel.jl | 41 ++++---- 4 files changed, 174 insertions(+), 94 deletions(-) create mode 100644 src/manifolds/SymplecticGrassmann.jl diff --git a/NEWS.md b/NEWS.md index e54201ab67..bc1ae148a5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,119 +5,125 @@ 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.9.8] - 2023-11-17 +## [unreleased] 2023-12-x + +### Added + +* added the real symplectic Grassmann manifold `SymplecticGrassmann` + +## [0.9.8] * 2023-11-17 ### Fixed -- Improved distribution of random vector generation for rotation matrices and complex circle. +* Improved distribution of random vector generation for rotation matrices and complex circle. -## [0.9.7] - 2023-11-14 +## [0.9.7] * 2023-11-14 ### Fixed -- Fixed `is_flat` for `CholeskySpace` and `SymmetricPositiveDefinite` with `LogCholeskyMetric` [https://github.com/JuliaManifolds/Manifolds.jl/issues/684](https://github.com/JuliaManifolds/Manifolds.jl/issues/684). +* Fixed `is_flat` for `CholeskySpace` and `SymmetricPositiveDefinite` with `LogCholeskyMetric` [https://github.com/JuliaManifolds/Manifolds.jl/issues/684](https://github.com/JuliaManifolds/Manifolds.jl/issues/684). -## [0.9.6] - 2023-11-09 +## [0.9.6] * 2023-11-09 ### Fixed -- Fixed real coefficient basis for complex circle (an issue exposed by [https://github.com/JuliaManifolds/ManifoldsBase.jl/pull/173](https://github.com/JuliaManifolds/ManifoldsBase.jl/pull/173)). -- Fixed `VeeOrthogonalBasis` test for non-real manifolds. +* Fixed real coefficient basis for complex circle (an issue exposed by [https://github.com/JuliaManifolds/ManifoldsBase.jl/pull/173](https://github.com/JuliaManifolds/ManifoldsBase.jl/pull/173)). +* Fixed `VeeOrthogonalBasis` test for non-real manifolds. -## [0.9.5] - 2023-11-08 +## [0.9.5] * 2023-11-08 ### Changed -- `identity_element` now returns a complex matrix for unitary group. -- `number_of_coordinates` is now exported. +* `identity_element` now returns a complex matrix for unitary group. +* `number_of_coordinates` is now exported. -## [0.9.4] - 2023-11-06 +## [0.9.4] * 2023-11-06 ### Added -- Functions `inv_diff`, `inv_diff!`, `adjoint_inv_diff` and `adjoint_inv_diff!` that correspond to differentials and pullbacks of group inversion. -- Julia 1.10-rc CI workflow. +* Functions `inv_diff`, `inv_diff!`, `adjoint_inv_diff` and `adjoint_inv_diff!` that correspond to differentials and pullbacks of group inversion. +* Julia 1.10-rc CI workflow. ### Changed -- Documentation project files are marked as compatible with `BoundaryValueDiffEq` v5. +* Documentation project files are marked as compatible with `BoundaryValueDiffEq` v5. ### Fixed -- Fixed issue with incorrect implementation of `apply_diff_group` in `GroupOperationAction` with left backward and right forward action [#669](https://github.com/JuliaManifolds/Manifolds.jl/issues/669). +* Fixed issue with incorrect implementation of `apply_diff_group` in `GroupOperationAction` with left backward and right forward action [#669](https://github.com/JuliaManifolds/Manifolds.jl/issues/669). -## [0.9.3] - 2023-10-28 +## [0.9.3] * 2023-10-28 ### Added -- Support for `BoundaryValueDiffEq` v5. +* Support for `BoundaryValueDiffEq` v5. -## [0.9.2] - 2023-10-27 +## [0.9.2] * 2023-10-27 ### Added -- `rand(G; vector_at=Identity(G))` now works for translation, special orthogonal and special Euclidean groups `G` (issue [#665](https://github.com/JuliaManifolds/Manifolds.jl/issues/665)). -- `get_embedding` now works for `GeneralUnitaryMultiplicationGroup`. -- Github action that checks for NEWS.md changes. +* `rand(G; vector_at=Identity(G))` now works for translation, special orthogonal and special Euclidean groups `G` (issue [#665](https://github.com/JuliaManifolds/Manifolds.jl/issues/665)). +* `get_embedding` now works for `GeneralUnitaryMultiplicationGroup`. +* Github action that checks for NEWS.md changes. -## [0.9.1] - 2023-10-25 +## [0.9.1] * 2023-10-25 ### Added -- a new retraction and its inverse for the fixed Rank Manifolds, the orthographic retraction. +* a new retraction and its inverse for the fixed Rank Manifolds, the orthographic retraction. -## [0.9.0] - 2023-10-24 +## [0.9.0] * 2023-10-24 ### Added -- Vector bundles are generalized to fiber bundles. Old `BundleFibers` functionality was reworked to better match mathematical abstractions. Fiber bundle functionality is experimental and minor changes may happen without a breaking release, with the exception of `TangentBundle` which is considered to be stable. -- `RotationTranslationAction` is introduced. +* Vector bundles are generalized to fiber bundles. Old `BundleFibers` functionality was reworked to better match mathematical abstractions. Fiber bundle functionality is experimental and minor changes may happen without a breaking release, with the exception of `TangentBundle` which is considered to be stable. +* `RotationTranslationAction` is introduced. ### Changed -- Sizes of all manifolds can now be either encoded in type or stored in a field to avoid over-specialization. +* Sizes of all manifolds can now be either encoded in type or stored in a field to avoid over-specialization. The default is set to store the size in type parameter (except for `PowerManifold` and its variants), replicating the previous behavior. For field storage, pass the `parameter=:field` keyword argument to manifold constructor. For example statically sized `CenteredMatrices{m,n}` is now `CenteredMatrices{TypeParameter{Tuple{m,n}}}`, whereas the type of special Euclidean group with field-stored size is `CenteredMatrices{Tuple{Int,Int}}`. Similar change applies to: - - `CenteredMatrices{m,n}`, - - `CholeskySpace{N}`, - - `Elliptope{N,K}`, - - `Euclidean`, - - `FixedRankMatrices{m,n,k}`, - - `KendallsPreShapeSpace{n,k}`, - - `KendallsShapeSpace{n,k}`, - - `GeneralLinear{n}`, - - `GeneralUnitaryMultiplicationGroup{n}`, - - `GeneralizedGrassmann{n,k}`, - - `GeneralizedStiefel{n,k}`, - - `Grassmann{n,k}`, - - `Heisenberg{n}`, - - `Hyperbolic{n}`, - - `MultinomialMatrices{N,M}`, - - `MultinomialDoublyStochastic{n}`, - - `MultinomialSymmetric{n}`, - - `Orthogonal{n}`, - - `PowerManifold`, - - `PositiveArrays`, - - `PositiveMatrices`, - - `PositiveNumbers`, - - `ProbabilitySimplex{n}`, - - `SPDFixedDeterminant{n}`, - - `SpecialLinear{n}`, - - `SpecialOrthogonal{n}`, - - `SpecialUnitary{n}`, - - `SpecialEuclidean{n}`, - - `SpecialEuclideanManifold{n}`, - - `Spectrahedron{n,k}`, - - `SphereSymmetricMatrices{N}`, - - `Stiefel{n,k}`, - - `SymmetricMatrices{N}`, - - `SymmetricPositiveDefinite{n}`, - - `SymmetricPositiveSemidefiniteFixedRank{n,k}`, - - `Symplectic{n}`, - - `SymplecticStiefel{n,k}`, - - `TranslationGroup`, - - `Tucker`. + * `CenteredMatrices{m,n}`, + * `CholeskySpace{N}`, + * `Elliptope{N,K}`, + * `Euclidean`, + * `FixedRankMatrices{m,n,k}`, + * `KendallsPreShapeSpace{n,k}`, + * `KendallsShapeSpace{n,k}`, + * `GeneralLinear{n}`, + * `GeneralUnitaryMultiplicationGroup{n}`, + * `GeneralizedGrassmann{n,k}`, + * `GeneralizedStiefel{n,k}`, + * `Grassmann{n,k}`, + * `Heisenberg{n}`, + * `Hyperbolic{n}`, + * `MultinomialMatrices{N,M}`, + * `MultinomialDoublyStochastic{n}`, + * `MultinomialSymmetric{n}`, + * `Orthogonal{n}`, + * `PowerManifold`, + * `PositiveArrays`, + * `PositiveMatrices`, + * `PositiveNumbers`, + * `ProbabilitySimplex{n}`, + * `SPDFixedDeterminant{n}`, + * `SpecialLinear{n}`, + * `SpecialOrthogonal{n}`, + * `SpecialUnitary{n}`, + * `SpecialEuclidean{n}`, + * `SpecialEuclideanManifold{n}`, + * `Spectrahedron{n,k}`, + * `SphereSymmetricMatrices{N}`, + * `Stiefel{n,k}`, + * `SymmetricMatrices{N}`, + * `SymmetricPositiveDefinite{n}`, + * `SymmetricPositiveSemidefiniteFixedRank{n,k}`, + * `Symplectic{n}`, + * `SymplecticStiefel{n,k}`, + * `TranslationGroup`, + * `Tucker`. For example @@ -157,12 +163,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 end ``` -- Argument order for type aliases `RotationActionOnVector` and `RotationTranslationActionOnVector`: most often dispatched on argument is now first. -- A more consistent handling of action direction was introduced. 4-valued `ActionDirection` was split into 2-valued `ActionDirection` (either left or right action) and `GroupActionSide` (action acting from the left or right side). See [https://github.com/JuliaManifolds/Manifolds.jl/issues/637](https://github.com/JuliaManifolds/Manifolds.jl/issues/637) for a design discussion. +* Argument order for type aliases `RotationActionOnVector` and `RotationTranslationActionOnVector`: most often dispatched on argument is now first. +* A more consistent handling of action direction was introduced. 4-valued `ActionDirection` was split into 2-valued `ActionDirection` (either left or right action) and `GroupActionSide` (action acting from the left or right side). See [https://github.com/JuliaManifolds/Manifolds.jl/issues/637](https://github.com/JuliaManifolds/Manifolds.jl/issues/637) for a design discussion. ### Removed -- `ProductRepr` is removed; please use `ArrayPartition` instead. -- Default methods throwing "not implemented" `ErrorException` for some group-related operations. Standard `MethodError` is now thrown instead. -- `LinearAffineMetric` was deprecated in a previous release and the symbol is now removed. +* `ProductRepr` is removed; please use `ArrayPartition` instead. +* Default methods throwing "not implemented" `ErrorException` for some group-related operations. Standard `MethodError` is now thrown instead. +* `LinearAffineMetric` was deprecated in a previous release and the symbol is now removed. Please use `AffineInvariantMetric` instead. diff --git a/src/manifolds/Grassmann.jl b/src/manifolds/Grassmann.jl index c8f23a7612..dca7289c3f 100644 --- a/src/manifolds/Grassmann.jl +++ b/src/manifolds/Grassmann.jl @@ -144,7 +144,7 @@ is_flat(M::Grassmann) = manifold_dimension(M) == 1 @doc raw""" manifold_dimension(M::Grassmann) -Return the dimension of the [`Grassmann(n,k,𝔽)`](@ref) manifold `M`, i.e. +Return the dimension of the [`Grassmann`](@ref)`(n,k,𝔽)` manifold `M`, i.e. ````math \dim \operatorname{Gr}(n,k) = k(n-k) \dim_ℝ 𝔽, diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl new file mode 100644 index 0000000000..2d00cbbe30 --- /dev/null +++ b/src/manifolds/SymplecticGrassmann.jl @@ -0,0 +1,77 @@ +@doc raw""" + SymplecticGrassmann{T,𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType} + +The symplectic Grassmann manifold consists of all symplectic subspaces of +``\mathbb R^{2n}`` of dimension ``2k``, ``n β‰₯ k``. + +This manifold can be represented as corresponding representers on the [`SymplecticStiefel`](@ref) + +````math +\operatorname{SpGr}(n,k) := \bigl\{ \operatorname{span}(p) \ \big| \ p ∈ \operatorname{SpSt}(2n, 2k, \mathhb R)\}, +```` + +or as projectors + +````math +\operatorname{SpGr}(2n, 2k, ℝ) = \bigl\{ p ∈ ℝ^{2n Γ— 2n} \ \big| \ p^2 = p, \operatorname{rank}(p) = 2k, p^+=p \bigr\}, +```` + +where ``β‹…^+`` is defined even more general for ``q∈\mathbb R^{2n Γ— 2k}`` matrices as + +````math +q^+ := J_{2k}^{\mathrm{T}}q^{\mathrm{T}}J_{2n} +\quad\text{ with }\quad +J_{2n} = +\begin{bmatrix} + 0_n & I_n \\ + -I_n & 0_n +\end{bmatrix}. +```` + +See also [`ProjectorPoint`](@ref) and [`StiefelPoint`](@ref) for these two representations, +where arrays are interpreted as those on the Stiefel manifold. + + +The manifold was first introduced in [BendokatZimmermann:2021](@cite) + +# Constructor + + SymplecticGrassmann(2n::Int, 2k::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) + +Generate the (real-valued) symplectic Grassmann manifold. +of ``2k`` dimensional symplectic subspace of ``ℝ^{2n}``. +Note that both dimensions passed to this constructor have to be even. +""" +struct SymplecticGrassmann{T,𝔽} <: AbstractDecoratorManifold{𝔽} + size::T +end + +function SymplecticGrassmann( + two_n::Int, + two_k::Int, + field::AbstractNumbers=ℝ; + parameter::Symbol=:type, +) + size = wrap_type_parameter(parameter, (div(two_n, 2), div(two_k, 2))) + return SymplecticGrassmann{typeof(size),field}(size) +end + +function active_traits(f, ::SymplecticGrassmann, args...) + return merge_traits(IsEmbeddedManifold(), IsQuotientManifold()) +end + +@doc raw""" + manifold_dimension(::SymplecticGrassmann) + +Return the dimension of the [`SymplecticGrassmann`](@ref)`(2n,2k)`, which is + +````math +\operatorname{dim}\operatorname{SpGr}(2n, 2k) = 4(n-k)k, +```` + +see [BendokatZimmermann](@cite), Section 4. +""" +function manifold_dimension(::SymplecticGrassmann) + n, k = get_parameter(M.size) + return 4 * (n - k) * k +end diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 3a4c1c6ebb..2bbc9dd441 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -2,32 +2,29 @@ SymplecticStiefel{T,𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType} The symplectic Stiefel manifold consists of all -$2n Γ— 2k, \; n \geq k$ matrices satisfying the requirement +``2n Γ— 2k, n β‰₯ k`` matrices satisfying the requirement ````math \operatorname{SpSt}(2n, 2k, ℝ) - = \bigl\{ p ∈ ℝ^{2n Γ— 2n} \, \big| \, p^{\mathrm{T}}Q_{2n}p = Q_{2k} \bigr\}, + := \bigl\{ p ∈ ℝ^{2n Γ— 2n} \ \big| \ p^{\mathrm{T}}J_{2n}p = J_{2k} \bigr\}, ```` where ````math -Q_{2n} = -\begin{bmatrix} - 0_n & I_n \\ - -I_n & 0_n -\end{bmatrix}. +J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}. ```` The symplectic Stiefel tangent space at ``p`` can be parametrized as [BendokatZimmermann:2021](@cite) ````math - \begin{align*} +\begin{align*} T_p\operatorname{SpSt}(2n, 2k) - = \{&X \in \mathbb{R}^{2n \times 2k} \;|\; p^{T}Q_{2n}X + X^{T}Q_{2n}p = 0 \}, \\ - = \{&X = pΞ© + p^sB \;|\; + &= \{X ∈ \mathbb{R}^{2n Γ— 2k} ∣ p^{T}Q_{2n}X + X^{T}Q_{2n}p = 0 \}, \\ + &= \{X = pΞ© + p^sB \mid Ξ© ∈ ℝ^{2k Γ— 2k}, Ξ©^+ = -Ξ©, \\ - &\; p^s ∈ \operatorname{SpSt}(2n, 2(n- k)), B ∈ ℝ^{2(n-k) Γ— 2k}, \}, - \end{align*} + &\qquad & p^s ∈ \operatorname{SpSt}(2n, 2(n- k)), B ∈ ℝ^{2(n-k) Γ— 2k}, \}, +\end{align*} ```` where ``Ξ© \in \mathfrak{sp}(2n,F)`` is Hamiltonian and ``p^s`` means the symplectic complement of ``p`` s.t. ``p^{+}p^{s} = 0``. +Here ``p^+`` denotes the symplecic inverse ``p^+ := J_{2k}^{\mathrm{T}}p^{\mathrm{T}}J_{2n}``. # Constructor SymplecticStiefel(2n::Int, 2k::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) @@ -89,11 +86,11 @@ end check_point(M::SymplecticStiefel, p; kwargs...) Check whether `p` is a valid point on the [`SymplecticStiefel`](@ref), -$\operatorname{SpSt}(2n, 2k)$ manifold. -That is, the point has the right [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and $p^{+}p$ is +``\operatorname{SpSt}(2n, 2k)`` manifold. +That is, the point has the right [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and ``p^{+}p`` is (approximately) the identity, -where for $A \in \mathbb{R}^{2n \times 2k}$, -$A^{+} = Q_{2k}^{\mathrm{T}}A^{\mathrm{T}}Q_{2n}$ is the symplectic inverse, with +where for ``A \in \mathbb{R}^{2n \times 2k}``, +``A^{+} = Q_{2k}^{\mathrm{T}}A^{\mathrm{T}}Q_{2n}`` is the symplectic inverse, with ````math Q_{2n} = \begin{bmatrix} @@ -110,7 +107,7 @@ function check_point(M::SymplecticStiefel, p; kwargs...) return DomainError( expected_zero, ( - "The point p does not lie on $(M) because its symplectic" * + "The point p does not lie on ``(M) because its symplectic" * " inverse composed with itself is not the identity." ), ) @@ -123,8 +120,8 @@ end Checks whether `X` is a valid tangent vector at `p` on the [`SymplecticStiefel`](@ref), ``\operatorname{SpSt}(2n, 2k)`` manifold. First recall the definition of the symplectic -inverse for $A \in \mathbb{R}^{2n \times 2k}$, -$A^{+} = Q_{2k}^{\mathrm{T}}A^{\mathrm{T}}Q_{2n}$ is the symplectic inverse, with +inverse for ``A \in \mathbb{R}^{2n \times 2k}``, +``A^{+} = Q_{2k}^{\mathrm{T}}A^{\mathrm{T}}Q_{2n}`` is the symplectic inverse, with ````math Q_{2n} = \begin{bmatrix} @@ -154,7 +151,7 @@ function check_vector(M::SymplecticStiefel{<:Any,field}, p, X; kwargs...) where hamiltonian_identity_norm, ( "The matrix X is not in the tangent space at point p of the" * - " $(M) manifold, as p^{+}X is not a Hamiltonian matrix." + " ``(M) manifold, as p^{+}X is not a Hamiltonian matrix." ), ) end @@ -623,11 +620,11 @@ function riemannian_gradient!( end function Base.show(io::IO, ::SymplecticStiefel{TypeParameter{Tuple{n,k}},𝔽}) where {n,k,𝔽} - return print(io, "SymplecticStiefel($(2n), $(2k), $(𝔽))") + return print(io, "SymplecticStiefel(``(2n), ``(2k), ``(𝔽))") end function Base.show(io::IO, M::SymplecticStiefel{Tuple{Int,Int},𝔽}) where {𝔽} n, k = get_parameter(M.size) - return print(io, "SymplecticStiefel($(2n), $(2k), $(𝔽); parameter=:field)") + return print(io, "SymplecticStiefel(``(2n), ``(2k), ``(𝔽); parameter=:field)") end @doc raw""" From 0ed78d5bfc243466b9fed74238d049bc40d94fdd Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 3 Jan 2024 09:51:19 +0100 Subject: [PATCH 02/65] Finish manifold doc string by adding the tangent spaces. --- src/manifolds/SymplecticGrassmann.jl | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 2d00cbbe30..11d3c4ec28 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -31,6 +31,24 @@ J_{2n} = See also [`ProjectorPoint`](@ref) and [`StiefelPoint`](@ref) for these two representations, where arrays are interpreted as those on the Stiefel manifold. +The tangent space is either the tangent space from the symplecti Stiefel manifold, where +tangent vectors are representers of their corresponding congruence classes, or for the +representation as projectors, using a [`ProjectorTVector`](@ref) as + +```math + T_p\operatorname{SpGr}(2n, 2k, ℝ) + = \bigl\{ + [X,p] \ \mid\ X ∈ \mathfrac{sp(2n,\mathbb R), Xp+pX = X + \bigr\}, +``` +where +``[X,p] = Xp-pX`` denotes the matrix commutator and +``\mathfrac{sp}(2n,\mathbb R) = \{ X \in \mathbb R^{2n Γ— 2n} \ \mid\ X^+ = -X\}`` +is the Lie algebra of the Hamiltonian matrices. + +For simplicity, the [`ProjectorTVector`](@ref) is stored as just ``X`` from the representation above. + +For the tangent space, arrays are interpreted as being [`StiefelTVector`](@ref)s. The manifold was first introduced in [BendokatZimmermann:2021](@cite) From 3b3d1e3ef3d68ce93cc330f0eccca16eea0f42b8 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 3 Jan 2024 15:19:44 +0100 Subject: [PATCH 03/65] A bit of work on the symplectic inverse. --- src/Manifolds.jl | 9 ++- src/manifolds/Hamiltonian.jl | 42 ++++++++++++++ src/manifolds/Symplectic.jl | 109 ++++++++++++++++++++++------------- 3 files changed, 118 insertions(+), 42 deletions(-) create mode 100644 src/manifolds/Hamiltonian.jl diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 89c466e728..7727d593e7 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -4,6 +4,7 @@ module Manifolds import Base: + ^, angle, copyto!, convert, @@ -445,7 +446,9 @@ include("manifolds/SymmetricPositiveDefiniteLogCholesky.jl") include("manifolds/SymmetricPositiveDefiniteLogEuclidean.jl") include("manifolds/SymmetricPositiveSemidefiniteFixedRank.jl") include("manifolds/Symplectic.jl") +include("manifolds/Hamiltonian.jl") # Hamiltonian requires symplectic include("manifolds/SymplecticStiefel.jl") +include("manifolds/SymplecticGrassmann.jl") # Requires SymplecticStiefel include("manifolds/Tucker.jl") # include("manifolds/ProbabilitySimplex.jl") @@ -659,6 +662,7 @@ export Euclidean, SPDFixedDeterminant, SymmetricPositiveSemidefiniteFixedRank, Symplectic, + SymplecticGrassmann, SymplecticStiefel, SymplecticMatrix, Torus, @@ -682,7 +686,7 @@ export HyperboloidTVector, ProjectorTVector, StiefelTVector export AbstractNumbers, ℝ, β„‚, ℍ - +export Hamiltonian # decorator manifolds export AbstractDecoratorManifold export IsIsometricEmbeddedManifold, IsEmbeddedManifold, IsEmbeddedSubmanifold @@ -775,6 +779,7 @@ export CachedBasis, export ComponentManifoldError, CompositeManifoldError # Functions on Manifolds export Γ—, + ^, action_side, allocate, allocate_result, @@ -900,6 +905,8 @@ export Γ—, skewness, std, sym_rem, + symplectic_inverse, + symplectic_inverse!, symplectic_inverse_times, symplectic_inverse_times!, submanifold, diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl new file mode 100644 index 0000000000..af5b1fd6f3 --- /dev/null +++ b/src/manifolds/Hamiltonian.jl @@ -0,0 +1,42 @@ +# +# This file requires Symplectic to be defined, since it need the symplectic inverse A^+ +# +@doc raw""" + Hamiltonian{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T} + +A type to store an hamiltonien matrix, i.e. A square matrix matrix for which ``A^+ = -A`` where + +```math +A^+ = J_{2n}A^{\mathrm{T}}J_{2n}, \qquad J_{2n} \begin{pmatrix} 0 & I_n\\-I_n & 0 \end{pmatrix}, +``` + +and ``I_n`` denotes the ``n Γ— n`` +""" + +struct Hamiltonian{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T} + data::S + function Hamiltonian(A::S) where {T,S<:AbstractMatrix{<:T}} + n = div(size(A, 1), 2) + @assert size(A, 1) == 2 * n "The first dimension of A ($(size(A,1))) is not even" + @assert size(A, 2) == 2 * n "The matrix A is of size ($(size(A))), which is not square." + return new{T,S}(A) + end +end + +# Conversion +function Matrix(A::Hamiltonian) + return copy(A.data) +end + +@doc raw""" + ^(A::Hamilonian, ::typeof(+)) + +Compute the [`symplectic_inverse`](@ref) of a Hamiltonian (A) +""" +function ^(A::Hamiltonian, ::typeof(+)) + return Hamiltonian(symplectic_inverse(A.data)) +end + +function show(io::IO, A::Hamiltonian) + return print(io, "Hamiltonian($(A.data))") +end diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index 67b3492b3f..3a40b39e9d 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -433,60 +433,78 @@ function inner(M::Symplectic{<:Any,ℝ}, p, X, Y) end @doc raw""" - inv(::Symplectic, A) - inv!(::Symplectic, A) + symplectic_inverse(A) + +Given a matrix +``math + A ∈ ℝ^{2n Γ— 2k},\quad + A = + \begin{bmatrix} + A_{1,1} & A_{1,2} \\ + A_{2,1} & A_{2, 2} + \end{bmatrix} +``` -Compute the symplectic inverse ``A^+`` of matrix ``A ∈ ℝ^{2n Γ— 2n}``. Given a matrix -````math -A ∈ ℝ^{2n Γ— 2n},\quad -A = -\begin{bmatrix} -A_{1,1} & A_{1,2} \\ -A_{2,1} & A_{2, 2} -\end{bmatrix} -```` the symplectic inverse is defined as: -````math -A^{+} := Q_{2n}^{\mathrm{T}} A^{\mathrm{T}} Q_{2n}, -```` + +```math +A^{+} := Q_{2k}^{\mathrm{T}} A^{\mathrm{T}} Q_{2n}, +``` + where -````math -Q_{2n} = -\begin{bmatrix} -0_n & I_n \\ - -I_n & 0_n -\end{bmatrix}. -```` + +```math + Q_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}. +``` + The symplectic inverse of A can be expressed explicitly as: -````math + +```math A^{+} = -\begin{bmatrix} - A_{2, 2}^{\mathrm{T}} & -A_{1, 2}^{\mathrm{T}} \\[1.2mm] - -A_{2, 1}^{\mathrm{T}} & A_{1, 1}^{\mathrm{T}} -\end{bmatrix}. -```` + \begin{bmatrix} + A_{2, 2}^{\mathrm{T}} & -A_{1, 2}^{\mathrm{T}} \\[1.2mm] + -A_{2, 1}^{\mathrm{T}} & A_{1, 1}^{\mathrm{T}} + \end{bmatrix}. +``` + """ -function Base.inv(M::Symplectic{<:Any,ℝ}, A) - n = get_parameter(M.size)[1] - Ai = similar(A) - checkbounds(A, 1:(2n), 1:(2n)) - @inbounds for i in 1:n, j in 1:n - Ai[i, j] = A[j + n, i + n] +function symplectic_inverse(A::AbstractMatrix) + N, K = size(A) + @assert iseven(N) "The first matrix dimension of A ($N) has to be even" + @assert iseven(K) "The second matrix dimension of A ($K) has to be even" + n = div(N, 2) + k = div(K, 2) + Ai = similar(A') + checkbounds(A, 1:(2n), 1:(2k)) + @inbounds for i in 1:k, j in 1:n + Ai[i, j] = A[j + n, i + k] end - @inbounds for i in 1:n, j in 1:n - Ai[i + n, j] = -A[j + n, i] + @inbounds for i in 1:k, j in 1:n + Ai[i + k, j] = -A[j + n, i] end - @inbounds for i in 1:n, j in 1:n - Ai[i, j + n] = -A[j, i + n] + @inbounds for i in 1:k, j in 1:n + Ai[i, j + n] = -A[j, i + k] end - @inbounds for i in 1:n, j in 1:n - Ai[i + n, j + n] = A[j, i] + @inbounds for i in 1:k, j in 1:n + Ai[i + k, j + n] = A[j, i] end return Ai end -function inv!(M::Symplectic{<:Any,ℝ}, A) - n = get_parameter(M.size)[1] +@doc raw""" + inv(::Symplectic, A) + inv!(::Symplectic, A) + +Compute the symplectic inverse ``A^+`` of matrix ``A ∈ ℝ^{2n Γ— 2n}``. See [`symplectic_inverse`](@ref) +for details. + +""" +function Base.inv(M::Symplectic{<:Any,ℝ}, A) + return symplectic_inverse(A) +end + +function symplectic_inverse!(A) + n = div(size(A, 1), 1) checkbounds(A, 1:(2n), 1:(2n)) @inbounds for i in 1:n, j in 1:n A[i, j], A[j + n, i + n] = A[j + n, i + n], A[i, j] @@ -508,6 +526,15 @@ function inv!(M::Symplectic{<:Any,ℝ}, A) return A end +@doc raw""" + inv!(M::Symplectic, A) + +Compute the symplectic inverse of a suqare matrix A inplace of A +""" +function inv!(M::Symplectic{<:Any,ℝ}, A) + return symplectic_inverse!(A) +end + @doc raw""" inverse_retract(M::Symplectic, p, q, ::CayleyInverseRetraction) From 5d800f6b29eefbd31b7131789797dd5026a08ace Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 5 Jan 2024 12:39:24 +0100 Subject: [PATCH 04/65] Adapt a few docs and default shows, implement symplectic Grassmann checkls. --- docs/make.jl | 2 + docs/src/manifolds/hamiltonian.md | 7 ++ docs/src/manifolds/symplecticgrassmann.md | 30 ++++++++ docs/src/manifolds/symplecticstiefel.md | 2 +- src/Manifolds.jl | 11 +-- src/manifolds/Grassmann.jl | 2 +- src/manifolds/Hamiltonian.jl | 39 +++++++--- src/manifolds/Symplectic.jl | 31 ++++---- src/manifolds/SymplecticGrassmann.jl | 13 +++- src/manifolds/SymplecticGrassmannProjector.jl | 72 +++++++++++++++++++ src/manifolds/SymplecticGrassmannStiefel.jl | 25 +++++++ src/manifolds/SymplecticStiefel.jl | 48 ++++++------- test/manifolds/symplecticstiefel.jl | 2 +- 13 files changed, 226 insertions(+), 58 deletions(-) create mode 100644 docs/src/manifolds/hamiltonian.md create mode 100644 docs/src/manifolds/symplecticgrassmann.md create mode 100644 src/manifolds/SymplecticGrassmannProjector.jl create mode 100644 src/manifolds/SymplecticGrassmannStiefel.jl diff --git a/docs/make.jl b/docs/make.jl index 0caf926f5a..beb636a6f3 100755 --- a/docs/make.jl +++ b/docs/make.jl @@ -113,6 +113,7 @@ makedocs(; "Generalized Stiefel" => "manifolds/generalizedstiefel.md", "Generalized Grassmann" => "manifolds/generalizedgrassmann.md", "Grassmann" => "manifolds/grassmann.md", + "Hamiltonian" => "manifolds/hamiltonian.md", "Hyperbolic space" => "manifolds/hyperbolic.md", "Lorentzian manifold" => "manifolds/lorentz.md", "Multinomial doubly stochastic matrices" => "manifolds/multinomialdoublystochastic.md", @@ -134,6 +135,7 @@ makedocs(; "SPD, fixed determinant" => "manifolds/spdfixeddeterminant.md", "Symmetric positive semidefinite fixed rank" => "manifolds/symmetricpsdfixedrank.md", "Symplectic" => "manifolds/symplectic.md", + "Symplectic Grassmann" => "manifolds/symplecticgrassmann.md", "Symplectic Stiefel" => "manifolds/symplecticstiefel.md", "Torus" => "manifolds/torus.md", "Tucker" => "manifolds/tucker.md", diff --git a/docs/src/manifolds/hamiltonian.md b/docs/src/manifolds/hamiltonian.md new file mode 100644 index 0000000000..0a40cf2049 --- /dev/null +++ b/docs/src/manifolds/hamiltonian.md @@ -0,0 +1,7 @@ +# Symmetric matrices + +```@autodocs +Modules = [Manifolds] +Pages = ["manifolds/Hamiltonian.jl"] +Order = [:type, :function] +``` diff --git a/docs/src/manifolds/symplecticgrassmann.md b/docs/src/manifolds/symplecticgrassmann.md new file mode 100644 index 0000000000..d8d061820f --- /dev/null +++ b/docs/src/manifolds/symplecticgrassmann.md @@ -0,0 +1,30 @@ +# (Real) Symplectic Grassmann + +```@autodocs +Modules = [Manifolds] +Pages = ["manifolds/SymplecticGrassmann.jl"] +Order = [:type, :function] +``` + +## The (default) symplectic Stiefel representation + +```@autodocs +Modules = [Manifolds] +Pages = ["manifolds/SymplecticGrassmannStiefel.jl"] +Order = [:type, :function] +``` + +## The symplectic projector representation + +```@autodocs +Modules = [Manifolds] +Pages = ["manifolds/SymplecticGrassmannProjector.jl"] +Order = [:type, :function] +``` + +## Literature + +```@bibliography +Pages = ["symplecticgrassmann.md"] +Canonical=false +``` \ No newline at end of file diff --git a/docs/src/manifolds/symplecticstiefel.md b/docs/src/manifolds/symplecticstiefel.md index 502f97e211..6251c06841 100644 --- a/docs/src/manifolds/symplecticstiefel.md +++ b/docs/src/manifolds/symplecticstiefel.md @@ -1,4 +1,4 @@ -# Symplectic Stiefel +# (Real) Symplectic Stiefel The [`SymplecticStiefel`](@ref) manifold, denoted $\operatorname{SpSt}(2n, 2k)$, represents canonical symplectic bases of $2k$ dimensonal symplectic subspaces of $\mathbb{R}^{2n \times 2n}$. diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 7727d593e7..c300546695 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -445,10 +445,6 @@ include("manifolds/SymmetricPositiveDefiniteAffineInvariant.jl") include("manifolds/SymmetricPositiveDefiniteLogCholesky.jl") include("manifolds/SymmetricPositiveDefiniteLogEuclidean.jl") include("manifolds/SymmetricPositiveSemidefiniteFixedRank.jl") -include("manifolds/Symplectic.jl") -include("manifolds/Hamiltonian.jl") # Hamiltonian requires symplectic -include("manifolds/SymplecticStiefel.jl") -include("manifolds/SymplecticGrassmann.jl") # Requires SymplecticStiefel include("manifolds/Tucker.jl") # include("manifolds/ProbabilitySimplex.jl") @@ -465,6 +461,13 @@ include("manifolds/KendallsShapeSpace.jl") # Introduce the quotient, Grassmann, only after Stiefel include("manifolds/Grassmann.jl") +# Introduce Symplectic and so on manifolds only after Grassmann +# Since that defines the StiefelPoint, StiefelTVector +include("manifolds/Symplectic.jl") +include("manifolds/Hamiltonian.jl") # Hamiltonian requires symplectic +include("manifolds/SymplecticStiefel.jl") +include("manifolds/SymplecticGrassmann.jl") # Requires SymplecticStiefel + # Product or power based manifolds include("manifolds/Torus.jl") include("manifolds/Multinomial.jl") diff --git a/src/manifolds/Grassmann.jl b/src/manifolds/Grassmann.jl index bc3b757d3c..28d1068727 100644 --- a/src/manifolds/Grassmann.jl +++ b/src/manifolds/Grassmann.jl @@ -195,7 +195,7 @@ function get_total_space(M::Grassmann{Tuple{Int,Int},𝔽}) where {𝔽} end # -# Reprenter specific implementations in their corresponding subfiles +# Representer specific implementations in their corresponding subfiles # include("GrassmannStiefel.jl") include("GrassmannProjector.jl") diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index af5b1fd6f3..0400094c05 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -1,6 +1,6 @@ # # This file requires Symplectic to be defined, since it need the symplectic inverse A^+ -# +# This type is used in the Symplectic Grassmann @doc raw""" Hamiltonian{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T} @@ -12,9 +12,8 @@ A^+ = J_{2n}A^{\mathrm{T}}J_{2n}, \qquad J_{2n} \begin{pmatrix} 0 & I_n\\-I_n & and ``I_n`` denotes the ``n Γ— n`` """ - struct Hamiltonian{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T} - data::S + value::S function Hamiltonian(A::S) where {T,S<:AbstractMatrix{<:T}} n = div(size(A, 1), 2) @assert size(A, 1) == 2 * n "The first dimension of A ($(size(A,1))) is not even" @@ -22,10 +21,11 @@ struct Hamiltonian{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T} return new{T,S}(A) end end - +# Avoid double wrapping / unwrap if that happened +Hamiltonian(A::Hamiltonian) = Hamiltonian(A.value) # Conversion function Matrix(A::Hamiltonian) - return copy(A.data) + return copy(A.value) end @doc raw""" @@ -34,9 +34,32 @@ end Compute the [`symplectic_inverse`](@ref) of a Hamiltonian (A) """ function ^(A::Hamiltonian, ::typeof(+)) - return Hamiltonian(symplectic_inverse(A.data)) + return Hamiltonian(symplectic_inverse(A.value)) +end + +@doc raw""" + is_hamiltonian(A; kwargs...) + +Test whether a matrix `A` is hamiltonian. +The test consists of verifying whether + +```math +A^+ = -A +``` +where ``A^+`` denotes the [`symplectic_inverse`](@ref) of `A`. + +The passed keyword arguments are passed on to the [`isapprox`](@ref) +check within +""" +function is_hamiltonian(A::AbstractMatrix; kwargs...) + return isapprox(symplectic_inverse(A), -A; kwargs...) +end +function is_hamiltonian(A::Hamiltonian; kwargs...) + return isapprox((A^+).value, -A.value; kwargs...) end -function show(io::IO, A::Hamiltonian) - return print(io, "Hamiltonian($(A.data))") +function show(io::IO, ::MIME"text/plain", A::Hamiltonian) + return print(io, "Hamiltonian($(A.value))") end + +size(A::Hamiltonian) = size(A.value) diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index 3a40b39e9d..7139dc0b8d 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -219,8 +219,7 @@ function check_point( kwargs..., ) where {T} # Perform check that the matrix lives on the real symplectic manifold: - expected_zero = norm(inv(M, p) * p - LinearAlgebra.I) - if !isapprox(expected_zero, 0; atol=atol, kwargs...) + if !isapprox(inv(M, p) * p, LinearAlgebra.I; atol=atol, kwargs...) return DomainError( expected_zero, ( @@ -282,7 +281,7 @@ Compute an approximate geodesic distance between two Symplectic matrices ``p, q \in \operatorname{Sp}(2n)``, as done in [WangSunFiori:2018](@cite). ````math \operatorname{dist}(p, q) - β‰ˆ ||\operatorname{Log}(p^+q)||_{\operatorname{Fr}}, + β‰ˆ \lVert\operatorname{Log}(p^+q)\rVert_{\operatorname{Fr}}, ```` where the ``\operatorname{Log}(\cdot)`` operator is the matrix logarithm. @@ -302,18 +301,20 @@ Then we write the expression for the exponential map from ``p`` to ``q`` as X \in T_p\operatorname{Sp}, ```` and with the geodesic distance between ``p`` and ``q`` given by -``\operatorname{dist}(p, q) = ||X||_p = ||p^+X||_{\operatorname{Fr}}`` +``\operatorname{dist}(p, q) = \lVertX\rVert_p = \lVertp^+X\rVert_{\operatorname{Fr}}`` we see that ````math \begin{align*} - ||\operatorname{Log}(p^+q)||_{\operatorname{Fr}} - &= ||\operatorname{Log}\left( - \operatorname{Exp}((p^{+}X)^{\mathrm{T}}) - \operatorname{Exp}(p^{+}X - (p^{+}X)^{\mathrm{T}}) - \right)||_{\operatorname{Fr}} \\ - &= ||p^{+}X + \frac{1}{2}[(p^{+}X)^{\mathrm{T}}, p^{+}X - (p^{+}X)^{\mathrm{T}}] - + \ldots ||_{\operatorname{Fr}} \\ - &β‰ˆ ||p^{+}X||_{\operatorname{Fr}} = \operatorname{dist}(p, q). + \lVert\operatorname{Log}(p^+q)\rVert_{\operatorname{Fr}} + &=\Bigl\lVert + \operatorname{Log}\bigl( + \operatorname{Exp}((p^{+}X)^{\mathrm{T}}) + \operatorname{Exp}(p^{+}X - (p^{+}X)^{\mathrm{T}}) + \bigr) + \Bigr\rVert_{\operatorname{Fr}} \\ + &=\lVertp^{+}X + \frac{1}{2}[(p^{+}X)^{\mathrm{T}}, p^{+}X - (p^{+}X)^{\mathrm{T}}] + + \ldots\lVert_{\operatorname{Fr}} \\ + &β‰ˆ\lVertp^{+}X\rVert_{\operatorname{Fr}} = \operatorname{dist}(p, q). \end{align*} ```` """ @@ -504,7 +505,7 @@ function Base.inv(M::Symplectic{<:Any,ℝ}, A) end function symplectic_inverse!(A) - n = div(size(A, 1), 1) + n = div(size(A, 1), 2) checkbounds(A, 1:(2n), 1:(2n)) @inbounds for i in 1:n, j in 1:n A[i, j], A[j + n, i + n] = A[j + n, i + n], A[i, j] @@ -612,8 +613,8 @@ the euclidean metric of the embedding ``\mathbb{R}^{2n \times 2n}``. That is, we find the element ``X \in T_p\operatorname{SpSt}(2n, 2k)`` which solves the constrained optimization problem ````math - \operatorname{min}_{X \in \mathbb{R}^{2n \times 2n}} \frac{1}{2}||X - A||^2, \quad - \text{s.t.}\; + \operatorname{min}_{X \in \mathbb{R}^{2n \times 2n}} \frac{1}{2}\lVert X - A\rVert^2, \quad + \text{such that}\; h(X) \colon= X^{\mathrm{T}} Q p + p^{\mathrm{T}} Q X = 0, ```` where ``h\colon\mathbb{R}^{2n \times 2n} \rightarrow \operatorname{skew}(2n)`` defines diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 11d3c4ec28..8073841516 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -7,7 +7,7 @@ The symplectic Grassmann manifold consists of all symplectic subspaces of This manifold can be represented as corresponding representers on the [`SymplecticStiefel`](@ref) ````math -\operatorname{SpGr}(n,k) := \bigl\{ \operatorname{span}(p) \ \big| \ p ∈ \operatorname{SpSt}(2n, 2k, \mathhb R)\}, +\operatorname{SpGr}(2n,2k) := \bigl\{ \operatorname{span}(p) \ \big| \ p ∈ \operatorname{SpSt}(2n, 2k, \mathhb R)\}, ```` or as projectors @@ -78,6 +78,9 @@ function active_traits(f, ::SymplecticGrassmann, args...) return merge_traits(IsEmbeddedManifold(), IsQuotientManifold()) end +# Define Stiefel as the array fallback +ManifoldsBase.@default_manifold_fallbacks SymplecticGrassmann StiefelPoint StiefelTVector value value + @doc raw""" manifold_dimension(::SymplecticGrassmann) @@ -89,7 +92,13 @@ Return the dimension of the [`SymplecticGrassmann`](@ref)`(2n,2k)`, which is see [BendokatZimmermann](@cite), Section 4. """ -function manifold_dimension(::SymplecticGrassmann) +function manifold_dimension(::SymplecticGrassmann{<:Any,ℝ}) n, k = get_parameter(M.size) return 4 * (n - k) * k end + +# +# Representer specific implementations in their corrsponding subfiles +# +include("SymplecticGrassmannStiefel.jl") +include("SymplecticGrassmannProjector.jl") diff --git a/src/manifolds/SymplecticGrassmannProjector.jl b/src/manifolds/SymplecticGrassmannProjector.jl new file mode 100644 index 0000000000..312058f841 --- /dev/null +++ b/src/manifolds/SymplecticGrassmannProjector.jl @@ -0,0 +1,72 @@ +@doc raw""" + check_point(M::SymplecticGrassmann, p::ProjectorPoint; kwargs...) + +Check whether `p` is a valid point on the [`SymplecticGrassmann`](@ref), +``\operatorname{SpGr}(2n, 2k)``, that is a propoer symplectic projection: + +* ``p^2 = p``, that is ``p`` is a projection +* ``\operatorname{rank(p) = 2k``, that is, the supspace projected onto is of right dimension +* ``p^+ = p`` the projection is symplectic. +""" +function check_point(M::SymplecticGrassmann, p::ProjectorPoint; kwargs...) + n, k = get_parameter(M.size) + c = p.value * p.value + if !isapprox(c, p.value; kwargs...) + return DomainError( + norm(c - p.value), + "The point $(p) is not equal to its square $c, so it does not lie on $M.", + ) + end + if !isapprox(p.value, symplectic_inverse(p.value); kwargs...) + return DomainError( + norm(p.value - symplectic_inverse(p.value)), + "The point $(p) is not equal to its symplectic inverse p^+, so it does not lie on $M.", + ) + end + k2 = rank(p.value; kwargs...) + if k2 != 2 * k + return DomainError( + k2, + "The point $(p) is a projector of rank $k2 and not of rank $(2*k), so it does not lie on $(M).", + ) + end + return nothing +end + +@doc raw""" + check_vector(M::SymplecticGrassmann, p::ProjectorPoint, X::ProjectorTVector; kwargs...) + +Check whether `X` is a valid tangent vector at `p` on the [`SymplecticGrassmann`](@ref), +``\operatorname{SpGr}(2n, 2k)`` manifold by verifying that it + +* ``X^+ = -X``, verify that `X` is [`Hamiltonian`](@ref) +* ``X = Xp + pX`` + +For details see Proposition 4.2 in [BendokatZimmermannAbsil:2020](@cite) and the definition of ``\mathfrac{sp}_P(2n)`` before, +especially the ``\bar{Ξ©}``, which is the representation for ``X`` used here. +""" +function check_point( + M::SymplecticGrassmann, + p::ProjectorPoint, + X::ProjectorTVector; + kwargs..., +) + n, k = get_parameter(M.size) + if !is_hamiltonian(X.value; kwargs...) + return DomainError( + norm(Hamiltonian(X.value)^+X.value), + ( + "The matrix X is not in the tangent space at $p of $M, since X is not Hamiltonian." + ), + ) + end + XppX = X.value * p.value .+ p.value * X.value + if !isapprox(X.value, XppX; kwargs...) + return DomainError( + norm(XppX - X.value), + ( + "The matrix X is not in the tangent space at $p of $M, since X is not Hamiltonian." + ), + ) + end +end diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl new file mode 100644 index 0000000000..4e351090c1 --- /dev/null +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -0,0 +1,25 @@ +@doc raw""" + check_point(M::SymplecticGrassmann, p; kwargs...) + +Check whether `p` is a valid point on the [`SymplecticGrassmann`](@ref), +``\operatorname{SpGr}(2n, 2k)`` manifold by verifying that it +is a valid representer of an equivalence class of the corersponding +[`SymplecticStiefel`](@ref) manifold. +""" +function check_point(M::SymplecticGrassmann, p; kwargs...) + n, k = get_parameter(M.size) + return check_point(SymplecticStiefel(2 * n, 2 * k), p; kwargs...) +end + +@doc raw""" + check_vector(M::SymplecticGrassmann, p, X; kwargs...) + +Check whether `X` is a valid tangent vector at `p` on the [`SymplecticGrassmann`](@ref), +``\operatorname{SpGr}(2n, 2k)`` manifold by verifying that it +is a valid representer of an equivalence class of the corersponding +[`SymplecticStiefel`](@ref) manifolds tangent space at `p`. +""" +function check_point(M::SymplecticGrassmann, p, X; kwargs...) + n, k = get_parameter(M.size) + return check_vector(SymplecticStiefel(2 * n, 2 * k), p, X; kwargs...) +end diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 89e0cc6a83..9ad7bb8eb9 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -3,16 +3,20 @@ The symplectic Stiefel manifold consists of all ``2n Γ— 2k, n β‰₯ k`` matrices satisfying the requirement + ````math \operatorname{SpSt}(2n, 2k, ℝ) := \bigl\{ p ∈ ℝ^{2n Γ— 2n} \ \big| \ p^{\mathrm{T}}J_{2n}p = J_{2k} \bigr\}, ```` + where + ````math J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}. ```` The symplectic Stiefel tangent space at ``p`` can be parametrized as [BendokatZimmermann:2021](@cite) + ````math \begin{align*} T_p\operatorname{SpSt}(2n, 2k) @@ -22,10 +26,14 @@ The symplectic Stiefel tangent space at ``p`` can be parametrized as [BendokatZi &\qquad & p^s ∈ \operatorname{SpSt}(2n, 2(n- k)), B ∈ ℝ^{2(n-k) Γ— 2k}, \}, \end{align*} ```` -where ``Ξ© \in \mathfrak{sp}(2n,F)`` is Hamiltonian and ``p^s`` means + +where ``Ξ© \in \mathfrak{sp}(2n,F)`` is [`Hamiltonian`](@ref) and ``p^s`` means the symplectic complement of ``p`` s.t. ``p^{+}p^{s} = 0``. Here ``p^+`` denotes the symplecic inverse ``p^+ := J_{2k}^{\mathrm{T}}p^{\mathrm{T}}J_{2n}``. +You can also use [`StiefelPoint`](@ref) and [`StiefelTVector`](@ref) with this manifold, +they are equivalent to using arrays. + # Constructor SymplecticStiefel(2n::Int, 2k::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) @@ -53,6 +61,9 @@ function active_traits(f, ::SymplecticStiefel, args...) return merge_traits(IsEmbeddedManifold(), IsDefaultMetric(RealSymplecticMetric())) end +# Define Stiefel as the array fallback +ManifoldsBase.@default_manifold_fallbacks SymplecticStiefel StiefelPoint StiefelTVector value value + function ManifoldsBase.default_inverse_retraction_method(::SymplecticStiefel) return CayleyInverseRetraction() end @@ -100,19 +111,13 @@ Q_{2n} = ```` The tolerance can be set with `kwargs...` (e.g. `atol = 1.0e-14`). """ -function check_point( - M::SymplecticStiefel, - p::T; - atol::Real=sqrt(prod(representation_size(M))) * eps(real(float(number_eltype(T)))), - kwargs..., -) where {T} +function check_point(M::SymplecticStiefel{<:Any,ℝ}, p::T; kwargs...) where {T} # Perform check that the matrix lives on the real symplectic manifold: - expected_zero = norm(inv(M, p) * p - I) - if !isapprox(expected_zero, 0; atol=atol, kwargs...) + if !isapprox(inv(M, p) * p, I; kwargs...) return DomainError( - expected_zero, + norm(inv(M, p) * p - I), ( - "The point p does not lie on ``(M) because its symplectic" * + "The point p does not lie on $(M) because its symplectic" * " inverse composed with itself is not the identity." ), ) @@ -144,25 +149,16 @@ The tolerance can be set with `kwargs...` (e.g. `atol = 1.0e-14`). """ check_vector(::SymplecticStiefel, ::Any...) -function check_vector( - M::SymplecticStiefel{S,𝔽}, - p, - X::T; - atol::Real=sqrt(prod(representation_size(M))) * eps(real(float(number_eltype(T)))), - kwargs..., -) where {S,T,𝔽} +function check_vector(M::SymplecticStiefel{S,𝔽}, p, X::T; kwargs...) where {S,T,𝔽} n, k = get_parameter(M.size) # From Bendokat-Zimmermann: T_pSpSt(2n, 2k) = \{p*H | H^{+} = -H \} H = inv(M, p) * X # ∈ ℝ^{2k Γ— 2k}, should be Hamiltonian. - H_star = inv(Symplectic(2k, 𝔽), H) - hamiltonian_identity_norm = norm(H + H_star) - if !isapprox(hamiltonian_identity_norm, 0; atol=atol, kwargs...) + if !is_hamiltonian(H; kwargs...) return DomainError( - hamiltonian_identity_norm, + norm(Hamiltonian(H)^+H), ( - "The matrix X is not in the tangent space at point p of the" * - " ``(M) manifold, as p^{+}X is not a Hamiltonian matrix." + "The matrix X is not in the tangent space at point p of $M at $p, since p^{+}X is not a Hamiltonian matrix." ), ) end @@ -631,11 +627,11 @@ function riemannian_gradient!( end function Base.show(io::IO, ::SymplecticStiefel{TypeParameter{Tuple{n,k}},𝔽}) where {n,k,𝔽} - return print(io, "SymplecticStiefel(``(2n), ``(2k), ``(𝔽))") + return print(io, "SymplecticStiefel($(2n), $(2k); field=$(𝔽))") end function Base.show(io::IO, M::SymplecticStiefel{Tuple{Int,Int},𝔽}) where {𝔽} n, k = get_parameter(M.size) - return print(io, "SymplecticStiefel(``(2n), ``(2k), ``(𝔽); parameter=:field)") + return print(io, "SymplecticStiefel($(2n), $(2k); field=$(𝔽); parameter=:field)") end @doc raw""" diff --git a/test/manifolds/symplecticstiefel.jl b/test/manifolds/symplecticstiefel.jl index db18123d23..542e301390 100644 --- a/test/manifolds/symplecticstiefel.jl +++ b/test/manifolds/symplecticstiefel.jl @@ -137,7 +137,7 @@ end ] @testset "Basics" begin - @test repr(SpSt_6_4) == "SymplecticStiefel(6, 4, ℝ)" + @test repr(SpSt_6_4) == "SymplecticStiefel(6, 4; field=ℝ)" @test representation_size(SpSt_6_4) == (6, 4) @test base_manifold(SpSt_6_4) === SpSt_6_4 @test get_total_space(SpSt_6_4) == Symplectic(6) From c80df094dd7857a5a063026e64d17fdf6b30a187 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 5 Jan 2024 12:46:00 +0100 Subject: [PATCH 05/65] Undo a chick search-and-replace, that was not careful enough. --- NEWS.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/NEWS.md b/NEWS.md index 54812655b7..8243d8f897 100644 --- a/NEWS.md +++ b/NEWS.md @@ -43,27 +43,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Improved distribution of random vector generation for rotation matrices and complex circle. -## [0.9.7] * 2023-11-14 +## [0.9.7] – 2023-11-14 ### Fixed * Fixed `is_flat` for `CholeskySpace` and `SymmetricPositiveDefinite` with `LogCholeskyMetric` [https://github.com/JuliaManifolds/Manifolds.jl/issues/684](https://github.com/JuliaManifolds/Manifolds.jl/issues/684). -## [0.9.6] * 2023-11-09 +## [0.9.6] - 2023-11-09 ### Fixed * Fixed real coefficient basis for complex circle (an issue exposed by [https://github.com/JuliaManifolds/ManifoldsBase.jl/pull/173](https://github.com/JuliaManifolds/ManifoldsBase.jl/pull/173)). * Fixed `VeeOrthogonalBasis` test for non-real manifolds. -## [0.9.5] * 2023-11-08 +## [0.9.5] - 2023-11-08 ### Changed * `identity_element` now returns a complex matrix for unitary group. * `number_of_coordinates` is now exported. -## [0.9.4] * 2023-11-06 +## [0.9.4] - 2023-11-06 ### Added @@ -78,13 +78,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Fixed issue with incorrect implementation of `apply_diff_group` in `GroupOperationAction` with left backward and right forward action [#669](https://github.com/JuliaManifolds/Manifolds.jl/issues/669). -## [0.9.3] * 2023-10-28 +## [0.9.3] - 2023-10-28 ### Added * Support for `BoundaryValueDiffEq` v5. -## [0.9.2] * 2023-10-27 +## [0.9.2] - 2023-10-27 ### Added @@ -92,13 +92,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `get_embedding` now works for `GeneralUnitaryMultiplicationGroup`. * Github action that checks for NEWS.md changes. -## [0.9.1] * 2023-10-25 +## [0.9.1] - 2023-10-25 ### Added * a new retraction and its inverse for the fixed Rank Manifolds, the orthographic retraction. -## [0.9.0] * 2023-10-24 +## [0.9.0] - 2023-10-24 ### Added From 60d29448c8572154b6727d3611f469059672665a Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 5 Jan 2024 14:06:19 +0100 Subject: [PATCH 06/65] Fix docs and tests. --- docs/src/manifolds/grassmann.md | 2 +- docs/src/manifolds/hamiltonian.md | 2 +- src/Manifolds.jl | 1 + src/manifolds/Hamiltonian.jl | 100 +++++++++++++++++- src/manifolds/Symmetric.jl | 18 ++-- src/manifolds/SymplecticGrassmann.jl | 37 +++---- src/manifolds/SymplecticGrassmannProjector.jl | 8 +- src/manifolds/SymplecticGrassmannStiefel.jl | 2 +- test/manifolds/symplecticstiefel.jl | 2 +- 9 files changed, 128 insertions(+), 44 deletions(-) diff --git a/docs/src/manifolds/grassmann.md b/docs/src/manifolds/grassmann.md index 1fb337c887..c3dc8bfc28 100644 --- a/docs/src/manifolds/grassmann.md +++ b/docs/src/manifolds/grassmann.md @@ -10,7 +10,7 @@ Order = [:type,:function] ```@autodocs Modules = [Manifolds] -Pages = ["GrassmannStiefel.jl"] +Pages = ["manifolds/GrassmannStiefel.jl"] Order = [:type,:function] ``` diff --git a/docs/src/manifolds/hamiltonian.md b/docs/src/manifolds/hamiltonian.md index 0a40cf2049..dc5dd48bbb 100644 --- a/docs/src/manifolds/hamiltonian.md +++ b/docs/src/manifolds/hamiltonian.md @@ -1,4 +1,4 @@ -# Symmetric matrices +# Hamiltonian matrices ```@autodocs Modules = [Manifolds] diff --git a/src/Manifolds.jl b/src/Manifolds.jl index c300546695..f2e3ec25d7 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -637,6 +637,7 @@ export Euclidean, GeneralizedGrassmann, GeneralizedStiefel, Grassmann, + HamiltonianMatrices, HeisenbergGroup, Hyperbolic, KendallsPreShapeSpace, diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index 0400094c05..aa4696cc59 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -28,6 +28,43 @@ function Matrix(A::Hamiltonian) return copy(A.value) end +@doc raw""" + HamiltonianMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} + +The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) +consisting of (real-valued) hamiltonian matrices of size ``n Γ— n``, i.e. the set + +````math +\mathfrak{sp}(2n,𝔽) = \bigl\{p ∈ 𝔽^{2n Γ— 2n}\ \big|\ p^+ = p \bigr\}, +```` +where ``\cdot^{+}`` denotes the [`symplectic_inverse`](@ref),. and ``𝔽 ∈ \{ ℝ, β„‚\}``. + +Though it is slightly redundant, usually the matrices are stored as ``2n Γ— 2n`` arrays. + +The symbol refers to the main usage within `Manifolds.jl` that is the +Lie algebra to the [`Symplectic`](@ref) as a Lie group with the matrix operation as group operation. + +# Constructor + + HamiltonianMatrices(n::Int, field::AbstractNumbers=ℝ) + +Generate the manifold of ``n Γ— n`` symmetric matrices. +""" +struct HamiltonianMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} + size::T +end + +function HamiltonianMatrices(n::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) + size = wrap_type_parameter(parameter, (n,)) + return HamiltonianMatrices{typeof(size),field}(size) +end + +function active_traits(f, ::HamiltonianMatrices, args...) + return merge_traits(IsEmbeddedSubmanifold()) +end + +ManifoldsBase.@default_manifold_fallbacks HamiltonianMatrices Hamiltonian Hamiltonian value value + @doc raw""" ^(A::Hamilonian, ::typeof(+)) @@ -37,6 +74,59 @@ function ^(A::Hamiltonian, ::typeof(+)) return Hamiltonian(symplectic_inverse(A.value)) end +@doc raw""" + check_point(M::HamiltonianMatrices{n,𝔽}, p; kwargs...) + +Check whether `p` is a valid manifold point on the [`HamiltonianMatrices`](@ref) `M`, i.e. +whether `p` [`is_hamiltonian`](@ref). + +The tolerance for the test of `p` can be set using `kwargs...`. +""" +function check_point(M::HamiltonianMatrices, p; kwargs...) + if !is_hamiltonian(p; kwargs...) + return DomainError( + norm((Hamiltonian(p)^+) + p), + "The point $(p) does not lie on $M, since it is not hamiltonian.", + ) + end + return nothing +end + +""" + check_vector(M::HamiltonianMatrices{n,𝔽}, p, X; kwargs... ) + +Check whether `X` is a tangent vector to manifold point `p` on the +[`HamiltonianMatrices`](@ref) `M`, i.e. `X` has to be a Hamiltonian matrix +The tolerance for [`is_hamiltonian`](@ref) `X` can be set using `kwargs...`. +""" +function check_vector(M::HamiltonianMatrices, p, X; kwargs...) + if !is_hamiltonian(X; kwargs...) + return DomainError( + norm((Hamiltonian(X)^+) + X), + "The vector $(X) is not a tangent vector to $(p) on $(M), since it is not hamiltonian.", + ) + end + return nothing +end + +embed(::HamiltonianMatrices, p) = p +embed(::HamiltonianMatrices, p, X) = X + +function get_embedding(::HamiltonianMatrices{TypeParameter{Tuple{N}},𝔽}) where {N,𝔽} + return Euclidean(N, N; field=𝔽) +end +function get_embedding(M::HamiltonianMatrices{Tuple{Int},𝔽}) where {𝔽} + N = get_parameter(M.size)[1] + return Euclidean(N, N; field=𝔽, parameter=:field) +end + +""" + is_flat(::HamiltonianMatrices) + +Return true. [`HamiltonianMatrices`](@ref) is a flat manifold. +""" +is_flat(M::HamiltonianMatrices) = true + @doc raw""" is_hamiltonian(A; kwargs...) @@ -48,7 +138,7 @@ A^+ = -A ``` where ``A^+`` denotes the [`symplectic_inverse`](@ref) of `A`. -The passed keyword arguments are passed on to the [`isapprox`](@ref) +The passed keyword arguments are passed on to `isapprox` check within """ function is_hamiltonian(A::AbstractMatrix; kwargs...) @@ -61,5 +151,11 @@ end function show(io::IO, ::MIME"text/plain", A::Hamiltonian) return print(io, "Hamiltonian($(A.value))") end - +function Base.show(io::IO, ::HamiltonianMatrices{TypeParameter{Tuple{n}},F}) where {n,F} + return print(io, "HamiltonianMatrices($(n), $(F))") +end +function Base.show(io::IO, M::HamiltonianMatrices{Tuple{Int},F}) where {F} + n = get_parameter(M.size)[1] + return print(io, "HamiltonianMatrices($(n), $(F); parameter=:field)") +end size(A::Hamiltonian) = size(A.value) diff --git a/src/manifolds/Symmetric.jl b/src/manifolds/Symmetric.jl index 989d3dba29..c39501d8f6 100644 --- a/src/manifolds/Symmetric.jl +++ b/src/manifolds/Symmetric.jl @@ -1,16 +1,16 @@ @doc raw""" SymmetricMatrices{n,𝔽} <: AbstractDecoratorManifold{𝔽} -The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) $ \operatorname{Sym}(n)$ consisting of the real- or complex-valued -symmetric matrices of size $n Γ— n$, i.e. the set +The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) ``\operatorname{Sym}(n)`` consisting of the real- or complex-valued +symmetric matrices of size ``n Γ— n``, i.e. the set ````math \operatorname{Sym}(n) = \bigl\{p ∈ 𝔽^{n Γ— n}\ \big|\ p^{\mathrm{H}} = p \bigr\}, ```` -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, -and the field $𝔽 ∈ \{ ℝ, β„‚\}$. +where ``\cdot^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transpose, +and the field ``𝔽 ∈ \{ ℝ, β„‚\}``. -Though it is slightly redundant, usually the matrices are stored as $n Γ— n$ arrays. +Though it is slightly redundant, usually the matrices are stored as ``n Γ— n`` arrays. Note that in this representation, the complex valued case has to have a real-valued diagonal, which is also reflected in the [`manifold_dimension`](@ref manifold_dimension(::SymmetricMatrices)). @@ -19,7 +19,7 @@ which is also reflected in the [`manifold_dimension`](@ref manifold_dimension(:: SymmetricMatrices(n::Int, field::AbstractNumbers=ℝ) -Generate the manifold of $n Γ— n$ symmetric matrices. +Generate the manifold of ``n Γ— n`` symmetric matrices. """ struct SymmetricMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} size::T @@ -186,7 +186,7 @@ Return the dimension of the [`SymmetricMatrices`](@ref) matrix `M` over the numb \end{aligned} ```` -where the last $-n$ is due to the zero imaginary part for Hermitian matrices +where the last ``-n`` is due to the zero imaginary part for Hermitian matrices """ function manifold_dimension(M::SymmetricMatrices{<:Any,𝔽}) where {𝔽} N = get_parameter(M.size)[1] @@ -202,7 +202,7 @@ Projects `p` from the embedding onto the [`SymmetricMatrices`](@ref) `M`, i.e. \operatorname{proj}_{\operatorname{Sym}(n)}(p) = \frac{1}{2} \bigl( p + p^{\mathrm{H}} \bigr), ```` -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +where ``\cdot^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SymmetricMatrices, ::Any) @@ -220,7 +220,7 @@ Project the matrix `X` onto the tangent space at `p` on the [`SymmetricMatrices` \operatorname{proj}_p(X) = \frac{1}{2} \bigl( X + X^{\mathrm{H}} \bigr), ```` -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +where ``\cdot^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SymmetricMatrices, ::Any, ::Any) diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 8073841516..a694169bc1 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -6,27 +6,17 @@ The symplectic Grassmann manifold consists of all symplectic subspaces of This manifold can be represented as corresponding representers on the [`SymplecticStiefel`](@ref) -````math -\operatorname{SpGr}(2n,2k) := \bigl\{ \operatorname{span}(p) \ \big| \ p ∈ \operatorname{SpSt}(2n, 2k, \mathhb R)\}, -```` +```math +\operatorname{SpGr}(2n,2k) = \bigl\{ \operatorname{span}(p)\ \big| \ p ∈ \operatorname{SpSt}(2n, 2k, ℝ)\}, +``` or as projectors -````math +```math \operatorname{SpGr}(2n, 2k, ℝ) = \bigl\{ p ∈ ℝ^{2n Γ— 2n} \ \big| \ p^2 = p, \operatorname{rank}(p) = 2k, p^+=p \bigr\}, -```` - -where ``β‹…^+`` is defined even more general for ``q∈\mathbb R^{2n Γ— 2k}`` matrices as +``` -````math -q^+ := J_{2k}^{\mathrm{T}}q^{\mathrm{T}}J_{2n} -\quad\text{ with }\quad -J_{2n} = -\begin{bmatrix} - 0_n & I_n \\ - -I_n & 0_n -\end{bmatrix}. -```` +where ``β‹…^+`` is the [`symplectic_inverse`](@ref). See also [`ProjectorPoint`](@ref) and [`StiefelPoint`](@ref) for these two representations, where arrays are interpreted as those on the Stiefel manifold. @@ -36,15 +26,12 @@ tangent vectors are representers of their corresponding congruence classes, or f representation as projectors, using a [`ProjectorTVector`](@ref) as ```math - T_p\operatorname{SpGr}(2n, 2k, ℝ) - = \bigl\{ - [X,p] \ \mid\ X ∈ \mathfrac{sp(2n,\mathbb R), Xp+pX = X - \bigr\}, + T_p\operatorname{SpGr}(2n, 2k, ℝ) = + \bigl\{ [X,p] \ \mid\ X ∈ \mathfrak{sp}(2n,ℝ), Xp+pX = X \bigr\}, ``` -where -``[X,p] = Xp-pX`` denotes the matrix commutator and -``\mathfrac{sp}(2n,\mathbb R) = \{ X \in \mathbb R^{2n Γ— 2n} \ \mid\ X^+ = -X\}`` -is the Lie algebra of the Hamiltonian matrices. + +where ``[X,p] = Xp-pX`` denotes the matrix commutator and +``\mathfrak{sp}(2n,ℝ)`` is the Lie algebra of the symplectic group consisting of [`HamiltonianMatrices`](@ref) For simplicity, the [`ProjectorTVector`](@ref) is stored as just ``X`` from the representation above. @@ -90,7 +77,7 @@ Return the dimension of the [`SymplecticGrassmann`](@ref)`(2n,2k)`, which is \operatorname{dim}\operatorname{SpGr}(2n, 2k) = 4(n-k)k, ```` -see [BendokatZimmermann](@cite), Section 4. +see [BendokatZimmermann:2021](@cite), Section 4. """ function manifold_dimension(::SymplecticGrassmann{<:Any,ℝ}) n, k = get_parameter(M.size) diff --git a/src/manifolds/SymplecticGrassmannProjector.jl b/src/manifolds/SymplecticGrassmannProjector.jl index 312058f841..150959afcb 100644 --- a/src/manifolds/SymplecticGrassmannProjector.jl +++ b/src/manifolds/SymplecticGrassmannProjector.jl @@ -5,7 +5,7 @@ Check whether `p` is a valid point on the [`SymplecticGrassmann`](@ref), ``\operatorname{SpGr}(2n, 2k)``, that is a propoer symplectic projection: * ``p^2 = p``, that is ``p`` is a projection -* ``\operatorname{rank(p) = 2k``, that is, the supspace projected onto is of right dimension +* ``\operatorname{rank}(p) = 2k``, that is, the supspace projected onto is of right dimension * ``p^+ = p`` the projection is symplectic. """ function check_point(M::SymplecticGrassmann, p::ProjectorPoint; kwargs...) @@ -42,10 +42,10 @@ Check whether `X` is a valid tangent vector at `p` on the [`SymplecticGrassmann` * ``X^+ = -X``, verify that `X` is [`Hamiltonian`](@ref) * ``X = Xp + pX`` -For details see Proposition 4.2 in [BendokatZimmermannAbsil:2020](@cite) and the definition of ``\mathfrac{sp}_P(2n)`` before, +For details see Proposition 4.2 in [BendokatZimmermann:2021](@cite) and the definition of ``\mathfrak{sp}_P(2n)`` before, especially the ``\bar{Ξ©}``, which is the representation for ``X`` used here. """ -function check_point( +function check_vector( M::SymplecticGrassmann, p::ProjectorPoint, X::ProjectorTVector; @@ -54,7 +54,7 @@ function check_point( n, k = get_parameter(M.size) if !is_hamiltonian(X.value; kwargs...) return DomainError( - norm(Hamiltonian(X.value)^+X.value), + norm((Hamiltonian(X.value)^+) + X.value), ( "The matrix X is not in the tangent space at $p of $M, since X is not Hamiltonian." ), diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index 4e351090c1..ea36f35a52 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -19,7 +19,7 @@ Check whether `X` is a valid tangent vector at `p` on the [`SymplecticGrassmann` is a valid representer of an equivalence class of the corersponding [`SymplecticStiefel`](@ref) manifolds tangent space at `p`. """ -function check_point(M::SymplecticGrassmann, p, X; kwargs...) +function check_vector(M::SymplecticGrassmann, p, X; kwargs...) n, k = get_parameter(M.size) return check_vector(SymplecticStiefel(2 * n, 2 * k), p, X; kwargs...) end diff --git a/test/manifolds/symplecticstiefel.jl b/test/manifolds/symplecticstiefel.jl index 542e301390..ac851092eb 100644 --- a/test/manifolds/symplecticstiefel.jl +++ b/test/manifolds/symplecticstiefel.jl @@ -311,7 +311,7 @@ end @testset "field parameter" begin SpSt_6_4 = SymplecticStiefel(2 * 3, 2 * 2; parameter=:field) @test typeof(get_embedding(SpSt_6_4)) === Euclidean{Tuple{Int,Int},ℝ} - @test repr(SpSt_6_4) == "SymplecticStiefel(6, 4, ℝ; parameter=:field)" + @test repr(SpSt_6_4) == "SymplecticStiefel(6, 4; field=ℝ; parameter=:field)" @test get_total_space(SpSt_6_4) == Symplectic(6; parameter=:field) end end From 95c984862adefcee64a8de91e3e48fceb4548c80 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 9 Jan 2024 16:08:45 +0100 Subject: [PATCH 07/65] Further work on Symplectic Grasmann --- src/manifolds/QuotientManifold.jl | 16 +++++++++---- src/manifolds/SymplecticGrassmann.jl | 34 +++++++++++++++++++++++++++- src/manifolds/SymplecticStiefel.jl | 14 +++++++----- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/manifolds/QuotientManifold.jl b/src/manifolds/QuotientManifold.jl index 3c806f8b09..8f8f8390c9 100644 --- a/src/manifolds/QuotientManifold.jl +++ b/src/manifolds/QuotientManifold.jl @@ -136,7 +136,7 @@ get_orbit_action(::AbstractManifold) @doc raw""" horizontal_lift(N::AbstractManifold, q, X) - horizontal_lift(::QuotientManifold{𝔽,MT<:AbstractManifold{𝔽},NT<:AbstractManifold}, p, X) where {𝔽} + horizontal_lift(::QuotientManifold{𝔽,M,N}, p, X) Given a point `q` in total space of quotient manifold `N` such that ``p=Ο€(q)`` is a point on a quotient manifold `M` (implicitly given for the first case) and a tangent vector `X` this @@ -150,18 +150,21 @@ end @doc raw""" horizontal_lift!(N, Y, q, X) - horizontal_lift!(QuotientManifold{M,N}, Y, p, X) + horizontal_lift!(QuotientManifold{𝔽,M,N}, Y, p, X) -Compute the [`horizontal_lift`](@ref) of `X` from ``T_p\mathcal M``, ``p=Ο€(q)``. +Compute the horizontal lift of `X` from ``T_p\mathcal M``, ``p=Ο€(q)``. to ``T_q\mathcal N` in place of `Y`. """ horizontal_lift!(N::AbstractManifold, Y, q, X) -""" +@doc raw""" horizontal_component(N::AbstractManifold, p, X) + horizontal_compontent(QuotientManifold{M,N}, p, X) Compute the horizontal component of tangent vector `X` at point `p` in the total space of quotient manifold `N`. + +This is often written as the space ``\mathrm{Hor}_p^Ο€\mathcal N``. """ function horizontal_component(N::AbstractManifold, p, X) Y = allocate_result(N, horizontal_component, X, p) @@ -172,11 +175,14 @@ function Base.show(io::IO, M::QuotientManifold) return print(io, "QuotientManifold($(M.manifold), $(M.total_space))") end -""" +@doc raw""" vertical_component(N::AbstractManifold, p, X) + vertical_compontent(QuotientManifold{M,N}, p, X) Compute the vertical component of tangent vector `X` at point `p` in the total space of quotient manifold `N`. + +This is often written as the space ``\mathrm{ver}_p^Ο€\mathcal N``. """ function vertical_component(N::AbstractManifold, p, X) return X - horizontal_component(N, p, X) diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index a694169bc1..1be5f639d2 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -17,10 +17,15 @@ or as projectors ``` where ``β‹…^+`` is the [`symplectic_inverse`](@ref). - See also [`ProjectorPoint`](@ref) and [`StiefelPoint`](@ref) for these two representations, where arrays are interpreted as those on the Stiefel manifold. +With respect to the quotient structure, the canonical projection ``Ο€ = Ο€_{\mathrm{SpSt},\mathrm{SpGr}}`` is given by + +```math +Ο€: \mathrm{SpSt}(2n2k) β†’ \mathrm{SpGr}(2n,2k), p ↦ Ο€(p) = pp^+. +``` + The tangent space is either the tangent space from the symplecti Stiefel manifold, where tangent vectors are representers of their corresponding congruence classes, or for the representation as projectors, using a [`ProjectorTVector`](@ref) as @@ -68,6 +73,33 @@ end # Define Stiefel as the array fallback ManifoldsBase.@default_manifold_fallbacks SymplecticGrassmann StiefelPoint StiefelTVector value value +@doc raw""" + inner(::SymplecticGrassmann, p, X, Y) + +Compute the Riemannian inner product ``g^{\mathrm{SpGr}}_p(X,Y)``, where ``p`` +is a point on the [`SymplecticStiefel`](@ref) manifold and ``X,Y \in \mathrm{Hor}_p^Ο€\operatorname{SpSt}(2n,2k)`` +are horizontal tangent vectors. The formula reads according to Proposition Lemma 4.8 [BendokatZimmermann:2021](@cite). + +```math +g^{\mathrm{SpGr}_p(X,Y) = \operatorname{tr}\bigl( + (p^{\mathrm{T}p)^{-1}X^{\mathrm{T}}(I_{2n} - pp^+)Y + \bigr), +``` +where ``I_{2n}`` denotes the identity matrix and ``(\cdot)^+`` the [`symplectic_inverse`](@ref). +""" +function inner(M::SymplecticGrassmann, p, X, Y) + n, k = get_parameter(M.size) + Q = SymplecticMatrix(p, X, Y) # in BZ21 also J + # Procompute lu(p'p) since we solve a^{-1}* 3 times + a = lu(p' * p) # note that p'p is symmetric, thus so is its inverse c=a^{-1} + # we split the original trace into two one with I -> (X'Yc) + # 1) we permute X' and Y c to c^{\mathrm{T}}Y^{\mathrm{T}}X = a\(Y'X) (avoids a large interims matrix) + # 2) the second we compute as c (X'p)(p^+Y) since both brackets are the smaller matrices + return tr(a \ (Y' * X)) - tr( + a \ ((X' * p) * symplectic_inverse_times(SymplecticStiefel(2 * n, 2 * k), p, Y)), + ) +end + @doc raw""" manifold_dimension(::SymplecticGrassmann) diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 9ad7bb8eb9..19a84c2ba3 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -308,7 +308,7 @@ function get_total_space(::SymplecticStiefel{TypeParameter{Tuple{n,k}},ℝ}) whe return Symplectic(2 * n) end function get_total_space(M::SymplecticStiefel{Tuple{Int,Int},ℝ}) - n, k = get_parameter(M.size) + n, _ = get_parameter(M.size) return Symplectic(2 * n; parameter=:field) end @@ -320,12 +320,14 @@ Compute the Riemannian inner product ``g^{\operatorname{SpSt}}`` at Given by Proposition 3.10 in [BendokatZimmermann:2021](@cite). ````math g^{\operatorname{SpSt}}_p(X, Y) - = \operatorname{tr}\left(X^{\mathrm{T}}\left(I_{2n} - - \frac{1}{2}Q_{2n}^{\mathrm{T}}p(p^{\mathrm{T}}p)^{-1}p^{\mathrm{T}}Q_{2n}\right)Y(p^{\mathrm{T}}p)^{-1}\right). + = \operatorname{tr}\Bigl( + X^{\mathrm{T}}\bigl( + I_{2n} - \frac{1}{2}Q_{2n}^{\mathrm{T}} p(p^{\mathrm{T}}p)^{-1}p^{\mathrm{T}}Q_{2n} + \bigr) Y (p^{\mathrm{T}}p)^{-1}\Bigr). ```` """ function inner(::SymplecticStiefel, p, X, Y) - Q = SymplecticMatrix(p, X, Y) + Q = SymplecticMatrix(p, X, Y) # in BZ21 also J # Procompute lu(p'p) since we solve a^{-1}* 3 times a = lu(p' * p) # note that p'p is symmetric, thus so is its inverse c=a^{-1} b = Q' * p @@ -544,8 +546,8 @@ end retract(::SymplecticStiefel, p, X, ::CayleyRetraction) retract!(::SymplecticStiefel, q, p, X, ::CayleyRetraction) -Compute the Cayley retraction on the Symplectic Stiefel manifold, computed inplace -of `q` from `p` along `X`. +Compute the Cayley retraction on the Symplectic Stiefel manifold, +from `p` along `X` (computed inplace of `q`). Given a point ``p \in \operatorname{SpSt}(2n, 2k)``, every tangent vector ``X \in T_p\operatorname{SpSt}(2n, 2k)`` is of the form From 01434a8a6d6866be1b4f6ae366d5e83116849d85 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 11 Jan 2024 18:03:46 +0100 Subject: [PATCH 08/65] Unify notation to use UTF8 where possible and use J for the symplectic element instead of Q and/or J. --- docs/src/features/atlases.md | 8 +- docs/src/manifolds/essentialmanifold.md | 2 +- docs/src/manifolds/euclidean.md | 2 +- docs/src/manifolds/fiber_bundle.md | 2 +- docs/src/manifolds/power.md | 4 +- docs/src/manifolds/shapespace.md | 2 +- docs/src/manifolds/symplectic.md | 18 +- docs/src/manifolds/symplecticstiefel.md | 12 +- docs/src/misc/notation.md | 23 +- src/manifolds/CholeskySpace.jl | 6 +- src/manifolds/Circle.jl | 4 +- src/manifolds/EssentialManifold.jl | 2 +- src/manifolds/Euclidean.jl | 6 +- src/manifolds/FixedRankMatrices.jl | 2 +- src/manifolds/FlagOrthogonal.jl | 16 +- src/manifolds/FlagStiefel.jl | 10 +- src/manifolds/GeneralizedGrassmann.jl | 22 +- src/manifolds/GeneralizedStiefel.jl | 10 +- src/manifolds/Grassmann.jl | 2 +- src/manifolds/GrassmannStiefel.jl | 18 +- src/manifolds/Hamiltonian.jl | 2 +- src/manifolds/Hyperbolic.jl | 10 +- src/manifolds/HyperbolicHyperboloid.jl | 2 +- src/manifolds/MetricManifold.jl | 2 +- src/manifolds/PositiveNumbers.jl | 2 +- src/manifolds/SkewHermitian.jl | 6 +- src/manifolds/Sphere.jl | 6 +- src/manifolds/SphereSymmetricMatrices.jl | 6 +- src/manifolds/Stiefel.jl | 8 +- src/manifolds/StiefelCanonicalMetric.jl | 2 +- src/manifolds/StiefelEuclideanMetric.jl | 10 +- src/manifolds/Symmetric.jl | 6 +- ...ymmetricPositiveDefiniteAffineInvariant.jl | 2 +- .../SymmetricPositiveDefiniteLogCholesky.jl | 12 +- .../SymmetricPositiveDefiniteLogEuclidean.jl | 2 +- .../SymmetricPositiveSemidefiniteFixedRank.jl | 2 +- src/manifolds/Symplectic.jl | 546 +++++++++--------- src/manifolds/SymplecticGrassmann.jl | 4 +- src/manifolds/SymplecticStiefel.jl | 346 +++++------ src/manifolds/Tucker.jl | 28 +- src/manifolds/power.md | 114 ++++ src/utils.jl | 2 +- tutorials/getstarted.qmd | 4 +- tutorials/integration.qmd | 6 +- 44 files changed, 678 insertions(+), 623 deletions(-) create mode 100644 src/manifolds/power.md diff --git a/docs/src/features/atlases.md b/docs/src/features/atlases.md index d7ca297e26..58cece4be2 100644 --- a/docs/src/features/atlases.md +++ b/docs/src/features/atlases.md @@ -1,6 +1,6 @@ # [Atlases and charts](@id atlases_and_charts) -Atlases on an ``n``-dimensional manifold $\mathcal M$ are collections of charts ``\mathcal A = \{(U_i, Ο†_i) \colon i \in I\}``, where ``I`` is a (finite or infinte) index family, such that ``U_i \subseteq \mathcal M`` is an open set and each chart ``Ο†_i: U_i \to \mathbb{R}^n`` is a homeomorphism. This means, that ``Ο†_i`` is bijective – sometimes also called one-to-one and onto - and continuous, and its inverse ``Ο†_i^{-1}`` is continuous as well. +Atlases on an ``n``-dimensional manifold $\mathcal M$ are collections of charts ``\mathcal A = \{(U_i, Ο†_i) \colon i \in I\}``, where ``I`` is a (finite or infinte) index family, such that ``U_i \subseteq \mathcal M`` is an open set and each chart ``Ο†_i: U_i \to ℝ^n`` is a homeomorphism. This means, that ``Ο†_i`` is bijective – sometimes also called one-to-one and onto - and continuous, and its inverse ``Ο†_i^{-1}`` is continuous as well. The inverse ``Ο†_i^{-1}`` is called (local) parametrization. The resulting _parameters_ ``a=Ο†(p)`` of ``p`` (with respect to the chart ``Ο†``) are in the literature also called β€œ(local) coordinates”. To distinguish the parameter ``a`` from [`get_coordinates`](@ref) in a basis, we use the terminology parameter in this package. @@ -11,9 +11,9 @@ For an atlas ``\mathcal A`` we further require that ``` We say that ``Ο†_i`` is a chart about ``p``, if ``p\in U_i``. -An atlas provides a connection between a manifold and the Euclidean space ``\mathbb{R}^n``, since +An atlas provides a connection between a manifold and the Euclidean space ``ℝ^n``, since locally, a chart about ``p`` can be used to identify its neighborhood (as long as you stay in ``U_i``) with a subset of a Euclidean space. -Most manifolds we consider are smooth, i.e. any change of charts ``Ο†_i \circ Ο†_j^{-1}: \mathbb{R}^n\to\mathbb{R}^n``, where ``i,j\in I``, is a smooth function. These changes of charts are also called transition maps. +Most manifolds we consider are smooth, i.e. any change of charts ``Ο†_i \circ Ο†_j^{-1}: ℝ^n\toℝ^n``, where ``i,j\in I``, is a smooth function. These changes of charts are also called transition maps. Most operations on manifolds in `Manifolds.jl` avoid operating in a chart through appropriate embeddings and formulas derived for particular manifolds, though atlases provide the most general way of working with manifolds. Compared to these approaches, using an atlas is often more technical and time-consuming. @@ -28,7 +28,7 @@ Operations using atlases and charts are available through the following function * [`get_parameters`](@ref Main.Manifolds.get_parameters) converts a point to its parameters with respect to the chart in a chart. * [`get_point`](@ref Main.Manifolds.get_point) converts parameters (local coordinates) in a chart to the point that corresponds to them. * [`induced_basis`](@ref Main.Manifolds.induced_basis) returns a basis of a given vector space at a point induced by a chart ``Ο†``. -* [`transition_map`](@ref Main.Manifolds.transition_map) converts coordinates of a point between two charts, e.g. computes ``Ο†_i\circ Ο†_j^{-1}: \mathbb{R}^n\to\mathbb{R}^n``, ``i,j\in I``. +* [`transition_map`](@ref Main.Manifolds.transition_map) converts coordinates of a point between two charts, e.g. computes ``Ο†_i\circ Ο†_j^{-1}: ℝ^n\toℝ^n``, ``i,j\in I``. While an atlas could store charts as explicit functions, it is favourable, that the [`get_parameters`] actually implements a chart ``Ο†``, [`get_point`](@ref) its inverse, the prametrization ``Ο†^{-1}``. diff --git a/docs/src/manifolds/essentialmanifold.md b/docs/src/manifolds/essentialmanifold.md index 7a0ef023a2..8fadf05856 100644 --- a/docs/src/manifolds/essentialmanifold.md +++ b/docs/src/manifolds/essentialmanifold.md @@ -1,5 +1,5 @@ # Essential Manifold -The essential manifold is modeled as an [`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) of the $3\times3$ [`Rotations`](@ref) and uses [`NestedPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedPowerRepresentation). +The essential manifold is modeled as an [`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) of the $3Γ—3$ [`Rotations`](@ref) and uses [`NestedPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedPowerRepresentation). ```@autodocs Modules = [Manifolds] diff --git a/docs/src/manifolds/euclidean.md b/docs/src/manifolds/euclidean.md index 5cd8f6f498..1d420b8ac2 100644 --- a/docs/src/manifolds/euclidean.md +++ b/docs/src/manifolds/euclidean.md @@ -1,7 +1,7 @@ # [Euclidean space](@id EuclideanSection) The Euclidean space $ℝ^n$ is a simple model space, since it has curvature constantly zero everywhere; hence, nearly all operations simplify. -The easiest way to generate an Euclidean space is to use a field, i.e. [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system), e.g. to create the $ℝ^n$ or $ℝ^{n\times n}$ you can simply type `M = ℝ^n` or `ℝ^(n,n)`, respectively. +The easiest way to generate an Euclidean space is to use a field, i.e. [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system), e.g. to create the $ℝ^n$ or $ℝ^{nΓ—n}$ you can simply type `M = ℝ^n` or `ℝ^(n,n)`, respectively. ```@autodocs Modules = [Manifolds] diff --git a/docs/src/manifolds/fiber_bundle.md b/docs/src/manifolds/fiber_bundle.md index 9acbe33db4..c995126afd 100644 --- a/docs/src/manifolds/fiber_bundle.md +++ b/docs/src/manifolds/fiber_bundle.md @@ -4,7 +4,7 @@ Fiber bundle $E$ is a manifold that is built on top of another manifold $\mathca It is characterized by a continuous function $Ξ  : E β†’ \mathcal M$. For each point $p ∈ \mathcal M$ the preimage of $p$ by $Ξ $, $Ξ ^{-1}(\{p\})$ is called a fiber $F$. Bundle projection can be performed using function [`bundle_projection`](@ref). -`Manifolds.jl` primarily deals with the case of trivial bundles, where $E$ can be identified with a product $M \times F$. +`Manifolds.jl` primarily deals with the case of trivial bundles, where $E$ can be identified with a product $M Γ—F$. [Vector bundles](@ref VectorBundleSection) is a special case of a fiber bundle. Other examples include unit tangent bundle. Note that in general fiber bundles don't have a canonical Riemannian structure but can at least be equipped with an [Ehresmann connection](https://en.wikipedia.org/wiki/Ehresmann_connection), providing notions of parallel transport and curvature. diff --git a/docs/src/manifolds/power.md b/docs/src/manifolds/power.md index 3b9f70a3ee..6f04e8bb58 100644 --- a/docs/src/manifolds/power.md +++ b/docs/src/manifolds/power.md @@ -1,8 +1,8 @@ # [Power manifold](@id PowerManifoldSection) -A power manifold is based on a [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) $\mathcal M$ to build a $\mathcal M^{n_1 \times n_2 \times \cdots \times n_m}$. +A power manifold is based on a [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) $\mathcal M$ to build a $\mathcal M^{n_1Γ—n_2 Γ—β‹―Γ—n_m}$. In the case where $m=1$ we can represent a manifold-valued vector of data of length $n_1$, for example a time series. -The case where $m=2$ is useful for representing manifold-valued matrices of data of size $n_1 \times n_2$, for example certain types of images. +The case where $m=2$ is useful for representing manifold-valued matrices of data of size $n_1Γ—n_2$, for example certain types of images. There are three available representations for points and vectors on a power manifold: diff --git a/docs/src/manifolds/shapespace.md b/docs/src/manifolds/shapespace.md index 2867825624..e2df610aae 100644 --- a/docs/src/manifolds/shapespace.md +++ b/docs/src/manifolds/shapespace.md @@ -1,6 +1,6 @@ # Shape spaces -Shape spaces are spaces of ``k`` points in ``\mathbb{R}^n`` up to simultaneous action of a group on all points. +Shape spaces are spaces of ``k`` points in ``ℝ^n`` up to simultaneous action of a group on all points. The most commonly encountered are Kendall's pre-shape and shape spaces. In the case of the Kendall's pre-shape spaces the action is translation and scaling. In the case of the Kendall's shape spaces the action is translation, scaling and rotation. diff --git a/docs/src/manifolds/symplectic.md b/docs/src/manifolds/symplectic.md index 3673e6be2b..562360e798 100644 --- a/docs/src/manifolds/symplectic.md +++ b/docs/src/manifolds/symplectic.md @@ -1,12 +1,12 @@ # Symplectic -The [`Symplectic`](@ref) manifold, denoted $\operatorname{Sp}(2n, \mathbb{F})$, is a closed, embedded, submanifold of -$\mathbb{F}^{2n \times 2n}$ that represents transformations into symplectic subspaces which keep the -canonical symplectic form over $\mathbb{F}^{2n \times 2n }$ invariant under the standard embedding inner product. +The [`Symplectic`](@ref) manifold, denoted $\operatorname{Sp}(2n, 𝔽)$, is a closed, embedded, submanifold of +$𝔽^{2nΓ—2n}$ that represents transformations into symplectic subspaces which keep the +canonical symplectic form over $𝔽^{2nΓ—2n}$ invariant under the standard embedding inner product. The canonical symplectic form is a non-degenerate bilinear and skew symmetric map -$\omega\colon \mathbb{F}^{2n} \times \mathbb{F}^{2n} -\rightarrow \mathbb{F}$, given by -$\omega(x, y) = x^T Q_{2n} y$ for elements $x, y \in \mathbb{F}^{2n}$, with +$\omega\colon 𝔽 𝔽^{2n}×𝔽^{2n} +β†’ 𝔽$, given by +$\omega(x, y) = x^T Q_{2n} y$ for elements $x, y \in 𝔽^{2n}$, with ````math Q_{2n} = \begin{bmatrix} @@ -22,11 +22,11 @@ leading to the requirement on $p$ that $p^TQp = Q$. The symplectic manifold also forms a group under matrix multiplication, called the $\textit{symplectic group}$. Since all the symplectic matrices necessarily have determinant one, the [symplectic group](https://en.wikipedia.org/wiki/Symplectic_group) -$\operatorname{Sp}(2n, \mathbb{F})$ is a subgroup of the special linear group, $\operatorname{SL}(2n, \mathbb{F})$. When the underlying -field is either $\mathbb{R}$ or $\mathbb{C}$ the symplectic group with a manifold structure constitutes a Lie group, with the Lie +$\operatorname{Sp}(2n, 𝔽)$ is a subgroup of the special linear group, $\operatorname{SL}(2n, 𝔽)$. When the underlying +field is either $ℝ$ or $β„‚$ the symplectic group with a manifold structure constitutes a Lie group, with the Lie Algebra ````math - \mathfrak{sp}(2n,F) = \{H \in \mathbb{F}^{2n \times 2n} \;|\; Q H + H^{T} Q = 0\}. + \mathfrak{sp}(2n,F) = \{H \in 𝔽^{2nΓ—2n} \;|\; Q H + H^{T} Q = 0\}. ```` This set is also known as the [Hamiltonian matrices](https://en.wikipedia.org/wiki/Hamiltonian_matrix), which have the property that $(QH)^T = QH$ and are commonly used in physics. diff --git a/docs/src/manifolds/symplecticstiefel.md b/docs/src/manifolds/symplecticstiefel.md index 6251c06841..a70a937709 100644 --- a/docs/src/manifolds/symplecticstiefel.md +++ b/docs/src/manifolds/symplecticstiefel.md @@ -1,13 +1,13 @@ # (Real) Symplectic Stiefel The [`SymplecticStiefel`](@ref) manifold, denoted $\operatorname{SpSt}(2n, 2k)$, -represents canonical symplectic bases of $2k$ dimensonal symplectic subspaces of $\mathbb{R}^{2n \times 2n}$. -This means that the columns of each element $p \in \operatorname{SpSt}(2n, 2k) \subset \mathbb{R}^{2n \times 2k}$ +represents canonical symplectic bases of $2k$ dimensonal symplectic subspaces of $ℝ^{2nΓ—2n}$. +This means that the columns of each element $p \in \operatorname{SpSt}(2n, 2k) \subset ℝ^{2nΓ—2k}$ constitute a canonical symplectic basis of $\operatorname{span}(p)$. The canonical symplectic form is a non-degenerate, bilinear, and skew symmetric map -$\omega_{2k}\colon \mathbb{F}^{2k} \times \mathbb{F}^{2k} -\rightarrow \mathbb{F}$, given by -$\omega_{2k}(x, y) = x^T Q_{2k} y$ for elements $x, y \in \mathbb{F}^{2k}$, with +$\omega_{2k}\colon 𝔽^{2k}×𝔽^{2k} +β†’ 𝔽$, given by +$\omega_{2k}(x, y) = x^T Q_{2k} y$ for elements $x, y \in 𝔽^{2k}$, with ````math Q_{2k} = \begin{bmatrix} @@ -17,7 +17,7 @@ $\omega_{2k}(x, y) = x^T Q_{2k} y$ for elements $x, y \in \mathbb{F}^{2k}$, with ```` Specifically given an element $p \in \operatorname{SpSt}(2n, 2k)$ we require that ````math - \omega_{2n} (p x, p y) = x^T(p^TQ_{2n}p)y = x^TQ_{2k}y = \omega_{2k}(x, y) \;\forall\; x, y \in \mathbb{F}^{2k}, + \omega_{2n} (p x, p y) = x^T(p^TQ_{2n}p)y = x^TQ_{2k}y = \omega_{2k}(x, y) \;\forall\; x, y \in 𝔽^{2k}, ```` leading to the requirement on $p$ that $p^TQ_{2n}p = Q_{2k}$. In the case that $k = n$, this manifold reduces to the [`Symplectic`](@ref) manifold, which is also known as the symplectic group. diff --git a/docs/src/misc/notation.md b/docs/src/misc/notation.md index ee7975861d..e564baddf0 100644 --- a/docs/src/misc/notation.md +++ b/docs/src/misc/notation.md @@ -11,30 +11,30 @@ Within the documented functions, the utf8 symbols are used whenever possible, as |:--:|:--------------- |:--:|:-- | | ``\tau_p`` | action map by group element ``p`` | ``\mathrm{L}_p``, ``\mathrm{R}_p`` | either left or right | | ``\operatorname{Ad}_p(X)`` | adjoint action of element ``p`` of a Lie group on the element ``X`` of the corresponding Lie algebra | | | -| ``\times`` | Cartesian product of two manifolds |Β | see [`ProductManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#ManifoldsBase.ProductManifold) | +| ``Γ—`` | Cartesian product of two manifolds |Β | see [`ProductManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#ManifoldsBase.ProductManifold) | | ``^{\wedge}`` | (n-ary) Cartesian power of a manifold |Β | see [`PowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.PowerManifold) | -| ``\cdot^\mathrm{H}`` | conjugate/Hermitian transpose | | +| ``β‹…^\mathrm{H}`` | conjugate/Hermitian transpose | | | ``a`` | coordinates of a point in a chart | | see [`get_parameters`](@ref) | | ``\frac{\mathrm{D}}{\mathrm{d}t}`` | covariant derivative of a vector field ``X(t)`` | | | | ``T^*_p \mathcal M`` | the cotangent space at ``p`` | | | | ``ΞΎ`` | a cotangent vector from ``T^*_p \mathcal M`` | ``ΞΎ_1, ΞΎ_2,… ,Ξ·,\zeta`` | sometimes written with base point ``ΞΎ_p``. | | ``\mathrm{d}\phi_p(q)`` | Differential of a map ``\phi: \mathcal M \to \mathcal N`` with respect to ``p`` at a point ``q``. For functions of multiple variables, for example ``\phi(p, p_1)`` where ``p \in \mathcal M`` and ``p_1 \in \mathcal M_1``, variable ``p`` is explicitly stated to specify with respect to which argument the differential is calculated. | ``\mathrm{d}\phi_q``, ``(\mathrm{d}\phi)_q``, ``(\phi_*)_q``, ``D_p\phi(q)`` | pushes tangent vectors ``X \in T_q \mathcal M`` forward to ``\mathrm{d}\phi_p(q)[X] \in T_{\phi(q)} \mathcal N`` | | ``n`` | dimension (of a manifold) | ``n_1,n_2,\ldots,m, \dim(\mathcal M)``| for the real dimension sometimes also ``\dim_{\mathbb R}(\mathcal M)``| -| ``d(\cdot,\cdot)`` | (Riemannian) distance | ``d_{\mathcal M}(\cdot,\cdot)`` | | +| ``d(β‹…,β‹…)`` | (Riemannian) distance | ``d_{\mathcal M}(β‹…,β‹…)`` | | | ``\exp_p X`` | exponential map at ``p \in \mathcal M`` of a vector ``X \in T_p \mathcal M`` | ``\exp_p(X)`` | | | ``F`` | a fiber | | see [`Fiber`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#Fiber) | | ``\mathbb F`` | a field, usually ``\mathbb F \in \{\mathbb R,\mathbb C, \mathbb H\}``, i.e. the real, complex, and quaternion numbers, respectively. | |field a manifold or a basis is based on | | ``\gamma`` | a geodesic | ``\gamma_{p;q}``, ``\gamma_{p,X}`` | connecting two points ``p,q`` or starting in ``p`` with velocity ``X``. | -| ``\operatorname{grad} f(p)`` | (Riemannian) gradient of function ``f \colon \mathcal{M} \to \mathbb{R}`` at ``p \in \mathcal{M}`` | | | -| ``\nabla f(p)`` | (Euclidean) gradient of function ``f \colon \mathcal{M} \to \mathbb{R}`` at ``p \in \mathcal{M}`` but thought of as evaluated in the embedding | `G` | | +| ``\operatorname{grad} f(p)`` | (Riemannian) gradient of function ``f \colon \mathcal{M} \to ℝ`` at ``p \in \mathcal{M}`` | | | +| ``\nabla f(p)`` | (Euclidean) gradient of function ``f \colon \mathcal{M} \to ℝ`` at ``p \in \mathcal{M}`` but thought of as evaluated in the embedding | `G` | | | ``\circ`` | a group operation |Β | -| ``\cdot^\mathrm{H}`` | Hermitian or conjugate transposed for both complex or quaternion matrices| | +| ``β‹…^\mathrm{H}`` | Hermitian or conjugate transposed for both complex or quaternion matrices| | | ``\operatorname{Hess} f(p)`` | (Riemannian) Hessian of function ``f \colon T_p\mathcal{M} \to T_p\mathcal M`` (i.e. the 1-1-tensor form) at ``p \in \mathcal{M}`` | | | | ``\nabla^2 f(p)`` | (Euclidean) Hessian of function ``f`` in the embedding | `H` | | | ``e`` | identity element of a group | | -| ``I_k`` | identity matrix of size ``k\times k`` |Β | +| ``I_k`` | identity matrix of size ``kΓ—k`` |Β | | ``k`` | indices | ``i,j`` | | -| ``\langle\cdot,\cdot\rangle`` | inner product (in ``T_p \mathcal M``) | ``\langle\cdot,\cdot\rangle_p, g_p(\cdot,\cdot)`` | +| ``\langleβ‹…,β‹…\rangle`` | inner product (in ``T_p \mathcal M``) | ``\langleβ‹…,β‹…\rangle_p, g_p(β‹…,β‹…)`` | | ``\operatorname{retr}^{-1}_pq``| an inverse retraction | | | ``\mathfrak g`` | a Lie algebra |Β | | ``\mathcal{G}`` | a (Lie) group |Β | @@ -50,15 +50,16 @@ Within the documented functions, the utf8 symbols are used whenever possible, as | ``p`` | a point on ``\mathcal M`` | ``p_1, p_2, \ldots,q`` | for 3 points one might use ``x,y,z`` | | ``\operatorname{retr}_pX``| a retraction | | | ``ΞΎ`` | a set of tangent vectors | ``\{X_1,\ldots,X_n\}`` | | +| ``J_{2n} \in ℝ^{2nΓ—2n}`` | the [`SymplecticMatrix`](@ref) |Β | | | ``T_p \mathcal M`` | the tangent space at ``p`` | | | | ``X`` | a tangent vector from ``T_p \mathcal M`` | ``X_1,X_2,\ldots,Y,Z`` | sometimes written with base point ``X_p`` | | ``\operatorname{tr}`` | trace (of a matrix) | | -| ``\cdot^\mathrm{T}`` | transposed | | -| ``e_i \in \mathbb R^n`` | the ``i``th unit vector | ``e_i^n`` | the space dimension (``n``) is omited, when clear from context +| ``β‹…^\mathrm{T}`` | transposed | | +| ``e_i \in \mathbb R^n`` | the ``i``th unit vector | ``e_i^n`` | the space dimension (``n``) is omitted, when clear from context | ``B`` | a vector bundle | | | ``\mathcal T_{q\gets p}X`` | vector transport | | of the vector ``X`` from ``T_p\mathcal M`` to ``T_q\mathcal M`` | ``\mathcal T_{p,Y}X`` | vector transport in direction ``Y`` | | of the vector ``X`` from ``T_p\mathcal M`` to ``T_q\mathcal M``, where ``q`` is deretmined by ``Y``, for example using the exponential map or some retraction. | | ``\operatorname{Vol}(\mathcal M)`` | volume of manifold ``\mathcal M`` | | | ``\theta_p(X)`` | volume density for vector ``X`` tangent at point ``p`` | | | ``\mathcal W`` | the Weingarten map ``\mathcal W: T_p\mathcal M Γ— N_p\mathcal M β†’ T_p\mathcal M`` |Β ``\mathcal W_p`` |Β the second notation to emphasize the dependency of the point ``p\in\mathcal M`` | -| ``0_k`` | the ``k\times k`` zero matrix. | | +| ``0_k`` | the ``kΓ—k`` zero matrix. | | diff --git a/src/manifolds/CholeskySpace.jl b/src/manifolds/CholeskySpace.jl index 2d2226c4b4..18aa9475cf 100644 --- a/src/manifolds/CholeskySpace.jl +++ b/src/manifolds/CholeskySpace.jl @@ -107,7 +107,7 @@ The formula reads \operatorname{diag}(p)\exp\bigl( \operatorname{diag}(X)\operatorname{diag}(p)^{-1}\bigr), ```` -where $⌊\cdotβŒ‹$ denotes the strictly lower triangular matrix, +where $βŒŠβ‹…βŒ‹$ denotes the strictly lower triangular matrix, and $\operatorname{diag}$ extracts the diagonal matrix. """ exp(::CholeskySpace, ::Any...) @@ -158,7 +158,7 @@ The formula reads \log_p q = ⌊ p βŒ‹ - ⌊ q βŒ‹ + \operatorname{diag}(p)\log\bigl(\operatorname{diag}(q)\operatorname{diag}(p)^{-1}\bigr), ```` -where $⌊\cdotβŒ‹$ denotes the strictly lower triangular matrix, +where $βŒŠβ‹…βŒ‹$ denotes the strictly lower triangular matrix, and $\operatorname{diag}$ extracts the diagonal matrix. """ log(::Cholesky, ::Any...) @@ -219,7 +219,7 @@ on the [`CholeskySpace`](@ref) manifold `M`. The formula reads + \operatorname{diag}(q)\operatorname{diag}(p)^{-1}\operatorname{diag}(X), ```` -where $⌊\cdotβŒ‹$ denotes the strictly lower triangular matrix, +where $βŒŠβ‹…βŒ‹$ denotes the strictly lower triangular matrix, and $\operatorname{diag}$ extracts the diagonal matrix. """ parallel_transport_to(::CholeskySpace, ::Any, ::Any, ::Any) diff --git a/src/manifolds/Circle.jl b/src/manifolds/Circle.jl index a82cff544c..27d7df3807 100644 --- a/src/manifolds/Circle.jl +++ b/src/manifolds/Circle.jl @@ -148,7 +148,7 @@ Compute the exponential map on the [`Circle`](@ref). ````math \exp_p X = (p+X)_{2Ο€}, ```` -where ``(\cdot)_{2Ο€}`` is the (symmetric) remainder with respect to division by ``2Ο€``, i.e. in ``[-Ο€,Ο€)``. +where ``(β‹…)_{2Ο€}`` is the (symmetric) remainder with respect to division by ``2Ο€``, i.e. in ``[-Ο€,Ο€)``. For the complex-valued case, the same formula as for the [`Sphere`](@ref) ``π•Š^1`` is applied to values in the complex plane. @@ -299,7 +299,7 @@ Compute the logarithmic map on the [`Circle`](@ref) `M`. ````math \log_p q = (q-p)_{2Ο€}, ```` -where ``(\cdot)_{2Ο€}`` is the (symmetric) remainder with respect to division by ``2Ο€``, i.e. in ``[-Ο€,Ο€)``. +where ``(β‹…)_{2Ο€}`` is the (symmetric) remainder with respect to division by ``2Ο€``, i.e. in ``[-Ο€,Ο€)``. For the complex-valued case, the same formula as for the [`Sphere`](@ref) ``π•Š^1`` is applied to values in the complex plane. diff --git a/src/manifolds/EssentialManifold.jl b/src/manifolds/EssentialManifold.jl index 6d585d4974..cf36ef6169 100644 --- a/src/manifolds/EssentialManifold.jl +++ b/src/manifolds/EssentialManifold.jl @@ -4,7 +4,7 @@ The essential manifold is the space of the essential matrices which is represented as a quotient space of the [`Rotations`](@ref) manifold product ``\mathrm{SO}(3)^2``. -Let ``R_x(ΞΈ), R_y(ΞΈ), R_x(ΞΈ) \in ℝ^{x\times 3}`` denote the rotation around the ``z``, +Let ``R_x(ΞΈ), R_y(ΞΈ), R_x(ΞΈ) \in ℝ^{xΓ—3}`` denote the rotation around the ``z``, ``y``, and ``x`` axis in ``ℝ^3``, respectively, and further the groups ```math diff --git a/src/manifolds/Euclidean.jl b/src/manifolds/Euclidean.jl index 4dc39a7da6..a0eacec744 100644 --- a/src/manifolds/Euclidean.jl +++ b/src/manifolds/Euclidean.jl @@ -12,7 +12,7 @@ Generate the ``n``-dimensional vector space ``ℝ^n``. Euclidean(n₁,nβ‚‚,...,nα΅’; field=ℝ, parameter::Symbol = :field) 𝔽^(n₁,nβ‚‚,...,nα΅’) = Euclidean(n₁,nβ‚‚,...,nα΅’; field=𝔽) -Generate the vector space of ``k = n_1 \cdot n_2 \cdot … \cdot n_i`` values, i.e. the +Generate the vector space of ``k = n_1 β‹… n_2 β‹… … β‹… n_i`` values, i.e. the manifold ``𝔽^{n_1, n_2, …, n_i}``, ``𝔽\in\{ℝ,β„‚\}``, whose elements are interpreted as ``n_1 Γ— n_2 Γ— … Γ— n_i`` arrays. For ``i=2`` we obtain a matrix space. @@ -402,7 +402,7 @@ g_p(X,Y) = \sum_{k ∈ I} \overline{X}_{k} Y_{k}, where ``I`` is the set of vectors ``k ∈ β„•^i``, such that for all -``i ≀ j ≀ i`` it holds ``1 ≀ k_j ≀ n_j`` and ``\overline{\cdot}`` denotes the complex conjugate. +``i ≀ j ≀ i`` it holds ``1 ≀ k_j ≀ n_j`` and ``\overline{β‹…}`` denotes the complex conjugate. For the special case of ``i ≀ 2``, i.e. matrices and vectors, this simplifies to @@ -410,7 +410,7 @@ For the special case of ``i ≀ 2``, i.e. matrices and vectors, this simplifies g_p(X,Y) = X^{\mathrm{H}}Y, ```` -where ``\cdot^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. """ inner(::Euclidean, ::Any...) @inline inner(::Euclidean, p, X, Y) = dot(X, Y) diff --git a/src/manifolds/FixedRankMatrices.jl b/src/manifolds/FixedRankMatrices.jl index ddc145ea82..7bd71a85e1 100644 --- a/src/manifolds/FixedRankMatrices.jl +++ b/src/manifolds/FixedRankMatrices.jl @@ -10,7 +10,7 @@ where ``𝔽 ∈ \{ℝ,β„‚\}`` and the rank is the number of linearly independen # Representation with 3 matrix factors A point ``p ∈ \mathcal M`` can be stored using unitary matrices ``U ∈ 𝔽^{m Γ— k}``, ``V ∈ 𝔽^{n Γ— k}`` as well as the ``k`` -singular values of ``p = U_p S V_p^\mathrm{H}``, where ``\cdot^{\mathrm{H}}`` denotes the complex conjugate transpose or +singular values of ``p = U_p S V_p^\mathrm{H}``, where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transpose or Hermitian. In other words, ``U`` and ``V`` are from the manifolds [`Stiefel`](@ref)`(m,k,𝔽)` and [`Stiefel`](@ref)`(n,k,𝔽)`, respectively; see [`SVDMPoint`](@ref) for details. diff --git a/src/manifolds/FlagOrthogonal.jl b/src/manifolds/FlagOrthogonal.jl index c6d897b70a..e30d034ac6 100644 --- a/src/manifolds/FlagOrthogonal.jl +++ b/src/manifolds/FlagOrthogonal.jl @@ -7,10 +7,10 @@ Check whether `X` is a tangent vector to point `p` on the [`Flag`](@ref) manifol i.e. that `X` is block-skew-symmetric with zero diagonal: ````math X = \begin{bmatrix} -0 & B_{1,2} & \cdots & B_{1,d+1} \\ --B_{1,2}^\mathrm{T} & 0 & \cdots & B_{2,d+1} \\ -\vdots & \vdots & \ddots & \vdots \\ --B_{1,d+1}^\mathrm{T} & -B_{2,d+1}^\mathrm{T} & \cdots & 0 +0 & B_{1,2} & β‹― & B_{1,d+1} \\ +-B_{1,2}^\mathrm{T} & 0 & β‹― & B_{2,d+1} \\ +\vdots & \vdots & β‹± & \vdots \\ +-B_{1,d+1}^\mathrm{T} & -B_{2,d+1}^\mathrm{T} & β‹― & 0 \end{bmatrix} ```` where ``B_{i,j} ∈ ℝ^{(n_i - n_{i-1}) Γ— (n_j - n_{j-1})}``, for ``1 ≀ i < j ≀ d+1``. @@ -105,10 +105,10 @@ It works by first projecting `X` to the space of [`SkewHermitianMatrices`](@ref) setting diagonal blocks to 0: ````math X = \begin{bmatrix} -0 & B_{1,2} & \cdots & B_{1,d+1} \\ --B_{1,2}^\mathrm{T} & 0 & \cdots & B_{2,d+1} \\ -\vdots & \vdots & \ddots & \vdots \\ --B_{1,d+1}^\mathrm{T} & -B_{2,d+1}^\mathrm{T} & \cdots & 0 +0 & B_{1,2} & β‹― & B_{1,d+1} \\ +-B_{1,2}^\mathrm{T} & 0 & β‹― & B_{2,d+1} \\ +\vdots & \vdots & β‹± & \vdots \\ +-B_{1,d+1}^\mathrm{T} & -B_{2,d+1}^\mathrm{T} & β‹― & 0 \end{bmatrix} ```` where ``B_{i,j} ∈ ℝ^{(n_i - n_{i-1}) Γ— (n_j - n_{j-1})}``, for ``1 ≀ i < j ≀ d+1``. diff --git a/src/manifolds/FlagStiefel.jl b/src/manifolds/FlagStiefel.jl index 11d2bee355..0338d21c6a 100644 --- a/src/manifolds/FlagStiefel.jl +++ b/src/manifolds/FlagStiefel.jl @@ -74,11 +74,11 @@ Check whether `X` is a tangent vector to point `p` on the [`Flag`](@ref) manifol i.e. that `X` is a matrix of the form ````math X = \begin{bmatrix} -0 & B_{1,2} & \cdots & B_{1,d} \\ --B_{1,2}^\mathrm{T} & 0 & \cdots & B_{2,d} \\ -\vdots & \vdots & \ddots & \vdots \\ --B_{1,d}^\mathrm{T} & -B_{2,d}^\mathrm{T} & \cdots & 0 \\ --B_{1,d+1}^\mathrm{T} & -B_{2,d+1}^\mathrm{T} & \cdots & -B_{d,d+1}^\mathrm{T} +0 & B_{1,2} & β‹― & B_{1,d} \\ +-B_{1,2}^\mathrm{T} & 0 & β‹― & B_{2,d} \\ +\vdots & \vdots & β‹± & \vdots \\ +-B_{1,d}^\mathrm{T} & -B_{2,d}^\mathrm{T} & β‹― & 0 \\ +-B_{1,d+1}^\mathrm{T} & -B_{2,d+1}^\mathrm{T} & β‹― & -B_{d,d+1}^\mathrm{T} \end{bmatrix} ```` where ``B_{i,j} ∈ ℝ^{(n_i - n_{i-1}) Γ— (n_j - n_{j-1})}``, for ``1 ≀ i < j ≀ d+1``. diff --git a/src/manifolds/GeneralizedGrassmann.jl b/src/manifolds/GeneralizedGrassmann.jl index 7fd9c26dff..fda1b2d150 100644 --- a/src/manifolds/GeneralizedGrassmann.jl +++ b/src/manifolds/GeneralizedGrassmann.jl @@ -12,7 +12,7 @@ The manifold can be represented as \operatorname{Gr}(n, k, B) := \bigl\{ \operatorname{span}(p)\ \big|\ p ∈ 𝔽^{n Γ— k}, p^\mathrm{H}Bp = I_k\}, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate (or Hermitian) transpose and +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate (or Hermitian) transpose and $I_k$ is the $k Γ— k$ identity matrix. This means, that the columns of $p$ form an unitary basis of the subspace with respect to the scaled inner product, that is a point on $\operatorname{Gr}(n,k,B)$, and hence the subspace can actually be represented by @@ -40,7 +40,7 @@ The manifold is named after GeneralizedGrassmann(n, k, B=I_n, field=ℝ) -Generate the (real-valued) Generalized Grassmann manifold of $n\times k$ dimensional +Generate the (real-valued) Generalized Grassmann manifold of $nΓ—k$ dimensional orthonormal matrices with scalar product `B`. """ struct GeneralizedGrassmann{T,𝔽,TB<:AbstractMatrix} <: AbstractDecoratorManifold{𝔽} @@ -116,8 +116,8 @@ the [`GeneralizedGrassmann`](@ref) `M`, i.e. that `X` is of size and type as wel p^{\mathrm{H}}BX + \overline{X^{\mathrm{H}}Bp} = 0_k, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, -$\overline{\cdot}$ the (elementwise) complex conjugate, and $0_k$ denotes the $k Γ— k$ zero natrix. +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, +$\overline{β‹…}$ the (elementwise) complex conjugate, and $0_k$ denotes the $k Γ— k$ zero natrix. """ function check_vector(M::GeneralizedGrassmann, p, X; kwargs...) return nothing # everything already checked in the embedding (generalized Stiefel) @@ -157,7 +157,7 @@ SVD decomposition of $X^{\mathrm{H}}BX$. Then the exponential map is written usi \exp_p X = p V\cos(S)V^\mathrm{H} + U\sin(S)V^\mathrm{H}, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian and the +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian and the cosine and sine are applied element wise to the diagonal entries of $S$. """ exp(::GeneralizedGrassmann, ::Any...) @@ -209,7 +209,7 @@ of `p` on the [`GeneralizedGrassmann`](@ref) manifold `M`. The formula reads g_p(X,Y) = \operatorname{tr}(X^{\mathrm{H}}BY), ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. """ inner(M::GeneralizedGrassmann, p, X, Y) = dot(X, M.B, Y) @@ -228,10 +228,10 @@ i.e. the tangent vector `X` whose corresponding [`geodesic`](https://juliamanifo reaches `q` after time 1 on `M`. The formula reads ````math -\log_p q = V\cdot \operatorname{atan}(S) \cdot U^\mathrm{H}, +\log_p q = Vβ‹… \operatorname{atan}(S) β‹… U^\mathrm{H}, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. The matrices $U$ and $V$ are the unitary matrices, and $S$ is the diagonal matrix containing the singular values of the SVD-decomposition @@ -289,7 +289,7 @@ end Project `p` from the embedding onto the [`GeneralizedGrassmann`](@ref) `M`, i.e. compute `q` as the polar decomposition of $p$ such that $q^{\mathrm{H}}Bq$ is the identity, -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose. +where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose. """ project(::GeneralizedGrassmann, ::Any) @@ -311,8 +311,8 @@ Project the `n`-by-`k` `X` onto the tangent space of `p` on the \operatorname{proj_p}(X) = X - pp^{\mathrm{H}}B^\mathrm{T}X, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian -and $\cdot^{\mathrm{T}}$ the transpose. +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian +and $β‹…^{\mathrm{T}}$ the transpose. """ project(::GeneralizedGrassmann, ::Any, ::Any) diff --git a/src/manifolds/GeneralizedStiefel.jl b/src/manifolds/GeneralizedStiefel.jl index 5510abe875..1972cad68a 100644 --- a/src/manifolds/GeneralizedStiefel.jl +++ b/src/manifolds/GeneralizedStiefel.jl @@ -1,7 +1,7 @@ @doc raw""" GeneralizedStiefel{T,𝔽,B} <: AbstractDecoratorManifold{𝔽} -The Generalized Stiefel manifold consists of all $n\times k$, $n\geq k$ orthonormal +The Generalized Stiefel manifold consists of all $nΓ—k$, $n\geq k$ orthonormal matrices w.r.t. an arbitrary scalar product with symmetric positive definite matrix $B\in R^{n Γ— n}$, i.e. @@ -10,7 +10,7 @@ $B\in R^{n Γ— n}$, i.e. ```` where $𝔽 ∈ \{ℝ, β„‚\}$, -$\cdot^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and +$β‹…^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and $I_k \in \mathbb R^{k Γ— k}$ denotes the $k Γ— k$ identity matrix. @@ -32,7 +32,7 @@ The manifold is named after # Constructor GeneralizedStiefel(n, k, B=I_n, F=ℝ) -Generate the (real-valued) Generalized Stiefel manifold of $n\times k$ dimensional +Generate the (real-valued) Generalized Stiefel manifold of $nΓ—k$ dimensional orthonormal matrices with scalar product `B`. """ struct GeneralizedStiefel{T,𝔽,TB<:AbstractMatrix} <: AbstractDecoratorManifold{𝔽} @@ -58,7 +58,7 @@ active_traits(f, ::GeneralizedStiefel, args...) = merge_traits(IsEmbeddedManifol Check whether `p` is a valid point on the [`GeneralizedStiefel`](@ref) `M`=$\operatorname{St}(n,k,B)$, i.e. that it has the right [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and $x^{\mathrm{H}}Bx$ -is (approximately) the identity, where $\cdot^{\mathrm{H}}$ is the complex conjugate +is (approximately) the identity, where $β‹…^{\mathrm{H}}$ is the complex conjugate transpose. The settings for approximately can be set with `kwargs...`. """ function check_point(M::GeneralizedStiefel, p; kwargs...) @@ -160,7 +160,7 @@ end Project `p` from the embedding onto the [`GeneralizedStiefel`](@ref) `M`, i.e. compute `q` as the polar decomposition of $p$ such that $q^{\mathrm{H}}Bq$ is the identity, -where $\cdot^{\mathrm{H}}$ denotes the hermitian, i.e. complex conjugate transposed. +where $β‹…^{\mathrm{H}}$ denotes the hermitian, i.e. complex conjugate transposed. """ project(::GeneralizedStiefel, ::Any) diff --git a/src/manifolds/Grassmann.jl b/src/manifolds/Grassmann.jl index 28d1068727..768491131d 100644 --- a/src/manifolds/Grassmann.jl +++ b/src/manifolds/Grassmann.jl @@ -12,7 +12,7 @@ The manifold can be represented as \operatorname{Gr}(n,k) := \bigl\{ \operatorname{span}(p) : p ∈ 𝔽^{n Γ— k}, p^\mathrm{H}p = I_k\}, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian and +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian and $I_k$ is the $k Γ— k$ identity matrix. This means, that the columns of $p$ form an unitary basis of the subspace, that is a point on $\operatorname{Gr}(n,k)$, and hence the subspace can actually be represented by diff --git a/src/manifolds/GrassmannStiefel.jl b/src/manifolds/GrassmannStiefel.jl index 5fa2382b61..e1dc8279be 100644 --- a/src/manifolds/GrassmannStiefel.jl +++ b/src/manifolds/GrassmannStiefel.jl @@ -76,7 +76,7 @@ Then the exponential map is written using z = p V\cos(S)V^\mathrm{H} + U\sin(S)V^\mathrm{H}, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian and the +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian and the cosine and sine are applied element wise to the diagonal entries of $S$. A final QR decomposition $z=QR$ is performed for numerical stability reasons, yielding the result as @@ -111,7 +111,7 @@ of `p` on the [`Grassmann`](@ref) manifold `M`. The formula reads g_p(X,Y) = \operatorname{tr}(X^{\mathrm{H}}Y), ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. """ inner(::Grassmann, p, X, Y) = dot(X, Y) @@ -125,7 +125,7 @@ Compute the inverse retraction for the [`PolarRetraction`](https://juliamanifold \operatorname{retr}_p^{-1}q = q*(p^\mathrm{H}q)^{-1} - p, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. """ inverse_retract(::Grassmann, ::Any, ::Any, ::PolarInverseRetraction) @@ -143,7 +143,7 @@ Compute the inverse retraction for the [`QRRetraction`](https://juliamanifolds.g ````math \operatorname{retr}_p^{-1}q = q(p^\mathrm{H}q)^{-1} - p, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. """ inverse_retract(::Grassmann, ::Any, ::Any, ::QRInverseRetraction) @@ -160,10 +160,10 @@ i.e. the tangent vector `X` whose corresponding [`geodesic`](https://juliamanifo reaches `q` after time 1 on `M`. The formula reads ````math -\log_p q = V\cdot \operatorname{atan}(S) \cdot U^\mathrm{H}, +\log_p q = Vβ‹… \operatorname{atan}(S) β‹… U^\mathrm{H}, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. The matrices $U$ and $V$ are the unitary matrices, and $S$ is the diagonal matrix containing the singular values of the SVD-decomposition @@ -187,7 +187,7 @@ end Project `p` from the embedding onto the [`Grassmann`](@ref) `M`, i.e. compute `q` as the polar decomposition of $p$ such that $q^{\mathrm{H}}q$ is the identity, -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. """ project(::Grassmann, ::Any) @@ -207,7 +207,7 @@ which is computed by \operatorname{proj_p}(X) = X - pp^{\mathrm{H}}X, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. """ project(::Grassmann, ::Any...) @@ -266,7 +266,7 @@ Compute the SVD-based retraction [`PolarRetraction`](https://juliamanifolds.gith \operatorname{retr}_p X = UV^\mathrm{H}, ```` -where $\cdot^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. """ retract(::Grassmann, ::Any, ::Any, ::PolarRetraction) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index aa4696cc59..ea0171f47a 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -37,7 +37,7 @@ consisting of (real-valued) hamiltonian matrices of size ``n Γ— n``, i.e. the se ````math \mathfrak{sp}(2n,𝔽) = \bigl\{p ∈ 𝔽^{2n Γ— 2n}\ \big|\ p^+ = p \bigr\}, ```` -where ``\cdot^{+}`` denotes the [`symplectic_inverse`](@ref),. and ``𝔽 ∈ \{ ℝ, β„‚\}``. +where ``β‹…^{+}`` denotes the [`symplectic_inverse`](@ref),. and ``𝔽 ∈ \{ ℝ, β„‚\}``. Though it is slightly redundant, usually the matrices are stored as ``2n Γ— 2n`` arrays. diff --git a/src/manifolds/Hyperbolic.jl b/src/manifolds/Hyperbolic.jl index 3d40bbcd4c..6877640070 100644 --- a/src/manifolds/Hyperbolic.jl +++ b/src/manifolds/Hyperbolic.jl @@ -3,7 +3,7 @@ The hyperbolic space $\mathcal H^n$ represented by $n+1$-Tuples, i.e. embedded in the [`Lorentz`](@ref)ian manifold equipped with the [`MinkowskiMetric`](@ref) -$⟨\cdot,\cdot⟩_{\mathrm{M}}$. The space is defined as +$βŸ¨β‹…,β‹…βŸ©_{\mathrm{M}}$. The space is defined as ```math \mathcal H^n = \Bigl\{p ∈ ℝ^{n+1}\ \Big|\ ⟨p,p⟩_{\mathrm{M}}= -p_{n+1}^2 @@ -223,7 +223,7 @@ from `p` towards `X`. The formula reads + \sinh(\sqrt{⟨X,X⟩_{\mathrm{M}}})\frac{X}{\sqrt{⟨X,X⟩_{\mathrm{M}}}}, ```` -where $⟨\cdot,\cdot⟩_{\mathrm{M}}$ denotes the [`MinkowskiMetric`](@ref) on the embedding, +where $βŸ¨β‹…,β‹…βŸ©_{\mathrm{M}}$ denotes the [`MinkowskiMetric`](@ref) on the embedding, the [`Lorentz`](@ref)ian manifold. """ exp(::Hyperbolic, ::Any...) @@ -287,7 +287,7 @@ reaches `q` after time 1. The formula reads for $p β‰  q$ \frac{q-⟨p,q⟩_{\mathrm{M}} p}{\lVert q-⟨p,q⟩_{\mathrm{M}} p \rVert_2}, ``` -where $⟨\cdot,\cdot⟩_{\mathrm{M}}$ denotes the [`MinkowskiMetric`](@ref) on the embedding, +where $βŸ¨β‹…,β‹…βŸ©_{\mathrm{M}}$ denotes the [`MinkowskiMetric`](@ref) on the embedding, the [`Lorentz`](@ref)ian manifold. For $p=q$ the logarihmic map is equal to the zero vector. """ log(::Hyperbolic, ::Any...) @@ -344,7 +344,7 @@ The formula reads ````math Y = X + ⟨p,X⟩_{\mathrm{M}} p, ```` -where $⟨\cdot, \cdot⟩_{\mathrm{M}}$ denotes the [`MinkowskiMetric`](@ref) on the embedding, +where $βŸ¨β‹…, β‹…βŸ©_{\mathrm{M}}$ denotes the [`MinkowskiMetric`](@ref) on the embedding, the [`Lorentz`](@ref)ian manifold. !!! note @@ -376,7 +376,7 @@ connecting `p` and `q`. The formula reads \mathcal P_{q←p}X = X - \frac{⟨\log_p q,X⟩_p}{d^2_{\mathcal H^n}(p,q)} \bigl(\log_p q + \log_qp \bigr), ```` -where $⟨\cdot,\cdot⟩_p$ denotes the inner product in the tangent space at `p`. +where $βŸ¨β‹…,β‹…βŸ©_p$ denotes the inner product in the tangent space at `p`. """ parallel_transport_to(::Hyperbolic, ::Any, ::Any, ::Any) diff --git a/src/manifolds/HyperbolicHyperboloid.jl b/src/manifolds/HyperbolicHyperboloid.jl index b5df6543bb..0f4c30f083 100644 --- a/src/manifolds/HyperbolicHyperboloid.jl +++ b/src/manifolds/HyperbolicHyperboloid.jl @@ -229,7 +229,7 @@ Compute the distance on the [`Hyperbolic`](@ref) `M`, which reads d_{\mathcal H^n}(p,q) = \operatorname{acosh}( - ⟨p, q⟩_{\mathrm{M}}), ```` -where $⟨\cdot,\cdot⟩_{\mathrm{M}}$ denotes the [`MinkowskiMetric`](@ref) on the embedding, +where $βŸ¨β‹…,β‹…βŸ©_{\mathrm{M}}$ denotes the [`MinkowskiMetric`](@ref) on the embedding, the [`Lorentz`](@ref)ian manifold. """ function distance(::Hyperbolic, p, q) diff --git a/src/manifolds/MetricManifold.jl b/src/manifolds/MetricManifold.jl index 87ba053734..62a028ddbf 100644 --- a/src/manifolds/MetricManifold.jl +++ b/src/manifolds/MetricManifold.jl @@ -449,7 +449,7 @@ end Return the local matrix representation at the point `p` of the metric tensor ``g`` with respect to the [`AbstractBasis`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/bases.html#ManifoldsBase.AbstractBasis) `B` on the [`AbstractManifold`](https://juliamanifolds.github.io/Manifolds.jl/latest/interface.html#ManifoldsBase.AbstractManifold) `M`. Let ``d``denote the dimension of the manifold and $b_1,\ldots,b_d$ the basis vectors. -Then the local matrix representation is a matrix ``G\in 𝔽^{n\times n}`` whose entries are +Then the local matrix representation is a matrix ``G\in 𝔽^{nΓ—n}`` whose entries are given by ``g_{ij} = g_p(b_i,b_j), i,j\in\{1,…,d\}``. This yields the property for two tangent vectors (using Einstein summation convention) diff --git a/src/manifolds/PositiveNumbers.jl b/src/manifolds/PositiveNumbers.jl index 84313f329c..05abf09b57 100644 --- a/src/manifolds/PositiveNumbers.jl +++ b/src/manifolds/PositiveNumbers.jl @@ -304,7 +304,7 @@ Compute the parallel transport of `X` from the tangent space at `p` to the tange `q` on the [`PositiveNumbers`](@ref) `M`. ````math -\mathcal P_{q\gets p}(X) = X\cdot\frac{q}{p}. +\mathcal P_{q\gets p}(X) = Xβ‹…\frac{q}{p}. ```` """ parallel_transport_to(::PositiveNumbers, ::Any, ::Any, ::Any) diff --git a/src/manifolds/SkewHermitian.jl b/src/manifolds/SkewHermitian.jl index 0427cf8c8a..61aebdb0f5 100644 --- a/src/manifolds/SkewHermitian.jl +++ b/src/manifolds/SkewHermitian.jl @@ -7,7 +7,7 @@ complex-valued skew-hermitian matrices of size ``n Γ— n``, i.e. the set ````math \operatorname{SkewHerm}(n) = \bigl\{p ∈ 𝔽^{n Γ— n}\ \big|\ p^{\mathrm{H}} = -p \bigr\}, ```` -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, +where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, and the field $𝔽 ∈ \{ ℝ, β„‚, ℍ\}$. Though it is slightly redundant, usually the matrices are stored as ``n Γ— n`` arrays. @@ -223,7 +223,7 @@ Projects `p` from the embedding onto the [`SkewHermitianMatrices`](@ref) `M`, i. \operatorname{proj}_{\operatorname{SkewHerm}(n)}(p) = \frac{1}{2} \bigl( p - p^{\mathrm{H}} \bigr), ```` -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SkewHermitianMatrices, ::Any) @@ -241,7 +241,7 @@ Project the matrix `X` onto the tangent space at `p` on the [`SkewHermitianMatri \operatorname{proj}_p(X) = \frac{1}{2} \bigl( X - X^{\mathrm{H}} \bigr), ```` -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SkewHermitianMatrices, ::Any, ::Any) diff --git a/src/manifolds/Sphere.jl b/src/manifolds/Sphere.jl index b39be325f1..d27318148a 100644 --- a/src/manifolds/Sphere.jl +++ b/src/manifolds/Sphere.jl @@ -28,7 +28,7 @@ The tangent space at point $p$ is given by T_pπ•Š^{n} := \bigl\{ X ∈ 𝔽^{n+1}\ |\ \Re(⟨p,X⟩) = 0 \bigr \}, ```` -where $𝔽\in\{ℝ,β„‚,ℍ\}$ and $⟨\cdot,\cdot⟩$ denotes the inner product in the +where $𝔽\in\{ℝ,β„‚,ℍ\}$ and $βŸ¨β‹…,β‹…βŸ©$ denotes the inner product in the embedding $𝔽^{n+1}$. For $𝔽=β„‚$, the manifold is the complex sphere, written $β„‚π•Š^n$, embedded in $β„‚^{n+1}$. @@ -80,7 +80,7 @@ The tangent space at point $p$ is given by T_p π•Š^{n_1, n_2, …, n_i} := \bigl\{ X ∈ 𝔽^{n_1, n_2, …, n_i}\ |\ \Re(⟨p,X⟩) = 0 \bigr \}, ```` -where $𝔽\in\{ℝ,β„‚,ℍ\}$ and $⟨\cdot,\cdot⟩$ denotes the (Frobenius) inner product in the +where $𝔽\in\{ℝ,β„‚,ℍ\}$ and $βŸ¨β‹…,β‹…βŸ©$ denotes the (Frobenius) inner product in the embedding $𝔽^{n_1, n_2, …, n_i}$. This manifold is modeled as an embedded manifold to the [`Euclidean`](@ref), i.e. @@ -437,7 +437,7 @@ Project the point `p` from the embedding onto the [`Sphere`](@ref) `M`. ````math \operatorname{proj}(p) = \frac{p}{\lVert p \rVert}, ```` -where $\lVert\cdot\rVert$ denotes the usual 2-norm for vectors if $m=1$ and the Frobenius +where $\lVertβ‹…\rVert$ denotes the usual 2-norm for vectors if $m=1$ and the Frobenius norm for the case $m>1$. """ project(::AbstractSphere, ::Any) diff --git a/src/manifolds/SphereSymmetricMatrices.jl b/src/manifolds/SphereSymmetricMatrices.jl index 1c9eecf0f0..a3e15a8b91 100644 --- a/src/manifolds/SphereSymmetricMatrices.jl +++ b/src/manifolds/SphereSymmetricMatrices.jl @@ -6,7 +6,7 @@ of unit Frobenius norm, i.e. ````math \mathcal{S}_{\text{sym}} :=\bigl\{p ∈ 𝔽^{n Γ— n}\ \big|\ p^{\mathrm{H}} = p, \lVert p \rVert = 1 \bigr\}, ```` -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, +where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, and the field $𝔽 ∈ \{ ℝ, β„‚\}$. # Constructor @@ -119,7 +119,7 @@ Projects `p` from the embedding onto the [`SphereSymmetricMatrices`](@ref) `M`, ````math \operatorname{proj}_{\mathcal{S}_{\text{sym}}}(p) = \frac{1}{2} \bigl( p + p^{\mathrm{H}} \bigr), ```` -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SphereSymmetricMatrices, ::Any) @@ -135,7 +135,7 @@ Project the matrix `X` onto the tangent space at `p` on the [`SphereSymmetricMat ````math \operatorname{proj}_p(X) = \frac{X + X^{\mathrm{H}}}{2} - ⟨p, \frac{X + X^{\mathrm{H}}}{2}⟩p, ```` -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SphereSymmetricMatrices, ::Any, ::Any) diff --git a/src/manifolds/Stiefel.jl b/src/manifolds/Stiefel.jl index e17da0546a..6317bea1e1 100644 --- a/src/manifolds/Stiefel.jl +++ b/src/manifolds/Stiefel.jl @@ -8,7 +8,7 @@ The Stiefel manifold consists of all $n Γ— k$, $n β‰₯ k$ unitary matrices, i.e. ```` where $𝔽 ∈ \{ℝ, β„‚\}$, -$\cdot^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and +$β‹…^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and $I_k ∈ ℝ^{k Γ— k}$ denotes the $k Γ— k$ identity matrix. The tangent space at a point $p ∈ \mathcal M$ is given by @@ -17,7 +17,7 @@ The tangent space at a point $p ∈ \mathcal M$ is given by T_p \mathcal M = \{ X ∈ 𝔽^{n Γ— k} : p^{\mathrm{H}}X + \overline{X^{\mathrm{H}}p} = 0_k\}, ```` -where $0_k$ is the $k Γ— k$ zero matrix and $\overline{\cdot}$ the (elementwise) complex conjugate. +where $0_k$ is the $k Γ— k$ zero matrix and $\overline{β‹…}$ the (elementwise) complex conjugate. This manifold is modeled as an embedded manifold to the [`Euclidean`](@ref), i.e. several functions like the [`inner`](@ref inner(::Euclidean, ::Any...)) product and the @@ -78,7 +78,7 @@ end check_point(M::Stiefel, p; kwargs...) Check whether `p` is a valid point on the [`Stiefel`](@ref) `M`=$\operatorname{St}(n,k)$, i.e. that it has the right -[`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and $p^{\mathrm{H}}p$ is (approximately) the identity, where $\cdot^{\mathrm{H}}$ is the +[`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and $p^{\mathrm{H}}p$ is (approximately) the identity, where $β‹…^{\mathrm{H}}$ is the complex conjugate transpose. The settings for approximately can be set with `kwargs...`. """ function check_point(M::Stiefel, p; kwargs...) @@ -100,7 +100,7 @@ end Checks whether `X` is a valid tangent vector at `p` on the [`Stiefel`](@ref) `M`=$\operatorname{St}(n,k)$, i.e. the [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) fits and it (approximately) holds that $p^{\mathrm{H}}X + \overline{X^{\mathrm{H}}p} = 0$, -where $\cdot^{\mathrm{H}}$ denotes the Hermitian and $\overline{\cdot}$ the (elementwise) complex conjugate. +where $β‹…^{\mathrm{H}}$ denotes the Hermitian and $\overline{β‹…}$ the (elementwise) complex conjugate. The settings for approximately can be set with `kwargs...`. """ function check_vector(M::Stiefel, p, X; kwargs...) diff --git a/src/manifolds/StiefelCanonicalMetric.jl b/src/manifolds/StiefelCanonicalMetric.jl index 7e750c3f9d..9306988fd8 100644 --- a/src/manifolds/StiefelCanonicalMetric.jl +++ b/src/manifolds/StiefelCanonicalMetric.jl @@ -40,7 +40,7 @@ respect to ``p``, i.e. ```math X = pp^{\mathrm{T}}X + (I_n-pp^{\mathrm{T}})X, ``` -where ``I_n`` is the ``n\times n`` identity matrix. +where ``I_n`` is the ``nΓ—n`` identity matrix. We introduce ``A=p^{\mathrm{T}}X`` and ``QR = (I_n-pp^{\mathrm{T}})X`` the `qr` decomposition of the vertical component. Then using the matrix exponential ``\operatorname{Exp}`` we introduce ``B`` and ``C`` as diff --git a/src/manifolds/StiefelEuclideanMetric.jl b/src/manifolds/StiefelEuclideanMetric.jl index fa2e64518c..304bb124c3 100644 --- a/src/manifolds/StiefelEuclideanMetric.jl +++ b/src/manifolds/StiefelEuclideanMetric.jl @@ -18,7 +18,7 @@ emanating from `p` in tangent direction `X`. ```` where $\operatorname{Exp}$ denotes matrix exponential, -$\cdot^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and $I_k$ and +$β‹…^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and $I_k$ and $0_k$ are the identity matrix and the zero matrix of dimension $k Γ— k$, respectively. """ exp(::Stiefel, ::Any...) @@ -39,9 +39,9 @@ end get_basis(M::Stiefel{<:Any,ℝ}, p, B::DefaultOrthonormalBasis) Create the default basis using the parametrization for any $X ∈ T_p\mathcal M$. -Set $p_\bot \in ℝ^{n\times(n-k)}$ the matrix such that the $n\times n$ matrix of the common +Set $p_\bot \in ℝ^{nΓ—(n-k)}$ the matrix such that the $nΓ—n$ matrix of the common columns $[p\ p_\bot]$ is an ONB. -For any skew symmetric matrix $a ∈ ℝ^{k\times k}$ and any $b ∈ ℝ^{(n-k)\times k}$ the matrix +For any skew symmetric matrix $a ∈ ℝ^{kΓ—k}$ and any $b ∈ ℝ^{(n-k)Γ—k}$ the matrix ````math X = pa + p_\bot b ∈ T_p\mathcal M @@ -53,7 +53,7 @@ using unit vectors for constructing both the upper matrix of $a$ to build a skew symmetric matrix and the matrix b, the default basis is constructed. -Since $[p\ p_\bot]$ is an automorphism on $ℝ^{n\times p}$ the elements of $a$ and $b$ are +Since $[p\ p_\bot]$ is an automorphism on $ℝ^{nΓ—p}$ the elements of $a$ and $b$ are orthonormal coordinates for the tangent space. To be precise exactly one element in the upper trangular entries of $a$ is set to $1$ its symmetric entry to $-1$ and we normalize with the factor $\frac{1}{\sqrt{2}}$ and for $b$ one can just use unit vectors reshaped to a matrix @@ -129,7 +129,7 @@ end Projects `p` from the embedding onto the [`Stiefel`](@ref) `M`, i.e. compute `q` as the polar decomposition of $p$ such that ``q^{\mathrm{H}}q`` is the identity, -where ``\cdot^{\mathrm{H}}`` denotes the hermitian, i.e. complex conjugate transposed. +where ``β‹…^{\mathrm{H}}`` denotes the hermitian, i.e. complex conjugate transposed. """ project(::Stiefel, ::Any, ::Any) diff --git a/src/manifolds/Symmetric.jl b/src/manifolds/Symmetric.jl index c39501d8f6..02381510be 100644 --- a/src/manifolds/Symmetric.jl +++ b/src/manifolds/Symmetric.jl @@ -7,7 +7,7 @@ symmetric matrices of size ``n Γ— n``, i.e. the set ````math \operatorname{Sym}(n) = \bigl\{p ∈ 𝔽^{n Γ— n}\ \big|\ p^{\mathrm{H}} = p \bigr\}, ```` -where ``\cdot^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transpose, +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transpose, and the field ``𝔽 ∈ \{ ℝ, β„‚\}``. Though it is slightly redundant, usually the matrices are stored as ``n Γ— n`` arrays. @@ -202,7 +202,7 @@ Projects `p` from the embedding onto the [`SymmetricMatrices`](@ref) `M`, i.e. \operatorname{proj}_{\operatorname{Sym}(n)}(p) = \frac{1}{2} \bigl( p + p^{\mathrm{H}} \bigr), ```` -where ``\cdot^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SymmetricMatrices, ::Any) @@ -220,7 +220,7 @@ Project the matrix `X` onto the tangent space at `p` on the [`SymmetricMatrices` \operatorname{proj}_p(X) = \frac{1}{2} \bigl( X + X^{\mathrm{H}} \bigr), ```` -where ``\cdot^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SymmetricMatrices, ::Any, ::Any) diff --git a/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl b/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl index 126b40c1e2..5be7335301 100644 --- a/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl +++ b/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl @@ -65,7 +65,7 @@ d_{\mathcal P(n)}(p,q) = \lVert \operatorname{Log}(p^{-\frac{1}{2}}qp^{-\frac{1}{2}})\rVert_{\mathrm{F}}., ``` where $\operatorname{Log}$ denotes the matrix logarithm and -$\lVert\cdot\rVert_{\mathrm{F}}$ denotes the matrix Frobenius norm. +$\lVertβ‹…\rVert_{\mathrm{F}}$ denotes the matrix Frobenius norm. """ function distance(::SymmetricPositiveDefinite, p, q) # avoid numerical instabilities in cholesky diff --git a/src/manifolds/SymmetricPositiveDefiniteLogCholesky.jl b/src/manifolds/SymmetricPositiveDefiniteLogCholesky.jl index 47c43ea723..2c652a8876 100644 --- a/src/manifolds/SymmetricPositiveDefiniteLogCholesky.jl +++ b/src/manifolds/SymmetricPositiveDefiniteLogCholesky.jl @@ -32,8 +32,8 @@ d_{\mathcal P(n)}(p,q) = \sqrt{ ```` where $x$ and $y$ are the cholesky factors of $p$ and $q$, respectively, -$⌊\cdotβŒ‹$ denbotes the strictly lower triangular matrix of its argument, -and $\lVert\cdot\rVert_{\mathrm{F}}$ the Frobenius norm. +$βŒŠβ‹…βŒ‹$ denbotes the strictly lower triangular matrix of its argument, +and $\lVertβ‹…\rVert_{\mathrm{F}}$ the Frobenius norm. """ function distance(M::MetricManifold{ℝ,<:SymmetricPositiveDefinite,LogCholeskyMetric}, p, q) N = get_parameter(M.manifold.size)[1] @@ -52,7 +52,7 @@ Compute the exponential map on the [`SymmetricPositiveDefinite`](@ref) `M` with where $\exp_xW$ is the exponential map on [`CholeskySpace`](@ref), $y$ is the cholesky decomposition of $p$, $W = y(y^{-1}Xy^{-\mathrm{T}})_\frac{1}{2}$, -and $(\cdot)_\frac{1}{2}$ +and $(β‹…)_\frac{1}{2}$ denotes the lower triangular matrix with the diagonal multiplied by $\frac{1}{2}$. """ exp(::MetricManifold{ℝ,SymmetricPositiveDefinite,LogCholeskyMetric}, ::Any...) @@ -84,9 +84,9 @@ a [`MetricManifold`](@ref) with [`LogCholeskyMetric`](@ref). The formula reads g_p(X,Y) = ⟨a_z(X),a_z(Y)⟩_z, ```` -where $⟨\cdot,\cdot⟩_x$ denotes inner product on the [`CholeskySpace`](@ref), +where $βŸ¨β‹…,β‹…βŸ©_x$ denotes inner product on the [`CholeskySpace`](@ref), $z$ is the cholesky factor of $p$, -$a_z(W) = z (z^{-1}Wz^{-\mathrm{T}})_{\frac{1}{2}}$, and $(\cdot)_\frac{1}{2}$ +$a_z(W) = z (z^{-1}Wz^{-\mathrm{T}})_{\frac{1}{2}}$, and $(β‹…)_\frac{1}{2}$ denotes the lower triangular matrix with the diagonal multiplied by $\frac{1}{2}$ """ function inner(M::MetricManifold{ℝ,<:SymmetricPositiveDefinite,LogCholeskyMetric}, p, X, Y) @@ -139,7 +139,7 @@ Parallel transport the tangent vector `X` at `p` along the geodesic to `q` with the [`SymmetricPositiveDefinite`](@ref) manifold `M` and [`LogCholeskyMetric`](@ref). The parallel transport is based on the parallel transport on [`CholeskySpace`](@ref): Let $x$ and $y$ denote the cholesky factors of `p` and `q`, respectively and -$W = x(x^{-1}Xx^{-\mathrm{T}})_\frac{1}{2}$, where $(\cdot)_\frac{1}{2}$ denotes the lower +$W = x(x^{-1}Xx^{-\mathrm{T}})_\frac{1}{2}$, where $(β‹…)_\frac{1}{2}$ denotes the lower triangular matrix with the diagonal multiplied by $\frac{1}{2}$. With $V$ the parallel transport on [`CholeskySpace`](@ref) from $x$ to $y$. The formula hear reads diff --git a/src/manifolds/SymmetricPositiveDefiniteLogEuclidean.jl b/src/manifolds/SymmetricPositiveDefiniteLogEuclidean.jl index ad579dffc1..4bd85955f1 100644 --- a/src/manifolds/SymmetricPositiveDefiniteLogEuclidean.jl +++ b/src/manifolds/SymmetricPositiveDefiniteLogEuclidean.jl @@ -18,7 +18,7 @@ The formula reads ``` where $\operatorname{Log}$ denotes the matrix logarithm and -$\lVert\cdot\rVert_{\mathrm{F}}$ denotes the matrix Frobenius norm. +$\lVertβ‹…\rVert_{\mathrm{F}}$ denotes the matrix Frobenius norm. """ function distance(::MetricManifold{ℝ,<:SymmetricPositiveDefinite,LogEuclideanMetric}, p, q) return norm(log(Symmetric(p)) - log(Symmetric(q))) diff --git a/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl b/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl index 65c774f07c..435d95ece6 100644 --- a/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl +++ b/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl @@ -10,7 +10,7 @@ p ∈ 𝔽^{n Γ— n}\ \big|\ p^{\mathrm{H}} = p, apa^{\mathrm{H}} \geq 0 \text{ for all } a ∈ 𝔽 \text{ and } \operatorname{rank}(p) = k\bigr\}, ```` -where $\cdot^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, +where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, and the field $𝔽 ∈ \{ ℝ, β„‚\}$. We sometimes $\operatorname{SPS}_{k,𝔽}(n)$, when distinguishing the real- and complex-valued manifold is important. diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index 7139dc0b8d..0328f20ac3 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -1,41 +1,36 @@ @doc raw""" Symplectic{T, 𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType} -The symplectic manifold consists of all ``2n \times 2n`` matrices which preserve -the canonical symplectic form over ``𝔽^{2n Γ— 2n} \times 𝔽^{2n Γ— 2n}``, -````math - \omega\colon 𝔽^{2n Γ— 2n} \times 𝔽^{2n Γ— 2n} \rightarrow 𝔽, - \quad \omega(x, y) = p^{\mathrm{T}} Q_{2n} q, \; x, y \in 𝔽^{2n Γ— 2n}, -```` -where -````math -Q_{2n} = -\begin{bmatrix} - 0_n & I_n \\ - -I_n & 0_n -\end{bmatrix}. -```` -That is, the symplectic manifold consists of -````math -\operatorname{Sp}(2n, ℝ) = \bigl\{ p ∈ ℝ^{2n Γ— 2n} \, \big| \, p^{\mathrm{T}}Q_{2n}p = Q_{2n} \bigr\}, -```` -with ``0_n`` and ``I_n`` denoting the ``n Γ— n`` zero-matrix -and indentity matrix in ``ℝ^{n \times n}`` respectively. +The symplectic manifold consists of all ``2nΓ—2n`` matrices which preserve +the canonical symplectic form over ``𝔽^{2n Γ— 2n}×𝔽^{2n Γ— 2n}``, +```math + \omega\colon 𝔽^{2n Γ— 2n}×𝔽^{2n Γ— 2n} β†’ 𝔽, + \quad \omega(x, y) = p^{\mathrm{T}} J_{2n} q, \ x, y \in 𝔽^{2n Γ— 2n}, +``` + +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). + +The symplectic manifold consists of + +```math +\mathrm{Sp}(2n, ℝ) = \bigl\{ p ∈ ℝ^{2n Γ— 2n} \, \big| \, p^{\mathrm{T}}J_{2n}p = J_{2n} \bigr\}, +``` The tangent space at a point ``p`` is given by [BendokatZimmermann:2021](@cite) -````math + +```math \begin{align*} - T_p\operatorname{Sp}(2n) - &= \{X \in \mathbb{R}^{2n \times 2n} \;|\; p^{T}Q_{2n}X + X^{T}Q_{2n}p = 0 \}, \\ - &= \{X = pQS \;|\; S ∈ R^{2n Γ— 2n}, S^{\mathrm{T}} = S \}. + T_p\mathrm{Sp}(2n) + &= \{X \in ℝ^{2nΓ—2n} \ |\ p^{T}J_{2n}X + X^{T}J_{2n}p = 0 \}, \\ + &= \{X = pJ_{2n}S \ \mid\ S ∈ R^{2n Γ— 2n}, S^{\mathrm{T}} = S \}. \end{align*} -```` +``` # Constructor Symplectic(2n, field=ℝ; parameter::Symbol=:type) -Generate the (real-valued) symplectic manifold of ``2n \times 2n`` symplectic matrices. +Generate the (real-valued) symplectic manifold of ``2n Γ— 2n`` symplectic matrices. The constructor for the [`Symplectic`](@ref) manifold accepts the even column/row embedding dimension ``2n`` for the real symplectic manifold, ``ℝ^{2n Γ— 2n}``. """ @@ -58,13 +53,15 @@ end RealSymplecticMetric <: RiemannianMetric The canonical Riemannian metric on the symplectic manifold, -defined pointwise for ``p \in \operatorname{Sp}(2n)`` by [Fiori:2011](@cite)] -````math +defined pointwise for ``p \in \mathrm{Sp}(2n)`` by [Fiori:2011](@cite)] + +```math \begin{align*} - & g_p \colon T_p\operatorname{Sp}(2n) \times T_p\operatorname{Sp}(2n) \rightarrow ℝ, \\ - & g_p(Z_1, Z_2) = \operatorname{tr}((p^{-1}Z_1)^{\mathrm{T}} (p^{-1}Z_2)). + & g_p \colon T_p\mathrm{Sp}(2n)Γ—T_p\mathrm{Sp}(2n) β†’ ℝ, \\ + & g_p(Z_1, Z_2) = \operatorname{tr}((p^{-1}Z_1)^{\mathrm{T}} (p^{-1}Z_2)). \end{align*} -```` +``` + This metric is also the default metric for the [`Symplectic`](@ref) manifold. """ struct RealSymplecticMetric <: RiemannianMetric end @@ -72,12 +69,13 @@ struct RealSymplecticMetric <: RiemannianMetric end @doc raw""" ExtendedSymplecticMetric <: AbstractMetric -The extension of the [`RealSymplecticMetric`](@ref) at a point `p \in \operatorname{Sp}(2n)` -as an inner product over the embedding space ``ℝ^{2n \times 2n}``, i.e. -````math - \langle x, y \rangle_{p} = \langle p^{-1}x, p^{-1}\rangle_{\operatorname{Fr}} - = \operatorname{tr}(x^{\mathrm{T}}(pp^{\mathrm{T}})^{-1}y), \;\forall\; x, y \in ℝ^{2n \times 2n}. -```` +The extension of the [`RealSymplecticMetric`](@ref) at a point `p \in \mathrm{Sp}(2n)` +as an inner product over the embedding space ``ℝ^{2nΓ—2n}``, i.e. + +```math + ⟨x, y⟩_p = ⟨p^{-1}x, p^{-1}⟩_{\mathrm{Fr}} + = \operatorname{tr}(x^{\mathrm{T}}(pp^{\mathrm{T}})^{-1}y), \text{ for all } x, y \in ℝ^{2n Γ— 2n}. +``` """ struct ExtendedSymplecticMetric <: AbstractMetric end @@ -86,23 +84,31 @@ struct ExtendedSymplecticMetric <: AbstractMetric end A lightweight structure to represent the action of the matrix representation of the canonical symplectic form, -````math -Q_{2n}(Ξ») = Ξ» -\begin{bmatrix} + +```math +J_{2n}(Ξ») = Ξ»\begin{bmatrix} 0_n & I_n \\ -I_n & 0_n -\end{bmatrix} \quad \in ℝ^{2n \times 2n}, -```` -such that the canonical symplectic form is represented by -````math -\omega_{2n}(x, y) = x^{\mathrm{T}}Q_{2n}(1)y, \quad x, y \in ℝ^{2n}. -```` +\end{bmatrix} ∈ ℝ^{2n Γ— 2n}, +``` + +where we write ``J_{2n} = J_{2n}(1)`` for short. +The canonical symplectic form is represented by + +```math +\omega_{2n}(x, y) = x^{\mathrm{T}}J_{2n}y, \quad x, y ∈ ℝ^{2n}. +``` The entire matrix is however not instantiated in memory, instead a scalar ``Ξ»`` of type `T` is stored, which is used to keep track of scaling and transpose operations applied to each `SymplecticMatrix`. -For example, given `Q = SymplecticMatrix(1.0)` represented as `1.0*[0 I; -I 0]`, -the adjoint `Q'` returns `SymplecticMatrix(-1.0) = (-1.0)*[0 I; -I 0]`. +This type acts similar to `I` from `LinearAlgeba`. + +# Constructor + + SymplecticMatrix(Ξ»=1) + +Generate the sumplectic matrix with scaling ``1``. """ struct SymplecticMatrix{T} Ξ»::T @@ -119,35 +125,42 @@ end change_representer(::Symplectic, ::EuclideanMetric, p, X) change_representer!(::Symplectic, Y, ::EuclideanMetric, p, X) -Compute the representation of a tangent vector ``ΞΎ ∈ T_p\operatorname{Sp}(2n, ℝ)`` s.t. -````math - g_p(c_p(ΞΎ), Ξ·) = ⟨ξ, η⟩^{\text{Euc}} \;βˆ€\; Ξ· ∈ T_p\operatorname{Sp}(2n, ℝ). -```` +Compute the representation of a tangent vector ``ΞΎ ∈ T_p\mathrm{Sp}(2n, ℝ)`` s.t. +```math + g_p(c_p(ΞΎ), Ξ·) = ⟨ξ, η⟩^{\text{Euc}} \text{for all } Ξ· ∈ T_p\mathrm{Sp}(2n, ℝ). +``` with the conversion function -````math - c_p : T_p\operatorname{Sp}(2n, ℝ) \rightarrow T_p\operatorname{Sp}(2n, ℝ), \quad - c_p(ΞΎ) = \frac{1}{2} pp^{\mathrm{T}} ΞΎ + \frac{1}{2} pQ ΞΎ^{\mathrm{T}} pQ. -```` -Each of the terms ``c_p^1(ΞΎ) = p p^{\mathrm{T}} ΞΎ`` and ``c_p^2(ΞΎ) = pQ ΞΎ^{\mathrm{T}} pQ`` from the +```math + c_p : T_p\mathrm{Sp}(2n, ℝ) β†’ T_p\mathrm{Sp}(2n, ℝ), \quad + c_p(ΞΎ) = \frac{1}{2} pp^{\mathrm{T}} ΞΎ + \frac{1}{2} pJ_{2n} ΞΎ^{\mathrm{T}} pJ_{2n}, +``` + +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). + +Each of the terms ``c_p^1(ΞΎ) = p p^{\mathrm{T}} ΞΎ`` and ``c_p^2(ΞΎ) = pJ_{2n} ΞΎ^{\mathrm{T}} pJ_{2n}`` from the above definition of ``c_p(Ξ·)`` are themselves metric compatible in the sense that -````math - c_p^i : T_p\operatorname{Sp}(2n, ℝ) \rightarrow \mathbb{R}^{2n \times 2n}\quad - g_p^i(c_p(ΞΎ), Ξ·) = ⟨ξ, η⟩^{\text{Euc}} \;βˆ€\; Ξ· ∈ T_p\operatorname{Sp}(2n, ℝ), -```` + +```math + c_p^i : T_p\mathrm{Sp}(2n, ℝ) β†’ ℝ^{2nΓ—2n}\quad + g_p^i(c_p(ΞΎ), Ξ·) = ⟨ξ, η⟩^{\text{Euc}} \;βˆ€\; Ξ· ∈ T_p\mathrm{Sp}(2n, ℝ), +``` + for ``i \in {1, 2}``. However the range of each function alone is not confined to -``T_p\operatorname{Sp}(2n, ℝ)``, but the convex combination -````math + ``T_p\mathrm{Sp}(2n, ℝ)``, but the convex combination + +```math c_p(ΞΎ) = \frac{1}{2}c_p^1(ΞΎ) + \frac{1}{2}c_p^2(ΞΎ) -```` -does have the correct range ``T_p\operatorname{Sp}(2n, ℝ)``. +``` + +does have the correct range ``T_p\mathrm{Sp}(2n, ℝ)``. """ change_representer(::Symplectic, ::EuclideanMetric, p, X) function change_representer!(::Symplectic, Y, ::EuclideanMetric, p, X) - Q = SymplecticMatrix(p, X) + J = SymplecticMatrix(p, X) # J_{2n} pT_X = p' * X - Y .= (1 / 2) .* p * (pT_X .+ Q * pT_X' * Q) + Y .= (1 / 2) .* p * (pT_X .+ J * pT_X' * J) return Y end @@ -157,20 +170,20 @@ end change_representer!(MetMan::MetricManifold{<:Any, <:Euclidean, ExtendedSymplecticMetric}, Y, EucMet::EuclideanMetric, p, X) -Change the representation of a matrix ``ΞΎ ∈ \mathbb{R}^{2n \times 2n}`` -into the inner product space ``(ℝ^{2n \times 2n}, g_p)`` where the inner product +Change the representation of a matrix ``ΞΎ ∈ ℝ^{2nΓ—2n}`` +into the inner product space ``(ℝ^{2nΓ—2n}, g_p)`` where the inner product is given by ``g_p(ΞΎ, Ξ·) = \langle p^{-1}ΞΎ, p^{-1}Ξ· \rangle = \operatorname{tr}(ΞΎ^{\mathrm{T}}(pp^{\mathrm{T}})^{-1}Ξ·)``, as the extension of the [`RealSymplecticMetric`](@ref) onto the entire embedding space. By changing the representation we mean to apply a mapping ````math - c_p : \mathbb{R}^{2n \times 2n} \rightarrow \mathbb{R}^{2n \times 2n}, + c_p : ℝ^{2nΓ—2n} β†’ ℝ^{2nΓ—2n}, ```` defined by requiring that it satisfy the metric compatibility condition ````math g_p(c_p(ΞΎ), Ξ·) = ⟨p^{-1}c_p(ΞΎ), p^{-1}η⟩ = ⟨ξ, η⟩^{\text{Euc}} - \;βˆ€\; Ξ· ∈ T_p\operatorname{Sp}(2n, ℝ). + \;βˆ€\; Ξ· ∈ T_p\mathrm{Sp}(2n, ℝ). ```` In this case, we compute the mapping ````math @@ -200,17 +213,11 @@ end @doc raw""" check_point(M::Symplectic, p; kwargs...) -Check whether `p` is a valid point on the [`Symplectic`](@ref) `M`=$\operatorname{Sp}(2n)$, +Check whether `p` is a valid point on the [`Symplectic`](@ref) `M`=$\mathrm{Sp}(2n)$, i.e. that it has the right [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and $p^{+}p$ is (approximately) -the identity, where $A^{+} = Q_{2n}^{\mathrm{T}}A^{\mathrm{T}}Q_{2n}$ is the symplectic inverse, with -````math -Q_{2n} = -\begin{bmatrix} -0_n & I_n \\ - -I_n & 0_n -\end{bmatrix}. -```` -The tolerance can be set with `kwargs...` (e.g. `atol = 1.0e-14`). +the identity, where ``A^+`` denotes the [`symplectic_inverse`]/@ref). + +The tolerance can be set with `kwargs...`. """ function check_point( M::Symplectic, @@ -235,35 +242,25 @@ end check_vector(M::Symplectic, p, X; kwargs...) Checks whether `X` is a valid tangent vector at `p` on the [`Symplectic`](@ref) -`M`=``\operatorname{Sp}(2n)``, i.e. the [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) fits and -it (approximately) holds that ``p^{T}Q_{2n}X + X^{T}Q_{2n}p = 0``, -where -````math -Q_{2n} = -\begin{bmatrix} -0_n & I_n \\ - -I_n & 0_n -\end{bmatrix}. -```` -The tolerance can be set with `kwargs...` (e.g. `atol = 1.0e-14`). +`M`=``\mathrm{Sp}(2n)``, which requires that + +```math +p^{T}J_{2n}X + X^{T}J_{2n}p = 0 +``` +holds (approximately), where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). + +The tolerance can be set with `kwargs...` """ check_vector(::Symplectic, ::Any...) -function check_vector( - M::Symplectic, - p, - X::T; - atol::Real=sqrt(prod(representation_size(M))) * eps(real(float(number_eltype(T)))), - kwargs..., -) where {T} - Q = SymplecticMatrix(p, X) - tangent_requirement_norm = norm(X' * Q * p + p' * Q * X, 2) - if !isapprox(tangent_requirement_norm, 0; atol=atol, kwargs...) +function check_vector(M::Symplectic, p, X::T; kwargs...) where {T} + J = SymplecticMatrix(p, X) + if !isapprox(X' * J * p, -p' * J * X; kwargs...) return DomainError( - tangent_requirement_norm, + norm(X' * J * p + p' * J * X, 2), ( "The matrix X is not in the tangent space at point p of the" * - " manifold $(M), as X'Qp + p'QX is not the zero matrix." + " manifold $(M), as X'Jp + p'JX is not the zero matrix." ), ) end @@ -278,12 +275,13 @@ ManifoldsBase.default_retraction_method(::Symplectic) = CayleyRetraction() distance(M::Symplectic, p, q) Compute an approximate geodesic distance between two Symplectic matrices -``p, q \in \operatorname{Sp}(2n)``, as done in [WangSunFiori:2018](@cite). +``p, q \in \mathrm{Sp}(2n)``, as done in [WangSunFiori:2018](@cite). + ````math - \operatorname{dist}(p, q) - β‰ˆ \lVert\operatorname{Log}(p^+q)\rVert_{\operatorname{Fr}}, + \operatorname{dist}(p, q) + β‰ˆ \lVert\operatorname{Log}(p^+q)\rVert_{\\mathrm{Fr}}, ```` -where the ``\operatorname{Log}(\cdot)`` operator is the matrix logarithm. +where the ``\operatorname{Log}(β‹…)`` operator is the matrix logarithm. This approximation is justified by first recalling the Baker-Campbell-Hausdorf formula, ````math @@ -298,23 +296,23 @@ Then we write the expression for the exponential map from ``p`` to ``q`` as = p \operatorname{Exp}((p^{+}X)^{\mathrm{T}}) \operatorname{Exp}([p^{+}X - (p^{+}X)^{\mathrm{T}}]), - X \in T_p\operatorname{Sp}, + X \in T_p\mathrm{Sp}, ```` and with the geodesic distance between ``p`` and ``q`` given by -``\operatorname{dist}(p, q) = \lVertX\rVert_p = \lVertp^+X\rVert_{\operatorname{Fr}}`` +``\operatorname{dist}(p, q) = \lVertX\rVert_p = \lVertp^+X\rVert_{\\mathrm{Fr}}`` we see that ````math \begin{align*} - \lVert\operatorname{Log}(p^+q)\rVert_{\operatorname{Fr}} + \lVert\operatorname{Log}(p^+q)\rVert_{\\mathrm{Fr}} &=\Bigl\lVert \operatorname{Log}\bigl( \operatorname{Exp}((p^{+}X)^{\mathrm{T}}) \operatorname{Exp}(p^{+}X - (p^{+}X)^{\mathrm{T}}) \bigr) - \Bigr\rVert_{\operatorname{Fr}} \\ + \Bigr\rVert_{\\mathrm{Fr}} \\ &=\lVertp^{+}X + \frac{1}{2}[(p^{+}X)^{\mathrm{T}}, p^{+}X - (p^{+}X)^{\mathrm{T}}] - + \ldots\lVert_{\operatorname{Fr}} \\ - &β‰ˆ\lVertp^{+}X\rVert_{\operatorname{Fr}} = \operatorname{dist}(p, q). + + \ldots\lVert_{\\mathrm{Fr}} \\ + &β‰ˆ\lVertp^{+}X\rVert_{\\mathrm{Fr}} = \operatorname{dist}(p, q). \end{align*} ```` """ @@ -332,13 +330,13 @@ embed(::Symplectic, p, X) = X The Exponential mapping on the Symplectic manifold with the [`RealSymplecticMetric`](@ref) Riemannian metric. -For the point ``p \in \operatorname{Sp}(2n)`` the exponential mapping along the tangent -vector ``X \in T_p\operatorname{Sp}(2n)`` is computed as [WangSunFiori:2018](@cite) +For the point ``p \in \mathrm{Sp}(2n)`` the exponential mapping along the tangent +vector ``X \in T_p\mathrm{Sp}(2n)`` is computed as [WangSunFiori:2018](@cite) ````math \operatorname{exp}_p(X) = p \operatorname{Exp}((p^{-1}X)^{\mathrm{T}}) \operatorname{Exp}(p^{-1}X - (p^{-1}X)^{\mathrm{T}}), ```` -where ``\operatorname{Exp}(\cdot)`` denotes the matrix exponential. +where ``\operatorname{Exp}(β‹…)`` denotes the matrix exponential. """ exp(::Symplectic, ::Any...) @@ -363,28 +361,28 @@ end extended_metric=true) Compute the manifold gradient ``\text{grad}f(p)`` of a scalar function -``f \colon \operatorname{Sp}(2n) \rightarrow ℝ`` at -``p \in \operatorname{Sp}(2n)``. +``f \colon \mathrm{Sp}(2n) β†’ ℝ`` at +``p \in \mathrm{Sp}(2n)``. The element ``\text{grad}f(p)`` is found as the Riesz representer of the differential -``\text{D}f(p) \colon T_p\operatorname{Sp}(2n) \rightarrow ℝ`` w.r.t. +``\text{D}f(p) \colon T_p\mathrm{Sp}(2n) β†’ ℝ`` with respect to the Riemannian metric inner product at ``p`` [Fiori:2011](@cite)]. -That is, ``\text{grad}f(p) \in T_p\operatorname{Sp}(2n)`` solves the relation +That is, ``\text{grad}f(p) \in T_p\mathrm{Sp}(2n)`` solves the relation ````math - g_p(\text{grad}f(p), X) = \text{D}f(p) \quad\forall\; X \in T_p\operatorname{Sp}(2n). + g_p(\text{grad}f(p), X) = \text{D}f(p) \quad\forall\; X \in T_p\mathrm{Sp}(2n). ```` The default behaviour is to first change the representation of the Euclidean gradient from the Euclidean metric to the [`RealSymplecticMetric`](@ref) at ``p``, and then we projecting -the result onto the correct tangent tangent space ``T_p\operatorname{Sp}(2n, ℝ)`` +the result onto the correct tangent tangent space ``T_p\mathrm{Sp}(2n, ℝ)`` w.r.t the Riemannian metric ``g_p`` extended to the entire embedding space. # Arguments: - `extended_metric = true`: If `true`, compute the gradient ``\text{grad}f(p)`` by first changing the representer of the Euclidean gradient of a smooth extension - of ``f``, ``βˆ‡f(p)``, w.r.t. the [`RealSymplecticMetric`](@ref) at ``p`` + of ``f``, ``βˆ‡f(p)``, with respect to the [`RealSymplecticMetric`](@ref) at ``p`` extended to the entire embedding space, before projecting onto the correct - tangent vector space w.r.t. the same extended metric ``g_p``. + tangent vector space with respect to the same extended metric ``g_p``. If `false`, compute the gradient by first projecting ``βˆ‡f(p)`` onto the tangent vector space, before changing the representer in the tangent vector space to comply with the [`RealSymplecticMetric`](@ref). @@ -426,7 +424,7 @@ Compute the canonical Riemannian inner product [`RealSymplecticMetric`](@ref) ````math g_p(X, Y) = \operatorname{tr}((p^{-1}X)^{\mathrm{T}} (p^{-1}Y)) ```` -between the two tangent vectors ``X, Y \in T_p\operatorname{Sp}(2n)``. +between the two tangent vectors ``X, Y \in T_p\mathrm{Sp}(2n)``. """ function inner(M::Symplectic{<:Any,ℝ}, p, X, Y) p_star = inv(M, p) @@ -437,7 +435,7 @@ end symplectic_inverse(A) Given a matrix -``math +```math A ∈ ℝ^{2n Γ— 2k},\quad A = \begin{bmatrix} @@ -449,14 +447,10 @@ Given a matrix the symplectic inverse is defined as: ```math -A^{+} := Q_{2k}^{\mathrm{T}} A^{\mathrm{T}} Q_{2n}, +A^{+} := J_{2k}^{\mathrm{T}} A^{\mathrm{T}} J_{2n}, ``` -where - -```math - Q_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}. -``` +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). The symplectic inverse of A can be expressed explicitly as: @@ -467,7 +461,6 @@ A^{+} = -A_{2, 1}^{\mathrm{T}} & A_{1, 1}^{\mathrm{T}} \end{bmatrix}. ``` - """ function symplectic_inverse(A::AbstractMatrix) N, K = size(A) @@ -496,8 +489,8 @@ end inv(::Symplectic, A) inv!(::Symplectic, A) -Compute the symplectic inverse ``A^+`` of matrix ``A ∈ ℝ^{2n Γ— 2n}``. See [`symplectic_inverse`](@ref) -for details. +Compute the symplectic inverse ``A^+`` of matrix ``A ∈ ℝ^{2n Γ— 2n}``. +See [`symplectic_inverse`](@ref) for details. """ function Base.inv(M::Symplectic{<:Any,ℝ}, A) @@ -530,7 +523,7 @@ end @doc raw""" inv!(M::Symplectic, A) -Compute the symplectic inverse of a suqare matrix A inplace of A +Compute the [`symplectic_inverse`](@ref) of a suqare matrix A inplace of A """ function inv!(M::Symplectic{<:Any,ℝ}, A) return symplectic_inverse!(A) @@ -539,36 +532,23 @@ end @doc raw""" inverse_retract(M::Symplectic, p, q, ::CayleyInverseRetraction) -Compute the Cayley Inverse Retraction ``X = \mathcal{L}_p^{\operatorname{Sp}}(q)`` +Compute the Cayley Inverse Retraction ``X = \mathcal{L}_p^{\mathrm{Sp}}(q)`` such that the Cayley Retraction from ``p`` along ``X`` lands at ``q``, i.e. ``\mathcal{R}_p(X) = q`` [BendokatZimmermann:2021](@cite). -First, recall the definition the standard symplectic matrix -````math -Q = -\begin{bmatrix} - 0 & I \\ --I & 0 -\end{bmatrix} -```` -as well as the symplectic inverse of a matrix ``A``, ``A^{+} = Q^{\mathrm{T}} A^{\mathrm{T}} Q``. - -For ``p, q ∈ \operatorname{Sp}(2n, ℝ)`` then, we can then define the +For ``p, q ∈ \mathrm{Sp}(2n, ℝ)`` then, we can define the inverse cayley retraction as long as the following matrices exist. ````math - U = (I + p^+ q)^{-1}, \quad V = (I + q^+ p)^{-1}. + U = (I + p^+ q)^{-1}, \quad V = (I + q^+ p)^{-1}, ```` -If that is the case, the inverse cayley retration at ``p`` applied to ``q`` is -````math -\mathcal{L}_p^{\operatorname{Sp}}(q) = 2p\bigl(V - U\bigr) + 2\bigl((p + q)U - p\bigr) - ∈ T_p\operatorname{Sp}(2n). -```` +where ``(β‹…)^+`` denotes the [`symplectic_inverse`](@ref). -[BendokatZimmermann:2021](@cite): - > Bendokat, Thomas and Zimmermann, Ralf: - > The real symplectic Stiefel and Grassmann manifolds: metrics, geodesics and applications - > arXiv preprint arXiv:[2108.12447](https://arxiv.org/abs/2108.12447), 2021. +Then inverse cayley retration at ``p`` applied to ``q`` is +```math +\mathcal{L}_p^{\mathrm{Sp}}(q) + = 2p\bigl(V - U\bigr) + 2\bigl((p + q)U - p\bigr) ∈ T_p\mathrm{Sp}(2n). +``` """ inverse_retract(::Symplectic, p, q, ::CayleyInverseRetraction) @@ -591,10 +571,10 @@ is_flat(M::Symplectic) = false manifold_dimension(::Symplectic) Returns the dimension of the symplectic manifold -embedded in ``ℝ^{2n \times 2n}``, i.e. -````math - \operatorname{dim}(\operatorname{Sp}(2n)) = (2n + 1)n. -```` +embedded in ``ℝ^{2nΓ—2n}``, i.e. +```math + \operatorname{dim}(\mathrm{Sp}(2n)) = (2n + 1)n. +``` """ function manifold_dimension(M::Symplectic) n = get_parameter(M.size)[1] @@ -605,98 +585,99 @@ end project(::Symplectic, p, A) project!(::Symplectic, Y, p, A) -Given a point ``p \in \operatorname{Sp}(2n)``, -project an element ``A \in \mathbb{R}^{2n \times 2n}`` onto -the tangent space ``T_p\operatorname{Sp}(2n)`` relative to -the euclidean metric of the embedding ``\mathbb{R}^{2n \times 2n}``. +Given a point ``p \in \mathrm{Sp}(2n)``, +project an element ``A \in ℝ^{2nΓ—2n}`` onto +the tangent space ``T_p\mathrm{Sp}(2n)`` relative to +the euclidean metric of the embedding ``ℝ^{2nΓ—2n}``. -That is, we find the element ``X \in T_p\operatorname{SpSt}(2n, 2k)`` +That is, we find the element ``X \in T_p\operatorname{Sp}(2n)`` which solves the constrained optimization problem ````math - \operatorname{min}_{X \in \mathbb{R}^{2n \times 2n}} \frac{1}{2}\lVert X - A\rVert^2, \quad + \operatorname{min}_{X \in ℝ^{2nΓ—2n}} \frac{1}{2}\lVert X - A\rVert^2, \quad \text{such that}\; - h(X) \colon= X^{\mathrm{T}} Q p + p^{\mathrm{T}} Q X = 0, + h(X) := X^{\mathrm{T}} J_{2n} p + p^{\mathrm{T}} J_{2n} X = 0, ```` -where ``h\colon\mathbb{R}^{2n \times 2n} \rightarrow \operatorname{skew}(2n)`` defines -the restriction of ``X`` onto the tangent space ``T_p\operatorname{SpSt}(2n, 2k)``. +where ``h: ℝ^{2n Γ— 2n} β†’ \operatorname{skew}(2n)`` denotes +the restriction of ``X`` onto the tangent space ``T_p\operatorname{SpSt}(2n, 2k)`` +and ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). """ project(::Symplectic, p, A) function project!(::Symplectic, Y, p, A) - Q = SymplecticMatrix(Y, p, A) - Q_p = Q * p + J = SymplecticMatrix(Y, p, A) + Jp = J * p function h(X) - XT_Q_p = X' * Q_p - return XT_Q_p .- XT_Q_p' + XtJp = X' * Jp + return XtJp .- XtJp' end # Solve for Ξ› (Lagrange mutliplier): pT_p = p' * p # (2k Γ— 2k) Ξ› = sylvester(pT_p, pT_p, h(A) ./ 2) - Y[:, :] = A .- Q_p * (Ξ› .- Ξ›') + Y[:, :] = A .- Jp * (Ξ› .- Ξ›') return Y end @doc raw""" project!(::MetricManifold{𝔽,<:Euclidean,ExtendedSymplecticMetric}, Y, p, X) where {𝔽} -Compute the projection of ``X ∈ R^{2n Γ— 2n}`` onto ``T_p\operatorname{Sp}(2n, ℝ)`` w.r.t. -the Riemannian metric ``g`` [`RealSymplecticMetric`](@ref). +Compute the projection of ``X ∈ R^{2n Γ— 2n}`` onto ``T_p\mathrm{Sp}(2n, ℝ)`` with respect to +the [`RealSymplecticMetric`](@ref) ``g``. + The closed form projection mapping is given by [GaoSonAbsilStykel:2021](@cite) ````math - \operatorname{P}^{T_p\operatorname{Sp}(2n)}_{g_p}(X) = pQ\operatorname{sym}(p^{\mathrm{T}}Q^{\mathrm{T}}X), + \operatorname{P}^{T_p\mathrm{Sp}(2n)}_{g_p}(X) = pJ_{2n}\operatorname{sym}(p^{\mathrm{T}}J_{2n}^{\mathrm{T}}X), ```` -where ``\operatorname{sym}(A) = \frac{1}{2}(A + A^{\mathrm{T}})``. -This function is not exported. +where ``\operatorname{sym}(A) = \frac{1}{2}(A + A^{\mathrm{T}})`` and and ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). """ function project!(::MetricManifold{<:Any,<:Euclidean,ExtendedSymplecticMetric}, Y, p, X) - Q = SymplecticMatrix(p, X) - - pT_QT_X = p' * Q' * X - symmetrized_pT_QT_X = (1 / 2) .* (pT_QT_X + pT_QT_X') + J = SymplecticMatrix(p, X) - Y .= p * Q * (symmetrized_pT_QT_X) + pTJTX = p' * J' * X + sym_pTJTX = (1 / 2) .* (pTJTX + pTJTX') + Y .= p * J * (sym_pTJTX) return Y end @doc raw""" project_normal!(::MetricManifold{𝔽,<:Euclidean,ExtendedSymplecticMetric}, Y, p, X) -Project onto the normal of the tangent space ``(T_p\operatorname{Sp}(2n))^{\perp_g}`` at -a point ``p ∈ \operatorname{Sp}(2n)``, relative to the riemannian metric +Project onto the normal of the tangent space ``(T_p\mathrm{Sp}(2n))^{\perp_g}`` at +a point ``p ∈ \mathrm{Sp}(2n)``, relative to the riemannian metric ``g`` [`RealSymplecticMetric`](@ref). + That is, ````math -(T_p\operatorname{Sp}(2n))^{\perp_g} = \{Y \in \mathbb{R}^{2n \times 2n} : - g_p(Y, X) = 0 \;\forall\; X \in T_p\operatorname{Sp}(2n)\}. +(T_p\mathrm{Sp}(2n))^{\perp_g} + = \{Y ∈ ℝ^{2n Γ— 2n} : g_p(Y, X) = 0 \test{ for all } X \in T_p\mathrm{Sp}(2n)\}. ```` The closed form projection operator onto the normal space is given by [GaoSonAbsilStykel:2021](@cite) ````math -\operatorname{P}^{(T_p\operatorname{Sp}(2n))\perp}_{g_p}(X) = pQ\operatorname{skew}(p^{\mathrm{T}}Q^{\mathrm{T}}X), +\operatorname{P}^{(T_p\mathrm{Sp}(2n))\perp}_{g_p}(X) = pJ_{2n}\operatorname{skew}(p^{\mathrm{T}}J_{2n}^{\mathrm{T}}X), ```` -where ``\operatorname{skew}(A) = \frac{1}{2}(A - A^{\mathrm{T}})``. +where ``\operatorname{skew}(A) = \frac{1}{2}(A - A^{\mathrm{T}})`` +and ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). + This function is not exported. """ function project_normal!( - M::MetricManifold{𝔽,<:Euclidean,ExtendedSymplecticMetric}, + ::MetricManifold{𝔽,<:Euclidean,ExtendedSymplecticMetric}, Y, p, X, ) where {𝔽} - Q = SymplecticMatrix(p, X) - - pT_QT_X = p' * Q' * X - skew_pT_QT_X = (1 / 2) .* (pT_QT_X .- pT_QT_X') - - Y .= p * Q * skew_pT_QT_X + J = SymplecticMatrix(p, X) + pTJTX = p' * J' * X + skew_pTJTX = (1 / 2) .* (pTJTX .- pTJTX') + Y .= p * J * skew_pTJTX return Y end @@ -704,23 +685,25 @@ end rand(::SymplecticStiefel; vector_at=nothing, hamiltonian_norm = (vector_at === nothing ? 1/2 : 1.0)) -Generate a random point on ``\operatorname{Sp}(2n)`` or a random -tangent vector ``X \in T_p\operatorname{Sp}(2n)`` if `vector_at` is set to -a point ``p \in \operatorname{Sp}(2n)``. +Generate a random point on ``\mathrm{Sp}(2n)`` or a random +tangent vector ``X \in T_p\mathrm{Sp}(2n)`` if `vector_at` is set to +a point ``p \in \mathrm{Sp}(2n)``. -A random point on ``\operatorname{Sp}(2n)`` is constructed by generating a +A random point on ``\mathrm{Sp}(2n)`` is constructed by generating a random Hamiltonian matrix ``Ξ© \in \mathfrak{sp}(2n,F)`` with norm `hamiltonian_norm`, and then transforming it to a symplectic matrix by applying the Cayley transform -````math - \operatorname{cay}\colon \mathfrak{sp}(2n,F) \rightarrow \operatorname{Sp}(2n), - \; \Omega \mapsto (I - \Omega)^{-1}(I + \Omega). -```` -To generate a random tangent vector in ``T_p\operatorname{Sp}(2n)``, this code employs the + +```math + \operatorname{cay}: \mathfrak{sp}(2n,F) β†’ \mathrm{Sp}(2n), + \ \Omega \mapsto (I - \Omega)^{-1}(I + \Omega). +``` + +To generate a random tangent vector in ``T_p\mathrm{Sp}(2n)``, this code employs the second tangent vector space parametrization of [Symplectic](@ref). It first generates a random symmetric matrix ``S`` by `S = randn(2n, 2n)` and then symmetrizes it as `S = S + S'`. Then ``S`` is normalized to have Frobenius norm of `hamiltonian_norm` -and `X = pQS` is returned, where `Q` is the [`SymplecticMatrix`](@ref). +and `X = pJS` is returned, where `J` is the [`SymplecticMatrix`](@ref). """ function Random.rand( M::Symplectic; @@ -741,8 +724,7 @@ function random_vector(M::Symplectic, p::AbstractMatrix; symmetric_norm=1.0) S = randn(2n, 2n) S .= (S + S') S *= symmetric_norm / norm(S) - Q = SymplecticMatrix(p) - lmul!(Q, S) + lmul!(SymplecticMatrix(p), S) return p * S end @@ -761,24 +743,12 @@ end retract(::Symplectic, p, X, ::CayleyRetraction) retract!(::Symplectic, q, p, X, ::CayleyRetraction) -Compute the Cayley retraction on ``p ∈ \operatorname{Sp}(2n, ℝ)`` in -the direction of tangent vector ``X ∈ T_p\operatorname{Sp}(2n, ℝ)``, +Compute the Cayley retraction on ``p ∈ \mathrm{Sp}(2n, ℝ)`` in +the direction of tangent vector ``X ∈ T_p\mathrm{Sp}(2n, ℝ)``, as defined in by Birtea et al in proposition 2 [BirteaCaşuComΔƒnescu:2020](@cite). -Using the symplectic inverse of a matrix ``A \in ℝ^{2n \times 2n}``, -`` -A^{+} := Q_{2n}^{\mathrm{T}} A^{\mathrm{T}} Q_{2n} -`` -where -````math -Q_{2n} = -\begin{bmatrix} -0_n & I_n \\ - -I_n & 0_n -\end{bmatrix}, -```` -the retraction -``\mathcal{R}\colon T\operatorname{Sp}(2n) \rightarrow \operatorname{Sp}(2n)`` +Using the [symplectic_inverse](@ref) ``A^+`` of a matrix ``A \in ℝ^{2nΓ—2n}`` +the retraction ``\mathcal{R}: T\mathrm{Sp}(2n) β†’ \mathrm{Sp}(2n)`` is defined pointwise as ````math \begin{align*} @@ -813,12 +783,12 @@ end symplectic_inverse_times(::Symplectic, p, q) symplectic_inverse_times!(::Symplectic, A, p, q) -Directly compute the symplectic inverse of ``p \in \operatorname{Sp}(2n)``, -multiplied with ``q \in \operatorname{Sp}(2n)``. +Directly compute the symplectic inverse of ``p \in \mathrm{Sp}(2n)``, +multiplied with ``q \in \mathrm{Sp}(2n)``. That is, this function efficiently computes -``p^+q = (Q_{2n}p^{\mathrm{T}}Q_{2n})q \in ℝ^{2n \times 2n}``, -where ``Q_{2n}`` is the [`SymplecticMatrix`](@ref) -of size ``2n \times 2n``. +``p^+q = (J_{2n}p^{\mathrm{T}}J_{2n})q ∈ ℝ^{2nΓ—2n}``, +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). + """ function symplectic_inverse_times(M::Symplectic, p, q) A = similar(p) @@ -851,46 +821,46 @@ function symplectic_inverse_times!(M::Symplectic, A, p, q) return A end -ndims(Q::SymplecticMatrix) = 2 -copy(Q::SymplecticMatrix) = SymplecticMatrix(copy(Q.Ξ»)) +ndims(J::SymplecticMatrix) = 2 +copy(J::SymplecticMatrix) = SymplecticMatrix(copy(J.Ξ»)) Base.eltype(::SymplecticMatrix{T}) where {T} = T -function Base.convert(::Type{SymplecticMatrix{T}}, Q::SymplecticMatrix) where {T} - return SymplecticMatrix(convert(T, Q.Ξ»)) +function Base.convert(::Type{SymplecticMatrix{T}}, J::SymplecticMatrix) where {T} + return SymplecticMatrix(convert(T, J.Ξ»)) end -function Base.show(io::IO, Q::SymplecticMatrix) - s = "$(Q.Ξ»)" +function Base.show(io::IO, J::SymplecticMatrix) + s = "$(J.Ξ»)" if occursin(r"\w+\s*[\+\-]\s*\w+", s) s = "($s)" end - return print(io, typeof(Q), "(): $(s)*[0 I; -I 0]") + return print(io, typeof(J), "(): $(s)*[0 I; -I 0]") end -(Base.:-)(Q::SymplecticMatrix) = SymplecticMatrix(-Q.Ξ») +(Base.:-)(J::SymplecticMatrix) = SymplecticMatrix(-J.Ξ») -function (Base.:^)(Q::SymplecticMatrix, n::Integer) +function (Base.:^)(J::SymplecticMatrix, n::Integer) return ifelse( n % 2 == 0, - UniformScaling((-1)^(div(n, 2)) * (Q.Ξ»)^n), - SymplecticMatrix((-1)^(div(n - 1, 2)) * (Q.Ξ»)^n), + UniformScaling((-1)^(div(n, 2)) * (J.Ξ»)^n), + SymplecticMatrix((-1)^(div(n - 1, 2)) * (J.Ξ»)^n), ) end -(Base.:*)(x::Number, Q::SymplecticMatrix) = SymplecticMatrix(x * Q.Ξ») -(Base.:*)(Q::SymplecticMatrix, x::Number) = SymplecticMatrix(x * Q.Ξ») -function (Base.:*)(Q1::SymplecticMatrix, Q2::SymplecticMatrix) - return LinearAlgebra.UniformScaling(-Q1.Ξ» * Q2.Ξ») +(Base.:*)(x::Number, J::SymplecticMatrix) = SymplecticMatrix(x * J.Ξ») +(Base.:*)(J::SymplecticMatrix, x::Number) = SymplecticMatrix(x * J.Ξ») +function (Base.:*)(J::SymplecticMatrix, K::SymplecticMatrix) + return LinearAlgebra.UniformScaling(-J.Ξ» * K.Ξ») end -Base.transpose(Q::SymplecticMatrix) = -Q -Base.adjoint(Q::SymplecticMatrix) = SymplecticMatrix(-conj(Q.Ξ»)) -Base.inv(Q::SymplecticMatrix) = SymplecticMatrix(-(1 / Q.Ξ»)) +Base.transpose(J::SymplecticMatrix) = -J +Base.adjoint(J::SymplecticMatrix) = SymplecticMatrix(-conj(J.Ξ»)) +Base.inv(J::SymplecticMatrix) = SymplecticMatrix(-(1 / J.Ξ»)) -(Base.:+)(Q1::SymplecticMatrix, Q2::SymplecticMatrix) = SymplecticMatrix(Q1.Ξ» + Q2.Ξ») -(Base.:-)(Q1::SymplecticMatrix, Q2::SymplecticMatrix) = SymplecticMatrix(Q1.Ξ» - Q2.Ξ») +(Base.:+)(J::SymplecticMatrix, K::SymplecticMatrix) = SymplecticMatrix(J.Ξ» + K.Ξ») +(Base.:-)(J::SymplecticMatrix, K::SymplecticMatrix) = SymplecticMatrix(J.Ξ» - K.Ξ») -(Base.:+)(Q::SymplecticMatrix, p::AbstractMatrix) = p + Q -function (Base.:+)(p::AbstractMatrix, Q::SymplecticMatrix) +(Base.:+)(J::SymplecticMatrix, p::AbstractMatrix) = p + J +function (Base.:+)(p::AbstractMatrix, J::SymplecticMatrix) # When we are adding, the Matrices must match in size: two_n, two_k = size(p) if (two_n % 2 != 0) || (two_n != two_k) @@ -904,19 +874,19 @@ function (Base.:+)(p::AbstractMatrix, Q::SymplecticMatrix) n = div(two_n, 2) # Allocate new memory: - TS = typeof(one(eltype(p)) + one(eltype(Q))) + TS = typeof(one(eltype(p)) + one(eltype(J))) out = copyto!(similar(p, TS), p) - add_scaled_I!(view(out, 1:n, (n + 1):(2n)), Q.Ξ») - add_scaled_I!(view(out, (n + 1):(2n), 1:n), -Q.Ξ») + add_scaled_I!(view(out, 1:n, (n + 1):(2n)), J.Ξ») + add_scaled_I!(view(out, (n + 1):(2n), 1:n), -J.Ξ») return out end # Binary minus: -(Base.:-)(Q::SymplecticMatrix, p::AbstractMatrix) = Q + (-p) -(Base.:-)(p::AbstractMatrix, Q::SymplecticMatrix) = p + (-Q) +(Base.:-)(J::SymplecticMatrix, p::AbstractMatrix) = J + (-p) +(Base.:-)(p::AbstractMatrix, J::SymplecticMatrix) = p + (-J) -function (Base.:*)(Q::SymplecticMatrix, p::AbstractVecOrMat) +function (Base.:*)(J::SymplecticMatrix, p::AbstractVecOrMat) two_n = size(p)[1] if two_n % 2 != 0 throw(ArgumentError("'p' must have even row dimension, was: $(two_n) != 2n.")) @@ -924,17 +894,17 @@ function (Base.:*)(Q::SymplecticMatrix, p::AbstractVecOrMat) n = div(two_n, 2) # Allocate new memory: - TS = typeof(one(eltype(p)) + one(eltype(Q))) - Qp = similar(p, TS) + TS = typeof(one(eltype(p)) + one(eltype(J))) + Jp = similar(p, TS) - # Perform left mulitply by Ξ»*Q: - mul!((@inbounds view(Qp, 1:n, :)), Q.Ξ», @inbounds view(p, (n + 1):lastindex(p, 1), :)) - mul!((@inbounds view(Qp, (n + 1):lastindex(Qp, 1), :)), -Q.Ξ», @inbounds view(p, 1:n, :)) + # Perform left mulitply by Ξ»*J: + mul!((@inbounds view(Jp, 1:n, :)), J.Ξ», @inbounds view(p, (n + 1):lastindex(p, 1), :)) + mul!((@inbounds view(Jp, (n + 1):lastindex(Jp, 1), :)), -J.Ξ», @inbounds view(p, 1:n, :)) - return Qp + return Jp end -function (Base.:*)(p::AbstractMatrix, Q::SymplecticMatrix) +function (Base.:*)(p::AbstractMatrix, J::SymplecticMatrix) two_k = size(p)[2] if two_k % 2 != 0 throw(ArgumentError("'p' must have even column dimension, was: $(two_k) != 2k.")) @@ -942,16 +912,16 @@ function (Base.:*)(p::AbstractMatrix, Q::SymplecticMatrix) k = div(two_k, 2) # Allocate new memory: - TS = typeof(one(eltype(p)) + one(eltype(Q))) - pQ = similar(p, TS) + TS = typeof(one(eltype(p)) + one(eltype(J))) + pJ = similar(p, TS) - # Perform right mulitply by Ξ»*Q: - mul!((@inbounds view(pQ, :, 1:k)), -Q.Ξ», @inbounds view(p, :, (k + 1):lastindex(p, 2))) - mul!((@inbounds view(pQ, :, (k + 1):lastindex(pQ, 2))), Q.Ξ», @inbounds view(p, :, 1:k)) - return pQ + # Perform right mulitply by Ξ»*J: + mul!((@inbounds view(pJ, :, 1:k)), -J.Ξ», @inbounds view(p, :, (k + 1):lastindex(p, 2))) + mul!((@inbounds view(pJ, :, (k + 1):lastindex(pJ, 2))), J.Ξ», @inbounds view(p, :, 1:k)) + return pJ end -function LinearAlgebra.lmul!(Q::SymplecticMatrix, p::AbstractVecOrMat) +function LinearAlgebra.lmul!(J::SymplecticMatrix, p::AbstractVecOrMat) # Perform left multiplication by a symplectic matrix, # overwriting the matrix p in place: two_n = size(p)[1] @@ -962,17 +932,17 @@ function LinearAlgebra.lmul!(Q::SymplecticMatrix, p::AbstractVecOrMat) half_row_p = copy(@inbounds view(p, 1:n, :)) - mul!((@inbounds view(p, 1:n, :)), Q.Ξ», @inbounds view(p, (n + 1):lastindex(p, 1), :)) + mul!((@inbounds view(p, 1:n, :)), J.Ξ», @inbounds view(p, (n + 1):lastindex(p, 1), :)) mul!( (@inbounds view(p, (n + 1):lastindex(p, 1), :)), - -Q.Ξ», + -J.Ξ», @inbounds view(half_row_p, :, :) ) return p end -function LinearAlgebra.rmul!(p::AbstractMatrix, Q::SymplecticMatrix) +function LinearAlgebra.rmul!(p::AbstractMatrix, J::SymplecticMatrix) # Perform right multiplication by a symplectic matrix, # overwriting the matrix p in place: two_k = size(p)[2] @@ -983,18 +953,18 @@ function LinearAlgebra.rmul!(p::AbstractMatrix, Q::SymplecticMatrix) half_col_p = copy(@inbounds view(p, :, 1:k)) - mul!((@inbounds view(p, :, 1:k)), -Q.Ξ», @inbounds view(p, :, (k + 1):lastindex(p, 2))) + mul!((@inbounds view(p, :, 1:k)), -J.Ξ», @inbounds view(p, :, (k + 1):lastindex(p, 2))) mul!( (@inbounds view(p, :, (k + 1):lastindex(p, 2))), - Q.Ξ», + J.Ξ», @inbounds view(half_col_p, :, :) ) return p end -function LinearAlgebra.mul!(A::AbstractVecOrMat, Q::SymplecticMatrix, p::AbstractVecOrMat) +function LinearAlgebra.mul!(A::AbstractVecOrMat, J::SymplecticMatrix, p::AbstractVecOrMat) size_p = size(p) two_n = size_p[1] if two_n % 2 != 0 @@ -1006,13 +976,13 @@ function LinearAlgebra.mul!(A::AbstractVecOrMat, Q::SymplecticMatrix, p::Abstrac # k == 0 means we're multiplying with a vector: @boundscheck k == 0 ? checkbounds(A, 1:(2n), 1) : checkbounds(A, 1:(2n), 1:(2k)) - # Perform left multiply by Ξ»*Q: - mul!((@inbounds view(A, 1:n, :)), Q.Ξ», @inbounds view(p, (n + 1):lastindex(p, 1), :)) - mul!((@inbounds view(A, (n + 1):lastindex(A, 1), :)), -Q.Ξ», @inbounds view(p, 1:n, :)) + # Perform left multiply by Ξ»*J: + mul!((@inbounds view(A, 1:n, :)), J.Ξ», @inbounds view(p, (n + 1):lastindex(p, 1), :)) + mul!((@inbounds view(A, (n + 1):lastindex(A, 1), :)), -J.Ξ», @inbounds view(p, 1:n, :)) return A end -function LinearAlgebra.mul!(A::AbstractVecOrMat, p::AbstractMatrix, Q::SymplecticMatrix) +function LinearAlgebra.mul!(A::AbstractVecOrMat, p::AbstractMatrix, J::SymplecticMatrix) two_n, two_k = size(p) if two_k % 2 != 0 throw(ArgumentError("'p' must have even col dimension, was: $(two_k) != 2k.")) @@ -1023,9 +993,9 @@ function LinearAlgebra.mul!(A::AbstractVecOrMat, p::AbstractMatrix, Q::Symplecti # n == 0 means we're multiplying with a vector: @boundscheck n == 0 ? checkbounds(A, 1, 1:(2k)) : checkbounds(A, 1:(2n), 1:(2k)) - # Perform right multiply by Ξ»*Q: - mul!((@inbounds view(A, :, 1:k)), -Q.Ξ», @inbounds view(p, :, (k + 1):lastindex(p, 2))) - mul!((@inbounds view(A, :, (k + 1):lastindex(A, 2))), Q.Ξ», @inbounds view(p, :, 1:k)) + # Perform right multiply by Ξ»*J: + mul!((@inbounds view(A, :, 1:k)), -J.Ξ», @inbounds view(p, :, (k + 1):lastindex(p, 2))) + mul!((@inbounds view(A, :, (k + 1):lastindex(A, 2))), J.Ξ», @inbounds view(p, :, 1:k)) return A end diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 1be5f639d2..63a485b227 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -85,11 +85,11 @@ g^{\mathrm{SpGr}_p(X,Y) = \operatorname{tr}\bigl( (p^{\mathrm{T}p)^{-1}X^{\mathrm{T}}(I_{2n} - pp^+)Y \bigr), ``` -where ``I_{2n}`` denotes the identity matrix and ``(\cdot)^+`` the [`symplectic_inverse`](@ref). +where ``I_{2n}`` denotes the identity matrix and ``(β‹…)^+`` the [`symplectic_inverse`](@ref). """ function inner(M::SymplecticGrassmann, p, X, Y) n, k = get_parameter(M.size) - Q = SymplecticMatrix(p, X, Y) # in BZ21 also J + J = SymplecticMatrix(p, X, Y) # in BZ21 also J # Procompute lu(p'p) since we solve a^{-1}* 3 times a = lu(p' * p) # note that p'p is symmetric, thus so is its inverse c=a^{-1} # we split the original trace into two one with I -> (X'Yc) diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 19a84c2ba3..d539155ebd 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -5,11 +5,11 @@ The symplectic Stiefel manifold consists of all ``2n Γ— 2k, n β‰₯ k`` matrices satisfying the requirement ````math -\operatorname{SpSt}(2n, 2k, ℝ) +\mathrm{SpSt}(2n, 2k, ℝ) := \bigl\{ p ∈ ℝ^{2n Γ— 2n} \ \big| \ p^{\mathrm{T}}J_{2n}p = J_{2k} \bigr\}, ```` -where +where ``J_{2n}`` denotes the [`SymplecticMatrix`](@ref) ````math J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}. @@ -17,19 +17,19 @@ J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}. The symplectic Stiefel tangent space at ``p`` can be parametrized as [BendokatZimmermann:2021](@cite) -````math +```math \begin{align*} - T_p\operatorname{SpSt}(2n, 2k) - &= \{X ∈ \mathbb{R}^{2n Γ— 2k} ∣ p^{T}Q_{2n}X + X^{T}Q_{2n}p = 0 \}, \\ + T_p\mathrm{SpSt}(2n, 2k) + &= \{X ∈ ℝ^{2n Γ— 2k} ∣ p^{T}J_{2n}X + X^{T}J_{2n}p = 0 \}, \\ &= \{X = pΞ© + p^sB \mid Ξ© ∈ ℝ^{2k Γ— 2k}, Ξ©^+ = -Ξ©, \\ - &\qquad & p^s ∈ \operatorname{SpSt}(2n, 2(n- k)), B ∈ ℝ^{2(n-k) Γ— 2k}, \}, + &\qquad & p^s ∈ \mathrm{SpSt}(2n, 2(n- k)), B ∈ ℝ^{2(n-k) Γ— 2k}, \}, \end{align*} -```` +``` -where ``Ξ© \in \mathfrak{sp}(2n,F)`` is [`Hamiltonian`](@ref) and ``p^s`` means +where ``Ξ© ∈ \mathfrak{sp}(2n,F)`` is [`Hamiltonian`](@ref) and ``p^s`` means the symplectic complement of ``p`` s.t. ``p^{+}p^{s} = 0``. -Here ``p^+`` denotes the symplecic inverse ``p^+ := J_{2k}^{\mathrm{T}}p^{\mathrm{T}}J_{2n}``. +Here ``p^+`` denotes the [`symplectic_inverse`](@ref). You can also use [`StiefelPoint`](@ref) and [`StiefelTVector`](@ref) with this manifold, they are equivalent to using arrays. @@ -37,11 +37,11 @@ they are equivalent to using arrays. # Constructor SymplecticStiefel(2n::Int, 2k::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) -Generate the (real-valued) symplectic Stiefel manifold of ``2n \times 2k`` -matrices which span a ``2k`` dimensional symplectic subspace of ``ℝ^{2n \times 2n}``. +Generate the (real-valued) symplectic Stiefel manifold of ``2nΓ—2k`` +matrices which span a ``2k`` dimensional symplectic subspace of ``ℝ^{2nΓ—2n}``. The constructor for the [`SymplecticStiefel`](@ref) manifold accepts the even column dimension ``2n`` and an even number of columns ``2k`` for -the real symplectic Stiefel manifold with elements ``p \in ℝ^{2n Γ— 2k}``. +the real symplectic Stiefel manifold with elements ``p ∈ ℝ^{2n Γ— 2k}``. """ struct SymplecticStiefel{T,𝔽} <: AbstractDecoratorManifold{𝔽} size::T @@ -75,7 +75,7 @@ ManifoldsBase.default_retraction_method(::SymplecticStiefel) = CayleyRetraction( canonical_project!(::SymplecticStiefel, p, p_Sp) Define the canonical projection from ``\operatorname{Sp}(2n, 2n)`` onto -``\operatorname{SpSt}(2n, 2k)``, by projecting onto the first ``k`` columns +``\mathrm{SpSt}(2n, 2k)``, by projecting onto the first ``k`` columns and the ``n + 1``'th onto the ``n + k``'th columns [BendokatZimmermann:2021](@cite). It is assumed that the point ``p`` is on ``\operatorname{Sp}(2n, 2n)``. @@ -97,19 +97,8 @@ end check_point(M::SymplecticStiefel, p; kwargs...) Check whether `p` is a valid point on the [`SymplecticStiefel`](@ref), -``\operatorname{SpSt}(2n, 2k)`` manifold. -That is, the point has the right [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and ``p^{+}p`` is -(approximately) the identity, -where for ``A \in \mathbb{R}^{2n \times 2k}``, -``A^{+} = Q_{2k}^{\mathrm{T}}A^{\mathrm{T}}Q_{2n}`` is the symplectic inverse, with -````math -Q_{2n} = -\begin{bmatrix} -0_n & I_n \\ - -I_n & 0_n -\end{bmatrix}. -```` -The tolerance can be set with `kwargs...` (e.g. `atol = 1.0e-14`). +``\mathrm{SpSt}(2n, 2k)`` manifold, that is ``p^{+}p`` is the identity, +``(β‹…)^+`` denotes the [`symplectic_inverse`](@ref). """ function check_point(M::SymplecticStiefel{<:Any,ℝ}, p::T; kwargs...) where {T} # Perform check that the matrix lives on the real symplectic manifold: @@ -129,23 +118,11 @@ end check_vector(M::Symplectic, p, X; kwargs...) Checks whether `X` is a valid tangent vector at `p` on the [`SymplecticStiefel`](@ref), -``\operatorname{SpSt}(2n, 2k)`` manifold. First recall the definition of the symplectic -inverse for ``A \in \mathbb{R}^{2n \times 2k}``, -``A^{+} = Q_{2k}^{\mathrm{T}}A^{\mathrm{T}}Q_{2n}`` is the symplectic inverse, with -````math - Q_{2n} = - \begin{bmatrix} - 0_n & I_n \\ - -I_n & 0_n -\end{bmatrix}. -```` -The we check that ``H = p^{+}X \in 𝔀_{2k}``, where ``𝔀`` -is the Lie Algebra of the symplectic group ``\operatorname{Sp}(2k)``, -characterized as [BendokatZimmermann:2021](@cite), -````math - 𝔀_{2k} = \{H \in ℝ^{2k \times 2k} \;|\; H^+ = -H \}. -```` -The tolerance can be set with `kwargs...` (e.g. `atol = 1.0e-14`). +``\mathrm{SpSt}(2n, 2k)`` manifold. + +The check consists of verifying that ``H = p^{+}X ∈ 𝔀_{2k}``, where ``𝔀`` +is the Lie Algebra of the symplectic group ``\operatorname{Sp}(2k)``, that is +the set of [`HamiltonianMatrices`])(@ref), where ``(β‹…)^+`` denotes the [`symplectic_inverse`](@ref). """ check_vector(::SymplecticStiefel, ::Any...) @@ -170,102 +147,105 @@ end exp!(M::SymplecticStiefel, q, p, X) Compute the exponential mapping -````math - \operatorname{exp}\colon T\operatorname{SpSt}(2n, 2k) - \rightarrow \operatorname{SpSt}(2n, 2k) -```` -at a point ``p \in \operatorname{SpSt}(2n, 2k)`` -in the direction of ``X \in T_p\operatorname{SpSt}(2n, 2k)``. +```math + \exp\colon T\mathrm{SpSt}(2n, 2k) β†’ \mathrm{SpSt}(2n, 2k) +``` +at a point ``p ∈ \mathrm{SpSt}(2n, 2k)`` +in the direction of ``X ∈ T_p\mathrm{SpSt}(2n, 2k)``. The tangent vector ``X`` can be written in the form ``X = \bar{\Omega}p`` [BendokatZimmermann:2021](@cite), with -````math - \bar{\Omega} = X (p^{\mathrm{T}}p)^{-1}p^{\mathrm{T}} - + Q_{2n}p(p^{\mathrm{T}}p)^{-1}X^{\mathrm{T}}(I_{2n} - Q_{2n}^{\mathrm{T}}p(p^{\mathrm{T}}p)^{-1}p^{\mathrm{T}}Q_{2n})Q_{2n} - \in ℝ^{2n \times 2n}, -```` -where ``Q_{2n}`` is the [`SymplecticMatrix`](@ref). Using this expression for ``X``, + +```math + \bar{\Omega} = X (p^{\mathrm{T}}p)^{-1}p^{\mathrm{T}} + + J_{2n}p(p^{\mathrm{T}}p)^{-1}X^{\mathrm{T}}(I_{2n} + - J_{2n}^{\mathrm{T}}p(p^{\mathrm{T}}p)^{-1}p^{\mathrm{T}}J_{2n})J_{2n} + ∈ ℝ^{2nΓ—2n}, +``` + +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). + +Using this expression for ``X``, the exponential mapping can be computed as + ````math - \operatorname{exp}_p(X) = \operatorname{Exp}([\bar{\Omega} - \bar{\Omega}^{\mathrm{T}}]) - \operatorname{Exp}(\bar{\Omega}^{\mathrm{T}})p, + \exp_p(X) = \operatorname{Exp}([\bar{\Omega} - \bar{\Omega}^{\mathrm{T}}]) + \operatorname{Exp}(\bar{\Omega}^{\mathrm{T}})p, ```` -where ``\operatorname{Exp}(\cdot)`` denotes the matrix exponential. +where ``\operatorname{Exp}(β‹…)`` denotes the matrix exponential. Computing the above mapping directly however, requires taking matrix exponentials -of two ``2n \times 2n`` matrices, which is computationally expensive when ``n`` +of two ``2nΓ—2n`` matrices, which is computationally expensive when ``n`` increases. Therefore we instead follow [BendokatZimmermann:2021](@cite) who express the above exponential mapping in a way which only requires taking matrix exponentials -of an ``8k \times 8k`` matrix and a ``4k \times 4k`` matrix. +of an ``8kΓ—8k`` matrix and a ``4kΓ—4k`` matrix. To this end, first define -````math -\bar{A} = Q_{2k}p^{\mathrm{T}}X(p^{\mathrm{T}}p)^{-1}Q_{2k} + - (p^{\mathrm{T}}p)^{-1}X^{\mathrm{T}}(p - Q_{2n}^{\mathrm{T}}p(p^{\mathrm{T}}p)^{-1}Q_{2k}) \in ℝ^{2k \times 2k}, -```` +```math +\bar{A} = J_{2k}p^{\mathrm{T}}X(p^{\mathrm{T}}p)^{-1}J_{2k} + + (p^{\mathrm{T}}p)^{-1}X^{\mathrm{T}}(p - J_{2n}^{\mathrm{T}}p(p^{\mathrm{T}}p)^{-1}J_{2k}) ∈ ℝ^{2kΓ—2k}, +``` + and -````math -\bar{H} = (I_{2n} - pp^+)Q_{2n}X(p^{\mathrm{T}}p)^{-1}Q_{2k} \in ℝ^{2n \times 2k}. -```` + +```math +\bar{H} = (I_{2n} - pp^+)J_{2n}X(p^{\mathrm{T}}p)^{-1}J_{2k} ∈ ℝ^{2nΓ—2k}. +``` + We then let ``\bar{\Delta} = p\bar{A} + \bar{H}``, and define the matrices -````math + +```math Ξ³ = \left[\left(I_{2n} - \frac{1}{2}pp^+\right)\bar{\Delta} \quad - -p \right] \in ℝ^{2n \times 4k}, -```` + -p \right] ∈ ℝ^{2nΓ—4k}, +``` and ````math - Ξ» = \left[Q_{2n}^{\mathrm{T}}pQ_{2k} \quad + Ξ» = \left[J_{2n}^{\mathrm{T}}pJ_{2k} \quad \left(\bar{\Delta}^+\left(I_{2n} - - \frac{1}{2}pp^+\right)\right)^{\mathrm{T}}\right] \in ℝ^{2n \times 4k}. + - \frac{1}{2}pp^+\right)\right)^{\mathrm{T}}\right] ∈ ℝ^{2nΓ—4k}. ```` With the above defined matrices it holds that ``\bar{\Omega} = λγ^{\mathrm{T}}``. As a last preliminary step, concatenate ``Ξ³`` and ``Ξ»`` to define the matrices -``Ξ“ = [Ξ» \quad -Ξ³] \in ℝ^{2n \times 8k}`` and -``Ξ› = [Ξ³ \quad Ξ»] \in ℝ^{2n \times 8k}``. +``Ξ“ = [Ξ» \quad -Ξ³] ∈ ℝ^{2nΓ—8k}`` and +``Ξ› = [Ξ³ \quad Ξ»] ∈ ℝ^{2nΓ—8k}``. With these matrix constructions done, we can compute the exponential mapping as -````math - \operatorname{exp}_p(X) = - Ξ“ \operatorname{Exp}(ΛΓ^{\mathrm{T}}) - \begin{bmatrix} - 0_{4k} \\ - I_{4k} - \end{bmatrix} - \operatorname{Exp}(λγ^{\mathrm{T}}) - \begin{bmatrix} - 0_{2k} \\ - I_{2k} - \end{bmatrix}. -```` +```math + \exp_p(X) = Ξ“ \operatorname{Exp}(ΛΓ^{\mathrm{T}}) + \begin{bmatrix} 0_{4k} \\ I_{4k} \end{bmatrix} + \operatorname{Exp}(λγ^{\mathrm{T}}) + \begin{bmatrix} 0_{2k} \\ I_{2k} \end{bmatrix}. +``` + which only requires computing the matrix exponentials of -``ΛΓ^{\mathrm{T}} \in ℝ^{8k \times 8k}`` and ``λγ^{\mathrm{T}} \in ℝ^{4k \times 4k}``. +``ΛΓ^{\mathrm{T}} ∈ ℝ^{8kΓ—8k}`` and ``λγ^{\mathrm{T}} ∈ ℝ^{4kΓ—4k}``. """ exp(::SymplecticStiefel, p, X) function exp!(M::SymplecticStiefel, q, p, X) n, k = get_parameter(M.size) - Q = SymplecticMatrix(p, X) + J = SymplecticMatrix(p, X) pT_p = lu(p' * p) # ∈ ℝ^{2k Γ— 2k} C = pT_p \ X' # ∈ ℝ^{2k Γ— 2n} # Construct A-bar: - # First A-term: Q * (p^{\mathrm{T}} * C^{\mathrm{T}}) * Q - A_bar = rmul!(lmul!(Q, (p' * C')), Q) + # First A-term: J * (p^{\mathrm{T}} * C^{\mathrm{T}}) * J + A_bar = rmul!(lmul!(J, (p' * C')), J) A_bar .+= C * p # Second A-term, use C-memory: - rmul!(C, Q') # C*Q^{\mathrm{T}} -> C - C_QT = C + rmul!(C, J') # C*J^{\mathrm{T}} -> C + C_JT = C - # Subtract C*Q^{\mathrm{T}}*p*(pT_p)^{-1}*Q: + # Subtract C*J^{\mathrm{T}}*p*(pT_p)^{-1}*J: # A_bar is "star-skew symmetric" (A^+ = -A). - A_bar .-= rmul!((C_QT * p) / pT_p, Q) + A_bar .-= rmul!((C_JT * p) / pT_p, J) # Construct H_bar: - # First H-term: Q * (C_QT * Q)' * Q -> Q * C' * Q = Q * (X / pT_p) * Q - H_bar = rmul!(lmul!(Q, rmul!(C_QT, Q)'), Q) + # First H-term: J * (C_JT * J)' * J -> J * C' * J = J * (X / pT_p) * J + H_bar = rmul!(lmul!(J, rmul!(C_JT, J)'), J) # Subtract second H-term: H_bar .-= p * symplectic_inverse_times(M, p, H_bar) @@ -278,8 +258,8 @@ function exp!(M::SymplecticStiefel, q, p, X) Ξ³_1 = Ξ”_bar - (1 / 2) .* p * symplectic_inverse_times(M, p, Ξ”_bar) Ξ³ = [Ξ³_1 -p] # ∈ ℝ^{2n Γ— 4k} - Ξ”_bar_star = rmul!(Q' * Ξ”_bar', Q) - Ξ»_1 = lmul!(Q', p * Q) + Ξ”_bar_star = rmul!(J' * Ξ”_bar', J) + Ξ»_1 = lmul!(J', p * J) Ξ»_2 = (Ξ”_bar_star .- (1 / 2) .* (Ξ”_bar_star * p) * Ξ»_1')' Ξ» = [Ξ»_1 Ξ»_2] # ∈ ℝ^{2n Γ— 4k} @@ -315,22 +295,22 @@ end @doc raw""" inner(M::SymplecticStiefel, p, X. Y) -Compute the Riemannian inner product ``g^{\operatorname{SpSt}}`` at -``p \in \operatorname{SpSt}`` between tangent vectors ``X, X \in T_p\operatorname{SpSt}``. +Compute the Riemannian inner product ``g^{\mathrm{SpSt}}`` at +``p ∈ \mathrm{SpSt}`` of tangent vectors ``Y, X ∈ T_p\mathrm{SpSt}``. Given by Proposition 3.10 in [BendokatZimmermann:2021](@cite). -````math -g^{\operatorname{SpSt}}_p(X, Y) - = \operatorname{tr}\Bigl( - X^{\mathrm{T}}\bigl( - I_{2n} - \frac{1}{2}Q_{2n}^{\mathrm{T}} p(p^{\mathrm{T}}p)^{-1}p^{\mathrm{T}}Q_{2n} - \bigr) Y (p^{\mathrm{T}}p)^{-1}\Bigr). -```` +```math +g^{\mathrm{SpSt}}_p(X, Y) + = \operatorname{tr}\Bigl( + X^{\mathrm{T}}\bigl( + I_{2n} - \frac{1}{2}J_{2n}^{\mathrm{T}} p(p^{\mathrm{T}}p)^{-1}p^{\mathrm{T}}J_{2n} + \bigr) Y (p^{\mathrm{T}}p)^{-1}\Bigr). +``` """ function inner(::SymplecticStiefel, p, X, Y) - Q = SymplecticMatrix(p, X, Y) # in BZ21 also J + J = SymplecticMatrix(p, X, Y) # in BZ21 also J # Procompute lu(p'p) since we solve a^{-1}* 3 times a = lu(p' * p) # note that p'p is symmetric, thus so is its inverse c=a^{-1} - b = Q' * p + b = J' * p # we split the original trace into two one with I->(X'Yc) # and the other with 1/2 X'b c b' Y c # 1) we permute X' and Y c to c^{\mathrm{T}}Y^{\mathrm{T}}X = a\(Y'X) (avoids a large interims matrix) @@ -343,37 +323,33 @@ end inv(::SymplecticStiefel, A) inv!(::SymplecticStiefel, q, p) -Compute the symplectic inverse ``A^+`` of matrix ``A ∈ ℝ^{2n Γ— 2k}``. Given a matrix +Compute the symplectic inverse ``A^+`` of matrix ``A ∈ ℝ^{2n Γ— 2k}``. +Given a matrix ````math A ∈ ℝ^{2n Γ— 2k},\quad A = \begin{bmatrix} A_{1, 1} & A_{1, 2} \\ A_{2, 1} & A_{2, 2} -\end{bmatrix},\; A_{i, j} \in ℝ^{2n Γ— 2k} +\end{bmatrix}, \quad A_{i, j} ∈ ℝ^{2n Γ— 2k} ```` + the symplectic inverse is defined as: -````math -A^{+} := Q_{2k}^{\mathrm{T}} A^{\mathrm{T}} Q_{2n}, -```` -where -````math -Q_{2n} = -\begin{bmatrix} -0_n & I_n \\ - -I_n & 0_n -\end{bmatrix}. -```` -For any ``p \in \operatorname{SpSt}(2n, 2k)`` we have that ``p^{+}p = I_{2k}``. + +```math +A^{+} := J_{2k}^{\mathrm{T}} A^{\mathrm{T}} J_{2n}, +``` + +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). The symplectic inverse of a matrix A can be expressed explicitly as: -````math +```math A^{+} = -\begin{bmatrix} - A_{2, 2}^{\mathrm{T}} & -A_{1, 2}^{\mathrm{T}} \\[1.2mm] - -A_{2, 1}^{\mathrm{T}} & A_{1, 1}^{\mathrm{T}} -\end{bmatrix}. -```` + \begin{bmatrix} + A_{2, 2}^{\mathrm{T}} & -A_{1, 2}^{\mathrm{T}} \\[1.2mm] + -A_{2, 1}^{\mathrm{T}} & A_{1, 1}^{\mathrm{T}} + \end{bmatrix}. +``` """ function Base.inv(M::SymplecticStiefel, p) q = similar(p') @@ -403,29 +379,21 @@ end inverse_retract(::SymplecticStiefel, p, q, ::CayleyInverseRetraction) inverse_retract!(::SymplecticStiefel, q, p, X, ::CayleyInverseRetraction) -Compute the Cayley Inverse Retraction ``X = \mathcal{L}_p^{\operatorname{SpSt}}(q)`` +Compute the Cayley Inverse Retraction ``X = \mathcal{L}_p^{\mathrm{SpSt}}(q)`` such that the Cayley Retraction from ``p`` along ``X`` lands at ``q``, i.e. ``\mathcal{R}_p(X) = q`` [BendokatZimmermann:2021](@cite). -First, recall the definition the standard symplectic matrix -````math -Q = -\begin{bmatrix} - 0 & I \\ --I & 0 -\end{bmatrix} -```` -as well as the symplectic inverse of a matrix ``A``, ``A^{+} = Q^{\mathrm{T}} A^{\mathrm{T}} Q``. - -For ``p, q ∈ \operatorname{SpSt}(2n, 2k, ℝ)`` then, we can define the +For ``p, q ∈ \mathrm{SpSt}(2n, 2k, ℝ)`` we can define the inverse cayley retraction as long as the following matrices exist. ````math - U = (I + p^+ q)^{-1} \in ℝ^{2k \times 2k}, + U = (I + p^+ q)^{-1} ∈ ℝ^{2kΓ—2k}, \quad - V = (I + q^+ p)^{-1} \in ℝ^{2k \times 2k}. + V = (I + q^+ p)^{-1} ∈ ℝ^{2kΓ—2k}, ```` -If that is the case, the inverse cayley retration at ``p`` applied to ``q`` is +where ``(β‹…)^+`` denotes the [`symplectic_inverse`](@ref). + +THen the inverse retraction reads ````math \mathcal{L}_p^{\operatorname{Sp}}(q) = 2p\bigl(V - U\bigr) + 2\bigl((p + q)U - p\bigr) ∈ T_p\operatorname{Sp}(2n). @@ -451,10 +419,10 @@ is_flat(M::SymplecticStiefel) = false @doc raw""" manifold_dimension(::SymplecticStiefel) -Returns the dimension of the symplectic Stiefel manifold embedded in ``ℝ^{2n \times 2k}``, +Returns the dimension of the symplectic Stiefel manifold embedded in ``ℝ^{2nΓ—2k}``, i.e. [BendokatZimmermann:2021](@cite) ````math - \operatorname{dim}(\operatorname{SpSt}(2n, 2k)) = (4n - 2k + 1)k. + \operatorname{dim}(\mathrm{SpSt}(2n, 2k)) = (4n - 2k + 1)k. ```` """ function manifold_dimension(M::SymplecticStiefel) @@ -466,38 +434,38 @@ end project(::SymplecticStiefel, p, A) project!(::SymplecticStiefel, Y, p, A) -Given a point ``p \in \operatorname{SpSt}(2n, 2k)``, -project an element ``A \in \mathbb{R}^{2n \times 2k}`` onto -the tangent space ``T_p\operatorname{SpSt}(2n, 2k)`` relative to -the euclidean metric of the embedding ``\mathbb{R}^{2n \times 2k}``. +Given a point ``p ∈ \mathrm{SpSt}(2n, 2k)``, +project an element ``A ∈ ℝ^{2nΓ—2k}`` onto +the tangent space ``T_p\mathrm{SpSt}(2n, 2k)`` relative to +the euclidean metric of the embedding ``ℝ^{2nΓ—2k}``. -That is, we find the element ``X \in T_p\operatorname{SpSt}(2n, 2k)`` +That is, we find the element ``X ∈ T_p\mathrm{SpSt}(2n, 2k)`` which solves the constrained optimization problem ````math - \operatorname{min}_{X \in \mathbb{R}^{2n \times 2k}} \frac{1}{2}||X - A||^2, \quad + \operatorname{min}_{X ∈ ℝ^{2nΓ—2k}} \frac{1}{2}||X - A||^2, \quad \text{s.t.}\; - h(X)\colon= X^{\mathrm{T}} Q p + p^{\mathrm{T}} Q X = 0, + h(X)\colon= X^{\mathrm{T}} J p + p^{\mathrm{T}} J X = 0, ```` -where ``h : \mathbb{R}^{2n \times 2k} \rightarrow \operatorname{skew}(2k)`` defines -the restriction of ``X`` onto the tangent space ``T_p\operatorname{SpSt}(2n, 2k)``. +where ``h : ℝ^{2nΓ—2k} β†’ \operatorname{skew}(2k)`` defines +the restriction of ``X`` onto the tangent space ``T_p\mathrm{SpSt}(2n, 2k)``. """ project(::SymplecticStiefel, p, A) function project!(::SymplecticStiefel, Y, p, A) - Q = SymplecticMatrix(Y, p, A) - Q_p = Q * p + J = SymplecticMatrix(Y, p, A) + Jp = J * p function h(X) - XT_Q_p = X' * Q_p - return XT_Q_p .- XT_Q_p' + XTJp = X' * Jp + return XTJp .- XTJp' end # Solve for Ξ› (Lagrange mutliplier): pT_p = p' * p # (2k Γ— 2k) Ξ› = sylvester(pT_p, pT_p, h(A) ./ 2) - Y[:, :] = A .- Q_p * (Ξ› .- Ξ›') + Y[:, :] = A .- Jp * (Ξ› .- Ξ›') return Y end @@ -505,22 +473,22 @@ end rand(M::SymplecticStiefel; vector_at=nothing, hamiltonian_norm=(vector_at === nothing ? 1/2 : 1.0)) -Generate a random point ``p \in \operatorname{SpSt}(2n, 2k)`` or -a random tangent vector ``X \in T_p\operatorname{SpSt}(2n, 2k)`` -if `vector_at` is set to a point ``p \in \operatorname{Sp}(2n)``. +Generate a random point ``p ∈ \mathrm{SpSt}(2n, 2k)`` or +a random tangent vector ``X ∈ T_p\mathrm{SpSt}(2n, 2k)`` +if `vector_at` is set to a point ``p ∈ \operatorname{Sp}(2n)``. -A random point on ``\operatorname{SpSt}(2n, 2k)`` is found by first generating a +A random point on ``\mathrm{SpSt}(2n, 2k)`` is found by first generating a random point on the symplectic manifold ``\operatorname{Sp}(2n)``, and then projecting onto the Symplectic Stiefel manifold using the -[`canonical_project`](@ref) ``Ο€_{\operatorname{SpSt}(2n, 2k)}``. -That is, ``p = Ο€_{\operatorname{SpSt}(2n, 2k)}(p_{\operatorname{Sp}})``. +[`canonical_project`](@ref) ``Ο€_{\mathrm{SpSt}(2n, 2k)}``. +That is, ``p = Ο€_{\mathrm{SpSt}(2n, 2k)}(p_{\operatorname{Sp}})``. -To generate a random tangent vector in ``T_p\operatorname{SpSt}(2n, 2k)`` +To generate a random tangent vector in ``T_p\mathrm{SpSt}(2n, 2k)`` this code exploits the second tangent vector space parametrization of -[`SymplecticStiefel`](@ref), showing that any ``X \in T_p\operatorname{SpSt}(2n, 2k)`` +[`SymplecticStiefel`](@ref), showing that any ``X ∈ T_p\mathrm{SpSt}(2n, 2k)`` can be written as ``X = pΞ©_X + p^sB_X``. To generate random tangent vectors at ``p`` then, this function sets ``B_X = 0`` -and generates a random Hamiltonian matrix ``Ξ©_X \in \mathfrak{sp}(2n,F)`` with +and generates a random Hamiltonian matrix ``Ξ©_X ∈ \mathfrak{sp}(2n,F)`` with Frobenius norm of `hamiltonian_norm` before returning ``X = pΞ©_X``. """ function Random.rand( @@ -549,23 +517,23 @@ end Compute the Cayley retraction on the Symplectic Stiefel manifold, from `p` along `X` (computed inplace of `q`). -Given a point ``p \in \operatorname{SpSt}(2n, 2k)``, every tangent vector -``X \in T_p\operatorname{SpSt}(2n, 2k)`` is of the form +Given a point ``p ∈ \mathrm{SpSt}(2n, 2k)``, every tangent vector +``X ∈ T_p\mathrm{SpSt}(2n, 2k)`` is of the form ``X = \tilde{\Omega}p``, with ````math \tilde{\Omega} = \left(I_{2n} - \frac{1}{2}pp^+\right)Xp^+ - - pX^+\left(I_{2n} - \frac{1}{2}pp^+\right) \in ℝ^{2n \times 2n}, + pX^+\left(I_{2n} - \frac{1}{2}pp^+\right) ∈ ℝ^{2nΓ—2n}, ```` as shown in Proposition 3.5 of [BendokatZimmermann:2021](@cite). Using this representation of ``X``, the Cayley retraction -on ``\operatorname{SpSt}(2n, 2k)`` is defined pointwise as +on ``\mathrm{SpSt}(2n, 2k)`` is defined pointwise as ````math \mathcal{R}_p(X) = \operatorname{cay}\left(\frac{1}{2}\tilde{\Omega}\right)p. ```` The operator ``\operatorname{cay}(A) = (I - A)^{-1}(I + A)`` is the Cayley transform. -However, the computation of an ``2n \times 2n`` matrix inverse in the expression -above can be reduced down to inverting a ``2k \times 2k`` matrix due to Proposition +However, the computation of an ``2nΓ—2n`` matrix inverse in the expression +above can be reduced down to inverting a ``2kΓ—2k`` matrix due to Proposition 5.2 of [BendokatZimmermann:2021](@cite). Let ``A = p^+X`` and ``H = X - pA``. Then an equivalent expression for the Cayley @@ -604,16 +572,18 @@ provided that the gradient of the function ``\tilde f``, which is `f` continued is given by `Y`. The metric in the embedding is the Euclidean metric. The manifold gradient `X` is computed from `Y` as + ```math - X = Yp^{\mathrm{T}}p + Q_{2n}pY^{\mathrm{T}}Q_{2n}p, + X = Yp^{\mathrm{T}}p + J_{2n}pY^{\mathrm{T}}J_{2n}p, ``` -where ``Q_{2n}`` is the [`SymplecticMatrix`](@ref). + +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). """ function riemannian_gradient(::SymplecticStiefel, p, Y) - Q_p = SymplecticMatrix(p, Y) * p - return Y * (p' * p) .+ Q_p * (Y' * Q_p) + Jp = SymplecticMatrix(p, Y) * p + return Y * (p' * p) .+ Jp * (Y' * Jp) end function riemannian_gradient!( @@ -623,8 +593,8 @@ function riemannian_gradient!( Y; embedding_metric::EuclideanMetric=EuclideanMetric(), ) - Q_p = SymplecticMatrix(p, Y) * p - X .= Y * (p' * p) .+ Q_p * (Y' * Q_p) + Jp = SymplecticMatrix(p, Y) * p + X .= Y * (p' * p) .+ Jp * (Y' * Jp) return X end @@ -640,15 +610,15 @@ end symplectic_inverse_times(::SymplecticStiefel, p, q) symplectic_inverse_times!(::SymplecticStiefel, A, p, q) -Directly compute the symplectic inverse of ``p \in \operatorname{SpSt}(2n, 2k)``, -multiplied with ``q \in \operatorname{SpSt}(2n, 2k)``. +Directly compute the symplectic inverse of ``p ∈ \mathrm{SpSt}(2n, 2k)``, +multiplied with ``q ∈ \mathrm{SpSt}(2n, 2k)``. That is, this function efficiently computes -``p^+q = (Q_{2k}p^{\mathrm{T}}Q_{2n})q \in ℝ^{2k \times 2k}``, -where ``Q_{2n}, Q_{2k}`` are the [`SymplecticMatrix`](@ref) -of sizes ``2n \times 2n`` and ``2k \times 2k`` respectively. +``p^+q = (J_{2k}p^{\mathrm{T}}J_{2n})q ∈ ℝ^{2kΓ—2k}``, +where ``J_{2n}, J_{2k}`` are the [`SymplecticMatrix`](@ref) +of sizes ``2nΓ—2n`` and ``2kΓ—2k`` respectively. This function performs this common operation without allocating more than -a ``2k \times 2k`` matrix to store the result in, or in the case of the in-place +a ``2kΓ—2k`` matrix to store the result in, or in the case of the in-place function, without allocating memory at all. """ function symplectic_inverse_times(M::SymplecticStiefel, p, q) diff --git a/src/manifolds/Tucker.jl b/src/manifolds/Tucker.jl index 414d00e62c..5ad07de410 100644 --- a/src/manifolds/Tucker.jl +++ b/src/manifolds/Tucker.jl @@ -2,33 +2,33 @@ @doc raw""" Tucker{T, D, 𝔽} <: AbstractManifold{𝔽} -The manifold of ``N_1 \times \dots \times N_D`` real-valued or complex-valued tensors of +The manifold of ``N_1Γ—\dotsΓ—N_D`` real-valued or complex-valued tensors of fixed multilinear rank ``(R_1, \dots, R_D)`` . If ``R_1 = \dots = R_D = 1``, this is the Segre manifold, i.e., the set of rank-1 tensors. # Representation in HOSVD format -Let ``\mathbb{F}`` be the real or complex numbers. +Let ``𝔽`` be the real or complex numbers. Any tensor ``p`` on the Tucker manifold can be represented as a multilinear product in HOSVD [DeLathauwerDeMoorVanderwalle:2000](@cite) form ```math -p = (U_1,\dots,U_D) \cdot \mathcal{C} +p = (U_1,\dots,U_D) β‹… \mathcal{C} ``` -where ``\mathcal C \in \mathbb{F}^{R_1 \times \dots \times R_D}`` and, for ``d=1,\dots,D``, -the matrix ``U_d \in \mathbb{F}^{N_d \times R_d}`` contains the singular vectors of the +where ``\mathcal C \in 𝔽^{R_1Γ—\dotsΓ—R_D}`` and, for ``d=1,\dots,D``, +the matrix ``U_d \in 𝔽^{N_dΓ—R_d}`` contains the singular vectors of the ``d``th unfolding of ``\mathcal{A}`` # Tangent space The tangent space to the Tucker manifold at -``p = (U_1,\dots,U_D) \cdot \mathcal{C}`` is [KochLubich:2010](@cite) +``p = (U_1,\dots,U_D) β‹… \mathcal{C}`` is [KochLubich:2010](@cite) ```math T_p \mathcal{M} = \bigl\{ -(U_1,\dots,U_D) \cdot \mathcal{C}^\prime +(U_1,\dots,U_D) β‹… \mathcal{C}^\prime + \sum_{d=1}^D \bigl( (U_1, \dots, U_{d-1}, U_d^\prime, U_{d+1}, \dots, U_D) - \cdot \mathcal{C} + β‹… \mathcal{C} \bigr) \bigr\} ``` @@ -124,8 +124,8 @@ Tangent vector to the `D`-th order [`Tucker`](@ref) manifold at represented as ````math X = -(U_1,\dots,U_D) \cdot \mathcal{C}^\prime + -\sum_{d=1}^D (U_1,\dots,U_{d-1},U_d^\prime,U_{d+1},\dots,U_D) \cdot \mathcal{C} +(U_1,\dots,U_D) β‹… \mathcal{C}^\prime + +\sum_{d=1}^D (U_1,\dots,U_{d-1},U_d^\prime,U_{d+1},\dots,U_D) β‹… \mathcal{C} ```` where ``U_d^\mathrm{H} U_d^\prime = 0``. @@ -444,7 +444,7 @@ end get_basis(:: Tucker, p::TuckerPoint, basisType::DefaultOrthonormalBasis{𝔽, TangentSpaceType}) where 𝔽 An implicitly stored basis of the tangent space to the Tucker manifold. -Assume ``p = (U_1,\dots,U_D) \cdot \mathcal{C}`` is in HOSVD format and that, for +Assume ``p = (U_1,\dots,U_D) β‹… \mathcal{C}`` is in HOSVD format and that, for ``d=1,\dots,D``, the singular values of the ``d``'th unfolding are ``\sigma_{dj}``, with ``j = 1,\dots,R_d``. The basis of the tangent space is as follows: [DewaeleBreidingVannieuwenhoven:2021](@cite) @@ -453,13 +453,13 @@ The basis of the tangent space is as follows: [DewaeleBreidingVannieuwenhoven:20 \bigl\{ (U_1,\dots,U_D) e_i \bigr\} \cup \bigl\{ -(U_1,\dots, \sigma_{dj}^{-1} U_d^{\perp} e_i e_j^T,\dots,U_D) \cdot \mathcal{C} +(U_1,\dots, \sigma_{dj}^{-1} U_d^{\perp} e_i e_j^T,\dots,U_D) β‹… \mathcal{C} \bigr\} ```` for all ``d = 1,\dots,D`` and all canonical basis vectors ``e_i`` and ``e_j``. Every ``U_d^\perp`` is such that ``[U_d \quad U_d^{\perp}]`` forms an orthonormal basis -of ``\mathbb{R}^{N_d}``. +of ``ℝ^{N_d}``. """ function get_basis( ::Tucker, @@ -634,7 +634,7 @@ end @doc raw""" manifold_dimension(::Tucker) -The dimension of the manifold of ``N_1 \times \dots \times N_D`` tensors of multilinear +The dimension of the manifold of ``N_1Γ—\dotsΓ—N_D`` tensors of multilinear rank ``(R_1, \dots, R_D)``, i.e. ````math \mathrm{dim}(\mathcal{M}) = \prod_{d=1}^D R_d + \sum_{d=1}^D R_d (N_d - R_d). diff --git a/src/manifolds/power.md b/src/manifolds/power.md new file mode 100644 index 0000000000..6f04e8bb58 --- /dev/null +++ b/src/manifolds/power.md @@ -0,0 +1,114 @@ +# [Power manifold](@id PowerManifoldSection) + +A power manifold is based on a [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) $\mathcal M$ to build a $\mathcal M^{n_1Γ—n_2 Γ—β‹―Γ—n_m}$. +In the case where $m=1$ we can represent a manifold-valued vector of data of length $n_1$, for example a time series. +The case where $m=2$ is useful for representing manifold-valued matrices of data of size $n_1Γ—n_2$, for example certain types of images. + +There are three available representations for points and vectors on a power manifold: + +* [`ArrayPowerRepresentation`](@ref) (the default one), very efficient but only applicable when points on the underlying manifold are represented using plain `AbstractArray`s. +* [`NestedPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedPowerRepresentation), applicable to any manifold. It assumes that points on the underlying manifold are represented using mutable data types. +* [`NestedReplacingPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedReplacingPowerRepresentation), applicable to any manifold. It does not mutate points on the underlying manifold, replacing them instead when appropriate. + +Below are some examples of usage of these representations. + +## Example + +There are two ways to store the data: in a multidimensional array or in a nested array. + +Let's look at an example for both. +Let $\mathcal M$ be `Sphere(2)` the 2-sphere and we want to look at vectors of length 4. + +### `ArrayPowerRepresentation` + +For the default, the [`ArrayPowerRepresentation`](@ref), we store the data in a multidimensional array, + +```@example 1 +using Manifolds +M = PowerManifold(Sphere(2), 4) +p = cat([1.0, 0.0, 0.0], + [1/sqrt(2.0), 1/sqrt(2.0), 0.0], + [1/sqrt(2.0), 0.0, 1/sqrt(2.0)], + [0.0, 1.0, 0.0] + ,dims=2) +``` + +which is a valid point i.e. + +```@example 1 +is_point(M, p) +``` + +This can also be used in combination with [HybridArrays.jl](https://github.com/mateuszbaran/HybridArrays.jl) and [StaticArrays.jl](https://github.com/JuliaArrays/StaticArrays.jl), by setting + +```@example 1 +using HybridArrays, StaticArrays +q = HybridArray{Tuple{3,StaticArrays.Dynamic()},Float64,2}(p) +``` + +which is still a valid point on `M` and [`PowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.PowerManifold) works with these, too. + +An advantage of this representation is that it is quite efficient, especially when a `HybridArray` (from the [HybridArrays.jl](https://github.com/mateuszbaran/HybridArrays.jl) package) is used to represent a point on the power manifold. +A disadvantage is not being able to easily identify parts of the multidimensional array that correspond to a single point on the base manifold. +Another problem is, that accessing a single point is ` p[:, 1]` which might be unintuitive. + +### `NestedPowerRepresentation` + +For the [`NestedPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedPowerRepresentation) we can now do + +```@example 2 +using Manifolds +M = PowerManifold(Sphere(2), NestedPowerRepresentation(), 4) +p = [ [1.0, 0.0, 0.0], + [1/sqrt(2.0), 1/sqrt(2.0), 0.0], + [1/sqrt(2.0), 0.0, 1/sqrt(2.0)], + [0.0, 1.0, 0.0], + ] +``` + +which is again a valid point so `is_point(M, p)` here also yields true. +A disadvantage might be that with nested arrays one loses a little bit of performance. +The data however is nicely encapsulated. Accessing the first data item is just `p[1]`. + +For accessing points on power manifolds in both representations you can use [`get_component`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#ManifoldsBase.get_component-Tuple%7BAbstractPowerManifold,%20Any,%20Vararg%7BAny%7D%7D) and [`set_component!`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#ManifoldsBase.set_component!-Tuple%7BAbstractPowerManifold,%20Any,%20Any,%20Vararg%7BAny%7D%7D) functions. +They work work both point representations. + +```@example 3 +using Manifolds +M = PowerManifold(Sphere(2), NestedPowerRepresentation(), 4) +p = [ [1.0, 0.0, 0.0], + [1/sqrt(2.0), 1/sqrt(2.0), 0.0], + [1/sqrt(2.0), 0.0, 1/sqrt(2.0)], + [0.0, 1.0, 0.0], + ] +set_component!(M, p, [0.0, 0.0, 1.0], 4) +get_component(M, p, 4) +``` + +### `NestedReplacingPowerRepresentation` + +The final representation is the [`NestedReplacingPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedReplacingPowerRepresentation). It is similar to the [`NestedPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedPowerRepresentation) but it does not perform in-place operations on the points on the underlying manifold. The example below uses this representation to store points on a power manifold of the [`SpecialEuclidean`](@ref) group in-line in an `Vector` for improved efficiency. When having a mixture of both, i.e. an array structure that is nested (like [Β΄NestedPowerRepresentation](@ref)) in the sense that the elements of the main vector are immutable, then changing the elements can not be done in an in-place way and hence [`NestedReplacingPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedReplacingPowerRepresentation) has to be used. + +```@example 4 +using Manifolds, StaticArrays +R2 = Rotations(2) + +G = SpecialEuclidean(2) +N = 5 +GN = PowerManifold(G, NestedReplacingPowerRepresentation(), N) + +q = [1.0 0.0; 0.0 1.0] +p1 = [ArrayPartition(SVector{2,Float64}([i - 0.1, -i]), SMatrix{2,2,Float64}(exp(R2, q, hat(R2, q, i)))) for i in 1:N] +p2 = [ArrayPartition(SVector{2,Float64}([i - 0.1, -i]), SMatrix{2,2,Float64}(exp(R2, q, hat(R2, q, -i)))) for i in 1:N] + +X = similar(p1); + +log!(GN, X, p1, p2) +``` + +## Types and Functions +```@autodocs +Modules = [Manifolds] +Pages = ["manifolds/PowerManifold.jl"] +Order = [:type, :function] +``` diff --git a/src/utils.jl b/src/utils.jl index d12937d426..41a0c97d73 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -229,7 +229,7 @@ end @doc raw""" vec2skew!(X, v, k) -create a skew symmetric matrix inplace in `X` of size $k\times k$ from a vector `v`, +create a skew symmetric matrix inplace in `X` of size $kΓ—k$ from a vector `v`, for example for `v=[1,2,3]` and `k=3` this yields ````julia diff --git a/tutorials/getstarted.qmd b/tutorials/getstarted.qmd index 283d79f777..be3edad047 100644 --- a/tutorials/getstarted.qmd +++ b/tutorials/getstarted.qmd @@ -73,7 +73,7 @@ manifold_dimension(M₁) The $d$-dimensional ``[hyperbolic space](@ref HyperbolicSpace)``{=commonmark} is usually represented in $\mathbb R^{d+1}$ as the set of points $p\in\mathbb R^3$ fulfilling ```math -p_1^2+p_2^2+\cdots+p_d^2-p_{d+1}^2 = -1. +p_1^2+p_2^2+β‹…s+p_d^2-p_{d+1}^2 = -1. ``` We define the manifold using @@ -190,7 +190,7 @@ Note that nested power manifolds are combined into one as in Mβ‚„β‚‚ = Mβ‚„^4 ``` -which represents $2\times 4$ – matrices of hyperbolic points represented in $3\times 2\times 4$ arrays. +which represents $2Γ—4$ – matrices of hyperbolic points represented in $3Γ—2Γ—4$ arrays. We can – alternatively – use a power manifold with nested arrays diff --git a/tutorials/integration.qmd b/tutorials/integration.qmd index 29ae261dad..b22501c695 100644 --- a/tutorials/integration.qmd +++ b/tutorials/integration.qmd @@ -13,7 +13,7 @@ Pkg.develop(PackageSpec(; path=(@__DIR__) * "/../")) using Markdown ``` -This part of documentation covers integration of scalar functions defined on manifolds $f \colon \mathcal{M} \to \mathbb{R}$: +This part of documentation covers integration of scalar functions defined on manifolds $f \colon \mathcal{M} \to ℝ$: ```math \int_{\mathcal M} f(p) \mathrm{d}p @@ -55,7 +55,7 @@ We used the function [`manifold_volume`](@ref) to get the volume of the set over We will now try to verify that volume density correction correctly changes probability density of an exponential-wrapped normal distribution. `pdf_tangent_space` (defined in the next code block) represents probability density of a normally distributed random variable $X_T$ in the tangent space $T_p \mathcal{M}$. -Its probability density (with respect to the Lebesgue measure of the tangent space) is $f_{X_T}\colon T_p \mathcal{M} \to \mathbb{R}$. +Its probability density (with respect to the Lebesgue measure of the tangent space) is $f_{X_T}\colon T_p \mathcal{M} \to ℝ$. `pdf_manifold` (defined below) refers to the probability density of the distribution $X_M$ from the tangent space $T_p \mathcal{M}$ wrapped using exponential map on the manifold. The formula for probability density with respect to pushforward measure of the Lebesgue measure in the tangent space reads @@ -105,7 +105,7 @@ the density at point $q$ is defined as f(q) = \frac{1}{n h^d} \sum_{i=1}^n \frac{1}{\theta_q(\log_q(p_i))}K\left( \frac{d(q, p_i)}{h} \right), ``` -where $h$ is the bandwidth, a small positive number less than the injectivity radius of $\mathcal M$ and $K\colon\mathbb{R}\to\mathbb{R}$ is a kernel function. +where $h$ is the bandwidth, a small positive number less than the injectivity radius of $\mathcal M$ and $K\colonℝ\toℝ$ is a kernel function. Note that Pelletier's estimator can only use radially-symmetric kernels. The radially symmetric multivariate Epanechnikov kernel used in the example below is described in [LangreneMarin:2019](@cite). From 5f6409f218c68fa6a15058f81531ddf651bbfb3e Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 11 Jan 2024 18:20:46 +0100 Subject: [PATCH 09/65] delete an accidentially moved file --- src/manifolds/power.md | 114 ----------------------------------------- 1 file changed, 114 deletions(-) delete mode 100644 src/manifolds/power.md diff --git a/src/manifolds/power.md b/src/manifolds/power.md deleted file mode 100644 index 6f04e8bb58..0000000000 --- a/src/manifolds/power.md +++ /dev/null @@ -1,114 +0,0 @@ -# [Power manifold](@id PowerManifoldSection) - -A power manifold is based on a [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) $\mathcal M$ to build a $\mathcal M^{n_1Γ—n_2 Γ—β‹―Γ—n_m}$. -In the case where $m=1$ we can represent a manifold-valued vector of data of length $n_1$, for example a time series. -The case where $m=2$ is useful for representing manifold-valued matrices of data of size $n_1Γ—n_2$, for example certain types of images. - -There are three available representations for points and vectors on a power manifold: - -* [`ArrayPowerRepresentation`](@ref) (the default one), very efficient but only applicable when points on the underlying manifold are represented using plain `AbstractArray`s. -* [`NestedPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedPowerRepresentation), applicable to any manifold. It assumes that points on the underlying manifold are represented using mutable data types. -* [`NestedReplacingPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedReplacingPowerRepresentation), applicable to any manifold. It does not mutate points on the underlying manifold, replacing them instead when appropriate. - -Below are some examples of usage of these representations. - -## Example - -There are two ways to store the data: in a multidimensional array or in a nested array. - -Let's look at an example for both. -Let $\mathcal M$ be `Sphere(2)` the 2-sphere and we want to look at vectors of length 4. - -### `ArrayPowerRepresentation` - -For the default, the [`ArrayPowerRepresentation`](@ref), we store the data in a multidimensional array, - -```@example 1 -using Manifolds -M = PowerManifold(Sphere(2), 4) -p = cat([1.0, 0.0, 0.0], - [1/sqrt(2.0), 1/sqrt(2.0), 0.0], - [1/sqrt(2.0), 0.0, 1/sqrt(2.0)], - [0.0, 1.0, 0.0] - ,dims=2) -``` - -which is a valid point i.e. - -```@example 1 -is_point(M, p) -``` - -This can also be used in combination with [HybridArrays.jl](https://github.com/mateuszbaran/HybridArrays.jl) and [StaticArrays.jl](https://github.com/JuliaArrays/StaticArrays.jl), by setting - -```@example 1 -using HybridArrays, StaticArrays -q = HybridArray{Tuple{3,StaticArrays.Dynamic()},Float64,2}(p) -``` - -which is still a valid point on `M` and [`PowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.PowerManifold) works with these, too. - -An advantage of this representation is that it is quite efficient, especially when a `HybridArray` (from the [HybridArrays.jl](https://github.com/mateuszbaran/HybridArrays.jl) package) is used to represent a point on the power manifold. -A disadvantage is not being able to easily identify parts of the multidimensional array that correspond to a single point on the base manifold. -Another problem is, that accessing a single point is ` p[:, 1]` which might be unintuitive. - -### `NestedPowerRepresentation` - -For the [`NestedPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedPowerRepresentation) we can now do - -```@example 2 -using Manifolds -M = PowerManifold(Sphere(2), NestedPowerRepresentation(), 4) -p = [ [1.0, 0.0, 0.0], - [1/sqrt(2.0), 1/sqrt(2.0), 0.0], - [1/sqrt(2.0), 0.0, 1/sqrt(2.0)], - [0.0, 1.0, 0.0], - ] -``` - -which is again a valid point so `is_point(M, p)` here also yields true. -A disadvantage might be that with nested arrays one loses a little bit of performance. -The data however is nicely encapsulated. Accessing the first data item is just `p[1]`. - -For accessing points on power manifolds in both representations you can use [`get_component`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#ManifoldsBase.get_component-Tuple%7BAbstractPowerManifold,%20Any,%20Vararg%7BAny%7D%7D) and [`set_component!`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#ManifoldsBase.set_component!-Tuple%7BAbstractPowerManifold,%20Any,%20Any,%20Vararg%7BAny%7D%7D) functions. -They work work both point representations. - -```@example 3 -using Manifolds -M = PowerManifold(Sphere(2), NestedPowerRepresentation(), 4) -p = [ [1.0, 0.0, 0.0], - [1/sqrt(2.0), 1/sqrt(2.0), 0.0], - [1/sqrt(2.0), 0.0, 1/sqrt(2.0)], - [0.0, 1.0, 0.0], - ] -set_component!(M, p, [0.0, 0.0, 1.0], 4) -get_component(M, p, 4) -``` - -### `NestedReplacingPowerRepresentation` - -The final representation is the [`NestedReplacingPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedReplacingPowerRepresentation). It is similar to the [`NestedPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedPowerRepresentation) but it does not perform in-place operations on the points on the underlying manifold. The example below uses this representation to store points on a power manifold of the [`SpecialEuclidean`](@ref) group in-line in an `Vector` for improved efficiency. When having a mixture of both, i.e. an array structure that is nested (like [Β΄NestedPowerRepresentation](@ref)) in the sense that the elements of the main vector are immutable, then changing the elements can not be done in an in-place way and hence [`NestedReplacingPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedReplacingPowerRepresentation) has to be used. - -```@example 4 -using Manifolds, StaticArrays -R2 = Rotations(2) - -G = SpecialEuclidean(2) -N = 5 -GN = PowerManifold(G, NestedReplacingPowerRepresentation(), N) - -q = [1.0 0.0; 0.0 1.0] -p1 = [ArrayPartition(SVector{2,Float64}([i - 0.1, -i]), SMatrix{2,2,Float64}(exp(R2, q, hat(R2, q, i)))) for i in 1:N] -p2 = [ArrayPartition(SVector{2,Float64}([i - 0.1, -i]), SMatrix{2,2,Float64}(exp(R2, q, hat(R2, q, -i)))) for i in 1:N] - -X = similar(p1); - -log!(GN, X, p1, p2) -``` - -## Types and Functions -```@autodocs -Modules = [Manifolds] -Pages = ["manifolds/PowerManifold.jl"] -Order = [:type, :function] -``` From ab162ba0d93ade502b75712cd5c5500faaa6c837 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 11 Jan 2024 18:43:27 +0100 Subject: [PATCH 10/65] Worked a bit on math formulae. --- docs/src/manifolds/rotations.md | 4 +- src/groups/group.jl | 10 +-- src/groups/heisenberg.jl | 2 +- src/groups/special_linear.jl | 2 +- src/groups/unitary.jl | 2 +- src/manifolds/CenteredMatrices.jl | 12 +-- src/manifolds/CholeskySpace.jl | 14 ++-- src/manifolds/Elliptope.jl | 46 +++++------ src/manifolds/FixedRankMatrices.jl | 18 ++--- src/manifolds/GeneralUnitaryMatrices.jl | 4 +- src/manifolds/GeneralizedGrassmann.jl | 76 +++++++++---------- src/manifolds/GeneralizedStiefel.jl | 42 +++++----- src/manifolds/Grassmann.jl | 40 +++++----- src/manifolds/GrassmannStiefel.jl | 42 +++++----- src/manifolds/Hamiltonian.jl | 10 +-- src/manifolds/Oblique.jl | 2 +- src/manifolds/Rotations.jl | 6 +- src/manifolds/SPDFixedDeterminant.jl | 2 +- src/manifolds/SkewHermitian.jl | 10 +-- src/manifolds/Spectrahedron.jl | 14 ++-- src/manifolds/SphereSymmetricMatrices.jl | 4 +- src/manifolds/Stiefel.jl | 70 ++++++++--------- src/manifolds/StiefelEuclideanMetric.jl | 2 +- src/manifolds/StiefelSubmersionMetric.jl | 10 +-- src/manifolds/Symmetric.jl | 8 +- src/manifolds/SymmetricPositiveDefinite.jl | 6 +- .../SymmetricPositiveSemidefiniteFixedRank.jl | 16 ++-- src/manifolds/Symplectic.jl | 30 ++++---- src/manifolds/SymplecticGrassmann.jl | 2 +- src/manifolds/SymplecticStiefel.jl | 38 +++++----- src/utils.jl | 30 ++++---- test/manifolds/symplectic.jl | 2 +- test/manifolds/symplecticstiefel.jl | 2 +- 33 files changed, 289 insertions(+), 289 deletions(-) diff --git a/docs/src/manifolds/rotations.md b/docs/src/manifolds/rotations.md index 0458a7e58c..d2106e3239 100644 --- a/docs/src/manifolds/rotations.md +++ b/docs/src/manifolds/rotations.md @@ -1,8 +1,8 @@ # Rotations -The manifold $\mathrm{SO}(n)$ of orthogonal matrices with determinant $+1$ in $ℝ^{n Γ— n}$, i.e. +The manifold $\mathrm{SO}(n)$ of orthogonal matrices with determinant $+1$ in $ℝ^{nΓ—n}$, i.e. -$\mathrm{SO}(n) = \bigl\{R ∈ ℝ^{n Γ— n} \big| R R^{\mathrm{T}} = +$\mathrm{SO}(n) = \bigl\{R ∈ ℝ^{nΓ—n} \big| R R^{\mathrm{T}} = R^{\mathrm{T}}R = I_n, \det(R) = 1 \bigr\}$ The Lie group $\mathrm{SO}(n)$ is a subgroup of the orthogonal group $\mathrm{O}(n)$ and also known as the special orthogonal group or the set of rotations group. diff --git a/src/groups/group.jl b/src/groups/group.jl index 9d138b975e..45572d50f2 100644 --- a/src/groups/group.jl +++ b/src/groups/group.jl @@ -118,7 +118,7 @@ abstract type ActionDirection end @doc raw""" LeftAction() -Left action of a group on a manifold. For a forward action ``Ξ±: G Γ— X β†’ X`` it is characterized by +Left action of a group on a manifold. For a forward action ``Ξ±: GΓ—X β†’ X`` it is characterized by ```math Ξ±(g, Ξ±(h, x)) = Ξ±(gh, x) ``` @@ -129,7 +129,7 @@ struct LeftAction <: ActionDirection end """ RightAction() -Right action of a group on a manifold. For a forward action ``Ξ±: G Γ— X β†’ X`` it is characterized by +Right action of a group on a manifold. For a forward action ``Ξ±: GΓ—X β†’ X`` it is characterized by ```math Ξ±(g, Ξ±(h, x)) = Ξ±(hg, x) ``` @@ -149,14 +149,14 @@ abstract type GroupActionSide end """ LeftSide() -An action of a group on a manifold that acts from the left side, i.e. ``Ξ±: G Γ— X β†’ X``. +An action of a group on a manifold that acts from the left side, i.e. ``Ξ±: GΓ—X β†’ X``. """ struct LeftSide <: GroupActionSide end """ RightSide() -An action of a group on a manifold that acts from the right side, i.e. ``Ξ±: X Γ— G β†’ X``. +An action of a group on a manifold that acts from the right side, i.e. ``Ξ±: XΓ—G β†’ X``. """ struct RightSide <: GroupActionSide end @@ -1037,7 +1037,7 @@ Given an element ``q ∈ \mathcal{G}``, compute the right inverse of the group e ```` 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}``. +identity matrix ``I_m`` for matrix ``q ∈ ℝ^{mΓ—m}``. Since this function also depends on the group operation, make sure to implement either diff --git a/src/groups/heisenberg.jl b/src/groups/heisenberg.jl index 2c5793cae3..2b9e815def 100644 --- a/src/groups/heisenberg.jl +++ b/src/groups/heisenberg.jl @@ -2,7 +2,7 @@ @doc raw""" HeisenbergGroup{T} <: AbstractDecoratorManifold{ℝ} -Heisenberg group `HeisenbergGroup(n)` is the group of ``(n+2) Γ— (n+2)`` matrices [BinzPods:2008](@cite) +Heisenberg group `HeisenbergGroup(n)` is the group of ``(n+2)Γ—(n+2)`` matrices [BinzPods:2008](@cite) ```math \begin{bmatrix} 1 & \mathbf{a} & c \\ diff --git a/src/groups/special_linear.jl b/src/groups/special_linear.jl index e8f8eb05a9..2a72ac0ef4 100644 --- a/src/groups/special_linear.jl +++ b/src/groups/special_linear.jl @@ -126,7 +126,7 @@ end @doc raw""" project(G::SpecialLinear, p, X) -Orthogonally project ``X ∈ 𝔽^{n Γ— n}`` onto the tangent space of ``p`` to the +Orthogonally project ``X ∈ 𝔽^{nΓ—n}`` onto the tangent space of ``p`` to the [`SpecialLinear`](@ref) ``G = \mathrm{SL}(n, 𝔽)``. The formula reads ````math \operatorname{proj}_{p} diff --git a/src/groups/unitary.jl b/src/groups/unitary.jl index 7b7795d90b..3dd7255287 100644 --- a/src/groups/unitary.jl +++ b/src/groups/unitary.jl @@ -4,7 +4,7 @@ The group of unitary matrices ``\mathrm{U}(n, 𝔽)``, either complex (when 𝔽=β„‚) or quaternionic (when 𝔽=ℍ) -The group consists of all points ``p ∈ 𝔽^{n Γ— n}`` where ``p^{\mathrm{H}}p = pp^{\mathrm{H}} = I``. +The group consists of all points ``p ∈ 𝔽^{nΓ—n}`` where ``p^{\mathrm{H}}p = pp^{\mathrm{H}} = I``. The tangent spaces are if the form diff --git a/src/manifolds/CenteredMatrices.jl b/src/manifolds/CenteredMatrices.jl index e5f801797a..1cca7154e8 100644 --- a/src/manifolds/CenteredMatrices.jl +++ b/src/manifolds/CenteredMatrices.jl @@ -1,11 +1,11 @@ @doc raw""" CenteredMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} -The manifold of $m Γ— n$ real-valued or complex-valued matrices whose columns sum to zero, i.e. +The manifold of ``mΓ—n`` real-valued or complex-valued matrices whose columns sum to zero, i.e. ````math -\bigl\{ p ∈ 𝔽^{m Γ— n}\ \big|\ [1 … 1] * p = [0 … 0] \bigr\}, +\bigl\{ p ∈ 𝔽^{mΓ—n}\ \big|\ [1 … 1] * p = [0 … 0] \bigr\}, ```` -where $𝔽 ∈ \{ℝ,β„‚\}$. +where ``𝔽 ∈ \{ℝ,β„‚\}``. # Constructor CenteredMatrices(m, n[, field=ℝ]; parameter::Symbol=:type) @@ -105,7 +105,7 @@ Return the manifold dimension of the [`CenteredMatrices`](@ref) `m`-by-`n` matri ````math \dim(\mathcal M) = (m*n - n) \dim_ℝ 𝔽, ```` -where $\dim_ℝ 𝔽$ is the [`real_dimension`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.real_dimension-Tuple{ManifoldsBase.AbstractNumbers}) of `𝔽`. +where ``\dim_ℝ 𝔽`` is the [`real_dimension`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.real_dimension-Tuple{ManifoldsBase.AbstractNumbers}) of `𝔽`. """ function manifold_dimension(M::CenteredMatrices{<:Any,𝔽}) where {𝔽} m, n = get_parameter(M.size) @@ -124,7 +124,7 @@ Projects `p` from the embedding onto the [`CenteredMatrices`](@ref) `M`, i.e. 1 \end{bmatrix} * [c_1 \dots c_n], ```` -where $c_i = \frac{1}{m}\sum_{j=1}^m p_{j,i}$ for $i = 1, \dots, n$. +where ``c_i = \frac{1}{m}\sum_{j=1}^m p_{j,i}`` for ``i = 1, \dots, n``. """ project(::CenteredMatrices, ::Any) @@ -142,7 +142,7 @@ Project the matrix `X` onto the tangent space at `p` on the [`CenteredMatrices`] 1 \end{bmatrix} * [c_1 \dots c_n], ```` -where $c_i = \frac{1}{m}\sum_{j=1}^m x_{j,i}$ for $i = 1, \dots, n$. +where ``c_i = \frac{1}{m}\sum_{j=1}^m x_{j,i}`` for ``i = 1, \dots, n``. """ project(::CenteredMatrices, ::Any, ::Any) diff --git a/src/manifolds/CholeskySpace.jl b/src/manifolds/CholeskySpace.jl index 18aa9475cf..e5bf0eb31a 100644 --- a/src/manifolds/CholeskySpace.jl +++ b/src/manifolds/CholeskySpace.jl @@ -9,7 +9,7 @@ are for example summarized in Table 1 of [Lin:2019](@cite). CholeskySpace(n; parameter::Symbol=:type) -Generate the manifold of $nΓ— n$ lower triangular matrices with positive diagonal. +Generate the manifold of ``nΓ—n`` lower triangular matrices with positive diagonal. """ struct CholeskySpace{T} <: AbstractManifold{ℝ} size::T @@ -107,8 +107,8 @@ The formula reads \operatorname{diag}(p)\exp\bigl( \operatorname{diag}(X)\operatorname{diag}(p)^{-1}\bigr), ```` -where $βŒŠβ‹…βŒ‹$ denotes the strictly lower triangular matrix, -and $\operatorname{diag}$ extracts the diagonal matrix. +where ``βŒŠβ‹…βŒ‹`` denotes the strictly lower triangular matrix, +and ``\operatorname{diag}`` extracts the diagonal matrix. """ exp(::CholeskySpace, ::Any...) @@ -158,8 +158,8 @@ The formula reads \log_p q = ⌊ p βŒ‹ - ⌊ q βŒ‹ + \operatorname{diag}(p)\log\bigl(\operatorname{diag}(q)\operatorname{diag}(p)^{-1}\bigr), ```` -where $βŒŠβ‹…βŒ‹$ denotes the strictly lower triangular matrix, -and $\operatorname{diag}$ extracts the diagonal matrix. +where ``βŒŠβ‹…βŒ‹`` denotes the strictly lower triangular matrix, +and ``\operatorname{diag}`` extracts the diagonal matrix. """ log(::Cholesky, ::Any...) @@ -219,8 +219,8 @@ on the [`CholeskySpace`](@ref) manifold `M`. The formula reads + \operatorname{diag}(q)\operatorname{diag}(p)^{-1}\operatorname{diag}(X), ```` -where $βŒŠβ‹…βŒ‹$ denotes the strictly lower triangular matrix, -and $\operatorname{diag}$ extracts the diagonal matrix. +where ``βŒŠβ‹…βŒ‹`` denotes the strictly lower triangular matrix, +and ``\operatorname{diag}`` extracts the diagonal matrix. """ parallel_transport_to(::CholeskySpace, ::Any, ::Any, ::Any) diff --git a/src/manifolds/Elliptope.jl b/src/manifolds/Elliptope.jl index e7d7d7432d..638bdbeaef 100644 --- a/src/manifolds/Elliptope.jl +++ b/src/manifolds/Elliptope.jl @@ -2,32 +2,32 @@ Elliptope{T} <: AbstractDecoratorManifold{ℝ} The Elliptope manifold, also known as the set of correlation matrices, consists of all -symmetric positive semidefinite matrices of rank $k$ with unit diagonal, i.e., +symmetric positive semidefinite matrices of rank ``k`` with unit diagonal, i.e., ````math \begin{aligned} \mathcal E(n,k) = -\bigl\{p ∈ ℝ^{n Γ— n}\ \big|\ &a^\mathrm{T}pa \geq 0 \text{ for all } a ∈ ℝ^{n},\\ +\bigl\{p ∈ ℝ^{nΓ—n}\ \big|\ &a^\mathrm{T}pa \geq 0 \text{ for all } a ∈ ℝ^{n},\\ &p_{ii} = 1 \text{ for all } i=1,\ldots,n,\\ -&\text{and } p = qq^{\mathrm{T}} \text{ for } q \in ℝ^{n Γ— k} \text{ with } \operatorname{rank}(p) = \operatorname{rank}(q) = k +&\text{and } p = qq^{\mathrm{T}} \text{ for } q \in ℝ^{nΓ—k} \text{ with } \operatorname{rank}(p) = \operatorname{rank}(q) = k \bigr\}. \end{aligned} ```` -And this manifold is working solely on the matrices $q$. Note that this $q$ is not unique, -indeed for any orthogonal matrix $A$ we have $(qA)(qA)^{\mathrm{T}} = qq^{\mathrm{T}} = p$, +And this manifold is working solely on the matrices ``q``. Note that this ``q`` is not unique, +indeed for any orthogonal matrix ``A`` we have ``(qA)(qA)^{\mathrm{T}} = qq^{\mathrm{T}} = p``, so the manifold implemented here is the quotient manifold. The unit diagonal translates to -unit norm columns of $q$. +unit norm columns of ``q``. -The tangent space at $p$, denoted $T_p\mathcal E(n,k)$, is also represented by matrices -$Y\in ℝ^{n Γ— k}$ and reads as +The tangent space at ``p``, denoted ``T_p\mathcal E(n,k)``, is also represented by matrices +``Y\in ℝ^{nΓ—k}`` and reads as ````math T_p\mathcal E(n,k) = \bigl\{ -X ∈ ℝ^{n Γ— n}\,|\,X = qY^{\mathrm{T}} + Yq^{\mathrm{T}} \text{Β with } X_{ii} = 0 \text{ for } i=1,\ldots,n +X ∈ ℝ^{nΓ—n}\,|\,X = qY^{\mathrm{T}} + Yq^{\mathrm{T}} \text{ with } X_{ii} = 0 \text{ for } i=1,\ldots,n \bigr\} ```` -endowed with the [`Euclidean`](@ref) metric from the embedding, i.e. from the $ℝ^{n Γ— k}$ +endowed with the [`Euclidean`](@ref) metric from the embedding, i.e. from the ``ℝ^{nΓ—k}`` This manifold was for example @@ -37,7 +37,7 @@ investigated in[JourneeBachAbsilSepulchre:2010](@cite). Elliptope(n::Int, k::Int; parameter::Symbol=:type) -generates the manifold $\mathcal E(n,k) \subset ℝ^{n Γ— n}$. +generates the manifold ``\mathcal E(n,k) \subset ℝ^{nΓ—n}``. `parameter`: whether a type parameter should be used to store `n` and `k`. By default size is stored in type. Value can either be `:field` or `:type`. @@ -56,11 +56,11 @@ end @doc raw""" check_point(M::Elliptope, q; kwargs...) -checks, whether `q` is a valid reprsentation of a point $p=qq^{\mathrm{T}}$ on the +checks, whether `q` is a valid reprsentation of a point ``p=qq^{\mathrm{T}}`` on the [`Elliptope`](@ref) `M`, i.e. is a matrix -of size `(N,K)`, such that $p$ is symmetric positive semidefinite and has unit trace. -Since by construction $p$ is symmetric, this is not explicitly checked. -Since $p$ is by construction positive semidefinite, this is not checked. +of size `(N,K)`, such that ``p`` is symmetric positive semidefinite and has unit trace. +Since by construction ``p`` is symmetric, this is not explicitly checked. +Since ``p`` is by construction positive semidefinite, this is not checked. The tolerances for positive semidefiniteness and unit trace can be set using the `kwargs...`. """ function check_point(M::Elliptope, q; kwargs...) @@ -77,13 +77,13 @@ end @doc raw""" check_vector(M::Elliptope, q, Y; kwargs... ) -Check whether $X = qY^{\mathrm{T}} + Yq^{\mathrm{T}}$ is a tangent vector to -$p=qq^{\mathrm{T}}$ on the [`Elliptope`](@ref) `M`, -i.e. `Y` has to be of same dimension as `q` and a $X$ has to be a symmetric matrix with +Check whether ``X = qY^{\mathrm{T}} + Yq^{\mathrm{T}}`` is a tangent vector to +``p=qq^{\mathrm{T}}`` on the [`Elliptope`](@ref) `M`, +i.e. `Y` has to be of same dimension as `q` and a ``X`` has to be a symmetric matrix with zero diagonal. The tolerance for the base point check and zero diagonal can be set using the `kwargs...`. -Note that symmetric of $X$ holds by construction an is not explicitly checked. +Note that symmetric of ``X`` holds by construction an is not explicitly checked. """ function check_vector( M::Elliptope, @@ -122,7 +122,7 @@ is_flat(M::Elliptope) = false manifold_dimension(M::Elliptope) returns the dimension of -[`Elliptope`](@ref) `M`$=\mathcal E(n,k), n,k ∈ β„•$, i.e. +[`Elliptope`](@ref) `M` ``=\mathcal E(n,k), n,k ∈ β„•``, i.e. ````math \dim \mathcal E(n,k) = n(k-1) - \frac{k(k-1)}{2}. ```` @@ -158,7 +158,7 @@ end @doc raw""" retract(M::Elliptope, q, Y, ::ProjectionRetraction) -compute a projection based retraction by projecting $q+Y$ back onto the manifold. +compute a projection based retraction by projecting ``q+Y`` back onto the manifold. """ retract(::Elliptope, ::Any, ::Any, ::ProjectionRetraction) @@ -172,8 +172,8 @@ end representation_size(M::Elliptope) Return the size of an array representing an element on the -[`Elliptope`](@ref) manifold `M`, i.e. $n Γ— k$, the size of such factor of $p=qq^{\mathrm{T}}$ -on $\mathcal M = \mathcal E(n,k)$. +[`Elliptope`](@ref) manifold `M`, i.e. ``nΓ—k``, the size of such factor of ``p=qq^{\mathrm{T}}`` +on ``\mathcal M = \mathcal E(n,k)``. """ representation_size(M::Elliptope) = get_parameter(M.size) diff --git a/src/manifolds/FixedRankMatrices.jl b/src/manifolds/FixedRankMatrices.jl index 7bd71a85e1..e84b17c6ca 100644 --- a/src/manifolds/FixedRankMatrices.jl +++ b/src/manifolds/FixedRankMatrices.jl @@ -1,15 +1,15 @@ @doc raw""" FixedRankMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} -The manifold of ``m Γ— n`` real-valued or complex-valued matrices of fixed rank ``k``, i.e. +The manifold of ``mΓ—n`` real-valued or complex-valued matrices of fixed rank ``k``, i.e. ````math -\bigl\{ p ∈ 𝔽^{m Γ— n}\ \big|\ \operatorname{rank}(p) = k\bigr\}, +\bigl\{ p ∈ 𝔽^{mΓ—n}\ \big|\ \operatorname{rank}(p) = k\bigr\}, ```` where ``𝔽 ∈ \{ℝ,β„‚\}`` and the rank is the number of linearly independent columns of a matrix. # Representation with 3 matrix factors -A point ``p ∈ \mathcal M`` can be stored using unitary matrices ``U ∈ 𝔽^{m Γ— k}``, ``V ∈ 𝔽^{n Γ— k}`` as well as the ``k`` +A point ``p ∈ \mathcal M`` can be stored using unitary matrices ``U ∈ 𝔽^{mΓ—k}``, ``V ∈ 𝔽^{nΓ—k}`` as well as the ``k`` singular values of ``p = U_p S V_p^\mathrm{H}``, where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transpose or Hermitian. In other words, ``U`` and ``V`` are from the manifolds [`Stiefel`](@ref)`(m,k,𝔽)` and [`Stiefel`](@ref)`(n,k,𝔽)`, respectively; see [`SVDMPoint`](@ref) for details. @@ -18,18 +18,18 @@ The tangent space ``T_p \mathcal M`` at a point ``p ∈ \mathcal M`` with ``p=U_ is given by ````math T_p\mathcal M = \bigl\{ U_p M V_p^\mathrm{H} + U_X V_p^\mathrm{H} + U_p V_X^\mathrm{H} : - M ∈ 𝔽^{k Γ— k}, - U_X ∈ 𝔽^{m Γ— k}, - V_X ∈ 𝔽^{n Γ— k} + M ∈ 𝔽^{kΓ—k}, + U_X ∈ 𝔽^{mΓ—k}, + V_X ∈ 𝔽^{nΓ—k} \text{ s.t. } U_p^\mathrm{H}U_X = 0_k, V_p^\mathrm{H}V_X = 0_k \bigr\}, ```` -where ``0_k`` is the ``k Γ— k`` zero matrix. See [`UMVTVector`](@ref) for details. +where ``0_k`` is the ``kΓ—k`` zero matrix. See [`UMVTVector`](@ref) for details. The (default) metric of this manifold is obtained by restricting the metric -on ``ℝ^{m Γ— n}`` to the tangent bundle [Vandereycken:2013](@cite). +on ``ℝ^{mΓ—n}`` to the tangent bundle [Vandereycken:2013](@cite). # Constructor FixedRankMatrices(m, n, k[, field=ℝ]) @@ -671,7 +671,7 @@ Compute an SVD-based retraction on the [`FixedRankMatrices`](@ref) `M` by comput q = U_kS_kV_k^\mathrm{H}, ```` where ``U_k S_k V_k^\mathrm{H}`` is the shortened singular value decomposition ``USV^\mathrm{H}=p+X``, -in the sense that ``S_k`` is the diagonal matrix of size ``k Γ— k`` with the ``k`` largest +in the sense that ``S_k`` is the diagonal matrix of size ``kΓ—k`` with the ``k`` largest singular values and ``U`` and ``V`` are shortened accordingly. """ retract(::FixedRankMatrices, ::Any, ::Any, ::PolarRetraction) diff --git a/src/manifolds/GeneralUnitaryMatrices.jl b/src/manifolds/GeneralUnitaryMatrices.jl index 6ff6f9068c..7adcc0c002 100644 --- a/src/manifolds/GeneralUnitaryMatrices.jl +++ b/src/manifolds/GeneralUnitaryMatrices.jl @@ -954,7 +954,7 @@ mean(::GeneralUnitaryMatrices{<:Any,ℝ}, ::Any) project(G::UnitaryMatrices, p) project(G::OrthogonalMatrices, p) -Project the point ``p ∈ 𝔽^{n Γ— n}`` to the nearest point in +Project the point ``p ∈ 𝔽^{nΓ—n}`` to the nearest point in ``\mathrm{U}(n,𝔽)=``[`Unitary(n,𝔽)`](@ref) under the Frobenius norm. If ``p = U S V^\mathrm{H}`` is the singular value decomposition of ``p``, then the projection is @@ -980,7 +980,7 @@ end project(M::Rotations, p, X) project(M::UnitaryMatrices, p, X) -Orthogonally project the tangent vector ``X ∈ 𝔽^{n Γ— n}``, ``\mathbb F ∈ \{\mathbb R, \mathbb C\}`` +Orthogonally project the tangent vector ``X ∈ 𝔽^{nΓ—n}``, ``\mathbb F ∈ \{\mathbb R, \mathbb C\}`` to the tangent space of `M` at `p`, and change the representer to use the corresponding Lie algebra, i.e. we compute diff --git a/src/manifolds/GeneralizedGrassmann.jl b/src/manifolds/GeneralizedGrassmann.jl index fda1b2d150..83e2fac35f 100644 --- a/src/manifolds/GeneralizedGrassmann.jl +++ b/src/manifolds/GeneralizedGrassmann.jl @@ -1,37 +1,37 @@ @doc raw""" GeneralizedGrassmann{T,𝔽,TB<:AbstractMatrix} <: AbstractDecoratorManifold{𝔽} -The generalized Grassmann manifold $\operatorname{Gr}(n,k,B)$ consists of all subspaces -spanned by $k$ linear independent vectors $𝔽^n$, where $𝔽 ∈ \{ℝ, β„‚\}$ is either the real- (or complex-) valued vectors. -This yields all $k$-dimensional subspaces of $ℝ^n$ for the real-valued case and all $2k$-dimensional subspaces -of $β„‚^n$ for the second. +The generalized Grassmann manifold ``\operatorname{Gr}(n,k,B)`` consists of all subspaces +spanned by ``k`` linear independent vectors ``𝔽^n``, where ``𝔽 ∈ \{ℝ, β„‚\}`` is either the real- (or complex-) valued vectors. +This yields all ``k``-dimensional subspaces of ``ℝ^n`` for the real-valued case and all ``2k``-dimensional subspaces +of ``β„‚^n`` for the second. The manifold can be represented as ````math -\operatorname{Gr}(n, k, B) := \bigl\{ \operatorname{span}(p)\ \big|\ p ∈ 𝔽^{n Γ— k}, p^\mathrm{H}Bp = I_k\}, +\operatorname{Gr}(n, k, B) := \bigl\{ \operatorname{span}(p)\ \big|\ p ∈ 𝔽^{nΓ—k}, p^\mathrm{H}Bp = I_k\}, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate (or Hermitian) transpose and -$I_k$ is the $k Γ— k$ identity matrix. This means, that the columns of $p$ +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate (or Hermitian) transpose and +``I_k`` is the ``kΓ—k`` identity matrix. This means, that the columns of ``p`` form an unitary basis of the subspace with respect to the scaled inner product, that is a -point on $\operatorname{Gr}(n,k,B)$, and hence the subspace can actually be represented by -a whole equivalence class of representers. For $B=I_n$ this simplifies to the [`Grassmann`](@ref) manifold. +point on ``\operatorname{Gr}(n,k,B)``, and hence the subspace can actually be represented by +a whole equivalence class of representers. For ``B=I_n`` this simplifies to the [`Grassmann`](@ref) manifold. -The tangent space at a point (subspace) $p$ is given by +The tangent space at a point (subspace) ``p`` is given by ````math T_x\mathrm{Gr}(n,k,B) = \bigl\{ -X ∈ 𝔽^{n Γ— k} : +X ∈ 𝔽^{nΓ—k} : X^{\mathrm{H}}Bp + p^{\mathrm{H}}BX = 0_{k} \bigr\}, ```` -where $0_{k}$ denotes the $k Γ— k$ zero matrix. +where ``0_{k}`` denotes the ``kΓ—k`` zero matrix. -Note that a point $p ∈ \operatorname{Gr}(n,k,B)$ might be represented by -different matrices (i.e. matrices with $B$-unitary column vectors that span -the same subspace). Different representations of $p$ also lead to different -representation matrices for the tangent space $T_p\mathrm{Gr}(n,k,B)$ +Note that a point ``p ∈ \operatorname{Gr}(n,k,B)`` might be represented by +different matrices (i.e. matrices with ``B``-unitary column vectors that span +the same subspace). Different representations of ``p`` also lead to different +representation matrices for the tangent space ``T_p\mathrm{Gr}(n,k,B)`` The manifold is named after [Hermann G. Graßmann](https://en.wikipedia.org/wiki/Hermann_Grassmann) (1809-1877). @@ -40,7 +40,7 @@ The manifold is named after GeneralizedGrassmann(n, k, B=I_n, field=ℝ) -Generate the (real-valued) Generalized Grassmann manifold of $nΓ—k$ dimensional +Generate the (real-valued) Generalized Grassmann manifold of ``nΓ—k`` dimensional orthonormal matrices with scalar product `B`. """ struct GeneralizedGrassmann{T,𝔽,TB<:AbstractMatrix} <: AbstractDecoratorManifold{𝔽} @@ -116,8 +116,8 @@ the [`GeneralizedGrassmann`](@ref) `M`, i.e. that `X` is of size and type as wel p^{\mathrm{H}}BX + \overline{X^{\mathrm{H}}Bp} = 0_k, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, -$\overline{β‹…}$ the (elementwise) complex conjugate, and $0_k$ denotes the $k Γ— k$ zero natrix. +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transpose or Hermitian, +``\overline{β‹…}`` the (elementwise) complex conjugate, and ``0_k`` denotes the ``kΓ—k`` zero natrix. """ function check_vector(M::GeneralizedGrassmann, p, X; kwargs...) return nothing # everything already checked in the embedding (generalized Stiefel) @@ -127,7 +127,7 @@ end distance(M::GeneralizedGrassmann, p, q) Compute the Riemannian distance on [`GeneralizedGrassmann`](@ref) -manifold `M`$= \mathrm{Gr}(n,k,B)$. +manifold `M```= \mathrm{Gr}(n,k,B)``. The distance is given by ````math @@ -149,16 +149,16 @@ embed(::GeneralizedGrassmann, p, X) = X @doc raw""" exp(M::GeneralizedGrassmann, p, X) -Compute the exponential map on the [`GeneralizedGrassmann`](@ref) `M`$= \mathrm{Gr}(n,k,B)$ -starting in `p` with tangent vector (direction) `X`. Let $X^{\mathrm{H}}BX = USV$ denote the -SVD decomposition of $X^{\mathrm{H}}BX$. Then the exponential map is written using +Compute the exponential map on the [`GeneralizedGrassmann`](@ref) `M` ``= \mathrm{Gr}(n,k,B)`` +starting in `p` with tangent vector (direction) `X`. Let ``X^{\mathrm{H}}BX = USV`` denote the +SVD decomposition of ``X^{\mathrm{H}}BX``. Then the exponential map is written using ````math \exp_p X = p V\cos(S)V^\mathrm{H} + U\sin(S)V^\mathrm{H}, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian and the -cosine and sine are applied element wise to the diagonal entries of $S$. +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transposed or Hermitian and the +cosine and sine are applied element wise to the diagonal entries of ``S``. """ exp(::GeneralizedGrassmann, ::Any...) @@ -177,7 +177,7 @@ end injectivity_radius(M::GeneralizedGrassmann, p) Return the injectivity radius on the [`GeneralizedGrassmann`](@ref) `M`, -which is $\frac{Ο€}{2}$. +which is ``\frac{Ο€}{2}``. """ injectivity_radius(::GeneralizedGrassmann) = Ο€ / 2 injectivity_radius(::GeneralizedGrassmann, p) = Ο€ / 2 @@ -209,7 +209,7 @@ of `p` on the [`GeneralizedGrassmann`](@ref) manifold `M`. The formula reads g_p(X,Y) = \operatorname{tr}(X^{\mathrm{H}}BY), ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transposed or Hermitian. """ inner(M::GeneralizedGrassmann, p, X, Y) = dot(X, M.B, Y) @@ -223,7 +223,7 @@ end @doc raw""" log(M::GeneralizedGrassmann, p, q) -Compute the logarithmic map on the [`GeneralizedGrassmann`](@ref) `M`$ = \mathcal M=\mathrm{Gr}(n,k,B)$, +Compute the logarithmic map on the [`GeneralizedGrassmann`](@ref) `M` `` = \mathcal M=\mathrm{Gr}(n,k,B)``, i.e. the tangent vector `X` whose corresponding [`geodesic`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/functions.html#ManifoldsBase.geodesic-Tuple{AbstractManifold,%20Any,%20Any}) starting from `p` reaches `q` after time 1 on `M`. The formula reads @@ -231,15 +231,15 @@ reaches `q` after time 1 on `M`. The formula reads \log_p q = Vβ‹… \operatorname{atan}(S) β‹… U^\mathrm{H}, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. -The matrices $U$ and $V$ are the unitary matrices, and $S$ is the diagonal matrix +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transposed or Hermitian. +The matrices ``U`` and ``V`` are the unitary matrices, and ``S`` is the diagonal matrix containing the singular values of the SVD-decomposition ````math USV = (q^\mathrm{H}Bp)^{-1} ( q^\mathrm{H} - q^\mathrm{H}Bpp^\mathrm{H}). ```` -In this formula the $\operatorname{atan}$ is meant elementwise. +In this formula the ``\operatorname{atan}`` is meant elementwise. """ log(::GeneralizedGrassmann, ::Any...) @@ -259,7 +259,7 @@ Return the dimension of the [`GeneralizedGrassmann(n,k,𝔽)`](@ref) manifold `M \dim \operatorname{Gr}(n,k,B) = k(n-k) \dim_ℝ 𝔽, ```` -where $\dim_ℝ 𝔽$ is the [`real_dimension`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.real_dimension-Tuple{ManifoldsBase.AbstractNumbers}) of `𝔽`. +where ``\dim_ℝ 𝔽`` is the [`real_dimension`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.real_dimension-Tuple{ManifoldsBase.AbstractNumbers}) of `𝔽`. """ function manifold_dimension(M::GeneralizedGrassmann{<:Any,𝔽}) where {𝔽} n, k = get_parameter(M.size) @@ -288,8 +288,8 @@ end project(M::GeneralizedGrassmann, p) Project `p` from the embedding onto the [`GeneralizedGrassmann`](@ref) `M`, i.e. compute `q` -as the polar decomposition of $p$ such that $q^{\mathrm{H}}Bq$ is the identity, -where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose. +as the polar decomposition of ``p`` such that ``q^{\mathrm{H}}Bq`` is the identity, +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transpose. """ project(::GeneralizedGrassmann, ::Any) @@ -311,8 +311,8 @@ Project the `n`-by-`k` `X` onto the tangent space of `p` on the \operatorname{proj_p}(X) = X - pp^{\mathrm{H}}B^\mathrm{T}X, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian -and $β‹…^{\mathrm{T}}$ the transpose. +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transposed or Hermitian +and ``β‹…^{\mathrm{T}}`` the transpose. """ project(::GeneralizedGrassmann, ::Any, ::Any) @@ -360,7 +360,7 @@ end representation_size(M::GeneralizedGrassmann) Return the represenation size or matrix dimension of a point on the [`GeneralizedGrassmann`](@ref) -`M`, i.e. $(n,k)$ for both the real-valued and the complex value case. +`M`, i.e. ``(n,k)`` for both the real-valued and the complex value case. """ representation_size(M::GeneralizedGrassmann) = get_parameter(M.size) @@ -369,7 +369,7 @@ representation_size(M::GeneralizedGrassmann) = get_parameter(M.size) Compute the SVD-based retraction [`PolarRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.PolarRetraction) on the [`GeneralizedGrassmann`](@ref) `M`, by -[`project`](@ref project(M::GeneralizedGrassmann, p))ing $p + X$ onto `M`. +[`project`](@ref project(M::GeneralizedGrassmann, p))ing ``p + X`` onto `M`. """ retract(::GeneralizedGrassmann, ::Any, ::Any, ::PolarRetraction) diff --git a/src/manifolds/GeneralizedStiefel.jl b/src/manifolds/GeneralizedStiefel.jl index 1972cad68a..6ff117e86a 100644 --- a/src/manifolds/GeneralizedStiefel.jl +++ b/src/manifolds/GeneralizedStiefel.jl @@ -1,27 +1,27 @@ @doc raw""" GeneralizedStiefel{T,𝔽,B} <: AbstractDecoratorManifold{𝔽} -The Generalized Stiefel manifold consists of all $nΓ—k$, $n\geq k$ orthonormal +The Generalized Stiefel manifold consists of all ``nΓ—k``, ``n\geq k`` orthonormal matrices w.r.t. an arbitrary scalar product with symmetric positive definite matrix -$B\in R^{n Γ— n}$, i.e. +``B\in R^{nΓ—n}``, i.e. ````math -\operatorname{St}(n,k,B) = \bigl\{ p \in \mathbb F^{n Γ— k}\ \big|\ p^{\mathrm{H}} B p = I_k \bigr\}, +\operatorname{St}(n,k,B) = \bigl\{ p \in \mathbb F^{nΓ—k}\ \big|\ p^{\mathrm{H}} B p = I_k \bigr\}, ```` -where $𝔽 ∈ \{ℝ, β„‚\}$, -$β‹…^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and -$I_k \in \mathbb R^{k Γ— k}$ denotes the $k Γ— k$ identity matrix. +where ``𝔽 ∈ \{ℝ, β„‚\}``, +``β‹…^{\mathrm{H}}`` denotes the complex conjugate transpose or Hermitian, and +``I_k \in \mathbb R^{kΓ—k}`` denotes the ``kΓ—k`` identity matrix. -In the case $B=I_k$ one gets the usual [`Stiefel`](@ref) manifold. +In the case ``B=I_k`` one gets the usual [`Stiefel`](@ref) manifold. -The tangent space at a point $p\in\mathcal M=\operatorname{St}(n,k,B)$ is given by +The tangent space at a point ``p\in\mathcal M=\operatorname{St}(n,k,B)`` is given by ````math -T_p\mathcal M = \{ X \in 𝔽^{n Γ— k} : p^{\mathrm{H}}BX + X^{\mathrm{H}}Bp=0_n\}, +T_p\mathcal M = \{ X \in 𝔽^{nΓ—k} : p^{\mathrm{H}}BX + X^{\mathrm{H}}Bp=0_n\}, ```` -where $0_k$ is the $k Γ— k$ zero matrix. +where ``0_k`` is the ``kΓ—k`` zero matrix. This manifold is modeled as an embedded manifold to the [`Euclidean`](@ref), i.e. several functions like the [`zero_vector`](@ref) are inherited from the embedding. @@ -32,7 +32,7 @@ The manifold is named after # Constructor GeneralizedStiefel(n, k, B=I_n, F=ℝ) -Generate the (real-valued) Generalized Stiefel manifold of $nΓ—k$ dimensional +Generate the (real-valued) Generalized Stiefel manifold of ``nΓ—k`` dimensional orthonormal matrices with scalar product `B`. """ struct GeneralizedStiefel{T,𝔽,TB<:AbstractMatrix} <: AbstractDecoratorManifold{𝔽} @@ -56,9 +56,9 @@ active_traits(f, ::GeneralizedStiefel, args...) = merge_traits(IsEmbeddedManifol @doc raw""" check_point(M::GeneralizedStiefel, p; kwargs...) -Check whether `p` is a valid point on the [`GeneralizedStiefel`](@ref) `M`=$\operatorname{St}(n,k,B)$, -i.e. that it has the right [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and $x^{\mathrm{H}}Bx$ -is (approximately) the identity, where $β‹…^{\mathrm{H}}$ is the complex conjugate +Check whether `p` is a valid point on the [`GeneralizedStiefel`](@ref) `M`=``\operatorname{St}(n,k,B)``, +i.e. that it has the right [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and ``x^{\mathrm{H}}Bx`` +is (approximately) the identity, where ``β‹…^{\mathrm{H}}`` is the complex conjugate transpose. The settings for approximately can be set with `kwargs...`. """ function check_point(M::GeneralizedStiefel, p; kwargs...) @@ -84,9 +84,9 @@ end check_vector(M::GeneralizedStiefel, p, X; kwargs...) Check whether `X` is a valid tangent vector at `p` on the [`GeneralizedStiefel`](@ref) -`M`=$\operatorname{St}(n,k,B)$, i.e. the [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) fits, +`M`=``\operatorname{St}(n,k,B)``, i.e. the [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) fits, `p` is a valid point on `M` and -it (approximately) holds that $p^{\mathrm{H}}BX + \overline{X^{\mathrm{H}}Bp} = 0$, where +it (approximately) holds that ``p^{\mathrm{H}}BX + \overline{X^{\mathrm{H}}Bp} = 0``, where `kwargs...` is passed to the `isapprox`. """ function check_vector(M::GeneralizedStiefel, p, X; kwargs...) @@ -131,7 +131,7 @@ is_flat(M::GeneralizedStiefel) = manifold_dimension(M) == 1 @doc raw""" manifold_dimension(M::GeneralizedStiefel) -Return the dimension of the [`GeneralizedStiefel`](@ref) manifold `M`=$\operatorname{St}(n,k,B,𝔽)$. +Return the dimension of the [`GeneralizedStiefel`](@ref) manifold `M`=``\operatorname{St}(n,k,B,𝔽)``. The dimension is given by ````math @@ -159,8 +159,8 @@ end project(M::GeneralizedStiefel, p) Project `p` from the embedding onto the [`GeneralizedStiefel`](@ref) `M`, i.e. compute `q` -as the polar decomposition of $p$ such that $q^{\mathrm{H}}Bq$ is the identity, -where $β‹…^{\mathrm{H}}$ denotes the hermitian, i.e. complex conjugate transposed. +as the polar decomposition of ``p`` such that ``q^{\mathrm{H}}Bq`` is the identity, +where ``β‹…^{\mathrm{H}}`` denotes the hermitian, i.e. complex conjugate transposed. """ project(::GeneralizedStiefel, ::Any) @@ -182,8 +182,8 @@ The formula reads \operatorname{proj}_{\operatorname{St}(n,k)}(p,X) = X - p\operatorname{Sym}(p^{\mathrm{H}}BX), ```` -where $\operatorname{Sym}(y)$ is the symmetrization of $y$, e.g. by -$\operatorname{Sym}(y) = \frac{y^{\mathrm{H}}+y}{2}$. +where ``\operatorname{Sym}(y)`` is the symmetrization of ``y``, e.g. by +``\operatorname{Sym}(y) = \frac{y^{\mathrm{H}}+y}{2}``. """ project(::GeneralizedStiefel, ::Any, ::Any) diff --git a/src/manifolds/Grassmann.jl b/src/manifolds/Grassmann.jl index 768491131d..cda76c1efc 100644 --- a/src/manifolds/Grassmann.jl +++ b/src/manifolds/Grassmann.jl @@ -1,47 +1,47 @@ @doc raw""" Grassmann{T,𝔽} <: AbstractDecoratorManifold{𝔽} -The Grassmann manifold $\operatorname{Gr}(n,k)$ consists of all subspaces spanned by $k$ linear independent -vectors $𝔽^n$, where $𝔽 ∈ \{ℝ, β„‚\}$ is either the real- (or complex-) valued vectors. -This yields all $k$-dimensional subspaces of $ℝ^n$ for the real-valued case and all $2k$-dimensional subspaces -of $β„‚^n$ for the second. +The Grassmann manifold ``\mathrm{Gr}(n,k)`` consists of all subspaces spanned by ``k`` linear independent +vectors ``𝔽^n``, where ``𝔽 ∈ \{ℝ, β„‚\}`` is either the real- (or complex-) valued vectors. +This yields all ``k``-dimensional subspaces of ``ℝ^n`` for the real-valued case and all ``2k``-dimensional subspaces +of ``β„‚^n`` for the second. The manifold can be represented as ````math -\operatorname{Gr}(n,k) := \bigl\{ \operatorname{span}(p) : p ∈ 𝔽^{n Γ— k}, p^\mathrm{H}p = I_k\}, +\mathrm{Gr}(n,k) := \bigl\{ \operatorname{span}(p) : p ∈ 𝔽^{nΓ—k}, p^\mathrm{H}p = I_k\}, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian and -$I_k$ is the $k Γ— k$ identity matrix. This means, that the columns of $p$ +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transpose or Hermitian and +``I_k`` is the ``kΓ—k`` identity matrix. This means, that the columns of ``p`` form an unitary basis of the subspace, that is a point on -$\operatorname{Gr}(n,k)$, and hence the subspace can actually be represented by +``\operatorname{Gr}(n,k)``, and hence the subspace can actually be represented by a whole equivalence class of representers. Another interpretation is, that ````math -\operatorname{Gr}(n,k) = \operatorname{St}(n,k) / \operatorname{O}(k), +\mathrm{Gr}(n,k) = \mathrm{St}(n,k) / \operatorname{O}(k), ```` i.e the Grassmann manifold is the quotient of the [`Stiefel`](@ref) manifold and -the orthogonal group $\operatorname{O}(k)$ of orthogonal $k Γ— k$ matrices. +the orthogonal group ``\operatorname{O}(k)`` of orthogonal ``kΓ—k`` matrices. Note that it doesn't matter whether we start from the Euclidean or canonical metric on the Stiefel manifold, the resulting quotient metric on Grassmann is the same. -The tangent space at a point (subspace) $p$ is given by +The tangent space at a point (subspace) ``p`` is given by ````math T_p\mathrm{Gr}(n,k) = \bigl\{ -X ∈ 𝔽^{n Γ— k} : +X ∈ 𝔽^{nΓ—k} : X^{\mathrm{H}}p + p^{\mathrm{H}}X = 0_{k} \bigr\}, ```` -where $0_k$ is the $k Γ— k$ zero matrix. +where ``0_k`` is the ``kΓ—k`` zero matrix. -Note that a point $p ∈ \operatorname{Gr}(n,k)$ might be represented by +Note that a point ``p ∈ \operatorname{Gr}(n,k)`` might be represented by different matrices (i.e. matrices with unitary column vectors that span -the same subspace). Different representations of $p$ also lead to different -representation matrices for the tangent space $T_p\mathrm{Gr}(n,k)$ +the same subspace). Different representations of ``p`` also lead to different +representation matrices for the tangent space ``T_p\mathrm{Gr}(n,k)`` For a representation of points as orthogonal projectors. Here @@ -53,7 +53,7 @@ with tangent space ```math T_p\mathrm{Gr}(n,k) = \bigl\{ -X ∈ \mathbb R^{n Γ— n} : X=X^{\mathrm{T}} \text{ and } X = pX+Xp \bigr\}, +X ∈ \mathbb R^{nΓ—n} : X=X^{\mathrm{T}} \text{ and } X = pX+Xp \bigr\}, ``` see also [`ProjectorPoint`](@ref) and [`ProjectorTVector`](@ref). @@ -67,7 +67,7 @@ A good overview can be found in[BendokatZimmermannAbsil:2020](@cite). Grassmann(n, k, field=ℝ, parameter::Symbol=:type) -Generate the Grassmann manifold $\operatorname{Gr}(n,k)$, where the real-valued +Generate the Grassmann manifold ``\operatorname{Gr}(n,k)``, where the real-valued case `field=ℝ` is the default. """ struct Grassmann{T,𝔽} <: AbstractDecoratorManifold{𝔽} @@ -120,7 +120,7 @@ end injectivity_radius(M::Grassmann) injectivity_radius(M::Grassmann, p) -Return the injectivity radius on the [`Grassmann`](@ref) `M`, which is $\frac{Ο€}{2}$. +Return the injectivity radius on the [`Grassmann`](@ref) `M`, which is ``\frac{Ο€}{2}``. """ injectivity_radius(::Grassmann) = Ο€ / 2 injectivity_radius(::Grassmann, p) = Ο€ / 2 @@ -150,7 +150,7 @@ Return the dimension of the [`Grassmann`](@ref)`(n,k,𝔽)` manifold `M`, i.e. \dim \operatorname{Gr}(n,k) = k(n-k) \dim_ℝ 𝔽, ```` -where $\dim_ℝ 𝔽$ is the [`real_dimension`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.real_dimension-Tuple{ManifoldsBase.AbstractNumbers}) of `𝔽`. +where ``\dim_ℝ 𝔽`` is the [`real_dimension`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.real_dimension-Tuple{ManifoldsBase.AbstractNumbers}) of `𝔽`. """ function manifold_dimension(M::Grassmann{<:Any,𝔽}) where {𝔽} n, k = get_parameter(M.size) diff --git a/src/manifolds/GrassmannStiefel.jl b/src/manifolds/GrassmannStiefel.jl index e1dc8279be..1db4205144 100644 --- a/src/manifolds/GrassmannStiefel.jl +++ b/src/manifolds/GrassmannStiefel.jl @@ -39,7 +39,7 @@ default_vector_transport_method(::Grassmann, ::Type{<:StiefelPoint}) = Projectio @doc raw""" distance(M::Grassmann, p, q) -Compute the Riemannian distance on [`Grassmann`](@ref) manifold `M`$= \mathrm{Gr}(n,k)$. +Compute the Riemannian distance on [`Grassmann`](@ref) manifold `M```= \mathrm{Gr}(n,k)``. The distance is given by ````math @@ -68,17 +68,17 @@ embed(::Stiefel, p::StiefelPoint, X::StiefelTVector) = X.value @doc raw""" exp(M::Grassmann, p, X) -Compute the exponential map on the [`Grassmann`](@ref) `M`$= \mathrm{Gr}(n,k)$ starting in -`p` with tangent vector (direction) `X`. Let $X = USV$ denote the SVD decomposition of $X$. +Compute the exponential map on the [`Grassmann`](@ref) `M` ``= \mathrm{Gr}(n,k)`` starting in +`p` with tangent vector (direction) `X`. Let ``X = USV`` denote the SVD decomposition of ``X``. Then the exponential map is written using ````math z = p V\cos(S)V^\mathrm{H} + U\sin(S)V^\mathrm{H}, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian and the -cosine and sine are applied element wise to the diagonal entries of $S$. A final QR -decomposition $z=QR$ is performed for numerical stability reasons, yielding the result as +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transposed or Hermitian and the +cosine and sine are applied element wise to the diagonal entries of ``S``. A final QR +decomposition ``z=QR`` is performed for numerical stability reasons, yielding the result as ````math \exp_p X = Q. @@ -111,7 +111,7 @@ of `p` on the [`Grassmann`](@ref) manifold `M`. The formula reads g_p(X,Y) = \operatorname{tr}(X^{\mathrm{H}}Y), ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transposed or Hermitian. """ inner(::Grassmann, p, X, Y) = dot(X, Y) @@ -125,7 +125,7 @@ Compute the inverse retraction for the [`PolarRetraction`](https://juliamanifold \operatorname{retr}_p^{-1}q = q*(p^\mathrm{H}q)^{-1} - p, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transposed or Hermitian. """ inverse_retract(::Grassmann, ::Any, ::Any, ::PolarInverseRetraction) @@ -143,7 +143,7 @@ Compute the inverse retraction for the [`QRRetraction`](https://juliamanifolds.g ````math \operatorname{retr}_p^{-1}q = q(p^\mathrm{H}q)^{-1} - p, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transposed or Hermitian. """ inverse_retract(::Grassmann, ::Any, ::Any, ::QRInverseRetraction) @@ -155,7 +155,7 @@ end @doc raw""" log(M::Grassmann, p, q) -Compute the logarithmic map on the [`Grassmann`](@ref) `M`$ = \mathcal M=\mathrm{Gr}(n,k)$, +Compute the logarithmic map on the [`Grassmann`](@ref) `M` `` = \mathcal M=\mathrm{Gr}(n,k)``, i.e. the tangent vector `X` whose corresponding [`geodesic`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/functions.html#ManifoldsBase.geodesic-Tuple{AbstractManifold,%20Any,%20Any}) starting from `p` reaches `q` after time 1 on `M`. The formula reads @@ -163,15 +163,15 @@ reaches `q` after time 1 on `M`. The formula reads \log_p q = Vβ‹… \operatorname{atan}(S) β‹… U^\mathrm{H}, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. -The matrices $U$ and $V$ are the unitary matrices, and $S$ is the diagonal matrix +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transposed or Hermitian. +The matrices ``U`` and ``V`` are the unitary matrices, and ``S`` is the diagonal matrix containing the singular values of the SVD-decomposition ````math USV = (q^\mathrm{H}p)^{-1} ( q^\mathrm{H} - q^\mathrm{H}pp^\mathrm{H}). ```` -In this formula the $\operatorname{atan}$ is meant elementwise. +In this formula the ``\operatorname{atan}`` is meant elementwise. """ log(::Grassmann, ::Any...) @@ -186,8 +186,8 @@ end project(M::Grassmann, p) Project `p` from the embedding onto the [`Grassmann`](@ref) `M`, i.e. compute `q` -as the polar decomposition of $p$ such that $q^{\mathrm{H}}q$ is the identity, -where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +as the polar decomposition of ``p`` such that ``q^{\mathrm{H}}q`` is the identity, +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. """ project(::Grassmann, ::Any) @@ -207,7 +207,7 @@ which is computed by \operatorname{proj_p}(X) = X - pp^{\mathrm{H}}X, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transposed or Hermitian. """ project(::Grassmann, ::Any...) @@ -253,7 +253,7 @@ end representation_size(M::Grassmann) Return the representation size or matrix dimension of a point on the [`Grassmann`](@ref) -`M`, i.e. $(n,k)$ for both the real-valued and the complex value case. +`M`, i.e. ``(n,k)`` for both the real-valued and the complex value case. """ representation_size(M::Grassmann) = get_parameter(M.size) @@ -261,12 +261,12 @@ representation_size(M::Grassmann) = get_parameter(M.size) retract(M::Grassmann, p, X, ::PolarRetraction) Compute the SVD-based retraction [`PolarRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.PolarRetraction) on the -[`Grassmann`](@ref) `M`. With $USV = p + X$ the retraction reads +[`Grassmann`](@ref) `M`. With ``USV = p + X`` the retraction reads ````math \operatorname{retr}_p X = UV^\mathrm{H}, ```` -where $β‹…^{\mathrm{H}}$ denotes the complex conjugate transposed or Hermitian. +where ``β‹…^{\mathrm{H}}`` denotes the complex conjugate transposed or Hermitian. """ retract(::Grassmann, ::Any, ::Any, ::PolarRetraction) @@ -280,11 +280,11 @@ end retract(M::Grassmann, p, X, ::QRRetraction ) Compute the QR-based retraction [`QRRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.QRRetraction) on the -[`Grassmann`](@ref) `M`. With $QR = p + X$ the retraction reads +[`Grassmann`](@ref) `M`. With ``QR = p + X`` the retraction reads ````math \operatorname{retr}_p X = QD, ```` -where D is a $m Γ— n$ matrix with +where D is a ``mΓ—n`` matrix with ````math D = \operatorname{diag}\left( \operatorname{sgn}\left(R_{ii}+\frac{1}{2}\right)_{i=1}^n \right). ```` diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index ea0171f47a..ec71f58300 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -10,7 +10,7 @@ A type to store an hamiltonien matrix, i.e. A square matrix matrix for which ``A A^+ = J_{2n}A^{\mathrm{T}}J_{2n}, \qquad J_{2n} \begin{pmatrix} 0 & I_n\\-I_n & 0 \end{pmatrix}, ``` -and ``I_n`` denotes the ``n Γ— n`` +and ``I_n`` denotes the ``nΓ—n`` """ struct Hamiltonian{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T} value::S @@ -32,14 +32,14 @@ end HamiltonianMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) -consisting of (real-valued) hamiltonian matrices of size ``n Γ— n``, i.e. the set +consisting of (real-valued) hamiltonian matrices of size ``nΓ—n``, i.e. the set ````math -\mathfrak{sp}(2n,𝔽) = \bigl\{p ∈ 𝔽^{2n Γ— 2n}\ \big|\ p^+ = p \bigr\}, +\mathfrak{sp}(2n,𝔽) = \bigl\{p ∈ 𝔽^{2nΓ—2n}\ \big|\ p^+ = p \bigr\}, ```` where ``β‹…^{+}`` denotes the [`symplectic_inverse`](@ref),. and ``𝔽 ∈ \{ ℝ, β„‚\}``. -Though it is slightly redundant, usually the matrices are stored as ``2n Γ— 2n`` arrays. +Though it is slightly redundant, usually the matrices are stored as ``2nΓ—2n`` arrays. The symbol refers to the main usage within `Manifolds.jl` that is the Lie algebra to the [`Symplectic`](@ref) as a Lie group with the matrix operation as group operation. @@ -48,7 +48,7 @@ Lie algebra to the [`Symplectic`](@ref) as a Lie group with the matrix operation HamiltonianMatrices(n::Int, field::AbstractNumbers=ℝ) -Generate the manifold of ``n Γ— n`` symmetric matrices. +Generate the manifold of ``nΓ—n`` symmetric matrices. """ struct HamiltonianMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} size::T diff --git a/src/manifolds/Oblique.jl b/src/manifolds/Oblique.jl index 9663f92633..5ca96de428 100644 --- a/src/manifolds/Oblique.jl +++ b/src/manifolds/Oblique.jl @@ -13,7 +13,7 @@ The [`Sphere`](@ref) is stored internally within `M.manifold`, such that all fun Oblique(n::Int, m::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) -Generate the manifold of matrices $\mathbb R^{n Γ— m}$ such that the $m$ columns are unit +Generate the manifold of matrices $\mathbb R^{nΓ—m}$ such that the $m$ columns are unit vectors, i.e. from the [`Sphere`](@ref)`(n-1)`. """ struct Oblique{T,𝔽,S} <: AbstractPowerManifold{𝔽,Sphere{S,𝔽},ArrayPowerRepresentation} diff --git a/src/manifolds/Rotations.jl b/src/manifolds/Rotations.jl index 1a1aef5776..dc66b52b7b 100644 --- a/src/manifolds/Rotations.jl +++ b/src/manifolds/Rotations.jl @@ -1,14 +1,14 @@ @doc raw""" Rotations{T} <: AbstractManifold{ℝ} -The manifold of rotation matrices of size ``n Γ— n``, i.e. +The manifold of rotation matrices of size ``nΓ—n``, i.e. real-valued orthogonal matrices with determinant ``+1``. # Constructor Rotations(n::Int; parameter::Symbol=:type) -Generate the manifold of ``n Γ— n`` rotation matrices. +Generate the manifold of ``nΓ—n`` rotation matrices. """ const Rotations{T} = GeneralUnitaryMatrices{T,ℝ,DeterminantOneMatrices} @@ -43,7 +43,7 @@ end @doc raw""" angles_4d_skew_sym_matrix(A) -The Lie algebra of [`Rotations(4)`](@ref) in ``ℝ^{4 Γ— 4}``, ``𝔰𝔬(4)``, consists of ``4 Γ— 4`` +The Lie algebra of [`Rotations(4)`](@ref) in ``ℝ^{4Γ—4}``, ``𝔰𝔬(4)``, consists of ``4Γ—4`` skew-symmetric matrices. The unique imaginary components of their eigenvalues are the angles of the two plane rotations. This function computes these more efficiently than `eigvals`. diff --git a/src/manifolds/SPDFixedDeterminant.jl b/src/manifolds/SPDFixedDeterminant.jl index d72d3f1f8d..4b4f467e6e 100644 --- a/src/manifolds/SPDFixedDeterminant.jl +++ b/src/manifolds/SPDFixedDeterminant.jl @@ -6,7 +6,7 @@ The manifold of symmetric positive definite matrices of fixed determinant ``d > ````math \mathcal P_d(n) = \bigl\{ -p ∈ ℝ^{n Γ— n} \ \big|\ a^\mathrm{T}pa > 0 \text{ for all } a ∈ ℝ^{n}\backslash\{0\} +p ∈ ℝ^{nΓ—n} \ \big|\ a^\mathrm{T}pa > 0 \text{ for all } a ∈ ℝ^{n}\backslash\{0\} \text{ and } \det(p) = d \bigr\}. ```` diff --git a/src/manifolds/SkewHermitian.jl b/src/manifolds/SkewHermitian.jl index 61aebdb0f5..06a4b69a78 100644 --- a/src/manifolds/SkewHermitian.jl +++ b/src/manifolds/SkewHermitian.jl @@ -2,15 +2,15 @@ SkewHermitianMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) $ \operatorname{SkewHerm}(n)$ consisting of the real- or -complex-valued skew-hermitian matrices of size ``n Γ— n``, i.e. the set +complex-valued skew-hermitian matrices of size ``nΓ—n``, i.e. the set ````math -\operatorname{SkewHerm}(n) = \bigl\{p ∈ 𝔽^{n Γ— n}\ \big|\ p^{\mathrm{H}} = -p \bigr\}, +\operatorname{SkewHerm}(n) = \bigl\{p ∈ 𝔽^{nΓ—n}\ \big|\ p^{\mathrm{H}} = -p \bigr\}, ```` where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, and the field $𝔽 ∈ \{ ℝ, β„‚, ℍ\}$. -Though it is slightly redundant, usually the matrices are stored as ``n Γ— n`` arrays. +Though it is slightly redundant, usually the matrices are stored as ``nΓ—n`` arrays. Note that in this representation, the real-valued part of the diagonal must be zero, which is also reflected in the @@ -20,7 +20,7 @@ which is also reflected in the SkewHermitianMatrices(n::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) -Generate the manifold of ``n Γ— n`` skew-hermitian matrices. +Generate the manifold of ``nΓ—n`` skew-hermitian matrices. """ struct SkewHermitianMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} size::T @@ -34,7 +34,7 @@ end @doc raw""" SkewSymmetricMatrices{T} -Generate the manifold of ``n Γ— n`` real skew-symmetric matrices. +Generate the manifold of ``nΓ—n`` real skew-symmetric matrices. This is equivalent to [`SkewHermitianMatrices(n, ℝ)`](@ref). # Constructor diff --git a/src/manifolds/Spectrahedron.jl b/src/manifolds/Spectrahedron.jl index 082b6f8fa0..bac7012274 100644 --- a/src/manifolds/Spectrahedron.jl +++ b/src/manifolds/Spectrahedron.jl @@ -7,9 +7,9 @@ positive semidefinite matrices) of rank $k$ with unit trace. ````math \begin{aligned} \mathcal S(n,k) = -\bigl\{p ∈ ℝ^{n Γ— n}\ \big|\ &a^\mathrm{T}pa \geq 0 \text{ for all } a ∈ ℝ^{n},\\ +\bigl\{p ∈ ℝ^{nΓ—n}\ \big|\ &a^\mathrm{T}pa \geq 0 \text{ for all } a ∈ ℝ^{n},\\ &\operatorname{tr}(p) = \sum_{i=1}^n p_{ii} = 1,\\ -&\text{and } p = qq^{\mathrm{T}} \text{ for } q \in ℝ^{n Γ— k} +&\text{and } p = qq^{\mathrm{T}} \text{ for } q \in ℝ^{nΓ—k} \text{ with } \operatorname{rank}(p) = \operatorname{rank}(q) = k \bigr\}. \end{aligned} @@ -22,15 +22,15 @@ unit frobenius norm of $q$. The tangent space at $p$, denoted $T_p\mathcal E(n,k)$, is also represented by matrices -$Y\in ℝ^{n Γ— k}$ and reads as +$Y\in ℝ^{nΓ—k}$ and reads as ````math T_p\mathcal S(n,k) = \bigl\{ -X ∈ ℝ^{n Γ— n}\,|\,X = qY^{\mathrm{T}} + Yq^{\mathrm{T}} +X ∈ ℝ^{nΓ—n}\,|\,X = qY^{\mathrm{T}} + Yq^{\mathrm{T}} \text{ with } \operatorname{tr}(X) = \sum_{i=1}^{n}X_{ii} = 0 \bigr\} ```` -endowed with the [`Euclidean`](@ref) metric from the embedding, i.e. from the $ℝ^{n Γ— k}$ +endowed with the [`Euclidean`](@ref) metric from the embedding, i.e. from the $ℝ^{nΓ—k}$ This manifold was for example @@ -40,7 +40,7 @@ investigated in [JourneeBachAbsilSepulchre:2010](@cite). Spectrahedron(n::Int, k::Int; parameter::Symbol=:type) -generates the manifold $\mathcal S(n,k) \subset ℝ^{n Γ— n}$. +generates the manifold $\mathcal S(n,k) \subset ℝ^{nΓ—n}$. """ struct Spectrahedron{T} <: AbstractDecoratorManifold{ℝ} size::T @@ -168,7 +168,7 @@ retract_project!(M::Spectrahedron, r, q, Y, t::Number) = project!(M, r, q .+ t . representation_size(M::Spectrahedron) Return the size of an array representing an element on the -[`Spectrahedron`](@ref) manifold `M`, i.e. $n Γ— k$, the size of such factor of $p=qq^{\mathrm{T}}$ +[`Spectrahedron`](@ref) manifold `M`, i.e. $nΓ—k$, the size of such factor of $p=qq^{\mathrm{T}}$ on $\mathcal M = \mathcal S(n,k)$. """ representation_size(M::Spectrahedron) = get_parameter(M.size) diff --git a/src/manifolds/SphereSymmetricMatrices.jl b/src/manifolds/SphereSymmetricMatrices.jl index a3e15a8b91..1b691ef5cb 100644 --- a/src/manifolds/SphereSymmetricMatrices.jl +++ b/src/manifolds/SphereSymmetricMatrices.jl @@ -1,10 +1,10 @@ @doc raw""" SphereSymmetricMatrices{T,𝔽} <: AbstractEmbeddedManifold{ℝ,TransparentIsometricEmbedding} -The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) consisting of the $n Γ— n$ symmetric matrices +The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) consisting of the $nΓ—n$ symmetric matrices of unit Frobenius norm, i.e. ````math -\mathcal{S}_{\text{sym}} :=\bigl\{p ∈ 𝔽^{n Γ— n}\ \big|\ p^{\mathrm{H}} = p, \lVert p \rVert = 1 \bigr\}, +\mathcal{S}_{\text{sym}} :=\bigl\{p ∈ 𝔽^{nΓ—n}\ \big|\ p^{\mathrm{H}} = p, \lVert p \rVert = 1 \bigr\}, ```` where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, and the field $𝔽 ∈ \{ ℝ, β„‚\}$. diff --git a/src/manifolds/Stiefel.jl b/src/manifolds/Stiefel.jl index 6317bea1e1..f4ca7f7bf0 100644 --- a/src/manifolds/Stiefel.jl +++ b/src/manifolds/Stiefel.jl @@ -1,23 +1,23 @@ @doc raw""" Stiefel{T,𝔽} <: AbstractDecoratorManifold{𝔽} -The Stiefel manifold consists of all $n Γ— k$, $n β‰₯ k$ unitary matrices, i.e. +The Stiefel manifold consists of all ``nΓ—k``, ``n β‰₯ k`` unitary matrices, i.e. ````math -\operatorname{St}(n,k) = \bigl\{ p ∈ 𝔽^{n Γ— k}\ \big|\ p^{\mathrm{H}}p = I_k \bigr\}, +\operatorname{St}(n,k) = \bigl\{ p ∈ 𝔽^{nΓ—k}\ \big|\ p^{\mathrm{H}}p = I_k \bigr\}, ```` -where $𝔽 ∈ \{ℝ, β„‚\}$, -$β‹…^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and -$I_k ∈ ℝ^{k Γ— k}$ denotes the $k Γ— k$ identity matrix. +where ``𝔽 ∈ \{ℝ, β„‚\}``, +``β‹…^{\mathrm{H}}`` denotes the complex conjugate transpose or Hermitian, and +``I_k ∈ ℝ^{kΓ—k}`` denotes the ``kΓ—k`` identity matrix. -The tangent space at a point $p ∈ \mathcal M$ is given by +The tangent space at a point ``p ∈ \mathcal M`` is given by ````math -T_p \mathcal M = \{ X ∈ 𝔽^{n Γ— k} : p^{\mathrm{H}}X + \overline{X^{\mathrm{H}}p} = 0_k\}, +T_p \mathcal M = \{ X ∈ 𝔽^{nΓ—k} : p^{\mathrm{H}}X + \overline{X^{\mathrm{H}}p} = 0_k\}, ```` -where $0_k$ is the $k Γ— k$ zero matrix and $\overline{β‹…}$ the (elementwise) complex conjugate. +where ``0_k`` is the ``kΓ—k`` zero matrix and ``\overline{β‹…}`` the (elementwise) complex conjugate. This manifold is modeled as an embedded manifold to the [`Euclidean`](@ref), i.e. several functions like the [`inner`](@ref inner(::Euclidean, ::Any...)) product and the @@ -29,7 +29,7 @@ The manifold is named after # Constructor Stiefel(n, k, field=ℝ; parameter::Symbol=:type) -Generate the (real-valued) Stiefel manifold of $n Γ— k$ dimensional orthonormal matrices. +Generate the (real-valued) Stiefel manifold of ``nΓ—k`` dimensional orthonormal matrices. """ struct Stiefel{T,𝔽} <: AbstractDecoratorManifold{𝔽} size::T @@ -77,8 +77,8 @@ end @doc raw""" check_point(M::Stiefel, p; kwargs...) -Check whether `p` is a valid point on the [`Stiefel`](@ref) `M`=$\operatorname{St}(n,k)$, i.e. that it has the right -[`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and $p^{\mathrm{H}}p$ is (approximately) the identity, where $β‹…^{\mathrm{H}}$ is the +Check whether `p` is a valid point on the [`Stiefel`](@ref) `M`=``\operatorname{St}(n,k)``, i.e. that it has the right +[`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and ``p^{\mathrm{H}}p`` is (approximately) the identity, where ``β‹…^{\mathrm{H}}`` is the complex conjugate transpose. The settings for approximately can be set with `kwargs...`. """ function check_point(M::Stiefel, p; kwargs...) @@ -98,9 +98,9 @@ end check_vector(M::Stiefel, p, X; kwargs...) Checks whether `X` is a valid tangent vector at `p` on the [`Stiefel`](@ref) -`M`=$\operatorname{St}(n,k)$, i.e. the [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) fits and -it (approximately) holds that $p^{\mathrm{H}}X + \overline{X^{\mathrm{H}}p} = 0$, -where $β‹…^{\mathrm{H}}$ denotes the Hermitian and $\overline{β‹…}$ the (elementwise) complex conjugate. +`M`=``\operatorname{St}(n,k)``, i.e. the [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) fits and +it (approximately) holds that ``p^{\mathrm{H}}X + \overline{X^{\mathrm{H}}p} = 0``, +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian and ``\overline{β‹…}`` the (elementwise) complex conjugate. The settings for approximately can be set with `kwargs...`. """ function check_vector(M::Stiefel, p, X; kwargs...) @@ -163,8 +163,8 @@ This follows the folloing approach: From the Polar retraction we know that \operatorname{retr}_p^{-1}q = qs - t ```` -if such a symmetric positive definite $k Γ— k$ matrix exists. Since $qs - t$ -is also a tangent vector at $p$ we obtain +if such a symmetric positive definite ``kΓ—k`` matrix exists. Since ``qs - t`` +is also a tangent vector at ``p`` we obtain ````math p^{\mathrm{H}}qs + s(p^{\mathrm{H}}q)^{\mathrm{H}} + 2I_k = 0, @@ -318,7 +318,7 @@ is_flat(M::Stiefel) = manifold_dimension(M) == 1 @doc raw""" manifold_dimension(M::Stiefel) -Return the dimension of the [`Stiefel`](@ref) manifold `M`=$\operatorname{St}(n,k,𝔽)$. +Return the dimension of the [`Stiefel`](@ref) manifold `M`=``\operatorname{St}(n,k,𝔽)``. The dimension is given by ````math @@ -390,15 +390,15 @@ the formula reads \operatorname{retr}_pX = \Bigl(I - \frac{1}{2}W_{p,X}\Bigr)^{-1}\Bigl(I + \frac{1}{2}W_{p,X}\Bigr)p. ```` -It is implemented as the case $m=1$ of the `PadeRetraction`. +It is implemented as the case ``m=1`` of the `PadeRetraction`. """ retract(::Stiefel, ::Any, ::Any, ::CayleyRetraction) @doc raw""" retract(M::Stiefel, p, X, ::PadeRetraction{m}) -Compute the retraction on the [`Stiefel`](@ref) manifold `M` based on the PadΓ© approximation of order $m$ [ZhuDuan:2018](@cite). -Let $p_m$ and $q_m$ be defined for any matrix $A ∈ ℝ^{nΓ—x}$ as +Compute the retraction on the [`Stiefel`](@ref) manifold `M` based on the PadΓ© approximation of order ``m`` [ZhuDuan:2018](@cite). +Let ``p_m`` and ``q_m`` be defined for any matrix ``A ∈ ℝ^{nΓ—x}`` as ````math p_m(A) = \sum_{k=0}^m \frac{(2m-k)!m!}{(2m)!(m-k)!}\frac{A^k}{k!} @@ -410,7 +410,7 @@ and q_m(A) = \sum_{k=0}^m \frac{(2m-k)!m!}{(2m)!(m-k)!}\frac{(-A)^k}{k!} ```` -respectively. Then the PadΓ© approximation (of the matrix exponential $\exp(A)$) reads +respectively. Then the PadΓ© approximation (of the matrix exponential ``\exp(A)``) reads ````math r_m(A) = q_m(A)^{-1}p_m(A) @@ -436,7 +436,7 @@ retract(::Stiefel, ::Any, ::Any, ::PadeRetraction) retract(M::Stiefel, p, X, ::PolarRetraction) Compute the SVD-based retraction [`PolarRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.PolarRetraction) on the -[`Stiefel`](@ref) manifold `M`. With $USV = p + X$ the retraction reads +[`Stiefel`](@ref) manifold `M`. With ``USV = p + X`` the retraction reads ````math \operatorname{retr}_p X = U\bar{V}^\mathrm{H}. @@ -448,23 +448,23 @@ retract(::Stiefel, ::Any, ::Any, ::PolarRetraction) retract(M::Stiefel, p, X, ::QRRetraction) Compute the QR-based retraction [`QRRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.QRRetraction) on the -[`Stiefel`](@ref) manifold `M`. With $QR = p + X$ the retraction reads +[`Stiefel`](@ref) manifold `M`. With ``QR = p + X`` the retraction reads ````math \operatorname{retr}_p X = QD, ```` -where $D$ is a $n Γ— k$ matrix with +where ``D`` is a ``nΓ—k`` matrix with ````math D = \operatorname{diag}\bigl(\operatorname{sgn}(R_{ii}+0,5)_{i=1}^k \bigr), ```` -where $\operatorname{sgn}(p) = \begin{cases} +where ``\operatorname{sgn}(p) = \begin{cases} 1 & \text{ for } p > 0,\\ 0 & \text{ for } p = 0,\\ -1& \text{ for } p < 0. -\end{cases}$ +\end{cases}`` """ retract(::Stiefel, ::Any, ::Any, ::QRRetraction) @@ -509,7 +509,7 @@ end @doc raw""" representation_size(M::Stiefel) -Returns the representation size of the [`Stiefel`](@ref) `M`=$\operatorname{St}(n,k)$, +Returns the representation size of the [`Stiefel`](@ref) `M`=``\operatorname{St}(n,k)``, i.e. `(n,k)`, which is the matrix dimensions. """ representation_size(M::Stiefel) = get_parameter(M.size) @@ -561,7 +561,7 @@ with ```` Since this is the differentiated retraction as a vector transport, the result will be in the -tangent space at $q=\operatorname{retr}_p(d)$ using the [`CayleyRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.CayleyRetraction). +tangent space at ``q=\operatorname{retr}_p(d)`` using the [`CayleyRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.CayleyRetraction). """ vector_transport_direction( M::Stiefel, @@ -581,7 +581,7 @@ Compute the vector transport by computing the push forward of T_{p,d}^{\text{Pol}}(X) = q*Ξ› + (I-qq^{\mathrm{T}})X(1+d^\mathrm{T}d)^{-\frac{1}{2}}, ``` -where $q = \operatorname{retr}^{\mathrm{Pol}}_p(d)$, and $Ξ›$ is the unique solution of the Sylvester equation +where ``q = \operatorname{retr}^{\mathrm{Pol}}_p(d)``, and ``Ξ›`` is the unique solution of the Sylvester equation ```math Ξ›(I+d^\mathrm{T}d)^{\frac{1}{2}} + (I + d^\mathrm{T}d)^{\frac{1}{2}} = q^\mathrm{T}X - X^\mathrm{T}q @@ -604,8 +604,8 @@ See [AbsilMahonySepulchre:2008](@cite), p. 173, or Section 3.5 of [Zhu:2016](@c ```math T_{p,d}^{\text{QR}}(X) = q*\rho_{\mathrm{s}}(q^\mathrm{T}XR^{-1}) + (I-qq^{\mathrm{T}})XR^{-1}, ``` -where $q = \operatorname{retr}^{\mathrm{QR}}_p(d)$, $R$ is the $R$ factor of the QR -decomposition of $p + d$, and +where ``q = \operatorname{retr}^{\mathrm{QR}}_p(d)``, ``R`` is the ``R`` factor of the QR +decomposition of ``p + d``, and ```math \bigl( \rho_{\mathrm{s}}(A) \bigr)_{ij} = \begin{cases} @@ -665,8 +665,8 @@ Section 4 of [HuangGallivanAbsil:2015](@cite) or Section 3.5 of [Zhu:2016](@cit T_{q\gets p}^{\text{Pol}}(X) = q*Ξ› + (I-qq^{\mathrm{T}})X(1+d^\mathrm{T}d)^{-\frac{1}{2}}, ``` -where $d = \bigl( \operatorname{retr}^{\mathrm{Pol}}_p\bigr)^{-1}(q)$, -and $Ξ›$ is the unique solution of the Sylvester equation +where ``d = \bigl( \operatorname{retr}^{\mathrm{Pol}}_p\bigr)^{-1}(q)``, +and ``Ξ›`` is the unique solution of the Sylvester equation ```math Ξ›(I+d^\mathrm{T}d)^{\frac{1}{2}} + (I + d^\mathrm{T}d)^{\frac{1}{2}} = q^\mathrm{T}X - X^\mathrm{T}q @@ -690,8 +690,8 @@ see [AbsilMahonySepulchre:2008](@cite), p. 173, or Section 3.5 of [Zhu:2016](@c ```math T_{q \gets p}^{\text{QR}}(X) = q*\rho_{\mathrm{s}}(q^\mathrm{T}XR^{-1}) + (I-qq^{\mathrm{T}})XR^{-1}, ``` -where $d = \bigl(\operatorname{retr}^{\mathrm{QR}}\bigr)^{-1}_p(q)$, $R$ is the $R$ factor of the QR -decomposition of $p+X$, and +where ``d = \bigl(\operatorname{retr}^{\mathrm{QR}}\bigr)^{-1}_p(q)``, ``R`` is the ``R`` factor of the QR +decomposition of ``p+X``, and ```math \bigl( \rho_{\mathrm{s}}(A) \bigr)_{ij} = \begin{cases} diff --git a/src/manifolds/StiefelEuclideanMetric.jl b/src/manifolds/StiefelEuclideanMetric.jl index 304bb124c3..16c07ef16c 100644 --- a/src/manifolds/StiefelEuclideanMetric.jl +++ b/src/manifolds/StiefelEuclideanMetric.jl @@ -19,7 +19,7 @@ emanating from `p` in tangent direction `X`. where $\operatorname{Exp}$ denotes matrix exponential, $β‹…^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and $I_k$ and -$0_k$ are the identity matrix and the zero matrix of dimension $k Γ— k$, respectively. +$0_k$ are the identity matrix and the zero matrix of dimension $kΓ—k$, respectively. """ exp(::Stiefel, ::Any...) diff --git a/src/manifolds/StiefelSubmersionMetric.jl b/src/manifolds/StiefelSubmersionMetric.jl index 601db4d684..52d2b7d746 100644 --- a/src/manifolds/StiefelSubmersionMetric.jl +++ b/src/manifolds/StiefelSubmersionMetric.jl @@ -292,15 +292,15 @@ end @doc raw""" StiefelFactorization{UT,XT} <: AbstractManifoldPoint -Represent points (and vectors) on `Stiefel(n, k)` with ``2k Γ— k`` factors [ZimmermannHueper:2022](@cite). +Represent points (and vectors) on `Stiefel(n, k)` with ``2kΓ—k`` factors [ZimmermannHueper:2022](@cite). -Given a point ``p ∈ \mathrm{St}(n, k)`` and another matrix ``B ∈ ℝ^{n Γ— k}`` for +Given a point ``p ∈ \mathrm{St}(n, k)`` and another matrix ``B ∈ ℝ^{nΓ—k}`` for ``k ≀ \lfloor\frac{n}{2}\rfloor`` the factorization is ````math \begin{aligned} B &= UZ\\ U &= \begin{bmatrix}p & Q\end{bmatrix} ∈ \mathrm{St}(n, 2k)\\ -Z &= \begin{bmatrix}Z_1 \\ Z_2\end{bmatrix}, \quad Z_1,Z_2 ∈ ℝ^{k Γ— k}. +Z &= \begin{bmatrix}Z_1 \\ Z_2\end{bmatrix}, \quad Z_1,Z_2 ∈ ℝ^{kΓ—k}. \end{aligned} ```` If ``B ∈ \mathrm{St}(n, k)``, then ``Z ∈ \mathrm{St}(2k, k)``. @@ -310,7 +310,7 @@ For a fixed ``U``, if ``r ∈ \mathrm{St}(n, k)`` has the factor ``Z_r ∈ \math then ``X_r ∈ T_r \mathrm{St}(n, k)`` has the factor ``Z_{X_r} ∈ T_{Z_r} \mathrm{St}(2k, k)``. -``Q`` is determined by choice of a second matrix ``A ∈ ℝ^{n Γ— k}`` with the decomposition +``Q`` is determined by choice of a second matrix ``A ∈ ℝ^{nΓ—k}`` with the decomposition ````math \begin{aligned} A &= UZ\\ @@ -325,7 +325,7 @@ This factorization is useful because it is closed under addition, subtraction, s projection, and the Riemannian exponential and logarithm under the [`StiefelSubmersionMetric`](@ref). That is, if all matrices involved are factorized to have the same ``U``, then all of these operations and any algorithm that depends only on them can -be performed in terms of the ``2k Γ— k`` matrices ``Z``. For ``n ≫ k``, this can be much more +be performed in terms of the ``2kΓ—k`` matrices ``Z``. For ``n ≫ k``, this can be much more efficient than working with the full matrices. !!! warning diff --git a/src/manifolds/Symmetric.jl b/src/manifolds/Symmetric.jl index 02381510be..5f0a982e24 100644 --- a/src/manifolds/Symmetric.jl +++ b/src/manifolds/Symmetric.jl @@ -2,15 +2,15 @@ SymmetricMatrices{n,𝔽} <: AbstractDecoratorManifold{𝔽} The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) ``\operatorname{Sym}(n)`` consisting of the real- or complex-valued -symmetric matrices of size ``n Γ— n``, i.e. the set +symmetric matrices of size ``nΓ—n``, i.e. the set ````math -\operatorname{Sym}(n) = \bigl\{p ∈ 𝔽^{n Γ— n}\ \big|\ p^{\mathrm{H}} = p \bigr\}, +\operatorname{Sym}(n) = \bigl\{p ∈ 𝔽^{nΓ—n}\ \big|\ p^{\mathrm{H}} = p \bigr\}, ```` where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transpose, and the field ``𝔽 ∈ \{ ℝ, β„‚\}``. -Though it is slightly redundant, usually the matrices are stored as ``n Γ— n`` arrays. +Though it is slightly redundant, usually the matrices are stored as ``nΓ—n`` arrays. Note that in this representation, the complex valued case has to have a real-valued diagonal, which is also reflected in the [`manifold_dimension`](@ref manifold_dimension(::SymmetricMatrices)). @@ -19,7 +19,7 @@ which is also reflected in the [`manifold_dimension`](@ref manifold_dimension(:: SymmetricMatrices(n::Int, field::AbstractNumbers=ℝ) -Generate the manifold of ``n Γ— n`` symmetric matrices. +Generate the manifold of ``nΓ—n`` symmetric matrices. """ struct SymmetricMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} size::T diff --git a/src/manifolds/SymmetricPositiveDefinite.jl b/src/manifolds/SymmetricPositiveDefinite.jl index 13b58b171b..746ea87dfd 100644 --- a/src/manifolds/SymmetricPositiveDefinite.jl +++ b/src/manifolds/SymmetricPositiveDefinite.jl @@ -6,7 +6,7 @@ The manifold of symmetric positive definite matrices, i.e. ````math \mathcal P(n) = \bigl\{ -p ∈ ℝ^{n Γ— n}\ \big|\ a^\mathrm{T}pa > 0 \text{ for all } a ∈ ℝ^{n}\backslash\{0\} +p ∈ ℝ^{nΓ—n}\ \big|\ a^\mathrm{T}pa > 0 \text{ for all } a ∈ ℝ^{n}\backslash\{0\} \bigr\} ```` @@ -24,7 +24,7 @@ i.e. the set of symmetric matrices, SymmetricPositiveDefinite(n; parameter::Symbol=:type) -generates the manifold $\mathcal P(n) \subset ℝ^{n Γ— n}$ +generates the manifold $\mathcal P(n) \subset ℝ^{nΓ—n}$ """ struct SymmetricPositiveDefinite{T} <: AbstractDecoratorManifold{ℝ} size::T @@ -466,7 +466,7 @@ end representation_size(M::SymmetricPositiveDefinite) Return the size of an array representing an element on the -[`SymmetricPositiveDefinite`](@ref) manifold `M`, i.e. $n Γ— n$, the size of such a +[`SymmetricPositiveDefinite`](@ref) manifold `M`, i.e. $nΓ—n$, the size of such a symmetric positive definite matrix on $\mathcal M = \mathcal P(n)$. """ function representation_size(M::SymmetricPositiveDefinite) diff --git a/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl b/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl index 435d95ece6..e72804ecf5 100644 --- a/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl +++ b/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl @@ -2,11 +2,11 @@ SymmetricPositiveSemidefiniteFixedRank{T,𝔽} <: AbstractDecoratorManifold{𝔽} The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) $ \operatorname{SPS}_k(n)$ consisting of the real- or complex-valued -symmetric positive semidefinite matrices of size $n Γ— n$ and rank $k$, i.e. the set +symmetric positive semidefinite matrices of size $nΓ—n$ and rank $k$, i.e. the set ````math \operatorname{SPS}_k(n) = \bigl\{ -p ∈ 𝔽^{n Γ— n}\ \big|\ p^{\mathrm{H}} = p, +p ∈ 𝔽^{nΓ—n}\ \big|\ p^{\mathrm{H}} = p, apa^{\mathrm{H}} \geq 0 \text{ for all } a ∈ 𝔽 \text{ and } \operatorname{rank}(p) = k\bigr\}, ```` @@ -15,17 +15,17 @@ and the field $𝔽 ∈ \{ ℝ, β„‚\}$. We sometimes $\operatorname{SPS}_{k,𝔽}(n)$, when distinguishing the real- and complex-valued manifold is important. -An element is represented by $q ∈ 𝔽^{n Γ— k}$ from the factorization $p = qq^{\mathrm{H}}$. -Note that since for any unitary (orthogonal) $A ∈ 𝔽^{n Γ— n}$ we have +An element is represented by $q ∈ 𝔽^{nΓ—k}$ from the factorization $p = qq^{\mathrm{H}}$. +Note that since for any unitary (orthogonal) $A ∈ 𝔽^{nΓ—n}$ we have $(Aq)(Aq)^{\mathrm{H}} = qq^{\mathrm{H}} = p$, the representation is not unique, or in -other words, the manifold is a quotient manifold of $𝔽^{n Γ— k}$. +other words, the manifold is a quotient manifold of $𝔽^{nΓ—k}$. The tangent space at $p$, $T_p\operatorname{SPS}_k(n)$, is also represented -by matrices $Y ∈ 𝔽^{n Γ— k}$ and reads as +by matrices $Y ∈ 𝔽^{nΓ—k}$ and reads as ````math T_p\operatorname{SPS}_k(n) = \bigl\{ -X ∈ 𝔽^{n Γ— n}\,|\,X = qY^{\mathrm{H}} + Yq^{\mathrm{H}} +X ∈ 𝔽^{nΓ—n}\,|\,X = qY^{\mathrm{H}} + Yq^{\mathrm{H}} \text{ i.e. } X = X^{\mathrm{H}} \bigr\}. ```` @@ -37,7 +37,7 @@ The metric was used in [JourneeBachAbsilSepulchre:2010](@cite)[MassartAbsil:2020 SymmetricPositiveSemidefiniteFixedRank(n::Int, k::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) -Generate the manifold of $n Γ— n$ symmetric positive semidefinite matrices of rank $k$ +Generate the manifold of $nΓ—n$ symmetric positive semidefinite matrices of rank $k$ over the `field` of real numbers `ℝ` or complex numbers `β„‚`. """ struct SymmetricPositiveSemidefiniteFixedRank{T,𝔽} <: AbstractDecoratorManifold{𝔽} diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index 0328f20ac3..02017ff4b3 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -2,10 +2,10 @@ Symplectic{T, 𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType} The symplectic manifold consists of all ``2nΓ—2n`` matrices which preserve -the canonical symplectic form over ``𝔽^{2n Γ— 2n}×𝔽^{2n Γ— 2n}``, +the canonical symplectic form over ``𝔽^{2nΓ—2n}×𝔽^{2nΓ—2n}``, ```math - \omega\colon 𝔽^{2n Γ— 2n}×𝔽^{2n Γ— 2n} β†’ 𝔽, - \quad \omega(x, y) = p^{\mathrm{T}} J_{2n} q, \ x, y \in 𝔽^{2n Γ— 2n}, + \omega\colon 𝔽^{2nΓ—2n}×𝔽^{2nΓ—2n} β†’ 𝔽, + \quad \omega(x, y) = p^{\mathrm{T}} J_{2n} q, \ x, y \in 𝔽^{2nΓ—2n}, ``` where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). @@ -13,7 +13,7 @@ where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes The symplectic manifold consists of ```math -\mathrm{Sp}(2n, ℝ) = \bigl\{ p ∈ ℝ^{2n Γ— 2n} \, \big| \, p^{\mathrm{T}}J_{2n}p = J_{2n} \bigr\}, +\mathrm{Sp}(2n, ℝ) = \bigl\{ p ∈ ℝ^{2nΓ—2n} \, \big| \, p^{\mathrm{T}}J_{2n}p = J_{2n} \bigr\}, ``` The tangent space at a point ``p`` is given by [BendokatZimmermann:2021](@cite) @@ -22,7 +22,7 @@ The tangent space at a point ``p`` is given by [BendokatZimmermann:2021](@cite) \begin{align*} T_p\mathrm{Sp}(2n) &= \{X \in ℝ^{2nΓ—2n} \ |\ p^{T}J_{2n}X + X^{T}J_{2n}p = 0 \}, \\ - &= \{X = pJ_{2n}S \ \mid\ S ∈ R^{2n Γ— 2n}, S^{\mathrm{T}} = S \}. + &= \{X = pJ_{2n}S \ \mid\ S ∈ R^{2nΓ—2n}, S^{\mathrm{T}} = S \}. \end{align*} ``` @@ -30,9 +30,9 @@ The tangent space at a point ``p`` is given by [BendokatZimmermann:2021](@cite) Symplectic(2n, field=ℝ; parameter::Symbol=:type) -Generate the (real-valued) symplectic manifold of ``2n Γ— 2n`` symplectic matrices. +Generate the (real-valued) symplectic manifold of ``2nΓ—2n`` symplectic matrices. The constructor for the [`Symplectic`](@ref) manifold accepts the even column/row embedding -dimension ``2n`` for the real symplectic manifold, ``ℝ^{2n Γ— 2n}``. +dimension ``2n`` for the real symplectic manifold, ``ℝ^{2nΓ—2n}``. """ struct Symplectic{T,𝔽} <: AbstractDecoratorManifold{𝔽} size::T @@ -74,7 +74,7 @@ as an inner product over the embedding space ``ℝ^{2nΓ—2n}``, i.e. ```math ⟨x, y⟩_p = ⟨p^{-1}x, p^{-1}⟩_{\mathrm{Fr}} - = \operatorname{tr}(x^{\mathrm{T}}(pp^{\mathrm{T}})^{-1}y), \text{ for all } x, y \in ℝ^{2n Γ— 2n}. + = \operatorname{tr}(x^{\mathrm{T}}(pp^{\mathrm{T}})^{-1}y), \text{ for all } x, y \in ℝ^{2nΓ—2n}. ``` """ struct ExtendedSymplecticMetric <: AbstractMetric end @@ -89,7 +89,7 @@ representation of the canonical symplectic form, J_{2n}(Ξ») = Ξ»\begin{bmatrix} 0_n & I_n \\ -I_n & 0_n -\end{bmatrix} ∈ ℝ^{2n Γ— 2n}, +\end{bmatrix} ∈ ℝ^{2nΓ—2n}, ``` where we write ``J_{2n} = J_{2n}(1)`` for short. @@ -436,7 +436,7 @@ end Given a matrix ```math - A ∈ ℝ^{2n Γ— 2k},\quad + A ∈ ℝ^{2nΓ—2k},\quad A = \begin{bmatrix} A_{1,1} & A_{1,2} \\ @@ -489,7 +489,7 @@ end inv(::Symplectic, A) inv!(::Symplectic, A) -Compute the symplectic inverse ``A^+`` of matrix ``A ∈ ℝ^{2n Γ— 2n}``. +Compute the symplectic inverse ``A^+`` of matrix ``A ∈ ℝ^{2nΓ—2n}``. See [`symplectic_inverse`](@ref) for details. """ @@ -597,7 +597,7 @@ which solves the constrained optimization problem \text{such that}\; h(X) := X^{\mathrm{T}} J_{2n} p + p^{\mathrm{T}} J_{2n} X = 0, ```` -where ``h: ℝ^{2n Γ— 2n} β†’ \operatorname{skew}(2n)`` denotes +where ``h: ℝ^{2nΓ—2n} β†’ \operatorname{skew}(2n)`` denotes the restriction of ``X`` onto the tangent space ``T_p\operatorname{SpSt}(2n, 2k)`` and ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). """ @@ -613,7 +613,7 @@ function project!(::Symplectic, Y, p, A) end # Solve for Ξ› (Lagrange mutliplier): - pT_p = p' * p # (2k Γ— 2k) + pT_p = p' * p # (2kΓ—2k) Ξ› = sylvester(pT_p, pT_p, h(A) ./ 2) Y[:, :] = A .- Jp * (Ξ› .- Ξ›') @@ -623,7 +623,7 @@ end @doc raw""" project!(::MetricManifold{𝔽,<:Euclidean,ExtendedSymplecticMetric}, Y, p, X) where {𝔽} -Compute the projection of ``X ∈ R^{2n Γ— 2n}`` onto ``T_p\mathrm{Sp}(2n, ℝ)`` with respect to +Compute the projection of ``X ∈ R^{2nΓ—2n}`` onto ``T_p\mathrm{Sp}(2n, ℝ)`` with respect to the [`RealSymplecticMetric`](@ref) ``g``. The closed form projection mapping is given by [GaoSonAbsilStykel:2021](@cite) @@ -654,7 +654,7 @@ That is, ````math (T_p\mathrm{Sp}(2n))^{\perp_g} - = \{Y ∈ ℝ^{2n Γ— 2n} : g_p(Y, X) = 0 \test{ for all } X \in T_p\mathrm{Sp}(2n)\}. + = \{Y ∈ ℝ^{2nΓ—2n} : g_p(Y, X) = 0 \test{ for all } X \in T_p\mathrm{Sp}(2n)\}. ```` The closed form projection operator onto the normal space is given by [GaoSonAbsilStykel:2021](@cite) diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 63a485b227..35d2e8d037 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -13,7 +13,7 @@ This manifold can be represented as corresponding representers on the [`Symplect or as projectors ```math -\operatorname{SpGr}(2n, 2k, ℝ) = \bigl\{ p ∈ ℝ^{2n Γ— 2n} \ \big| \ p^2 = p, \operatorname{rank}(p) = 2k, p^+=p \bigr\}, +\operatorname{SpGr}(2n, 2k, ℝ) = \bigl\{ p ∈ ℝ^{2nΓ—2n} \ \big| \ p^2 = p, \operatorname{rank}(p) = 2k, p^+=p \bigr\}, ``` where ``β‹…^+`` is the [`symplectic_inverse`](@ref). diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index d539155ebd..b6f6391948 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -2,11 +2,11 @@ SymplecticStiefel{T,𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType} The symplectic Stiefel manifold consists of all -``2n Γ— 2k, n β‰₯ k`` matrices satisfying the requirement +``2nΓ—2k, n β‰₯ k`` matrices satisfying the requirement ````math \mathrm{SpSt}(2n, 2k, ℝ) - := \bigl\{ p ∈ ℝ^{2n Γ— 2n} \ \big| \ p^{\mathrm{T}}J_{2n}p = J_{2k} \bigr\}, + := \bigl\{ p ∈ ℝ^{2nΓ—2n} \ \big| \ p^{\mathrm{T}}J_{2n}p = J_{2k} \bigr\}, ```` where ``J_{2n}`` denotes the [`SymplecticMatrix`](@ref) @@ -20,10 +20,10 @@ The symplectic Stiefel tangent space at ``p`` can be parametrized as [BendokatZi ```math \begin{align*} T_p\mathrm{SpSt}(2n, 2k) - &= \{X ∈ ℝ^{2n Γ— 2k} ∣ p^{T}J_{2n}X + X^{T}J_{2n}p = 0 \}, \\ + &= \{X ∈ ℝ^{2nΓ—2k} ∣ p^{T}J_{2n}X + X^{T}J_{2n}p = 0 \}, \\ &= \{X = pΞ© + p^sB \mid - Ξ© ∈ ℝ^{2k Γ— 2k}, Ξ©^+ = -Ξ©, \\ - &\qquad & p^s ∈ \mathrm{SpSt}(2n, 2(n- k)), B ∈ ℝ^{2(n-k) Γ— 2k}, \}, + Ξ© ∈ ℝ^{2kΓ—2k}, Ξ©^+ = -Ξ©, \\ + &\qquad & p^s ∈ \mathrm{SpSt}(2n, 2(n- k)), B ∈ ℝ^{2(n-k)Γ—2k}, \}, \end{align*} ``` @@ -41,7 +41,7 @@ Generate the (real-valued) symplectic Stiefel manifold of ``2nΓ—2k`` matrices which span a ``2k`` dimensional symplectic subspace of ``ℝ^{2nΓ—2n}``. The constructor for the [`SymplecticStiefel`](@ref) manifold accepts the even column dimension ``2n`` and an even number of columns ``2k`` for -the real symplectic Stiefel manifold with elements ``p ∈ ℝ^{2n Γ— 2k}``. +the real symplectic Stiefel manifold with elements ``p ∈ ℝ^{2nΓ—2k}``. """ struct SymplecticStiefel{T,𝔽} <: AbstractDecoratorManifold{𝔽} size::T @@ -129,7 +129,7 @@ check_vector(::SymplecticStiefel, ::Any...) function check_vector(M::SymplecticStiefel{S,𝔽}, p, X::T; kwargs...) where {S,T,𝔽} n, k = get_parameter(M.size) # From Bendokat-Zimmermann: T_pSpSt(2n, 2k) = \{p*H | H^{+} = -H \} - H = inv(M, p) * X # ∈ ℝ^{2k Γ— 2k}, should be Hamiltonian. + H = inv(M, p) * X # ∈ ℝ^{2kΓ—2k}, should be Hamiltonian. if !is_hamiltonian(H; kwargs...) return DomainError( @@ -226,9 +226,9 @@ exp(::SymplecticStiefel, p, X) function exp!(M::SymplecticStiefel, q, p, X) n, k = get_parameter(M.size) J = SymplecticMatrix(p, X) - pT_p = lu(p' * p) # ∈ ℝ^{2k Γ— 2k} + pT_p = lu(p' * p) # ∈ ℝ^{2kΓ—2k} - C = pT_p \ X' # ∈ ℝ^{2k Γ— 2n} + C = pT_p \ X' # ∈ ℝ^{2kΓ—2n} # Construct A-bar: # First A-term: J * (p^{\mathrm{T}} * C^{\mathrm{T}}) * J @@ -256,17 +256,17 @@ function exp!(M::SymplecticStiefel, q, p, X) Ξ”_bar = H_bar Ξ³_1 = Ξ”_bar - (1 / 2) .* p * symplectic_inverse_times(M, p, Ξ”_bar) - Ξ³ = [Ξ³_1 -p] # ∈ ℝ^{2n Γ— 4k} + Ξ³ = [Ξ³_1 -p] # ∈ ℝ^{2nΓ—4k} Ξ”_bar_star = rmul!(J' * Ξ”_bar', J) Ξ»_1 = lmul!(J', p * J) Ξ»_2 = (Ξ”_bar_star .- (1 / 2) .* (Ξ”_bar_star * p) * Ξ»_1')' - Ξ» = [Ξ»_1 Ξ»_2] # ∈ ℝ^{2n Γ— 4k} + Ξ» = [Ξ»_1 Ξ»_2] # ∈ ℝ^{2nΓ—4k} - Ξ“ = [Ξ» -Ξ³] # ∈ ℝ^{2n Γ— 8k} - Ξ› = [Ξ³ Ξ»] # ∈ ℝ^{2n Γ— 8k} + Ξ“ = [Ξ» -Ξ³] # ∈ ℝ^{2nΓ—8k} + Ξ› = [Ξ³ Ξ»] # ∈ ℝ^{2nΓ—8k} - # At last compute the (8k Γ— 8k) and (4k Γ— 4k) matrix exponentials: + # At last compute the (8kΓ—8k) and (4kΓ—4k) matrix exponentials: q .= Ξ“ * (exp(Ξ›' * Ξ“)[:, (4k + 1):end]) * (exp(Ξ»' * Ξ³)[:, (2k + 1):end]) return q end @@ -323,15 +323,15 @@ end inv(::SymplecticStiefel, A) inv!(::SymplecticStiefel, q, p) -Compute the symplectic inverse ``A^+`` of matrix ``A ∈ ℝ^{2n Γ— 2k}``. +Compute the symplectic inverse ``A^+`` of matrix ``A ∈ ℝ^{2nΓ—2k}``. Given a matrix ````math -A ∈ ℝ^{2n Γ— 2k},\quad +A ∈ ℝ^{2nΓ—2k},\quad A = \begin{bmatrix} A_{1, 1} & A_{1, 2} \\ A_{2, 1} & A_{2, 2} -\end{bmatrix}, \quad A_{i, j} ∈ ℝ^{2n Γ— 2k} +\end{bmatrix}, \quad A_{i, j} ∈ ℝ^{2nΓ—2k} ```` the symplectic inverse is defined as: @@ -462,7 +462,7 @@ function project!(::SymplecticStiefel, Y, p, A) end # Solve for Ξ› (Lagrange mutliplier): - pT_p = p' * p # (2k Γ— 2k) + pT_p = p' * p # (2kΓ—2k) Ξ› = sylvester(pT_p, pT_p, h(A) ./ 2) Y[:, :] = A .- Jp * (Ξ› .- Ξ›') @@ -550,7 +550,7 @@ function retract_cayley!(M::SymplecticStiefel, q, p, X, t::Number) # Define intermediate matrices for later use: A = symplectic_inverse_times(M, p, tX) - H = tX .- p * A # Allocates (2n Γ— 2k). + H = tX .- p * A # Allocates (2nΓ—2k). # A = I - A/2 + H^{+}H/4: A .= (symplectic_inverse_times(M, H, H) ./ 4) .- (A ./ 2) diff --git a/src/utils.jl b/src/utils.jl index 41a0c97d73..c45413cd42 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -2,7 +2,7 @@ @doc raw""" usinc(ΞΈ::Real) -Unnormalized version of `sinc` function, i.e. $\operatorname{usinc}(ΞΈ) = \frac{\sin(ΞΈ)}{ΞΈ}$. +Unnormalized version of `sinc` function, i.e. ``\operatorname{usinc}(ΞΈ) = \frac{\sin(ΞΈ)}{ΞΈ}``. This is equivalent to `sinc(ΞΈ/Ο€)`. """ @inline usinc(ΞΈ::Real) = ΞΈ == 0 ? one(ΞΈ) : isinf(ΞΈ) ? zero(ΞΈ) : sin(ΞΈ) / ΞΈ @@ -10,8 +10,8 @@ This is equivalent to `sinc(ΞΈ/Ο€)`. @doc raw""" usinc_from_cos(x::Real) -Unnormalized version of `sinc` function, i.e. $\operatorname{usinc}(ΞΈ) = \frac{\sin(ΞΈ)}{ΞΈ}$, -computed from $x = cos(ΞΈ)$. +Unnormalized version of `sinc` function, i.e. ``\operatorname{usinc}(ΞΈ) = \frac{\sin(ΞΈ)}{ΞΈ}``, +computed from ``x = cos(ΞΈ)``. """ @inline function usinc_from_cos(x::Real) return if x >= 1 @@ -140,15 +140,15 @@ mul!_safe(Y, A, B) = (Y === A || Y === B) ? copyto!(Y, A * B) : mul!(Y, A, B) @doc raw""" realify(X::AbstractMatrix{T𝔽}, 𝔽::AbstractNumbers) -> Y::AbstractMatrix{<:Real} -Given a matrix $X ∈ 𝔽^{n Γ— n}$, compute $Y ∈ ℝ^{m Γ— m}$, where $m = n \operatorname{dim}_𝔽$, -and $\operatorname{dim}_𝔽$ is the [`real_dimension`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.real_dimension-Tuple{ManifoldsBase.AbstractNumbers}) of the number field $𝔽$, using -the map $Ο• \colon X ↦ Y$, that preserves the matrix product, so that for all -$C,D ∈ 𝔽^{n Γ— n}$, +Given a matrix ``X ∈ 𝔽^{nΓ—n}``, compute ``Y ∈ ℝ^{mΓ—m}``, where ``m = n \operatorname{dim}_𝔽``, +and ``\operatorname{dim}_𝔽`` is the [`real_dimension`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.real_dimension-Tuple{ManifoldsBase.AbstractNumbers}) of the number field ``𝔽``, using +the map ``Ο• \colon X ↦ Y``, that preserves the matrix product, so that for all +``C,D ∈ 𝔽^{nΓ—n}``, ````math Ο•(C) Ο•(D) = Ο•(CD). ```` See [`realify!`](@ref) for an in-place version, and [`unrealify!`](@ref) to compute the -inverse of $Ο•$. +inverse of ``Ο•``. """ function realify(X, 𝔽) n = LinearAlgebra.checksquare(X) @@ -168,8 +168,8 @@ realify!(Y, X, 𝔽) @doc raw""" realify!(Y::AbstractMatrix{<:Real}, X::AbstractMatrix{<:Complex}, ::typeof(β„‚)) -Given a complex matrix $X = A + iB ∈ β„‚^{n Γ— n}$, compute its realified matrix -$Y ∈ ℝ^{2n Γ— 2n}$, written +Given a complex matrix ``X = A + iB ∈ β„‚^{nΓ—n}``, compute its realified matrix +``Y ∈ ℝ^{2nΓ—2n}``, written where ````math Y = \begin{pmatrix}A & -B \\ B & A \end{pmatrix}. @@ -188,10 +188,10 @@ end @doc raw""" unrealify!(X::AbstractMatrix{T𝔽}, Y::AbstractMatrix{<:Real}, 𝔽::AbstractNumbers[, n]) -Given a real matrix $Y ∈ ℝ^{m Γ— m}$, where $m = n \operatorname{dim}_𝔽$, and -$\operatorname{dim}_𝔽$ is the [`real_dimension`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.real_dimension-Tuple{ManifoldsBase.AbstractNumbers}) of the number field $𝔽$, compute -in-place its equivalent matrix $X ∈ 𝔽^{n Γ— n}$. Note that this function does not check that -$Y$ has a valid structure to be un-realified. +Given a real matrix ``Y ∈ ℝ^{mΓ—m}``, where ``m = n \operatorname{dim}_𝔽``, and +``\operatorname{dim}_𝔽`` is the [`real_dimension`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.real_dimension-Tuple{ManifoldsBase.AbstractNumbers}) of the number field ``𝔽``, compute +in-place its equivalent matrix ``X ∈ 𝔽^{nΓ—n}``. Note that this function does not check that +``Y`` has a valid structure to be un-realified. See [`realify!`](@ref) for the inverse of this function. """ @@ -229,7 +229,7 @@ end @doc raw""" vec2skew!(X, v, k) -create a skew symmetric matrix inplace in `X` of size $kΓ—k$ from a vector `v`, +create a skew symmetric matrix inplace in `X` of size ``kΓ—k`` from a vector `v`, for example for `v=[1,2,3]` and `k=3` this yields ````julia diff --git a/test/manifolds/symplectic.jl b/test/manifolds/symplectic.jl index e618d11968..af4cd95cd9 100644 --- a/test/manifolds/symplectic.jl +++ b/test/manifolds/symplectic.jl @@ -156,7 +156,7 @@ using ManifoldDiff proj_normal_X2 = Manifolds.project_normal!(Extended_Sp_2, copy(X2), p_2, X2) @test isapprox(proj_normal_X2, zero(X2); atol=1.0e-16) - # Project Project matrix A ∈ ℝ^{2 Γ— 2} onto (T_pSp): + # Project Project matrix A ∈ ℝ^{2Γ—2} onto (T_pSp): A_2 = [5.0 -21.5; 3.14 14.9] A_2_proj = similar(A_2) project!(Extended_Sp_2, A_2_proj, p_2, A_2) diff --git a/test/manifolds/symplecticstiefel.jl b/test/manifolds/symplecticstiefel.jl index ac851092eb..f54f55d128 100644 --- a/test/manifolds/symplecticstiefel.jl +++ b/test/manifolds/symplecticstiefel.jl @@ -218,7 +218,7 @@ end atol=1.0e-6, ) - # Project Project matrix A ∈ ℝ^{6 Γ— 4} onto (T_pSpSt): + # Project Project matrix A ∈ ℝ^{6Γ—4} onto (T_pSpSt): A_6_4 = Array{Float64}([ -7 2 12 0 4 0 1 -2 From 770bf765f8d83f33f2c7b0b2850edeb72e3317bc Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 12 Jan 2024 12:07:40 +0100 Subject: [PATCH 11/65] Rearrange code to avoid redefining functions. --- src/manifolds/MultinomialSymmetric.jl | 18 +++---- src/manifolds/Oblique.jl | 8 +-- src/manifolds/SphereSymmetricMatrices.jl | 10 ++-- src/manifolds/StiefelEuclideanMetric.jl | 32 ++++++------ src/manifolds/SymmetricPositiveDefinite.jl | 10 ++-- .../SymmetricPositiveSemidefiniteFixedRank.jl | 42 ++++++++-------- test/ambiguities.jl | 11 ++++ test/approx_inverse_retraction.jl | 2 +- test/differentiation.jl | 2 +- test/groups/circle_group.jl | 2 +- test/groups/connections.jl | 2 +- test/groups/general_linear.jl | 2 +- test/groups/general_unitary_groups.jl | 2 +- test/groups/group_operation_action.jl | 2 +- test/groups/groups_general.jl | 2 +- test/groups/heisenberg.jl | 2 +- test/groups/metric.jl | 2 +- test/groups/power_group.jl | 2 +- test/groups/product_group.jl | 2 +- test/groups/rotation_action.jl | 2 +- test/groups/rotation_translation_action.jl | 2 +- test/groups/semidirect_product_group.jl | 2 +- test/groups/special_euclidean.jl | 2 +- test/groups/special_linear.jl | 2 +- test/groups/special_orthogonal.jl | 2 +- test/groups/translation_action.jl | 2 +- test/groups/translation_group.jl | 2 +- test/groups/validation_group.jl | 2 +- test/header.jl | 24 +++++++++ test/manifolds/centered_matrices.jl | 2 +- test/manifolds/cholesky_space.jl | 2 +- test/manifolds/circle.jl | 2 +- test/manifolds/elliptope.jl | 2 +- test/manifolds/essential_manifold.jl | 2 +- test/manifolds/euclidean.jl | 2 +- test/manifolds/fiber.jl | 2 +- test/manifolds/fiber_bundle.jl | 2 +- test/manifolds/fixed_rank.jl | 2 +- test/manifolds/generalized_grassmann.jl | 2 +- test/manifolds/generalized_stiefel.jl | 2 +- test/manifolds/graph.jl | 2 +- test/manifolds/grassmann.jl | 2 +- test/manifolds/hyperbolic.jl | 2 +- test/manifolds/lorentz.jl | 2 +- .../multinomial_doubly_stochastic.jl | 2 +- test/manifolds/multinomial_matrices.jl | 2 +- test/manifolds/multinomial_symmetric.jl | 2 +- test/manifolds/oblique.jl | 2 +- test/manifolds/positive_numbers.jl | 2 +- test/manifolds/power_manifold.jl | 2 +- test/manifolds/probability_simplex.jl | 2 +- test/manifolds/product_manifold.jl | 2 +- test/manifolds/projective_space.jl | 2 +- test/manifolds/quotient_manifold.jl | 2 +- test/manifolds/rotations.jl | 2 +- test/manifolds/shape_space.jl | 2 +- test/manifolds/skewhermitian.jl | 2 +- test/manifolds/spd_fixed_determinant.jl | 2 +- test/manifolds/spectrahedron.jl | 2 +- test/manifolds/sphere.jl | 2 +- test/manifolds/sphere_symmetric_matrices.jl | 2 +- test/manifolds/stiefel.jl | 2 +- test/manifolds/symmetric.jl | 2 +- test/manifolds/symmetric_positive_definite.jl | 2 +- ...metric_positive_semidefinite_fixed_rank.jl | 2 +- test/manifolds/symplectic.jl | 2 +- test/manifolds/symplecticstiefel.jl | 2 +- test/manifolds/torus.jl | 2 +- test/manifolds/tucker.jl | 2 +- test/manifolds/unitary_matrices.jl | 2 +- test/manifolds/vector_bundle.jl | 2 +- test/metric.jl | 2 +- test/notation.jl | 2 +- test/recipes.jl | 2 +- test/runtests.jl | 9 +++- test/statistics.jl | 2 +- test/utils.jl | 50 ------------------- 77 files changed, 169 insertions(+), 179 deletions(-) create mode 100644 test/header.jl delete mode 100644 test/utils.jl diff --git a/src/manifolds/MultinomialSymmetric.jl b/src/manifolds/MultinomialSymmetric.jl index 23b178b368..110d782bf9 100644 --- a/src/manifolds/MultinomialSymmetric.jl +++ b/src/manifolds/MultinomialSymmetric.jl @@ -1,7 +1,7 @@ @doc raw""" MultinomialSymmetric{T} <: AbstractMultinomialDoublyStochastic{N} -The multinomial symmetric matrices manifold consists of all symmetric $nΓ—n$ matrices with +The multinomial symmetric matrices manifold consists of all symmetric ``nΓ—n`` matrices with positive entries such that each column sums to one, i.e. ````math @@ -13,7 +13,7 @@ positive entries such that each column sums to one, i.e. \end{aligned} ```` -where $\mathbf{1}_n$ is the vector of length $n$ containing ones. +where ``\mathbf{1}_n`` is the vector of length ``n`` containing ones. It is modeled as [`IsIsometricEmbeddedManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/decorator.html#ManifoldsBase.IsIsometricEmbeddedManifold). via the [`AbstractMultinomialDoublyStochastic`](@ref) type, since it shares a few functions @@ -29,7 +29,7 @@ X\mathbf{1}_n = \mathbf{0}_n \bigr\}, ```` -where $\mathbf{0}_n$ is the vector of length $n$ containing zeros. +where ``\mathbf{0}_n`` is the vector of length ``n`` containing zeros. More details can be found in Section IV [DouikHassibi:2019](@cite). @@ -37,7 +37,7 @@ More details can be found in Section IV [DouikHassibi:2019](@cite). MultinomialSymmetric(n) -Generate the manifold of matrices $\mathbb R^{nΓ—n}$ that are doubly stochastic and symmetric. +Generate the manifold of matrices ``\mathbb R^{nΓ—n}`` that are doubly stochastic and symmetric. """ struct MultinomialSymmetric{T} <: AbstractMultinomialDoublyStochastic size::T @@ -110,12 +110,12 @@ The formula reads ````math \operatorname{proj}_p(Y) = Y - (Ξ±\mathbf{1}_n^{\mathrm{T}} + \mathbf{1}_n Ξ±^{\mathrm{T}}) βŠ™ p, ```` -where $βŠ™$ denotes the Hadamard or elementwise product and $\mathbb{1}_n$ is the vector of length $n$ containing ones. -The two vector $Ξ± ∈ ℝ^{nΓ—n}$ is given by solving +where ``βŠ™`` denotes the Hadamard or elementwise product and ``\mathbb{1}_n`` is the vector of length ``n`` containing ones. +The two vector ``Ξ± ∈ ℝ^{nΓ—n}`` is given by solving ````math (I_n+p)Ξ± = Y\mathbf{1}, ```` -where $I_n$ is teh $nΓ—n$ unit matrix and $\mathbf{1}_n$ is the vector of length $n$ containing ones. +where ``I_n`` is teh ``nΓ—n`` unit matrix and ``\mathbf{1}_n`` is the vector of length ``n`` containing ones. """ project(::MultinomialSymmetric, ::Any, ::Any) @@ -133,8 +133,8 @@ end @doc raw""" retract(M::MultinomialSymmetric, p, X, ::ProjectionRetraction) -compute a projection based retraction by projecting $p\odot\exp(Xβ¨Έp)$ back onto the manifold, -where $βŠ™,β¨Έ$ are elementwise multiplication and division, respectively. Similarly, $\exp$ +compute a projection based retraction by projecting ``pβŠ™\exp(Xβ¨Έp)`` back onto the manifold, +where ``βŠ™,β¨Έ`` are elementwise multiplication and division, respectively. Similarly, ``\exp`` refers to the elementwise exponentiation. """ retract(::MultinomialSymmetric, ::Any, ::Any, ::ProjectionRetraction) diff --git a/src/manifolds/Oblique.jl b/src/manifolds/Oblique.jl index 5ca96de428..94407b7564 100644 --- a/src/manifolds/Oblique.jl +++ b/src/manifolds/Oblique.jl @@ -1,10 +1,10 @@ @doc raw""" Oblique{T,𝔽,S} <: AbstractPowerManifold{𝔽} -The oblique manifold $\mathcal{OB}(n,m)$ is the set of 𝔽-valued matrices with unit norm +The oblique manifold ``\mathcal{OB}(n,m)`` is the set of 𝔽-valued matrices with unit norm column endowed with the metric from the embedding. This yields exactly the same metric as considering the product metric of the unit norm vectors, i.e. [`PowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.PowerManifold) of the -$(n-1)$-dimensional [`Sphere`](@ref). +``(n-1)``-dimensional [`Sphere`](@ref). The [`Sphere`](@ref) is stored internally within `M.manifold`, such that all functions of [`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) can be used directly. @@ -13,7 +13,7 @@ The [`Sphere`](@ref) is stored internally within `M.manifold`, such that all fun Oblique(n::Int, m::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) -Generate the manifold of matrices $\mathbb R^{nΓ—m}$ such that the $m$ columns are unit +Generate the manifold of matrices ``\mathbb R^{nΓ—m}`` such that the ``m`` columns are unit vectors, i.e. from the [`Sphere`](@ref)`(n-1)`. """ struct Oblique{T,𝔽,S} <: AbstractPowerManifold{𝔽,Sphere{S,𝔽},ArrayPowerRepresentation} @@ -39,7 +39,7 @@ end check_point(M::Oblique, p) Checks whether `p` is a valid point on the [`Oblique`](@ref)`{m,n}` `M`, i.e. is a matrix -of `m` unit columns from $\mathbb R^{n}$, i.e. each column is a point from +of `m` unit columns from ``\mathbb R^{n}``, i.e. each column is a point from [`Sphere`](@ref)`(n-1)`. """ check_point(::Oblique, ::Any) diff --git a/src/manifolds/SphereSymmetricMatrices.jl b/src/manifolds/SphereSymmetricMatrices.jl index 1b691ef5cb..d023e881c7 100644 --- a/src/manifolds/SphereSymmetricMatrices.jl +++ b/src/manifolds/SphereSymmetricMatrices.jl @@ -1,13 +1,13 @@ @doc raw""" SphereSymmetricMatrices{T,𝔽} <: AbstractEmbeddedManifold{ℝ,TransparentIsometricEmbedding} -The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) consisting of the $nΓ—n$ symmetric matrices +The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) consisting of the ``nΓ—n`` symmetric matrices of unit Frobenius norm, i.e. ````math \mathcal{S}_{\text{sym}} :=\bigl\{p ∈ 𝔽^{nΓ—n}\ \big|\ p^{\mathrm{H}} = p, \lVert p \rVert = 1 \bigr\}, ```` -where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, -and the field $𝔽 ∈ \{ ℝ, β„‚\}$. +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transpose, +and the field ``𝔽 ∈ \{ ℝ, β„‚\}``. # Constructor SphereSymmetricMatrices(n[, field=ℝ]) @@ -119,7 +119,7 @@ Projects `p` from the embedding onto the [`SphereSymmetricMatrices`](@ref) `M`, ````math \operatorname{proj}_{\mathcal{S}_{\text{sym}}}(p) = \frac{1}{2} \bigl( p + p^{\mathrm{H}} \bigr), ```` -where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SphereSymmetricMatrices, ::Any) @@ -135,7 +135,7 @@ Project the matrix `X` onto the tangent space at `p` on the [`SphereSymmetricMat ````math \operatorname{proj}_p(X) = \frac{X + X^{\mathrm{H}}}{2} - ⟨p, \frac{X + X^{\mathrm{H}}}{2}⟩p, ```` -where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SphereSymmetricMatrices, ::Any, ::Any) diff --git a/src/manifolds/StiefelEuclideanMetric.jl b/src/manifolds/StiefelEuclideanMetric.jl index 16c07ef16c..9edc20aba3 100644 --- a/src/manifolds/StiefelEuclideanMetric.jl +++ b/src/manifolds/StiefelEuclideanMetric.jl @@ -17,9 +17,9 @@ emanating from `p` in tangent direction `X`. \begin{pmatrix} \exp( -p^{\mathrm{H}}X) \\ 0_n\end{pmatrix}, ```` -where $\operatorname{Exp}$ denotes matrix exponential, -$β‹…^{\mathrm{H}}$ denotes the complex conjugate transpose or Hermitian, and $I_k$ and -$0_k$ are the identity matrix and the zero matrix of dimension $kΓ—k$, respectively. +where ``\operatorname{Exp}`` denotes matrix exponential, +``β‹…^{\mathrm{H}}`` denotes the complex conjugate transpose or Hermitian, and ``I_k`` and +``0_k`` are the identity matrix and the zero matrix of dimension ``kΓ—k``, respectively. """ exp(::Stiefel, ::Any...) @@ -38,25 +38,25 @@ end @doc raw""" get_basis(M::Stiefel{<:Any,ℝ}, p, B::DefaultOrthonormalBasis) -Create the default basis using the parametrization for any $X ∈ T_p\mathcal M$. -Set $p_\bot \in ℝ^{nΓ—(n-k)}$ the matrix such that the $nΓ—n$ matrix of the common -columns $[p\ p_\bot]$ is an ONB. -For any skew symmetric matrix $a ∈ ℝ^{kΓ—k}$ and any $b ∈ ℝ^{(n-k)Γ—k}$ the matrix +Create the default basis using the parametrization for any ``X ∈ T_p\mathcal M``. +Set ``p_\bot \in ℝ^{nΓ—(n-k)}`` the matrix such that the ``nΓ—n`` matrix of the common +columns ``[p\ p_\bot]`` is an ONB. +For any skew symmetric matrix ``a ∈ ℝ^{kΓ—k}`` and any ``b ∈ ℝ^{(n-k)Γ—k}`` the matrix ````math X = pa + p_\bot b ∈ T_p\mathcal M ```` -and we can use the $\frac{1}{2}k(k-1) + (n-k)k = nk-\frac{1}{2}k(k+1)$ entries -of $a$ and $b$ to specify a basis for the tangent space. +and we can use the ``\frac{1}{2}k(k-1) + (n-k)k = nk-\frac{1}{2}k(k+1)`` entries +of ``a`` and ``b`` to specify a basis for the tangent space. using unit vectors for constructing both -the upper matrix of $a$ to build a skew symmetric matrix and the matrix b, the default +the upper matrix of ``a`` to build a skew symmetric matrix and the matrix b, the default basis is constructed. -Since $[p\ p_\bot]$ is an automorphism on $ℝ^{nΓ—p}$ the elements of $a$ and $b$ are +Since ``[p\ p_βŠ₯]`` is an automorphism on ``ℝ^{nΓ—p}`` the elements of ``a`` and ``b`` are orthonormal coordinates for the tangent space. To be precise exactly one element in the upper -trangular entries of $a$ is set to $1$ its symmetric entry to $-1$ and we normalize with -the factor $\frac{1}{\sqrt{2}}$ and for $b$ one can just use unit vectors reshaped to a matrix +trangular entries of ``a`` is set to ``1`` its symmetric entry to ``-1`` and we normalize with +the factor ``\frac{1}{\sqrt{2}}`` and for ``b`` one can just use unit vectors reshaped to a matrix to obtain orthonormal set of parameters. """ get_basis(M::Stiefel{<:Any,ℝ}, p, B::DefaultOrthonormalBasis{ℝ,TangentSpaceType}) @@ -128,7 +128,7 @@ end project(M::Stiefel,p) Projects `p` from the embedding onto the [`Stiefel`](@ref) `M`, i.e. compute `q` -as the polar decomposition of $p$ such that ``q^{\mathrm{H}}q`` is the identity, +as the polar decomposition of ``p`` such that ``q^{\mathrm{H}}q`` is the identity, where ``β‹…^{\mathrm{H}}`` denotes the hermitian, i.e. complex conjugate transposed. """ project(::Stiefel, ::Any, ::Any) @@ -149,8 +149,8 @@ The formula reads \operatorname{proj}_{T_p\mathcal M}(X) = X - p \operatorname{Sym}(p^{\mathrm{H}}X), ```` -where $\operatorname{Sym}(q)$ is the symmetrization of $q$, e.g. by -$\operatorname{Sym}(q) = \frac{q^{\mathrm{H}}+q}{2}$. +where ``\operatorname{Sym}(q)`` is the symmetrization of ``q``, e.g. by +``\operatorname{Sym}(q) = \frac{q^{\mathrm{H}}+q}{2}``. """ project(::Stiefel, ::Any...) diff --git a/src/manifolds/SymmetricPositiveDefinite.jl b/src/manifolds/SymmetricPositiveDefinite.jl index 746ea87dfd..95d051b9ec 100644 --- a/src/manifolds/SymmetricPositiveDefinite.jl +++ b/src/manifolds/SymmetricPositiveDefinite.jl @@ -24,7 +24,7 @@ i.e. the set of symmetric matrices, SymmetricPositiveDefinite(n; parameter::Symbol=:type) -generates the manifold $\mathcal P(n) \subset ℝ^{nΓ—n}$ +generates the manifold ``\mathcal P(n) \subset ℝ^{nΓ—n}`` """ struct SymmetricPositiveDefinite{T} <: AbstractDecoratorManifold{ℝ} size::T @@ -243,7 +243,7 @@ end Return the injectivity radius of the [`SymmetricPositiveDefinite`](@ref). Since `M` is a Hadamard manifold with respect to the [`AffineInvariantMetric`](@ref) and the -[`LogCholeskyMetric`](@ref), the injectivity radius is globally $∞$. +[`LogCholeskyMetric`](@ref), the injectivity radius is globally ``∞``. """ injectivity_radius(::SymmetricPositiveDefinite) = Inf injectivity_radius(::SymmetricPositiveDefinite, p) = Inf @@ -265,7 +265,7 @@ is_flat(M::SymmetricPositiveDefinite) = false manifold_dimension(M::SymmetricPositiveDefinite) returns the dimension of -[`SymmetricPositiveDefinite`](@ref) `M`$=\mathcal P(n), n ∈ β„•$, i.e. +[`SymmetricPositiveDefinite`](@ref) `M` ``=\mathcal P(n), n ∈ β„•``, i.e. ````math \dim \mathcal P(n) = \frac{n(n+1)}{2}. ```` @@ -466,8 +466,8 @@ end representation_size(M::SymmetricPositiveDefinite) Return the size of an array representing an element on the -[`SymmetricPositiveDefinite`](@ref) manifold `M`, i.e. $nΓ—n$, the size of such a -symmetric positive definite matrix on $\mathcal M = \mathcal P(n)$. +[`SymmetricPositiveDefinite`](@ref) manifold `M`, i.e. ``nΓ—n``, the size of such a +symmetric positive definite matrix on ``\mathcal M = \mathcal P(n)``. """ function representation_size(M::SymmetricPositiveDefinite) N = get_parameter(M.size)[1] diff --git a/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl b/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl index e72804ecf5..46d3d867d7 100644 --- a/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl +++ b/src/manifolds/SymmetricPositiveSemidefiniteFixedRank.jl @@ -1,8 +1,8 @@ @doc raw""" SymmetricPositiveSemidefiniteFixedRank{T,𝔽} <: AbstractDecoratorManifold{𝔽} -The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) $ \operatorname{SPS}_k(n)$ consisting of the real- or complex-valued -symmetric positive semidefinite matrices of size $nΓ—n$ and rank $k$, i.e. the set +The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) `` \operatorname{SPS}_k(n)`` consisting of the real- or complex-valued +symmetric positive semidefinite matrices of size ``nΓ—n`` and rank ``k``, i.e. the set ````math \operatorname{SPS}_k(n) = \bigl\{ @@ -10,18 +10,18 @@ p ∈ 𝔽^{nΓ—n}\ \big|\ p^{\mathrm{H}} = p, apa^{\mathrm{H}} \geq 0 \text{ for all } a ∈ 𝔽 \text{ and } \operatorname{rank}(p) = k\bigr\}, ```` -where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, -and the field $𝔽 ∈ \{ ℝ, β„‚\}$. -We sometimes $\operatorname{SPS}_{k,𝔽}(n)$, when distinguishing the real- and complex-valued +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transpose, +and the field ``𝔽 ∈ \{ ℝ, β„‚\}``. +We sometimes ``\operatorname{SPS}_{k,𝔽}(n)``, when distinguishing the real- and complex-valued manifold is important. -An element is represented by $q ∈ 𝔽^{nΓ—k}$ from the factorization $p = qq^{\mathrm{H}}$. -Note that since for any unitary (orthogonal) $A ∈ 𝔽^{nΓ—n}$ we have -$(Aq)(Aq)^{\mathrm{H}} = qq^{\mathrm{H}} = p$, the representation is not unique, or in -other words, the manifold is a quotient manifold of $𝔽^{nΓ—k}$. +An element is represented by ``q ∈ 𝔽^{nΓ—k}`` from the factorization ``p = qq^{\mathrm{H}}``. +Note that since for any unitary (orthogonal) ``A ∈ 𝔽^{nΓ—n}`` we have +``(Aq)(Aq)^{\mathrm{H}} = qq^{\mathrm{H}} = p``, the representation is not unique, or in +other words, the manifold is a quotient manifold of ``𝔽^{nΓ—k}``. -The tangent space at $p$, $T_p\operatorname{SPS}_k(n)$, is also represented -by matrices $Y ∈ 𝔽^{nΓ—k}$ and reads as +The tangent space at ``p``, ``T_p\operatorname{SPS}_k(n)``, is also represented +by matrices ``Y ∈ 𝔽^{nΓ—k}`` and reads as ````math T_p\operatorname{SPS}_k(n) = \bigl\{ @@ -37,7 +37,7 @@ The metric was used in [JourneeBachAbsilSepulchre:2010](@cite)[MassartAbsil:2020 SymmetricPositiveSemidefiniteFixedRank(n::Int, k::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) -Generate the manifold of $nΓ—n$ symmetric positive semidefinite matrices of rank $k$ +Generate the manifold of ``nΓ—n`` symmetric positive semidefinite matrices of rank ``k`` over the `field` of real numbers `ℝ` or complex numbers `β„‚`. """ struct SymmetricPositiveSemidefiniteFixedRank{T,𝔽} <: AbstractDecoratorManifold{𝔽} @@ -107,8 +107,8 @@ end distance(M::SymmetricPositiveSemidefiniteFixedRank, p, q) Compute the distance between two points `p`, `q` on the -[`SymmetricPositiveSemidefiniteFixedRank`](@ref), which is the Frobenius norm of $Y$ which -minimizes $\lVert p - qY\rVert$ with respect to $Y$. +[`SymmetricPositiveSemidefiniteFixedRank`](@ref), which is the Frobenius norm of ``Y`` which +minimizes ``\lVert p - qY\rVert`` with respect to ``Y``. """ distance(M::SymmetricPositiveSemidefiniteFixedRank, p, q) = norm(M, p, log(M, p, q)) @@ -129,8 +129,8 @@ which just reads ````math q_2 = \exp_p(\log_pq) ```` - might yield a matrix $q_2\neq q$, but they represent the same point on the quotient - manifold, i.e. $d_{\operatorname{SPS}_k(n)}(q_2,q) = 0$. + might yield a matrix ``q_2\neq q``, but they represent the same point on the quotient + manifold, i.e. ``d_{\operatorname{SPS}_k(n)}(q_2,q) = 0``. """ exp(::SymmetricPositiveSemidefiniteFixedRank, ::Any, ::Any) @@ -144,7 +144,7 @@ end test, whether two points `p`, `q` are (approximately) nearly the same. Since this is a quotient manifold in the embedding, the test is performed by checking -their distance, if they are not the same, i.e. that $d_{\mathcal M}(p,q) \approx 0$, where +their distance, if they are not the same, i.e. that ``d_{\mathcal M}(p,q) \approx 0``, where the comparison is performed with the classical `isapprox`. The `kwargs...` are passed on to this accordingly. """ @@ -170,7 +170,7 @@ is_flat(M::SymmetricPositiveSemidefiniteFixedRank) = false log(M::SymmetricPositiveSemidefiniteFixedRank, q, p) Compute the logarithmic map on the [`SymmetricPositiveSemidefiniteFixedRank`](@ref) manifold -by minimizing $\lVert p - qY\rVert$ with respect to $Y$. +by minimizing ``\lVert p - qY\rVert`` with respect to ``Y``. !!! note @@ -180,8 +180,8 @@ by minimizing $\lVert p - qY\rVert$ with respect to $Y$. ````math q_2 = \exp_p(\log_pq) ```` - might yield a matrix $q_2\neq q$, but they represent the same point on the quotient - manifold, i.e. $d_{\operatorname{SPS}_k(n)}(q_2,q) = 0$. + might yield a matrix ``q_2β‰ q``, but they represent the same point on the quotient + manifold, i.e. ``d_{\operatorname{SPS}_k(n)}(q_2,q) = 0``. """ log(::SymmetricPositiveSemidefiniteFixedRank, q, p) @@ -203,7 +203,7 @@ Return the dimension of the [`SymmetricPositiveSemidefiniteFixedRank`](@ref) mat \end{aligned} ```` -where the last $k^2$ is due to the zero imaginary part for Hermitian matrices diagonal +where the last ``k^2`` is due to the zero imaginary part for Hermitian matrices diagonal """ manifold_dimension(::SymmetricPositiveSemidefiniteFixedRank) diff --git a/test/ambiguities.jl b/test/ambiguities.jl index b46f568017..da14e7a079 100644 --- a/test/ambiguities.jl +++ b/test/ambiguities.jl @@ -1,3 +1,14 @@ +""" + has_type_in_signature(sig, T) + Test whether the signature `sig` has an argument of type `T` as one of its paramaters +""" +function has_type_in_signature(sig, T::Type) + return any(map(Base.unwrap_unionall(sig.sig).parameters) do x + xw = Base.rewrap_unionall(x, sig.sig) + return (xw isa Type ? xw : xw.T) <: T + end) +end + @testset "Ambiguities" begin if VERSION.prerelease == () && !Sys.iswindows() && VERSION < v"1.10.0" mbs = Test.detect_ambiguities(ManifoldsBase) diff --git a/test/approx_inverse_retraction.jl b/test/approx_inverse_retraction.jl index 7d9b40ea12..cdf492b2ea 100644 --- a/test/approx_inverse_retraction.jl +++ b/test/approx_inverse_retraction.jl @@ -1,7 +1,7 @@ using NLsolve using LinearAlgebra -include("utils.jl") +include("header.jl") Random.seed!(10) diff --git a/test/differentiation.jl b/test/differentiation.jl index 35a9dca2d7..3db2a3745c 100644 --- a/test/differentiation.jl +++ b/test/differentiation.jl @@ -1,6 +1,6 @@ # A bit of duplication of tests in ManifoldDiff.jl but it ensures that it works here too. -include("utils.jl") +include("header.jl") using Manifolds: default_differential_backend, _derivative, diff --git a/test/groups/circle_group.jl b/test/groups/circle_group.jl index cd6ce39923..5676cd5b4c 100644 --- a/test/groups/circle_group.jl +++ b/test/groups/circle_group.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") using Manifolds: diff --git a/test/groups/connections.jl b/test/groups/connections.jl index efaaf739af..0d2e4c4a7e 100644 --- a/test/groups/connections.jl +++ b/test/groups/connections.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") using Manifolds: connection diff --git a/test/groups/general_linear.jl b/test/groups/general_linear.jl index 24fe8026d6..1af110b040 100644 --- a/test/groups/general_linear.jl +++ b/test/groups/general_linear.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") using NLsolve diff --git a/test/groups/general_unitary_groups.jl b/test/groups/general_unitary_groups.jl index d681c818bb..d2cc2c8c22 100644 --- a/test/groups/general_unitary_groups.jl +++ b/test/groups/general_unitary_groups.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") @testset "General Unitary Groups" begin diff --git a/test/groups/group_operation_action.jl b/test/groups/group_operation_action.jl index f99542588b..ec7e9d569e 100644 --- a/test/groups/group_operation_action.jl +++ b/test/groups/group_operation_action.jl @@ -1,5 +1,5 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") using Manifolds: diff --git a/test/groups/groups_general.jl b/test/groups/groups_general.jl index 6e3cbb4d8d..710167904b 100644 --- a/test/groups/groups_general.jl +++ b/test/groups/groups_general.jl @@ -1,7 +1,7 @@ using StaticArrays: identity_perm using Base: decode_overlong -include("../utils.jl") +include("../header.jl") include("group_utils.jl") using Manifolds: diff --git a/test/groups/heisenberg.jl b/test/groups/heisenberg.jl index 1e13d24387..86c3ab4188 100644 --- a/test/groups/heisenberg.jl +++ b/test/groups/heisenberg.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") @testset "Heisenberg group" begin diff --git a/test/groups/metric.jl b/test/groups/metric.jl index f759d20426..fa5b82fb44 100644 --- a/test/groups/metric.jl +++ b/test/groups/metric.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") using OrdinaryDiffEq diff --git a/test/groups/power_group.jl b/test/groups/power_group.jl index 60000fa36c..d2aa761b94 100644 --- a/test/groups/power_group.jl +++ b/test/groups/power_group.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") @testset "Power group" begin diff --git a/test/groups/product_group.jl b/test/groups/product_group.jl index 05e251e1a6..b1e1f7e978 100644 --- a/test/groups/product_group.jl +++ b/test/groups/product_group.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") using RecursiveArrayTools diff --git a/test/groups/rotation_action.jl b/test/groups/rotation_action.jl index 71be2acd73..2a29167258 100644 --- a/test/groups/rotation_action.jl +++ b/test/groups/rotation_action.jl @@ -1,5 +1,5 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") @testset "Rotation action" begin diff --git a/test/groups/rotation_translation_action.jl b/test/groups/rotation_translation_action.jl index 2bb61eb137..8ecf8bbadc 100644 --- a/test/groups/rotation_translation_action.jl +++ b/test/groups/rotation_translation_action.jl @@ -1,5 +1,5 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") @testset "Rotation-translation action" begin diff --git a/test/groups/semidirect_product_group.jl b/test/groups/semidirect_product_group.jl index 49c24acdd3..83611ca9bd 100644 --- a/test/groups/semidirect_product_group.jl +++ b/test/groups/semidirect_product_group.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") @testset "Semidirect product group" begin diff --git a/test/groups/special_euclidean.jl b/test/groups/special_euclidean.jl index 0030a38b72..2820469949 100644 --- a/test/groups/special_euclidean.jl +++ b/test/groups/special_euclidean.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") using ManifoldsBase: VeeOrthogonalBasis diff --git a/test/groups/special_linear.jl b/test/groups/special_linear.jl index 107ee1f9cf..c16f508243 100644 --- a/test/groups/special_linear.jl +++ b/test/groups/special_linear.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") using NLsolve diff --git a/test/groups/special_orthogonal.jl b/test/groups/special_orthogonal.jl index 5ac62be630..32753dd0bf 100644 --- a/test/groups/special_orthogonal.jl +++ b/test/groups/special_orthogonal.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") using Manifolds: LeftForwardAction, RightBackwardAction diff --git a/test/groups/translation_action.jl b/test/groups/translation_action.jl index 1348759b93..75bcee6d93 100644 --- a/test/groups/translation_action.jl +++ b/test/groups/translation_action.jl @@ -1,5 +1,5 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") @testset "Translation action" begin diff --git a/test/groups/translation_group.jl b/test/groups/translation_group.jl index 457f4bcaa0..d941cc3e57 100644 --- a/test/groups/translation_group.jl +++ b/test/groups/translation_group.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") include("group_utils.jl") using Manifolds: LeftForwardAction, RightBackwardAction diff --git a/test/groups/validation_group.jl b/test/groups/validation_group.jl index 1c8db47dbb..e5853b8a0f 100644 --- a/test/groups/validation_group.jl +++ b/test/groups/validation_group.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Group wrapped in ValidationManifold" begin G = SpecialOrthogonal(3) diff --git a/test/header.jl b/test/header.jl new file mode 100644 index 0000000000..bbffe9d9fc --- /dev/null +++ b/test/header.jl @@ -0,0 +1,24 @@ + +TEST_FLOAT32 = get(ENV, "MANIFOLDS_TEST_FLOAT32", false) +TEST_DOUBLE64 = get(ENV, "MANIFOLDS_TEST_FLOAT64", false) +TEST_STATIC_SIZED = get(ENV, "MANIFOLDS_TEST_STATIC_SIZED", false) +TEST_GROUP = get(ENV, "MANIFOLDS_TEST_GROUP", "all") + +using Manifolds +using ManifoldsBase +using ManifoldsBase: number_of_coordinates, TypeParameter +import ManifoldsBase: active_traits, merge_traits + +using ManifoldDiff + +using LinearAlgebra +using Distributions +using DoubleFloats +using Quaternions +using Random +using StaticArrays +using Statistics +using StatsBase +using Test +using Graphs +using SimpleWeightedGraphs diff --git a/test/manifolds/centered_matrices.jl b/test/manifolds/centered_matrices.jl index ae63d1f5f9..8276a9bb40 100644 --- a/test/manifolds/centered_matrices.jl +++ b/test/manifolds/centered_matrices.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "CenteredMatrices" begin M = CenteredMatrices(3, 2) diff --git a/test/manifolds/cholesky_space.jl b/test/manifolds/cholesky_space.jl index 3fe165f654..d227c06ad5 100644 --- a/test/manifolds/cholesky_space.jl +++ b/test/manifolds/cholesky_space.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Cholesky Space" begin M = Manifolds.CholeskySpace(3) diff --git a/test/manifolds/circle.jl b/test/manifolds/circle.jl index bc829fb91f..8296554eb0 100644 --- a/test/manifolds/circle.jl +++ b/test/manifolds/circle.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") using Manifolds: TFVector, CoTFVector diff --git a/test/manifolds/elliptope.jl b/test/manifolds/elliptope.jl index e36fae782f..465f4fb162 100644 --- a/test/manifolds/elliptope.jl +++ b/test/manifolds/elliptope.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Elliptope" begin M = Elliptope(4, 2) diff --git a/test/manifolds/essential_manifold.jl b/test/manifolds/essential_manifold.jl index a05e3edd98..02bbba2a7f 100644 --- a/test/manifolds/essential_manifold.jl +++ b/test/manifolds/essential_manifold.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Essential manifold" begin M = EssentialManifold() diff --git a/test/manifolds/euclidean.jl b/test/manifolds/euclidean.jl index e83572c67e..64e856177a 100644 --- a/test/manifolds/euclidean.jl +++ b/test/manifolds/euclidean.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") using Manifolds: induced_basis using FiniteDifferences diff --git a/test/manifolds/fiber.jl b/test/manifolds/fiber.jl index 8bf9253d09..640836b455 100644 --- a/test/manifolds/fiber.jl +++ b/test/manifolds/fiber.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") using RecursiveArrayTools diff --git a/test/manifolds/fiber_bundle.jl b/test/manifolds/fiber_bundle.jl index 9950c1ac67..3e2e49a653 100644 --- a/test/manifolds/fiber_bundle.jl +++ b/test/manifolds/fiber_bundle.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") using RecursiveArrayTools diff --git a/test/manifolds/fixed_rank.jl b/test/manifolds/fixed_rank.jl index ef128f8e85..4536e4e66c 100644 --- a/test/manifolds/fixed_rank.jl +++ b/test/manifolds/fixed_rank.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "fixed Rank" begin M = FixedRankMatrices(3, 2, 2) diff --git a/test/manifolds/generalized_grassmann.jl b/test/manifolds/generalized_grassmann.jl index 243b3af019..0f7850daa2 100644 --- a/test/manifolds/generalized_grassmann.jl +++ b/test/manifolds/generalized_grassmann.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Generalized Grassmann" begin @testset "Real" begin diff --git a/test/manifolds/generalized_stiefel.jl b/test/manifolds/generalized_stiefel.jl index 9dc195e0e7..ebfce1d7fe 100644 --- a/test/manifolds/generalized_stiefel.jl +++ b/test/manifolds/generalized_stiefel.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Generalized Stiefel" begin @testset "Real" begin diff --git a/test/manifolds/graph.jl b/test/manifolds/graph.jl index 73f0cd5c12..4e08759f52 100644 --- a/test/manifolds/graph.jl +++ b/test/manifolds/graph.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Graph AbstractManifold" begin M = Euclidean(2) diff --git a/test/manifolds/grassmann.jl b/test/manifolds/grassmann.jl index 500ad62f5a..9f6827b274 100644 --- a/test/manifolds/grassmann.jl +++ b/test/manifolds/grassmann.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Grassmann" begin @testset "Real" begin diff --git a/test/manifolds/hyperbolic.jl b/test/manifolds/hyperbolic.jl index 887627371c..f4970ca3d1 100644 --- a/test/manifolds/hyperbolic.jl +++ b/test/manifolds/hyperbolic.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Hyperbolic Space" begin M = Hyperbolic(2) diff --git a/test/manifolds/lorentz.jl b/test/manifolds/lorentz.jl index 59e0362818..d61cc8c32b 100644 --- a/test/manifolds/lorentz.jl +++ b/test/manifolds/lorentz.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Lorentz Manifold" begin M = Lorentz(3) diff --git a/test/manifolds/multinomial_doubly_stochastic.jl b/test/manifolds/multinomial_doubly_stochastic.jl index dd48083f72..22e55e77d9 100644 --- a/test/manifolds/multinomial_doubly_stochastic.jl +++ b/test/manifolds/multinomial_doubly_stochastic.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Multinomial doubly stochastic Matrices" begin M = MultinomialDoubleStochastic(3) diff --git a/test/manifolds/multinomial_matrices.jl b/test/manifolds/multinomial_matrices.jl index c04d07410f..f23fa4e760 100644 --- a/test/manifolds/multinomial_matrices.jl +++ b/test/manifolds/multinomial_matrices.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "MultinomialMatrices manifold" begin M = MultinomialMatrices(3, 2) diff --git a/test/manifolds/multinomial_symmetric.jl b/test/manifolds/multinomial_symmetric.jl index 58450b5bac..fcf0a2360e 100644 --- a/test/manifolds/multinomial_symmetric.jl +++ b/test/manifolds/multinomial_symmetric.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Multinomial symmetric matrices" begin M = MultinomialSymmetric(3) diff --git a/test/manifolds/oblique.jl b/test/manifolds/oblique.jl index 4f51907aea..b29678e972 100644 --- a/test/manifolds/oblique.jl +++ b/test/manifolds/oblique.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Oblique manifold" begin M = Oblique(3, 2) diff --git a/test/manifolds/positive_numbers.jl b/test/manifolds/positive_numbers.jl index c914ba0940..350e3d0373 100644 --- a/test/manifolds/positive_numbers.jl +++ b/test/manifolds/positive_numbers.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Positive Numbers" begin M = PositiveNumbers() diff --git a/test/manifolds/power_manifold.jl b/test/manifolds/power_manifold.jl index bace6ba9b7..192df1dced 100644 --- a/test/manifolds/power_manifold.jl +++ b/test/manifolds/power_manifold.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") using HybridArrays, Random using StaticArrays: Dynamic diff --git a/test/manifolds/probability_simplex.jl b/test/manifolds/probability_simplex.jl index d2b6a5445d..e82af8b304 100644 --- a/test/manifolds/probability_simplex.jl +++ b/test/manifolds/probability_simplex.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Probability simplex" begin M = ProbabilitySimplex(2) diff --git a/test/manifolds/product_manifold.jl b/test/manifolds/product_manifold.jl index 5bbf9cd3cf..9f12478ea0 100644 --- a/test/manifolds/product_manifold.jl +++ b/test/manifolds/product_manifold.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") using RecursiveArrayTools: ArrayPartition diff --git a/test/manifolds/projective_space.jl b/test/manifolds/projective_space.jl index 140da634cc..8a843d6096 100644 --- a/test/manifolds/projective_space.jl +++ b/test/manifolds/projective_space.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "ProjectiveSpace" begin @testset "Real" begin diff --git a/test/manifolds/quotient_manifold.jl b/test/manifolds/quotient_manifold.jl index 36f482439f..b1d6a2b084 100644 --- a/test/manifolds/quotient_manifold.jl +++ b/test/manifolds/quotient_manifold.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") struct DummyManifold <: AbstractManifold{ℝ} end struct DummyTotalSpace <: AbstractManifold{ℝ} end diff --git a/test/manifolds/rotations.jl b/test/manifolds/rotations.jl index 4a276b8def..dfd4aee46e 100644 --- a/test/manifolds/rotations.jl +++ b/test/manifolds/rotations.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Rotations" begin M = Rotations(2) diff --git a/test/manifolds/shape_space.jl b/test/manifolds/shape_space.jl index 777b298914..0873fe75ca 100644 --- a/test/manifolds/shape_space.jl +++ b/test/manifolds/shape_space.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "KendallsPreShapeSpace" begin M = KendallsPreShapeSpace(2, 3) diff --git a/test/manifolds/skewhermitian.jl b/test/manifolds/skewhermitian.jl index 7fd5a7600e..6db2139ad5 100644 --- a/test/manifolds/skewhermitian.jl +++ b/test/manifolds/skewhermitian.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "SkewSymmetricMatrices" begin @test SkewSymmetricMatrices(3) === SkewHermitianMatrices(3) diff --git a/test/manifolds/spd_fixed_determinant.jl b/test/manifolds/spd_fixed_determinant.jl index 21f01506fa..74c8f39ca7 100644 --- a/test/manifolds/spd_fixed_determinant.jl +++ b/test/manifolds/spd_fixed_determinant.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Isochoric matrices" begin M = SPDFixedDeterminant(2, 1.0) diff --git a/test/manifolds/spectrahedron.jl b/test/manifolds/spectrahedron.jl index ffbf6290f4..dd5737bc00 100644 --- a/test/manifolds/spectrahedron.jl +++ b/test/manifolds/spectrahedron.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Spectrahedron" begin M = Spectrahedron(4, 2) diff --git a/test/manifolds/sphere.jl b/test/manifolds/sphere.jl index 3c04cb7be2..9031742fb2 100644 --- a/test/manifolds/sphere.jl +++ b/test/manifolds/sphere.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") using Manifolds: induced_basis using ManifoldsBase: TFVector diff --git a/test/manifolds/sphere_symmetric_matrices.jl b/test/manifolds/sphere_symmetric_matrices.jl index 255a35e0bc..f5d8e02779 100644 --- a/test/manifolds/sphere_symmetric_matrices.jl +++ b/test/manifolds/sphere_symmetric_matrices.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "SphereSymmetricMatrices" begin M = SphereSymmetricMatrices(3) diff --git a/test/manifolds/stiefel.jl b/test/manifolds/stiefel.jl index 6154ce2a28..d075384a36 100644 --- a/test/manifolds/stiefel.jl +++ b/test/manifolds/stiefel.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Stiefel" begin @testset "Real" begin diff --git a/test/manifolds/symmetric.jl b/test/manifolds/symmetric.jl index 5e0ce75a1e..79a164dc97 100644 --- a/test/manifolds/symmetric.jl +++ b/test/manifolds/symmetric.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "SymmetricMatrices" begin M = SymmetricMatrices(3, ℝ) diff --git a/test/manifolds/symmetric_positive_definite.jl b/test/manifolds/symmetric_positive_definite.jl index e8d0e6c091..b01662de22 100644 --- a/test/manifolds/symmetric_positive_definite.jl +++ b/test/manifolds/symmetric_positive_definite.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Symmetric Positive Definite Matrices" begin M1 = SymmetricPositiveDefinite(3) diff --git a/test/manifolds/symmetric_positive_semidefinite_fixed_rank.jl b/test/manifolds/symmetric_positive_semidefinite_fixed_rank.jl index 83eae0b079..d0e7e4fd79 100644 --- a/test/manifolds/symmetric_positive_semidefinite_fixed_rank.jl +++ b/test/manifolds/symmetric_positive_semidefinite_fixed_rank.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Symmetric Positive Semidefinite Matrices of Fixed Rank" begin @testset "Real Matrices" begin diff --git a/test/manifolds/symplectic.jl b/test/manifolds/symplectic.jl index af4cd95cd9..99558d9e16 100644 --- a/test/manifolds/symplectic.jl +++ b/test/manifolds/symplectic.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") using FiniteDifferences using Manifolds: RiemannianProjectionBackend using ManifoldDiff diff --git a/test/manifolds/symplecticstiefel.jl b/test/manifolds/symplecticstiefel.jl index f54f55d128..92f43c2d2b 100644 --- a/test/manifolds/symplecticstiefel.jl +++ b/test/manifolds/symplecticstiefel.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") using FiniteDifferences using Manifolds: RiemannianProjectionBackend using ManifoldDiff diff --git a/test/manifolds/torus.jl b/test/manifolds/torus.jl index ddab72ceef..78abc15313 100644 --- a/test/manifolds/torus.jl +++ b/test/manifolds/torus.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") @testset "Torus" begin M = Torus(2) diff --git a/test/manifolds/tucker.jl b/test/manifolds/tucker.jl index 762662cbcb..a8b6e131ba 100644 --- a/test/manifolds/tucker.jl +++ b/test/manifolds/tucker.jl @@ -1,5 +1,5 @@ using ManifoldsBase: LinearAlgebra -include("../utils.jl") +include("../header.jl") @testset "Tucker" begin nβƒ— = (4, 5, 6) diff --git a/test/manifolds/unitary_matrices.jl b/test/manifolds/unitary_matrices.jl index 6584e8b48e..4683363658 100644 --- a/test/manifolds/unitary_matrices.jl +++ b/test/manifolds/unitary_matrices.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") using Quaternions diff --git a/test/manifolds/vector_bundle.jl b/test/manifolds/vector_bundle.jl index 370aacbafa..c0d7d0cae6 100644 --- a/test/manifolds/vector_bundle.jl +++ b/test/manifolds/vector_bundle.jl @@ -1,4 +1,4 @@ -include("../utils.jl") +include("../header.jl") using RecursiveArrayTools diff --git a/test/metric.jl b/test/metric.jl index b9fd75b17a..6441406310 100644 --- a/test/metric.jl +++ b/test/metric.jl @@ -6,7 +6,7 @@ import ManifoldsBase: default_retraction_method import Manifolds: solve_exp_ode using Manifolds: InducedBasis, connection, get_chart_index, induced_basis, mean!, median! using ManifoldDiff: FiniteDifferencesBackend -include("utils.jl") +include("header.jl") struct TestEuclidean{N} <: AbstractManifold{ℝ} end struct TestEuclideanMetric <: AbstractMetric end diff --git a/test/notation.jl b/test/notation.jl index 294cc39a7c..f9d9a8f9a2 100644 --- a/test/notation.jl +++ b/test/notation.jl @@ -1,4 +1,4 @@ -include("utils.jl") +include("header.jl") @testset "Test Notation" begin M = Sphere(2) diff --git a/test/recipes.jl b/test/recipes.jl index f595fa3044..b5af2da28e 100644 --- a/test/recipes.jl +++ b/test/recipes.jl @@ -1,6 +1,6 @@ using RecipesBase, Plots, Colors #using VisualRegressionTests, -include("utils.jl") +include("header.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 diff --git a/test/runtests.jl b/test/runtests.jl index afb113cc85..7a8e331b10 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,11 +1,16 @@ -include("utils.jl") +include("header.jl") @info "Manifolds.jl Test settings:\n\n" * "Testing Float32: $(TEST_FLOAT32)\n" * "Testing Double64: $(TEST_DOUBLE64)\n" * "Testing Static: $(TEST_STATIC_SIZED)\n\n" * "Test group: $(TEST_GROUP)\n\n" * - "These settings are stored in environment variables, see in test/utils.jl" + "These settings are stored in environment variables, see in test/header.jl" + +function include_test(path) + @info "Testing $path" + @time include(path) # show basic timing, (this will print a newline at end) +end @testset "Manifolds.jl" begin if TEST_GROUP ∈ ["all", "test_manifolds"] diff --git a/test/statistics.jl b/test/statistics.jl index 160537bc00..7cbb10b753 100644 --- a/test/statistics.jl +++ b/test/statistics.jl @@ -1,4 +1,4 @@ -include("utils.jl") +include("header.jl") using StatsBase: AbstractWeights, pweights using Random: GLOBAL_RNG, seed! import ManifoldsBase: diff --git a/test/utils.jl b/test/utils.jl deleted file mode 100644 index 6e53f06d56..0000000000 --- a/test/utils.jl +++ /dev/null @@ -1,50 +0,0 @@ -TEST_FLOAT32 = get(ENV, "MANIFOLDS_TEST_FLOAT32", false) -TEST_DOUBLE64 = get(ENV, "MANIFOLDS_TEST_FLOAT64", false) -TEST_STATIC_SIZED = get(ENV, "MANIFOLDS_TEST_STATIC_SIZED", false) -TEST_GROUP = get(ENV, "MANIFOLDS_TEST_GROUP", "all") - -using Manifolds -using ManifoldsBase -using ManifoldsBase: number_of_coordinates, TypeParameter -import ManifoldsBase: active_traits, merge_traits - -using ManifoldDiff - -using LinearAlgebra -using Distributions -using DoubleFloats -using Quaternions -using Random -using StaticArrays -using Statistics -using StatsBase -using Test -using Graphs -using SimpleWeightedGraphs - -function include_test(path) - @info "Testing $path" - @time include(path) # show basic timing, (this will print a newline at end) -end - -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) - we_care = m1.module in modules_we_care_about && m2.module in modules_we_care_about - return we_care && (m1.module === Manifolds || m2.module === Manifolds) - end - return our_ambigs -end - -""" - has_type_in_signature(sig, T) - Test whether the signature `sig` has an argument of type `T` as one of its paramaters -""" -function has_type_in_signature(sig, T::Type) - return any(map(Base.unwrap_unionall(sig.sig).parameters) do x - xw = Base.rewrap_unionall(x, sig.sig) - return (xw isa Type ? xw : xw.T) <: T - end) -end From f9769a16cb1b5f4389105c1ab7266653b390b10c Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 13 Jan 2024 16:52:40 +0100 Subject: [PATCH 12/65] Fix improvised test, fix documentation. --- src/manifolds/Symplectic.jl | 4 +-- src/manifolds/SymplecticStiefel.jl | 2 +- test/groups/group_utils.jl | 54 ++++++++++++++++-------------- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index 02017ff4b3..023e81e657 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -228,7 +228,7 @@ function check_point( # Perform check that the matrix lives on the real symplectic manifold: if !isapprox(inv(M, p) * p, LinearAlgebra.I; atol=atol, kwargs...) return DomainError( - expected_zero, + norm(inv(M, p) * p - LinearAlgebra.I), ( "The point p does not lie on $(M) because its symplectic" * " inverse composed with itself is not the identity." @@ -747,7 +747,7 @@ Compute the Cayley retraction on ``p ∈ \mathrm{Sp}(2n, ℝ)`` in the direction of tangent vector ``X ∈ T_p\mathrm{Sp}(2n, ℝ)``, as defined in by Birtea et al in proposition 2 [BirteaCaşuComΔƒnescu:2020](@cite). -Using the [symplectic_inverse](@ref) ``A^+`` of a matrix ``A \in ℝ^{2nΓ—2n}`` +Using the [`symplectic_inverse`](@ref) ``A^+`` of a matrix ``A \in ℝ^{2nΓ—2n}`` the retraction ``\mathcal{R}: T\mathrm{Sp}(2n) β†’ \mathrm{Sp}(2n)`` is defined pointwise as ````math diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index b6f6391948..8cddb733fb 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -133,7 +133,7 @@ function check_vector(M::SymplecticStiefel{S,𝔽}, p, X::T; kwargs...) where {S if !is_hamiltonian(H; kwargs...) return DomainError( - norm(Hamiltonian(H)^+H), + norm(Matrix(Hamiltonian(H)^+) + H), ( "The matrix X is not in the tangent space at point p of $M at $p, since p^{+}X is not a Hamiltonian matrix." ), diff --git a/test/groups/group_utils.jl b/test/groups/group_utils.jl index 2a307ab276..4254997dfc 100644 --- a/test/groups/group_utils.jl +++ b/test/groups/group_utils.jl @@ -1,31 +1,35 @@ -struct NotImplementedOperation <: AbstractGroupOperation end +s = @isdefined _group_utils_included +if !s + _group_utils_included = true + struct NotImplementedOperation <: AbstractGroupOperation end -struct NotImplementedManifold <: AbstractManifold{ℝ} end + struct NotImplementedManifold <: AbstractManifold{ℝ} end -struct NotImplementedGroupDecorator{𝔽,M<:AbstractManifold{𝔽}} <: - AbstractDecoratorManifold{𝔽} - manifold::M -end -function active_traits(f, M::NotImplementedGroupDecorator, args...) - return merge_traits(active_traits(f, M.manifold, args...), IsExplicitDecorator()) -end + struct NotImplementedGroupDecorator{𝔽,M<:AbstractManifold{𝔽}} <: + AbstractDecoratorManifold{𝔽} + manifold::M + end + function active_traits(f, M::NotImplementedGroupDecorator, args...) + return merge_traits(active_traits(f, M.manifold, args...), IsExplicitDecorator()) + end -function Manifolds.decorated_manifold(M::NotImplementedGroupDecorator) - return M.manifold -end + function Manifolds.decorated_manifold(M::NotImplementedGroupDecorator) + return M.manifold + end -struct DefaultTransparencyGroup{𝔽,M<:AbstractManifold{𝔽},A<:AbstractGroupOperation} <: - AbstractDecoratorManifold{𝔽} - manifold::M - op::A -end -function active_traits(f, M::DefaultTransparencyGroup, args...) - return merge_traits( - Manifolds.IsGroupManifold(M.op), - active_traits(f, M.manifold, args...), - ) -end + struct DefaultTransparencyGroup{𝔽,M<:AbstractManifold{𝔽},A<:AbstractGroupOperation} <: + AbstractDecoratorManifold{𝔽} + manifold::M + op::A + end + function active_traits(f, M::DefaultTransparencyGroup, args...) + return merge_traits( + Manifolds.IsGroupManifold(M.op), + active_traits(f, M.manifold, args...), + ) + end -function Manifolds.decorated_manifold(M::DefaultTransparencyGroup) - return M.manifold + function Manifolds.decorated_manifold(M::DefaultTransparencyGroup) + return M.manifold + end end From 3f5137ec01f1cfc58d944604b6c43cd6433fb656 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 14 Jan 2024 17:49:43 +0100 Subject: [PATCH 13/65] implement `rand!` for Hamiltonians. Deprecate `rand_hamiltonian`. --- src/manifolds/Hamiltonian.jl | 51 +++++++++++++++++++++++++++--- src/manifolds/Symplectic.jl | 14 ++++---- src/manifolds/SymplecticStiefel.jl | 14 ++++---- 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index ec71f58300..191f40281e 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -46,16 +46,18 @@ Lie algebra to the [`Symplectic`](@ref) as a Lie group with the matrix operation # Constructor - HamiltonianMatrices(n::Int, field::AbstractNumbers=ℝ) + HamiltonianMatrices(2n::Int, field::AbstractNumbers=ℝ) -Generate the manifold of ``nΓ—n`` symmetric matrices. +Generate the manifold of ``2nΓ—2n`` Hamiltonian matrices. """ struct HamiltonianMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} size::T end function HamiltonianMatrices(n::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) - size = wrap_type_parameter(parameter, (n,)) + n % 2 == 0 || throw(ArgumentError("The dimension of the symplectic manifold + embedding space must be even. Was odd, n % 2 == $(n % 2).")) + size = wrap_type_parameter(parameter, (div(n, 2),)) return HamiltonianMatrices{typeof(size),field}(size) end @@ -113,11 +115,11 @@ embed(::HamiltonianMatrices, p) = p embed(::HamiltonianMatrices, p, X) = X function get_embedding(::HamiltonianMatrices{TypeParameter{Tuple{N}},𝔽}) where {N,𝔽} - return Euclidean(N, N; field=𝔽) + return Euclidean(2 * N, 2 * N; field=𝔽) end function get_embedding(M::HamiltonianMatrices{Tuple{Int},𝔽}) where {𝔽} N = get_parameter(M.size)[1] - return Euclidean(N, N; field=𝔽, parameter=:field) + return Euclidean(2 * N, 2 * N; field=𝔽, parameter=:field) end """ @@ -159,3 +161,42 @@ function Base.show(io::IO, M::HamiltonianMatrices{Tuple{Int},F}) where {F} return print(io, "HamiltonianMatrices($(n), $(F); parameter=:field)") end size(A::Hamiltonian) = size(A.value) + +@doc raw""" + p = rand(M::HamiltonianMatrices; Οƒ::Real=1.0, vector_at=nothing) + rand(M::HamiltonianMatrices; Οƒ::Real=1.0, vector_at=nothing) + +Generate a Hamiltonian matrix. Since these are a submanifold of ``ℝ^{2nΓ—2n}``, +the same method applies for points and tangent vectors. + +The generation is based on generating one normally-distributed +``nΓ—n`` matrix ``A`` and two symmetric ``nΓ—n`` matrices ``B,C`` to generate + +```math +p = \begin{pmatrix} A & B\\ C & -A^{\mathrm{T}} \end{pmatrix} +``` + +""" +rand(M::HamiltonianMatrices; Οƒ::Real=1.0) + +function rand!( + rng::AbstractRNG, + M::HamiltonianMatrices{<:Any,ℝ}, + pX; + Οƒ::Real=one(real(eltype(pX))), + vector_at=nothing, +) + n = get_parameter(M.size)[1] + p1 = @view(pX[1:n, 1:n]) + p2 = @view(pX[1:n, (n + 1):(2n)]) + p3 = @view(pX[(n + 1):(2n), 1:n]) + p4 = @view(pX[(n + 1):(2n), (n + 1):(2n)]) + randn!(rng, p1) + p4 .= -p1' + randn!(rng, p2) + randn!(rng, p3) + p2 .= (1 / 2) .* (p2 .+ p2') + p3 .= (1 / 2) .* (p2 .+ p2') + pX .= (Οƒ / norm(pX, 2)) .* pX + return pX +end diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index 023e81e657..3c4668745e 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -710,8 +710,9 @@ function Random.rand( vector_at=nothing, hamiltonian_norm=(vector_at === nothing ? 1 / 2 : 1.0), ) + n = get_parameter(M.size)[1] if vector_at === nothing - Ξ© = rand_hamiltonian(M; frobenius_norm=hamiltonian_norm) + Ξ© = rand(HamiltonianMatrices(2n); Οƒ=hamiltonian_norm) return (I - Ξ©) \ (I + Ξ©) else random_vector(M, vector_at; symmetric_norm=hamiltonian_norm) @@ -730,13 +731,10 @@ end function rand_hamiltonian(M::Symplectic; frobenius_norm=1.0) n = get_parameter(M.size)[1] - A = randn(n, n) - B = randn(n, n) - C = randn(n, n) - B = (1 / 2) .* (B .+ B') - C = (1 / 2) .* (C .+ C') - Ξ© = [A B; C -A'] - return frobenius_norm * Ξ© / norm(Ξ©, 2) + Base.depwarn( + "`rand_hamiltonian(M::Symplectic($(2n)); frobeniusnorm=$(frobeniusnorm)) is deprecated. Use `rand(HamiltonianMatrices($(2n); Οƒ=$(frobenius_norm))` instead", + ) + return rand(HamiltonianMatrices(2n); Οƒ=frobenius_norm) end @doc raw""" diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 8cddb733fb..9a00b1611c 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -505,8 +505,8 @@ function Random.rand( end function random_vector(M::SymplecticStiefel, p::AbstractMatrix; hamiltonian_norm=1.0) - n, k = get_parameter(M.size) - Ξ© = rand_hamiltonian(Symplectic(2k); frobenius_norm=hamiltonian_norm) + k = get_parameter(M.size)[2] + Ξ© = rand(HamiltonianMatrices(2k); Οƒ=hamiltonian_norm) return p * Ξ© end @@ -538,10 +538,12 @@ above can be reduced down to inverting a ``2kΓ—2k`` matrix due to Proposition Let ``A = p^+X`` and ``H = X - pA``. Then an equivalent expression for the Cayley retraction defined pointwise above is -````math - \mathcal{R}_p(X) = -p + (H + 2p)(H^+H/4 - A/2 + I_{2k})^{-1}. -```` -It is this expression we compute inplace of `q`. + +```math + \mathcal{R}_p(X) = -p + (H + 2p)(H^+H/4 - A/2 + I_{2k})^{-1}. +``` + +This expression is computed inplace of `q`. """ retract(::SymplecticStiefel, p, X, ::CayleyRetraction) From f4f6cefed458d80ee4e4b6fa3625402e283e3f62 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 15 Jan 2024 19:26:08 +0100 Subject: [PATCH 14/65] Implement exp and the Caley retraction in the quivalence class representation on symplectic Grassmann. --- src/manifolds/SymplecticGrassmannStiefel.jl | 56 +++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index ea36f35a52..583263ee95 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -23,3 +23,59 @@ function check_vector(M::SymplecticGrassmann, p, X; kwargs...) n, k = get_parameter(M.size) return check_vector(SymplecticStiefel(2 * n, 2 * k), p, X; kwargs...) end + +@doc raw""" + exp(::SymplecticGrassmann, p, X) + exp!(M::SymplecticGrassmann, q, p, X) + +Compute the exponential mapping + +```math + \exp\colon T\mathrm{SpGr}(2n, 2k) β†’ \mathrm{SpGr}(2n, 2k) +``` + +when representing points and tangent vectors as symplectic bases and their tangents, i.e. +on the [`SymplecticStiefel`](@ref) manifold. Then we can just pass this on to [`exp(::SymplecticStiefel, p, X)`](@ref). +""" +exp(::SymplecticGrassmann, p, X) + +function exp!(M::SymplecticGrassmann, q, p, X) + n, k = get_parameter(M.size) + exp!(SymplecticStiefel(2 * n, 2 * k), q, p, X) + return q +end + +@doc raw""" + inverse_retract(::SymplecticGrassmann, p, q, ::CayleyInverseRetraction) + inverse_retract!(::SymplecticGrassmann, q, p, X, ::CayleyInverseRetraction) + +Compute the Cayley Inverse Retraction on the Symplectic Grassmann manifold, +when the points are represented as symplectic bases, i.e. on the [`SymplecticStiefel`](@ref). + +Here we can directly employ the [`CaleyInverseRetraction`](@ref) on the symplectic Stiefel manifold +itself, see [`inverse_retract(::SymplecticStiefel, p, q, ::CayleyInverseRetraction)``](@ref). +""" +inverse_retract(::SymplecticGrassmann, p, q, ::CayleyInverseRetraction) + +function inverse_retract_cayley!(M::SymplecticGrassmann, X, p, q) + n, k = get_parameter(M.size) + return inverse_retract_cayley!(SymplecticStiefel(2 * n, 2 * k), X, p, q) +end + +@doc raw""" + retract(::SymplecticGrassmann, p, X, ::CayleyRetraction) + retract!(::SymplecticGrassmann, q, p, X, ::CayleyRetraction) + +Compute the Cayley retraction on the Symplectic Grassmann manifold, +when the points are represented as symplectic bases, i.e. on the [`SymplecticStiefel`](@ref). + +Here we can directly employ the [`CaleyRetraction`](@ref) on the symplectic Stiefel manifold +itself, see [`retract(::SymplecticStiefel, p, X, ::CayleyRetraction)``](@ref). +""" +retract(::SymplecticGrassmann, p, X, ::CayleyRetraction) + +function retract_cayley!(M::SymplecticGrassmann, q, p, X, t::Number) + n, k = get_parameter(M.size) + retract_cayley!(SymplecticStiefel(2 * n, 2 * k), q, p, X, t) + return q +end From 5b22c6caa6f960e3cc8289aa8131736ff6557780 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 15 Jan 2024 19:36:07 +0100 Subject: [PATCH 15/65] Simplify math. --- src/manifolds/SymplecticStiefel.jl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 9a00b1611c..82adbe5a88 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -74,11 +74,11 @@ ManifoldsBase.default_retraction_method(::SymplecticStiefel) = CayleyRetraction( canonical_project(::SymplecticStiefel, p_Sp) canonical_project!(::SymplecticStiefel, p, p_Sp) -Define the canonical projection from ``\operatorname{Sp}(2n, 2n)`` onto +Define the canonical projection from ``\mathrm{Sp}(2n, 2n)`` onto ``\mathrm{SpSt}(2n, 2k)``, by projecting onto the first ``k`` columns and the ``n + 1``'th onto the ``n + k``'th columns [BendokatZimmermann:2021](@cite). -It is assumed that the point ``p`` is on ``\operatorname{Sp}(2n, 2n)``. +It is assumed that the point ``p`` is on ``\mathrm{Sp}(2n, 2n)``. """ function canonical_project(M::SymplecticStiefel, p_Sp) n, k = get_parameter(M.size) @@ -121,7 +121,7 @@ Checks whether `X` is a valid tangent vector at `p` on the [`SymplecticStiefel`] ``\mathrm{SpSt}(2n, 2k)`` manifold. The check consists of verifying that ``H = p^{+}X ∈ 𝔀_{2k}``, where ``𝔀`` -is the Lie Algebra of the symplectic group ``\operatorname{Sp}(2k)``, that is +is the Lie Algebra of the symplectic group ``\mathrm{Sp}(2k)``, that is the set of [`HamiltonianMatrices`])(@ref), where ``(β‹…)^+`` denotes the [`symplectic_inverse`](@ref). """ check_vector(::SymplecticStiefel, ::Any...) @@ -395,8 +395,7 @@ where ``(β‹…)^+`` denotes the [`symplectic_inverse`](@ref). THen the inverse retraction reads ````math -\mathcal{L}_p^{\operatorname{Sp}}(q) = 2p\bigl(V - U\bigr) + 2\bigl((p + q)U - p\bigr) - ∈ T_p\operatorname{Sp}(2n). +\mathcal{L}_p^{\mathrm{Sp}}(q) = 2p\bigl(V - U\bigr) + 2\bigl((p + q)U - p\bigr) ∈ T_p\mathrm{Sp}(2n). ```` """ inverse_retract(::SymplecticStiefel, p, q, ::CayleyInverseRetraction) @@ -475,13 +474,13 @@ end Generate a random point ``p ∈ \mathrm{SpSt}(2n, 2k)`` or a random tangent vector ``X ∈ T_p\mathrm{SpSt}(2n, 2k)`` -if `vector_at` is set to a point ``p ∈ \operatorname{Sp}(2n)``. +if `vector_at` is set to a point ``p ∈ \mathrm{Sp}(2n)``. A random point on ``\mathrm{SpSt}(2n, 2k)`` is found by first generating a -random point on the symplectic manifold ``\operatorname{Sp}(2n)``, +random point on the symplectic manifold ``\mathrm{Sp}(2n)``, and then projecting onto the Symplectic Stiefel manifold using the [`canonical_project`](@ref) ``Ο€_{\mathrm{SpSt}(2n, 2k)}``. -That is, ``p = Ο€_{\mathrm{SpSt}(2n, 2k)}(p_{\operatorname{Sp}})``. +That is, ``p = Ο€_{\mathrm{SpSt}(2n, 2k)}(p_{\mathrm{Sp}})``. To generate a random tangent vector in ``T_p\mathrm{SpSt}(2n, 2k)`` this code exploits the second tangent vector space parametrization of From 898297145b3f736c5cd5809879963cbb49d95ba2 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 18 Jan 2024 19:20:35 +0100 Subject: [PATCH 16/65] Deprecate Symplectic in favour of SymplecticMatrices (cf. #701 Point 1) --- NEWS.md | 6 +- docs/make.jl | 2 +- docs/src/manifolds/symplectic.md | 4 +- docs/src/manifolds/symplecticstiefel.md | 2 +- src/Manifolds.jl | 1 + src/deprecated.jl | 3 + src/manifolds/Symplectic.jl | 142 ++++++++++++------------ src/manifolds/SymplecticStiefel.jl | 13 ++- test/manifolds/symplectic.jl | 18 +-- test/manifolds/symplecticstiefel.jl | 6 +- 10 files changed, 105 insertions(+), 92 deletions(-) diff --git a/NEWS.md b/NEWS.md index 8243d8f897..eaee731cbf 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,11 +5,15 @@ 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). -## [unreleased] 2023-12-x +## [0.9.x] – 2024-01-18 ### Added * added the real symplectic Grassmann manifold `SymplecticGrassmann` +* Introduce the manifold of `HamiltonianMatrices` and a wrapper for `Hamiltonian` matrices +* introduce `rand(:HamiltonianMatrices)` +* Rename (deprecate) `Symplectic` to `SimplecticMatrices` in order to have a `Symplectic` wrapper for such matrices as well +* Rename (deprecate) `SymplecticMatrix` to `SymplecticElement` to cclarify that it is the special matrix ``J_{2n}`` and not an arbitrary symplectic matrix. ## [0.9.11] – 2023-12-27 diff --git a/docs/make.jl b/docs/make.jl index beb636a6f3..c67ad99467 100755 --- a/docs/make.jl +++ b/docs/make.jl @@ -134,8 +134,8 @@ makedocs(; "Symmetric positive definite" => "manifolds/symmetricpositivedefinite.md", "SPD, fixed determinant" => "manifolds/spdfixeddeterminant.md", "Symmetric positive semidefinite fixed rank" => "manifolds/symmetricpsdfixedrank.md", - "Symplectic" => "manifolds/symplectic.md", "Symplectic Grassmann" => "manifolds/symplecticgrassmann.md", + "Symplectic matrices" => "manifolds/symplectic.md", "Symplectic Stiefel" => "manifolds/symplecticstiefel.md", "Torus" => "manifolds/torus.md", "Tucker" => "manifolds/tucker.md", diff --git a/docs/src/manifolds/symplectic.md b/docs/src/manifolds/symplectic.md index 562360e798..1b9c785115 100644 --- a/docs/src/manifolds/symplectic.md +++ b/docs/src/manifolds/symplectic.md @@ -1,6 +1,6 @@ -# Symplectic +# Symplectic matrices -The [`Symplectic`](@ref) manifold, denoted $\operatorname{Sp}(2n, 𝔽)$, is a closed, embedded, submanifold of +The [`SymplecticMatrices`](@ref) manifold, denoted $\operatorname{Sp}(2n, 𝔽)$, is a closed, embedded, submanifold of $𝔽^{2nΓ—2n}$ that represents transformations into symplectic subspaces which keep the canonical symplectic form over $𝔽^{2nΓ—2n}$ invariant under the standard embedding inner product. The canonical symplectic form is a non-degenerate bilinear and skew symmetric map diff --git a/docs/src/manifolds/symplecticstiefel.md b/docs/src/manifolds/symplecticstiefel.md index a70a937709..b53c1afe23 100644 --- a/docs/src/manifolds/symplecticstiefel.md +++ b/docs/src/manifolds/symplecticstiefel.md @@ -20,7 +20,7 @@ Specifically given an element $p \in \operatorname{SpSt}(2n, 2k)$ we require tha \omega_{2n} (p x, p y) = x^T(p^TQ_{2n}p)y = x^TQ_{2k}y = \omega_{2k}(x, y) \;\forall\; x, y \in 𝔽^{2k}, ```` leading to the requirement on $p$ that $p^TQ_{2n}p = Q_{2k}$. -In the case that $k = n$, this manifold reduces to the [`Symplectic`](@ref) manifold, which is also known as the symplectic group. +In the case that $k = n$, this manifold reduces to the [`SymplecticMatrices`](@ref) manifold, which is also known as the symplectic group. ```@autodocs Modules = [Manifolds] diff --git a/src/Manifolds.jl b/src/Manifolds.jl index f2e3ec25d7..20ca413e3e 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -667,6 +667,7 @@ export Euclidean, SymmetricPositiveSemidefiniteFixedRank, Symplectic, SymplecticGrassmann, + SymplecticMatrices, SymplecticStiefel, SymplecticMatrix, Torus, diff --git a/src/deprecated.jl b/src/deprecated.jl index 03601238b0..ad091f408e 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -4,3 +4,6 @@ f, ) @deprecate ExtrinsicEstimation() ExtrinsicEstimation(EfficientEstimator()) + +Base.@deprecate_binding Symplectic SymplecticMatrices +#Base.@deprecate_binding SynplecticMatrix SymplecticElement diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index 3c4668745e..301653bf38 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -1,5 +1,5 @@ @doc raw""" - Symplectic{T, 𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType} + SymplecticMatricesMatrices{T, 𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType} The symplectic manifold consists of all ``2nΓ—2n`` matrices which preserve the canonical symplectic form over ``𝔽^{2nΓ—2n}×𝔽^{2nΓ—2n}``, @@ -28,25 +28,25 @@ The tangent space at a point ``p`` is given by [BendokatZimmermann:2021](@cite) # Constructor - Symplectic(2n, field=ℝ; parameter::Symbol=:type) + SymplecticMatrices(2n, field=ℝ; parameter::Symbol=:type) Generate the (real-valued) symplectic manifold of ``2nΓ—2n`` symplectic matrices. -The constructor for the [`Symplectic`](@ref) manifold accepts the even column/row embedding +The constructor for the [`SymplecticMatrices`](@ref) manifold accepts the even column/row embedding dimension ``2n`` for the real symplectic manifold, ``ℝ^{2nΓ—2n}``. """ -struct Symplectic{T,𝔽} <: AbstractDecoratorManifold{𝔽} +struct SymplecticMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} size::T end -function active_traits(f, ::Symplectic, args...) +function active_traits(f, ::SymplecticMatrices, args...) return merge_traits(IsEmbeddedManifold(), IsDefaultMetric(RealSymplecticMetric())) end -function Symplectic(n::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) +function SymplecticMatrices(n::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) n % 2 == 0 || throw(ArgumentError("The dimension of the symplectic manifold embedding space must be even. Was odd, n % 2 == $(n % 2).")) size = wrap_type_parameter(parameter, (div(n, 2),)) - return Symplectic{typeof(size),field}(size) + return SymplecticMatrices{typeof(size),field}(size) end @doc raw""" @@ -62,7 +62,7 @@ defined pointwise for ``p \in \mathrm{Sp}(2n)`` by [Fiori:2011](@cite)] \end{align*} ``` -This metric is also the default metric for the [`Symplectic`](@ref) manifold. +This metric is also the default metric for the [`SymplecticMatrices`](@ref) manifold. """ struct RealSymplecticMetric <: RiemannianMetric end @@ -122,8 +122,8 @@ function SymplecticMatrix(arrays::Vararg{AbstractArray}) end @doc raw""" - change_representer(::Symplectic, ::EuclideanMetric, p, X) - change_representer!(::Symplectic, Y, ::EuclideanMetric, p, X) + change_representer(::SymplecticMatrices, ::EuclideanMetric, p, X) + change_representer!(::SymplecticMatrices, Y, ::EuclideanMetric, p, X) Compute the representation of a tangent vector ``ΞΎ ∈ T_p\mathrm{Sp}(2n, ℝ)`` s.t. ```math @@ -155,9 +155,9 @@ for ``i \in {1, 2}``. However the range of each function alone is not confined t does have the correct range ``T_p\mathrm{Sp}(2n, ℝ)``. """ -change_representer(::Symplectic, ::EuclideanMetric, p, X) +change_representer(::SymplecticMatrices, ::EuclideanMetric, p, X) -function change_representer!(::Symplectic, Y, ::EuclideanMetric, p, X) +function change_representer!(::SymplecticMatrices, Y, ::EuclideanMetric, p, X) J = SymplecticMatrix(p, X) # J_{2n} pT_X = p' * X Y .= (1 / 2) .* p * (pT_X .+ J * pT_X' * J) @@ -211,16 +211,16 @@ function change_representer!( end @doc raw""" - check_point(M::Symplectic, p; kwargs...) + check_point(M::SymplecticMatrices, p; kwargs...) -Check whether `p` is a valid point on the [`Symplectic`](@ref) `M`=$\mathrm{Sp}(2n)$, +Check whether `p` is a valid point on the [`SymplecticMatrices`](@ref) `M`=$\mathrm{Sp}(2n)$, i.e. that it has the right [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and $p^{+}p$ is (approximately) the identity, where ``A^+`` denotes the [`symplectic_inverse`]/@ref). The tolerance can be set with `kwargs...`. """ function check_point( - M::Symplectic, + M::SymplecticMatrices, p::T; atol::Real=sqrt(prod(representation_size(M))) * eps(real(float(number_eltype(T)))), kwargs..., @@ -239,9 +239,9 @@ function check_point( end @doc raw""" - check_vector(M::Symplectic, p, X; kwargs...) + check_vector(M::SymplecticMatrices, p, X; kwargs...) -Checks whether `X` is a valid tangent vector at `p` on the [`Symplectic`](@ref) +Checks whether `X` is a valid tangent vector at `p` on the [`SymplecticMatrices`](@ref) `M`=``\mathrm{Sp}(2n)``, which requires that ```math @@ -251,9 +251,9 @@ holds (approximately), where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n The tolerance can be set with `kwargs...` """ -check_vector(::Symplectic, ::Any...) +check_vector(::SymplecticMatrices, ::Any...) -function check_vector(M::Symplectic, p, X::T; kwargs...) where {T} +function check_vector(M::SymplecticMatrices, p, X::T; kwargs...) where {T} J = SymplecticMatrix(p, X) if !isapprox(X' * J * p, -p' * J * X; kwargs...) return DomainError( @@ -267,12 +267,14 @@ function check_vector(M::Symplectic, p, X::T; kwargs...) where {T} return nothing end -ManifoldsBase.default_inverse_retraction_method(::Symplectic) = CayleyInverseRetraction() +function ManifoldsBase.default_inverse_retraction_method(::SymplecticMatrices) + return CayleyInverseRetraction() +end -ManifoldsBase.default_retraction_method(::Symplectic) = CayleyRetraction() +ManifoldsBase.default_retraction_method(::SymplecticMatrices) = CayleyRetraction() @doc raw""" - distance(M::Symplectic, p, q) + distance(M::SymplecticMatrices, p, q) Compute an approximate geodesic distance between two Symplectic matrices ``p, q \in \mathrm{Sp}(2n)``, as done in [WangSunFiori:2018](@cite). @@ -316,16 +318,16 @@ we see that \end{align*} ```` """ -function distance(M::Symplectic, p, q) +function distance(M::SymplecticMatrices, p, q) return norm(log(symplectic_inverse_times(M, p, q))) end -embed(::Symplectic, p) = p -embed(::Symplectic, p, X) = X +embed(::SymplecticMatrices, p) = p +embed(::SymplecticMatrices, p, X) = X @doc raw""" - exp(M::Symplectic, p, X) - exp!(M::Symplectic, q, p, X) + exp(M::SymplecticMatrices, p, X) + exp!(M::SymplecticMatrices, q, p, X) The Exponential mapping on the Symplectic manifold with the [`RealSymplecticMetric`](@ref) Riemannian metric. @@ -338,26 +340,26 @@ vector ``X \in T_p\mathrm{Sp}(2n)`` is computed as [WangSunFiori:2018](@cite) ```` where ``\operatorname{Exp}(β‹…)`` denotes the matrix exponential. """ -exp(::Symplectic, ::Any...) +exp(::SymplecticMatrices, ::Any...) -function exp!(M::Symplectic, q, p, X) +function exp!(M::SymplecticMatrices, q, p, X) p_star_X = symplectic_inverse_times(M, p, X) q .= p * exp(Array(p_star_X')) * exp(p_star_X - p_star_X') return q end -function get_embedding(::Symplectic{TypeParameter{Tuple{n}},𝔽}) where {n,𝔽} +function get_embedding(::SymplecticMatrices{TypeParameter{Tuple{n}},𝔽}) where {n,𝔽} return Euclidean(2 * n, 2 * n; field=𝔽) end -function get_embedding(M::Symplectic{Tuple{Int},𝔽}) where {𝔽} +function get_embedding(M::SymplecticMatrices{Tuple{Int},𝔽}) where {𝔽} n = get_parameter(M.size)[1] return Euclidean(2 * n, 2 * n; field=𝔽, parameter=:field) end @doc raw""" - gradient(M::Symplectic, f, p, backend::RiemannianProjectionBackend; + gradient(M::SymplecticMatrices, f, p, backend::RiemannianProjectionBackend; extended_metric=true) - gradient!(M::Symplectic, f, p, backend::RiemannianProjectionBackend; + gradient!(M::SymplecticMatrices, f, p, backend::RiemannianProjectionBackend; extended_metric=true) Compute the manifold gradient ``\text{grad}f(p)`` of a scalar function @@ -388,7 +390,7 @@ w.r.t the Riemannian metric ``g_p`` extended to the entire embedding space. vector space to comply with the [`RealSymplecticMetric`](@ref). """ function ManifoldDiff.gradient( - M::Symplectic, + M::SymplecticMatrices, f, p, backend::RiemannianProjectionBackend; @@ -399,7 +401,7 @@ function ManifoldDiff.gradient( end function ManifoldDiff.gradient!( - M::Symplectic, + M::SymplecticMatrices, f, X, p, @@ -418,7 +420,7 @@ function ManifoldDiff.gradient!( end @doc raw""" - inner(::Symplectic{<:Any,ℝ}, p, X, Y) + inner(::SymplecticMatrices{<:Any,ℝ}, p, X, Y) Compute the canonical Riemannian inner product [`RealSymplecticMetric`](@ref) ````math @@ -426,7 +428,7 @@ Compute the canonical Riemannian inner product [`RealSymplecticMetric`](@ref) ```` between the two tangent vectors ``X, Y \in T_p\mathrm{Sp}(2n)``. """ -function inner(M::Symplectic{<:Any,ℝ}, p, X, Y) +function inner(M::SymplecticMatrices{<:Any,ℝ}, p, X, Y) p_star = inv(M, p) return dot((p_star * X), (p_star * Y)) end @@ -486,14 +488,14 @@ function symplectic_inverse(A::AbstractMatrix) end @doc raw""" - inv(::Symplectic, A) - inv!(::Symplectic, A) + inv(::SymplecticMatrices, A) + inv!(::SymplecticMatrices, A) Compute the symplectic inverse ``A^+`` of matrix ``A ∈ ℝ^{2nΓ—2n}``. See [`symplectic_inverse`](@ref) for details. """ -function Base.inv(M::Symplectic{<:Any,ℝ}, A) +function Base.inv(M::SymplecticMatrices{<:Any,ℝ}, A) return symplectic_inverse(A) end @@ -521,16 +523,16 @@ function symplectic_inverse!(A) end @doc raw""" - inv!(M::Symplectic, A) + inv!(M::SymplecticMatrices, A) Compute the [`symplectic_inverse`](@ref) of a suqare matrix A inplace of A """ -function inv!(M::Symplectic{<:Any,ℝ}, A) +function inv!(M::SymplecticMatrices{<:Any,ℝ}, A) return symplectic_inverse!(A) end @doc raw""" - inverse_retract(M::Symplectic, p, q, ::CayleyInverseRetraction) + inverse_retract(M::SymplecticMatrices, p, q, ::CayleyInverseRetraction) Compute the Cayley Inverse Retraction ``X = \mathcal{L}_p^{\mathrm{Sp}}(q)`` such that the Cayley Retraction from ``p`` along ``X`` lands at ``q``, i.e. @@ -550,9 +552,9 @@ Then inverse cayley retration at ``p`` applied to ``q`` is = 2p\bigl(V - U\bigr) + 2\bigl((p + q)U - p\bigr) ∈ T_p\mathrm{Sp}(2n). ``` """ -inverse_retract(::Symplectic, p, q, ::CayleyInverseRetraction) +inverse_retract(::SymplecticMatrices, p, q, ::CayleyInverseRetraction) -function inverse_retract_cayley!(M::Symplectic, X, p, q) +function inverse_retract_cayley!(M::SymplecticMatrices, X, p, q) U_inv = lu(add_scaled_I!(symplectic_inverse_times(M, p, q), 1)) V_inv = lu(add_scaled_I!(symplectic_inverse_times(M, q, p), 1)) @@ -561,14 +563,14 @@ function inverse_retract_cayley!(M::Symplectic, X, p, q) end """ - is_flat(::Symplectic) + is_flat(::SymplecticMatrices) -Return false. [`Symplectic`](@ref) is not a flat manifold. +Return false. [`SymplecticMatrices`](@ref) is not a flat manifold. """ -is_flat(M::Symplectic) = false +is_flat(M::SymplecticMatrices) = false @doc raw""" - manifold_dimension(::Symplectic) + manifold_dimension(::SymplecticMatrices) Returns the dimension of the symplectic manifold embedded in ``ℝ^{2nΓ—2n}``, i.e. @@ -576,14 +578,14 @@ embedded in ``ℝ^{2nΓ—2n}``, i.e. \operatorname{dim}(\mathrm{Sp}(2n)) = (2n + 1)n. ``` """ -function manifold_dimension(M::Symplectic) +function manifold_dimension(M::SymplecticMatrices) n = get_parameter(M.size)[1] return (2n + 1) * n end @doc raw""" - project(::Symplectic, p, A) - project!(::Symplectic, Y, p, A) + project(::SymplecticMatrices, p, A) + project!(::SymplecticMatrices, Y, p, A) Given a point ``p \in \mathrm{Sp}(2n)``, project an element ``A \in ℝ^{2nΓ—2n}`` onto @@ -601,9 +603,9 @@ where ``h: ℝ^{2nΓ—2n} β†’ \operatorname{skew}(2n)`` denotes the restriction of ``X`` onto the tangent space ``T_p\operatorname{SpSt}(2n, 2k)`` and ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). """ -project(::Symplectic, p, A) +project(::SymplecticMatrices, p, A) -function project!(::Symplectic, Y, p, A) +function project!(::SymplecticMatrices, Y, p, A) J = SymplecticMatrix(Y, p, A) Jp = J * p @@ -699,14 +701,14 @@ and then transforming it to a symplectic matrix by applying the Cayley transform ``` To generate a random tangent vector in ``T_p\mathrm{Sp}(2n)``, this code employs the -second tangent vector space parametrization of [Symplectic](@ref). +second tangent vector space parametrization of [`SymplecticMatrices`](@ref). It first generates a random symmetric matrix ``S`` by `S = randn(2n, 2n)` and then symmetrizes it as `S = S + S'`. Then ``S`` is normalized to have Frobenius norm of `hamiltonian_norm` and `X = pJS` is returned, where `J` is the [`SymplecticMatrix`](@ref). """ function Random.rand( - M::Symplectic; + M::SymplecticMatrices; vector_at=nothing, hamiltonian_norm=(vector_at === nothing ? 1 / 2 : 1.0), ) @@ -719,7 +721,7 @@ function Random.rand( end end -function random_vector(M::Symplectic, p::AbstractMatrix; symmetric_norm=1.0) +function random_vector(M::SymplecticMatrices, p::AbstractMatrix; symmetric_norm=1.0) n = get_parameter(M.size)[1] # Generate random symmetric matrix: S = randn(2n, 2n) @@ -729,7 +731,7 @@ function random_vector(M::Symplectic, p::AbstractMatrix; symmetric_norm=1.0) return p * S end -function rand_hamiltonian(M::Symplectic; frobenius_norm=1.0) +function rand_hamiltonian(M::SymplecticMatrices; frobenius_norm=1.0) n = get_parameter(M.size)[1] Base.depwarn( "`rand_hamiltonian(M::Symplectic($(2n)); frobeniusnorm=$(frobeniusnorm)) is deprecated. Use `rand(HamiltonianMatrices($(2n); Οƒ=$(frobenius_norm))` instead", @@ -738,8 +740,8 @@ function rand_hamiltonian(M::Symplectic; frobenius_norm=1.0) end @doc raw""" - retract(::Symplectic, p, X, ::CayleyRetraction) - retract!(::Symplectic, q, p, X, ::CayleyRetraction) + retract(::SymplecticMatrices, p, X, ::CayleyRetraction) + retract!(::SymplecticMatrices, q, p, X, ::CayleyRetraction) Compute the Cayley retraction on ``p ∈ \mathrm{Sp}(2n, ℝ)`` in the direction of tangent vector ``X ∈ T_p\mathrm{Sp}(2n, ℝ)``, @@ -759,9 +761,9 @@ Here ``\operatorname{exp}_{1/1}(z) = (2 - z)^{-1}(2 + z)`` denotes the PadΓ© (1, 1) approximation to ``\operatorname{exp}(z)``. """ -retract(M::Symplectic, p, X) +retract(M::SymplecticMatrices, p, X) -function retract_cayley!(M::Symplectic, q, p, X, t::Number) +function retract_cayley!(M::SymplecticMatrices, q, p, X, t::Number) p_star_X = symplectic_inverse_times(M, p, t * X) divisor = lu(2 * I - p_star_X) @@ -769,17 +771,17 @@ function retract_cayley!(M::Symplectic, q, p, X, t::Number) return q end -function Base.show(io::IO, ::Symplectic{TypeParameter{Tuple{n}},𝔽}) where {n,𝔽} - return print(io, "Symplectic($(2n), $(𝔽))") +function Base.show(io::IO, ::SymplecticMatrices{TypeParameter{Tuple{n}},𝔽}) where {n,𝔽} + return print(io, "SymplecticMatrices($(2n), $(𝔽))") end -function Base.show(io::IO, M::Symplectic{Tuple{Int},𝔽}) where {𝔽} +function Base.show(io::IO, M::SymplecticMatrices{Tuple{Int},𝔽}) where {𝔽} n = get_parameter(M.size)[1] - return print(io, "Symplectic($(2n), $(𝔽); parameter=:field)") + return print(io, "SymplecticMatrices($(2n), $(𝔽); parameter=:field)") end @doc raw""" - symplectic_inverse_times(::Symplectic, p, q) - symplectic_inverse_times!(::Symplectic, A, p, q) + symplectic_inverse_times(::SymplecticMatrices, p, q) + symplectic_inverse_times!(::SymplecticMatrices, A, p, q) Directly compute the symplectic inverse of ``p \in \mathrm{Sp}(2n)``, multiplied with ``q \in \mathrm{Sp}(2n)``. @@ -788,12 +790,12 @@ That is, this function efficiently computes where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). """ -function symplectic_inverse_times(M::Symplectic, p, q) +function symplectic_inverse_times(M::SymplecticMatrices, p, q) A = similar(p) return symplectic_inverse_times!(M, A, p, q) end -function symplectic_inverse_times!(M::Symplectic, A, p, q) +function symplectic_inverse_times!(M::SymplecticMatrices, A, p, q) n = get_parameter(M.size)[1] # we write p = [p1 p2; p3 p4] (and q, too), then p1 = @view(p[1:n, 1:n]) diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 82adbe5a88..4e3c1faa21 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -115,7 +115,7 @@ function check_point(M::SymplecticStiefel{<:Any,ℝ}, p::T; kwargs...) where {T} end @doc raw""" - check_vector(M::Symplectic, p, X; kwargs...) + check_vector(M::SymplecticMatrices, p, X; kwargs...) Checks whether `X` is a valid tangent vector at `p` on the [`SymplecticStiefel`](@ref), ``\mathrm{SpSt}(2n, 2k)`` manifold. @@ -282,14 +282,14 @@ end @doc raw""" get_total_space(::SymplecticStiefel) -Return the total space of the [`SymplecticStiefel`](@ref) manifold, which is the corresponding [`Symplectic`](@ref) manifold. +Return the total space of the [`SymplecticStiefel`](@ref) manifold, which is the corresponding [`SymplecticMatrices`](@ref) manifold. """ function get_total_space(::SymplecticStiefel{TypeParameter{Tuple{n,k}},ℝ}) where {n,k} - return Symplectic(2 * n) + return SymplecticMatrices(2 * n) end function get_total_space(M::SymplecticStiefel{Tuple{Int,Int},ℝ}) n, _ = get_parameter(M.size) - return Symplectic(2 * n; parameter=:field) + return SymplecticMatrices(2 * n; parameter=:field) end @doc raw""" @@ -497,7 +497,10 @@ function Random.rand( ) n, k = get_parameter(M.size) if vector_at === nothing - return canonical_project(M, rand(Symplectic(2n); hamiltonian_norm=hamiltonian_norm)) + return canonical_project( + M, + rand(SymplecticMatrices(2n); hamiltonian_norm=hamiltonian_norm), + ) else return random_vector(M, vector_at; hamiltonian_norm=hamiltonian_norm) end diff --git a/test/manifolds/symplectic.jl b/test/manifolds/symplectic.jl index 99558d9e16..751be1d263 100644 --- a/test/manifolds/symplectic.jl +++ b/test/manifolds/symplectic.jl @@ -3,9 +3,9 @@ using FiniteDifferences using Manifolds: RiemannianProjectionBackend using ManifoldDiff -@testset "Symplectic" begin +@testset "SymplecticMatrices" begin @testset "Real" begin - Sp_2 = Symplectic(2 * 1) + Sp_2 = SymplecticMatrices(2 * 1) Metr_Sp_2 = MetricManifold(Sp_2, RealSymplecticMetric()) p_2 = [0.0 1.0/2.0; -2.0 -2.0] @@ -18,7 +18,7 @@ using ManifoldDiff 0.0 -1.0 ] - Sp_6 = Symplectic(6) + Sp_6 = SymplecticMatrices(6) points = [ [ 1 1 3 0 0 0 @@ -74,7 +74,7 @@ using ManifoldDiff ] @testset "Basics" begin - @test repr(Sp_2) == "Symplectic($(2), ℝ)" + @test repr(Sp_2) == "SymplecticMatrices($(2), ℝ)" @test representation_size(Sp_2) == (2, 2) @test base_manifold(Sp_2) === Sp_2 @test !is_flat(Sp_2) @@ -188,13 +188,13 @@ using ManifoldDiff end end @testset "Generate random points/tangent vectors" begin - M_big = Symplectic(20) + M_big = SymplecticMatrices(20) p_big = rand(M_big) @test is_point(M_big, p_big; error=:error, atol=1.0e-12) X_big = rand(M_big; vector_at=p_big) @test is_vector(M_big, p_big, X_big; error=:error, atol=1.0e-12) end - @testset "test_manifold(Symplectic(6), ...)" begin + @testset "test_manifold(SymplecticMatrices(6), ...)" begin @testset "Type $(Matrix{Float64})" begin type = Matrix{Float64} pts = convert.(type, points) @@ -294,7 +294,7 @@ using ManifoldDiff @testset "SymplecticMatrix" begin # TODO: Test for different type matrices. @test SymplecticMatrix() == SymplecticMatrix(1) - Sp_4 = Symplectic(4) + Sp_4 = SymplecticMatrices(4) pQ_1 = [ 0 0 -2 3 0 0 1 -1 @@ -422,8 +422,8 @@ using ManifoldDiff end end @testset "field parameter" begin - Sp_2 = Symplectic(2; parameter=:field) + Sp_2 = SymplecticMatrices(2; parameter=:field) @test typeof(get_embedding(Sp_2)) === Euclidean{Tuple{Int,Int},ℝ} - @test repr(Sp_2) == "Symplectic(2, ℝ; parameter=:field)" + @test repr(Sp_2) == "SymplecticMatrices(2, ℝ; parameter=:field)" end end diff --git a/test/manifolds/symplecticstiefel.jl b/test/manifolds/symplecticstiefel.jl index 92f43c2d2b..2d2007a72f 100644 --- a/test/manifolds/symplecticstiefel.jl +++ b/test/manifolds/symplecticstiefel.jl @@ -140,7 +140,7 @@ end @test repr(SpSt_6_4) == "SymplecticStiefel(6, 4; field=ℝ)" @test representation_size(SpSt_6_4) == (6, 4) @test base_manifold(SpSt_6_4) === SpSt_6_4 - @test get_total_space(SpSt_6_4) == Symplectic(6) + @test get_total_space(SpSt_6_4) == SymplecticMatrices(6) @test !is_flat(SpSt_6_4) @test is_point(SpSt_6_4, p_6_4) @@ -238,7 +238,7 @@ end X_big = rand(M_big; vector_at=p_big, hamiltonian_norm=1.0) @test is_vector(M_big, p_big, X_big; error=:error, atol=1.0e-14) end - @testset "test_manifold(Symplectic(6), ...)" begin + @testset "test_manifold(SymplecticMatrices(6), ...)" begin types = [Matrix{Float64}] TEST_FLOAT32 && push!(types, Matrix{Float32}) TEST_STATIC_SIZED && push!(types, MMatrix{6,4,Float64,24}) @@ -312,6 +312,6 @@ end SpSt_6_4 = SymplecticStiefel(2 * 3, 2 * 2; parameter=:field) @test typeof(get_embedding(SpSt_6_4)) === Euclidean{Tuple{Int,Int},ℝ} @test repr(SpSt_6_4) == "SymplecticStiefel(6, 4; field=ℝ; parameter=:field)" - @test get_total_space(SpSt_6_4) == Symplectic(6; parameter=:field) + @test get_total_space(SpSt_6_4) == SymplecticMatrices(6; parameter=:field) end end From 385f9b59bcca9ebbd5a67923d3a5abf0619c1a70 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 18 Jan 2024 19:31:50 +0100 Subject: [PATCH 17/65] Rename SymplecticMatrix to SymplecticElement (#701, Point 2). --- docs/src/misc/notation.md | 2 +- src/Manifolds.jl | 2 +- src/deprecated.jl | 2 +- src/manifolds/Symplectic.jl | 100 +++++++++++++-------------- src/manifolds/SymplecticGrassmann.jl | 2 +- src/manifolds/SymplecticStiefel.jl | 20 +++--- test/manifolds/symplectic.jl | 41 +++++------ test/manifolds/symplecticstiefel.jl | 4 +- 8 files changed, 87 insertions(+), 86 deletions(-) diff --git a/docs/src/misc/notation.md b/docs/src/misc/notation.md index e564baddf0..a3fdf6e788 100644 --- a/docs/src/misc/notation.md +++ b/docs/src/misc/notation.md @@ -50,7 +50,7 @@ Within the documented functions, the utf8 symbols are used whenever possible, as | ``p`` | a point on ``\mathcal M`` | ``p_1, p_2, \ldots,q`` | for 3 points one might use ``x,y,z`` | | ``\operatorname{retr}_pX``| a retraction | | | ``ΞΎ`` | a set of tangent vectors | ``\{X_1,\ldots,X_n\}`` | | -| ``J_{2n} \in ℝ^{2nΓ—2n}`` | the [`SymplecticMatrix`](@ref) |Β | | +| ``J_{2n} \in ℝ^{2nΓ—2n}`` | the [`SymplecticElement`](@ref) |Β | | | ``T_p \mathcal M`` | the tangent space at ``p`` | | | | ``X`` | a tangent vector from ``T_p \mathcal M`` | ``X_1,X_2,\ldots,Y,Z`` | sometimes written with base point ``X_p`` | | ``\operatorname{tr}`` | trace (of a matrix) | | diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 20ca413e3e..534ad683b3 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -669,7 +669,7 @@ export Euclidean, SymplecticGrassmann, SymplecticMatrices, SymplecticStiefel, - SymplecticMatrix, + SymplecticElement, Torus, Tucker, UnitaryMatrices diff --git a/src/deprecated.jl b/src/deprecated.jl index ad091f408e..eea4fe49ac 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -6,4 +6,4 @@ @deprecate ExtrinsicEstimation() ExtrinsicEstimation(EfficientEstimator()) Base.@deprecate_binding Symplectic SymplecticMatrices -#Base.@deprecate_binding SynplecticMatrix SymplecticElement +Base.@deprecate_binding SymplecticMatrix SymplecticElement diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index 301653bf38..b38d684da4 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -8,7 +8,7 @@ the canonical symplectic form over ``𝔽^{2nΓ—2n}×𝔽^{2nΓ—2n}``, \quad \omega(x, y) = p^{\mathrm{T}} J_{2n} q, \ x, y \in 𝔽^{2nΓ—2n}, ``` -where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticElement`](@ref). The symplectic manifold consists of @@ -80,7 +80,7 @@ as an inner product over the embedding space ``ℝ^{2nΓ—2n}``, i.e. struct ExtendedSymplecticMetric <: AbstractMetric end @doc raw""" - SymplecticMatrix{T} + SymplecticElement{T} A lightweight structure to represent the action of the matrix representation of the canonical symplectic form, @@ -101,24 +101,24 @@ The canonical symplectic form is represented by The entire matrix is however not instantiated in memory, instead a scalar ``Ξ»`` of type `T` is stored, which is used to keep track of scaling and transpose operations -applied to each `SymplecticMatrix`. +applied to each `SymplecticElement`. This type acts similar to `I` from `LinearAlgeba`. # Constructor - SymplecticMatrix(Ξ»=1) + SymplecticElement(Ξ»=1) Generate the sumplectic matrix with scaling ``1``. """ -struct SymplecticMatrix{T} +struct SymplecticElement{T} Ξ»::T end -SymplecticMatrix() = SymplecticMatrix(1) -SymplecticMatrix(Ξ»::T) where {T<:Number} = SymplecticMatrix{T}(Ξ») +SymplecticElement() = SymplecticElement(1) +SymplecticElement(Ξ»::T) where {T<:Number} = SymplecticElement{T}(Ξ») -function SymplecticMatrix(arrays::Vararg{AbstractArray}) +function SymplecticElement(arrays::Vararg{AbstractArray}) TS = Base.promote_type(map(eltype, arrays)...) - return SymplecticMatrix(one(TS)) + return SymplecticElement(one(TS)) end @doc raw""" @@ -136,7 +136,7 @@ with the conversion function c_p(ΞΎ) = \frac{1}{2} pp^{\mathrm{T}} ΞΎ + \frac{1}{2} pJ_{2n} ΞΎ^{\mathrm{T}} pJ_{2n}, ``` -where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticElement`](@ref). Each of the terms ``c_p^1(ΞΎ) = p p^{\mathrm{T}} ΞΎ`` and ``c_p^2(ΞΎ) = pJ_{2n} ΞΎ^{\mathrm{T}} pJ_{2n}`` from the above definition of ``c_p(Ξ·)`` are themselves metric compatible in the sense that @@ -158,7 +158,7 @@ does have the correct range ``T_p\mathrm{Sp}(2n, ℝ)``. change_representer(::SymplecticMatrices, ::EuclideanMetric, p, X) function change_representer!(::SymplecticMatrices, Y, ::EuclideanMetric, p, X) - J = SymplecticMatrix(p, X) # J_{2n} + J = SymplecticElement(p, X) # J_{2n} pT_X = p' * X Y .= (1 / 2) .* p * (pT_X .+ J * pT_X' * J) return Y @@ -247,14 +247,14 @@ Checks whether `X` is a valid tangent vector at `p` on the [`SymplecticMatrices` ```math p^{T}J_{2n}X + X^{T}J_{2n}p = 0 ``` -holds (approximately), where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). +holds (approximately), where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticElement`](@ref). The tolerance can be set with `kwargs...` """ check_vector(::SymplecticMatrices, ::Any...) function check_vector(M::SymplecticMatrices, p, X::T; kwargs...) where {T} - J = SymplecticMatrix(p, X) + J = SymplecticElement(p, X) if !isapprox(X' * J * p, -p' * J * X; kwargs...) return DomainError( norm(X' * J * p + p' * J * X, 2), @@ -452,7 +452,7 @@ the symplectic inverse is defined as: A^{+} := J_{2k}^{\mathrm{T}} A^{\mathrm{T}} J_{2n}, ``` -where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticElement`](@ref). The symplectic inverse of A can be expressed explicitly as: @@ -601,12 +601,12 @@ which solves the constrained optimization problem ```` where ``h: ℝ^{2nΓ—2n} β†’ \operatorname{skew}(2n)`` denotes the restriction of ``X`` onto the tangent space ``T_p\operatorname{SpSt}(2n, 2k)`` -and ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). +and ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticElement`](@ref). """ project(::SymplecticMatrices, p, A) function project!(::SymplecticMatrices, Y, p, A) - J = SymplecticMatrix(Y, p, A) + J = SymplecticElement(Y, p, A) Jp = J * p function h(X) @@ -634,10 +634,10 @@ The closed form projection mapping is given by [GaoSonAbsilStykel:2021](@cite) \operatorname{P}^{T_p\mathrm{Sp}(2n)}_{g_p}(X) = pJ_{2n}\operatorname{sym}(p^{\mathrm{T}}J_{2n}^{\mathrm{T}}X), ```` -where ``\operatorname{sym}(A) = \frac{1}{2}(A + A^{\mathrm{T}})`` and and ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). +where ``\operatorname{sym}(A) = \frac{1}{2}(A + A^{\mathrm{T}})`` and and ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticElement`](@ref). """ function project!(::MetricManifold{<:Any,<:Euclidean,ExtendedSymplecticMetric}, Y, p, X) - J = SymplecticMatrix(p, X) + J = SymplecticElement(p, X) pTJTX = p' * J' * X sym_pTJTX = (1 / 2) .* (pTJTX + pTJTX') @@ -666,7 +666,7 @@ The closed form projection operator onto the normal space is given by [GaoSonAbs ```` where ``\operatorname{skew}(A) = \frac{1}{2}(A - A^{\mathrm{T}})`` -and ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). +and ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticElement`](@ref). This function is not exported. """ @@ -676,7 +676,7 @@ function project_normal!( p, X, ) where {𝔽} - J = SymplecticMatrix(p, X) + J = SymplecticElement(p, X) pTJTX = p' * J' * X skew_pTJTX = (1 / 2) .* (pTJTX .- pTJTX') Y .= p * J * skew_pTJTX @@ -705,7 +705,7 @@ second tangent vector space parametrization of [`SymplecticMatrices`](@ref). It first generates a random symmetric matrix ``S`` by `S = randn(2n, 2n)` and then symmetrizes it as `S = S + S'`. Then ``S`` is normalized to have Frobenius norm of `hamiltonian_norm` -and `X = pJS` is returned, where `J` is the [`SymplecticMatrix`](@ref). +and `X = pJS` is returned, where `J` is the [`SymplecticElement`](@ref). """ function Random.rand( M::SymplecticMatrices; @@ -727,7 +727,7 @@ function random_vector(M::SymplecticMatrices, p::AbstractMatrix; symmetric_norm= S = randn(2n, 2n) S .= (S + S') S *= symmetric_norm / norm(S) - lmul!(SymplecticMatrix(p), S) + lmul!(SymplecticElement(p), S) return p * S end @@ -787,7 +787,7 @@ Directly compute the symplectic inverse of ``p \in \mathrm{Sp}(2n)``, multiplied with ``q \in \mathrm{Sp}(2n)``. That is, this function efficiently computes ``p^+q = (J_{2n}p^{\mathrm{T}}J_{2n})q ∈ ℝ^{2nΓ—2n}``, -where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticElement`](@ref). """ function symplectic_inverse_times(M::SymplecticMatrices, p, q) @@ -821,14 +821,14 @@ function symplectic_inverse_times!(M::SymplecticMatrices, A, p, q) return A end -ndims(J::SymplecticMatrix) = 2 -copy(J::SymplecticMatrix) = SymplecticMatrix(copy(J.Ξ»)) -Base.eltype(::SymplecticMatrix{T}) where {T} = T -function Base.convert(::Type{SymplecticMatrix{T}}, J::SymplecticMatrix) where {T} - return SymplecticMatrix(convert(T, J.Ξ»)) +ndims(J::SymplecticElement) = 2 +copy(J::SymplecticElement) = SymplecticElement(copy(J.Ξ»)) +Base.eltype(::SymplecticElement{T}) where {T} = T +function Base.convert(::Type{SymplecticElement{T}}, J::SymplecticElement) where {T} + return SymplecticElement(convert(T, J.Ξ»)) end -function Base.show(io::IO, J::SymplecticMatrix) +function Base.show(io::IO, J::SymplecticElement) s = "$(J.Ξ»)" if occursin(r"\w+\s*[\+\-]\s*\w+", s) s = "($s)" @@ -836,31 +836,31 @@ function Base.show(io::IO, J::SymplecticMatrix) return print(io, typeof(J), "(): $(s)*[0 I; -I 0]") end -(Base.:-)(J::SymplecticMatrix) = SymplecticMatrix(-J.Ξ») +(Base.:-)(J::SymplecticElement) = SymplecticElement(-J.Ξ») -function (Base.:^)(J::SymplecticMatrix, n::Integer) +function (Base.:^)(J::SymplecticElement, n::Integer) return ifelse( n % 2 == 0, UniformScaling((-1)^(div(n, 2)) * (J.Ξ»)^n), - SymplecticMatrix((-1)^(div(n - 1, 2)) * (J.Ξ»)^n), + SymplecticElement((-1)^(div(n - 1, 2)) * (J.Ξ»)^n), ) end -(Base.:*)(x::Number, J::SymplecticMatrix) = SymplecticMatrix(x * J.Ξ») -(Base.:*)(J::SymplecticMatrix, x::Number) = SymplecticMatrix(x * J.Ξ») -function (Base.:*)(J::SymplecticMatrix, K::SymplecticMatrix) +(Base.:*)(x::Number, J::SymplecticElement) = SymplecticElement(x * J.Ξ») +(Base.:*)(J::SymplecticElement, x::Number) = SymplecticElement(x * J.Ξ») +function (Base.:*)(J::SymplecticElement, K::SymplecticElement) return LinearAlgebra.UniformScaling(-J.Ξ» * K.Ξ») end -Base.transpose(J::SymplecticMatrix) = -J -Base.adjoint(J::SymplecticMatrix) = SymplecticMatrix(-conj(J.Ξ»)) -Base.inv(J::SymplecticMatrix) = SymplecticMatrix(-(1 / J.Ξ»)) +Base.transpose(J::SymplecticElement) = -J +Base.adjoint(J::SymplecticElement) = SymplecticElement(-conj(J.Ξ»)) +Base.inv(J::SymplecticElement) = SymplecticElement(-(1 / J.Ξ»)) -(Base.:+)(J::SymplecticMatrix, K::SymplecticMatrix) = SymplecticMatrix(J.Ξ» + K.Ξ») -(Base.:-)(J::SymplecticMatrix, K::SymplecticMatrix) = SymplecticMatrix(J.Ξ» - K.Ξ») +(Base.:+)(J::SymplecticElement, K::SymplecticElement) = SymplecticElement(J.Ξ» + K.Ξ») +(Base.:-)(J::SymplecticElement, K::SymplecticElement) = SymplecticElement(J.Ξ» - K.Ξ») -(Base.:+)(J::SymplecticMatrix, p::AbstractMatrix) = p + J -function (Base.:+)(p::AbstractMatrix, J::SymplecticMatrix) +(Base.:+)(J::SymplecticElement, p::AbstractMatrix) = p + J +function (Base.:+)(p::AbstractMatrix, J::SymplecticElement) # When we are adding, the Matrices must match in size: two_n, two_k = size(p) if (two_n % 2 != 0) || (two_n != two_k) @@ -883,10 +883,10 @@ function (Base.:+)(p::AbstractMatrix, J::SymplecticMatrix) end # Binary minus: -(Base.:-)(J::SymplecticMatrix, p::AbstractMatrix) = J + (-p) -(Base.:-)(p::AbstractMatrix, J::SymplecticMatrix) = p + (-J) +(Base.:-)(J::SymplecticElement, p::AbstractMatrix) = J + (-p) +(Base.:-)(p::AbstractMatrix, J::SymplecticElement) = p + (-J) -function (Base.:*)(J::SymplecticMatrix, p::AbstractVecOrMat) +function (Base.:*)(J::SymplecticElement, p::AbstractVecOrMat) two_n = size(p)[1] if two_n % 2 != 0 throw(ArgumentError("'p' must have even row dimension, was: $(two_n) != 2n.")) @@ -904,7 +904,7 @@ function (Base.:*)(J::SymplecticMatrix, p::AbstractVecOrMat) return Jp end -function (Base.:*)(p::AbstractMatrix, J::SymplecticMatrix) +function (Base.:*)(p::AbstractMatrix, J::SymplecticElement) two_k = size(p)[2] if two_k % 2 != 0 throw(ArgumentError("'p' must have even column dimension, was: $(two_k) != 2k.")) @@ -921,7 +921,7 @@ function (Base.:*)(p::AbstractMatrix, J::SymplecticMatrix) return pJ end -function LinearAlgebra.lmul!(J::SymplecticMatrix, p::AbstractVecOrMat) +function LinearAlgebra.lmul!(J::SymplecticElement, p::AbstractVecOrMat) # Perform left multiplication by a symplectic matrix, # overwriting the matrix p in place: two_n = size(p)[1] @@ -942,7 +942,7 @@ function LinearAlgebra.lmul!(J::SymplecticMatrix, p::AbstractVecOrMat) return p end -function LinearAlgebra.rmul!(p::AbstractMatrix, J::SymplecticMatrix) +function LinearAlgebra.rmul!(p::AbstractMatrix, J::SymplecticElement) # Perform right multiplication by a symplectic matrix, # overwriting the matrix p in place: two_k = size(p)[2] @@ -964,7 +964,7 @@ function LinearAlgebra.rmul!(p::AbstractMatrix, J::SymplecticMatrix) return p end -function LinearAlgebra.mul!(A::AbstractVecOrMat, J::SymplecticMatrix, p::AbstractVecOrMat) +function LinearAlgebra.mul!(A::AbstractVecOrMat, J::SymplecticElement, p::AbstractVecOrMat) size_p = size(p) two_n = size_p[1] if two_n % 2 != 0 @@ -982,7 +982,7 @@ function LinearAlgebra.mul!(A::AbstractVecOrMat, J::SymplecticMatrix, p::Abstrac return A end -function LinearAlgebra.mul!(A::AbstractVecOrMat, p::AbstractMatrix, J::SymplecticMatrix) +function LinearAlgebra.mul!(A::AbstractVecOrMat, p::AbstractMatrix, J::SymplecticElementt) two_n, two_k = size(p) if two_k % 2 != 0 throw(ArgumentError("'p' must have even col dimension, was: $(two_k) != 2k.")) diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 35d2e8d037..80bb9c243a 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -89,7 +89,7 @@ where ``I_{2n}`` denotes the identity matrix and ``(β‹…)^+`` the [`symplectic_in """ function inner(M::SymplecticGrassmann, p, X, Y) n, k = get_parameter(M.size) - J = SymplecticMatrix(p, X, Y) # in BZ21 also J + J = SymplecticElement(p, X, Y) # in BZ21 also J # Procompute lu(p'p) since we solve a^{-1}* 3 times a = lu(p' * p) # note that p'p is symmetric, thus so is its inverse c=a^{-1} # we split the original trace into two one with I -> (X'Yc) diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 4e3c1faa21..3be288b917 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -9,7 +9,7 @@ The symplectic Stiefel manifold consists of all := \bigl\{ p ∈ ℝ^{2nΓ—2n} \ \big| \ p^{\mathrm{T}}J_{2n}p = J_{2k} \bigr\}, ```` -where ``J_{2n}`` denotes the [`SymplecticMatrix`](@ref) +where ``J_{2n}`` denotes the [`SymplecticElement`](@ref) ````math J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}. @@ -163,7 +163,7 @@ The tangent vector ``X`` can be written in the form ∈ ℝ^{2nΓ—2n}, ``` -where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticElement`](@ref). Using this expression for ``X``, the exponential mapping can be computed as @@ -225,7 +225,7 @@ exp(::SymplecticStiefel, p, X) function exp!(M::SymplecticStiefel, q, p, X) n, k = get_parameter(M.size) - J = SymplecticMatrix(p, X) + J = SymplecticElement(p, X) pT_p = lu(p' * p) # ∈ ℝ^{2kΓ—2k} C = pT_p \ X' # ∈ ℝ^{2kΓ—2n} @@ -307,7 +307,7 @@ g^{\mathrm{SpSt}}_p(X, Y) ``` """ function inner(::SymplecticStiefel, p, X, Y) - J = SymplecticMatrix(p, X, Y) # in BZ21 also J + J = SymplecticElement(p, X, Y) # in BZ21 also J # Procompute lu(p'p) since we solve a^{-1}* 3 times a = lu(p' * p) # note that p'p is symmetric, thus so is its inverse c=a^{-1} b = J' * p @@ -340,7 +340,7 @@ the symplectic inverse is defined as: A^{+} := J_{2k}^{\mathrm{T}} A^{\mathrm{T}} J_{2n}, ``` -where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticElement`](@ref). The symplectic inverse of a matrix A can be expressed explicitly as: ```math @@ -452,7 +452,7 @@ the restriction of ``X`` onto the tangent space ``T_p\mathrm{SpSt}(2n, 2k)``. project(::SymplecticStiefel, p, A) function project!(::SymplecticStiefel, Y, p, A) - J = SymplecticMatrix(Y, p, A) + J = SymplecticElement(Y, p, A) Jp = J * p function h(X) @@ -581,12 +581,12 @@ The manifold gradient `X` is computed from `Y` as X = Yp^{\mathrm{T}}p + J_{2n}pY^{\mathrm{T}}J_{2n}p, ``` -where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticMatrix`](@ref). +where ``J_{2n} = \begin{bmatrix} 0_n & I_n \\ -I_n & 0_n \end{bmatrix}`` denotes the [`SymplecticElement`](@ref). """ function riemannian_gradient(::SymplecticStiefel, p, Y) - Jp = SymplecticMatrix(p, Y) * p + Jp = SymplecticElement(p, Y) * p return Y * (p' * p) .+ Jp * (Y' * Jp) end @@ -597,7 +597,7 @@ function riemannian_gradient!( Y; embedding_metric::EuclideanMetric=EuclideanMetric(), ) - Jp = SymplecticMatrix(p, Y) * p + Jp = SymplecticElement(p, Y) * p X .= Y * (p' * p) .+ Jp * (Y' * Jp) return X end @@ -618,7 +618,7 @@ Directly compute the symplectic inverse of ``p ∈ \mathrm{SpSt}(2n, 2k)``, multiplied with ``q ∈ \mathrm{SpSt}(2n, 2k)``. That is, this function efficiently computes ``p^+q = (J_{2k}p^{\mathrm{T}}J_{2n})q ∈ ℝ^{2kΓ—2k}``, -where ``J_{2n}, J_{2k}`` are the [`SymplecticMatrix`](@ref) +where ``J_{2n}, J_{2k}`` are the [`SymplecticElement`](@ref) of sizes ``2nΓ—2n`` and ``2kΓ—2k`` respectively. This function performs this common operation without allocating more than diff --git a/test/manifolds/symplectic.jl b/test/manifolds/symplectic.jl index 751be1d263..0447ed646b 100644 --- a/test/manifolds/symplectic.jl +++ b/test/manifolds/symplectic.jl @@ -258,7 +258,7 @@ using ManifoldDiff @testset "Gradient Computations" begin test_f(p) = tr(p) - Q_grad = SymplecticMatrix(points[1]) + Q_grad = SymplecticElement(points[1]) analytical_grad_f(p) = (1 / 2) * (p * Q_grad * p * Q_grad + p * p') p_grad = convert(Array{Float64}, points[1]) @@ -291,9 +291,9 @@ using ManifoldDiff end end - @testset "SymplecticMatrix" begin + @testset "SymplecticElement" begin # TODO: Test for different type matrices. - @test SymplecticMatrix() == SymplecticMatrix(1) + @test SymplecticElement() == SymplecticElement(1) Sp_4 = SymplecticMatrices(4) pQ_1 = [ 0 0 -2 3 @@ -318,30 +318,30 @@ using ManifoldDiff -1 0 0 -2 4 -8 ] - Q = SymplecticMatrix(pQ_1, pQ_2) - Q2 = SymplecticMatrix(1) + Q = SymplecticElement(pQ_1, pQ_2) + Q2 = SymplecticElement(1) @testset "Type Basics" begin @test Q == Q2 @test ndims(Q) == 2 @test copy(Q) == Q - @test eltype(SymplecticMatrix(1 // 1)) == Rational{Int64} - @test convert(SymplecticMatrix{Float64}, Q) == SymplecticMatrix(1.0) - @test "$Q" == "SymplecticMatrix{Int64}(): 1*[0 I; -I 0]" + @test eltype(SymplecticElement(1 // 1)) == Rational{Int64} + @test convert(SymplecticElement{Float64}, Q) == SymplecticElement(1.0) + @test "$Q" == "SymplecticElement{Int64}(): 1*[0 I; -I 0]" @test ( - "$(SymplecticMatrix(1 + 2im))" == - "SymplecticMatrix{Complex{Int64}}(): (1 + 2im)*[0 I; -I 0]" + "$(SymplecticElement(1 + 2im))" == + "SymplecticElement{Complex{Int64}}(): (1 + 2im)*[0 I; -I 0]" ) end @testset "Matrix Operations" begin - @test -Q == SymplecticMatrix(-1) - @test (2 * Q) * (5 // 6) == SymplecticMatrix(5 // 3) + @test -Q == SymplecticElement(-1) + @test (2 * Q) * (5 // 6) == SymplecticElement(5 // 3) @testset "Powers" begin @test inv(Q) * Q == I @test ( - inv(SymplecticMatrix(-4.0 + 8im)) * SymplecticMatrix(-4.0 + 8im) == + inv(SymplecticElement(-4.0 + 8im)) * SymplecticElement(-4.0 + 8im) == UniformScaling(1.0 + 0.0im) ) @test Q * Q == -I @@ -351,7 +351,7 @@ using ManifoldDiff end @testset "Addition (subtraction)" begin @test Q + Q == 2 * Q - @test Q - SymplecticMatrix(1.0) == SymplecticMatrix(0.0) + @test Q - SymplecticElement(1.0) == SymplecticElement(0.0) @test Q + pQ_1 == [ 0 0 -1 3 0 0 1 0 @@ -375,13 +375,14 @@ using ManifoldDiff @test_throws ArgumentError Q + p_odd_row end @testset "Transpose-Adjoint" begin - @test Q' == SymplecticMatrix(-1) - @test transpose(SymplecticMatrix(10)) == SymplecticMatrix(-10) - @test transpose(SymplecticMatrix(1 - 2.0im)) == SymplecticMatrix(-1 + 2.0im) + @test Q' == SymplecticElement(-1) + @test transpose(SymplecticElement(10)) == SymplecticElement(-10) + @test transpose(SymplecticElement(1 - 2.0im)) == + SymplecticElement(-1 + 2.0im) @test adjoint(Q) == -Q - @test adjoint(SymplecticMatrix(1 - 2.0im)) == SymplecticMatrix(-1 - 2.0im) - @test adjoint(SymplecticMatrix(-1im)) == SymplecticMatrix(-1im) - @test adjoint(SymplecticMatrix(2.0)) == SymplecticMatrix(-2.0) + @test adjoint(SymplecticElement(1 - 2.0im)) == SymplecticElement(-1 - 2.0im) + @test adjoint(SymplecticElement(-1im)) == SymplecticElement(-1im) + @test adjoint(SymplecticElement(2.0)) == SymplecticElement(-2.0) end @testset "Inplace mul!" begin z1 = [1 + 2im; 1 - 2im] diff --git a/test/manifolds/symplecticstiefel.jl b/test/manifolds/symplecticstiefel.jl index 2d2007a72f..87c9f3fe55 100644 --- a/test/manifolds/symplecticstiefel.jl +++ b/test/manifolds/symplecticstiefel.jl @@ -4,7 +4,7 @@ using Manifolds: RiemannianProjectionBackend using ManifoldDiff function Ξ©(::SymplecticStiefel, p, X) - Q = SymplecticMatrix(X, p) + Q = SymplecticElement(X, p) pT_p = lu(p' * p) inv_pTp_pT = pT_p \ p' @@ -284,7 +284,7 @@ end end @testset "Gradient Computations" begin - Q_grad = SymplecticMatrix(points[1]) + Q_grad = SymplecticElement(points[1]) function test_f(p) k = size(p)[2] return tr(p[1:k, 1:k]) From de1cee2f499f849f4d7ec861ab3a1448e5483bc0 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 18 Jan 2024 19:57:27 +0100 Subject: [PATCH 18/65] this fixes a typo and I am getting a bit tired so I should stop also to write so long messages here. --- src/manifolds/Symplectic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index b38d684da4..4cf6794475 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -982,7 +982,7 @@ function LinearAlgebra.mul!(A::AbstractVecOrMat, J::SymplecticElement, p::Abstra return A end -function LinearAlgebra.mul!(A::AbstractVecOrMat, p::AbstractMatrix, J::SymplecticElementt) +function LinearAlgebra.mul!(A::AbstractVecOrMat, p::AbstractMatrix, J::SymplecticElement) two_n, two_k = size(p) if two_k % 2 != 0 throw(ArgumentError("'p' must have even col dimension, was: $(two_k) != 2k.")) From 9f8b71973009bc746fd0e9ac80b9319d9a99ed2b Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 19 Jan 2024 09:59:18 +0100 Subject: [PATCH 19/65] Fix references. --- src/manifolds/Hamiltonian.jl | 2 +- src/manifolds/SymplecticGrassmannStiefel.jl | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index 191f40281e..c5cf09c138 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -42,7 +42,7 @@ where ``β‹…^{+}`` denotes the [`symplectic_inverse`](@ref),. and ``𝔽 ∈ \{ Though it is slightly redundant, usually the matrices are stored as ``2nΓ—2n`` arrays. The symbol refers to the main usage within `Manifolds.jl` that is the -Lie algebra to the [`Symplectic`](@ref) as a Lie group with the matrix operation as group operation. +Lie algebra to the [`SymplecticMatrices`](@ref) as a Lie group with the matrix operation as group operation. # Constructor diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index 583263ee95..c0d7febfb1 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -52,8 +52,7 @@ end Compute the Cayley Inverse Retraction on the Symplectic Grassmann manifold, when the points are represented as symplectic bases, i.e. on the [`SymplecticStiefel`](@ref). -Here we can directly employ the [`CaleyInverseRetraction`](@ref) on the symplectic Stiefel manifold -itself, see [`inverse_retract(::SymplecticStiefel, p, q, ::CayleyInverseRetraction)``](@ref). +Here we can directly employ the `CaleyInverseRetraction` on the symplectic Stiefel manifold. """ inverse_retract(::SymplecticGrassmann, p, q, ::CayleyInverseRetraction) @@ -69,8 +68,7 @@ end Compute the Cayley retraction on the Symplectic Grassmann manifold, when the points are represented as symplectic bases, i.e. on the [`SymplecticStiefel`](@ref). -Here we can directly employ the [`CaleyRetraction`](@ref) on the symplectic Stiefel manifold -itself, see [`retract(::SymplecticStiefel, p, X, ::CayleyRetraction)``](@ref). +Here we can directly employ the `CaleyRetraction` on the symplectic Stiefel manifold. """ retract(::SymplecticGrassmann, p, X, ::CayleyRetraction) From 9173543f308f22bf595277fae8cbd9df6eb90c81 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 19 Jan 2024 16:40:24 +0100 Subject: [PATCH 20/65] Unify and extend rands. Introduce Riemannian Gradients. --- NEWS.md | 4 +- src/manifolds/Symplectic.jl | 69 ++++++++++++++++----- src/manifolds/SymplecticGrassmannStiefel.jl | 35 +++++++++++ src/manifolds/SymplecticStiefel.jl | 35 ++++++----- 4 files changed, 112 insertions(+), 31 deletions(-) diff --git a/NEWS.md b/NEWS.md index eaee731cbf..bb95c93808 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,8 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * added the real symplectic Grassmann manifold `SymplecticGrassmann` * Introduce the manifold of `HamiltonianMatrices` and a wrapper for `Hamiltonian` matrices * introduce `rand(:HamiltonianMatrices)` +* extend `rand` to also `rand!` for `HamiltonianMatrices`, `SymplecticMatrices` and `SymplecticStiefel` +* implement `riemannian_gradient` conversion for `SymplecticMatrices` and `SymplecticGrassmann` * Rename (deprecate) `Symplectic` to `SimplecticMatrices` in order to have a `Symplectic` wrapper for such matrices as well -* Rename (deprecate) `SymplecticMatrix` to `SymplecticElement` to cclarify that it is the special matrix ``J_{2n}`` and not an arbitrary symplectic matrix. +* Rename (deprecate) `SymplecticMatrix` to `SymplecticElement` to clarify that it is the special matrix ``J_{2n}`` and not an arbitrary symplectic matrix. ## [0.9.11] – 2023-12-27 diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index 4cf6794475..abdae1c00b 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -684,15 +684,14 @@ function project_normal!( end @doc raw""" - rand(::SymplecticStiefel; vector_at=nothing, - hamiltonian_norm = (vector_at === nothing ? 1/2 : 1.0)) + rand(::SymplecticStiefel; vector_at=nothing, Οƒ=1.0) Generate a random point on ``\mathrm{Sp}(2n)`` or a random tangent vector ``X \in T_p\mathrm{Sp}(2n)`` if `vector_at` is set to a point ``p \in \mathrm{Sp}(2n)``. A random point on ``\mathrm{Sp}(2n)`` is constructed by generating a -random Hamiltonian matrix ``Ξ© \in \mathfrak{sp}(2n,F)`` with norm `hamiltonian_norm`, +random Hamiltonian matrix ``Ξ© \in \mathfrak{sp}(2n,F)`` with norm `Οƒ`, and then transforming it to a symplectic matrix by applying the Cayley transform ```math @@ -704,31 +703,43 @@ To generate a random tangent vector in ``T_p\mathrm{Sp}(2n)``, this code employs second tangent vector space parametrization of [`SymplecticMatrices`](@ref). It first generates a random symmetric matrix ``S`` by `S = randn(2n, 2n)` and then symmetrizes it as `S = S + S'`. -Then ``S`` is normalized to have Frobenius norm of `hamiltonian_norm` +Then ``S`` is normalized to have Frobenius norm of `Οƒ` and `X = pJS` is returned, where `J` is the [`SymplecticElement`](@ref). """ -function Random.rand( - M::SymplecticMatrices; +rand(SymplecticMatrices; Οƒ::Rieal=1.0, kwargs...) + +function Random.rand!( + rng::AbstractRNG, + M::SymplecticMatrices, + pX; vector_at=nothing, - hamiltonian_norm=(vector_at === nothing ? 1 / 2 : 1.0), + hamiltonian_norm=nothing, + Οƒ=hamiltonian_norm === nothing ? 1.0 : hamiltonian_norm, ) + !(hamiltonian_norm === nothing) && Base.depwarn( + Random.rand!, + "hamiltonian_norm is deprecated as a keyword, please use the default Οƒ.", + ) n = get_parameter(M.size)[1] if vector_at === nothing - Ξ© = rand(HamiltonianMatrices(2n); Οƒ=hamiltonian_norm) - return (I - Ξ©) \ (I + Ξ©) + rand!(rng, HamiltonianMatrices(2n), pX; Οƒ=Οƒ) + pX .= (I - pX) \ (I + pX) + return pX else - random_vector(M, vector_at; symmetric_norm=hamiltonian_norm) + random_vector!(M, pX, vector_at; Οƒ=Οƒ) + return pX end end -function random_vector(M::SymplecticMatrices, p::AbstractMatrix; symmetric_norm=1.0) +function random_vector!(M::SymplecticMatrices, X, p; Οƒ=1.0) n = get_parameter(M.size)[1] # Generate random symmetric matrix: - S = randn(2n, 2n) - S .= (S + S') - S *= symmetric_norm / norm(S) - lmul!(SymplecticElement(p), S) - return p * S + randn!(X) + X .= 0.5 * (X + X') + X .*= Οƒ / norm(X) + lmul!(SymplecticElement(p), X) + X .= p * X + return X end function rand_hamiltonian(M::SymplecticMatrices; frobenius_norm=1.0) @@ -771,6 +782,32 @@ function retract_cayley!(M::SymplecticMatrices, q, p, X, t::Number) return q end +@doc raw""" + riemannian_gradient(M::SymplecticMatrices, p, Y) + +Given a gradient ``Y = \operatorname{grad} \tilde f(p)`` in the embedding ``ℝ^{2nΓ—2n}`` or at +least around the [`SymplecicMatrices`](@ref) `M` where `p` (the embedding of) a point on `M`, +we restrict ``\tilde f`` to the manifold and denote that by ``f``. +Then the Riemannian gradient ``X = \operatorname{grad} f(p)`` is given by + +```math + X = Yp^{\mathrm{T}}p + J_{2n}pY^{\mathrm{T}}J_{2n}p, +``` + +where ``J_{2n}`` denotes the [`SymplecticElement`)(@ref). + +""" +function riemannian_gradient(::SymplecticMatrices, p, Y; kwargs...) + J = SymplecticElement(p, X) + return Y * p'p .+ (J * p) * Y' * (J * p) +end + +function riemannian_gradient!(M::SymplecticMatrices, X, p, Y; kwargs...) + J = SymplecticElement(p, X) + X .= Y * p'p .+ (J * p) * Y' * (J * p) + return X +end + function Base.show(io::IO, ::SymplecticMatrices{TypeParameter{Tuple{n}},𝔽}) where {n,𝔽} return print(io, "SymplecticMatrices($(2n), $(𝔽))") end diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index c0d7febfb1..43d52a731d 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -77,3 +77,38 @@ function retract_cayley!(M::SymplecticGrassmann, q, p, X, t::Number) retract_cayley!(SymplecticStiefel(2 * n, 2 * k), q, p, X, t) return q end + +@doc raw""" + riemannian_gradient(M::SymplecticGrassmann, p, Y) + +Given a gradient ``Y = \operatorname{grad} \tilde f(p)`` in the embedding ``ℝ^{2nΓ—2k}`` or at +least around the [`SymplecicGrassmann`](@ref) `M` where `p` (the embedding of) a point on `M`, +and the restriction ``\tilde f`` to the [`SymplecticStiefel`] be invariant for the equivalence classes. +In other words ``f(p) = f(qp)`` for ``q \in \mathrm{Sp}(2k, ℝ)``. +Then the Riemannian gradient ``X = \operatorname{grad} f(p)`` is given by + +```math + X = J_{2n}^THJ_{2k}p^{\mathrm{T}}p - J_{2n}^TpJ_{2k}H^{\mathrm{T}}p, +``` + +where ``J_{2n}`` denotes the [`SymplecticElement`)(@ref), and +``H = (I_{2n} - pp^+)J_{2n}^{\mathrm{T}YJ``. +""" +function riemannian_gradient(::SymplecticGrassmann, p, Y; kwargs...) + n, k = get_parameter(M.size) + J = SymplecticElement(p, X) + # Since J' = -J We can write (J'YJ) = -J * (YJ) + JTYJ = (-J * (Y * J)) + H = (I - symplectic_inverse_times(SymplecticStiefel(2 * n, 2 * k), p, p)) * JTYJ + return (-J * (H * J)) * (p' * p) .- JTYJ * (H' * p) +end + +function riemannian_gradient!(M::SymplecticGrassmann, X, p, Y; kwargs...) + n, k = get_parameter(M.size) + J = SymplecticElement(p, X) + # Since J' = -J We can write (J'YJ) = -J * (YJ) + JTYJ = (-J * (Y * J)) + H = (I - symplectic_inverse_times(SymplecticStiefel(2 * n, 2 * k), p, p)) * JTYJ + X .= (-J * (H * J)) * (p' * p) .- JTYJ * (H' * p) + return X +end diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 3be288b917..2c3e5dfb69 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -469,8 +469,7 @@ function project!(::SymplecticStiefel, Y, p, A) end @doc raw""" - rand(M::SymplecticStiefel; vector_at=nothing, - hamiltonian_norm=(vector_at === nothing ? 1/2 : 1.0)) + rand(M::SymplecticStiefel; vector_at=nothing, Οƒ = 1.0) Generate a random point ``p ∈ \mathrm{SpSt}(2n, 2k)`` or a random tangent vector ``X ∈ T_p\mathrm{SpSt}(2n, 2k)`` @@ -488,28 +487,36 @@ this code exploits the second tangent vector space parametrization of can be written as ``X = pΞ©_X + p^sB_X``. To generate random tangent vectors at ``p`` then, this function sets ``B_X = 0`` and generates a random Hamiltonian matrix ``Ξ©_X ∈ \mathfrak{sp}(2n,F)`` with -Frobenius norm of `hamiltonian_norm` before returning ``X = pΞ©_X``. +Frobenius norm of `Οƒ` before returning ``X = pΞ©_X``. """ -function Random.rand( - M::SymplecticStiefel; +rand(M::SymplecticStiefel; Οƒ::Real=1.0, kwargs...) + +function Random.rand!( + rng::AbstractRNG, + M::SymplecticStiefel, + pX; vector_at=nothing, - hamiltonian_norm=(vector_at === nothing ? 1 / 2 : 1.0), + hamiltonian_norm=nothing, + Οƒ=hamiltonian_norm === nothing ? 1.0 : hamiltonian_norm, ) + !(hamiltonian_norm === nothing) && Base.depwarn( + Random.rand!, + "hamiltonian_norm is deprecated as a keyword, please use the default Οƒ.", + ) n, k = get_parameter(M.size) if vector_at === nothing - return canonical_project( - M, - rand(SymplecticMatrices(2n); hamiltonian_norm=hamiltonian_norm), - ) + canonical_project!(M, pX, rand(SymplecticMatrices(2n); Οƒ=Οƒ)) + return pX else - return random_vector(M, vector_at; hamiltonian_norm=hamiltonian_norm) + return random_vector!(M, pX, vector_at; Οƒ=Οƒ) end end -function random_vector(M::SymplecticStiefel, p::AbstractMatrix; hamiltonian_norm=1.0) +function random_vector!(M::SymplecticStiefel, X, p; Οƒ=1.0) k = get_parameter(M.size)[2] - Ξ© = rand(HamiltonianMatrices(2k); Οƒ=hamiltonian_norm) - return p * Ξ© + rand!(HamiltonianMatrices(2k), X; Οƒ=Οƒ) + X .= p * X + return X end @doc raw""" From 273de800d04559922ddd74453042480b83ad8365 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 19 Jan 2024 21:38:23 +0100 Subject: [PATCH 21/65] Apply suggestions from code review Co-authored-by: Mateusz Baran --- docs/src/manifolds/fiber_bundle.md | 2 +- src/manifolds/QuotientManifold.jl | 2 +- test/ambiguities.jl | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/src/manifolds/fiber_bundle.md b/docs/src/manifolds/fiber_bundle.md index c995126afd..b361719c6e 100644 --- a/docs/src/manifolds/fiber_bundle.md +++ b/docs/src/manifolds/fiber_bundle.md @@ -4,7 +4,7 @@ Fiber bundle $E$ is a manifold that is built on top of another manifold $\mathca It is characterized by a continuous function $Ξ  : E β†’ \mathcal M$. For each point $p ∈ \mathcal M$ the preimage of $p$ by $Ξ $, $Ξ ^{-1}(\{p\})$ is called a fiber $F$. Bundle projection can be performed using function [`bundle_projection`](@ref). -`Manifolds.jl` primarily deals with the case of trivial bundles, where $E$ can be identified with a product $M Γ—F$. +`Manifolds.jl` primarily deals with the case of trivial bundles, where $E$ can be topologically identified with a product $MΓ—F$. [Vector bundles](@ref VectorBundleSection) is a special case of a fiber bundle. Other examples include unit tangent bundle. Note that in general fiber bundles don't have a canonical Riemannian structure but can at least be equipped with an [Ehresmann connection](https://en.wikipedia.org/wiki/Ehresmann_connection), providing notions of parallel transport and curvature. diff --git a/src/manifolds/QuotientManifold.jl b/src/manifolds/QuotientManifold.jl index 8f8f8390c9..9ac2aa1873 100644 --- a/src/manifolds/QuotientManifold.jl +++ b/src/manifolds/QuotientManifold.jl @@ -177,7 +177,7 @@ end @doc raw""" vertical_component(N::AbstractManifold, p, X) - vertical_compontent(QuotientManifold{M,N}, p, X) + vertical_component(QuotientManifold{M,N}, p, X) Compute the vertical component of tangent vector `X` at point `p` in the total space of quotient manifold `N`. diff --git a/test/ambiguities.jl b/test/ambiguities.jl index da14e7a079..bd61a4cc77 100644 --- a/test/ambiguities.jl +++ b/test/ambiguities.jl @@ -1,6 +1,7 @@ """ - has_type_in_signature(sig, T) - Test whether the signature `sig` has an argument of type `T` as one of its paramaters + has_type_in_signature(sig, T::Type) + +Test whether the signature `sig` has an argument of type `T` as one of its parameters. """ function has_type_in_signature(sig, T::Type) return any(map(Base.unwrap_unionall(sig.sig).parameters) do x From 72d04e10a0c0c74916e234795c720959f4e6673b Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Fri, 19 Jan 2024 22:14:07 +0100 Subject: [PATCH 22/65] Fix 2 typos. --- src/manifolds/Symplectic.jl | 2 +- src/manifolds/SymplecticGrassmannStiefel.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index abdae1c00b..587d7f45dd 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -786,7 +786,7 @@ end riemannian_gradient(M::SymplecticMatrices, p, Y) Given a gradient ``Y = \operatorname{grad} \tilde f(p)`` in the embedding ``ℝ^{2nΓ—2n}`` or at -least around the [`SymplecicMatrices`](@ref) `M` where `p` (the embedding of) a point on `M`, +least around the [`SymplecticMatrices`](@ref) `M` where `p` (the embedding of) a point on `M`, we restrict ``\tilde f`` to the manifold and denote that by ``f``. Then the Riemannian gradient ``X = \operatorname{grad} f(p)`` is given by diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index 43d52a731d..f141ca31d9 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -82,7 +82,7 @@ end riemannian_gradient(M::SymplecticGrassmann, p, Y) Given a gradient ``Y = \operatorname{grad} \tilde f(p)`` in the embedding ``ℝ^{2nΓ—2k}`` or at -least around the [`SymplecicGrassmann`](@ref) `M` where `p` (the embedding of) a point on `M`, +least around the [`SymplecticGrassmann`](@ref) `M` where `p` (the embedding of) a point on `M`, and the restriction ``\tilde f`` to the [`SymplecticStiefel`] be invariant for the equivalence classes. In other words ``f(p) = f(qp)`` for ``q \in \mathrm{Sp}(2k, ℝ)``. Then the Riemannian gradient ``X = \operatorname{grad} f(p)`` is given by From 9b3dee376ea87d02c70af15ee8757c00af20d1cd Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 20 Jan 2024 12:55:44 +0100 Subject: [PATCH 23/65] =?UTF-8?q?Replace=20\to=20with=20=E2=86=92=20in=20L?= =?UTF-8?q?aTeX=20formulae.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/src/features/atlases.md | 6 +++--- docs/src/misc/notation.md | 8 ++++---- src/manifolds/EssentialManifold.jl | 2 +- src/manifolds/ProbabilitySimplex.jl | 2 +- src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/src/features/atlases.md b/docs/src/features/atlases.md index 58cece4be2..4302f7f0bf 100644 --- a/docs/src/features/atlases.md +++ b/docs/src/features/atlases.md @@ -1,6 +1,6 @@ # [Atlases and charts](@id atlases_and_charts) -Atlases on an ``n``-dimensional manifold $\mathcal M$ are collections of charts ``\mathcal A = \{(U_i, Ο†_i) \colon i \in I\}``, where ``I`` is a (finite or infinte) index family, such that ``U_i \subseteq \mathcal M`` is an open set and each chart ``Ο†_i: U_i \to ℝ^n`` is a homeomorphism. This means, that ``Ο†_i`` is bijective – sometimes also called one-to-one and onto - and continuous, and its inverse ``Ο†_i^{-1}`` is continuous as well. +Atlases on an ``n``-dimensional manifold $\mathcal M$ are collections of charts ``\mathcal A = \{(U_i, Ο†_i) \colon i \in I\}``, where ``I`` is a (finite or infinte) index family, such that ``U_i \subseteq \mathcal M`` is an open set and each chart ``Ο†_i: U_i β†’ ℝ^n`` is a homeomorphism. This means, that ``Ο†_i`` is bijective – sometimes also called one-to-one and onto - and continuous, and its inverse ``Ο†_i^{-1}`` is continuous as well. The inverse ``Ο†_i^{-1}`` is called (local) parametrization. The resulting _parameters_ ``a=Ο†(p)`` of ``p`` (with respect to the chart ``Ο†``) are in the literature also called β€œ(local) coordinates”. To distinguish the parameter ``a`` from [`get_coordinates`](@ref) in a basis, we use the terminology parameter in this package. @@ -13,7 +13,7 @@ For an atlas ``\mathcal A`` we further require that We say that ``Ο†_i`` is a chart about ``p``, if ``p\in U_i``. An atlas provides a connection between a manifold and the Euclidean space ``ℝ^n``, since locally, a chart about ``p`` can be used to identify its neighborhood (as long as you stay in ``U_i``) with a subset of a Euclidean space. -Most manifolds we consider are smooth, i.e. any change of charts ``Ο†_i \circ Ο†_j^{-1}: ℝ^n\toℝ^n``, where ``i,j\in I``, is a smooth function. These changes of charts are also called transition maps. +Most manifolds we consider are smooth, i.e. any change of charts ``Ο†_i \circ Ο†_j^{-1}: ℝ^n β†’ ℝ^n``, where ``i,j\in I``, is a smooth function. These changes of charts are also called transition maps. Most operations on manifolds in `Manifolds.jl` avoid operating in a chart through appropriate embeddings and formulas derived for particular manifolds, though atlases provide the most general way of working with manifolds. Compared to these approaches, using an atlas is often more technical and time-consuming. @@ -28,7 +28,7 @@ Operations using atlases and charts are available through the following function * [`get_parameters`](@ref Main.Manifolds.get_parameters) converts a point to its parameters with respect to the chart in a chart. * [`get_point`](@ref Main.Manifolds.get_point) converts parameters (local coordinates) in a chart to the point that corresponds to them. * [`induced_basis`](@ref Main.Manifolds.induced_basis) returns a basis of a given vector space at a point induced by a chart ``Ο†``. -* [`transition_map`](@ref Main.Manifolds.transition_map) converts coordinates of a point between two charts, e.g. computes ``Ο†_i\circ Ο†_j^{-1}: ℝ^n\toℝ^n``, ``i,j\in I``. +* [`transition_map`](@ref Main.Manifolds.transition_map) converts coordinates of a point between two charts, e.g. computes ``Ο†_i\circ Ο†_j^{-1}: ℝ^n β†’ ℝ^n``, ``i,j\in I``. While an atlas could store charts as explicit functions, it is favourable, that the [`get_parameters`] actually implements a chart ``Ο†``, [`get_point`](@ref) its inverse, the prametrization ``Ο†^{-1}``. diff --git a/docs/src/misc/notation.md b/docs/src/misc/notation.md index a3fdf6e788..a87fd187a8 100644 --- a/docs/src/misc/notation.md +++ b/docs/src/misc/notation.md @@ -18,18 +18,18 @@ Within the documented functions, the utf8 symbols are used whenever possible, as | ``\frac{\mathrm{D}}{\mathrm{d}t}`` | covariant derivative of a vector field ``X(t)`` | | | | ``T^*_p \mathcal M`` | the cotangent space at ``p`` | | | | ``ΞΎ`` | a cotangent vector from ``T^*_p \mathcal M`` | ``ΞΎ_1, ΞΎ_2,… ,Ξ·,\zeta`` | sometimes written with base point ``ΞΎ_p``. | -| ``\mathrm{d}\phi_p(q)`` | Differential of a map ``\phi: \mathcal M \to \mathcal N`` with respect to ``p`` at a point ``q``. For functions of multiple variables, for example ``\phi(p, p_1)`` where ``p \in \mathcal M`` and ``p_1 \in \mathcal M_1``, variable ``p`` is explicitly stated to specify with respect to which argument the differential is calculated. | ``\mathrm{d}\phi_q``, ``(\mathrm{d}\phi)_q``, ``(\phi_*)_q``, ``D_p\phi(q)`` | pushes tangent vectors ``X \in T_q \mathcal M`` forward to ``\mathrm{d}\phi_p(q)[X] \in T_{\phi(q)} \mathcal N`` | +| ``\mathrm{d}\phi_p(q)`` | Differential of a map ``\phi: \mathcal M β†’ \mathcal N`` with respect to ``p`` at a point ``q``. For functions of multiple variables, for example ``\phi(p, p_1)`` where ``p \in \mathcal M`` and ``p_1 \in \mathcal M_1``, variable ``p`` is explicitly stated to specify with respect to which argument the differential is calculated. | ``\mathrm{d}\phi_q``, ``(\mathrm{d}\phi)_q``, ``(\phi_*)_q``, ``D_p\phi(q)`` | pushes tangent vectors ``X \in T_q \mathcal M`` forward to ``\mathrm{d}\phi_p(q)[X] \in T_{\phi(q)} \mathcal N`` | | ``n`` | dimension (of a manifold) | ``n_1,n_2,\ldots,m, \dim(\mathcal M)``| for the real dimension sometimes also ``\dim_{\mathbb R}(\mathcal M)``| | ``d(β‹…,β‹…)`` | (Riemannian) distance | ``d_{\mathcal M}(β‹…,β‹…)`` | | | ``\exp_p X`` | exponential map at ``p \in \mathcal M`` of a vector ``X \in T_p \mathcal M`` | ``\exp_p(X)`` | | | ``F`` | a fiber | | see [`Fiber`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#Fiber) | | ``\mathbb F`` | a field, usually ``\mathbb F \in \{\mathbb R,\mathbb C, \mathbb H\}``, i.e. the real, complex, and quaternion numbers, respectively. | |field a manifold or a basis is based on | | ``\gamma`` | a geodesic | ``\gamma_{p;q}``, ``\gamma_{p,X}`` | connecting two points ``p,q`` or starting in ``p`` with velocity ``X``. | -| ``\operatorname{grad} f(p)`` | (Riemannian) gradient of function ``f \colon \mathcal{M} \to ℝ`` at ``p \in \mathcal{M}`` | | | -| ``\nabla f(p)`` | (Euclidean) gradient of function ``f \colon \mathcal{M} \to ℝ`` at ``p \in \mathcal{M}`` but thought of as evaluated in the embedding | `G` | | +| ``\operatorname{grad} f(p)`` | (Riemannian) gradient of function ``f \colon \mathcal{M} β†’ ℝ`` at ``p \in \mathcal{M}`` | | | +| ``\nabla f(p)`` | (Euclidean) gradient of function ``f \colon \mathcal{M} β†’ ℝ`` at ``p \in \mathcal{M}`` but thought of as evaluated in the embedding | `G` | | | ``\circ`` | a group operation |Β | | ``β‹…^\mathrm{H}`` | Hermitian or conjugate transposed for both complex or quaternion matrices| | -| ``\operatorname{Hess} f(p)`` | (Riemannian) Hessian of function ``f \colon T_p\mathcal{M} \to T_p\mathcal M`` (i.e. the 1-1-tensor form) at ``p \in \mathcal{M}`` | | | +| ``\operatorname{Hess} f(p)`` | (Riemannian) Hessian of function ``f \colon T_p\mathcal{M} β†’ T_p\mathcal M`` (i.e. the 1-1-tensor form) at ``p \in \mathcal{M}`` | | | | ``\nabla^2 f(p)`` | (Euclidean) Hessian of function ``f`` in the embedding | `H` | | | ``e`` | identity element of a group | | | ``I_k`` | identity matrix of size ``kΓ—k`` |Β | diff --git a/src/manifolds/EssentialManifold.jl b/src/manifolds/EssentialManifold.jl index cf36ef6169..0cabf9eaf3 100644 --- a/src/manifolds/EssentialManifold.jl +++ b/src/manifolds/EssentialManifold.jl @@ -39,7 +39,7 @@ E = (R'_1)^T [T'_2 - T'_1]_{Γ—} R'_2, ```` where the poses of two cameras ``(R_i', T_i'), i=1,2``, are contained in the space of -rigid body transformations $SE(3)$ and the operator $[β‹…]_{Γ—}\colon ℝ^3 \to \operatorname{SkewSym}(3)$ +rigid body transformations $SE(3)$ and the operator $[β‹…]_{Γ—}\colon ℝ^3 β†’ \operatorname{SkewSym}(3)$ denotes the matrix representation of the cross product operator. For more details see [TronDaniilidis:2017](@cite). # Constructor diff --git a/src/manifolds/ProbabilitySimplex.jl b/src/manifolds/ProbabilitySimplex.jl index 7a7983314d..86cbd46fc6 100644 --- a/src/manifolds/ProbabilitySimplex.jl +++ b/src/manifolds/ProbabilitySimplex.jl @@ -82,7 +82,7 @@ end @doc raw""" change_metric(M::ProbabilitySimplex, ::EuclideanMetric, p, X) -To change the metric, we are looking for a function ``c\colon T_pΞ”^n \to T_pΞ”^n`` such that for all ``X,Y ∈ T_pΞ”^n`` +To change the metric, we are looking for a function ``c\colon T_pΞ”^n β†’ T_pΞ”^n`` such that for all ``X,Y ∈ T_pΞ”^n`` This can be achieved by rewriting representer change in matrix form as `(Diagonal(p) - p * p') * X` and taking square root of the matrix """ diff --git a/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl b/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl index 5be7335301..612b26216c 100644 --- a/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl +++ b/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl @@ -37,7 +37,7 @@ Given a tangent vector ``X ∈ T_p\mathcal P(n)`` with respect to the [`Euclidea `g_E`, this function changes into the [`AffineInvariantMetric`](@ref) (default) metric on the [`SymmetricPositiveDefinite`](@ref) `M`. -To be precise we are looking for ``c\colon T_p\mathcal P(n) \to T_p\mathcal P(n) `` +To be precise we are looking for ``c\colon T_p\mathcal P(n) β†’ T_p\mathcal P(n) `` such that for all ``Y,Z ∈ T_p\mathcal P(n)``` it holds ```math From 52db3004bcdee2ed4606efd8eeb018e3e683c9f5 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 20 Jan 2024 13:36:36 +0100 Subject: [PATCH 24/65] Start new test file, fix an old test. --- src/manifolds/SymplecticStiefel.jl | 12 +++++----- test/manifolds/symplecticgrassmann.jl | 1 + test/manifolds/symplecticstiefel.jl | 34 +++++++++++++-------------- test/runtests.jl | 1 + 4 files changed, 25 insertions(+), 23 deletions(-) create mode 100644 test/manifolds/symplecticgrassmann.jl diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 2c3e5dfb69..a33ed3e3cd 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -483,7 +483,7 @@ That is, ``p = Ο€_{\mathrm{SpSt}(2n, 2k)}(p_{\mathrm{Sp}})``. To generate a random tangent vector in ``T_p\mathrm{SpSt}(2n, 2k)`` this code exploits the second tangent vector space parametrization of -[`SymplecticStiefel`](@ref), showing that any ``X ∈ T_p\mathrm{SpSt}(2n, 2k)`` +[`SymplecticStiefel`](@ref), that any ``X ∈ T_p\mathrm{SpSt}(2n, 2k)`` can be written as ``X = pΞ©_X + p^sB_X``. To generate random tangent vectors at ``p`` then, this function sets ``B_X = 0`` and generates a random Hamiltonian matrix ``Ξ©_X ∈ \mathfrak{sp}(2n,F)`` with @@ -505,17 +505,17 @@ function Random.rand!( ) n, k = get_parameter(M.size) if vector_at === nothing - canonical_project!(M, pX, rand(SymplecticMatrices(2n); Οƒ=Οƒ)) + canonical_project!(M, pX, rand(rng, SymplecticMatrices(2n); Οƒ=Οƒ)) return pX else - return random_vector!(M, pX, vector_at; Οƒ=Οƒ) + return random_vector!(rng, M, pX, vector_at; Οƒ=Οƒ) end end -function random_vector!(M::SymplecticStiefel, X, p; Οƒ=1.0) +function random_vector!(rng, M::SymplecticStiefel, X, p; Οƒ=1.0) k = get_parameter(M.size)[2] - rand!(HamiltonianMatrices(2k), X; Οƒ=Οƒ) - X .= p * X + Ξ© = rand(rng, HamiltonianMatrices(2k); Οƒ=Οƒ) + X .= p * Ξ© return X end diff --git a/test/manifolds/symplecticgrassmann.jl b/test/manifolds/symplecticgrassmann.jl new file mode 100644 index 0000000000..e22146d9c3 --- /dev/null +++ b/test/manifolds/symplecticgrassmann.jl @@ -0,0 +1 @@ +include("../header.jl") diff --git a/test/manifolds/symplecticstiefel.jl b/test/manifolds/symplecticstiefel.jl index 87c9f3fe55..0dd2e23297 100644 --- a/test/manifolds/symplecticstiefel.jl +++ b/test/manifolds/symplecticstiefel.jl @@ -25,22 +25,22 @@ end @testset "Real" begin SpSt_6_4 = SymplecticStiefel(2 * 3, 2 * 2) - p_6_4 = Array{Float64}([ - 0 0 -5 -1 - 0 0 9 -2 - 0 0 -2 1 - -2 -9 -3 6 - -3 -13 -21 9 - -8 -36 18 -6 - ]) - q_6_4 = Array{Float64}([ - 0 0 -3 1 - 0 0 8 -3 - 0 0 -2 1 - -1 -4 -6 3 - -1 -3 -21 9 - -2 -6 18 -6 - ]) + p_6_4 = [ + 0.0 0.0 -5.0 -1.0 + 0.0 0.0 9.0 -2.0 + 0.0 0.0 -2.0 1.0 + -2.0 -9.0 -3.0 6.0 + -3.0 -13.0 -21.0 9.0 + -8.0 -36.0 18.0 -6.0 + ] + q_6_4 = [ + 0.0 0.0 -3.0 1.0 + 0.0 0.0 8.0 -3.0 + 0.0 0.0 -2.0 1.0 + -1.0 -4.0 -6.0 3.0 + -1.0 -3.0 -21.0 9.0 + -2.0 -6.0 18.0 -6.0 + ] X1 = [ 0.0 0.0 4.25 4.25 0.0 0.0 0.125 0.125 @@ -235,7 +235,7 @@ end M_big = SymplecticStiefel(20, 10) p_big = rand(M_big) @test is_point(M_big, p_big; error=:error, atol=1.0e-14) - X_big = rand(M_big; vector_at=p_big, hamiltonian_norm=1.0) + X_big = rand(M_big; vector_at=p_big) @test is_vector(M_big, p_big, X_big; error=:error, atol=1.0e-14) end @testset "test_manifold(SymplecticMatrices(6), ...)" begin diff --git a/test/runtests.jl b/test/runtests.jl index 7a8e331b10..a96ea13f23 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -168,6 +168,7 @@ end include_test("manifolds/spd_fixed_determinant.jl") include_test("manifolds/symmetric_positive_semidefinite_fixed_rank.jl") include_test("manifolds/symplectic.jl") + include_test("manifolds/symplecticgrassmann.jl") include_test("manifolds/symplecticstiefel.jl") include_test("manifolds/tucker.jl") include_test("manifolds/unitary_matrices.jl") From 009622ba20fe21ee0f25f91797b8ecf6d2cb9f43 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 20 Jan 2024 13:38:05 +0100 Subject: [PATCH 25/65] Fix News.md --- NEWS.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index bb95c93808..7e24ebf002 100644 --- a/NEWS.md +++ b/NEWS.md @@ -14,8 +14,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * introduce `rand(:HamiltonianMatrices)` * extend `rand` to also `rand!` for `HamiltonianMatrices`, `SymplecticMatrices` and `SymplecticStiefel` * implement `riemannian_gradient` conversion for `SymplecticMatrices` and `SymplecticGrassmann` -* Rename (deprecate) `Symplectic` to `SimplecticMatrices` in order to have a `Symplectic` wrapper for such matrices as well -* Rename (deprecate) `SymplecticMatrix` to `SymplecticElement` to clarify that it is the special matrix ``J_{2n}`` and not an arbitrary symplectic matrix. + +### Deprecated + +* Rename `Symplectic` to `SimplecticMatrices` in order to have a `Symplectic` wrapper for such matrices as well in the future for the next breaking change. +* Rename `SymplecticMatrix` to `SymplecticElement` to clarify that it is the special matrix ``J_{2n}`` and not an arbitrary symplectic matrix. + ## [0.9.11] – 2023-12-27 From aca6452e4493d56f6a03308bab0ea6b8a4229192 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 20 Jan 2024 13:45:12 +0100 Subject: [PATCH 26/65] Improve memory a bit. --- src/manifolds/SymplecticStiefel.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index a33ed3e3cd..1b2d5a22f9 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -514,7 +514,8 @@ end function random_vector!(rng, M::SymplecticStiefel, X, p; Οƒ=1.0) k = get_parameter(M.size)[2] - Ξ© = rand(rng, HamiltonianMatrices(2k); Οƒ=Οƒ) + Ξ© = @view(X[1:(2k), 1:(2k)]) # use this memory + rand!(rng, HamiltonianMatrices(2k), Ξ©; Οƒ=Οƒ) X .= p * Ξ© return X end From 1e9da054869cadf57c9624e0b9b100ac6a72b4c2 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 20 Jan 2024 14:06:09 +0100 Subject: [PATCH 27/65] Fix doc strings. --- src/manifolds/SymplecticGrassmann.jl | 4 ++-- src/manifolds/SymplecticGrassmannStiefel.jl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 80bb9c243a..51c864c265 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -81,8 +81,8 @@ is a point on the [`SymplecticStiefel`](@ref) manifold and ``X,Y \in \mathrm{Hor are horizontal tangent vectors. The formula reads according to Proposition Lemma 4.8 [BendokatZimmermann:2021](@cite). ```math -g^{\mathrm{SpGr}_p(X,Y) = \operatorname{tr}\bigl( - (p^{\mathrm{T}p)^{-1}X^{\mathrm{T}}(I_{2n} - pp^+)Y +g^{\mathrm{SpGr}}_p(X,Y) = \operatorname{tr}\bigl( + (p^{\mathrm{T}}p)^{-1}X^{\mathrm{T}}(I_{2n} - pp^+)Y \bigr), ``` where ``I_{2n}`` denotes the identity matrix and ``(β‹…)^+`` the [`symplectic_inverse`](@ref). diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index f141ca31d9..83148b716b 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -91,8 +91,8 @@ Then the Riemannian gradient ``X = \operatorname{grad} f(p)`` is given by X = J_{2n}^THJ_{2k}p^{\mathrm{T}}p - J_{2n}^TpJ_{2k}H^{\mathrm{T}}p, ``` -where ``J_{2n}`` denotes the [`SymplecticElement`)(@ref), and -``H = (I_{2n} - pp^+)J_{2n}^{\mathrm{T}YJ``. +where ``J_{2n}`` denotes the [`SymplecticElement`](@ref), and +``H = (I_{2n} - pp^+)J_{2n}^{\mathrm{T}}YJ``. """ function riemannian_gradient(::SymplecticGrassmann, p, Y; kwargs...) n, k = get_parameter(M.size) From 22717dff7df75a371cc4ec0813d133ae435f5929 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 20 Jan 2024 14:32:22 +0100 Subject: [PATCH 28/65] =?UTF-8?q?$=20=E2=86=92=20``=20for=20math,=20\mathb?= =?UTF-8?q?b=20R=20=E2=86=92=20=E2=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/src/features/atlases.md | 2 +- docs/src/features/utilities.md | 2 +- docs/src/manifolds/connection.md | 2 +- docs/src/manifolds/essentialmanifold.md | 2 +- docs/src/manifolds/euclidean.md | 4 +- docs/src/manifolds/fiber_bundle.md | 6 +-- docs/src/manifolds/graph.md | 6 +-- docs/src/manifolds/metric.md | 4 +- docs/src/manifolds/oblique.md | 4 +- docs/src/manifolds/power.md | 8 ++-- docs/src/manifolds/product.md | 4 +- docs/src/manifolds/rotations.md | 12 +++--- docs/src/manifolds/sphere.md | 4 +- docs/src/manifolds/symplectic.md | 24 +++++------ docs/src/manifolds/symplecticstiefel.md | 20 +++++----- docs/src/manifolds/torus.md | 8 ++-- docs/src/manifolds/vector_bundle.md | 6 +-- src/Manifolds.jl | 2 +- src/cotangent_space.jl | 4 +- src/groups/metric.jl | 2 +- src/groups/rotation_action.jl | 2 +- src/groups/special_euclidean.jl | 2 +- src/manifolds/EssentialManifold.jl | 14 +++---- src/manifolds/Hyperbolic.jl | 4 +- src/manifolds/HyperbolicHyperboloid.jl | 4 +- src/manifolds/HyperbolicPoincareBall.jl | 4 +- src/manifolds/HyperbolicPoincareHalfspace.jl | 4 +- src/manifolds/Multinomial.jl | 8 ++-- src/manifolds/MultinomialDoublyStochastic.jl | 16 ++++---- src/manifolds/MultinomialSymmetric.jl | 2 +- src/manifolds/ProbabilitySimplex.jl | 4 +- src/manifolds/ProjectiveSpace.jl | 40 +++++++++---------- src/manifolds/Spectrahedron.jl | 22 +++++----- src/manifolds/Sphere.jl | 16 ++++---- ...ymmetricPositiveDefiniteAffineInvariant.jl | 4 +- .../SymmetricPositiveDefiniteLogCholesky.jl | 18 ++++----- src/manifolds/Symplectic.jl | 2 +- src/manifolds/SymplecticGrassmann.jl | 2 +- src/manifolds/Torus.jl | 2 +- src/statistics.jl | 2 +- 40 files changed, 149 insertions(+), 149 deletions(-) diff --git a/docs/src/features/atlases.md b/docs/src/features/atlases.md index 4302f7f0bf..a0f4067af6 100644 --- a/docs/src/features/atlases.md +++ b/docs/src/features/atlases.md @@ -1,6 +1,6 @@ # [Atlases and charts](@id atlases_and_charts) -Atlases on an ``n``-dimensional manifold $\mathcal M$ are collections of charts ``\mathcal A = \{(U_i, Ο†_i) \colon i \in I\}``, where ``I`` is a (finite or infinte) index family, such that ``U_i \subseteq \mathcal M`` is an open set and each chart ``Ο†_i: U_i β†’ ℝ^n`` is a homeomorphism. This means, that ``Ο†_i`` is bijective – sometimes also called one-to-one and onto - and continuous, and its inverse ``Ο†_i^{-1}`` is continuous as well. +Atlases on an ``n``-dimensional manifold ``mathcal M``are collections of charts ``\mathcal A = \{(U_i, Ο†_i) \colon i \in I\}``, where ``I`` is a (finite or infinte) index family, such that ``U_i \subseteq \mathcal M`` is an open set and each chart ``Ο†_i: U_i β†’ ℝ^n`` is a homeomorphism. This means, that ``Ο†_i`` is bijective – sometimes also called one-to-one and onto - and continuous, and its inverse ``Ο†_i^{-1}`` is continuous as well. The inverse ``Ο†_i^{-1}`` is called (local) parametrization. The resulting _parameters_ ``a=Ο†(p)`` of ``p`` (with respect to the chart ``Ο†``) are in the literature also called β€œ(local) coordinates”. To distinguish the parameter ``a`` from [`get_coordinates`](@ref) in a basis, we use the terminology parameter in this package. diff --git a/docs/src/features/utilities.md b/docs/src/features/utilities.md index b1ecffe3c5..f32a5b945c 100644 --- a/docs/src/features/utilities.md +++ b/docs/src/features/utilities.md @@ -2,7 +2,7 @@ ## Ease of notation -The following terms introduce a nicer notation for some operations, for example using the ∈ operator, $p ∈ \mathcal M$, to determine whether $p$ is a point on the [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) $\mathcal M$. +The following terms introduce a nicer notation for some operations, for example using the ∈ operator, `` ∈ \mathcal M`` to determine whether ``p`` is a point on the [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) ``\mathcal M``. ````@docs in diff --git a/docs/src/manifolds/connection.md b/docs/src/manifolds/connection.md index 9aa6b08e05..07b1a61ad8 100644 --- a/docs/src/manifolds/connection.md +++ b/docs/src/manifolds/connection.md @@ -1,6 +1,6 @@ # [Connection manifold](@id ConnectionSection) -A connection manifold always consists of a [topological manifold](https://en.wikipedia.org/wiki/Topological_manifold) together with a [connection](https://en.wikipedia.org/wiki/Connection_(mathematics)) $\Gamma$. +A connection manifold always consists of a [topological manifold](https://en.wikipedia.org/wiki/Topological_manifold) together with a [connection](https://en.wikipedia.org/wiki/Connection_(mathematics)) ``\Gamma``. However, often there is an implicitly assumed (default) connection, like the [`LeviCivitaConnection`](@ref) connection on a Riemannian manifold. It is not necessary to use this decorator if you implement just one (or the first) connection. diff --git a/docs/src/manifolds/essentialmanifold.md b/docs/src/manifolds/essentialmanifold.md index 8fadf05856..2aa07f3a1c 100644 --- a/docs/src/manifolds/essentialmanifold.md +++ b/docs/src/manifolds/essentialmanifold.md @@ -1,5 +1,5 @@ # Essential Manifold -The essential manifold is modeled as an [`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) of the $3Γ—3$ [`Rotations`](@ref) and uses [`NestedPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedPowerRepresentation). +The essential manifold is modeled as an [`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) of the ``3Γ—3`` [`Rotations`](@ref) and uses [`NestedPowerRepresentation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.NestedPowerRepresentation). ```@autodocs Modules = [Manifolds] diff --git a/docs/src/manifolds/euclidean.md b/docs/src/manifolds/euclidean.md index 1d420b8ac2..a93aaddf1f 100644 --- a/docs/src/manifolds/euclidean.md +++ b/docs/src/manifolds/euclidean.md @@ -1,7 +1,7 @@ # [Euclidean space](@id EuclideanSection) -The Euclidean space $ℝ^n$ is a simple model space, since it has curvature constantly zero everywhere; hence, nearly all operations simplify. -The easiest way to generate an Euclidean space is to use a field, i.e. [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system), e.g. to create the $ℝ^n$ or $ℝ^{nΓ—n}$ you can simply type `M = ℝ^n` or `ℝ^(n,n)`, respectively. +The Euclidean space ``ℝ^n`` is a simple model space, since it has curvature constantly zero everywhere; hence, nearly all operations simplify. +The easiest way to generate an Euclidean space is to use a field, i.e. [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system), e.g. to create the ``ℝ^n`` or ``ℝ^{nΓ—n}`` you can simply type `M = ℝ^n` or `ℝ^(n,n)`, respectively. ```@autodocs Modules = [Manifolds] diff --git a/docs/src/manifolds/fiber_bundle.md b/docs/src/manifolds/fiber_bundle.md index b361719c6e..9a25487e7d 100644 --- a/docs/src/manifolds/fiber_bundle.md +++ b/docs/src/manifolds/fiber_bundle.md @@ -1,10 +1,10 @@ # [Fiber bundles](@id FiberBundleSection) -Fiber bundle $E$ is a manifold that is built on top of another manifold $\mathcal M$ (base space). -It is characterized by a continuous function $Ξ  : E β†’ \mathcal M$. For each point $p ∈ \mathcal M$ the preimage of $p$ by $Ξ $, $Ξ ^{-1}(\{p\})$ is called a fiber $F$. +Fiber bundle ``E`` is a manifold that is built on top of another manifold ``\mathcal M`` (base space). +It is characterized by a continuous function ``Ξ  : E β†’ \mathcal M``. For each point ``p ∈ \mathcal M`` the preimage of ``p`` by ``Ξ ``, ``Ξ ^{-1}(\{p\})`` is called a fiber ``F``. Bundle projection can be performed using function [`bundle_projection`](@ref). -`Manifolds.jl` primarily deals with the case of trivial bundles, where $E$ can be topologically identified with a product $MΓ—F$. +`Manifolds.jl` primarily deals with the case of trivial bundles, where ``E`` can be topologically identified with a product ``MΓ—F``. [Vector bundles](@ref VectorBundleSection) is a special case of a fiber bundle. Other examples include unit tangent bundle. Note that in general fiber bundles don't have a canonical Riemannian structure but can at least be equipped with an [Ehresmann connection](https://en.wikipedia.org/wiki/Ehresmann_connection), providing notions of parallel transport and curvature. diff --git a/docs/src/manifolds/graph.md b/docs/src/manifolds/graph.md index f744fdfb27..0dc2b0e229 100644 --- a/docs/src/manifolds/graph.md +++ b/docs/src/manifolds/graph.md @@ -1,11 +1,11 @@ # Graph manifold -For a given graph $G(V,E)$ implemented using [`Graphs.jl`](https://juliagraphs.github.io/Graphs.jl/latest/), the [`GraphManifold`](@ref) models a [`PowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.PowerManifold) either on the nodes or edges of the graph, depending on the [`GraphManifoldType`](@ref). -i.e., it's either a $\mathcal M^{\lvert V \rvert}$ for the case of a vertex manifold or a $\mathcal M^{\lvert E \rvert}$ for the case of a edge manifold. +For a given graph ``G(V,E)`` implemented using [`Graphs.jl`](https://juliagraphs.github.io/Graphs.jl/latest/), the [`GraphManifold`](@ref) models a [`PowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.PowerManifold) either on the nodes or edges of the graph, depending on the [`GraphManifoldType`](@ref). +i.e., it's either a ``\mathcal M^{\lvert V \rvert}`` for the case of a vertex manifold or a ``\mathcal M^{\lvert E \rvert}`` for the case of a edge manifold. ## Example -To make a graph manifold over $ℝ^2$ with three vertices and two edges, one can use +To make a graph manifold over ``ℝ^2`` with three vertices and two edges, one can use ```@example using Manifolds diff --git a/docs/src/manifolds/metric.md b/docs/src/manifolds/metric.md index 96bde7a440..b57ea3d829 100644 --- a/docs/src/manifolds/metric.md +++ b/docs/src/manifolds/metric.md @@ -1,6 +1,6 @@ # Metric manifold -A Riemannian manifold always consists of a [topological manifold](https://en.wikipedia.org/wiki/Topological_manifold) together with a smoothly varying metric $g$. +A Riemannian manifold always consists of a [topological manifold](https://en.wikipedia.org/wiki/Topological_manifold) together with a smoothly varying metric ``g``. However, often there is an implicitly assumed (default) metric, like the usual inner product on [`Euclidean`](@ref) space. This decorator takes this into account. @@ -17,7 +17,7 @@ Pages = ["metric.md"] Depth = 2 ``` -Note that a metric manifold is has a [`IsConnectionManifold`](@ref) trait referring to the [`LeviCivitaConnection`](@ref) of the metric $g$, and thus a large part of metric manifold's functionality relies on this. +Note that a metric manifold is has a [`IsConnectionManifold`](@ref) trait referring to the [`LeviCivitaConnection`](@ref) of the metric ``g``, and thus a large part of metric manifold's functionality relies on this. Let's first look at the provided types. diff --git a/docs/src/manifolds/oblique.md b/docs/src/manifolds/oblique.md index 36f36233a4..7f0644ee28 100644 --- a/docs/src/manifolds/oblique.md +++ b/docs/src/manifolds/oblique.md @@ -1,7 +1,7 @@ # Oblique manifold -The oblique manifold $\mathcal{OB}(n,m)$ is modeled as an [`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) of the (real-valued) [`Sphere`](@ref) and uses [`ArrayPowerRepresentation`](@ref). -Points on the torus are hence matrices, $x ∈ ℝ^{n,m}$. +The oblique manifold ``\mathcal{OB}(n,m)`` is modeled as an [`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) of the (real-valued) [`Sphere`](@ref) and uses [`ArrayPowerRepresentation`](@ref). +Points on the torus are hence matrices, ``x ∈ ℝ^{n,m}``. ```@autodocs Modules = [Manifolds] diff --git a/docs/src/manifolds/power.md b/docs/src/manifolds/power.md index 6f04e8bb58..c21b9faff4 100644 --- a/docs/src/manifolds/power.md +++ b/docs/src/manifolds/power.md @@ -1,8 +1,8 @@ # [Power manifold](@id PowerManifoldSection) -A power manifold is based on a [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) $\mathcal M$ to build a $\mathcal M^{n_1Γ—n_2 Γ—β‹―Γ—n_m}$. -In the case where $m=1$ we can represent a manifold-valued vector of data of length $n_1$, for example a time series. -The case where $m=2$ is useful for representing manifold-valued matrices of data of size $n_1Γ—n_2$, for example certain types of images. +A power manifold is based on a [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) ``\mathcal M`` to build a ``\mathcal M^{n_1Γ—n_2 Γ—β‹―Γ—n_m}``. +In the case where ``m=1`` we can represent a manifold-valued vector of data of length ``n_1``, for example a time series. +The case where ``m=2`` is useful for representing manifold-valued matrices of data of size ``n_1Γ—n_2``, for example certain types of images. There are three available representations for points and vectors on a power manifold: @@ -17,7 +17,7 @@ Below are some examples of usage of these representations. There are two ways to store the data: in a multidimensional array or in a nested array. Let's look at an example for both. -Let $\mathcal M$ be `Sphere(2)` the 2-sphere and we want to look at vectors of length 4. +Let ``\mathcal M`` be `Sphere(2)` the 2-sphere and we want to look at vectors of length 4. ### `ArrayPowerRepresentation` diff --git a/docs/src/manifolds/product.md b/docs/src/manifolds/product.md index cd1e38aafb..550de31134 100644 --- a/docs/src/manifolds/product.md +++ b/docs/src/manifolds/product.md @@ -1,7 +1,7 @@ # [Product manifold](@id ProductManifoldSection) -Product manifold $\mathcal M = \mathcal{M}_1 Γ— \mathcal{M}_2 Γ— … Γ— \mathcal{M}_n$ of manifolds $\mathcal{M}_1, \mathcal{M}_2, …, \mathcal{M}_n$. -Points on the product manifold can be constructed using `ArrayPartition` (from `RecursiveArrayTools.jl`) with canonical projections $Ξ _i : \mathcal{M} β†’ \mathcal{M}_i$ for $i ∈ 1, 2, …, n$ provided by [`submanifold_component`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#ManifoldsBase.submanifold_component-Tuple). +Product manifold ``\mathcal M = \mathcal{M}_1 Γ— \mathcal{M}_2 Γ— … Γ— \mathcal{M}_n`` of manifolds ``\mathcal{M}_1, \mathcal{M}_2, …, \mathcal{M}_n``. +Points on the product manifold can be constructed using `ArrayPartition` (from `RecursiveArrayTools.jl`) with canonical projections ``Ξ _i : \mathcal{M} β†’ \mathcal{M}_i`` for ``i ∈ 1, 2, …, n`` provided by [`submanifold_component`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#ManifoldsBase.submanifold_component-Tuple). ```@autodocs Modules = [Manifolds] diff --git a/docs/src/manifolds/rotations.md b/docs/src/manifolds/rotations.md index d2106e3239..fce5d8fde9 100644 --- a/docs/src/manifolds/rotations.md +++ b/docs/src/manifolds/rotations.md @@ -1,11 +1,11 @@ # Rotations -The manifold $\mathrm{SO}(n)$ of orthogonal matrices with determinant $+1$ in $ℝ^{nΓ—n}$, i.e. +The manifold ``\mathrm{SO}(n)`` of orthogonal matrices with determinant ``+1`` in ``ℝ^{nΓ—n}``, i.e. -$\mathrm{SO}(n) = \bigl\{R ∈ ℝ^{nΓ—n} \big| R R^{\mathrm{T}} = +``\mathrm{SO}(n) = \bigl\{R ∈ ℝ^{nΓ—n} \big| R R^{\mathrm{T}} = R^{\mathrm{T}}R = I_n, \det(R) = 1 \bigr\}$ -The Lie group $\mathrm{SO}(n)$ is a subgroup of the orthogonal group $\mathrm{O}(n)$ and also known as the special orthogonal group or the set of rotations group. +The Lie group ``\mathrm{SO}(n)`` is a subgroup of the orthogonal group ``\mathrm{O}(n)`` and also known as the special orthogonal group or the set of rotations group. See also [`SpecialOrthogonal`](@ref), which is this manifold equipped with the group operation. The tangent space to a point ``p ∈ \mathrm{SO}(n)`` is given by @@ -23,9 +23,9 @@ In the notation above, this means we just store the component ``Y`` of ``X``. This convention allows for more efficient operations on tangent vectors. Tangent spaces at different points are different vector spaces. -Let $L_R: \mathrm{SO}(n) β†’ \mathrm{SO}(n)$ where $R ∈ \mathrm{SO}(n)$ be the left-multiplication by $R$, that is $L_R(S) = RS$. -The tangent space at rotation $R$, $T_R \mathrm{SO}(n)$, is related to the tangent space at the identity rotation $I_n$ by the differential of $L_R$ at identity, $(\mathrm{d}L_R)_{I_n} : T_{I_n} \mathrm{SO}(n) β†’ T_R \mathrm{SO}(n)$. -To convert the tangent vector representation at the identity rotation $X ∈ T_{I_n} \mathrm{SO}(n)$ (i.e., the default) to the matrix representation of the corresponding tangent vector $Y$ at a rotation $R$ use the [`embed`](@ref embed(::Manifolds.Rotations, :Any...)) which implements the following multiplication: $Y = RX ∈ T_R \mathrm{SO}(n)$. +Let ``L_R: \mathrm{SO}(n) β†’ \mathrm{SO}(n)`` where ``R ∈ \mathrm{SO}(n)`` be the left-multiplication by ``R``, that is ``L_R(S) = RS``. +The tangent space at rotation ``R``, ``T_R \mathrm{SO}(n)``, is related to the tangent space at the identity rotation ``I_n`` by the differential of ``L_R`` at identity, $(\mathrm{d}L_R)_{I_n} : T_{I_n} \mathrm{SO}(n) β†’ T_R \mathrm{SO}(n)``. +To convert the tangent vector representation at the identity rotation ``X ∈ T_{I_n} \mathrm{SO}(n)`` (i.e., the default) to the matrix representation of the corresponding tangent vector ``Y`` at a rotation ``R`` use the [`embed`](@ref embed(::Manifolds.Rotations, :Any...)) which implements the following multiplication: ``Y = RX ∈ T_R \mathrm{SO}(n)``. You can compare the functions [`log`](@ref log(::Manifolds.Rotations, :Any...)) and [`exp`](@ref exp(::Manifolds.Rotations, ::Any...)) to see how it works in practice. Several common functions are also implemented together with [orthogonal and unitary matrices](@ref generalunitarymatrices). diff --git a/docs/src/manifolds/sphere.md b/docs/src/manifolds/sphere.md index c4ae99589e..47fa663cc1 100644 --- a/docs/src/manifolds/sphere.md +++ b/docs/src/manifolds/sphere.md @@ -4,14 +4,14 @@ AbstractSphere ``` -The classical sphere, i.e. unit norm (real- or complex-valued) vectors can be generated as usual: to create the 2-dimensional sphere (in $ℝ^3$), use `Sphere(2)` and `Sphere(2,β„‚)`, respectively. +The classical sphere, i.e. unit norm (real- or complex-valued) vectors can be generated as usual: to create the 2-dimensional sphere (in ``ℝ^3``), use `Sphere(2)` and `Sphere(2,β„‚)`, respectively. ```@docs Sphere ``` For the higher-dimensional arrays, for example unit (Frobenius) norm matrices, the manifold is generated using the size of the matrix. -To create the unit sphere of $3Γ—2$ real-valued matrices, write `ArraySphere(3,2)` and the complex case is done – as for the [`Euclidean`](@ref) case – with an keyword argument `ArraySphere(3,2; field=β„‚)`. This case also covers the classical sphere as a special case, but you specify the size of the vectors/embedding instead: The 2-sphere can here be generated `ArraySphere(3)`. +To create the unit sphere of ``3Γ—2`` real-valued matrices, write `ArraySphere(3,2)` and the complex case is done – as for the [`Euclidean`](@ref) case – with an keyword argument `ArraySphere(3,2; field=β„‚)`. This case also covers the classical sphere as a special case, but you specify the size of the vectors/embedding instead: The 2-sphere can here be generated `ArraySphere(3)`. ```@docs ArraySphere diff --git a/docs/src/manifolds/symplectic.md b/docs/src/manifolds/symplectic.md index 1b9c785115..6fcd5e3967 100644 --- a/docs/src/manifolds/symplectic.md +++ b/docs/src/manifolds/symplectic.md @@ -1,12 +1,12 @@ # Symplectic matrices -The [`SymplecticMatrices`](@ref) manifold, denoted $\operatorname{Sp}(2n, 𝔽)$, is a closed, embedded, submanifold of -$𝔽^{2nΓ—2n}$ that represents transformations into symplectic subspaces which keep the -canonical symplectic form over $𝔽^{2nΓ—2n}$ invariant under the standard embedding inner product. +The [`SymplecticMatrices`](@ref) manifold, denoted ``\operatorname{Sp}(2n, 𝔽)``, is a closed, embedded, submanifold of +``𝔽^{2nΓ—2n}`` that represents transformations into symplectic subspaces which keep the +canonical symplectic form over ``𝔽^{2nΓ—2n}`` invariant under the standard embedding inner product. The canonical symplectic form is a non-degenerate bilinear and skew symmetric map -$\omega\colon 𝔽 𝔽^{2n}×𝔽^{2n} -β†’ 𝔽$, given by -$\omega(x, y) = x^T Q_{2n} y$ for elements $x, y \in 𝔽^{2n}$, with +``\omega\colon 𝔽 𝔽^{2n}×𝔽^{2n} +β†’ 𝔽``, given by +``\omega(x, y) = x^T Q_{2n} y`` for elements ``x, y \in 𝔽^{2n}``, with ````math Q_{2n} = \begin{bmatrix} @@ -14,22 +14,22 @@ $\omega(x, y) = x^T Q_{2n} y$ for elements $x, y \in 𝔽^{2n}$, with -I_n & 0_n \end{bmatrix}. ```` -That means that an element $p \in \operatorname{Sp}(2n)$ must fulfill the requirement that +That means that an element ``p \in \operatorname{Sp}(2n)`` must fulfill the requirement that ````math \omega (p x, p y) = x^T(p^TQp)y = x^TQy = \omega(x, y), ```` -leading to the requirement on $p$ that $p^TQp = Q$. +leading to the requirement on ``p`` that ``p^TQp = Q``. -The symplectic manifold also forms a group under matrix multiplication, called the $\textit{symplectic group}$. +The symplectic manifold also forms a group under matrix multiplication, called the ``\textit{symplectic group}``. Since all the symplectic matrices necessarily have determinant one, the [symplectic group](https://en.wikipedia.org/wiki/Symplectic_group) -$\operatorname{Sp}(2n, 𝔽)$ is a subgroup of the special linear group, $\operatorname{SL}(2n, 𝔽)$. When the underlying -field is either $ℝ$ or $β„‚$ the symplectic group with a manifold structure constitutes a Lie group, with the Lie +``\operatorname{Sp}(2n, 𝔽)`` is a subgroup of the special linear group, ``\operatorname{SL}(2n, 𝔽)``. When the underlying +field is either ``ℝ`` or ``β„‚`` the symplectic group with a manifold structure constitutes a Lie group, with the Lie Algebra ````math \mathfrak{sp}(2n,F) = \{H \in 𝔽^{2nΓ—2n} \;|\; Q H + H^{T} Q = 0\}. ```` This set is also known as the [Hamiltonian matrices](https://en.wikipedia.org/wiki/Hamiltonian_matrix), which have the -property that $(QH)^T = QH$ and are commonly used in physics. +property that $(QH)^T = QH`` and are commonly used in physics. ```@autodocs Modules = [Manifolds] diff --git a/docs/src/manifolds/symplecticstiefel.md b/docs/src/manifolds/symplecticstiefel.md index b53c1afe23..e2890dc566 100644 --- a/docs/src/manifolds/symplecticstiefel.md +++ b/docs/src/manifolds/symplecticstiefel.md @@ -1,13 +1,13 @@ # (Real) Symplectic Stiefel -The [`SymplecticStiefel`](@ref) manifold, denoted $\operatorname{SpSt}(2n, 2k)$, -represents canonical symplectic bases of $2k$ dimensonal symplectic subspaces of $ℝ^{2nΓ—2n}$. -This means that the columns of each element $p \in \operatorname{SpSt}(2n, 2k) \subset ℝ^{2nΓ—2k}$ -constitute a canonical symplectic basis of $\operatorname{span}(p)$. +The [`SymplecticStiefel`](@ref) manifold, denoted ``\operatorname{SpSt}(2n, 2k)``, +represents canonical symplectic bases of ``2k`` dimensonal symplectic subspaces of ``ℝ^{2nΓ—2n}``. +This means that the columns of each element ``p \in \operatorname{SpSt}(2n, 2k) \subset ℝ^{2nΓ—2k}$ +constitute a canonical symplectic basis of ``\operatorname{span}(p)``. The canonical symplectic form is a non-degenerate, bilinear, and skew symmetric map -$\omega_{2k}\colon 𝔽^{2k}×𝔽^{2k} -β†’ 𝔽$, given by -$\omega_{2k}(x, y) = x^T Q_{2k} y$ for elements $x, y \in 𝔽^{2k}$, with +``\omega_{2k}\colon 𝔽^{2k}×𝔽^{2k} +β†’ 𝔽``, given by +``\omega_{2k}(x, y) = x^T Q_{2k} y`` for elements ``x, y \in 𝔽^{2k}``, with ````math Q_{2k} = \begin{bmatrix} @@ -15,12 +15,12 @@ $\omega_{2k}(x, y) = x^T Q_{2k} y$ for elements $x, y \in 𝔽^{2k}$, with -I_k & 0_k \end{bmatrix}. ```` -Specifically given an element $p \in \operatorname{SpSt}(2n, 2k)$ we require that +Specifically given an element ``p \in \operatorname{SpSt}(2n, 2k)`` we require that ````math \omega_{2n} (p x, p y) = x^T(p^TQ_{2n}p)y = x^TQ_{2k}y = \omega_{2k}(x, y) \;\forall\; x, y \in 𝔽^{2k}, ```` -leading to the requirement on $p$ that $p^TQ_{2n}p = Q_{2k}$. -In the case that $k = n$, this manifold reduces to the [`SymplecticMatrices`](@ref) manifold, which is also known as the symplectic group. +leading to the requirement on ``p`` that ``p^TQ_{2n}p = Q_{2k}``. +In the case that ``k = n``, this manifold reduces to the [`SymplecticMatrices`](@ref) manifold, which is also known as the symplectic group. ```@autodocs Modules = [Manifolds] diff --git a/docs/src/manifolds/torus.md b/docs/src/manifolds/torus.md index efd21ed246..17a695ca3a 100644 --- a/docs/src/manifolds/torus.md +++ b/docs/src/manifolds/torus.md @@ -1,11 +1,11 @@ # Torus -The torus $𝕋^d β‰… [-Ο€,Ο€)^d$ is modeled as an [`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) of the (real-valued) [`Circle`](@ref) and uses [`ArrayPowerRepresentation`](@ref). -Points on the torus are hence row vectors, $x ∈ ℝ^{d}$. +The torus ``𝕋^d β‰… [-Ο€,Ο€)^d`` is modeled as an [`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) of the (real-valued) [`Circle`](@ref) and uses [`ArrayPowerRepresentation`](@ref). +Points on the torus are hence row vectors, ``x ∈ ℝ^{d}``. ## Example -The following code can be used to make a three-dimensional torus $𝕋^3$ and compute a tangent vector: +The following code can be used to make a three-dimensional torus ``𝕋^3`` and compute a tangent vector: ```@example using Manifolds @@ -27,7 +27,7 @@ Order = [:type, :function] ## Embedded Torus -Two-dimensional torus embedded in $ℝ^3$. +Two-dimensional torus embedded in ``ℝ^3``. ```@autodocs Modules = [Manifolds] diff --git a/docs/src/manifolds/vector_bundle.md b/docs/src/manifolds/vector_bundle.md index 19d732ca6d..4f41be455e 100644 --- a/docs/src/manifolds/vector_bundle.md +++ b/docs/src/manifolds/vector_bundle.md @@ -1,8 +1,8 @@ # [Vector bundles](@id VectorBundleSection) -Vector bundle $E$ is a special case of a [fiber bundle](@ref FiberBundleSection) where each fiber is a vector space. +Vector bundle ``E`` is a special case of a [fiber bundle](@ref FiberBundleSection) where each fiber is a vector space. -Tangent bundle is a simple example of a vector bundle, where each fiber is the tangent space at the specified point $p$. +Tangent bundle is a simple example of a vector bundle, where each fiber is the tangent space at the specified point ``p``. An object representing a tangent bundle can be obtained using the constructor called `TangentBundle`. There is also another type, [`VectorSpaceFiber`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#ManifoldsBase.VectorSpaceFiber), that represents a specific fiber at a given point. @@ -23,7 +23,7 @@ Order = [:constant, :type, :function] ## Example -The following code defines a point on the tangent bundle of the sphere $S^2$ and a tangent vector to that point. +The following code defines a point on the tangent bundle of the sphere ``S^2`` and a tangent vector to that point. ```@example tangent-bundle using Manifolds diff --git a/src/Manifolds.jl b/src/Manifolds.jl index 534ad683b3..dc15b9187d 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -526,7 +526,7 @@ Base.in(p, M::AbstractManifold; kwargs...) = is_point(M, p, false; kwargs...) Base.in(p, TpM::TangentSpace; kwargs...) X ∈ TangentSpace(M, p) -Check whether `X` is a tangent vector from (in) the tangent space $T_p\mathcal M$, i.e. +Check whether `X` is a tangent vector from (in) the tangent space ``T_p\mathcal M``, i.e. the [`TangentSpace`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/metamanifolds/#ManifoldsBase.TangentSpace) at `p` on the [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) `M`. This method uses [`is_vector`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/functions.html#ManifoldsBase.is_vector) deactivating the error throw option. diff --git a/src/cotangent_space.jl b/src/cotangent_space.jl index 7cdef27ec3..cfa271f52d 100644 --- a/src/cotangent_space.jl +++ b/src/cotangent_space.jl @@ -29,7 +29,7 @@ from the vector space of type `M` at point `p` from the underlying `AbstractMani The function can be used for example to transform vectors from the tangent bundle to vectors from the cotangent bundle -$β™­ : T\mathcal M β†’ T^{*}\mathcal M$ +``β™­ : T\mathcal M β†’ T^{*}\mathcal M`` """ flat(M::AbstractManifold, p, X) = RieszRepresenterCotangentVector(M, p, X) function flat(M::AbstractManifold, p, X::TFVector{<:Any,<:AbstractBasis}) @@ -145,7 +145,7 @@ from the vector space `M` at point `p` from the underlying `AbstractManifold`. The function can be used for example to transform vectors from the cotangent bundle to vectors from the tangent bundle -$β™― : T^{*}\mathcal M β†’ T\mathcal M$ +``β™― : T^{*}\mathcal M β†’ T\mathcal M`` """ sharp(::AbstractManifold, p, ΞΎ) diff --git a/src/groups/metric.jl b/src/groups/metric.jl index ed3552421b..1fcff4a045 100644 --- a/src/groups/metric.jl +++ b/src/groups/metric.jl @@ -10,7 +10,7 @@ ) -> Bool Check whether the metric on the group $\mathcal{G}$ is (approximately) invariant using a set of predefined -points. Namely, for $p ∈ \mathcal{G}$, $X,Y ∈ T_p \mathcal{G}$, a metric $g$, and a +points. Namely, for $p ∈ \mathcal{G}$, $X,Y ∈ T_p \mathcal{G}$, a metric ``g``, and a translation map $Ο„_q$ in the specified direction, check for each $q ∈ \mathcal{G}$ that the following condition holds: diff --git a/src/groups/rotation_action.jl b/src/groups/rotation_action.jl index fc803a5363..275f18cb61 100644 --- a/src/groups/rotation_action.jl +++ b/src/groups/rotation_action.jl @@ -121,7 +121,7 @@ The formula reads ````math p_{rot} = (\cos(ΞΈ))p + (kΓ—p) \sin(ΞΈ) + k (kβ‹…p) (1-\cos(ΞΈ)), ```` -where $k$ is the vector `A.axis` and `β‹…` is the dot product. +where ``k`` is the vector `A.axis` and `β‹…` is the dot product. """ function apply(A::RotationAroundAxisAction, ΞΈ, p) sΞΈ, cΞΈ = sincos(ΞΈ) diff --git a/src/groups/special_euclidean.jl b/src/groups/special_euclidean.jl index 337ffa424e..d814c85da3 100644 --- a/src/groups/special_euclidean.jl +++ b/src/groups/special_euclidean.jl @@ -10,7 +10,7 @@ Special Euclidean group $\mathrm{SE}(n)$, the group of rigid motions. \mathrm{SE}(n) ≐ \mathrm{T}(n) β‹Š_ΞΈ \mathrm{SO}(n), ```` -where $ΞΈ$ is the canonical action of $\mathrm{SO}(n)$ on $\mathrm{T}(n)$ by vector rotation. +where ``ΞΈ`` is the canonical action of ``\mathrm{SO}(n)`` on $\mathrm{T}(n)$ by vector rotation. This constructor is equivalent to calling diff --git a/src/manifolds/EssentialManifold.jl b/src/manifolds/EssentialManifold.jl index 0cabf9eaf3..93102c00fa 100644 --- a/src/manifolds/EssentialManifold.jl +++ b/src/manifolds/EssentialManifold.jl @@ -103,7 +103,7 @@ are equal (up to a sign flip). Using the logarithmic map, the distance is given \text{dist}([p],[q]) = \| \text{log}_{[p]} [q] \| = \| \log_p (S_z(t_{\text{opt}})q) \|, ```` where $S_z ∈ H_z = \{(R_z(ΞΈ),R_z(ΞΈ))\colon ΞΈ \in [-Ο€,Ο€) \}$ in which $R_z(ΞΈ)$ is the rotation around the z axis with angle -$ΞΈ$ and $t_{\text{opt}}$ is the minimizer of the cost function +``ΞΈ`` and $t_{\text{opt}}$ is the minimizer of the cost function ````math f(t) = f_1 + f_2, \quad f_i = \frac{1}{2} ΞΈ^2_i(t), \quad ΞΈ_i(t)=d(R_{p_i},R_z(t)R_{b_i}) \text{ for } i=1,2, ```` @@ -119,7 +119,7 @@ Compute the exponential map on the [`EssentialManifold`](@ref) from `p` into dir ````math \text{exp}_p(X) =\text{exp}_g( \tilde X), \quad g \in \text(SO)(3)^2, ```` -where $\tilde X$ is the horizontal lift of $X$[TronDaniilidis:2017](@cite). +where $\tilde X$ is the horizontal lift of ``X``[TronDaniilidis:2017](@cite). """ exp(::EssentialManifold, ::Any...) @@ -164,7 +164,7 @@ on the left on $SO(3)^2$ is defined as ````math H_z = \{(R_z(ΞΈ),R_z(ΞΈ))\colon ΞΈ \in [-Ο€,Ο€) \}, ```` -where $R_z(ΞΈ)$ is the rotation around the z axis with angle $ΞΈ$. Points in $H_z$ are denoted by +where $R_z(ΞΈ)$ is the rotation around the z axis with angle ``ΞΈ``. Points in $H_z$ are denoted by $S_z$. Then, the logarithm is defined as ````math @@ -223,7 +223,7 @@ f(t) = f_1 + f_2, \quad f_i = \frac{1}{2} ΞΈ^2_i(t), \quad ΞΈ_i(t)=d(R_{p_i},R_z ```` for the given values. This is done by finding the discontinuity points $t_{d_i}, i=1,2$ of its derivative and using Newton's method to minimize the function over the intervals $[t_{d_1},t_{d_2}]$ and $[t_{d_2},t_{d_1}+2Ο€]$ -separately. Then, the minimizer for which $f$ is minimal is chosen and given back together with the minimal value. +separately. Then, the minimizer for which ``f`` is minimal is chosen and given back together with the minimal value. For more details see Algorithm 1 in [TronDaniilidis:2017](@cite). """ function dist_min_angle_pair(p, q) @@ -360,7 +360,7 @@ This function computes the minimizer of the function ````math f(t) = f_1 + f_2, \quad f_i = \frac{1}{2} ΞΈ^2_i(t), \quad ΞΈ_i(t)=d(R_{p_i},R_z(t)R_{b_i}) \text{ for } i=1,2, ```` -in the interval $[$`t_low`, `t_high`$]$ using Newton's method. For more details see [TronDaniilidis:2017](@cite). +in the interval ``[```t_low`, `t_high```]`` using Newton's method. For more details see [TronDaniilidis:2017](@cite). """ function dist_min_angle_pair_df_newton(m1, Ξ¦1, c1, m2, Ξ¦2, c2, t_min, t_low, t_high) tol_dist = sqrt(eps(eltype(t_min))) @@ -425,7 +425,7 @@ Then the orthogonal projection of `X` onto the horizontal space $T_{\text{hp}}\t ````math \Pi_h(X) = X - \frac{\text{vert\_proj}_p(X)}{2} \begin{bmatrix} R_1^T e_z \\ R_2^T e_z \end{bmatrix}, ```` -with $R_i = R_0 R'_i, i=1,2,$ where $R'_i$ is part of the pose of camera $i$ $g_i = (R'_i,T'_i) ∈ \text{SE}(3)$ +with $R_i = R_0 R'_i, i=1,2,$ where $R'_i$ is part of the pose of camera ``i`` $g_i = (R'_i,T'_i) ∈ \text{SE}(3)$ and $R_0 ∈ \text{SO}(3)$ such that $R_0(T'_2-T'_1) = e_z$. """ project(::EssentialManifold, ::Any, ::Any) @@ -486,7 +486,7 @@ Project `X` onto the vertical space $T_{\text{vp}}\text{SO}(3)^2$ with \text{vert\_proj}_p(X) = e_z^T(R_1 X_1 + R_2 X_2), ```` where $e_z$ is the third unit vector, $X_i ∈ T_{p}\text{SO}(3)$ for $i=1,2,$ and it holds $R_i = R_0 R'_i, i=1,2,$ where $R'_i$ is part of the -pose of camera $i$ $g_i = (R_i,T'_i) ∈ \text{SE}(3)$ and $R_0 ∈ \text{SO}(3)$ such that $R_0(T'_2-T'_1) = e_z$ [TronDaniilidis:2017](@cite). +pose of camera ``i`` $g_i = (R_i,T'_i) ∈ \text{SE}(3)$ and $R_0 ∈ \text{SO}(3)$ such that $R_0(T'_2-T'_1) = e_z$ [TronDaniilidis:2017](@cite). """ function vert_proj(M::EssentialManifold, p, X) return sum(vert_proj.(Ref(M.manifold), p, X)) diff --git a/src/manifolds/Hyperbolic.jl b/src/manifolds/Hyperbolic.jl index 6877640070..4ff055eff0 100644 --- a/src/manifolds/Hyperbolic.jl +++ b/src/manifolds/Hyperbolic.jl @@ -63,7 +63,7 @@ end In the Hyperboloid model of the [`Hyperbolic`](@ref) $\mathcal H^n$ tangent vctors are represented as vectors in $ℝ^{n+1}$ with [`MinkowskiMetric`](@ref) $⟨p,X⟩_{\mathrm{M}}=0$ to their base -point $p$. +point ``p``. This representation is the default, i.e. vectors are assumed to have this repesentation. """ @@ -253,7 +253,7 @@ end injectivity_radius(M::Hyperbolic) injectivity_radius(M::Hyperbolic, p) -Return the injectivity radius on the [`Hyperbolic`](@ref), which is $∞$. +Return the injectivity radius on the [`Hyperbolic`](@ref), which is ``∞``. """ injectivity_radius(::Hyperbolic) = Inf diff --git a/src/manifolds/HyperbolicHyperboloid.jl b/src/manifolds/HyperbolicHyperboloid.jl index 0f4c30f083..e5070232e5 100644 --- a/src/manifolds/HyperbolicHyperboloid.jl +++ b/src/manifolds/HyperbolicHyperboloid.jl @@ -308,7 +308,7 @@ end get_coordinates(M::Hyperbolic, p, X, ::DefaultOrthonormalBasis) Compute the coordinates of the vector `X` with respect to the orthogonalized version of -the unit vectors from $ℝ^n$, where $n$ is the manifold dimension of the [`Hyperbolic`](@ref) +the unit vectors from $ℝ^n$, where ``n`` is the manifold dimension of the [`Hyperbolic`](@ref) `M`, utting them intop the tangent space at `p` and orthonormalizing them. """ get_coordinates(M::Hyperbolic, p, X, ::DefaultOrthonormalBasis) @@ -335,7 +335,7 @@ end get_vector(M::Hyperbolic, p, c, ::DefaultOrthonormalBasis) Compute the vector from the coordinates with respect to the orthogonalized version of -the unit vectors from $ℝ^n$, where $n$ is the manifold dimension of the [`Hyperbolic`](@ref) +the unit vectors from $ℝ^n$, where ``n`` is the manifold dimension of the [`Hyperbolic`](@ref) `M`, utting them intop the tangent space at `p` and orthonormalizing them. """ get_vector(M::Hyperbolic, p, c, ::DefaultOrthonormalBasis) diff --git a/src/manifolds/HyperbolicPoincareBall.jl b/src/manifolds/HyperbolicPoincareBall.jl index 81726e55da..fd1c96ffd2 100644 --- a/src/manifolds/HyperbolicPoincareBall.jl +++ b/src/manifolds/HyperbolicPoincareBall.jl @@ -120,7 +120,7 @@ end convert a [`HyperboloidTVector`](@ref) `X` at `p` to a [`PoincareBallTVector`](@ref) on the [`Hyperbolic`](@ref) manifold $\mathcal H^n$ by computing the push forward $Ο€_*(p)[X]$ of -the isometry $Ο€$ that maps from the Hyperboloid to the PoincarΓ© ball, +the isometry ``Ο€`` that maps from the Hyperboloid to the PoincarΓ© ball, cf. [`convert(::Type{PoincareBallPoint}, ::HyperboloidPoint)`](@ref). The formula reads @@ -184,7 +184,7 @@ end convert a [`PoincareHalfSpaceTVector`](@ref) `X` at `p` to a [`PoincareBallTVector`](@ref) on the [`Hyperbolic`](@ref) manifold $\mathcal H^n$ by computing the push forward $Ο€_*(p)[X]$ of -the isometry $Ο€$ that maps from the PoincarΓ© half space to the PoincarΓ© ball, +the isometry ``Ο€`` that maps from the PoincarΓ© half space to the PoincarΓ© ball, cf. [`convert(::Type{PoincareBallPoint}, ::PoincareHalfSpacePoint)`](@ref). The formula reads diff --git a/src/manifolds/HyperbolicPoincareHalfspace.jl b/src/manifolds/HyperbolicPoincareHalfspace.jl index 0bc0c14457..8ecc74d2e2 100644 --- a/src/manifolds/HyperbolicPoincareHalfspace.jl +++ b/src/manifolds/HyperbolicPoincareHalfspace.jl @@ -74,7 +74,7 @@ end convert a [`PoincareBallTVector`](@ref) `X` at `p` to a [`PoincareHalfSpacePoint`](@ref) on the [`Hyperbolic`](@ref) manifold $\mathcal H^n$ by computing the push forward $Ο€_*(p)[X]$ of -the isometry $Ο€$ that maps from the PoincarΓ© ball to the PoincarΓ© half space, +the isometry ``Ο€`` that maps from the PoincarΓ© ball to the PoincarΓ© half space, cf. [`convert(::Type{PoincareHalfSpacePoint}, ::PoincareBallPoint)`](@ref). The formula reads @@ -119,7 +119,7 @@ end convert a [`HyperboloidTVector`](@ref) `X` at `p` to a [`PoincareHalfSpaceTVector`](@ref) on the [`Hyperbolic`](@ref) manifold $\mathcal H^n$ by computing the push forward $Ο€_*(p)[X]$ of -the isometry $Ο€$ that maps from the Hyperboloid to the PoincarΓ© half space, +the isometry ``Ο€`` that maps from the Hyperboloid to the PoincarΓ© half space, cf. [`convert(::Type{PoincareHalfSpacePoint}, ::HyperboloidPoint)`](@ref). This is done similarly to the approach there, i.e. by using the PoincarΓ© ball model as diff --git a/src/manifolds/Multinomial.jl b/src/manifolds/Multinomial.jl index e01f2b763d..5d0dbc42b4 100644 --- a/src/manifolds/Multinomial.jl +++ b/src/manifolds/Multinomial.jl @@ -7,11 +7,11 @@ The multinomial manifold consists of `m` column vectors, where each column is of ````math \mathcal{MN}(n,m) \coloneqq \bigl\{ p ∈ ℝ^{nΓ—m}\ \big|\ p_{i,j} > 0 \text{ for all } i=1,…,n, j=1,…,m \text{ and } p^{\mathrm{T}}\mathbb{1}_m = \mathbb{1}_n\bigr\}, ```` -where $\mathbb{1}_k$ is the vector of length $k$ containing ones. +where ``\mathbb{1}_k`` is the vector of length ``k`` containing ones. This yields exactly the same metric as considering the product metric of the probablity vectors, i.e. [`PowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.PowerManifold) of the -$(n-1)$-dimensional [`ProbabilitySimplex`](@ref). +``(n-1)``-dimensional [`ProbabilitySimplex`](@ref). The [`ProbabilitySimplex`](@ref) is stored internally within `M.manifold`, such that all functions of [`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) can be used directly. @@ -20,7 +20,7 @@ The [`ProbabilitySimplex`](@ref) is stored internally within `M.manifold`, such MultinomialMatrices(n::Int, m::Int; parameter::Symbol=:type) -Generate the manifold of matrices $\mathbb R^{nΓ—m}$ such that the $m$ columns are +Generate the manifold of matrices ``ℝ^{nΓ—m}`` such that the ``m`` columns are discrete probability distributions, i.e. sum up to one. `parameter`: whether a type parameter should be used to store `n` and `m`. By default size @@ -50,7 +50,7 @@ end check_point(M::MultinomialMatrices, p) Checks whether `p` is a valid point on the [`MultinomialMatrices`](@ref)`(m,n)` `M`, i.e. is a matrix -of `m` discrete probability distributions as columns from $\mathbb R^{n}$, i.e. each column is a point from +of `m` discrete probability distributions as columns from ``ℝ^n``, i.e. each column is a point from [`ProbabilitySimplex`](@ref)`(n-1)`. """ check_point(::MultinomialMatrices, ::Any) diff --git a/src/manifolds/MultinomialDoublyStochastic.jl b/src/manifolds/MultinomialDoublyStochastic.jl index 40a4ef3e03..6ff2769a94 100644 --- a/src/manifolds/MultinomialDoublyStochastic.jl +++ b/src/manifolds/MultinomialDoublyStochastic.jl @@ -14,7 +14,7 @@ end @doc raw""" MultinomialDoublyStochastic{T} <: AbstractMultinomialDoublyStochastic -The set of doubly stochastic multinomial matrices consists of all $nΓ—n$ matrices with +The set of doubly stochastic multinomial matrices consists of all ``nΓ—n`` matrices with stochastic columns and rows, i.e. ````math \begin{aligned} @@ -24,7 +24,7 @@ stochastic columns and rows, i.e. \end{aligned} ```` -where $\mathbf{1}_n$ is the vector of length $n$ containing ones. +where ``\mathbf{1}_n`` is the vector of length ``n`` containing ones. The tangent space can be written as @@ -35,7 +35,7 @@ X\mathbf{1}_n = X^{\mathrm{T}}\mathbf{1}_n = \mathbf{0}_n \bigr\}, ```` -where $\mathbf{0}_n$ is the vector of length $n$ containing zeros. +where ``\mathbf{0}_n`` is the vector of length ``n`` containing zeros. More details can be found in Section III [DouikHassibi:2019](@cite). @@ -43,7 +43,7 @@ More details can be found in Section III [DouikHassibi:2019](@cite). MultinomialDoubleStochastic(n::Int; parameter::Symbol=:type) -Generate the manifold of matrices $\mathbb R^{nΓ—n}$ that are doubly stochastic and symmetric. +Generate the manifold of matrices ``ℝ^{nΓ—n}`` that are doubly stochastic and symmetric. """ struct MultinomialDoubleStochastic{T} <: AbstractMultinomialDoublyStochastic size::T @@ -137,15 +137,15 @@ The formula reads ````math \operatorname{proj}_p(Y) = Y - (Ξ±\mathbf{1}_n^{\mathrm{T}} + \mathbf{1}_nΞ²^{\mathrm{T}}) βŠ™ p, ```` -where $βŠ™$ denotes the Hadamard or elementwise product and $\mathbb{1}_n$ is the vector of length $n$ containing ones. -The two vectors $Ξ±,Ξ² ∈ ℝ^{nΓ—n}$ are computed as a solution (typically using the left pseudo inverse) of +where ``βŠ™`` denotes the Hadamard or elementwise product and ``\mathbb{1}_n`` is the vector of length ``n`` containing ones. +The two vectors ``Ξ±,Ξ² ∈ ℝ^{nΓ—n}`` are computed as a solution (typically using the left pseudo inverse) of ````math \begin{pmatrix} I_n & p\\p^{\mathrm{T}} & I_n \end{pmatrix} \begin{pmatrix} Ξ±\\ Ξ²\end{pmatrix} = \begin{pmatrix} Y\mathbf{1}\\Y^{\mathrm{T}}\mathbf{1}\end{pmatrix}, ```` -where $I_n$ is the $nΓ—n$ unit matrix and $\mathbf{1}_n$ is the vector of length $n$ containing ones. +where ``I_n`` is the ``nΓ—n`` unit matrix and ``\mathbf{1}_n`` is the vector of length ``n`` containing ones. """ project(::MultinomialDoubleStochastic, ::Any, ::Any) @@ -210,7 +210,7 @@ end retract(M::MultinomialDoubleStochastic, p, X, ::ProjectionRetraction) compute a projection based retraction by projecting $p\odot\exp(Xβ¨Έp)$ back onto the manifold, -where $βŠ™,β¨Έ$ are elementwise multiplication and division, respectively. Similarly, $\exp$ +where ``βŠ™,β¨Έ`` are elementwise multiplication and division, respectively. Similarly, ``\exp`` refers to the elementwise exponentiation. """ retract(::MultinomialDoubleStochastic, ::Any, ::Any, ::ProjectionRetraction) diff --git a/src/manifolds/MultinomialSymmetric.jl b/src/manifolds/MultinomialSymmetric.jl index 110d782bf9..470f6bb779 100644 --- a/src/manifolds/MultinomialSymmetric.jl +++ b/src/manifolds/MultinomialSymmetric.jl @@ -37,7 +37,7 @@ More details can be found in Section IV [DouikHassibi:2019](@cite). MultinomialSymmetric(n) -Generate the manifold of matrices ``\mathbb R^{nΓ—n}`` that are doubly stochastic and symmetric. +Generate the manifold of matrices ``ℝ^{nΓ—n}`` that are doubly stochastic and symmetric. """ struct MultinomialSymmetric{T} <: AbstractMultinomialDoublyStochastic size::T diff --git a/src/manifolds/ProbabilitySimplex.jl b/src/manifolds/ProbabilitySimplex.jl index 86cbd46fc6..74da5388bc 100644 --- a/src/manifolds/ProbabilitySimplex.jl +++ b/src/manifolds/ProbabilitySimplex.jl @@ -24,7 +24,7 @@ T_pΞ”^n = \biggl\{ X ∈ ℝ^{n+1}\ \big|\ ⟨\mathbb{1},X⟩ = \sum_{i=1}^{n+1} The manifold is implemented assuming the Fisher-Rao metric for the multinomial distribution, which is equivalent to the induced metric from isometrically embedding the probability -simplex in the $n$-sphere of radius 2. +simplex in the ``n``-sphere of radius 2. The corresponding diffeomorphism $\varphi: \mathbb Ξ”^n β†’ \mathcal N$, where $\mathcal N \subset 2π•Š^n$ is given by $\varphi(p) = 2\sqrt{p}$. @@ -441,7 +441,7 @@ end @doc raw""" representation_size(::ProbabilitySimplex) -Return the representation size of points in the $n$-dimensional probability simplex, +Return the representation size of points in the ``n``-dimensional probability simplex, i.e. an array size of `(n+1,)`. """ function representation_size(M::ProbabilitySimplex) diff --git a/src/manifolds/ProjectiveSpace.jl b/src/manifolds/ProjectiveSpace.jl index 7135eb4df2..0675918d16 100644 --- a/src/manifolds/ProjectiveSpace.jl +++ b/src/manifolds/ProjectiveSpace.jl @@ -15,11 +15,11 @@ $𝔽^{n+1}$: ````math 𝔽ℙ^n := \bigl\{ [p] βŠ‚ 𝔽^{n+1} \ \big|\ \lVert p \rVert = 1, Ξ» ∈ 𝔽, |Ξ»| = 1, p ∼ p Ξ» \bigr\}, ```` -where $[p]$ is an equivalence class of points $p$, and $∼$ indicates equivalence. +where $[p]$ is an equivalence class of points ``p``, and ``∼`` indicates equivalence. For example, the real projective space $ℝℙ^n$ is represented as the unit sphere $π•Š^n$, where antipodal points are considered equivalent. -The tangent space at point $p$ is given by +The tangent space at point ``p`` is given by ````math T_p 𝔽ℙ^{n} := \bigl\{ X ∈ 𝔽^{n+1}\ \big|\ ⟨p,X⟩ = 0 \bigr \}, @@ -59,7 +59,7 @@ $𝔽^{n₁,nβ‚‚,…,nα΅’}$: ````math 𝔽ℙ^{n_1, n_2, …, n_i} := \bigl\{ [p] βŠ‚ 𝔽^{n_1, n_2, …, n_i} \ \big|\ \lVert p \rVert_{\mathrm{F}} = 1, Ξ» ∈ 𝔽, |Ξ»| = 1, p ∼ p Ξ» \bigr\}. ```` -where $[p]$ is an equivalence class of points $p$, $\sim$ indicates equivalence, and +where $[p]$ is an equivalence class of points ``p``, $\sim$ indicates equivalence, and $\lVert β‹… \rVert_{\mathrm{F}}$ is the Frobenius norm. Note that unlike [`ProjectiveSpace`](@ref), the argument for `ArrayProjectiveSpace` is given by the size of the embedding. @@ -68,7 +68,7 @@ manifold. Additionally, `ArrayProjectiveSpace(n,1;field=𝔽)` and [`Grassmann(n,1;field=𝔽)`](@ref) are the same. -The tangent space at point $p$ is given by +The tangent space at point ``p`` is given by ````math T_p 𝔽ℙ^{n_1, n_2, …, n_i} := \bigl\{ X ∈ 𝔽^{n_1, n_2, …, n_i}\ |\ ⟨p,X⟩_{\mathrm{F}} = 0 \bigr \}, @@ -193,14 +193,14 @@ end @doc raw""" get_coordinates(M::AbstractProjectiveSpace, p, X, B::DefaultOrthonormalBasis{ℝ}) -Represent the tangent vector $X$ at point $p$ from the [`AbstractProjectiveSpace`](@ref) -$M = 𝔽ℙ^n$ in an orthonormal basis by unitarily transforming the hyperplane containing $X$, -whose normal is $p$, to the hyperplane whose normal is the $x$-axis. +Represent the tangent vector ``X`` at point ``p`` from the [`AbstractProjectiveSpace`](@ref) +$M = 𝔽ℙ^n$ in an orthonormal basis by unitarily transforming the hyperplane containing ``X``, +whose normal is ``p``, to the hyperplane whose normal is the ``x``-axis. Given $q = p \overline{Ξ»} + x$, where $Ξ» = \frac{⟨x, p⟩_{\mathrm{F}}}{|⟨x, p⟩_{\mathrm{F}}|}$, $βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ denotes the Frobenius inner product, and $\overline{β‹…}$ denotes complex or quaternionic conjugation, the -formula for $Y$ is +formula for ``Y`` is ````math \begin{pmatrix}0 \\ Y\end{pmatrix} = \left(X - q\frac{2 ⟨q, X⟩_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}\right)\overline{Ξ»}. ```` @@ -227,15 +227,15 @@ end @doc raw""" get_vector(M::AbstractProjectiveSpace, p, X, B::DefaultOrthonormalBasis{ℝ}) -Convert a one-dimensional vector of coefficients $X$ in the basis `B` of the tangent space -at $p$ on the [`AbstractProjectiveSpace`](@ref) $M=𝔽ℙ^n$ to a tangent vector $Y$ at $p$ by -unitarily transforming the hyperplane containing $X$, whose normal is the $x$-axis, to the -hyperplane whose normal is $p$. +Convert a one-dimensional vector of coefficients ``X`` in the basis `B` of the tangent space +at ``p`` on the [`AbstractProjectiveSpace`](@ref) $M=𝔽ℙ^n$ to a tangent vector ``Y`` at ``p`` by +unitarily transforming the hyperplane containing ``X``, whose normal is the ``x``-axis, to the +hyperplane whose normal is ``p``. Given $q = p \overline{Ξ»} + x$, where $Ξ» = \frac{⟨x, p⟩_{\mathrm{F}}}{|⟨x, p⟩_{\mathrm{F}}|}$, $βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ denotes the Frobenius inner product, and $\overline{β‹…}$ denotes complex or quaternionic conjugation, the -formula for $Y$ is +formula for ``Y`` is ````math Y = \left(X - q\frac{2 \left\langle q, \begin{pmatrix}0 \\ X\end{pmatrix}\right\rangle_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}\right) Ξ». ```` @@ -335,16 +335,16 @@ reaches `q` after time 1 on `M`. The formula reads \log_p q = (q Ξ» - \cos ΞΈ p) \frac{ΞΈ}{\sin ΞΈ}, ```` where $ΞΈ = \arccos|⟨q, p⟩_{\mathrm{F}}|$ is the -[`distance`](@ref distance(::AbstractProjectiveSpace, p, q)) between $p$ and $q$, +[`distance`](@ref distance(::AbstractProjectiveSpace, p, q)) between ``p`` and ``q``, $βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ is the Frobenius inner product, and $Ξ» = \frac{⟨q, p⟩_{\mathrm{F}}}{|⟨q, p⟩_{\mathrm{F}}|} ∈ 𝔽$ is the unit scalar that minimizes $d_{𝔽^{n+1}}(p - q Ξ»)$. -That is, $q Ξ»$ is the member of the equivalence class $[q]$ that is closest to $p$ in the +That is, $q Ξ»$ is the member of the equivalence class $[q]$ that is closest to ``p`` in the embedding. As a result, $\exp_p \circ \log_p \colon q ↦ q Ξ»$. The logarithmic maps for the real [`AbstractSphere`](@ref) $π•Š^n$ and the real projective -space $ℝℙ^n$ are identical when $p$ and $q$ are in the same hemisphere. +space $ℝℙ^n$ are identical when ``p`` and ``q`` are in the same hemisphere. """ log(::AbstractProjectiveSpace, p, q) @@ -523,10 +523,10 @@ end Parallel transport a vector `X` from the tangent space at a point `p` on the [`AbstractProjectiveSpace`](@ref) `M`$=𝔽ℙ^n$ to the tangent space at another point `q`. -This implementation proceeds by transporting $X$ to $T_{q Ξ»} M$ using the same approach as +This implementation proceeds by transporting ``X`` to $T_{q Ξ»} M$ using the same approach as [`parallel_transport_direction`](@ref parallel_transport_direction(::AbstractProjectiveSpace, p, X, d)), where $Ξ» = \frac{⟨q, p⟩_{\mathrm{F}}}{|⟨q, p⟩_{\mathrm{F}}|} ∈ 𝔽$ is the unit scalar that -takes $q$ to the member $q Ξ»$ of its equivalence class $[q]$ closest to $p$ in the +takes ``q`` to the member $q Ξ»$ of its equivalence class $[q]$ closest to ``p`` in the embedding. It then maps the transported vector from $T_{q Ξ»} M$ to $T_{q} M$. The resulting transport to $T_{q} M$ is @@ -534,7 +534,7 @@ The resulting transport to $T_{q} M$ is \mathcal{P}_{q ← p}(X) = \left(X - \left(p \frac{\sin ΞΈ}{ΞΈ} + d \frac{1 - \cos ΞΈ}{ΞΈ^2}\right) ⟨d, X⟩_p\right) \overline{Ξ»}, ```` where $d = \log_p q$ is the direction of the transport, $ΞΈ = \lVert d \rVert_p$ is the -[`distance`](@ref distance(::AbstractProjectiveSpace, p, q)) between $p$ and $q$, and +[`distance`](@ref distance(::AbstractProjectiveSpace, p, q)) between ``p`` and ``q``, and $\overline{β‹…}$ denotes complex or quaternionic conjugation. """ parallel_transport_to(::AbstractProjectiveSpace, ::Any, ::Any, ::Any) @@ -564,7 +564,7 @@ indicated by the tangent vector `d`, i.e. ````math \mathcal{P}_{\exp_p (d) ← p}(X) = X - \left(p \frac{\sin ΞΈ}{ΞΈ} + d \frac{1 - \cos ΞΈ}{ΞΈ^2}\right) ⟨d, X⟩_p, ```` -where $ΞΈ = \lVert d \rVert$, and $βŸ¨β‹…, β‹…βŸ©_p$ is the [`inner`](@ref) product at the point $p$. +where $ΞΈ = \lVert d \rVert$, and $βŸ¨β‹…, β‹…βŸ©_p$ is the [`inner`](@ref) product at the point ``p``. For the real projective space, this is equivalent to the same vector transport on the real [`AbstractSphere`](@ref). """ diff --git a/src/manifolds/Spectrahedron.jl b/src/manifolds/Spectrahedron.jl index bac7012274..b1f626ac72 100644 --- a/src/manifolds/Spectrahedron.jl +++ b/src/manifolds/Spectrahedron.jl @@ -2,7 +2,7 @@ Spectrahedron{T} <: AbstractDecoratorManifold{ℝ} The Spectrahedron manifold, also known as the set of correlation matrices (symmetric -positive semidefinite matrices) of rank $k$ with unit trace. +positive semidefinite matrices) of rank ``k`` with unit trace. ````math \begin{aligned} @@ -15,13 +15,13 @@ positive semidefinite matrices) of rank $k$ with unit trace. \end{aligned} ```` -This manifold is working solely on the matrices $q$. Note that this $q$ is not unique, -indeed for any orthogonal matrix $A$ we have $(qA)(qA)^{\mathrm{T}} = qq^{\mathrm{T}} = p$, +This manifold is working solely on the matrices ``q``. Note that this ``q`` is not unique, +indeed for any orthogonal matrix ``A`` we have $(qA)(qA)^{\mathrm{T}} = qq^{\mathrm{T}} = p$, so the manifold implemented here is the quotient manifold. The unit trace translates to -unit frobenius norm of $q$. +unit frobenius norm of ``q``. -The tangent space at $p$, denoted $T_p\mathcal E(n,k)$, is also represented by matrices +The tangent space at ``p``, denoted $T_p\mathcal E(n,k)$, is also represented by matrices $Y\in ℝ^{nΓ—k}$ and reads as ````math @@ -58,10 +58,10 @@ active_traits(f, ::Spectrahedron, args...) = merge_traits(IsIsometricEmbeddedMan checks, whether `q` is a valid reprsentation of a point $p=qq^{\mathrm{T}}$ on the [`Spectrahedron`](@ref) `M`, i.e. is a matrix -of size `(N,K)`, such that $p$ is symmetric positive semidefinite and has unit trace, -i.e. $q$ has to have unit frobenius norm. -Since by construction $p$ is symmetric, this is not explicitly checked. -Since $p$ is by construction positive semidefinite, this is not checked. +of size `(N,K)`, such that ``p`` is symmetric positive semidefinite and has unit trace, +i.e. ``q`` has to have unit frobenius norm. +Since by construction ``p`` is symmetric, this is not explicitly checked. +Since ``p`` is by construction positive semidefinite, this is not checked. The tolerances for positive semidefiniteness and unit trace can be set using the `kwargs...`. """ function check_point(M::Spectrahedron, q; kwargs...) @@ -81,9 +81,9 @@ end Check whether $X = qY^{\mathrm{T}} + Yq^{\mathrm{T}}$ is a tangent vector to $p=qq^{\mathrm{T}}$ on the [`Spectrahedron`](@ref) `M`, i.e. atfer [`check_point`](@ref) of `q`, `Y` has to be of same dimension as `q` -and a $X$ has to be a symmetric matrix with trace. +and a ``X`` has to be a symmetric matrix with trace. The tolerance for the base point check and zero diagonal can be set using the `kwargs...`. -Note that symmetry of $X$ holds by construction and is not explicitly checked. +Note that symmetry of ``X`` holds by construction and is not explicitly checked. """ function check_vector( M::Spectrahedron, diff --git a/src/manifolds/Sphere.jl b/src/manifolds/Sphere.jl index d27318148a..c8cc2c3734 100644 --- a/src/manifolds/Sphere.jl +++ b/src/manifolds/Sphere.jl @@ -22,7 +22,7 @@ The sphere is represented in the embedding, i.e. where $𝔽\in\{ℝ,β„‚,ℍ\}$. Note that compared to the [`ArraySphere`](@ref), here the argument `n` of the manifold is the dimension of the manifold, i.e. $π•Š^{n} βŠ‚ 𝔽^{n+1}$, $n\in β„•$. -The tangent space at point $p$ is given by +The tangent space at point ``p`` is given by ````math T_pπ•Š^{n} := \bigl\{ X ∈ 𝔽^{n+1}\ |\ \Re(⟨p,X⟩) = 0 \bigr \}, @@ -74,7 +74,7 @@ where $𝔽\in\{ℝ,β„‚,ℍ\}$. Setting $i=1$ and $𝔽=ℝ$ this simplifies t the argument for the generalized case here is given by the dimension of the embedding. This means that `Sphere(2)` and `ArraySphere(3)` are the same manifold. -The tangent space at point $p$ is given by +The tangent space at point ``p`` is given by ````math T_p π•Š^{n_1, n_2, …, n_i} := \bigl\{ X ∈ 𝔽^{n_1, n_2, …, n_i}\ |\ \Re(⟨p,X⟩) = 0 \bigr \}, @@ -91,7 +91,7 @@ several functions like the [`inner`](@ref inner(::Euclidean, ::Any...)) product ArraySphere(n₁,nβ‚‚,...,nα΅’; field=ℝ, parameter::Symbol=:type) -Generate sphere in $𝔽^{n_1, n_2, …, n_i}$, where $𝔽$ defaults to the real-valued case $ℝ$. +Generate sphere in $𝔽^{n_1, n_2, …, n_i}$, where ``𝔽`` defaults to the real-valued case ``ℝ``. """ struct ArraySphere{T,𝔽} <: AbstractSphere{𝔽} size::T @@ -225,10 +225,10 @@ end Represent the tangent vector `X` at point `p` from the [`AbstractSphere`](@ref) `M` in an orthonormal basis by rotating the hyperplane containing `X` to a hyperplane whose -normal is the $x$-axis. +normal is the ``x``-axis. Given $q = p Ξ» + x$, where $Ξ» = \operatorname{sgn}(⟨x, p⟩)$, and $βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ -denotes the Frobenius inner product, the formula for $Y$ is +denotes the Frobenius inner product, the formula for ``Y`` is ````math \begin{pmatrix}0 \\ Y\end{pmatrix} = X - q\frac{2 ⟨q, X⟩_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}. ```` @@ -258,11 +258,11 @@ end Convert a one-dimensional vector of coefficients `X` in the basis `B` of the tangent space at `p` on the [`AbstractSphere`](@ref) `M` to a tangent vector `Y` at `p` by rotating the -hyperplane containing `X`, whose normal is the $x$-axis, to the hyperplane whose normal is +hyperplane containing `X`, whose normal is the ``x``-axis, to the hyperplane whose normal is `p`. Given $q = p Ξ» + x$, where $Ξ» = \operatorname{sgn}(⟨x, p⟩)$, and $βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ -denotes the Frobenius inner product, the formula for $Y$ is +denotes the Frobenius inner product, the formula for ``Y`` is ````math Y = X - q\frac{2 \left\langle q, \begin{pmatrix}0 \\ X\end{pmatrix}\right\rangle_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}. ```` @@ -285,7 +285,7 @@ end @doc raw""" injectivity_radius(M::AbstractSphere[, p]) -Return the injectivity radius for the [`AbstractSphere`](@ref) `M`, which is globally $Ο€$. +Return the injectivity radius for the [`AbstractSphere`](@ref) `M`, which is globally ``Ο€``. injectivity_radius(M::Sphere, x, ::ProjectionRetraction) diff --git a/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl b/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl index 612b26216c..54ffe9169c 100644 --- a/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl +++ b/src/manifolds/SymmetricPositiveDefiniteAffineInvariant.jl @@ -234,7 +234,7 @@ the coordinates with respect to this ONB can be simplified to ```math c_k = \mathrm{tr}(p^{-\frac{1}{2}}\Delta_{i,j} X) ``` -where $k$ is trhe linearized index of the $i=1,\ldots,n, j=i,\ldots,n$. +where ``k`` is trhe linearized index of the $i=1,\ldots,n, j=i,\ldots,n$. """ get_coordinates(::SymmetricPositiveDefinite, c, p, X, ::DefaultOrthonormalBasis) @@ -272,7 +272,7 @@ the vector reconstruction with respect to this ONB can be simplified to ```math X = p^{\frac{1}{2}} \Biggl( \sum_{i=1,j=i}^n c_k \Delta_{i,j} \Biggr) p^{\frac{1}{2}} ``` -where $k$ is the linearized index of the $i=1,\ldots,n, j=i,\ldots,n$. +where ``k`` is the linearized index of the $i=1,\ldots,n, j=i,\ldots,n$. """ get_vector(::SymmetricPositiveDefinite, X, p, c, ::DefaultOrthonormalBasis) diff --git a/src/manifolds/SymmetricPositiveDefiniteLogCholesky.jl b/src/manifolds/SymmetricPositiveDefiniteLogCholesky.jl index 2c652a8876..b137bc495c 100644 --- a/src/manifolds/SymmetricPositiveDefiniteLogCholesky.jl +++ b/src/manifolds/SymmetricPositiveDefiniteLogCholesky.jl @@ -31,7 +31,7 @@ d_{\mathcal P(n)}(p,q) = \sqrt{ + \lVert \log(\operatorname{diag}(x)) - \log(\operatorname{diag}(y))\rVert_{\mathrm{F}}^2 }\ \ , ```` -where $x$ and $y$ are the cholesky factors of $p$ and $q$, respectively, +where ``x`` and ``y`` are the cholesky factors of ``p`` and ``q``, respectively, $βŒŠβ‹…βŒ‹$ denbotes the strictly lower triangular matrix of its argument, and $\lVertβ‹…\rVert_{\mathrm{F}}$ the Frobenius norm. """ @@ -50,8 +50,8 @@ Compute the exponential map on the [`SymmetricPositiveDefinite`](@ref) `M` with \exp_p X = (\exp_y W)(\exp_y W)^\mathrm{T} ```` -where $\exp_xW$ is the exponential map on [`CholeskySpace`](@ref), $y$ is the cholesky -decomposition of $p$, $W = y(y^{-1}Xy^{-\mathrm{T}})_\frac{1}{2}$, +where $\exp_xW$ is the exponential map on [`CholeskySpace`](@ref), ``y`` is the cholesky +decomposition of ``p``, $W = y(y^{-1}Xy^{-\mathrm{T}})_\frac{1}{2}$, and $(β‹…)_\frac{1}{2}$ denotes the lower triangular matrix with the diagonal multiplied by $\frac{1}{2}$. """ @@ -85,7 +85,7 @@ a [`MetricManifold`](@ref) with [`LogCholeskyMetric`](@ref). The formula reads ```` where $βŸ¨β‹…,β‹…βŸ©_x$ denotes inner product on the [`CholeskySpace`](@ref), -$z$ is the cholesky factor of $p$, +``z`` is the cholesky factor of ``p``, $a_z(W) = z (z^{-1}Wz^{-\mathrm{T}})_{\frac{1}{2}}$, and $(β‹…)_\frac{1}{2}$ denotes the lower triangular matrix with the diagonal multiplied by $\frac{1}{2}$ """ @@ -113,8 +113,8 @@ The formula can be adapted from the [`CholeskySpace`](@ref) as ````math \log_p q = xW^{\mathrm{T}} + Wx^{\mathrm{T}}, ```` -where $x$ is the cholesky factor of $p$ and $W=\log_x y$ for $y$ the cholesky factor -of $q$ and the just mentioned logarithmic map is the one on [`CholeskySpace`](@ref). +where ``x`` is the cholesky factor of ``p`` and $W=\log_x y$ for ``y`` the cholesky factor +of ``q`` and the just mentioned logarithmic map is the one on [`CholeskySpace`](@ref). """ log(::MetricManifold{ℝ,SymmetricPositiveDefinite,LogCholeskyMetric}, ::Any...) @@ -138,10 +138,10 @@ end Parallel transport the tangent vector `X` at `p` along the geodesic to `q` with respect to the [`SymmetricPositiveDefinite`](@ref) manifold `M` and [`LogCholeskyMetric`](@ref). The parallel transport is based on the parallel transport on [`CholeskySpace`](@ref): -Let $x$ and $y$ denote the cholesky factors of `p` and `q`, respectively and +Let ``x`` and ``y`` denote the cholesky factors of `p` and `q`, respectively and $W = x(x^{-1}Xx^{-\mathrm{T}})_\frac{1}{2}$, where $(β‹…)_\frac{1}{2}$ denotes the lower -triangular matrix with the diagonal multiplied by $\frac{1}{2}$. With $V$ the parallel -transport on [`CholeskySpace`](@ref) from $x$ to $y$. The formula hear reads +triangular matrix with the diagonal multiplied by $\frac{1}{2}$. With ``V`` the parallel +transport on [`CholeskySpace`](@ref) from ``x`` to ``y``. The formula hear reads ````math \mathcal P_{q←p}X = yV^{\mathrm{T}} + Vy^{\mathrm{T}}. diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index 587d7f45dd..a4c89159e0 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -214,7 +214,7 @@ end check_point(M::SymplecticMatrices, p; kwargs...) Check whether `p` is a valid point on the [`SymplecticMatrices`](@ref) `M`=$\mathrm{Sp}(2n)$, -i.e. that it has the right [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and $p^{+}p$ is (approximately) +i.e. that it has the right [`AbstractNumbers`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#number-system) type and ``p^{+}p`` is (approximately) the identity, where ``A^+`` denotes the [`symplectic_inverse`]/@ref). The tolerance can be set with `kwargs...`. diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 51c864c265..8f3ec41cd8 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -2,7 +2,7 @@ SymplecticGrassmann{T,𝔽} <: AbstractEmbeddedManifold{𝔽, DefaultIsometricEmbeddingType} The symplectic Grassmann manifold consists of all symplectic subspaces of -``\mathbb R^{2n}`` of dimension ``2k``, ``n β‰₯ k``. +``ℝ^{2n}`` of dimension ``2k``, ``n β‰₯ k``. This manifold can be represented as corresponding representers on the [`SymplecticStiefel`](@ref) diff --git a/src/manifolds/Torus.jl b/src/manifolds/Torus.jl index 6a5b934b78..000ca54aea 100644 --- a/src/manifolds/Torus.jl +++ b/src/manifolds/Torus.jl @@ -1,7 +1,7 @@ @doc raw""" Torus{N} <: AbstractPowerManifold -The n-dimensional torus is the $n$-dimensional product of the [`Circle`](@ref). +The n-dimensional torus is the ``n``-dimensional product of the [`Circle`](@ref). The [`Circle`](@ref) is stored internally within `M.manifold`, such that all functions of [`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold) can be used directly. diff --git a/src/statistics.jl b/src/statistics.jl index e4cad6c6fd..4f7c7c8bca 100644 --- a/src/statistics.jl +++ b/src/statistics.jl @@ -549,7 +549,7 @@ The parameter ``Ξ±\in (0,2]`` is a step size. The algorithm is further described in [FletcherVenkatasubramanianJoshi:2008](@cite), especially the update rule in Eq. (6), i.e. Let ``q_{k}`` denote the current -iterate, $n$ the number of points ``x_1,\ldots,x_n``, and +iterate, ``n`` the number of points ``x_1,\ldots,x_n``, and ```math I_k = \bigl\{ i \in \{1,\ldots,n\} \big| x_i \neq q_k \bigr\} From 4d5c62c9163d8f65828b2ea8c2568016b3f07613 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 20 Jan 2024 14:34:22 +0100 Subject: [PATCH 29/65] Missed a p. --- docs/src/features/utilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/features/utilities.md b/docs/src/features/utilities.md index f32a5b945c..d0fa97ca44 100644 --- a/docs/src/features/utilities.md +++ b/docs/src/features/utilities.md @@ -2,7 +2,7 @@ ## Ease of notation -The following terms introduce a nicer notation for some operations, for example using the ∈ operator, `` ∈ \mathcal M`` to determine whether ``p`` is a point on the [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) ``\mathcal M``. +The following terms introduce a nicer notation for some operations, for example using the ∈ operator, ``p ∈ \mathcal M`` to determine whether ``p`` is a point on the [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) ``\mathcal M``. ````@docs in From 020b0b5f6ebaa6a31a6278ddddb3cb6ac076efd0 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 20 Jan 2024 14:40:57 +0100 Subject: [PATCH 30/65] And another symbol. --- docs/src/manifolds/connection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/manifolds/connection.md b/docs/src/manifolds/connection.md index 07b1a61ad8..f9eb679fe6 100644 --- a/docs/src/manifolds/connection.md +++ b/docs/src/manifolds/connection.md @@ -1,6 +1,6 @@ # [Connection manifold](@id ConnectionSection) -A connection manifold always consists of a [topological manifold](https://en.wikipedia.org/wiki/Topological_manifold) together with a [connection](https://en.wikipedia.org/wiki/Connection_(mathematics)) ``\Gamma``. +A connection manifold always consists of a [topological manifold](https://en.wikipedia.org/wiki/Topological_manifold) together with a [connection](https://en.wikipedia.org/wiki/Connection_(mathematics)) ``Ξ“``. However, often there is an implicitly assumed (default) connection, like the [`LeviCivitaConnection`](@ref) connection on a Riemannian manifold. It is not necessary to use this decorator if you implement just one (or the first) connection. From 08712a2a1a168706ef4734fa15f87a60c137fa88 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 20 Jan 2024 16:43:09 +0100 Subject: [PATCH 31/65] My VS Code reportet an error on this line, removing the "" fixed it, let's see whether that still works. --- .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 23b005dc5d..189da25747 100644 --- a/.github/workflows/documenter.yml +++ b/.github/workflows/documenter.yml @@ -9,7 +9,7 @@ jobs: docs: name: Documentation runs-on: ubuntu-latest - if: "contains( github.event.pull_request.labels.*.name, 'preview docs') ||Β github.ref == 'refs/heads/master' || contains(github.ref, 'refs/tags/')" + if: contains( github.event.pull_request.labels.*.name, 'preview docs') || github.ref == 'refs/heads/master' || contains(github.ref, 'refs/tags/') steps: - uses: actions/checkout@v4 - uses: quarto-dev/quarto-actions/setup@v2 From c193a8efbde7d3f0eeec5cc7fd8f014d581e5fb7 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 20 Jan 2024 17:07:46 +0100 Subject: [PATCH 32/65] Code Coverage for Symplectic Stiefel. --- src/manifolds/Symplectic.jl | 11 +- src/manifolds/SymplecticStiefel.jl | 10 + test/manifolds/symplecticstiefel.jl | 542 ++++++++++++++-------------- 3 files changed, 285 insertions(+), 278 deletions(-) diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index a4c89159e0..5f416a81ea 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -42,10 +42,13 @@ function active_traits(f, ::SymplecticMatrices, args...) return merge_traits(IsEmbeddedManifold(), IsDefaultMetric(RealSymplecticMetric())) end -function SymplecticMatrices(n::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) - n % 2 == 0 || throw(ArgumentError("The dimension of the symplectic manifold - embedding space must be even. Was odd, n % 2 == $(n % 2).")) - size = wrap_type_parameter(parameter, (div(n, 2),)) +function SymplecticMatrices(two_n::Int, field::AbstractNumbers=ℝ; parameter::Symbol=:type) + two_n % 2 == 0 || throw( + ArgumentError( + "The matrix size `2n` of the symplectic manifold must be even, but was $(two_n).", + ), + ) + size = wrap_type_parameter(parameter, (div(two_n, 2),)) return SymplecticMatrices{typeof(size),field}(size) end diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 1b2d5a22f9..2a5d481a32 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -53,6 +53,16 @@ function SymplecticStiefel( field::AbstractNumbers=ℝ; parameter::Symbol=:type, ) + two_n % 2 == 0 || throw( + ArgumentError( + "The first matrix size of the symplectic Stiefel manifold must be even, but was $(two_n).", + ), + ) + two_k % 2 == 0 || throw( + ArgumentError( + "The second matrix size of the symplectic Stiefel manifold must be even. but was $(two_k).", + ), + ) size = wrap_type_parameter(parameter, (div(two_n, 2), div(two_k, 2))) return SymplecticStiefel{typeof(size),field}(size) end diff --git a/test/manifolds/symplecticstiefel.jl b/test/manifolds/symplecticstiefel.jl index 0dd2e23297..3bb17932a0 100644 --- a/test/manifolds/symplecticstiefel.jl +++ b/test/manifolds/symplecticstiefel.jl @@ -22,296 +22,290 @@ function exp_naiive!(M::SymplecticStiefel, q, p, X) end @testset "SymplecticStiefel" begin - @testset "Real" begin - SpSt_6_4 = SymplecticStiefel(2 * 3, 2 * 2) + M = SymplecticStiefel(6, 4) - p_6_4 = [ - 0.0 0.0 -5.0 -1.0 - 0.0 0.0 9.0 -2.0 - 0.0 0.0 -2.0 1.0 - -2.0 -9.0 -3.0 6.0 - -3.0 -13.0 -21.0 9.0 - -8.0 -36.0 18.0 -6.0 - ] - q_6_4 = [ - 0.0 0.0 -3.0 1.0 - 0.0 0.0 8.0 -3.0 - 0.0 0.0 -2.0 1.0 - -1.0 -4.0 -6.0 3.0 - -1.0 -3.0 -21.0 9.0 - -2.0 -6.0 18.0 -6.0 - ] - X1 = [ - 0.0 0.0 4.25 4.25 - 0.0 0.0 0.125 0.125 - 0.0 0.0 -1.125 -1.125 - 3.625 18.125 -10.875 -10.875 - 5.0 25.0 -9.0 -9.0 - 13.5 67.5 4.5 4.5 - ] - X2 = [ - -0.02648060 0.00416977 0.01130802 0.01015956 - 0.01718954 -0.00680433 0.02364406 -0.00083272 - 0.00050392 0.00191916 -0.01035902 -0.00079734 - 0.01811917 -0.02307032 -0.04297277 -0.05409099 - -0.02529516 0.00959934 -0.08594555 -0.06117803 - -0.02823014 0.00029946 -0.04196034 -0.04145413 - ] + p_6_4 = [ + 0.0 0.0 -5.0 -1.0 + 0.0 0.0 9.0 -2.0 + 0.0 0.0 -2.0 1.0 + -2.0 -9.0 -3.0 6.0 + -3.0 -13.0 -21.0 9.0 + -8.0 -36.0 18.0 -6.0 + ] + q_6_4 = [ + 0.0 0.0 -3.0 1.0 + 0.0 0.0 8.0 -3.0 + 0.0 0.0 -2.0 1.0 + -1.0 -4.0 -6.0 3.0 + -1.0 -3.0 -21.0 9.0 + -2.0 -6.0 18.0 -6.0 + ] + X1 = [ + 0.0 0.0 4.25 4.25 + 0.0 0.0 0.125 0.125 + 0.0 0.0 -1.125 -1.125 + 3.625 18.125 -10.875 -10.875 + 5.0 25.0 -9.0 -9.0 + 13.5 67.5 4.5 4.5 + ] + X2 = [ + -0.02648060 0.00416977 0.01130802 0.01015956 + 0.01718954 -0.00680433 0.02364406 -0.00083272 + 0.00050392 0.00191916 -0.01035902 -0.00079734 + 0.01811917 -0.02307032 -0.04297277 -0.05409099 + -0.02529516 0.00959934 -0.08594555 -0.06117803 + -0.02823014 0.00029946 -0.04196034 -0.04145413 + ] - points = [ - [ - 0 0 2 6 - 0 0 1 -4 - 0 0 0 1 - -1 0 -7 1 - 1 0 -4 -24 - 10 -1 4 -4 - ], - [ - 0 0 5 8 - 0 0 -2 -6 - 0 0 0 1 - 1 0 -4 3 - 3 0 -19 -34 - 10 -1 1 -6 - ], - [ - 5 -3 0 0 - 11 -6 0 0 - -2 1 0 0 - 8 -5 -3 -3 - 0 0 2 1 - 5 -3 3 -2 - ], - [ - 1 -1 0 0 - 3 -2 0 0 - 0 0 0 0 - 2 -2 -2 -3 - 0 0 1 1 - 1 -1 1 -2 - ], - [ - 0 0 0 0 - 0 0 -1 0 - 0 0 4 -1 - -1 -10 -5 2 - 1 4 -2 0 - 0 1 -16 4 - ], - [ - 0 0 0 0 - 0 0 -1 0 - 0 0 4 -1 - 0 -6 -5 2 - 1 4 -2 0 - 0 1 -16 4 - ], - ] + points = [ + [ + 0 0 2 6 + 0 0 1 -4 + 0 0 0 1 + -1 0 -7 1 + 1 0 -4 -24 + 10 -1 4 -4 + ], + [ + 0 0 5 8 + 0 0 -2 -6 + 0 0 0 1 + 1 0 -4 3 + 3 0 -19 -34 + 10 -1 1 -6 + ], + [ + 5 -3 0 0 + 11 -6 0 0 + -2 1 0 0 + 8 -5 -3 -3 + 0 0 2 1 + 5 -3 3 -2 + ], + [ + 1 -1 0 0 + 3 -2 0 0 + 0 0 0 0 + 2 -2 -2 -3 + 0 0 1 1 + 1 -1 1 -2 + ], + [ + 0 0 0 0 + 0 0 -1 0 + 0 0 4 -1 + -1 -10 -5 2 + 1 4 -2 0 + 0 1 -16 4 + ], + [ + 0 0 0 0 + 0 0 -1 0 + 0 0 4 -1 + 0 -6 -5 2 + 1 4 -2 0 + 0 1 -16 4 + ], + ] - close_points = [ - [ - -2 1 -2 -14 - 1 0 1 11 - 1 0 4 9 - 0 0 0 1 - 0 0 0 -1 - 0 0 1 3 - ], - [ - -3 1 -2 -10 - 1 0 1 7 - 1 0 4 10 - 0 0 0 1 - 0 0 0 0 - 0 0 1 3 - ], - [ - -2 1 -6 -26 - 1 0 5 23 - 3 -1 2 3 - 0 0 1 4 - 0 0 0 -1 - 0 0 1 3 - ], - ] + close_points = [ + [ + -2 1 -2 -14 + 1 0 1 11 + 1 0 4 9 + 0 0 0 1 + 0 0 0 -1 + 0 0 1 3 + ], + [ + -3 1 -2 -10 + 1 0 1 7 + 1 0 4 10 + 0 0 0 1 + 0 0 0 0 + 0 0 1 3 + ], + [ + -2 1 -6 -26 + 1 0 5 23 + 3 -1 2 3 + 0 0 1 4 + 0 0 0 -1 + 0 0 1 3 + ], + ] - @testset "Basics" begin - @test repr(SpSt_6_4) == "SymplecticStiefel(6, 4; field=ℝ)" - @test representation_size(SpSt_6_4) == (6, 4) - @test base_manifold(SpSt_6_4) === SpSt_6_4 - @test get_total_space(SpSt_6_4) == SymplecticMatrices(6) - @test !is_flat(SpSt_6_4) + @testset "Basics" begin + @test_throws ArgumentError SymplecticStiefel(5, 4) + @test_throws ArgumentError SymplecticStiefel(6, 3) + @test repr(M) == "SymplecticStiefel(6, 4; field=ℝ)" + @test representation_size(M) == (6, 4) + @test base_manifold(M) === M + @test get_total_space(M) == SymplecticMatrices(6) + @test !is_flat(M) - @test is_point(SpSt_6_4, p_6_4) - @test_throws DomainError is_point(SpSt_6_4, 2 * p_6_4; error=:error) + @test is_point(M, p_6_4) + @test_throws DomainError is_point(M, 2 * p_6_4; error=:error) - @test is_vector(SpSt_6_4, p_6_4, X1; atol=1.0e-12) - @test is_vector(SpSt_6_4, p_6_4, X2; atol=1.0e-6) - @test_throws DomainError is_vector( - SpSt_6_4, - p_6_4, - X2; - error=:error, - atol=1.0e-12, - ) - @test is_vector(SpSt_6_4, p_6_4, X1 + X2; atol=1.0e-6) - @test_throws DomainError is_vector(SpSt_6_4, p_6_4, X1 + p_6_4; error=:error) - end - @testset "Symplectic Inverse" begin - I_2k = Array(I, 4, 4) - @test Manifolds.symplectic_inverse_times(SpSt_6_4, p_6_4, p_6_4) == I_2k - @test Manifolds.symplectic_inverse_times!( - SpSt_6_4, - zeros(4, 4), - p_6_4, - p_6_4, - ) == I_2k - @test inv(SpSt_6_4, p_6_4) * p_6_4 == I_2k - @test inv!(SpSt_6_4, copy(p_6_4'), p_6_4) * p_6_4 == I_2k - end - @testset "Embedding" begin - x = [ - 1 1 -9 7 - -1 -1 -13 11 - 7 8 -22 19 - 0 0 7 -6 - 0 0 -1 1 - 0 0 -1 1 - ] - y = similar(x) - z = embed(SpSt_6_4, x) - @test z == x - - Y = similar(X1) - embed!(SpSt_6_4, Y, p_6_4, X1) - @test Y == X1 - end - @testset "Retractions and Exponential Mapping" begin - @test isapprox(retract(SpSt_6_4, p_6_4, X1), q_6_4; atol=1.0e-12) - @test isapprox( - retract(SpSt_6_4, p_6_4, X1, CayleyRetraction()), - q_6_4; - atol=1.0e-12, - ) + @test is_vector(M, p_6_4, X1; atol=1.0e-12) + @test is_vector(M, p_6_4, X2; atol=1.0e-6) + @test_throws DomainError is_vector(M, p_6_4, X2; error=:error, atol=1.0e-12) + @test is_vector(M, p_6_4, X1 + X2; atol=1.0e-6) + @test_throws DomainError is_vector(M, p_6_4, X1 + p_6_4; error=:error) + end + @testset "Symplectic Inverse" begin + I_2k = Array(I, 4, 4) + @test Manifolds.symplectic_inverse_times(M, p_6_4, p_6_4) == I_2k + @test Manifolds.symplectic_inverse_times!(M, zeros(4, 4), p_6_4, p_6_4) == I_2k + @test inv(M, p_6_4) * p_6_4 == I_2k + @test inv!(M, copy(p_6_4'), p_6_4) * p_6_4 == I_2k + end + @testset "Embedding" begin + x = [ + 1 1 -9 7 + -1 -1 -13 11 + 7 8 -22 19 + 0 0 7 -6 + 0 0 -1 1 + 0 0 -1 1 + ] + y = similar(x) + z = embed(M, x) + @test z == x - X_inv_cayley_retraction = inverse_retract(SpSt_6_4, p_6_4, q_6_4) - X_inv_cayley_retraction_2 = - inverse_retract(SpSt_6_4, p_6_4, q_6_4, CayleyInverseRetraction()) - @test isapprox(X_inv_cayley_retraction, X_inv_cayley_retraction_2; atol=1.0e-16) - @test isapprox(X_inv_cayley_retraction, X1; atol=1.0e-12) - end - @testset "Riemannian Metric" begin - X1_norm = 37.85466645 - @test isapprox(norm(SpSt_6_4, p_6_4, X1), X1_norm; atol=1.0e-8) - @test isapprox( - norm(SpSt_6_4, p_6_4, X1), - √inner(SpSt_6_4, p_6_4, X1, X1); - atol=1.0e-8, - ) + Y = similar(X1) + embed!(M, Y, p_6_4, X1) + @test Y == X1 + end + @testset "Retractions and Exponential Mapping" begin + @test isapprox(retract(M, p_6_4, X1), q_6_4; atol=1.0e-12) + @test isapprox(retract(M, p_6_4, X1, CayleyRetraction()), q_6_4; atol=1.0e-12) - X2_norm = 1.0 - @test isapprox(norm(SpSt_6_4, p_6_4, X2), X2_norm; atol=1.0e-6) - @test isapprox( - norm(SpSt_6_4, p_6_4, X2), - √inner(SpSt_6_4, p_6_4, X2, X2); - atol=1.0e-6, - ) + X_inv_cayley_retraction = inverse_retract(M, p_6_4, q_6_4) + X_inv_cayley_retraction_2 = + inverse_retract(M, p_6_4, q_6_4, CayleyInverseRetraction()) + @test isapprox(X_inv_cayley_retraction, X_inv_cayley_retraction_2; atol=1.0e-16) + @test isapprox(X_inv_cayley_retraction, X1; atol=1.0e-12) + end + @testset "Riemannian Metric" begin + X1_norm = 37.85466645 + @test isapprox(norm(M, p_6_4, X1), X1_norm; atol=1.0e-8) + @test isapprox(norm(M, p_6_4, X1), √inner(M, p_6_4, X1, X1); atol=1.0e-8) - # Project Project matrix A ∈ ℝ^{6Γ—4} onto (T_pSpSt): - A_6_4 = Array{Float64}([ - -7 2 12 0 - 4 0 1 -2 - -1 -1 4 0 - -18 4 -1 5 - 7 0 -2 11 - 2 2 -2 9 - ]) - A_6_4_proj = similar(A_6_4) - Manifolds.project!(SpSt_6_4, A_6_4_proj, p_6_4, A_6_4) - @test is_vector(SpSt_6_4, p_6_4, A_6_4_proj; error=:error, atol=2.0e-12) - end - @testset "Generate random points/tangent vectors" begin - M_big = SymplecticStiefel(20, 10) - p_big = rand(M_big) - @test is_point(M_big, p_big; error=:error, atol=1.0e-14) - X_big = rand(M_big; vector_at=p_big) - @test is_vector(M_big, p_big, X_big; error=:error, atol=1.0e-14) - end - @testset "test_manifold(SymplecticMatrices(6), ...)" begin - types = [Matrix{Float64}] - TEST_FLOAT32 && push!(types, Matrix{Float32}) - TEST_STATIC_SIZED && push!(types, MMatrix{6,4,Float64,24}) - for type in types - @testset "Type $(type)" begin - @testset "CayleyRetraction" begin - test_manifold( - SpSt_6_4, - convert.(type, points); - retraction_methods=[CayleyRetraction()], - default_retraction_method=CayleyRetraction(), - default_inverse_retraction_method=CayleyInverseRetraction(), - test_inplace=true, - is_point_atol_multiplier=1.0e4, - is_tangent_atol_multiplier=1.0e3, - retraction_atol_multiplier=1.0e1, - test_project_tangent=(type != MMatrix{6,4,Float64,24}), - test_injectivity_radius=false, - test_exp_log=false, - test_representation_size=true, - ) - end + X2_norm = 1.0 + @test isapprox(norm(M, p_6_4, X2), X2_norm; atol=1.0e-6) + @test isapprox(norm(M, p_6_4, X2), √inner(M, p_6_4, X2, X2); atol=1.0e-6) - @testset "ExponentialRetraction" begin - test_manifold( - SpSt_6_4, - convert.(type, close_points); - retraction_methods=[ExponentialRetraction()], - default_retraction_method=ExponentialRetraction(), - default_inverse_retraction_method=CayleyInverseRetraction(), - test_inplace=true, - is_point_atol_multiplier=1.0e11, - is_tangent_atol_multiplier=1.0e2, - retraction_atol_multiplier=1.0e4, - test_project_tangent=(type != MMatrix{6,4,Float64,24}), - test_injectivity_radius=false, - test_exp_log=false, - test_representation_size=true, - ) - end + # Project Project matrix A ∈ ℝ^{6Γ—4} onto (T_pSpSt): + A_6_4 = Array{Float64}([ + -7 2 12 0 + 4 0 1 -2 + -1 -1 4 0 + -18 4 -1 5 + 7 0 -2 11 + 2 2 -2 9 + ]) + A_6_4_proj = similar(A_6_4) + Manifolds.project!(M, A_6_4_proj, p_6_4, A_6_4) + @test is_vector(M, p_6_4, A_6_4_proj; error=:error, atol=2.0e-12) + end + @testset "Generate random points/tangent vectors" begin + M_big = SymplecticStiefel(20, 10) + p_big = rand(M_big) + @test is_point(M_big, p_big; error=:error, atol=1.0e-14) + X_big = rand(M_big; vector_at=p_big) + @test is_vector(M_big, p_big, X_big; error=:error, atol=1.0e-14) + end + @testset "test_manifold(SymplecticMatrices(6), ...)" begin + types = [Matrix{Float64}] + TEST_FLOAT32 && push!(types, Matrix{Float32}) + TEST_STATIC_SIZED && push!(types, MMatrix{6,4,Float64,24}) + for type in types + @testset "Type $(type)" begin + @testset "CayleyRetraction" begin + test_manifold( + M, + convert.(type, points); + retraction_methods=[CayleyRetraction()], + default_retraction_method=CayleyRetraction(), + default_inverse_retraction_method=CayleyInverseRetraction(), + test_inplace=true, + is_point_atol_multiplier=1.0e4, + is_tangent_atol_multiplier=1.0e3, + retraction_atol_multiplier=1.0e1, + test_project_tangent=(type != MMatrix{6,4,Float64,24}), + test_injectivity_radius=false, + test_exp_log=false, + test_representation_size=true, + ) end - end # for - end - @testset "Gradient Computations" begin - Q_grad = SymplecticElement(points[1]) - function test_f(p) - k = size(p)[2] - return tr(p[1:k, 1:k]) - end - function analytical_grad_f(p) - n, k = size(p) - euc_grad_f = [Array(I, k, k); zeros((n - k), k)] - return Q_grad * p * (euc_grad_f') * Q_grad * p + euc_grad_f * p' * p + @testset "ExponentialRetraction" begin + test_manifold( + M, + convert.(type, close_points); + retraction_methods=[ExponentialRetraction()], + default_retraction_method=ExponentialRetraction(), + default_inverse_retraction_method=CayleyInverseRetraction(), + test_inplace=true, + is_point_atol_multiplier=1.0e11, + is_tangent_atol_multiplier=1.0e2, + retraction_atol_multiplier=1.0e4, + test_project_tangent=(type != MMatrix{6,4,Float64,24}), + test_injectivity_radius=false, + test_exp_log=false, + test_representation_size=true, + ) + end end - p_grad = convert(Array{Float64}, points[1]) - fd_diff = RiemannianProjectionBackend(ManifoldDiff.FiniteDifferencesBackend()) + end # for + end + @testset "Canonical project" begin + E = SymplecticMatrices(6) + p = [ + 1.0 1.0 3.0 0.0 0.0 0.0 + -1.0 -2.0 -4.0 0.0 0.0 0.0 + 3.0 0.0 7.0 0.0 0.0 0.0 + 3.0 4 10.0 14.0 5.0 -6.0 + -5.0 -9.0 -19.0 7.0 2.0 -3.0 + 0.0 0.0 0.0 -2.0 -1.0 1.0 + ] + @test is_point(E, p) + M = SymplecticStiefel(6, 4) + q = canonical_project(M, p) + @test is_point(M, q) + q2 = similar(q) + canonical_project!(M, q2, p) + @test isapprox(M, q, q2) + end + @testset "Gradient Computations" begin + Q_grad = SymplecticElement(points[1]) + function test_f(p) + k = size(p)[2] + return tr(p[1:k, 1:k]) + end + function analytical_grad_f(p) + n, k = size(p) + euc_grad_f = [Array(I, k, k); zeros((n - k), k)] + return Q_grad * p * (euc_grad_f') * Q_grad * p + euc_grad_f * p' * p + end + p_grad = convert(Array{Float64}, points[1]) + fd_diff = RiemannianProjectionBackend(ManifoldDiff.FiniteDifferencesBackend()) - @test isapprox( - Manifolds.gradient(SpSt_6_4, test_f, p_grad, fd_diff), - analytical_grad_f(p_grad); - atol=1.0e-9, - ) + @test isapprox( + Manifolds.gradient(M, test_f, p_grad, fd_diff), + analytical_grad_f(p_grad); + atol=1.0e-9, + ) - grad_f_p = similar(p_grad) - Manifolds.gradient!(SpSt_6_4, test_f, grad_f_p, p_grad, fd_diff) - @test isapprox(grad_f_p, analytical_grad_f(p_grad); atol=1.0e-9) - end + grad_f_p = similar(p_grad) + Manifolds.gradient!(M, test_f, grad_f_p, p_grad, fd_diff) + @test isapprox(grad_f_p, analytical_grad_f(p_grad); atol=1.0e-9) end @testset "field parameter" begin - SpSt_6_4 = SymplecticStiefel(2 * 3, 2 * 2; parameter=:field) - @test typeof(get_embedding(SpSt_6_4)) === Euclidean{Tuple{Int,Int},ℝ} - @test repr(SpSt_6_4) == "SymplecticStiefel(6, 4; field=ℝ; parameter=:field)" - @test get_total_space(SpSt_6_4) == SymplecticMatrices(6; parameter=:field) + M = SymplecticStiefel(6, 4; parameter=:field) + @test typeof(get_embedding(M)) === Euclidean{Tuple{Int,Int},ℝ} + @test repr(M) == "SymplecticStiefel(6, 4; field=ℝ; parameter=:field)" + @test get_total_space(M) == SymplecticMatrices(6; parameter=:field) end end From 7af7ae3a5200b42127887862292887520065aa2e Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sat, 20 Jan 2024 17:52:17 +0100 Subject: [PATCH 33/65] Work on Symplectic test coverage. --- src/manifolds/Symplectic.jl | 15 +- test/manifolds/symplectic.jl | 573 +++++++++++++++-------------------- 2 files changed, 252 insertions(+), 336 deletions(-) diff --git a/src/manifolds/Symplectic.jl b/src/manifolds/Symplectic.jl index 5f416a81ea..bb630dc391 100644 --- a/src/manifolds/Symplectic.jl +++ b/src/manifolds/Symplectic.jl @@ -745,14 +745,6 @@ function random_vector!(M::SymplecticMatrices, X, p; Οƒ=1.0) return X end -function rand_hamiltonian(M::SymplecticMatrices; frobenius_norm=1.0) - n = get_parameter(M.size)[1] - Base.depwarn( - "`rand_hamiltonian(M::Symplectic($(2n)); frobeniusnorm=$(frobeniusnorm)) is deprecated. Use `rand(HamiltonianMatrices($(2n); Οƒ=$(frobenius_norm))` instead", - ) - return rand(HamiltonianMatrices(2n); Οƒ=frobenius_norm) -end - @doc raw""" retract(::SymplecticMatrices, p, X, ::CayleyRetraction) retract!(::SymplecticMatrices, q, p, X, ::CayleyRetraction) @@ -797,12 +789,11 @@ Then the Riemannian gradient ``X = \operatorname{grad} f(p)`` is given by X = Yp^{\mathrm{T}}p + J_{2n}pY^{\mathrm{T}}J_{2n}p, ``` -where ``J_{2n}`` denotes the [`SymplecticElement`)(@ref). - +where ``J_{2n}`` denotes the [`SymplecticElement`](@ref). """ function riemannian_gradient(::SymplecticMatrices, p, Y; kwargs...) - J = SymplecticElement(p, X) - return Y * p'p .+ (J * p) * Y' * (J * p) + J = SymplecticElement(p) + return Y * p' * p .+ (J * p) * Y' * (J * p) end function riemannian_gradient!(M::SymplecticMatrices, X, p, Y; kwargs...) diff --git a/test/manifolds/symplectic.jl b/test/manifolds/symplectic.jl index 0447ed646b..8550a31ced 100644 --- a/test/manifolds/symplectic.jl +++ b/test/manifolds/symplectic.jl @@ -4,322 +4,247 @@ using Manifolds: RiemannianProjectionBackend using ManifoldDiff @testset "SymplecticMatrices" begin - @testset "Real" begin - Sp_2 = SymplecticMatrices(2 * 1) - Metr_Sp_2 = MetricManifold(Sp_2, RealSymplecticMetric()) - - p_2 = [0.0 1.0/2.0; -2.0 -2.0] - X1 = [ - -0.121212 0.121212 - 0.969697 -1.0 - ] - X2 = [ - 0.0 0.0 - 0.0 -1.0 - ] - - Sp_6 = SymplecticMatrices(6) - points = [ - [ - 1 1 3 0 0 0 - -1 -2 -4 0 0 0 - 3 0 7 0 0 0 - 3 4 10 14 5 -6 - -5 -9 -19 7 2 -3 - 0 0 0 -2 -1 1 - ], - [ - 0 0 0 -2 1 5 - 0 0 0 0 -1 -2 - 0 0 0 -1 -2 -3 - -1 2 -1 9 -4 -21 - -7 11 -5 -2 10 24 - 3 -4 2 -2 -7 -13 - ], - [ - 6 -1 11 -10 8 6 - 2 0 3 23 -14 -14 - -3 0 -5 -1 5 1 - 0 0 0 0 -1 0 - 0 0 0 5 -3 -3 - 0 0 0 3 -4 -2 - ], - [ - 2 -1 5 -4 4 2 - 2 0 3 11 -6 -6 - -1 0 -2 -4 7 3 - 0 0 0 0 -1 0 - 0 0 0 2 -1 -1 - 0 0 0 3 -4 -2 - ], + M = SymplecticMatrices(2) + Metr_Sp_2 = MetricManifold(M, RealSymplecticMetric()) + + p_2 = [0.0 1.0/2.0; -2.0 -2.0] + X1 = [ + -0.121212 0.121212 + 0.969697 -1.0 + ] + X2 = [ + 0.0 0.0 + 0.0 -1.0 + ] + + Sp_6 = SymplecticMatrices(6) + points = [ + [ + 1.0 1.0 3.0 0.0 0.0 0.0 + -1.0 -2.0 -4.0 0.0 0.0 0.0 + 3.0 0.0 7.0 0.0 0.0 0.0 + 3.0 4.0 10.0 14.0 5.0 -6.0 + -5.0 -9.0 -19.0 7.0 2.0 -3.0 + 0.0 0.0 0.0 -2.0 -1.0 1.0 + ], + [ + 0.0 0.0 0.0 -2.0 1.0 5.0 + 0.0 0.0 0.0 0.0 -1.0 -2.0 + 0.0 0.0 0.0 -1.0 -2.0 -3.0 + -1.0 2.0 -1.0 9.0 -4.0 -21.0 + -7.0 11.0 -5.0 -2.0 10.0 24.0 + 3.0 -4.0 2.0 -2.0 -7.0 -13.0 + ], + [ + 6.0 -1.0 11.0 -10.0 8.0 6.0 + 2.0 0.0 3.0 23.0 -14.0 -14.0 + -3.0 0.0 -5.0 -1.0 5.0 1.0 + 0.0 0.0 0.0 0.0 -1.0 0.0 + 0.0 0.0 0.0 5.0 -3.0 -3.0 + 0.0 0.0 0.0 3.0 -4.0 -2.0 + ], + [ + 2.0 -1.0 5.0 -4.0 4.0 2.0 + 2.0 0.0 3.0 11.0 -6.0 -6.0 + -1.0 0.0 -2.0 -4.0 7.0 3.0 + 0.0 0.0 0.0 0.0 -1.0 0.0 + 0.0 0.0 0.0 2.0 -1.0 -1.0 + 0.0 0.0 0.0 3.0 -4.0 -2.0 + ], + ] + + large_tr_norm_points = [ + [ + 0.0 -3.0 -5.0 0.0 0.0 0.0 + -2.0 -3.0 4.0 0.0 0.0 0.0 + -3.0 -5.0 5.0 0.0 0.0 0.0 + 11.0 27.0 -5.0 5.0 -2.0 1.0 + -37.0 -29.0 117.0 40.0 -15.0 9.0 + 22.0 30.0 -47.0 -27.0 10.0 -6.0 + ], + [ + 0.0 0.0 0.0 7.0 -2.0 1.0 + 0.0 0.0 0.0 19.0 -5.0 3.0 + 0.0 0.0 0.0 -6.0 2.0 -1.0 + -1.0 1.0 8.0 -14.0 4.0 -2.0 + 0.0 -1.0 -2.0 -94.0 26.0 -15.0 + -1.0 -2.0 3.0 45.0 -11.0 7.0 + ], + ] + + @testset "Basics" begin + @test repr(M) == "SymplecticMatrices($(2), ℝ)" + @test_throws ArgumentError SymplecticMatrices(3) + @test representation_size(M) == (2, 2) + @test !is_flat(M) + + @test is_point(M, p_2) + @test_throws DomainError is_point(M, p_2 + I; error=:error) + + @test is_vector(M, p_2, X1; atol=1.0e-6) + @test is_vector(M, p_2, X2; atol=1.0e-12) + @test is_vector(M, p_2, X1 + X2; atol=1.0e-6) + @test_throws DomainError is_vector(M, p_2, X1 + [0.1 0.1; -0.1 0.1]; error=:error) + end + @testset "Symplectic Inverse" begin + I_2n = Array(I, 2, 2) + @test Manifolds.symplectic_inverse_times(M, p_2, p_2) == I_2n + @test Manifolds.symplectic_inverse_times!(M, copy(p_2), p_2, p_2) == I_2n + @test inv(M, p_2) * p_2 == I_2n + @test inv!(M, copy(p_2)) * p_2 == I_2n + end + @testset "Embedding" begin + x = [0.0 1.0/2.0; -2.0 -2.0] + y = similar(x) + z = embed(M, x) + @test z == x + + Y = similar(X1) + embed!(M, Y, p_2, X1) + @test Y == X1 + end + @testset "Retractions and Exponential Mapping" begin + q_exp = [ + -0.0203171 0.558648 + -1.6739 -3.19344 ] + @test isapprox(exp(M, p_2, X2), q_exp; atol=1.0e-5) + @test isapprox(retract(M, p_2, X2, ExponentialRetraction()), q_exp; atol=1.0e-5) - large_tr_norm_points = [ - [ - 0 -3 -5 0 0 0 - -2 -3 4 0 0 0 - -3 -5 5 0 0 0 - 11 27 -5 5 -2 1 - -37 -29 117 40 -15 9 - 22 30 -47 -27 10 -6 - ], - [ - 0 0 0 7 -2 1 - 0 0 0 19 -5 3 - 0 0 0 -6 2 -1 - -1 1 8 -14 4 -2 - 0 -1 -2 -94 26 -15 - -1 -2 3 45 -11 7 - ], + q_cay = [ + 0.0 0.5 + -2.0 -3.0 ] - - @testset "Basics" begin - @test repr(Sp_2) == "SymplecticMatrices($(2), ℝ)" - @test representation_size(Sp_2) == (2, 2) - @test base_manifold(Sp_2) === Sp_2 - @test !is_flat(Sp_2) - - @test is_point(Sp_2, p_2) - @test_throws DomainError is_point(Sp_2, p_2 + I; error=:error) - - @test is_vector(Sp_2, p_2, X1; atol=1.0e-6) - @test is_vector(Sp_2, p_2, X2; atol=1.0e-12) - @test is_vector(Sp_2, p_2, X1 + X2; atol=1.0e-6) - @test_throws DomainError is_vector( - Sp_2, + @test retract(M, p_2, X2) == q_cay + @test retract(M, p_2, X2, CayleyRetraction()) == q_cay + + X_inv_cayley_retraction = inverse_retract(M, p_2, q_cay) + X_inv_cayley_retraction_2 = + inverse_retract(M, p_2, q_cay, CayleyInverseRetraction()) + @test X_inv_cayley_retraction == X_inv_cayley_retraction_2 + @test X_inv_cayley_retraction β‰ˆ X2 + end + @testset "Riemannian metric" begin + X1_p_norm = 0.49259905148939337 + @test norm(M, p_2, X1) == X1_p_norm + @test norm(M, p_2, X1) == √(inner(M, p_2, X1, X1)) + + X2_p_norm = 1 / 2 + @test norm(M, p_2, X2) == X2_p_norm + @test norm(M, p_2, X2) == √(inner(M, p_2, X2, X2)) + + q_2 = retract(M, p_2, X2, ExponentialRetraction()) + approximate_p_q_geodesic_distance = 0.510564444555605 + @test isapprox(distance(M, p_2, q_2), approximate_p_q_geodesic_distance; atol=1e-14) + + # Project tangent vector into (T_pSp)^{\perp}: + Extended_Sp_2 = MetricManifold(get_embedding(M), ExtendedSymplecticMetric()) + proj_normal_X2 = Manifolds.project_normal!(Extended_Sp_2, copy(X2), p_2, X2) + @test isapprox(proj_normal_X2, zero(X2); atol=1.0e-16) + + # Project Project matrix A ∈ ℝ^{2Γ—2} onto (T_pSp): + A_2 = [5.0 -21.5; 3.14 14.9] + A_2_proj = similar(A_2) + project!(Extended_Sp_2, A_2_proj, p_2, A_2) + @test is_vector(M, p_2, A_2_proj; atol=1.0e-16) + + # Change representer of A onto T_pSp: + @testset "Change Representer" begin + A_2_representer = change_representer( + MetricManifold(get_embedding(M), ExtendedSymplecticMetric()), + EuclideanMetric(), p_2, - X1 + [0.1 0.1; -0.1 0.1]; - error=:error, + A_2, ) - end - @testset "Symplectic Inverse" begin - I_2n = Array(I, 2, 2) - @test Manifolds.symplectic_inverse_times(Sp_2, p_2, p_2) == I_2n - @test Manifolds.symplectic_inverse_times!(Sp_2, copy(p_2), p_2, p_2) == I_2n - @test inv(Sp_2, p_2) * p_2 == I_2n - @test inv!(Sp_2, copy(p_2)) * p_2 == I_2n - end - @testset "Embedding" begin - x = [0.0 1.0/2.0; -2.0 -2.0] - y = similar(x) - z = embed(Sp_2, x) - @test z == x - - Y = similar(X1) - embed!(Sp_2, Y, p_2, X1) - @test Y == X1 - end - @testset "Retractions and Exponential Mapping" begin - q_exp = [ - -0.0203171 0.558648 - -1.6739 -3.19344 - ] - @test isapprox(exp(Sp_2, p_2, X2), q_exp; atol=1.0e-5) - @test isapprox( - retract(Sp_2, p_2, X2, ExponentialRetraction()), - q_exp; - atol=1.0e-5, - ) - - q_cay = [ - 0.0 0.5 - -2.0 -3.0 - ] - @test retract(Sp_2, p_2, X2) == q_cay - @test retract(Sp_2, p_2, X2, CayleyRetraction()) == q_cay - - X_inv_cayley_retraction = inverse_retract(Sp_2, p_2, q_cay) - X_inv_cayley_retraction_2 = - inverse_retract(Sp_2, p_2, q_cay, CayleyInverseRetraction()) - @test X_inv_cayley_retraction == X_inv_cayley_retraction_2 - @test X_inv_cayley_retraction β‰ˆ X2 - end - @testset "Riemannian metric" begin - X1_p_norm = 0.49259905148939337 - @test norm(Sp_2, p_2, X1) == X1_p_norm - @test norm(Sp_2, p_2, X1) == √(inner(Sp_2, p_2, X1, X1)) - - X2_p_norm = 1 / 2 - @test norm(Sp_2, p_2, X2) == X2_p_norm - @test norm(Sp_2, p_2, X2) == √(inner(Sp_2, p_2, X2, X2)) - - q_2 = retract(Sp_2, p_2, X2, ExponentialRetraction()) - approximate_p_q_geodesic_distance = 0.510564444555605 - @test isapprox( - distance(Sp_2, p_2, q_2), - approximate_p_q_geodesic_distance; - atol=1e-14, - ) - - # Project tangent vector into (T_pSp)^{\perp}: - Extended_Sp_2 = MetricManifold(get_embedding(Sp_2), ExtendedSymplecticMetric()) - proj_normal_X2 = Manifolds.project_normal!(Extended_Sp_2, copy(X2), p_2, X2) - @test isapprox(proj_normal_X2, zero(X2); atol=1.0e-16) - - # Project Project matrix A ∈ ℝ^{2Γ—2} onto (T_pSp): - A_2 = [5.0 -21.5; 3.14 14.9] - A_2_proj = similar(A_2) - project!(Extended_Sp_2, A_2_proj, p_2, A_2) - @test is_vector(Sp_2, p_2, A_2_proj; atol=1.0e-16) - - # Change representer of A onto T_pSp: - @testset "Change Representer" begin - A_2_representer = change_representer( - MetricManifold(get_embedding(Sp_2), ExtendedSymplecticMetric()), - EuclideanMetric(), - p_2, - A_2, - ) - @test isapprox( - inner(Sp_2, p_2, A_2_representer, X1), - tr(A_2' * X1); - atol=1.0e-12, - ) - @test isapprox( - inner(Sp_2, p_2, A_2_representer, X2), - tr(A_2' * X2); - atol=1.0e-12, - ) - @test isapprox( - inner(Sp_2, p_2, A_2_representer, A_2), - norm(A_2)^2; - atol=1.0e-12, - ) - end - end - @testset "Generate random points/tangent vectors" begin - M_big = SymplecticMatrices(20) - p_big = rand(M_big) - @test is_point(M_big, p_big; error=:error, atol=1.0e-12) - X_big = rand(M_big; vector_at=p_big) - @test is_vector(M_big, p_big, X_big; error=:error, atol=1.0e-12) - end - @testset "test_manifold(SymplecticMatrices(6), ...)" begin - @testset "Type $(Matrix{Float64})" begin - type = Matrix{Float64} - pts = convert.(type, points) - test_manifold( - Sp_6, - cat(pts, large_tr_norm_points; dims=1); - retraction_methods=[CayleyRetraction(), ExponentialRetraction()], - default_retraction_method=CayleyRetraction(), - default_inverse_retraction_method=CayleyInverseRetraction(), - test_inplace=true, - is_point_atol_multiplier=1.0e8, - is_tangent_atol_multiplier=1.0e6, - retraction_atol_multiplier=1.0e4, - test_project_tangent=true, - test_injectivity_radius=false, - test_exp_log=false, - test_representation_size=true, - ) - end - - TEST_FLOAT32 && @testset "Type $(Matrix{Float32})" begin - type = Matrix{Float64} - pts = convert.(type, points) - test_manifold( - Sp_6, - pts; - retraction_methods=[CayleyRetraction(), ExponentialRetraction()], - default_retraction_method=CayleyRetraction(), - default_inverse_retraction_method=CayleyInverseRetraction(), - test_inplace=true, - is_point_atol_multiplier=1.0e8, - is_tangent_atol_multiplier=1.0e6, - retraction_atol_multiplier=1.0e4, - test_project_tangent=true, - test_injectivity_radius=false, - test_exp_log=false, - test_representation_size=true, - ) - end - - TEST_STATIC_SIZED && @testset "Type $(MMatrix{6, 6, Float64, 36})" begin - type = MMatrix{6,6,Float64,36} - pts = convert.(type, points) - test_manifold( - Sp_6, - pts; - retraction_methods=[CayleyRetraction(), ExponentialRetraction()], - default_retraction_method=CayleyRetraction(), - default_inverse_retraction_method=CayleyInverseRetraction(), - test_inplace=true, - is_point_atol_multiplier=1.0e7, - is_tangent_atol_multiplier=1.0e6, - retraction_atol_multiplier=1.0e4, - test_project_tangent=false, # Cannot solve 'sylvester' for MMatrix-type. - test_injectivity_radius=false, - test_exp_log=false, - test_representation_size=true, - ) - end - end - - @testset "Gradient Computations" begin - test_f(p) = tr(p) - Q_grad = SymplecticElement(points[1]) - analytical_grad_f(p) = (1 / 2) * (p * Q_grad * p * Q_grad + p * p') - - p_grad = convert(Array{Float64}, points[1]) - fd_diff = RiemannianProjectionBackend(ManifoldDiff.FiniteDifferencesBackend()) - - @test isapprox( - Manifolds.gradient(Sp_6, test_f, p_grad, fd_diff), - analytical_grad_f(p_grad); - atol=1.0e-9, - ) - @test isapprox( - Manifolds.gradient(Sp_6, test_f, p_grad, fd_diff; extended_metric=false), - analytical_grad_f(p_grad); - atol=1.0e-9, - ) - - grad_f_p = similar(p_grad) - Manifolds.gradient!(Sp_6, test_f, grad_f_p, p_grad, fd_diff) - @test isapprox(grad_f_p, analytical_grad_f(p_grad); atol=1.0e-9) - - Manifolds.gradient!( - Sp_6, - test_f, - grad_f_p, - p_grad, - fd_diff; - extended_metric=false, - ) - @test isapprox(grad_f_p, analytical_grad_f(p_grad); atol=1.0e-9) + @test isapprox(inner(M, p_2, A_2_representer, X1), tr(A_2' * X1); atol=1.0e-12) + @test isapprox(inner(M, p_2, A_2_representer, X2), tr(A_2' * X2); atol=1.0e-12) + @test isapprox(inner(M, p_2, A_2_representer, A_2), norm(A_2)^2; atol=1.0e-12) end end - + @testset "Generate random points/tangent vectors" begin + M_big = SymplecticMatrices(20) + p_big = rand(M_big) + @test is_point(M_big, p_big; error=:error, atol=1.0e-12) + X_big = rand(M_big; vector_at=p_big) + @test is_vector(M_big, p_big, X_big; error=:error, atol=1.0e-12) + end + @testset "test_manifold(SymplecticMatrices(6))" begin + test_manifold( + Sp_6, + cat(points, large_tr_norm_points; dims=1); + retraction_methods=[CayleyRetraction(), ExponentialRetraction()], + default_retraction_method=CayleyRetraction(), + default_inverse_retraction_method=CayleyInverseRetraction(), + test_inplace=true, + is_point_atol_multiplier=1.0e8, + is_tangent_atol_multiplier=1.0e6, + retraction_atol_multiplier=1.0e4, + test_project_tangent=true, + test_injectivity_radius=false, + test_exp_log=false, + test_representation_size=true, + ) + end + @testset "Gradient Computations" begin + test_f(p) = tr(p) + J = SymplecticElement(points[1]) + analytical_grad_f(p) = (1 / 2) * (p * J * p * J + p * p') + + p_grad = points[1] + fd_diff = RiemannianProjectionBackend(ManifoldDiff.FiniteDifferencesBackend()) + + @test isapprox( + Manifolds.gradient(Sp_6, test_f, p_grad, fd_diff), + analytical_grad_f(p_grad); + atol=1.0e-9, + ) + @test isapprox( + Manifolds.gradient(Sp_6, test_f, p_grad, fd_diff; extended_metric=false), + analytical_grad_f(p_grad); + atol=1.0e-9, + ) + + grad_f_p = similar(p_grad) + Manifolds.gradient!(Sp_6, test_f, grad_f_p, p_grad, fd_diff) + @test isapprox(grad_f_p, analytical_grad_f(p_grad); atol=1.0e-9) + + Manifolds.gradient!(Sp_6, test_f, grad_f_p, p_grad, fd_diff; extended_metric=false) + @test isapprox(grad_f_p, analytical_grad_f(p_grad); atol=1.0e-9) + + Euclidean_gradient(p) = one(p) + X = riemannian_gradient(Sp_6, p, one(p)) + X2 = similar(X) + riemannian_gradient!(Sp_6, X2, p, one(p)) + @test isapprox(Sp_6, p, X, X2) + end @testset "SymplecticElement" begin - # TODO: Test for different type matrices. @test SymplecticElement() == SymplecticElement(1) Sp_4 = SymplecticMatrices(4) pQ_1 = [ - 0 0 -2 3 - 0 0 1 -1 - -1 -1 0 0 - -3 -2 4 -4 + 0.0 0 -2.0 3.0 + 0.0 0.0 1.0 -1.0 + -1.0 -1.0 0.0 0.0 + -3.0 -2.0 4.0 -4.0 ] pQ_2 = [ - 0 0 -2 5 - 0 0 1 -2 - -2 -1 0 0 - -5 -2 4 -8 + 0.0 0.0 -2.0 5.0 + 0.0 0.0 1.0 -2.0 + -2.0 -1.0 0.0 0.0 + -5.0 -2.0 4 -8.0 ] p_odd_row = [ - 0 0 -1 3 - 0 0 1 0 - -2 -1 0 0 + 0.0 0.0 -1.0 3.0 + 0.0 0.0 1.0 0.0 + -2.0 -1.0 0.0 0.0 ] p_odd_col = [ - 0 -2 5 - 0 1 -2 - -1 0 0 - -2 4 -8 + 0.0 -2.0 5.0 + 0.0 1.0 -2.0 + -1.0 0.0 0.0 + -2.0 4.0 -8.0 ] Q = SymplecticElement(pQ_1, pQ_2) - Q2 = SymplecticElement(1) + Q2 = SymplecticElement(1.0) @testset "Type Basics" begin @test Q == Q2 @@ -327,7 +252,7 @@ using ManifoldDiff @test copy(Q) == Q @test eltype(SymplecticElement(1 // 1)) == Rational{Int64} @test convert(SymplecticElement{Float64}, Q) == SymplecticElement(1.0) - @test "$Q" == "SymplecticElement{Int64}(): 1*[0 I; -I 0]" + @test "$Q" == "SymplecticElement{Float64}(): 1.0*[0 I; -I 0]" @test ( "$(SymplecticElement(1 + 2im))" == "SymplecticElement{Complex{Int64}}(): (1 + 2im)*[0 I; -I 0]" @@ -335,8 +260,8 @@ using ManifoldDiff end @testset "Matrix Operations" begin - @test -Q == SymplecticElement(-1) - @test (2 * Q) * (5 // 6) == SymplecticElement(5 // 3) + @test -Q == SymplecticElement(-1.0) + @test (2 * Q) * (5 / 6) == SymplecticElement(5 / 3) @testset "Powers" begin @test inv(Q) * Q == I @@ -353,30 +278,30 @@ using ManifoldDiff @test Q + Q == 2 * Q @test Q - SymplecticElement(1.0) == SymplecticElement(0.0) @test Q + pQ_1 == [ - 0 0 -1 3 - 0 0 1 0 - -2 -1 0 0 - -3 -3 4 -4 + 0.0 0.0 -1.0 3.0 + 0.0 0.0 1.0 0.0 + -2.0 -1.0 0.0 0.0 + -3.0 -3.0 4.0 -4.0 ] @test Q - pQ_1 == [ - 0 0 3 -3 - 0 0 -1 2 - 0 1 0 0 - 3 1 -4 4 + 0.0 0.0 3.0 -3.0 + 0.0 0.0 -1.0 2.0 + 0.0 1.0 0.0 0.0 + 3.0 1.0 -4.0 4.0 ] @test pQ_1 - Q == [ - 0 0 -3 3 - 0 0 1 -2 - 0 -1 0 0 - -3 -1 4 -4 + 0.0 0.0 -3.0 3.0 + 0.0 0.0 1.0 -2.0 + 0.0 -1.0 0.0 0.0 + -3.0 -1.0 4.0 -4.0 ] @test (pQ_1 + Q) == (Q + pQ_1) @test_throws ArgumentError Q + p_odd_row end @testset "Transpose-Adjoint" begin - @test Q' == SymplecticElement(-1) - @test transpose(SymplecticElement(10)) == SymplecticElement(-10) + @test Q' == SymplecticElement(-1.0) + @test transpose(SymplecticElement(10.0)) == SymplecticElement(-10.0) @test transpose(SymplecticElement(1 - 2.0im)) == SymplecticElement(-1 + 2.0im) @test adjoint(Q) == -Q @@ -388,18 +313,18 @@ using ManifoldDiff z1 = [1 + 2im; 1 - 2im] @test lmul!(Q, copy(z1)) == Q * z1 @test lmul!(Q, copy(p_odd_col)) == [ - -1 0 0 - -2 4 -8 - 0 2 -5 - 0 -1 2 + -1 0 0.0 + -2 4 -8.0 + 0 2 -5.0 + 0 -1 2.0 ] @test_throws ArgumentError lmul!(Q, copy(p_odd_row)) @test rmul!(copy(z1'), Q) == z1' * Q @test rmul!(copy(p_odd_row), Q) == [ - 1 -3 0 0 - -1 0 0 0 - 0 0 -2 -1 + 1 -3 0 0.0 + -1 0 0 0.0 + 0 0 -2 -1.0 ] @test_throws ArgumentError rmul!(copy(p_odd_col), Q) @@ -423,8 +348,8 @@ using ManifoldDiff end end @testset "field parameter" begin - Sp_2 = SymplecticMatrices(2; parameter=:field) - @test typeof(get_embedding(Sp_2)) === Euclidean{Tuple{Int,Int},ℝ} - @test repr(Sp_2) == "SymplecticMatrices(2, ℝ; parameter=:field)" + M = SymplecticMatrices(2; parameter=:field) + @test typeof(get_embedding(M)) === Euclidean{Tuple{Int,Int},ℝ} + @test repr(M) == "SymplecticMatrices(2, ℝ; parameter=:field)" end end From 8021ed175fb4c473562dc9fdc10eca5ac10560ee Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 21 Jan 2024 13:24:07 +0100 Subject: [PATCH 34/65] fix a typo. --- test/manifolds/symplectic.jl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/manifolds/symplectic.jl b/test/manifolds/symplectic.jl index 8550a31ced..b97db3eaf1 100644 --- a/test/manifolds/symplectic.jl +++ b/test/manifolds/symplectic.jl @@ -211,11 +211,10 @@ using ManifoldDiff Manifolds.gradient!(Sp_6, test_f, grad_f_p, p_grad, fd_diff; extended_metric=false) @test isapprox(grad_f_p, analytical_grad_f(p_grad); atol=1.0e-9) - Euclidean_gradient(p) = one(p) - X = riemannian_gradient(Sp_6, p, one(p)) + X = riemannian_gradient(Sp_6, p_grad, one(p_grad)) X2 = similar(X) - riemannian_gradient!(Sp_6, X2, p, one(p)) - @test isapprox(Sp_6, p, X, X2) + riemannian_gradient!(Sp_6, X2, p_grad, one(p_grad)) + @test isapprox(Sp_6, p_grad, X, X2) end @testset "SymplecticElement" begin @test SymplecticElement() == SymplecticElement(1) From b94a8e471b09c63e3b12cd470d91c8adda1ac2fb Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 21 Jan 2024 14:34:51 +0100 Subject: [PATCH 35/65] A few more tests. --- src/manifolds/SymplecticGrassmann.jl | 10 ++++- src/manifolds/SymplecticGrassmannStiefel.jl | 17 ++++++++ test/manifolds/symplecticgrassmann.jl | 46 +++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 8f3ec41cd8..df90425161 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -111,11 +111,19 @@ Return the dimension of the [`SymplecticGrassmann`](@ref)`(2n,2k)`, which is see [BendokatZimmermann:2021](@cite), Section 4. """ -function manifold_dimension(::SymplecticGrassmann{<:Any,ℝ}) +function manifold_dimension(M::SymplecticGrassmann{<:Any,ℝ}) n, k = get_parameter(M.size) return 4 * (n - k) * k end +function Base.show(io::IO, ::SymplecticGrassmann{TypeParameter{Tuple{n,k}},𝔽}) where {n,k,𝔽} + return print(io, "SymplecticStiefel($(2n), $(2k); field=$(𝔽))") +end +function Base.show(io::IO, M::SymplecticGrassmann{Tuple{Int,Int},𝔽}) where {𝔽} + n, k = get_parameter(M.size) + return print(io, "SymplecticStiefel($(2n), $(2k); field=$(𝔽); parameter=:field)") +end + # # Representer specific implementations in their corrsponding subfiles # diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index 83148b716b..b29e73823c 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -24,6 +24,15 @@ function check_vector(M::SymplecticGrassmann, p, X; kwargs...) return check_vector(SymplecticStiefel(2 * n, 2 * k), p, X; kwargs...) end +embed(::SymplecticGrassmann, p) = p +embed(::SymplecticGrassmann, p, X) = X +embed!(::SymplecticGrassmann, q, p) = copyto!(q, p) +embed!(::SymplecticGrassmann, Y, p, X) = copyto!(Y, X) +embed!(::SymplecticGrassmann, q, p::StiefelPoint) = copyto!(q, p.value) +embed!(::SymplecticGrassmann, Y, p::StiefelPoint, X::StiefelTVector) = copyto!(Y, X.value) +embed(::SymplecticGrassmann, p::StiefelPoint) = p.value +embed(::SymplecticGrassmann, p::StiefelPoint, X::StiefelTVector) = X.value + @doc raw""" exp(::SymplecticGrassmann, p, X) exp!(M::SymplecticGrassmann, q, p, X) @@ -45,6 +54,14 @@ function exp!(M::SymplecticGrassmann, q, p, X) return q end +function get_embedding(::SymplecticGrassmann{TypeParameter{Tuple{n,k}},𝔽}) where {n,k,𝔽} + return SymplecticStiefel(2n, 2k, 𝔽) +end +function get_embedding(M::SymplecticGrassmann{Tuple{Int,Int},𝔽}) where {𝔽} + n, k = get_parameter(M.size) + return SymplecticStiefel(2n, 2k, 𝔽; parameter=:field) +end + @doc raw""" inverse_retract(::SymplecticGrassmann, p, q, ::CayleyInverseRetraction) inverse_retract!(::SymplecticGrassmann, q, p, X, ::CayleyInverseRetraction) diff --git a/test/manifolds/symplecticgrassmann.jl b/test/manifolds/symplecticgrassmann.jl index e22146d9c3..07bebe0ecb 100644 --- a/test/manifolds/symplecticgrassmann.jl +++ b/test/manifolds/symplecticgrassmann.jl @@ -1 +1,47 @@ include("../header.jl") + +@testset "Symplectic Grassmann" begin + M = SymplecticGrassmann(6, 4) + Mf = SymplecticGrassmann(6, 4; parameter=:field) + p = [ + 0.0 0.0 -5.0 -1.0 + 0.0 0.0 9.0 -2.0 + 0.0 0.0 -2.0 1.0 + -2.0 -9.0 -3.0 6.0 + -3.0 -13.0 -21.0 9.0 + -8.0 -36.0 18.0 -6.0 + ] + q = [ + 0.0 0.0 -3.0 1.0 + 0.0 0.0 8.0 -3.0 + 0.0 0.0 -2.0 1.0 + -1.0 -4.0 -6.0 3.0 + -1.0 -3.0 -21.0 9.0 + -2.0 -6.0 18.0 -6.0 + ] + X = [ + 0.0 0.0 4.25 4.25 + 0.0 0.0 0.125 0.125 + 0.0 0.0 -1.125 -1.125 + 3.625 18.125 -10.875 -10.875 + 5.0 25.0 -9.0 -9.0 + 13.5 67.5 4.5 4.5 + ] + Y = [ + -0.02648060 0.00416977 0.01130802 0.01015956 + 0.01718954 -0.00680433 0.02364406 -0.00083272 + 0.00050392 0.00191916 -0.01035902 -0.00079734 + 0.01811917 -0.02307032 -0.04297277 -0.05409099 + -0.02529516 0.00959934 -0.08594555 -0.06117803 + -0.02823014 0.00029946 -0.04196034 -0.04145413 + ] + @testset "Basics" begin + @test repr(M) == "SymplecticStiefel(6, 4; field=ℝ)" + @test repr(Mf) == "SymplecticStiefel(6, 4; field=ℝ; parameter=:field)" + @test manifold_dimension(M) == 4 * (6 - 4) + for _M in [M, Mf] + @test is_point(M, p) + @test is_vector(_M, p, X) + end + end +end From e10d3532db90502537910d3f8f2f85e9d356dc6b Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 21 Jan 2024 14:41:20 +0100 Subject: [PATCH 36/65] Fix embedding functions. --- src/manifolds/SymplecticGrassmann.jl | 27 ------------------- src/manifolds/SymplecticGrassmannProjector.jl | 18 +++++++++++++ src/manifolds/SymplecticGrassmannStiefel.jl | 27 +++++++++++++++++++ 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index df90425161..0e56b84108 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -73,33 +73,6 @@ end # Define Stiefel as the array fallback ManifoldsBase.@default_manifold_fallbacks SymplecticGrassmann StiefelPoint StiefelTVector value value -@doc raw""" - inner(::SymplecticGrassmann, p, X, Y) - -Compute the Riemannian inner product ``g^{\mathrm{SpGr}}_p(X,Y)``, where ``p`` -is a point on the [`SymplecticStiefel`](@ref) manifold and ``X,Y \in \mathrm{Hor}_p^Ο€\operatorname{SpSt}(2n,2k)`` -are horizontal tangent vectors. The formula reads according to Proposition Lemma 4.8 [BendokatZimmermann:2021](@cite). - -```math -g^{\mathrm{SpGr}}_p(X,Y) = \operatorname{tr}\bigl( - (p^{\mathrm{T}}p)^{-1}X^{\mathrm{T}}(I_{2n} - pp^+)Y - \bigr), -``` -where ``I_{2n}`` denotes the identity matrix and ``(β‹…)^+`` the [`symplectic_inverse`](@ref). -""" -function inner(M::SymplecticGrassmann, p, X, Y) - n, k = get_parameter(M.size) - J = SymplecticElement(p, X, Y) # in BZ21 also J - # Procompute lu(p'p) since we solve a^{-1}* 3 times - a = lu(p' * p) # note that p'p is symmetric, thus so is its inverse c=a^{-1} - # we split the original trace into two one with I -> (X'Yc) - # 1) we permute X' and Y c to c^{\mathrm{T}}Y^{\mathrm{T}}X = a\(Y'X) (avoids a large interims matrix) - # 2) the second we compute as c (X'p)(p^+Y) since both brackets are the smaller matrices - return tr(a \ (Y' * X)) - tr( - a \ ((X' * p) * symplectic_inverse_times(SymplecticStiefel(2 * n, 2 * k), p, Y)), - ) -end - @doc raw""" manifold_dimension(::SymplecticGrassmann) diff --git a/src/manifolds/SymplecticGrassmannProjector.jl b/src/manifolds/SymplecticGrassmannProjector.jl index 150959afcb..933e529594 100644 --- a/src/manifolds/SymplecticGrassmannProjector.jl +++ b/src/manifolds/SymplecticGrassmannProjector.jl @@ -70,3 +70,21 @@ function check_vector( ) end end + +embed!(::SymplecticGrassmann, q, p::ProjectorPoint) = copyto!(q, p.value) +function embed!(::SymplecticGrassmann, Y, p::ProjectorPoint, X::ProjectorTVector) + return copyto!(Y, X.value) +end +embed(::SymplecticGrassmann, p::ProjectorPoint) = p.value +embed(::SymplecticGrassmann, p::ProjectorPoint, X::ProjectorTVector) = X.value + +function get_embedding( + ::SymplecticGrassmann{TypeParameter{Tuple{n,k}},𝔽}, + p::ProjectorPoint, +) where {n,k,𝔽} + return Euclidean(2n, 2n; field=𝔽) +end +function get_embedding(M::SymplecticGrassmann{Tuple{Int,Int},𝔽}, ::ProjectorPoint) where {𝔽} + n, _ = get_parameter(M.size) + return Euclidean(2n, 2n; field=𝔽, parameter=:field) +end diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index b29e73823c..caf6fde336 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -62,6 +62,33 @@ function get_embedding(M::SymplecticGrassmann{Tuple{Int,Int},𝔽}) where {𝔽} return SymplecticStiefel(2n, 2k, 𝔽; parameter=:field) end +@doc raw""" + inner(::SymplecticGrassmann, p, X, Y) + +Compute the Riemannian inner product ``g^{\mathrm{SpGr}}_p(X,Y)``, where ``p`` +is a point on the [`SymplecticStiefel`](@ref) manifold and ``X,Y \in \mathrm{Hor}_p^Ο€\operatorname{SpSt}(2n,2k)`` +are horizontal tangent vectors. The formula reads according to Proposition Lemma 4.8 [BendokatZimmermann:2021](@cite). + +```math +g^{\mathrm{SpGr}}_p(X,Y) = \operatorname{tr}\bigl( + (p^{\mathrm{T}}p)^{-1}X^{\mathrm{T}}(I_{2n} - pp^+)Y + \bigr), +``` +where ``I_{2n}`` denotes the identity matrix and ``(β‹…)^+`` the [`symplectic_inverse`](@ref). +""" +function inner(M::SymplecticGrassmann, p, X, Y) + n, k = get_parameter(M.size) + J = SymplecticElement(p, X, Y) # in BZ21 also J + # Procompute lu(p'p) since we solve a^{-1}* 3 times + a = lu(p' * p) # note that p'p is symmetric, thus so is its inverse c=a^{-1} + # we split the original trace into two one with I -> (X'Yc) + # 1) we permute X' and Y c to c^{\mathrm{T}}Y^{\mathrm{T}}X = a\(Y'X) (avoids a large interims matrix) + # 2) the second we compute as c (X'p)(p^+Y) since both brackets are the smaller matrices + return tr(a \ (Y' * X)) - tr( + a \ ((X' * p) * symplectic_inverse_times(SymplecticStiefel(2 * n, 2 * k), p, Y)), + ) +end + @doc raw""" inverse_retract(::SymplecticGrassmann, p, q, ::CayleyInverseRetraction) inverse_retract!(::SymplecticGrassmann, q, p, X, ::CayleyInverseRetraction) From 4a149fc55f70421de714370e963b23770512b7bd Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 21 Jan 2024 17:55:36 +0100 Subject: [PATCH 37/65] add a few nicer functions to Hamiltonian and extend test coverage. --- src/Manifolds.jl | 1 + src/manifolds/Hamiltonian.jl | 29 ++++++++--- src/manifolds/SymplecticGrassmannStiefel.jl | 8 +-- test/manifolds/hamiltonian.jl | 54 +++++++++++++++++++++ test/manifolds/symplecticgrassmann.jl | 37 ++++++++++++++ test/runtests.jl | 1 + 6 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 test/manifolds/hamiltonian.jl diff --git a/src/Manifolds.jl b/src/Manifolds.jl index dc15b9187d..0ab1a05787 100644 --- a/src/Manifolds.jl +++ b/src/Manifolds.jl @@ -851,6 +851,7 @@ export Γ—, is_default_metric, is_flat, is_group_manifold, + is_hamiltonian, is_identity, is_point, is_vector, diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index c5cf09c138..3f5e02462d 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -28,6 +28,24 @@ function Matrix(A::Hamiltonian) return copy(A.value) end +Base.:*(H::Hamiltonian, K::Hamiltonian) = Hamiltonian(H.value * K.value) +Base.:*(H::Hamiltonian, A::AbstractMatrix) = H.value * A +Base.:*(A::AbstractMatrix, K::Hamiltonian) = A * K.value +Base.:+(H::Hamiltonian, K::Hamiltonian) = Hamiltonian(H.value .+ K.value) +Base.:+(H::Hamiltonian, A::AbstractMatrix) = H.value .+ A +Base.:+(A::AbstractMatrix, K::Hamiltonian) = A .+ K.value +Base.:-(H::Hamiltonian, K::Hamiltonian) = Hamiltonian(H.value .- K.value) +Base.:-(H::Hamiltonian, A::AbstractMatrix) = H.value .- A +Base.:-(A::AbstractMatrix, K::Hamiltonian) = A .- K.value + +function show(io::IO, A::Hamiltonian) + return print(io, "Hamiltonian($(A.value))") +end +function show(io::IO, ::MIME"text/plain", A::Hamiltonian) + return print(io, "Hamiltonian($(A.value))") +end +size(A::Hamiltonian) = size(A.value) + @doc raw""" HamiltonianMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} @@ -75,6 +93,9 @@ Compute the [`symplectic_inverse`](@ref) of a Hamiltonian (A) function ^(A::Hamiltonian, ::typeof(+)) return Hamiltonian(symplectic_inverse(A.value)) end +function symplectic_inverse(A::Hamiltonian) + return Hamiltonian(symplectic_inverse(A.value)) +end @doc raw""" check_point(M::HamiltonianMatrices{n,𝔽}, p; kwargs...) @@ -150,17 +171,13 @@ function is_hamiltonian(A::Hamiltonian; kwargs...) return isapprox((A^+).value, -A.value; kwargs...) end -function show(io::IO, ::MIME"text/plain", A::Hamiltonian) - return print(io, "Hamiltonian($(A.value))") -end function Base.show(io::IO, ::HamiltonianMatrices{TypeParameter{Tuple{n}},F}) where {n,F} - return print(io, "HamiltonianMatrices($(n), $(F))") + return print(io, "HamiltonianMatrices($(2n), $(F))") end function Base.show(io::IO, M::HamiltonianMatrices{Tuple{Int},F}) where {F} n = get_parameter(M.size)[1] - return print(io, "HamiltonianMatrices($(n), $(F); parameter=:field)") + return print(io, "HamiltonianMatrices($(2n), $(F); parameter=:field)") end -size(A::Hamiltonian) = size(A.value) @doc raw""" p = rand(M::HamiltonianMatrices; Οƒ::Real=1.0, vector_at=nothing) diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index caf6fde336..566fd5119b 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -138,12 +138,12 @@ Then the Riemannian gradient ``X = \operatorname{grad} f(p)`` is given by where ``J_{2n}`` denotes the [`SymplecticElement`](@ref), and ``H = (I_{2n} - pp^+)J_{2n}^{\mathrm{T}}YJ``. """ -function riemannian_gradient(::SymplecticGrassmann, p, Y; kwargs...) +function riemannian_gradient(M::SymplecticGrassmann, p, Y; kwargs...) n, k = get_parameter(M.size) - J = SymplecticElement(p, X) + J = SymplecticElement(p) # Since J' = -J We can write (J'YJ) = -J * (YJ) JTYJ = (-J * (Y * J)) - H = (I - symplectic_inverse_times(SymplecticStiefel(2 * n, 2 * k), p, p)) * JTYJ + H = (I - p * symplectic_inverse(p)) * JTYJ return (-J * (H * J)) * (p' * p) .- JTYJ * (H' * p) end @@ -152,7 +152,7 @@ function riemannian_gradient!(M::SymplecticGrassmann, X, p, Y; kwargs...) J = SymplecticElement(p, X) # Since J' = -J We can write (J'YJ) = -J * (YJ) JTYJ = (-J * (Y * J)) - H = (I - symplectic_inverse_times(SymplecticStiefel(2 * n, 2 * k), p, p)) * JTYJ + H = (I - p * symplectic_inverse(p)) * JTYJ X .= (-J * (H * J)) * (p' * p) .- JTYJ * (H' * p) return X end diff --git a/test/manifolds/hamiltonian.jl b/test/manifolds/hamiltonian.jl new file mode 100644 index 0000000000..27b6c9d38f --- /dev/null +++ b/test/manifolds/hamiltonian.jl @@ -0,0 +1,54 @@ +include("../header.jl") + +@testset "Hamiltonian matrices" begin + M = HamiltonianMatrices(4) + Mf = HamiltonianMatrices(4; parameter=:field) + # A has to be of the Form JS, S symmetric + p = + SymplecticElement(1.0) * [ + 1.0 2.0 0.0 0.0 + 2.0 3.0 0.0 0.0 + 0.0 0.0 1.0 0.0 + 0.0 0.0 0.0 4.0 + ] + q = + SymplecticElement(1.0) * [ + 4.0 3.0 0.0 0.0 + 3.0 2.0 0.0 0.0 + 0.0 0.0 4.0 0.0 + 0.0 0.0 0.0 1.0 + ] + @testset "Hamiltonian" begin + @test is_hamiltonian(p) + pH = Hamiltonian(p) + @test is_hamiltonian(pH) + @test Hamiltonian(pH) === pH + @test startswith("$(pH)", "Hamiltonian([") + @test size(pH) == size(p) + @test (pH^+).value == symplectic_inverse(p) + @test symplectic_inverse(pH).value == symplectic_inverse(p) + qH = Hamiltonian(q) + pqH = pH * qH + @test pqH isa Hamiltonian + @test pqH.value == p * q + @test pH * q == p * q + @test p * qH == p * q + pqH2 = pH + qH + @test pqH2 isa Hamiltonian + @test pqH2.value == p + q + @test pH + q == p + q + @test p + qH == p + q + end + @testset "Basics" begin + @test repr(M) == "HamiltonianMatrices(4, ℝ)" + @test repr(Mf) == "HamiltonianMatrices(4, ℝ; parameter=:field)" + @test is_point(M, p) + @test is_point(M, Hamiltonian(p)) + @test is_vector(M, p, p) + @test get_embedding(M) == Euclidean(4, 4; field=ℝ) + @test get_embedding(Mf) == Euclidean(4, 4; field=ℝ, parameter=:field) + @test is_flat(M) + Random.seed!(42) + is_point(M, rand(M)) + end +end diff --git a/test/manifolds/symplecticgrassmann.jl b/test/manifolds/symplecticgrassmann.jl index 07bebe0ecb..54c294c629 100644 --- a/test/manifolds/symplecticgrassmann.jl +++ b/test/manifolds/symplecticgrassmann.jl @@ -43,5 +43,42 @@ include("../header.jl") @test is_point(M, p) @test is_vector(_M, p, X) end + @test get_embedding(M) == SymplecticStiefel(6, 4) + end + @testset "Embedding / Total Space" begin + @test get_embedding(M) == SymplecticStiefel(6, 4) + pE = similar(p) + embed!(M, pE, p) + @test p == pE + embed!(M, pE, StiefelPoint(p)) + @test p == pE + @test embed(M, StiefelPoint(p)) == p + XE = similar(X) + embed!(M, XE, p, X) + @test XE == X + embed!(M, XE, StiefelPoint(p), StiefelTVector(X)) + @test XE == X + @test embed(M, StiefelPoint(p), StiefelTVector(X)) == X + end + @testset "Expnential and Retractions" begin + @test inner(M, p, X, X) == norm(M, p, X)^2 + N = get_embedding(M) + @test isapprox(N, exp(M, p, X), exp(N, p, X)) + rtm = CayleyRetraction() + r = retract(M, p, X, rtm) + @test is_point(M, r) + irtm = CayleyInverseRetraction() + X2 = inverse_retract(M, p, r, irtm) + @test isapprox(M, p, X, X2) + @test is_vector(M, p, X2) + end + @testset "Riemannian Gradient conversion" begin + A = Matrix{Float64}(I, 6, 6)[:, 1:4] + Z = riemannian_gradient(M, p, A) + Z2 = similar(Z) + riemannian_gradient!(M, Z2, p, A) + @test isapprox(M, Z2, Z) + # How can we better test that this is a correct gradient? + # Or what can we further test here? end end diff --git a/test/runtests.jl b/test/runtests.jl index a96ea13f23..bc740b3112 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -149,6 +149,7 @@ end include_test("manifolds/generalized_grassmann.jl") include_test("manifolds/generalized_stiefel.jl") include_test("manifolds/grassmann.jl") + include_test("manifolds/hamiltonian.jl") include_test("manifolds/hyperbolic.jl") include_test("manifolds/lorentz.jl") include_test("manifolds/multinomial_doubly_stochastic.jl") From ef55fa7bc581f766f085cf6ad28eadc79c8f536d Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 21 Jan 2024 19:02:03 +0100 Subject: [PATCH 38/65] Mixinf Hamiltonian with other matrices introduces 120+ ambiguities, let's not do that. --- src/manifolds/Hamiltonian.jl | 6 ------ src/manifolds/SymplecticStiefel.jl | 2 +- test/ambiguities.jl | 3 ++- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index 3f5e02462d..5bcdcf7b50 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -29,14 +29,8 @@ function Matrix(A::Hamiltonian) end Base.:*(H::Hamiltonian, K::Hamiltonian) = Hamiltonian(H.value * K.value) -Base.:*(H::Hamiltonian, A::AbstractMatrix) = H.value * A -Base.:*(A::AbstractMatrix, K::Hamiltonian) = A * K.value Base.:+(H::Hamiltonian, K::Hamiltonian) = Hamiltonian(H.value .+ K.value) -Base.:+(H::Hamiltonian, A::AbstractMatrix) = H.value .+ A -Base.:+(A::AbstractMatrix, K::Hamiltonian) = A .+ K.value Base.:-(H::Hamiltonian, K::Hamiltonian) = Hamiltonian(H.value .- K.value) -Base.:-(H::Hamiltonian, A::AbstractMatrix) = H.value .- A -Base.:-(A::AbstractMatrix, K::Hamiltonian) = A .- K.value function show(io::IO, A::Hamiltonian) return print(io, "Hamiltonian($(A.value))") diff --git a/src/manifolds/SymplecticStiefel.jl b/src/manifolds/SymplecticStiefel.jl index 2a5d481a32..33ea6776b5 100644 --- a/src/manifolds/SymplecticStiefel.jl +++ b/src/manifolds/SymplecticStiefel.jl @@ -110,7 +110,7 @@ Check whether `p` is a valid point on the [`SymplecticStiefel`](@ref), ``\mathrm{SpSt}(2n, 2k)`` manifold, that is ``p^{+}p`` is the identity, ``(β‹…)^+`` denotes the [`symplectic_inverse`](@ref). """ -function check_point(M::SymplecticStiefel{<:Any,ℝ}, p::T; kwargs...) where {T} +function check_point(M::SymplecticStiefel{<:Any,ℝ}, p; kwargs...) # Perform check that the matrix lives on the real symplectic manifold: if !isapprox(inv(M, p) * p, I; kwargs...) return DomainError( diff --git a/test/ambiguities.jl b/test/ambiguities.jl index bd61a4cc77..4214a4feff 100644 --- a/test/ambiguities.jl +++ b/test/ambiguities.jl @@ -1,3 +1,4 @@ +include("header.jl") """ has_type_in_signature(sig, T::Type) @@ -11,7 +12,7 @@ function has_type_in_signature(sig, T::Type) end @testset "Ambiguities" begin - if VERSION.prerelease == () && !Sys.iswindows() && VERSION < v"1.10.0" + if VERSION.prerelease == () && !Sys.iswindows() && VERSION < v"1.11.0" mbs = Test.detect_ambiguities(ManifoldsBase) # Interims solution until we follow what was proposed in # https://discourse.julialang.org/t/avoid-ambiguities-with-individual-number-element-identity/62465/2 From e4015abe013679f368be7626208d98d1472837f8 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 21 Jan 2024 19:11:14 +0100 Subject: [PATCH 39/65] Forgot to remove the mixed tests. Brain is melting. --- test/manifolds/hamiltonian.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/manifolds/hamiltonian.jl b/test/manifolds/hamiltonian.jl index 27b6c9d38f..e39c3245ac 100644 --- a/test/manifolds/hamiltonian.jl +++ b/test/manifolds/hamiltonian.jl @@ -31,13 +31,9 @@ include("../header.jl") pqH = pH * qH @test pqH isa Hamiltonian @test pqH.value == p * q - @test pH * q == p * q - @test p * qH == p * q pqH2 = pH + qH @test pqH2 isa Hamiltonian @test pqH2.value == p + q - @test pH + q == p + q - @test p + qH == p + q end @testset "Basics" begin @test repr(M) == "HamiltonianMatrices(4, ℝ)" From 09202d0e45567e8e4a825826eece3fa4bf1d7b35 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 21 Jan 2024 20:58:57 +0100 Subject: [PATCH 40/65] fix a too strict test. --- test/manifolds/symplecticgrassmann.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/manifolds/symplecticgrassmann.jl b/test/manifolds/symplecticgrassmann.jl index 54c294c629..2ea88d75b0 100644 --- a/test/manifolds/symplecticgrassmann.jl +++ b/test/manifolds/symplecticgrassmann.jl @@ -61,7 +61,7 @@ include("../header.jl") @test embed(M, StiefelPoint(p), StiefelTVector(X)) == X end @testset "Expnential and Retractions" begin - @test inner(M, p, X, X) == norm(M, p, X)^2 + @test inner(M, p, X, X) β‰ˆ norm(M, p, X)^2 N = get_embedding(M) @test isapprox(N, exp(M, p, X), exp(N, p, X)) rtm = CayleyRetraction() From b1548bb84d877ff2dd84392d24e17bcb239f9e60 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Sun, 21 Jan 2024 21:52:13 +0100 Subject: [PATCH 41/65] MOre tst coverage. --- src/manifolds/Hamiltonian.jl | 4 ++-- test/manifolds/hamiltonian.jl | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index 5bcdcf7b50..5cb21cf748 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -102,7 +102,7 @@ The tolerance for the test of `p` can be set using `kwargs...`. function check_point(M::HamiltonianMatrices, p; kwargs...) if !is_hamiltonian(p; kwargs...) return DomainError( - norm((Hamiltonian(p)^+) + p), + norm((Hamiltonian(p)^+).value + p), "The point $(p) does not lie on $M, since it is not hamiltonian.", ) end @@ -119,7 +119,7 @@ The tolerance for [`is_hamiltonian`](@ref) `X` can be set using `kwargs...`. function check_vector(M::HamiltonianMatrices, p, X; kwargs...) if !is_hamiltonian(X; kwargs...) return DomainError( - norm((Hamiltonian(X)^+) + X), + norm((Hamiltonian(X)^+).value + X), "The vector $(X) is not a tangent vector to $(p) on $(M), since it is not hamiltonian.", ) end diff --git a/test/manifolds/hamiltonian.jl b/test/manifolds/hamiltonian.jl index e39c3245ac..9062a7c678 100644 --- a/test/manifolds/hamiltonian.jl +++ b/test/manifolds/hamiltonian.jl @@ -34,6 +34,11 @@ include("../header.jl") pqH2 = pH + qH @test pqH2 isa Hamiltonian @test pqH2.value == p + q + pqH3 = pH - qH + @test pqH3 isa Hamiltonian + @test pqH3.value == p - q + @test_throws DomainError is_point(M, ones(4, 4), true) + @test_throws DomainError is_vector(M, p, ones(4, 4), true, true) end @testset "Basics" begin @test repr(M) == "HamiltonianMatrices(4, ℝ)" From 1ed51cb7ca414934cd88951192b77df876d44c7e Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 22 Jan 2024 19:15:14 +0100 Subject: [PATCH 42/65] A bit of testcoverage --- src/manifolds/SymplecticGrassmann.jl | 4 +- src/manifolds/SymplecticGrassmannProjector.jl | 2 +- test/manifolds/symplecticgrassmann.jl | 43 ++++++++++++++++++- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 0e56b84108..52c5cdea6f 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -90,11 +90,11 @@ function manifold_dimension(M::SymplecticGrassmann{<:Any,ℝ}) end function Base.show(io::IO, ::SymplecticGrassmann{TypeParameter{Tuple{n,k}},𝔽}) where {n,k,𝔽} - return print(io, "SymplecticStiefel($(2n), $(2k); field=$(𝔽))") + return print(io, "SymplecticGrassmann($(2n), $(2k); field=$(𝔽))") end function Base.show(io::IO, M::SymplecticGrassmann{Tuple{Int,Int},𝔽}) where {𝔽} n, k = get_parameter(M.size) - return print(io, "SymplecticStiefel($(2n), $(2k); field=$(𝔽); parameter=:field)") + return print(io, "SymplecticGrassmann($(2n), $(2k); field=$(𝔽); parameter=:field)") end # diff --git a/src/manifolds/SymplecticGrassmannProjector.jl b/src/manifolds/SymplecticGrassmannProjector.jl index 933e529594..8bfe216072 100644 --- a/src/manifolds/SymplecticGrassmannProjector.jl +++ b/src/manifolds/SymplecticGrassmannProjector.jl @@ -54,7 +54,7 @@ function check_vector( n, k = get_parameter(M.size) if !is_hamiltonian(X.value; kwargs...) return DomainError( - norm((Hamiltonian(X.value)^+) + X.value), + norm((Hamiltonian(X.value)^+).value + X.value), ( "The matrix X is not in the tangent space at $p of $M, since X is not Hamiltonian." ), diff --git a/test/manifolds/symplecticgrassmann.jl b/test/manifolds/symplecticgrassmann.jl index 2ea88d75b0..30561fc4b5 100644 --- a/test/manifolds/symplecticgrassmann.jl +++ b/test/manifolds/symplecticgrassmann.jl @@ -36,8 +36,8 @@ include("../header.jl") -0.02823014 0.00029946 -0.04196034 -0.04145413 ] @testset "Basics" begin - @test repr(M) == "SymplecticStiefel(6, 4; field=ℝ)" - @test repr(Mf) == "SymplecticStiefel(6, 4; field=ℝ; parameter=:field)" + @test repr(M) == "SymplecticGrassmann(6, 4; field=ℝ)" + @test repr(Mf) == "SymplecticGrassmann(6, 4; field=ℝ; parameter=:field)" @test manifold_dimension(M) == 4 * (6 - 4) for _M in [M, Mf] @test is_point(M, p) @@ -81,4 +81,43 @@ include("../header.jl") # How can we better test that this is a correct gradient? # Or what can we further test here? end + @testset "Projector representation" begin + # cf. Propo 4.3 BendokatZimmermann, Ο† and + Ο†(p) = p * symplectic_inverse(p) + # for dΟ† the proof we keve to consider their Ξ©, hence the /p + function dΟ†(p, X) + # This still needs to be fixed + p_plus = symplectic_inverse(p) + X_plus = symplectic_inverse(p) + A = (I - 0.5 * p * p_plus) + Ξ© = A * X * p_plus - p * X_plus * A + P = Ο†(p) + Ξ©bar = Ξ© * P + P * Ξ© - 2 * P * Ξ© * P # From the representation discussion before + return Ξ©bar + end + pP = ProjectorPoint(Ο†(p)) + XP = ProjectorTVector(dΟ†(p, X)) + @test is_point(M, pP) + # Fix + @test_broken is_vector(M, pP, XP) + Pf1 = zeros(6, 6) + Pf1[1, 2] = 1.0 + # No projector + @test_throws DomainError is_point(M, ProjectorPoint(Pf1), true) + Pf2 = zeros(6, 6) + Pf2[1, 1] = 1.0 + # Pf2 not equal to its symplectic inverse + @test_throws DomainError is_point(M, ProjectorPoint(Pf1), true) + # Missing: Rank test, maybe best with a p from SpSt(6,2)? + + @test get_embedding(M, pP) == Euclidean(6, 6) + get_embedding(Mf, pP) == Euclidean(6, 6; parameter=:field) + @test embed(M, pP) == pP.value + pE = zeros(6, 6) + embed!(M, pE, pP) + @test pE == pP.value + @test embed(M, pP, XP) == XP.value + embed!(M, pE, pP, XP) + @test pE == XP.value + end end From bece83a2acbd025b3807b07b9609decffe4bf141 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Mon, 22 Jan 2024 19:31:25 +0100 Subject: [PATCH 43/65] Maybe increase test cov. --- src/manifolds/Hamiltonian.jl | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index 5cb21cf748..e64e176da5 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -35,9 +35,6 @@ Base.:-(H::Hamiltonian, K::Hamiltonian) = Hamiltonian(H.value .- K.value) function show(io::IO, A::Hamiltonian) return print(io, "Hamiltonian($(A.value))") end -function show(io::IO, ::MIME"text/plain", A::Hamiltonian) - return print(io, "Hamiltonian($(A.value))") -end size(A::Hamiltonian) = size(A.value) @doc raw""" From 324c791b93e647264b7083e52a61c81c1a2d8689 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 23 Jan 2024 08:35:41 +0100 Subject: [PATCH 44/65] This should finish code coverage up to one final line, a valid ProjectorTVector. --- src/manifolds/SymplecticGrassmannProjector.jl | 4 ++-- test/manifolds/symplecticgrassmann.jl | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/manifolds/SymplecticGrassmannProjector.jl b/src/manifolds/SymplecticGrassmannProjector.jl index 8bfe216072..b9f93df7d9 100644 --- a/src/manifolds/SymplecticGrassmannProjector.jl +++ b/src/manifolds/SymplecticGrassmannProjector.jl @@ -14,7 +14,7 @@ function check_point(M::SymplecticGrassmann, p::ProjectorPoint; kwargs...) if !isapprox(c, p.value; kwargs...) return DomainError( norm(c - p.value), - "The point $(p) is not equal to its square $c, so it does not lie on $M.", + "The poin $(p) is not equal to its square $c, so it does not lie on $M.", ) end if !isapprox(p.value, symplectic_inverse(p.value); kwargs...) @@ -65,7 +65,7 @@ function check_vector( return DomainError( norm(XppX - X.value), ( - "The matrix X is not in the tangent space at $p of $M, since X is not Hamiltonian." + "The matrix X is not in the tangent space at $p of $M, since X is not equal to Xp + pX." ), ) end diff --git a/test/manifolds/symplecticgrassmann.jl b/test/manifolds/symplecticgrassmann.jl index 30561fc4b5..ce99c25360 100644 --- a/test/manifolds/symplecticgrassmann.jl +++ b/test/manifolds/symplecticgrassmann.jl @@ -107,8 +107,18 @@ include("../header.jl") Pf2 = zeros(6, 6) Pf2[1, 1] = 1.0 # Pf2 not equal to its symplectic inverse - @test_throws DomainError is_point(M, ProjectorPoint(Pf1), true) - # Missing: Rank test, maybe best with a p from SpSt(6,2)? + @test_throws DomainError is_point(M, ProjectorPoint(Pf2), true) + # Missing: Rank test, maybe best with a p from SpSt(6,2) + ps = p[:, [1, 3]] # This is on SpSt(6,2) + Pf3 = Ο†(ps) # too low rank + @test_throws DomainError is_point(M, ProjectorPoint(Pf3), true) + + # Not Hamiltonian + Xf1 = ProjectorTVector(Matrix{Float64}(I, 6, 6)) + @test_throws DomainError is_vector(M, pP, Xf1; error=:error) + # Hamiltonian but Xp + pX not correct + Xf2 = ProjectorTVector(SymplecticElement(1.0) * Matrix{Float64}(I, 6, 6)) + @test_throws DomainError is_vector(M, pP, Xf2; error=:error) @test get_embedding(M, pP) == Euclidean(6, 6) get_embedding(Mf, pP) == Euclidean(6, 6; parameter=:field) From 1a21e9b81bdf2d91b4cc700e3dd189a4316de7f6 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 23 Jan 2024 09:25:49 +0100 Subject: [PATCH 45/65] Add a line for the case that the vector is correct to return nothing. --- src/manifolds/SymplecticGrassmannProjector.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/manifolds/SymplecticGrassmannProjector.jl b/src/manifolds/SymplecticGrassmannProjector.jl index b9f93df7d9..a75d6fb171 100644 --- a/src/manifolds/SymplecticGrassmannProjector.jl +++ b/src/manifolds/SymplecticGrassmannProjector.jl @@ -69,6 +69,7 @@ function check_vector( ), ) end + return nothing end embed!(::SymplecticGrassmann, q, p::ProjectorPoint) = copyto!(q, p.value) From 2f438e21ee40f195ee26bbce6e6627b05e7a3bc4 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Tue, 23 Jan 2024 18:38:56 +0100 Subject: [PATCH 46/65] Checking a new formula for the conversion, still have to debug this. --- test/manifolds/symplecticgrassmann.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/manifolds/symplecticgrassmann.jl b/test/manifolds/symplecticgrassmann.jl index ce99c25360..59bc83a148 100644 --- a/test/manifolds/symplecticgrassmann.jl +++ b/test/manifolds/symplecticgrassmann.jl @@ -86,13 +86,13 @@ include("../header.jl") Ο†(p) = p * symplectic_inverse(p) # for dΟ† the proof we keve to consider their Ξ©, hence the /p function dΟ†(p, X) - # This still needs to be fixed - p_plus = symplectic_inverse(p) - X_plus = symplectic_inverse(p) - A = (I - 0.5 * p * p_plus) - Ξ© = A * X * p_plus - p * X_plus * A - P = Ο†(p) - Ξ©bar = Ξ© * P + P * Ξ© - 2 * P * Ξ© * P # From the representation discussion before + # Following (3.15) - this has still to be debugged + pTp = lu(p' * p) + pTp_I_pT = pTp \ (p') + J2n = Matrix{Float64}(I, 6, 6) * (SymplecticElement(1.0)) + Ξ©bar = + X * pTp_I_pT + + J2n * p * (pTp \ (X')) * (I - J2n' * p * pTp_I_pT * J2n) * J2n return Ξ©bar end pP = ProjectorPoint(Ο†(p)) From 195835789094c0339529475131c4b9bba3eff12e Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 11:47:18 +0100 Subject: [PATCH 47/65] Fix a test, --- src/manifolds/SymplecticGrassmannProjector.jl | 8 ++++---- test/manifolds/symplecticgrassmann.jl | 13 +++---------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/manifolds/SymplecticGrassmannProjector.jl b/src/manifolds/SymplecticGrassmannProjector.jl index a75d6fb171..8a9235a3de 100644 --- a/src/manifolds/SymplecticGrassmannProjector.jl +++ b/src/manifolds/SymplecticGrassmannProjector.jl @@ -39,7 +39,7 @@ end Check whether `X` is a valid tangent vector at `p` on the [`SymplecticGrassmann`](@ref), ``\operatorname{SpGr}(2n, 2k)`` manifold by verifying that it -* ``X^+ = -X``, verify that `X` is [`Hamiltonian`](@ref) +* ``X^+ = X`` * ``X = Xp + pX`` For details see Proposition 4.2 in [BendokatZimmermann:2021](@cite) and the definition of ``\mathfrak{sp}_P(2n)`` before, @@ -52,11 +52,11 @@ function check_vector( kwargs..., ) n, k = get_parameter(M.size) - if !is_hamiltonian(X.value; kwargs...) + if !isapprox((Hamiltonian(X.value)^+).value, X.value; kwargs...) return DomainError( - norm((Hamiltonian(X.value)^+).value + X.value), + norm((Hamiltonian(X.value)^+).value - X.value), ( - "The matrix X is not in the tangent space at $p of $M, since X is not Hamiltonian." + "The matrix X is not in the tangent space at $p of $M, since X is not equal to ist symplectic inverse." ), ) end diff --git a/test/manifolds/symplecticgrassmann.jl b/test/manifolds/symplecticgrassmann.jl index 59bc83a148..8569538d8b 100644 --- a/test/manifolds/symplecticgrassmann.jl +++ b/test/manifolds/symplecticgrassmann.jl @@ -86,20 +86,14 @@ include("../header.jl") Ο†(p) = p * symplectic_inverse(p) # for dΟ† the proof we keve to consider their Ξ©, hence the /p function dΟ†(p, X) - # Following (3.15) - this has still to be debugged - pTp = lu(p' * p) - pTp_I_pT = pTp \ (p') - J2n = Matrix{Float64}(I, 6, 6) * (SymplecticElement(1.0)) - Ξ©bar = - X * pTp_I_pT + - J2n * p * (pTp \ (X')) * (I - J2n' * p * pTp_I_pT * J2n) * J2n - return Ξ©bar + # \bar Ξ© is Xp^+ + pX^+ + return X * symplectic_inverse(p) + p * symplectic_inverse(X) end pP = ProjectorPoint(Ο†(p)) XP = ProjectorTVector(dΟ†(p, X)) @test is_point(M, pP) # Fix - @test_broken is_vector(M, pP, XP) + @test is_vector(M, pP, XP; atol=1e-9, error=:error) Pf1 = zeros(6, 6) Pf1[1, 2] = 1.0 # No projector @@ -108,7 +102,6 @@ include("../header.jl") Pf2[1, 1] = 1.0 # Pf2 not equal to its symplectic inverse @test_throws DomainError is_point(M, ProjectorPoint(Pf2), true) - # Missing: Rank test, maybe best with a p from SpSt(6,2) ps = p[:, [1, 3]] # This is on SpSt(6,2) Pf3 = Ο†(ps) # too low rank @test_throws DomainError is_point(M, ProjectorPoint(Pf3), true) From b986b8b2201dc93ef0181eefe6cc4d1ae6671fc4 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 14:57:30 +0100 Subject: [PATCH 48/65] =?UTF-8?q?finish=20tests.=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/manifolds/symplecticgrassmann.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/manifolds/symplecticgrassmann.jl b/test/manifolds/symplecticgrassmann.jl index 8569538d8b..8bd7f1f1cf 100644 --- a/test/manifolds/symplecticgrassmann.jl +++ b/test/manifolds/symplecticgrassmann.jl @@ -90,7 +90,8 @@ include("../header.jl") return X * symplectic_inverse(p) + p * symplectic_inverse(X) end pP = ProjectorPoint(Ο†(p)) - XP = ProjectorTVector(dΟ†(p, X)) + Xe = dΟ†(p, X) + XP = ProjectorTVector(Xe) @test is_point(M, pP) # Fix @test is_vector(M, pP, XP; atol=1e-9, error=:error) @@ -109,10 +110,9 @@ include("../header.jl") # Not Hamiltonian Xf1 = ProjectorTVector(Matrix{Float64}(I, 6, 6)) @test_throws DomainError is_vector(M, pP, Xf1; error=:error) - # Hamiltonian but Xp + pX not correct - Xf2 = ProjectorTVector(SymplecticElement(1.0) * Matrix{Float64}(I, 6, 6)) + # X^+ = X, but Xp + pX not correct + Xf2 = ProjectorTVector(0.5 .* (symplectic_inverse(X * X') + X * X')) @test_throws DomainError is_vector(M, pP, Xf2; error=:error) - @test get_embedding(M, pP) == Euclidean(6, 6) get_embedding(Mf, pP) == Euclidean(6, 6; parameter=:field) @test embed(M, pP) == pP.value From db2ce47268f6979ca2cbdad01b069671b9c09754 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 15:04:32 +0100 Subject: [PATCH 49/65] Apply suggestions from code review Co-authored-by: Mateusz Baran --- docs/src/manifolds/symplectic.md | 2 +- src/manifolds/Hamiltonian.jl | 2 +- src/manifolds/QuotientManifold.jl | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/src/manifolds/symplectic.md b/docs/src/manifolds/symplectic.md index 6fcd5e3967..4a3e9a68de 100644 --- a/docs/src/manifolds/symplectic.md +++ b/docs/src/manifolds/symplectic.md @@ -29,7 +29,7 @@ Algebra \mathfrak{sp}(2n,F) = \{H \in 𝔽^{2nΓ—2n} \;|\; Q H + H^{T} Q = 0\}. ```` This set is also known as the [Hamiltonian matrices](https://en.wikipedia.org/wiki/Hamiltonian_matrix), which have the -property that $(QH)^T = QH`` and are commonly used in physics. +property that ``(QH)^T = QH`` and are commonly used in physics. ```@autodocs Modules = [Manifolds] diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index e64e176da5..246fa64ebe 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -25,7 +25,7 @@ end Hamiltonian(A::Hamiltonian) = Hamiltonian(A.value) # Conversion function Matrix(A::Hamiltonian) - return copy(A.value) + return Matrix(A.value) end Base.:*(H::Hamiltonian, K::Hamiltonian) = Hamiltonian(H.value * K.value) diff --git a/src/manifolds/QuotientManifold.jl b/src/manifolds/QuotientManifold.jl index 9ac2aa1873..c7e5467df5 100644 --- a/src/manifolds/QuotientManifold.jl +++ b/src/manifolds/QuotientManifold.jl @@ -159,7 +159,7 @@ horizontal_lift!(N::AbstractManifold, Y, q, X) @doc raw""" horizontal_component(N::AbstractManifold, p, X) - horizontal_compontent(QuotientManifold{M,N}, p, X) + horizontal_compontent(QuotientManifold{𝔽,M,N}, p, X) Compute the horizontal component of tangent vector `X` at point `p` in the total space of quotient manifold `N`. @@ -177,7 +177,7 @@ end @doc raw""" vertical_component(N::AbstractManifold, p, X) - vertical_component(QuotientManifold{M,N}, p, X) + vertical_component(QuotientManifold{𝔽,M,N}, p, X) Compute the vertical component of tangent vector `X` at point `p` in the total space of quotient manifold `N`. From c2b71bcf2c697ba5042fbe589c2a9dcaaf6812aa Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 15:29:15 +0100 Subject: [PATCH 50/65] Fiinalise PR by fixing rand on Hamiltonian and update the docs for SpGr. --- src/manifolds/Hamiltonian.jl | 2 +- src/manifolds/SymplecticGrassmann.jl | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index 246fa64ebe..0eb4802200 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -205,6 +205,6 @@ function rand!( randn!(rng, p3) p2 .= (1 / 2) .* (p2 .+ p2') p3 .= (1 / 2) .* (p2 .+ p2') - pX .= (Οƒ / norm(pX, 2)) .* pX + pX .*= Οƒ return pX end diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 52c5cdea6f..f81ff0a06a 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -36,12 +36,28 @@ representation as projectors, using a [`ProjectorTVector`](@ref) as ``` where ``[X,p] = Xp-pX`` denotes the matrix commutator and -``\mathfrak{sp}(2n,ℝ)`` is the Lie algebra of the symplectic group consisting of [`HamiltonianMatrices`](@ref) +``\mathfrak{sp}(2n,ℝ)`` is the Lie algebra of the symplectic group consisting of [`HamiltonianMatrices`](@ref). -For simplicity, the [`ProjectorTVector`](@ref) is stored as just ``X`` from the representation above. +The first repesentation is in [`StiefelPoints`](@ref) and [`StiefelTVectors`](@ref), +which both represent their symplectic Grassmann equivalence class. Arrays are interpreted +in this representation as well -For the tangent space, arrays are interpreted as being [`StiefelTVector`](@ref)s. +For the representation in [`ProjectorPoint`](@ref) and [`ProjectorTVector`](@ref)s, +we use the representation from the surjective submersion +```math +ρ: \mathrm{SpSt}(2n,2k) β†’ \mathrm{SpGr}(2n,2k), +\qquad +ρ(p) = pp^+ +``` + +and its differential + +```math +\mathrm{d}ρ(p,X) = Xp^+ + pX^+, +``` + +respectively. The manifold was first introduced in [BendokatZimmermann:2021](@cite) # Constructor From bfac83e6387a75538d401f2371ddfa5db9e04d27 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 15:30:04 +0100 Subject: [PATCH 51/65] bump version. --- NEWS.md | 2 +- Project.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 24ae01b85c..d0e50a50f9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,7 +5,7 @@ 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.9.x] – 2024-01-22 +## [0.9.13] – 2024-01-24 ### Added diff --git a/Project.toml b/Project.toml index f0480b91b6..f70057a1d2 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.9.12" +version = "0.9.13" [deps] Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" From 6fb62878f04bd940c0c42bf69e9009694a9c2007 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 15:51:42 +0100 Subject: [PATCH 52/65] More $ -> `` (trying to remove the one warning from documenter but can't find it) --- src/groups/general_linear.jl | 4 +- src/groups/special_linear.jl | 4 +- src/manifolds/ProjectiveSpace.jl | 106 +++++++++++++-------------- src/manifolds/SkewHermitian.jl | 10 +-- src/manifolds/Sphere.jl | 56 +++++++------- src/manifolds/SymplecticGrassmann.jl | 2 +- src/statistics.jl | 6 +- 7 files changed, 94 insertions(+), 94 deletions(-) diff --git a/src/groups/general_linear.jl b/src/groups/general_linear.jl index 8f2f24d21b..da9abdc29e 100644 --- a/src/groups/general_linear.jl +++ b/src/groups/general_linear.jl @@ -268,11 +268,11 @@ function Random.rand!(rng::AbstractRNG, G::GeneralLinear, pX; kwargs...) end function Base.show(io::IO, ::GeneralLinear{TypeParameter{Tuple{n}},𝔽}) where {n,𝔽} - return print(io, "GeneralLinear($n, $𝔽)") + return print(io, "GeneralLinear($n, $(𝔽))") end function Base.show(io::IO, M::GeneralLinear{Tuple{Int},𝔽}) where {𝔽} n = get_parameter(M.size)[1] - return print(io, "GeneralLinear($n, $𝔽; parameter=:field)") + return print(io, "GeneralLinear($n, $(𝔽); parameter=:field)") end translate_diff(::GeneralLinear, p, q, X, ::LeftForwardAction) = X diff --git a/src/groups/special_linear.jl b/src/groups/special_linear.jl index 2a72ac0ef4..c29907f080 100644 --- a/src/groups/special_linear.jl +++ b/src/groups/special_linear.jl @@ -146,11 +146,11 @@ function project!(G::SpecialLinear, Y, p, X) end function Base.show(io::IO, ::SpecialLinear{TypeParameter{Tuple{n}},𝔽}) where {n,𝔽} - return print(io, "SpecialLinear($n, $𝔽)") + return print(io, "SpecialLinear($n, $(𝔽))") end function Base.show(io::IO, M::SpecialLinear{Tuple{Int},𝔽}) where {𝔽} n = get_parameter(M.size)[1] - return print(io, "SpecialLinear($n, $𝔽; parameter=:field)") + return print(io, "SpecialLinear($n, $(𝔽); parameter=:field)") end translate_diff(::SpecialLinear, p, q, X, ::LeftForwardAction) = X diff --git a/src/manifolds/ProjectiveSpace.jl b/src/manifolds/ProjectiveSpace.jl index 0675918d16..008a5d138e 100644 --- a/src/manifolds/ProjectiveSpace.jl +++ b/src/manifolds/ProjectiveSpace.jl @@ -9,14 +9,14 @@ abstract type AbstractProjectiveSpace{𝔽} <: AbstractDecoratorManifold{𝔽} e @doc raw""" ProjectiveSpace{n,𝔽} <: AbstractProjectiveSpace{𝔽} -The projective space $𝔽ℙ^n$ is the manifold of all lines in $𝔽^{n+1}$. +The projective space ``𝔽ℙ^n`` is the manifold of all lines in ``𝔽^{n+1}``. The default representation is in the embedding, i.e. as unit norm vectors in -$𝔽^{n+1}$: +``𝔽^{n+1}``: ````math 𝔽ℙ^n := \bigl\{ [p] βŠ‚ 𝔽^{n+1} \ \big|\ \lVert p \rVert = 1, Ξ» ∈ 𝔽, |Ξ»| = 1, p ∼ p Ξ» \bigr\}, ```` -where $[p]$ is an equivalence class of points ``p``, and ``∼`` indicates equivalence. -For example, the real projective space $ℝℙ^n$ is represented as the unit sphere $π•Š^n$, where +where ``[p]`` is an equivalence class of points ``p``, and ``∼`` indicates equivalence. +For example, the real projective space ``ℝℙ^n`` is represented as the unit sphere ``π•Š^n``, where antipodal points are considered equivalent. The tangent space at point ``p`` is given by @@ -24,17 +24,17 @@ The tangent space at point ``p`` is given by ````math T_p 𝔽ℙ^{n} := \bigl\{ X ∈ 𝔽^{n+1}\ \big|\ ⟨p,X⟩ = 0 \bigr \}, ```` -where $βŸ¨β‹…,β‹…βŸ©$ denotes the inner product in the embedding $𝔽^{n+1}$. +where ``βŸ¨β‹…,β‹…βŸ©`` denotes the inner product in the embedding ``𝔽^{n+1}``. -When $𝔽 = ℍ$, this implementation of $ℍℙ^n$ is the right-quaternionic projective +When ``𝔽 = ℍ``, this implementation of ``ℍℙ^n`` is the right-quaternionic projective space. # Constructor ProjectiveSpace(n[, field=ℝ]) -Generate the projective space $𝔽ℙ^{n} βŠ‚ 𝔽^{n+1}$, defaulting to the real projective space -$ℝℙ^n$, where `field` can also be used to generate the complex- and right-quaternionic +Generate the projective space ``𝔽ℙ^{n} βŠ‚ 𝔽^{n+1}``, defaulting to the real projective space +``ℝℙ^n``, where `field` can also be used to generate the complex- and right-quaternionic projective spaces. """ struct ProjectiveSpace{T,𝔽} <: AbstractProjectiveSpace{𝔽} @@ -52,15 +52,15 @@ end @doc raw""" ArrayProjectiveSpace{T<:Tuple,𝔽} <: AbstractProjectiveSpace{𝔽} -The projective space $𝔽ℙ^{n₁,nβ‚‚,…,nα΅’}$ is the manifold of all lines in $𝔽^{n₁,nβ‚‚,…,nα΅’}$. +The projective space ``𝔽ℙ^{n₁,nβ‚‚,…,nα΅’}`` is the manifold of all lines in ``𝔽^{n₁,nβ‚‚,…,nα΅’}``. The default representation is in the embedding, i.e. as unit (Frobenius) norm matrices in -$𝔽^{n₁,nβ‚‚,…,nα΅’}$: +``𝔽^{n₁,nβ‚‚,…,nα΅’}``: ````math 𝔽ℙ^{n_1, n_2, …, n_i} := \bigl\{ [p] βŠ‚ 𝔽^{n_1, n_2, …, n_i} \ \big|\ \lVert p \rVert_{\mathrm{F}} = 1, Ξ» ∈ 𝔽, |Ξ»| = 1, p ∼ p Ξ» \bigr\}. ```` -where $[p]$ is an equivalence class of points ``p``, $\sim$ indicates equivalence, and -$\lVert β‹… \rVert_{\mathrm{F}}$ is the Frobenius norm. +where ``[p]`` is an equivalence class of points ``p``, ``∼`` indicates equivalence, and +``\lVert β‹… \rVert_{\mathrm{F}}`` is the Frobenius norm. Note that unlike [`ProjectiveSpace`](@ref), the argument for `ArrayProjectiveSpace` is given by the size of the embedding. This means that [`ProjectiveSpace(2)`](@ref) and `ArrayProjectiveSpace(3)` are the same @@ -74,14 +74,14 @@ The tangent space at point ``p`` is given by T_p 𝔽ℙ^{n_1, n_2, …, n_i} := \bigl\{ X ∈ 𝔽^{n_1, n_2, …, n_i}\ |\ ⟨p,X⟩_{\mathrm{F}} = 0 \bigr \}, ```` -where $βŸ¨β‹…,β‹…βŸ©_{\mathrm{F}}$ denotes the (Frobenius) inner product in the embedding -$𝔽^{n_1, n_2, …, n_i}$. +where ``βŸ¨β‹…,β‹…βŸ©_{\mathrm{F}}`` denotes the (Frobenius) inner product in the embedding +``𝔽^{n_1, n_2, …, n_i}``. # Constructor ArrayProjectiveSpace(n₁,nβ‚‚,...,nα΅’; field=ℝ) -Generate the projective space $𝔽ℙ^{n_1, n_2, …, n_i}$, defaulting to the real projective +Generate the projective space ``𝔽ℙ^{n_1, n_2, …, n_i}``, defaulting to the real projective space, where `field` can also be used to generate the complex- and right-quaternionic projective spaces. """ @@ -124,7 +124,7 @@ end Check whether `X` is a tangent vector in the tangent space of `p` on the [`AbstractProjectiveSpace`](@ref) `M`, i.e. that `X` has the same size as elements of the tangent space of the embedding and that the Frobenius inner product -$⟨p, X⟩_{\mathrm{F}} = 0$. +``⟨p, X⟩_{\mathrm{F}} = 0``. """ function check_vector( M::AbstractProjectiveSpace, @@ -158,7 +158,7 @@ embed(::AbstractProjectiveSpace, p, X) = X @doc raw""" distance(M::AbstractProjectiveSpace, p, q) -Compute the Riemannian distance on [`AbstractProjectiveSpace`](@ref) `M`$=𝔽ℙ^n$ between +Compute the Riemannian distance on [`AbstractProjectiveSpace`](@ref) `M```=𝔽ℙ^n`` between points `p` and `q`, i.e. ````math d_{𝔽ℙ^n}(p, q) = \arccos\bigl| ⟨p, q⟩_{\mathrm{F}} \bigr|. @@ -194,12 +194,12 @@ end get_coordinates(M::AbstractProjectiveSpace, p, X, B::DefaultOrthonormalBasis{ℝ}) Represent the tangent vector ``X`` at point ``p`` from the [`AbstractProjectiveSpace`](@ref) -$M = 𝔽ℙ^n$ in an orthonormal basis by unitarily transforming the hyperplane containing ``X``, +``M = 𝔽ℙ^n`` in an orthonormal basis by unitarily transforming the hyperplane containing ``X``, whose normal is ``p``, to the hyperplane whose normal is the ``x``-axis. -Given $q = p \overline{Ξ»} + x$, where -$Ξ» = \frac{⟨x, p⟩_{\mathrm{F}}}{|⟨x, p⟩_{\mathrm{F}}|}$, $βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ denotes the -Frobenius inner product, and $\overline{β‹…}$ denotes complex or quaternionic conjugation, the +Given ``q = p \overline{Ξ»} + x``, where +``Ξ» = \frac{⟨x, p⟩_{\mathrm{F}}}{|⟨x, p⟩_{\mathrm{F}}|}``, ``βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}`` denotes the +Frobenius inner product, and ``\overline{β‹…}`` denotes complex or quaternionic conjugation, the formula for ``Y`` is ````math \begin{pmatrix}0 \\ Y\end{pmatrix} = \left(X - q\frac{2 ⟨q, X⟩_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}\right)\overline{Ξ»}. @@ -228,13 +228,13 @@ end get_vector(M::AbstractProjectiveSpace, p, X, B::DefaultOrthonormalBasis{ℝ}) Convert a one-dimensional vector of coefficients ``X`` in the basis `B` of the tangent space -at ``p`` on the [`AbstractProjectiveSpace`](@ref) $M=𝔽ℙ^n$ to a tangent vector ``Y`` at ``p`` by +at ``p`` on the [`AbstractProjectiveSpace`](@ref) ``M=𝔽ℙ^n`` to a tangent vector ``Y`` at ``p`` by unitarily transforming the hyperplane containing ``X``, whose normal is the ``x``-axis, to the hyperplane whose normal is ``p``. -Given $q = p \overline{Ξ»} + x$, where -$Ξ» = \frac{⟨x, p⟩_{\mathrm{F}}}{|⟨x, p⟩_{\mathrm{F}}|}$, $βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ denotes the -Frobenius inner product, and $\overline{β‹…}$ denotes complex or quaternionic conjugation, the +Given ``q = p \overline{Ξ»} + x``, where +``Ξ» = \frac{⟨x, p⟩_{\mathrm{F}}}{|⟨x, p⟩_{\mathrm{F}}|}``, ``βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}`` denotes the +Frobenius inner product, and ``\overline{β‹…}`` denotes complex or quaternionic conjugation, the formula for ``Y`` is ````math Y = \left(X - q\frac{2 \left\langle q, \begin{pmatrix}0 \\ X\end{pmatrix}\right\rangle_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}\right) Ξ». @@ -272,16 +272,16 @@ injectivity_radius(::AbstractProjectiveSpace, p, ::AbstractRetractionMethod) = Compute the equivalent inverse retraction [`ProjectionInverseRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.ProjectionInverseRetraction), [`PolarInverseRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.PolarInverseRetraction), and [`QRInverseRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.QRInverseRetraction) on the -[`AbstractProjectiveSpace`](@ref) manifold `M`$=𝔽ℙ^n$, i.e. +[`AbstractProjectiveSpace`](@ref) manifold `M```=𝔽ℙ^n``, i.e. ````math \operatorname{retr}_p^{-1} q = q \frac{1}{⟨p, q⟩_{\mathrm{F}}} - p, ```` -where $βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ is the Frobenius inner product. +where ``βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}`` is the Frobenius inner product. Note that this inverse retraction is equivalent to the three corresponding inverse retractions on [`Grassmann(n+1,1,𝔽)`](@ref), where the three inverse retractions in this case coincide. -For $ℝℙ^n$, it is the same as the `ProjectionInverseRetraction` on the real +For ``ℝℙ^n``, it is the same as the `ProjectionInverseRetraction` on the real [`Sphere`](@ref). """ inverse_retract( @@ -307,9 +307,9 @@ end @doc raw""" isapprox(M::AbstractProjectiveSpace, p, q; kwargs...) -Check that points `p` and `q` on the [`AbstractProjectiveSpace`](@ref) `M`$=𝔽ℙ^n$ are -members of the same equivalence class, i.e. that $p = q Ξ»$ for some element $Ξ» ∈ 𝔽$ with -unit absolute value, that is, $|Ξ»| = 1$. +Check that points `p` and `q` on the [`AbstractProjectiveSpace`](@ref) `M```=𝔽ℙ^n`` are +members of the same equivalence class, i.e. that ``p = q Ξ»`` for some element ``Ξ» ∈ 𝔽`` with +unit absolute value, that is, ``|Ξ»| = 1``. This is equivalent to the Riemannian [`distance`](@ref distance(::AbstractProjectiveSpace, p, q)) being 0. """ @@ -327,24 +327,24 @@ is_flat(M::AbstractProjectiveSpace) = manifold_dimension(M) == 1 @doc raw""" log(M::AbstractProjectiveSpace, p, q) -Compute the logarithmic map on [`AbstractProjectiveSpace`](@ref) `M`$ = 𝔽ℙ^n$, +Compute the logarithmic map on [`AbstractProjectiveSpace`](@ref) `M``` = 𝔽ℙ^n``, i.e. the tangent vector whose corresponding [`geodesic`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/functions.html#ManifoldsBase.geodesic-Tuple{AbstractManifold,%20Any,%20Any}) starting from `p` reaches `q` after time 1 on `M`. The formula reads ````math \log_p q = (q Ξ» - \cos ΞΈ p) \frac{ΞΈ}{\sin ΞΈ}, ```` -where $ΞΈ = \arccos|⟨q, p⟩_{\mathrm{F}}|$ is the +where ``ΞΈ = \arccos|⟨q, p⟩_{\mathrm{F}}|`` is the [`distance`](@ref distance(::AbstractProjectiveSpace, p, q)) between ``p`` and ``q``, -$βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ is the Frobenius inner product, and -$Ξ» = \frac{⟨q, p⟩_{\mathrm{F}}}{|⟨q, p⟩_{\mathrm{F}}|} ∈ 𝔽$ is the unit scalar that -minimizes $d_{𝔽^{n+1}}(p - q Ξ»)$. -That is, $q Ξ»$ is the member of the equivalence class $[q]$ that is closest to ``p`` in the +``βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}`` is the Frobenius inner product, and +``Ξ» = \frac{⟨q, p⟩_{\mathrm{F}}}{|⟨q, p⟩_{\mathrm{F}}|} ∈ 𝔽`` is the unit scalar that +minimizes ``d_{𝔽^{n+1}}(p - q Ξ»)``. +That is, ``q Ξ»`` is the member of the equivalence class ``[q]`` that is closest to ``p`` in the embedding. -As a result, $\exp_p \circ \log_p \colon q ↦ q Ξ»$. +As a result, ``\exp_p \circ \log_p \colon q ↦ q Ξ»``. -The logarithmic maps for the real [`AbstractSphere`](@ref) $π•Š^n$ and the real projective -space $ℝℙ^n$ are identical when ``p`` and ``q`` are in the same hemisphere. +The logarithmic maps for the real [`AbstractSphere`](@ref) ``π•Š^n`` and the real projective +space ``ℝℙ^n`` are identical when ``p`` and ``q`` are in the same hemisphere. """ log(::AbstractProjectiveSpace, p, q) @@ -417,7 +417,7 @@ Orthogonally project the point `p` from the embedding onto the ````math \operatorname{proj}(p) = \frac{p}{\lVert p \rVert}_{\mathrm{F}}, ```` -where $\lVert β‹… \rVert_{\mathrm{F}}$ denotes the Frobenius norm. +where ``\lVert β‹… \rVert_{\mathrm{F}}`` denotes the Frobenius norm. This is identical to projection onto the [`AbstractSphere`](@ref). """ project(::AbstractProjectiveSpace, ::Any) @@ -433,7 +433,7 @@ Orthogonally project the point `X` onto the tangent space at `p` on the ````math \operatorname{proj}_p (X) = X - p⟨p, X⟩_{\mathrm{F}}, ```` -where $βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ denotes the Frobenius inner product. +where ``βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}`` denotes the Frobenius inner product. For the real [`AbstractSphere`](@ref) and `AbstractProjectiveSpace`, this projection is the same. """ @@ -461,7 +461,7 @@ end retract(M::AbstractProjectiveSpace, p, X, method::QRRetraction) Compute the equivalent retraction [`ProjectionRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.ProjectionRetraction), [`PolarRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.PolarRetraction), -and [`QRRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.QRRetraction) on the [`AbstractProjectiveSpace`](@ref) manifold `M`$=𝔽ℙ^n$, +and [`QRRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.QRRetraction) on the [`AbstractProjectiveSpace`](@ref) manifold `M```=𝔽ℙ^n``, i.e. ````math \operatorname{retr}_p X = \operatorname{proj}_p(p + X). @@ -469,7 +469,7 @@ i.e. Note that this retraction is equivalent to the three corresponding retractions on [`Grassmann(n+1,1,𝔽)`](@ref), where in this case they coincide. -For $ℝℙ^n$, it is the same as the `ProjectionRetraction` on the real [`Sphere`](@ref). +For ``ℝℙ^n``, it is the same as the `ProjectionRetraction` on the real [`Sphere`](@ref). """ retract( ::AbstractProjectiveSpace, @@ -521,21 +521,21 @@ end parallel_transport_to(M::AbstractProjectiveSpace, p, X, q) Parallel transport a vector `X` from the tangent space at a point `p` on the -[`AbstractProjectiveSpace`](@ref) `M`$=𝔽ℙ^n$ to the tangent space at another point `q`. +[`AbstractProjectiveSpace`](@ref) `M```=𝔽ℙ^n`` to the tangent space at another point `q`. -This implementation proceeds by transporting ``X`` to $T_{q Ξ»} M$ using the same approach as +This implementation proceeds by transporting ``X`` to ``T_{q Ξ»} M`` using the same approach as [`parallel_transport_direction`](@ref parallel_transport_direction(::AbstractProjectiveSpace, p, X, d)), -where $Ξ» = \frac{⟨q, p⟩_{\mathrm{F}}}{|⟨q, p⟩_{\mathrm{F}}|} ∈ 𝔽$ is the unit scalar that -takes ``q`` to the member $q Ξ»$ of its equivalence class $[q]$ closest to ``p`` in the +where ``Ξ» = \frac{⟨q, p⟩_{\mathrm{F}}}{|⟨q, p⟩_{\mathrm{F}}|} ∈ 𝔽`` is the unit scalar that +takes ``q`` to the member ``q Ξ»`` of its equivalence class ``[q]`` closest to ``p`` in the embedding. -It then maps the transported vector from $T_{q Ξ»} M$ to $T_{q} M$. -The resulting transport to $T_{q} M$ is +It then maps the transported vector from ``T_{q Ξ»} M`` to ``T_{q} M``. +The resulting transport to ``T_{q} M`` is ````math \mathcal{P}_{q ← p}(X) = \left(X - \left(p \frac{\sin ΞΈ}{ΞΈ} + d \frac{1 - \cos ΞΈ}{ΞΈ^2}\right) ⟨d, X⟩_p\right) \overline{Ξ»}, ```` -where $d = \log_p q$ is the direction of the transport, $ΞΈ = \lVert d \rVert_p$ is the +where ``d = \log_p q`` is the direction of the transport, ``ΞΈ = \lVert d \rVert_p`` is the [`distance`](@ref distance(::AbstractProjectiveSpace, p, q)) between ``p`` and ``q``, and -$\overline{β‹…}$ denotes complex or quaternionic conjugation. +``\overline{β‹…}`` denotes complex or quaternionic conjugation. """ parallel_transport_to(::AbstractProjectiveSpace, ::Any, ::Any, ::Any) @@ -564,7 +564,7 @@ indicated by the tangent vector `d`, i.e. ````math \mathcal{P}_{\exp_p (d) ← p}(X) = X - \left(p \frac{\sin ΞΈ}{ΞΈ} + d \frac{1 - \cos ΞΈ}{ΞΈ^2}\right) ⟨d, X⟩_p, ```` -where $ΞΈ = \lVert d \rVert$, and $βŸ¨β‹…, β‹…βŸ©_p$ is the [`inner`](@ref) product at the point ``p``. +where ``ΞΈ = \lVert d \rVert``, and ``βŸ¨β‹…, β‹…βŸ©_p`` is the [`inner`](@ref) product at the point ``p``. For the real projective space, this is equivalent to the same vector transport on the real [`AbstractSphere`](@ref). """ diff --git a/src/manifolds/SkewHermitian.jl b/src/manifolds/SkewHermitian.jl index 06a4b69a78..a8641512ca 100644 --- a/src/manifolds/SkewHermitian.jl +++ b/src/manifolds/SkewHermitian.jl @@ -1,14 +1,14 @@ @doc raw""" SkewHermitianMatrices{T,𝔽} <: AbstractDecoratorManifold{𝔽} -The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) $ \operatorname{SkewHerm}(n)$ consisting of the real- or +The [`AbstractManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/types.html#ManifoldsBase.AbstractManifold) ``\operatorname{SkewHerm}(n)`` consisting of the real- or complex-valued skew-hermitian matrices of size ``nΓ—n``, i.e. the set ````math \operatorname{SkewHerm}(n) = \bigl\{p ∈ 𝔽^{nΓ—n}\ \big|\ p^{\mathrm{H}} = -p \bigr\}, ```` -where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transpose, -and the field $𝔽 ∈ \{ ℝ, β„‚, ℍ\}$. +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transpose, +and the field ``𝔽 ∈ \{ ℝ, β„‚, ℍ\}``. Though it is slightly redundant, usually the matrices are stored as ``nΓ—n`` arrays. @@ -223,7 +223,7 @@ Projects `p` from the embedding onto the [`SkewHermitianMatrices`](@ref) `M`, i. \operatorname{proj}_{\operatorname{SkewHerm}(n)}(p) = \frac{1}{2} \bigl( p - p^{\mathrm{H}} \bigr), ```` -where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SkewHermitianMatrices, ::Any) @@ -241,7 +241,7 @@ Project the matrix `X` onto the tangent space at `p` on the [`SkewHermitianMatri \operatorname{proj}_p(X) = \frac{1}{2} \bigl( X - X^{\mathrm{H}} \bigr), ```` -where $β‹…^{\mathrm{H}}$ denotes the Hermitian, i.e. complex conjugate transposed. +where ``β‹…^{\mathrm{H}}`` denotes the Hermitian, i.e. complex conjugate transposed. """ project(::SkewHermitianMatrices, ::Any, ::Any) diff --git a/src/manifolds/Sphere.jl b/src/manifolds/Sphere.jl index c8cc2c3734..8ed626caaf 100644 --- a/src/manifolds/Sphere.jl +++ b/src/manifolds/Sphere.jl @@ -12,15 +12,15 @@ end @doc raw""" Sphere{T,𝔽} <: AbstractSphere{𝔽} -The (unit) sphere manifold $π•Š^{n}$ is the set of all unit norm vectors in $𝔽^{n+1}$. +The (unit) sphere manifold ``π•Š^{n}`` is the set of all unit norm vectors in ``𝔽^{n+1}``. The sphere is represented in the embedding, i.e. ````math π•Š^{n} := \bigl\{ p \in 𝔽^{n+1}\ \big|\ \lVert p \rVert = 1 \bigr\} ```` -where $𝔽\in\{ℝ,β„‚,ℍ\}$. Note that compared to the [`ArraySphere`](@ref), here the -argument `n` of the manifold is the dimension of the manifold, i.e. $π•Š^{n} βŠ‚ 𝔽^{n+1}$, $n\in β„•$. +where ``𝔽\in\{ℝ,β„‚,ℍ\}``. Note that compared to the [`ArraySphere`](@ref), here the +argument `n` of the manifold is the dimension of the manifold, i.e. ``π•Š^{n} βŠ‚ 𝔽^{n+1}``, ``n\in β„•``. The tangent space at point ``p`` is given by @@ -28,15 +28,15 @@ The tangent space at point ``p`` is given by T_pπ•Š^{n} := \bigl\{ X ∈ 𝔽^{n+1}\ |\ \Re(⟨p,X⟩) = 0 \bigr \}, ```` -where $𝔽\in\{ℝ,β„‚,ℍ\}$ and $βŸ¨β‹…,β‹…βŸ©$ denotes the inner product in the -embedding $𝔽^{n+1}$. +where ``𝔽\in\{ℝ,β„‚,ℍ\}`` and ``βŸ¨β‹…,β‹…βŸ©`` denotes the inner product in the +embedding ``𝔽^{n+1}``. -For $𝔽=β„‚$, the manifold is the complex sphere, written $β„‚π•Š^n$, embedded in $β„‚^{n+1}$. -$β„‚π•Š^n$ is the complexification of the real sphere $π•Š^{2n+1}$. -Likewise, the quaternionic sphere $β„π•Š^n$ is the quaternionification of the real sphere -$π•Š^{4n+3}$. -Consequently, $β„‚π•Š^0$ is equivalent to $π•Š^1$ and [`Circle`](@ref), while $β„‚π•Š^1$ and $β„π•Š^0$ -are equivalent to $π•Š^3$, though with different default representations. +For ``𝔽=β„‚``, the manifold is the complex sphere, written ``β„‚π•Š^n``, embedded in ``β„‚^{n+1}``. +``β„‚π•Š^n`` is the complexification of the real sphere ``π•Š^{2n+1}``. +Likewise, the quaternionic sphere ``β„π•Š^n`` is the quaternionification of the real sphere +``π•Š^{4n+3}``. +Consequently, ``β„‚π•Š^0`` is equivalent to ``π•Š^1`` and [`Circle`](@ref), while ``β„‚π•Š^1`` and ``β„π•Š^0`` +are equivalent to ``π•Š^3``, though with different default representations. This manifold is modeled as a special case of the more general case, i.e. as an embedded manifold to the [`Euclidean`](@ref), and several functions like the [`inner`](@ref inner(::Euclidean, ::Any...)) product @@ -46,7 +46,7 @@ and the [`zero_vector`](@ref zero_vector(::Euclidean, ::Any...)) are inherited f Sphere(n[, field=ℝ]) -Generate the (real-valued) sphere $π•Š^{n} βŠ‚ ℝ^{n+1}$, where `field` can also be used to +Generate the (real-valued) sphere ``π•Š^{n} βŠ‚ ℝ^{n+1}``, where `field` can also be used to generate the complex- and quaternionic-valued sphere. """ struct Sphere{T,𝔽} <: AbstractSphere{𝔽} @@ -60,8 +60,8 @@ end @doc raw""" ArraySphere{T<:Tuple,𝔽} <: AbstractSphere{𝔽} -The (unit) sphere manifold $π•Š^{n₁,nβ‚‚,...,nα΅’}$ is the set of all unit (Frobenius) norm elements of -$𝔽^{n₁,nβ‚‚,...,nα΅’}$, where $𝔽\in\{ℝ,β„‚,ℍ\}. The generalized sphere is +The (unit) sphere manifold ``π•Š^{n₁,nβ‚‚,...,nα΅’}`` is the set of all unit (Frobenius) norm elements of +``𝔽^{n₁,nβ‚‚,...,nα΅’}``, where ``𝔽\in\{ℝ,β„‚,ℍ\}. The generalized sphere is represented in the embedding, and supports arbitrary sized arrays or in other words arbitrary tensors of unit norm. The set formally reads @@ -69,7 +69,7 @@ tensors of unit norm. The set formally reads π•Š^{n_1, n_2, …, n_i} := \bigl\{ p \in 𝔽^{n_1, n_2, …, n_i}\ \big|\ \lVert p \rVert = 1 \bigr\} ```` -where $𝔽\in\{ℝ,β„‚,ℍ\}$. Setting $i=1$ and $𝔽=ℝ$ this simplifies to unit vectors in $ℝ^n$, see +where ``𝔽\in\{ℝ,β„‚,ℍ\}``. Setting ``i=1`` and ``𝔽=ℝ`` this simplifies to unit vectors in ``ℝ^n``, see [`Sphere`](@ref) for this special case. Note that compared to this classical case, the argument for the generalized case here is given by the dimension of the embedding. This means that `Sphere(2)` and `ArraySphere(3)` are the same manifold. @@ -80,8 +80,8 @@ The tangent space at point ``p`` is given by T_p π•Š^{n_1, n_2, …, n_i} := \bigl\{ X ∈ 𝔽^{n_1, n_2, …, n_i}\ |\ \Re(⟨p,X⟩) = 0 \bigr \}, ```` -where $𝔽\in\{ℝ,β„‚,ℍ\}$ and $βŸ¨β‹…,β‹…βŸ©$ denotes the (Frobenius) inner product in the -embedding $𝔽^{n_1, n_2, …, n_i}$. +where ``𝔽\in\{ℝ,β„‚,ℍ\}`` and ``βŸ¨β‹…,β‹…βŸ©`` denotes the (Frobenius) inner product in the +embedding ``𝔽^{n_1, n_2, …, n_i}``. This manifold is modeled as an embedded manifold to the [`Euclidean`](@ref), i.e. several functions like the [`inner`](@ref inner(::Euclidean, ::Any...)) product and the @@ -91,7 +91,7 @@ several functions like the [`inner`](@ref inner(::Euclidean, ::Any...)) product ArraySphere(n₁,nβ‚‚,...,nα΅’; field=ℝ, parameter::Symbol=:type) -Generate sphere in $𝔽^{n_1, n_2, …, n_i}$, where ``𝔽`` defaults to the real-valued case ``ℝ``. +Generate sphere in ``𝔽^{n_1, n_2, …, n_i}``, where ``𝔽`` defaults to the real-valued case ``ℝ``. """ struct ArraySphere{T,𝔽} <: AbstractSphere{𝔽} size::T @@ -187,7 +187,7 @@ Compute the exponential map from `p` in the tangent direction `X` on the [`Abstr ````math \exp_p X = \cos(\lVert X \rVert_p)p + \sin(\lVert X \rVert_p)\frac{X}{\lVert X \rVert_p}, ```` -where $\lVert X \rVert_p$ is the [`norm`](@ref norm(::AbstractSphere,p,X)) on the +where ``\lVert X \rVert_p`` is the [`norm`](@ref norm(::AbstractSphere,p,X)) on the tangent space at `p` of the [`AbstractSphere`](@ref) `M`. """ exp(::AbstractSphere, ::Any...) @@ -227,7 +227,7 @@ Represent the tangent vector `X` at point `p` from the [`AbstractSphere`](@ref) an orthonormal basis by rotating the hyperplane containing `X` to a hyperplane whose normal is the ``x``-axis. -Given $q = p Ξ» + x$, where $Ξ» = \operatorname{sgn}(⟨x, p⟩)$, and $βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ +Given ``q = p Ξ» + x``, where ``Ξ» = \operatorname{sgn}(⟨x, p⟩)``, and ``βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}`` denotes the Frobenius inner product, the formula for ``Y`` is ````math \begin{pmatrix}0 \\ Y\end{pmatrix} = X - q\frac{2 ⟨q, X⟩_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}. @@ -261,7 +261,7 @@ at `p` on the [`AbstractSphere`](@ref) `M` to a tangent vector `Y` at `p` by rot hyperplane containing `X`, whose normal is the ``x``-axis, to the hyperplane whose normal is `p`. -Given $q = p Ξ» + x$, where $Ξ» = \operatorname{sgn}(⟨x, p⟩)$, and $βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}$ +Given ``q = p Ξ» + x``, where ``Ξ» = \operatorname{sgn}(⟨x, p⟩)``, and ``βŸ¨β‹…, β‹…βŸ©_{\mathrm{F}}`` denotes the Frobenius inner product, the formula for ``Y`` is ````math Y = X - q\frac{2 \left\langle q, \begin{pmatrix}0 \\ X\end{pmatrix}\right\rangle_{\mathrm{F}}}{⟨q, q⟩_{\mathrm{F}}}. @@ -290,7 +290,7 @@ Return the injectivity radius for the [`AbstractSphere`](@ref) `M`, which is glo injectivity_radius(M::Sphere, x, ::ProjectionRetraction) Return the injectivity radius for the [`ProjectionRetraction`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/retractions.html#ManifoldsBase.ProjectionRetraction) on the -[`AbstractSphere`](@ref), which is globally $\frac{Ο€}{2}$. +[`AbstractSphere`](@ref), which is globally ``\frac{Ο€}{2}``. """ injectivity_radius(::AbstractSphere) = Ο€ injectivity_radius(::AbstractSphere, p) = Ο€ @@ -308,8 +308,8 @@ _injectivity_radius(::AbstractSphere, ::ProjectionRetraction) = Ο€ / 2 inverse_retract(M::AbstractSphere, p, q, ::ProjectionInverseRetraction) Compute the inverse of the projection based retraction on the [`AbstractSphere`](@ref) `M`, -i.e. rearranging $p+X = q\lVert p+X\rVert_2$ yields -since $\Re(⟨p,X⟩) = 0$ and when $d_{π•Š^2}(p,q) ≀ \frac{Ο€}{2}$ that +i.e. rearranging ``p+X = q\lVert p+X\rVert_2`` yields +since ``\Re(⟨p,X⟩) = 0`` and when ``d_{π•Š^2}(p,q) ≀ \frac{Ο€}{2}`` that ````math \operatorname{retr}_p^{-1}(q) = \frac{q}{\Re(⟨p, q⟩)} - p. @@ -352,13 +352,13 @@ end Compute the logarithmic map on the [`AbstractSphere`](@ref) `M`, i.e. the tangent vector, whose geodesic starting from `p` reaches `q` after time 1. -The formula reads for $x β‰  -y$ +The formula reads for ``x β‰  -y`` ````math \log_p q = d_{π•Š}(p,q) \frac{q-\Re(⟨p,q⟩) p}{\lVert q-\Re(⟨p,q⟩) p \rVert_2}, ```` -and a deterministic choice from the set of tangent vectors is returned if $x=-y$, i.e. for +and a deterministic choice from the set of tangent vectors is returned if ``x=-y``, i.e. for opposite points. """ log(::AbstractSphere, ::Any...) @@ -437,8 +437,8 @@ Project the point `p` from the embedding onto the [`Sphere`](@ref) `M`. ````math \operatorname{proj}(p) = \frac{p}{\lVert p \rVert}, ```` -where $\lVertβ‹…\rVert$ denotes the usual 2-norm for vectors if $m=1$ and the Frobenius -norm for the case $m>1$. +where ``\lVertβ‹…\rVert`` denotes the usual 2-norm for vectors if ``m=1`` and the Frobenius +norm for the case ``m>1``. """ project(::AbstractSphere, ::Any) diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index f81ff0a06a..fe3a6223c3 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -38,7 +38,7 @@ representation as projectors, using a [`ProjectorTVector`](@ref) as where ``[X,p] = Xp-pX`` denotes the matrix commutator and ``\mathfrak{sp}(2n,ℝ)`` is the Lie algebra of the symplectic group consisting of [`HamiltonianMatrices`](@ref). -The first repesentation is in [`StiefelPoints`](@ref) and [`StiefelTVectors`](@ref), +The first repesentation is in [`StiefelPoint`](@ref)s and [`StiefelTVector`](@ref)s, which both represent their symplectic Grassmann equivalence class. Arrays are interpreted in this representation as well diff --git a/src/statistics.jl b/src/statistics.jl index 4f7c7c8bca..aff3e6e1d1 100644 --- a/src/statistics.jl +++ b/src/statistics.jl @@ -85,7 +85,7 @@ as the point that satisfies the minimizer ````math \argmin_{y ∈ \mathcal M} \frac{1}{2 \sum_{i=1}^n w_i} \sum_{i=1}^n w_i\mathrm{d}_{\mathcal M}^2(y,x_i), ```` -where $\mathrm{d}_{\mathcal M}$ denotes the Riemannian [`distance`](@ref). +where ``\mathrm{d}_{\mathcal M}`` denotes the Riemannian [`distance`](@ref). In the general case, the [`GradientDescentEstimation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/functions/#ManifoldsBase.GradientDescentEstimation) is used to compute the mean. mean( @@ -445,7 +445,7 @@ Compute the (optionally weighted) Riemannian median of the vector `x` of points ````math \argmin_{y ∈ \mathcal M} \frac{1}{\sum_{i=1}^n w_i} \sum_{i=1}^n w_i\mathrm{d}_{\mathcal M}(y,x_i), ```` -where $\mathrm{d}_{\mathcal M}$ denotes the Riemannian [`distance`](@ref). +where ``\mathrm{d}_{\mathcal M}`` denotes the Riemannian [`distance`](@ref). This function is nonsmooth (i.e nondifferentiable). In the general case, the [`CyclicProximalPointEstimation`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/functions/#ManifoldsBase.CyclicProximalPointEstimation) is used to compute the @@ -566,7 +566,7 @@ X = \frac{1}{s}\sum_{i\in I_k} \frac{w_i}{d_{\mathcal M}(q_k,x_i)}\log_{q_k}x_i s = \sum_{i\in I_k} \frac{w_i}{d_{\mathcal M}(q_k,x_i)}, ``` -and where $\mathrm{d}_{\mathcal M}$ denotes the Riemannian [`distance`](@ref). +and where ``\mathrm{d}_{\mathcal M}`` denotes the Riemannian [`distance`](@ref). Optionally, pass `retraction` and `inverse_retraction` method types to specify the (inverse) retraction, which by default use the exponential and logarithmic map, From 6d577eab6705393bee7fa0f795850fe76af2f90e Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 19:02:40 +0100 Subject: [PATCH 53/65] Apply suggestions from code review Co-authored-by: Mateusz Baran --- src/manifolds/Hamiltonian.jl | 4 ++-- src/manifolds/SymplecticGrassmann.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index 0eb4802200..261f81d44b 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -177,8 +177,8 @@ end Generate a Hamiltonian matrix. Since these are a submanifold of ``ℝ^{2nΓ—2n}``, the same method applies for points and tangent vectors. -The generation is based on generating one normally-distributed -``nΓ—n`` matrix ``A`` and two symmetric ``nΓ—n`` matrices ``B,C`` to generate +The construction is based on generating one normally-distributed +``nΓ—n`` matrix ``A`` and two symmetric ``nΓ—n`` matrices ``B, C`` which are then stacked: ```math p = \begin{pmatrix} A & B\\ C & -A^{\mathrm{T}} \end{pmatrix} diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index fe3a6223c3..986faff208 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -4,7 +4,7 @@ The symplectic Grassmann manifold consists of all symplectic subspaces of ``ℝ^{2n}`` of dimension ``2k``, ``n β‰₯ k``. -This manifold can be represented as corresponding representers on the [`SymplecticStiefel`](@ref) +Points on this manifold can be represented as corresponding representers on the [`SymplecticStiefel`](@ref) ```math \operatorname{SpGr}(2n,2k) = \bigl\{ \operatorname{span}(p)\ \big| \ p ∈ \operatorname{SpSt}(2n, 2k, ℝ)\}, From 2657758b83d5b400419e304fe64d352e1075ace6 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 19:03:14 +0100 Subject: [PATCH 54/65] fix test tolerances. --- test/manifolds/symplecticstiefel.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/manifolds/symplecticstiefel.jl b/test/manifolds/symplecticstiefel.jl index 3bb17932a0..f4543f249c 100644 --- a/test/manifolds/symplecticstiefel.jl +++ b/test/manifolds/symplecticstiefel.jl @@ -212,9 +212,9 @@ end @testset "Generate random points/tangent vectors" begin M_big = SymplecticStiefel(20, 10) p_big = rand(M_big) - @test is_point(M_big, p_big; error=:error, atol=1.0e-14) + @test is_point(M_big, p_big; error=:error, atol=5e-14) X_big = rand(M_big; vector_at=p_big) - @test is_vector(M_big, p_big, X_big; error=:error, atol=1.0e-14) + @test is_vector(M_big, p_big, X_big; error=:error, atol=5e-14) end @testset "test_manifold(SymplecticMatrices(6), ...)" begin types = [Matrix{Float64}] From 91a09ebf629835c6c37957efd688ab2fdb6b5e4a Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 19:03:53 +0100 Subject: [PATCH 55/65] Update src/manifolds/SymplecticGrassmann.jl Co-authored-by: Mateusz Baran --- src/manifolds/SymplecticGrassmann.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manifolds/SymplecticGrassmann.jl b/src/manifolds/SymplecticGrassmann.jl index 986faff208..2438a616cc 100644 --- a/src/manifolds/SymplecticGrassmann.jl +++ b/src/manifolds/SymplecticGrassmann.jl @@ -26,7 +26,7 @@ With respect to the quotient structure, the canonical projection ``Ο€ = Ο€_{\mat Ο€: \mathrm{SpSt}(2n2k) β†’ \mathrm{SpGr}(2n,2k), p ↦ Ο€(p) = pp^+. ``` -The tangent space is either the tangent space from the symplecti Stiefel manifold, where +The tangent space is either the tangent space from the symplectic Stiefel manifold, where tangent vectors are representers of their corresponding congruence classes, or for the representation as projectors, using a [`ProjectorTVector`](@ref) as From 02a59f5d5bfc4c90d3514793ea0a8c9b3f1a08e8 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 19:05:26 +0100 Subject: [PATCH 56/65] Edit rand doc string. --- src/manifolds/Hamiltonian.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index 261f81d44b..edb8b7ffb8 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -171,11 +171,12 @@ function Base.show(io::IO, M::HamiltonianMatrices{Tuple{Int},F}) where {F} end @doc raw""" - p = rand(M::HamiltonianMatrices; Οƒ::Real=1.0, vector_at=nothing) - rand(M::HamiltonianMatrices; Οƒ::Real=1.0, vector_at=nothing) + pX = rand(M::HamiltonianMatrices; Οƒ::Real=1.0, vector_at=nothing) + rand!(M::HamiltonianMatrices, pX; Οƒ::Real=1.0, vector_at=nothing) Generate a Hamiltonian matrix. Since these are a submanifold of ``ℝ^{2nΓ—2n}``, the same method applies for points and tangent vectors. +This can also be done in-place of `pX`. The construction is based on generating one normally-distributed ``nΓ—n`` matrix ``A`` and two symmetric ``nΓ—n`` matrices ``B, C`` which are then stacked: From 22b27ff4f51bccac3900a18d35376f1912befde7 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 19:06:15 +0100 Subject: [PATCH 57/65] Update src/manifolds/Hamiltonian.jl Co-authored-by: Mateusz Baran --- src/manifolds/Hamiltonian.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index edb8b7ffb8..2af5bb7d0a 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -142,7 +142,7 @@ Return true. [`HamiltonianMatrices`](@ref) is a flat manifold. is_flat(M::HamiltonianMatrices) = true @doc raw""" - is_hamiltonian(A; kwargs...) + is_hamiltonian(A::AbstractMatrix; kwargs...) Test whether a matrix `A` is hamiltonian. The test consists of verifying whether From 7cf4731cf584b94e79c7a8636c16c468f8543179 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 19:36:44 +0100 Subject: [PATCH 58/65] Update src/manifolds/Hamiltonian.jl Co-authored-by: Mateusz Baran --- src/manifolds/Hamiltonian.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index 2af5bb7d0a..bfdf2da0a9 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -46,7 +46,7 @@ consisting of (real-valued) hamiltonian matrices of size ``nΓ—n``, i.e. the set ````math \mathfrak{sp}(2n,𝔽) = \bigl\{p ∈ 𝔽^{2nΓ—2n}\ \big|\ p^+ = p \bigr\}, ```` -where ``β‹…^{+}`` denotes the [`symplectic_inverse`](@ref),. and ``𝔽 ∈ \{ ℝ, β„‚\}``. +where ``β‹…^{+}`` denotes the [`symplectic_inverse`](@ref), and ``𝔽 ∈ \{ ℝ, β„‚\}``. Though it is slightly redundant, usually the matrices are stored as ``2nΓ—2n`` arrays. From d2813551b39ecb00408ad3fca608a528cbe468d3 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 19:37:29 +0100 Subject: [PATCH 59/65] Update src/manifolds/Hamiltonian.jl Co-authored-by: Mateusz Baran --- src/manifolds/Hamiltonian.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index bfdf2da0a9..137ee96425 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -4,7 +4,7 @@ @doc raw""" Hamiltonian{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T} -A type to store an hamiltonien matrix, i.e. A square matrix matrix for which ``A^+ = -A`` where +A type to store a Hamiltonian matrix, that is a square matrix for which ``A^+ = -A`` where ```math A^+ = J_{2n}A^{\mathrm{T}}J_{2n}, \qquad J_{2n} \begin{pmatrix} 0 & I_n\\-I_n & 0 \end{pmatrix}, From e3d83da8b5f3a961e959bc7945989213ea3cc8a2 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 19:39:07 +0100 Subject: [PATCH 60/65] Update src/manifolds/Hamiltonian.jl Co-authored-by: Mateusz Baran --- src/manifolds/Hamiltonian.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index 137ee96425..3b203c0586 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -174,7 +174,7 @@ end pX = rand(M::HamiltonianMatrices; Οƒ::Real=1.0, vector_at=nothing) rand!(M::HamiltonianMatrices, pX; Οƒ::Real=1.0, vector_at=nothing) -Generate a Hamiltonian matrix. Since these are a submanifold of ``ℝ^{2nΓ—2n}``, +Generate a random Hamiltonian matrix. Since these are a submanifold of ``ℝ^{2nΓ—2n}``, the same method applies for points and tangent vectors. This can also be done in-place of `pX`. From 32aa72e9f7c4d33d3bfe88456c426389865f532c Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 19:40:38 +0100 Subject: [PATCH 61/65] Update src/manifolds/SymplecticGrassmannStiefel.jl Co-authored-by: Mateusz Baran --- src/manifolds/SymplecticGrassmannStiefel.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index 566fd5119b..8a274c5a70 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -127,7 +127,7 @@ end Given a gradient ``Y = \operatorname{grad} \tilde f(p)`` in the embedding ``ℝ^{2nΓ—2k}`` or at least around the [`SymplecticGrassmann`](@ref) `M` where `p` (the embedding of) a point on `M`, -and the restriction ``\tilde f`` to the [`SymplecticStiefel`] be invariant for the equivalence classes. +and the restriction ``\tilde f`` to the [`SymplecticStiefel`](@ref) be invariant for the equivalence classes. In other words ``f(p) = f(qp)`` for ``q \in \mathrm{Sp}(2k, ℝ)``. Then the Riemannian gradient ``X = \operatorname{grad} f(p)`` is given by From cff33871cb96e241198296a24313f1791c6a4275 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 21:13:57 +0100 Subject: [PATCH 62/65] Adress points from code review. --- src/manifolds/Hamiltonian.jl | 5 +++-- src/manifolds/SymplecticGrassmannStiefel.jl | 12 +++--------- test/manifolds/symplecticstiefel.jl | 4 ++-- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/manifolds/Hamiltonian.jl b/src/manifolds/Hamiltonian.jl index 3b203c0586..be0f33539d 100644 --- a/src/manifolds/Hamiltonian.jl +++ b/src/manifolds/Hamiltonian.jl @@ -50,8 +50,9 @@ where ``β‹…^{+}`` denotes the [`symplectic_inverse`](@ref), and ``𝔽 ∈ \{ Though it is slightly redundant, usually the matrices are stored as ``2nΓ—2n`` arrays. -The symbol refers to the main usage within `Manifolds.jl` that is the -Lie algebra to the [`SymplecticMatrices`](@ref) as a Lie group with the matrix operation as group operation. +The symbol ``\mathfak{sp}`` refers to the main usage within `Manifolds.jl` that is the +Lie algebra to the [`SymplecticMatrices`](@ref) interpreted as a Lie group with the +matrix multiplication as group operation. # Constructor diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index 8a274c5a70..4e62f1c277 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -128,7 +128,8 @@ end Given a gradient ``Y = \operatorname{grad} \tilde f(p)`` in the embedding ``ℝ^{2nΓ—2k}`` or at least around the [`SymplecticGrassmann`](@ref) `M` where `p` (the embedding of) a point on `M`, and the restriction ``\tilde f`` to the [`SymplecticStiefel`](@ref) be invariant for the equivalence classes. -In other words ``f(p) = f(qp)`` for ``q \in \mathrm{Sp}(2k, ℝ)``. +In other words ``f(p) = f(qp)`` for ``q \in \mathrm{Sp}(2k, ℝ)``, +where ``\mathrm{Sp}(2k, ℝ)`` denotes the [`SymplecticMatricesMatrices`](@ref) manifold. Then the Riemannian gradient ``X = \operatorname{grad} f(p)`` is given by ```math @@ -138,14 +139,7 @@ Then the Riemannian gradient ``X = \operatorname{grad} f(p)`` is given by where ``J_{2n}`` denotes the [`SymplecticElement`](@ref), and ``H = (I_{2n} - pp^+)J_{2n}^{\mathrm{T}}YJ``. """ -function riemannian_gradient(M::SymplecticGrassmann, p, Y; kwargs...) - n, k = get_parameter(M.size) - J = SymplecticElement(p) - # Since J' = -J We can write (J'YJ) = -J * (YJ) - JTYJ = (-J * (Y * J)) - H = (I - p * symplectic_inverse(p)) * JTYJ - return (-J * (H * J)) * (p' * p) .- JTYJ * (H' * p) -end +riemannian_gradient(M::SymplecticGrassmann, p, Y; kwargs...) function riemannian_gradient!(M::SymplecticGrassmann, X, p, Y; kwargs...) n, k = get_parameter(M.size) diff --git a/test/manifolds/symplecticstiefel.jl b/test/manifolds/symplecticstiefel.jl index f4543f249c..b60fbb3d4f 100644 --- a/test/manifolds/symplecticstiefel.jl +++ b/test/manifolds/symplecticstiefel.jl @@ -212,9 +212,9 @@ end @testset "Generate random points/tangent vectors" begin M_big = SymplecticStiefel(20, 10) p_big = rand(M_big) - @test is_point(M_big, p_big; error=:error, atol=5e-14) + @test is_point(M_big, p_big; error=:error, atol=5e-12) X_big = rand(M_big; vector_at=p_big) - @test is_vector(M_big, p_big, X_big; error=:error, atol=5e-14) + @test is_vector(M_big, p_big, X_big; error=:error, atol=5e-12) end @testset "test_manifold(SymplecticMatrices(6), ...)" begin types = [Matrix{Float64}] From c25e87050041993f535445ea1b30deb902811226 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Wed, 24 Jan 2024 21:26:51 +0100 Subject: [PATCH 63/65] I am not sure which AI / auotcomplete stepped in there :/. --- src/manifolds/SymplecticGrassmannStiefel.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index 4e62f1c277..7a07afbfcb 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -129,7 +129,7 @@ Given a gradient ``Y = \operatorname{grad} \tilde f(p)`` in the embedding ``ℝ^ least around the [`SymplecticGrassmann`](@ref) `M` where `p` (the embedding of) a point on `M`, and the restriction ``\tilde f`` to the [`SymplecticStiefel`](@ref) be invariant for the equivalence classes. In other words ``f(p) = f(qp)`` for ``q \in \mathrm{Sp}(2k, ℝ)``, -where ``\mathrm{Sp}(2k, ℝ)`` denotes the [`SymplecticMatricesMatrices`](@ref) manifold. +where ``\mathrm{Sp}(2k, ℝ)`` denotes the [`SymplecticMatrices`](@ref) manifold. Then the Riemannian gradient ``X = \operatorname{grad} f(p)`` is given by ```math From 6eb0d3eabfe1023e198c620717254606b486092b Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 25 Jan 2024 08:25:23 +0100 Subject: [PATCH 64/65] Rephrase a docstring. --- src/manifolds/SymplecticGrassmannStiefel.jl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/manifolds/SymplecticGrassmannStiefel.jl b/src/manifolds/SymplecticGrassmannStiefel.jl index 8a274c5a70..9f405d08c7 100644 --- a/src/manifolds/SymplecticGrassmannStiefel.jl +++ b/src/manifolds/SymplecticGrassmannStiefel.jl @@ -65,15 +65,22 @@ end @doc raw""" inner(::SymplecticGrassmann, p, X, Y) -Compute the Riemannian inner product ``g^{\mathrm{SpGr}}_p(X,Y)``, where ``p`` -is a point on the [`SymplecticStiefel`](@ref) manifold and ``X,Y \in \mathrm{Hor}_p^Ο€\operatorname{SpSt}(2n,2k)`` -are horizontal tangent vectors. The formula reads according to Proposition Lemma 4.8 [BendokatZimmermann:2021](@cite). +Compute the Riemannian inner product ``g^{\mathrm{SpGr}}_p(X,Y)`` +on the [`SymplecticGrassmann`](@ref) manifold `\mathrm{SpGr}``. + +For the case where ``p`` is represented by a point on the [`SymplecticStiefel`](@ref) manifold +acting as a representant of its equivalence class ``[p] \in \mathrm{SpGr}`` +and the tangent vectors ``X,Y \in \mathrm{Hor}_p^Ο€\operatorname{SpSt}(2n,2k)`` +are horizontal tangent vectors. + +Then the inner product reads according to Proposition Lemma 4.8 [BendokatZimmermann:2021](@cite). ```math g^{\mathrm{SpGr}}_p(X,Y) = \operatorname{tr}\bigl( (p^{\mathrm{T}}p)^{-1}X^{\mathrm{T}}(I_{2n} - pp^+)Y \bigr), ``` + where ``I_{2n}`` denotes the identity matrix and ``(β‹…)^+`` the [`symplectic_inverse`](@ref). """ function inner(M::SymplecticGrassmann, p, X, Y) From 9500bd5ebfda2a75c714a573585fd405f03056e9 Mon Sep 17 00:00:00 2001 From: Ronny Bergmann Date: Thu, 25 Jan 2024 09:21:09 +0100 Subject: [PATCH 65/65] =?UTF-8?q?Fix=20the=20seed,=20raise=20tolerances=20?= =?UTF-8?q?=E2=80=93=C2=A0again.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/manifolds/symplectic.jl | 5 +++-- test/manifolds/symplecticstiefel.jl | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/manifolds/symplectic.jl b/test/manifolds/symplectic.jl index b97db3eaf1..deaa1c8767 100644 --- a/test/manifolds/symplectic.jl +++ b/test/manifolds/symplectic.jl @@ -163,10 +163,11 @@ using ManifoldDiff end @testset "Generate random points/tangent vectors" begin M_big = SymplecticMatrices(20) + Random.seed!(49) p_big = rand(M_big) - @test is_point(M_big, p_big; error=:error, atol=1.0e-12) + @test is_point(M_big, p_big; error=:error, atol=1.0e-9) X_big = rand(M_big; vector_at=p_big) - @test is_vector(M_big, p_big, X_big; error=:error, atol=1.0e-12) + @test is_vector(M_big, p_big, X_big; error=:error, atol=1.0e-9) end @testset "test_manifold(SymplecticMatrices(6))" begin test_manifold( diff --git a/test/manifolds/symplecticstiefel.jl b/test/manifolds/symplecticstiefel.jl index b60fbb3d4f..bee161cd0b 100644 --- a/test/manifolds/symplecticstiefel.jl +++ b/test/manifolds/symplecticstiefel.jl @@ -211,10 +211,11 @@ end end @testset "Generate random points/tangent vectors" begin M_big = SymplecticStiefel(20, 10) + Random.seed!(49) p_big = rand(M_big) - @test is_point(M_big, p_big; error=:error, atol=5e-12) + @test is_point(M_big, p_big; error=:error, atol=1e-9) X_big = rand(M_big; vector_at=p_big) - @test is_vector(M_big, p_big, X_big; error=:error, atol=5e-12) + @test is_vector(M_big, p_big, X_big; error=:error, atol=1e-9) end @testset "test_manifold(SymplecticMatrices(6), ...)" begin types = [Matrix{Float64}]