# Manifolds

While the interface `ManifoldsBase.jl`

does not cover concrete manifolds, it provides a few helpers to build or create manifolds based on existing manifolds

## (Abstract) power manifold

A power manifold is constructed like higher dimensional vector spaces are formed from the real line, just that for every point $p = (p_1,\ldots,p_n) ∈ \mathcal M^n$ on the power manifold $\mathcal M^n$ the entries of $p$ are points $p_1,\ldots,p_n ∈ \mathcal M$ on some manifold $\mathcal M$. Note that $n$ can also be replaced by multiple values, such that $p$ is not a vector but a matrix or a multi-index array of points.

`ManifoldsBase.AbstractPowerManifold`

— Type`AbstractPowerManifold{𝔽,M,TPR} <: AbstractManifold{𝔽}`

An abstract `AbstractManifold`

to represent manifolds that are build as powers of another `AbstractManifold`

`M`

with representation type `TPR`

, a subtype of `AbstractPowerRepresentation`

.

`ManifoldsBase.AbstractPowerRepresentation`

— Type`AbstractPowerRepresentation`

An abstract representation type of points and tangent vectors on a power manifold.

`ManifoldsBase.NestedPowerRepresentation`

— Type`NestedPowerRepresentation`

Representation of points and tangent vectors on a power manifold using arrays of size equal to `TSize`

of a `PowerManifold`

. Each element of such array stores a single point or tangent vector.

For modifying operations, each element of the outer array is modified in-place, differently than in `NestedReplacingPowerRepresentation`

.

`ManifoldsBase.NestedReplacingPowerRepresentation`

— Type`NestedReplacingPowerRepresentation`

Representation of points and tangent vectors on a power manifold using arrays of size equal to `TSize`

of a `PowerManifold`

. Each element of such array stores a single point or tangent vector.

For modifying operations, each element of the outer array is replaced using non-modifying operations, differently than for `NestedReplacingPowerRepresentation`

.

`ManifoldsBase.PowerBasisData`

— Type`PowerBasisData{TB<:AbstractArray}`

Data storage for an array of basis data.

`ManifoldsBase.PowerManifold`

— Type`PowerManifold{𝔽,TM<:AbstractManifold,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.

**Constructor**

```
PowerManifold(M::PowerManifold, N_1, N_2, ..., N_d)
PowerManifold(M::AbstractManifold, 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, a [`PowerManifold`

](@ref} is expanded further, i.e. for `M=PowerManifold(N,3)`

`PowerManifold(M,2)`

is equivalend to `PowerManifold(N,3,2)`

. Points are then 3×2 matrices of points on `N`

. Providing a `NestedPowerRepresentation`

as the second argument to the constructor can be used to nest manifold, i.e. `PowerManifold(M,NestedPowerRepresentation(),2)`

represents vectors of length 2 whose elements are vectors of length 3 of points on N in a nested array representation.

Since there is no default `AbstractPowerRepresentation`

within this interface, the `^`

operator is only available for `PowerManifold`

s and concatenates dimensions.

`Base.copyto!`

— Method`copyto!(M::PowerManifoldNested, Y, p, X)`

Copy the values elementwise, i.e. call `copyto!(M.manifold, B, a, A)`

for all elements `A`

, `a`

and `B`

of `X`

, `p`

, and `Y`

, respectively.

`Base.copyto!`

— Method`copyto!(M::PowerManifoldNested, q, p)`

Copy the values elementwise, i.e. call `copyto!(M.manifold, b, a)`

for all elements `a`

and `b`

of `p`

and `q`

, respectively.

`Base.exp`

— Method`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.

`Base.getindex`

— Method```
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.

`Base.log`

— Method`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.

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

`Base.view`

— Method`view(p, M::PowerManifoldNested, 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.

`LinearAlgebra.norm`

— Method`norm(M::AbstractPowerManifold, p, X)`

Compute the norm of `X`

from the tangent space of `p`

on an `AbstractPowerManifold`

`M`

, i.e. from the element wise norms the Frobenius norm is computed.

`ManifoldsBase._allocate_access_nested`

— Method`_allocate_access_nested(M::PowerManifoldNested, y, i)`

Helper function for `allocate_result`

on `PowerManifoldNested`

. In allocation `y`

can be a number in which case `_access_nested`

wouldn't work.

`ManifoldsBase.check_point`

— Method`check_point(M::AbstractPowerManifold, 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...`

.

`ManifoldsBase.check_power_size`

— Method```
check_power_size(M, p)
check_power_size(M, p, X)
```

Check whether p hase the right size to represent points on M generically, i.e. just cheking the overall sizes, not the individual ones per manifold

`ManifoldsBase.check_vector`

— Method`check_vector(M::AbstractPowerManifold, p, X; kwargs... )`

Check whether `X`

is a tangent vector to `p`

an the `AbstractPowerManifold`

`M`

, i.e. atfer `check_point`

`(M, p)`

, and all projections to base manifolds must be respective tangent vectors. 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...`

.

`ManifoldsBase.default_inverse_retraction_method`

— Method`default_inverse_retraction_method(M::PowerManifold)`

Use the default inverse retraction method of the internal `M.manifold`

also in defaults of functions defined for the power manifold, meaning that this is used elementwise.

`ManifoldsBase.default_retraction_method`

— Method`default_retraction_method(M::PowerManifold)`

Use the default retraction method of the internal `M.manifold`

also in defaults of functions defined for the power manifold, meaning that this is used elementwise.

`ManifoldsBase.default_vector_transport_method`

— Method`default_vector_transport_method(M::PowerManifold)`

Use the default vector transport method of the internal `M.manifold`

also in defaults of functions defined for the power manifold, meaning that this is used elementwise.

`ManifoldsBase.distance`

— Method`distance(M::AbstractPowerManifold, p, q)`

Compute the distance between `q`

and `p`

on an `AbstractPowerManifold`

, i.e. from the element wise distances the Forbenius norm is computed.

`ManifoldsBase.get_component`

— Method`get_component(M::AbstractPowerManifold, p, idx...)`

Get the component of a point `p`

on an `AbstractPowerManifold`

`M`

at index `idx`

.

`ManifoldsBase.injectivity_radius`

— Method`injectivity_radius(M::AbstractPowerManifold[, p])`

the injectivity radius on an `AbstractPowerManifold`

is for the global case equal to the one of its base manifold. For a given point `p`

it's equal to the minimum of all radii in the array entries.

`ManifoldsBase.inner`

— Method`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.

`ManifoldsBase.inverse_retract`

— Method`inverse_retract(M::AbstractPowerManifold, p, q, m::AbstractInverseRetractionMethod)`

Compute the inverse retraction from `p`

with respect to `q`

on an `AbstractPowerManifold`

`M`

using an `AbstractInverseRetractionMethod`

. Then this method is performed elementwise, so the inverse retraction method has to be one that is available on the base `AbstractManifold`

.

`ManifoldsBase.is_flat`

— Method`is_flat(M::AbstractPowerManifold)`

Return true if `AbstractPowerManifold`

is flat. It is flat if and only if the wrapped manifold is flat.

`ManifoldsBase.manifold_dimension`

— Method`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).\]

`ManifoldsBase.power_dimensions`

— Method`power_dimensions(M::PowerManifold)`

return the power of `M`

,

`ManifoldsBase.project`

— Method`project(M::AbstractPowerManifold, p, X)`

Project the point `X`

onto the tangent space at `p`

on the `AbstractPowerManifold`

`M`

by projecting all components.

`ManifoldsBase.project`

— Method`project(M::AbstractPowerManifold, p)`

Project the point `p`

from the embedding onto the `AbstractPowerManifold`

`M`

by projecting all components.

`ManifoldsBase.retract`

— Method`retract(M::AbstractPowerManifold, p, X, method::AbstractRetractionMethod)`

Compute the retraction from `p`

with tangent vector `X`

on an `AbstractPowerManifold`

`M`

using a `AbstractRetractionMethod`

. Then this method is performed elementwise, so the retraction method has to be one that is available on the base `AbstractManifold`

.

`ManifoldsBase.riemann_tensor`

— Method`riemann_tensor(M::AbstractPowerManifold, p, X, Y, Z)`

Compute the Riemann tensor at point from `p`

with tangent vectors `X`

, `Y`

and `Z`

on the `AbstractPowerManifold`

`M`

.

`ManifoldsBase.set_component!`

— Method`set_component!(M::AbstractPowerManifold, q, p, idx...)`

Set the component of a point `q`

on an `AbstractPowerManifold`

`M`

at index `idx`

to `p`

, which itself is a point on the `AbstractManifold`

the power manifold is build on.

`ManifoldsBase.vector_transport_to`

— Method`vector_transport_to(M::AbstractPowerManifold, p, X, q, method::AbstractVectorTransportMethod)`

Compute the vector transport the tangent vector `X`

at `p`

to `q`

on the `PowerManifold`

`M`

using an `AbstractVectorTransportMethod`

`m`

. This method is performed elementwise, i.e. the method `m`

has to be implemented on the base manifold.

`ValidationManifold`

`ValidationManifold`

is a simple decorator using the `AbstractDecoratorManifold`

that “decorates” a manifold with tests that all involved points and vectors are valid for the wrapped manifold. For example involved input and output paratemers are checked before and after running a function, repectively. This is done by calling `is_point`

or `is_vector`

whenever applicable.

`ManifoldsBase.ValidationCoTVector`

— Type`ValidationCoTVector = ValidationFibreVector{CotangentSpaceType}`

Represent a cotangent vector to a point on an `ValidationManifold`

, i.e. on a manifold where data can be represented by arrays. The array is stored internally and semantically. This distinguished the value from `ValidationMPoint`

s vectors of other types.

`ManifoldsBase.ValidationFibreVector`

— Type`ValidationFibreVector{TType<:VectorSpaceType} <: AbstractFibreVector{TType}`

Represent a tangent vector to a point on an `ValidationManifold`

, i.e. on a manifold where data can be represented by arrays. The array is stored internally and semantically. This distinguished the value from `ValidationMPoint`

s vectors of other types.

`ManifoldsBase.ValidationMPoint`

— Type`ValidationMPoint <: AbstractManifoldPoint`

Represent a point on an `ValidationManifold`

, i.e. on a manifold where data can be represented by arrays. The array is stored internally and semantically. This distinguished the value from `ValidationTVector`

s and `ValidationCoTVector`

s.

`ManifoldsBase.ValidationManifold`

— Type`ValidationManifold{𝔽,M<:AbstractManifold{𝔽}} <: AbstractDecoratorManifold{𝔽}`

A manifold to encapsulate manifolds working on array representations of `AbstractManifoldPoint`

s and `TVector`

s in a transparent way, such that for these manifolds it's not necessary to introduce explicit types for the points and tangent vectors, but they are encapsulated/stripped automatically when needed.

This manifold is a decorator for a manifold, i.e. it decorates a `AbstractManifold`

`M`

with types points, vectors, and covectors.

`ManifoldsBase.ValidationTVector`

— Type`ValidationTVector = ValidationFibreVector{TangentSpaceType}`

Represent a tangent vector to a point on an `ValidationManifold`

, i.e. on a manifold where data can be represented by arrays. The array is stored internally and semantically. This distinguished the value from `ValidationMPoint`

s vectors of other types.

`ManifoldsBase.array_value`

— Method`array_value(p)`

Return the internal array value of an `ValidationMPoint`

, `ValidationTVector`

, or `ValidationCoTVector`

if the value `p`

is encapsulated as such. Return `p`

if it is already an array.

`DefaultManifold`

`DefaultManifold`

is a simplified version of `Euclidean`

and demonstrates a basic interface implementation. It can be used to perform simple tests. Since when using `Manifolds.jl`

the `Euclidean`

is available, the `DefaultManifold`

itself is not exported.

`ManifoldsBase.DefaultManifold`

— Type`DefaultManifold <: AbstractManifold`

This default manifold illustrates the main features of the interface and provides a skeleton to build one's own manifold. It is a simplified/shortened variant of `Euclidean`

from `Manifolds.jl`

.

This manifold further illustrates how to type your manifold points and tangent vectors. Note that the interface does not require this, but it might be handy in debugging and educative situations to verify correctness of involved variabes.

## Embedded manifold

The embedded manifold is a manifold $\mathcal M$ which is modelled *explicitly* specifying its embedding $\mathcal N$ in which the points and tangent vectors are represented. Most prominently `is_point`

and `is_vector`

of an embedded manifold are implemented to check whether the point is a valid point in the embedding. This can of course still be extended by further tests. `ManifoldsBase.jl`

provides two possibilities of easily introducing this in order to dispatch some functions to the embedding.

### Implicit case: the `IsEmbeddedManifold`

Trait

For the implicit case, your manifold has to be a subtype of the `AbstractDecoratorManifold`

. Adding a method to the `active_traits`

function for a manifold that returns an `AbstractTrait`

`IsEmbeddedManifold`

, makes that manifold an embedded manifold. You just have to also define `get_embedding`

so that appropriate functions are passed on to that embedding. This is the implicit case, since the manifold type itself does not carry any information about the embedding, just the trait and the function definition do.

### Explicit case: the `EmbeddedManifold`

The `EmbeddedManifold`

itself is an `AbstractDecoratorManifold`

so it is a case of the implicit embedding itself, but internally stores both the original manifold and the embedding. They are also parameters of the type. This way, an additional embedding of one manifold in another can be modelled. That is, if the manifold is implemented using the implicit embedding approach from before but can also be implemented using a *different* embedding, then this method should be chosen, since you can dispatch functions that you want to implement in this embedding then on the type which explicitly has the manifold and its embedding as parameters.

Hence this case should be used for any further embedding after the first or if the default implementation works without an embedding and the alternative needs one.

`ManifoldsBase.EmbeddedManifold`

— Type`EmbeddedManifold{𝔽, MT <: AbstractManifold, NT <: AbstractManifold} <: AbstractDecoratorManifold{𝔽}`

A type to represent an explicit embedding of a `AbstractManifold`

`M`

of type `MT`

embedded into a manifold `N`

of type `NT`

. By default, an embedded manifold is set to be embedded, but neither isometrically embedded nor a submanifold.

This type is not required if a manifold `M`

is to be embedded in one specific manifold `N`

. One can then just implement `embed!`

and `project!`

. You can further pass functions to the embedding, for example, when it is an isometric embedding, by using an `AbstractDecoratorManifold`

. Only for a second –maybe considered non-default– embedding, this type should be considered in order to dispatch on different embed and project methods for different embeddings `N`

.

**Fields**

`manifold`

the manifold that is an embedded manifold`embedding`

a second manifold, the first one is embedded into

**Constructor**

`EmbeddedManifold(M, N)`

Generate the `EmbeddedManifold`

of the `AbstractManifold`

`M`

into the `AbstractManifold`

`N`

.

`ManifoldsBase.decorated_manifold`

— Method`decorated_manifold(M::EmbeddedManifold, d::Val{N} = Val(-1))`

Return the manifold of `M`

that is decorated with its embedding. For this specific type the internally stored enhanced manifold `M.manifold`

is returned.

See also `base_manifold`

, where this is used to (potentially) completely undecorate the manifold.

`ManifoldsBase.get_embedding`

— Method`get_embedding(M::EmbeddedManifold)`

Return the embedding `AbstractManifold`

`N`

of `M`

, if it exists.

## Metrics

Most metric-related functionality is currently defined in `Manifolds.jl`

but a few basic types are defined here.

`ManifoldsBase.AbstractMetric`

— Type`AbstractMetric`

Abstract type for the pseudo-Riemannian metric tensor $g$, a family of smoothly varying inner products on the tangent space. See `inner`

.

**Functor**

```
(metric::Metric)(M::AbstractManifold)
(metric::Metric)(M::MetricManifold)
```

Generate the `MetricManifold`

that wraps the manifold `M`

with given `metric`

. This works for both a variable containing the metric as well as a subtype `T<:AbstractMetric`

, where a zero parameter constructor `T()`

is availabe. If `M`

is already a metric manifold, the inner manifold with the new `metric`

is returned.

`ManifoldsBase.EuclideanMetric`

— Type`EuclideanMetric <: RiemannianMetric`

A general type for any manifold that employs the Euclidean Metric, for example the `Euclidean`

manifold itself, or the `Sphere`

, where every tangent space (as a plane in the embedding) uses this metric (in the embedding).

Since the metric is independent of the field type, this metric is also used for the Hermitian metrics, i.e. metrics that are analogous to the `EuclideanMetric`

but where the field type of the manifold is `ℂ`

.

This metric is the default metric for example for the `Euclidean`

manifold.

`ManifoldsBase.RiemannianMetric`

— Type`RiemannianMetric <: AbstractMetric`

Abstract type for Riemannian metrics, a family of positive definite inner products. The positive definite property means that for $X ∈ T_p \mathcal M$, the inner product $g(X, X) > 0$ whenever $X$ is not the zero vector.

`ManifoldsBase.change_metric!`

— Method`change_metric!(M::AbstractcManifold, Y, G2::AbstractMetric, p, X)`

Compute the `change_metric`

in place of `Y`

.

`ManifoldsBase.change_metric`

— Method`change_metric(M::AbstractcManifold, G2::AbstractMetric, p, X)`

On the `AbstractManifold`

`M`

with implicitly given metric $g_1$ and a second `AbstractMetric`

$g_2$ this function performs a change of metric in the sense that it returns the tangent vector $Z=BX$ such that the linear map $B$ fulfills

\[g_2(Y_1,Y_2) = g_1(BY_1,BY_2) \quad \text{for all } Y_1, Y_2 ∈ T_p\mathcal M.\]

`ManifoldsBase.change_representer!`

— Method`change_representer!(M::AbstractcManifold, Y, G2::AbstractMetric, p, X)`

Compute the `change_metric`

in place of `Y`

.

`ManifoldsBase.change_representer`

— Method`change_representer(M::AbstractManifold, G2::AbstractMetric, p, X)`

Convert the representer `X`

of a linear function (in other words a cotangent vector at `p`

) in the tangent space at `p`

on the `AbstractManifold`

`M`

given with respect to the `AbstractMetric`

`G2`

into the representer with respect to the (implicit) metric of `M`

.

In order to convert `X`

into the representer with respect to the (implicitly given) metric $g_1$ of `M`

, we have to find the conversion function $c: T_p\mathcal M \to T_p\mathcal M$ such that

\[ g_2(X,Y) = g_1(c(X),Y)\]