ex2: init
This commit is contained in:
2
assignment2/.gitignore
vendored
Normal file
2
assignment2/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.zip
|
||||||
118
assignment2/csp.py
Normal file
118
assignment2/csp.py
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
from queue import Queue
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
class CSP:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
variables: list[str],
|
||||||
|
domains: dict[str, set],
|
||||||
|
edges: list[tuple[str, str]],
|
||||||
|
):
|
||||||
|
"""Constructs a CSP instance with the given variables, domains and edges.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
variables : list[str]
|
||||||
|
The variables for the CSP
|
||||||
|
domains : dict[str, set]
|
||||||
|
The domains of the variables
|
||||||
|
edges : list[tuple[str, str]]
|
||||||
|
Pairs of variables that must not be assigned the same value
|
||||||
|
"""
|
||||||
|
self.variables = variables
|
||||||
|
self.domains = domains
|
||||||
|
|
||||||
|
# Binary constraints as a dictionary mapping variable pairs to a set of value pairs.
|
||||||
|
#
|
||||||
|
# To check if variable1=value1, variable2=value2 is in violation of a binary constraint:
|
||||||
|
# if (
|
||||||
|
# (variable1, variable2) in self.binary_constraints and
|
||||||
|
# (value1, value2) not in self.binary_constraints[(variable1, variable2)]
|
||||||
|
# ) or (
|
||||||
|
# (variable2, variable1) in self.binary_constraints and
|
||||||
|
# (value1, value2) not in self.binary_constraints[(variable2, variable1)]
|
||||||
|
# ):
|
||||||
|
# Violates a binary constraint
|
||||||
|
self.binary_constraints: dict[tuple[str, str], set] = {}
|
||||||
|
for variable1, variable2 in edges:
|
||||||
|
self.binary_constraints[(variable1, variable2)] = set()
|
||||||
|
for value1 in self.domains[variable1]:
|
||||||
|
for value2 in self.domains[variable2]:
|
||||||
|
if value1 != value2:
|
||||||
|
self.binary_constraints[(variable1, variable2)].add(
|
||||||
|
(value1, value2)
|
||||||
|
)
|
||||||
|
self.binary_constraints[(variable1, variable2)].add(
|
||||||
|
(value2, value1)
|
||||||
|
)
|
||||||
|
|
||||||
|
def ac_3(self) -> bool:
|
||||||
|
"""Performs AC-3 on the CSP.
|
||||||
|
Meant to be run prior to calling backtracking_search() to reduce the search for some problems.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
False if a domain becomes empty, otherwise True
|
||||||
|
"""
|
||||||
|
# YOUR CODE HERE (and remove the assertion below)
|
||||||
|
assert False, "Not implemented"
|
||||||
|
|
||||||
|
def _consistent(self, var, value, assignment) -> bool:
|
||||||
|
for v in assignment:
|
||||||
|
if (var, v) in self.binary_constraints.keys():
|
||||||
|
if (value, assignment[v]) not in self.binary_constraints[(var, v)]:
|
||||||
|
return False
|
||||||
|
if (v, var) in self.binary_constraints.keys():
|
||||||
|
if (value, assignment[v]) not in self.binary_constraints[(v, var)]:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _backtrack(self, assignment: dict[str, Any]) -> dict | None:
|
||||||
|
if len(assignment) == len(self.variables):
|
||||||
|
return assignment # base-case
|
||||||
|
var = self._select_unassigned_variable(assignment)
|
||||||
|
for value in self._order_domain_values(var, assignment):
|
||||||
|
if not self._consistent(var, value, assignment):
|
||||||
|
continue
|
||||||
|
assignment[var] = value
|
||||||
|
if result := self._backtrack(assignment):
|
||||||
|
return result
|
||||||
|
assignment.pop(var)
|
||||||
|
return None # failure
|
||||||
|
|
||||||
|
def backtracking_search(self) -> None | dict[str, Any]:
|
||||||
|
"""Performs backtracking search on the CSP.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
None | dict[str, Any]
|
||||||
|
A solution if any exists, otherwise None
|
||||||
|
"""
|
||||||
|
|
||||||
|
def backtrack(assignment: dict[str, Any]):
|
||||||
|
# YOUR CODE HERE (and remove the assertion below)
|
||||||
|
assert False, "Not implemented"
|
||||||
|
|
||||||
|
return backtrack({})
|
||||||
|
|
||||||
|
|
||||||
|
def alldiff(variables: list[str]) -> list[tuple[str, str]]:
|
||||||
|
"""Returns a list of edges interconnecting all of the input variables
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
variables : list[str]
|
||||||
|
The variables that all must be different
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list[tuple[str, str]]
|
||||||
|
List of edges in the form (a, b)
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
(variables[i], variables[j])
|
||||||
|
for i in range(len(variables) - 1)
|
||||||
|
for j in range(i + 1, len(variables))
|
||||||
|
]
|
||||||
27
assignment2/map_coloring.py
Normal file
27
assignment2/map_coloring.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# The map coloring problem from the text book.
|
||||||
|
# The CSP.backtrack() method needs to be implemented
|
||||||
|
|
||||||
|
from csp import CSP, alldiff
|
||||||
|
|
||||||
|
variables = ['WA', 'NT', 'Q', 'NSW', 'V', 'SA', 'T']
|
||||||
|
csp = CSP(
|
||||||
|
variables=variables,
|
||||||
|
domains={variable: {'red', 'green', 'blue'}
|
||||||
|
for variable in variables},
|
||||||
|
edges=[
|
||||||
|
('SA', 'WA'),
|
||||||
|
('SA', 'NT'),
|
||||||
|
('SA', 'Q'),
|
||||||
|
('SA', 'NSW'),
|
||||||
|
('SA', 'V'),
|
||||||
|
('WA', 'NT'),
|
||||||
|
('NT', 'Q'),
|
||||||
|
('Q', 'NSW'),
|
||||||
|
('NSW', 'V'),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
print(csp.backtracking_search())
|
||||||
|
|
||||||
|
# Example output after implementing csp.backtracking_search():
|
||||||
|
# {'WA': 'red', 'NT': 'green', 'Q': 'red', 'NSW': 'green', 'V': 'red', 'SA': 'blue', 'T': 'red'}
|
||||||
72
assignment2/sudoku.py
Normal file
72
assignment2/sudoku.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# Sudoku problems.
|
||||||
|
# The CSP.ac_3() and CSP.backtrack() methods need to be implemented
|
||||||
|
|
||||||
|
from csp import CSP, alldiff
|
||||||
|
|
||||||
|
|
||||||
|
def print_solution(solution):
|
||||||
|
"""
|
||||||
|
Convert the representation of a Sudoku solution, as returned from
|
||||||
|
the method CSP.backtracking_search(), into a Sudoku board.
|
||||||
|
"""
|
||||||
|
for row in range(width):
|
||||||
|
for col in range(width):
|
||||||
|
print(solution[f'X{row+1}{col+1}'], end=" ")
|
||||||
|
if col == 2 or col == 5:
|
||||||
|
print('|', end=" ")
|
||||||
|
print("")
|
||||||
|
if row == 2 or row == 5:
|
||||||
|
print('------+-------+------')
|
||||||
|
|
||||||
|
|
||||||
|
# Choose Sudoku problem
|
||||||
|
grid = open('sudoku_easy.txt').read().split()
|
||||||
|
|
||||||
|
width = 9
|
||||||
|
box_width = 3
|
||||||
|
|
||||||
|
domains = {}
|
||||||
|
for row in range(width):
|
||||||
|
for col in range(width):
|
||||||
|
if grid[row][col] == '0':
|
||||||
|
domains[f'X{row+1}{col+1}'] = set(range(1, 10))
|
||||||
|
else:
|
||||||
|
domains[f'X{row+1}{col+1}'] = {int(grid[row][col])}
|
||||||
|
|
||||||
|
edges = []
|
||||||
|
for row in range(width):
|
||||||
|
edges += alldiff([f'X{row+1}{col+1}' for col in range(width)])
|
||||||
|
for col in range(width):
|
||||||
|
edges += alldiff([f'X{row+1}{col+1}' for row in range(width)])
|
||||||
|
for box_row in range(box_width):
|
||||||
|
for box_col in range(box_width):
|
||||||
|
cells = []
|
||||||
|
edges += alldiff(
|
||||||
|
[
|
||||||
|
f'X{row+1}{col+1}' for row in range(box_row * box_width, (box_row + 1) * box_width)
|
||||||
|
for col in range(box_col * box_width, (box_col + 1) * box_width)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
csp = CSP(
|
||||||
|
variables=[f'X{row+1}{col+1}' for row in range(width) for col in range(width)],
|
||||||
|
domains=domains,
|
||||||
|
edges=edges,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(csp.ac_3())
|
||||||
|
print_solution(csp.backtracking_search())
|
||||||
|
|
||||||
|
# Expected output after implementing csp.ac_3() and csp.backtracking_search():
|
||||||
|
# True
|
||||||
|
# 7 8 4 | 9 3 2 | 1 5 6
|
||||||
|
# 6 1 9 | 4 8 5 | 3 2 7
|
||||||
|
# 2 3 5 | 1 7 6 | 4 8 9
|
||||||
|
# ------+-------+------
|
||||||
|
# 5 7 8 | 2 6 1 | 9 3 4
|
||||||
|
# 3 4 1 | 8 9 7 | 5 6 2
|
||||||
|
# 9 2 6 | 5 4 3 | 8 7 1
|
||||||
|
# ------+-------+------
|
||||||
|
# 4 5 3 | 7 2 9 | 6 1 8
|
||||||
|
# 8 6 2 | 3 1 4 | 7 9 5
|
||||||
|
# 1 9 7 | 6 5 8 | 2 4 3
|
||||||
9
assignment2/sudoku_easy.txt
Normal file
9
assignment2/sudoku_easy.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
004030050
|
||||||
|
609400000
|
||||||
|
005100489
|
||||||
|
000060930
|
||||||
|
300807002
|
||||||
|
026040000
|
||||||
|
453009600
|
||||||
|
000004705
|
||||||
|
090050200
|
||||||
9
assignment2/sudoku_hard.txt
Normal file
9
assignment2/sudoku_hard.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
102040007
|
||||||
|
000080000
|
||||||
|
009500304
|
||||||
|
000607900
|
||||||
|
540000026
|
||||||
|
006405000
|
||||||
|
708003400
|
||||||
|
000010000
|
||||||
|
200060509
|
||||||
9
assignment2/sudoku_medium.txt
Normal file
9
assignment2/sudoku_medium.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
000030040
|
||||||
|
109700000
|
||||||
|
000851070
|
||||||
|
002607830
|
||||||
|
906010207
|
||||||
|
031502900
|
||||||
|
010369000
|
||||||
|
000005703
|
||||||
|
090070000
|
||||||
9
assignment2/sudoku_very_hard.txt
Normal file
9
assignment2/sudoku_very_hard.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
001007000
|
||||||
|
600400300
|
||||||
|
000030064
|
||||||
|
380076000
|
||||||
|
000000036
|
||||||
|
270015000
|
||||||
|
000020051
|
||||||
|
700100200
|
||||||
|
008009000
|
||||||
Reference in New Issue
Block a user