prolog约束编程和forall / 2

时间:2016-05-29 17:54:41

标签: prolog clpfd

我正在使用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),则当它返回X = Y, X in 1\/3..4(或类似)时,它会返回false。

我知道not(something(X))的意思是“没有X存在于哪里是真的”,我想“存在X,其中某些东西(X)不是真的”(通过我实际上意为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中,我认为引入单独的谓词可以解决它,但事实并非如此。

我想到将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))表示“没有X或Z存在哪个墙(X,Z)是真的”,我不希望这个,因为wall是动态的我不能做任何事情它

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。

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

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

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

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

这种方式between将实例化XY,幸运的是between会提供区间中的所有值。

clpfd和just between之间的主要区别在于clpfd在between时返回域 - 如果第三个参数未被实例化 - 返回两个值之间的每个值。