annotate CircularCA.py @ 42:039249efe42f

Chapter 6, exercise 2, #4. Wrote a program to output the center column of a rule 30 CA as a stream of bytes. It is very slow though. It has to run a very long time to produce enough data for dieharder. Committing it now but will have to let it run overnight or something to generate a large file.
author Brian Neal <bgneal@gmail.com>
date Sun, 13 Jan 2013 16:24:00 -0600
parents ae310a2f42b4
children 6cd37534c12e
rev   line source
bgneal@40 1 """Chapter 6, exercise 1 in Allen Downey's Think Complexity book.
bgneal@40 2
bgneal@40 3 "Create a new class called CircularCA that extends CA so that the cells are
bgneal@40 4 arranged in a ring. Hint: you might find it useful to add a column of 'ghost
bgneal@40 5 cells' to the array."
bgneal@40 6
bgneal@40 7 """
bgneal@40 8
bgneal@40 9 import numpy
bgneal@40 10
bgneal@40 11 from CA import CA
bgneal@40 12
bgneal@40 13
bgneal@40 14 class CircularCA(CA):
bgneal@40 15 """A circular cellular automaton; the cells are arranged in a ring."""
bgneal@40 16
bgneal@42 17 def __init__(self, rule, n=100, m=50):
bgneal@40 18 """Parameters:
bgneal@40 19
bgneal@40 20 * rule: an integer in the range 0-255 that represents the CA rule
bgneal@40 21 using Wolfram's encoding
bgneal@40 22 * n: the number of rows (time steps) in the result
bgneal@42 23 * m: the number of columns
bgneal@40 24
bgneal@40 25 """
bgneal@40 26 self.table = self.make_table(rule)
bgneal@40 27 self.n = n
bgneal@40 28 # a ghost column is added to either end
bgneal@42 29 self.m = m + 2 # add 2 ghost columns
bgneal@40 30 self.array = numpy.zeros((n, self.m), dtype=numpy.int8)
bgneal@40 31 self.next = 0
bgneal@40 32
bgneal@40 33 def start_single(self):
bgneal@40 34 self.array[0, 1] = 1
bgneal@40 35 self.next = 1
bgneal@40 36
bgneal@40 37 def step(self):
bgneal@40 38 """Executes one time step by computing the next row of the array."""
bgneal@40 39 i = self.next
bgneal@40 40 self.next += 1
bgneal@40 41 assert i > 0, 'call start_single() or start_random() first'
bgneal@40 42
bgneal@40 43 a = self.array
bgneal@40 44 t = self.table
bgneal@40 45
bgneal@40 46 # update the ghost cells to enable wrapping
bgneal@40 47 a[i - 1, 0] = a[i - 1, self.m - 2]
bgneal@40 48 a[i - 1, self.m - 1] = a[i - 1, 1]
bgneal@40 49
bgneal@40 50 for j in xrange(1, self.m - 1):
bgneal@40 51 a[i, j] = t[tuple(a[i - 1, j-1:j+2])]
bgneal@40 52
bgneal@42 53 def loop(self, steps=1):
bgneal@42 54 """Executes the given number of time steps."""
bgneal@42 55 for i in xrange(steps):
bgneal@42 56 self.step()
bgneal@40 57
bgneal@40 58 def get_array(self, start=0, end=None):
bgneal@40 59 """Gets a slice of columns from the CA, with slice indices
bgneal@40 60 (start, end).
bgneal@40 61
bgneal@40 62 """
bgneal@40 63 # do not return the ghost columns
bgneal@40 64 if end==None:
bgneal@40 65 return self.array[:, start+1:self.m-1]
bgneal@40 66 else:
bgneal@40 67 return self.array[:, start+1:end+1]
bgneal@40 68
bgneal@42 69 def wrap(self):
bgneal@42 70 """Copies the last row to row 0, then resets the CA to start back at the
bgneal@42 71 top.
bgneal@42 72
bgneal@42 73 """
bgneal@42 74 a = self.array
bgneal@42 75 a[0, :] = a[self.next - 1, :]
bgneal@42 76 self.next = 1
bgneal@42 77
bgneal@40 78
bgneal@40 79 if __name__ == '__main__':
bgneal@40 80
bgneal@40 81 import sys
bgneal@40 82 from CADrawer import PyplotDrawer
bgneal@40 83
bgneal@42 84 def main(script, rule, n, m):
bgneal@40 85 rule = int(rule)
bgneal@40 86 n = int(n)
bgneal@42 87 m = int(m)
bgneal@42 88 ca = CircularCA(rule, n, m)
bgneal@40 89 ca.start_single()
bgneal@40 90 ca.loop(n - 1)
bgneal@40 91
bgneal@40 92 drawer = PyplotDrawer()
bgneal@40 93 drawer.draw(ca)
bgneal@40 94 drawer.show()
bgneal@40 95
bgneal@40 96
bgneal@40 97 main(*sys.argv)