Keep your Prolog notes open beside your keyboard so you can look for help when things do not work as you expect. Also see the Hints at the end of this lab.
Harry Potter and the Poison Potions
Here is another logic puzzle that models the situation as a
list of elements and tries out various permutations to find
those that match the problem.
In the first Harry Potter book, Harry and Hermione have to solve a puzzle involving 7 potions. I handed out the details earlier [ Potions.htm ] plus a copy of the source code. You can download the source code here: [ potion1.plg ] and then test it out. Note if you are running gprolog or a later version of SWI Prolog then you need [ potion1.pro ] instead. They've changed the way that select works:-(
Terminate Prolog by tapping CTRL/D
A Cryptarithm Puzzle
The following is intended to dazzle you with the sheer
cleverness of Prolog. I don't expect you to duplicate this
technique in this class. But I can't resist sharing it with you.
Prolog can be used to solve puzzles where you are given a sum and all the numbers have been coded as letters. The file [ crptarth.plg ] shows a clever way to this by using the fact that Prolog variables are rather like algebraic variables. They stand for blanks that need to filled in. All you have to do is generate all the possibilities and reject the ones that do not fit the rules.
Download it and use pl to compile the program:
...$ pl
?- consult('crptarth.plg').
....
?- listing.
?- go.
For simpler examples of this kind of puzzle solving see [ Another Approach to Logic Puzzles ]
Logic Puzzles
In these puzzles you try to complete the known data about a set
of entities. Each entity in the puzzle has the same set of
attributes, and the attribute values are not repeated. For
example you may need to find the last-names of people and
you know that
each last-name appears once in the solution.
These puzzles are also known as Smith-Jones-Robinson puzzles.
Prolog is best when you need to try out a moderately large number of possibilities against a set of given facts and rules. It has a definite problem if it has to search an infinite number of options. Trying all combinations can take much to long as well. In this case however the Prolog solution is fast enough:
http://www/dick/cs320/prolog/sample1.plg[ sample1.plg ] sets up and solves a sample logic puzzle found in a magazine.
Look at the file, down load it, and then try it out:
pl -o sample1 sample1.plg
sample1
When you use Prolog to help you solve these puzzles the challenge of the puzzle becomes extracting the properties of the attributes from the clues you've been given. If you miss a "given" then this algorithm may generate a solution that is not a solution of the problem.
There are some variations on this program: [ sample2.plg ] [ sample3.plg ]
Another Approach to Logic Puzzles
The previous experiment introduced you to Logic Puzzle
[ Logic Puzzles ]
Another approach is to set up a data structure representing the
complete solution with blanks and variables where the values are unknown.
Normally this a list of entities. Each entity has the same arguments.
I use the 'member(Entity, List)'
to scan the entities in the "world" (List)
and match up meanings for us. Here are two examples:
[ sample4.plg ]
[ zebra2.plg ]
Write a file 'cones.plg' that defines all my favorite scoop(Flavor).
scoop(chocolate).
scoop(vanilla).
scoop(strawberry).Compile, run and test it with:
scoop(Top).(and don't forget to tap ';' to ask for each cone in turn.)
Then try two scoops of ice-cream.
scoop(Top),scoop(Bottom).(and don't forget to tap ';' to ask for each cone in turn.) Now try the following simple Prolog loop....
scoop(Top),write(Top),nl,fail.Notice how we put fail at the end of the loop, because it forces Prolog to go back and find the next alternative, and in the above, the scoop provides a choice point with 3 alternatives. 'fail' take Prolog back to the last choice point to look for another alternative... and if there are none it backtracks to the next previous choice point.
We can use the same technique with two scoops... to generate all combinations:
scoop(Top),scoop(Bottom),write(Top+Bottom),nl,fail.Also notice that we can use + in the output.... because Prolog will write X+Y without evaluating it!
Edit your 'cones.plg' file so that it defines a predicate cone(Top, Middle, Bottom) that chooses a Top, Middle and Bottom Scoop.
cone(Top, Middle, Botttom):-scoop(Top), scoop(Middle). scoop(Bottom).Compile and run. Test it like this:
cone(Top,Middle,Bottom),
write(Top+Middle+Bottom),nl,fail.And fix the errors in the definition of a cone. I know of two.
Put Combinations in a Database
It is possible to save the database of ice-cream cones.
The program file must tell the Prolog system that there
is a dynamic predicate with 3 arguments:
:-dynamic(a_cone/3).Try the following which generates a database of all the possible cones, ready for further computation, as long as you tap the ";" key:
cone(A,B,C), assert( a_cone(A,B,C) ).
listing(a_cone).
Bags of Snow Cones
This continues the Ice-cream Cone scenario, but shows you a
powerful alternative to using the Prolog database for saving
a set of items for future use.
Prolog has some high-level commands for handling list, sets, and "bags". (A bag can have elements that occur several times). The bagof(Term, Condition, Bag) predicate is built into our Prolog and assembles a list in Bag of all Terms that fit the Condition. Load your 'cones.plg' into Prolog and try the following:
bagof(X, scoop(X), Scoops).
bagof(X+Y, (scoop(X), scoop(Y)), Scoops).You can count the number of cones easily by using the length(List, Length) predicate:
bagof(A+B+C, cone(A,B,C), Cones), length(Cones, Number_cones).You can add a definition of count to your cones.plg program:
count(N):-bagof(A+B+C, cone(A,B,C), Cones), length(Cones, N).
. . . . . . . . . ( end of section Combinatorics) <<Contents | End>>
Programs that Learn
assert(Fact)puts the query into the data base. The predicate
assertz(Fact)puts the item at the end of the data base.
asserta(Fact).adds the Fact at the beginning of the facts.
In modern Prologs the facts and clauses in the database are assumed to be static. To allow them to be dynamic the following command has to be executed in any program that uses the assert predicates:
:-dynamic(functor/arity).where functor is the name of the fact and arity is the number of arguments:
:-dynamic(fact/1).allows new 'facts' about single objects to be asserted or retracted.
It helps to know that a fact we assert is not already in the data base. There is a special Prolog statement that checks for a the existence of a clause - rather than trying to discover if the query is true:
clause(Head, Body).searches for a rule of form:
Head:-Body.
A Trivial Example
Here is an simple example. Suppose we already have a predicate
that finds the fourth power of a number:
fourth(X, X4):- square(X,X2), square(X2,X4).(try this definition out, adding anything that is missing:-)
However we want to avoid doing the same calculation twice. Instead, whenever we recalculating the old values.... Instead, each time a fourth power for an integer is found we add any new facts to the data base:
fourth(X,X4):-square(X,X2), square(X2,X4),
assert_if_new(fourth(X,X4)).The resulting program is in [ 4th.plg ] download this file and start up Prolog with this program. Repeatedly try queries like:
fourth(2, F).and and do a listing after each one... see how it accumulates data....
cone(A,B,C), count, fail.The fail forces Prolog to backtrack and find another cone. We need the right definition for count. We want count to increase some hidden item of data each time is called, and we don't want it to undo anything when backtracking from the fail.
Prolog variables only have one value so we can not use them for counting (except recursively - one symbol but many variables!). We can't use a variable so we use the Prolog database: Initially we have no cones:
cones(0).To count a cone we:
count:-retract(cones(Old)), New is Old+1, assert(cones(New)).(Prolog uses the jargon word retract to mean `find the first matching rule and remove it from the data base`.)
Put together the definition of cone, scoop, cones, and count, in your cones.plg file and then test:
cone(A,B, C), count, fail.
cones(Number).
Prolog List Processing
See Sebesta pages 502..507 first.
Ask Prolog for a listing of
appendStudy it. Test it out. Trace it. Describe in English how 'append' works.
function(square(X),X*X).You can then see how '=', 'is', and 'es' differ:
Y = square(3).
Y is square(3).
Y es square(3).You can add a new function to the definitions by asserting it:
assert(function( cube(X), X*X*X)).or like this:
assert((function( abs(X), X) :- X>=0))).
assert((function( abs(X), Y) :- X<0, Y is -X))).
Adding Rational Numbers to Prolog
Because Prolog stores expressions until it is forced to
evaluate them by an is or a relational operator we can easily
program Prolog with a new way to evaluate them - as long as we
give it a new name. In the
[ rational.plg ]
I programmed an
assignment like 'is', called 'es', which treats
n/das a fraction with numerator n and denominator d. This shows how the ADT(class) of rational numbers is declared and can be used.
Adding RAM to Prolog
Another feature of Prolog is the absence of global variables - data stored
in locations in random access memory. The file
[ ram.plg ]
Shows how to simulate such a memory using the Prolog data base.
When you look at the code, notice that 'ram' is essentially a function that converts the names of variables into values. So the code must make sure that there is never more than one value for any variable.
The file also needs you to download [ functions.plg ] so that the 'let' command will work.
It uses two special Prolog functors 'assert' and 'retract' to store and retrieve values in a array called ram.
Here is a set of tests.
set(x,1)
print_ram.
set(x,3)
print_ram.
set(y,2)
print_ram.
let(z,x+y).
print_ram.
univ or =.. predicate.">The univ or =.. predicate.
What happens to these queries:
(a+b)=..X.
tree(left,right)=..X.
Y=..[power, x, 2].
a*b+c =.. [F, X, Y].
a*(b+c) =.. [F, X, Y].
help(univ)Describe what 'univ'/=.. is supposed to do.
Faster Factorials by Caching Values
Look at
[ factorl2.plg ]
Down load it, compile, and list it. Figure out how to
test it from the listing.
A Real C Program
The time has come for you to see an industrial size C program.... the
Prolog Source Code. Explore this a little... before you
start the lab:
[ http://csci.csusb.edu/dick/cs320/prolog/src/ ]
This is precisely what I downloaded, uncompressed, unarchived,
compiled, and installed so that you could do these labs.
Note.
Picking lotto type numbers
My first algorithm
[ lotto.plg ]
for picking a sample of lottery picks has a bad feature....
Load the bad solution and investigate why and how it fails, using trace to help. What are the problems?
Later I produced [ lotto93.plg ] that seems to have the problem licked by using a smarter idea and a way to express a 'for loop' in Prolog.
For loops in Prolog
[ for.plg ]
[ for.example.plg ]
[ for.complex.plg ]
Magic squares revisited
See
[ magic2.plg ]
for an attempt to select unused values from a set
of possibilities.... and so generating permutations.
Currently this has developed a bug that I can't spot...
A Prototype Advising Program
The following is out of date and not useful advising system
[ compsci.plg ]
Improve it.
The Barber Paradox
In a certain village every boy shaves and are
either shaved by themselves or the barber. And
nobody is shaved by two people. Who shaves the barber?
[ barber.plg ]
Parallel Processing
[ cobegin.plg ]
Gries Coffee Can Problem
Actually it is Dick Scholten's coffee bean can...
[ coffeecan.plg ]
Cantor's Enumeration of Pairs
The following example runs through every pair of positive integers if
you run it long enough. It could be used to find whole number
solutions to equations. However it will go on forever if there
is no solution.
[ cantor.plg ]
Pretty Print a Structure
The following is used to print out a structure (a parse tree for
example) in a more readable way.
[ pp.plg ]
Quick Sort made Simple
The following experiments show
how simple sorting can be.
Two different examples...
[ qsort.plg ]
[ qsort2.plg ]
In both of these you call the sort like this:
qsort(Given_list, Variable_for_sorted_list).
Sorting in Practice
Practical Prolog programmers use the built-in sort/2
or setof/3 predicates when they want data in a
particular order. You can find out more about sort and
setof by asking prolog
help(sort).
help(setof).or trying out [ setof.plg ]
A Tool for Programming
This is based on a research paper in the IEEE Transactions of Software
Engineering. It shows how a lot of information about a complicated
C program can be placed in a Prolog data base and then searched to answer
questions like: "What could change the following variable?".
[ tool.plg ]
Statistics
This shows how you to use the Prolog data base to do
summations that appear in statistical work. The predicate
expects a list of numbers stored as data(...). data(....). ... and
sums the squares of these numbers:
[ sum_squares.plg ]
Genealogies
Here is an excellent example
[ genealogy.html ]
given to me by Jonathan Wheeler. It grows a simple Prolog
program for handling family trees and such. Try it out!
. . . . . . . . . ( end of section More sample Programs) <<Contents | End>>
. . . . . . . . . ( end of section If you have Time) <<Contents | End>>
For more on Prolog
Schnupp and Bernard have written an excellent introduction.
There book
is in the CSUSB library.
If you want to learn the techniques used for expert systems, simulations, and half a dozen other purposes... see T Van Le's text book.
I have a page of pointers to Prolog information: [ prolog.html ]
Also see a selection of messages from the SWI-Prolog mailing list [ mbox ]
The SWI manual (with some GIFs missing) is in [ http://www.csci.csusb.edu/dick/cs320/prolog/SWI-prolog/ ] and the Gnu Prolog manual is at [ http://www.csci.csusb.edu/dick/cs320/prolog/gnu/ ] and describes how to use gprolog and all the predicates it defines.
Hints
Study these hints if unexpected things happen...
End of line does not count.
X is a variable - with an unknown (as yet?) value.
x is the atom x
pl
consult('name_of_file').
EDIT=name_of_your_favorite_editor
VISUAL=$EDIT
EDITOR=$EDIT
export EDIT VISUAL EDITOR
The next time you login most UNIX programs will know what editor
you like to use.
UML to Prolog
Speaking of data bases.... You can often do a very quick translation
from a UML class diagram into a prototype Prolog data base. Each
box becomes a predicate. The chemistry example had a predicate
called element which would come from the UML class Element
with 8 public attributes: name:atom, symbol:string, etc. . The
operations would typically be written as rules. Operations
that change the state of the object will need to retract the
old attribute values and assert the new ones in place of
the old ones. Relationships
between classes can be code as: a predicate relating the two classes,
a list stored as an parameter of a predicate in a class, or a
single parameter identifying a unique corresponding object in
the other calls. Inheritance is harder but you can write
Prolog rules that attempt to find information in one predicate,
and if it fails goes else where. You can also write rules that
will search a series of predicates to find which one needs changing.
element(Name, _, Number1), element(Name, _, Number2), Number1=\=Number2.
. . . . . . . . . ( end of section CS320 Prolog Examples) <<Contents | End>>
Check the Preparation for next class
[ ../20.html ]