# Functions on manifolds

This page collects several basic functions on manifolds.

## The exponential map, the logarithmic map, and geodesics

Geodesics are the generalizations of a straight line to manifolds, i.e. their intrinsic acceleration is zero. Together with geodesics one also obtains the exponential map and its inverse, the logarithmic map. Informally speaking, the exponential map takes a vector (think of a direction and a length) at one point and returns another point, which lies towards this direction at distance of the specified length. The logarithmic map does the inverse, i.e. given two points, it tells which vector “points towards” the other point.

`Base.exp`

— Method```
exp(M::AbstractManifold, p, X)
exp(M::AbstractManifold, p, X, t::Real = 1)
```

Compute the exponential map of tangent vector `X`

, optionally scaled by `t`

, at point `p`

from the manifold `AbstractManifold`

`M`

, i.e.

\[\exp_p X = γ_{p,X}(1),\]

where $γ_{p,X}$ is the unique geodesic starting in $γ(0)=p$ such that $\dot γ(0) = X$.

See also `shortest_geodesic`

, `retract`

.

`Base.log`

— Method`log(M::AbstractManifold, p, q)`

Compute the logarithmic map of point `q`

at base point `p`

on the `AbstractManifold`

`M`

. The logarithmic map is the inverse of the `exp`

onential map. Note that the logarithmic map might not be globally defined.

See also `inverse_retract`

.

`ManifoldsBase.exp!`

— Method```
exp!(M::AbstractManifold, q, p, X)
exp!(M::AbstractManifold, q, p, X, t::Real = 1)
```

Compute the exponential map of tangent vector `X`

, optionally scaled by `t`

, at point `p`

from the manifold `AbstractManifold`

`M`

. The result is saved to `q`

.

See also `exp`

.

`ManifoldsBase.geodesic!`

— Method`geodesic!(M::AbstractManifold, Q, p, X, T::AbstractVector) -> AbstractVector`

Get the geodesic with initial point `p`

and velocity `X`

on the `AbstractManifold`

`M`

. A geodesic is a curve of zero acceleration. That is for the curve $γ_{p,X}: I → \mathcal M$, with $γ_{p,X}(0) = p$ and $\dot γ_{p,X}(0) = X$ a geodesic further fulfills

\[∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,\]

i.e. the curve is acceleration free with respect to the Riemannian metric. This function evaluates the geodeic at time points `t`

fom `T`

in place of `Q`

.

`ManifoldsBase.geodesic!`

— Method`geodesic!(M::AbstractManifold, q, p, X, t::Real)`

Get the geodesic with initial point `p`

and velocity `X`

on the `AbstractManifold`

`M`

. A geodesic is a curve of zero acceleration. That is for the curve $γ_{p,X}: I → \mathcal M$, with $γ_{p,X}(0) = p$ and $\dot γ_{p,X}(0) = X$ a geodesic further fulfills

\[∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,\]

i.e. the curve is acceleration free with respect to the Riemannian metric. This function evaluates the geodeic at `t`

in place of `q`

.

`ManifoldsBase.geodesic!`

— Method`geodesic!(M::AbstractManifold, p, X) -> Function`

Get the geodesic with initial point `p`

and velocity `X`

on the `AbstractManifold`

`M`

. A geodesic is a curve of zero acceleration. That is for the curve $γ_{p,X}: I → \mathcal M$, with $γ_{p,X}(0) = p$ and $\dot γ_{p,X}(0) = X$ a geodesic further fulfills

\[∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,\]

i.e. the curve is acceleration free with respect to the Riemannian metric. This yields that the curve has constant velocity and is locally distance-minimizing.

This function returns a function `(q,t)`

of (time) `t`

that mutates `q`

`.

`ManifoldsBase.geodesic`

— Method`geodesic(M::AbstractManifold, p, X, T::AbstractVector) -> AbstractVector`

Evaluate the geodesic $γ_{p,X}: I → \mathcal M$, with $γ_{p,X}(0) = p$ and $\dot γ_{p,X}(0) = X$ a geodesic further fulfills

\[∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,\]

at time points `t`

from `T`

.

`ManifoldsBase.geodesic`

— Method`geodesic(M::AbstractManifold, p, X, t::Real)`

Evaluate the geodesic $γ_{p,X}: I → \mathcal M$, with $γ_{p,X}(0) = p$ and $\dot γ_{p,X}(0) = X$ a geodesic further fulfills

\[∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,\]

at time `t`

.

`ManifoldsBase.geodesic`

— Method`geodesic(M::AbstractManifold, p, X) -> Function`

`p`

and velocity `X`

on the `AbstractManifold`

`M`

. A geodesic is a curve of zero acceleration. That is for the curve $γ_{p,X}: I → \mathcal M$, with $γ_{p,X}(0) = p$ and $\dot γ_{p,X}(0) = X$ a geodesic further fulfills

\[∇_{\dot γ_{p,X}(t)} \dot γ_{p,X}(t) = 0,\]

i.e. the curve is acceleration free with respect to the Riemannian metric. This yields, that the curve has constant velocity that is locally distance-minimizing.

This function returns a function of (time) `t`

.

`ManifoldsBase.log!`

— Method`log!(M::AbstractManifold, X, p, q)`

Compute the logarithmic map of point `q`

at base point `p`

on the `AbstractManifold`

`M`

. The result is saved to `X`

. The logarithmic map is the inverse of the `exp!`

onential map. Note that the logarithmic map might not be globally defined.

see also `log`

and `inverse_retract!`

,

`ManifoldsBase.shortest_geodesic!`

— Method`shortest_geodesic!(M::AbstractManifold, R, p, q, T::AbstractVector) -> AbstractVector`

Evaluate a `geodesic`

$γ_{p,q}(t)$ whose length is the shortest path between the points `p`

and `q`

, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$ at all `t`

from `T`

in place of `R`

. When there are multiple shortest geodesics, a deterministic choice will be taken.

`ManifoldsBase.shortest_geodesic!`

— Method`shortest_geodesic!(M::AabstractManifold, r, p, q, t::Real)`

Evaluate a `geodesic`

$γ_{p,q}(t)$ whose length is the shortest path between the points `p`

and `q`

, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$ at `t`

in place of `r`

. When there are multiple shortest geodesics, a deterministic choice will be taken.

`ManifoldsBase.shortest_geodesic!`

— Method`shortest_geodesic!(M::AbstractManifold, p, q) -> Function`

Get a `geodesic`

$γ_{p,q}(t)$ whose length is the shortest path between the points `p`

and `q`

, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$. When there are multiple shortest geodesics, a deterministic choice will be returned.

This function returns a function `(r,t) -> ...`

of time `t`

which works in place of `r`

.

Further variants

```
shortest_geodesic!(M::AabstractManifold, r, p, q, t::Real)
shortest_geodesic!(M::AbstractManifold, R, p, q, T::AbstractVector) -> AbstractVector
```

mutate (and return) the point `r`

and the vector of points `R`

, respectively, returning the point at time `t`

or points at times `t`

in `T`

along the shortest `geodesic`

.

`ManifoldsBase.shortest_geodesic`

— Method`shortest_geodesic(M::AbstractManifold, p, q, T::AbstractVector) -> AbstractVector`

Evaluate a `geodesic`

$γ_{p,q}(t)$ whose length is the shortest path between the points `p`

and `q`

, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$ at time points `T`

. When there are multiple shortest geodesics, a deterministic choice will be returned.

`ManifoldsBase.shortest_geodesic`

— Method`shortest_geodesic(M::AabstractManifold, p, q, t::Real)`

Evaluate a `geodesic`

$γ_{p,q}(t)$ whose length is the shortest path between the points `p`

and `q`

, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$ at time `t`

. When there are multiple shortest geodesics, a deterministic choice will be returned.

`ManifoldsBase.shortest_geodesic`

— Method`shortest_geodesic(M::AbstractManifold, p, q) -> Function`

Get a `geodesic`

$γ_{p,q}(t)$ whose length is the shortest path between the points `p`

and `q`

, where $γ_{p,q}(0)=p$ and $γ_{p,q}(1)=q$. When there are multiple shortest geodesics, a deterministic choice will be returned.

This function returns a function of time, which may be a `Real`

or an `AbstractVector`

.

## Parallel transport

While moving vectors from one base point to another is the identity in the Euclidean space – or in other words all tangent spaces (directions one can “walk” into) are the same. This is different on a manifold.

If we have two points $p,q ∈ \mathcal M$, we take a $c: [0,1] → \mathcal M$ connecting the two points, i.e. $c(0) = p$ and $c(1) = q$. this could be a (or the) geodesic. If we further consider a vector field $X: [0,1] → T\mathcal M$, i.e. where $X(t) ∈ T_{c(t)}\mathcal M$. Then the vector field is called *parallel* if its covariant derivative $\frac{\mathrm{D}}{\mathrm{d}t}X(t) = 0$ for all $t∈ |0,1]$.

If we now impose a value for $X=X(0) ∈ T_p\mathcal M$, we obtain an ODE with an initial condition. The resulting value $X(1) ∈ T_q\mathcal M$ is called the *parallel transport* of `X`

along $c$ or in case of a geodesic the _parallel transport of `X`

from `p`

to `q`

.

`ManifoldsBase.parallel_transport_along`

— Method`Y = parallel_transport_along(M::AbstractManifold, p, X, c)`

Compute the parallel transport of the vector `X`

from the tangent space at `p`

along the curve `c`

.

To be precise let $c(t)$ be a curve $c(0)=p$ for `vector_transport_along`

$\mathcal P^cY$

THen In the result $Y\in T_p\mathcal M$ is the vector $X$ from the tangent space at $p=c(0)$ to the tangent space at $c(1)$.

Let $Z\colon [0,1] \to T\mathcal M$, $Z(t)\in T_{c(t)}\mathcal M$ be a smooth vector field along the curve $c$ with $Z(0) = Y$, such that $Z$ is *parallel*, i.e. its covariant derivative $\frac{\mathrm{D}}{\mathrm{d}t}Z$ is zero. Note that such a $Z$ always exists and is unique.

Then the parallel transport is given by $Z(1)$.

`ManifoldsBase.parallel_transport_direction`

— Method`parallel_transport_direction(M::AbstractManifold, p, X, d)`

Compute the `parallel_transport_along`

the curve $c(t) = γ_{p,q}(t)$, i.e. the * the unique geodesic $c(t)=γ_{p,X}(t)$ from $γ_{p,d}(0)=p$ into direction $\dot γ_{p,d}(0)=d$, of the tangent vector `X`

.

By default this function calls `parallel_transport_to`

`(M, p, X, q)`

, where $q=\exp_pX$.

`ManifoldsBase.parallel_transport_to`

— Method`parallel_transport_to(M::AbstractManifold, p, X, q)`

Compute the `parallel_transport_along`

the curve $c(t) = γ_{p,q}(t)$, i.e. the (assumed to be unique) `geodesic`

connecting `p`

and `q`

, of the tangent vector `X`

.

## Further functions on manifolds

### General functions provided by the interface

`Base.angle`

— Method`angle(M::AbstractManifold, p, X, Y)`

Compute the angle between tangent vectors `X`

and `Y`

at point `p`

from the `AbstractManifold`

`M`

with respect to the inner product from `inner`

.

`Base.copy`

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

Copy the value(s) from the tangent vector `X`

at a point `p`

on the `AbstractManifold`

`M`

into a new tangent vector. See `allocate_result`

for the allocation of new point memory and `copyto!`

for the copying.

`Base.copy`

— Method`copy(M, p)`

Copy the value(s) from the point `p`

on the `AbstractManifold`

`M`

into a new point. See `allocate_result`

for the allocation of new point memory and `copyto!`

for the copying.

`Base.copyto!`

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

Copy the value(s) from `X`

to `Y`

, where both are tangent vectors from the tangent space at `p`

on the `AbstractManifold`

`M`

. This function defaults to calling `copyto!(Y, X)`

, but it might be useful to overwrite the function at the level, where also information from `p`

and `M`

can be accessed.

`Base.copyto!`

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

Copy the value(s) from `p`

to `q`

, where both are points on the `AbstractManifold`

`M`

. This function defaults to calling `copyto!(q, p)`

, but it might be useful to overwrite the function at the level, where also information from `M`

can be accessed.

`Base.isapprox`

— Method`isapprox(M::AbstractManifold, p, X, Y; error:Symbol=:none; kwargs...)`

Check if vectors `X`

and `Y`

tangent at `p`

from `AbstractManifold`

`M`

are approximately equal.

The optional positional argument can be used to get more information for the case that the result is false, if the concrete manifold provides such information. Currently the following are supported

`:error`

- throws an error if`isapprox`

evaluates to false, providing possibly a more detailed error. Note that this turns`isapprox`

basically to an`@assert`

.`:info`

– prints the information in an`@info`

`:warn`

– prints the information in an`@warn`

`:none`

(default) – the function just returns`true`

/`false`

By default these informations are collected by calling `check_approx`

.

Keyword arguments can be used to specify tolerances.

`Base.isapprox`

— Method`isapprox(M::AbstractManifold, p, q; error::Symbol=none, kwargs...)`

Check if points `p`

and `q`

from `AbstractManifold`

`M`

are approximately equal.

The keyword argument can be used to get more information for the case that the result is false, if the concrete manifold provides such information. Currently the following are supported

`:error`

- throws an error if`isapprox`

evaluates to false, providing possibly a more detailed error. Note that this turns`isapprox`

basically to an`@assert`

.`:info`

– prints the information in an`@info`

`:warn`

– prints the information in an`@warn`

`:none`

(default) – the function just returns`true`

/`false`

Keyword arguments can be used to specify tolerances.

`Base.rand`

— Method```
Random.rand(M::AbstractManifold, [d::Integer]; vector_at=nothing)
Random.rand(rng::AbstractRNG, M::AbstractManifold, [d::Integer]; vector_at=nothing)
```

Generate a random point on manifold `M`

(when `vector_at`

is `nothing`

) or a tangent vector at point `vector_at`

(when it is not `nothing`

).

Optionally a random number generator `rng`

to be used can be specified. An optional integer `d`

indicates that a vector of `d`

points or tangent vectors is to be generated.

Usually a uniform distribution should be expected for compact manifolds and a Gaussian-like distribution for non-compact manifolds and tangent vectors, although it is not guaranteed. The distribution may change between releases.

`rand`

methods for specific manifolds may take additional keyword arguments.

`LinearAlgebra.norm`

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

Compute the norm of tangent vector `X`

at point `p`

from a `AbstractManifold`

`M`

. By default this is computed using `inner`

.

`ManifoldsBase.allocate`

— Method```
allocate(a)
allocate(a, dims::Integer...)
allocate(a, dims::Tuple)
allocate(a, T::Type)
allocate(a, T::Type, dims::Integer...)
allocate(a, T::Type, dims::Tuple)
allocate(M::AbstractManifold, a)
allocate(M::AbstractManifold, a, dims::Integer...)
allocate(M::AbstractManifold, a, dims::Tuple)
allocate(M::AbstractManifold, a, T::Type)
allocate(M::AbstractManifold, a, T::Type, dims::Integer...)
allocate(M::AbstractManifold, a, T::Type, dims::Tuple)
```

Allocate an object similar to `a`

. It is similar to function `similar`

, although instead of working only on the outermost layer of a nested structure, it maps recursively through outer layers and calls `similar`

on the innermost array-like object only. Type `T`

is the new number element type `number_eltype`

, if it is not given the element type of `a`

is retained. The `dims`

argument can be given for non-nested allocation and is forwarded to the function `similar`

.

It's behavior can be overriden by a specific manifold, for example power manifold with nested replacing representation can decide that `allocate`

for `Array{<:SArray}`

returns another `Array{<:SArray}`

instead of `Array{<:MArray}`

, as would be done by default.

`ManifoldsBase.base_manifold`

— Function`base_manifold(M::AbstractManifold, depth = Val(-1))`

Return the internally stored `AbstractManifold`

for decorated manifold `M`

and the base manifold for vector bundles or power manifolds. The optional parameter `depth`

can be used to remove only the first `depth`

many decorators and return the `AbstractManifold`

from that level, whether its decorated or not. Any negative value deactivates this depth limit.

`ManifoldsBase.distance`

— Method`distance(M::AbstractManifold, p, q, m::AbstractInverseRetractionMethod)`

Approximate distance between points `p`

and `q`

on manifold `M`

using `AbstractInverseRetractionMethod`

`m`

.

`ManifoldsBase.distance`

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

Shortest distance between the points `p`

and `q`

on the `AbstractManifold`

`M`

, i.e.

\[d(p,q) = \inf_{γ} L(γ),\]

where the infimum is over all piecewise smooth curves $γ: [a,b] \to \mathcal M$ connecting $γ(a)=p$ and $γ(b)=q$ and

\[L(γ) = \displaystyle\int_{a}^{b} \lVert \dotγ(t)\rVert_{γ(t)} \mathrm{d}t\]

is the length of the curve $γ$.

If $\mathcal M$ is not connected, i.e. consists of several disjoint components, the distance between two points from different components should be $∞$.

`ManifoldsBase.embed!`

— Method`embed!(M::AbstractManifold, Y, p, X)`

Embed a tangent vector `X`

at a point `p`

on the `AbstractManifold`

`M`

into the ambient space and return the result in `Y`

. This method is only available for manifolds where implicitly an embedding or ambient space is given. Additionally, `embed!`

includes changing data representation, if applicable, i.e. if the tangents on `M`

are not represented in the same way as tangents on the embedding, the representation is changed accordingly. This is the case for example for Lie groups, when tangent vectors are represented in the Lie algebra. The embedded tangents are then in the tangent spaces of the embedded base points.

The default is set in such a way that it assumes that the points on `M`

are represented in their embedding (for example like the unit vectors in a space to represent the sphere) and hence embedding also for tangent vectors is the identity by default.

See also: `EmbeddedManifold`

, `project!`

`ManifoldsBase.embed!`

— Method`embed!(M::AbstractManifold, q, p)`

Embed point `p`

from the `AbstractManifold`

`M`

into an ambient space. This method is only available for manifolds where implicitly an embedding or ambient space is given. Not implementing this function means, there is no proper embedding for your manifold. Additionally, `embed`

might include changing data representation, if applicable, i.e. if points on `M`

are not represented in the same way as their counterparts in the embedding, the representation is changed accordingly.

The default is set in such a way that it assumes that the points on `M`

are represented in their embedding (for example like the unit vectors in a space to represent the sphere) and hence embedding in the identity by default.

If you have more than one embedding, see `EmbeddedManifold`

for defining a second embedding. If your point `p`

is already represented in some embedding, see `AbstractDecoratorManifold`

how you can avoid reimplementing code from the embedded manifold

See also: `EmbeddedManifold`

, `project!`

`ManifoldsBase.embed`

— Method`embed(M::AbstractManifold, p, X)`

Embed a tangent vector `X`

at a point `p`

on the `AbstractManifold`

`M`

into an ambient space. This method is only available for manifolds where implicitly an embedding or ambient space is given. Not implementing this function means, there is no proper embedding for your tangent space(s).

Additionally, `embed`

might include changing data representation, if applicable, i.e. if tangent vectors on `M`

are not represented in the same way as their counterparts in the embedding, the representation is changed accordingly.

The default is set in such a way that memory is allocated and `embed!(M, Y, p. X)`

is called.

If you have more than one embedding, see `EmbeddedManifold`

for defining a second embedding. If your tangent vector `X`

is already represented in some embedding, see `AbstractDecoratorManifold`

how you can avoid reimplementing code from the embedded manifold

See also: `EmbeddedManifold`

, `project`

`ManifoldsBase.embed`

— Method`embed(M::AbstractManifold, p)`

Embed point `p`

from the `AbstractManifold`

`M`

into the ambient space. This method is only available for manifolds where implicitly an embedding or ambient space is given. Additionally, `embed`

includes changing data representation, if applicable, i.e. if the points on `M`

are not represented in the same way as points on the embedding, the representation is changed accordingly.

The default is set in such a way that memory is allocated and `embed!(M, q, p)`

is called.

See also: `EmbeddedManifold`

, `project`

`ManifoldsBase.injectivity_radius`

— Method`injectivity_radius(M::AbstractManifold)`

Infimum of the injectivity radii `injectivity_radius(M,p)`

of all points `p`

on the `AbstractManifold`

.

`injectivity_radius(M::AbstractManifold, p)`

Return the distance $d$ such that `exp(M, p, X)`

is injective for all tangent vectors shorter than $d$ (i.e. has an inverse).

```
injectivity_radius(M::AbstractManifold[, x], method::AbstractRetractionMethod)
injectivity_radius(M::AbstractManifold, x, method::AbstractRetractionMethod)
```

Distance $d$ such that `retract(M, p, X, method)`

is injective for all tangent vectors shorter than $d$ (i.e. has an inverse) for point `p`

if provided or all manifold points otherwise.

In order to dispatch on different retraction methods, please either implement `_injectivity_radius(M[, p], m::T)`

for your retraction `R`

or specifically `injectivity_radius_exp(M[, p])`

for the exponential map. By default the variant with a point `p`

assumes that the default (without `p`

) can ve called as a lower bound.

`ManifoldsBase.inner`

— Method`inner(M::AbstractManifold, p, X, Y)`

Compute the inner product of tangent vectors `X`

and `Y`

at point `p`

from the `AbstractManifold`

`M`

.

`ManifoldsBase.is_flat`

— Method`is_flat(M::AbstractManifold)`

Return true if the `AbstractManifold`

`M`

is flat, i.e. if its Riemann curvature tensor is everywhere zero.

`ManifoldsBase.is_point`

— Function```
is_point(M::AbstractManifold, p, throw_error::Boolean = false; kwargs...)
is_point(M::AbstractManifold, p, report_error::Symbol; kwargs...)
```

Return whether `p`

is a valid point on the `AbstractManifold`

`M`

.

If `throw_error`

is `false`

, the function returns either `true`

or `false`

. If `throw_error`

is `true`

, the function either returns `true`

or throws an error. By default the function calls `check_point`

and checks whether the returned value is `nothing`

or an error.

A more precise way can be set using a symbol as the optional parameter, where ' `:error`

is the same as setting `throw_error=true`

' `:info`

displays the error message as an `@info`

`:warn`

displays the error message as a`@warning`

all other symbols are equivalent to `throw_error=false`

.

`ManifoldsBase.is_vector`

— Function```
is_vector(M::AbstractManifold, p, X, throw_error = false, check_base_point=true; kwargs...)
is_vector(M::AbstractManifold, p, X, error::Symbol, check_base_point::Bool=true; kwargs...)
```

Return whether `X`

is a valid tangent vector at point `p`

on the `AbstractManifold`

`M`

. Returns either `true`

or `false`

.

If `throw_error`

is `false`

, the function returns either `true`

or `false`

. If `throw_error`

is `true`

, the function either returns `true`

or throws an error. By default the function calls `check_vector`

and checks whether the returned value is `nothing`

or an error.

If `check_base_point`

is true, then the point `p`

will be first checked using the `check_point`

function.

A more precise way can be set using a symbol as the optional parameter, where ' `:error`

is the same as setting `throw_error=true`

' `:info`

displays the error message as an `@info`

`:warn`

displays the error message as a`@warn`

ing.

all other symbols are equivalent to `throw_error=false`

.

`ManifoldsBase.manifold_dimension`

— Method`manifold_dimension(M::AbstractManifold)`

The dimension $n=\dim_{\mathcal M}$ of real space $\mathbb R^n$ to which the neighborhood of each point of the `AbstractManifold`

`M`

is homeomorphic.

`ManifoldsBase.mid_point!`

— Method`mid_point!(M::AbstractManifold, q, p1, p2)`

Calculate the middle between the two point `p1`

and `p2`

from manifold `M`

. By default uses `log`

, divides the vector by 2 and uses `exp!`

. Saves the result in `q`

.

`ManifoldsBase.mid_point`

— Method`mid_point(M::AbstractManifold, p1, p2)`

Calculate the middle between the two point `p1`

and `p2`

from manifold `M`

. By default uses `log`

, divides the vector by 2 and uses `exp`

.

`ManifoldsBase.number_eltype`

— Method`number_eltype(x)`

Numeric element type of the a nested representation of a point or a vector. To be used in conjuntion with `allocate`

or `allocate_result`

.

`ManifoldsBase.representation_size`

— Method`representation_size(M::AbstractManifold)`

The size of an array representing a point on `AbstractManifold`

`M`

. Returns `nothing`

by default indicating that points are not represented using an `AbstractArray`

.

`ManifoldsBase.riemann_tensor`

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

Compute the value of the Riemann tensor $R(X_f,Y_f)Z_f$ at point `p`

, where $X_f$, $Y_f$ and $Z_f$ are vector fields defined by parallel transport of, respectively, `X`

, `Y`

and `Z`

to the desired point. All computations are performed using the connection associated to manifold `M`

.

The formula reads $R(X_f,Y_f)Z_f = \nabla_X\nabla_Y Z - \nabla_Y\nabla_X Z - \nabla_{[X, Y]}Z$, where $[X, Y]$ is the Lie bracket of vector fields.

Note that some authors define this quantity with inverse sign.

`ManifoldsBase.zero_vector!`

— Method`zero_vector!(M::AbstractManifold, X, p)`

Save to `X`

the tangent vector from the tangent space $T_p\mathcal M$ at `p`

that represents the zero vector, i.e. such that retracting `X`

to the `AbstractManifold`

`M`

at `p`

produces `p`

.

`ManifoldsBase.zero_vector`

— Method`zero_vector(M::AbstractManifold, p)`

Return the tangent vector from the tangent space $T_p\mathcal M$ at `p`

on the `AbstractManifold`

`M`

, that represents the zero vector, i.e. such that a retraction at `p`

produces `p`

.

### Internal functions

While you should always add your documentation to functions from the last section, some of the functions dispatch onto functions on layer III. These are the ones you usually implement for your manifold – unless there is no lower level function called, like for the `manifold_dimension`

.

`ManifoldsBase._pick_basic_allocation_argument`

— Method`_pick_basic_allocation_argument(::AbstractManifold, f, x...)`

Pick which one of elements of `x`

should be used as a basis for allocation in the `allocate_result(M::AbstractManifold, f, x...)`

method. This can be specialized to, for example, skip `Identity`

arguments in Manifolds.jl group-related functions.

`ManifoldsBase.allocate_result`

— Method`allocate_result(M::AbstractManifold, f, x...)`

Allocate an array for the result of function `f`

on `AbstractManifold`

`M`

and arguments `x...`

for implementing the non-modifying operation using the modifying operation.

Usefulness of passing a function is demonstrated by methods that allocate results of musical isomorphisms.

`ManifoldsBase.allocate_result_type`

— Method`allocate_result_type(M::AbstractManifold, f, args::NTuple{N,Any}) where N`

Return type of element of the array that will represent the result of function `f`

and the `AbstractManifold`

`M`

on given arguments `args`

(passed as a tuple).

`ManifoldsBase.check_approx`

— Method```
check_approx(M::AbstractManifold, p, q; kwargs...)
check_approx(M::AbstractManifold, p, X, Y; kwargs...)
```

Check whether two elements are approximately equal, either `p`

, `q`

on the `AbstractManifold`

or the two tangent vectors `X`

, `Y`

in the tangent space at `p`

are approximately the same. The keyword arguments `kwargs`

can be used to set tolerances, similar to Julia's `isapprox`

.

This function might use `isapprox`

from Julia internally and is similar to `isapprox`

, with the difference that is returns an `ApproximatelyError`

if the two elements are not approximately equal, containting a more detailed description/reason. If the two elements are approximalely equal, this method returns `nothing`

.

This method is an internal function and is called by `isapprox`

whenever the user specifies an `error=`

keyword therein.

`ManifoldsBase.check_point`

— Method`check_point(M::AbstractManifold, p; kwargs...) -> Union{Nothing,String}`

Return `nothing`

when `p`

is a point on the `AbstractManifold`

`M`

. Otherwise, return an error with description why the point does not belong to manifold `M`

.

By default, `check_point`

returns `nothing`

, i.e. if no checks are implemented, the assumption is to be optimistic for a point not deriving from the `AbstractManifoldPoint`

type.

`ManifoldsBase.check_size`

— Method```
check_size(M::AbstractManifold, p)
check_size(M::AbstractManifold, p, X)
```

Check whether `p`

has the right `representation_size`

for a `AbstractManifold`

`M`

. Additionally if a tangent vector is given, both `p`

and `X`

are checked to be of corresponding correct representation sizes for points and tangent vectors on `M`

.

By default, `check_size`

returns `nothing`

, i.e. if no checks are implemented, the assumption is to be optimistic.

`ManifoldsBase.check_vector`

— Method`check_vector(M::AbstractManifold, p, X; kwargs...) -> Union{Nothing,String}`

Check whether `X`

is a valid tangent vector in the tangent space of `p`

on the `AbstractManifold`

`M`

. An implementation does not have to validate the point `p`

. If it is not a tangent vector, an error string should be returned.

By default, `check_vector`

returns `nothing`

, i.e. if no checks are implemented, the assumption is to be optimistic for tangent vectors not deriving from the `TVector`

type.

`ManifoldsBase.size_to_tuple`

— Method`size_to_tuple(::Type{S}) where S<:Tuple`

Converts a size given by `Tuple{N, M, ...}`

into a tuple `(N, M, ...)`

.

## Error Messages

This interface introduces a small set of own error messages.

`ManifoldsBase.AbstractManifoldDomainError`

— Type`AbstractManifoldDomainError <: Exception`

An absytract Case for Errors when checking validity of points/vectors on mainfolds

`ManifoldsBase.ApproximatelyError`

— Type`ApproximatelyError{V,S} <: Exception`

Store an error that occurs when two data structures, e.g. points or tangent vectors.

**Fields**

`val`

amount the two approximate elements are apart – is set to`NaN`

if this is not known`msg`

a message providing more detail about the performed test and why it failed.

**Constructors**

`ApproximatelyError(val::V, msg::S) where {V,S}`

Generate an Error with value `val`

and message `msg`

.

`ApproximatelyError(msg::S) where {S}`

Generate a message without a value (using `val=NaN`

internally) and message `msg`

.

`ManifoldsBase.ComponentManifoldError`

— Type`CompnentError{I,E} <: Exception`

Store an error that occured in a component, where the additional `index`

is stored.

**Fields**

`index::I`

index where the error occured``error::E`

error that occured.

`ManifoldsBase.CompositeManifoldError`

— Type`CompositeManifoldError{T} <: Exception`

A composite type to collect a set of errors that occured. Mainly used in conjunction with `ComponentManifoldError`

to store a set of errors that occured.

**Fields**

`errors`

a`Vector`

of`<:Exceptions`

.

`ManifoldsBase.ManifoldDomainError`

— Type`ManifoldDomainError{<:Exception} <: Exception`

An error to represent a nested (Domain) error on a manifold, for example if a point or tangent vector is invalid because its representation in some embedding is already invalid.

`ManifoldsBase.OutOfInjectivityRadiusError`

— Type`OutOfInjectivityRadiusError`

An error thrown when a function (for example `log`

arithmic map or `inverse_retract`

) is given arguments outside of its `injectivity_radius`

.