Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(topology): prove a space is preconnected iff every continuous ma… #16974

Closed
wants to merge 1 commit into from

Conversation

dagurtomas
Copy link
Collaborator

…p to a discrete space is constant

this useful characterisation of connectedness was missing from mathlib.


Open in Gitpod

…p to a discrete space is constant

this useful characterisation of connectedness was missing from mathlib.
@dagurtomas dagurtomas added awaiting-review The author would like community review of the PR t-topology Topological spaces, uniform spaces, metric spaces, filters labels Oct 14, 2022
@PatrickMassot PatrickMassot self-assigned this Oct 14, 2022
Copy link
Collaborator

@alreadydone alreadydone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! I'll look at the proofs later if no one beats me to it :)

Copy link
Member

@PatrickMassot PatrickMassot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for this first contribution! I let detailed comments in the beginning, but at some point the only efficient thing to do is to redo everything. I still hope you'll learn stuff from reading this after making your own version.

My first advice is to take seriously the fact that you want a bool-valued indicator function. So I created one, without relying on set.indicator because I didn't want to drag in all the dependencies of that function. You get:

open bool

namespace set
variables {α : Type*} (s : set α)

def bool_indicator (x : α) := 
@ite _ (x ∈ s) (classical.prop_decidable _) tt ff

lemma mem_iff_bool_indicator (x : α) : x ∈ s ↔ s.bool_indicator x = tt :=
by { unfold bool_indicator, split_ifs ; tauto }

lemma not_mem_iff_bool_indicator (x : α) : x ∉ s ↔ s.bool_indicator x = ff :=
by { unfold bool_indicator, split_ifs ; tauto }

lemma preimage_bool_indicator_tt : s.bool_indicator ⁻¹' {tt} = s :=
ext (λ α, (s.mem_iff_bool_indicator α).symm)

lemma preimage_bool_indicator_ff : s.bool_indicator ⁻¹' {ff} = sᶜ :=
ext (λ α, (s.not_mem_iff_bool_indicator α).symm)

open_locale classical

lemma preimage_bool_indicator_eq_union (t : set bool) :
  s.bool_indicator ⁻¹' t = (if tt ∈ t then s else ∅) ∪ (if ff ∈ t then sᶜ else ∅) :=
begin
  ext α,
  dsimp [bool_indicator],
  split_ifs ; tauto
end

lemma preimage_bool_indicator (t : set bool) :
  s.bool_indicator ⁻¹' t = univ ∨ s.bool_indicator ⁻¹' t = s ∨ 
  s.bool_indicator ⁻¹' t = sᶜ ∨ s.bool_indicator ⁻¹' t = ∅ :=
begin
  simp only [preimage_bool_indicator_eq_union],
  split_ifs ; simp [s.union_compl_self]
end

end set

to put somewhere in data.set.basic or a new file in the data.set folder. Also in data.set.basic we can add:

lemma preimage_subtype_coe_eq_compl {α : Type*} {s u v : set α} (hsuv : s ⊆ u ∪ v)
  (H : s ∩ (u ∩ v) = ∅) : (coe : s → α) ⁻¹' u = (coe ⁻¹' v)ᶜ :=
begin
  ext ⟨x, x_in_s⟩,
  split,
  { intros x_in_u x_in_v,
    exact eq_empty_iff_forall_not_mem.mp H x ⟨x_in_s, ⟨x_in_u, x_in_v⟩⟩ },
  { intro hx,
    exact or.elim (hsuv x_in_s) id (λ hx', hx.elim hx') }
end

Note that nothing above has anything to do with topology, so it definitely shouldn't be anywhere near the topology folder.

Inside the topology folder, next to the definition of clopen sets, you can put

variables {X : Type*} [topological_space X]

lemma continuous_bool_indicator_iff_clopen (U : set X) :
  continuous U.bool_indicator ↔ is_clopen U :=
begin
  split,
  { intros hc,
    rw ← U.preimage_bool_indicator_tt,
    exact ⟨hc.is_open_preimage _ trivial, continuous_iff_is_closed.mp hc _ (is_closed_discrete _)⟩ },
  { refine λ hU, ⟨λ s hs, _⟩,
    rcases U.preimage_bool_indicator s with (h|h|h|h) ; rw h,
    exacts [is_open_univ, hU.1, hU.2.is_open_compl, is_open_empty] },
end

lemma continuous_on_indicator_iff_clopen (s U : set X) :
  continuous_on U.bool_indicator s ↔ is_clopen ((coe : s → X) ⁻¹' U) :=
begin
  rw [continuous_on_iff_continuous_restrict, ← continuous_bool_indicator_iff_clopen],
  refl
end

All this is nice and useful and has nothing to do with connected sets. We've been doing what is called "filling API holes before tackling the stuff you actually care about". Note that some lemmas above won't be used in our main target, but they are expected once you define set.bool_indicator for instance. Now we can move to the file defining connected set, and we no longer need to create a new file there. First one implication is essentially already there, so let's simply state it.

lemma is_preconnected.constant {Y : Type*} [topological_space Y] [discrete_topology Y]
  {s : set X} (hs : is_preconnected s) {f : X → Y} (hf : continuous_on f s) 
  {x y : X} (hx : x ∈ s) (hy : y ∈ s) : f x = f y :=
(hs.image f hf).subsingleton (mem_image_of_mem f hx) (mem_image_of_mem f hy)

The converse implication is where we'll need the preliminaries.

lemma is_preconnected_of_forall_constant {s : set X} 
  (hs : ∀ f : X → bool, continuous_on f s → ∀ x ∈ s, ∀ y ∈ s, f x = f y) : is_preconnected s := 
begin
  unfold is_preconnected,
  by_contra',
  rcases this with ⟨u, v, u_op, v_op, hsuv, ⟨x, x_in_s, x_in_u⟩, ⟨y, y_in_s, y_in_v⟩, H⟩,
  rw [not_nonempty_iff_eq_empty] at H,
  have hy : y ∉ u,
    from λ y_in_u, eq_empty_iff_forall_not_mem.mp H y ⟨y_in_s, ⟨y_in_u, y_in_v⟩⟩,
  have : continuous_on u.bool_indicator s,
  { apply (continuous_on_indicator_iff_clopen _ _).mpr ⟨_, _⟩,
    { exact continuous_subtype_coe.is_open_preimage u u_op },
    { rw preimage_subtype_coe_eq_compl hsuv H,
      exact (continuous_subtype_coe.is_open_preimage v v_op).is_closed_compl } },
  simpa [(u.mem_iff_bool_indicator _).mp x_in_u, (u.not_mem_iff_bool_indicator _).mp hy] using 
    hs _ this x x_in_s y y_in_s
end

Then you need to add a version for preconnected_space.

Thanks again for you contribution and I hope you'll learn some interesting stuff from this review!

noncomputable theory

instance has_zero_bool : has_zero bool := ⟨⊥⟩
def cst_top (X : Type*) : X → bool := λ x, ⊤
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is function.const X tt.


instance has_zero_bool : has_zero bool := ⟨⊥⟩
def cst_top (X : Type*) : X → bool := λ x, ⊤
def cst_top' (X : Type) : X → bool := λ x, ⊤
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you feel you need that less general version? Does anything break if you replace all uses of cst_top' with cst_top?

have htop : ⊤ ≠ (0 : bool) := by tauto,
rw ← hx at htop,
exact set.mem_of_indicator_ne_zero htop },
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For such statements that intuitively require no proof at all, the tradition is to compress the proof. Here you can write the exact same proof as

⟨λ hx, set.indicator_of_mem hx _, 
 λ hx, set.mem_of_indicator_ne_zero 
   (hx.symm ▸ (dec_trivial : ⊤ ≠ (0 : bool)) : U.indicator (cst_top X) x ≠ 0)⟩

(without begin and end, this is a proof term). For readers this is a clear indication that they don't want to see this proof.

have h₁ : ∀ s : set bool, is_open (f ⁻¹' s) := λ s, continuous_def.mp hc s trivial,
have h₂ : ∀ s : set bool, is_closed (f ⁻¹' s) :=
λ s, continuous_iff_is_closed.mp hc s (is_closed_discrete s),
simp at *,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should never let such a line in a finished proof that needs to be maintainable. If someone adds a lemma to the simp set then the behavior of this line will change and the remaining part of the proof will be broken in a way that will be very difficult to diagnose. In this specific case, that line also does nothing at all in your proof.

have h₂ : ∀ s : set bool, is_closed (f ⁻¹' s) :=
λ s, continuous_iff_is_closed.mp hc s (is_closed_discrete s),
simp at *,
specialize h {⊤},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line isn't used at all. It's fine for exploration, but you need to cleanup before opening a PR.

end

def continuous_to_discrete {X Y : Type*} (f : X → Y) [topological_space X] : Prop :=
∀ s : set Y, is_open (f ⁻¹' s)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definition is a bad idea because it won't play well with the rest of mathlib.

[topological_space Y] [discrete_topology Y] :
continuous_to_discrete f ↔ continuous f :=
begin
split, swap, { exact λ hf s, continuous_def.mp hf s (is_open_discrete s) },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This swap shouldn't stay in the final proof since it was only a psychological help for you.

continuous_to_discrete f ↔ continuous f :=
begin
split, swap, { exact λ hf s, continuous_def.mp hf s (is_open_discrete s) },
tidy,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to avoid letting such an expensive tactic when a faster one would do the job. You could replace this proof with

⟨λ h, ⟨by tauto⟩, λ hf s, continuous_def.mp hf s (is_open_discrete s)⟩

for instance. Better, you could replace by tauto with λ s _, h s which is the actual proof (you can even use show_term to get that proof term).

tidy,
end

def continuous_to_discrete_imp_constant {X Y : Type*} (α : set X) (f : X → Y)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introducing this definition to use it only twice is a bad idea. Either you really need a definition and you need to prove a bunch of basic lemmas about it to make it useful or you don't need it.

Everything below this point starts being really suboptimal, and I think it's more efficient to show you how to do it in a more efficient way.

end

lemma is_preconnected_iff_continuous_to_bool_imp_constant {X : Type*} (α : set X)
[topological_space X] [decidable_pred (∈ α)] :
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[decidable_pred (∈ α)] shouldn't be in the statement since it is not needed to state the lemma. You can remove it and start the proof with classical.

@PatrickMassot PatrickMassot added awaiting-author A reviewer has asked the author a question or requested changes and removed awaiting-review The author would like community review of the PR labels Oct 14, 2022
@dagurtomas
Copy link
Collaborator Author

Thank you for your detailed feedback, Patrick! It is certainly very helpful and I'm sure I'll learn a lot from it. I'll try to change the PR according to your suggestions.

@dagurtomas
Copy link
Collaborator Author

I've created a new PR #17070 which completely redoes this as Patrick suggests. Closing this one now.

@dagurtomas dagurtomas closed this Oct 19, 2022
bors bot pushed a commit that referenced this pull request Oct 21, 2022
… a space is preconnected iff every continuous map to a discrete space is constant (#17070)

This useful characterisation was missing from mathlib. 
Closes #16974 by completely redoing it as suggested by Patrick Massot. 

Co-authored-by: Patrick Massot <patrick.massot@math.cnrs.fr>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting-author A reviewer has asked the author a question or requested changes t-topology Topological spaces, uniform spaces, metric spaces, filters
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants