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.
In the first Harry Potter book, Harry and Hermione have to solve a puzzle involving 7 potions. Here is a page with the details [ Potions.htm ] and here [ potion1.plg ] a copy of the source code.
When compiled an run you can print out a solution of the puzzle, a list of the types of potion by using 'go.'. Terminate Prolog by tapping CTRL/D.
Note. You can experiment with solving the problem without the drawing by removing the comment and the following line.
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 swipl to compile the program:
...$ swipl
?- consult('crptarth.plg').
....
?- listing.
?- go.
For simpler examples of this kind of puzzle solving see [ Another Approach to Logic 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:
swipl sample1.plg
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 ]
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.
:-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).
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>>
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.
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).
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))).
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.
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.
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.
Note.
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.
Currently this has developed a bug that I can't spot...
qsort(Given_list, Variable_for_sorted_list).
help(sort).
help(setof).or trying out [ setof.plg ]
. . . . . . . . . ( end of section More sample Programs) <<Contents | End>>
. . . . . . . . . ( end of section If you have Time) <<Contents | End>>
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://cse.csusb.edu/dick/cs320/prolog/SWI-prolog/ ] and the Gnu Prolog manual is at [ http://cse.csusb.edu/dick/cs320/prolog/gnu/ ] and describes how to use gprolog and all the predicates it defines.
End of line does not count.
X is a variable - with an unknown (as yet?) value.
x is the atom x
swipl
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.
element(Name, _, Number1), element(Name, _, Number2), Number1=\=Number2.
. . . . . . . . . ( end of section CS320 Prolog Examples) <<Contents | End>>