mirror of
https://github.com/AdaCore/why3.git
synced 2026-02-12 12:34:55 -08:00
210 lines
5.3 KiB
Plaintext
210 lines
5.3 KiB
Plaintext
(** {1 Priority queues} *)
|
|
|
|
(** {2 Polymorphic mutable priority queues} *)
|
|
|
|
module Pqueue
|
|
|
|
(** {3 Types} *)
|
|
|
|
type elt
|
|
(** the abstract type of elements *)
|
|
|
|
predicate le elt elt
|
|
(** `elt` is equipped with a total pre order `le` *)
|
|
|
|
clone export relations.TotalPreOrder
|
|
with type t = elt, predicate rel = le, axiom .
|
|
|
|
use int.Int
|
|
use seq.Seq
|
|
use seq.Occ
|
|
|
|
(** the priority queue is modeled as a sorted sequence of elements *)
|
|
type t = abstract { mutable elts: seq elt }
|
|
invariant { forall i1 i2.
|
|
0 <= i1 <= i2 < length elts -> le elts[i1] elts[i2] }
|
|
meta coercion function elts
|
|
|
|
(** {3 Operations} *)
|
|
|
|
val create () : t ensures { result = empty }
|
|
(** create a fresh, empty queue *)
|
|
|
|
val push (x: elt) (q: t) : unit
|
|
writes { q }
|
|
ensures { length q = 1 + length (old q) }
|
|
ensures { occ_all x q = 1 + occ_all x (old q) }
|
|
ensures { forall y. y <> x -> occ_all y q = occ_all y (old q) }
|
|
(** push an element in a queue *)
|
|
|
|
exception Empty
|
|
(** exception raised by `pop` and `peek` to signal an empty queue *)
|
|
|
|
val pop (q: t) : elt
|
|
writes {q}
|
|
ensures { length (old q) > 0 }
|
|
ensures { result = (old q)[0] }
|
|
ensures { q = (old q)[1..] }
|
|
raises { Empty -> q = old q = empty }
|
|
(** remove and return the minimal element *)
|
|
|
|
val safe_pop (q: t) : elt
|
|
requires { length q > 0 }
|
|
writes { q }
|
|
ensures { result = (old q)[0] }
|
|
ensures { q = (old q)[1..] }
|
|
(** remove and return the minimal element *)
|
|
|
|
val peek (q: t) : elt
|
|
ensures { length q > 0 }
|
|
ensures { result = q[0] }
|
|
raises { Empty -> q = empty }
|
|
(** return the minimal element, without modifying the queue *)
|
|
|
|
val safe_peek (q: t) : elt
|
|
requires { length q > 0 }
|
|
ensures { result = q[0] }
|
|
(** return the minimal element, without modifying the queue *)
|
|
|
|
val clear (q: t) : unit
|
|
writes { q }
|
|
ensures { q = empty }
|
|
(** empty the queue *)
|
|
|
|
val copy (q: t) : t
|
|
ensures { result == q }
|
|
(** return a fresh copy of the queue *)
|
|
|
|
val is_empty (q: t) : bool
|
|
ensures { result <-> q = empty }
|
|
(** check whether the queue is empty *)
|
|
|
|
val length (q: t) : int
|
|
ensures { result = length q }
|
|
(** return the number of elements in the queue *)
|
|
|
|
end
|
|
|
|
(** Test the interface above using an external heapsort *)
|
|
module Harness
|
|
|
|
use int.Int
|
|
use array.Array
|
|
use array.IntArraySorted
|
|
use array.ArrayPermut
|
|
use map.Occ as MO
|
|
use seq.Seq
|
|
use seq.FreeMonoid
|
|
use seq.Occ as SO
|
|
|
|
clone Pqueue as PQ with type elt = int, predicate le = (<=)
|
|
|
|
let heapsort (a: array int) : unit
|
|
ensures { sorted a }
|
|
ensures { permut_all (old a) a }
|
|
= let n = length a in
|
|
let pq = PQ.create () in
|
|
for i = 0 to n - 1 do
|
|
invariant { length pq = i }
|
|
invariant { forall x. MO.occ x a.elts 0 n =
|
|
MO.occ x a.elts i n + SO.occ_all x pq }
|
|
PQ.push (Array.([]) a i) pq
|
|
done;
|
|
for i = 0 to n - 1 do
|
|
invariant { length pq = n - i }
|
|
invariant { sorted_sub a 0 i }
|
|
invariant { forall j k. 0 <= j < i -> 0 <= k < length pq ->
|
|
Array.([]) a j <= pq[k] }
|
|
invariant { forall x. MO.occ x (old a.elts) 0 n =
|
|
MO.occ x a.elts 0 i + SO.occ_all x pq }
|
|
a[i] <- PQ.safe_pop pq
|
|
done
|
|
|
|
end
|
|
|
|
(** {2 Simpler interface}
|
|
|
|
when duplicate elements are not allowed
|
|
|
|
*)
|
|
|
|
module PqueueNoDup
|
|
|
|
(** {3 Types} *)
|
|
|
|
type elt
|
|
(** the abstract type of elements *)
|
|
|
|
predicate le elt elt
|
|
(** `elt` is equipped with a total pre order `le` *)
|
|
|
|
clone export relations.TotalPreOrder
|
|
with type t = elt, predicate rel = le, axiom .
|
|
|
|
use set.Fset
|
|
|
|
type t = abstract { mutable elts: fset elt }
|
|
(** the priority queue is modeled as a finite set of elements *)
|
|
meta coercion function elts
|
|
|
|
(** {3 Operations} *)
|
|
|
|
val create () : t
|
|
ensures { result = empty }
|
|
(** create a fresh, empty queue *)
|
|
|
|
val push (x: elt) (q: t) : unit
|
|
writes { q }
|
|
ensures { q = add x (old q) }
|
|
(** push an element in a queue *)
|
|
|
|
exception Empty
|
|
(** exception raised by `pop` and `peek` to signal an empty queue *)
|
|
|
|
predicate minimal_elt (x: elt) (s: fset elt) =
|
|
mem x s /\ forall e: elt. mem e s -> le x e
|
|
(** property of the element returned by `pop` and `peek` *)
|
|
|
|
val pop (q: t) : elt
|
|
writes { q }
|
|
ensures { q = remove result (old q) }
|
|
ensures { minimal_elt result (old q) }
|
|
raises { Empty -> q = old q = empty }
|
|
(** remove and returns the minimal element *)
|
|
|
|
val safe_pop (q: t) : elt
|
|
writes { q }
|
|
requires { not q = empty }
|
|
ensures { q = remove result (old q) }
|
|
ensures { minimal_elt result (old q) }
|
|
(** remove and returns the minimal element *)
|
|
|
|
val peek (q: t) : elt
|
|
ensures { minimal_elt result q }
|
|
raises { Empty -> q = empty }
|
|
(** return the minimal element, without modifying the queue *)
|
|
|
|
val safe_peek (q: t) : elt
|
|
requires { not q = empty }
|
|
ensures { minimal_elt result q }
|
|
(** return the minimal element, without modifying the queue *)
|
|
|
|
val clear (q: t) : unit
|
|
writes { q }
|
|
ensures { q = empty }
|
|
(** empty the queue *)
|
|
|
|
val copy (q: t) : t
|
|
ensures { result = q }
|
|
(** return a fresh copy of the queue *)
|
|
|
|
val is_empty (q: t) : bool
|
|
ensures { result <-> q = empty }
|
|
(** check whether the queue is empty *)
|
|
|
|
val length (q: t) : int
|
|
ensures { result = cardinal q }
|
|
(** return the number of elements in the queue *)
|
|
|
|
end
|