-
Notifications
You must be signed in to change notification settings - Fork 449
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
feat: add BitVec.(msb, getMsbD, getLsbD)_(neg, abs)
#5721
Conversation
Mathlib CI status (docs):
|
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.
@luisacicolini I pushed a proof of msb_neg. I did have to use results from the Bitblast.lean
file. For now, I copied the statements to Lemmas and sorried them out, but we'll have to move msb_neg
et al to Bitblast.lean eventually (or another file that imports Bitblast.lean but has all the non-bitblasting lemmas that use bitblast results, which is an idea I'm starting to like more, the more we encounter this type of situation)
Thank you very much @kim-em for reviewing this! All comments should be addressed now. |
awaiting-review |
src/Init/Data/BitVec/Bitblast.lean
Outdated
getLsbD (-x) i = | ||
(getLsbD x i ^^ decide (i < w ∧ ∃ j < i, getLsbD x j = true)) := by |
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.
Would
(-x).getLsbD i = (x.getLsbD i ^^ decide (i < w) && decide (∃ j, j < i ∧ x.getLsbD j = true))
be okay here? This is what simp
would transform the goal into.
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.
Jup. Personally, I don't really like having so many separate decide
s floating around, but it is the simp normal form, so we should write it like you suggest. I just pushed the change
src/Init/Data/BitVec/Bitblast.lean
Outdated
exact ⟨w - 1 - j, by omega, h⟩ | ||
|
||
theorem msb_neg {w : Nat} {x : BitVec w} : | ||
(-x).msb = ((decide (x ≠ 0#w) && decide (x ≠ intMin w)) ^^ x.msb) := by |
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.
(-x).msb = ((decide (x ≠ 0#w) && decide (x ≠ intMin w)) ^^ x.msb) := by | |
(-x).msb = (((x != 0#w) && (x != intMin w)) ^^ x.msb) := by |
Does this work? Seems slightly easier to just keep decide
out of the statements when bool valued relations are available.
(Generally, I'm unhappy about how often we need decide
in the BitVec API, but I don't have good solutions.)
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.
It does, with a slightly amended proof I literally just pushed.
theorem msb_neg {w : Nat} {x : BitVec w} : | ||
(-x).msb = ((x != 0#w && x != intMin w) ^^ x.msb) := by | ||
simp only [BitVec.msb, getMsbD_neg] | ||
by_cases hmin : x = intMin _ | ||
case pos => | ||
have : (∃ j, j < w ∧ 0 < j ∧ 0 < w ∧ j = 0) ↔ False := by | ||
simp; omega | ||
simp [hmin, getMsbD_intMin, this] | ||
case neg => | ||
by_cases hzero : x = 0#w | ||
case pos => simp [hzero] | ||
case neg => | ||
have w_pos : 0 < w := by | ||
cases w | ||
· rw [@of_length_zero x] at hzero | ||
contradiction | ||
· omega | ||
suffices ∃ j, j < w ∧ 0 < j ∧ x.getMsbD j = true | ||
by simp [show x != 0#w by simpa, show x != intMin w by simpa, this] | ||
false_or_by_contra | ||
rename_i getMsbD_x | ||
simp only [not_exists, _root_.not_and, not_eq_true] at getMsbD_x | ||
/- `getMsbD` says that all bits except the msb are `false` -/ | ||
cases hmsb : x.msb | ||
case true => | ||
apply hmin | ||
apply eq_of_getMsbD_eq | ||
rintro ⟨i, hi⟩ | ||
simp only [getMsbD_intMin, w_pos, decide_True, Bool.true_and] | ||
cases i | ||
case zero => exact hmsb | ||
case succ => exact getMsbD_x _ hi (by omega) | ||
case false => | ||
apply hzero | ||
apply eq_of_getMsbD_eq | ||
rintro ⟨i, hi⟩ | ||
simp only [getMsbD_zero] | ||
cases i | ||
case zero => exact hmsb | ||
case succ => exact getMsbD_x _ hi (by omega) |
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.
theorem msb_neg {w : Nat} {x : BitVec w} : | |
(-x).msb = ((x != 0#w && x != intMin w) ^^ x.msb) := by | |
simp only [BitVec.msb, getMsbD_neg] | |
by_cases hmin : x = intMin _ | |
case pos => | |
have : (∃ j, j < w ∧ 0 < j ∧ 0 < w ∧ j = 0) ↔ False := by | |
simp; omega | |
simp [hmin, getMsbD_intMin, this] | |
case neg => | |
by_cases hzero : x = 0#w | |
case pos => simp [hzero] | |
case neg => | |
have w_pos : 0 < w := by | |
cases w | |
· rw [@of_length_zero x] at hzero | |
contradiction | |
· omega | |
suffices ∃ j, j < w ∧ 0 < j ∧ x.getMsbD j = true | |
by simp [show x != 0#w by simpa, show x != intMin w by simpa, this] | |
false_or_by_contra | |
rename_i getMsbD_x | |
simp only [not_exists, _root_.not_and, not_eq_true] at getMsbD_x | |
/- `getMsbD` says that all bits except the msb are `false` -/ | |
cases hmsb : x.msb | |
case true => | |
apply hmin | |
apply eq_of_getMsbD_eq | |
rintro ⟨i, hi⟩ | |
simp only [getMsbD_intMin, w_pos, decide_True, Bool.true_and] | |
cases i | |
case zero => exact hmsb | |
case succ => exact getMsbD_x _ hi (by omega) | |
case false => | |
apply hzero | |
apply eq_of_getMsbD_eq | |
rintro ⟨i, hi⟩ | |
simp only [getMsbD_zero] | |
cases i | |
case zero => exact hmsb | |
case succ => exact getMsbD_x _ hi (by omega) | |
theorem msb_neg {w : Nat} {x : BitVec w} : | |
(-x).msb = ((x != 0#w && x != intMin w) ^^ x.msb) := by | |
simp only [BitVec.msb, getMsbD_neg] | |
by_cases hmin : x = intMin _ | |
· have : (∃ j, j < w ∧ 0 < j ∧ 0 < w ∧ j = 0) ↔ False := by | |
simp; omega | |
simp [hmin, getMsbD_intMin, this] | |
· by_cases hzero : x = 0#w | |
· simp [hzero] | |
· have w_pos : 0 < w := by | |
cases w | |
· rw [@of_length_zero x] at hzero | |
contradiction | |
· omega | |
suffices ∃ j, j < w ∧ 0 < j ∧ x.getMsbD j = true | |
by simp [show x != 0#w by simpa, show x != intMin w by simpa, this] | |
false_or_by_contra | |
rename_i getMsbD_x | |
simp only [not_exists, _root_.not_and, not_eq_true] at getMsbD_x | |
/- `getMsbD` says that all bits except the msb are `false` -/ | |
cases hmsb : x.msb with | |
| true => | |
apply hmin | |
apply eq_of_getMsbD_eq | |
rintro ⟨i, hi⟩ | |
simp only [getMsbD_intMin, w_pos, decide_True, Bool.true_and] | |
cases i with | |
| zero => exact hmsb | |
| succ => exact getMsbD_x _ hi (by omega) | |
| false => | |
apply hzero | |
apply eq_of_getMsbD_eq | |
rintro ⟨i, hi⟩ | |
simp only [getMsbD_zero] | |
cases i with | |
| zero => exact hmsb | |
| succ => exact getMsbD_x _ hi (by omega) |
@kim-em Is the preference for cases _ with | zero => ...
over case zero => ...
a universal one, or just in those specific cases you pointed out before? I did a pass and noticed a few more uses of the latter
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.
It is a mild, personal, universal preference. i.e. I always use with
in every situation, but I don't particularly object to the other forms.
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.
Let's not worry about this. Otherwise everything looks good now.
No description provided.