Power manifold

A power manifold is based on a Manifold $\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.

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.

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 Array{Float64,2}:
 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_manifold_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.HybridArray{Tuple{3,StaticArrays.Dynamic()},Float64,2,2,Array{Float64,2}} 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.

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 Array{Array{Float64,1},1}:
 [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_manifold_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 view(::Array{Float64,1}, :) with eltype Float64:
 0.0
 0.0
 1.0

Types and Functions

Manifolds.ArrayPowerRepresentationType
ArrayPowerRepresentation

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.

source
Manifolds.PowerFVectorDistributionType
PowerFVectorDistribution([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.

source
Manifolds.PowerManifoldType
PowerManifold{𝔽,TM<:Manifold,TSize<:Tuple,TPR<:AbstractPowerRepresentation} <: AbstractPowerManifold{𝔽,TM}

The power manifold $\mathcal M^{n_1× n_2 × … × n_d}$ with power geometry TSize statically defines the number of elements along each axis.

For example, a manifold-valued time series would be represented by a power manifold with $d$ equal to 1 and $n_1$ equal to the number of samples. A manifold-valued image (for example in diffusion tensor imaging) would be represented by a two-axis power manifold ($d=2$) with $n_1$ and $n_2$ equal to width and height of the image.

While the size of the manifold is static, points on the power manifold would not be represented by statically-sized arrays. Operations on small power manifolds might be faster if they are represented as ProductManifold.

Constructor

PowerManifold(M, N_1, N_2, ..., N_d)
PowerManifold(M, NestedPowerRepresentation(), N_1, N_2, ..., N_d)
M^(N_1, N_2, ..., N_d)

Generate the power manifold $M^{N_1 × N_2 × … × N_d}$. By default, the ArrayPowerRepresentation of points and tangent vectors is used, although a different one, for example NestedPowerRepresentation, can be given as the second argument to the constructor. When M is a PowerManifold (not any AbstractPowerManifold) itself, given dimensions will be appended to the dimensions already present, for example PowerManifold(PowerManifold(Sphere(2), 2), 3) is equivalent to PowerManifold(Sphere(2), 2, 3). This feature preserves the representation of the inner power manifold (unless it's explicitly overridden).

source
Base.expMethod
exp(M::AbstractPowerManifold, p, X)

Compute the exponential map from p in direction X on the AbstractPowerManifold M, which can be computed using the base manifolds exponential map elementwise.

source
Base.getindexMethod
getindex(p, M::AbstractPowerManifold, i::Union{Integer,Colon,AbstractVector}...)
p[M::AbstractPowerManifold, i...]

Access the element(s) at index [i...] of a point p on an AbstractPowerManifold M by linear or multidimensional indexing. See also Array Indexing in Julia.

source
Base.logMethod
log(M::AbstractPowerManifold, p, q)

Compute the logarithmic map from p to q on the AbstractPowerManifold M, which can be computed using the base manifolds logarithmic map elementwise.

source
Base.setindex!Method
setindex!(q, p, M::AbstractPowerManifold, i::Union{Integer,Colon,AbstractVector}...)
q[M::AbstractPowerManifold, i...] = p

Set the element(s) at index [i...] of a point q on an AbstractPowerManifold M by linear or multidimensional indexing to q. See also Array Indexing in Julia.

source
Base.viewMethod
view(p, M::AbstractPowerManifold, i::Union{Integer,Colon,AbstractVector}...)

Get the view of the element(s) at index [i...] of a point p on an AbstractPowerManifold M by linear or multidimensional indexing.

source
Manifolds.flatMethod
flat(M::AbstractPowerManifold, p, X::FVector{TangentSpaceType})

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).

source
Manifolds.sharpMethod
sharp(M::AbstractPowerManifold, p, ξ::FVector{CotangentSpaceType})

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).

source
ManifoldsBase.check_manifold_pointMethod
check_manifold_point(M::AbstractProductManifold, p; kwargs...)

Check whether p is a valid point on an AbstractPowerManifold M, i.e. each element of p has to be a valid point on the base manifold. If p is not a point on M a CompositeManifoldError consisting of all error messages of the components, for which the tests fail is returned.

The tolerance for the last test can be set using the kwargs....

source
ManifoldsBase.check_tangent_vectorMethod
check_tangent_vector(M::AbstractPowerManifold, p, X; check_base_point = true, kwargs... )

Check whether X is a tangent vector to p an the AbstractPowerManifold M, i.e. atfer check_manifold_point(M, p), and all projections to base manifolds must be respective tangent vectors. The optional parameter check_base_point indicates, whether to call check_manifold_point for p. If X is not a tangent vector to p on M a CompositeManifoldError consisting of all error messages of the components, for which the tests fail is returned.

The tolerance for the last test can be set using the kwargs....

source
ManifoldsBase.innerMethod
inner(M::AbstractPowerManifold, p, X, Y)

Compute the inner product of X and Y from the tangent space at p on an AbstractPowerManifold M, i.e. for each arrays entry the tangent vector entries from X and Y are in the tangent space of the corresponding element from p. The inner product is then the sum of the elementwise inner products.

source
ManifoldsBase.inverse_retractMethod
inverse_retract(M::AbstractPowerManifold, p, q, m::InversePowerRetraction)

Compute the inverse retraction from p with respect to q on an AbstractPowerManifold M using an InversePowerRetraction, which by default encapsulates a inverse retraction of the base manifold. Then this method is performed elementwise, so the encapsulated inverse retraction method has to be one that is available on the base Manifold.

source
ManifoldsBase.manifold_dimensionMethod
manifold_dimension(M::PowerManifold)

Returns the manifold-dimension of an PowerManifold M $=\mathcal N = (\mathcal M)^{n_1,…,n_d}$, i.e. with $n=(n_1,…,n_d)$ the array size of the power manifold and $d_{\mathcal M}$ the dimension of the base manifold $\mathcal M$, the manifold is of dimension

\[\dim(\mathcal N) = \dim(\mathcal M)\prod_{i=1}^d n_i = n_1n_2\cdot…\cdot n_d \dim(\mathcal M).\]
source
ManifoldsBase.retractMethod
retract(M::AbstractPowerManifold, p, X, method::PowerRetraction)

Compute the retraction from p with tangent vector X on an AbstractPowerManifold M using a PowerRetraction, which by default encapsulates a retraction of the base manifold. Then this method is performed elementwise, so the encapsulated retraction method has to be one that is available on the base Manifold.

source