-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolutions.py
122 lines (98 loc) · 3.55 KB
/
solutions.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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
from utils import first, argmin_random_tie, count
# Variable ordering
def first_unassigned_variable(assignment, csp):
"""The default variable order."""
return first([var for var in csp.variables if var not in assignment])
def num_legal_values(csp, var, assignment):
if csp.curr_domains:
return len(csp.curr_domains[var])
else:
return count(csp.nconflicts(var, val, assignment) == 0
for val in csp.domains[var])
def mrv(assignment, csp):
"""
Q1
Minimum-remaining-values heuristic.
returns minimun remaining value for variables
"""
return argmin_random_tie(
[v for v in csp.variables if v not in assignment],
key=lambda var: num_legal_values(csp, var, assignment))
# Value ordering
def unordered_domain_values(var, assignment, csp):
"""The default value order."""
return csp.choices(var)
def lcv(var, assignment, csp):
"""
Q2
Least-constraining-values heuristic.
returns list of variables
"""
return sorted(csp.choices(var),
key=lambda val: csp.nconflicts(var, val, assignment))
# Filtering
def no_inference(csp, var, value, assignment, removals):
return True
def forward_checking(csp, var, value, assignment, removals):
"""
Q3
Prune neighbor values inconsistent with var=value.
"""
for B in csp.neighbors[var]:
if B not in assignment:
for b in csp.curr_domains[B][:]:
if not csp.constraints(var, value, B, b):
csp.prune(B, b, removals)
if not csp.curr_domains[B]:
return False
return True
def AC3(csp, queue=None, removals=None):
"""[Figure 6.3]"""
if queue is None:
queue = [(Xi, Xk) for Xi in csp.variables for Xk in csp.neighbors[Xi]]
csp.support_pruning()
while queue:
(Xi, Xj) = queue.pop()
if revise(csp, Xi, Xj, removals):
if not csp.curr_domains[Xi]:
return False
for Xk in csp.neighbors[Xi]:
if Xk != Xi:
queue.append((Xk, Xi))
return True
def revise(csp, Xi, Xj, removals):
"""Return true if we remove a value."""
revised = False
for x in csp.curr_domains[Xi][:]:
if all(not csp.constraints(Xi, x, Xj, y) for y in csp.curr_domains[Xj]):
csp.prune(Xi, x, removals)
revised = True
return revised
def arc_cons(csp, var, value, assignment, removals):
"""
Q4
Maintain arc consistency.
"""
return AC3(csp, [(X, var) for X in csp.neighbors[var]], removals)
def backtracking_search(csp,
select_unassigned_variable=first_unassigned_variable,
order_domain_values=unordered_domain_values,
inference=forward_checking):
def backtrack(assignment):
if len(assignment) == len(csp.variables):
return assignment
var = select_unassigned_variable(assignment, csp)
for value in order_domain_values(var, assignment, csp):
if 0 == csp.nconflicts(var, value, assignment):
csp.assign(var, value, assignment)
removals = csp.suppose(var, value)
if inference(csp, var, value, assignment, removals):
result = backtrack(assignment)
if result is not None:
return result
csp.restore(removals)
csp.unassign(var, assignment)
return None
result = backtrack({})
assert result is None or csp.goal_test(result)
return result