CA code

61 days ago by eviatarbach

%hide %cython """ SAGE/Python Cellular Automata Toolkit (PYCA) 0.2.1, by Iztok Jeras """ cdef extern from "numpy/arrayobject.h": ctypedef int intp ctypedef extern class numpy.ndarray [object PyArrayObject]: cdef char *data cdef int nd cdef intp *dimensions cdef intp *strides cdef int flags def ca1d_next_generic (int k, int m, ndarray f, int N, ndarray Cc, ndarray Cn) : """ Generic version of 1D CA processor. INPUTS: int k -- number of states per cell int m -- number of cells inside a neighborhood ndarray f -- local transition function int N -- configuration size ndarray Cc -- cell configuration ndarray Cn -- neighborhood configuration (nut used as input, but overwritten) """ cdef unsigned char *pf = <unsigned char *>f.data cdef unsigned char *pc = <unsigned char *>Cc.data cdef unsigned char *pn = <unsigned char *>Cn.data cdef int x # current position inside the configuration cdef int n # current neighborhood value cdef int w # the weight of the first cell inside the neighborhood if 1 : # initialization n = 0 w = 1 for x from 0 <= x < m-1 : n = n * k + pc[x] # preparing the first overlap w = w * k # setting the weight # building of neighborhoods for x from 0 <= x < N : n = n * k + pc[(x+m-1)%N] pn[x] = n n = n - pc[x] * w else : # initialization n = 0 w = 1 for x from 0 <= x < m-1 : n = n << 1 | pc[x] # preparing the first overlap w = w << 1 w = w-1 # building of neighborhoods for x from 0 <= x < N : n = n << 1 | pc[x+m-1] pn[x] = n n = n & w # applying transition function for x from 0 <= x < N : pc[x] = pf[pn[x]] return 
%hide """ SAGE/Python Cellular Automata Toolkit (PYCA) 0.2.1, by Iztok Jeras """ import numpy class pyca_rule () : """ A CA rule is a tuple defined by three parameters (k, m, r). INPUTS: k -- number of states per cell a -- neighborhood (a list of cell coordinates) r -- rule number INTERNALS: m -- neighborhood size (number of cells composing a neighborhood) d -- number of dimensions D -- a list of $k$ de Bruijn matrices Sf -- forward state machine Sb -- backward state machine """ def __init__(ca, k, a, r): ca.k = k ca.a = a ca.m = len(ca.a) #if (type(ca.a[0]) not in (tuple, list)) if ( (type(ca.a ) not in (tuple,)) or (type(ca.a[0]) not in (tuple,)) ) : #ca.a = [[x] for x in ca.a] ca.a = tuple([tuple([x]) for x in ca.a]) ca.d = len(ca.a[0]) ca.r = r ca.f = numpy.array([ca.r // ca.k**n % ca.k for n in xrange(ca.k**ca.m)], dtype='uint8') # for 1D CA some rule properties can be computed if (ca.d == 1) : ca.D = [numpy.mat (numpy.zeros ((ca.k**(ca.m-1), ca.k**(ca.m-1)), int)) for k in xrange(ca.k)] for n in xrange(ca.k**ca.m) : o_l = n // ca.k; o_r = n % (ca.k**(ca.m-1)) ca.D [ca.f[n]] [o_l, o_r] = 1 # ca.Sf = [ [ list2int (list2bool (vector(int2list(i, ca.k, ca.k**(ca.m-1))) * ca.D[c]), ca.k) for i in xrange(2**(ca.k**(ca.m-1))) ] for c in xrange(ca.k) ] # ca.Sb = [ [ list2int (list2bool (ca.D[c] * vector(int2list(i, ca.k, ca.k**(ca.m-1)))), ca.k) for i in xrange(2**(ca.k**(ca.m-1))) ] for c in xrange(ca.k) ] def __repr__(ca): return "Cellular Automaton (states = "+str(ca.k)+", neighborhood = "+str(ca.a)+", rule = "+str(ca.r)+")" class pyca_lattice () : """ CA lattice INPUTS: ca -- CA rule object C -- CA configuration (can be a list, n-D array or string) b -- boundary type (default 'cyclic') dtype -- cell value data type (default 'uint8') METHODS: next(t) -- compute t time steps (default t is 1) INTERNALS: N -- lattice size as number of cells in each dimension Cc -- internal array representation of the cell lattice Cn -- internal array representation of the neighborhood lattice The configuration can be initialized from different data types depending on the number of dimensions: 1D -- numpy.ndarray, list or string 2D -- numpy.ndarray, list of lists or strings, or from images (png, bmp, ...) nD -- numpy.ndarray only By default the internal arrays are of type 'uint8', the number of states per cell is limited to 256. The supported boundary tipes are 'cyclic and 'open'. The 'cyclic' or periodic boundary is used when the each boundary is directly conected to the oposite boundary (1D - start <=> end, 2D - left <=> right, top <=> bottom). The 'open' boundary is used when the defined configuration is only a segment of an infinite configuration, where cells outside the observed segment can have any value. The next(t) method computes t discrete time steps, the prev() method computes a list of preimages, the results depends on the boundary type. """ def __init__(lt, ca, C, b='cyclic', dtype='uint8') : lt.ca = ca lt.N = len(C) # detecting the CA type if ( (lt.ca.d==1) & (lt.ca.a == tuple([tuple([x+lt.ca.a[0][0]]) for x in range(lt.ca.m)])) ) : lt.type = '1D' else : lt.type = 'general' # parsing the input configuration if (lt.ca.d == 1) : # 1D CA can be initialized from numpy.ndarray, list or string if (type(C) in (numpy.ndarray, list)) : lt.Cc = numpy.array(C, dtype=dtype) elif (type(C) in (string,)) : lt.Cc = numpy.fromstring(C, dtype=dtype)-int(48) else : print "Error: incompattible configuration" return elif (lt.ca.d == 1) : # 2D CA can be initialized from numpy.ndarray, list of lists or strings, or from images if (type(C) in (numpy.ndarray,)) : lt.Cc = numpy.array(C, dtype=dtype) elif (type(C) in (list,)) : if (type(C[0]) in (list,)) : lt.Cc = numpy.array(C, dtype=dtype) elif (type(C) in (string,)) : lt.Cc = numpy.empty(lt.N, dtype=dtype) for y in range(len(C)) : lt.Cc = numpy.fromstring(C[y], dtype=dtype)-int(48) else : print "Error: incompattible configuration" return else : print "Error: incompattible configuration" return else : # nD CA where n>2 can only be initialized from numpy.ndarray if (type(C) in (numpy.ndarray,)) : lt.Cc = numpy.array(C, dtype=dtype) else : print "Error: incompattible configuration" return # an empty array for neighborhoods, can be used for temporal results lt.Cn = numpy.empty(lt.N, dtype=dtype) # parsing the input boundary if (b in ('cyclic', 'open')) : lt.b = b else : print "Error: currently only 'cyclic' and 'open' boundaries are supported" return def __repr__(lt): return repr((lt.Cc+int(48)).tostring()) def next (lt, t=1) : """ Performs a step forward in time, the result is stored back into the configuration 'Cc'. As a partial result the neighborhood configuration is computed an stored into 'Cn'. """ if (lt.type == '1D') : if (lt.b == 'cyclic') : for _ in xrange(t) : ca1d_next_generic (lt.ca.k, lt.ca.m, lt.ca.f, lt.N, lt.Cc, lt.Cn) shift = t * (-lt.ca.a[0][0]) lt.Cc = numpy.concatenate((lt.Cc[lt.N-shift:lt.N], lt.Cc[0:lt.N-shift]), axis=0) else : for _ in xrange(t) : ca1d_next_generic (lt.ca.k, lt.ca.m, lt.ca.f, lt.N, lt.Cc, lt.Cn) lt.N = lt.N - (lt.ca.m-1) lt.Cc = lt.Cc[0:lt.N] else : print "Error: feature not yet implemented" return def run (lt, t, out='Cc') : if (lt.ca.d == 1) : #if ( (lt.Cc.dtype in (dtype('uint8'),)) and (lt.ca.k == 2) ) : if (lt.ca.k == 2) : cct = numpy.empty([t+1, lt.N], dtype='uint8') if (out == 'Cc') : cct [0] = lt.Cc elif (out == 'Cn') : cct [0] = lt.Cn else : print "Error: wrong out parameter" for y in range(t) : lt.next() if (out == 'Cc') : cct [y+1] = lt.Cc elif (out == 'Cn') : cct [y+1] = lt.Cn else : print "Error: feature not yet implemented, only 1D CA are supported" return cct 
       
# Generate unique rules unique_rules = [] redundant_rules = [] def colour_inverse(decimal): return Integer(''.join(['0' if digit == '1' else '1' for digit in decimal.binary().zfill(8)][::-1]), base=2) def reverse(decimal): decimal = list(decimal.binary().zfill(8)) decimal[1], decimal[4] = decimal[4], decimal[1] decimal[3], decimal[6] = decimal[6], decimal[3] return Integer(''.join(decimal), base=2) for rule in srange(256): if rule not in redundant_rules: unique_rules.append(rule) redundant_rules.extend([colour_inverse(rule), reverse(rule), reverse(colour_inverse(rule))]) 
       
def period(array, reps=5): '''Return the period of a list''' for period in range(1, 100): wrong_period = False for count in range(reps): if array[:period] != array[count * period:(count + 1) * period]: wrong_period = True break if not wrong_period: return period return None 
       
def entropy_str(string): '''Return the entropy of a string of bits''' one_count = Integer(string.count('1')) zero_count = Integer(string.count('0')) if one_count == 0 or zero_count == 0: return 0 one_prob = one_count / len(string) zero_prob = zero_count / len(string) return n(-len(string)*((one_prob * log(one_prob, 2)) + (zero_prob * log(zero_prob, 2)))) 
       
y = var('y') zero_distrib = Integer(round(find_root((500 == -1000 * ((x / 1000) * log(x / 1000, 2) + (y / 1000) * log(y / 1000, 2))).substitute({y:(1000 - x)}), 1, 1000))) initial_config = ([0] * zero_distrib) + ([1] * (1000 - zero_distrib)) for rule in unique_rules: classification = '' shuffle(initial_config) rule_obj = pyca_rule(2, (-1, 0, 1), rule) ca_obj = pyca_lattice(rule_obj, initial_config) evolutions = [] for step in range(1000): evolutions.append(str(ca_obj)[1:-1]) ca_obj.next() entropies_list = [entropy_str(evolution) for evolution in evolutions[-200:]] if min(entropies_list) >= 980: classification = 'Maximal entropy' elif max(entropies_list) <= 20: classification = 'Null' else: rule_period = period(entropies_list) if rule_period == 1: classification = 'Fixed-point' elif rule_period == 2: classification = 'Two-cycle' elif rule_period > 2: classification = 'Periodic' elif rule_period == None: classification = 'Nonperiodic' print 'Rule', rule, classification 
       
Rule 0 Null
Rule 1 Two-cycle
Rule 2 Fixed-point
Rule 3 Two-cycle
Rule 4 Fixed-point
Rule 5 Two-cycle
Rule 6 Two-cycle
Rule 7 Two-cycle
Rule 8 Null
Rule 9 Two-cycle
Rule 10 Fixed-point
Rule 11 Fixed-point
Rule 12 Fixed-point
Rule 13 Maximal entropy
Rule 14 Fixed-point
Rule 15 Fixed-point
Rule 18 Nonperiodic
Rule 19 Fixed-point
Rule 22 Nonperiodic
Rule 23 Fixed-point
Rule 24 Fixed-point
Rule 25 Two-cycle
Rule 26 Nonperiodic
Rule 27 Two-cycle
Rule 28 Maximal entropy
Rule 29 Fixed-point
Rule 30 Maximal entropy
Rule 32 Null
Rule 33 Two-cycle
Rule 34 Fixed-point
Rule 35 Two-cycle
Rule 36 Fixed-point
Rule 37 Two-cycle
Rule 38 Two-cycle
Rule 40 Null
Rule 41 Periodic
Rule 42 Fixed-point
Rule 43 Fixed-point
Rule 44 Fixed-point
Rule 45 Maximal entropy
Rule 46 Fixed-point
Rule 50 Maximal entropy
Rule 51 Fixed-point
Rule 54 Maximal entropy
Rule 56 Fixed-point
Rule 57 Maximal entropy
Rule 58 Maximal entropy
Rule 60 Nonperiodic
Rule 62 Periodic
Rule 72 Fixed-point
Rule 73 Nonperiodic
Rule 74 Fixed-point
Rule 76 Fixed-point
Rule 77 Maximal entropy
Rule 78 Maximal entropy
Rule 90 Nonperiodic
Rule 94 Periodic
Rule 104 Fixed-point
Rule 105 Maximal entropy
Rule 106 Nonperiodic
Rule 108 Two-cycle
Rule 110 Nonperiodic
Rule 122 Maximal entropy
Rule 126 Maximal entropy
Rule 128 Null
Rule 130 Fixed-point
Rule 132 Fixed-point
Rule 134 Two-cycle
Rule 136 Null
Rule 138 Fixed-point
Rule 140 Fixed-point
Rule 142 Fixed-point
Rule 146 Nonperiodic
Rule 150 Maximal entropy
Rule 152 Fixed-point
Rule 154 Nonperiodic
Rule 156 Maximal entropy
Rule 160 Null
Rule 162 Fixed-point
Rule 164 Fixed-point
Rule 168 Null
Rule 170 Fixed-point
Rule 172 Fixed-point
Rule 178 Maximal entropy
Rule 184 Fixed-point
Rule 200 Fixed-point
Rule 204 Fixed-point
Rule 232 Fixed-point
Rule 0 Null
Rule 1 Two-cycle
Rule 2 Fixed-point
Rule 3 Two-cycle
Rule 4 Fixed-point
Rule 5 Two-cycle
Rule 6 Two-cycle
Rule 7 Two-cycle
Rule 8 Null
Rule 9 Two-cycle
Rule 10 Fixed-point
Rule 11 Fixed-point
Rule 12 Fixed-point
Rule 13 Maximal entropy
Rule 14 Fixed-point
Rule 15 Fixed-point
Rule 18 Nonperiodic
Rule 19 Fixed-point
Rule 22 Nonperiodic
Rule 23 Fixed-point
Rule 24 Fixed-point
Rule 25 Two-cycle
Rule 26 Nonperiodic
Rule 27 Two-cycle
Rule 28 Maximal entropy
Rule 29 Fixed-point
Rule 30 Maximal entropy
Rule 32 Null
Rule 33 Two-cycle
Rule 34 Fixed-point
Rule 35 Two-cycle
Rule 36 Fixed-point
Rule 37 Two-cycle
Rule 38 Two-cycle
Rule 40 Null
Rule 41 Periodic
Rule 42 Fixed-point
Rule 43 Fixed-point
Rule 44 Fixed-point
Rule 45 Maximal entropy
Rule 46 Fixed-point
Rule 50 Maximal entropy
Rule 51 Fixed-point
Rule 54 Maximal entropy
Rule 56 Fixed-point
Rule 57 Maximal entropy
Rule 58 Maximal entropy
Rule 60 Nonperiodic
Rule 62 Periodic
Rule 72 Fixed-point
Rule 73 Nonperiodic
Rule 74 Fixed-point
Rule 76 Fixed-point
Rule 77 Maximal entropy
Rule 78 Maximal entropy
Rule 90 Nonperiodic
Rule 94 Periodic
Rule 104 Fixed-point
Rule 105 Maximal entropy
Rule 106 Nonperiodic
Rule 108 Two-cycle
Rule 110 Nonperiodic
Rule 122 Maximal entropy
Rule 126 Maximal entropy
Rule 128 Null
Rule 130 Fixed-point
Rule 132 Fixed-point
Rule 134 Two-cycle
Rule 136 Null
Rule 138 Fixed-point
Rule 140 Fixed-point
Rule 142 Fixed-point
Rule 146 Nonperiodic
Rule 150 Maximal entropy
Rule 152 Fixed-point
Rule 154 Nonperiodic
Rule 156 Maximal entropy
Rule 160 Null
Rule 162 Fixed-point
Rule 164 Fixed-point
Rule 168 Null
Rule 170 Fixed-point
Rule 172 Fixed-point
Rule 178 Maximal entropy
Rule 184 Fixed-point
Rule 200 Fixed-point
Rule 204 Fixed-point
Rule 232 Fixed-point