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
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
234 changes: 234 additions & 0 deletions src/topology/preconnected_characterisation.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
/-
Copyright (c) 2022 Dagur Asgeirsson. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Dagur Asgeirsson
-/
import topology.connected
import algebra.indicator_function

/-!
# Characterisation of preconnected spaces in terms of continuous maps with discrete target

In this file we prove that a topological space is preconnected if,
and only if, every continuous map into a discrete space is constant.#check

## Main results

- `preconnected_space_iff_continuous_to_bool_imp_constant`: a topological space X is a
preconnected_space if and only if every continuous map X → bool is constant
- `is_preconnected_iff_continuous_to_discrete_imp_constant`: a subset α of a topological
space X is_preconnected if and only if for every discrete space Y, every map X → Y, which is
continuous on α, is constant on α.
alreadydone marked this conversation as resolved.
Show resolved Hide resolved
-/

noncomputable theory

instance has_zero_bool : has_zero bool := ⟨⊥⟩
alreadydone marked this conversation as resolved.
Show resolved Hide resolved
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.

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?


lemma mem_iff_indicator_eq_top {X : Type*} (U : set X) (x : X) :
x ∈ U ↔ set.indicator U (cst_top X) x = ⊤ :=
begin
split,
{ intros hx,
have hx' : set.indicator U (cst_top X) x = cst_top X x := set.indicator_of_mem hx _,
rw hx',
triv },
{ intros hx,
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.


lemma indicator_fibre_of_top_eq_set {X : Type*} (U : set X) :
(set.indicator U (cst_top X) ) ⁻¹' {⊤} = U :=
begin
ext,
rw mem_iff_indicator_eq_top U x,
triv,
end

lemma indicator_continuous_iff_clopen {X : Type*} (U : set X) [topological_space X] :
continuous (set.indicator U (cst_top X)) ↔ is_clopen U :=
begin
let f := (set.indicator U (cst_top X)),
have h : ∀ s : set bool, (f ⁻¹' s) ∈ {set.univ, U, Uᶜ, ∅} :=
λ s, set.indicator_const_preimage U s ⊤,
split,
{ intros hc,
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.

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.

have hfibre : f ⁻¹' {⊤} = U := indicator_fibre_of_top_eq_set U,
specialize h₁ {⊤},
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.

Those two lines are fine for exploration, but you should remove them during cleanup. After removing them you can change exact ⟨h₁, h₂⟩ to exact ⟨h₁ {⊤}, h₂ {⊤}⟩ (or even exact ⟨h₁ _, h₂ _⟩).

Note that whole first implication can be written as

  { intros hc,
    rw ← indicator_fibre_of_top_eq_set U,
    exact ⟨hc.is_open_preimage _ trivial, continuous_iff_is_closed.mp hc _ (is_closed_discrete _)⟩ },

rw ← hfibre,
exact ⟨h₁, h₂⟩ },
{ intros hU,
refine {is_open_preimage := _},
intros s hs,
specialize h s,
simp at *,
cases h,
{ rw h, exact is_open_univ },
cases h,
{ rw h, exact hU.1 },
cases h,
{ rw h, refine is_open_compl_iff.mpr _, exact hU.2 },
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 leave something like refine is_open_compl_iff.mpr _, exact hU.2 in a finished proof. This is fine for exploration, but here you clearly mean exact is_open_compl_iff.mpr hU.2

rw h, exact is_open_empty },
end
Copy link
Member

Choose a reason for hiding this comment

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

Once cleaned up, that second implication reduces to

  { refine λ hU, ⟨λ s hs, _⟩,
    simp only [set.mem_insert_iff, set.mem_singleton_iff] at h,
    rcases h s with (h|h|h|h) ; rw h,
    exacts [is_open_univ, hU.1, is_open_compl_iff.mpr hU.2, is_open_empty] }


lemma indicator_continuous_on_iff_clopen {X : Type*} (α U : set X) [topological_space X] :
continuous_on (set.indicator U (cst_top X)) α ↔ is_clopen (α.restrict U) :=
begin
rw ← indicator_continuous_iff_clopen (α.restrict U),
exact continuous_on_iff_continuous_restrict,
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.


lemma continuous_to_discrete_iff_continuous {X Y : Type*} (f : X → Y) [topological_space X]
[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.

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).

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.

[topological_space X] : Prop :=
continuous_to_discrete f → ∀ a b : X, a ∈ α → b ∈ α → f a = f b

def continuous_on_to_discrete {X Y : Type*} (α : set X) (f : X → Y) [topological_space X] : Prop :=
∀ s : set Y, is_open (α.restrict (f ⁻¹' s))

def continuous_on_to_discrete_imp_constant {X Y : Type*} (α : set X) (f : X → Y)
[topological_space X] : Prop :=
continuous_on_to_discrete α f → ∀ a b : X, a ∈ α → b ∈ α → f a = f b

lemma preconnected_space_iff_continuous_to_bool_imp_constant (X : Type*) [topological_space X] :
preconnected_space X ↔ ∀ f : X → bool, continuous_to_discrete_imp_constant set.univ f :=
begin
split,
{ intros hp f hf a b ha hb,
by_contra,
let U := f ⁻¹' {f a},
let V := f ⁻¹' ({f a}ᶜ),
rw continuous_to_discrete_iff_continuous f at hf,
have hU : is_closed U,
{ refine is_closed.preimage hf _,
exact is_closed_discrete _ },
have hV : is_closed V,
{ refine is_closed.preimage hf _,
exact is_closed_discrete _, },
have haU : (set.univ ∩ U).nonempty,
{ use a,
tidy },
have haV : (set.univ ∩ V).nonempty,
{ use b,
tidy },
have haUuV : set.univ ⊆ U ∪ V,
{ intros x hx,
by_cases hf : f x = f a,
{ left,
exact hf },
{ right,
exact hf } },
have haUV : ¬(set.univ ∩ (U ∩ V)).nonempty := by tidy,
apply haUV,
cases hp,
exact is_preconnected_closed_iff.mp hp U V hU hV haUuV haU haV },
{ intros h,
fconstructor,
intros U V hU hV hUnion hneU hneV,
simp at *,
by_contra h1,
have heUV : (U ∩ V) = ∅,
{ rw ← set.ne_empty_iff_nonempty at h1,
tidy, },
have h_V_in_Uc : V ⊆ Uᶜ :=
disjoint.subset_compl_left (set.disjoint_iff_inter_eq_empty.mpr heUV),
have hUnion' : set.univ = U ∪ V := by tidy,
have h_V_eq_Uc : V = Uᶜ,
{ ext, split, { exact λ hx, h_V_in_Uc hx },
intros hx,
have hx' : x ∈ U ∪ V := hUnion trivial,
cases hx',
exfalso, { exact hx hx' }, { exact hx' } },
have hcU : is_clopen U,
{ split, { exact hU },
{ refine {is_open_compl := _},
rw ← h_V_eq_Uc, exact hV } },
rw ← indicator_continuous_iff_clopen U at hcU,
specialize h (set.indicator U (cst_top X)),
rw ← continuous_to_discrete_iff_continuous _ at hcU, swap, { apply_instance },
have habU := h hcU,
obtain ⟨u, hu⟩ := hneU,
obtain ⟨v, hv⟩ := hneV,
specialize habU u v trivial trivial,
rw h_V_eq_Uc at hv,
apply hv,
rw mem_iff_indicator_eq_top at hu,
rw hu at habU,
exact (mem_iff_indicator_eq_top U v).mpr habU.symm },
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.

is_preconnected α ↔ ∀ f : X → bool, continuous_on_to_discrete_imp_constant α f :=
begin
rw is_preconnected_iff_preconnected_space,
rw preconnected_space_iff_continuous_to_bool_imp_constant α,
split,
{ intros h f,
specialize h (α.restrict f),
intros hf a b ha hb,
have hf' : continuous_to_discrete (α.restrict f) := hf,
have h' := h hf' ⟨a, ha⟩ ⟨b, hb⟩ trivial trivial,
exact h' },
{ intros h f,
let f' : X → bool := λ x, if hx : x ∈ α then f ⟨x, hx⟩ else 0,
specialize h f',
intros hf a b ha hb,
have hf' : f = α.restrict f' := by tidy,
rw hf' at hf,
have hf'' : continuous_on_to_discrete α f' := hf,
have h' := h hf'',
rw hf',
tidy },
end

lemma is_preconnected_iff_continuous_to_discrete_imp_constant {X : Type*} (α : set X)
[topological_space X] [decidable_pred (∈ α)] :
is_preconnected α ↔ ∀ Y : Type, ∀ f : X → Y, continuous_on_to_discrete_imp_constant α f :=
begin
rw is_preconnected_iff_continuous_to_bool_imp_constant α,
split, swap, { exact λ h b, h bool b, },
intros h Y f hf a b ha hb,
specialize h ((set.indicator {f a} (cst_top' Y)) ∘ f),
have hf' : continuous_on_to_discrete α ((set.indicator {f a} (cst_top' Y)) ∘ f),
{ intros s,
have hs : is_open (α.restrict f ⁻¹' ((set.indicator {f a} (cst_top' Y)) ⁻¹' s)) := hf _,
exact hs, },
have hh := h hf',
specialize hh a b,
have hi := hh ha hb,
have hia : ((set.indicator {f a} (cst_top' Y)) ∘ f) a = ⊤ := by tidy,
rw hia at hi,
have hib := @indicator_fibre_of_top_eq_set Y {f a},
rw hi at hib,
have hib' : {f b} ⊆ {f a},
{ rw ← hib,
norm_num,
simp at *,
have hfb : {(set.indicator {f a} (cst_top' Y)) (f b)} =
(set.indicator {f a} (cst_top' Y)) '' {f b} := by tidy,
have hfb' := set.subset_preimage_image (set.indicator {f a} (cst_top' Y)) {f b},
rw ← hfb at hfb',
exact hfb', },
tauto,
end