В настоящее время я реализую программу пролога для вычисления кратчайшего пути между двумя точками. Фреймворк уже существует в проекте Java. Как требование, путь должен быть реализован в прологе. Поэтому я использую gnu.prolog ( http://www.gnu.org/software/gnuprologjava/)
Из java я вызываю searchPath(1,5,Path)
, который вернет Path=[5,4,3,2,1]
Вот мой код пролога:
:- dynamic(path/3).
findPath( [Goal | Rest], Goal, Temp, Temp, [Goal | Rest]).
findPath( [A | Rest], Goal, Cost, Temp, Path) :-
path(A,B,C),
\+member(B, [A | Rest]),
NewCosts is (Temp + C),
findPath([B, A | Rest], Goal, Cost, NewCosts, Path).
searchPath(Start,Goal,Path_to_goal) :-
findPath([Start], Goal, Cost1, 0, Path),
findPath([Start], Goal, Cost2, 0, Path2),
Cost1=<Cost2,
Path_to_goal = Path.
У меня есть две проблемы с этим:
Метод
searchPath
должен возвращать кратчайший путь . Однако это не делает НЕ . Это приводит к тому, что мой призрак «решает» переключить направление в какой-то момент, приводящее к дрожанию призрака слева направо.Мой код пролога возвращает результат до 6 секунд . я не нужно говорить вам, что это слишком много времени. Однако иногда для пролога требуется всего 19 мс . Я не мог понять, от каких обстоятельств это зависит. Например, для расчета списка путей, содержащего 99 элементов, требуется 19 мс, но 6 секунд были потрачены на список, содержащий всего 38 элементов.
Вы можете предложить какие-нибудь улучшения?
Заранее спасибо за помощь!
1 ответ
Вы можете использовать алгоритм Дейкстры. Я реализовал его отвечая на это вопрос. В моем коде используется переменные с атрибутами, я думаю, они должны работать в GnuProlog (сейчас я протестирую). В любом случае, там вы найдете ссылку на рабочий чистый Prolog реализация.
edit ну, я думаю, вы могли бы исправить свой код, потому что есть проблема:
Path2
в searchPath
/ 3 это singleton : тогда вы явно собираетесь всегда заканчиваться первым Path, а поскольку второй findPath / 3 найдет всегда (если база данных не изменяется) те же Стоимость и Путь, что и первый, Cost1=<Cost2,
всегда будет истинным. Вы могли бы попробовать, если
searchPath(Start,Goal,Path_to_goal) :-
findall(Cost-Path, findPath([Start], Goal, Cost, 0, Path), Paths),
sort(Paths, [_-Path_to_goal|_]).
Достаточно быстро для вашего задания. В противном случае вам нужно будет реализовать инкрементный поиск, что нелегко, потому что Prolog «возвращает» альтернативные пути при обратном отслеживании, а затем заставляет использовать какой-то побочный эффект для выбора минимального значения.
дополнительное редактирование findall / 3 приведет к слишком медленной работе кода. Я написал что-то более эффективное, используя присваивание без возврата (я использовал SWI-Prolog nb_setarg / 3, вы должны использовать setarg / 3 в GProlog).
findPath(_Limit, [Goal | Rest], Goal, Temp, Temp, [Goal | Rest]) :- !.
findPath(Limit, [A | Rest], Goal, Cost, Temp, Path) :-
path(A,B,C),
\+member(B, Rest),
NewCosts is (Temp + C),
NewCosts < Limit,
findPath(Limit, [B, A | Rest], Goal, Cost, NewCosts, Path).
% ?- searchPath(aberdeen, glasgow, Path, Length).
%
searchPath(Start, Goal, Path_to_goal, L) :-
S = path_len([], 1000000),
repeat,
arg(2, S, Limit),
( findPath(Limit, [Start], Goal, Cost, 0, Path)
-> ( Cost < Limit
-> nb_setarg(1, S, Path),
nb_setarg(2, S, Cost),
fail
)
; true
),
arg(1, S, Rev),
reverse(Rev, Path_to_goal),
arg(2, S, L).
Похожие вопросы
Связанные вопросы
Новые вопросы
performance
По вопросам, касающимся измерения или улучшения кода и эффективности приложений.
nb_setarg
иsetarg
. Верно ли, что сsetarg
Значение заменяется, если при поиске с возвратом найдено другое решение, но этого не произойдет сnb_setarg
? 2. Я не могу понять, почему в вашем алгоритме естьfail
иtrue
. Не могли бы вы объяснить их цель?fail
создает следующее решение с помощью findPath, но после того, как оно сгенерирует последнее доступное, оно завершится ошибкой, иtrue
позволит завершить процедуру. См. -> на управляющие предикаты. Несвязанный: я думаю, что repeat / 0 можно было бы удалить.