Creating a mutually exclusive or in prolog - prolog

Say you have a group of people who played chess. You want to determine if a player exists who never lost to anybody (undefeated). Suppose the facts are given as won(james, tom). won(james, peter), won(craig, tom). lost(peter, tom). Then a player X has never lost according to the conditions.
undefeated(X) :- \+ won(_, X), \+ lost(X, _).
so undefeated(james) is true and undefeated(craig) are true but undefeated(tom) and undefeated(peter) are false. Now the problem arises when calling undefeated(X) as this will simply return no. To resolve this we want a statement that is always true at the start so we add facts whiteplayer() and blackplayer() for a player who plays white and black pieces respectively.
whiteplayer(james).
whiteplayer(craig).
whiteplayer(tom).
whiteplayer(peter).
blackplayer(james).
blackplayer(peter).
blackplayer(tom).
and change undefeated to:
undefeated(X) :- (whiteplayer(X); blackplayer(X)), \+ won(_, X), \+ lost(X, _).
But now we run into a new problem. Querying undefeated(X) gives solutions james, craig, james, this happens since james plays both white and black pieces but craig only plays white pieces. So the problem is undefeated(james) is proceeding to continue for both whiteplayer(james) and blackplayer(james), how can I make it so that it only proceeds for one of these while backtracking?

If your facts and rules allow a specific instantiation of variables to succeed multiple ways, you're going to get duplicates unless you use a cut (which also then generally eliminates valid solutions, which is not desirable), or you can collect the redundant subsolutions using setof (or "manually") which eliminates duplicates.
So you can do something like this:
validplayer(X) :- whiteplayer(X) ; blackplayer(X).
undefeated(Player) :-
setof(P, validplayer(P), Players),
member(Player, Players),
\+ won(_, Player), \+ lost(Player, _).
Ideally, it's better if you can define validplayer/1 such that it succeeds once for any given player and doesn't cut. But your current definition of facts don't enable this.
I would also suggest you shouldn't need both won/2 and lost/2 facts, since won(X, Y) is equivalent to lost(Y, X). It's best to stick with one or the other. Hopefully, your database doesn't have both won(john, paul) and lost(paul, john) or the above solution will still yield duplicates and you'd need to do the setof/3 on undefeated/1: setof(U, undefeated(U), ListOfUndefeatedPlayers).

If you know that there is atleast one person who won from X then X is not undefeated. Simply you just try to find atleast one Z such that Z won from X.If this happends then it means that prolog finds a match and it will try to return true and you just invert that value in false and cut all other branches.
Same goes for one who is not undfeated. In this case prolog find no match and returns false without inverting it's value.
This is your code if i understood your questionr right btw it's always good to use guitracer to see what's going on.
won(james,tom).
won(james,peter).
won(craig,tom).
lost(peter,tom).
undefeated(X):-
\+ won(_Z,X),!.

Related

What am I missing about equality and unification in Prolog?

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.

Prolog: deduction given that items can be in exactly one of two sets, with set sizes known

I have 5 people in a room. I'll be writing rules to determine whether the people are happy or sad. However, before I even start with that, I have the overlying knowledge that - of the 5 - exactly 3 are happy and 2 are sad (and none can be both). It should therefore be possible to make deductions based on this: if - by any means - I know who the three happy people are, then I can deduce the two sad people, and vice versa.
What I've got so far is as follows:
person(bob).
person(tim).
person(steve).
person(roy).
person(jack).
sad(bob).
sad(tim).
happy(X) :-
person(X),
\+ sad(X),
findall(Y, sad(Y), YS),
length(YS, 2).
When asked happy(X), Prolog will give me Roy, Steve and Jack, because it already knows who the two sad people are. Problem: I'm unable to define a sad/1 rule in the same manner, because of the mutual recursion with happy/1. I want to be able to add in rules such that the outcome in the above example remains the same, yet the following initialisation would list Bob and Tim as sad:
person(bob).
person(tim).
person(steve).
person(roy).
person(jack).
happy(steve).
happy(roy).
happy(jack).
Is there a better way I should be thinking about this? It's important that I'll be able to go on to later write more rules for sad/1 and happy/1, adding additional logic beyond the fact that deduction should be possible based on the knowledge that the 5 are split into 3 happy and 2 sad.
How about using clpb?
:- use_module(library(clpb)).
Sample query:
?- Hs = [Bob,Tim,Steve,Roy,Jack],
sat(card([3],Hs)), % exactly three are happy.
(
Who = sad, sat(~H_bob * ~H_tim) % specify the sad ones ...
; Who = happy, sat(H_jack * H_roy * H_steve) % ... OR the happy ones?
),
labeling(Hs).
Who = sad, Bob = 0, Tim = 0, Jack = 1, Roy = 1, Steve = 1, Hs = [0,0,1,1,1]
; Who = happy, Bob = 0, Tim = 0, Jack = 1, Roy = 1, Steve = 1, Hs = [0,0,1,1,1].
Sorting the logic out is a matter of consistency and avoiding conflicting meanings of a given predicate or fact.
Your definition of sad/1 is currently a fact that results in one result for each backtrack to the query, sad(X). But your definition of happy/1 generates a list. That leaves you with how you want to define sad/1 to generate a list, which would be in conflict with your current definition of sad/1 as a query that is true if the argument is a sad person.
A more consistent approach would be define happy/1 to behave the way sad/1 behaves:
happy(X) :-
person(X),
\+ sad(X).
Then you can define your list versions:
happy_all(A) :-
findall(X, happy(X), A).
sad_all(A) :-
findall(X, sad(X), A).
Now the above assumes you have explicit facts for person/1 which defines the universe of all valid people, and sad/1 which defines who the sad ones are. It also assumes that if a person isn't sad, then they must be happy.
You could flip this around and explicitly define happy people with happy/1 facts, then define sad/1 in terms of people not being happy assuming that a person must be happy if they aren't sad:
sad(X) :-
person(X),
\+ sad(X).
And the happy_all/1 and sad_all/1 predicates will still apply.
If you want to mix your facts with happy/1 and sad/1, this can create a consistency issue: (1) cases where a person isn't defined as happy or sad... then what are they? and (2) what if a person is defined as both happy and sad?
Semantically, you may want to define both sad/1 and happy/1 explicitly if you are also allowing for someone not being either happy or sad. You can do this:
person(bob).
person(tim).
person(steve).
person(roy).
person(jack).
sad(bob).
sad(tim).
happy(steve).
happy(roy).
happy_all(A) :-
findall(X, happy(X), A).
sad_all(A) :-
findall(X, sad(X), A).
But not define predicates for happy/1 or sad/1 since they are already facts. That keeps things simple. We just don't know if jack is happy or sad.
But what if we want to say that if a person isn't happy or sad, then they must be happy and add that rule back in. To avoid the looping you mentioned, we don't to be mixing rule names with fact names. In that case:
person(bob).
person(tim).
person(steve).
person(roy).
person(jack).
sad(bob).
sad(tim).
happy(steve).
happy(roy).
% A person is happy if they are, in fact, happy
happy_person(X) :-
happy(X),
% A person is happy if they are neither happy or sad
happy_person(X) :-
person(X),
\+ happy(X),
\+ sad(X).
% A person is sad if they are, in fact, sad
sad_person(X) :-
sad(X).
% Who are all the happy people?
happy_all(A) :-
findall(X, happy_person(X), A).
% Who are all the sad people?
sad_all(A) :-
findall(X, sad_person(X), A).

Prolog taking inverse of a predicate

I got a database that looks like
hasChild(person1, person2).
hasChild(person1, person3).
hasChild(person4, person5).
Which means that (for example) person1 has child named person2.
I then create a predicate that identifies if the person is a parent
parent(A):- hasChild(A,_).
Which identifies if the person is a parent, i.e. has any children
Then I try to create a predicate childless(A) that should return true if the user doesn't have any children which is basically an inverse of parent(A).
So I have 2 questions here:
a) is it possible to somehow take an "inverse" of a predicate, like childless(A):-not(parent(A)). or in any other way bypass this using the hasChild or any other method?
b) parent(A) will return true multiple times if the person has multiple children. Is it possible to make it return true only once?
For problem 1, yes. Prolog is not entirely magically delicious to some because it conflates negation and failure, but you can definitely write:
childless(X) :- \+ hasChild(X, _).
and you will see "true" for people that do not have children. You will also see "true" for vegetables, minerals, ideologies, procedures, shoeboxes, beer recipes and unfeathered bipeds. If this is a problem for you, a simple solution is to improve your data model, but complaining about Prolog is a very popular alternative. :)
For problem 2, the simplest solution is to use once:
parent(A) :- once(hasChild(A, _)).
This is a safer alternative to using the cut operator, which would look like this:
parent(A) :- hasChild(A, _), !.
This has a fairly significant cost: parent/1 will only generate a single valid solution, though it will verify other correct solutions. To wit:
?- parent(X).
X = person1.
Notice it did not suggest person4. However,
?- childless(person4).
true.
This asymmetry is certainly a "code smell" to most any intermediate Prolog programmer such as myself. It's as though Prolog has some sort of amnesia or selective hearing depending on the query. This is no way to get invited to high society events!
I would suggest that the best solution here (which handles the mineral/vegetable problem above as well) is to add some more facts about people. After all, a person exists before they have kids (or do they?) so they are not "defined" by that relationship. But continuing to play the game, you may be able to circumvent the problem using setof/3 to construct a list of all the people:
parent(Person) :-
setof(X, C^hasChild(X, C), People),
member(Person, People).
The odd expression C^hasChild(X, C) tells Prolog that C is a free variable; this ensures that we get the set of all things in the first argument of hasChild/2 bound to the list People. This is not first-order logic anymore folks! And the advantage here is that member/2 will generate for us as well as check:
?- parent(person4).
true.
?- parent(X).
X = person1 ;
X = person4.
Is this efficient? No. Is it smart? Probably not. Is it a solution to your question that also generates? Yes, it seems to be. Well, one out of three ain't bad. :)
As a final remark, some Prolog implementations treat not/1 as an alias for \+/1; if you happen to be using one of them, I recommend you not mistake compatibility with pre-ISO conventions for a jovial tolerance for variety: correct the spelling of not(X) to \+ X. :)
Here's another way you could do it!
Define everything you know for a fact as a Prolog fact, no matter if it is positive or negative.
In your sample, we define "positives" like person/1 and "negatives" like childless/1. Of course, we also define the predicates child_of/2, male/1, female/1, spouse_husband/2, and so on.
Note that we have introduced quite a bit of redundancy into the database.
In return, we got a clearer line of knowns/unknowns without resorting to higher-order constructs.
We need to define the right data consistency constraints:
% There is no person which is neither male nor female.
:- \+ (person(X), \+ (male(X) ; female(X))).
% Nobody is male and female (at once).
:- \+ (male(X), female(X)).
% Nobody is childless and parental (at once).
:- \+ (childless(X), child_of(_,X)).
% There is no person which is neither childless nor parental.
:- \+ (person(X), \+ (childless(X) ; child_of(_,X))).
% There is no child which is not a person.
:- \+ (child_of(X,_), \+ person(X)).
% There is no parent which is not a person.
:- \+ (child_of(_,X), \+ person(X)).
% (...plus, quite likely, a lot more integrity constraints...)
This is just a rough sketch... Depending on your use-cases you could do the modeling differently, e.g. using relations like parental/1 together with suitable integrity constraints. YMMY! HTH

Prolog - Rules are correct, but not outputting the way it's supposed to?

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.

Prolog — symmetrical predicates

I have to simulate family tree in prolog.
And i have problem of symetrical predicates.
Facts:
parent(x,y).
male(x).
female(y).
age(x, number).
Rules:
blood_relation is giving me headache. this is what i have done:
blood_relation(X,Y) :- ancestor(X,Y).
blood_relation(X,Y) :- uncle(X,Y)
; brother(X,Y)
; sister(X,Y)
; (mother(Z,Y),sister(X,Z))
; (father(Z,Y),sister(X,Z))
; (father(Z,Y),brother(X,Z)).
blood_relation(X,Y) :- uncle(X,Z)
, blood_relation(Z,Y).
and I am getting i think satisfactory results(i have double prints - can i fix this), problem is that i want that this relation be symmetrical. It is not now.
blood_relation(johns_father, john):yes
blood_relation(john,johns_father): no
so..is there a way to fix this.
And i need query: All pairs that are not in blood_relation..
Update:
What kinds of relationships is the first statement supposed to satisfy?
blood_relation(X,Y):-blood_relation(X,Y).
sorry..it is a bad copy/paste..it
blood_relation(X,Y):-ancestor(X,Y).
Now fixed above.
here are other rules:
father(X,Y) :-
parent(X,Y),male(X).
mother(X,Y) :-
parent(X,Y),female(X).
brother(X,Y) :-
parent(Z,X),parent(Z,Y),
male(X).
sister(X,Y) :-
parent(Z,X),parent(Z,Y),
female(X).
grandFather(X,Y) :-
parent(Z,Y),parent(X,Z),
male(X).
grandMother(X,Y) :-
parent(Z,Y),
parent(X,Z),female(X).
uncle(X,Y) :-
mother(Z,Y),brother(X,Z).
ancestor(X,Y) :-
ancestor(X,Y).
ancestor(X,Y) :-
parent(X,Z),ancestor(Z,Y).
Mother's brother is in uncle definition. It's kind of strange. I've got rules that I need to implement, and I don't know how I can implement rules besides that. I'm just confused.
Any idea how to make blood_relation symmetric? And not_blood_relation is a new rule. And I need query. This one is really giving me headache. Maybe because relation is written like crap.
And there are no more facts. That's all. All rules, and all facts.
query.. not(blood_relation(X,Y)) doesn't work, and I really don't know why.
For example query:
age(X,Y), Y>18,
not(parent(X,Z)),write(X),nl,fail.
works just fine
The naive solution to making a particular predicate symmetric isn't that far from a decent one. For the sake of generality, let's look at a friendship relation so people don't get tripped up on uncles and the like.
Here are some facts detailing a friendship relation (where, say, the numbers are user ids and the particular ordering of the arguments came from who initiated the friendship).
friends(1,2).
friends(5,2).
friends(7,4).
You'd initially think a rule like "friends(A,B) :- friends(B,A)." would fix things right up, but this leads you to infinite recursion because it tells prolog that if it just swaps the argument one more time it might just work. There is a predicate called "#</2" that tells you whether one term (even a variable) comes before another in the "standard order of terms". The technical meaning isn't all that important here, but what we care about is that for two different terms it is only true for one ordering of them. We can use this to break the infinite recursion!
This single rule will take care of making "friend/2" symmetric.
friends(A,B) :- A #< B, friends(B,A).
As neat as this is, there is an approach way you should take for large projects. Recall that the ordering of the args in my list of facts had some actual meaning (who initiated the friendship). Adding the final rule destroyed future access to this information and, for other people reading the code, hides the symmetric property in a single line of code which is easy to ignore in the face of a block of hard-coded data.
Condsider the industrial-strength solution:
friended(1,2).
friended(5,2).
friended(7,4).
friends(A,B) :- friended(A,B).
friends(A,B) :- friended(B,A).
It is bulkier, but it reads cleanly without using obscure predicates and retains the original information (which you might want again someday in a real application).
--
As for finding pairs that don't have a specific property, make sure you always include some predicate to provide context in your rule when you use negation to look for actual individuals.
potential_enemies(A,B) :- user(A), user(B), \+ friends(A,B).
A bit looks like a homework, isn't it...
One trick which most of beginners of prolog don't think of is list pattern matching. Think of a tree like [a1,[[a2],[b2,[[e3],[f3]]],[c2]]] as in <tree>=[root,[<tree1>,<tree2>,...]]:
%Y is immediate child of X?
child(X,Y,[X|S]) :- member([Y|_],S).
%pick one tree in S and check
child(X,Y,[X|S]) :- member([Z|SS],S),child(Z,Y,[Z|SS]).
%X and Y end up with same root?
sib(X,Y,[R|T]) :- child(R,X,[R|T]), child(R,Y,[R|T]).
I think you can improve upon this like, using pairs as roots, adding genders, giving names to specific relations of members of the tree...
What kinds of relationships is the first statement supposed to satisfy?
blood_relation(X,Y):-blood_relation(X,Y).
That isn't telling you anything that you don't already "know" and is going to cause you recursion headaches. As for the 'no' answer, is looks like you've already gotten all of the answers from the query that you are going to get, and the interpreter is just telling you that there aren't any more.
You really should post more facts, and the definition of uncle/2, and is there a reason why you're not matching a mother's brother, just her sister? You have lots of other issues to work on :-).
For everything that is not a blood relation, try this:
not_blood_relation(X, Y) :- blood_relation(X, Y), !, fail.
not_blood_relation(X, Y).
And ask yourself why it works!

Resources