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!