在Prolog中定义图形:边缘和路径,查找两个顶点之间是否存在路径

时间:2014-01-16 12:20:57

标签: graph prolog transitive-closure

我对Prolog很新。我在graph.pl中定义了以下图表:

graph

这是我的Prolog代码:

edge(a,e).
edge(e,d).
edge(d,c).
edge(c,b).
edge(b,a).
edge(d,a).
edge(e,c).
edge(f,b).
path(X,X).
path(X,Y):- edge(X,Z) ; path(Z,Y).

我理解如下:只有在顶点X和顶点Y之间存在边缘时,顶点X和顶点Z之间才会有路径并且顶点Z和顶点Y 之间存在一条路径(某种递归)。

这对于提供的图表是否正确?当我向Prolog询问顶点A和顶点F之间的路径时,它给了我true ...这甚至都不对!这段代码可能有什么问题?

4 个答案:

答案 0 :(得分:13)

图表中的周期。您需要跟踪您正在访问的节点,并检查它们。试试这个,使用辅助谓词和累加器来跟踪被访问的节点:

path(A,B) :-   % two nodes are connected, if
  walk(A,B,[]) % - if we can walk from one to the other,
  .            % first seeding the visited list with the empty list

walk(A,B,V) :-       % we can walk from A to B...
  edge(A,X) ,        % - if A is connected to X, and
  not(member(X,V)) , % - we haven't yet visited X, and
  (                  % - either
    B = X            %   - X is the desired destination
  ;                  %   OR
    walk(X,B,[A|V])  %   - we can get to it from X
  )                  %
  .                  % Easy!

edge(a,e).
edge(e,d).
edge(d,c).
edge(c,b).
edge(b,a).
edge(d,a).
edge(e,c).
edge(f,b).

答案 1 :(得分:5)

您使用的格式(edge / 2)对于学习Prolog很有意义,您应该遵循mbratch对该教程的建议。

实际上,有一些很好的替代品已经可用,在某些情况下可以使用有用的谓词:例如,在库(ugraph)中,有reachable / 3。现在,使用您的数据,此路径/ 2谓词

path(X,Y) :-
    findall(A-B, edge(A,B), Es),
    vertices_edges_to_ugraph([],Es,G),
    reachable(X,G,Path),
    member(Y,Path).

确实

?- path(a,X).
X = a ;
X = b ;
X = c ;
X = d ;
X = e.

让我们看看它意味着什么:

findall(A-B, edge(A,B), Es)

将所有边缘放入,并根据库的要求输入

vertices_edges_to_ugraph([],Es,G)

在G中构建相应的图形

reachable(X,G,Path)

制作一个列表从X

到达所有顶点的路径(duh)
member(Y,Path)

查看路径中是否存在Y。

由于我使用Y free 查询,我从X获得所有可到达的顶点,我绑定到a

答案 2 :(得分:3)

如果您有兴趣了解如果路径存在 - 但不一定在实际路径中 - 计算二元关系edge/2的{​​{3}}。< / p>

幸运的是,transitive closure中常见的习语!

要表达edge/2的反射性传递闭包,请使用 - 在前面的问题中定义&#34; closure/3&#34;:

?- closure(edge, X, Y).
   X = a, Y = e
;  X = a, Y = d
;  X = a, Y = c
;  ...

请注意closure/3具有非常好的终止属性。

如果edge/2的所有条款都是基本事实,closure(edge, _, _)会普遍终止!看:

?- closure(edge, _, _), false.
false.

答案 3 :(得分:2)

正在检查一个循环! 我事先用trace.命令执行了这个例子,并且看到程序返回问题以找到循环后从a到f的路径。 路径(a,f)需要路径(e,f)为真,遵循简短的符号我们需要为真:

(d,f),(c,f),(b,f),然后是(a,f)再次。

要解析循环,您需要一种机制来防止循环。我的第一个想法是保留一个节点名列表,如果列表在检查路径时没有包含当前的X,也要检查。

相关问题