在 Prolog 语句的末尾剪切

Cut at the end of a Prolog statement

我遇到过这种切割,如果图 Graph 的某个节点 B 存在边 A-B 或 B-A,它应该 return 为真。

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

问题是我不明白为什么删除这个削减会对 returned 解决方案产生任何影响。

据我所知,Prolog 语句的 cut at the end 的唯一用途是存在另一个我们不想成为的同名语句 [another node(...)]如果第一个成功则调用。一个例子是将 X 和 Y 和 returns 作为第三个参数的函数。

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

解决方案return未经删减(正确)

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

解决方案return剪辑(不正确)

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

"As I understand it the only use for a cut at the end of a Prolog statement is when there is another statement with the same name [another node(...)] which we don't want to be called if the first one succeedes."

好吧,这对你的情况来说是不正确的,因为你使用的是 member/2 谓词,它可以与回溯一起使用。在这种情况下,使用切割将 p运行e Prolog 在回溯中使用的解决方案树,并可能导致您获得的结果发生变化。为了举例说明,请在此处查看原始 post 的略微修改代码:

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) 对,并且由于代码中有 ! 语句,搜索树的其余部分现在是 p运行ed。因此,您得到的结果为 Target = x

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

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

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