''' Created on Jul 28, 2015 @author: Brett Paufler Copyright Brett Paufler The matrix module exports the Class centered_matrix. A centered matrix has (x,y) coordinated centered on a specific point(cx, cy), such that (cx,cy) is located at the physical center of the matrix and a position indexed by (cx + 1, cy + 1) is located as one would expect in the cartesianal coordinate world. The intent is to create a class that one can reason about in a traditional (x,y) way but has all the advantages of being a numpy array. As of 9-4-15, football_tournament or other modules in football do not access this in any meaningful way Though I still feel this will make it easier to reason about complex plays in the future simple lines and nearest neighbor algorithms have sufficed thus far. #TODO Notes: from here down #Eventually, this will be important #rr,cc = line(0,0,10,9) #pos[rr,cc] = 3 #x = random.randint(-3,3) #y = random.randint(-3,3) xy = [(-1,1), (2,2), (3,-3), (-4,-4)] xy2 = [(-1,3), (2,4), (3,-1), (-4,-2)] ''' import numpy as np class centered_matrix(): '''Arbitrarily centered 2-D numpy array accessible by standard (x,y) Cartesian coordinates''' def __init__(self, radius=3, center=(0,0)): '''Returns a centered_matrix with properties as follows: (Note: __init__ simply calls refresh). r = half size of array (distance from center to top, bottom, left, right) s = total size of array: array.shape = (s,s) m = new numpy array of integers (s,s) with all values zeroed out cx = the relative x center of the array cy = the relative y center of the array an incomming value of cx, cy indexes the center of the array (self.m) an incomming value of cx + 1, cy + 1, would index the point of the array one up and right from the center if center = (0,0), then (1,1) is located one space diagonally up and right from there centered_matrix(radius=1, center=(0,0)) indexes to these values: [[(-1,1) (0,1) (1,1)] [(-1,0) (0,0) (1,0)] [(-1,-1) (0,-1) (1,-1)]] ''' self.refresh(radius, center) def refresh(self, radius, center): '''(Re)Builds the matrix (self.m) with all indexes set to zero.''' self.r = radius self.cx = center[0] self.cy = center[1] s = 2 * self.r + 1 self.m = np.zeros((s, s), dtype=int) def __repr__(self): t = 'centered_array: r=%d, c=(%d, %d)\n' % (self.r, self.cx, self.cy) t += str(self.m) return t def xy_in(self, (x, y)): '''Converts (x,y) from centered normal to numpy normal. Given an (x,y) coordinate as measured from the center, returns appropriate numpy index''' return int(self.r - y + self.cy), int(self.r + x - self.cx) def xy_out(self, (y, x)): '''Converts a numpy index to an (x,y) Cartesian Coordinate relative to center. Compliment to xy_in self.xy_in(self.xy_out((x, y))) == self.xy_out(self.xy_in((x, y)))''' return + self.cx - self.r + x, -y + self.r + self.cy def load_xyz(self, x,y,z): '''Loads value z in centered matrix at relative position (x,y). If relative position of (x,y) is not a valid matrix index, nothing happens.''' x, y = self.xy_in((x,y)) if x >= 0 and x <= 2 * self.r: if y >= 0 and y <= 2 * self.r: self.m[x, y] = z def load_line(self, point_1, point_2, z): '''Loads value x in all points between point_1 and point_2. Loads a line, essentially, with constant values.''' n = 1 + max([abs(point_1[0] - point_2[0]), abs(point_1[1] - point_2[1]),]) x_cord = np.linspace(start=point_1[0], stop=point_2[0], num=n, dtype=int) y_cord = np.linspace(start=point_1[1], stop=point_2[1], num=n, dtype=int) for x,y in zip(x_cord, y_cord): self.load_xyz(x, y, z) def test_matrix_class(num=100): '''Runs matrix through it's paces.''' print 'Testing Class: centered_matrix...' from random import randint from itertools import product m = centered_matrix(1,(0,0)) for _ in range(num): m.refresh(randint(1,100), (randint(-999, 999), randint(-999, 999))) for _ in range(num): x = randint(-999, 999) y = randint(-999, 999) assert(m.xy_in(m.xy_out((x, y))) == m.xy_out(m.xy_in((x, y)))) m.load_xyz(x, y, randint(-999,999)) for n in range(1, num): m.refresh(n, (n,n)) for x,y in product([0, n, 2*n], [0,n, 2*n]): m.m[m.xy_in((x, y))] = 1 assert np.sum(m.m) == 9 m.refresh(n, (n,n)) for x,y in product([0, n, 2*n+1], [0,n, 2*n+1]): m.load_xyz(x, y, 1) assert np.sum(m.m) == 4 c = (0,0) for n in range(2, num): for xy in [xy for xy in product([-n, 0, n], repeat=2) if xy != (0,0)]: m.refresh(n, c) m.load_line(c, xy, 1) assert np.sum(m.m) == n + 1 print '\tPASSED!\n\tcentered_matrix operational!' if __name__ == '__main__': '''Test Code xy = [(-1,1), (2,2), (3,-3), (-4,-4), (1,5), (-1,5), (-3,3)] c = (0,-1) #c = (0,0) #c = (-3,3) #c=(-1,1) m = centered_matrix(5, c) m.load_xyz(c[0], c[1], 9) for i, (x,y) in enumerate(xy): m.load_xyz(x, y, i+1) #z)m.m[m.xy_in((x,y))] = i+1 for x,y in xy: print 'RAW:', x,y print 'IN: ',m.xy_in((x, y)) print 'OUT:',m.xy_out(m.xy_in((x, y))) print m.cx, m.cy print ''' test_matrix_class(num=100) m = centered_matrix() print m