File: Mathlib/Topology/DiscreteQuotient.lean

full_name: DiscreteQuotient.isOpen_setOf_rel
code: /-- The type of discrete quotients of a topological space. -/
@[ext] -- Porting note: in Lean 4, uses projection to `r` instead of `Setoid`.
structure DiscreteQuotient (X : Type*) [TopologicalSpace X] extends Setoid X where
  /-- For every point `x`, the set `{ y | Rel x y }` is an open set. -/
  protected isOpen_setOf_rel : ∀ x, IsOpen (setOf (toSetoid.Rel x))
goal: IsOpen (setOf (self.Rel x))

full_name: DiscreteQuotient
code: /-- The type of discrete quotients of a topological space. -/
@[ext] -- Porting note: in Lean 4, uses projection to `r` instead of `Setoid`.
structure DiscreteQuotient (X : Type*) [TopologicalSpace X] extends Setoid X where
  /-- For every point `x`, the set `{ y | Rel x y }` is an open set. -/
  protected isOpen_setOf_rel : ∀ x, IsOpen (setOf (toSetoid.Rel x))
goal: Type u_5

full_name: DiscreteQuotient.toSetoid_injective
code: lemma toSetoid_injective : Function.Injective (@toSetoid X _)
  
goal: Function.Injective DiscreteQuotient.toSetoid

full_name: DiscreteQuotient.ofIsClopen
code: /-- Construct a discrete quotient from a clopen set. -/
def ofIsClopen {A : Set X} (h : IsClopen A) : DiscreteQuotient X 
goal: DiscreteQuotient X

full_name: DiscreteQuotient.refl
code: theorem refl : ∀ x, S.Rel x x 
goal: S.Rel x x

full_name: DiscreteQuotient.symm
code: theorem symm (x y : X) : S.Rel x y → S.Rel y x 
goal: S.Rel x y → S.Rel y x

full_name: DiscreteQuotient.trans
code: theorem trans (x y z : X) : S.Rel x y → S.Rel y z → S.Rel x z 
goal: S.Rel x y → S.Rel y z → S.Rel x z

full_name: DiscreteQuotient.instCoeSortType
code: instance : CoeSort (DiscreteQuotient X) (Type _) 
goal: CoeSort (DiscreteQuotient X) (Type u_2)

full_name: DiscreteQuotient.instTopologicalSpaceQuotient
code: instance : TopologicalSpace S 
goal: TopologicalSpace (Quotient S.toSetoid)

full_name: DiscreteQuotient.proj
code: /-- The projection from `X` to the given discrete quotient. -/
def proj : X → S 
goal: X → Quotient S.toSetoid

full_name: DiscreteQuotient.fiber_eq
code: theorem fiber_eq (x : X) : S.proj ⁻¹' {S.proj x} = setOf (S.Rel x) 
goal: S.proj ⁻¹' {S.proj x} = setOf (S.Rel x)

full_name: DiscreteQuotient.proj_surjective
code: theorem proj_surjective : Function.Surjective S.proj 
goal: Function.Surjective S.proj

full_name: DiscreteQuotient.proj_quotientMap
code: theorem proj_quotientMap : QuotientMap S.proj 
goal: QuotientMap S.proj

full_name: DiscreteQuotient.proj_continuous
code: theorem proj_continuous : Continuous S.proj 
goal: Continuous S.proj

full_name: DiscreteQuotient.instDiscreteTopologyQuotient
code: instance : DiscreteTopology S 
goal: DiscreteTopology (Quotient S.toSetoid)

full_name: DiscreteQuotient.proj_isLocallyConstant
code: theorem proj_isLocallyConstant : IsLocallyConstant S.proj 
goal: IsLocallyConstant S.proj

full_name: DiscreteQuotient.isClopen_preimage
code: theorem isClopen_preimage (A : Set S) : IsClopen (S.proj ⁻¹' A) 
goal: IsClopen (S.proj ⁻¹' A)

full_name: DiscreteQuotient.isOpen_preimage
code: theorem isOpen_preimage (A : Set S) : IsOpen (S.proj ⁻¹' A) 
goal: IsOpen (S.proj ⁻¹' A)

full_name: DiscreteQuotient.isClosed_preimage
code: theorem isClosed_preimage (A : Set S) : IsClosed (S.proj ⁻¹' A) 
goal: IsClosed (S.proj ⁻¹' A)

full_name: DiscreteQuotient.isClopen_setOf_rel
code: theorem isClopen_setOf_rel (x : X) : IsClopen (setOf (S.Rel x)) 
goal: IsClopen (setOf (S.Rel x))

full_name: DiscreteQuotient.instInf
code: instance : Inf (DiscreteQuotient X) 
goal: Inf (DiscreteQuotient X)

full_name: DiscreteQuotient.instSemilatticeInf
code: instance : SemilatticeInf (DiscreteQuotient X) 
goal: SemilatticeInf (DiscreteQuotient X)

full_name: DiscreteQuotient.instOrderTop
code: instance : OrderTop (DiscreteQuotient X) 
goal: OrderTop (DiscreteQuotient X)

full_name: DiscreteQuotient.instInhabited
code: instance : Inhabited (DiscreteQuotient X) 
goal: Inhabited (DiscreteQuotient X)

full_name: DiscreteQuotient.inhabitedQuotient
code: instance inhabitedQuotient [Inhabited X] : Inhabited S 
goal: Inhabited (Quotient S.toSetoid)

full_name: DiscreteQuotient.instNonemptyQuotient
code: instance [Nonempty X] : Nonempty S 
goal: Nonempty (Quotient S.toSetoid)

full_name: DiscreteQuotient.instSubsingletonQuotientTop
code: /-- The quotient by `⊤ : DiscreteQuotient X` is a `Subsingleton`. -/
instance : Subsingleton (⊤ : DiscreteQuotient X) 
goal: Subsingleton (Quotient ⊤.toSetoid)

full_name: DiscreteQuotient.comap
code: /-- Comap a discrete quotient along a continuous map. -/
def comap (S : DiscreteQuotient Y) : DiscreteQuotient X 
goal: DiscreteQuotient X

full_name: DiscreteQuotient.comap_id
code: @[simp]
theorem comap_id : S.comap (ContinuousMap.id X) = S 
goal: DiscreteQuotient.comap (ContinuousMap.id X) S = S

full_name: DiscreteQuotient.comap_comp
code: @[simp]
theorem comap_comp (S : DiscreteQuotient Z) : S.comap (g.comp f) = (S.comap g).comap f 
goal: DiscreteQuotient.comap (g.comp f) S = DiscreteQuotient.comap f (DiscreteQuotient.comap g S)

full_name: DiscreteQuotient.comap_mono
code: @[mono]
theorem comap_mono {A B : DiscreteQuotient Y} (h : A ≤ B) : A.comap f ≤ B.comap f 
goal: DiscreteQuotient.comap f A ≤ DiscreteQuotient.comap f B

full_name: DiscreteQuotient.ofLE
code: /-- The map induced by a refinement of a discrete quotient. -/
def ofLE (h : A ≤ B) : A → B 
goal: Quotient A.toSetoid → Quotient B.toSetoid

full_name: DiscreteQuotient.ofLE_refl
code: @[simp]
theorem ofLE_refl : ofLE (le_refl A) = id 
goal: DiscreteQuotient.ofLE ⋯ = id

full_name: DiscreteQuotient.ofLE_refl_apply
code: theorem ofLE_refl_apply (a : A) : ofLE (le_refl A) a = a 
goal: DiscreteQuotient.ofLE ⋯ a = a

full_name: DiscreteQuotient.ofLE_ofLE
code: @[simp]
theorem ofLE_ofLE (h₁ : A ≤ B) (h₂ : B ≤ C) (x : A) :
    ofLE h₂ (ofLE h₁ x) = ofLE (h₁.trans h₂) x 
goal: DiscreteQuotient.ofLE h₂ (DiscreteQuotient.ofLE h₁ x) = DiscreteQuotient.ofLE ⋯ x

full_name: DiscreteQuotient.ofLE_comp_ofLE
code: @[simp]
theorem ofLE_comp_ofLE (h₁ : A ≤ B) (h₂ : B ≤ C) : ofLE h₂ ∘ ofLE h₁ = ofLE (le_trans h₁ h₂) 
goal: DiscreteQuotient.ofLE h₂ ∘ DiscreteQuotient.ofLE h₁ = DiscreteQuotient.ofLE ⋯

full_name: DiscreteQuotient.ofLE_continuous
code: theorem ofLE_continuous (h : A ≤ B) : Continuous (ofLE h) 
goal: Continuous (DiscreteQuotient.ofLE h)

full_name: DiscreteQuotient.ofLE_proj
code: @[simp]
theorem ofLE_proj (h : A ≤ B) (x : X) : ofLE h (A.proj x) = B.proj x 
goal: DiscreteQuotient.ofLE h (A.proj x) = B.proj x

full_name: DiscreteQuotient.ofLE_comp_proj
code: @[simp]
theorem ofLE_comp_proj (h : A ≤ B) : ofLE h ∘ A.proj = B.proj 
goal: DiscreteQuotient.ofLE h ∘ A.proj = B.proj

full_name: DiscreteQuotient.instOrderBotOfLocallyConnectedSpace
code: /-- When `X` is a locally connected space, there is an `OrderBot` instance on
`DiscreteQuotient X`. The bottom element is given by `connectedComponentSetoid X`
-/
instance [LocallyConnectedSpace X] : OrderBot (DiscreteQuotient X) 
goal: OrderBot (DiscreteQuotient X)

full_name: DiscreteQuotient.proj_bot_eq
code: @[simp]
theorem proj_bot_eq [LocallyConnectedSpace X] {x y : X} :
    proj ⊥ x = proj ⊥ y ↔ connectedComponent x = connectedComponent y 
goal: ⊥.proj x = ⊥.proj y ↔ connectedComponent x = connectedComponent y

full_name: DiscreteQuotient.proj_bot_inj
code: theorem proj_bot_inj [DiscreteTopology X] {x y : X} : proj ⊥ x = proj ⊥ y ↔ x = y 
goal: ⊥.proj x = ⊥.proj y ↔ x = y

full_name: DiscreteQuotient.proj_bot_injective
code: theorem proj_bot_injective [DiscreteTopology X] : Injective (⊥ : DiscreteQuotient X).proj 
goal: Function.Injective ⊥.proj

full_name: DiscreteQuotient.proj_bot_bijective
code: theorem proj_bot_bijective [DiscreteTopology X] : Bijective (⊥ : DiscreteQuotient X).proj 
goal: Function.Bijective ⊥.proj

full_name: DiscreteQuotient.LEComap
code: /-- Given `f : C(X, Y)`, `DiscreteQuotient.LEComap f A B` is defined as
`A ≤ B.comap f`. Mathematically this means that `f` descends to a morphism `A → B`. -/
def LEComap : Prop 
goal: Prop

full_name: DiscreteQuotient.leComap_id
code: theorem leComap_id : LEComap (.id X) A A 
goal: DiscreteQuotient.LEComap (ContinuousMap.id X) A A

full_name: DiscreteQuotient.leComap_id_iff
code: @[simp]
theorem leComap_id_iff : LEComap (ContinuousMap.id X) A A' ↔ A ≤ A' 
goal: DiscreteQuotient.LEComap (ContinuousMap.id X) A A' ↔ A ≤ A'

full_name: DiscreteQuotient.LEComap.comp
code: theorem LEComap.comp : LEComap g B C → LEComap f A B → LEComap (g.comp f) A C 
goal: DiscreteQuotient.LEComap g B C → DiscreteQuotient.LEComap f A B → DiscreteQuotient.LEComap (g.comp f) A C

full_name: DiscreteQuotient.LEComap.mono
code: @[mono]
theorem LEComap.mono (h : LEComap f A B) (hA : A' ≤ A) (hB : B ≤ B') : LEComap f A' B' 
goal: DiscreteQuotient.LEComap f A' B'

full_name: DiscreteQuotient.map
code: /-- Map a discrete quotient along a continuous map. -/
def map (f : C(X, Y)) (cond : LEComap f A B) : A → B 
goal: Quotient A.toSetoid → Quotient B.toSetoid

full_name: DiscreteQuotient.map_continuous
code: theorem map_continuous (cond : LEComap f A B) : Continuous (map f cond) 
goal: Continuous (DiscreteQuotient.map f cond)

full_name: DiscreteQuotient.map_comp_proj
code: @[simp]
theorem map_comp_proj (cond : LEComap f A B) : map f cond ∘ A.proj = B.proj ∘ f 
goal: DiscreteQuotient.map f cond ∘ A.proj = B.proj ∘ ⇑f

full_name: DiscreteQuotient.map_proj
code: @[simp]
theorem map_proj (cond : LEComap f A B) (x : X) : map f cond (A.proj x) = B.proj (f x) 
goal: DiscreteQuotient.map f cond (A.proj x) = B.proj (f x)

full_name: DiscreteQuotient.map_id
code: @[simp]
theorem map_id : map _ (leComap_id A) = id 
goal: DiscreteQuotient.map (ContinuousMap.id X) ⋯ = id

full_name: DiscreteQuotient.map_comp
code: theorem map_comp (h1 : LEComap g B C) (h2 : LEComap f A B) :
    map (g.comp f) (h1.comp h2) = map g h1 ∘ map f h2 
goal: DiscreteQuotient.map (g.comp f) ⋯ = DiscreteQuotient.map g h1 ∘ DiscreteQuotient.map f h2

full_name: DiscreteQuotient.ofLE_map
code: @[simp]
theorem ofLE_map (cond : LEComap f A B) (h : B ≤ B') (a : A) :
    ofLE h (map f cond a) = map f (cond.mono le_rfl h) a 
goal: DiscreteQuotient.ofLE h (DiscreteQuotient.map f cond a) = DiscreteQuotient.map f ⋯ a

full_name: DiscreteQuotient.ofLE_comp_map
code: @[simp]
theorem ofLE_comp_map (cond : LEComap f A B) (h : B ≤ B') :
    ofLE h ∘ map f cond = map f (cond.mono le_rfl h) 
goal: DiscreteQuotient.ofLE h ∘ DiscreteQuotient.map f cond = DiscreteQuotient.map f ⋯

full_name: DiscreteQuotient.map_ofLE
code: @[simp]
theorem map_ofLE (cond : LEComap f A B) (h : A' ≤ A) (c : A') :
    map f cond (ofLE h c) = map f (cond.mono h le_rfl) c 
goal: DiscreteQuotient.map f cond (DiscreteQuotient.ofLE h c) = DiscreteQuotient.map f ⋯ c

full_name: DiscreteQuotient.map_comp_ofLE
code: @[simp]
theorem map_comp_ofLE (cond : LEComap f A B) (h : A' ≤ A) :
    map f cond ∘ ofLE h = map f (cond.mono h le_rfl) 
goal: DiscreteQuotient.map f cond ∘ DiscreteQuotient.ofLE h = DiscreteQuotient.map f ⋯

full_name: DiscreteQuotient.eq_of_forall_proj_eq
code: theorem eq_of_forall_proj_eq [T2Space X] [CompactSpace X] [disc : TotallyDisconnectedSpace X]
    {x y : X} (h : ∀ Q : DiscreteQuotient X, Q.proj x = Q.proj y) : x = y 
goal: x = y

full_name: DiscreteQuotient.fiber_subset_ofLE
code: theorem fiber_subset_ofLE {A B : DiscreteQuotient X} (h : A ≤ B) (a : A) :
    A.proj ⁻¹' {a} ⊆ B.proj ⁻¹' {ofLE h a} 
goal: A.proj ⁻¹' {a} ⊆ B.proj ⁻¹' {DiscreteQuotient.ofLE h a}

full_name: DiscreteQuotient.exists_of_compat
code: theorem exists_of_compat [CompactSpace X] (Qs : (Q : DiscreteQuotient X) → Q)
    (compat : ∀ (A B : DiscreteQuotient X) (h : A ≤ B), ofLE h (Qs _) = Qs _) :
    ∃ x : X, ∀ Q : DiscreteQuotient X, Q.proj x = Qs _ 
goal: ∃ x, ∀ (Q : DiscreteQuotient X), Q.proj x = Qs Q

full_name: DiscreteQuotient.instFiniteQuotientOfCompactSpace
code: /-- If `X` is a compact space, then any discrete quotient of `X` is finite. -/
instance [CompactSpace X] : Finite S 
goal: Finite (Quotient S.toSetoid)

full_name: DiscreteQuotient.finsetClopens
code: /--
If `X` is a compact space, then we associate to any discrete quotient on `X` a finite set of
clopen subsets of `X`, given by the fibers of `proj`.

TODO: prove that these form a partition of `X` 
-/
noncomputable def finsetClopens [CompactSpace X]
    (d : DiscreteQuotient X) : Finset (Clopens X) 
goal: Finset (TopologicalSpace.Clopens X)

full_name: DiscreteQuotient.comp_finsetClopens
code: /-- A helper lemma to prove that `finsetClopens X` is injective, see `finsetClopens_inj`. -/
lemma comp_finsetClopens [CompactSpace X] :
    (Set.image (fun (t : Clopens X) ↦ t.carrier) ∘ Finset.toSet) ∘
      finsetClopens X = fun ⟨f, _⟩ ↦ f.classes 
goal: ((Set.image fun t => t.carrier) ∘ Finset.toSet) ∘ DiscreteQuotient.finsetClopens X = fun x =>
  match x with
  | { toSetoid := f, isOpen_setOf_rel := isOpen_setOf_rel } => f.classes

full_name: DiscreteQuotient.finsetClopens_inj
code: /-- `finsetClopens X` is injective. -/
theorem finsetClopens_inj [CompactSpace X] :
    (finsetClopens X).Injective 
goal: Function.Injective (DiscreteQuotient.finsetClopens X)

full_name: DiscreteQuotient.equivFinsetClopens
code: /--
The discrete quotients of a compact space are in bijection with a subtype of the type of
`Finset (Clopens X)`.

TODO: show that this is precisely those finsets of clopens which form a partition of `X`.
-/
noncomputable
def equivFinsetClopens [CompactSpace X] 
goal: DiscreteQuotient X ≃ ↑(Set.range (DiscreteQuotient.finsetClopens X))

full_name: LocallyConstant.discreteQuotient
code: /-- Any locally constant function induces a discrete quotient. -/
def discreteQuotient : DiscreteQuotient X 
goal: DiscreteQuotient X

full_name: LocallyConstant.lift
code: /-- The (locally constant) function from the discrete quotient associated to a locally constant
function. -/
def lift : LocallyConstant f.discreteQuotient α 
goal: LocallyConstant (Quotient f.discreteQuotient.toSetoid) α

full_name: LocallyConstant.lift_comp_proj
code: @[simp]
theorem lift_comp_proj : f.lift ∘ f.discreteQuotient.proj = f 
goal: ⇑f.lift ∘ f.discreteQuotient.proj = ⇑f