在Prolog语句的结尾处剪切

时间:2019-01-20 15:44:31

标签: prolog spanning-tree prolog-cut

我遇到过这种割伤,如果图Graph的某些节点B存在边A-B或B-A,则应该返回true。

node(A,Graph) :- adjacent(A,_,Graph),!.

问题是我不明白为什么删除此切口会对返回的解决方案产生任何影响。

据我所知,Prolog语句的cut at the end的唯一用法是当存在另一个我们不想调用的同名语句[another node(...)]时第一个成功。一个例子是一个函数,它使用X和Y并返回较大的一个作为第三个参数。

max1(X, Y, X) :- X > Y, !.
max1(_X, Y, Y).

但是,没有其他语句称为node(...),所以我看不到切割会如何影响解决方案。

这是我的代码。它应该找到一个生成树。 here进行了详细说明。编译器是Linux上的SWI-Prolog 7.6.4。

:- op(900, fy, not).

stree1( Graph, Tree)  :-
    subset( Graph, Tree),  tree( Tree),  covers( Tree, Graph).

tree( Tree)  :-
    connected( Tree),  not hasacycle( Tree).

connected( Graph)  :-
    not ( node( A, Graph), node( B, Graph), not path( A, B, Graph, _) ).

hasacycle( Graph)  :-
     adjacent( Node1, Node2, Graph),
     path( Node1, Node2, Graph, [Node1, X, Y | _] ). 

covers( Tree, Graph)  :-
    not ( node( Node, Graph), not node( Node, Tree) ).

subset( [], [] ). 
subset( [X | Set], Subset)  :-  subset( Set, Subset).
subset( [X | Set], [X | Subset])  :-  subset( Set, Subset).

adjacent( Node1, Node2, Graph)  :-
      member( Node1-Node2, Graph)
      ;
      member( Node2-Node1, Graph).

node( Node, Graph)  :-  adjacent( Node, _, Graph). 

path( A, Z, Graph, Path)  :-
      path1( A, [Z], Graph, Path).

path1( A, [A | Path1], _, [A | Path1] ).

path1( A, [Y | Path1], Graph, Path)  :-
      adjacent( X, Y, Graph),
      not member( X, Path1), 
      path1( A, [X, Y | Path1], Graph, Path).

返回的溶液未经切割(正确)

?- stree1([a-b, b-c, b-d, c-d], Tree).
Tree = [a-b, b-d, c-d] ;
Tree = [a-b, b-c, c-d] ;
Tree = [a-b, b-c, b-d] ;
false.

通过剪切返回的解决方案(不正确)

?- stree1([a-b, b-c, b-d, c-d], Tree).
Tree = [a-b] ;
Tree = [a-b, c-d] ;
Tree = [a-b, b-d] ;
Tree = [a-b, b-d, c-d] ;
Tree = [a-b, b-c] ;
Tree = [a-b, b-c, c-d] ;
Tree = [a-b, b-c, b-d] ;
false.

1 个答案:

答案 0 :(得分:2)

“据我所知,在Prolog语句末尾进行剪切的唯一用途是当存在另一个不希望被调用的同名语句[another node(...)]时,第一个成功。”

好吧,这不适用于您的情况,因为您正在使用member/2谓词,该谓词可用于回溯。在这种情况下,使用剪切将修剪Prolog在回溯中使用的解决方案树,并可能导致您获得的结果发生变化。要举例说明,请参见此处原始帖子的稍作修改的代码:

node( Node, Graph , Target)  :-  adjacent( Node, Target, Graph),!.

adjacent( Node1, Node2, Graph)  :-
  member( Node1-Node2, Graph)
  ;
  member( Node2-Node1, Graph).

在控制台中运行此查询时,您将看到输出:

?- node(l,[l-x,l-y],Target).
Target = x

为什么?因为一开始,您的搜索树有两片叶子。对(l-x)或(l-y)都满足adjacent/3中的条件。然后,根据深度优先搜索,选择对(l-x),并且由于您的代码中包含!语句,因此现在修剪了搜索树的其余部分。因此,您得到的结果为Target = x

但是,如果您从代码中删除!语句,您将看到的是:

?- node(l,[l-x,l-y],Target).
Target = x ;
Target = y ;
false.

在这里,您看到搜索树的两个叶子都按照深度优先顺序顺序执行,并且看到两个结果。这就是导致!不存在时看到不同结果的原因。