【问题标题】:Equivalent of nvalue/2 from SICStus in SWIProlog相当于 SWI Prolog 中 SICStus 的 n 值/2
【发布时间】:2017-01-05 23:10:17
【问题描述】:

CLP(FD) 库的 SICStus 手册说:

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

当人们想要最小化解决方案中不同值的数量时,这特别有用。例如,如果有人试图将物品分配到不同尺寸的袋子中,并希望尽量减少袋子的数量。

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

【问题讨论】:

  • fd_size/2 是这样做的吗?
  • 我不这么认为...fd_size/2 返回域的元素数。例如,X in 0..10, fd_size(X, 11)。我正在寻找限制变量列表中 distinct 元素数量的东西。
  • 你会期待X in 0..10, foo([X], 1)?
  • 我希望length(Vs, 3), Vs ins 1..3, nvalue(2, Vs) 排除Vs = [3, 3, 3]Vs = [1, 2, 3] 等可能的答案,因为我们说必须有两个不同的值。
  • Backlink 改进 clpz。

标签: prolog swi-prolog clpfd sicstus-prolog


【解决方案1】:

@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 注释之后,我调整了代码:现在它非常紧凑,这要归功于库 apply 和 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 的副本会丢失发布的约束。

【讨论】:

  • 不正确:例如,nvalue(3, [1,1,1,2]) 的代码成功。
  • 很好的重写!请注意,您仍然可以通过使用E#&lt;==&gt;E1#/\(V#\=U)count_equals/3 中的求和转换为连词并在外循环中简单地对结果布尔值求和来进行简化。
  • @jschimpf:再次感谢。我已经按照您的提示进行了操作,但进行了简化...希望我做对了...至少,看起来还可以。
  • 不完全是我的想法。您不需要计算满足的等式的总和E,您只需计算一个布尔值D,如果所有等式都为假,则该布尔值为真。然后您可以将E #= 0 #/\ C #= R+1 #\/ E #&gt; 0 #/\ C #= R 简化为C #= R+D
猜你喜欢
  • 2011-11-11
  • 1970-01-01
  • 1970-01-01
  • 2022-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多