feat: add Simp.Config.ground for simplifying nested ground terms
This is an experimental new feature. We need more bells and whistles, and `cbv` tactic for improving its performance.
This commit is contained in:
parent
67b5cd9c0e
commit
419100d42b
3 changed files with 54 additions and 3 deletions
|
|
@ -1261,6 +1261,10 @@ structure Config where
|
|||
/-- If `failIfUnchanged := true`, then calls to `simp`, `dsimp`, or `simp_all`
|
||||
will fail if they do not make progress. -/
|
||||
failIfUnchanged : Bool := true
|
||||
/-- If `ground := true`, then ground terms are reduced. A term is ground when
|
||||
it does not contain free or meta variables. Reduction is interrupted at a function application `f ...`
|
||||
if `f` is marked to not be unfolded. -/
|
||||
ground : Bool := false
|
||||
deriving Inhabited, BEq, Repr
|
||||
|
||||
-- Configuration object for `simp_all`
|
||||
|
|
@ -1276,6 +1280,7 @@ def neutralConfig : Simp.Config := {
|
|||
decide := false
|
||||
arith := false
|
||||
autoUnfold := false
|
||||
ground := false
|
||||
}
|
||||
|
||||
end Simp
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ builtin_initialize registerTraceClass `Meta.Tactic.simp.congr (inherited := true
|
|||
builtin_initialize registerTraceClass `Meta.Tactic.simp.discharge (inherited := true)
|
||||
builtin_initialize registerTraceClass `Meta.Tactic.simp.rewrite (inherited := true)
|
||||
builtin_initialize registerTraceClass `Meta.Tactic.simp.unify (inherited := true)
|
||||
builtin_initialize registerTraceClass `Meta.Tactic.simp.ground (inherited := true)
|
||||
builtin_initialize registerTraceClass `Meta.Tactic.simp.numSteps
|
||||
builtin_initialize registerTraceClass `Meta.Tactic.simp.heads
|
||||
builtin_initialize registerTraceClass `Debug.Meta.Tactic.simp
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import Lean.Meta.Transform
|
|||
import Lean.Meta.Tactic.Replace
|
||||
import Lean.Meta.Tactic.UnifyEq
|
||||
import Lean.Meta.Tactic.Simp.Rewrite
|
||||
import Lean.Meta.Match.Value
|
||||
|
||||
namespace Lean.Meta
|
||||
namespace Simp
|
||||
|
|
@ -145,15 +146,59 @@ where
|
|||
let f := e.getAppFn
|
||||
f.isConst && isMatcherCore env f.constName!
|
||||
|
||||
/--
|
||||
Auxiliary function for implementing `ctx.config.ground`: evaluate ground terms eagerly.
|
||||
We currently use `whnf` to implement this feature, but we want to stop ground evaluation at symbols marked with the `-` modifier.
|
||||
For example, `simp (config := { ground := true }) [-f]` should not unfold `f` even if the goal contains a ground term such as `f 2`.
|
||||
-/
|
||||
private def canUnfoldAtSimpGround (erased : SimpTheoremsArray) (_ : Meta.Config) (info : ConstantInfo) : CoreM Bool := do
|
||||
return !erased.isErased (.decl info.name)
|
||||
|
||||
/--
|
||||
Try to unfold `e`.
|
||||
-/
|
||||
private def unfold? (e : Expr) : SimpM (Option Expr) := do
|
||||
let f := e.getAppFn
|
||||
if !f.isConst then
|
||||
return none
|
||||
let fName := f.constName!
|
||||
if (← isProjectionFn fName) then
|
||||
return none -- should be reduced by `reduceProjFn?`
|
||||
let ctx ← read
|
||||
if ctx.config.autoUnfold then
|
||||
-- TODO: remove `rec` after we switch to new code generator
|
||||
let rec unfoldGround? : SimpM (Option Expr) := do
|
||||
unless ctx.config.ground do return none
|
||||
-- We are assuming that assigned metavariables are going to be instantiated by the main simp loop.
|
||||
if e.hasExprMVar || e.hasFVar then return none
|
||||
if ctx.simpTheorems.isErased (.decl fName) then return none
|
||||
-- TODO: check whether we need more filters
|
||||
if (← isType e) then return none -- we don't unfold types
|
||||
if (← isProof e) then return none -- we don't unfold proofs
|
||||
if (← isInstance fName) then return none -- we don't unfold instances
|
||||
-- TODO: we must have a notion of `simp` value, or more general solution for Lean
|
||||
if Meta.isMatchValue e || isOfNatNatLit e then return none
|
||||
if e.isConst then
|
||||
-- We don't unfold constants that take arguments
|
||||
-- TODO: add support for skipping partial applications too.
|
||||
if let .forallE .. ← whnfD (← inferType e) then
|
||||
return none
|
||||
/-
|
||||
We are currently using `whnf` with a custom `canUnfold?` predicate to reduce ground terms.
|
||||
This can be inefficient, and produce proofs that are too expensive to type check in the Kernel. Some reasons:
|
||||
- Functions defined by Well-founded recursion are expensive to reduce here and in the kernel.
|
||||
- The kernel does not know we may have controlled reduction using `canUnfold?`.
|
||||
|
||||
It would be great to reduce the ground term using a to-be-implemented `cbv` tactic which produces a
|
||||
proof that can be efficiently checked by the kernel.
|
||||
-/
|
||||
let eNew ← withDefault <|
|
||||
withTheReader Meta.Context (fun c => { c with canUnfold? := canUnfoldAtSimpGround ctx.simpTheorems }) <| whnf e
|
||||
if eNew == e then return none
|
||||
trace[Meta.Tactic.simp.ground] "{e}\n---->\n{eNew}"
|
||||
return some eNew
|
||||
if let some eNew ← unfoldGround? then
|
||||
return some eNew
|
||||
else if (← isProjectionFn fName) then
|
||||
return none -- should be reduced by `reduceProjFn?`
|
||||
else if ctx.config.autoUnfold then
|
||||
if ctx.simpTheorems.isErased (.decl fName) then
|
||||
return none
|
||||
else if hasSmartUnfoldingDecl (← getEnv) fName then
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue