" first == null ? false : second == null ? false : first < second "
这是我尝试这样做的。目标是将其输入SWI-Prolog,以便输出结果。
test(X, Y) :-
X ins 1..3,
Y ins 1..3,
X #\= Y.
......等等。
我实际上是尝试使用prolog来解决8-queens问题,并且到目前为止还有这个问题。
?- test(X, Y).
X = 1
Y = 2 ;
X = 2,
Y = 1;
X = 3,
Y = 1 ;
但是我一直收到这个错误:eight_queens(Qs, L) :-
Qs = [ [X1,Y1], [X2, Y2], [X3, Y3], [X4, Y4], [X5, Y5], [X6, Y6], [X7, Y7], [X8, Y8], [X9, Y9] ],
Qs ins 1..9,
X1 #\= X2,
X1 #\= X3,
...
etc.
对于测试函数和8_queens问题。
答案 0 :(得分:3)
ins
用于列表,in
用于单个变量,所以在您的示例中:
test(X, Y) :-
X ins 1..3,
Y ins 1..3,
X #\= Y.
X,Y
被假定为列表。这不会产生语法错误,但在尝试使用X运行它时会产生错误,Y不是列表。
同样在使用in
Low..High时,并不意味着变量只是X=<High
和X>=Low
的int。为了将约束设为整数,请使用label/1
:
:- use_module(library(clpfd)).
%using in/
test(X,Y):- X in 1..3,Y in 1..3,label([X,Y]), X#\=Y.
%2nd way using ins
test(X,Y):- [X,Y] ins 1..3, label([X,Y]), X#\=Y.
示例:
?- test(X,Y).
X = 1,
Y = 2 ;
X = 1,
Y = 3 ;
X = 2,
Y = 1 ;
X = 2,
Y = 3 ;
X = 3,
Y = 1 ;
X = 3,
Y = 2 ;
false.
答案 1 :(得分:3)
除了@coder发布的/ 2和ins / 2的观察,解决你迫在眉睫的问题之外,我还要添加以下几点,在使用CLP(FD)时要记住:
首先让我们在@ coder的帖子中观察使用ins 标记为 2nd way的变体的答案,但没有目标标签/ 1:
test(X, Y) :-
[X,Y] ins 1..3,
X #\= Y.
?- test(X,Y).
X in 1..3, % residual goal
X#\=Y, % residual goal
Y in 1..3. % residual goal
由于查询没有唯一的答案,Prolog以剩余目标回答(有关详细信息,请参阅section A.8.8 of the CLP(FD) manual)。这些剩余目标是正在传播的约束,并且随着每个附加(非冗余)约束,域变窄。如果这不会导致上述示例中的唯一解决方案,则可以通过标记约束变量(例如使用label / 1)来获取具体值。该观察结果表明使用标签作为最后目标:
?- test(X,Y), label([X,Y]).
X = 1,
Y = 2 ;
X = 1,
Y = 3 ;
X = 2,
Y = 1 ;
X = 2,
Y = 3 ;
X = 3,
Y = 1 ;
X = 3,
Y = 2.
这显然与@coders版本的结果相同,但由于约束而在标记时不考虑三对(X,Y)=(1,1)∨(2,2)∨(3,3)在目标X#\=Y
之前发布label([X,Y])
。在@ coder的版本中,它是另一种方式:label([X,Y])
提供所有三对作为可能的解决方案,最后一个目标X#\=Y
随后消除它们。要看到这一点,只需将最后一个目标作为注释并查询谓词:
test(X,Y):- [X,Y] ins 1..3, label([X,Y]). %, X#\=Y.
?- test(X,Y).
X = Y, Y = 1 ; % <- (1,1)
X = 1,
Y = 2 ;
X = 1,
Y = 3 ;
X = 2,
Y = 1 ;
X = Y, Y = 2 ; % <- (2,2)
X = 2,
Y = 3 ;
X = 3,
Y = 1 ;
X = 3,
Y = 2 ;
X = Y, Y = 3. % <- (3,3)
在这个例子中,差异是微不足道的,所以@coder的版本没有任何问题。但总的来说,如果贴标后发布的约束排除了很多候选人,这可能会产生很大的差异。因此,始终将标签作为最后一个目标是一种好习惯。
根据之前的观察结果,将谓词划分为发布所有约束和标签的核心关系是恰当的。将重构的谓词test / 2视为模板:
test(X,Y) :-
test_(X,Y,L), % the core relation
label(L). % labeling
test_(X,Y,L) :-
L=[X,Y], % variables to be labeled in a flat list
L ins 1..3,
X#\=Y.
谓词test_ / 3通过发布所有必要的约束来描述实际关系,并且列表作为包含要标记的所有变量的附加参数。获取后者可能并不简单,具体取决于您的参数所带来的数据结构(例如,将列表列表作为参数,您希望将其转换为用于标记的平面列表)。所以谓词test / 2只调用test_ / 3,然后是标记目标。通过这种方式,您可以获得清晰易读的分离。
目标label(L)
是进行标记的最简单方法。它相当于labeling([],L)
。标签/ 2的第一个参数是一个选项列表,可以让您对搜索过程进行一些控制,例如: labeling([ff],L)
标记最左边的变量,然后是最小的域,以便尽早发现不可行性。根据您尝试解决的问题,不同的标记策略可能会导致结果更快或更慢。有关可用的标签策略和更多示例,请参阅documentation of labeling/2。