Files
why3/stdlib/python.mlw
2022-11-14 14:58:24 +01:00

174 lines
5.3 KiB
Plaintext

module Python
use int.Int
use ref.Ref
use seq.Seq
use int.EuclideanDivision as E
type list 'a = private {
mutable elts: seq 'a;
mutable len: int;
} invariant { len = length elts }
meta coercion function elts
function ([]) (l: list 'a) (i: int) : 'a
= [@inline:trivial]
if i >= 0 then Seq.(l[i]) else Seq.(l[l.len + i])
val ghost function create (s: seq 'a) : list 'a
ensures { result = s }
ensures { len result = length s }
function ([<-]) (l: list 'a) (i: int) (v: 'a) : list 'a
= [@inline:trivial]
create (if i >= 0 then Seq.(l.elts[i <- v]) else Seq.(l.elts[l.len + i <- v]))
let ([]) (l: list 'a) (i: int) : 'a
requires { [@expl:index in array bounds] -len l <= i < len l }
ensures { result = l[i] }
= if i >= 0 then Seq.(l.elts[i]) else Seq.(l.elts[len l + i])
val ([]<-) (l: list 'a) (i: int) (v: 'a) : unit
requires { [@expl:index in array bounds] -len l <= i < len l }
writes { l.elts }
ensures { l.elts = (old l)[i <- v].elts }
val empty () : list 'a
ensures { result = Seq.empty }
val make (n: int) (v: 'a) : list 'a
requires { n >= 0 }
ensures { len result = n }
ensures { forall i. -n <= i < n -> result[i] = v }
(* ad-hoc facts about exchange *)
use seq.Occ
function occurrence (v: 'a) (l: list 'a) (lo hi: int): int =
Occ.occ v l lo hi
use int.Abs
(* Python's division and modulus according are neither Euclidean division,
nor computer division, but something else defined in
https://docs.python.org/3/reference/expressions.html *)
function (//) (x y: int) : int =
let q = E.div x y in
if y >= 0 then q else if E.mod x y > 0 then q-1 else q
function (%) (x y: int) : int =
let r = E.mod x y in
if y >= 0 then r else if r > 0 then r+y else r
lemma div_mod:
forall x y:int. y <> 0 -> x = y * (x // y) + (x % y)
lemma mod_bounds:
forall x y:int. y <> 0 -> 0 <= abs (x % y) < abs y
lemma mod_sign:
forall x y:int. y <> 0 -> if y < 0 then x % y <= 0 else x % y >= 0
val (//) (x y: int) : int
requires { [@expl:check division by zero] y <> 0 }
ensures { result = x // y }
val (%) (x y: int) : int
requires { [@expl:check division by zero] y <> 0 }
ensures { result = x % y }
(* random.randint *)
val randint (l u: int) : int
requires { [@expl:valid range] l <= u }
ensures { l <= result <= u }
use int.Power
function pow (x y: int) : int = power x y
val input () : int
val int (n: int) : int
ensures { result = n }
(* ajouts réalisés *)
val range (lo hi: int) : list int
requires { [@expl:valid range] lo <= hi }
ensures { len result = hi - lo }
ensures { forall i. 0 <= i < hi - lo -> result[i] = i + lo }
let range3 (le ri step: int) : list int
requires { [@expl:valid range] (le <= ri /\ step > 0) \/ (ri <= le /\ step < 0) }
ensures { len result = E.div (ri - le) step + if E.mod (ri - le) step <> 0 then 1 else 0 }
ensures { forall i. 0 <= i < len result -> result[i] = le + i * step }
= let n = E.div (ri - le) step + if E.mod (ri - le) step <> 0 then 1 else 0 in
let a = make n 0 in
for i=0 to n-1 do
invariant { forall j. 0 <= j < i -> a[j] = le + j * step }
a[i] <- le + i * step;
done;
assert { step > 0 -> le + n * step >= ri
/\ step > 0 -> le + (n-1) * step < ri
/\ step < 0 -> le + n * step <= ri
/\ step < 0 -> le + (n-1) * step > ri };
return a
val pop (l: list 'a) : 'a
requires { len l > 0 }
writes { l }
ensures { len l = len (old l) - 1 }
ensures { result = (old l)[len l] }
ensures { forall i. 0 <= i < len l -> l[i] = (old l)[i] }
val append (l: list 'a) (v: 'a) : unit
writes { l }
ensures { len l = len (old l) + 1 }
ensures { l[len (old l)] = v }
ensures { forall i. 0 <= i < len (old l) -> l[i] = (old l)[i] }
val function add_list (a1: list 'a) (a2: list 'a) : list 'a
ensures { len result = len a1 + len a2 }
ensures { forall i. 0 <= i < len a1 -> result[i] = a1[i] }
ensures { forall i. len a1 <= i < len result -> result[i] = a2[i-len a1] }
function transform_idx (l: list 'a) (i: int): int
= [@inline:trivial]
if i < 0 then len l + i else i
val function slice (l: list 'a) (lo hi: int) : list 'a
requires { transform_idx l lo >= 0 }
requires { transform_idx l hi <= len l }
requires { transform_idx l lo <= transform_idx l hi }
ensures { len result = transform_idx l hi - transform_idx l lo }
ensures { forall i. 0 <= i < len result -> result[i] = l[transform_idx l lo + i] }
val clear (l : list 'a) : unit
writes { l }
ensures { len l = 0 }
val copy (l: list 'a): list 'a
ensures { len result = len l }
ensures { result.elts = l.elts }
use seq.Permut
predicate is_permutation (l1 l2: list 'a)
= ([@expl:equality of length] length l1 = length l2)
/\ ([@expl:equality of elements] permut l1 l2 0 (length l2))
val sort (l : list int) : unit
writes { l.elts }
ensures { is_permutation l (old l) }
ensures { forall i, j. 0 <= i <= j < len(l) -> l[i] <= l[j] }
val reverse (l: list 'a) : unit
writes { l.elts }
ensures { len l = len (old l) }
ensures { forall i. 0 <= i < len l -> l[i] = (old l)[-(i+1)] }
ensures { forall i. 0 <= i < len l -> (old l)[i] = l[-(i+1)] }
ensures { is_permutation l (old l) }
end