so3.py
Go to the documentation of this file.
1 import sympy
2 import sys
3 import unittest
4 import sophus
5 import functools
6 
7 
8 class So3:
9  """ 3 dimensional group of orthogonal matrices with determinant 1 """
10 
11  def __init__(self, q):
12  """ internally represented by a unit quaternion q """
13  self.q = q
14 
15  @staticmethod
16  def exp(v):
17  """ exponential map """
18  theta_sq = sophus.squared_norm(v)
19  theta = sympy.sqrt(theta_sq)
20  return So3(
22  sympy.cos(0.5 * theta),
23  sympy.sin(0.5 * theta) / theta * v))
24 
25  def log(self):
26  """ logarithmic map"""
27  n = sympy.sqrt(sophus.squared_norm(self.q.vec))
28  return 2 * sympy.atan(n / self.q.real) / n * self.q.vec
29 
30  def __repr__(self):
31  return "So3:" + repr(self.q)
32 
33  def inverse(self):
34  return So3(self.q.conj())
35 
36  @staticmethod
37  def hat(o):
38  return sympy.Matrix([[0, -o[2], o[1]],
39  [o[2], 0, -o[0]],
40  [-o[1], o[0], 0]])
41 
42  """vee-operator
43 
44  It takes the 3x3-matrix representation ``Omega`` and maps it to the
45  corresponding vector representation of Lie algebra.
46 
47  This is the inverse of the hat-operator, see above.
48 
49  Precondition: ``Omega`` must have the following structure:
50 
51  | 0 -c b |
52  | c 0 -a |
53  | -b a 0 |
54  """
55  @staticmethod
56  def vee(Omega):
57  v = sophus.Vector3(Omega.row(2).col(1), Omega.row(0).col(2), Omega.row(1).col(0))
58  return v
59 
60  def matrix(self):
61  """ returns matrix representation """
62  return sympy.Matrix([[
63  1 - 2 * self.q.vec[1]**2 - 2 * self.q.vec[2]**2,
64  2 * self.q.vec[0] * self.q.vec[1] -
65  2 * self.q.vec[2] * self.q[3],
66  2 * self.q.vec[0] * self.q.vec[2] +
67  2 * self.q.vec[1] * self.q[3]
68  ], [
69  2 * self.q.vec[0] * self.q.vec[1] +
70  2 * self.q.vec[2] * self.q[3],
71  1 - 2 * self.q.vec[0]**2 - 2 * self.q.vec[2]**2,
72  2 * self.q.vec[1] * self.q.vec[2] -
73  2 * self.q.vec[0] * self.q[3]
74  ], [
75  2 * self.q.vec[0] * self.q.vec[2] -
76  2 * self.q.vec[1] * self.q[3],
77  2 * self.q.vec[1] * self.q.vec[2] +
78  2 * self.q.vec[0] * self.q[3],
79  1 - 2 * self.q.vec[0]**2 - 2 * self.q.vec[1]**2
80  ]])
81 
82  def __mul__(self, right):
83  """ left-multiplication
84  either rotation concatenation or point-transform """
85  if isinstance(right, sympy.Matrix):
86  assert right.shape == (3, 1), right.shape
87  return (self.q * sophus.Quaternion(0, right) * self.q.conj()).vec
88  elif isinstance(right, So3):
89  return So3(self.q * right.q)
90  assert False, "unsupported type: {0}".format(type(right))
91 
92  def __getitem__(self, key):
93  return self.q[key]
94 
95  @staticmethod
96  def calc_Dx_exp_x(x):
97  return sympy.Matrix(4, 3, lambda r, c:
98  sympy.diff(So3.exp(x)[r], x[c]))
99 
100  @staticmethod
102  return sympy.Matrix([[0.5, 0.0, 0.0],
103  [0.0, 0.5, 0.0],
104  [0.0, 0.0, 0.5],
105  [0.0, 0.0, 0.0]])
106 
107  @staticmethod
109  return So3.calc_Dx_exp_x(x).subs(x[0], 0).subs(x[1], 0).limit(x[2], 0)
110 
112  return sympy.Matrix(4, 3, lambda r, c:
113  sympy.diff((self * So3.exp(x))[r], x[c]))\
114  .subs(x[0], 0).subs(x[1], 0).limit(x[2], 0)
115 
117  return sympy.Matrix(3, 4, lambda r, c:
118  sympy.diff((self * So3.exp(x))[c], x[r, 0]))\
119  .subs(x[0], 0).subs(x[1], 0).limit(x[2], 0)
120 
121  @staticmethod
122  def Dxi_x_matrix(x, i):
123  if i == 0:
124  return sympy.Matrix([[0, 2 * x[1], 2 * x[2]],
125  [2 * x[1], -4 * x[0], -2 * x[3]],
126  [2 * x[2], 2 * x[3], -4 * x[0]]])
127  if i == 1:
128  return sympy.Matrix([[-4 * x[1], 2 * x[0], 2 * x[3]],
129  [2 * x[0], 0, 2 * x[2]],
130  [-2 * x[3], 2 * x[2], -4 * x[1]]])
131  if i == 2:
132  return sympy.Matrix([[-4 * x[2], -2 * x[3], 2 * x[0]],
133  [2 * x[3], -4 * x[2], 2 * x[1]],
134  [2 * x[0], 2 * x[1], 0]])
135  if i == 3:
136  return sympy.Matrix([[0, -2 * x[2], 2 * x[1]],
137  [2 * x[2], 0, -2 * x[0]],
138  [-2 * x[1], 2 * x[0], 0]])
139 
140  @staticmethod
141  def calc_Dxi_x_matrix(x, i):
142  return sympy.Matrix(3, 3, lambda r, c:
143  sympy.diff(x.matrix()[r, c], x[i]))
144 
145  @staticmethod
146  def Dxi_exp_x_matrix(x, i):
147  R = So3.exp(x)
148  Dx_exp_x = So3.calc_Dx_exp_x(x)
149  l = [Dx_exp_x[j, i] * So3.Dxi_x_matrix(R, j) for j in [0, 1, 2, 3]]
150  return functools.reduce((lambda a, b: a + b), l)
151 
152  @staticmethod
154  return sympy.Matrix(3, 3, lambda r, c:
155  sympy.diff(So3.exp(x).matrix()[r, c], x[i]))
156 
157  @staticmethod
159  v = sophus.ZeroVector3()
160  v[i] = 1
161  return So3.hat(v)
162 
163  @staticmethod
165  return sympy.Matrix(3, 3, lambda r, c:
166  sympy.diff(So3.exp(x).matrix()[r, c], x[i])
167  ).subs(x[0], 0).subs(x[1], 0).limit(x[2], 0)
168 
169 
170 class TestSo3(unittest.TestCase):
171  def setUp(self):
172  omega0, omega1, omega2 = sympy.symbols(
173  'omega[0], omega[1], omega[2]', real=True)
174  x, v0, v1, v2 = sympy.symbols('q.w() q.x() q.y() q.z()', real=True)
175  p0, p1, p2 = sympy.symbols('p0 p1 p2', real=True)
176  v = sophus.Vector3(v0, v1, v2)
177  self.omega = sophus.Vector3(omega0, omega1, omega2)
178  self.a = So3(sophus.Quaternion(x, v))
179  self.p = sophus.Vector3(p0, p1, p2)
180 
181  def test_exp_log(self):
182  for o in [sophus.Vector3(0., 1, 0.5),
183  sophus.Vector3(0.1, 0.1, 0.1),
184  sophus.Vector3(0.01, 0.2, 0.03)]:
185  w = So3.exp(o).log()
186  for i in range(0, 3):
187  self.assertAlmostEqual(o[i], w[i])
188 
189  def test_matrix(self):
190  R_foo_bar = So3.exp(self.omega)
191  Rmat_foo_bar = R_foo_bar.matrix()
192  point_bar = self.p
193  p1_foo = R_foo_bar * point_bar
194  p2_foo = Rmat_foo_bar * point_bar
195  self.assertEqual(sympy.simplify(p1_foo - p2_foo),
196  sophus.ZeroVector3())
197 
198  def test_derivatives(self):
199  self.assertEqual(sympy.simplify(So3.calc_Dx_exp_x_at_0(self.omega) -
200  So3.Dx_exp_x_at_0()),
201  sympy.Matrix.zeros(4, 3))
202 
203  for i in [0, 1, 2, 3]:
204  self.assertEqual(sympy.simplify(So3.calc_Dxi_x_matrix(self.a, i) -
205  So3.Dxi_x_matrix(self.a, i)),
206  sympy.Matrix.zeros(3, 3))
207  for i in [0, 1, 2]:
208  self.assertEqual(sympy.simplify(
209  So3.Dxi_exp_x_matrix(self.omega, i) -
210  So3.calc_Dxi_exp_x_matrix(self.omega, i)),
211  sympy.Matrix.zeros(3, 3))
212  self.assertEqual(sympy.simplify(
213  So3.Dxi_exp_x_matrix_at_0(i) -
214  So3.calc_Dxi_exp_x_matrix_at_0(self.omega, i)),
215  sympy.Matrix.zeros(3, 3))
216 
217  def test_codegen(self):
218  stream = sophus.cse_codegen(So3.calc_Dx_exp_x(self.omega))
219  filename = "cpp_gencode/So3_Dx_exp_x.cpp"
220  # set to true to generate codegen files
221  if False:
222  file = open(filename, "w")
223  for line in stream:
224  file.write(line)
225  file.close()
226  else:
227  file = open(filename, "r")
228  file_lines = file.readlines()
229  for i, line in enumerate(stream):
230  self.assertEqual(line, file_lines[i])
231  file.close()
232  stream.close
233 
234  stream = sophus.cse_codegen(
235  self.a.calc_Dx_this_mul_exp_x_at_0(self.omega))
236  filename = "cpp_gencode/So3_Dx_this_mul_exp_x_at_0.cpp"
237  # set to true to generate codegen files
238  if False:
239  file = open(filename, "w")
240  for line in stream:
241  file.write(line)
242  file.close()
243  else:
244  file = open(filename, "r")
245  file_lines = file.readlines()
246  for i, line in enumerate(stream):
247  self.assertEqual(line, file_lines[i])
248  file.close()
249  stream.close
250 
251 
252 if __name__ == '__main__':
253  unittest.main()
sophus.so3.TestSo3.test_derivatives
def test_derivatives(self)
Definition: so3.py:198
sophus.so3.So3.__getitem__
def __getitem__(self, key)
Definition: so3.py:92
sophus.so3.So3.calc_Dx_exp_x
def calc_Dx_exp_x(x)
Definition: so3.py:96
sophus.so3.TestSo3.setUp
def setUp(self)
Definition: so3.py:171
sophus.so3.So3.matrix
def matrix(self)
Definition: so3.py:60
sophus.so3.So3.__mul__
def __mul__(self, right)
Definition: so3.py:82
sophus.so3.TestSo3
Definition: so3.py:170
sophus.so3.So3.q
q
Definition: so3.py:13
sophus.so3.So3.vee
def vee(Omega)
Definition: so3.py:56
sophus.so3.So3.exp
def exp(v)
Definition: so3.py:16
sophus.so3.TestSo3.test_matrix
def test_matrix(self)
Definition: so3.py:189
sophus.so3.So3
Definition: so3.py:8
sophus.so3.TestSo3.test_codegen
def test_codegen(self)
Definition: so3.py:217
sophus.so3.So3.Dx_exp_x_at_0
def Dx_exp_x_at_0()
Definition: so3.py:101
sophus.quaternion.Quaternion
Definition: quaternion.py:9
sophus.so3.TestSo3.test_exp_log
def test_exp_log(self)
Definition: so3.py:181
sophus.cse_codegen
Definition: cse_codegen.py:1
sophus.so3.TestSo3.p
p
Definition: so3.py:179
sophus.so3.So3.__repr__
def __repr__(self)
Definition: so3.py:30
sophus.so3.TestSo3.a
a
Definition: so3.py:178
sophus.so3.So3.Dxi_exp_x_matrix_at_0
def Dxi_exp_x_matrix_at_0(i)
Definition: so3.py:158
sophus.so3.So3.__init__
def __init__(self, q)
Definition: so3.py:11
sophus.so3.So3.calc_Dx_exp_x_at_0
def calc_Dx_exp_x_at_0(x)
Definition: so3.py:108
sophus.so3.So3.inverse
def inverse(self)
Definition: so3.py:33
sophus.so3.So3.calc_Dx_this_mul_exp_x_at_0
def calc_Dx_this_mul_exp_x_at_0(self, x)
Definition: so3.py:111
sophus.so3.So3.calc_Dxi_x_matrix
def calc_Dxi_x_matrix(x, i)
Definition: so3.py:141
sophus.so3.So3.calc_Dx_exp_x_mul_this_at_0
def calc_Dx_exp_x_mul_this_at_0(self, x)
Definition: so3.py:116
sophus.so3.So3.Dxi_x_matrix
def Dxi_x_matrix(x, i)
Definition: so3.py:122
sophus.so3.So3.hat
def hat(o)
Definition: so3.py:37
sophus.so3.TestSo3.omega
omega
Definition: so3.py:177
sophus.so3.So3.Dxi_exp_x_matrix
def Dxi_exp_x_matrix(x, i)
Definition: so3.py:146
sophus.so3.So3.calc_Dxi_exp_x_matrix_at_0
def calc_Dxi_exp_x_matrix_at_0(x, i)
Definition: so3.py:164
sophus.so3.So3.calc_Dxi_exp_x_matrix
def calc_Dxi_exp_x_matrix(x, i)
Definition: so3.py:153
sophus.so3.So3.log
def log(self)
Definition: so3.py:25


sophus
Author(s): Hauke Strasdat
autogenerated on Wed Mar 2 2022 01:01:48