logic in prolog language - prolog

I have a question in prolog here is the code:
sound(time1).
sound(time2).
sun(time3).
relax(X):-
not(sound(X)),
!,
sun(X).
relax(_):-
sun(_).
now I an running - relax(T). I get true when I run relax(F) I get true also. Why does it happen?
and one more question, why relax(time4). also gets false? I think I am missing something.
thanks a lot!

The fact that relax(T) and relax(F) both give the same result, is normal: uppercase identifiers are variables. So the two queries are semantically the same: you query with an ungrounded variable.
Now why do we get true.? If you query relax(T), Prolog will first call the first clause of relax(X).
The first clause has a body that starts with not(sound(X)). So we actually query not(sound(T)). Not is satisfied by the negation as finite failure principle: Prolog will aim to "prove" sound(T), and if that fails (it cannot find a way to satisfy that query).
So now Prolog queries sound(T), and this query is satisfied: indeed, sound(time1) satisfies this query, since Prolog reasons that now T = time1. As a result not(sound(T)) is false, and thus Prolog backtracks.
Now Prolog will try the next clause: relax(_) :- sun(_). The _ is a "wildcard" or "don't care" variable. Furthermore if you use multiple _s in the same clause, those are not related. So you basically say: everything is relax/1, given there is at least one sun/1. So now Prolog will query for a sun(_). This query succeeds: sun(time3) is a valid candidate, since _ = time3. So that means that relax(_) succeeds. We did not alter the variable T (or F), so Prolog can only say that the query is true.
Now if we query relax(time4), that's a different story. Again Prolog will first try to satisfy the first clause of relax/1. This is again done by calling not(sound(time4)). But note that time4 is a constant. And in Prolog all constants are different: so time1 and time4 cannot unify.
So now Prolog first aims to unify sound(time1) (first clause for sound/1) with sound(time4), but since time1 and time4 are different, that fails. Next it aims to unify sound(time2) (second clause of sound/1) with sound(time4), but again no luck. Now there are no clauses of sound/1 anymore. So Prolog gives up and considers not(sound(time4)) to be true.
That means that Prolog will continu in the body of the first clause of relax/1. The next statement is a !, that is a "cut" in Prolog. It means that Prolog should, for this branching point - no longer consider the remaining clauses. So it will from now on, ignore the second clause of relax/1. Next it encounters sun(X). So now Prolog will call sun(time4) and aim to satisfy this. It will aim to unify with the first (and only) clause of sun/1: sun(time3). But as said before, time3 and time4 do not unify. So as a result, that fails. Since Prolog cannot take the second clause of relax/1 (due to the cut (!)), it thus has exhausted all the options, and decides that the query relax(time4) is false.

Related

Prolog single-variable query returns an error. Why?

I've created a simple Prolog program (using GNU Prolog v1.4.4) with a single fact:
sunny.
When I run the following query:
sunny.
I get:
yes
As I'd expect. When I run this query:
X.
I get:
uncaught exception: error(instantiation_error,top_level/0)
when I expected to get:
X = sunny
Anyone know why?
Prolog is based on first-order logic but X is a second order logic query (the variable stands for a rule head / fact, not only a term): you ask "which predicates can be derived?" or in other words "which formulas are true?". Second order logic is so expressive that we lose many nice properties of first-order logic (*). That's why a second order variable must be sufficiently instantiated to know which rule to try at the time it is called (that's what the error message means). For instance the queries
?- X=member(A,[1,2,3]), X.
and
?- member(A,[1,2,3]).
still allow Prolog to try the definition of the member predicate (in fact the two definitions are equivalent) but
?- X, X=member(A,[1,2,3]).
will throw an exception because at the time X should be derived, we don't know that it's supposed to become the predicate member(A,[1,2,3]).
Your case is much simpler though: you can wrap sunny as a term into a predicate such that Prolog knows which rules to try. The facts
weather(sunny).
weather(rainy).
define the predicate weather such that now we only have a first-order variable as argument in our query:
?- weather(X).
X = sunny ;
X = rainy.
Now that we are talking about the term level, everything works as you expected.
(*) Although the problem of finding out if a formula is valid is undecidable in both cases, in first order logic at least all true formulas can be eventually derived but if a formula is false, the search might not terminate (i.e. first-order logic is semi-decidable). For second order logic there are formulas that can neither be proved not disproved. What is worse is that we cannot even tell if a second-order formula belongs to this category.

SWI-Prolog: Understanding Infinite Loops

I am currently trying to understand the basics of prolog.
I have a knowledge base like this:
p(a).
p(X) :- p(X).
If I enter the query p(b), the unification with the fact fails and the rule p(X) :- p(X) is used which leads the unification with the fact to fail again. Why is the rule applied over and over again after that? Couldn't prolog return false at this point?
After a certain time I get the message "Time limit exceeded".
I'm not quite sure why prolog uses the rule over and over again, but since it is, I don't understand why I get a different error message as in the following case.
To be clear, I do understand that "p(X) if p(X)" is an unreasonable rule, but I would like to understand what exactly happens there.
If I have a knowledge base like this:
p(X) :- p(X).
p(a).
There is no chance to come to a result even with p(a) because the fact is below the rule and the rule is called over and over again. For this variant I receive a different error message almost instantly "ERROR: Out of local stack" which is comprehensible.
Now my question - what is the difference between those cases?
Why am I receiving different error messages and why is prolog not returning false after the first application of the rule in the above case? My idea would be that in the above case the procedure is kind of restarted each time the rule gets called and in the below case the same procedure calls the rule over and over again. I would be grateful if somebody could elaborate this.
Update: If I query p(a). to the 2nd KB as said I receive "Out of local stack", but if I query p(b). to the same KB I get "Time limit exceeded". This is even more confusing to me, shouldn't the constant be irrelevant for the infinite loop?
Let us first consider the following program fragment that both examples have in common:
p(X) :- p(X).
As you correctly point out, it is obvious that no particular solutions are described by this fragment in isolation. Declaratively, we can read it as: "p(X) holds if p(X) holds". OK, so we cannot deduce any concrete solution from only this clause.
This explains why p(b) cannot hold if only this fragment is considered. Additionally, p(a) does not imply p(b) either, so no matter where you put the fact p(a), you will never derive p(b) from these two clauses.
Procedurally, Prolog still attempts to find cases where p(X) holds. So, if you post ?- p(X). as a query, Prolog will try to find a resolution refutation, disregarding what it has "already tried". For this reason, it will try to prove p(X) over and over. Prolog's default resolution strategy, SLDNF resolution, keeps no memory of which branches have already been tried, and also for this reason can be implemented very efficiently, with little overhead compared to other programming languages.
The difference between an infinite deduction attempt and an out of local stack error error can only be understood procedurally, by taking into account how Prolog executes these fragments.
Prolog systems typically apply an optimization that is called tail call optimization. This is applicable if no more choice-points remain, and means that it can discard (or reuse) existing stack frames.
The key difference between your two examples is obviously where you add the fact: Either before or after the recursive clause.
In your case, if the recursive clause comes last, then no more choice-points remain at the time the goal p(X) is invoked. For this reason, an existing stack frame can be reused or discarded.
On the other hand, if you write the recursive clause first, and then query ?- q(X). (or ?- q(a).), then both clauses are applicable, and Prolog remembers this by creating a choice-point. When the recursive goal is invoked, the choice-point still exists, and therefore the stack frames pile up until they exceed the available limits.
If you query ?- p(b)., then argument indexing detects that p(a) is not applicable, and again only the recursive clause applies, independent of whether you write it before or after the fact. This explains the difference between querying p(X) (or p(a)) and p(b) (or other queries). Note that Prolog implementations differ regarding the strength of their indexing mechanisms. In any case, you should expect your Prolog system to index at least on the outermost functor and arity of the first argument. If necessary, more complex indexing schemes can be constructed manually on top of this mechanism. Modern Prolog systems provide JIT indexing, deep indexing and other mechanisms, and so they often automatically detect the exact subset of clauses that are applicable.
Note that there is a special form of resolution called SLG resolution, which you can use to improve termination properties of your programs in such cases. For example, in SWI-Prolog, you can enable SLG resolution by adding the following directives before your program:
:- use_module(library(tabling)).
:- table p/1.
With these directives, we obtain:
?- p(X).
X = a.
?- p(b).
false.
This coincides with the declarative semantics you expect from your definitions. Several other Prolog systems provide similar facilities.
It should be easy to grasp the concept of infinite loop by studying how standard repeat/0 is implemented:
repeat.
repeat :- repeat.
This creates an infinite number of choice points. First clause, repeat., simply allows for a one time execution. The second clause, repeat :- repeat. makes it infinitely deep recursion.
Adding any number of parameters:
repeat(_, _, ..., _).
repeat(Param1, Param2, ..., ParamN) :- repeat(Param1, Param2, ..., ParamN).
You may have bodies added to these clauses and have parameters of the first class having meaningful names depending on what you are trying to archive. If bodies won't contain cuts, direct or inherited from predicates used, this will be an infinite loop too just as repeat/0.

Logical OR in Prolog

I´m new in Prolog learning and tried out a logical OR-operator for that context:
%a.
b.
foo:- a ; b.
I have commented a. to try out the logical OR-Operator but it does not work. If you query with ?-foo. you get an exception. Prolog only checks the first term but not the second. Can anyone help me please?
Best regards.
You get the exception as a/0 is undefined. In order to check the or-operator you could explicitely define a as being false.
a:-false.
b.
foo:- a ; b.
Now ?- foo. gives the answer true.
Prolog makes a 'closed world' assumption. It can only evaluate the trueness or falseness of a predicate that is defined. That means that you need at least one clause that has the predicate on its left hand side (or a fact, as this will be interpreted as a clausel with no condition thus without a right hand side).
This is essentially equivalent to:
foo :- a.
foo :- b.
The first clause tries to assess whether foo is true or not, by evaluating whether a is true or not. a doesn't even exist in the database, therefore you get an error.

Commutativity of disjunction in Prolog

I've just started learning Prolog and I encountered a problem that I don't understand.
When I ask:
?- fail; true.
Prolog answers:
true
Which is something I expected. But, if I ask:
?- true; fail.
Prolog answers:
true ;
false.
..and I don't understand why. The disjunction operator should be commutative. Why are these two Prolog answers different?
Also note that the Prolog disjunction operator, (;)/2, is not commutative in general. For example:
?- !; write(else).
true.
?- write(then); !.
then
true ;
true.
The right branch of the disjunction is only tried on backtracking if the implicit choice point is not cut when executing the left branch. Note that a clause such as:
foo :- (!; write(else)).
is equivalent to:
foo :- !.
foo :- write(else).
Thus, cuts and (other) side-effects result in (;)/2 not behaving as logical disjunction.
it's just a detail of top level interaction, then you could observe a different behaviour depending on Prolog interpreter you're using.
SWI-Prolog, in introductory documentation, gives some information:
2.1.2 Executing a query
After loading a program, one can ask Prolog queries about the program. The query below asks Prolog what food `sam' likes. The system responds with X = if it can prove the goal for a certain X. The user can type the semi-colon (;) or spacebar6 if (s)he wants another solution. Use the return key if you do not want to see the more answers. Prolog completes the output with a full stop (.) if the user uses the return key or Prolog knows there are no more answers. If Prolog cannot find (more) answers, it writes false.
The confusion regards how prolog displays results. When you make a query in prolog, it will attempt to find all possible answers. That means it will start at the first fact or clause, go through them sequentially and, when it can finally make the query true, displays the answer. If there was a choice point in the process of finding the last solution, prolog prompts the user to seek more possible successful solutions.
In the case of:
?- false ; true.
This query starts by looking at the clause false, which fails and then, since there's a disjunction ;, checks the clause after the ; which is true. This succeeds, and prolog displays:
true
Note that when it found this solution, there were no more choices, so there's no prompt for further solutions.
Now let's look at the second example:
?- true ; false.
Prolog looks at the first clause, true, and succeeds and tells the user:
true
But in this case, it hasn't exhausted all of the possible solutions since there's a disjunction ; that created another choice. So when you enter the ; at the prompt:
true ;
You tell prolog to find more solutions. Prolog goes back and checks the clause after the disjunction and encounters false. This fails and there are no other solutions. Therefore, your request for further solutions fails and prolog outputs false:
true ;
false
The first true means it succeeded. The false means it found no more solutions and failed on the second attempt.
Prolog's behavior is to seek solutions sequentially through the appropriate clauses and present them as long as you ask for them until it fails. When it finally fails, you get false. Some prologs output no. The behavior above is not a commutativity issue.

prolog cut off in method

I have a question I would like to ask you something about a code snippet:
insert_pq(State, [], [State]) :- !.
insert_pq(State, [H|Tail], [State, H|Tail]) :-
precedes(State, H).
insert_pq(State, [H|T], [H|Tnew]) :-
insert_pq(State, T, Tnew).
precedes(X, Y) :- X < Y. % < needs to be defined depending on problem
the function quite clearly adds an item to a priority queue. The problem I have is the cut off operator in the first line. Presumably whenever the call reaches this line of code this is the only possible solution to the query, and the function calls would simply unwind (or is it wind up?), there would be no need to back track and search for another solution to the query.
So this cut off here is superfluous. Am I correct in my deduction?
Yes, any half-decent Prolog compiler will notice that there is no other clause where the second argument is an empty list.
It would be more useful at the end of the second clause, though I'd rather combine the second and the third clause and use a local cut (precedes(...) -> ... ; ...).
The particular technique that the compiler users to eliminate candidate predicates for matching is called argument indexing. Different prolog implementations could potentially index different numbers of arguments by default.
So if you're worried about whether an argument is being indexed or not, you should check how many arguments the prolog you're using indexes. According to the SWI reference manual it only indexes the first argument by default. So in your case the cut is actually not redundant. You can however explicitly stipulate which arguments should be indexed using the predicates index/1 and hash/1 which are linked to in the above link.
Or you could just reorder the arguments, or you could just keep the cut.
Yes, you are correct. Even if the compiler isn't half-decent (which SWI Prolog certainly is), the worst it can do is match the second and third clauses, which will fail immediately.
However, if the second clause matches, the third does as well. Is this the intended behaviour?

Resources