use std::fmt::{Debug, Display};
use downcast_rs::{Downcast, impl_downcast};
use crate::{
dtype,
linalg::{
AllocatorBuffer, Const, DefaultAllocator, DimName, DualAllocator, DualVector, MatrixDim,
MatrixViewDim, Numeric, SupersetOf, VectorDim, VectorViewX, VectorX,
},
};
pub trait Variable: Clone + Sized + Display + Debug {
type T: Numeric;
type Dim: DimName;
const DIM: usize = Self::Dim::DIM;
type Alias<TT: Numeric>: Variable<T = TT>;
fn identity() -> Self;
fn inverse(&self) -> Self;
fn compose(&self, other: &Self) -> Self;
fn exp(delta: VectorViewX<Self::T>) -> Self;
fn log(&self) -> VectorX<Self::T>;
fn cast<TT: Numeric + SupersetOf<Self::T>>(&self) -> Self::Alias<TT>;
fn dim(&self) -> usize {
Self::DIM
}
#[inline]
fn oplus(&self, xi: VectorViewX<Self::T>) -> Self {
if cfg!(feature = "left") {
self.oplus_left(xi)
} else {
self.oplus_right(xi)
}
}
#[inline]
fn oplus_right(&self, xi: VectorViewX<Self::T>) -> Self {
self.compose(&Self::exp(xi))
}
#[inline]
fn oplus_left(&self, xi: VectorViewX<Self::T>) -> Self {
Self::exp(xi).compose(self)
}
#[inline]
fn ominus(&self, y: &Self) -> VectorX<Self::T> {
if cfg!(feature = "left") {
self.ominus_left(y)
} else {
self.ominus_right(y)
}
}
#[inline]
fn ominus_right(&self, y: &Self) -> VectorX<Self::T> {
y.inverse().compose(self).log()
}
#[inline]
fn ominus_left(&self, y: &Self) -> VectorX<Self::T> {
self.compose(&y.inverse()).log()
}
#[inline]
fn minus(&self, other: &Self) -> Self {
other.inverse().compose(self)
}
#[inline]
fn dual_exp<N: DimName>(idx: usize) -> Self::Alias<DualVector<N>>
where
AllocatorBuffer<N>: Sync + Send,
DefaultAllocator: DualAllocator<N>,
DualVector<N>: Copy,
{
let mut tv: VectorX<DualVector<N>> = VectorX::zeros(Self::DIM);
let n = VectorDim::<N>::zeros().shape_generic().0;
for (i, tvi) in tv.iter_mut().enumerate() {
tvi.eps = num_dual::Derivative::derivative_generic(n, Const::<1>, idx + i)
}
Self::Alias::<DualVector<N>>::exp(tv.as_view())
}
#[inline]
fn dual<N: DimName>(&self, idx: usize) -> Self::Alias<DualVector<N>>
where
AllocatorBuffer<N>: Sync + Send,
DefaultAllocator: DualAllocator<N>,
DualVector<N>: Copy + SupersetOf<Self::T>,
{
let casted: Self::Alias<DualVector<N>> = self.cast::<DualVector<N>>();
let setup: Self::Alias<DualVector<N>> = Self::dual_exp(idx);
if cfg!(feature = "left") {
setup.compose(&casted)
} else {
casted.compose(&setup)
}
}
}
#[cfg_attr(feature = "serde", typetag::serde(tag = "tag"))]
pub trait VariableSafe: Debug + Display + Downcast {
fn clone_box(&self) -> Box<dyn VariableSafe>;
fn dim(&self) -> usize;
fn oplus_mut(&mut self, delta: VectorViewX);
}
#[cfg_attr(feature = "serde", typetag::serde)]
impl<V: Variable<T = dtype> + 'static> VariableSafe for V {
fn clone_box(&self) -> Box<dyn VariableSafe> {
Box::new((*self).clone())
}
fn dim(&self) -> usize {
self.dim()
}
fn oplus_mut(&mut self, delta: VectorViewX) {
*self = self.oplus(delta);
}
}
impl_downcast!(VariableSafe);
impl Clone for Box<dyn VariableSafe> {
fn clone(&self) -> Self {
self.clone_box()
}
}
#[cfg(feature = "serde")]
pub use register_variablesafe as tag_variable;
pub trait VariableDtype: VariableSafe + Variable<T = dtype, Alias<dtype> = Self> {}
impl<V: VariableSafe + Variable<T = dtype, Alias<dtype> = V>> VariableDtype for V {}
use nalgebra as na;
pub trait MatrixLieGroup: Variable
where
na::DefaultAllocator: na::allocator::Allocator<Self::TangentDim, Self::TangentDim>,
na::DefaultAllocator: na::allocator::Allocator<Self::MatrixDim, Self::MatrixDim>,
na::DefaultAllocator: na::allocator::Allocator<Self::VectorDim, Self::TangentDim>,
na::DefaultAllocator: na::allocator::Allocator<Self::TangentDim, Const<1>>,
na::DefaultAllocator: na::allocator::Allocator<Self::VectorDim, Const<1>>,
{
type TangentDim: DimName;
type MatrixDim: DimName;
type VectorDim: DimName;
fn adjoint(&self) -> MatrixDim<Self::TangentDim, Self::TangentDim, Self::T>;
fn hat(
xi: MatrixViewDim<'_, Self::TangentDim, Const<1>, Self::T>,
) -> MatrixDim<Self::MatrixDim, Self::MatrixDim, Self::T>;
fn vee(
xi: MatrixViewDim<'_, Self::MatrixDim, Self::MatrixDim, Self::T>,
) -> MatrixDim<Self::TangentDim, Const<1>, Self::T>;
fn hat_swap(
xi: MatrixViewDim<'_, Self::VectorDim, Const<1>, Self::T>,
) -> MatrixDim<Self::VectorDim, Self::TangentDim, Self::T>;
fn apply(
&self,
v: MatrixViewDim<'_, Self::VectorDim, Const<1>, Self::T>,
) -> MatrixDim<Self::VectorDim, Const<1>, Self::T>;
fn to_matrix(&self) -> MatrixDim<Self::MatrixDim, Self::MatrixDim, Self::T>;
fn from_matrix(mat: MatrixViewDim<'_, Self::MatrixDim, Self::MatrixDim, Self::T>) -> Self;
}