Skip to content

Commit fff0bc6

Browse files
feat: prove equality of Nat.bitwise and Nat.bitwise' (#7410)
This PR proves that `Nat.bitwise` (from core) and `Nat.bitwise'` (from mathlib) are equal Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
1 parent 2ee7c9f commit fff0bc6

File tree

4 files changed

+116
-37
lines changed

4 files changed

+116
-37
lines changed

Mathlib/Data/Int/Bitwise.lean

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Jeremy Avigad
55
-/
66
import Mathlib.Data.Int.Basic
7+
import Mathlib.Data.Nat.Bitwise
78
import Mathlib.Data.Nat.Pow
89
import Mathlib.Data.Nat.Size
910
import Mathlib.Init.Data.Int.Bitwise
@@ -205,9 +206,9 @@ theorem testBit_zero (b) : ∀ n, testBit (bit b n) 0 = b
205206
theorem testBit_succ (m b) : ∀ n, testBit (bit b n) (Nat.succ m) = testBit n m
206207
| (n : ℕ) => by rw [bit_coe_nat]; apply Nat.testBit_succ
207208
| -[n+1] => by
208-
dsimp [testBit]
209+
dsimp only [testBit]
209210
simp only [bit_negSucc]
210-
cases b <;> simp [Nat.testBit_succ]
211+
cases b <;> simp only [Bool.not_false, Bool.not_true, Nat.testBit_succ]
211212
#align int.test_bit_succ Int.testBit_succ
212213

213214
-- Porting note: TODO

Mathlib/Data/Nat/Bitwise.lean

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
/-
22
Copyright (c) 2020 Markus Himmel. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
4-
Authors: Markus Himmel
4+
Authors: Markus Himmel, Alex Keizer
55
-/
66
import Lean.Elab.Tactic
77
import Mathlib.Data.List.Basic
88
import Mathlib.Data.Nat.Bits
99
import Mathlib.Data.Nat.Size
1010
import Mathlib.Data.Nat.Order.Lemmas
1111
import Mathlib.Tactic.Linarith
12+
import Mathlib.Tactic.Ring
1213

1314
#align_import data.nat.bitwise from "leanprover-community/mathlib"@"6afc9b06856ad973f6a2619e3e8a0a8d537a58f2"
1415

@@ -44,6 +45,104 @@ namespace Nat
4445

4546
set_option linter.deprecated false
4647

48+
section
49+
variable {f : Bool → Bool → Bool}
50+
51+
lemma bitwise'_bit' {f : Bool → Bool → Bool} (a : Bool) (m : Nat) (b : Bool) (n : Nat)
52+
(ham : m = 0 → a = true) (hbn : n = 0 → b = true) :
53+
bitwise' f (bit a m) (bit b n) = bit (f a b) (bitwise' f m n) := by
54+
rw [bitwise', binaryRec_eq', binaryRec_eq']
55+
· apply Or.inr hbn
56+
· apply Or.inr ham
57+
58+
@[simp]
59+
lemma bitwise_zero_left (m : Nat) : bitwise f 0 m = if f false true then m else 0 :=
60+
rfl
61+
62+
@[simp]
63+
lemma bitwise_zero_right (n : Nat) : bitwise f n 0 = if f true false then n else 0 := by
64+
unfold bitwise
65+
simp only [ite_self, decide_False, Nat.zero_div, ite_true, ite_eq_right_iff]
66+
rintro ⟨⟩
67+
split_ifs <;> rfl
68+
69+
@[simp]
70+
theorem bitwise'_zero_right (m : Nat) :
71+
bitwise' f m 0 = bif f true false then m else 0 := by
72+
unfold bitwise' binaryRec
73+
simp only [Bool.cond_eq_ite, eq_mpr_eq_cast, cast_eq, dite_eq_ite]
74+
split_ifs with hx <;> simp only [bit_decomp, binaryRec_zero, hx]
75+
76+
lemma bitwise_zero : bitwise f 0 0 = 0 := by
77+
simp only [bitwise_zero_right, ite_self]
78+
79+
@[simp]
80+
lemma bitwise_of_ne_zero {n m : Nat} (hn : n ≠ 0) (hm : m ≠ 0) :
81+
bitwise f n m = bit (f (bodd n) (bodd m)) (bitwise f (n / 2) (m / 2)) := by
82+
conv_lhs => { unfold bitwise }
83+
have mod_two_iff_bod x : (x % 2 = 1 : Bool) = bodd x := by
84+
simp [mod_two_of_bodd, cond]; cases bodd x <;> rfl
85+
simp only [hn, hm, mod_two_iff_bod, ite_false, bit, bit1, bit0, Bool.cond_eq_ite]
86+
split_ifs <;> rfl
87+
88+
@[simp]
89+
lemma bitwise'_of_ne_zero {n m : Nat} (hn : n ≠ 0) (hm : m ≠ 0) :
90+
bitwise' f n m = bit (f (bodd n) (bodd m)) (bitwise' f (n / 2) (m / 2)) := by
91+
conv_lhs => { rw [←bit_decomp n, ←bit_decomp m] }
92+
rw [bitwise'_bit', bit, div2_val, div2_val]
93+
case ham =>
94+
obtain ⟨⟩ | n := n
95+
· contradiction
96+
· simp only [div2_succ, cond, bodd_succ, Bool.not_not]
97+
cases bodd n <;> simp
98+
case hbn =>
99+
obtain ⟨⟩ | m := m
100+
· contradiction
101+
· simp only [div2_succ, cond, bodd_succ, Bool.not_not]
102+
cases bodd m <;> simp
103+
104+
lemma bitwise'_eq_bitwise (f) : bitwise' f = bitwise f := by
105+
funext x y
106+
induction' x using Nat.strongInductionOn with x ih generalizing y
107+
cases' x with x <;> cases' y with y
108+
· simp only [bitwise_zero, bitwise'_zero]
109+
· simp only [bitwise_zero_left, bitwise'_zero_left, Bool.cond_eq_ite]
110+
· simp only [bitwise_zero_right, bitwise'_zero_right, Bool.cond_eq_ite]
111+
· specialize ih ((x+1) / 2) (div_lt_self' ..)
112+
simp only [ne_eq, succ_ne_zero, not_false_eq_true, bitwise'_of_ne_zero, ih, bitwise_of_ne_zero]
113+
114+
theorem lor'_eq_lor : lor' = lor :=
115+
bitwise'_eq_bitwise _
116+
117+
theorem land'_eq_land : land' = land :=
118+
bitwise'_eq_bitwise _
119+
120+
theorem xor'_eq_xor : lxor' = xor := by
121+
unfold lxor' xor
122+
have : _root_.xor = bne := by
123+
funext x y; cases x <;> cases y <;> rfl
124+
rw [this]
125+
exact bitwise'_eq_bitwise _
126+
127+
@[simp]
128+
lemma bitwise_bit {f : Bool → Bool → Bool} (h : f false false = false := by rfl) (a m b n) :
129+
bitwise f (bit a m) (bit b n) = bit (f a b) (bitwise f m n) := by
130+
simp only [←bitwise'_eq_bitwise, bitwise'_bit h]
131+
132+
@[simp]
133+
theorem lor_bit : ∀ a m b n, lor (bit a m) (bit b n) = bit (a || b) (lor m n) :=
134+
bitwise_bit
135+
136+
@[simp]
137+
theorem land_bit : ∀ a m b n, land (bit a m) (bit b n) = bit (a && b) (land m n) :=
138+
bitwise_bit
139+
140+
@[simp]
141+
theorem lxor_bit : ∀ a m b n, xor (bit a m) (bit b n) = bit (bne a b) (xor m n) :=
142+
bitwise_bit
143+
144+
end
145+
47146
@[simp]
48147
theorem bit_false : bit false = bit0 :=
49148
rfl
@@ -161,6 +260,17 @@ theorem testBit_two_pow (n m : ℕ) : testBit (2 ^ n) m = (n = m) := by
161260
simp [h]
162261
#align nat.test_bit_two_pow Nat.testBit_two_pow
163262

263+
theorem bitwise'_swap {f : Bool → Bool → Bool} (h : f false false = false) :
264+
bitwise' (Function.swap f) = Function.swap (bitwise' f) := by
265+
funext m n; revert n
266+
dsimp [Function.swap]
267+
apply binaryRec _ _ m <;> intro n
268+
· rw [bitwise'_zero_left, bitwise'_zero_right, Bool.cond_eq_ite]
269+
· intros a ih m'
270+
apply bitCasesOn m'; intro b n'
271+
rw [bitwise'_bit, bitwise'_bit, ih] <;> exact h
272+
#align nat.bitwise_swap Nat.bitwise'_swap
273+
164274
/-- If `f` is a commutative operation on bools such that `f false false = false`, then `bitwise f`
165275
is also commutative. -/
166276
theorem bitwise'_comm {f : Bool → Bool → Bool} (hf : ∀ b b', f b b' = f b' b)

Mathlib/Data/Num/Lemmas.lean

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Authors: Mario Carneiro
55
-/
66
import Mathlib.Data.Num.Bitwise
77
import Mathlib.Data.Int.CharZero
8+
import Mathlib.Data.Nat.Bitwise
89
import Mathlib.Data.Nat.GCD.Basic
910
import Mathlib.Data.Nat.PSub
1011
import Mathlib.Data.Nat.Size
@@ -922,7 +923,7 @@ theorem bitwise'_to_nat {f : Num → Num → Num} {g : Bool → Bool → Bool} (
922923
any_goals assumption
923924
any_goals rw [Nat.bitwise'_zero, p11]; cases g true true <;> rfl
924925
any_goals rw [Nat.bitwise'_zero_left, this, ← bit_to_nat, p1b]
925-
any_goals rw [Nat.bitwise'_zero_right _ gff, this, ← bit_to_nat, pb1]
926+
any_goals rw [Nat.bitwise'_zero_right, this, ← bit_to_nat, pb1]
926927
all_goals
927928
rw [← show ∀ n : PosNum, ↑(p m n) = Nat.bitwise' g ↑m ↑n from IH]
928929
rw [← bit_to_nat, pbb]

Mathlib/Init/Data/Nat/Bitwise.lean

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -409,14 +409,6 @@ theorem bitwise'_zero_left (f : Bool → Bool → Bool) (n) :
409409
unfold bitwise'; rw [binaryRec_zero]
410410
#align nat.bitwise_zero_left Nat.bitwise'_zero_left
411411

412-
@[simp]
413-
theorem bitwise'_zero_right (f : Bool → Bool → Bool) (h : f false false = false) (m) :
414-
bitwise' f m 0 = cond (f true false) m 0 := by
415-
unfold bitwise'; apply bitCasesOn m; intros; rw [binaryRec_eq, binaryRec_zero]
416-
exact bitwise'_bit_aux h
417-
#align nat.bitwise_zero_right Nat.bitwise'_zero_right
418-
419-
@[simp]
420412
theorem bitwise'_zero (f : Bool → Bool → Bool) : bitwise' f 0 0 = 0 := by
421413
rw [bitwise'_zero_left]
422414
cases f false true <;> rfl
@@ -442,31 +434,6 @@ theorem bitwise'_bit {f : Bool → Bool → Bool} (h : f false false = false) (a
442434
· exact bitwise'_bit_aux h
443435
#align nat.bitwise_bit Nat.bitwise'_bit
444436

445-
theorem bitwise'_swap {f : Bool → Bool → Bool} (h : f false false = false) :
446-
bitwise' (Function.swap f) = Function.swap (bitwise' f) := by
447-
funext m n; revert n
448-
dsimp [Function.swap]
449-
apply binaryRec _ _ m <;> intro n
450-
· rw [bitwise'_zero_left, bitwise'_zero_right]
451-
exact h
452-
· intros a ih m'
453-
apply bitCasesOn m'; intro b n'
454-
rw [bitwise'_bit, bitwise'_bit, ih] <;> exact h
455-
#align nat.bitwise_swap Nat.bitwise'_swap
456-
457-
-- Porting note:
458-
-- If someone wants to merge `bitwise` and `bitwise'`
459-
-- (and similarly `lor` / `lor'` and `land` / `land'`)
460-
-- they could start by proving the next theorem:
461-
-- lemma bitwise_eq_bitwise' (f : Bool → Bool → Bool) :
462-
-- bitwise f = bitwise' f := by
463-
-- sorry
464-
465-
-- @[simp]
466-
-- theorem bitwise_bit {f : Bool → Bool → Bool} (h : f false false = false) (a m b n) :
467-
-- bitwise f (bit a m) (bit b n) = bit (f a b) (bitwise f m n) := by
468-
-- simp only [bitwise_eq_bitwise', bitwise'_bit h]
469-
470437
@[simp]
471438
theorem lor'_bit : ∀ a m b n, lor' (bit a m) (bit b n) = bit (a || b) (lor' m n) :=
472439
bitwise'_bit rfl

0 commit comments

Comments
 (0)