元胞自动机的numpy向量化



尝试优化我当前使用Wolfram编号生成细胞自动机的程序的实现。在计算每个单元的邻居后,我遇到了将规则应用于董事会的麻烦。当前的例子使用了2种状态,与Conway的生命游戏相同,但我的程序可以处理任意数量的状态。小数224以以下方式对应于CGOL的规则集:(0, 0, 0, 0, 0, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)基本上,每个状态有18个位置,或者9个可能的邻域和(0-8)。如果当前单元格为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/该单元格的邻域和,以获得该单元格的实际更新值。因此,要在每一代更新一个单元格,您需要:规则[state_value::total_states][邻居的总和]。例如,

>>> [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的卷积计算-称为nbr -,以及前面提到的规则列表-是否有可能更新世界中每个细胞的值,同时避免for循环?

例如:World = rule[cell_value::total_states][sum_of_neighbors_for_given_cell_in_nbrs]

您没有给我们很多代码,所以这里有一个关于它如何工作的最小想法。

首先,创建一个数组,您可以使用当前状态对其进行索引,以获得规则:

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

相关内容

  • 没有找到相关文章

最新更新