Bagof/3是不可预测的



我对以下结果感到困惑。我正在使用swi-prolog。

?- bagof(Q, (Q=A, (A=[a,_] ; A=[_,b])), X).
A = [_G16898, b],
X = [[_G16898, b]] ;
A = [a, _G16892],
X = [[a, _G16892]].

请注意,[a,_][_,b]未统一以产生答案A = [a,b], X=[[a,b],[a,b]]

现在,让我们尝试使用算术约束:

?- bagof(Q, (Q=A, (A in 1..5 ; A in 3..8)), X).
X = [A, A],
A in 3..5.

奇怪的是,这次算术约束是一起进行的,但没有答案A in 1..5, X=[A]A in 3..8, X=[A]

现在让我们以另一种方式尝试一下:

?- bagof(Q, (Q=A, ((1 #=< A, A #=< 5) ; (3 #=< A, A #=< 8))), X).
X = [A],
A in 3..5 ;
X = [A],
A in 3..5.

算术约束像以前一样合并,但是我们有两个答案,而不是一个答案。

如何解释所有这些?

编辑:一些更奇怪的结果。比较以下内容:

?- A=[_,_], bagof(Q, K1^K2^(Q=A, (A=[a,K1] ; A=[K2,b])), X).
A = [_G16886, b],
X = [[_G16886, b]] ;
A = [a, _G16889],
X = [[a, _G16889]].

与此:

?- A=[a,b], bagof(Q, K1^K2^(Q=A, (A=[a,K1] ; A=[K2,b])), X).
A = [a, b],
X = [[a, b], [a, b]].

多数民众赞成在Swi-prolog的人工制品,它在获取Findall/3副本时也确实复制了归因于变量。在执行Keysort/2之前,在Bagof/3中使用Findall/3副本。但是效果已经可以通过Findall/3:

来解释。

swi-prolog,findall/3副本归因于变量条件:

?- findall(A, A in 1..5, L).
L = [_3464],
_3464 in 1..5.
?- findall(A, (A in 1..5, (true; true)), L).
L = [_3762, _3768],
_3762 in 1..5,
_3768 in 1..5

jekejeke prolog,findall/3不复制属性变量条件:

?- findall(A, A in 1..5, L).
L = [_A]
?- findall(A, (A in 1..5, (true; true)), L).
L = [_A, _B]

在bagof/3中,不仅有钥匙码/2步,而且还有恢复变量的步骤。在SWI-Promog的此步骤中,可能会加入约束,因为将存在约束。

这解释了OP问题的第一个结果。OP问题的第二个结果可以解释,因为Swi-Prog确实在(#=&lt;)/2的情况下引入了新变量。您可以检查自己:

?- [user].
test(A) :- A in 1..5 ; A in 3..8.
test(A) :- (1 #=< A, A #=< 5) ; (3 #=< A, A #=< 8).
?- listing(test/1).
test(A) :-
    (   (   integer(A)
        ->  between(1, 5, A)
        ;   clpfd:clpfd_in(A, 1..5)
        )
    ;   integer(A)
    ->  between(3, 8, A)
    ;   clpfd:clpfd_in(A, 3..8)
    ).
test(A) :-
    (   (   integer(A)
        ->  A>=1
        ;   B=1,
            clpfd:clpfd_geq(A, B)
        ),
        (   integer(A)
        ->  5>=A
        ;   C=5,
            clpfd:clpfd_geq(C, A)
        )
    ;   (   integer(A)
        ->  A>=3
        ;   D=3,
            clpfd:clpfd_geq(A, D)
        ),
        (   integer(A)
        ->  8>=A
        ;   E=8,
            clpfd:clpfd_geq(E, A)
        )
    ).

(in)/2的扩展中没有新鲜变量。但是我猜(#=&lt;)/2扩展中的新鲜变量,然后导致Bagof/3看到两个解决方案,而不是仅一个解决方案。

编辑19.08.2019:
现在,我想知道使用CLP(FD)来解决问题...

最新更新