Skip to content
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: redefine Nat.bit Nat.div2 Nat.bodd #13649

Open
wants to merge 46 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c047c64
chore: redefine `Nat.binaryRec` `Nat.div2` `Nat.bodd`
FR-vdash-bot Jun 9, 2024
5ccab29
Update Mathlib.lean
FR-vdash-bot Jun 9, 2024
9f429e9
fix
FR-vdash-bot Jun 9, 2024
7ffe999
Merge branch 'master' into FR_binrec
FR-vdash-bot Jul 13, 2024
584c3ce
fix
FR-vdash-bot Jul 13, 2024
fde50df
fix
FR-vdash-bot Jul 13, 2024
68a2c0b
fix
FR-vdash-bot Jul 13, 2024
ea3360b
shake
FR-vdash-bot Jul 13, 2024
6392674
fix
FR-vdash-bot Jul 13, 2024
77d68ab
Merge branch 'master' into FR_binrec
FR-vdash-bot Jul 15, 2024
bd0c24f
Merge branch 'master' into FR_binrec
FR-vdash-bot Jul 15, 2024
fd5c58d
fix merge
FR-vdash-bot Jul 15, 2024
049d442
fix
FR-vdash-bot Jul 15, 2024
16a10ce
fix
FR-vdash-bot Jul 15, 2024
7398e5b
fix
FR-vdash-bot Jul 15, 2024
4a9fd6e
Merge branch 'master' into FR_binrec
FR-vdash-bot Jul 17, 2024
ccb809c
fix
FR-vdash-bot Jul 17, 2024
38780b5
fix
FR-vdash-bot Jul 17, 2024
e056180
fix
FR-vdash-bot Jul 17, 2024
199117a
shake
FR-vdash-bot Jul 17, 2024
27734ef
Merge branch 'master' into FR_binrec
FR-vdash-bot Jul 17, 2024
84535ce
Merge branch 'master' into FR_binrec
FR-vdash-bot Jul 24, 2024
40ed248
shake
FR-vdash-bot Jul 24, 2024
80ce83e
fix
FR-vdash-bot Jul 24, 2024
e57a5d9
fix
FR-vdash-bot Jul 24, 2024
2046094
fix
FR-vdash-bot Jul 24, 2024
432eaec
fix
FR-vdash-bot Jul 24, 2024
9d9ccda
fix
FR-vdash-bot Jul 24, 2024
2097400
fix
FR-vdash-bot Jul 24, 2024
194bf44
Merge branch 'master' into FR_binrec
FR-vdash-bot Jul 27, 2024
d32d5c6
Merge branch 'master' into FR_binrec
FR-vdash-bot Jul 27, 2024
7a00093
Merge branch 'master' into FR_binrec
FR-vdash-bot Aug 2, 2024
7c3e5b3
Merge branch 'master' into FR_binrec
FR-vdash-bot Aug 6, 2024
6b19c7e
name
FR-vdash-bot Aug 6, 2024
871aa5f
golf
FR-vdash-bot Aug 6, 2024
19b05e0
golf
FR-vdash-bot Aug 6, 2024
3389c1d
Merge branch 'master' into FR_binrec
FR-vdash-bot Oct 22, 2024
8b6ae3b
split to #18039
FR-vdash-bot Oct 22, 2024
ccbbd75
fix merge
FR-vdash-bot Oct 22, 2024
4855c89
cleanup
FR-vdash-bot Oct 22, 2024
d1de536
cleanup
FR-vdash-bot Oct 22, 2024
c47385f
fix merge
FR-vdash-bot Oct 22, 2024
9bfda89
`Nat.bit`
FR-vdash-bot Oct 22, 2024
d569f2d
fix merge
FR-vdash-bot Oct 22, 2024
2983872
fix
FR-vdash-bot Oct 22, 2024
7e64fc8
fix merge
FR-vdash-bot Oct 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Mathlib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -2285,6 +2285,7 @@ import Mathlib.Data.NNRat.Defs
import Mathlib.Data.NNRat.Lemmas
import Mathlib.Data.NNReal.Basic
import Mathlib.Data.NNReal.Star
import Mathlib.Data.Nat.BinaryRec
import Mathlib.Data.Nat.BitIndices
import Mathlib.Data.Nat.Bits
import Mathlib.Data.Nat.Bitwise
Expand Down
2 changes: 1 addition & 1 deletion Mathlib/Computability/Primrec.lean
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ instance sum : Primcodable (α ⊕ β) :=
to₂ <| nat_double.comp (Primrec.encode.comp snd)))).of_eq
fun n =>
show _ = encode (decodeSum n) by
simp only [decodeSum, Nat.boddDiv2_eq]
simp only [decodeSum]
cases Nat.bodd n <;> simp [decodeSum]
· cases @decode α _ n.div2 <;> rfl
· cases @decode β _ n.div2 <;> rfl⟩
Expand Down
10 changes: 5 additions & 5 deletions Mathlib/Data/Int/Bitwise.lean
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,12 @@ theorem bodd_bit (b n) : bodd (bit b n) = b := by
cases b <;> cases bodd n <;> simp [(show bodd 2 = false by rfl)]

@[simp]
theorem testBit_bit_zero (b) : ∀ n, testBit (bit b n) 0 = b
| (n : ℕ) => by rw [bit_coe_nat]; apply Nat.testBit_bit_zero
theorem bit_testBit_zero (b) : ∀ n, testBit (bit b n) 0 = b
FR-vdash-bot marked this conversation as resolved.
Show resolved Hide resolved
| (n : ℕ) => by rw [bit_coe_nat]; apply Nat.bit_testBit_zero
| -[n+1] => by
rw [bit_negSucc]; dsimp [testBit]; rw [Nat.testBit_bit_zero]; clear testBit_bit_zero
cases b <;>
rfl
rw [bit_negSucc]; dsimp [testBit]; rw [Nat.bit_testBit_zero, Bool.not_not]

@[deprecated (since := "2024-06-09")] alias testBit_bit_zero := bit_testBit_zero

@[simp]
theorem testBit_bit_succ (m b) : ∀ n, testBit (bit b n) (Nat.succ m) = testBit n m
Expand Down
133 changes: 133 additions & 0 deletions Mathlib/Data/Nat/BinaryRec.lean
eric-wieser marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/-
Copyright (c) 2022 Praneeth Kolichala. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Praneeth Kolichala, Yuyang Zhao
-/

/-!
# Binary recursion on `Nat`

This file defines binary recursion on `Nat`.

## Main results
* `Nat.binaryRec`: A recursion principle for `bit` representations of natural numbers.
* `Nat.binaryRec'`: The same as `binaryRec`, but the induction step can assume that if `n=0`,
the bit being appended is `true`.
* `Nat.binaryRecFromOne`: The same as `binaryRec`, but special casing both 0 and 1 as base cases.
-/

universe u

namespace Nat

/-- `bit b` appends the digit `b` to the little end of the binary representation of
its natural number input. -/
def bit (b : Bool) (n : Nat) : Nat :=
cond b (n <<< 1 + 1) (n <<< 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably | 1 is also faster than + 1, if you're really micro-optimizing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not faster in my tests. Also it would make proofs much more complicated.


theorem shiftRight_one (n) : n >>> 1 = n / 2 := rfl

theorem bit_testBit_zero_shiftRight_one (n : Nat) : bit (n.testBit 0) (n >>> 1) = n := by
simp only [bit, testBit_zero]
cases mod_two_eq_zero_or_one n with | _ h => simpa [h] using Nat.div_add_mod n 2

@[simp]
theorem bit_eq_zero_iff {n : Nat} {b : Bool} : bit b n = 0 ↔ n = 0 ∧ b = false := by
cases n <;> cases b <;> simp [bit, Nat.shiftLeft_succ, Nat.two_mul, ← Nat.add_assoc]

/-- For a predicate `C : Nat → Sort u`, if instances can be
constructed for natural numbers of the form `bit b n`,
they can be constructed for any given natural number. -/
@[inline]
def bitCasesOn {C : Nat → Sort u} (n) (h : ∀ b n, C (bit b n)) : C n :=
-- `1 &&& n != 0` is faster than `n.testBit 0`. This may change when we have faster `testBit`.
let x := h (1 &&& n != 0) (n >>> 1)
-- `congrArg C _` is `rfl` in non-dependent case
congrArg C n.bit_testBit_zero_shiftRight_one ▸ x

/-- A recursion principle for `bit` representations of natural numbers.
For a predicate `C : Nat → Sort u`, if instances can be
constructed for natural numbers of the form `bit b n`,
they can be constructed for all natural numbers. -/
@[elab_as_elim, specialize]
def binaryRec {C : Nat → Sort u} (z : C 0) (f : ∀ b n, C n → C (bit b n)) (n : Nat) : C n :=
if n0 : n = 0 then congrArg C n0 ▸ z
else
let x := f (1 &&& n != 0) (n >>> 1) (binaryRec z f (n >>> 1))
congrArg C n.bit_testBit_zero_shiftRight_one ▸ x
decreasing_by exact bitwise_rec_lemma n0

/-- The same as `binaryRec`, but the induction step can assume that if `n=0`,
the bit being appended is `true`-/
@[elab_as_elim, specialize]
def binaryRec' {C : Nat → Sort u} (z : C 0)
(f : ∀ b n, (n = 0 → b = true) → C n → C (bit b n)) : ∀ n, C n :=
binaryRec z fun b n ih =>
if h : n = 0 → b = true then f b n h ih
else
have : bit b n = 0 := by
rw [bit_eq_zero_iff]
cases n <;> cases b <;> simp at h <;> simp [h]
congrArg C this ▸ z

/-- The same as `binaryRec`, but special casing both 0 and 1 as base cases -/
@[elab_as_elim, specialize]
def binaryRecFromOne {C : Nat → Sort u} (z₀ : C 0) (z₁ : C 1)
(f : ∀ b n, n ≠ 0 → C n → C (bit b n)) : ∀ n, C n :=
binaryRec' z₀ fun b n h ih =>
if h' : n = 0 then
have : bit b n = bit true 0 := by
rw [h', h h']
congrArg C this ▸ z₁
else f b n h' ih

theorem bit_val (b n) : bit b n = 2 * n + b.toNat := by
cases b <;> rfl

@[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]

@[simp] theorem bit_shiftRight_one (b n) : bit b n >>> 1 = n :=
bit_div_two b n

theorem bit_testBit_zero (b n) : (bit b n).testBit 0 = b := by
simp

@[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

unseal binaryRec in
@[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
unfold binaryRec
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
4 changes: 2 additions & 2 deletions Mathlib/Data/Nat/BitIndices.lean
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ def bitIndices (n : ℕ) : List ℕ :=

theorem bitIndices_bit_true (n : ℕ) :
bitIndices (bit true n) = 0 :: ((bitIndices n).map (· + 1)) :=
binaryRec_eq rfl _ _
binaryRec_eq _ _ (.inl rfl)

theorem bitIndices_bit_false (n : ℕ) :
bitIndices (bit false n) = (bitIndices n).map (· + 1) :=
binaryRec_eq rfl _ _
binaryRec_eq _ _ (.inl rfl)

@[simp] theorem bitIndices_two_mul_add_one (n : ℕ) :
bitIndices (2 * n + 1) = 0 :: (bitIndices n).map (· + 1) := by
Expand Down
Loading
Loading