Documentation

Mathlib.Tactic.TFAE

The Following Are Equivalent (TFAE) #

This file provides the tactics tfae_have and tfae_finish for proving goals of the form TFAE [P₁, P₂, ...].

Parsing and syntax #

We implement tfae_have in terms of a syntactic have. To support as much of the same syntax as possible, we recreate the parsers for have, except with the changes necessary for tfae_have.

A tfae_have type specification, e.g. 1 ↔ 3 The numbers refer to the proposition at the corresponding position in the TFAE goal (starting at 1).

Instances For

    The following parsers are similar to those for have in Lean.Parser.Term, but instead of optType, we use tfaeType := num >> impArrow >> num (as a tfae_have invocation must always include this specification). Also, we disallow including extra binders, as that makes no sense in this context; we also include " : " after the binder to avoid breaking tfae_have 1 → 2 syntax (which, unlike have, omits " : ").

    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 := t adds a hypothesis in the reverse direction, of type Pⱼ → Pᵢ.
    • tfae_have i ↔ j := t adds a hypothesis in the both directions, of type Pᵢ ↔ Pⱼ.
    • tfae_have hij : i → j := t names the introduced hypothesis hij instead of tfae_i_to_j.
    • tfae_have i j | p₁ => t₁ | ... matches on the assumption p : Pᵢ.
    • tfae_have ⟨hij, hji⟩ : i ↔ j := t destructures the bi-implication into hij : Pᵢ → Pⱼ and hji : Pⱼ → Pⱼ.
    • tfae_have i → j := t ?a creates 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
    
    Instances For

      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
      
      Instances For

        Setup #

        Extract a list of Prop expressions from an expression of the form TFAE [P₁, P₂, ...] as long as [P₁, P₂, ...] is an explicit list.

        Instances For

          Proof construction #

          partial def Mathlib.Tactic.TFAE.dfs (hyps : Array ( × × Lean.Expr)) (atoms : Array Q(Prop)) (i j : ) (P P' : Q(Prop)) (hP : Q(«$P»)) :

          Uses depth-first search to find a path from P to P'.

          def Mathlib.Tactic.TFAE.proveImpl (hyps : Array ( × × Lean.Expr)) (atoms : Array Q(Prop)) (i j : ) (P P' : Q(Prop)) :
          Lean.MetaM Q(«$P»«$P'»)

          Prove an implication via depth-first traversal.

          Instances For
            partial def Mathlib.Tactic.TFAE.proveChain (hyps : Array ( × × Lean.Expr)) (atoms : Array Q(Prop)) (i : ) (is : List ) (P : Q(Prop)) (l : Q(List Prop)) :
            Lean.MetaM Q(List.IsChain (fun (x1 x2 : Prop) => x1x2) («$P» :: «$l»))

            Generate a proof of Chain (· → ·) P l. We assume P : Prop and l : List Prop, and that l is an explicit list.

            partial def Mathlib.Tactic.TFAE.proveGetLastDImpl (hyps : Array ( × × Lean.Expr)) (atoms : Array Q(Prop)) (i i' : ) (is : List ) (P P' : Q(Prop)) (l : Q(List Prop)) :
            Lean.MetaM Q(«$l».getLastD «$P'»«$P»)

            Attempt to prove getLastD l P' → P given an explicit list l.

            def Mathlib.Tactic.TFAE.proveTFAE (hyps : Array ( × × Lean.Expr)) (atoms : Array Q(Prop)) (is : List ) (l : Q(List Prop)) :
            Lean.MetaM Q(«$l».TFAE)

            Attempt to prove a statement of the form TFAE [P₁, P₂, ...].

            Instances For

              tfae_have components #

              def Mathlib.Tactic.TFAE.mkTFAEId :
              Lean.TSyntax `Mathlib.Tactic.TFAE.Parser.tfaeTypeLean.MacroM Lean.Name

              Construct a name for a hypothesis introduced by tfae_have.

              Instances For

                Turn syntax for a given index into a natural number, as long as it lies between 1 and maxIndex.

                Instances For

                  Tactic implementation #

                  def Mathlib.Tactic.TFAE.elabTFAEType (tfaeList : List Q(Prop)) :
                  Lean.TSyntax `Mathlib.Tactic.TFAE.Parser.tfaeTypeLean.Elab.TermElabM Lean.Expr

                  Accesses the propositions at indices i and j of tfaeList, and constructs the expression Pi <arr> Pj, which will be the type of our tfae_have hypothesis

                  Instances For

                    Deprecated "Goal-style" tfae_have #

                    This syntax and its implementation, which behaves like "Mathlib have" is deprecated; we preserve it here to provide graceful deprecation behavior.

                    Re-enables "goal-style" syntax for tfae_have when true.

                    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 := t adds a hypothesis in the reverse direction, of type Pⱼ → Pᵢ.
                    • tfae_have i ↔ j := t adds a hypothesis in the both directions, of type Pᵢ ↔ Pⱼ.
                    • tfae_have hij : i → j := t names the introduced hypothesis hij instead of tfae_i_to_j.
                    • tfae_have i j | p₁ => t₁ | ... matches on the assumption p : Pᵢ.
                    • tfae_have ⟨hij, hji⟩ : i ↔ j := t destructures the bi-implication into hij : Pᵢ → Pⱼ and hji : Pⱼ → Pⱼ.
                    • tfae_have i → j := t ?a creates 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
                    
                    Instances For