To complete this lab you will need to either ssh to student.cs.uni.edu or use the Linux boot in one of the Wright Hall labs. In either case, your name/password is the one you use for the homework submission system. Alternately, you can download one of the Windows implementations and try it on windows from home, but be aware that some flavors of Prolog have slightly different syntax and your final deliverable must work on the lab machines.
Introduction
In class the other day I briefly demonstrated how to use Prolog in the labs. In this homework you will first walk through a simple tutorial for using Prolog. Second, you will create a simple knowledge base in Prolog and be asked it to prove some simple facts.
Disclaimer - This Homework is loosely based on an online tutorial by James Power.
Firstly, we want to type in a Prolog program and save it in a file, so, using the Text Editor of your choice (emacs, vi, or some graphical editor from the "start" menu), type in the following prolog program:
likes(mary,food).
likes(mary,wine).
likes(steve,wine).
likes(steve,mary).
likes(john,wine).
likes(john,mary).
Once you have typed this in, save it as intro.pl (Prolog files usually end with ".pl", just as Java files end with ".java")
Begin a Konsole session (the icon with a Shell). Start Prolog at the command prompt; by typing 'prolog' After a while, you should get something like the following on screen:
GNU Prolog 1.2.9
By Daniel Diaz
Copyright © 1999-2001 Daniel Diaz
|| ?-
Prolog is now running and waiting for you to type in some commands.
Writing programs in Prolog is a cycle involving
1. Write/Edit the program in a text-editor
2. Save the program in the text editor
3. Tell Prolog to read in the program
4. If Prolog gives you errors, go back to step 1 and fix them
5. Test it - if it doesn't do what you expected, go back to step 1
We've done the first two of these, so now we need to load the program into Prolog. The program has been saved as "intro.pl", so in your Prolog window, type the following and hit the return key:
[intro].
Don't forget the full-stop at the end of this!
This tells Prolog to read in the file called intro.pl - you should do this every time you change your program in the text editor. (If your program was called something else, like "other.pl", you'd type "other" instead of "intro" above).
You should now have something like the following on screen
| ?- [intro].
compiling /user/username/intro.pl for byte code
/user/username/intro.pl compiled, 4 lines read- 554 bytes written, 12 ms
yes
|| ?-
The "yes" at the end indicates that Prolog has checked your code and found no errors. If you get anything else (particularly a "no"), you should check that you have typed in the code correctly.
We can now ask Prolog about some of the information it has just read in. The simplest thing that we can ask is whether a given fact is known in the knowledge base. Type in the following (and don't forget the full-stop at the end: Prolog won't do anything until it sees a full-stop)...
? likes(mary,food).
When you do this you should get
true ?
The term "true" means that it has matched your "query" and that fact is know. The question mark, however, may confuse you. This isn't there because Prolog is questioning whether the fact is true. Interestingly, Prolog does not consider this "query" to be a done deal yet. The question mark tells you that you have to tell the system what to do next. The standard choice is to hit the semicolon key. This tells the computer you wish to see any additional facts pertaining to your query. Since there aren't any, it quits and returns "no." Indicating there are no additional facts. This is a little bit confusing because you might mistake this to mean that the knowledge base does not "entail" your query. However, the REAL answer is the true. For the most part, you will ignore the yes/no answers.
Repeat this process for each of the following. What do you observe for
each?
? likes(john,wine).
? likes(john,food).
Suppose you are interested in asking more generic questions. For example, suppose you want to query the knowledge base about what things john likes. You can do this by entering...
? likes(john,X).
(notice that variables in Prolog start with an uppercase letter. OFTEN we simply use a single letter such as X. However, any term starting with a lowercase letter is a ground term, and any term starting with an uppercase letter is a variable.)
Notice that the first time you do this you receive the binding
X=wine ?
This means that ONE fact that is known is that john likes wine. Pressing the semicolon asks the program to continue, and this time produces the binding
X=mary ?
Thus, we know that john like several things.
Repeat with...
? likes(mary,X).
? likes(Y,food).
? likes(Y,wine).
Now is a good place to take a break if you need to. When you want to leave Prolog you do so by typing
halt.
So far, our program is a fairly small one containing few facts. We have seen in class that facts are good, but general rules are even better. To get you started consider the following rule:
- John likes anything that Mary likes
How do you write this rule? In Prolog, rules are written BACKWARDS from what you think of in discrete. The conditions go on the right hand side, and the result goes on the left hand side. The way to think about it, we read Prolog rules as saying I can INFER fact A if I know fact B.
A :- B.
Since we can infer John liking some item if we know that Mary likes that same item, we write:
likes(john,I) :- likes(mary,I).
(Realize that the variable name is arbitrary. I choose "I" as in "Item". The only requirement is that it starts with a capital letter since it is a variable, not a ground term).
Add this rule you your knowledge base using your text editor. Test the impact of this rule by reloading and resubmitting the following queries against it:
? likes(john,X).
? likes(mary,X).
? likes(Y,food).
? likes(Y,wine).
Notice that this rule changes the results to some of these queries, but not all of them
For the time being, REPLACE the previous rule with a rule that states:
- John likes anyone who likes wine and mary
In order to do this, we need to provide the condition (the right hand side of our rule) with a compound statement that says that this other person must like BOTH wine AND mary. Compound statements in Prolog are made by using the comma to join together the multiple conditions. Thus, we might right:
likes(john,P) :- likes(P,mary) , likes(P,wine)
Bring up intro.pl in your editor if it is not still open, and replace the old rule with this rule. Test this, but saving the file, reloading the file, and submitting the query
? likes(john,X).
You should receive the following output (if not, you probably have something wrong).
X = wine ? X = mary ? X = steve? X = john ?
The first two make sense - these are simply facts in the program/knowledgebase.
The third one makes sense - this was derived from the new rule. steve DOES like both wine and mary, thus, john now likes him.
The fourth one may seem a little odd to you - john likes john? Well, that IS what the rule tells us. The rule says that we can infer that john likes any person P where P likes both mary and wine. Since john likes both mary and wine, john likes himself.
While we can argue whether or not john liking john SHOULD be allowed - I think it probably is legal - let's for a minute assume that it is NOT legal. We then need to change the rule so that it reads
This is done in Prolog by using the not operator - the backslash. We would write
likes(john,P) :- likes(P,mary) , likes(P,wine) , P\=john .
Test this, but saving the file, reloading the file, and submitting the query
? likes(john,X).
You should receive the following output (if not, you probably have something wrong).
X = wine ? X = mary ? X = steve?
Suppose that we want to represent a family tree, so that we can ask questions like "is john related to ...", or "list all john's sisters" and so on.
The basic entities will be people; the properties we will want to look at will be father, mother, brother, sister, ..... We choose three basic predicates, male, female and parentOf, which will describe a family by a series of facts.
Take the following family tree as an example:
James I
| | +----------------+-----------------+ | | Charles I Elizabeth | | | | +----------+------------+ | | | | | Catherine Charles II James II Sophia | | | George I
In Prolog we represent this family tree by stating 8 facts regarding gender (one for each of the 8 people in the family tree) and 7 facts regarding parents.
Using what you have learned, add these 15 facts to a new file in your text editor (call it "family.pl").
We can now formulate some queries (try entering these yourself):
? Was George I the parent of Charles I?
Query: parentOf(george1,charles1).
? Who was Charles I's parent?
Query: parentOf(X,charles1).
? Who were the children of Charles I?
Query: parentOf(charles1,X).
In order to test your knowledge base, submit these queries, and observe if the correct answers come out.
Add the following rules to the program, and check the results:
? M is the motherOf of X if she is a parent of X and is female
? F is the fatherOf of X if he is a parent of X and is male
? X is a siblingOf of Y if they both have the same parent.
(this one can be tricky if you don't pay attention).
Finally, add rules for the following relationships. I leave it up to you to figure the specification for each. I also leave it up to you to decide in which order to complete these. You may discover that
Prior to the deadline, use the homework submission system (http://math-cs.cns.uni.edu/~schafer/submit/which_course.cgi) to upload :
family.pl