use super::FixedVector;
use super::FixedMatrix;
use super::manifold::Manifold;
use super::matrix_functions::{matrix_exp, matrix_log, matrix_exp_compute, matrix_log_compute};
use super::compute_matrix::{ComputeMatrix, compute_lu_decompose};
use super::kernels;
use super::kernels::Orient;
use super::Scalar;
use super::matrix_functions::MatrixFunctions;
use crate::fixed_point::fixed_num::{Compute, Fixed, FixedNum};
use crate::fixed_point::width::{Storage, WideInt};
use crate::fixed_point::core_types::errors::OverflowDetected;
#[inline]
fn up<S: Storage, const F: u32>(x: Fixed<S, F>) -> Compute<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{ Fixed::<S, F>::upscale_to_compute(x.raw()) }
#[inline]
fn down<S: Storage, const F: u32>(c: Compute<Fixed<S, F>>) -> Result<Fixed<S, F>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
Ok(Fixed::from_raw(Fixed::<S, F>::downscale_to_storage(c)?))
}
fn down_vector<S: Storage, const F: u32>(v: &[Compute<Fixed<S, F>>]) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let mut out = FixedVector::<Fixed<S, F>>::new(v.len());
for (i, c) in v.iter().enumerate() { out[i] = down(*c)?; }
Ok(out)
}
fn down_matrix<S: Storage, const F: u32>(m: &ComputeMatrix<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let (rows, cols) = (m.rows(), m.cols());
let mut out = FixedMatrix::<Fixed<S, F>>::new(rows, cols);
for r in 0..rows {
for c in 0..cols { out.set(r, c, down(m.get(r, c))?); }
}
Ok(out)
}
fn norm_to_storage<S: Storage, const F: u32>(v: &[Compute<Fixed<S, F>>]) -> Result<Fixed<S, F>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let mut sum = Fixed::<S, F>::make_compute_int(0);
for c in v { sum = Fixed::<S, F>::compute_add(sum, Fixed::<S, F>::compute_multiply(*c, *c)); }
down(Fixed::<S, F>::sqrt_at_compute_tier(sum))
}
fn atan2_compute<S: Storage, const F: u32>(y: Compute<Fixed<S, F>>, x: Compute<Fixed<S, F>>) -> Compute<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
Fixed::<S, F>::atan2_at_compute_tier(y, x)
}
fn series<S: Storage, const F: u32>(t: Compute<Fixed<S, F>>, coeffs: &[(i64, i64)]) -> Result<Compute<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let mut power = Fixed::<S, F>::make_compute_int(1);
let mut sum = Fixed::<S, F>::make_compute_int(0);
for (k, (num, den)) in coeffs.iter().enumerate() {
if k > 0 { power = Fixed::<S, F>::compute_multiply(power, t); }
sum = Fixed::<S, F>::compute_add(sum, Fixed::<S, F>::compute_mul_div_int(power, *num, *den)?);
}
Ok(sum)
}
fn triple_to_storage<S: Storage, const F: u32>(terms: &[(Compute<Fixed<S, F>>, S)], negate: bool) -> Result<Fixed<S, F>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let mut sum = <Orient<Fixed<S, F>> as WideInt>::zero();
for (c, s) in terms { sum = sum.add_exact(S::widen_product(*c, S::widen(*s)))?; }
Ok(Fixed::from_raw(kernels::narrow_triple_nearest::<Fixed<S, F>>(if negate { -sum } else { sum })?))
}
fn cross_exact<S: Storage, const F: u32>(a: &FixedVector<Fixed<S, F>>, b: &FixedVector<Fixed<S, F>>) -> [Compute<Fixed<S, F>>; 3]
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let p = |i: usize, j: usize| S::mul_wide(a[i].raw(), b[j].raw());
[
Fixed::<S, F>::compute_subtract(p(1, 2), p(2, 1)),
Fixed::<S, F>::compute_subtract(p(2, 0), p(0, 2)),
Fixed::<S, F>::compute_subtract(p(0, 1), p(1, 0)),
]
}
fn commutator_exact<S: Storage, const F: u32>(a: &FixedMatrix<Fixed<S, F>>, b: &FixedMatrix<Fixed<S, F>>) -> ComputeMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = a.rows();
ComputeMatrix::<Fixed<S, F>>::from_fn(n, n, |i, j| {
let (mut ab, mut ba) = (Fixed::<S, F>::make_compute_int(0), Fixed::<S, F>::make_compute_int(0));
for k in 0..n {
ab = Fixed::<S, F>::compute_add(ab, S::mul_wide(a.get(i, k).raw(), b.get(k, j).raw()));
ba = Fixed::<S, F>::compute_add(ba, S::mul_wide(b.get(i, k).raw(), a.get(k, j).raw()));
}
Fixed::<S, F>::compute_subtract(ab, ba)
})
}
fn conjugate_exact<S: Storage, const F: u32>(g: &FixedMatrix<Fixed<S, F>>, x: &FixedMatrix<Fixed<S, F>>, h: &FixedMatrix<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = g.rows();
let mut out = FixedMatrix::<Fixed<S, F>>::new(n, n);
for i in 0..n {
for j in 0..n {
let mut terms = Vec::with_capacity(n * n);
for k in 0..n {
for l in 0..n {
terms.push((S::mul_wide(g.get(i, k).raw(), x.get(k, l).raw()), h.get(j, l).raw()));
}
}
out.set(i, j, triple_to_storage(&terms, false)?);
}
}
Ok(out)
}
fn inverse_compute<S: Storage, const F: u32>(g: &ComputeMatrix<Fixed<S, F>>) -> Result<ComputeMatrix<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
compute_lu_decompose(g)?.inverse()
}
fn conjugate_by_inverse<S: Storage, const F: u32>(g: &FixedMatrix<Fixed<S, F>>, xi_hat: &FixedMatrix<Fixed<S, F>>) -> Result<ComputeMatrix<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let g_c = ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(g);
let g_inv = inverse_compute(&g_c)?;
Ok(g_c.mat_mul(&ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(xi_hat)).mat_mul(&g_inv))
}
fn skew_half<S: Storage, const F: u32>(a: &ComputeMatrix<Fixed<S, F>>) -> ComputeMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
a.sub(&a.transpose()).halve()
}
pub trait LieGroup<T: Scalar>: Manifold<T> {
fn algebra_dim(&self) -> usize;
fn matrix_dim(&self) -> usize;
fn identity_element(&self) -> FixedMatrix<T>;
fn compose(&self, g1: &FixedMatrix<T>, g2: &FixedMatrix<T>) -> FixedMatrix<T>;
fn group_inverse(&self, g: &FixedMatrix<T>) -> Result<FixedMatrix<T>, OverflowDetected>;
fn lie_exp(&self, xi: &FixedVector<T>) -> Result<FixedMatrix<T>, OverflowDetected>;
fn lie_log(&self, g: &FixedMatrix<T>) -> Result<FixedVector<T>, OverflowDetected>;
fn hat(&self, xi: &FixedVector<T>) -> FixedMatrix<T>;
fn vee(&self, xi_hat: &FixedMatrix<T>) -> FixedVector<T>;
fn adjoint(&self, g: &FixedMatrix<T>, xi: &FixedVector<T>) -> Result<FixedVector<T>, OverflowDetected>;
fn bracket(&self, xi: &FixedVector<T>, eta: &FixedVector<T>) -> FixedVector<T>;
fn act(&self, g: &FixedMatrix<T>, point: &FixedVector<T>) -> FixedVector<T>;
}
pub struct SO3;
fn rodrigues_threshold<S: Storage, const F: u32>() -> Fixed<S, F>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
let k = match S::BITS { 32 | 64 => 3, 128 => 5, 256 => 10, _ => 20 };
let d = if k == 20 { let e10 = S::from_i64(10_000_000_000); e10.mul_exact(e10) } else { S::from_i64(10i64.pow(k)) };
let (q, r) = S::one().shl_bits(F).divmod(d);
let raw = if r.shl_bits(1) >= d { q + S::one() } else { q };
Fixed::from_raw(if raw == S::ZERO { S::one() } else { raw })
}
fn se3_series_threshold<S: Storage, const F: u32>() -> Compute<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let mut t = Fixed::<S, F>::make_compute_int(4);
for _ in 0..F / 2 { t = Fixed::<S, F>::compute_halve(t); }
t
}
fn angle_compute<S: Storage, const F: u32>(omega: &[Compute<Fixed<S, F>>]) -> (Compute<Fixed<S, F>>, Compute<Fixed<S, F>>)
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let mut theta_sq = Fixed::<S, F>::make_compute_int(0);
for c in omega { theta_sq = Fixed::<S, F>::compute_add(theta_sq, Fixed::<S, F>::compute_multiply(*c, *c)); }
(theta_sq, Fixed::<S, F>::sqrt_at_compute_tier(theta_sq))
}
fn hat_compute<S: Storage, const F: u32>(w: &[Compute<Fixed<S, F>>]) -> ComputeMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let z = Fixed::<S, F>::make_compute_int(0);
let m = [z, Fixed::<S, F>::compute_negate(w[2]), w[1], w[2], z, Fixed::<S, F>::compute_negate(w[0]), Fixed::<S, F>::compute_negate(w[1]), w[0], z];
ComputeMatrix::<Fixed<S, F>>::from_fn(3, 3, |r, c| m[3 * r + c])
}
fn rodrigues_exp_compute<S: Storage, const F: u32>(omega: &[Compute<Fixed<S, F>>]) -> Result<ComputeMatrix<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let (theta_sq, theta) = angle_compute(omega);
let (sinc, half_cosc) = if theta < Fixed::<S, F>::upscale_to_compute(rodrigues_threshold::<S, F>().raw()) {
(
series(theta_sq, &[(1, 1), (-1, 6), (1, 120), (-1, 5040)])?,
series(theta_sq, &[(1, 2), (-1, 24), (1, 720), (-1, 40320)])?,
)
} else {
let (sin_c, cos_c) = Fixed::<S, F>::sincos_at_compute_tier(theta);
(
Fixed::<S, F>::compute_divide(sin_c, theta)?,
Fixed::<S, F>::compute_divide(Fixed::<S, F>::compute_subtract(Fixed::<S, F>::make_compute_int(1), cos_c), theta_sq)?,
)
};
let k = hat_compute(omega);
let k2 = k.mat_mul(&k);
Ok(ComputeMatrix::<Fixed<S, F>>::identity(3).add(&k.scalar_mul(sinc)).add(&k2.scalar_mul(half_cosc)))
}
fn rodrigues_log_compute<S: Storage, const F: u32>(r: &ComputeMatrix<Fixed<S, F>>) -> Result<([Compute<Fixed<S, F>>; 3], Compute<Fixed<S, F>>), OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let one = Fixed::<S, F>::make_compute_int(1);
let zero = Fixed::<S, F>::make_compute_int(0);
let d = [
Fixed::<S, F>::compute_subtract(r.get(2, 1), r.get(1, 2)),
Fixed::<S, F>::compute_subtract(r.get(0, 2), r.get(2, 0)),
Fixed::<S, F>::compute_subtract(r.get(1, 0), r.get(0, 1)),
];
let tr_minus_one = Fixed::<S, F>::compute_subtract(Fixed::<S, F>::compute_add(Fixed::<S, F>::compute_add(r.get(0, 0), r.get(1, 1)), r.get(2, 2)), one);
let (_, d_norm) = angle_compute(&d);
let d_zero = Fixed::<S, F>::compute_is_zero(&d_norm);
if !Fixed::<S, F>::compute_is_negative(&tr_minus_one) {
if d_zero {
return Ok(([zero, zero, zero], zero));
}
let theta = atan2_compute(d_norm, tr_minus_one);
let mut omega = [zero; 3];
for i in 0..3 {
omega[i] = kernels::divide_to_compute_nearest::<Fixed<S, F>>(S::widen_product(theta, d[i]), d_norm)?;
}
return Ok((omega, theta));
}
let theta = if d_zero { atan2_compute(zero, tr_minus_one) } else { atan2_compute(d_norm, tr_minus_one) };
let cos_theta = Fixed::<S, F>::compute_halve(tr_minus_one);
let one_minus_cos = Fixed::<S, F>::compute_subtract(one, cos_theta);
let mut i = 0;
for k in 1..3 {
if r.get(k, k) > r.get(i, i) { i = k; }
}
let ui_sq = Fixed::<S, F>::compute_divide(Fixed::<S, F>::compute_subtract(r.get(i, i), cos_theta), one_minus_cos)?;
if Fixed::<S, F>::compute_is_negative(&ui_sq) || Fixed::<S, F>::compute_is_zero(&ui_sq) {
return Err(OverflowDetected::DomainError);
}
let ui = Fixed::<S, F>::sqrt_at_compute_tier(ui_sq);
let den = Fixed::<S, F>::compute_multiply(Fixed::<S, F>::compute_add(one_minus_cos, one_minus_cos), ui);
let mut u = [zero; 3];
for k in 0..3 {
u[k] = if k == i { ui } else { Fixed::<S, F>::compute_divide(Fixed::<S, F>::compute_add(r.get(i, k), r.get(k, i)), den)? };
}
let mut dot = zero;
for k in 0..3 { dot = Fixed::<S, F>::compute_add(dot, Fixed::<S, F>::compute_multiply(u[k], d[k])); }
let sign_flip = Fixed::<S, F>::compute_is_negative(&dot);
let mut omega = [zero; 3];
for k in 0..3 {
let w = Fixed::<S, F>::compute_multiply(theta, u[k]);
omega[k] = if sign_flip { Fixed::<S, F>::compute_negate(w) } else { w };
}
Ok((omega, theta))
}
fn se3_exp_compute<S: Storage, const F: u32>(xi: &[Compute<Fixed<S, F>>]) -> Result<ComputeMatrix<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let omega = &xi[0..3];
let r = rodrigues_exp_compute(omega)?;
let (theta_sq, theta) = angle_compute(omega);
let (c1, c2) = if theta < se3_series_threshold::<S, F>() {
(
series(theta_sq, &[(1, 2), (-1, 24), (1, 720), (-1, 40320)])?,
series(theta_sq, &[(1, 6), (-1, 120), (1, 5040), (-1, 362880)])?,
)
} else {
let (sin_c, cos_c) = Fixed::<S, F>::sincos_at_compute_tier(theta);
(
Fixed::<S, F>::compute_divide(Fixed::<S, F>::compute_subtract(Fixed::<S, F>::make_compute_int(1), cos_c), theta_sq)?,
Fixed::<S, F>::compute_divide(Fixed::<S, F>::compute_divide(Fixed::<S, F>::compute_subtract(theta, sin_c), theta_sq)?, theta)?,
)
};
let k = hat_compute(omega);
let k2 = k.mat_mul(&k);
let v_mat = ComputeMatrix::<Fixed<S, F>>::identity(3).add(&k.scalar_mul(c1)).add(&k2.scalar_mul(c2));
let t = v_mat.mul_vector_compute(&xi[3..6]);
Ok(ComputeMatrix::<Fixed<S, F>>::from_fn(4, 4, |i, j| {
if i < 3 && j < 3 { r.get(i, j) }
else if i < 3 { t[i] }
else if j == 3 { Fixed::<S, F>::make_compute_int(1) }
else { Fixed::<S, F>::make_compute_int(0) }
}))
}
fn se3_log_compute<S: Storage, const F: u32>(g: &ComputeMatrix<Fixed<S, F>>) -> Result<[Compute<Fixed<S, F>>; 6], OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let r = ComputeMatrix::<Fixed<S, F>>::from_fn(3, 3, |i, j| g.get(i, j));
let t = [g.get(0, 3), g.get(1, 3), g.get(2, 3)];
let (omega, theta) = rodrigues_log_compute(&r)?;
let theta_sq = Fixed::<S, F>::compute_multiply(theta, theta);
let c2 = if theta < se3_series_threshold::<S, F>() {
series(theta_sq, &[(1, 12), (1, 720), (1, 30240), (1, 1209600)])?
} else {
let one = Fixed::<S, F>::make_compute_int(1);
let (sin_c, cos_c) = Fixed::<S, F>::sincos_at_compute_tier(theta);
let one_minus_cos = Fixed::<S, F>::compute_subtract(one, cos_c);
let alpha = Fixed::<S, F>::compute_divide(Fixed::<S, F>::compute_multiply(theta, sin_c), Fixed::<S, F>::compute_add(one_minus_cos, one_minus_cos))?;
Fixed::<S, F>::compute_divide(Fixed::<S, F>::compute_subtract(one, alpha), theta_sq)?
};
let k = hat_compute(&omega);
let k2 = k.mat_mul(&k);
let v_inv = ComputeMatrix::<Fixed<S, F>>::identity(3).sub(&k.halve()).add(&k2.scalar_mul(c2));
let v = v_inv.mul_vector_compute(&t);
Ok([omega[0], omega[1], omega[2], v[0], v[1], v[2]])
}
fn se3_inverse_compute<S: Storage, const F: u32>(g: &ComputeMatrix<Fixed<S, F>>) -> ComputeMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let mut out = ComputeMatrix::<Fixed<S, F>>::identity(4);
for i in 0..3 {
let mut acc = Fixed::<S, F>::make_compute_int(0);
for k in 0..3 {
out.set(i, k, g.get(k, i));
acc = Fixed::<S, F>::compute_add(acc, Fixed::<S, F>::compute_multiply(g.get(k, i), g.get(k, 3)));
}
out.set(i, 3, Fixed::<S, F>::compute_negate(acc));
}
out
}
fn up_all<S: Storage, const F: u32>(v: &FixedVector<Fixed<S, F>>) -> Vec<Compute<Fixed<S, F>>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{ (0..v.len()).map(|i| up(v[i])).collect() }
fn so3_log_map_compute<S: Storage, const F: u32>(base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>) -> Result<[Compute<Fixed<S, F>>; 3], OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let g_base = rodrigues_exp_compute(&up_all(base))?;
let g_target = rodrigues_exp_compute(&up_all(target))?;
Ok(rodrigues_log_compute(&g_base.transpose().mat_mul(&g_target))?.0)
}
fn se3_log_map_compute<S: Storage, const F: u32>(base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>) -> Result<[Compute<Fixed<S, F>>; 6], OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let g_base = se3_exp_compute(&up_all(base))?;
let g_target = se3_exp_compute(&up_all(target))?;
se3_log_compute(&se3_inverse_compute(&g_base).mat_mul(&g_target))
}
fn vraws<S: Storage, const F: u32>(v: &FixedVector<Fixed<S, F>>) -> Vec<S> where Fixed<S, F>: FixedNum<Storage = S> { (0..v.len()).map(|i| v[i].raw()).collect() }
fn mraws<S: Storage, const F: u32>(m: &FixedMatrix<Fixed<S, F>>) -> Vec<S> where Fixed<S, F>: FixedNum<Storage = S> {
let mut out = Vec::with_capacity(m.rows() * m.cols());
for i in 0..m.rows() { for j in 0..m.cols() { out.push(m.get(i, j).raw()); } }
out
}
fn as_vector<S: Storage, const F: u32>(r: Vec<S>) -> FixedVector<Fixed<S, F>> where Fixed<S, F>: FixedNum<Storage = S> {
FixedVector::from_slice(&r.into_iter().map(Fixed::<S, F>::from_raw).collect::<Vec<_>>())
}
fn as_matrix<S: Storage, const F: u32>(n: usize, r: Vec<S>) -> FixedMatrix<Fixed<S, F>> where Fixed<S, F>: FixedNum<Storage = S> {
FixedMatrix::from_slice(n, n, &r.into_iter().map(Fixed::<S, F>::from_raw).collect::<Vec<_>>())
}
impl SO3 {
pub fn hat_so3<S: Storage, const F: u32>(omega: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let (wx, wy, wz) = (omega[0], omega[1], omega[2]);
let z = Fixed::ZERO;
FixedMatrix::<Fixed<S, F>>::from_slice(3, 3, &[z, -wz, wy, wz, z, -wx, -wy, wx, z])
}
pub fn vee_so3<S: Storage, const F: u32>(m: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
FixedVector::<Fixed<S, F>>::from_slice(&[m.get(2, 1), m.get(0, 2), m.get(1, 0)])
}
pub fn rodrigues_exp<S: Storage, const F: u32>(omega: &FixedVector<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
assert_eq!(omega.len(), 3);
match exact_forms::settled::<Fixed<S, F>>(exact_forms::Op::So3Exp, &vraws(omega), &[], &[])? {
Some(r) => Ok(as_matrix(3, r)),
None => down_matrix(&rodrigues_exp_compute(&up_all(omega))?),
}
}
pub fn rodrigues_log<S: Storage, const F: u32>(r: &FixedMatrix<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
assert!(r.rows() == 3 && r.cols() == 3, "rodrigues_log: R must be 3x3");
match exact_forms::settled::<Fixed<S, F>>(exact_forms::Op::So3Log, &mraws(r), &[], &[])? {
Some(v) => Ok(as_vector(v)),
None => down_vector(&rodrigues_log_compute(&ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(r))?.0),
}
}
}
impl<S: Storage, const F: u32> Manifold<Fixed<S, F>> for SO3
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn dimension(&self) -> usize { 3 }
fn inner_product(&self, _base: &FixedVector<Fixed<S, F>>, u: &FixedVector<Fixed<S, F>>, v: &FixedVector<Fixed<S, F>>) -> Fixed<S, F> {
u.dot_precise(v)
}
fn exp_map(&self, base: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
if let Some(v) = exact_forms::settled::<Fixed<S, F>>(exact_forms::Op::So3ExpMap, &vraws(base), &vraws(tangent), &[])? { return Ok(as_vector(v)); }
let g_base = rodrigues_exp_compute(&up_all(base))?;
let g_tangent = rodrigues_exp_compute(&up_all(tangent))?;
down_vector(&rodrigues_log_compute(&g_base.mat_mul(&g_tangent))?.0)
}
fn log_map(&self, base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
if let Some(v) = exact_forms::settled::<Fixed<S, F>>(exact_forms::Op::So3LogMap, &vraws(base), &vraws(target), &[])? { return Ok(as_vector(v)); }
down_vector(&so3_log_map_compute(base, target)?)
}
fn distance(&self, p: &FixedVector<Fixed<S, F>>, q: &FixedVector<Fixed<S, F>>) -> Result<Fixed<S, F>, OverflowDetected> {
if let Some(v) = exact_forms::settled::<Fixed<S, F>>(exact_forms::Op::So3Dist, &vraws(p), &vraws(q), &[])? { return Ok(Fixed::from_raw(v[0])); }
norm_to_storage(&so3_log_map_compute(p, q)?)
}
fn parallel_transport(&self, base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
if let Some(v) = exact_forms::settled::<Fixed<S, F>>(exact_forms::Op::So3Transport, &vraws(base), &vraws(target), &vraws(tangent))? { return Ok(as_vector(v)); }
let diff = so3_log_map_compute(base, target)?;
let half = [Fixed::<S, F>::compute_halve(diff[0]), Fixed::<S, F>::compute_halve(diff[1]), Fixed::<S, F>::compute_halve(diff[2])];
let r_half = rodrigues_exp_compute(&half)?;
down_vector(&r_half.mul_vector_compute(&up_all(tangent)))
}
}
impl<S: Storage, const F: u32> LieGroup<Fixed<S, F>> for SO3
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn algebra_dim(&self) -> usize { 3 }
fn matrix_dim(&self) -> usize { 3 }
fn identity_element(&self) -> FixedMatrix<Fixed<S, F>> { FixedMatrix::<Fixed<S, F>>::identity(3) }
fn compose(&self, g1: &FixedMatrix<Fixed<S, F>>, g2: &FixedMatrix<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { g1 * g2 }
fn group_inverse(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> { Ok(g.transpose()) }
fn lie_exp(&self, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> { SO3::rodrigues_exp(xi) }
fn lie_log(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> { SO3::rodrigues_log(g) }
fn hat(&self, xi: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { SO3::hat_so3(xi) }
fn vee(&self, xi_hat: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> { SO3::vee_so3(xi_hat) }
fn adjoint(&self, g: &FixedMatrix<Fixed<S, F>>, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
Ok(g.mul_vector(xi)) }
fn bracket(&self, xi: &FixedVector<Fixed<S, F>>, eta: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> {
let c = cross_exact(xi, eta);
down_vector(&c).expect("SO3::bracket: result exceeds storage")
}
fn act(&self, g: &FixedMatrix<Fixed<S, F>>, point: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> {
g.mul_vector(point)
}
}
pub struct SE3;
impl SE3 {
pub fn hat_se3<S: Storage, const F: u32>(xi: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
assert_eq!(xi.len(), 6);
let z = Fixed::ZERO;
FixedMatrix::<Fixed<S, F>>::from_slice(4, 4, &[
z, -xi[2], xi[1], xi[3],
xi[2], z, -xi[0], xi[4],
-xi[1], xi[0], z, xi[5],
z, z, z, z,
])
}
pub fn vee_se3<S: Storage, const F: u32>(m: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
FixedVector::<Fixed<S, F>>::from_slice(&[m.get(2, 1), m.get(0, 2), m.get(1, 0), m.get(0, 3), m.get(1, 3), m.get(2, 3)])
}
pub fn extract_rotation<S: Storage, const F: u32>(g: &FixedMatrix<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
g.submatrix(0, 0, 3, 3)
}
pub fn extract_translation<S: Storage, const F: u32>(g: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
FixedVector::<Fixed<S, F>>::from_slice(&[g.get(0, 3), g.get(1, 3), g.get(2, 3)])
}
pub fn from_rt<S: Storage, const F: u32>(r: &FixedMatrix<Fixed<S, F>>, t: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let mut m = FixedMatrix::<Fixed<S, F>>::new(4, 4);
m.set_submatrix(0, 0, r);
m.set(0, 3, t[0]); m.set(1, 3, t[1]); m.set(2, 3, t[2]);
m.set(3, 3, Fixed::one());
m
}
pub fn se3_exp<S: Storage, const F: u32>(xi: &FixedVector<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
assert_eq!(xi.len(), 6);
match exact_forms::settled::<Fixed<S, F>>(exact_forms::Op::Se3Exp, &vraws(xi), &[], &[])? {
Some(r) => Ok(as_matrix(4, r)),
None => down_matrix(&se3_exp_compute(&up_all(xi))?),
}
}
pub fn se3_log<S: Storage, const F: u32>(g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
match exact_forms::settled::<Fixed<S, F>>(exact_forms::Op::Se3Log, &mraws(g), &[], &[])? {
Some(v) => Ok(as_vector(v)),
None => down_vector(&se3_log_compute(&ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(g))?),
}
}
}
impl<S: Storage, const F: u32> Manifold<Fixed<S, F>> for SE3
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn dimension(&self) -> usize { 6 }
fn inner_product(&self, _base: &FixedVector<Fixed<S, F>>, u: &FixedVector<Fixed<S, F>>, v: &FixedVector<Fixed<S, F>>) -> Fixed<S, F> {
u.dot_precise(v)
}
fn exp_map(&self, base: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
if let Some(v) = exact_forms::settled::<Fixed<S, F>>(exact_forms::Op::Se3ExpMap, &vraws(base), &vraws(tangent), &[])? { return Ok(as_vector(v)); }
let g_base = se3_exp_compute(&up_all(base))?;
let g_tangent = se3_exp_compute(&up_all(tangent))?;
down_vector(&se3_log_compute(&g_base.mat_mul(&g_tangent))?)
}
fn log_map(&self, base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
if let Some(v) = exact_forms::settled::<Fixed<S, F>>(exact_forms::Op::Se3LogMap, &vraws(base), &vraws(target), &[])? { return Ok(as_vector(v)); }
down_vector(&se3_log_map_compute(base, target)?)
}
fn distance(&self, p: &FixedVector<Fixed<S, F>>, q: &FixedVector<Fixed<S, F>>) -> Result<Fixed<S, F>, OverflowDetected> {
if let Some(v) = exact_forms::settled::<Fixed<S, F>>(exact_forms::Op::Se3Dist, &vraws(p), &vraws(q), &[])? { return Ok(Fixed::from_raw(v[0])); }
norm_to_storage(&se3_log_map_compute(p, q)?)
}
fn parallel_transport(&self, _base: &FixedVector<Fixed<S, F>>, _target: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
Ok(tangent.clone())
}
}
impl<S: Storage, const F: u32> LieGroup<Fixed<S, F>> for SE3
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn algebra_dim(&self) -> usize { 6 }
fn matrix_dim(&self) -> usize { 4 }
fn identity_element(&self) -> FixedMatrix<Fixed<S, F>> { FixedMatrix::<Fixed<S, F>>::identity(4) }
fn compose(&self, g1: &FixedMatrix<Fixed<S, F>>, g2: &FixedMatrix<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { g1 * g2 }
fn group_inverse(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> {
let r = SE3::extract_rotation(g);
let t = SE3::extract_translation(g);
let rt = r.transpose();
let t_raw: Vec<S> = (0..3).map(|i| t[i].raw()).collect();
let mut neg_rt_t = FixedVector::<Fixed<S, F>>::new(3);
for i in 0..3 {
let col: Vec<S> = (0..3).map(|k| r.get(k, i).raw()).collect();
neg_rt_t[i] = down(Fixed::<S, F>::compute_negate(kernels::exact_dot::<Fixed<S, F>>(&col, &t_raw)?))?;
}
Ok(SE3::from_rt(&rt, &neg_rt_t))
}
fn lie_exp(&self, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> { SE3::se3_exp(xi) }
fn lie_log(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> { SE3::se3_log(g) }
fn hat(&self, xi: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { SE3::hat_se3(xi) }
fn vee(&self, xi_hat: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> { SE3::vee_se3(xi_hat) }
fn adjoint(&self, g: &FixedMatrix<Fixed<S, F>>, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
let r = SE3::extract_rotation(g);
let t = SE3::extract_translation(g);
let omega: Vec<S> = (0..3).map(|i| xi[i].raw()).collect();
let v: Vec<S> = (0..3).map(|i| xi[3 + i].raw()).collect();
let mut r_omega = [Fixed::<S, F>::make_compute_int(0); 3];
let mut r_v = [Fixed::<S, F>::make_compute_int(0); 3];
for i in 0..3 {
let row: Vec<S> = (0..3).map(|k| r.get(i, k).raw()).collect();
r_omega[i] = kernels::exact_dot::<Fixed<S, F>>(&row, &omega)?;
r_v[i] = kernels::exact_dot::<Fixed<S, F>>(&row, &v)?;
}
let one = Fixed::one().raw();
let mut out = FixedVector::<Fixed<S, F>>::new(6);
for i in 0..3 {
out[i] = down(r_omega[i])?;
let (j, k) = ((i + 1) % 3, (i + 2) % 3);
out[3 + i] = triple_to_storage(&[
(r_v[i], one),
(r_omega[k], t[j].raw()),
(Fixed::<S, F>::compute_negate(r_omega[j]), t[k].raw()),
], false)?;
}
Ok(out)
}
fn bracket(&self, xi: &FixedVector<Fixed<S, F>>, eta: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> {
let w1 = FixedVector::<Fixed<S, F>>::from_slice(&[xi[0], xi[1], xi[2]]);
let v1 = FixedVector::<Fixed<S, F>>::from_slice(&[xi[3], xi[4], xi[5]]);
let w2 = FixedVector::<Fixed<S, F>>::from_slice(&[eta[0], eta[1], eta[2]]);
let v2 = FixedVector::<Fixed<S, F>>::from_slice(&[eta[3], eta[4], eta[5]]);
let w = cross_exact(&w1, &w2);
let (a, b) = (cross_exact(&w1, &v2), cross_exact(&w2, &v1));
let out = [w[0], w[1], w[2],
Fixed::<S, F>::compute_subtract(a[0], b[0]), Fixed::<S, F>::compute_subtract(a[1], b[1]), Fixed::<S, F>::compute_subtract(a[2], b[2])];
down_vector(&out).expect("SE3::bracket: result exceeds storage")
}
fn act(&self, g: &FixedMatrix<Fixed<S, F>>, point: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> {
let r = SE3::extract_rotation(g);
let t = SE3::extract_translation(g);
&r.mul_vector(point) + &t
}
}
pub struct SOn {
pub n: usize,
}
impl SOn {
pub fn hat_son<S: Storage, const F: u32>(&self, xi: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = self.n;
let mut m = FixedMatrix::<Fixed<S, F>>::new(n, n);
let mut k = 0;
for i in 0..n {
for j in (i + 1)..n {
m.set(i, j, xi[k]);
m.set(j, i, -xi[k]);
k += 1;
}
}
m
}
pub fn vee_son<S: Storage, const F: u32>(&self, m: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = self.n;
let dim = n * (n - 1) / 2;
let mut v = FixedVector::<Fixed<S, F>>::new(dim);
let mut k = 0;
for i in 0..n {
for j in (i + 1)..n {
v[k] = m.get(i, j);
k += 1;
}
}
v
}
fn vee_son_compute<S: Storage, const F: u32>(&self, m: &ComputeMatrix<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = self.n;
let mut v = Vec::with_capacity(n * (n - 1) / 2);
for i in 0..n {
for j in (i + 1)..n { v.push(m.get(i, j)); }
}
down_vector(&v)
}
fn log_compute<S: Storage, const F: u32>(&self, g: &ComputeMatrix<Fixed<S, F>>) -> Result<Vec<Compute<Fixed<S, F>>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let skew = skew_half(&matrix_log_compute(g)?);
let n = self.n;
let mut v = Vec::with_capacity(n * (n - 1) / 2);
for i in 0..n {
for j in (i + 1)..n { v.push(skew.get(i, j)); }
}
Ok(v)
}
fn exp_compute<S: Storage, const F: u32>(&self, xi: &FixedVector<Fixed<S, F>>) -> Result<ComputeMatrix<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
matrix_exp_compute(&ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(&self.hat_son(xi)))
}
fn log_map_compute<S: Storage, const F: u32>(&self, base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>) -> Result<Vec<Compute<Fixed<S, F>>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let g = self.exp_compute(base)?.transpose().mat_mul(&self.exp_compute(target)?);
self.log_compute(&g)
}
}
impl<S: Storage, const F: u32> Manifold<Fixed<S, F>> for SOn
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn dimension(&self) -> usize { self.n * (self.n - 1) / 2 }
fn inner_product(&self, _base: &FixedVector<Fixed<S, F>>, u: &FixedVector<Fixed<S, F>>, v: &FixedVector<Fixed<S, F>>) -> Fixed<S, F> { u.dot_precise(v) }
fn exp_map(&self, base: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
let g = self.exp_compute(base)?.mat_mul(&self.exp_compute(tangent)?);
down_vector(&self.log_compute(&g)?)
}
fn log_map(&self, base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
down_vector(&self.log_map_compute(base, target)?)
}
fn distance(&self, p: &FixedVector<Fixed<S, F>>, q: &FixedVector<Fixed<S, F>>) -> Result<Fixed<S, F>, OverflowDetected> {
norm_to_storage(&self.log_map_compute(p, q)?)
}
fn parallel_transport(&self, _base: &FixedVector<Fixed<S, F>>, _target: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
Ok(tangent.clone())
}
}
impl<S: Storage, const F: u32> LieGroup<Fixed<S, F>> for SOn
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn algebra_dim(&self) -> usize { self.n * (self.n - 1) / 2 }
fn matrix_dim(&self) -> usize { self.n }
fn identity_element(&self) -> FixedMatrix<Fixed<S, F>> { FixedMatrix::<Fixed<S, F>>::identity(self.n) }
fn compose(&self, g1: &FixedMatrix<Fixed<S, F>>, g2: &FixedMatrix<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { g1 * g2 }
fn group_inverse(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> { Ok(g.transpose()) }
fn lie_exp(&self, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> {
matrix_exp(&self.hat_son(xi))
}
fn lie_log(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
down_vector(&self.log_compute(&ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(g))?)
}
fn hat(&self, xi: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { self.hat_son(xi) }
fn vee(&self, xi_hat: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> { self.vee_son(xi_hat) }
fn adjoint(&self, g: &FixedMatrix<Fixed<S, F>>, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
Ok(self.vee_son(&conjugate_exact(g, &self.hat_son(xi), g)?))
}
fn bracket(&self, xi: &FixedVector<Fixed<S, F>>, eta: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> {
self.vee_son_compute(&commutator_exact(&self.hat_son(xi), &self.hat_son(eta)))
.expect("SOn::bracket: result exceeds storage")
}
fn act(&self, g: &FixedMatrix<Fixed<S, F>>, point: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> {
g.mul_vector(point)
}
}
pub struct GLn {
pub n: usize,
}
impl GLn {
pub fn hat_gln<S: Storage, const F: u32>(&self, xi: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = self.n;
FixedMatrix::<Fixed<S, F>>::from_fn(n, n, |i, j| xi[i * n + j])
}
pub fn vee_gln<S: Storage, const F: u32>(&self, m: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = self.n;
let mut v = FixedVector::<Fixed<S, F>>::new(n * n);
for i in 0..n {
for j in 0..n {
v[i * n + j] = m.get(i, j);
}
}
v
}
fn vee_gln_compute<S: Storage, const F: u32>(&self, m: &ComputeMatrix<Fixed<S, F>>) -> Vec<Compute<Fixed<S, F>>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = self.n;
(0..n * n).map(|k| m.get(k / n, k % n)).collect()
}
fn exp_compute<S: Storage, const F: u32>(&self, xi: &FixedVector<Fixed<S, F>>) -> Result<ComputeMatrix<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
matrix_exp_compute(&ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(&self.hat_gln(xi)))
}
fn log_map_compute<S: Storage, const F: u32>(&self, base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>) -> Result<Vec<Compute<Fixed<S, F>>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let g = inverse_compute(&self.exp_compute(base)?)?.mat_mul(&self.exp_compute(target)?);
Ok(self.vee_gln_compute(&matrix_log_compute(&g)?))
}
}
impl<S: Storage, const F: u32> Manifold<Fixed<S, F>> for GLn
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn dimension(&self) -> usize { self.n * self.n }
fn inner_product(&self, _base: &FixedVector<Fixed<S, F>>, u: &FixedVector<Fixed<S, F>>, v: &FixedVector<Fixed<S, F>>) -> Fixed<S, F> {
u.dot_precise(v)
}
fn exp_map(&self, base: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
let g = self.exp_compute(base)?.mat_mul(&self.exp_compute(tangent)?);
down_vector(&self.vee_gln_compute(&matrix_log_compute(&g)?))
}
fn log_map(&self, base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
down_vector(&self.log_map_compute(base, target)?)
}
fn distance(&self, p: &FixedVector<Fixed<S, F>>, q: &FixedVector<Fixed<S, F>>) -> Result<Fixed<S, F>, OverflowDetected> {
norm_to_storage(&self.log_map_compute(p, q)?)
}
fn parallel_transport(&self, _base: &FixedVector<Fixed<S, F>>, _target: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
Ok(tangent.clone())
}
}
impl<S: Storage, const F: u32> LieGroup<Fixed<S, F>> for GLn
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn algebra_dim(&self) -> usize { self.n * self.n }
fn matrix_dim(&self) -> usize { self.n }
fn identity_element(&self) -> FixedMatrix<Fixed<S, F>> { FixedMatrix::<Fixed<S, F>>::identity(self.n) }
fn compose(&self, g1: &FixedMatrix<Fixed<S, F>>, g2: &FixedMatrix<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { g1 * g2 }
fn group_inverse(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> {
down_matrix(&inverse_compute(&ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(g))?)
}
fn lie_exp(&self, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> { matrix_exp(&self.hat_gln(xi)) }
fn lie_log(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> { Ok(self.vee_gln(&matrix_log(g)?)) }
fn hat(&self, xi: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { self.hat_gln(xi) }
fn vee(&self, xi_hat: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> { self.vee_gln(xi_hat) }
fn adjoint(&self, g: &FixedMatrix<Fixed<S, F>>, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
down_vector(&self.vee_gln_compute(&conjugate_by_inverse(g, &self.hat_gln(xi))?))
}
fn bracket(&self, xi: &FixedVector<Fixed<S, F>>, eta: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> {
let c = commutator_exact(&self.hat_gln(xi), &self.hat_gln(eta));
down_vector(&self.vee_gln_compute(&c)).expect("GLn::bracket: result exceeds storage")
}
fn act(&self, g: &FixedMatrix<Fixed<S, F>>, point: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> { g.mul_vector(point) }
}
pub struct On {
pub n: usize,
}
impl<S: Storage, const F: u32> Manifold<Fixed<S, F>> for On
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn dimension(&self) -> usize { self.n * (self.n - 1) / 2 }
fn inner_product(&self, _base: &FixedVector<Fixed<S, F>>, u: &FixedVector<Fixed<S, F>>, v: &FixedVector<Fixed<S, F>>) -> Fixed<S, F> { u.dot_precise(v) }
fn exp_map(&self, base: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> { SOn { n: self.n }.exp_map(base, tangent) }
fn log_map(&self, base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> { SOn { n: self.n }.log_map(base, target) }
fn distance(&self, p: &FixedVector<Fixed<S, F>>, q: &FixedVector<Fixed<S, F>>) -> Result<Fixed<S, F>, OverflowDetected> { Ok(self.log_map(p, q)?.length()) }
fn parallel_transport(&self, _base: &FixedVector<Fixed<S, F>>, _target: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> { Ok(tangent.clone()) }
}
impl<S: Storage, const F: u32> LieGroup<Fixed<S, F>> for On
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn algebra_dim(&self) -> usize { self.n * (self.n - 1) / 2 }
fn matrix_dim(&self) -> usize { self.n }
fn identity_element(&self) -> FixedMatrix<Fixed<S, F>> { FixedMatrix::<Fixed<S, F>>::identity(self.n) }
fn compose(&self, g1: &FixedMatrix<Fixed<S, F>>, g2: &FixedMatrix<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { g1 * g2 }
fn group_inverse(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> { Ok(g.transpose()) }
fn lie_exp(&self, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> { SOn { n: self.n }.lie_exp(xi) }
fn lie_log(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> { SOn { n: self.n }.lie_log(g) }
fn hat(&self, xi: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { SOn { n: self.n }.hat_son(xi) }
fn vee(&self, xi_hat: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> { SOn { n: self.n }.vee_son(xi_hat) }
fn adjoint(&self, g: &FixedMatrix<Fixed<S, F>>, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> { SOn { n: self.n }.adjoint(g, xi) }
fn bracket(&self, xi: &FixedVector<Fixed<S, F>>, eta: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> { SOn { n: self.n }.bracket(xi, eta) }
fn act(&self, g: &FixedMatrix<Fixed<S, F>>, point: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> { g.mul_vector(point) }
}
pub struct SLn {
pub n: usize,
}
impl SLn {
pub fn hat_sln<S: Storage, const F: u32>(&self, xi: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = self.n;
let mut m = FixedMatrix::<Fixed<S, F>>::new(n, n);
let mut trace_sum = Fixed::ZERO;
for i in 0..n - 1 {
m.set(i, i, xi[i]);
trace_sum = trace_sum + xi[i];
}
m.set(n - 1, n - 1, -trace_sum);
let mut k = n - 1;
for i in 0..n {
for j in 0..n {
if i != j { m.set(i, j, xi[k]); k += 1; }
}
}
m
}
pub fn vee_sln<S: Storage, const F: u32>(&self, m: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = self.n;
let mut v = FixedVector::<Fixed<S, F>>::new(n * n - 1);
for i in 0..n - 1 { v[i] = m.get(i, i); }
let mut k = n - 1;
for i in 0..n {
for j in 0..n {
if i != j { v[k] = m.get(i, j); k += 1; }
}
}
v
}
pub fn project_traceless<S: Storage, const F: u32>(m: &FixedMatrix<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
down_matrix(&project_traceless_compute(&ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(m)))
.expect("SLn::project_traceless: result exceeds storage")
}
fn vee_sln_compute<S: Storage, const F: u32>(&self, m: &ComputeMatrix<Fixed<S, F>>) -> Vec<Compute<Fixed<S, F>>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = self.n;
let mut v: Vec<Compute<Fixed<S, F>>> = (0..n - 1).map(|i| m.get(i, i)).collect();
for i in 0..n {
for j in 0..n {
if i != j { v.push(m.get(i, j)); }
}
}
v
}
fn exp_compute<S: Storage, const F: u32>(&self, xi: &FixedVector<Fixed<S, F>>) -> Result<ComputeMatrix<Fixed<S, F>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
matrix_exp_compute(&ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(&self.hat_sln(xi)))
}
fn log_compute<S: Storage, const F: u32>(&self, g: &ComputeMatrix<Fixed<S, F>>) -> Result<Vec<Compute<Fixed<S, F>>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
Ok(self.vee_sln_compute(&project_traceless_compute(&matrix_log_compute(g)?)))
}
fn log_map_compute<S: Storage, const F: u32>(&self, base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>) -> Result<Vec<Compute<Fixed<S, F>>>, OverflowDetected>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let g = inverse_compute(&self.exp_compute(base)?)?.mat_mul(&self.exp_compute(target)?);
self.log_compute(&g)
}
}
fn project_traceless_compute<S: Storage, const F: u32>(m: &ComputeMatrix<Fixed<S, F>>) -> ComputeMatrix<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
let n = m.rows();
let mut trace = Fixed::<S, F>::make_compute_int(0);
for i in 0..n { trace = Fixed::<S, F>::compute_add(trace, m.get(i, i)); }
let trace_per_n = Fixed::<S, F>::compute_mul_div_int(trace, 1, n as i64).expect("project_traceless: n > 0");
let mut result = m.copy();
for i in 0..n { result.set(i, i, Fixed::<S, F>::compute_subtract(m.get(i, i), trace_per_n)); }
result
}
impl<S: Storage, const F: u32> Manifold<Fixed<S, F>> for SLn
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn dimension(&self) -> usize { self.n * self.n - 1 }
fn inner_product(&self, _base: &FixedVector<Fixed<S, F>>, u: &FixedVector<Fixed<S, F>>, v: &FixedVector<Fixed<S, F>>) -> Fixed<S, F> { u.dot_precise(v) }
fn exp_map(&self, base: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
let g = self.exp_compute(base)?.mat_mul(&self.exp_compute(tangent)?);
down_vector(&self.log_compute(&g)?)
}
fn log_map(&self, base: &FixedVector<Fixed<S, F>>, target: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
down_vector(&self.log_map_compute(base, target)?)
}
fn distance(&self, p: &FixedVector<Fixed<S, F>>, q: &FixedVector<Fixed<S, F>>) -> Result<Fixed<S, F>, OverflowDetected> {
norm_to_storage(&self.log_map_compute(p, q)?)
}
fn parallel_transport(&self, _base: &FixedVector<Fixed<S, F>>, _target: &FixedVector<Fixed<S, F>>, tangent: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> { Ok(tangent.clone()) }
}
impl<S: Storage, const F: u32> LieGroup<Fixed<S, F>> for SLn
where
Fixed<S, F>: FixedNum<Storage = S> + MatrixFunctions,
{
fn algebra_dim(&self) -> usize { self.n * self.n - 1 }
fn matrix_dim(&self) -> usize { self.n }
fn identity_element(&self) -> FixedMatrix<Fixed<S, F>> { FixedMatrix::<Fixed<S, F>>::identity(self.n) }
fn compose(&self, g1: &FixedMatrix<Fixed<S, F>>, g2: &FixedMatrix<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { g1 * g2 }
fn group_inverse(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> {
down_matrix(&inverse_compute(&ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(g))?)
}
fn lie_exp(&self, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedMatrix<Fixed<S, F>>, OverflowDetected> { matrix_exp(&self.hat_sln(xi)) }
fn lie_log(&self, g: &FixedMatrix<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
down_vector(&self.log_compute(&ComputeMatrix::<Fixed<S, F>>::from_fixed_matrix(g))?)
}
fn hat(&self, xi: &FixedVector<Fixed<S, F>>) -> FixedMatrix<Fixed<S, F>> { self.hat_sln(xi) }
fn vee(&self, xi_hat: &FixedMatrix<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> { self.vee_sln(xi_hat) }
fn adjoint(&self, g: &FixedMatrix<Fixed<S, F>>, xi: &FixedVector<Fixed<S, F>>) -> Result<FixedVector<Fixed<S, F>>, OverflowDetected> {
let conj = conjugate_by_inverse(g, &self.hat_sln(xi))?;
down_vector(&self.vee_sln_compute(&project_traceless_compute(&conj)))
}
fn bracket(&self, xi: &FixedVector<Fixed<S, F>>, eta: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> {
let c = commutator_exact(&self.hat_sln(xi), &self.hat_sln(eta));
down_vector(&self.vee_sln_compute(&c)).expect("SLn::bracket: result exceeds storage")
}
fn act(&self, g: &FixedMatrix<Fixed<S, F>>, point: &FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> { g.mul_vector(point) }
}
pub(crate) mod exact_forms {
use super::*;
use crate::fixed_point::domains::binary_fixed::transcendental::mpf::MpfErr;
use crate::fixed_point::exact::{settle, Formula, Num};
type R<X> = Result<X, MpfErr>;
type M3<B> = [[B; 3]; 3];
fn w<T: FixedNum, B: Num<T>>(x: T::Storage) -> R<B> { B::from_word(x, T::FRAC_BITS) }
fn vec3<T: FixedNum, B: Num<T>>(x: &[T::Storage]) -> R<[B; 3]> { Ok([w::<T, B>(x[0])?, w::<T, B>(x[1])?, w::<T, B>(x[2])?]) }
fn mat3<T: FixedNum, B: Num<T>>(m: &[T::Storage], stride: usize) -> R<M3<B>> {
let mut out = [[B::int(0)?; 3]; 3];
for i in 0..3 { for j in 0..3 { out[i][j] = w::<T, B>(m[i * stride + j])?; } }
Ok(out)
}
fn sq3<T: FixedNum, B: Num<T>>(v: &[B; 3]) -> R<B> { v[0].mul(v[0])?.add(v[1].mul(v[1])?)?.add(v[2].mul(v[2])?) }
fn hat<T: FixedNum, B: Num<T>>(v: &[B; 3]) -> R<M3<B>> {
let z = B::int(0)?;
Ok([[z, v[2].neg(), v[1]], [v[2], z, v[0].neg()], [v[1].neg(), v[0], z]])
}
fn matmul<T: FixedNum, B: Num<T>>(a: &M3<B>, b: &M3<B>) -> R<M3<B>> {
let mut out = [[B::int(0)?; 3]; 3];
for i in 0..3 { for j in 0..3 {
out[i][j] = a[i][0].mul(b[0][j])?.add(a[i][1].mul(b[1][j])?)?.add(a[i][2].mul(b[2][j])?)?;
} }
Ok(out)
}
fn transpose<B: Copy>(a: &M3<B>) -> M3<B> { [[a[0][0], a[1][0], a[2][0]], [a[0][1], a[1][1], a[2][1]], [a[0][2], a[1][2], a[2][2]]] }
fn mulvec<T: FixedNum, B: Num<T>>(a: &M3<B>, v: &[B; 3]) -> R<[B; 3]> {
let row = |i: usize| -> R<B> { a[i][0].mul(v[0])?.add(a[i][1].mul(v[1])?)?.add(a[i][2].mul(v[2])?) };
Ok([row(0)?, row(1)?, row(2)?])
}
fn poly<T: FixedNum, B: Num<T>>(k: &M3<B>, a: B, b: B) -> R<M3<B>> {
let k2 = matmul::<T, B>(k, k)?;
let mut out = [[B::int(0)?; 3]; 3];
for i in 0..3 { for j in 0..3 {
let id = if i == j { B::int(1)? } else { B::int(0)? };
out[i][j] = id.add(a.mul(k[i][j])?)?.add(b.mul(k2[i][j])?)?;
} }
Ok(out)
}
fn coeffs<T: FixedNum, B: Num<T>>(t2: B) -> R<(B, B, B)> {
if t2.is_exact_zero() { return Ok((t2, B::int(1)?, B::int(1)?.half())); }
let th = t2.sqrt()?;
let h = th.half();
let sh = h.sin()?.div(h)?;
Ok((th, th.sin()?.div(th)?, sh.mul(sh)?.half()))
}
pub(super) fn rod_exp<T: FixedNum, B: Num<T>>(omega: &[B; 3]) -> R<M3<B>> {
let (_, sinc, hc) = coeffs::<T, B>(sq3::<T, B>(omega)?)?;
poly::<T, B>(&hat::<T, B>(omega)?, sinc, hc)
}
pub(super) fn rod_log<T: FixedNum, B: Num<T>>(r: &M3<B>) -> R<([B; 3], B)> {
let one = B::int(1)?;
let zero = B::int(0)?;
let d = [r[2][1].sub(r[1][2])?, r[0][2].sub(r[2][0])?, r[1][0].sub(r[0][1])?];
let trm1 = r[0][0].add(r[1][1])?.add(r[2][2])?.sub(one)?;
if !trm1.sign_certain() { return Err(MpfErr::Undecided); }
let dn2 = sq3::<T, B>(&d)?;
let d_zero = dn2.is_exact_zero();
if !trm1.is_negative() {
if d_zero { return Ok(([zero, zero, zero], zero)); }
let dn = dn2.sqrt()?;
let theta = dn.atan2(trm1)?;
let s = theta.div(dn)?;
return Ok(([d[0].mul(s)?, d[1].mul(s)?, d[2].mul(s)?], theta));
}
let theta = if d_zero { zero.atan2(trm1)? } else { dn2.sqrt()?.atan2(trm1)? };
let cos_t = trm1.half();
let omc = one.sub(cos_t)?;
let mut i = 0;
for k in 1..3 { if r[i][i].sub(r[k][k])?.is_negative() { i = k; } }
let ui2 = r[i][i].sub(cos_t)?.div(omc)?;
if !ui2.sign_certain() { return Err(MpfErr::Undecided); }
if ui2.is_negative() || ui2.is_exact_zero() { return Err(MpfErr::Domain); }
let ui = ui2.sqrt()?;
let den = omc.add(omc)?.mul(ui)?;
let mut u = [zero; 3];
for k in 0..3 { u[k] = if k == i { ui } else { r[i][k].add(r[k][i])?.div(den)? }; }
let mut flip = false;
if !d_zero {
let dot = u[0].mul(d[0])?.add(u[1].mul(d[1])?)?.add(u[2].mul(d[2])?)?;
if !dot.sign_certain() { return Err(MpfErr::Undecided); }
flip = dot.is_negative();
}
let mut omega = [zero; 3];
for k in 0..3 { let v = theta.mul(u[k])?; omega[k] = if flip { v.neg() } else { v }; }
Ok((omega, theta))
}
pub(super) fn se3_exp<T: FixedNum, B: Num<T>>(xi: &[B; 6]) -> R<(M3<B>, [B; 3])> {
let omega = [xi[0], xi[1], xi[2]];
let t2 = sq3::<T, B>(&omega)?;
let (th, sinc, c1) = coeffs::<T, B>(t2)?;
let c2 = if t2.is_exact_zero() { B::int(1)?.div(B::int(6)?)? } else { th.sub(th.sin()?)?.div(t2.mul(th)?)? };
let k = hat::<T, B>(&omega)?;
let r = poly::<T, B>(&k, sinc, c1)?;
let v = poly::<T, B>(&k, c1, c2)?;
Ok((r, mulvec::<T, B>(&v, &[xi[3], xi[4], xi[5]])?))
}
pub(super) fn se3_log<T: FixedNum, B: Num<T>>(r: &M3<B>, t: &[B; 3]) -> R<[B; 6]> {
let (omega, theta) = rod_log::<T, B>(r)?;
let c = if theta.is_exact_zero() {
B::int(1)?.div(B::int(12)?)?
} else {
let h = theta.half();
let alpha = h.div(h.tan()?)?;
B::int(1)?.sub(alpha)?.div(theta.mul(theta)?)?
};
let k = hat::<T, B>(&omega)?;
let vinv = poly::<T, B>(&k, B::int(1)?.half().neg(), c)?;
let v = mulvec::<T, B>(&vinv, t)?;
Ok([omega[0], omega[1], omega[2], v[0], v[1], v[2]])
}
fn se3_inverse<T: FixedNum, B: Num<T>>(r: &M3<B>, t: &[B; 3]) -> R<(M3<B>, [B; 3])> {
let rt = transpose(r);
let m = mulvec::<T, B>(&rt, t)?;
Ok((rt, [m[0].neg(), m[1].neg(), m[2].neg()]))
}
fn se3_compose<T: FixedNum, B: Num<T>>(a: &(M3<B>, [B; 3]), b: &(M3<B>, [B; 3])) -> R<(M3<B>, [B; 3])> {
let r = matmul::<T, B>(&a.0, &b.0)?;
let m = mulvec::<T, B>(&a.0, &b.1)?;
Ok((r, [m[0].add(a.1[0])?, m[1].add(a.1[1])?, m[2].add(a.1[2])?]))
}
fn vec6<T: FixedNum, B: Num<T>>(x: &[T::Storage]) -> R<[B; 6]> {
let mut out = [B::int(0)?; 6];
for i in 0..6 { out[i] = w::<T, B>(x[i])?; }
Ok(out)
}
fn norm<T: FixedNum, B: Num<T>>(v: &[B]) -> R<B> {
let mut acc = B::int(0)?;
for x in v { acc = acc.add(x.mul(*x)?)?; }
acc.sqrt()
}
#[derive(Clone, Copy)]
pub(crate) enum Op { So3Exp, So3Log, So3ExpMap, So3LogMap, So3Dist, So3Transport, Se3Exp, Se3Log, Se3ExpMap, Se3LogMap, Se3Dist }
pub(crate) struct Form<'a, W> { pub op: Op, pub a: &'a [W], pub b: &'a [W], pub c: &'a [W] }
impl<'a, T: FixedNum> Formula<T> for Form<'a, T::Storage> {
fn eval<B: Num<T>>(&self) -> R<Vec<B>> {
let flat = |m: &M3<B>| -> Vec<B> { m.iter().flat_map(|row| row.iter().copied()).collect() };
Ok(match self.op {
Op::So3Exp => flat(&rod_exp::<T, B>(&vec3::<T, B>(self.a)?)?),
Op::So3Log => rod_log::<T, B>(&mat3::<T, B>(self.a, 3)?)?.0.to_vec(),
Op::So3ExpMap | Op::So3LogMap | Op::So3Dist | Op::So3Transport => {
let ga = rod_exp::<T, B>(&vec3::<T, B>(self.a)?)?;
let gb = rod_exp::<T, B>(&vec3::<T, B>(self.b)?)?;
let g = match self.op { Op::So3ExpMap => matmul::<T, B>(&ga, &gb)?, _ => matmul::<T, B>(&transpose(&ga), &gb)? };
let omega = rod_log::<T, B>(&g)?.0;
match self.op {
Op::So3Dist => vec![norm::<T, B>(&omega)?],
Op::So3Transport => {
let half = [omega[0].half(), omega[1].half(), omega[2].half()];
mulvec::<T, B>(&rod_exp::<T, B>(&half)?, &vec3::<T, B>(self.c)?)?.to_vec()
}
_ => omega.to_vec(),
}
}
Op::Se3Exp => {
let (r, t) = se3_exp::<T, B>(&vec6::<T, B>(self.a)?)?;
let (z, o) = (B::int(0)?, B::int(1)?);
vec![r[0][0], r[0][1], r[0][2], t[0], r[1][0], r[1][1], r[1][2], t[1], r[2][0], r[2][1], r[2][2], t[2], z, z, z, o]
}
Op::Se3Log => {
let r = mat3::<T, B>(self.a, 4)?;
let t = [w::<T, B>(self.a[3])?, w::<T, B>(self.a[7])?, w::<T, B>(self.a[11])?];
se3_log::<T, B>(&r, &t)?.to_vec()
}
Op::Se3ExpMap | Op::Se3LogMap | Op::Se3Dist => {
let ga = se3_exp::<T, B>(&vec6::<T, B>(self.a)?)?;
let gb = se3_exp::<T, B>(&vec6::<T, B>(self.b)?)?;
let g = match self.op { Op::Se3ExpMap => se3_compose::<T, B>(&ga, &gb)?, _ => se3_compose::<T, B>(&se3_inverse::<T, B>(&ga.0, &ga.1)?, &gb)? };
let xi = se3_log::<T, B>(&g.0, &g.1)?;
match self.op { Op::Se3Dist => vec![norm::<T, B>(&xi)?], _ => xi.to_vec() }
}
})
}
}
pub(crate) fn settled<T: FixedNum>(op: Op, a: &[T::Storage], b: &[T::Storage], c: &[T::Storage]) -> Result<Option<Vec<T::Storage>>, OverflowDetected> {
match settle::<T, _>(&Form { op, a, b, c }) {
Ok(v) => Ok(Some(v)),
Err(MpfErr::Domain) => Err(OverflowDetected::DomainError),
Err(MpfErr::Overflow) => Err(OverflowDetected::TierOverflow),
Err(_) => Ok(None),
}
}
}