r
/
fifth
1
Fork 0

3x speed increase; not quite functional

master
Joshua Potter 2015-06-06 19:07:52 -04:00
parent e931af0020
commit e64dfa9e79
11 changed files with 83 additions and 51 deletions

View File

@ -10,11 +10,10 @@ if __name__ == '__main__':
sys.path.append(os.path.abspath('src'))
import cam
import util as u
import ruleset as rs
import cam_parser
c = cam.CAM(1, 100, 2)
p = u.CAMParser('B368/S23', c)
p = cam_parser.CAMParser('B368/S23', c)
c.randomize()
c.start_plot(100, p.ruleset)

View File

@ -10,11 +10,10 @@ if __name__ == '__main__':
sys.path.append(os.path.abspath('src'))
import cam
import util as u
import ruleset as rs
import cam_parser
c = cam.CAM(1, 100, 2)
p = u.CAMParser('B3/S23', c)
p = cam_parser.CAMParser('B3/S23', c)
c.randomize()
c.start_plot(400, p.ruleset)
c.start_plot(100, p.ruleset)

View File

@ -10,11 +10,10 @@ if __name__ == '__main__':
sys.path.append(os.path.abspath('src'))
import cam
import util as u
import ruleset as rs
import cam_parser
c = cam.CAM(1, 100, 2)
p = u.CAMParser('B3/S012345678', c)
p = cam_parser.CAMParser('B3/S012345678', c)
c.randomize()
c.start_plot(100, p.ruleset)

View File

@ -10,11 +10,10 @@ if __name__ == '__main__':
sys.path.append(os.path.abspath('src'))
import cam
import util as u
import ruleset as rs
import cam_parser
c = cam.CAM(1, 100, 2)
p = u.CAMParser('B368/S245', c)
p = cam_parser.CAMParser('B368/S245', c)
c.randomize()
c.start_plot(100, p.ruleset)

View File

@ -10,11 +10,10 @@ if __name__ == '__main__':
sys.path.append(os.path.abspath('src'))
import cam
import util as u
import ruleset as rs
import cam_parser
c = cam.CAM(1, 100, 2)
p = u.CAMParser('B1357/S1357', c)
p = cam_parser.CAMParser('B1357/S1357', c)
c.randomize()
c.start_plot(100, p.ruleset)

View File

@ -10,11 +10,10 @@ if __name__ == '__main__':
sys.path.append(os.path.abspath('src'))
import cam
import cam_util as u
import ruleset as rs
import cam_parser
c = cam.CAM(1, 100, 2)
p = u.CAMParser('B2/S', c)
p = cam_parser.CAMParser('B2/S', c)
c.randomize()
c.start_plot(100, p.ruleset)

View File

@ -7,6 +7,8 @@ all methods needed (i.e. supported) to interact/configure with the cellular auto
@date: June 01, 2015
"""
import plane
import time
import matplotlib.pyplot as plt
import matplotlib.animation as ani
@ -37,10 +39,12 @@ class CAM:
plane_count = max(cps, 1)
grid_dimen = (states,) * dimen
self.planes = [Plane(grid_dimen) for i in range(cps)]
self.planes = [plane.Plane(grid_dimen) for i in range(cps)]
self.master = self.planes[0]
self.ticks = [(0, 1)]
self.total = 0
def tick(self, rules, *args):
"""
Modify all states in a given CAM "simultaneously".
@ -53,7 +57,8 @@ class CAM:
self.total += 1
for i, j in self.ticks:
if self.total % j == 0:
rules.applyTo(self.planes[i], *args)
rules.apply_to(self.planes[i], *args)
def start_plot(self, clock, rules, *args):
"""
@ -68,17 +73,18 @@ class CAM:
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
mshown = plt.matshow(self.planes[0].bits(), fig.number, cmap='Greys')
mshown = plt.matshow(self.master.bits(), fig.number, cmap='Greys')
def animate(frame):
self.tick(rules, *args)
mshown.set_array(self.planes[0].bits())
mshown.set_array(self.master.bits())
return [mshown]
ani.FuncAnimation(fig, animate, interval=clock)
plt.axis('off')
plt.show()
def start_console(self, clock, rules, *args):
"""
Initates main console loop.
@ -87,7 +93,17 @@ class CAM:
TODO: Incorporate curses, instead of just printing repeatedly.
"""
while True:
print(self.planes[0].bits())
print(self.master.bits())
time.sleep(clock / 1000)
self.tick(rules, *args)
def randomize(self):
"""
Convenience function to randomize individual planes.
"""
self.master.randomize()
for plane in self.planes[1:]:
plane.grid = self.master.grid

View File

@ -53,7 +53,7 @@ class CAMParser:
"""
self.sfunc = None
self.offsets = c.Configuration.moore(cam.master)
self.ruleset = r.Ruleset(rsRuleset.Method.ALWAYS_PASS)
self.ruleset = r.Ruleset(r.Ruleset.Method.ALWAYS_PASS)
if re.match(CAMParser.MCELL_FORMAT, notation):
x, y = notation.split('/')
@ -98,12 +98,11 @@ class CAMParser:
Conway's Game of Life is denoted 23/3
"""
x, y = list(map(int, x)), list(map(int, y))
def next_state(f_index, f_grid, indices, states, *args):
total = sum(f_grid[indices])
if f_grid[f_index]:
return int(total in x)
def next_state(plane, neighborhood, *args):
if plane.grid.flat[neighborhood.flat_index]:
return int(neighborhood.total in x)
else:
return int(total in y)
return int(neighborhood.total in y)
return next_state

View File

@ -21,6 +21,8 @@ with the ALWAYS_PASS flag set in the given ruleset the configuration is bundled
@date: June 5th, 2015
"""
import numpy as np
from itertools import product
from collections import namedtuple
@ -104,8 +106,8 @@ class Configuration:
Note the center cell is excluded, so the total number of offsets are 3^N - 1.
"""
offsets = {}
variants = ([-1, 0, 1],) * len(grid.shape)
for current in it.product(*variants):
variants = ([-1, 0, 1],) * len(plane.shape)
for current in product(*variants):
if any(current):
offsets[current] = value
@ -124,7 +126,7 @@ class Configuration:
Note the center cell is excluded, so the total number of offsets are 2N.
"""
offsets = []
variant = [0] * len(grid.shape)
variant = [0] * len(plane.shape)
for i in range(len(variant)):
for j in [-1, 1]:
variant[i] = j
@ -159,7 +161,7 @@ class Configuration:
"""
for coor, bit in offsets.items():
flat_index, bit_index = plane.flatten(coor)
self.offsets.append(Offset(flat_index, bit_index, bit))
self.offsets.append(Configuration.Offset(flat_index, bit_index, bit))
def passes(self, plane, neighborhood, vfunc, *args):

View File

@ -44,7 +44,7 @@ class Plane:
else:
self.grid = np.empty(shape[:-1], dtype=np.object)
for i in range(self.grid.size):
self.grid.flat[i] = bitarray(self.N)
self.grid.flat[i] = self.N * bitarray('0')
def __getitem__(self, index):
@ -95,17 +95,21 @@ class Plane:
"""
Sets values of grid to random values.
Since numbers of the grid may be larger than numpy can handle natively (i.e. too big
for C long types), we use the python random module instead.
By default, newly initialized bitarrays are random, but in a weird way I'm not sure I
understand. For example, constructing bitarrays in a loop appear to set every bitarray
after the first to 0, and, if I put a print statement afterwards, all bitarrays maintain
the same value. I'm not really too interested in figuring this out, so I use the alternate
method below.
"""
if len(self.shape) > 0:
import random as r
max_u = 2**self.N - 1
gen = lambda: bin(r.randrange(0, max_u))[2:]
if len(self.shape) == 1:
self.grid = r.randrange(0, max_u)
self.grid = bitarray(gen().zfill(self.N))
else:
tmp = np.array([r.randrange(0, max_u) for i in range(len(self.grid))])
self.grid = tmp.reshape(self.grid.shape)
for i in range(self.grid.size):
self.grid.flat[i] = bitarray(gen().zfill(self.N))
def flatten(self, coordinate):
@ -118,6 +122,21 @@ class Plane:
flat_index, gridprod = 0, 1
for i in reversed(range(len(coordinate[:-1]))):
flat_index += coordinate[i] * gridprod
gridprod *= shape[i]
gridprod *= self.shape[i]
return flat_index, coordinate[-1]
def bits(self):
"""
Expands out bitarray into individual bits.
This is useful for display in matplotlib for example, but does take a dimension more space.
"""
if len(self.shape) == 1:
return np.array(self.grid)
else:
tmp = np.array([list(self.grid.flat[i]) for i in range(self.grid.size)])
return np.reshape(tmp, self.shape)

View File

@ -7,8 +7,9 @@ said neighborhood that yield an "on" or "off" state on the cell a ruleset is bei
@date: May 31st, 2015
"""
import enum
import numpy as np
import configuration as c
from bitarray import bitarray
class Ruleset:
@ -71,8 +72,8 @@ class Ruleset:
# either all bits pass or configurations are exhausted
for flat_index, value in enumerate(plane.grid.flat):
next_row = bitarray(self.N)
to_update = range(0, self.N)
next_row = bitarray(plane.N)
to_update = range(0, plane.N)
for config in self.configurations:
next_update = []
@ -86,17 +87,18 @@ class Ruleset:
# no overflowing of a single column can occur. We can then find the total of the ith neighborhood by checking the
# sum of the ith index of the summation of every 9 chunks of numbers (this is done a row at a time).
neighboring = []
for flat_offset, bit_offset in config.offsets:
neighbor = plane.grid.flat[flat_index + flat_offset]
for flat_offset, bit_offset, _ in config.offsets:
neighbor = plane.grid.flat[(flat_index + flat_offset) % plane.N]
cycled = neighbor[bit_offset:] + neighbor[:bit_offset]
neighboring.append(int(cycled.to01()))
# Chunk into groups of 9 and sum all values
# These summations represent the total number of active states in a given neighborhood
totals = [0] * self.N
chunks = map(sum, [offset_totals[i:i+9] for i in range(0, len(neighboring), 9)])
totals = [0] * plane.N
chunks = list(map(sum, [neighboring[i:i+9] for i in range(0, len(neighboring), 9)]))
for chunk in chunks:
totals = list(map(sum, zip(totals, chunk)))
i_chunk = list(map(int, str(chunk).zfill(plane.N)))
totals = list(map(sum, zip(totals, i_chunk)))
# Determine which function should be used to test success
if self.method == Ruleset.Method.MATCH:
@ -110,8 +112,8 @@ class Ruleset:
# Apply change to all successful configurations
for bit_index in to_update:
neighborhood = Neighborhood(flat_index, bit_index, totals[bit_index])
success, state = config.passes(neighborhood, vfunc, *args)
neighborhood = c.Neighborhood(flat_index, bit_index, totals[bit_index])
success, state = config.passes(plane, neighborhood, vfunc, *args)
if success:
next_row[bit_index] = state
else: