How to properly express inequality in prolog? - prolog

TL;DR: sibling(a,X) succeeds with the answer X = a, but sibling(a,a) fails.
I have the following Prolog file:
children(a, c).
children(a, d).
children(b, c).
children(b, d).
sibling(X, Y) :-
X \== Y, A \== B,
children(X, A), children(X, B),
children(Y, A), children(Y, B).
It seems clear enough to me, two person are siblings if their parents are the same. Also, a person is not their own sibling.
But when I tried to run some queries on GNU Prolog, I get some strange results:
| ?- sibling(a, b).
true ? a
true
true
yes
This is the intended behavior. a and b are siblings. There are three results, which is a bit weird, but I assume Prolog is binding A = c, B = d and A = d, B = c.
| ?- sibling(a, a).
no
I think this means a and a are not siblings.
| ?- sibling(a, X).
X = a ? a
X = b
X = a
X = b
X = a
X = b
X = a
X = b
(15 ms) yes
This is where I got stuck: It says X = a, which means sibling(a,a) is true, but sibling(a,a) failed in the previous query!
I feel that I'm not understanding what \== actually does in Prolog.
What is happening, and how do I fix this?

TL;DR: Use prolog-dif—or iso_dif/2 (on iso-prolog conforming systems like gnu-prolog)!
Good question, +1!
In fact, it's a question I have asked myself, and the answer has to do with logical-purity: logical purity is a central aspect of what
makes Prolog as a language so special, as it enables you to:
describe—not prescribe
write code that is relational—not just functional
think in terms of problems / solutions—not the individual steps of the search process itself
operate on a higher level—not get lost in nitty-gritty details
Unlike many other programming languages, Prolog programs have both procedural semantics (defining the execution steps and their order) and declarative semantics (allowing you to state relations that should hold and let the Prolog processor find a proper way of execution by itself).
But, beware: Prolog has some features that, when used, ruin declarative semantics. To prevent this, try to structure your application into two parts: an impure shell for dealing with side-effects (input/output) and a logically pure base which comprises pure monotonic Prolog code.

Try moving the inequality to the end of the predicate. Maybe it gives you true because it's not instantiated already.
sibling(X,Y):- children(X, A), children(X, B),
children(Y, A), children(Y, B),
X \== Y, A \== B.

Related

Proper subsumes_term/2 in SWI-Prolog?

Lets assume SICStus Prolog is the benchmark for the
implementation of certain predicates, even ISO core standard
predicates. Especially in connection with attributed variables.
I then find these examples here. It's from SICStus 4 and not only SICStus 3:
?- when(nonvar(X), X=a), subsumes_term(X, b), X = a.
X = a ?
yes
?- when(nonvar(X), X=a), subsumes_term(X, b), X = b.
no
When doing the same in SWI-Prolog I get different results:
?- when(nonvar(X), X=a), subsumes_term(X, b), X = a.
false.
?- when(nonvar(X), X=a), subsumes_term(X, b), X = b.
false.
How would one implement a workaround in SWI-Prolog? ROKs METUTL.PL probably doesn't help, since it uses normal unification.
Here is a suggestion (not actually tested in SWI-prolog):
subsumes_term_sicstus(X, Y):-
copy_term(X-Y, XC-YC, _),
subsumes_term(XC, YC).
The idea is simply to copy the two structures then use the original predicate on the copies, which do not have attributes or frozen goals attached.
According to the documentation, it appears that copy_term/2 copies the attributes of attributed variables in SWI-prolog (but not in SICStus), so I am using copy_term/3 instead here. I see that there is also a copy_term_nat/2, which might be used instead.

Optional binding in Prolog

Let's imagine a simple database of genealogy facts where mother(M, C) and father(F, C) denotes that M/F is the mother/father of child C.
I've written a rule to find known parents of a child (zero, one or both):
parents(C, M, F) :-
(mother(M, C) -> true; true),
(father(M, C) -> true; true).
which binds M and F if they are known and leaves them unbound otherwise.
It works fine, which means that for a set of facts:
mother(m1, c1).
father(f1, c1).
mother(m2, c2).
a call to parents(c1, M, F) returns:
M = m1,
F = f1.
while parents(c2, M, F) returns:
M = m2.
but the use of the arrow operators seems a little strange to me. Am I missing something basic? Can the (X -> true ; true) calls be avoided/simplified?
Any help appreciated.
Cheers,
From a logical perspective, a major mistake in this program is its incompleteness.
Consider for example the most general query:
?- parents(X, Y, C).
X = c1,
Y = m1.
So, no solution for c2 is reported.
But such a solution exists, as can be seen with:
?- parents(c2, Y, C).
Y = m2.
So, which is it, is there a solution or not?
Such mistakes almost invariably arise if you use (->)/2 and other constructs that violate logical purity of your code. Please see logical-purity for more information.
Hence, from a logical perspective, I can only recommend to avoid such constructs, since they defeat the primary advantage of a logic programming language to begin with: The ability to reason logically about your programs.
Instead, focus on a clear description of the relations you want to describe, and state the conditions that make them true. This will allow you to use your Prolog programs in a sensible way.
EDIT: I see you prefer a botched program. For this purpose, I recommend ignore/1. ignore(Goal) calls Goal as once(Goal), and succeeds. You can use this to simplify your program and still ensure that it remains incomplete.
Prolog is a real down to earth programming language. It has a pure subset. Both have their place.
once( (A ; true) ) is the answer to the question "how can we simplify (A -> true; true)".
If you want more purity, you could write (A *-> true ; true ) with the "soft cut" *-> which admits all solutions from the successful A and only switches to the unsuccessful branch in case A didn't produce any. See also e.g. this answer of mine for more discussion.
Another variant is (A ; \+ A).

prolog doesn't give me a solution when one exists

I am working through Seven Languages in Seven Weeks, but there is something I don't understand about prolog. I have the following program (based on their wallace and grommit program):
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- \+(X = Y), onTeam(X, Z), onTeam(Y, Z).
and load it like this
?- ['teams.pl'].
true.
but it doesn't give me any solutions to the following
?- teamMate(a, X).
false.
it can solve simpler stuff (which is shown in the book):
?- onTeam(b, X).
X = aTeam ;
X = superTeam.
and there are solutions:
?- teamMate(a, b).
true ;
false.
What am I missing? I have tried with both gnu prolog and swipl.
...AND THERE IS MORE...
when you move the "can't be your own teammate" restriction to then end:
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- onTeam(X, Z), onTeam(Y, Z), \+(X = Y).
it gives me the solutions I would expect:
?- ['teams.pl'].
true.
?- teamMate(a, X).
X = b.
?- teamMate(b, X).
X = a ;
X = c.
What gives?
You have made a very good observation! In fact, the situation is even worse, because even the most general query fails:
?- teamMate(X, Y).
false.
Declaratively, this means "there are no solutions whatsoever", which is obviously wrong and not how we expect relations to behave: If there are solutions, then more general queries must not fail.
The reason you get this strange and logically incorrect behaviour is that (\+)/1 is only sound if its arguments are sufficiently instantiated.
To express disequality of terms in a more general way, which works correctly no matter if the arguments are instantiated or not, use dif/2, or, if your Prolog system does not provide it, the safe approximation iso_dif/2 which you can find in the prolog-dif tag.
For example, in your case (note_that_I_am_using_underscores_for_readability instead of tuckingTheNamesTogetherWhichMakesThemHarderToRead):
team_mate(X, Y) :- dif(X, Y), on_team(X, Z), on_team(Y, Z).
Your query now works exactly as expected:
?- team_mate(a, X).
X = b.
The most general query of course also works correctly:
?- team_mate(X, Y).
X = a,
Y = b ;
X = b,
Y = a ;
X = b,
Y = c ;
etc.
Thus, using dif/2 to express disequality preserves logical-purity of your relations: The system now no longer simply says false even though there are solutions. Instead, you get the answer you expect! Note that, in contrast to before, this also works no matter where you place the call!
The answer by mat gives you some high-level considerations and a solution. My answer is a more about the underlying reasons, which might or might not be interesting to you.
(By the way, while learning Prolog, I asked pretty much the same question and got a very similar answer by the same user. Great.)
The proof tree
You have a question:
Are two players team mates?
To get an answer from Prolog, you formulate a query:
?- team_mate(X, Y).
where both X and Y can be free variables or bound.
Based on your database of predicates (facts and rules), Prolog tries to find a proof and gives you solutions. Prolog searches for a proof by doing a depth-first traversal of a proof tree.
In your first implementation, \+ (X = Y) comes before anything else, so it at the root node of the tree, and will be evaluated before the following goals. And if either X or Y is a free variable, X = Y must succeed, which means that \+ (X = Y) must fail. So the query must fail.
On the other hand, if either X or Y is a free variable, dif(X, Y) will succeed, but a later attempt to unify them with each other must fail. At that point, Prolog will have to look for a proof down another branch of the proof tree, if there are any left.
(With the proof tree in mind, try to figure out a way of implementing dif/2: do you think it is possible without either a) adding some kind of state to the arguments of dif/2 or b) changing the resolution strategy?)
And finally, if you put \+ (X = Y) at the very end, and take care that both X and Y are ground by the time it is evaluated, then the unification becomes more like a simple comparison, and it can fail, so that the negation can succeed.

Why double negation doesn't bind in Prolog

Say I have the following theory:
a(X) :- \+ b(X).
b(X) :- \+ c(X).
c(a).
It simply says true, which is of course correct, a(X) is true because there is no b(X) (with negation as finite failure). Since there is only a b(X) if there is no c(X) and we have c(a), one can state this is true. I was wondering however why Prolog does not provide the answer X = a? Say for instance I introduce some semantics:
noOrphan(X) :- \+ orphan(X).
orphan(X) :- \+ parent(_,X).
parent(david,michael).
Of course if I query noOrphan(michael), this will result in true and noOrphan(david) in false (since I didn't define a parent for david)., but I was wondering why there is no proactive way of detecting which persons (michael, david,...) belong to the noOrphan/1 relation?
This probably is a result of the backtracking mechanism of Prolog, but Prolog could maintain a state which validates if one is searching in the positive way (0,2,4,...) negations deep, or the negative way (1,3,5,...) negations deep.
Let's start with something simpler. Say \+ X = Y. Here, the negated goal is a predefined built-in predicate. So things are even clearer: X and Y should be different. However, \+ X = Y fails, because X = Y succeeds. So no trace is left under which precise condition the goal failed.
Thus, \+ \+ X = Y does produce an empty answer, and not the expected X = Y. See this answer for more.
Given that such simple queries already show problems, you cannot expect too much of user defined goals such as yours.
In the general case, you would have to first reconsider what you actually mean by negation. The answer is much more complex than it seems at first glance. Think of the program p :- \+ p. should p succeed or fail? Should p be true or not? There are actually two models here which no longer fits into Prolog's view of going with the minimal model. Considerations as these opened new branches to Logic Programming like Answer Set Programming (ASP).
But let's stick to Prolog. Negation can only be used in very restricted contexts, such as when the goal is sufficiently instantiated and the definition is stratified. Unfortunately, there are no generally accepted criteria for the safe execution of a negated goal. We could wait until the goal is variable free (ground), but this means quite often that we have to wait way too long - in jargon: the negated goal flounders.
So effectively, general negation does not go very well together with pure Prolog programs. The heart of Prolog really is the pure, monotonic subset of the language. Within the constraint part of Prolog (or its respective extensions) negation might work quite well, though.
I might be misunderstanding the question, and I don't understand the last paragraph.
Anyway, there is a perfectly valid way of detecting which people are not orphans. In your example, you have forgotten to tell the computer something that you know, namely:
person(michael).
person(david).
% and a few more
person(anna).
person(emilia).
not_orphan(X) :- \+ orphan(X).
orphan(X) :- person(X), \+ parent(_, X).
parent(david, michael).
parent(anna, david).
?- orphan(X).
X = anna ;
X = emilia.
?- not_orphan(X).
X = michael ;
X = david ;
false.
I don't know how exactly you want to define an "orphan", as this definition is definitely a bit weird, but that's not the point.
In conclusion: you can't expect Prolog to know that michael and david and all others are people unless you state it explicitly. You also need to state explicitly that orphan or not_orphan are relationships that only apply to people. The world you are modeling could also have:
furniture(red_sofa).
furniture(kitchen_table).
abstract_concept(love).
emotion(disbelief).
and you need a way of leaving those out of your family affairs.
I hope that helps.

Prolog implying a negative predicate

How can I write the following rule in PROLOG: if P then not Q
I understand that you can easily write if P then Q the predicates like q(X) :- p(X), but how can you negate the q/1 predicate? I don't want to define new predicates with other semantics like non_q/1.
The clause "if P then not Q" is logically equivalent to the negative clause "not P OR not Q". As such it is a Horn clause without a positive literal, and as an application of the correspondence of SLD theorem proving and Horn clauses, can be represented in Prolog programming as a goal clause or "query":
?- P, Q.
Let's come back to this idea in a minute.
But the goal clause is perhaps not the sort of representation you have in mind. The facts and rules that constitute a Prolog "knowledgebase" are definite clauses, i.e. Horn clauses each with exactly one positive literal. "If P then not Q" has no positive literal, so in this sense it cannot be represented (as a definite clause).
The goal clause shown above "asks" if P and Q can both be proven. Prolog provides a notion of "negation as failure", so a more natural way to "ask" whether "not P OR not Q" holds would be:
?- not((P,Q)).
Then we would get success if either P or Q fails, and failure if both succeed.
However if your purpose is to assert the negation something in the knowledgebase, Prolog doesn't naturally support this. Depending on your application, there may be a reasonable way to work around the Prolog syntax and accomplish what is needed (there's always an unreasonable way to do it, as you've hinted as with a non_q predicate).
Have you ever heard about cut in Prolog?
Anyway I don't know much about Prolog standard, but in SWI-Prolog the symbol \+ means negation. I know it don't have to work in every Prolog's interpreter.
You can make the predicate negation with Prolog's cut. The predicate is defined like:
not(Goal) :- call(Goal),!,fail.
not(Goal).
It means that Goal can't be proven, not the Goal is false.
Maybe this Prolog & Cut link will be useful.
"...if P then not Q" can be represented via the -> if-then control-flow predicate (e.g., GNU) , along with the \+ negation (or 'not-provable') operator (e.g., GNU), as follows:
(P -> \+ Q),
Note that, typically, \+ will implement what is known as negation-as-failure; i.e., the subgoal/expression \+ Q will succeed iff Q cannot. Note that the evaluation of Q under \+ will not affect the bindings of any variables present in the expression Q at execution.
For example, consider:
foo(a).
bar(b).
Given these facts, the following hold:
foo(a) -> \+ bar(a). % succeeds, as bar(a) is not provable.
foo(a) -> \+ bar(b). % fails, as bar(b) is provable.
foo(a) -> \+ bar(X). % fails, as bar(X) is provable; note that X remains unbound.
foo(X) -> \+ bar(X). % succeeds, as bar(X) where X unified to 'a' isn't provable.
Implementing something akin to \+ q(X) :- p(X) as you might want (in terms of a 'rule') isn't straightforward, as you describe, however a potential hack is:
q(X) :- p(X), !, fail.
This definition will only reflect the intention that q(X) is to fail for all X where p(X) succeeds iff it is asserted before any other clauses of q(X), but may not be ideal.
You can use minimal logic to define a negative head. In minimal logic
~A can be viewed as A -> ff. Thus the following
P -> ~Q
Can be viewed as:
P -> (Q -> ff).
Now if we take the following identity (A -> (B -> C)) = (A & B -> C), we
see that the above is equivalent to:
P & Q -> ff.
There is now one problem, how can we ask negative queries? There is one
way to make use of minimal logic which is different from negation as
failure. The idea is that a query of the form:
G |- A -> B
is answered by temporarily adding A to the prolog program G, and then
trying to solve B, i.e. doing the following:
G, A |- B
Now lets turn to Prolog notation, we will show that p, and p -> ~q
implies ~q by executing a (minimal logic) Prolog program. The
prolog program is:
p.
ff :- p, q.
And the query is:
?- q -: ff.
We first need to define the new connective (-:)/2. A quick solution
is as follows:
(A -: B) :- (assert(A); retract(A), fail), B, (retract(A); assert(A), fail).
Here you see a realisation of this minimal logic negation in SWI Prolog:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 5.10.4)
Copyright (c) 1990-2011 University of Amsterdam, VU Amsterdam
1 ?- [user].
:- op(1200,xfy,-:).
|: (A -: B) :- (assertz(A); retract(A), fail), B, (retract(A); assertz(A), fail).
|: p.
|: ff :- p, q.
|:
% user://1 compiled 0.02 sec, 1,832 bytes
true.
2 ?- q -: ff.
true .
Best Regards
Reference:
Uniform Proofs as a Foundation for Logic Programming (1989)
by Dale Miller, Gopalan Nadathur, Frank Pfenning, Andre Scedrov

Resources