Lab 1
Lab 1
Lab 1
Se Topics Page
Lab 10 Implementation of Breadth and Depth First Search In Prolog goal finding,
Lab 11 Implementation of Breadth and Depth First Search In Prolog path finding
and path Checking..................................................................................
I. What is Prolog?
Prolog (programming in logic) is one of the most widely used programming languages in
artificial intelligence research. As opposed to imperative languages such as C or Java (the
latter of which also happens to be object-oriented) it is a declarative programming
language.
That means, when implementing the solution to a problem, instead of specifying how to
achieve a certain goal in a certain situation, we specify what the situation (rules and facts)
and the goal (query) are and let the Prolog interpreter derive the solution for us.
Prolog is very useful in some problem areas, such as artificial intelligence, natural language
processing, and databases and so on but pretty useless in others, such as graphics or
numerical algorithms.
A program is partly like a database but much more powerful since we can also have
general rules to infer new facts!
A Prolog interpreter can follow these facts/rules and answer queries by sophisticated search.
There are different version and products of prolog interpreters. The Commonly used
interpreters in academic environment for prolog is SWI-Prolog
Swi‐Prolog can be freely downloaded from http://www.swi‐prolog.org and can easily install
it.
The SWI-Prolog executable swipl-win.exe can be started from the Start Menu or by
opening a .pl file holding Prolog program text from the Windows explorer.The .PL file
extension can be changed during installation. See section 3.2.
The above states, quite intuitively describes, the fact that an elephant is bigger than a
horse. (Whether the world described by a Prolog program has anything to do with our real
world is, of course, entirely up to the programmer imagination.)
Let's add a few more facts to our little program:
bigger(elephant, horse).
bigger(horse, donkey).
bigger(donkey, dog).
bigger(donkey, monkey).
In this environment prior to query presentation, the user first should call the prolog source
file (bigger.pl) to memory buffer for consultation of the stored facts and rules in the file
usually named as knowledge base for some domain specific query need of a user. (Refer
consulting source file topics in the previous portion).
Fig 1.4 user query and answer of the prolog engine in the interactive interface
In a similar fascine we can present different queries for the prolog engine. The following are few
instance of user query and the answer from prolog engine that consulted prolog engine.
?- bigger(donkey, dog). The answer for this query will be
true
Or
?bigger(donkey,X). the answer will be
Y = dog ;
Y = monkey.
or
?- bigger(X,Y).the answer will be
X = elephant,
Y = horse ;
X = horse,
Y = donkey ;
X = donkey,
Y = dog ;
X = donkey,
Y = monkey.
or
?- bigger(monkey, elephant).
The answer will be false
Fig 1.6 queries and positive responds as interpreted by SWI-Prolog engine
Fig 1.7 queries and false responds for unknown facts interpreted by SWI-Prolog engine
According to this elephants are not bigger than monkeys. This is clearly wrong as far as our real world
is concerned, but if you check our little program again (check contents of biiger.pl at fig 1.2), you will
find that it says nothing about the relationship between elephants and monkeys. This kind of problem
can be solved by generalized rules.
Example 2 Family.pl
Let us see other features of prolog programming with family.pl. Sometimes it may be too tedious to
describe every real world facts to prolog engine explicitly through fact description. Instead, if there are
some common features and clear relationships among real world facts, programmer may write rules in
their knowledge base that used to generalize about facts for prolog engine from available facts during
interpretation of queries (see fig 1.8). In this example the programmer define rules for father, mother,
daughter, and son facts using available facts such as parent, male, and female predicates.
male(abebe).
male(tadesse).
female(aster).
female(almaz).m
parent(abebe,tadesse).
parent(almaz,tadesse).
parent(abebe,aster).
parent(almaz,aster).
father(X,Y):-parent(X,Y),male(X).
mother(X,Y):-parent(X,Y),female(X).
doughter(X,Y):-parent(Y,X),female(X).
son(X,Y):-parent(Y,X),male(X).
Fig 1.8 knowledge base for family relationship made using facts and rules
In the above example one can see that, facts such as parent, male, and female predicates
are written in different format than their precedent set of facts. First the argument for each
predicates written in capital letter (variable writing form for prolog programming) since,
variables usually used to generalize about some common features of objects in the real
world.
Notes: Variables in prolog programming written using alphanumeric character that starts
with capital letter and constant facts written using any combination of alphanumeric
characters that starts with small letters. (Next time we will see in detail about prolog object
type).
Figure 1.9 shows queries and responds of SWI-Prolog engine by consulting family.pl
knowledge base.
Exercise of Lab session one
1. Take your own case and write prolog codes and test with different form of queries
2. Consider family.pla as your knowledge base and define other rule for brother, sister,
and other relationship of family.
Laboratory Secession Two
Syntax of Prolog
Data objects/Terms
Types of objects that a prolog interpreter recognizes by its syntactic forms are called data-
object/terms.
The central data structure in Prolog is that of a term. There are terms of four kinds: atoms,
numbers, variables, and compound terms. Atoms and numbers are sometimes grouped
together and called atomic terms or simple object. A combination of two or more atomic
terms can form compound term or structure.
Simple objects (terms) can be a static facts (constant) that represent specific real-world
facts or events or a generalized fact that can symbolically represent similar real-world
objects’ fact called variable. We have already seen the different between variables and
constants terms in the previous section examples.
Variable start with upper case letter while constant start with small letter. No additional
information such as data type declaration has been communicated to prolog in order to
recognize the objects.
Data objects
Constant Variables
Atoms Numbers
Example
On top of that also any series of arbitrary characters enclosed in single quotes denotes an
atom.
Finally, strings made up solely of special characters like + - * = < > : & (check the manual of
our SWI-Prolog system for the exact set of these characters) are also atoms.
Examples:
Variables. Variables are strings of letters, digits, and the underscore, starting with a
capital letter or an underscore. Examples:
The last one of the above examples (the single underscore) constitutes a special case. It is
called the anonymous variable and is used when the value of a variable is of no particular
interest. Multiple occurrences of the anonymous variable in one expression are assumed to
be distinct, i.e., their values don't necessarily have to be the same.
Structure/Compound terms.
Compound terms are made up of a functor (a Prolog atom) and a number of arguments
(Prolog terms, i.e., atoms, numbers, variables, or other compound terms) enclosed in
parentheses and separated by commas.
The following are some examples for compound terms:
is_bigger(horse, X),
f(g(X, _), 7),
'My Functor'(dog)
Structured objects (or simply structures are objects that have several components. The
components themselves can, in turn, be structures. For example,
The date can be viewed as a structure with three components day, month, and year.
Although composed of several components, structures are treated in the program as single
objects. In order to combine the components in to a single object we have to choose a
function
haliday('Ethiopian ChristMass',date(january,7,2013)).
haliday('Eid_al_adha',date(january,10,2013)).
haliday('Epiphany',date(january,19,2013)).
haliday('Adwa Victory day',date(march,2,2013)).
haliday('The phrophet Birth Day',date(april,11,2013)).
haliday('Ethiopian Good Friday',date(april,21,2013)).
haliday('Ethiopian Easter Sunday',date(april,23,2013)).
haliday('International Labor Day',date(may,1,2013)).
haliday('Freedom Day',date(may,5,2013)).
haliday('Derg Downfall Day',date(may,28,2013)).
haliday('Ethiopian New Year',date(september,11,2013)).
haliday('Finding of the True
Cross',date(september,27,2013)).
haliday('Eid-al-Fitr',date(october,24,2013)).
haliday('Eid al-Adha',date(december,31,2013)).
Exercises
1. Write the appropriate prolog statement for the following statements.
a. Abebe likes aster.
b. Kebede is handsom.
c. Today is holiday.
d. Abebe likes French food.
e. Haile G/Silassie was famous runner since from 1996E.C.
f. Aster merried to Alemayeu.
g. Every man is mortal.
h. Africa connected with ther est of world through Addis Ababa
2. See the following table and represent the data in prolog to keep the appropriate
information students information.
(s)
3. Assume given a set of facts of the form father(name1,name2) (name1 is the father
of name2).
a. Define a predicate brother(X,Y) which holds iff X and Y are brothers.
b. Define a predicate cousin(X,Y) which holds iff X and Y are cousins.
c. Define a predicate grandson(X,Y) which holds iff X is a grandson of Y.
d. Define a predicate descendent(X,Y) which holds iff X is a descendent of Y.
e. Consider the following genealogical tree:
f. father(a,b).
g. father(a,c).
h. father(b,d).
i. father(b,e).
j. father(c,f).
a
/\
b c
/\ |
d ef
4. See the following knowledge base interpret what the program does with your own
statement.
Laboratory Secession 3 : Operators and Arithmetic
Operators
Prolog defines a set of prefix, infix, and postfix operators that includes the classical
arithmetic symbols: “+”, “-”, “*”, and “/”. The Prolog interpreter considers operators as
functors and transforms expressions into terms.
The mapping of operators onto terms is governed by rules of priority and classes of
associatively:
Arithmetic in Prolog
Prolog is not the programming language of choice for carrying out heavy duty
mathematics. It does, however, provide arithmetical capabilities. The pattern for
evaluating arithmetic expressions is (where Expression is some arithmetical expression) the
general for arithmetic expression in prolog is
X is Expression
or
is(X,expression).
example
writing X is 10+5*6/3.12 to prolog consol gives you the following result
X = 20.
the above statement can be rewritten in the form of is(X,expression) as follows
is(X,+(10,/(*(5,6),3.12))).
to find the predicate equivalent for the arithmetic expression you should first know the
operator precedence
Multiplication
division
addition
subtraction
for example if you want to convert Y is 2*6/2+12 start first forming the multiplication
predicate then the division predicate the addition and finally the is predicate.
is(Y,+(/(*(2,6),2),12)).
to find the equivalent expression for a particular arithmetic expression you can use
display(expression).
is(X,+(10,/(*(5,6),3)))
Typical Arithmetic Operators
+ addition
_substraction
/division
* multiplication
mod modulo
Population Examples
pop(usa,280).
pop(india,1000).
pop(china,1200).
pop(brazil,130).
pop(ethiopia,90).
area(usa,3).
area(india,1).
area(china,4).
area(brazil,3).
area(ethiopia,1.3).
density(X,Y) :-
pop(X,P),
area(X,A),
Y is P/A.
Typical relational operators.
X = Y X and Y stand for the same number
X \= Y X and Y stand for different numbers
X < Y X is less than Y
X > Y X is greater than Y
X =< Y X is less than or equal to Y
X >= Y X is greater than or equal to Y
Exercises
1. Write a prolog program that can calculate area of a circle by taking the radios of a
circle from the user.
Area=pi*2r
2. Write a prolog program that can respond to peoples as Hello Miss Name or Mr. by
taking Sex information from the User.
3. re write the following expression in the forms of is(X,Expression format).
a. X is 12/2*14-2+13
Laboratory Secession 4: Cuts, Negation, and Related Predicates
Cuts
The cut predicate, written “!”, is a device to prune some backtracking alternatives. It
modifies the way Prolog explores goals and enables a programmer to control the execution
of programs. When executed in the body of a clause, the cut always succeeds and removes
backtracking points set before it in the current clause. Figure 4.1 shows the execution model
of the rule p(X) :- q(X), !, r(X) that contains a cut.
Fig. 4.1 The execution box representing the rule p(X) :- q(X), !, r(X).
Executing the cut in the first clause has the following consequences:
1. All other clauses of the predicate below the clause containing the cut are pruned. That is,
here the two remaining clauses of P will not be tried.
2. All the goals to the left of the cut are also pruned. That is, A1, ..., Ai will no longer
be tried.
Cuts are intended to improve the speed and memory consumption of a program.
However, wrongly placed cuts may discard some useful backtracking paths and solutions.
Then, they may introduce vicious bugs that are often difficult to track. Therefore, cuts
should be used carefully.
minimum(X, Y, Y) :- X >= Y.
Once the comparisons done, there is no means to backtrack because both clauses are
mutually exclusive. This can be expressed by adding two cuts:
minimum(X, Y, X) :- X < Y, !.
minimum(X, Y, Y) :- X >= Y, !.
The idea behind this is that once Prolog has compared X and Y in the first clause, it is not
necessary to compare them again in the second one. Although the latter program may be
more efficient in terms of speed, it is obscure. In the first version of minimum/3, cuts respect
the logical meaning of the program and do not impair its legibility. Such cuts are called
green cuts. The cut in the second minimum/3 predicate is to avoid writing a condition
explicitly. Such cuts are error-prone and are called red cuts. Sometimes red cuts are crucial
to a program but when overused, they are a bad programming practice.
Negation
A logic program contains no negative information, only queries that can be proven or not.
The Prolog built-in negation corresponds to a query failure: the program cannot prove the
query. The negation symbol is written “\+” or not in older Prolog systems:
where fail/0 is a built-in predicate that always fails. Most of the time, it is preferable to
ensure that a negated goal is ground: all its variables are instantiated. Let us illustrate it
with the somewhat odd rule:
and facts:
child(telemachus, penelope).
male(ulysses).
male(telemachus).
The query
?- mother(X, Y).
false because the subgoal male(X) is not ground and unifies with the fact male(ulysses). If
the subgoals are inverted:
as in
X = penelope, Y = telemachus
’->’(P, Q):- P, !, Q.
The if-then-else predicate is an extension of ’->’/2 with a second member to the right. Its
syntax is
The built-in predicate once/1 also controls Prolog execution. once(P) executes P once and
removes backtrack points from it. If P is a conjunction of goals as in the rule:
the backtracking path goes directly from Bi+1 to B2, skipping B3, ..., Bi. It is necessary to
bracket the conjunction inside once twice because its arity is equal to one. A single level of
brackets, as in once(B3, ..., Bi), would tell Prolog that once/1 has an arity of i-3. once(Goal)
is defined as:
once(Goal) :- Goal, !
Laboratory Secession 5: Lists and Recursion
Lists are data structures essential to many programs. A Prolog list is a sequence of an
arbitrary number of terms separated by commas and enclosed within square brackets. For
example:
Although it is not obvious from these examples, Prolog lists are compound terms and the
square bracketed notation is only a shortcut. The list functor is a dot: “./2”, and [a, b] is
equivalent to the term .(a,.(b,[])). Computationally, lists are recursive structures. They
consist of two parts:
The head and the tail correspond to the first and second argument of the Prolog list func-
tor. Figure 5.1 shows the term structure of the list [a, b, c]. The tail of a list is possibly empty
as in .(c,[])).
The notation “|” splits a list into its head and tail, and [H | T] is equivalent to .(H, T).
Splitting a list enables us to access any element of it and therefore it is a very frequent
operation. Here are some examples of its use:
?- [a] = [H | T]. H = a, T = []
?- [] = [H | T]. No
Many applications require extensive list processing. This section describes some useful
predicates. Generally, Prolog systems provide a set of built-in list predicates. Consult your
manual to see which ones; there is no use in reinventing the wheel.
Yes
No
member(X, YS).
We could also use anonymous variables to improve legibility and rewrite mem- ber/2 as
member(X, [X | _]).
member/2 can be queried with variables to generate elements member of a list, as in:
X = a ;
X = b ;
X = c ;
False
?- member(a, Z).
Z = [a | Y] ; Z = [Y, a | X] ; etc.
Finally, the query:
?- \+ member(X, L).
true
where X and L are ground variables, returns Yes if member(X, L) fails and No if it succeeds.
append/3 is defined as
append([], L, L).
The delete/3 predicate deletes a given element from a list. Its synopsis is:
example queries
?- delete([2,3,4,5,6],6,X).
X = [2, 3, 4, 5].
It is defined as:
delete([], _, []).
L = [a, b]
L = [a, b, a]
% Termination case
intersection([], _, []).
% Head of L1 is in L2
As for delete/3, clauses of intersection/3 are mutually exclusive, and the programmer can
omit the condition\+ member(X, L2) in the third clause.
The reverse/2 predicate reverses the elements of a list. There are two classic ways to define
it. The first definition is straight forward but consumes much memory. It is often called the
naïve reverse:
Exercises
Write a predicate twice(In,Out) whose left argument is a list, and whose right argument is
a list consisting of every element in the left list written twice. For example, the query
twice([a,4,buggle],X).
should return
X = [a,a,4,4,buggle,buggle]).
twice([1,2,1,1],X).
should return
X = [1,1,2,2,1,1,1,1].
Prolog comes with a range of predefined predicates for manipulating lists. Some of the
most important ones are presented here. Note that they could all easily be implemented
by exploiting the head/tail-pattern.
length/2: The second argument is matched with the length of the list in the first argu- ment.
Example:
It is also possible to use length/2 with an uninstantiated first argument. This will generate a
list of free variables of the specified length:
The names of those variables may well be different every time you call this query, because
they are generated by Prolog during execution time.
member/2: The goal member(Elem, List) will succeed, if the term Elem can be matched
with one of the members of the list List. Example:
append/3: Concatenate two lists. This built-in works exactly like the predicate concat_lists/3
presented in Section 2.2.
last/2: This predicate succeeds, if its second argument matches the last element of the list
given as the first argument of last/2.
reverse/2: This predicate can be used to reverse the order of elements in a list. The first
argument has to be a (fully instantiated) list and the second one will be matched with the
reversed list. Example:
select/3: Given a list in the second argument and an element of that list in the first, this
predicate will match the third argument with the remainder of that list. Example:
?- select(bird, [mouse, bird, jellyfish, zebra], X). X = [mouse, jellyfish, zebra] Yes
Laboratory Secession 6: Input and Output in Prolog
write( ) : Writes a single term to the terminal. write(term) is true if term is a Prolog term.
For example: write(a), or write(‘How are you?’)
write_ln() Writes a term to the terminal followed by a new line.
tab(X) Writes an X number of spaces to the terminal.
read(X) Reads a term from the keyboard and instantiates variable X to the value of the
read term.
_ This term to be read has to be followed by a dot “.” and a white space character (such as
an enter or space).
_ For example:
hello :-
write(‘What is your name ?’),
read(X),
write(‘Hello’), tab(1), write(X).
You can write more than one horn clause in prolog file
sum :-
write('Enter the first Number ?'),
read(X),
write('Enter the Second Number'),
read(Y),
Z is X+Y,
write('The sum of the two number is'), write(Z).
subtract:-
write('Enter the first Number ?'),
read(X),
write('Enter the Second Number'),
read(Y),
Z is X-Y,
write('The first number minus the second number is'),
write(Z).
divide :-
write('Enter the first Number ?'),
read(X),
write('Enter the Second Number'),
read(Y),
Z is X/Y,
write('The fiirst number divided for second number is'),
write(Z).
product:-
write('Enter the first Number ?'),
read(X),
write('Enter the Second Number'),
read(Y),
Z is X*Y,
write('The product of the two number is'), write(Z).
modules:-
write('Enter the first Number ?'),
read(X),
write('Enter the Second Number'),
read(Y),
Z is mod(X,Y),
write('The modulo of first number to the second is'),
write(Z).
Laboratory Secession 8: Fact representation for AI Problems directed graph,
and defining successor function
The most concise and easy way to remember illustration of AI searches is using the road
map model that connects different locations shown in figure 6.1
As there are different types of searching techniques in AI, in this laboratory secession we will
see implementation of one type of blind-searching techniques called breadth first Search
for the road map model that has described in figure 6.1.
For the convenience of understanding the codes clearly, We alienated the facts that
describes the road maps facts from the actual depth first implementation. The fact
description implementation module created and saved by the name fact.pl. Later we will
call this module in the search algorithm bodies by its file name.
:- module(edges,[link/2]).
connect(a,b).
connect(a,d).
connect(a,s).
connect(b,c).
connect(b,e).
connect(d,e).
connect(d,s).
connect(e,f).
connect(f,g).
link(Node1,Node2) :- connect(Node1,Node2).
link(Node1,Node2) :- connect(Node2,Node1).
Exercises
Important functions and lists to implement this searching techniques described in the
following table .
1 Goal-test function That check whether the nodes to be expanded is a goal node or
not before given
2 Successor function A function that generates the child nodes from the current nodes
if the current node is not a goal node.
3 Merger function A function that checks weather the newly generated nodes are
not a member of explored nodes(a nodes that have been already
tested with goal test function and their child nodes are generated
usually kept as closed list) and merge with a node that has kept
in an open list that are waiting for further to be checked by goal-
test function and by successor function. Newopenlist={listof nodes
generated by successor function} n {nodes lists that is not in closed
list} plus previous open list compliment current node.
4 Open list Lists that contain the set of nodes that has been generated by
successor-function through each and further weighting for
checking by goal test function and successor-function. always
updated by merger-function. Note Remember Breadth first
search use FIFO data structure for accessing lists and
implemented in queue data structure.
5 Closed List Lists that contain a set of nodes that have already cheked with
goal-test function and were not a goal.
BreadthFirst(StartNode,GoalNode)
comment: Depth First Search with a List of Closed Nodes
RootNode ← StartNode
OpenList← [RootNode]
ClosedList← []
[H|T] ← OpenList while [H = GoalNode]
do
{
SuccList← successors of H ....................(1)
OpenList← (SuccList∩ClosedList copmliment) ..............(2)
ClosedList← [H|ClosedList]................... (3)
if OpenList = [] then return (failure)
[H|T] ← OpenListreturn (success)
}
The following figure shows the general algorithm for breadth first search
:-use_module(fact).
breadth_first(Start,Goal):-write('Open: '),
write([Start]), write(', Closed: '), write([]),
nl,
loop([Start],[],Goal).
loop([Goal|_],_,Goal):- write('The Goal is : '),
write(Goal).
loop([CurrNode|OtherNodes],ClosedList,Goal):-
successors(CurrNode,SuccNodes),
write('Node '), write(CurrNode),
write(' is being expanded.'),
findall(Node,(member(Node,SuccNodes),
not(member(Node,ClosedList))),Nodes),
append(OtherNodes,Nodes,NewOpenNodes),
write('Sucessor nodes: '),
write(SuccNodes),nl,
write('Open Nodes: '), write(NewOpenNodes),
write(', Closed Node : '),
write([CurrNode|ClosedList]),nl,
loop(NewOpenNodes,[CurrNode|ClosedList],Goal)
.
successors(Node,SuccNodes):-
findall(Successor,link(Node,Successor),SuccNodes)
.
Exercises
1. Implement depth first search and Iterative deepening search for similar problem of goal
finding.
Laboratory Secession 10: Implementation of Breadth First Search and Depth
first search with Path finder
1. Extend the above Implementation of BFS to be more interactive and finds the
paths instead of the nodes alone.
for this laboratory secession we implement the depth first search which finds paths for a
particular path finding problem. what makes different this implementation from previous
topic is that
its first argument will take the list of open paths (and not that of open nodes). This
is the argument where we accumulate (maintain) the agenda.
• Into an additional (fourth) argument will the path from Start to Goal be copied as
soon as it appears at the head of the agenda. The search is then finished.
• The second and third arguments of will hold, as before, the list of closed nodes and
the goal node, respectively.
the following is the algorithm for path finding problem using depth first search
:- use_module(paths).
depth_first(Start,Goal,PathFound) :-
dfs_loop([[Start]],[],Goal,PathFoundRev),
reverse(PathFoundRev,PathFound).
dfs_loop([[Goal|PathTail]|_],_,Goal,[Goal|PathTail]).
dfs_loop([[CurrNode|T]|Others],ClosedList,Goal,PathFound) :-
successors(CurrNode,SuccNodes),
findall(Node,(member(Node,SuccNodes),
not(member(Node,ClosedList))),Nodes),
extend_path(Nodes,[CurrNode|T],Paths),
append(Others,Paths,NewOpenPaths),
dfs_loop(NewOpenPaths,[CurrNode|ClosedList],Goal,PathFound).
successors(Node,SuccNodes) :-
findall(Successor,link(Node,Successor),SuccNodes).
extend_path([],_,[]). % clause 1
extend_path([Node|Nodes],Path,[[Node|Path]|Extended]) :- %
clause 2
extend_path(Nodes,Path,Extended). %
Exercises
1. Implement the path finder solution for breadth and iterative deepening search