Skip to content

Commit 09f2220

Browse files
authored
feat: add SolverExtension.action and Solvers.mkAction (#10836)
This PR implements support for `Action` in the `grind` solver extensions (`SolverExtension`). It also provides the `Solvers.mkAction` function that constructs an `Action` using all registered solvers. The generated action is "fair," that is, a solver cannot prevent other solvers from making progress.
1 parent ef23782 commit 09f2220

File tree

9 files changed

+68
-35
lines changed

9 files changed

+68
-35
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ builtin_initialize
3737
(internalize := AC.internalize)
3838
(newEq := AC.processNewEq)
3939
(newDiseq := AC.processNewDiseq)
40+
(action := Action.ac)
4041
(check := AC.check')
4142
(checkInv := AC.checkInvariants)
42-
(mkTactic? := return some (← `(grind| ac)))
4343

4444
end Lean.Meta.Grind.AC

src/Lean/Meta/Tactic/Grind/AC/Eq.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ Authors: Leonardo de Moura
66
module
77
prelude
88
public import Lean.Meta.Tactic.Grind.AC.Util
9-
public import Lean.Meta.Tactic.Grind.CheckResult
109
import Lean.Meta.Tactic.Grind.AC.DenoteExpr
1110
import Lean.Meta.Tactic.Grind.AC.Proof
1211
import Lean.Meta.Tactic.Grind.AC.Seq

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

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ Authors: Leonardo de Moura
66
module
77
prelude
88
public import Lean.Meta.Tactic.Grind.Types
9-
public import Lean.Meta.Tactic.Grind.CheckResult
109
public section
1110
namespace Lean.Meta.Grind
1211
/-!
@@ -69,42 +68,20 @@ use `callCC` here.
6968
7069
-/
7170

72-
abbrev TGrind := TSyntax `grind
7371
abbrev TGrindStep := TSyntax ``Parser.Tactic.Grind.grindStep
7472

75-
/-- Result type for a `grind` Action -/
76-
inductive ActionResult where
77-
| /--
78-
The goal has been closed, and you can use `seq` to close the goal efficiently.
79-
-/
80-
closed (seq : List TGrind)
81-
| /--
82-
The action could not make further progress.
83-
`gs` are subgoals that could not be closed. They are used for producing error messages.
84-
-/
85-
stuck (gs : List Goal)
86-
8773
def ActionResult.toMessageData : ActionResult → MessageData
8874
| .closed seq => m!"closed {seq}"
8975
| .stuck goals => m!"stuck {goals.map (·.mvarId)}"
9076

9177
instance : ToMessageData ActionResult where
9278
toMessageData := ActionResult.toMessageData
9379

94-
abbrev ActionCont : Type :=
95-
Goal → GrindM ActionResult
96-
97-
abbrev Action : Type :=
98-
Goal → (kna : ActionCont) → (kp : ActionCont) → GrindM ActionResult
99-
10080
namespace Action
10181

10282
def skip : Action := fun goal _ kp =>
10383
kp goal
10484

105-
def notApplicable : Action := fun goal kna _ =>
106-
kna goal
107-
10885
/--
10986
If the `goal` is already inconsistent, returns `.closed []`. Otherwise, executes
11087
then not applicable continuation.

src/Lean/Meta/Tactic/Grind/Arith/CommRing.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ builtin_initialize
5353
(internalize := CommRing.internalize)
5454
(newEq := CommRing.processNewEq)
5555
(newDiseq := CommRing.processNewDiseq)
56+
(action := Action.ring)
5657
(check := CommRing.check')
5758
(checkInv := CommRing.checkInvariants)
58-
(mkTactic? := return some (← `(grind| ring)))
5959

6060
end Lean.Meta.Grind.Arith.CommRing

src/Lean/Meta/Tactic/Grind/Arith/CommRing/EqCnstr.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ Authors: Leonardo de Moura
66
module
77
prelude
88
public import Lean.Meta.Tactic.Grind.Arith.CommRing.RingId
9-
public import Lean.Meta.Tactic.Grind.CheckResult
109
import Lean.Meta.Tactic.Grind.ProveEq
1110
import Lean.Meta.Tactic.Grind.Diseq
1211
import Lean.Meta.Tactic.Grind.Arith.Util

src/Lean/Meta/Tactic/Grind/Arith/Cutsat.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ builtin_initialize
4949
(internalize := Cutsat.internalize)
5050
(newEq := Cutsat.processNewEq)
5151
(newDiseq := Cutsat.processNewDiseq)
52+
(action := Action.lia)
5253
(check := Cutsat.check)
5354
(checkInv := Cutsat.checkInvariants)
5455
(mbtc := Cutsat.mbtc)
55-
(mkTactic? := return some (← `(grind| lia)))
5656

5757
end Lean.Meta.Grind.Arith.Cutsat

src/Lean/Meta/Tactic/Grind/Arith/Linear.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ builtin_initialize
4848
(internalize := Linear.internalize)
4949
(newEq := Linear.processNewEq)
5050
(newDiseq := Linear.processNewDiseq)
51+
(action := Action.linarith)
5152
(check := Linear.check)
5253
(checkInv := Linear.checkInvariants)
5354
(mbtc := Linear.mbtc)
54-
(mkTactic? := return some (← `(grind| linarith)))
5555

5656
end Lean.Meta.Grind.Arith.Linear

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Authors: Leonardo de Moura
55
-/
66
module
77
prelude
8-
public import Lean.Meta.Tactic.Grind.Types
8+
public import Init.Data.Repr
99
public section
1010
namespace Lean.Meta.Grind
1111
/--

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

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ prelude
88
public import Lean.Meta.Tactic.Simp.Types
99
public import Lean.Meta.Tactic.Grind.AlphaShareCommon
1010
public import Lean.Meta.Tactic.Grind.Attr
11+
public import Lean.Meta.Tactic.Grind.CheckResult
1112
public import Init.Data.Queue
1213
import Lean.Meta.Tactic.Grind.ExprPtr
1314
import Lean.HeadIndex
@@ -1493,6 +1494,38 @@ def withoutModifyingState (x : GoalM α) : GoalM α := do
14931494
@[extern "lean_grind_canon"] -- Forward definition
14941495
opaque canon (e : Expr) : GoalM Expr
14951496

1497+
/-!
1498+
`Action` is the *control interface* for `grind`’s search steps. It is defined in
1499+
Continuation-Passing Style (CPS).
1500+
See `Grind/Action.lean` for additional details.
1501+
-/
1502+
1503+
abbrev TGrind := TSyntax `grind
1504+
1505+
/-- Result type for a `grind` Action -/
1506+
inductive ActionResult where
1507+
| /--
1508+
The goal has been closed, and you can use `seq` to close the goal efficiently.
1509+
-/
1510+
closed (seq : List TGrind)
1511+
| /--
1512+
The action could not make further progress.
1513+
`gs` are subgoals that could not be closed. They are used for producing error messages.
1514+
-/
1515+
stuck (gs : List Goal)
1516+
1517+
abbrev ActionCont : Type :=
1518+
Goal → GrindM ActionResult
1519+
1520+
abbrev Action : Type :=
1521+
Goal → (kna : ActionCont) → (kp : ActionCont) → GrindM ActionResult
1522+
1523+
@[expose] def Action.notApplicable : Action := fun goal kna _ =>
1524+
kna goal
1525+
1526+
instance : Inhabited Action where
1527+
default := Action.notApplicable
1528+
14961529
/-!
14971530
Solver Extensions
14981531
-/
@@ -1508,9 +1541,9 @@ structure SolverExtension (σ : Type) where private mk ::
15081541
newEq : Expr → Expr → GoalM Unit
15091542
newDiseq : Expr → Expr → GoalM Unit
15101543
mbtc : GoalM Bool
1511-
check : GoalM Bool
1544+
action : Action
1545+
check : GoalM Bool -- **TODO**: Consider deleting `check` in the future.
15121546
checkInv : GoalM Unit
1513-
mkTactic? : CoreM (Option (TSyntax `grind))
15141547
deriving Inhabited
15151548

15161549
private builtin_initialize solverExtensionsRef : IO.Ref (Array (SolverExtension SolverExtensionState)) ← IO.mkRef #[]
@@ -1530,10 +1563,10 @@ def registerSolverExtension {σ : Type} (mkInitial : IO σ) : IO (SolverExtensio
15301563
internalize := fun _ _ => return ()
15311564
newEq := fun _ _ => return ()
15321565
newDiseq := fun _ _ => return ()
1566+
action := Action.notApplicable
15331567
check := fun _ _ => return false
15341568
checkInv := fun _ _ => return ()
15351569
mbtc := fun _ _ => return false
1536-
mkTactic? := return none
15371570
}
15381571
solverExtensionsRef.modify fun exts => exts.push (unsafe unsafeCast ext)
15391572
return ext
@@ -1548,16 +1581,16 @@ def SolverExtension.setMethods (ext : SolverExtension σ)
15481581
(newEq : Expr → Expr → GoalM Unit := fun _ _ => return ())
15491582
(newDiseq : Expr → Expr → GoalM Unit := fun _ _ => return ())
15501583
(mbtc : GoalM Bool := return false)
1584+
(action : Action := Action.notApplicable)
15511585
(check : GoalM Bool := return false)
15521586
(checkInv : GoalM Unit := return ())
1553-
(mkTactic? : CoreM (Option (TSyntax `grind)) := return none)
15541587
: IO Unit := do
15551588
unless (← initializing) do
15561589
throw (IO.userError "failed to register `grind` solver, extensions can only be registered during initialization")
15571590
unless ext.id < (← solverExtensionsRef.get).size do
15581591
throw (IO.userError "failed to register `grind` solver methods, invalid solver id")
15591592
solverExtensionsRef.modify fun exts => exts.modify ext.id fun s => { s with
1560-
internalize, newEq, newDiseq, mbtc, check, checkInv, mkTactic?
1593+
internalize, newEq, newDiseq, mbtc, action, check, checkInv
15611594
}
15621595

15631596
/-- Returns initial state for registered solvers. -/
@@ -1621,6 +1654,31 @@ def Solvers.mbtc : GoalM Bool := do
16211654
result := true
16221655
return result
16231656

1657+
/--
1658+
Sequential conjunction: executes both `x` and `y`.
1659+
1660+
- Runs `x` and always runs `y` afterward, regardless of whether `x` made progress.
1661+
- It is not applicable only if both `x` and `y` are not applicable.
1662+
-/
1663+
def Action.andAlso (x y : Action) : Action := fun goal kna kp => do
1664+
x goal (fun goal => y goal kna kp) (fun goal => y goal kp kp)
1665+
1666+
/-
1667+
Creates an action that tries all solver extensions. It uses the `Action.andAlso`
1668+
to combine them.
1669+
-/
1670+
def Solvers.mkAction : IO Action := do
1671+
let exts ← solverExtensionsRef.get
1672+
let rec go (i : Nat) (acc : Action) : Action :=
1673+
if h : i < exts.size then
1674+
go (i+1) (acc.andAlso exts[i].action)
1675+
else
1676+
acc
1677+
if h : 0 < exts.size then
1678+
return go 1 exts[0].action
1679+
else
1680+
return Action.notApplicable
1681+
16241682
/--
16251683
Given a new disequality `lhs ≠ rhs`, propagates it to relevant theories.
16261684
-/

0 commit comments

Comments
 (0)