(* CTM Chapter #09 Examples in Alice ML *)
import structure Space from "x-alice:/lib/gecode/Space"
import structure FS from "x-alice:/lib/gecode/FS"
import structure FD from "x-alice:/lib/gecode/FD"
import structure Search from "x-alice:/lib/gecode/Search"
import structure Linear from "x-alice:/lib/gecode/Linear"
import structure Explorer from "x-alice:/lib/tools/Explorer";
(* syntactic sugar for solutions using promises/futures *)
open Linear
open Promise
open Future
infix 3 ?=
val op?= = fulfill
val ? = future
(* Note: I haven't figured out how to get a choice type statement in Alice ML.
In the meantime, I show how to use constraint programming (ala chapter #12)
to translate the examples *)
(* 9.1.1 The relational computation model - The choice and fail statements *)
(* Encoding: beige=0 coral=1 mauve=2 ochre=3 *)
fun suit sp =
let
val soft = FD.intvar(sp, #[(0,1)])
val hard = FD.intvar(sp, #[(2,3)])
val shirt = FD.intvar(sp, #[(0,3)])
val pants = FD.intvar(sp, #[(0,3)])
val socks = FD.intvar(sp, #[(0,3)])
in
Linear.distinct (sp, #[FD(shirt),FD(pants),FD(socks)], FD.BND);
(* Need to figure out how to use FD.conj and FD.disj???
FD.disj(sp, `true,
FD.conj(sp, `true, shirt'>=hard, FD.conj(sp, `true, pants'>=soft, socks'<=hard)),
FD.conj(sp, `true, shirt'<=soft, FD.conj(sp, `true, pants'<=hard, socks'>=soft))); *)
branch (sp, #[FD(shirt),FD(pants),FD(socks)], FD.B_SIZE_MIN, FD.B_MIN);
{shirt,pants,socks}
end;
Explorer.exploreAll suit;
(* 8 Solutions
suit(0 2 1) suit(beige mauve coral)
suit(0 3 1) suit(beige ochre coral)
suit(1 2 0) suit(coral mauve beige)
suit(1 3 0) suit(coral ochre beige)
suit(2 0 3) suit(mauve beige ochre)
suit(2 1 3) suit(mauve coral ochre)
suit(3 0 2) suit(ochre beige mauve)
suit(3 1 2) suit(ochre coral mauve)
*)
(* 9.1.4 The relational computation model - The Solve function *)
fun nrange sp =
let
val x = fdterm(sp, [``1, ``2, ``3])
in
branch (sp, #[x], FD.B_SIZE_MIN, FD.B_MIN);
{x}
end;
Explorer.exploreAll nrange;
(* 9.2.1 Further examples - Numeric examples *)
fun digit sp =
let
val x = fdterm(sp, [0 `# 9])
in
branch (sp, #[x], FD.B_SIZE_MIN, FD.B_MIN);
{x}
end;
Explorer.exploreAll digit;
fun twodigit sp =
let
val x = fdterm(sp, [0 `# 9])
val y = fdterm(sp, [0 `# 9])
val a = fdterm(sp, [0 `# 99])
in
post (sp, a `= x `+ `10 `* y, FD.DOM);
branch (sp, #[a], FD.B_SIZE_MIN, FD.B_MIN);
{a}
end;
Explorer.exploreAll twodigit;
fun palindrome sp =
let
val a = FD.intvar(sp, #[(0,9999)])
val b = FD.intvar(sp, #[(0,99)])
val c = FD.intvar(sp, #[(0,99)])
val x = FD.intvar(sp, #[(0,9)])
val y = FD.intvar(sp, #[(0,9)])
in
(* post (sp, FD(a) `= FD(b) `* FD(c), FD.DOM); *)
FD.mult (sp, b, c, a, FD.DOM);
post (sp, FD(a) `= (FD(x) `* `1000) `+
(FD(y) `* `100) `+
(FD(y) `* `10) `+
FD(x), FD.DOM);
post (sp, FD(a) `> `1000, FD.DOM);
branch (sp, #[FD(x),FD(y),FD(b),FD(c)], FD.B_SIZE_MIN, FD.B_MIN);
{a,x,y}
end;
Explorer.exploreOne palindrome;
(* 9.2.1 Further examples - Puzzles and the n-queens problem *)
(* Alice ML code for queens was lifted from the lecture notes from
Guido Tack and Marco Kuhlmann. See:
http://www.ps.uni-sb.de/courses/cp-ss05/
http://www.ps.uni-sb.de/courses/cp-ss05/services.html *)
(* triangle n computes the upper triangular matrix with elements 0 <= i < j <= n *)
fun loop i n f = if i >= n then nil else f i :: loop (i + 1) n f
fun upperTriangle n = List.concat (loop 0 n (fn i => loop (i + 1) n (fn j => (i, j))))
(* n-queens problem *)
fun queens n sp =
let
val row = Linear.fdtermVec (sp, n, [0`#(n - 1)])
in
Linear.distinct (sp, row, FD.BND);
List.app (fn (i, j) =>
let
val rowi = Vector.sub (row, i)
val rowj = Vector.sub (row, j)
in
post (sp, rowi `+ (`j `- `i) `<> rowj, FD.BND);
post (sp, rowi `- (`j `- `i) `<> rowj, FD.BND)
end) (upperTriangle n);
Linear.branch (sp, row, FD.B_SIZE_MIN, FD.B_MED);
row
end;
Explorer.exploreOne (queens 8);
(* n-queens problem, more efficient *)
fun betterqueens n sp =
let
val row = FD.rangeVec (sp, n, (0, n - 1))
val add = Vector.tabulate (n, fn i => 0 + i)
val sub = Vector.tabulate (n, fn i => 0 - i)
in
FD.distinct (sp, row, FD.BND);
FD.distinctOffset (sp, VectorPair.zip (add, row), FD.BND);
FD.distinctOffset (sp, VectorPair.zip (sub, row), FD.BND);
FD.branch (sp, row, FD.B_SIZE_MIN, FD.B_MED);
row
end;
Explorer.exploreOne (betterqueens 8);
|