2020-03-04 15:02:59 +01:00
|
|
|
|
|
|
|
|
(** Implementation of a mutable queue using two lists.
|
|
|
|
|
|
|
|
|
|
Author: Léo Andrès (Univ. paris-Sud) *)
|
|
|
|
|
|
2019-06-05 17:52:22 +02:00
|
|
|
module Queue
|
|
|
|
|
|
|
|
|
|
use int.Int
|
|
|
|
|
use mach.peano.Peano
|
|
|
|
|
use list.List
|
|
|
|
|
use list.Length
|
|
|
|
|
use list.Reverse
|
|
|
|
|
use list.NthNoOpt
|
|
|
|
|
use list.Append
|
|
|
|
|
use seq.Seq
|
2020-03-13 17:00:37 +01:00
|
|
|
use seq.FreeMonoid
|
2019-06-05 17:52:22 +02:00
|
|
|
|
|
|
|
|
type t 'a = {
|
2020-03-13 17:00:37 +01:00
|
|
|
mutable front: list 'a; (* entry *)
|
|
|
|
|
mutable rear: list 'a; (* exit *)
|
2019-06-05 17:52:22 +02:00
|
|
|
ghost mutable seq: Seq.seq 'a;
|
|
|
|
|
}
|
|
|
|
|
invariant { length seq = Length.length front + Length.length rear }
|
2020-03-13 17:00:37 +01:00
|
|
|
invariant { Length.length front > 0 -> Length.length rear > 0 }
|
2019-06-05 17:52:22 +02:00
|
|
|
invariant {
|
|
|
|
|
forall i. 0 <= i < length seq ->
|
|
|
|
|
seq[i] =
|
|
|
|
|
let n = Length.length rear in
|
|
|
|
|
if i < n then nth i rear
|
|
|
|
|
else nth (Length.length front - 1 - (i - n)) front }
|
|
|
|
|
|
|
|
|
|
meta coercion function seq
|
|
|
|
|
|
|
|
|
|
let create () : t 'a
|
|
|
|
|
ensures { result = empty }
|
|
|
|
|
= {
|
|
|
|
|
front = Nil;
|
|
|
|
|
rear = Nil;
|
|
|
|
|
seq = empty
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let push (x: 'a) (q: t 'a) : unit
|
2020-03-13 17:00:37 +01:00
|
|
|
writes { q }
|
2019-06-05 17:52:22 +02:00
|
|
|
ensures { q = snoc (old q) x }
|
2020-03-13 17:00:37 +01:00
|
|
|
= match q.front, q.rear with
|
|
|
|
|
| Nil, Nil -> q.rear <- Cons x Nil
|
|
|
|
|
| _ -> q.front <- Cons x q.front
|
|
|
|
|
end;
|
|
|
|
|
q.seq <- snoc q.seq x
|
2019-06-05 17:52:22 +02:00
|
|
|
|
|
|
|
|
let rec lemma nth_append (i: int) (l1: list 'a) (l2: list 'a)
|
|
|
|
|
requires { 0 <= i < Length.length l1 + Length.length l2 }
|
|
|
|
|
ensures {
|
|
|
|
|
nth i (Append.(++) l1 l2) =
|
|
|
|
|
if i < Length.length l1 then nth i l1
|
|
|
|
|
else nth (i - Length.length l1) l2 }
|
|
|
|
|
variant { l1 }
|
|
|
|
|
=
|
|
|
|
|
match l1 with
|
|
|
|
|
| Nil -> ()
|
|
|
|
|
| Cons _ r1 ->
|
|
|
|
|
if i > 0 then nth_append (i - 1) r1 l2
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
(* TODO: move this to stdlib ? *)
|
|
|
|
|
let rec lemma nth_rev (i: int) (l: list 'a)
|
|
|
|
|
requires { 0 <= i < Length.length l }
|
|
|
|
|
ensures { nth i l = nth (Length.length l - 1 - i) (reverse l) }
|
|
|
|
|
variant { l }
|
|
|
|
|
=
|
|
|
|
|
match l with
|
|
|
|
|
| Nil -> absurd
|
2020-03-04 15:02:59 +01:00
|
|
|
| Cons _ s ->
|
2019-06-05 17:52:22 +02:00
|
|
|
if i > 0 then nth_rev (i - 1) s
|
2020-03-04 15:02:59 +01:00
|
|
|
end
|
2019-06-05 17:52:22 +02:00
|
|
|
|
|
|
|
|
exception Empty
|
|
|
|
|
|
|
|
|
|
let pop (q: t 'a) : 'a
|
2020-03-13 17:00:37 +01:00
|
|
|
writes { q }
|
2019-06-05 17:52:22 +02:00
|
|
|
ensures { (old q) <> empty }
|
|
|
|
|
ensures { result = (old q)[0] }
|
|
|
|
|
ensures { q = (old q)[1 ..] }
|
2020-03-13 17:00:37 +01:00
|
|
|
raises { Empty -> q = old q = empty }
|
2019-06-05 17:52:22 +02:00
|
|
|
=
|
2020-03-13 17:00:37 +01:00
|
|
|
let res = match q.rear with
|
2019-06-05 17:52:22 +02:00
|
|
|
| Nil -> raise Empty
|
2020-03-13 17:00:37 +01:00
|
|
|
| Cons x Nil -> q.front, q.rear <- Nil, reverse q.front; x
|
2019-06-05 17:52:22 +02:00
|
|
|
| Cons x s -> q.rear <- s; x
|
2020-03-13 17:00:37 +01:00
|
|
|
end in
|
2019-06-05 17:52:22 +02:00
|
|
|
q.seq <- q.seq [1 ..];
|
|
|
|
|
res
|
|
|
|
|
|
|
|
|
|
let peek (q: t 'a) : 'a
|
|
|
|
|
ensures { q <> empty }
|
|
|
|
|
ensures { result = q[0] }
|
2020-03-13 17:00:37 +01:00
|
|
|
raises { Empty -> q == empty }
|
2019-06-05 17:52:22 +02:00
|
|
|
=
|
|
|
|
|
match q.rear with
|
2020-03-13 17:00:37 +01:00
|
|
|
| Nil -> raise Empty
|
2019-06-05 17:52:22 +02:00
|
|
|
| Cons x _ -> x
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let safe_pop (q: t 'a) : 'a
|
|
|
|
|
requires { q <> empty }
|
|
|
|
|
writes { q }
|
|
|
|
|
ensures { result = (old q)[0] }
|
|
|
|
|
ensures { q = (old q)[1 ..] }
|
|
|
|
|
= try pop q with Empty -> absurd end
|
|
|
|
|
|
|
|
|
|
let safe_peek (q: t 'a) : 'a
|
|
|
|
|
requires { q <> empty }
|
|
|
|
|
ensures { result = q[0] }
|
|
|
|
|
= try peek q with Empty -> absurd end
|
|
|
|
|
|
|
|
|
|
let clear (q: t 'a) : unit
|
|
|
|
|
writes { q }
|
|
|
|
|
ensures { q = empty }
|
|
|
|
|
=
|
|
|
|
|
q.seq <- empty;
|
|
|
|
|
q.rear <- Nil;
|
|
|
|
|
q.front <- Nil
|
|
|
|
|
|
|
|
|
|
let copy (q: t 'a) : t 'a
|
|
|
|
|
ensures { result == q }
|
|
|
|
|
= {
|
2020-03-04 15:02:59 +01:00
|
|
|
front = q.front;
|
|
|
|
|
rear = q.rear;
|
2019-06-05 17:52:22 +02:00
|
|
|
seq = q.seq
|
2020-03-04 15:02:59 +01:00
|
|
|
}
|
2019-06-05 17:52:22 +02:00
|
|
|
|
|
|
|
|
let is_empty (q: t 'a)
|
2019-06-05 18:01:49 +02:00
|
|
|
ensures { result <-> q == empty }
|
2019-06-05 17:52:22 +02:00
|
|
|
=
|
|
|
|
|
match q.front, q.rear with
|
|
|
|
|
| Nil, Nil -> true
|
|
|
|
|
| _ -> false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let length (q: t 'a) : Peano.t
|
|
|
|
|
ensures { result = Seq.length q.seq }
|
|
|
|
|
=
|
|
|
|
|
let rec length_aux (acc: Peano.t) (l: list 'a) : Peano.t
|
|
|
|
|
ensures { result = acc + Length.length l }
|
|
|
|
|
variant { l }
|
|
|
|
|
= match l with
|
|
|
|
|
| Nil -> acc
|
|
|
|
|
| Cons _ s -> length_aux (Peano.succ acc) s
|
|
|
|
|
end in
|
|
|
|
|
length_aux (length_aux Peano.zero q.front) q.rear
|
|
|
|
|
|
|
|
|
|
let transfer (q1: t 'a) (q2: t 'a) : unit
|
2020-03-13 17:00:37 +01:00
|
|
|
writes { q1, q2 }
|
2019-06-05 17:52:22 +02:00
|
|
|
ensures { q1 = empty }
|
|
|
|
|
ensures { q2 = (old q2) ++ (old q1) }
|
2020-03-13 17:00:37 +01:00
|
|
|
= match q2.rear with
|
|
|
|
|
| Nil ->
|
|
|
|
|
q2.front, q2.rear, q2.seq <- q1.front, q1.rear, q1.seq
|
|
|
|
|
| _ ->
|
|
|
|
|
q2.front <- Append.(++) q1.front (Append.(++) (reverse q1.rear) q2.front);
|
|
|
|
|
q2.seq <- q2.seq ++ q1.seq;
|
|
|
|
|
end;
|
2019-06-05 17:52:22 +02:00
|
|
|
clear q1
|
|
|
|
|
|
|
|
|
|
end
|
2019-06-05 18:01:49 +02:00
|
|
|
|
|
|
|
|
(** the module above is a valid implementation of queue.Queue *)
|
|
|
|
|
module Correct
|
|
|
|
|
use Queue as Q
|
|
|
|
|
clone queue.Queue with
|
2020-03-13 17:00:37 +01:00
|
|
|
type t = Q.t, exception Empty = Q.Empty,
|
2019-06-05 18:01:49 +02:00
|
|
|
val create = Q.create, val push = Q.push, val pop = Q.pop, val peek = Q.peek,
|
|
|
|
|
val safe_pop = Q.safe_pop, val safe_peek = Q.safe_peek,
|
|
|
|
|
val clear = Q.clear, val copy = Q.copy, val is_empty = Q.is_empty,
|
2020-03-13 17:00:19 +01:00
|
|
|
val length = Q.length, val transfer = Q.transfer
|
2020-03-13 17:00:37 +01:00
|
|
|
end
|