Skip to content

Instantly share code, notes, and snippets.

@agrif
Created January 13, 2014 23:49
Show Gist options
  • Select an option

  • Save agrif/8410290 to your computer and use it in GitHub Desktop.

Select an option

Save agrif/8410290 to your computer and use it in GitHub Desktop.
demo vector implementation with quickcheck tests
import math
class Vector:
"""A test vector class, with dot products, cross products,
addition, and scalar multiplication.
"""
def __init__(self, x, y, z):
self.val = (x, y, z)
def __repr__(self):
return "<Vector: {}>".format(self.val)
def __add__(self, other):
if not isinstance(other, Vector):
raise TypeError("cannot add vector to non-vector")
return Vector(*(a + b for a, b in zip(self.val, other.val)))
def __neg__(self):
return Vector(*(-a for a in self.val))
def __mul__(self, other):
if isinstance(other, Vector):
return sum(a * b for a, b in zip(self.val, other.val))
return Vector(*(a * other for a in self.val))
def __rmul__(self, other):
return self.__mul__(other)
def __eq__(self, other, eps=0.0001):
if not isinstance(other, Vector):
raise TypeError("cannot compare vector to non-vector")
try:
return all(abs(math.log(abs(a/b))) <= eps for a, b in zip(self.val, other.val))
except ZeroDivisionError:
return all(abs(a - b) <= eps for a, b in zip(self.val, other.val))
def magnitude(self):
return sum(a**2 for a in self.val)
def cross(self, other):
if not isinstance(other, Vector):
raise TypeError("cannot cross vector with non-vector")
a = self.val
b = other.val
res = (
a[1] * b[2] - a[2] * b[1],
a[2] * b[0] - a[0] * b[2],
a[0] * b[1] - a[1] * b[0]
)
return Vector(*res)
# a zero vector
Vector.zero = Vector(0, 0, 0)
##
## Tests
##
import quickcheck as qc
import unittest
@qc.arbitrary.register(Vector)
def arbitrary_vector(_):
"""returns a random vector"""
return Vector(*(qc.arbitrary(float) for _ in range(3)))
@qc.simplify.register(Vector)
def simplify_vector(v):
"""simplifies a vector"""
for s in qc.simplify(v.val):
yield Vector(*s)
class TestVector(unittest.TestCase):
@qc.quickcheck()
def test_add_neg(self, a: Vector):
self.assertEqual(a + (-a), Vector.zero)
@qc.quickcheck()
def test_add_double(self, a: Vector):
self.assertEqual(a + a, 2 * a)
@qc.quickcheck()
def test_add_n(self, a: Vector, n: qc.Integer.exponential(0, 10)):
v = Vector.zero
for _ in range(n):
v += a
self.assertEqual(v, a * n)
@qc.quickcheck()
def test_dot_positive_definite(self, a: Vector):
c = a * a
if a == Vector.zero:
self.assertEqual(c, 0)
else:
self.assertGreater(c, 0)
@qc.quickcheck()
def test_dot_magnitude(self, a: Vector):
self.assertEqual(a.magnitude(), a * a)
@qc.quickcheck()
def test_dot_commute(self, a: Vector, b: Vector):
self.assertEqual(a * b, b * a)
@qc.quickcheck()
def test_cross_self(self, a: Vector):
self.assertEqual(a.cross(a), Vector.zero)
@qc.quickcheck()
def test_cross_anticommute(self, a: Vector, b: Vector):
self.assertEqual(a.cross(b), -b.cross(a))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment