0% found this document useful (0 votes)
17 views28 pages

AI - Lab Manual - Removed

The document contains multiple Python programs demonstrating various algorithms and problem-solving techniques. These include implementations for the A* search algorithm, the Eight Queens problem, cryptarithmetic puzzles, and Tic-Tac-Toe using the minimax algorithm. Each program includes functions for solving the respective problems and outputs the results or solutions found.

Uploaded by

divyakannan590
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views28 pages

AI - Lab Manual - Removed

The document contains multiple Python programs demonstrating various algorithms and problem-solving techniques. These include implementations for the A* search algorithm, the Eight Queens problem, cryptarithmetic puzzles, and Tic-Tac-Toe using the minimax algorithm. Each program includes functions for solving the respective problems and outputs the results or solutions found.

Uploaded by

divyakannan590
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 28

PROGRAM:

importheapq

import copy

classPuzzleNode:

def_init_(self,state,parent=None,action=None,cost=0):

self.state = state

self.parent=parent

self.action=action

self.cost = cost

self.heuristic=self.calculate_heuristic()

def_ lt_(self, other):

return(self.cost+self.heuristic)<(other.cost+other.heuristic) def

calculate_heuristic(self):

#Asimpleheuristicfunction:Manhattandistance

goal_state = [[1, 2, 3], [4, 5, 6], [7, 8, 0]]

heuristic=0

for i in range(3):

forjinrange(3):

ifself.state[i][j]!=0:

goal_i,goal_j=divmod(self.state[i][j]-1,3)

heuristic += abs(i - goal_i) + abs(j - goal_j)

return heuristic

def get_blank_position(state):

for i in range(3):

for j in range(3):

if state[i][j]==0:

return i, j

def get_neighbors(node):
i,j=get_blank_position(node.state)

neighbors = []

for action in[(0, 1), (0,-1),(1,0),(-1,0)]:

new_i,new_j=i+action[0],j+action[1]

if 0 <= new_i < 3 and 0 <= new_j < 3:

new_state= copy.deepcopy(node.state)

new_state[i][j],new_state[new_i][new_j]=new_state[new_i][new_j],new_state[i][j]

neighbors.append(PuzzleNode(new_state, node, action, node.cost + 1))

return neighbors

def a_star(initial_state):

start_node=PuzzleNode(initial_state)

frontier = [start_node]

explored=set()

while frontier:

node=heapq.heappop(frontier)

ifnode.state== [[1,2,3],[4,5,6],[7,8,0]]:

return get_solution_path(node)

explored.add(tuple(map(tuple, node.state)))

for neighbor in get_neighbors(node):

if tuple(map(tuple,neighbor.state))notinexplored:

heapq.heappush(frontier, neighbor)

return None

def get_solution_path(node):

path = []

while node.parent:

path.append((node.state, node.action))

node = node.parent

path.append((node.state, node.action))
path.reverse()

return path

def print_solution_path(path):

for i,(state,action)in enumerate(path):

print(f"Step {i + 1}:")

print_state(state)

if action:

print(f"Action:Move{state[action[0]][action[1]]}{action_direction(action)}\n")

def action_direction(action):

ifaction==(0,1):

return "right"

elifaction==(0,-1):

return "left"

elifaction==(1,0):

return "down"

elifaction==(-1,0):

return "up"

def print_state(state):

for row in state:

print(row)

print()

if__name =="__main__":

initial_state=[[1,2,3],[4,0,5],[7,8,6]]

print("Initial State:")

print_state(initial_state)

solution_path=a_star(initial_state)

if solution_path:

print("Solution Path:")
print_solution_path(solution_path)

else:

print("No solution found.")

OUTPUT:
Initial State:
[1, 2,3]
[4, 0,5]
[7,8,6]

Solution Path:
Step1:
[1, 2,3]
[4, 0,5]
[7, 8,6]

Step2:
[1, 2,3]
[4, 5,0]
[7, 8,6]

Action: Move 2 right

Step 3:
[1, 2,3]
[4, 5,6]
[7, 8,0]

Action: Move 4 down

>>>
PROGRAM:

ClassEightQueensProblem:
def_init_(self,size=8):
self.size=size
self.solution=[None]*size

defis_safe(self,row,col):
for prev_row in range(row):
prev_col=self.solution[prev_row]

if prev_col==color\
prev_col-prev_row==col-rowor\
prev_col + prev_row == col + row:
return False

return True

defsolve_queens(self,row):
if row == self.size:
returnTrue

for colinrange(self.size):
ifself.is_safe(row,col):
self.solution[row]=col
ifself.solve_queens(row+1):
return True

self.solution[row]=None

return False

def print_solution(self):
for row in range(self.size):
line = ""
for col in range(self.size):
if col==self.solution[row]:
line += "Q "
else:
line += ".
"print(line.strip())

if __name == "main":
queens_problem=Eight QueensProblem()

if queens_problem.solve_queens(0):
print("Solution Found:")
queens_problem.print_solution()
else:
print("No solution exists.")
OUTPUT:

SolutionFound:
Q.......
....Q...
....... Q
..... Q..
..Q.....
.......Q.
.Q......
...Q....
>
PROGRAM:

def is_valid(assignment,word,mapping):
return sum(mapping[letter]for letter in word[:-1])%10==mapping[word[-1]]

def solve_cryptarithmetic(puzzle):
letters = set("".join(puzzle))
if len(letters)>10:
print("Invalid puzzle.Too many unique letters.")
return None

def backtrack(mapping,index):
if index == len(letters):
returnTrue

letter=list(letters)[index]

for digit in range(10):


if digit not in mapping.values():
mapping[letter] = digit

if all(is_valid(mapping,word,mapping)for word in puzzle):


if backtrack(mapping, index + 1):
return True

mapping[letter]=None

returnFalse

initial_mapping={letter:None for letter in letters}


if backtrack(initial_mapping, 0):
return initial_mapping
else:
print("Nosolutionfound.")
return None

def print_solution(mapping,puzzle):
for word in puzzle:
print("+".join(str(mapping[letter])for letter in word[:-1]),end="=")
print(mapping[word[-1]])

if__name =="__main__":
puzzle=["SEND","MORE","MONEY"]

print("Cryptarithmetic Puzzle:")
for word in puzzle:
print(word,end="")
print()

solution=solve_cryptarithmetic(puzzle)
if solution:
print("\nSolution:")
print_solution(solution, puzzle)
else:
print("\nNo solution found.")

OUTPUT:
Cryptarithmetic Puzzle:
SEND MORE MONEY
PROGRAM:

importheapq

def heuristic(node,goal):
#Euclidean distance heuristic
return((node[0]-goal[0])**2+ (node[1]-goal[1])**2)**0.5

def astar_search(start,goal,graph):
open_set = [(0, start)]
closed_set=set()
came_from = {}

g_score={start:0}
f_score={start:heuristic(start,goal)}

while open_set:
current_f,current=heapq.heappop(open_set)

if current==goal:
path=reconstruct_path(came_from,current)
return path

closed_set.add(current)

for neighbor in graph[current]:


if neighbor in closed_set:
continue

tentative_g=g_score[current]+1

if neighbor not in [item[1]foriteminopen_set]ortentative_g<g_score[neighbor]:


came_from[neighbor] = current
g_score[neighbor]=tentative_g
f_score[neighbor]=tentative_g+heuristic(neighbor,goal)
heapq.heappush(open_set, (f_score[neighbor], neighbor))

return None

def reconstruct_path(came_from,current):
path = [current]
while current in came_from:
current=came_from[current]
path.append(current)
return path[::-1]

if __name =="__main__":
# Example usage
graph= {
(0,0):[(1,0),(0, 1)],
(1,0):[(0,0),(2, 0)],
(0,1):[(0,0),(1,1),(0,2)],
(1,1):[(0,1),(2, 1)],
(0,2):[(0,1),(1, 2)],
(2,0):[(1,0),(2, 1)],
(2,1):[(1,1),(2,0),(2,2)],
(1,2):[(0,2),(2, 2)],
(2,2):[(1,2),(2, 1)]
}

start_node=(0,0)
goal_node=(2, 2)

result=astar_search(start_node,goal_node,graph)

if result:
print(f"Shortest Path from{start_node}to{goal_node}:{result}")
else:
print("Nopathfound.")

OUTPUT:
Shortest Path from (0,0) to (2,2): [(0,0), (0,1), (0,2), (1,2), (2,2)]
>
PROGRAM:

import heapq

def heuristic(node,goal):

return abs(node[0]-goal[0])+abs(node[1]-goal[1])

def memory_bounded_astar(start,goal,graph,memory_limit):

open_set = [(0, start)]


closed_set=set()
came_from = {}

g_score={start:0}
f_score={start:heuristic(start,goal)}

while open_set:
current_f,current=heapq.heappop(open_set)

if current==goal:
path=reconstruct_path(came_from,current)
return path

closed_set.add(current)

for neighbor in graph[current]:


if neighbor in closed_set:
continue

tentative_g=g_score[current]+1

if neighbor not in[item[1]foriteminopen_set]ortentative_g<g_score[neighbor]:


came_from[neighbor] = current
g_score[neighbor]=tentative_g
f_score[neighbor]=tentative_g+heuristic(neighbor,goal)
heapq.heappush(open_set, (f_score[neighbor], neighbor))

#Prune nodes based on memory limit


if len(open_set) > memory_limit:
open_set=open_set[:memory_limit]

return None

def reconstruct_path(came_from,current):
path = [current]
while current in came_from:
current=came_from[current]
path.append(current)
return path[::-1]

if__ name =="__main_":


# Example usage
graph= {
(0,0):[(1,0),(0, 1)],
(1,0):[(0,0),(2, 0)],
(0,1):[(0,0),(1,1),(0,2)],
(1,1):[(0,1),(2, 1)],
(0,2):[(0,1),(1, 2)],
(2,0):[(1,0),(2, 1)],
(2,1):[(1,1),(2,0),(2,2)],
(1,2):[(0,2),(2, 2)],
(2,2):[(1,2),(2, 1)]
}

start_node=(0,0)
goal_node=(2,2)
memory_limit=5#Set the memory limit

result = memory_bounded_astar(start_node, goal_node, graph,memory_limit)

if result:
print(f"Shortest Path from {start_node} to {goal_node}:{result}")
else:
print("No path found.")

OUTPUT:
Shortest Path from (0,0) to (2,2): [(0,0), (0,1), (0,2), (1,2), (2,2)]
>
PROGRAM:

def evaluate(board):
#Check rows, columns, and diagonals for a win
for row in board:
if all(cell=='X' for cell in row):
return 1# Player X wins
elif all(cell=='O' for cell in row):
return -1 # Player O wins

for col in range(3):


if all(board[row][col]=='X'for row in range(3)):
return 1 # Player X wins
elif all(board[row][col]=='O' for row in range(3)):
return -1 # Player O wins

if all(board[i][i]=='X' for i in range(3)) or all(board[i][2-i]=='X' for i in range(3)):


return 1 # Player X wins

if all(board[i][i]=='O' for i in range(3)) or all(board[i][2 -i]=='O' for i in range(3)):


return -1 # Player O wins

#Check for a draw


if all(cell !=' 'for row in board for cell in row):
return 0 # Draw

#Game still ongoing


return None

def is_terminal(board):
return evaluate(board)is not None

def minimax(board,depth,maximizingPlayer):
if depth == 0 or is_terminal(board):
return evaluate(board)

if maximizingPlayer:
maxEval=float('-inf')
for i in range(3):
for j in range(3):
if board[i][j]=='':
board[i][j]='X'
eval=minimax(board,depth-1,False)
board[i][j] = ''# Undo the move
maxEval = max(maxEval, eval)
return maxEval
else:
minEval=float('inf')
for i in range(3):
for j in range(3):
if board[i][j]=='':
board[i][j]='O'
eval=minimax(board,depth-1,True)
board[i][j] = ' ' # Undo the move
minEval = min(minEval, eval)
return minEval

def best_move(board):
bestVal=float('-inf')
bestMove = None

for i in range(3):
for j in range(3):
if board[i][j] ==' ':
board[i][j] ='X'
moveVal= minimax(board, 9,False) #Depth is set to 9 for Tic-Tac-Toe
board[i][j] = ' ' # Undo the move

if moveVal > bestVal:


bestMove = (i, j)
bestVal = moveVal

return bestMove

def print_board(board):
for row in board:
print(" ".join(row))

if__name =="__main__":
# Example usage for Tic-Tac-Toe
initial_board=[['', '',''],['','',''],['','','']]

while not is_terminal(initial_board):


print_board(initial_board)
player_move=tuple(map(int,input("Enter your move(row and column): ").split()))
initial_board[player_move[0]][player_move[1]] = 'O'

if is_terminal(initial_board):
break

print_board(initial_board)
ai_move = best_move(initial_board)
print(f"AI's move: {ai_move}")
initial_board[ai_move[0]][ai_move[1]] = 'X'

result = evaluate(initial_board)
print_board(initial_board)

if result == 1:
print("Player Xwins!")
elif result == -1:
print("Player Owins!")
else:
print("It's a draw!")

OUTPUT:
Enter your move (row and column): 1
PROGRAM:

from itertools import product

def is_valid_assignment(assignment):

# Check constraints for the assignment

a, b, c = assignment

return a+b+ c = = 15 and len(set(assignment)) = = 3

def print_solution(assignments):

# Print valid assignments

for assignment in assignments:

print(f" A: {assignment[0]}, B: {assignment[1]}, C: {assignment[2]}")

print()

def solve_csp():

variables = [1, 2, 3, 4, 5, 6, 7, 8, 9]

domains = [variables, variables, variables]

#Generate all possible combinations of assignments

all_assignments = list(product(*domains))

#Filter valid assignments based on constraints

valid_assignments=[assignment for assignment in all_assignments if


is_valid_assignment(assignment)]

# Print the solutions

print_solution(valid_assignments)

if __name =="__main__":

solve_csp()
OUTPUT:
A:1,B:5,C:9

A:1,B:6,C:8

A:1,B:8,C:6

A:1,B:9,C:5

A:2,B:4,C:9
A:2,B:5,C:8

A:2,B:6,C:7

A:2,B:7,C:6

A:2,B:8,C:5

A:2,B:9,C:4

A:3,B:4,C:8

A:3,B:5,C:7

A:3,B:7,C:5

A:3,B:8,C:4

A:4,B:2,C:9

A:4,B:3,C:8

A:4,B:5,C:6

A:4,B:6,C:5

A:4,B:8,C:3

A:4,B:9,C:2

A:5,B:1,C:9

A:5,B:2,C:8

A:5,B:3,C:7

A:5,B:4,C:6

A:5,B:6,C:4

A:5,B:7,C:3

A:5,B:8,C:2

A:5,B:9,C:1

A:6,B:1,C:8
A:6,B:2,C:7

A:6,B:4,C:5

A:6,B:5,C:4

A:6,B:7,C:2

A:6,B:8,C:1

A:7,B:2,C:6

A:7,B:3,C:5

A:7,B:5,C:3

A:7,B:6,C:2

A:8,B:1,C:6

A:8,B:2,C:5

A:8,B:3,C:4

A:8,B:4,C:3

A:8,B:5,C:2

A:8,B:6,C:1

A:9,B:1,C:5

A:9,B:2,C:4

A:9,B:4,C:2

A:9,B:5,C:1
PROGRAM:

def evaluate_propositional_formula(formula,model):

if formula[0] == 'Var':

# Variable:Check if th evariable is True in the model

return model. get(formula[1], False)

elif formula[0] == 'Not':

# Negation: Recursively evaluate the negated formula

return note valuate_propositional_formula(formula[1],model)

elif formula[0] == 'And':

# Conjunction: Recursively evaluate both subformulas

return evaluate_propositional_formula(formula[1],model)and
evaluate_propositional_formula(formula[2], model)

elif formula[0] == 'Or':

#Disjunction :Recursively evaluate both subformulas

return evaluate_propositional_formula(formula[1],model) or
evaluate_propositional_formula(formula[2], model)

elif formula[0] == 'Implies':

# Implication: Recursively evaluate both subformulas

return not evaluate_propositional_formula(formula[1], model) or


evaluate_propositional_formula(formula[2], model)

else:

raise ValueError("Invalidformula")

if__ name == "__main__":

# Example usage

# Formula: (A and B) or ( not C)

propositional_formula=('Or', ('And', ('Var', 'A'), ('Var', 'B')), ('Not', ('Var' , 'C')))


# Model: {'A': True,'B': False,'C': True}

model = {'A': True,'B': False,'C': True}

result = evaluate_propositional_formula(propositional_formula, model)

print(f"Does the formula hold in the model? {'Yes' if result else 'No'}")

OUTPUT:

Does the formula hold in the model? No

>
PROGRAM:

def forward_chaining(knowledge_base,goal):

agenda = list(knowledge_base['facts'])

inferred = set()

while agenda:

current_fact= agenda.pop(0)

if current_fact = = goal:

return True #Goal achieved

if current_fact not in inferred:

inferred .add(current_fact)

agenda.extend(rule['conclusion']for rule in knowledge_base['rules']if current_fact in


rule['premises'])

return False #Goal not achieved

def backward_chaining(knowledge_base , goal,explored=None):

if explored is None:

explored = set()

if goal in knowledge_base['facts']:

return True# Goal achieved

for rule in knowledge_base['rules']:

if goal = = rule['conclusion']and goal not in explored:

explored.add(goal)

premises_satisfied = all(backward_chaining(knowledge_base,premise,explored)for premise in


rule['premises'])

if premises_satisfied:

return True

return False #Goal not achieved

def resolution(knowledge_base, query):

clauses = knowledge_base['clauses'] +[frozenset([query])]

new = set()
while True:

for ci in clauses:

for cj in clauses:

if ci != cj:

resolvents = resolve(ci,cj)

if not resolvents:

return True #Goal achieved

new.update(resolvents)

if new.issubset(clauses):

return False #No new information

clauses.update(new)

def resolve(ci, cj):

resolvents = set()

for literal in ci:

if frozenset([-literal]) in cj:

resolvent = (ci - {literal}).union(cj-{-literal})

if not resolvent:

return None #Empty clause,contradiction

resolvents.add(frozenset(resolvent))

return resolvents

if__ name == "__main__":

knowledge_base_forward = {

'facts':{'A','B'},

'rules':[

{'premises':{'A'}, 'conclusion': 'C'},


{'premises': {'B','C'},'conclusion': 'D'},

goal_forward = 'D'

result_forward = forward_chaining(knowledge_base_forward, goal_forward)

print(f"Forward Chaining: Can we derive {goal_forward}? {'Yes' if result_forward else 'No'}")

knowledge_base_backward = {

'facts': {'D'},

'rules': [
{'premises':{'A'},'conclusion': 'C'},

{'premises':{'B','C'},'conclusion': 'D'},

goal_backward = 'A'

result_backward = backward_chaining(knowledge_base_backward, goal_backward)

print(f"Backward Chaining :Can we derive {goal_backward}? {'Yes' if result_backward else 'No'}")

knowledge_base_resolution = {

'clauses' : [frozenset({-1,2}), frozenset ({-2,3}), frozenset ({-3})],

query_resolution = -1

result_resolution = resolution(knowledge_base_resolution, query_resolution)

print(f"Resolution: Can we derive {query_resolution}? {'Yes'ifresult_resolutionelse'No'}")


OUTPUT:

Forward Chaining: Can we derive D? Yes

Backward Chaining: Can we derive A? No

Resolution: Can we derive -1? Yes

>
PROGRAM:

from sklearn.feature_extraction.text import Count Vectorizer

from sklearn.naive_bayes import MultinomialNB

from sklearn.model_selectionimport train_test_split

from sklearn.metrics import accuracy_score, classification_report

# Example data

corpus = [

{'text': 'this is a positive example', 'label': 'positive'},

{'text': 'negative sentiment here', 'label': 'negative'},

{'text': 'a positive message', 'label': 'positive'},

{'text': 'I dislike this', 'label':'negative'},

# Add more examples as needed

# Extract features and labels

texts = [example['text'] for example in corpus]

labels=[example['label']for example in corpus]

# Split the data into training and testing sets

X_train, X_test, y_train, y_test = train_test_split(texts, labels, test_size=0.2,random_state=42)

# Vectorize the text data using bag-of-words representation

vectorizer = CountVectorizer()

X_train_vectorized = vectorizer.fit_transform(X_train)

X_test_vectorized = vectorizer. transform(X_test)

# Train a Multinomial Naive Bayes classifier

naive_bayes_classifier = MultinomialNB()

naive_bayes_classifier.fit(X_train_vectorized, y_train)

# Make predictions on the test set


predictions = naive_bayes_classifier.predict(X_test_vectorized)

# Evaluate the classifier

accuracy = accuracy_score(y_test, predictions)

print(f"Accuracy: {accuracy:.2f}")

# Display classification report

print("Classification Report:")

print(classification_report(y_test,predictions))

# Display predictions for the test set

print("\nPredictions for the test set:")

for text, true_label, predicted_label in zip(X_test, y_test, predictions):

print(f"Text:{text},TrueLabel:{true_label},PredictedLabel:{predicted_label}")

OUTPUT:
Accuracy: 0.00
Classification Report:
precision recall f1-score support
negative 0.00 0.00 0.00 1.0
positive 0.00 0.00 0.00 0.0
accuracy 0.00 1.0
macro avg 0.00 0.00 0.00 1.0
weighted avg 0.00 0.00 0.00 1.0
Predictions for the test set:
Text: negative sentiment here, True Label: negative, Predicted Label: positive
PROGRAM:

from pgmpy. models import Bayesian Model

from pgmpy.estimators importParameterEstimator

from pgmpy.inference import VariableElimination

# Create a Bayesian network model

model = BayesianModel([('A','C'),('B','C')])

# Define conditional probability distributions (CPDs)

cpd_a = ParameterEstimator(model).estimate_cpd('A')

cpd_b = ParameterEstimator(model).estimate_cpd('B')

# Assign CPDs to the model

model.add_cpds(cpd_a,cpd_b)

#Check model structure and CPDs

print("Model Structure:")

print(model.edges())

print("\nCPD for A:")

print(model.get_cpds('A'))

print("\nCPD for B:")

print(model.get_cpds('B'))

# Perform inference using VariableElimination

inference = VariableElimination(model)

query = inference.query(variables=['C'],evidence={'A':1,'B':0})

print("\nInference Result:")

print(query)
OUTPUT:

Collectingpgmpy
Downloadingpgmpy-0.1.24-py3-none-any.whl(2.0MB)
Requirement already satisfied: scipy in c:\users\a\anaconda3\lib\site-packages (from pgmpy) (1.7.3)
Requirement already satisfied: numpy in c:\users\a\anaconda3\lib\site-packages (from pgmpy) (1.21.5)
Requirement already satisfied: pandas in c:\users\a\anaconda3\lib\site-packages (from pgmpy) (1.4.2)
Requirementalreadysatisfied:statsmodelsinc:\users\a\anaconda3\lib\site-packages(frompgmpy)(0.13.2)
Requirement already satisfied: joblib in c:\users\a\anaconda3\lib\site-packages (from pgmpy) (1.1.0)
Requirement already satisfied: pyparsing in c:\users\a\anaconda3\lib\site-packages (from pgmpy) (3.0.4)
Requirement already satisfied: tqdm in c:\users\a\anaconda3\lib\site-packages (from pgmpy) (4.64.0)
Downloading pgmpy-0.1.23-py3-none-any.whl (1.9 MB)
Downloadingpgmpy-0.1.22-py3-none-any.whl(1.9MB)
Downloadingpgmpy-0.1.21-py3-none-any.whl(1.9MB)
Downloadingpgmpy-0.1.20-py3-none-any.whl(1.9MB)
Downloadingpgmpy-0.1.19-py3-none-any.whl(1.9MB)
Downloadingpgmpy-0.1.18-py3-none-any.whl(1.9MB)
Downloadingpgmpy-0.1.17-py3-none-any.whl(1.9MB)
Downloading pgmpy-0.1.16-py3-none-any.whl (1.9 MB)
Downloading pgmpy-0.1.15-py3-none-any.whl (1.9 MB)
Downloading pgmpy-0.1.14-py3-none-any.whl (331 kB)
Downloading pgmpy-0.1.13-py3-none-any.whl (324 kB)
Downloading pgmpy-0.1.12-py3-none-any.whl (322 kB)
Downloading pgmpy-0.1.11-py3-none-any.whl (314 kB)
Downloading pgmpy-0.1.10-py3-none-any.whl (339 kB)
Downloading pgmpy-0.1.9-py3-none-any.whl (331 kB)
Installing collected packages: pgmpy
Successfullyinstalledpgmpy-0.1.9

You might also like