mirror of
https://github.com/AdaCore/why3.git
synced 2026-02-12 12:34:55 -08:00
187 lines
4.0 KiB
Plaintext
187 lines
4.0 KiB
Plaintext
|
|
(*
|
|
Snapshotable Trees
|
|
|
|
Formalized Verification of Snapshotable Trees: Separation and Sharing
|
|
Hannes Mehnert, Filip Sieczkowski, Lars Birkedal, and Peter Sestoft
|
|
VSTTE 2012
|
|
*)
|
|
|
|
(* Purely applicative binary trees with elements at the nodes *)
|
|
|
|
theory Tree
|
|
|
|
use export int.Int
|
|
use export list.List
|
|
use export list.Length
|
|
use export list.Append
|
|
|
|
type elt = int
|
|
|
|
type tree =
|
|
| Empty
|
|
| Node tree elt tree
|
|
|
|
function tree_elements (t: tree) : list elt = match t with
|
|
| Empty -> Nil
|
|
| Node l x r -> tree_elements l ++ Cons x (tree_elements r)
|
|
end
|
|
|
|
predicate mem (x: elt) (t: tree) = match t with
|
|
| Empty -> false
|
|
| Node l y r -> mem x l || x = y || mem x r
|
|
end
|
|
|
|
end
|
|
|
|
(* Purely applicative iterators over binary trees *)
|
|
|
|
module Enum
|
|
|
|
use Tree
|
|
|
|
type enum =
|
|
| Done
|
|
| Next elt tree enum
|
|
|
|
function enum_elements (e: enum) : list elt = match e with
|
|
| Done -> Nil
|
|
| Next x r e -> Cons x (tree_elements r ++ enum_elements e)
|
|
end
|
|
|
|
let rec enum t e variant {t}
|
|
ensures { enum_elements result = tree_elements t ++ enum_elements e }
|
|
= match t with
|
|
| Empty -> e
|
|
| Node l x r -> enum l (Next x r e)
|
|
end
|
|
|
|
end
|
|
|
|
(* Mutable iterators with a Java-like API *)
|
|
|
|
module Iterator
|
|
|
|
use Tree
|
|
use Enum
|
|
|
|
type iterator = { mutable it: enum }
|
|
|
|
function elements (i: iterator) : list elt = enum_elements i.it
|
|
|
|
let create_iterator (t: tree)
|
|
ensures { elements result = tree_elements t }
|
|
= { it = enum t Done }
|
|
|
|
predicate hasNext (i: iterator) = i.it <> Done
|
|
|
|
let hasNext (i: iterator)
|
|
ensures { result = True <-> hasNext i }
|
|
= match i.it with Done -> False | _ -> True end
|
|
|
|
let next (i: iterator)
|
|
requires { hasNext i }
|
|
ensures { old (elements i) = Cons result (elements i) }
|
|
= match i.it with
|
|
| Done -> absurd
|
|
| Next x r e -> i.it <- enum r e; x
|
|
end
|
|
|
|
end
|
|
|
|
(* Binary search trees *)
|
|
|
|
module BSTree
|
|
|
|
use export Tree
|
|
|
|
predicate lt_tree (x: elt) (t: tree) =
|
|
forall y: elt. mem y t -> y < x
|
|
|
|
predicate gt_tree (x: elt) (t: tree) =
|
|
forall y: elt. mem y t -> x < y
|
|
|
|
predicate bst (t: tree) =
|
|
match t with
|
|
| Empty -> true
|
|
| Node l x r -> bst l /\ bst r /\ lt_tree x l /\ gt_tree x r
|
|
end
|
|
|
|
let rec bst_mem (x: elt) (t: tree)
|
|
requires { bst t } ensures { result=True <-> mem x t } variant { t }
|
|
= match t with
|
|
| Empty ->
|
|
False
|
|
| Node l y r ->
|
|
if x < y then bst_mem x l else x = y || bst_mem x r
|
|
end
|
|
|
|
exception Already
|
|
(* bst_add raises exception Already when the element is already present *)
|
|
|
|
let rec bst_add (x: elt) (t: tree)
|
|
requires { bst t }
|
|
ensures { bst result /\ not (mem x t) /\
|
|
forall y: elt. mem y result <-> y=x || mem y t }
|
|
raises { Already -> mem x t }
|
|
variant { t }
|
|
= match t with
|
|
| Empty ->
|
|
Node Empty x Empty
|
|
| Node l y r ->
|
|
if x = y then raise Already;
|
|
if x < y then Node (bst_add x l) y r else Node l y (bst_add x r)
|
|
end
|
|
|
|
end
|
|
|
|
(* Imperative trees with add/contains/snapshot/iterator API *)
|
|
|
|
module ITree
|
|
|
|
use export BSTree
|
|
use export Iterator
|
|
|
|
type itree = { mutable tree: tree } invariant { bst tree }
|
|
|
|
let create () = { tree = Empty }
|
|
|
|
let contains (t: itree) (x: elt)
|
|
ensures { result=True <-> mem x t.tree }
|
|
= bst_mem x t.tree
|
|
|
|
let add (t: itree) (x: elt)
|
|
ensures { (result=False <-> mem x (old t.tree)) /\
|
|
forall y: elt. mem y t.tree <-> y=x || mem y (old t.tree) }
|
|
= try t.tree <- bst_add x t.tree; True with Already -> False end
|
|
|
|
let snapshot (t: itree) = { tree = t.tree }
|
|
|
|
let iterator (t: itree)
|
|
ensures { elements result = tree_elements t.tree }
|
|
= create_iterator t.tree
|
|
|
|
end
|
|
|
|
module Harness
|
|
|
|
use ITree
|
|
|
|
let test () =
|
|
let t = create () in
|
|
let _ = add t 1 in
|
|
let _ = add t 2 in
|
|
let _ = add t 3 in
|
|
assert { mem 2 t.tree };
|
|
let s = snapshot t in
|
|
let it = iterator s in
|
|
while hasNext it do
|
|
invariant { bst t.tree }
|
|
variant { length (elements it) }
|
|
let x = next it in
|
|
let _ = add t (x * 3) in
|
|
()
|
|
done
|
|
|
|
end
|