Abstract
Pathfinding in uniform-cost grid environments is a problem commonly found in application areas such as robotics and video games. The state-of-the-art is dominated by hierarchical pathfinding algorithms which are fast and have small memory overheads but usually return suboptimal paths. In this paper we present a novel search strategy, specific to grids, which is fast, optimal and requires no memory overhead. Our algorithm can be described as a macro operator which identifies and selectively expands only certain nodes in a grid map which we call jump points. Intermediate nodes on a path connecting two jump points are never expanded. We prove that this approach always computes optimal solutions and then undertake a thorough empirical analysis, comparing our method with related works from the literature. We find that searching with jump points can speed up A* by an order of magnitude and more and report significant improvement over the current state of the art.
摘要
比如在移动机器人和视频游戏的应用领域中,统一代价网格环境中的路径搜索是一个常见的问题。最先进的技术是分层路径搜索算法,这类算法不仅搜索速度快,而且内存占用小,但是通常返回的是次优的路径。在本文中,我们提出了一个新的搜索方法,特别对于栅格地图,具有速度快、最优性、且不需要占用内存。我们的这个算法可以被形容为一个宏操作符,它可以识别并且选择扩展在栅格地图上的某些节点,该节点我们称之为跳转节点。连接两个跳点的路径中间上的节点不会在被扩展。我们证明这个方法总会计算出最优的解并且随后进行全方面的实例分析,再将相关的文献工作与之我们的方法做对比。我们可以发现到挑点搜索算法可以加快A*一个数量级甚至更多的搜索速度,而且报告了与现在最高技术对比有着显著的改进。
Introduction
Widely employed in areas such as robotics (Lee and Yu 2009), artificial intelligence (Wang and Botea 2009) and video games (Davis 2000; Sturtevant 2007), the ubiquitous undirected uniform-cost grid map is a highly popular method for representing pathfinding environments. Regular in nature, this domain typically features a high degree of path symmetry (Harabor and Botea 2010; Pochter et al. 2010). Symmetry in this case manifests itself as paths (or path segments) which share the same start and end point, have the same length and are otherwise identical save for the order in which moves occur. Unless handled properly, symmetry can force search algorithms to evaluate many equivalent states and prevents real progress toward the goal.
In this paper we deal with such path symmetries by developing a macro operator that selectively expands only certain nodes from the grid, which we call jump points. Moving from one jump point to the next involves travelling in a fixed direction while repeatedly applying a set of simple neighbour pruning rules until either a dead-end or a jump point is reached. Because we do not expand any intermediate nodes between jump points our strategy can have a dramatic positive effect on search performance. Furthermore, computed solutions are guaranteed to be optimal. Jump point pruning is fast, requires no preprocessing and introduces no memory overheads. It is also largely orthogonal to many existing speedup techniques applicable to grid maps.
We make the following contributions: (i) a detailed description of the jump points algorithm; (ii) a theoretical result which shows that searching with jump points preserves optimality; (iii) an empirical analysis comparing our method with two state-of-the-art search space reduction algorithms. We run experiments on a range of synthetic and real-world benchmarks from the literature and find that jump points improve the search time performance of standard A* by an order of magnitude and more. We also report significant improvement over Swamps (Pochter et al. 2010), a recent optimality preserving pruning technique, and performance that is competitive with, and in many cases dominates, HPA* (Botea, Muller, and Schaeffer 2004); a well ¨ known sub-optimal pathfinding algorithm.
序言
广泛应用于机器人技术(Lee和Yu2009),人工智能(Wang和Botea2009)和视频游戏(Davis2000;Sturtevant2007)等领域。普遍存在的无方向统一代价的栅格地图在表示路径搜索环境是一个非常受欢迎的方法。在自然规律上说,该领域通常具有高度的路径对称性(Harabor and Botea 2010; Pochter et al.2010)。在这种情况下,对称性表现为路径(或是路径段),具有相同的起始点和终止点,具有相同的长度,其他也都一样,除了移动顺序。除非处理得当,不然对称性会强行使搜索算法去评估很多等效状态,并且阻止向着目标真正的进程。
在本文中,我们通过开发一个宏操作解决这类的路径对称性,它可以选择性的扩展某些来自栅格地图上的节点,我们称之为跳点。从一个跳点移向下一个跳点,包括在一个固定的方向移动。同时反复应用一系列简单的邻居修剪规则直到遇到任意死胡同或者是跳点到到达目标处。因为我们不扩展跳点之间的任何中间节点,,所以我们的方法在搜索性能上有着巨大的积极影响。此外,计算的解保证是最优的,跳点修剪是快速的,不需要预处理和不须占用内存。它很大程度上与在对栅格地图的很多现有的加速技术形成正交。
我们做出如下的介绍:(i)跳点算法的一个细节描述;(ii)理论结果表明跳点搜索保有最优性;(iii)用我们方法的对比两种最先进的搜索空间缩减算法进行实例分析。我们对文献中一系列合成和真实基准进行了实验,可以发现跳点搜索对标准的A*搜索时间性能提高一个数量级甚至更多。我们也报告关于沼泽的显著提升(Pochter 等人. 2010),一个最近的最优保持修剪技术。该性能与HPA*(Botea、Müller和Schaeffer,2004)相媲美,并且在很多情况下占据着主导地位;一个很著名的次优路径搜索算法。
Related Work
Approaches for identifying and eliminating search-space symmetry have been proposed in areas including planning(Fox and Long 1999), constraint programming (Gent andSmith 2000), and combinatorial optimization (Fukunaga2008). V ery few works however explicitly identify and deal with symmetry in pathfinding domains such as grid maps.
Empty Rectangular Rooms (Harabor and Botea 2010) is an offline symmetry breaking technique which attempts to redress this oversight. It decomposes grid maps into a series of obstacle-free rectangles and replaces all nodes from the interior of each rectangle with a set of macro edges that facilitate optimal travel. Specific to 4-connected maps, this approach is less general than jump point pruning. It also requires offline pre-processing whereas our method is online.
The dead-end heuristic (Bjornsson and Halld ¨ orsson 2006) ´ and Swamps (Pochter et al. 2010) are two similar pruning techniques related to our work. Both decompose grid maps into a series of adjacent areas. Later, this decomposition is used to identify areas not relevant to optimally solving a particular pathfinding instance. This objective is similar yet orthogonal to our work where the aim is to reduce the effort required to explore any given area in the search space.
A different method for pruning the search space is to identify dead and redundant cells (Sturtevant, Bulitko, and Bjornsson 2010). Developed in the context of learning- ¨ based heuristic search, this method speeds up search only after running multiple iterations of an iterative deepening algorithm. Further, the identification of redundant cells requires additional memory overheads which jump points do not have.
Fast expansion (Sun et al. 2009) is another related work that speeds up optimal A* search. It avoids unnecessary open list operations when it finds a successor node just as good (or better) than the best node in the open list. Jump points are a similar yet fundamentally different idea: they allow us to identify large sets of nodes that would be ordinarily expanded but which can be skipped entirely.
In cases where optimality is not required, hierarchical pathfinding methods are pervasive. They improve performance by decomposing the search space, usually offline, into a much smaller approximation. Algorithms of this type, such as HPA* (Botea, Muller, and Schaeffer 2004), are fast ¨ and memory-efficient but also suboptimal.
相关工作
在规划(Fox和Long,1999年)、约束规划(Gent和Smith,2000年)和组合规划(Fukunaga,2008年)等领域提出了识别和消除空间搜索对称性的方法。但是有很少的工作来明确识别和处理比如是栅格地图的路径搜索领域。
空的矩形房间(Harabor和Botea 2010)是一个试图纠正类似忽略的离线对称性处理技术。它将栅格地图分解为一系列无障碍的矩形,将每一个矩形内部的所有节点替换为一组宏边以促进最优的前进。尤其是对于4相连的地图,这个方法不如跳点修剪更通用。它还需要离弦的预处理,反之,我们的方法是在线的。
死胡同启发式(Björnsson and Halldórsson 2006)和沼泽(Pochter et al 2010)是与我们工作相关的两种类似的修剪技术。两者都是分解栅格地图为一系列的相邻区域。之后,该分解被用于识别不相关的区域,最佳地解决特殊的路径搜索实例。该目标与我们的工作相似又正交,我们的目标则是减少需要在搜索空间中任意给定的区域探索所需的努力。
对于修剪空间搜索的一个不同的方法是识别死的单元和冗余的单元(Sturtevant、Bulitko.和 Björnsson 2010)。在基于学习的启发式搜索的背景下开发的这个方法,仅仅在运行迭代深化算法的多次迭代后加快搜索速度。此外,冗余单元的识别需要额外的内存占用,而跳点则是不需要。
快速扩展(Sun等人,2009年)是另一种加速优化A*搜索的相关工作,该搜索找到一个后续节点与在开放列表中的最好的节点一样好(或者更好)时,它会避免不必需要的开放列表操作。跳点是一个相同但又根本不同的构思:它们允许我们去识别通常扩展但又可以完全跳过的大型节点。
在不需要优化的情况下,分层的路径搜索方法是非常普遍的。他们通过分解搜索空间成更小的近似值来提高性能,改搜索空间一般是离线的。比如HPA* (Botea, Müller, and Schaeffer 2004)这种类型的算法,虽然是快并且内存效率高,但是也只是次优的。
Notation and Terminology
We work with undirected uniform-cost grid maps. Each node has ≤ 8 neighbours and is either traversable or not. Each straight (i.e. horizontal or vertical) move, from a traversable node to one of its neighbours, has a cost of 1; diagonal moves cost . Moves involving non-traversable (obstacle) nodes are disallowed. The notation refers to one of the eight allowable movement directions (up, down, left, right etc.). We write y = x+k when node y can be reached by taking k unit moves from node x in direction . When is a diagonal move, we denote the two straight moves at 45 deg to as and .
A path π =< n0, n1, . . . , nk> is a cycle-free ordered walk starting at node n0 and ending at nk. We will sometimes use the set minus operator in the context of a path: for example π \x. This means that the subtracted node x does not appear on (i.e. is not mentioned by) the path. We will also use the function len to refer the length (or cost) of a path and the function dist to refer to the distance between two nodes on the grid: e.g. len(π) or dist(n0, nk) respectively.
符号和术语
我们使用无方向统一代价的栅格地图。每个节点有小于等于8的邻居,而且是可遍历的,也或者是不可遍历的。每次从一个可遍历的节点到它的邻居节点的直线移动(即水平或者垂直),所消耗的代价为1;对角移动的代价则是,不允许的移动包括不可穿越的节点(障碍节点)。符号代表8个可以移动的方向之一(上,下,左,右等等)。当节点 x 沿着方向移动 k 个单元到达 y 节点时,我们写 y = x + k。当对角移动时,我们把与成45角度的两个直线移动表示为 和 .
路径 π = (n0,n1,. . .,nk)是一个从节点n0开始,结束在nk的无周期有序前进。我们有时候会在路径的上下文中使用集减算子:对于实例 π \x 。这意味着被减去的节点 x 不会再出现在(即未提及的)路径上。我们还会使用函数 len 去表示路径的长短(或者是代价)和函数 dist 去表示在地图上的俩个节点的距离:比如 len(π) 或者是 dist(n0,nk)。
Jump Points
In this section we introduce a search strategy for speeding up optimal search by selectively expanding only certain nodes on a grid map which we term jump points. We give an example of the basic idea in Figure 1(a).
Here the search is expanding a node x which has as its parent p(x); the direction of travel from p(x) to x is a straight move to the right. When expanding x we may notice that there is little point to evaluating any neighbour highlighted grey as the path induced by such a move is always dominated by (i.e. no better than) an alternative path which mentions p(x) but not x. We will make this idea more precise in the next section but for now it is sufficient to observe that the only non-dominated neighbour of x lies immediately to the right. Rather than generating this neighbour and adding it to the open list, as in the classical A* algorithm,
Figure 1: Examples of straight (a) and diagonal (b) jump points. Dashed lines indicate a sequence of interim node evaluations that reached a dead end. Strong lines indicate eventual successor nodes.
图1:跳点直线(a)和跳点对角(b)的例子。虚线表示到达死胡同的一系列临时点评估。实线表示最终的后续节点。
Figure 2: We show several cases where a node x is reached from its parent p(x) by either a straight or diagonal move. When x is expanded we can prune from consideration all nodes marked grey.
图2:我们展示出父节点p(x)到达节点x或是直线移动或是对角运动的几种情况。当x扩展时,我们可以考虑修剪所有灰色标记的节点。
we propose to simply step to the right and continue moving in this direction until we encounter a node such as y; which has at least one other non-dominated neighbour (here z). If we find a node such as y (a jump point) we generate it as a successor of x and assign it a g-value (or cost-so-far) of g(y) = g(x) + dist(x, y). Alternatively, if we reach an obstacle we conclude that further search in this direction is fruitless and generate nothing.
In the remainder of this section we will develop a macrostep operator which speeds up node expansion by identifying jump point successors in the case of both straight and diagonal moves. First it will be necessary to define a series of pruning rules to determine whether a node should be generated or skipped. This will allow us to make precise the notion of a jump point and give a detailed description of the jump points algorithm. Then, we prove that the process of “jumping” nodes, such as x in Figure 1(a), has no effect on the optimality of search.
跳点
在本节中,我们介绍一种搜索方法来加快优化搜索,仅仅通过选择性的扩展某些栅格地图上的节点,该节点我们称之为跳点。我们在图1(a)中给出一个基本思想的例子。
这里的搜索是扩展一个拥有父节点 p(x) 的节点 x :方向是从p(x) 到x的一个直线向右前进。当扩展 x 的时候,我们会注意到,评估任何以灰色突出显示的邻居几乎是没有意义,产生的原因是这种移动总是被(即不好于)所提及的p(x)可替代的路径所支配,而不是x。我们会在下一节中更明确地阐述这个想法,而现在只需仅仅专注于 x 的唯一未支配的邻居位于右侧。而不像是经典的A*算法那样生成这个邻居而且加入开放列表里,我们建议简单的向右走并持续的向这个方向移动,直到遇到一个节点,比如y;该节点至少有一个其他不可支配的邻居(这里可表示为z)。如果我们找到一个节点比如是y(一个跳点),我们生成它作为x的后继节点,并分配给它一个g值(目前代价)这个g值表示为:g(y) = g(x)+dist(x,y).亦或者是,如果我们到达一个障碍物,我们推断在这个方向上的进一步搜索是徒劳的,不会产生任何结果(毫无结果,一无所获)。
我们建议仅仅向右进行移动并持续向这个方向移动,直至遇到像y这样的节点,该节点具有至少一个其他非支配邻居节点(这里为z)。如果我们找到一个类似y的节点(一个跳点),我们将生成x的后续节点g(y)=g(x)+dist(x,y)的g值(目前为止的代价)。或者是,如若我们遇到了障碍,我们将会得出结论,在这个方向上的搜索是徒劳的,没有任何结果。
在本节的剩余部分中,我们将会开发一个宏步操作来加快节点扩展,而这个扩展是通过在直线和对角移动的情况下识别跳点后继。首先,它需要定义一系列修剪规则来确定一个节点是否生成或是跳过。这将允许我们精确的定义跳点的概念,同时给出跳点算法的细节描述。之后,我们证明了“跳跃”节点的过程,如图1(a)中的 x 对搜索的最优性并无影响。
Neighbour Pruning Rules
In this section we develop rules for pruning the set of nodes immediately adjacent to some node x from the grid. The objective is to identify from each set of such neighbours, i.e. neighbours(x), any nodes n that do not need to be evaluated in order to reach the goal optimally. We achieve this by comparing the length of two paths: π, which begins with node p(x) visits x and ends with n and another path π 0 which also begins at node p(x) and ends with n but does not mention x. Additionally, each node mentioned by either π or π 0 must belong to neighbours(x).
There are two cases to consider, depending on whether the transition to x from its parent p(x) involves a straight move or a diagonal move. Note that if x is the start node p(x) is null and nothing is pruned.
Straight Moves: We prune any node n ∈ neighbours(x) which satisfies the following dominance constraint:
len( hp(x), . . . , ni \ x ) ≤ len( hp(x), x, ni ) (1)
Figure 2(a) shows an example. Here p(x) = 4 and we prune all neighbours except n = 5.
Diagonal Moves: This case is similar to the pruning rules we developed for straight moves; the only difference is that the path which excludes x must be strictly dominant:
len( hp(x), . . . , ni \ x ) < len( hp(x), x, ni ) (2)
Figure 2(c) shows an example. Here p(x) = 6 and we prune all neighbours except n = 2, n = 3 and n = 5.
Assuming neighbours(x) contains no obstacles, we will refer to the nodes that remain after the application of straight or diagonal pruning (as appropriate) as the natural neighbours of x. These correspond to the non-gray nodes in Figures 2(a) and 2(c). When neighbours(x) contains an obstacle, we may not be able to prune all non-natural neighbours. If this occurs we say that the evaluation of each such neighbour is forced.
Definition 1. A node n ∈ neighbours(x) is forced if:
1. n is not a natural neighbour of x
2.len [ ( p(x), x, ni ) ]< len [ ( hp(x), . . . , ni )\ x ]
In Figure 2(b) we show an example of a straight move where the evaluation of n = 3 is forced. Figure 2(d) shows an similar example involving a diagonal move; here the evaluation of n = 1 is forced.
邻域修剪规则
在本节中我们制定规则用于来自栅格中修剪相邻一些节点x的节点集。其目的是识别来自每组这类的邻居点,即邻居(x),为了能够达到最佳目标的优化,不需要评估任何的节点n。我们通过比较两个路径的长度来实现这个目标:π,以节点p(x)开始访问x并结束于n,另一个路径π也是从节点p(x)开始并且以n结束,但未曾提及x。此外,不管是π还是π所提到的节点必须是属于邻居(x).
这里有两个情况需要去考虑,取决于父节点p(x)到x的转变涉及的是直线移动还是对角移动。注意,如果x是起始点而p(x)是空的,则不需修剪任何。
直线移动:我们修剪任何的节点n∈邻居(x),需要满足以下控制限制:
len( hp(x), . . . , ni \ x ) ≤ len( hp(x), x, ni ) (1)
图2(a)显示一个例子。这里的p(x)=4,我们修剪了n=5以外的所有邻居点。
对角移动:这种情况则类似于我们建立的直线修剪规则;唯一不同的是排除x的路径必须是严格的占据主导地位:
len( hp(x), . . . , ni \ x ) < len( hp(x), x, ni ) (2)
图2(c)显示一个例子。这里的p(x)=6,我们修剪了除n=2,n=3,n=5的所有邻居点。
假设邻域(x)不包括障碍物,我们将在应用直线或者对角线修剪(视情况而定)后的节点称之为x的自然域。这里对应的则是图2(a)与2(c)中非灰色节点。当邻域(x)包含障碍时我们,我们则是可能不会去修剪所有非自然邻居。如若发生这类情况,我们说对于每个这样的邻居评估是被迫的。
定义1. 一个节点n∈邻域(x)是强迫的,如若:
1.n不是x的自然邻域
2.len [ ( p(x), x, ni ) ]< len [ ( hp(x), . . . , ni )\ x ]
Algorithmic Description
We begin by making precise the concept of a jump point.
Definition 2.Node y is the jump point from node x, heading in direction , if y minimizes the value k such that y = x+k and one of the following conditions holds:
1. Node y is the goal node.
2. Node y has at least one neighbour whose evaluation is forced according to Definition 1.
3. is a diagonal move and there exists a node z = y + ki which lies ki ∈ N steps in direction ∈ { , } such that z is a jump point from y by condition 1 or condition 2.
Figure 1(b) shows an example of a jump point which is identified by way of condition 3. Here we start at x and travel diagonally until encountering node y. From y, node z can be reached with ki = 2 horizontal moves. Thus z is a jump point successor of y (by condition 2) and this in turn
identifies y as a jump point successor of x.
The process by which individual jump point successors are identified is given in Algorithm 1. We start with the pruned set of neighbours immediately adjacent to the current node x (line 2). Then, instead of adding each neighbourn to the set of successors for x, we try to “jump” to a node that is further away but which lies in the same relative direction to x as n (lines 3:5). For example, if the edge (x, n) constitutes a straight move travelling right from x, we look for a jump point among the nodes immediately to the right of x. If we find such a node, we add it to the set of successors instead of n. If we fail to find a jump point, we add nothing. The process continues until the set of neighbours is exhausted and we return the set of successors for x (line 6).
In order to identify individual jump point successors we will apply Algorithm 2. It requires an initial node x, a direction of travel , and the identities of the start node s and the goal node g. In rough overview, the algorithm attempts to establish whether x has any jump point successors by stepping in the direction (line 1) and testing if the node n at that location satisfies Definition 2. When this is the case, n is designated a jump point and returned (lines 5, 7 and 11). When n is not a jump point the algorithm recurses and steps again in direction but this time n is the new initial node (line 12). The recursion terminates when an obstacle is encountered and no further steps can be taken (line 3). Note that before each diagonal step the algorithm must first fail
to detect any straight jump points (lines 9:11). This check corresponds to the third condition of Definition 2 and is essential for preserving optimality.
算法描述
我们首先要明确跳点的概念。
定义2.节点y是节点x向方向的跳跃点,如若y使得k值最小,有y = x+k,同时满足一下的条件之一:
1、节点y是目标节点。
2、节点y至少有一个邻居点,其评估根据定义1被强迫。
3、是对角移动,而且在此还存在一个节点z = y+,该节点处于∈【,】方向的∈N步,使得z是由条件1或者条件2从y起始的跳跃点。
图1(b)表示由条件3定义的一个跳点实例,这里我们开始于x,同时进行对角前进,直到碰到节点y。节点z可以从y通过=2水平到达。因此,z是y的后续跳点(根据条件2),并且将y标记为x的后续跳点。
在算法1中给出了识别单独的跳点后续节点的过程。我们从相邻的当前节点x(第二行)的修剪域开始。然后代替将每个相邻节点n添加到x的后续节点,我们将尝试“跳跃”到距离x更远并且是与n相同的对应方向(3到5行)。
例如,如果边(x,n)构成了从x向右的直线移动,我们在紧邻x的右侧节点中寻求跳点。如果我们找到了这样的一个节点,我们添加其到后续节点集合来代替n。如果我们找不到跳点,我们则是啥也不加。该过程持续到邻居节点耗尽,之后我们返回关于x的后续集(第六行)。
为了识别单独跳点的后续点,我们将使用算法2。它需要一个最初的节点x,一个行进的方向和起始节点s以及最终目标节点。粗略概述,该算法试图通过沿着方向(第一行)步进前行并测试x该位置的节点n是否满足定义2来确定x是否有任何跳跃点的后续点。在此情况下,n则是被标明为跳点并且返回(第五,七,十一行)。
当n不是跳点的时候,算法递归且再次在方向上步进出点前行,但是这回的n是单独的初始节点(第12行) 。当遇到障碍物的时候,递归停止并且不能进行下一步(第三行)。注意的是,在每次对角步骤之前,算法必须首先不能检测到任何的直线跳点(第九到11行)。这个检查对应的定义2的第三个条件,并且是保证最优性的必要条件。
https://qiao.github.io/PathFinding.js/visual/
https://www.redblobgames.com/pathfinding/a-star/introduction.html