How to check if variable is instantiated in Prolog? - prolog

I need to know if variable is instantiated in a given rule, yet I'm not allowed to use var(X), and have no clue on how to do so.
To be specific, my rule gets 4 parameter (P, A, B, C).
If P, A, B, C are instantiated then my rule should "return" true iff (A+B)mod(P)=C(mod(P)).
If one of A B and C isn't isntantiated I should return what value of it will guarantee that (A+B)mod(P)=C(mod(P)). so for example if C isn't instantiated the rule should "return" (A+B)mod(P) as C, and similar behavoir if A or B are not instantiated. Writing each rule is easy, but how can I know which of the cases I'm at if I don't know whther a variable is instantiated or not? as mentioned before, I can't use var(X) or number(X) and so on, I can only assume that P is always instantiated.
Thanks in advance!

I think #mat answer is definitely the way to go to solve your problem.
However, if you want to check whether a variable is not instantiated without using builtin predicate var/1 which does exactly that (due to some restriction, e.g. your teacher explicitly prohibited it) you may use double negation twice to test for the ability to bound a variable without really instantiating it if it is not bound:
not_inst(Var):-
\+(\+(Var=0)),
\+(\+(Var=1)).
Test cases:
?- not_inst(X).
true.
?- not_inst(a).
false.

Testing manually whether or not something is instantiated makes it very hard to correctly handle all cases that can arise in practice. Almost invariably, your resulting code will behave incorrectly for certain instantiation patterns you have not thought about.
Luckily, there is a declarative solution for such problems: Constraints work correctly in all cases, no matter what is instantiated and what is not.
For example, use your Prolog system's CLP(FD) constraints to solve your task:
:- use_module(library(clpfd)).
same_sum_mod(A, B, C, P) :-
(A+B) mod P #= C mod P.
It works correctly in all directions, for example:
?- same_sum_mod(1, 2, 3, 3).
true.
?- same_sum_mod(1, B, 3, 2).
1+B#=_G823,
_G823 mod 2#=1.
?- same_sum_mod(1, 2, 3, P).
P in inf..-1\/1..sup,
3 mod P#=_G855,
3 mod P#=_G855.
And also check out the following case, where B is initially not instantiated, but its domain is known, and the constraint solver can deduce the single admissible solution:
?- B in 0..1, same_sum_mod(1, B, 3, 2).
B = 0.
Such cases cannot be handled by simple instantiation checks, but require reasoning about constraints.
See clpfd for more information about CLP(FD) constraints.

Related

Prolog - Infinite loop with very basic rule definition

I was trying to practice Prolog, as suggested by my TA, I am trying to create the rule append3(A,B,C,D) which means D is the result of the append of A,B and C.
The definition of append(A,B,C) is given
append([],B,B).
append([X|A],B,[X|C]):-append(A,B,C).
So I simply wrote following, which makes sense to me, as the rule for append3
append3(A,B,C,D) :- append(A,B,X),append(X,C,D).
After, I tried some query, such as append3(A,B,C,[1,2,3]). Everything was fine in the beginning, it was giving me the right results. However, at one moment, I pressed ;, it went into an infinite loop trying to search another answer.
I am not really sure why this happens? I suppose that append3(A,B,C,D) is a very basic rule to define. Is there anything that I am missing or that I didn't consider?
How can I fix this problem?
Prolog's execution mechanism is pretty complex compared to command oriented programming languages a.k.a. imperative languages (short form: imps). Your TA has given you an excellent example where you can improve your mastery of Prolog.
First of all, you need to understand the termination behavior of append/3. The best way is via a failure-slice which helps you focus on the part that is relevant to termination. In this case it is:
append([],B,B) :- false.
append([X|A],B,[X|C]):-append(A,B,C), false.
This fragment or failure slice now terminates exactly in all cases where your original definition terminates! And since it is shorter, it makes understanding of termination a bit easier. Of course, this new program will no longer find answers like for append([a],[b],[a,b]) — it will fail in stead. But for termination alone it's perfect.
Now let's go through the arguments one by one:
argument needs to have a non-empty list element and will fail (and terminate) should the argument be [] or any other term. Non-termination may only occur with a partial list (that's a list with a variable instead of [] at the end like [a,b|L]) or just a variable.
argument is just the variable B. There is no way how this B might be different to any term. Thus, B has no influence on termination at all. It is termination neutral.
argument is essentially the same as the first argument. In fact, those arguments look quite symmetrical although they describe different things.
To summarize, if the first or the last argument is a (fully instantiated) list, append/3 will terminate.
Note that I just said if and not iff. After all, the first and third argument are a bit connected to each other via the variable X. Let's ignore that for this analysis.
Now, to a failure slice of your definition.
append3(A,B,C,D) :- append(A,B,X), false, append(X,C,D).
Note that D does no longer occur in the visible part! Therefore, the fourth argument has no influence on termination of this fragment. And since X occurs for the first time, only A has an influence on its termination. Therefore, if A is just a variable (or a partial list), the program will not terminate! No need to look any further. No need to look at screens full of traces.
To fix this for a query like your query append3(A,B,C,[1,2,3])., D has to influence the first goal somewhat.
One possible fix suggested by another answer would be to exchange the goals:
append3(A,B,C,D) :- append(X,C,D), false, append(A,B,X).
Let's look at the variables of append(X,C,D)! C is termination neutral, X occurs for the first time and thus has no influence on termination at all. Only D may make this goal terminate. And thus queries like append3([1],[2],[3], D) will now loop! What a bargain, exchanging non-termination in one case for another!
To make your program work for both cases, the first goal of append/3 must contain both D and at least one of A, B or C. Try to find it yourself! Here is the spoiler:
append3(A, B, C, D) :- append(A, BC, D), append(B, C, BC).
Now the first goal terminates if either A or D is a (fully instantiated) list. The second goal requires either B or BC to be a list. And BC comes from the first goal, which is a list if D is one.
Thus append3(A, B, C, D) terminates_if b(A), b(B) ; (D).
See another answer for more on termination, failure slices, and a technique I have not mentioned here, which is termination inference.
And, note that there are still more cases where the definitions terminate, although they are rather obscure like append([a|_],_,[b|_]) or append3([a|_],_,_,[b|_])) which both fail (and thus terminate) although they only have partial lists. Because of this it's terminates_if and not terminates_iff.
You need to flip the predicates append(A, B, X), append(X, C, D). Since all three variables A, B, and X are unbound in append(A, B, X) prolog tries to satisfy it and then constrain it with append(X, C, D) which will always fail after giving you existing solutions. So it enters an infinite loop.
Try just executing append(A, B, X). all of them unbound. Prolog should show you an infinite sequence of solutions, these fail in the next clause append(X, C, D).
Flip the predicates and you should be fine.
append3(A, B, C, D) :-
append(T, C, D),
append(A, B, T).

Prolog CLPFD Transitivity

"Obvious" is not a word lightly bandied about, but why does SWI-Prolog's CLPFD correctly solve this:
?- A+1 #= A*2.
A = 1.
but not this:
?- B #= A + 1, B #= A * 2.
A+1#=B,
A*2#=B.
(label and indomain yield Arguments are not sufficiently instantiated.)
Is it just...the solver doesn't catch that case? (I'd sure have expected it to apply transitivity.) Or is it a symptom of some deeper syntactic conundrum, or something?
It tries to solve the constraint from the values in the domain of each variable! As the domain of B and A is infinite and not bound, backtracking over a constraint satisfaction will be delayed and the program is stopped.
It means it tries to find some solution for the constraint B #= A + 1, but it finds many (infinite values for A and B) and also the same for the second constraint. Hence it will be stopped here as the possible values of A and B are infinite. However, the result is not No. It is Yes with 2 delayed goals.
B = B{-1.0Inf .. 1.0Inf}
A = A{-1.0Inf .. 1.0Inf}
There are 2 delayed goals.
To solve this, you need to bound at least one of the A or B. For example, if you run this query A::1..1000, B#=A+1, B #= A*2., you will get the same result as for the first query in your examples. And also, there is not any deduction in clpfd to resolve the transitivity as it uses from the backtracking method.
In sum, it is one of the shortcomings of the library that you are using, as it will be stopped when the domain of a constraint with more than one variable has an infinite domain and you can solve it by setting a bounded domain for at least one of the variables.

Duplicate constraints in CLP(FD) and with dif/2

In SWI-Prolog, the following query gives this result:
?- X mod 2 #= 0, X mod 2 #= 0.
X mod 2#=0,
X mod 2#=0.
While correct, there is obviously no need for the second constraint
Similarly:
?- dif(X,0), dif(X,0).
dif(X, 0),
dif(X, 0).
Is there no way to avoid such duplicate constraints? (Obviously the most correct way would be to not write code that leads to that situation, but it is not always that easy).
You can either avoid posting redundant constraints, or remove them with a setof/3-like construct. Both are very implementation specific. The best interface for such purpose is offered by SICStus. Other implementations like YAP or SWI more or less copied that interface, by leaving out some essential parts. A recent attempt to overcome SWI's deficiencies was rejected.
Avoid posting constraints
In SICStus, you can use frozen/2 for this purpose:
| ?- dif(X,0), frozen(X,Goal).
Goal = prolog:dif(X,0),
prolog:dif(X,0) ? ;
no
| ?- X mod 2#=0, frozen(X, Goal).
Goal = clpfd:(X in inf..sup,X mod 2#=0),
X mod 2#=0,
X in inf..sup ? ;
no
Otherwise, copy_term/3 might be good enough, provided the constraints are not too much interconnected with each other.
Eliminate redundant constraints
Here, a setof-like construct together with call_residue_vars/1 and copy_term/3 is probably the best approach. Again, the original implementation is in SICStus....
For dif/2 alone, entailment can be tested without resorting to any internals:
difp(X,Y) :-
( X \= Y -> true
; dif(X, Y)
).
Few constraint programming systems implement contraction also related to factoring in resolution theorem proving, since CLP labeling is not SMT. Contraction is a structural rule, and it reads as follows, assuming constraints are stored before the (|-)/2 in negated form.
G, A, A |- B
------------ (Left-Contraction)
G, A |- B
We might also extend it to the case where the two A's are derivably equivalent. Mostlikely this is not implemented, since it is costly. For example Jekejeke Minlog already implements contraction for CLP(FD), i.e. finite domains. We find for queries similar to the first query from the OP:
?- use_module(library(finite/clpfd)).
% 19 consults and 0 unloads in 829 ms.
Yes
?- Y+X*3 #= 2, 2-Y #= 3*X.
3*X #= -Y+2
?- X #< Y, Y-X #> 0.
X #=< Y-1
Basically we normalize to A1*X1+..+An*Xn #= B respectively A1*X1+..+An*Xn #=< B where gcd(A1,..,An)=1 and X1,..,Xn are lexically ordered, and then we check whether there is already the same constraint in the constraint store. But for CLP(H), i.e. Herbrand domain terms, we have not yet implemented contraction. We are still deliberating an efficient algorithm:
?- use_module(library(term/herbrand)).
% 2 consults and 0 unloads in 35 ms.
Yes
?- neq(X,0), neq(X,0).
neq(X, 0),
neq(X, 0)
Contraction for dif/2 would mean to implement a kind of (==)/2 via the instantiation defined in the dif/2 constraint. i.e. we would need to apply a recursive test following the pairing of variables and terms defined in the dif/2 constraint against all other dif/2 constraints already in the constraint store. Testing subsumption instead of contraction would also make more sense.
It probably is only feasible to implement contraction or subsumption for dif/2 with the help of some appropriate indexing technique. In Jekejeke Minlog for example for CLP(FD) we index on X1, but we did not yet realize some indexing for CLP(H). What we first might need to figure out is a normal form for the dif/2 constraints, see also this problem here.

Prolog and limitations of backtracking

This is probably the most trivial implementation of a function that returns the length of a list in Prolog
count([], 0).
count([_|B], T) :- count(B, U), T is U + 1.
one thing about Prolog that I still cannot wrap my head around is the flexibility of using variables as parameters.
So for example I can run count([a, b, c], 3). and get true. I can also run count([a, b], X). and get an answer X = 2.. Oddly (at least for me) is that I can also run count(X, 3). and get at least one result, which looks something like X = [_G4337877, _G4337880, _G4337883] ; before the interpreter disappears into an infinite loop. I can even run something truly "flexible" like count(X, A). and get X = [], A = 0 ; X = [_G4369400], A = 1., which is obviously incomplete but somehow really nice.
Therefore my multifaceted question. Can I somehow explain to Prolog not to look beyond first result when executing count(X, 3).? Can I somehow make Prolog generate any number of solutions for count(X, A).? Is there a limitation of what kind of solutions I can generate? What is it about this specific predicate, that prevents me from generating all solutions for all possible kinds of queries?
This is probably the most trivial implementation
Depends from viewpoint: consider
count(L,C) :- length(L,C).
Shorter and functional. And this one also works for your use case.
edit
library CLP(FD) allows for
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :- U #>= 0, T #= U + 1, count(B, U).
?- count(X,3).
X = [_G2327, _G2498, _G2669] ;
false.
(further) answering to comments
It was clearly sarcasm
No, sorry for giving this impression. It was an attempt to give you a synthetic answer to your question. Every details of the implementation of length/2 - indeed much longer than your code - have been carefully weighted to give us a general and efficient building block.
There must be some general concept
I would call (full) Prolog such general concept. From the very start, Prolog requires us to solve computational tasks describing relations among predicate arguments. Once we have described our relations, we can query our 'knowledge database', and Prolog attempts to enumerate all answers, in a specific order.
High level concepts like unification and depth first search (backtracking) are keys in this model.
Now, I think you're looking for second order constructs like var/1, that allow us to reason about our predicates. Such constructs cannot be written in (pure) Prolog, and a growing school of thinking requires to avoid them, because are rather difficult to use. So I posted an alternative using CLP(FD), that effectively shields us in some situation. In this question specific context, it actually give us a simple and elegant solution.
I am not trying to re-implement length
Well, I'm aware of this, but since count/2 aliases length/2, why not study the reference model ? ( see source on SWI-Prolog site )
The answer you get for the query count(X,3) is actually not odd at all. You are asking which lists have a length of 3. And you get a list with 3 elements. The infinite loop appears because the variables B and U in the first goal of your recursive rule are unbound. You don't have anything before that goal that could fail. So it is always possible to follow the recursion. In the version of CapelliC you have 2 goals in the second rule before the recursion that fail if the second argument is smaller than 1. Maybe it becomes clearer if you consider this slightly altered version:
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :-
T #> 0,
U #= T - 1,
count(B, U).
Your query
?- count(X,3).
will not match the first rule but the second one and continue recursively until the second argument is 0. At that point the first rule will match and yield the result:
X = [_A,_B,_C] ?
The head of the second rule will also match but its first goal will fail because T=0:
X = [_A,_B,_C] ? ;
no
In your above version however Prolog will try the recursive goal of the second rule because of the unbound variables B and U and hence loop infinitely.

Prolog without if and else statements

I am currently trying to learn some basic prolog. As I learn I want to stay away from if else statements to really understand the language. I am having trouble doing this though. I have a simple function that looks like this:
if a > b then 1
else if
a == b then c
else
-1;;
This is just very simple logic that I want to convert into prolog.
So here where I get very confused. I want to first check if a > b and if so output 1. Would I simply just do:
sample(A,B,C,O):-
A > B, 1,
A < B, -1,
0.
This is what I came up with. o being the output but I do not understand how to make the 1 the output. Any thoughts to help me better understand this?
After going at it some more I came up with this but it does not seem to be correct:
Greaterthan(A,B,1.0).
Lessthan(A,B,-1.0).
Equal(A,B,C).
Sample(A,B,C,What):-
Greaterthan(A,B,1.0),
Lessthan(A,B,-1.0),
Equal(A,B,C).
Am I headed down the correct track?
If you really want to try to understand the language, I recommend using CapelliC's first suggestion:
sample(A, B, _, 1) :- A > B.
sample(A, B, C, C) :- A == B.
sample(A, B, _, -1) :- A < B.
I disagree with CappeliC that you should use the if/then/else syntax, because that way (in my experience) it's easy to fall into the trap of translating the different constructs, ending up doing procedural programming in Prolog, without fully grokking the language itself.
TL;DR: Don't.
You are trying to translate constructs you know from other programming languages to Prolog. With the assumption that learning Prolog means essentially mapping one construct after the other into Prolog. After all, if all constructs have been mapped, you will be able to encode any program into Prolog.
However, by doing that you are missing the essence of Prolog altogether.
Prolog consists of a pure, monotonic core and some procedural adornments. If you want to understand what distinguishes Prolog so much from other programming languages you really should study its core first. And that means, you should ignore those other parts. You have only so much attention span, and if you waste your time with going through all of these non-monotonic, even procedural constructs, chances are that you will miss its essence.
So, why is a general if-then-else (as it has been proposed by several answers) such a problematic construct? There are several reasons:
In the general case, it breaks monotonicity. In pure monotonic Prolog programs, adding a new fact will increase the set of true statements you can derive from it. So everything that was true before adding the fact, will be true thereafter. It is this property which permits one to reason very effectively over programs. However, note that monotonicity means that you cannot model every situation you might want to model. Think of a predicate childless/1 that should succeed if a person does not have a child. And let's assume that childless(john). is true. Now, if you add a new fact about john being the parent of some child, it will no longer hold that childless(john) is true. So there are situations that inherently demand some non-monotonic constructs. But there are many situations that can be modeled in the monotonic part. Stick to those first.
if-then-else easily leads to hard-to-read nesting. Just look at your if-then-else-program and try to answer "When will the result be -1"? The answer is: "If neither a > b is true nor a == b is true". Lengthy, isn't it? So the people who will maintain, revise and debug your program will have to "pay".
From your example it is not clear what arguments you are considering, should you be happy with integers, consider to use library(clpfd) as it is available in SICStus, SWI, YAP:
sample(A,B,_,1) :- A #> B.
sample(A,B,C,C) :- A #= B.
sample(A,B,_,-1) :- A #< B.
This definition is now so general, you might even ask
When will -1 be returned?
?- sample(A,B,C,-1).
A = B, C = -1, B in inf..sup
; A#=<B+ -1.
So there are two possibilities.
Here are some addenda to CapelliC's helpful answer:
When starting out, it is sometimes easy to mistakenly conceive of Prolog predicates functionally. They are either not functions at all, or they are n-ary functions which only ever yield true or false as outputs. However, I often find it helpful to forget about functions and just think of predicates relationally. When we define a predicate p/n, we're describing a relation between n elements, and we've named the relation p.
In your case, it sounds like we're defining conditions on an ordered triplet, <A, B, C>, where the value of C depends upon the relation between A and B. There are three relevant relationships between A and B (here, since we are dealing with a simple case, these three are exhaustive for the kind of relationship in question), and we can simply describe what value C should have in the three cases.
sample(A, B, 1.0) :-
A > B.
sample(A, B, -1.0) :-
A < B.
sample(A, B, some_value) :-
A =:= B.
Notice that I have used the arithmetical operator =:=/2. This is more specific than ==/2, and it lets us compare mathematical expressions for numerical equality. ==/2 checks for equivalence of terms: a == a, 2 == 2, 5+7 == 5+7 are all true, because equivalent terms stand on the left and right of the operator. But 5+7 == 7+5, 5+7 == 12, A == a are all false, since it are the terms themselves which are being compared and, in the first case the values are reversed, in the second we're comparing +(5,7) with an integer and in the third we're comparing a free variable with an atom. The following, however, are true: 2 =:= 2, 5 + 7 =:= 12, 2 + 2 =:= 4 + 0. This will let us unify A and B with evaluable mathematical expressions, rather than just integers or floats. We can then pose queries such as
?- sample(2^3, 2+2+2, X).
X = 1.0
?- sample(2*3, 2+2+2, X).
X = some_value.
CapelliC points out that when we write multiple clauses for a predicate, we are expressing a disjunction. He is also careful to note that this particular example works as a plain disjunction only because the alternatives are by nature mutually exclusive. He shows how to get the same exclusivity entailed by the structure of your first "if ... then ... else if ... else ..." by intervening in the resolution procedure with cuts. In fact, if you consult the swi-prolog docs for the conditional ->/2, you'll see the semantics of ->/2 explained with cuts, !, and disjunctions, ;.
I come down midway between CapelliC and SQB in prescribing use of the control predicates. I think you are wise to stick with defining such things with separate clauses while you are still learning the basics of the syntax. However, ->/2 is just another predicate with some syntax sugar, so you oughtn't be afraid of it. Once you start thinking relationally instead of functionally or imperatively, you might find that ->/2 is a very nice tool for giving concise expression to patterns of relation. I would format my clause using the control predicates thus:
sample(A, B, Out) :-
( A > B -> Out = 1.0
; A =:= B -> Out = some_value
; Out = -1.0
).
Your code has both syntactic and semantic issues.
Predicates starts lower case, and the comma represent a conjunction. That is, you could read your clause as
sample(A,B,C,What) if
greaterthan(A,B,1.0) and lessthan(A,B,-1.0) and equal(A,B,C).
then note that the What argument is useless, since it doesn't get a value - it's called a singleton.
A possible way of writing disjunction (i.e. OR)
sample(A,B,_,1) :- A > B.
sample(A,B,C,C) :- A == B.
sample(A,B,_,-1) :- A < B.
Note the test A < B to guard the assignment of value -1. That's necessary because Prolog will execute all clause if required. The basic construct to force Prolog to avoid some computation we know should not be done it's the cut:
sample(A,B,_,1) :- A > B, !.
sample(A,B,C,C) :- A == B, !.
sample(A,B,_,-1).
Anyway, I think you should use the if/then/else syntax, even while learning.
sample(A,B,C,W) :- A > B -> W = 1 ; A == B -> W = C ; W = -1.

Resources