How does negation-as-failure works in Prolog? - prolog

I want to know how Prolog solves this program:
test(X, Y).
test(X, X):-!, fail.
I googled "negation as failure" but I am confused!

Consider the following example:
father(nick, john).
We use the predicate father(X,Y) to denote that the father of X is Y.
Let's query the database:
?- father(nick,X).
X = john.
?- father(john,Y).
false.
In both cases we asked who is the father of someone (nick, john respectively). In the first case, prolog knew the answer (john) however in the second it didn't and so the answer was false, meaning that john does not have any father. We might expect that, as we gave prolog no information about john's father, it would respond with unknown. That would be an open-world where if something is not known we don't assume that it's false. On the contrary, in the closed world of prolog, if we don't know something, we assume that it's false.
Note that a world where we say that we don't know who the father of john is, based on knowing that anyone must have a father is not an open world; it can be easily modelled in prolog:
data_father(nick, john).
father(X,Y):-
data_father(X,Y) -> true ; true.
On the other hand, in an open world prolog you would write facts and counter facts:
father(nick, john).
not father(adam, X).
And this is negation as failure. However, this is not what happens in your program:
test(X, Y).
test(X, X):-!, fail.
The first clause will always succeed, regardless of the value of the arguments. In fact, exactly because of that, there is no point in naming the arguments and prolog will give you a singleton warning; you can write the clause as test(_, _).
On the other hand, the second clause will always fail. It can fail in two ways: (1) the arguments may be different (2) the arguments are unifiable so prolog moves to the body and then fails.
Precisely because prolog is using a closed world model there is no point of having clauses (without side-effects (but that's considered bad practise anyway)) that always fail. On the contrary, these extra calls cause your program to run slower and use more memory.
It is also worth noting that the cut (!/0) does nothing here since when you reach it there are no more choice points. Consider however this example:
test(X, Y).
test(X, X):-!, fail.
test(X, 42).
?- test(1,42).
true ;
true.
?- test(42,42).
true ;
false.
In both cases prolog will create 3 choice points, one for each clause.
In the first case, Prolog will successfully match the head of the first clause and succeed since there is no body.
Then, it will fail matching the head of the second clause and the body will not be "executed".
Finally, it will match the head of the third clause and succeed since there is no body.
However, on the second case:
Prolog will succeed in matching the head of the first clause and succeed since there is no body.
Then, it will succeed in matching the head of the second clause; the cut will remove all other choice points and then it will fail due to fail.
Therefore, prolog will not try the third clause.
A few words about negation as failure since you mentioned it. Negation as failure is based on the closed world assumption; since we assume that anything that cannot be deduced from the facts we already have is wrong, if we fail to prove something it means that the opposite of it is considered true. For example, consider this:
father(nick, john).
fatherless(X) :- \+ father(X, _).
And
?- fatherless(nick).
false.
?- fatherless(john).
true.
On the contrary, in an open world prolog with the following code:
father(nick, john).
not father(adam, X).
fatherless(X) :- \+ father(X, _).
fatherless/1 would succeed only for adam, fail for nick and return unknown for anything else

the first clause test(X, Y). says that test/2 is unconditionally true, for whatsoever argument pattern.
the second clause test(X, X):-!, fail. says that, when test/2 is called with unifiable first and second argument, there are not more alternative, then fail (note that will fail always, because argument schema is ruling out the instantiation pattern where first argument \= second implicitly).
The operational effect if the same as a logical negation, under 'Closed World Assumption'.

Related

Does Prolog's Cut predicate execute after a true/ yes call?

Say I have the following list of literals and a cut in my query:
?- c(X), d(X), e(X), !.
if X=1 evaluates all the literals to true, does the cut, !, predicate, at the end, get called anyway or can the whole thing backtrack?
From my own experience it seems like it can't backtrack, which implies the cut predicate is called even after true or yes has been found, is that accurate?
Yes; although I'm not sure what you are thinking of when you say
get called anyway
even though its name is an exclamation mark instead of a word and it does something outside normal logic, cut is "just another predicate" ("literal") in the sense that it gets called if execution gets to it. If c(X) holds for the current value of X then d(X) is called. If that holds then e(X) is called. If that holds then ! is called.
Using some low effort proxies for c d e:
?- member(X, [1,2,3,4,5]), write(X), X>2, write(X).
?- member(X, [1,2,3,4,5]), write(X), X>2, write(X), !.
The first line, member chooses a value for X and binds X=1, marks a choicepoint, writes 1, fails at X>2, backtracks to the choicepoint, rebinds X=2, tries again, fails again, backtracks to the choicepoint again, rebinds X=3, now all three succeed; Prolog gives you X = 3 as a solution and the choicepoint is still there so it waits for you to ask for more solutions or cancel. If you prompt for more, it backtracks to the choicepoint, binds X=4, tries again.
The second line does the same initially, but once it gets to X=3 the cut is called, the choicepoint from member() is removed and Prolog gives you X = 3 and finishes, no prompts. It has found a solution and pruned (cut) the search tree so it has not, and will not, explore for all possible solutions.
Since a Prolog program can have a lot of choicepoints happening, one "cut" will not remove all of them; exactly which ones are removed by any given ! is in #brebs' link.

Relationship between not found, dif, and \+

Conceptually what's the relationship between false, dif, and \+.
Given this program:
likes(john, mary).
What is being asked exactly when executing the query:
\+ like(john, A).
And why is the answer not:
dif(A, mary).
The more I think about it, the more I'm convinced that I don't understand the meaning of negation in Prolog.
\+ like(john, A)
(This is an malformed query if variable A behind the \+ is unbound at call time: floundering)
\+ is an operator that is defined procedurally:
prove the query on the right of \+
If it succeeds then fail.
In other words, "if you can't find evidence for it, assume it's false" aka. "default negation". An attitude taken in relational databases for one. It is basically a replacement for the problem that Prolog doesn't have strongly negated statements, but turns out to be a welcome extension that the philosophers of logic hadn't even come up with earlier.
dif(A, mary).
Is much simpler: "Make sure that A and mary do not unify on this branch of the computation". A constraint is set up that will cause unification of mary and A to fail, either immediately if A is already bound to mary or later. Compare with A \= mary which states that A and mary do not unification at the time this statement is encountered, and so is not really a "logic statement" at all.
I collected some notes on negation as failure and dif/2 which need to be reworked. Still useful.

Why do I get a Infinite Loop (Prolog)

I am just starting to learn Prolog and I played around with it. Now I got to a point where I´m stuck. The program i wrote gets into an infinite loop when I ask for
?- q(b).
and I don´t understand why it does that. It would be nice if someone could explain it to me.
p(a).
p(b).
q(Y) :- r(X), r(Y).
r(X) :- r(f(X)).
r(a) :- p(c).
r(a) :- p(a).
r(b) :- p(b).
As said in the comment, the loop is caused by r/1. To show why, yust type ?- trace, q(b). Look at the trace (ignore by now the singleton warning):
Call:q(b)
Call:r(_4244)
Call:r(f(_4162))
Call:r(f(f(_4162)))
Call:r(f(f(f(_4162))))
Call:r(f(f(f(f(_4162)))))
Call:r(f(f(f(f(f(_4162))))))
Call:r(f(f(f(f(f(f(_4162)))))))
Call:r(f(f(f(f(f(f(f(_4162))))))))
Now you can see that it try to derives r/1 entering a loop. You can see also this question to have a more in depth explaination.
Notice that in prolog, the order of the clauses matters. Just try to put the line r(X) :- r(f(X)). to the bottom of your program. Now try ?- q(b). On the first answer you get true because prolog unifies X with a and Y with b before entering in a loop.
Another way to identify reasons for non-termination is to reduce the number of inferences your program will execute by adding goals false into your program:
q(Y) :- r(X), false, r(Y).
r(X) :- r(f(X)), false.
r(a) :- false, p(c).
r(a) :- false, p(a).
r(b) :- false, p(b).
?- q(Y).
loops.
Since this program is still looping, you will need to modify something in the visible part. Note how many things have been removed entirely! No matter how p/1 is defined, this problem will persist.
If you look at q/1 closely, you see one of the problems:
q(Y) :- r(X), false, r(Y).
The variable Y is not used in the visible part at all. The X appears just once. Thus, r(X) will be the most general query possible and thus it will have the worst termination property possible (that depends on the definition of r/1, indeed). In any case, the argument of q/1 has no influence on termination!
There is another property to conclude: The order of clauses does not have any influence on the termination property! You can see this easily: No matter where the clauses that have been removed entirely with false appear, they can be removed.
For more, see failure-slice.

Prolog: Redundant results in clauses involving anonymous variables

Consider the following Prolog program.
a(X) :- b(_), c(X).
b(1).
b(2).
b(3).
c(1).
Running the query:
a(X).
in SWI-Prolog, we get three results, all X = 1.
Given that we do not care about the anonymous variable, what is preventing SWI-Prolog to return a single result? Why isn't this optimization performed?
Thanks
Well for Prolog the underscore is simply an anonymous variable. So the a/1 predicate is equivalent to:
a(X) :-
b(Y),
c(X).
Now it may look useless to backtrack over the b(Y) clause, since once it is satisfied, the Y is nowhere used, and thus should not have impact on the rest of the program. Furthermore Y has no effect on X so b(Y) should not have the slightest influence on X.
In real Prolog however, there are some things that might have impact:
the b/1 predicate might perform I/O. Say that the predicate is implemented as:
b(a) :-
print(a).
b(a) :-
print(b).
then it will print a in the first branch and b in the second one.
b/1 might raise an exception in a second, third, ... path. In which case we probably want to handle the error;
b/1 might use asserta/1, assertz/1, etc. and alter the program. It might for instance add facts for c/1 such that in the second run c/1 has other results.
A lot of Prolog interpreters have a non-backtrackable store such that the different backtracking paths, can share information with each other.
other coding facilities such that the outcome of b/1 might have impact on c/1.
You can avoid this backtracking over b/1 by using the once/1 meta-predicate. For instance:
a(X) :-
once(b(_)),
c(X).

Prolog Unification with not()

I am just learning prolog and there is a thing I can't get my head over.
Suppose I have the following program
value(v).
a(X) :- not(value(X)).
So a(v). gives me false, as value(v) can be proved correct.
a(w) gives me true, as there is no fact value(w), therefore, even when trying, it can't be proved correct.
In my understanding, requesting a(X). should give me the first possible value that makes value(X) unproveable. There should be an infinite amount of possibilities, as only value(v) is correct.
But why does Prolog keep answering false?
First of all, please use the ISO predicate (\+)/1 instead of not/1.
Second, please don't use (\+)/1 to denote disequality of terms: (\+)/1 is incomplete in Prolog, and thus not logically sound. It is not logical negation, but rather denotes "not provable".
In your case: ?- value(X). succeeds, so it is provable, so ?- \+ value(X). fails although there are instantiations that make the query succeed.
In particular, ?- \+ value(a). succeeds.
So we have:
?- \+ value(V).
false.
But a more specific query succeeds:
?- V = a, \+ value(V).
V = a.
This obviously runs counter to logical properties we expect from pure relations. See logical-purity.
To denote disequality of terms, use dif/2. If your Prolog system does not support dif/2, ask for its inclusion, or use iso_dif/2 as a safe approximation that is logically sound. See prolog-dif for more information.
Prolog operates under "closed world assumption" – it only knows what we told it about. In particular, we've told it nothing about no w, u, or any other stuff, so how could it produce them to us? And why should w come before u, and not vice versa?
The only thing sensible could be to produce (X, dif(X,v)), but it would be the answer to a different question, namely, "how to make a(X) provable?", not the one Prolog is actually answering, namely "is a(X) provable?".
To ease up your cognitive burden, rename the Prolog prompt's replies in your head from true to Yes, and from false to No.
Yes would mean Prolog telling us "yes, I could prove it!", and No – "no, I couldn't prove it."
Also rename "not" to read \+ as not_provable, mentally.

Resources