| 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