python: division and modulus, fixed for loop

parent 17487845
...@@ -34,11 +34,38 @@ module Python ...@@ -34,11 +34,38 @@ module Python
ensures { A.length result = u - l } ensures { A.length result = u - l }
ensures { forall i. l <= i < u -> result[i] = i } ensures { forall i. l <= i < u -> result[i] = i }
(* TODO: specify division and modulus according to (* 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 *) https://docs.python.org/3/reference/expressions.html *)
function div int int : int
function mod int int : int
use import int.Abs
use int.EuclideanDivision as E
function div (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 mod (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 * div x y + mod x y
lemma mod_bounds:
forall x y:int. y <> 0 -> 0 <= abs (mod x y) < abs y
lemma mod_sign:
forall x y:int. y <> 0 -> if y < 0 then mod x y <= 0 else mod x y >= 0
let (//) (x y: int) : int
requires { y <> 0 }
ensures { result = div x y }
= div x y
let (%) (x y: int) : int
requires { y <> 0 }
ensures { result = mod x y }
= mod x y
(* random.randint *)
val randint (l u: int) : int val randint (l u: int) : int
requires { l <= u } requires { l <= u }
ensures { l <= result <= u } ensures { l <= result <= u }
......
...@@ -50,7 +50,7 @@ and stmt_desc = ...@@ -50,7 +50,7 @@ and stmt_desc =
| Sassign of ident * expr | Sassign of ident * expr
| Sprint of expr | Sprint of expr
| Swhile of expr * Ptree.loop_annotation * block | Swhile of expr * Ptree.loop_annotation * block
| Sfor of ident * expr * Ptree.loop_annotation * block | Sfor of ident * expr * Ptree.invariant * block
| Seval of expr | Seval of expr
| Sset of expr * expr * expr (* e1[e2] = e3 *) | Sset of expr * expr * expr (* e1[e2] = e3 *)
| Sassert of Ptree.assertion_kind * Ptree.term | Sassert of Ptree.assertion_kind * Ptree.term
......
...@@ -123,7 +123,7 @@ let rec expr env {Py_ast.expr_loc = loc; Py_ast.expr_desc = d } = match d with ...@@ -123,7 +123,7 @@ let rec expr env {Py_ast.expr_loc = loc; Py_ast.expr_desc = d } = match d with
| Py_ast.Ecall (id, el) -> | Py_ast.Ecall (id, el) ->
mk_expr ~loc (Eidapp (Qident id, List.map (expr env) el)) mk_expr ~loc (Eidapp (Qident id, List.map (expr env) el))
| Py_ast.Elist _el -> | Py_ast.Elist _el ->
assert false assert false (*TODO*)
| Py_ast.Eget (e1, e2) -> | Py_ast.Eget (e1, e2) ->
mk_expr ~loc (Eidapp (mixfix ~loc "[]", [expr env e1; expr env e2])) mk_expr ~loc (Eidapp (mixfix ~loc "[]", [expr env e1; expr env e2]))
...@@ -152,33 +152,32 @@ let rec stmt env ({Py_ast.stmt_loc = loc; Py_ast.stmt_desc = d } as s) = ...@@ -152,33 +152,32 @@ let rec stmt env ({Py_ast.stmt_loc = loc; Py_ast.stmt_desc = d } as s) =
| Py_ast.Swhile (e, ann, s) -> | Py_ast.Swhile (e, ann, s) ->
mk_expr ~loc mk_expr ~loc
(Ewhile (expr env e, loop_annotation env ann, block env ~loc s)) (Ewhile (expr env e, loop_annotation env ann, block env ~loc s))
| Py_ast.Sfor (id, e, ann, body) -> | Py_ast.Sfor (id, e, inv, body) ->
(* for x in e: s (* for x in e:
is translated to s
is translated to
let l = e in let l = e in
let i = ref 0 in for i = 0 to len(l)-1 do
while !i < len(e) do user invariants
invariant 0 <= !i (and user invariants) let x = l[i] in
let x = l[!i] in s
s;
i := !i + 1
done done
*) *)
let i, l, env = for_vars ~loc env in let i, l, env = for_vars ~loc env in
let e = expr env e in let e = expr env e in
let env = add_var env id in
mk_expr ~loc (Elet (l, Gnone, e, (* evaluate e only once *) mk_expr ~loc (Elet (l, Gnone, e, (* evaluate e only once *)
mk_expr ~loc (Elet (i, Gnone, mk_ref ~loc (constant ~loc "0"), let lb = constant ~loc "0" in
let lenl = mk_expr ~loc (Eidapp (len ~loc, [mk_var ~loc l])) in let lenl = mk_expr ~loc (Eidapp (len ~loc, [mk_var ~loc l])) in
let test = let ub = mk_expr ~loc (Eidapp (infix ~loc "-", [lenl;constant ~loc "1"])) in
mk_expr ~loc (Eidapp (infix ~loc "<", [deref_id ~loc i; lenl])) in mk_expr ~loc (Efor (i, lb, To, ub, List.map (deref env) inv,
mk_expr ~loc (Ewhile (test, loop_annotation env ann,
let li = mk_expr ~loc let li = mk_expr ~loc
(Eidapp (mixfix ~loc "[]", [mk_var ~loc l; deref_id ~loc i])) in (Eidapp (mixfix ~loc "[]", [mk_var ~loc l; mk_var ~loc i])) in
mk_expr ~loc (Elet (id, Gnone, mk_ref ~loc li, mk_expr ~loc (Elet (id, Gnone, mk_ref ~loc li,
mk_expr ~loc (Esequence (block env body, let env = add_var env id in
mk_expr ~loc (Eidapp (Qident (mk_id ~loc "incr"), [mk_var ~loc i]))) block env body
))))))))) ))))))
and block env ?(loc=Loc.dummy_position) = function and block env ?(loc=Loc.dummy_position) = function
| [] -> | [] ->
......
...@@ -152,7 +152,7 @@ stmt_desc: ...@@ -152,7 +152,7 @@ stmt_desc:
| WHILE e = expr COLON b=loop_body | WHILE e = expr COLON b=loop_body
{ let a, l = b in Swhile (e, a, l) } { let a, l = b in Swhile (e, a, l) }
| FOR x = ident IN e = expr COLON b=loop_body | FOR x = ident IN e = expr COLON b=loop_body
{ let a, l = b in Sfor (x, e, a, l) } { let a, l = b in Sfor (x, e, a.loop_invariant, l) }
; ;
loop_body: loop_body:
......
...@@ -23,18 +23,20 @@ while i < 10: ...@@ -23,18 +23,20 @@ while i < 10:
l[i] = 0 l[i] = 0
i = i+1 i = i+1
sum = 0
for x in l: for x in l:
#@ invariant sum >= 0
print(x) print(x)
#@ assert x >= 0
sum = sum+x
# # arithmetic # Python's division is neither Euclidean division, nor computer division
# # Python's division is not *Euclidean* division #@ assert 4 // 3 == 1 and 4 % 3 == 1
# q = -4 // 3 #@ assert -4 // 3 == -2 and -4 % 3 == 2
# #@ assert q == -2 #@ assert 4 // -3 == -2 and 4 % -3 == -2
# r = -4 % 3 #@ assert -4 // -3 == 1 and -4 % -3 == -1
# #@ assert r == 2
# #@ assert 4 // -3 == -2
# #@ assert 4 % -3 == -2
# Local Variables: # Local Variables:
# compile-command: "make -C ../.. && why3 prove -P alt-ergo test.py" # compile-command: "make -C ../.. && why3 prove -P alt-ergo test.py"
# End: # End:
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment