@@ -3,7 +3,7 @@ Copyright (c) 2024 Siddharth Bhat. All rights reserved.
33Released under Apache 2.0 license as described in the file LICENSE.
44Authors: Siddharth Bhat
55
6- This file implements lazy ackermannization [1, 2]
6+ This file implements strict ackermannization [1, 2]
77
88[ 1 ] https://lara.epfl.ch/w/_media/model-based.pdf
99[ 2 ] https://leodemoura.github.io/files/oregon08.pdf
@@ -31,11 +31,6 @@ initialize Lean.registerTraceClass `bv_ack
3131
3232namespace Ack
3333
34- structure Config where
35-
36- structure Context extends Config where
37- config : Config
38-
3934 /-- Types that can be bitblasted by bv_decide -/
4035 inductive BVTy
4136 /-- Booleans -/
@@ -51,9 +46,6 @@ instance : ToMessageData BVTy where
5146
5247namespace BVTy
5348
54- /-- info: _root_ .BitVec (w : Nat) : Type -/
55- #guard_msgs in #check _root_.BitVec
56-
5749/-- Reify a raw expression of type `Type` into the types of bitvectors we can bitblast,
5850returning `none` if `e` was not recognized as either `Bool` or `BitVec ?w`,
5951with `?w` a literal `Nat` -/
@@ -65,12 +57,14 @@ def ofExpr? (e : Expr) : OptionT MetaM BVTy :=
6557 return .BitVec w
6658 | _ => OptionT.fail
6759
60+ /-- Convert a `BVTy` back into an `Expr` -/
6861def toExpr : BVTy → Expr
6962| .Bool => mkConst ``_root_.Bool
7063| .BitVec w => mkApp (mkConst ``_root_.BitVec) (mkNatLit w)
7164
7265end BVTy
7366
67+ /-- An argument to an uninterpreted function, which we track for ackermannization. -/
7468structure Argument where
7569 /-- The expression corresponding to the argument -/
7670 x : Expr
@@ -89,15 +83,21 @@ def ofExpr? (e : Expr) : OptionT MetaM Argument := do
8983 return { x := e, xTy := t}
9084
9185end Argument
86+
87+ /--
88+ A function, which packs the expression and the type of the codomain of the function.
89+ We use the type of the codomain to build an abstracted value for every call of this function.
90+ -/
9291structure Function where
9392 /-- The function -/
9493 f : Expr
95- codTy : BVTy
94+ /-- The type of the function's codomain -/
95+ codomain : BVTy
9696 deriving Hashable, BEq, Inhabited
9797namespace Function
9898
9999instance : ToMessageData Function where
100- toMessageData fn := m!"{fn.f} (cod: {fn.codTy })"
100+ toMessageData fn := m!"{fn.f} (cod: {fn.codomain })"
101101
102102/--
103103Reify an expression `e` of the kind `f x₁ ... xₙ`, where all the arguments and the return type are
@@ -107,9 +107,9 @@ def reifyAp (f : Expr) : OptionT MetaM (Function × Array Argument) := do
107107 let xs := f.getAppArgs
108108 /- We need at least one argument for this to be a function call we can ackermannize. -/
109109 guard <| xs.size > 0
110- let codTy ← BVTy.ofExpr? (← inferType f)
110+ let codomain ← BVTy.ofExpr? (← inferType f)
111111 let args ← xs.mapM Argument.ofExpr?
112- let fn : Function := { f, codTy }
112+ let fn : Function := { f, codomain }
113113 return (fn, args)
114114end Function
115115/--
@@ -142,14 +142,14 @@ structure State where
142142 fn2args2call : Std.HashMap Function (Std.HashMap ArgumentList CallVal) := {}
143143 /-- A counter for generating fresh names. -/
144144 gensymCounter : Nat := 0
145- def State.init (_cfg : Config) : State where
146145
147- abbrev AckM := StateRefT State (ReaderT Context MetaM)
146+ def State.init : State where
147+
148+ abbrev AckM := StateRefT State MetaM
148149
149150namespace AckM
150151
151- def run (m : AckM α) (ctx : Context) : MetaM α :=
152- m.run' (State.init ctx.config) |>.run ctx
152+ def run (m : AckM α) : MetaM α := m.run' State.init
153153
154154/-- Generate a fresh name. -/
155155def gensym : AckM Name := do
@@ -204,7 +204,7 @@ def replaceCallWithFVar (g : MVarId) (fn : Function) (args : ArgumentList) : Ack
204204 return (val, g)
205205 let e := mkAppN fn.f (args.map Argument.x)
206206 let name ← gensym
207- let (introDef, g) ← introDefExt g name fn.codTy .toExpr e
207+ let (introDef, g) ← introDefExt g name fn.codomain .toExpr e
208208 let cv := { fvar := introDef.defn, heqProof := Expr.fvar introDef.eqProof : CallVal }
209209 _insertCallVal fn args cv
210210 return (cv, g)
@@ -261,13 +261,13 @@ partial def introAckForExpr (g : MVarId) (e : Expr) : AckM (Expr × MVarId) := d
261261 withTraceNode m!"🎯 Expr.app '{e}'" (collapsed := false ) do
262262 let f := e.getAppFn
263263 let te ← inferType e
264- let .some codTy ← BVTy.ofExpr? te |>.run
264+ let .some codomain ← BVTy.ofExpr? te |>.run
265265 | do
266266 trace[bv_ack] "{crossEmoji} '{te}' not BitVec/Bool."
267267 return (← ackAppChildren g e)
268268 trace[bv_ack] "{checkEmoji} {e}'s codomain '{te}'"
269269
270- let fn := { f, codTy : Function }
270+ let fn := { f, codomain : Function }
271271
272272 let args := e.getAppArgs
273273 assert! args.size > 0 -- since we are an application, we must have at least one argument.
@@ -278,7 +278,6 @@ partial def introAckForExpr (g : MVarId) (e : Expr) : AckM (Expr × MVarId) := d
278278 for arg in args do
279279 trace[bv_ack] "🎯 arg {arg}"
280280 let (arg, g) ← introAckForExpr g arg
281- -- do I need a `withContext` here? :(
282281 if let .some ackArg ← Argument.ofExpr? arg |>.run then
283282 trace[bv_ack] "{checkEmoji} arg {arg}"
284283 ackArgs := ackArgs.push ackArg
@@ -393,18 +392,16 @@ def ack (g : MVarId) : AckM MVarId := do
393392end AckM
394393
395394/-- Entry point for programmatic usage of `bv_ackermannize` -/
396- def ackTac (ctx : Context) : TacticM Unit := do
395+ def ackTac : TacticM Unit := do
397396 withoutRecover do
398397 liftMetaTactic fun g => do
399- let g ← (AckM.ack g).run ctx
398+ let g ← (AckM.ack g).run
400399 return [g]
401400
402401end Ack
403402
404403@[builtin_tactic Lean.Parser.Tactic.bvAckEager]
405404def evalBvAckEager : Tactic := fun
406405 | `(tactic| bv_ack_eager) =>
407- let config : Ack.Config := {}
408- let ctx : Ack.Context := { config := config }
409- Ack.ackTac ctx
406+ Ack.ackTac
410407 | _ => throwUnsupportedSyntax
0 commit comments