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
and he wants to split it into two goals
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 , 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