gtsam-develop 4.3a0.dev202506061328__cp313-cp313-macosx_11_0_arm64.whl → 4.3a0.dev202508020718__cp313-cp313-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of gtsam-develop might be problematic. Click here for more details.

gtsam/gtsam/imuBias.pyi CHANGED
@@ -52,10 +52,16 @@ class ConstantBias:
52
52
  """
53
53
  get gyroscope bias
54
54
  """
55
+ def localCoordinates(self, b: ConstantBias) -> numpy.ndarray[tuple[typing.Literal[6], typing.Literal[1]], numpy.dtype[numpy.float64]]:
56
+ ...
55
57
  def print(self, s: str = '') -> None:
56
58
  """
57
59
  print with optional string
58
60
  """
61
+ def retract(self, v: numpy.ndarray[tuple[M, typing.Literal[1]], numpy.dtype[numpy.float64]]) -> ConstantBias:
62
+ """
63
+ The retract function.
64
+ """
59
65
  def serialize(self) -> str:
60
66
  ...
61
67
  def vector(self) -> numpy.ndarray[tuple[typing.Literal[6], typing.Literal[1]], numpy.dtype[numpy.float64]]:
Binary file
@@ -12,8 +12,24 @@ Author: Frank Dellaert
12
12
  import unittest
13
13
 
14
14
  import numpy as np
15
- from gtsam import (Rot3, SO3, SO4, FrobeniusBetweenFactorSO4, FrobeniusFactorSO4,
16
- ShonanFactor3, SOn)
15
+ from gtsam import (
16
+ Rot3,
17
+ SO3,
18
+ SO4,
19
+ FrobeniusBetweenFactorSO4,
20
+ FrobeniusFactorSO4,
21
+ ShonanFactor3,
22
+ SOn,
23
+ Similarity2,
24
+ Similarity3,
25
+ FrobeniusFactorSimilarity2,
26
+ FrobeniusBetweenFactorSimilarity2,
27
+ FrobeniusFactorSimilarity3,
28
+ FrobeniusBetweenFactorSimilarity3,
29
+ Gal3,
30
+ FrobeniusFactorGal3,
31
+ FrobeniusBetweenFactorGal3,
32
+ )
17
33
 
18
34
  id = SO4()
19
35
  v1 = np.array([0, 0, 0, 0.1, 0, 0])
@@ -21,6 +37,15 @@ Q1 = SO4.Expmap(v1)
21
37
  v2 = np.array([0, 0, 0, 0.01, 0.02, 0.03])
22
38
  Q2 = SO4.Expmap(v2)
23
39
 
40
+ P1_sim2 = Similarity2.Expmap(np.array([0.1, 0.2, 0.3, 0.4]))
41
+ P2_sim2 = Similarity2.Expmap(np.array([0.2, 0.3, 0.4, 0.5]))
42
+
43
+ P1_sim3 = Similarity3.Expmap(np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7]))
44
+ P2_sim3 = Similarity3.Expmap(np.array([0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]))
45
+
46
+ G1_gal3 = Gal3(Rot3.Rz(0.1), np.array([0.2, 0.3, 0.4]), np.array([0.5, 0.6, 0.7]), 0.8)
47
+ G2_gal3 = Gal3(Rot3.Rz(0.2), np.array([0.3, 0.4, 0.5]), np.array([0.6, 0.7, 0.8]), 0.9)
48
+
24
49
 
25
50
  class TestFrobeniusFactorSO4(unittest.TestCase):
26
51
  """Test FrobeniusFactor factors."""
@@ -29,7 +54,7 @@ class TestFrobeniusFactorSO4(unittest.TestCase):
29
54
  """Test creation of a factor that calculates the Frobenius norm."""
30
55
  factor = FrobeniusFactorSO4(1, 2)
31
56
  actual = factor.evaluateError(Q1, Q2)
32
- expected = (Q2.matrix()-Q1.matrix()).transpose().reshape((16,))
57
+ expected = (Q2.matrix() - Q1.matrix()).transpose().reshape((16,))
33
58
  np.testing.assert_array_equal(actual, expected)
34
59
 
35
60
  def test_frobenius_between_factor(self):
@@ -52,5 +77,47 @@ class TestFrobeniusFactorSO4(unittest.TestCase):
52
77
  np.testing.assert_array_almost_equal(actual, expected, decimal=4)
53
78
 
54
79
 
80
+ class TestFrobeniusFactorSimilarity2(unittest.TestCase):
81
+ def test_frobenius_factor(self):
82
+ factor = FrobeniusFactorSimilarity2(1, 2)
83
+ actual = factor.evaluateError(P1_sim2, P2_sim2)
84
+ expected = (P2_sim2.matrix() - P1_sim2.matrix()).transpose().reshape((9,))
85
+ np.testing.assert_allclose(actual, expected, atol=1e-9)
86
+
87
+ def test_frobenius_between_factor(self):
88
+ factor = FrobeniusBetweenFactorSimilarity2(1, 2, P1_sim2.between(P2_sim2))
89
+ actual = factor.evaluateError(P1_sim2, P2_sim2)
90
+ expected = np.zeros((9,))
91
+ np.testing.assert_allclose(actual, expected, atol=1e-9)
92
+
93
+
94
+ class TestFrobeniusFactorSimilarity3(unittest.TestCase):
95
+ def test_frobenius_factor(self):
96
+ factor = FrobeniusFactorSimilarity3(1, 2)
97
+ actual = factor.evaluateError(P1_sim3, P2_sim3)
98
+ expected = (P2_sim3.matrix() - P1_sim3.matrix()).transpose().reshape((16,))
99
+ np.testing.assert_allclose(actual, expected, atol=1e-9)
100
+
101
+ def test_frobenius_between_factor(self):
102
+ factor = FrobeniusBetweenFactorSimilarity3(1, 2, P1_sim3.between(P2_sim3))
103
+ actual = factor.evaluateError(P1_sim3, P2_sim3)
104
+ expected = np.zeros((16,))
105
+ np.testing.assert_allclose(actual, expected, atol=1e-9)
106
+
107
+
108
+ class TestFrobeniusFactorGal3(unittest.TestCase):
109
+ def test_frobenius_factor(self):
110
+ factor = FrobeniusFactorGal3(1, 2)
111
+ actual = factor.evaluateError(G1_gal3, G2_gal3)
112
+ expected = (G2_gal3.matrix() - G1_gal3.matrix()).transpose().reshape((25,))
113
+ np.testing.assert_allclose(actual, expected, atol=1e-9)
114
+
115
+ def test_frobenius_between_factor(self):
116
+ factor = FrobeniusBetweenFactorGal3(1, 2, G1_gal3.between(G2_gal3))
117
+ actual = factor.evaluateError(G1_gal3, G2_gal3)
118
+ expected = np.zeros((25,))
119
+ np.testing.assert_allclose(actual, expected, atol=1e-9)
120
+
121
+
55
122
  if __name__ == "__main__":
56
123
  unittest.main()
gtsam/tests/test_Sim2.py CHANGED
@@ -8,6 +8,7 @@ See LICENSE for the license information
8
8
  Sim3 unit tests.
9
9
  Author: John Lambert
10
10
  """
11
+
11
12
  # pylint: disable=no-name-in-module
12
13
  import unittest
13
14
 
@@ -27,12 +28,12 @@ class TestSim2(GtsamTestCase):
27
28
  3 object poses
28
29
  same scale (no gauge ambiguity)
29
30
  world frame has poses rotated about 180 degrees.
30
- world and egovehicle frame translated by 15 meters w.r.t. each other
31
+ world and ego-vehicle frame translated by 15 meters w.r.t. each other
31
32
  """
32
33
  R180 = Rot2.fromDegrees(180)
33
34
 
34
- # Create source poses (three objects o1, o2, o3 living in the egovehicle "e" frame)
35
- # Suppose they are 3d cuboids detected by an onboard sensor in the egovehicle frame
35
+ # Create source poses (three objects o1, o2, o3 living in the ego-vehicle "e" frame)
36
+ # Suppose they are 3d cuboids detected by an onboard sensor in the ego-vehicle frame
36
37
  eTo0 = Pose2(Rot2(), np.array([5, 0]))
37
38
  eTo1 = Pose2(Rot2(), np.array([10, 0]))
38
39
  eTo2 = Pose2(Rot2(), np.array([15, 0]))
@@ -49,7 +50,7 @@ class TestSim2(GtsamTestCase):
49
50
 
50
51
  we_pairs = list(zip(wToi_list, eToi_list))
51
52
 
52
- # Recover the transformation wSe (i.e. world_S_egovehicle)
53
+ # Recover the transformation wSe (i.e. world_S_ego-vehicle)
53
54
  wSe = Similarity2.Align(we_pairs)
54
55
 
55
56
  for wToi, eToi in zip(wToi_list, eToi_list):
@@ -62,12 +63,12 @@ class TestSim2(GtsamTestCase):
62
63
  3 object poses
63
64
  with gauge ambiguity (2x scale)
64
65
  world frame has poses rotated by 90 degrees.
65
- world and egovehicle frame translated by 11 meters w.r.t. each other
66
+ world and ego-vehicle frame translated by 11 meters w.r.t. each other
66
67
  """
67
68
  R90 = Rot2.fromDegrees(90)
68
69
 
69
- # Create source poses (three objects o1, o2, o3 living in the egovehicle "e" frame)
70
- # Suppose they are 3d cuboids detected by an onboard sensor in the egovehicle frame
70
+ # Create source poses (three objects o1, o2, o3 living in the ego-vehicle "e" frame)
71
+ # Suppose they are 3d cuboids detected by an onboard sensor in the ego-vehicle frame
71
72
  eTo0 = Pose2(Rot2(), np.array([1, 0]))
72
73
  eTo1 = Pose2(Rot2(), np.array([2, 0]))
73
74
  eTo2 = Pose2(Rot2(), np.array([4, 0]))
@@ -84,7 +85,7 @@ class TestSim2(GtsamTestCase):
84
85
 
85
86
  we_pairs = list(zip(wToi_list, eToi_list))
86
87
 
87
- # Recover the transformation wSe (i.e. world_S_egovehicle)
88
+ # Recover the transformation wSe (i.e. world_S_ego-vehicle)
88
89
  wSe = Similarity2.Align(we_pairs)
89
90
 
90
91
  for wToi, eToi in zip(wToi_list, eToi_list):
@@ -122,7 +123,7 @@ class TestSim2(GtsamTestCase):
122
123
 
123
124
  ab_pairs = list(zip(aTi_list, bTi_list))
124
125
 
125
- # Recover the transformation wSe (i.e. world_S_egovehicle)
126
+ # Recover the transformation wSe (i.e. world_S_ego-vehicle)
126
127
  aSb = Similarity2.Align(ab_pairs)
127
128
 
128
129
  for aTi, bTi in zip(aTi_list, bTi_list):
@@ -190,6 +191,89 @@ class TestSim2(GtsamTestCase):
190
191
  bSa = Similarity2(R=bRa, t=bta, s=bsa)
191
192
  self.assertEqual(bSa.scale(), 3.0)
192
193
 
194
+ def test_compose(self) -> None:
195
+ """Test group operation: compose two Similarity2 elements."""
196
+ R1 = Rot2.fromDegrees(30)
197
+ t1 = np.array([1, 2])
198
+ s1 = 2.0
199
+ S1 = Similarity2(R=R1, t=t1, s=s1)
200
+
201
+ R2 = Rot2.fromDegrees(45)
202
+ t2 = np.array([-1, 1])
203
+ s2 = 4.0
204
+ S2 = Similarity2(R=R2, t=t2, s=s2)
205
+
206
+ S3 = S1.compose(S2)
207
+
208
+ # Compose manually
209
+ expected_R = R1.compose(R2)
210
+ expected_s = s1 * s2
211
+ expected_t = t1 / s2 + R1.matrix() @ t2
212
+ expected_S3 = Similarity2(R=expected_R, t=expected_t, s=expected_s)
213
+
214
+ self.gtsamAssertEquals(S3, expected_S3)
215
+ self.gtsamAssertEquals(S1 * S2, expected_S3)
216
+ self.gtsamAssertEquals(S1.matrix() @ S2.matrix(), S3.matrix())
217
+
218
+ def test_inverse(self) -> None:
219
+ """Test group operation: inverse of a Similarity2 element."""
220
+ R = Rot2.fromDegrees(60)
221
+ t = np.array([3, -2])
222
+ s = 4.0
223
+ S = Similarity2(R=R, t=t, s=s)
224
+ S_inv = S.inverse()
225
+
226
+ # Check that S * S_inv is identity
227
+ I_sim = S.compose(S_inv)
228
+ expected_I = Similarity2()
229
+ self.gtsamAssertEquals(I_sim, expected_I)
230
+
231
+ def test_identity(self) -> None:
232
+ """Test that the identity Similarity2 acts as expected."""
233
+ S_id = Similarity2()
234
+ R = Rot2.fromDegrees(10)
235
+ t = np.array([5, 7])
236
+ s = 2.5
237
+ S = Similarity2(R=R, t=t, s=s)
238
+
239
+ # Compose with identity
240
+ self.gtsamAssertEquals(S.compose(S_id), S)
241
+ self.gtsamAssertEquals(S_id.compose(S), S)
242
+
243
+ def test_transform_from_point2(self):
244
+ """Test Similarity2.transformFrom with a Point2."""
245
+ R = Rot2.fromAngle(np.pi / 4) # 45 degrees
246
+ t = np.array([1.0, 2.0])
247
+ s = 3.0
248
+ sim = Similarity2(R, t, s)
249
+
250
+ p = np.array([2.0, 0.0])
251
+
252
+ # Expected: s * (R * p + t)
253
+ expected = s * (R.matrix() @ p + t)
254
+ actual = sim.transformFrom(p)
255
+
256
+ np.testing.assert_allclose(expected, actual, atol=1e-9)
257
+
258
+ def test_transform_from_pose2(self):
259
+ """Test Similarity2.transformFrom with a Pose2."""
260
+ R_sim = Rot2.fromAngle(np.pi / 6) # 30 degrees
261
+ t_sim = np.array([1.0, -1.0])
262
+ s_sim = 2.0
263
+ sim = Similarity2(R_sim, t_sim, s_sim)
264
+
265
+ R_pose = Rot2.fromAngle(-np.pi / 4) # -45 degrees
266
+ t_pose = np.array([3.0, 4.0])
267
+ pose = Pose2(R_pose, t_pose)
268
+
269
+ expected_R = R_sim.compose(R_pose)
270
+ expected_t = s_sim * (R_sim.matrix() @ t_pose + t_sim)
271
+ expected = Pose2(expected_R, expected_t)
272
+
273
+ actual = sim.transformFrom(pose)
274
+
275
+ self.gtsamAssertEquals(actual, expected)
276
+
193
277
 
194
278
  if __name__ == "__main__":
195
279
  unittest.main()
gtsam/tests/test_Sim3.py CHANGED
@@ -8,6 +8,7 @@ See LICENSE for the license information
8
8
  Sim3 unit tests.
9
9
  Author: John Lambert
10
10
  """
11
+
11
12
  # pylint: disable=no-name-in-module
12
13
  import unittest
13
14
  from typing import List, Optional
@@ -16,12 +17,88 @@ import numpy as np
16
17
  from gtsam.utils.test_case import GtsamTestCase
17
18
 
18
19
  import gtsam
19
- from gtsam import Point3, Pose3, Rot3, Similarity3, BetweenFactorSimilarity3, NonlinearFactorGraph, Values, LevenbergMarquardtOptimizer, LevenbergMarquardtParams
20
+ from gtsam import (
21
+ BetweenFactorSimilarity3,
22
+ LevenbergMarquardtOptimizer,
23
+ LevenbergMarquardtParams,
24
+ NonlinearFactorGraph,
25
+ Point3,
26
+ Pose3,
27
+ Rot3,
28
+ Similarity3,
29
+ Values,
30
+ )
20
31
 
21
32
 
22
33
  class TestSim3(GtsamTestCase):
23
34
  """Test selected Sim3 methods."""
24
35
 
36
+ # Class constants for reuse
37
+ R1 = Rot3.RzRyRx(0.1, 0.2, 0.3)
38
+ t1 = Point3(1, 2, 3)
39
+ s1 = 2.0
40
+ S1 = Similarity3(R1, t1, s1)
41
+
42
+ R2 = Rot3.RzRyRx(0.4, 0.5, 0.6)
43
+ t2 = Point3(-1, 1, 0)
44
+ s2 = 4.0
45
+ S2 = Similarity3(R2, t2, s2)
46
+
47
+ def test_compose(self) -> None:
48
+ """Test group operation: compose two Similarity3 elements."""
49
+ S3 = self.S1.compose(self.S2)
50
+
51
+ # Compose manually
52
+ expected_R = self.R1.compose(self.R2)
53
+ expected_s = self.s1 * self.s2
54
+ expected_t = self.t1 / self.s2 + self.R1.matrix() @ self.t2
55
+ expected_S3 = Similarity3(expected_R, expected_t, expected_s)
56
+
57
+ self.gtsamAssertEquals(S3, expected_S3)
58
+ self.gtsamAssertEquals(self.S1 * self.S2, expected_S3)
59
+ self.gtsamAssertEquals(self.S1.matrix() @ self.S2.matrix(), S3.matrix())
60
+
61
+ def test_inverse(self) -> None:
62
+ """Test group operation: inverse of a Similarity3 element."""
63
+ S_inv = self.S1.inverse()
64
+
65
+ # Check that S1 * S1_inv is identity
66
+ I_sim = self.S1.compose(S_inv)
67
+ expected_I = Similarity3()
68
+ self.gtsamAssertEquals(I_sim, expected_I)
69
+
70
+ def test_identity(self) -> None:
71
+ """Test that the identity Similarity3 acts as expected."""
72
+ S_id = Similarity3()
73
+
74
+ # Compose with identity
75
+ self.gtsamAssertEquals(self.S1.compose(S_id), self.S1)
76
+ self.gtsamAssertEquals(S_id.compose(self.S1), self.S1)
77
+
78
+ def test_transform_from_point3(self):
79
+ """Test Similarity3.transformFrom with a Point3."""
80
+ p = Point3(2.0, 0.0, 1.0)
81
+
82
+ # Expected: s * (R * p + t)
83
+ expected = self.s1 * (self.R1.matrix() @ p + self.t1)
84
+ actual = self.S1.transformFrom(p)
85
+
86
+ np.testing.assert_allclose(expected, actual, atol=1e-9)
87
+
88
+ def test_transform_from_pose3(self):
89
+ """Test Similarity3.transformFrom with a Pose3."""
90
+ R_pose = Rot3.RzRyRx(0.2, -0.1, 0.3)
91
+ t_pose = Point3(3.0, 4.0, 5.0)
92
+ pose = Pose3(R_pose, t_pose)
93
+
94
+ expected_R = self.R1.compose(R_pose)
95
+ expected_t = self.s1 * (self.R1.matrix() @ t_pose + self.t1)
96
+ expected = Pose3(expected_R, expected_t)
97
+
98
+ actual = self.S1.transformFrom(pose)
99
+
100
+ self.gtsamAssertEquals(actual, expected)
101
+
25
102
  def test_align_poses_along_straight_line(self):
26
103
  """Test Pose3 Align method.
27
104
 
@@ -130,7 +207,7 @@ class TestSim3(GtsamTestCase):
130
207
  for aTi, bTi in zip(aTi_list, bTi_list):
131
208
  self.gtsamAssertEquals(aTi, aSb.transformFrom(bTi))
132
209
 
133
- def test_sim3_optimization(self)->None:
210
+ def test_sim3_optimization(self) -> None:
134
211
  # Create a PriorFactor with a Sim3 prior
135
212
  prior = Similarity3(Rot3.Ypr(0.1, 0.2, 0.3), Point3(1, 2, 3), 4)
136
213
  model = gtsam.noiseModel.Isotropic.Sigma(7, 1)
@@ -154,14 +231,22 @@ class TestSim3(GtsamTestCase):
154
231
  def test_sim3_optimization2(self) -> None:
155
232
  prior = Similarity3()
156
233
  m1 = Similarity3(Rot3.Ypr(np.pi / 4.0, 0, 0), Point3(2.0, 0, 0), 1.0)
157
- m2 = Similarity3(Rot3.Ypr(np.pi / 2.0, 0, 0), Point3(np.sqrt(8) * 0.9, 0, 0), 1.0)
158
- m3 = Similarity3(Rot3.Ypr(3 * np.pi / 4.0, 0, 0), Point3(np.sqrt(32) * 0.8, 0, 0), 1.0)
234
+ m2 = Similarity3(
235
+ Rot3.Ypr(np.pi / 2.0, 0, 0), Point3(np.sqrt(8) * 0.9, 0, 0), 1.0
236
+ )
237
+ m3 = Similarity3(
238
+ Rot3.Ypr(3 * np.pi / 4.0, 0, 0), Point3(np.sqrt(32) * 0.8, 0, 0), 1.0
239
+ )
159
240
  m4 = Similarity3(Rot3.Ypr(np.pi / 2.0, 0, 0), Point3(6 * 0.7, 0, 0), 1.0)
160
241
  loop = Similarity3(1.42)
161
242
 
162
243
  priorNoise = gtsam.noiseModel.Isotropic.Sigma(7, 0.01)
163
- betweenNoise = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 10]))
164
- betweenNoise2 = gtsam.noiseModel.Diagonal.Sigmas(np.array([ 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 1.0]))
244
+ betweenNoise = gtsam.noiseModel.Diagonal.Sigmas(
245
+ np.array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 10])
246
+ )
247
+ betweenNoise2 = gtsam.noiseModel.Diagonal.Sigmas(
248
+ np.array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 1.0])
249
+ )
165
250
  b1 = BetweenFactorSimilarity3(1, 2, m1, betweenNoise)
166
251
  b2 = BetweenFactorSimilarity3(2, 3, m2, betweenNoise)
167
252
  b3 = BetweenFactorSimilarity3(3, 4, m3, betweenNoise)
@@ -178,13 +263,20 @@ class TestSim3(GtsamTestCase):
178
263
  graph.add(lc)
179
264
 
180
265
  # graph.print("Full Graph\n");
181
- initial=Values()
266
+ initial = Values()
182
267
  initial.insert(1, prior)
183
- initial.insert(2, Similarity3(Rot3.Ypr(np.pi / 2.0, 0, 0), Point3(1, 0, 0), 1.1))
184
- initial.insert(3, Similarity3(Rot3.Ypr(2.0 * np.pi / 2.0, 0, 0), Point3(0.9, 1.1, 0), 1.2))
185
- initial.insert(4, Similarity3(Rot3.Ypr(3.0 * np.pi / 2.0, 0, 0), Point3(0, 1, 0), 1.3))
186
- initial.insert(5, Similarity3(Rot3.Ypr(4.0 * np.pi / 2.0, 0, 0), Point3(0, 0, 0), 1.0))
187
-
268
+ initial.insert(
269
+ 2, Similarity3(Rot3.Ypr(np.pi / 2.0, 0, 0), Point3(1, 0, 0), 1.1)
270
+ )
271
+ initial.insert(
272
+ 3, Similarity3(Rot3.Ypr(2.0 * np.pi / 2.0, 0, 0), Point3(0.9, 1.1, 0), 1.2)
273
+ )
274
+ initial.insert(
275
+ 4, Similarity3(Rot3.Ypr(3.0 * np.pi / 2.0, 0, 0), Point3(0, 1, 0), 1.3)
276
+ )
277
+ initial.insert(
278
+ 5, Similarity3(Rot3.Ypr(4.0 * np.pi / 2.0, 0, 0), Point3(0, 0, 0), 1.0)
279
+ )
188
280
 
189
281
  result = LevenbergMarquardtOptimizer(graph, initial).optimizeSafely()
190
282
  self.gtsamAssertEquals(Similarity3(0.7), result.atSimilarity3(5), 0.4)
@@ -695,11 +787,15 @@ class TestSim3(GtsamTestCase):
695
787
  wTi = unaligned_pose_dict.get(i, None)
696
788
  unaligned_pose_list.append(wTi)
697
789
  # GT poses are the reference/target
698
- rSe = align_poses_sim3_ignore_missing(aTi_list=poses_gt, bTi_list=unaligned_pose_list)
790
+ rSe = align_poses_sim3_ignore_missing(
791
+ aTi_list=poses_gt, bTi_list=unaligned_pose_list
792
+ )
699
793
  assert rSe.scale() >= 0
700
794
 
701
795
 
702
- def align_poses_sim3_ignore_missing(aTi_list: List[Optional[Pose3]], bTi_list: List[Optional[Pose3]]) -> Similarity3:
796
+ def align_poses_sim3_ignore_missing(
797
+ aTi_list: List[Optional[Pose3]], bTi_list: List[Optional[Pose3]]
798
+ ) -> Similarity3:
703
799
  """Align by similarity transformation, but allow missing estimated poses in the input.
704
800
 
705
801
  Note: this is a wrapper for align_poses_sim3() that allows for missing poses/dropped cameras.
@@ -763,7 +859,9 @@ def align_poses_sim3(aTi_list: List[Pose3], bTi_list: List[Pose3]) -> Similarity
763
859
 
764
860
  # fit a single translation motion to the centroid
765
861
  aTi_centroid = np.array([aTi.translation() for aTi in aTi_list]).mean(axis=0)
766
- aTi_rot_aligned_centroid = np.array([aTi.translation() for aTi in aTi_list_rot_aligned]).mean(axis=0)
862
+ aTi_rot_aligned_centroid = np.array(
863
+ [aTi.translation() for aTi in aTi_list_rot_aligned]
864
+ ).mean(axis=0)
767
865
 
768
866
  # construct the final SIM3 transform
769
867
  aSb = Similarity3(aSb.rotation(), aTi_centroid - aTi_rot_aligned_centroid, 1.0)
@@ -0,0 +1,100 @@
1
+ """
2
+ Generates a CSV file with ground-truth trajectory data for testing a
3
+ DiscreteScenario in GTSAM.
4
+
5
+ The trajectory is a simple horizontal circle at a constant height and speed.
6
+
7
+ CSV Format:
8
+ timestamp,px,py,pz,qw,qx,qy,qz,vx,vy,vz,omegax,omegay,omegaz,ax,ay,az
9
+ """
10
+ import numpy as np
11
+ import csv
12
+ from gtsam import Rot3
13
+
14
+ # --- Trajectory Parameters ---
15
+ RADIUS = 5.0 # meters
16
+ HEIGHT = 1.0 # meters
17
+ OMEGA_Z = 0.2 # rad/s (angular velocity around Z-axis)
18
+ DURATION = 20.0 # seconds
19
+ FREQUENCY = 100 # Hz
20
+ FILENAME = "trajectory.csv"
21
+
22
+
23
+ def generate_data():
24
+ """Generates and saves the trajectory data."""
25
+
26
+ # Time vector
27
+ t = np.arange(0.0, DURATION, 1.0 / FREQUENCY)
28
+
29
+ # Angle at each time step
30
+ angle = OMEGA_Z * t
31
+
32
+ # Position (p_n) in navigation frame
33
+ px = RADIUS * np.cos(angle)
34
+ py = RADIUS * np.sin(angle)
35
+ pz = np.full_like(t, HEIGHT)
36
+
37
+ # Velocity (v_n) in navigation frame (derivative of position)
38
+ speed = RADIUS * OMEGA_Z
39
+ vx = -speed * np.sin(angle)
40
+ vy = speed * np.cos(angle)
41
+ vz = np.zeros_like(t)
42
+
43
+ # Acceleration (a_n) in navigation frame (derivative of velocity)
44
+ # This is the centripetal acceleration.
45
+ ax = -speed * OMEGA_Z * np.cos(angle)
46
+ ay = -speed * OMEGA_Z * np.sin(angle)
47
+ az = np.zeros_like(t)
48
+
49
+ # Angular velocity (omega_b) in the body frame
50
+ # The body is only rotating around its z-axis to face forward.
51
+ omegax = np.zeros_like(t)
52
+ omegay = np.zeros_like(t)
53
+ omegaz = np.full_like(t, OMEGA_Z)
54
+
55
+ # Orientation (quaternion q_n_b)
56
+ # We use gtsam.Rot3 to easily get the quaternion
57
+ quaternions = [Rot3.Yaw(a).toQuaternion() for a in angle]
58
+
59
+ # --- Write to CSV ---
60
+ header = [
61
+ 'timestamp',
62
+ 'px',
63
+ 'py',
64
+ 'pz', # Position
65
+ 'qw',
66
+ 'qx',
67
+ 'qy',
68
+ 'qz', # Quaternion (orientation)
69
+ 'vx',
70
+ 'vy',
71
+ 'vz', # Velocity (nav frame)
72
+ 'omegax',
73
+ 'omegay',
74
+ 'omegaz', # Angular velocity (body frame)
75
+ 'ax',
76
+ 'ay',
77
+ 'az' # Acceleration (nav frame)
78
+ ]
79
+
80
+ with open(FILENAME, 'w', newline='') as f:
81
+ writer = csv.writer(f)
82
+ writer.writerow(header)
83
+
84
+ for i in range(len(t)):
85
+ q = quaternions[i]
86
+ row = [
87
+ t[i], px[i], py[i], pz[i],
88
+ q.w(),
89
+ q.x(),
90
+ q.y(),
91
+ q.z(), vx[i], vy[i], vz[i], omegax[i], omegay[i], omegaz[i],
92
+ ax[i], ay[i], az[i]
93
+ ]
94
+ writer.writerow(row)
95
+
96
+ print(f"Successfully generated trajectory data at '{FILENAME}'")
97
+
98
+
99
+ if __name__ == "__main__":
100
+ generate_data()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gtsam-develop
3
- Version: 4.3a0.dev202506061328
3
+ Version: 4.3a0.dev202508020718
4
4
  Summary: Georgia Tech Smoothing And Mapping library
5
5
  Home-page: https://gtsam.org/
6
6
  Author: Frank Dellaert et. al.
@@ -1,15 +1,15 @@
1
1
  gtsam/symbol_shorthand.py,sha256=HlTV-Z5aB5cXWT5AsbKOeWZIHoXQsH2W1S90ET-tidA,236
2
- gtsam/gtsam.cpython-313-darwin.so,sha256=s6_6Y3ReaYVrKDw6PI9xGcy-Rw81QT_TEC7osfW2-HQ,17958208
3
- gtsam/__init__.pyi,sha256=UcDdH7hnX_LxPoVGgEVTc61uIO9EPlz7wbNb6q0NztM,43159
2
+ gtsam/gtsam.cpython-313-darwin.so,sha256=ajEhpJFGFxUHBlvoqK7UXRzBb_v4a0fQyYNOfGtWhFw,18388256
3
+ gtsam/__init__.pyi,sha256=DYxi6z8omNp5T223mvKU4atL3VufNl0ZIV0kzzQSiKA,44348
4
4
  gtsam/gtsfm.py,sha256=Udlkb6o5iUk69uxBkb88-W1GLfu1g8iSuZlLu-RRU0o,202
5
5
  gtsam/__init__.py,sha256=6G-WPnb_FMQEJXNDDAmrKrQPau7evtd5svhTmMqhYSI,2011
6
6
  gtsam/noiseModel.py,sha256=ybfIHa4sLXe78_k-Dib8nTaw34BRXqEDVtS2B9dzSO0,217
7
7
  gtsam/imuBias.py,sha256=tz3bOCFl29iMycbGFoF-ud6kRsJYjA7DJ2RJoKPFRU8,209
8
8
  gtsam/gtsam/utilities.pyi,sha256=-yn7_jeJbTa_3KJGgqcr_NDD70UhDZ8tYX2M2lPLmSQ,3384
9
9
  gtsam/gtsam/gtsfm.pyi,sha256=Onoh4CRaSYIQ0FID0vBkZeV7ESIhc2fh4rJGgaPY-ug,702
10
- gtsam/gtsam/__init__.pyi,sha256=jXBrjnWgYNOL6XPnXscjpsnIVXibwxHBM3IptxDxXrM,719848
10
+ gtsam/gtsam/__init__.pyi,sha256=FPVgJrBj3b8G3M2wkTchZ8RCFSR9DqaWn88Bzn0yQ9w,738515
11
11
  gtsam/gtsam/so3.pyi,sha256=UoDGISMgcStVTAtc_y6CmHXCtPJrJ7ju70z3ZH1OLR4,3939
12
- gtsam/gtsam/imuBias.pyi,sha256=gD6w5kd9xpO4uBEpfNym_3LjW67MV7HPQRYOOoDPysQ,2478
12
+ gtsam/gtsam/imuBias.pyi,sha256=UqK0nLVICpnyw8B8_Q1GgX-qRd6atlCXT6OZNffZ1ao,2797
13
13
  gtsam/gtsam/symbol_shorthand.pyi,sha256=iaQLf_-hch_4YTYbSWTLINKtIL9Mg7W7HKOMuCXp8Ok,991
14
14
  gtsam/gtsam/lago.pyi,sha256=-VzJaQ1ho25n7S4VjbugWmPNUtKeMsoESifX9K8l2Yo,551
15
15
  gtsam/gtsam/noiseModel/__init__.pyi,sha256=hmp6DnyP7wwhjNN_Xoh2dX0E89yJ_YMBrlbjxu-1Kr0,8787
@@ -17,7 +17,7 @@ gtsam/gtsam/noiseModel/mEstimator.pyi,sha256=DCClE_67kH2L-6wsiIEExB3xzkwi-dprZM2
17
17
  gtsam/tests/simulation.py,sha256=VAopcCosvdtXRy6xe547EDz73lXhLiYbPnFQZWjo2wU,5405
18
18
  gtsam/tests/test_OdometryExample.py,sha256=aO-ciYNbKo8ru0bxexEtlj4xN9WGiSBlLOQnRkCCAx0,2094
19
19
  gtsam/tests/test_KarcherMeanFactor.py,sha256=L3_VAOljyRDmyOjOlZqnW-5apqufsDd8UnLIZ-d-_VE,2369
20
- gtsam/tests/test_FrobeniusFactor.py,sha256=egW1w1CzwlfGXijNB6_eYL2s9A0fSpTqtvXmqeL_jVo,1831
20
+ gtsam/tests/test_FrobeniusFactor.py,sha256=azS0x0EDgj9N4Z4OYAMip94hTkvYo7AcjZvuLtctGMA,4420
21
21
  gtsam/tests/ImuFactorISAM2Example.py,sha256=G9HS3tHAp3plMfulFtsxE1mR467wSXlpoND8GjbqbyM,5724
22
22
  gtsam/tests/CombinedImuFactorExample.py,sha256=RLR2_q6IU-cAHiaVYBNPeT8Xg1COVHuXKrML6l480Vk,9455
23
23
  gtsam/tests/test_Factors.py,sha256=ehOfrP2xHSQiIDgtWcoxxg59MiQsHWPB_maaf-YEs7U,1427
@@ -36,7 +36,7 @@ gtsam/tests/test_KalmanFilter.py,sha256=OinaR5eDHP9kYzn-CDvtX2FiPdOW15EkGExGIrSz
36
36
  gtsam/tests/SimpleRotation.py,sha256=3ZAReijr08HTDwA_Hl48gBgcERvd1hjl9YUSVGQTwDQ,2862
37
37
  gtsam/tests/test_pickle.py,sha256=10MzCXyC6glUuFfYOlUufvVhEOYTRyJOTaTrnYG2n1U,1526
38
38
  gtsam/tests/ViewGraphComparison.py,sha256=A2mDOHKHOKMUqUo8OR0Sv8yNjDg3wum7T6vUSeGnCvw,15837
39
- gtsam/tests/test_Sim2.py,sha256=7wWyW0Cvyt5r8GFWPPoWAzZ7iaepI1rPTUlxLCso1EE,6941
39
+ gtsam/tests/test_Sim2.py,sha256=qU3nxd7fJDHS4dnTENVX-b5rukV33q649WBfQ-5q6Po,9630
40
40
  gtsam/tests/test_Robust.py,sha256=_PlWYU0geYoYTQXXKNz4jsHnjZbGyN7ZkJnymAAV9Cs,1221
41
41
  gtsam/tests/Pose3SLAMExample_g2o.py,sha256=iei2UD8L7o9XkSOLmHy8cAI3iPcVbYBPO-zraSbq_Cc,2555
42
42
  gtsam/tests/Pose3ISAM2Example.py,sha256=pTSARr97SpU9ooKTK8qgBWIdCGtcoajje25V67BiyyE,9664
@@ -55,7 +55,7 @@ gtsam/tests/Pose2SLAMExample_g2o.py,sha256=H6fQLRonBpcmwIS8SbD8DSqv4M62LC2LwlUp1
55
55
  gtsam/tests/test_PriorFactor.py,sha256=ksMSqAX5qLcyLYOuwixWetZZLYkAXPA3z9uOcY-ySyw,1692
56
56
  gtsam/tests/test_lago.py,sha256=c5QBnmxYzTiZ2-B7Uk4pyiUEU4LvQsaDrejsVxhes2I,2507
57
57
  gtsam/tests/Pose3SLAMExample_initializePose3Chordal.py,sha256=0SgX7ClrRzABbCqtNN3ZqaCR92p_uOtGoUJziwsYfOQ,1071
58
- gtsam/tests/test_Sim3.py,sha256=N-QnVc_PHVp292lsnNWgiA0NJvIYVLYN94Z74WxG1gA,29949
58
+ gtsam/tests/test_Sim3.py,sha256=6Ku0Ij_VsU5u7pUZVZCBDN4uf3-V8jTPbJM9EHNLjEM,32486
59
59
  gtsam/tests/test_Pose3SLAMExample.py,sha256=aKR4LiKfjGg2eypgreQeFr40zsq3ScCDGfpdGs6j-lc,2168
60
60
  gtsam/tests/test_custom_factor.py,sha256=J9Bu3SSGaEyyO0xHmyO7l1wWsw9olEon0lAjic7WCaU,7105
61
61
  gtsam/tests/test_NonlinearOptimizer.py,sha256=-2bnIvl2L_KrGUQICkiCvyAyOSjvKMrIG0jkrKmZiiY,7021
@@ -127,11 +127,12 @@ gtsam/utils/__init__.pyi,sha256=rOxjuQsV7ttKrJTXadEoMU5hwYD1bs07TeRQPlhtskk,232
127
127
  gtsam/utils/__init__.py,sha256=_ID7pb13SDZedga5KdBqpPug4PW3eU3THdVF_3jrakQ,678
128
128
  gtsam/utils/test_case.py,sha256=3wIqAW5_smes95XUJgUjD4v3FXACYSVzQ1l6MMdwSkA,1848
129
129
  gtsam/utils/logging_optimizer.py,sha256=tRnzQKV4eT5djS0Ojy5J7OGu7oVRjZw7Jhjrx_VQVTU,4417
130
+ gtsam/utils/generate_trajectory.py,sha256=_1TZWhpRKj8ha0FOEmqUpEzAt3KLgwqyZJ4ueFD2jmE,2663
130
131
  gtsam/.dylibs/libboost_thread.dylib,sha256=aT1DCt1Kvw1A2w2mRHIJhZRFrYmoDaI5xYM6wEt86L8,137200
131
- gtsam/.dylibs/libgtsam.4.3a0.dev202506061328.dylib,sha256=97SFwIW0MvuSUb5MDBMmLfUTVbrWwwPypPTBVJrtQrE,5666736
132
+ gtsam/.dylibs/libgtsam.4.3a0.dev202508020718.dylib,sha256=UqslIPQSC8Auc26ab9nU6Ph2cFfKp93A4Bqy7_kmJ38,5958080
132
133
  gtsam/.dylibs/libboost_regex.dylib,sha256=XWw3H3ehJjFuFVSSDGo2lyKOIsoTQ-0Aaf1ekhsQJfY,356464
133
- gtsam/.dylibs/libgtsam_unstable.4.3a0.dev202506061328.dylib,sha256=xt4wapQFshSo8VQKaac3YNU7cmvErNlt2eiPOwf7EeY,1623104
134
134
  gtsam/.dylibs/libboost_serialization.dylib,sha256=7OW78djID14u2YB_F_TuXomOIsEpt8I7RnCAGuGmwCc,418288
135
+ gtsam/.dylibs/libgtsam_unstable.4.3a0.dev202508020718.dylib,sha256=qBHqX_oNtcxOl_E4VdrKuw0HCwgXrE30c4-VjTreZLA,1623248
135
136
  gtsam/.dylibs/libboost_timer.dylib,sha256=leVXIyCdydip4vwIm-Ghrt6UGy_Q-yhL2f8ITyfRku0,81520
136
137
  gtsam/.dylibs/libboost_filesystem.dylib,sha256=WUuuO1JZADriLciFi63Ky4dmqt1KA7_V6DcNdzCANSo,197328
137
138
  gtsam/.dylibs/libcephes-gtsam.1.0.0.dylib,sha256=pNZtgCIaV7_dC0WPXobOc8sNvd_0WQo1AdYxUsqZ1D0,176352
@@ -249,12 +250,12 @@ gtsam/Data/Balbianello/BalbianelloMedium-4.key.gz,sha256=P6tu3JmA0NKlcFYdgYczTOH
249
250
  gtsam/Data/Balbianello/BalbianelloMedium-1.key.gz,sha256=RgT7tVXXOwvDug20TW-9xtoeO3dSSPMF1n9DaKxdrIw,332878
250
251
  gtsam/Data/Balbianello/BalbianelloMedium-3.key.gz,sha256=yNMcyqwZCOj9FG-6qXQ9xhJjpM135cTBJYlOUBG0rnQ,296236
251
252
  gtsam/Data/Balbianello/BalbianelloMedium-5.key.gz,sha256=4veDrxRdLH8k1DIhgj1984MitZ7nAWoXDWTWyXuu7Lg,241361
252
- gtsam_develop-4.3a0.dev202506061328.dist-info/RECORD,,
253
- gtsam_develop-4.3a0.dev202506061328.dist-info/WHEEL,sha256=oqGJCpG61FZJmvyZ3C_0aCv-2mdfcY9e3fXvyUNmWfM,136
254
- gtsam_develop-4.3a0.dev202506061328.dist-info/top_level.txt,sha256=DOnqfd8DN2HpG5-V5t32TjFOB_vcYuyOWyRsgeoANEo,30
255
- gtsam_develop-4.3a0.dev202506061328.dist-info/METADATA,sha256=37w798g3ZJ3SpCfrPO6ttpf1_SPl9MJ992G6PUotF_s,7767
253
+ gtsam_develop-4.3a0.dev202508020718.dist-info/RECORD,,
254
+ gtsam_develop-4.3a0.dev202508020718.dist-info/WHEEL,sha256=oqGJCpG61FZJmvyZ3C_0aCv-2mdfcY9e3fXvyUNmWfM,136
255
+ gtsam_develop-4.3a0.dev202508020718.dist-info/top_level.txt,sha256=DOnqfd8DN2HpG5-V5t32TjFOB_vcYuyOWyRsgeoANEo,30
256
+ gtsam_develop-4.3a0.dev202508020718.dist-info/METADATA,sha256=AQqsvHo0Jzs8I42vYOzqyhIUnT32oqoQp0vq7D0MSqU,7767
256
257
  gtsam_unstable/__init__.py,sha256=FPc_oO5PFQZbrfpgugzQuI6LJfP1fzq82UQf_nuyGtk,30
257
- gtsam_unstable/gtsam_unstable.cpython-313-darwin.so,sha256=AeSYJ-q7LZLDBOllOL6gkRZNoJNM-fQfZhxdiNEZuK8,2050208
258
+ gtsam_unstable/gtsam_unstable.cpython-313-darwin.so,sha256=ZP61nXHgImqgLVEEcVOq0FL8P9Nr8srtbX8Q_EJh8ro,2050224
258
259
  gtsam_unstable/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
259
260
  gtsam_unstable/tests/test_ProjectionFactorRollingShutter.py,sha256=t2l62uWoXfjrM8oH6ogV7M20WjTYKZ4CSferdurMIY0,2156
260
261
  gtsam_unstable/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0