1use nalgebra::{Matrix3, Vector3};
43use std::ops::{Mul, Neg};
44use std::{
45 error, fmt,
46 fmt::{Display, Formatter},
47};
48
49pub const SMALL_ANGLE_THRESHOLD: f64 = 1e-10;
64
65pub mod rn;
66pub mod se2;
67pub mod se23;
68pub mod se3;
69pub mod sgal3;
70pub mod sim3;
71pub mod so2;
72pub mod so3;
73
74#[derive(Debug, Clone, PartialEq)]
76pub enum ManifoldError {
77 InvalidTangentDimension { expected: usize, actual: usize },
79 NumericalInstability(String),
81 InvalidElement(String),
83 DimensionMismatch { expected: usize, actual: usize },
85 InvalidNumber,
87 NormalizationFailed(String),
89}
90
91#[derive(Debug, Clone, PartialEq)]
92pub enum ManifoldType {
93 RN,
94 SE2,
95 SE3,
96 SE23,
97 SGal3,
98 Sim3,
99 SO2,
100 SO3,
101}
102
103impl Display for ManifoldError {
104 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
105 match self {
106 ManifoldError::InvalidTangentDimension { expected, actual } => {
107 write!(
108 f,
109 "Invalid tangent dimension: expected {expected}, got {actual}"
110 )
111 }
112 ManifoldError::NumericalInstability(msg) => {
113 write!(f, "Numerical instability: {msg}")
114 }
115 ManifoldError::InvalidElement(msg) => {
116 write!(f, "Invalid manifold element: {msg}")
117 }
118 ManifoldError::DimensionMismatch { expected, actual } => {
119 write!(f, "Dimension mismatch: expected {expected}, got {actual}")
120 }
121 ManifoldError::InvalidNumber => {
122 write!(f, "Invalid number: NaN or Inf detected")
123 }
124 ManifoldError::NormalizationFailed(msg) => {
125 write!(f, "Normalization failed: {msg}")
126 }
127 }
128 }
129}
130
131impl error::Error for ManifoldError {}
132
133pub type ManifoldResult<T> = Result<T, ManifoldError>;
135
136pub trait LieGroup: Clone + PartialEq {
147 const NAME: &'static str;
149
150 type TangentVector: Tangent<Self>;
152
153 type JacobianMatrix: Clone
155 + PartialEq
156 + Neg<Output = Self::JacobianMatrix>
157 + Mul<Output = Self::JacobianMatrix>
158 + std::ops::Index<(usize, usize), Output = f64>;
159
160 type LieAlgebra: Clone + PartialEq;
162
163 fn inverse(&self, jacobian: Option<&mut Self::JacobianMatrix>) -> Self;
172
173 fn compose(
182 &self,
183 other: &Self,
184 jacobian_self: Option<&mut Self::JacobianMatrix>,
185 jacobian_other: Option<&mut Self::JacobianMatrix>,
186 ) -> Self;
187
188 fn log(&self, jacobian: Option<&mut Self::JacobianMatrix>) -> Self::TangentVector;
195
196 fn vee(&self) -> Self::TangentVector;
203
204 fn act(
213 &self,
214 vector: &Vector3<f64>,
215 jacobian_self: Option<&mut Self::JacobianMatrix>,
216 jacobian_vector: Option<&mut Matrix3<f64>>,
217 ) -> Vector3<f64>;
218
219 fn adjoint(&self) -> Self::JacobianMatrix;
226
227 fn random() -> Self;
231
232 fn jacobian_identity() -> Self::JacobianMatrix;
237
238 fn zero_jacobian() -> Self::JacobianMatrix;
243
244 fn normalize(&mut self);
248
249 fn is_valid(&self, tolerance: f64) -> bool;
251
252 fn is_approx(&self, other: &Self, tolerance: f64) -> bool;
258
259 fn as_param_slice(&self) -> &[f64];
263
264 fn as_param_slice_mut(&mut self) -> &mut [f64];
266
267 fn from_param_slice(s: &[f64]) -> Self;
269
270 fn right_plus(
286 &self,
287 tangent: &Self::TangentVector,
288 jacobian_self: Option<&mut Self::JacobianMatrix>,
289 jacobian_tangent: Option<&mut Self::JacobianMatrix>,
290 ) -> Self {
291 let exp_tangent = tangent.exp(None);
292
293 if let Some(jac_tangent) = jacobian_tangent {
294 *jac_tangent = tangent.right_jacobian();
295 }
296
297 self.compose(&exp_tangent, jacobian_self, None)
298 }
299
300 fn right_minus(
314 &self,
315 other: &Self,
316 jacobian_self: Option<&mut Self::JacobianMatrix>,
317 jacobian_other: Option<&mut Self::JacobianMatrix>,
318 ) -> Self::TangentVector {
319 let other_inverse = other.inverse(None);
320 let result_group = other_inverse.compose(self, None, None);
321 let result = result_group.log(None);
322
323 if let Some(jac_self) = jacobian_self {
324 *jac_self = result.right_jacobian_inv();
325 }
326
327 if let Some(jac_other) = jacobian_other {
328 *jac_other = -result.left_jacobian_inv();
329 }
330
331 result
332 }
333
334 fn left_plus(
341 &self,
342 tangent: &Self::TangentVector,
343 jacobian_tangent: Option<&mut Self::JacobianMatrix>,
344 jacobian_self: Option<&mut Self::JacobianMatrix>,
345 ) -> Self {
346 let exp_tangent = tangent.exp(None);
347 let result = exp_tangent.compose(self, None, None);
348
349 if let Some(jac_self) = jacobian_self {
350 *jac_self = self.adjoint();
351 }
352
353 if let Some(jac_tangent) = jacobian_tangent {
354 *jac_tangent = self.inverse(None).adjoint() * tangent.right_jacobian();
355 }
356
357 result
358 }
359
360 fn left_minus(
367 &self,
368 other: &Self,
369 jacobian_self: Option<&mut Self::JacobianMatrix>,
370 jacobian_other: Option<&mut Self::JacobianMatrix>,
371 ) -> Self::TangentVector {
372 let other_inverse = other.inverse(None);
373 let result_group = self.compose(&other_inverse, None, None);
374 let result = result_group.log(None);
375
376 if let Some(jac_self) = jacobian_self {
377 *jac_self = result.right_jacobian_inv() * other.adjoint();
378 }
379
380 if let Some(jac_other) = jacobian_other {
381 *jac_other = -(result.right_jacobian_inv() * other.adjoint());
382 }
383
384 result
385 }
386
387 fn plus(
391 &self,
392 tangent: &Self::TangentVector,
393 jacobian_self: Option<&mut Self::JacobianMatrix>,
394 jacobian_tangent: Option<&mut Self::JacobianMatrix>,
395 ) -> Self {
396 self.right_plus(tangent, jacobian_self, jacobian_tangent)
397 }
398
399 fn minus(
401 &self,
402 other: &Self,
403 jacobian_self: Option<&mut Self::JacobianMatrix>,
404 jacobian_other: Option<&mut Self::JacobianMatrix>,
405 ) -> Self::TangentVector {
406 self.right_minus(other, jacobian_self, jacobian_other)
407 }
408
409 fn between(
418 &self,
419 other: &Self,
420 jacobian_self: Option<&mut Self::JacobianMatrix>,
421 jacobian_other: Option<&mut Self::JacobianMatrix>,
422 ) -> Self {
423 let self_inverse = self.inverse(None);
424 let result = self_inverse.compose(other, None, None);
425
426 if let Some(jac_self) = jacobian_self {
427 *jac_self = -result.inverse(None).adjoint();
428 }
429
430 if let Some(jac_other) = jacobian_other {
431 *jac_other = Self::jacobian_identity();
432 }
433
434 result
435 }
436
437 fn tangent_dim(&self) -> usize {
450 Self::TangentVector::DIM
451 }
452}
453
454pub trait Tangent<Group: LieGroup>: Clone + PartialEq {
463 const DIM: usize;
472
473 fn is_dynamic() -> bool {
478 Self::DIM == 0
479 }
480
481 fn exp(&self, jacobian: Option<&mut Group::JacobianMatrix>) -> Group;
488
489 fn right_jacobian(&self) -> Group::JacobianMatrix;
494
495 fn left_jacobian(&self) -> Group::JacobianMatrix;
500
501 fn right_jacobian_inv(&self) -> Group::JacobianMatrix;
503
504 fn left_jacobian_inv(&self) -> Group::JacobianMatrix;
506
507 fn hat(&self) -> Group::LieAlgebra;
515
516 fn small_adj(&self) -> Group::JacobianMatrix;
522
523 fn lie_bracket(&self, other: &Self) -> Group::TangentVector;
529
530 fn is_approx(&self, other: &Self, tolerance: f64) -> bool;
536
537 fn generator(&self, i: usize) -> Group::LieAlgebra;
539
540 fn zero() -> Group::TangentVector;
544
545 fn random() -> Group::TangentVector;
547
548 fn is_zero(&self, tolerance: f64) -> bool;
550
551 fn normalize(&mut self);
553
554 fn normalized(&self) -> Group::TangentVector;
556
557 fn as_slice(&self) -> &[f64];
559
560 fn from_slice(s: &[f64]) -> Self;
562}
563
564pub trait Interpolatable: LieGroup {
566 fn interp(&self, other: &Self, t: f64) -> Self;
574
575 fn slerp(&self, other: &Self, t: f64) -> Self;
577}
578
579#[cfg(test)]
580mod tests {
581 use crate::LieGroup;
582 use crate::Tangent;
583 use crate::so2::{SO2, SO2Tangent};
584 use crate::so3::{SO3, SO3Tangent};
585 use crate::{ManifoldError, ManifoldType};
586 use nalgebra::Matrix1;
587
588 fn make_so2(angle: f64) -> SO2 {
589 SO2::from_angle(angle)
590 }
591
592 fn make_so2_tangent(angle: f64) -> SO2Tangent {
593 SO2Tangent::new(angle)
594 }
595
596 #[test]
597 fn manifold_error_display_invalid_tangent_dimension() {
598 let e = ManifoldError::InvalidTangentDimension {
599 expected: 3,
600 actual: 6,
601 };
602 let s = e.to_string();
603 assert!(s.contains("3"), "got: {s}");
604 assert!(s.contains("6"), "got: {s}");
605 }
606
607 #[test]
608 fn manifold_error_display_numerical_instability() {
609 let e = ManifoldError::NumericalInstability("singularity".to_string());
610 assert!(e.to_string().contains("singularity"));
611 }
612
613 #[test]
614 fn manifold_error_display_invalid_element() {
615 let e = ManifoldError::InvalidElement("bad quaternion".to_string());
616 assert!(e.to_string().contains("bad quaternion"));
617 }
618
619 #[test]
620 fn manifold_error_display_dimension_mismatch() {
621 let e = ManifoldError::DimensionMismatch {
622 expected: 4,
623 actual: 3,
624 };
625 let s = e.to_string();
626 assert!(s.contains("4") && s.contains("3"), "got: {s}");
627 }
628
629 #[test]
630 fn manifold_error_display_invalid_number() {
631 let e = ManifoldError::InvalidNumber;
632 assert!(!e.to_string().is_empty());
633 }
634
635 #[test]
636 fn manifold_error_display_normalization_failed() {
637 let e = ManifoldError::NormalizationFailed("zero vector".to_string());
638 assert!(e.to_string().contains("zero vector"));
639 }
640
641 #[test]
642 fn manifold_error_is_std_error() {
643 let e = ManifoldError::InvalidNumber;
644 let _: &dyn std::error::Error = &e;
645 }
646
647 #[test]
648 fn manifold_type_variants_are_distinct() {
649 let types = [
650 ManifoldType::RN,
651 ManifoldType::SE2,
652 ManifoldType::SE3,
653 ManifoldType::SE23,
654 ManifoldType::SGal3,
655 ManifoldType::Sim3,
656 ManifoldType::SO2,
657 ManifoldType::SO3,
658 ];
659 assert_eq!(types.len(), 8);
660 assert_eq!(ManifoldType::SO3, ManifoldType::SO3);
661 assert_ne!(ManifoldType::SO2, ManifoldType::SO3);
662 }
663
664 #[test]
665 fn default_right_plus_no_jacobians() {
666 let g = make_so2(0.3);
667 let t = make_so2_tangent(0.1);
668 let result = g.right_plus(&t, None, None);
669 assert!(result.is_valid(1e-9));
670 }
671
672 #[test]
673 fn default_right_plus_with_jacobians() {
674 let g = make_so2(0.3);
675 let t = make_so2_tangent(0.1);
676 let mut j_self = Matrix1::zeros();
677 let mut j_tan = Matrix1::zeros();
678 let result = g.right_plus(&t, Some(&mut j_self), Some(&mut j_tan));
679 assert!(result.is_valid(1e-9));
680 assert!(j_tan[0].is_finite());
681 }
682
683 #[test]
684 fn default_right_minus_no_jacobians() {
685 let g1 = make_so2(0.5);
686 let g2 = make_so2(0.2);
687 let _t = g1.right_minus(&g2, None, None);
688 }
689
690 #[test]
691 fn default_right_minus_with_jacobians() {
692 let g1 = make_so2(0.5);
693 let g2 = make_so2(0.2);
694 let mut j_self = Matrix1::zeros();
695 let mut j_other = Matrix1::zeros();
696 let _t = g1.right_minus(&g2, Some(&mut j_self), Some(&mut j_other));
697 assert!(j_self[0].is_finite());
698 assert!(j_other[0].is_finite());
699 }
700
701 #[test]
702 fn default_left_plus_no_jacobians() {
703 let g = make_so2(0.3);
704 let t = make_so2_tangent(0.1);
705 let result = g.left_plus(&t, None, None);
706 assert!(result.is_valid(1e-9));
707 }
708
709 #[test]
710 fn default_left_plus_with_jacobians() {
711 let g = make_so2(0.3);
712 let t = make_so2_tangent(0.1);
713 let mut j_tan = Matrix1::zeros();
714 let mut j_self = Matrix1::zeros();
715 let result = g.left_plus(&t, Some(&mut j_tan), Some(&mut j_self));
716 assert!(result.is_valid(1e-9));
717 assert!(j_tan[0].is_finite());
718 assert!(j_self[0].is_finite());
719 }
720
721 #[test]
722 fn default_left_minus_no_jacobians() {
723 let g1 = make_so2(0.5);
724 let g2 = make_so2(0.2);
725 let _t = g1.left_minus(&g2, None, None);
726 }
727
728 #[test]
729 fn default_left_minus_with_jacobians() {
730 let g1 = make_so2(0.5);
731 let g2 = make_so2(0.2);
732 let mut j_self = Matrix1::zeros();
733 let mut j_other = Matrix1::zeros();
734 let _t = g1.left_minus(&g2, Some(&mut j_self), Some(&mut j_other));
735 assert!(j_self[0].is_finite());
736 assert!(j_other[0].is_finite());
737 }
738
739 #[test]
740 fn default_plus_delegates_to_right_plus() {
741 let g = make_so2(0.3);
742 let t = make_so2_tangent(0.1);
743 let r1 = g.plus(&t, None, None);
744 let r2 = g.right_plus(&t, None, None);
745 assert!(r1.is_approx(&r2, 1e-9));
746 }
747
748 #[test]
749 fn default_minus_delegates_to_right_minus() {
750 let g1 = make_so2(0.5);
751 let g2 = make_so2(0.2);
752 let t1 = g1.minus(&g2, None, None);
753 let t2 = g1.right_minus(&g2, None, None);
754 assert!(t1.is_approx(&t2, 1e-9));
755 }
756
757 #[test]
758 fn default_between_no_jacobians() {
759 let g1 = make_so2(0.3);
760 let g2 = make_so2(0.7);
761 let b = g1.between(&g2, None, None);
762 assert!(b.is_valid(1e-9));
763 }
764
765 #[test]
766 fn default_between_with_jacobians() {
767 let g1 = make_so2(0.3);
768 let g2 = make_so2(0.7);
769 let mut j_self = Matrix1::zeros();
770 let mut j_other = Matrix1::zeros();
771 let b = g1.between(&g2, Some(&mut j_self), Some(&mut j_other));
772 assert!(b.is_valid(1e-9));
773 assert!(j_self[0].is_finite());
774 assert!(j_other[0].is_finite());
775 }
776
777 #[test]
778 fn default_tangent_dim_returns_dof() {
779 let g = make_so2(0.0);
780 assert_eq!(g.tangent_dim(), 1); }
782
783 #[test]
784 fn tangent_is_dynamic_false_for_so2() {
785 assert!(!SO2Tangent::is_dynamic());
786 }
787
788 #[test]
789 fn manifold_error_clone_and_partial_eq() {
790 let e = ManifoldError::InvalidTangentDimension {
791 expected: 1,
792 actual: 2,
793 };
794 let e2 = e.clone();
795 assert_eq!(e, e2);
796
797 let e3 = ManifoldError::NumericalInstability("x".to_string());
798 let e4 = e3.clone();
799 assert_eq!(e3, e4);
800
801 let e5 = ManifoldError::InvalidElement("y".to_string());
802 let e6 = e5.clone();
803 assert_eq!(e5, e6);
804
805 let e7 = ManifoldError::DimensionMismatch {
806 expected: 3,
807 actual: 4,
808 };
809 let e8 = e7.clone();
810 assert_eq!(e7, e8);
811
812 let e9 = ManifoldError::InvalidNumber;
813 let e10 = e9.clone();
814 assert_eq!(e9, e10);
815
816 let e11 = ManifoldError::NormalizationFailed("z".to_string());
817 let e12 = e11.clone();
818 assert_eq!(e11, e12);
819 }
820
821 #[test]
822 fn manifold_type_clone_and_eq() {
823 let all_types = [
824 ManifoldType::RN,
825 ManifoldType::SE2,
826 ManifoldType::SE3,
827 ManifoldType::SE23,
828 ManifoldType::SGal3,
829 ManifoldType::Sim3,
830 ManifoldType::SO2,
831 ManifoldType::SO3,
832 ];
833 for t in &all_types {
834 let t2 = t.clone();
835 assert_eq!(t, &t2);
836 }
837 assert_ne!(ManifoldType::RN, ManifoldType::SE2);
839 assert_ne!(ManifoldType::SE2, ManifoldType::SE3);
840 assert_ne!(ManifoldType::SE3, ManifoldType::SE23);
841 assert_ne!(ManifoldType::SE23, ManifoldType::SGal3);
842 assert_ne!(ManifoldType::SGal3, ManifoldType::Sim3);
843 assert_ne!(ManifoldType::Sim3, ManifoldType::SO2);
844 assert_ne!(ManifoldType::SO2, ManifoldType::SO3);
845 }
846
847 #[test]
848 fn manifold_type_debug() {
849 let s = format!("{:?}", ManifoldType::RN);
850 assert!(!s.is_empty());
851 let s2 = format!("{:?}", ManifoldType::SE23);
852 assert!(!s2.is_empty());
853 let s3 = format!("{:?}", ManifoldType::SGal3);
854 assert!(!s3.is_empty());
855 let s4 = format!("{:?}", ManifoldType::Sim3);
856 assert!(!s4.is_empty());
857 }
858
859 #[test]
860 fn manifold_error_debug() {
861 let e = ManifoldError::InvalidNumber;
862 let s = format!("{e:?}");
863 assert!(!s.is_empty());
864 }
865
866 #[test]
869 fn so3_default_right_plus_with_jacobians() {
870 use crate::LieGroup;
871 let r = SO3::from_euler_angles(0.1, 0.2, 0.3);
872 let t = SO3Tangent::new(nalgebra::Vector3::new(0.05, 0.0, 0.0));
873 let mut j_self = nalgebra::Matrix3::zeros();
874 let mut j_tan = nalgebra::Matrix3::zeros();
875 let result = r.right_plus(&t, Some(&mut j_self), Some(&mut j_tan));
876 assert!(result.is_valid(1e-6));
877 assert!(j_self[(0, 0)].is_finite());
878 assert!(j_tan[(0, 0)].is_finite());
879 }
880
881 #[test]
882 fn so3_default_left_plus_with_jacobians() {
883 use crate::LieGroup;
884 let r = SO3::from_euler_angles(0.1, 0.2, 0.3);
885 let t = SO3Tangent::new(nalgebra::Vector3::new(0.05, 0.0, 0.0));
886 let mut j_tan = nalgebra::Matrix3::zeros();
887 let mut j_self = nalgebra::Matrix3::zeros();
888 let result = r.left_plus(&t, Some(&mut j_tan), Some(&mut j_self));
889 assert!(result.is_valid(1e-6));
890 assert!(j_tan[(0, 0)].is_finite());
891 assert!(j_self[(0, 0)].is_finite());
892 }
893
894 #[test]
895 fn so3_default_right_minus_with_jacobians() {
896 use crate::LieGroup;
897 let r1 = SO3::from_euler_angles(0.3, 0.1, 0.2);
898 let r2 = SO3::from_euler_angles(0.1, 0.0, 0.1);
899 let mut j_self = nalgebra::Matrix3::zeros();
900 let mut j_other = nalgebra::Matrix3::zeros();
901 let _t = r1.right_minus(&r2, Some(&mut j_self), Some(&mut j_other));
902 assert!(j_self[(0, 0)].is_finite());
903 assert!(j_other[(0, 0)].is_finite());
904 }
905
906 #[test]
907 fn so3_default_left_minus_with_jacobians() {
908 use crate::LieGroup;
909 let r1 = SO3::from_euler_angles(0.3, 0.1, 0.2);
910 let r2 = SO3::from_euler_angles(0.1, 0.0, 0.1);
911 let mut j_self = nalgebra::Matrix3::zeros();
912 let mut j_other = nalgebra::Matrix3::zeros();
913 let _t = r1.left_minus(&r2, Some(&mut j_self), Some(&mut j_other));
914 assert!(j_self[(0, 0)].is_finite());
915 assert!(j_other[(0, 0)].is_finite());
916 }
917
918 #[test]
919 fn so3_default_between_with_jacobians() {
920 use crate::LieGroup;
921 let r1 = SO3::from_euler_angles(0.1, 0.2, 0.3);
922 let r2 = SO3::from_euler_angles(0.4, 0.1, 0.2);
923 let mut j_self = nalgebra::Matrix3::zeros();
924 let mut j_other = nalgebra::Matrix3::zeros();
925 let b = r1.between(&r2, Some(&mut j_self), Some(&mut j_other));
926 assert!(b.is_valid(1e-6));
927 assert!(j_self[(0, 0)].is_finite());
928 assert!(j_other[(0, 0)].is_finite());
929 }
930
931 #[test]
932 fn so3_default_tangent_dim() {
933 use crate::LieGroup;
934 let r = SO3::identity();
935 assert_eq!(r.tangent_dim(), 3);
936 }
937}