# Documentation

Mathlib.Tactic.SolveByElim

A work-in-progress replacement for Lean3's solve_by_elim tactic. We'll gradually bring it up to feature parity.

def exceptEmoji {ε : Type u_1} {α : Type u_2} :
Except ε αString

Visualize an Except using a checkmark or a cross.

Equations
def Lean.MVarId.applyFirst {α : Type} (cfg : optParam Lean.Meta.ApplyConfig { newGoals := Lean.Meta.ApplyNewGoals.nonDependentFirst, synthAssignedInstances := true, approx := true }) (transparency : ) (trace : ) (lemmas : ) (cont : ) (g : Lean.MVarId) :

applyFirst lemmas cont goal will try to apply one of the lemmas to the goal goal, and then call cont on the resulting List MVarId of subgoals.

It returns the result from cont for the first such lemma for which both the apply and the call to cont succeed.

applyFirst (trace := name) will construct trace nodes for nameindicating which calls toapply succeeded or failed.

Equations
• One or more equations did not get rendered due to their size.
• Maximum recursion depth.

maxDepth :
• If failAtDepth, then solve_by_elim will fail (and backtrack) upon reaching the max depth. Otherwise, upon reaching the max depth, all remaining goals will be returned. (defaults to true)

failAtMaxDepth : Bool
• Transparency mode for calls to apply.

• Also use symmetric versions (via @[symm]) of local hypotheses.

symm : Bool
• Try proving the goal via exfalso if solve_by_elim otherwise fails. This is only used when operating on a single goal.

exfalso : Bool
• An arbitrary procedure which can be used to modify the list of goals before each attempt to apply a lemma. Called as proc goals curr, where goals are the original goals for solve_by_elim, and curr are the current goals. Returning some l will replace the current goals with l and recurse (consuming one step of maximum depth). Returning none will proceed to applying lemmas without changing goals. Failure will cause backtracking. (defaults to none)

proc :
• If suspend g, then we do not attempt to apply any further lemmas, but return g as a new subgoal. (defaults to false)

suspend :
• discharge g is called on goals for which no lemmas apply. If none we return g as a new subgoal. If some l, we replace g by l in the list of active goals, and recurse. If failure, we backtrack. (defaults to failure)

discharge :

Configuration structure to control the behaviour of solve_by_elim:

• control the maximum depth and behaviour (fail or return subgoals) at the maximum depth,
• whether to use symm on hypotheses and exfalso on the goal as needed,
• and hooks allowing
• modifying intermediate goals,
• returning goals as subgoals, and
• discharging subgoals.
Instances For

The default maxDepth for apply_rules is higher.

Instances For

Allow elaboration of Config arguments to tactics.

Equations
• One or more equations did not get rendered due to their size.

Allow elaboration of ApplyRulesConfig arguments to tactics.

Equations
• One or more equations did not get rendered due to their size.
def Mathlib.Tactic.SolveByElim.Config.accept (cfg : optParam Mathlib.Tactic.SolveByElim.Config { toApplyConfig := { newGoals := Lean.Meta.ApplyNewGoals.nonDependentFirst, synthAssignedInstances := true, approx := true }, maxDepth := 6, failAtMaxDepth := true, transparency := Lean.Meta.TransparencyMode.default, symm := true, exfalso := true, proc := fun x x => pure none, suspend := fun x => , discharge := fun x => failure }) (test : ) :

Create or modify a Config which allows a class of goals to be returned as subgoals.

Equations
• One or more equations did not get rendered due to their size.
def Mathlib.Tactic.SolveByElim.Config.noBackTracking (cfg : optParam Mathlib.Tactic.SolveByElim.Config { toApplyConfig := { newGoals := Lean.Meta.ApplyNewGoals.nonDependentFirst, synthAssignedInstances := true, approx := true }, maxDepth := 6, failAtMaxDepth := true, transparency := Lean.Meta.TransparencyMode.default, symm := true, exfalso := true, proc := fun x x => pure none, suspend := fun x => , discharge := fun x => failure }) :

Create or modify a Config which does no backtracking.

Equations
def Mathlib.Tactic.SolveByElim.Config.mainGoalProc (cfg : optParam Mathlib.Tactic.SolveByElim.Config { toApplyConfig := { newGoals := Lean.Meta.ApplyNewGoals.nonDependentFirst, synthAssignedInstances := true, approx := true }, maxDepth := 6, failAtMaxDepth := true, transparency := Lean.Meta.TransparencyMode.default, symm := true, exfalso := true, proc := fun x x => pure none, suspend := fun x => , discharge := fun x => failure }) (proc : ) :

Create or modify a Config which runs a tactic on the main goal. If that tactic fails, fall back to the proc behaviour of cfg.

Equations
• One or more equations did not get rendered due to their size.
def Mathlib.Tactic.SolveByElim.Config.intros (cfg : optParam Mathlib.Tactic.SolveByElim.Config { toApplyConfig := { newGoals := Lean.Meta.ApplyNewGoals.nonDependentFirst, synthAssignedInstances := true, approx := true }, maxDepth := 6, failAtMaxDepth := true, transparency := Lean.Meta.TransparencyMode.default, symm := true, exfalso := true, proc := fun x x => pure none, suspend := fun x => , discharge := fun x => failure }) :

Create or modify a Config which calls intro on each goal before applying lemmas.

Equations
def Mathlib.Tactic.SolveByElim.Config.testPartialSolutions (cfg : optParam Mathlib.Tactic.SolveByElim.Config { toApplyConfig := { newGoals := Lean.Meta.ApplyNewGoals.nonDependentFirst, synthAssignedInstances := true, approx := true }, maxDepth := 6, failAtMaxDepth := true, transparency := Lean.Meta.TransparencyMode.default, symm := true, exfalso := true, proc := fun x x => pure none, suspend := fun x => , discharge := fun x => failure }) (test : ) :

Create or modify a Config which rejects branches for which test, applied to the instantiations of the original goals, fails or returns false.

Equations
• One or more equations did not get rendered due to their size.
def Mathlib.Tactic.SolveByElim.Config.testSolutions (cfg : optParam Mathlib.Tactic.SolveByElim.Config { toApplyConfig := { newGoals := Lean.Meta.ApplyNewGoals.nonDependentFirst, synthAssignedInstances := true, approx := true }, maxDepth := 6, failAtMaxDepth := true, transparency := Lean.Meta.TransparencyMode.default, symm := true, exfalso := true, proc := fun x x => pure none, suspend := fun x => , discharge := fun x => failure }) (test : ) :

Create or modify a Config which rejects complete solutions for which test, applied to the instantiations of the original goals, fails or returns false.

Equations
• One or more equations did not get rendered due to their size.
def Mathlib.Tactic.SolveByElim.Config.requireUsingAll (cfg : optParam Mathlib.Tactic.SolveByElim.Config { toApplyConfig := { newGoals := Lean.Meta.ApplyNewGoals.nonDependentFirst, synthAssignedInstances := true, approx := true }, maxDepth := 6, failAtMaxDepth := true, transparency := Lean.Meta.TransparencyMode.default, symm := true, exfalso := true, proc := fun x x => pure none, suspend := fun x => , discharge := fun x => failure }) (use : ) :

Create or modify a Config which only accept solutions for which every expression in use appears as a subexpression.

Equations
• One or more equations did not get rendered due to their size.

Elaborate a list of lemmas and local context. See mkAssumptionSet for an explanation of why this is needed.

Equations
• One or more equations did not get rendered due to their size.
def Mathlib.Tactic.SolveByElim.solveByElim (lemmas : ) (ctx : ) (goals : ) :

Solve a collection of goals by repeatedly applying lemmas, backtracking as necessary.

Arguments:

• cfg : Config additional configuration options (options for apply, maximum depth, and custom flow control)
• lemmas : List (TermElabM Expr) lemmas to apply. These are thunks in TermElabM to avoid stuck metavariables.
• ctx : TermElabM (List Expr) monadic function returning the local hypotheses to use.
• goals : List MVarId the initial list of goals for solveByElim

Returns a list of suspended goals, if it succeeded on all other subgoals. By default cfg.suspend is false, cfg.discharge fails, and cfg.failAtMaxDepth is true, and so the returned list is always empty. Custom wrappers (e.g. apply_assumption and apply_rules) may modify this behaviour.

Equations
• One or more equations did not get rendered due to their size.
def Mathlib.Tactic.SolveByElim.solveByElim.run (lemmas : ) (ctx : ) (goals : ) (n : ) (curr : ) (acc : ) :
• n : Nat steps remaining.
• curr : List MVarId the current list of unsolved goals.
• acc : List MVarId a list of "suspended" goals, which will be returned as subgoals.
Equations
• One or more equations did not get rendered due to their size.
def Lean.MVarId.applyRules (lemmas : ) (only : ) (g : Lean.MVarId) :

A MetaM analogue of the apply_rules user tactic.

Since apply_rules does not backtrack, we don't need to worry about stuck metavariables and can pass the lemmas as a List Expr.

By default it uses all local hypotheses, but you can disable this with only := true. If you need to remove particular local hypotheses, call solveByElim directly.

Equations
• One or more equations did not get rendered due to their size.
def Mathlib.Tactic.SolveByElim.mkAssumptionSet (noDefaults : Bool) (star : Bool) (add : ) (remove : ) (use : ) :

mkAssumptionSet builds a collection of lemmas for use in the backtracking search in solve_by_elim.

• By default, it includes all local hypotheses, along with rfl, trivial, congrFun and congrArg.
• The flag noDefaults removes these.
• The flag star includes all local hypotheses, but not rfl, trivial, congrFun, or congrArg. (It doesn't make sense to use star without noDefaults.)
• The argument add is the list of terms inside the square brackets that did not have - and can be used to add expressions or local hypotheses
• The argument remove is the list of terms inside the square brackets that had a -, and can be used to remove local hypotheses. (It doesn't make sense to remove expressions which are not local hypotheses, to remove local hypotheses unless !noDefaults || star, and it does not make sense to use star unless you remove at least one local hypothesis.)

mkAssumptionSet returns not a List expr, but a List (TermElabM Expr) × TermElabM (List Expr). There are two separate problems that need to be solved.

### Stuck metavariables #

Lemmas with implicit arguments would be filled in with metavariables if we created the Expr objects immediately, so instead we return thunks that generate the expressions on demand. This is the first component, with type List (TermElabM expr).

As an example, we have def rfl : ∀ {α : Sort u} {a : α}, a = a, which on elaboration will become @rfl ?m_1 ?m_2.

Because solve_by_elim works by repeated application of lemmas against subgoals, the first time such a lemma is successfully applied, those metavariables will be unified, and thereafter have fixed values. This would make it impossible to apply the lemma a second time with different values of the metavariables.

See https://github.com/leanprover-community/mathlib/issues/2269

### Relevant local hypotheses #

solve_by_elim* works with multiple goals, and we need to use separate sets of local hypotheses for each goal. The second component of the returned value provides these local hypotheses. (Essentially using local_context, along with some filtering to remove hypotheses that have been explicitly removed via only or [-h].)

Equations
• One or more equations did not get rendered due to their size.

Run elabTerm.

Equations

Syntax for omitting a local hypothesis in solve_by_elim.

Equations
• One or more equations did not get rendered due to their size.

Syntax for including all local hypotheses in solve_by_elim.

Equations

Syntax for adding or removing a term, or *, in solve_by_elim.

Equations
• One or more equations did not get rendered due to their size.

Syntax for adding and removing terms in solve_by_elim.

Equations
• One or more equations did not get rendered due to their size.

Syntax for using all lemmas labelled with an attribute in solve_by_elim.

Equations
• One or more equations did not get rendered due to their size.
def Mathlib.Tactic.SolveByElim.parseArgs (s : Option (Lean.TSyntax Mathlib.Tactic.SolveByElim.args)) :

Parse the lemma argument of a call to solve_by_elim. The first component should be true if * appears at least once. The second component should contain each term tin the arguments. The third component should contain t for each -t in the arguments.

Equations
• One or more equations did not get rendered due to their size.
def Mathlib.Tactic.SolveByElim.parseUsing (s : Option (Lean.TSyntax Mathlib.Tactic.SolveByElim.using_)) :

Parse the using ... argument for solve_by_elim.

Equations
• One or more equations did not get rendered due to their size.

solve_by_elim calls apply on the main goal to find an assumption whose head matches and then repeatedly calls apply on the generated subgoals until no subgoals remain, performing at most maxDepth (defaults to 6) recursive steps.

solve_by_elim discharges the current goal or fails.

solve_by_elim performs backtracking if subgoals can not be solved.

By default, the assumptions passed to apply are the local context, rfl, trivial, congrFun and congrArg.

The assumptions can be modified with similar syntax as for simp:

• solve_by_elim [h₁, h₂, ..., hᵣ] also applies the given expressions.
• solve_by_elim only [h₁, h₂, ..., hᵣ] does not include the local context, rfl, trivial, congrFun, or congrArg unless they are explicitly included.
• solve_by_elim [-h₁, ... -hₙ] removes the given local hypotheses.
• solve_by_elim using [a₁, ...] uses all lemmas which have been labelled with the attributes aᵢ (these attributes must be created using register_label_attr).

solve_by_elim* tries to solve all goals together, using backtracking if a solution for one goal makes other goals impossible. (Adding or removing local hypotheses may not be well-behaved when starting with multiple goals.)

Optional arguments passed via a configuration argument as solve_by_elim (config := { ... })

• maxDepth: number of attempts at discharging generated subgoals
• symm: adds all hypotheses derived by symm (defaults to true).
• exfalso: allow calling exfalso and trying again if solve_by_elim fails (defaults to true).
• transparency: change the transparency mode when calling apply. Defaults to .default, but it is often useful to change to .reducible, so semireducible definitions will not be unfolded when trying to apply a lemma.

See also the doc-comment for Mathlib.Tactic.SolveByElim.Config for the options proc, suspend, and discharge which allow further customization of solve_by_elim. Both apply_assumption and apply_rules are implemented via these hooks.

Equations
• One or more equations did not get rendered due to their size.
def Mathlib.Tactic.SolveByElim.solveByElim.processSyntax (cfg : optParam Mathlib.Tactic.SolveByElim.Config { toApplyConfig := { newGoals := Lean.Meta.ApplyNewGoals.nonDependentFirst, synthAssignedInstances := true, approx := true }, maxDepth := 6, failAtMaxDepth := true, transparency := Lean.Meta.TransparencyMode.default, symm := true, exfalso := true, proc := fun x x => pure none, suspend := fun x => , discharge := fun x => failure }) (only : Bool) (star : Bool) (add : ) (remove : ) (use : ) (goals : ) :

Wrapper for solveByElim that processes a list of Terms that specify the lemmas to use.

Equations
• One or more equations did not get rendered due to their size.

apply_assumption looks for an assumption of the form ... → ∀ _, ... → head where head matches the current goal.

You can specify additional rules to apply using apply_assumption [...]. By default apply_assumption will also try rfl, trivial, congrFun, and congrArg. If you don't want these, or don't want to use all hypotheses, use apply_assumption only [...]. You can use apply_assumption [-h] to omit a local hypothesis. You can use apply_assumption using [a₁, ...] to use all lemmas which have been labelled with the attributes aᵢ (these attributes must be created using register_label_attr).

apply_assumption will use consequences of local hypotheses obtained via symm.

If apply_assumption fails, it will call exfalso and try again. Thus if there is an assumption of the form P → ¬ Q, the new tactic state will have two goals, P and Q.

You can pass a further configuration via the syntax apply_rules (config := {...}) lemmas. The options supported are the same as for solve_by_elim (and include all the options for apply).

Equations
• One or more equations did not get rendered due to their size.

apply_rules [l₁, l₂, ...] tries to solve the main goal by iteratively applying the list of lemmas [l₁, l₂, ...] or by applying a local hypothesis. If apply generates new goals, apply_rules iteratively tries to solve those goals. You can use apply_rules [-h] to omit a local hypothesis.

apply_rules will also use rfl, trivial, congrFun and congrArg. These can be disabled, as can local hypotheses, by using apply_rules only [...].

You can use apply_rules using [a₁, ...] to use all lemmas which have been labelled with the attributes aᵢ (these attributes must be created using register_label_attr).

You can pass a further configuration via the syntax apply_rules (config := {...}). The options supported are the same as for solve_by_elim (and include all the options for apply).

apply_rules will try calling symm on hypotheses and exfalso on the goal as needed. This can be disabled with apply_rules (config := {symm := false, exfalso := false}).

You can bound the iteration depth using the syntax apply_rules (config := {maxDepth := n}).

Unlike solve_by_elim, apply_rules does not perform backtracking, and greedily applies a lemma from the list until it gets stuck.

Equations
• One or more equations did not get rendered due to their size.