tower_of_hanoi.mlw 3.09 KB
Newer Older
1
module Hanoi
2
  (* a simple version where the disks are natural numbers from 1 to n *)
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

  use import int.Int
  use import list.List
  use import list.Length
  use import list.SortedInt

  type tower = {
    mutable rod : list int;
  } invariant {
    sorted self.rod
  }

  function prepend (n: int) (s: list int) : list int

  axiom prepend_def_zero :
    forall s: list int, n: int.
      n <= 0 -> prepend n s = s

  axiom prepend_def_succ :
    forall s: list int, n: int.
      n > 0 -> prepend n s = prepend (n - 1) (Cons n s)

  let move (a b: tower) (ghost n: int) (ghost s: list int)
    requires { a.rod = Cons n s }
    requires { match b.rod with Nil -> true | Cons x _ -> x > n end }
    ensures  { a.rod = s }
    ensures  { b.rod = Cons n (old b.rod) }
  = match a.rod with
    | Cons x r ->
        a.rod <- r;
        b.rod <- Cons x b.rod
    | Nil -> absurd
    end

  let rec hanoi_rec (a b c: tower) (n: int) (ghost s: list int)
    requires { a.rod = prepend n s }
    requires { match b.rod with Nil -> true | Cons x _ -> x > n end }
    requires { match c.rod with Nil -> true | Cons x _ -> x > n end }
    variant  { n }
    ensures  { a.rod = s }
    ensures  { b.rod = prepend n (old b.rod) }
    ensures  { c.rod = old c.rod }
  = if n > 0 then begin
Andrei Paskevich's avatar
Andrei Paskevich committed
46
      let ghost t = c.rod in
47 48 49 50 51 52 53 54 55 56 57 58 59
      hanoi_rec a c b (n-1) (Cons n s);
      move a b n s;
      hanoi_rec c b a (n-1) t
    end

  let tower_of_hanoi (a b c: tower)
    requires { a.rod = prepend (length a.rod) Nil }
    requires { b.rod = c.rod = Nil }
    ensures  { b.rod = old a.rod }
    ensures  { a.rod = c.rod = Nil }
  = hanoi_rec a b c (length a.rod) Nil

end
60

61
module Tower_of_Hanoi
62
  (* a generalized version where the disks are arbitrary integers *)
63 64 65 66 67

  use import int.Int
  use import list.List
  use import list.Length

68
  use import list.RevAppend
69 70
  clone import list.RevSorted with type t = int, predicate le = (<),
  goal Transitive.Trans
71 72 73 74

  type tower = {
    mutable rod : list int;
  } invariant {
75
    Incr.sorted self.rod
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
  }

  let move (a b: tower) (ghost x: int) (ghost s: list int)
    requires { a.rod = Cons x s }
    requires { match b.rod with Nil -> true | Cons y _ -> x < y end }
    ensures  { a.rod = s }
    ensures  { b.rod = Cons x (old b.rod) }
  = match a.rod with
    | Cons x r ->
        a.rod <- r;
        b.rod <- Cons x b.rod
    | Nil -> absurd
    end

  let rec hanoi_rec (a b c: tower) (n: int) (ghost p s: list int)
91
    requires { length p = n /\ Decr.sorted p }
92 93 94 95 96 97 98 99 100
    requires { a.rod = rev_append p s }
    requires { compat p b.rod }
    requires { compat p c.rod }
    variant  { n }
    ensures  { a.rod = s }
    ensures  { b.rod = rev_append p (old b.rod) }
    ensures  { c.rod = old c.rod }
  = if n > 0 then begin
      let ghost t = c.rod in
101
      let x,r = match p with Cons x r -> (x,r) | Nil -> absurd end in
102 103 104 105 106 107 108 109 110
      hanoi_rec a c b (n-1) r (Cons x s);
      move a b x s;
      hanoi_rec c b a (n-1) r t
    end

  let tower_of_hanoi (a b c: tower)
    requires { b.rod = c.rod = Nil }
    ensures  { b.rod = old a.rod }
    ensures  { a.rod = c.rod = Nil }
111
  = hanoi_rec a b c (length a.rod) (ghost rev_append a.rod Nil) Nil
112 113

end