def test_to_euler(self): """mtx -> euler -> mtx""" data = random_rotations(13, dtype=torch.float64) for convention in self._all_euler_angle_conventions(): euler_angles = matrix_to_euler_angles(data, convention) mdata = euler_angles_to_matrix(euler_angles, convention) self.assertTrue(torch.allclose(data, mdata))
def test_euler_grad_exists(self): """Euler angle calculations are differentiable.""" rotation = random_rotation(dtype=torch.float64, requires_grad=True) for convention in self._all_euler_angle_conventions(): euler_angles = matrix_to_euler_angles(rotation, convention) mdata = euler_angles_to_matrix(euler_angles, convention) [g] = torch.autograd.grad(mdata.sum(), rotation) self.assertTrue(torch.isfinite(g).all())
def test_from_euler(self): """euler -> mtx -> euler""" n_repetitions = 10 # tolerance is how much we keep the middle angle away from the extreme # allowed values which make the calculation unstable (Gimbal lock). tolerance = 0.04 half_pi = math.pi / 2 data = torch.zeros(n_repetitions, 3) data.uniform_(-math.pi, math.pi) data[:, 1].uniform_(-half_pi + tolerance, half_pi - tolerance) for convention in self._tait_bryan_conventions(): matrices = euler_angles_to_matrix(data, convention) mdata = matrix_to_euler_angles(matrices, convention) self.assertTrue(torch.allclose(data, mdata)) data[:, 1] += half_pi for convention in self._proper_euler_conventions(): matrices = euler_angles_to_matrix(data, convention) mdata = matrix_to_euler_angles(matrices, convention) self.assertTrue(torch.allclose(data, mdata))