I am doing resolution proof in formal logic using truth table and prolog program outcome of my experiments are different and I want to know why.
Here is the problem in plain english:
1. If someone looks into eyes of fighter, he is going to get angry.
2. If the fighter gets angry, he is going to punch.
If the fighter punched, did someone look into fighter's eyes?
'Fighter punched' is conclusion, and we know when conclusion is true the premise could be either false or true, therefore we can't answer the question.
However, following SWI prolog program returns true:
eyes:-angry.
angry:-punch.
punch.
?-eyes.
True
Also
aggregate_all(count, (eyes), Count)
1
Can somebody explain this?
Remember that :- in Prolog is supposed to look like an arrow — an arrow from right to left, like <==. (We do not actually use an arrow, so that users can freely define a custom operator and use it for their own purpose without interfering with regular Prolog code.)
Thus, all your arrows point in the wrong direction. You probably meant:
angry(true) :- eyes(true).
punch(true) :- angry(true).
I am introducing a Boolean argument for these predicates so that you can play with different parameters without worrying about (non)existence of any predicates.
For example, if you add to these clauses:
eyes(true).
Then you get:
?- punch(T).
T = true.
However, if you instead add:
eyes(false).
then you get:
?- punch(T).
false.
This shows that yes, someone must have looked the person in the eye.
Related
I'm working through Clocksin and Mellish to try and finally go beyond just dabbling in Prolog. FWIW, I'm running SWI-Prolog:
SWI-Prolog version 7.2.3 for x86_64-linux
Anyway, I implemented a diff/2 predicate as part of exercise 1.4. The predicate is very simple:
diff(X,Y) :- X \== Y.
And it works when used in the sister_of predicate, like this:
sister_of(X,Y) :-
female(X),
diff(X,Y),
parents(X, Mum, Dad ),
parents(Y, Mum, Dad ).
in that, assuming the necessary additional facts, doing this:
?- sister_of(alice,alice).
returns false as expected. But here's the rub. If I do this instead:
?- sister_of(alice, Who).
(again, given the additional facts necessary)
I get
Who = edward ;
Who = alice;
false
Even though, as already shown, the sister_of predicate does not treat alice as her own sister.
On the other hand, if I use the SWI provided dif/2 predicate, then everything works the way I would naively expect.
Can anyone explain why this is happening this way, and why my diff implementation doesn't work the way I'm expecting, in the case where I ask for additional unifications from that query?
The entire source file I'm working with can be found here
Any help is much appreciated.
As you note, the problem stems from the interplay between equality (or rather, inequality) and unification. Observe that in your definition of sister_of, you first find a candidate value for X, then try to constrain Y to be different, but Y is still an uninstantiated logic variable and the check is always going to succeed, like diff(alice, Y) will. The following constraints, including the last one that gives a concrete value to Y, come too late.
In general, what you need to do is ensure that by the time you get to the inequality check all variables are instantiated. Negation is a non-logical feature of Prolog and therefore potentially dangerous, but checking whether two ground terms are not equal is safe.
Hi :) Beginner to Prolog.
I have this code:
dog(rex).
owns(bill,rex).
animallover(X):-owns(X,Y),dog(Y).
not(beat(X,Y)):-animallover(X),isAnimal(Y).
beat(bill,tom);beat(bull,tom).
iscat(tom).
isAnimal(X):-iscat(X).
This yields the error: No permission to modify static procedure `(;)/2'
What's wrong there?
Thanks for your help.
dog(rex).
owns(bill,rex).
animallover(X):-owns(X,Y),dog(Y).
notbeat(X,Y):-animallover(X),isAnimal(Y).
not(notbeat(bill,tom),notbeat(bull,tom)).
iscat(tom).
isAnimal(X):-iscat(X).
This solves the problem. But we want to answer the question "Who hit Tom?"
That way we can only ask
?- nothit(X,tom).
and this would yield bill.
So how can we change the code so we can ask who did hit Tom?
The source of your problem is some code that would, in a lesser language, produce a syntax error, but which is syntactically valid but definitely meaningless Prolog.
This part of your code is totally fine:
dog(rex).
owns(bill, rex).
animallover(X) :- owns(X, Y), dog(Y).
Whitespace is free. :)
This is your first problem:
not(beat(X,Y)) :- animallover(X), isAnimal(Y).
I'm not sure what you're trying to say here because I've been doing Prolog too long. But what you are saying here, stated a little differently, is this:
not(Q) :- Q = beat(X, Y), ...
In other words, the procedure you are defining here is not/1, rather than anything to do with beat/2. You've got too much stuff in the head. This is kind of an unusual problem for a beginner; usually people with exposure to other languages would make the error of doing too much assignment on the right side of :- rather than the left side.
In any case, another way to read Q :- P is, "to prove Q, I must first prove P." That's how Prolog thinks about it. Or, "if P, then I can conclude Q." So, you're teaching Prolog how to make a conclusion called not, which is almost certainly not what you mean.
Now, on to your next line, where the error occurs:
beat(bill, tom); beat(bull, tom).
Prolog deals in what are called Horn clauses. The generic Horn clause looks like Q :- P, but if you omit :- P, what you get is usually called a fact. In this case, the entire thing you have on that line is one fact. The head of that expression turns out to be ;, so what you've actually written is this:
A ; B :- A = beat(bill, tom), B = beat(bull, tom).
You're trying to redefine ;/2 here, in essence, and Prolog is not allowing that because ; is too important. What you probably meant here was just a period separating two facts: beat(bill, tom). beat(bull, tom)..
I hope this helps get you over the hump.
In the line
beat(bill,tom);beat(bull,tom).
you seem to mean "Bill beat Tom or Bull beat Tom".
But by Prolog's rules you are instead trying to redefine ;, which isn't allowed, and you can't write "Bill beat Tom or Bull beat Tom" as a fact.
Clue
Four guests (Colonel Mustard, Professor Plum, Miss Scarlett, Ms. Green) attend a dinner party at the home of Mr. Boddy. Suddenly, the lights go out! When they come back, Mr Boddy lies dead in the middle of the table. Everyone is a suspect. Upon further examination, the following facts come to light:
Mr Boddy was having an affair with Ms. Green.
Professor Plum is married to Ms. Green.
Mr. Boddy was very rich.
Colonel Mustard is very greedy.
Miss Scarlett was also having an affair with Mr. Boddy.
There are two possible motives for the murder:
Hatred: Someone hates someone else if that other person is having an affair with his/her spouse.
Greed: Someone is willing to commit murder if they are greedy and not rich, and the victim is rich.
Part A: Write the above facts and rules in your Prolog program. Use the following names for the people: colMustard, profPlum, missScarlet, msGreen, mrBoddy. Be careful about how you encode (or don’t encode) symmetric relationships like marriage - you don’t want infinite loops! married(X,Y) :- married(Y,X) % INFINITE LOOP
?-suspect(Killer,mrBoddy)
Killer = suspect_name_1
Killer = suspect_name_2
etc.
Part B: Write a predicate, suspect/2, that determines who the suspects may be, i.e. who had a motive.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Part C: Add a single factto your database that will result in there being a unique suspect.
Clearly indicate this line in your source comments so that it can be removed/added for
grading.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Whenever I type in
suspect(Killer,mrBoddy).
I get
suspect(Killer,mrBoddy).
Killer = profPlum
I'm missing
Killer = colMustard.
Here's my source.
%8) Clue
%facts
affair(mrBoddy,msGreen).
affair(missScarlett, mrBoddy).
affair(X,Y) :- affair(X,Y), affair(Y,X).
married(profPlum, msGreen).
married(X,Y) :- married(X,Y), married(Y,X).
rich(mrBoddy).
greedy(colMustard).
%rules
hate(X,Y) :- married(X,Spouse), affair(Y,Spouse).
greed(X,Y) :- greedy(X), not(rich(X)), rich(Y).
%suspect
suspect(X,Y):- hate(X,Y).
suspect(X,Y):- greed(X,Y).
There are two kinds of problems with your program. One is on the procedural level: you observed that Prolog loops; the other is on the logical level — Prolog people call this rather the declarative level. Since the first annoying thing is this endless loop, let's first narrow that down. Actually we get:
?- suspect(Killer,mrBoddy).
Killer = profPlum ;
ERROR: Out of local stack
You have now several options to narrow down this problem. Either, go with the other answer and call up a tracer. While the tracer might show you the actual culprit it might very well intersperse it with many irrelevant steps. So many that your mind will overflow.
The other option is to manually modify your program by adding goals false into your program. I will add as many false goals as I can while still getting a loop. The big advantage is that this way you will see in your source the actual culprit (or to be more precise one of potentially many such culprits).1 After trying a bit, this is what I got as failure-slice:
?- suspect(Killer,mrBoddy), false.
married(profPlum, msGreen) :- false.
married(X,Y) :- married(X,Y), false, married(Y,X).
hate(X,Y) :- married(X,Spouse), false, affair(Y,Spouse).
suspect(X,Y):- hate(X,Y), false.
suspect(X,Y):- false, greed(X,Y).
All remaining parts of your program were irrelevant, that is, they are no longer used. So essentially the rule
married(X,Y) :- married(X,Y), married(Y,X).
is the culprit.
Now, for the declarative part of it. What does this rule mean anyway? To understand it, I will interpret :- as an implication. So provided what is written on the right-hand side is true, we conclude what is written on the left-hand side. In this case:
Provided X is married to Y and Y is married to X
we can conclude that
X is married to Y.
This conclusion concluded what we have assumed to be true anyway. So it does not define anything new, logically. You can just remove the rule to get same results — declaratively. So married(profPlum, msGreen) holds but married(msGreen, profPlum) does not. In other words, your rules are not correct, as you claim.
To resolve this problem, remove the rule, rename all facts to husband_wife/2 and add the definition
married(M,F) :- husband_wife(M,F).
married(F,M) :- husband_wife(M,F).
So the actual deeper problem here was a logical error. In addition to that Prolog's proof mechanism is very simplistic, turning this into a loop. But that is not much more than a welcome excuse to the original logical problem.2
Footnotes:1 This method only works for pure, monotonic fragments. Non-monotonic constructs like not/1 or (\+)/1 must not appear in the fragment.
2 This example is of interest to #larsmans.
The problem is the recursive rules of the predicates affair/2 and married/2. Attempting to use them easily leads to an endless loop (i.e. until the stack memory is exhausted). You must use a different predicate in each case to represent that if X is having an affair with Y, then Y is having an affair with X. You also need to change your definition of the suspect/2 predicate to call those new predicates.
To better understand why you get an endless loop, use the trace facilities of your Prolog system. Try:
?- trace, suspect(Killer, mrBoddy).
and go step by step.
I'm trying to get comfortable with Prolog (SWI Prolog specifically).
I have this very simple listing:
animal(bear).
animal(mouse).
animal(bird).
Now whenever I ask for all atoms that fulfill (what is the correct expression?) the predicate
animal I always get only the first one.
?- animal(X).
X = bear .
Though all three atoms evaluate to 'true' for animal.
?- animal(mouse).
true.
?- animal(bird).
true.
What am I doing wrong? Is this behavior controllable via some setting?
There is nothing wrong in your code. Prolog is a reasoning machine. So it tries to find the first solution that will satisfy all the variables.
Once the solution is found it prints it out.
Now if you need additional solution there should be some combination that you should enter so that prolog will continue searching.
If I remember correctly it might be a semicolon...
Hope this helps
I'm running my first few programs in Prolog and have hit a snag in the kind of experiment I'm trying to run. Initially I was doing it on a mini-map of a few US states but I simplified it to an alphabet:
adj(a,b).
adj(b,a).
adj(b,c).
adj(c,b).
adj(c,d).
na(X, Z) :- \+adj(X, Z).
When I query for na(a, What). I don't get any responses (just a no) but if I individually check na(a,d) it, of course, naturally returns yes.
What's the explanation behind why this would happen? I've been able to get other queries to work in different programs so I'm wondering what key information I'm missing. Thanks!
Think of (\+)/1 not as logical negation, but as "not provable". \+ na(a, What) succeeds if and only if na(a, What) is not provable. Since na(a, What) yields at least one solution and is thus provable, its negation (in this sense) fails. (\+)/1 is thus logically incomplete: It fails in this case although, as you observed, there are ground values that would make it succeed. However, (\+/1) works like you expect from logical negation if its argument is ground. You can therefore solve it for example with
na(X, Y) :- country(X), country(Y), \+ adj(X, Y).
where country/1 yields ground instances of countries. Another way to solve it is to explicitly enumerate countries that are not adjacent, which is possible since the domain is finite. An advantage of this approach is that your queries are then monotonic: Adding new facts will never make a query that previously succeeded fail (this does not hold when using (\+)/1 as above). This is a nice property for declarative debugging.