Я думаю, проблема в том, что вы просто не имеете никакой логики, записанной для возврата цикла.
Циклы, которые происходят от узла
Это не так сложно, вы уже используете аккумулятор, вы просто нужен механизм, который когда-то цикл найден, верните аккумулятор в качестве цикла. Вы можете сделать это, предоставляя дополнительный параметр cycle
:
cycle(Node,Cycle) :-
cycle(Node,[],Cycle).
cycle(Curr,Visited,Cycle) :-
member(Curr,Visited),
!,
reverse([Curr|Visited],Cycle).
cycle(Curr,Visited,Cycle) :-
edge(Curr,Next),
cycle(Next,[Curr|Visited],Cycle).
В этой реализации я использовал reverse/2
, так как это даст вам правильный порядок узлов (краевой-накрест). Если вы не заинтересованы в этом (например, вы только хотите, чтобы проанализировать цикл, и вы можете проанализировать в обратном направлении, вы можете просто заменить Cycle
в первом пункте cycle/3
с [Curr|Visited]
.
Проблема заключается в том, однако, что если вы вызываете этот предикат, он возвращает:.
?- cycle(d,Cycle).
Cycle = [d, c, b, a, e, d] ;
Cycle = [d, c, b, a, e, c] ;
Cycle = [d, a, e, d] ;
Cycle = [d, a, e, c, b, a].
Таким образом, она не ищет циклы где d
является частью цикла самих по себе, он ищет для всех циклов, которые могут происходящих из d
Это, вероятно, не то, что вы хотите.
Циклы с данным узлом
Однако вы можете переписать предикат: вам нужно будет хранить узел, из которого вы родиной происхождения:
cycle(Node,Cycle) :-
edge(Node,Next),
cycle(Node,Next,[Node],Cycle).
Так вот мы смотрим на каждый edge/2
происходящий из Node
и мы вызываем cycle/4
с начальным Node
(чтобы проверить, когда мы нашли цикл), узел Next
, список посещенных [Node]
s и параметр Cycle
для возврата найденных циклов.
В настоящее время существует три возможных варианта cycle/4
:
Приходим исходный узел, в этом случае мы нашли цикл, где Node
является частью из, мы обработка аналогична первой версии:
cycle(Curr,Curr,Visited,Cycle) :-
!,
reverse([Curr|Visited],Cycle).
мы прибываем в узле мы уже посетили: Curr
элемент Visited
, в этом случае мы должны прекращаться поиск: в противном случае мы будем цикл двутавровой nfinite количество раз:
cycle(_,Curr,Visited,_) :-
member(Curr,Visited),
!,
fail.
fail
предикат, который гласит ветвь терпит неудачу. Это может быть полезно, потому что теперь мы указываем, как это может произойти.
Наконец, мы просто посетили другой край и попытаться найти следующий узел:
cycle(Node,Curr,Visited,Cycle) :-
edge(Curr,Next),
cycle(Node,Next,[Curr|Visited],Cycle).
Полная версия:
cycle(Node,Cycle) :-
edge(Node,Next),
cycle(Node,Next,[Node],Cycle).
cycle(Curr,Curr,Visited,Cycle) :-
!,
reverse([Curr|Visited],Cycle).
cycle(_,Curr,Visited,_) :-
member(Curr,Visited),
!,
fail.
cycle(Node,Curr,Visited,Cycle) :-
edge(Curr,Next),
cycle(Node,Next,[Curr|Visited],Cycle).
, который генерирует:
?- cycle(d,Cycle).
Cycle = [d, c, b, a, e, d] ;
Cycle = [d, a, e, d] ;
Таким образом, все циклы начинаются г от d
и снова посетить d
. Мы можем сделать код немного более эффективным путем сжатия второй и третий сценарий, в одном предложении:
cycle(Node,Cycle) :-
edge(Node,Next),
cycle(Node,Next,[Node],Cycle).
cycle(Curr,Curr,Visited,Cycle) :-
!,
reverse([Curr|Visited],Cycle).
cycle(Node,Curr,Visited,Cycle) :-
\+ member(Curr,Visited),
edge(Curr,Next),
cycle(Node,Next,[Curr|Visited],Cycle).
Где \+
означает не.
Благодаря Виллем, я действительно appriciate свой ответ он мне очень помог. Теперь я полностью понимаю это. благодаря – Chris