打印图形的指定节点Prolog的图形的所有周期

时间:2016-01-14 18:05:30

标签: list graph prolog cycle

我是Prolog世界的新手。我正在尝试编写谓词来打印图形的指定节点的图形的所有周期,这是给定节点的元素。我的图表看起来像这样。

d

不幸的是现在我找不到特定节点的循环。例如,我正在寻找节点{{1}}的所有周期。

2 个答案:

答案 0 :(得分:4)

你要找的是给我的声音......不需要重新发明轮子!

简单地构建在" 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 的所有解决方案都可以实现更通用的查询#2-monotonic Prolog symm12 在工作中:))

答案 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).
    
  • 我们到达了一个我们已经访问过的节点:CurrVisited的一个元素,在这种情况下我们需要中断搜索:否则我们将循环无限次:

    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).

\+表示