Skip to content

Commit 8b5443e

Browse files
authored
feat: support BitVec.ofBool in bv_decide (leanprover#5852)
This is the first step towards fixing the issue of not having mutual recursion between the `Bool` and `BitVec` fragment of `QF_BV` in `bv_decide`. This PR adds support for `BitVec.ofBool` by doing the following: 1. Introduce a new mechanism into the reification engine that allows us to add additional lemmas to the top level on the fly as we are traversing the expression tree. 2. If we encounter an expression `BitVec.ofBool boolExpr` we reify `boolExpr` and then abstract `BitVec.ofBool boolExpr` as some atom `a` 3. We add two lemmas `boolExpr = true -> a = 1#1` and `boolExpr = false -> a = 0#1`. This mirrors the full behavior of `BitVec.ofBool` and thus makes our atom `a` correctly interpreted again. In order to do the reification in step 2 mutual recursion in the reification engine is required. For this reason I started pulling out logic from the, now rather large, mutual block into other files and document the invariants that they assume explicitly.
1 parent 08c36e4 commit 8b5443e

File tree

14 files changed

+743
-516
lines changed

14 files changed

+743
-516
lines changed

src/Lean/Elab/Tactic/BVDecide/Frontend/BVDecide.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,8 @@ def reflectBV (g : MVarId) : M ReflectionResult := g.withContext do
225225
let mut sats := #[]
226226
let mut unusedHypotheses := {}
227227
for hyp in hyps do
228-
if let some reflectedSatAtBVLogical.of (mkFVar hyp) then
229-
sats := sats.push reflected
228+
if let (some reflected, lemmas) ← (SatAtBVLogical.of (mkFVar hyp)).run then
229+
sats := (sats ++ lemmas).push reflected
230230
else
231231
unusedHypotheses := unusedHypotheses.insert hyp
232232
if h : sats.size = 0 then

src/Lean/Elab/Tactic/BVDecide/Frontend/BVDecide/Reflect.lean

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ instance : ToExpr Gate where
8080
| .and => mkConst ``Gate.and
8181
| .xor => mkConst ``Gate.xor
8282
| .beq => mkConst ``Gate.beq
83+
| .imp => mkConst ``Gate.imp
8384
toTypeExpr := mkConst ``Gate
8485

8586
instance : ToExpr BVPred where
@@ -125,6 +126,76 @@ The reflection monad, used to track `BitVec` variables that we see as we travers
125126
-/
126127
abbrev M := StateRefT State MetaM
127128

129+
/--
130+
A reified version of an `Expr` representing a `BVExpr`.
131+
-/
132+
structure ReifiedBVExpr where
133+
width : Nat
134+
/--
135+
The reified expression.
136+
-/
137+
bvExpr : BVExpr width
138+
/--
139+
A proof that `bvExpr.eval atomsAssignment = originalBVExpr`.
140+
-/
141+
evalsAtAtoms : M Expr
142+
/--
143+
A cache for `toExpr bvExpr`.
144+
-/
145+
expr : Expr
146+
147+
/--
148+
A reified version of an `Expr` representing a `BVPred`.
149+
-/
150+
structure ReifiedBVPred where
151+
/--
152+
The reified expression.
153+
-/
154+
bvPred : BVPred
155+
/--
156+
A proof that `bvPred.eval atomsAssignment = originalBVPredExpr`.
157+
-/
158+
evalsAtAtoms : M Expr
159+
/--
160+
A cache for `toExpr bvPred`
161+
-/
162+
expr : Expr
163+
164+
/--
165+
A reified version of an `Expr` representing a `BVLogicalExpr`.
166+
-/
167+
structure ReifiedBVLogical where
168+
/--
169+
The reified expression.
170+
-/
171+
bvExpr : BVLogicalExpr
172+
/--
173+
A proof that `bvExpr.eval atomsAssignment = originalBVLogicalExpr`.
174+
-/
175+
evalsAtAtoms : M Expr
176+
/--
177+
A cache for `toExpr bvExpr`
178+
-/
179+
expr : Expr
180+
181+
/--
182+
A reified version of an `Expr` representing a `BVLogicalExpr` that we know to be true.
183+
-/
184+
structure SatAtBVLogical where
185+
/--
186+
The reified expression.
187+
-/
188+
bvExpr : BVLogicalExpr
189+
/--
190+
A proof that `bvExpr.eval atomsAssignment = true`.
191+
-/
192+
satAtAtoms : M Expr
193+
/--
194+
A cache for `toExpr bvExpr`
195+
-/
196+
expr : Expr
197+
198+
128199
namespace M
129200

130201
/--
@@ -172,5 +243,34 @@ where
172243

173244
end M
174245

246+
/--
247+
The state of the lemma reflection monad.
248+
-/
249+
structure LemmaState where
250+
/--
251+
The list of top level lemmas that got created on the fly during reflection.
252+
-/
253+
lemmas : Array SatAtBVLogical := #[]
254+
255+
/--
256+
The lemma reflection monad. It extends the usual reflection monad `M` by adding the ability to
257+
add additional top level lemmas on the fly.
258+
-/
259+
abbrev LemmaM := StateRefT LemmaState M
260+
261+
namespace LemmaM
262+
263+
def run (m : LemmaM α) (state : LemmaState := {}) : M (α × Array SatAtBVLogical) := do
264+
let (res, state) ← StateRefT'.run m state
265+
return (res, state.lemmas)
266+
267+
/--
268+
Add another top level lemma.
269+
-/
270+
def addLemma (lemma : SatAtBVLogical) : LemmaM Unit := do
271+
modify fun s => { s with lemmas := s.lemmas.push lemma }
272+
273+
end LemmaM
274+
175275
end Frontend
176276
end Lean.Elab.Tactic.BVDecide

0 commit comments

Comments
 (0)