Power manifold
A power manifold is based on a AbstractManifold $\mathcal M$ to build a $\mathcal M^{n_1 \times n_2 \times \cdots \times 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.
There are three available representations for points and vectors on a power manifold:
ArrayPowerRepresentation(the default one), very efficient but only applicable when points on the underlying manifold are represented using plainAbstractArrays.NestedPowerRepresentation, applicable to any manifold. It assumes that points on the underlying manifold are represented using mutable data types.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, we store the data in a multidimensional array,
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)3×4 Matrix{Float64}:
1.0 0.707107 0.707107 0.0
0.0 0.707107 0.0 1.0
0.0 0.0 0.707107 0.0which is a valid point i.e.
is_point(M, p)trueThis can also be used in combination with HybridArrays.jl and StaticArrays.jl, by setting
using HybridArrays, StaticArrays
q = HybridArray{Tuple{3,StaticArrays.Dynamic()},Float64,2}(p)3×4 HybridArrays.HybridMatrix{3, StaticArraysCore.Dynamic(), Float64, 2, Matrix{Float64}} with indices SOneTo(3)×Base.OneTo(4):
1.0 0.707107 0.707107 0.0
0.0 0.707107 0.0 1.0
0.0 0.0 0.707107 0.0which is still a valid point on M and PowerManifold works with these, too.
An advantage of this representation is that it is quite efficient, especially when a HybridArray (from the 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 we can now do
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],
]4-element Vector{Vector{Float64}}:
[1.0, 0.0, 0.0]
[0.7071067811865475, 0.7071067811865475, 0.0]
[0.7071067811865475, 0.0, 0.7071067811865475]
[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 and set_component! functions. They work work both point representations.
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)3-element Vector{Float64}:
0.0
0.0
1.0NestedReplacingPowerRepresentation
The final representation is the NestedReplacingPowerRepresentation. It is similar to the NestedPowerRepresentation but it does not perform mutating operations on the points on the underlying manifold. The example below uses this representation to store points on a power manifold of the SpecialEuclidean 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) in the sense that the elements of the main vector are immutable, then changing the elements can not be done in a mutating way and hence NestedReplacingPowerRepresentation has to be used.
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 = [ProductRepr(SVector{2,Float64}([i - 0.1, -i]), SMatrix{2,2,Float64}(exp(R2, q, hat(R2, q, i)))) for i in 1:N]
p2 = [ProductRepr(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)5-element Vector{ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}}:
ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}(([0.0, 0.0], [0.0 2.0; -2.0 0.0]))
ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}(([0.0, 0.0], [0.0 -2.2831853071795862; 2.2831853071795862 0.0]))
ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}(([0.0, 0.0], [0.0 -0.28318530717958645; 0.28318530717958645 0.0]))
ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}(([0.0, 0.0], [0.0 1.7168146928204135; -1.7168146928204135 0.0]))
ProductRepr{Tuple{StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}(([0.0, 0.0], [0.0 -2.566370614359173; 2.566370614359173 0.0]))Types and Functions
Manifolds.ArrayPowerRepresentation — TypeArrayPowerRepresentationRepresentation of points and tangent vectors on a power manifold using multidimensional arrays where first dimensions are equal to representation_size of the wrapped manifold and the following ones are equal to the number of elements in each direction.
Torus uses this representation.
Manifolds.PowerFVectorDistribution — TypePowerFVectorDistribution([type::VectorBundleFibers], [x], distr)Generates a random vector at a point from vector space (a fiber of a tangent bundle) of type type using the power distribution of distr.
Vector space type and point can be automatically inferred from distribution distr.
Manifolds.PowerMetric — TypePowerMetric <: AbstractMetricRepresent the AbstractMetric on an AbstractPowerManifold, i.e. the inner product on the tangent space is the sum of the inner product of each elements tangent space of the power manifold.
Manifolds.PowerPointDistribution — TypePowerPointDistribution(M::AbstractPowerManifold, distribution)Power distribution on manifold M, based on distribution.
Manifolds.change_metric — Methodchange_metric(M::AbstractPowerManifold, ::AbstractMetric, p, X)Since the metric on a power manifold decouples, the change of metric can be done elementwise.
Manifolds.change_representer — Methodchange_representer(M::AbstractPowerManifold, ::AbstractMetric, p, X)Since the metric on a power manifold decouples, the change of a representer can be done elementwise
Manifolds.flat — Methodflat(M::AbstractPowerManifold, p, X)use the musical isomorphism to transform the tangent vector X from the tangent space at p on an AbstractPowerManifold M to a cotangent vector. This can be done elementwise for each entry of X (and p).
Manifolds.sharp — Methodsharp(M::AbstractPowerManifold, p, ξ::RieszRepresenterCotangentVector)Use the musical isomorphism to transform the cotangent vector ξ from the tangent space at p on an AbstractPowerManifold M to a tangent vector. This can be done elementwise for every entry of ξ (and p).