Finding a person with no siblings in prolog - prolog

I'm trying to write Prolog code that calculates how the fortune of man divided between his family members based on Islamic inheritance rules.
One of the cases is that, if a daughter has no siblings from her father she has the right for half of his fortune.
So my question is how to set a rule that tests if the daughter has no siblings from her father.
half(X,Y) :-
father(Y,X),
female(X),
sibling(What to do here?),
read(N),F is N*0.5, write(F).
male(ahmed).
male(adel).
male(hamza).
male(marwan).
female(sara).
female(lobna).
female(ghada).
female(aisha).
female(noor).
parent(aisha,sara).
parent(aisha,hamza).
parent(aisha,ghada).
parent(adel,sara).
parent(adel,hamza).
parent(adel,ghada).
parent(adel,lobna).
parent(marwan,noor).
sibling(X,Y):-parent(Z,X), parent(Z,Y), X\=Y.
father(X,Y):-male(X), parent(X,Y).
mother(X,Y):-female(X), parent(X,Y).
brother(X,Y):-male(X), (sibling(X,Y);sibling(Y,X)).
sister(X,Y):-female(X), (sibling(X,Y); sibling(Y,X)).
half(X,Y):-father(Y,X),female(X),sibling(X,_),read(N),F is N*0.5, write(F).

Personally, I'd add a few more rules to make the intent clearer - e.g.:
daughter(D,P) :- parent(P,D), female(D).
And you can create a rule which specifically checks to see if someone has any siblings:
has_sibling(X) :- sibling(X,_).
You can then write a rule called, say, eligible_half\2 to check for eligibility --
eligible_half(D,F) :- father(F,D), daughter(D,F), \+ has_sibling(D).
It looks like you've done the opposite of this in your definition of half/2 at the bottom of your code, though - your definition requires that the daughter does have a sibling.
At any rate, this means you can write a definition of half\2 which doesn't itself define any logical rule, but just checks that eligible_half\2 holds and does some I/O:
half(D,F):-
eligible_half(D,F),
read(N), number(N), HalfN is N*0.5, write(HalfN).
And as #lurker noted, you don't need to have the symmetric calls to sibling\2 in your definition of brother\2 and sister\2. Hopefully that's of use.

Related

Learning Prolog (cuts, lists, negation) push me in the right direction

I have the following base knowledge:
“NBA players over 30 years old that have won at least 3 NBA championships are superstars. NBA players below 30 are superstars only if they appear on the front cover of a videogame or if they have at least 5 million followers in Twitter.”
Define a unary predicate superstar that gives only one answer (true/false) to each query, when applied to a concrete person, e.g. superstar(pauGasol). The rules should only check a fact once (for instance, they should not check the age of the queried person twice). You can’t use the “;” operator.
You can use these data in your tests (4 of these 8 players are superstars, according to the previous definition):
age(kobeBryant,37).
championships(kobeBryant,5).
millionsFollowers(kobeBryant,9).
age(pauGasol,35).
championships(pauGasol,2).
videogameCover(pauGasol).
millionsFollowers(pauGasol,3).
age(marcGasol,31).
videogameCover(marcGasol).
millionsFollowers(marcGasol,1).
age(stephenCurry,28).
championships(stephenCurry,1).
videogameCover(stephenCurry).
millionsFollowers(stephenCurry,5).
age(klayThompson,26).
championships(klayThompson,1).
age(kevinDurant,27).
millionsFollowers(kevinDurant,13).
age(russellWestbrook,27).
videogameCover(russellWestbrook).
millionsFollowers(russellWestbrook,3).
age(dwayneWade,29).
championships(dwayneWade,3).
millionsFollowers(dwayneWade,4).
So what i did was this:
superstar(X):- age(X,Y), Y>=30, championships(X,Z), Z>=3,!.
superstar(X):- age(X,Y), Y=<30, videogameCover(X),!.
superstar(X):- millionsFollowers(X,Z), Z>=5.
We learned lists, cuts and negation last lesson.
Could someone push me in the right direction as to what should i use, so the age is only checked once, and if it's greater then 30 goes one way less then 30 goes other way, im new to prolog and programming in general.
I am not asking for a solution, I am asking for a push, hint.
When i will figure it out, I will post the solution my self hopefully.
The request to access only once a DB table normalizes the AND/OR search tree. You could introduce a service predicate to discriminate a pre-condition.
superstar(X) :- age(X,Y), age_check(X,Y).
now, using the cut, you can actually commit to a branch
age_check(X,Y) :- Y>=30, !, championships(X,Z), Z>=3.
% other 2 rules for age_check, actually not using Y
or, avoid the cut, but use a correct domain disjunction:
age_check(X,Y) :- Y>=30, championships(X,Z), Z>=3.
age_check(X,Y) :- Y<30, etc etc
...
in the end i did it like this:
superstar(A) :- age(A,B), B>=30, !, championships(A,C), C>=3.
superstar(A) :- videogameCover(A),!.
superstar(A) :- millionsFollowers(A,B), B>=5.
This is how the teacher wanted it to be, seems like that is way to complicated for something that can be done simpler:
trichampion(X) :- championships(X,Z), Z>=3.
socialmediastar(X) :- millionsFollowers(X,Z), Z>=5.
superstar(X) :- age(X,Y), Y>=30,!,trichampion(X).
superstar(X) :- videogameCover(X),!.
superstar(X) :- socialmediastar(X).

Is there a way to annotate the parameter and return value in Prolog?

parent(mel, joan).
parent(jane, betty).
parent(jane, tom).
parent(richard, adam).
parent(richard, rosa).
parent(joan, fran).
For example someone asks me to find all ancestors of a parent. I give him the code:
ancestor(P,C) :- parent(P, C).
ancestor(P,C) :- ancestor(P,P1), parent(P1, C).
But my friend still doesn't know how to use the predicate. Does he call it like
ancestor(richard, C) or ancestor(C, richard) ?
Is there a way to annotate that P is the parameter while C is the return value? And in a complex case, there will be predicates with different names, how should my user know which predicate is the final predicate he wants to use?
To help the human-readable meaning, you could add an extra predicate documenting the parameters as readable name/value pairs:
entry_ancestor_of(ancestor=P, descendent=C) :-
ancestor(P,C).
?- entry_ancestor_of(ancestor=richard, descendent=C).
C = adam .
Above, the suffix *ancestor_of* suggests param 1 is ancestor of param 2, so naming the predicate carefully can make it clearer.
Usually(convention), input parameters are the earlier parameters, and output parameters are later parameters, but where the predicate 'works both ways', ie. either could be input or output, this rule can't hold. This is the case for your predicate:
?- entry_ancestor_of(ancestor=X, descendent=adam).
X = richard .
Either parameter could be input or output, so there is no need to codify/explain them as such, although you might want to comment that it works both ways.
I would usually comment these 'flexible' predicates by putting an example of both of the above usages in a comment next to the predicate.
For entrypoint labelling, just do one or more of the following:
explicitly name the predicate as an entrypoint, as above
document using comments in the code which are the entrypoints
arrange the entrypoints in the same physical section with a comment
block saying that the predicates below are entrypoints.
Edit: Extra things re: coding guidelines / other answers.
In Coding guidelines for Prolog, section 3.8, it says 'For example, mother_of(A, B) is ambiguous;', so I gave bad advice on that.. perhaps acapelli's suggestion would be more useful on that.
In that document, also have a look at:
3.5 Choose sensible names for auxiliary predicates
3.8 Choose predicate names to help show the argument order
3.13 Decide whether predicate names should carry the types on which they operate
4.1 Begin every predicate (except perhaps auxiliary predicates) with an introductory comment in a well-defined format
The '?' system for identifying parameter types that will ness mentioned is on page 21.
a useful convention, sponsored for instance by Markus Triska, builds a predicate functor by joining the parameters 'names' - in a wide, applicable sense. Your example could be
parent_child(mel, joan).
...
ancestor_descendant(P, C) :- parent_child(P, C).
ancestor_descendant(A, D) :- ancestor_descendant(A, I), parent_child(I, D).
Also ISO-Prolog, and - for instance - SWI-Prolog library, attempt to follow this strategy.
For instance
atom_codes(Atom, Codes) :- ...
WRT to declare the type and status of arguments, some Prolog provide declarations - for instance Turbo Prolog, ECLiPSe, others... Sometime such declarations are required - usually to check correctness, often to speed up the computation.
SWI-Prolog offers 'just' structured comments, that IDE process automatically, and there has been a contribution aiming to exploit such declarations with runtime check.
Yes, with comments, and/or meaningful argument names,
% ancestor( ?Ancestor, ?Descendent).
ancestor(P,C) :- parent(P, C).
ancestor(P,C) :- ancestor(P,P1), parent(P1, C).
? means the argument can be used both as input (already set when the call is made), or for output (not yet set when the call is made).
The convention promoted in The Art of Prolog (I think) is that you place the name of the predicate after its first argument, to get at the intended argument ordering: P "is" ancestor C. Presumably "ancestor_of". But if you use that name, someone unfamiliar with that convention might read ancestor_of(P,C) as "ancestor of P is C", so it's a double-edged sword.

State facts with unbound variables

How would I state things "in general" about the facts? Suppose I need to state "everyone likes the person who likes him/her", and I have a list of people who may or may not like each other.
This is what I tried so far, but it's sure not the way to do it:
likes(dana, cody).
hates(bess, dana).
hates(cody, abby).
likes(first(Girl, OtherGirl), first(OtherGirl, Girl)).
hates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).
because this won't even compile.
everybody([dana, cody, bess, abby]).
likes_reflexive(dana, cody).
hates(bess, dana).
hates(cody, abby).
likes_reflexive(X, Y):- likes(X, Y), likes(Y, X).
hates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).
%% likes_reflikes_reflexive(X, Y):- likes(X, Y), likes(Y, X).
%% user:6: warning: discontiguous predicate likes_reflexive/2 - clause ignored
%% hates(Girhates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).
%% user:8: warning: discontiguous predicate hates/2 - clause ignored
Unfortunately I don't understand what the warnings say. Hope it makes my intention more clear. I.e. by stating one fact, I also want to state the other related fact.
If you want to change your knowledge base dynamically, you can use asserts. If you want to modify existing predicate, you should define it as dynamic, e.g. :- dynamic(likes/2).. If predicate is undefined, you can omit it.
add_mutual_likes(X, Y) :- asserta(likes(X, Y)), asserta(likes(Y, X)).
:- initialization(add_mutual_likes(dana, cody)).
initialization/1 calls add_mutual_likes(data, cody) goal when file is loaded. add_mutual_likes/2 adds two facts to a database. asserta/1 converts it's argument into a clause and adds it to a database.
| ?- [my].
yes
| ?- listing(likes/2).
% file: user_input
likes(cody, dana).
likes(dana, cody).
yes
| ?- likes(cody, dana).
yes
| ?- likes(dana, cody).
yes
| ?- add_mutual_likes(oleg, semen).
yes
| ?- listing(likes/2).
% file: user_input
likes(semen, oleg).
likes(oleg, semen).
likes(cody, data).
likes(data, cody).
yes
I use gprolog.
Let's start with the warnings. They are merely "style" suggestions. They are telling you that all the definitions for likes and hates should be together. Trust me if you have a big Prolog program it becomes a nightmare to go around tour code to get the full definition of your predicate. It would be like writing half a function in C++ and finish it in another file.
Now, you want to say "everyone likes the person who likes him/her". I'm not sure why you are using that function "first" in the code. This would be sufficient:
likes(dana, cody).
likes(Girl, OtherGirl) :- likes(OtherGirl, Girl).
The second clause reads "Girl likes OtherGirl if OtherGirl likes Girl. This won't work.
If you ask your program "is it true that cody likes dana"
? likes(cody, dana)
Prolog will reason like this:
The answer is yes if dana likes cody (using the second clause).
Yes! Because dana likes cody (using the first clause).
This is not enough to make it a correct program. Since we are in Prolog you can say: "give me another solution" (usually by entering ";" in the prompt).
Prolog will think "I only used the first clause, I haven't tried the second".
The answer is Yes also if dana likes cody (using the second clause).
The answer is Yes according to the second clause, if cody likes dana.
But that's our initial query. Prolog will give you the same answer again and again, looping forever if you asked for all the solutions.
You can do two things here. The first is telling Prolog that one solution is enough. You do this adding a "!" (that basically says, clear all the open branches left to explore).
likes(dana, cody) :- !.
likes(Girl, OtherGirl) :- likes(OtherGirl, Girl).
Another alternative is to "stratify the program".
direct_likes(dana, cody).
likes(Girl, OtherGirl) :- direct_likes(OtherGirl, Girl), !.
likes(Girl, OtherGirl) :- direct_likes(Girl, OtherGirl).
What you want is a fact where Prolog does not care about the order of arguments. Alas, something like that does not exist. What you can do instead is define facts where the implied meaning is that it is valid for all argument orders (like_each in the example below). But of course, you cannot use these facts in that way. Instead, you define the actual predicate to try (hence the or ;) all possible argument orders.
Thus, the solution is:
%% bi-directional like
like_each(dana, cody).
likes(A, B) :- like_each(A, B); like_each(B, A).
%% optional: one-directional like
% likes(cody, sarah).
Also, be careful with
hates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).
If both variables are unbound (e.g., ?- hates(A,B)), it will always fail. This happens because Prolog first tries to find a match for likes, which always succeeds for two variables, and then negates the result. Thus, you cannot use hates to find all pairs who don't like each other.

User input in prolog

I want to write a program that sets cold to true if the user enters winter and sets warm to true if the user enters summer. This is what I have so far:
start :- write('What season is it?: '), read(X), season(X).
cold :- season(winter).
warm :- season(summer).
However when I query start and enter winter for the season I get an error that season/1 is undefined. To fix this I tried changing my code to the following:
start :- season(X).
season(X) :- write('What season is it?: '), read(X).
cold :- season(winter).
warm :- season(summer).
Now when I query start it asks for the season as expected and I entered winter. I queried cold expecting a return of true since I figured season(winter) would be true, but instead I was again prompted to answer "what season is it?". How can I make this simple program work?
It looks that what you want to do is kind of "forward chaining". So you
want to be able to add a fact to the knowledge base, and then see
additional facts pop up.
Such things were very fashionable in the 80's when expert systems emerged
and can also be done with Prolog. Here is an article roughly describing the
difference between "backward chaining" and "forward chaining":
Logic Programming Associates Ltd.
ProWeb: Expert System
I have tried to remodel something similar to the above forward chaining
via the clause expansion mechanism that is available in many Prolog
systems and via an agenda that is held in the knowledge base as ordinary
facts. The expansion mechanism changes a rule of the following form:
P :- A
Into a rule where X is a fresh variable not occuring in P or A:
delta(X, P) :- A_new(X)
Where A_new is a condition that says that P is new when a new fact
X has arrived. Lets consider your example:
?- ['delta.p'].
?- [user].
:- forward season/1.
:- forward cold/0.
:- forward warm/0.
cold :- season(winter).
warm :- season(summer).
^D
These two Prolog rules would be turned into the following delta/2 rules
via the rewriting. Since the rules are very simple, the delta/2 rules
are also very simple:
?- listing(delta/2).
delta(X, cold) :-
X = season(winter).
delta(X, warm) :-
X = season(summer).
Here is an example session:
?- list.
Yes
?- volunteer(season(winter)).
Yes
?- list.
season(winter).
cold.
Yes
The rewriting in delta.p is very primitive. The rewriting can be enhanced
to support rigid predicates and to support the dynamic removal of facts.
Possible additional application areas of the "forward chaining" are then:
Natural Language Processing
Constraint Solving
Best Regards
The current delta/2 rewriting after a few more years development:
http://www.jekejeke.ch/idatab/doclet/blog/en/docs/15_min/02_reference/minimal/delta.html
An Article showing that a Constraint Store can be modelled:
https://plus.google.com/+JekejekeCh/posts/8oHErwopKxK
P.S.: The predicate name volunteer/1 stems form Nexpert Object,
an expert system shell in use in the 80's and 90's.
NEXPERT OBJECT version 3.0, Jean-Marie Chauvet, Neuron Data, Inc.
P.P.S.: But you might want to lookup newer things, such as Rete-NT, or OWL:
http://answers.semanticweb.com/questions/3304/forward-vs-backward-chaining
Because "cold/0" and "warm/0" take no arguments, it is impossible to change the result at runtime without altering their definition at runtime. The simplest way to do this is just to add or remove the facts "cold." and "warm." depending on user input, using assert/1 and retractall/1.
start :- write('What season is it?: '), read(X), season(X).
season(summer) :- retractall(cold), assert(warm).
season(winter) :- retractall(warm), assert(cold).
While defining the facts, you need to change the syntax a little bit.
start(Y) :- write('What season is it?: '), read(X), nl, season(X,Y).
season(winter,cold).
season(summer,warm).
Note that the user needs to end the input with a full stop. (eg. winter.)
season(winter,cold).
season(summer,warm).
start:-write('What season is it?'),write(' '),read(X),season(X,Y),write(Y).
The output will be look like this:
?- start.
What season is it? winter.
cold
true.

Using And clause in HEAD of a prolog statement

Every member of this club is either educated or rich or both.
I wanted to write a statement very similar to above in my PROLOG code. I wrote everything else.
edu(X);rich(X) :- member(X).
This is what I had written. But then PROLOG doesn't allow any operators in the clause head. I have spent 5 hours till now trying to do various things with this statement but unable to reach a solution that works. :(
See http://en.wikipedia.org/wiki/Horn_clause for am explanation of the form of logic Prolog is based on.
Given your statement, ("Every member of this club is either educated or rich or both."), the only things you can declare to be true are:
A person is educated if they are a member and not rich.
A person is rich if they are a member and not educated.
The following, for example, are not necessarily true:
A person who is rich and educated is a member.
A member who is rich is educated.
A member who is rich is not educated.
You can't combine multiple heads. If you want edu(X) and rich(X) to be true when member(X) is true, you have to define them separately ("every member of this club is educationed" and "every member of this club is rich"):
edu(X) :-
member(X).
rich(X) :-
member(X).
The tricky part is that your original statement is not well-formed. It says that some members may be rich but not educated or vice versa. This is problematic. For example, let's take the naive case that if a member isn't rich, he's educated, and the reverse:
edu(X) :-
member(X), \+ rich(X).
rich(X) :-
member(X), \+ edu(X).
Now, according to these rules, nobody is automatically rich and educated. So long as we define every member as at least one of the two, this is fine. However, consider these facts:
member(alice).
member(bob).
member(charlie).
member(dave).
rich(alice).
edu(bob).
rich(charlie).
edu(charlie).
In this case, rich(alice) works fine, because it's a fact. edu(alice) will result in no. The reverse is true for bob. With charlie, we've defined both as facts, so both are true. But what about dave? Both edu(dave) and rich(dave) refer back to the other, creating an infinite recursion. Without any further knowledge of what you're doing, the best we can do to resolve this is to default either edu(X) or rich(X) to true:
edu(X) :-
member(X).
rich(X) :-
member(X), \+ edu(X).
Now everyone is assumed to be educated unless we explicitly declare otherwise. You could do the same thing defaulting to rich if you preferred. Short of additional information, this is the best you can do.
As a side note: the idea of using disjunctions in heads of clauses has lead to disjunctive logic programming, see, e.g., "Foundations of Disjunctive Logic Programming" by Jorge Lobo, Jack Minker, Arcot Rajaseka. edu(X);rich(X) :- member(X). would be a valid disjunctive clause. A related topic, disjunctive Datalog, has been explored by Nicola Leone, Gerald Pfeifer and Wolfgang Faber in the DLV project: http://www.dbai.tuwien.ac.at/proj/dlv/
Maybe you want to write:
member(X) :- edu(X) ; rich(X)
If someone is educated, rich or both, is a member of the club.

Resources