@@ -85,7 +85,7 @@ def display(self, assignment):
8585 # Subclasses can print in a prettier way, or display with a GUI
8686 print ('CSP:' , self , 'with assignment:' , assignment )
8787
88- # These methods are for the tree- and graph-search interface:
88+ # These methods are for the tree and graph-search interface:
8989
9090 def actions (self , state ):
9191 """Return a list of applicable actions: nonconflicting
@@ -308,15 +308,18 @@ def tree_csp_solver(csp):
308308 """[Figure 6.11]"""
309309 assignment = {}
310310 root = csp .variables [0 ]
311- root = 'NT'
312311 X , parent = topological_sort (csp , root )
312+
313+ csp .support_pruning ()
313314 for Xj in reversed (X [1 :]):
314315 if not make_arc_consistent (parent [Xj ], Xj , csp ):
315316 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 ]:
318322 return None
319- assignment [Xi ] = csp .curr_domains [Xi ][0 ]
320323 return assignment
321324
322325
@@ -361,7 +364,34 @@ def build_topological(node, parent, neighbors, visited, stack, parents):
361364
362365
363366def 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
365395
366396# ______________________________________________________________________________
367397# Map-Coloring Problems
@@ -389,8 +419,8 @@ def different_values_constraint(A, a, B, b):
389419
390420def MapColoringCSP (colors , neighbors ):
391421 """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
394424 specified as a string of the form defined by parse_neighbors."""
395425 if isinstance (neighbors , str ):
396426 neighbors = parse_neighbors (neighbors )
@@ -400,9 +430,9 @@ def MapColoringCSP(colors, neighbors):
400430
401431def parse_neighbors (neighbors , variables = []):
402432 """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 ':'
404434 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'.
406436 >>> parse_neighbors('X: Y Z; Y: Z') == {'Y': ['X', 'Z'], 'X': ['Y', 'Z'], 'Z': ['X', 'Y']}
407437 True
408438 """
0 commit comments