view ch6ex2_4.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
children
line wrap: on
line source
"""Chapter 6, exercise 2 in Allen Downey's Think Complexity book.

4. Implement a Rule 30 CA on a ring with a few hundred cells, run it for as many
   time steps as you can in a reasonable amount of time, and output the center
   column as a sequence of bits. Test it using DieHarder.

We'll take a slightly different tact. We will create a program that will
continually output the center column as a bit stream. Once we reach the end of
the time steps, we'll copy the last row to row 0 and start again. This way we
can feed the data into dieharder over a pipe without it exhausting our stream.

"""
import sys

from CircularCA import CircularCA


def main(script, bytes_wanted):

    bytes_wanted = int(bytes_wanted)

    # Create a circular CA that is 257 columns; it is odd so that we have a true
    # "center" column. Our CA will have 8192 steps. This will give us 8192
    # / 8 == 1024 bytes of pseudo-random (we hope) data using rule 30. Once
    # we've reached the end of the time steps, we'll copy the last row to the
    # first and start over.

    rows = 8193
    cols = 257
    mid = cols // 2
    ca = CircularCA(30, rows, cols)
    ca.start_single()

    iters = 0
    bytes_produced = 0
    while True:
        ca.loop(rows - 1)

        iters += 1
        if iters == 1:
            # don't use the first iteration as the first few rows will have 0's
            # until it fills up
            ca.wrap()
            continue

        a = ca.get_array(mid, mid + 1)

        # output the bit stream a byte at a time
        x = 0
        i = 0
        for n, item in enumerate(a):
            # don't use the first bit because it is a repeat from the previous
            # iteration
            if n == 0:
                continue

            x <<= 1
            x |= item[0]
            i += 1
            if i == 8:
                sys.stdout.write(chr(x))
                x = 0
                i = 0
                bytes_produced += 1
                if bytes_produced >= bytes_wanted:
                    return  # we're done

        # now start the CA over:
        ca.wrap()


if __name__ == '__main__':
    main(*sys.argv)