feat: add solve_by_elim +suggestions (#11468)
This PR adds `+suggestions` support to `solve_by_elim`, following the
pattern established by `grind +suggestions` and `simp_all +suggestions`.
Gracefully handles invalid/nonexistent suggestions by filtering them out
🤖 Prepared with Claude Code
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
1c1c534a03
commit
519ccf5d9d
3 changed files with 98 additions and 0 deletions
|
|
@ -8,6 +8,7 @@ module
|
|||
prelude
|
||||
public import Lean.Meta.Tactic.SolveByElim
|
||||
public import Lean.Elab.Tactic.Config
|
||||
public import Lean.LibrarySuggestions.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
|
@ -108,6 +109,21 @@ def evalSolveByElim : Tactic
|
|||
else
|
||||
pure [← getMainGoal]
|
||||
let cfg ← elabConfig cfg
|
||||
-- Add library suggestions if +suggestions is enabled
|
||||
let add ← if cfg.suggestions then
|
||||
let mainGoal ← getMainGoal
|
||||
let suggestions ← LibrarySuggestions.select mainGoal { caller := some "solve_by_elim" }
|
||||
let suggestionTerms ← suggestions.toList.filterMapM fun s => do
|
||||
-- Only include suggestions for constants that exist
|
||||
let env ← getEnv
|
||||
if env.contains s.name then
|
||||
let ident := mkCIdentFrom (← getRef) s.name (canonical := true)
|
||||
return some (⟨ident⟩ : Term)
|
||||
else
|
||||
return none
|
||||
pure (add ++ suggestionTerms)
|
||||
else
|
||||
pure add
|
||||
let [] ← processSyntax cfg o.isSome star add remove use goals |
|
||||
throwError "Internal error: `solve_by_elim` unexpectedly returned subgoals"
|
||||
pure ()
|
||||
|
|
|
|||
|
|
@ -100,6 +100,12 @@ structure SolveByElimConfig extends ApplyRulesConfig where
|
|||
intro : Bool := true
|
||||
/-- Try calling `constructor` if no lemmas apply. -/
|
||||
constructor : Bool := true
|
||||
/--
|
||||
If `suggestions` is `true`, `solve_by_elim` will invoke the currently configured library
|
||||
suggestion engine on the current goal, and attempt to use the resulting suggestions as
|
||||
additional lemmas.
|
||||
-/
|
||||
suggestions : Bool := false
|
||||
|
||||
namespace SolveByElimConfig
|
||||
|
||||
|
|
|
|||
76
tests/lean/run/solve_by_elim_suggestions.lean
Normal file
76
tests/lean/run/solve_by_elim_suggestions.lean
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import Lean.LibrarySuggestions.Basic
|
||||
import Lean.Elab.Tactic.SolveByElim
|
||||
|
||||
-- First test without any library suggestions set up
|
||||
/--
|
||||
error: No library suggestions engine registered. (Add `import Lean.LibrarySuggestions.Default` to use Lean's built-in engine, or use `set_library_suggestions` to configure a custom one.)
|
||||
-/
|
||||
#guard_msgs in
|
||||
example : True := by
|
||||
solve_by_elim +suggestions
|
||||
|
||||
-- Set up an empty library suggestion engine
|
||||
set_library_suggestions (fun _ _ => pure #[])
|
||||
|
||||
#guard_msgs in
|
||||
example : True := by
|
||||
solve_by_elim +suggestions
|
||||
|
||||
-- A custom proposition that solve_by_elim doesn't know about by default
|
||||
-- We use a custom non-defeq type so that `trivial` and `rfl` don't solve it
|
||||
inductive MyProp : Nat → Prop where
|
||||
| intro37 : MyProp 37
|
||||
| intro42 : MyProp 42
|
||||
|
||||
theorem myPropThm37 : MyProp 37 := MyProp.intro37
|
||||
|
||||
-- Without +suggestions (or explicit lemma), solve_by_elim should fail
|
||||
-- Note: need -constructor to prevent constructor from solving it
|
||||
/--
|
||||
error: failed
|
||||
-/
|
||||
#guard_msgs in
|
||||
example : MyProp 37 := by
|
||||
solve_by_elim -constructor
|
||||
|
||||
-- With explicit lemma, it works
|
||||
example : MyProp 37 := by
|
||||
solve_by_elim only [myPropThm37]
|
||||
|
||||
-- Set up library suggestion engine that suggests our theorem
|
||||
set_library_suggestions (fun _ _ => pure #[{ name := `myPropThm37, score := 1.0 }])
|
||||
|
||||
-- With +suggestions, it should work
|
||||
example : MyProp 37 := by
|
||||
solve_by_elim -constructor +suggestions
|
||||
|
||||
-- Test that suggestions work with local hypotheses
|
||||
example (h : MyProp 42) : MyProp 42 := by
|
||||
solve_by_elim +suggestions
|
||||
|
||||
-- Test with chain of applications
|
||||
inductive IsZero : Nat → Prop where
|
||||
| intro : IsZero 0
|
||||
|
||||
def fromZero (n : Nat) (h : n = 0) : IsZero n := by
|
||||
subst h
|
||||
exact IsZero.intro
|
||||
|
||||
theorem isZero_zero : IsZero 0 := IsZero.intro
|
||||
|
||||
set_library_suggestions (fun _ _ => pure #[
|
||||
{ name := `isZero_zero, score := 1.0 }
|
||||
])
|
||||
|
||||
example : IsZero 0 := by
|
||||
solve_by_elim +suggestions
|
||||
|
||||
-- Test with bad suggestions - they should be ignored silently
|
||||
set_library_suggestions (fun _ _ => pure #[
|
||||
{ name := `isZero_zero, score := 1.0 },
|
||||
{ name := `nonexistent_theorem, score := 0.5 }
|
||||
])
|
||||
|
||||
-- Bad suggestions should be filtered out, and the good one should work
|
||||
example : IsZero 0 := by
|
||||
solve_by_elim +suggestions
|
||||
Loading…
Add table
Reference in a new issue