Chapter 6 notebook: Straightforward translation of GoL rules using loops doesn't handle boundaries correctly
gwtaylor opened this issue · 1 comments
Note that the output for the straightforward loop-based implementation is different from the correlation-based versions. In the static version of the notebook, the input is:
[[1 1 1 0 1 1 1 1 0 1]
[0 1 0 1 0 1 0 0 1 1]
[0 0 1 0 0 1 1 0 0 1]
[0 0 0 0 0 1 1 0 0 1]
[0 0 0 1 0 1 1 1 1 1]
[0 0 1 0 1 0 1 0 0 0]
[0 0 0 1 0 0 0 0 0 0]
[0 1 0 0 0 1 0 1 1 0]
[1 1 0 1 0 0 1 1 1 1]
[0 0 1 0 0 0 0 0 0 0]]
The output for the loop-based implementation is:
[[0 0 0 0 0 0 0 0 0 0]
[0 0 0 1 0 0 0 0 0 0]
[0 0 1 0 0 0 0 1 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 1 0 0 0 0 1 0]
[0 0 1 0 1 0 1 0 1 0]
[0 0 1 1 1 1 1 1 0 0]
[0 1 0 0 1 0 0 0 0 0]
[0 1 0 0 0 0 1 0 0 0]
[0 0 0 0 0 0 0 0 0 0]]
The output for the cross correlation version is:
[[1 1 1 1 1 1 1 1 0 1]
[1 0 0 1 0 0 0 0 0 1]
[0 0 1 0 0 0 0 1 0 1]
[0 0 0 0 0 0 0 0 0 1]
[0 0 0 1 0 0 0 0 1 1]
[0 0 1 0 1 0 1 0 1 0]
[0 0 1 1 1 1 1 1 0 0]
[1 1 0 0 1 0 0 0 0 1]
[1 1 0 0 0 0 1 0 0 1]
[0 1 1 0 0 0 0 1 1 0]]
Note that the difference is on the boundaries, and that's because the following line doesn't work for the boundaries:
neighbors = a[i-1:i+2, j-1:j+2]
A student in my class made this observation, and also supplied an alternative version that explicitly checks for boundaries. I have confirmed that this version produces the same output as the cross correlation version.
b = np.zeros_like(a)
rows, cols = a.shape
for i in range(0, rows):
for j in range(0, cols):
state = a[i, j]
if i == 0 and j == 0:
neighbors = a[i:i+2, j:j+2]
elif j == 0:
neighbors = a[i-1:i+2, j:j+2]
elif i == 0:
neighbors = a[i:i+2, j-1:j+2]
else:
neighbors = a[i-1:i+2, j-1:j+2]
k = np.sum(neighbors) - state
if state:
if k==2 or k==3:
b[i, j] = 1
else:
if k == 3:
b[i, j] = 1
print(b)
This is a good catch, and thanks to your student for the updated code.
I am inclined to leave this issue along for now, but I will leave it open in case other readers are bothered.