@@ -3,7 +3,7 @@ Copyright (c) 2024 Siddharth Bhat. All rights reserved.
3
3
Released under Apache 2.0 license as described in the file LICENSE.
4
4
Authors: Siddharth Bhat
5
5
6
- This file implements lazy ackermannization [1, 2]
6
+ This file implements strict ackermannization [1, 2]
7
7
8
8
[ 1 ] https://lara.epfl.ch/w/_media/model-based.pdf
9
9
[ 2 ] https://leodemoura.github.io/files/oregon08.pdf
@@ -31,11 +31,6 @@ initialize Lean.registerTraceClass `bv_ack
31
31
32
32
namespace Ack
33
33
34
- structure Config where
35
-
36
- structure Context extends Config where
37
- config : Config
38
-
39
34
/-- Types that can be bitblasted by bv_decide -/
40
35
inductive BVTy
41
36
/-- Booleans -/
@@ -51,9 +46,6 @@ instance : ToMessageData BVTy where
51
46
52
47
namespace BVTy
53
48
54
- /-- info: _root_ .BitVec (w : Nat) : Type -/
55
- #guard_msgs in #check _root_.BitVec
56
-
57
49
/-- Reify a raw expression of type `Type` into the types of bitvectors we can bitblast,
58
50
returning `none` if `e` was not recognized as either `Bool` or `BitVec ?w`,
59
51
with `?w` a literal `Nat` -/
@@ -65,12 +57,14 @@ def ofExpr? (e : Expr) : OptionT MetaM BVTy :=
65
57
return .BitVec w
66
58
| _ => OptionT.fail
67
59
60
+ /-- Convert a `BVTy` back into an `Expr` -/
68
61
def toExpr : BVTy → Expr
69
62
| .Bool => mkConst ``_root_.Bool
70
63
| .BitVec w => mkApp (mkConst ``_root_.BitVec) (mkNatLit w)
71
64
72
65
end BVTy
73
66
67
+ /-- An argument to an uninterpreted function, which we track for ackermannization. -/
74
68
structure Argument where
75
69
/-- The expression corresponding to the argument -/
76
70
x : Expr
@@ -89,15 +83,21 @@ def ofExpr? (e : Expr) : OptionT MetaM Argument := do
89
83
return { x := e, xTy := t}
90
84
91
85
end 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
+ -/
92
91
structure Function where
93
92
/-- The function -/
94
93
f : Expr
95
- codTy : BVTy
94
+ /-- The type of the function's codomain -/
95
+ codomain : BVTy
96
96
deriving Hashable, BEq, Inhabited
97
97
namespace Function
98
98
99
99
instance : ToMessageData Function where
100
- toMessageData fn := m!"{fn.f} (cod: {fn.codTy })"
100
+ toMessageData fn := m!"{fn.f} (cod: {fn.codomain })"
101
101
102
102
/--
103
103
Reify 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
107
107
let xs := f.getAppArgs
108
108
/- We need at least one argument for this to be a function call we can ackermannize. -/
109
109
guard <| xs.size > 0
110
- let codTy ← BVTy.ofExpr? (← inferType f)
110
+ let codomain ← BVTy.ofExpr? (← inferType f)
111
111
let args ← xs.mapM Argument.ofExpr?
112
- let fn : Function := { f, codTy }
112
+ let fn : Function := { f, codomain }
113
113
return (fn, args)
114
114
end Function
115
115
/--
@@ -142,14 +142,14 @@ structure State where
142
142
fn2args2call : Std.HashMap Function (Std.HashMap ArgumentList CallVal) := {}
143
143
/-- A counter for generating fresh names. -/
144
144
gensymCounter : Nat := 0
145
- def State.init (_cfg : Config) : State where
146
145
147
- abbrev AckM := StateRefT State (ReaderT Context MetaM)
146
+ def State.init : State where
147
+
148
+ abbrev AckM := StateRefT State MetaM
148
149
149
150
namespace AckM
150
151
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
153
153
154
154
/-- Generate a fresh name. -/
155
155
def gensym : AckM Name := do
@@ -204,7 +204,7 @@ def replaceCallWithFVar (g : MVarId) (fn : Function) (args : ArgumentList) : Ack
204
204
return (val, g)
205
205
let e := mkAppN fn.f (args.map Argument.x)
206
206
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
208
208
let cv := { fvar := introDef.defn, heqProof := Expr.fvar introDef.eqProof : CallVal }
209
209
_insertCallVal fn args cv
210
210
return (cv, g)
@@ -261,13 +261,13 @@ partial def introAckForExpr (g : MVarId) (e : Expr) : AckM (Expr × MVarId) := d
261
261
withTraceNode m!"🎯 Expr.app '{e}'" (collapsed := false ) do
262
262
let f := e.getAppFn
263
263
let te ← inferType e
264
- let .some codTy ← BVTy.ofExpr? te |>.run
264
+ let .some codomain ← BVTy.ofExpr? te |>.run
265
265
| do
266
266
trace[bv_ack] "{crossEmoji} '{te}' not BitVec/Bool."
267
267
return (← ackAppChildren g e)
268
268
trace[bv_ack] "{checkEmoji} {e}'s codomain '{te}'"
269
269
270
- let fn := { f, codTy : Function }
270
+ let fn := { f, codomain : Function }
271
271
272
272
let args := e.getAppArgs
273
273
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
278
278
for arg in args do
279
279
trace[bv_ack] "🎯 arg {arg}"
280
280
let (arg, g) ← introAckForExpr g arg
281
- -- do I need a `withContext` here? :(
282
281
if let .some ackArg ← Argument.ofExpr? arg |>.run then
283
282
trace[bv_ack] "{checkEmoji} arg {arg}"
284
283
ackArgs := ackArgs.push ackArg
@@ -393,18 +392,16 @@ def ack (g : MVarId) : AckM MVarId := do
393
392
end AckM
394
393
395
394
/-- Entry point for programmatic usage of `bv_ackermannize` -/
396
- def ackTac (ctx : Context) : TacticM Unit := do
395
+ def ackTac : TacticM Unit := do
397
396
withoutRecover do
398
397
liftMetaTactic fun g => do
399
- let g ← (AckM.ack g).run ctx
398
+ let g ← (AckM.ack g).run
400
399
return [g]
401
400
402
401
end Ack
403
402
404
403
@[builtin_tactic Lean.Parser.Tactic.bvAckEager]
405
404
def evalBvAckEager : Tactic := fun
406
405
| `(tactic| bv_ack_eager) =>
407
- let config : Ack.Config := {}
408
- let ctx : Ack.Context := { config := config }
409
- Ack.ackTac ctx
406
+ Ack.ackTac
410
407
| _ => throwUnsupportedSyntax
0 commit comments