diff --git a/quaternions/__init__.py b/quaternions/__init__.py index fd54ad8..af65e04 100644 --- a/quaternions/__init__.py +++ b/quaternions/__init__.py @@ -1,3 +1,6 @@ from quaternions.quaternion import Quaternion # NOQA from quaternions.general_quaternion import GeneralQuaternion, QuaternionError # NOQA from quaternions.version import __version__ # NOQA + +import warnings +warnings.simplefilter('once') diff --git a/quaternions/quaternion.py b/quaternions/quaternion.py index 5636f22..4f3fc58 100644 --- a/quaternions/quaternion.py +++ b/quaternions/quaternion.py @@ -8,6 +8,8 @@ GeneralQuaternion, QuaternionError, DEFAULT_TOLERANCE, exp ) +import warnings + class Quaternion(GeneralQuaternion): ''' A class that holds unit quaternions (norm==1, aka versors). It actually holds Q^op, as @@ -119,6 +121,7 @@ def average(cls, *quaternions, weights=None): @property def basis(self): + warnings.warn('This property will be deprecated. Use matrix instead', DeprecationWarning) m = self.matrix return m[0, :], m[1, :], m[2, :] @@ -156,6 +159,7 @@ def astrometry_ra_dec_roll(self): Notice that Tetra gives a different roll angle, so this is not a fixed standard. ''' + warnings.warn('This method will be deprecated', DeprecationWarning) twisted = self.OpticalAxisFirst() * self ra, dec, roll = twisted.ra_dec_roll return np.array([-ra, dec, roll - 180]) diff --git a/tests/test_general_quaternion.py b/tests/test_general_quaternion.py index ccbbae5..0939ca0 100644 --- a/tests/test_general_quaternion.py +++ b/tests/test_general_quaternion.py @@ -121,3 +121,7 @@ def test_log_identical_both_ways(self, arr): assume(np.linalg.norm(arr) > DEFAULT_TOLERANCE) q = GeneralQuaternion(*arr) assert log(q) == q.log() + + def test_repr(self): + gen_quat = GeneralQuaternion(1, 2, 3, 4) + assert repr(gen_quat) == 'GeneralQuaternion(1, 2, 3, 4)' diff --git a/tests/test_quaternion.py b/tests/test_quaternion.py index bda2be8..9fd1f17 100644 --- a/tests/test_quaternion.py +++ b/tests/test_quaternion.py @@ -161,11 +161,29 @@ def test_ra_dec_roll(self, arr): def test_qmethod(self): v1, v2 = [2 / 3, 2 / 3, 1 / 3], [2 / 3, -1 / 3, -2 / 3] w1, w2 = [0.8, 0.6, 0], [-0.6, 0.8, 0] - q = Quaternion.from_qmethod(np.array([v1, v2]).T, np.array([w1, w2]).T, np.ones(2)) + q = Quaternion.from_qmethod(np.array([v1, v2]).T, np.array([w1, w2]).T) np.testing.assert_allclose(q(v1), w1, atol=1e-10) np.testing.assert_allclose(q(v2), w2, atol=1e-10) + def test_weights_change_in_qmethod(self): + v1, v2 = [1, 0, 0], [0, 1, 0] + w1, w2 = [1, 0, 0], [-1/2, np.sqrt(3) / 2, 0] + + previous_cos_1 = np.inf + previous_cos_2 = -np.inf + for second_weight in np.linspace(0.1, 2, 10): + q = Quaternion.from_qmethod(np.array([v1, v2]).T, np.array([w1, w2]).T, [1, second_weight]) + current_cos_1 = q(v1).dot(w1) + current_cos_2 = q(v2).dot(w2) + + # since first weight is constant and second weight increases, correlation with + # first vector should go down and correlation with second vector should go up + assert current_cos_1 < previous_cos_1 + assert current_cos_2 > previous_cos_2 + + previous_cos_1, previous_cos_2 = current_cos_1, current_cos_2 + @given(ANY_ROTATION_VECTOR) def test_from_qmethod_with_noise(self, r): assume(np.linalg.norm(r) > Quaternion.tolerance) @@ -253,6 +271,19 @@ def test_apply_wrong_type(self): with pytest.raises(QuaternionError): q({1, 2, 3}) + def test_repr(self): + unit_quat = Quaternion(1, 2, 3, 4) + assert repr(unit_quat).startswith('Quaternion(') + assert eval(repr(unit_quat)) == unit_quat + + @given(strategies.integers(min_value=1, max_value=5)) + def test_integrate(self, number_of_vectors): + vectors = [np.array([0, 0, i / 10]) for i in range(1, number_of_vectors + 1)] + v = Quaternion.integrate_from_velocity_vectors(vectors) + expected = [0, 0, number_of_vectors * (number_of_vectors + 1) / 20] + np.testing.assert_allclose(expected, v) + + class QuaternionStdDevTests(unittest.TestCase): # tolerance is this big because average_and_std_naive gives slightly different results than matlab implementation # this may be due to the way weights are taken into account, as in matlab implementation weights were not being used