1use crate::{Interpolatable, LieGroup, Tangent};
14use nalgebra::{DMatrix, DVector, Matrix3, Vector3};
15use std::{
16 fmt,
17 fmt::{Display, Formatter},
18};
19
20#[derive(Clone, PartialEq)]
24pub struct Rn {
25 data: DVector<f64>,
27}
28
29impl Display for Rn {
30 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
31 write!(f, "Rn(dim: {}, data: [", self.data.len())?;
32 for (i, val) in self.data.iter().enumerate() {
33 if i > 0 {
34 write!(f, ", ")?;
35 }
36 write!(f, "{:.4}", val)?;
37 }
38 write!(f, "])")
39 }
40}
41
42impl From<DVector<f64>> for Rn {
44 fn from(data: DVector<f64>) -> Self {
45 Rn::new(data)
46 }
47}
48
49impl From<Rn> for DVector<f64> {
50 fn from(rn: Rn) -> Self {
51 rn.data
52 }
53}
54
55#[derive(Clone, PartialEq)]
60pub struct RnTangent {
61 data: DVector<f64>,
63}
64impl From<DVector<f64>> for RnTangent {
65 fn from(data: DVector<f64>) -> Self {
66 RnTangent::new(data)
67 }
68}
69
70impl From<RnTangent> for DVector<f64> {
71 fn from(rn: RnTangent) -> Self {
72 rn.data
73 }
74}
75
76impl Display for RnTangent {
77 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
78 write!(f, "rn(dim: {}, data: [", self.data.len())?;
79 for (i, val) in self.data.iter().enumerate() {
80 if i > 0 {
81 write!(f, ", ")?;
82 }
83 write!(f, "{:.4}", val)?;
84 }
85 write!(f, "])")
86 }
87}
88
89impl Rn {
90 pub const DIM: usize = 0;
93
94 pub const DOF: usize = 0;
97
98 pub const REP_SIZE: usize = 0;
101
102 pub fn identity() -> Self {
107 Rn::new(DVector::zeros(3))
108 }
109
110 pub fn jacobian_identity() -> DMatrix<f64> {
115 DMatrix::identity(3, 3)
116 }
117
118 #[inline]
123 pub fn new(data: DVector<f64>) -> Self {
124 Rn { data }
125 }
126
127 pub fn from_slice(slice: &[f64]) -> Self {
132 Rn::new(DVector::from_row_slice(slice))
133 }
134
135 pub fn from_vec(components: Vec<f64>) -> Self {
137 Rn::new(DVector::from_vec(components))
138 }
139
140 #[inline]
142 pub fn data(&self) -> &DVector<f64> {
143 &self.data
144 }
145
146 #[inline]
148 pub fn dim(&self) -> usize {
149 self.data.len()
150 }
151
152 #[inline]
154 pub fn component(&self, index: usize) -> f64 {
155 self.data[index]
156 }
157
158 pub fn set_component(&mut self, index: usize, value: f64) {
160 self.data[index] = value;
161 }
162
163 #[inline]
165 pub fn norm(&self) -> f64 {
166 self.data.norm()
167 }
168
169 #[inline]
171 pub fn norm_squared(&self) -> f64 {
172 self.data.norm_squared()
173 }
174
175 #[inline]
177 pub fn to_vector(&self) -> DVector<f64> {
178 self.data.clone()
179 }
180}
181
182impl LieGroup for Rn {
183 const NAME: &'static str = "Rn";
184
185 type TangentVector = RnTangent;
186 type JacobianMatrix = DMatrix<f64>;
187 type LieAlgebra = DMatrix<f64>;
188
189 fn inverse(&self, jacobian: Option<&mut Self::JacobianMatrix>) -> Self {
198 let dim = self.data.len();
199 if let Some(jac) = jacobian {
200 *jac = -DMatrix::identity(dim, dim);
201 }
202 Rn::new(-&self.data)
203 }
204
205 fn compose(
216 &self,
217 other: &Self,
218 jacobian_self: Option<&mut Self::JacobianMatrix>,
219 jacobian_other: Option<&mut Self::JacobianMatrix>,
220 ) -> Self {
221 assert_eq!(
222 self.data.len(),
223 other.data.len(),
224 "Rn elements must have the same dimension for composition"
225 );
226
227 let dim = self.data.len();
228 if let Some(jac_self) = jacobian_self {
229 *jac_self = DMatrix::identity(dim, dim);
230 }
231 if let Some(jac_other) = jacobian_other {
232 *jac_other = DMatrix::identity(dim, dim);
233 }
234
235 Rn::new(&self.data + &other.data)
236 }
237
238 fn log(&self, jacobian: Option<&mut Self::JacobianMatrix>) -> Self::TangentVector {
247 let dim = self.data.len();
248 if let Some(jac) = jacobian {
249 *jac = DMatrix::identity(dim, dim);
250 }
251 RnTangent::new(self.data.clone())
252 }
253
254 fn vee(&self) -> Self::TangentVector {
258 self.log(None)
259 }
260
261 fn act(
275 &self,
276 vector: &Vector3<f64>,
277 jacobian_self: Option<&mut Self::JacobianMatrix>,
278 jacobian_vector: Option<&mut Matrix3<f64>>,
279 ) -> Vector3<f64> {
280 if let Some(jac_self) = jacobian_self {
281 *jac_self = DMatrix::identity(3, 3);
282 }
283 if let Some(jac_vector) = jacobian_vector {
284 *jac_vector = Matrix3::identity();
285 }
286
287 Vector3::new(
288 self.data[0] + vector.x,
289 self.data[1] + vector.y,
290 self.data[2] + vector.z,
291 )
292 }
293
294 fn adjoint(&self) -> Self::JacobianMatrix {
299 let dim = self.data.len();
300 DMatrix::identity(dim, dim)
301 }
302
303 fn random() -> Self {
305 let data = DVector::from_fn(3, |_, _| rand::random::<f64>() * 10.0 - 5.0);
307 Rn::new(data)
308 }
309
310 fn jacobian_identity() -> Self::JacobianMatrix {
311 DMatrix::identity(3, 3)
313 }
314
315 fn zero_jacobian() -> Self::JacobianMatrix {
316 DMatrix::zeros(3, 3)
318 }
319
320 fn normalize(&mut self) {
321 let norm = self.data.norm();
322 if norm > 1e-12 {
323 self.data /= norm;
324 }
325 }
326
327 fn is_valid(&self, _tolerance: f64) -> bool {
328 self.data.iter().all(|x| x.is_finite())
329 }
330
331 fn as_param_slice(&self) -> &[f64] {
332 self.data.as_slice()
333 }
334
335 fn as_param_slice_mut(&mut self) -> &mut [f64] {
336 self.data.as_mut_slice()
337 }
338
339 fn from_param_slice(s: &[f64]) -> Self {
340 Rn::from_slice(s)
341 }
342
343 fn is_approx(&self, other: &Self, tolerance: f64) -> bool {
349 if self.data.len() != other.data.len() {
350 return false;
351 }
352 let difference = self.right_minus(other, None, None);
353 difference.is_zero(tolerance)
354 }
355
356 fn right_plus(
373 &self,
374 tangent: &Self::TangentVector,
375 jacobian_self: Option<&mut Self::JacobianMatrix>,
376 jacobian_tangent: Option<&mut Self::JacobianMatrix>,
377 ) -> Self {
378 assert_eq!(
379 self.data.len(),
380 tangent.data.len(),
381 "Rn element and tangent must have the same dimension"
382 );
383
384 let dim = self.data.len();
385
386 if let Some(jac_self) = jacobian_self {
387 *jac_self = DMatrix::identity(dim, dim);
388 }
389
390 if let Some(jac_tangent) = jacobian_tangent {
391 *jac_tangent = DMatrix::identity(dim, dim);
392 }
393
394 Rn::new(&self.data + &tangent.data)
395 }
396
397 fn right_minus(
410 &self,
411 other: &Self,
412 jacobian_self: Option<&mut Self::JacobianMatrix>,
413 jacobian_other: Option<&mut Self::JacobianMatrix>,
414 ) -> Self::TangentVector {
415 assert_eq!(
416 self.data.len(),
417 other.data.len(),
418 "Rn elements must have the same dimension"
419 );
420
421 let dim = self.data.len();
422
423 if let Some(jac_self) = jacobian_self {
424 *jac_self = DMatrix::identity(dim, dim);
425 }
426
427 if let Some(jac_other) = jacobian_other {
428 *jac_other = -DMatrix::identity(dim, dim);
429 }
430
431 RnTangent::new(&self.data - &other.data)
432 }
433
434 fn left_plus(
446 &self,
447 tangent: &Self::TangentVector,
448 jacobian_tangent: Option<&mut Self::JacobianMatrix>,
449 jacobian_self: Option<&mut Self::JacobianMatrix>,
450 ) -> Self {
451 assert_eq!(
452 self.data.len(),
453 tangent.data.len(),
454 "Rn element and tangent must have the same dimension"
455 );
456
457 let dim = self.data.len();
458
459 if let Some(jac_tangent) = jacobian_tangent {
460 *jac_tangent = DMatrix::identity(dim, dim);
461 }
462
463 if let Some(jac_self) = jacobian_self {
464 *jac_self = DMatrix::identity(dim, dim);
465 }
466
467 Rn::new(&tangent.data + &self.data)
469 }
470
471 fn left_minus(
483 &self,
484 other: &Self,
485 jacobian_self: Option<&mut Self::JacobianMatrix>,
486 jacobian_other: Option<&mut Self::JacobianMatrix>,
487 ) -> Self::TangentVector {
488 self.right_minus(other, jacobian_self, jacobian_other)
490 }
491
492 fn tangent_dim(&self) -> usize {
501 self.data.len()
502 }
503}
504
505impl RnTangent {
506 #[inline]
511 pub fn new(data: DVector<f64>) -> Self {
512 RnTangent { data }
513 }
514
515 pub fn from_slice(slice: &[f64]) -> Self {
520 RnTangent::new(DVector::from_row_slice(slice))
521 }
522
523 pub fn from_vec(components: Vec<f64>) -> Self {
525 RnTangent::new(DVector::from_vec(components))
526 }
527
528 #[inline]
530 pub fn data(&self) -> &DVector<f64> {
531 &self.data
532 }
533
534 #[inline]
536 pub fn dim(&self) -> usize {
537 self.data.len()
538 }
539
540 #[inline]
542 pub fn component(&self, index: usize) -> f64 {
543 self.data[index]
544 }
545
546 pub fn set_component(&mut self, index: usize, value: f64) {
548 self.data[index] = value;
549 }
550
551 #[inline]
553 pub fn norm(&self) -> f64 {
554 self.data.norm()
555 }
556
557 #[inline]
559 pub fn norm_squared(&self) -> f64 {
560 self.data.norm_squared()
561 }
562
563 #[inline]
565 pub fn to_vector(&self) -> DVector<f64> {
566 self.data.clone()
567 }
568
569 pub fn from_vector(data: DVector<f64>) -> Self {
571 RnTangent::new(data)
572 }
573}
574
575impl Tangent<Rn> for RnTangent {
576 const DIM: usize = 0;
579
580 fn exp(&self, jacobian: Option<&mut <Rn as LieGroup>::JacobianMatrix>) -> Rn {
589 let dim = self.data.len();
590 if let Some(jac) = jacobian {
591 *jac = DMatrix::identity(dim, dim);
592 }
593 Rn::new(self.data.clone())
594 }
595
596 fn right_jacobian(&self) -> <Rn as LieGroup>::JacobianMatrix {
597 let dim = self.data.len();
598 DMatrix::identity(dim, dim)
599 }
600
601 fn left_jacobian(&self) -> <Rn as LieGroup>::JacobianMatrix {
602 let dim = self.data.len();
603 DMatrix::identity(dim, dim)
604 }
605
606 fn right_jacobian_inv(&self) -> <Rn as LieGroup>::JacobianMatrix {
607 let dim = self.data.len();
608 DMatrix::identity(dim, dim)
609 }
610
611 fn left_jacobian_inv(&self) -> <Rn as LieGroup>::JacobianMatrix {
612 let dim = self.data.len();
613 DMatrix::identity(dim, dim)
614 }
615
616 fn hat(&self) -> <Rn as LieGroup>::LieAlgebra {
621 DMatrix::from_diagonal(&self.data)
622 }
623
624 fn small_adj(&self) -> <Rn as LieGroup>::JacobianMatrix {
626 let dim = self.data.len();
627 DMatrix::zeros(dim, dim)
628 }
629
630 fn lie_bracket(&self, _other: &Self) -> <Rn as LieGroup>::TangentVector {
634 RnTangent::new(DVector::zeros(self.data.len()))
635 }
636
637 fn is_approx(&self, other: &Self, tolerance: f64) -> bool {
643 if self.data.len() != other.data.len() {
644 return false;
645 }
646 (&self.data - &other.data).norm() < tolerance
647 }
648
649 fn generator(&self, i: usize) -> <Rn as LieGroup>::LieAlgebra {
653 let dim = self.data.len();
654 let mut generator_matrix = DMatrix::zeros(dim, dim);
655 generator_matrix[(i, i)] = 1.0;
656 generator_matrix
657 }
658
659 fn zero() -> <Rn as LieGroup>::TangentVector {
661 RnTangent::new(DVector::zeros(3))
663 }
664
665 fn random() -> <Rn as LieGroup>::TangentVector {
667 let data = DVector::from_fn(3, |_, _| rand::random::<f64>() * 10.0 - 5.0);
669 RnTangent::new(data)
670 }
671
672 fn is_zero(&self, tolerance: f64) -> bool {
674 self.data.norm() < tolerance
675 }
676
677 fn normalize(&mut self) {
679 let norm = self.data.norm();
680 if norm > 1e-12 {
681 self.data /= norm;
682 }
683 }
684
685 fn normalized(&self) -> <Rn as LieGroup>::TangentVector {
687 let mut result = self.clone();
688 result.normalize();
689 result
690 }
691
692 fn as_slice(&self) -> &[f64] {
693 self.data.as_slice()
694 }
695
696 fn from_slice(s: &[f64]) -> Self {
697 RnTangent::from_slice(s)
698 }
699}
700
701impl Interpolatable for Rn {
703 fn interp(&self, other: &Self, t: f64) -> Self {
711 assert_eq!(
712 self.data.len(),
713 other.data.len(),
714 "Rn elements must have the same dimension for interpolation"
715 );
716
717 let interpolated = &self.data * (1.0 - t) + &other.data * t;
718 Rn::new(interpolated)
719 }
720
721 fn slerp(&self, other: &Self, t: f64) -> Self {
723 self.interp(other, t)
724 }
725}
726
727impl Rn {
729 pub fn identity_with_dim(dim: usize) -> Self {
735 Rn::new(DVector::zeros(dim))
736 }
737
738 pub fn zeros(dim: usize) -> Self {
740 Rn::new(DVector::zeros(dim))
741 }
742
743 pub fn ones(dim: usize) -> Self {
745 Rn::new(DVector::from_element(dim, 1.0))
746 }
747
748 pub fn random_with_dim(dim: usize) -> Self {
750 let data = DVector::from_fn(dim, |_, _| rand::random::<f64>() * 10.0 - 5.0);
751 Rn::new(data)
752 }
753
754 pub fn jacobian_identity_with_dim(dim: usize) -> DMatrix<f64> {
756 DMatrix::identity(dim, dim)
757 }
758}
759
760impl RnTangent {
761 pub fn zero_with_dim(dim: usize) -> Self {
763 RnTangent::new(DVector::zeros(dim))
764 }
765
766 pub fn zeros(dim: usize) -> Self {
768 RnTangent::new(DVector::zeros(dim))
769 }
770
771 pub fn ones(dim: usize) -> Self {
773 RnTangent::new(DVector::from_element(dim, 1.0))
774 }
775
776 pub fn random_with_dim(dim: usize) -> Self {
778 let data = DVector::from_fn(dim, |_, _| rand::random::<f64>() * 2.0 - 1.0);
779 RnTangent::new(data)
780 }
781}
782
783#[cfg(test)]
784mod tests {
785 use super::*;
786 use crate::{Interpolatable, LieGroup, Tangent};
787
788 #[test]
789 fn test_rn_basic_operations() {
790 let v1 = Rn::from_vec(vec![1.0, 2.0, 3.0]);
792 let v2 = Rn::from_vec(vec![4.0, 5.0, 6.0]);
793
794 let sum = v1.compose(&v2, None, None);
796 assert_eq!(sum.component(0), 5.0);
797 assert_eq!(sum.component(1), 7.0);
798 assert_eq!(sum.component(2), 9.0);
799
800 let identity = Rn::zeros(3);
802 let result = v1.compose(&identity, None, None);
803 assert_eq!(result.component(0), v1.component(0));
804 assert_eq!(result.component(1), v1.component(1));
805 assert_eq!(result.component(2), v1.component(2));
806
807 let v1_inv = v1.inverse(None);
809 assert_eq!(v1_inv.component(0), -1.0);
810 assert_eq!(v1_inv.component(1), -2.0);
811 assert_eq!(v1_inv.component(2), -3.0);
812
813 let tangent = v1.log(None);
815 let recovered = tangent.exp(None);
816 assert!((recovered.component(0) - v1.component(0)).abs() < 1e-10);
817 assert!((recovered.component(1) - v1.component(1)).abs() < 1e-10);
818 assert!((recovered.component(2) - v1.component(2)).abs() < 1e-10);
819 }
820
821 #[test]
822 fn test_rn_tangent_operations() {
823 let t1 = RnTangent::from_vec(vec![1.0, 2.0, 3.0]);
824 let t2 = RnTangent::from_vec(vec![4.0, 5.0, 6.0]);
825
826 let bracket = t1.lie_bracket(&t2);
828 assert!(bracket.is_zero(1e-10));
829
830 let zero = RnTangent::zeros(3);
832 assert!(zero.is_zero(1e-10));
833
834 let mut t = RnTangent::from_vec(vec![3.0, 4.0, 0.0]);
836 t.normalize();
837 assert!((t.norm() - 1.0).abs() < 1e-10);
838 }
839
840 #[test]
841 fn test_rn_interpolation() {
842 let v1 = Rn::from_vec(vec![0.0, 0.0, 0.0]);
843 let v2 = Rn::from_vec(vec![10.0, 20.0, 30.0]);
844
845 let mid = v1.interp(&v2, 0.5);
847 assert_eq!(mid.component(0), 5.0);
848 assert_eq!(mid.component(1), 10.0);
849 assert_eq!(mid.component(2), 15.0);
850
851 let start = v1.interp(&v2, 0.0);
853 let end = v1.interp(&v2, 1.0);
854 assert!(v1.is_approx(&start, 1e-10));
855 assert!(v2.is_approx(&end, 1e-10));
856 }
857
858 #[test]
859 fn test_rn_different_dimensions() {
860 let v2d = Rn::from_vec(vec![1.0, 2.0]);
862 assert_eq!(v2d.dim(), 2);
863
864 let v1d = Rn::from_vec(vec![5.0]);
866 assert_eq!(v1d.dim(), 1);
867
868 let v5d = Rn::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
870 assert_eq!(v5d.dim(), 5);
871 assert_eq!(v5d.component(4), 5.0);
872 }
873
874 #[test]
875 fn test_rn_action() {
876 let translation = Rn::from_vec(vec![1.0, 2.0, 3.0]);
878 let point = Vector3::new(4.0, 5.0, 6.0);
879 let transformed = translation.act(&point, None, None);
880
881 assert_eq!(transformed.x, 5.0);
882 assert_eq!(transformed.y, 7.0);
883 assert_eq!(transformed.z, 9.0);
884 }
885
886 #[test]
887 fn test_rn_right_plus_operations() {
888 let v = Rn::from_vec(vec![1.0, 2.0, 3.0]);
889 let delta = RnTangent::from_vec(vec![0.1, 0.2, 0.3]);
890
891 let result = v.right_plus(&delta, None, None);
893 assert!((result.component(0) - 1.1).abs() < 1e-10);
894 assert!((result.component(1) - 2.2).abs() < 1e-10);
895 assert!((result.component(2) - 3.3).abs() < 1e-10);
896
897 let mut jac_self = DMatrix::zeros(3, 3);
899 let mut jac_tangent = DMatrix::zeros(3, 3);
900 let result_jac = v.right_plus(&delta, Some(&mut jac_self), Some(&mut jac_tangent));
901
902 assert!((result_jac.component(0) - result.component(0)).abs() < 1e-10);
904 assert!((result_jac.component(1) - result.component(1)).abs() < 1e-10);
905 assert!((result_jac.component(2) - result.component(2)).abs() < 1e-10);
906
907 let identity = DMatrix::identity(3, 3);
909 assert!((jac_self - &identity).norm() < 1e-10);
910 assert!((jac_tangent - &identity).norm() < 1e-10);
911 }
912
913 #[test]
914 fn test_rn_right_minus_operations() {
915 let v1 = Rn::from_vec(vec![5.0, 7.0, 9.0]);
916 let v2 = Rn::from_vec(vec![1.0, 2.0, 3.0]);
917
918 let result = v1.right_minus(&v2, None, None);
920 assert!((result.component(0) - 4.0).abs() < 1e-10);
921 assert!((result.component(1) - 5.0).abs() < 1e-10);
922 assert!((result.component(2) - 6.0).abs() < 1e-10);
923
924 let mut jac_self = DMatrix::zeros(3, 3);
926 let mut jac_other = DMatrix::zeros(3, 3);
927 let result_jac = v1.right_minus(&v2, Some(&mut jac_self), Some(&mut jac_other));
928
929 assert!((result_jac.component(0) - result.component(0)).abs() < 1e-10);
931 assert!((result_jac.component(1) - result.component(1)).abs() < 1e-10);
932 assert!((result_jac.component(2) - result.component(2)).abs() < 1e-10);
933
934 let identity = DMatrix::identity(3, 3);
936 let neg_identity = -&identity;
937 assert!((jac_self - &identity).norm() < 1e-10);
938 assert!((jac_other - &neg_identity).norm() < 1e-10);
939 }
940
941 #[test]
942 fn test_rn_left_plus_operations() {
943 let v = Rn::from_vec(vec![1.0, 2.0, 3.0]);
944 let delta = RnTangent::from_vec(vec![0.1, 0.2, 0.3]);
945
946 let result = v.left_plus(&delta, None, None);
948 assert!((result.component(0) - 1.1).abs() < 1e-10);
949 assert!((result.component(1) - 2.2).abs() < 1e-10);
950 assert!((result.component(2) - 3.3).abs() < 1e-10);
951
952 let mut jac_tangent = DMatrix::zeros(3, 3);
954 let mut jac_self = DMatrix::zeros(3, 3);
955 let result_jac = v.left_plus(&delta, Some(&mut jac_tangent), Some(&mut jac_self));
956
957 assert!((result_jac.component(0) - result.component(0)).abs() < 1e-10);
959 assert!((result_jac.component(1) - result.component(1)).abs() < 1e-10);
960 assert!((result_jac.component(2) - result.component(2)).abs() < 1e-10);
961
962 let identity = DMatrix::identity(3, 3);
964 assert!((jac_tangent - &identity).norm() < 1e-10);
965 assert!((jac_self - &identity).norm() < 1e-10);
966 }
967
968 #[test]
969 fn test_rn_left_minus_operations() {
970 let v1 = Rn::from_vec(vec![5.0, 7.0, 9.0]);
971 let v2 = Rn::from_vec(vec![1.0, 2.0, 3.0]);
972
973 let result = v1.left_minus(&v2, None, None);
975 assert!((result.component(0) - 4.0).abs() < 1e-10);
976 assert!((result.component(1) - 5.0).abs() < 1e-10);
977 assert!((result.component(2) - 6.0).abs() < 1e-10);
978
979 let mut jac_self = DMatrix::zeros(3, 3);
981 let mut jac_other = DMatrix::zeros(3, 3);
982 let result_jac = v1.left_minus(&v2, Some(&mut jac_self), Some(&mut jac_other));
983
984 assert!((result_jac.component(0) - result.component(0)).abs() < 1e-10);
986 assert!((result_jac.component(1) - result.component(1)).abs() < 1e-10);
987 assert!((result_jac.component(2) - result.component(2)).abs() < 1e-10);
988
989 let identity = DMatrix::identity(3, 3);
991 let neg_identity = -&identity;
992 assert!((jac_self - &identity).norm() < 1e-10);
993 assert!((jac_other - &neg_identity).norm() < 1e-10);
994 }
995
996 #[test]
997 fn test_rn_left_right_equivalence() {
998 let v1 = Rn::from_vec(vec![1.0, 2.0, 3.0]);
1000 let v2 = Rn::from_vec(vec![4.0, 5.0, 6.0]);
1001 let delta = RnTangent::from_vec(vec![0.1, 0.2, 0.3]);
1002
1003 let right_plus = v1.right_plus(&delta, None, None);
1005 let left_plus = v1.left_plus(&delta, None, None);
1006 assert!(right_plus.is_approx(&left_plus, 1e-10));
1007
1008 let right_minus = v1.right_minus(&v2, None, None);
1010 let left_minus = v1.left_minus(&v2, None, None);
1011 assert!(right_minus.is_approx(&left_minus, 1e-10));
1012 }
1013
1014 #[test]
1015 fn test_rn_plus_minus_different_dimensions() {
1016 let v2d = Rn::from_vec(vec![1.0, 2.0]);
1018 let delta2d = RnTangent::from_vec(vec![0.5, 1.0]);
1019 let result2d = v2d.right_plus(&delta2d, None, None);
1020 assert_eq!(result2d.dim(), 2);
1021 assert!((result2d.component(0) - 1.5).abs() < 1e-10);
1022 assert!((result2d.component(1) - 3.0).abs() < 1e-10);
1023
1024 let v5d = Rn::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
1026 let delta5d = RnTangent::from_vec(vec![0.1, 0.2, 0.3, 0.4, 0.5]);
1027 let result5d = v5d.right_plus(&delta5d, None, None);
1028 assert_eq!(result5d.dim(), 5);
1029 for i in 0..5 {
1030 assert!(
1031 (result5d.component(i) - (i as f64 + 1.0 + (i as f64 + 1.0) * 0.1)).abs() < 1e-10
1032 );
1033 }
1034 }
1035
1036 #[test]
1037 fn test_rn_plus_minus_edge_cases() {
1038 let v = Rn::from_vec(vec![1.0, 2.0, 3.0]);
1039
1040 let zero_tangent = RnTangent::zeros(3);
1042 let result_zero = v.right_plus(&zero_tangent, None, None);
1043 assert!(v.is_approx(&result_zero, 1e-10));
1044
1045 let self_minus = v.right_minus(&v, None, None);
1047 assert!(self_minus.is_zero(1e-10));
1048
1049 let delta = RnTangent::from_vec(vec![0.5, 1.0, 1.5]);
1051 let plus_result = v.right_plus(&delta, None, None);
1052 let recovered_delta = plus_result.right_minus(&v, None, None);
1053 assert!(delta.is_approx(&recovered_delta, 1e-10));
1054 }
1055
1056 #[test]
1057 fn test_rn_jacobian_dimensions() {
1058 let v1d = Rn::from_vec(vec![1.0]);
1060 let delta1d = RnTangent::from_vec(vec![0.1]);
1061 let mut jac1d = DMatrix::zeros(1, 1);
1062 v1d.right_plus(&delta1d, Some(&mut jac1d), None);
1063 assert_eq!(jac1d.nrows(), 1);
1064 assert_eq!(jac1d.ncols(), 1);
1065
1066 let v4d = Rn::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
1067 let delta4d = RnTangent::from_vec(vec![0.1, 0.2, 0.3, 0.4]);
1068 let mut jac4d = DMatrix::zeros(4, 4);
1069 v4d.right_plus(&delta4d, Some(&mut jac4d), None);
1070 assert_eq!(jac4d.nrows(), 4);
1071 assert_eq!(jac4d.ncols(), 4);
1072
1073 assert!((jac1d - DMatrix::identity(1, 1)).norm() < 1e-10);
1075 assert!((jac4d - DMatrix::identity(4, 4)).norm() < 1e-10);
1076 }
1077
1078 #[test]
1079 fn test_rn_addition_chain() {
1080 let increment = Rn::new(DVector::from_vec(vec![0.001, -0.002, 0.003]));
1082 let mut accumulated = Rn::new(DVector::zeros(3));
1083
1084 for _ in 0..1000 {
1085 accumulated = accumulated.compose(&increment, None, None);
1086 }
1087
1088 let expected = Rn::new(DVector::from_vec(vec![1.0, -2.0, 3.0]));
1089 assert!((accumulated.to_vector() - expected.to_vector()).norm() < 1e-10);
1090 }
1091
1092 #[test]
1093 #[should_panic(expected = "Rn elements must have the same dimension")]
1094 fn test_rn_dimension_mismatch_compose() {
1095 let rn_2d = Rn::new(DVector::from_vec(vec![1.0, 2.0]));
1096 let rn_3d = Rn::new(DVector::from_vec(vec![3.0, 4.0, 5.0]));
1097
1098 let _ = rn_2d.compose(&rn_3d, None, None); }
1100
1101 #[test]
1102 fn test_rn_zero_dimension() {
1103 let rn_0d = Rn::new(DVector::zeros(0));
1104 assert_eq!(rn_0d.dim(), 0);
1105
1106 let identity = Rn::new(DVector::zeros(0));
1107 let composed = rn_0d.compose(&identity, None, None);
1108 assert_eq!(composed.dim(), 0);
1109 }
1110
1111 #[test]
1112 fn test_rn_identity_with_dim() {
1113 for dim in [1, 2, 3, 5, 10] {
1114 let id = Rn::identity_with_dim(dim);
1115 assert_eq!(id.dim(), dim);
1116 assert!(id.norm() < 1e-15);
1117
1118 let v = Rn::random_with_dim(dim);
1120 let result = v.compose(&id, None, None);
1121 assert!(v.is_approx(&result, 1e-10));
1122 }
1123 }
1124
1125 #[test]
1126 fn test_rn_tangent_zero_with_dim() {
1127 for dim in [1, 2, 3, 5, 10] {
1128 let z = RnTangent::zero_with_dim(dim);
1129 assert_eq!(z.dim(), dim);
1130 assert!(z.is_zero(1e-15));
1131 }
1132 }
1133
1134 #[test]
1135 fn test_rn_tangent_is_dynamic() {
1136 assert!(RnTangent::is_dynamic());
1137 }
1138
1139 #[test]
1140 fn test_rn_display_format() {
1141 let rn = Rn::new(DVector::from_vec(vec![1.0, 2.0, 3.0]));
1142 let s = format!("{rn}");
1143 assert!(
1144 s.contains("1") && s.contains("2") && s.contains("3"),
1145 "got: {s}"
1146 );
1147
1148 let t = RnTangent::new(DVector::from_vec(vec![4.0, 5.0]));
1149 let st = format!("{t}");
1150 assert!(st.contains("4") && st.contains("5"), "got: {st}");
1151 }
1152
1153 #[test]
1154 fn test_rn_from_dvector_and_back() {
1155 let v = DVector::from_vec(vec![1.0, 2.0, 3.0]);
1156 let rn: Rn = Rn::from(v.clone());
1157 let v2: DVector<f64> = DVector::from(rn);
1158 assert_eq!(v, v2);
1159 }
1160
1161 #[test]
1162 fn test_rn_tangent_from_vec_and_back() {
1163 let v = vec![4.0f64, 5.0];
1164 let t = RnTangent::from_vec(v.clone());
1165 let v2 = t.to_vector();
1166 assert!((v2[0] - v[0]).abs() < 1e-10);
1167 assert!((v2[1] - v[1]).abs() < 1e-10);
1168 }
1169
1170 #[test]
1171 fn test_rn_from_slice_from_vec() {
1172 let rn = Rn::from_slice(&[1.0, 2.0, 3.0]);
1173 assert_eq!(rn.dim(), 3);
1174 assert!((rn.component(0) - 1.0).abs() < 1e-10);
1175
1176 let rn2 = Rn::from_vec(vec![4.0, 5.0]);
1177 assert_eq!(rn2.dim(), 2);
1178
1179 let t = RnTangent::from_slice(&[1.0, 2.0]);
1180 assert_eq!(t.dim(), 2);
1181 let t2 = RnTangent::from_vec(vec![3.0, 4.0]);
1182 assert_eq!(t2.dim(), 2);
1183 }
1184
1185 #[test]
1186 fn test_rn_accessors() {
1187 let mut rn = Rn::from_slice(&[1.0, 2.0, 3.0]);
1188 assert_eq!(rn.data().len(), 3);
1189 assert_eq!(rn.dim(), 3);
1190 assert!((rn.component(1) - 2.0).abs() < 1e-10);
1191 rn.set_component(1, 99.0);
1192 assert!((rn.component(1) - 99.0).abs() < 1e-10);
1193 let rn2 = Rn::from_slice(&[3.0, 4.0]);
1194 assert!((rn2.norm() - 5.0).abs() < 1e-10);
1195 assert!((rn2.norm_squared() - 25.0).abs() < 1e-10);
1196 let v = rn2.to_vector();
1197 assert_eq!(v.len(), 2);
1198 }
1199
1200 #[test]
1201 fn test_rn_tangent_accessors() {
1202 let mut t = RnTangent::from_slice(&[3.0, 4.0]);
1203 assert_eq!(t.data().len(), 2);
1204 assert_eq!(t.dim(), 2);
1205 assert!((t.component(0) - 3.0).abs() < 1e-10);
1206 t.set_component(0, 10.0);
1207 assert!((t.component(0) - 10.0).abs() < 1e-10);
1208
1209 let t2 = RnTangent::from_slice(&[3.0, 4.0]);
1210 assert!((t2.norm() - 5.0).abs() < 1e-10);
1211 assert!((t2.norm_squared() - 25.0).abs() < 1e-10);
1212
1213 let v = t2.to_vector();
1214 assert_eq!(v.len(), 2);
1215
1216 let t3 = RnTangent::from_vector(DVector::from_vec(vec![1.0, 2.0]));
1217 assert_eq!(t3.dim(), 2);
1218 }
1219
1220 #[test]
1221 fn test_rn_vee_adjoint() {
1222 let rn = Rn::from_slice(&[1.0, 2.0, 3.0]);
1223 let t = rn.vee();
1224 assert_eq!(t.dim(), 3);
1225
1226 let adj = rn.adjoint();
1227 assert_eq!(adj.nrows(), 3);
1228 assert_eq!(adj.ncols(), 3);
1229 }
1230
1231 #[test]
1232 fn test_rn_tangent_hat_small_adj_lie_bracket() {
1233 let t = RnTangent::from_slice(&[1.0, 2.0, 3.0]);
1234 let hat = t.hat();
1235 assert!(hat.nrows() > 0);
1236
1237 let sadj = t.small_adj();
1238 assert!(sadj.nrows() > 0);
1239
1240 let t2 = RnTangent::from_slice(&[0.5, 1.0, 1.5]);
1241 let bracket = t.lie_bracket(&t2);
1242 assert_eq!(bracket.dim(), 3);
1243 for i in 0..3 {
1244 assert!(bracket.component(i).abs() < 1e-10);
1245 }
1246 }
1247
1248 #[test]
1249 fn test_rn_tangent_generator_normalize_normalized() {
1250 let mut t2 = RnTangent::from_slice(&[3.0, 4.0]);
1252 t2.normalize();
1253 assert!((t2.norm() - 1.0).abs() < 1e-9);
1254
1255 let t3 = RnTangent::from_slice(&[0.0, 5.0]);
1257 let t3n = t3.normalized();
1258 assert!((t3n.norm() - 1.0).abs() < 1e-9);
1259
1260 let t_gen = RnTangent::from_slice(&[0.0, 0.0]);
1262 let gen0 = t_gen.generator(0);
1263 assert!((gen0[(0, 0)] - 1.0).abs() < 1e-10);
1265
1266 let t4 = RnTangent::from_slice(&[1.0, 2.0]);
1267 assert!(t4.is_approx(&t4, 1e-9));
1268 }
1269
1270 #[test]
1271 fn test_rn_tangent_is_zero() {
1272 let zero = RnTangent::from_slice(&[0.0, 0.0, 0.0]);
1273 assert!(zero.is_zero(1e-9));
1274
1275 let nonzero = RnTangent::from_slice(&[0.1, 0.0, 0.0]);
1276 assert!(!nonzero.is_zero(1e-9));
1277 }
1278
1279 #[test]
1280 fn test_rn_factory_methods() {
1281 let id = Rn::identity_with_dim(3);
1282 assert_eq!(id.dim(), 3);
1283
1284 let z = Rn::zeros(4);
1285 assert_eq!(z.dim(), 4);
1286 for i in 0..4 {
1287 assert!(z.component(i).abs() < 1e-10);
1288 }
1289
1290 let o = Rn::ones(3);
1291 for i in 0..3 {
1292 assert!((o.component(i) - 1.0).abs() < 1e-10);
1293 }
1294
1295 let r = Rn::random_with_dim(5);
1296 assert_eq!(r.dim(), 5);
1297
1298 let ji = Rn::jacobian_identity_with_dim(3);
1299 assert_eq!(ji.nrows(), 3);
1300 assert_eq!(ji.ncols(), 3);
1301 }
1302
1303 #[test]
1304 fn test_rn_tangent_factory_methods() {
1305 let zwd = RnTangent::zero_with_dim(4);
1306 assert_eq!(zwd.dim(), 4);
1307
1308 let z = RnTangent::zeros(3);
1309 for i in 0..3 {
1310 assert!(z.component(i).abs() < 1e-10);
1311 }
1312
1313 let o = RnTangent::ones(3);
1314 for i in 0..3 {
1315 assert!((o.component(i) - 1.0).abs() < 1e-10);
1316 }
1317
1318 let r = RnTangent::random_with_dim(5);
1319 assert_eq!(r.dim(), 5);
1320 }
1321
1322 #[test]
1323 fn test_rn_slerp() {
1324 let a = Rn::from_slice(&[0.0, 0.0]);
1325 let b = Rn::from_slice(&[4.0, 0.0]);
1326 let mid = a.slerp(&b, 0.5);
1327 assert!((mid.component(0) - 2.0).abs() < 1e-9);
1328 }
1329
1330 #[test]
1331 fn test_rn_normalize_is_valid() {
1332 let mut rn = Rn::from_slice(&[1.0, 2.0]);
1333 rn.normalize();
1334 assert!(rn.is_valid(1e-9));
1335 assert!((rn.norm() - 1.0).abs() < 1e-9);
1337 }
1338
1339 #[test]
1340 fn rn_param_slice_round_trip() {
1341 let g = Rn::random_with_dim(4);
1342 let recovered = Rn::from_param_slice(g.as_param_slice());
1343 assert!(g.is_approx(&recovered, 1e-14));
1344 }
1345
1346 #[test]
1347 fn rn_tangent_slice_round_trip() {
1348 let t = RnTangent::from_slice(&[1.0, 2.0, 3.0]);
1349 let recovered = RnTangent::from_slice(t.as_slice());
1350 assert!(t.is_approx(&recovered, 1e-14));
1351 }
1352
1353 #[test]
1354 fn test_bijective_rn_tangent() {
1355 let tangent_expected = RnTangent::from_slice(&[1.0, 2.0, 3.0]);
1356 let slice_expected = tangent_expected.as_slice();
1357 let tangent_actual = RnTangent::from_slice(slice_expected);
1358 assert!(tangent_expected.is_approx(&tangent_actual, 1e-14));
1359 }
1360}