Cellular Automata

Cellular automata are a special type of network. They can be envisioned at a boolean networks wherein every node has exactly 3 incoming edges. The neet.automata modules provides two submodules, neet.automata.eca and neet.automata.reca. As a convenience, the classes in each are exposed in the neet.automata, so you never have to reference the submodules unless you so choose.

API Documentation

Elementary Cellular Automata

The neet.automata.eca.ECA class describes an Elementary Cellular Automaton with an arbitrary rule. The ECA class is not a fixed sized network. This means that the size is determined when it is used based on arguments passed to the relevant methods or functions.

Examples

>>> ca = ECA(30)
>>> ca.update([0, 0, 1, 0, 0])
[0, 1, 1, 1, 0]
>>> ca.update([0, 1, 0])
[1, 1, 1]
>>> transitions(ca, size=3)
[[0, 0, 0], [1, 1, 1], [1, 1, 1], [1, 0, 0], [1, 1, 1], [0, 0, 1], [0, 1, 0], [0, 0, 0]]
class neet.automata.eca.ECA(code, boundary=None)[source]

ECA is a class to represent elementary cellular automaton rules. Each ECA contains an 8-bit integral member variable code representing the Wolfram code for the ECA rule and a set of boundary conditions which is either None, signifying periodic boundary conditions, or a pair of cell states signifying fixed, open boundary conditions.

__init__(code, boundary=None)[source]

Construct an elementary cellular automaton rule.

Examples

>>> ca = ECA(30)
>>> ca.code
30
>>> ca.boundary
>>> ca = ECA(30, boundary=(0,0))
>>> ca.boundary
(0, 0)
Parameters:
  • code (int) – the Wolfram code for the ECA
  • boundary (tuple or None) – the boundary conditions for the CA
Raises:
  • TypeError – if code is not an instance of int
  • ValueError – if code is not in \(\{0,1,\ldots,255\}\)
  • TypeError – if boundary is neither None or an instance of tuple
  • ValueError – if boundary is a neither None or a pair of binary states
code

The Wolfram code of the elementary cellular automaton

Examples

>>> eca = ECA(30)
>>> eca.code
30
>>> eca.code = 45
>>> eca.code
45
>>> eca.code = 256
Traceback (most recent call last):
    ...
ValueError: invalid ECA code
Type:

int

Raises:
  • TypeError – if code is not an instance of int
  • ValueError – if code is not in \(\{0,1,\ldots,255\}\)
boundary

The boundary conditions of the elemenary cellular automaton

Examples

>>> eca = ECA(30)
>>> eca.boundary
>>> eca.boundary = (0,1)
>>> eca.boundary
(0, 1)
>>> eca.boundary = None
>>> eca.boundary
>>> eca.boundary = [0,1]
Traceback (most recent call last):
    ...
TypeError: ECA boundary are neither None nor a tuple
Type:

None or tuple

Raises:
  • TypeError – if boundary is neither None or an instance of tuple
  • ValueError – if boundary is a neither None or a pair of binary states
state_space(n)[source]

Return a neet.statespace.StateSpace object for a lattice of length n.

>>> eca = ECA(30)
>>> eca.state_space(3)
<neet.statespace.StateSpace object at 0x...>
>>> space = eca.state_space(3)
>>> list(space)
[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]]
Parameters:n (int) – the number of nodes in the lattice
Returns:neet.statespace.StateSpace
Raises:ValueError – if n < 1
update(lattice, index=None, pin=None, values=None)[source]

Update the state of the lattice in place.

Basic Use:

>>> ca = ECA(30)
>>> xs = [0,0,1,0,0]
>>> ca.update(xs)
[0, 1, 1, 1, 0]
>>> ca.boundary = (1,1)
>>> ca.update([0,0,1,0,0])
[1, 1, 1, 1, 1]

Single-Node Update:

>>> ca.boundary = None
>>> xs = [0,0,1,0,0]
>>> ca.update(xs, index=1)
[0, 1, 1, 0, 0]
>>> xs
[0, 1, 1, 0, 0]
>>> ca.boundary = (1,1)
>>> ca.update(xs, index=-1)
[0, 1, 1, 0, 1]

State Pinning:

>>> ca.boundary = None
>>> xs = [0,0,1,0,0]
>>> ca.update(xs, pin=[-2])
[0, 1, 1, 0, 0]
>>> ca.boundary = (1,1)
>>> ca.update(xs, pin=[4])
[0, 1, 0, 1, 0]

Value Fixing:

>>> ca.boundary = None
>>> xs = [0,0,1,0,0]
>>> ca.update(xs, values={0:1,-2:0})
[1, 1, 1, 0, 0]
>>> ca.boundary = (1,1)
>>> xs = [1,1,1,0,0]
>>> ca.update(xs, values={1:0,-1:0})
[0, 0, 0, 1, 0]

Erroneous Usage:

>>> xs = []
>>> ca.update(xs)
Traceback (most recent call last):
...
ValueError: lattice is empty
>>> xs = [0,0,2,0,0]
>>> ca.update(xs)
Traceback (most recent call last):
...
ValueError: invalid value "2" in lattice
>>> ca.update(xs, index=5)
Traceback (most recent call last):
...
ValueError: the provided state is not in the ECA's state space
>>> ca.update([0,0,1,0,0,], index=1, pin=[0])
Traceback (most recent call last):
...
ValueError: cannot provide both the index and pin arguments
>>> ca.update([0,0,1,0,0], index=1, values={0:0})
Traceback (most recent call last):
...
ValueError: cannot provide both the index and values arguments
>>> ca.update([0,0,1,0,0], pin=[2], values={2:0})
Traceback (most recent call last):
...
ValueError: cannot set a value for a pinned state
>>> ca.update([0,0,1,0,0], values={2:2})
Traceback (most recent call last):
...
ValueError: invalid state in values argument
Parameters:
  • lattice – the one-dimensional sequence of states
  • index – the index to update (or None)
  • pin – a sequence of indicies to pin (or None)
  • values – a dictionary of index-value pairs to fix after update
Returns:

the updated lattice

Raises:
  • ValueError – if lattice is not in the ECA’s state space
  • IndexError – if index is not None and index > len(states)
  • ValueError – if index and pin are both provided
  • ValueError – if index and values are both provided
  • ValueError – if an element of pin is a key in values
  • ValueError – if a value in values is not binary (0 or 1)
neighbors_in(index, size, **kwargs)[source]

Return the set of all incoming neighbor nodes.

In the cases of the lattices having fixed boundary conditions, the left boundary, being on the left of the leftmost index 0, has an index of -1, while the right boundary’s index is the size+1. The full state of the lattices and the boundaries is equavolent to: [cell0, cell1, …, cellN, right_boundary, left_boundary] if it is ever presented as a single list in Python.

Parameters:
  • index – node index
  • size – size of ECA
Returns:

the set of all node indices which point toward the index node

Raises:

ValueError – if index < 0 or index > n - 1

Basic Use:

>>> net = ECA(30)
>>> net.neighbors_in(1, size=3)
{0, 1, 2}
>>> net.neighbors_in(2, size=3)
{0, 1, 2}
>>> net.boundary = (1,1)
>>> net.neighbors_in(2, size=3)
{1, 2, 3}
>>> net.neighbors_in(0, 3)
{0, 1, -1}

Erroneous Usage:

>>> net = ECA(30,boundary=(1, 1))
>>> net.neighbors_in(5, 3)
Traceback (most recent call last):
    ...
ValueError: index must be a non-negative integer less than size
neighbors_out(index, size)[source]

Return the set of all outgoing neighbor nodes.

Fixed boundaries are excluded as they are not affected by internal states.

Parameters:
  • index – node index
  • size – size of ECA
Returns:

the set of all node indices which point from the index node

Raises:

ValueError – if index < 0 or index > n - 1

Basic Use:

>>> net = ECA(30)
>>> net.neighbors_out(1, 3)
{0, 1, 2}
>>> net.neighbors_out(2, 3)
{0, 1, 2}
>>> net.boundary = (1, 1)
>>> net.neighbors_out(2, 3)
{1, 2}
>>> net.neighbors_out(0, 3)
{0, 1}

Erroneous Usage:

>>> net = ECA(30,boundary=(1, 1))
>>> net.neighbors_out(5, 3)
Traceback (most recent call last):
    ...
ValueError: index must be a non-negative integer less than size
neighbors(index, size)[source]

Return a set of neighbors for a specified node.

In the cases of the lattices having fixed boundary conditions, the left boundary, being on the left of the leftmost index 0, has an index of -1, while the right boundary’s index is the size+1. The full state of the lattices and the boundaries is equavolent to: [cell0, cell1, …, cellN, right_boundary, left_boundary] if it is ever presented as a single list in Python.

Parameters:
  • index – node index
  • size – size of ECA
Returns:

the set of all node indices adjacent to the index node

Raises:

ValueError – if index < 0 or index > n - 1

Basic Use:

>>> net = ECA(30)
>>> net.neighbors(1, size=3)
{0, 1, 2}
>>> net.neighbors(2, size=3)
{0, 1, 2}
>>> net.boundary = (1,1)
>>> net.neighbors(2, size=3)
{1, 2, 3}
>>> net.neighbors(0, 3)
{0, 1, -1}

Erroneous Usage:

>>> net = ECA(30,boundary=(1, 1))
>>> net.neighbors(5, 3)
Traceback (most recent call last):
    ...
ValueError: index must be a non-negative integer less than size
to_networkx_graph(size)[source]

Return networkx graph given neet network. Requires networkx.

Parameters:size – size of ECA, required if network is an ECA
Returns:a networkx.DiGraph
draw(size, filename=None)[source]

Output a file with a simple network drawing.

Requires networkx and pygraphviz.

Supported image formats are determined by graphviz. In particular, pdf support requires ‘cairo’ and ‘pango’ to be installed prior to graphviz installation.

Parameters:
  • filename – filename to write drawing to. Temporary filename will be used if no filename provided.
  • size – size of ECA, required if network is an ECA
Returns:

a pygraphviz network drawing

Rewired Elementary Cellular Automata

The neet.automata.reca.RewiredECA implements a variant of an ECA wherein the neighbors of a give cell can be specified by the user. This allows one to study, for example, the role of topology in the dynamics of a network. Every ECA can be represented as a RewiredECA with standard wiring, but all RewiredECA are fixed sized networks.

Examples

>>> ca = RewiredECA(30, size=3)
>>> ca.update([0, 1, 0])
[1, 1, 1]
>>> ca = RewiredECA(30, wiring=[[0,1,3], [1,1,1], [2,1,2]])
>>> ca.update([0, 1, 0])
[1, 0, 1]
class neet.automata.reca.RewiredECA(code, boundary=None, size=None, wiring=None)[source]

RewiredECA is a class to represent elementary cellular automata rules with arbitrarily defined topology. Since the topology must be provided, RewiredECA are naturally fixed-sized.

__init__(code, boundary=None, size=None, wiring=None)[source]

Construct a rewired elementary cellular automaton rule.

Examples

>>> reca = RewiredECA(30, size=3)
>>> reca.code
30
>>> reca.size
3
>>> reca.wiring
array([[-1,  0,  1],
       [ 0,  1,  2],
       [ 1,  2,  3]])
>>> reca = RewiredECA(30, wiring=[[0,1,2],[-1,0,0],[2,3,1]])
>>> reca.code
30
>>> reca.size
3
>>> reca.wiring
array([[ 0,  1,  2],
       [-1,  0,  0],
       [ 2,  3,  1]])
Parameters:
  • code (int) – the 8-bit Wolfram code for the rule
  • boundary (tuple or None) – the boundary conditions for the CA
  • size (int or None) – the number of cells in the lattice
  • wiring – a wiring matrix
Raises:
  • ValueError – if size is None and wiring is None
  • ValueError – if size is not None and wiring is not None
  • TypeError – if size is not None and not isinstance(size, int)
  • ValueError – if size is not None and size <= 0
  • TypeError – if not isinstance(wiring, list) and not isinstance(wiring, numpy.ndarray)
  • ValueError – if wiring is not \(3 imes N\)
  • ValueError – if any(wiring < -1) or any(wiring > N)
code

The Wolfram code of the elementary cellular automaton

Examples

>>> eca = ECA(30)
>>> eca.code
30
>>> eca.code = 45
>>> eca.code
45
>>> eca.code = 256
Traceback (most recent call last):
    ...
ValueError: invalid ECA code
Type:

int

Raises:
  • TypeError – if code is not an instance of int
  • ValueError – if code is not in \(\{0,1,\ldots,255\}\)
boundary

The boundary conditions of the elemenary cellular automaton

Examples

>>> eca = ECA(30)
>>> eca.boundary
>>> eca.boundary = (0,1)
>>> eca.boundary
(0, 1)
>>> eca.boundary = None
>>> eca.boundary
>>> eca.boundary = [0,1]
Traceback (most recent call last):
    ...
TypeError: ECA boundary are neither None nor a tuple
Type:

None or tuple

Raises:
  • TypeError – if boundary is neither None or an instance of tuple
  • ValueError – if boundary is a neither None or a pair of binary states
size

The number of cells in the CA lattice.

Examples

>>> eca = RewiredECA(30, size=3)
>>> eca.size
3
>>> eca = RewiredECA(30, wiring=[[-1,0], [0,1], [1,0]])
>>> eca.size
2
Type:int
wiring

The wiring matrix for the rule.

Examples

>>> reca = RewiredECA(30, size=3)
>>> reca.wiring
array([[-1,  0,  1],
       [ 0,  1,  2],
       [ 1,  2,  3]])
>>> eca = RewiredECA(30, wiring=[[0,1],[1,1],[-1,-1]])
>>> eca.wiring
array([[ 0,  1],
       [ 1,  1],
       [-1, -1]])
Type:numpy.ndarray
state_space()[source]

Return a neet.statespace.StateSpace object for the cellular automaton lattice.

Examples

>>> eca = RewiredECA(30, size=3)
>>> eca.state_space()
<neet.statespace.StateSpace object at 0x...>
>>> space = eca.state_space()
>>> list(space)
[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]]
Returns:neet.statespace.StateSpace
update(lattice, index=None, pin=None, values=None)[source]

Update the state of the lattice in place.

Examples

>>> reca = RewiredECA(30, size=5)
>>> reca.update([1,0,0,0,0])
[1, 1, 0, 0, 1]
>>> reca.wiring[:,:] = [[-1, 2, 1, 2, -1], [0, 1, 2, 3, 4], [0, 2, 3, 4, 5]]
>>> reca.update([0,0,1,0,0])
[0, 0, 1, 1, 0]
>>> reca.update([1,1,1,1,1])
[0, 0, 0, 0, 0]
>>> reca.update([1,1,1,1,1], index=2)
[1, 1, 0, 1, 1]
>>> reca.update([1,1,1,1,1], pin=[1, 3])
[0, 1, 0, 1, 0]
>>> reca.update([1,1,1,1,1], values={0: 1, -1: 1})
[1, 0, 0, 0, 1]
Parameters:
  • lattice – the one-dimensional sequence of states
  • index – the index to update (optional)
  • pin – a sequence of indices to fix (optional)
  • values – a dict of index/value pairs to set (optional)
Returns:

the updated lattice

neighbors_in(index, size, **kwargs)

Return the set of all incoming neighbor nodes.

In the cases of the lattices having fixed boundary conditions, the left boundary, being on the left of the leftmost index 0, has an index of -1, while the right boundary’s index is the size+1. The full state of the lattices and the boundaries is equavolent to: [cell0, cell1, …, cellN, right_boundary, left_boundary] if it is ever presented as a single list in Python.

Parameters:
  • index – node index
  • size – size of ECA
Returns:

the set of all node indices which point toward the index node

Raises:

ValueError – if index < 0 or index > n - 1

Basic Use:

>>> net = ECA(30)
>>> net.neighbors_in(1, size=3)
{0, 1, 2}
>>> net.neighbors_in(2, size=3)
{0, 1, 2}
>>> net.boundary = (1,1)
>>> net.neighbors_in(2, size=3)
{1, 2, 3}
>>> net.neighbors_in(0, 3)
{0, 1, -1}

Erroneous Usage:

>>> net = ECA(30,boundary=(1, 1))
>>> net.neighbors_in(5, 3)
Traceback (most recent call last):
    ...
ValueError: index must be a non-negative integer less than size
neighbors_out(index, size)

Return the set of all outgoing neighbor nodes.

Fixed boundaries are excluded as they are not affected by internal states.

Parameters:
  • index – node index
  • size – size of ECA
Returns:

the set of all node indices which point from the index node

Raises:

ValueError – if index < 0 or index > n - 1

Basic Use:

>>> net = ECA(30)
>>> net.neighbors_out(1, 3)
{0, 1, 2}
>>> net.neighbors_out(2, 3)
{0, 1, 2}
>>> net.boundary = (1, 1)
>>> net.neighbors_out(2, 3)
{1, 2}
>>> net.neighbors_out(0, 3)
{0, 1}

Erroneous Usage:

>>> net = ECA(30,boundary=(1, 1))
>>> net.neighbors_out(5, 3)
Traceback (most recent call last):
    ...
ValueError: index must be a non-negative integer less than size
neighbors(index, size)

Return a set of neighbors for a specified node.

In the cases of the lattices having fixed boundary conditions, the left boundary, being on the left of the leftmost index 0, has an index of -1, while the right boundary’s index is the size+1. The full state of the lattices and the boundaries is equavolent to: [cell0, cell1, …, cellN, right_boundary, left_boundary] if it is ever presented as a single list in Python.

Parameters:
  • index – node index
  • size – size of ECA
Returns:

the set of all node indices adjacent to the index node

Raises:

ValueError – if index < 0 or index > n - 1

Basic Use:

>>> net = ECA(30)
>>> net.neighbors(1, size=3)
{0, 1, 2}
>>> net.neighbors(2, size=3)
{0, 1, 2}
>>> net.boundary = (1,1)
>>> net.neighbors(2, size=3)
{1, 2, 3}
>>> net.neighbors(0, 3)
{0, 1, -1}

Erroneous Usage:

>>> net = ECA(30,boundary=(1, 1))
>>> net.neighbors(5, 3)
Traceback (most recent call last):
    ...
ValueError: index must be a non-negative integer less than size
to_networkx_graph(size)

Return networkx graph given neet network. Requires networkx.

Parameters:size – size of ECA, required if network is an ECA
Returns:a networkx.DiGraph
draw(size, filename=None)

Output a file with a simple network drawing.

Requires networkx and pygraphviz.

Supported image formats are determined by graphviz. In particular, pdf support requires ‘cairo’ and ‘pango’ to be installed prior to graphviz installation.

Parameters:
  • filename – filename to write drawing to. Temporary filename will be used if no filename provided.
  • size – size of ECA, required if network is an ECA
Returns:

a pygraphviz network drawing