2016-06-09 17:30:09 +02:00
|
|
|
|
|
|
|
|
(** Flexible arrays
|
|
|
|
|
|
|
|
|
|
Flexible arrays are arrays whose size can be changed by adding or
|
|
|
|
|
removing elements at either end (one at a time).
|
|
|
|
|
|
|
|
|
|
This is an implementation of flexible arrays using Braun trees,
|
|
|
|
|
following
|
|
|
|
|
|
|
|
|
|
Rob Hoogerwoord
|
|
|
|
|
A logarithmic implementation of flexible arrays
|
|
|
|
|
http://alexandria.tue.nl/repository/notdare/772185.pdf
|
|
|
|
|
|
|
|
|
|
All operations (get, set, le, lr, he, hr) have logarithmic complexity.
|
|
|
|
|
|
|
|
|
|
Note: Braun trees can also be used to implement priority queues.
|
|
|
|
|
See braun_trees.mlw. This file also contains a proof that Braun
|
|
|
|
|
trees have logarithmic height.
|
|
|
|
|
|
|
|
|
|
Author: Jean-Christophe Filliâtre (CNRS)
|
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
module FlexibleArray
|
|
|
|
|
|
2018-06-15 16:45:31 +02:00
|
|
|
use int.Int
|
|
|
|
|
use int.ComputerDivision
|
|
|
|
|
use bintree.Tree
|
2016-06-09 17:30:09 +02:00
|
|
|
use export bintree.Size
|
2018-06-15 16:45:31 +02:00
|
|
|
use ref.Ref
|
2016-06-23 10:00:04 +02:00
|
|
|
use import seq.Seq as S
|
|
|
|
|
use import queue.Queue as Q
|
2018-06-15 16:45:31 +02:00
|
|
|
use list.List
|
2019-06-05 18:17:17 +02:00
|
|
|
use seq.Mem
|
2016-06-09 17:30:09 +02:00
|
|
|
|
|
|
|
|
(* to be a Braun tree *)
|
|
|
|
|
predicate inv (t: tree 'a) = match t with
|
|
|
|
|
| Empty -> true
|
|
|
|
|
| Node l _ r -> (size l = size r || size l = size r + 1) && inv l && inv r
|
|
|
|
|
end
|
|
|
|
|
|
2016-06-12 12:06:02 +02:00
|
|
|
type t 'a = {
|
|
|
|
|
length: int;
|
|
|
|
|
tree: tree 'a;
|
|
|
|
|
} invariant {
|
|
|
|
|
length = size tree && inv tree
|
|
|
|
|
}
|
2016-06-09 17:30:09 +02:00
|
|
|
|
2016-06-12 12:06:02 +02:00
|
|
|
let empty () : t 'a
|
|
|
|
|
ensures { result.length = 0 }
|
|
|
|
|
= { length = 0; tree = Empty }
|
|
|
|
|
|
|
|
|
|
let is_empty (t: t 'a) : bool
|
|
|
|
|
ensures { result <-> t.length = 0 }
|
2016-06-09 17:30:09 +02:00
|
|
|
=
|
2016-06-12 12:06:02 +02:00
|
|
|
t.length = 0
|
2016-06-09 17:30:09 +02:00
|
|
|
|
2016-06-12 12:06:02 +02:00
|
|
|
let rec function get_aux (t: tree 'a) (i: int) : 'a
|
2016-06-09 17:30:09 +02:00
|
|
|
requires { 0 <= i < size t }
|
|
|
|
|
requires { inv t }
|
|
|
|
|
variant { t }
|
|
|
|
|
= match t with
|
|
|
|
|
| Empty -> absurd
|
|
|
|
|
| Node l x r ->
|
|
|
|
|
if i = 0 then x
|
2016-06-12 12:06:02 +02:00
|
|
|
else if mod i 2 = 1 then get_aux l (div i 2) else get_aux r (div i 2 - 1)
|
2016-06-09 17:30:09 +02:00
|
|
|
end
|
|
|
|
|
|
2016-06-12 12:06:02 +02:00
|
|
|
let function get (t: t 'a) (i: int) : 'a
|
|
|
|
|
requires { 0 <= i < t.length }
|
|
|
|
|
= get_aux t.tree i
|
|
|
|
|
|
|
|
|
|
let rec set_aux (t: tree 'a) (i: int) (v: 'a) : tree 'a
|
2016-06-09 17:30:09 +02:00
|
|
|
requires { 0 <= i < size t }
|
|
|
|
|
requires { inv t }
|
|
|
|
|
variant { t }
|
|
|
|
|
ensures { inv result }
|
|
|
|
|
ensures { size result = size t }
|
2016-06-12 12:06:02 +02:00
|
|
|
ensures { forall j. 0 <= j < size t -> j <> i ->
|
|
|
|
|
get_aux result j = get_aux t j }
|
|
|
|
|
ensures { get_aux result i = v }
|
2016-06-09 17:30:09 +02:00
|
|
|
= match t with
|
|
|
|
|
| Empty -> absurd
|
|
|
|
|
| Node l x r ->
|
|
|
|
|
if i = 0 then Node l v r
|
2016-06-12 12:06:02 +02:00
|
|
|
else if mod i 2 = 1 then Node (set_aux l (div i 2) v) x r
|
|
|
|
|
else Node l x (set_aux r (div i 2 - 1) v)
|
2016-06-09 17:30:09 +02:00
|
|
|
end
|
|
|
|
|
|
2016-06-12 12:06:02 +02:00
|
|
|
let set (t: t 'a) (i: int) (v: 'a) : t 'a
|
|
|
|
|
requires { 0 <= i < t.length }
|
|
|
|
|
ensures { result.length = t.length }
|
|
|
|
|
ensures { forall j. 0 <= j < t.length -> j <> i -> get result j = get t j }
|
|
|
|
|
ensures { get result i = v }
|
|
|
|
|
= { length = t.length; tree = set_aux t.tree i v }
|
|
|
|
|
|
2016-06-09 17:30:09 +02:00
|
|
|
(* low extension *)
|
2016-06-12 12:06:02 +02:00
|
|
|
let rec le_aux (v: 'a) (t: tree 'a) : tree 'a
|
2016-06-09 17:30:09 +02:00
|
|
|
requires { inv t }
|
|
|
|
|
variant { t }
|
|
|
|
|
ensures { inv result }
|
|
|
|
|
ensures { size result = size t + 1 }
|
2016-06-12 12:06:02 +02:00
|
|
|
ensures { get_aux result 0 = v }
|
|
|
|
|
ensures { forall j. 0 <= j < size t ->
|
|
|
|
|
get_aux result (j + 1) = get_aux t j }
|
2016-06-09 17:30:09 +02:00
|
|
|
= match t with
|
|
|
|
|
| Empty -> Node Empty v Empty
|
2016-06-12 12:06:02 +02:00
|
|
|
| Node l x r -> Node (le_aux x r) v l
|
2016-06-09 17:30:09 +02:00
|
|
|
end
|
|
|
|
|
|
2016-06-12 12:06:02 +02:00
|
|
|
let rec le (v: 'a) (t: t 'a) : t 'a
|
|
|
|
|
ensures { result.length = t.length + 1 }
|
|
|
|
|
ensures { get result 0 = v }
|
|
|
|
|
ensures { forall j. 0 <= j < t.length -> get result (j + 1) = get t j }
|
|
|
|
|
= { length = t.length + 1; tree = le_aux v t.tree }
|
|
|
|
|
|
2016-06-09 17:30:09 +02:00
|
|
|
(* low removal *)
|
2016-06-12 12:06:02 +02:00
|
|
|
let rec lr_aux (t: tree 'a) : tree 'a
|
2016-06-09 17:30:09 +02:00
|
|
|
requires { inv t }
|
|
|
|
|
requires { size t > 0 }
|
|
|
|
|
variant { t }
|
|
|
|
|
ensures { inv result }
|
|
|
|
|
ensures { size result = size t - 1 }
|
2016-06-12 12:06:02 +02:00
|
|
|
ensures { forall j. 0 <= j < size result ->
|
|
|
|
|
get_aux result j = get_aux t (j + 1) }
|
2016-06-09 17:30:09 +02:00
|
|
|
= match t with
|
|
|
|
|
| Empty -> absurd
|
|
|
|
|
| Node Empty _ Empty -> Empty
|
2016-06-12 12:06:02 +02:00
|
|
|
| Node l _ r -> Node r (get_aux l 0) (lr_aux l)
|
2016-06-09 17:30:09 +02:00
|
|
|
end
|
|
|
|
|
|
2016-06-12 12:06:02 +02:00
|
|
|
let lr (t: t 'a) : t 'a
|
|
|
|
|
requires { t.length > 0 }
|
|
|
|
|
ensures { result.length = t.length - 1 }
|
|
|
|
|
ensures { forall j. 0 <= j < result.length ->
|
|
|
|
|
get result j = get t (j + 1) }
|
|
|
|
|
= { length = t.length - 1; tree = lr_aux t.tree }
|
|
|
|
|
|
2016-06-09 17:30:09 +02:00
|
|
|
(* high extension *)
|
|
|
|
|
let rec he_aux (s: int) (t: tree 'a) (v: 'a) : tree 'a
|
|
|
|
|
requires { inv t }
|
|
|
|
|
requires { s = size t }
|
|
|
|
|
variant { t }
|
|
|
|
|
ensures { inv result }
|
|
|
|
|
ensures { size result = size t + 1 }
|
2016-06-12 12:06:02 +02:00
|
|
|
ensures { get_aux result (size t) = v }
|
|
|
|
|
ensures { forall j. 0 <= j < size t -> get_aux result j = get_aux t j }
|
2016-06-09 17:30:09 +02:00
|
|
|
= match t with
|
|
|
|
|
| Empty -> Node Empty v Empty
|
|
|
|
|
| Node l x r -> if mod s 2 = 1 then Node (he_aux (div s 2) l v) x r
|
|
|
|
|
else Node l x (he_aux (div s 2 - 1) r v)
|
|
|
|
|
end
|
|
|
|
|
|
2016-06-12 12:06:02 +02:00
|
|
|
let he (t: t 'a) (v: 'a) : t 'a
|
|
|
|
|
ensures { result.length = t.length + 1 }
|
|
|
|
|
ensures { get result t.length = v }
|
|
|
|
|
ensures { forall j. 0 <= j < t.length -> get result j = get t j }
|
2016-06-09 17:30:09 +02:00
|
|
|
=
|
2016-06-12 12:06:02 +02:00
|
|
|
{ length = t.length + 1; tree = he_aux t.length t.tree v }
|
2016-06-09 17:30:09 +02:00
|
|
|
|
|
|
|
|
(* high removal *)
|
|
|
|
|
let rec hr_aux (s: int) (t: tree 'a) : tree 'a
|
|
|
|
|
requires { inv t }
|
|
|
|
|
requires { s = size t > 0 }
|
|
|
|
|
variant { t }
|
|
|
|
|
ensures { inv result }
|
|
|
|
|
ensures { size result = size t - 1 }
|
2016-06-12 12:06:02 +02:00
|
|
|
ensures { forall j. 0 <= j < size result ->
|
|
|
|
|
get_aux result j = get_aux t j }
|
2016-06-09 17:30:09 +02:00
|
|
|
= match t with
|
|
|
|
|
| Empty -> absurd
|
|
|
|
|
| Node Empty _ Empty -> Empty
|
|
|
|
|
| Node l x r -> if mod s 2 = 0 then Node (hr_aux (div s 2) l) x r
|
|
|
|
|
else Node l x (hr_aux (div s 2) r)
|
|
|
|
|
end
|
|
|
|
|
|
2016-06-12 12:06:02 +02:00
|
|
|
let hr (t: t 'a) : t 'a
|
|
|
|
|
requires { t.length > 0 }
|
|
|
|
|
ensures { result.length = t.length - 1 }
|
|
|
|
|
ensures { forall j. 0 <= j < result.length -> get result j = get t j }
|
2016-06-09 17:30:09 +02:00
|
|
|
=
|
2016-06-12 12:06:02 +02:00
|
|
|
{ length = t.length - 1; tree = hr_aux t.length t.tree }
|
2016-06-09 17:30:09 +02:00
|
|
|
|
2016-07-01 12:08:41 +02:00
|
|
|
(* the sequence of elements, in order *)
|
|
|
|
|
|
|
|
|
|
function interleave (x y: seq 'a) : seq 'a =
|
|
|
|
|
S.create
|
|
|
|
|
(S.length x + S.length y)
|
|
|
|
|
(fun i -> if mod i 2 = 0 then x[div i 2] else y[div i 2])
|
|
|
|
|
|
|
|
|
|
function elements_aux (t: tree 'a): seq 'a =
|
|
|
|
|
match t with
|
|
|
|
|
| Empty -> S.empty
|
|
|
|
|
| Node l x r -> cons x (interleave (elements_aux l) (elements_aux r))
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let rec lemma elements_aux_length (t: tree 'a)
|
|
|
|
|
variant { t }
|
|
|
|
|
ensures { S.length (elements_aux t) = size t }
|
|
|
|
|
= match t with
|
|
|
|
|
| Empty -> ()
|
|
|
|
|
| Node l _ r -> elements_aux_length l; elements_aux_length r
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let rec lemma elements_aux_correct (t: tree 'a) (i: int)
|
|
|
|
|
requires { 0 <= i < size t }
|
|
|
|
|
requires { inv t }
|
|
|
|
|
variant { t }
|
|
|
|
|
ensures { (elements_aux t)[i] = get_aux t i }
|
|
|
|
|
= match t with
|
|
|
|
|
| Empty -> ()
|
|
|
|
|
| Node l _ r ->
|
|
|
|
|
elements_aux_length l; elements_aux_length r;
|
|
|
|
|
if i = 0 then () else
|
|
|
|
|
if mod i 2 = 1 then elements_aux_correct l (div i 2)
|
|
|
|
|
else elements_aux_correct r (div i 2 - 1)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function elements (a: t 'a) : seq 'a =
|
|
|
|
|
elements_aux a.tree
|
|
|
|
|
|
|
|
|
|
lemma elements_correct:
|
|
|
|
|
forall a: t 'a.
|
|
|
|
|
S.length (elements a) = a.length /\
|
|
|
|
|
forall i. 0 <= i < a.length -> (elements a)[i] = get a i
|
|
|
|
|
|
|
|
|
|
(* traversing the elements, in order, in linear time *)
|
2016-06-23 10:00:04 +02:00
|
|
|
|
2016-07-01 11:08:10 +02:00
|
|
|
let non_empty (t: tree 'a) : bool
|
|
|
|
|
ensures { result <-> t <> Empty }
|
|
|
|
|
= match t with
|
|
|
|
|
| Empty -> false
|
|
|
|
|
| Node _ _ _ -> true
|
|
|
|
|
end
|
2016-06-23 10:00:04 +02:00
|
|
|
|
2019-06-05 18:17:17 +02:00
|
|
|
use int.Sum
|
2016-07-01 11:08:10 +02:00
|
|
|
|
2019-06-05 18:17:17 +02:00
|
|
|
function size_list (l: seq (tree 'a)) : int =
|
|
|
|
|
sum (fun i -> size l[i]) 0 (Seq.length l)
|
|
|
|
|
|
|
|
|
|
let lemma size_list_nonneg (l: seq (tree 'a)) : unit
|
2016-07-01 11:08:10 +02:00
|
|
|
ensures { size_list l >= 0 }
|
2019-06-05 18:17:17 +02:00
|
|
|
= ()(* match l with Nil -> () | Cons _ s -> size_list_nonneg s end *)
|
2016-07-01 11:08:10 +02:00
|
|
|
|
2019-06-05 18:17:17 +02:00
|
|
|
let lemma size_list_append (l1 l2: seq (tree 'a)) : unit
|
2016-07-01 11:08:10 +02:00
|
|
|
ensures { size_list (l1 ++ l2) = size_list l1 + size_list l2 }
|
2019-06-05 18:17:17 +02:00
|
|
|
= ()(* match l1 with Nil -> () | Cons _ s1 -> size_list_append s1 l2 end *)
|
2016-07-01 11:08:10 +02:00
|
|
|
|
|
|
|
|
lemma size_list_snoc:
|
2019-06-05 18:17:17 +02:00
|
|
|
forall l: seq (tree 'a), t: tree 'a.
|
|
|
|
|
size_list (l ++ cons t empty) = size_list l + size t
|
2016-07-01 11:08:10 +02:00
|
|
|
|
2016-07-01 12:08:41 +02:00
|
|
|
(* FIXME: In practice, such a function iter would have a visitor function
|
|
|
|
|
as argument. Here, we only intend to prove the soundness of such
|
|
|
|
|
an iteration. So we simply store the visited elements in a ghost
|
|
|
|
|
sequence and then prove at this end that this sequence is in order,
|
|
|
|
|
with an assertion. *)
|
|
|
|
|
|
2016-07-01 11:08:10 +02:00
|
|
|
let iter (a: t 'a) : unit =
|
2016-06-23 10:00:04 +02:00
|
|
|
let ghost visited = ref S.empty in
|
|
|
|
|
let q = Q.create () in
|
|
|
|
|
let left = Q.create () in
|
|
|
|
|
let right = Q.create () in
|
2016-07-01 11:08:10 +02:00
|
|
|
if non_empty a.tree then begin
|
|
|
|
|
Q.push a.tree q;
|
|
|
|
|
while not (Q.is_empty q) do
|
2019-06-05 18:17:17 +02:00
|
|
|
invariant { not (mem Empty q) }
|
|
|
|
|
invariant { not (mem Empty left) }
|
|
|
|
|
invariant { not (mem Empty right) }
|
|
|
|
|
invariant { S.length !visited + size_list q +
|
|
|
|
|
size_list left + size_list right = a.length }
|
2016-07-01 11:08:10 +02:00
|
|
|
invariant { forall i. 0 <= i < S.length !visited ->
|
|
|
|
|
!visited[i] = get a i }
|
2019-06-05 18:17:17 +02:00
|
|
|
invariant { S.length q = 0 -> S.length left = S.length right = 0 }
|
2016-07-01 11:08:10 +02:00
|
|
|
variant { a.length - S.length !visited }
|
|
|
|
|
let x = Q.safe_pop q in
|
|
|
|
|
match x with
|
|
|
|
|
| Empty -> absurd
|
|
|
|
|
| Node l y r ->
|
|
|
|
|
(* visit y here *)
|
|
|
|
|
ghost visited := snoc !visited y;
|
|
|
|
|
if non_empty l then Q.push l left;
|
|
|
|
|
if non_empty r then Q.push r right;
|
|
|
|
|
end;
|
|
|
|
|
if Q.is_empty q then begin
|
|
|
|
|
Q.transfer right left;
|
|
|
|
|
Q.transfer left q;
|
|
|
|
|
end
|
|
|
|
|
done
|
|
|
|
|
end;
|
|
|
|
|
assert { forall i. 0 <= i < a.length -> !visited[i] = get a i }
|
2016-06-23 10:00:04 +02:00
|
|
|
|
2016-06-09 17:30:09 +02:00
|
|
|
end
|