В прологе почему не добавляется "край (X, Y):- край (Y, X)". работа по преобразованию определения ориентированного графа в неориентированный граф
Я только изучаю Пролог, и я рассматриваю конспекты лекций, и все примечания говорят о том, что:
дано следующее определение для ориентированных графов:
path(X, Y) :- edge(X, Y).
path(X, Y) :- edge(X, Z), path(Z, Y).
Если бы мы хотели сделать это неориентированным графом, определяяedge(X, Y) :- edge(Y, X).
одно не работает, и я не могу понять, почему.
X к Y имеет ребро, если Y к X имеет ребро. Кажется, имеет смысл для меня.
Примечания на самом деле не разъясняют, почему нет, но они определяют, что правильным решением будет:
edge1(X, Y) :- edge(X, Y).
edge1(X, Y) :- edge(Y, X).
к тому, что у нас уже было.
Может кто-нибудь объяснить это мне, пожалуйста, и спасибо? <3
2 ответа
Потому что правила не работают так же, как факты, и вы переходите в бесконечный цикл, если используете один и тот же предикат.
Давайте возьмем пример ?-edge(5,2)
, Мы в конечном итоге позвоним -
edge(5,2) :- edge(2,5).
Хорошо, что происходит, когда мы звоним edge(2,5)
?
edge(2,5) :- edge(5,2).
... э-э Логический круг.
Когда используешь edge1
вы просто создаете оболочку для своего предиката, чтобы избежать рекурсивного определения.
Есть несколько потенциальных источников прерывания в вашей программе.
Во-первых, с правилом edge(X, Y) :- edge(Y, X).
Ваша программа никогда не прекратит работу. Независимо от того, где вы добавляете это правило в вашу программу. Что часто вызывает раздражение, так это то, что ваша программа будет по-прежнему давать много ответов, что несколько говорит о том, что она работает. Однако это никогда не остановится.
Лучший способ понять это - рассмотреть слегка измененную программу, называемую срез-срез. Эта измененная программа поделится многими свойствами с вашей программой. Не все из них, но некоторые. Мы добавим цели false
в вашу программу. Если результирующая программа зацикливается, оригинальная программа также зацикливается.
путь (X, Y):- край (X, Y), ложь.путь (X, Y):- ложь, ребро (X, Z), путь (Z, Y).край (а, б): - неверно. край (X, Y):- край (Y, X).
Во-вторых, есть еще один источник прерывания в вашей улучшенной программе. Вот связанный срез-срез:
путь (X, Y):- ложь, edge1 (X, Y). путь (X, Y):- edge1(X, Z), путь (Z, Y), ложь. edge1(X, Y):- край (X, Y). edge1(X, Y):- край (Y, X). край (а, б).
edge1/2
теперь всегда содержит циклы, поэтому этот фрагмент будет цикл для path(a, Y)
, и в целом также path(X, Y), false
,
Чтобы решить эту проблему, вам придется переписать path/2
,
Вы можете переписать это в общем виде, используя closure0/3
а также path/4
!
Так path/2
можно определить как:
path(X, Y) :-
closure(edge, X, Y).