【问题标题】:Anyone has implemented SMA* search algorithm?有人实施了 SMA* 搜索算法吗?
【发布时间】:2010-12-26 02:10:48
【问题描述】:

我发现 AIMA (Artificial Intelligence: A Modern Approach) 中的算法描述根本不正确。 “必要”是什么意思?内存限制是多少?队列大小或处理的节点?如果当前节点根本没有子节点怎么办?

我想知道这个算法本身是否正确。因为我在网上搜了一下,还没有人实现。

谢谢。

【问题讨论】:

  • 你试过aima-talk群吗? tech.groups.yahoo.com/group/aima-talk
  • 你为什么假设每个人都有这本书并且阅读你所谈论的任何东西。如果某本书中的某些描述正确与否,那么这个编程有什么关系
  • (谁投票“与编程无关”?WTF?)您能否附上您认为不正确的描述?即使我有这本书,我可能也不会想查它......
  • @Q8-coder:是的,它是简化的内存有界 A* 搜索算法。
  • 如果您需要熟悉算法或书籍,这有什么关系。如果你不知道他在说什么,请不要回答!

标签: algorithm search artificial-intelligence a-star path-finding


【解决方案1】:

我已经设法在 C# 中使用 the PDF 实现了图形搜索。

我使用了 3 个列表 - 边界(开放列表)、叶列表和“树枝”列表。

  • Frontier 即 Queue,在 PDF 中提到,它是一个普通的优先级队列,从好到坏排序。

  • 叶子列表只保留叶子,从最差到最好排序,当我们决定要忘记哪个叶子时,我们将需要它。 SMA 只忘记树叶,而不是整个树枝。

  • 树分支列表保持完全展开的节点,其子节点都在内存中。我们需要它来测试状态交集。

我使用快速二叉堆作为边界和叶子列表,并使用哈希表作为树分支列表。

节点应保留以下附加信息:

  • 具有位置的后继迭代器(指向后继列表需要位置)。如果我们忘记了,我们绝对不能将我们的后继枚举重置为零,因为有可能我们忘记了刚刚添加的节点。我使用 IEnumerator,int 表示位置,bool 表示“完成”标志。

  • 继任者列表。我们不可避免地需要它来进行 f-cost 向上传播。我还保留了简单的后继状态列表——比如[阻塞、遗忘、存在]。它是跟踪被遗忘和阻塞的节点所必需的。 (阻塞 - 在图中 - 被某个节点扩展得更快)

  • PDF 中提到的两个 F,我们当前的 F,以及最被遗忘的继任者 F。

  • 节点深度

边界和叶子列表中的节点排序应该像这样进行:“如果我们有“完成”枚举标志,则选择最好的被遗忘的后继 F,否则选择当前 F,如果相等,则选择最深的。叶列表使用完全相同的条件以相反的顺序排序。

基本算法大纲是这样的(类似于PDF):

  • 我们从边界中选择最佳节点,如果它具有“已完成”标志 - 我们知道我们会记住,重置迭代器,并且在这种情况下我们必须重置最佳遗忘后继 F(原因很复杂)。

  • 如果我们在列表中还没有这个后继(可能是,当我们记住时) - 我们生成它并将其设置为 F,如 PDF 中所述。

  • 接下来是最复杂的事情——我们测试具有相同状态的节点是否存在于边界或树分支列表中。如果是这样 - 我将在稍后描述要做什么。如果不是,我们只需将子级添加到边界(并从叶列表中删除父级)。

  • 在所有后继枚举结束的情况下 - 我们会执行所谓的 f 成本备份,如果我们没有任何被遗忘的节点(并且有一些后继),我们会从边界并将其添加到树分支列表中。

如何忘记:我们从叶子列表中选择第一个叶子(最差的叶子),将其从边界中删除,将其从父节点的后继列表中删除,如果需要,更新(减少)父节点的最佳被遗忘后继节点的 F,如果父节点是不在边界上 - 我们将其从树分支列表中删除并将其添加到边界并添加到叶列表中,如果它现在是叶(不再有继任者)。

如果我们生成了一个已经在边界或树分支列表中的后继者,该怎么办。首先,我们需要测试它是否更好——我们比较两个节点的 PathCost + H(“原始”F)。请注意,我们根本无法比较备份的 F - 这不起作用。如果不是更好 - 我们只是将后继状态设置为阻塞。如果是 - 可能存在这样的情况,即最差的节点是一个巨大子树的根(太复杂,无法再次解释)。在这种唯一的情况下,我们完全切断了子树,SMA 立即忘记了一堆节点。在用更好的节点替换更差的节点后,我们从它的父后继列表、边界、叶列表甚至树分支列表中删除更差的节点(它甚至可能在那里!),将后继状态设置为阻塞它的父节点并不要'不要忘记检查更糟糕的节点的父节点现在是否已阻止所有节点 - 我们需要将其 F 设置为无穷大,因为它成为终端节点。

也许我没有最简单的实现,但它是唯一适合我的。我使用了 8 个谜题进行测试 - 使用最少 (n+1) 个内存(计算起始节点)解决 n 步,并使用传统的 a-star 检查解决方案的最优性。我花了大约 20 到 30 个小时试图找出所有细节 - 主要问题在于失败测试用例的复杂性 - 我只有在 20 多个步骤中出现“用更好的节点替换”逻辑错误对数以千计的随机种子进行广泛测试。还要注意优先级队列——在很多情况下我不得不重新插入项目,导致 F、最好忘记的 F 或“完成”标志的任何变化——改变排序顺序。我最终检查了每个出队的二进制堆一致性。摆脱最复杂的无休止循环错误的主要想法是检查,在所有情况下都不会降低 F。这样 F 会不断增加。

我将在几周后分享有效的实现源代码。

【讨论】:

    【解决方案2】:

    我相信this PDF 是 AIMA 的 SMA* 部分,适合那些没有这本书的人。

    我首先注意到来自维基百科的伪代码在该行中有一个相当明显的错误:

    parent.successors.remove(parent);
    

    应该是

    parent.successors.remove(badNode);
    

    (父母怎么可能是自己的继任者?)

    “必要”是什么意思?

    如果它的父节点还没有在队列中,那么我们必须将它添加到队列中。否则,我们最终会再次搜索该节点。

    内存限制是多少?队列大小或处理的节点?

    队列将占用所有可用内存。处理的节点没有队列。这正是 SMA* 可以重新遍历节点并可能卡住的原因。

    如果当前节点根本没有子节点怎么办?

    如果一个节点没有子节点,那么它就是一个叶子节点。如果它是一个叶节点,那么它就是一个终端节点。在这种情况下,如果它不是目标节点,我们将其 f-cost 设置为无穷大,并将该信息传播给其父节点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-22
      • 1970-01-01
      • 2011-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-19
      • 1970-01-01
      相关资源
      最近更新 更多