ROUGH IDEA FOR CONSTRAINTS PACKAGE: A *constraint network* is a collection of *variables* and *constraint arcs*. Each *variable* has a name (a symbol or number) and a finite domain (a list of acceptable values). Each *constraint arc* has a pair of variables (between which the constraint is enforced), a string description of the arc (for debugging), a *predicate* that checks if the constraint is satisfied, and a list of parameters that can affect the behavior of the predicate. Constraint-based reasoning consists of two interdigitated phases: propagation of constraints and search. Each of these phases can take several forms, depending on the precise reasoning approach being used. Recall that propagation on its own does *not* ensure identification of a single, consistent solution; search may be needed to try out various choices. In this system, *constraint-search-strategies* contain all the information about how the system is supposed to make these choices. There are three components: - How to pick which variable to search on, at each step. This takes the form of a procedure that is called on the network (capturing the state of all assignments made so far) and a list of the names of the variables that have yet to be assigned by the search process. In practice, this procedure might compare domain sizes (in an effort to first choose the "most constrained" domain) or use other sophisticated heuristics. For this problem set, you'll only have to use simple, arbitrary strategies that add no heuristic information, such as picking the first variable from the list. - How much propagation should be done in between each step. This essentially takes the form of a predicate that is given the variable, the variable's previous domain size, and the variable's new domain size, and returns true if inconsistent domain values should be eliminated. See propagate-constraints.scm for examples (e.g. the *propagate-constraints-strategy::domains-of-one* procedure). - How to decide when to stop. This takes the form of a predicate called on the list of successes so far (where each success consists of a list of bindings that solves the reasoning problem). If this always returns false, this will cause the reasoner to search until no further choices can be made, and return all possible successes. If this predicate returns true whenever the list of successes is nonempty, the search will stop as soon as the first set of satisfactory bindings is found. Constraint strategy objects are constructed by the new-constraint-search-strategy procedure (documented in constraint-search.scm), with examples such as *constraint-search-strategy::only-check-assignments* that does no constraint propagation, and *constraint-search-strategy::domains-of-one/all* which propagates constraints when the relevant domain is of size one, and continues until all solutions have been found. Note that you will not be able to use the only-check-assignments strategy until you have completed problem 6.