How can I ask questions on a family tree in Prolog? - prolog

I'm currently trying to learn how to use Prolog. I have SWI-Prolog version 6.2.6 installed.
It seems to run:
?- 3<4.
true.
?- 4<3.
false.
As a first example, I was trying to implement the possibility of asking questions about a family tree. So I've started with this, stored in family.pl:
father(bob,danna).
father(bob,fabienne).
father(bob,gabrielle).
mother(alice,danna).
mother(alice,fabienne).
mother(alice,gabrielle).
father(charlie,ida).
father(charlie,jake).
mother(danna,ida).
mother(danna,jake).
father(edgar,kahlan).
mother(fabienne,kahlan).
father(hager,luci).
mother(gabrielle,luci).
male(X) :- father(X,_).
female(X) :- mother(X,_).
But when I try to load this with consult(family). I get:
?- consult(family).
Warning: /home/moose/Desktop/family.pl:7:
Clauses of father/2 are not together in the source-file
Warning: /home/moose/Desktop/family.pl:9:
Clauses of mother/2 are not together in the source-file
Warning: /home/moose/Desktop/family.pl:11:
Clauses of father/2 are not together in the source-file
Warning: /home/moose/Desktop/family.pl:12:
Clauses of mother/2 are not together in the source-file
Warning: /home/moose/Desktop/family.pl:13:
Clauses of father/2 are not together in the source-file
Warning: /home/moose/Desktop/family.pl:14:
Clauses of mother/2 are not together in the source-file
% family compiled 0.00 sec, 17 clauses
true.
I don't understand what is the problem here. I've found some results that mentioned that - cannot be used in identifiers, but I didn't use - in an identifier.
Question 1: What causes the Warning from above? How can I fix it?
But there are only warnings, so I've continued with
?- female(fabienne).
true.
?- male(fabienne).
false.
Ok, this seems to work as expected.
Then I've added
male(jake).
female(ida).
female(kahlan).
female(luci).
brother(X,Y):-
male(X),
(mother(Z,X)=mother(Z,Y);father(Z,X)=father(Z,Y)).
and tried:
?- brother(jake,ida).
false.
Why isn't this true?
Question 2: What is the problem with my brother rule?

Your first question is answered here.
As for the second, you're thinking in terms of functions instead of relations.
mother(Z,X) = mother(Z,Y)
is the same as saying X = Y because it compares two terms, without interpreting them. If you want Z to be the mother of both X and Y, you need a conjunction:
mother(Z, X), mother(Z, Y)

the warrning can be fixed if you move all the father and mother declarations together (do not mix them)
In brother definition you use = and you should use a logical AND so use ,(comma)
also you need to tell prolog that jake is a male because he can't figure it out from those rules
I split the brother definition in 2 because is more clear and this is like a logical OR (the first definition is valid or the second one)
father(bob,danna).
father(bob,fabienne).
father(bob,gabrielle).
father(charlie,ida).
father(charlie,jake).
father(edgar,kahlan).
father(hager,luci).
mother(alice,danna).
mother(alice,fabienne).
mother(alice,gabrielle).
mother(danna,ida).
mother(danna,jake).
mother(fabienne,kahlan).
mother(gabrielle,luci).
male(jake).
male(X) :- father(X,_).
female(X) :- mother(X,_).
brother(X,Y):-
male(X),
mother(Z,X),mother(Z,Y).
brother(X,Y):-
male(X),
father(Z,X),father(Z,Y).
For test run
brother(X,Y).
for more results you need to add who is male opr female for those childs like I did for jake

Related

Representing truth regarding beliefs in prolog

How to make this (or something similar) work in Prolog:
belief(john,red(apple)).
belief(peter,red(apple)).
X :- belief(john,X), belief(peter,X).
And get true. for the following query (while consulting above):-
?- red(apple).
First, it's useful to define a little helper to capture when all (relevant) persons believe something:
all_believe(Belief) :-
belief(john, Belief),
belief(peter, Belief).
Then you can define, for example:
red(Object) :-
all_believe(red(Object)).
green(Object) :-
all_believe(green(Object)).
And with your given set of beliefs you get:
?- red(apple).
true.
?- green(apple).
false.
This works. It requires you to define similar rules for any term that you want to use as a belief.
You can make this a bit shorter with macro definitions using term_expansion:
term_expansion(declare_belief(Belief),
Belief :- all_believe(Belief)).
This means that every top-level definition in your source code of the form declare_belief(Belief) should be treated as if you had written Belief :- all_believe(Belief) instead (with the variable Belief substituted appropriately).
So now you can just write this:
declare_belief(red(_)).
declare_belief(green(_)).
and it will be treated exactly like the longer definitions for red(Object) and red(Object) above. You will still have to write this kind of declaration for any term that you want to use as a possible belief.
Prolog does not allow the head of a rule to be just a variable. The head must be a nonvar term, whose functor (i.e., name and arity) identifies the predicate being defined. So, a possible solution would be something like this:
true_belief(X) :-
belief(john, X),
belief(peter, X).
belief(john, red(apple)).
belief(peter, red(apple)).
Examples:
?- true_belief(red(apple)).
true.
?- true_belief(X).
X = red(apple).

turning off Redefined static procedure in prolog

anyone of you could tell me how to turn off "Redefined static procedure" warnings?
I red online documentation of swi-prolog and i found this predicate no_style_check(ultimate) that in principle should turn off these warnings, but when i execute this predicate
main:-
no_style_check(singleton),
no_style_check(discontiguous),
no_style_check(multiple),
require,
test_all.
i received this error
ERROR: Domain error: style_name' expected, foundmultiple'
Anyone knows an alternative way to do this or could tell me why i receive this error ?
Thanks in advance!
Prolog is a pretty loosey-goosey language, so by default it warns you when you do certain things that are not wrong per se, but tend to be a good indication that you've made a typo.
Now, suppose you write something like this:
myfoo(3, 3).
myfoo(N, M) :- M is N*4+1.
Then from the prompt you write this:
?- asserta(myfoo(7,9)).
ERROR: asserta/1: No permission to modify static procedure `myfoo/2'
ERROR: Defined at user://1:9
What's happening here is that you haven't told Prolog that it's OK for you to modify myfoo/2 so it is stopping you. The trick is to add a declaration:
:- dynamic myfoo/2.
myfoo(3, 3).
myfoo(N, M) :- M is N*4+1.
Now it will let you modify it just fine:
?- asserta(myfoo(7,9)).
true.
Now suppose you have three modules and they each advertise themselves by defining some predicate. For instance, you might have three files.
foo.pl
can_haz(foo).
bar.pl
can_haz(bar).
When you load them both you're going to get a warning:
?- [foo].
true.
?- [bar].
Warning: /home/fox/HOME/Projects/bar.pl:1:
Redefined static procedure can_haz/1
Previously defined at /home/fox/HOME/Projects/foo.pl:1
true.
And notice this:
?- can_haz(X).
X = bar.
The foo solution is gone.
The trick here is to tell Prolog that clauses of this predicate may be defined in different files. The trick is multifile:
foo.pl
:- multifile can_haz/1.
can_haz(foo).
bar.pl
:- multifile can_haz/1.
can_haz(bar).
In use:
?- [foo].
true.
?- [bar].
true.
?- can_haz(X).
X = foo ;
X = bar.
:- discontiguous does the same thing as multifile except in a single file; so you define clauses of the same predicate in different places in one file.
Again, singleton warnings are a completely different beast and I would absolutely not modify the warnings on them, they're too useful in debugging.

Accepting 2 different colors, but not the same colors

I'm trying out an exercise where I have to write the predicate, colors/2 (or colors(C1,C2) :- ...) that runs like the following:
?- colors(red,blue).
true.
?- colors(red,red).
false.
?- colors(blue,blue).
false.
So, essentially, I have to write my predicate in a manner where it doesn't accept when you enter the same color twice.
I am defining my facts to be:
col(red,blue).
col(purple,orange).
col(green, yellow).
I am making my predicate to be:
colors(X,Y) :- (col(X,Y); col(Y,X)) not (col(X,X); col(Y,Y)).
I don't understand why my predicate won't work. It is returning a syntax error with "Operator Expected." I am saying that it doesn't matter in what order you write the facts. Meaning, you can say colors(red,blue) or colors(blue,red), but you can't query colors with the same name without it returning false.
I would like to know:
Why this isn't a valid expression.
What I can do to fix the problem.
A couple of things:
You're missing a comma (,) before not and not/1 expects a single term in parentheses, so use more parentheses:
colors(X,Y) :- (col(X,Y); col(Y,X)), not( (col(X,X); col(Y,Y)) ).
As #PauloMora indicated, not/1 is deprecated in favor of the ISO \+/1, so better would be:
colors(X,Y) :- (col(X,Y); col(Y,X)), \+ (col(X,X); col(Y,Y)).
Then looking at col(X,X) and col(Y,Y), there are no facts or predicates where col(X,X) would be true (both arguments are the same). So each of these will always be false, and \+ (col(X,X); col(Y,Y)) will always be true. So the expression is superfluous, and your predicate becomes (at least with the pattern established in your current set of facts):
colors(X,Y) :- col(X,Y) ; col(Y,X).
Since you don't have any facts stipulated with matching colors (col(x,x)), then queries like col(red, red) will fail anyway.
Per the recommendation by #false, for an integrity check on equality of X and Y, the appropriate mechanism would be dif(X, Y):
colors(X, Y) :- (col(X, Y) ; col(Y, X)), dif(X, Y).
The parentheses are desired since , has higher precedence than ;. This would guard against the case where you happened to have a fact or predicate col/2 in which both arguments were the same (identical or unified).

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.

How do I add this prolog to my .pl file?

I am just starting to learn prolog. I am learning it for my CS 2300 class. I am trying to learn the basics right now. How do I add a predicate to my .pl file? I am just trying to add a predicate to my .pl file. I am doing this:
married(X,Y) :- married(Y,X).
And I get the errors:
ERROR: Undefined procedure: (:-)/2
ERROR: Rules must be loaded from a file
ERROR: See FAQ at http://www.swi-prolog.org/FAQ/ToplevelMode.tx
Am I supposed to enable this somehow?
This is the given .pl file:
% File FAMILY.PL
% Part of a family tree expressed in Prolog
% In father/2, mother/2, and parent/2,
% first arg. is parent and second arg. is child.
father(michael,cathy).
father(michael,sharon).
father(charles_gordon,michael).
father(charles_gordon,julie).
father(charles,charles_gordon).
father(jim,melody).
father(jim,crystal).
father(elmo,jim).
father(greg,stephanie).
father(greg,danielle).
mother(melody,cathy).
mother(melody,sharon).
mother(hazel,michael).
mother(hazel,julie).
mother(eleanor,melody).
mother(eleanor,crystal).
mother(crystal,stephanie).
mother(crystal,danielle).
parent(X,Y) :- father(X,Y).
parent(X,Y) :- mother(X,Y).
you have to write what are predicates by using word predicates before all predicates.
predicates , clauses are keyword in prolog. you have to use that key word as well.
you can refer this link for family relation program.
http://www.dailyfreecode.com/Code/prolog-find-relations-family-3025.aspx
if you are new to prolog.
predicates
father (symbol,symbol).
clauses
father(michael,cathy).
try this code.
What's happened here is you're trying to enter rules at a query prompt. This is what you're experiencing:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 6.2.6)
Copyright (c) 1990-2012 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- parent(X,Y) :- father(X,Y).
ERROR: Undefined procedure: (:-)/2
ERROR: Rules must be loaded from a file
ERROR: See FAQ at http://www.swi-prolog.org/FAQ/ToplevelMode.txt
?-
Notice that I have the exact same error message there as you do. Prolog distinguishes between queries and consulting database. What you want to do is consult. Put all your stuff into a file and name it family.pl, and then do this:
?- [family].
You should see this result:
% family compiled 0.00 sec, 21 clauses
true.
?-
If you want to enter rules and facts interactively, consult "user" like so:
?- [user].
|: foo(X) :- bar(X).
|: <Ctrl-D>
% user://1 compiled 0.00 sec, 2 clauses
true.
Notice that the <Ctrl-D> there is typing D while holding the Control key down, not literally typing that text.
As for the other answer, it pertains to Visual Prolog only, and therefore has nothing to do with your problem. Many Prologs implement the ISO standard and you can expect them to behave similarly or identically depending on the input. SWI and GNU are some of the more popular ISO Prolog implementations. However, Visual Prolog is a completely different language and should not be called "Prolog" in passing.

Resources