DEPARTMENT OF INFORMATION TECHNOLOGY
ARTIFICIAL INTELLIGENCE AND EXPERT
SYSTEMS LABORATORY MANUAL
DELHI TECHNOLOGICAL UNIVERSITY
(Formerly Delhi College of Engineering)
Shahbad Daulatpur, Bawana Road, Delhi-
110042
Subject Code: IT-306
Subject Name: AIES
PRACTICAL FILE
SUBMITTED TO: SUBMITTED BY:
Mr Akshay Mool Amrit Singh Rawat
(2K22/IT/22)
LIST OF EXPERIMENTS
1. Basic Array Characteristics using Numpy
2. Write a program to implement tic-tac-toe problem
3. Write a program to implement the breadth first search for water jug problem
4. Write a program using depth first search algorithm for water jug problem
5. Write a program to implement breadth first search for 8-puzzle problem in python
6. Write a program to implement the steps of A* algorithm
7. Write a program to implement the fuzzy logic for Decision making using skfuzzy
8. Write a program to implement the rule based expert system using experta library
INDEX
S. Title Date Signature
No.
8
EXPERIMENT – 1
AIM:
Basic Array Characteristics using Numpy.
THEORY:
NumPy is a fundamental package for scientific computing in Python. It provides high-performance
multidimensional array objects and tools for working with these arrays. In this experiment, we
demonstrate the creation of arrays and perform basic arithmetic operations like addition and subtraction.
We also explore some important array attributes like data type (dtype), size, shape, and byte order.
Understanding these characteristics helps in optimizing code performance and managing memory
efficiently, especially in data-intensive applications such as machine learning and data analysis.
Key points:
1. np.add() and np.subtract() perform element-wise addition and subtraction.
2. dtype shows the data type of elements in the array.
3. byteorder shows the byte-order notation used (native, little-endian, or big-endian).
4. size returns the total number of elements in the array.
5. shape returns a tuple showing dimensions of the array.
6. reshape() is used to change the shape of the array without changing its data
ALGORITHM:
Import NumPy:
Use import numpy as np to access NumPy functionalities.
Create Arrays:
Define two 1D arrays: array_one and array_two using np.array().
Perform Addition:
Use np.add(array_one, array_two) to add the corresponding elements.
Perform Subtraction:
Use np.subtract(array_one, array_two) to subtract corresponding elements.
Check Data Type:
Use array_one.dtype to display the data type of the array elements.
Display Byte Order:
Use np.dtype('S1').byteorder to show the byte order of a string-type element.
Display Size:
Use array_one.size to print the total number of elements in the array.
Display Shape:
Use array_one.shape to check the shape (dimensions) of the array.
Reshape the Array:
Use array_one.reshape(2, 1) to change the shape from (2,) to (2,1).
CODE:
import numpy as np
array_one = np.array([1, 2])
array_two = np.array([3, 4])
# Add
print(np.add(array_one, array_two))
# Subtract
print(np.subtract(array_one, array_two))
# dtype
print(array_one.dtype)
# Byte order
print(np.dtype('S1').byteorder)
# Size
print(array_one.size)
# Shape
print(array_one.shape)
# Reshape
reshaped_array = array_one.reshape(2, 1)
print(reshaped_array.shape)
OUTPUT:
LEARNING OUTCOMES:
1. Learned how to create and manipulate NumPy arrays using np.array().
2. Performed element-wise addition and subtraction using np.add() and np.subtract().
3. Explored array attributes like dtype, size, shape, and byteorder.
4. Used the reshape() function to modify the shape of an array without changing its data.
5. Understood how NumPy supports efficient memory usage and faster numerical operations.
EXPERIMENT – 2
AIM:
Write a program to implement tic-tac-toe problem.
THEORY:
Tic-Tac-Toe is a two-player game played on a 3×3 grid. One player uses 'X' and the other uses 'O'.
Players take turns placing their symbol in an empty cell. The game ends when one player forms a
straight line (horizontal, vertical, or diagonal) or when all cells are filled without a winner (draw).
In this program, we simulate the game in the terminal using Python. We use a 2D list (a list of lists) to
represent the game board. The game continues in a loop, alternating turns between 'X' and 'O', until a
player wins or all cells are filled.
Key concepts used:
2D Lists: To represent the 3×3 grid. Input/Output:
For player interaction.
Conditionals & Loops: To control the game flow and check for win/draw.
Functions: To modularize the code (check(), is_draw(), solve()).
ALGORITHM:
1. Start the program.
2. Create a 3x3 grid (list of lists) initialized with '.' to represent empty cells.
3. Set a boolean variable turn to True to indicate that player 'O' starts first.
4. Enter a loop that continues until the game ends.
5. Display the current grid using a nested loop.
6. Check if any player has won by evaluating all rows, columns, and diagonals.
7. If a player has won, print the winner and exit the loop.
8. Check if the game is a draw by verifying if all cells are filled.
9. If the game is a draw, print "It's a draw!" and exit the loop.
10. Ask the current player to enter row and column coordinates.
11. Check if the entered coordinates are within range and the selected cell is empty.
12. If valid, update the grid with 'O' if it's O's turn, else with 'X'.
13. Toggle the turn variable to switch to the other player.
14. If input is invalid, display an error message and continue the loop.
15. Repeat steps 5 to 14 until the game ends.
CODE:
#include <bits\stdc++.h>
using namespace std;
void checkForWinner(vector<vector<int>> grid, string& winner){
for(int row = 0; row < 3; row++){
if(grid[row][0] == grid[row][1] && grid[row][1] == grid[row][2] && grid[row][0] != -1){
winner = "player " + to_string(grid[row][1]);
return;
}
}
for(int col = 0; col < 3; col++){
if(grid[0][col] == grid[1][col] && grid[1][col] == grid[2][col] && grid[0][col] != -1){
winner = "player " + to_string(grid[1][col]);
return;
}
}
if(grid[0][0] == grid[1][1] && grid[1][1] == grid[2][2] && grid[0][0] != -1){
winner = "player " + to_string(grid[1][1]);
return;
}
if(grid[0][2] == grid[1][1] && grid[1][1] == grid[2][0] && grid[0][2] != -1){
winner = "player " + to_string(grid[1][1]);
return;
}
}
int main(){
vector<vector<int>> grid(3, vector<int>(3, -1));
int player = 1; string
winner = "";
while(winner == ""){
cout << "Player " << player << " turn..." << endl; int
row = -1, col = -1;
while(row < 1 || row > 3 || col < 1 || col > 3){
cout << "Enter row: ";
cin >> row;
cout << "Enter col: ";
cin >> col;
if(row < 1 || row > 3){
cout << "Row value is invalid. Enter a value between 1 and 3" << endl;
continue;
}
if(col < 1 || col > 3){
cout << "Col value is invalid. Enter a value between 1 and 3" << endl;
continue;
}
if(grid[row - 1][col - 1] != -1){
cout << "The position you entered is already taken." << endl;
row = -1;
continue;
}
}
grid[row - 1][col - 1] = player;
cout << "Entered positon: " << row << "," << col << endl;
for(int row = 0; row < 3; row++){
for(int col = 0; col < 3; col++)
cout << grid[row][col] << " ";
cout << endl;
}
cout << endl;
player = player == 1 ? 0: 1;
checkForWinner(grid, winner);
}
cout << winner << " has won the game." << endl;
return 0;
}
OUTPUT:
LEARNING OUTCOME:
1. Understood how to represent a 2D grid using nested lists in Python.
2. Learned to use loops, conditionals, and user input to control game flow.
3. Implemented game logic using modular functions (check(), is_draw(), solve()).
4. Practiced checking winning conditions (rows, columns, diagonals) and draw scenarios.
EXPERIMENT-3
AIM:
Write a program to implement the Breadth First Search for Water Jug Problem.
THEORY:
The Water Jug Problem is a classic example of a state-space search problem in artificial intelligence, where the
objective is to measure a specific amount of water using two jugs of different capacities and a set of allowed
operations such as filling, emptying, or pouring water between the jugs. Breadth First Search is an effective
algorithm for solving this problem because it systematically explores all possible states level by level,
ensuring that the solution found uses the minimum number of steps. By representing each state as a pair
indicating the amount of water in each jug and using a queue to manage the exploration process, BFS
guarantees that the shortest sequence of operations leading to the goal state is found, making it an ideal
approach for this type of problem.
ALGORITHM:
1. Initialize
Let the capacities of Jug1 and Jug2 be C1 and C2, and the target amount be T.
Set the initial state as (0, 0) (both jugs are empty).
Create a queue and enqueue the initial state along with an empty path.
Create a set to keep track of visited states and add the initial state to it.
2. BFS Loop
While the queue is not empty:
1. Dequeue the front state (jug1, jug2) and the path leading to it.
2. If either jug1 or jug2 equals the target T, print the path and stop (solution found).
3. Generate all possible next states from the current state by performing the following
operations:
Fill Jug1 to capacity: (C1, jug2)
Fill Jug2 to capacity: (jug1, C2)
Empty Jug1: (0, jug2)
Empty Jug2: (jug1, 0)
Pour water from Jug1 to Jug2:
If jug1 + jug2 <= C2: (0, jug1 + jug2)
Else: (jug1 - (C2 - jug2), C2)
Pour water from Jug2 to Jug1:
If jug1 + jug2 <= C1: (jug1 + jug2, 0)
Else: (C1, jug2 - (C1 - jug1))
4. For each generated next state:
If it is valid (within jug capacities) and not yet visited, mark as visited and
enqueue it with the updated path.
3. No Solution
If the queue is exhausted without finding the target, print that no solution exists
CODE:
from queue import Queue
def is_valid_state(state, jug_capacities):
return 0 <= state[0] <= jug_capacities[0] and 0 <= state[1] <= jug_capacities[1]
def print_sequence(moves):
for move in moves:
print(f"Jug1: {move[0]}, Jug2: {move[1]}")
def water_jug_bfs(capacity_jug1, capacity_jug2, target):
jug_capacities = [capacity_jug1, capacity_jug2]
initial_state = (0, 0)
queue = Queue()
queue.put((initial_state, []))
visited = set()
visited.add(initial_state)
while not queue.empty():
(jug1, jug2), path = queue.get()
if jug1 == target or jug2 == target:
print("Solution found:")
print_sequence(path + [(jug1, jug2)])
return
possible_moves =
[ (capacity_jug1,
jug2), (jug1,
capacity_jug2), (0,
jug2),
(jug1, 0),
(0, jug1 + jug2) if jug1 + jug2 <= capacity_jug2 else (jug1 - (capacity_jug2 - jug2), capacity_jug2), (jug1
+ jug2, 0) if jug1 + jug2 <= capacity_jug1 else (capacity_jug1, jug2 - (capacity_jug1 - jug1))
]
for next_state in possible_moves:
if is_valid_state(next_state, jug_capacities) and next_state not in visited:
visited.add(next_state)
queue.put((next_state, path + [(jug1, jug2)]))
print("No solution found.")
water_jug_bfs(4, 3, 2)
OUTPUT:
LEARNING OUTCOMES:
1. Understand how to represent the Water Jug Problem as a state-space and apply BFS to
systematically explore all possible states.
2. Gain hands-on experience in implementing the Breadth First Search algorithm in Python for real-
world problem-solving.
3. Learn to identify and generate valid moves (fill, empty, pour) and use them to transition
between states efficiently.
4. Develop the ability to track visited states to avoid redundant computations and ensure algorithm
correctness.
5. Analyze and interpret the BFS solution path to ensure the minimum number of steps is used to reach
the target state.
EXPERIMENT-4
AIM:
Write a program using Depth First Search Algorithm for Water Jug Problem.
THEORY:
The Water Jug Problem is a classic example in artificial intelligence that demonstrates state-space search, where
the goal is to measure a specific quantity of water using two jugs of different capacities through operations
such as filling, emptying, or pouring between the jugs. Depth-First Search (DFS) is a search algorithm that
explores possible solutions by going as deep as possible along each branch before backtracking. In the
context of the Water Jug Problem, DFS starts from the initial state (both jugs empty) and recursively or
iteratively explores all possible next states by applying allowed operations, such as filling a jug, emptying a
jug, or pouring water from one jug to another. DFS continues to explore deeper states until it either finds a
state where the desired quantity is achieved in one of the jugs or exhausts all possibilities.
ALGORITHM:
1. Initialize
Let the capacities of Jug1 and Jug2 be C1 and C2, and the target amount be T.
Start with both jugs empty: initial state (0, 0).
Create a stack (e.g., list) and push the initial state onto it.
Create a set to keep track of visited states.
Create a list to record the path taken.
2. DFS Loop
While the stack is not empty:
1. Pop the top state (x, y) from the stack.
2. If (x, y) is already in the visited set, skip to the next iteration.
3. Mark (x, y) as visited.
4. Add (x, y) to the path.
5. If x == T or y == T, return the current path as the solution.
6. Generate all possible next states by:
Filling Jug1: (C1, y)
Filling Jug2: (x, C2)
Emptying Jug1: (0, y)
Emptying Jug2: (x, 0)
Pouring water from Jug1 to Jug2: (x - min(x, C2 - y), y + min(x, C2 - y))
Pouring water from Jug2 to Jug1: (x + min(y, C1 - x), y - min(y, C1 - x))
7. For each generated next state:
If the state has not been visited, push it onto the stack.
3. No Solution
If the stack is exhausted and no solution is found, return that no solution exists.
This algorithm follows the DFS approach as implemented in your code, exploring each possible state deeply
before backtracking, and tracks visited states to avoid cycles.
CODE:
def is_goal(state, target):
return state[0] == target or state[1] == target
def valid_state(state, jug1_capacity, jug2_capacity):
jug1, jug2 = state
return 0 <= jug1 <= jug1_capacity and 0 <= jug2 <= jug2_capacity
def dfs(state, jug1_capacity, jug2_capacity):
jug1, jug2 = state
possible_move = []
if jug1 < jug1_capacity:
possible_move.append((jug1_capacity, jug2))
if jug2 < jug2_capacity:
possible_move.append((jug1, jug2_capacity))
if jug1 > 0:
possible_move.append((0, jug2))
if jug2 > 0:
possible_move.append((jug1, 0))
if jug1 > 0 and jug2 < jug2_capacity:
pour = min(jug1, jug2_capacity - jug2)
possible_move.append((jug1 - pour, jug2 + pour))
if jug2 > 0 and jug1 < jug1_capacity:
pour = min(jug2, jug1_capacity - jug1)
possible_move.append((jug1 + pour, jug2 - pour))
return possible_move
def water_jug(jug1_capacity, jug2_capacity,
target): start_state = (0, 0)
stack = [start_state]
visited = set()
parent_map = {start_state: None}
while stack:
current_state = stack.pop()
if is_goal(current_state, target):
path = []
while current_state is not None:
path.append(current_state)
current_state = parent_map[current_state]
return path[::-1]
if current_state not in visited:
visited.add(current_state)
for neighbor in dfs(current_state, jug1_capacity,
jug2_capacity): if neighbor not in visited:
stack.append(neighbor)
parent_map[neighbor] = current_state
return None
jug1_capacity = 10
jug2_capacity = 6
target = 2
solution = water_jug(jug1_capacity, jug2_capacity, target)
if solution:
print("Solution path:")
for state in solution:
print(state)
else:
print("No solution found.")
OUTPUT:
LEARNING OUTCOMES:
1. Understand how to represent the Water Jug Problem as a state-space and apply Depth First Search
to explore possible solutions.
2. Gain practical skills in implementing DFS in Python to solve constraint-based problems by traversing
states deeply before backtracking.
3. Learn to generate and apply valid operations for state transitions and manage them using a stack
structure.
4. Develop the ability to track and avoid revisiting states, ensuring efficient and cycle-free
exploration of the solution space.
5. Analyze the strengths and limitations of DFS, including its non-optimality for shortest paths and
its suitability for smaller state spaces.
EXPERIMENT-5
AIM:
To implement breadth first search for 8-puzzle problem in python.
THEORY:
The 8-puzzle problem is a classic artificial intelligence challenge where the objective is to rearrange a 3x3 grid
of numbered tiles (with one empty space) from a given initial configuration to a specified goal configuration
by sliding tiles into the empty space. Breadth-First Search (BFS) is an uninformed search algorithm that
systematically explores all possible puzzle states level by level, ensuring that the shortest sequence of moves
to reach the goal is found. In BFS, each state of the puzzle is represented as a node, and all possible moves
from the current state (sliding the blank tile up, down, left, or right) generate new child nodes. These nodes
are added to a queue, which ensures that the algorithm explores all states at the current depth before moving
deeper. BFS guarantees an optimal solution if one exists, but it can be memory- intensive due to the large
number of possible states in the 8-puzzle.
ALGORITHM:
1. Initialize
Define the initial state of the puzzle as a 3x3 board.
Define the goal state to be reached.
Create a queue and enqueue a tuple containing the initial state and an empty path.
Create a set to keep track of visited states.
2. BFS Loop
While the queue is not empty:
1. Dequeue the front element, which consists of the current state and the path taken so far.
2. If the current state matches the goal state, return the path as the solution.
3. Convert the current state into a hashable form (such as a tuple of tuples) and check if
it has already been visited.
4. If already visited, skip to the next iteration.
5. Mark the current state as visited.
6. Generate all valid neighboring states by moving the blank tile (0) up, down, left, or
right, ensuring moves stay within the board boundaries.
7. For each valid neighbor:
Enqueue the neighbor state along with the updated path (including this
neighbor).
3. No Solution
If the queue becomes empty and the goal state has not been found, return that no solution
exists.
This algorithm systematically explores all possible board configurations level by level, ensuring the shortest path
to the goal state is found if a solution exists.
CODE:
from collections import deque
MOVES = [(-1, 0, "Up"), (1, 0, "Down"), (0, -1, "Left"), (0, 1, "Right")]
def find_empty(state):
for i in range(3):
for j in range(3):
if state[i][j] == 0:
return i, j
def is_goal_state(state):
return state == GOAL_STATE
def print_state(state):
for row in state:
print(row)
print()
def bfs_search(initial_state):
queue = deque([(initial_state, [], "")])
visited = set()
visited.add(initial_state)
while queue:
current_state, path, moves = queue.popleft()
if is_goal_state(current_state):
return path, moves
empty_pos = find_empty(current_state)
x, y = empty_pos
for dx, dy, direction in MOVES:
new_x, new_y = x + dx, y + dy
if 0 <= new_x < 3 and 0 <= new_y < 3:
new_state = list(list(row) for row in current_state)
new_state[x][y], new_state[new_x][new_y] = new_state[new_x][new_y], new_state[x][y]
new_state = tuple(tuple(row) for row in new_state)
if new_state not in visited:
visited.add(new_state)
new_moves = moves + direction + " "
queue.append((new_state, path + [new_state], new_moves))
initial_state = ((1, 2, 3), (4, 5, 6), (0, 7, 8))
GOAL_STATE = ((1, 2, 3), (4, 5, 6), (7, 8, 0))
print("Goal State:")
print_state(GOAL_STATE)
print("Initial State:")
print_state(initial_state)
solution, moves = bfs_search(initial_state)
if solution:
print("Solution steps:")
print("Move Sequence:", moves)
for step in solution:
print_state(step)
else:
print("No solution found")
OUTPUT:
LEARNING OUTCOMES:
1. Understand how to represent the 8-puzzle problem as a state-space and model valid moves as
transitions between states.
2. Gain practical experience in implementing the Breadth First Search (BFS) algorithm to systematically
explore all possible puzzle configurations.
3. Learn to use data structures like queues and sets in Python to manage the search process and avoid
revisiting already explored states.
4. Develop the ability to find the shortest sequence of moves to solve the 8-puzzle, ensuring an optimal
solution is obtained.
5. Analyze the efficiency and limitations of BFS in solving combinatorial problems with large
state spaces, such as the 8-puzzle.
EXPERIMENT-6
AIM: Write a program to implement the steps of A* algorithm.
THEORY:
The A* algorithm is a widely used pathfinding and graph traversal technique in artificial intelligence, designed
to efficiently find the shortest path from a start node to a goal node. It combines the strengths of both
Dijkstra's algorithm and Greedy Best-First Search by using a cost function f(n) = g(n) + h(n), where g(n) is
the exact cost from the start node to the current node, and h(n) is a heuristic estimate of the cost from the
current node to the goal. The algorithm uses a priority queue to explore nodes with the lowest estimated total
cost first, ensuring both optimality and efficiency. By expanding the most promising paths based on this
heuristic-driven evaluation, A* guarantees the optimal solution when the heuristic is admissible, making it a
powerful and flexible algorithm for solving shortest path problems in various domains.
ALGORITHM:
1. Initialize
● Define the start node and the goal node.
● Create an open list (priority queue) and insert the start node with its f(n) = g(n) + h(n), where:
● g(n) = cost from the start node to node n (initially 0 for the start node),
● h(n) = heuristic estimate of the cost from node n to the goal.
● Create a closed set to keep track of visited nodes.
● Store the path and g(n) cost for each node.
2. A* Loop
● While the open list is not empty:
1. Remove the node with the lowest f(n) from the open list. Let this be the current node.
2. If the current node is the goal node:
●
Reconstruct and print the path from the start to the goal.
●
Stop (solution found).
3. Add the current node to the closed set.
4. For each neighbor of the current node:
●
If the neighbor is in the closed set, skip it.
●
Calculate tentative g(n) = g(current) + cost to neighbor.
●
If the neighbor is not in the open list or the tentative g(n) is less than the
previously recorded g(n):
●
Update g(n) and f(n) = g(n) + h(n) for the neighbor.
●
Set the current node as the parent of the neighbor (for path
reconstruction).
●
If the neighbor is not in the open list, add it.
3. No Solution
● If the open list is exhausted without reaching the goal node print that no solution exists.
CODE:
import heapq
def heuristic(node, goal):
return abs(node - goal)
def a_star(start, goal, graph, heuristic):
open_list = []
heapq.heappush(open_list, (0 + heuristic(start, goal), start)) g_score =
{start: 0}
visited = {}
while open_list:
_, current = heapq.heappop(open_list) if
current == goal:
path = []
while current in visited:
path.append(current)
current = visited[current]
path.append(start)
path.reverse()
return path, g_score[goal]
for neighbor, cost in graph.get(current, []):
tentative_g_score = g_score[current] + cost
if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
g_score[neighbor] = tentative_g_score
f_score = tentative_g_score + heuristic(neighbor, goal)
heapq.heappush(open_list, (f_score, neighbor))
visited[neighbor] = current
return [], 0
graph = {
1: [(2, 1), (3, 4)],
2: [(1, 1), (3, 2), (4, 5)],
3: [(1, 4), (2, 2), (4, 1)],
4: [(2, 5), (3, 1)],
}
start = 1
goal = 4
path, total_score = a_star(start, goal, graph, heuristic)
print("Path:", path)
print("Total cost: ", total_score)
OUTPUT
:
LEARNING OUTCOMES:
1. Understand the implementation and application of the A* (A-star) search algorithm for pathfinding
in a grid-based environment.
2. Gain practical experience with priority queues using Python’s heapq for managing nodes with
the lowest cost first.
3. Develop the ability to represent and traverse a graph while avoiding obstacles and ensuring
valid moves.
4. Learn how to reconstruct the optimal path from the goal back to the start using a backtracking
approach.
EXPERIMENT – 7
AIM:
Write a program to implement the fuzzy logic for Decision making using skfuzzy.
THEORY:
This program implements a fuzzy logic system using the scikit-fuzzy library to evaluate the driving risk
based on two input variables: traffic conditions and weather conditions. Fuzzy logic is particularly
useful for handling uncertain or imprecise information, making it ideal for real-world decision-making
problems where variables aren't just "high" or "low" but may lie somewhere in between.
Key points:
1. Inputs & Outputs: The system takes two inputs—traffic and weather—and produces one output—
risk level.
2. Membership Functions: Each variable uses triangular membership functions to define fuzzy
categories like "light traffic" or "rainy weather".
3. Rule Base: Decision-making is guided by a set of fuzzy if-then rules that reflect expert or intuitive
knowledge.
4. Fuzzy Inference: The system evaluates which rules fire and to what extent, combining their
outputs through fuzzy logic.
5. Defuzzification: The fuzzy results are converted into a crisp numerical value (e.g., risk level =
7.2), which lies within the output universe.
ALGORITHM:
Start the program.
Initialize the fuzzy input variables: traffic and weather, each ranging from 0 to 10.
Initialize the fuzzy output variable: risk, also ranging from 0 to 10.
Define triangular membership functions for all variables:
traffic has categories: light, moderate, and heavy.
weather has categories: clear, cloudy, and rainy.
risk has categories: low, medium, and high.
Create fuzzy rules based on expert knowledge:
If traffic is light and weather is clear, then risk is low.
If traffic is light and weather is rainy, then risk is medium. If
traffic is heavy or weather is rainy, then risk is high.
If traffic is moderate and weather is cloudy, then risk is medium. If
traffic is moderate and weather is clear, then risk is low.
Construct the fuzzy control system and simulate the control system. Provide
specific input values for traffic and weather and compute the result. Apply
membership functions to inputs.
Evaluate rule firing strengths and aggregate the rule outputs. Defuzzify
the output to obtain a crisp value for risk.
Print the final risk level and visualize the output using the fuzzy membership plot. End
the program.
CODE:
import numpy as np
import skfuzzy as fuzz
from skfuzzy import control as ctrl
traffic = ctrl.Antecedent(np.arange(0, 11, 1), 'traffic')
weather = ctrl.Antecedent(np.arange(0, 11, 1), 'weather')
risk = ctrl.Consequent(np.arange(0, 11, 1), 'risk')
traffic['light'] = fuzz.trimf(traffic.universe, [0, 0, 5])
traffic['moderate'] = fuzz.trimf(traffic.universe, [2, 5, 8])
traffic['heavy'] = fuzz.trimf(traffic.universe, [5, 10, 10])
weather['clear'] = fuzz.trimf(weather.universe, [0, 0, 4])
weather['cloudy'] = fuzz.trimf(weather.universe, [2, 5, 8])
weather['rainy'] = fuzz.trimf(weather.universe, [6, 10, 10])
risk['low'] = fuzz.trimf(risk.universe, [0, 0, 4])
risk['medium'] = fuzz.trimf(risk.universe, [3, 5, 7])
risk['high'] = fuzz.trimf(risk.universe, [6, 10, 10])
rule1 = ctrl.Rule(traffic['light'] & weather['clear'], risk['low'])
rule2 = ctrl.Rule(traffic['light'] & weather['rainy'], risk['medium'])
rule3 = ctrl.Rule(traffic['heavy'] | weather['rainy'], risk['high'])
rule4 = ctrl.Rule(traffic['moderate'] & weather['cloudy'], risk['medium'])
rule5 = ctrl.Rule(traffic['moderate'] & weather['clear'], risk['low'])
risk_ctrl = ctrl.ControlSystem([rule1, rule2, rule3, rule4, rule5])
risk_sim = ctrl.ControlSystemSimulation(risk_ctrl)
risk_sim.input['traffic'] = 7
risk_sim.input['weather'] = 8
risk_sim.compute()
print(f"Risk level: {risk_sim.output['risk']:.2f}")
risk.view(sim=risk_sim)
OUTPUT:
LEARNING OUTCOMES:
1. Learn how to create and interpret fuzzy sets and membership functions for real-world variables.
2. Understand the process of building fuzzy inference systems using the skfuzzy library.
3. Gain the ability to design and apply fuzzy rules for decision-making based on multiple input
factors.
4. Explore how fuzzy logic handles gradual transitions and uncertainty in variable values.
5. Learn how to visualize fuzzy outputs and evaluate system responses for different inputs.
EXPERIMENT – 8
AIM:
Write a program to implement the rule based expert system using experta library.
THEORY:
A Rule-Based Expert System uses a set of predefined rules to infer solutions to a problem based on the
given facts. The system applies these rules to evaluate inputs and provide an output (like a diagnosis
or recommendation).
The system leverages the experta library, a Python library that implements expert systems based on forward
chaining logic. When facts are provided, the engine applies the rules and provides a solution based on
the conditions that match the facts.
Key points:
1. Facts Representation: Facts represent the inputs to the expert system, such as symptoms
(fever, cough, headache).
2. Rule-Based Inference: The system applies predefined rules to process the facts and determine
the appropriate output.
3. Forward Chaining: The system works by applying the rules to infer the result from the facts.
When facts are input, the system "fires" the matching rules.
4. Knowledge Engine: The experta knowledge engine evaluates the facts against the rules to make
the decision (e.g., diagnose flu, dengue, etc.).
5. Diagnosis Output: Based on the input symptoms, the system provides a diagnosis, showing the power
of rule-based decision-making.
ALGORITHM:
Start the program.
Initialize the knowledge engine (HealthExpertSystem).
Define the facts to represent the input symptoms. For example, fever, cough, headache. Define
the rules based on expert knowledge:
If fever is yes and cough is yes, diagnose flu.
If fever is yes and cough is no, diagnose dengue. If
fever is no and cough is yes, diagnose cold.
If fever is no and cough is no, diagnose migraine or health.
Create an instance of the knowledge engine and reset it.
Declare facts (input the symptoms) to the engine.
Run the engine to apply the rules based on the facts.
Display the result (e.g., diagnosis like "You may have the flu"). End
the program.
CODE:
from experta import *
class Symptoms(Fact):
pass
class HealthExpertSystem(KnowledgeEngine):
@Rule(Symptoms(fever='yes', cough='yes', headache='yes'))
def flu(self):
print("Diagnosis: You may have the flu.")
@Rule(Symptoms(fever='yes', cough='no', headache='yes'))
def dengue(self):
print("Diagnosis: You may have dengue.")
@Rule(Symptoms(fever='no', cough='yes', headache='no'))
def cold(self):
print("Diagnosis: You may have a common cold.")
@Rule(Symptoms(fever='no', cough='no', headache='yes'))
def migraine(self):
print("Diagnosis: You may have a migraine.")
@Rule(Symptoms(fever='no', cough='no', headache='no'))
def healthy(self):
print("Diagnosis: You seem to be healthy.")
engine = HealthExpertSystem()
engine.reset()
engine.declare(Symptoms(fever='yes', cough='yes', headache='yes'))
engine.run()
OUTPUT:
LEARNING OUTCOMES:
1. Understand how to represent facts and rules using the experta library in Python.
2. Learn how to implement forward chaining for automatic reasoning and diagnosis.
3. Develop skills in designing if-then logical rules to simulate human decision-making.
4. Explore how expert systems can be used in healthcare diagnostics and other knowledgebased
fields.
5. Learn the structure and flow of a knowledge engine and how it processes user-provided facts.