(** We can now derive all properties of basic functions and orders, and use these properties for proving the specs of more advanced functions. *)
Include ZBasicProp <+ UsualMinMaxLogicalProperties <+ UsualMinMaxDecProperties.
Register eq_decidable as num.Z.eq_decidable.
Register le_decidable as num.Z.le_decidable.
Register lt_decidable as num.Z.lt_decidable.
(** ** Specification of absolute value *)

(* Specifications: *)
Lemma abs_eq n : 0 <= n -> abs n = n.
Lemma abs_neq n : n <= 0 -> abs n = - n.
(** ** Specification of sign *)
Lemma sgn_null n : n = 0 -> sgn n = 0.
Lemma sgn_pos n : 0 < n -> sgn n = 1.
Lemma sgn_neg n : n < 0 -> sgn n = -1.
(** ** Specification of power *)
Lemma pow_0_r n : n^0 = 1.
Lemma pow_succ_r n m : 0<=m -> n^(succ m) = n * n^m.
Lemma pow_neg_r n m : m<0 -> n^m = 0.
(** For folding back a [pow_pos] into a [pow] *)
Lemma pow_pos_fold n p : pow_pos n p = n ^ (pos p).
(** ** Specification of square *)
Lemma square_spec n : square n = n * n.
(** ** Specification of square root *)
Lemma sqrtrem_spec n : 0<=n ->
let (s,r) := sqrtrem n in n = s*s + r /\ 0 <= r <= 2*s.
Lemma sqrt_spec n : 0<=n ->
let s := sqrt n in s*s <= n < (succ s)*(succ s).
Lemma sqrt_neg n : n<0 -> sqrt n = 0.
Lemma sqrtrem_sqrt n : fst (sqrtrem n) = sqrt n.
(** ** Specification of logarithm *)
Lemma log2_spec n : 0 < n -> 2^(log2 n) <= n < 2^(succ (log2 n)).
Lemma log2_nonpos n : n<=0 -> log2 n = 0.
(** Specification of parity functions *)
Lemma even_spec n : even n = true <-> Even n.
Lemma odd_spec n : odd n = true <-> Odd n.
(** ** Multiplication and Doubling *)
Lemma double_spec n : double n = 2*n.
Lemma succ_double_spec n : succ_double n = 2*n + 1.
Lemma pred_double_spec n : pred_double n = 2*n - 1.
(** ** Correctness proofs for Trunc division *)
Lemma pos_div_eucl_eq a b : 0 < b ->
let (q, r) := pos_div_eucl a b in pos a = q * b + r.
Lemma div_eucl_eq a b : b<>0 ->
let (q, r) := div_eucl a b in a = b * q + r.
Lemma div_mod a b : b<>0 -> a = b*(a/b) + (a mod b).
Lemma pos_div_eucl_bound a b : 0<b -> 0 <= snd (pos_div_eucl a b) < b.
Lemma mod_pos_bound a b : 0 < b -> 0 <= a mod b < b.
Definition mod_bound_pos a b (_:0<=a) := mod_pos_bound a b.
Lemma mod_neg_bound a b : b < 0 -> b < a mod b <= 0.
(** ** Correctness proofs for Floor division *)
Theorem quotrem_eq a b : let (q,r) := quotrem a b in a = q * b + r.
Lemma quot_rem' a b : a = b*(a÷b) + rem a b.
Lemma quot_rem a b : b<>0 -> a = b*(a÷b) + rem a b.
Lemma rem_opp_l' a b : rem (-a) b = - (rem a b).
Lemma rem_opp_r' a b : rem a (-b) = rem a b.
Lemma rem_opp_l a b : b<>0 -> rem (-a) b = - (rem a b).
Lemma divide_Zpos_Zneg_r n p : (n|pos p) <-> (n|neg p).
Lemma divide_Zpos_Zneg_l n p : (pos p|n) <-> (neg p|n).
(** ** Correctness proofs for gcd *)
Lemma ggcd_gcd a b : fst (ggcd a b) = gcd a b.
Lemma ggcd_correct_divisors a b :
let '(g,(aa,bb)) := ggcd a b in
a = g*aa /\ b = g*bb.
Lemma gcd_divide_l a b : (gcd a b | a).
Lemma gcd_divide_r a b : (gcd a b | b).
Lemma gcd_greatest a b c : (c|a) -> (c|b) -> (c | gcd a b).
Lemma gcd_nonneg a b : 0 <= gcd a b.
(** ggcd and opp : an auxiliary result used in QArith *)
Theorem ggcd_opp a b :
ggcd (-a) b = (let '(g,(aa,bb)) := ggcd a b in (g,(-aa,bb))).