如何利用 NumPy 的功能来修复和优化这段非常简单的“生命游戏”代码?

2023-12-31

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
from random import randint

arraySize = 50
Z = np.array([[randint(0, 1) for x in range(arraySize)] for y in range(arraySize)])


def computeNeighbours(Z):
    rows, cols = len(Z), len(Z[0])
    N = np.zeros(np.shape(Z))

    for x in range(rows):
        for y in range(cols):
            Q = [q for q in [x-1, x, x+1] if ((q >= 0) and (q < cols))]
            R = [r for r in [y-1, y, y+1] if ((r >= 0) and (r < rows))]
            S = [Z[q][r] for q in Q for r in R if (q, r) != (x, y)]
            N[x][y] = sum(S)

    return N

def iterate(Z):
    rows, cols = len(Z), len(Z[0])
    N = computeNeighbours(Z)

    for x in range(rows):
        for y in range(cols):
            if Z[x][y] == 1:
                if (N[x][y] < 2) or (N[x][y] > 3):
                    Z[x][y] = 0
            else:
                if (N[x][y] == 3):
                    Z[x][y] = 1

    return Z

fig = plt.figure()

Zs = [Z]
ims = []

for i in range(0, 100):
    im = plt.imshow(Zs[len(Zs)-1], interpolation = 'nearest', cmap='binary')
    ims.append([im])
    Zs.append(iterate(Z))

ani = animation.ArtistAnimation(fig, ims, interval=250, blit=True)
plt.show()

首先,我写了一个简单的实现《生命的游戏》 http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life仅使用标准 Python 工具。我绘制了它,它运行正确,并且动画正确。

接下来我尝试将数组转换为 NumPy 数组,这就是代码现在所在的位置。然而,动画似乎不再起作用,我一直无法弄清楚为什么。 (Update:此错误已修复!)

接下来,我有兴趣利用 NumPy 来优化我的代码。到目前为止,我所做的是将我使用的 Python 数组转换为 NumPy 数组。虽然我确信性能有所提高,但无法识别。

我有兴趣知道对于此类应用程序将执行什么优化顺序,这样我就可以了解如何在我当前的项目中使用 NumPy 的强大功能,该项目只是一个(可能)具有许多规则的三维元胞自动机。


对代码进行以下更改修复了动画错误:

1)改变iterate创建 Z 的深层副本,然后对该深层副本进行更改。新的iterate:

def iterate(Z):
    Zprime = Z.copy()
    rows, cols = len(Zprime), len(Zprime[0])
    N = computeNeighbours(Zprime)

    for x in range(rows):
        for y in range(cols):
            if Zprime[x][y] == 1:
                if (N[x][y] < 2) or (N[x][y] > 3):
                    Zprime[x][y] = 0
            else:
                if (N[x][y] == 3):
                    Zprime[x][y] = 1

    return Zprime

2)根据1,更改这段代码:

for i in range(0, 100):
    im = plt.imshow(Zs[len(Zs)-1], interpolation = 'nearest', cmap='binary')
    ims.append([im])
    Zs.append(iterate(Z))

to:

for i in range(0, 100):
    im = plt.imshow(Zs[len(Zs)-1], interpolation = 'nearest', cmap='binary')
    ims.append([im])
    Zs.append(iterate(Zs[len(Zs)-1]))

下列:

for x in range(rows):
        for y in range(cols):
            if Z[x][y] == 1:
                if (N[x][y] < 2) or (N[x][y] > 3):
                    Z[x][y] = 0
            else:
                if (N[x][y] == 3):
                    Z[x][y] = 1

可以替换为:

set_zero_idxs = (Z==1) & ((N<2) | (N>3))
set_one_idxs = (Z!=1) & (N==3)
Z[set_zero_idxs] = 0
Z[set_one_idxs] = 1

这将比您拥有的循环需要更多的操作,但我希望它会更快。

EDIT:

所以我刚刚对这两个解决方案进行了基准测试,毫不奇怪,numpy 版本快了 180 倍:

In [49]: %timeit no_loop(z,n)
1000 loops, best of 3: 177 us per loop

In [50]: %timeit loop(z,n)
10 loops, best of 3: 31.2 ms per loop

EDIT2:

我认为这个循环:

for x in range(rows):
        for y in range(cols):
            Q = [q for q in [x-1, x, x+1] if ((q >= 0) and (q < cols))]
            R = [r for r in [y-1, y, y+1] if ((r >= 0) and (r < rows))]
            S = [Z[q][r] for q in Q for r in R if (q, r) != (x, y)]
            N[x][y] = sum(S)

可以替换为:

N = np.roll(Z,1,axis=1) + np.roll(Z,-1,axis=1) + np.roll(Z,1,axis=0) + np.roll(Z,-1,axis=0)

这里有一个隐含的假设,即数组没有界限,并且x[-1]旁边是x[0]。如果这是一个问题,您可以在数组周围添加一个零缓冲区:

shape = Z.shape
new_shape = (shape[0]+2,shape[1]+2)
b_z = np.zeros(new_shape)
b_z[1:-1,1:-1] = Z
b_n = np.roll(b_z,1,axis=1) + np.roll(b_z,-1,axis=1) + np.roll(b_z,1,axis=0) + np.roll(b_z,-1,axis=0)
N = b_n[1:-1,1:-1]

并作为基准:

In [4]: %timeit computeNeighbours(z)
10 loops, best of 3: 140 ms per loop 

In [5]: %timeit noloop_computeNeighbours(z)
10000 loops, best of 3: 133 us per loop

In [6]: %timeit noloop_with_buffer_computeNeighbours(z)
10000 loops, best of 3: 170 us per loop

所以只需稍微改进一个因素1052。 Numpy 万岁!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何利用 NumPy 的功能来修复和优化这段非常简单的“生命游戏”代码? 的相关文章

随机推荐

  • MKLocalSearch 只产生美国结果,如何扩展搜索?

    我正在使用 MKLocalSearch 来允许用户搜索他们的城市 但是 当我尝试该代码时 我只收到美国的结果 我还收到了很多结果 包括商店等 我添加了过滤器func completerDidUpdateResults completer M
  • 清除淘汰验证错误

    我有一个使用 Knockout js 并使用 Knockout Validation 的页面设置 在页面加载期间 我在选择框中放置了另一个插件 该插件会触发更改 从而触发验证 我需要能够使用 JS 清除该错误 以便我可以从外观新颖的 UI
  • 为什么计算斐波那契数列的复杂度是 2^n 而不是 n^2?

    我试图使用递归树找到斐波那契数列的复杂性并得出结论height of tree O n 最坏的情况下 cost of each level cn hence complexity n n n 2 怎么会这样O 2 n 朴素递归斐波那契的复杂
  • Linq 连接参数化的不同键

    我正在尝试基于动态键 LINQ 两个表 用户可以通过组合框更改密钥 键可能是钱 字符串 双精度数 整数等 目前我得到的数据很好 但没有过滤掉双精度数 我可以在 VB 中过滤双精度值 但速度很慢 我想立即在 LINQ 查询中执行此操作 这是数
  • libc++ std::istringstream 不会引发异常。漏洞?

    配置完后std istringstream抛出异常时failbit已设置 我在 libc 中没有发生任何异常 这是在 linux 下 使用 libcxxrt 支持编译的 libc 我认为这是 libc 或 libcxxrt 中的错误 inc
  • python导入具有相同根包名和不同位置的不同子包

    我想知道是否有人可以阐明这一点 我们有多个具有相同根包的包库 例如a 我也有包a b位于 X 和包中a c位于Y X和Y都在我的PYTHONPATH当我这样做时 import a c import a b 我收到错误 No module n
  • 当 ModelState 无效时保留下拉信息

    我的 DropDownLists 遇到一些问题 因为当我发布信息并且我的模型无效时 它会返回 空 页面 从而触发错误 就像这个问题 https stackoverflow com questions 3393521 the viewdata
  • Azure Functions - 拥有 host.json 和 local.settings.json 的目的是什么

    我可以看到两个 json 文件 host json 和 local settings json 已添加到 Azure Function 目录中 主机 json version 2 0 logging applicationInsights
  • 按月将带有 NSDate 对象的 NSArray 排序到 NSDictionary 中

    我正在构建一个UITableView并想按月分组 以便我可以将这些字符串作为我的节标题 例如 February 2013 Item 1 Item 2 January 2013 Item 1 Item 2 我有一个NSArray其中包含具有
  • Windows 7 上的 Microsoft Access 文本 ODBC 驱动程序

    我创建了一个 Delphi 应用程序 它利用 ODBC 数据源访问 csv 格式的文本文件 该驱动程序是 Microsoft Access Text Driver 但是 当我在 Windows 7 计算机上部署应用程序时 它无法工作 因为该
  • 应用程序先前由“root”运行后,QSerialPort 无法打开 tty [重复]

    这个问题在这里已经有答案了 我有一个应用程序 使用QSerialPort 从串行端口读取和写入 当我运行这个应用程序时root用户 然后以非 root 用户身份再次运行它 我不再能够写入串行端口 收到以下错误 QIODevice write
  • React useId 创建无效的选择器

    我正在尝试通过 id 获取元素 这是重现错误的示例代码 function MyComponent const myId useId useEffect gt const myComponentDOMElement document quer
  • 如何删除 git 用户属性?

    我不小心输入了以下错误的 git 命令 git config global user mail email protected cdn cgi l email protection 现在当我输入时我会看到一个额外的属性git config
  • 包标识符无法从当前值错误更改

    我制作了 iPhone 应用程序 现在我想将这个应用程序上传到 Appstore 当我尝试从组织者上传存档文件时 它向我显示以下错误 Bundle identifier in my target project is com Appname
  • 如何获取调用函数的名称?

    我正在使用 gnu 工具链 如何在运行时找到函数的调用者 例如 许多函数使用函数指针调用函数 B 现在 每当 B 被呼叫时 我想打印呼叫者的姓名 我需要这个来调试某个问题 如果您使用的是 GNU 则可以使用回溯 http www kerne
  • 关于操作系统,关于页表条目状态位

    在电影里社交网络马克 扎克伯格上课时 老师问了这样一个问题 假设我们有一台计算机 具有 16 位虚拟地址 页大小为 256 字节 系统使用从地址十六进制 400 开始的一级页表 您可能需要 DMA 直接内存访问 在您的 16 位系统上 谁知
  • 捕获 Mac 屏幕

    用cocoa录制mac屏幕的最佳方法是什么 我知道苹果开发人员参考库中有很多示例 SonOfGrab 解释了如何使用石英捕获屏幕 但也指出使用它每秒捕获许多帧的速度不够快 OpenGLScreenSnapshot 具有相同的结果 但速度也不
  • 如何使用 TortoiseSVN 根据修订版之间的差异创建补丁?

    我正在开发一个项目 其中使用 Subversion 来维护版本控制 我使用 TortoiseSVN 访问项目存储库 在项目的两个修订版之间进行了一些更改 我们将其称为 rev1 和 rev2 我希望能够将这些更改应用到暂时无法访问存储库的工
  • Rspec:如何在辅助规范中规范 request.env?

    在我的帮助模块中 我有 def abc url if request env HTTP USER AGENT do something end end 在我的规范文件中 我有 describe abc do before each do m
  • 如何利用 NumPy 的功能来修复和优化这段非常简单的“生命游戏”代码?

    import numpy as np from matplotlib import pyplot as plt from matplotlib import animation from random import randint arra