bindings_explog.py
Go to the documentation of this file.
1 import sys
2 import unittest
3 from pathlib import Path
4 
5 sys.path.append(str(Path(__file__).parent.parent))
6 
7 import casadi
8 import numpy as np
9 import pinocchio as pin
10 import pinocchio.casadi as cpin
11 from casadi import SX
12 from test_case import PinocchioTestCase as TestCase
13 
14 
15 class TestLogExpDerivatives(TestCase):
16  def setUp(self) -> None:
17  self.cR0 = SX.sym("R0", 3, 3)
18  self.cR1 = SX.sym("R1", 3, 3)
19  self.dv0 = SX.sym("v0", 3)
20  self.dv1 = SX.sym("v1", 3)
21  self.v_all = casadi.vertcat(self.dv0, self.dv1)
22  self.cv2 = SX.sym("v2", 3)
23  self.cdv2 = SX.sym("dv", 3) # for forming the difference
24 
25  self.cR0_i = self.cR0 @ cpin.exp3(self.dv0)
26  self.cR1_i = self.cR1 @ cpin.exp3(self.dv1)
27 
28  # SE(3) examples
29  self.cM0 = SX.sym("M0", 4, 4)
30  self.cM1 = SX.sym("M1", 4, 4)
31  self.cdw0 = SX.sym("dm0", 6)
32  self.cdw1 = SX.sym("dm1", 6)
33  self.cw2 = SX.sym("w2", 6)
34  self.cdw2 = SX.sym("dw2", 6)
35  self.cM0_i = cpin.SE3(self.cM0) * cpin.exp6(self.cdw0)
36  self.cM1_i = cpin.SE3(self.cM1) * cpin.exp6(self.cdw1)
37 
38  def test_exp3(self):
39  """Test the exp map and its derivative."""
40  dw = self.cdv2
41  exp_expr = self.cR0_i @ cpin.exp3(self.cv2 + dw)
42 
43  def repl_dargs(e):
44  return casadi.substitute(e, casadi.vertcat(self.dv0, dw), np.zeros(6))
45 
46  exp_eval = casadi.Function("exp", [self.cR0, self.cv2], [repl_dargs(exp_expr)])
47 
48  diff_expr = cpin.log3(exp_eval(self.cR0, self.cv2).T @ exp_expr)
49  Jexp_expr = casadi.jacobian(diff_expr, casadi.vertcat(self.dv0, dw))
50  Jexp_eval = casadi.Function(
51  "exp", [self.cR0, self.cv2], [repl_dargs(Jexp_expr)]
52  )
53 
54  w0 = np.zeros(3)
55  w1 = np.random.randn(3)
56  w2 = np.array([np.pi, 0, 0])
57  w3 = np.array([-np.pi, 0, 0])
58  R0 = pin.exp3(w0) # eye(3)
59  R1 = pin.exp3(w1)
60  R2 = pin.exp3(w2)
61  R3 = pin.exp3(w3)
62  self.assertApprox(exp_eval(R0, np.zeros(3)).full(), R0)
63  self.assertApprox(exp_eval(R0, w1).full(), R1)
64  self.assertApprox(exp_eval(R0, -w1).full(), R1.T)
65  self.assertApprox(exp_eval(R1, -w1).full(), R0)
66  self.assertApprox(exp_eval(R0, w2).full(), R2)
67 
68  J0 = pin.Jexp3(w0)
69  J1 = pin.Jexp3(w1)
70  J2 = pin.Jexp3(w2)
71  J3 = pin.Jexp3(w3)
72  # print(J0)
73  # print(Jexp_eval(R0, np.zeros(3)))
74  # print(J1)
75  # print(Jexp_eval(R0, w1))
76  # print("R1:", R1)
77  # print(Jexp_eval(R1, w1))
78  # print(Jexp_eval(R2, w1))
79  self.assertApprox(Jexp_eval(R0, w0).full(), np.hstack([R0.T, J0]))
80  self.assertApprox(Jexp_eval(R0, w1).full(), np.hstack([R1.T, J1]))
81  self.assertApprox(Jexp_eval(R0, w2).full(), np.hstack([R2.T, J2]))
82  self.assertApprox(Jexp_eval(R0, w3).full(), np.hstack([R3.T, J3]))
83  self.assertApprox(Jexp_eval(R1, w0).full(), np.hstack([R0.T, J0]))
84  self.assertApprox(Jexp_eval(R1, w2).full(), np.hstack([R2.T, J2]))
85 
86  def test_log3(self):
87  log_expr = cpin.log3(self.cR0_i.T @ self.cR1_i)
88  log_eval = casadi.Function(
89  "log",
90  [self.cR0, self.cR1],
91  [casadi.substitute(log_expr, self.v_all, np.zeros(6))],
92  )
93 
94  Jlog_expr = casadi.jacobian(log_expr, self.v_all)
95  Jlog_eval = casadi.Function(
96  "Jlog",
97  [self.cR0, self.cR1],
98  [casadi.substitute(Jlog_expr, self.v_all, np.zeros(6))],
99  )
100 
101  R0 = np.eye(3)
102  vr = np.random.randn(3)
103  R1 = pin.exp3(vr)
104  R2 = pin.exp3(np.array([np.pi, 0, 0]))
105  v3 = np.array([0, np.pi, 0])
106  R3 = pin.exp3(v3)
107 
108  self.assertApprox(log_eval(R0, R0).full().squeeze(), np.zeros(3))
109  self.assertApprox(log_eval(R0, R1).full().squeeze(), vr)
110  self.assertApprox(log_eval(R1, R1).full().squeeze(), np.zeros(3))
111  self.assertApprox(log_eval(R0, R2).full().squeeze(), np.array([np.pi, 0, 0]))
112  self.assertApprox(log_eval(R0, R3).full().squeeze(), v3)
113 
114  J0 = pin.Jlog3(R0)
115  jac_identity = np.hstack([-J0, J0])
116  self.assertApprox(Jlog_eval(R0, R0).full(), jac_identity)
117 
118  J1 = pin.Jlog3(R1)
119  self.assertApprox(Jlog_eval(R0, R1).full(), np.hstack([-R1.T @ J1, J1]))
120 
121  J2 = pin.Jlog3(R2)
122  self.assertApprox(Jlog_eval(R0, R2).full(), np.hstack([-R2.T @ J2, J2]))
123 
124  def test_log3_quat(self):
125  cquat = SX.sym("quat", 4)
126  cdv = SX.sym("dv", 3)
127  SO3 = cpin.liegroups.SO3()
128 
129  def repl_dargs(e):
130  return casadi.substitute(e, cdv, np.zeros(3))
131 
132  cquat_i = SO3.integrate(cquat, cdv)
133 
134  clog = cpin.log3(cquat_i)
135  cJlog = casadi.jacobian(clog, cdv)
136  clog_eval = casadi.Function("log", [cquat], [repl_dargs(clog)])
137  cJlog_eval = casadi.Function("Jlog", [cquat], [repl_dargs(cJlog)])
138 
139  q0 = np.array([0.0, 0.0, 0.0, 1.0])
140  q1 = np.array([0.0, 1.0, 0.0, 0.0])
141  q2 = np.array([0.0, 0.0, 1.0, 0.0])
142  q3 = np.array([1.0, 0.0, 0.0, 0.0])
143 
144  self.assertApprox(clog_eval(q0).full().squeeze(), np.zeros(3))
145  self.assertApprox(cJlog_eval(q0).full().squeeze(), np.eye(3))
146 
147  clog_fun = casadi.dot(clog, clog)
148  cJlog_fun = casadi.jacobian(clog_fun, cdv)
149  clog_fun_eval = casadi.Function("normlog", [cquat], [repl_dargs(clog_fun)])
150  cJlog_fun_eval = casadi.Function("Jnormlog", [cquat], [repl_dargs(cJlog_fun)])
151 
152  self.assertApprox(clog_fun_eval(q0).full().squeeze(), np.zeros(1))
153  self.assertApprox(cJlog_fun_eval(q0).full(), np.zeros(3))
154 
155  self.assertApprox(
156  cJlog_fun_eval(q1).full(), 2 * np.pi * np.array([0.0, 1.0, 0.0])
157  )
158  self.assertApprox(
159  cJlog_fun_eval(q2).full(), 2 * np.pi * np.array([0.0, 0.0, 1.0])
160  )
161  self.assertApprox(
162  cJlog_fun_eval(q3).full(), 2 * np.pi * np.array([1.0, 0.0, 0.0])
163  )
164  print("log3 quat done")
165 
166  def test_exp6(self):
167  exp_expr = cpin.exp6(self.cw2 + self.cdw2)
168 
169  def repl_dargs(e):
170  return casadi.substitute(e, self.cdw2, np.zeros(6))
171 
172  exp_eval = casadi.Function("exp6", [self.cw2], [repl_dargs(exp_expr.np)])
173 
174  diff_expr = cpin.log6(cpin.SE3(exp_eval(self.cw2)).actInv(exp_expr)).np
175  Jexp_expr = casadi.jacobian(diff_expr, self.cdw2)
176 
177  Jexp_eval = casadi.Function("exp6", [self.cw2], [repl_dargs(Jexp_expr)])
178 
179  w0 = np.zeros(6)
180  w1 = np.array([0.0, 0.0, 0.0, np.pi, 0.0, 0.0])
181  w2 = np.random.randn(6)
182  w3 = np.array([0.0, 0.0, 0.0, np.pi / 2, 0.0, 0.0])
183  M0 = pin.exp6(w0)
184  M1 = pin.exp6(w1)
185  M2 = pin.exp6(w2)
186  M3 = pin.exp6(w3)
187  self.assertApprox(exp_eval(w0).full(), M0.np)
188  self.assertApprox(exp_eval(w1).full(), M1.np)
189  self.assertApprox(exp_eval(w2).full(), M2.np)
190  self.assertApprox(exp_eval(w3).full(), M3.np)
191 
192  np.set_printoptions(precision=3)
193  J0 = pin.Jexp6(w0)
194  self.assertApprox(Jexp_eval(w0).full(), J0)
195  J1 = pin.Jexp6(w1)
196  self.assertApprox(Jexp_eval(w1).full(), J1)
197  J2 = pin.Jexp6(w2)
198  self.assertApprox(Jexp_eval(w2).full(), J2)
199 
200  def test_log6(self):
201  log_expr = cpin.log6(self.cM0_i.actInv(self.cM1_i))
202 
203  def repl_dargs(e):
204  return casadi.substitute(
205  e, casadi.vertcat(self.cdw0, self.cdw1), np.zeros(12)
206  )
207 
208  log_eval = casadi.Function(
209  "log6", [self.cM0, self.cM1], [repl_dargs(log_expr.np)]
210  )
211 
212  Jlog_expr = casadi.jacobian(log_expr.np, casadi.vertcat(self.cdw0, self.cdw1))
213  Jlog_eval = casadi.Function(
214  "Jlog6", [self.cM0, self.cM1], [repl_dargs(Jlog_expr)]
215  )
216 
217  w0 = np.zeros(6)
218  M0 = pin.exp6(np.zeros(6))
219  w1 = np.array([0, 0, 0, np.pi, 0.0, 0.0])
220  M1 = pin.exp6(w1)
221  w2 = np.random.randn(6)
222  M2 = pin.exp6(w2)
223 
224  self.assertApprox(log_eval(M0.np, M0.np).full(), w0)
225  self.assertApprox(log_eval(M1.np, M1.np).full(), w0)
226  self.assertApprox(log_eval(M0.np, M1.np).full(), w1)
227  self.assertApprox(log_eval(M0.np, M2.np).full(), w2)
228 
229  J0 = pin.Jlog6(M0)
230  J1 = pin.Jlog6(M1)
231  J2 = pin.Jlog6(M2)
232  self.assertApprox(Jlog_eval(M0.np, M0.np).full(), np.hstack([-J0, J0]))
233  self.assertApprox(
234  Jlog_eval(M0.np, M1.np).full(), np.hstack([-M1.dualAction.T @ J1, J1])
235  )
236  self.assertApprox(
237  Jlog_eval(M0.np, M2.np).full(), np.hstack([-M2.dualAction.T @ J2, J2])
238  )
239 
240  def test_log6_quat(self):
241  cq0 = SX.sym("q0", 7)
242  cv0 = SX.sym("q0", 6)
243 
244  def repl_dargs(e):
245  return casadi.substitute(e, cv0, np.zeros(6))
246 
247  SE3 = cpin.liegroups.SE3()
248 
249  cq0_i = SE3.integrate(cq0, cv0)
250  clog = cpin.log6_quat(cq0_i).vector
251  clog_eval = casadi.Function("log", [cq0], [repl_dargs(clog)])
252 
253  cJlog = casadi.jacobian(clog, cv0)
254  cJlog_eval = casadi.Function("Jlog", [cq0], [repl_dargs(cJlog)])
255 
256  q0 = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0])
257  q1 = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0])
258  q2 = np.array([0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0])
259  q3 = np.array([0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0])
260  self.assertApprox(clog_eval(q0).full().squeeze(), np.zeros(6))
261  self.assertApprox(cJlog_eval(q0).full(), np.eye(6))
262 
263  print("log6 with quats")
264  print(clog_eval(q1).full())
265  print(cJlog_eval(q1).full())
266 
267  clog_fun = casadi.dot(clog, clog)
268  clog_fun = casadi.dot(clog, clog)
269  cJlog_fun = casadi.jacobian(clog_fun, cv0)
270  clog_fun_eval = casadi.Function("normlog", [cq0], [repl_dargs(clog_fun)])
271  cJlog_fun_eval = casadi.Function("Jnormlog", [cq0], [repl_dargs(cJlog_fun)])
272 
273  print(clog_fun_eval(q0).full().squeeze())
274  print(cJlog_fun_eval(q0).full())
275 
276  print(clog_fun_eval(q1).full().squeeze())
277  print(cJlog_fun_eval(q1).full())
278 
279  print(clog_fun_eval(q2).full().squeeze())
280  print(cJlog_fun_eval(q2).full())
281 
282  print(clog_fun_eval(q3).full().squeeze())
283  print(cJlog_fun_eval(q3).full())
284 
285 
286 if __name__ == "__main__":
287  unittest.main()
bindings_explog.TestLogExpDerivatives.cR0
cR0
Definition: bindings_explog.py:17
bindings_explog.TestLogExpDerivatives.cR1
cR1
Definition: bindings_explog.py:18
bindings_explog.TestLogExpDerivatives.test_exp3
def test_exp3(self)
Definition: bindings_explog.py:38
bindings_explog.TestLogExpDerivatives.test_log3
def test_log3(self)
Definition: bindings_explog.py:86
bindings_explog.TestLogExpDerivatives.cM1
cM1
Definition: bindings_explog.py:30
bindings_explog.TestLogExpDerivatives.v_all
v_all
Definition: bindings_explog.py:21
pinocchio.casadi
Definition: bindings/python/pinocchio/casadi/__init__.py:1
bindings_explog.TestLogExpDerivatives.cw2
cw2
Definition: bindings_explog.py:33
bindings_explog.TestLogExpDerivatives.test_log3_quat
def test_log3_quat(self)
Definition: bindings_explog.py:124
bindings_explog.TestLogExpDerivatives.cdv2
cdv2
Definition: bindings_explog.py:23
bindings_explog.TestLogExpDerivatives.cR0_i
cR0_i
Definition: bindings_explog.py:25
bindings_explog.TestLogExpDerivatives.test_exp6
def test_exp6(self)
Definition: bindings_explog.py:166
bindings_explog.TestLogExpDerivatives.setUp
None setUp(self)
Definition: bindings_explog.py:16
bindings_explog.TestLogExpDerivatives.cv2
cv2
Definition: bindings_explog.py:22
bindings_explog.TestLogExpDerivatives.cdw0
cdw0
Definition: bindings_explog.py:31
bindings_explog.TestLogExpDerivatives.cM0
cM0
Definition: bindings_explog.py:29
bindings_explog.TestLogExpDerivatives.dv0
dv0
Definition: bindings_explog.py:19
bindings_explog.TestLogExpDerivatives.cdw1
cdw1
Definition: bindings_explog.py:32
bindings_explog.TestLogExpDerivatives.dv1
dv1
Definition: bindings_explog.py:20
bindings_explog.TestLogExpDerivatives.test_log6
def test_log6(self)
Definition: bindings_explog.py:200
bindings_explog.TestLogExpDerivatives.test_log6_quat
def test_log6_quat(self)
Definition: bindings_explog.py:240
bindings_explog.TestLogExpDerivatives.cM1_i
cM1_i
Definition: bindings_explog.py:36
bindings_explog.TestLogExpDerivatives.cdw2
cdw2
Definition: bindings_explog.py:34
bindings_explog.TestLogExpDerivatives
Definition: bindings_explog.py:15
bindings_explog.TestLogExpDerivatives.cM0_i
cM0_i
Definition: bindings_explog.py:35
bindings_explog.TestLogExpDerivatives.cR1_i
cR1_i
Definition: bindings_explog.py:26


pinocchio
Author(s):
autogenerated on Sun Dec 22 2024 03:41:06