https://github.com/EasyCrypt/easycrypt
Tip revision: a79f9aeb6de046ca12210d26317fab59c175d0dd authored by Pierre-Yves Strub on 08 July 2014, 09:43:21 UTC
Fix bug w.r.t. _tools presence detection.
Fix bug w.r.t. _tools presence detection.
Tip revision: a79f9ae
Int.ec
(* --------------------------------------------------------------------
* Copyright IMDEA Software Institute / INRIA - 2013, 2014
* -------------------------------------------------------------------- *)
import why3 "int" "Int"
op "prefix -" as "[-]".
(* Random thing *)
op int_of_bool (b : bool) = if b then 1 else 0.
(* Group operation *)
op zeroz = 0.
op onez = 1.
lemma nosmt onez_neq0 : 1 <> 0
by [].
lemma nosmt addzA (x y z : int): x + (y + z) = (x + y) + z
by [].
lemma nosmt addzC (x y : int): x + y = y + x
by [].
lemma nosmt add0z (x : int): 0 + x = x
by [].
lemma nosmt addNz (x : int): (-x) + x = 0
by [].
lemma nosmt mulzA (x y z : int): x * (y * z) = (x * y) * z
by [].
lemma nosmt mulzC (x y : int): x * y = y * x
by [].
lemma nosmt mul1z (x : int): 1 * x = x
by [].
lemma nosmt mulzDl (x y z : int): (x + y) * z = x * z + y * z
by [].
(** Number theory *)
(* TODO: I merged in some stray bits from NewList and this may appear to be in whatever order... it is. *)
op "`|_|" (x:int) = (0 <= x) ? x : -x.
lemma nosmt lez_norm_add (x y : int): `|x + y| <= `|x| + `|y|
by [].
lemma nosmt addz_gt0 (x y : int): 0 < x => 0 < y => 0 < x + y
by [].
lemma nosmt norm_eq0 (x : int): `|x| = 0 => x = 0
by [].
lemma nosmt gez_leVge (x y : int): 0 <= x => 0 <= y => x <= y \/ y <= x
by [].
lemma nosmt normzM (x y : int): `|x * y| = `|x| * `|y|
by [].
lemma nosmt lez_def (x y : int): x <= y <=> `|y - x| = y - x
by [].
lemma nosmt ltz_def (x y : int): x < y <=> ( y <> x /\ x <= y)
by [].
lemma nosmt subzz (z : int): z - z = 0 by [].
lemma nosmt lezz (z : int): z <= z by [].
lemma nosmt ltzz (z : int): z < z <=> false by [].
lemma nosmt ltzNge (x y : int): (x < y) <=> !(y <= x) by [].
lemma nosmt lezNgt (x y : int): (x <= y) <=> !(y < x) by [].
lemma nosmt gez_le (x y : int): (x >= y) <=> (y <= x) by [].
lemma nosmt gtz_lt (x y : int): (x > y) <=> (y < x) by [].
lemma nosmt neq_ltz (x y : int): (x <> y) <=> (x < y \/ y < x) by [].
lemma nosmt eqz_leq (x y : int): (x = y) <=> (x <= y /\ y <= x) by [].
lemma nosmt lez_addl (x y z : int): (x + y <= x + z) <=> (y <= z) by [].
lemma nosmt lez_add1r (x y : int): (1 + x <= y) = (x < y) by [].
theory Induction.
axiom nosmt induction (p:int -> bool):
(p 0) =>
(forall i, 0 <= i => p i => p (i + 1)) =>
(forall i, 0 <= i => p i).
lemma nosmt strongInduction (p:int -> bool):
(forall j, 0 <= j => (forall k, 0 <= k < j => p k) => p j) =>
(forall i, 0 <= i => p i).
proof strict.
intros hyp i iVal.
apply (induction (fun i, forall k, 0 <= k <= i => p k) _ _ i); smt.
qed.
end Induction.
(* Fold operator *)
op fold : ('a -> 'a) -> 'a -> int -> 'a.
axiom foldle0 p (f : 'a -> 'a) a: p <= 0 => fold f a p = a.
lemma fold0 (f : 'a -> 'a) a: fold f a 0 = a
by [].
axiom foldS (f : 'a -> 'a) a n: 0 <= n => fold f a (n+1) = f (fold f a n).
lemma nosmt foldpos (f : 'a -> 'a) a n: 0 < n => f (fold f a (n-1)) = fold f a n
by [].
lemma fold_add (f : 'a -> 'a) a n1 n2 : 0 <= n1 => 0 <= n2 =>
fold f (fold f a n2) n1 = fold f a (n1 + n2).
proof strict. elim /Induction.induction n1; smt. qed.
(* Power *)
op ( ^ ) (x:int) (p:int) = fold (( * ) x) 1 p
axiomatized by powE.
lemma nosmt powNeg p x: p <= 0 => x ^ p = 1
by [].
lemma pow0 x: x ^ 0 = 1
by [].
lemma powS p x: 0 <= p => x ^ (p+1) = x * x ^ p
by [].
lemma pow_add z p1 p2: 0 <= p1 => 0 <= p2 => z^p1 * z^p2 = z^(p1+p2).
proof strict.
intros Hp1;elim /Induction.induction p2;smt.
qed.
lemma pow_mul z p1 p2: 0 <= p1 => 0 <= p2 => (z^p1)^p2 = z^(p1*p2).
proof strict.
intros Hp1;elim /Induction.induction p2;smt.
qed.
lemma powPos z p: 0 < z => 0 < z ^ p.
proof.
case (0 <= p); intros Hp Hz; last smt.
elim /Induction.induction p Hp; smt.
qed.
lemma pow_Mle (x y:int): 0 <= x <= y => 2^x <= 2^y.
proof.
intros [leq0_x leqx_y]; cut leq0_y: 0 <= y by smt.
move: leqx_y; elim /Induction.induction y leq0_y; smt.
qed.
(* Diveucl *)
import why3 "int" "EuclideanDivision"
op "div" as "/%";
op "mod" as "%%".
theory EuclDiv.
axiom ediv_spec m d:
d <> 0 =>
0 <= m %% d < `|d| /\
m = (m /% d) * d + (m %% d).
axiom ediv_unique m d q r:
d <> 0 =>
0 <= r < `|d| =>
m = q * d + r =>
q = m /% d /\ r = m %% d.
axiom ediv_Mle : forall (m1 m2 d:int), 0 < d => m1 <= m2 => m1/%d <= m2/%d.
lemma ediv_pos : forall m d, 0 < d => 0 <= m => 0 <= m /%d.
proof -strict.
intros m d Hd Hm.
apply (Trans _ (0/%d));last apply ediv_Mle;smt.
elim (ediv_unique 0 d 0 0 _ _ _) => //;smt.
qed.
end EuclDiv.
export EuclDiv.
theory Extrema.
op min (a b:int) = if (a < b) then a else b.
lemma nosmt min_is_lb a b:
min a b <= a /\
min a b <= b
by [].
lemma nosmt min_is_glb x a b:
x <= a => x <= b =>
x <= min a b
by [].
lemma nosmt min_is_extremum a b:
min a b = a \/ min a b = b
by [].
(* This is much more satisfying: it defines the notion,
and proves that it exists and is unique by giving it a
functional definition. Still, the above definition
is---probably---more usable.
Note that the following could be used for iterated versions,
for example on sets, with a proof that folding the binary min
over the set fulfills the axioms. *)
(*op min: int -> int -> int.
axiom min_is_lb: forall a b, min a b <= a /\ min a b <= b.
axiom min_is_glb: forall x a b, x <= a => x <= b => x <= min a b.
lemma min_is_extremum: forall a b, min a b = a \/ min a b = b.
lemma min_def: forall a b,
min a b = if (a < b) then a else b. *)
op max (a b:int) = if (a < b) then b else a.
lemma nosmt max_is_ub a b:
a <= max a b /\
b <= max a b
by [].
lemma nosmt max_is_lub x a b:
a <= x => b <= x =>
max a b <= x
by [].
lemma nosmt max_is_extremum a b:
max a b = a \/ max a b = b
by [].
end Extrema.
export Extrema.
lemma mulMle : forall (x1 x2 y1 y2:int),
0 <= x1 <= x2 => 0 <= y1 <= y2 => x1 * y1 <= x2 * y2.
proof -strict.
intros x1 x2 y1 y2 Hx Hy.
apply (Trans _ (x1 * y2)).
rewrite ?(Comm.Comm x1) CompatOrderMult; smt.
apply CompatOrderMult;smt.
qed.
theory ForLoop.
op range: int -> int -> 'a -> (int -> 'a -> 'a) -> 'a.
axiom range_base i j (st:'a) f:
j <= i =>
range i j st f = st.
axiom range_ind i j (st:'a) f:
i < j =>
range i j st f = range (i + 1) j (f i st) f.
lemma range_ind_lazy i j (st:'a) f:
i < j =>
range i j st f = f (j - 1) (range i (j - 1) st f).
proof strict.
intros=> h; cut {h}: 0 < j-i by smt. (* missing gt0_subr *)
cut: (j-i) = (j-i) by trivial. (* missing move: on pseudo proof-terms *)
generalize {2 3}(j-i) => n. (* missing negative pattern selector *)
intros=> eq_iBj_n gt0_n; generalize i j eq_iBj_n.
cut ge0_n: 0 <= n by smt; generalize ge0_n gt0_n st.
elim/Induction.induction n; first smt.
intros=> n ge0_n IH _ st i j.
case (n = 0); first intros=> -> h.
by (cut ->: j = i+1 by smt); rewrite range_ind ?range_base; smt.
intros=> nz_n eq_iBj_Sn; rewrite range_ind; first by smt.
(rewrite IH; first 2 smt); congr => //.
by rewrite -range_ind; first smt.
qed.
(* General result on boolean accumulation *)
lemma rangeb_forall i j p b:
ForLoop.range i j b (fun k b, b /\ p k) =
(b /\ forall k, i <= k < j => p k).
proof strict.
case (i < j)=> i_j; last smt.
pose n := j - i; cut ->: j = n + i by smt.
cut: 0 <= n by smt; elim/Induction.induction n;first by smt.
intros i0 Hi0 Hrec;rewrite range_ind_lazy;smt.
qed.
(* General result on restricting the range *)
lemma range_restr (i j:int) (base:'a) f:
0 <= j - i =>
ForLoop.range i j base (fun k a, if i <= k < j then f k a else a) = ForLoop.range i j base f.
proof strict.
intros=> h; case (0 = j - i)=> h2; first smt.
pose k:= j - i - 1; cut {1 3}->: j = k + i + 1 by smt.
cut: k < j - i by smt; cut: 0 <= k by smt.
by elim/Induction.induction k; smt.
qed.
axiom range_add i j1 j2 (a:'a) f : 0 <= j1 => 0 <= j2 => i <= j1 =>
range i (j1 + j2) a f = range (i+j1) (j1 + j2) (range i j1 a f) f.
end ForLoop.