def test_grade_obj(self): algebras = [Cl(i) for i in [3, 4]] + [conformalize(Cl(3)[0])] for alg in algebras: layout = alg[0] for i in range(len(layout.sig)+1): mv = layout.randomMV()(i) assert i == grade_obj(mv)
def test_sparse_multiply(self): algebras = [Cl(i) for i in [4]] + [conformalize(Cl(3)[0])] # For all the algebras we are interested in for alg in algebras: layout = alg[0] # Make two random multivectors a = layout.randomMV() b = layout.randomMV() # Project the multivectors to the grades required grades_possibilities = [] for r in range(1, len(layout.sig)): possible_grades = [ list(m) for m in list( itertools.combinations(range(len(layout.sig)), r)) ] grades_possibilities += possible_grades for i, grades_a in enumerate(grades_possibilities): sparse_mv_a = sum([a(k) for k in grades_a]) for j, grades_b in enumerate(grades_possibilities): sparse_mv_b = sum([b(k) for k in grades_b]) # Compute results gp = layout.gmt_func_generator(grades_a=grades_a, grades_b=grades_b) result_sparse = gp(sparse_mv_a.value, sparse_mv_b.value) result_dense = (sparse_mv_a * sparse_mv_b).value # Check they are the same testing.assert_almost_equal(result_sparse, result_dense) print(j + i * len(grades_possibilities), len(grades_possibilities)**2)
class TestBasicAlgebra: def test_gp_op_ip(self): layout = Cl(3)[0] e1 = layout.blades['e1'] e2 = layout.blades['e2'] e3 = layout.blades['e3'] print('outer product') e123 = layout.blades['e123'] np.testing.assert_almost_equal(e123.value, (e1 ^ e2 ^ e3).value) np.testing.assert_almost_equal(e123.value, (e1 * e2 * e3).value) print('outer product ordering') e12 = layout.blades['e12'] np.testing.assert_almost_equal(-e12.value, (e2 ^ e1).value) print('outer product zeros') np.testing.assert_almost_equal(0, (e1 ^ e1).value) np.testing.assert_almost_equal(0, (e2 ^ e2).value) np.testing.assert_almost_equal(0, (e3 ^ e3).value) print('scalar outer product') np.testing.assert_almost_equal(((1 + 0 * e1) ^ (1 + 0 * e1)).value, (1 + 0 * e1).value) print('scalar inner product') np.testing.assert_almost_equal(((1 + 0 * e1) | (1 + 0 * e1)).value, 0) @pytest.fixture(params=[Cl(i) for i in [3, 4]] + [conformalize(Cl(3)[0])], ids=['Cl(3)', 'Cl(4)', 'conformal Cl(3)']) def algebra(self, request): return request.param def test_grade_obj(self, algebra): layout = algebra[0] for i in range(len(layout.sig) + 1): mv = layout.randomMV()(i) assert i == grade_obj(mv) def test_left_multiplication_matrix(self, algebra): layout = algebra[0] for i in range(1000): mv = layout.randomMV() mv2 = layout.randomMV() np.testing.assert_almost_equal( np.matmul(layout.get_left_gmt_matrix(mv), mv2.value), (mv * mv2).value) def test_right_multiplication_matrix(self, algebra): layout = algebra[0] for i in range(1000): a = layout.randomMV() b = layout.randomMV() b_right = val_get_right_gmt_matrix(b.value, layout.k_list, layout.l_list, layout.m_list, layout.mult_table_vals, layout.gaDims) res = a * b res2 = layout.MultiVector(value=b_right @ a.value) np.testing.assert_almost_equal(res.value, res2.value)
def test_left_multiplication_matrix(self): algebras = [Cl(i) for i in [3, 4]] + [conformalize(Cl(3)[0])] for alg in algebras: layout = alg[0] for i in range(1000): mv = layout.randomMV() mv2 = layout.randomMV() np.testing.assert_almost_equal(np.matmul(layout.get_left_gmt_matrix(mv),mv2.value), (mv*mv2).value)
def test_initialise(self): # Dirac Algebra `D` D, D_blades = Cl(1, 3, names='d', firstIdx=0) # Pauli Algebra `P` P, P_blades = Cl(3, names='p') # put elements of each in namespace locals().update(D_blades) locals().update(P_blades)
def test_right_multiplication_matrix(self): algebras = [Cl(i) for i in [3, 4]] + [conformalize(Cl(3)[0])] for alg in algebras: layout = alg[0] for i in range(1000): a = layout.randomMV() b = layout.randomMV() b_right = val_get_right_gmt_matrix(b.value, layout.k_list, layout.l_list, layout.m_list, layout.mult_table_vals, layout.gaDims) res = a*b res2 = layout.MultiVector([email protected]) testing.assert_almost_equal(res.value, res2.value)
def test_layout_comparison_operators(self): l3a, _ = Cl(3) l3b, _ = Cl(3) l4, _ = Cl(4) assert operator.eq(l3a, l3b) is True assert operator.eq(l3a, l4) is False assert operator.eq(l3a, None) is False assert operator.ne(l3a, l3b) is False assert operator.ne(l3a, l4) is True assert operator.ne(l3a, None) is True
class TestInitialisation: @pytest.mark.parametrize( "n", [x for x in range(2, 7)] + [pytest.param(x, marks=too_slow_without_jit) for x in range(7, 9)]) def test_speed(self, n, benchmark): def generate_algebra(): layout = Cl(n)[0] layout.gmt_func layout.imt_func layout.omt_func layout.lcmt_func layout.adjoint_func layout.left_complement_func layout.right_complement_func layout.dual_func layout.vee_func layout.inv_func benchmark(generate_algebra) @too_slow_without_jit @pytest.mark.veryslow @pytest.mark.parametrize('algebra', [Cl(i) for i in [4]] + [conformalize(Cl(3)[0])], ids=['Cl(4)', 'conformalize(Cl(3))']) def test_sparse_multiply(self, algebra, rng): # noqa: F811 layout = algebra[0] # Make two random multivectors a = layout.randomMV(rng=rng) b = layout.randomMV(rng=rng) # Choose the grades we care about. # We skip the cases of: # - all grades # - no grades # - any multiplications including the pseudoscalar grades_possibilities = list(_powerset(range(layout.dims)))[1:-1] for i, grades_a in enumerate(grades_possibilities): sparse_mv_a = sum([a(k) for k in grades_a], layout.MultiVector()) for j, grades_b in enumerate(grades_possibilities): sparse_mv_b = sum([b(k) for k in grades_b], layout.MultiVector()) # Compute results gp = layout.gmt_func_generator(grades_a=grades_a, grades_b=grades_b) result_sparse = gp(sparse_mv_a.value, sparse_mv_b.value) result_dense = (sparse_mv_a * sparse_mv_b).value # Check they are the same np.testing.assert_almost_equal(result_sparse, result_dense) print(j + i * len(grades_possibilities), len(grades_possibilities)**2)
def test_exp_g4(self): ''' a numerical test for the exponential of a bivector. truth was generated by results of clifford v0.82 ''' layout, blades = Cl(4) valB = np.array([ -0. , 0. , # noqa 0. , -0. , # noqa -0. , -1.9546896043012914 , # noqa 0.7069828848351363 , -0.22839793693302957, # noqa 1.0226966962560002 , 1.8673816483342143 , # noqa -1.7694566455296474 , -0. , # noqa -0. , 0. , # noqa -0. , -0. # noqa ]) valexpB = np.array([ -0.8154675764311629 , 0. , # noqa 0. , 0. , # noqa 0. , 0.3393508714682218 , # noqa 0.22959588097548828 , -0.1331099867581965 , # noqa -0.01536404898029994 , 0.012688721722814184, # noqa 0.35678394795928464 , 0. , # noqa 0. , 0. , # noqa 0. , -0.14740840378445502 # noqa ]) B = MultiVector(layout=layout, value=valB) expB = MultiVector(layout=layout, value=valexpB) np.testing.assert_almost_equal(np.exp(B)[0].value, expB.value)
def test_inv_g4(self): ''' a numerical test for the inverse of a MV. truth was generated by results of clifford v0.82 ''' layout, blades = Cl(4) valA = np.array([ -0.3184271488037198 , -0.8751064635010213 , # noqa -1.5011710376191947 , 1.7946332649746224 , # noqa -0.8899576254164621 , -0.3297631748225678 , # noqa 0.04310366054166925, 1.3970365638677635 , # noqa -1.545423393858595 , 1.7790215501876614 , # noqa 0.4785341530609175 , -1.32279679741638 , # noqa 0.5874769077573831 , -1.0227287710873676 , # noqa 1.779673249468527 , -1.5415648119743852 # noqa ]) valAinv = np.array([ 0.06673424072253006 , -0.005709960252678998, # noqa -0.10758540037163118 , 0.1805895938775471 , # noqa 0.13919236400967427 , 0.04123255613093294 , # noqa -0.015395162562329407, -0.1388977308136247 , # noqa -0.1462160646855434 , -0.1183453106997158 , # noqa -0.06961956152268277 , 0.1396713851886765 , # noqa -0.02572904638749348 , 0.02079613649197489 , # noqa -0.06933660606043765 , -0.05436077710009021 # noqa ]) A = MultiVector(layout=layout, value=valA) Ainv = MultiVector(layout=layout, value=valAinv) np.testing.assert_almost_equal(A.inv().value, Ainv.value)
def test_innermorphic(self, p, q): layout, blades = Cl(p, q) A = Frame(layout.randomV(p + q)) R = layout.randomRotor() B = Frame([R * a * ~R for a in A]) assert A.is_innermorphic_to(B)
def test_gp_op_ip(self): layout = Cl(3)[0] e1 = layout.blades['e1'] e2 = layout.blades['e2'] e3 = layout.blades['e3'] print('outer product') e123 = layout.blades['e123'] np.testing.assert_almost_equal(e123.value, (e1 ^ e2 ^ e3).value) np.testing.assert_almost_equal(e123.value, (e1 * e2 * e3).value) print('outer product ordering') e12 = layout.blades['e12'] np.testing.assert_almost_equal(-e12.value, (e2 ^ e1).value) print('outer product zeros') np.testing.assert_almost_equal(0, (e1 ^ e1).value) np.testing.assert_almost_equal(0, (e2 ^ e2).value) np.testing.assert_almost_equal(0, (e3 ^ e3).value) print('scalar outer product') np.testing.assert_almost_equal(((1 + 0 * e1) ^ (1 + 0 * e1)).value, (1 + 0 * e1).value) print('scalar inner product') np.testing.assert_almost_equal(((1 + 0 * e1) | (1 + 0 * e1)).value, 0)
def test_categorization(self): layout = Cl(3)[0] e1 = layout.blades['e1'] e2 = layout.blades['e2'] e3 = layout.blades['e3'] blades = [ layout.scalar, e1, e1 ^ e2, (e1 + e2) ^ e2, ] for b in blades: # all invertible blades are also versors assert b.isBlade() assert b.isVersor() versors = [ 1 + (e1 ^ e2), e1 + (e1 ^ e2 ^ e3), ] for v in versors: assert not v.isBlade() assert v.isVersor() neither = [layout.scalar * 0, 1 + e1, 1 + (e1 ^ e2 ^ e3)] for n in neither: assert not n.isBlade() assert not n.isVersor()
def test_exp(self): layout, blades = Cl(3) e12 = blades['e12'] theta = np.linspace(0, 100 * np.pi, 101) a_list = [np.e**(t * e12) for t in theta] for a in a_list: np.testing.assert_almost_equal(abs(a), 1.0, 5)
def test_binary_op_preserves_dtype(self, dtype, func): """ test that simple binary ops on blades do not promote types """ layout, blades = Cl(3) e1 = blades['e1'].astype(dtype) e2 = blades['e2'].astype(dtype) assert func(e1, np.int8(1)).value.dtype == dtype assert func(e1, e2).value.dtype == dtype
def test_add_preserves_dtype(self): """ test that adding blades does not promote types """ layout, blades = Cl(3) e1 = blades['e1'] e2 = blades['e2'] assert (e1 + 1).value.dtype == e1.value.dtype assert (e1 + e2).value.dtype == e1.value.dtype
def test_speed(self): algebras = range(2, 9) print() # So that the first number is on a new line for i in algebras: t_start = time.time() Cl(i) t_end = time.time() print(i, t_end - t_start)
def testframe2Mat(self): for N in [2, 3, 4]: l, b = Cl(N) X = np.random.rand((N**2)).reshape(N, N) I = l.pseudoScalar B, I = tools.mat2Frame(X, I=I) X_, I = tools.frame2Mat(B=B, I=I) testing.assert_almost_equal(X, X_)
def test_innermorphic(self): for p, q in [(2, 0), (3, 0), (4, 0)]: layout, blades = Cl(p, q) A = Frame(layout.randomV(p + q)) R = layout.randomRotor() B = Frame([R * a * ~R for a in A]) self.assertTrue(A.is_innermorphic_to(B))
def test_indexing(self): layout, blades = Cl(3) e12 = blades['e12'] e1 = blades['e1'] e2 = blades['e2'] e3 = blades['e3'] assert e12[e12] == 1 assert e12[e3] == 0 assert e12[(2, 1)] == -1
def test_blades_of_grade(self): layout = Cl(3)[0] e1 = layout.blades['e1'] e2 = layout.blades['e2'] e3 = layout.blades['e3'] assert layout.blades_of_grade(0) == [layout.scalar] assert layout.blades_of_grade(1) == [e1, e2, e3] assert layout.blades_of_grade(2) == [e1 ^ e2, e1 ^ e3, e2 ^ e3] assert layout.blades_of_grade(3) == [e1 ^ e2 ^ e3]
def test_add_float64(self): ''' test array_wrap method to take control addition from numpy array ''' layout, blades = Cl(3) e1 = blades['e1'] np.float64(1) + e1 assert 1 + e1 == np.float64(1) + e1 assert 1 + e1 == e1 + np.float64(1)
def test_mv_str(self): """ Test the __str__ magic method """ layout, blades = Cl(3) e1 = blades['e1'] e2 = blades['e2'] e12 = blades['e12'] assert str(e1) == "(1^e1)" assert str(1 + e1) == "1 + (1^e1)" assert str(-e1) == "-(1^e1)" assert str(1 - e1) == "1 - (1^e1)"
def test_gp_op_ip(self): layout = Cl(3)[0] e1 = layout.blades['e1'] e2 = layout.blades['e2'] e3 = layout.blades['e3'] e123 = layout.blades['e123'] np.testing.assert_almost_equal(e123.value, (e1 ^ e2 ^ e3).value) np.testing.assert_almost_equal(e123.value, (e1 * e2 * e3).value) e12 = layout.blades['e12'] np.testing.assert_almost_equal(-e12.value, (e2 ^ e1).value)
def test_layout_comparison_operators(self, g3, g4): l3a = g3 l3b, _ = Cl(3) # need a new copy here l4 = g4 assert operator.eq(l3a, l3b) is True assert operator.eq(l3a, l4) is False assert operator.eq(l3a, None) is False assert operator.ne(l3a, l3b) is False assert operator.ne(l3a, l4) is True assert operator.ne(l3a, None) is True
def generate_algebra(): layout = Cl(n)[0] layout.gmt_func layout.imt_func layout.omt_func layout.lcmt_func layout.adjoint_func layout.left_complement_func layout.right_complement_func layout.dual_func layout.vee_func layout.inv_func
def test_metric(self): layout = Cl(4, 1)[0] e1 = layout.blades['e1'] e2 = layout.blades['e2'] e3 = layout.blades['e3'] e4 = layout.blades['e4'] e5 = layout.blades['e5'] self.assertAlmostEqual((e1 * e1)[0], 1) self.assertAlmostEqual((e2 * e2)[0], 1) self.assertAlmostEqual((e3 * e3)[0], 1) self.assertAlmostEqual((e4 * e4)[0], 1) self.assertAlmostEqual((e5 * e5)[0], -1)
class TestInitialisation: def test_speed(self): algebras = range(2, 9) print() # So that the first number is on a new line for i in algebras: t_start = time.time() Cl(i) t_end = time.time() print(i, t_end - t_start) @pytest.mark.parametrize('algebra', [Cl(i) for i in [4]] + [conformalize(Cl(3)[0])], ids=['Cl(4)', 'conformalize(Cl(3))']) def test_sparse_multiply(self, algebra): layout = algebra[0] # Make two random multivectors a = layout.randomMV() b = layout.randomMV() # Project the multivectors to the grades required grades_possibilities = [] for r in range(1, len(layout.sig)): possible_grades = [ list(m) for m in list( itertools.combinations(range(len(layout.sig)), r)) ] grades_possibilities += possible_grades for i, grades_a in enumerate(grades_possibilities): sparse_mv_a = sum([a(k) for k in grades_a]) for j, grades_b in enumerate(grades_possibilities): sparse_mv_b = sum([b(k) for k in grades_b]) # Compute results gp = layout.gmt_func_generator(grades_a=grades_a, grades_b=grades_b) result_sparse = gp(sparse_mv_a.value, sparse_mv_b.value) result_dense = (sparse_mv_a * sparse_mv_b).value # Check they are the same np.testing.assert_almost_equal(result_sparse, result_dense) print(j + i * len(grades_possibilities), len(grades_possibilities)**2)
def test_metric(self): layout = Cl(4, 1)[0] e1 = layout.blades['e1'] e2 = layout.blades['e2'] e3 = layout.blades['e3'] e4 = layout.blades['e4'] e5 = layout.blades['e5'] assert (e1 * e1)[0] == 1 assert (e2 * e2)[0] == 1 assert (e3 * e3)[0] == 1 assert (e4 * e4)[0] == 1 assert (e5 * e5)[0] == -1
def test_mv_str(self): """ Test the __str__ magic method """ layout, blades = Cl(3) e1 = blades['e1'] e2 = blades['e2'] e12 = blades['e12'] assert str(e1) == "(1^e1)" assert str(1 + e1) == "1 + (1^e1)" assert str(-e1) == "-(1^e1)" assert str(1 - e1) == "1 - (1^e1)" mv = layout.scalar * 1.0 mv[(1,)] = float('nan') mv[(1, 2)] = float('nan') assert str(mv) == "1.0 + (nan^e1) + (nan^e12)"