def test_up_down(self, rng): # noqa: F811 from clifford.dpga import up, down for i in range(10 if numba.config.DISABLE_JIT else 1000): p = rng.standard_normal(3) dpga_pnt = up(p) pnt_down = down(np.random.rand() * dpga_pnt) np.testing.assert_allclose(pnt_down, p)
def test_up_down(self): from clifford.dpga import up, down rng = np.random.RandomState() # can pass a seed here later for i in range(10 if numba.config.DISABLE_JIT else 1000): p = rng.standard_normal(3) dpga_pnt = up(p) pnt_down = down(np.random.rand() * dpga_pnt) np.testing.assert_allclose(pnt_down, p)
def test_rotate(self): from clifford.dpga import w0, w1, w2, w3, w1s, w2s, w3s from clifford.dpga import up, down rng = np.random.RandomState() # can pass a seed here later for i in range(10 if numba.config.DISABLE_JIT else 100): mvec = rng.standard_normal(3) nvec = rng.standard_normal(3) m = mvec[0] * w1 + mvec[1] * w2 + mvec[2] * w3 n = nvec[0] * w1 + nvec[1] * w2 + nvec[2] * w3 ms = mvec[0] * w1s + mvec[1] * w2s + mvec[2] * w3s ns = nvec[0] * w1s + nvec[1] * w2s + nvec[2] * w3s biv = 2 * ((ms ^ n) - (ns ^ m)) Rt = np.e**(-biv) # Rotor should be unit np.testing.assert_allclose((Rt * ~Rt).value, (1 + 0 * w1).value, atol=1E-4) # The origin should be unaffected by rotation np.testing.assert_allclose((Rt * w0 * ~Rt).value, w0.value, atol=1E-4) # Vectors orthogonal to the rotation should be unaffected by rotation vorthog = np.cross(mvec, nvec) uporthog = up(vorthog) np.testing.assert_allclose((Rt * uporthog * ~Rt).value, uporthog.value, atol=1E-4) # Points should maintain their distance from the origin pnt_vec = rng.standard_normal(3) l = np.linalg.norm(pnt_vec) pnt = up(pnt_vec) lres = np.linalg.norm(down(Rt * pnt * ~Rt)) np.testing.assert_allclose(l, lres, atol=1E-6)
def test_line(self): from clifford.dpga import w0, w1, w2, w3, w0s from clifford.dpga import e12, e13, e23, e1b2b, e1b3b, e2b3b from clifford.dpga import up, down rng = np.random.RandomState() # can pass a seed here later for i in range(5 if numba.config.DISABLE_JIT else 100): p1vec = rng.standard_normal(3) p2vec = rng.standard_normal(3) p1 = up(p1vec) p2 = up(p2vec) line_direc = p2vec - p1vec # Plucker line is the outer product of two points or the outer product # of a point and a free vector line = p1 ^ p2 free_direc = line_direc[0] * w1 + line_direc[1] * w2 + line_direc[ 2] * w3 line_alt = p1 ^ free_direc assert line_alt == line # The line should be the outer product null space lamb = rng.standard_normal() assert up(lamb * p1vec + (1 - lamb) * p2vec) ^ line == 0 # Lines can be transformed with rotors tvec = p1vec wt = tvec[0] * w1 + tvec[1] * w2 + tvec[2] * w3 Raxis = 1 - w0s * wt assert (~Raxis * line * Raxis) ^ w0 == 0 # Lines are invariant to screw transformations about their axis axis = p1vec - p2vec rotation_biv = axis[0] * (e23 - e2b3b) + axis[1] * ( e1b3b - e13) + axis[2] * (e12 - e1b2b) Rr = np.e**(-rng.standard_normal() * rotation_biv) Rt = 1 - w0s * rng.standard_normal() * ( axis[0] * w1 + axis[1] * w2 + axis[2] * w3) np.testing.assert_allclose( (Raxis * Rr * Rt * (~Raxis * line * Raxis) * ~Rt * ~Rr * ~Raxis).value, line.value, rtol=1E-4, atol=1E-4) # A bivector line is invariant under its own exponential Rline = np.e**line assert Rline * line * ~Rline == line # The exponential of a line is a rotation about the line line_origin = (~Raxis * line * Raxis) RLineOrigin = np.e**line_origin random_pnt = up(rng.standard_normal(3)) np.testing.assert_allclose(np.linalg.norm( down(RLineOrigin * random_pnt * ~RLineOrigin)), np.linalg.norm(down(random_pnt)), rtol=1E-3, atol=1E-4) np.testing.assert_allclose( down(RLineOrigin * (random_pnt + free_direc) * ~RLineOrigin), down(RLineOrigin * random_pnt * ~RLineOrigin) + line_direc, rtol=1E-3, atol=1E-4) np.testing.assert_allclose((Rline * ~Rline).value, (1 + 0 * w1).value, rtol=1E-4, atol=1E-4)