在prolog的列表中排除元组

在prolog的列表中排除元组,prolog,clpfd,Prolog,Clpfd,简而言之,这就是问题所在: 16名儿童将坐在一排4 x 4的椅子上。孩子们是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]] 查找两个子对象不是敌人的谓词定义为: not_enemy(A, B) :- NotA #\= A #\/ NotB #\= B, tuples_in([[NotA, No

简而言之,这就是问题所在: 16名儿童将坐在一排4 x 4的椅子上。孩子们是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]]

查找两个子对象不是敌人的谓词定义为:

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]]).
找到了上面的代码

但是当我询问时?-不是敌人(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\u in来解决这个问题。

以上使用
tuples\u in/2
是错误的

将中的
tuples\u视为定义“兼容性表”的一种方式:
那么很明显,与
(#\=)/2
的组合不可能用于表示“不兼容表”

为什么??因为——对于一个不兼容表——我们不想排除任何一个不兼容的元组,而是all 它们中的一个同时出现


当使用有限域时,我们可以通过笛卡尔积作为消除不相容对的基础,显式地构造相容表。

我找到了另一个答案,而不是使用这个

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]]).
只要用#\


在我上面给出的评论的基础上,我想向您展示SWI Prolog toplevel的一个重要功能,它有助于检测错误公式的明显问题

首先,考虑<代码>错误的答案> NothOut仇敌/ 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.
?-不是敌人(1,2)。
%还有悬而未决的剩余目标
_G454在0..1中,
_G454\/\U G460\\1,
等
从这一点来看,很明显,公式中存在一些错误:存在未决的剩余约束,而CLP(FD)通常不会也不能保证未决约束的一致性。您必须使用一个枚举谓词来查看是否有任何具体的解决方案

在这种情况下,即使使用枚举谓词,也会得到错误的结果,因为问题的表达是错误和笨拙的。然而,仅靠悬而未决的剩余约束已经清楚地表明,您无法将答案视为具体的解决方案

标记
toplevel\u residence\u vars
的工作原理是将查询隐式包装在名为
call\u residence\u vars/2
的重要谓词中。这在SICStus和SWI中可用,以显示所有剩余约束。使用它来确保您没有意外地在公式中的某个地方创建不可满足的约束


出于这些原因,我强烈建议您避免副作用,这样您就可以更具声明性地对代码进行推理,并使用顶层显示答案和具体解决方案。

?兼容性表?谢谢,我能从概念上理解你的想法,我将在prolog中尝试。它有效吗?很高兴知道!我以为\#是用于可修改的约束,而tuples#u in不属于这一类。所以我没有试过……我检查了文档,如果经过进一步调查,你的答案是正确的,我会在clpfd文档上提交一份错误报告。它确实有效否定后面的任何内容(在clpfd中)。示例是错误的,将具体化与/2中的
tuples_
混合显然不是用CLP(FD)表示给定约束的好方法。您的代码是一种正确的方法(+1!)。另一种方法是应用@repeat descripes方法:您可以构建关系的补码,并使用/2中的
tuples\u
将对约束到兼容的元素。另一种方法是否定/2
约束中的单个
元组。注意不要意外地否定/2
中涉及多对的
tuples\u约束,因为这在逻辑上并不等同于其他方法。
?- not_enemy(1, 2).
% with pending residual goals
_G454 in 0..1,
_G454#\/_G460#<==>1,
etc.