В прологе почему не добавляется "край (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).
Другие вопросы по тегам