| A hard Sudoku Puzzle | ||||||||
| 3 | 6 | |||||||
| 1 | ||||||||
| 9 | 7 | 5 | 8 | |||||
| 9 | 2 | |||||||
| 8 | 7 | 4 | ||||||
| 3 | 6 | |||||||
| 1 | 2 | 8 | 9 | |||||
| 4 | ||||||||
| 5 | 1 | |||||||
grid'[i] = jwhere grid is the vector of problem variables from the first model and numbers the vector of problem variables from the second model. Note, that the channeling constraints are realized with Reified Constraints among other things.i + 1
numbers[ j-1],
val inputlist_hard=[(0,5,3),(0,7,6),(1,7,1),(2,1,9),
                    (2,2,7),(2,3,5),(2,7,8),(3,4,9),
                    (3,6,2),(4,2,8),(4,4,7),(4,6,4),
                    (5,2,3),(5,4,6),(6,1,1),(6,5,2),
                    (6,6,8),(6,7,9),(7,1,4),(8,1,5),
                    (8,3,1)]                 
fun sudoku inputlist space = 
  let
     val grid = Vector.tabulate(9,fn x => 
                         FD.rangeVec(space,9,(1,9)))
     val grid' = Vector.concat(Vector.toList(grid))
     val numbers = Vector.tabulate(9,fn x => 
                         FS.upperBound(space,#[(1,81)]))
     val rows = List.tabulate(9,fn x =>(x*9+9-8,x*9+9)) 
     val domainvecs = List.tabulate(9,fn y => 
                       Vector.tabulate(9,fn x =>(x*9+1+y,x*9+1+y)))
     val boxes1 = List.tabulate(3,fn y => 
                   Vector.tabulate(3,fn x =>(x*9+1+y*3,x*9+3+y*3)))
     val boxes2 = List.tabulate(3,fn y => 
                   Vector.tabulate(3,fn x =>(x*9+28+y*3,x*9+30+y*3)))
     val boxes3 = List.tabulate(3,fn y => 
                   Vector.tabulate(3,fn x =>(x*9+55+y*3,x*9+57+y*3)))
     val boxes = List.concat([boxes1,boxes2,boxes3])
     fun flatten([])= []
       | flatten(x::xs)= x@flatten(xs)
     fun box(x,y)= flatten(List.tabulate(3,fn k => 
                            List.tabulate(3,fn z =>(k+x,z+y))))
     fun constr l = 
       List.app(fn y => 
           let
              val tmp1 = FS.Value.make(space,y)
           in
              Vector.app(fn x => 
                  let 
                     val tmp2 = FS.setvar space 
                  in
                     FS.relOp(space,x,FS.INTER,tmp1,FS.SEQ,tmp2);
                     FS.cardRange(space,1,1,tmp2)
                  end)numbers
           end)l 
     fun fsDisjoint ([]) = ()
       | fsDisjoint (x::xs) = 
            (List.app(fn y => FS.rel(space,y, FS.DISJ,x))xs;
             fsDisjoint(xs))           
  in
     List.app(fn(x,y,z) => FD.relI(space,Vector.sub
                          (Vector.sub(grid,x),y),FD.EQ,z))inputlist;
    (* distinct values in rows *)
     Vector.app(fn x => FD.distinct(space,x,FD.DOM))grid;
    (* distinct values in columns *)
     Vector.appi(fn(i,y)=> FD.distinct(space,Vector.map(fn x => 
                                  Vector.sub(x,i))grid,FD.DOM))grid;
    (* distinct values in 3 x 3 boxes *)
     Vector.app(fn(k,l)=> 
       let
          val box' = Vector.map(fn(x,y) => 
                              Vector.sub(Vector.sub(grid,x),y))
                       (Vector.fromList(box(k,l)))
       in
          FD.distinct(space,box',FD.DOM)
      end)(#[(0,0),(0,3),(0,6),(3,0),(3,3),(3,6),(6,0),(6,3),(6,6)]);
     Vector.app(fn x => FS.cardRange(space,9,9,x))numbers;
    (* the domains of all numbers are pairwise distinct *)
     fsDisjoint(Vector.toList numbers);
    (* distinct numbers in rows *)
     List.app(fn(y,z)=>
        let 
           val tmp1 = FS.Value.make(space,#[(y,z)]) 
        in
           Vector.app(fn x => 
                let 
                   val tmp2 = FS.setvar space 
                in
                   FS.relOp(space,x,FS.INTER,tmp1,FS.SEQ,tmp2);
                   FS.cardRange(space,1,1,tmp2)
               end)numbers
        end)rows;
    (* distinct numbers in columns *)
     constr domainvecs;  
    (* distinct numbers in 3 x 3 boxes *)
     constr boxes;   
    (* channeling constraints: grid'[i] = j <=> i+1 in numbers[j-1] *)
     List.app(fn i => 
          List.app(fn j =>
             let
                val bvar = FD.boolvar space
             in  
                FD.Reified.relI(space,Vector.sub(grid',i-1),
                                     FD.EQ,j,bvar);
                FS.domR(space,Vector.sub(numbers,j-1),
                                     FS.SUP,#[(i,i)],bvar)
             end)
             (List.tabulate(9,fn x => x+1)))
         (List.tabulate(81,fn x => x+1));
     FS.setvarbranch(space,numbers,FS.FSB_MIN_CARD,FS.FSB_MIN); 
     numbers
  end
Below, the three realizations of the a hard Sudoku Problem 12.2.1 are compared:
| Problem realized with | Choices | Failures | Solutions | 
| finite domain constraints | 28 | 28 | 1 | 
| finite set constraints | 12 | 12 | 1 | 
| combined model | 10 | 10 | 1 | 
Andreas Rossberg 2006-08-28