Image goes here
Constraint Programming Example
CptS 355 - Programming Language Design
Washington State University

Constraint programming example

Here is the sudoku example of constraint programming, coded in a language called Alice-ML (look it up!). The example might help clarify some of what was said in class, but you are responsible only for what was discussed in class.
(*
 * Sudoku solver in alice-ml, using its constraint-programming capability.
 * This is a little tricky to follow if you start reading from the top, but
 * if you start with the in ... end block at the very end of the program
 * it will be clearer. Everything before that is in support of what is 
 * said in that block
 *)

(*
 * the function sudoku is passed to a built-in solver in alice ml;
 * the details are beyond the scope of this presentation. Just note
 * that the result of calling (sudoku sp) is a collection of constrained
 * variables (in the constraint programming sense). Depending on which
 * function is used to call sudoku the effect may be either to find the first
 * solution or all solutions.
 *) 
import structure FD from "x-alice:/lib/gecode/FD"
open FD
fun sudoku sp =
let
   (* 
    * first build the 81 variables of the sudoku problem. We
    * organize them as a vector of vectors. The notation #[...] is
    * a vector expression in alice-ml. rangeVec is a function in the 
    * FD structure. Each of these calls builds a 9-element vector
    * of variables, each variable constrained to values 1 thru 9.
    * Vector.tabulate could be used to avoid writing the same thing
    * 9 times!
    * the parameter sp is a so-called "computation space" roughly
    * corresponding to the abstract machine for constraint programming
    * that I described in class. Alice-ml supports the existence
    * of many such computation spaces at once.
    *)
   val m = #[rangeVec(sp, 9, (1,9)),
             rangeVec(sp, 9, (1,9)),
             rangeVec(sp, 9, (1,9)),
             rangeVec(sp, 9, (1,9)),
             rangeVec(sp, 9, (1,9)),
             rangeVec(sp, 9, (1,9)),
             rangeVec(sp, 9, (1,9)),
             rangeVec(sp, 9, (1,9)),
             rangeVec(sp, 9, (1,9))]
   (* indices - all of the interesting vector indices for this problem *)
   val indices = [0, 1, 2, 3, 4, 5, 6, 7, 8]
   (* 
    * distinct is a function from the FD structure that asserts that 
    * all of the elements of its vector paramenter (v) are distinct.
    * FD.BND means that "bounds propagation" is used -- again the
    * details are beyond the scope of this example.
    *)
   fun distinctRow v = distinct (sp, v, FD.BND)
   (*
    * For columns we have to form a vector of the elements of 
    * the column in order to pass it to distinct.
    * FD.branch states the distribution strategy to use:
    *    in this case choose the variable with the 
    *    fewest values (B_SIZE_MIN) and try the two
    *    cases: 
    *      assume the variable to has the minimum possible value (B_MIN)
    *      assume it does NOT have the minimum possible value 
    *)
   fun distinctCol i = let
      val col = Vector.tabulate (9, fn j => Vector.sub(Vector.sub (m, j), i))
   in	
      distinct (sp, col, FD.BND);
      branch(sp, col, B_SIZE_MIN, B_MIN)
   end
   (* 
    * all of the top left corners of the subsquares;
    * List comprehensions (which alice-ml does not have
    * would be able to express this algorithmically with greater
    * succinctness and clarity
    *)
   val sqTopLeft = [(0,0), (0,3), (0,6),
                  (3,0), (3,3), (3,6),
                  (6,0), (6,3), (6,6)]
   (* 
    * as for distinctCol we need to form a vector containing the elements of the square
    * to pass to distinct 
    *)
   fun distinctSquare (i,j) = let
      (* a list comprehension would be nice here too *)
      val sq = #[Vector.sub(Vector.sub(m,i),j),
                 Vector.sub(Vector.sub(m,i),j+1),
                 Vector.sub(Vector.sub(m,i),j+2),
                 Vector.sub(Vector.sub(m,i+1),j),
                 Vector.sub(Vector.sub(m,i+1),j+1),
                 Vector.sub(Vector.sub(m,i+1),j+2),
                 Vector.sub(Vector.sub(m,i+2),j),
                 Vector.sub(Vector.sub(m,i+2),j+1),
                 Vector.sub(Vector.sub(m,i+2),j+2)]
   in
      distinct(sp, sq, FD.BND)
   end
(*   val givens = [
      (0,1,6), (0,3,1), (0,5,4), (0,7,5),
      (1,2,8), (1,3,3), (1,5,5), (1,6,6),
      (2,0,2), (2,8,1),
      (3,0,8), (3,3,4), (3,5,7), (3,8,6),
      (4,2,6), (4,6,3),
      (5,0,7), (5,3,9), (5,5,1), (5,8,4),
      (6,0,5), (6,8,2),
      (7,2,7), (7,3,2), (7,5,6), (7,6,9),
      (8,1,4), (8,3,5), (8,5,8), (8,7,7)]
*)
(*   val givens = [
      (0,2,1), (0,6,8),
      (1,1,7), (1,3,3), (1,4,1), (1,7,9),
      (2,0,3), (2,4,4), (2,5,5), (2,8,7),
      (3,1,9), (3,3,7), (3,6,5),
      (4,1,4), (4,2,2), (4,4,5), (4,6,1), (4,7,3),
      (5,2,3), (5,5,9), (5,7,4),
      (6,0,2), (6,3,5), (6,4,7), (6,8,4),
      (7,1,3), (7,4,9), (7,5,1), (7,7,6),
      (8,2,4), (8,6,3)
   ]   
*)
   (* 
    * Being lazy I didn't write any input code and just
    * coded the sudoku puzzle input as part of the program
    *)
   val givens = [
      (0,3,1), (0,6,7), (0,7,4),
      (1,1,5), (1,4,9), (1,7,3), (1,8,2),
      (2,2,6), (2,3,7), (2,6,9),
      (3,0,4), (3,3,8),
      (4,1,2), (4,7,1),
      (5,5,9), (5,8,5),
      (6,2,4), (6,5,7), (6,6,3),
      (7,0,7), (7,1,3), (7,4,2), (7,7,6),
      (8,1,6), (8,2,5), (8,5,4)
   ]   

   (* 
    * To assert that a particular square (i,j) has value v we use
    * FD.reLI which inserts an integer relation (EQ in this case) between
    * a particular variable and value
    *)
   fun insertGiven (i,j,v) = relI(sp,Vector.sub(Vector.sub(m, i),j), EQ, v)
in
   (* 
    * distinctRow imposes all the constraints needed to say that the elements of a row
    * are distinct. The representation of the problem is a vector of vectors, each
    * vector containing the "variables" (in the constraint programming sense) of a 
    * single row. distinctRow takes a vector of such variables. 
    *)
   Vector.app distinctRow m;
   (*
    * distinctCol imposes all the constraints needed to say that the elements of a column
    * are distinct. Since the columns are not themselves vectors (the jth col is the jth element
    * of each of the nine row vectors) distinctCol takes an int column number as its parameter
    *)
   List.app distinctCol indices;
   (*
    * distinctSquare imposes all the constraints for a single square given the indices of 
    * its top left corner
    *)
   List.app distinctSquare sqTopLeft;
   (*
    * given a list of (i,j,v) tuples, insertGivens asserts the equality of 
    * the variable representing the (i,j) square to v.
    *)
   List.app insertGiven givens;
   (*
    * The result is the vector of vectors of variables.
    *)
   m
end

(c) 2003 Curtis Dyreson, (c) 2004-2006 Carl H. Hauser           E-mail questions or comments to Prof. Carl Hauser