r
/
fifth
1
Fork 0

Development of ruleset

master
jrpotter 2015-05-31 18:13:14 -04:00
parent e3843a7c58
commit f0790de0e3
3 changed files with 95 additions and 23 deletions

View File

@ -8,29 +8,29 @@ import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
class Bit: class Cell:
""" """
Represents a "bit" in a bitplane. Represents a "cell" in a CellPlane.
Note we keep track of the index for vectorization purposes. By maintaining each index Note we keep track of the index for vectorization purposes. By maintaining each index
and batch updating via the given index, we can much more efficiently update the entire and batch updating via the given index, we can much more efficiently update the entire
bitplane. cell plane.
""" """
def __init__(self, value, *index): def __init__(self, value, *index):
self.value = value self.value = value
self.index = index self.index = index
class BitPlane: class CellPlane:
""" """
A BitPlane represents a layer of the grids that can be placed on top of one another in a 2D CAM. A CellPlane represents a layer of the grids that can be placed on top of one another in a 2D CAM.
The use of multiple bit plane allow for more intricate states of life and death, though there The use of multiple cell plane allow for more intricate states of life and death, though there
exists only a single master bit plane that controls the others. That is, the master bit plane has exists only a single master cell plane that controls the others. That is, the master cell plane has
a CAM ruleset applied to it, and the other bit planes merely copy the master, though this can a CAM ruleset applied to it, and the other cell planes merely copy the master, though this can
be delayed and have different color mappings. be delayed and have different color mappings.
For example, by setting a delay of two ticks on the second bit plane of a 2-level CAM configuration, For example, by setting a delay of two ticks on the second cell plane of a 2-level CAM configuration,
one can allow for ECHOing, providing a more intuitive sense of "velocity" based on the master. one can allow for ECHOing, providing a more intuitive sense of "velocity" based on the master.
That is not to say one could not have multiple CAM's operating simultaneously though. We can consider That is not to say one could not have multiple CAM's operating simultaneously though. We can consider
@ -44,18 +44,18 @@ class BitPlane:
""" """
The following joins indices in N-dimensions together. The following joins indices in N-dimensions together.
This information is stored in a bit (with initial value False) in order for batch processing This information is stored in a cell (with initial value False) in order for batch processing
to be performed when actually updating values and computing whether a bit is on or off. For to be performed when actually updating values and computing whether a cell is on or off. For
example, if exploring a 4D array, we want to be able to know which bits we need to check the example, if exploring a 4D array, we want to be able to know which cells we need to check the
status of, but this is relative to the current bit, whose position we do not know unless that status of, but this is relative to the current cell, whose position we do not know unless that
information is stored with the current bit. information is stored with the current cell.
""" """
return Bit(False, *indices) return Cell(False, *indices)
def __init__(self, dimen): def __init__(self, dimen):
""" """
""" """
self.grid = BitPlane._populate(*np.indices(dimen)) self.grid = CellPlane._populate(*np.indices(dimen))

View File

@ -1,6 +1,8 @@
""" """
@author: jrpotter
@date: May 31st, 2015
""" """
import itertools import itertools
@ -70,25 +72,25 @@ class Neighborhood:
self.offsets = {} self.offsets = {}
def neighbors(self, bit, grid, wrap_around=True): def neighbors(self, cell, grid, wrap_around=True):
""" """
Returns all bits in the given neighborhood. Returns all cells in the given neighborhood.
The returned cells are grouped with the value the cell is checked to be (a 2-tuple (Bit, value) pair). The returned cells are grouped with the value the cell is checked to be (a 2-tuple (Cell, value) pair).
These are sorted based on the NeighborhoodKey comparison class defined above. These are sorted based on the NeighborhoodKey comparison class defined above.
""" """
bits = [] cells = []
for k in sorted(self.offsets.keys()): for k in sorted(self.offsets.keys()):
position = [sum(x) for x in zip(bit.index, k)] position = [sum(x) for x in zip(cell.index, k)]
for i in range(len(position)): for i in range(len(position)):
if wrap_around: if wrap_around:
position[i] = position[i] % grid.shape[i] position[i] = position[i] % grid.shape[i]
elif i < 0 or i >= grid.shape[i]: elif i < 0 or i >= grid.shape[i]:
break break
else: else:
bits.append(grid[tuple(position)]) cells.append((grid[tuple(position)], self.offsets[k]))
return bits return cells
def extend(self, offsets, strict=False): def extend(self, offsets, strict=False):

70
src/ruleset.py Normal file
View File

@ -0,0 +1,70 @@
"""
@author: jrpotter
@date: May 31st, 2015
"""
class Ruleset:
"""
The following determines the next state of a given cell in a CAM.
Given a neighborhood and a tolerance level, the ruleset determines whether a given cell should be on or off after a tick.
For example, if the tolerance level is set to 100% (i.e. neighborhoods must exactly match desired neighborhood to be on),
then the ruleset iterates through all neighbors and verifies a match.
For the sake of clarity, we consider a neighborhood to actually contain the "rules" for matching, and a ruleset to be the
application of the rules as defined in the neighborhood. We state this since the actual expected values are declared in
a neighborhood instance's offsets member.
"""
def __init__(self, grid, wrap_around=True):
"""
"""
self.grid = grid
self.wrap_around = wrap_around
def matches(self, cell, neighborhood):
"""
Determines that neighborhood matches expectation exactly.
Note this is just like the tolerate method with a tolerance of 1, but
recoding allows for short circuiting.
"""
residents = neighborhood.neighbors(cell, self.grid, self.wrap_around)
for resident in residents:
if resident[0].value != resident[1]:
return False
return True
def tolerate(self, cell, neighborhood, tolerance):
"""
Determines that neighborhood matches expectation within tolerance.
We see that the percentage of actual matches are greater than or equal to the given tolerance level. If so, we
consider this cell to be alive. Note tolerance must be a value 0 <= t <= 1.
"""
matches = 0
residents = neighborhood.neighbors(cell, self.grid, self.wrap_around)
for resident in residents:
if resident[0].value == resident[1]:
matches += 1
return (matches / len(residents)) >= tolerance
def satisfies(self, cell, neighborhood, valid_func):
"""
Allows custom function to relay next state of given cell.
The passed function is supplied the list of 2-tuple elements, of which the first is a Cell and the second is
the expected state as declared in the Neighborhood, as well as the grid and cell in question.
"""
residents = neighborhood.neighbors(cell, self.grid, self.wrap_around)
return valid_func(cell, self.grid, residents)