跳转至

求解器综述

IPC 赛事:问题起源与发展脉络

IPC 赛事官方网站 汇总了历届比赛的完整信息

国际规划大赛概述(幻灯片)

IPC 2014 年赛事

IPC 2018 年经典规划赛事

第六届国际规划大赛学习页面

国际规划大赛系列概述

依据问题特性,主要可划分为如下两类:

经典规划(Classical Planning, CP):每个实例对应于一个独立的解;

通用规划(General Planning, GP):多个实例共享同一个解子图算法(即控制流图 Control Flow Graph),常见形式化范式包括 QNP 与 FOND。

CP:经典规划

  • FF
  • FD
  • LAPKT

GP:通用规划

  • MyND
  • PRP
  • FOND-SAT
  • PRP_planner-for-relevant-policies

从宏观视角审视,学界通常沿两条技术路径展开探索:

自顶向下(Top-Down)方法:在与或树(亦可理解为控制流图 Control Flow Graph)中进行搜索,从而得到类算法(algorithm-like)的策略(policy)。就其本质而言,这乃是符号化 goto 语句所对应的底层汇编算法的等价表述。

自底向上(Bottom-Up)方法:在经典规划中生成实例,据此完善并补全抽象图,并以响应式方式持续打补丁。FOND-SAT 可被视为一种文法自动机,通过符号 SAT 可满足性求解实现规划。据本文作者理解,其本质归属于自顶向下(Top-Down)的"求解"范式。

诸如 Merging Example Plans into Generalized Plans for Non-deterministic Environments 以及 Directed Search for Generalized Plans Using Classical Planners 等研究工作即属于此类范畴。

正如 Dijkstra 在其经典著作中所阐述的,编程应当是经由严谨思考与推理所得的算法产物,而不应是在意大利面条式代码中盲目调试、反复试错,以及为各种特殊情况仓促打补丁的结果。

图灵所开创的自动编程篇章,令人坚信规划(plan)将是一种优雅的解法。

QNP 的提出,实际上是受模拟包含 while 循环的链表反转(Linked List Reverse)过程的启发。此类问题的解子图策略(policy),本质上便是**包含 while 循环的算法(algorithm)**。

从实例中学习时,不可避免地需要考量**覆盖率**(即已解决问题数目占规划问题总数的比例)。我们设想,倘若存在一个较为完善的通用规划(GP)的良性定义,其结果应当是经过精心设计的自顶向下结构的产物,而非仓促上线、不断打补丁的拼合体——尽管在多数实践场景中,后者往往成为常态。

一个较为合适的算法示例是三数之和问题:

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c,使得 a + b + c = 0?请找出所有满足和为 0 且不重复的三元组。

注意:答案中不得包含重复的三元组。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        sort(nums.begin(),nums.end());
        for(int i =0;i<nums.size();i++){
            if(nums[i] > 0) return res;
            // 错误去重方法,将会漏掉-1,-1,2 这种情况
            /*
            if (nums[i] == nums[i + 1]) {
                continue;
            }
            */
            // 正确去重方法
            if(i >0 && nums[i] == nums[i - 1] ){
                continue;
            };
            int left = i+1;
            int right = nums.size() -1;
            while(left < right){
                // 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组
                /*
                while (right > left && nums[right] == nums[right - 1]) right--;
                while (right > left && nums[left] == nums[left + 1]) left++;
                */
                if(nums[i] + nums[left] + nums[right] > 0){
                    right --;
                }else if(nums[i] + nums[left] + nums[right] <  0){
                    left++;
                }else{//nums[i] + nums[left] + nums[right] = 0
                    res.push_back(vector<int>{nums[i], nums[left], nums[right]});
                    // 去重逻辑应该放在找到一个三元组之后
                    while (right > left && nums[right] == nums[right - 1]) right--;
                    while (right > left && nums[left] == nums[left + 1]) left++;

                    // 找到答案时,双指针同时收缩
                    right--;
                    left++;
                }
            }
        }
        return res;
    }
};

审视上述示例,需着重关注以下要点:

错误的去重方法将会遗漏诸如 -1, -1, 2 这类情形;去重逻辑的放置位置亦会对最终结果产生显著影响,例如 0, 0, 0 的案例所示。

由此可得出的启示,正如 Dijkstra 在其著作中所阐述的:唯有自顶向下(Top-Down)的精巧设计,方能产生兼具实用价值与强鲁棒性的算法解,而非仅止于玩具级别的实现。

而这一点,恰恰是从实例经典规划(CP)中学习通用规划(GP)抽象图、不断打补丁的自底向上(Bottom-Up)方法所无法习得的。经由后者所习得的 GP 抽象控制流图往往千疮百孔、遍布补丁,甚至无法通过足够的测试用例以满足所需的测例覆盖率。

为何 CFG 控制流图是最佳中间表示(Intermediate Representation, IR)方法

Planning Graph Analysis:规划图分析

上述问题对于基于规划图(如 IPP、Graphplan 和 Blackbox)的现行规划器而言,具有重要的理论意义与实践价值。

面向动态图的最新路径查找算法

面向动态图(D*、D* Lite、LPA* 等)的最新路径查找算法之间存在何种本质差异?

算法差异讨论

截至目前所整理的相关算法清单如下:

D*(1994年)
Focused D*(1995年)
Dynamic SWSF-FP(1996年)
LPA(1997年)
LPA* / Incremental A*(2001年)
D* Lite(2002年)
SetA*(2002年)
HPA*(2004年)
Anytime D*(2005年)
PRA*(2005年)
Field D*(2007年)
Theta*(2007年)
HAA*(2008年)
GAA*(2008年)
LEARCH(2009年)
BDDD*(2009年——笔者无法获取该论文)
Incremental Phi*(2009年)
GFRA*(2010年)
MTD*-Lite(2010年)
Tree-AA*(2011年)

可以在上述问题栏中找到每篇论文的对应链接。

简单重计算

D*(亦称 Dynamic A*,1994年):在初次运行时,D* 的行为与 A* 高度相似,能够迅速找到从起点至终点的最优路径。然而,当单元沿路径移动且图结构发生变化时,D* 能够极为高效地重新计算从当前单元位置至终点的最优路径,其速度远超重新运行 A* 的方案。然而,D* 以其实现复杂性而著称,更为简洁的 D* Lite 已完全取代了 D*。

Focused D*(1995年):对 D* 的改进,旨在提升运算速度以实现"更接近实时"的性能表现。笔者未能找到其与 D* Lite 的直接对比资料,但鉴于其提出年代较早且 D* Lite 的讨论更为广泛,可以合理推断 D* Lite 更具优势。

Dynamic SWSF-FP(1996年):存储从每个节点至目标节点的距离估算值。初始设置阶段需计算所有距离,计算开销较大。当图结构发生变化后,该算法仅更新距离发生变化的节点。该算法与 A* 及 D* 无直接关联。适用于每次变更后需计算从多个节点至目标距离的场景;否则,LPA* 或 D* Lite 通常是更为实用的选择。

LPA* / Incremental A*(2001年):LPA*(Lifelong Planning A*,亦称 Incremental A*,有时被混淆地简称为"LPA",但其与另一同名算法并无关联)是 Dynamic SWSF-FP 与 A* 的结合体。初次运行时,其行为与 A* 完全一致。然而,在图结构发生小幅变更后,相比于重新运行 A* 进行同一起讫点对的搜索,LPA* 能够利用先前运行中积累的信息,大幅减少需要检查的节点数量。这恰好契合了笔者的需求,因此 LPA* 被认为是最佳选择。LPA* 与 D* 的不同之处在于,它始终寻求从同一固定起点到同一固定终点的最优路径,不适用于起点发生移动的场景(例如沿初始最优路径移动的单元)。然而……

D* Lite(2002年):该算法利用 LPA* 来模拟 D* 的行为。换言之,当单元沿初始最优路径移动且图结构发生变化时,D* Lite 调用 LPA* 来计算该单元的新最优路径。D* Lite 被公认在实现上远比 D* 简洁,并且其运行速度始终不逊于 D*,因此已完全淘汰了 D*。从任何角度来看,都没有继续使用 D* 的充分理由,建议改用 D* Lite。

任意角度运动

Field D*(2007年):D* Lite 的一种变体,不再将运动限制于网格约束之内。换言之,最优路径可使单元沿任意角度移动,而不仅限于网格点之间的 45 度(或 90 度)方向。该技术已被美国国家航空航天局(NASA)应用于火星探测车的路径规划。

Theta*(2007年):A* 的一种变体,能够提供比 Field D* 更优(更短)的路径。然而,由于其基于 A* 而非 D* Lite,因此不具备 Field D* 所具有的快速重规划能力。另请参阅相关文献。

Incremental Phi*(2009年):兼具两者之长。Theta* 的增量版本(即支持快速重规划)。

移动目标点

GAA*(2008年):GAA*(Generalized Adaptive A*)是 A* 的一种变体,专门用于处理运动目标点场景。这是更早的算法"Moving Target Adaptive A*"的泛化推广。

GFRA*(2010年):GFRA*(Generalized Edge Retrieval A*)似乎是 GAA* 的进一步泛化,通过使用另一种称为 FRA* 的算法,将其适用范围拓展至任意图结构(即不限于二维网格)。

MTD*-Lite(2010年):MTD*-Lite(Moving Target D* Lite)是"D* Lite 的扩展,它使用 Generalized Edge Retrieval A* 背后的原理"来实现面向移动目标的高效重规划搜索。

Tree-AA*(2011年):(待考证)似乎是一种用于未知地形搜索的算法,但与本小节中的所有其他算法一样,它同样基于 Adaptive A*,因此在此一并列出。与本节中其他算法的对比尚不明确。

快速/次优

Anytime D*(2005年):这是 D* Lite 的"随时"变体,通过将 D* Lite 与称为 Anytime Repairing A* 的算法相结合而实现。随时算法是一种可在任意时间约束下运行的算法——它能够迅速找到一条初始的次优路径作为起点,然后在给定更多时间的情况下,对该路径进行持续改进。

HPA*(2004年):HPA*(Hierarchical Pathfinding A*)专为在大型图上为大量单元(例如 RTS 实时策略视频游戏中的单位)寻找路径而设计。这些单元各自具有不同的起始位置,且可能具有不同的目标位置。HPA* 将图分解为层次结构,从而能够快速找到所有这些单元的"接近最优"路径,其速度远胜于在每个单元上单独运行 A* 的方案。另请参阅相关文献。

PRA*(2005年):据笔者理解,PRA*(Partial Refinement A*)解决了与 HPA* 相同的问题,但采用了不同的实现方式。两者具有"相似的性能特征"。

HAA*(2008年):HAA*(Hierarchical Annotated A*)是 HPA* 的泛化推广,允许限制某些单元在某些地形上的通行能力(例如,某些通道大型单位无法通过而小型单位则可以;或仅飞行单位能够穿过的孔洞等)。

其他/未知

LPA(1997年):LPA(Loop-free Pathfinding Algorithm)似乎是一种路由算法,与本节中其他算法所解决的问题仅存在轻微关联。笔者在此提及它,仅因为该论文在互联网上多处被混淆地(且错误地)引用为介绍 LPA* 的文献,实则并非如此。

LEARCH(2009年):LEARCH 是一组机器学习算法的组合,用于教导机器人如何自主寻找接近最优的路径。作者建议将 LEARCH 与 Field D* 结合使用以获得更优效果。

BDDD*(2009年):(待考证)笔者无法获取该论文。

SetA*(2002年):(待考证)这显然是 A* 的一种变体,用于搜索图的"二元决策图"(BDD)模型。据称在某些情况下,其运行速度"比 A* 快数个数量级"。然而,若笔者的理解正确,这些情况是指图中每个节点均具有大量边的场景。

综合上述分析,LPA* 似乎最适合笔者所面临的问题。