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 plainAbstractArray
s.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.0
which is a valid point i.e.
is_point(M, p)
true
This 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.0
which 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.0
NestedReplacingPowerRepresentation
The final representation is the NestedReplacingPowerRepresentation
. It is similar to the 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
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 an in-place 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
— TypeArrayPowerRepresentation
Representation 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 <: AbstractMetric
Represent 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
.
ManifoldDiff.riemannian_Hessian
— MethodY = riemannian_Hessian(M::AbstractPowerManifold, p, G, H, X)
riemannian_Hessian!(M::AbstractPowerManifold, Y, p, G, H, X)
Compute the Riemannian Hessian $\operatorname{Hess} f(p)[X]$ given the Euclidean gradient $∇ f(\tilde p)$ in G
and the Euclidean Hessian $∇^2 f(\tilde p)[\tilde X]$ in H
, where $\tilde p, \tilde X$ are the representations of $p,X$ in the embedding,.
On an abstract power manifold, this decouples and can be computed 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.manifold_volume
— Methodmanifold_volume(M::PowerManifold)
Return the manifold volume of an PowerManifold
M
.
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
).
Manifolds.volume_density
— Methodvolume_density(M::PowerManifold, p, X)
Return volume density on the PowerManifold
M
, i.e. product of constituent volume densities.
ManifoldsBase.Weingarten
— MethodY = Weingarten(M::AbstractPowerManifold, p, X, V)
Weingarten!(M::AbstractPowerManifold, Y, p, X, V)
Since the metric decouples, also the computation of the Weingarten map $\mathcal W_p$ can be computed elementwise on the single elements of the PowerManifold
M
.
ManifoldsBase.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.
ManifoldsBase.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