The tactic language is a special-purpose programming language for constructing proofs, indicated using the keyword by.
#adaptation_note
#adaptation_note /-- comment -/ adds an adaptation note to the current file.
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.
This syntax works as a command, or inline in tactic or term mode.
- Tags:
- Defined in module:
- Mathlib.Tactic.AdaptationNote
#check
#check t 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.
- Tags:
- Defined in module:
- Mathlib.Tactic.Check
#count_heartbeats
#count_heartbeats tac counts the heartbeats used by the tactic sequence tac
and prints an info line with the number of heartbeats.
#count_heartbeats! n in tac, wherenis an optional natural number literal, runstacntimes on the same goal while counting the heartbeats, and prints an info line with range and standard deviation.ncan be left out, and defaults to 10.
Example:
example : 1 + 1 = 2 := by
-- The next line will print an info message of this format; the exact number may vary.
-- info: 4646
#count_heartbeats simp
example : 1 + 1 = 2 := by
-- The next line will print an info message of this format; the exact numbers may vary.
-- info: Min: 4 Max: 4 StdDev: 2%
#count_heartbeats! 37 in simp
- Tags:
- Defined in module:
- Mathlib.Util.CountHeartbeats
#find
#find t finds definitions and theorems whose result type matches the term t, and prints them as
info lines. Use holes in t to indicate arbitrary subexpressions, for example #find _ ∧ _ will
match any conjunction. #find is also available as a command.
#find will not affect the goal by itself and should be removed from the finished proof.
There is also the find tactic which looks for lemmas which are applyable against the current
goal.
Examples:
#find _ + _ = _ + _
#find ?n + _ = _ + ?n
#find (_ : Nat) + _ = _ + _
#find Nat → Nat
- Tags:
- Defined in module:
- Mathlib.Tactic.Find
#leansearch
Search LeanSearch 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.
#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
You can modify the LeanSearch URL by setting the LEANSEARCHCLIENT_LEANSEARCH_API_URL environment variable.
- Tags:
- Defined in module:
- LeanSearchClient.Syntax
#loogle
Search Loogle 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.
#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, _ * _, _ ^ _, |- _ < _ → _ would 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.
You can modify the Loogle server URL by setting the LEANSEARCHCLIENT_LOOGLE_API_URL environment variable.
- Tags:
- Defined in module:
- LeanSearchClient.LoogleSyntax
#search
Search from within Lean, depending on the option leansearchclient.backend (currently only leansearch).
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.
#search "If a natural number n is less than m, then the successor of n is less than the successor of m."
example := #search "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
#search "If a natural number n is less than m, then the successor of n is less than the successor of m."
sorry
In tactic mode, if the query string is not supplied, then [LeanStateSearch](https://premise-search.com) is queried based on the goal state.
- Tags:
- Defined in module:
- LeanSearchClient.Syntax
#statesearch
Search LeanStateSearch from within Lean.
Your current main goal is sent as query. The revision to search can be set
using the statesearch.revision option. The number of results can be set
using the statesearch.queries option.
Hint: If you want to modify the query, you need to use the web interface.
set_option statesearch.queries 1
set_option statesearch.revision "v4.16.0"
example : 0 ≤ 1 := by
#statesearch
sorry
You can modify the LeanStateSearch URL by setting the LEANSEARCHCLIENT_LEANSTATESEARCH_API_URL environment variable.
- Tags:
- Defined in module:
- LeanSearchClient.Syntax
(
(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 ;.
- Tags:
- Defined in module:
- Init.Tactics
.
· tac focuses on the main goal and tries to solve it using tac, or else fails.
- Tags:
- Defined in module:
- Init.NotationExtra
<;>
tac <;> tac' runs tac on the main goal and tac' on each produced goal,
concatenating all goals produced by tac'.
- Tags:
- Defined in module:
- Init.Tactics
<;>
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.
- Tags:
- Defined in module:
- Batteries.Tactic.SeqFocus
Lean.Parser.Tactic.nestedTactic
This tactic has no documentation.
- Tags:
- Defined in module:
- Lean.Parser.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.
- Tags:
- Defined in module:
- Batteries.Tactic.Init
abel
abel solves equations in the language of additive, commutative monoids and groups.
abel and its variants work as both tactics and conv tactics.
abel1fails if the target is not an equality that is provable by the axioms of commutative monoids/groups.abel_nfrewrites all group expressions into a normal form.abel_nf at hrewrites in a hypothesis.abel_nf (config := cfg)allows for additional configuration:red: the reducibility setting (overridden by!).zetaDelta: if true, localletvariables can be unfolded (overridden by!).recursive: if true,abel_nfalso recurses into atoms.
abel!,abel1!,abel_nf!use a more aggressive reducibility setting to identify atoms.
Examples:
example [AddCommMonoid α] (a b : α) : a + (b + a) = a + a + b := by abel
example [AddCommGroup α] (a : α) : (3 : ℤ) • a = a + (2 : ℤ) • a := by abel
- Tags:
- Defined in module:
- Mathlib.Tactic.Abel
absurd
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.
- Tags:
- Defined in module:
- Batteries.Tactic.Init
ac_change
ac_change t on a goal ⊢ t' changes the goal to ⊢ t and adds new goals for proving the equality
t' = t using congruence, then tries proving these goals by associativity and commutativity. The
goals are created like congr! would.
In other words, ac_change t is like convert_to t followed by ac_refl.
Like refine e, any holes (?_ or ?x) in t that are not solved by unification are converted
into new goals, using the hole's name, if any, as the goal case name.
Like congr!, convert_to introduces variables while applying congruence rules. These can be
pattern-matched, like rintro would, using the with keyword.
ac_change t using n, wherenis a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is⊢ Prime ((a * b + 1) + c), thenac_change Prime ((1 + a * b) + c) using 2solves the side goals, andac_change Prime ((1 + a * b) + c) using 3(or more) results in two (impossible) goals⊢ 1 = a * band⊢ a * b = 1. The default value fornis 1.
Example:
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
- Tags:
- Defined in module:
- Mathlib.Tactic.Convert
ac_nf
ac_nf normalizes equalities up to application of an associative and commutative operator.
ac_nfnormalizes all hypotheses and the goal target of the goal.ac_nf at lnormalizes at location(s)l, wherelis 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 : Std.Associative (α := Nat) (.+.) := ⟨Nat.add_assoc⟩
instance : Std.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))
- Tags:
- Defined in module:
- Init.Tactics
ac_nf0
Implementation of ac_nf (the full ac_nf calls trivial afterwards).
- Tags:
- Defined in module:
- Init.Tactics
ac_rfl
ac_rfl proves equalities up to application of an associative and commutative operator.
instance : Std.Associative (α := Nat) (.+.) := ⟨Nat.add_assoc⟩
instance : Std.Commutative (α := Nat) (.+.) := ⟨Nat.add_comm⟩
example (a b c d : Nat) : a + b + c + d = d + (b + c) + a := by ac_rfl
- Tags:
- Defined in module:
- Init.Tactics
aesop
aesop <clause>* tries to solve the current goal by applying a set of rules
registered with the @[aesop] attribute. See its
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 <phase> <priority> <builder> <rule>)adds a rule.<phase>isunsafe,safeornorm.<priority>is a percentage for unsafe rules and an integer for safe and norm rules.<rule>is the name of a declaration or local hypothesis.<builder>is the rule builder used to turn<rule>into an Aesop rule. Example:(add unsafe 50% apply Or.inl).(erase <rule>)disables a globally registered Aesop rule. Example:(erase Aesop.BuiltinRules.assumption).(rule_sets := [<ruleset>,*])enables or disables named sets of rules for this Aesop call. Example:(rule_sets := [-builtin, MyRuleSet]).(config { <opt> := <value> })adjusts Aesop's search options. SeeAesop.Options.(simp_config { <opt> := <value> })adjusts options for Aesop's built-insimprule. The given options are directly passed tosimp. For example,(simp_config := { zeta := false })makes Aesop usesimp (config := { zeta := false }).
- Tags:
- Defined in module:
- Aesop.Frontend.Tactic
aesop?
aesop <clause>* tries to solve the current goal by applying a set of rules
registered with the @[aesop] attribute. See its
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 <phase> <priority> <builder> <rule>)adds a rule.<phase>isunsafe,safeornorm.<priority>is a percentage for unsafe rules and an integer for safe and norm rules.<rule>is the name of a declaration or local hypothesis.<builder>is the rule builder used to turn<rule>into an Aesop rule. Example:(add unsafe 50% apply Or.inl).(erase <rule>)disables a globally registered Aesop rule. Example:(erase Aesop.BuiltinRules.assumption).(rule_sets := [<ruleset>,*])enables or disables named sets of rules for this Aesop call. Example:(rule_sets := [-builtin, MyRuleSet]).(config { <opt> := <value> })adjusts Aesop's search options. SeeAesop.Options.(simp_config { <opt> := <value> })adjusts options for Aesop's built-insimprule. The given options are directly passed tosimp. For example,(simp_config := { zeta := false })makes Aesop usesimp (config := { zeta := false }).
- Tags:
- Defined in module:
- Aesop.Frontend.Tactic
algebraize
Tactic that, given RingHoms, 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 -properties,
so in other words it only adds Algebra and IsScalarTower instances.
- Tags:
- Defined in module:
- Mathlib.Tactic.Algebraize
algebraize_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.
- Tags:
- Defined in module:
- Mathlib.Tactic.Algebraize
all_goals
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.
- Tags:
- Defined in module:
- Init.Tactics
and_intros
and_intros applies And.intro until it does not make progress.
- Tags:
- Defined in module:
- Init.Tactics
any_goals
any_goals tac applies the tactic tac to every goal,
concatenating 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.
- Tags:
- Defined in module:
- Init.Tactics
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.
- Tags:
- Defined in module:
- Init.Tactics
apply
apply t at i uses forward reasoning with t at the hypothesis i.
Explicitly, if t : α₁ → ⋯ → αᵢ → ⋯ → αₙ and i has type αᵢ, then this tactic adds
metavariables/goals for any terms of αⱼ for j = 1, …, i-1,
then replaces the type of i with αᵢ₊₁ → ⋯ → αₙ by applying those metavariables and the
original i.
- Tags:
- Defined in module:
- Mathlib.Tactic.ApplyAt
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.
Use +grind to enable grind as a fallback discharger for subgoals.
Use +try? to enable try? as a fallback discharger for subgoals.
Use -star to disable fallback to star-indexed lemmas.
Use +all to collect all successful lemmas instead of stopping at the first.
- Tags:
- Defined in module:
- Init.Tactics
apply_assumption
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).
- Tags:
- Defined in module:
- Init.Tactics
apply_ext_theorem
Apply a single extensionality theorem to the current goal.
- Tags:
- Defined in module:
- Init.Ext
apply_fun
Apply a function to an equality or inequality in either a local hypothesis or the goal.
- If we have
h : a = b, thenapply_fun f at hwill replace this withh : f a = f b. - If we have
h : a ≤ b, thenapply_fun f at hwill replace this withh : f a ≤ f b, and create a subsidiary goalMonotone f.apply_funwill automatically attempt to discharge this subsidiary goal usingmono, or an explicit solution can be provided withapply_fun f at h using P, whereP : Monotone f. - If we have
h : a < b, thenapply_fun f at hwill replace this withh : f a < f b, and create a subsidiary goalStrictMono fand behaves as in the previous case. - If we have
h : a ≠ b, thenapply_fun f at hwill replace this withh : f a ≠ f b, and create a subsidiary goalInjective fand behaves as in the previous two cases. - If the goal is
a ≠ b,apply_fun fwill replace this withf a ≠ f b. - If the goal is
a = b,apply_fun fwill replace this withf a = f b, and create a subsidiary goalinjective f.apply_funwill automatically attempt to discharge this subsidiary goal using local hypotheses, or iffis actually anEquiv, or an explicit solution can be provided withapply_fun f using P, whereP : Injective f. - If the goal is
a ≤ b(or similarly fora < b), andfis actually anOrderIso,apply_fun fwill replace the goal withf a ≤ f b. Iffis anything else (e.g. just a function, or anEquiv),apply_funwill fail.
Typical usage is:
open Function
example (X Y Z : Type) (f : X → Y) (g : Y → Z) (H : Injective <| g ∘ f) :
Injective f := by
intro 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.
- Tags:
- Defined in module:
- Mathlib.Tactic.ApplyFun
apply_mod_cast
Normalize casts in the goal and the given expression, then apply the expression to the goal.
- Tags:
- Defined in module:
- Init.TacticsExtra
apply_rewrite
apply_rewrite [rules] is a shorthand for grewrite +implicationHyp [rules].
- Tags:
- Defined in module:
- Mathlib.Tactic.GRewrite.Elab
apply_rules
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.
- Tags:
- Defined in module:
- Init.Tactics
apply_rw
apply_rw [rules] is a shorthand for grw +implicationHyp [rules].
- Tags:
- Defined in module:
- Mathlib.Tactic.GRewrite.Elab
array_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.
- Tags:
- Defined in module:
- Init.Data.Array.Mem
array_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.
- Tags:
- Defined in module:
- Init.Data.Array.Mem
as_aux_lemma
as_aux_lemma => tac does the same as tac, except that it wraps the resulting expression
into an auxiliary lemma. In some cases, this significantly reduces the size of expressions
because the proof term is not duplicated.
- Tags:
- Defined in module:
- Init.Tactics
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.
- Tags:
- Defined in module:
- Init.Tactics
assumption'
Try calling assumption on all goals; succeeds if it closes at least one goal.
- Tags:
- Defined in module:
- Mathlib.Tactic.Basic
assumption_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.
- Tags:
- Defined in module:
- Init.Tactics
attempt_all_par
Helper internal tactic for implementing the tactic try? with parallel execution.
- Tags:
- Defined in module:
- Init.Try
aux_group₁
Auxiliary tactic for the group tactic. Calls the simplifier only.
- Tags:
- Defined in module:
- Mathlib.Tactic.Group
aux_group₂
Auxiliary tactic for the group tactic. Calls ring_nf to normalize exponents.
- Tags:
- Defined in module:
- Mathlib.Tactic.Group
bddDefault
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).
- Tags:
- Defined in module:
- Mathlib.Order.Bounds.Basic
beta_reduce
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.
- Tags:
- Defined in module:
- Mathlib.Tactic.DefEqTransformations
borelize
The behaviour of borelize α depends on the existing assumptions on α.
- if
αis a topological space with instances[MeasurableSpace α] [BorelSpace α], thenborelize αreplaces the former instance byborel α; - otherwise,
borelize αadds instancesborel α : MeasurableSpace αand⟨rfl⟩ : BorelSpace α.
Finally, borelize α β γ runs borelize α; borelize β; borelize γ.
- Tags:
- Defined in module:
- Mathlib.MeasureTheory.Constructions.BorelSpace.Basic
bound
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 : ‖c‖ ≤ ‖z‖) (z3 : 3 ≤ ‖z‖) :
2 * ‖z‖ ≤ ‖z^2 + c‖ := by
calc ‖z^2 + c‖
_ ≥ ‖z^2‖ - ‖c‖ := by bound
_ ≥ ‖z^2‖ - ‖z‖ := by bound
_ ≥ (‖z‖ - 1) * ‖z‖ := by
rw [mul_comm, mul_sub_one, ← pow_two, ← norm_pow]
_ ≥ 2 * ‖z‖ := by bound
bound is built on top of aesop, and uses
- Apply lemmas registered via the
@[bound]attribute - Forward lemmas registered via the
@[bound_forward]attribute - Local hypotheses from the context
- Optionally: additional hypotheses provided as
bound [h₀, h₁]or similar. These are added to the context as if byhave := 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).
- Tags:
- Defined in module:
- Mathlib.Tactic.Bound
bv_check
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"
- Tags:
- Defined in module:
- Std.Tactic.BVDecide.Syntax
bv_decide
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 - automatically splitting up
structures that contain information aboutBitVecorBool
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.
Note: include import Std.Tactic.BVDecide
- Tags:
- Defined in module:
- Init.Tactics
bv_decide?
Suggest a proof script for a bv_decide tactic call. Useful for caching LRAT proofs.
Note: include import Std.Tactic.BVDecide
- Tags:
- Defined in module:
- Init.Tactics
bv_normalize
Run the normalization procedure of bv_decide only. Sometimes this is enough to solve basic
BitVec goals already.
Note: include import Std.Tactic.BVDecide
- Tags:
- Defined in module:
- Init.Tactics
bv_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 [bitvec_to_nat] at *.
bitvec_to_nat is a @[simp] attribute that you can (cautiously) add to more theorems.
- Tags:
- Defined in module:
- Init.Tactics
by_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.
- Tags:
- Defined in module:
- Init.ByCases
by_cases!
by_cases! h : p runs the by_cases h : p tactic, followed by
push_neg at h in the second subgoal. For example,
by_cases! h : a < bcreates one goal with hypothesish : a < band another withh : b ≤ a.by_cases! h : a ≠ bcreates one goal with hypothesish : a ≠ band another withh : a = b.
- Tags:
- Defined in module:
- Mathlib.Tactic.ByCases
by_contra
by_contra h proves ⊢ p by contradiction,
introducing a hypothesis h : ¬p and proving False.
- If
pis a negation¬q,h : qwill be introduced instead of¬¬q. - If
pis decidable, it usesDecidable.byContradictioninstead ofClassical.byContradiction. - If
his omitted, the introduced variable will be calledthis.
- Tags:
- Defined in module:
- Batteries.Tactic.Init
by_contra!
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 normalized using push_neg.
For instance, ¬ a < b will be changed to b ≤ a.
by_contra! can be used with rcases patterns.
For instance, by_contra! rfl on ⊢ s.Nonempty will substitute the equality s = ∅,
and by_contra! ⟨hp, hq⟩ on ⊢ ¬ p ∨ ¬ q will introduce hp : p and hq : q.
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:
example : 1 < 2 := by
by_contra! h
-- h : 2 ≤ 1 ⊢ False
example : 1 < 2 := by
by_contra! h : ¬ 1 < 2
-- h : ¬ 1 < 2 ⊢ False
- Tags:
- Defined in module:
- Mathlib.Tactic.ByContra
calc
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 <lhs>\n _ = <rhs> := <proof>. 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 for more information.
- Tags:
- Defined in module:
- Init.NotationExtra
cancel_denoms
cancel_denoms attempts to remove numerals from the denominators of fractions.
It works on propositions that are field-valued inequalities.
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
- Tags:
- Defined in module:
- Mathlib.Tactic.CancelDenoms.Core
case
case _ : t => tacfinds the first goal that unifies withtand then solves it usingtacor else fails. Likeshow, it changes the type of the goal tot. The_can optionally be a case tag, in which case it only looks at goals whose tag would be considered bycase(goals with an exact tag match, followed by goals with the tag as a suffix, followed by goals with the tag as a prefix).case _ n₁ ... nₘ : t => tacadditionally names themmost recent hypotheses with inaccessible names to the given names. The names are renamed before matching againstt. The_can optionally be a case tag.case _ : t := eis short forcase _ : t => exact e.case _ : t₁ | _ : t₂ | ... => tacis equivalent to(case _ : t₁ => tac); (case _ : t₂ => tac); ...but with all matching done on the original list of goals -- each goal is consumed as they are matched, so patterns may repeat or overlap.case _ : twill make the matched goal be the first goal.case _ : t₁ | _ : t₂ | ...makes the matched goals be the first goals in the given order.case _ : t := _andcase _ : t := ?mare the same ascase _ : tbut in the?mcase the goal tag is changed tom. In particular, the goal becomes metavariable?m.
- Tags:
- Defined in module:
- Batteries.Tactic.Case
case
case tag => tacfocuses on the goal with case nametagand solves it usingtac, or else fails.case tag x₁ ... xₙ => tacadditionally renames thenmost recent hypotheses with inaccessible names to the given names.case tag₁ | tag₂ => tacis equivalent to(case tag₁ => tac); (case tag₂ => tac).
- Tags:
- Defined in module:
- Init.Tactics
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.
- Tags:
- Defined in module:
- Init.Tactics
case'
case' _ : t => tac is similar to the case _ : t => tac tactic,
but it does not ensure the goal has been solved after applying tac,
nor does it admit the goal if tac failed.
Recall that case closes the goal using sorry when tac fails,
and the tactic execution is not interrupted.
- Tags:
- Defined in module:
- Batteries.Tactic.Case
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, whereeis an expression instead of a variable, generalizesein the goal, and then cases on the resulting variable.- Given
as : List α,cases as with | nil => tac₁ | cons a as' => tac₂, uses tactictac₁for thenilcase, andtac₂for theconscase, andaandas'are used as names for the new variables introduced. cases h : e, whereeis a variable or an expression, performs cases oneas above, but also adds a hypothesish : e = ...to each goal, where...is the constructor instance for that particular case.
- Tags:
- Defined in module:
- Init.Tactics
cases'
cases' x, where the variable x has inductive type t, splits the main goal,
producing one goal for each constructor of t, in which x is replaced by that constructor
applied to newly introduced variables. This is a backwards-compatible variant of the
cases tactic in Lean 4 core.
Prefer cases, rcases, or obtain when possible, because these tactics promote
structured proofs.
cases' x with n1 n2 ...names the arguments to the constructors. This is the main difference withcasesin core Lean.cases' e, whereeis an expression instead of a variable, generalizesein the goal, and then performs induction on the resulting variable.cases' h : e, whereeis an expression instead of a variable, generalizesein the goal, and then splits by cases on the resulting variable, adding to each goal the hypothesish : e = _where_is the constructor instance.cases' x using rusesras the case matching rule. Herershould be a term whose result type is of the formC t1 t2 ..., whereCis a bound variable andt1,t2, ... (if present) are bound variables.
Example:
example (h : p ∨ q) : q ∨ p := by
cases' h with hp hq
· exact Or.inr hp
· exact Or.inl hq
-- Though the following equivalent spellings should be preferred
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
rcases h with hp | hq
· exact Or.inr hp
· exact Or.inl hq
- Tags:
- Defined in module:
- Mathlib.Tactic.Cases
cases_type
cases_type I searches for a hypothesis h : type where I has the form (I ...), and splits the
main goal by cases on h. cases_type p fails if no hypothesis type has the identifier I as its
head symbol.
cases_type I_1 ... I_nsearches for a hypothesish : typewheretypehas one or more ofI_1, ...,I_nas its head symbol, and splits the main goal by cases onh.cases_type* Irepeatedly performs case splits until no more hypothesis type hasIas its head symbol. This shorthand for· repeat cases_type I.cases_type! pandcases_type!* pskip a hypothesis if the main goal would be replaced with two or more subgoals.
Example:
example (h : a ∧ b ∨ c ∧ d) (h2 : e ∧ f) : True := by
-- The following tactic destructs all conjunctions and disjunctions in the current context.
cases_type* Or And
· clear ‹a› ‹b› ‹e› ‹f›; (fail_if_success clear ‹c›); trivial
· clear ‹c› ‹d› ‹e› ‹f›; trivial
- Tags:
- Defined in module:
- Mathlib.Tactic.CasesM
casesm
casesm p searches for the first hypothesis h : type where type matches the term p,
and splits the main goal by cases on h. Use holes in p to indicate arbitrary subexpressions,
for example casesm _ ∧ _ will match any conjunction. casesm p fails if no hypothesis type
matches p.
casesm p_1, ..., p_nsearches for a hypothesish : typewheretypematches one or more of the given patternsp_1, ...p_n, and splits the main goal by cases onh.casesm* prepeatedly performs case splits until no more hypothesis type matchesp. This is a more efficient and compact version of· repeat casesm p. It is more efficient because the pattern is compiled once.casesm! pandcasesm!* pskip a hypothesis if the main goal would be replaced with two or more subgoals.
Example:
example (h : a ∧ b ∨ c ∧ d) (h2 : e ∧ f) : True := by
-- The following tactic destructs all conjunctions and disjunctions in the current context.
casesm* _∨_, _∧_
· clear ‹a› ‹b› ‹e› ‹f›; (fail_if_success clear ‹c›); trivial
· clear ‹c› ‹d› ‹e› ‹f›; trivial
- Tags:
- Defined in module:
- Mathlib.Tactic.CasesM
cfc_cont_tac
A tactic used to automatically discharge goals relating to the continuous functional calculus, specifically concerning continuity of the functions involved.
- Tags:
- Defined in module:
- Mathlib.Tactic.ContinuousFunctionalCalculus
cfc_tac
A tactic used to automatically discharge goals relating to the continuous functional calculus, specifically whether the element satisfies the predicate.
- Tags:
- Defined in module:
- Mathlib.Tactic.ContinuousFunctionalCalculus
cfc_zero_tac
A tactic used to automatically discharge goals relating to the non-unital continuous functional
calculus, specifically concerning whether f 0 = 0.
- Tags:
- Defined in module:
- Mathlib.Tactic.ContinuousFunctionalCalculus
change
change tgt'will change the goal fromtgttotgt', assuming these are definitionally equal.change t' at hwill change hypothesish : tto have typet', assuming assumingtandt'are definitionally equal.change a with bwill change occurrences ofatobin the goal, assumingaandbare definitionally equal.change a with b at hsimilarly changesatobin the type of hypothesish.
- Tags:
- Defined in module:
- Init.Tactics
choose
choose a b h h' using hyptakes a hypothesishypof the form∀ (x : X) (y : Y), ∃ (a : A) (b : B), P x y a b ∧ Q x y a bfor someP Q : X → Y → A → B → Propand outputs into context a functiona : X → Y → A,b : X → Y → Band two assumptions:h : ∀ (x : X) (y : Y), P x y (a x y) (b x y)andh' : ∀ (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 hypdoes the same, except that it will remove dependency of the functions on propositional arguments if possible. For example ifYis a proposition andAandBare nonempty in the above example then we will instead geta : X → A,b : X → B, and the assumptionsh : ∀ (x : X) (y : Y), P x y (a x) (b x)andh' : ∀ (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.
Like intro, the choose tactic supports type annotations to specify the expected type
of the introduced variables. This is useful for documentation and for catching mistakes early:
example (h : ∃ n : ℕ, n > 0) : True := by
choose (n : ℕ) (hn : n > 0) using h
trivial
If the provided type does not match the actual type, an error is raised.
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
- Tags:
- Defined in module:
- Mathlib.Tactic.Choose
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.
- Tags:
- Defined in module:
- Init.Tactics
clean_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.
- Tags:
- Defined in module:
- Init.WFTactics
clear
clear x... removes the given hypotheses, or fails if there are remaining
references to a hypothesis.
- Tags:
- Defined in module:
- Init.Tactics
clear
Clears all hypotheses it can, except those provided after a minus sign. Example:
clear * - h₁ h₂
- Tags:
- Defined in module:
- Mathlib.Tactic.ClearExcept
clear!
A variant of clear which clears not only the given hypotheses but also any other hypotheses
depending on them
- Tags:
- Defined in module:
- Mathlib.Tactic.ClearExclamation
clear_
Clear all hypotheses starting with _, like _match and _let_match.
- Tags:
- Defined in module:
- Mathlib.Tactic.Clear_
clear_aux_decl
This tactic clears all auxiliary declarations from the context.
- Tags:
- Defined in module:
- Mathlib.Tactic.Basic
clear_value
clear_value x...clears the values of the given local definitions. A local definitionx : α := vbecomes a hypothesisx : α.clear_value (h : x = _)adds a hypothesish : x = vbefore clearing the value ofx. This is short forhave h : x = v := rfl; clear_value x. Any value definitionally equal tovcan be used in place of_.clear_value *clears values of all hypotheses that can be cleared. Fails if none can be cleared.
These syntaxes can be combined. For example, clear_value x y * ensures that x and y are cleared
while trying to clear all other local definitions,
and clear_value (hx : x = _) y * with hx does the same while first adding the hx : x = v hypothesis.
- Tags:
- Defined in module:
- Init.Tactics
compareOfLessAndEq_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:
- seeing if
rflworks - seeing if the
compareat hand is nonetheless essentiallycompareOfLessAndEq, but, because of implicit arguments, requires us to unfold the defs and split theifs in the definition ofcompareOfLessAndEq - seeing if we can split by cases on the arguments, then see if the defs work themselves out
(useful when
compareis defined via amatchstatement, as it is forBool)
- Tags:
- Defined in module:
- Mathlib.Order.Defs.LinearOrder
compute_degree
compute_degree is a tactic to solve goals of the form
natDegree f = d,degree f = d,natDegree f ≤ d(or<),degree f ≤ d(or<),coeff f d = r, ifdis the degree off.
The tactic may leave goals of the form d' = d, 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 remaining goals and tries assumption.
- Tags:
- Defined in module:
- Mathlib.Tactic.ComputeDegree
congr
Apply congruence (recursively) to goals of the form ⊢ f as = f bs and ⊢ 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.
- Tags:
- Defined in module:
- Init.Tactics
congr
Apply congruence (recursively) to goals of the form ⊢ f as = f bs and ⊢ 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.
- Tags:
- Defined in module:
- Batteries.Tactic.Congr
congr
Apply congruence (recursively) to goals of the form ⊢ f as = f bs and ⊢ f as ≍ f bs.
congr ncontrols the depth of the recursive applications. This is useful whencongris too aggressive in breaking down the goal. For example, given⊢ f (g (x + y)) = f (g (y + x)),congrproduces the goals⊢ x = yand⊢ y = x, whilecongr 2produces 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 callext p (: n)?to all subgoals generated bycongr. For example, if the goal is⊢ f '' s = g '' sthencongr with xgenerates the goalx : α ⊢ f x = g x.
- Tags:
- Defined in module:
- Batteries.Tactic.Congr
congr!
congr! tries to prove the main goal by repeatedly applying congruence rules. For example, on a
goal of the form ⊢ f a1 a2 ... = f b1 b2 ..., congr! will make new goals ⊢ a1 = b1,
⊢ a2 = b2, ...
congr! is a more powerful version of the congr tactic that uses congruence lemmas (tagged with
@[congr]), reflexivity rules (tagged with @[refl]) and proof discharging strategies. The full
list of congruence proof strategies is documented in the module Mathlib.Tactic.CongrExclamation.
The congr! tactic is used by the convert and convert_to tactics.
congr! n, wherenis a positive numeral, controls the depth with which congruence is applied. For example, if the main goal isn + n + 1 = 2 * n + 1, thencongr! 1results in one goal,⊢ n + n = 2 * n, andcongr! 2(or more) results in two (impossible) goals⊢ HAdd.hAdd = HMul.hMuland⊢ n = 2. By default, the depth is unlimited.congr! with x ⟨y₁, y₂⟩ (z₁ | z₂)names or pattern-matches the variables introduced by congruence rules, likerintro x ⟨y₁, y₂⟩ (z₁ | z₂)would.congr! (config := cfg)uses the configuration options incfgto control the congruence rules (seeCongr!.Config).
- Tags:
- Defined in module:
- Mathlib.Tactic.CongrExclamation
congrm
congrm e is a tactic for proving goals of the form lhs = rhs, lhs ↔ rhs, 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:
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.
- Tags:
- Defined in module:
- Mathlib.Tactic.CongrM
congrm?
Display a widget panel allowing to generate a congrm call with holes specified by selecting
subexpressions in the goal.
- Tags:
- Defined in module:
- Mathlib.Tactic.Widget.CongrM
constructor
If the main goal's target type is an inductive type, constructor solves it with
the first matching constructor, or else fails.
- Tags:
- Defined in module:
- Init.Tactics
constructorm
constructorm p_1, ..., p_n, where the main goal has type type, applies the first matching
constructor for type, if type matches one of the given patterns. If type does not match any
of the patterns, constructorm fails.
constructorm* p_1, ..., p_nrepeatedly applies a constructor until the goal no longer matchesp_1, ...,p_n. This is a more efficient and compact version of· repeat constructorm p_1, ..., p_n. It is more efficient because the pattern is compiled once.
Examples:
example : True ∧ (True ∨ True) := by
constructorm* _ ∨ _, _ ∧ _, True
- Tags:
- Defined in module:
- Mathlib.Tactic.CasesM
continuity
The tactic continuity solves goals of the form Continuous f by applying lemmas tagged with the
continuity user attribute.
fun_prop is a (usually more powerful) alternative to continuity.
- Tags:
- Defined in module:
- Mathlib.Tactic.Continuity
continuity?
The tactic continuity solves goals of the form Continuous f by applying lemmas tagged with the
continuity user attribute.
- Tags:
- Defined in module:
- Mathlib.Tactic.Continuity
contradiction
contradiction closes the main goal if its hypotheses are "trivially contradictory".
- Inductive type/family with no applicable constructors
example (h : False) : p := by contradiction - Injectivity of constructors
example (h : none = some true) : p := by contradiction -- - Decidable false proposition
example (h : 2 + 2 = 3) : p := by contradiction - Contradictory hypotheses
example (h : p) (h' : ¬ p) : q := by contradiction - Other simple contradictions such as
example (x : Nat) (h : x ≠ x) : p := by contradiction
- Tags:
- Defined in module:
- Init.Tactics
contrapose
Transforms the goal into its contrapositive.
contraposeturns a goalP → Qinto¬ Q → ¬ Pand it turns a goalP ↔ Qinto¬ P ↔ ¬ Qcontrapose hfirst reverts the local assumptionh, and then usescontraposeandintro hcontrapose h with new_huses the namenew_hfor the introduced hypothesis
- Tags:
- Defined in module:
- Mathlib.Tactic.Contrapose
contrapose!
Transforms the goal into its contrapositive and pushes negations in the result.
Usage matches contrapose
- Tags:
- Defined in module:
- Mathlib.Tactic.Contrapose
conv
conv => ... allows the user to perform targeted rewriting on a goal or hypothesis,
by focusing on particular subexpressions.
See https://lean-lang.org/theorem_proving_in_lean4/conv.html for more details.
Basic forms:
conv => cswill rewrite the goal with conv tacticscs.conv at h => cswill rewrite hypothesish.conv in pat => cswill rewrite the first subexpression matchingpat(seepattern).
- Tags:
- Defined in module:
- Init.Conv
conv'
Executes the given conv block without converting regular goal into a conv goal.
- Tags:
- Defined in module:
- Init.Conv
conv?
Display a widget panel allowing to generate a conv call zooming to the subexpression selected
in the goal or in the type of a local hypothesis or let-decl.
- Tags:
- Defined in module:
- Mathlib.Tactic.Widget.Conv
conv_lhs
conv_lhs => cs runs the conv tactic sequence cs on the left hand side of the target.
In general, for an n-ary operator as the target, it traverses into the second to last argument.
It is a synonym for conv => arg -2; cs.
conv_lhs at h => csrunscson the left hand side of hypothesish.conv_lhs in pat => csfirst looks for a subexpression matchingpat(see also thepatternconv tactic) and then traverses into the left hand side of this subexpression. This syntax also supports theoccsclause for the pattern.
- Tags:
- Defined in module:
- Mathlib.Tactic.Conv
conv_rhs
conv_rhs => cs runs the conv tactic sequence cs on the right hand side of the target.
In general, for an n-ary operator as the target, it traverses into the last argument.
It is a synonym for conv => arg -1; cs.
conv_rhs at h => csrunscson the right hand side of hypothesish.conv_rhs in pat => csfirst looks for a subexpression matchingpat(see thepatternconv tactic) and then traverses into the right hand side of this subexpression. This syntax also supports theoccsclause for the pattern.
- Tags:
- Defined in module:
- Mathlib.Tactic.Conv
convert
convert e, where the term e is inferred to have type t, replaces the main goal ⊢ t' with new
goals for proving the equality t' = t using congruence. The goals are created like congr! would.
Like refine e, any holes (?_ or ?x) in e that are not solved by unification are converted
into new goals, using the hole's name, if any, as the goal case name.
Like congr!, convert introduces variables while applying congruence rules. These can be
pattern-matched, like rintro would, using the with keyword.
See also convert_to t, where t specifies the expected type, instead of a proof term of type t.
In other words, convert_to t works like convert (?_ : t). Both tactics use the same options.
convert ← ecreates equality goals in the opposite direction (with the goal type on the right).convert e using n, wherenis a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is⊢ Prime (n + n + 1)ande : Prime (2 * n + 1), thenconvert e using 2results in one goal,⊢ n + n = 2 * n, andconvert e using 3(or more) results in two (impossible) goals⊢ HAdd.hAdd = HMul.hMuland⊢ n = 2. By default, the depth is unlimited.convert e with x ⟨y₁, y₂⟩ (z₁ | z₂)names or pattern-matches the variables introduced by congruence rules, likerintro x ⟨y₁, y₂⟩ (z₁ | z₂)would.convert (config := cfg) euses the configuration options incfgto control the congruence rules (seeCongr!.Config).
Examples:
-- `convert using` controls the depth of congruence.
example {n : ℕ} (e : Prime (2 * n + 1)) :
Prime (n + n + 1) := by
convert e using 2
-- One goal: ⊢ n + n = 2 * n
ring
-- `convert` can fail where `exact` succeeds.
example (h : p 0) : p 1 := by
fail_if_success
convert h -- fails, left-over goal 1 = 0
done
exact h -- succeeds
```lean
-- `convert with` names introduced variables.
example (p q : Nat → Prop) (h : ∀ ε > 0, p ε) :
∀ ε > 0, q ε := by
convert h using 2 with ε hε
-- Goal now looks like:
-- hε : ε > 0
-- ⊢ q ε ↔ p ε
sorry
- Tags:
- Defined in module:
- Mathlib.Tactic.Convert
convert_to
convert_to t on a goal ⊢ t' changes the goal to ⊢ t and adds new goals for proving the
equality t' = t using congruence. The goals are created like congr! would.
Any remaining congruence goals come before the main goal.
Like refine e, any holes (?_ or ?x) in t that are not solved by unification are converted
into new goals, using the hole's name, if any, as the goal case name.
Like congr!, convert_to introduces variables while applying congruence rules. These can be
pattern-matched, like rintro would, using the with keyword.
convert e, where e is a term of type t, uses e to close the new main goal. In other words,
convert e works like convert_to t; refine e. Both tactics use the same options.
convert_to ty at hchanges the type of the local hypothesishtoty. If later local hypotheses or the goal depend onh, thenconvert_to t at hmay leave a copy ofh.convert_to ← tcreates equality goals in the opposite direction (with the original goal type on the right).convert_to t using n, wherenis a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is⊢ Prime (n + n + 1), thenconvert_to Prime (2 * n + 1) using 2results in one goal,⊢ n + n = 2 * n, andconvert_to Prime (2 * n + 1) using 3(or more) results in two (impossible) goals⊢ HAdd.hAdd = HMul.hMuland⊢ n = 2. The default value fornis 1.convert_to t with x ⟨y₁, y₂⟩ (z₁ | z₂)names or pattern-matches the variables introduced by congruence rules, likerintro x ⟨y₁, y₂⟩ (z₁ | z₂)would.convert_to (config := cfg) tuses the configuration options incfgto control the congruence rules (seeCongr!.Config).
- Tags:
- Defined in module:
- Mathlib.Tactic.Convert
cutsat
cutsat solves linear integer arithmetic goals.
It is a implemented as a thin wrapper around the grind tactic, enabling only the lia solver.
Please use grind instead if you need additional capabilities.
Deprecated: Use lia instead.
- Tags:
- Defined in module:
- Init.Grind.Tactics
dbg_trace
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"
- Tags:
- Defined in module:
- Init.Tactics
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 +revertbegins 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 +kerneluses 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 theDecidableinstance only once instead of twice.decide +nativeuses the native code compiler (#eval) to evaluate theDecidableinstance, admitting the result via theLean.ofReduceBoolaxiom. 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, theDecidableinstance 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:
example : 2 + 2 ≠ 5 := by decide
Trying to prove a false proposition:
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
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.
example : 1 + 1 = 2 := by decide
example : 1 + 1 = 2 := by rfl
- Tags:
- Defined in module:
- Init.Tactics
decreasing_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).
- Tags:
- Defined in module:
- Init.WFTactics
decreasing_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)
- Tags:
- Defined in module:
- Init.WFTactics
decreasing_trivial_pre_omega
Variant of decreasing_trivial that does not use omega, intended to be used in core modules
before omega is available.
- Tags:
- Defined in module:
- Init.WFTactics
decreasing_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.
- Tags:
- Defined in module:
- Init.WFTactics
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.
- Tags:
- Defined in module:
- Init.Tactics
deriving_LawfulEq_tactic
This tactic has no documentation.
- Tags:
- Defined in module:
- Init.LawfulBEqTactics
deriving_LawfulEq_tactic_step
This tactic has no documentation.
- Tags:
- Defined in module:
- Init.LawfulBEqTactics
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.
- Tags:
- Defined in module:
- Init.Tactics
dsimp!
dsimp! is shorthand for dsimp with autoUnfold := true.
This will unfold applications of functions defined by pattern matching, when one of the patterns applies.
This can be used to partially evaluate many definitions.
- Tags:
- Defined in module:
- Init.Meta
dsimp?
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.
- Tags:
- Defined in module:
- Init.Tactics
dsimp?!
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.
- Tags:
- Defined in module:
- Init.Tactics
eapply
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'
- Tags:
- Defined in module:
- Batteries.Tactic.Init
econstructor
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.
- Tags:
- Defined in module:
- Mathlib.Tactic.Constructor
eq_refl
eq_refl is equivalent to exact rfl, but has a few optimizations.
- Tags:
- Defined in module:
- Init.Tactics
erw
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).
- Tags:
- Defined in module:
- Init.Meta
erw?
erw? [r, ...] calls erw [r, ...] (at hypothesis h if written erw [r, ...] at h),
and then attempts to identify any subexpression which would block the use of rw instead.
It does so by identifying subexpressions which are defeq, but not at reducible transparency.
- Tags:
- Defined in module:
- Mathlib.Tactic.ErwQuestion
eta_expand
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.
- Tags:
- Defined in module:
- Mathlib.Tactic.DefEqTransformations
eta_reduce
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.
- Tags:
- Defined in module:
- Mathlib.Tactic.DefEqTransformations
eta_struct
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.
- Tags:
- Defined in module:
- Mathlib.Tactic.DefEqTransformations
exact
exact e closes the main goal if its target type matches that of e.
- Tags:
- Defined in module:
- Init.Tactics
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.
Use +grind to enable grind as a fallback discharger for subgoals.
Use +try? to enable try? as a fallback discharger for subgoals.
Use -star to disable fallback to star-indexed lemmas (like Empty.elim, And.left).
Use +all to collect all successful lemmas instead of stopping at the first.
- Tags:
- Defined in module:
- Init.Tactics
exact_mod_cast
Normalize casts in the goal and the given expression, then close the goal with exact.
- Tags:
- Defined in module:
- Init.TacticsExtra
exacts
Like exact, but takes a list of terms and checks that all goals are discharged after the tactic.
- Tags:
- Defined in module:
- Batteries.Tactic.Init
exfalso
exfalso converts a goal ⊢ tgt into ⊢ False by applying False.elim.
- Tags:
- Defined in module:
- Init.Tactics
exists
exists e₁, e₂, ... is shorthand for refine ⟨e₁, e₂, ...⟩; try trivial.
It is useful for existential goals.
- Tags:
- Defined in module:
- Init.Tactics
existsi
existsi e₁, e₂, ⋯ applies the tactic refine ⟨e₁, e₂, ⋯, ?_⟩. It's purpose is to instantiate
existential quantifiers.
Examples:
example : ∃ x : Nat, x = x := by
existsi 42
rfl
example : ∃ x : Nat, ∃ y : Nat, x = y := by
existsi 42, 42
rfl
- Tags:
- Defined in module:
- Mathlib.Tactic.ExistsI
expose_names
expose_names renames all inaccessible variables with accessible names, making them available
for reference in generated tactics. However, this renaming introduces machine-generated names
that are not fully under user control. expose_names is primarily intended as a preamble for
auto-generated end-game tactic scripts. It is also useful as an alternative to
set_option tactic.hygienic false. If explicit control over renaming is needed in the
middle of a tactic script, consider using structured tactic scripts with
match .. with, induction .. with, or intro with explicit user-defined names,
as well as tactics such as next, case, and rename_i.
- Tags:
- Defined in module:
- Init.Tactics
ext
Applies extensionality lemmas that are registered with the @[ext] attribute.
ext pat*applies extensionality theorems as much as possible, using the patternspat*to introduce the variables in extensionality theorems usingrintro. For example, the patterns are used to name the variables introduced by lemmas such asfunext.- Without patterns,
extapplies extensionality lemmas as much as possible but introduces anonymous hypotheses whenever needed. ext pat* : napplies ext theorems only up to depthn.
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.
- Tags:
- Defined in module:
- Init.Ext
ext1
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.
- Tags:
- Defined in module:
- Init.Ext
extract_goal
extract_goalformats 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 convenienceextract_goalincludes 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 variablesa,b,c, ... do not depend on.extract_goal ... using nameuses the namenamefor 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.
- Tags:
- Defined in module:
- Mathlib.Tactic.ExtractGoal
extract_lets
Extracts let and have expressions from within the target or a local hypothesis,
introducing new local definitions.
extract_letsextracts all the lets from the target.extract_lets x y zextracts all the lets from the target and usesx,y, andzfor the first names. Using_for a name leaves it unnamed.extract_lets x y z at hoperates on the local hypothesishinstead of the target.
For example, given a local hypotheses if the form h : let x := v; b x, then extract_lets z at h
introduces a new local definition z := v and changes h to be h : b z.
- Tags:
- Defined in module:
- Init.Tactics
fail
fail msg is a tactic that always fails, and produces an error using the given message.
- Tags:
- Defined in module:
- Init.Tactics
fail_if_no_progress
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.
- Tags:
- Defined in module:
- Mathlib.Tactic.FailIfNoProgress
false_or_by_contra
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, introducex = y.) - Otherwise, for a propositional goal
P, replace it with¬ ¬ P(attempting to find aDecidableinstance, but otherwise falling back to working classically) and introduce¬ P. - For a non-propositional goal use
False.elim.
- Tags:
- Defined in module:
- Init.Tactics
fapply
fapply e is like apply e but it adds goals in the order they appear,
rather than putting the dependent goals first.
- Tags:
- Defined in module:
- Batteries.Tactic.Init
fconstructor
fconstructor is like constructor
(it calls apply using the first matching constructor of an inductive datatype)
except that it does not reorder goals.
- Tags:
- Defined in module:
- Mathlib.Tactic.Constructor
field
The field tactic proves equality goals in (semi-)fields. For example:
example {x y : ℚ} (hx : x + y ≠ 0) : x / (x + y) + y / (x + y) = 1 := by
field
example {a b : ℝ} (ha : a ≠ 0) : a / (a * b) - 1 / b = 0 := by field
The scope of the tactic is equality goals which are universal, in the sense that they are true in any field in which the appropriate denominators don't vanish. (That is, they are consequences purely of the field axioms.)
Checking the nonvanishing of the necessary denominators is done using a variety of tricks -- in
particular this part of the reasoning is non-universal, i.e. can be specific to the field at hand
(order properties, explicit ≠ 0 hypotheses, CharZero if that is known, etc). The user can also
provide additional terms to help with the nonzeroness proofs. For example:
example {K : Type*} [Field K] (hK : ∀ x : K, x ^ 2 + 1 ≠ 0) (x : K) :
1 / (x ^ 2 + 1) + x ^ 2 / (x ^ 2 + 1) = 1 := by
field [hK]
The field tactic is built from the tactics field_simp (which clears the denominators) and ring
(which proves equality goals universally true in commutative (semi-)rings). If field fails to
prove your goal, you may still be able to prove your goal by running the field_simp and ring_nf
normalizations in some order. For example, this statement:
example {a b : ℚ} (H : b + a ≠ 0) : a / (a + b) + b / (b + a) = 1
is not proved by field but is proved by ring_nf at *; field.
- Tags:
- Defined in module:
- Mathlib.Tactic.Field
field_simp
The goal of field_simp is to bring expressions in (semi-)fields over a common denominator, i.e. to
reduce them to expressions of the form n / d where neither n nor d contains any division
symbol. For example, x / (1 - y) / (1 + y / (1 - y)) is reduced to x / (1 - y + y):
example (x y z : ℚ) (hy : 1 - y ≠ 0) :
⌊x / (1 - y) / (1 + y / (1 - y))⌋ < 3 := by
field_simp
-- new goal: `⊢ ⌊x / (1 - y + y)⌋ < 3`
The field_simp tactic will also clear denominators in field (in)equalities, by
cross-multiplying. For example, field_simp will clear the x denominators in the following
equation:
example {K : Type*} [Field K] {x : K} (hx0 : x ≠ 0) :
(x + 1 / x) ^ 2 + (x + 1 / x) = 1 := by
field_simp
-- new goal: `⊢ (x ^ 2 + 1) * (x ^ 2 + 1 + x) = x ^ 2`
A very common pattern is field_simp; ring (clear denominators, then the resulting goal is
solvable by the axioms of a commutative ring). The finishing tactic field is a shorthand for this
pattern.
Cancelling and combining denominators will generally require checking "nonzeroness"/"positivity"
side conditions. The field_simp tactic attempts to discharge these, and will omit such steps if it
cannot discharge the corresponding side conditions. The discharger will try, among other things,
positivity and norm_num, and will also use any nonzeroness/positivity proofs included explicitly
(e.g. field_simp [hx]). If your expression is not completely reduced by field_simp, check the
denominators of the resulting expression and provide proofs that they are nonzero/positive to enable
further progress.
- Tags:
- Defined in module:
- Mathlib.Tactic.FieldSimp
field_simp_discharge
Discharge strategy for the field_simp tactic.
- Tags:
- Defined in module:
- Mathlib.Tactic.FieldSimp.Discharger
filter_upwards
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ₙ], intro 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.
- Tags:
- Defined in module:
- Mathlib.Order.Filter.Defs
fin_cases
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.
- Tags:
- Defined in module:
- Mathlib.Tactic.FinCases
fin_omega
Preprocessor for omega to handle inequalities in Fin.
Note that this involves a lot of case splitting, so may be slow.
- Tags:
- Defined in module:
- Mathlib.Data.Fin.Basic
find
find finds definitions and theorems whose result type matches the current goal exactly,
and prints them as info lines.
In other words, find lists definitions and theorems that are applyable against the current goal.
find will not affect the goal by itself and should be removed from the finished proof.
For a command or tactic that takes the type to search for as an argument, see #find.
Example:
example : True := by
find
-- True.intro: True
-- trivial: True
-- ...
- Tags:
- Defined in module:
- Mathlib.Tactic.Find
finiteness
finiteness proves goals of the form *** < ∞ and (equivalently) *** ≠ ∞ in the extended
nonnegative reals (ℝ≥0∞). Supports passing additional expressions as local hypotheses.
finiteness?additionally shows the proof thatfinitenessfoundfiniteness_nonterminalis a version offinitenessthat may (but doesn't have to) close the goal.
- Tags:
- Defined in module:
- Mathlib.Tactic.Finiteness
first
first | tac | ... runs each tac until one succeeds, or else fails.
- Tags:
- Defined in module:
- Init.Tactics
first_par
Helper internal tactic for implementing the tactic try? with parallel execution, returning first success.
- Tags:
- Defined in module:
- Init.Try
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.
- Tags:
- Defined in module:
- Init.Tactics
fun_cases
The fun_cases tactic is a convenience wrapper of the cases tactic when using a functional
cases principle.
The tactic invocation
fun_cases f x ... y ...`
is equivalent to
cases y, ... using f.fun_cases_unfolding x ...
where the arguments of f are used as arguments to f.fun_cases_unfolding or targets of the case
analysis, as appropriate.
The form
fun_cases f
(with no arguments to f) searches the goal for a unique eligible application of f, and uses
these arguments. An application of f is eligible if it is saturated and the arguments that will
become targets are free variables.
The form fun_cases f x y with | case1 => tac₁ | case2 x' ih => tac₂ works like with cases.
Under set_option tactic.fun_induction.unfolding true (the default), fun_induction uses the
f.fun_cases_unfolding theorem, which will try to automatically unfold the call to f in
the goal. With set_option tactic.fun_induction.unfolding false, it uses f.fun_cases instead.
- Tags:
- Defined in module:
- Init.Tactics
fun_induction
The fun_induction tactic is a convenience wrapper around the induction tactic to use the
functional induction principle.
The tactic invocation
fun_induction f x₁ ... xₙ y₁ ... yₘ
where f is a function defined by non-mutual structural or well-founded recursion, is equivalent to
induction y₁, ... yₘ using f.induct_unfolding x₁ ... xₙ
where the arguments of f are used as arguments to f.induct_unfolding or targets of the
induction, as appropriate.
The form
fun_induction f
(with no arguments to f) searches the goal for a unique eligible application of f, and uses
these arguments. An application of f is eligible if it is saturated and the arguments that will
become targets are free variables.
The forms fun_induction f x y generalizing z₁ ... zₙ and
fun_induction f x y with | case1 => tac₁ | case2 x' ih => tac₂ work like with induction.
Under set_option tactic.fun_induction.unfolding true (the default), fun_induction uses the
f.induct_unfolding induction principle, which will try to automatically unfold the call to f in
the goal. With set_option tactic.fun_induction.unfolding false, it uses f.induct instead.
- Tags:
- Defined in module:
- Init.Tactics
fun_prop
fun_prop solves a goal of the form P f, where P is a predicate and f is a function,
by decomposing f into a composition of elementary functions, and proving P on each of those
by matching against a set of @[fun_prop] lemmas.
If fun_prop fails to solve a goal with the error "No theorems found", you can solve this issue
by importing or adding new theorems tagged with the @[fun_prop] attribute. See the module
documentation for Mathlib/Tactic/FunProp.lean for a detailed explanation.
fun_prop (disch := tac)usestacto solve potential side goals. Setting this option is required to solveContinuousAt/On/Withingoals.fun_prop [c, ...]will unfold the constant(s)c, ... before decomposingf.fun_prop (config := cfg)sets advanced configuration options usingcfg : FunProp.Config(seeFunProp.Configfor details).
Examples:
example : Continuous (fun x : ℝ ↦ x * sin x) := by fun_prop
-- Specify a discharger to solve `ContinuousAt`/`Within`/`On` goals:
example (y : ℝ) (hy : y ≠ 0) : ContinuousAt (fun x : ℝ ↦ 1/x) y := by
fun_prop (disch := assumption)
example (y : ℝ) (hy : y ≠ 0) : ContinuousAt (fun x => x * (Real.log x) ^ 2 - Real.exp x / x) y := by
fun_prop (disch := aesop)
- Tags:
- Defined in module:
- Mathlib.Tactic.FunProp.Elab
funext
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.
- Tags:
- Defined in module:
- Init.NotationExtra
gcongr
The gcongr tactic applies "generalized congruence" rules, reducing a relational goal
between an LHS and RHS. 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 an LHS and RHS both of the pattern
x ^ 2 * ?_ + ?_
(with inputs a, c on the left and b, d on the right); after the use of
gcongr, we have the simpler goals a ≤ b and c ≤ d.
A depth limit or a pattern can be provided explicitly; this is useful if a non-maximal match is desired:
example {a b c d x : ℝ} (h : a + c + 1 ≤ b + d + 1) :
x ^ 2 * (a + c) + 5 ≤ x ^ 2 * (b + d) + 5 := by
gcongr x ^ 2 * ?_ + 5 -- or `gcongr 2`
linarith
The "generalized congruence" rules are the library lemmas which have been tagged with the
attribute @[gcongr]. For example, the first example constructs the proof term
add_le_add (mul_le_mul_of_nonneg_left ?_ (Even.pow_nonneg (even_two_mul 1) x)) ?_
using the generalized congruence lemmas add_le_add and mul_le_mul_of_nonneg_left.
The tactic attempts to discharge side goals to these "generalized congruence" lemmas (such as the
side goal 0 ≤ x ^ 2 in the above application of mul_le_mul_of_nonneg_left) using the tactic
gcongr_discharger, which wraps positivity but can also be extended. Side goals not discharged
in this way are left for the user.
gcongr will descend into binders (for example sums or suprema). To name the bound variables,
use with:
example {f g : ℕ → ℝ≥0∞} (h : ∀ n, f n ≤ g n) : ⨆ n, f n ≤ ⨆ n, g n := by
gcongr with i
exact h i
- Tags:
- Defined in module:
- Mathlib.Tactic.GCongr.Core
gcongr_discharger
gcongr_discharger is used by gcongr to discharge side goals.
This is an extensible tactic using macro_rules.
By default it calls positivity (after importing the positivity tactic).
Example: macro_rules | `(tactic| gcongr_discharger) => `(tactic| positivity).
- Tags:
- Defined in module:
- Mathlib.Tactic.GCongr.Core
generalize
generalize ([h :] e = x),+replaces all occurrenceses in the main goal with a fresh hypothesisxs. Ifhis given,h : e = xis introduced as well.generalize e = x at h₁ ... hₙalso generalizes occurrences ofeinsideh₁, ...,hₙ.generalize e = x at *will generalize occurrences ofeeverywhere.
- Tags:
- Defined in module:
- Init.Tactics
generalize_proofs
generalize_proofs ids* [at locs]? generalizes proofs in the current goal,
turning them into new local hypotheses.
generalize_proofsgeneralizes proofs in the target.generalize_proofs at h₁ h₂generalized proofs in hypothesesh₁andh₂.generalize_proofs at *generalizes proofs in the entire local context.generalize_proofs pf₁ pf₂ pf₃uses namespf₁,pf₂, andpf₃for the generalized proofs. These can be_to not name proofs.
If a proof is already present in the local context, it will use that rather than create a new local hypothesis.
When doing generalize_proofs at h, if h is a let binding, its value is cleared,
and furthermore if h duplicates a preceding local hypothesis then it is eliminated.
The tactic is able to abstract proofs from under binders, creating universally quantified
proofs in the local context.
To disable this, use generalize_proofs -abstract.
The tactic is also set to recursively abstract proofs from the types of the generalized proofs.
This can be controlled with the maxDepth configuration option,
with generalize_proofs (config := { maxDepth := 0 }) turning this feature off.
For example:
def List.nthLe {α} (l : List α) (n : ℕ) (_h : n < l.length) : α := sorry
example : List.nthLe [1, 2] 1 (by simp) = 2 := by
-- ⊢ [1, 2].nthLe 1 ⋯ = 2
generalize_proofs h
-- h : 1 < [1, 2].length
-- ⊢ [1, 2].nthLe 1 h = 2
- Tags:
- Defined in module:
- Batteries.Tactic.GeneralizeProofs
get_elem_tactic
get_elem_tactic is the tactic automatically called by the notation arr[i]
to prove any side conditions that arise when constructing the term
(e.g. the index is in bounds of the array). It just delegates to
get_elem_tactic_extensible and gives a diagnostic error message otherwise;
users are encouraged to extend get_elem_tactic_extensible instead of this tactic.
- Tags:
- Defined in module:
- Init.Tactics
get_elem_tactic_extensible
get_elem_tactic_extensible is an extensible tactic automatically called
by the notation arr[i] to prove any side conditions that arise when
constructing the term (e.g. the index is in bounds of the array).
The default behavior is to try simp +arith and omega
(for doing linear arithmetic in the index).
(Note that the core tactic get_elem_tactic has already tried
done and assumption before the extensible tactic is called.)
- Tags:
- Defined in module:
- Init.Tactics
get_elem_tactic_trivial
get_elem_tactic_trivial has been deprecated in favour of get_elem_tactic_extensible.
- Tags:
- Defined in module:
- Init.Tactics
grewrite
grewrite [e] is like grw [e], but it doesn't try to close the goal with rfl.
This is analogous to rw and rewrite, where rewrite doesn't try to close the goal with rfl.
- Tags:
- Defined in module:
- Mathlib.Tactic.GRewrite.Elab
grind
grind is a tactic inspired by modern SMT solvers. Picture a virtual whiteboard:
every time grind discovers a new equality, inequality, or logical fact,
it writes it on the board, groups together terms known to be equal,
and lets each reasoning engine read from and contribute to the shared workspace.
These engines work together to handle equality reasoning, apply known theorems,
propagate new facts, perform case analysis, and run specialized solvers
for domains like linear arithmetic and commutative rings.
See the reference manual's chapter on grind for more information.
grind is not designed for goals whose search space explodes combinatorially,
think large pigeonhole instances, graph‑coloring reductions, high‑order N‑queens boards,
or a 200‑variable Sudoku encoded as Boolean constraints. Such encodings require
thousands (or millions) of case‑splits that overwhelm grind’s branching search.
For bit‑level or combinatorial problems, consider using bv_decide.
bv_decide calls a state‑of‑the‑art SAT solver (CaDiCaL) and then returns a
compact, machine‑checkable certificate.
Equality reasoning #
grind uses congruence closure to track equalities between terms.
When two terms are known to be equal, congruence closure automatically deduces
equalities between more complex expressions built from them.
For example, if a = b, then congruence closure will also conclude that f a = f b
for any function f. This forms the foundation for efficient equality reasoning in grind.
Here is an example:
example (f : Nat → Nat) (h : a = b) : f (f b) = f (f a) := by
grind
Applying theorems using E-matching #
To apply existing theorems, grind uses a technique called E-matching,
which finds matches for known theorem patterns while taking equalities into account.
Combined with congruence closure, E-matching helps grind discover
non-obvious consequences of theorems and equalities automatically.
Consider the following functions and theorems:
def f (a : Nat) : Nat :=
a + 1
def g (a : Nat) : Nat :=
a - 1
@[grind =]
theorem gf (x : Nat) : g (f x) = x := by
simp [f, g]
The theorem gf asserts that g (f x) = x for all natural numbers x.
The attribute [grind =] instructs grind to use the left-hand side of the equation,
g (f x), as a pattern for E-matching.
Suppose we now have a goal involving:
example {a b} (h : f b = a) : g a = b := by
grind
Although g a is not an instance of the pattern g (f x),
it becomes one modulo the equation f b = a. By substituting a
with f b in g a, we obtain the term g (f b),
which matches the pattern g (f x) with the assignment x := b.
Thus, the theorem gf is instantiated with x := b,
and the new equality g (f b) = b is asserted.
grind then uses congruence closure to derive the implied equality
g a = g (f b) and completes the proof.
The pattern used to instantiate theorems affects the effectiveness of grind.
For example, the pattern g (f x) is too restrictive in the following case:
the theorem gf will not be instantiated because the goal does not even
contain the function symbol g.
example (h₁ : f b = a) (h₂ : f c = a) : b = c := by
grind
You can use the command grind_pattern to manually select a pattern for a given theorem.
In the following example, we instruct grind to use f x as the pattern,
allowing it to solve the goal automatically:
grind_pattern gf => f x
example {a b c} (h₁ : f b = a) (h₂ : f c = a) : b = c := by
grind
You can enable the option trace.grind.ematch.instance to make grind print a
trace message for each theorem instance it generates.
You can also specify a multi-pattern to control when grind should apply a theorem.
A multi-pattern requires that all specified patterns are matched in the current context
before the theorem is applied. This is useful for theorems such as transitivity rules,
where multiple premises must be simultaneously present for the rule to apply.
The following example demonstrates this feature using a transitivity axiom for a binary relation R:
opaque R : Int → Int → Prop
axiom Rtrans {x y z : Int} : R x y → R y z → R x z
grind_pattern Rtrans => R x y, R y z
example {a b c d} : R a b → R b c → R c d → R a d := by
grind
By specifying the multi-pattern R x y, R y z, we instruct grind to
instantiate Rtrans only when both R x y and R y z are available in the context.
In the example, grind applies Rtrans to derive R a c from R a b and R b c,
and can then repeat the same reasoning to deduce R a d from R a c and R c d.
Instead of using grind_pattern to explicitly specify a pattern,
you can use the @[grind] attribute or one of its variants, which will use a heuristic to
generate a (multi-)pattern. The complete list is available in the reference manual. The main ones are:
@[grind →]will select a multi-pattern from the hypotheses of the theorem (i.e. it will use the theorem for forwards reasoning). In more detail, it will traverse the hypotheses of the theorem from left-to-right, and each time it encounters a minimal indexable (i.e. has a constant as its head) subexpression which "covers" (i.e. fixes the value of) an argument which was not previously covered, it will add that subexpression as a pattern, until all arguments have been covered.@[grind ←]will select a multi-pattern from the conclusion of theorem (i.e. it will use the theorem for backwards reasoning). This may fail if not all the arguments to the theorem appear in the conclusion.@[grind]will traverse the conclusion and then the hypotheses left-to-right, adding patterns as they increase the coverage, stopping when all arguments are covered.@[grind =]checks that the conclusion of the theorem is an equality, and then uses the left-hand-side of the equality as a pattern. This may fail if not all of the arguments appear in the left-hand-side.
Here is the previous example again but using the attribute [grind →]
opaque R : Int → Int → Prop
@[grind →] axiom Rtrans {x y z : Int} : R x y → R y z → R x z
example {a b c d} : R a b → R b c → R c d → R a d := by
grind
To control theorem instantiation and avoid generating an unbounded number of instances,
grind uses a generation counter. Terms in the original goal are assigned generation zero.
When grind applies a theorem using terms of generation ≤ n n, any new terms it creates
are assigned generation n + 1 + 1 1. This limits how far the tactic explores when applying
theorems and helps prevent an excessive number of instantiations.
Key options: #
grind (ematch := <num>)controls the number of E-matching rounds.grind [<name>, ...]instructsgrindto use the declarationnameduring E-matching.grind only [<name>, ...]is likegrind [<name>, ...]but does not use theorems tagged with@[grind].grind (gen := <num>)sets the maximum generation.
Linear integer arithmetic (lia) #
grind can solve goals that reduce to linear integer arithmetic (LIA) using an
integrated decision procedure called lia. It understands
- equalities
p = 0 - inequalities
p ≤ 0 - disequalities
p ≠ 0 - divisibility
d ∣ p
The solver incrementally assigns integer values to variables; when a partial assignment violates a constraint it adds a new, implied constraint and retries. This model-based search is complete for LIA.
Key options: #
grind -liadisable the solver (useful for debugging)grind +qliaaccept rational models (shrinks the search space but is incomplete for ℤ)
Examples: #
-- Even + even is never odd.
example {x y : Int} : 2 * x + 4 * y ≠ 5 := by
grind
-- Mixing equalities and inequalities.
example {x y : Int} :
2 * x + 3 * y = 0 → 1 ≤ x → y < 1 := by
grind
-- Reasoning with divisibility.
example (a b : Int) :
2 ∣ a + 1 → 2 ∣ b + a → ¬ 2 ∣ b + 2 * a := by
grind
example (x y : Int) :
27 ≤ 11*x + 13*y →
11*x + 13*y ≤ 45 →
-10 ≤ 7*x - 9*y →
7*x - 9*y ≤ 4 → False := by
grind
-- Types that implement the `ToInt` type-class.
example (a b c : UInt64)
: a ≤ 2 → b ≤ 3 → c - a - b = 0 → c ≤ 5 := by
grind
Algebraic solver (ring) #
grind ships with an algebraic solver nick-named ring for goals that can
be phrased as polynomial equations (or disequations) over commutative rings,
semirings, or fields.
Works out of the box All core numeric types and relevant Mathlib types already provide the required type-class instances, so the solver is ready to use in most developments.
What it can decide:
- equalities of the form
p = q - disequalities
p ≠ q - basic reasoning under field inverses (
a / b := a * b⁻¹) - goals that mix ring facts with other
grindengines
Key options: #
grind -ringturn the solver off (useful when debugging)grind (ringSteps := n)cap the number of steps performed by this procedure.
Examples #
open Lean Grind
example [CommRing α] (x : α) : (x + 1) * (x - 1) = x^2 - 1 := by
grind
-- Characteristic 256 means 16 * 16 = 0.
example [CommRing α] [IsCharP α 256] (x : α) :
(x + 16) * (x - 16) = x^2 := by
grind
-- Works on built-in rings such as `UInt8`.
example (x : UInt8) : (x + 16) * (x - 16) = x^2 := by
grind
example [CommRing α] (a b c : α) :
a + b + c = 3 →
a^2 + b^2 + c^2 = 5 →
a^3 + b^3 + c^3 = 7 →
a^4 + b^4 = 9 - c^4 := by
grind
example [Field α] [NoNatZeroDivisors α] (a : α) :
1 / a + 1 / (2 * a) = 3 / (2 * a) := by
grind
Other options #
grind (splits := <num>)caps the depth of the search tree. Once a branch performsnumsplitsgrindstops splitting further in that branch.grind -splitItedisables case splitting on if-then-else expressions.grind -splitMatchdisables case splitting onmatchexpressions.grind +splitImpinstructsgrindto split on any hypothesisA → Bwhose antecedentAis propositional.grind -linarithdisables the linear arithmetic solver for (ordered) modules and rings.
Additional Examples #
example {a b} {as bs : List α} : (as ++ bs ++ [b]).getLastD a = b := by
grind
example (x : BitVec (w+1)) : (BitVec.cons x.msb (x.setWidth w)) = x := by
grind
example (as : Array α) (lo hi i j : Nat) :
lo ≤ i → i < j → j ≤ hi → j < as.size → min lo (as.size - 1) ≤ i := by
grind
- Tags:
- Defined in module:
- Init.Grind.Tactics
grind?
grind? takes the same arguments as grind, but reports an equivalent call to grind only
that would be sufficient to close the goal. This is useful for reducing the size of the grind
theorems in a local invocation.
- Tags:
- Defined in module:
- Init.Grind.Tactics
grobner
grobner solves goals that can be phrased as polynomial equations (with further polynomial equations as hypotheses)
over commutative (semi)rings, using the Grobner basis algorithm.
It is a implemented as a thin wrapper around the grind tactic, enabling only the grobner solver.
Please use grind instead if you need additional capabilities.
- Tags:
- Defined in module:
- Init.Grind.Tactics
group
Tactic for normalizing expressions in multiplicative groups, without assuming commutativity, using only the group axioms without any information about which group is manipulated.
(For additive commutative groups, use the abel tactic instead.)
Example:
example {G : Type} [Group G] (a b c d : G) (h : c = (a*b^2)*((b*b)⁻¹*a⁻¹)*d) : a*c*d⁻¹ = a := by
group at h -- normalizes `h` which becomes `h : c = d`
rw [h] -- the goal is now `a*d*d⁻¹ = a`
group -- which then normalized and closed
- Tags:
- Defined in module:
- Mathlib.Tactic.Group
grw
grw [e] works just like rw [e], but e can be a relation other than = or ↔.
For example:
variable {a b c d n : ℤ}
example (h₁ : a < b) (h₂ : b ≤ c) : a + d ≤ c + d := by
grw [h₁, h₂]
example (h : a ≡ b [ZMOD n]) : a ^ 2 ≡ b ^ 2 [ZMOD n] := by
grw [h]
example (h₁ : a ∣ b) (h₂ : b ∣ a ^ 2 * c) : a ∣ b ^ 2 * c := by
grw [h₁] at *
exact h₂
To replace the RHS with the LHS of the given relation, use the ← notation (just like in rw):
example (h₁ : a < b) (h₂ : b ≤ c) : a + d ≤ c + d := by
grw [← h₂, ← h₁]
The strict inequality a < b is turned into the non-strict inequality a ≤ b to rewrite with it.
A future version of grw may get special support for making better use of strict inequalities.
To rewrite only in the n-th position, use nth_grw n.
This is useful when grw tries to rewrite in a position that is not valid for the given relation.
To be able to use grw, the relevant lemmas need to be tagged with @[gcongr].
To rewrite inside a transitive relation, you can also give it an IsTrans instance.
To let grw unfold more aggressively, as in erw, use grw (transparency := default).
- Tags:
- Defined in module:
- Mathlib.Tactic.GRewrite.Elab
guard_expr
Tactic to check equality of two expressions.
guard_expr e = e'checks thateande'are defeq at reducible transparency.guard_expr e =~ e'checks thateande'are defeq at default transparency.guard_expr e =ₛ e'checks thateande'are syntactically equal.guard_expr e =ₐ e'checks thateande'are alpha-equivalent.
Both e and e' are elaborated then have their metavariables instantiated before the equality
check. Their types are unified (using isDefEqGuarded) before synthetic metavariables are
processed, which helps with default instance handling.
- Tags:
- Defined in module:
- Init.Guard
guard_goal_nums
guard_goal_nums n succeeds if there are exactly n goals and fails otherwise.
- Tags:
- Defined in module:
- Mathlib.Tactic.GuardGoalNums
guard_hyp
Tactic to check that a named hypothesis has a given type and/or value.
guard_hyp h : tchecks the type up to reducible defeq,guard_hyp h :~ tchecks the type up to default defeq,guard_hyp h :ₛ tchecks the type up to syntactic equality,guard_hyp h :ₐ tchecks the type up to alpha equality.guard_hyp h := vchecks value up to reducible defeq,guard_hyp h :=~ vchecks value up to default defeq,guard_hyp h :=ₛ vchecks value up to syntactic equality,guard_hyp h :=ₐ vchecks the value up to alpha equality.
The value v is elaborated using the type of h as the expected type.
- Tags:
- Defined in module:
- Init.Guard
guard_hyp_nums
guard_hyp_nums n succeeds if there are exactly n hypotheses and fails otherwise.
Note that, depending on what options are set, some hypotheses in the local context might not be printed in the goal view. This tactic computes the total number of hypotheses, not the number of visible hypotheses.
- Tags:
- Defined in module:
- Mathlib.Tactic.GuardHypNums
guard_target
Tactic to check that the target agrees with a given expression.
guard_target = echecks that the target is defeq at reducible transparency toe.guard_target =~ echecks that the target is defeq at default transparency toe.guard_target =ₛ echecks that the target is syntactically equal toe.guard_target =ₐ echecks that the target is alpha-equivalent toe.
The term e is elaborated with the type of the goal as the expected type, which is mostly
useful within conv mode.
- Tags:
- Defined in module:
- Init.Guard
have
The have tactic is for adding opaque definitions and hypotheses to the local context of the main goal.
The definitions forget their associated value and cannot be unfolded, unlike definitions added by the let tactic.
have h : t := eadds the hypothesish : tifeis a term of typet.have h := euses the type ofefort.have : t := eandhave := eusethisfor the name of the hypothesis.have pat := efor a patternpatis equivalent tomatch e with | pat => _, where_stands for the tactics that follow this one. It is convenient for types that have only one applicable constructor. For example, givenh : p ∧ q ∧ r,have ⟨h₁, h₂, h₃⟩ := hproduces the hypothesesh₁ : p,h₂ : q, andh₃ : r.- The syntax
have (eq := h) pat := eis equivalent tomatch h : e with | pat => _, which adds the equationh : e = patto the local context.
The tactic supports all the same syntax variants and options as the have term.
Properties and relations #
- It is not possible to unfold a variable introduced using
have, since the definition's value is forgotten. Thelettactic introduces definitions that can be unfolded. - The
have h : t := eis like doinglet h : t := e; clear_value h. - The
havetactic is preferred for propositions, andletis preferred for non-propositions. - Sometimes
haveis used for non-propositions to ensure that the variable is never unfolded, which may be important for performance reasons. Consider using the equivalentlet +nondepto indicate the intent.
- Tags:
- Defined in module:
- Init.Tactics
haveI
haveI behaves like have, but inlines the value instead of producing a have term.
- Tags:
- Defined in module:
- Init.Tactics
hint
The hint tactic tries every tactic registered using register_hint <prio> tac,
and reports any that succeed.
- Tags:
- Defined in module:
- Mathlib.Tactic.Hint
if
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 ?_.)
The assumptions in each subgoal can be named. 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.
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.
- Tags:
- Defined in module:
- Init.Tactics
induction
Assuming x is a variable in the local context with an inductive type,
induction x applies induction on x to 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
and an inductive hypothesis is added for each recursive argument to the constructor.
If the type of an element in the local context depends on x,
that element is reverted and reintroduced afterward,
so that the inductive hypothesis incorporates that hypothesis as well.
For example, given n : Nat and a goal with a hypothesis h : P n and target Q n,
induction n produces one goal with hypothesis h : P 0 and target Q 0,
and one goal with hypotheses h : P (Nat.succ a) and ih₁ : P a → Q a and target Q (Nat.succ a).
Here the names a and ih₁ are chosen automatically and are not accessible.
You can use with to provide the variables names for each constructor.
induction e, whereeis an expression instead of a variable, generalizesein the goal, and then performs induction on the resulting variable.induction e using rallows the user to specify the principle of induction that should be used. Herershould be a term whose result type must be of the formC t, whereCis a bound variable andtis a (possibly empty) sequence of bound variablesinduction e generalizing z₁ ... zₙ, wherez₁ ... zₙare variables in the local context, generalizes overz₁ ... zₙbefore applying the induction but then introduces them in each goal. In other words, the net effect is that each inductive hypothesis is generalized.- Given
x : Nat,induction x with | zero => tac₁ | succ x' ih => tac₂uses tactictac₁for thezerocase, andtac₂for thesucccase.
- Tags:
- Defined in module:
- Init.Tactics
induction'
induction' x applies induction on the variable x of the inductive type t to the main goal,
producing one goal for each constructor of t, in which x is replaced by that constructor
applied to newly introduced variables. induction' adds an inductive hypothesis for
each recursive argument to the constructor. This is a backwards-compatible variant of the
induction tactic in Lean 4 core.
Prefer induction when possible, because it promotes structured proofs.
induction' x with n1 n2 ...names the introduced hypotheses: arguments to constructors and inductive hypotheses. This is the main difference withinductionin core Lean.induction' e, whereeis an expression instead of a variable, generalizesein the goal, and then performs induction on the resulting variable.induction' h : e, whereeis an expression instead of a variable, generalizesein the goal, and then performs induction on the resulting variable, adding to each goal the hypothesish : e = _where_is the constructor instance.induction' x using rusesras the principle of induction. Herershould be a term whose result type is of the formC t1 t2 ..., whereCis a bound variable andt1,t2, ... (if present) are bound variables.induction' x generalizing z1 z2 ...generalizes over the local variablesz1,z2, ... in the inductive hypothesis.
Example:
open Nat
example (n : ℕ) : 0 < factorial n := by
induction' n with n ih
· rw [factorial_zero]
simp
· rw [factorial_succ]
apply mul_pos (succ_pos n) ih
-- Though the following equivalent spellings should be preferred
example (n : ℕ) : 0 < factorial n := by
induction n
case zero =>
rw [factorial_zero]
simp
case succ n ih =>
rw [factorial_succ]
apply mul_pos (succ_pos n) ih
- Tags:
- Defined in module:
- Mathlib.Tactic.Cases
infer_instance
infer_instance is an abbreviation for exact inferInstance.
It synthesizes a value of any target type by typeclass inference.
- Tags:
- Defined in module:
- Init.Tactics
infer_param
Close a goal of the form optParam α a or autoParam α stx by using a.
- Tags:
- Defined in module:
- Mathlib.Tactic.InferParam
inhabit
inhabit α tries to derive a Nonempty α instance and
then uses it to make an Inhabited α instance.
If the target is a Prop, this is done constructively. Otherwise, it uses Classical.choice.
- Tags:
- Defined in module:
- Mathlib.Tactic.Inhabit
injection
The injection tactic is based on the fact that constructors of inductive data
types are injections.
That means that if c is a constructor of an inductive datatype, and if (c t₁)
and (c t₂) are two terms that are equal then t₁ and t₂ are equal too.
If q is a proof of a statement of conclusion t₁ = t₂, then injection applies
injectivity to derive the equality of all arguments of t₁ and t₂ placed in
the same positions. For example, from (a::b) = (c::d) we derive a=c and b=d.
To use this tactic t₁ and t₂ should be constructor applications of the same constructor.
Given h : a::b = c::d, the tactic injection h adds two new hypothesis with types
a = c and b = d to the main goal.
The tactic injection h with h₁ h₂ uses the names h₁ and h₂ to name the new hypotheses.
- Tags:
- Defined in module:
- Init.Tactics
injections
injections applies injection to all hypotheses recursively
(since injection can produce new hypotheses). Useful for destructing nested
constructor equalities like (a::b::c) = (d::e::f).
- Tags:
- Defined in module:
- Init.Tactics
interval_cases
interval_cases n searches for upper and lower bounds on a variable n,
and if bounds are found,
splits into separate cases for each possible value of n.
As an example, in
example (n : ℕ) (w₁ : n ≥ 3) (w₂ : n < 5) : n = 3 ∨ n = 4 := by
interval_cases n
all_goals simp
after interval_cases n, the goals are 3 = 3 ∨ 3 = 4 and 4 = 3 ∨ 4 = 4.
You can also explicitly specify a lower and upper bound to use,
as interval_cases using hl, hu.
The hypotheses should be in the form hl : a ≤ n and hu : n < b,
in which case interval_cases calls fin_cases on the resulting fact n ∈ Set.Ico a b.
You can specify a name h for the new hypothesis,
as interval_cases h : n or interval_cases h : n using hl, hu.
- Tags:
- Defined in module:
- Mathlib.Tactic.IntervalCases
intro
Introduces one or more hypotheses, optionally naming and/or pattern-matching them.
For each hypothesis to be introduced, the remaining main goal's target type must
be a let or function type.
introby itself introduces one anonymous hypothesis, which can be accessed by e.g.assumption. It is equivalent tointro _.intro x yintroduces two hypotheses and names them. Individual hypotheses can be anonymized via_, given a type ascription, or matched against a pattern:-- ... ⊢ α × β → ... intro (a, b) -- ..., a : α, b : β ⊢ ...intro rflis short forintro h; subst h, ifhis an equality where the left-hand or right-hand side is a variable.- Alternatively,
introcan be combined with pattern matching much likefun:intro | n + 1, 0 => tac | ...
- Tags:
- Defined in module:
- Init.Tactics
intros
intros repeatedly applies intro to introduce zero or more hypotheses
until the goal is no longer a binding expression
(i.e., a universal quantifier, function type, implication, or have/let),
without performing any definitional reductions (no unfolding, beta, eta, etc.).
The introduced hypotheses receive inaccessible (hygienic) names.
intros x y z is equivalent to intro x y z and exists only for historical reasons.
The intro tactic should be preferred in this case.
Properties and relations #
introssucceeds even when it introduces no hypotheses.repeat introis likeintros, but it performs definitional reductions to expose binders, and as such it may introduce more hypotheses thanintros.introsis equivalent tointro _ _ … _, with the fewest trailing_placeholders needed so that the goal is no longer a binding expression. The trailing introductions do not perform any definitional reductions.
Examples #
Implications:
example (p q : Prop) : p → q → p := by
intros
/- Tactic state
a✝¹ : p
a✝ : q
⊢ p -/
assumption
Let-bindings:
example : let n := 1; let k := 2; n + k = 3 := by
intros
/- n✝ : Nat := 1
k✝ : Nat := 2
⊢ n✝ + k✝ = 3 -/
rfl
Does not unfold definitions:
def AllEven (f : Nat → Nat) := ∀ n, f n % 2 = 0
example : ∀ (f : Nat → Nat), AllEven f → AllEven (fun k => f (k + 1)) := by
intros
/- Tactic state
f✝ : Nat → Nat
a✝ : AllEven f✝
⊢ AllEven fun k => f✝ (k + 1) -/
sorry
- Tags:
- Defined in module:
- Init.Tactics
introv
The tactic introv allows the user to automatically introduce the variables of a theorem and
explicitly name the non-dependent hypotheses.
Any dependent hypotheses are assigned their default names.
Examples:
example : ∀ a b : Nat, a = b → b = a := by
introv h,
exact h.symm
The state after introv h is
a b : ℕ,
h : a = b
⊢ b = a
example : ∀ a b : Nat, a = b → ∀ c, b = c → a = c := by
introv h₁ h₂,
exact h₁.trans h₂
The state after introv h₁ h₂ is
a b : ℕ,
h₁ : a = b,
c : ℕ,
h₂ : b = c
⊢ a = c
- Tags:
- Defined in module:
- Mathlib.Tactic.Basic
isBoundedDefault
Filters 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 isBoundedDefault in the statements,
in the form (hf : f.IsBounded (≥) := by isBoundedDefault).
- Tags:
- Defined in module:
- Mathlib.Order.Filter.IsBounded
iterate
iterate n tac runs tac exactly n times.
iterate tac runs tac repeatedly until failure.
iterate's argument is a tactic sequence,
so multiple tactics can be run using iterate n (tac₁; tac₂; ⋯) or
iterate n
tac₁
tac₂
⋯
- Tags:
- Defined in module:
- Init.TacticsExtra
left
Applies the first constructor when the goal is an inductive type with exactly two constructors, or fails otherwise.
example : True ∨ False := by
left
trivial
- Tags:
- Defined in module:
- Init.Tactics
let
The let tactic is for adding definitions to the local context of the main goal.
The definition can be unfolded, unlike definitions introduced by have.
let x : t := eadds the definitionx : t := eifeis a term of typet.let x := euses the type ofefort.let : t := eandlet := eusethisfor the name of the hypothesis.let pat := efor a patternpatis equivalent tomatch e with | pat => _, where_stands for the tactics that follow this one. It is convenient for types that let only one applicable constructor. For example, givenp : α × β × γ,let ⟨x, y, z⟩ := pproduces the local variablesx : α,y : β, andz : γ.- The syntax
let (eq := h) pat := eis equivalent tomatch h : e with | pat => _, which adds the equationh : e = patto the local context.
The tactic supports all the same syntax variants and options as the let term.
Properties and relations #
- Unlike
have, it is possible to unfold definitions introduced usinglet, using tactics such assimp,dsimp,unfold, andsubst. - The
clear_valuetactic turns aletdefinition into ahavedefinition after the fact. The tactic might fail if the local context depends on the value of the variable. - The
lettactic is preferred for data (non-propositions). - Sometimes
haveis used for non-propositions to ensure that the variable is never unfolded, which may be important for performance reasons.
- Tags:
- Defined in module:
- Init.Tactics
let rec
let rec f : t := e adds a recursive definition f to the current goal.
The syntax is the same as term-mode let rec.
The tactic supports all the same syntax variants and options as the let term.
- Tags:
- Defined in module:
- Init.Tactics
letI
letI behaves like let, but inlines the value instead of producing a let term.
- Tags:
- Defined in module:
- Init.Tactics
let_to_have
Transforms let expressions into have expressions when possible.
let_to_havetransformslets in the target.let_to_have at htransformslets in the given local hypothesis.
- Tags:
- Defined in module:
- Init.Tactics
lia
lia solves linear integer arithmetic goals.
It is a implemented as a thin wrapper around the grind tactic, enabling only the lia solver.
Please use grind instead if you need additional capabilities.
- Tags:
- Defined in module:
- Init.Grind.Tactics
lift
Lift an expression to another type.
- Usage:
'lift' expr 'to' expr ('using' expr)? ('with' id (id id?)?)?. - If
n : ℤandhn : n ≥ 0then the tacticlift n to ℕ using hncreates a new constant of typeℕ, also namednand replaces all occurrences of the old variable(n : ℤ)with↑n(wherenin the new variable). It will clearnfrom the context and try to clearhnfrom the context.- So for example the tactic
lift n to ℕ using hntransforms the goaln : ℤ, hn : n ≥ 0, h : P n ⊢ n = 3ton : ℕ, h : P ↑n ⊢ ↑n = 3(herePis some term of typeℤ → Prop).
- So for example the tactic
- The argument
using hnis optional, the tacticlift n to ℕdoes the same, but also creates a new subgoal thatn ≥ 0(wherenis the old variable). This subgoal will be placed at the top of the goal list.- So for example the tactic
lift n to ℕtransforms the goaln : ℤ, h : P n ⊢ n = 3to two goalsn : ℤ, h : P n ⊢ n ≥ 0andn : ℕ, h : P ↑n ⊢ ↑n = 3.
- So for example the tactic
- You can also use
lift n to ℕ using ewhereeis any expression of typen ≥ 0. - Use
lift n to ℕ with kto specify the name of the new variable. - Use
lift n to ℕ with k hkto also specify the name of the equality↑k = n. In this case,nwill remain in the context. You can userflfor the name ofhkto substitutenaway (i.e. the default behavior). - You can also use
lift e to ℕ with k hkwhereeis any expression of typeℤ. In this case, thehkwill always stay in the context, but it will be used to rewriteein all hypotheses and the target.- So for example the tactic
lift n + 3 to ℕ using hn with k hktransforms the goaln : ℤ, hn : n + 3 ≥ 0, h : P (n + 3) ⊢ n + 3 = 2 * nto the goaln : ℤ, k : ℕ, hk : ↑k = n + 3, h : P ↑k ⊢ ↑k = 2 * n.
- So for example the tactic
- The tactic
lift n to ℕ using hwill removehfrom the context. If you want to keep it, specify it again as the third argument towith, like this:lift n to ℕ using h with n rfl h. - More generally, this can lift an expression from
αtoβassuming that there is an instance ofCanLift α β. In this case the proof obligation is specified byCanLift.prf. - Given an instance
CanLift β γ, it can also liftα → βtoα → γ; more generally, givenβ : Π a : α, Type*,γ : Π a : α, Type*, and[Π a : α, CanLift (β a) (γ a)], it automatically generates an instanceCanLift (Π a, β a) (Π a, γ a).
lift is in some sense dual to the zify tactic. lift (z : ℤ) to ℕ will change the type of an
integer z (in the supertype) to ℕ (the subtype), given a proof that z ≥ 0;
propositions concerning z will still be over ℤ. zify changes propositions about ℕ (the
subtype) to propositions about ℤ (the supertype), without changing the type of any variable.
The norm_cast tactic can be used after lift to normalize introduced casts.
- Tags:
- Defined in module:
- Mathlib.Tactic.Lift
lift_lets
Lifts let and have expressions within a term as far out as possible.
It is like extract_lets +lift, but the top-level lets at the end of the procedure
are not extracted as local hypotheses.
lift_letslifts let expressions in the target.lift_lets at hlifts let expressions at the given local hypothesis.
For example,
example : (let x := 1; x) = 1 := by
lift_lets
-- ⊢ let x := 1; x = 1
...
- Tags:
- Defined in module:
- Init.Tactics
linarith
linarith attempts to find a contradiction between hypotheses that are linear (in)equalities.
Equivalently, it can prove a linear inequality by assuming its negation and proving False.
In theory, linarith should prove any goal that is true in the theory of linear arithmetic over
the rationals. While there is some special handling for non-dense orders like Nat and Int,
this tactic is not complete for these theories and will not prove every true goal. It will solve
goals over arbitrary types that instantiate CommRing, LinearOrder and IsStrictOrderedRing.
An example:
example (x y z : ℚ) (h1 : 2*x < 3*y) (h2 : -4*x + 2*z < 0)
(h3 : 12*y - 4* z < 0) : False := by
linarith
linarith will use all appropriate hypotheses and the negation of the goal, if applicable.
Disequality hypotheses require case splitting and are not normally considered
(see the splitNe option below).
linarith [t1, t2, t3] will additionally use proof terms t1, t2, t3.
linarith only [h1, h2, h3, t1, t2, t3] will use only the goal (if relevant), local hypotheses
h1, h2, h3, and proofs t1, t2, t3. It will ignore the rest of the local context.
linarith! will use a stronger reducibility setting to try to identify atoms. For example,
example (x : ℚ) : id x ≥ x := by
linarith
will fail, because linarith will not identify x and id x. linarith! will.
This can sometimes be expensive.
linarith (config := { .. }) takes a config object with five
optional arguments:
dischargerspecifies a tactic to be used for reducing an algebraic equation in the proof stage. The default isring. Other options includesimpfor basic problems.transparencycontrols how hardlinarithwill try to match atoms to each other. By default it will only unfoldreducibledefinitions.- If
splitHypothesesis true,linarithwill split conjunctions in the context into separate hypotheses. - If
splitNeistrue,linarithwill case split on disequality hypotheses. For a givenx ≠ yhypothesis,linarithis run with bothx < yandx > y, and so this runs linarith exponentially many times with respect to the number of disequality hypotheses. (falseby default.) - If
exfalsoisfalse,linarithwill fail when the goal is neither an inequality norFalse. (trueby default.) - If
minimizeisfalse,linarith?will report all hypotheses appearing in its initial proof without attempting to drop redundancies. (trueby default.) restrict_type(not yet implemented in mathlib4) will only use hypotheses that are inequalities overtp. This is useful if you have e.g. both integer- and rational-valued inequalities in the local context, which can sometimes confuse the tactic.
A variant, nlinarith, does some basic preprocessing to handle some nonlinear goals.
The option set_option trace.linarith true will trace certain intermediate stages of the linarith
routine.
- Tags:
- Defined in module:
- Mathlib.Tactic.Linarith.Frontend
linarith?
linarith? behaves like linarith but, on success, it prints a suggestion of
the form linarith only [...] listing a minimized set of hypotheses used in the
final proof. Use linarith?! for the higher-reducibility variant and set the
minimize flag in the configuration to control whether greedy minimization is
performed.
- Tags:
- Defined in module:
- Mathlib.Tactic.Linarith.Frontend
linear_combination
The linear_combination tactic attempts to prove an (in)equality goal by exhibiting it as a
specified linear combination of (in)equality hypotheses, or other (in)equality proof terms, modulo
(A) moving terms between the LHS and RHS of the (in)equalities, and (B) a normalization tactic
which by default is ring-normalization.
Example usage:
example {a b : ℚ} (h1 : a = 1) (h2 : b = 3) : (a + b) / 2 = 2 := by
linear_combination (h1 + h2) / 2
example {a b : ℚ} (h1 : a ≤ 1) (h2 : b ≤ 3) : (a + b) / 2 ≤ 2 := by
linear_combination (h1 + h2) / 2
example {a b : ℚ} : 2 * a * b ≤ a ^ 2 + b ^ 2 := by
linear_combination sq_nonneg (a - b)
example {x y z w : ℤ} (h₁ : x * z = y ^ 2) (h₂ : y * w = z ^ 2) :
z * (x * w - y * z) = 0 := by
linear_combination w * h₁ + y * h₂
example {x : ℚ} (h : x ≥ 5) : x ^ 2 > 2 * x + 11 := by
linear_combination (x + 3) * h
example {R : Type*} [CommRing R] {a b : R} (h : a = b) : a ^ 2 = b ^ 2 := by
linear_combination (a + b) * h
example {A : Type*} [AddCommGroup A]
{x y z : A} (h1 : x + y = 10 • z) (h2 : x - y = 6 • z) :
2 • x = 2 • (8 • z) := by
linear_combination (norm := abel) h1 + h2
example (x y : ℤ) (h1 : x * y + 2 * x = 1) (h2 : x = y) :
x * y = -2 * y + 1 := by
linear_combination (norm := ring_nf) -2 * h2
-- leaves goal `⊢ x * y + x * 2 - 1 = 0`
The input e in linear_combination e is a linear combination of proofs of (in)equalities,
given as a sum/difference of coefficients multiplied by expressions.
The coefficients may be arbitrary expressions (with nonnegativity constraints in the case of
inequalities).
The expressions can be arbitrary proof terms proving (in)equalities;
most commonly they are hypothesis names h1, h2, ....
The left and right sides of all the (in)equalities should have the same type α, and the
coefficients should also have type α. For full functionality α should be a commutative ring --
strictly speaking, a commutative semiring with "cancellative" addition (in the semiring case,
negation and subtraction will be handled "formally" as if operating in the enveloping ring). If a
nonstandard normalization is used (for example abel or skip), the tactic will work over types
α with less algebraic structure: for equalities, the minimum is instances of
[Add α] [IsRightCancelAdd α] together with instances of whatever operations are used in the tactic
call.
The variant linear_combination (norm := tac) e specifies explicitly the "normalization tactic"
tac to be run on the subgoal(s) after constructing the linear combination.
- The default normalization tactic is
ring1(for equalities) orMathlib.Tactic.Ring.prove{LE,LT}(for inequalities). These are finishing tactics: they close the goal or fail. - When working in algebraic categories other than commutative rings -- for example fields, abelian
groups, modules -- it is sometimes useful to use normalization tactics adapted to those categories
(
field_simp,abel,module). - To skip normalization entirely, use
skipas the normalization tactic. - The
linear_combinationtactic creates a linear combination by adding the provided (in)equalities together from left to right, so iftacis not invariant under commutation of additive expressions, then the order of the input hypotheses can matter.
The variant linear_combination (exp := n) e will take the goal to the nth power before
subtracting the combination e. In other words, if the goal is t1 = t2,
linear_combination (exp := n) e will change the goal to (t1 - t2)^n = 0 before proceeding as
above. This variant is implemented only for linear combinations of equalities (i.e., not for
inequalities).
- Tags:
- Defined in module:
- Mathlib.Tactic.LinearCombination
map_tacs
Assuming there are n goals, map_tacs [t1; t2; ...; tn] applies each ti to the respective
goal and leaves the resulting subgoals.
- Tags:
- Defined in module:
- Batteries.Tactic.SeqFocus
massumption
massumption is like assumption, but operating on a stateful Std.Do.SPred goal.
example (P Q : SPred σs) : Q ⊢ₛ P → Q := by
mintro _ _
massumption
- Tags:
- Defined in module:
- Init.Tactics
match
match performs case analysis on one or more expressions.
See Induction and Recursion.
The syntax for the match tactic is the same as term-mode match, except that
the match arms are tactics instead of expressions.
example (n : Nat) : n = n := by
match n with
| 0 => rfl
| i+1 => simp
- Tags:
- Defined in module:
- Lean.Parser.Tactic
match_scalars
Given a goal which is an equality in a type M (with M an AddCommMonoid), parse the LHS and
RHS of the goal as linear combinations of M-atoms over some semiring R, and reduce the goal to
the respective equalities of the R-coefficients of each atom.
For example, this produces the goal ⊢ a * 1 + b * 1 = (b + a) * 1:
example [AddCommMonoid M] [Semiring R] [Module R M] (a b : R) (x : M) :
a • x + b • x = (b + a) • x := by
match_scalars
This produces the two goals ⊢ a * (a * 1) + b * (b * 1) = 1 (from the x atom) and
⊢ a * -(b * 1) + b * (a * 1) = 0 (from the y atom):
example [AddCommGroup M] [Ring R] [Module R M] (a b : R) (x : M) :
a • (a • x - b • y) + (b • a • y + b • b • x) = x := by
match_scalars
This produces the goal ⊢ -2 * (a * 1) = a * (-2 * 1):
example [AddCommGroup M] [Ring R] [Module R M] (a : R) (x : M) :
-(2:R) • a • x = a • (-2:ℤ) • x := by
match_scalars
The scalar type for the goals produced by the match_scalars tactic is the largest scalar type
encountered; for example, if ℕ, ℚ and a characteristic-zero field K all occur as scalars, then
the goals produced are equalities in K. A variant of push_cast is used internally in
match_scalars to interpret scalars from the other types in this largest type.
If the set of scalar types encountered is not totally ordered (in the sense that for all rings R,
S encountered, it holds that either Algebra R S or Algebra S R), then the match_scalars
tactic fails.
- Tags:
- Defined in module:
- Mathlib.Tactic.Module
mcases
Like rcases, but operating on stateful Std.Do.SPred goals.
Example: Given a goal h : (P ∧ (Q ∨ R) ∧ (Q → R)) ⊢ₛ R,
mcases h with ⟨-, ⟨hq | hr⟩, hqr⟩ will yield two goals:
(hq : Q, hqr : Q → R) ⊢ₛ R and (hr : R) ⊢ₛ R.
That is, mcases h with pat has the following semantics, based on pat:
pat=□h'renameshtoh'in the stateful context, regardless of whetherhis purepat=⌜h'⌝introducesh' : φto the pure local context ifh : ⌜φ⌝(c.f.Lean.Elab.Tactic.Do.ProofMode.IsPure)pat=h'is likepat=⌜h'⌝ifhis pure (c.f.Lean.Elab.Tactic.Do.ProofMode.IsPure), otherwise it is likepat=□h'.pat=_renameshto an inaccessible namepat=-discardsh⟨pat₁, pat₂⟩matches on conjunctions and existential quantifiers and recurses viapat₁andpat₂.⟨pat₁ | pat₂⟩matches on disjunctions, matching the left alternative viapat₁and the right alternative viapat₂.
- Tags:
- Defined in module:
- Init.Tactics
mclear
mclear is like clear, but operating on a stateful Std.Do.SPred goal.
example (P Q : SPred σs) : P ⊢ₛ Q → Q := by
mintro HP
mintro HQ
mclear HP
mexact HQ
- Tags:
- Defined in module:
- Init.Tactics
mconstructor
mconstructor is like constructor, but operating on a stateful Std.Do.SPred goal.
example (Q : SPred σs) : Q ⊢ₛ Q ∧ Q := by
mintro HQ
mconstructor <;> mexact HQ
- Tags:
- Defined in module:
- Init.Tactics
measurability
The tactic measurability solves goals of the form Measurable f, AEMeasurable f,
StronglyMeasurable f, AEStronglyMeasurable f μ, or MeasurableSet s by applying lemmas tagged
with the measurability user attribute.
Note that measurability uses fun_prop for solving measurability of functions, so statements
about Measurable, AEMeasurable, StronglyMeasurable and AEStronglyMeasurable should be tagged
with fun_prop rather that measurability. The measurability attribute is equivalent to
fun_prop in these cases for backward compatibility with the earlier implementation.
- Tags:
- Defined in module:
- Mathlib.Tactic.Measurability
measurability?
The tactic measurability? solves goals of the form Measurable f, AEMeasurable f,
StronglyMeasurable f, AEStronglyMeasurable f μ, or MeasurableSet s by applying lemmas tagged
with the measurability user attribute, and suggests a faster proof script that can be substituted
for the tactic call in case of success.
- Tags:
- Defined in module:
- Mathlib.Tactic.Measurability
mexact
mexact is like exact, but operating on a stateful Std.Do.SPred goal.
example (Q : SPred σs) : Q ⊢ₛ Q := by
mstart
mintro HQ
mexact HQ
- Tags:
- Defined in module:
- Init.Tactics
mexfalso
mexfalso is like exfalso, but operating on a stateful Std.Do.SPred goal.
example (P : SPred σs) : ⌜False⌝ ⊢ₛ P := by
mintro HP
mexfalso
mexact HP
- Tags:
- Defined in module:
- Init.Tactics
mexists
mexists is like exists, but operating on a stateful Std.Do.SPred goal.
example (ψ : Nat → SPred σs) : ψ 42 ⊢ₛ ∃ x, ψ x := by
mintro H
mexists 42
- Tags:
- Defined in module:
- Init.Tactics
mfld_set_tac
A very basic tactic to show that sets showing up in manifolds coincide or are included in one another.
- Tags:
- Defined in module:
- Mathlib.Logic.Equiv.PartialEquiv
mframe
mframe infers which hypotheses from the stateful context can be moved into the pure context.
This is useful because pure hypotheses "survive" the next application of modus ponens
(Std.Do.SPred.mp) and transitivity (Std.Do.SPred.entails.trans).
It is used as part of the mspec tactic.
example (P Q : SPred σs) : ⊢ₛ ⌜p⌝ ∧ Q ∧ ⌜q⌝ ∧ ⌜r⌝ ∧ P ∧ ⌜s⌝ ∧ ⌜t⌝ → Q := by
mintro _
mframe
/- `h : p ∧ q ∧ r ∧ s ∧ t` in the pure context -/
mcases h with hP
mexact h
- Tags:
- Defined in module:
- Init.Tactics
mhave
mhave is like have, but operating on a stateful Std.Do.SPred goal.
example (P Q : SPred σs) : P ⊢ₛ (P → Q) → Q := by
mintro HP HPQ
mhave HQ : Q := by mspecialize HPQ HP; mexact HPQ
mexact HQ
- Tags:
- Defined in module:
- Init.Tactics
mintro
Like intro, but introducing stateful hypotheses into the stateful context of the Std.Do.SPred
proof mode.
That is, given a stateful goal (hᵢ : Hᵢ)* ⊢ₛ P → T, mintro h transforms
into (hᵢ : Hᵢ)*, (h : P) ⊢ₛ T.
Furthermore, mintro ∀s is like intro s, but preserves the stateful goal.
That is, mintro ∀s brings the topmost state variable s:σ in scope and transforms
(hᵢ : Hᵢ)* ⊢ₛ T (where the entailment is in Std.Do.SPred (σ::σs)) into
(hᵢ : Hᵢ s)* ⊢ₛ T s (where the entailment is in Std.Do.SPred σs).
Beyond that, mintro supports the full syntax of mcases patterns
(mintro pat = (mintro h; mcases h with pat), and can perform multiple
introductions in sequence.
- Tags:
- Defined in module:
- Init.Tactics
mleave
Leaves the stateful proof mode of Std.Do.SPred, tries to eta-expand through all definitions
related to the logic of the Std.Do.SPred and gently simplifies the resulting pure Lean
proposition. This is often the right thing to do after mvcgen in order for automation to prove
the goal.
- Tags:
- Defined in module:
- Init.Tactics
mleft
mleft is like left, but operating on a stateful Std.Do.SPred goal.
example (P Q : SPred σs) : P ⊢ₛ P ∨ Q := by
mintro HP
mleft
mexact HP
- Tags:
- Defined in module:
- Init.Tactics
module
Given a goal which is an equality in a type M (with M an AddCommMonoid), parse the LHS and
RHS of the goal as linear combinations of M-atoms over some commutative semiring R, and prove
the goal by checking that the LHS- and RHS-coefficients of each atom are the same up to
ring-normalization in R.
(If the proofs of coefficient-wise equality will require more reasoning than just
ring-normalization, use the tactic match_scalars instead, and then prove coefficient-wise equality
by hand.)
Example uses of the module tactic:
example [AddCommMonoid M] [CommSemiring R] [Module R M] (a b : R) (x : M) :
a • x + b • x = (b + a) • x := by
module
example [AddCommMonoid M] [Field K] [CharZero K] [Module K M] (x : M) :
(2:K)⁻¹ • x + (3:K)⁻¹ • x + (6:K)⁻¹ • x = x := by
module
example [AddCommGroup M] [CommRing R] [Module R M] (a : R) (v w : M) :
(1 + a ^ 2) • (v + w) - a • (a • v - w) = v + (1 + a + a ^ 2) • w := by
module
example [AddCommGroup M] [CommRing R] [Module R M] (a b μ ν : R) (x y : M) :
(μ - ν) • a • x = (a • μ • x + b • ν • y) - ν • (a • x + b • y) := by
module
- Tags:
- Defined in module:
- Mathlib.Tactic.Module
monicity
monicity tries to solve a goal of the form Monic f.
It converts the goal into a goal of the form natDegree f ≤ n and one of the form f.coeff n = 1
and calls compute_degree on those two goals.
The variant monicity! starts like monicity, but calls compute_degree! on the two side-goals.
- Tags:
- Defined in module:
- Mathlib.Tactic.ComputeDegree
mpure
mpure moves a pure hypothesis from the stateful context into the pure context.
example (Q : SPred σs) (ψ : φ → ⊢ₛ Q): ⌜φ⌝ ⊢ₛ Q := by
mintro Hφ
mpure Hφ
mexact (ψ Hφ)
- Tags:
- Defined in module:
- Init.Tactics
mpure_intro
mpure_intro operates on a stateful Std.Do.SPred goal of the form P ⊢ₛ ⌜φ⌝.
It leaves the stateful proof mode (thereby discarding P), leaving the regular goal φ.
theorem simple : ⊢ₛ (⌜True⌝ : SPred σs) := by
mpure_intro
exact True.intro
- Tags:
- Defined in module:
- Init.Tactics
mrefine
Like refine, but operating on stateful Std.Do.SPred goals.
example (P Q R : SPred σs) : (P ∧ Q ∧ R) ⊢ₛ P ∧ R := by
mintro ⟨HP, HQ, HR⟩
mrefine ⟨HP, HR⟩
example (ψ : Nat → SPred σs) : ψ 42 ⊢ₛ ∃ x, ψ x := by
mintro H
mrefine ⟨⌜42⌝, H⟩
- Tags:
- Defined in module:
- Init.Tactics
mrename_i
mrename_i is like rename_i, but names inaccessible stateful hypotheses in a Std.Do.SPred goal.
- Tags:
- Defined in module:
- Init.Tactics
mreplace
mreplace is like replace, but operating on a stateful Std.Do.SPred goal.
example (P Q : SPred σs) : P ⊢ₛ (P → Q) → Q := by
mintro HP HPQ
mreplace HPQ : Q := by mspecialize HPQ HP; mexact HPQ
mexact HPQ
- Tags:
- Defined in module:
- Init.Tactics
mrevert
mrevert is like revert, but operating on a stateful Std.Do.SPred goal.
example (P Q R : SPred σs) : P ∧ Q ∧ R ⊢ₛ P → R := by
mintro ⟨HP, HQ, HR⟩
mrevert HR
mrevert HP
mintro HP'
mintro HR'
mexact HR'
- Tags:
- Defined in module:
- Init.Tactics
mright
mright is like right, but operating on a stateful Std.Do.SPred goal.
example (P Q : SPred σs) : P ⊢ₛ Q ∨ P := by
mintro HP
mright
mexact HP
- Tags:
- Defined in module:
- Init.Tactics
mspec
mspec is an apply-like tactic that applies a Hoare triple specification to the target of the
stateful goal.
Given a stateful goal H ⊢ₛ wp⟦prog⟧ Q', mspec foo_spec will instantiate
foo_spec : ... → ⦃P⦄ foo ⦃Q⦄, match foo against prog and produce subgoals for
the verification conditions ?pre : H ⊢ₛ P and ?post : Q ⊢ₚ Q'.
- If
prog = x >>= f, thenmspec Specs.bindis tried first so thatfoois matched againstxinstead. Tacticmspec_no_binddoes not attempt to do this decomposition. - If
?preor?postfollow by.rfl, then they are discharged automatically. ?postis automatically simplified into constituent⊢ₛentailments on success and failure continuations.?preand?post.*goals introduce their stateful hypothesis under an inaccessible name. You can give it a name with themrename_itactic.- Any uninstantiated MVar arising from instantiation of
foo_specbecomes a new subgoal. - If the target of the stateful goal looks like
fun s => _thenmspecwill firstmintro ∀s. - If
Phas schematic variables that can be instantiated by doingmintro ∀s, for examplefoo_spec : ∀(n:Nat), ⦃fun s => ⌜n = s⌝⦄ foo ⦃Q⦄, thenmspecwill domintro ∀sfirst to instantiaten = s. - Right before applying the spec, the
mframetactic is used, which has the following effect: Any hypothesisHᵢin the goalh₁:H₁, h₂:H₂, ..., hₙ:Hₙ ⊢ₛ Tthat is pure (i.e., equivalent to some⌜φᵢ⌝) will be moved into the pure context ashᵢ:φᵢ.
Additionally, mspec can be used without arguments or with a term argument:
mspecwithout argument will try and look up a spec forxregistered with@[spec].mspec (foo_spec blah ?bleh)will elaborate its argument as a term with expected type⦃?P⦄ x ⦃?Q⦄and introduce?blehas a subgoal. This is useful to pass an invariant to e.g.,Specs.forIn_listand leave the inductive step as a hole.
- Tags:
- Defined in module:
- Init.Tactics
mspec_no_bind
mspec_no_simp $spec first tries to decompose Bind.binds before applying $spec.
This variant of mspec_no_simp does not; mspec_no_bind $spec is defined as
try with_reducible mspec_no_bind Std.Do.Spec.bind
mspec_no_bind $spec
- Tags:
- Defined in module:
- Std.Tactic.Do.Syntax
mspec_no_simp
Like mspec, but does not attempt slight simplification and closing of trivial sub-goals.
mspec $spec is roughly (the set of simp lemmas below might not be up to date)
mspec_no_simp $spec
all_goals
((try simp only [SPred.true_intro_simp, SPred.apply_pure]);
(try mpure_intro; trivial))
- Tags:
- Defined in module:
- Std.Tactic.Do.Syntax
mspecialize
mspecialize is like specialize, but operating on a stateful Std.Do.SPred goal.
It specializes a hypothesis from the stateful context with hypotheses from either the pure
or stateful context or pure terms.
example (P Q : SPred σs) : P ⊢ₛ (P → Q) → Q := by
mintro HP HPQ
mspecialize HPQ HP
mexact HPQ
example (y : Nat) (P Q : SPred σs) (Ψ : Nat → SPred σs) (hP : ⊢ₛ P) : ⊢ₛ Q → (∀ x, P → Q → Ψ x) → Ψ (y + 1) := by
mintro HQ HΨ
mspecialize HΨ (y + 1) hP HQ
mexact HΨ
- Tags:
- Defined in module:
- Init.Tactics
mspecialize_pure
mspecialize_pure is like mspecialize, but it specializes a hypothesis from the
pure context with hypotheses from either the pure or stateful context or pure terms.
example (y : Nat) (P Q : SPred σs) (Ψ : Nat → SPred σs) (hP : ⊢ₛ P) (hΨ : ∀ x, ⊢ₛ P → Q → Ψ x) : ⊢ₛ Q → Ψ (y + 1) := by
mintro HQ
mspecialize_pure (hΨ (y + 1)) hP HQ => HΨ
mexact HΨ
- Tags:
- Defined in module:
- Init.Tactics
mstart
Start the stateful proof mode of Std.Do.SPred.
This will transform a stateful goal of the form H ⊢ₛ T into ⊢ₛ H → T
upon which mintro can be used to re-introduce H and give it a name.
It is often more convenient to use mintro directly, which will
try mstart automatically if necessary.
- Tags:
- Defined in module:
- Init.Tactics
mstop
Stops the stateful proof mode of Std.Do.SPred.
This will simply forget all the names given to stateful hypotheses and pretty-print
a bit differently.
- Tags:
- Defined in module:
- Init.Tactics
mvcgen
mvcgen will break down a Hoare triple proof goal like ⦃P⦄ prog ⦃Q⦄ into verification conditions,
provided that all functions used in prog have specifications registered with @[spec].
Verification Conditions and specifications #
A verification condition is an entailment in the stateful logic of Std.Do.SPred
in which the original program prog no longer occurs.
Verification conditions are introduced by the mspec tactic; see the mspec tactic for what they
look like.
When there's no applicable mspec spec, mvcgen will try and rewrite an application
prog = f a b c with the simp set registered via @[spec].
Features #
When used like mvcgen +noLetElim [foo_spec, bar_def, instBEqFloat], mvcgen will additionally
- add a Hoare triple specification
foo_spec : ... → ⦃P⦄ foo ... ⦃Q⦄tospecset for a functionfoooccurring inprog, - unfold a definition
def bar_def ... := ...inprog, - unfold any method of the
instBEqFloat : BEq Floatinstance inprog. - it will no longer substitute away
let-expressions that occur at most once inP,Qorprog.
Config options #
+noLetElim is just one config option of many. Check out Lean.Elab.Tactic.Do.VCGen.Config for all
options. Of particular note is stepLimit = some 42, which is useful for bisecting bugs in
mvcgen and tracing its execution.
Extended syntax #
Often, mvcgen will be used like this:
mvcgen [...]
case inv1 => by exact I1
case inv2 => by exact I2
all_goals (mleave; try grind)
There is special syntax for this:
mvcgen [...] invariants
· I1
· I2
with grind
When I1 and I2 need to refer to inaccessibles (mvcgen will introduce a lot of them for program
variables), you can use case label syntax:
mvcgen [...] invariants
| inv1 _ acc _ => I1 acc
| _ => I2
with grind
This is more convenient than the equivalent · by rename_i _ acc _; exact I1 acc.
Invariant suggestions #
mvcgen will suggest invariants for you if you use the invariants? keyword.
mvcgen [...] invariants?
This is useful if you do not recall the exact syntax to construct invariants. Furthermore, it will suggest a concrete invariant encoding "this holds at the start of the loop and this must hold at the end of the loop" by looking at the corresponding VCs. Although the suggested invariant is a good starting point, it is too strong and requires users to interpolate it such that the inductive step can be proved. Example:
def mySum (l : List Nat) : Nat := Id.run do
let mut acc := 0
for x in l do
acc := acc + x
return acc
/--
info: Try this:
invariants
· ⇓⟨xs, letMuts⟩ => ⌜xs.prefix = [] ∧ letMuts = 0 ∨ xs.suffix = [] ∧ letMuts = l.sum⌝
-/
#guard_msgs (info) in
theorem mySum_suggest_invariant (l : List Nat) : mySum l = l.sum := by
generalize h : mySum l = r
apply Id.of_wp_run_eq h
mvcgen invariants?
all_goals admit
- Tags:
- Defined in module:
- Init.Tactics
mvcgen_trivial
mvcgen_trivial is the tactic automatically called by mvcgen to discharge VCs.
It tries to discharge the VC by applying (try mpure_intro); trivial and otherwise delegates to
mvcgen_trivial_extensible.
Users are encouraged to extend mvcgen_trivial_extensible instead of this tactic in order not to
override the default (try mpure_intro); trivial behavior.
- Tags:
- Defined in module:
- Std.Tactic.Do.Syntax
mvcgen_trivial_extensible
This tactic has no documentation.
- Tags:
- Defined in module:
- Std.Tactic.Do.Syntax
native_decide
native_decide is a synonym for decide +native.
It will attempt to prove a goal of type p by synthesizing an instance
of Decidable p and then evaluating it to isTrue ... Unlike decide, this
uses #eval to evaluate the decidability instance.
This should be used with care because it adds the entire lean compiler to the trusted
part, and the axiom Lean.ofReduceBool will show up in #print axioms for theorems using
this method or anything that transitively depends on them. Nevertheless, because it is
compiled, this can be significantly more efficient than using decide, and for very
large computations this is one way to run external programs and trust the result.
example : (List.range 1000).length = 1000 := by native_decide
- Tags:
- Defined in module:
- Init.Tactics
next
next => tac focuses on the next goal and solves it using tac, or else fails.
next x₁ ... xₙ => tac additionally renames the n most recent hypotheses with
inaccessible names to the given names.
- Tags:
- Defined in module:
- Init.Tactics
nlinarith
An extension of linarith with some preprocessing to allow it to solve some nonlinear arithmetic
problems. (Based on Coq's nra tactic.) See linarith for the available syntax of options,
which are inherited by nlinarith; that is, nlinarith! and nlinarith only [h1, h2] all work as
in linarith. The preprocessing is as follows:
- For every subterm
a ^ 2ora * ain a hypothesis or the goal, the assumption0 ≤ a ^ 2or0 ≤ a * ais added to the context. - For every pair of hypotheses
a1 R1 b1,a2 R2 b2in the context,R1, R2 ∈ {<, ≤, =}, the assumption0 R' (b1 - a1) * (b2 - a2)is added to the context (non-recursively), whereR ∈ {<, ≤, =}is the appropriate comparison derived fromR1, R2.
- Tags:
- Defined in module:
- Mathlib.Tactic.Linarith.Frontend
nofun
The tactic nofun is shorthand for exact nofun: it introduces the assumptions, then performs an
empty pattern match, closing the goal if the introduced pattern is impossible.
- Tags:
- Defined in module:
- Init.Tactics
noncomm_ring
A tactic for simplifying identities in not-necessarily-commutative rings.
An example:
example {R : Type*} [Ring R] (a b c : R) : a * (b + c + c - b) = 2 * a * c := by
noncomm_ring
You can use noncomm_ring [h] to also simplify using h.
- Tags:
- Defined in module:
- Mathlib.Tactic.NoncommRing
nontriviality
Attempts to generate a Nontrivial α hypothesis.
The tactic first checks to see that there is not already a Nontrivial α instance
before trying to synthesize one using other techniques.
If the goal is an (in)equality, the type α is inferred from the goal.
Otherwise, the type needs to be specified in the tactic invocation, as nontriviality α.
The nontriviality tactic will first look for strict inequalities amongst the hypotheses,
and use these to derive the Nontrivial instance directly.
Otherwise, it will perform a case split on Subsingleton α ∨ Nontrivial α, and attempt to discharge
the Subsingleton goal using simp [h₁, h₂, ..., hₙ, nontriviality], where [h₁, h₂, ..., hₙ] is
a list of additional simp lemmas that can be passed to nontriviality using the syntax
nontriviality α using h₁, h₂, ..., hₙ.
example {R : Type} [OrderedRing R] {a : R} (h : 0 < a) : 0 < a := by
nontriviality -- There is now a `Nontrivial R` hypothesis available.
assumption
example {R : Type} [CommRing R] {r s : R} : r * s = s * r := by
nontriviality -- There is now a `Nontrivial R` hypothesis available.
apply mul_comm
example {R : Type} [OrderedRing R] {a : R} (h : 0 < a) : (2 : ℕ) ∣ 4 := by
nontriviality R -- there is now a `Nontrivial R` hypothesis available.
dec_trivial
def myeq {α : Type} (a b : α) : Prop := a = b
example {α : Type} (a b : α) (h : a = b) : myeq a b := by
success_if_fail nontriviality α -- Fails
nontriviality α using myeq -- There is now a `Nontrivial α` hypothesis available
assumption
- Tags:
- Defined in module:
- Mathlib.Tactic.Nontriviality.Core
norm_cast
The norm_cast family of tactics is used to normalize certain coercions (casts) in expressions.
norm_castnormalizes casts in the target.norm_cast at hnormalizes casts in hypothesish.
The tactic is basically a version of simp with a specific set of lemmas to move casts
upwards in the expression.
Therefore even in situations where non-terminal simp calls are discouraged (because of fragility),
norm_cast is considered to be safe.
It also has special handling of numerals.
For instance, given an assumption
a b : ℤ
h : ↑a + ↑b < (10 : ℚ)
writing norm_cast at h will turn h into
h : a + b < 10
There are also variants of basic tactics that use norm_cast to normalize expressions during
their operation, to make them more flexible about the expressions they accept
(we say that it is a tactic modulo the effects of norm_cast):
exact_mod_castforexactandapply_mod_castforapply. Writingexact_mod_cast handapply_mod_cast hwill normalize casts in the goal andhbefore usingexact horapply h.rw_mod_castforrw. It appliesnorm_castbetween rewrites.assumption_mod_castforassumption. This is effectivelynorm_cast at *; assumption, but more efficient. It normalizes casts in the goal and, for every hypothesishin the context, it will try to normalize casts inhand useexact h.
See also push_cast, which moves casts inwards rather than lifting them outwards.
- Tags:
- Defined in module:
- Init.Tactics
norm_cast0
Implementation of norm_cast (the full norm_cast calls trivial afterwards).
- Tags:
- Defined in module:
- Init.Tactics
norm_num
norm_num normalizes numerical expressions in the goal. By default, it supports the operations
+ - * / ⁻¹ ^ and % over types with (at least) an AddMonoidWithOne instance, such as
ℕ, ℤ, ℚ, ℝ, ℂ. In addition to evaluating numerical expressions, norm_num will use simp
to simplify the goal. If the goal has the form A = B, A ≠ B, A < B or A ≤ B, where A and
B are numerical expressions, norm_num will try to close it. It also has a relatively simple
primality prover.
This tactic is extensible. Extensions can allow norm_num to evaluate more kinds of expressions, or
to prove more kinds of propositions. See the @[norm_num] attribute for further information on
extending norm_num.
norm_num at lnormalizes at location(s)l.norm_num [h1, ...]adds the argumentsh1, ...to thesimpset in addition to the defaultsimpset. All options forsimparguments are supported, in particular←,↑and↓.norm_num onlydoes not use the defaultsimpset for simplification.norm_num only [h1, ...]uses only the argumentsh1, ...in addition to the routines tagged@[norm_num].norm_num onlystill performs post-processing steps, likesimp only, usenorm_num1if you exclusively want to normalize numerical expressions.norm_num (config := cfg)usescfgas configuration forsimpcalls (see thesimptactic for further details).
Examples:
example : 43 ≤ 74 + (33 : ℤ) := by norm_num
example : ¬ (7-2)/(2*3) ≥ (1:ℝ) + 2/(3^2) := by norm_num
- Tags:
- Defined in module:
- Mathlib.Tactic.NormNum.Core
norm_num1
norm_num1 normalizes numerical expressions in the goal. It is a basic version of norm_num
that does not call simp.
By default, it supports the operations + - * / ⁻¹ ^ and % over types with (at least)
an AddMonoidWithOne instance, such as ℕ, ℤ, ℚ, ℝ, ℂ. If the goal has the form A = B,
A ≠ B, A < B or A ≤ B, where A and B are numerical expressions, norm_num1 will try to
close it. It also has a relatively simple primality prover.
:e
This tactic is extensible. Extensions can allow norm_num1 to evaluate more kinds of expressions,
or to prove more kinds of propositions. See the @[norm_num] attribute for further information on
extending norm_num1.
norm_num1 at lnormalizes at location(s)l.
Examples:
example : 43 ≤ 74 + (33 : ℤ) := by norm_num1
example : ¬ (7-2)/(2*3) ≥ (1:ℝ) + 2/(3^2) := by norm_num1
- Tags:
- Defined in module:
- Mathlib.Tactic.NormNum.Core
nth_grewrite
nth_grewrite is just like nth_rewrite, but for grewrite.
- Tags:
- Defined in module:
- Mathlib.Tactic.GRewrite.Elab
nth_rewrite
nth_rewrite is a variant of rewrite that only changes the n₁, ..., nₖᵗʰ occurrence of
the expression to be rewritten. nth_rewrite n₁ ... nₖ [eq₁, eq₂,..., eqₘ] will rewrite the
n₁, ..., nₖᵗʰ occurrence of each of the m equalities eqᵢin that order. Occurrences are
counted beginning with 1 in order of precedence.
For example,
example (h : a = 1) : a + a + a + a + a = 5 := by
nth_rewrite 2 3 [h]
/-
a: ℕ
h: a = 1
⊢ a + 1 + 1 + a + a = 5
-/
Notice that the second and third occurrences of a from the left have been rewritten by
nth_rewrite.
To understand the importance of order of precedence, consider the example below
example (a b c : Nat) : (a + b) + c = (b + a) + c := by
nth_rewrite 2 [Nat.add_comm] -- ⊢ (b + a) + c = (b + a) + c
Here, although the occurrence parameter is 2, (a + b) is rewritten to (b + a). This happens
because in order of precedence, the first occurrence of _ + _ is the one that adds a + b to c.
The occurrence in a + b counts as the second occurrence.
If a term t is introduced by rewriting with eqᵢ, then this instance of t will be counted as an
occurrence of t for all subsequent rewrites of t with eqⱼ for j > i. This behaviour is
illustrated by the example below
example (h : a = a + b) : a + a + a + a + a = 0 := by
nth_rewrite 3 [h, h]
/-
a b: ℕ
h: a = a + b
⊢ a + a + (a + b + b) + a + a = 0
-/
Here, the first nth_rewrite with h introduces an additional occurrence of a in the goal.
That is, the goal state after the first rewrite looks like below
/-
a b: ℕ
h: a = a + b
⊢ a + a + (a + b) + a + a = 0
-/
This new instance of a also turns out to be the third occurrence of a. Therefore,
the next nth_rewrite with h rewrites this a.
- Tags:
- Defined in module:
- Mathlib.Tactic.NthRewrite
nth_rw
nth_rw is a variant of rw that only changes the n₁, ..., nₖᵗʰ occurrence of the expression
to be rewritten. Like rw, and unlike nth_rewrite, it will try to close the goal by trying rfl
afterwards. nth_rw n₁ ... nₖ [eq₁, eq₂,..., eqₘ] will rewrite the n₁, ..., nₖᵗʰ occurrence of
each of the m equalities eqᵢin that order. Occurrences are counted beginning with 1 in
order of precedence. For example,
example (h : a = 1) : a + a + a + a + a = 5 := by
nth_rw 2 3 [h]
/-
a: ℕ
h: a = 1
⊢ a + 1 + 1 + a + a = 5
-/
Notice that the second and third occurrences of a from the left have been rewritten by
nth_rw.
To understand the importance of order of precedence, consider the example below
example (a b c : Nat) : (a + b) + c = (b + a) + c := by
nth_rewrite 2 [Nat.add_comm] -- ⊢ (b + a) + c = (b + a) + c
Here, although the occurrence parameter is 2, (a + b) is rewritten to (b + a). This happens
because in order of precedence, the first occurrence of _ + _ is the one that adds a + b to c.
The occurrence in a + b counts as the second occurrence.
If a term t is introduced by rewriting with eqᵢ, then this instance of t will be counted as an
occurrence of t for all subsequent rewrites of t with eqⱼ for j > i. This behaviour is
illustrated by the example below
example (h : a = a + b) : a + a + a + a + a = 0 := by
nth_rw 3 [h, h]
/-
a b: ℕ
h: a = a + b
⊢ a + a + (a + b + b) + a + a = 0
-/
Here, the first nth_rw with h introduces an additional occurrence of a in the goal. That is,
the goal state after the first rewrite looks like below
/-
a b: ℕ
h: a = a + b
⊢ a + a + (a + b) + a + a = 0
-/
This new instance of a also turns out to be the third occurrence of a. Therefore,
the next nth_rw with h rewrites this a.
Further, nth_rw will close the remaining goal with rfl if possible.
- Tags:
- Defined in module:
- Mathlib.Tactic.NthRewrite
observe
observe hp : p asserts the proposition p as a hypothesis named hp, and tries to prove it
using exact?.
If no proof is found, the tactic fails.
In other words, this tactic is equivalent to have hp : p := by exact?.
observe : puses the namethisfor the new hypothesis.observe? hp : pwill emit a trace message of the formhave hp : p := proof_term. This may be particularly useful to speed up proofs.
- Tags:
- Defined in module:
- Mathlib.Tactic.Observe
obtain
The obtain tactic is a combination of have and rcases. See rcases for
a description of supported patterns.
obtain ⟨patt⟩ : type := proof
is equivalent to
have h : type := proof
rcases h with ⟨patt⟩
If ⟨patt⟩ is omitted, rcases will try to infer the pattern.
If type is omitted, := proof is required.
- Tags:
- Defined in module:
- Init.RCases
omega
The omega tactic, for resolving integer and natural linear arithmetic problems.
It is not yet a full decision procedure (no "dark" or "grey" shadows), but should be effective on many problems.
We handle hypotheses of the form x = y, x < y, x ≤ y, and k ∣ x for x y in Nat or Int
(and k a literal), along with negations of these statements.
We decompose the sides of the inequalities as linear combinations of atoms.
If we encounter x / k or x % k for literal integers k we introduce new auxiliary variables
and the relevant inequalities.
On the first pass, we do not perform case splits on natural subtraction.
If omega fails, we recursively perform a case split on
a natural subtraction appearing in a hypothesis, and try again.
The options
omega +splitDisjunctions +splitNatSub +splitNatAbs +splitMinMax
can be used to:
splitDisjunctions: split any disjunctions found in the context, if the problem is not otherwise solvable.splitNatSub: for each appearance of((a - b : Nat) : Int), split ona ≤ bif necessary.splitNatAbs: for each appearance ofInt.natAbs a, split on0 ≤ aif necessary.splitMinMax: for each occurrence ofmin a b, split onmin a b = a ∨ min a b = bCurrently, all of these are on by default.
- Tags:
- Defined in module:
- Init.Tactics
on_goal
on_goal n => tacSeq creates a block scope for the n-th goal and tries the sequence
of tactics tacSeq on it.
on_goal -n => tacSeq does the same, but the n-th goal is chosen by counting from the
bottom.
The goal is not required to be solved and any resulting subgoals are inserted back into the list of goals, replacing the chosen goal.
- Tags:
- Defined in module:
- Batteries.Tactic.PermuteGoals
open
open Foo in tacs (the tactic) acts like open Foo at command level,
but it opens a namespace only within the tactics tacs.
- Tags:
- Defined in module:
- Lean.Parser.Command
order
A finishing tactic for solving goals in arbitrary Preorder, PartialOrder,
or LinearOrder. Supports ⊤, ⊥, and lattice operations.
- Tags:
- Defined in module:
- Mathlib.Tactic.Order
order_core
order_core is the part of the order tactic that tries to find a contradiction.
- Tags:
- Defined in module:
- Mathlib.Tactic.Order
peel
Peels matching quantifiers off of a given term and the goal and introduces the relevant variables.
peel epeels all quantifiers (at reducible transparency), usingthisfor the name of the peeled hypothesis.peel e with hispeel ebut names the peeled hypothesish. Ifhis_then usesthisfor the name of the peeled hypothesis.peel n epeelsnquantifiers (at default transparency).peel n e with x y z ... hpeelsnquantifiers, names the peeled hypothesish, and usesx,y,z, and so on to name the introduced variables; these names may be_. Ifhis_then usesthisfor the name of the peeled hypothesis. The length of the list of variables does not need to equaln.peel e with x₁ ... xₙ hispeel n e with x₁ ... xₙ h.
There are also variants that apply to an iff in the goal:
peel npeelsnquantifiers in an iff.peel with x₁ ... xₙpeelsnquantifiers in an iff and names them.
Given p q : ℕ → Prop, h : ∀ x, p x, and a goal ⊢ : ∀ x, q x, the tactic peel h with x h'
will introduce x : ℕ, h' : p x into the context and the new goal will be ⊢ q x. This works
with ∃, as well as ∀ᶠ and ∃ᶠ, and it can even be applied to a sequence of quantifiers. Note
that this is a logically weaker setup, so using this tactic is not always feasible.
For a more complex example, given a hypothesis and a goal:
h : ∀ ε > (0 : ℝ), ∃ N : ℕ, ∀ n ≥ N, 1 / (n + 1 : ℝ) < ε
⊢ ∀ ε > (0 : ℝ), ∃ N : ℕ, ∀ n ≥ N, 1 / (n + 1 : ℝ) ≤ ε
(which differ only in </≤), applying peel h with ε hε N n hn h_peel will yield a tactic state:
h : ∀ ε > (0 : ℝ), ∃ N : ℕ, ∀ n ≥ N, 1 / (n + 1 : ℝ) < ε
ε : ℝ
hε : 0 < ε
N n : ℕ
hn : N ≤ n
h_peel : 1 / (n + 1 : ℝ) < ε
⊢ 1 / (n + 1 : ℝ) ≤ ε
and the goal can be closed with exact h_peel.le.
Note that in this example, h and the goal are logically equivalent statements, but peel
cannot be immediately applied to show that the goal implies h.
In addition, peel supports goals of the form (∀ x, p x) ↔ ∀ x, q x, or likewise for any
other quantifier. In this case, there is no hypothesis or term to supply, but otherwise the syntax
is the same. So for such goals, the syntax is peel 1 or peel with x, and after which the
resulting goal is p x ↔ q x. The congr! tactic can also be applied to goals of this form using
congr! 1 with x. While congr! applies congruence lemmas in general, peel can be relied upon
to only apply to outermost quantifiers.
Finally, the user may supply a term e via ... using e in order to close the goal
immediately. In particular, peel h using e is equivalent to peel h; exact e. The using syntax
may be paired with any of the other features of peel.
This tactic works by repeatedly applying lemmas such as forall_imp, Exists.imp,
Filter.Eventually.mp, Filter.Frequently.mp, and Filter.Eventually.of_forall.
- Tags:
- Defined in module:
- Mathlib.Tactic.Peel
pick_goal
pick_goal n will move the n-th goal to the front.
pick_goal -n will move the n-th goal (counting from the bottom) to the front.
See also Tactic.rotate_goals, which moves goals from the front to the back and vice-versa.
- Tags:
- Defined in module:
- Batteries.Tactic.PermuteGoals
plausible
plausible considers a proof goal and tries to generate examples
that would contradict the statement.
Let's consider the following proof goal.
xs : List Nat,
h : ∃ (x : Nat) (H : x ∈ xs), x < 3
⊢ ∀ (y : Nat), y ∈ xs → y < 5
The local constants will be reverted and an instance will be found for
Testable (∀ (xs : List Nat), (∃ x ∈ xs, x < 3) → (∀ y ∈ xs, y < 5)).
The Testable instance is supported by an instance of Sampleable (List Nat),
Decidable (x < 3) and Decidable (y < 5).
Examples will be created in ascending order of size (more or less)
The first counter-examples found will be printed and will result in an error:
===================
Found problems!
xs := [1, 28]
x := 1
y := 28
-------------------
If plausible successfully tests 100 examples, it acts like
admit. If it gives up or finds a counter-example, it reports an error.
For more information on writing your own Sampleable and Testable
instances, see Testing.Plausible.Testable.
Optional arguments given with plausible (config : { ... })
numInst(default 100): number of examples to test properties withmaxSize(default 100): final size argument
Options:
set_option trace.plausible.decoration true: print the proposition with quantifier annotationsset_option trace.plausible.discarded true: print the examples discarded because they do not satisfy assumptionsset_option trace.plausible.shrink.steps true: trace the shrinking of counter-exampleset_option trace.plausible.shrink.candidates true: print the lists of candidates considered when shrinking each variableset_option trace.plausible.instance true: print the instances oftestablebeing used to test the propositionset_option trace.plausible.success true: print the tested samples that satisfy a property
- Tags:
- Defined in module:
- Plausible.Tactic
positivity
Tactic solving goals of the form 0 ≤ x, 0 < x and x ≠ 0. The tactic works recursively
according to the syntax of the expression x, if the atoms composing the expression all have
numeric lower bounds which can be proved positive/nonnegative/nonzero by norm_num. This tactic
either closes the goal or fails.
positivity [t₁, …, tₙ] first executes have := t₁; …; have := tₙ in the current goal,
then runs positivity. This is useful when positivity needs derived premises such as 0 < y
for division/reciprocal, or 0 ≤ x for real powers.
Examples:
example {a : ℤ} (ha : 3 < a) : 0 ≤ a ^ 3 + a := by positivity
example {a : ℤ} (ha : 1 < a) : 0 < |(3:ℤ) + a| := by positivity
example {b : ℤ} : 0 ≤ max (-3) (b ^ 2) := by positivity
example {a b c d : ℝ} (hab : 0 < a * b) (hb : 0 ≤ b) (hcd : c < d) :
0 < a ^ c + 1 / (d - c) := by
positivity [sub_pos_of_lt hcd, pos_of_mul_pos_left hab hb]
- Tags:
- Defined in module:
- Mathlib.Tactic.Positivity.Core
pull
pull c rewrites the goal by pulling the constant c closer to the head of the expression.
For instance, pull _ ∈ _ rewrites x ∈ y ∨ ¬ x ∈ z into x ∈ y ∪ zᶜ.
More precisely, the pull tactic repeatedly rewrites an expression by applying lemmas
of the form ... (c ...) = c ... (where c can appear 1 or more times on the left hand side).
pull is the inverse tactic to push. To extend the pull tactic, you can tag a lemma
with the @[push] attribute. pull works as both a tactic and a conv tactic.
A lemma is considered a pull lemma if its reverse direction is a push lemma
that actually moves the given constant away from the head. For example
not_or : ¬ (p ∨ q) ↔ ¬ p ∧ ¬ qis apulllemma, butnot_not : ¬ ¬ p ↔ pis not.log_mul : log (x * y) = log x + log yis apulllemma, butlog_abs : log |x| = log xis not.Pi.mul_def : f * g = fun (i : ι) => f i * g iandPi.one_def : 1 = fun (x : ι) => 1are bothpulllemmas forfun, because everypush fun _ ↦ _lemma is also considered apulllemma.
TODO: define a @[pull] attribute for tagging pull lemmas that are not push lemmas.
pull _ ~ _pulls the operator or relation~.pull c at l1 l2 ...rewrites at the given locations.pull c at *rewrites at all hypotheses and the goal.pull (disch := tac) cuses the tactictacto discharge any hypotheses for@[push]lemmas.
Examples:
pull _ ∈ _rewritesx ∈ y ∨ ¬ x ∈ zintox ∈ y ∪ zᶜ.pull (disch := positivity) Real.logrewriteslog a + 2 * log bintolog (a * b ^ 2).pull fun _ ↦ _rewritesf ^ 2 + 5intofun x => f x ^ 2 + 5wherefis a function.
- Tags:
- Defined in module:
- Mathlib.Tactic.Push
push
push c rewrites the goal by pushing the constant c deeper into an expression.
For instance, push _ ∈ _ rewrites x ∈ {y} ∪ zᶜ into x = y ∨ ¬ x ∈ z.
More precisely, the push tactic repeatedly rewrites an expression by applying lemmas
of the form c ... = ... (c ...) (where c can appear 0 or more times on the right hand side).
To extend the push tactic, you can tag a lemma of this form with the @[push] attribute.
To instead move a constant closer to the head of the expression, use the pull tactic.
push works as both a tactic and a conv tactic.
push _ ~ _pushes the (binary) operator~,push ~ _pushes the (unary) operator~.push c at l1 l2 ...rewrites at the given locations.push c at *rewrites at all hypotheses and the goal.push (disch := tac) cuses the tactictacto discharge any hypotheses for@[push]lemmas.
Examples:
push _ ∈ _rewritesx ∈ {y} ∪ zᶜintox = y ∨ ¬ x ∈ z.push (disch := positivity) Real.logrewriteslog (a * b ^ 2)intolog a + 2 * log b.push ¬ _is the same aspush_negorpush Not, and it rewrites¬ ∀ ε > 0, ∃ δ > 0, δ < εinto∃ ε > 0, ∀ δ > 0, ε ≤ δ.push fun _ ↦ _rewritesfun x => f x ^ 2 + 5intof ^ 2 + 5push ∀ _, _rewrites∀ a, p a ∧ q ainto(∀ a, p a) ∧ (∀ a, q a).
- Tags:
- Defined in module:
- Mathlib.Tactic.Push
push_cast
push_cast rewrites the goal to move certain coercions (casts) inward, toward the leaf nodes.
This uses norm_cast lemmas in the forward direction.
For example, ↑(a + b) will be written to ↑a + ↑b.
push_castmoves casts inward in the goal.push_cast at hmoves casts inward in the hypothesish. It can be used with extra simp lemmas with, for example,push_cast [Int.add_zero].
Example:
example (a b : Nat)
(h1 : ((a + b : Nat) : Int) = 10)
(h2 : ((a + b + 0 : Nat) : Int) = 10) :
((a + b : Nat) : Int) = 10 := by
/-
h1 : ↑(a + b) = 10
h2 : ↑(a + b + 0) = 10
⊢ ↑(a + b) = 10
-/
push_cast
/- Now
⊢ ↑a + ↑b = 10
-/
push_cast at h1
push_cast [Int.add_zero] at h2
/- Now
h1 h2 : ↑a + ↑b = 10
-/
exact h1
See also norm_cast.
- Tags:
- Defined in module:
- Init.Tactics
push_neg
push_neg rewrites the goal by pushing negations deeper into an expression.
For instance, the goal ¬ ∀ x, ∃ y, x ≤ y will be transformed by push_neg into
∃ x, ∀ y, y < x. Binder names are preserved (contrary to what would happen with simp
using the relevant lemmas). push_neg works as both a tactic and a conv tactic.
push_neg is a special case of the more general push tactic, namely push Not.
The push tactic can be extended using the @[push] attribute. push has special-casing
built in for push Not.
Tactics that introduce a negation usually have a version that automatically calls push_neg on
that negation. These include by_cases!, contrapose! and by_contra!.
push_neg at l1 l2 ...rewrites at the given locations.push_neg at *rewrites at each hypothesis and the goal.push_neg +distribrewrites¬ (p ∧ q)into¬ p ∨ ¬ q(by default, the tactic rewrites it intop → ¬ qinstead).
Example:
example (h : ¬ ∀ ε > 0, ∃ δ > 0, ∀ x, |x - x₀| ≤ δ → |f x - y₀| ≤ ε) :
∃ ε > 0, ∀ δ > 0, ∃ x, |x - x₀| ≤ δ ∧ ε < |f x - y₀| := by
push_neg at h
-- Now we have the hypothesis `h : ∃ ε > 0, ∀ δ > 0, ∃ x, |x - x₀| ≤ δ ∧ ε < |f x - y₀|`
exact h
- Tags:
- Defined in module:
- Mathlib.Tactic.Push
rcases
rcases is a tactic that will perform cases recursively, according to a pattern. It is used to
destructure hypotheses or expressions composed of inductive types like h1 : a ∧ b ∧ c ∨ d or
h2 : ∃ x y, trans_rel R x y. Usual usage might be rcases h1 with ⟨ha, hb, hc⟩ | hd or
rcases h2 with ⟨x, y, _ | ⟨z, hxz, hzy⟩⟩ for these examples.
Each element of an rcases pattern is matched against a particular local hypothesis (most of which
are generated during the execution of rcases and represent individual elements destructured from
the input expression). An rcases pattern has the following grammar:
- A name like
x, which names the active hypothesis asx. - A blank
_, which does nothing (letting the automatic naming system used bycasesname the hypothesis). - A hyphen
-, which clears the active hypothesis and any dependents. - The keyword
rfl, which expects the hypothesis to beh : a = b, and callssubston the hypothesis (which has the effect of replacingbwithaeverywhere or vice versa). - A type ascription
p : ty, which sets the type of the hypothesis totyand then matches it againstp. (Of course,tymust unify with the actual type ofhfor this to work.) - A tuple pattern
⟨p1, p2, p3⟩, which matches a constructor with many arguments, or a series of nested conjunctions or existentials. For example if the active hypothesis isa ∧ b ∧ c, then the conjunction will be destructured, andp1will be matched againsta,p2againstband so on. - A
@before a tuple pattern as in@⟨p1, p2, p3⟩will bind all arguments in the constructor, while leaving the@off will only use the patterns on the explicit arguments. - An alternation pattern
p1 | p2 | p3, which matches an inductive type with multiple constructors, or a nested disjunction likea ∨ b ∨ c.
A pattern like ⟨a, b, c⟩ | ⟨d, e⟩ will do a split over the inductive datatype,
naming the first three parameters of the first constructor as a,b,c and the
first two of the second constructor d,e. If the list is not as long as the
number of arguments to the constructor or the number of constructors, the
remaining variables will be automatically named. If there are nested brackets
such as ⟨⟨a⟩, b | c⟩ | d then these will cause more case splits as necessary.
If there are too many arguments, such as ⟨a, b, c⟩ for splitting on
∃ x, ∃ y, p x, then it will be treated as ⟨a, ⟨b, c⟩⟩, splitting the last
parameter as necessary.
rcases also has special support for quotient types: quotient induction into Prop works like
matching on the constructor quot.mk.
rcases h : e with PAT will do the same as rcases e with PAT with the exception that an
assumption h : e = PAT will be added to the context.
- Tags:
- Defined in module:
- Init.RCases
rcongr
Repeatedly apply congr and ext, using the given patterns as arguments for ext.
There are two ways this tactic stops:
congrfails (makes no progress), after having already appliedext.congrcanceled out the last usage ofext. In this case, the state is reverted to before thecongrwas applied.
For example, when the goal is
⊢ (fun x => f x + 3) '' s = (fun x => g x + 3) '' s
then rcongr x produces the goal
x : α ⊢ f x = g x
This gives the same result as congr; ext x; congr.
In contrast, congr would produce
⊢ (fun x => f x + 3) = (fun x => g x + 3)
and congr with x (or congr; ext x) would produce
x : α ⊢ f x + 3 = g x + 3
- Tags:
- Defined in module:
- Batteries.Tactic.Congr
recover
recover tacs applies the tactic (sequence) tacs and then re-adds goals that were
incorrectly marked as closed. This helps to debug issues where a tactic closes goals without
solving them (i.e. goals were removed from the MetaM state without the metavariable
being assigned), resulting in the error "(kernel) declaration has metavariables".
- Tags:
- Defined in module:
- Mathlib.Tactic.Recover
reduce
reduce at loc completely reduces the given location.
This also exists as a conv-mode tactic.
This does the same transformation as the #reduce command.
- Tags:
- Defined in module:
- Mathlib.Tactic.DefEqTransformations
refine
refine e behaves like exact e, except that named (?x) or unnamed (?_)
holes in e that are not solved by unification with the main goal's target type
are converted into new goals, using the hole's name, if any, as the goal case name.
- Tags:
- Defined in module:
- Init.Tactics
refine'
refine' e behaves like refine e, except that unsolved placeholders (_)
and implicit parameters are also converted into new goals.
- Tags:
- Defined in module:
- Init.Tactics
refine_lift
Auxiliary macro for lifting have/suffices/let/...
It makes sure the "continuation" ?_ is the main goal after refining.
- Tags:
- Defined in module:
- Init.Tactics
refold_let
refold_let x y z at loc looks for the bodies of local definitions x, y, and z at the given
location and replaces them with x, y, or z. This is the inverse of "zeta reduction."
This also exists as a conv-mode tactic.
- Tags:
- Defined in module:
- Mathlib.Tactic.DefEqTransformations
rel
The rel tactic applies "generalized congruence" rules to solve a relational goal by
"substitution". For example,
example {a b x c d : ℝ} (h1 : a ≤ b) (h2 : c ≤ d) :
x ^ 2 * a + c ≤ x ^ 2 * b + d := by
rel [h1, h2]
In this example we "substitute" the hypotheses a ≤ b and c ≤ d into the LHS x ^ 2 * a + c of
the goal and obtain the RHS x ^ 2 * b + d, thus proving the goal.
The "generalized congruence" rules used are the library lemmas which have been tagged with the
attribute @[gcongr]. For example, the first example constructs the proof term
add_le_add (mul_le_mul_of_nonneg_left h1 (pow_bit0_nonneg x 1)) h2
using the generalized congruence lemmas add_le_add and mul_le_mul_of_nonneg_left. If there are
no applicable generalized congruence lemmas, the tactic fails.
The tactic attempts to discharge side goals to these "generalized congruence" lemmas (such as the
side goal 0 ≤ x ^ 2 in the above application of mul_le_mul_of_nonneg_left) using the tactic
gcongr_discharger, which wraps positivity but can also be extended. If the side goals cannot
be discharged in this way, the tactic fails.
- Tags:
- Defined in module:
- Mathlib.Tactic.GCongr.Core
rename
rename t => x renames the most recent hypothesis whose type matches t
(which may contain placeholders) to x, or fails if no such hypothesis could be found.
- Tags:
- Defined in module:
- Init.Tactics
rename'
rename' h => hnew renames the hypothesis named h to hnew.
To rename several hypothesis, use rename' h₁ => h₁new, h₂ => h₂new.
You can use rename' a => b, b => a to swap two variables.
- Tags:
- Defined in module:
- Mathlib.Tactic.Rename
rename_bvar
rename_bvar old → newrenames all bound variables namedoldtonewin the target.rename_bvar old → new at hdoes the same in hypothesish.
example (P : ℕ → ℕ → Prop) (h : ∀ n, ∃ m, P n m) : ∀ l, ∃ m, P l m := by
rename_bvar n → q at h -- h is now ∀ (q : ℕ), ∃ (m : ℕ), P q m,
rename_bvar m → n -- target is now ∀ (l : ℕ), ∃ (n : ℕ), P k n,
exact h -- Lean does not care about those bound variable names
Note: name clashes are resolved automatically.
- Tags:
- Defined in module:
- Mathlib.Tactic.RenameBVar
rename_i
rename_i x_1 ... x_n renames the last n inaccessible names using the given names.
- Tags:
- Defined in module:
- Init.Tactics
repeat
repeat tac repeatedly applies tac so long as it succeeds.
The tactic tac may be a tactic sequence, and if tac fails at any point in its execution,
repeat will revert any partial changes that tac made to the tactic state.
The tactic tac should eventually fail, otherwise repeat tac will run indefinitely.
See also:
try tacis likerepeat tacbut will applytacat most once.repeat' tacrecursively appliestacto each goal.first | tac1 | tac2implements the backtracking used byrepeat
- Tags:
- Defined in module:
- Init.Tactics
repeat'
repeat' tac recursively applies tac on all of the goals so long as it succeeds.
That is to say, if tac produces multiple subgoals, then repeat' tac is applied to each of them.
See also:
repeat tacsimply repeatedly appliestac.repeat1' tacisrepeat' tacbut requires thattacsucceed for some goal at least once.
- Tags:
- Defined in module:
- Init.Tactics
repeat1
repeat1 tac applies tac to main goal at least once. If the application succeeds,
the tactic is applied recursively to the generated subgoals until it eventually fails.
- Tags:
- Defined in module:
- Mathlib.Tactic.Core
repeat1'
repeat1' tac recursively applies to tac on all of the goals so long as it succeeds,
but repeat1' tac fails if tac succeeds on none of the initial goals.
See also:
repeat tacsimply appliestacrepeatedly.repeat' tacis likerepeat1' tacbut it does not require thattacsucceed at least once.
- Tags:
- Defined in module:
- Init.Tactics
replace
Acts like have, but removes a hypothesis with the same name as
this one if possible. For example, if the state is:
f : α → β
h : α
⊢ goal
Then after replace h := f h the state will be:
f : α → β
h : β
⊢ goal
whereas have h := f h would result in:
f : α → β
h† : α
h : β
⊢ goal
This can be used to simulate the specialize and apply at tactics of Coq.
- Tags:
- Defined in module:
- Init.Tactics
revert
revert x... is the inverse of intro x...: it moves the given hypotheses
into the main goal's target type.
- Tags:
- Defined in module:
- Init.Tactics
rewrite
rewrite [e] applies identity e as a rewrite rule to the target of the main goal.
If e is preceded by left arrow (← or <-), the rewrite is applied in the reverse direction.
If e is a defined constant, then the equational theorems associated with e are used.
This provides a convenient way to unfold e.
rewrite [e₁, ..., eₙ]applies the given rules sequentially.rewrite [e] at lrewriteseat location(s)l, wherelis 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.
Using rw (occs := .pos L) [e],
where L : List Nat, you can control which "occurrences" are rewritten.
(This option applies to each rule, so usually this will only be used with a single rule.)
Occurrences count from 1.
At each allowed occurrence, arguments of the rewrite rule e may be instantiated,
restricting which later rewrites can be found.
(Disallowed occurrences do not result in instantiation.)
(occs := .neg L) allows skipping specified occurrences.
- Tags:
- Defined in module:
- Init.Tactics
rewrite!
rewrite! is like rewrite,
but can also insert casts to adjust types that depend on the LHS of a rewrite.
It is available as an ordinary tactic and a conv tactic.
The sort of casts that are inserted is controlled by the castMode configuration option.
By default, only proof terms are casted;
by proof irrelevance, this adds no observable complexity.
With rewrite! +letAbs (castMode := .all), casts are inserted whenever necessary.
This means that the 'motive is not type correct' error never occurs,
at the expense of creating potentially complicated terms.
- Tags:
- Defined in module:
- Mathlib.Tactic.DepRewrite
rfl
This tactic applies to a goal whose target has the form x ~ x,
where ~ is equality, heterogeneous equality or any relation that
has a reflexivity lemma tagged with the attribute @[refl].
- Tags:
- Defined in module:
- Init.Tactics
rfl'
rfl' is similar to rfl, but disables smart unfolding and unfolds all kinds of definitions,
theorems included (relevant for declarations defined by well-founded recursion).
- Tags:
- Defined in module:
- Init.Tactics
right
Applies the second constructor when the goal is an inductive type with exactly two constructors, or fails otherwise.
example {p q : Prop} (h : q) : p ∨ q := by
right
exact h
- Tags:
- Defined in module:
- Init.Tactics
ring
ring solves equations in commutative (semi)rings, allowing for variables in the
exponent. If the goal is not appropriate for ring (e.g. not an equality) ring_nf will be
suggested. See also ring1, which fails if the goal is not an equality.
ring!will use a more aggressive reducibility setting to determine equality of atoms.
Examples:
example (n : ℕ) (m : ℤ) : 2^(n+1) * m = 2 * 2^n * m := by ring
example (a b : ℤ) (n : ℕ) : (a + b)^(n + 2) = (a^2 + b^2 + a * b + b * a) * (a + b)^n := by ring
example (x y : ℕ) : x + id y = y + id x := by ring!
example (x : ℕ) (h : x * 2 > 5): x + x > 5 := by ring; assumption -- suggests ring_nf
- Tags:
- Defined in module:
- Mathlib.Tactic.Ring.RingNF
ring1
ring1 solves the goal when it is an equality in commutative (semi)rings,
allowing variables in the exponent.
This version of ring fails if the target is not an equality.
ring1!uses a more aggressive reducibility setting to determine equality of atoms.
- Tags:
- Defined in module:
- Mathlib.Tactic.Ring.Basic
ring_nf
ring_nf simplifies expressions in the language of commutative (semi)rings,
which rewrites all ring expressions into a normal form, allowing variables in the exponents.
ring_nf works as both a tactic and a conv tactic.
See also the ring tactic for solving a goal which is an equation in the language
of commutative (semi)rings.
ring_nf!will use a more aggressive reducibility setting to identify atoms.ring_nf (config := cfg)allows for additional configuration (seeRingNF.Config):red: the reducibility setting (overridden by!)zetaDelta: if true, local let variables can be unfolded (overridden by!)recursive: if true,ring_nfwill also recurse into atoms
ring_nf at l1 l2 ...can be used to rewrite at the given locations.
Examples:
This can be used non-terminally to normalize ring expressions in the goal such as
⊢ P (x + x + x) ~> ⊢ P (x * 3), as well as being able to prove some equations that
ring cannot because they involve ring reasoning inside a subterm, such as
sin (x + y) + sin (y + x) = 2 * sin (x + y).
- Tags:
- Defined in module:
- Mathlib.Tactic.Ring.RingNF
rintro
The rintro tactic is a combination of the intros tactic with rcases to
allow for destructuring patterns while introducing variables. See rcases for
a description of supported patterns. For example, rintro (a | ⟨b, c⟩) ⟨d, e⟩
will introduce two variables, and then do case splits on both of them producing
two subgoals, one with variables a d e and the other with b c d e.
rintro, unlike rcases, also supports the form (x y : ty) for introducing
and type-ascripting multiple variables at once, similar to binders.
- Tags:
- Defined in module:
- Init.RCases
rotate_left
rotate_left n rotates goals to the left by n. That is, rotate_left 1
takes the main goal and puts it to the back of the subgoal list.
If n is omitted, it defaults to 1.
- Tags:
- Defined in module:
- Init.Tactics
rotate_right
Rotate the goals to the right by n. That is, take the goal at the back
and push it to the front n times. If n is omitted, it defaults to 1.
- Tags:
- Defined in module:
- Init.Tactics
rsuffices
The rsuffices tactic is an alternative version of suffices, that allows the usage
of any syntax that would be valid in an obtain block. This tactic just calls obtain
on the expression, and then rotate_left.
- Tags:
- Defined in module:
- Mathlib.Tactic.RSuffices
rw
rw is like rewrite, but also tries to close the goal by "cheap" (reducible) rfl afterwards.
- Tags:
- Defined in module:
- Init.Tactics
rw!
rw! is like rewrite!, but also cleans up introduced refl-casts after every substitution.
It is available as an ordinary tactic and a conv tactic.
- Tags:
- Defined in module:
- Mathlib.Tactic.DepRewrite
rw?
rw? tries to find a lemma which can rewrite the goal.
rw? should not be left in proofs; it is a search tool, like apply?.
Suggestions are printed as rw [h] or rw [← h].
You can use rw? [-my_lemma, -my_theorem] to prevent rw? using the named lemmas.
- Tags:
- Defined in module:
- Init.Tactics
rw??
rw?? is an interactive tactic that suggests rewrites for any expression selected by the user.
To use it, shift-click an expression in the goal or a hypothesis that you want to rewrite.
Clicking on one of the rewrite suggestions will paste the relevant rewrite tactic into the editor.
The rewrite suggestions are grouped and sorted by the pattern that the rewrite lemmas match with. Rewrites that don't change the goal and rewrites that create the same goal as another rewrite are filtered out, as well as rewrites that have new metavariables in the replacement expression. To see all suggestions, click on the filter button (▼) in the top right.
- Tags:
- Defined in module:
- Mathlib.Tactic.Widget.LibraryRewrite
rw_mod_cast
Rewrites with the given rules, normalizing casts prior to each step.
- Tags:
- Defined in module:
- Init.TacticsExtra
says
If you write X says, where X is a tactic that produces a "Try this: Y" message,
then you will get a message "Try this: X says Y".
Once you've clicked to replace X says with X says Y,
afterwards X says Y will only run Y.
The typical usage case is:
simp? [X] says simp only [X, Y, Z]
If you use set_option says.verify true (set automatically during CI) then X says Y
runs X and verifies that it still prints "Try this: Y".
- Tags:
- Defined in module:
- Mathlib.Tactic.Says
set
set a := t with h is a variant of let a := t. It adds the hypothesis h : a = t to
the local context and replaces t with a everywhere it can.
set a := t with ← h will add h : t = a instead.
set! a := t with h does not do any replacing.
example (x : Nat) (h : x + x - x = 3) : x + x - x = 3 := by
set y := x with ← h2
sorry
/-
x : Nat
y : Nat := x
h : y + y - y = 3
h2 : x = y
⊢ y + y - y = 3
-/
- Tags:
- Defined in module:
- Mathlib.Tactic.Set
set_option
set_option opt val in tacs (the tactic) acts like set_option opt val at the command level,
but it sets the option only within the tactics tacs.
- Tags:
- Defined in module:
- Lean.Parser.Command
show
show t finds the first goal whose target unifies with t. It makes that the main goal,
performs the unification, and replaces the target with the unified version of t.
- Tags:
- Defined in module:
- Init.Tactics
show_term
show_term tac runs tac, then prints the generated term in the form
"exact X Y Z" or "refine X ?_ Z" (prefixed by expose_names if necessary)
if there are remaining subgoals.
(For some tactics, the printed term will not be human readable.)
- Tags:
- Defined in module:
- Init.Tactics
simp
The simp tactic uses lemmas and hypotheses to simplify the main goal target or
non-dependent hypotheses. It has many variants:
simpsimplifies the main goal target using lemmas tagged with the attribute[simp].simp [h₁, h₂, ..., hₙ]simplifies the main goal target using the lemmas tagged with the attribute[simp]and the givenhᵢ's, where thehᵢ's are expressions.-- If an
hᵢis a defined constantf, thenfis unfolded. Iffhas equational lemmas associated with it (and is not a projection or areducibledefinition), these are used to rewrite withf. simp [*]simplifies the main goal target using the lemmas tagged with the attribute[simp]and all hypotheses.simp only [h₁, h₂, ..., hₙ]is likesimp [h₁, h₂, ..., hₙ]but does not use[simp]lemmas.simp [-id₁, ..., -idₙ]simplifies the main goal target using the lemmas tagged with the attribute[simp], but removes the ones namedidᵢ.simp at h₁ h₂ ... hₙsimplifies the hypothesesh₁ : T₁...hₙ : Tₙ. If the target or another hypothesis depends onhᵢ, a new simplified hypothesishᵢis introduced, but the old one remains in the local context.simp at *simplifies all the hypotheses and the target.simp [*] at *simplifies target and all (propositional) hypotheses using the other hypotheses.
- Tags:
- Defined in module:
- Init.Tactics
simp!
simp! is shorthand for simp with autoUnfold := true.
This will unfold applications of functions defined by pattern matching, when one of the patterns applies.
This can be used to partially evaluate many definitions.
- Tags:
- Defined in module:
- Init.Meta
simp?
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.
- Tags:
- Defined in module:
- Init.Tactics
simp?!
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.
- Tags:
- Defined in module:
- Init.Tactics
simp_all
simp_all is a stronger version of simp [*] at * where the hypotheses and target
are simplified multiple times until no simplification is applicable.
Only non-dependent propositional hypotheses are considered.
- Tags:
- Defined in module:
- Init.Tactics
simp_all!
simp_all! is shorthand for simp_all with autoUnfold := true.
This will unfold applications of functions defined by pattern matching, when one of the patterns applies.
This can be used to partially evaluate many definitions.
- Tags:
- Defined in module:
- Init.Meta
simp_all?
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.
- Tags:
- Defined in module:
- Init.Tactics
simp_all?!
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.
- Tags:
- Defined in module:
- Init.Tactics
simp_all_arith
simp_all_arith has been deprecated. It was a shorthand for simp_all +arith +decide.
Note that +decide is not needed for reducing arithmetic terms since simprocs have been added to Lean.
- Tags:
- Defined in module:
- Init.Meta
simp_all_arith!
simp_all_arith! has been deprecated. It was a shorthand for simp_all! +arith +decide.
Note that +decide is not needed for reducing arithmetic terms since simprocs have been added to Lean.
- Tags:
- Defined in module:
- Init.Meta
simp_arith
simp_arith has been deprecated. It was a shorthand for simp +arith +decide.
Note that +decide is not needed for reducing arithmetic terms since simprocs have been added to Lean.
- Tags:
- Defined in module:
- Init.Meta
simp_arith!
simp_arith! has been deprecated. It was a shorthand for simp! +arith +decide.
Note that +decide is not needed for reducing arithmetic terms since simprocs have been added to Lean.
- Tags:
- Defined in module:
- Init.Meta
simp_intro
The simp_intro tactic is a combination of simp and intro: it will simplify the types of
variables as it introduces them and uses the new variables to simplify later arguments
and the goal.
simp_intro x y zintroduces variables namedx y zsimp_intro x y z ..introduces variables namedx y zand then keeps introducing_binderssimp_intro (config := cfg) (discharger := tac) x y .. only [h₁, h₂]:simp_introtakes the same options assimp(seesimp)
example : x + 0 = y → x = z := by
simp_intro h
-- h: x = y ⊢ y = z
sorry
- Tags:
- Defined in module:
- Mathlib.Tactic.SimpIntro
simp_rw
simp_rw functions as a mix of simp and rw. Like rw, it applies each
rewrite rule in the given order, but like simp it repeatedly applies these
rules and also under binders like ∀ x, ..., ∃ x, ... and fun x ↦....
Usage:
simp_rw [lemma_1, ..., lemma_n]will rewrite the goal by applying the lemmas in that order. A lemma preceded by←is applied in the reverse direction.simp_rw [lemma_1, ..., lemma_n] at h₁ ... hₙwill rewrite the given hypotheses.simp_rw [...] at *rewrites in the whole context: all hypotheses and the goal.
Lemmas passed to simp_rw must be expressions that are valid arguments to simp.
For example, neither simp nor rw can solve the following, but simp_rw can:
example {a : ℕ}
(h1 : ∀ a b : ℕ, a - 1 ≤ b ↔ a ≤ b + 1)
(h2 : ∀ a b : ℕ, a ≤ b ↔ ∀ c, c < a → c < b) :
(∀ b, a - 1 ≤ b) = ∀ b c : ℕ, c < a → c < b + 1 := by
simp_rw [h1, h2]
- Tags:
- Defined in module:
- Mathlib.Tactic.SimpRw
simp_wf
Unfold definitions commonly used in well founded relation definitions.
Since Lean 4.12, Lean unfolds these definitions automatically before presenting the goal to the
user, and this tactic should no longer be necessary. Calls to simp_wf can be removed or replaced
by plain calls to simp.
- Tags:
- Defined in module:
- Init.WFTactics
simpa
This is a "finishing" tactic modification of simp. It has two forms.
simpa [rules, ⋯] using ewill simplify the goal and the type ofeusingrules, then try to close the goal usinge.
Simplifying the type of e makes it more likely to match the goal
(which has also been simplified). This construction also tends to be
more robust under changes to the simp lemma set.
simpa [rules, ⋯]will simplify the goal and the type of a hypothesisthisif present in the context, then try to close the goal using theassumptiontactic.
- Tags:
- Defined in module:
- Init.Tactics
simpa!
This is a "finishing" tactic modification of simp. It has two forms.
simpa [rules, ⋯] using ewill simplify the goal and the type ofeusingrules, then try to close the goal usinge.
Simplifying the type of e makes it more likely to match the goal
(which has also been simplified). This construction also tends to be
more robust under changes to the simp lemma set.
simpa [rules, ⋯]will simplify the goal and the type of a hypothesisthisif present in the context, then try to close the goal using theassumptiontactic.
- Tags:
- Defined in module:
- Init.Tactics
simpa?
This is a "finishing" tactic modification of simp. It has two forms.
simpa [rules, ⋯] using ewill simplify the goal and the type ofeusingrules, then try to close the goal usinge.
Simplifying the type of e makes it more likely to match the goal
(which has also been simplified). This construction also tends to be
more robust under changes to the simp lemma set.
simpa [rules, ⋯]will simplify the goal and the type of a hypothesisthisif present in the context, then try to close the goal using theassumptiontactic.
- Tags:
- Defined in module:
- Init.Tactics
simpa?!
This is a "finishing" tactic modification of simp. It has two forms.
simpa [rules, ⋯] using ewill simplify the goal and the type ofeusingrules, then try to close the goal usinge.
Simplifying the type of e makes it more likely to match the goal
(which has also been simplified). This construction also tends to be
more robust under changes to the simp lemma set.
simpa [rules, ⋯]will simplify the goal and the type of a hypothesisthisif present in the context, then try to close the goal using theassumptiontactic.
- Tags:
- Defined in module:
- Init.Tactics
sizeOf_list_dec
This tactic, added to the decreasing_trivial toolbox, proves that
sizeOf a < sizeOf as when a ∈ as, which is useful for well founded recursions
over a nested inductive like inductive T | mk : List T → T.
- Tags:
- Defined in module:
- Init.Data.List.BasicAux
sleep
The tactic sleep ms sleeps for ms milliseconds and does nothing.
It is used for debugging purposes only.
- Tags:
- Defined in module:
- Init.Tactics
solve
Similar to first, but succeeds only if one the given tactics solves the current goal.
- Tags:
- Defined in module:
- Init.NotationExtra
solve_by_elim
solve_by_elim calls apply on the main goal to find an assumption whose head matches
and then repeatedly calls apply on the generated subgoals until no subgoals remain,
performing at most maxDepth (defaults to 6) recursive steps.
solve_by_elim discharges the current goal or fails.
solve_by_elim performs backtracking if subgoals can not be solved.
By default, the assumptions passed to apply are the local context, rfl, trivial,
congrFun and congrArg.
The assumptions can be modified with similar syntax as for simp:
solve_by_elim [h₁, h₂, ..., hᵣ]also applies the given expressions.solve_by_elim only [h₁, h₂, ..., hᵣ]does not include the local context,rfl,trivial,congrFun, orcongrArgunless they are explicitly included.solve_by_elim [-h₁, ... -hₙ]removes the given local hypotheses.solve_by_elim using [a₁, ...]uses all lemmas which have been labelled with the attributesaᵢ(these attributes must be created usingregister_label_attr).
solve_by_elim* tries to solve all goals together, using backtracking if a solution for one goal
makes other goals impossible.
(Adding or removing local hypotheses may not be well-behaved when starting with multiple goals.)
Optional arguments passed via a configuration argument as solve_by_elim (config := { ... })
maxDepth: number of attempts at discharging generated subgoalssymm: adds all hypotheses derived bysymm(defaults totrue).exfalso: allow callingexfalsoand trying again ifsolve_by_elimfails (defaults totrue).transparency: change the transparency mode when callingapply. Defaults to.default, but it is often useful to change to.reducible, so semireducible definitions will not be unfolded when trying to apply a lemma.
See also the doc-comment for Lean.Meta.Tactic.Backtrack.BacktrackConfig for the options
proc, suspend, and discharge which allow further customization of solve_by_elim.
Both apply_assumption and apply_rules are implemented via these hooks.
- Tags:
- Defined in module:
- Init.Tactics
sorry
The sorry tactic is a temporary placeholder for an incomplete tactic proof,
closing the main goal using exact sorry.
This is intended for stubbing-out incomplete parts of a proof while still having a syntactically correct proof skeleton.
Lean will give a warning whenever a proof uses sorry, so you aren't likely to miss it,
but you can double check if a theorem depends on sorry by looking for sorryAx in the output
of the #print axioms my_thm command, the axiom used by the implementation of sorry.
- Tags:
- Defined in module:
- Init.Tactics
specialize
The tactic specialize h a₁ ... aₙ works on local hypothesis h.
The premises of this hypothesis, either universal quantifications or
non-dependent implications, are instantiated by concrete terms coming
from arguments a₁ ... aₙ.
The tactic adds a new hypothesis with the same name h := h a₁ ... aₙ
and tries to clear the previous one.
- Tags:
- Defined in module:
- Init.Tactics
specialize_all
specialize_all x runs specialize h x for all hypotheses h where this tactic succeeds.
- Tags:
- Defined in module:
- Mathlib.Tactic.TautoSet
split
The split tactic is useful for breaking nested if-then-else and match expressions into separate cases.
For a match expression with n cases, the split tactic generates at most n subgoals.
For example, given n : Nat, and a target if n = 0 then Q else R, split will generate
one goal with hypothesis n = 0 and target Q, and a second goal with hypothesis
¬n = 0 and target R. Note that the introduced hypothesis is unnamed, and is commonly
renamed using the case or next tactics.
splitwill split the goal (target).split at hwill split the hypothesish.
- Tags:
- Defined in module:
- Init.Tactics
split_ands
split_ands applies And.intro until it does not make progress.
- Tags:
- Defined in module:
- Batteries.Tactic.Init
split_ifs
Splits all if-then-else-expressions into multiple goals.
Given a goal of the form g (if p then x else y), split_ifs will produce
two goals: p ⊢ g x and ¬p ⊢ g y.
If there are multiple ite-expressions, then split_ifs will split them all,
starting with a top-most one whose condition does not contain another
ite-expression.
split_ifs at * splits all ite-expressions in all hypotheses as well as the goal.
split_ifs with h₁ h₂ h₃ overrides the default names for the hypotheses.
- Tags:
- Defined in module:
- Mathlib.Tactic.SplitIfs
stop
stop is a helper tactic for "discarding" the rest of a proof:
it is defined as repeat sorry.
It is useful when working on the middle of a complex proofs,
and less messy than commenting the remainder of the proof.
- Tags:
- Defined in module:
- Init.Tactics
subsingleton
The subsingleton tactic tries to prove a goal of the form x = y or x ≍ y
using the fact that the types involved are subsingletons
(a type with exactly zero or one terms).
To a first approximation, it does apply Subsingleton.elim.
As a nicety, subsingleton first runs the intros tactic.
- If the goal is an equality, it either closes the goal or fails.
subsingleton [inst1, inst2, ...]can be used to add additionalSubsingletoninstances to the local context. This can be more flexible thanhave := inst1; have := inst2; ...; subsingletonsince the tactic does not require that all placeholders be solved for.
Techniques the subsingleton tactic can apply:
- proof irrelevance
- heterogeneous proof irrelevance (via
proof_irrel_heq) - using
Subsingleton(viaSubsingleton.elim) - proving
BEqinstances are equal if they are both lawful (vialawful_beq_subsingleton)
Properties #
The tactic is careful not to accidentally specialize Sort _ to Prop,
avoiding the following surprising behavior of apply Subsingleton.elim:
example (α : Sort _) (x y : α) : x = y := by apply Subsingleton.elim
The reason this example goes through is that
it applies the ∀ (p : Prop), Subsingleton p instance,
specializing the universe level metavariable in Sort _ to 0.
- Tags:
- Defined in module:
- Mathlib.Tactic.Subsingleton
subst
subst x... substitutes each hypothesis x with a definition found in the local context,
then eliminates the hypothesis.
- If
xis a local definition, then its definition is used. - Otherwise, if there is a hypothesis of the form
x = eore = x, theneis used for the definition ofx.
If h : a = b, then subst h may be used if either a or b unfolds to a local hypothesis.
This is similar to the cases h tactic.
See also: subst_vars for substituting all local hypotheses that have a defining equation.
- Tags:
- Defined in module:
- Init.Tactics
subst_eqs
subst_eq repeatedly substitutes according to the equality proof hypotheses in the context,
replacing the left side of the equality with the right, until no more progress can be made.
- Tags:
- Defined in module:
- Init.Tactics
subst_vars
Applies subst to all hypotheses of the form h : x = t or h : t = x.
- Tags:
- Defined in module:
- Init.Tactics
substs
Applies the subst tactic to all given hypotheses from left to right.
- Tags:
- Defined in module:
- Mathlib.Tactic.Substs
success_if_fail_with_msg
success_if_fail_with_msg msg tacs runs tacs and succeeds only if they fail with the message
msg.
msg can be any term that evaluates to an explicit String.
- Tags:
- Defined in module:
- Mathlib.Tactic.SuccessIfFailWithMsg
suffices
Given a main goal ctx ⊢ t, suffices h : t' from e replaces the main goal with ctx ⊢ t',
e must have type t in the context ctx, h : t'.
The variant suffices h : t' by tac is a shorthand for suffices h : t' from by tac.
If h : is omitted, the name this is used.
- Tags:
- Defined in module:
- Init.Tactics
suggestions
#suggestions will suggest relevant theorems from the library for the current goal,
using the currently registered library suggestion engine.
The suggestions are printed in the order of their confidence, from highest to lowest.
- Tags:
- Defined in module:
- Init.Tactics
swap
swap is a shortcut for pick_goal 2, which interchanges the 1st and 2nd goals.
- Tags:
- Defined in module:
- Batteries.Tactic.PermuteGoals
swap_var
swap_var swap_rule₁, swap_rule₂, ⋯ applies swap_rule₁ then swap_rule₂ then ⋯.
A swap_rule is of the form x y or x ↔ y, and "applying it" means swapping the variable name
x by y and vice-versa on all hypotheses and the goal.
example {P Q : Prop} (q : P) (p : Q) : P ∧ Q := by
swap_var p ↔ q
exact ⟨p, q⟩
- Tags:
- Defined in module:
- Mathlib.Tactic.SwapVar
symm
symmapplies to a goal whose target has the formt ~ uwhere~is a symmetric relation, that is, a relation which has a symmetry lemma tagged with the attribute [symm]. It replaces the target withu ~ t.symm at hwill rewrite a hypothesish : t ~ utoh : u ~ t.
- Tags:
- Defined in module:
- Init.Tactics
symm_saturate
For every hypothesis h : a ~ b where a @[symm] lemma is available,
add a hypothesis h_symm : b ~ a.
- Tags:
- Defined in module:
- Init.Tactics
tauto
tauto breaks down assumptions of the form _ ∧ _, _ ∨ _, _ ↔ _ and ∃ _, _
and splits a goal of the form _ ∧ _, _ ↔ _ or ∃ _, _ until it can be discharged
using rfl or solve_by_elim.
This is a finishing tactic: it either closes the goal or raises an error.
The Lean 3 version of this tactic by default attempted to avoid classical reasoning
where possible. This Lean 4 version makes no such attempt. The itauto tactic
is designed for that purpose.
- Tags:
- Defined in module:
- Mathlib.Tactic.Tauto
tauto_set
tauto_set attempts to prove tautologies involving hypotheses and goals of the form X ⊆ Y
or X = Y, where X, Y are expressions built using ∪, ∩, , and ᶜ from finitely many
variables of type Set α. It also unfolds expressions of the form Disjoint A B and
symmDiff A B.
Examples:
example {α} (A B C D : Set α) (h1 : A ⊆ B) (h2 : C ⊆ D) : C \ B ⊆ D \ A := by
tauto_set
example {α} (A B C : Set α) (h1 : A ⊆ B ∪ C) : (A ∩ B) ∪ (A ∩ C) = A := by
tauto_set
- Tags:
- Defined in module:
- Mathlib.Tactic.TautoSet
tfae_finish
tfae_finish closes goals of the form TFAE [P₁, P₂, ...] once a sufficient collection
of hypotheses of the form Pᵢ → Pⱼ or Pᵢ ↔ Pⱼ have been introduced to the local context.
tfae_have can be used to conveniently introduce these hypotheses; see tfae_have.
Example:
example : TFAE [P, Q, R] := by
tfae_have 1 → 2 := sorry /- proof of P → Q -/
tfae_have 2 → 1 := sorry /- proof of Q → P -/
tfae_have 2 ↔ 3 := sorry /- proof of Q ↔ R -/
tfae_finish
- Tags:
- Defined in module:
- Mathlib.Tactic.TFAE
tfae_have
tfae_have i → j := t, where the goal is TFAE [P₁, P₂, ...] introduces a hypothesis
tfae_i_to_j : Pᵢ → Pⱼ and proof t to the local context. Note that i and j are
natural number literals (beginning at 1) used as indices to specify the propositions
P₁, P₂, ... that appear in the goal.
Once sufficient hypotheses have been introduced by tfae_have, tfae_finish can be used to close
the goal.
All features of have are supported by tfae_have, including naming, matching,
destructuring, and goal creation.
tfae_have i ← j := tadds a hypothesis in the reverse direction, of typePⱼ → Pᵢ.tfae_have i ↔ j := tadds a hypothesis in the both directions, of typePᵢ ↔ Pⱼ.tfae_have hij : i → j := tnames the introduced hypothesishijinstead oftfae_i_to_j.tfae_have i j | p₁ => t₁ | ...matches on the assumptionp : Pᵢ.tfae_have ⟨hij, hji⟩ : i ↔ j := tdestructures the bi-implication intohij : Pᵢ → Pⱼandhji : Pⱼ → Pⱼ.tfae_have i → j := t ?acreates a new goal for?a.
Examples:
example (h : P → R) : TFAE [P, Q, R] := by
tfae_have 1 → 3 := h
-- The resulting context now includes `tfae_1_to_3 : P → R`.
sorry
-- An example of `tfae_have` and `tfae_finish`:
example : TFAE [P, Q, R] := by
tfae_have 1 → 2 := sorry /- proof of P → Q -/
tfae_have 2 → 1 := sorry /- proof of Q → P -/
tfae_have 2 ↔ 3 := sorry /- proof of Q ↔ R -/
tfae_finish
-- All features of `have` are supported by `tfae_have`:
example : TFAE [P, Q] := by
-- assert `tfae_1_to_2 : P → Q`:
tfae_have 1 → 2 := sorry
-- assert `hpq : P → Q`:
tfae_have hpq : 1 → 2 := sorry
-- match on `p : P` and prove `Q` via `f p`:
tfae_have 1 → 2
| p => f p
-- assert `pq : P → Q`, `qp : Q → P`:
tfae_have ⟨pq, qp⟩ : 1 ↔ 2 := sorry
-- assert `h : P → Q`; `?a` is a new goal:
tfae_have h : 1 → 2 := f ?a
sorry
- Tags:
- Defined in module:
- Mathlib.Tactic.TFAE
toFinite_tac
A tactic (for use in default params) that applies Set.toFinite to synthesize a Set.Finite
term.
- Tags:
- Defined in module:
- Mathlib.Data.Set.Card
to_encard_tac
A tactic useful for transferring proofs for encard to their corresponding card statements
- Tags:
- Defined in module:
- Mathlib.Data.Set.Card
trace
Evaluates a term to a string (when possible), and prints it as a trace message.
- Tags:
- Defined in module:
- Mathlib.Tactic.Trace
trace_state
trace_state displays the current state in the info view.
- Tags:
- Defined in module:
- Init.Tactics
trans
trans applies to a goal whose target has the form t ~ u where ~ is a transitive relation,
that is, a relation which has a transitivity lemma tagged with the attribute [trans].
trans sreplaces the goal with the two subgoalst ~ sands ~ u.- If
sis omitted, then a metavariable is used instead.
Additionally, trans also applies to a goal whose target has the form t → u,
in which case it replaces the goal with t → s and s → u.
- Tags:
- Defined in module:
- Batteries.Tactic.Trans
trivial
trivial tries different simple tactics (e.g., rfl, contradiction, ...)
to close the current goal.
You can use the command macro_rules to extend the set of tactics used. Example:
macro_rules | `(tactic| trivial) => `(tactic| simp)
- Tags:
- Defined in module:
- Init.Tactics
try_suggestions
Helper internal tactic used to implement evalSuggest in try?
- Tags:
- Defined in module:
- Init.Try
try_this
Produces the text Try this: <tac> with the given tactic, and then executes it.
- Tags:
- Defined in module:
- Mathlib.Tactic.TryThis
type_check
Type check the given expression, and trace its type.
- Tags:
- Defined in module:
- Mathlib.Tactic.TypeCheck
unfold
unfold idunfolds all occurrences of definitionidin the target.unfold id1 id2 ...is equivalent tounfold id1; unfold id2; ....unfold id at hunfolds at the hypothesish.
Definitions can be either global or local definitions.
For non-recursive global definitions, this tactic is identical to delta.
For recursive global definitions, it uses the "unfolding lemma" id.eq_def,
which is generated for each recursive definition, to unfold according to the recursive definition given by the user.
Only one level of unfolding is performed, in contrast to simp only [id], which unfolds definition id recursively.
- Tags:
- Defined in module:
- Init.Tactics
unfold?
Replace the selected expression with a definitional unfolding.
- After each unfolding, we apply
whnfCoreto simplify the expression. - Explicit natural number expressions are evaluated.
- Unfolds of class projections of instances marked with
@[default_instance]are not shown. This is relevant for notational type classes like+: we don't want to suggestAdd.add a bas an unfolding ofa + b. Similarly forOfNat n : Natwhich unfolds inton : Nat.
To use unfold?, shift-click an expression in the tactic state.
This gives a list of rewrite suggestions for the selected expression.
Click on a suggestion to replace unfold? by a tactic that performs this rewrite.
- Tags:
- Defined in module:
- Mathlib.Tactic.Widget.InteractiveUnfold
unfold_projs
unfold_projs at loc unfolds projections of class instances at the given location.
This also exists as a conv-mode tactic.
- Tags:
- Defined in module:
- Mathlib.Tactic.DefEqTransformations
unhygienic
unhygienic tacs runs tacs with name hygiene disabled.
This means that tactics that would normally create inaccessible names will instead
make regular variables. Warning: Tactics may change their variable naming
strategies at any time, so code that depends on autogenerated names is brittle.
Users should try not to use unhygienic if possible.
example : ∀ x : Nat, x = x := by unhygienic
intro -- x would normally be intro'd as inaccessible
exact Eq.refl x -- refer to x
- Tags:
- Defined in module:
- Init.Tactics
uniqueDiffWithinAt_Ici_Iic_univ
An auxiliary tactic closing goals UniqueDiffWithinAt ℝ s a where
s ∈ {Iic a, Ici a, univ}.
- Tags:
- Defined in module:
- Mathlib.MeasureTheory.Integral.IntervalIntegral.FundThmCalculus
unit_interval
A tactic that solves 0 ≤ ↑x, 0 ≤ 1 - ↑x, ↑x ≤ 1, and 1 - ↑x ≤ 1 for x : I.
- Tags:
- Defined in module:
- Mathlib.Topology.UnitInterval
unreachable!
This tactic causes a panic when run (at compile time).
(This is distinct from exact unreachable!, which inserts code which will panic at run time.)
It is intended for tests to assert that a tactic will never be executed, which is otherwise an
unusual thing to do (and the unreachableTactic linter will give a warning if you do).
The unreachableTactic linter has a special exception for uses of unreachable!.
example : True := by trivial <;> unreachable!
- Tags:
- Defined in module:
- Batteries.Tactic.Unreachable
use
use e₁, e₂, ⋯ is similar to exists, but unlike exists it is equivalent to applying the tactic
refine ⟨e₁, e₂, ⋯, ?_, ⋯, ?_⟩ with any number of placeholders (rather than just one) and
then trying to close goals associated to the placeholders with a configurable discharger (rather
than just try trivial).
Examples:
example : ∃ x : Nat, x = x := by use 42
example : ∃ x : Nat, ∃ y : Nat, x = y := by use 42, 42
example : Nonempty Nat := by use 5
example : Nonempty (PNat ≃ Nat) := by
use PNat.natPred, Nat.succPNat
· exact PNat.succPNat_natPred
· intro; rfl
use! e₁, e₂, ⋯ is similar but it applies constructors everywhere rather than just for
goals that correspond to the last argument of a constructor. This gives the effect that
nested constructors are being flattened out, with the supplied values being used along the
leaves and nodes of the tree of constructors.
With use! one can feed in each 42 one at a time:
example : ∃ n : {n : Nat // n % 2 = 0}, n.val > 10 := by use! 20; simp
example : ∃ p : Nat × Nat, p.1 = p.2 := by use! (42, 42)
The second line makes use of the fact that use! tries refining with the argument before
applying a constructor. Also note that use/use! by default uses a tactic
called use_discharger to discharge goals, so use! 42 will close the goal in this example since
use_discharger applies rfl, which as a consequence solves for the other Nat metavariable.
These tactics take an optional discharger to handle remaining explicit Prop constructor arguments.
By default it is use (discharger := try with_reducible use_discharger) e₁, e₂, ⋯.
To turn off the discharger and keep all goals, use (discharger := skip).
To allow "heavy refls", use (discharger := try use_discharger).
- Tags:
- Defined in module:
- Mathlib.Tactic.Use
use_discharger
Default discharger to try to use for the use and use! tactics.
This is similar to the trivial tactic but doesn't do things like contradiction or decide.
- Tags:
- Defined in module:
- Mathlib.Tactic.Use
use_finite_instance
Try using Set.toFinite to dispatch a Set.Finite goal.
- Tags:
- Defined in module:
- Mathlib.LinearAlgebra.Dual.Basis
volume_tac
The tactic exact volume, to be used in optional (autoParam) arguments.
- Tags:
- Defined in module:
- Mathlib.MeasureTheory.Measure.MeasureSpaceDef
wait_for_unblock_async
Spawns a logSnapshotTask that waits for unblock to be called, which is expected to happen in a
subsequent document version that does not invalidate this tactic. Complains if cancellation token
was set before unblocking, i.e. if the tactic was invalidated after all.
- Tags:
- Defined in module:
- Lean.Server.Test.Cancel
whnf
whnf at loc puts the given location into weak-head normal form.
This also exists as a conv-mode tactic.
Weak-head normal form is when the outer-most expression has been fully reduced, the expression may contain subexpressions which have not been reduced.
- Tags:
- Defined in module:
- Mathlib.Tactic.DefEqTransformations
with_reducible
with_reducible tacs executes tacs using the reducible transparency setting.
In this setting only definitions tagged as [reducible] are unfolded.
- Tags:
- Defined in module:
- Init.Tactics
with_reducible_and_instances
with_reducible_and_instances tacs executes tacs using the .instances transparency setting.
In this setting only definitions tagged as [reducible] or type class instances are unfolded.
- Tags:
- Defined in module:
- Init.Tactics
with_unfolding_all
with_unfolding_all tacs executes tacs using the .all transparency setting.
In this setting all definitions that are not opaque are unfolded.
- Tags:
- Defined in module:
- Init.Tactics
with_unfolding_none
with_unfolding_none tacs executes tacs using the .none transparency setting.
In this setting no definitions are unfolded.
- Tags:
- Defined in module:
- Init.Tactics
wlog
wlog h : P adds an assumption h : P to the main goal, and adds a side goal that
requires showing that the case h : ¬ P can be reduced to the case where P holds
(typically by symmetry). The side goal will be at the top of the stack. In this side goal,
there will be two additional assumptions:
h : ¬ P: the assumption thatPdoes not holdthis: which is the statement that in the old contextPsuffices to prove the goal. By default, the entire context is reverted to producethis.
wlog h : P with Hgives the nameHto the statement thatPproves the goal.wlog h : P generalizing x y ...reverts certain parts of the context before creating the new goal. In this way, the wlog-claimthiscan be applied toxandyin different orders (exploiting symmetry, which is the typical use case).wlog! h : Palso callspush_negat the generated hypothesish.wlog! h : P ∧ Qwill transform¬ (P ∧ Q)toP → ¬ Qwlog! +distrib h : Palso callspush_neg +distribat the generated hypothesish.wlog! +distrib h : P ∧ Qwill transform¬ (P ∧ Q)to¬P ∨ ¬Q.
- Tags:
- Defined in module:
- Mathlib.Tactic.WLOG
zify
The zify tactic is used to shift propositions from Nat to Int.
This is often useful since Int has well-behaved subtraction.
example (a b c x y z : Nat) (h : ¬ x*y*z < 0) : c < a + 3*b := by
zify
zify at h
/-
h : ¬↑x * ↑y * ↑z < 0
⊢ ↑c < ↑a + 3 * ↑b
-/
zify can be given extra lemmas to use in simplification. This is especially useful in the
presence of nat subtraction: passing ≤ arguments will allow push_cast to do more work.
example (a b c : Nat) (h : a - b < c) (hab : b ≤ a) : false := by
zify [hab] at h
/- h : ↑a - ↑b < ↑c -/
zify makes use of the @[zify_simps] attribute to move propositions,
and the push_cast tactic to simplify the Int-valued expressions.
zify is in some sense dual to the lift tactic.
lift (z : Int) to Nat will change the type of an
integer z (in the supertype) to Nat (the subtype), given a proof that z ≥ 0;
propositions concerning z will still be over Int.
zify changes propositions about Nat (the subtype) to propositions about Int (the supertype),
without changing the type of any variable.
- Tags:
- Defined in module:
- Mathlib.Tactic.Zify