(** * Logic Predicates *)

Definition eq := @Logic.eq Z.Definition eq_equiv := @eq_equivalence Z.Notation "x <= y <= z" := (x <= y /\ y <= z) : Z_scope.Notation "x <= y < z" := (x <= y /\ y < z) : Z_scope.Notation "x < y < z" := (x < y /\ y < z) : Z_scope.Notation "x < y <= z" := (x < y /\ y <= z) : Z_scope.Definition divide x y := exists z, y = z*x.Notation "( x | y )" := (divide x y) (at level 0).Definition Even a := exists b, a = 2*b.Definition Odd a := exists b, a = 2*b+1.(** * Decidability of equality. *)

Definition eq_dec (x y : Z) : {x = y} + {x <> y}.Program Definition succ_wd : Proper (eq==>eq) succ := _.Program Definition pred_wd : Proper (eq==>eq) pred := _.Program Definition opp_wd : Proper (eq==>eq) opp := _.Program Definition add_wd : Proper (eq==>eq==>eq) add := _.Program Definition sub_wd : Proper (eq==>eq==>eq) sub := _.Program Definition mul_wd : Proper (eq==>eq==>eq) mul := _.Program Definition lt_wd : Proper (eq==>eq==>iff) lt := _.Program Definition div_wd : Proper (eq==>eq==>eq) div := _.Program Definition mod_wd : Proper (eq==>eq==>eq) modulo := _.Program Definition quot_wd : Proper (eq==>eq==>eq) quot := _.Program Definition rem_wd : Proper (eq==>eq==>eq) rem := _.Program Definition pow_wd : Proper (eq==>eq==>eq) pow := _.Program Definition testbit_wd : Proper (eq==>eq==>Logic.eq) testbit := _.

(* Specifications: *)
Lemma pos_sub_spec p q : pos_sub p q = match (p ?= q)%positive with | Eq => 0 | Lt => neg (q - p) | Gt => pos (p - q) end.
Lemma pos_sub_discr p q : match pos_sub p q with | Z0 => p = q | pos k => p = q + k | neg k => q = p + k end%positive.
Lemma pos_sub_diag p : pos_sub p p = 0.
Lemma pos_sub_lt p q : (p < q)%positive -> pos_sub p q = neg (q - p).
Lemma pos_sub_gt p q : (q < p)%positive -> pos_sub p q = pos (p - q).
Lemma pos_sub_opp p q : - pos_sub p q = pos_sub q p.
Lemma add_0_r n : n + 0 = n.
Lemma mul_0_r n : n * 0 = 0.
Lemma mul_1_l n : 1 * n = n.
Lemma add_comm n m : n + m = m + n.
Lemma opp_add_distr n m : - (n + m) = - n + - m.
Lemma opp_inj n m : -n = -m -> n = m.
Lemma pos_sub_add p q r : pos_sub (p + q) r = pos p + pos_sub q r.
Lemma add_assoc_pos p n m : pos p + (n + m) = pos p + n + m.
Lemma add_assoc n m p : n + (m + p) = n + m + p.
Lemma add_opp_diag_r n : n + - n = 0.
Lemma mul_opp_r n m : n * - m = - (n * m).
Lemma mul_add_distr_pos (p:positive) n m : (n + m) * pos p = n * pos p + m * pos p.
Lemma mul_add_distr_r n m p : (n + m) * p = n * p + m * p.
Lemma one_succ : 1 = succ 0.
Lemma two_succ : 2 = succ 1.
Lemma add_0_l n : 0 + n = n.
Lemma add_succ_l n m : succ n + m = succ (n + m).
Lemma opp_0 : -0 = 0.
Lemma opp_succ n : -(succ n) = pred (-n).
Lemma succ_pred n : succ (pred n) = n.
Lemma pred_succ n : pred (succ n) = n.
Lemma sub_0_r n : n - 0 = n.
Lemma sub_succ_r n m : n - succ m = pred (n - m).
Lemma mul_0_l n : 0 * n = 0.
Lemma mul_succ_l n m : succ n * m = n * m + m.
Lemma eqb_eq n m : (n =? m) = true <-> n = m.