https://github.com/tristan-f-r/mathlib4-tactics
autogenerated tactics list for mathlib4
https://github.com/tristan-f-r/mathlib4-tactics
lean4 mathlib4
Last synced: 10 days ago
JSON representation
autogenerated tactics list for mathlib4
- Host: GitHub
- URL: https://github.com/tristan-f-r/mathlib4-tactics
- Owner: tristan-f-r
- Created: 2025-01-08T04:05:41.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-01-09T04:06:09.000Z (over 1 year ago)
- Last Synced: 2025-03-26T10:36:51.637Z (about 1 year ago)
- Topics: lean4, mathlib4
- Language: Lean
- Homepage:
- Size: 91.8 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# mathlib4-tactics
An autogenerated list of tactics from a modified `#help tactic`.
# "#adaptation_note" [«tactic#adaptation_note_»](https://leanprover-community.github.io/mathlib4_docs/search.html?q=«tactic#adaptation_note_»)
Adaptation notes are comments that are used to indicate that a piece of code
has been changed to accommodate a change in Lean core.
They typically require further action/maintenance to be taken in the future.
# "#check" [Mathlib.Tactic.«tactic#check__»](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.«tactic#check__»)
The `#check t` tactic elaborates the term `t` and then pretty prints it with its type as `e : ty`.
If `t` is an identifier, then it pretty prints a type declaration form
for the global constant `t` instead.
Use `#check (t)` to pretty print it as an elaborated expression.
Like the `#check` command, the `#check` tactic allows stuck typeclass instance problems.
These become metavariables in the output.
# "#find" [Mathlib.Tactic.Find.«tactic#find_»](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Find.«tactic#find_»)
# "#leansearch" [LeanSearchClient.leansearch_search_tactic](https://leanprover-community.github.io/mathlib4_docs/search.html?q=LeanSearchClient.leansearch_search_tactic)
Search [LeanSearch](https://leansearch.net/) from within Lean.
Queries should be a string that ends with a `.` or `?`. This works as a command, as a term
and as a tactic as in the following examples. In tactic mode, only valid tactics are displayed.
```lean
#leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m."
example := #leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m."
example : 3 ≤ 5 := by
#leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m."
sorry
```
# "#loogle" [LeanSearchClient.loogle_tactic](https://leanprover-community.github.io/mathlib4_docs/search.html?q=LeanSearchClient.loogle_tactic)
Search [Loogle](https://loogle.lean-lang.org/json) from within Lean. This can be used as a command, term or tactic as in the following examples. In the case of a tactic, only valid tactics are displayed.
```lean
#loogle List ?a → ?a
example := #loogle List ?a → ?a
example : 3 ≤ 5 := by
#loogle Nat.succ_le_succ
sorry
```
## Loogle Usage
Loogle finds definitions and lemmas in various ways:
By constant:
🔍 Real.sin
finds all lemmas whose statement somehow mentions the sine function.
By lemma name substring:
🔍 \"differ\"
finds all lemmas that have \"differ\" somewhere in their lemma name.
By subexpression:
🔍 _ * (_ ^ _)
finds all lemmas whose statements somewhere include a product where the second argument is raised to some power.
The pattern can also be non-linear, as in
🔍 Real.sqrt ?a * Real.sqrt ?a
If the pattern has parameters, they are matched in any order. Both of these will find List.map:
🔍 (?a -> ?b) -> List ?a -> List ?b
🔍 List ?a -> (?a -> ?b) -> List ?b
By main conclusion:
🔍 |- tsum _ = _ * tsum _
finds all lemmas where the conclusion (the subexpression to the right of all → and ∀) has the given shape.
As before, if the pattern has parameters, they are matched against the hypotheses of the lemma in any order; for example,
🔍 |- _ < _ → tsum _ < tsum _
will find tsum_lt_tsum even though the hypothesis f i < g i is not the last.
If you pass more than one such search filter, separated by commas Loogle will return lemmas which match all of them. The search
🔍 Real.sin, \"two\", tsum, _ * _, _ ^ _, |- _ < _ → _
woould find all lemmas which mention the constants Real.sin and tsum, have \"two\" as a substring of the lemma name, include a product and a power somewhere in the type, and have a hypothesis of the form _ < _ (if there were any such lemmas). Metavariables (?a) are assigned independently in each filter.
# "#loogle" [LeanSearchClient.just_loogle_tactic](https://leanprover-community.github.io/mathlib4_docs/search.html?q=LeanSearchClient.just_loogle_tactic)
# "#moogle" [LeanSearchClient.moogle_search_tactic](https://leanprover-community.github.io/mathlib4_docs/search.html?q=LeanSearchClient.moogle_search_tactic)
Search [Moogle](https://www.moogle.ai/api/search) from within Lean.
Queries should be a string that ends with a `.` or `?`. This works as a command, as a term
and as a tactic as in the following examples. In tactic mode, only valid tactics are displayed.
```lean
#moogle "If a natural number n is less than m, then the successor of n is less than the successor of m."
example := #moogle "If a natural number n is less than m, then the successor of n is less than the successor of m."
example : 3 ≤ 5 := by
#moogle "If a natural number n is less than m, then the successor of n is less than the successor of m."
sorry
```
# "(" [Parser.Tactic.paren](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.paren)
`(tacs)` executes a list of tactics in sequence, without requiring that
the goal be closed at the end like `· tacs`. Like `by` itself, the tactics
can be either separated by newlines or `;`.
# "<;>" [Batteries.Tactic.seq_focus](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Batteries.Tactic.seq_focus)
`t <;> [t1; t2; ...; tn]` focuses on the first goal and applies `t`, which should result in `n`
subgoals. It then applies each `ti` to the corresponding goal and collects the resulting
subgoals.
# "<;>" [Parser.Tactic.«tactic_<;>_»](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.«tactic_<;>_»)
`tac <;> tac'` runs `tac` on the main goal and `tac'` on each produced goal,
concatenating all goals produced by `tac'`.
# "_" [Batteries.Tactic.tactic_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Batteries.Tactic.tactic_)
`_` in tactic position acts like the `done` tactic: it fails and gives the list
of goals if there are any. It is useful as a placeholder after starting a tactic block
such as `by _` to make it syntactically correct and show the current goal.
# "abel" [Mathlib.Tactic.Abel.abel_term](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Abel.abel_term)
Unsupported legacy syntax from mathlib3, which allowed passing additional terms to `abel`.
# "abel" [Mathlib.Tactic.Abel.abel](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Abel.abel)
Tactic for evaluating expressions in abelian groups.
* `abel!` will use a more aggressive reducibility setting to determine equality of atoms.
* `abel1` fails if the target is not an equality.
For example:
```
example [AddCommMonoid α] (a b : α) : a + (b + a) = a + a + b := by abel
example [AddCommGroup α] (a : α) : (3 : ℤ) • a = a + (2 : ℤ) • a := by abel
```
# "abel!" [Mathlib.Tactic.Abel.abel!_term](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Abel.abel!_term)
Unsupported legacy syntax from mathlib3, which allowed passing additional terms to `abel!`.
# "abel!" [Mathlib.Tactic.Abel.tacticAbel!](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Abel.tacticAbel!)
Tactic for evaluating expressions in abelian groups.
* `abel!` will use a more aggressive reducibility setting to determine equality of atoms.
* `abel1` fails if the target is not an equality.
For example:
```
example [AddCommMonoid α] (a b : α) : a + (b + a) = a + a + b := by abel
example [AddCommGroup α] (a : α) : (3 : ℤ) • a = a + (2 : ℤ) • a := by abel
```
# "abel1" [Mathlib.Tactic.Abel.abel1](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Abel.abel1)
Tactic for solving equations in the language of
*additive*, commutative monoids and groups.
This version of `abel` fails if the target is not an equality
that is provable by the axioms of commutative monoids/groups.
`abel1!` will use a more aggressive reducibility setting to identify atoms.
This can prove goals that `abel` cannot, but is more expensive.
# "abel1!" [Mathlib.Tactic.Abel.abel1!](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Abel.abel1!)
Tactic for solving equations in the language of
*additive*, commutative monoids and groups.
This version of `abel` fails if the target is not an equality
that is provable by the axioms of commutative monoids/groups.
`abel1!` will use a more aggressive reducibility setting to identify atoms.
This can prove goals that `abel` cannot, but is more expensive.
# "abel_nf" [Mathlib.Tactic.Abel.abelNF](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Abel.abelNF)
Simplification tactic for expressions in the language of abelian groups,
which rewrites all group expressions into a normal form.
* `abel_nf!` will use a more aggressive reducibility setting to identify atoms.
* `abel_nf (config := cfg)` allows for additional configuration:
* `red`: the reducibility setting (overridden by `!`)
* `recursive`: if true, `abel_nf` will also recurse into atoms
* `abel_nf` works as both a tactic and a conv tactic.
In tactic mode, `abel_nf at h` can be used to rewrite in a hypothesis.
# "abel_nf!" [Mathlib.Tactic.Abel.tacticAbel_nf!__](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Abel.tacticAbel_nf!__)
Simplification tactic for expressions in the language of abelian groups,
which rewrites all group expressions into a normal form.
* `abel_nf!` will use a more aggressive reducibility setting to identify atoms.
* `abel_nf (config := cfg)` allows for additional configuration:
* `red`: the reducibility setting (overridden by `!`)
* `recursive`: if true, `abel_nf` will also recurse into atoms
* `abel_nf` works as both a tactic and a conv tactic.
In tactic mode, `abel_nf at h` can be used to rewrite in a hypothesis.
# "absurd" [Batteries.Tactic.tacticAbsurd_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Batteries.Tactic.tacticAbsurd_)
Given a proof `h` of `p`, `absurd h` changes the goal to `⊢ ¬ p`.
If `p` is a negation `¬q` then the goal is changed to `⊢ q` instead.
# "ac_change" [Mathlib.Tactic.acChange](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.acChange)
`ac_change g using n` is `convert_to g using n` followed by `ac_rfl`. It is useful for
rearranging/reassociating e.g. sums:
```lean
example (a b c d e f g N : ℕ) : (a + b) + (c + d) + (e + f) + g ≤ N := by
ac_change a + d + e + f + c + g + b ≤ _
-- ⊢ a + d + e + f + c + g + b ≤ N
```
# "ac_nf" [Parser.Tactic.tacticAc_nf_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacticAc_nf_)
`ac_nf` normalizes equalities up to application of an associative and commutative operator.
- `ac_nf` normalizes all hypotheses and the goal target of the goal.
- `ac_nf at l` normalizes at location(s) `l`, where `l` is either `*` or a
list of hypotheses in the local context. In the latter case, a turnstile `⊢` or `|-`
can also be used, to signify the target of the goal.
```
instance : Associative (α := Nat) (.+.) := ⟨Nat.add_assoc⟩
instance : Commutative (α := Nat) (.+.) := ⟨Nat.add_comm⟩
example (a b c d : Nat) : a + b + c + d = d + (b + c) + a := by
ac_nf
-- goal: a + (b + (c + d)) = a + (b + (c + d))
```
# "ac_nf0" [Parser.Tactic.acNf0](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.acNf0)
Implementation of `ac_nf` (the full `ac_nf` calls `trivial` afterwards).
# "ac_rfl" [Parser.Tactic.acRfl](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.acRfl)
`ac_rfl` proves equalities up to application of an associative and commutative operator.
```
instance : Associative (α := Nat) (.+.) := ⟨Nat.add_assoc⟩
instance : Commutative (α := Nat) (.+.) := ⟨Nat.add_comm⟩
example (a b c d : Nat) : a + b + c + d = d + (b + c) + a := by ac_rfl
```
# "admit" [Parser.Tactic.tacticAdmit](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacticAdmit)
`admit` is a synonym for `sorry`.
# "aesop" [Aesop.Frontend.Parser.aesopTactic](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Aesop.Frontend.Parser.aesopTactic)
`aesop *` tries to solve the current goal by applying a set of rules
registered with the `@[aesop]` attribute. See [its
README](https://github.com/JLimperg/aesop#readme) for a tutorial and a
reference.
The variant `aesop?` prints the proof it found as a `Try this` suggestion.
Clauses can be used to customise the behaviour of an Aesop call. Available
clauses are:
- `(add )` adds a rule. `` is
`unsafe`, `safe` or `norm`. `` is a percentage for unsafe rules and
an integer for safe and norm rules. `` is the name of a declaration or
local hypothesis. `` is the rule builder used to turn `` into
an Aesop rule. Example: `(add unsafe 50% apply Or.inl)`.
- `(erase )` disables a globally registered Aesop rule. Example: `(erase
Aesop.BuiltinRules.assumption)`.
- `(rule_sets := [,*])` enables or disables named sets of rules for
this Aesop call. Example: `(rule_sets := [-builtin, MyRuleSet])`.
- `(config { := })` adjusts Aesop's search options. See
`Aesop.Options`.
- `(simp_config { := })` adjusts options for Aesop's built-in
`simp` rule. The given options are directly passed to `simp`. For example,
`(simp_config := { zeta := false })` makes Aesop use
`simp (config := { zeta := false })`.
# "aesop?" [Aesop.Frontend.Parser.aesopTactic?](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Aesop.Frontend.Parser.aesopTactic?)
`aesop *` tries to solve the current goal by applying a set of rules
registered with the `@[aesop]` attribute. See [its
README](https://github.com/JLimperg/aesop#readme) for a tutorial and a
reference.
The variant `aesop?` prints the proof it found as a `Try this` suggestion.
Clauses can be used to customise the behaviour of an Aesop call. Available
clauses are:
- `(add )` adds a rule. `` is
`unsafe`, `safe` or `norm`. `` is a percentage for unsafe rules and
an integer for safe and norm rules. `` is the name of a declaration or
local hypothesis. `` is the rule builder used to turn `` into
an Aesop rule. Example: `(add unsafe 50% apply Or.inl)`.
- `(erase )` disables a globally registered Aesop rule. Example: `(erase
Aesop.BuiltinRules.assumption)`.
- `(rule_sets := [,*])` enables or disables named sets of rules for
this Aesop call. Example: `(rule_sets := [-builtin, MyRuleSet])`.
- `(config { := })` adjusts Aesop's search options. See
`Aesop.Options`.
- `(simp_config { := })` adjusts options for Aesop's built-in
`simp` rule. The given options are directly passed to `simp`. For example,
`(simp_config := { zeta := false })` makes Aesop use
`simp (config := { zeta := false })`.
# "aesop_cat" [CategoryTheory.aesop_cat](https://leanprover-community.github.io/mathlib4_docs/search.html?q=CategoryTheory.aesop_cat)
A thin wrapper for `aesop` which adds the `CategoryTheory` rule set and
allows `aesop` to look through semireducible definitions when calling `intros`.
This tactic fails when it is unable to solve the goal, making it suitable for
use in auto-params.
# "aesop_cat?" [CategoryTheory.aesop_cat?](https://leanprover-community.github.io/mathlib4_docs/search.html?q=CategoryTheory.aesop_cat?)
We also use `aesop_cat?` to pass along a `Try this` suggestion when using `aesop_cat`
# "aesop_cat_nonterminal" [CategoryTheory.aesop_cat_nonterminal](https://leanprover-community.github.io/mathlib4_docs/search.html?q=CategoryTheory.aesop_cat_nonterminal)
A variant of `aesop_cat` which does not fail when it is unable to solve the
goal. Use this only for exploration! Nonterminal `aesop` is even worse than
nonterminal `simp`.
# "aesop_unfold" [Aesop.tacticAesop_unfold_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Aesop.tacticAesop_unfold_)
# "aesop_unfold" [Aesop.tacticAesop_unfold_At_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Aesop.tacticAesop_unfold_At_)
# "algebraize" [Mathlib.Tactic.tacticAlgebraize__](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.tacticAlgebraize__)
Tactic that, given `RingHom`s, adds the corresponding `Algebra` and (if possible)
`IsScalarTower` instances, as well as `Algebra` corresponding to `RingHom` properties available
as hypotheses.
Example: given `f : A →+* B` and `g : B →+* C`, and `hf : f.FiniteType`, `algebraize [f, g]` will
add the instances `Algebra A B`, `Algebra B C`, and `Algebra.FiniteType A B`.
See the `algebraize` tag for instructions on what properties can be added.
The tactic also comes with a configuration option `properties`. If set to `true` (default), the
tactic searches through the local context for `RingHom` properties that can be converted to
`Algebra` properties. The macro `algebraize_only` calls
`algebraize (config := {properties := false})`,
so in other words it only adds `Algebra` and `IsScalarTower` instances.
# "algebraize_only" [Mathlib.Tactic.tacticAlgebraize_only__](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.tacticAlgebraize_only__)
Version of `algebraize`, which only adds `Algebra` instances and `IsScalarTower` instances,
but does not try to add any instances about any properties tagged with
`@[algebraize]`, like for example `Finite` or `IsIntegral`.
# "all_goals" [Parser.Tactic.allGoals](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.allGoals)
`all_goals tac` runs `tac` on each goal, concatenating the resulting goals.
If the tactic fails on any goal, the entire `all_goals` tactic fails.
See also `any_goals tac`.
# "and_intros" [Parser.Tactic.tacticAnd_intros](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacticAnd_intros)
`and_intros` applies `And.intro` until it does not make progress.
# "any_goals" [Parser.Tactic.anyGoals](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.anyGoals)
`any_goals tac` applies the tactic `tac` to every goal,
concating the resulting goals for successful tactic applications.
If the tactic fails on all of the goals, the entire `any_goals` tactic fails.
This tactic is like `all_goals try tac` except that it fails if none of the applications of `tac` succeeds.
# "apply" [Mathlib.Tactic.tacticApply_At_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.tacticApply_At_)
`apply t at i` will use forward reasoning with `t` at the hypothesis `i`.
Explicitly, if `t : α₁ → ⋯ → αᵢ → ⋯ → αₙ` and `i` has type `αᵢ`, then this tactic will add
metavariables/goals for any terms of `αⱼ` for `j = 1, …, i-1`,
then replace the type of `i` with `αᵢ₊₁ → ⋯ → αₙ` by applying those metavariables and the
original `i`.
# "apply" [Parser.Tactic.apply](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.apply)
`apply e` tries to match the current goal against the conclusion of `e`'s type.
If it succeeds, then the tactic returns as many subgoals as the number of premises that
have not been fixed by type inference or type class resolution.
Non-dependent premises are added before dependent ones.
The `apply` tactic uses higher-order pattern matching, type class resolution,
and first-order unification with dependent types.
# "apply" [Mathlib.Tactic.applyWith](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.applyWith)
`apply (config := cfg) e` is like `apply e` but allows you to provide a configuration
`cfg : ApplyConfig` to pass to the underlying `apply` operation.
# "apply?" [Parser.Tactic.apply?](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.apply?)
Searches environment for definitions or theorems that can refine the goal using `apply`
with conditions resolved when possible with `solve_by_elim`.
The optional `using` clause provides identifiers in the local context that must be
used when closing the goal.
# "apply_assumption" [Parser.Tactic.applyAssumption](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.applyAssumption)
`apply_assumption` looks for an assumption of the form `... → ∀ _, ... → head`
where `head` matches the current goal.
You can specify additional rules to apply using `apply_assumption [...]`.
By default `apply_assumption` will also try `rfl`, `trivial`, `congrFun`, and `congrArg`.
If you don't want these, or don't want to use all hypotheses, use `apply_assumption only [...]`.
You can use `apply_assumption [-h]` to omit a local hypothesis.
You can use `apply_assumption using [a₁, ...]` to use all lemmas which have been labelled
with the attributes `aᵢ` (these attributes must be created using `register_label_attr`).
`apply_assumption` will use consequences of local hypotheses obtained via `symm`.
If `apply_assumption` fails, it will call `exfalso` and try again.
Thus if there is an assumption of the form `P → ¬ Q`, the new tactic state
will have two goals, `P` and `Q`.
You can pass a further configuration via the syntax `apply_rules (config := {...}) lemmas`.
The options supported are the same as for `solve_by_elim` (and include all the options for `apply`).
# "apply_ext_theorem" [Ext.applyExtTheorem](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Ext.applyExtTheorem)
Apply a single extensionality theorem to the current goal.
# "apply_fun" [Mathlib.Tactic.applyFun](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.applyFun)
Apply a function to an equality or inequality in either a local hypothesis or the goal.
* If we have `h : a = b`, then `apply_fun f at h` will replace this with `h : f a = f b`.
* If we have `h : a ≤ b`, then `apply_fun f at h` will replace this with `h : f a ≤ f b`,
and create a subsidiary goal `Monotone f`.
`apply_fun` will automatically attempt to discharge this subsidiary goal using `mono`,
or an explicit solution can be provided with `apply_fun f at h using P`, where `P : Monotone f`.
* If we have `h : a < b`, then `apply_fun f at h` will replace this with `h : f a < f b`,
and create a subsidiary goal `StrictMono f` and behaves as in the previous case.
* If we have `h : a ≠ b`, then `apply_fun f at h` will replace this with `h : f a ≠ f b`,
and create a subsidiary goal `Injective f` and behaves as in the previous two cases.
* If the goal is `a ≠ b`, `apply_fun f` will replace this with `f a ≠ f b`.
* If the goal is `a = b`, `apply_fun f` will replace this with `f a = f b`,
and create a subsidiary goal `injective f`.
`apply_fun` will automatically attempt to discharge this subsidiary goal using local hypotheses,
or if `f` is actually an `Equiv`,
or an explicit solution can be provided with `apply_fun f using P`, where `P : Injective f`.
* If the goal is `a ≤ b` (or similarly for `a < b`), and `f` is actually an `OrderIso`,
`apply_fun f` will replace the goal with `f a ≤ f b`.
If `f` is anything else (e.g. just a function, or an `Equiv`), `apply_fun` will fail.
Typical usage is:
```lean
open Function
example (X Y Z : Type) (f : X → Y) (g : Y → Z) (H : Injective <| g ∘ f) :
Injective f := by
intros x x' h
apply_fun g at h
exact H h
```
The function `f` is handled similarly to how it would be handled by `refine` in that `f` can contain
placeholders. Named placeholders (like `?a` or `?_`) will produce new goals.
# "apply_mod_cast" [Parser.Tactic.tacticApply_mod_cast_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacticApply_mod_cast_)
Normalize casts in the goal and the given expression, then `apply` the expression to the goal.
# "apply_rfl" [Parser.Tactic.applyRfl](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.applyRfl)
The same as `rfl`, but without trying `eq_refl` at the end.
# "apply_rules" [Parser.Tactic.applyRules](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.applyRules)
`apply_rules [l₁, l₂, ...]` tries to solve the main goal by iteratively
applying the list of lemmas `[l₁, l₂, ...]` or by applying a local hypothesis.
If `apply` generates new goals, `apply_rules` iteratively tries to solve those goals.
You can use `apply_rules [-h]` to omit a local hypothesis.
`apply_rules` will also use `rfl`, `trivial`, `congrFun` and `congrArg`.
These can be disabled, as can local hypotheses, by using `apply_rules only [...]`.
You can use `apply_rules using [a₁, ...]` to use all lemmas which have been labelled
with the attributes `aᵢ` (these attributes must be created using `register_label_attr`).
You can pass a further configuration via the syntax `apply_rules (config := {...})`.
The options supported are the same as for `solve_by_elim` (and include all the options for `apply`).
`apply_rules` will try calling `symm` on hypotheses and `exfalso` on the goal as needed.
This can be disabled with `apply_rules (config := {symm := false, exfalso := false})`.
You can bound the iteration depth using the syntax `apply_rules (config := {maxDepth := n})`.
Unlike `solve_by_elim`, `apply_rules` does not perform backtracking, and greedily applies
a lemma from the list until it gets stuck.
# "arith_mult" [ArithmeticFunction.arith_mult](https://leanprover-community.github.io/mathlib4_docs/search.html?q=ArithmeticFunction.arith_mult)
`arith_mult` solves goals of the form `IsMultiplicative f` for `f : ArithmeticFunction R`
by applying lemmas tagged with the user attribute `arith_mult`.
# "arith_mult?" [ArithmeticFunction.arith_mult?](https://leanprover-community.github.io/mathlib4_docs/search.html?q=ArithmeticFunction.arith_mult?)
`arith_mult` solves goals of the form `IsMultiplicative f` for `f : ArithmeticFunction R`
by applying lemmas tagged with the user attribute `arith_mult`, and prints out the generated
proof term.
# "array_get_dec" [Array.tacticArray_get_dec](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Array.tacticArray_get_dec)
This tactic, added to the `decreasing_trivial` toolbox, proves that
`sizeOf arr[i] < sizeOf arr`, which is useful for well founded recursions
over a nested inductive like `inductive T | mk : Array T → T`.
# "array_mem_dec" [Array.tacticArray_mem_dec](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Array.tacticArray_mem_dec)
This tactic, added to the `decreasing_trivial` toolbox, proves that `sizeOf a < sizeOf arr`
provided that `a ∈ arr` which is useful for well founded recursions over a nested inductive like
`inductive T | mk : Array T → T`.
# "assumption" [Parser.Tactic.assumption](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.assumption)
`assumption` tries to solve the main goal using a hypothesis of compatible type, or else fails.
Note also the `‹t›` term notation, which is a shorthand for `show t by assumption`.
# "assumption'" [Mathlib.Tactic.tacticAssumption'](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.tacticAssumption')
Try calling `assumption` on all goals; succeeds if it closes at least one goal.
# "assumption_mod_cast" [Parser.Tactic.tacticAssumption_mod_cast_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacticAssumption_mod_cast_)
`assumption_mod_cast` is a variant of `assumption` that solves the goal
using a hypothesis. Unlike `assumption`, it first pre-processes the goal and
each hypothesis to move casts as far outwards as possible, so it can be used
in more situations.
Concretely, it runs `norm_cast` on the goal. For each local hypothesis `h`, it also
normalizes `h` with `norm_cast` and tries to use that to close the goal.
# "aux_group₁" [Mathlib.Tactic.Group.aux_group₁](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Group.aux_group₁)
Auxiliary tactic for the `group` tactic. Calls the simplifier only.
# "aux_group₂" [Mathlib.Tactic.Group.aux_group₂](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Group.aux_group₂)
Auxiliary tactic for the `group` tactic. Calls `ring_nf` to normalize exponents.
# "bddDefault" [tacticBddDefault](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticBddDefault)
Sets are automatically bounded or cobounded in complete lattices. To use the same statements
in complete and conditionally complete lattices but let automation fill automatically the
boundedness proofs in complete lattices, we use the tactic `bddDefault` in the statements,
in the form `(hA : BddAbove A := by bddDefault)`.
# "beta_reduce" [Mathlib.Tactic.betaReduceStx](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.betaReduceStx)
`beta_reduce at loc` completely beta reduces the given location.
This also exists as a `conv`-mode tactic.
This means that whenever there is an applied lambda expression such as
`(fun x => f x) y` then the argument is substituted into the lambda expression
yielding an expression such as `f y`.
# "bicategory" [Mathlib.Tactic.Bicategory.tacticBicategory](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Bicategory.tacticBicategory)
Use the coherence theorem for bicategories to solve equations in a bicategory,
where the two sides only differ by replacing strings of bicategory structural morphisms
(that is, associators, unitors, and identities)
with different strings of structural morphisms with the same source and target.
That is, `bicategory` can handle goals of the form
`a ≫ f ≫ b ≫ g ≫ c = a' ≫ f ≫ b' ≫ g ≫ c'`
where `a = a'`, `b = b'`, and `c = c'` can be proved using `bicategory_coherence`.
# "bicategory_coherence" [Mathlib.Tactic.BicategoryCoherence.tacticBicategory_coherence](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.BicategoryCoherence.tacticBicategory_coherence)
Coherence tactic for bicategories.
Use `pure_coherence` instead, which is a frontend to this one.
# "bicategory_coherence" [Mathlib.Tactic.Bicategory.tacticBicategory_coherence](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Bicategory.tacticBicategory_coherence)
Close the goal of the form `η = θ`, where `η` and `θ` are 2-isomorphisms made up only of
associators, unitors, and identities.
```lean
example {B : Type} [Bicategory B] {a : B} :
(λ_ (𝟙 a)).hom = (ρ_ (𝟙 a)).hom := by
bicategory_coherence
```
# "bicategory_nf" [Mathlib.Tactic.Bicategory.tacticBicategory_nf](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Bicategory.tacticBicategory_nf)
Normalize the both sides of an equality.
# "bitwise_assoc_tac" [Nat.tacticBitwise_assoc_tac](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Nat.tacticBitwise_assoc_tac)
Proving associativity of bitwise operations in general essentially boils down to a huge case
distinction, so it is shorter to use this tactic instead of proving it in the general case.
# "borelize" [Mathlib.Tactic.Borelize.tacticBorelize___](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Borelize.tacticBorelize___)
The behaviour of `borelize α` depends on the existing assumptions on `α`.
- if `α` is a topological space with instances `[MeasurableSpace α] [BorelSpace α]`, then
`borelize α` replaces the former instance by `borel α`;
- otherwise, `borelize α` adds instances `borel α : MeasurableSpace α` and `⟨rfl⟩ : BorelSpace α`.
Finally, `borelize α β γ` runs `borelize α; borelize β; borelize γ`.
# "bound" [«tacticBound[_]»](https://leanprover-community.github.io/mathlib4_docs/search.html?q=«tacticBound[_]»)
`bound` tactic for proving inequalities via straightforward recursion on expression structure.
An example use case is
```
-- Calc example: A weak lower bound for `z ↦ z^2 + c`
lemma le_sqr_add {c z : ℂ} (cz : abs c ≤ abs z) (z3 : 3 ≤ abs z) :
2 * abs z ≤ abs (z^2 + c) := by
calc abs (z^2 + c)
_ ≥ abs (z^2) - abs c := by bound
_ ≥ abs (z^2) - abs z := by bound
_ ≥ (abs z - 1) * abs z := by rw [mul_comm, mul_sub_one, ← pow_two, ← abs.map_pow]
_ ≥ 2 * abs z := by bound
```
`bound` is built on top of `aesop`, and uses
1. Apply lemmas registered via the `@[bound]` attribute
2. Forward lemmas registered via the `@[bound_forward]` attribute
3. Local hypotheses from the context
4. Optionally: additional hypotheses provided as `bound [h₀, h₁]` or similar. These are added to the
context as if by `have := hᵢ`.
The functionality of `bound` overlaps with `positivity` and `gcongr`, but can jump back and forth
between `0 ≤ x` and `x ≤ y`-type inequalities. For example, `bound` proves
`0 ≤ c → b ≤ a → 0 ≤ a * c - b * c`
by turning the goal into `b * c ≤ a * c`, then using `mul_le_mul_of_nonneg_right`. `bound` also
contains lemmas for goals of the form `1 ≤ x, 1 < x, x ≤ 1, x < 1`. Conversely, `gcongr` can prove
inequalities for more types of relations, supports all `positivity` functionality, and is likely
faster since it is more specialized (not built atop `aesop`).
# "bv_check" [Parser.Tactic.bvCheck](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.bvCheck)
This tactic works just like `bv_decide` but skips calling a SAT solver by using a proof that is
already stored on disk. It is called with the name of an LRAT file in the same directory as the
current Lean file:
```
bv_check "proof.lrat"
```
# "bv_decide" [Parser.Tactic.bvDecide](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.bvDecide)
Close fixed-width `BitVec` and `Bool` goals by obtaining a proof from an external SAT solver and
verifying it inside Lean. The solvable goals are currently limited to the Lean equivalent of
[`QF_BV`](https://smt-lib.org/logics-all.shtml#QF_BV):
```lean
example : ∀ (a b : BitVec 64), (a &&& b) + (a ^^^ b) = a ||| b := by
intros
bv_decide
```
If `bv_decide` encounters an unknown definition it will be treated like an unconstrained `BitVec`
variable. Sometimes this enables solving goals despite not understanding the definition because
the precise properties of the definition do not matter in the specific proof.
If `bv_decide` fails to close a goal it provides a counter-example, containing assignments for all
terms that were considered as variables.
In order to avoid calling a SAT solver every time, the proof can be cached with `bv_decide?`.
If solving your problem relies inherently on using associativity or commutativity, consider enabling
the `bv.ac_nf` option.
Note: `bv_decide` uses `ofReduceBool` and thus trusts the correctness of the code generator.
# "bv_decide?" [Parser.Tactic.bvTrace](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.bvTrace)
Suggest a proof script for a `bv_decide` tactic call. Useful for caching LRAT proofs.
# "bv_normalize" [Parser.Tactic.bvNormalize](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.bvNormalize)
Run the normalization procedure of `bv_decide` only. Sometimes this is enough to solve basic
`BitVec` goals already.
# "bv_omega" [Parser.Tactic.tacticBv_omega](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacticBv_omega)
`bv_omega` is `omega` with an additional preprocessor that turns statements about `BitVec` into statements about `Nat`.
Currently the preprocessor is implemented as `try simp only [bv_toNat] at *`.
`bv_toNat` is a `@[simp]` attribute that you can (cautiously) add to more theorems.
# "by_cases" [«tacticBy_cases_:_»](https://leanprover-community.github.io/mathlib4_docs/search.html?q=«tacticBy_cases_:_»)
`by_cases (h :)? p` splits the main goal into two cases, assuming `h : p` in the first branch, and `h : ¬ p` in the second branch.
# "by_contra" [Batteries.Tactic.byContra](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Batteries.Tactic.byContra)
`by_contra h` proves `⊢ p` by contradiction,
introducing a hypothesis `h : ¬p` and proving `False`.
* If `p` is a negation `¬q`, `h : q` will be introduced instead of `¬¬q`.
* If `p` is decidable, it uses `Decidable.byContradiction` instead of `Classical.byContradiction`.
* If `h` is omitted, the introduced variable `_: ¬p` will be anonymous.
# "by_contra!" [byContra!](https://leanprover-community.github.io/mathlib4_docs/search.html?q=byContra!)
If the target of the main goal is a proposition `p`,
`by_contra!` reduces the goal to proving `False` using the additional hypothesis `this : ¬ p`.
`by_contra! h` can be used to name the hypothesis `h : ¬ p`.
The hypothesis `¬ p` will be negation normalized using `push_neg`.
For instance, `¬ a < b` will be changed to `b ≤ a`.
`by_contra! h : q` will normalize negations in `¬ p`, normalize negations in `q`,
and then check that the two normalized forms are equal.
The resulting hypothesis is the pre-normalized form, `q`.
If the name `h` is not explicitly provided, then `this` will be used as name.
This tactic uses classical reasoning.
It is a variant on the tactic `by_contra`.
Examples:
```lean
example : 1 < 2 := by
by_contra! h
-- h : 2 ≤ 1 ⊢ False
example : 1 < 2 := by
by_contra! h : ¬ 1 < 2
-- h : ¬ 1 < 2 ⊢ False
```
# "calc" [calcTactic](https://leanprover-community.github.io/mathlib4_docs/search.html?q=calcTactic)
Step-wise reasoning over transitive relations.
```
calc
a = b := pab
b = c := pbc
...
y = z := pyz
```
proves `a = z` from the given step-wise proofs. `=` can be replaced with any
relation implementing the typeclass `Trans`. Instead of repeating the right-
hand sides, subsequent left-hand sides can be replaced with `_`.
```
calc
a = b := pab
_ = c := pbc
...
_ = z := pyz
```
It is also possible to write the *first* relation as `\n _ = :=
`. This is useful for aligning relation symbols, especially on longer:
identifiers:
```
calc abc
_ = bce := pabce
_ = cef := pbcef
...
_ = xyz := pwxyz
```
`calc` works as a term, as a tactic or as a `conv` tactic.
See [Theorem Proving in Lean 4][tpil4] for more information.
[tpil4]: https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#calculational-proofs
# "cancel_denoms" [tacticCancel_denoms_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticCancel_denoms_)
# "cancel_denoms" [cancelDenoms](https://leanprover-community.github.io/mathlib4_docs/search.html?q=cancelDenoms)
`cancel_denoms` attempts to remove numerals from the denominators of fractions.
It works on propositions that are field-valued inequalities.
```lean
variable [LinearOrderedField α] (a b c : α)
example (h : a / 5 + b / 4 < c) : 4*a + 5*b < 20*c := by
cancel_denoms at h
exact h
example (h : a > 0) : a / 5 > 0 := by
cancel_denoms
exact h
```
# "case" [Parser.Tactic.case](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.case)
* `case tag => tac` focuses on the goal with case name `tag` and solves it using `tac`,
or else fails.
* `case tag x₁ ... xₙ => tac` additionally renames the `n` most recent hypotheses
with inaccessible names to the given names.
* `case tag₁ | tag₂ => tac` is equivalent to `(case tag₁ => tac); (case tag₂ => tac)`.
# "case'" [Parser.Tactic.case'](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.case')
`case'` is similar to the `case tag => tac` tactic, but does not ensure the goal
has been solved after applying `tac`, nor admits the goal if `tac` failed.
Recall that `case` closes the goal using `sorry` when `tac` fails, and
the tactic execution is not interrupted.
# "cases" [Parser.Tactic.cases](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.cases)
Assuming `x` is a variable in the local context with an inductive type,
`cases x` splits the main goal, producing one goal for each constructor of the
inductive type, in which the target is replaced by a general instance of that constructor.
If the type of an element in the local context depends on `x`,
that element is reverted and reintroduced afterward,
so that the case split affects that hypothesis as well.
`cases` detects unreachable cases and closes them automatically.
For example, given `n : Nat` and a goal with a hypothesis `h : P n` and target `Q n`,
`cases n` produces one goal with hypothesis `h : P 0` and target `Q 0`,
and one goal with hypothesis `h : P (Nat.succ a)` and target `Q (Nat.succ a)`.
Here the name `a` is chosen automatically and is not accessible.
You can use `with` to provide the variables names for each constructor.
- `cases e`, where `e` is an expression instead of a variable, generalizes `e` in the goal,
and then cases on the resulting variable.
- Given `as : List α`, `cases as with | nil => tac₁ | cons a as' => tac₂`,
uses tactic `tac₁` for the `nil` case, and `tac₂` for the `cons` case,
and `a` and `as'` are used as names for the new variables introduced.
- `cases h : e`, where `e` is a variable or an expression,
performs cases on `e` as above, but also adds a hypothesis `h : e = ...` to each hypothesis,
where `...` is the constructor instance for that particular case.
# "cases'" [Mathlib.Tactic.cases'](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.cases')
The `cases'` tactic is similar to the `cases` tactic in Lean 4 core, but the syntax for giving
names is different:
```
example (h : p ∨ q) : q ∨ p := by
cases h with
| inl hp => exact Or.inr hp
| inr hq => exact Or.inl hq
example (h : p ∨ q) : q ∨ p := by
cases' h with hp hq
· exact Or.inr hp
· exact Or.inl hq
example (h : p ∨ q) : q ∨ p := by
rcases h with hp | hq
· exact Or.inr hp
· exact Or.inl hq
```
Prefer `cases` or `rcases` when possible, because these tactics promote structured proofs.
# "cases_type" [Mathlib.Tactic.casesType](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.casesType)
* `cases_type I` applies the `cases` tactic to a hypothesis `h : (I ...)`
* `cases_type I_1 ... I_n` applies the `cases` tactic to a hypothesis
`h : (I_1 ...)` or ... or `h : (I_n ...)`
* `cases_type* I` is shorthand for `· repeat cases_type I`
* `cases_type! I` only applies `cases` if the number of resulting subgoals is <= 1.
Example: The following tactic destructs all conjunctions and disjunctions in the current goal.
```
cases_type* Or And
```
# "cases_type!" [Mathlib.Tactic.casesType!](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.casesType!)
* `cases_type I` applies the `cases` tactic to a hypothesis `h : (I ...)`
* `cases_type I_1 ... I_n` applies the `cases` tactic to a hypothesis
`h : (I_1 ...)` or ... or `h : (I_n ...)`
* `cases_type* I` is shorthand for `· repeat cases_type I`
* `cases_type! I` only applies `cases` if the number of resulting subgoals is <= 1.
Example: The following tactic destructs all conjunctions and disjunctions in the current goal.
```
cases_type* Or And
```
# "casesm" [Mathlib.Tactic.casesM](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.casesM)
* `casesm p` applies the `cases` tactic to a hypothesis `h : type`
if `type` matches the pattern `p`.
* `casesm p_1, ..., p_n` applies the `cases` tactic to a hypothesis `h : type`
if `type` matches one of the given patterns.
* `casesm* p` is a more efficient and compact version of `· repeat casesm p`.
It is more efficient because the pattern is compiled once.
Example: The following tactic destructs all conjunctions and disjunctions in the current context.
```
casesm* _ ∨ _, _ ∧ _
```
# "cc" [Mathlib.Tactic.cc](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.cc)
The congruence closure tactic `cc` tries to solve the goal by chaining
equalities from context and applying congruence (i.e. if `a = b`, then `f a = f b`).
It is a finishing tactic, i.e. it is meant to close
the current goal, not to make some inconclusive progress.
A mostly trivial example would be:
```lean
example (a b c : ℕ) (f : ℕ → ℕ) (h: a = b) (h' : b = c) : f a = f c := by
cc
```
As an example requiring some thinking to do by hand, consider:
```lean
example (f : ℕ → ℕ) (x : ℕ)
(H1 : f (f (f x)) = x) (H2 : f (f (f (f (f x)))) = x) :
f x = x := by
cc
```
# "cfc_cont_tac" [cfcContTac](https://leanprover-community.github.io/mathlib4_docs/search.html?q=cfcContTac)
A tactic used to automatically discharge goals relating to the continuous functional calculus,
specifically concerning continuity of the functions involved.
# "cfc_tac" [cfcTac](https://leanprover-community.github.io/mathlib4_docs/search.html?q=cfcTac)
A tactic used to automatically discharge goals relating to the continuous functional calculus,
specifically whether the element satisfies the predicate.
# "cfc_zero_tac" [cfcZeroTac](https://leanprover-community.github.io/mathlib4_docs/search.html?q=cfcZeroTac)
A tactic used to automatically discharge goals relating to the non-unital continuous functional
calculus, specifically concerning whether `f 0 = 0`.
# "change" [Parser.Tactic.change](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.change)
* `change tgt'` will change the goal from `tgt` to `tgt'`,
assuming these are definitionally equal.
* `change t' at h` will change hypothesis `h : t` to have type `t'`, assuming
assuming `t` and `t'` are definitionally equal.
# "change" [Parser.Tactic.changeWith](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.changeWith)
* `change a with b` will change occurrences of `a` to `b` in the goal,
assuming `a` and `b` are definitionally equal.
* `change a with b at h` similarly changes `a` to `b` in the type of hypothesis `h`.
# "change?" [change?](https://leanprover-community.github.io/mathlib4_docs/search.html?q=change?)
`change? term` unifies `term` with the current goal, then suggests explicit `change` syntax
that uses the resulting unified term.
If `term` is not present, `change?` suggests the current goal itself. This is useful after tactics
which transform the goal while maintaining definitional equality, such as `dsimp`; those preceding
tactic calls can then be deleted.
```lean
example : (fun x : Nat => x) 0 = 1 := by
change? 0 = _ -- `Try this: change 0 = 1`
```
# "checkpoint" [Parser.Tactic.checkpoint](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.checkpoint)
`checkpoint tac` acts the same as `tac`, but it caches the input and output of `tac`,
and if the file is re-elaborated and the input matches, the tactic is not re-run and
its effects are reapplied to the state. This is useful for improving responsiveness
when working on a long tactic proof, by wrapping expensive tactics with `checkpoint`.
See the `save` tactic, which may be more convenient to use.
(TODO: do this automatically and transparently so that users don't have to use
this combinator explicitly.)
# "choose" [Mathlib.Tactic.Choose.choose](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Choose.choose)
* `choose a b h h' using hyp` takes a hypothesis `hyp` of the form
`∀ (x : X) (y : Y), ∃ (a : A) (b : B), P x y a b ∧ Q x y a b`
for some `P Q : X → Y → A → B → Prop` and outputs
into context a function `a : X → Y → A`, `b : X → Y → B` and two assumptions:
`h : ∀ (x : X) (y : Y), P x y (a x y) (b x y)` and
`h' : ∀ (x : X) (y : Y), Q x y (a x y) (b x y)`. It also works with dependent versions.
* `choose! a b h h' using hyp` does the same, except that it will remove dependency of
the functions on propositional arguments if possible. For example if `Y` is a proposition
and `A` and `B` are nonempty in the above example then we will instead get
`a : X → A`, `b : X → B`, and the assumptions
`h : ∀ (x : X) (y : Y), P x y (a x) (b x)` and
`h' : ∀ (x : X) (y : Y), Q x y (a x) (b x)`.
The `using hyp` part can be omitted,
which will effectively cause `choose` to start with an `intro hyp`.
Examples:
```
example (h : ∀ n m : ℕ, ∃ i j, m = n + i ∨ m + j = n) : True := by
choose i j h using h
guard_hyp i : ℕ → ℕ → ℕ
guard_hyp j : ℕ → ℕ → ℕ
guard_hyp h : ∀ (n m : ℕ), m = n + i n m ∨ m + j n m = n
trivial
```
```
example (h : ∀ i : ℕ, i < 7 → ∃ j, i < j ∧ j < i+i) : True := by
choose! f h h' using h
guard_hyp f : ℕ → ℕ
guard_hyp h : ∀ (i : ℕ), i < 7 → i < f i
guard_hyp h' : ∀ (i : ℕ), i < 7 → f i < i + i
trivial
```
# "choose!" [Mathlib.Tactic.Choose.tacticChoose!___Using_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Choose.tacticChoose!___Using_)
* `choose a b h h' using hyp` takes a hypothesis `hyp` of the form
`∀ (x : X) (y : Y), ∃ (a : A) (b : B), P x y a b ∧ Q x y a b`
for some `P Q : X → Y → A → B → Prop` and outputs
into context a function `a : X → Y → A`, `b : X → Y → B` and two assumptions:
`h : ∀ (x : X) (y : Y), P x y (a x y) (b x y)` and
`h' : ∀ (x : X) (y : Y), Q x y (a x y) (b x y)`. It also works with dependent versions.
* `choose! a b h h' using hyp` does the same, except that it will remove dependency of
the functions on propositional arguments if possible. For example if `Y` is a proposition
and `A` and `B` are nonempty in the above example then we will instead get
`a : X → A`, `b : X → B`, and the assumptions
`h : ∀ (x : X) (y : Y), P x y (a x) (b x)` and
`h' : ∀ (x : X) (y : Y), Q x y (a x) (b x)`.
The `using hyp` part can be omitted,
which will effectively cause `choose` to start with an `intro hyp`.
Examples:
```
example (h : ∀ n m : ℕ, ∃ i j, m = n + i ∨ m + j = n) : True := by
choose i j h using h
guard_hyp i : ℕ → ℕ → ℕ
guard_hyp j : ℕ → ℕ → ℕ
guard_hyp h : ∀ (n m : ℕ), m = n + i n m ∨ m + j n m = n
trivial
```
```
example (h : ∀ i : ℕ, i < 7 → ∃ j, i < j ∧ j < i+i) : True := by
choose! f h h' using h
guard_hyp f : ℕ → ℕ
guard_hyp h : ∀ (i : ℕ), i < 7 → i < f i
guard_hyp h' : ∀ (i : ℕ), i < 7 → f i < i + i
trivial
```
# "classical" [Parser.Tactic.classical](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.classical)
`classical tacs` runs `tacs` in a scope where `Classical.propDecidable` is a low priority
local instance.
Note that `classical` is a scoping tactic: it adds the instance only within the
scope of the tactic.
# "clean" [Mathlib.Tactic.tacticClean_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.tacticClean_)
(Deprecated) `clean t` is a macro for `exact clean% t`.
# "clean_wf" [tacticClean_wf](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticClean_wf)
This tactic is used internally by lean before presenting the proof obligations from a well-founded
definition to the user via `decreasing_by`. It is not necessary to use this tactic manually.
# "clear" [clearExcept](https://leanprover-community.github.io/mathlib4_docs/search.html?q=clearExcept)
Clears all hypotheses it can, except those provided after a minus sign. Example:
```
clear * - h₁ h₂
```
# "clear" [Parser.Tactic.clear](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.clear)
`clear x...` removes the given hypotheses, or fails if there are remaining
references to a hypothesis.
# "clear!" [Mathlib.Tactic.clear!](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.clear!)
A variant of `clear` which clears not only the given hypotheses but also any other hypotheses
depending on them
# "clear_" [Mathlib.Tactic.clear_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.clear_)
Clear all hypotheses starting with `_`, like `_match` and `_let_match`.
# "clear_aux_decl" [Mathlib.Tactic.clearAuxDecl](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.clearAuxDecl)
This tactic clears all auxiliary declarations from the context.
# "clear_value" [Mathlib.Tactic.clearValue](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.clearValue)
`clear_value n₁ n₂ ...` clears the bodies of the local definitions `n₁, n₂ ...`, changing them
into regular hypotheses. A hypothesis `n : α := t` is changed to `n : α`.
The order of `n₁ n₂ ...` does not matter, and values will be cleared in reverse order of
where they appear in the context.
# "coherence" [Mathlib.Tactic.Coherence.coherence](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Coherence.coherence)
Use the coherence theorem for monoidal categories to solve equations in a monoidal equation,
where the two sides only differ by replacing strings of monoidal structural morphisms
(that is, associators, unitors, and identities)
with different strings of structural morphisms with the same source and target.
That is, `coherence` can handle goals of the form
`a ≫ f ≫ b ≫ g ≫ c = a' ≫ f ≫ b' ≫ g ≫ c'`
where `a = a'`, `b = b'`, and `c = c'` can be proved using `pure_coherence`.
(If you have very large equations on which `coherence` is unexpectedly failing,
you may need to increase the typeclass search depth,
using e.g. `set_option synthInstance.maxSize 500`.)
# "compareOfLessAndEq_rfl" [tacticCompareOfLessAndEq_rfl](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticCompareOfLessAndEq_rfl)
This attempts to prove that a given instance of `compare` is equal to `compareOfLessAndEq` by
introducing the arguments and trying the following approaches in order:
1. seeing if `rfl` works
2. seeing if the `compare` at hand is nonetheless essentially `compareOfLessAndEq`, but, because of
implicit arguments, requires us to unfold the defs and split the `if`s in the definition of
`compareOfLessAndEq`
3. seeing if we can split by cases on the arguments, then see if the defs work themselves out
(useful when `compare` is defined via a `match` statement, as it is for `Bool`)
# "compute_degree" [Mathlib.Tactic.ComputeDegree.computeDegree](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.ComputeDegree.computeDegree)
`compute_degree` is a tactic to solve goals of the form
* `natDegree f = d`,
* `degree f = d`,
* `natDegree f ≤ d`,
* `degree f ≤ d`,
* `coeff f d = r`, if `d` is the degree of `f`.
The tactic may leave goals of the form `d' = d` `d' ≤ d`, or `r ≠ 0`, where `d'` in `ℕ` or
`WithBot ℕ` is the tactic's guess of the degree, and `r` is the coefficient's guess of the
leading coefficient of `f`.
`compute_degree` applies `norm_num` to the left-hand side of all side goals, trying to close them.
The variant `compute_degree!` first applies `compute_degree`.
Then it uses `norm_num` on all the whole remaining goals and tries `assumption`.
# "compute_degree!" [Mathlib.Tactic.ComputeDegree.tacticCompute_degree!](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.ComputeDegree.tacticCompute_degree!)
`compute_degree` is a tactic to solve goals of the form
* `natDegree f = d`,
* `degree f = d`,
* `natDegree f ≤ d`,
* `degree f ≤ d`,
* `coeff f d = r`, if `d` is the degree of `f`.
The tactic may leave goals of the form `d' = d` `d' ≤ d`, or `r ≠ 0`, where `d'` in `ℕ` or
`WithBot ℕ` is the tactic's guess of the degree, and `r` is the coefficient's guess of the
leading coefficient of `f`.
`compute_degree` applies `norm_num` to the left-hand side of all side goals, trying to close them.
The variant `compute_degree!` first applies `compute_degree`.
Then it uses `norm_num` on all the whole remaining goals and tries `assumption`.
# "congr" [Parser.Tactic.congr](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.congr)
Apply congruence (recursively) to goals of the form `⊢ f as = f bs` and `⊢ HEq (f as) (f bs)`.
The optional parameter is the depth of the recursive applications.
This is useful when `congr` is too aggressive in breaking down the goal.
For example, given `⊢ f (g (x + y)) = f (g (y + x))`,
`congr` produces the goals `⊢ x = y` and `⊢ y = x`,
while `congr 2` produces the intended `⊢ x + y = y + x`.
# "congr" [Batteries.Tactic.congrConfigWith](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Batteries.Tactic.congrConfigWith)
Apply congruence (recursively) to goals of the form `⊢ f as = f bs` and `⊢ HEq (f as) (f bs)`.
* `congr n` controls the depth of the recursive applications.
This is useful when `congr` is too aggressive in breaking down the goal.
For example, given `⊢ f (g (x + y)) = f (g (y + x))`,
`congr` produces the goals `⊢ x = y` and `⊢ y = x`,
while `congr 2` produces the intended `⊢ x + y = y + x`.
* If, at any point, a subgoal matches a hypothesis then the subgoal will be closed.
* You can use `congr with p (: n)?` to call `ext p (: n)?` to all subgoals generated by `congr`.
For example, if the goal is `⊢ f '' s = g '' s` then `congr with x` generates the goal
`x : α ⊢ f x = g x`.
# "congr" [Batteries.Tactic.congrConfig](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Batteries.Tactic.congrConfig)
Apply congruence (recursively) to goals of the form `⊢ f as = f bs` and `⊢ HEq (f as) (f bs)`.
The optional parameter is the depth of the recursive applications.
This is useful when `congr` is too aggressive in breaking down the goal.
For example, given `⊢ f (g (x + y)) = f (g (y + x))`,
`congr` produces the goals `⊢ x = y` and `⊢ y = x`,
while `congr 2` produces the intended `⊢ x + y = y + x`.
# "congr!" [Congr!.congr!](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Congr!.congr!)
Equates pieces of the left-hand side of a goal to corresponding pieces of the right-hand side by
recursively applying congruence lemmas. For example, with `⊢ f as = g bs` we could get
two goals `⊢ f = g` and `⊢ as = bs`.
Syntax:
```
congr!
congr! n
congr! with x y z
congr! n with x y z
```
Here, `n` is a natural number and `x`, `y`, `z` are `rintro` patterns (like `h`, `rfl`, `⟨x, y⟩`,
`_`, `-`, `(h | h)`, etc.).
The `congr!` tactic is similar to `congr` but is more insistent in trying to equate left-hand sides
to right-hand sides of goals. Here is a list of things it can try:
- If `R` in `⊢ R x y` is a reflexive relation, it will convert the goal to `⊢ x = y` if possible.
The list of reflexive relations is maintained using the `@[refl]` attribute.
As a special case, `⊢ p ↔ q` is converted to `⊢ p = q` during congruence processing and then
returned to `⊢ p ↔ q` form at the end.
- If there is a user congruence lemma associated to the goal (for instance, a `@[congr]`-tagged
lemma applying to `⊢ List.map f xs = List.map g ys`), then it will use that.
- It uses a congruence lemma generator at least as capable as the one used by `congr` and `simp`.
If there is a subexpression that can be rewritten by `simp`, then `congr!` should be able
to generate an equality for it.
- It can do congruences of pi types using lemmas like `implies_congr` and `pi_congr`.
- Before applying congruences, it will run the `intros` tactic automatically.
The introduced variables can be given names using a `with` clause.
This helps when congruence lemmas provide additional assumptions in hypotheses.
- When there is an equality between functions, so long as at least one is obviously a lambda, we
apply `funext` or `Function.hfunext`, which allows for congruence of lambda bodies.
- It can try to close goals using a few strategies, including checking
definitional equality, trying to apply `Subsingleton.elim` or `proof_irrel_heq`, and using the
`assumption` tactic.
The optional parameter is the depth of the recursive applications.
This is useful when `congr!` is too aggressive in breaking down the goal.
For example, given `⊢ f (g (x + y)) = f (g (y + x))`,
`congr!` produces the goals `⊢ x = y` and `⊢ y = x`,
while `congr! 2` produces the intended `⊢ x + y = y + x`.
The `congr!` tactic also takes a configuration option, for example
```lean
congr! (config := {transparency := .default}) 2
```
This overrides the default, which is to apply congruence lemmas at reducible transparency.
The `congr!` tactic is aggressive with equating two sides of everything. There is a predefined
configuration that uses a different strategy:
Try
```lean
congr! (config := .unfoldSameFun)
```
This only allows congruences between functions applications of definitionally equal functions,
and it applies congruence lemmas at default transparency (rather than just reducible).
This is somewhat like `congr`.
See `Congr!.Config` for all options.
# "congrm" [Mathlib.Tactic.congrM](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.congrM)
`congrm e` is a tactic for proving goals of the form `lhs = rhs`, `lhs ↔ rhs`, `HEq lhs rhs`,
or `R lhs rhs` when `R` is a reflexive relation.
The expression `e` is a pattern containing placeholders `?_`,
and this pattern is matched against `lhs` and `rhs` simultaneously.
These placeholders generate new goals that state that corresponding subexpressions
in `lhs` and `rhs` are equal.
If the placeholders have names, such as `?m`, then the new goals are given tags with those names.
Examples:
```lean
example {a b c d : ℕ} :
Nat.pred a.succ * (d + (c + a.pred)) = Nat.pred b.succ * (b + (c + d.pred)) := by
congrm Nat.pred (Nat.succ ?h1) * (?h2 + ?h3)
/- Goals left:
case h1 ⊢ a = b
case h2 ⊢ d = b
case h3 ⊢ c + a.pred = c + d.pred
-/
sorry
sorry
sorry
example {a b : ℕ} (h : a = b) : (fun y : ℕ => ∀ z, a + a = z) = (fun x => ∀ z, b + a = z) := by
congrm fun x => ∀ w, ?_ + a = w
-- ⊢ a = b
exact h
```
The `congrm` command is a convenient frontend to `congr(...)` congruence quotations.
If the goal is an equality, `congrm e` is equivalent to `refine congr(e')` where `e'` is
built from `e` by replacing each placeholder `?m` by `$(?m)`.
The pattern `e` is allowed to contain `$(...)` expressions to immediately substitute
equality proofs into the congruence, just like for congruence quotations.
# "congrm?" [tacticCongrm?](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticCongrm?)
Display a widget panel allowing to generate a `congrm` call with holes specified by selecting
subexpressions in the goal.
# "constructor" [Parser.Tactic.constructor](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.constructor)
If the main goal's target type is an inductive type, `constructor` solves it with
the first matching constructor, or else fails.
# "constructorm" [Mathlib.Tactic.constructorM](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.constructorM)
* `constructorm p_1, ..., p_n` applies the `constructor` tactic to the main goal
if `type` matches one of the given patterns.
* `constructorm* p` is a more efficient and compact version of `· repeat constructorm p`.
It is more efficient because the pattern is compiled once.
Example: The following tactic proves any theorem like `True ∧ (True ∨ True)` consisting of
and/or/true:
```
constructorm* _ ∨ _, _ ∧ _, True
```
# "continuity" [tacticContinuity](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticContinuity)
The tactic `continuity` solves goals of the form `Continuous f` by applying lemmas tagged with the
`continuity` user attribute.
# "continuity?" [tacticContinuity?](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticContinuity?)
The tactic `continuity` solves goals of the form `Continuous f` by applying lemmas tagged with the
`continuity` user attribute.
# "contradiction" [Parser.Tactic.contradiction](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.contradiction)
`contradiction` closes the main goal if its hypotheses are "trivially contradictory".
- Inductive type/family with no applicable constructors
```lean
example (h : False) : p := by contradiction
```
- Injectivity of constructors
```lean
example (h : none = some true) : p := by contradiction --
```
- Decidable false proposition
```lean
example (h : 2 + 2 = 3) : p := by contradiction
```
- Contradictory hypotheses
```lean
example (h : p) (h' : ¬ p) : q := by contradiction
```
- Other simple contradictions such as
```lean
example (x : Nat) (h : x ≠ x) : p := by contradiction
```
# "contrapose" [Mathlib.Tactic.Contrapose.contrapose](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Contrapose.contrapose)
Transforms the goal into its contrapositive.
* `contrapose` turns a goal `P → Q` into `¬ Q → ¬ P`
* `contrapose h` first reverts the local assumption `h`, and then uses `contrapose` and `intro h`
* `contrapose h with new_h` uses the name `new_h` for the introduced hypothesis
# "contrapose!" [Mathlib.Tactic.Contrapose.contrapose!](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Contrapose.contrapose!)
Transforms the goal into its contrapositive and uses pushes negations inside `P` and `Q`.
Usage matches `contrapose`
# "conv" [Parser.Tactic.Conv.conv](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.Conv.conv)
`conv => ...` allows the user to perform targeted rewriting on a goal or hypothesis,
by focusing on particular subexpressions.
See for more details.
Basic forms:
* `conv => cs` will rewrite the goal with conv tactics `cs`.
* `conv at h => cs` will rewrite hypothesis `h`.
* `conv in pat => cs` will rewrite the first subexpression matching `pat` (see `pattern`).
# "conv'" [Parser.Tactic.Conv.convTactic](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.Conv.convTactic)
Executes the given conv block without converting regular goal into a `conv` goal.
# "conv?" [tacticConv?](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticConv?)
Display a widget panel allowing to generate a `conv` call zooming to the subexpression selected
in the goal.
# "conv_lhs" [Mathlib.Tactic.Conv.convLHS](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Conv.convLHS)
# "conv_rhs" [Mathlib.Tactic.Conv.convRHS](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Conv.convRHS)
# "convert" [Mathlib.Tactic.convert](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.convert)
The `exact e` and `refine e` tactics require a term `e` whose type is
definitionally equal to the goal. `convert e` is similar to `refine e`,
but the type of `e` is not required to exactly match the
goal. Instead, new goals are created for differences between the type
of `e` and the goal using the same strategies as the `congr!` tactic.
For example, in the proof state
```lean
n : ℕ,
e : Prime (2 * n + 1)
⊢ Prime (n + n + 1)
```
the tactic `convert e using 2` will change the goal to
```lean
⊢ n + n = 2 * n
```
In this example, the new goal can be solved using `ring`.
The `using 2` indicates it should iterate the congruence algorithm up to two times,
where `convert e` would use an unrestricted number of iterations and lead to two
impossible goals: `⊢ HAdd.hAdd = HMul.hMul` and `⊢ n = 2`.
A variant configuration is `convert (config := .unfoldSameFun) e`, which only equates function
applications for the same function (while doing so at the higher `default` transparency).
This gives the same goal of `⊢ n + n = 2 * n` without needing `using 2`.
The `convert` tactic applies congruence lemmas eagerly before reducing,
therefore it can fail in cases where `exact` succeeds:
```lean
def p (n : ℕ) := True
example (h : p 0) : p 1 := by exact h -- succeeds
example (h : p 0) : p 1 := by convert h -- fails, with leftover goal `1 = 0`
```
Limiting the depth of recursion can help with this. For example, `convert h using 1` will work
in this case.
The syntax `convert ← e` will reverse the direction of the new goals
(producing `⊢ 2 * n = n + n` in this example).
Internally, `convert e` works by creating a new goal asserting that
the goal equals the type of `e`, then simplifying it using
`congr!`. The syntax `convert e using n` can be used to control the
depth of matching (like `congr! n`). In the example, `convert e using 1`
would produce a new goal `⊢ n + n + 1 = 2 * n + 1`.
Refer to the `congr!` tactic to understand the congruence operations. One of its many
features is that if `x y : t` and an instance `Subsingleton t` is in scope,
then any goals of the form `x = y` are solved automatically.
Like `congr!`, `convert` takes an optional `with` clause of `rintro` patterns,
for example `convert e using n with x y z`.
The `convert` tactic also takes a configuration option, for example
```lean
convert (config := {transparency := .default}) h
```
These are passed to `congr!`. See `Congr!.Config` for options.
# "convert_to" [Mathlib.Tactic.convertTo](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.convertTo)
The `convert_to` tactic is for changing the type of the target or a local hypothesis,
but unlike the `change` tactic it will generate equality proof obligations using `congr!`
to resolve discrepancies.
* `convert_to ty` changes the target to `ty`
* `convert_to ty using n` uses `congr! n` instead of `congr! 1`
* `convert_to ty at h` changes the type of the local hypothesis `h` to `ty`.
Any remaining `congr!` goals come first.
Operating on the target, the tactic `convert_to ty using n`
is the same as `convert (?_ : ty) using n`.
The difference is that `convert_to` takes a type but `convert` takes a proof term.
Except for it also being able to operate on local hypotheses,
the syntax for `convert_to` is the same as for `convert`, and it has variations such as
`convert_to ← g` and `convert_to (config := {transparency := .default}) g`.
Note that `convert_to ty at h` may leave a copy of `h` if a later local hypotheses or the target
depends on it, just like in `rw` or `simp`.
# "count_heartbeats" [Mathlib.CountHeartbeats.tacticCount_heartbeats_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.CountHeartbeats.tacticCount_heartbeats_)
Count the heartbeats used by a tactic, e.g.: `count_heartbeats simp`.
# "count_heartbeats!" [Mathlib.CountHeartbeats.tacticCount_heartbeats!_In__](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.CountHeartbeats.tacticCount_heartbeats!_In__)
`count_heartbeats! in tac` runs a tactic 10 times, counting the heartbeats used, and logs the range
and standard deviation. The tactic `count_heartbeats! n in tac` runs it `n` times instead.
# "dbg_trace" [Parser.Tactic.dbgTrace](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.dbgTrace)
`dbg_trace "foo"` prints `foo` when elaborated.
Useful for debugging tactic control flow:
```
example : False ∨ True := by
first
| apply Or.inl; trivial; dbg_trace "left"
| apply Or.inr; trivial; dbg_trace "right"
```
# "decide" [Parser.Tactic.decide](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.decide)
`decide` attempts to prove the main goal (with target type `p`) by synthesizing an instance of `Decidable p`
and then reducing that instance to evaluate the truth value of `p`.
If it reduces to `isTrue h`, then `h` is a proof of `p` that closes the goal.
The target is not allowed to contain local variables or metavariables.
If there are local variables, you can first try using the `revert` tactic with these local variables to move them into the target,
or you can use the `+revert` option, described below.
Options:
- `decide +revert` begins by reverting local variables that the target depends on,
after cleaning up the local context of irrelevant variables.
A variable is *relevant* if it appears in the target, if it appears in a relevant variable,
or if it is a proposition that refers to a relevant variable.
- `decide +kernel` uses kernel for reduction instead of the elaborator.
It has two key properties: (1) since it uses the kernel, it ignores transparency and can unfold everything,
and (2) it reduces the `Decidable` instance only once instead of twice.
- `decide +native` uses the native code compiler (`#eval`) to evaluate the `Decidable` instance,
admitting the result via the `Lean.ofReduceBool` axiom.
This can be significantly more efficient than using reduction, but it is at the cost of increasing the size
of the trusted code base.
Namely, it depends on the correctness of the Lean compiler and all definitions with an `@[implemented_by]` attribute.
Like with `+kernel`, the `Decidable` instance is evaluated only once.
Limitation: In the default mode or `+kernel` mode, since `decide` uses reduction to evaluate the term,
`Decidable` instances defined by well-founded recursion might not work because evaluating them requires reducing proofs.
Reduction can also get stuck on `Decidable` instances with `Eq.rec` terms.
These can appear in instances defined using tactics (such as `rw` and `simp`).
To avoid this, create such instances using definitions such as `decidable_of_iff` instead.
## Examples
Proving inequalities:
```lean
example : 2 + 2 ≠ 5 := by decide
```
Trying to prove a false proposition:
```lean
example : 1 ≠ 1 := by decide
/-
tactic 'decide' proved that the proposition
1 ≠ 1
is false
-/
```
Trying to prove a proposition whose `Decidable` instance fails to reduce
```lean
opaque unknownProp : Prop
open scoped Classical in
example : unknownProp := by decide
/-
tactic 'decide' failed for proposition
unknownProp
since its 'Decidable' instance reduced to
Classical.choice ⋯
rather than to the 'isTrue' constructor.
-/
```
## Properties and relations
For equality goals for types with decidable equality, usually `rfl` can be used in place of `decide`.
```lean
example : 1 + 1 = 2 := by decide
example : 1 + 1 = 2 := by rfl
```
# "decreasing_tactic" [tacticDecreasing_tactic](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticDecreasing_tactic)
`decreasing_tactic` is called by default on well-founded recursions in order
to synthesize a proof that recursive calls decrease along the selected
well founded relation. It can be locally overridden by using `decreasing_by tac`
on the recursive definition, and it can also be globally extended by adding
more definitions for `decreasing_tactic` (or `decreasing_trivial`,
which this tactic calls).
# "decreasing_trivial" [tacticDecreasing_trivial](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticDecreasing_trivial)
Extensible helper tactic for `decreasing_tactic`. This handles the "base case"
reasoning after applying lexicographic order lemmas.
It can be extended by adding more macro definitions, e.g.
```
macro_rules | `(tactic| decreasing_trivial) => `(tactic| linarith)
```
# "decreasing_trivial_pre_omega" [tacticDecreasing_trivial_pre_omega](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticDecreasing_trivial_pre_omega)
Variant of `decreasing_trivial` that does not use `omega`, intended to be used in core modules
before `omega` is available.
# "decreasing_with" [tacticDecreasing_with_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticDecreasing_with_)
Constructs a proof of decreasing along a well founded relation, by simplifying, then applying
lexicographic order lemmas and finally using `ts` to solve the base case. If it fails,
it prints a message to help the user diagnose an ill-founded recursive definition.
# "delta" [Parser.Tactic.delta](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.delta)
`delta id1 id2 ...` delta-expands the definitions `id1`, `id2`, ....
This is a low-level tactic, it will expose how recursive definitions have been
compiled by Lean.
# "discrete_cases" [CategoryTheory.Discrete.tacticDiscrete_cases](https://leanprover-community.github.io/mathlib4_docs/search.html?q=CategoryTheory.Discrete.tacticDiscrete_cases)
A simple tactic to run `cases` on any `Discrete α` hypotheses.
# "done" [Parser.Tactic.done](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.done)
`done` succeeds iff there are no remaining goals.
# "dsimp" [Parser.Tactic.dsimp](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.dsimp)
The `dsimp` tactic is the definitional simplifier. It is similar to `simp` but only
applies theorems that hold by reflexivity. Thus, the result is guaranteed to be
definitionally equal to the input.
# "dsimp!" [Parser.Tactic.dsimpAutoUnfold](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.dsimpAutoUnfold)
`dsimp!` is shorthand for `dsimp` with `autoUnfold := true`.
This will rewrite with all equation lemmas, which can be used to
partially evaluate many definitions.
# "dsimp?" [Parser.Tactic.dsimpTrace](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.dsimpTrace)
`simp?` takes the same arguments as `simp`, but reports an equivalent call to `simp only`
that would be sufficient to close the goal. This is useful for reducing the size of the simp
set in a local invocation to speed up processing.
```
example (x : Nat) : (if True then x + 2 else 3) = x + 2 := by
simp? -- prints "Try this: simp only [ite_true]"
```
This command can also be used in `simp_all` and `dsimp`.
# "dsimp?!" [Parser.Tactic.tacticDsimp?!_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacticDsimp?!_)
`simp?` takes the same arguments as `simp`, but reports an equivalent call to `simp only`
that would be sufficient to close the goal. This is useful for reducing the size of the simp
set in a local invocation to speed up processing.
```
example (x : Nat) : (if True then x + 2 else 3) = x + 2 := by
simp? -- prints "Try this: simp only [ite_true]"
```
This command can also be used in `simp_all` and `dsimp`.
# "eapply" [Batteries.Tactic.tacticEapply_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Batteries.Tactic.tacticEapply_)
`eapply e` is like `apply e` but it does not add subgoals for variables that appear
in the types of other goals. Note that this can lead to a failure where there are
no goals remaining but there are still metavariables in the term:
```
example (h : ∀ x : Nat, x = x → True) : True := by
eapply h
rfl
-- no goals
-- (kernel) declaration has metavariables '_example'
```
# "econstructor" [tacticEconstructor](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticEconstructor)
`econstructor` is like `constructor`
(it calls `apply` using the first matching constructor of an inductive datatype)
except only non-dependent premises are added as new goals.
# "elementwise" [Elementwise.tacticElementwise___](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Elementwise.tacticElementwise___)
# "elementwise!" [Elementwise.tacticElementwise!___](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Elementwise.tacticElementwise!___)
# "else" [Parser.Tactic.tacDepIfThenElse](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacDepIfThenElse)
In tactic mode, `if h : t then tac1 else tac2` can be used as alternative syntax for:
```
by_cases h : t
· tac1
· tac2
```
It performs case distinction on `h : t` or `h : ¬t` and `tac1` and `tac2` are the subproofs.
You can use `?_` or `_` for either subproof to delay the goal to after the tactic, but
if a tactic sequence is provided for `tac1` or `tac2` then it will require the goal to be closed
by the end of the block.
# "else" [Parser.Tactic.tacIfThenElse](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacIfThenElse)
In tactic mode, `if t then tac1 else tac2` is alternative syntax for:
```
by_cases t
· tac1
· tac2
```
It performs case distinction on `h† : t` or `h† : ¬t`, where `h†` is an anonymous
hypothesis, and `tac1` and `tac2` are the subproofs. (It doesn't actually use
nondependent `if`, since this wouldn't add anything to the context and hence would be
useless for proving theorems. To actually insert an `ite` application use
`refine if t then ?_ else ?_`.)
# "eq_refl" [Parser.Tactic.eqRefl](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.eqRefl)
`eq_refl` is equivalent to `exact rfl`, but has a few optimizations.
# "erw" [Parser.Tactic.tacticErw___](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacticErw___)
`erw [rules]` is a shorthand for `rw (transparency := .default) [rules]`.
This does rewriting up to unfolding of regular definitions (by comparison to regular `rw`
which only unfolds `@[reducible]` definitions).
# "eta_expand" [Mathlib.Tactic.etaExpandStx](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.etaExpandStx)
`eta_expand at loc` eta expands all sub-expressions at the given location.
It also beta reduces any applications of eta expanded terms, so it puts it
into an eta-expanded "normal form."
This also exists as a `conv`-mode tactic.
For example, if `f` takes two arguments, then `f` becomes `fun x y => f x y`
and `f x` becomes `fun y => f x y`.
This can be useful to turn, for example, a raw `HAdd.hAdd` into `fun x y => x + y`.
# "eta_reduce" [Mathlib.Tactic.etaReduceStx](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.etaReduceStx)
`eta_reduce at loc` eta reduces all sub-expressions at the given location.
This also exists as a `conv`-mode tactic.
For example, `fun x y => f x y` becomes `f` after eta reduction.
# "eta_struct" [Mathlib.Tactic.etaStructStx](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.etaStructStx)
`eta_struct at loc` transforms structure constructor applications such as `S.mk x.1 ... x.n`
(pretty printed as, for example, `{a := x.a, b := x.b, ...}`) into `x`.
This also exists as a `conv`-mode tactic.
The transformation is known as eta reduction for structures, and it yields definitionally
equal expressions.
For example, given `x : α × β`, then `(x.1, x.2)` becomes `x` after this transformation.
# "exact" [Parser.Tactic.exact](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.exact)
`exact e` closes the main goal if its target type matches that of `e`.
# "exact?" [Parser.Tactic.exact?](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.exact?)
Searches environment for definitions or theorems that can solve the goal using `exact`
with conditions resolved by `solve_by_elim`.
The optional `using` clause provides identifiers in the local context that must be
used by `exact?` when closing the goal. This is most useful if there are multiple
ways to resolve the goal, and one wants to guide which lemma is used.
# "exact_mod_cast" [Parser.Tactic.tacticExact_mod_cast_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacticExact_mod_cast_)
Normalize casts in the goal and the given expression, then close the goal with `exact`.
# "exacts" [Batteries.Tactic.exacts](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Batteries.Tactic.exacts)
Like `exact`, but takes a list of terms and checks that all goals are discharged after the tactic.
# "exfalso" [Parser.Tactic.tacticExfalso](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.tacticExfalso)
`exfalso` converts a goal `⊢ tgt` into `⊢ False` by applying `False.elim`.
# "exists" [Parser.Tactic.«tacticExists_,,»](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.«tacticExists_,,»)
`exists e₁, e₂, ...` is shorthand for `refine ⟨e₁, e₂, ...⟩; try trivial`.
It is useful for existential goals.
# "existsi" [Mathlib.Tactic.«tacticExistsi_,,»](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.«tacticExistsi_,,»)
`existsi e₁, e₂, ⋯` applies the tactic `refine ⟨e₁, e₂, ⋯, ?_⟩`. It's purpose is to instantiate
existential quantifiers.
Examples:
```lean
example : ∃ x : Nat, x = x := by
existsi 42
rfl
example : ∃ x : Nat, ∃ y : Nat, x = y := by
existsi 42, 42
rfl
```
# "ext" [Ext.ext](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Ext.ext)
Applies extensionality lemmas that are registered with the `@[ext]` attribute.
* `ext pat*` applies extensionality theorems as much as possible,
using the patterns `pat*` to introduce the variables in extensionality theorems using `rintro`.
For example, the patterns are used to name the variables introduced by lemmas such as `funext`.
* Without patterns,`ext` applies extensionality lemmas as much
as possible but introduces anonymous hypotheses whenever needed.
* `ext pat* : n` applies ext theorems only up to depth `n`.
The `ext1 pat*` tactic is like `ext pat*` except that it only applies a single extensionality theorem.
Unused patterns will generate warning.
Patterns that don't match the variables will typically result in the introduction of anonymous hypotheses.
# "ext1" [Ext.tacticExt1___](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Ext.tacticExt1___)
`ext1 pat*` is like `ext pat*` except that it only applies a single extensionality theorem rather
than recursively applying as many extensionality theorems as possible.
The `pat*` patterns are processed using the `rintro` tactic.
If no patterns are supplied, then variables are introduced anonymously using the `intros` tactic.
# "extract_goal" [Mathlib.Tactic.ExtractGoal.extractGoal](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.ExtractGoal.extractGoal)
- `extract_goal` formats the current goal as a stand-alone theorem or definition after
cleaning up the local context of irrelevant variables.
A variable is *relevant* if (1) it occurs in the target type, (2) there is a relevant variable
that depends on it, or (3) the type of the variable is a proposition that depends on a
relevant variable.
If the target is `False`, then for convenience `extract_goal` includes all variables.
- `extract_goal *` formats the current goal without cleaning up the local context.
- `extract_goal a b c ...` formats the current goal after removing everything that the given
variables `a`, `b`, `c`, ... do not depend on.
- `extract_goal ... using name` uses the name `name` for the theorem or definition rather than
the autogenerated name.
The tactic tries to produce an output that can be copy-pasted and just work,
but its success depends on whether the expressions are amenable
to being unambiguously pretty printed.
The tactic responds to pretty printing options.
For example, `set_option pp.all true in extract_goal` gives the `pp.all` form.
# "extract_lets" [Mathlib.extractLets](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.extractLets)
The `extract_lets at h` tactic takes a local hypothesis of the form `h : let x := v; b`
and introduces a new local definition `x := v` while changing `h` to be `h : b`. It can be thought
of as being a `cases` tactic for `let` expressions. It can also be thought of as being like
`intros at h` for `let` expressions.
For example, if `h : let x := 1; x = x`, then `extract_lets x at h` introduces `x : Nat := 1` and
changes `h` to `h : x = x`.
Just like `intros`, the `extract_lets` tactic either takes a list of names, in which case
that specifies the number of `let` bindings that must be extracted, or it takes no names, in which
case all the `let` bindings are extracted.
The tactic `extract_lets` (without `at`) or `extract_lets at h ⊢` acts as a weaker
form of `intros` on the goal that only introduces obvious `let`s.
# "fail" [Parser.Tactic.fail](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.fail)
`fail msg` is a tactic that always fails, and produces an error using the given message.
# "fail_if_no_progress" [Mathlib.Tactic.failIfNoProgress](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.failIfNoProgress)
`fail_if_no_progress tacs` evaluates `tacs`, and fails if no progress is made on the main goal
or the local context at reducible transparency.
# "fail_if_success" [Parser.Tactic.failIfSuccess](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.failIfSuccess)
`fail_if_success t` fails if the tactic `t` succeeds.
# "false_or_by_contra" [Parser.Tactic.falseOrByContra](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.falseOrByContra)
Changes the goal to `False`, retaining as much information as possible:
* If the goal is `False`, do nothing.
* If the goal is an implication or a function type, introduce the argument and restart.
(In particular, if the goal is `x ≠ y`, introduce `x = y`.)
* Otherwise, for a propositional goal `P`, replace it with `¬ ¬ P`
(attempting to find a `Decidable` instance, but otherwise falling back to working classically)
and introduce `¬ P`.
* For a non-propositional goal use `False.elim`.
# "fapply" [Batteries.Tactic.tacticFapply_](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Batteries.Tactic.tacticFapply_)
`fapply e` is like `apply e` but it adds goals in the order they appear,
rather than putting the dependent goals first.
# "fconstructor" [tacticFconstructor](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticFconstructor)
`fconstructor` is like `constructor`
(it calls `apply` using the first matching constructor of an inductive datatype)
except that it does not reorder goals.
# "field_simp" [Mathlib.Tactic.FieldSimp.fieldSimp](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.FieldSimp.fieldSimp)
The goal of `field_simp` is to reduce an expression in a field to an expression of the form `n / d`
where neither `n` nor `d` contains any division symbol, just using the simplifier (with a carefully
crafted simpset named `field_simps`) to reduce the number of division symbols whenever possible by
iterating the following steps:
- write an inverse as a division
- in any product, move the division to the right
- if there are several divisions in a product, group them together at the end and write them as a
single division
- reduce a sum to a common denominator
If the goal is an equality, this simpset will also clear the denominators, so that the proof
can normally be concluded by an application of `ring`.
`field_simp [hx, hy]` is a short form for
`simp (disch := field_simp_discharge) [-one_div, -one_divp, -mul_eq_zero, hx, hy, field_simps]`
Note that this naive algorithm will not try to detect common factors in denominators to reduce the
complexity of the resulting expression. Instead, it relies on the ability of `ring` to handle
complicated expressions in the next step.
As always with the simplifier, reduction steps will only be applied if the preconditions of the
lemmas can be checked. This means that proofs that denominators are nonzero should be included. The
fact that a product is nonzero when all factors are, and that a power of a nonzero number is
nonzero, are included in the simpset, but more complicated assertions (especially dealing with sums)
should be given explicitly. If your expression is not completely reduced by the simplifier
invocation, check the denominators of the resulting expression and provide proofs that they are
nonzero to enable further progress.
To check that denominators are nonzero, `field_simp` will look for facts in the context, and
will try to apply `norm_num` to close numerical goals.
The invocation of `field_simp` removes the lemma `one_div` from the simpset, as this lemma
works against the algorithm explained above. It also removes
`mul_eq_zero : x * y = 0 ↔ x = 0 ∨ y = 0`, as `norm_num` can not work on disjunctions to
close goals of the form `24 ≠ 0`, and replaces it with `mul_ne_zero : x ≠ 0 → y ≠ 0 → x * y ≠ 0`
creating two goals instead of a disjunction.
For example,
```lean
example (a b c d x y : ℂ) (hx : x ≠ 0) (hy : y ≠ 0) :
a + b / x + c / x^2 + d / x^3 = a + x⁻¹ * (y * b / y + (d / x + c) / x) := by
field_simp
ring
```
Moreover, the `field_simp` tactic can also take care of inverses of units in
a general (commutative) monoid/ring and partial division `/ₚ`, see `Algebra.Group.Units`
for the definition. Analogue to the case above, the lemma `one_divp` is removed from the simpset
as this works against the algorithm. If you have objects with an `IsUnit x` instance like
`(x : R) (hx : IsUnit x)`, you should lift them with
`lift x to Rˣ using id hx; rw [IsUnit.unit_of_val_units] clear hx`
before using `field_simp`.
See also the `cancel_denoms` tactic, which tries to do a similar simplification for expressions
that have numerals in denominators.
The tactics are not related: `cancel_denoms` will only handle numeric denominators, and will try to
entirely remove (numeric) division from the expression by multiplying by a factor.
# "field_simp_discharge" [Mathlib.Tactic.FieldSimp.tacticField_simp_discharge](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.FieldSimp.tacticField_simp_discharge)
Discharge strategy for the `field_simp` tactic.
# "filter_upwards" [Mathlib.Tactic.filterUpwards](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.filterUpwards)
`filter_upwards [h₁, ⋯, hₙ]` replaces a goal of the form `s ∈ f` and terms
`h₁ : t₁ ∈ f, ⋯, hₙ : tₙ ∈ f` with `∀ x, x ∈ t₁ → ⋯ → x ∈ tₙ → x ∈ s`.
The list is an optional parameter, `[]` being its default value.
`filter_upwards [h₁, ⋯, hₙ] with a₁ a₂ ⋯ aₖ` is a short form for
`{ filter_upwards [h₁, ⋯, hₙ], intros a₁ a₂ ⋯ aₖ }`.
`filter_upwards [h₁, ⋯, hₙ] using e` is a short form for
`{ filter_upwards [h1, ⋯, hn], exact e }`.
Combining both shortcuts is done by writing `filter_upwards [h₁, ⋯, hₙ] with a₁ a₂ ⋯ aₖ using e`.
Note that in this case, the `aᵢ` terms can be used in `e`.
# "fin_cases" [finCases](https://leanprover-community.github.io/mathlib4_docs/search.html?q=finCases)
`fin_cases h` performs case analysis on a hypothesis of the form
`h : A`, where `[Fintype A]` is available, or
`h : a ∈ A`, where `A : Finset X`, `A : Multiset X` or `A : List X`.
As an example, in
```
example (f : ℕ → Prop) (p : Fin 3) (h0 : f 0) (h1 : f 1) (h2 : f 2) : f p.val := by
fin_cases p; simp
all_goals assumption
```
after `fin_cases p; simp`, there are three goals, `f 0`, `f 1`, and `f 2`.
# "fin_omega" [Fin.tacticFin_omega](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Fin.tacticFin_omega)
Preprocessor for `omega` to handle inequalities in `Fin`.
Note that this involves a lot of case splitting, so may be slow.
# "find" [Mathlib.Tactic.Find.tacticFind](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.Find.tacticFind)
# "finiteness" [finiteness](https://leanprover-community.github.io/mathlib4_docs/search.html?q=finiteness)
Tactic to solve goals of the form `*** < ∞` and (equivalently) `*** ≠ ∞` in the extended
nonnegative reals (`ℝ≥0∞`).
# "finiteness?" [finiteness?](https://leanprover-community.github.io/mathlib4_docs/search.html?q=finiteness?)
Tactic to solve goals of the form `*** < ∞` and (equivalently) `*** ≠ ∞` in the extended
nonnegative reals (`ℝ≥0∞`).
# "finiteness_nonterminal" [finiteness_nonterminal](https://leanprover-community.github.io/mathlib4_docs/search.html?q=finiteness_nonterminal)
Tactic to solve goals of the form `*** < ∞` and (equivalently) `*** ≠ ∞` in the extended
nonnegative reals (`ℝ≥0∞`).
# "first" [Parser.Tactic.first](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.first)
`first | tac | ...` runs each `tac` until one succeeds, or else fails.
# "focus" [Parser.Tactic.focus](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Parser.Tactic.focus)
`focus tac` focuses on the main goal, suppressing all other goals, and runs `tac` on it.
Usually `· tac`, which enforces that the goal is closed by `tac`, should be preferred.
# "forward" [Aesop.Frontend.tacticForward___](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Aesop.Frontend.tacticForward___)
# "forward?" [Aesop.Frontend.tacticForward?___](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Aesop.Frontend.tacticForward?___)
# "frac_tac" [RatFunc.tacticFrac_tac](https://leanprover-community.github.io/mathlib4_docs/search.html?q=RatFunc.tacticFrac_tac)
Solve equations for `RatFunc K` by working in `FractionRing K[X]`.
# "fun_prop" [Mathlib.Meta.FunProp.funPropTacStx](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Meta.FunProp.funPropTacStx)
Tactic to prove function properties
# "funext" [tacticFunext___](https://leanprover-community.github.io/mathlib4_docs/search.html?q=tacticFunext___)
Apply function extensionality and introduce new hypotheses.
The tactic `funext` will keep applying the `funext` lemma until the goal target is not reducible to
```
|- ((fun x => ...) = (fun x => ...))
```
The variant `funext h₁ ... hₙ` applies `funext` `n` times, and uses the given identifiers to name the new hypotheses.
Patterns can be used like in the `intro` tactic. Example, given a goal
```
|- ((fun x : Nat × Bool => ...) = (fun x => ...))
```
`funext (a, b)` applies `funext` once and performs pattern matching on the newly introduced pair.
# "gcongr" [Mathlib.Tactic.GCongr.tacticGcongr__With__](https://leanprover-community.github.io/mathlib4_docs/search.html?q=Mathlib.Tactic.GCongr.tacticGcongr__With__)
The `gcongr` tactic applies "generalized congruence" rules, reducing a relational goal
between a LHS and RHS matching the same pattern to relational subgoals between the differing
inputs to the pattern. For example,
```
example {a b x c d : ℝ} (h1 : a + 1 ≤ b + 1) (h2 : c + 2 ≤ d + 2) :
x ^ 2 * a + c ≤ x ^ 2 * b + d := by
gcongr
· linarith
· linarith
```
This example has the goal of proving the relation `≤` between a LHS and RHS both of the pattern
```
x ^ 2