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
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
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
aesop_cat
A thin wrapper for aesop which adds the CategoryTheory rule set and
allows aesop to look through semireducible definitions when calling intros.
This tactic fails when it is unable to solve the goal, making it suitable for
use in auto-params.
- Tags:
- Defined in module:
- Mathlib.CategoryTheory.Category.Basic
aesop_cat?
We also use aesop_cat? to pass along a Try this suggestion when using aesop_cat
- Tags:
- Defined in module:
- Mathlib.CategoryTheory.Category.Basic
aesop_cat_nonterminal
A variant of aesop_cat which does not fail when it is unable to solve the
goal. Use this only for exploration! Nonterminal aesop is even worse than
nonterminal simp.
- Tags:
- Defined in module:
- Mathlib.CategoryTheory.Category.Basic
aesop_graph
A variant of the aesop tactic for use in the graph library. Changes relative
to standard aesop:
- We use the
SimpleGraphrule set in addition to the default rule sets. - We instruct Aesop's
introrule to unfold withdefaulttransparency. - We instruct Aesop to fail if it can't fully solve the goal. This allows us to
use
aesop_graphfor auto-params.
- Tags:
- Defined in module:
- Mathlib.Combinatorics.SimpleGraph.Basic
aesop_graph?
Use aesop_graph? to pass along a Try this suggestion when using aesop_graph
- Tags:
- Defined in module:
- Mathlib.Combinatorics.SimpleGraph.Basic
aesop_graph_nonterminal
A variant of aesop_graph which does not fail if it is unable to solve the goal.
Use this only for exploration! Nonterminal Aesop is even worse than nonterminal simp.
- Tags:
- Defined in module:
- Mathlib.Combinatorics.SimpleGraph.Basic
aesop_mat
The aesop_mat tactic attempts to prove a set is contained in the ground set of a matroid.
It uses a [Matroid] ruleset, and is allowed to fail.
- Tags:
- Defined in module:
- Mathlib.Combinatorics.Matroid.Basic
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
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_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_gmonoid_gnpowRec_succ_tac
A tactic to for use as an optional value for GMonoid.gnpow_succ'.
- Tags:
- Defined in module:
- Mathlib.Algebra.GradedMonoid
apply_gmonoid_gnpowRec_zero_tac
A tactic to for use as an optional value for GMonoid.gnpow_zero'.
- Tags:
- Defined in module:
- Mathlib.Algebra.GradedMonoid
apply_rewrite
apply_rewrite [rules] is a shorthand for grewrite +implicationHyp [rules].
- Tags:
- Defined in module:
- Mathlib.Tactic.GRewrite.Elab
apply_rw
apply_rw [rules] is a shorthand for grw +implicationHyp [rules].
- Tags:
- Defined in module:
- Mathlib.Tactic.GRewrite.Elab
arith_mult
arith_mult solves goals of the form IsMultiplicative f for f : ArithmeticFunction R
by applying lemmas tagged with the user attribute arith_mult.
- Tags:
- Defined in module:
- Mathlib.Tactic.ArithMult
arith_mult?
arith_mult solves goals of the form IsMultiplicative f for f : ArithmeticFunction R
by applying lemmas tagged with the user attribute arith_mult, and prints out the generated
proof term.
- Tags:
- Defined in module:
- Mathlib.Tactic.ArithMult
assumption'
Try calling assumption on all goals; succeeds if it closes at least one goal.
- Tags:
- Defined in module:
- Mathlib.Tactic.Basic
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
bicategory
Use the coherence theorem for bicategories to solve equations in a bicategory, where the two sides only differ by replacing strings of bicategory structural morphisms (that is, associators, unitors, and identities) with different strings of structural morphisms with the same source and target.
That is, bicategory can handle goals of the form
a ≫ f ≫ b ≫ g ≫ c = a' ≫ f ≫ b' ≫ g ≫ c'
where a = a', b = b', and c = c' can be proved using bicategory_coherence.
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Bicategory.Basic
bicategory_coherence
Close the goal of the form η.hom = θ.hom, where η and θ are 2-isomorphisms made up only of
associators, unitors, and identities.
example {B : Type} [Bicategory B] {a : B} :
(λ_ (𝟙 a)).hom = (ρ_ (𝟙 a)).hom := by
bicategory_coherence
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Bicategory.PureCoherence
bicategory_coherence
Coherence tactic for bicategories.
Use pure_coherence instead, which is a frontend to this one.
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.BicategoryCoherence
bicategory_nf
Normalize the both sides of an equality.
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Bicategory.Basic
bitwise_assoc_tac
Proving associativity of bitwise operations in general essentially boils down to a huge case distinction, so it is shorter to use this tactic instead of proving it in the general case.
- Tags:
- Defined in module:
- Mathlib.Data.Nat.Bitwise
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
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!
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
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
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_first_enat
Finds the first ENat in the context and applies the cases tactic to it.
Then simplifies expressions involving ⊤ using the enat_to_nat_top simp set.
- Tags:
- Defined in module:
- Mathlib.Tactic.ENatToNat
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
cat_disch
A tactic for discharging easy category theory goals, widely used as an autoparameter.
Currently this defaults to the aesop_cat wrapper around aesop, but by setting
the option mathlib.tactic.category.grind to true, it will use the grind tactic instead.
- Tags:
- Defined in module:
- Mathlib.CategoryTheory.Category.Basic
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? term unifies term with the current goal, then suggests explicit change syntax
that uses the resulting unified term.
If term is not present, change? suggests the current goal itself. This is useful after tactics
which transform the goal while maintaining definitional equality, such as dsimp; those preceding
tactic calls can then be deleted.
example : (fun x : Nat => x) 0 = 1 := by
change? 0 = _ -- `Try this: change 0 = 1`
- Tags:
- Defined in module:
- Mathlib.Tactic.Change
check_compositions
For each composition f ≫ g in the goal,
which internally is represented as CategoryStruct.comp C inst X Y Z f g,
infer the types of f and g and check whether their sources and targets agree
with X, Y, and Z at "instances and reducible" transparency,
reporting any discrepancies.
An example:
example (j : J) :
colimit.ι ((F ⋙ G) ⋙ H) j ≫ (preservesColimitIso (G ⋙ H) F).inv =
H.map (G.map (colimit.ι F j)) := by
-- We know which lemma we want to use, and it's even a simp lemma, but `rw`
-- won't let us apply it
fail_if_success rw [ι_preservesColimitIso_inv]
fail_if_success rw [ι_preservesColimitIso_inv (G ⋙ H)]
fail_if_success simp only [ι_preservesColimitIso_inv]
-- This would work:
-- erw [ι_preservesColimitIso_inv (G ⋙ H)]
-- `check_compositions` checks if the two morphisms we're composing are
-- composed by abusing defeq, and indeed it tells us that we are abusing
-- definitional associativity of composition of functors here: it prints
-- the following.
-- info: In composition
-- colimit.ι ((F ⋙ G) ⋙ H) j ≫ (preservesColimitIso (G ⋙ H) F).inv
-- the source of
-- (preservesColimitIso (G ⋙ H) F).inv
-- is
-- colimit (F ⋙ G ⋙ H)
-- but should be
-- colimit ((F ⋙ G) ⋙ H)
check_compositions
-- In this case, we can "fix" this by reassociating in the goal, but
-- usually at this point the right thing to do is to back off and
-- check how we ended up with a bad goal in the first place.
dsimp only [Functor.assoc]
-- This would work now, but it is not needed, because simp works as well
-- rw [ι_preservesColimitIso_inv]
simp
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.CheckCompositions
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
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
coherence
Use the coherence theorem for monoidal categories to solve equations in a monoidal equation, where the two sides only differ by replacing strings of monoidal structural morphisms (that is, associators, unitors, and identities) with different strings of structural morphisms with the same source and target.
That is, coherence can handle goals of the form
a ≫ f ≫ b ≫ g ≫ c = a' ≫ f ≫ b' ≫ g ≫ c'
where a = a', b = b', and c = c' can be proved using pure_coherence.
(If you have very large equations on which coherence is unexpectedly failing,
you may need to increase the typeclass search depth,
using e.g. set_option synthInstance.maxSize 500.)
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Coherence
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!
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
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
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?
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
discrete_cases
A simple tactic to run cases on any Discrete α hypotheses.
- Tags:
- Defined in module:
- Mathlib.CategoryTheory.Discrete.Basic
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
enat_to_nat
enat_to_nat shifts all ENats in the context to Nat, rewriting propositions about them.
A typical use case is enat_to_nat; lia.
- Tags:
- Defined in module:
- Mathlib.Tactic.ENatToNat
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
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
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
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
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
frac_tac
Solve equations for RatFunc K by working in FractionRing K[X].
- Tags:
- Defined in module:
- Mathlib.FieldTheory.RatFunc.Basic
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
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?
Display a widget panel allowing to generate a gcongr call with holes specified by selecting
subexpressions in the goal.
- Tags:
- Defined in module:
- Mathlib.Tactic.Widget.GCongr
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'
Backwards compatibility shim for generalize.
- Tags:
- Defined in module:
- Mathlib.Tactic.Generalize
ghost_calc
ghost_calc is a tactic for proving identities between polynomial functions.
Typically, when faced with a goal like
∀ (x y : 𝕎 R), verschiebung (x * frobenius y) = verschiebung x * y
you can
- call
ghost_calc - do a small amount of manual work -- maybe nothing, maybe
rintro, etc - call
ghost_simp
and this will close the goal.
ghost_calc cannot detect whether you are dealing with unary or binary polynomial functions.
You must give it arguments to determine this.
If you are proving a universally quantified goal like the above,
call ghost_calc _ _.
If the variables are introduced already, call ghost_calc x y.
In the unary case, use ghost_calc _ or ghost_calc x.
ghost_calc is a light wrapper around type class inference.
All it does is apply the appropriate extensionality lemma and try to infer the resulting goals.
This is subtle and Lean's elaborator doesn't like it because of the HO unification involved,
so it is easier (and prettier) to put it in a tactic script.
- Tags:
- Defined in module:
- Mathlib.RingTheory.WittVector.IsPoly
ghost_fun_tac
An auxiliary tactic for proving that ghostFun respects the ring operations.
- Tags:
- Defined in module:
- Mathlib.RingTheory.WittVector.Basic
ghost_simp
A macro for a common simplification when rewriting with ghost component equations.
- Tags:
- Defined in module:
- Mathlib.RingTheory.WittVector.IsPoly
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
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_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_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
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
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_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
init_ring
init_ring is an auxiliary tactic that discharges goals factoring init over ring operations.
- Tags:
- Defined in module:
- Mathlib.RingTheory.WittVector.InitTail
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
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
itauto
itauto solves the main goal when it is a tautology of intuitionistic propositional logic.
Unlike grind and tauto! this tactic never uses the law of excluded middle (without the !
option), and the proof search is tailored for this use case. itauto is complete for intuitionistic
propositional logic: it will solve any goal that is provable in this logic.
itauto [a, b]will additionally attempt case analysis onaandbassuming that it can deriveDecidable aandDecidable b.itauto *will case on all decidable propositions that it can find among the atomic propositions.itauto!will work as a classical SAT solver, but the algorithm is not very good in this situation.itauto! *will case on all propositional atoms. Warning: This can blow up the proof search, so it should be used sparingly.
Example:
example (p : Prop) : ¬ (p ↔ ¬ p) := by itauto
- Tags:
- Defined in module:
- Mathlib.Tactic.ITauto
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
liftable_prefixes
Internal tactic used in coherence.
Rewrites an equation f = g as f₀ ≫ f₁ = g₀ ≫ g₁,
where f₀ and g₀ are maximal prefixes of f and g (possibly after reassociating)
which are "liftable" (i.e. expressible as compositions of unitors and associators).
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Coherence
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
linear_combination'
linear_combination' attempts to simplify the target by creating a linear combination
of a list of equalities and subtracting it from the target.
The tactic will create a linear
combination by adding the equalities together from left to right, so the order
of the input hypotheses does matter. If the norm field of the
tactic is set to skip, then the tactic will simply set the user up to
prove their target using the linear combination instead of normalizing the subtraction.
Note: There is also a similar tactic linear_combination (no prime); this version is
provided for backward compatibility. Compared to this tactic, linear_combination:
- drops the
←syntax for reversing an equation, instead offering this operation using the-syntax - does not support multiplication of two hypotheses (
h1 * h2), division by a hypothesis (3 / h), or inversion of a hypothesis (h⁻¹) - produces noisy output when the user adds or subtracts a constant to a hypothesis (
h + 3)
Note: The left and right sides of all the equalities should have the same
type, and the coefficients should also have this type. There must be
instances of Mul and AddGroup for this type.
- The input
einlinear_combination' eis a linear combination of proofs of equalities, given as a sum/difference of coefficients multiplied by expressions. The coefficients may be arbitrary expressions. The expressions can be arbitrary proof terms proving equalities. Most commonly they are hypothesis namesh1, h2, .... linear_combination' (norm := tac) eruns the "normalization tactic"tacon the subgoal(s) after constructing the linear combination.- The default normalization tactic is
ring1, which closes the goal or fails. - To get a subgoal in the case that it is not immediately provable, use
ring_nfas the normalization tactic. - To avoid normalization entirely, use
skipas the normalization tactic.
- The default normalization tactic is
linear_combination' (exp := n) ewill take the goal to thenth power before subtracting the combinatione. In other words, if the goal ist1 = t2,linear_combination' (exp := n) ewill change the goal to(t1 - t2)^n = 0before proceeding as above. This feature is not supported forlinear_combination2.linear_combination2 eis the same aslinear_combination' ebut it produces two subgoals instead of one: rather than proving that(a - b) - (a' - b') = 0wherea' = b'is the linear combination fromeanda = bis the goal, it instead attempts to provea = a'andb = b'. Because it does not use subtraction, this form is applicable also to semirings.- Note that a goal which is provable by
linear_combination' emay not be provable bylinear_combination2 e; in general you may need to add a coefficient toeto make both sides match, as inlinear_combination2 e + c. - You can also reverse equalities using
← h, so for example ifh₁ : a = bthen2 * (← h)is a proof of2 * b = 2 * a.
- Note that a goal which is provable by
Example Usage:
example (x y : ℤ) (h1 : x*y + 2*x = 1) (h2 : x = y) : x*y = -2*y + 1 := by
linear_combination' 1*h1 - 2*h2
example (x y : ℤ) (h1 : x*y + 2*x = 1) (h2 : x = y) : x*y = -2*y + 1 := by
linear_combination' h1 - 2*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
/- Goal: x * y + x * 2 - 1 = 0 -/
example (x y z : ℝ) (ha : x + 2*y - z = 4) (hb : 2*x + y + z = -2)
(hc : x + 2*y + z = 2) :
-3*x - 3*y - 4*z = 2 := by
linear_combination' ha - hb - 2*hc
example (x y : ℚ) (h1 : x + y = 3) (h2 : 3*x = 7) :
x*x*y + y*x*y + 6*x = 3*x*y + 14 := by
linear_combination' x*y*h1 + 2*h2
example (x y : ℤ) (h1 : x = -3) (h2 : y = 10) : 2*x = -6 := by
linear_combination' (norm := skip) 2*h1
simp
axiom qc : ℚ
axiom hqc : qc = 2*qc
example (a b : ℚ) (h : ∀ p q : ℚ, p = q) : 3*a + qc = 3*b + 2*qc := by
linear_combination' 3 * h a b + hqc
- Tags:
- Defined in module:
- Mathlib.Tactic.LinearCombination'
map_fun_tac
Auxiliary tactic for showing that mapFun respects the ring operations.
- Tags:
- Defined in module:
- Mathlib.RingTheory.WittVector.Basic
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
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
mem_tac
mem_tac tries to prove goals of the form x ∈ 𝒜 i when x has the form of:
y ^ nwherei = n • jandy ∈ 𝒜 j.- a natural number
n.
- Tags:
- Defined in module:
- Mathlib.AlgebraicGeometry.ProjectiveSpectrum.Scheme
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
mod_cases
- The tactic
mod_cases h : e % 3will perform a case disjunction one. Ife : ℤ, then it will yield subgoals containing the assumptionsh : e ≡ 0 [ZMOD 3],h : e ≡ 1 [ZMOD 3],h : e ≡ 2 [ZMOD 3]respectively. Ife : ℕinstead, then it works similarly, except with[MOD 3]instead of[ZMOD 3]. - In general,
mod_cases h : e % nworks whennis a positive numeral andeis an expression of typeℕorℤ. - If
his omitted as inmod_cases e % n, it will be default-namedH.
- Tags:
- Defined in module:
- Mathlib.Tactic.ModCases
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
mono
mono applies monotonicity rules and local hypotheses repetitively. For example,
example (x y z k : ℤ)
(h : 3 ≤ (4 : ℤ))
(h' : z ≤ y) :
(k + 3 + x) - y ≤ (k + 4 + x) - z := by
mono
- Tags:
- Defined in module:
- Mathlib.Tactic.Monotonicity.Basic
monoidal
Use the coherence theorem for monoidal categories to solve equations in a monoidal category, where the two sides only differ by replacing strings of monoidal structural morphisms (that is, associators, unitors, and identities) with different strings of structural morphisms with the same source and target.
That is, monoidal can handle goals of the form
a ≫ f ≫ b ≫ g ≫ c = a' ≫ f ≫ b' ≫ g ≫ c'
where a = a', b = b', and c = c' can be proved using monoidal_coherence.
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Monoidal.Basic
monoidal_coherence
Coherence tactic for monoidal categories.
Use pure_coherence instead, which is a frontend to this one.
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Coherence
monoidal_coherence
Close the goal of the form η = θ, where η and θ are 2-isomorphisms made up only of
associators, unitors, and identities.
example {C : Type} [Category* C] [MonoidalCategory C] :
(λ_ (𝟙_ C)).hom = (ρ_ (𝟙_ C)).hom := by
monoidal_coherence
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Monoidal.PureCoherence
monoidal_nf
Normalize the both sides of an equality.
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Monoidal.Basic
monoidal_simps
Simp lemmas for rewriting a hom in monoidal categories into a normal form.
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Coherence
move_oper
The tactic move_add rearranges summands of expressions.
Calling move_add [a, ← b, ...] matches a, b,... with summands in the main goal.
It then moves a to the far right and b to the far left of each addition in which they appear.
The side to which the summands are moved is determined by the presence or absence of the arrow ←.
The inputs a, b,... can be any terms, also with underscores.
The tactic uses the first "new" summand that unifies with each one of the given inputs.
There is a multiplicative variant, called move_mul.
There is also a general tactic for a "binary associative commutative operation": move_oper.
In this case the syntax requires providing first a term whose head symbol is the operation.
E.g. move_oper HAdd.hAdd [...] is the same as move_add, while move_oper Max.max [...]
rearranges maxs.
- Tags:
- Defined in module:
- Mathlib.Tactic.MoveAdd
mv_bisim
tactic for proof by bisimulation
- Tags:
- Defined in module:
- Mathlib.Data.QPF.Multivariate.Constructions.Cofix
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
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_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
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
pgame_wf_tac
Discharges proof obligations of the form ⊢ Subsequent .. arising in termination proofs
of definitions using well-founded recursion on PGame.
- Tags:
- Defined in module:
- Mathlib.SetTheory.PGame.Basic
pi_lower_bound
Create a proof of a < π for a fixed rational number a, given a witness, which is a
sequence of rational numbers √2 < r 1 < r 2 < ... < r n < 2 satisfying the property that
√(2 + r i) ≤ r(i+1), where r 0 = 0 and √(2 - r n) ≥ a/2^(n+1).
- Tags:
- Defined in module:
- Mathlib.Analysis.Real.Pi.Bounds
pi_upper_bound
Create a proof of π < a for a fixed rational number a, given a witness, which is a
sequence of rational numbers √2 < r 1 < r 2 < ... < r n < 2 satisfying the property that
√(2 + r i) ≥ r(i+1), where r 0 = 0 and √(2 - r n) ≤ (a - 1/4^n) / 2^(n+1).
- Tags:
- Defined in module:
- Mathlib.Analysis.Real.Pi.Bounds
pnat_positivity
For each x : PNat in the context, add the hypothesis 0 < (↑x : ℕ).
- Tags:
- Defined in module:
- Mathlib.Tactic.PNatToNat
pnat_to_nat
pnat_to_nat shifts all PNats in the context to Nat, rewriting propositions about them.
A typical use case is pnat_to_nat; lia.
- Tags:
- Defined in module:
- Mathlib.Tactic.PNatToNat
polyrith
The polyrith tactic is no longer supported in Mathlib,
because it relied on a defunct external service.
Attempts to prove polynomial equality goals through polynomial arithmetic
on the hypotheses (and additional proof terms if the user specifies them).
It proves the goal by generating an appropriate call to the tactic
linear_combination. If this call succeeds, the call to linear_combination
is suggested to the user.
polyrithwill use all relevant hypotheses in the local context.polyrith [t1, t2, t3]will add proof terms t1, t2, t3 to the local context.polyrith only [h1, h2, h3, t1, t2, t3]will use only local hypothesesh1,h2,h3, and proofst1,t2,t3. It will ignore the rest of the local context.
Notes:
- This tactic only works with a working internet connection, since it calls Sage using the SageCell web API at https://sagecell.sagemath.org/. Many thanks to the Sage team and organization for allowing this use.
- This tactic assumes that the user has
curlavailable on path.
- Tags:
- Defined in module:
- Mathlib.Tactic.Polyrith
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
pure_coherence
pure_coherence uses the coherence theorem for monoidal categories to prove the goal.
It can prove any equality made up only of associators, unitors, and identities.
example {C : Type} [Category* C] [MonoidalCategory C] :
(λ_ (𝟙_ C)).hom = (ρ_ (𝟙_ C)).hom := by
pure_coherence
Users will typically just use the coherence tactic,
which can also cope with identities of the form
a ≫ f ≫ b ≫ g ≫ c = a' ≫ f ≫ b' ≫ g ≫ c'
where a = a', b = b', and c = c' can be proved using pure_coherence
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Coherence
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_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
qify
The qify tactic is used to shift propositions from ℕ or ℤ to ℚ.
This is often useful since ℚ has well-behaved division.
example (a b c x y z : ℕ) (h : ¬ x*y*z < 0) : c < a + 3*b := by
qify
qify at h
/-
h : ¬↑x * ↑y * ↑z < 0
⊢ ↑c < ↑a + 3 * ↑b
-/
sorry
qify 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 : ℤ) (h : a / b = c) (hab : b ∣ a) (hb : b ≠ 0) : a = c * b := by
qify [hab] at h hb ⊢
exact (div_eq_iff hb).1 h
qify makes use of the @[zify_simps] and @[qify_simps] attributes to move propositions,
and the push_cast tactic to simplify the ℚ-valued expressions.
- Tags:
- Defined in module:
- Mathlib.Tactic.Qify
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
reduce_mod_char
The tactic reduce_mod_char looks for numeric expressions in characteristic p
and reduces these to lie between 0 and p.
For example:
example : (5 : ZMod 4) = 1 := by reduce_mod_char
example : (X ^ 2 - 3 * X + 4 : (ZMod 4)[X]) = X ^ 2 + X := by reduce_mod_char
It also handles negation, turning it into multiplication by p - 1,
and similarly subtraction.
This tactic uses the type of the subexpression to figure out if it is indeed of positive
characteristic, for improved performance compared to trying to synthesise a CharP instance.
The variant reduce_mod_char! also tries to use CharP R n hypotheses in the context.
(Limitations of the typeclass system mean the tactic can't search for a CharP R n instance if
n is not yet known; use have : CharP R n := inferInstance; reduce_mod_char! as a workaround.)
- Tags:
- Defined in module:
- Mathlib.Tactic.ReduceModChar
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' 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
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
replace
Acts like have, but removes a hypothesis with the same name as
this one if possible. For example, if the state is:
Then after replace h : β the state will be:
case h
f : α → β
h : α
⊢ β
f : α → β
h : β
⊢ goal
whereas have h : β would result in:
case h
f : α → β
h : α
⊢ β
f : α → β
h✝ : α
h : β
⊢ goal
- Tags:
- Defined in module:
- Mathlib.Tactic.Replace
restrict_tac
restrict_tac solves relations among subsets (copied from aesop cat)
- Tags:
- Defined in module:
- Mathlib.Topology.Sheaves.Presheaf
restrict_tac?
restrict_tac? passes along Try this from aesop
- Tags:
- Defined in module:
- Mathlib.Topology.Sheaves.Presheaf
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_cat
rfl_cat is a macro for intros; rfl which is attempted in aesop_cat before
doing the more expensive aesop tactic.
This gives a speedup because simp (called by aesop) can be very slow.
https://github.com/leanprover-community/mathlib4/pull/25475 contains measurements from June 2025.
Implementation notes:
refine id ?_: In some cases it is important that the type of the proof matches the expected type exactly. e.g. if the goal is2 = 1 + 1, therfltactic will give a proof of type2 = 2. Starting a proof withrefine id ?_is a trick to make sure that the proof has exactly the expected type, in this case2 = 1 + 1. See also https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/changing.20a.20proof.20can.20break.20a.20later.20proofapply_rfl:rflis a macro that attempts botheq_reflandapply_rfl. Sinceapply_rflsubsumeseq_refl, we can useapply_rflinstead. This fails twice as fast asrfl.
- Tags:
- Defined in module:
- Mathlib.CategoryTheory.Category.Basic
rify
The rify tactic is used to shift propositions from ℕ, ℤ or ℚ to ℝ.
Although less useful than its cousins zify and qify, it can be useful when your
goal or context already involves real numbers.
In the example below, assumption hn is about natural numbers, hk is about integers
and involves casting a natural number to ℤ, and the conclusion is about real numbers.
The proof uses rify to lift both assumptions to ℝ before calling linarith.
example {n : ℕ} {k : ℤ} (hn : 8 ≤ n) (hk : 2 * k ≤ n + 2) :
(0 : ℝ) < n - k - 1 := by
rify at hn hk /- Now have hn : 8 ≤ (n : ℝ) hk : 2 * (k : ℝ) ≤ (n : ℝ) + 2 -/
linarith
rify makes use of the @[zify_simps], @[qify_simps] and @[rify_simps] attributes to move
propositions, and the push_cast tactic to simplify the ℝ-valued expressions.
rify 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 : ℕ) (h : a - b < c) (hab : b ≤ a) : a < b + c := by
rify [hab] at h ⊢
linarith
Note that zify or qify would work just as well in the above example (and zify is the natural
choice since it is enough to get rid of the pathological ℕ subtraction).
- Tags:
- Defined in module:
- Mathlib.Tactic.Rify
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.
Extensions:
ring1_nfadditionally usesring_nfto simplify in atoms.ring1_nf!will use a more aggressive reducibility setting to determine equality of atoms.*ring1_nfadditionally usesring_nfto simplify in atoms.
ring1_nf!will use 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
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 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?? 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_search
rw_search has been removed from Mathlib.
- Tags:
- Defined in module:
- Mathlib.Tactic.RewriteSearch
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
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
sleep_heartbeats
do nothing for at least n heartbeats
- Tags:
- Defined in module:
- Mathlib.Util.SleepHeartbeats
slice_lhs
slice_lhs a b => tac zooms to the left-hand side, uses associativity for categorical
composition as needed, zooms in on the a-th through b-th morphisms, and invokes tac.
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Slice
slice_rhs
slice_rhs a b => tac zooms to the right-hand side, uses associativity for categorical
composition as needed, zooms in on the a-th through b-th morphisms, and invokes tac.
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.Slice
smul_tac
Solve equations for RatFunc K by applying RatFunc.induction_on.
- Tags:
- Defined in module:
- Mathlib.FieldTheory.RatFunc.Basic
sorry_if_sorry
Close the main goal with sorry if its type contains sorry, and fail otherwise.
- Tags:
- Defined in module:
- Mathlib.CategoryTheory.Category.Basic
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_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
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_hom_lift
subst_hom_lift p f φ tries to substitute f with p(φ) by using p.IsHomLift f φ
- Tags:
- Defined in module:
- Mathlib.CategoryTheory.FiberedCategory.HomLift
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
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
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
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?
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
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
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
valid
A wrapper for omega which prefaces it with some quick and useful attempts
- Tags:
- Defined in module:
- Mathlib.CategoryTheory.ComposableArrows.Basic
volume_tac
The tactic exact volume, to be used in optional (autoParam) arguments.
- Tags:
- Defined in module:
- Mathlib.MeasureTheory.Measure.MeasureSpaceDef
whisker_simps
Simp lemmas for rewriting a 2-morphism into a normal form.
- Tags:
- Defined in module:
- Mathlib.Tactic.CategoryTheory.BicategoryCoherence
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
witt_truncateFun_tac
A macro tactic used to prove that truncateFun respects ring operations.
- Tags:
- Defined in module:
- Mathlib.RingTheory.WittVector.Truncated
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