Zulip Chat Archive

Stream: Is there code for X?

Topic: explicit bitvectors


Jeremy Avigad (Mar 20 2024 at 02:15):

Suppose I want to write a definition of the form

def foo (b0 b1 b2 b3 : Bool) : BitVec 4 := ...

and prove

example (b0 b1 b2 b2 : Bool) : (foo b0 b1 b2 b3).getMsb 0 = b0 := ...
example (b0 b1 b2 b2 : Bool) : (foo b0 b1 b2 b3).getMsb 1 = b1 := ...
example (b0 b1 b2 b2 : Bool) : (foo b0 b1 b2 b3).getMsb 2 = b2 := ...
example (b0 b1 b2 b2 : Bool) : (foo b0 b1 b2 b3).getMsb 3 = b3 := ...

What's the easiest way to define foo and prove those properties? When bitvectors were represented by lists of booleans, we could take the definition to be { val := [b0, b1, b2, b3] } and then the proofs were all rfl.

Mario Carneiro (Mar 20 2024 at 02:30):

there should hopefully be a definition such that the proof is by simp [foo] at least

Kim Morrison (Mar 20 2024 at 02:31):

Yes, I can give you

def foo (b0 b1 b2 b3 : Bool) : BitVec 4 := ofBoolList [b0, b1, b2, b3]

example (b0 b1 b2 b2 : Bool) : (foo b0 b1 b2 b3).getMsb 0 = b0 := by simp [foo]
example (b0 b1 b2 b2 : Bool) : (foo b0 b1 b2 b3).getMsb 1 = b1 := by simp [foo]
example (b0 b1 b2 b2 : Bool) : (foo b0 b1 b2 b3).getMsb 2 = b2 := by simp [foo]
example (b0 b1 b2 b2 : Bool) : (foo b0 b1 b2 b3).getMsb 3 = b3 := by simp [foo]

Kim Morrison (Mar 20 2024 at 02:31):

There's one or two easy sorries, but I could have a PR up shortly.

Mario Carneiro (Mar 20 2024 at 02:32):

although I think it's weird that getMsb would have this effect in this case, I would expect b0 to be the lsb

Mario Carneiro (Mar 20 2024 at 02:33):

I think BE needs to be in the name of ofBoolList there

Kim Morrison (Mar 20 2024 at 02:33):

Sure.

Kim Morrison (Mar 20 2024 at 02:33):

Should there be the pair ofBoolListLE and ofBoolListBE?

Jeremy Avigad (Mar 20 2024 at 02:46):

In the meantime, I got these working:

import Std.Data.BitVec.Lemmas
import Mathlib.Data.Fin.Basic
import Mathlib.Algebra.Order.Sub.Defs

namespace BitVec

variable {n : }

theorem getMsb_cons_zero (b : Bool) (v : BitVec n) : getMsb (cons b v) 0 = b := by
  simp [getMsb, cons, ofBool]
  cases b <;> simp

theorem getMsb_cons_succ (b : Bool) (v : BitVec n) (i : Nat) : getMsb (cons b v) (i + 1) = getMsb v i := by
  by_cases h : i < n
  . have : n - (i + 1) < n := Nat.sub_lt_of_pos_le (Nat.succ_pos _) h
    have : n - 1 - i = n - (i + 1) := by rw [add_comm, tsub_tsub]
    simp [*, getMsb, cons]
  . simp [*, getMsb, cons]

end BitVec

I think that will serve my purposes, but I'll be happy to see a nicer solution.

Kim Morrison (Mar 20 2024 at 02:47):

@Jeremy Avigad, you may be using an old Std: BitVec is all in the Lean repository now.

Kim Morrison (Mar 20 2024 at 02:59):

Also, you need to start using omega. I just also needed to prove getMsb_cons_succ, but just wrote:

@[simp] theorem getMsb_cons_succ : (cons a x).getMsb (i + 1) = x.getMsb i := by
  simp [cons, cond_eq_if]
  omega

:-)

Kim Morrison (Mar 20 2024 at 03:18):

@Jeremy Avigad, would you check if lean#3721 covers what you need?

Jeremy Avigad (Mar 21 2024 at 20:56):

Thank you, @Scott Morrison . I appreciate the help.

ofBoolListBE and getMsb_ofBoolListBE solved the problem I asked about. In terms of recapturing functionality I had with previous versions of BitVec, I needed to convert to and from a Fin n → Bool representation, which I managed to do with this:

def ofFnBE (f : Fin n  Bool) : BitVec n :=
  ofBoolListBE (List.ofFn f) |>.cast (by rw [List.length_ofFn])

theorem getMsb_ofFnBE (f : Fin n  Bool) (i : Fin n) :
    getMsb (ofFnBE f) i = f i := by
  have : i < List.length (List.ofFn f) := by rw [List.length_ofFn]; exact i.2
  simp [ofFnBE, getMsb_cast, List.getD_eq_get, this]

theorem ofFnBE_getMsb : (ofFnBE fun i : Fin n => getMsb b i) = b := by
  apply eq_of_getMsb_eq; intro i; rw [getMsb_ofFnBE]

I had a surprisingly hard time proving that toNat is injective, but I managed it with this:

theorem toNat_inj {n : } {b1 b2 : BitVec n} (h : b1.toNat = b2.toNat) : b1 = b2 := by
  rcases b1 with b1, h1; rcases b2 with b2, h2; cases h; rfl

Kim Morrison (Mar 21 2024 at 21:13):

These look good. Would you like to PR them?

Eric Wieser (Mar 21 2024 at 22:35):

Isn't _inj usually reserved for the Iff lemma?

Jeremy Avigad (Mar 23 2024 at 16:47):

Scott Morrison said:

Would you like to PR them?

Yes, I'll try to do this soon. (I am swamped.)


Last updated: May 02 2025 at 03:31 UTC