Documentation

Mathlib.Tactic.Convert

The convert tactic. #

The exact e and refine e tactics require a term e whose type is definitionally equal to the goal. convert e is similar to refine e, but the type of e is not required to exactly match the goal. Instead, new goals are created for differences between the type of e and the goal using the same strategies as the congr! tactic. For example, in the proof state

n : ℕ,
e : Prime (2 * n + 1)
⊢ Prime (n + n + 1)

the tactic convert e will change the goal to

⊢ n + n = 2 * n

In this example, the new goal can be solved using ring.

The convert tactic applies congruence lemmas eagerly before reducing, therefore it can fail in cases where exact succeeds:

def p (n : ℕ) := True
example (h : p 0) : p 1 := by exact h -- succeeds
example (h : p 0) : p 1 := by convert h -- fails, with leftover goal `1 = 0`

Limiting the depth of recursion can help with this. For example, convert h using 0 will work in this case.

The syntax convert ← e will reverse the direction of the new goals (producing ⊢ 2 * n = n + n in this example).

Internally, convert e works by creating a new goal asserting that the goal equals the type of e, then simplifying it using congr!. The syntax convert e using n can be used to control the depth of matching (like congr! n). In the example, convert e using 1 would produce a new goal ⊢ n + n + 1 = 2 * n + 1.

Refer to the congr! tactic to understand the congruence operations. One of its many features is that if x y : t and an instance Subsingleton t is in scope, then any goals of the form x = y are solved automatically.

Like congr!, convert takes an optional with clause of rintro patterns, for example convert e using n with x y z.

The convert tactic also takes a configuration option, for example

convert (config := {transparency := .default}) h

These are passed to congr!. See Congr!.Config for options.

Configuration for the convert family of tactics. This is Congr!.Config with different, less aggressive, defaults.

To elaborate config options for convert, use Convert.elabConfig which chooses between Convert.CheapConfig and Convert.ExpensiveConfig based on other flags.

Instances For

    Internal elaborator for Convert.CheapConfig: use Convert.elabConfig instead.

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

      Configuration for the convert! family of tactics. This is Convert.CheapConfig (used by convert without exclamation mark) with different, more aggressive, defaults.

      To elaborate config options for convert, use Convert.elabConfig which chooses between Convert.CheapConfig and Convert.ExpensiveConfig based on other flags.

      We separate out the two structures to allow the user to explicitly set options in the call, so for example the following call runs at .instances transparency.

      convert! (postTransparency := .instances)
      
      Instances For

        Internal elaborator for Convert.ExpensiveConfig: use Convert.elabConfig instead.

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

          Configuration elaborator for the convert/convert! family of tactics.

          If expensive is true, we're elaborating for convert!, and will configure to run at default transparency (unless explicitly overridden by the user saying e.g. (transparency := .instances).)

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            def Lean.MVarId.convert (e : Expr) (symm : Bool) (depth : Option := none) (config : Congr!.Config := { }) (patterns : List (TSyntax `rintroPat) := []) (g : MVarId) :

            Close the goal g using Eq.mp v e, where v is a metavariable asserting that the type of g and e are equal. Then call MVarId.congrN! (also using local hypotheses and reflexivity) on v, and return the resulting goals.

            With symm = true, reverses the equality in v, and uses Eq.mpr v e instead. With depth = some n, calls MVarId.congrN! n instead, with n as the max recursion depth.

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For
              def Lean.MVarId.convertLocalDecl (g : MVarId) (fvarId : FVarId) (typeNew : Expr) (symm : Bool) (depth : Option := none) (config : Congr!.Config := { }) (patterns : List (TSyntax `rintroPat) := []) :

              Replaces the type of the local declaration fvarId with typeNew, using Lean.MVarId.congrN! to prove that the old type of fvarId is equal to typeNew. Uses Lean.MVarId.replaceLocalDecl to replace the type. Returns the new goal along with the side goals generated by congrN!.

              With symm = true, reverses the equality, changing the goal to prove typeNew is equal to typeOld. With depth = some n, calls MVarId.congrN! n instead, with n as the max recursion depth.

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

                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! e uses default transparency, rather than reducible, when solving side goals, and it tries to apply congruence even if the two expressions do not have the same head constant.
                • convert ← e creates equality goals in the opposite direction (with the goal type on the right).
                • convert e using n, where n is a numeral, controls the depth with which congruence is applied. For example, if the main goal is Prime (n + n + 1) and e : Prime (2 * n + 1), then convert e using 2 results in one goal, ⊢ n + n = 2 * n, and convert e using 3 (or more) results in two (impossible) goals HAdd.hAdd = HMul.hMul and ⊢ 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, like rintro x ⟨y₁, y₂⟩ (z₁ | z₂) would.
                • convert (config := cfg) e uses the configuration options in cfg to control the congruence rules (see Congr!.Config).

                Examples:

                example {n : ℕ} (e : Prime (2 * n + 1)) :
                    Prime (n + n + 1) := by
                  convert e
                  -- One goal: ⊢ n + n = 2 * n
                  ring
                
                -- `convert` can fail where `exact` succeeds.
                def p (n : ℕ) := True
                example (h : p 0) : p 1 := by
                  fail_if_success
                    convert h -- fails, left-over goal 1 = 0
                    done
                  exact h -- succeeds
                
                -- `convert with` names introduced variables.
                example (p q : Nat → Prop) (h : ∀ ε > 0, p ε) :
                    ∀ ε > 0, q ε := by
                  convert h with ε hε
                  -- Goal now looks like:
                  -- hε : ε > 0
                  -- ⊢ q ε ↔ p ε
                  sorry
                
                Equations
                • One or more equations did not get rendered due to their size.
                Instances For

                  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! e uses default transparency, rather than reducible, when solving side goals, and it tries to apply congruence even if the two expressions do not have the same head constant.
                  • convert ← e creates equality goals in the opposite direction (with the goal type on the right).
                  • convert e using n, where n is a numeral, controls the depth with which congruence is applied. For example, if the main goal is Prime (n + n + 1) and e : Prime (2 * n + 1), then convert e using 2 results in one goal, ⊢ n + n = 2 * n, and convert e using 3 (or more) results in two (impossible) goals HAdd.hAdd = HMul.hMul and ⊢ 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, like rintro x ⟨y₁, y₂⟩ (z₁ | z₂) would.
                  • convert (config := cfg) e uses the configuration options in cfg to control the congruence rules (see Congr!.Config).

                  Examples:

                  example {n : ℕ} (e : Prime (2 * n + 1)) :
                      Prime (n + n + 1) := by
                    convert e
                    -- One goal: ⊢ n + n = 2 * n
                    ring
                  
                  -- `convert` can fail where `exact` succeeds.
                  def p (n : ℕ) := True
                  example (h : p 0) : p 1 := by
                    fail_if_success
                      convert h -- fails, left-over goal 1 = 0
                      done
                    exact h -- succeeds
                  
                  -- `convert with` names introduced variables.
                  example (p q : Nat → Prop) (h : ∀ ε > 0, p ε) :
                      ∀ ε > 0, q ε := by
                    convert h with ε hε
                    -- Goal now looks like:
                    -- hε : ε > 0
                    -- ⊢ q ε ↔ p ε
                    sorry
                  
                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For

                    Elaborates term ensuring the expected type, allowing stuck metavariables. Returns stuck metavariables as additional goals.

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

                      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! t uses default transparency, rather than reducible, when solving side goals.
                      • convert_to ty at h changes the type of the local hypothesis h to ty. If later local hypotheses or the goal depend on h, then convert_to t at h may leave a copy of h.
                      • convert_to ← t creates equality goals in the opposite direction (with the original goal type on the right).
                      • convert_to t using n, where n is a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is Prime (n + n + 1), then convert_to Prime (2 * n + 1) using 2 results in one goal, ⊢ n + n = 2 * n, and convert_to Prime (2 * n + 1) using 3 (or more) results in two (impossible) goals HAdd.hAdd = HMul.hMul and ⊢ n = 2. The default value for n is 1.
                      • convert_to t with x ⟨y₁, y₂⟩ (z₁ | z₂) names or pattern-matches the variables introduced by congruence rules, like rintro x ⟨y₁, y₂⟩ (z₁ | z₂) would.
                      • convert_to (config := cfg) t uses the configuration options in cfg to control the congruence rules (see Congr!.Config).
                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For

                        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! t uses default transparency, rather than reducible, when solving side goals.
                        • convert_to ty at h changes the type of the local hypothesis h to ty. If later local hypotheses or the goal depend on h, then convert_to t at h may leave a copy of h.
                        • convert_to ← t creates equality goals in the opposite direction (with the original goal type on the right).
                        • convert_to t using n, where n is a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is Prime (n + n + 1), then convert_to Prime (2 * n + 1) using 2 results in one goal, ⊢ n + n = 2 * n, and convert_to Prime (2 * n + 1) using 3 (or more) results in two (impossible) goals HAdd.hAdd = HMul.hMul and ⊢ n = 2. The default value for n is 1.
                        • convert_to t with x ⟨y₁, y₂⟩ (z₁ | z₂) names or pattern-matches the variables introduced by congruence rules, like rintro x ⟨y₁, y₂⟩ (z₁ | z₂) would.
                        • convert_to (config := cfg) t uses the configuration options in cfg to control the congruence rules (see Congr!.Config).
                        Equations
                        • One or more equations did not get rendered due to their size.
                        Instances For

                          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 uses default transparency, rather than reducible, when solving side goals.
                          • ac_change t using n, where n is a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is Prime ((a * b + 1) + c), then ac_change Prime ((1 + a * b) + c) using 2 solves the side goals, and ac_change Prime ((1 + a * b) + c) using 3 (or more) results in two (impossible) goals ⊢ 1 = a * b and ⊢ a * b = 1. The default value for n is 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
                          
                          Equations
                          • One or more equations did not get rendered due to their size.
                          Instances For

                            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 uses default transparency, rather than reducible, when solving side goals.
                            • ac_change t using n, where n is a positive numeral, controls the depth with which congruence is applied. For example, if the main goal is Prime ((a * b + 1) + c), then ac_change Prime ((1 + a * b) + c) using 2 solves the side goals, and ac_change Prime ((1 + a * b) + c) using 3 (or more) results in two (impossible) goals ⊢ 1 = a * b and ⊢ a * b = 1. The default value for n is 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
                            
                            Equations
                            • One or more equations did not get rendered due to their size.
                            Instances For