Skip to content

Commit ff8c411

Browse files
committed
Revert "added the mentioned AC4 algorithm for constraint propagation"
This reverts commit 03551fb.
1 parent 0c7e5af commit ff8c411

File tree

2 files changed

+11
-96
lines changed

2 files changed

+11
-96
lines changed

csp.py

+10-69
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from utils import argmin_random_tie, count, first
44
import search
55

6-
from collections import defaultdict, Counter
6+
from collections import defaultdict
77
from functools import reduce
88

99
import itertools
@@ -50,12 +50,13 @@ class CSP(search.Problem):
5050

5151
def __init__(self, variables, domains, neighbors, constraints):
5252
"""Construct a CSP problem. If variables is empty, it becomes domains.keys()."""
53-
super().__init__(())
5453
variables = variables or list(domains.keys())
54+
5555
self.variables = variables
5656
self.domains = domains
5757
self.neighbors = neighbors
5858
self.constraints = constraints
59+
self.initial = ()
5960
self.curr_domains = None
6061
self.nassigns = 0
6162

@@ -73,12 +74,10 @@ def unassign(self, var, assignment):
7374

7475
def nconflicts(self, var, val, assignment):
7576
"""Return the number of conflicts var=val has with other variables."""
76-
7777
# Subclasses may implement this more efficiently
7878
def conflict(var2):
7979
return (var2 in assignment and
8080
not self.constraints(var, val, var2, assignment[var2]))
81-
8281
return count(conflict(v) for v in self.neighbors[var])
8382

8483
def display(self, assignment):
@@ -154,7 +153,6 @@ def conflicted_vars(self, current):
154153
return [var for var in self.variables
155154
if self.nconflicts(var, current[var], current) > 0]
156155

157-
158156
# ______________________________________________________________________________
159157
# Constraint Propagation with AC-3
160158

@@ -185,51 +183,6 @@ def revise(csp, Xi, Xj, removals):
185183
revised = True
186184
return revised
187185

188-
189-
# Constraint Propagation with AC-4
190-
191-
def AC4(csp, queue=None, removals=None):
192-
"""AC4 algorithm runs in O(cd^2) worst-case time but can be slower
193-
than AC3 on average cases"""
194-
if queue is None:
195-
queue = {(Xi, Xk) for Xi in csp.variables for Xk in csp.neighbors[Xi]}
196-
csp.support_pruning()
197-
support_counter = Counter()
198-
variable_value_pairs_supported = defaultdict(set)
199-
unsupported_variable_value_pairs = []
200-
# construction and initialization of support sets
201-
while queue:
202-
(Xi, Xj) = queue.pop()
203-
revised = False
204-
for x in csp.curr_domains[Xi][:]:
205-
for y in csp.curr_domains[Xj]:
206-
if csp.constraints(Xi, x, Xj, y):
207-
support_counter[(Xi, x, Xj)] += 1
208-
variable_value_pairs_supported[(Xj, y)].add((Xi, x))
209-
if support_counter[(Xi, x, Xj)] == 0:
210-
csp.prune(Xi, x, removals)
211-
revised = True
212-
unsupported_variable_value_pairs.append((Xi, x))
213-
if revised:
214-
if not csp.curr_domains[Xi]:
215-
return False
216-
# propagation of removed values
217-
while unsupported_variable_value_pairs:
218-
Xj, y = unsupported_variable_value_pairs.pop()
219-
for Xi, x in variable_value_pairs_supported[(Xj, y)]:
220-
revised = False
221-
if x in csp.curr_domains[Xi][:]:
222-
support_counter[(Xi, x, Xj)] -= 1
223-
if support_counter[(Xi, x, Xj)] == 0:
224-
csp.prune(Xi, x, removals)
225-
revised = True
226-
unsupported_variable_value_pairs.append((Xi, x))
227-
if revised:
228-
if not csp.curr_domains[Xi]:
229-
return False
230-
return True
231-
232-
233186
# ______________________________________________________________________________
234187
# CSP Backtracking Search
235188

@@ -255,7 +208,6 @@ def num_legal_values(csp, var, assignment):
255208
return count(csp.nconflicts(var, val, assignment) == 0
256209
for val in csp.domains[var])
257210

258-
259211
# Value ordering
260212

261213

@@ -269,7 +221,6 @@ def lcv(var, assignment, csp):
269221
return sorted(csp.choices(var),
270222
key=lambda val: csp.nconflicts(var, val, assignment))
271223

272-
273224
# Inference
274225

275226

@@ -294,7 +245,6 @@ def mac(csp, var, value, assignment, removals):
294245
"""Maintain arc consistency."""
295246
return AC3(csp, {(X, var) for X in csp.neighbors[var]}, removals)
296247

297-
298248
# The search, proper
299249

300250

@@ -324,7 +274,6 @@ def backtrack(assignment):
324274
assert result is None or csp.goal_test(result)
325275
return result
326276

327-
328277
# ______________________________________________________________________________
329278
# Min-conflicts hillclimbing search for CSPs
330279

@@ -353,7 +302,6 @@ def min_conflicts_value(csp, var, current):
353302
return argmin_random_tie(csp.domains[var],
354303
key=lambda val: csp.nconflicts(var, val, current))
355304

356-
357305
# ______________________________________________________________________________
358306

359307

@@ -408,7 +356,7 @@ def build_topological(node, parent, neighbors, visited, stack, parents):
408356
visited[node] = True
409357

410358
for n in neighbors[node]:
411-
if (not visited[n]):
359+
if(not visited[n]):
412360
build_topological(n, node, neighbors, visited, stack, parents)
413361

414362
parents[node] = parent
@@ -418,9 +366,9 @@ def build_topological(node, parent, neighbors, visited, stack, parents):
418366
def make_arc_consistent(Xj, Xk, csp):
419367
"""Make arc between parent (Xj) and child (Xk) consistent under the csp's constraints,
420368
by removing the possible values of Xj that cause inconsistencies."""
421-
# csp.curr_domains[Xj] = []
369+
#csp.curr_domains[Xj] = []
422370
for val1 in csp.domains[Xj]:
423-
keep = False # Keep or remove val1
371+
keep = False # Keep or remove val1
424372
for val2 in csp.domains[Xk]:
425373
if csp.constraints(Xj, val1, Xk, val2):
426374
# Found a consistent assignment for val1, keep it
@@ -445,7 +393,6 @@ def assign_value(Xj, Xk, csp, assignment):
445393
# No consistent assignment available
446394
return None
447395

448-
449396
# ______________________________________________________________________________
450397
# Map-Coloring Problems
451398

@@ -521,7 +468,6 @@ def parse_neighbors(neighbors, variables=None):
521468
PI; PA: LR RA; PC: PL CE LI AQ; PI: NH NO CA IF; PL: BR NB CE PC; RA:
522469
AU BO FC PA LR""")
523470

524-
525471
# ______________________________________________________________________________
526472
# n-Queens Problem
527473

@@ -557,16 +503,16 @@ def __init__(self, n):
557503
CSP.__init__(self, list(range(n)), UniversalDict(list(range(n))),
558504
UniversalDict(list(range(n))), queen_constraint)
559505

560-
self.rows = [0] * n
561-
self.ups = [0] * (2 * n - 1)
562-
self.downs = [0] * (2 * n - 1)
506+
self.rows = [0]*n
507+
self.ups = [0]*(2*n - 1)
508+
self.downs = [0]*(2*n - 1)
563509

564510
def nconflicts(self, var, val, assignment):
565511
"""The number of conflicts, as recorded with each assignment.
566512
Count conflicts in row and in up, down diagonals. If there
567513
is a queen there, it can't conflict with itself, so subtract 3."""
568514
n = len(self.variables)
569-
c = self.rows[val] + self.downs[var + val] + self.ups[var - val + n - 1]
515+
c = self.rows[val] + self.downs[var+val] + self.ups[var-val+n-1]
570516
if assignment.get(var, None) == val:
571517
c -= 3
572518
return c
@@ -614,7 +560,6 @@ def display(self, assignment):
614560
print(str(self.nconflicts(var, val, assignment)) + ch, end=' ')
615561
print()
616562

617-
618563
# ______________________________________________________________________________
619564
# Sudoku
620565

@@ -701,12 +646,9 @@ def show_cell(cell): return str(assignment.get(cell, '.'))
701646

702647
def abut(lines1, lines2): return list(
703648
map(' | '.join, list(zip(lines1, lines2))))
704-
705649
print('\n------+-------+------\n'.join(
706650
'\n'.join(reduce(
707651
abut, map(show_box, brow))) for brow in self.bgrid))
708-
709-
710652
# ______________________________________________________________________________
711653
# The Zebra Puzzle
712654

@@ -774,7 +716,6 @@ def zebra_constraint(A, a, B, b, recurse=0):
774716
(A in Smokes and B in Smokes)):
775717
return not same
776718
raise Exception('error')
777-
778719
return CSP(variables, domains, neighbors, zebra_constraint)
779720

780721

tests/test_csp.py

+1-27
Original file line numberDiff line numberDiff line change
@@ -211,39 +211,13 @@ def test_AC3():
211211
removals == [('B', 1), ('B', 3), ('A', 1), ('A', 3)])
212212

213213
domains = {'A': [2, 4], 'B': [3, 5]}
214-
constraints = lambda X, x, Y, y: x > y
214+
constraints = lambda X, x, Y, y: int(x) > int(y)
215215
removals = []
216216
csp = CSP(variables=None, domains=domains, neighbors=neighbors, constraints=constraints)
217217

218218
assert AC3(csp, removals=removals)
219219

220220

221-
def test_AC4():
222-
neighbors = parse_neighbors('A: B; B: ')
223-
domains = {'A': [0, 1, 2, 3, 4], 'B': [0, 1, 2, 3, 4]}
224-
constraints = lambda X, x, Y, y: x % 2 == 0 and (x + y) == 4 and y % 2 != 0
225-
removals = []
226-
227-
csp = CSP(variables=None, domains=domains, neighbors=neighbors, constraints=constraints)
228-
229-
assert AC4(csp, removals=removals) is False
230-
231-
constraints = lambda X, x, Y, y: (x % 2) == 0 and (x + y) == 4
232-
removals = []
233-
csp = CSP(variables=None, domains=domains, neighbors=neighbors, constraints=constraints)
234-
235-
assert AC4(csp, removals=removals) is True
236-
assert (removals == [('A', 1), ('A', 3), ('B', 1), ('B', 3)] or
237-
removals == [('B', 1), ('B', 3), ('A', 1), ('A', 3)])
238-
239-
domains = {'A': [2, 4], 'B': [3, 5]}
240-
constraints = lambda X, x, Y, y: (X == 'A' and Y == 'B') or (X == 'B' and Y == 'A') and x < y
241-
removals = []
242-
csp = CSP(variables=None, domains=domains, neighbors=neighbors, constraints=constraints)
243-
244-
assert AC4(csp, removals=removals)
245-
246-
247221
def test_first_unassigned_variable():
248222
map_coloring_test = MapColoringCSP(list('123'), 'A: B C; B: C; C: ')
249223
assignment = {'A': '1', 'B': '2'}

0 commit comments

Comments
 (0)