def test_vector_mul_vector(self): vec1 = Vector(data=[1, 3, -5]) vec2 = Vector(data=[4, -2, -1]) vec_dot = vec1 * vec2 self.assertEqual(vec_dot, 3.0)
def test_area_of_parallelogram_with(self): v7 = Vector([8.462, 7.893, -8.187]) v8 = Vector([6.984, -5.975, 4.778]) magnitude_of_cross_product = Decimal("144.300032696633225246124302074") self.assertEqual( v7.area_of_parallelogram_with(v8), magnitude_of_cross_product, "incorrect area of parallelogram", )
def test_vector_add(self): vec1 = Vector(data=[2, -4, 7], dtype=np.int32) vec2 = Vector(data=[5, 3, 0]) vec_add = vec1 + vec2 self.assertIsInstance(vec_add, Vector) self.assertEqual(vec_add.dtype, 'int32') self.assertTrue(np.array_equal(vec_add.data, np.array([7, -1, 7])))
def test_vector_sub(self): vec1 = Vector(data=[2, -4, 7], dtype=np.int32) vec2 = Vector(data=[5, 3, 0]) vec_sub = vec1 - vec2 self.assertIsInstance(vec_sub, Vector) self.assertEqual(vec_sub.dtype, 'int32') self.assertTrue(np.array_equal(vec_sub.data, np.array([-3, -7, 7])))
def test_area_of_triangle_with(self): v7 = Vector([8.462, 7.893, -8.187]) v8 = Vector([6.984, -5.975, 4.778]) area_of_triangle = Decimal( "144.300032696633225246124302074") / Decimal("2.0") self.assertEqual( v7.area_of_triangle_with(v8), area_of_triangle, "incorrect area of triangle", )
def test_is_parallel_to(self): self.assertEqual( self.v1.is_parallel_to(self.v2), False, "incorrect, these vectors are NOT parallel to eaach other", ) v5 = Vector([-7.579, -7.88]) # parallel to v6 v6 = Vector([22.737, 23.64]) self.assertEqual( v5.is_parallel_to(v6), True, "incorrect, these vectors are parallel to each other", )
def test_is_orthogonal_to(self): self.assertEqual( self.v1.is_orthogonal_to(self.v2), False, "incorrect, these vectors are not orthogonal to each other", ) v3 = Vector([-2.328, -7.284, -1.214]) # orthogonal to v4 v4 = Vector([-1.821, 1.072, -2.94]) self.assertEqual( v3.is_orthogonal_to(v4), True, "incorrect result, these vectors are orthogonal to each other", )
def test_vector_initialize_zero_vector_dtype_int(self): vec = Vector(dtype=np.int32) self.assertIsInstance(vec, Vector) self.assertEqual(vec.size, 2) self.assertEqual(vec.dtype, 'int32') self.assertTrue(np.array_equal(vec.data, np.array([0, 0])))
def test_vector_initialize_zero_vector_default(self): vec = Vector() self.assertIsInstance(vec, Vector) self.assertEqual(vec.size, 2) self.assertEqual(vec.dtype, 'float32') self.assertTrue(np.array_equal(vec.data, np.array([0.0, 0.0])))
def test_vector_len(self): vec = Vector(data=[1, 2, 3]) expected_len = 3 actual_len = len(vec) self.assertEqual(actual_len, expected_len)
def test_vector_initialize_zero_vector_custom_size(self): expected_size = 4 vec = Vector(size=expected_size) self.assertIsInstance(vec, Vector) self.assertEqual(vec.size, expected_size) self.assertEqual(vec.dtype, 'float32') self.assertTrue(np.array_equal(vec.data, np.zeros(expected_size)))
def test_vector_initialize_list_data(self): data = [1, 2, 3, 4] vec = Vector(data=data) self.assertIsInstance(vec, Vector) self.assertEqual(vec.size, 4) self.assertEqual(vec.dtype, 'float32') self.assertTrue(np.array_equal(vec.data, np.array(data)))
def test_vector_initialize_list_data_dtype_int(self): data = [1, 2, 3] vec = Vector(data=data, dtype=np.int32) self.assertIsInstance(vec, Vector) self.assertEqual(vec.size, 3) self.assertEqual(vec.dtype, 'int32') self.assertTrue(np.array_equal(vec.data, np.array(data)))
def test_matrix_mul_vector_invalid(self): m_data = [[1, 2, 3], [4, 5, 6]] v_data = [1, 2] m = Matrix(data=m_data, dtype=np.int32) v = Vector(data=v_data, dtype=np.int32) with self.assertRaises(ValueError): mv_prod = m * v
def test_vector_rmul(self): vec = Vector(data=[1, 2, 3, 4], dtype=np.int32) expected_data = [2, 4, 6, 8] scalar = 2 scaled_vec = scalar * vec self.assertIsInstance(scaled_vec, Vector) self.assertTrue( np.array_equal(scaled_vec.data, np.array(expected_data)))
def test_identity_vector_orthogonality_and_parallelism(self): """ The zero vector is the only vector that is both orthogonal and parallel to itself. """ v = Vector([0, 0, 0]) self.assertTrue(v.is_orthogonal(v)) self.assertTrue(v.is_parallel(v)) w = Vector([4, 5, 6]) self.assertFalse(w.is_orthogonal(w)) self.assertTrue(w.is_parallel(w))
def test_vector_mul_float(self): vec = Vector(data=[1, 2, 3]) scalar = 2.5 new_vec = vec * scalar self.assertIsInstance(new_vec, Vector) self.assertEqual(new_vec.size, 3) self.assertEqual(new_vec.dtype, 'float32') self.assertTrue(np.array_equal(new_vec.data, np.array([2.5, 5.0, 7.5])))
def test_matrix_mul_vector_2(self): m_data = [[0.8, 0.6, 0.4], [0.2, 0.4, 0.6]] v_data = [60, 50, 30] expected_data = [90, 50] matrix = Matrix(data=m_data) vector = Vector(data=v_data, dtype=np.int32) mv_prod = matrix * vector self.assertIsInstance(mv_prod, Vector) self.assertEqual(mv_prod.dtype, 'float32') self.assertEqual(mv_prod.size, 2) self.assertTrue(np.array_equal(mv_prod.data, np.array(expected_data)))
def test_dot_product_association(self): """ The dot product is associative, meaning it shouldn't matter what order the vectors go in. """ v = Vector([7, 4]) w = Vector([-8, 6.776]) self.assertEqual(v.dot(w), w.dot(v))
def test_matrix_mul_vector_1(self): m_data = [[1, 2], [3, 4], [5, 6]] v_data = [7, 8] expected_data = [23, 53, 83] matrix = Matrix(data=m_data, dtype=np.int32) vector = Vector(data=v_data, dtype=np.int32) mv_prod = matrix * vector self.assertIsInstance(mv_prod, Vector) self.assertEqual(mv_prod.dtype, 'int32') self.assertEqual(mv_prod.size, 3) self.assertTrue(np.array_equal(mv_prod.data, np.array(expected_data))) self.assertTrue(np.array_equal(matrix.data, np.array(m_data))) self.assertTrue(np.array_equal(vector.data, np.array(v_data)))
def __mul__( self, other: Union[Matrix, Vector, int, float]) -> Union[Matrix, Vector]: """Performs: - Matrix-Matrix multiplication if other is a matrix - Matrix-vector multiplication if other is a vector - Scales self by other if other is an int or a float Returns: - A matrix if other is a matrix - A vector of other is a vector - The scaled matrix if other is an int or a float """ if type(other) is Matrix and self.shape[1] != other.shape[0]: raise ValueError( (f"Cannot multiply a {self.shape[0]}x{self.shape[1]} matrix" f" and a {other.shape[0]}x{other.shape[1]} matrix")) elif type(other) is Vector and self.shape[1] != other.size: raise ValueError( ("Cannot perform matrix-vector multiplication on a " f"{self.shape[0]}x{self.shape[1]} matrix and a " f"{other.size}x1 vector")) if type(other) is Matrix: mul_data = self.data @ other.data return Matrix(data=mul_data, dtype=self.dtype) if type(other) is Vector: sum_data = np.zeros(self.shape[0]) temp_matrix = Matrix(data=self.data, dtype=self.dtype) for i, scalar in enumerate(other.data): temp_matrix.data[:, i] *= scalar for i, row in enumerate(temp_matrix.data): sum_data[i] = np.sum(temp_matrix.data[i]) return Vector(data=sum_data, dtype=self.dtype) scaled_data = self.data * other return Matrix(data=scaled_data, dtype=self.dtype)
def test_cross(self): # Test case with 2D-vector when 3D-vectors is expected cross_product1 = ( Decimal("-0E-51"), Decimal("0E-51"), Decimal("6.8022090000000024155504263490"), ) self.assertEqual( self.v1.cross(self.v2).coordinates, cross_product1, "incorrect crossvector") # Normal case with 3D-vectors cross_product2 = ( Decimal("-11.2045709999999977337168388658"), Decimal("-97.6094439999999908463337305875"), Decimal("-105.685161999999993914045148813"), ) v7 = Vector([8.462, 7.893, -8.187]) v8 = Vector([6.984, -5.975, 4.778]) self.assertEqual( v7.cross(v8).coordinates, cross_product2, "incorrect cross vector") # Catch an expected error message if vector is 1D or > 3D v9 = Vector([1]) with self.assertRaises(Exception): v9.cross(v9)
from linalg.vector import Vector # 1. addition v1 = Vector(8.218, -9.341) v2 = Vector(-1.129, 2.111) print(v1, "+", v2, "=", v1 + v2) # 2. subtraction v1 = Vector(7.119, 8.215) v2 = Vector(-8.223, 0.878) print(v1, "-", v2, "=", v1 - v2) # 3. scalar multiplication v = Vector(1.671, -1.012, -0.318) x = 7.41 print("{}{}".format(x,v), "=", x * v)
# Dot product and angle between vectors import math from linalg.vector import Vector # Dot product v1 = Vector(7.887, 4.138) v2 = Vector(-8.802, 6.776) print(v1, "dot", v2, "=", v1 * v2) v1 = Vector(-5.955, -4.904, -1.874) v2 = Vector(-4.496, -8.755, 7.103) print(v1, "dot", v2, "=", v1 * v2) # Angles v1 = Vector(3.183, -7.627) v2 = Vector(-2.668, 5.319) print("Angle between", v1, "and", v2, "=", v1.angle(v2), "rad") v1 = Vector(7.35, 0.221, 5.188) v2 = Vector(2.751, 8.259, 3.985) print("Angle between", v1, "and", v2, "=", v1.angle(v2, degrees=True), "deg")
# Example of the linear system usage from linalg.plane import Plane from linalg.vector import Vector from linalg.mydecimal import MyDecimal from linalg.linsys import LinearSystem p0 = Plane(normal_vector=Vector(*['1', '1', '1']), constant_term='1') p1 = Plane(normal_vector=Vector(*['0', '1', '0']), constant_term='2') p2 = Plane(normal_vector=Vector(*['1', '1', '-1']), constant_term='3') p3 = Plane(normal_vector=Vector(*['1', '0', '-2']), constant_term='2') s = LinearSystem([p0, p1, p2, p3]) print(s.indices_of_first_nonzero_terms_in_each_row()) print('{},{},{},{}'.format(s[0], s[1], s[2], s[3])) print(len(s)) print(s) s[0] = p1 print(s) print(MyDecimal('1e-9').is_near_zero()) print(MyDecimal('1e-11').is_near_zero()) print("== Row operations ==") s2 = LinearSystem([ Plane(Vector(1, 0, 1), 2), Plane(Vector(2, 4, 1), 3), Plane(Vector(3, 4, 10, 2)) ])
def test_vector_sub_invalid(self): vec1 = Vector(data=[1, 2, 3, 4]) vec2 = Vector(data=[5, 1, 6, 2, 5, 2]) with self.assertRaises(ValueError): vec_sub = vec1 - vec2
def test_vector_add_invalid(self): vec1 = Vector(data=[4, 1, 5]) vec2 = Vector(data=[-4, 9]) with self.assertRaises(ValueError): vec_add = vec1 + vec2
def test_vector_shape_required(self): data = [[1, 2, 3], [4, 5, 6]] with self.assertRaises(ValueError): vec = Vector(data=data)
def test_vector_too_high_index(self): vec = Vector(data=[1, 2, 3], dtype=np.int32) with self.assertRaises(IndexError): idx = vec[3]
def test_vector_iter(self): data = [1, 2, 3, 4, 5] vec = Vector(data=data, dtype=np.int32) for i, item in enumerate(data): self.assertEqual(vec[i], item)