Prolog -- Arguments are not sufficiently instantiated - prolog

I am trying to check for even/odd players and even/odd columns in a game by counting the players and the columns. At some point, it seems I am not instantiating my variables correctly.
Here is how I call the game:
playGame(Game):-
countPlayers(Game,TotalPlayers),
colSize(Game,TotalCols),
checkEvens(TotalPlayers,TotalCols);
checkOdds(TotalPlayers,TotalCols).
I assume the issues lies with TotalPlayers and TotalCols not being assigned correctly.
I tried looking at other questions, however the problems seem to be different. I am new to prolog and likely making a trivial mistake somewhere.
After some tracing, it seems the error is being caused when a combination of odd/even is the input. Given an input of two even or two odd numbers, the program behaves as expected. Given an input of one odd and one even number, and it breaks.
Full error:
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [11] 1 is _34862 mod 2
ERROR: [10] checkOdds(_34894,_34896)

?- X = 3, between(1, X, 2), between(1, X, 3).
X = 3.
?- X = 3, between(1, X, 2); between(1, X, 3).
X = 3 ;
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [9] between(1,_7656,3)
ERROR: [7] <user>
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
Can you spot what is going on?
A predicate like this:
foo :- a, b; c.
is the same thing as:
foo :- a, b.
foo :- c.
In other words, a, b is indeed in a different "context" than c.
Often, you mean to say a, (b ; c) instead. This is why the ; is usually put at the beginning of the line, and you do use parens around it. So it would be either
( a,
b
; c
)
or
a,
( b
; c
)
(which is not the same thing!)
This is definitely confusing:
a,
b;
c
You don't see "good" Prolog code written like this (say library code).
But really, try to read a textbook or something, Stackoverflow is good for figuring out where your error is but not for really learning.

Related

Safe sorting of terms

Standard term order takes variables as syntactic objects only. As a consequence beside other problems, sort/2 breaks the common assumptions of a relational definition. Neither can answer substitutions be a guarantee for solutions nor are ground instances of the second argument sorted.
?- X = 1, sort([1,X],[1]).
X = 1.
?- sort([1,X],[1]). % generalization fails
false.
?- sort([1,X],[2,1]).
X = 2. % unsorted list succeeds
?- X = 2, sort([1,X],[2,1]). % answer substitution fails
false.
But even if we ignore declarative concerns we are still faced with the problem that variable ordering only remains constant during the creation of a sorted list. So depending on the "age" of a variable we get
?- _=X+Y, sort([X,Y],[2,1]).
X = 2, Y = 1.
?- _=Y+X, sort([X,Y],[2,1]).
Y = 2, X = 1.
and age may change over time, even relative age.
We really should be protected by all such erratic behavior.
What I have tried so far is a safe definition, which produces the very same type errors as sort/2 but produces instantiation errors when the list to be sorted is not ground. As long as no instantiation error occurs, the definition is perfect, indeed.
sort_si(List, Sorted) :-
sort(List, ISorted),
( sort([], [_|Sorted]) ; true ), % just to get the type_error
( ground(ISorted)
-> Sorted = ISorted
; throw(error(instantiation_error, _Imp_def))
).
?- sort_si([X,X],S).
caught: error(instantiation_error, _97) % unexpected; expected: S = [X]
?- sort_si([-X,+Y], S).
caught: error(instantiation_error, _97) % unexpected; expected: S = [+Y,-X]
?- sort_si([_,_], []).
caught: error(instantiation_error, _97) % unclear, maybe failure
My question is: How to improve in ISO Prolog upon this definition by reducing the number of unnecessary instantiation errors? Ideally, an instantiation error for sort_si(List, Sorted) only occurs, when there are instances of the goal sort(List, Sorted) with different outcome. An optimal number of instantiation errors is not required. Maybe the fact that the list ISorted is sorted can be used to some degree.
And, also Sorted might be considered as now there will be never unsorted ground lists solutions to Sorted.
My take is go through ISorted and check whether every pair of successive terms are "safely comparable", meaning that there is no further instantiation that would change their order. I captured that idea in the comparable/2 predicate with the following cases:
If the two arguments are variable, then they must be the same variable in order to be comparable.
If the two arguments are ground, then they are comparable. (Not sure this case is necessary, beside to shortcut the manual traversal of terms.)
Otherwise, the two arguments must be non-variable, and at least one of them contains a variable. We need to compare the terms further, but only if both are complex terms with the same functor and same number of arguments. In that case, the first argument needs to be comparable. Then, the following ones need to be comparable only if the first one does not discriminate between the two terms, which happens when the first argument is equal (==).
I've added a test in the main predicate to fail when ISorted can't be unified with Sorted, with the idea that sort_si/2 would only differ from sort/2 when sort/2 would succeed "incorrectly", but not when it fails, but I am not sure on that point.
sort_si(List, Sorted) :-
sort(List, ISorted),
( sort([], [_|Sorted]) ; true ), % just to get the type_error
( Sorted \= ISorted % just to fail whenever sort/2 would fail
-> fail
; pairwise_comparable(ISorted)
-> Sorted = ISorted
; throw(error(instantiation_error, _Imp_def))
).
pairwise_comparable([]).
pairwise_comparable([_]).
pairwise_comparable([X1,X2|Xs]):-
comparable(X1,X2),
pairwise_comparable([X2|Xs]).
comparable(X1,X2):-
var(X1),
var(X2),
X1==X2.
comparable(X1,X2):-
ground(X1),
ground(X2).
comparable(X1,X2):-
nonvar(X1),
nonvar(X2),
functor(X1,F1,A1),
functor(X2,F2,A2),
( F1\=F2
-> true
; A1\=A2
-> true
; X1=..[_|Xs1],
X2=..[_|Xs2],
comparable_args(Xs1,Xs2)
).
comparable_args([],[]).
comparable_args([X1|Xs1],[X2|Xs2]):-
comparable(X1, X2),
( X1\==X2
-> true
; comparable_args(Xs1,Xs2)
).

Setting types of unbound variables in Prolog

I'm trying to find a way to set the type of a variable before it has been bound to a value. Unfortunately, the integer/1 predicate cannot be used for this purpose:
%This goal fails if Int is an unbound variable.
get_first_int(Int,List) :-
integer(Int),member(Int,List),writeln(Int).
I wrote a predicate called is_int that attempts to check the type in advance, but it does not work as I expected. It allows the variable to be bound to an atom instead of an integer:
:- initialization(main).
%This prints 'a' instead of 1.
main :- get_first_int(Int,[a,b,c,1]),writeln(Int).
get_first_int(Int,List) :-
is_integer(Int),member(Int,List).
is_integer(A) :- integer(A);var(A).
Is it still possible to set the type of a variable that is not yet bound to a value?
In SWI-Prolog I have used when/2 for similar situations. I really don't know if it is a good idea, it definitely feels like a hack, but I guess it is good enough if you just want to say "this variable can only become X" where X is integer, or number, or atom and so on.
So:
will_be_integer(X) :- when(nonvar(X), integer(X)).
and then:
?- will_be_integer(X), member(X, [a,b,c,1]).
X = 1.
But I have the feeling that almost always you can figure out a less hacky way to achieve the same. For example, why not just write:
?- member(X, [a,b,c,1]), integer(X).
???
Specific constraints for integers
In addition to what Boris said, I have a recommendation for the particular case of integers: Consider using CLP(FD) constraints to express that a variable must be of type integer. To express only this quite general requirement, you can post a CLP(FD) constraint that necessarily holds for all integers.
For example:
?- X in inf..sup.
X in inf..sup.
From this point onwards, X can only be instantiated to an integer. Everything else will yield a type error.
For example:
?- X in inf..sup, X = 3.
X = 3.
?- X in inf..sup, X = a.
ERROR: Type error: `integer' expected, found `a' (an atom)
Declaratively, you can always replace a type error with silent failure, since no possible additional instantiation can make the program succeed if this error arises.
Thus, in case you prefer silent failure over this type error, you can obtain it with catch/3:
?- X in inf..sup, catch(X = a, error(type_error(integer,_),_), false).
false.
CLP(FD) constraints are tailor-made for integers, and let you express also further requirements for this specific domain in a convenient way.
Case-specific advice
Let us consider your specific example of get_first_int/2. First, let us rename it to list_first_integer/3 so that it is clear what each argument is, and also to indicate that we fully intend to use it in several directions, not just to "get", but also to test and ideally to generate lists and integers that are in this relation.
Second, note that this predicate is rather messy, since it impurely depends on the instantiation of the list and integer, a property which cannot be expressed in first-order logic but rather depends on something outside of this logic. If we accept this, then one quite straight-forward way to do what you primarily want is to write it as:
list_first_integer(Ls, I) :-
once((member(I0, Ls), integer(I0))),
I = I0.
This works as long as the list is sufficiently instantiated, which implicitly seems to be the case in your examples, but definitely need not be the case in general. For example, with fully instantiated lists, we get:
?- list_first_integer([a,b,c], I).
false.
?- list_first_integer([a,b,c,4], I).
I = 4.
?- list_first_integer([a,b,c,4], 3).
false.
In contrast, if the list is not sufficiently instantiated, then we have the following major problems:
?- list_first_integer(Ls, I).
nontermination
and further:
?- list_first_integer([X,Y,Z], I).
false.
even though a more specific instantiation succeeds:
?- X = 0, list_first_integer([X,Y,Z], I).
X = I, I = 0.
Core problem: Defaulty representation
The core problem is that you are reasoning here about defaulty terms: A list element that is still a variable may either be instantiated to an integer or to any other term in the future. A clean way out is to design your data representation to symbolically distinguish the possible cases. For example, let us use the wrapper i/1 to denote an integer, and o/1 to denote any other kind of term. With this representation, we can write:
list_first_integer([i(I)|_], I).
list_first_integer([o(_)|Ls], I) :-
list_first_integer(Ls, I).
Now, we get correct results:
?- list_first_integer([X,Y,Z], I).
X = i(I) ;
X = o(_12702),
Y = i(I) ;
X = o(_12702),
Y = o(_12706),
Z = i(I) ;
false.
?- X = i(0), list_first_integer([X,Y,Z], I).
X = i(0),
I = 0 ;
false.
And the other examples also still work, if we only use the clean data representation:
?- list_first_integer([o(a),o(b),o(c)], I).
false.
?- list_first_integer([o(a),o(b),o(c),i(4)], I).
I = 4 ;
false.
?- list_first_integer([o(a),o(b),o(c),i(4)], 3).
false.
The most general query now allows us to generate solutions:
?- list_first_integer(Ls, I).
Ls = [i(I)|_16880] ;
Ls = [o(_16884), i(I)|_16890] ;
Ls = [o(_16884), o(_16894), i(I)|_16900] ;
Ls = [o(_16884), o(_16894), o(_16904), i(I)|_16910] ;
etc.
The price you have to pay for this generality lies in these symbolic wrappers. As you seem to care about correctness and also about generality of your code, I consider this a bargain in comparison to more error prone defaulty approaches.
Synthesis
Note that CLP(FD) constraints can be naturally used together with a clean representation. For example, to benefit from more finely grained type errors as explained above, you can write:
list_first_integer([i(I)|_], I) :- I in inf..sup.
list_first_integer([o(_)|Ls], I) :-
list_first_integer(Ls, I).
Now, you get:
?- list_first_integer([i(a)], I).
ERROR: Type error: `integer' expected, found `a' (an atom)
Initially, you may be faced with a defaulty representation. In my experience, a good approach is to convert it to a clean representation as soon as you can, for the sake of the remainder of your program in which you can then distinguish all cases symbolically in such a way that no ambiguity remains.

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
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 instantiation-error 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 program-slicing and logical-purity.

Building a base 2 exponent calculator in Prolog

log2(I,E):-
I is 2.0**E,
E is log(I)/log(2).
I am trying to use Prolog to compute either the power 2 was raised to 'I' or 2 raised to the 'E' power equals 'I'. I am extremely new to this language and from my understanding it infers the answer based on the information provided.
Queries:
log2(I,3).
-->false.
log2(I,3.0).
-->I = 8.0.
log2(8,E).
-->ERROR: is/2: Arguments are not sufficiently instantiated
log2(8,E).
-->ERROR: is/2: Arguments are not sufficiently instantiated
I'm confused why I have to provide a float in the first circumstance to get the correct answer and why Prolog is unable to infer the answer from the second circumstance at all.
What you have there is a conjunction. In Prolog, a conjunction a, b means:
Evaluate a, and if it succeeds, evaluate b.
You are trying to do something else, maybe:
Try a, and if it doesn't succeed, try b.
The first thing you should consider is using library(clpr), if it is available in your Prolog implementation.
With SWI-Prolog:
?- use_module(library(clpr)).
true.
?- {I = 2^3}.
I = 8.0 ;
false.
?- {8 = 2^E}.
E = 3.0 ;
false.
You literally have no problem any more.
If this is not an option, you need to do something along these lines:
log2(I, E) :-
( number(I)
-> E is /* expression here, now that I is a number */
; number(E)
-> I is /* expression here, now that E is a number */
; /* what do you do if both are variables? */
).
Note that X is Expr will work even if Expr is an expression and not a number. If you want to allow this, then you need to maybe try eval(Expr) first and catch the error or something along these lines.

Generic prolog cryptarithmetic program

I'm trying to write a program to solve general cryptarithmetic puzzles such as AM+PM=DAY, SEND+MORE=MONEY..
The program I've written is:
gsolve([H1,T1],[H2|T2],[H3|T3]):-
gsolvehelper([H1,T1],[H2|T2],[H3|T3],[0,1,2,3,4,5,6,7,8,9],0).
gsolvehelper([H1,T1],[H2|T2],[H3|T3],D,C):-
( var(H1)->select(H1,D,D1);D1=D),
( var(H2)->select(H2,D1,D2);D2=D1),
( X1 is H1+H2+C),
( H3 is mod(X1,10)),
( C1 is X1//10),
gsolvehelper(T1,T2,T3,D2,C1).
The input is of the form:
gsolve([A,M],[P,M],[D,A,Y]).
The head of the first two lists is added to the carry to find the head of the third list and the new carry and so on.
The error I get is:
ERROR: is/2: Type error: `[]' expected, found `[2,_G3922]' ("x" must hold one character)
I cannot figure out what this error is. Can someone please help me with this?
The error you report is due to what is probably a typo: [H1,T1], appearing in several places. Due to this typo H2 gets -- unintentionally -- instantiated to a list, causing problems in the summation statement. The following reproduces the error in SWI7:
?- X is 1 + [1,_] + 3.
ERROR: is/2: Type error: `[]' expected, found `[1,_G11068]' (a list) ("x" must hold one character)
There are other ways in which you can improve your code:
Since you simply pass on the arguments of gsolve/3 you do not need to use the head/tail-notation [H|T] here.
You can simply name your second predicate gsolve/5, as it is already different from gsolve/3 due to its arity.
Several brackets in bsolve/5 are superfluous. Spacing around the if/then operators can be improved as well.
Using the combination of mod/2 and ///2 may introduce problems since the rounding of ///2 (i.e., towards zero, typically at least...) is not consistent with mod/2. Use div/2 (rounding towards negative infinity) instead.
Making alterations based upon the above I get:
gsolve(L1, L2, L3):-
gsolve(L1, L2, L3, [0,1,2,3,4,5,6,7,8,9], 0).
gsolve([H1|T1], [H2|T2], [H3|T3], D, C):-
( var(H1)
-> select(H1, D, D1)
; D1 = D
),
( var(H2)
-> select(H2, D1, D2)
; D2=D1
),
X1 is H1 + H2 + C,
H3 is mod(X1, 10),
C1 is div(X1, 10),
gsolve(T1, T2, T3, D2, C1).
This does not solve the puzzle yet... However, since it solves the error you mentioned -- and some other things as well -- you should be able to take it on from here.

Resources