@@ -85,7 +85,7 @@ def display(self, assignment):
85
85
# Subclasses can print in a prettier way, or display with a GUI
86
86
print ('CSP:' , self , 'with assignment:' , assignment )
87
87
88
- # These methods are for the tree- and graph-search interface:
88
+ # These methods are for the tree and graph-search interface:
89
89
90
90
def actions (self , state ):
91
91
"""Return a list of applicable actions: nonconflicting
@@ -308,15 +308,18 @@ def tree_csp_solver(csp):
308
308
"""[Figure 6.11]"""
309
309
assignment = {}
310
310
root = csp .variables [0 ]
311
- root = 'NT'
312
311
X , parent = topological_sort (csp , root )
312
+
313
+ csp .support_pruning ()
313
314
for Xj in reversed (X [1 :]):
314
315
if not make_arc_consistent (parent [Xj ], Xj , csp ):
315
316
return None
316
- for Xi in X :
317
- if not csp .curr_domains [Xi ]:
317
+
318
+ assignment [root ] = csp .curr_domains [root ][0 ]
319
+ for Xi in X [1 :]:
320
+ assignment [Xi ] = assign_value (parent [Xi ], Xi , csp , assignment )
321
+ if not assignment [Xi ]:
318
322
return None
319
- assignment [Xi ] = csp .curr_domains [Xi ][0 ]
320
323
return assignment
321
324
322
325
@@ -361,7 +364,34 @@ def build_topological(node, parent, neighbors, visited, stack, parents):
361
364
362
365
363
366
def make_arc_consistent (Xj , Xk , csp ):
364
- raise NotImplementedError
367
+ """Make arc between parent (Xj) and child (Xk) consistent under the csp's constraints,
368
+ by removing the possible values of Xj that cause inconsistencies."""
369
+ #csp.curr_domains[Xj] = []
370
+ for val1 in csp .domains [Xj ]:
371
+ keep = False # Keep or remove val1
372
+ for val2 in csp .domains [Xk ]:
373
+ if csp .constraints (Xj , val1 , Xk , val2 ):
374
+ # Found a consistent assignment for val1, keep it
375
+ keep = True
376
+ break
377
+
378
+ if not keep :
379
+ # Remove val1
380
+ csp .prune (Xj , val1 , None )
381
+
382
+ return csp .curr_domains [Xj ]
383
+
384
+
385
+ def assign_value (Xj , Xk , csp , assignment ):
386
+ """Assign a value to Xk given Xj's (Xk's parent) assignment.
387
+ Return the first value that satisfies the constraints."""
388
+ parent_assignment = assignment [Xj ]
389
+ for val in csp .curr_domains [Xk ]:
390
+ if csp .constraints (Xj , parent_assignment , Xk , val ):
391
+ return val
392
+
393
+ # No consistent assignment available
394
+ return None
365
395
366
396
# ______________________________________________________________________________
367
397
# Map-Coloring Problems
@@ -389,8 +419,8 @@ def different_values_constraint(A, a, B, b):
389
419
390
420
def MapColoringCSP (colors , neighbors ):
391
421
"""Make a CSP for the problem of coloring a map with different colors
392
- for any two adjacent regions. Arguments are a list of colors, and a
393
- dict of {region: [neighbor,...]} entries. This dict may also be
422
+ for any two adjacent regions. Arguments are a list of colors, and a
423
+ dict of {region: [neighbor,...]} entries. This dict may also be
394
424
specified as a string of the form defined by parse_neighbors."""
395
425
if isinstance (neighbors , str ):
396
426
neighbors = parse_neighbors (neighbors )
@@ -400,9 +430,9 @@ def MapColoringCSP(colors, neighbors):
400
430
401
431
def parse_neighbors (neighbors , variables = []):
402
432
"""Convert a string of the form 'X: Y Z; Y: Z' into a dict mapping
403
- regions to neighbors. The syntax is a region name followed by a ':'
433
+ regions to neighbors. The syntax is a region name followed by a ':'
404
434
followed by zero or more region names, followed by ';', repeated for
405
- each region name. If you say 'X: Y' you don't need 'Y: X'.
435
+ each region name. If you say 'X: Y' you don't need 'Y: X'.
406
436
>>> parse_neighbors('X: Y Z; Y: Z') == {'Y': ['X', 'Z'], 'X': ['Y', 'Z'], 'Z': ['X', 'Y']}
407
437
True
408
438
"""
0 commit comments