What algorithms compute directions from point A to point B on a map?
地图提供商(如Google或Yahoo!)地图)建议方向?
我的意思是,他们可能有某种形式的真实数据,当然包括距离,但也可能包括行驶速度、人行道、火车时刻表等。但是假设数据是一种更简单的格式,比如一个具有反映距离的边权的非常大的有向图。我希望能够快速计算从一个任意点到另一个任意点的方向。有时这些点会很近(在一个城市内),而有时它们会相距很远(跨国)。
像Dijkstra算法这样的图形算法将无法工作,因为图形是巨大的。幸运的是,像*这样的启发式算法可能有效。然而,我们的数据是非常结构化的,也许某种分层方法可以工作?(例如,将预先计算的方向存储在相距很远的某些"关键"点之间,以及一些本地方向。然后,两个远点的方向将涉及到一个关键点的本地方向、到另一个关键点的全局方向,然后再次涉及到本地方向。)
实践中实际使用的算法是什么?
附言:这个问题的动机是在在线地图方向上发现一些怪癖。与三角形不等式相反,有时谷歌地图认为x-z比使用中间点(如x-y-z)需要更长的时间和更长的距离,但也许它们的行走方向也会针对另一个参数进行优化?
PPS。这是对三角不平等的另一个违背,它暗示(对我来说)他们使用某种分层的方法:x-z对x-y-z。前者似乎使用了著名的塞巴斯托波尔大道,尽管它有点不合适。
编辑:这两个例子似乎都不起作用了,但都是在最初发布的时候起作用的。
作为一个在地图公司工作了18个月的人,包括在路由算法方面的工作…是的,Dijkstra的确实有效,经过了一些修改:
- 不是从源头到Dijkstra,而是从两端开始,扩大两边,直到中间相遇。这大约消除了一半的工作量(2*pi*(r/2)^2与pi*r^2)。
- 为了避免在源和目的地之间探索每个城市的后巷,您可以有几个地图数据层:一个只包含高速公路的"高速公路"层,一个只包含次要街道的"次要"层,等等。然后,您只探索更详细层的较小部分,并根据需要进行扩展。很明显,这个描述遗漏了很多细节,但你明白了。
通过沿着这些线路进行修改,您甚至可以在非常合理的时间段内进行跨国家路由。
这个问题在过去几年一直是一个活跃的研究领域。主要的想法是对图表进行一次预处理,以加速所有后续查询。有了这些额外的信息,行程可以很快计算出来。不过,Dijkstra的算法是所有优化的基础。
蛛形纲动物描述了基于层次信息的双向搜索和边缘修剪的用法。这些加速技术工作得很好,但最新的算法在所有方面都优于这些技术。利用现有的算法,在大陆公路网上,最短路径的计算时间可在不到1毫秒的时间内完成。一个未修改的dijkstra算法的快速实现需要大约10秒的时间。
本文对快速路径规划算法的工程化研究进展进行了综述。有关更多信息,请参阅该论文的参考文献。
已知最快的算法不会在数据中使用有关道路分层状态的信息,例如,如果是公路或本地道路。相反,他们在预处理步骤中计算自己的层次结构,优化后可以加快路线规划。这个预计算可以用来修剪搜索:在dijkstra的算法中,不需要考虑远离起点和终点的慢行道路。这些好处是非常好的性能和结果的正确性保证。
第一种优化的路线规划算法只处理静态道路网络,这意味着图中的边具有固定的成本值。这在实践中是不正确的,因为我们要考虑到动态信息,如交通堵塞或与车辆相关的限制因素。最新的算法也可以处理这些问题,但仍有一些问题需要解决,并且正在进行研究。
如果您需要最短的路径距离来计算TSP的解决方案,那么您可能对包含源和目标之间所有距离的矩阵感兴趣。为此,您可以考虑使用高速公路层次结构计算多到多条最短路径。值得注意的是,在过去的2年中,新的方法改善了这一点。
仅仅解决三角不平等的问题,希望他们正在优化的额外因素是常识。你不一定想要最短或最快的路线,因为这会导致混乱和破坏。如果你想让你的方向更倾向于卡车友好型的主要路线,并且能够应付每个跟随驾驶员的卫星导航系统,那么你很快就会放弃三角形不等式[1]。
如果y是x和z之间的一条狭窄的居住街道,那么如果用户明确要求x-y-z,那么您可能只想通过y使用快捷方式。如果他们要求x-z,那么他们应该坚持走主要道路,即使道路再远一点,也需要更长的时间。这类似于布雷斯的悖论——如果每个人都试图走最短、最快的路线,那么由此产生的拥堵意味着它不再是任何人最快的路线。从这里我们从图论转向博弈论。
[1]事实上,当您允许单向道路并且失去对称性要求时,任何希望所产生的距离将是数学意义上的距离函数的希望都会消失。失去三角不平等也只是在伤口上撒盐。
以下是世界上最快的路由算法对比,并证明其正确性:
http://algo2.iti.uka.de/schultes/hwy/schultes-diss.pdf
下面是谷歌技术部关于这个主题的演讲:
http://www.youtube.com/watch?V=-0erpe8tqbw
下面是Schultes讨论的公路等级算法的实现(目前仅在柏林,我正在编写接口,并且正在开发移动版本):
http://tom.mapsforge.org网站/
我以前没有在谷歌、微软或雅虎地图上工作过,所以我不能告诉你它们是如何工作的。
但是,我为一家能源公司设计了一个定制的供应链优化系统,其中包括他们的卡车车队的调度和路由应用程序。然而,我们的路线选择标准远比建设地点、交通减速或车道关闭更具体。
我们采用了一种称为ACO(蚁群优化)的技术来调度和路由卡车。该技术是一种人工智能技术,用于解决旅行商的路径问题。ACO的诀窍是根据已知的路由事实建立一个错误计算,以便图形求解模型知道何时退出(什么时候错误足够小)。
你可以在ACO或TSP上搜索更多关于这种技术的信息。不过,我还没有使用任何开源的人工智能工具来实现这一点,因此不能推荐一个(尽管我听说Swarm非常全面)。
Graph algorithms like Dijkstra's algorithm will not work because the graph is enormous.
号
这个论点不一定成立,因为Dijkstra通常不会看完整的图,而只看一个非常小的子集(图之间的关联越好,这个子集越小)。
对于行为良好的图,dijkstra实际上可能表现得相当好。另一方面,通过仔细的参数化,A*的性能总是一样好,或者更好。您是否已经尝试过如何对您的数据执行此操作?
也就是说,我也很有兴趣了解其他人的经历。当然,像谷歌地图搜索这样的突出例子尤其有趣。我可以想象像一个定向的近邻启发式。
静态道路网络查询时间方面的最新技术是Abraham等人提出的枢纽标记算法。http://link.springer.com/chapter/10.1007/978-3-642-20662-7_20.最近,微软技术报告http://research.microsoft.com/pubs/207102/msr-tr-2014-4.pdf公布了一份完整的、优秀的实地调查报告。
简短的版本是…
集线器标记算法为静态道路网络提供最快的查询,但需要运行大量RAM(18 GiB)。
传输节点路由稍微慢一点,但是它只需要大约2 GiB的内存,并且具有更快的预处理时间。
收缩层次结构在快速预处理时间、低空间要求(0.4 gib)和快速查询时间之间提供了一个很好的权衡。
没有一种算法是完全主导的…
彼得·桑德斯的这篇谷歌技术演讲可能会引起人们的兴趣。
https://www.youtube.com/watch?V=-0erpe8tqbw
还有安德鲁·戈德伯格的演讲
https://www.youtube.com/watch?V=WPRKC78XLHW
收缩层次的开放源代码实现可从Kit的PeterSanders研究组网站获得。http://algo2.iti.kit.edu/english/routeplanning.php
还有一篇容易访问的博客文章,是微软写的,关于CRP算法的使用…http://blogs.bing.com/maps/2012/01/05/bing-maps-new-routing-engine/
我有点吃惊,没有看到这里提到的弗洛伊德·沃威尔的算法。这个算法的工作原理和dijkstra非常相似。它还有一个非常好的特性,就是它允许你计算,只要你想继续允许更多中间顶点。因此,它很自然地会找到使用州际公路或高速公路相当快的路线。
实际上,我已经做了很多次了,尝试了几种不同的方法。根据地图的大小(地理位置),您可能需要考虑将haversine函数用作启发式函数。
我提出的最佳解决方案是使用一个*和一个直线距离作为启发式函数。但是你需要地图上每个点(交叉点或顶点)的某种坐标。您还可以为启发式函数尝试不同的权重,即
1 | f(n) = k*h(n) + g(n) |
其中k是大于0的常数。
可能类似于主要地点和分层地图之间预先计算的路线的答案,但我的理解是,在游戏中,为了加快A*的速度,您有一个宏观导航非常粗糙的地图,以及一个宏观方向边界导航的细粒度地图。所以你有两条小路径要计算,因此你的搜索空间比简单地做一条到目的地的路径要小得多。如果你要做的事情很多,你会有很多预先计算的数据,所以至少部分搜索是对预先计算的数据的搜索,而不是对路径的搜索。
这纯粹是我的猜测,但我想他们可能会使用覆盖定向地图的影响地图数据结构来缩小搜索范围。这将允许搜索算法在所需行程较长时将路径指向主要路线。
考虑到这是一个Google应用程序,假设大量的魔法是通过广泛的缓存实现的也是合理的。:)如果缓存5%最常见的Google地图路由请求,允许一个大块(20%)的话,我不会感到惊讶。50%??)通过简单的查找来回答的请求。
我对所用的启发式方法很好奇,不久前,我们从圣罗莎附近的同一个起点出发,到达约塞米蒂国家公园的两个不同的营地。这些不同的目的地产生了相当不同的路线(通过I-580或CA-12),尽管两条路线在最后100英里(沿着CA-120)会聚,然后在终点再次分流几英里。这是可以重复的。这两条路线相距50英里,大约100英里,但距离/时间非常接近,正如您所期望的那样。
唉,我无法重现这一点——算法肯定已经改变了。但它让我对算法很好奇。我所能推测的是,有一些定向修剪,它恰好对从远处看目的地之间的微小角度差异非常敏感,或者通过选择最终目的地来选择不同的预先计算的段。
我对这个有了更多的想法:
1)记住,地图代表一个物理组织。存储每个交叉点的纬度/经度。你不需要检查太多超出你目标方向的点。只有当你发现自己被挡住了,你才需要超越这一点。如果您存储了一个高级连接的覆盖,那么您可以对其进行更大的限制——通常情况下,您不会以远离最终目的地的方式通过其中一个连接。
2)将世界划分为一组由有限连通性定义的区域,定义区域之间的所有连通点。查找源和目标所在的区域,从您的位置到每个连接点的起点和终点区域路由,以及连接点之间的简单映射区域。(我怀疑很多后者已经预先计算过了。)
请注意,区域可以小于大都市区域。任何一个有地形特征的城市(如河流)都是多个区域。
说到抓钩,一个基于OpenStreetmap的快速开源路由规划器,我已经阅读了一些文献并实现了一些方法。最简单的解决方案是dijkstra,而简单的改进是双向dijkstra,它只探索大约一半的节点。对于双循环Dijkstra,一条穿过整个德国的路线已经走了1秒(对于汽车模式),在C中可能只有0.5秒左右;
我用双向dijkstra创建了一个真实路径搜索的动画gif。此外,还有更多的方法可以使dijkstra更快,就像做一个*,这是一个"面向目标的dijkstra"。我还为它创建了一个GIF动画。
但是怎么做得更快呢?
问题是,对于路径搜索,必须对位置之间的所有节点进行探索,这是非常昂贵的,因为在德国已经有数百万个节点了。但Dijkstra等的另一个痛点是,这样的搜索使用大量的RAM。
有启发式的解决方案,但也有精确的解决方案,将图形(道路网络)组织成层次结构,两者都有优点和缺点,主要解决速度和RAM问题。我在这个答案中列出了其中一些。
对于graphhopper,我决定使用收缩层次结构,因为它相对容易实现,并且不需要花费很多时间来准备图表。它仍然会导致非常快的响应时间,就像您可以在我们的在线实例graphhopper maps上测试一样。例如,从南非到中国东部,这导致了23万公里的距离和近14天的汽车驾驶时间,并且在服务器上只花了大约0.1秒。
我在路由方面工作了几年,最近一系列的活动都是由我的客户的需求引起的,我发现A*很容易就足够快;实际上没有必要寻找优化或更复杂的算法。在一个巨大的图上进行路由不是问题。
但是速度取决于整个路由网络,我指的是内存中分别表示路由段和连接的弧和节点的有向图。主要的时间开销是创建这个网络所花费的时间。一些粗略的数据是基于一台普通的笔记本电脑运行Windows,并在整个西班牙进行路由:创建网络所用的时间:10-15秒;计算路由所用的时间:太短,无法测量。
另一件重要的事情是能够重新使用网络进行任意多的路由计算。如果您的算法以某种方式标记了节点以记录最佳路由(到当前节点的总成本和到当前节点的最佳弧),那么您必须重置或清除这些旧信息。与其经历数十万个节点,还不如使用一个代数系统。用数据的生成号标记每个节点;计算新路由时增加生成号;任何具有旧生成号的节点都已过时,其信息可以忽略。
我看到操作中的地图是怎么回事:
查看指定中间点的路线:由于该道路不直,路线稍微向后移动。
如果他们的算法不后退,就看不到更短的路线。
全对最短路径算法将计算图中所有顶点之间的最短路径。这将允许预先计算路径,而不需要每次有人想找到源和目标之间最短路径时都计算路径。Floyd Warshall算法是一种全对最短路径算法。
地图从不考虑整个地图。我的猜测是:1。根据你的位置,他们装载一个地方和地标在那个地方。2。当你搜索目的地时,那就是他们加载地图的另一部分,然后用两个地方做一个图表,然后应用最短路径算法。
另外,在计算最短路径时,我怀疑有一种重要的动态编程技术。你也可以参考这个。