Skip to content

Commit 8502cbe

Browse files
committed
feat: model-based theory combination tactic and action
This PR adds the `mbtc` tactic to the `grind` interactive mode. It implements model-based theory combination. It also ensures `finish?` is capable of generating it.
1 parent 3d55951 commit 8502cbe

File tree

4 files changed

+57
-3
lines changed

4 files changed

+57
-3
lines changed

src/Init/Grind/Interactive.lean

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,5 +225,10 @@ Proves `<term>` using the current `grind` state and default search strategy.
225225
-/
226226
syntax (name := haveSilent) "have" (ppSpace ident)? ppSpace ": " term : grind
227227

228+
/--
229+
Adds new case-splits using model-based theory combination.
230+
-/
231+
syntax (name := mbtc) "mbtc" : grind
232+
228233
end Grind
229234
end Lean.Parser.Tactic

src/Lean/Elab/Tactic/Grind/BuiltinTactic.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,4 +429,13 @@ where
429429
let options ← Elab.elabSetOption stx[1] stx[3]
430430
withOptions (fun _ => options) do evalGrindTactic stx[5]
431431

432+
@[builtin_grind_tactic mbtc] def elabMBTC : GrindTactic := fun _ => do
433+
liftGoalM do
434+
discard <| Solvers.check
435+
if (← get).inconsistent then
436+
return ()
437+
let progress ← Solvers.mbtc
438+
unless progress do
439+
throwError "`mbtc` tactic failed to generate new candidate case-splits."
440+
432441
end Lean.Elab.Tactic.Grind

src/Lean/Meta/Tactic/Grind/Action.lean

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ Appends a new tactic syntax to a successful result.
225225
Used by leaf actions to record the tactic that produced progress.
226226
If `(← getConfig).trace` is `false`, it just returns `r`.
227227
-/
228-
def concatTactic (r : ActionResult) (mk : GrindM (TSyntax `grind)) : GrindM ActionResult := do
228+
def concatTactic (r : ActionResult) (mk : GrindM TGrind) : GrindM ActionResult := do
229229
if (← getConfig).trace then
230230
match r with
231231
| .closed seq =>
@@ -236,7 +236,7 @@ def concatTactic (r : ActionResult) (mk : GrindM (TSyntax `grind)) : GrindM Acti
236236
return r
237237

238238
/-- Returns `.closed [← mk]` if tracing is enabled, and `.closed []` otherwise. -/
239-
def closeWith (mk : GrindM (TSyntax `grind)) : GrindM ActionResult := do
239+
def closeWith (mk : GrindM TGrind) : GrindM ActionResult := do
240240
if (← getConfig).trace then
241241
return .closed [(← mk)]
242242
else
@@ -247,7 +247,7 @@ A terminal action which closes the goal or not.
247247
This kind of action may make progress, but we only include `mkTac` into the resulting tactic sequence
248248
if it closed the goal.
249249
-/
250-
def terminalAction (check : GoalM Bool) (mkTac : GrindM (TSyntax `grind)) : Action := fun goal kna kp => do
250+
def terminalAction (check : GoalM Bool) (mkTac : GrindM TGrind) : Action := fun goal kna kp => do
251251
let (progress, goal') ← GoalM.run goal check
252252
if progress then
253253
if goal'.inconsistent then
@@ -332,6 +332,24 @@ def solverAction (check : GoalM CheckResult) (mkTac : GrindM TGrind) : Action :=
332332
kp goal'
333333
| .closed => closeWith mkTac
334334

335+
def mbtc : Action := fun goal kna kp => do
336+
let saved? ← saveStateIfTracing
337+
let (progress, goal') ← GoalM.run goal Solvers.mbtc
338+
if progress then
339+
if (← getConfig).trace then
340+
match (← kp goal') with
341+
| .closed seq =>
342+
if (← checkSeqAt saved? goal seq) then
343+
return .closed seq
344+
else
345+
let tac ← `(grind| mbtc)
346+
return .closed (tac :: seq)
347+
| r => return r
348+
else
349+
kp goal'
350+
else
351+
kna goal'
352+
335353
section
336354
/-!
337355
Some sanity check properties.

tests/lean/run/grind_finish_trace.lean

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,25 @@ info: Try this:
134134
example (a : Array (BitVec 64)) (i : Nat) (v : BitVec 64)
135135
: (_ : i < a.size) → (_ : i + 1 < a.size) → (a.set i v)[i+1] + a[i+1] = 2*a[i+1] := by
136136
grind => finish?
137+
138+
/--
139+
info: Try this:
140+
[apply]
141+
mbtc
142+
cases #a6c8
143+
-/
144+
#guard_msgs in
145+
example (f : Nat → Nat) (x : Nat)
146+
: x ≠ 0 → x ≤ 1 → f x = 2 → f 1 = 2 := by
147+
grind => finish?
148+
149+
/--
150+
info: Try this:
151+
[apply]
152+
mbtc
153+
cases #beb4
154+
-/
155+
#guard_msgs in
156+
example (f : Int → Int → Int) (x y : Int)
157+
: 0 ≤ x → x ≠ 0 → x ≤ 1 → f x y = 2 → f 1 y = 2 := by
158+
grind => finish?

0 commit comments

Comments
 (0)