/- Copyright (c) 2017 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Mario Carneiro -/ prelude import init.data.int.lemmas init.data.nat.bitwise init.data.bool.lemmas universe u namespace int def div2 : ℤ → ℤ | (of_nat n) := n.div2 | -[1+ n] := -[1+ n.div2] def bodd : ℤ → bool | (of_nat n) := n.bodd | -[1+ n] := bnot (n.bodd) @[simp] lemma bodd_zero : bodd 0 = ff := rfl @[simp] lemma bodd_one : bodd 1 = tt := rfl @[simp] lemma bodd_two : bodd 2 = ff := rfl @[simp] lemma bodd_sub_nat_nat (m n : ℕ) : bodd (sub_nat_nat m n) = bxor m.bodd n.bodd := by apply sub_nat_nat_elim m n (λ m n i, bodd i = bxor m.bodd n.bodd); intros i m; simp [bodd]; cases i.bodd; cases m.bodd; refl @[simp] lemma bodd_neg_of_nat (n : ℕ) : bodd (neg_of_nat n) = n.bodd := by cases n; simp; refl @[simp] lemma bodd_neg (n : ℤ) : bodd (-n) = bodd n := by cases n; unfold has_neg.neg; simp [int.coe_nat_eq, int.neg, bodd] @[simp] lemma bodd_add (m n : ℤ) : bodd (m + n) = bxor (bodd m) (bodd n) := by cases m with m m; cases n with n n; unfold has_add.add; simp [int.add, bodd]; cases m.bodd; cases n.bodd; refl @[simp] lemma bodd_mul (m n : ℤ) : bodd (m * n) = bodd m && bodd n := by cases m with m m; cases n with n n; unfold has_mul.mul; simp [int.mul, bodd]; cases m.bodd; cases n.bodd; refl theorem bodd_add_div2 : ∀ n, cond (bodd n) 1 0 + 2 * div2 n = n | (n : ℕ) := by rw [show (cond (bodd n) 1 0 : ℤ) = (cond (bodd n) 1 0 : ℕ), by cases bodd n; refl]; exact congr_arg of_nat n.bodd_add_div2 | -[1+ n] := begin refine eq.trans _ (congr_arg neg_succ_of_nat n.bodd_add_div2), dsimp [bodd], cases nat.bodd n; dsimp [cond, bnot, div2, int.mul], { change -[1+ 2 * nat.div2 n] = _, rw zero_add }, { rw [zero_add, add_comm], refl } end theorem div2_val : ∀ n, div2 n = n / 2 | (n : ℕ) := congr_arg of_nat n.div2_val | -[1+ n] := congr_arg neg_succ_of_nat n.div2_val def bit (b : bool) : ℤ → ℤ := cond b bit1 bit0 lemma bit0_val (n : ℤ) : bit0 n = 2 * n := (two_mul _).symm lemma bit1_val (n : ℤ) : bit1 n = 2 * n + 1 := congr_arg (+(1:ℤ)) (bit0_val _) lemma bit_val (b n) : bit b n = 2 * n + cond b 1 0 := by { cases b, apply (bit0_val n).trans (add_zero _).symm, apply bit1_val } lemma bit_decomp (n : ℤ) : bit (bodd n) (div2 n) = n := (bit_val _ _).trans $ (add_comm _ _).trans $ bodd_add_div2 _ def bit_cases_on {C : ℤ → Sort u} (n) (h : ∀ b n, C (bit b n)) : C n := by rw [← bit_decomp n]; apply h @[simp] lemma bit_zero : bit ff 0 = 0 := rfl @[simp] lemma bit_coe_nat (b) (n : ℕ) : bit b n = nat.bit b n := by rw [bit_val, nat.bit_val]; cases b; refl @[simp] lemma bit_neg_succ (b) (n : ℕ) : bit b -[1+ n] = -[1+ nat.bit (bnot b) n] := by rw [bit_val, nat.bit_val]; cases b; refl @[simp] lemma bodd_bit (b n) : bodd (bit b n) = b := by rw bit_val; simp; cases b; cases bodd n; refl @[simp] lemma div2_bit (b n) : div2 (bit b n) = n := begin rw [bit_val, div2_val, add_comm, int.add_mul_div_left, (_ : (_/2:ℤ) = 0), zero_add], cases b, all_goals {exact dec_trivial} end def test_bit : ℤ → ℕ → bool | (m : ℕ) n := nat.test_bit m n | -[1+ m] n := bnot (nat.test_bit m n) @[simp] lemma test_bit_zero (b) : ∀ n, test_bit (bit b n) 0 = b | (n : ℕ) := by rw [bit_coe_nat]; apply nat.test_bit_zero | -[1+ n] := by rw [bit_neg_succ]; dsimp [test_bit]; rw [nat.test_bit_zero]; clear test_bit_zero; cases b; refl @[simp] lemma test_bit_succ (m b) : ∀ n, test_bit (bit b n) (nat.succ m) = test_bit n m | (n : ℕ) := by rw [bit_coe_nat]; apply nat.test_bit_succ | -[1+ n] := by rw [bit_neg_succ]; dsimp [test_bit]; rw [nat.test_bit_succ] def nat_bitwise (f : bool → bool → bool) (m n : ℕ) : ℤ := cond (f ff ff) -[1+ nat.bitwise (λx y, bnot (f x y)) m n] (nat.bitwise f m n) def bitwise (f : bool → bool → bool) : ℤ → ℤ → ℤ | (m : ℕ) (n : ℕ) := nat_bitwise f m n | (m : ℕ) -[1+ n] := nat_bitwise (λ x y, f x (bnot y)) m n | -[1+ m] (n : ℕ) := nat_bitwise (λ x y, f (bnot x) y) m n | -[1+ m] -[1+ n] := nat_bitwise (λ x y, f (bnot x) (bnot y)) m n def lnot : ℤ → ℤ | (m : ℕ) := -[1+ m] | -[1+ m] := m def lor : ℤ → ℤ → ℤ | (m : ℕ) (n : ℕ) := nat.lor m n | (m : ℕ) -[1+ n] := -[1+ nat.ldiff n m] | -[1+ m] (n : ℕ) := -[1+ nat.ldiff m n] | -[1+ m] -[1+ n] := -[1+ nat.land m n] def land : ℤ → ℤ → ℤ | (m : ℕ) (n : ℕ) := nat.land m n | (m : ℕ) -[1+ n] := nat.ldiff m n | -[1+ m] (n : ℕ) := nat.ldiff n m | -[1+ m] -[1+ n] := -[1+ nat.lor m n] def ldiff : ℤ → ℤ → ℤ | (m : ℕ) (n : ℕ) := nat.ldiff m n | (m : ℕ) -[1+ n] := nat.land m n | -[1+ m] (n : ℕ) := -[1+ nat.lor m n] | -[1+ m] -[1+ n] := nat.ldiff n m def lxor : ℤ → ℤ → ℤ | (m : ℕ) (n : ℕ) := nat.lxor m n | (m : ℕ) -[1+ n] := -[1+ nat.lxor m n] | -[1+ m] (n : ℕ) := -[1+ nat.lxor m n] | -[1+ m] -[1+ n] := nat.lxor m n def shiftl : ℤ → ℤ → ℤ | (m : ℕ) (n : ℕ) := nat.shiftl m n | (m : ℕ) -[1+ n] := nat.shiftr m (nat.succ n) | -[1+ m] (n : ℕ) := -[1+ nat.shiftl' tt m n] | -[1+ m] -[1+ n] := -[1+ nat.shiftr m (nat.succ n)] def shiftr (m n : ℤ) : ℤ := shiftl m (-n) private meta def bitwise_tac : tactic unit := `[ apply funext, intro m, apply funext, intro n, cases m with m m; cases n with n n; try {refl}, all_goals { apply congr_arg of_nat <|> apply congr_arg neg_succ_of_nat, try {dsimp [nat.land, nat.ldiff, nat.lor]}, try {rw [ show nat.bitwise (λ a b, a && bnot b) n m = nat.bitwise (λ a b, b && bnot a) m n, from congr_fun (congr_fun (@nat.bitwise_swap (λ a b, b && bnot a) rfl) n) m]}, apply congr_arg (λ f, nat.bitwise f m n), apply funext, intro a, apply funext, intro b, cases a; cases b; refl }, all_goals {unfold nat.land nat.ldiff nat.lor} ] theorem bitwise_or : bitwise bor = lor := by bitwise_tac theorem bitwise_and : bitwise band = land := by bitwise_tac theorem bitwise_diff : bitwise (λ a b, a && bnot b) = ldiff := by bitwise_tac theorem bitwise_xor : bitwise bxor = lxor := by bitwise_tac @[simp] lemma bitwise_bit (f : bool → bool → bool) (a m b n) : bitwise f (bit a m) (bit b n) = bit (f a b) (bitwise f m n) := begin cases m with m m; cases n with n n; repeat { rw [← int.coe_nat_eq] <|> rw bit_coe_nat <|> rw bit_neg_succ }; unfold bitwise nat_bitwise bnot; [ ginduction f ff ff with h, ginduction f ff tt with h, ginduction f tt ff with h, ginduction f tt tt with h ], all_goals { unfold cond, rw nat.bitwise_bit, repeat { rw bit_coe_nat <|> rw bit_neg_succ <|> rw bnot_bnot } }, all_goals { unfold bnot {fail_if_unchanged := ff}; rw h; refl } end @[simp] lemma lor_bit (a m b n) : lor (bit a m) (bit b n) = bit (a || b) (lor m n) := by rw [← bitwise_or, bitwise_bit] @[simp] lemma land_bit (a m b n) : land (bit a m) (bit b n) = bit (a && b) (land m n) := by rw [← bitwise_and, bitwise_bit] @[simp] lemma ldiff_bit (a m b n) : ldiff (bit a m) (bit b n) = bit (a && bnot b) (ldiff m n) := by rw [← bitwise_diff, bitwise_bit] @[simp] lemma lxor_bit (a m b n) : lxor (bit a m) (bit b n) = bit (bxor a b) (lxor m n) := by rw [← bitwise_xor, bitwise_bit] @[simp] lemma lnot_bit (b) : ∀ n, lnot (bit b n) = bit (bnot b) (lnot n) | (n : ℕ) := by simp [lnot] | -[1+ n] := by simp [lnot] @[simp] lemma test_bit_bitwise (f : bool → bool → bool) (m n k) : test_bit (bitwise f m n) k = f (test_bit m k) (test_bit n k) := begin revert m n; induction k with k IH; intros m n; apply bit_cases_on m; intros a m'; apply bit_cases_on n; intros b n'; rw bitwise_bit, { simp [test_bit_zero] }, { simp [test_bit_succ, IH] } end @[simp] lemma test_bit_lor (m n k) : test_bit (lor m n) k = test_bit m k || test_bit n k := by rw [← bitwise_or, test_bit_bitwise] @[simp] lemma test_bit_land (m n k) : test_bit (land m n) k = test_bit m k && test_bit n k := by rw [← bitwise_and, test_bit_bitwise] @[simp] lemma test_bit_ldiff (m n k) : test_bit (ldiff m n) k = test_bit m k && bnot (test_bit n k) := by rw [← bitwise_diff, test_bit_bitwise] @[simp] lemma test_bit_lxor (m n k) : test_bit (lxor m n) k = bxor (test_bit m k) (test_bit n k) := by rw [← bitwise_xor, test_bit_bitwise] @[simp] lemma test_bit_lnot : ∀ n k, test_bit (lnot n) k = bnot (test_bit n k) | (n : ℕ) k := by simp [lnot, test_bit] | -[1+ n] k := by simp [lnot, test_bit] lemma shiftl_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), shiftl m (n + k) = shiftl (shiftl m n) k | (m : ℕ) n (k:ℕ) := congr_arg of_nat (nat.shiftl_add _ _ _) | -[1+ m] n (k:ℕ) := congr_arg neg_succ_of_nat (nat.shiftl'_add _ _ _ _) | (m : ℕ) n -[1+k] := sub_nat_nat_elim n k.succ (λ n k i, shiftl ↑m i = nat.shiftr (nat.shiftl m n) k) (λ i n, congr_arg coe $ by rw [← nat.shiftl_sub, nat.add_sub_cancel_left]; apply nat.le_add_right) (λ i n, congr_arg coe $ by rw [add_assoc, nat.shiftr_add, ← nat.shiftl_sub, nat.sub_self]; refl) | -[1+ m] n -[1+k] := sub_nat_nat_elim n k.succ (λ n k i, shiftl -[1+ m] i = -[1+ nat.shiftr (nat.shiftl' tt m n) k]) (λ i n, congr_arg neg_succ_of_nat $ by rw [← nat.shiftl'_sub, nat.add_sub_cancel_left]; apply nat.le_add_right) (λ i n, congr_arg neg_succ_of_nat $ by rw [add_assoc, nat.shiftr_add, ← nat.shiftl'_sub, nat.sub_self]; refl) lemma shiftl_sub (m : ℤ) (n : ℕ) (k : ℤ) : shiftl m (n - k) = shiftr (shiftl m n) k := shiftl_add _ _ _ @[simp] lemma shiftl_neg (m n : ℤ) : shiftl m (-n) = shiftr m n := rfl @[simp] lemma shiftr_neg (m n : ℤ) : shiftr m (-n) = shiftl m n := by rw [← shiftl_neg, neg_neg] @[simp] lemma shiftl_coe_nat (m n : ℕ) : shiftl m n = nat.shiftl m n := rfl @[simp] lemma shiftr_coe_nat (m n : ℕ) : shiftr m n = nat.shiftr m n := by cases n; refl @[simp] lemma shiftl_neg_succ (m n : ℕ) : shiftl -[1+ m] n = -[1+ nat.shiftl' tt m n] := rfl @[simp] lemma shiftr_neg_succ (m n : ℕ) : shiftr -[1+ m] n = -[1+ nat.shiftr m n] := by cases n; refl lemma shiftr_add : ∀ (m : ℤ) (n k : ℕ), shiftr m (n + k) = shiftr (shiftr m n) k | (m : ℕ) n k := by rw [shiftr_coe_nat, shiftr_coe_nat, ← int.coe_nat_add, shiftr_coe_nat, nat.shiftr_add] | -[1+ m] n k := by rw [shiftr_neg_succ, shiftr_neg_succ, ← int.coe_nat_add, shiftr_neg_succ, nat.shiftr_add] lemma shiftl_eq_mul_pow : ∀ (m : ℤ) (n : ℕ), shiftl m n = m * 2 ^ n | (m : ℕ) n := congr_arg coe (nat.shiftl_eq_mul_pow _ _) | -[1+ m] n := @congr_arg ℕ ℤ _ _ (λi, -i) (nat.shiftl'_tt_eq_mul_pow _ _) lemma shiftr_eq_div_pow : ∀ (m : ℤ) (n : ℕ), shiftr m n = m / 2 ^ n | (m : ℕ) n := by rw shiftr_coe_nat; exact congr_arg coe (nat.shiftr_eq_div_pow _ _) | -[1+ m] n := begin rw [shiftr_neg_succ, neg_succ_of_nat_div, nat.shiftr_eq_div_pow], refl, exact coe_nat_lt_coe_nat_of_lt (nat.pos_pow_of_pos _ dec_trivial) end lemma one_shiftl (n : ℕ) : shiftl 1 n = (2 ^ n : ℕ) := congr_arg coe (nat.one_shiftl _) @[simp] lemma zero_shiftl : ∀ n : ℤ, shiftl 0 n = 0 | (n : ℕ) := congr_arg coe (nat.zero_shiftl _) | -[1+ n] := congr_arg coe (nat.zero_shiftr _) @[simp] lemma zero_shiftr (n) : shiftr 0 n = 0 := zero_shiftl _ end int