Source code for dynpy.ca
"""Module implementing Cellular automaton dynamical systems.
"""
from __future__ import division, print_function, absolute_import
import six
range = six.moves.range
map = six.moves.map
import numpy as np
from itertools import product as iprod
from . import bn
from .cutils import int2tuple
[docs]
class CellularAutomaton(bn.BooleanNetwork):
"""Cellular automaton object. Constructs an underlying
:class:`dynpy.bn.BooleanNetwork` on a lattice and with a homogenous update
function. Implements periodic boundary conditions.
For example:
>>> from dynpy.ca import CellularAutomaton
>>> import numpy as np
>>> ca = CellularAutomaton(num_vars=50, num_neighbors=1, rule=110)
>>> init_state = np.zeros(ca.num_vars, dtype='uint8')
>>> init_state[int(ca.num_vars/2)] = 1
>>> for line in ca.get_trajectory(init_state, 10):
... print("".join('#' if e == 1 else '-' for e in line))
-------------------------#------------------------
------------------------##------------------------
-----------------------###------------------------
----------------------##-#------------------------
---------------------#####------------------------
--------------------##---#------------------------
-------------------###--##------------------------
------------------##-#-###------------------------
-----------------#######-#------------------------
----------------##-----###------------------------
Parameters
----------
num_vars : int or list
The number of cells in the automaton (i.e. the size of the automaton).
If dim > 1, then this must be list indicating the number of variables
in each dimension.
num_neighbors : int
Number of neighbors in each direction that the update rule depends on.
rule : int or list
If mode is 'RULENUMBER', then this should be the update rule, specified
as a number representing the truth table of each node. If mode is
'TRUTHTABLE', this should be a list specifying the truthtable.
mode : {'RULENUMBER','TRUTHTABLE','FUNC'} (default 'RULENUMBER')
How the rules parameter should be interpreted.
dim : int (default 1)
Dimensionality of cellular automata lattice.
"""
def __init__(self, num_vars, num_neighbors, rule, mode="RULENUMBER", dim=1):
if dim <= 0:
raise ValueError('dim must be strictly positive')
elif dim == 1 and not isinstance(num_vars, list):
num_vars = [num_vars,]
if not isinstance(num_vars, list) or len(num_vars) != dim:
raise ValueError('num_vars should be list with %d elements' % dims)
all_vars = np.array(list(iprod( *[list(range(d)) for d in num_vars] )))
total_num_vars = len(all_vars)
all_var_ndxs = { tuple(v):ndx for ndx, v in enumerate(all_vars) }
neighbor_offsets = np.array(list(iprod(*
[list(range(-num_neighbors,num_neighbors+1))
for d in num_vars])))
if mode == 'FUNC':
updaterule = self._updatefunc_to_truthtables(len(neighbor_offsets), rule)
elif mode == "RULENUMBER":
all_neighbor_cnt = (2*num_neighbors)**dim
updaterule = list(int2tuple(rule, 2**(all_neighbor_cnt+1)))
elif mode == "TRUTHTABLE":
updaterule = rule
else:
raise ValueError("Unknown mode %s" % mode)
rules = []
for v in all_vars:
conns = []
coffsets = v+neighbor_offsets
conn_address = zip(*[(coffsets[:,d] % num_vars[d])
for d in range(dim)])
conns = [all_var_ndxs[v] for v in conn_address]
rules.append([tuple(v), conns, updaterule])
super(CellularAutomaton,self).__init__(
rules=rules, mode='TRUTHTABLES')