Prolog negation with more solutions - prolog

I've got a little problem and don't know where to find a solution. You probably heard of problem of flying birds:
bird(eagle).
bird(penguin).
can_fly(penguin):-!,fail.
can_fly(X):-bird(X).
I tried to modify and use this knowledge for some "love story". Imagine this
maried(a, b).
maried(c, d).
lovers(a, d).
likes(X, Y):-maried(X, Y).
Now I want to say something like "If X is maried with Y, but X is Z's lover, then X doesn't like Y, but likes Z".
I tried this:
likes(X, Y) :- lovers(X, Y).
likes(X, Y) :- maried(X, Y), lovers(X, _),!,fail.
likes(X, Y) :- maried(X, Y).
It works unless I want to evaluate a goal
likes(A, B).
If there is more facts in the database and Prolog finds first cheater, it will stop backtracking and I can't find any other solution. Maybe it will be obvious after, but now I have nothing on my mind..
Thanks in advance (and maybe sorry for my English :))

Already your first example is not too useful. You can ask:
is the eagle a bird?
is the penguin a bird?
can the eagle fly?
can the penguin fly?
but you can't even ask, "which birds can fly?":
?- can_fly(Bird).
false.
If you would want to be able to ask more general question, like, "which birds can fly?", or "which birds cannot fly?", you would need to either explicitly list the flying or non-flying birds. As most birds can fly, let's list explicitly the non-flying birds:
bird(eagle).
bird(penguin).
bird(ostrich).
bird(dodo).
bird(sparrow).
bird(pigeon).
flightless_bird(penguin).
flightless_bird(ostrich).
flightless_bird(dodo).
bird_of_pray(eagle).
extinct(dodo).
extinct(wooly_mammoth).
can_fly(Bird) :-
bird(Bird),
\+ flightless_bird(Bird).
extinct_bird(Bird) :-
bird(Bird),
extinct(Bird).
Note the use of the ISO predicate for negation, \+/1. It is true if the goal cannot be proven. It is much cleaner than the fail-cut combination you are using.
How you organize your knowledge is a totally different question. The example I have given is incomplete and not necessarily the best way to do it. As a general rule, you should try to keep your data in a normalized form, with facts and clauses of facts playing the role of tables and table rows.
Hopefully this answer points in the right direction.

The cut-fail thing is an antipattern that's misleading you. It would be much better to say something in the original like this:
bird(eagle).
bird(penguin).
flightless(penguin).
can_fly(X) :- bird(X), \+ flightless(X).
See #boris's answer for an excellent and much more detailed discussion of this problem.
So, you have this database. I'm going to put names in so that I can comprehend it a little better.
married(bill, hillary).
married(barack, michelle).
lovers(bill, michelle).
Now what you want to say is that married people like each other, unless they're cheating. Well, it would be better to define these terms in Prolog so we can reason with them. Create the language we need to use to define our domain. That's going to look like this:
cheating(Cheater, SpitedSpouse, Lover) :-
married(Cheater, SpitedSpouse),
lovers(Cheater, Lover),
SpitedSpouse \= Lover.
Now it's much easier to define likes/2!
likes(Husband, Wife) :- married(Husband, Wife), \+ cheating(Husband, Wife, _).
likes(Husband, Lover) :- cheating(Husband, _, Lover).
We can even define dislikes properly:
dislikes(SpitedSpouse, Lover) :- cheating(_, SpitedSpouse, Lover).
dislikes(Cheater, Spouse) :- cheating(Cheater, Spouse, _).
Look at what we've learned: what you really have is a marriage relationship between two people, or a cheating relationship between three people, and of your other predicates are just projections of these two fundamental relationships. That's pretty neat, yeah? :) cheating/3 is basically the classic "love triangle." That suggests ways we could evolve the program to be more potent: handling love quadrilaterals, of course! And so forth.
Notice something interesting? This code can't "catch" michelle—isn't she just as culpable as bill? This underscores a bigger problem: the gender/orientation limitation of the predicates. I think it helps to have concrete nouns like these to see the logical relationships, but it's a dangerous shortcut that should be resolved. An easy way to handle the logic would be to create a predicate like this:
spouse(X, Y) :- married(X, Y)
spouse(X, Y) :- married(Y, X).
Of course you then have to do more checks to make sure you don't have the same people repeated, but it's not hard, and then change your variables to be less gender-specific.

Related

How would you express mutual exclusion of facts in Prolog?

Suppose you are working with a genealogy database. Some records are missing. You might know that people named "John" were male, and people named "Mary" were female, etc.
male(X) :- first_name(X, "John").
female(X) :- first_name(X, "Mary").
For people with exotic or foreign names, their gender can be unclear, but it must have been one of the two. Marriage (before this century) was between opposite genders.
female(X) :- wed(X, Y), male (Y).
male (X) :- wed(X, Y), female(Y).
Knowing that someone's gender was either male or female (even if you don't know which) is an important tidbit in deciphering identities and relationships.
How would you encode this knowledge in Prolog?
female(X) :- person(X), not(male(X)).
is incorrect, as it makes you conclude that everyone is female unless they can be proven to be male.
incorrect, as it makes you conclude that everyone is female unless they can be proven to be male
This kind of reasoning, slightly refined, is not incorrect. Everyone is potentially female unless they are proven to be male. What else would they be?
possibly_female(Person) :-
person(Person),
\+ proven_male(Person).
possibly_female(Person) :-
proven_female(Person).
possibly_male(Person) :-
person(Person),
\+ proven_female(Person).
possibly_male(Person) :-
proven_male(Person).
Although, depending on what you want to do, rather than using a division into known/possible genders it might be simpler to use a three-way male/female/unknown division:
unknown_gender(Person) :-
person(Person),
\+ proven_female(Person),
\+ proven_male(Person).
(Lots of caveats about gender binarism apply to the real world, though arguably if you're really modeling historical databases based on a binary assumption, it's reasonable to use that model.)
You are making a ton of assumptions about many things. The question is more complicated than it needs to be because of this.
In your case, "is not known to be male" is not enough for "is female", you say. But you also say, "is not known to be male AND is married to a male" is enough.
In some hypothetical program (which we don't have in your question, so it isn't really reproducible) you would maybe write:
is_female(X) :- female(X).
is_female(X) :- \+ is_male(X), married_to(X, Y), is_male(Y).
There is stuff that came from filling in the blanks in your question. Is there need for female/1 and for is_female/1? It depends. Etc

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

Unbroken loops loops

Hi I have this problem that I can not solve.
I am a Prolog rookie and I've seen a ton of these family tree examples but none seem to address my problem.
Say I have
son(X, Y) :-
\+daughter(X, Y),
father(Y, X).
father(Y, X) :-
male(X),
son(X, Y).
and I call one of them, it will go back and forth between the conditions because each one would satisfy the one before, therefore resulting in a local stack error.
Most seem to recommend removing one of the definitions, but I need to answer father and son queries. Please, help, this seems so simple, but I just can not figure it out. How can I break after looping once?
TIA
You could:
1) you could use a wrapper predicate:
father(Y,X):-
male(X),
son_data(X,Y).
son(X,Y):-
son_data(X,Y).
son(X,Y):-
\+daughter(X, Y),
father(Y, X).
your database should look like
son_data(mike,steph).
....
father(nick,john).
....
(no son/2 entries)
2) use a prolog version that supports tabling (such as XSB) (or implement it; not such a good idea ofc)

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