Вы находитесь на странице: 1из 20

ARTIFICIAL INTELLIGENCE

LAB FILE

SUBMITTED TO:
Sr. Lecturer
Computer Science
Department

SUBMITTED BY:
Nehal Kumar Mishra
1009210065
CS VIII Sem.

INDEX
S.NO. PRACTICAL DATE SIGNATURE
1.
2.

DFA PARSER

TOWER OF HANOI
PUZZLE

3.

GRAPH
STRUCTURES
AND PATH

4.

Map colorings

5.

Tree data and


relations

6.

ANIMAL
IDENTIFICATION
GAME

7.

N QUEEN
PROBLEM

PRACTICAL No: 1
DFA PARSER
The following program simulates a parser/acceptor for an arbitrary deterministic finite automaton
(DFA). When this and a state table program are loaded into Prolog, the parser/acceptor may be used
to check inputs to the DFA to see whether or not they are acceptable. The program traces its action
using write statements; these have been indented in order to better display the logical structure of
the clauses.
parse(L) :- start(S), trans(S,L).
trans(X,[A|B]) :- delta(X,A,Y),
/* X ---A---> Y */ write(X), write('
write([A|B]), nl, trans(Y,B).
trans(X,[]) :final(X), write(X), write(' '), write([]), nl.

'),

As an example, the following Prolog code specifies a state table for a DFA that accepts the language
(a,b)*ab(a,b)* .
delta(0,a,1).
delta(0,b,0).
delta(1,a,1).
delta(1,b,2).
delta(2,a,2).
delta(2,b,2).
start(0).
final(2).

A state diagram for this machine is as follows:

Suppose that both the driver program and the state table program are loaded ...
?0
0
0
1
1
2
2

parse([b,b,a,a,b,a,b]).
[b,b,a,a,b,a,b]
[b,a,a,b,a,b]
[a,a,b,a,b]
[a,b,a,b]
[b,a,b]
[a,b]
[b]

2 []
yes
?0
0
0
no

parse([b,b,a]).
[b,b,a]
[b,a]
[a]

Prolog program for DFA parser :parse(L) :- start(S), trans(S,L).


trans(X,[A|B]) :- delta(X,A,Y), /* X ---A---> Y */ write(X), write(' '), write([A|B]), nl, trans(Y,B).
trans(X,[]) :delta(0,a,1).
delta(0,b,0).
delta(1,a,1).
delta(1,b,2).
delta(2,a,2).
delta(2,b,2).
start(0).
final(2).

final(X), write(X), write(' '), write([]), nl.

PRACTICAL No: 2
TOWER OF HANOI PUZZLE

This object of this famous puzzle is to move N disks from the left peg to the right peg
using the center peg as an auxiliary holding peg. At no time can a larger disk be
placed upon a smaller disk. The following diagram depicts the starting setup for N=3
disks.

A recursive prolog program for Tower of hanoi puzzle:move(1,X,Y,_) :- write('Move top disk from '), write(X),write(' to '), write(Y),nl.
move(N,X,Y,Z) :- N>1, M is N-1, move(M,X,Z,Y), move(1,X,Y,_), move(M,Z,Y,X).

PRACTICAL No: 3
GRAPH STRUCTURES AND PATH
As an example, consider the following connected graph:

The edges can be represented in Prolog as facts:


edge(1,2).
edge(1,4).
edge(1,3).
edge(2,3).
edge(2,5).
edge(3,4).
edge(3,5).
edge(4,5).

To represent the fact that the edges are bi-directional we could either add eight more 'edge' clauses
(edge(2,1),etc.) or we could try a rule like:
(*)

edge(X,Y) :- edge(Y,X).

This is not a good idea, however. To see why it is not a good idea, try the following goal.
?- edge(5,1).

Notice that the rule (*) will be tried over and over in an infinite loop, so the goal will not terminate.
Try it! A better way to handle this is to use a rule such as the following.
connected(X,Y) :- edge(X,Y) ; edge(Y,X).

Note the use of disjunction ';' in this rule. This rule could have been written as two rules:
connected(X,Y) :- edge(X,Y).
connected(X,Y) :- edge(Y,X).

We wish to develop a Prolog definition which generates paths between any two nodes of the graph.
More specifically, we require the following (kind of) behavior for the predicate 'paths'.

?- path(1,5,P).
P = [1,2,5] ;
P = [1,2,3,5] ;
P = [1,2,3,4,5] ;
P = [1,4,5] ;
P = [1,4,3,5] ;
P = [1,4,3,2,5] ;
P = [1,3,5] ;
P = [1,3,4,5] ;
P = [1,3,2,5] ;
no

The paths are represented by the list of nodes through which one must travel to get from node 1 to
node 5. Here is a definition for paths:
path(A,B,Path) :- travel(A,B,[A],Q), reverse(Q,Path).
travel(A,B,P,[B|P]) :- connected(A,B).
travel(A,B,Visited,Path) :- connected(A,C), C \== B, \+member(C,Visited),
travel(C,B,[C|Visited],Path).

A declarative reading for the first clause amounts to "A path from A to B is obtained if A and B are
connected". A declarative reading for the second clause amounts to "A path from A to B is obtained
provided that A is connected to a node C different from B that is not on the previously visited part
of the path, and one continues finding a path from C to B". Avoiding repeated nodes ensures that
the program will not cycle endlessly.

Prolog program for graph structures and paths :edge(1,2).


edge(1,4).
edge(1,3).
edge(2,3).
edge(2,5).
edge(3,4).
edge(3,5).
edge(4,5).
connected(X,Y) :- edge(X,Y) ; edge(Y,X).
path(A,B,Path) :- travel(A,B,[A],Q), reverse(Q,Path).
travel(A,B,P,[B|P]) :- connected(A,B).
travel(A,B,Visited,Path) :- connected(A,C), C \== B, \+member(C,Visited),
travel(C,B,[C|Visited],Path).

PRACTICAL NO: 4
Map colorings
A famous problem in mathematics concerns coloring adjacent planar regions. Like cartographic
maps, it is required that, whatever colors are actually used, no two adjacent regions may not have
the same color. Two regions are considered adjacent provided they share some boundary line
segment. Consider the following map.

We have given numerical names to the regions. To represent which regions are adjacent, consider
also the following graph.

Here we have erased the original boundaries and have instead drawn an arc between the names of
two regions, provided they were adjacent in the original drawing. In fact, the adjacency graph will
convey all of the original adjacency information. A Prolog representation for the adjacency
information could be represented by the following unit clauses, or facts.
adjacent(1,2).
adjacent(1,3).
adjacent(1,4).
adjacent(1,5).
adjacent(2,3).
adjacent(2,4).
adjacent(3,4).
adjacent(4,5).

adjacent(2,1).
adjacent(3,1).
adjacent(4,1).
adjacent(5,1).
adjacent(3,2).
adjacent(4,2).
adjacent(4,3).
adjacent(5,4).

If these clauses were loaded into Prolog, we could observe the following behavior for some goals.
?- adjacent(2,3).
yes
?- adjacent(5,3).
no
?- adjacent(3,R).
R = 1 ;
R = 2 ;
R = 4 ;
no

One could declare colorings for the regions in Prolog also using unit clauses.
color(1,red,a).
color(2,blue,a).
color(3,green,a).
color(4,yellow,a).
color(5,blue,a).

color(1,red,b).
color(2,blue,b).
color(3,green,b).
color(4,blue,b).
color(5,green,b).

Here we have encoded 'a' and 'b' colorings. We want to write a Prolog definition of a conflictive
coloring, meaning that two adjacent regions have the same color. For example, here is a Prolog
clause, or rule to that effect.
conflict(Coloring) :adjacent(X,Y),
color(X,Color,Coloring),
color(Y,Color,Coloring).

For example,

?- conflict(a).
no
?- conflict(b).
yes
?- conflict(Which).
Which = b

Here is another version of 'conflict' that has more logical parameters.


conflict(R1,R2,Coloring) :adjacent(R1,R2),

color(R1,Color,Coloring),
color(R2,Color,Coloring).

Prolog allows and distinguishes the two definitions of 'conflict'; one has one logical parameter
('conflict/1') and the other has three ('conflict/3'). Now we have
?R1
?R1

conflict(R1,R2,b).
= 2
R2 = 4
conflict(R1,R2,b),color(R1,C,b).
= 2
R2 = 4
C = blue

The last goal means that regions 2 and 4 are adjacent and both are blue. Grounded instances like
'conflict(2,4,b)' are said to be consequences of the Prolog program. One way to demonstrate such a
consequence is to draw a program clause tree having the consequence as the root of the tree, use
clauses of the program to branch the tree, and eventually produce a finite tree having all true leaves.
The bottom leftmost branch drawn in the tree corresponds to the unit clause
adjacent(2,4).

which is equivalent in Prolog to the clause


adjacent(2,4) :- true.

Now, on the other hand, 'conflict(1,3,b)' is not a consequence of the Prolog program because it is
not possible to construct a finite finite clause tree using grounded clauses of P containing all 'true'
leaves. Likewise, 'conflict(a)' is not a consequence of the program, as one would expect. We will
have more to say about program clause trees in subsequent sections.

Prolog program for map coloring :adjacent(1,2).

adjacent(2,1).

adjacent(1,3).

adjacent(3,1).

adjacent(1,4).

adjacent(4,1).

adjacent(1,5).

adjacent(5,1).

adjacent(2,3).

adjacent(3,2).

adjacent(2,4).

adjacent(4,2).

adjacent(3,4).

adjacent(4,3).

adjacent(4,5).

adjacent(5,4).

/*------------------------------------*/
color(1,red,a).

color(1,red,b).

color(2,blue,a). color(2,blue,b).
color(3,green,a). color(3,green,b).
color(4,yellow,a). color(4,blue,b).
color(5,blue,a). color(5,green,b).
/*------------------------------------*/
conflict(Coloring) :- adjacent(X,Y), color(X,Color,Coloring), color(Y,Color,Coloring).
/*-------------------------------------*/
conflict(R1,R2,Coloring) :- adjacent(R1,R2), color(R1,Color,Coloring), color(R2,Color,Coloring).

PRACTICAL No: 5
Tree data and relations
Consider the following tree diagram.

/* The tree database */


:- op(500,xfx,'is_parent').
a
a
a
b
b

is_parent
is_parent
is_parent
is_parent
is_parent

b.
c.
d.
e.
f.

c
c
c
d
e

is_parent
is_parent
is_parent
is_parent
is_parent

g.
h.
i.
j.
k.

f
f
h
i
i

is_parent
is_parent
is_parent
is_parent
is_parent

/* X and Y are siblings */


:- op(500,xfx,'is_sibling_of').
X is_sibling_of Y :- Z is_parent X,
Z is_parent Y,
X \== Y.
/* X and Y are on the same level in the tree. */
:-op(500,xfx,'is_same_level_as').
X is_same_level_as
X is_same_level_as

X .
Y :- W is_parent X,
Z is_parent Y,
W is_same_level_as Z.

/* Depth of node in the tree. */

l.
m.
n.
o.
p.

j
j
j
m

is_parent
is_parent
is_parent
is_parent

q.
r.
s.
t.

:- op(500,xfx,'has_depth').
a has_depth 0 :- !.
Node has_depth D :- Mother is_parent Node,
Mother has_depth D1,
D is D1 + 1.
/* Locate node by finding a path from root down to the node. */
locate(Node) :- path(Node),
write(Node),
nl.
path(a).
/* Can start at a.
*/
path(Node) :- Mother is_parent Node, /* Choose parent,
*/
path(Mother),
/* find path and then */
write(Mother),
write(' --> ').
/*

Calculate the height of a node, length of longest


a leaf under the node.
*/

height(N,H) :- setof(Z,ht(N,Z),Set),
max(Set,0,H).

path to

/* See section 2.8 for 'setof'.

*/

ht(Node,0) :- leaf(Node), !.
ht(Node,H) :- Node is_parent Child,
ht(Child,H1),
H is H1 +1.
leaf(Node) :- not(is_parent(Node,Child)). /* Node grounded */
max([],M,M).
max([X|R],M,A) :- (X > M -> max(R,X,A) ; max(R,M,A)).

The 'is_sibling_of' relationship tests whether two nodes have a common parent in the tree. For
example,
?- h is_sibling_of
S=g ;
S=i ;
no

S.

Note the use of the literal X \==Y, which succeeds just in case X and Y are not cobound (bound to
the same value).
The 'is_same_level_as' relationship tests whether two nodes are on the same level in the tree.
The 'depth' predicate computes the depth of a node in the tree (how many edges from the root). For
example,
?- t has_depth D.
D=4

Here is an alternate definition of 'depth' using Prolog implication:


N has_depth D :- N == 'a' -> D=0 ;
Mother is_parent N,
Mother has_depth D1,
D is D1 + 1.

The 'locate' predicate computes and prints a path from the root to a node. For example,
?- locate(n).
a --> c --> h --> n

The 'leaf' predicate defines a leaf to be a node which is not a parent. Note the free variable inside the
negation. This is correct, since if the node has any child then the node is not a leaf.
The 'height' predicate computes the height of a node -- defined as the length of the longest path to a
leaf under the node. This definition uses lists and the second-order Prolog predicate 'setof'.

Prolog program for Tree data and relations :


/* The tree database */
:- op(500,xfx,'is_parent').
a is_parent b. c is_parent g.
a is_parent c. c is_parent h.
a is_parent d. c is_parent i.
b is_parent e. d is_parent j.
b is_parent f. e is_parent k.

f is_parent l. j is_parent q.
f is_parent m. j is_parent r.
h is_parent n. j is_parent s.
i is_parent o. m is_parent t.
i is_parent p.

/* X and Y are siblings */


:- op(500,xfx,'is_sibling_of').
X is_sibling_of Y :- Z is_parent X, Z is_parent Y, X \== Y.
/* X and Y are on the same level in the tree. */
:-op(500,xfx,'is_same_level_as').
X is_same_level_as X .
X is_same_level_as Y :- W is_parent X, Z is_parent Y, W is_same_level_as Z.
/* Depth of node in the tree. */

:- op(500,xfx,'has_depth').
a has_depth 0 :- !.
Node has_depth D :- Mother is_parent Node, Mother has_depth D1, D is D1 + 1.
/* Locate node by finding a path from root down to the node. */
locate(Node) :- path(Node), write(Node), nl.
path(a).

/* Can start at a.

*/

path(Node) :- Mother is_parent Node, /* Choose parent,


*/
path(Mother),
/* find path and then */
write(Mother), write(' --> ').
/* Calculate the height of a node, length of longest path to
a leaf under the node. */
height(N,H) :- setof(Z,ht(N,Z),Set), /* See section 2.8 for 'setof'. */
max(Set,0,H).
ht(Node,0) :- leaf(Node), !.
ht(Node,H) :- Node is_parent Child, ht(Child,H1), H is H1 +1.
leaf(Node) :- not(is_parent(Node,Child)). %/* Node grounded */
max([],M,M).
max([X|R],M,A) :- (X > M -> max(R,X,A) ; max(R,M,A)).

PRACTICAL No: 6
ANIMAL IDENTIFICATION GAME
The program uses its identification rules to determine the animal that you have chosen.
Prolog program for animal identification:/* animal.pro
animal identification game.
start with ?- go.

*/

go :- hypothesize(Animal), write('I guess that the animal is: '),


write(Animal), nl, undo.
/* hypotheses to be tested */
hypothesize(cheetah)
:- cheetah, !.
hypothesize(tiger)
:- tiger, !.
hypothesize(giraffe)
:- giraffe, !.
hypothesize(zebra)
:- zebra, !.
hypothesize(ostrich)
:- ostrich, !.
hypothesize(penguin)
:- penguin, !.
hypothesize(albatross) :- albatross, !.
hypothesize(unknown).
/* no diagnosis */
/* animal identification rules */
cheetah :- mammal, carnivore, verify(has_tawny_color), verify(has_dark_spots).
tiger :- mammal, carnivore, verify(has_tawny_color), verify(has_black_stripes).
giraffe :- ungulate, verify(has_long_neck), verify(has_long_legs).
zebra :- ungulate, verify(has_black_stripes).
ostrich :- bird, verify(does_not_fly), verify(has_long_neck).
penguin :- bird, verify(does_not_fly), verify(swims),verify(is_black_and_white).
/* classification rules */
mammal
:- verify(has_hair), !.
mammal
:- verify(gives_milk).
bird
:- verify(has_feathers), !.
bird
:- verify(flys),
verify(lays_eggs).
carnivore :- verify(eats_meat), !.
carnivore :- verify(has_pointed_teeth),
verify(has_claws),

verify(has_forward_eyes).
ungulate :- mammal,
verify(has_hooves), !.
ungulate :- mammal,
verify(chews_cud).
/* how to ask questions */
ask(Question) :write('Does the animal have the following attribute: '),
write(Question),
write('? '),
read(Response),
nl,
( (Response == yes ; Response == y)
->
assert(yes(Question)) ;
assert(no(Question)), fail).
:- dynamic yes/1,no/1.
/* How to verify something */
verify(S) :(yes(S)
->
true ;
(no(S)
->
fail ;
ask(S))).
/* undo all yes/no assertions */
undo :- retract(yes(_)),fail.
undo :- retract(no(_)),fail.
undo.

The program is mainly interesting with regard to how it tries to verify certain properties that it uses
to draw conclusions, and how it asks questions and records the answers for further reference. If a
question q is asked and the answer is 'yes', then that answer is recorded by asserting 'yes(q)' and
succeeding, otherwise the answer is recorded by asserting 'no(q)' and failing. Even 'yes' answers
need to be recorded since a subsequent 'no' answer to a different question while trying to verify the
same hypothesis may cause the entire hypothesis to fail, but that same 'yes' answer could lead to a
successful verification of a different hypothesis later. This is how the program avoids asking the
same question twice. The general method of verifying a condition q is then to check whether 'yes(q)'
has been stored in memory, and succeed, or 'no(q)' has been stored, and fail, otherwise ask(q).

Prolog program for animal identification:*/ start with ?- go.

*/

go :- hypothesize(Animal),
write('I guess that the animal is: '),
write(Animal),

nl,
undo.
/* hypotheses to be tested */
hypothesize(cheetah) :- cheetah, !.
hypothesize(tiger) :- tiger, !.
hypothesize(giraffe) :- giraffe, !.
hypothesize(zebra) :- zebra, !.
hypothesize(ostrich) :- ostrich, !.
hypothesize(penguin) :- penguin, !.
hypothesize(albatross) :- albatross, !.
hypothesize(unknown).
/* no diagnosis */
/* animal identification rules */
cheetah :- mammal, carnivore, verify(has_tawny_color), verify(has_dark_spots).
tiger :- mammal, carnivore, verify(has_tawny_color), verify(has_black_stripes).
giraffe :- ungulate, verify(has_long_neck), verify(has_long_legs).
zebra :- ungulate, verify(has_black_stripes).
ostrich :- bird, verify(does_not_fly), verify(has_long_neck).
penguin :- bird, verify(does_not_fly), verify(swims), verify(is_black_and_white).
/* classification rules */
mammal

:- verify(has_hair), !.

mammal

:- verify(gives_milk).

bird

:-

verify(has_feathers), !.

bird

:-

verify(flys), verify(lays_eggs).

carnivore :-

verify(eats_meat), !.

carnivore :- verify(has_pointed_teeth), verify(has_claws), verify(has_forward_eyes).


ungulate :- mammal, verify(has_hooves), !.
ungulate :- mammal, verify(chews_cud).
/* how to ask questions */
ask(Question) :- write('Does the animal have the following attribute: '), write(Question),

write('? '), read(Response), nl, ( (Response == yes ; Response == y) ->


assert(yes(Question)) ; assert(no(Question)), fail).
:- dynamic yes/1,no/1.
/* How to verify something */
verify(S) :- (yes(S) -> true ; (no(S) -> fail ; ask(S))).

PRACTICAL N0: 7
N QUEEN PROBLEM
The challenge is to set N queens on an NxN grid so that no queen can "take" any other queen.
Queens can move horizontally, vertically, or along a (45%) diagonal. The following diagram shows
a solution for N=4 queens.
________________
|
|
| Q |
|
|___|___|___|___|
| Q |
|
|
|
|___|___|___|___|
|
|
|
| Q |
|___|___|___|___|
|
| Q |
|
|

A solution to this puzzle can be represented as a special permutation of the list [1,2,3,4]. For
example, the solution pictured above can be represented as [3,1,4,2], meaning that, in the first row
place a queen in column 3, in the second row place a queen in column 1, etc. To test whether a
given permutation is a solution, one needs to calculate whether the permutation has (or represents a
situation where) two or more queens lie on the same diagonal. The representation itself prevents two
or more queens in the same row or column. Two queens are on the same / diagonal if and only if the
sum of the row and column is the same for each; they are on the same \ diagonal if and only if the
difference of their row and column is the same number. The following Prolog program has the
details; assume that predicates 'perm' and 'takeout' are defined as in section 2.7.
solve(P) :perm([1,2,3,4,5,6,7,8],P),
combine([1,2,3,4,5,6,7,8],P,S,D),
all_diff(S),
all_diff(D).

combine([X1|X],[Y1|Y],[S1|S],[D1|D]) :S1 is X1 +Y1,


D1 is X1 - Y1,
combine(X,Y,S,D).
combine([],[],[],[]).
all_diff([X|Y]) :all_diff([X]).

\+member(X,Y), all_diff(Y).

Notice the inclusion of file lists.pro discussed in section 2.6. This is a nice, simple specification that
uses 'perm' to generate possible solutions to the puzzle. A sample goal is

?- solve(P).
P = [5,2,6,1,7,4,8,3] ;
P = [6,3,5,7,1,4,2,8] ;
...
?- setof(P,solve(P),Set), length(Set,L).
...
L = 92

The last goal reflects the fact that there are 92 distinct solutions to the queens challenge puzzle for
an 8x8 board. One inefficiency that this program suffers is that each permutation is completely
calculated before it is checked to see whether it represents a solution to the puzzle. It is easy to see
that this is not necessary. For example, suppose that a "partial solution" P = [1,3,2, ...] is up for
consideration. The row and column calculations show already the "2" is not a safe move!

Prolog program for solving N Queen Chess problem :perm([X|Y],Z) :- perm(Y,W), takeout(X,Z,W).
perm([],[]).
takeout(X,[X|R],R).
takeout(X,[F|R],[F|S]) :- takeout(X,R,S).
solve(P) :-

perm([1,2,3,4,5,6,7,8],P), combine([1,2,3,4,5,6,7,8],P,S,D),
all_diff(S), all_diff(D).

combine([X1|X],[Y1|Y],[S1|S],[D1|D]) :- S1 is X1 +Y1, D1 is X1 - Y1, combine(X,Y,S,D).


combine([],[],[],[]).
all_diff([X|Y]) :- \+member(X,Y), all_diff(Y).
all_diff([X]).

Вам также может понравиться