什么algorithm在地图上计算从点A到点B的方向?
地图提供者(如Google或Yahoo! Maps)如何提供方向?
我的意思是,他们可能有某种forms的真实世界的数据,当然包括距离,但也可能是像驾驶速度,人行道,列车时刻表等等。但假设数据是一个更简单的格式,比如一个非常大的有向图边缘权重反映距离。 我希望能够快速计算从一个任意点到另一个点的方向。 有时候这些点会在一起(在一个城市内)靠近,而有时它们会相距甚远(越野)。
像Dijkstraalgorithm这样的graphicsalgorithm将不起作用,因为graphics是巨大的。 幸运的是,像A *这样的启发式algorithm可能会起作用。 但是,我们的数据是非常有条理的,也许某种分层的方法可能工作? (例如,存储相距很远的某些“关键”点之间的预先计算的方向以及一些局部方向,然后两个远处点的方向将涉及到关键点的局部方向,到另一关键点的全局方向,然后是局部方向再次。)
实际中使用了哪些algorithm?
PS。 这个问题的动机是在在线制图方向上发现怪癖。 与三angular形不等式相反,有时Google Maps会认为XZ比XYZ中的中间点更长,而且更远。 但是也许他们的行走方向也可以优化另一个参数呢?
PPS。 这是另外一个违反三angular形不平等的情况,对我来说,他们使用某种分层的方法: XZ和XYZ 。 前者似乎使用着名的塞瓦斯托波尔大道,尽pipe它稍微偏离了方向。
编辑 :这些例子都没有工作了,但都在原来的职位时。
作为一个在地图公司工作了18个月的人,包括在路由algorithm方面的工作……是的, Dijkstra的工作,做了一些修改:
- 迪克斯特拉不是一次从源头到目的地,而是从两端开始,扩大双方直到他们在中间相遇。 这消除了大约一半的工作(2 * pi *(r / 2)^ 2 vs pi * r ^ 2)。
- 为了避免在源和目的地之间探索每个城市的后巷,可以有几层地图数据:只包含高速公路的“高速公路”层,仅包含次要街道的“次要”层等等。 然后,只探索更详细图层的较小部分,并根据需要进行扩展。 显然这个描述留下了很多细节,但你明白了。
通过这些修改,您甚至可以在非常合理的时间内完成跨国路由。
这个问题在过去几年一直是一个活跃的研究领域。 主要思想是对图进行一次 预处理 ,以加快所有后续查询 。 有了这些附加信息,可以非常快地计算行程。 但是, Dijkstra的algorithm是所有优化的基础。
Arachnid描述了基于分层信息的双向search和边缘修剪的使用。 这些加速技术运行得非常好,但最新的algorithm通过一切手段胜过了这些技术。 使用目前的algorithm,在欧陆大陆路网上,可以在比毫秒less得多的时间内计算最短path。 Dijkstra的未修改algorithm的快速实现需要大约10秒钟 。
文章工程快速路线规划algorithm给出了该领域研究进展的概述。 有关更多信息,请参阅该文件的参考资料。
已知最快的algorithm不使用关于数据中道路的等级状态的信息,即,如果是公路或当地道路。 相反,他们在预处理步骤中计算自己的层次结构,以便加快路线规划。 这个预计算可以用来修剪search:远离开始和目的地,在Dijkstra的algorithm中,不需要考虑缓慢的道路。 好处是非常好的performance和结果的正确性保证。
第一种优化的path规划algorithm只处理静态路网,即图中的边具有固定的成本值。 实际情况并非如此,因为我们要考虑交通堵塞或依赖车辆限制等dynamic信息。 最新的algorithm也可以处理这些问题,但是仍然有待解决的问题和正在进行的研究。
如果您需要最短path距离来计算TSP的解决scheme,那么您可能对包含源和目标之间所有距离的matrix感兴趣。 为此,您可以考虑使用公路层次结构计算多对多最短path 。 请注意,过去两年新的方法已经改善了这一点。
只要解决三angular不平等侵犯,希望他们正在优化的额外因素是常识。 你不一定要最短或最快的路线,因为它可能导致混乱 和 破坏 。 如果你想让自己的方向更喜欢卡车友好的主要路线,并且可以应付让每一位随行的司机下车,那么你很快就会丢弃三angular形的不平等[1]。
如果Y是X和Z之间狭窄的住宅街道,如果用户明确要求XYZ,则可能只希望通过Y使用快捷方式。 如果他们要求XZ的话,他们应该坚持主要的道路,即使有点进一步,需要更长的时间。 这与Braess的悖论相似 – 如果每个人都试图走最短,最快的路线,那么由此产生的拥堵意味着它不再是任何人的最快路线。 从这里我们偏离图论到博弈论。
[1]事实上,当你允许单向道路并且失去对称性要求时,任何希望产生的距离都将成为math意义上的距离函数。 失去三angular形的不平等也只是在伤口上抹盐。
这里是世界上最快的路由algorithm比较和certificate正确性:
schultes/hwy/schultes_diss.pdf
这里是关于这个问题的谷歌技术讨论:
http://www.youtube.com/watch?v=-0ErpE8tQbw
下面是由schultes讨论的高速公路层次结构algorithm的实现(目前仅在柏林,我正在编写接口,并且正在开发移动版本):
像Dijkstraalgorithm这样的graphicsalgorithm将不起作用,因为graphics是巨大的。
这个论点并不一定成立,因为Dijkstra通常不会看完整的图,而只是一个非常小的子集(图中相互关联越好,子集越小)。
对于performance良好的图表,Dijkstra可能performance得相当不错。 另一方面,通过仔细的参数化,A *将始终performance良好或更好。 你有没有试过它将如何执行你的数据?
也就是说,我也很想听听其他人的经验。 当然,像谷歌地图的search显着的例子是特别有趣的。 我可以想象像一个定向最近邻的启发式。
我之前没有在Google或者微软或者雅虎地图上工作,所以我不能告诉你他们是如何工作的。
但是,我为能源公司构build了一个定制的供应链优化系统,其中包括一个卡车车队的调度和路由应用程序。 然而,我们的路线标准要比build筑或交通减速或车道封闭的地方要多得多。
我们采用了一种叫做ACO(蚁群优化)的技术来安排和路线卡车。 这种技术是一种应用于旅行商问题解决路由问题的AI技术。 ACO的诀窍是根据已知的路由事实build立一个错误计算,以便图解模型知道何时退出(错误何时足够小)。
你可以谷歌ACO或TSPfind更多的这种技术。 我没有使用任何开源AI工具,所以不能提出一个(虽然我听说SWARM是相当全面的)。
我有点惊讶没有看到这里提到的Floyd Warshall的algorithm 。 这个algorithm的工作非常像Dijkstra的。 它也有一个非常好的function,它允许你计算,只要你想继续允许更多的中间顶点。 所以自然会很快find使用州际公路或高速公路的路线。
我已经做了很多次了,实际上,尝试了几种不同的方法。 根据地图的大小(地理位置),您可能需要考虑使用haversine函数作为启发式。
我所做的最好的解决scheme是使用A *和直线距离作为启发式函数。 但是,那么你需要在地图上的每个点(交点或顶点)的某种坐标。 你也可以尝试不同的权重启发式function,即
f(n) = k*h(n) + g(n)
其中k是一些大于0的常数。
在静态道路networking的查询时间方面的现有技术是由Abraham等人提出的Hub标记algorithm。 http://link.springer.com/chapter/10.1007/978-3-642-20662-7_20 。 最近,作为一个微软技术报告pubs/207102/MSR-TR-2014-4.html ,对该领域进行了一次精彩的书面调查。
简短的版本是…
Hub标记algorithm为静态路网提供了最快的查询,但需要大量的RAM运行(18 GiB)。
传输节点路由稍慢,但只需要大约2吉比特的内存,并且预处理时间更快。
收缩层次结构在快速预处理时间,低空间要求(0.4 GiB)和快速查询时间之间提供了良好的折衷。
没有一个algorithm是完全主宰…
彼得·桑德斯(Peter Sanders)的Google技术讲座可能会引起人们的兴趣
https://www.youtube.com/watch?v=-0ErpE8tQbw
Andrew Goldberg的这个演讲也是
https://www.youtube.com/watch?v=WPrkc78XLhw
KIT的Peter Sanders研究小组网站提供了收缩层级的开源实现。 http://algo2.iti.kit.edu/english/routeplanning.php
另外还有一个由微软撰写的关于使用CRPalgorithm的博客文章。http: //blogs.bing.com/maps/2012/01/05/bing-maps-new-routing-engine/
可能与主要地点和分层地图之间的预先计算路线的答案类似,但是我的理解是,在游戏中,为了加速A *,您有一个对于macros观导航非常粗糙的地图,以及一个细粒度的地图导航到macros观方向的边界。 所以你有两条小path可以计算,因此你的search空间要比简单地做一条到达目的地的path要小得多。 如果你做这么多的事情,你会有很多预先计算的数据,所以至less部分search是search预先计算的数据,而不是searchpath。
我对此有了更多的想法:
1)请记住,地图代表一个实体组织。 存储每个路口的纬度/经度。 你不需要检查超出目标方向的点数。 只有当你发现自己被封锁了,你才需要超越这个。 如果你存储了一个超级连接的覆盖范围,你可以进一步限制它 – 你通常不会以远离最终目的地的方式穿越其中的一个。
2)将世界分成由有限的连通性定义的整个区域,定义区域之间的所有连接点。 find您的源和目标所在的区域,从您的位置到每个连接点的开始和结束区域路线,以及连接点之间的简单映射区域。 (我怀疑很多后者已经预先计算好了)
请注意,区域可能比大都市地区小。 任何具有地形特征的城市(比如河stream)都是多个区域。
我很好奇启发式的使用情况,一段时间后,我们从圣罗莎附近的同一起始地点,到约塞米蒂国家公园的两个不同的露营地, 尽pipe两条路线在最后100英里(沿着CA-120)汇合,然后在最后几英里处再次发散,但是这些不同的目的地产生了完全不同的路线(通过I-580或CA-12)。 这是相当可重复的。 这两条路线相距50英里,路程约100英里,但距离/时间相当接近,就像你期望的那样。
唉,我不能重现 – algorithm必须改变。 但它让我对algorithm感到好奇。 我可以推测的是,有些定向修剪恰好对从远处看到的目的地之间微小的angular度差异非常敏感,或者是由最终目的地的selectselect了不同的预先计算的分段。
这完全是我的猜测,但我想他们可能会使用覆盖有向图的影响图数据结构来缩小search范围。 当期望的行程很长时,这将允许searchalgorithm将path引导到主要路线。
鉴于这是一个谷歌应用程序,这也是合理的假设,通过大量的caching完成了很多的魔术。 :)如果caching前5%的最常见的Google Map路由请求允许大块(20%?50%?)的请求通过简单的查找来回答,我不会感到惊讶。
我已经在路由上工作了几年,最近一阵活动是由我的客户的需求引起的,我发现A *很容易就足够快; 实际上不需要寻找优化或更复杂的algorithm。 在巨大的图表上路由不成问题。
但是速度依赖于整个路由networking,我的意思是分别代表路由段和路口的弧和节点的有向图。 主要的时间开销是创build这个networking所花费的时间。 基于一台运行Windows的普通笔记本电脑的一些粗略的数字,并在整个西class牙的路由:创buildnetworking所花费的时间:10-15秒; 计算路线所用的时间太短,无法衡量。
另一个重要的事情是能够重新使用networking进行尽可能多的路由计算。 如果你的algorithm以某种方式标记节点来logging最佳path(总节省成本,最好的弧),就像A *一样 – 你必须重置或清除这些旧信息。 代替成千上万的节点,使用代号系统更容易。 用每个节点的数据代号标记每个节点; 计算新路线时增加世代数; 任何具有旧代号的节点都是陈旧的,其信息可以被忽略。
说到基于OpenStreetMap的快速开源路由规划器GraphHopper ,我已经阅读了一些文献并实现了一些方法。 最简单的解决scheme是Dijkstra,简单的改进是一个双向的Dijkstra,它大致只探索一半的节点。 对于迪克斯特拉而言,通过整个德国的路线已经是1秒(对于汽车模式),在C中它可能只有0.5秒左右;)
我在这里创build了一个带双向Dijkstra的真实pathsearch的animationgif。 还有一些更多的想法可以让迪克斯特拉更快地像做一个“面向目标的迪克斯特拉”的A *。 我也为它创build了一个gifanimation 。
但如何做(很多)更快?
问题是,对于pathsearch,所有位置之间的所有节点都必须进行探索,而这在德国已经有数百万的成本。 但是Dijkstra等人的另一个痛点是这种search使用了大量的RAM。
存在启发式的解决scheme,而且在层次结构上组织图(路网)的精确解决scheme,都有其优缺点,主要解决速度和内存问题。 我在这个答案中列出了其中的一些。
对于GraphHopper,我决定使用“ 收缩层次”,因为它是相对“容易”实现的,不需要花费很长时间来准备graphics。 它仍然会导致非常快的响应时间,就像您可以在我们的在线实例GraphHopper Maps中testing一样。 例如从南非到华东 ,导致23000公里的距离和近14天的驾驶时间,在服务器上只花费了0.1秒。
我看到OP中的地图有什么问题:
查看指定中间点的路线:由于该路线不平直,路线稍微向后移动。
如果他们的algorithm不会回溯,则不会看到较短的路线。
全对最短pathalgorithm将计算图中所有顶点之间的最短path。 这将允许预先计算path,而不是在每次有人想要find源和目的地之间的最短path时要求计算path。 Floyd-Warshallalgorithm是一种全对最短pathalgorithm。
地图从不考虑整个地图。 我的猜测是:1.根据你的位置,他们在这个地方加载一个地方和地标。 2.当你search目的地时,这是当他们加载地图的另一部分,并做出两个地方的graphics,然后应用最短pathalgorithm。
此外,还有一个重要的技术dynamic规划,我怀疑是用于计算最短path。 你也可以参考。