【问题标题】:Prolog Constraint Programing finding even and odd numbersProlog约束编程查找偶数和奇数
【发布时间】:2014-02-05 17:42:40
【问题描述】:

我需要创建一个谓词:

applyConstraints(L)

这对 L 中的变量施加了约束,使得 L 中没有两个连续的元素都是奇数甚至是奇数,我该怎么做?使用固定大小的 L 很简单,但是可变大小的 L 呢? 我需要使用 sicstus-prolog clpfd 库来完成。

【问题讨论】:

  • 无法想象怎么会比循环更简单...

标签: prolog clpfd constraint-programming


【解决方案1】:
% SICStus:

applyConstraints([]).
applyConstraints([X|Xs]) :-
    X mod 2 #= R,
    applyConstraints(Xs, R).

applyConstraints([], _).
applyConstraints([X|Xs], R) :-
    X mod 2 #= S,
    S #\= R,
    applyConstraints(Xs, S).

% Query:

| ?- applyConstraints(L), length(L,2), !, domain(L,-2,2), labeling([],L).
L = [-2,-1] ? ;
L = [-2,1] ? ;
L = [-1,-2] ? ;
L = [-1,0] ? ;
L = [-1,2] ? ;
L = [0,-1] ? ;
L = [0,1] ? ;
L = [1,-2] ? ;
L = [1,0] ? ;
L = [1,2] ? ;
L = [2,-1] ? ;
L = [2,1] ? ;
no

【讨论】:

  • 我认为没有必要放弃您原来的单线解决方案。当 OP 谈到 可变大小 L 时,他们可能只是表示 在编译时不固定。通过在约束设置阶段显示具有选择点的程序,您可能会在此处给出一个不好的示例。
【解决方案2】:

受@MatsCarlsson 版本的启发,我尝试尽量减少涉及的约束变量的数量:

applyConstraints(Xs) :-
   S #\= R,
   applyConstraints(Xs, S, R).

applyConstraints([], _, _).
applyConstraints([X|Xs], S, R) :-
   X mod 2 #= S,
   applyConstraints(Xs, R, S).

编辑:这个版本对于目标applyConstraints([]) 有一个不明显的缺陷。实际上,需要在 SICStus 中切换到full_answer 模式,如下所示:

| ?- applyConstraints([]).
yes
| ?- assertz(clpfd:full_answer).
yes
| ?- applyConstraints([]).
clpfd:(_A#\=_B),
_A in inf..sup,
_B in inf..sup ? ;
no

所以我们有这个无用的约束,它可能会消耗资源。 为了克服这个缺陷,需要一些特殊的外壳:

applyConstraints([]).
applyConstraints([X|Xs]) :-
   X mod 2 #= S,
   S #\= R,
   applyConstraints(Xs, R, S).

注意 1 — 在 SWI 或 YAP 中,没有直接的方法可以打开完全应答模式。解决问题的唯一方法是将查询包裹在 call_residue_vars/2 周围,如下所示:

?- applyConstraints([]).
true.

?- call_residue_vars(applyConstraints([]),RVs).
RVs = [_G794, _G797],
_G794#\=_G797.

注意 2 — 感谢 @mat,自 SWI 7.3 以来有类似的功能(请记住,SWI 7 需要 --traditional 以实现兼容性):

?- set_prolog_flag(toplevel_residue_vars, true).
true.

?- applyConstraints([]).
% with detached residual goals
_G430#\=_G433.

(在这种情况下,“分离”应该是什么意思还不是很清楚,毕竟剩余的目标必须为真,才能使答案为真。所以不涉及分离。 )

【讨论】:

  • 对于 SWI 7.3 或更高版本,您可以使用?- set_prolog_flag(toplevel_residue_vars, true). 查看所有剩余约束。
【解决方案3】:

只考虑一对元素

applyConstraints([A,B|R]) :-
    A mod 2 #\= B mod 2,
    applyConstraints([B|R]).
applyConstraints([_]).

测试(使用 SWI-Prolog 库(clpfd),也许您需要将 ins/2 替换为 Sicstus 的对应项)

?- L=[X,Y,Z], applyConstraints(L), L ins 1..4, label(L).
L = [1, 2, 1],
X = Z, Z = 1,
Y = 2 ;
L = [1, 2, 3],
X = 1,
Y = 2,
Z = 3 ;
...

【讨论】:

  • 你为什么不按常见的方式编写子句:事实第一。你的写作引起了一堆不必要的开销。
  • @false: 因为在没有索引的情况下匹配?
  • 原因:缺少索引(在当前实现中),而且无法为最一般的查询生成答案 - 这在诊断上下文中通常非常有用。
  • applyConstraints([]) 失败
猜你喜欢
  • 2014-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-05
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
相关资源
最近更新 更多