-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcsp.py
67 lines (59 loc) · 2.66 KB
/
csp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
from typing import Callable
class CSP:
def __init__(self, variables: list, domains: dict, neighbors: dict, constraints: Callable):
self.variables = variables
self.domains = domains
self.neighbors = neighbors
self.constraints = constraints
def ac3(self, queue: list = None) -> bool:
if queue is None:
queue = [(i, j) for i in self.variables for j in self.neighbors[i]]
while queue:
(xi, xj) = queue.pop(0)
if self.revise(xi, xj):
if not self.domains[xi]:
return False
for xk in self.neighbors[xi]:
if xk != xj:
queue.append((xk, xi))
return True
def revise(self, xi: tuple, xj: tuple) -> bool:
revised = False
for x in set(self.domains[xi]):
if not any([self.constraints(xi, x, xj, y) for y in self.domains[xj]]):
self.domains[xi].remove(x)
revised = True
return revised
def backtracking_search(self, assignment: dict = {}) -> dict:
if len(assignment) == len(self.variables):
return assignment
var = self.select_unassigned_variable(assignment)
for value in self.order_domain_values(var, assignment):
if self.is_consistent(var, value, assignment):
assignment[var] = value
result = self.backtracking_search(assignment)
if result is not None:
return result
del assignment[var]
return None
def select_unassigned_variable(self, assignment: dict) -> list:
unassigned = [v for v in self.variables if v not in assignment]
return self.min_remaining_values(unassigned)
def order_domain_values(self, var: tuple, assignment: dict) -> list:
domain_values = []
for value in self.domains[var]:
count = 0
for neighbor in self.neighbors[var]:
if neighbor not in assignment:
if value in self.domains[neighbor]:
count += 1
domain_values.append((value, count))
domain_values.sort(key=lambda x: x[1])
return [x[0] for x in domain_values]
def is_consistent(self, var: tuple, value: int, assignment: dict) -> bool:
for neighbor in self.neighbors[var]:
if neighbor in assignment and not self.constraints(var, value, neighbor, assignment[neighbor]):
return False
return True
def min_remaining_values(self, variables: list) -> tuple:
return min(variables, key=lambda var: len(self.domains[var]))