Development of ruleset
parent
e3843a7c58
commit
f0790de0e3
|
@ -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))
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue