什么会导致Prolog在匹配中成功,但在要求标记输出时失败?

什么会导致Prolog在匹配中成功,但在要求标记输出时失败?,prolog,gnu-prolog,Prolog,Gnu Prolog,作为一个学习练习,我正在尝试用Prolog解决问题,我认为我已经使用GNU Prolog有限域求解器正确地映射了这个问题 当我运行solve函数时,Prolog返回:yes和一个变量列表,所有变量都在0..1范围内(布尔值,因为我限制了它们)。问题是,当我试图添加一个fd_标签(解决方案)子句时,Prolog关于faces并抛出:no 我是这门语言的新手,在我真正要求它标注答案之前,我似乎找不到任何攻击途径来找出为什么一切似乎都有效…显然,你没有“正确”地将问题映射到FD,因为当你尝试标注变量时

作为一个学习练习,我正在尝试用Prolog解决问题,我认为我已经使用GNU Prolog有限域求解器正确地映射了这个问题

当我运行solve函数时,Prolog返回:yes和一个变量列表,所有变量都在0..1范围内(布尔值,因为我限制了它们)。问题是,当我试图添加一个fd_标签(解决方案)子句时,Prolog关于faces并抛出:no

我是这门语言的新手,在我真正要求它标注答案之前,我似乎找不到任何攻击途径来找出为什么一切似乎都有效…

显然,你没有“正确”地将问题映射到FD,因为当你尝试标注变量时,你会得到一个“否”

在约束逻辑编程中,您要做的是建立一个约束模型,其中有一个域的变量(在您的例子中,域[0,1]为布尔值),以及这些变量之间的许多约束。每个约束都有一个传播规则,该规则尝试实现发布约束的变量域的一致性。不一致的值将从域中删除。有几种类型的一致性,但它们有一个共同点:约束本身通常不会给出完整的解决方案,甚至不会告诉您约束模型是否有解决方案

例如,假设您有两个变量X和Y,都有域[1..10],约束X 为了得到一个解决方案(所有变量都绑定到值),您需要标记变量。每个标记都会唤醒附加到标记变量的约束,从而触发另一轮传播。这将导致解决方案(所有变量都绑定到值,答案:是)或失败(在搜索树的每个分支中,某些变量以空域结束,答案:否)

由于每个约束仅针对其发布的变量域的一致性,因此可能在传播阶段未检测到由约束组合产生的不可行性。例如,具有域[1..2]和成对不等式约束的三个变量X、Y、Z。这似乎发生在您的约束模型中

如果您确信这个难题一定有解决方案,那么您的约束模型就包含一些不可行性。也许仔细观察一下约束条件就足以发现它

如果您没有看到任何明显的不可行性(例如,一些矛盾的约束,如上面的不等式示例),则需要调试程序。如果可能的话,不要使用内置的标记谓词,而是编写自己的谓词。然后,您可以添加一些输出谓词,允许您跟踪实例化了什么变量,以及这导致了布尔决策变量中的哪些更改,或者是否导致了失败。

(@twinterer已经给出了解释,我的答案试图从另一个角度进行解释)

当您输入一个查询到Prolog时,您得到的是一个答案。通常一个答案包含一个解决方案,有时包含多个解决方案,有时根本不包含任何解决方案。这两个概念经常混淆。让我们看一下GNU Prolog的示例:

| ?- length(Vs,3), fd_domain_bool(Vs).                                       

Vs = [_#0(0..1),_#19(0..1),_#38(0..1)]

yes
这里,我们有一个包含8个解决方案的答案。即:

| ?- length(Vs,3), fd_domain_bool(Vs), fd_labeling(Vs).

Vs = [0,0,0] ? ;

Vs = [0,0,1] ? ;

...

Vs = [1,1,1]

yes
现在是另一个问题。这就是所提到的@twinterer的例子

| ?- length(Vs,3), fd_domain_bool(Vs), fd_all_different(Vs).

Vs = [_#0(0..1),_#19(0..1),_#38(0..1)]

yes
答案看起来和以前一样。但是,它不再包含解决方案

| ?- length(Vs,3), fd_domain_bool(Vs), fd_all_different(Vs), fd_labeling(Vs).

no
理想情况下,在这种情况下,高层不会说“是”,而是说“可能”。事实上,CLP(R),最早的约束系统之一,做到了这一点

另一种使这一点不那么神秘的方法是显示所涉及的实际约束。威斯康辛州投资局这样做:

?- length(Vs,3), Vs ins 0..1, all_different(Vs).
Vs = [_G565,_G568,_G571],
_G565 in 0..1,
all_different([_G565,_G568,_G571]),
_G568 in 0..1,
_G571 in 0..1.

?- length(Vs,3), Vs ins 0..1, all_different(Vs), labeling([], Vs).
false.
所以SWI向您展示了获得具体解决方案必须满足的所有约束。将SWI的回答解读为:是的,有一个解决方案,前提是所有这些细节都是真实的! 唉,这些细节是错误的

解决这个问题的另一种方法是获得一致性更强的
所有不同/1
的实现。但这只适用于特定情况

?- length(Vs,3), Vs ins 0..1, all_distinct(Vs).
false.
在一般情况下,您不能期望系统保持全局一致性。原因:

  • 保持一致性可能非常昂贵。通常最好将此类决策委托给标签部门。事实上,简单的
    all_distinct/1
    通常比
    all_distinct/1

  • 更好的一致性算法通常非常复杂

  • 在一般情况下,保持全局一致性是一个无法确定的问题