3
3
from utils import argmin_random_tie , count , first
4
4
import search
5
5
6
- from collections import defaultdict , Counter
6
+ from collections import defaultdict
7
7
from functools import reduce
8
8
9
9
import itertools
@@ -50,12 +50,13 @@ class CSP(search.Problem):
50
50
51
51
def __init__ (self , variables , domains , neighbors , constraints ):
52
52
"""Construct a CSP problem. If variables is empty, it becomes domains.keys()."""
53
- super ().__init__ (())
54
53
variables = variables or list (domains .keys ())
54
+
55
55
self .variables = variables
56
56
self .domains = domains
57
57
self .neighbors = neighbors
58
58
self .constraints = constraints
59
+ self .initial = ()
59
60
self .curr_domains = None
60
61
self .nassigns = 0
61
62
@@ -73,12 +74,10 @@ def unassign(self, var, assignment):
73
74
74
75
def nconflicts (self , var , val , assignment ):
75
76
"""Return the number of conflicts var=val has with other variables."""
76
-
77
77
# Subclasses may implement this more efficiently
78
78
def conflict (var2 ):
79
79
return (var2 in assignment and
80
80
not self .constraints (var , val , var2 , assignment [var2 ]))
81
-
82
81
return count (conflict (v ) for v in self .neighbors [var ])
83
82
84
83
def display (self , assignment ):
@@ -154,7 +153,6 @@ def conflicted_vars(self, current):
154
153
return [var for var in self .variables
155
154
if self .nconflicts (var , current [var ], current ) > 0 ]
156
155
157
-
158
156
# ______________________________________________________________________________
159
157
# Constraint Propagation with AC-3
160
158
@@ -185,51 +183,6 @@ def revise(csp, Xi, Xj, removals):
185
183
revised = True
186
184
return revised
187
185
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
-
233
186
# ______________________________________________________________________________
234
187
# CSP Backtracking Search
235
188
@@ -255,7 +208,6 @@ def num_legal_values(csp, var, assignment):
255
208
return count (csp .nconflicts (var , val , assignment ) == 0
256
209
for val in csp .domains [var ])
257
210
258
-
259
211
# Value ordering
260
212
261
213
@@ -269,7 +221,6 @@ def lcv(var, assignment, csp):
269
221
return sorted (csp .choices (var ),
270
222
key = lambda val : csp .nconflicts (var , val , assignment ))
271
223
272
-
273
224
# Inference
274
225
275
226
@@ -294,7 +245,6 @@ def mac(csp, var, value, assignment, removals):
294
245
"""Maintain arc consistency."""
295
246
return AC3 (csp , {(X , var ) for X in csp .neighbors [var ]}, removals )
296
247
297
-
298
248
# The search, proper
299
249
300
250
@@ -324,7 +274,6 @@ def backtrack(assignment):
324
274
assert result is None or csp .goal_test (result )
325
275
return result
326
276
327
-
328
277
# ______________________________________________________________________________
329
278
# Min-conflicts hillclimbing search for CSPs
330
279
@@ -353,7 +302,6 @@ def min_conflicts_value(csp, var, current):
353
302
return argmin_random_tie (csp .domains [var ],
354
303
key = lambda val : csp .nconflicts (var , val , current ))
355
304
356
-
357
305
# ______________________________________________________________________________
358
306
359
307
@@ -408,7 +356,7 @@ def build_topological(node, parent, neighbors, visited, stack, parents):
408
356
visited [node ] = True
409
357
410
358
for n in neighbors [node ]:
411
- if (not visited [n ]):
359
+ if (not visited [n ]):
412
360
build_topological (n , node , neighbors , visited , stack , parents )
413
361
414
362
parents [node ] = parent
@@ -418,9 +366,9 @@ def build_topological(node, parent, neighbors, visited, stack, parents):
418
366
def make_arc_consistent (Xj , Xk , csp ):
419
367
"""Make arc between parent (Xj) and child (Xk) consistent under the csp's constraints,
420
368
by removing the possible values of Xj that cause inconsistencies."""
421
- # csp.curr_domains[Xj] = []
369
+ #csp.curr_domains[Xj] = []
422
370
for val1 in csp .domains [Xj ]:
423
- keep = False # Keep or remove val1
371
+ keep = False # Keep or remove val1
424
372
for val2 in csp .domains [Xk ]:
425
373
if csp .constraints (Xj , val1 , Xk , val2 ):
426
374
# Found a consistent assignment for val1, keep it
@@ -445,7 +393,6 @@ def assign_value(Xj, Xk, csp, assignment):
445
393
# No consistent assignment available
446
394
return None
447
395
448
-
449
396
# ______________________________________________________________________________
450
397
# Map-Coloring Problems
451
398
@@ -521,7 +468,6 @@ def parse_neighbors(neighbors, variables=None):
521
468
PI; PA: LR RA; PC: PL CE LI AQ; PI: NH NO CA IF; PL: BR NB CE PC; RA:
522
469
AU BO FC PA LR""" )
523
470
524
-
525
471
# ______________________________________________________________________________
526
472
# n-Queens Problem
527
473
@@ -557,16 +503,16 @@ def __init__(self, n):
557
503
CSP .__init__ (self , list (range (n )), UniversalDict (list (range (n ))),
558
504
UniversalDict (list (range (n ))), queen_constraint )
559
505
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 )
563
509
564
510
def nconflicts (self , var , val , assignment ):
565
511
"""The number of conflicts, as recorded with each assignment.
566
512
Count conflicts in row and in up, down diagonals. If there
567
513
is a queen there, it can't conflict with itself, so subtract 3."""
568
514
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 ]
570
516
if assignment .get (var , None ) == val :
571
517
c -= 3
572
518
return c
@@ -614,7 +560,6 @@ def display(self, assignment):
614
560
print (str (self .nconflicts (var , val , assignment )) + ch , end = ' ' )
615
561
print ()
616
562
617
-
618
563
# ______________________________________________________________________________
619
564
# Sudoku
620
565
@@ -701,12 +646,9 @@ def show_cell(cell): return str(assignment.get(cell, '.'))
701
646
702
647
def abut (lines1 , lines2 ): return list (
703
648
map (' | ' .join , list (zip (lines1 , lines2 ))))
704
-
705
649
print ('\n ------+-------+------\n ' .join (
706
650
'\n ' .join (reduce (
707
651
abut , map (show_box , brow ))) for brow in self .bgrid ))
708
-
709
-
710
652
# ______________________________________________________________________________
711
653
# The Zebra Puzzle
712
654
@@ -774,7 +716,6 @@ def zebra_constraint(A, a, B, b, recurse=0):
774
716
(A in Smokes and B in Smokes )):
775
717
return not same
776
718
raise Exception ('error' )
777
-
778
719
return CSP (variables , domains , neighbors , zebra_constraint )
779
720
780
721
0 commit comments