Search code examples
prologclpfdinstantiation-error

Labeling in Prolog constraint programming


I am new to Prolog and currently working on a simple constraint programming problem. So I have four real numbers A,B,C,D with the property such that A+B+C+d = ABC*D = 7.11 Since it is easier to work with integer, I tried the following implementation:

   :- use_module(library(clpfd)).
   grocery(Vars):-
      Vars=[A,B,C,D],
      X #= 100 * A,
      Y #= 100 * B,
      Z #= 100 * C,
      W #= 100 * D,
      X+Y+Z+W #= 711,
      X*Y*Z*W #= 71100000000.

Since the above will give me partially solved answer, I tried putting the keyword label(Vars) at the end. But this causes my execution of grocery(V) to produce

ERROR: Arguments are not sufficiently instantiated.

While grocery([V]) will give me a false. Can anyone enlighten me on how to do the labeling? Thanks

Edit : I did not put the call to the library clpfd earlier on


Solution

  • You are facing two issues that I would like to discuss separately:

    Instantiation error

    As you mentioned, we get:

    ?- grocery(Vs), label(Vs).
    ERROR: Arguments are not sufficiently instantiated
    

    Labeling requires that the variables that are to be labeled all have finite domains. In your case, label/1 throws an because the domains of some variables are still infinite:

    ?- grocery([A,B,C,D]).
    A in inf.. -1\/1..sup,
    100*A#=_9006,
    _9006 in inf.. -100\/100..sup,
    _9006+_9084+_9078+_9072#=711,
    _9006*_9084#=_9102,
    _9084 in inf.. -100\/100..sup,
    100*B#=_9084,
    _9102 in inf.. -1\/1..sup,
    _9102*_9078#=_9222,
    _9078 in inf.. -100\/100..sup,
    100*C#=_9078,
    C in inf.. -1\/1..sup,
    _9222 in -71100000000.. -1\/1..71100000000,
    _9222*_9072#=71100000000,
    _9072 in -71100000000.. -100\/100..71100000000,
    100*D#=_9072,
    D in -711000000.. -1\/1..711000000,
    B in inf.. -1\/1..sup.
    

    The only chance to correct this is to create a suitable specialization of the program, where the variables end up with finite domains. Writing [Vs] instead of Vs is obviously no solution:

    ?- grocery(Vs), label([Vs]).
    ERROR: Type error: `integer' expected, found `[_8206,_9038,_8670,_8930]' (a list)
    

    This is because label/1 requires its argument to be a list of finite domain variables, not a list of lists.

    An example of a suitable specialization could be:

    ?- grocery(Vs), Vs ins 0..sup, label(Vs).
    false.
    

    The resulting program has no solution, but at least we know that it definitely has no solution, because there is no more instantiation error.

    No solution

    We have thus arrived at a second, rather independent question: Why does this resulting program have no solution?

    A major advantage of using a logic programming language like Prolog is that it enables the application of declarative debugging approaches as for example shown in GUPU.

    Like in GUPU, use the following definition to generalize away goals:

    :- op(950,fy, *).
    
    *_.
    

    For example, we can generalize away the last goal of your program:

    grocery(Vars):-
            Vars = [A,B,C,D],
            X #= 100 * A,
            Y #= 100 * B,
            Z #= 100 * C,
            W #= 100 * D,
            X+Y+Z+W #= 711,
            * X*Y*Z*W #= 71100000000.
    

    The resulting program is obviously more general than the original program, because we have removed a constraint from a pure and monotonic Prolog program.

    Now, we still get for the preceding query:

    ?- grocery(Vs), Vs ins 0..sup, label(Vs).
    false.
    

    And now we know: Even the more general program has no solution.

    If you expect solutions in this case, you will have to change portions of the remaining program to correct the mistake in the formulation.

    For more information about this approach, see and .