来自SWIProlog中SICStus的nvalue / 2的等价物

时间:2017-01-05 23:10:17

标签: prolog swi-prolog clpfd sicstus-prolog

CLP(FD)库的SICStus手册说:

  

nvalue(?N, +Variables) 其中Variables是包含有限边界或整数的域变量列表,N是整数或   域变量。如果N是采用的不同值的数量,则为真   Variables

当想要最小化解决方案中不同值的数量时,这尤其有用。例如,如果一个人试图将东西分配到不同尺寸的袋子中,并希望最小化袋子的数量。

在SWI Prolog中是否有相同的谓词(或方式)来实现相同的目标?

1 个答案:

答案 0 :(得分:4)

在@jschimpf评论之后,我重新考虑了算法。

nvalue(1, [_]).
nvalue(C, [V|Vs]) :-
    count_equals(V, Vs, E),
    E #= 0 #/\ C #= R+1 #\/ E #> 0 #/\ C #= R,
    nvalue(R, Vs).

count_equals(_, [], 0).
count_equals(V, [U|Vs], E) :-
    V #= U #/\ E #= E1+1 #\/ V #\= U #/\ E #= E1,
    count_equals(V, Vs, E1).

进一步清理

再次,在@jschimpf之后,我已经调整了代码:现在它非常紧凑,多亏了库应用和yall。

nvalue(1, [_]).
nvalue(C, [V|Vs]) :-
    maplist({V}/[U,Eq]>>(Eq#<==>V#=U), Vs, Es),
    sum(Es, #=, E),
    E #= 0 #/\ C #= R+1 #\/ E #> 0 #/\ C #= R,
    nvalue(R, Vs).

旧答案,越野车

我天真的尝试,基于reification

% nvalue(?N, +Variables)
nvalue(N, Vs) :-
    nvalues(Vs, [], VRs),
    sum(VRs, #=, N).

nvalues([], Acc, Acc).
nvalues([V|Vs], Acc, VRs) :-
    nvalues_(V, Vs, Acc, Upd),
    nvalues(Vs, Upd, VRs).

nvalues_(_V, [], Acc, Acc).
nvalues_(V, [U|Vs], Acc, Upd) :-
    V #\= U #<==> D,
    nvalues_(V, Vs, [D|Acc], Upd).

运行示例查询:

?- length(Vs, 3), Vs ins 1..3, nvalue(2, Vs), label(Vs).
Vs = [1, 1, 2] ;
Vs = [1, 1, 3] ;
Vs = [1, 2, 1] ;
Vs = [1, 2, 2] ;
Vs = [1, 3, 1] ;
Vs = [1, 3, 3] ;
Vs = [2, 1, 1] ;
Vs = [2, 1, 2] ;
Vs = [2, 2, 1] ;
Vs = [2, 2, 3] ;
Vs = [2, 3, 2] ;
Vs = [2, 3, 3] ;
Vs = [3, 1, 1] ;
Vs = [3, 1, 3] ;
Vs = [3, 2, 2] ;
Vs = [3, 2, 3] ;
Vs = [3, 3, 1] ;
Vs = [3, 3, 2].

修改

我的代码有点迂腐,当然可以更紧凑(也很清楚?):

nvalue(N, Vs) :-
    bagof(D, X^H^T^V^(append(X, [H|T], Vs), member(V, T), V #\= H #<==> D), VRs),
    sum(VRs, #=, N).

请注意,findall / 3不起作用,因为已知的变量D的副本将丢失已发布的约束。