l3lab/ntp-mathlib huggingface dataset:
protected theorem lt_succ_iff {r : α → α → Prop} [wo : IsWellOrder α r] {x : α} (h : ∃ y, r x y)
    (y : α) : r y (wo.wf.succ x) ↔ r y x ∨ y = x := by
  constructor
  · intro h'
    have : ¬r x y := by
      intro hy
      rw [WellFounded.succ, dif_pos] at h'
      exact wo.wf.not_lt_min _ h hy h'
    rcases trichotomous_of r x y with (hy | hy | hy)
    exfalso
    exact this hy
    

Proof state:
case mp.inr.inl
α : Type u_1
β : Type u_2
γ : Type u_3
r✝ r' r : α → α → Prop
wo : IsWellOrder α r
x : α
h : ∃ y, r x y
y : α
h' : r y (WellFounded.succ (_ : WellFounded r) x)
this : ¬r x y
hy : x = y
⊢ r y x ∨ y = x
case mp.inr.inr
α : Type u_1
β : Type u_2
γ : Type u_3
r✝ r' r : α → α → Prop
wo : IsWellOrder α r
x : α
h : ∃ y, r x y
y : α
h' : r y (WellFounded.succ (_ : WellFounded r) x)
this : ¬r x y
hy : r y x
⊢ r y x ∨ y = x

Next tactic:
right
protected theorem lt_succ_iff {r : α → α → Prop} [wo : IsWellOrder α r] {x : α} (h : ∃ y, r x y)
    (y : α) : r y (wo.wf.succ x) ↔ r y x ∨ y = x := by
  constructor
  · intro h'
    have : ¬r x y := by
      intro hy
      rw [WellFounded.succ, dif_pos] at h'
      exact wo.wf.not_lt_min _ h hy h'
    rcases trichotomous_of r x y with (hy | hy | hy)
    exfalso
    exact this hy
    right
    

Proof state:
case mp.inr.inl.h
α : Type u_1
β : Type u_2
γ : Type u_3
r✝ r' r : α → α → Prop
wo : IsWellOrder α r
x : α
h : ∃ y, r x y
y : α
h' : r y (WellFounded.succ (_ : WellFounded r) x)
this : ¬r x y
hy : x = y
⊢ y = x
case mp.inr.inr
α : Type u_1
β : Type u_2
γ : Type u_3
r✝ r' r : α → α → Prop
wo : IsWellOrder α r
x : α
h : ∃ y, r x y
y : α
h' : r y (WellFounded.succ (_ : WellFounded r) x)
this : ¬r x y
hy : r y x
⊢ r y x ∨ y = x

Next tactic:
exact hy.symm
protected theorem lt_succ_iff {r : α → α → Prop} [wo : IsWellOrder α r] {x : α} (h : ∃ y, r x y)
    (y : α) : r y (wo.wf.succ x) ↔ r y x ∨ y = x := by
  constructor
  · intro h'
    have : ¬r x y := by
      intro hy
      rw [WellFounded.succ, dif_pos] at h'
      exact wo.wf.not_lt_min _ h hy h'
    rcases trichotomous_of r x y with (hy | hy | hy)
    exfalso
    exact this hy
    right
    exact hy.symm
    

Proof state:
case mp.inr.inr
α : Type u_1
β : Type u_2
γ : Type u_3
r✝ r' r : α → α → Prop
wo : IsWellOrder α r
x : α
h : ∃ y, r x y
y : α
h' : r y (WellFounded.succ (_ : WellFounded r) x)
this : ¬r x y
hy : r y x
⊢ r y x ∨ y = x

Next tactic:
left
protected theorem lt_succ_iff {r : α → α → Prop} [wo : IsWellOrder α r] {x : α} (h : ∃ y, r x y)
    (y : α) : r y (wo.wf.succ x) ↔ r y x ∨ y = x := by
  constructor
  · intro h'
    have : ¬r x y := by
      intro hy
      rw [WellFounded.succ, dif_pos] at h'
      exact wo.wf.not_lt_min _ h hy h'
    rcases trichotomous_of r x y with (hy | hy | hy)
    exfalso
    exact this hy
    right
    exact hy.symm
    left
    

Proof state:
case mp.inr.inr.h
α : Type u_1
β : Type u_2
γ : Type u_3
r✝ r' r : α → α → Prop
wo : IsWellOrder α r
x : α
h : ∃ y, r x y
y : α
h' : r y (WellFounded.succ (_ : WellFounded r) x)
this : ¬r x y
hy : r y x
⊢ r y x

Next tactic:
exact hy
protected theorem lt_succ_iff {r : α → α → Prop} [wo : IsWellOrder α r] {x : α} (h : ∃ y, r x y)
    (y : α) : r y (wo.wf.succ x) ↔ r y x ∨ y = x := by
  constructor
  · intro h'
    have : ¬r x y := by
      intro hy
      rw [WellFounded.succ, dif_pos] at h'
      exact wo.wf.not_lt_min _ h hy h'
    rcases trichotomous_of r x y with (hy | hy | hy)
    exfalso
    exact this hy
    right
    exact hy.symm
    left
    exact hy
  

Proof state:
case mpr
α : Type u_1
β : Type u_2
γ : Type u_3
r✝ r' r : α → α → Prop
wo : IsWellOrder α r
x : α
h : ∃ y, r x y
y : α
⊢ r y x ∨ y = x → r y (WellFounded.succ (_ : WellFounded r) x)

Next tactic:
rintro (hy | rfl)
protected theorem lt_succ_iff {r : α → α → Prop} [wo : IsWellOrder α r] {x : α} (h : ∃ y, r x y)
    (y : α) : r y (wo.wf.succ x) ↔ r y x ∨ y = x := by
  constructor
  · intro h'
    have : ¬r x y := by
      intro hy
      rw [WellFounded.succ, dif_pos] at h'
      exact wo.wf.not_lt_min _ h hy h'
    rcases trichotomous_of r x y with (hy | hy | hy)
    exfalso
    exact this hy
    right
    exact hy.symm
    left
    exact hy
  rintro (hy | rfl); 

Proof state:
case mpr.inl
α : Type u_1
β : Type u_2
γ : Type u_3
r✝ r' r : α → α → Prop
wo : IsWellOrder α r
x : α
h : ∃ y, r x y
y : α
hy : r y x
⊢ r y (WellFounded.succ (_ : WellFounded r) x)
case mpr.inr
α : Type u_1
β : Type u_2
γ : Type u_3
r✝ r' r : α → α → Prop
wo : IsWellOrder α r
y : α
h : ∃ y_1, r y y_1
⊢ r y (WellFounded.succ (_ : WellFounded r) y)

Next tactic:
exact _root_.trans hy (wo.wf.lt_succ h)
protected theorem lt_succ_iff {r : α → α → Prop} [wo : IsWellOrder α r] {x : α} (h : ∃ y, r x y)
    (y : α) : r y (wo.wf.succ x) ↔ r y x ∨ y = x := by
  constructor
  · intro h'
    have : ¬r x y := by
      intro hy
      rw [WellFounded.succ, dif_pos] at h'
      exact wo.wf.not_lt_min _ h hy h'
    rcases trichotomous_of r x y with (hy | hy | hy)
    exfalso
    exact this hy
    right
    exact hy.symm
    left
    exact hy
  rintro (hy | rfl); exact _root_.trans hy (wo.wf.lt_succ h); 

Proof state:
case mpr.inr
α : Type u_1
β : Type u_2
γ : Type u_3
r✝ r' r : α → α → Prop
wo : IsWellOrder α r
y : α
h : ∃ y_1, r y y_1
⊢ r y (WellFounded.succ (_ : WellFounded r) y)

Next tactic:
exact wo.wf.lt_succ h
private theorem eq_strictMono_iff_eq_range_aux {f g : β → γ} (hf : StrictMono f)
    (hg : StrictMono g) (hfg : Set.range f = Set.range g) {b : β} (H : ∀ a < b, f a = g a) :
    f b ≤ g b := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
b : β
H : ∀ a < b, f a = g a
⊢ f b ≤ g b

Next tactic:
obtain ⟨c, hc⟩ : g b ∈ Set.range f := by
    rw [hfg]
    exact Set.mem_range_self b
private theorem eq_strictMono_iff_eq_range_aux {f g : β → γ} (hf : StrictMono f)
    (hg : StrictMono g) (hfg : Set.range f = Set.range g) {b : β} (H : ∀ a < b, f a = g a) :
    f b ≤ g b := by
  obtain ⟨c, hc⟩ : g b ∈ Set.range f := by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
b : β
H : ∀ a < b, f a = g a
⊢ g b ∈ range f

Next tactic:
rw [hfg]
private theorem eq_strictMono_iff_eq_range_aux {f g : β → γ} (hf : StrictMono f)
    (hg : StrictMono g) (hfg : Set.range f = Set.range g) {b : β} (H : ∀ a < b, f a = g a) :
    f b ≤ g b := by
  obtain ⟨c, hc⟩ : g b ∈ Set.range f := by
    rw [hfg]
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
b : β
H : ∀ a < b, f a = g a
⊢ g b ∈ range g

Next tactic:
exact Set.mem_range_self b
private theorem eq_strictMono_iff_eq_range_aux {f g : β → γ} (hf : StrictMono f)
    (hg : StrictMono g) (hfg : Set.range f = Set.range g) {b : β} (H : ∀ a < b, f a = g a) :
    f b ≤ g b := by
  obtain ⟨c, hc⟩ : g b ∈ Set.range f := by
    rw [hfg]
    exact Set.mem_range_self b
  

Proof state:
case intro
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
b : β
H : ∀ a < b, f a = g a
c : β
hc : f c = g b
⊢ f b ≤ g b

Next tactic:
cases' lt_or_le c b with hcb hbc
private theorem eq_strictMono_iff_eq_range_aux {f g : β → γ} (hf : StrictMono f)
    (hg : StrictMono g) (hfg : Set.range f = Set.range g) {b : β} (H : ∀ a < b, f a = g a) :
    f b ≤ g b := by
  obtain ⟨c, hc⟩ : g b ∈ Set.range f := by
    rw [hfg]
    exact Set.mem_range_self b
  cases' lt_or_le c b with hcb hbc
  · 

Proof state:
case intro.inl
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
b : β
H : ∀ a < b, f a = g a
c : β
hc : f c = g b
hcb : c < b
⊢ f b ≤ g b

Next tactic:
rw [H c hcb] at hc
private theorem eq_strictMono_iff_eq_range_aux {f g : β → γ} (hf : StrictMono f)
    (hg : StrictMono g) (hfg : Set.range f = Set.range g) {b : β} (H : ∀ a < b, f a = g a) :
    f b ≤ g b := by
  obtain ⟨c, hc⟩ : g b ∈ Set.range f := by
    rw [hfg]
    exact Set.mem_range_self b
  cases' lt_or_le c b with hcb hbc
  · rw [H c hcb] at hc
    

Proof state:
case intro.inl
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
b : β
H : ∀ a < b, f a = g a
c : β
hc : g c = g b
hcb : c < b
⊢ f b ≤ g b

Next tactic:
rw [hg.injective hc] at hcb
private theorem eq_strictMono_iff_eq_range_aux {f g : β → γ} (hf : StrictMono f)
    (hg : StrictMono g) (hfg : Set.range f = Set.range g) {b : β} (H : ∀ a < b, f a = g a) :
    f b ≤ g b := by
  obtain ⟨c, hc⟩ : g b ∈ Set.range f := by
    rw [hfg]
    exact Set.mem_range_self b
  cases' lt_or_le c b with hcb hbc
  · rw [H c hcb] at hc
    rw [hg.injective hc] at hcb
    

Proof state:
case intro.inl
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
b : β
H : ∀ a < b, f a = g a
c : β
hc : g c = g b
hcb : b < b
⊢ f b ≤ g b

Next tactic:
exact hcb.false.elim
private theorem eq_strictMono_iff_eq_range_aux {f g : β → γ} (hf : StrictMono f)
    (hg : StrictMono g) (hfg : Set.range f = Set.range g) {b : β} (H : ∀ a < b, f a = g a) :
    f b ≤ g b := by
  obtain ⟨c, hc⟩ : g b ∈ Set.range f := by
    rw [hfg]
    exact Set.mem_range_self b
  cases' lt_or_le c b with hcb hbc
  · rw [H c hcb] at hc
    rw [hg.injective hc] at hcb
    exact hcb.false.elim
  · 

Proof state:
case intro.inr
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
b : β
H : ∀ a < b, f a = g a
c : β
hc : f c = g b
hbc : b ≤ c
⊢ f b ≤ g b

Next tactic:
rw [← hc]
private theorem eq_strictMono_iff_eq_range_aux {f g : β → γ} (hf : StrictMono f)
    (hg : StrictMono g) (hfg : Set.range f = Set.range g) {b : β} (H : ∀ a < b, f a = g a) :
    f b ≤ g b := by
  obtain ⟨c, hc⟩ : g b ∈ Set.range f := by
    rw [hfg]
    exact Set.mem_range_self b
  cases' lt_or_le c b with hcb hbc
  · rw [H c hcb] at hc
    rw [hg.injective hc] at hcb
    exact hcb.false.elim
  · rw [← hc]
    

Proof state:
case intro.inr
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
b : β
H : ∀ a < b, f a = g a
c : β
hc : f c = g b
hbc : b ≤ c
⊢ f b ≤ f c

Next tactic:
exact hf.monotone hbc
theorem eq_strictMono_iff_eq_range {f g : β → γ} (hf : StrictMono f) (hg : StrictMono g) :
    Set.range f = Set.range g ↔ f = g :=
  ⟨fun hfg => by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
⊢ f = g

Next tactic:
funext a
theorem eq_strictMono_iff_eq_range {f g : β → γ} (hf : StrictMono f) (hg : StrictMono g) :
    Set.range f = Set.range g ↔ f = g :=
  ⟨fun hfg => by
    funext a
    

Proof state:
case h
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
a : β
⊢ f a = g a

Next tactic:
apply h.induction a
theorem eq_strictMono_iff_eq_range {f g : β → γ} (hf : StrictMono f) (hg : StrictMono g) :
    Set.range f = Set.range g ↔ f = g :=
  ⟨fun hfg => by
    funext a
    apply h.induction a
    

Proof state:
case h
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f g : β → γ
hf : StrictMono f
hg : StrictMono g
hfg : range f = range g
a : β
⊢ ∀ (x : β), (∀ y < x, f y = g y) → f x = g x

Next tactic:
exact fun b H =>
      le_antisymm (eq_strictMono_iff_eq_range_aux hf hg hfg H)
        (eq_strictMono_iff_eq_range_aux hg hf hfg.symm fun a hab => (H a hab).symm)
theorem self_le_of_strictMono {f : β → β} (hf : StrictMono f) : ∀ n, n ≤ f n := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f : β → β
hf : StrictMono f
⊢ ∀ (n : β), n ≤ f n

Next tactic:
by_contra! h₁
theorem self_le_of_strictMono {f : β → β} (hf : StrictMono f) : ∀ n, n ≤ f n := by
  by_contra! h₁
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f : β → β
hf : StrictMono f
h₁ : ∃ n, f n < n
⊢ False

Next tactic:
have h₂ := h.min_mem _ h₁
theorem self_le_of_strictMono {f : β → β} (hf : StrictMono f) : ∀ n, n ≤ f n := by
  by_contra! h₁
  have h₂ := h.min_mem _ h₁
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r r' : α → α → Prop
inst✝¹ : LinearOrder β
h : WellFounded fun x x_1 => x < x_1
inst✝ : PartialOrder γ
f : β → β
hf : StrictMono f
h₁ : ∃ n, f n < n
h₂ : min h (fun x => Preorder.toLT.1 (f x) x) h₁ ∈ fun x => Preorder.toLT.1 (f x) x
⊢ False

Next tactic:
exact h.not_lt_min _ h₁ (hf h₂) h₂
/-- An homeomorphism is proper. -/
@[simp] lemma Homeomorph.isProperMap (e : X ≃ₜ Y) : IsProperMap e := by
  

Proof state:
X : Type u_2
Y : Type u_1
Z : Type ?u.666
W : Type ?u.669
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
e : X ≃ₜ Y
⊢ IsProperMap ⇑e

Next tactic:
rw [isProperMap_iff_clusterPt]
/-- An homeomorphism is proper. -/
@[simp] lemma Homeomorph.isProperMap (e : X ≃ₜ Y) : IsProperMap e := by
  rw [isProperMap_iff_clusterPt]
  

Proof state:
X : Type u_2
Y : Type u_1
Z : Type ?u.666
W : Type ?u.669
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
e : X ≃ₜ Y
⊢ Continuous ⇑e ∧ ∀ ⦃ℱ : Filter X⦄ ⦃y : Y⦄, MapClusterPt y ℱ ⇑e → ∃ x, e x = y ∧ ClusterPt x ℱ

Next tactic:
refine ⟨e.continuous, fun ℱ y ↦ ?_⟩
/-- An homeomorphism is proper. -/
@[simp] lemma Homeomorph.isProperMap (e : X ≃ₜ Y) : IsProperMap e := by
  rw [isProperMap_iff_clusterPt]
  refine ⟨e.continuous, fun ℱ y ↦ ?_⟩
  

Proof state:
X : Type u_2
Y : Type u_1
Z : Type ?u.666
W : Type ?u.669
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
e : X ≃ₜ Y
ℱ : Filter X
y : Y
⊢ MapClusterPt y ℱ ⇑e → ∃ x, e x = y ∧ ClusterPt x ℱ

Next tactic:
simp_rw [MapClusterPt, ClusterPt, ← Filter.push_pull', map_neBot_iff, e.comap_nhds_eq,
    ← e.coe_toEquiv, ← e.eq_symm_apply, exists_eq_left]
/-- An homeomorphism is proper. -/
@[simp] lemma Homeomorph.isProperMap (e : X ≃ₜ Y) : IsProperMap e := by
  rw [isProperMap_iff_clusterPt]
  refine ⟨e.continuous, fun ℱ y ↦ ?_⟩
  simp_rw [MapClusterPt, ClusterPt, ← Filter.push_pull', map_neBot_iff, e.comap_nhds_eq,
    ← e.coe_toEquiv, ← e.eq_symm_apply, exists_eq_left]
  

Proof state:
X : Type u_2
Y : Type u_1
Z : Type ?u.666
W : Type ?u.669
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
e : X ≃ₜ Y
ℱ : Filter X
y : Y
⊢ NeBot (𝓝 ((Homeomorph.symm e) y) ⊓ ℱ) → NeBot (𝓝 (e.symm y) ⊓ ℱ)

Next tactic:
exact id
/-- A proper map is closed. -/
lemma IsProperMap.isClosedMap (h : IsProperMap f) : IsClosedMap f := by
  

Proof state:
X : Type u_1
Y : Type u_2
Z : Type ?u.2756
W : Type ?u.2759
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
h : IsProperMap f
⊢ IsClosedMap f

Next tactic:
rw [isClosedMap_iff_clusterPt]
/-- A proper map is closed. -/
lemma IsProperMap.isClosedMap (h : IsProperMap f) : IsClosedMap f := by
  rw [isClosedMap_iff_clusterPt]
  

Proof state:
X : Type u_1
Y : Type u_2
Z : Type ?u.2756
W : Type ?u.2759
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
h : IsProperMap f
⊢ ∀ (s : Set X) (y : Y), MapClusterPt y (𝓟 s) f → ∃ x, f x = y ∧ ClusterPt x (𝓟 s)

Next tactic:
exact fun s y ↦ h.clusterPt_of_mapClusterPt (ℱ := 𝓟 s) (y := y)
/-- Characterization of proper maps by ultrafilters. -/
lemma isProperMap_iff_ultrafilter : IsProperMap f ↔ Continuous f ∧
    ∀ ⦃𝒰 : Ultrafilter X⦄, ∀ ⦃y : Y⦄, Tendsto f 𝒰 (𝓝 y) → ∃ x, f x = y ∧ 𝒰 ≤ 𝓝 x := by
  -- This is morally trivial since ultrafilters give all the information about cluster points.
  

Proof state:
X : Type u_1
Y : Type u_2
Z : Type ?u.3121
W : Type ?u.3124
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
⊢ IsProperMap f ↔ Continuous f ∧ ∀ ⦃𝒰 : Ultrafilter X⦄ ⦃y : Y⦄, Tendsto f (↑𝒰) (𝓝 y) → ∃ x, f x = y ∧ ↑𝒰 ≤ 𝓝 x

Next tactic:
rw [isProperMap_iff_clusterPt]
/-- Characterization of proper maps by ultrafilters. -/
lemma isProperMap_iff_ultrafilter : IsProperMap f ↔ Continuous f ∧
    ∀ ⦃𝒰 : Ultrafilter X⦄, ∀ ⦃y : Y⦄, Tendsto f 𝒰 (𝓝 y) → ∃ x, f x = y ∧ 𝒰 ≤ 𝓝 x := by
  -- This is morally trivial since ultrafilters give all the information about cluster points.
  rw [isProperMap_iff_clusterPt]
  

Proof state:
X : Type u_1
Y : Type u_2
Z : Type ?u.3121
W : Type ?u.3124
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
⊢ (Continuous f ∧ ∀ ⦃ℱ : Filter X⦄ ⦃y : Y⦄, MapClusterPt y ℱ f → ∃ x, f x = y ∧ ClusterPt x ℱ) ↔
    Continuous f ∧ ∀ ⦃𝒰 : Ultrafilter X⦄ ⦃y : Y⦄, Tendsto f (↑𝒰) (𝓝 y) → ∃ x, f x = y ∧ ↑𝒰 ≤ 𝓝 x

Next tactic:
refine and_congr_right (fun _ ↦ ?_)
/-- Characterization of proper maps by ultrafilters. -/
lemma isProperMap_iff_ultrafilter : IsProperMap f ↔ Continuous f ∧
    ∀ ⦃𝒰 : Ultrafilter X⦄, ∀ ⦃y : Y⦄, Tendsto f 𝒰 (𝓝 y) → ∃ x, f x = y ∧ 𝒰 ≤ 𝓝 x := by
  -- This is morally trivial since ultrafilters give all the information about cluster points.
  rw [isProperMap_iff_clusterPt]
  refine and_congr_right (fun _ ↦ ?_)
  

Proof state:
X : Type u_1
Y : Type u_2
Z : Type ?u.3121
W : Type ?u.3124
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
x✝ : Continuous f
⊢ (∀ ⦃ℱ : Filter X⦄ ⦃y : Y⦄, MapClusterPt y ℱ f → ∃ x, f x = y ∧ ClusterPt x ℱ) ↔
    ∀ ⦃𝒰 : Ultrafilter X⦄ ⦃y : Y⦄, Tendsto f (↑𝒰) (𝓝 y) → ∃ x, f x = y ∧ ↑𝒰 ≤ 𝓝 x

Next tactic:
constructor
/-- Characterization of proper maps by ultrafilters. -/
lemma isProperMap_iff_ultrafilter : IsProperMap f ↔ Continuous f ∧
    ∀ ⦃𝒰 : Ultrafilter X⦄, ∀ ⦃y : Y⦄, Tendsto f 𝒰 (𝓝 y) → ∃ x, f x = y ∧ 𝒰 ≤ 𝓝 x := by
  -- This is morally trivial since ultrafilters give all the information about cluster points.
  rw [isProperMap_iff_clusterPt]
  refine and_congr_right (fun _ ↦ ?_)
  constructor <;> 

Proof state:
case mp
X : Type u_1
Y : Type u_2
Z : Type ?u.3121
W : Type ?u.3124
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
x✝ : Continuous f
⊢ (∀ ⦃ℱ : Filter X⦄ ⦃y : Y⦄, MapClusterPt y ℱ f → ∃ x, f x = y ∧ ClusterPt x ℱ) →
    ∀ ⦃𝒰 : Ultrafilter X⦄ ⦃y : Y⦄, Tendsto f (↑𝒰) (𝓝 y) → ∃ x, f x = y ∧ ↑𝒰 ≤ 𝓝 x

Next tactic:
intro H
/-- Characterization of proper maps by ultrafilters. -/
lemma isProperMap_iff_ultrafilter : IsProperMap f ↔ Continuous f ∧
    ∀ ⦃𝒰 : Ultrafilter X⦄, ∀ ⦃y : Y⦄, Tendsto f 𝒰 (𝓝 y) → ∃ x, f x = y ∧ 𝒰 ≤ 𝓝 x := by
  -- This is morally trivial since ultrafilters give all the information about cluster points.
  rw [isProperMap_iff_clusterPt]
  refine and_congr_right (fun _ ↦ ?_)
  constructor <;> 

Proof state:
case mpr
X : Type u_1
Y : Type u_2
Z : Type ?u.3121
W : Type ?u.3124
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
x✝ : Continuous f
⊢ (∀ ⦃𝒰 : Ultrafilter X⦄ ⦃y : Y⦄, Tendsto f (↑𝒰) (𝓝 y) → ∃ x, f x = y ∧ ↑𝒰 ≤ 𝓝 x) →
    ∀ ⦃ℱ : Filter X⦄ ⦃y : Y⦄, MapClusterPt y ℱ f → ∃ x, f x = y ∧ ClusterPt x ℱ

Next tactic:
intro H
/-- Characterization of proper maps by ultrafilters. -/
lemma isProperMap_iff_ultrafilter : IsProperMap f ↔ Continuous f ∧
    ∀ ⦃𝒰 : Ultrafilter X⦄, ∀ ⦃y : Y⦄, Tendsto f 𝒰 (𝓝 y) → ∃ x, f x = y ∧ 𝒰 ≤ 𝓝 x := by
  -- This is morally trivial since ultrafilters give all the information about cluster points.
  rw [isProperMap_iff_clusterPt]
  refine and_congr_right (fun _ ↦ ?_)
  constructor <;> intro H
  · 

Proof state:
case mp
X : Type u_1
Y : Type u_2
Z : Type ?u.3121
W : Type ?u.3124
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
x✝ : Continuous f
H : ∀ ⦃ℱ : Filter X⦄ ⦃y : Y⦄, MapClusterPt y ℱ f → ∃ x, f x = y ∧ ClusterPt x ℱ
⊢ ∀ ⦃𝒰 : Ultrafilter X⦄ ⦃y : Y⦄, Tendsto f (↑𝒰) (𝓝 y) → ∃ x, f x = y ∧ ↑𝒰 ≤ 𝓝 x

Next tactic:
intro 𝒰 y (hY : (Ultrafilter.map f 𝒰 : Filter Y) ≤ _)
/-- Characterization of proper maps by ultrafilters. -/
lemma isProperMap_iff_ultrafilter : IsProperMap f ↔ Continuous f ∧
    ∀ ⦃𝒰 : Ultrafilter X⦄, ∀ ⦃y : Y⦄, Tendsto f 𝒰 (𝓝 y) → ∃ x, f x = y ∧ 𝒰 ≤ 𝓝 x := by
  -- This is morally trivial since ultrafilters give all the information about cluster points.
  rw [isProperMap_iff_clusterPt]
  refine and_congr_right (fun _ ↦ ?_)
  constructor <;> intro H
  · intro 𝒰 y (hY : (Ultrafilter.map f 𝒰 : Filter Y) ≤ _)
    

Proof state:
case mp
X : Type u_1
Y : Type u_2
Z : Type ?u.3121
W : Type ?u.3124
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
x✝ : Continuous f
H : ∀ ⦃ℱ : Filter X⦄ ⦃y : Y⦄, MapClusterPt y ℱ f → ∃ x, f x = y ∧ ClusterPt x ℱ
𝒰 : Ultrafilter X
y : Y
hY : ↑(Ultrafilter.map f 𝒰) ≤ 𝓝 y
⊢ ∃ x, f x = y ∧ ↑𝒰 ≤ 𝓝 x

Next tactic:
simp_rw [← Ultrafilter.clusterPt_iff] at hY ⊢
/-- Characterization of proper maps by ultrafilters. -/
lemma isProperMap_iff_ultrafilter : IsProperMap f ↔ Continuous f ∧
    ∀ ⦃𝒰 : Ultrafilter X⦄, ∀ ⦃y : Y⦄, Tendsto f 𝒰 (𝓝 y) → ∃ x, f x = y ∧ 𝒰 ≤ 𝓝 x := by
  -- This is morally trivial since ultrafilters give all the information about cluster points.
  rw [isProperMap_iff_clusterPt]
  refine and_congr_right (fun _ ↦ ?_)
  constructor <;> intro H
  · intro 𝒰 y (hY : (Ultrafilter.map f 𝒰 : Filter Y) ≤ _)
    simp_rw [← Ultrafilter.clusterPt_iff] at hY ⊢
    

Proof state:
case mp
X : Type u_1
Y : Type u_2
Z : Type ?u.3121
W : Type ?u.3124
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
x✝ : Continuous f
H : ∀ ⦃ℱ : Filter X⦄ ⦃y : Y⦄, MapClusterPt y ℱ f → ∃ x, f x = y ∧ ClusterPt x ℱ
𝒰 : Ultrafilter X
y : Y
hY : ClusterPt y ↑(Ultrafilter.map f 𝒰)
⊢ ∃ x, f x = y ∧ ClusterPt x ↑𝒰

Next tactic:
exact H hY
/-- Characterization of proper maps by ultrafilters. -/
lemma isProperMap_iff_ultrafilter : IsProperMap f ↔ Continuous f ∧
    ∀ ⦃𝒰 : Ultrafilter X⦄, ∀ ⦃y : Y⦄, Tendsto f 𝒰 (𝓝 y) → ∃ x, f x = y ∧ 𝒰 ≤ 𝓝 x := by
  -- This is morally trivial since ultrafilters give all the information about cluster points.
  rw [isProperMap_iff_clusterPt]
  refine and_congr_right (fun _ ↦ ?_)
  constructor <;> intro H
  · intro 𝒰 y (hY : (Ultrafilter.map f 𝒰 : Filter Y) ≤ _)
    simp_rw [← Ultrafilter.clusterPt_iff] at hY ⊢
    exact H hY
  · 

Proof state:
case mpr
X : Type u_1
Y : Type u_2
Z : Type ?u.3121
W : Type ?u.3124
inst✝³ : TopologicalSpace X
inst✝² : TopologicalSpace Y
inst✝¹ : TopologicalSpace Z
inst✝ : TopologicalSpace W
f : X → Y
x✝ : Continuous f
H : ∀ ⦃𝒰 : Ultrafilter X⦄ ⦃y : Y⦄, Tendsto f (↑𝒰) (𝓝 y) → ∃ x, f x = y ∧ ↑𝒰 ≤ 𝓝 x
⊢ ∀ ⦃ℱ : Filter X⦄ ⦃y : Y⦄, MapClusterPt y ℱ f → ∃ x, f x = y ∧ ClusterPt x ℱ

Next tactic:
simp_rw [MapClusterPt, ClusterPt, ← Filter.push_pull', map_neBot_iff, ← exists_ultrafilter_iff,
      forall_exists_index]