Skip to content

Commit f1fc7ad

Browse files
leodemouraluisacicolini
authored andcommitted
feat: improve case-split heuristic used in grind (leanprover#6658)
This PR ensures that `grind` avoids case-splitting on terms congruent to those that have already been case-split.
1 parent 22a9cd0 commit f1fc7ad

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed

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

+11
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ private def checkIffStatus (e a b : Expr) : GoalM CaseSplitStatus := do
7474
else
7575
return .notReady
7676

77+
/-- Returns `true` is `c` is congruent to a case-split that was already performed. -/
78+
private def isCongrToPrevSplit (c : Expr) : GoalM Bool := do
79+
(← get).resolvedSplits.foldM (init := false) fun flag { expr := c' } => do
80+
if flag then
81+
return true
82+
else
83+
return isCongruent (← get).enodes c c'
84+
7785
private def checkCaseSplitStatus (e : Expr) : GoalM CaseSplitStatus := do
7886
match_expr e with
7987
| Or a b => checkDisjunctStatus e a b
@@ -85,6 +93,8 @@ private def checkCaseSplitStatus (e : Expr) : GoalM CaseSplitStatus := do
8593
if (← isResolvedCaseSplit e) then
8694
trace[grind.debug.split] "split resolved: {e}"
8795
return .resolved
96+
if (← isCongrToPrevSplit e) then
97+
return .resolved
8898
if let some info := isMatcherAppCore? (← getEnv) e then
8999
return .ready info.numAlts
90100
let .const declName .. := e.getAppFn | unreachable!
@@ -163,6 +173,7 @@ def splitNext : GrindTactic := fun goal => do
163173
| return none
164174
let gen ← getGeneration c
165175
let genNew := if numCases > 1 || isRec then gen+1 else gen
176+
markCaseSplitAsResolved c
166177
trace_goal[grind.split] "{c}, generation: {gen}"
167178
let mvarIds ← if (← isMatcherApp c) then
168179
casesMatch (← get).mvarId c

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ structure Goal where
378378
splitCandidates : List Expr := []
379379
/-- Number of splits performed to get to this goal. -/
380380
numSplits : Nat := 0
381-
/-- Case-splits that do not have to be performed anymore. -/
381+
/-- Case-splits that have already been performed, or that do not have to be performed anymore. -/
382382
resolvedSplits : PHashSet ENodeKey := {}
383383
/-- Next local E-match theorem idx. -/
384384
nextThmIdx : Nat := 0
@@ -879,7 +879,8 @@ def isResolvedCaseSplit (e : Expr) : GoalM Bool :=
879879

880880
/--
881881
Mark `e` as a case-split that does not need to be performed anymore.
882-
Remark: we currently use this feature to disable `match`-case-splits
882+
Remark: we currently use this feature to disable `match`-case-splits.
883+
Remark: we also use this feature to record the case-splits that have already been performed.
883884
-/
884885
def markCaseSplitAsResolved (e : Expr) : GoalM Unit := do
885886
unless (← isResolvedCaseSplit e) do

tests/lean/run/grind_split_issue.lean

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
variable (d : Nat) in
2+
inductive X : Nat → Prop
3+
| f {s : Nat} : X s
4+
| g {s : Nat} : X d → X s
5+
6+
/--
7+
error: `grind` failed
8+
case grind.1
9+
c : Nat
10+
q : X c 0
11+
s : Nat
12+
h✝ : 0 = s
13+
h : HEq ⋯ ⋯
14+
⊢ False
15+
[grind] Diagnostics
16+
[facts] Asserted facts
17+
[prop] X c 0
18+
[prop] 0 = s
19+
[prop] HEq ⋯ ⋯
20+
[eqc] True propositions
21+
[prop] X c 0
22+
[prop] X c s
23+
[eqc] Equivalence classes
24+
[eqc] {s, 0}
25+
case grind.2
26+
c : Nat
27+
q : X c 0
28+
s : Nat
29+
a✝¹ a✝ : X c c
30+
h✝ : 0 = s
31+
h : HEq ⋯ ⋯
32+
⊢ False
33+
[grind] Diagnostics
34+
[facts] Asserted facts
35+
[prop] X c 0
36+
[prop] X c c
37+
[prop] 0 = s
38+
[prop] HEq ⋯ ⋯
39+
[eqc] True propositions
40+
[prop] X c 0
41+
[prop] X c c
42+
[prop] X c s
43+
[eqc] Equivalence classes
44+
[eqc] {s, 0}
45+
[issues] Issues
46+
[issue] this goal was not fully processed due to previous failures, threshold: `(failures := 1)`
47+
-/
48+
#guard_msgs (error) in
49+
example {c : Nat} (q : X c 0) : False := by
50+
grind

0 commit comments

Comments
 (0)