Search code examples
prologclpfd

prolog constraint programming and forall/2


I'm using SWI 7.2.3 and have the following program :

?-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).

I'm using constraint programming here because I want in_board to work even when both X and Y are not instantiated(yes I know it could be implemented other ways but I found this to be easier).

As you can see size,wall are dynamic and both essentially takes integers.

My problem is if I assert size(4,4) and wall(2,2) and query same_line(X,1,Y,3) it returns false when it should return X = Y, X in 1\/3..4(or alike).

I know that not(something(X)) means "no X exists where something is true", I wanted "there exists X where something(X) is not true"(by something I actually mean wall_exists_line).

I tried using forall but forall doesn't work good with constraints as stated in this question.

A solution for my particular problem can be found But I'd prefer a general answer, that is how to do for constraints what forall would do normally ?.

Big Goal

The program above is just a subset of a prolog program which is supposed to solve akari game(also called light-up, see game), the predicate same_line is needed to determine which cells are lighten up by some light.

size(N,M) means our board has N rows and M columns, wall(X,Y) means the cell (X,Y) is a wall.

Edit

I didn't have wall_not_exists_line before, I put not(wall_exists_line) directly in same_line, I thought introducing separate predicate would solve it but it didn't.

I thought of changing wall_exists_line into the negation of it, the negation of q and p is not(q) or not(p) so wall_exists_line would change to this:

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

Unfortunately not(wall(X,Z)) means "No X or Z exists for which wall(X,Z) is true", I don't want this and as wall is dynamic I can't do anything with it.


Solution

  • I have found the solution.

    not(wall_exists_line(X,Y,W)) would check every value of X and Y and W if they don't have a fixed value.

    in_board(X,Y) constraint both X and Y in intervals but not a fixed value so not would try every value in the interval.

    The solution is to have the variables X,Y,W instantiated before entering not, this is done by changing in_board to this :

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

    This way between will instantiate X and Y and fortunately between gives all the values in the interval.

    The main difference between clpfd and just between is that clpfd returns domain while between - if the third argument isn't instantiated - returns every value between two values.