Zulip Chat Archive
Stream: mathlib4
Topic: mem_image
Yury G. Kudryashov (Dec 25 2023 at 21:45):
I think that this was discussed some time ago but I can't quickly find the thread. What do you think about removing @[simp]
from lemmas like docs#Set.mem_image and moving it to lemmas like docs#Set.ball_image_iff and docs#Set.biUnion_image ?
Yury G. Kudryashov (Dec 25 2023 at 21:45):
IMHO, in case of docs#Set.mem_image, docs#Set.mem_range, and docs#Set.mem_image2, the RHS is not simpler than LHS.
Yury G. Kudryashov (Dec 25 2023 at 21:54):
Also, this creates simp
confluence issues when we have something like ⋃ y ∈ f '' s, g y
but there is a simp
lemma for ⋃ x ∈ s, _
that stops Lean from applying docs#Set.iUnion_iUnion_eq_right
Eric Wieser (Dec 25 2023 at 22:21):
I think this was discussed before, perhaps pre-lean4. It would be good to find the old thread.
Yury G. Kudryashov (Dec 25 2023 at 22:26):
I tried and failed.
Yaël Dillies (Dec 26 2023 at 07:29):
I'm a priori not super happy with such a change, but good alternative simp lemmas could convince me otherwise.
Yaël Dillies (Dec 26 2023 at 07:29):
My hunch is that a lot of proofs of the form by ext; simp
will break.
Yaël Dillies (Dec 26 2023 at 07:30):
For confluence on ⋃ y ∈ f '' s, g y
, I would think this just means that we're missing simp lemmas for ⋃
mimicking the basic logic ones
Yury G. Kudryashov (Dec 26 2023 at 14:27):
We do have docs#Set.iUnion_iUnion_eq_right but it doesn't work if Lean can simplify x ∈ s
. The same happens in a simpler case:
import Mathlib.Data.Set.Lattice
example {f : ℕ → ℕ} {s t : Set ℕ} :
(∀ y ∈ f '' (s ∩ t), y = 0) ↔ ∀ x ∈ s ∩ t, f x = 0 := by
simp
guard_target =ₛ (∀ y x : ℕ, x ∈ s → x ∈ t → f x = y → y = 0) ↔ ∀ x ∈ s, x ∈ t → f x = 0
example {f : ℕ → ℕ} {s t : Set ℕ} :
(∀ y ∈ f '' (s ∪ t), y = 0) ↔ ∀ x ∈ s ∪ t, f x = 0 := by
simp -- success
example {f : ℕ → ℕ} {s : ℕ → Set ℕ} {t : Set ℕ} :
(∀ y ∈ f '' (⋃ i ∈ t, s i), y = 0) ↔ ∀ x ∈ ⋃ i ∈ t, s i, f x = 0 := by
simp
guard_target =ₛ (∀ (y x x_1 : ℕ), x_1 ∈ t → x ∈ s x_1 → f x = y → y = 0) ↔
∀ (x x_1 : ℕ), x_1 ∈ t → x ∈ s x_1 → f x = 0
example {f : ℕ → ℕ} {s : ℕ → Set ℕ} {t : Set ℕ} :
(∀ y ∈ f '' (⋂ i ∈ t, s i), y = 0) ↔ ∀ x ∈ ⋂ i ∈ t, s i, f x = 0 := by
simp -- success
Eric Wieser (Dec 26 2023 at 15:36):
Here's one old message I found:
Gabriel Ebner said:
Another one that annoys me greatly is
Set.mem_image
, which I always have to disable because what I actually want isSet.ball_image_iff
.
Eric Wieser (Dec 26 2023 at 15:39):
And another
Sebastien Gouezel said:
By the way, is this really a good simp lemma? It turns something into an existential, which is not very good as a normal form because it is hard to manipulate (Lean will almost never be able to guess the right
y
to discharge such a proof obligation).
Yaël Dillies (Dec 26 2023 at 15:47):
We certainly can try removing it
Yury G. Kudryashov (Dec 26 2023 at 16:00):
I'll try after #9275
Kyle Miller (Dec 26 2023 at 16:04):
I'm wondering if this is suggesting a different design for "cute" binders. For example, if we had a separate notation and definition for bounded quantifiers
def BForall {α β : Type*} [Membership α β] (dom : β) (p : (x : α) → Prop) : Prop :=
∀ x, x ∈ dom → p x
macro (priority := high) "∀ " n:ident " ∈ " s:term ", " p:term : term =>
`(BForall $s (fun $n => $p))
-- LHS is `BForall (Set.Icc 0 1) fun x ↦ x < 2`
#check (rfl : (∀ x ∈ Set.Icc 0 1, x < 2) = (∀ x, x ∈ Set.Icc 0 1 → x < 2))
then we could be sure that Set.ball_image_iff
would get applied rather than Set.mem_image
.
The tradeoff would be needing specialized lemmas for handling BForall
as well as potentially needing to modify tactics to be BForall
-aware. While intro
would be able to see through it for example, intros
would not...
Yury G. Kudryashov (Dec 26 2023 at 16:15):
Do you suggest introducing BForall
, BExists
, Set.biUnion
etc?
Mario Carneiro (Dec 26 2023 at 16:26):
another alternative is for simp to just "get good" at handling forall x, (exist y, x = f y) -> P x
simplification. Isabelle is able to simplify this using a simpproc
Kyle Miller (Dec 26 2023 at 17:03):
@Yury G. Kudryashov Yeah, that's the suggestion. It's just an idea I thought I'd mention which didn't seem immediately bad. I came up with it because it's something I noticed is necessary when making a framework for binders over different types of containers -- not everything can use the nesting trick, for example Finset.sum
can't, and it's easier to handle when binders have both a raw type for the bound variable along with some object representing its domain.
I'm not suggesting this very seriously though.
Last updated: May 02 2025 at 03:31 UTC