The `simp` tactic uses a discrimination tree to select candidate
theorems that will be used to rewrite an expression. This indexing data
structure minimizes the number of theorems that need to be tried and
improves performance. However, indexing modulo reducibility is
challenging, and a theorem that could be applied, when taking reduction
into account, may be missed. For example, suppose we have a `simp`
theorem `foo : forall x y, f x (x, y).2 = y`, and we are trying to
simplify the expression `f a b <= b`. `foo` will not be tried by `simp`
because the second argument of `f a b` is not a projection of a pair.
However, `f a b` is definitionally equal to `f a (a, b).2` since we can
reduce `(a, b).2`.
In Lean 3, we had a much simpler indexing data structure where only the
head symbol was taken into account. For the theorem `foo`, the head
symbol is `f`. Thus, the theorem would be considered by `simp`.
This commit adds the option `Simp.Config.index`. When `simp (config := {
index := false })`, only the head symbol is considered when retrieving
theorems, as in Lean 3. Moreover, if `set_option diagnostics true`,
`simp` will check whether every applied theorem would also have been
applied if `index := true`, and report them. This feature can help users
diagnose tricky issues in code that has been ported from libraries
developed using Lean 3 and then ported to Lean 4. In the following
example, it will report that `foo` is a problematic theorem.
```lean
opaque f : Nat → Nat → Nat
@[simp] theorem foo : f x (x, y).2 = y := by sorry
example : f a b ≤ b := by
set_option diagnostics true in
simp (config := { index := false })
```
In the example above, the following diagnostic message is produced.
```lean
[simp] theorems with bad keys
foo, key: [f, *, Prod.1, Prod.mk, Nat, Nat, *, *]
```
With the information above, users can annotate theorems such as `foo`
using `no_index` for problematic subterms.
Example:
```lean
opaque f : Nat → Nat → Nat
@[simp] theorem foo : f x (no_index (x, y).2) = y := by sorry
example : f a b ≤ b := by
simp -- `foo` is still applied
```
cc @semorrison
cc @PatrickMassot
207 lines
6.9 KiB
Text
207 lines
6.9 KiB
Text
/-
|
|
Copyright (c) Leonardo de Moura. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Authors: Leonardo de Moura
|
|
-/
|
|
prelude
|
|
import Init.Core
|
|
|
|
namespace Lean
|
|
|
|
structure NameGenerator where
|
|
namePrefix : Name := `_uniq
|
|
idx : Nat := 1
|
|
deriving Inhabited
|
|
|
|
/-- Syntax objects for a Lean module. -/
|
|
structure Module where
|
|
header : Syntax
|
|
commands : Array Syntax
|
|
|
|
namespace Meta
|
|
|
|
inductive TransparencyMode where
|
|
/-- unfold all constants, even those tagged as `@[irreducible]`. -/
|
|
| all
|
|
/-- unfold all constants except those tagged as `@[irreducible]`. -/
|
|
| default
|
|
/-- unfold only constants tagged with the `@[reducible]` attribute. -/
|
|
| reducible
|
|
/-- unfold reducible constants and constants tagged with the `@[instance]` attribute. -/
|
|
| instances
|
|
deriving Inhabited, BEq
|
|
|
|
inductive EtaStructMode where
|
|
/-- Enable eta for structure and classes. -/
|
|
| all
|
|
/-- Enable eta only for structures that are not classes. -/
|
|
| notClasses
|
|
/-- Disable eta for structures and classes. -/
|
|
| none
|
|
deriving Inhabited, BEq
|
|
|
|
namespace DSimp
|
|
|
|
structure Config where
|
|
/-- `let x := v; e[x]` reduces to `e[v]`. -/
|
|
zeta : Bool := true
|
|
beta : Bool := true
|
|
eta : Bool := true
|
|
etaStruct : EtaStructMode := .all
|
|
iota : Bool := true
|
|
proj : Bool := true
|
|
decide : Bool := false
|
|
autoUnfold : Bool := false
|
|
/-- If `failIfUnchanged := true`, then calls to `simp`, `dsimp`, or `simp_all`
|
|
will fail if they do not make progress. -/
|
|
failIfUnchanged : Bool := true
|
|
/-- If `unfoldPartialApp := true`, then calls to `simp`, `dsimp`, or `simp_all`
|
|
will unfold even partial applications of `f` when we request `f` to be unfolded. -/
|
|
unfoldPartialApp : Bool := false
|
|
/-- Given a local context containing entry `x : t := e`, free variable `x` reduces to `e`. -/
|
|
zetaDelta : Bool := false
|
|
deriving Inhabited, BEq
|
|
|
|
end DSimp
|
|
|
|
namespace Simp
|
|
|
|
def defaultMaxSteps := 100000
|
|
|
|
/--
|
|
The configuration for `simp`.
|
|
Passed to `simp` using, for example, the `simp (config := {contextual := true})` syntax.
|
|
|
|
See also `Lean.Meta.Simp.neutralConfig`.
|
|
-/
|
|
structure Config where
|
|
/--
|
|
The maximum number of subexpressions to visit when performing simplification.
|
|
The default is 100000.
|
|
-/
|
|
maxSteps : Nat := defaultMaxSteps
|
|
/--
|
|
When simp discharges side conditions for conditional lemmas, it can recursively apply simplification.
|
|
The `maxDischargeDepth` (default: 2) is the maximum recursion depth when recursively applying simplification to side conditions.
|
|
-/
|
|
maxDischargeDepth : Nat := 2
|
|
/--
|
|
When `contextual` is true (default: `false`) and simplification encounters an implication `p → q`
|
|
it includes `p` as an additional simp lemma when simplifying `q`.
|
|
-/
|
|
contextual : Bool := false
|
|
/--
|
|
When true (default: `true`) then the simplifier caches the result of simplifying each subexpression, if possible.
|
|
-/
|
|
memoize : Bool := true
|
|
/--
|
|
When `singlePass` is `true` (default: `false`), the simplifier runs through a single round of simplification,
|
|
which consists of running pre-methods, recursing using congruence lemmas, and then running post-methods.
|
|
Otherwise, when it is `false`, it iteratively applies this simplification procedure.
|
|
-/
|
|
singlePass : Bool := false
|
|
/--
|
|
When `true` (default: `true`), performs zeta reduction of let expressions.
|
|
That is, `let x := v; e[x]` reduces to `e[v]`.
|
|
See also `zetaDelta`.
|
|
-/
|
|
zeta : Bool := true
|
|
/--
|
|
When `true` (default: `true`), performs beta reduction of applications of `fun` expressions.
|
|
That is, `(fun x => e[x]) v` reduces to `e[v]`.
|
|
-/
|
|
beta : Bool := true
|
|
/--
|
|
TODO (currently unimplemented). When `true` (default: `true`), performs eta reduction for `fun` expressions.
|
|
That is, `(fun x => f x)` reduces to `f`.
|
|
-/
|
|
eta : Bool := true
|
|
/--
|
|
Configures how to determine definitional equality between two structure instances.
|
|
See documentation for `Lean.Meta.EtaStructMode`.
|
|
-/
|
|
etaStruct : EtaStructMode := .all
|
|
/--
|
|
When `true` (default: `true`), reduces `match` expressions applied to constructors.
|
|
-/
|
|
iota : Bool := true
|
|
/--
|
|
When `true` (default: `true`), reduces projections of structure constructors.
|
|
-/
|
|
proj : Bool := true
|
|
/--
|
|
When `true` (default: `false`), rewrites a proposition `p` to `True` or `False` by inferring
|
|
a `Decidable p` instance and reducing it.
|
|
-/
|
|
decide : Bool := false
|
|
/-- When `true` (default: `false`), simplifies simple arithmetic expressions. -/
|
|
arith : Bool := false
|
|
/--
|
|
When `true` (default: `false`), unfolds definitions.
|
|
This can be enabled using the `simp!` syntax.
|
|
-/
|
|
autoUnfold : Bool := false
|
|
/--
|
|
When `true` (default: `true`) then switches to `dsimp` on dependent arguments
|
|
if there is no congruence theorem that would allow `simp` to visit them.
|
|
When `dsimp` is `false`, then the argument is not visited.
|
|
-/
|
|
dsimp : Bool := true
|
|
/--
|
|
If `failIfUnchanged` is `true` (default: `true`), then calls to `simp`, `dsimp`, or `simp_all`
|
|
will fail if they do not make progress.
|
|
-/
|
|
failIfUnchanged : Bool := true
|
|
/--
|
|
If `ground` is `true` (default: `false`), 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 term reduction applies `@[seval]` lemmas.
|
|
-/
|
|
ground : Bool := false
|
|
/--
|
|
If `unfoldPartialApp` is `true` (default: `false`), then calls to `simp`, `dsimp`, or `simp_all`
|
|
will unfold even partial applications of `f` when we request `f` to be unfolded.
|
|
-/
|
|
unfoldPartialApp : Bool := false
|
|
/--
|
|
When `true` (default: `false`), local definitions are unfolded.
|
|
That is, given a local context containing entry `x : t := e`, the free variable `x` reduces to `e`.
|
|
-/
|
|
zetaDelta : Bool := false
|
|
/--
|
|
When `index` (default : `true`) is `false`, `simp` will only use the root symbol
|
|
to find candidate `simp` theorems. It approximates Lean 3 `simp` behavior.
|
|
-/
|
|
index : Bool := true
|
|
deriving Inhabited, BEq
|
|
|
|
-- Configuration object for `simp_all`
|
|
structure ConfigCtx extends Config where
|
|
contextual := true
|
|
|
|
/--
|
|
A neutral configuration for `simp`, turning off all reductions and other built-in simplifications.
|
|
-/
|
|
def neutralConfig : Simp.Config := {
|
|
zeta := false
|
|
beta := false
|
|
eta := false
|
|
iota := false
|
|
proj := false
|
|
decide := false
|
|
arith := false
|
|
autoUnfold := false
|
|
ground := false
|
|
zetaDelta := false
|
|
}
|
|
|
|
end Simp
|
|
|
|
inductive Occurrences where
|
|
| all
|
|
| pos (idxs : List Nat)
|
|
| neg (idxs : List Nat)
|
|
deriving Inhabited, BEq
|
|
|
|
end Lean.Meta
|