(* CTM Chapter #12 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
(* convert term to intvar *)
fun term2intvar (FD(x)) = x
| term2intvar _ = raise Domain
(* convert int to intvar *)
fun int2intvar (sp, x) = FD.intvar(sp, #[(x,x)])
(* 12.1.2 Propagate-and-search - Calculating with partial information *)
fun partial sp =
let
val x = fdterm(sp, [90 `# 110])
val y = fdterm(sp, [48 `# 53])
val a = fdterm(sp, [0 `# 10000])
in
(* Alice currently only supports linear expressions. Will be
generalized for non-linear expressions in the next release. *)
(* post (sp, x `* y `= a, FD.DOM); *)
FD.mult (sp, term2intvar(x), term2intvar(y), term2intvar(a), FD.DOM);
post (sp, a `> `4000, FD.DOM);
post (sp, x `- `2 `* y `= `11, FD.DOM);
branch (sp, #[a, x, y], FD.B_SIZE_MIN, FD.B_MIN);
{a, x, y}
end;
Explorer.exploreAll partial;
val sol = Search.searchAll partial
(* another way to do the same thing *)
fun partial2 sp =
let
val x = FD.intvar(sp, #[(90,110)])
val y = FD.intvar(sp, #[(48,53)])
val a = FD.intvar(sp, #[(0,10000)])
in
FD.mult (sp, x, y, a, FD.DOM);
post (sp, FD(a) `> `4000, FD.DOM);
post (sp, FD(x) `- `2 `* FD(y) `= `11, FD.DOM);
FD.branch (sp, #[x, y], FD.B_SIZE_MIN, FD.B_MIN);
{x,y}
end;
Explorer.exploreAll partial2;
(* 12.1.4 Propagate-and-search - Executing the example *)
fun rectangle sp =
let
val v as #[x, y] = fdtermVec (sp, 2, [0 `# 9])
val a = FD.intvar(sp, #[(0,10000)]) (* needed for workaround *)
in
(* post (sp, x `* y `= `24, FD.DOM); *)
FD.mult (sp, term2intvar(x), term2intvar(y), a, FD.DOM);
post (sp, FD(a) `= `24, FD.DOM);
post (sp, x `+ y `= `10, FD.DOM);
post (sp, x `< y, FD.DOM);
branch (sp, #[x, y], FD.B_SIZE_MIN, FD.B_MIN);
{x, y}
end;
Explorer.exploreAll rectangle;
(* 12.2.1 Programming techniques - Calculting with partial information *)
(* Note: this comes straight out of the Alice documentation *)
fun money sp =
let
val v as #[s, e, n, d, m, o', r, y] = Linear.fdtermVec (sp, 8, [0 `# 9])
in
distinct (sp, v, FD.BND);
post (sp, s `<> `0, FD.BND);
post (sp, m `<> `0, FD.BND);
post (sp, `1000`*s `+ `100`*e `+ `10`*n `+ d `+
`1000`*m `+ `100`*o' `+ `10`*r `+ e `=
`10000`*m `+ `1000`*o' `+ `100`*n `+ `10`*e `+ y, FD.BND);
branch (sp, v, FD.B_SIZE_MIN, FD.B_MIN);
{s,e,n,d,m,o',r,y}
end;
Explorer.exploreAll money;
(* 12.2.2 Programming techniques - Palindrome products revisited *)
fun palindrome sp =
let
val a = FD.intvar(sp, #[(0,999999)])
val b = FD.intvar(sp, #[(0,999)])
val c = FD.intvar(sp, #[(0,999)])
val x = FD.intvar(sp, #[(0,9)])
val y = FD.intvar(sp, #[(0,9)])
val z = 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) `* `100000) `+
(FD(y) `* `10000) `+
(FD(z) `* `1000) `+
(FD(z) `* `100) `+
(FD(y) `* `10) `+
FD(x), FD.DOM);
post (sp, FD(a) `> `100000, FD.DOM);
branch (sp, #[FD(x),FD(y),FD(z),FD(b),FD(c)], FD.B_SIZE_MIN, FD.B_MIN);
{a,x,y}
end;
Explorer.exploreOne palindrome;
|