mirror of
https://github.com/AdaCore/why3.git
synced 2026-02-12 12:34:55 -08:00
220 lines
5.3 KiB
Plaintext
220 lines
5.3 KiB
Plaintext
|
|
(** {1 Cursors}
|
|
|
|
Some implementations and clients of module `cursor.Cursor`
|
|
from the standard library.
|
|
|
|
Author: Mário Pereira (Université Paris Sud) *)
|
|
|
|
module TestCursor
|
|
|
|
use int.Int
|
|
use int.Sum
|
|
use seq.Seq
|
|
use ref.Refint
|
|
|
|
use cursor.Cursor
|
|
|
|
(** sums all the remaining elements in the cursor *)
|
|
let sum (c: cursor int) : int
|
|
requires { permitted c }
|
|
requires { c.visited = empty }
|
|
ensures { result = sum (get c.visited) 0 (length c.visited) }
|
|
diverges
|
|
= let s = ref 0 in
|
|
while has_next c do
|
|
invariant { permitted c }
|
|
invariant { !s = sum (get c.visited) 0 (length c.visited) }
|
|
let x = next c in
|
|
s += x
|
|
done;
|
|
!s
|
|
|
|
end
|
|
|
|
(** {2 Iteration over an immuable collection}
|
|
|
|
here we choose a list *)
|
|
|
|
module ListCursorImpl : cursor.ListCursor
|
|
|
|
use int.Int
|
|
use list.List
|
|
use seq.Seq
|
|
use seq.OfList
|
|
|
|
type cursor 'a = {
|
|
mutable ghost visited : seq 'a;
|
|
ghost collection : list 'a;
|
|
mutable to_visit : list 'a;
|
|
} invariant { visited ++ to_visit = collection }
|
|
by { visited = empty; collection = Nil; to_visit = Nil }
|
|
|
|
predicate permitted (c: cursor 'a) =
|
|
length c.visited <= length c.collection /\
|
|
forall i. 0 <= i < length c.visited -> c.visited[i] = c.collection[i]
|
|
|
|
predicate complete (c: cursor 'a) =
|
|
length c.visited = length c.collection
|
|
|
|
let lemma snoc_Cons (s: seq 'a) (l: list 'a) (x: 'a)
|
|
ensures { snoc s x ++ l == s ++ Cons x l }
|
|
= ()
|
|
|
|
scope C
|
|
|
|
let next (c: cursor 'a) : 'a
|
|
requires { not (complete c) }
|
|
writes { c }
|
|
ensures { c.visited = snoc (old c).visited result }
|
|
ensures { match (old c).to_visit with
|
|
| Nil -> false
|
|
| Cons x r -> c.to_visit = r /\ x = result
|
|
end }
|
|
= match c.to_visit with
|
|
| Nil -> absurd
|
|
| Cons x r ->
|
|
let ghost v0 = c.visited in
|
|
c.visited <- snoc c.visited x; c.to_visit <- r;
|
|
snoc_Cons v0 r x;
|
|
assert { c.to_visit == c.collection [length c.visited ..] };
|
|
x
|
|
end
|
|
|
|
let has_next (c: cursor 'a) : bool
|
|
ensures { result <-> not (complete c) }
|
|
= match c.to_visit with (* could define a [val eq (l1 l2: list 'a) : bool] *)
|
|
| Nil -> false
|
|
| _ -> true
|
|
end
|
|
|
|
end
|
|
|
|
let create (t: list 'a) : cursor 'a
|
|
ensures { result.visited = empty }
|
|
ensures { result.collection = t }
|
|
ensures { result.to_visit = t }
|
|
= { visited = empty; collection = t; to_visit = t }
|
|
|
|
end
|
|
|
|
module TestListCursor
|
|
|
|
use int.Int
|
|
use int.Sum as S
|
|
use list.List
|
|
use list.Length
|
|
use list.Sum
|
|
use ref.Refint
|
|
use seq.Seq
|
|
use seq.OfList
|
|
|
|
use ListCursorImpl
|
|
|
|
lemma sum_of_list: forall l: list int.
|
|
sum l = S.sum (get (of_list l)) 0 (length l)
|
|
|
|
let list_sum (l: list int) : int
|
|
ensures { result = sum l }
|
|
= let s = ref 0 in
|
|
let c = create l in
|
|
while C.has_next c do
|
|
invariant { !s = S.sum (get c.visited) 0 (length c.visited) }
|
|
invariant { permitted c }
|
|
variant { length l - length c.visited }
|
|
let x = C.next c in
|
|
s += x
|
|
done;
|
|
!s
|
|
|
|
end
|
|
|
|
(** {2 Iteration over a mutable collection}
|
|
|
|
here we choose an array of integers *)
|
|
|
|
module ArrayCursorImpl : cursor.ArrayCursor
|
|
|
|
use int.Int
|
|
use array.Array
|
|
use array.ToSeq
|
|
use list.List
|
|
use list.Reverse
|
|
use array.ToList
|
|
use seq.Seq
|
|
|
|
type cursor 'a = {
|
|
mutable ghost visited : seq 'a;
|
|
collection : seq 'a; (* FIXME : extraction of seq *)
|
|
mutable index : int; (** index of next element *)
|
|
} invariant { 0 <= index <= length collection /\
|
|
index = length visited /\
|
|
forall i. 0 <= i < index -> collection[i] = visited[i] }
|
|
by { visited = empty; collection = empty; index = 0 }
|
|
|
|
predicate permitted (c: cursor 'a) =
|
|
length c.visited <= length c.collection /\
|
|
forall i. 0 <= i < length c.visited -> c.visited[i] = c.collection[i]
|
|
|
|
predicate complete (c: cursor 'a) =
|
|
length c.visited = length c.collection
|
|
|
|
let create (a: array 'a) : cursor 'a
|
|
ensures { result.visited = empty }
|
|
ensures { result.index = 0 }
|
|
ensures { result.collection = to_seq a }
|
|
= { visited = empty; collection = to_seq a; index = 0; }
|
|
|
|
scope C
|
|
|
|
let has_next (c: cursor 'a) : bool
|
|
ensures { result <-> not (complete c) }
|
|
= c.index < length c.collection
|
|
|
|
let next (c: cursor 'a) : 'a
|
|
requires { not (complete c) }
|
|
writes { c }
|
|
ensures { c.visited = snoc (old c).visited result }
|
|
ensures { c.index = (old c).index + 1 }
|
|
= if c.index >= length c.collection then absurd
|
|
else begin let x = c.collection[c.index] in
|
|
c.visited <- snoc c.visited x;
|
|
c.index <- c.index + 1;
|
|
x end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
module TestArrayCursor
|
|
|
|
use int.Int
|
|
use array.Array
|
|
use array.ToSeq
|
|
use seq.Seq
|
|
use int.Sum
|
|
use ref.Refint
|
|
|
|
use ArrayCursorImpl
|
|
|
|
let array_sum (a: array int) : int
|
|
ensures { result = sum (Array.([]) a) 0 (length a) }
|
|
= let s = ref 0 in
|
|
let c = create a in
|
|
while C.has_next c do
|
|
invariant { !s = sum (get c.visited) 0 (length c.visited) }
|
|
invariant { permitted c }
|
|
variant { length c.collection - length c.visited }
|
|
let x = C.next c in
|
|
s += x
|
|
done;
|
|
!s
|
|
|
|
let harness1 () : unit
|
|
= let a = Array.make 42 0 in
|
|
let c = create a in
|
|
let x = C.next c in
|
|
assert { x = 0 }
|
|
|
|
end
|