l3lab/ntp-mathlib huggingface dataset:
/-- Embeddings from a sum type are equivalent to two separate embeddings with disjoint ranges. -/
def sumEmbeddingEquivProdEmbeddingDisjoint {α β γ : Type*} :
    (Sum α β ↪ γ) ≃ { f : (α ↪ γ) × (β ↪ γ) // Disjoint (Set.range f.1) (Set.range f.2) } where
  toFun f :=
    ⟨(inl.trans f, inr.trans f), by
      rw [Set.disjoint_left]
      rintro _ ⟨a, h⟩ ⟨b, rfl⟩
      simp only [trans_apply, inl_apply, inr_apply] at h
      have : Sum.inl a = Sum.inr b := f.injective h
      simp only at this⟩
  invFun := fun ⟨⟨f, g⟩, disj⟩ =>
    ⟨fun x =>
      match x with
      | Sum.inl a => f a
      | Sum.inr b => g b, by
      rintro (a₁ | b₁) (a₂ | b₂) f_eq <;>
        simp only [Equiv.coe_fn_symm_mk, Sum.elim_inl, Sum.elim_inr] at f_eq
      · rw [f.injective f_eq]
      · exfalso
        refine disj.le_bot ⟨⟨a₁, f_eq⟩, ⟨b₂, by simp [f_eq]⟩⟩
      · exfalso
        

Proof state:
case inr.inl.h
α : Type u_1
β : Type u_2
γ : Type u_3
x✝ : { f // Disjoint (Set.range ⇑f.1) (Set.range ⇑f.2) }
f : α ↪ γ
g : β ↪ γ
disj : Disjoint (Set.range ⇑(f, g).1) (Set.range ⇑(f, g).2)
b₁ : β
a₂ : α
f_eq : g b₁ = f a₂
⊢ False

Next tactic:
exact disj.le_bot ⟨⟨a₂, rfl⟩, ⟨b₁, f_eq⟩⟩
/-- Embeddings from a sum type are equivalent to two separate embeddings with disjoint ranges. -/
def sumEmbeddingEquivProdEmbeddingDisjoint {α β γ : Type*} :
    (Sum α β ↪ γ) ≃ { f : (α ↪ γ) × (β ↪ γ) // Disjoint (Set.range f.1) (Set.range f.2) } where
  toFun f :=
    ⟨(inl.trans f, inr.trans f), by
      rw [Set.disjoint_left]
      rintro _ ⟨a, h⟩ ⟨b, rfl⟩
      simp only [trans_apply, inl_apply, inr_apply] at h
      have : Sum.inl a = Sum.inr b := f.injective h
      simp only at this⟩
  invFun := fun ⟨⟨f, g⟩, disj⟩ =>
    ⟨fun x =>
      match x with
      | Sum.inl a => f a
      | Sum.inr b => g b, by
      rintro (a₁ | b₁) (a₂ | b₂) f_eq <;>
        simp only [Equiv.coe_fn_symm_mk, Sum.elim_inl, Sum.elim_inr] at f_eq
      · rw [f.injective f_eq]
      · exfalso
        refine disj.le_bot ⟨⟨a₁, f_eq⟩, ⟨b₂, by simp [f_eq]⟩⟩
      · exfalso
        exact disj.le_bot ⟨⟨a₂, rfl⟩, ⟨b₁, f_eq⟩⟩
      · 

Proof state:
case inr.inr
α : Type u_1
β : Type u_2
γ : Type u_3
x✝ : { f // Disjoint (Set.range ⇑f.1) (Set.range ⇑f.2) }
f : α ↪ γ
g : β ↪ γ
disj : Disjoint (Set.range ⇑(f, g).1) (Set.range ⇑(f, g).2)
b₁ b₂ : β
f_eq : g b₁ = g b₂
⊢ Sum.inr b₁ = Sum.inr b₂

Next tactic:
rw [g.injective f_eq]
/-- Embeddings from a sum type are equivalent to two separate embeddings with disjoint ranges. -/
def sumEmbeddingEquivProdEmbeddingDisjoint {α β γ : Type*} :
    (Sum α β ↪ γ) ≃ { f : (α ↪ γ) × (β ↪ γ) // Disjoint (Set.range f.1) (Set.range f.2) } where
  toFun f :=
    ⟨(inl.trans f, inr.trans f), by
      rw [Set.disjoint_left]
      rintro _ ⟨a, h⟩ ⟨b, rfl⟩
      simp only [trans_apply, inl_apply, inr_apply] at h
      have : Sum.inl a = Sum.inr b := f.injective h
      simp only at this⟩
  invFun := fun ⟨⟨f, g⟩, disj⟩ =>
    ⟨fun x =>
      match x with
      | Sum.inl a => f a
      | Sum.inr b => g b, by
      rintro (a₁ | b₁) (a₂ | b₂) f_eq <;>
        simp only [Equiv.coe_fn_symm_mk, Sum.elim_inl, Sum.elim_inr] at f_eq
      · rw [f.injective f_eq]
      · exfalso
        refine disj.le_bot ⟨⟨a₁, f_eq⟩, ⟨b₂, by simp [f_eq]⟩⟩
      · exfalso
        exact disj.le_bot ⟨⟨a₂, rfl⟩, ⟨b₁, f_eq⟩⟩
      · rw [g.injective f_eq]⟩
  left_inv f := by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
f : α ⊕ β ↪ γ
⊢ (fun x =>
        match x with
        | { val := (f, g), property := disj } =>
          {
            toFun := fun x =>
              match x with
              | Sum.inl a => f a
              | Sum.inr b => g b,
            inj' :=
              (_ :
                ∀ ⦃a₁ a₂ : α ⊕ β⦄,
                  (fun x =>
                          match x with
                          | Sum.inl a => f a
                          | Sum.inr b => g b)
                        a₁ =
                      (fun x =>
                          match x with
                          | Sum.inl a => f a
                          | Sum.inr b => g b)
                        a₂ →
                    a₁ = a₂) })
      ((fun f =>
          { val := (Function.Embedding.trans inl f, Function.Embedding.trans inr f),
            property :=
              (_ :
                Disjoint (Set.range ⇑(Function.Embedding.trans inl f, Function.Embedding.trans inr f).1)
                  (Set.range ⇑(Function.Embedding.trans inl f, Function.Embedding.trans inr f).2)) })
        f) =
    f

Next tactic:
dsimp only
/-- Embeddings from a sum type are equivalent to two separate embeddings with disjoint ranges. -/
def sumEmbeddingEquivProdEmbeddingDisjoint {α β γ : Type*} :
    (Sum α β ↪ γ) ≃ { f : (α ↪ γ) × (β ↪ γ) // Disjoint (Set.range f.1) (Set.range f.2) } where
  toFun f :=
    ⟨(inl.trans f, inr.trans f), by
      rw [Set.disjoint_left]
      rintro _ ⟨a, h⟩ ⟨b, rfl⟩
      simp only [trans_apply, inl_apply, inr_apply] at h
      have : Sum.inl a = Sum.inr b := f.injective h
      simp only at this⟩
  invFun := fun ⟨⟨f, g⟩, disj⟩ =>
    ⟨fun x =>
      match x with
      | Sum.inl a => f a
      | Sum.inr b => g b, by
      rintro (a₁ | b₁) (a₂ | b₂) f_eq <;>
        simp only [Equiv.coe_fn_symm_mk, Sum.elim_inl, Sum.elim_inr] at f_eq
      · rw [f.injective f_eq]
      · exfalso
        refine disj.le_bot ⟨⟨a₁, f_eq⟩, ⟨b₂, by simp [f_eq]⟩⟩
      · exfalso
        exact disj.le_bot ⟨⟨a₂, rfl⟩, ⟨b₁, f_eq⟩⟩
      · rw [g.injective f_eq]⟩
  left_inv f := by
    dsimp only
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
f : α ⊕ β ↪ γ
⊢ {
      toFun := fun x =>
        match x with
        | Sum.inl a => (Function.Embedding.trans inl f) a
        | Sum.inr b => (Function.Embedding.trans inr f) b,
      inj' :=
        (_ :
          ∀ ⦃a₁ a₂ : α ⊕ β⦄,
            ((match a₁ with
                | Sum.inl a => (Function.Embedding.trans inl f) a
                | Sum.inr b => (Function.Embedding.trans inr f) b) =
                match a₂ with
                | Sum.inl a => (Function.Embedding.trans inl f) a
                | Sum.inr b => (Function.Embedding.trans inr f) b) →
              a₁ = a₂) } =
    f

Next tactic:
ext x
/-- Embeddings from a sum type are equivalent to two separate embeddings with disjoint ranges. -/
def sumEmbeddingEquivProdEmbeddingDisjoint {α β γ : Type*} :
    (Sum α β ↪ γ) ≃ { f : (α ↪ γ) × (β ↪ γ) // Disjoint (Set.range f.1) (Set.range f.2) } where
  toFun f :=
    ⟨(inl.trans f, inr.trans f), by
      rw [Set.disjoint_left]
      rintro _ ⟨a, h⟩ ⟨b, rfl⟩
      simp only [trans_apply, inl_apply, inr_apply] at h
      have : Sum.inl a = Sum.inr b := f.injective h
      simp only at this⟩
  invFun := fun ⟨⟨f, g⟩, disj⟩ =>
    ⟨fun x =>
      match x with
      | Sum.inl a => f a
      | Sum.inr b => g b, by
      rintro (a₁ | b₁) (a₂ | b₂) f_eq <;>
        simp only [Equiv.coe_fn_symm_mk, Sum.elim_inl, Sum.elim_inr] at f_eq
      · rw [f.injective f_eq]
      · exfalso
        refine disj.le_bot ⟨⟨a₁, f_eq⟩, ⟨b₂, by simp [f_eq]⟩⟩
      · exfalso
        exact disj.le_bot ⟨⟨a₂, rfl⟩, ⟨b₁, f_eq⟩⟩
      · rw [g.injective f_eq]⟩
  left_inv f := by
    dsimp only
    ext x
    

Proof state:
case h
α : Type u_1
β : Type u_2
γ : Type u_3
f : α ⊕ β ↪ γ
x : α ⊕ β
⊢ {
        toFun := fun x =>
          match x with
          | Sum.inl a => (Function.Embedding.trans inl f) a
          | Sum.inr b => (Function.Embedding.trans inr f) b,
        inj' :=
          (_ :
            ∀ ⦃a₁ a₂ : α ⊕ β⦄,
              ((match a₁ with
                  | Sum.inl a => (Function.Embedding.trans inl f) a
                  | Sum.inr b => (Function.Embedding.trans inr f) b) =
                  match a₂ with
                  | Sum.inl a => (Function.Embedding.trans inl f) a
                  | Sum.inr b => (Function.Embedding.trans inr f) b) →
                a₁ = a₂) }
      x =
    f x

Next tactic:
cases x
/-- Embeddings from a sum type are equivalent to two separate embeddings with disjoint ranges. -/
def sumEmbeddingEquivProdEmbeddingDisjoint {α β γ : Type*} :
    (Sum α β ↪ γ) ≃ { f : (α ↪ γ) × (β ↪ γ) // Disjoint (Set.range f.1) (Set.range f.2) } where
  toFun f :=
    ⟨(inl.trans f, inr.trans f), by
      rw [Set.disjoint_left]
      rintro _ ⟨a, h⟩ ⟨b, rfl⟩
      simp only [trans_apply, inl_apply, inr_apply] at h
      have : Sum.inl a = Sum.inr b := f.injective h
      simp only at this⟩
  invFun := fun ⟨⟨f, g⟩, disj⟩ =>
    ⟨fun x =>
      match x with
      | Sum.inl a => f a
      | Sum.inr b => g b, by
      rintro (a₁ | b₁) (a₂ | b₂) f_eq <;>
        simp only [Equiv.coe_fn_symm_mk, Sum.elim_inl, Sum.elim_inr] at f_eq
      · rw [f.injective f_eq]
      · exfalso
        refine disj.le_bot ⟨⟨a₁, f_eq⟩, ⟨b₂, by simp [f_eq]⟩⟩
      · exfalso
        exact disj.le_bot ⟨⟨a₂, rfl⟩, ⟨b₁, f_eq⟩⟩
      · rw [g.injective f_eq]⟩
  left_inv f := by
    dsimp only
    ext x
    cases x <;> 

Proof state:
case h.inl
α : Type u_1
β : Type u_2
γ : Type u_3
f : α ⊕ β ↪ γ
val✝ : α
⊢ {
        toFun := fun x =>
          match x with
          | Sum.inl a => (Function.Embedding.trans inl f) a
          | Sum.inr b => (Function.Embedding.trans inr f) b,
        inj' :=
          (_ :
            ∀ ⦃a₁ a₂ : α ⊕ β⦄,
              ((match a₁ with
                  | Sum.inl a => (Function.Embedding.trans inl f) a
                  | Sum.inr b => (Function.Embedding.trans inr f) b) =
                  match a₂ with
                  | Sum.inl a => (Function.Embedding.trans inl f) a
                  | Sum.inr b => (Function.Embedding.trans inr f) b) →
                a₁ = a₂) }
      (Sum.inl val✝) =
    f (Sum.inl val✝)

Next tactic:
simp!
/-- Embeddings from a sum type are equivalent to two separate embeddings with disjoint ranges. -/
def sumEmbeddingEquivProdEmbeddingDisjoint {α β γ : Type*} :
    (Sum α β ↪ γ) ≃ { f : (α ↪ γ) × (β ↪ γ) // Disjoint (Set.range f.1) (Set.range f.2) } where
  toFun f :=
    ⟨(inl.trans f, inr.trans f), by
      rw [Set.disjoint_left]
      rintro _ ⟨a, h⟩ ⟨b, rfl⟩
      simp only [trans_apply, inl_apply, inr_apply] at h
      have : Sum.inl a = Sum.inr b := f.injective h
      simp only at this⟩
  invFun := fun ⟨⟨f, g⟩, disj⟩ =>
    ⟨fun x =>
      match x with
      | Sum.inl a => f a
      | Sum.inr b => g b, by
      rintro (a₁ | b₁) (a₂ | b₂) f_eq <;>
        simp only [Equiv.coe_fn_symm_mk, Sum.elim_inl, Sum.elim_inr] at f_eq
      · rw [f.injective f_eq]
      · exfalso
        refine disj.le_bot ⟨⟨a₁, f_eq⟩, ⟨b₂, by simp [f_eq]⟩⟩
      · exfalso
        exact disj.le_bot ⟨⟨a₂, rfl⟩, ⟨b₁, f_eq⟩⟩
      · rw [g.injective f_eq]⟩
  left_inv f := by
    dsimp only
    ext x
    cases x <;> 

Proof state:
case h.inr
α : Type u_1
β : Type u_2
γ : Type u_3
f : α ⊕ β ↪ γ
val✝ : β
⊢ {
        toFun := fun x =>
          match x with
          | Sum.inl a => (Function.Embedding.trans inl f) a
          | Sum.inr b => (Function.Embedding.trans inr f) b,
        inj' :=
          (_ :
            ∀ ⦃a₁ a₂ : α ⊕ β⦄,
              ((match a₁ with
                  | Sum.inl a => (Function.Embedding.trans inl f) a
                  | Sum.inr b => (Function.Embedding.trans inr f) b) =
                  match a₂ with
                  | Sum.inl a => (Function.Embedding.trans inl f) a
                  | Sum.inr b => (Function.Embedding.trans inr f) b) →
                a₁ = a₂) }
      (Sum.inr val✝) =
    f (Sum.inr val✝)

Next tactic:
simp!
/-- Embeddings from a sum type are equivalent to two separate embeddings with disjoint ranges. -/
def sumEmbeddingEquivProdEmbeddingDisjoint {α β γ : Type*} :
    (Sum α β ↪ γ) ≃ { f : (α ↪ γ) × (β ↪ γ) // Disjoint (Set.range f.1) (Set.range f.2) } where
  toFun f :=
    ⟨(inl.trans f, inr.trans f), by
      rw [Set.disjoint_left]
      rintro _ ⟨a, h⟩ ⟨b, rfl⟩
      simp only [trans_apply, inl_apply, inr_apply] at h
      have : Sum.inl a = Sum.inr b := f.injective h
      simp only at this⟩
  invFun := fun ⟨⟨f, g⟩, disj⟩ =>
    ⟨fun x =>
      match x with
      | Sum.inl a => f a
      | Sum.inr b => g b, by
      rintro (a₁ | b₁) (a₂ | b₂) f_eq <;>
        simp only [Equiv.coe_fn_symm_mk, Sum.elim_inl, Sum.elim_inr] at f_eq
      · rw [f.injective f_eq]
      · exfalso
        refine disj.le_bot ⟨⟨a₁, f_eq⟩, ⟨b₂, by simp [f_eq]⟩⟩
      · exfalso
        exact disj.le_bot ⟨⟨a₂, rfl⟩, ⟨b₁, f_eq⟩⟩
      · rw [g.injective f_eq]⟩
  left_inv f := by
    dsimp only
    ext x
    cases x <;> simp!
  right_inv := fun ⟨⟨f, g⟩, _⟩ => by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x✝ : { f // Disjoint (Set.range ⇑f.1) (Set.range ⇑f.2) }
f : α ↪ γ
g : β ↪ γ
property✝ : Disjoint (Set.range ⇑(f, g).1) (Set.range ⇑(f, g).2)
⊢ (fun f =>
        { val := (Function.Embedding.trans inl f, Function.Embedding.trans inr f),
          property :=
            (_ :
              Disjoint (Set.range ⇑(Function.Embedding.trans inl f, Function.Embedding.trans inr f).1)
                (Set.range ⇑(Function.Embedding.trans inl f, Function.Embedding.trans inr f).2)) })
      ((fun x =>
          match x with
          | { val := (f, g), property := disj } =>
            {
              toFun := fun x =>
                match x with
                | Sum.inl a => f a
                | Sum.inr b => g b,
              inj' :=
                (_ :
                  ∀ ⦃a₁ a₂ : α ⊕ β⦄,
                    (fun x =>
                            match x with
                            | Sum.inl a => f a
                            | Sum.inr b => g b)
                          a₁ =
                        (fun x =>
                            match x with
                            | Sum.inl a => f a
                            | Sum.inr b => g b)
                          a₂ →
                      a₁ = a₂) })
        { val := (f, g), property := property✝ }) =
    { val := (f, g), property := property✝ }

Next tactic:
simp only [Prod.mk.inj_iff]
/-- Embeddings whose range lies within a set are equivalent to embeddings to that set.
This is `Function.Embedding.codRestrict` as an equiv. -/
def codRestrict (α : Type*) {β : Type*} (bs : Set β) :
    { f : α ↪ β // ∀ a, f a ∈ bs } ≃
      (α ↪ bs) where
  toFun f := (f : α ↪ β).codRestrict bs f.prop
  invFun f := ⟨f.trans (Function.Embedding.subtype _), fun a => (f a).prop⟩
  left_inv x := by 

Proof state:
α : Type u_1
β : Type u_2
bs : Set β
x : { f // ∀ (a : α), f a ∈ bs }
⊢ (fun f => { val := Function.Embedding.trans f (subtype fun x => x ∈ bs), property := (_ : ∀ (a : α), ↑(f a) ∈ bs) })
      ((fun f => Function.Embedding.codRestrict bs ↑f (_ : ∀ (a : α), ↑f a ∈ bs)) x) =
    x

Next tactic:
ext
/-- Embeddings whose range lies within a set are equivalent to embeddings to that set.
This is `Function.Embedding.codRestrict` as an equiv. -/
def codRestrict (α : Type*) {β : Type*} (bs : Set β) :
    { f : α ↪ β // ∀ a, f a ∈ bs } ≃
      (α ↪ bs) where
  toFun f := (f : α ↪ β).codRestrict bs f.prop
  invFun f := ⟨f.trans (Function.Embedding.subtype _), fun a => (f a).prop⟩
  left_inv x := by ext; 

Proof state:
case a.h
α : Type u_1
β : Type u_2
bs : Set β
x : { f // ∀ (a : α), f a ∈ bs }
x✝ : α
⊢ ↑((fun f => { val := Function.Embedding.trans f (subtype fun x => x ∈ bs), property := (_ : ∀ (a : α), ↑(f a) ∈ bs) })
          ((fun f => Function.Embedding.codRestrict bs ↑f (_ : ∀ (a : α), ↑f a ∈ bs)) x))
      x✝ =
    ↑x x✝

Next tactic:
rfl
/-- Embeddings whose range lies within a set are equivalent to embeddings to that set.
This is `Function.Embedding.codRestrict` as an equiv. -/
def codRestrict (α : Type*) {β : Type*} (bs : Set β) :
    { f : α ↪ β // ∀ a, f a ∈ bs } ≃
      (α ↪ bs) where
  toFun f := (f : α ↪ β).codRestrict bs f.prop
  invFun f := ⟨f.trans (Function.Embedding.subtype _), fun a => (f a).prop⟩
  left_inv x := by ext; rfl
  right_inv x := by 

Proof state:
α : Type u_1
β : Type u_2
bs : Set β
x : α ↪ ↑bs
⊢ (fun f => Function.Embedding.codRestrict bs ↑f (_ : ∀ (a : α), ↑f a ∈ bs))
      ((fun f =>
          { val := Function.Embedding.trans f (subtype fun x => x ∈ bs), property := (_ : ∀ (a : α), ↑(f a) ∈ bs) })
        x) =
    x

Next tactic:
ext
/-- Embeddings whose range lies within a set are equivalent to embeddings to that set.
This is `Function.Embedding.codRestrict` as an equiv. -/
def codRestrict (α : Type*) {β : Type*} (bs : Set β) :
    { f : α ↪ β // ∀ a, f a ∈ bs } ≃
      (α ↪ bs) where
  toFun f := (f : α ↪ β).codRestrict bs f.prop
  invFun f := ⟨f.trans (Function.Embedding.subtype _), fun a => (f a).prop⟩
  left_inv x := by ext; rfl
  right_inv x := by ext; 

Proof state:
case h.a
α : Type u_1
β : Type u_2
bs : Set β
x : α ↪ ↑bs
x✝ : α
⊢ ↑(((fun f => Function.Embedding.codRestrict bs ↑f (_ : ∀ (a : α), ↑f a ∈ bs))
          ((fun f =>
              { val := Function.Embedding.trans f (subtype fun x => x ∈ bs), property := (_ : ∀ (a : α), ↑(f a) ∈ bs) })
            x))
        x✝) =
    ↑(x x✝)

Next tactic:
rfl
/-- Pairs of embeddings with disjoint ranges are equivalent to a dependent sum of embeddings,
in which the second embedding cannot take values in the range of the first. -/
def prodEmbeddingDisjointEquivSigmaEmbeddingRestricted {α β γ : Type*} :
    { f : (α ↪ γ) × (β ↪ γ) // Disjoint (Set.range f.1) (Set.range f.2) } ≃
      Σf : α ↪ γ, β ↪ ↥(Set.range f)ᶜ :=
  (subtypeProdEquivSigmaSubtype fun (a : α ↪ γ) (b : β ↪ _) =>
        Disjoint (Set.range a) (Set.range b)).trans <|
    Equiv.sigmaCongrRight fun a =>
      (subtypeEquivProp <| by
            

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
a : α ↪ γ
⊢ (fun b => Disjoint (Set.range ⇑a) (Set.range ⇑b)) = fun f => ∀ (a_1 : β), f a_1 ∈ (Set.range ⇑a)ᶜ

Next tactic:
ext f
/-- Pairs of embeddings with disjoint ranges are equivalent to a dependent sum of embeddings,
in which the second embedding cannot take values in the range of the first. -/
def prodEmbeddingDisjointEquivSigmaEmbeddingRestricted {α β γ : Type*} :
    { f : (α ↪ γ) × (β ↪ γ) // Disjoint (Set.range f.1) (Set.range f.2) } ≃
      Σf : α ↪ γ, β ↪ ↥(Set.range f)ᶜ :=
  (subtypeProdEquivSigmaSubtype fun (a : α ↪ γ) (b : β ↪ _) =>
        Disjoint (Set.range a) (Set.range b)).trans <|
    Equiv.sigmaCongrRight fun a =>
      (subtypeEquivProp <| by
            ext f
            

Proof state:
case h.a
α : Type u_1
β : Type u_2
γ : Type u_3
a : α ↪ γ
f : β ↪ γ
⊢ Disjoint (Set.range ⇑a) (Set.range ⇑f) ↔ ∀ (a_1 : β), f a_1 ∈ (Set.range ⇑a)ᶜ

Next tactic:
rw [← Set.range_subset_iff, Set.subset_compl_iff_disjoint_right, disjoint_comm]
/-- Embeddings from a single-member type are equivalent to members of the target type. -/
def uniqueEmbeddingEquivResult {α β : Type*} [Unique α] :
    (α ↪ β) ≃ β where
  toFun f := f default
  invFun x := ⟨fun _ => x, fun _ _ _ => Subsingleton.elim _ _⟩
  left_inv _ := by
    

Proof state:
α : Type u_1
β : Type u_2
inst✝ : Unique α
x✝ : α ↪ β
⊢ (fun x =>
        { toFun := fun x_1 => x, inj' := (_ : ∀ (x_1 x_2 : α), (fun x_3 => x) x_1 = (fun x_3 => x) x_2 → x_1 = x_2) })
      ((fun f => f default) x✝) =
    x✝

Next tactic:
ext x
/-- Embeddings from a single-member type are equivalent to members of the target type. -/
def uniqueEmbeddingEquivResult {α β : Type*} [Unique α] :
    (α ↪ β) ≃ β where
  toFun f := f default
  invFun x := ⟨fun _ => x, fun _ _ _ => Subsingleton.elim _ _⟩
  left_inv _ := by
    ext x
    

Proof state:
case h
α : Type u_1
β : Type u_2
inst✝ : Unique α
x✝ : α ↪ β
x : α
⊢ ((fun x =>
          { toFun := fun x_1 => x, inj' := (_ : ∀ (x_1 x_2 : α), (fun x_3 => x) x_1 = (fun x_3 => x) x_2 → x_1 = x_2) })
        ((fun f => f default) x✝))
      x =
    x✝ x

Next tactic:
simp_rw [Function.Embedding.coeFn_mk]
/-- Embeddings from a single-member type are equivalent to members of the target type. -/
def uniqueEmbeddingEquivResult {α β : Type*} [Unique α] :
    (α ↪ β) ≃ β where
  toFun f := f default
  invFun x := ⟨fun _ => x, fun _ _ _ => Subsingleton.elim _ _⟩
  left_inv _ := by
    ext x
    simp_rw [Function.Embedding.coeFn_mk]
    

Proof state:
case h
α : Type u_1
β : Type u_2
inst✝ : Unique α
x✝ : α ↪ β
x : α
⊢ x✝ default = x✝ x

Next tactic:
congr 1
/-- Embeddings from a single-member type are equivalent to members of the target type. -/
def uniqueEmbeddingEquivResult {α β : Type*} [Unique α] :
    (α ↪ β) ≃ β where
  toFun f := f default
  invFun x := ⟨fun _ => x, fun _ _ _ => Subsingleton.elim _ _⟩
  left_inv _ := by
    ext x
    simp_rw [Function.Embedding.coeFn_mk]
    congr 1
    

Proof state:
case h.h.e_6.h
α : Type u_1
β : Type u_2
inst✝ : Unique α
x✝ : α ↪ β
x : α
⊢ default = x

Next tactic:
exact Subsingleton.elim _ x
/-- Embeddings from a single-member type are equivalent to members of the target type. -/
def uniqueEmbeddingEquivResult {α β : Type*} [Unique α] :
    (α ↪ β) ≃ β where
  toFun f := f default
  invFun x := ⟨fun _ => x, fun _ _ _ => Subsingleton.elim _ _⟩
  left_inv _ := by
    ext x
    simp_rw [Function.Embedding.coeFn_mk]
    congr 1
    exact Subsingleton.elim _ x
  right_inv _ := by 

Proof state:
α : Type u_1
β : Type u_2
inst✝ : Unique α
x✝ : β
⊢ (fun f => f default)
      ((fun x =>
          { toFun := fun x_1 => x, inj' := (_ : ∀ (x_1 x_2 : α), (fun x_3 => x) x_1 = (fun x_3 => x) x_2 → x_1 = x_2) })
        x✝) =
    x✝

Next tactic:
simp
theorem Filter.HasBasis.cauchy_iff {ι} {p : ι → Prop} {s : ι → Set (α × α)} (h : (𝓤 α).HasBasis p s)
    {f : Filter α} :
    Cauchy f ↔ NeBot f ∧ ∀ i, p i → ∃ t ∈ f, ∀ x ∈ t, ∀ y ∈ t, (x, y) ∈ s i :=
  and_congr Iff.rfl <|
    (f.basis_sets.prod_self.le_basis_iff h).trans <| by
      

Proof state:
α : Type u
β : Type v
uniformSpace : UniformSpace α
ι : Sort u_1
p : ι → Prop
s : ι → Set (α × α)
h : HasBasis (𝓤 α) p s
f : Filter α
⊢ (∀ (i' : ι), p i' → ∃ i ∈ f, id i ×ˢ id i ⊆ s i') ↔ ∀ (i : ι), p i → ∃ t ∈ f, ∀ x ∈ t, ∀ y ∈ t, (x, y) ∈ s i

Next tactic:
simp only [subset_def, Prod.forall, mem_prod_eq, and_imp, id, ball_mem_comm]
theorem cauchy_iff {f : Filter α} : Cauchy f ↔ NeBot f ∧ ∀ s ∈ 𝓤 α, ∃ t ∈ f, t ×ˢ t ⊆ s :=
  cauchy_iff'.trans <| by
    

Proof state:
α : Type u
β : Type v
uniformSpace : UniformSpace α
f : Filter α
⊢ (NeBot f ∧ ∀ s ∈ 𝓤 α, ∃ t ∈ f, ∀ x ∈ t, ∀ y ∈ t, (x, y) ∈ s) ↔ NeBot f ∧ ∀ s ∈ 𝓤 α, ∃ t ∈ f, t ×ˢ t ⊆ s

Next tactic:
simp only [subset_def, Prod.forall, mem_prod_eq, and_imp, id, ball_mem_comm]
lemma cauchy_iff_le {l : Filter α} [hl : l.NeBot] :
    Cauchy l ↔ l ×ˢ l ≤ 𝓤 α := by
  

Proof state:
α : Type u
β : Type v
uniformSpace : UniformSpace α
l : Filter α
hl : NeBot l
⊢ Cauchy l ↔ l ×ˢ l ≤ 𝓤 α

Next tactic:
simp only [Cauchy, hl, true_and]
theorem Cauchy.ultrafilter_of {l : Filter α} (h : Cauchy l) :
    Cauchy (@Ultrafilter.of _ l h.1 : Filter α) := by
  

Proof state:
α : Type u
β : Type v
uniformSpace : UniformSpace α
l : Filter α
h : Cauchy l
⊢ Cauchy ↑(Ultrafilter.of l)

Next tactic:
haveI := h.1
theorem Cauchy.ultrafilter_of {l : Filter α} (h : Cauchy l) :
    Cauchy (@Ultrafilter.of _ l h.1 : Filter α) := by
  haveI := h.1
  

Proof state:
α : Type u
β : Type v
uniformSpace : UniformSpace α
l : Filter α
h : Cauchy l
this : NeBot l
⊢ Cauchy ↑(Ultrafilter.of l)

Next tactic:
have := Ultrafilter.of_le l
theorem Cauchy.ultrafilter_of {l : Filter α} (h : Cauchy l) :
    Cauchy (@Ultrafilter.of _ l h.1 : Filter α) := by
  haveI := h.1
  have := Ultrafilter.of_le l
  

Proof state:
α : Type u
β : Type v
uniformSpace : UniformSpace α
l : Filter α
h : Cauchy l
this✝ : NeBot l
this : ↑(Ultrafilter.of l) ≤ l
⊢ Cauchy ↑(Ultrafilter.of l)

Next tactic:
exact ⟨Ultrafilter.neBot _, (Filter.prod_mono this this).trans h.2⟩
theorem cauchy_map_iff {l : Filter β} {f : β → α} :
    Cauchy (l.map f) ↔ NeBot l ∧ Tendsto (fun p : β × β => (f p.1, f p.2)) (l ×ˢ l) (𝓤 α) := by
  

Proof state:
α : Type u
β : Type v
uniformSpace : UniformSpace α
l : Filter β
f : β → α
⊢ Cauchy (map f l) ↔ NeBot l ∧ Tendsto (fun p => (f p.1, f p.2)) (l ×ˢ l) (𝓤 α)

Next tactic:
rw [Cauchy, map_neBot_iff, prod_map_map_eq, Tendsto]
lemma cauchy_inf_uniformSpace {u v : UniformSpace β} {F : Filter β} :
    Cauchy (uniformSpace := u ⊓ v) F ↔
    Cauchy (uniformSpace := u) F ∧ Cauchy (uniformSpace := v) F := by
  

Proof state:
α : Type u
β : Type v
uniformSpace : UniformSpace α
u v : UniformSpace β
F : Filter β
⊢ Cauchy F ↔ Cauchy F ∧ Cauchy F

Next tactic:
unfold Cauchy