-
Notifications
You must be signed in to change notification settings - Fork 420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: upstream Nat.binaryRec
#3756
base: master
Are you sure you want to change the base?
Changes from all commits
f66834f
93d85bb
ac17fc1
aaeb7aa
26c483f
0004d42
3eb032a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,51 +35,61 @@ private theorem two_mul_sub_one {n : Nat} (n_pos : n > 0) : (2*n - 1) % 2 = 1 := | |
|
||
/-! ### Preliminaries -/ | ||
|
||
/-- | ||
An induction principal that works on divison by two. | ||
-/ | ||
noncomputable def div2Induction {motive : Nat → Sort u} | ||
(n : Nat) (ind : ∀(n : Nat), (n > 0 → motive (n/2)) → motive n) : motive n := by | ||
induction n using Nat.strongInductionOn with | ||
| ind n hyp => | ||
apply ind | ||
intro n_pos | ||
if n_eq : n = 0 then | ||
simp [n_eq] at n_pos | ||
else | ||
apply hyp | ||
exact Nat.div_lt_self n_pos (Nat.le_refl _) | ||
|
||
@[simp] theorem zero_and (x : Nat) : 0 &&& x = 0 := by rfl | ||
|
||
@[simp] theorem and_zero (x : Nat) : x &&& 0 = 0 := by | ||
simp only [HAnd.hAnd, AndOp.and, land] | ||
unfold bitwise | ||
simp | ||
|
||
@[simp] theorem and_one_is_mod (x : Nat) : x &&& 1 = x % 2 := by | ||
if xz : x = 0 then | ||
simp [xz, zero_and] | ||
else | ||
have andz := and_zero (x/2) | ||
simp only [HAnd.hAnd, AndOp.and, land] at andz | ||
simp only [HAnd.hAnd, AndOp.and, land] | ||
unfold bitwise | ||
cases mod_two_eq_zero_or_one x with | _ p => | ||
simp [xz, p, andz, one_div_two, mod_eq_of_lt] | ||
/-! ### bitwise -/ | ||
|
||
@[simp] | ||
theorem bitwise_zero_left (m : Nat) : bitwise f 0 m = if f false true then m else 0 := | ||
rfl | ||
|
||
@[simp] | ||
theorem bitwise_zero_right (n : Nat) : bitwise f n 0 = if f true false then n else 0 := by | ||
unfold bitwise | ||
simp only [ite_self, decide_False, Nat.zero_div, ite_true] | ||
cases n <;> simp | ||
|
||
theorem bitwise_zero : bitwise f 0 0 = 0 := by | ||
simp only [bitwise_zero_right, ite_self] | ||
|
||
/-! ### bit -/ | ||
|
||
theorem bit_val (b n) : bit b n = 2 * n + b.toNat := by | ||
rw [Nat.mul_comm] | ||
induction b with | ||
| false => exact congrArg (· + n) n.zero_add.symm | ||
| true => exact congrArg (· + n + 1) n.zero_add.symm | ||
|
||
@[simp] | ||
theorem bit_div_two (b n) : bit b n / 2 = n := by | ||
rw [bit_val, Nat.add_comm, add_mul_div_left, div_eq_of_lt, Nat.zero_add] | ||
· cases b <;> decide | ||
· decide | ||
|
||
@[simp] | ||
theorem bit_mod_two (b n) : bit b n % 2 = b.toNat := by | ||
cases b <;> simp [bit_val, mul_add_mod] | ||
|
||
theorem mul_two_le_bit {x b n} : x * 2 ≤ bit b n ↔ x ≤ n := by | ||
rw [← le_div_iff_mul_le Nat.two_pos, bit_div_two] | ||
|
||
/-! ### testBit -/ | ||
|
||
@[simp] theorem zero_testBit (i : Nat) : testBit 0 i = false := by | ||
simp only [testBit, zero_shiftRight, zero_and, bne_self_eq_false] | ||
simp only [testBit, zero_shiftRight, and_zero, bne_self_eq_false] | ||
|
||
@[simp] theorem testBit_zero (x : Nat) : testBit x 0 = decide (x % 2 = 1) := by | ||
cases mod_two_eq_zero_or_one x with | _ p => simp [testBit, p] | ||
|
||
@[simp] theorem testBit_succ (x i : Nat) : testBit x (succ i) = testBit (x/2) i := by | ||
@[simp] theorem testBit_succ (x i : Nat) : testBit x (i + 1) = testBit (x / 2) i := by | ||
unfold testBit | ||
simp [shiftRight_succ_inside] | ||
|
||
theorem bit_testBit_zero (b n) : (bit b n).testBit 0 = b := by | ||
simp | ||
|
||
theorem testBit_to_div_mod {x : Nat} : testBit x i = decide (x / 2^i % 2 = 1) := by | ||
induction i generalizing x with | ||
| zero => | ||
|
@@ -88,51 +98,37 @@ theorem testBit_to_div_mod {x : Nat} : testBit x i = decide (x / 2^i % 2 = 1) := | |
| succ i hyp => | ||
simp [hyp, Nat.div_div_eq_div_mul, Nat.pow_succ'] | ||
|
||
@[simp] theorem _root_.Bool.toNat_testBit_zero (b : Bool) : b.toNat.testBit 0 = b := by | ||
cases b <;> rfl | ||
|
||
theorem toNat_testBit (x i : Nat) : | ||
(x.testBit i).toNat = x / 2 ^ i % 2 := by | ||
rw [Nat.testBit_to_div_mod] | ||
rcases Nat.mod_two_eq_zero_or_one (x / 2^i) <;> simp_all | ||
|
||
theorem ne_zero_implies_bit_true {x : Nat} (xnz : x ≠ 0) : ∃ i, testBit x i := by | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
induction x using div2Induction with | ||
| ind x hyp => | ||
have x_pos : x > 0 := Nat.pos_of_ne_zero xnz | ||
match mod_two_eq_zero_or_one x with | ||
| Or.inl mod2_eq => | ||
rw [←div_add_mod x 2] at xnz | ||
simp only [mod2_eq, ne_eq, Nat.mul_eq_zero, Nat.add_zero, false_or] at xnz | ||
have ⟨d, dif⟩ := hyp x_pos xnz | ||
apply Exists.intro (d+1) | ||
simp_all | ||
| Or.inr mod2_eq => | ||
apply Exists.intro 0 | ||
simp_all | ||
induction x using binaryRecFromOne with | ||
| z₀ => exact absurd rfl xnz | ||
| z₁ => exact ⟨0, rfl⟩ | ||
| f b n n0 hyp => | ||
obtain ⟨i, h⟩ := hyp n0 | ||
refine ⟨i + 1, ?_⟩ | ||
rwa [testBit_succ, bit_div_two] | ||
|
||
theorem ne_implies_bit_diff {x y : Nat} (p : x ≠ y) : ∃ i, testBit x i ≠ testBit y i := by | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be renamed (with a deprecation) to |
||
induction y using Nat.div2Induction generalizing x with | ||
| ind y hyp => | ||
cases Nat.eq_zero_or_pos y with | ||
| inl yz => | ||
simp only [yz, Nat.zero_testBit, Bool.eq_false_iff] | ||
simp only [yz] at p | ||
have ⟨i,ip⟩ := ne_zero_implies_bit_true p | ||
apply Exists.intro i | ||
simp [ip] | ||
| inr ypos => | ||
if lsb_diff : x % 2 = y % 2 then | ||
rw [←Nat.div_add_mod x 2, ←Nat.div_add_mod y 2] at p | ||
simp only [ne_eq, lsb_diff, Nat.add_right_cancel_iff, | ||
Nat.zero_lt_succ, Nat.mul_left_cancel_iff] at p | ||
have ⟨i, ieq⟩ := hyp ypos p | ||
apply Exists.intro (i+1) | ||
simpa | ||
else | ||
apply Exists.intro 0 | ||
simp only [testBit_zero] | ||
revert lsb_diff | ||
cases mod_two_eq_zero_or_one x with | _ p => | ||
cases mod_two_eq_zero_or_one y with | _ q => | ||
simp [p,q] | ||
induction y using binaryRec' generalizing x with | ||
| z => | ||
simp only [zero_testBit, Bool.ne_false_iff] | ||
exact ne_zero_implies_bit_true p | ||
| f yb y h hyp => | ||
rw [← x.bit_testBit_zero_shiftRight_one] at * | ||
by_cases hb : testBit x 0 = yb | ||
· subst hb | ||
obtain ⟨i, h⟩ := hyp (mt (congrArg _) p) | ||
refine ⟨i + 1, ?_⟩ | ||
rwa [testBit_succ, bit_div_two, testBit_succ, bit_div_two] | ||
· refine ⟨0, ?_⟩ | ||
simpa using hb | ||
|
||
/-- | ||
`eq_of_testBit_eq` allows proving two natural numbers are equal | ||
|
@@ -146,25 +142,18 @@ theorem eq_of_testBit_eq {x y : Nat} (pred : ∀i, testBit x i = testBit y i) : | |
have p := pred i | ||
contradiction | ||
|
||
theorem ge_two_pow_implies_high_bit_true {x : Nat} (p : x ≥ 2^n) : ∃ i, i ≥ n ∧ testBit x i := by | ||
induction x using div2Induction generalizing n with | ||
| ind x hyp => | ||
have x_pos : x > 0 := Nat.lt_of_lt_of_le (Nat.two_pow_pos n) p | ||
have x_ne_zero : x ≠ 0 := Nat.ne_of_gt x_pos | ||
theorem ge_two_pow_implies_high_bit_true {x : Nat} (p : 2^n ≤ x) : ∃ i, n ≤ i ∧ testBit x i := by | ||
induction x using binaryRec generalizing n with | ||
| z => exact absurd p (Nat.not_le_of_lt n.two_pow_pos) | ||
| f xb x hyp => | ||
match n with | ||
| zero => | ||
let ⟨j, jp⟩ := ne_zero_implies_bit_true x_ne_zero | ||
exact Exists.intro j (And.intro (Nat.zero_le _) jp) | ||
| succ n => | ||
have x_ge_n : x / 2 ≥ 2 ^ n := by | ||
simpa [le_div_iff_mul_le, ← Nat.pow_succ'] using p | ||
have ⟨j, jp⟩ := @hyp x_pos n x_ge_n | ||
apply Exists.intro (j+1) | ||
apply And.intro | ||
case left => | ||
exact (Nat.succ_le_succ jp.left) | ||
case right => | ||
simpa using jp.right | ||
| 0 => | ||
simp only [zero_le, true_and] | ||
exact ne_zero_implies_bit_true (ne_of_gt (Nat.lt_of_succ_le p)) | ||
| n+1 => | ||
obtain ⟨i, h⟩ := hyp (mul_two_le_bit.mp p) | ||
refine ⟨i + 1, ?_⟩ | ||
rwa [Nat.add_le_add_iff_right, testBit_succ, bit_div_two] | ||
|
||
theorem testBit_implies_ge {x : Nat} (p : testBit x i = true) : x ≥ 2^i := by | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, all these |
||
simp only [testBit_to_div_mod] at p | ||
|
@@ -188,8 +177,6 @@ theorem lt_pow_two_of_testBit (x : Nat) (p : ∀i, i ≥ n → testBit x i = fal | |
have test_false := p _ i_ge_n | ||
simp only [test_true] at test_false | ||
|
||
/-! ### testBit -/ | ||
|
||
private theorem succ_mod_two : succ x % 2 = 1 - x % 2 := by | ||
induction x with | ||
| zero => | ||
|
@@ -233,7 +220,7 @@ theorem testBit_two_pow_add_gt {i j : Nat} (j_lt_i : j < i) (x : Nat) : | |
rw [Nat.sub_eq_zero_iff_le] at i_sub_j_eq | ||
exact Nat.not_le_of_gt j_lt_i i_sub_j_eq | ||
| d+1 => | ||
simp [Nat.pow_succ, Nat.mul_comm _ 2, Nat.mul_add_mod] | ||
simp [Nat.pow_succ, Nat.mul_comm _ 2, Nat.mul_add_mod] | ||
|
||
@[simp] theorem testBit_mod_two_pow (x j i : Nat) : | ||
testBit (x % 2^j) i = (decide (i < j) && testBit x i) := by | ||
|
@@ -257,7 +244,7 @@ theorem testBit_two_pow_add_gt {i j : Nat} (j_lt_i : j < i) (x : Nat) : | |
exact Nat.lt_add_of_pos_right (Nat.two_pow_pos j) | ||
simp only [hyp y y_lt_x] | ||
if i_lt_j : i < j then | ||
rw [ Nat.add_comm _ (2^_), testBit_two_pow_add_gt i_lt_j] | ||
rw [Nat.add_comm _ (2^_), testBit_two_pow_add_gt i_lt_j] | ||
else | ||
simp [i_lt_j] | ||
|
||
|
@@ -274,7 +261,7 @@ theorem testBit_two_pow_sub_succ (h₂ : x < 2 ^ n) (i : Nat) : | |
match n with | ||
| 0 => simp [succ_sub_succ_eq_sub] | ||
| n+1 => | ||
simp [not_decide_mod_two_eq_one] | ||
simp [← decide_not] | ||
omega | ||
| succ i ih => | ||
simp only [testBit_succ] | ||
|
@@ -487,3 +474,38 @@ theorem mul_add_lt_is_or {b : Nat} (b_lt : b < 2^i) (a : Nat) : 2^i * a + b = 2^ | |
|
||
@[simp] theorem testBit_shiftRight (x : Nat) : testBit (x >>> i) j = testBit x (i+j) := by | ||
simp [testBit, ←shiftRight_add] | ||
|
||
@[simp] theorem bit_shiftRight_one (b n) : bit b n >>> 1 = n := | ||
bit_div_two b n | ||
|
||
/-! ### binaryRec -/ | ||
|
||
@[simp] | ||
theorem bitCasesOn_bit {C : Nat → Sort u} (h : ∀ b n, C (bit b n)) (b : Bool) (n : Nat) : | ||
bitCasesOn (bit b n) h = h b n := by | ||
change congrArg C (bit b n).bit_testBit_zero_shiftRight_one ▸ h _ _ = h b n | ||
generalize congrArg C (bit b n).bit_testBit_zero_shiftRight_one = e; revert e | ||
rw [bit_testBit_zero, bit_shiftRight_one] | ||
intros; rfl | ||
|
||
@[simp] | ||
theorem binaryRec_zero {C : Nat → Sort u} (z : C 0) (f : ∀ b n, C n → C (bit b n)) : | ||
binaryRec z f 0 = z := | ||
rfl | ||
|
||
theorem binaryRec_eq {C : Nat → Sort u} {z : C 0} {f : ∀ b n, C n → C (bit b n)} (b n) | ||
(h : f false 0 z = z ∨ (n = 0 → b = true)) : | ||
binaryRec z f (bit b n) = f b n (binaryRec z f n) := by | ||
by_cases h' : bit b n = 0 | ||
case pos => | ||
obtain ⟨rfl, rfl⟩ := bit_eq_zero_iff.mp h' | ||
simp only [forall_const, or_false] at h | ||
exact h.symm | ||
case neg => | ||
rw [binaryRec, dif_neg h'] | ||
change congrArg C (bit b n).bit_testBit_zero_shiftRight_one ▸ f _ _ _ = _ | ||
generalize congrArg C (bit b n).bit_testBit_zero_shiftRight_one = e; revert e | ||
rw [bit_testBit_zero, bit_shiftRight_one] | ||
intros; rfl | ||
|
||
end Nat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be
one_and_eq_mod_two
for consistency?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have
Nat.land_bit
Nat.land_comm
Nat.land_assoc
Nat.testBit_land
in Mathlib now.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe those should all be changed too. :-) I'm more concerned about internal consistency in lean4 here.