Zulip Chat Archive
Stream: new members
Topic: Variable Macro For bv_decide
Oscar Bender-Stone (Jan 03 2025 at 15:19):
I am trying to use bv_decide on a vector of variables, and it returns with a "potientially spurious counterexample":
import Mathlib.Data.BitVec
import Std.Tactic.BVDecide
/- The prover found a counterexample, consider the following assignment: -/
/- x = 0x3#2 -/
/- y = 0x3#2 -/
lemma test (x y : BitVec 2): x &&& ~~~x + y = 0 := by
bv_decide
/- The prover found a potentially spurious counterexample: -/
/- - It abstracted the following unsupported expressions as opaque variables: [x[1], x[0]] -/
/- Consider the following assignment: -/
/- v[0] = 0x3#2 -/
/- v[1] = 0x3#2 -/
lemma vector_test (v : Vector (BitVec 2) 2): v[0] &&& ~~~v[0] + v[1] = 0 := by
bv_decide
I understand from this GitHub issue [https://github.com/leanprover/lean4/issues/5326] that bv_decide doesn't always work with abstracted terms. In the case above, the counterexample is correct, but I want to use Array.foldl to generate new constraints (e.g., to check whether each component of the vector is 0). Is there a way that I could generate n variables (of the same type) in a theorem using a macro, or would I need to combine my variables into a single BitVec? I tried writing a macro to create two variables, and that didn't work:
macro "#vars" : command => `(variable (x y : Bool))
#vars
/- unknown identifier 'x' -/
/- unknown identifier 'y' -/
theorem macro_test: x && y = 0 := by bv_decide
Henrik Böving (Jan 03 2025 at 15:35):
I understand from this GitHub issue https://github.com/leanprover/lean4/issues/5326 that bv_decide doesn't always work with abstracted terms
Yes, the reason for this is that bv_decide
only works on BitVec
and Bool
theory so when you have, in your case, a Vector
term around there is nothing saying that you might not have additional hypotheses from the theorey that your BitVec
atoms are coming from that would invalidate counter examples that bv_decide
finds so it has to account for this.
Your macro doesn't work because of hygiene.
It's not quite clear to me what your desired end goal here is. Do you want to generate a theorem statements automatically? Do you want to automatically introduce additional hypotheses?
Oscar Bender-Stone (Jan 03 2025 at 15:40):
Oh I see - thank you for the clarification on bv_decide and hygiene.
I want to generate theorem statements automatically. For instance, I would like to write something like:
theorem (x1 ... xn : BitVec 2): x1 + ... + xn = 0
for, say, n = 3.
Henrik Böving (Jan 03 2025 at 15:42):
You can write a macro that does something like this in principle sure. Is there a particular reason you dislike the Vector
based approach?
Oscar Bender-Stone (Jan 03 2025 at 15:50):
Henrik Böving said:
Is there a particular reason you dislike the
Vector
based approach? In my situation, I have several constraints like these:
Is there a way to make bv_decide work with Vector and Array.foldl?
def gt_one (vars : Vector (BitVec 10) 3) : Bool :=
Array.foldl (fun acc v => v > 1 && acc) true vars.1
/- The prover found a potentially spurious counterexample: -/
/- - It abstracted the following unsupported expressions as opaque variables: [BitVec.ofBool (gt_one vars)] -/
/- Consider the following assignment: -/
/- BitVec.ofBool (gt_one vars) = 0x0#1 -/
theorem gt_one_test (vars : Vector (BitVec 10) 3) : gt_one vars := by bv_decide
I want to make sure bv_decide does return sat if the theorem is actually sat and not this error message. It would be great if I could also get the counter-example. Either way, I am not sure how to expand out Array.foldl to make this work.
Henrik Böving (Jan 03 2025 at 15:55):
Basically speaking bv_decide
will only work on things that are within the basic BitVec
theory of Lean so if you want to call it you need to first simplify your goal towards this. What you can do in this specific situation is run something like this:
import Std.Tactic.BVDecide
def gt_one (vars : Vector (BitVec 10) 3) : Bool :=
Array.foldl (fun acc v => v > 1 && acc) true vars.1
theorem gt_one_test (vars : Vector (BitVec 10) 3) : gt_one vars := by
simp [gt_one, Array.foldl, Array.foldlM, Array.foldlM.loop, Id.run]
bv_decide
Which is of course a bit annoying but works out. If we had more simp
API around this type of stuff this would certainly be more convenient to write.
Oscar Bender-Stone (Jan 03 2025 at 16:04):
Thank you, that works well! I appreciate your help! I didn't know about completely simplifying Array.foldl.
Notification Bot (Jan 03 2025 at 16:04):
Oscar Bender-Stone has marked this topic as resolved.
Notification Bot (Jan 03 2025 at 19:02):
Oscar Bender-Stone has marked this topic as unresolved.
Notification Bot (Jan 03 2025 at 19:04):
Oscar Bender-Stone has marked this topic as resolved.
Notification Bot (Jan 03 2025 at 20:49):
Oscar Bender-Stone has marked this topic as unresolved.
Oscar Bender-Stone (Jan 03 2025 at 20:51):
Could anyone provide some code to generate variables via a macro in a theorem? Currently, when I use BitVec, it sometimes assigns the same component of a vector two two different numbers. I think the main culprit is using .toNat in a few functions, so if there is a way to simplify .toNat methods instead, that would be even better.
Last updated: May 02 2025 at 03:31 UTC