我想用以下简单规则实现一维元胞自动机:
- 如果单元格为1且相邻单元格为0,则(向右)移动
- 如果单元格为1且相邻单元格为1,则不要移动
- 所有细胞根据它们的状态同时更新。
- 我们有封闭边界条件。这意味着最后一个单元格的邻居是第一个单元格。
例如:
0 1 1 0 1
更新后:
1 1 0 1 0
我的解决方案是
def update(cells):
neighbors = np.roll(cells,-1)
dim = len(cells)
tmp_cells = np.zeros(dim)
for i,j in enumerate(cells):
if j and not neighbors[i]:
tmp_cells[i], tmp_cells[(i+1)%dim] = 0, 1
elif j:
tmp_cells[i] = 1
return tmp_cells
这很好,但解决方案并没有利用 np.arrays 的所有可能性,而是简化为一个简单的 list 算法。
我以为我可以在 cells 和 neighbors 之间找到一个简洁的逻辑,但显然我现在必须去 sleep 了。
一些想法?
请您参考如下方法:
要在不循环的情况下获取单元格的值,您需要知道它在两边 的邻居。您需要左边,因为如果您是 0,您的新值取决于您左边邻居的值,而如果您是 1,您的新值取决于您右边邻居的值。
你可以穷尽所有的 3 格组合,对吧?换句话说:
000 -> 0
001 -> 0
010 -> 0 # move to the right
011 -> 1 # stay put
100 -> 1 # left neighbor has moved
101 -> 1 # left neighbor has moved
110 -> 0 # move to the right
111 -> 1 # stay put
您可以很容易地将那个表变成一个 bool 函数。我们可以简化它,但让我们开始时是愚蠢的:-x & y & z | x & -y & -z | x & -y & z | x & y & z.
就是这样:
left = np.roll(cells, -1)
right = np.roll(cells, 1)
return (np.logical_not(left) & cells & right | # ...)
现在您当然想要简化 bool 方程,*但这应该让您入门。
* 或者退后一步,重新考虑规则。如果你是 0,你的新值总是从你左边的邻居那里复制;如果你是 1,它总是从你右边的邻居那里复制的。您可以使用 bool 运算符的组合来编写它,但使用掩码赋值可能会更简单:result[cells] = left[cells];结果[notcells] = right[notcells].
