# work with groups

- Introduction: group of rotations on a plane
- Relationship between groups, metrics and connections
- Literature

This is a short overview of group support in `Manifolds.jl`

and how to get started working with them.

Groups currently available in `Manifolds.jl`

are listed in group section.

You can read more about the theory of Lie groups for example in [Chi12]. An example application of Lie groups in robotics is described in [SDA21].

First, let’s load libraries we will use. `RecursiveArrayTools.jl`

is necessary because its `ArrayPartition`

is used as one of the possible representations of elements of product and semidirect product groups. `StaticArrays.jl`

can be used to speed up some operations.

`using Manifolds, RecursiveArrayTools, StaticArrays`

## Introduction: group of rotations on a plane

Let’s first consider an example of the group of rotations of a plane, $\operatorname{SO}(2)$. They can be represented in several ways, for example as angles of rotation (which corresponds to `RealCircleGroup`

), unit complex numbers (`CircleGroup`

), or rotation matrices (`SpecialOrthogonal`

). Let’s consider the last representation since it is the most nontrivial one and can be more easily generalized to other groups.

The associated manifolds and groups are defined by:

```
G = SpecialOrthogonal(2)
M = base_manifold(G)
@assert M === Rotations(2)
```

This duality (Lie group and the underlying manifold being separate) is a common pattern in `Manifolds.jl`

. The group `G`

can be used for both Lie group-specific operations and metric-specific operation, while the manifold `M`

only allows using manifold and metric operations. This way groups can be specialized in ways not relevant to plain manifolds, and if someone doesn’t use the groups structure, they don’t have to consider it by just using the manifold.

Some basic definitions

```
# default basis
B = DefaultOrthogonalBasis()
# Identity rotation
p0 = @SMatrix [1.0 0; 0 1]
# Group identity element of a special type
IG = Identity(G)
```

`Identity(MultiplicationOperation)`

Let’s say we want to define a manifold point `p_i`

some rotation θ from the `identity_element`

reference rotation `p0`

(another point on the manifold that we will use as reference)

```
# + radians rotation from x-axis on plane to point i
xθi = π/6
```

`0.5235987755982988`

### From Coordinates

To get our first Lie algebra element we can use the `hat`

function which is commonly used in robotics, or equivalently a more generalized `get_vector`

, function:

```
X_ = hat(G, IG, xθi) # specific definition to Lie algebras
xXi = get_vector(G, p0, xθi, B) # generalized definition beyond Lie algebras
println(xXi)
@assert isapprox(X_, xXi)
```

`[0.0 -0.5235987755982988; 0.5235987755982988 0.0]`

Note that `hat`

here assumes a default (orthogonal) basis for the more general `get_vector`

.

NoteIn this case, the same would work given the base manifold

`Rotations(2)`

:`_X_ = hat(M, p0, xθi) # Lie groups definition _X = get_vector(M, p0, xθi, B) # generalized definition @assert _X_ == xXi; @assert _X == xXi`

One more caveat here is that for the Rotation matrices, the tangent vectors are always stored as elements from the Lie algebra.

Now, we can transform this algebra element to a point on the manifold using the exponential map `exp`

:

```
xRi = exp(G, p0, xXi)
# similarly for known underlying manifold
xRi_ = exp(M, p0, xXi)
@assert isapprox(xRi, xRi_)
```

### To Coordinates

The logarithmic map transforms elements of the group back to its Lie algebra:

```
xXi_ = log(G, p0, xRi)
xXi__ = log(M, p0, xRi)
@assert xXi ≈ xXi__
```

Similarly, the coordinate values can be extracted from the algebra elements using `vee`

, or using the more generalized `get_coordinates`

:

```
# extracting coordinates using vee
xθi__ = vee(G, p0, xXi_)[1]
_xθi__ = vee(M, p0, xXi_)[1]
# OR, the preferred generalized get_coordinate function
xθi_ = get_coordinates(G, p0, xXi_, B)[1]
_xθi_ = get_coordinates(M, p0, xXi_, B)[1]
# confirm all versions are correct
@assert isapprox(xθi, xθi_); @assert isapprox(xθi, _xθi_)
@assert isapprox(xθi, xθi__); @assert isapprox(xθi, _xθi__)
```

### Actions and Operations

With the basics in hand on how to move between the coordinate, algebra, and group representations, let’s briefly look at composition and application of points on the manifold. For example, a `Rotations`

manifold is the mathematical representation, but the points have an application purpose in retaining information regarding a specific rotation.

Points from a Lie group may have an associated action (i.e. a rotation) which we `apply`

. Consider rotating through `θ = π/6`

three vectors `V`

from their native domain `Euclidean(2)`

, from the reference point `a`

to a new point `b`

. Engineering disciplines sometimes refer to the action of a manifold point `a`

or `b`

as reference frames. More generally, by taking the tangent space at point `p`

, we are defining a local coordinate frame with basis `B`

, and should not be confused with “reference frame” `a`

or `b`

.

Keeping with our two-dimensional example above:

```
aV1 = [1; 0]
aV2 = [0; 1]
aV3 = [10; 10]
A_left = RotationAction(Euclidean(2), G)
bθa = π/6
bXa = get_vector(base_manifold(G), p0, bθa, B)
bRa = exp(G, p0, bXa)
for aV in [aV1; aV2; aV3]
bV = apply(A_left, bRa, aV)
# test we are getting the rotated vectors in Euclidean(2) as expected
@assert isapprox(bV[1], norm(aV) * cos(bθa))
@assert isapprox(bV[2], norm(aV) * sin(bθa))
end
```

NoteIn general, actions are usually non-commutative and the user must therefore be aware whether they want to use

`LeftAction`

or`RightAction`

. In this case, the default`LeftAction()`

is used.

Finally, the actions (i.e. points from a manifold) can be `compose`

d together. Consider putting together two rotations `aRb`

and `bRc`

such that a single composite rotation `aRc`

is found. The next bit of code composes five rotations of `π/4`

increments:

```
A_left = RotationAction(M, G)
aRi = copy(p0)
iθi_ = π/4
x_θ = get_vector(M, p0, iθi_, B) #hat(Rn, R0, θ)
iRi_ = exp(M, p0, x_θ)
# do 5 times over:
# Ri_ = Ri*iRi_
for i in 1:5
aRi = compose(A_left, aRi, iRi_)
end
# drop back to a algebra, then coordinate
aXi = log(G, p0, aRi)
aθi = get_coordinates(G, p0, aXi, B)
# should wrap around to 3rd quadrant of xy-plane
@assert isapprox(-3π/4, aθi[1])
```

Warning

`compose`

or`apply`

must be done with group (not algebra) elements. This example shows how these two element types can easily be confused, since both the manifold group and algebra elements can have exactly the same data storage type – i.e. a 2x2 matrix.

As a last note, other rotation representations, including quaternions, Pauli matrices, etc., have similar features. A contrasting example in rotations, however, are Euler angles which can also store rotation information but quickly becomes problematic with familiar problems such as “gimbal-lock”.

## Relationship between groups, metrics and connections

Group structure provides a canonical way to define 📖 exponential and logarithmic maps from the Lie algebra. They can be calculated in `Manifolds.jl`

using the `exp_lie`

and `log_lie`

functions. Such exponential and logarithmic maps can be extended invariantly to tangent spaces at any point of the Lie group. This extension is implemented using functions `exp_inv`

and `log_inv`

.

Finally, there are `log`

and `exp`

functions which are metric (or connection)-related functions in `Manifolds.jl`

. For groups which can be equipped with a bi-invariant metric, `log`

and `log_inv`

return the same result, similarly `exp`

and `exp_inv`

. However, only compact groups and their products with Euclidean spaces can have a bi-invariant metric (see for example Theorem 21.9 in [GQ20]). A prominent example of a Lie group without a bi-invariant metric is the special Euclidean group (in two or more dimensions). Then we have a choice between a metric but non-invariant exponential map (which is generally the default choice for `exp`

) or a non-metric, invariant exponential map (`exp_inv`

). Which one should be used depends on whether being metric or being invariant is more important in a particular application.

```
G = SpecialEuclidean(2)
p = ArrayPartition([1.0, -1.0], xRi)
X = ArrayPartition([2.0, -3.0], aXi)
q_m = exp(G, p, X)
println(q_m)
q_i = exp_inv(G, p, X)
println(q_i)
```

```
ArrayPartition{Float64, Tuple{Vector{Float64}, SMatrix{2, 2, Float64, 4}}}(([3.0, -4.0], [-0.25881904510252124 0.9659258262890682; -0.9659258262890682 -0.25881904510252124]))
ArrayPartition{Float64, Tuple{Vector{Float64}, MMatrix{2, 2, Float64, 4}}}(([0.8121200537878321, -3.8212723543456155], [-0.25881904510252124 0.9659258262890682; -0.9659258262890682 -0.25881904510252124]))
```

As we can see, the results differ. We can observe the invariance as follows:

```
p2 = ArrayPartition([2.0, -1.0], xRi)
q1_m = exp(G, translate(G, p2, p), translate_diff(G, p2, p, X))
q2_m = translate(G, p2, exp(G, p, X))
println(isapprox(q1_m, q2_m))
q1_i = exp_inv(G, translate(G, p2, p), translate_diff(G, p2, p, X))
q2_i = translate(G, p2, exp_inv(G, p, X))
println(isapprox(q1_i, q2_i))
```

```
false
true
```

Now, `q1_m`

and `q2_m`

are different due to non-invariance of the metric connection but `q1_i`

and `q2_i`

are equal due to invarianced of `exp_inv`

.

The following table outlines invariance of `exp`

and `log`

of various groups.

Group | Zero torsion connection | Invariant |
---|---|---|

`ProductGroup` | Product of connections in each submanifold | 🟡^{[1]} |

`SemidirectProductGroup` | Same as underlying product | ❌ |

`TranslationGroup` | `CartanSchoutenZero` | ✅ |

`CircleGroup` | `CartanSchoutenZero` | ✅ |

`GeneralLinearGroup` | Metric connection from the left invariant metric induced from the standard basis on the Lie algebra | ❌ |

`GeneralUnitaryMultiplicationGroup` | `CartanSchoutenZero` (explicitly) | ✅ |

`HeisenbergGroup` | `CartanSchoutenZero` | ✅ |

`SpecialLinearGroup` | Same as `GeneralLinear` | ❌ |

## Literature

- [Chi12]
- G. S. Chirikjian.
*Stochastic Models, Information Theory, and Lie Groups, Volume 2*. 1 Edition, Vol. 2 of*Applied and Numerical Harmonic Analysis*(Birkhäuser Boston, MA, 2012). - [GQ20]
- J. Gallier and J. Quaintance.
*Differential Geometry and Lie Groups: A Computational Perspective*. Vol. 12 of*Geometry and Computing*(Springer International Publishing, Cham, 2020). - [SDA21]
- J. Solà, J. Deray and D. Atchuthan.
*A micro Lie theory for state estimation in robotics*(Dec 2021), arXiv:1812.01537 [cs.RO], arXiv: 1812.01537.

- 1Yes if all component connections are invariant separately, otherwise no