This PR both adds initial `@[grind]` annotations for `BitVec`, and uses `grind` to remove many proofs from `BitVec/Lemmas`. --------- Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
157 lines
5.7 KiB
Text
157 lines
5.7 KiB
Text
/-
|
||
Copyright (c) 2023 Lean FRO, LLC. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Joe Hendrix, Harun Khan, Alex Keizer, Abdalrhman M Mohamed, Siddharth Bhat
|
||
-/
|
||
module
|
||
|
||
prelude
|
||
import all Init.Data.BitVec.Basic
|
||
|
||
namespace BitVec
|
||
|
||
theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i := rfl
|
||
|
||
@[simp, grind =] theorem getLsbD_ofFin (x : Fin (2^n)) (i : Nat) :
|
||
getLsbD (BitVec.ofFin x) i = x.val.testBit i := rfl
|
||
|
||
@[simp, grind] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false := by
|
||
let ⟨x, x_lt⟩ := x
|
||
simp only [getLsbD_ofFin]
|
||
apply Nat.testBit_lt_two_pow
|
||
have p : 2^w ≤ 2^i := Nat.pow_le_pow_right (by omega) ge
|
||
omega
|
||
|
||
/-- Prove equality of bitvectors in terms of nat operations. -/
|
||
theorem eq_of_toNat_eq {n} : ∀ {x y : BitVec n}, x.toNat = y.toNat → x = y
|
||
| ⟨_, _⟩, ⟨_, _⟩, rfl => rfl
|
||
|
||
theorem eq_of_getLsbD_eq {x y : BitVec w}
|
||
(pred : ∀ i, i < w → x.getLsbD i = y.getLsbD i) : x = y := by
|
||
apply eq_of_toNat_eq
|
||
apply Nat.eq_of_testBit_eq
|
||
intro i
|
||
if i_lt : i < w then
|
||
exact pred i i_lt
|
||
else
|
||
have p : i ≥ w := Nat.le_of_not_gt i_lt
|
||
simp [testBit_toNat, getLsbD_of_ge _ _ p]
|
||
|
||
@[simp, bitvec_to_nat, grind =]
|
||
theorem toNat_ofNat (x w : Nat) : (BitVec.ofNat w x).toNat = x % 2^w := by
|
||
simp [BitVec.toNat, BitVec.ofNat, Fin.ofNat]
|
||
|
||
@[ext, grind ext] theorem eq_of_getElem_eq {x y : BitVec n} :
|
||
(∀ i (hi : i < n), x[i] = y[i]) → x = y :=
|
||
fun h => BitVec.eq_of_getLsbD_eq (h ↑·)
|
||
|
||
@[simp, grind =] theorem toNat_append (x : BitVec m) (y : BitVec n) :
|
||
(x ++ y).toNat = x.toNat <<< n ||| y.toNat :=
|
||
rfl
|
||
|
||
@[simp, grind =] theorem toNat_ofBool (b : Bool) : (ofBool b).toNat = b.toNat := by
|
||
cases b <;> rfl
|
||
|
||
@[simp, bitvec_to_nat, grind =]
|
||
theorem toNat_cast (h : w = v) (x : BitVec w) : (x.cast h).toNat = x.toNat := rfl
|
||
|
||
@[simp, bitvec_to_nat, grind =]
|
||
theorem toNat_ofFin (x : Fin (2^n)) : (BitVec.ofFin x).toNat = x.val := rfl
|
||
|
||
@[simp, grind =] theorem toNat_ofNatLT (x : Nat) (p : x < 2^w) : (x#'p).toNat = x := rfl
|
||
|
||
@[simp, grind =] theorem toNat_cons (b : Bool) (x : BitVec w) :
|
||
(cons b x).toNat = (b.toNat <<< w) ||| x.toNat := by
|
||
let ⟨x, _⟩ := x
|
||
simp only [cons, toNat_cast, toNat_append, toNat_ofBool, toNat_ofFin]
|
||
|
||
@[grind =]
|
||
theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
|
||
(cons b x)[i] = if h : i = n then b else x[i] := by
|
||
simp only [getElem_eq_testBit_toNat, toNat_cons, Nat.testBit_or]
|
||
rw [Nat.testBit_shiftLeft]
|
||
rcases Nat.lt_trichotomy i n with i_lt_n | i_eq_n | n_lt_i
|
||
· have p1 : ¬(n ≤ i) := by omega
|
||
have p2 : i ≠ n := by omega
|
||
simp [p1, p2]
|
||
· simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_true, Nat.sub_self, Nat.testBit_zero,
|
||
Bool.true_and, testBit_toNat, getLsbD_of_ge, Bool.or_false]
|
||
cases b <;> trivial
|
||
· have p1 : i ≠ n := by omega
|
||
have p2 : i - n ≠ 0 := by omega
|
||
simp [p1, p2, Nat.testBit_bool_toNat]
|
||
|
||
private theorem lt_two_pow_of_le {x m n : Nat} (lt : x < 2 ^ m) (le : m ≤ n) : x < 2 ^ n :=
|
||
Nat.lt_of_lt_of_le lt (Nat.pow_le_pow_right (by trivial : 0 < 2) le)
|
||
|
||
@[simp, bitvec_to_nat, grind =]
|
||
theorem toNat_setWidth' {m n : Nat} (p : m ≤ n) (x : BitVec m) :
|
||
(setWidth' p x).toNat = x.toNat := by
|
||
simp only [setWidth', toNat_ofNatLT]
|
||
|
||
@[simp, bitvec_to_nat, grind =]
|
||
theorem toNat_setWidth (i : Nat) (x : BitVec n) :
|
||
(setWidth i x).toNat = x.toNat % 2^i := by
|
||
let ⟨x, lt_n⟩ := x
|
||
simp only [setWidth]
|
||
if n_le_i : n ≤ i then
|
||
have x_lt_two_i : x < 2 ^ i := lt_two_pow_of_le lt_n n_le_i
|
||
simp [n_le_i, Nat.mod_eq_of_lt, x_lt_two_i]
|
||
else
|
||
simp [n_le_i, toNat_ofNat]
|
||
|
||
@[simp, grind =]
|
||
theorem ofNat_toNat (m : Nat) (x : BitVec n) : BitVec.ofNat m x.toNat = setWidth m x := by
|
||
apply eq_of_toNat_eq
|
||
simp only [toNat_ofNat, toNat_setWidth]
|
||
|
||
@[grind =]
|
||
theorem getElem_setWidth' (x : BitVec w) (i : Nat) (h : w ≤ v) (hi : i < v) :
|
||
(setWidth' h x)[i] = x.getLsbD i := by
|
||
rw [getElem_eq_testBit_toNat, toNat_setWidth', getLsbD]
|
||
|
||
@[simp, grind =]
|
||
theorem getElem_setWidth (m : Nat) (x : BitVec n) (i : Nat) (h : i < m) :
|
||
(setWidth m x)[i] = x.getLsbD i := by
|
||
rw [setWidth]
|
||
split
|
||
· rw [getElem_setWidth']
|
||
· simp only [ofNat_toNat, getElem_eq_testBit_toNat, toNat_setWidth, Nat.testBit_mod_two_pow,
|
||
getLsbD, Bool.and_eq_right_iff_imp, decide_eq_true_eq]
|
||
omega
|
||
|
||
-- Later this is provable by `grind`, so doesn't need an annotation.
|
||
@[simp] theorem cons_msb_setWidth (x : BitVec (w+1)) : (cons x.msb (x.setWidth w)) = x := by
|
||
ext i
|
||
simp only [getElem_cons]
|
||
split <;> rename_i h
|
||
· simp [BitVec.msb, getMsbD, h]
|
||
· by_cases h' : i < w
|
||
· simp_all only [getElem_setWidth, getLsbD_eq_getElem]
|
||
· omega
|
||
|
||
@[simp, bitvec_to_nat, grind =]
|
||
theorem toNat_neg (x : BitVec n) : (- x).toNat = (2^n - x.toNat) % 2^n := by
|
||
simp [Neg.neg, BitVec.neg]
|
||
|
||
@[simp, grind =]
|
||
theorem setWidth_neg_of_le {x : BitVec v} (h : w ≤ v) : BitVec.setWidth w (-x) = -BitVec.setWidth w x := by
|
||
apply BitVec.eq_of_toNat_eq
|
||
simp only [toNat_setWidth, toNat_neg]
|
||
rw [Nat.mod_mod_of_dvd _ (Nat.pow_dvd_pow 2 h)]
|
||
rw [Nat.mod_eq_mod_iff]
|
||
rw [Nat.mod_def]
|
||
refine ⟨1 + x.toNat / 2^w, 2^(v-w), ?_⟩
|
||
rw [← Nat.pow_add]
|
||
have : v - w + w = v := by omega
|
||
rw [this]
|
||
rw [Nat.add_mul, Nat.one_mul, Nat.mul_comm (2^w)]
|
||
have sub_sub : ∀ (a : Nat) {b c : Nat} (h : c ≤ b), a - (b - c) = a + c - b := by omega
|
||
rw [sub_sub _ (Nat.div_mul_le_self x.toNat (2 ^ w))]
|
||
have : x.toNat / 2 ^ w * 2 ^ w ≤ x.toNat := Nat.div_mul_le_self x.toNat (2 ^ w)
|
||
have : x.toNat < 2 ^w ∨ x.toNat - 2 ^ w < x.toNat / 2 ^ w * 2 ^ w := by
|
||
have := Nat.lt_div_mul_add (a := x.toNat) (b := 2 ^ w) (Nat.two_pow_pos w)
|
||
omega
|
||
omega
|
||
|
||
end BitVec
|