Experiment No: 1 (Part 1 - Attendance Checker)
Code:
attendance = float(input("Enter attendance percentage: "))
if attendance >= 75:
print("Student is Eligible for Exam")
else:
print("Student is Not Eligible for Exam")
Output:
Enter attendance percentage: 82
Student is Eligible for Exam
Conclusion: This program demonstrates a basic AI rule-based system, where decisions are
made using predefined rules without learning from data.
Experiment No: 1 (Part 2 - Medical Expert System)
Code:
symptom1 = input("Enter first symptom: ").lower()
symptom2 = input("Enter second symptom (or none): ").lower()
if symptom1 == "fever" and symptom2 == "cough":
print("Possible Diagnosis: Flu")
elif symptom1 == "fever" and symptom2 == "headache":
print("Possible Diagnosis: Viral Infection")
elif symptom1 == "stomach pain" or symptom2 == "stomach pain":
print("Possible Diagnosis: Food Poisoning")
else:
print("Diagnosis: Consult a Doctor")
Output:
Enter first symptom: fever
Enter second symptom (or none): cough
Possible Diagnosis: Flu
Conclusion: This practical demonstrates a rule-based expert system where decisions are
made using predefined knowledge and inference rules.
Experiment No: 2
Code:
import random
import re
def simple_chatbot():
responses = {
"hello": ["Hi there!", "Hello!", "Greetings!"],
"hi": ["Hi there!", "Hello!", "Greetings!"],
"how are you": ["I'm a bot, I'm doing great!", "I'm functioning optimally."],
"what is your name": ["You can call me PyBot.", "I don't have a name, but I respond to 'Hey you!'"],
"bye": ["Goodbye!", "See you later!", "Have a great day!"],
"exit": ["Goodbye!", "See you later!", "Have a great day!"]
}
default_responses = [
"Sorry, I didn't understand that.",
"Could you please rephrase that?",
"I'm not sure how to respond to that."
]
print("PyBot: Hi! I'm a simple chatbot. Type 'bye' or 'exit' to end the conversation.")
while True:
user_input = input("You: ").lower()
user_input = [Link](r'[^\w\s]', '', user_input)
if user_input in ["bye", "exit"]:
print(f"PyBot: {[Link](responses[user_input])}")
break
matched = False
for key in responses:
if key in user_input:
bot_response = [Link](responses[key])
print(f"PyBot: {bot_response}")
matched = True
break
if not matched:
print(f"PyBot: {[Link](default_responses)}")
if __name__ == "__main__":
simple_chatbot()
Output:
PyBot: Hi! I'm a simple chatbot. Type 'bye' or 'exit' to end the conversation.
You: Hello
PyBot: Hi there!
You: how are you
PyBot: I'm a bot, I'm doing great!
You: what is your name
PyBot: I don't have a name, but I respond to 'Hey you!'
You: abc
PyBot: Sorry, I didn't understand that.
You: @@@
PyBot: Could you please rephrase that?
You: HELLO^% &
PyBot: Hi there!
You: Bye
PyBot: See you later!
Conclusion:This experiment demonstrates that a functional chatbot can be built using basic
Python fundamentals like loops and conditional logic. It highlights how core programming
concepts—control flow and string matching—form the essential foundation for more advanced
AI and Natural Language Processing (NLP) development.
Experiment No: 3
Code:
import itertools
def is_tautology(expression):
variables = sorted(list(set(c for c in expression if 'a' <= c <= 'z')))
if not variables:
return bool(eval(expression))
num_vars = len(variables)
truth_assignments = list([Link]([True, False], repeat=num_vars))
results = []
for assignment in truth_assignments:
env = dict(zip(variables, assignment))
try:
result = eval(expression, {}, env)
[Link](result)
except Exception as e:
print(f"Error evaluating '{expression}': {e}")
return False
return all(results)
if __name__ == "__main__":
expr1 = "(p or not p)"
print(f"Is '{expr1}' a tautology? {is_tautology(expr1)}")
expr2 = "(p and not p)"
print(f"Is '{expr2}' a tautology? {is_tautology(expr2)}")
expr3 = "((p or q) and not p) <= q"
print(f"Is '{expr3}' a tautology? {is_tautology(expr3)}")
expr4 = "(not p or q) or (not q or p)"
print(f"Is '{expr4}' a tautology? {is_tautology(expr4)}")
Output:
Is '(p or not p)' a tautology? True
Is '(p and not p)' a tautology? False
Is '((p or q) and not p) <= q' a tautology? True
Is '(not p or q) or (not q or p)' a tautology? True
Conclusion:The is_tautology function illustrates how Python can solve logical problems by
systematically evaluating truth tables. This approach reinforces understanding of propositional
logic and automated reasoning, serving as a basis for complex theorem-checking applications.
Experiment No: 4
Code:
GRID = 4
wumpus = (1, 2)
pit = (2, 1)
gold = (3, 3)
safe_cells = set()
visited = set()
possible_pit = set()
possible_wumpus = set()
agent_pos = (0, 0)
safe_cells.add(agent_pos)
def neighbors(cell):
x, y = cell
n = []
if x > 0: [Link]((x-1, y))
if x < GRID-1: [Link]((x+1, y))
if y > 0: [Link]((x, y-1))
if y < GRID-1: [Link]((x, y+1))
return n
def perceive(cell):
percepts = []
for n in neighbors(cell):
if n == pit:
[Link]("Breeze")
if n == wumpus:
[Link]("Stench")
return percepts
def infer(cell, percepts):
adj = neighbors(cell)
if "Breeze" not in percepts:
for a in adj:
safe_cells.add(a)
else:
for a in adj:
possible_pit.add(a)
if "Stench" not in percepts:
for a in adj:
safe_cells.add(a)
else:
for a in adj:
possible_wumpus.add(a)
def choose_move(cell):
for n in neighbors(cell):
if n in safe_cells and n not in visited:
return n
return None
print("Simple Wumpus World Simulation\n")
for step in range(10):
print(f"Step {step+1}")
print("Agent at:", agent_pos)
[Link](agent_pos)
percepts = perceive(agent_pos)
print("Percepts:", percepts if percepts else "None")
infer(agent_pos, percepts)
move = choose_move(agent_pos)
if move:
print("Moving to:", move, "\n")
agent_pos = move
else:
print("No safe move available. Stopping.\n")
break
print("Visited cells:", visited)
print("Safe cells:", safe_cells)
print("Possible pits:", possible_pit)
print("Possible wumpus:", possible_wumpus)
if agent_pos == gold:
print("Agent found the gold!")
else:
print("Agent did not reach the gold.")
Output:
Simple Wumpus World Simulation
Step 1
Agent at: (0, 0)
Percepts: None
Moving to: (1, 0)
Step 2
Agent at: (1, 0)
Percepts: None
Moving to: (2, 0)
Step 3
Agent at: (2, 0)
Percepts: ['Breeze']
Moving to: (3, 0)
Step 4
Agent at: (3, 0)
Percepts: None
Moving to: (3, 1)
Step 5
Agent at: (3, 1)
Percepts: ['Breeze']
Moving to: (2, 1)
Step 6
Agent at: (2, 1)
Percepts: None
Moving to: (1, 1)
Step 7
Agent at: (1, 1)
Percepts: ['Breeze', 'Stench']
Moving to: (0, 1)
Step 8
Agent at: (0, 1)
Percepts: None
Moving to: (0, 2)
Step 9
Agent at: (0, 2)
Percepts: ['Stench']
Moving to: (1, 2)
Step 10
Agent at: (1, 2)
Percepts: None
Moving to: (2, 2)
Visited cells: {(0, 1), (1, 2), (2, 1), (0, 0), (3, 1), (1, 1), (2, 0), (3, 0), (0, 2), (1, 0)}
Safe cells: {(0, 1), (1, 2), (2, 1), (0, 0), (3, 1), (1, 1), (0, 3), (2, 0), (3, 0), (0, 2), (2, 2), (1, 0),
(3, 2), (1, 3)}
Possible pits: {(0, 1), (1, 2), (2, 1), (3, 0), (1, 0), (3, 2)}
Possible wumpus: {(0, 1), (1, 2), (2, 1), (0, 3), (1, 0)}
Agent did not reach the gold.
Conclusion:Wumpus World showcases how an intelligent agent uses knowledge
representation and logical inference to navigate uncertainty. By deriving safe actions from
sensory percepts (like breeze or stench), the model emphasizes the importance of
reasoning-based decision-making over simple reactive behavior.
Experiment No: 5
Code:
import networkx as nx
import [Link] as plt
G = [Link]()
G.add_nodes_from(["Dog", "Cat", "Animal", "Mammal", "CanFly", "HasFur", "Meows", "Barks"])
G.add_edge("Dog", "Mammal", label="is-a")
G.add_edge("Cat", "Mammal", label="is-a")
G.add_edge("Mammal", "Animal", label="is-a")
G.add_edge("Dog", "Barks", label="can")
G.add_edge("Dog", "HasFur", label="has")
G.add_edge("Cat", "Meows", label="can")
G.add_edge("Cat", "HasFur", label="has")
G.add_edge("Animal", "CanFly", label="cannot")
is_dog_an_animal = nx.has_path(G, "Dog", "Animal")
print(f"Is a Dog an Animal? {is_dog_an_animal}")
pos = nx.spring_layout(G, seed=42)
[Link](figsize=(10, 7))
nx.draw_networkx_nodes(G, pos, node_color='lightblue', node_size=2000)
nx.draw_networkx_labels(G, pos, font_size=12, font_weight='bold')
nx.draw_networkx_edges(G, pos, edge_color='gray', arrows=True)
edge_labels = nx.get_edge_attributes(G, 'label')
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_color='red')
[Link]("Simple Semantic Network for Knowledge Representation")
[Link]('off')
[Link]()
Output:
Is a Dog an Animal? True
Figure 1: Simple Semantic Network for Knowledge Representation
Conclusion: Semantic networks provide an intuitive, graph-based method for representing
knowledge. Utilizing libraries like NetworkX and spaCy allows for structured, contextual
information storage, which is vital for reasoning in expert systems and robotics.
Experiment No: 6
Code:
import itertools
def generate_sample_space(elements, r):
print("Elements:", elements)
print("Outcome length:", r)
permutations = list([Link](elements, r))
print("\nPermutations Sample Space:")
for p in permutations:
print(p)
print("Total permutations:", len(permutations))
combinations = list([Link](elements, r))
print("\nCombinations Sample Space:")
for c in combinations:
print(c)
print("Total combinations:", len(combinations))
elements = ['A', 'B', 'C', 'D']
r = 2
generate_sample_space(elements, r)
Output:
Elements: ['A', 'B', 'C', 'D']
Outcome length: 2
Permutations Sample Space:
('A', 'B')
('A', 'C')
('A', 'D')
('B', 'A')
('B', 'C')
('B', 'D')
('C', 'A')
('C', 'B')
('C', 'D')
('D', 'A')
('D', 'B')
('D', 'C')
Total permutations: 12
Combinations Sample Space:
('A', 'B')
('A', 'C')
('A', 'D')
('B', 'C')
('B', 'D')
('C', 'D')
Total combinations: 6
Conclusion: Using Python’s itertools library, this experiment efficiently generates sample
spaces for permutations and combinations. It demonstrates a modular approach to solving
discrete mathematics problems, eliminating manual enumeration and ensuring accuracy in
probability analysis.
Experiment No: 7
Code:
from [Link] import BayesianNetwork
from [Link] import TabularCPD
from [Link] import VariableElimination
model = BayesianNetwork([('Smoking', 'Disease'), ('Pollution', 'Disease')])
cpd_smoking = TabularCPD('Smoking', 2, [[0.7], [0.3]])
cpd_pollution = TabularCPD('Pollution', 2, [[0.6], [0.4]])
cpd_disease = TabularCPD('Disease', 2,
[[0.9, 0.7, 0.8, 0.1],
[0.1, 0.3, 0.2, 0.9]],
evidence=['Smoking', 'Pollution'],
evidence_card=[2, 2])
model.add_cpds(cpd_smoking, cpd_pollution, cpd_disease)
print("Model valid:", model.check_model())
inference = VariableElimination(model)
result = [Link](variables=['Disease'], evidence={'Smoking': 1, 'Pollution': 1})
print(result)
Output:
Model valid: True
+-------------+----------------+
| Disease | phi(Disease) |
+=============+================+
| Disease(0) | 0.10 |
+-------------+----------------+
| Disease(1) | 0.90 |
+-------------+----------------+
Conclusion: Implemented via the pgmpy library, this experiment shows how Bayesian
Networks model dependencies and perform probabilistic reasoning. These networks are
essential for decision-making under uncertainty in fields like medical diagnosis and risk
assessment.
Experiment No: 08
Code:
import numpy as np
import [Link] as plt
from [Link] import KMeans
from [Link] import make_blobs
X, y = make_blobs(n_samples=200, centers=3, random_state=42)
kmeans = KMeans(n_clusters=3, random_state=42)
[Link](X)
labels = kmeans.labels_
centroids = kmeans.cluster_centers_
[Link](X[:, 0], X[:, 1], c=labels)
[Link](centroids[:, 0], centroids[:, 1], marker='X', s=200)
[Link]("K-Means Clustering")
[Link]("Feature 1")
[Link]("Feature 2")
[Link]()
Output:
Figure 1: K-Means Clustering
(Scatter plot visualization mapping Feature 1 and Feature 2 points to distinct
clusters)
Conclusion: The K-Means algorithm, implemented through Scikit-learn, effectively groups
data into clusters based on similarity. It proves to be a powerful, accessible tool for exploratory
data analysis, market segmentation, and pattern recognition.
Experiment No: 09
Code:
from [Link] import load_iris
from sklearn.model_selection import train_test_split
from [Link] import KNeighborsClassifier
from [Link] import accuracy_score, classification_report
iris = load_iris()
X = [Link]
y = [Link]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
knn = KNeighborsClassifier(n_neighbors=5)
[Link](X_train, y_train)
y_pred = [Link](X_test)
print("Accuracy:", accuracy_score(y_test, y_pred))
print("\nClassification Report:\n", classification_report(y_test, y_pred))
Output:
Accuracy: 1.0
Classification Report:
precision recall f1-score support
0 1.00 1.00 1.00 19
1 1.00 1.00 1.00 13
2 1.00 1.00 1.00 13
accuracy 1.00 45
macro avg 1.00 1.00 1.00 45
weighted avg 1.00 1.00 1.00 45
Conclusion:This experiment utilized the K-Nearest Neighbors (KNN) algorithm to classify the
Iris dataset. While KNN is highly effective and simple for small datasets, its performance is
sensitive to the choice of $K$ and can become computationally intensive as data scales.
Experiment No: 10
Code:
import numpy as np
def sigmoid(x):
return 1 / (1 + [Link](-x))
def sigmoid_derivative(x):
return x * (1 - x)
X = [Link]([[0, 0], [0, 1], [1, 0], [1, 1]])
y = [Link]([[0], [1], [1], [0]])
[Link](42)
weights_input_hidden = [Link](-1, 1, (2, 2))
weights_hidden_output = [Link](-1, 1, (2, 1))
bias_hidden = [Link]((1, 2))
bias_output = [Link]((1, 1))
lr = 0.5
for epoch in range(10000):
hidden_layer_input = [Link](X, weights_input_hidden) + bias_hidden
hidden_layer_output = sigmoid(hidden_layer_input)
final_input = [Link](hidden_layer_output, weights_hidden_output) + bias_output
output = sigmoid(final_input)
error = y - output
d_output = error * sigmoid_derivative(output)
d_hidden = d_output.dot(weights_hidden_output.T) *
sigmoid_derivative(hidden_layer_output)
weights_hidden_output += hidden_layer_output.[Link](d_output) * lr
weights_input_hidden += [Link](d_hidden) * lr
bias_output += [Link](d_output, axis=0, keepdims=True) * lr
bias_hidden += [Link](d_hidden, axis=0, keepdims=True) * lr
print("Final Output after Training:")
print([Link](output))
Output:
Final Output after Training:
[[0.]
[1.]
[1.]
[0.]]
Conclusion: A NumPy-based neural network successfully solved the XOR problem,
demonstrating that non-linear boundaries and hidden layers are required for complex logic.
The experiment highlights the roles of backpropagation and gradient descent in modern deep
learning.
Experiment No: 11
Code:
import numpy as np
X = [Link]([1, 2, 3, 4, 5])
y = [Link]([2, 4, 6, 8, 10])
m = 0.0
c = 0.0
learning_rate = 0.01
epochs = 1000
n = len(X)
for i in range(epochs):
y_pred = m * X + c
dm = (-2/n) * [Link](X * (y - y_pred))
dc = (-2/n) * [Link](y - y_pred)
m = m - learning_rate * dm
c = c - learning_rate * dc
if i % 200 == 0:
loss = [Link]((y - y_pred) ** 2)
print(f"Epoch {i}, Loss={loss:.4f}")
print("\nFinal parameters:")
print("Slope (m):", round(m, 2))
print("Intercept (c):", round(c, 2))
Output:
Epoch 0, Loss=44.0000
Epoch 200, Loss=0.0124
Epoch 400, Loss=0.0032
Epoch 600, Loss=0.0008
Epoch 800, Loss=0.0002
Final parameters:
Slope (m): 2.0
Intercept (c): 0.02
Conclusion: Java access modifiers are critical for encapsulation and data security. By
restricting direct access to sensitive attributes—such as in a banking system—developers
ensure modularity and protect the integrity of the application's data.