元胞自动机numpy向量化

wfveoks0  于 2023-01-13  发布在  其他
关注(0)|答案(1)|浏览(113)

尝试优化我当前使用Wolfram Numbering生成元胞自动机的程序实现。在计算每个元胞的邻居后,我在将规则应用到棋盘上时遇到了问题。当前示例使用2个状态,与Conway的Game of Life相同,但我的程序可以处理任意数量的状态。十进制224以如下方式对应于CGOL的规则集:[0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0]基本上,每个状态(0 - 8)有18个位置或9个可能的邻域总和。如果当前单元格为1,则按以下方式索引到规则中:

>>> [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0][1::2]
[0, 0, 1, 1, 0, 0, 0, 0, 0]

1是单元格的值,2是状态数。如图所示,如果状态为1,则如果有2或3个相邻单元格,则该单元格生存,否则将死亡。在此基础上,您可以索引w/该单元格的邻域和,以获得该单元格的实际更新值。因此,要在每代更新单元格,您需要:规则[状态值::总状态][邻居的总和]。例如,

>>> [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0][1::2][2]
1

现在,我有了一个所有单元格的网格,叫做world,形状是任意的,另一个形状相同的numpy数组,它有每个单元格的所有邻居的总和,使用scipy的卷积计算--称之为nbrs--,还有前面提到的规则列表--是否可以更新world中每个单元格的值,同时避免for循环?
例如:world = rule [像元值::状态总数][nbrs中给定像元的相邻像元总和]

jmo0nnb3

jmo0nnb31#

你没有给我们很多代码,所以这里有一个最小的想法,它如何工作。
首先,创建一个数组,您可以使用当前状态索引该数组以获取规则:

rule = [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0]
rule_map = np.stack((rule[0::2], rule[1::2]), axis=0)

现在,您可以使用当前状态来获取每个单元格的规则:

world = np.random.randint(2, size=(5, 6))
cur_cell_rules = rule_map[world]  # shape: (5, 6, 9)

为了得到新的世界状态,我们可以使用索引迭代器。在这里,我使用一个包含所有世界索引的数组来首先得到(展平的)当前单元格邻域和,然后使用这些得到(展平的)新状态。在赋值中,我再次将其展平为世界形状。(可能有更简单的方法来做到这一点...)

cur_cell_neighborhood_sum = ...  # shape: (5, 6)
world_ind = np.asarray([*np.ndindex(world.shape)])

# update world
world[world_ind[:, 0], world_ind[:, 1]] = cur_cell_rules[world_ind[:, 0], world_ind[:, 1], cur_cell_neighborhood_sum[world_ind[:, 0], world_ind[:, 1]]]
    • 编辑**:

要避免使用大型cur_cell_rules数组,您也可以采用另一种方法:

world_potential = rule_map[:, cur_cell_neighborhood_sum]  # shape: (2, 5, 6)

# update world, this time in smaller steps
world_flat = world[world_ind[:, 0], world_ind[:, 1]]
world_new_flat = world_potential[world_flat, world_ind[:, 0], world_ind[:, 1]]
world[world_ind[:, 0], world_ind[:, 1]] = world_new_flat

相关问题