Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/const-ae/diffgeo

Working with manifolds in R
https://github.com/const-ae/diffgeo

Last synced: 9 days ago
JSON representation

Working with manifolds in R

Awesome Lists containing this project

README

        

---
output: github_document
---

```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```

# diffgeo

The `diffgeo` R package provides functions to work with six common manifolds:

* Euclidean arrays
* Spheres (in $n$ dimensions)
* Rotation matrices (also called special orthogonal manifolds $\text{SO}(n)$)
* Stiefel manifold (matrices with orthogonal columns)
* Grassmann manifold (matrices with orthogonal columns but they are only considered different if they span separate spaces)
* Symmetric positive definite (SPD) matrices (symmetric matrices with positive eigenvalues)

## Installation

You can install `diffgeo` from [Github](https://github.com/const-ae/diffgeo) with:

``` r
devtools::install_github("const-ae/diffgeo")
```

## Principles

For each manifold, `diffgeo` provides:

* Random points
* Random tangents
* Exponential map (a way to go along the manifold from one point to another)
* Logarithm (the inverse exponential map, that is a way calculate the direction between points on the manifold)

## Examples

To demonstrate the functionality of the package, I will show the functions for the rotation matrices. All functions work analoguously for the other manifolds.

```{r}
library(diffgeo)
set.seed(1)
```

To begin, I create a random rotation matrix in 2D

```{r}
rotation <- rotation_random_point(2)
```

We can visualize it's effect on a random set of points
```{r rotation_visualization_2d}
points <- rbind(rnorm(n = 20), rnorm(20))
rotated_points <- rotation %*% points
plot(t(points), pch = 16, col = "black", asp = 1, xlim = c(-3, 3), ylim = c(-2, 2))
points(t(rotated_points), pch = 16, col = "red")
segments(points[1,], points[2,], rotated_points[1,], rotated_points[2,])
```

We can also create high-dimensional rotations and check the formal conditions for the rotation manifold

```{r}
rotation2 <- rotation_random_point(5)
# Determinant is 1
Matrix::det(rotation2)
# All columns are orthogonal
round(t(rotation2) %*% rotation2, 3)
```

An important concept in differential geometry are geodesics, i.e. are lines on the manifold. To find the
line that connects two rotations we use the `rotation_log` function. These directions are from the tangent space
of the manifold. The tangent space of the rotation manifold is the set of skew-symmetric matrices.

```{r}
rotation3 <- rotation_random_point(5)
direction <- rotation_log(base_point = rotation2, target_point = rotation3)
round(direction, 3)
```

We can also reverse the operation and go from a base-point in the direction of a tangent vector ("exponential map"). If we do this
using the `direction` we will land exactly at `rotation3` again.

```{r}
rotation3
rotation_map(v = direction, base_point = rotation2)
```

Lastly, it is important to understand that the Sphere, the Grassmann, the Stiefel, and the Rotation manifold have a non-infinite injectivity radius.
The injectivity radius is furthest we can go along a manifold and still guarantee that $\log(p, \exp_p(v))$ returns the original tangent vector $v$.
The concept is clearest for a 1-Sphere (aka a circle): if we go further than 180° ($\pi$ radians), we end up at a point for which there exist a shorter path to
the starting point than the original direction.

```{r circle_injectivity_radius}
# Create a random vector with two elements on a circle
sp <- sphere_random_point(1)
# Make a tangent vector with norm 1
tang <- sphere_random_tangent(sp)
tang <- tang / sqrt(sum(tang^2))

# Plot different step lengths along the direction and
# highlight the starting point in red and the point at the injectivity radius in green
plot(t(do.call(cbind, lapply(seq(0, 2 * pi, l = 31), \(t) sphere_map(t * tang, sp)))), asp = 1)
points(t(sp), col = "red")
points(t(sphere_map(sphere_injectivity_radius() * tang, sp)), col = "green")
```

# Alternatives

This package is heavily inspired and builds on the [Manifolds](https://juliamanifolds.github.io/Manifolds.jl/latest/index.html) and [Manopt.jl](https://manoptjl.org/stable/) packages developed by Ronny Bergmann et al.. The Manopt.jl package in turn is inspired by the [Manopt](https://www.manopt.org/) toolbox for Matlab.