Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit e3d2f74

Browse files
committed
feat(data/nat): Add new binary recursors; prove the relationship between nat.bits and other pieces of code (#14990)
This is in connection to #13208, because I was asked to write `to_bits` in terms of `nat.size` and `nat.bits`, but `nat.bits` was hard to use (there were no lemmas about it). This PR proves some statements about `nat.bits`, so that it can finally be used.
1 parent dffc243 commit e3d2f74

File tree

4 files changed

+125
-0
lines changed

4 files changed

+125
-0
lines changed

src/data/list/basic.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4086,6 +4086,9 @@ lemma inth_eq_iget_nth (n : ℕ) :
40864086
l.inth n = (l.nth n).iget :=
40874087
by rw [←nthd_default_eq_inth, nthd_eq_get_or_else_nth, option.get_or_else_default_eq_iget]
40884088

4089+
lemma inth_zero_eq_head : l.inth 0 = l.head :=
4090+
by { cases l; refl, }
4091+
40894092
end inth
40904093

40914094
end list

src/data/nat/bits.lean

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/-
2+
Copyright (c) 2022 Praneeth Kolichala. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Praneeth Kolichala
5+
-/
6+
import tactic.generalize_proofs
7+
import tactic.norm_num
8+
9+
/-!
10+
# Additional properties of binary recursion on `nat`
11+
12+
This file documents additional properties of binary recursion,
13+
which allows us to more easily work with operations which do depend
14+
on the number of leading zeros in the binary representation of `n`.
15+
For example, we can more easily work with `nat.bits` and `nat.size`.
16+
17+
See also: `nat.bitwise`, `nat.pow` (for various lemmas about `size` and `shiftl`/`shiftr`),
18+
and `nat.digits`.
19+
-/
20+
21+
namespace nat
22+
23+
lemma bit_eq_zero_iff {n : ℕ} {b : bool} : bit b n = 0 ↔ n = 0 ∧ b = ff :=
24+
by { split, { cases b; simp [nat.bit], }, rintro ⟨rfl, rfl⟩, refl, }
25+
26+
/-- The same as binary_rec_eq, but that one unfortunately requires `f` to be the identity when
27+
appending `ff` to `0`. Here, we allow you to explicitly say that that case is not happening, i.e.
28+
supplying `n = 0 → b = tt`. -/
29+
lemma binary_rec_eq' {C : ℕ → Sort*} {z : C 0} {f : ∀ b n, C n → C (bit b n)}
30+
(b n) (h : f ff 0 z = z ∨ (n = 0 → b = tt)) :
31+
binary_rec z f (bit b n) = f b n (binary_rec z f n) :=
32+
begin
33+
rw [binary_rec],
34+
split_ifs with h',
35+
{ rcases bit_eq_zero_iff.mp h' with ⟨rfl, rfl⟩,
36+
rw binary_rec_zero,
37+
simp only [imp_false, or_false, eq_self_iff_true, not_true] at h,
38+
exact h.symm },
39+
{ generalize_proofs e, revert e,
40+
rw [bodd_bit, div2_bit],
41+
intros, refl, }
42+
end
43+
44+
/-- The same as `binary_rec`, but the induction step can assume that if `n=0`,
45+
the bit being appended is `tt`-/
46+
@[elab_as_eliminator]
47+
def binary_rec' {C : ℕ → Sort*} (z : C 0) (f : ∀ b n, (n = 0 → b = tt) → C n → C (bit b n)) :
48+
∀ n, C n :=
49+
binary_rec z (λ b n ih, if h : n = 0 → b = tt then f b n h ih else
50+
by { convert z, rw bit_eq_zero_iff, simpa using h, })
51+
52+
/-- The same as `binary_rec`, but special casing both 0 and 1 as base cases -/
53+
@[elab_as_eliminator]
54+
def binary_rec_from_one {C : ℕ → Sort*} (z₀ : C 0) (z₁ : C 1)
55+
(f : ∀ b n, n ≠ 0 → C n → C (bit b n)) : ∀ n, C n :=
56+
binary_rec' z₀ (λ b n h ih, if h' : n = 0 then by { rw [h', h h'], exact z₁ } else f b n h' ih)
57+
58+
@[simp] lemma zero_bits : bits 0 = [] := by simp [nat.bits]
59+
60+
@[simp] lemma bits_append_bit (n : ℕ) (b : bool) (hn : n = 0 → b = tt) :
61+
(bit b n).bits = b :: n.bits :=
62+
by { rw [nat.bits, binary_rec_eq'], simpa, }
63+
64+
@[simp] lemma bit0_bits (n : ℕ) (hn : n ≠ 0) : (bit0 n).bits = ff :: n.bits :=
65+
bits_append_bit n ff (λ hn', absurd hn' hn)
66+
67+
@[simp] lemma bit1_bits (n : ℕ) : (bit1 n).bits = tt :: n.bits :=
68+
bits_append_bit n tt (λ _, rfl)
69+
70+
@[simp] lemma one_bits : nat.bits 1 = [tt] := by { convert bit1_bits 0, simp, }
71+
72+
example : bits 3423 = [tt, tt, tt, tt, tt, ff, tt, ff, tt, ff, tt, tt] := by norm_num
73+
74+
lemma bodd_eq_bits_head (n : ℕ) : n.bodd = n.bits.head :=
75+
begin
76+
induction n using nat.binary_rec' with b n h ih, { simp, },
77+
simp [bodd_bit, bits_append_bit _ _ h],
78+
end
79+
80+
lemma div2_bits_eq_tail (n : ℕ) : n.div2.bits = n.bits.tail :=
81+
begin
82+
induction n using nat.binary_rec' with b n h ih, { simp, },
83+
simp [div2_bit, bits_append_bit _ _ h],
84+
end
85+
86+
lemma size_eq_bits_len (n : ℕ) : n.bits.length = n.size :=
87+
begin
88+
induction n using nat.binary_rec' with b n h ih, { simp, },
89+
rw [size_bit, bits_append_bit _ _ h],
90+
{ simp [ih], },
91+
{ simpa [bit_eq_zero_iff], }
92+
end
93+
94+
end nat

src/data/nat/bitwise.lean

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Copyright (c) 2020 Markus Himmel. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Markus Himmel
55
-/
6+
import data.nat.bits
67
import tactic.linarith
78

89
/-!
@@ -51,6 +52,16 @@ end
5152
@[simp] lemma zero_test_bit (i : ℕ) : test_bit 0 i = ff :=
5253
by simp [test_bit]
5354

55+
/-- The ith bit is the ith element of `n.bits`. -/
56+
lemma test_bit_eq_inth (n i : ℕ) : n.test_bit i = n.bits.inth i :=
57+
begin
58+
induction i with i ih generalizing n,
59+
{ simp [test_bit, shiftr, bodd_eq_bits_head, list.inth_zero_eq_head], },
60+
conv_lhs { rw ← bit_decomp n, },
61+
rw [test_bit_succ, ih n.div2, div2_bits_eq_tail],
62+
cases n.bits; simp,
63+
end
64+
5465
/-- Bitwise extensionality: Two numbers agree if they agree at every bit position. -/
5566
lemma eq_of_test_bit_eq {n m : ℕ} (h : ∀ i, test_bit n i = test_bit m i) : n = m :=
5667
begin

src/data/nat/digits.lean

Lines changed: 17 additions & 0 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: Scott Morrison, Shing Tak Lam, Mario Carneiro
55
-/
66
import data.int.modeq
7+
import data.nat.bits
78
import data.nat.log
89
import data.nat.parity
910
import data.list.indexes
@@ -471,6 +472,22 @@ begin
471472
exact base_pow_length_digits_le' b m,
472473
end
473474

475+
/-! ### Binary -/
476+
lemma digits_two_eq_bits (n : ℕ) : digits 2 n = n.bits.map (λ b, cond b 1 0) :=
477+
begin
478+
induction n using nat.binary_rec_from_one with b n h ih,
479+
{ simp, },
480+
{ simp, },
481+
rw bits_append_bit _ _ (λ hn, absurd hn h),
482+
cases b,
483+
{ rw digits_def' (le_refl 2),
484+
{ simpa [nat.bit, nat.bit0_val n], },
485+
{ simpa [pos_iff_ne_zero, bit_eq_zero_iff], }, },
486+
{ simpa [nat.bit, nat.bit1_val n, add_comm, digits_add 2 le_rfl 1 n (by norm_num)
487+
(by norm_num)] },
488+
end
489+
490+
474491
/-! ### Modular Arithmetic -/
475492

476493
-- This is really a theorem about polynomials.

0 commit comments

Comments
 (0)