Search code examples
prologclpfd

Enumerating domains in Prolog's clpfd


I'm exploring dependent structures of constraints like this one:

assign(X,Y) :- 
    X in 1..5, 
    ((X mod 2 #= 1) #=> Y in 2..3), 
    ((X mod 2 #= 0) #=> Y #= 5).

What I'm looking for is a representation of X's and Y's domains that is as sparse as possible - in this case it would be something along the lines of X in {1,3,5} and Y in {2,3} or X in {2,4} and Y = 5.

One way of doing that would be to detect all variables on the left side of the #=>, enumerate all their values and collect and merge them together, something like ?- assign(X, Y), findall(X-D, (indomain(X),fd_dom(Y,D)), C), do stuff with C, but maybe there is a more efficient way?

I've also encountered an error trying to label([X,Y]): Arguments are not sufficiently instantiated that goes away when I add another constraint on Y's domain.

When should I expect this error to occur? I feel I have a poor understanding of clpfd's mechanisms and limitations, are there any resources I could learn from? I already know the basics of constraint programming, arc consistency etc.


Solution

  • To keep clpfd enumeration predicates (like indomain/1, label/1, labeling/2, etc.) from ever throwing instantiation errors, simply ensure that all variables have been assigned some finite domain before any enumeration predicates is executed.

    So how about directly translating what you wrote to code?

    assign(X,Y) :- X in 1\/3\/5, Y in 2..3.     %    X in {1,3,5} and Y in {2,3} 
    assign(X,Y) :- X in 2..4,    Y in 5.        % or X in {2,4}   and Y = 5
    

    A simple query (with SWI-Prolog):

    ?- assign(X,Y), labeling([],[X,Y]).
      X = 1, Y = 2
    ; X = 1, Y = 3
    ; X = 3, Y = 2
    ; X = 3, Y = 3
    ; X = 5, Y = 2
    ; X = 5, Y = 3
    ; X = 2, Y = 5
    ; X = 3, Y = 5
    ; X = 4, Y = 5.