likes(alice, sports).
likes(alice, music).
likes(carol, music).
likes(david,animals).
likes(david,X) :- likes(X,sports).
likes(alice,X) :- likes(david,X).
?- likes(alice,X).
I've been trying to learn prolog an few days now, and when I attempted this question, I realised that I don't completely understand when the variables are instantiated and used. The initial goal is : likes(alice , X). After that, the next goal to prove is likes(david , X)? Then is it likes(X, sports). Then does X become alice?
Another route:
The initial goal is : likes(alice , X). After that, the next goal to prove is likes(david , X)? Then X becomes sports. Then the goal becomes likes(david , sports). Then I don't know.
Could someone please indicate where my thinking is flawed.
Given your code Prolog would try to unify the goal against he first fact, likes(alice, sports)., and it would succeed. X would be unified with sports.
If you asked Prolog to continue then it would next unify X with music (the second fact).
And if you continued again it would skip the next three facts/rules, and try to prove likes(alice,X) :- likes(david,X).. This would lead to trying to prove likes(david,X) which succeeds with the fact likes(david,animals) so X, in the original goal, would unify with animals.
And if you asked it to continue again you would find that it tries to prove likes(david,X) :- likes(X,sports). which leads to X unifying with alice, so the original goal would suggest that alice likes alice.
When I ran your code with this goal:
?- likes(alice,X), write(X), nl, fail.
...I got this output:
sports
music
animals
alice
No.
With the final No. being caused because I had the fail predicate in my goal. It was a goal that was always going to fail, but it produced a side-effect by outputting the intermediate result of X.
Let's break down the code. First, you have some facts:
likes(alice, sports). % Alice likes sports
likes(alice, music). % Alice likes music
likes(carol, music). % Carol likes music
likes(david, animals). % David likes animals
Just given these facts, you can make basic queries:
?- likes(alice, sports). % Does Alice like sports?
true ;
false. % no more solutions
So, yes, Alice likes sports (the result was true). Does Alice like animals?
?- likes(alice, animals).
false.
Evidently not. At least, according to the data we have, we cannot prove that Alice likes animals. (Remember, we only have the facts so far, but none of the rules, shown below.)
Well then, what does Alice like, according to the facts?
?- likes(alice, X).
X = sports ;
X = music.
Alice likes sports and music.
Now let's add in your rules:
likes(david, X) :- likes(X, sports).
This says that, David likes someone (X) if that someone (X) likes sports.
Let's see who/what David likes:
?- likes(david, X).
X = animals ;
X = alice ;
false % no more solutions
So David likes animals (because a fact says so), and David likes Alice (because we have a rule that says David likes X if X likes sports, and Alice likes sports).
Your other rule:
likes(alice, X) :- likes(david, X).
Says, Alice likes someone (X) if David likes that same someone (X).
With the new rules added, let's see who/what Alice likes:
?- likes(alice, X).
X = sports ;
X = music ;
X = animals ;
X = alice ;
false
Alice likes sports and music (because the facts say so). Alice likes animals because David likes animals and the rule says that if David likes X, then Alice likes X. Alice also evidently likes herself because, according to the first rule, we showed that David likes Alice. According to the second rule, Alice likes anyone that David likes. Therefore, Alice likes Alice.
You can get the step-by-step execution by running trace. then execute your query.
Note that this is fairly well behaved with these simple rules and facts. In more complex cases you have to be careful about naming your rules and your facts the same way because it can lead to infinite logical loops.
Related
Lets suppose my db.pl file consists of only
male(Oliver)
male(james)
male(sam)
female(X) :- \+ male(X)
Now if I query,
?- male(X).
Then this will successfully return all the males.
But if I query,
?- female(X)
Then this will not. However, if I put a name in the female predicate, it correctly gives the output as yes/no.
What am I missing here? How do I get the list of all females? Or basically list of "not male".
I thought I'd give a proper answer as well. As mentioned in the comments, the fact male(Oliver). contains the variable Oliver such that e.g. also male(catherine_the_great) succeeds. But fixing this mistake will not solve the problem. Suppose we fix the facts for male and define female as above:
male(oliver)
male(james)
male(sam)
female(X) :-
\+ male(X).
Then we can not derive male(catherine_the_great) anymore but female(catherine_the_great) succeeds:
?- male(catherine_the_great).
false.
?- female(catherine_the_great).
true.
Unfortunately, by this definition, a hamburger is also female:
?- female(hamburger).
true.
What's even worse is, when we ask if there exists someone female (at all!), we get no as an answer:
?- female(X).
false.
The reason for this is that \+ is not classical negation(*) but what is called weak negation / negation as failure. \+ male(X) is true if there is no X such that male(X) is derivable. But as soon as male/1 succeeds with any solution (e.g. male(oliver)), the negation fails. In such cases the substitution male(X) is not proper substiution for female(X) but how are we supposed to get a list of all women? A possible solution is a list of persons of which we define male/female as subsets:
person(oliver).
person(james).
person(sam).
person(jackie).
person(selma).
male(oliver).
male(james).
male(sam).
female(X) :-
person(X),
\+ male(X).
When we query a list of all women, we now get:
?- female(X).
X = jackie ;
X = selma.
I'd rather use a separate predicate listing women though because it is less error prone when adding new persons.
In general, negation as failure is rarely safe. Two rules of thumb i have for myself:
whenever \+ p(X) appears as a goal, it is fully instantiated (a ground term). In our case, this is what person assures.
p(X) terminates for every ground term X. This assures termination of the negation as well.
(*) in classical logic, the rule of generalization female(jackie) → ∃X female(X) holds but here we can not derive ∃X female(X) despite being able to derive female(jackie).
I'm trying to solve:
Given facts such as
Bob is taller than Mike.
Mike is taller than Jim
Jim is taller than George
Write a recursive program that will determine that Bob's height is greater than George's.
My solution so far is:
taller_than(bob, mike).
taller_than(mike, jim).
taller_than(jim, george).
taller_than(X,Y):-
taller_than(X, Z),
taller_than(Z, Y).
It returns True as expected, but then I reach the stack limit. I'm guessing I need a base case, but I'm not sure what it would be? Is my solution otherwise correct?
Oh so close.
Your main problem is that you have facts taller_than/2 and predicates taller_than/2 with the same signature. This even caught me off guard when I gave it an initial test run. You need to change the name of either the fact or the predicate. For this the name of the predicate is changed.
As you noted you need a base case and had you done the name change I think you would have figured this out also.
taller_than_rule(X,Y) :-
taller_than(X,Y).
taller_than_rule(X,Y) :-
taller_than(X, Z),
taller_than_rule(Z, Y).
Example run:
?- taller_than_rule(bob,Who).
Who = mike ;
Who = jim ;
Who = george ;
false.
Problem:
Jack is looking at Anne, Anne is looking at George
Jack is married, George is not.
Is a married person looking at an unmarried person?
I am looking at this solution found in this link which entails:
unmarried(X) :- not(married(X)).
unmarried("George").
unmarried("Anne").
married("Jack").
married("Anne").
looking_at("Jack", "Anne").
looking_at("Anne", "George").
check(X, Y):-
looking_at(X,Y),
married(X),
unmarried(Y).
There are several questions immediately apparent once this much is done. For the first part, I was confused as to why Anne is defined as Married("Anne") and Unmarried("Anne"), but I quickly put that aside assuming that it possibly means to define Anne as either married or unmarried
A quick look at SO doesn't help either, as I found only some remotely
related questions; This particular question being the closest one.
Now back to the problem that I have here...
unmarried(X) :- not(married(X)). handles the operation such that if Anne is passed as the first argument of check(_, _)
The programmer for that solution has handled it with a single check(_, _) according to which:
check(Anne,George) will infer:
Anne looking at George
Anne being married
George being unmarried
That compiler produces this result as:
Anne->Jack->Anne->Anne
George->Anne->George->George
At this point, I don't know why the compiler is producing those results. And as far as I know, this is not giving the solution either. In the old desktop version of prolog that I used, check(Anne,George). should have produced a YES, seeing as all the conditions were TRUE(Well I have never tried the online swi-prolog tbh; is it different?)
For check(Jack,Anne) it is:
Jack looking at Anne
Jack being married
Anne being unmarried
I don't see how this necessarily solves the problem. Could someone post a better solution or explain in detail how this is working?
Requirement:
I need a solution for the Problem that I posted at the begining of this question. If you can resolve it from the existing condition that I have posted, thats cool. However, I am also open to alternate ideas and solutions.
First lets look at the puzzle itself. The question "Is a married person looking at an unmarried person?" is clearly a yes/no question. Considering the marital status we have incomplete knowledge(Anne). The people who's marital status we know are not gazing at each other, so we have to consider Anne to find an answer. If we assume that:
Anne is married then the answer is yes because she is looking at the unmarried George.
Anne is not married then the answer is yes because the married Jack is looking at her.
So either way there is a married person looking at an unmarried person, thus the answer to the puzzle is yes.
Regarding the given solution: I think the author tries to model "Anne is either married or not married" by the facts married("Anne") and unmarried("Anne"). However the facts seem to express that Anne is married and unmarried at the same time. Also the rule unmarried(X) :- not(married(X)). in combination with the facts married/1 and unmarried/1 yields the solution "Anne" twice. Thus check/2 also yields the Anne-looks-at-George solution twice:
?- check(X,Y).
X = "Jack",
Y = "Anne" ? ;
X = "Anne",
Y = "George" ? ;
X = "Anne",
Y = "George"
I can see where the author is trying to go with his solution but it isn't really expressing that there is an assumption involved and how the two unique solutions are connected.
My attempt is the following: I would keep four facts from the original version and add another one for Anne:
married(jack).
unmarried(george).
looking_at(jack,anne).
looking_at(anne,george).
unknown(anne).
Then I can make assumptions about people who's marital status I don't know:
person_assumption(A,married) :- unknown(A).
person_assumption(A,unmarried) :- unknown(A).
Now the relevant cases for the yes-answer are: (1) a known unmarried person is being looked at by a known married person and (2) a person P1 is
looking at known unmarried person under the assumtion that P1 is married
AND
being looked at by a known married person under the assumption that P1 is unmarried
The predicate problematicgaze/1 is modeling these observations:
problematicgaze((P1-P2)) :- % case (1)
married(P1),
unmarried(P2),
looking_at(P1,P2).
problematicgaze((if_married(P1)-P2,P3-if_unmarried(P1))) :- % case (2)
assumedproblematic(if_married(P1),P2),
assumedproblematic(P3,if_unmarried(P1)).
assumedproblematic(if_married(P1),P2) :-
person_assumption(P1,married),
unmarried(P2),
looking_at(P1,P2).
assumedproblematic(P1,if_unmarried(P2)) :-
person_assumption(P2,unmarried),
married(P1),
looking_at(P1,P2).
This breaks down to: either I get a solution and the answer is yes or the predicate fails and the answer is no. So I ask if there is a problematic gaze in the given situation:
?- problematicgaze(G).
G = (if_married(anne)-george,jack-if_unmarried(anne)) ? ;
no
As expected there is no answer from the first rule of problematicgaze/1 but from the second. No matter which assumption is taken for Anne a married person is looking at an unmarried one. Other than that no solution is found.
The solution to which you have linked is not correct. A pointed out in the comments, I am not sure how this gives answers:
?- check(X, Y).
X = "Jack",
Y = "Anne" ;
X = "Anne",
Y = "George" ;
X = "Anne",
Y = "George".
Please if someone knows the program was meant to be used, explain. I am afraid I am just missing something.
Here is one attempt at a real solution. First, we leave the ground facts exactly as given:
looking_at(jack, anne).
looking_at(anne, george).
married(jack).
unmarried(george).
I will now define a predicate solution/2 which has the solution and any possible bindings that explain it. There are three possible solutions, if I understand: "yes", "no", and "undetermined". In the case of a "yes" answer:
solve(yes, married_unmarried(A, B)) :-
married(A),
looking_at(A, B),
unmarried(B).
The "no" case is a bit different. It is supposed to say:
For all A looking at a B, either A is unmarried or B is married.
With SWI-Prolog and forall/2, you can write:
solve(no, false) :-
forall(looking_at(A, B),
( unmarried(A) ; married(B) )).
This is equivalent to:
solve(no, false) :-
\+ ( looking_at(A, B),
\+ ( unmarried(A) ; married(B) ).
The undetermined case is more interesting, but we could try and cheat:
solve(undetermined, B) :-
\+ solve(yes, B),
\+ solve(no, B).
We can neither prove that someone is looking nor that no one is looking.
i just can't get my head around this problem i'm having with prolog. Only just started, but i can't seem to find a way to find out if an object is unique. Heres my code:
/* (Student Name, Student Number)*/
Student(stuart, 11234).
Student(ross, 11235).
Student(rose, 11236).
Student(stuart, 11237).
how can i find out if a student is unique. Take for example Stuart, there's two students named Stuart, so Stuart is not unique. How could i write a procedure to tell if its another Student called Stuart.
I've tried spending so many hours on this, but i can't seem to get my head around dealing with the original Stuart rather than the other Stuart because i can't exclude the one i'm trying to find out if its unique.
Thanks for the help.
With your database example this could do
unique(S) :-
student(S, N), \+ (student(S, M), M \= N).
as it yields
?- unique(S).
S = ross ;
S = rose ;
false.
Generally, Prolog is targeted toward existence of solutions. Then predication about cardinality need some support from the 'impure' part of the language: nb_setarg it's currently our best friend when we need to efficiently tracking cardinality.
Using a metapredicate like this:
%% count_solutions(+Goal, ?C)
%
% adapted from call_nth/2 for http://stackoverflow.com/a/14280226/874024
%
count_solutions(Goal, C) :-
State = count(0, _), % note the extra argument which remains a variable
( Goal,
arg(1, State, C1),
C2 is C1 + 1,
nb_setarg(1, State, C2),
fail
; arg(1, State, C)
).
:- meta_predicate count_solutions(0, ?).
you could solve the problem without considering the second argument
unique(S) :-
student(S, _), count_solutions(student(S, _), 1).
The same predicate could use aggregate_all(count, student(S,_), 1) from library(aggregate), but such library currently builds a list internally, then you could consider the answer from Peter as easier to implement.
There are probably quite a few ways to solve this problem but I would do it this way:
% a student has a name and a number
student(stuart, 11234).
student(ross, 11235).
student(rose, 11236).
student(stuart, 11237).
This code says "find a list the same length as the number of students with Name" and then "make Count the same as the length of the list":
% for every student name there is an associated count of how many times
% that name appears
number_students(Name, Count) :-
findall(_, student(Name, _), Students),
length(Students, Count).
This predicate will only be true if the number_students is 1:
% a student name is unique (appears once and only once) is the
% number_students count is 1
unique_student(Name) :-
number_students(Name, 1).
Testing:
12 ?- unique_student(ross).
true.
13 ?- unique_student(rose).
true.
14 ?- unique_student(bob).
false.
15 ?- unique_student(stuart).
false.
This is an easy way to solve the problem, but it isn't a great Prolog solution because you cannot say things like "give me a unique student name" and get a list of all the unique names.
Some comments on the code you have. This is not a fact:
Student(Ross).
These are two different facts (in SWI-Prolog, at least):
student(ross).
student('Ross').
In other words, predicate names must start with small letters, and identifiers starting with a capital letters denote variables, not atoms. You can put any character string in single quotes to make it a valid atom.
Now this out of the way, it is not clear what you are aiming at. What are you going to do with your unique student? How do you know the first one is the one you are looking for, and not the second? And why not use the student number for that (at least in your example the two Stuarts seem to have different numbers)?
What is the best way to express a total order relation in Prolog ?
For example, say I have a set of facts
person(tim)
person(ana)
person(jack)
...
and I want to express the following truth about a person's fortune: for each two persons X and Y, if not(X==Y), either X is richer than Y or Y is richer than X.
So my problem is that the richer clause should be capable of instantiating its variables and also to ensure that it is never the case that richer(X, Y) and richer(Y, X) at the same time.
Here is a better example to see what I mean:
person(tim).
person(john).
happier(tim, john).
hates(X, Y) :- person(X), person(Y), richer(Y, X).
hates(X, Y) :- person(X), person(Y), richer(X, Y), happier(Y, X).
Now the answer to the query hates(john, tim) should return true, because if richer satisfies the mentioned property, one of those two hates clauses must be true. In a resolution based inference engine I could assert the fact (richer(X, Y) V richer(Y, X)) and the predicate hates(john, tim) could be proved to be true.
I don't expect to be able to express this the same way in Prolog with the same effect. However, how can I implement this condition so the given example will work ?
Note also that I don't know who is richer: tim or john. I just now that one is richer than the other.
Thank you.
you cannot write in pure Prolog that a predicate should be a total order: that would require higher order logic since you want to declare a property about a predicate.
this is a predicate that checks if a relationship is total order on a finite set:
is_total_order(Foo,Set):-
forall(
(member(X,Set),
member(Y,Set)),
(
XY =.. [Foo,X,Y],
YX =.. [Foo,Y,X],
(call(XY);call(YX)), %checking if the relationship is total
\+ (call(XY),call(YX), X\=Y) %checking if it's an order
)
).
the operator =../2 (univ operator) creates a predicate from a list (ie: X =.. [foo,4,2]. -> X = foo(4,2)) and the predicate call/1 calls another predicate.
As you can see we use meta-predicates that operate on other predicates.
For an total order on infinite sets things get more complicated since we cannot check every single pair as we did before. I dont even think that it can be written since proving that a relationship is a total order isn't something trivial.
Still, this doesnt declare that a predicate is a total order; it just checks if it is.
So I believe your question is the best way to represent the relation between these 3 people. If you don't actually care about their wealth #'s, just their relative order, you could add predicates like this -
is_richer(tim, anna).
is_richer(anna, jack).
and then a predicate to find all people who X is richer than -
richer(X, Z) :-
is_richer(X, Z).
richer(X, Z) :-
is_richer(X, Y),
richer(Y, Z).
If your is_richer predicate contains cycles though (in this example, if you added is_richer(jack, tim)), this could explode. You need to track where you have visited in this tree.
An example run of richer would be:
?- richer(X, Y).
X=tim
Y=anna ;
X=anna
Y=jack ;
X=tim
y=jack ;
no