Zulip Chat Archive

Stream: mathlib4

Topic: Iff tactic


Antoine Chambert-Loir (Feb 18 2024 at 10:46):

Is there a tactic which, for a theorem that states PiffQ : ∀ (x : …) (y : …), P x y \iff Q x y, reduces it to the proof of one implication, say PtoQ : ∀ (x : …) (y : …), P x y \to Q x y, and for the converse implication adds the hypothesis PtoQ?

Michael (Feb 18 2024 at 10:47):

Iff.intro?

Yaël Dillies (Feb 18 2024 at 10:49):

https://leanprover-community.github.io/mathlib4_docs/Std/Logic.html#forall%E2%82%82_congr

Yaël Dillies (Feb 18 2024 at 10:49):

docs#forall₂_congr sadly breaks the linkifier still

Yaël Dillies (Feb 18 2024 at 10:50):

Ah sorry, I misread

Emilie (Shad Amethyst) (Feb 18 2024 at 10:50):

What about docs#forall%E2%82%82_congr ?
Nevermind

Michael (Feb 18 2024 at 10:54):

Is that what he wants? It looks like the goal is

x,y(p(x,y)q(x,y))\forall x, y \left( p(x,y) \leftrightarrow q(x,y) \right)

and he wants to split it into two goals

x,y(p(x,y)q(x,y))x,y(q(x,y)p(x,y))\forall x, y \left( p(x,y) \to q(x,y) \right) \\ \forall x, y \left( q(x,y) \to p(x,y) \right)

Emilie (Shad Amethyst) (Feb 18 2024 at 10:55):

Well, not quite, in the second goal, they would like to have access to what they proved beforehand

Michael (Feb 18 2024 at 10:56):

I thought that was automatic; once you've proved one subgoal, is it not available?

Emilie (Shad Amethyst) (Feb 18 2024 at 10:58):

The way I've been solving this issue so far was to use suffices; the forward direction can then be proven separately, and the backward direction can be proven inside of the by:

example :  (x: ) (y : ), P x y  Q x y := by
  suffices  (x : ) (y : ), P x y  Q x y by
    refine fun x y => this x y, ?rev_imp
    -- Prove Q x y → P x y here, with `this` available for `P x y → Q x y`
  -- Prove P x y → Q x y

Emilie (Shad Amethyst) (Feb 18 2024 at 11:03):

Usually though in Mathlib there are enough theorems to transform P x y into Q x y with exclusively rw, or the step that is hard to prove is isolated enough. From a quick ripgrep search, I can see that this is what's done in docs#star_le_star_iff or in docs#Ideal.subset_union_prime'

Antoine Chambert-Loir (Feb 18 2024 at 11:08):

Yes, I also do it this way, see https://github.com/leanprover-community/mathlib4/blob/02eb46065af4d2a0e05ac81b5df631e43fd45840/Mathlib/GroupTheory/Perm/Cycle/Basic.lean#L1534 but I wondered whether a clean tactic could help.

Emilie (Shad Amethyst) (Feb 18 2024 at 11:10):

It would certainly help me too, especially when making atomical theorems isn't currently a priority

Eric Wieser (Feb 18 2024 at 11:21):

How about this?

example (P Q : Prop) : P  Q := by
  refine ?h, ?_
  · sorry
  · have := ?h
    sorry

Damiano Testa (Feb 18 2024 at 11:25):

I find Eric's suggestion very clean and a great use of ?h!

Before this syntax was available, I think that quite a few of the situations where this was an issue, resolved in proving the implication ∀ (x : …) (y : …), P x y -> Q x y with weaker assumptions, so that it became just an implication, and the converse only followed with stronger assumptions. Once you have the separate, more general lemma, you can use it in the two branches, of course.

Damiano Testa (Feb 18 2024 at 11:25):

(This only works if you can find such a weakening, naturally.)

Eric Wieser (Feb 18 2024 at 11:29):

I can't get the ?h syntax to work if you need the quantification

Michael (Feb 18 2024 at 11:44):

Eric Wieser said:

I can't get the ?h syntax to work if you need the quantification

The quantification is around the \leftrightarrow, so will stripping it work?

example (α : Type) (β : Type) (p q : α  β  Prop) :
     x : α,  y : β, p x y  q x y := by
  intro x y
  -- special strategies

Michael (Feb 18 2024 at 11:50):

I guess not, when I fill in from your example, I see failed to infer 'let' declaration type.
Not sure what was wrong, but it does appear to work:

example (α : Type) (β : Type) (p q : α  β  Prop) :
     x : α,  y : β, p x y  q x y := by
  intro x y
  -- special strategies
  refine ?hmp, ?hmpr
  sorry
  have h := ?hmp
  sorry

But this only preserves p x y → q x y for the particular arbitrary x and y that are introduced.

Eric Wieser (Feb 18 2024 at 12:18):

Yes, that was my point, sorry for not being clearer; the quantification is absent from the extracted goal

Michael (Feb 18 2024 at 12:32):

the trick still works if you provide your own theorem:

theorem univ_iff {α : Type} {β : Type} {p q : α  β  Prop} :
    ( x : α,  y : β, p x y  q x y) 
      ( x : α,  y : β, p x y  q x y) 
      ( x : α,  y : β, q x y  p x y) := by
  sorry

example (α : Type) (β : Type) (p q : α  β  Prop) :
     x : α,  y : β, p x y  q x y := by
  rw [univ_iff]
  refine ?hmp, ?hmpr
  sorry
  have h := ?hmp
  sorry

Michael (Feb 18 2024 at 12:35):

This doesn't work:

example (α : Type) (β : Type) (p q : α  β  Prop) :
     x : α,  y : β, p x y  q x y := by
  rw [univ_iff]
  refine ?hmp, ?hmpr
  case hmp => sorry
  have h := ?hmp
  sorry

I'd really like to know what the deep difference is between solving case hmp implicitly, because it's the first one in the default sequence, and solving it explicitly by calling it case hmp.

Eric Wieser (Feb 18 2024 at 12:36):

simp_rw [iff_iff_implies_and_implies, forall_and] removes the need for univ_iff

Antoine Chambert-Loir (Feb 18 2024 at 13:19):

I should have been clearer: in my application case, I need to retain the forall quantification, because the reverse implication is obtained by applying the forward one to other elements than the obvious ones.

Eric Wieser (Feb 18 2024 at 13:55):

I think this is a niche enough case that either using suffices or writing a standalone lemma for the implication is a reasonable choice.

Eric Wieser (Feb 18 2024 at 13:56):

(As @Damiano Testa comments, it is very common that the implication is true more generally. Even cases where it isn't, the implication is often handy to have for dot notation)

Kyle Miller (Feb 18 2024 at 17:18):

I just made a prototype of a constructor! generalizing x y tactic. It looks like this:

example (P Q : Nat  Int  Prop) :  x y, P x y  Q x y := by
  intros x y
  constructor! generalizing x y
  /-
  case mp
  P Q : ℕ → ℤ → Prop
  x : ℕ
  y : ℤ
  ⊢ P x y → Q x y

  case mpr
  P Q : ℕ → ℤ → Prop
  h✝ : ∀ (x : ℕ) (y : ℤ), P x y → Q x y
  x : ℕ
  y : ℤ
  ⊢ Q x y → P x y
  -/

Kyle Miller (Feb 18 2024 at 17:19):

code v1

Kyle Miller (Feb 18 2024 at 17:21):

A nice extension to this would be a with clause to name the hypotheses for successive goals. It also is missing code to link up variables for the unused variable checker (see how docs#Lean.MVarId.withReverted uses pushInfoLeaf)

Kyle Miller (Feb 18 2024 at 17:30):

Here's an extension that handles @Antoine Chambert-Loir's original case.

It will auto-intro, apply constructors, and revert:

example (P Q : Nat  Int  Prop) :  x y, P x y  Q x y := by
  constructor!
  /-
  case mp
  P Q : ℕ → ℤ → Prop
  ⊢ ∀ (x : ℕ) (y : ℤ), P x y → Q x y

  case mpr
  P Q : ℕ → ℤ → Prop
  h✝: ∀ (x : ℕ) (y : ℤ), P x y → Q x y
  ⊢ ∀ (x : ℕ) (y : ℤ), Q x y → P x y
  -/

It also interacts with this generalizing clause:

example (P Q : Nat  Int  Prop) :  x y, P x y  Q x y := by
  intro x
  constructor! generalizing x
  /-
  case mp
  P Q : ℕ → ℤ → Prop
  x : ℕ
  ⊢ ∀ (y : ℤ), P x y → Q x y

  case mpr
  P Q : ℕ → ℤ → Prop
  h✝: ∀ (x : ℕ) (y : ℤ), P x y → Q x y
  x : ℕ
  ⊢ ∀ (y : ℤ), Q x y → P x y
  -/

Kyle Miller (Feb 18 2024 at 17:30):

code v2

Yaël Dillies (Feb 18 2024 at 22:06):

What's the ! in the name referring to?

Jireh Loreaux (Feb 18 2024 at 22:09):

It means "Lean, try hard to construct it!" :laughing:

Kyle Miller (Feb 18 2024 at 22:29):

Yeah, and it's constructor with bells and whistles, which tend to be loud!


Last updated: May 02 2025 at 03:31 UTC