序言约束规划和forall/2

prolog constraint programming and forall/2

我正在使用 SWI 7.2.3 并有以下程序:

?-use_module(library(clpfd)).
:- dynamic size/2,wall/2.

in_board(X,Y):-X #> 0,Y #> 0,size(N,M),X #=< N,Y #=< M.

wall_exists_line(X,Y,W) :- wall(X,Z),(Y #=< Z,W #=< Y;Y#=< W,Z#=< Y).

wall_not_exists_line(X,Y,W) :- not(wall_exists_line(X,Y,W)).

same_line(X,Y,Z,W):- X #= Z,in_board(Z,W),in_board(X,Y),wall_not_exists_line(X,Y,W).

我在这里使用约束编程,因为我希望 in_board 即使在 XY 都没有实例化的情况下也能工作(是的,我知道它可以通过其他方式实现,但是我发现这更容易)。

如您所见,size,wall 是动态的,两者本质上都是整数。

我的问题是,如果我断言 size(4,4)wall(2,2) 并查询 same_line(X,1,Y,3) 它 return 在应该 return X = Y, X in 1\/3..4 时为假(或类似)。

我知道 not(something(X)) 意味着 "no X exists where something is true",我想要 "there exists X where something(X) is not true"(我实际上是指 wall_exists_line)。

我尝试使用 forall 但 forall 不能很好地处理 this 问题中所述的约束。

可以找到针对我的特定问题的解决方案但我更喜欢一般性的答案,即如何针对约束做 forall 通常会做的事情?。

大目标

上面的程序只是prolog程序的一个子集,它应该解决akari游戏(也称为发光,见game),需要谓词same_line来确定哪个细胞被一些光照亮。

size(N,M) 表示我们的面板有 N 行和 M 列,wall(X,Y) 表示单元格 (X,Y) 是一堵墙。

编辑

我之前没有wall_not_exists_line,我直接把not(wall_exists_line)放在same_line里,我以为引入单独的predicate就解决了,结果没有。

我想把wall_exists_line改成它的否定,q and p的否定是not(q) or not(p)所以wall_exists_line就变成这样:

wall_not_exists_line(X,Y,W) :- not(wall(X,Z));(not(Y #=<Z);not(W #=<Y)),(not(Y#=<W);not(Z#=<Y)).

不幸的是 not(wall(X,Z)) 意味着 "No X or Z exists for which wall(X,Z) is true",我不想要这个,因为 wall 是动态的我不能用它做任何事情。

我找到了解决办法。

not(wall_exists_line(X,Y,W)) 将检查 XY 以及 W 的每个值(如果它们没有固定值)。

in_board(X,Y) 在区间内约束 XY 但不是固定值,因此 not 会尝试区间内的每个值。

解决方案是在进入 not 之前实例化变量 X,Y,W,这是通过将 in_board 更改为此来完成的:

in_board(X,Y):-size(N,M),between(0,N,X),between(0,M,Y).

这样 between 将实例化 XY 幸运的是 between 给出了区间内的所有值。

clpfd 和 between 之间的主要区别是 clpfd returns 域,而 between - 如果第三个参数未实例化 - returns 之间的每个值两个值。