序言约束规划和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
即使在 X
和 Y
都没有实例化的情况下也能工作(是的,我知道它可以通过其他方式实现,但是我发现这更容易)。
如您所见,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))
将检查 X
和 Y
以及 W
的每个值(如果它们没有固定值)。
in_board(X,Y)
在区间内约束 X
和 Y
但不是固定值,因此 not
会尝试区间内的每个值。
解决方案是在进入 not
之前实例化变量 X,Y,W
,这是通过将 in_board
更改为此来完成的:
in_board(X,Y):-size(N,M),between(0,N,X),between(0,M,Y).
这样 between
将实例化 X
和 Y
幸运的是 between
给出了区间内的所有值。
clpfd 和 between
之间的主要区别是 clpfd returns 域,而 between
- 如果第三个参数未实例化 - returns 之间的每个值两个值。
我正在使用 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
即使在 X
和 Y
都没有实例化的情况下也能工作(是的,我知道它可以通过其他方式实现,但是我发现这更容易)。
如您所见,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))
将检查 X
和 Y
以及 W
的每个值(如果它们没有固定值)。
in_board(X,Y)
在区间内约束 X
和 Y
但不是固定值,因此 not
会尝试区间内的每个值。
解决方案是在进入 not
之前实例化变量 X,Y,W
,这是通过将 in_board
更改为此来完成的:
in_board(X,Y):-size(N,M),between(0,N,X),between(0,M,Y).
这样 between
将实例化 X
和 Y
幸运的是 between
给出了区间内的所有值。
clpfd 和 between
之间的主要区别是 clpfd returns 域,而 between
- 如果第三个参数未实例化 - returns 之间的每个值两个值。