在序言中排除 tuples_in 列表
Excluding a tuples_in list in prolog
问题简而言之:
16 children 将坐在 4 x 4 的椅子阵列中。 children 是 8 个女孩(编号 1..8)和 8 个男孩(编号 9..16)。
1,3,5,8 觉得男孩子很讨厌
9,10,11,14 认为女孩很恶心
这些对是敌人:
[[1,2], [4,6], [4,7], [4, 9], [9,11], [12, 14], [14,16]]
判断两个children不是敌人的谓词定义为:
not_enemy(A, B) :-
NotA #\= A #\/ NotB #\= B,
tuples_in([[NotA, NotB]],
[[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]).
找到以上代码here
但是当我查询时 ?- not_enemy(1,2) 输出为真。
我必须改用这个长代码:
not_enemy(A, B) :-
A #=1 #==> B #\= 2,
A #=4 #==> B #\= 6,
A #=4 #==> B #\= 7,
A #=4 #==> B #\= 9,
A #=9 #==> B #\= 11,
A #=12 #==> B #\= 14,
A #=14 #==> B #\= 16.
谁能帮忙改正第一段代码?提前致谢。
我会改进你的代码,让它变得通用
not_enemy(A, B) :-
maplist(not_enemy(A,B), [[1,2], [4,6], [4,7], [4,9], [9,11], [12,14], [14,16]]).
not_enemy(A,B,[X,Y]) :-
X #= A #==> Y #\= B.
我找不到合适的方法来使用 tuples_in 来解决这个问题。
以上tuples_in/2
的用法是错误的。
将 tuples_in
视为定义 "compatibility tables" 的一种方式:
那么应该很明显,与 (#\=)/2
的组合不可能用于表达 "incompatibility tables".
为什么?因为---不兼容table---我们不想排除任何单个不兼容的元组,但是所有
其中 同时。
在处理有限域时,我们可以显式构建兼容性 table,方法是将笛卡尔积作为消除不兼容对的基础。
我找到了另一个答案,而不是使用这个
not_enemy(A, B) :-
NotA #\= A #\/ NotB #\= B,
tuples_in([[NotA, NotB]],
[[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]).
用#\
取反tuples_in
not_enemy(A, B) :-
#\ tuples_in([[A,B]],
[[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]).
扩展我上面给出的评论,我想向您展示 SWI-Prolog 顶层的一个重要特征,它有助于检测明显的错误公式问题。
首先考虑not_enemy/2
明显错误的答案:
?- not_enemy(1, 2).
true.
然而,还有更多,使用后你会发现:
?- set_prolog_flag(toplevel_residue_vars, true).
true.
然后,顶层显示挂起的剩余目标,这些目标通常不会显示,因为涉及的变量不会出现在查询中:
?- not_enemy(1, 2).
% with pending residual goals
_G454 in 0..1,
_G454#\/_G460#<==>1,
etc.
由此,已经很明显这个公式有问题:存在未决的剩余约束,而CLP(FD)一般不会也不能保证未决约束的一致性。你必须使用枚举谓词之一,看看是否有任何具体的解决方案。
在这种情况下,即使使用枚举谓词也会得到错误的结果,因为问题的表达方式错误且笨拙。但是,单是未决的剩余约束就已经清楚地表明您不能将答案视为具体的解决方案。
标志 toplevel_residue_vars
的工作原理是将查询隐式包装在名为 call_residue_vars/2
的重要谓词中。这在 SICStus 和 SWI 中可用,以显示 all 剩余约束。使用它来确保您不会在公式中的某处意外创建无法满足的约束。
出于这些原因,我强烈建议您避免副作用,这样您就可以更明确地推理您的代码并使用顶层显示答案和具体解决方案。
问题简而言之: 16 children 将坐在 4 x 4 的椅子阵列中。 children 是 8 个女孩(编号 1..8)和 8 个男孩(编号 9..16)。 1,3,5,8 觉得男孩子很讨厌 9,10,11,14 认为女孩很恶心 这些对是敌人: [[1,2], [4,6], [4,7], [4, 9], [9,11], [12, 14], [14,16]]
判断两个children不是敌人的谓词定义为:
not_enemy(A, B) :-
NotA #\= A #\/ NotB #\= B,
tuples_in([[NotA, NotB]],
[[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]).
找到以上代码here
但是当我查询时 ?- not_enemy(1,2) 输出为真。
我必须改用这个长代码:
not_enemy(A, B) :-
A #=1 #==> B #\= 2,
A #=4 #==> B #\= 6,
A #=4 #==> B #\= 7,
A #=4 #==> B #\= 9,
A #=9 #==> B #\= 11,
A #=12 #==> B #\= 14,
A #=14 #==> B #\= 16.
谁能帮忙改正第一段代码?提前致谢。
我会改进你的代码,让它变得通用
not_enemy(A, B) :-
maplist(not_enemy(A,B), [[1,2], [4,6], [4,7], [4,9], [9,11], [12,14], [14,16]]).
not_enemy(A,B,[X,Y]) :-
X #= A #==> Y #\= B.
我找不到合适的方法来使用 tuples_in 来解决这个问题。
以上tuples_in/2
的用法是错误的。
将 tuples_in
视为定义 "compatibility tables" 的一种方式:
那么应该很明显,与 (#\=)/2
的组合不可能用于表达 "incompatibility tables".
为什么?因为---不兼容table---我们不想排除任何单个不兼容的元组,但是所有 其中 同时。
在处理有限域时,我们可以显式构建兼容性 table,方法是将笛卡尔积作为消除不兼容对的基础。
我找到了另一个答案,而不是使用这个
not_enemy(A, B) :-
NotA #\= A #\/ NotB #\= B,
tuples_in([[NotA, NotB]],
[[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]).
用#\
取反tuples_innot_enemy(A, B) :-
#\ tuples_in([[A,B]],
[[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]).
扩展我上面给出的评论,我想向您展示 SWI-Prolog 顶层的一个重要特征,它有助于检测明显的错误公式问题。
首先考虑not_enemy/2
明显错误的答案:
?- not_enemy(1, 2).
true.
然而,还有更多,使用后你会发现:
?- set_prolog_flag(toplevel_residue_vars, true).
true.
然后,顶层显示挂起的剩余目标,这些目标通常不会显示,因为涉及的变量不会出现在查询中:
?- not_enemy(1, 2).
% with pending residual goals
_G454 in 0..1,
_G454#\/_G460#<==>1,
etc.
由此,已经很明显这个公式有问题:存在未决的剩余约束,而CLP(FD)一般不会也不能保证未决约束的一致性。你必须使用枚举谓词之一,看看是否有任何具体的解决方案。
在这种情况下,即使使用枚举谓词也会得到错误的结果,因为问题的表达方式错误且笨拙。但是,单是未决的剩余约束就已经清楚地表明您不能将答案视为具体的解决方案。
标志 toplevel_residue_vars
的工作原理是将查询隐式包装在名为 call_residue_vars/2
的重要谓词中。这在 SICStus 和 SWI 中可用,以显示 all 剩余约束。使用它来确保您不会在公式中的某处意外创建无法满足的约束。
出于这些原因,我强烈建议您避免副作用,这样您就可以更明确地推理您的代码并使用顶层显示答案和具体解决方案。