From 446763a53421c4e14dabfb29e992291904dc0948 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Wed, 13 May 2015 14:18:43 -0400 Subject: [PATCH 01/15] initial commit --- matrix.py | 140 +++++++++++++++++++++++++++++++++++++++++++++++++ test_matrix.py | 44 ++++++++++++++++ vector.py | 2 + 3 files changed, 186 insertions(+) create mode 100644 matrix.py create mode 100644 test_matrix.py create mode 100644 vector.py diff --git a/matrix.py b/matrix.py new file mode 100644 index 0000000..cb33e8d --- /dev/null +++ b/matrix.py @@ -0,0 +1,140 @@ +from vector import Vector + +import random + + +class ShapeException(Exception): + pass + + +class Matrix: + + def __init__(self, vectors, shape=None): + if vectors: + self.shape = self.check_vectors(vectors) + self.values = vectors + + else: + if shape: + self.shape = check_shape(shape) + return Matrix.zeroes(shape) + + @classmethod + def zeroes(cls, shape): + """ + Generates a matrix of zeroes with the given shape + """ + cls.check_shape(cls, shape) + values = [] + + for y_val in range(shape[0]): + values.append(Vector.zeroes(shape[1])) + + return cls(values) + + @classmethod + def random(cls, shape, random = random.Random(), start=0, end=10): + """ + takes a random number generator + and fills a matrix of a given shape + with random numbers + """ + values = [] + try: + cls.check_shape(cls, shape) + except ShapeException: + raise + + + for y_len in range(shape[0]): + values.append(Vector.random(shape, random, start, end)) + + return cls(vectors) + + + def check_vectors(self, vectors): + """ + if possible calculates the shape + of the matrix from the input vectors + else raises ShapeException + """ + x_len = len(vectors) + type_check_vect = True + type_check_mat = True + for item in vectors: + type_check_vect = type_check_vect and type(item) == type(1) + type_check_matrix = type_check_mat and type(item) == type([]) + + if type_check_vect: + return x_len, 0 + + if type_check_mat: + + len_check_mat = True + ref = len(vectors[0]) + + for item in vectors: + if len(item) != ref: + len_check_mat = False + + if len_check_mat: + return x_len, ref + + raise ShapeException("Unsuitable vectors used") + + + def check_shape(self, shape): + """ + tests whether shape is acceptable + e.g. a single integer or + two integers in a list/tuple + """ + size_check = (len(shape) == 1 or len(shape) == 2) + type_check = True + for entry in shape: + type_check = type_check and type(entry) == type(1) + + if not (size_check and type_check): + raise ShapeException + + else: + return True + + def __eq__(self, other): + try: + return self.shape == other.shape and self.values == other.values + except Exception: + raise + + def __mul__(self, other): + if type(other) == type(int) or type(other) == type(2.0): + return self.scalar_mult(other) + + if type(other) == type(Vector([1])): + try: + return self.vector_mult(other) + except ShapeException: + raise + + if type(other) == type(self): + try: + return self.matrix_mult(other) + except ShapeException: + raise + + def __pow__(self, other): + if type(other) != type(1): + raise TypeError("power must be an integer") + + if other < 1: + raise TypeError("power must be positive") + + # insert recursive multiply here + + def __add__(self, other): + try: + if self.shape == other.shape: + return [row1 + row2 in zip(self.vectors, other.vectors)] + + except Exception: + raise diff --git a/test_matrix.py b/test_matrix.py new file mode 100644 index 0000000..e1817d7 --- /dev/null +++ b/test_matrix.py @@ -0,0 +1,44 @@ +from matrix import Matrix, ShapeException + +import nose +from nose.tools import raises + +def test_zeroes(): + zeroes = Matrix.zeroes((3,2)) + assert zeroes.values == [[0, 0]]*3 + +@raises(ShapeException) +def test_zeroes_bad_shape(): + Matrix.zeroes((11,2,3)) + +@raises(ShapeException) +def test_matrix_bad_shape(): + Matrix([[0,0,0],[0,0]]) + +class Zeroes: + def randint(self, start, end): + return 0 + +class Ones: + def randint(self, start, end): + return 1 + +class Count: + def __init__(self): + self.int = 0 + + def randint(self, start, end): + self.int+=1 + return self.int + +def test_random(): + shape = (3, 5) + assert Matrix.random(shape, Zeroes()) == Matrix.zeroes(shape) + print(Matrix.random(shape, Ones()).values) + assert Matrix.random(shape, Ones()) == Matrix([[1, 1, 1, 1, 1]]*3) + assert Matrix.random(shape, Count()) == Matrix([[1, 2, 3, 4, 5], + [6, 7, 8, 9, 10], + [11, 12, 13, 14 ,15]]) + +if __name__ == '__main__': + nose.main() diff --git a/vector.py b/vector.py new file mode 100644 index 0000000..0ff3196 --- /dev/null +++ b/vector.py @@ -0,0 +1,2 @@ +class Vector: + def __init__(self, *args): From a1e68f48f9a545450236c6b6d037fb24ef17a62e Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Wed, 13 May 2015 16:32:05 -0400 Subject: [PATCH 02/15] added vector class, tests, all passing --- matrix.py | 89 ++++++++++++++++++++++++++++++++------------------ test_matrix.py | 31 ++++++++++++++---- test_vector.py | 69 ++++++++++++++++++++++++++++++++++++++ vector.py | 80 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 229 insertions(+), 40 deletions(-) create mode 100644 test_vector.py diff --git a/matrix.py b/matrix.py index cb33e8d..09510a8 100644 --- a/matrix.py +++ b/matrix.py @@ -1,18 +1,14 @@ -from vector import Vector +from vector import Vector, ShapeException import random -class ShapeException(Exception): - pass - - class Matrix: def __init__(self, vectors, shape=None): if vectors: - self.shape = self.check_vectors(vectors) - self.values = vectors + self.vectors = self.check_vectors(vectors) + self.shape = (len(vectors), len(vectors[0])) else: if shape: @@ -28,18 +24,18 @@ def zeroes(cls, shape): values = [] for y_val in range(shape[0]): - values.append(Vector.zeroes(shape[1])) + values.append([0 for _ in range(shape[1])]) return cls(values) @classmethod - def random(cls, shape, random = random.Random(), start=0, end=10): + def random(cls, shape, start=0, end=10, random = random.Random()): """ takes a random number generator and fills a matrix of a given shape with random numbers """ - values = [] + vectors = [] try: cls.check_shape(cls, shape) except ShapeException: @@ -47,7 +43,7 @@ def random(cls, shape, random = random.Random(), start=0, end=10): for y_len in range(shape[0]): - values.append(Vector.random(shape, random, start, end)) + vectors.append([random.randint(start,end) for _ in range(shape[1])]) return cls(vectors) @@ -59,28 +55,35 @@ def check_vectors(self, vectors): else raises ShapeException """ x_len = len(vectors) - type_check_vect = True - type_check_mat = True - for item in vectors: - type_check_vect = type_check_vect and type(item) == type(1) - type_check_matrix = type_check_mat and type(item) == type([]) + vect_type = [item for item in vectors if type(item) == type(Vector)] + list_type = [item for item in vectors if type(item) == type([])] + try: + if list_type: + lengths = [len(item) for item in vectors] + + for item in lengths: + if item != lengths[0]: + raise ShapeException("unsuitable vectors used") + + return [Vector(item) for item in vectors] - if type_check_vect: - return x_len, 0 + if vect_type: + shapes = [time.shape for item in vectors] - if type_check_mat: + for item in shapes: + if item != shapes[0]: + raise ShapeException("unsuitable vectors used") - len_check_mat = True - ref = len(vectors[0]) + return vectors - for item in vectors: - if len(item) != ref: - len_check_mat = False + except ShapeException: + raise + + except Exceptions: + + return ValueError("bad initial vectors") - if len_check_mat: - return x_len, ref - raise ShapeException("Unsuitable vectors used") def check_shape(self, shape): @@ -102,7 +105,8 @@ def check_shape(self, shape): def __eq__(self, other): try: - return self.shape == other.shape and self.values == other.values + return self.shape == other.shape and self.vectors == other.vectors + except Exception: raise @@ -117,10 +121,25 @@ def __mul__(self, other): raise if type(other) == type(self): - try: - return self.matrix_mult(other) - except ShapeException: - raise + try: + return self.matrix_mult(other) + except ShapeException: + raise + + @property + def transpose(self): + return Matrix([[row.values[i] for row in self.vectors] + for i in range(self.shape[1])]) + + def scalar_mult(self, other): + return Matrix([vector * other for vector in self.vectors]) + + def vector_mult(self, other): + return Vector([vector.dot(other) for vector in self.vectors]) + + def matrix_mult(self, other): + return Matrix([[vect1.dot(vect2) for vect2 in other.transpose.vectors] + for vect1 in self.vectors]) def __pow__(self, other): if type(other) != type(1): @@ -138,3 +157,9 @@ def __add__(self, other): except Exception: raise + + def __str__(self): + return "\n".join([vector.__str__() for vector in self.vectors]) + + def __repr__(self): + return self.__str__() diff --git a/test_matrix.py b/test_matrix.py index e1817d7..33a241f 100644 --- a/test_matrix.py +++ b/test_matrix.py @@ -5,7 +5,7 @@ def test_zeroes(): zeroes = Matrix.zeroes((3,2)) - assert zeroes.values == [[0, 0]]*3 + assert zeroes == Matrix([[0, 0]]*3) @raises(ShapeException) def test_zeroes_bad_shape(): @@ -33,12 +33,29 @@ def randint(self, start, end): def test_random(): shape = (3, 5) - assert Matrix.random(shape, Zeroes()) == Matrix.zeroes(shape) - print(Matrix.random(shape, Ones()).values) - assert Matrix.random(shape, Ones()) == Matrix([[1, 1, 1, 1, 1]]*3) - assert Matrix.random(shape, Count()) == Matrix([[1, 2, 3, 4, 5], - [6, 7, 8, 9, 10], - [11, 12, 13, 14 ,15]]) + assert Matrix.random(shape, 0, 5, Zeroes()) == Matrix.zeroes(shape) + + assert Matrix.random(shape, 0, 5, Ones()) == Matrix([[1, 1, 1, 1, 1]]*3) + + assert Matrix.random(shape, 0, 5, Count()) == Matrix([[1, 2, 3, 4, 5], + [6, 7, 8, 9, 10], + [11, 12, 13, 14 ,15]]) + +def test_matrix_mult(): + identity = Matrix([[1,0,0], + [0,1,0], + [0,0,1]]) + + a_mat = Matrix([[1,3,2], + [2,3,1], + [3,1,2]]) + + assert identity * a_mat == a_mat * identity + assert identity * a_mat == a_mat + +#def test_bad_matrix_mult(): + + if __name__ == '__main__': nose.main() diff --git a/test_vector.py b/test_vector.py new file mode 100644 index 0000000..a64b69d --- /dev/null +++ b/test_vector.py @@ -0,0 +1,69 @@ +from vector import Vector, ShapeException + +from nose.tools import raises +import nose + +def test_zeroes(): + zeroes = Vector.zeroes(10) + assert zeroes.values == [0]*10 + +def test_check_shape(): + vect = Vector([1, 2, 3]) + assert vect.shape == (3,) + assert vect.check_shape(Vector([2, 4, 6])) + assert not vect.check_shape(Vector([1, 3])) + +@raises(TypeError) +def test_vector_bad_shape(): + Vector([0, 0, [0, 0, 0], 0, 0]) + + +@raises(TypeError) +def test_zeroes_bad_shape(): + Vector.zeroes([[11, 2], 3]) + + +class Zeroes: + def randint(self, start, end): + return 0 + + +class Ones: + def randint(self, start, end): + return 1 + + +class Count: + def __init__(self): + self.int = 0 + + def randint(self, start, end): + self.int+=1 + return self.int + + +def test_random(): + length = 5 + assert Vector.random(length, 0, 10, Zeroes()) == Vector.zeroes(length) + assert Vector.random(length, 0, 10, Ones()) == Vector([1]*length) + assert Vector.random(length, 0, 10, Count()) == Vector([1, 2, 3, 4, 5]) + + +def test_vector_add(): + assert Vector([1, 3, 3]) + Vector([1, 2, 3]) == Vector([2, 5, 6]) + + +@raises(ShapeException) +def test_bad_add(): + Vector([1, 2, 3]) + Vector([1, 2]) + + +def test_scalar_mult(): + assert Vector([1, 1, 1]) * 5 == Vector([5, 5, 5]) + + +def test_dot(): + Vector([1, 3, 5]).dot(Vector([3,1,5])) == 16 + +if __name__ == '__main__': + nose.main() diff --git a/vector.py b/vector.py index 0ff3196..2f5de9b 100644 --- a/vector.py +++ b/vector.py @@ -1,2 +1,80 @@ +import random +import math + +class ShapeException(Exception): + pass + + class Vector: - def __init__(self, *args): + def __init__(self, arg): + + if type(arg) != type([]): + raise ShapeException + + for item in arg: + if not (type(item) == type(1) or type(item) == type(2.0)): + raise TypeError("List items not integers or floats") + + self.values = arg + self.shape = (len(arg),) + + @classmethod + def zeroes(cls, length): + if type(length) != type(1): + raise TypeError("input length is not an integer") + + return cls([0] * length) + + + @classmethod + def random(cls, length, start, end, random=random.Random()): + if type(length) != type(1) or \ + type(start) != type(1) or \ + type(end) != type(1): + + raise ValueError + + return cls([random.randint(start, end) for _ in range(length)]) + + def check_shape(self, other): + return self.shape == other.shape + + def __add__(self, other): + if self.check_shape(other): + return Vector([entry1 + entry2 for entry1, entry2 \ + in zip(self.values, other.values)]) + + raise ShapeException + + def __mul__(self, other): + if type(other) == type(1) or type(other) == type(2.0): + return self.scalar_mult(other) + + else: + raise ValueError("Cannot multiply {} and {}".format(type(self), + type(other))) + + def scalar_mult(self, other): + return Vector([val * other for val in self.values]) + + def __eq__(self, other): + return (type(self) == type(other) and + self.shape == other. shape and + self.values == other.values) + + def dot(self, other): + if self.check_shape(other): + return sum([coeff1 * coeff2 for (coeff1, coeff2) + in list(zip(self.values, other.values))]) + + raise ShapeException + + @property + def magnitude(self): + return math.sqrt(dot(self,self)) + + def __str__(self): + return ", ".join([str(val) for val in self.values]) + + def __repr__(self): + return self.__str__() From 8bfd9983d81914ca56e8dbf8070e0770cf889e24 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Wed, 13 May 2015 17:22:47 -0400 Subject: [PATCH 03/15] added generate --- matrix.py | 17 +++++++++++++++-- test_matrix.py | 31 +++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/matrix.py b/matrix.py index 09510a8..6032642 100644 --- a/matrix.py +++ b/matrix.py @@ -15,6 +15,14 @@ def __init__(self, vectors, shape=None): self.shape = check_shape(shape) return Matrix.zeroes(shape) + @classmethod + def generate(cls, shape, gen_func): + if cls.check_shape(cls, shape): + return cls([[gen_func() for _ in range(shape[0])] + for _ in range(shape[1])]) + + raise ShapeException + @classmethod def zeroes(cls, shape): """ @@ -138,8 +146,13 @@ def vector_mult(self, other): return Vector([vector.dot(other) for vector in self.vectors]) def matrix_mult(self, other): - return Matrix([[vect1.dot(vect2) for vect2 in other.transpose.vectors] - for vect1 in self.vectors]) + if self.shape == other.shape: + return Matrix([[vect1.dot(vect2) for vect2 in + other.transpose.vectors] + for vect1 in self.vectors]) + + raise ShapeException + def __pow__(self, other): if type(other) != type(1): diff --git a/test_matrix.py b/test_matrix.py index 33a241f..714dac1 100644 --- a/test_matrix.py +++ b/test_matrix.py @@ -1,4 +1,5 @@ -from matrix import Matrix, ShapeException +from matrix import Matrix +from vector import Vector, ShapeException import nose from nose.tools import raises @@ -53,9 +54,35 @@ def test_matrix_mult(): assert identity * a_mat == a_mat * identity assert identity * a_mat == a_mat -#def test_bad_matrix_mult(): +@raises(ShapeException) +def test_bad_matrix_mult(): + a_mat = Matrix([[1,2],[3,4]]) + b_mat = Matrix([[1,3,5],[2,5,5]]) + a_mat * b_mat + +def test_mat_vect_mult(): + a_mat = Matrix([[1, 2], [3, 4]]) + vect = Vector([3, 5]) + assert a_mat * vect == Vector([13, 29]) +@raises(ShapeException) +def test_bad_shape_vect_mult(): + a_mat = Matrix([[1, 2], [3, 4]]) + vect = Vector([3, 5, 6]) + a_mat * vect + +@raises(ValueError) +def test_bad_order_mult(): + a_mat = Matrix([[1, 2], [3, 4]]) + vect = Vector([3, 5]) + vect * a_mat + +def test_generate(): + def func(): + return 1 + a_mat = Matrix.generate((2,2),func) + assert a_mat == Matrix([[1, 1], [1, 1]]) if __name__ == '__main__': nose.main() From e787b878b9165e49e128869201291a53a57878f0 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Wed, 13 May 2015 17:47:57 -0400 Subject: [PATCH 04/15] PEP8 + fire_drake problem --- fire_drake.py | 14 ++++++++++++++ matrix.py | 46 ++++++++++++++++++++++++++++++++++------------ test_matrix.py | 48 ++++++++++++++++++++++++++++++++---------------- test_vector.py | 14 ++++++++++---- vector.py | 19 ++++++++++--------- 5 files changed, 100 insertions(+), 41 deletions(-) create mode 100644 fire_drake.py diff --git a/fire_drake.py b/fire_drake.py new file mode 100644 index 0000000..8630f21 --- /dev/null +++ b/fire_drake.py @@ -0,0 +1,14 @@ +from matrix import Matrix +from vector import Vector + +current_drakes = Vector([10, 0, 0, 0, 0, 0]) +leslie = Matrix([[0, .25, .6, .8, .15, 0], + [.7, 0, 0, 0, 0, 0], + [0, .95, 0, 0, 0, 0], + [0, 0, .9, 0, 0, 0], + [0, 0, 0, .9, 0, 0], + [0, 0, 0, 0, .5, 0]]) + + +drakes_future = leslie ** 20 * current_drakes +print(drakes_future) diff --git a/matrix.py b/matrix.py index 6032642..c24d3ab 100644 --- a/matrix.py +++ b/matrix.py @@ -17,9 +17,13 @@ def __init__(self, vectors, shape=None): @classmethod def generate(cls, shape, gen_func): + """ + creates a matrix whose values + are the result of calling gen_func + """ if cls.check_shape(cls, shape): return cls([[gen_func() for _ in range(shape[0])] - for _ in range(shape[1])]) + for _ in range(shape[1])]) raise ShapeException @@ -37,7 +41,7 @@ def zeroes(cls, shape): return cls(values) @classmethod - def random(cls, shape, start=0, end=10, random = random.Random()): + def random(cls, shape, start=0, end=10, random=random.Random()): """ takes a random number generator and fills a matrix of a given shape @@ -49,13 +53,12 @@ def random(cls, shape, start=0, end=10, random = random.Random()): except ShapeException: raise - for y_len in range(shape[0]): - vectors.append([random.randint(start,end) for _ in range(shape[1])]) + vectors.append([random.randint(start, end) + for _ in range(shape[1])]) return cls(vectors) - def check_vectors(self, vectors): """ if possible calculates the shape @@ -91,9 +94,6 @@ def check_vectors(self, vectors): return ValueError("bad initial vectors") - - - def check_shape(self, shape): """ tests whether shape is acceptable @@ -136,24 +136,37 @@ def __mul__(self, other): @property def transpose(self): + """ + the transpose of the matrix + """ return Matrix([[row.values[i] for row in self.vectors] - for i in range(self.shape[1])]) + for i in range(self.shape[1])]) def scalar_mult(self, other): + """ + multiplies the matrix by a constant + """ return Matrix([vector * other for vector in self.vectors]) def vector_mult(self, other): + """ + multiplies a vector by self + and returns the resulting vector + """ return Vector([vector.dot(other) for vector in self.vectors]) def matrix_mult(self, other): + """ + multiplies the matrix by a another matrix + and returns the resulting matrix + """ if self.shape == other.shape: return Matrix([[vect1.dot(vect2) for vect2 in other.transpose.vectors] - for vect1 in self.vectors]) + for vect1 in self.vectors]) raise ShapeException - def __pow__(self, other): if type(other) != type(1): raise TypeError("power must be an integer") @@ -161,7 +174,16 @@ def __pow__(self, other): if other < 1: raise TypeError("power must be positive") - # insert recursive multiply here + return self.remult(other) + + def remult(self, num): + """ + returns a matrix raised to a positive integer power + """ + if num > 1: + return self.remult(num - 1) * self + else: + return self def __add__(self, other): try: diff --git a/test_matrix.py b/test_matrix.py index 714dac1..2eae7a0 100644 --- a/test_matrix.py +++ b/test_matrix.py @@ -4,84 +4,100 @@ import nose from nose.tools import raises + def test_zeroes(): - zeroes = Matrix.zeroes((3,2)) - assert zeroes == Matrix([[0, 0]]*3) + zeroes = Matrix.zeroes((3, 2)) + assert zeroes == Matrix([[0, 0]] * 3) + @raises(ShapeException) def test_zeroes_bad_shape(): - Matrix.zeroes((11,2,3)) + Matrix.zeroes((11, 2, 3)) + @raises(ShapeException) def test_matrix_bad_shape(): - Matrix([[0,0,0],[0,0]]) + Matrix([[0, 0, 0], [0, 0]]) + class Zeroes: + def randint(self, start, end): return 0 + class Ones: + def randint(self, start, end): return 1 + class Count: + def __init__(self): self.int = 0 def randint(self, start, end): - self.int+=1 + self.int += 1 return self.int + def test_random(): shape = (3, 5) assert Matrix.random(shape, 0, 5, Zeroes()) == Matrix.zeroes(shape) - assert Matrix.random(shape, 0, 5, Ones()) == Matrix([[1, 1, 1, 1, 1]]*3) + assert Matrix.random(shape, 0, 5, Ones()) == Matrix([[1, 1, 1, 1, 1]] * 3) assert Matrix.random(shape, 0, 5, Count()) == Matrix([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], - [11, 12, 13, 14 ,15]]) + [11, 12, 13, 14, 15]]) + def test_matrix_mult(): - identity = Matrix([[1,0,0], - [0,1,0], - [0,0,1]]) + identity = Matrix([[1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) - a_mat = Matrix([[1,3,2], - [2,3,1], - [3,1,2]]) + a_mat = Matrix([[1, 3, 2], + [2, 3, 1], + [3, 1, 2]]) assert identity * a_mat == a_mat * identity assert identity * a_mat == a_mat + @raises(ShapeException) def test_bad_matrix_mult(): - a_mat = Matrix([[1,2],[3,4]]) - b_mat = Matrix([[1,3,5],[2,5,5]]) + a_mat = Matrix([[1, 2], [3, 4]]) + b_mat = Matrix([[1, 3, 5], [2, 5, 5]]) a_mat * b_mat + def test_mat_vect_mult(): a_mat = Matrix([[1, 2], [3, 4]]) vect = Vector([3, 5]) assert a_mat * vect == Vector([13, 29]) + @raises(ShapeException) def test_bad_shape_vect_mult(): a_mat = Matrix([[1, 2], [3, 4]]) vect = Vector([3, 5, 6]) a_mat * vect + @raises(ValueError) def test_bad_order_mult(): a_mat = Matrix([[1, 2], [3, 4]]) vect = Vector([3, 5]) vect * a_mat + def test_generate(): def func(): return 1 - a_mat = Matrix.generate((2,2),func) + a_mat = Matrix.generate((2, 2), func) assert a_mat == Matrix([[1, 1], [1, 1]]) if __name__ == '__main__': diff --git a/test_vector.py b/test_vector.py index a64b69d..ee1f475 100644 --- a/test_vector.py +++ b/test_vector.py @@ -3,9 +3,11 @@ from nose.tools import raises import nose + def test_zeroes(): zeroes = Vector.zeroes(10) - assert zeroes.values == [0]*10 + assert zeroes.values == [0] * 10 + def test_check_shape(): vect = Vector([1, 2, 3]) @@ -13,6 +15,7 @@ def test_check_shape(): assert vect.check_shape(Vector([2, 4, 6])) assert not vect.check_shape(Vector([1, 3])) + @raises(TypeError) def test_vector_bad_shape(): Vector([0, 0, [0, 0, 0], 0, 0]) @@ -24,28 +27,31 @@ def test_zeroes_bad_shape(): class Zeroes: + def randint(self, start, end): return 0 class Ones: + def randint(self, start, end): return 1 class Count: + def __init__(self): self.int = 0 def randint(self, start, end): - self.int+=1 + self.int += 1 return self.int def test_random(): length = 5 assert Vector.random(length, 0, 10, Zeroes()) == Vector.zeroes(length) - assert Vector.random(length, 0, 10, Ones()) == Vector([1]*length) + assert Vector.random(length, 0, 10, Ones()) == Vector([1] * length) assert Vector.random(length, 0, 10, Count()) == Vector([1, 2, 3, 4, 5]) @@ -63,7 +69,7 @@ def test_scalar_mult(): def test_dot(): - Vector([1, 3, 5]).dot(Vector([3,1,5])) == 16 + Vector([1, 3, 5]).dot(Vector([3, 1, 5])) == 16 if __name__ == '__main__': nose.main() diff --git a/vector.py b/vector.py index 2f5de9b..04e78a6 100644 --- a/vector.py +++ b/vector.py @@ -1,11 +1,13 @@ import random import math + class ShapeException(Exception): pass class Vector: + def __init__(self, arg): if type(arg) != type([]): @@ -25,12 +27,11 @@ def zeroes(cls, length): return cls([0] * length) - @classmethod def random(cls, length, start, end, random=random.Random()): if type(length) != type(1) or \ - type(start) != type(1) or \ - type(end) != type(1): + type(start) != type(1) or \ + type(end) != type(1): raise ValueError @@ -41,8 +42,8 @@ def check_shape(self, other): def __add__(self, other): if self.check_shape(other): - return Vector([entry1 + entry2 for entry1, entry2 \ - in zip(self.values, other.values)]) + return Vector([entry1 + entry2 for entry1, entry2 + in zip(self.values, other.values)]) raise ShapeException @@ -59,8 +60,8 @@ def scalar_mult(self, other): def __eq__(self, other): return (type(self) == type(other) and - self.shape == other. shape and - self.values == other.values) + self.shape == other. shape and + self.values == other.values) def dot(self, other): if self.check_shape(other): @@ -71,10 +72,10 @@ def dot(self, other): @property def magnitude(self): - return math.sqrt(dot(self,self)) + return math.sqrt(dot(self, self)) def __str__(self): - return ", ".join([str(val) for val in self.values]) + return "[" + ", ".join([str(val) for val in self.values]) + "]" def __repr__(self): return self.__str__() From da5b32befb38dd3d14507251db5ee281629946a1 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Wed, 13 May 2015 17:51:10 -0400 Subject: [PATCH 05/15] added docstrings to vector --- vector.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/vector.py b/vector.py index 04e78a6..5e82a09 100644 --- a/vector.py +++ b/vector.py @@ -22,6 +22,9 @@ def __init__(self, arg): @classmethod def zeroes(cls, length): + """ + makes a zero vector of the given length + """ if type(length) != type(1): raise TypeError("input length is not an integer") @@ -29,6 +32,10 @@ def zeroes(cls, length): @classmethod def random(cls, length, start, end, random=random.Random()): + """ + makes a vector of the given length + with entries from random.randint(start, end) + """ if type(length) != type(1) or \ type(start) != type(1) or \ type(end) != type(1): @@ -38,6 +45,10 @@ def random(cls, length, start, end, random=random.Random()): return cls([random.randint(start, end) for _ in range(length)]) def check_shape(self, other): + """ + checks if the shapes match between + the vector and other + """ return self.shape == other.shape def __add__(self, other): @@ -56,6 +67,10 @@ def __mul__(self, other): type(other))) def scalar_mult(self, other): + """ + multiplies the vector by a scalar + and returns the result + """ return Vector([val * other for val in self.values]) def __eq__(self, other): @@ -72,6 +87,10 @@ def dot(self, other): @property def magnitude(self): + """ + calculates the magnitude of the vector + in the Euclidean norm + """ return math.sqrt(dot(self, self)) def __str__(self): From cbcd80e7fc6f4b8fdb096b7913ba4a530f1818a0 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Wed, 13 May 2015 18:20:07 -0400 Subject: [PATCH 06/15] cleaning up --- matrix.py | 41 +++++++++++++++++++++++------------------ test_matrix.py | 13 +++++++++---- vector.py | 22 +++++++++++----------- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/matrix.py b/matrix.py index c24d3ab..410bf39 100644 --- a/matrix.py +++ b/matrix.py @@ -8,11 +8,11 @@ class Matrix: def __init__(self, vectors, shape=None): if vectors: self.vectors = self.check_vectors(vectors) - self.shape = (len(vectors), len(vectors[0])) + self.shape = (len(vectors), self.vectors[0].shape[0]) else: if shape: - self.shape = check_shape(shape) + self.shape = self.check_shape(shape) return Matrix.zeroes(shape) @classmethod @@ -61,15 +61,17 @@ def random(cls, shape, start=0, end=10, random=random.Random()): def check_vectors(self, vectors): """ - if possible calculates the shape - of the matrix from the input vectors - else raises ShapeException + checks the input vectors + to see if they are in fact + lists or vectors, then checks + their lengths. If they are + all the same length it returns + a list of vectors """ - x_len = len(vectors) - vect_type = [item for item in vectors if type(item) == type(Vector)] - list_type = [item for item in vectors if type(item) == type([])] + vect_type = [item for item in vectors if isinstance(item, Vector)] + list_type = [item for item in vectors if isinstance(item, list)] try: - if list_type: + if list_type and not vect_type: lengths = [len(item) for item in vectors] for item in lengths: @@ -78,8 +80,8 @@ def check_vectors(self, vectors): return [Vector(item) for item in vectors] - if vect_type: - shapes = [time.shape for item in vectors] + if vect_type and not list_type: + shapes = [item.shape for item in vectors] for item in shapes: if item != shapes[0]: @@ -87,10 +89,12 @@ def check_vectors(self, vectors): return vectors + raise TypeError("mismatched input types") + except ShapeException: raise - except Exceptions: + except Exception: return ValueError("bad initial vectors") @@ -103,7 +107,7 @@ def check_shape(self, shape): size_check = (len(shape) == 1 or len(shape) == 2) type_check = True for entry in shape: - type_check = type_check and type(entry) == type(1) + type_check = type_check and isinstance(entry, int) if not (size_check and type_check): raise ShapeException @@ -119,16 +123,16 @@ def __eq__(self, other): raise def __mul__(self, other): - if type(other) == type(int) or type(other) == type(2.0): + if isinstance(other, int) or isinstance(other, float): return self.scalar_mult(other) - if type(other) == type(Vector([1])): + if isinstance(other, Vector): try: return self.vector_mult(other) except ShapeException: raise - if type(other) == type(self): + if isinstance(other, Matrix): try: return self.matrix_mult(other) except ShapeException: @@ -168,7 +172,7 @@ def matrix_mult(self, other): raise ShapeException def __pow__(self, other): - if type(other) != type(1): + if not isinstance(other, int): raise TypeError("power must be an integer") if other < 1: @@ -188,7 +192,8 @@ def remult(self, num): def __add__(self, other): try: if self.shape == other.shape: - return [row1 + row2 in zip(self.vectors, other.vectors)] + return Matrix([row1 + row2 for row1, row2 + in zip(self.vectors, other.vectors)]) except Exception: raise diff --git a/test_matrix.py b/test_matrix.py index 2eae7a0..f22920b 100644 --- a/test_matrix.py +++ b/test_matrix.py @@ -48,12 +48,13 @@ def test_random(): assert Matrix.random(shape, 0, 5, Ones()) == Matrix([[1, 1, 1, 1, 1]] * 3) - assert Matrix.random(shape, 0, 5, Count()) == Matrix([[1, 2, 3, 4, 5], - [6, 7, 8, 9, 10], - [11, 12, 13, 14, 15]]) + assert Matrix.random(shape, 0, 5, Count()) == \ + Matrix([[1, 2, 3, 4, 5], + [6, 7, 8, 9, 10], + [11, 12, 13, 14, 15]]) -def test_matrix_mult(): +def test_matrix_add_mult(): identity = Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) @@ -65,6 +66,10 @@ def test_matrix_mult(): assert identity * a_mat == a_mat * identity assert identity * a_mat == a_mat + assert identity + a_mat == Matrix([[2, 3, 2], + [2, 4, 1], + [3, 1, 3]]) + @raises(ShapeException) def test_bad_matrix_mult(): diff --git a/vector.py b/vector.py index 5e82a09..0ea1a51 100644 --- a/vector.py +++ b/vector.py @@ -10,12 +10,12 @@ class Vector: def __init__(self, arg): - if type(arg) != type([]): + if not isinstance(arg, list): raise ShapeException for item in arg: - if not (type(item) == type(1) or type(item) == type(2.0)): - raise TypeError("List items not integers or floats") + if not (isinstance(item, int) or isinstance(item, float)): + raise TypeError("List items not ints or floats") self.values = arg self.shape = (len(arg),) @@ -25,8 +25,8 @@ def zeroes(cls, length): """ makes a zero vector of the given length """ - if type(length) != type(1): - raise TypeError("input length is not an integer") + if not isinstance(length, int): + raise TypeError("input length is not an int") return cls([0] * length) @@ -36,9 +36,9 @@ def random(cls, length, start, end, random=random.Random()): makes a vector of the given length with entries from random.randint(start, end) """ - if type(length) != type(1) or \ - type(start) != type(1) or \ - type(end) != type(1): + if not (isinstance(length, int) or + isinstance(start, int) or + isinstance(end, int)): raise ValueError @@ -59,7 +59,7 @@ def __add__(self, other): raise ShapeException def __mul__(self, other): - if type(other) == type(1) or type(other) == type(2.0): + if isinstance(other, int) or isinstance(other, float): return self.scalar_mult(other) else: @@ -89,9 +89,9 @@ def dot(self, other): def magnitude(self): """ calculates the magnitude of the vector - in the Euclidean norm + in the E """ - return math.sqrt(dot(self, self)) + return math.sqrt(self.dot(self)) def __str__(self): return "[" + ", ".join([str(val) for val in self.values]) + "]" From 7a86eaa9baf852b7305bf1fd268ad248bcb5553b Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Wed, 13 May 2015 20:11:54 -0400 Subject: [PATCH 07/15] added __sub__ to vectors/matrices --- matrix.py | 9 +++++++++ test_matrix.py | 12 ++++++++++++ test_vector.py | 1 + vector.py | 3 +++ 4 files changed, 25 insertions(+) diff --git a/matrix.py b/matrix.py index 410bf39..ed992b8 100644 --- a/matrix.py +++ b/matrix.py @@ -70,6 +70,12 @@ def check_vectors(self, vectors): """ vect_type = [item for item in vectors if isinstance(item, Vector)] list_type = [item for item in vectors if isinstance(item, list)] + none_type = [item for item in vectors + if item not in vect_type and item not in list_type] + + if none_type: + raise TypeError("supplied vectors are of incorrect type") + try: if list_type and not vect_type: lengths = [len(item) for item in vectors] @@ -198,6 +204,9 @@ def __add__(self, other): except Exception: raise + def __sub__(self, other): + return self.__add__(other * -1) + def __str__(self): return "\n".join([vector.__str__() for vector in self.vectors]) diff --git a/test_matrix.py b/test_matrix.py index f22920b..ac67832 100644 --- a/test_matrix.py +++ b/test_matrix.py @@ -63,6 +63,10 @@ def test_matrix_add_mult(): [2, 3, 1], [3, 1, 2]]) + b_mat = Matrix([[1, 1, 1], + [1, 1, 1], + [1, 1, 1]]) + assert identity * a_mat == a_mat * identity assert identity * a_mat == a_mat @@ -70,6 +74,14 @@ def test_matrix_add_mult(): [2, 4, 1], [3, 1, 3]]) + assert identity + a_mat == a_mat + identity + + assert a_mat - identity == Matrix([[0, 3, 2], + [2, 2, 1], + [3, 1, 1]]) + + assert a_mat * b_mat != b_mat * a_mat + @raises(ShapeException) def test_bad_matrix_mult(): diff --git a/test_vector.py b/test_vector.py index ee1f475..7f2be62 100644 --- a/test_vector.py +++ b/test_vector.py @@ -57,6 +57,7 @@ def test_random(): def test_vector_add(): assert Vector([1, 3, 3]) + Vector([1, 2, 3]) == Vector([2, 5, 6]) + assert Vector([1, 3, 3]) - Vector([1, 2, 3]) == Vector([0, 1, 0]) @raises(ShapeException) diff --git a/vector.py b/vector.py index 0ea1a51..d3092ba 100644 --- a/vector.py +++ b/vector.py @@ -58,6 +58,9 @@ def __add__(self, other): raise ShapeException + def __sub__(self, other): + return self.__add__(other * -1) + def __mul__(self, other): if isinstance(other, int) or isinstance(other, float): return self.scalar_mult(other) From 6d74dce2d40cce9a89df9daaefa5ea591c9f6066 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Wed, 13 May 2015 20:21:12 -0400 Subject: [PATCH 08/15] __iadd__ and __isub__ added --- matrix.py | 6 ++++++ vector.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/matrix.py b/matrix.py index ed992b8..a201e31 100644 --- a/matrix.py +++ b/matrix.py @@ -207,6 +207,12 @@ def __add__(self, other): def __sub__(self, other): return self.__add__(other * -1) + def __iadd__(self, other): + return self.__add__(other) + + def __isub__(self, other): + return self.__sub__(other) + def __str__(self): return "\n".join([vector.__str__() for vector in self.vectors]) diff --git a/vector.py b/vector.py index d3092ba..a784232 100644 --- a/vector.py +++ b/vector.py @@ -61,6 +61,12 @@ def __add__(self, other): def __sub__(self, other): return self.__add__(other * -1) + def __iadd__(self, other): + return self.__add__(other) + + def __isub__(self, other): + return self.__sub__(other) + def __mul__(self, other): if isinstance(other, int) or isinstance(other, float): return self.scalar_mult(other) From cb08bdb0d66273df70fedccebc825643fdfa2e8e Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Thu, 14 May 2015 08:54:26 -0400 Subject: [PATCH 09/15] added Matrix.function --- matrix.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/matrix.py b/matrix.py index a201e31..7395374 100644 --- a/matrix.py +++ b/matrix.py @@ -27,6 +27,12 @@ def generate(cls, shape, gen_func): raise ShapeException + @classmethod + def from_function(cls, shape, func): + if cls.check_shape(cls, shape): + return cls([[func(i, j) for j in range(shape[0])] for + i in range(shape[1])]) + @classmethod def zeroes(cls, shape): """ From fd65f01df364921e0ad5561af686e548f1a4c42e Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Thu, 14 May 2015 08:58:38 -0400 Subject: [PATCH 10/15] vector printing now rounds to 3 digits --- vector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector.py b/vector.py index a784232..d684fd6 100644 --- a/vector.py +++ b/vector.py @@ -103,7 +103,7 @@ def magnitude(self): return math.sqrt(self.dot(self)) def __str__(self): - return "[" + ", ".join([str(val) for val in self.values]) + "]" + return "[" + ", ".join([str(round(val, 3)) for val in self.values]) + "]" def __repr__(self): return self.__str__() From ec7d6f9ba3f2d2fca8ff00139e46c49eb14c64c5 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Thu, 14 May 2015 09:00:32 -0400 Subject: [PATCH 11/15] flake8 --- vector.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vector.py b/vector.py index d684fd6..3b27670 100644 --- a/vector.py +++ b/vector.py @@ -103,7 +103,8 @@ def magnitude(self): return math.sqrt(self.dot(self)) def __str__(self): - return "[" + ", ".join([str(round(val, 3)) for val in self.values]) + "]" + return "[" + ", ".join([str(round(val, 3)) + for val in self.values]) + "]" def __repr__(self): return self.__str__() From cd6108a7bfb94ae792b3b4d036865fcbc3a6a97f Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Thu, 14 May 2015 09:11:34 -0400 Subject: [PATCH 12/15] list -> tuple inside Vector --- fire_drake.py | 1 + test_vector.py | 2 +- vector.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fire_drake.py b/fire_drake.py index 8630f21..4f18d7b 100644 --- a/fire_drake.py +++ b/fire_drake.py @@ -2,6 +2,7 @@ from vector import Vector current_drakes = Vector([10, 0, 0, 0, 0, 0]) + leslie = Matrix([[0, .25, .6, .8, .15, 0], [.7, 0, 0, 0, 0, 0], [0, .95, 0, 0, 0, 0], diff --git a/test_vector.py b/test_vector.py index 7f2be62..1f5223b 100644 --- a/test_vector.py +++ b/test_vector.py @@ -6,7 +6,7 @@ def test_zeroes(): zeroes = Vector.zeroes(10) - assert zeroes.values == [0] * 10 + assert zeroes.values == tuple([0] * 10) def test_check_shape(): diff --git a/vector.py b/vector.py index 3b27670..7a73c0e 100644 --- a/vector.py +++ b/vector.py @@ -17,7 +17,7 @@ def __init__(self, arg): if not (isinstance(item, int) or isinstance(item, float)): raise TypeError("List items not ints or floats") - self.values = arg + self.values = tuple(arg) self.shape = (len(arg),) @classmethod From c333b039833c105bd1582218a41f8509d5b41ed2 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Thu, 14 May 2015 09:13:06 -0400 Subject: [PATCH 13/15] list of vectors -> tuple of vectors in matrix --- matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix.py b/matrix.py index 7395374..87558c6 100644 --- a/matrix.py +++ b/matrix.py @@ -7,7 +7,7 @@ class Matrix: def __init__(self, vectors, shape=None): if vectors: - self.vectors = self.check_vectors(vectors) + self.vectors = tuple(self.check_vectors(vectors)) self.shape = (len(vectors), self.vectors[0].shape[0]) else: From 36f5793de835ae2224732048cde33d1e2e7dbbf0 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Thu, 14 May 2015 09:19:45 -0400 Subject: [PATCH 14/15] using module numbers for isinstance now --- matrix.py | 3 ++- vector.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/matrix.py b/matrix.py index 87558c6..ee0190f 100644 --- a/matrix.py +++ b/matrix.py @@ -1,6 +1,7 @@ from vector import Vector, ShapeException import random +from numbers import Number class Matrix: @@ -135,7 +136,7 @@ def __eq__(self, other): raise def __mul__(self, other): - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, Number): return self.scalar_mult(other) if isinstance(other, Vector): diff --git a/vector.py b/vector.py index 7a73c0e..a16f3f7 100644 --- a/vector.py +++ b/vector.py @@ -1,5 +1,6 @@ import random import math +from number import Number class ShapeException(Exception): @@ -14,7 +15,7 @@ def __init__(self, arg): raise ShapeException for item in arg: - if not (isinstance(item, int) or isinstance(item, float)): + if not (isinstance(item, Number)): raise TypeError("List items not ints or floats") self.values = tuple(arg) From 19d86419e4f2b8678cb3e7570b181c1cb1406f9a Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Thu, 14 May 2015 09:41:14 -0400 Subject: [PATCH 15/15] __rmul__ and __neg__ added --- matrix.py | 9 ++++++++- vector.py | 11 +++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/matrix.py b/matrix.py index ee0190f..654df75 100644 --- a/matrix.py +++ b/matrix.py @@ -212,7 +212,14 @@ def __add__(self, other): raise def __sub__(self, other): - return self.__add__(other * -1) + return self.__add__(other.__neg__()) + + def __neg__(self): + return self.__mul__(-1) + + def __rmul__(self, other): + if isinstance(other, Number): + return self.__mul__(other) def __iadd__(self, other): return self.__add__(other) diff --git a/vector.py b/vector.py index a16f3f7..69113ed 100644 --- a/vector.py +++ b/vector.py @@ -1,6 +1,6 @@ import random import math -from number import Number +from numbers import Number class ShapeException(Exception): @@ -60,7 +60,10 @@ def __add__(self, other): raise ShapeException def __sub__(self, other): - return self.__add__(other * -1) + return self.__add__(other.__neg__()) + + def __neg__(self): + return self.__mul__(-1) def __iadd__(self, other): return self.__add__(other) @@ -76,6 +79,10 @@ def __mul__(self, other): raise ValueError("Cannot multiply {} and {}".format(type(self), type(other))) + def __rmul__(self, other): + if isinstance(other, Number): + return self.__mul__(other) + def scalar_mult(self, other): """ multiplies the vector by a scalar