A * Алгоритм для очень больших графиков, любые мысли о ярлыках кеширования?

Я пишу моделирование курьеров/логистики на картах OpenStreetMap и понял, что основной алгоритм A *, как показано на рисунке ниже, не будет достаточно быстрым для больших карт (например, Большой Лондон).

http://i.imgur.com/u2tVpML.jpg

Зеленые узлы соответствуют тем, которые были помещены в очередь открытого набора/приоритета, и из-за огромного количества (вся карта составляет примерно 1-2 миллиона), для поиска нарисованного маршрута требуется около 5 секунд. К сожалению, 100 мс на маршрут - мой абсолютный предел.

В настоящее время узлы хранятся как в списке смежности, так и в пространственном массиве 2D 100x100.

Я ищу методы, где я могу обменять время предварительной обработки, пространство и, если нужно, оптимальность маршрута, для более быстрых запросов. Прямая формула Хаверсина для эвристических затрат является самой дорогой функцией в соответствии с профилировщиком - я максимально оптимизировал свой основной A *.

Например, я думал, если бы я выбрал произвольный node X из каждого квадранта 2D-массива и запустил A * между каждым, я могу сохранить маршруты на диск для последующих симуляций. При запросе я могу запустить поиск A * только в квадрантах, чтобы пройти между предварительно вычисленным маршрутом и X.

Есть ли более совершенная версия того, что я описал выше, или, возможно, другой метод, который я должен преследовать. Большое спасибо!

Для записи здесь приведены некоторые результаты тестов для произвольного взвешивания эвристических затрат и вычисления пути между 10 парами случайно выбранных узлов:

Weight // AvgDist% // Time (ms)
1       1       1461.2
1.05    1       1327.2
1.1     1       900.7
1.2     1.019658848     196.4
1.3     1.027619169     53.6
1.4     1.044714394     33.6
1.5     1.063963413     25.5
1.6     1.071694171     24.1
1.7     1.084093229     24.3
1.8     1.092208509     22
1.9     1.109188175     22.5
2       1.122856792     18.2
2.2     1.131574742     16.9
2.4     1.139104895     15.4
2.6     1.140021962     16
2.8     1.14088128      15.5
3       1.156303676     16
4       1.20256964      13
5       1.19610861      12.9

Удивительно увеличивая коэффициент до 1,1, почти вдвое сократилось время выполнения, сохраняя тот же маршрут.

Ответ 1

Вы должны быть способны сделать это намного быстрее, торгуя оптимальностью. См. Приемлемость и оптимальность в википедии.

Идея состоит в том, чтобы использовать значение epsilon, которое приведет к решению не хуже, чем 1 + epsilon по сравнению с оптимальным путем, но это приведет к тому, что алгоритм будет рассматривать меньшее количество узлов. Обратите внимание, что это не означает, что возвращаемое решение всегда будет 1 + epsilon раз оптимального пути. Это самый худший случай. Я не знаю точно, как это будет вести себя на практике для вашей проблемы, но я думаю, что это стоит изучить.

Вам предоставляется ряд алгоритмов, которые полагаются на эту идею в википедии. Я считаю, что это ваш лучший выбор для улучшения алгоритма и возможность его работы в срок, сохраняя при этом хорошие пути.

Поскольку ваш алгоритм имеет дело с миллионами узлов за 5 секунд, я полагаю, вы также используете двоичные кучи для реализации, правильно? Если вы выполнили их вручную, убедитесь, что они реализованы как простые массивы и что они представляют собой двоичные кучи.

Ответ 2

Существуют специальные алгоритмы для этой проблемы, которые делают много предварительных вычислений. Из памяти предварительное вычисление добавляет информацию к графику, который использует A * для получения гораздо более точной эвристики, чем прямолинейное расстояние. Википедия дает имена нескольких методов в http://en.wikipedia.org/wiki/Shortest_path_problem#Road_networks и говорит, что лидер Hub Labeling является лидером. Быстрый поиск по этому вопросу появляется http://research.microsoft.com/pubs/142356/HL-TR.pdf. Старший, используя A *, находится в http://research.microsoft.com/pubs/64505/goldberg-sp-wea07.pdf.

Вам действительно нужно использовать Haversine? Чтобы покрыть Лондон, я бы подумал, что вы могли бы принять плоскую землю и использовать Pythagoras, или сохранить длину каждой ссылки на графике.

Ответ 3

Там действительно замечательная статья, которую Microsoft Research написала по этому вопросу:

http://research.microsoft.com/en-us/news/features/shortestpath-070709.aspx

Оригинальная бумага размещена здесь (PDF):

http://www.cc.gatech.edu/~thad/6601-gradAI-fall2012/02-search-Gutman04siam.pdf

По существу, есть несколько вещей, которые вы можете попробовать:

  • Начните как с источника, так и с адресата. Это помогает свести к минимуму количество потраченной впустую работы, которую вы будете выполнять при переходе от источника к месту назначения.
  • Используйте ориентиры и шоссе. По существу, найдите некоторые позиции на каждой карте, которые обычно принимают пути, и выполните некоторые предварительные вычисления, чтобы определить, как эффективно перемещаться между этими точками. Если вы можете найти путь от вашего источника до ориентира, то к другим достопримечательностям, а затем к месту назначения, вы можете быстро найти жизнеспособный маршрут и оптимизировать оттуда.
  • Исследуйте алгоритмы, подобные алгоритму "досягаемости". Это помогает свести к минимуму объем работы, которую вы будете выполнять при прохождении графика, минимизируя количество вершин, которые необходимо учитывать, чтобы найти правильный маршрут.

Ответ 4

GraphHopper делает две вещи более быстрыми, неэвристическими и гибкими маршрутами (примечание: я автор, и вы можете попробуйте в Интернете здесь)

  • Не столь очевидная оптимизация заключается в том, чтобы избежать отображения 1:1 узлов OSM во внутренние узлы. Вместо этого GraphHopper использует только узлы в качестве узлов и сохраняет примерно 1/8 пройденных узлов.
  • Он имеет эффективные инструменты для A *, Dijkstra или, например, один-ко-многим Дийкстра. Который делает маршрут менее чем одним возможным во всей Германии. (Неэвристическая) двунаправленная версия A * делает это еще быстрее.

Таким образом, вы можете получить быстрые маршруты для большего Лондона.

Дополнительно режим по умолчанию - это режим скорости, который делает все порядка величин быстрее (например, 30 мс для европейских маршрутов), но менее гибким, так как он требует предварительной обработки (Иерархия сокращений). Если вам это не нравится, просто отключите его, а затем еще тонко настройте включенные улицы для автомобиля или, возможно, лучше создайте новый профиль для грузовиков - например. исключить служебные улицы и дорожки, которые должны дать вам дополнительный 30-процентный импульс. И как с любым двунаправленным алгоритмом вы можете легко реализовать параллельный поиск.

Ответ 5

Думаю, стоит подумать над своей идеей с "квадрантами". Более строго, я бы назвал это поиском маршрутов с низким разрешением.

Вы можете выбрать X подключенных узлов, которые достаточно близки, и рассматривать их как единое низкоуровневое node. Разделите весь свой граф на такие группы, и вы получите график с низким разрешением. Это этап подготовки.

Чтобы вычислить маршрут от источника к цели, сначала определите узлы с низким разрешением, к которым они принадлежат, и найдите маршрут с низким разрешением. Затем улучшите свой результат, найдя маршрут на графике с высоким разрешением, однако ограничивая алгоритм только узлами, которые относятся к hte узлам низкого разрешения маршрута низкого разрешения (возможно, вы также можете рассмотреть соседние узлы с низким разрешением до некоторой глубины).

Это также может быть обобщено на несколько разрешений, а не только на высокий/низкий.

В конце вы должны получить маршрут, который достаточно близок к оптимальному. Он локально оптимален, но может быть несколько хуже, чем оптимально глобально в некоторой степени, что зависит от прыжка разрешения (т.е. Приближения, которое вы делаете, когда группа узлов определяется как одиночный node).

Ответ 6

Существуют десятки вариаций A *, которые могут соответствовать законопроекту здесь. Однако вы должны думать о своих случаях использования.

  • Вы ограничены памятью (а также кешем)?
  • Вы можете распараллелить поиск?
  • Будет ли использоваться ваша реализация алгоритма только в одном месте (например, в Большом Лондоне, а не в Нью-Йорке или Мумбаи или где-либо там)?

Невозможно узнать все сведения, которые вы и ваш работодатель узнаете. Таким образом, ваша первая остановка должна быть CiteSeer или Google Scholar: найдите документы, которые обрабатывают pathfinding с тем же общим набором ограничений, что и вы.

Затем уменьшите выбор до трех или четырех алгоритмов, выполните прототипирование, проверьте, как они масштабируются и заканчивают их. Вы должны помнить, что вы можете комбинировать различные алгоритмы в одной и той же программе дорожного поиска, основанной на расстоянии между точками, оставшимся временем или любыми другими факторами.

Как уже было сказано, на основе небольшого масштаба вашей целевой области падение Haversine - это, вероятно, ваш первый шаг, экономя драгоценное время на дорогостоящих триггерных оценках. ПРИМЕЧАНИЕ. Я не рекомендую использовать эвклидовое расстояние в координатах lat, lon - перепрограммировать вашу карту, например. поперечный Меркатор около центра и использовать декартовы координаты во дворах или метрах!

Предварительная компиляция является второй, и изменение компиляторов может быть очевидной третьей идеей (переход на C или С++ - см. https://benchmarksgame.alioth.debian.org/ для получения более подробной информации).

Дополнительные шаги оптимизации могут включать в себя избавление от распределения динамической памяти и использование эффективной индексации для поиска среди узлов (думаю, R-дерево и его производные/альтернативы).

Ответ 7

Я работал в крупной навигационной компании, поэтому могу с уверенностью сказать, что 100 мс должны получить вам маршрут из Лондона в Афины даже на встроенное устройство. Большой Лондон будет тестовой картой для нас, так как он удобно мал (легко вписывается в ОЗУ - на самом деле это не обязательно)

Во-первых, A * полностью устарел. Его главным преимуществом является то, что он "технически" не требует предварительной обработки. На практике вам необходимо предварительно обработать карту OSM, чтобы получить беспредметную выгоду.

Основной способ дать вам огромное ускорение скорости - это дуги. Если вы разделите карту в разделе 5x6, вы можете выделить 1 битовую позицию в 32-битном целое для каждого раздела. Теперь вы можете определить для каждого края, действительно ли это полезно при поездке в раздел {X,Y} из другого раздела. Довольно часто дороги двунаправлены, и это означает, что полезно только одно из двух направлений. Таким образом, одно из двух направлений имеет бит, установленный, а другой - очищенный. Это может показаться не реальным преимуществом, но это означает, что на многих пересечениях вы уменьшаете количество вариантов для рассмотрения от 2 до 1, и это занимает всего одну операцию бит.

Ответ 8

Обычно A * поставляется со слишком большим объемом памяти, а не с задержкой времени.

Однако я думаю, что было бы полезно сначала вычислить только узлы, которые являются частью "больших улиц", вы обычно выбирали шоссе над крошечной аллеей.

Я думаю, вы уже можете использовать это для своей весовой функции, но вы можете быть быстрее, если вы используете некоторую очередь приоритетов, чтобы решить, какой node проверить далее для дальнейшего путешествия.

Также вы можете попытаться уменьшить граф только на узлы, которые являются частью недорогих ребер, а затем найти способ от начала/конца до ближайшего из этих узлов. Таким образом, у вас есть 2 пути от начала до "большой улицы" и "большой улицы" до конца. Теперь вы можете вычислить лучший путь между двумя узлами, которые являются частью "больших улиц" в уменьшенном графике.

Ответ 9

Старый вопрос, но еще:

Попробуйте использовать разные кучи, которые "двоичная куча". "Лучшая куча асимптотической сложности" - это определенно куча Фибоначчи, и эта страница wiki получила хороший обзор:

https://en.wikipedia.org/wiki/Fibonacci_heap#Summary_of_running_times

Обратите внимание, что двоичная куча имеет более простой код и реализуется над массивом, и обход массива предсказуем, поэтому современный процессор выполняет операции с бинарной кучей намного быстрее.

Однако, учитывая набор данных достаточно большой, другие кучи выиграют двоичную кучу из-за их сложности...

Этот вопрос кажется достаточно большим.