/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura

Auxiliary lemmas used to compare int numerals.
-/
prelude
import init.data.int.order

namespace int
/- Auxiliary lemmas for proving that to int numerals are different -/

/- 1. Lemmas for reducing the problem to the case where the numerals are positive -/

protected lemma ne_neg_of_ne {a b : ℤ} : a ≠ b → -a ≠ -b :=
λ h₁ h₂, absurd (neg_inj h₂) h₁

protected lemma neg_ne_zero_of_ne {a : ℤ} : a ≠ 0 → -a ≠ 0 :=
λ h₁ h₂,
  have -a = -0, by rwa neg_zero,
  have a = 0, from neg_inj this,
  by contradiction

protected lemma zero_ne_neg_of_ne {a : ℤ} (h : 0 ≠ a) : 0 ≠ -a :=
ne.symm (int.neg_ne_zero_of_ne (ne.symm h))

protected lemma neg_ne_of_pos {a b : ℤ} : a > 0 → b > 0 → -a ≠ b :=
λ h₁ h₂ h,
begin
  rw [-h] at h₂,
  exact absurd (le_of_lt h₁) (not_le_of_gt (neg_of_neg_pos h₂))
end

protected lemma ne_neg_of_pos {a b : ℤ} : a > 0 → b > 0 → a ≠ -b :=
λ h₁ h₂, ne.symm (int.neg_ne_of_pos h₂ h₁)

/- 2. Lemmas for proving that positive int numerals are nonneg and positive -/

protected lemma one_pos : (1:int) > 0 :=
zero_lt_one

protected lemma bit0_pos {a : ℤ} : a > 0 → bit0 a > 0 :=
λ h, add_pos h h

protected lemma bit1_pos {a : ℤ} : a ≥ 0 → bit1 a > 0 :=
λ h, lt_add_of_le_of_pos (add_nonneg h h) zero_lt_one

protected lemma zero_nonneg : (0:int) ≥ 0 :=
le_refl 0

protected lemma one_nonneg : (1:int) ≥ 0 :=
le_of_lt (zero_lt_one)

protected lemma bit0_nonneg {a : ℤ} : a ≥ 0 → bit0 a ≥ 0 :=
λ h, add_nonneg h h

protected lemma bit1_nonneg {a : ℤ} : a ≥ 0 → bit1 a ≥ 0 :=
λ h, le_of_lt (int.bit1_pos h)

protected lemma nonneg_of_pos {a : ℤ} : a > 0 → a ≥ 0 :=
le_of_lt

/- 3. nat_abs auxiliary lemmas -/

lemma neg_succ_of_nat_lt_zero (n : ℕ) : neg_succ_of_nat n < 0 :=
@lt.intro _ _ n (by simp [neg_succ_of_nat_coe, int.coe_nat_succ, int.coe_nat_add, int.coe_nat_one])

lemma of_nat_ge_zero (n : ℕ) : of_nat n ≥ 0 :=
@le.intro _ _ n (by rw [zero_add, int.coe_nat_eq])

lemma of_nat_nat_abs_eq_of_nonneg : ∀ {a : ℤ}, a ≥ 0 → of_nat (nat_abs a) = a
| (of_nat n)          h := rfl
| (neg_succ_of_nat n) h := absurd (neg_succ_of_nat_lt_zero n) (not_lt_of_ge h)

lemma ne_of_nat_abs_ne_nat_abs_of_nonneg {a b : ℤ} (ha : a ≥ 0) (hb : b ≥ 0) (h : nat_abs a ≠ nat_abs b) : a ≠ b :=
assume h,
  have of_nat (nat_abs a) = of_nat (nat_abs b), by rwa [of_nat_nat_abs_eq_of_nonneg ha, of_nat_nat_abs_eq_of_nonneg hb],
  begin injection this, contradiction end

protected lemma ne_of_nat_ne_nonneg_case {a b : ℤ} {n m : nat} (ha : a ≥ 0) (hb : b ≥ 0) (e1 : nat_abs a = n) (e2 : nat_abs b = m) (h : n ≠ m) : a ≠ b :=
have nat_abs a ≠ nat_abs b, by rwa [e1, e2],
ne_of_nat_abs_ne_nat_abs_of_nonneg ha hb this

/- 4. Aux lemmas for pushing nat_abs inside numerals
   nat_abs_zero and nat_abs_one are defined at init/data/int/basic.lean -/

lemma nat_abs_of_nat_core (n : ℕ) : nat_abs (of_nat n) = n :=
rfl

lemma nat_abs_of_neg_succ_of_nat (n : ℕ) : nat_abs (neg_succ_of_nat n) = nat.succ n :=
rfl

protected lemma nat_abs_add_nonneg : ∀ {a b : int}, a ≥ 0 → b ≥ 0 → nat_abs (a + b) = nat_abs a + nat_abs b
| (of_nat n) (of_nat m)  h₁ h₂ :=
  have of_nat n + of_nat m = of_nat (n + m), from rfl,
  by simp [nat_abs_of_nat_core, this]
| _  (neg_succ_of_nat m) h₁ h₂ := absurd (neg_succ_of_nat_lt_zero m) (not_lt_of_ge h₂)
| (neg_succ_of_nat n) _  h₁ h₂ := absurd (neg_succ_of_nat_lt_zero n) (not_lt_of_ge h₁)

protected lemma nat_abs_add_neg : ∀ {a b : int}, a < 0 → b < 0 → nat_abs (a + b) = nat_abs a + nat_abs b
| (neg_succ_of_nat n) (neg_succ_of_nat m) h₁ h₂ :=
  have -[1+ n] + -[1+ m] = -[1+ nat.succ (n + m)], from rfl,
  begin simp [nat_abs_of_neg_succ_of_nat, this, nat.succ_add, nat.add_succ] end

protected lemma nat_abs_bit0 : ∀ (a : int), nat_abs (bit0 a) = bit0 (nat_abs a)
| (of_nat n)          := int.nat_abs_add_nonneg (of_nat_ge_zero n) (of_nat_ge_zero n)
| (neg_succ_of_nat n) := int.nat_abs_add_neg (neg_succ_of_nat_lt_zero n) (neg_succ_of_nat_lt_zero n)

protected lemma nat_abs_bit0_step {a : int} {n : nat} (h : nat_abs a = n) : nat_abs (bit0 a) = bit0 n :=
begin rw [-h], apply int.nat_abs_bit0 end

protected lemma nat_abs_bit1_nonneg {a : int} (h : a ≥ 0) : nat_abs (bit1 a) = bit1 (nat_abs a) :=
show nat_abs (bit0 a + 1) = bit0 (nat_abs a) + nat_abs 1, from
by rw [int.nat_abs_add_nonneg (int.bit0_nonneg h) (le_of_lt (zero_lt_one)), int.nat_abs_bit0]

protected lemma nat_abs_bit1_nonneg_step {a : int} {n : nat} (h₁ : a ≥ 0) (h₂ : nat_abs a = n) : nat_abs (bit1 a) = bit1 n :=
begin rw [-h₂], apply int.nat_abs_bit1_nonneg h₁ end

end int
