在纯粹的numpy中将康威的生命游戏矢量化?

时间:2018-02-02 15:04:53

标签: python numpy vectorization linear-algebra cellular-automata

我想知道是否有办法实现Conway的生活游戏而不诉诸于循环,if语句和其他典型的编程控制结构。 对于循环进行矢量化应该很容易,但是如何将邻域上的检查转换为矩阵运算?

基本逻辑类似于this

def neighbors(cell, distance=1):
    """Return the neighbors of cell."""
    x, y = cell
    r = xrange(0 - distance, 1 + distance)
    return ((x + i, y + j) # new cell offset from center
            for i in r for j in r # iterate over range in 2d
            if not i == j == 0) # exclude the center cell

我希望这不会被mod视为偏离主题,我真的好奇,而我刚刚开始使用CA.

干杯

1 个答案:

答案 0 :(得分:1)

您的问题的答案是“是,有可能”(尤其是董事会从董事会n更新到董事会n + 1)。

我将详细描述该过程here。产生围绕中心单元的邻域的主要技术涉及使用“步幅”(numpy和其他数组计算系统知道如何将元素的行和列真正存储在 flat 中时如何遍历元素的行和列。 em> 1D事物)以自定义的方式在单元格周围生成邻域。我描述了该过程here

最后一条评论:由于生命游戏从状态n迭代到状态n + 1,因此您可以从字面上删除所有命令性循环,因此删除该顶层命令实际上没有任何意义。电平控制回路。因此,有一个循环:for round in range(num_rounds): board.update(),其中board.update不使用循环(除了进行一些侧面计算……再次,您可以将其删除,但它将使程序变长而不太优雅。

为了给你一个具体的例子(并与StackOverflow的答案要求更加兼容),这里有一些从我的帖子中选择的剪切和粘贴操作,以从一个简单的4x4板生成中心邻域[抱歉,这是python 2代码,你'则必须修改print位]:

board = np.arange(16).reshape((4,4))
print board
print board.shape

我们要选择以5、6、7和8为中心的四个“完整”社区。让我们看一下5的社区。结果的形状是什么? 3×3。取得了什么进展?好吧,跨行仍然是一次只走一个元素,而到达下一行仍然是一次4个元素。这些与原始版本中的步骤相同。不同之处在于我们不选择“所有”,而只是选择一个。让我们看看它是否真的有效:

from numpy.lib.stride_tricks import as_strided
neighbors = as_strided(board, shape=(3,3), strides=board.strides)
print neighbors

好的,很好。现在,如果我们要所有四个邻域,输出形状是什么?我们有几个3×3的结果。多少?在这种情况下,我们有2×2(对于每个“中心”像元)。这样得到的形状为(2,2,3,3)–邻域是内部维度,而邻域的组织是外部维度。

因此,我们的步伐(就元素而言)最终是(4,0)在一个邻域内,而(4,0)则是将邻域发展为邻域。总步幅(从明智角度来看)为:(4,0,4,0)。但是,组件的步幅(我们的外部二维尺寸)与板的步幅相同。这意味着我们附近的步幅为board.strides + board.strides。

print board.strides + board.strides

neighborhoods = as_strided(board, 
                           shape=(2,2,3,3), 
                           strides=board.strides+board.strides)

print neighborhoods[0,0]
print neighborhoods[-1, -1]