Алгоритм D* — различия между версиями
Kabanov (обсуждение | вклад) |
Kabanov (обсуждение | вклад) |
||
| Строка 7: | Строка 7: | ||
=== Описание === | === Описание === | ||
| − | Обозначим множество <tex> | + | Обозначим множество <tex>Succ(s) \in V</tex> как множество вершин, исходящих из вершины <tex>s</tex>. |
| − | + | Аналогично множество <tex>Pred(s) \in V</tex> как множество вершин, входящих в вершину <tex>s</tex>. | |
| − | + | Функция <tex>0 \le с(s, s') \le +\infty</tex> будет возвращать стоимость перехода из вершины <tex>s</tex> в вершину <tex>s'</tex>. При этом <tex>s' \in Succ(s)</tex>. | |
| − | + | Функция <tex>g(s)</tex> будет возвращать последнее известное (и самое минимальное) значение расстояния от вершины <tex>s_{start}</tex> до <tex>s</tex>. | |
| − | |||
| − | Функция <tex>g(s)</tex> будет возвращать последнее известное значение | ||
Если <tex>s = s_{start}</tex> | Если <tex>s = s_{start}</tex> | ||
| − | <tex>rhs(s) = 0</tex> | + | :<tex dpi="120">rhs(s) = 0</tex> |
Иначе | Иначе | ||
| − | <tex>rhs(s) = min_{s' \in pred(s)}(g(s') + c(s', s)</tex> | + | :<tex dpi="120">rhs(s) = min_{s' \in pred(s)}(g(s') + c(s', s)</tex> |
| + | |||
| + | Вершина <tex>s</tex> может быть 3-х видов: | ||
| + | * насыщена, если <tex>g(s) = rhs(s)</tex> | ||
| + | * переполнена, если <tex>g(s) > rhs(s)</tex> | ||
| + | * ненасыщена, если <tex>g(s) < rhs(s)</tex> | ||
| − | |||
| − | |||
| − | |||
Очевидно, что если все вершины насыщены, то мы можем найти расстояние от стартовой вершины до любой. | Очевидно, что если все вершины насыщены, то мы можем найти расстояние от стартовой вершины до любой. | ||
Функция <tex>key(s)</tex>, где <tex>s</tex> - вершина, возвращает вектор из 2-ух значений <tex>k_1(s)</tex>, <tex>k_2(s)</tex>. <tex>k_1(s) = min(g(s), rhs(s)) + h(s, s_goal)</tex>. <tex>k_2(s) = min(g(s), rhs(s))</tex> | Функция <tex>key(s)</tex>, где <tex>s</tex> - вершина, возвращает вектор из 2-ух значений <tex>k_1(s)</tex>, <tex>k_2(s)</tex>. <tex>k_1(s) = min(g(s), rhs(s)) + h(s, s_goal)</tex>. <tex>k_2(s) = min(g(s), rhs(s))</tex> | ||
| − | Если в конце поиска пути <tex>g(s_{goal}) = + | + | Если в конце поиска пути <tex>g(s_{goal}) = +\infty</tex>, то мы не смогли найти путь от <tex>s_{start}</tex> до <tex>s_{goal}</tex> на текущей итерации. Но после следующего изменения графа путь вполне может найтись. |
=== Псевдокод === | === Псевдокод === | ||
| − | ''' | + | Основная функция, описывающая алгоритм |
| + | '''Main'''(): | ||
{ | { | ||
| − | + | '''Initialize'''(); | |
| + | while (true) | ||
| + | { | ||
| + | '''ComputeShortestPath'''(); | ||
| + | В данный момент мы знаем кратчайший путь из <tex>s_{start}</tex> в <tex>s_{goal}</tex>. | ||
| + | Ждем каких-либо изменений графа. | ||
| + | for всех ориентированных ребер <tex>(u; v)</tex> с измененными весами: | ||
| + | { | ||
| + | Обновляем результат функции <tex>c(u; v)</tex>; | ||
| + | '''UpdateVertex'''(<tex>v</tex>); | ||
| + | } | ||
| + | } | ||
} | } | ||
| + | |||
| + | Теперь опишем составные элементы подробнее | ||
'''Initialize'''(): | '''Initialize'''(): | ||
{ | { | ||
| − | <tex>U = | + | //Заведем приоритетную очередь <tex>U</tex>, в которую будем помещать вершины. Сортировка будет производиться по функции <tex>key(s)</tex>. |
| − | <tex> | + | <tex>U = \varnothing;</tex> |
| − | <tex>rhs(s) = g(s) = | + | for <tex>s \in S</tex> |
| − | <tex>rhs( | + | <tex>rhs(s) = g(s) = \infty;</tex> |
| − | + | <tex>rhs(s_{start}) = 0;</tex> | |
| + | U.Insert(<tex>s_{start}</tex>; CalcKey(<tex>s_{start}</tex>)); | ||
| + | } | ||
| + | |||
| + | Функция <tex>key(s)</tex>. Возвращаемые значения сортируются в лексографическом порядке, т.е. сначала <tex>k_1(s)</tex>, потом <tex>k_2(s)</tex> | ||
| + | '''CalcKey'''(s): | ||
| + | { | ||
| + | return [<tex>\min(g(s); rhs(s)) + h(s; s_{goal})</tex>;<tex>\min(g(s); rhs(s))</tex>]; | ||
} | } | ||
'''UpdateVertex'''(<tex>u</tex>): | '''UpdateVertex'''(<tex>u</tex>): | ||
{ | { | ||
| − | if (<tex>u | + | if (<tex>u \ne s_{start}</tex>) |
| − | <tex>rhs(u) = min_{s' \in Pred(u)}(g(s')+c(s',u));</tex> | + | <tex>rhs(u) = min_{s' \in Pred(u)}(g(s') + c(s',u));</tex> |
if (<tex>u \in U</tex>) | if (<tex>u \in U</tex>) | ||
U.Remove(u); | U.Remove(u); | ||
| − | if (g(u) | + | if (<tex>g(u) \ne rhs(u)</tex>) |
| − | U.Insert(<tex>u</tex>;CalcKey(<tex>u</tex>)); | + | U.Insert(<tex>u</tex>; CalcKey(<tex>u</tex>)); |
} | } | ||
'''ComputeShortestPath'''(): | '''ComputeShortestPath'''(): | ||
{ | { | ||
| − | while (U.TopKey()< CalcKey(<tex>s_{goal}</tex>) OR rhs(<tex>s_{goal}) | + | while (U.TopKey() < CalcKey(<tex>s_{goal}</tex>) OR rhs(<tex>s_{goal}) \ne g(s_{goal}</tex>)) |
u = U.Pop(); | u = U.Pop(); | ||
if (g(u) > rhs(u)) | if (g(u) > rhs(u)) | ||
g(u) = rhs(u); | g(u) = rhs(u); | ||
| − | for | + | for <tex>s \in Succ(u)</tex> |
| + | UpdateVertex(s); | ||
else | else | ||
| − | g(u) = | + | g(u) = <tex>+\infty</tex>; |
| − | + | for <tex>s \in Succ(u) \cup \{u\}</tex> | |
| − | + | UpdateVertex(s); | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
| Строка 91: | Строка 98: | ||
== Алгоритм D* == | == Алгоритм D* == | ||
| + | === Псевдокод (Первая версия) === | ||
'''CalcKey'''(s): | '''CalcKey'''(s): | ||
| − | return [<tex>min(g(s);rhs(s)) + h( | + | return [<tex>\min(g(s);rhs(s)) + h(s_{start};s)</tex>;<tex>\min(g(s); rhs(s))</tex>]; |
'''Initialize'''(): | '''Initialize'''(): | ||
| − | U = | + | U = <tex>\varnothing</tex>; |
| − | for | + | for <tex>s \in S</tex> |
| − | <tex>rhs(s) = g(s) = | + | <tex>rhs(s) = g(s) = +\infty</tex> |
<tex>rhs(s_{goal}) = 0</tex> | <tex>rhs(s_{goal}) = 0</tex> | ||
| − | U.Insert( | + | U.Insert(<tex>s_{goal}</tex>; CalcKey(<tex>s_{goal}</tex>)); |
'''UpdateVertex'''(u): | '''UpdateVertex'''(u): | ||
| − | if (u | + | if (<tex>u != s_{goal}</tex>) |
| − | (c(u | + | rhs(u) = min_{s' \in Succ(u)}(c(u,s')+g(s')); |
| − | + | if (<tex>u \in U</tex>) | |
| − | ) + g(s | + | U.Remove(u); |
| − | + | if (<tex>g(u) != rhs(u)</tex>) | |
| − | )); | + | U.Insert(u; CalcKey(u)); |
| − | |||
| − | |||
'''ComputeShortestPath'''() | '''ComputeShortestPath'''() | ||
| − | while (U.TopKey()< | + | while (U.TopKey() <tex><=</tex> CalcKey(<tex>s_{start}</tex>) OR <tex>rhs(s_{start}) != g(s_{start})</tex>) |
u = U.Pop(); | u = U.Pop(); | ||
if (g(u) > rhs(u)) | if (g(u) > rhs(u)) | ||
g(u) = rhs(u); | g(u) = rhs(u); | ||
| − | + | for <tex>s \in Pred(u)</tex> | |
| + | UpdateVertex(s); | ||
else | else | ||
| − | g(u) = | + | g(u) = <tex>+\infty</tex>; |
| − | + | for <tex>s \in Pred(u) \cup \{u\}</tex> | |
| + | UpdateVertex(s); | ||
'''Main'''(): | '''Main'''(): | ||
Initialize(); | Initialize(); | ||
ComputeShortestPath(); | ComputeShortestPath(); | ||
| − | while (s_{start} | + | while (<tex>s_{start} \ne s_{goal}</tex>) |
| − | if (g( | + | // if (<tex>g(s_{start}) = \infty</tex>) тогда путь на данной итерации не найден. |
| − | + | s_{start} = argmins02Succ(sstart) | |
| − | + | Move to <tex>s_{start}</tex>; | |
| − | + | Scan graph for changed edge costs; | |
| − | + | if any edge costs changed | |
| − | + | for all directed edges (u; v) with changed edge costs | |
| − | + | Update the edge cost c(u; v); | |
| − | + | UpdateVertex(u); | |
| − | + | for <tex>s \in U</tex> | |
| − | + | U.Update(<tex>s</tex>; CalcKey(<tex>s</tex>)); | |
| − | + | ComputeShortestPath(); | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
==Ссылки== | ==Ссылки== | ||
Версия 23:41, 2 января 2014
Алгоритм D* — алгоритм поиска кратчайшего пути во взвешенном ориентированном графе, где структура графа неизвестна заранее или постоянно подвергается изменению. Разработан Свеном Кёнигом и Максимом Лихачевым в 2002 году.
Содержание
Алгоритм LPA*
Постановка задачи
Дан взвешенный ориентированный граф . Даны вершины и . Требуется после каждого изменения графа уметь вычислять функцию для каждой известной вершины
Описание
Обозначим множество как множество вершин, исходящих из вершины .
Аналогично множество как множество вершин, входящих в вершину .
Функция будет возвращать стоимость перехода из вершины в вершину . При этом .
Функция будет возвращать последнее известное (и самое минимальное) значение расстояния от вершины до .
Если
Иначе
Вершина может быть 3-х видов:
- насыщена, если
- переполнена, если
- ненасыщена, если
Очевидно, что если все вершины насыщены, то мы можем найти расстояние от стартовой вершины до любой.
Функция , где - вершина, возвращает вектор из 2-ух значений , . .
Если в конце поиска пути , то мы не смогли найти путь от до на текущей итерации. Но после следующего изменения графа путь вполне может найтись.
Псевдокод
Основная функция, описывающая алгоритм
Main():
{
Initialize();
while (true)
{
ComputeShortestPath();
В данный момент мы знаем кратчайший путь из в .
Ждем каких-либо изменений графа.
for всех ориентированных ребер с измененными весами:
{
Обновляем результат функции ;
UpdateVertex();
}
}
}
Теперь опишем составные элементы подробнее
Initialize():
{
//Заведем приоритетную очередь , в которую будем помещать вершины. Сортировка будет производиться по функции .
for
U.Insert(; CalcKey());
}
Функция . Возвращаемые значения сортируются в лексографическом порядке, т.е. сначала , потом CalcKey(s): { return [;]; }
UpdateVertex(): { if () if () U.Remove(u); if () U.Insert(; CalcKey()); }
ComputeShortestPath():
{
while (U.TopKey() < CalcKey() OR rhs())
u = U.Pop();
if (g(u) > rhs(u))
g(u) = rhs(u);
for
UpdateVertex(s);
else
g(u) = ;
for
UpdateVertex(s);
}
Таким образом мы описали алгоритм LPA*. Он неоднократно определяет путь между вершинами и , используя при этом данные из предыдущих итераций. Очевидно, что в худшем случае (а именно когда все ребра вокруг текущей вершины изменили свой вес) алгоритм будет работать как последовательные вызовы алгоритма А* за . Улучшим эту оценку с помощью алгоритма D* lite.
Примечание: на практике же такой подход тоже имеет место на плотных графах (или матрицах), так как в среднем дает оценку О(n*log(n)).
Алгоритм D*
Псевдокод (Первая версия)
CalcKey(s): return [;];
Initialize(): U = ; for U.Insert(; CalcKey());
UpdateVertex(u): if () rhs(u) = min_{s' \in Succ(u)}(c(u,s')+g(s')); if () U.Remove(u); if () U.Insert(u; CalcKey(u));
ComputeShortestPath() while (U.TopKey() CalcKey() OR ) u = U.Pop(); if (g(u) > rhs(u)) g(u) = rhs(u); for UpdateVertex(s); else g(u) = ; for UpdateVertex(s);
Main(): Initialize(); ComputeShortestPath(); while () // if () тогда путь на данной итерации не найден. s_{start} = argmins02Succ(sstart) Move to ; Scan graph for changed edge costs; if any edge costs changed for all directed edges (u; v) with changed edge costs Update the edge cost c(u; v); UpdateVertex(u); for U.Update(; CalcKey()); ComputeShortestPath();