Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 优化康威';s';生活游戏';_Algorithm_Performance_Language Agnostic_Conways Game Of Life - Fatal编程技术网

Algorithm 优化康威';s';生活游戏';

Algorithm 优化康威';s';生活游戏';,algorithm,performance,language-agnostic,conways-game-of-life,Algorithm,Performance,Language Agnostic,Conways Game Of Life,为了试验,我(很久以前)已经实现了康威的(我知道相关的问题!) 我的实现通过保留两个布尔数组来工作,表示“最后一个状态”和“正在更新的状态”(在每次迭代中交换这两个数组)。虽然这相当快,但我经常想知道如何优化它 例如,一个想法是在迭代N时预计算可以在迭代(N+1)时修改的区域(这样,如果一个单元不属于这样的区域,它甚至不会在迭代(N+1)时被考虑修改)。我知道这是非常模糊的,我从来没有花时间去了解细节 你对如何优化(加速)生命之战的迭代有什么想法(或经验!)吗?我不知道如何做到这一点,但我记得我

为了试验,我(很久以前)已经实现了康威的(我知道相关的问题!)

我的实现通过保留两个布尔数组来工作,表示“最后一个状态”和“正在更新的状态”(在每次迭代中交换这两个数组)。虽然这相当快,但我经常想知道如何优化它

例如,一个想法是在迭代N时预计算可以在迭代(N+1)时修改的区域(这样,如果一个单元不属于这样的区域,它甚至不会在迭代(N+1)时被考虑修改)。我知道这是非常模糊的,我从来没有花时间去了解细节


你对如何优化(加速)生命之战的迭代有什么想法(或经验!)吗?

我不知道如何做到这一点,但我记得我的一些朋友不得不用四叉树来表示游戏的网格,以便分配任务。我想这对优化网格的空间非常有用,因为你基本上只表示被占用的单元。不过,我不知道执行速度。

这是一个二维自动机,所以您可能可以查找优化技术。您的想法似乎是压缩每个步骤需要检查的单元格数量。因为您只需要检查被占用的单元或与被占用单元相邻的单元,所以您可以保留所有此类单元的缓冲区,在处理每个单元时在每一步对其进行更新


如果您的字段最初为空,则速度会快得多。您可能会找到一些平衡点,在这个平衡点上维护缓冲区比处理所有单元格的成本更高。

有一些表驱动的解决方案,可以解决每个表查找中的多个单元格。谷歌查询应该会给你一些例子。

有一些超快的实现(从内存中)将8个或更多相邻正方形的单元表示为位模式,并将其作为一个大的预计算值数组的索引,以在一条机器指令中确定一个单元是活的还是死的

在这里查看:

还包括XLife:


我将引用另一个问题的答案,因为我提到的章节有一些非常有趣且经过微调的解决方案。有些实现细节是用c和/或汇编语言编写的,是的,但在大多数情况下,算法可以用任何语言工作:

章节和 迈克尔·艾布拉什是其中之一 我读过的最有趣的书 有这是一堂思考的课 在盒子外面。整本书是 真的很好,但最终的结果是优化的 生活游戏的解决方案是 难以置信的编程


正如Arbash在《黑皮书》中提到的,获得巨大加速的最简单、最直接的方法之一就是保留一个变更列表

不要每次都遍历整个单元格网格,而是保留所更改的所有单元格的副本

这将缩小每次迭代必须完成的工作范围。

两个想法:

(1) 许多配置大多是空的空间。保留一个活细胞的链接列表(不一定按顺序排列,这会花费更多的时间),在更新过程中,只更新活细胞周围的内容(这类似于你模糊的建议,Oysted:)


(2) 保留一个额外的数组,在每一行的3个位置(左-中-右)存储#个活细胞。现在,当您计算一个单元格的新死/活值时,只需要4次读取操作(顶行/底行和中心侧位置)和4次写入操作(更新3个受影响的行摘要值和新单元格的死/活值)。假设写入速度不低于读取速度,则这比8次读取和1次写入略有改进。我猜您可能会更聪明地使用这些配置,并在这些方面取得更好的改进。

您应该研究一下最终的优化。它使用了skinp提到的方法。

该算法本身具有内在的并行性。在未优化的CUDA内核中使用相同的双缓冲方法,在4096x4096包装的世界中,我的每代速度大约为25ms。

什么是最有效的算法主要取决于初始状态

如果大部分单元都已死亡,则可以通过跳过空部分和不逐个单元计算内容来节省大量CPU时间

我认为,当你的初始状态是“随机的,但生命的几率低于5%时,首先检查完全死区是有意义的。”

我只需要将矩阵分成两半,然后首先检查较大的矩阵

所以如果你有一个10000*10000的字段,你首先要把左上角四分之一的状态累加到5000*5000

如果第一个季度的状态和为零,你可以完全忽略第一个季度,然后检查右上角的5000*5000

如果它的状态之和大于0,您现在将再次将第二个季度划分为4个部分-并对每个子空间重复此检查

现在,您可以转到8*8或10*10的子帧(不确定这里什么最有意义)

每当你发现生命,你就把这些子空间标记为“有生命”

只有“有生命”的空间才需要划分为更小的子空间——可以跳过空的子空间

当您完成将“has life”属性指定给所有可能的子空间后,您将得到一个子空间列表,您现在只需将该列表向每个方向扩展+1即可(使用空单元格),并对其执行常规(或修改的)生命规则游戏

您可能会认为将10000*10000个spae划分为8*8的子空间是很多操作系统任务,但累积它们的状态值实际上比对每个单元加上它们的8个邻居执行GoL算法,再加上比较数字和存储n的新状态要少得多
/* The Game of Life function */
// @param s: current state of the grid
// @param d: size of the grid (d*d)
// @param n: placeholder
// @param k: placeholder
// @param m: placeholder
// @param i: placeholder
// @param j: placeholder
function(s, d, n, k, m, i, j){
  for(
    n = [],                           // Initialize next state
    m = [d + 1, d, d - 1, 1],         // Initialize the upper half of the neighbours indexes
    i = d * d;                        // For each cell
    i--;
    n[i] = k == 3 || s[i] && k == 2,  // Set next state (live if it has 3 neighbours or lives and has 2 neighbours)
    k = 0                             // Reset the count of living neighbours
  )
  for(j in m)                         // for each neighbour position
    k += s[i + m[j]] + s[i - m[j]]    // count the living neighbours
  return(n)                           // return the next state
}