1use crate::{Interpolatable, LieGroup, Tangent};
25use nalgebra::{DMatrix, DVector, Matrix3, Vector3};
26use std::{
27 fmt,
28 fmt::{Display, Formatter},
29};
30
31#[derive(Clone, PartialEq)]
35pub struct Rn {
36 data: DVector<f64>,
38}
39
40impl Display for Rn {
41 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
42 write!(f, "Rn(dim: {}, data: [", self.data.len())?;
43 for (i, val) in self.data.iter().enumerate() {
44 if i > 0 {
45 write!(f, ", ")?;
46 }
47 write!(f, "{:.4}", val)?;
48 }
49 write!(f, "])")
50 }
51}
52
53impl From<DVector<f64>> for Rn {
55 fn from(data: DVector<f64>) -> Self {
56 Rn::new(data)
57 }
58}
59
60impl From<Rn> for DVector<f64> {
61 fn from(rn: Rn) -> Self {
62 rn.data
63 }
64}
65
66#[derive(Clone, PartialEq)]
71pub struct RnTangent {
72 data: DVector<f64>,
74}
75impl From<DVector<f64>> for RnTangent {
76 fn from(data: DVector<f64>) -> Self {
77 RnTangent::new(data)
78 }
79}
80
81impl From<RnTangent> for DVector<f64> {
82 fn from(rn: RnTangent) -> Self {
83 rn.data
84 }
85}
86
87impl Display for RnTangent {
88 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
89 write!(f, "rn(dim: {}, data: [", self.data.len())?;
90 for (i, val) in self.data.iter().enumerate() {
91 if i > 0 {
92 write!(f, ", ")?;
93 }
94 write!(f, "{:.4}", val)?;
95 }
96 write!(f, "])")
97 }
98}
99
100impl Rn {
101 #[deprecated(
104 note = "Rn is dynamic: this const is the 0 sentinel, not a dimension. Use is_dynamic() and tangent_dim()."
105 )]
106 pub const DIM: usize = 0;
107
108 #[deprecated(
111 note = "Rn is dynamic: this const is the 0 sentinel, not a DOF. Use tangent_dim()."
112 )]
113 pub const DOF: usize = 0;
114
115 #[deprecated(
118 note = "Rn is dynamic: this const is the 0 sentinel, not a size. Use as_param_slice().len()."
119 )]
120 pub const REP_SIZE: usize = 0;
121
122 pub fn identity() -> Self {
127 Rn::new(DVector::zeros(3))
128 }
129
130 pub fn jacobian_identity() -> DMatrix<f64> {
135 DMatrix::identity(3, 3)
136 }
137
138 #[inline]
143 pub fn new(data: DVector<f64>) -> Self {
144 Rn { data }
145 }
146
147 pub fn from_slice(slice: &[f64]) -> Self {
152 Rn::new(DVector::from_row_slice(slice))
153 }
154
155 pub fn from_vec(components: Vec<f64>) -> Self {
157 Rn::new(DVector::from_vec(components))
158 }
159
160 #[inline]
162 pub fn data(&self) -> &DVector<f64> {
163 &self.data
164 }
165
166 #[inline]
168 pub fn dim(&self) -> usize {
169 self.data.len()
170 }
171
172 #[inline]
174 pub fn component(&self, index: usize) -> f64 {
175 self.data[index]
176 }
177
178 pub fn set_component(&mut self, index: usize, value: f64) {
180 self.data[index] = value;
181 }
182
183 #[inline]
185 pub fn norm(&self) -> f64 {
186 self.data.norm()
187 }
188
189 #[inline]
191 pub fn norm_squared(&self) -> f64 {
192 self.data.norm_squared()
193 }
194
195 #[inline]
197 pub fn to_vector(&self) -> DVector<f64> {
198 self.data.clone()
199 }
200}
201
202impl LieGroup for Rn {
203 const NAME: &'static str = "Rn";
204
205 type TangentVector = RnTangent;
206 type JacobianMatrix = DMatrix<f64>;
207 type LieAlgebra = DMatrix<f64>;
208
209 fn inverse(&self, jacobian: Option<&mut Self::JacobianMatrix>) -> Self {
218 let dim = self.data.len();
219 if let Some(jac) = jacobian {
220 *jac = -DMatrix::identity(dim, dim);
221 }
222 Rn::new(-&self.data)
223 }
224
225 fn compose(
236 &self,
237 other: &Self,
238 jacobian_self: Option<&mut Self::JacobianMatrix>,
239 jacobian_other: Option<&mut Self::JacobianMatrix>,
240 ) -> Self {
241 assert_eq!(
242 self.data.len(),
243 other.data.len(),
244 "Rn elements must have the same dimension for composition"
245 );
246
247 let dim = self.data.len();
248 if let Some(jac_self) = jacobian_self {
249 *jac_self = DMatrix::identity(dim, dim);
250 }
251 if let Some(jac_other) = jacobian_other {
252 *jac_other = DMatrix::identity(dim, dim);
253 }
254
255 Rn::new(&self.data + &other.data)
256 }
257
258 fn log(&self, jacobian: Option<&mut Self::JacobianMatrix>) -> Self::TangentVector {
267 let dim = self.data.len();
268 if let Some(jac) = jacobian {
269 *jac = DMatrix::identity(dim, dim);
270 }
271 RnTangent::new(self.data.clone())
272 }
273
274 fn vee(&self) -> Self::TangentVector {
278 self.log(None)
279 }
280
281 fn act(
295 &self,
296 vector: &Vector3<f64>,
297 jacobian_self: Option<&mut Self::JacobianMatrix>,
298 jacobian_vector: Option<&mut Matrix3<f64>>,
299 ) -> Vector3<f64> {
300 debug_assert_eq!(
301 self.data.len(),
302 3,
303 "Rn::act is the translation action on R³ and is only defined for Rn(3)"
304 );
305 if let Some(jac_self) = jacobian_self {
306 *jac_self = DMatrix::identity(3, 3);
307 }
308 if let Some(jac_vector) = jacobian_vector {
309 *jac_vector = Matrix3::identity();
310 }
311
312 Vector3::new(
313 self.data[0] + vector.x,
314 self.data[1] + vector.y,
315 self.data[2] + vector.z,
316 )
317 }
318
319 fn adjoint(&self) -> Self::JacobianMatrix {
324 let dim = self.data.len();
325 DMatrix::identity(dim, dim)
326 }
327
328 fn random() -> Self {
330 let data = DVector::from_fn(3, |_, _| rand::random::<f64>() * 10.0 - 5.0);
332 Rn::new(data)
333 }
334
335 fn jacobian_identity() -> Self::JacobianMatrix {
336 DMatrix::identity(3, 3)
338 }
339
340 fn zero_jacobian() -> Self::JacobianMatrix {
341 DMatrix::zeros(3, 3)
343 }
344
345 fn jacobian_identity_for(&self) -> Self::JacobianMatrix {
353 Rn::jacobian_identity_with_dim(self.dim())
354 }
355
356 fn normalize(&mut self) {
357 let norm = self.data.norm();
358 if norm > 1e-12 {
359 self.data /= norm;
360 }
361 }
362
363 fn is_valid(&self, _tolerance: f64) -> bool {
364 self.data.iter().all(|x| x.is_finite())
365 }
366
367 fn as_param_slice(&self) -> &[f64] {
368 self.data.as_slice()
369 }
370
371 fn as_param_slice_mut(&mut self) -> &mut [f64] {
372 self.data.as_mut_slice()
373 }
374
375 fn from_param_slice(s: &[f64]) -> Self {
376 Rn::from_slice(s)
377 }
378
379 fn is_approx(&self, other: &Self, tolerance: f64) -> bool {
385 if self.data.len() != other.data.len() {
386 return false;
387 }
388 let difference = self.right_minus(other, None, None);
389 difference.is_zero(tolerance)
390 }
391
392 fn right_plus(
409 &self,
410 tangent: &Self::TangentVector,
411 jacobian_self: Option<&mut Self::JacobianMatrix>,
412 jacobian_tangent: Option<&mut Self::JacobianMatrix>,
413 ) -> Self {
414 assert_eq!(
415 self.data.len(),
416 tangent.data.len(),
417 "Rn element and tangent must have the same dimension"
418 );
419
420 let dim = self.data.len();
421
422 if let Some(jac_self) = jacobian_self {
423 *jac_self = DMatrix::identity(dim, dim);
424 }
425
426 if let Some(jac_tangent) = jacobian_tangent {
427 *jac_tangent = DMatrix::identity(dim, dim);
428 }
429
430 Rn::new(&self.data + &tangent.data)
431 }
432
433 fn right_minus(
446 &self,
447 other: &Self,
448 jacobian_self: Option<&mut Self::JacobianMatrix>,
449 jacobian_other: Option<&mut Self::JacobianMatrix>,
450 ) -> Self::TangentVector {
451 assert_eq!(
452 self.data.len(),
453 other.data.len(),
454 "Rn elements must have the same dimension"
455 );
456
457 let dim = self.data.len();
458
459 if let Some(jac_self) = jacobian_self {
460 *jac_self = DMatrix::identity(dim, dim);
461 }
462
463 if let Some(jac_other) = jacobian_other {
464 *jac_other = -DMatrix::identity(dim, dim);
465 }
466
467 RnTangent::new(&self.data - &other.data)
468 }
469
470 fn left_plus(
482 &self,
483 tangent: &Self::TangentVector,
484 jacobian_tangent: Option<&mut Self::JacobianMatrix>,
485 jacobian_self: Option<&mut Self::JacobianMatrix>,
486 ) -> Self {
487 assert_eq!(
488 self.data.len(),
489 tangent.data.len(),
490 "Rn element and tangent must have the same dimension"
491 );
492
493 let dim = self.data.len();
494
495 if let Some(jac_tangent) = jacobian_tangent {
496 *jac_tangent = DMatrix::identity(dim, dim);
497 }
498
499 if let Some(jac_self) = jacobian_self {
500 *jac_self = DMatrix::identity(dim, dim);
501 }
502
503 Rn::new(&tangent.data + &self.data)
505 }
506
507 fn left_minus(
519 &self,
520 other: &Self,
521 jacobian_self: Option<&mut Self::JacobianMatrix>,
522 jacobian_other: Option<&mut Self::JacobianMatrix>,
523 ) -> Self::TangentVector {
524 self.right_minus(other, jacobian_self, jacobian_other)
526 }
527
528 fn tangent_dim(&self) -> usize {
537 self.data.len()
538 }
539}
540
541impl RnTangent {
542 #[inline]
547 pub fn new(data: DVector<f64>) -> Self {
548 RnTangent { data }
549 }
550
551 pub fn from_slice(slice: &[f64]) -> Self {
556 RnTangent::new(DVector::from_row_slice(slice))
557 }
558
559 pub fn from_vec(components: Vec<f64>) -> Self {
561 RnTangent::new(DVector::from_vec(components))
562 }
563
564 #[inline]
566 pub fn data(&self) -> &DVector<f64> {
567 &self.data
568 }
569
570 #[inline]
572 pub fn dim(&self) -> usize {
573 self.data.len()
574 }
575
576 #[inline]
578 pub fn component(&self, index: usize) -> f64 {
579 self.data[index]
580 }
581
582 pub fn set_component(&mut self, index: usize, value: f64) {
584 self.data[index] = value;
585 }
586
587 #[inline]
589 pub fn norm(&self) -> f64 {
590 self.data.norm()
591 }
592
593 #[inline]
595 pub fn norm_squared(&self) -> f64 {
596 self.data.norm_squared()
597 }
598
599 #[inline]
601 pub fn to_vector(&self) -> DVector<f64> {
602 self.data.clone()
603 }
604
605 pub fn from_vector(data: DVector<f64>) -> Self {
607 RnTangent::new(data)
608 }
609}
610
611impl Tangent<Rn> for RnTangent {
612 const DIM: usize = 0;
615
616 fn exp(&self, jacobian: Option<&mut <Rn as LieGroup>::JacobianMatrix>) -> Rn {
625 let dim = self.data.len();
626 if let Some(jac) = jacobian {
627 *jac = DMatrix::identity(dim, dim);
628 }
629 Rn::new(self.data.clone())
630 }
631
632 fn right_jacobian(&self) -> <Rn as LieGroup>::JacobianMatrix {
633 let dim = self.data.len();
634 DMatrix::identity(dim, dim)
635 }
636
637 fn left_jacobian(&self) -> <Rn as LieGroup>::JacobianMatrix {
638 let dim = self.data.len();
639 DMatrix::identity(dim, dim)
640 }
641
642 fn right_jacobian_inv(&self) -> <Rn as LieGroup>::JacobianMatrix {
643 let dim = self.data.len();
644 DMatrix::identity(dim, dim)
645 }
646
647 fn left_jacobian_inv(&self) -> <Rn as LieGroup>::JacobianMatrix {
648 let dim = self.data.len();
649 DMatrix::identity(dim, dim)
650 }
651
652 fn hat(&self) -> <Rn as LieGroup>::LieAlgebra {
657 DMatrix::from_diagonal(&self.data)
658 }
659
660 fn small_adj(&self) -> <Rn as LieGroup>::JacobianMatrix {
662 let dim = self.data.len();
663 DMatrix::zeros(dim, dim)
664 }
665
666 fn lie_bracket(&self, _other: &Self) -> <Rn as LieGroup>::TangentVector {
670 RnTangent::new(DVector::zeros(self.data.len()))
671 }
672
673 fn is_approx(&self, other: &Self, tolerance: f64) -> bool {
679 if self.data.len() != other.data.len() {
680 return false;
681 }
682 (&self.data - &other.data).norm() < tolerance
683 }
684
685 fn generator(&self, i: usize) -> <Rn as LieGroup>::LieAlgebra {
689 let dim = self.data.len();
690 let mut generator_matrix = DMatrix::zeros(dim, dim);
691 generator_matrix[(i, i)] = 1.0;
692 generator_matrix
693 }
694
695 fn zero() -> <Rn as LieGroup>::TangentVector {
697 RnTangent::new(DVector::zeros(3))
699 }
700
701 fn random() -> <Rn as LieGroup>::TangentVector {
703 let data = DVector::from_fn(3, |_, _| rand::random::<f64>() * 10.0 - 5.0);
705 RnTangent::new(data)
706 }
707
708 fn is_zero(&self, tolerance: f64) -> bool {
710 self.data.norm() < tolerance
711 }
712
713 fn normalize(&mut self) {
715 let norm = self.data.norm();
716 if norm > 1e-12 {
717 self.data /= norm;
718 }
719 }
720
721 fn normalized(&self) -> <Rn as LieGroup>::TangentVector {
723 let mut result = self.clone();
724 result.normalize();
725 result
726 }
727
728 fn as_slice(&self) -> &[f64] {
729 self.data.as_slice()
730 }
731
732 fn from_slice(s: &[f64]) -> Self {
733 RnTangent::from_slice(s)
734 }
735}
736
737impl Interpolatable for Rn {
739 fn interp(&self, other: &Self, t: f64) -> Self {
747 assert_eq!(
748 self.data.len(),
749 other.data.len(),
750 "Rn elements must have the same dimension for interpolation"
751 );
752
753 let interpolated = &self.data * (1.0 - t) + &other.data * t;
754 Rn::new(interpolated)
755 }
756
757 fn slerp(&self, other: &Self, t: f64) -> Self {
759 self.interp(other, t)
760 }
761}
762
763impl Rn {
765 pub fn identity_with_dim(dim: usize) -> Self {
771 Rn::new(DVector::zeros(dim))
772 }
773
774 pub fn zeros(dim: usize) -> Self {
776 Rn::new(DVector::zeros(dim))
777 }
778
779 pub fn ones(dim: usize) -> Self {
781 Rn::new(DVector::from_element(dim, 1.0))
782 }
783
784 pub fn random_with_dim(dim: usize) -> Self {
786 let data = DVector::from_fn(dim, |_, _| rand::random::<f64>() * 10.0 - 5.0);
787 Rn::new(data)
788 }
789
790 pub fn jacobian_identity_with_dim(dim: usize) -> DMatrix<f64> {
792 DMatrix::identity(dim, dim)
793 }
794}
795
796impl RnTangent {
797 pub fn zero_with_dim(dim: usize) -> Self {
799 RnTangent::new(DVector::zeros(dim))
800 }
801
802 pub fn zeros(dim: usize) -> Self {
804 RnTangent::new(DVector::zeros(dim))
805 }
806
807 pub fn ones(dim: usize) -> Self {
809 RnTangent::new(DVector::from_element(dim, 1.0))
810 }
811
812 pub fn random_with_dim(dim: usize) -> Self {
814 let data = DVector::from_fn(dim, |_, _| rand::random::<f64>() * 2.0 - 1.0);
815 RnTangent::new(data)
816 }
817}
818
819#[cfg(test)]
820mod tests {
821 use super::*;
822 use crate::{Interpolatable, LieGroup, Tangent};
823
824 #[test]
825 fn test_rn_basic_operations() {
826 let v1 = Rn::from_vec(vec![1.0, 2.0, 3.0]);
828 let v2 = Rn::from_vec(vec![4.0, 5.0, 6.0]);
829
830 let sum = v1.compose(&v2, None, None);
832 assert_eq!(sum.component(0), 5.0);
833 assert_eq!(sum.component(1), 7.0);
834 assert_eq!(sum.component(2), 9.0);
835
836 let identity = Rn::zeros(3);
838 let result = v1.compose(&identity, None, None);
839 assert_eq!(result.component(0), v1.component(0));
840 assert_eq!(result.component(1), v1.component(1));
841 assert_eq!(result.component(2), v1.component(2));
842
843 let v1_inv = v1.inverse(None);
845 assert_eq!(v1_inv.component(0), -1.0);
846 assert_eq!(v1_inv.component(1), -2.0);
847 assert_eq!(v1_inv.component(2), -3.0);
848
849 let tangent = v1.log(None);
851 let recovered = tangent.exp(None);
852 assert!((recovered.component(0) - v1.component(0)).abs() < 1e-10);
853 assert!((recovered.component(1) - v1.component(1)).abs() < 1e-10);
854 assert!((recovered.component(2) - v1.component(2)).abs() < 1e-10);
855 }
856
857 #[test]
858 fn test_rn_tangent_operations() {
859 let t1 = RnTangent::from_vec(vec![1.0, 2.0, 3.0]);
860 let t2 = RnTangent::from_vec(vec![4.0, 5.0, 6.0]);
861
862 let bracket = t1.lie_bracket(&t2);
864 assert!(bracket.is_zero(1e-10));
865
866 let zero = RnTangent::zeros(3);
868 assert!(zero.is_zero(1e-10));
869
870 let mut t = RnTangent::from_vec(vec![3.0, 4.0, 0.0]);
872 t.normalize();
873 assert!((t.norm() - 1.0).abs() < 1e-10);
874 }
875
876 #[test]
877 fn test_rn_interpolation() {
878 let v1 = Rn::from_vec(vec![0.0, 0.0, 0.0]);
879 let v2 = Rn::from_vec(vec![10.0, 20.0, 30.0]);
880
881 let mid = v1.interp(&v2, 0.5);
883 assert_eq!(mid.component(0), 5.0);
884 assert_eq!(mid.component(1), 10.0);
885 assert_eq!(mid.component(2), 15.0);
886
887 let start = v1.interp(&v2, 0.0);
889 let end = v1.interp(&v2, 1.0);
890 assert!(v1.is_approx(&start, 1e-10));
891 assert!(v2.is_approx(&end, 1e-10));
892 }
893
894 #[test]
895 fn test_rn_different_dimensions() {
896 let v2d = Rn::from_vec(vec![1.0, 2.0]);
898 assert_eq!(v2d.dim(), 2);
899
900 let v1d = Rn::from_vec(vec![5.0]);
902 assert_eq!(v1d.dim(), 1);
903
904 let v5d = Rn::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
906 assert_eq!(v5d.dim(), 5);
907 assert_eq!(v5d.component(4), 5.0);
908 }
909
910 #[test]
911 fn test_rn_action() {
912 let translation = Rn::from_vec(vec![1.0, 2.0, 3.0]);
914 let point = Vector3::new(4.0, 5.0, 6.0);
915 let transformed = translation.act(&point, None, None);
916
917 assert_eq!(transformed.x, 5.0);
918 assert_eq!(transformed.y, 7.0);
919 assert_eq!(transformed.z, 9.0);
920 }
921
922 #[test]
923 fn test_rn_right_plus_operations() {
924 let v = Rn::from_vec(vec![1.0, 2.0, 3.0]);
925 let delta = RnTangent::from_vec(vec![0.1, 0.2, 0.3]);
926
927 let result = v.right_plus(&delta, None, None);
929 assert!((result.component(0) - 1.1).abs() < 1e-10);
930 assert!((result.component(1) - 2.2).abs() < 1e-10);
931 assert!((result.component(2) - 3.3).abs() < 1e-10);
932
933 let mut jac_self = DMatrix::zeros(3, 3);
935 let mut jac_tangent = DMatrix::zeros(3, 3);
936 let result_jac = v.right_plus(&delta, Some(&mut jac_self), Some(&mut jac_tangent));
937
938 assert!((result_jac.component(0) - result.component(0)).abs() < 1e-10);
940 assert!((result_jac.component(1) - result.component(1)).abs() < 1e-10);
941 assert!((result_jac.component(2) - result.component(2)).abs() < 1e-10);
942
943 let identity = DMatrix::identity(3, 3);
945 assert!((jac_self - &identity).norm() < 1e-10);
946 assert!((jac_tangent - &identity).norm() < 1e-10);
947 }
948
949 #[test]
950 fn test_rn_right_minus_operations() {
951 let v1 = Rn::from_vec(vec![5.0, 7.0, 9.0]);
952 let v2 = Rn::from_vec(vec![1.0, 2.0, 3.0]);
953
954 let result = v1.right_minus(&v2, None, None);
956 assert!((result.component(0) - 4.0).abs() < 1e-10);
957 assert!((result.component(1) - 5.0).abs() < 1e-10);
958 assert!((result.component(2) - 6.0).abs() < 1e-10);
959
960 let mut jac_self = DMatrix::zeros(3, 3);
962 let mut jac_other = DMatrix::zeros(3, 3);
963 let result_jac = v1.right_minus(&v2, Some(&mut jac_self), Some(&mut jac_other));
964
965 assert!((result_jac.component(0) - result.component(0)).abs() < 1e-10);
967 assert!((result_jac.component(1) - result.component(1)).abs() < 1e-10);
968 assert!((result_jac.component(2) - result.component(2)).abs() < 1e-10);
969
970 let identity = DMatrix::identity(3, 3);
972 let neg_identity = -&identity;
973 assert!((jac_self - &identity).norm() < 1e-10);
974 assert!((jac_other - &neg_identity).norm() < 1e-10);
975 }
976
977 #[test]
978 fn test_rn_left_plus_operations() {
979 let v = Rn::from_vec(vec![1.0, 2.0, 3.0]);
980 let delta = RnTangent::from_vec(vec![0.1, 0.2, 0.3]);
981
982 let result = v.left_plus(&delta, None, None);
984 assert!((result.component(0) - 1.1).abs() < 1e-10);
985 assert!((result.component(1) - 2.2).abs() < 1e-10);
986 assert!((result.component(2) - 3.3).abs() < 1e-10);
987
988 let mut jac_tangent = DMatrix::zeros(3, 3);
990 let mut jac_self = DMatrix::zeros(3, 3);
991 let result_jac = v.left_plus(&delta, Some(&mut jac_tangent), Some(&mut jac_self));
992
993 assert!((result_jac.component(0) - result.component(0)).abs() < 1e-10);
995 assert!((result_jac.component(1) - result.component(1)).abs() < 1e-10);
996 assert!((result_jac.component(2) - result.component(2)).abs() < 1e-10);
997
998 let identity = DMatrix::identity(3, 3);
1000 assert!((jac_tangent - &identity).norm() < 1e-10);
1001 assert!((jac_self - &identity).norm() < 1e-10);
1002 }
1003
1004 #[test]
1005 fn test_rn_left_minus_operations() {
1006 let v1 = Rn::from_vec(vec![5.0, 7.0, 9.0]);
1007 let v2 = Rn::from_vec(vec![1.0, 2.0, 3.0]);
1008
1009 let result = v1.left_minus(&v2, None, None);
1011 assert!((result.component(0) - 4.0).abs() < 1e-10);
1012 assert!((result.component(1) - 5.0).abs() < 1e-10);
1013 assert!((result.component(2) - 6.0).abs() < 1e-10);
1014
1015 let mut jac_self = DMatrix::zeros(3, 3);
1017 let mut jac_other = DMatrix::zeros(3, 3);
1018 let result_jac = v1.left_minus(&v2, Some(&mut jac_self), Some(&mut jac_other));
1019
1020 assert!((result_jac.component(0) - result.component(0)).abs() < 1e-10);
1022 assert!((result_jac.component(1) - result.component(1)).abs() < 1e-10);
1023 assert!((result_jac.component(2) - result.component(2)).abs() < 1e-10);
1024
1025 let identity = DMatrix::identity(3, 3);
1027 let neg_identity = -&identity;
1028 assert!((jac_self - &identity).norm() < 1e-10);
1029 assert!((jac_other - &neg_identity).norm() < 1e-10);
1030 }
1031
1032 #[test]
1033 fn test_rn_left_right_equivalence() {
1034 let v1 = Rn::from_vec(vec![1.0, 2.0, 3.0]);
1036 let v2 = Rn::from_vec(vec![4.0, 5.0, 6.0]);
1037 let delta = RnTangent::from_vec(vec![0.1, 0.2, 0.3]);
1038
1039 let right_plus = v1.right_plus(&delta, None, None);
1041 let left_plus = v1.left_plus(&delta, None, None);
1042 assert!(right_plus.is_approx(&left_plus, 1e-10));
1043
1044 let right_minus = v1.right_minus(&v2, None, None);
1046 let left_minus = v1.left_minus(&v2, None, None);
1047 assert!(right_minus.is_approx(&left_minus, 1e-10));
1048 }
1049
1050 #[test]
1051 fn test_rn_plus_minus_different_dimensions() {
1052 let v2d = Rn::from_vec(vec![1.0, 2.0]);
1054 let delta2d = RnTangent::from_vec(vec![0.5, 1.0]);
1055 let result2d = v2d.right_plus(&delta2d, None, None);
1056 assert_eq!(result2d.dim(), 2);
1057 assert!((result2d.component(0) - 1.5).abs() < 1e-10);
1058 assert!((result2d.component(1) - 3.0).abs() < 1e-10);
1059
1060 let v5d = Rn::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
1062 let delta5d = RnTangent::from_vec(vec![0.1, 0.2, 0.3, 0.4, 0.5]);
1063 let result5d = v5d.right_plus(&delta5d, None, None);
1064 assert_eq!(result5d.dim(), 5);
1065 for i in 0..5 {
1066 assert!(
1067 (result5d.component(i) - (i as f64 + 1.0 + (i as f64 + 1.0) * 0.1)).abs() < 1e-10
1068 );
1069 }
1070 }
1071
1072 #[test]
1073 fn test_rn_plus_minus_edge_cases() {
1074 let v = Rn::from_vec(vec![1.0, 2.0, 3.0]);
1075
1076 let zero_tangent = RnTangent::zeros(3);
1078 let result_zero = v.right_plus(&zero_tangent, None, None);
1079 assert!(v.is_approx(&result_zero, 1e-10));
1080
1081 let self_minus = v.right_minus(&v, None, None);
1083 assert!(self_minus.is_zero(1e-10));
1084
1085 let delta = RnTangent::from_vec(vec![0.5, 1.0, 1.5]);
1087 let plus_result = v.right_plus(&delta, None, None);
1088 let recovered_delta = plus_result.right_minus(&v, None, None);
1089 assert!(delta.is_approx(&recovered_delta, 1e-10));
1090 }
1091
1092 #[test]
1093 fn test_rn_jacobian_dimensions() {
1094 let v1d = Rn::from_vec(vec![1.0]);
1096 let delta1d = RnTangent::from_vec(vec![0.1]);
1097 let mut jac1d = DMatrix::zeros(1, 1);
1098 v1d.right_plus(&delta1d, Some(&mut jac1d), None);
1099 assert_eq!(jac1d.nrows(), 1);
1100 assert_eq!(jac1d.ncols(), 1);
1101
1102 let v4d = Rn::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
1103 let delta4d = RnTangent::from_vec(vec![0.1, 0.2, 0.3, 0.4]);
1104 let mut jac4d = DMatrix::zeros(4, 4);
1105 v4d.right_plus(&delta4d, Some(&mut jac4d), None);
1106 assert_eq!(jac4d.nrows(), 4);
1107 assert_eq!(jac4d.ncols(), 4);
1108
1109 assert!((jac1d - DMatrix::identity(1, 1)).norm() < 1e-10);
1111 assert!((jac4d - DMatrix::identity(4, 4)).norm() < 1e-10);
1112 }
1113
1114 #[test]
1115 fn test_rn_addition_chain() {
1116 let increment = Rn::new(DVector::from_vec(vec![0.001, -0.002, 0.003]));
1118 let mut accumulated = Rn::new(DVector::zeros(3));
1119
1120 for _ in 0..1000 {
1121 accumulated = accumulated.compose(&increment, None, None);
1122 }
1123
1124 let expected = Rn::new(DVector::from_vec(vec![1.0, -2.0, 3.0]));
1125 assert!((accumulated.to_vector() - expected.to_vector()).norm() < 1e-10);
1126 }
1127
1128 #[test]
1129 #[should_panic(expected = "Rn elements must have the same dimension")]
1130 fn test_rn_dimension_mismatch_compose() {
1131 let rn_2d = Rn::new(DVector::from_vec(vec![1.0, 2.0]));
1132 let rn_3d = Rn::new(DVector::from_vec(vec![3.0, 4.0, 5.0]));
1133
1134 let _ = rn_2d.compose(&rn_3d, None, None); }
1136
1137 #[test]
1138 fn test_rn_zero_dimension() {
1139 let rn_0d = Rn::new(DVector::zeros(0));
1140 assert_eq!(rn_0d.dim(), 0);
1141
1142 let identity = Rn::new(DVector::zeros(0));
1143 let composed = rn_0d.compose(&identity, None, None);
1144 assert_eq!(composed.dim(), 0);
1145 }
1146
1147 #[test]
1148 fn test_rn_identity_with_dim() {
1149 for dim in [1, 2, 3, 5, 10] {
1150 let id = Rn::identity_with_dim(dim);
1151 assert_eq!(id.dim(), dim);
1152 assert!(id.norm() < 1e-15);
1153
1154 let v = Rn::random_with_dim(dim);
1156 let result = v.compose(&id, None, None);
1157 assert!(v.is_approx(&result, 1e-10));
1158 }
1159 }
1160
1161 #[test]
1162 fn test_rn_tangent_zero_with_dim() {
1163 for dim in [1, 2, 3, 5, 10] {
1164 let z = RnTangent::zero_with_dim(dim);
1165 assert_eq!(z.dim(), dim);
1166 assert!(z.is_zero(1e-15));
1167 }
1168 }
1169
1170 #[test]
1171 fn test_rn_tangent_is_dynamic() {
1172 assert!(RnTangent::is_dynamic());
1173 }
1174
1175 #[test]
1176 fn test_rn_display_format() {
1177 let rn = Rn::new(DVector::from_vec(vec![1.0, 2.0, 3.0]));
1178 let s = format!("{rn}");
1179 assert!(
1180 s.contains("1") && s.contains("2") && s.contains("3"),
1181 "got: {s}"
1182 );
1183
1184 let t = RnTangent::new(DVector::from_vec(vec![4.0, 5.0]));
1185 let st = format!("{t}");
1186 assert!(st.contains("4") && st.contains("5"), "got: {st}");
1187 }
1188
1189 #[test]
1190 fn test_rn_from_dvector_and_back() {
1191 let v = DVector::from_vec(vec![1.0, 2.0, 3.0]);
1192 let rn: Rn = Rn::from(v.clone());
1193 let v2: DVector<f64> = DVector::from(rn);
1194 assert_eq!(v, v2);
1195 }
1196
1197 #[test]
1198 fn test_rn_tangent_from_vec_and_back() {
1199 let v = vec![4.0f64, 5.0];
1200 let t = RnTangent::from_vec(v.clone());
1201 let v2 = t.to_vector();
1202 assert!((v2[0] - v[0]).abs() < 1e-10);
1203 assert!((v2[1] - v[1]).abs() < 1e-10);
1204 }
1205
1206 #[test]
1207 fn test_rn_from_slice_from_vec() {
1208 let rn = Rn::from_slice(&[1.0, 2.0, 3.0]);
1209 assert_eq!(rn.dim(), 3);
1210 assert!((rn.component(0) - 1.0).abs() < 1e-10);
1211
1212 let rn2 = Rn::from_vec(vec![4.0, 5.0]);
1213 assert_eq!(rn2.dim(), 2);
1214
1215 let t = RnTangent::from_slice(&[1.0, 2.0]);
1216 assert_eq!(t.dim(), 2);
1217 let t2 = RnTangent::from_vec(vec![3.0, 4.0]);
1218 assert_eq!(t2.dim(), 2);
1219 }
1220
1221 #[test]
1222 fn test_rn_accessors() {
1223 let mut rn = Rn::from_slice(&[1.0, 2.0, 3.0]);
1224 assert_eq!(rn.data().len(), 3);
1225 assert_eq!(rn.dim(), 3);
1226 assert!((rn.component(1) - 2.0).abs() < 1e-10);
1227 rn.set_component(1, 99.0);
1228 assert!((rn.component(1) - 99.0).abs() < 1e-10);
1229 let rn2 = Rn::from_slice(&[3.0, 4.0]);
1230 assert!((rn2.norm() - 5.0).abs() < 1e-10);
1231 assert!((rn2.norm_squared() - 25.0).abs() < 1e-10);
1232 let v = rn2.to_vector();
1233 assert_eq!(v.len(), 2);
1234 }
1235
1236 #[test]
1237 fn test_rn_tangent_accessors() {
1238 let mut t = RnTangent::from_slice(&[3.0, 4.0]);
1239 assert_eq!(t.data().len(), 2);
1240 assert_eq!(t.dim(), 2);
1241 assert!((t.component(0) - 3.0).abs() < 1e-10);
1242 t.set_component(0, 10.0);
1243 assert!((t.component(0) - 10.0).abs() < 1e-10);
1244
1245 let t2 = RnTangent::from_slice(&[3.0, 4.0]);
1246 assert!((t2.norm() - 5.0).abs() < 1e-10);
1247 assert!((t2.norm_squared() - 25.0).abs() < 1e-10);
1248
1249 let v = t2.to_vector();
1250 assert_eq!(v.len(), 2);
1251
1252 let t3 = RnTangent::from_vector(DVector::from_vec(vec![1.0, 2.0]));
1253 assert_eq!(t3.dim(), 2);
1254 }
1255
1256 #[test]
1257 fn test_rn_vee_adjoint() {
1258 let rn = Rn::from_slice(&[1.0, 2.0, 3.0]);
1259 let t = rn.vee();
1260 assert_eq!(t.dim(), 3);
1261
1262 let adj = rn.adjoint();
1263 assert_eq!(adj.nrows(), 3);
1264 assert_eq!(adj.ncols(), 3);
1265 }
1266
1267 #[test]
1268 fn test_rn_tangent_hat_small_adj_lie_bracket() {
1269 let t = RnTangent::from_slice(&[1.0, 2.0, 3.0]);
1270 let hat = t.hat();
1271 assert!(hat.nrows() > 0);
1272
1273 let sadj = t.small_adj();
1274 assert!(sadj.nrows() > 0);
1275
1276 let t2 = RnTangent::from_slice(&[0.5, 1.0, 1.5]);
1277 let bracket = t.lie_bracket(&t2);
1278 assert_eq!(bracket.dim(), 3);
1279 for i in 0..3 {
1280 assert!(bracket.component(i).abs() < 1e-10);
1281 }
1282 }
1283
1284 #[test]
1285 fn test_rn_tangent_generator_normalize_normalized() {
1286 let mut t2 = RnTangent::from_slice(&[3.0, 4.0]);
1288 t2.normalize();
1289 assert!((t2.norm() - 1.0).abs() < 1e-9);
1290
1291 let t3 = RnTangent::from_slice(&[0.0, 5.0]);
1293 let t3n = t3.normalized();
1294 assert!((t3n.norm() - 1.0).abs() < 1e-9);
1295
1296 let t_gen = RnTangent::from_slice(&[0.0, 0.0]);
1298 let gen0 = t_gen.generator(0);
1299 assert!((gen0[(0, 0)] - 1.0).abs() < 1e-10);
1301
1302 let t4 = RnTangent::from_slice(&[1.0, 2.0]);
1303 assert!(t4.is_approx(&t4, 1e-9));
1304 }
1305
1306 #[test]
1307 fn test_rn_tangent_is_zero() {
1308 let zero = RnTangent::from_slice(&[0.0, 0.0, 0.0]);
1309 assert!(zero.is_zero(1e-9));
1310
1311 let nonzero = RnTangent::from_slice(&[0.1, 0.0, 0.0]);
1312 assert!(!nonzero.is_zero(1e-9));
1313 }
1314
1315 #[test]
1316 fn test_rn_factory_methods() {
1317 let id = Rn::identity_with_dim(3);
1318 assert_eq!(id.dim(), 3);
1319
1320 let z = Rn::zeros(4);
1321 assert_eq!(z.dim(), 4);
1322 for i in 0..4 {
1323 assert!(z.component(i).abs() < 1e-10);
1324 }
1325
1326 let o = Rn::ones(3);
1327 for i in 0..3 {
1328 assert!((o.component(i) - 1.0).abs() < 1e-10);
1329 }
1330
1331 let r = Rn::random_with_dim(5);
1332 assert_eq!(r.dim(), 5);
1333
1334 let ji = Rn::jacobian_identity_with_dim(3);
1335 assert_eq!(ji.nrows(), 3);
1336 assert_eq!(ji.ncols(), 3);
1337 }
1338
1339 #[test]
1340 fn test_rn_tangent_factory_methods() {
1341 let zwd = RnTangent::zero_with_dim(4);
1342 assert_eq!(zwd.dim(), 4);
1343
1344 let z = RnTangent::zeros(3);
1345 for i in 0..3 {
1346 assert!(z.component(i).abs() < 1e-10);
1347 }
1348
1349 let o = RnTangent::ones(3);
1350 for i in 0..3 {
1351 assert!((o.component(i) - 1.0).abs() < 1e-10);
1352 }
1353
1354 let r = RnTangent::random_with_dim(5);
1355 assert_eq!(r.dim(), 5);
1356 }
1357
1358 #[test]
1359 fn test_rn_slerp() {
1360 let a = Rn::from_slice(&[0.0, 0.0]);
1361 let b = Rn::from_slice(&[4.0, 0.0]);
1362 let mid = a.slerp(&b, 0.5);
1363 assert!((mid.component(0) - 2.0).abs() < 1e-9);
1364 }
1365
1366 #[test]
1367 fn test_rn_normalize_is_valid() {
1368 let mut rn = Rn::from_slice(&[1.0, 2.0]);
1369 rn.normalize();
1370 assert!(rn.is_valid(1e-9));
1371 assert!((rn.norm() - 1.0).abs() < 1e-9);
1373 }
1374
1375 #[test]
1376 fn rn_param_slice_round_trip() {
1377 let g = Rn::random_with_dim(4);
1378 let recovered = Rn::from_param_slice(g.as_param_slice());
1379 assert!(g.is_approx(&recovered, 1e-14));
1380 }
1381
1382 #[test]
1383 fn rn_tangent_slice_round_trip() {
1384 let t = RnTangent::from_slice(&[1.0, 2.0, 3.0]);
1385 let recovered = RnTangent::from_slice(t.as_slice());
1386 assert!(t.is_approx(&recovered, 1e-14));
1387 }
1388
1389 #[test]
1390 fn test_bijective_rn_tangent() {
1391 let tangent_expected = RnTangent::from_slice(&[1.0, 2.0, 3.0]);
1392 let slice_expected = tangent_expected.as_slice();
1393 let tangent_actual = RnTangent::from_slice(slice_expected);
1394 assert!(tangent_expected.is_approx(&tangent_actual, 1e-14));
1395 }
1396}