File: Mathlib/Topology/Homotopy/Path.lean

full_name: Path.Homotopy
code: /-- The type of homotopies between two paths.
-/
abbrev Homotopy (p₀ p₁ : Path x₀ x₁) 
goal: Type u

full_name: Path.Homotopy.coeFn_injective
code: theorem coeFn_injective : @Function.Injective (Homotopy p₀ p₁) (I × I → X) (⇑) 
goal: Function.Injective DFunLike.coe

full_name: Path.Homotopy.source
code: @[simp]
theorem source (F : Homotopy p₀ p₁) (t : I) : F (t, 0) = x₀ 
goal: F (t, 0) = x₀

full_name: Path.Homotopy.target
code: @[simp]
theorem target (F : Homotopy p₀ p₁) (t : I) : F (t, 1) = x₁ 
goal: F (t, 1) = x₁

full_name: Path.Homotopy.eval
code: /-- Evaluating a path homotopy at an intermediate point, giving us a `Path`.
-/
def eval (F : Homotopy p₀ p₁) (t : I) : Path x₀ x₁ 
goal: Path x₀ x₁

full_name: Path.Homotopy.eval_zero
code: @[simp]
theorem eval_zero (F : Homotopy p₀ p₁) : F.eval 0 = p₀ 
goal: F.eval 0 = p₀

full_name: Path.Homotopy.eval_one
code: @[simp]
theorem eval_one (F : Homotopy p₀ p₁) : F.eval 1 = p₁ 
goal: F.eval 1 = p₁

full_name: Path.Homotopy.refl_toFun
code: /-- Given a path `p`, we can define a `Homotopy p p` by `F (t, x) = p x`.
-/
@[simps!]
def refl (p : Path x₀ x₁) : Homotopy p p 
goal: (Path.Homotopy.refl p) x = p x.2

full_name: Path.Homotopy.refl
code: /-- Given a path `p`, we can define a `Homotopy p p` by `F (t, x) = p x`.
-/
@[simps!]
def refl (p : Path x₀ x₁) : Homotopy p p 
goal: p.Homotopy p

full_name: Path.Homotopy.refl_apply
code: /-- Given a path `p`, we can define a `Homotopy p p` by `F (t, x) = p x`.
-/
@[simps!]
def refl (p : Path x₀ x₁) : Homotopy p p 
goal: (Path.Homotopy.refl p) x = p x.2

full_name: Path.Homotopy.symm_toFun
code: /-- Given a `Homotopy p₀ p₁`, we can define a `Homotopy p₁ p₀` by reversing the homotopy.
-/
@[simps!]
def symm (F : Homotopy p₀ p₁) : Homotopy p₁ p₀ 
goal: F.symm x = F (σ x.1, x.2)

full_name: Path.Homotopy.symm_apply
code: /-- Given a `Homotopy p₀ p₁`, we can define a `Homotopy p₁ p₀` by reversing the homotopy.
-/
@[simps!]
def symm (F : Homotopy p₀ p₁) : Homotopy p₁ p₀ 
goal: F.symm x = F (σ x.1, x.2)

full_name: Path.Homotopy.symm
code: /-- Given a `Homotopy p₀ p₁`, we can define a `Homotopy p₁ p₀` by reversing the homotopy.
-/
@[simps!]
def symm (F : Homotopy p₀ p₁) : Homotopy p₁ p₀ 
goal: p₁.Homotopy p₀

full_name: Path.Homotopy.symm_symm
code: @[simp]
theorem symm_symm (F : Homotopy p₀ p₁) : F.symm.symm = F 
goal: F.symm.symm = F

full_name: Path.Homotopy.symm_bijective
code: theorem symm_bijective : Function.Bijective (Homotopy.symm : Homotopy p₀ p₁ → Homotopy p₁ p₀) 
goal: Function.Bijective Path.Homotopy.symm

full_name: Path.Homotopy.trans
code: /--
Given `Homotopy p₀ p₁` and `Homotopy p₁ p₂`, we can define a `Homotopy p₀ p₂` by putting the first
homotopy on `[0, 1/2]` and the second on `[1/2, 1]`.
-/
def trans (F : Homotopy p₀ p₁) (G : Homotopy p₁ p₂) : Homotopy p₀ p₂ 
goal: p₀.Homotopy p₂

full_name: Path.Homotopy.trans_apply
code: theorem trans_apply (F : Homotopy p₀ p₁) (G : Homotopy p₁ p₂) (x : I × I) :
    (F.trans G) x =
      if h : (x.1 : ℝ) ≤ 1 / 2 then
        F (⟨2 * x.1, (unitInterval.mul_pos_mem_iff zero_lt_two).2 ⟨x.1.2.1, h⟩⟩, x.2)
      else
        G (⟨2 * x.1 - 1, unitInterval.two_mul_sub_one_mem_iff.2 ⟨(not_le.1 h).le, x.1.2.2⟩⟩, x.2) 
goal: (F.trans G) x = if h : ↑x.1 ≤ 1 / 2 then F (⟨2 * ↑x.1, ⋯⟩, x.2) else G (⟨2 * ↑x.1 - 1, ⋯⟩, x.2)

full_name: Path.Homotopy.symm_trans
code: theorem symm_trans (F : Homotopy p₀ p₁) (G : Homotopy p₁ p₂) :
    (F.trans G).symm = G.symm.trans F.symm 
goal: (F.trans G).symm = G.symm.trans F.symm

full_name: Path.Homotopy.cast_toFun
code: /-- Casting a `Homotopy p₀ p₁` to a `Homotopy q₀ q₁` where `p₀ = q₀` and `p₁ = q₁`. -/
@[simps!]
def cast {p₀ p₁ q₀ q₁ : Path x₀ x₁} (F : Homotopy p₀ p₁) (h₀ : p₀ = q₀) (h₁ : p₁ = q₁) :
    Homotopy q₀ q₁ 
goal: (F.cast h₀ h₁) a = F a

full_name: Path.Homotopy.cast_apply
code: /-- Casting a `Homotopy p₀ p₁` to a `Homotopy q₀ q₁` where `p₀ = q₀` and `p₁ = q₁`. -/
@[simps!]
def cast {p₀ p₁ q₀ q₁ : Path x₀ x₁} (F : Homotopy p₀ p₁) (h₀ : p₀ = q₀) (h₁ : p₁ = q₁) :
    Homotopy q₀ q₁ 
goal: (F.cast h₀ h₁) a = F a

full_name: Path.Homotopy.cast
code: /-- Casting a `Homotopy p₀ p₁` to a `Homotopy q₀ q₁` where `p₀ = q₀` and `p₁ = q₁`. -/
@[simps!]
def cast {p₀ p₁ q₀ q₁ : Path x₀ x₁} (F : Homotopy p₀ p₁) (h₀ : p₀ = q₀) (h₁ : p₁ = q₁) :
    Homotopy q₀ q₁ 
goal: q₀.Homotopy q₁

full_name: Path.Homotopy.hcomp
code: /-- Suppose `p₀` and `q₀` are paths from `x₀` to `x₁`, `p₁` and `q₁` are paths from `x₁` to `x₂`.
Furthermore, suppose `F : Homotopy p₀ q₀` and `G : Homotopy p₁ q₁`. Then we can define a homotopy
from `p₀.trans p₁` to `q₀.trans q₁`.
-/
def hcomp (F : Homotopy p₀ q₀) (G : Homotopy p₁ q₁) : Homotopy (p₀.trans p₁) (q₀.trans q₁) 
goal: (p₀.trans p₁).Homotopy (q₀.trans q₁)

full_name: Path.Homotopy.hcomp_apply
code: theorem hcomp_apply (F : Homotopy p₀ q₀) (G : Homotopy p₁ q₁) (x : I × I) :
    F.hcomp G x =
      if h : (x.2 : ℝ) ≤ 1 / 2 then
        F.eval x.1 ⟨2 * x.2, (unitInterval.mul_pos_mem_iff zero_lt_two).2 ⟨x.2.2.1, h⟩⟩
      else
        G.eval x.1
          ⟨2 * x.2 - 1, unitInterval.two_mul_sub_one_mem_iff.2 ⟨(not_le.1 h).le, x.2.2.2⟩⟩ 
goal: (F.hcomp G) x = if h : ↑x.2 ≤ 1 / 2 then (F.eval x.1) ⟨2 * ↑x.2, ⋯⟩ else (G.eval x.1) ⟨2 * ↑x.2 - 1, ⋯⟩

full_name: Path.Homotopy.hcomp_half
code: theorem hcomp_half (F : Homotopy p₀ q₀) (G : Homotopy p₁ q₁) (t : I) :
    F.hcomp G (t, ⟨1 / 2, by norm_num, by norm_num⟩) = x₁ 
goal: (F.hcomp G) (t, ⟨1 / 2, ⋯⟩) = x₁

full_name: Path.Homotopy.reparam
code: /--
Suppose `p` is a path, then we have a homotopy from `p` to `p.reparam f` by the convexity of `I`.
-/
def reparam (p : Path x₀ x₁) (f : I → I) (hf : Continuous f) (hf₀ : f 0 = 0) (hf₁ : f 1 = 1) :
    Homotopy p (p.reparam f hf hf₀ hf₁) 
goal: p.Homotopy (p.reparam f hf hf₀ hf₁)

full_name: Path.Homotopy.symm₂_toFun
code: /-- Suppose `F : Homotopy p q`. Then we have a `Homotopy p.symm q.symm` by reversing the second
argument.
-/
@[simps]
def symm₂ {p q : Path x₀ x₁} (F : p.Homotopy q) : p.symm.Homotopy q.symm 
goal: F.symm₂ x = F (x.1, σ x.2)

full_name: Path.Homotopy.symm₂
code: /-- Suppose `F : Homotopy p q`. Then we have a `Homotopy p.symm q.symm` by reversing the second
argument.
-/
@[simps]
def symm₂ {p q : Path x₀ x₁} (F : p.Homotopy q) : p.symm.Homotopy q.symm 
goal: p.symm.Homotopy q.symm

full_name: Path.Homotopy.symm₂_apply
code: /-- Suppose `F : Homotopy p q`. Then we have a `Homotopy p.symm q.symm` by reversing the second
argument.
-/
@[simps]
def symm₂ {p q : Path x₀ x₁} (F : p.Homotopy q) : p.symm.Homotopy q.symm 
goal: F.symm₂ x = F (x.1, σ x.2)

full_name: Path.Homotopy.map
code: /--
Given `F : Homotopy p q`, and `f : C(X, Y)`, we can define a homotopy from `p.map f.continuous` to
`q.map f.continuous`.
-/
@[simps]
def map {p q : Path x₀ x₁} (F : p.Homotopy q) (f : C(X, Y)) :
    Homotopy (p.map f.continuous) (q.map f.continuous) 
goal: (p.map ⋯).Homotopy (q.map ⋯)

full_name: Path.Homotopy.map_toFun
code: /--
Given `F : Homotopy p q`, and `f : C(X, Y)`, we can define a homotopy from `p.map f.continuous` to
`q.map f.continuous`.
-/
@[simps]
def map {p q : Path x₀ x₁} (F : p.Homotopy q) (f : C(X, Y)) :
    Homotopy (p.map f.continuous) (q.map f.continuous) 
goal: ∀ (a : ↑I × ↑I), (F.map f) a = (⇑f ∘ ⇑F) a

full_name: Path.Homotopy.map_apply
code: /--
Given `F : Homotopy p q`, and `f : C(X, Y)`, we can define a homotopy from `p.map f.continuous` to
`q.map f.continuous`.
-/
@[simps]
def map {p q : Path x₀ x₁} (F : p.Homotopy q) (f : C(X, Y)) :
    Homotopy (p.map f.continuous) (q.map f.continuous) 
goal: ∀ (a : ↑I × ↑I), (F.map f) a = (⇑f ∘ ⇑F) a

full_name: Path.Homotopic
code: /-- Two paths `p₀` and `p₁` are `Path.Homotopic` if there exists a `Homotopy` between them.
-/
def Homotopic (p₀ p₁ : Path x₀ x₁) : Prop 
goal: Prop

full_name: Path.Homotopic.refl
code: @[refl]
theorem refl (p : Path x₀ x₁) : p.Homotopic p 
goal: p.Homotopic p

full_name: Path.Homotopic.symm
code: @[symm]
theorem symm ⦃p₀ p₁ : Path x₀ x₁⦄ (h : p₀.Homotopic p₁) : p₁.Homotopic p₀ 
goal: p₁.Homotopic p₀

full_name: Path.Homotopic.trans
code: @[trans]
theorem trans ⦃p₀ p₁ p₂ : Path x₀ x₁⦄ (h₀ : p₀.Homotopic p₁) (h₁ : p₁.Homotopic p₂) :
    p₀.Homotopic p₂ 
goal: p₀.Homotopic p₂

full_name: Path.Homotopic.equivalence
code: theorem equivalence : Equivalence (@Homotopic X _ x₀ x₁) 
goal: Equivalence Path.Homotopic

full_name: Path.Homotopic.map
code: nonrec theorem map {p q : Path x₀ x₁} (h : p.Homotopic q) (f : C(X, Y)) :
    Homotopic (p.map f.continuous) (q.map f.continuous) 
goal: (p.map ⋯).Homotopic (q.map ⋯)

full_name: Path.Homotopic.hcomp
code: theorem hcomp {p₀ p₁ : Path x₀ x₁} {q₀ q₁ : Path x₁ x₂} (hp : p₀.Homotopic p₁)
    (hq : q₀.Homotopic q₁) : (p₀.trans q₀).Homotopic (p₁.trans q₁) 
goal: (p₀.trans q₀).Homotopic (p₁.trans q₁)

full_name: Path.Homotopic.setoid
code: /--
The setoid on `Path`s defined by the equivalence relation `Path.Homotopic`. That is, two paths are
equivalent if there is a `Homotopy` between them.
-/
protected def setoid (x₀ x₁ : X) : Setoid (Path x₀ x₁) 
goal: Setoid (Path x₀ x₁)

full_name: Path.Homotopic.Quotient
code: /-- The quotient on `Path x₀ x₁` by the equivalence relation `Path.Homotopic`.
-/
protected def Quotient (x₀ x₁ : X) 
goal: Type u

full_name: Path.Homotopic.instInhabitedQuotientUnitUnit
code: instance : Inhabited (Homotopic.Quotient () ()) 
goal: Inhabited (Path.Homotopic.Quotient () ())

full_name: Path.Homotopic.Quotient.comp
code: /-- The composition of path homotopy classes. This is `Path.trans` descended to the quotient. -/
def Quotient.comp (P₀ : Path.Homotopic.Quotient x₀ x₁) (P₁ : Path.Homotopic.Quotient x₁ x₂) :
    Path.Homotopic.Quotient x₀ x₂ 
goal: Path.Homotopic.Quotient x₀ x₂

full_name: Path.Homotopic.comp_lift
code: theorem comp_lift (P₀ : Path x₀ x₁) (P₁ : Path x₁ x₂) : ⟦P₀.trans P₁⟧ = Quotient.comp ⟦P₀⟧ ⟦P₁⟧ 
goal: ⟦P₀.trans P₁⟧ = Path.Homotopic.Quotient.comp ⟦P₀⟧ ⟦P₁⟧

full_name: Path.Homotopic.Quotient.mapFn
code: /-- The image of a path homotopy class `P₀` under a map `f`.
    This is `Path.map` descended to the quotient. -/
def Quotient.mapFn (P₀ : Path.Homotopic.Quotient x₀ x₁) (f : C(X, Y)) :
    Path.Homotopic.Quotient (f x₀) (f x₁) 
goal: Path.Homotopic.Quotient (f x₀) (f x₁)

full_name: Path.Homotopic.map_lift
code: theorem map_lift (P₀ : Path x₀ x₁) (f : C(X, Y)) : ⟦P₀.map f.continuous⟧ = Quotient.mapFn ⟦P₀⟧ f 
goal: ⟦P₀.map ⋯⟧ = Path.Homotopic.Quotient.mapFn ⟦P₀⟧ f

full_name: Path.Homotopic.hpath_hext
code: theorem hpath_hext {p₁ : Path x₀ x₁} {p₂ : Path x₂ x₃} (hp : ∀ t, p₁ t = p₂ t) :
    @HEq (Path.Homotopic.Quotient _ _) ⟦p₁⟧ (Path.Homotopic.Quotient _ _) ⟦p₂⟧ 
goal: HEq ⟦p₁⟧ ⟦p₂⟧

full_name: Path.toHomotopyConst_apply
code: /-- A path `Path x₀ x₁` generates a homotopy between constant functions `fun _ ↦ x₀` and
`fun _ ↦ x₁`. -/
@[simps!]
def toHomotopyConst (p : Path x₀ x₁) :
    (ContinuousMap.const Y x₀).Homotopy (ContinuousMap.const Y x₁) 
goal: ∀ (a : ↑I × Y), p.toHomotopyConst a = p a.1

full_name: Path.toHomotopyConst
code: /-- A path `Path x₀ x₁` generates a homotopy between constant functions `fun _ ↦ x₀` and
`fun _ ↦ x₁`. -/
@[simps!]
def toHomotopyConst (p : Path x₀ x₁) :
    (ContinuousMap.const Y x₀).Homotopy (ContinuousMap.const Y x₁) 
goal: (ContinuousMap.const Y x₀).Homotopy (ContinuousMap.const Y x₁)

full_name: ContinuousMap.homotopic_const_iff
code: /-- Two constant continuous maps with nonempty domain are homotopic if and only if their values are
joined by a path in the codomain. -/
@[simp]
theorem ContinuousMap.homotopic_const_iff [Nonempty Y] :
    (ContinuousMap.const Y x₀).Homotopic (ContinuousMap.const Y x₁) ↔ Joined x₀ x₁ 
goal: (ContinuousMap.const Y x₀).Homotopic (ContinuousMap.const Y x₁) ↔ Joined x₀ x₁

full_name: ContinuousMap.Homotopy.evalAt
code: /-- Given a homotopy `H : f ∼ g`, get the path traced by the point `x` as it moves from
`f x` to `g x`.
-/
def evalAt {X : Type*} {Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] {f g : C(X, Y)}
    (H : ContinuousMap.Homotopy f g) (x : X) : Path (f x) (g x) 
goal: Path (f x) (g x)