-
Notifications
You must be signed in to change notification settings - Fork 0
/
OneD.py
125 lines (106 loc) · 3.97 KB
/
OneD.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
class OneD:
from loc import loc as Loc
def rule_30(neighbors):
p1,p2,p3 = neighbors
if (p1) != (p2 or p3):
return 1
else:
return 0
def __init__(self, size=20, r=3, k=2, rule=rule_30, RIC=False):
"""Initializes the simulation with the passed parameters.
parameters:
size: The size of the simulation. The simulation will be square according to this parameter. Defaults to 20
r: The number of neighbors that will be evaluated by the rule function. Defaults to 3
k: The number of possible states in the system. The minimum value is 2. The states are represented as numbers
beginning with 0. Defaults to 2
rule: A function that accepts a tuple of r variables representing the neighbors and returns one of
k states. Defaults to rule 30
RIC (Rancom Initial Condition): a boolean variable that specifies if the simulation should start from a random
initial state. If True is passed, each cell in the first row will be initialized to one of the k states.
Defaults to Fales.
"""
from lattice import lattice
from loc import loc as Loc
import random
self.size = size
self.r = r
self.k = k
self.rule = rule
self.__ran = False
self.state = lattice(self.size)
if RIC:
for i in range(size):
if random.random() <= 1/k:
self.state.set_cell(Loc(0, i), 1)
else:
self.state.set_cell(Loc(0, int(size/2)), 1)
def default_neighbors(self, loc: Loc):
"""Returns the locations of the three cells atop this cell"""
return (self.state.offset(loc, -1,-1), self.state.offset(loc, -1), self.state.offset(loc, -1, 1))
def neighbor_locs(self, loc:Loc, neighbors=default_neighbors):
"""Returns the location of the neighbors of the cell at the specified location.
If no function is pased to determine the location of the neighbors, then the
3 neighbors atop the cell are chosen by default.
parameters:
loc: The location of the cell
neighbors: A function that maps the neighbors from the given loc.
"""
return neighbors(self,loc)
def neighbor_vals(self, loc:Loc):
""" Returns the value of the neighbord depending on the neighbor_locs
parameters:
loc: The location of which to get the values of the neighbors
"""
return [self.state.lat()[l.row()][l.col()] for l in self.neighbor_locs(loc)]
def run(self):
"""Runs the cellular automata simulation based on the passed rule."""
from loc import loc as Loc
for r in range(1,self.size):
for c in range(self.size):
this = Loc(r,c)
self.state.set_cell(this, self.rule(self.neighbor_vals(this)))
self.__ran = True
def extract_data(self, nominal=False):
"""Returns a list of tuples, each of which contains r+1 entries,
where r is the number of neighbors. The first r numbers in the tuples
represent the state of the neighbors, and the (r+1)st entry represents
the state of the resulting cell.
parameters:
nominal: if set to True, will return the values int the tuples in a nominal
format (alphabets each of which correspond to a unique value). Defaults to
False.
example:
nominal=False
[(1,1,0,0), (1,0,0,1)]
nominal=True
[('a', 'a', 'b', 'b'), ('a', 'b', 'b', 'a')]
"""
from loc import loc as Loc
data = []
if self.__ran == False:
self.run()
for row in range(1, self.size):
for col in range(0, self.size):
this = Loc(row,col)
data.append( tuple( self.neighbor_vals(this)) + tuple([self.state.lat()[row][col]]) )
if nominal:
nom_data = []
vals = {}
##starts the assignment of alphabetic nominal characters to values
reached_val = chr(ord('a')-1)
for tup in data:
new_tup = tuple( [] )
for val in tup:
if val in vals:
new_tup += tuple ([vals[val]])
else: #if new value encountered, choose a nominal character to represent it
reached_val = chr(ord(reached_val)+1)
vals[val] = reached_val
new_tup += tuple ([vals[val]])
nom_data.append(new_tup)
data = nom_data
return data
def __iter__(self):
return self.state.__iter__()
def __repr__(self):
return str(self.state)