def test_triple_vector_product_raises_error(): # Since vector products are interpretted as dot products, they are # ambiguous, and we disallow them. variables = { 'i': MathArray([1, 0]), 'j': MathArray([0, 1]), } assert equal_as_arrays( evaluator("(i*i)*j", variables)[0], variables['j'] ) match = ("Multiplying three or more vectors is ambiguous. " "Please place parentheses around vector multiplications.") with raises(CalcError, match=match): evaluator("i*i*j", variables)[0] with raises(CalcError, match=match): evaluator("i*2*i*3*j", variables)[0] # Next example should raise an operator shape error, not a triple vec error match='Cannot divide by a vector' with raises(CalcError, match=match): evaluator("i*j/i*i*j", variables)[0]
def test_math_arrays(): A = MathArray([[1, 5], [4, -2]]) v = MathArray([3, -2]) n = 3 x = 4.2 z = 2 + 3j variables = {'A': A, 'v': v, 'n': n, 'x': x, 'z': z} expr = '(z*[[1, 5], [4, -2]]^n + 10*A/x)*v' result = evaluator(expr, variables, max_array_dim=2)[0] assert equal_as_arrays(result, (z * A**n + 10 * A / x) * v)
def test_orthogonal(): # Test shape, orthogonality, determinant, python2 error, MathArray if six.PY2: with raises(NotImplementedError, match='This feature requires newer versions of ' 'numpy and scipy than are available.'): matrices = OrthogonalMatrices(unitdet=False) matrices.gen_sample() with raises(NotImplementedError, match='This feature requires newer versions of ' 'numpy and scipy than are available.'): matrices = OrthogonalMatrices(unitdet=True) matrices.gen_sample() else: # These are the doctests matrices = OrthogonalMatrices() assert matrices.gen_sample().shape == (2, 2) matrices = OrthogonalMatrices(dimension=4) assert matrices.gen_sample().shape == (4, 4) matrices = OrthogonalMatrices(unitdet=True) assert within_tolerance(np.linalg.det(matrices.gen_sample()), 1, 1e-14) matrices = OrthogonalMatrices(unitdet=False) m = matrices.gen_sample() assert (within_tolerance(np.linalg.det(m), 1, 1e-14) or within_tolerance(np.linalg.det(m), -1, 1e-14)) matrices = OrthogonalMatrices(unitdet=True) m = matrices.gen_sample() assert within_tolerance(m * np.conjugate(np.transpose(m)), MathArray(np.eye(2)), 1e-14) matrices = OrthogonalMatrices(unitdet=False) m = matrices.gen_sample() assert within_tolerance(m * np.conjugate(np.transpose(m)), MathArray(np.eye(2)), 1e-14) shapes = tuple(range(2, 5)) dets = (True, False) # More general testing for shape in shapes: for det in dets: matrices = matrices = OrthogonalMatrices(dimension=shape, unitdet=det) m = matrices.gen_sample() assert m.shape == (shape, shape) assert np.array_equal(np.conj(m), m) assert within_tolerance(m * np.transpose(m), MathArray(np.eye(shape)), 1e-14) assert (approx(np.abs(np.linalg.det(m)), 1) or approx(np.abs(np.linalg.det(m)), -1)) if det: assert approx(np.linalg.det(m), 1) assert isinstance(m, MathArray)
def test_array_input(): """Test that vectors/matrices can be inputted into calc's evaluator""" result = evaluator("[1, 2, 3]", {}, {}, {}, max_array_dim=1)[0] assert equal_as_arrays(result, MathArray([1, 2, 3])) result = evaluator("[[1, 2], [3, 4]]", {}, {}, {}, max_array_dim=2)[0] assert equal_as_arrays(result, MathArray([[1, 2], [3, 4]])) expr = '[v, [4, 5, 6]]' result = evaluator(expr, {'v': MathArray([1, 2, 3])}, max_array_dim=2)[0] assert equal_as_arrays(result, MathArray([[1, 2, 3], [4, 5, 6]])) msg = "Vector and matrix expressions have been forbidden in this entry." with raises(UnableToParse, match=msg): evaluator("[[1, 2], [3, 4]]", {}, {}, {}, max_array_dim=0) msg = "Matrix expressions have been forbidden in this entry." with raises(UnableToParse, match=msg): evaluator("[[1, 2], [3, 4]]", {}, {}, {}, max_array_dim=1) msg = "Tensor expressions have been forbidden in this entry." with raises(UnableToParse, match=msg): evaluator("[[[1, 2], [3, 4]]]", {}, {}, {}, max_array_dim=2) # By default, this is fine evaluator("[[[1, 2], [3, 4]]]")
def test_matharray_errors_make_it_through(): """ There is some overlap between this test and the tests in test_math_array. Main goal here is to make sure numpy numerics are not introduced during evaluator(...) calls, because np.float64(1.0) + MathArray([1, 2, 3]) does not throw an error. """ v = MathArray([1, 2, 3]) variables = {'v': v} with raises(CalcError, match="Cannot add/subtract"): evaluator('v*v + v', variables) with raises(CalcError, match="Cannot add/subtract"): evaluator('v*v - v', variables) with raises(CalcError, match="Cannot divide"): evaluator('v*v/v', variables)
def test_general_matrices(): # Test shape, real/complex, norm, triangular options, MathArray shapes = product(tuple(range(2, 5)), tuple(range(2, 5))) norms = ([2, 6], [3, 4], [4, 12], [1 - 1e-12, 1 + 1e-12]) triangles = (None, 'upper', 'lower') for shape in shapes: for norm in norms: for triangle in triangles: matrices = RealMatrices(shape=shape, norm=norm, triangular=triangle) m = matrices.gen_sample() assert m.shape == shape assert norm[0] <= np.linalg.norm(m) <= norm[1] assert np.array_equal(np.conj(m), m) assert isinstance(m, MathArray) if triangle is None: assert not within_tolerance(m, MathArray(np.triu(m)), 0) assert not within_tolerance(m, MathArray(np.tril(m)), 0) elif triangle == "upper": assert within_tolerance(m, MathArray(np.triu(m)), 0) elif triangle == "lower": assert within_tolerance(m, MathArray(np.tril(m)), 0) matrices = ComplexMatrices(shape=shape, norm=norm, triangular=triangle) m = matrices.gen_sample() assert m.shape == shape assert norm[0] <= np.linalg.norm(m) <= norm[1] assert not np.array_equal(np.conj(m), m) assert isinstance(m, MathArray) if triangle is None: assert not within_tolerance(m, MathArray(np.triu(m)), 0) assert not within_tolerance(m, MathArray(np.tril(m)), 0) elif triangle == "upper": assert within_tolerance(m, MathArray(np.triu(m)), 0) elif triangle == "lower": assert within_tolerance(m, MathArray(np.tril(m)), 0)