我是Prolog世界的新手。我正在尝试编写谓词来打印图形的指定节点的图形的所有周期,这是给定节点的元素。我的图表看起来像这样。
d
不幸的是现在我找不到特定节点的循环。例如,我正在寻找节点{{1}}的所有周期。
答案 0 :(得分:4)
你要找的是transitive-closure给我的声音......不需要重新发明轮子!
简单地构建在" Definition of a path/trail/walk"中显示的久经考验的代码并定义:
in_cycle(R_2, AZ, Path) :- % cf. "simple cycle" First = AZ, Last = AZ, path(R_2, Path, First, ButLast), % all "hops" but the last one ... call(R_2, ButLast, Last). % ... and here comes the last one
使用SICStus Prolog的示例查询#1 4.3.2:
| ?- in_cycle(edge, d, Path). Path = [d,c,b,a,e] ? ; Path = [d,a,e] ? ; no
在示例查询#2中,我们查看edge/2
的{{3}}的传递闭包:
| ?- in_cycle(symmetric closure(edge), d, Path). Path = [d,c] ? ; Path = [d,c,b,a] ? ; Path = [d,c,b,a,e] ? ; Path = [d,c,e] ? ; Path = [d,c,e,a] ? ; Path = [d,a] ? ; Path = [d,a,e] ? ; Path = [d,a,e,c] ? ; Path = [d,a,b,c] ? ; Path = [d,a,b,c,e] ? ; Path = [d,e] ? ; Path = [d,e,c] ? ; Path = [d,e,c,b,a] ? ; Path = [d,e,a] ? ; Path = [d,e,a,b,c] ? ; no
答案 1 :(得分:1)
我认为问题在于你只是没有写任何逻辑来返回周期。
这并不难,你已经使用了累加器,你只需要一个机制,一旦找到循环,就将你的累加器作为循环返回。您可以通过向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
(以检查我们何时找到一个周期),{ {1}}节点,已访问的[Node]
列表和Cycle
参数,用于返回找到的周期。
现在cycle/4
有三种可能的选项:
我们到达原始节点,在这种情况下,我们找到了Node
所属的循环,我们的处理类似于第一个版本:
cycle(Curr,Curr,Visited,Cycle) :-
!,
reverse([Curr|Visited],Cycle).
我们到达了一个我们已经访问过的节点:Curr
是Visited
的一个元素,在这种情况下我们需要中断搜索:否则我们将循环无限次:
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).
\+
表示不。