Zulip Chat Archive
Stream: mathlib4
Topic: Set.image with membership hypothesis
Enrico Borba (Jan 18 2024 at 20:45):
Is there a version of Set.image that accepts a function along with a hypothesis of membership? Something like:
def Set.image' {α : Type _} {β : Type _} (s : Set α) (f : α → α ∈ s → β) : Set β
In case this is an XY problem: I have a finite set of elements U = {a₁, .., aₙ} : Set α
, and I have another set K : Set (Set α)
. For each element in U
, there exists an element in K
containing it. That is, I have hU : ∀ aᵢ ∈ U, ∃ Yᵢ ∈ K, aᵢ ∈ Yᵢ
(though there may be multiple Yᵢ
s to choose from). I want to (noncomputably) produce a set Ys : Set α
that is effectively selecting a Yᵢ
for each aᵢ
. Critically, however, I want a single Yᵢ
for each aᵢ
, as I have Set.Finite U
, and want to have Set.Finite Ys
as well. K
is infinite and there may be infinitely many Yᵢ
to choose from for each aᵢ
.
I tried to do something like {Exists.choose (hU aᵢ) | aᵢ ∈ U}
, but hU
requires a proof of aᵢ ∈ U
.
Eric Rodriguez (Jan 18 2024 at 21:09):
You can use Set.attach
Enrico Borba (Jan 18 2024 at 21:17):
Oh huh, that's an interesting idea. Let me play around with that
Enrico Borba (Jan 18 2024 at 21:18):
Also do you mean Finset.attach
?
Enrico Borba (Jan 18 2024 at 22:47):
I think this will end up working, but definitely creates some nasty types b/c of the subtype.
Enrico Borba (Jan 19 2024 at 01:12):
I think the move is actually something like
let Ys := { (hU αᵢ αᵢ.prop).choose | αᵢ : U }
Enrico Borba (Jan 19 2024 at 01:13):
Note the αᵢ : U
instead of αᵢ ∈ U
Richard Copley (Jan 19 2024 at 01:24):
Nice, and is Ys
Finite
?
If U
is a Finset
, you can write U.attach.image fun u : ↥U => (hU u.val u.property).choose
, or come up with a Function.Embedding
e : ↥U ↪ K
and write U.attach.map e
[untested (an #mwe would be useful)].
Eric Wieser (Jan 19 2024 at 01:33):
This works on your original code sample:
import Mathlib.Data.Set.Basic
def Set.image' {α : Type _} {β : Type _} (s : Set α) (f : (a : α) → a ∈ s → β) : Set β :=
{b | ∃ a ha, f a ha = b}
Eric Wieser (Jan 19 2024 at 01:35):
As does
def Set.image'' {α : Type _} {β : Type _} (s : Set α) (f : (a : α) → a ∈ s → β) : Set β :=
Subtype.rec f '' univ
Enrico Borba (Jan 19 2024 at 01:44):
Richard Copley said:
Nice, and is
Ys
Finite
?
Actually stuck on that now haha. I have Set.Finite U
.
The embedding is a good suggestion.
Enrico Borba (Jan 19 2024 at 01:49):
Let me put together a mwe, trying to prove some lemmas on chains needed for Lindenbaum's Lemma
Enrico Borba (Jan 19 2024 at 01:58):
Uh on second thought might do that (provide a mwe) later, the proof is a bit disorganized at the moment and I should reorganize it first. This has already been a big help :)
Enrico Borba (Jan 19 2024 at 02:42):
I have sort of a mwe. It's not as relevant to the question, but
import Mathlib.Data.Set.Finite
import Mathlib.Order.Chain
variable
{α : Sort _} {K : Set (Set α)}
(hK : IsChain (· ⊆ ·) K) (U₀ : Set α) (hU₀fin : Set.Finite U₀)
(map : ∀ αᵢ ∈ U₀, ∃ Yᵢ ∈ K, αᵢ ∈ Yᵢ)
theorem U₀_supset : ∃ Y ∈ K, U₀ ⊆ Y := by
sorry
is essentially what I'm trying to prove. My initial thought (and what spawned my original question) was to map each αᵢ ∈ U₀
to a Yᵢ
using map
. Then use Finset.max
by showing a linear order since they are members of the chain K
. I'm wondering now if there's a simpler solution, but that's beyond the scope of this thread :)
Enrico Borba (Jan 19 2024 at 02:45):
Maybe induction on the cardinality is simpler
Enrico Borba (Jan 19 2024 at 14:55):
just to close this out, while this can probably be golfed, I ended up solving it with induction:
import Mathlib.Data.Set.Finite
import Mathlib.Order.Chain
lemma chain_fin_subset_max
{α : Sort _} {K : Set (Set α)} (hKne : Set.Nonempty K) (hKc : IsChain (· ⊆ ·) K)
(U₀ : Set α) (hU₀fin : Set.Finite U₀)
(map : ∀ αᵢ ∈ U₀, ∃ Yᵢ ∈ K, αᵢ ∈ Yᵢ) : ∃ Y ∈ K, U₀ ⊆ Y := by
induction' h : Set.ncard U₀ with n n_ih generalizing U₀
· rw [Set.ncard_eq_zero hU₀fin] at h
rw [h]
have ⟨Y, hY⟩ := hKne
exact ⟨Y, hY, Set.empty_subset Y⟩
· have ⟨αₙ, U₀', hαₙnotin, hαₙinsert, hU₀'card⟩ := Set.eq_insert_of_ncard_eq_succ h
have hαₙ : αₙ ∈ U₀ := by rw [←hαₙinsert]; exact Set.mem_insert _ _
have hαₙinsert_sub : insert αₙ U₀' ⊆ U₀ := by rw [hαₙinsert]
have hU₀'sub : U₀' ⊂ U₀ := Set.ssubset_iff_insert.mpr ⟨αₙ, hαₙnotin, hαₙinsert_sub⟩
have hU₀'fin : Set.Finite U₀' := Set.Finite.subset hU₀fin hU₀'sub.left
have map' : ∀ αᵢ ∈ U₀', ∃ Yᵢ ∈ K, αᵢ ∈ Yᵢ := by
intro αᵢ hαᵢ
exact map αᵢ (Set.mem_of_subset_of_mem hU₀'sub.left hαᵢ)
have ⟨Y', hY'memK, hY'sup⟩ := n_ih U₀' hU₀'fin map' hU₀'card
have ⟨Yₙ, hYₙmemK, hαₙmemYₙ⟩ := map αₙ hαₙ
wlog hneq : Y' ≠ Yₙ
· simp only [ne_eq, not_not] at hneq
apply Exists.intro Y'
apply And.intro hY'memK
intro αᵢ hαᵢ
simp [←hαₙinsert] at hαᵢ
match hαᵢ with
| Or.inl hαᵢeqαₙ => rw [hαᵢeqαₙ, hneq]; exact hαₙmemYₙ
| Or.inr hαᵢmemU₀' => exact hY'sup hαᵢmemU₀'
apply Or.elim (hKc hY'memK hYₙmemK hneq)
· intro hY'subYₙ
suffices hU₀subYₙ : U₀ ⊆ Yₙ
· exact ⟨Yₙ, hYₙmemK, hU₀subYₙ⟩
intro αᵢ hαᵢ
simp [←hαₙinsert] at hαᵢ
match hαᵢ with
| Or.inl hαᵢeqαₙ => rw [hαᵢeqαₙ]; exact hαₙmemYₙ
| Or.inr hαᵢmemU₀' => exact hY'subYₙ (hY'sup hαᵢmemU₀')
· intro hYₙsub
apply Exists.intro Y'
apply And.intro hY'memK
intro αᵢ hαᵢ
simp [←hαₙinsert] at hαᵢ
match hαᵢ with
| Or.inl hαᵢeqαₙ => rw [hαᵢeqαₙ]; exact hYₙsub hαₙmemYₙ
| Or.inr hαᵢmemU₀' => exact hY'sup hαᵢmemU₀'
Eric Wieser (Jan 19 2024 at 15:30):
I get the feeling starting with induction U₀, hU₀fin using Set.Finite.dinduction_on with
would make the proof shorter
Enrico Borba (Jan 19 2024 at 15:36):
Can you explain your intuition a bit? I'm not used to using induction tactics other than induction
and induction'
Eric Wieser (Jan 19 2024 at 15:39):
lemma chain_fin_subset_max
{α : Sort _} {K : Set (Set α)} (hKne : Set.Nonempty K) (hKc : IsChain (· ⊆ ·) K)
(U₀ : Set α) (hU₀fin : Set.Finite U₀)
(map : ∀ aᵢ ∈ U₀, ∃ Yᵢ ∈ K, aᵢ ∈ Yᵢ) : ∃ Y ∈ K, U₀ ⊆ Y := by
induction U₀, hU₀fin using Set.Finite.dinduction_on with
| H0 =>
obtain ⟨Y, hY⟩ := hKne
refine ⟨Y, hY, Set.empty_subset _⟩
| @H1 a s _ _ ih =>
obtain ⟨ya, hyak, haya⟩ := map a (Set.mem_insert _ _)
obtain ⟨ys, hyk, hsys⟩ := ih fun a ha => map a (Set.mem_insert_of_mem _ ha)
obtain rfl | hne := eq_or_ne ya ys
· exact ⟨ya, hyak, Set.insert_subset haya hsys⟩
cases hKc hyk hyak hne.symm with
| inl h =>
exact ⟨ya, hyak, Set.insert_subset haya <| hsys.trans h⟩
| inr h =>
refine ⟨ys, hyk, Set.insert_subset (h haya) hsys⟩
Eric Wieser (Jan 19 2024 at 15:39):
The induction
tactic lets you pass a custom induction principle
Eric Wieser (Jan 19 2024 at 15:40):
docs#Set.Finite.dinduction_on is the one that say "a finite set can be built by adding one element at a time"
Enrico Borba (Jan 19 2024 at 15:45):
dang that is much shorter. I'll have to look at the tactic definition a bit to understand why it's a theorem that you can pass to induction
. I guess, I'm unsure what counts as an "induction principle". Had I seen Set.Finite.dinduction_on
earlier, I would have tried to use it directly with apply
.
Enrico Borba (Jan 19 2024 at 15:50):
Also, can you explain your preference with obtain
and refine
instead of have
and exact
(in the cases where they can be used instead, aka not the obtain rfl | hne
constructs).
Eric Wieser (Jan 19 2024 at 15:58):
I think that's just me being sloppy, and leaning on Lean3 muscle memory
Eric Wieser (Jan 19 2024 at 15:59):
Probably refine
should give an error saying "use exact instead"
Enrico Borba (Jan 19 2024 at 16:01):
Got it. Thanks a ton :) Honestly super impressive to see such a short proof composed so quickly haha
Eric Wieser (Jan 19 2024 at 16:03):
Well, you already wrote down the mathematical ideas first, which made it much easier
Enrico Borba (Jan 19 2024 at 16:09):
Also, i'm trying to understand this section
obtain rfl | hne := eq_or_ne ya ys
· exact ⟨ya, hyak, Set.insert_subset haya hsys⟩
it seems equivalent to
wlog hne : Yₙ ≠ Y'
· rw [ne_eq, not_not] at hne
exact ⟨Yₙ, hYₙmemK, Set.insert_subset hαₙmemYₙ (hne ▸ hY'sup)⟩
But I can't seem to wrap my head around what rfl
is being applied to, or what kind of pattern rfl | hne
is.
(sorry for the slightly renamed variables in my version)
Eric Wieser (Jan 19 2024 at 16:16):
obtain rfl | hne := eq_or_ne ya ys
is the same as obtain heq | hne := eq_or_ne ya ys
, then subst heq
on the branch that uses it
Eric Wieser (Jan 19 2024 at 16:17):
The pattern is matching against the or
, and rfl
is matching against the equality
Eric Wieser (Jan 19 2024 at 16:17):
I've not seen wlog
used in that way before, but my spelling avoids the annoying Not (Ne _ _)
that appears in yours
Enrico Borba (Jan 19 2024 at 16:19):
yeah absolutely, don't like the rw
needed to transform the negative ¬ (Yₙ ≠ Y')
. Oh, rfl
from the equality makes a bit more sense, thanks.
Hmm I'll have to reread that a few times. I might try expanding the obtains
to rcases
, and see if I understand that better.
Enrico Borba (Jan 19 2024 at 16:23):
Oh I see this from the rcases docs
:
The keyword
rfl
, which expects the hypothesis to beh : a = b
, and callssubst
on the hypothesis (which has the effect of replacingb
witha
everywhere or vice versa).
Eric Wieser (Jan 19 2024 at 16:34):
obtain $patt := $val
is pretty much identical torcases $val with $patt
Eric Wieser (Jan 19 2024 at 16:35):
So I doubt you will learn anything by rewriting obtain
to rcases
:wink:
Enrico Borba (Jan 19 2024 at 16:39):
Yeah it's just weird (to me) to see the patt
and val
swap places, but yeah it's not that much insight... I think what really cleared it up is the fact that rfl
is special grammar, and applies the equality to all of the hypotheses, and that two goals are created. Pretty clever
Last updated: May 02 2025 at 03:31 UTC