Artificial Intelligence AI
Artificial Intelligence AI
INDEX
(Progressive Assessment Sheet)
Sr. No. Objective(s) of Experiment Page Date of Date of Assessme Sign. of Remar
No. perform submiss nt Teacher ks
ance ion Marks with date
A. Write a prolog program to put facts
indicating that sachin likes cricket, saurav
likes cricket, raj likes football, karan likes
basketball, indra likes chess and add rule
that parth likes whatever saurav likes.
Write goal for following queries:
a. Find the name of all players who
like cricket.
b. Check whether raj likes cricket or
not.
c. Display the list of all players with
the game they like.
1.
d. Display the name of players who
likes any game except cricket.
B. Implement prolog program that asks
username and password from user and
display whether login is successful or not
according to knowledge base considered
in the program.
a. Perform above program without
recursion.
b. Perform above program with
recursion.
A. Write a prolog program to put facts indicating that sachin likes cricket, saurav likes cricket, raj
likes football, karan likes basketball, indra likes chess and add rule that parth likes whatever
saurav likes. Write goal for following queries:
a. Find the name of all players who like cricket.
b. Check whether raj likes cricket or not.
c. Display the list of all players with the game they like.
d. Display the name of players who likes any game except cricket.
B. Implement prolog program that asks username and password from user and display whether
login is successful or not according to knowledge base considered in the program.
a. Perform above program without recursion.
b. Perform above program with recursion.
Competency and Practical Skills: Basic Understanding of Predicated and Prolog Syntax
Theory:
There are only three basic constructs in Prolog: facts, rules, and queries. A collection of facts and
rules is called a knowledge base (or a database) and Prolog programming is all about writing
knowledge bases. That is, Prolog programs simply are knowledge bases, collections of facts and
rules which describe some collection of relationships that we find interesting.
Knowledge Base 1
Knowledge Base 1 (KB1) is simply a collection of facts. Facts are used to state things that are
unconditionally true of some situation of interest. For example, we can state that Mia, Jody, and
Yolanda are women, that Jody plays air guitar, and that a party is taking place, using the following
five facts:
woman(mia).
woman (jody).
woman (yolanda).
playsAirGuitar(jody).
party.
Knowledge Base 2
happy (yolanda).
listens 2Music(mia).
listens 2Music(yolanda): - happy (yolanda). playsAirGuitar(mia):- listens2Music(mia).
playsAirGuitar(yolanda):- listens 2Music(yolanda).
There are two facts in KB2, listens2Music(mia) and happy(yolanda). The last three items it contains
are rules.
Rules state information that is conditionally true of the situation of interest The part on the left hand
side of the: - is called the head of the rule, the part on the right hand side is called the body. So in
general rules say: if the body of the rule is true, then the head of the rule is true too. And now for
the key point:
If a knowledge base contains a rule head - body, and Prolog knows that body follows from the
information in the knowledge base, then Prolog can infer head. This fundamental deduction step is
called modus ponens.
Knowledge Base 3
Knowledge Base 4
There are no rules, only a collection of facts. we're going to make use of variables. Here's an
example:
?- woman(X).
Prolog answers this query by working its way through KB4, from top to bottom, trying to unify
Artificial Intelligence (3161608) Meet Chikani(210130116011)
(or match) the expression woman(X) with the information KB4 contains. Now the first item in the
knowledge base is woman(mia). So, Prolog unifies X with mia, thus making the query agree
perfectly with this first item. (Incidentally, there's a lot of different terminology for this process: we
can also say that Prolog instantiates X to mia, or that it binds X to mia .) Prolog then reports back
to us as follows:
X = mia
That is, it not only says that there is information about at least one woman in KB4, it actually tells
us who she is. It didn't just say yes, it actually gave us the variable binding (or variable instantiation)
that led to success.
Knowledge Base 5
person(john).
person(susan).
person(bob).
person(alice).
city(new_york).
city(london).
city(paris).
city(tokyo).
lives_in(john, new_york).
lives_in(susan, london).
lives_in(bob, paris).
lives_in(alice, tokyo).
likes(john, sushi).
likes(john, pizza).
likes(susan, pizza).
likes(bob, croissants).
likes(alice, sushi).
likes_same_food(X, Y) :-
likes(X, Z),
likes(Y, Z),
X \= Y.
In this example, we have defined a knowledge base that includes facts about people and cities, as
well as rules that define relationships between them. Specifically, we have defined the following:
● Four facts that define the people in our knowledge base (john, susan, bob, and alice) and
the cities they live in (new_york, london, paris, and tokyo).
● Five facts that define the food preferences of our people.
● A rule called likes_same_food/2 that defines a relationship between two people who like
the same food.
To use this knowledge base, we can query it using Prolog's built-in ?- operator. For example, we
can ask:
?- likes(john, sushi).
true.
This will return true, indicating that John likes sushi.
Procedure:
1. Define the domain of the knowledge base.
2. Define the facts.
3. Define the rules.
4. Test the knowledge base.
Observation/Program:
For Part A
% Login predicate
login(Username, Password) :-
user_credentials(Username, Password),
format('Login successful. Welcome, ~w!~n', [Username]).
login(_, _) :-
format('Login failed. Invalid username or password.~n').
b.
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Conclusion:
Prolog is a useful tool for implementing knowledge bases for various domains, including family
relationships, and can provide efficient and effective reasoning capabilities for querying and
analyzing such data.)
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Experiment No: 2
Objectives:To create a functional and efficient Prolog program for solving logic puzzles.
Theory:
In Prolog, a program consists of a set of facts and rules that define relationships and properties in
a knowledge base. The primary theoretical foundation of Prolog is based on formal logic,
specifically first-order logic. Here's a brief overview of the key theoretical concepts that underlie
Prolog programs:
1. Predicates:
In Prolog, predicates are used to represent relationships or properties in the form of clauses.
Predicates consist of a name (an atom) and a fixed number of arguments. For example, `parent(X,
Y)` represents the "parent" relationship with two arguments, X and Y.
2. Facts:
Facts are the basic building blocks of Prolog programs. They represent simple, unconditionally
true statements. For example:
```
parent(john, mary).
```
3. Rules:
Rules define relationships and properties based on the satisfaction of certain conditions. Rules
have a head and a body. The head specifies the predicate to be derived, and the body specifies the
conditions that must be satisfied for the rule to apply. For example:
```
grandparent(X, Y) :- parent(X, Z), parent(Z, Y).
```
In this rule, `grandparent(X, Y)` is derived if `parent(X, Z)` and `parent(Z, Y)` are satisfied.
4. Logical Inference:
Prolog uses logical inference to make queries and derive conclusions from the facts and rules. It
employs a resolution-based mechanism to perform backward chaining, where it works backward
Artificial Intelligence (3161608) Meet Chikani(210130116011)
from the goal (query) to the premises (facts and rules) to find a solution. This is done using
unification, a process that matches variables in the query with terms in the knowledge base.
6. Recursion:
Recursion is a common and powerful technique in Prolog. It allows rules to refer to themselves,
enabling the definition of complex relationships and properties. For example, a rule for calculating
factorial using recursion:
```
factorial(0, 1).
factorial(N, F) :- N > 0, N1 is N - 1, factorial(N1, F1), F is N * F1.
```
7. Termination:
It is essential to ensure that Prolog programs terminate for all possible queries. Non-terminating
programs can lead to infinite loops and are generally undesirable.
Prolog's theoretical foundation in logic, along with its mechanism for logical inference, allows it to
express and solve complex problems in a declarative way. Prolog is particularly well-suited for tasks
involving symbolic reasoning, knowledge representation, and search problems. It is widely used in
artificial intelligence, expert systems, natural language processing, and more.
Observation/Program:
a. To find the greatest variable among the three variables.
greatest(X, Y, Z, Max) :-
( X >= Y, X >= Z -> Max = X
; Y >= X, Y >= Z -> Max = Y
; Max = Z ).
b. To find a factorial of a given number.
factorial(0, 1).
factorial(N, Fact) :-
N > 0,
N1 is N - 1,
factorial(N1, Fact1),
Fact is N * Fact1.
c. To check whether a given number is palindrome or not.
reverse_number(0, Num, Num).
reverse_number(N, Num, Rev) :-
N > 0,
N1 is N div 10,
Digit is N mod 10,
NewNum is Num * 10 + Digit,
reverse_number(N1, NewNum, Rev).
is_palindrome(N) :-
Artificial Intelligence (3161608) Meet Chikani(210130116011)
reverse_number(N, 0, Rev),
N =:= Rev.
d. To check whether a given number is prime or not.
is_prime(N) :-
N > 1,
N1 is floor(sqrt(N)),
\+ (between(2, N1, X), N mod X =:= 0).
Conclusion:
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Experiment No: 3
Objectives:To optimize the performance of the A* algorithm by minimizing the number of states
explored and improving the efficiency of the heuristic function.
Theory:
A* Algorithm
A* is a computer algorithm that is widely used in pathfinding and graph traversal, the process of
plotting an efficiently traversable path between multiple points, called nodes. Noted for its
performance and accuracy, it enjoys widespread use.
The key feature of the A* algorithm is that it keeps a track of each visited node which helps in
ignoring the nodes that are already visited, saving a huge amount of time. It also has a list that holds
all the nodes that are left to be explored and it chooses the most optimal node from this list, thus
saving time not exploring unnecessary or less optimal nodes.
So we use two lists namely ‘open list‘ and ‘closed list‘ the open list contains all the nodes that are
being generated and are not existing in the closed list and each node explored after it’s neighboring
nodes are discovered is put in the closed list and the neighbors are put in the open list this is how
the nodes expand. Each node has a pointer to its parent so that at any given point it can retrace the
path to the parent. Initially, the open list holds the start(Initial) node. The next node chosen from
the open list is based on its f score, the node with the least f score is picked up and explored.
A* uses a combination of heuristic value (h-score: how far the goal node is) as well as the g-score
(i.e. the number of nodes traversed from the start node to current node).
In our 8-Puzzle problem, we can define the h-score as the number of misplaced tiles by comparing
the current state and the goal state or summation of the Manhattan distance between misplaced
nodes.
g-score will remain as the number of nodes traversed from start node to get to the current node.
calculate the h-score by comparing the initial(current) state and goal state and counting the number
of misplaced tiles.
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Thus, h-score = 5 and g-score = 0 as the number of nodes traversed from the start node to the
current node is 0.
We first move the empty space in all the possible directions in the start state and calculate
the f-score for each state. This is called expanding the current state.
After expanding the current state, it is pushed into the closed list and the newly generated states
are pushed into the open list. A state with the least f-score is selected and expanded again. This
process continues until the goal state occurs as the current state. Basically, here we are providing
the algorithm a measure to choose its actions. The algorithm chooses the best possible action and
proceeds in that path.
This solves the issue of generating redundant child states, as the algorithm will expand the node
with the least f-score.
It is important to handle edge cases such as unsolvable puzzles, invalid puzzle states, and memory
limitations to avoid program crashes or incorrect results.
Procedure:
1. Define the starting and goal states of the puzzle.
Artificial Intelligence (3161608) Meet Chikani(210130116011)
2. Implement the A* algorithm, which uses the heuristic function to determine the best path to
reach the goal state.
Observation/Program:
can_it_move_left(Left):-
Left >= 0,
Left \= 2,
Left \= 5.
can_it_move_right(Right):-
8 >= Right,
Right \= 3,
Right \= 6.
can_it_move_down(Down):-
Down < 9.
can_it_move_up(Up):-
Up > 0.
countInversions(_,[],Inversions):-
Inversions is 0.
countInversions(Number,[Head|Tail],Inversions):-
Number>Head,
Count is 1,
countInversions(Number,Tail,Aux_inversions),
Inversions is Count+Aux_inversions.
countInversions(Number,[Head|Tail],Inversions):-
Number<Head,
Count is 0,
countInversions(Number,Tail,Aux_inversions),
Inversions is Count+Aux_inversions.
issolvable([],A):-
A is 0.
issolvable([Head|Tail],Inversions):-
countInversions(Head,Tail,Aux_inversions),
issolvable(Tail,Next_inversions),
Inversions is Next_inversions+Aux_inversions.
iseven(Number):-
0 is mod(Number,2).
solvepuzzle(Initial_state,Goal_state,Result):-
flatten(Initial_state, List_initial_state),
delete(List_initial_state, 0, X),
issolvable(X,Inversions),
0 is mod(Inversions,2),
flatten(Goal_state, List_goal_state),
delete(List_goal_state, 0, Y),
issolvable(Y,Inversions_two),
0 is mod(Inversions_two,2),
empty_heap(Inital_heap),
Explored_set = [List_initial_state],
astar([List_initial_state,0],List_goal_state,Goal_state,Inital_heap,Explored_set,Iterations),
copy_term(Iterations, Result),
!.
solvepuzzle(Initial_state,Goal_state,Result):-
flatten(Initial_state, List_initial_state),
delete(List_initial_state, 0, X),
Artificial Intelligence (3161608) Meet Chikani(210130116011)
issolvable(X,Inversions),
\+0 is mod(Inversions,2),
flatten(Goal_state, List_goal_state),
delete(List_goal_state, 0, Y),
issolvable(Y,Inversions_two),
\+0 is mod(Inversions_two,2),
empty_heap(Inital_heap),
Explored_set = [List_initial_state],
astar([List_initial_state,0],List_goal_state,Goal_state,Inital_heap,Explored_set,Iterations),
copy_term(Iterations, Result),
!.
solvepuzzle(_,_,Result):-
Result = 'No solution'.
create_explored_set(Old_Set,Element,X):-
Aux = [Element],
append(Old_Set,Aux,X).
divide_list([Head|_],Head).
print_element([],_).
print_element([Head|Tail],I):-
0 is mod(I,3),
Newi=I+1,
nl,
print(Head),
print_element(Tail,Newi).
print_element([Head|Tail],I):-
Newi=I+1,
print(Head),
print_element(Tail,Newi).
print_list([],_).
print_list([Head|Tail],I):-
number(Head),
print_list(Tail,I).
print_list([Head|Tail],I):-
Newi=I+1,
print_list(Tail,Newi),
print_element(Head,0),
nl.
create_list_with_new_cost([],_,_,_).
create_list_with_new_cost([Head|Tail],Iterator,Pos_cost,[New_cost|Tail]):-
Iterator == Pos_cost,
New_iterator is Iterator+1,
New_cost is Head + 1,
create_list_with_new_cost(Tail,New_iterator,Pos_cost,Tail).
create_list_with_new_cost([Head|Tail],Iterator,Pos_cost,[Head|Tail2]):-
New_iterator is Iterator+1,
create_list_with_new_cost(Tail,New_iterator,Pos_cost,Tail2).
astar([Head|Tail],Head,_,_,_,Result):-
append([Head],Tail,Fathers),
print_list(Fathers,0),
length(Tail,Aux),
Result is Aux-1.
astar(State,Goal_state,Grid_goal_state,Priority_queue,Explored_set,Result):-
divide_list(State,State_to_esplore),
nth0(Position_blank_tile,State_to_esplore, 0),
length(State,Pos_cost),
Artificial Intelligence (3161608) Meet Chikani(210130116011)
findcombinations(State,Matrix_goal_state,Position_blank_tile,0,Old_priority_queue,Cost_move_grid,Explor
ed_set,New_priority_queue):-
findcombinations(State,Matrix_goal_state,Position_blank_tile,1,Old_priority_queue,Cost_move_grid,
Explored_set,New_priority_queue).
findcombinations(State,Matrix_goal_state,Position_blank_tile,1,Old_priority_queue,Cost_move_grid,Explor
ed_set,New_priority_queue):-
divide_list(State,State_to_esplore),
Right is Position_blank_tile + 1,
can_it_move_right(Right),
swap_tiles(State_to_esplore, Position_blank_tile, Right, Permutation_right),
\+member(Permutation_right,Explored_set),
convert_to_matrix(Permutation_right,Matrix_per_right),
findcost(Permutation_right,Matrix_per_right,Matrix_goal_state,Cost),
create_list_of_explored_states(State,Permutation_right,State_with_fathers),
New_cost is Cost_move_grid + Cost,
add_to_heap(Old_priority_queue,New_cost,State_with_fathers,Aux_priority_queue),
findcombinations(State,Matrix_goal_state,Position_blank_tile,2,Aux_priority_queue,Cost_move_grid
,Explored_set,New_priority_queue).
findcombinations(State,Matrix_goal_state,Position_blank_tile,1,Old_priority_queue,Cost_move_grid,Explor
ed_set,New_priority_queue):-
findcombinations(State,Matrix_goal_state,Position_blank_tile,2,Old_priority_queue,Cost_move_grid,
Explored_set,New_priority_queue).
findcombinations(State,Matrix_goal_state,Position_blank_tile,2,Old_priority_queue,Cost_move_grid,Explor
ed_set,New_priority_queue):-
divide_list(State,State_to_esplore),
Down is Position_blank_tile + 3,
can_it_move_down(Down),
swap_tiles(State_to_esplore, Position_blank_tile, Down, Permutation_down),
\+member(Permutation_down,Explored_set),
convert_to_matrix(Permutation_down,Matrix_per_down),
findcost(Permutation_down,Matrix_per_down,Matrix_goal_state,Cost),
create_list_of_explored_states(State,Permutation_down,State_with_fathers),
New_cost is Cost_move_grid + Cost,
add_to_heap(Old_priority_queue,New_cost,State_with_fathers,Aux_priority_queue),
findcombinations(State,Matrix_goal_state,Position_blank_tile,3,Aux_priority_queue,Cost_move_grid
,Explored_set,New_priority_queue).
findcombinations(State,Matrix_goal_state,Position_blank_tile,2,Old_priority_queue,Cost_move_grid,Explor
ed_set,New_priority_queue):-
findcombinations(State,Matrix_goal_state,Position_blank_tile,3,Old_priority_queue,Cost_move_grid,
Explored_set,New_priority_queue).
findcombinations(State,Matrix_goal_state,Position_blank_tile,3,Old_priority_queue,Cost_move_grid,Explor
ed_set,New_priority_queue):-
divide_list(State,State_to_esplore),
Up is Position_blank_tile -3,
can_it_move_up(Up),
swap_tiles(State_to_esplore, Position_blank_tile, Up, Permutation_up),
\+member(Permutation_up,Explored_set),
convert_to_matrix(Permutation_up,Matrix_per_up),
findcost(Permutation_up,Matrix_per_up,Matrix_goal_state,Cost),
create_list_of_explored_states(State,Permutation_up,State_with_fathers),
New_cost is Cost_move_grid + Cost,
add_to_heap(Old_priority_queue,New_cost,State_with_fathers,Aux_priority_queue),
findcombinations(State,Matrix_goal_state,Position_blank_tile,4,Aux_priority_queue,Cost_move_grid
,Explored_set,New_priority_queue).
findcombinations(State,Matrix_goal_state,Position_blank_tile,3,Old_priority_queue,Cost_move_grid,Explor
Artificial Intelligence (3161608) Meet Chikani(210130116011)
ed_set,New_priority_queue):-
findcombinations(State,Matrix_goal_state,Position_blank_tile,4,Old_priority_queue,Cost_move_grid,
Explored_set,New_priority_queue).
findcombinations(_,_,_,4,Old_priority_queue,_,_,New_priority_queue):-
copy_term(Old_priority_queue,New_priority_queue).
matrix(M, X, Y, Element) :-
nth0(X, M, R),
nth0(Y, R, Element).
swap_tiles(List,Zero,Move,Nl):-
Ayuda is Move+1,
Zero==Ayuda,
nth0(Move,List, Number_to_find),
aux_swap_tiles(List,Move,0,New_list,_,List_to_explore_more),
append(New_list,[0],Nl_aux),
append(Nl_aux,[Number_to_find],Nl_aux2),
delete(List_to_explore_more, 0, X),
append(Nl_aux2,X,Nl),
!.
swap_tiles(List,Zero,Move,Nl):-
Ayuda is Move-1,
Zero==Ayuda,
nth0(Move,List,Number_to_find),
aux_swap_tiles(List,Zero,0,New_list,_,List_to_explore_more),
append(New_list,[Number_to_find],Nl_aux),
append(Nl_aux,[0],Nl_aux2),
delete(List_to_explore_more, Number_to_find, X),
append(Nl_aux2,X,Nl),
!.
swap_tiles(List,Zero,Move,Nl):-
Ayuda is Move+1,
Ayuda_dos is Move-1,
Zero<Move,
\+Zero==Ayuda,
\+Zero==Ayuda_dos,
nth0(Move,List, Number_to_find),
aux_swap_tiles(List,Zero,0,New_list,Current_iterator,List_to_explore_more),
append(New_list,[Number_to_find],Nl_aux),
aux_swap_tiles(List_to_explore_more,Move,Current_iterator+1,New_list_two,_,List_to_explore_mor
e_two),
append(Nl_aux,New_list_two,Nl_aux_two),
append(Nl_aux_two,[0],Nl_aux_three),
append(Nl_aux_three,List_to_explore_more_two,Nl),
!.
swap_tiles(List,Zero,Move,Nl):-
Ayuda is Move+1,
Ayuda_dos is Move-1,
Zero>Move,
\+Zero==Ayuda,
\+Zero==Ayuda_dos,
nth0(Move,List, Number_to_find),
aux_swap_tiles(List,Move,0,New_list,Current_iterator,List_to_explore_more),
append(New_list,[0],Nl_aux),
aux_swap_tiles(List_to_explore_more,Zero,Current_iterator+1,New_list_two,_,List_to_explore_more
_two),
append(Nl_aux,New_list_two,Nl_aux_two),
Artificial Intelligence (3161608) Meet Chikani(210130116011)
append(Nl_aux_two,[Number_to_find],Nl_aux_three),
append(Nl_aux_three,List_to_explore_more_two,Nl),
!.
aux_swap_tiles([_|Tail],Limit,Iterator,[],X,Tail):-
Iterator==Limit,
copy_term(Iterator,X).
aux_swap_tiles([Head|Tail],Limit,Iterator,[Head|Tail2],X,List_to_explore_more):-
Iterator<Limit,
New_iterator is Iterator+1,
aux_swap_tiles(Tail,Limit,New_iterator,Tail2,X,List_to_explore_more).
Conclusion:
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Experiment No: 4
Objectives: Learning about lists in Prolog is a fundamental and valuable concept as it allows you to
work with structured data and perform a wide range of tasks.
Theory:
Lists are a fundamental data structure in Prolog, allowing you to work with collections of
elements. In Prolog, a list is a sequence of terms enclosed in square brackets (`[ ]`). Lists
can contain a mix of elements, including atoms, variables, and other lists. Here's an
overview of the theory behind lists in Prolog:
1. List Syntax:
- In Prolog, lists are denoted by square brackets, such as `[a, b, c]`, which represents a
list of three atoms: 'a,' 'b,' and 'c.'
- Lists can be empty, represented as `[]`.
2. List Elements:
- Lists in Prolog can contain a mix of elements, including:
- Atoms (e.g., `a`, `b`, `c`)
- Variables (e.g., `X`, `Y`)
- Other lists (e.g., `[a, [b, c], d]`)
3. List Construction:
- Lists can be constructed using the "cons" operator, represented as `|` (often referred to
as "pipe").
- The "cons" operator allows you to prepend an element to an existing list or split a
list into its head and tail.
- For example, `[X | Rest]` represents a list with the first element `X` and the
remaining elements in `Rest`.
4. List Operations:
- Prolog provides various built-in predicates for working with lists, including:
- `length/2`: Finding the length of a list.
- `append/3`: Concatenating lists.
- `member/2`: Checking if an element is a member of a list.
- `nth0/3` and `nth1/3`: Accessing elements at a specific position in the list.
- `reverse/2`: Reversing a list.
- `select/3`: Removing an element from a list.
- `permutation/2`: Generating permutations of a list.
Artificial Intelligence (3161608) Meet Chikani(210130116011)
6. List Comprehensions:
- Prolog supports list comprehensions, which provide a declarative way to generate lists
based on conditions.
- List comprehensions are concise and resemble set-builder notation.
7. Higher-Order Predicates:
- Prolog allows you to define and use higher-order predicates that take lists as
arguments.
- Higher-order predicates can simplify list processing, making code more elegant and
concise.
Understanding lists in Prolog is crucial for a wide range of applications, from basic data
manipulation to complex problem-solving. Lists are a versatile data structure that enables
you to represent and process structured information efficiently in Prolog.
Observation/Program:
(a) To display first elements of a list.
Facts:-
first_element ([FirstElement |_ ], FirstElement).
Output:
Output:
count_odd_even(T, OddCount,
NewEvenCount), EvenCount is
NewEvenCount + 1.
Output:
Conclusion:-
The above Prolog programs are designed to perform various operations on lists. These
programs can be used to extract specific elements, count the number of elements, count
odd and even elements, and find the sum of elements in a list. By utilizing these
programs, one can efficiently work with list data structures in Prolog.
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Experiment No: 5
Objectives: The water jug problem, also known as the "water pouring problem" or "die hard
problem," is a classic puzzle in which the objective is to find a sequence of actions to measure a
specific volume of water using two jugs of known capacities. The problem involves critical
thinking and can be used to practice problem-solving skills.
Theory:
The water jug problem, also known as the "water pouring problem" or "die hard problem," is a
classic puzzle that involves finding a sequence of actions to measure or obtain a specific
volume of water using two jugs of known capacities. The problem can vary in complexity
depending on the specific constraints provided. Here is the theoretical background and the key
elements of the water jug problem:
Problem Statement:
- The problem typically involves two jugs with known capacities, often referred to as Jug A
and Jug B.
- There is usually a target volume of water that you need to measure or achieve using the jugs.
2. Wastage: Some variations of the problem may allow for, or restrict, wastage of water
during the pouring process. Wastage occurs when water is poured out and not used in the
target measurement.
2. Mathematical Analysis: In some cases, the problem can be solved through mathematical
modeling and equations. The mathematical approach may aim to find the optimal sequence of
actions.
Variations:
The water jug problem has multiple variations, including different jug capacities, additional
constraints (e.g., limited pouring steps), and variations that involve more than two jugs. Each
variation presents a unique challenge and may require a different approach.
Applications:
While the water jug problem is a classic puzzle, it also has practical applications, such as
modeling fluid transfers, understanding capacity constraints in logistics, and demonstrating
problem-solving techniques in artificial intelligence and computer science.
Solving the water jug problem serves as an excellent exercise in critical thinking,
problem-solving, and algorithm design, making it a valuable educational tool and a fascinating
logic puzzle.
Procedure:
% Water Jug problem using DFS in Prolog
\+ member(State1, Visited),
dfs(State1, Actions, [State1|Visited]).
Output:
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Experiment No: 6
Implement the Minimax algorithm for a simple tic-tac-toe game using Python Language.
Objectives: To illustrate how to recursively apply the Minimax algorithm to build a game tree
and determine the optimal move for the computer player.
Theory:
● The Minimax Algorithm is a popular decision-making algorithm used in game
theory, which allows a player to determine the best possible move to make, given
that the opponent will also make the best possible move.
● Here's a general implementation of the Minimax algorithm:
● Define the game state: The game state should be defined in terms of the current
state of the board or game, including the position of all pieces, scores, and any other
relevant information.
● Define the game tree: The game tree represents all the possible moves that can be
made from the current game state, and the resulting game states that will arise from
each move. The game tree can be constructed recursively, with the root node
representing the current game state, and the child nodes representing the possible
moves that can be made from that state.
● Assign scores to each game state: At the bottom of the game tree, assign a score to
each game state based on the outcome of the game from that state. For example, if
the game is won by the player who reached that state, assign a positive score, and
if the game is lost, assign a negative score.
● Determine the best move: Starting from the root node, alternate between selecting
the move that maximizes the score for the player and selecting the move that
minimizes the score for the opponent until you reach a leaf node. The score of that
leaf node will then be propagated back up the tree to the root node, and the best
move will be the one that leads to the highest score.
Handle edge cases such as invalid moves, repeated moves, and game-ending conditions to avoid
program crashes or incorrect results.
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Procedure:
1. Define an evaluation function to evaluate the game state and return a score.
2. Define a recursive function to search for the best move using the Minimax
algorithm.
3. Create a function to get the best move for the current player.
Observation/Program:
import math
def print_board(board):
for row in board:
print(" ".join(row))
def is_full(board):
return all(all(cell != ' ' for cell in row) for row in board)
def evaluate(board):
if check_win(board, 'X'):
return 10
elif check_win(board, 'O'):
return -10
elif is_full(board):
return 0
else:
return None
if maximizing_player:
max_eval = -math.inf
for row in range(3):
for col in range(3):
if board[row][col] == ' ':
board[row][col] = 'O'
eval = minimax(board, depth - 1, False)
board[row][col] = ' '
max_eval = max(max_eval, eval)
return max_eval
else:
Artificial Intelligence (3161608) Meet Chikani(210130116011)
min_eval = math.inf
for row in range(3):
for col in range(3):
if board[row][col] == ' ':
board[row][col] = 'X'
eval = minimax(board, depth - 1, True)
board[row][col] = ' '
min_eval = min(min_eval, eval)
return min_eval
def find_best_move(board):
best_score = -math.inf
move = (-1, -1)
for row in range(3):
for col in range(3):
if board[row][col] == ' ':
board[row][col] = 'O'
score = minimax(board, 3, False)
board[row][col] = ' '
if score > best_score:
best_score = score
move = (row, col)
return move
def tic_tac_toe():
board = [[' ' for _ in range(3)] for _ in range(3)]
while True:
print_board(board)
print("Player X, enter your move (row and column separated by a space):")
row, col = map(int, input().split())
if board[row - 1][col - 1] == ' ':
board[row - 1][col - 1] = 'X'
if not check_win(board, 'X') and not is_full(board):
move = find_best_move(board)
board[move[0]][move[1]] = 'O'
if check_win(board, 'X'):
print_board(board)
print("Player X wins!")
break
elif is_full(board):
print_board(board)
print("It's a draw!")
break
else:
continue
else:
print("That cell is already occupied. Try again.")
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Output:
Conclusion:-
The Minimax algorithm is a powerful method for decision-making in games,
considering all possible moves and outcomes to find the optimal strategy. It's
widely applicable and can be optimized for efficiency, making it a key tool
for developing AI opponents in various games.
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Experiment No: 7
Implement Bayesian Networks algorithm for the Monty Hall Problem using any
programming Language.
Objectives:To understand how Bayesian Networks can be used to represent and reason about
uncertain knowledge.
Theory:
Bayesian Networks is a probabilistic graphical model used for representing and reasoning about
uncertain knowledge. It consists of a directed acyclic graph (DAG) where nodes represent random
variables and edges represent dependencies between them. Each node has a conditional probability
distribution (CPD) that describes the probability of that node given its parents. Bayesian Networks
can be used for a wide range of tasks including prediction, classification, diagnosis, and decision-
making.
The algorithm for constructing a Bayesian Network involves the following steps:
● Identify the random variables: The first step is to identify the random variables that are
relevant to the problem. These variables can be discrete or continuous, and can represent
events, states, or properties.
● Define the dependencies: The next step is to define the dependencies between the variables.
This is done by specifying the causal relationships between the variables, and determining
which variables are parents and which are children.
● Assign probabilities: The next step is to assign probabilities to the variables. This involves
specifying the prior probabilities for each variable, as well as the conditional probabilities
for each node given its parents.
● Construct the graph: The final step is to construct the DAG by connecting the nodes
according to their dependencies, and specifying the CPDs for each node.
It is a famous probability puzzle based on a game show scenario. The problem is named after
Monty Hall, the host of the game show "Let's Make a Deal".
The scenario goes as follows:
● There are three doors, behind one of which is a prize, and behind the other two are goats.
The player chooses one door, and then the host, who knows what is behind each door,
Artificial Intelligence (3161608) Meet Chikani(210130116011)
opens one of the other two doors to reveal a goat. The player is then given the option to
switch their choice to the other unopened door or stick with their original choice.
● The question is: should the player switch their choice, or stick with their original choice?
● The answer is that the player should always switch their choice.
● To understand why this is the case, consider the following:
● When the player initially chooses a door, there is a 1/3 chance that they have chosen the
door with the prize, and a 2/3 chance that they have chosen a door with a goat. When the
host then opens one of the other doors to reveal a goat, the probability that the player's initial
choice was correct remains at 1/3. However, the probability that the prize is behind the other
unopened door is now 2/3.
● Therefore, when given the option to switch, the player should always switch because the
probability of winning the prize increases from 1/3 to 2/3. This may seem counterintuitive,
as it goes against our initial intuition that the probability of winning should be equally
distributed among the three doors. However, this is a classic example of how probabilities
can be counterintuitive, and why it is important to understand the underlying mathematics.
Ensure that the algorithm produces accurate results, it is important to validate the input
data to ensure that it is consistent and complete.
Procedure:
1. Define an evaluation function to evaluate the game state and return a score.
2. Define a recursive function to search for the best move using the Minimax
algorithm.
3. Create a function to get the best move for the current player.
Observation/Program:
from pgmpy.models import BayesianModel
from pgmpy.factors.discrete import TabularCPD
from pgmpy.inference import VariableElimination
inference = VariableElimination(model)
# Assuming the player initially chooses door 0, and the host opens door 1
result = inference.query(variables=['Prize'], evidence={'Player': 0, 'Host': 1})
print(result)
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Output:-
Conclusion:
In the Monty Hall problem, switching doors after one is revealed to be empty increases the
probability of winning from 1/3 to 2/3, while staying with the original choice maintains a 1/3
probability. This counterintuitive result demonstrates the importance of understanding
conditional probabilities in decision-making scenarios.
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Experiment No: 8
Demonstrate Connectionist Model using Tool.
Familiarity with neural networks, which are computational models inspired by the structure and
function of the brain.
Familiarity with a neural network tool.
Objectives:Learn a tool should be selected that provides an easy-to-use interface for designing,
training, and deploying Connectionist Model.
Theory:
Connectionist Models
Neural networks are by far the most commonly used connectionist model today.
● Though there are a large variety of neural network models, they almost always follow two
basic principles regarding the mind:
● Any mental state can be described as an (N)-dimensional vector of numeric activation
values over neural units in a network.
● Memory is created by modifying the strength of the connections between neural units. The
connection strengths, or "weights", are generally represented as an N×N matrix.
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Observation/Program:
import numpy as np
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.utils import to_categorical
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(784,)))
model.add(Dense(512, activation='relu'))
model.add(Dense(2, activation='softmax'))
model.save('mnist_binary_classification.h5')
Output:
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Experiment No: 9
Implement Genetic Algorithm in any Programming Language.
Understanding of genetic algorithms, which are a class of optimization algorithms that are
inspired by the principles of natural selection and genetics.
Knowledge of a programming language
Objectives:To use a computational approach that mimics the process of natural selection to solve
optimization problems
Equipment/InstrumentsProgramming language
Theory:
Genetic Algorithm (GA) is a popular meta heuristic optimization algorithm in the field of artificial
intelligence (AI).Genetic Algorithms are based on the theory of natural selection and work on
generating a set of random solutions and making them compete in an arena where only the fittest
survive. It is often used to solve complex optimization problems where other traditional methods
may not work well.
The first step in using GA for an AI problem is to define the problem as an optimization problem.
This involves identifying the objective function that needs to be optimized and the constraints (if
any) that need to be satisfied.
Once the problem is defined, the next step is to create an initial population of candidate solutions.
The population is typically generated randomly or using some heuristics depending on the problem.
The fitness function is then defined, which evaluates each chromosome in the population based on
how well it satisfies the objective function and constraints.
Next, the GA applies selection, crossover, and mutation operators to create new and hopefully better
solutions. Selection involves choosing the top-performing chromosomes to be carried over to the
next generation. Crossover involves combining two chromosomes to create new offspring. Mutation
involves randomly changing some genes in a chromosome to introduce diversity into the population.
The GA then repeats the process of selection, crossover, and mutation for a number of generations
Artificial Intelligence (3161608) Meet Chikani(210130116011)
or until a stopping criterion is met (such as reaching a maximum number of generations or finding
an optimal solution).
It is important to define clear objectives and constraints for the optimization problem.
It is crucial to validate the fitness function.
Procedure:
1. Define the problem
2. Define the representation
3. Initialize the population.
4. Evaluate the fitness
5. Select parents.
6. Create offspring: Use genetic operators such as crossover and mutation to create offspring
from the selected parents.
7. Evaluate the offspring.
8. Select survivor
9. Check stopping criteria
Observation/Program:
import random
Output:
Conclusion:
In conclusion, genetic algorithms offer an effective heuristic approach for optimization and search
problems, leveraging principles of natural selection and genetics. By iteratively evolving populations of
candidate solutions through selection, crossover, and mutation, genetic algorithms efficiently explore
solution spaces and converge towards optimal or near-optimal solutions, making them valuable in a wide
range of problem domains where traditional methods may be impractical or insufficient.
Artificial Intelligence (3161608) Meet Chikani(210130116011)
Experiment No: 10
Write a prolog program to solve Tower of Hanoi problem.
Objectives: The Tower of Hanoi problem is a classic mathematical puzzle that involves moving
a stack of disks from one peg to another while adhering to specific rules. The primary objective is
to find a sequence of moves that allows you to transfer the entire stack to a different peg.
Theory:
The Tower of Hanoi is a classic mathematical puzzle that was invented by the French mathematician
Édouard Lucas in 1883. It consists of three pegs and a number of disks of different sizes, which can
be slid onto any peg. The puzzle's objective is to move the entire stack of disks from one peg to
another, subject to the following rules:
2. Initial Configuration: The puzzle begins with all the disks stacked in decreasing order of size
on one peg, typically peg A. The smallest disk is on top, and the largest disk is at the bottom.
3. Goal Configuration: The goal is to move the entire stack of disks to another peg, typically peg
C. The disks should be stacked in the same order (smallest on top, largest on the bottom) on the
destination peg.
4. Intermediate Peg: You can use peg B as an intermediate peg to move the disks. This means
that you can only move one disk at a time from the top of one peg to the top of another peg.
5. Larger Disk on Top: A disk can never be placed on top of a smaller disk.
1. Recursion: The Tower of Hanoi problem is inherently recursive in nature. To solve a problem
with n disks, you can break it down into smaller subproblems, such as moving the top n-1 disks to
an intermediate peg, moving the largest disk to the destination peg, and then moving the n-1 disks
from the intermediate peg to the destination peg. This recursive decomposition is a fundamental
aspect of the problem.
Artificial Intelligence (3161608) Meet Chikani(210130116011)
2. Minimum Number of Moves: The minimum number of moves required to solve the Tower of
Hanoi problem with n disks is 2^n - 1. This is a well-established theoretical result and is used as a
basis for understanding the problem's complexity.
3. Recursive Formula: The number of moves required to solve the Tower of Hanoi problem for n
disks can be described by the recursive formula: `H(n) = 2 * H(n-1) + 1`, with the base case `H(1)
= 1`.
4. Mathematical Induction: Mathematical induction can be used to prove the minimum number of
moves required to solve the Tower of Hanoi problem for any number of disks.
5. Generalizations: The Tower of Hanoi problem can be generalized to include more than three
pegs, leading to variations like the Tower of Hanoi with four or more pegs. These generalizations
introduce new challenges and require different strategies for solving the problem.
6. Educational Significance: The Tower of Hanoi is often used as an educational tool to teach
concepts of recursion, mathematical induction, and algorithm design. It serves as a classic example
of a problem that can be solved using recursive algorithms.
The Tower of Hanoi problem, with its elegant mathematical properties and recursive nature,
continues to be a fundamental puzzle in computer science, mathematics, and education. It
exemplifies the power of recursion in problem-solving and serves as a valuable teaching and
learning tool.
The program should handle exceptions, such as input errors or invalid operations.
Observation/Program:
write(Destination), nl.
Destination) :-
N > 1,
M is N - 1,
Auxiliary),
Destination).
Output:
Conclusion:
In conclusion, the Tower of Hanoi problem is elegantly solved using Prolog through recursive
backtracking. By defining a predicate `hanoi/4`, the program efficiently generates the sequence of moves
required to transfer a stack of disks from one peg to another while adhering to the rules of the puzzle.
Prolog's declarative nature and built-in backtracking mechanism simplify the implementation of recursive
algorithms, making it a suitable choice for solving such logical puzzles.