Алгоритм поиска D*

Материал из Поле цифровой дидактики

Шаблон:О Алгоритм поиска D* (произносится как «Ди стар») — это любой из трёх связанных Шаблон:Нп5:

  • Оригинальный алгоритм D*<ref>Шаблон:Cite journal</ref> Энтони Стенца — это информированный алгоритм инкрементного поиска.
  • Сфокусированный D*<ref name="Stentz1995">Шаблон:Cite journal</ref> — это алгоритм инкрементного эвристического поиска, разработанный Энтони Стенцем, который сочетает в себе идеи A*<ref>Шаблон:Cite journal</ref> и оригинального D*. Сфокусированный D* возник в результате дальнейшего развития оригинального D*.
  • Облегчённый D*<ref>Шаблон:Cite journal</ref> — это алгоритм инкрементального эвристического поиска, созданный Свеном Кёнигом и Максимом Лихачёвым, который основан на LPA*<ref name="Koenig2004">Шаблон:Cite journal</ref>, алгоритме инкрементального эвристического поиска, объединяющем идеи алгоритма поиска A* и динамического SWSF-FP<ref>Шаблон:Cite journal</ref>.

Все три алгоритма поиска решают одни и те же основанные на предположениях Шаблон:Нп5 проблемы, включая планирование с предположением о свободном пространстве<ref>Шаблон:Cite journal</ref>, когда робот должен перемещаться к заданным координатам цели на неизвестной местности. Он делает предположения о неизвестной части местности (например, что на ней нет препятствий) и находит кратчайший путь от её текущих координат до координат цели при этих предположениях. Затем робот следует по пути. Когда он наблюдает новую информацию на карте (например, ранее неизвестные препятствия), он добавляет эту информацию на свою карту и, при необходимости, перепланировывает новый кратчайший путь от текущих координат к заданным координатам цели. Он повторяет процесс до тех пор, пока не достигнет координат цели или не определит, что координаты цели не могут быть достигнуты. При пересечении неизвестной местности могут часто обнаруживаться новые препятствия, поэтому это перепланирование должно быть быстрым. Инкрементальные (эвристические) алгоритмы поиска ускоряют поиск последовательностей похожих поисковых задач, используя опыт решения предыдущих проблем для ускорения поиска текущей. Если предположить, что координаты цели не меняются, все три алгоритма поиска более эффективны, чем повторные поиски A*.

D* и его варианты широко использовались для мобильного робота и автономного транспортного средства навигации. Современные системы обычно основаны на облегчённом, а не на оригинальном или сфокусированном D*. Фактически, даже лаборатория Стенца в некоторых реализациях использует облегчённый, а не оригинальный D*<ref>Шаблон:Cite thesis</ref>. Такие навигационные системы включают в себя прототип системы, испытанный на марсоходах Opportunity и Spirit, и навигационную систему победителя конкурса DARPA Urban Challenge, оба разработанные в Университете Карнеги — Меллона.

Оригинальный D* был представлен Энтони Стенцем в 1994 году. Название D* происходит от термина «Dynamic A*» (рус. «Динамический A*»), потому что алгоритм ведёт себя как A*<ref name="Stentz1995"/>, за исключением того, что стоимость дуги может изменяться по мере выполнения алгоритма.

Операции

Основные операции D* описаны ниже.

Подобно алгоритму Дейкстры и A*, D* поддерживает список узлов для оценки, известный как ОТКРЫТЫЙ список. Узлы помечаются как имеющие одно из нескольких состояний:

  • НОВЫЙ, означает, что он никогда не помещался в ОТКРЫТЫЙ список.
  • ОТКРЫТЫЙ, означает, что он в настоящее время находится в ОТКРЫТОМ списке.
  • ЗАКРЫТЫЙ, означает, что его больше нет в ОТКРЫТОМ списке.
  • ПОДНЯТЫЙ, указывает на то, что его стоимость выше, чем в последний раз, когда он был в ОТКРЫТОМ списке.
  • НИЖНИЙ, указывает на то, что его стоимость ниже, чем в последний раз, когда он был в ОТКРЫТОМ списке.

Расширение

Алгоритм работает путём итеративного выбора узла из ОТКРЫТОГО списка и его оценки. Затем он распространяет изменения узла на все соседние узлы и помещает их в ОТКРЫТЫЙ список. Этот процесс распространения называется «расширением». В отличие от канонического A*, который следует по пути от начала до конца, D* начинает поиск в обратном направлении от целевого узла. Каждый расширенный узел имеет обратный указатель, который относится к следующему узлу, ведущему к цели, и каждый узел знает точную стоимость для цели. Когда начальный узел является следующим расширяемым узлом, алгоритм выполнен, и путь к цели можно найти, просто следуя обратным указателям.

Преодоление препятствий

Когда на заданном пути обнаруживается препятствие, все затронутые точки снова помещаются в ОТКРЫТЫЙ список, на этот раз с пометкой ПОДНЯТЫЙ. Однако перед увеличением стоимости ПОДНЯТОГО узла алгоритм проверяет его соседей и исследует, может ли он снизить стоимость узла. В противном случае состояние ПОДНЯТЫЙ распространяется на всех потомков узлов, то есть узлы, на которые есть обратные указатели. Затем эти узлы оцениваются, и состояние ПОДНЯТЫЙ передаётся, формируя волну. Когда ПОДНЯТЫЙ узел может быть уменьшен, его обратный указатель обновляется и передаёт состояние НИЖНИЙ своим соседям. Эти волны состояний ПОДНЯТЫЙ и НИЖНИЙ являются сердцем D*.

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

Ещё один тупик

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

Псевдокод

while (!openList.isEmpty()) {
    point = openList.getFirst();
    expand(point);
}

Развернуть

void expand(currentPoint) {
    boolean isRaise = isRaise(currentPoint);
    double cost;
    for each (neighbor in currentPoint.getNeighbors()) {
        if (isRaise) {
            if (neighbor.nextPoint == currentPoint) {
                neighbor.setNextPointAndUpdateCost(currentPoint);
                openList.add(neighbor);
            } else {
                cost = neighbor.calculateCostVia(currentPoint);
                if (cost < neighbor.getCost()) {
                    currentPoint.setMinimumCostToCurrentCost();
                    openList.add(currentPoint);
                }
            }
        } else {
            cost = neighbor.calculateCostVia(currentPoint);
            if (cost < neighbor.getCost()) {
                neighbor.setNextPointAndUpdateCost(currentPoint);
                openList.add(neighbor);
            }
        }
    }
}

Проверить на поднятие

boolean isRaise(point) {
    double cost;
    if (point.getCurrentCost() > point.getMinimumCost()) {
        for each(neighbor in point.getNeighbors()) {
            cost = point.calculateCostVia(neighbor);
            if (cost < point.getCurrentCost()) {
                point.setNextPointAndUpdateCost(neighbor);
            }
        }
    }
    return point.getCurrentCost() > point.getMinimumCost();
}

Варианты

Сфокусированный D*

Как следует из названия, сфокусированный D* является расширением D*, которое использует эвристику, чтобы сфокусировать распространение ПОДНЯТОГО и НИЖНЕГО в направлении робота. Таким образом, обновляются только важные состояния, так же как A* вычисляет затраты только для некоторых узлов.

Облегчённый D*

Облегчённый D* не основан на исходном или сфокусированном D*, но реализует то же поведение. Это проще для понимания и может быть реализовано меньшим количеством строк кода, отсюда и название «Облегчённый D*». По производительности он не хуже сфокусированного D*. Облегчённый D* основан на LPA*<ref name="Koenig2004"/>, который был представлен Кёнигом и Лихачёвым несколькими годами ранее. Облегчённый D*

Минимальная стоимость по сравнению с текущей стоимостью

Для D* важно различать текущие и минимальные затраты. Первые важны только во время сбора, а последние решающие, потому что они сортируют ОТКРЫТЫЙ список. Функция, которая возвращает минимальную стоимость, всегда является наименьшей стоимостью для текущей точки, поскольку это первая запись в ОТКРЫТОМ списке.

Примечания

Шаблон:Примечания

Ссылки

Шаблон:Алгоритмы поиска на графах