/-
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Mario Carneiro, Yury Kudryashov
-/
import tactic.linarith
import tactic.tfae
import algebra.archimedean
import algebra.group.pi
import algebra.ordered_ring
import order.liminf_limsup
import data.set.intervals.image_preimage
import data.set.intervals.ord_connected
import data.set.intervals.surj_on
import data.set.intervals.pi
import topology.algebra.group
import topology.extend_from_subset
import order.filter.interval

/-!
# Theory of topology on ordered spaces

## Main definitions

The order topology on an ordered space is the topology generated by all open intervals (or
equivalently by those of the form `(-∞, a)` and `(b, +∞)`). We define it as `preorder.topology α`.
However, we do *not* register it as an instance (as many existing ordered types already have
topologies, which would be equal but not definitionally equal to `preorder.topology α`). Instead,
we introduce a class `order_topology α`(which is a `Prop`, also known as a mixin) saying that on
the type `α` having already a topological space structure and a preorder structure, the topological
structure is equal to the order topology.

We also introduce another (mixin) class `order_closed_topology α` saying that the set of points
`(x, y)` with `x ≤ y` is closed in the product space. This is automatically satisfied on a linear
order with the order topology.

We prove many basic properties of such topologies.

## Main statements

This file contains the proofs of the following facts. For exact requirements
(`order_closed_topology` vs `order_topology`, `preorder` vs `partial_order` vs `linear_order` etc)
see their statements.

### Open / closed sets

* `is_open_lt` : if `f` and `g` are continuous functions, then `{x | f x < g x}` is open;
* `is_open_Iio`, `is_open_Ioi`, `is_open_Ioo` : open intervals are open;
* `is_closed_le` : if `f` and `g` are continuous functions, then `{x | f x ≤ g x}` is closed;
* `is_closed_Iic`, `is_closed_Ici`, `is_closed_Icc` : closed intervals are closed;
* `frontier_le_subset_eq`, `frontier_lt_subset_eq` : frontiers of both `{x | f x ≤ g x}`
  and `{x | f x < g x}` are included by `{x | f x = g x}`;
* `exists_Ioc_subset_of_mem_nhds`, `exists_Ico_subset_of_mem_nhds` : if `x < y`, then any
  neighborhood of `x` includes an interval `[x, z)` for some `z ∈ (x, y]`, and any neighborhood
  of `y` includes an interval `(z, y]` for some `z ∈ [x, y)`.

### Convergence and inequalities

* `le_of_tendsto_of_tendsto` : if `f` converges to `a`, `g` converges to `b`, and eventually
  `f x ≤ g x`, then `a ≤ b`
* `le_of_tendsto`, `ge_of_tendsto` : if `f` converges to `a` and eventually `f x ≤ b`
  (resp., `b ≤ f x`), then `a ≤ b` (resp., `b ≤ a); we also provide primed versions
  that assume the inequalities to hold for all `x`.

### Min, max, `Sup` and `Inf`

* `continuous.min`, `continuous.max`: pointwise `min`/`max` of two continuous functions is
  continuous.
* `tendsto.min`, `tendsto.max` : if `f` tends to `a` and `g` tends to `b`, then their pointwise
  `min`/`max` tend to `min a b` and `max a b`, respectively.
* `tendsto_of_tendsto_of_tendsto_of_le_of_le` : theorem known as squeeze theorem,
  sandwich theorem, theorem of Carabinieri, and two policemen (and a drunk) theorem; if `g` and `h`
  both converge to `a`, and eventually `g x ≤ f x ≤ h x`, then `f` converges to `a`.

### Connected sets and Intermediate Value Theorem

* `is_preconnected_I??` : all intervals `I??` are preconnected,
* `is_preconnected.intermediate_value`, `intermediate_value_univ` : Intermediate Value Theorem for
  connected sets and connected spaces, respectively;
* `intermediate_value_Icc`, `intermediate_value_Icc'`: Intermediate Value Theorem for functions
  on closed intervals.

### Miscellaneous facts

* `is_compact.exists_forall_le`, `is_compact.exists_forall_ge` : extreme value theorem, a continuous
  function on a compact set takes its minimum and maximum values.
* `is_closed.Icc_subset_of_forall_mem_nhds_within` : “Continuous induction” principle;
  if `s ∩ [a, b]` is closed, `a ∈ s`, and for each `x ∈ [a, b) ∩ s` some of its right neighborhoods
  is included `s`, then `[a, b] ⊆ s`.
* `is_closed.Icc_subset_of_forall_exists_gt`, `is_closed.mem_of_ge_of_forall_exists_gt` : two
  other versions of the “continuous induction” principle.

## Implementation

We do _not_ register the order topology as an instance on a preorder (or even on a linear order).
Indeed, on many such spaces, a topology has already been constructed in a different way (think
of the discrete spaces `ℕ` or `ℤ`, or `ℝ` that could inherit a topology as the completion of `ℚ`),
and is in general not defeq to the one generated by the intervals. We make it available as a
definition `preorder.topology α` though, that can be registered as an instance when necessary, or
for specific types.
-/

open classical set filter topological_space
open function (curry uncurry)
open_locale topological_space classical filter

universes u v w
variables {α : Type u} {β : Type v} {γ : Type w}

/-- A topology on a set which is both a topological space and a preorder is _order-closed_ if the
set of points `(x, y)` with `x ≤ y` is closed in the product space. We introduce this as a mixin.
This property is satisfied for the order topology on a linear order, but it can be satisfied more
generally, and suffices to derive many interesting properties relating order and topology. -/
class order_closed_topology (α : Type*) [topological_space α] [preorder α] : Prop :=
(is_closed_le' : is_closed {p:α×α | p.1 ≤ p.2})

instance : Π [topological_space α], topological_space (order_dual α) := id

section order_closed_topology

section preorder
variables [topological_space α] [preorder α] [t : order_closed_topology α]
include t

lemma is_closed_le_prod : is_closed {p : α × α | p.1 ≤ p.2} :=
t.is_closed_le'

lemma is_closed_le [topological_space β] {f g : β → α} (hf : continuous f) (hg : continuous g) :
  is_closed {b | f b ≤ g b} :=
continuous_iff_is_closed.mp (hf.prod_mk hg) _ is_closed_le_prod

lemma is_closed_le' (a : α) : is_closed {b | b ≤ a} :=
is_closed_le continuous_id continuous_const

lemma is_closed_Iic {a : α} : is_closed (Iic a) :=
is_closed_le' a

lemma is_closed_ge' (a : α) : is_closed {b | a ≤ b} :=
is_closed_le continuous_const continuous_id

lemma is_closed_Ici {a : α} : is_closed (Ici a) :=
is_closed_ge' a

instance : order_closed_topology (order_dual α) :=
⟨(@order_closed_topology.is_closed_le' α _ _ _).preimage continuous_swap⟩

lemma is_closed_Icc {a b : α} : is_closed (Icc a b) :=
is_closed_inter is_closed_Ici is_closed_Iic

@[simp] lemma closure_Icc (a b : α) : closure (Icc a b) = Icc a b :=
is_closed_Icc.closure_eq

@[simp] lemma closure_Iic (a : α) : closure (Iic a) = Iic a :=
is_closed_Iic.closure_eq

@[simp] lemma closure_Ici (a : α) : closure (Ici a) = Ici a :=
is_closed_Ici.closure_eq

lemma le_of_tendsto_of_tendsto {f g : β → α} {b : filter β} {a₁ a₂ : α} [ne_bot b]
  (hf : tendsto f b (𝓝 a₁)) (hg : tendsto g b (𝓝 a₂)) (h : f ≤ᶠ[b] g) :
  a₁ ≤ a₂ :=
have tendsto (λb, (f b, g b)) b (𝓝 (a₁, a₂)),
  by rw [nhds_prod_eq]; exact hf.prod_mk hg,
show (a₁, a₂) ∈ {p:α×α | p.1 ≤ p.2},
  from t.is_closed_le'.mem_of_tendsto this h

lemma le_of_tendsto_of_tendsto' {f g : β → α} {b : filter β} {a₁ a₂ : α} [ne_bot b]
  (hf : tendsto f b (𝓝 a₁)) (hg : tendsto g b (𝓝 a₂)) (h : ∀ x, f x ≤ g x) :
  a₁ ≤ a₂ :=
le_of_tendsto_of_tendsto hf hg (eventually_of_forall h)

lemma le_of_tendsto {f : β → α} {a b : α} {x : filter β}
  [ne_bot x] (lim : tendsto f x (𝓝 a)) (h : ∀ᶠ c in x, f c ≤ b) : a ≤ b :=
le_of_tendsto_of_tendsto lim tendsto_const_nhds h

lemma le_of_tendsto' {f : β → α} {a b : α} {x : filter β}
  [ne_bot x] (lim : tendsto f x (𝓝 a)) (h : ∀ c, f c ≤ b) : a ≤ b :=
le_of_tendsto lim (eventually_of_forall h)

lemma ge_of_tendsto {f : β → α} {a b : α} {x : filter β} [ne_bot x]
  (lim : tendsto f x (𝓝 a)) (h : ∀ᶠ c in x, b ≤ f c) : b ≤ a :=
le_of_tendsto_of_tendsto tendsto_const_nhds lim h

lemma ge_of_tendsto' {f : β → α} {a b : α} {x : filter β} [ne_bot x]
  (lim : tendsto f x (𝓝 a)) (h : ∀ c, b ≤ f c) : b ≤ a :=
ge_of_tendsto lim (eventually_of_forall h)

@[simp]
lemma closure_le_eq [topological_space β] {f g : β → α} (hf : continuous f) (hg : continuous g) :
  closure {b | f b ≤ g b} = {b | f b ≤ g b} :=
(is_closed_le hf hg).closure_eq

lemma closure_lt_subset_le [topological_space β] {f g : β → α} (hf : continuous f)
  (hg : continuous g) :
  closure {b | f b < g b} ⊆ {b | f b ≤ g b} :=
by { rw [←closure_le_eq hf hg], exact closure_mono (λ b, le_of_lt) }

lemma continuous_within_at.closure_le [topological_space β]
 {f g : β → α} {s : set β} {x : β} (hx : x ∈ closure s)
 (hf : continuous_within_at f s x)
 (hg : continuous_within_at g s x)
 (h : ∀ y ∈ s, f y ≤ g y) : f x ≤ g x :=
show (f x, g x) ∈ {p : α × α | p.1 ≤ p.2},
from order_closed_topology.is_closed_le'.closure_subset ((hf.prod hg).mem_closure hx h)

/-- If `s` is a closed set and two functions `f` and `g` are continuous on `s`,
then the set `{x ∈ s | f x ≤ g x}` is a closed set. -/
lemma is_closed.is_closed_le [topological_space β] {f g : β → α} {s : set β} (hs : is_closed s)
  (hf : continuous_on f s) (hg : continuous_on g s) :
  is_closed {x ∈ s | f x ≤ g x} :=
(hf.prod hg).preimage_closed_of_closed hs order_closed_topology.is_closed_le'

omit t

lemma nhds_within_Ici_ne_bot {a b : α} (H₂ : a ≤ b) :
  ne_bot (𝓝[Ici a] b) :=
nhds_within_ne_bot_of_mem H₂

@[instance] lemma nhds_within_Ici_self_ne_bot (a : α) :
  ne_bot (𝓝[Ici a] a) :=
nhds_within_Ici_ne_bot (le_refl a)

lemma nhds_within_Iic_ne_bot {a b : α} (H : a ≤ b) :
  ne_bot (𝓝[Iic b] a) :=
nhds_within_ne_bot_of_mem H

@[instance] lemma nhds_within_Iic_self_ne_bot (a : α) :
  ne_bot (𝓝[Iic a] a) :=
nhds_within_Iic_ne_bot (le_refl a)

end preorder

section partial_order
variables [topological_space α] [partial_order α] [t : order_closed_topology α]
include t

private lemma is_closed_eq_aux : is_closed {p : α × α | p.1 = p.2} :=
by simp only [le_antisymm_iff];
   exact is_closed_inter t.is_closed_le' (is_closed_le continuous_snd continuous_fst)

@[priority 90] -- see Note [lower instance priority]
instance order_closed_topology.to_t2_space : t2_space α :=
{ t2 :=
  have is_open {p : α × α | p.1 ≠ p.2} := is_closed_eq_aux.is_open_compl,
  assume a b h,
  let ⟨u, v, hu, hv, ha, hb, h⟩ := is_open_prod_iff.mp this a b h in
  ⟨u, v, hu, hv, ha, hb,
    set.eq_empty_iff_forall_not_mem.2 $ assume a ⟨h₁, h₂⟩,
    have a ≠ a, from @h (a, a) ⟨h₁, h₂⟩,
    this rfl⟩ }

end partial_order

section linear_order
variables [topological_space α] [linear_order α] [order_closed_topology α]

lemma is_open_lt_prod : is_open {p : α × α | p.1 < p.2} :=
by { simp_rw [← is_closed_compl_iff, compl_set_of, not_lt],
     exact is_closed_le continuous_snd continuous_fst }

lemma is_open_lt [topological_space β] {f g : β → α} (hf : continuous f) (hg : continuous g) :
  is_open {b | f b < g b} :=
by simp [lt_iff_not_ge, -not_le]; exact (is_closed_le hg hf).is_open_compl

variables {a b : α}

lemma is_open_Iio : is_open (Iio a) :=
is_open_lt continuous_id continuous_const

lemma is_open_Ioi : is_open (Ioi a) :=
is_open_lt continuous_const continuous_id

lemma is_open_Ioo : is_open (Ioo a b) :=
is_open_inter is_open_Ioi is_open_Iio

@[simp] lemma interior_Ioi : interior (Ioi a) = Ioi a :=
is_open_Ioi.interior_eq

@[simp] lemma interior_Iio : interior (Iio a) = Iio a :=
is_open_Iio.interior_eq

@[simp] lemma interior_Ioo : interior (Ioo a b) = Ioo a b :=
is_open_Ioo.interior_eq

lemma eventually_le_of_tendsto_lt {l : filter γ} {f : γ → α} {u v : α} (hv : v < u)
  (h : tendsto f l (𝓝 v)) : ∀ᶠ a in l, f a ≤ u :=
eventually.mono (tendsto_nhds.1 h (< u) is_open_Iio hv) (λ v, le_of_lt)

lemma eventually_ge_of_tendsto_gt {l : filter γ} {f : γ → α} {u v : α} (hv : u < v)
  (h : tendsto f l (𝓝 v)) : ∀ᶠ a in l, u ≤ f a :=
eventually.mono (tendsto_nhds.1 h (> u) is_open_Ioi hv) (λ v, le_of_lt)

variables [topological_space γ]

/-- Intermediate value theorem for two functions: if `f` and `g` are two continuous functions
on a preconnected space and `f a ≤ g a` and `g b ≤ f b`, then for some `x` we have `f x = g x`. -/
lemma intermediate_value_univ₂ [preconnected_space γ] {a b : γ} {f g : γ → α} (hf : continuous f)
  (hg : continuous g) (ha : f a ≤ g a) (hb : g b ≤ f b) :
  ∃ x, f x = g x :=
begin
  obtain ⟨x, h, hfg, hgf⟩ : (univ ∩ {x | f x ≤ g x ∧ g x ≤ f x}).nonempty,
    from is_preconnected_closed_iff.1 preconnected_space.is_preconnected_univ _ _
      (is_closed_le hf hg) (is_closed_le hg hf) (λ x hx, le_total _ _) ⟨a, trivial, ha⟩
      ⟨b, trivial, hb⟩,
  exact ⟨x, le_antisymm hfg hgf⟩
end

lemma intermediate_value_univ₂_eventually₁ [preconnected_space γ] {a : γ} {l : filter γ} [ne_bot l]
  {f g : γ → α} (hf : continuous f) (hg : continuous g) (ha : f a ≤ g a) (he : g ≤ᶠ[l] f) :
  ∃ x, f x = g x :=
let ⟨c, hc⟩ := he.frequently.exists in intermediate_value_univ₂ hf hg ha hc

lemma intermediate_value_univ₂_eventually₂ [preconnected_space γ] {l₁ l₂ : filter γ}
  [ne_bot l₁] [ne_bot l₂] {f g : γ → α} (hf : continuous f) (hg : continuous g)
  (he₁ : f ≤ᶠ[l₁] g ) (he₂ : g ≤ᶠ[l₂] f) :
  ∃ x, f x = g x :=
let ⟨c₁, hc₁⟩ := he₁.frequently.exists, ⟨c₂, hc₂⟩ := he₂.frequently.exists in
intermediate_value_univ₂ hf hg hc₁ hc₂

/-- Intermediate value theorem for two functions: if `f` and `g` are two functions continuous
on a preconnected set `s` and for some `a b ∈ s` we have `f a ≤ g a` and `g b ≤ f b`,
then for some `x ∈ s` we have `f x = g x`. -/
lemma is_preconnected.intermediate_value₂ {s : set γ} (hs : is_preconnected s)
  {a b : γ} (ha : a ∈ s) (hb : b ∈ s) {f g : γ → α}
  (hf : continuous_on f s) (hg : continuous_on g s) (ha' : f a ≤ g a) (hb' : g b ≤ f b) :
  ∃ x ∈ s, f x = g x :=
let ⟨x, hx⟩ := @intermediate_value_univ₂ α s _ _ _ _ (subtype.preconnected_space hs) ⟨a, ha⟩ ⟨b, hb⟩
  _ _ (continuous_on_iff_continuous_restrict.1 hf) (continuous_on_iff_continuous_restrict.1 hg)
  ha' hb'
in ⟨x, x.2, hx⟩

lemma is_preconnected.intermediate_value₂_eventually₁ {s : set γ} (hs : is_preconnected s)
  {a : γ} {l : filter γ} (ha : a ∈ s) [ne_bot l] (hl : l ≤ 𝓟 s) {f g : γ → α}
  (hf : continuous_on f s) (hg : continuous_on g s) (ha' : f a ≤ g a) (he : g ≤ᶠ[l] f) :
  ∃ x ∈ s, f x = g x :=
begin
  rw continuous_on_iff_continuous_restrict at hf hg,
  obtain ⟨b, h⟩ := @intermediate_value_univ₂_eventually₁ _ _ _ _ _ _ (subtype.preconnected_space hs)
    ⟨a, ha⟩ _ (comap_coe_ne_bot_of_le_principal hl) _ _ hf hg ha' (eventually_comap' he),
  exact ⟨b, b.prop, h⟩,
end

lemma is_preconnected.intermediate_value₂_eventually₂ {s : set γ} (hs : is_preconnected s)
  {l₁ l₂ : filter γ} [ne_bot l₁] [ne_bot l₂] (hl₁ : l₁ ≤ 𝓟 s) (hl₂ : l₂ ≤ 𝓟 s) {f g : γ → α}
  (hf : continuous_on f s) (hg : continuous_on g s) (he₁ : f ≤ᶠ[l₁] g) (he₂ : g ≤ᶠ[l₂] f) :
  ∃ x ∈ s, f x = g x :=
begin
  rw continuous_on_iff_continuous_restrict at hf hg,
  obtain ⟨b, h⟩ := @intermediate_value_univ₂_eventually₂ _ _ _ _ _ _ (subtype.preconnected_space hs)
    _ _ (comap_coe_ne_bot_of_le_principal hl₁) (comap_coe_ne_bot_of_le_principal hl₂)
    _ _ hf hg (eventually_comap' he₁) (eventually_comap' he₂),
  exact ⟨b, b.prop, h⟩,
end

/-- Intermediate Value Theorem for continuous functions on connected sets. -/
lemma is_preconnected.intermediate_value {s : set γ} (hs : is_preconnected s)
  {a b : γ} (ha : a ∈ s) (hb : b ∈ s) {f : γ → α} (hf : continuous_on f s) :
  Icc (f a) (f b) ⊆ f '' s :=
λ x hx, mem_image_iff_bex.2 $ hs.intermediate_value₂ ha hb hf continuous_on_const hx.1 hx.2

lemma is_preconnected.intermediate_value_Ico {s : set γ} (hs : is_preconnected s)
  {a : γ} {l : filter γ} (ha : a ∈ s) [ne_bot l] (hl : l ≤ 𝓟 s) {f : γ → α}
  (hf : continuous_on f s) {v : α} (ht : tendsto f l (𝓝 v)) :
  Ico (f a) v ⊆ f '' s :=
λ y h, bex_def.1 $ hs.intermediate_value₂_eventually₁ ha hl
  hf continuous_on_const h.1 (eventually_ge_of_tendsto_gt h.2 ht)

lemma is_preconnected.intermediate_value_Ioc {s : set γ} (hs : is_preconnected s)
  {a : γ} {l : filter γ} (ha : a ∈ s) [ne_bot l] (hl : l ≤ 𝓟 s) {f : γ → α}
  (hf : continuous_on f s) {v : α} (ht : tendsto f l (𝓝 v)) :
  Ioc v (f a) ⊆ f '' s :=
λ y h, bex_def.1 $ bex.imp_right (λ x _, eq.symm) $ hs.intermediate_value₂_eventually₁ ha hl
  continuous_on_const hf h.2 (eventually_le_of_tendsto_lt h.1 ht)

lemma is_preconnected.intermediate_value_Ioo {s : set γ} (hs : is_preconnected s)
  {l₁ l₂ : filter γ} [ne_bot l₁] [ne_bot l₂] (hl₁ : l₁ ≤ 𝓟 s) (hl₂ : l₂ ≤ 𝓟 s) {f : γ → α}
  (hf : continuous_on f s) {v₁ v₂ : α} (ht₁ : tendsto f l₁ (𝓝 v₁)) (ht₂ : tendsto f l₂ (𝓝 v₂)) :
  Ioo v₁ v₂ ⊆ f '' s :=
λ y h, bex_def.1 $ hs.intermediate_value₂_eventually₂ hl₁ hl₂
  hf continuous_on_const (eventually_le_of_tendsto_lt h.1 ht₁) (eventually_ge_of_tendsto_gt h.2 ht₂)

lemma is_preconnected.intermediate_value_Ici {s : set γ} (hs : is_preconnected s)
  {a : γ} {l : filter γ} (ha : a ∈ s) [ne_bot l] (hl : l ≤ 𝓟 s) {f : γ → α}
  (hf : continuous_on f s) (ht : tendsto f l at_top) :
  Ici (f a) ⊆ f '' s :=
λ y h, bex_def.1 $ hs.intermediate_value₂_eventually₁ ha hl
  hf continuous_on_const h (tendsto_at_top.1 ht y)

lemma is_preconnected.intermediate_value_Iic {s : set γ} (hs : is_preconnected s)
  {a : γ} {l : filter γ} (ha : a ∈ s) [ne_bot l] (hl : l ≤ 𝓟 s) {f : γ → α}
  (hf : continuous_on f s) (ht : tendsto f l at_bot) :
  Iic (f a) ⊆ f '' s :=
λ y h, bex_def.1 $ bex.imp_right (λ x _, eq.symm) $ hs.intermediate_value₂_eventually₁ ha hl
  continuous_on_const hf h (tendsto_at_bot.1 ht y)

lemma is_preconnected.intermediate_value_Ioi {s : set γ} (hs : is_preconnected s)
  {l₁ l₂ : filter γ} [ne_bot l₁] [ne_bot l₂] (hl₁ : l₁ ≤ 𝓟 s) (hl₂ : l₂ ≤ 𝓟 s) {f : γ → α}
  (hf : continuous_on f s) {v : α} (ht₁ : tendsto f l₁ (𝓝 v)) (ht₂ : tendsto f l₂ at_top) :
  Ioi v ⊆ f '' s :=
λ y h, bex_def.1 $ hs.intermediate_value₂_eventually₂ hl₁ hl₂
  hf continuous_on_const (eventually_le_of_tendsto_lt h ht₁) (tendsto_at_top.1 ht₂ y)

lemma is_preconnected.intermediate_value_Iio {s : set γ} (hs : is_preconnected s)
  {l₁ l₂ : filter γ} [ne_bot l₁] [ne_bot l₂] (hl₁ : l₁ ≤ 𝓟 s) (hl₂ : l₂ ≤ 𝓟 s) {f : γ → α}
  (hf : continuous_on f s) {v : α} (ht₁ : tendsto f l₁ at_bot) (ht₂ : tendsto f l₂ (𝓝 v)) :
  Iio v ⊆ f '' s :=
λ y h, bex_def.1 $ hs.intermediate_value₂_eventually₂ hl₁ hl₂
  hf continuous_on_const (tendsto_at_bot.1 ht₁ y) (eventually_ge_of_tendsto_gt h ht₂)

lemma is_preconnected.intermediate_value_Iii {s : set γ} (hs : is_preconnected s)
  {l₁ l₂ : filter γ} [ne_bot l₁] [ne_bot l₂] (hl₁ : l₁ ≤ 𝓟 s) (hl₂ : l₂ ≤ 𝓟 s) {f : γ → α}
  (hf : continuous_on f s) (ht₁ : tendsto f l₁ at_bot) (ht₂ : tendsto f l₂ at_top) :
  univ ⊆ f '' s :=
λ y h, bex_def.1 $ hs.intermediate_value₂_eventually₂ hl₁ hl₂
  hf continuous_on_const (tendsto_at_bot.1 ht₁ y) (tendsto_at_top.1 ht₂ y)

/-- Intermediate Value Theorem for continuous functions on connected spaces. -/
lemma intermediate_value_univ [preconnected_space γ] (a b : γ) {f : γ → α} (hf : continuous f) :
  Icc (f a) (f b) ⊆ range f :=
λ x hx, intermediate_value_univ₂ hf continuous_const hx.1 hx.2

/-- Intermediate Value Theorem for continuous functions on connected spaces. -/
lemma mem_range_of_exists_le_of_exists_ge [preconnected_space γ] {c : α} {f : γ → α}
  (hf : continuous f) (h₁ : ∃ a, f a ≤ c) (h₂ : ∃ b, c ≤ f b) :
  c ∈ range f :=
let ⟨a, ha⟩ := h₁, ⟨b, hb⟩ := h₂ in intermediate_value_univ a b hf ⟨ha, hb⟩

/-- If a preconnected set contains endpoints of an interval, then it includes the whole interval. -/
lemma is_preconnected.Icc_subset {s : set α} (hs : is_preconnected s)
  {a b : α} (ha : a ∈ s) (hb : b ∈ s) :
  Icc a b ⊆ s :=
by simpa only [image_id] using hs.intermediate_value ha hb continuous_on_id

/-- If a preconnected set contains endpoints of an interval, then it includes the whole interval. -/
lemma is_connected.Icc_subset {s : set α} (hs : is_connected s)
  {a b : α} (ha : a ∈ s) (hb : b ∈ s) :
  Icc a b ⊆ s :=
hs.2.Icc_subset ha hb

/-- If preconnected set in a linear order space is unbounded below and above, then it is the whole
space. -/
lemma is_preconnected.eq_univ_of_unbounded {s : set α} (hs : is_preconnected s) (hb : ¬bdd_below s)
  (ha : ¬bdd_above s) :
  s = univ :=
begin
  refine eq_univ_of_forall (λ x, _),
  obtain ⟨y, ys, hy⟩ : ∃ y ∈ s, y < x := not_bdd_below_iff.1 hb x,
  obtain ⟨z, zs, hz⟩ : ∃ z ∈ s, x < z := not_bdd_above_iff.1 ha x,
  exact hs.Icc_subset ys zs ⟨le_of_lt hy, le_of_lt hz⟩
end

/-!
### Neighborhoods to the left and to the right on an `order_closed_topology`

Limits to the left and to the right of real functions are defined in terms of neighborhoods to
the left and to the right, either open or closed, i.e., members of `𝓝[Ioi a] a` and
`𝓝[Ici a] a` on the right, and similarly on the left. Here we simply prove that all
right-neighborhoods of a point are equal, and we'll prove later other useful characterizations which
require the stronger hypothesis `order_topology α` -/

/-!
#### Right neighborhoods, point excluded
-/

lemma Ioo_mem_nhds_within_Ioi {a b c : α} (H : b ∈ Ico a c) :
  Ioo a c ∈ 𝓝[Ioi b] b :=
mem_nhds_within.2 ⟨Iio c, is_open_Iio, H.2,
  by rw [inter_comm, Ioi_inter_Iio]; exact Ioo_subset_Ioo_left H.1⟩

lemma Ioc_mem_nhds_within_Ioi {a b c : α} (H : b ∈ Ico a c) :
  Ioc a c ∈ 𝓝[Ioi b] b :=
mem_sets_of_superset (Ioo_mem_nhds_within_Ioi H) Ioo_subset_Ioc_self

lemma Ico_mem_nhds_within_Ioi {a b c : α} (H : b ∈ Ico a c) :
  Ico a c ∈ 𝓝[Ioi b] b :=
mem_sets_of_superset (Ioo_mem_nhds_within_Ioi H) Ioo_subset_Ico_self

lemma Icc_mem_nhds_within_Ioi {a b c : α} (H : b ∈ Ico a c) :
  Icc a c ∈ 𝓝[Ioi b] b :=
mem_sets_of_superset (Ioo_mem_nhds_within_Ioi H) Ioo_subset_Icc_self

@[simp] lemma nhds_within_Ioc_eq_nhds_within_Ioi {a b : α} (h : a < b) :
  𝓝[Ioc a b] a = 𝓝[Ioi a] a :=
le_antisymm (nhds_within_mono _ Ioc_subset_Ioi_self) $
  nhds_within_le_of_mem $ Ioc_mem_nhds_within_Ioi $ left_mem_Ico.2 h

@[simp] lemma nhds_within_Ioo_eq_nhds_within_Ioi {a b : α} (h : a < b) :
  𝓝[Ioo a b] a = 𝓝[Ioi a] a :=
le_antisymm (nhds_within_mono _ Ioo_subset_Ioi_self) $
  nhds_within_le_of_mem $ Ioo_mem_nhds_within_Ioi $ left_mem_Ico.2 h

@[simp]
lemma continuous_within_at_Ioc_iff_Ioi [topological_space β] {a b : α} {f : α → β} (h : a < b) :
  continuous_within_at f (Ioc a b) a ↔ continuous_within_at f (Ioi a) a :=
by simp only [continuous_within_at, nhds_within_Ioc_eq_nhds_within_Ioi h]

@[simp]
lemma continuous_within_at_Ioo_iff_Ioi [topological_space β] {a b : α} {f : α → β} (h : a < b) :
  continuous_within_at f (Ioo a b) a ↔ continuous_within_at f (Ioi a) a :=
by simp only [continuous_within_at, nhds_within_Ioo_eq_nhds_within_Ioi h]

/-!
#### Left neighborhoods, point excluded
-/

lemma Ioo_mem_nhds_within_Iio {a b c : α} (H : b ∈ Ioc a c) :
  Ioo a c ∈ 𝓝[Iio b] b :=
by simpa only [dual_Ioo] using @Ioo_mem_nhds_within_Ioi (order_dual α) _ _ _ _ _ _ ⟨H.2, H.1⟩

lemma Ico_mem_nhds_within_Iio {a b c : α} (H : b ∈ Ioc a c) :
  Ico a c ∈ 𝓝[Iio b] b :=
mem_sets_of_superset (Ioo_mem_nhds_within_Iio H) Ioo_subset_Ico_self

lemma Ioc_mem_nhds_within_Iio {a b c : α} (H : b ∈ Ioc a c) :
  Ioc a c ∈ 𝓝[Iio b] b :=
mem_sets_of_superset (Ioo_mem_nhds_within_Iio H) Ioo_subset_Ioc_self

lemma Icc_mem_nhds_within_Iio {a b c : α} (H : b ∈ Ioc a c) :
  Icc a c ∈ 𝓝[Iio b] b :=
mem_sets_of_superset (Ioo_mem_nhds_within_Iio H) Ioo_subset_Icc_self

@[simp] lemma nhds_within_Ico_eq_nhds_within_Iio {a b : α} (h : a < b) :
  𝓝[Ico a b] b = 𝓝[Iio b] b :=
by simpa only [dual_Ioc] using @nhds_within_Ioc_eq_nhds_within_Ioi (order_dual α) _ _ _ _ _ h

@[simp] lemma nhds_within_Ioo_eq_nhds_within_Iio {a b : α} (h : a < b) :
  𝓝[Ioo a b] b = 𝓝[Iio b] b :=
by simpa only [dual_Ioo] using @nhds_within_Ioo_eq_nhds_within_Ioi (order_dual α) _ _ _ _ _ h

@[simp] lemma continuous_within_at_Ico_iff_Iio {a b : α} {f : α → γ} (h : a < b) :
  continuous_within_at f (Ico a b) b ↔ continuous_within_at f (Iio b) b :=
by simp only [continuous_within_at, nhds_within_Ico_eq_nhds_within_Iio h]

@[simp] lemma continuous_within_at_Ioo_iff_Iio {a b : α} {f : α → γ} (h : a < b) :
  continuous_within_at f (Ioo a b) b ↔ continuous_within_at f (Iio b) b :=
by simp only [continuous_within_at, nhds_within_Ioo_eq_nhds_within_Iio h]

/-!
#### Right neighborhoods, point included
-/

lemma Ioo_mem_nhds_within_Ici {a b c : α} (H : b ∈ Ioo a c) :
  Ioo a c ∈ 𝓝[Ici b] b :=
mem_nhds_within_of_mem_nhds $ mem_nhds_sets is_open_Ioo H

lemma Ioc_mem_nhds_within_Ici {a b c : α} (H : b ∈ Ioo a c) :
  Ioc a c ∈ 𝓝[Ici b] b :=
mem_sets_of_superset (Ioo_mem_nhds_within_Ici H) Ioo_subset_Ioc_self

lemma Ico_mem_nhds_within_Ici {a b c : α} (H : b ∈ Ico a c) :
  Ico a c ∈ 𝓝[Ici b] b :=
mem_nhds_within.2 ⟨Iio c, is_open_Iio, H.2,
  by simp only [inter_comm, Ici_inter_Iio, Ico_subset_Ico_left H.1]⟩

lemma Icc_mem_nhds_within_Ici {a b c : α} (H : b ∈ Ico a c) :
  Icc a c ∈ 𝓝[Ici b] b :=
mem_sets_of_superset (Ico_mem_nhds_within_Ici H) Ico_subset_Icc_self

@[simp] lemma nhds_within_Icc_eq_nhds_within_Ici {a b : α} (h : a < b) :
  𝓝[Icc a b] a = 𝓝[Ici a] a :=
le_antisymm (nhds_within_mono _ Icc_subset_Ici_self) $
  nhds_within_le_of_mem $ Icc_mem_nhds_within_Ici $ left_mem_Ico.2 h

@[simp] lemma nhds_within_Ico_eq_nhds_within_Ici {a b : α} (h : a < b) :
  𝓝[Ico a b] a = 𝓝[Ici a] a :=
le_antisymm (nhds_within_mono _ (λ x, and.left)) $
  nhds_within_le_of_mem $ Ico_mem_nhds_within_Ici $ left_mem_Ico.2 h

@[simp]
lemma continuous_within_at_Icc_iff_Ici [topological_space β] {a b : α} {f : α → β} (h : a < b) :
  continuous_within_at f (Icc a b) a ↔ continuous_within_at f (Ici a) a :=
by simp only [continuous_within_at, nhds_within_Icc_eq_nhds_within_Ici h]

@[simp]
lemma continuous_within_at_Ico_iff_Ici [topological_space β] {a b : α} {f : α → β} (h : a < b) :
  continuous_within_at f (Ico a b) a ↔ continuous_within_at f (Ici a) a :=
by simp only [continuous_within_at, nhds_within_Ico_eq_nhds_within_Ici h]

/-!
#### Left neighborhoods, point included
-/

lemma Ioo_mem_nhds_within_Iic {a b c : α} (H : b ∈ Ioo a c) :
  Ioo a c ∈ 𝓝[Iic b] b :=
mem_nhds_within_of_mem_nhds $ mem_nhds_sets is_open_Ioo H

lemma Ico_mem_nhds_within_Iic {a b c : α} (H : b ∈ Ioo a c) :
  Ico a c ∈ 𝓝[Iic b] b :=
mem_sets_of_superset (Ioo_mem_nhds_within_Iic H) Ioo_subset_Ico_self

lemma Ioc_mem_nhds_within_Iic {a b c : α} (H : b ∈ Ioc a c) :
  Ioc a c ∈ 𝓝[Iic b] b :=
by simpa only [dual_Ico] using @Ico_mem_nhds_within_Ici (order_dual α) _ _ _ _ _ _ ⟨H.2, H.1⟩

lemma Icc_mem_nhds_within_Iic {a b c : α} (H : b ∈ Ioc a c) :
  Icc a c ∈ 𝓝[Iic b] b :=
mem_sets_of_superset (Ioc_mem_nhds_within_Iic H) Ioc_subset_Icc_self

@[simp] lemma nhds_within_Icc_eq_nhds_within_Iic {a b : α} (h : a < b) :
  𝓝[Icc a b] b = 𝓝[Iic b] b :=
by simpa only [dual_Icc] using @nhds_within_Icc_eq_nhds_within_Ici (order_dual α) _ _ _ _ _ h

@[simp] lemma nhds_within_Ioc_eq_nhds_within_Iic {a b : α} (h : a < b) :
  𝓝[Ioc a b] b = 𝓝[Iic b] b :=
by simpa only [dual_Ico] using @nhds_within_Ico_eq_nhds_within_Ici (order_dual α) _ _ _ _ _ h

@[simp]
lemma continuous_within_at_Icc_iff_Iic [topological_space β] {a b : α} {f : α → β} (h : a < b) :
  continuous_within_at f (Icc a b) b ↔ continuous_within_at f (Iic b) b :=
by simp only [continuous_within_at, nhds_within_Icc_eq_nhds_within_Iic h]

@[simp]
lemma continuous_within_at_Ioc_iff_Iic [topological_space β] {a b : α} {f : α → β} (h : a < b) :
  continuous_within_at f (Ioc a b) b ↔ continuous_within_at f (Iic b) b :=
by simp only [continuous_within_at, nhds_within_Ioc_eq_nhds_within_Iic h]

end linear_order

section linear_order
variables [topological_space α] [linear_order α] [order_closed_topology α] {f g : β → α}

section
variables [topological_space β]

lemma frontier_le_subset_eq (hf : continuous f) (hg : continuous g) :
  frontier {b | f b ≤ g b} ⊆ {b | f b = g b} :=
begin
  rw [frontier_eq_closure_inter_closure, closure_le_eq hf hg],
  rintros b ⟨hb₁, hb₂⟩,
  refine le_antisymm hb₁ (closure_lt_subset_le hg hf _),
  convert hb₂ using 2, simp only [not_le.symm], refl
end

lemma frontier_Iic_subset (a : α) : frontier (Iic a) ⊆ {a} :=
frontier_le_subset_eq (@continuous_id α _) continuous_const

lemma frontier_Ici_subset (a : α) : frontier (Ici a) ⊆ {a} :=
@frontier_Iic_subset (order_dual α) _ _ _ _

lemma frontier_lt_subset_eq (hf : continuous f) (hg : continuous g) :
  frontier {b | f b < g b} ⊆ {b | f b = g b} :=
by rw ← frontier_compl;
   convert frontier_le_subset_eq hg hf; simp [ext_iff, eq_comm]

lemma continuous_if_le [topological_space γ] [Π x, decidable (f x ≤ g x)]
  {f' g' : β → γ} (hf : continuous f) (hg : continuous g)
  (hf' : continuous_on f' {x | f x ≤ g x}) (hg' : continuous_on g' {x | g x ≤ f x})
  (hfg : ∀ x, f x = g x → f' x = g' x) :
  continuous (λ x, if f x ≤ g x then f' x else g' x) :=
begin
  refine continuous_if (λ a ha, hfg _ (frontier_le_subset_eq hf hg ha)) _ (hg'.mono _),
  { rwa [(is_closed_le hf hg).closure_eq] },
  { simp only [not_le], exact closure_lt_subset_le hg hf }
end

lemma continuous.if_le [topological_space γ] [Π x, decidable (f x ≤ g x)] {f' g' : β → γ}
  (hf' : continuous f') (hg' : continuous g') (hf : continuous f) (hg : continuous g)
  (hfg : ∀ x, f x = g x → f' x = g' x) :
  continuous (λ x, if f x ≤ g x then f' x else g' x) :=
continuous_if_le hf hg hf'.continuous_on hg'.continuous_on hfg

@[continuity] lemma continuous.min (hf : continuous f) (hg : continuous g) :
  continuous (λb, min (f b) (g b)) :=
hf.if_le hg hf hg (λ x, id)

@[continuity] lemma continuous.max (hf : continuous f) (hg : continuous g) :
  continuous (λb, max (f b) (g b)) :=
@continuous.min (order_dual α) _ _ _ _ _ _ _ hf hg

end

lemma continuous_min : continuous (λ p : α × α, min p.1 p.2) := continuous_fst.min continuous_snd

lemma continuous_max : continuous (λ p : α × α, max p.1 p.2) := continuous_fst.max continuous_snd

lemma filter.tendsto.max {b : filter β} {a₁ a₂ : α} (hf : tendsto f b (𝓝 a₁))
  (hg : tendsto g b (𝓝 a₂)) :
  tendsto (λb, max (f b) (g b)) b (𝓝 (max a₁ a₂)) :=
(continuous_max.tendsto (a₁, a₂)).comp (hf.prod_mk_nhds hg)

lemma filter.tendsto.min {b : filter β} {a₁ a₂ : α} (hf : tendsto f b (𝓝 a₁))
  (hg : tendsto g b (𝓝 a₂)) :
  tendsto (λb, min (f b) (g b)) b (𝓝 (min a₁ a₂)) :=
(continuous_min.tendsto (a₁, a₂)).comp (hf.prod_mk_nhds hg)

end linear_order

end order_closed_topology

/-- The order topology on an ordered type is the topology generated by open intervals. We register
it on a preorder, but it is mostly interesting in linear orders, where it is also order-closed.
We define it as a mixin. If you want to introduce the order topology on a preorder, use
`preorder.topology`. -/
class order_topology (α : Type*) [t : topological_space α] [preorder α] : Prop :=
(topology_eq_generate_intervals : t = generate_from {s | ∃a, s = Ioi a ∨ s = Iio a})

/-- (Order) topology on a partial order `α` generated by the subbase of open intervals
`(a, ∞) = { x ∣ a < x }, (-∞ , b) = {x ∣ x < b}` for all `a, b` in `α`. We do not register it as an
instance as many ordered sets are already endowed with the same topology, most often in a non-defeq
way though. Register as a local instance when necessary. -/
def preorder.topology (α : Type*) [preorder α] : topological_space α :=
generate_from {s : set α | ∃ (a : α), s = {b : α | a < b} ∨ s = {b : α | b < a}}

section order_topology

instance {α : Type*} [topological_space α] [partial_order α] [order_topology α] :
  order_topology (order_dual α) :=
⟨by convert @order_topology.topology_eq_generate_intervals α _ _ _;
  conv in (_ ∨ _) { rw or.comm }; refl⟩

section partial_order
variables [topological_space α] [partial_order α] [t : order_topology α]
include t

lemma is_open_iff_generate_intervals {s : set α} :
  is_open s ↔ generate_open {s | ∃a, s = Ioi a ∨ s = Iio a} s :=
by rw [t.topology_eq_generate_intervals]; refl

lemma is_open_lt' (a : α) : is_open {b:α | a < b} :=
by rw [@is_open_iff_generate_intervals α _ _ t]; exact generate_open.basic _ ⟨a, or.inl rfl⟩

lemma is_open_gt' (a : α) : is_open {b:α | b < a} :=
by rw [@is_open_iff_generate_intervals α _ _ t]; exact generate_open.basic _ ⟨a, or.inr rfl⟩

lemma lt_mem_nhds {a b : α} (h : a < b) : ∀ᶠ x in 𝓝 b, a < x :=
mem_nhds_sets (is_open_lt' _) h

lemma le_mem_nhds {a b : α} (h : a < b) : ∀ᶠ x in 𝓝 b, a ≤ x :=
(𝓝 b).sets_of_superset (lt_mem_nhds h) $ assume b hb, le_of_lt hb

lemma gt_mem_nhds {a b : α} (h : a < b) : ∀ᶠ x in 𝓝 a, x < b :=
mem_nhds_sets (is_open_gt' _) h

lemma ge_mem_nhds {a b : α} (h : a < b) : ∀ᶠ x in 𝓝 a, x ≤ b :=
(𝓝 a).sets_of_superset (gt_mem_nhds h) $ assume b hb, le_of_lt hb

lemma nhds_eq_order (a : α) :
  𝓝 a = (⨅b ∈ Iio a, 𝓟 (Ioi b)) ⊓ (⨅b ∈ Ioi a, 𝓟 (Iio b)) :=
by rw [t.topology_eq_generate_intervals, nhds_generate_from];
from le_antisymm
  (le_inf
    (le_binfi $ assume b hb, infi_le_of_le {c : α | b < c} $ infi_le _ ⟨hb, b, or.inl rfl⟩)
    (le_binfi $ assume b hb, infi_le_of_le {c : α | c < b} $ infi_le _ ⟨hb, b, or.inr rfl⟩))
  (le_infi $ assume s, le_infi $ assume ⟨ha, b, hs⟩,
    match s, ha, hs with
    | _, h, (or.inl rfl) := inf_le_left_of_le $ infi_le_of_le b $ infi_le _ h
    | _, h, (or.inr rfl) := inf_le_right_of_le $ infi_le_of_le b $ infi_le _ h
    end)

lemma tendsto_order {f : β → α} {a : α} {x : filter β} :
  tendsto f x (𝓝 a) ↔ (∀ a' < a, ∀ᶠ b in x, a' < f b) ∧ (∀ a' > a, ∀ᶠ b in x, f b < a') :=
by simp [nhds_eq_order a, tendsto_inf, tendsto_infi, tendsto_principal]

instance tendsto_Icc_class_nhds (a : α) : tendsto_Ixx_class Icc (𝓝 a) (𝓝 a) :=
begin
  simp only [nhds_eq_order, infi_subtype'],
  refine ((has_basis_infi_principal_finite _).inf
    (has_basis_infi_principal_finite _)).tendsto_Ixx_class (λ s hs, _),
  refine ((ord_connected_bInter _).inter (ord_connected_bInter _)).out; intros _ _,
  exacts [ord_connected_Ioi, ord_connected_Iio]
end

instance tendsto_Ico_class_nhds (a : α) : tendsto_Ixx_class Ico (𝓝 a) (𝓝 a) :=
tendsto_Ixx_class_of_subset (λ _ _, Ico_subset_Icc_self)

instance tendsto_Ioc_class_nhds (a : α) : tendsto_Ixx_class Ioc (𝓝 a) (𝓝 a) :=
tendsto_Ixx_class_of_subset (λ _ _, Ioc_subset_Icc_self)

instance tendsto_Ioo_class_nhds (a : α) : tendsto_Ixx_class Ioo (𝓝 a) (𝓝 a) :=
tendsto_Ixx_class_of_subset (λ _ _, Ioo_subset_Icc_self)

/-- Also known as squeeze or sandwich theorem. This version assumes that inequalities hold
eventually for the filter. -/
lemma tendsto_of_tendsto_of_tendsto_of_le_of_le' {f g h : β → α} {b : filter β} {a : α}
  (hg : tendsto g b (𝓝 a)) (hh : tendsto h b (𝓝 a))
  (hgf : ∀ᶠ b in b, g b ≤ f b) (hfh : ∀ᶠ b in b, f b ≤ h b) :
  tendsto f b (𝓝 a) :=
tendsto_order.2
  ⟨assume a' h',
    have ∀ᶠ b in b, a' < g b, from (tendsto_order.1 hg).left a' h',
    by filter_upwards [this, hgf] assume a, lt_of_lt_of_le,
    assume a' h',
    have ∀ᶠ b in b, h b < a', from (tendsto_order.1 hh).right a' h',
    by filter_upwards [this, hfh] assume a h₁ h₂, lt_of_le_of_lt h₂ h₁⟩

/-- Also known as squeeze or sandwich theorem. This version assumes that inequalities hold
everywhere. -/
lemma tendsto_of_tendsto_of_tendsto_of_le_of_le {f g h : β → α} {b : filter β} {a : α}
  (hg : tendsto g b (𝓝 a)) (hh : tendsto h b (𝓝 a)) (hgf : g ≤ f) (hfh : f ≤ h) :
  tendsto f b (𝓝 a) :=
tendsto_of_tendsto_of_tendsto_of_le_of_le' hg hh
  (eventually_of_forall hgf) (eventually_of_forall hfh)

lemma nhds_order_unbounded {a : α} (hu : ∃u, a < u) (hl : ∃l, l < a) :
  𝓝 a = (⨅l (h₂ : l < a) u (h₂ : a < u), 𝓟 (Ioo l u)) :=
have ∃ u, u ∈ Ioi a, from hu, have ∃ l, l ∈ Iio a, from hl,
by { simp only [nhds_eq_order, inf_binfi, binfi_inf, *, inf_principal, Ioi_inter_Iio], refl }

lemma tendsto_order_unbounded {f : β → α} {a : α} {x : filter β}
  (hu : ∃u, a < u) (hl : ∃l, l < a) (h : ∀l u, l < a → a < u → ∀ᶠ b in x, l < f b ∧ f b < u) :
  tendsto f x (𝓝 a) :=
by rw [nhds_order_unbounded hu hl];
from (tendsto_infi.2 $ assume l, tendsto_infi.2 $ assume hl,
  tendsto_infi.2 $ assume u, tendsto_infi.2 $ assume hu, tendsto_principal.2 $ h l u hl hu)

end partial_order

instance tendsto_Ixx_nhds_within {α : Type*} [preorder α] [topological_space α]
  (a : α) {s t : set α} {Ixx}
  [tendsto_Ixx_class Ixx (𝓝 a) (𝓝 a)] [tendsto_Ixx_class Ixx (𝓟 s) (𝓟 t)]:
  tendsto_Ixx_class Ixx (𝓝[s] a) (𝓝[t] a) :=
filter.tendsto_Ixx_class_inf

instance tendsto_Icc_class_nhds_pi {ι : Type*} {α : ι → Type*}
  [Π i, partial_order (α i)] [Π i, topological_space (α i)] [∀ i, order_topology (α i)]
  (f : Π i, α i) :
  tendsto_Ixx_class Icc (𝓝 f) (𝓝 f) :=
begin
  constructor,
  conv in ((𝓝 f).lift' powerset) { rw [nhds_pi] },
  simp only [lift'_infi_powerset, comap_lift'_eq2 monotone_powerset, tendsto_infi, tendsto_lift',
    mem_powerset_iff, subset_def, mem_preimage],
  intros i s hs,
  have : tendsto (λ g : Π i, α i, g i) (𝓝 f) (𝓝 (f i)) := ((continuous_apply i).tendsto f),
  refine (tendsto_lift'.1 ((this.comp tendsto_fst).Icc (this.comp tendsto_snd)) s hs).mono _,
  exact λ p hp g hg, hp ⟨hg.1 _, hg.2 _⟩
end

theorem induced_order_topology' {α : Type u} {β : Type v}
  [partial_order α] [ta : topological_space β] [partial_order β] [order_topology β]
  (f : α → β) (hf : ∀ {x y}, f x < f y ↔ x < y)
  (H₁ : ∀ {a x}, x < f a → ∃ b < a, x ≤ f b)
  (H₂ : ∀ {a x}, f a < x → ∃ b > a, f b ≤ x) :
  @order_topology _ (induced f ta) _ :=
begin
  letI := induced f ta,
  refine ⟨eq_of_nhds_eq_nhds (λ a, _)⟩,
  rw [nhds_induced, nhds_generate_from, nhds_eq_order (f a)],
  apply le_antisymm,
  { refine le_infi (λ s, le_infi $ λ hs, le_principal_iff.2 _),
    rcases hs with ⟨ab, b, rfl|rfl⟩,
    { exact mem_comap_sets.2 ⟨{x | f b < x},
        mem_inf_sets_of_left $ mem_infi_sets _ $ mem_infi_sets (hf.2 ab) $ mem_principal_self _,
        λ x, hf.1⟩ },
    { exact mem_comap_sets.2 ⟨{x | x < f b},
        mem_inf_sets_of_right $ mem_infi_sets _ $ mem_infi_sets (hf.2 ab) $ mem_principal_self _,
        λ x, hf.1⟩ } },
  { rw [← map_le_iff_le_comap],
    refine le_inf _ _; refine le_infi (λ x, le_infi $ λ h, le_principal_iff.2 _); simp,
    { rcases H₁ h with ⟨b, ab, xb⟩,
      refine mem_infi_sets _ (mem_infi_sets ⟨ab, b, or.inl rfl⟩ (mem_principal_sets.2 _)),
      exact λ c hc, lt_of_le_of_lt xb (hf.2 hc) },
    { rcases H₂ h with ⟨b, ab, xb⟩,
      refine mem_infi_sets _ (mem_infi_sets ⟨ab, b, or.inr rfl⟩ (mem_principal_sets.2 _)),
      exact λ c hc, lt_of_lt_of_le (hf.2 hc) xb } },
end

theorem induced_order_topology {α : Type u} {β : Type v}
  [partial_order α] [ta : topological_space β] [partial_order β] [order_topology β]
  (f : α → β) (hf : ∀ {x y}, f x < f y ↔ x < y)
  (H : ∀ {x y}, x < y → ∃ a, x < f a ∧ f a < y) :
  @order_topology _ (induced f ta) _ :=
induced_order_topology' f @hf
  (λ a x xa, let ⟨b, xb, ba⟩ := H xa in ⟨b, hf.1 ba, le_of_lt xb⟩)
  (λ a x ax, let ⟨b, ab, bx⟩ := H ax in ⟨b, hf.1 ab, le_of_lt bx⟩)

/-- On an `ord_connected` subset of a linear order, the order topology for the restriction of the
order is the same as the restriction to the subset of the order topology. -/
instance order_topology_of_ord_connected {α : Type u}
  [ta : topological_space α] [linear_order α] [order_topology α]
  {t : set α} [ht : ord_connected t] :
  order_topology t :=
begin
  letI := induced (coe : t → α) ta,
  refine ⟨eq_of_nhds_eq_nhds (λ a, _)⟩,
  rw [nhds_induced, nhds_generate_from, nhds_eq_order (a : α)],
  apply le_antisymm,
  { refine le_infi (λ s, le_infi $ λ hs, le_principal_iff.2 _),
    rcases hs with ⟨ab, b, rfl|rfl⟩,
    { refine ⟨Ioi b, _, λ _, id⟩,
      refine mem_inf_sets_of_left (mem_infi_sets b _),
      exact mem_infi_sets ab (mem_principal_self (Ioi ↑b)) },
    { refine ⟨Iio b, _, λ _, id⟩,
      refine mem_inf_sets_of_right (mem_infi_sets b _),
      exact mem_infi_sets ab (mem_principal_self (Iio b)) } },
  { rw [← map_le_iff_le_comap],
    refine le_inf _ _,
    { refine le_infi (λ x, le_infi $ λ h, le_principal_iff.2 _),
      by_cases hx : x ∈ t,
      { refine mem_infi_sets (Ioi ⟨x, hx⟩) (mem_infi_sets ⟨h, ⟨⟨x, hx⟩, or.inl rfl⟩⟩ _),
        exact λ _, id },
      simp only [set_coe.exists, mem_set_of_eq, mem_map],
      convert univ_sets _,
      suffices hx' : ∀ (y : t), ↑y ∈ Ioi x,
      { simp [hx'] },
      intros y,
      revert hx,
      contrapose!,
      -- here we use the `ord_connected` hypothesis
      exact λ hx, ht.out y.2 a.2 ⟨le_of_not_gt hx, le_of_lt h⟩ },
    { refine le_infi (λ x, le_infi $ λ h, le_principal_iff.2 _),
      by_cases hx : x ∈ t,
      { refine mem_infi_sets (Iio ⟨x, hx⟩) (mem_infi_sets ⟨h, ⟨⟨x, hx⟩, or.inr rfl⟩⟩ _),
        exact λ _, id },
      simp only [set_coe.exists, mem_set_of_eq, mem_map],
      convert univ_sets _,
      suffices hx' : ∀ (y : t), ↑y ∈ Iio x,
      { simp [hx'] },
      intros y,
      revert hx,
      contrapose!,
      -- here we use the `ord_connected` hypothesis
      exact λ hx, ht.out a.2 y.2 ⟨le_of_lt h, le_of_not_gt hx⟩ } }
end

lemma nhds_top_order [topological_space α] [order_top α] [order_topology α] :
  𝓝 (⊤:α) = (⨅l (h₂ : l < ⊤), 𝓟 (Ioi l)) :=
by simp [nhds_eq_order (⊤:α)]

lemma nhds_bot_order [topological_space α] [order_bot α] [order_topology α] :
  𝓝 (⊥:α) = (⨅l (h₂ : ⊥ < l), 𝓟 (Iio l)) :=
by simp [nhds_eq_order (⊥:α)]

lemma tendsto_nhds_top_mono [topological_space β] [order_top β] [order_topology β] {l : filter α}
  {f g : α → β} (hf : tendsto f l (𝓝 ⊤)) (hg : f ≤ᶠ[l] g) :
  tendsto g l (𝓝 ⊤) :=
begin
  simp only [nhds_top_order, tendsto_infi, tendsto_principal] at hf ⊢,
  intros x hx,
  filter_upwards [hf x hx, hg],
  exact λ x, lt_of_lt_of_le
end

lemma tendsto_nhds_bot_mono [topological_space β] [order_bot β] [order_topology β] {l : filter α}
  {f g : α → β} (hf : tendsto f l (𝓝 ⊥)) (hg : g ≤ᶠ[l] f) :
  tendsto g l (𝓝 ⊥) :=
@tendsto_nhds_top_mono α (order_dual β) _ _ _ _ _ _ hf hg

lemma tendsto_nhds_top_mono' [topological_space β] [order_top β] [order_topology β] {l : filter α}
  {f g : α → β} (hf : tendsto f l (𝓝 ⊤)) (hg : f ≤ g) :
  tendsto g l (𝓝 ⊤) :=
tendsto_nhds_top_mono hf (eventually_of_forall hg)

lemma tendsto_nhds_bot_mono' [topological_space β] [order_bot β] [order_topology β] {l : filter α}
  {f g : α → β} (hf : tendsto f l (𝓝 ⊥)) (hg : g ≤ f) :
  tendsto g l (𝓝 ⊥) :=
tendsto_nhds_bot_mono hf (eventually_of_forall hg)

section linear_order

variables [topological_space α] [linear_order α] [order_topology α]

lemma exists_Ioc_subset_of_mem_nhds' {a : α} {s : set α} (hs : s ∈ 𝓝 a) {l : α} (hl : l < a) :
  ∃ l' ∈ Ico l a, Ioc l' a ⊆ s :=
begin
  rw [nhds_eq_order a] at hs,
  rcases hs with ⟨t₁, ht₁, t₂, ht₂, hts⟩,
  -- First we show that `t₂` includes `(-∞, a]`, so it suffices to show `(l', ∞) ⊆ t₁`
  suffices : ∃ l' ∈ Ico l a, Ioi l' ⊆ t₁,
  { have A : 𝓟 (Iic a) ≤ ⨅ b ∈ Ioi a, 𝓟 (Iio b),
      from (le_infi $ λ b, le_infi $ λ hb, principal_mono.2 $ Iic_subset_Iio.2 hb),
    have B : t₁ ∩ Iic a ⊆ s,
      from subset.trans (inter_subset_inter_right _ (A ht₂)) hts,
    from this.imp (λ l', Exists.imp $ λ hl' hl x hx, B ⟨hl hx.1, hx.2⟩) },
  clear hts ht₂ t₂,
  -- Now we find `l` such that `(l', ∞) ⊆ t₁`
  rw [mem_binfi] at ht₁,
  { rcases ht₁ with ⟨b, hb, hb'⟩,
    exact ⟨max b l, ⟨le_max_right _ _, max_lt hb hl⟩,
      λ x hx, hb' $ Ioi_subset_Ioi (le_max_left _ _) hx⟩ },
  { intros b hb b' hb', simp only [mem_Iio] at hb hb',
    use [max b b', max_lt hb hb'],
    simp [le_refl] },
  exact ⟨l, hl⟩
end

lemma exists_Ico_subset_of_mem_nhds' {a : α} {s : set α} (hs : s ∈ 𝓝 a) {u : α} (hu : a < u) :
  ∃ u' ∈ Ioc a u, Ico a u' ⊆ s :=
begin
  convert @exists_Ioc_subset_of_mem_nhds' (order_dual α) _ _ _ _ _ hs _ hu,
  ext, rw [dual_Ico, dual_Ioc]
end

lemma exists_Ioc_subset_of_mem_nhds {a : α} {s : set α} (hs : s ∈ 𝓝 a) (h : ∃ l, l < a) :
  ∃ l < a, Ioc l a ⊆ s :=
let ⟨l', hl'⟩ := h in let ⟨l, hl⟩ := exists_Ioc_subset_of_mem_nhds' hs hl' in ⟨l, hl.fst.2, hl.snd⟩

lemma exists_Ico_subset_of_mem_nhds {a : α} {s : set α} (hs : s ∈ 𝓝 a) (h : ∃ u, a < u) :
  ∃ u (_ : a < u), Ico a u ⊆ s :=
let ⟨l', hl'⟩ := h in let ⟨l, hl⟩ := exists_Ico_subset_of_mem_nhds' hs hl' in ⟨l, hl.fst.1, hl.snd⟩

lemma order_separated {a₁ a₂ : α} (h : a₁ < a₂) :
  ∃u v : set α, is_open u ∧ is_open v ∧ a₁ ∈ u ∧ a₂ ∈ v ∧ (∀b₁∈u, ∀b₂∈v, b₁ < b₂) :=
match dense_or_discrete a₁ a₂ with
| or.inl ⟨a, ha₁, ha₂⟩ := ⟨{a' | a' < a}, {a' | a < a'}, is_open_gt' a, is_open_lt' a, ha₁, ha₂,
    assume b₁ h₁ b₂ h₂, lt_trans h₁ h₂⟩
| or.inr ⟨h₁, h₂⟩ := ⟨{a | a < a₂}, {a | a₁ < a}, is_open_gt' a₂, is_open_lt' a₁, h, h,
    assume b₁ hb₁ b₂ hb₂,
    calc b₁ ≤ a₁ : h₂ _ hb₁
      ... < a₂ : h
      ... ≤ b₂ : h₁ _ hb₂⟩
end

@[priority 100] -- see Note [lower instance priority]
instance order_topology.to_order_closed_topology : order_closed_topology α :=
{ is_closed_le' :=
    is_open_compl_iff.1 $ is_open_prod_iff.mpr $ assume a₁ a₂ (h : ¬ a₁ ≤ a₂),
      have h : a₂ < a₁, from lt_of_not_ge h,
      let ⟨u, v, hu, hv, ha₁, ha₂, h⟩ := order_separated h in
      ⟨v, u, hv, hu, ha₂, ha₁, assume ⟨b₁, b₂⟩ ⟨h₁, h₂⟩, not_le_of_gt $ h b₂ h₂ b₁ h₁⟩ }

lemma order_topology.t2_space : t2_space α := by apply_instance

@[priority 100] -- see Note [lower instance priority]
instance order_topology.regular_space : regular_space α :=
{ regular := assume s a hs ha,
    have hs' : sᶜ ∈ 𝓝 a, from mem_nhds_sets hs.is_open_compl ha,
    have ∃t:set α, is_open t ∧ (∀l∈ s, l < a → l ∈ t) ∧ 𝓝[t] a = ⊥,
      from by_cases
        (assume h : ∃l, l < a,
          let ⟨l, hl, h⟩ := exists_Ioc_subset_of_mem_nhds hs' h in
          match dense_or_discrete l a with
          | or.inl ⟨b, hb₁, hb₂⟩ := ⟨{a | a < b}, is_open_gt' _,
              assume c hcs hca, show c < b,
                from lt_of_not_ge $ assume hbc, h ⟨lt_of_lt_of_le hb₁ hbc, le_of_lt hca⟩ hcs,
              inf_principal_eq_bot.2 $ (𝓝 a).sets_of_superset (mem_nhds_sets (is_open_lt' _) hb₂) $
                assume x (hx : b < x), show ¬ x < b, from not_lt.2 $ le_of_lt hx⟩
          | or.inr ⟨h₁, h₂⟩ := ⟨{a' | a' < a}, is_open_gt' _, assume b hbs hba, hba,
              inf_principal_eq_bot.2 $ (𝓝 a).sets_of_superset (mem_nhds_sets (is_open_lt' _) hl) $
                assume x (hx : l < x), show ¬ x < a, from not_lt.2 $ h₁ _ hx⟩
          end)
        (assume : ¬ ∃l, l < a, ⟨∅, is_open_empty, assume l _ hl, (this ⟨l, hl⟩).elim,
          nhds_within_empty _⟩),
    let ⟨t₁, ht₁o, ht₁s, ht₁a⟩ := this in
    have ∃t:set α, is_open t ∧ (∀u∈ s, u>a → u ∈ t) ∧ 𝓝[t] a = ⊥,
      from by_cases
        (assume h : ∃u, u > a,
          let ⟨u, hu, h⟩ := exists_Ico_subset_of_mem_nhds hs' h in
          match dense_or_discrete a u with
          | or.inl ⟨b, hb₁, hb₂⟩ := ⟨{a | b < a}, is_open_lt' _,
              assume c hcs hca, show c > b,
                from lt_of_not_ge $ assume hbc, h ⟨le_of_lt hca, lt_of_le_of_lt hbc hb₂⟩ hcs,
              inf_principal_eq_bot.2 $ (𝓝 a).sets_of_superset (mem_nhds_sets (is_open_gt' _) hb₁) $
                assume x (hx : b > x), show ¬ x > b, from not_lt.2 $ le_of_lt hx⟩
          | or.inr ⟨h₁, h₂⟩ := ⟨{a' | a' > a}, is_open_lt' _, assume b hbs hba, hba,
              inf_principal_eq_bot.2 $ (𝓝 a).sets_of_superset (mem_nhds_sets (is_open_gt' _) hu) $
                assume x (hx : u > x), show ¬ x > a, from not_lt.2 $ h₂ _ hx⟩
          end)
        (assume : ¬ ∃u, u > a, ⟨∅, is_open_empty, assume l _ hl, (this ⟨l, hl⟩).elim,
          nhds_within_empty _⟩),
    let ⟨t₂, ht₂o, ht₂s, ht₂a⟩ := this in
    ⟨t₁ ∪ t₂, is_open_union ht₁o ht₂o,
      assume x hx,
      have x ≠ a, from assume eq, ha $ eq ▸ hx,
      (ne_iff_lt_or_gt.mp this).imp (ht₁s _ hx) (ht₂s _ hx),
      by rw [nhds_within_union, ht₁a, ht₂a, bot_sup_eq]⟩,
  ..order_topology.t2_space }

/-- A set is a neighborhood of `a` if and only if it contains an interval `(l, u)` containing `a`,
provided `a` is neither a bottom element nor a top element. -/
lemma mem_nhds_iff_exists_Ioo_subset' {a : α} {s : set α} (hl : ∃ l, l < a) (hu : ∃ u, a < u) :
  s ∈ 𝓝 a ↔ ∃l u, a ∈ Ioo l u ∧ Ioo l u ⊆ s :=
begin
  split,
  { assume h,
    rcases exists_Ico_subset_of_mem_nhds h hu with ⟨u, au, hu⟩,
    rcases exists_Ioc_subset_of_mem_nhds h hl with ⟨l, la, hl⟩,
    refine ⟨l, u, ⟨la, au⟩, λx hx, _⟩,
    cases le_total a x with hax hax,
    { exact hu ⟨hax, hx.2⟩ },
    { exact hl ⟨hx.1, hax⟩ } },
  { rintros ⟨l, u, ha, h⟩,
    apply mem_sets_of_superset (mem_nhds_sets is_open_Ioo ha) h }
end

/-- A set is a neighborhood of `a` if and only if it contains an interval `(l, u)` containing `a`.
-/
lemma mem_nhds_iff_exists_Ioo_subset [no_top_order α] [no_bot_order α] {a : α} {s : set α} :
  s ∈ 𝓝 a ↔ ∃l u, a ∈ Ioo l u ∧ Ioo l u ⊆ s :=
mem_nhds_iff_exists_Ioo_subset' (no_bot a) (no_top a)

lemma nhds_basis_Ioo' {a : α} (hl : ∃l, l < a) (hu : ∃u, a < u) :
  (𝓝 a).has_basis (λ b : α × α, b.1 < a ∧ a < b.2) (λ b, Ioo b.1 b.2) :=
⟨λ s, (mem_nhds_iff_exists_Ioo_subset' hl hu).trans $ by simp⟩

lemma nhds_basis_Ioo [no_top_order α] [no_bot_order α] {a : α} :
  (𝓝 a).has_basis (λ b : α × α, b.1 < a ∧ a < b.2) (λ b, Ioo b.1 b.2) :=
nhds_basis_Ioo' (no_bot a) (no_top a)

lemma filter.eventually.exists_Ioo_subset [no_top_order α] [no_bot_order α] {a : α} {p : α → Prop}
  (hp : ∀ᶠ x in 𝓝 a, p x) :
  ∃ l u, a ∈ Ioo l u ∧ Ioo l u ⊆ {x | p x} :=
mem_nhds_iff_exists_Ioo_subset.1 hp

lemma Iio_mem_nhds {a b : α} (h : a < b) : Iio b ∈ 𝓝 a :=
mem_nhds_sets is_open_Iio h

lemma Ioi_mem_nhds {a b : α} (h : a < b) : Ioi a ∈ 𝓝 b :=
mem_nhds_sets is_open_Ioi h

lemma Iic_mem_nhds {a b : α} (h : a < b) : Iic b ∈ 𝓝 a :=
mem_sets_of_superset (Iio_mem_nhds h) Iio_subset_Iic_self

lemma Ici_mem_nhds {a b : α} (h : a < b) : Ici a ∈ 𝓝 b :=
mem_sets_of_superset (Ioi_mem_nhds h) Ioi_subset_Ici_self

lemma Ioo_mem_nhds {a b x : α} (ha : a < x) (hb : x < b) : Ioo a b ∈ 𝓝 x :=
mem_nhds_sets is_open_Ioo ⟨ha, hb⟩

lemma Ioc_mem_nhds {a b x : α} (ha : a < x) (hb : x < b) : Ioc a b ∈ 𝓝 x :=
mem_sets_of_superset (Ioo_mem_nhds ha hb) Ioo_subset_Ioc_self

lemma Ico_mem_nhds {a b x : α} (ha : a < x) (hb : x < b) : Ico a b ∈ 𝓝 x :=
mem_sets_of_superset (Ioo_mem_nhds ha hb) Ioo_subset_Ico_self

lemma Icc_mem_nhds {a b x : α} (ha : a < x) (hb : x < b) : Icc a b ∈ 𝓝 x :=
mem_sets_of_superset (Ioo_mem_nhds ha hb) Ioo_subset_Icc_self

section pi

/-!
### Intervals in `Π i, π i` belong to `𝓝 x`

For each leamma `pi_Ixx_mem_nhds` we add a non-dependent version `pi_Ixx_mem_nhds'` because
sometimes Lean fails to unify different instances while trying to apply the dependent version to,
e.g., `ι → ℝ`.
-/

variables {ι : Type*} {π : ι → Type*} [fintype ι] [Π i, linear_order (π i)]
  [Π i, topological_space (π i)] [∀ i, order_topology (π i)] {a b x : Π i, π i} {a' b' x' : ι → α}

lemma pi_Iic_mem_nhds (ha : ∀ i, x i < a i) : Iic a ∈ 𝓝 x :=
pi_univ_Iic a ▸ set_pi_mem_nhds (finite.of_fintype _) (λ i _, Iic_mem_nhds (ha _))

lemma pi_Iic_mem_nhds' (ha : ∀ i, x' i < a' i) : Iic a' ∈ 𝓝 x' :=
pi_Iic_mem_nhds ha

lemma pi_Ici_mem_nhds (ha : ∀ i, a i < x i) : Ici a ∈ 𝓝 x :=
pi_univ_Ici a ▸ set_pi_mem_nhds (finite.of_fintype _) (λ i _, Ici_mem_nhds (ha _))

lemma pi_Ici_mem_nhds' (ha : ∀ i, a' i < x' i) : Ici a' ∈ 𝓝 x' :=
pi_Ici_mem_nhds ha

lemma pi_Icc_mem_nhds (ha : ∀ i, a i < x i) (hb : ∀ i, x i < b i) : Icc a b ∈ 𝓝 x :=
pi_univ_Icc a b ▸ set_pi_mem_nhds (finite.of_fintype _) (λ i _, Icc_mem_nhds (ha _) (hb _))

lemma pi_Icc_mem_nhds' (ha : ∀ i, a' i < x' i) (hb : ∀ i, x' i < b' i) : Icc a' b' ∈ 𝓝 x' :=
pi_Icc_mem_nhds ha hb

variables [nonempty ι]

lemma pi_Iio_mem_nhds (ha : ∀ i, x i < a i) : Iio a ∈ 𝓝 x :=
begin
  refine mem_sets_of_superset (set_pi_mem_nhds (finite.of_fintype _) (λ i _, _))
    (pi_univ_Iio_subset a),
  exact Iio_mem_nhds (ha i)
end

lemma pi_Iio_mem_nhds' (ha : ∀ i, x' i < a' i) : Iio a' ∈ 𝓝 x' :=
pi_Iio_mem_nhds ha

lemma pi_Ioi_mem_nhds (ha : ∀ i, a i < x i) : Ioi a ∈ 𝓝 x :=
@pi_Iio_mem_nhds ι (λ i, order_dual (π i)) _ _ _ _ _ _ _ ha

lemma pi_Ioi_mem_nhds' (ha : ∀ i, a' i < x' i) : Ioi a' ∈ 𝓝 x' :=
pi_Ioi_mem_nhds ha

lemma pi_Ioc_mem_nhds (ha : ∀ i, a i < x i) (hb : ∀ i, x i < b i) : Ioc a b ∈ 𝓝 x :=
begin
  refine mem_sets_of_superset (set_pi_mem_nhds (finite.of_fintype _) (λ i _, _))
    (pi_univ_Ioc_subset a b),
  exact Ioc_mem_nhds (ha i) (hb i)
end

lemma pi_Ioc_mem_nhds' (ha : ∀ i, a' i < x' i) (hb : ∀ i, x' i < b' i) : Ioc a' b' ∈ 𝓝 x' :=
pi_Ioc_mem_nhds ha hb

lemma pi_Ico_mem_nhds (ha : ∀ i, a i < x i) (hb : ∀ i, x i < b i) : Ico a b ∈ 𝓝 x :=
begin
  refine mem_sets_of_superset (set_pi_mem_nhds (finite.of_fintype _) (λ i _, _))
    (pi_univ_Ico_subset a b),
  exact Ico_mem_nhds (ha i) (hb i)
end

lemma pi_Ico_mem_nhds' (ha : ∀ i, a' i < x' i) (hb : ∀ i, x' i < b' i) : Ico a' b' ∈ 𝓝 x' :=
pi_Ico_mem_nhds ha hb

lemma pi_Ioo_mem_nhds (ha : ∀ i, a i < x i) (hb : ∀ i, x i < b i) : Ioo a b ∈ 𝓝 x :=
begin
  refine mem_sets_of_superset (set_pi_mem_nhds (finite.of_fintype _) (λ i _, _))
    (pi_univ_Ioo_subset a b),
  exact Ioo_mem_nhds (ha i) (hb i)
end

lemma pi_Ioo_mem_nhds' (ha : ∀ i, a' i < x' i) (hb : ∀ i, x' i < b' i) : Ioo a' b' ∈ 𝓝 x' :=
pi_Ioo_mem_nhds ha hb

end pi

lemma disjoint_nhds_at_top [no_top_order α] (x : α) :
  disjoint (𝓝 x) at_top :=
begin
  rw filter.disjoint_iff,
  cases no_top x with a ha,
  use [Iio a, Iio_mem_nhds ha, Ici a, mem_at_top a],
  rw [inter_comm, Ici_inter_Iio, Ico_self]
end

@[simp] lemma inf_nhds_at_top [no_top_order α] (x : α) :
  𝓝 x ⊓ at_top = ⊥ :=
disjoint_iff.1 (disjoint_nhds_at_top x)

lemma disjoint_nhds_at_bot [no_bot_order α] (x : α) :
  disjoint (𝓝 x) at_bot :=
@disjoint_nhds_at_top (order_dual α) _ _ _ _ x

@[simp] lemma inf_nhds_at_bot [no_bot_order α] (x : α) :
  𝓝 x ⊓ at_bot = ⊥ :=
@inf_nhds_at_top (order_dual α) _ _ _ _ x

lemma not_tendsto_nhds_of_tendsto_at_top [no_top_order α]
  {F : filter β} [ne_bot F] {f : β → α} (hf : tendsto f F at_top) (x : α) :
  ¬ tendsto f F (𝓝 x) :=
hf.not_tendsto (disjoint_nhds_at_top x).symm

lemma not_tendsto_at_top_of_tendsto_nhds [no_top_order α]
  {F : filter β} [ne_bot F] {f : β → α} {x : α} (hf : tendsto f F (𝓝 x)) :
  ¬  tendsto f F at_top :=
hf.not_tendsto (disjoint_nhds_at_top x)

lemma not_tendsto_nhds_of_tendsto_at_bot [no_bot_order α]
  {F : filter β} [ne_bot F] {f : β → α} (hf : tendsto f F at_bot) (x : α) :
  ¬ tendsto f F (𝓝 x) :=
hf.not_tendsto (disjoint_nhds_at_bot x).symm

lemma not_tendsto_at_bot_of_tendsto_nhds [no_bot_order α]
  {F : filter β} [ne_bot F] {f : β → α} {x : α} (hf : tendsto f F (𝓝 x)) :
  ¬  tendsto f F at_bot :=
hf.not_tendsto (disjoint_nhds_at_bot x)

/-!
### Neighborhoods to the left and to the right on an `order_topology`

We've seen some properties of left and right neighborhood of a point in an `order_closed_topology`.
In an `order_topology`, such neighborhoods can be characterized as the sets containing suitable
intervals to the right or to the left of `a`. We give now these characterizations. -/

-- NB: If you extend the list, append to the end please to avoid breaking the API
/-- The following statements are equivalent:

0. `s` is a neighborhood of `a` within `(a, +∞)`
1. `s` is a neighborhood of `a` within `(a, b]`
2. `s` is a neighborhood of `a` within `(a, b)`
3. `s` includes `(a, u)` for some `u ∈ (a, b]`
4. `s` includes `(a, u)` for some `u > a` -/
lemma tfae_mem_nhds_within_Ioi {a b : α} (hab : a < b) (s : set α) :
  tfae [s ∈ 𝓝[Ioi a] a, -- 0 : `s` is a neighborhood of `a` within `(a, +∞)`
    s ∈ 𝓝[Ioc a b] a,   -- 1 : `s` is a neighborhood of `a` within `(a, b]`
    s ∈ 𝓝[Ioo a b] a,   -- 2 : `s` is a neighborhood of `a` within `(a, b)`
    ∃ u ∈ Ioc a b, Ioo a u ⊆ s,    -- 3 : `s` includes `(a, u)` for some `u ∈ (a, b]`
    ∃ u ∈ Ioi a, Ioo a u ⊆ s] :=   -- 4 : `s` includes `(a, u)` for some `u > a`
begin
  tfae_have : 1 ↔ 2, by rw [nhds_within_Ioc_eq_nhds_within_Ioi hab],
  tfae_have : 1 ↔ 3, by rw [nhds_within_Ioo_eq_nhds_within_Ioi hab],
  tfae_have : 4 → 5, from λ ⟨u, umem, hu⟩, ⟨u, umem.1, hu⟩,
  tfae_have : 5 → 1,
  { rintros ⟨u, hau, hu⟩,
    exact mem_sets_of_superset (Ioo_mem_nhds_within_Ioi ⟨le_refl a, hau⟩) hu },
  tfae_have : 1 → 4,
  { assume h,
    rcases mem_nhds_within_iff_exists_mem_nhds_inter.1 h with ⟨v, va, hv⟩,
    rcases exists_Ico_subset_of_mem_nhds' va hab with ⟨u, au, hu⟩,
    refine ⟨u, au, λx hx, _⟩,
    refine hv ⟨hu ⟨le_of_lt hx.1, hx.2⟩, _⟩,
    exact hx.1 },
  tfae_finish
end

lemma mem_nhds_within_Ioi_iff_exists_mem_Ioc_Ioo_subset {a u' : α} {s : set α} (hu' : a < u') :
  s ∈ 𝓝[Ioi a] a ↔ ∃u ∈ Ioc a u', Ioo a u ⊆ s :=
(tfae_mem_nhds_within_Ioi hu' s).out 0 3

/-- A set is a neighborhood of `a` within `(a, +∞)` if and only if it contains an interval `(a, u)`
with `a < u < u'`, provided `a` is not a top element. -/
lemma mem_nhds_within_Ioi_iff_exists_Ioo_subset' {a u' : α} {s : set α} (hu' : a < u') :
  s ∈ 𝓝[Ioi a] a ↔ ∃u ∈ Ioi a, Ioo a u ⊆ s :=
(tfae_mem_nhds_within_Ioi hu' s).out 0 4

/-- A set is a neighborhood of `a` within `(a, +∞)` if and only if it contains an interval `(a, u)`
with `a < u`. -/
lemma mem_nhds_within_Ioi_iff_exists_Ioo_subset [no_top_order α] {a : α} {s : set α} :
  s ∈ 𝓝[Ioi a] a ↔ ∃u ∈ Ioi a, Ioo a u ⊆ s :=
let ⟨u', hu'⟩ := no_top a in mem_nhds_within_Ioi_iff_exists_Ioo_subset' hu'

/-- A set is a neighborhood of `a` within `(a, +∞)` if and only if it contains an interval `(a, u]`
with `a < u`. -/
lemma mem_nhds_within_Ioi_iff_exists_Ioc_subset [no_top_order α] [densely_ordered α]
  {a : α} {s : set α} : s ∈ 𝓝[Ioi a] a ↔ ∃u ∈ Ioi a, Ioc a u ⊆ s :=
begin
  rw mem_nhds_within_Ioi_iff_exists_Ioo_subset,
  split,
  { rintros ⟨u, au, as⟩,
    rcases exists_between au with ⟨v, hv⟩,
    exact ⟨v, hv.1, λx hx, as ⟨hx.1, lt_of_le_of_lt hx.2 hv.2⟩⟩ },
  { rintros ⟨u, au, as⟩,
    exact ⟨u, au, subset.trans Ioo_subset_Ioc_self as⟩ }
end

/-- The following statements are equivalent:

0. `s` is a neighborhood of `b` within `(-∞, b)`
1. `s` is a neighborhood of `b` within `[a, b)`
2. `s` is a neighborhood of `b` within `(a, b)`
3. `s` includes `(l, b)` for some `l ∈ [a, b)`
4. `s` includes `(l, b)` for some `l < b` -/
lemma tfae_mem_nhds_within_Iio {a b : α} (h : a < b) (s : set α) :
  tfae [s ∈ 𝓝[Iio b] b, -- 0 : `s` is a neighborhood of `b` within `(-∞, b)`
    s ∈ 𝓝[Ico a b] b,   -- 1 : `s` is a neighborhood of `b` within `[a, b)`
    s ∈ 𝓝[Ioo a b] b,   -- 2 : `s` is a neighborhood of `b` within `(a, b)`
    ∃ l ∈ Ico a b, Ioo l b ⊆ s,    -- 3 : `s` includes `(l, b)` for some `l ∈ [a, b)`
    ∃ l ∈ Iio b, Ioo l b ⊆ s] :=   -- 4 : `s` includes `(l, b)` for some `l < b`
begin
  have := @tfae_mem_nhds_within_Ioi (order_dual α) _ _ _ _ _ h s,
  -- If we call `convert` here, it generates wrong equations, so we need to simplify first
  simp only [exists_prop] at this ⊢,
  rw [dual_Ioi, dual_Ioc, dual_Ioo] at this,
  convert this; ext l; rw [dual_Ioo]
end

lemma mem_nhds_within_Iio_iff_exists_mem_Ico_Ioo_subset {a l' : α} {s : set α} (hl' : l' < a) :
  s ∈ 𝓝[Iio a] a ↔ ∃l ∈ Ico l' a, Ioo l a ⊆ s :=
(tfae_mem_nhds_within_Iio hl' s).out 0 3

/-- A set is a neighborhood of `a` within `(-∞, a)` if and only if it contains an interval `(l, a)`
with `l < a`, provided `a` is not a bottom element. -/
lemma mem_nhds_within_Iio_iff_exists_Ioo_subset' {a l' : α} {s : set α} (hl' : l' < a) :
  s ∈ 𝓝[Iio a] a ↔ ∃l ∈ Iio a, Ioo l a ⊆ s :=
(tfae_mem_nhds_within_Iio hl' s).out 0 4

/-- A set is a neighborhood of `a` within `(-∞, a)` if and only if it contains an interval `(l, a)`
with `l < a`. -/
lemma mem_nhds_within_Iio_iff_exists_Ioo_subset [no_bot_order α] {a : α} {s : set α} :
  s ∈ 𝓝[Iio a] a ↔ ∃l ∈ Iio a, Ioo l a ⊆ s :=
let ⟨l', hl'⟩ := no_bot a in mem_nhds_within_Iio_iff_exists_Ioo_subset' hl'

/-- A set is a neighborhood of `a` within `(-∞, a)` if and only if it contains an interval `[l, a)`
with `l < a`. -/
lemma mem_nhds_within_Iio_iff_exists_Ico_subset [no_bot_order α] [densely_ordered α]
  {a : α} {s : set α} : s ∈ 𝓝[Iio a] a ↔ ∃l ∈ Iio a, Ico l a ⊆ s :=
begin
  convert @mem_nhds_within_Ioi_iff_exists_Ioc_subset (order_dual α) _ _ _ _ _ _ _,
  simp only [dual_Ioc], refl
end

/-- The following statements are equivalent:

0. `s` is a neighborhood of `a` within `[a, +∞)`
1. `s` is a neighborhood of `a` within `[a, b]`
2. `s` is a neighborhood of `a` within `[a, b)`
3. `s` includes `[a, u)` for some `u ∈ (a, b]`
4. `s` includes `[a, u)` for some `u > a` -/
lemma tfae_mem_nhds_within_Ici {a b : α} (hab : a < b) (s : set α) :
  tfae [s ∈ 𝓝[Ici a] a, -- 0 : `s` is a neighborhood of `a` within `[a, +∞)`
    s ∈ 𝓝[Icc a b] a,   -- 1 : `s` is a neighborhood of `a` within `[a, b]`
    s ∈ 𝓝[Ico a b] a,   -- 2 : `s` is a neighborhood of `a` within `[a, b)`
    ∃ u ∈ Ioc a b, Ico a u ⊆ s,    -- 3 : `s` includes `[a, u)` for some `u ∈ (a, b]`
    ∃ u ∈ Ioi a, Ico a u ⊆ s] :=   -- 4 : `s` includes `[a, u)` for some `u > a`
begin
  tfae_have : 1 ↔ 2, by rw [nhds_within_Icc_eq_nhds_within_Ici hab],
  tfae_have : 1 ↔ 3, by rw [nhds_within_Ico_eq_nhds_within_Ici hab],
  tfae_have : 4 → 5, from λ ⟨u, umem, hu⟩, ⟨u, umem.1, hu⟩,
  tfae_have : 5 → 1,
  { rintros ⟨u, hau, hu⟩,
    exact mem_sets_of_superset (Ico_mem_nhds_within_Ici ⟨le_refl a, hau⟩) hu },
  tfae_have : 1 → 4,
  { assume h,
    rcases mem_nhds_within_iff_exists_mem_nhds_inter.1 h with ⟨v, va, hv⟩,
    rcases exists_Ico_subset_of_mem_nhds' va hab with ⟨u, au, hu⟩,
    refine ⟨u, au, λx hx, _⟩,
    refine hv ⟨hu ⟨hx.1, hx.2⟩, _⟩,
    exact hx.1 },
  tfae_finish
end

lemma mem_nhds_within_Ici_iff_exists_mem_Ioc_Ico_subset {a u' : α} {s : set α} (hu' : a < u') :
  s ∈ 𝓝[Ici a] a ↔ ∃u ∈ Ioc a u', Ico a u ⊆ s :=
(tfae_mem_nhds_within_Ici hu' s).out 0 3 (by norm_num) (by norm_num)

/-- A set is a neighborhood of `a` within `[a, +∞)` if and only if it contains an interval `[a, u)`
with `a < u < u'`, provided `a` is not a top element. -/
lemma mem_nhds_within_Ici_iff_exists_Ico_subset' {a u' : α} {s : set α} (hu' : a < u') :
  s ∈ 𝓝[Ici a] a ↔ ∃u ∈ Ioi a, Ico a u ⊆ s :=
(tfae_mem_nhds_within_Ici hu' s).out 0 4 (by norm_num) (by norm_num)

/-- A set is a neighborhood of `a` within `[a, +∞)` if and only if it contains an interval `[a, u)`
with `a < u`. -/
lemma mem_nhds_within_Ici_iff_exists_Ico_subset [no_top_order α] {a : α} {s : set α} :
  s ∈ 𝓝[Ici a] a ↔ ∃u ∈ Ioi a, Ico a u ⊆ s :=
let ⟨u', hu'⟩ := no_top a in mem_nhds_within_Ici_iff_exists_Ico_subset' hu'

/-- A set is a neighborhood of `a` within `[a, +∞)` if and only if it contains an interval `[a, u]`
with `a < u`. -/
lemma mem_nhds_within_Ici_iff_exists_Icc_subset' [no_top_order α] [densely_ordered α]
  {a : α} {s : set α} : s ∈ 𝓝[Ici a] a ↔ ∃u ∈ Ioi a, Icc a u ⊆ s :=
begin
  rw mem_nhds_within_Ici_iff_exists_Ico_subset,
  split,
  { rintros ⟨u, au, as⟩,
    rcases exists_between au with ⟨v, hv⟩,
    exact ⟨v, hv.1, λx hx, as ⟨hx.1, lt_of_le_of_lt hx.2 hv.2⟩⟩ },
  { rintros ⟨u, au, as⟩,
    exact ⟨u, au, subset.trans Ico_subset_Icc_self as⟩ }
end

/-- The following statements are equivalent:

0. `s` is a neighborhood of `b` within `(-∞, b]`
1. `s` is a neighborhood of `b` within `[a, b]`
2. `s` is a neighborhood of `b` within `(a, b]`
3. `s` includes `(l, b]` for some `l ∈ [a, b)`
4. `s` includes `(l, b]` for some `l < b` -/
lemma tfae_mem_nhds_within_Iic {a b : α} (h : a < b) (s : set α) :
  tfae [s ∈ 𝓝[Iic b] b, -- 0 : `s` is a neighborhood of `b` within `(-∞, b]`
    s ∈ 𝓝[Icc a b] b,   -- 1 : `s` is a neighborhood of `b` within `[a, b]`
    s ∈ 𝓝[Ioc a b] b,   -- 2 : `s` is a neighborhood of `b` within `(a, b]`
    ∃ l ∈ Ico a b, Ioc l b ⊆ s,    -- 3 : `s` includes `(l, b]` for some `l ∈ [a, b)`
    ∃ l ∈ Iio b, Ioc l b ⊆ s] :=   -- 4 : `s` includes `(l, b]` for some `l < b`
begin
  have := @tfae_mem_nhds_within_Ici (order_dual α) _ _ _ _ _ h s,
  -- If we call `convert` here, it generates wrong equations, so we need to simplify first
  simp only [exists_prop] at this ⊢,
  rw [dual_Icc, dual_Ioc, dual_Ioi] at this,
  convert this; ext l; rw [dual_Ico]
end

lemma mem_nhds_within_Iic_iff_exists_mem_Ico_Ioc_subset {a l' : α} {s : set α} (hl' : l' < a) :
  s ∈ 𝓝[Iic a] a ↔ ∃l ∈ Ico l' a, Ioc l a ⊆ s :=
(tfae_mem_nhds_within_Iic hl' s).out 0 3 (by norm_num) (by norm_num)

/-- A set is a neighborhood of `a` within `(-∞, a]` if and only if it contains an interval `(l, a]`
with `l < a`, provided `a` is not a bottom element. -/
lemma mem_nhds_within_Iic_iff_exists_Ioc_subset' {a l' : α} {s : set α} (hl' : l' < a) :
  s ∈ 𝓝[Iic a] a ↔ ∃l ∈ Iio a, Ioc l a ⊆ s :=
(tfae_mem_nhds_within_Iic hl' s).out 0 4 (by norm_num) (by norm_num)

/-- A set is a neighborhood of `a` within `(-∞, a]` if and only if it contains an interval `(l, a]`
with `l < a`. -/
lemma mem_nhds_within_Iic_iff_exists_Ioc_subset [no_bot_order α] {a : α} {s : set α} :
  s ∈ 𝓝[Iic a] a ↔ ∃l ∈ Iio a, Ioc l a ⊆ s :=
let ⟨l', hl'⟩ := no_bot a in mem_nhds_within_Iic_iff_exists_Ioc_subset' hl'

/-- A set is a neighborhood of `a` within `(-∞, a]` if and only if it contains an interval `[l, a]`
with `l < a`. -/
lemma mem_nhds_within_Iic_iff_exists_Icc_subset' [no_bot_order α] [densely_ordered α]
  {a : α} {s : set α} : s ∈ 𝓝[Iic a] a ↔ ∃l ∈ Iio a, Icc l a ⊆ s :=
begin
  convert @mem_nhds_within_Ici_iff_exists_Icc_subset' (order_dual α) _ _ _ _ _ _ _,
  simp_rw (show ∀ u : order_dual α, @Icc (order_dual α) _ a u = @Icc α _ u a, from λ u, dual_Icc),
  refl,
end

/-- A set is a neighborhood of `a` within `[a, +∞)` if and only if it contains an interval `[a, u]`
with `a < u`. -/
lemma mem_nhds_within_Ici_iff_exists_Icc_subset [no_top_order α] [densely_ordered α]
  {a : α} {s : set α} : s ∈ 𝓝[Ici a] a ↔ ∃u, a < u ∧ Icc a u ⊆ s :=
begin
  rw mem_nhds_within_Ici_iff_exists_Ico_subset,
  split,
  { rintros ⟨u, au, as⟩,
    rcases exists_between au with ⟨v, hv⟩,
    exact ⟨v, hv.1, λx hx, as ⟨hx.1, lt_of_le_of_lt hx.2 hv.2⟩⟩ },
  { rintros ⟨u, au, as⟩,
    exact ⟨u, au, subset.trans Ico_subset_Icc_self as⟩ }
end

/-- A set is a neighborhood of `a` within `(-∞, a]` if and only if it contains an interval `[l, a]`
with `l < a`. -/
lemma mem_nhds_within_Iic_iff_exists_Icc_subset [no_bot_order α] [densely_ordered α]
  {a : α} {s : set α} : s ∈ 𝓝[Iic a] a ↔ ∃l, l < a ∧ Icc l a ⊆ s :=
begin
  rw mem_nhds_within_Iic_iff_exists_Ioc_subset,
  split,
  { rintros ⟨l, la, as⟩,
    rcases exists_between la with ⟨v, hv⟩,
    refine ⟨v, hv.2, λx hx, as ⟨lt_of_lt_of_le hv.1 hx.1, hx.2⟩⟩, },
  { rintros ⟨l, la, as⟩,
    exact ⟨l, la, subset.trans Ioc_subset_Icc_self as⟩ }
end

end linear_order

section linear_ordered_add_comm_group
variables [topological_space α] [linear_ordered_add_comm_group α] [order_topology α]
variables {l : filter β} {f g : β → α}

local notation `|` x `|` := abs x

lemma nhds_eq_infi_abs_sub (a : α) : 𝓝 a = (⨅r>0, 𝓟 {b | |a - b| < r}) :=
begin
  simp only [le_antisymm_iff, nhds_eq_order, le_inf_iff, le_infi_iff, le_principal_iff, mem_Ioi,
    mem_Iio, abs_sub_lt_iff, @sub_lt_iff_lt_add _ _ _ _ a, @sub_lt _ _ a, set_of_and],
  refine ⟨_, _, _⟩,
  { intros ε ε0,
    exact inter_mem_inf_sets
      (mem_infi_sets (a - ε) $ mem_infi_sets (sub_lt_self a ε0) (mem_principal_self _))
      (mem_infi_sets (ε + a) $ mem_infi_sets (by simpa) (mem_principal_self _)) },
  { intros b hb,
    exact mem_infi_sets (a - b) (mem_infi_sets (sub_pos.2 hb) (by simp [Ioi])) },
  { intros b hb,
    exact mem_infi_sets (b - a) (mem_infi_sets (sub_pos.2 hb) (by simp [Iio])) }
end

lemma order_topology_of_nhds_abs {α : Type*} [topological_space α] [linear_ordered_add_comm_group α]
  (h_nhds : ∀a:α, 𝓝 a = (⨅r>0, 𝓟 {b | |a - b| < r})) : order_topology α :=
begin
  refine ⟨eq_of_nhds_eq_nhds $ λ a, _⟩,
  rw [h_nhds],
  letI := preorder.topology α, letI : order_topology α := ⟨rfl⟩,
  exact (nhds_eq_infi_abs_sub a).symm
end

lemma linear_ordered_add_comm_group.tendsto_nhds {x : filter β} {a : α} :
  tendsto f x (𝓝 a) ↔ ∀ ε > (0 : α), ∀ᶠ b in x, |f b - a| < ε :=
by simp [nhds_eq_infi_abs_sub, abs_sub a]

lemma eventually_abs_sub_lt (a : α) {ε : α} (hε : 0 < ε) : ∀ᶠ x in 𝓝 a, |x - a| < ε :=
(nhds_eq_infi_abs_sub a).symm ▸ mem_infi_sets ε
  (mem_infi_sets hε $ by simp only [abs_sub, mem_principal_self])

@[priority 100] -- see Note [lower instance priority]
instance linear_ordered_add_comm_group.topological_add_group : topological_add_group α :=
{ continuous_add :=
    begin
      refine continuous_iff_continuous_at.2 _,
      rintro ⟨a, b⟩,
      refine linear_ordered_add_comm_group.tendsto_nhds.2 (λ ε ε0, _),
      rcases dense_or_discrete 0 ε with (⟨δ, δ0, δε⟩|⟨h₁, h₂⟩),
      { -- If there exists `δ ∈ (0, ε)`, then we choose `δ`-nhd of `a` and `(ε-δ)`-nhd of `b`
        filter_upwards [prod_mem_nhds_sets (eventually_abs_sub_lt a δ0)
          (eventually_abs_sub_lt b (sub_pos.2 δε))],
        rintros ⟨x, y⟩ ⟨hx : |x - a| < δ, hy : |y - b| < ε - δ⟩,
        rw [add_sub_comm],
        calc |x - a + (y - b)| ≤ |x - a| + |y - b| : abs_add _ _
        ... < δ + (ε - δ) : add_lt_add hx hy
        ... = ε : add_sub_cancel'_right _ _ },
      { -- Otherewise `ε`-nhd of each point `a` is `{a}`
        have hε : ∀ {x y}, abs (x - y) < ε → x = y,
        { intros x y h,
          simpa [sub_eq_zero] using h₂ _ h },
        filter_upwards [prod_mem_nhds_sets (eventually_abs_sub_lt a ε0)
          (eventually_abs_sub_lt b ε0)],
        rintros ⟨x, y⟩ ⟨hx : |x - a| < ε, hy : |y - b| < ε⟩,
        simpa [hε hx, hε hy] }
    end,
  continuous_neg := continuous_iff_continuous_at.2 $ λ a,
    linear_ordered_add_comm_group.tendsto_nhds.2 $ λ ε ε0,
      (eventually_abs_sub_lt a ε0).mono $ λ x hx, by rwa [neg_sub_neg, abs_sub] }

@[continuity]
lemma continuous_abs : continuous (abs : α → α) := continuous_id.max continuous_neg

lemma filter.tendsto.abs {f : β → α} {a : α} {l : filter β} (h : tendsto f l (𝓝 a)) :
  tendsto (λ x, |f x|) l (𝓝 (|a|)) :=
(continuous_abs.tendsto _).comp h

section

variables [topological_space β] {b : β} {a : α} {s : set β}

lemma continuous.abs (h : continuous f) : continuous (λ x, |f x|) := continuous_abs.comp h

lemma continuous_at.abs (h : continuous_at f b) : continuous_at (λ x, |f x|) b := h.abs

lemma continuous_within_at.abs (h : continuous_within_at f s b) :
  continuous_within_at (λ x, |f x|) s b := h.abs

lemma continuous_on.abs (h : continuous_on f s) : continuous_on (λ x, |f x|) s :=
λ x hx, (h x hx).abs

lemma tendsto_abs_nhds_within_zero : tendsto (abs : α → α) (𝓝[{0}ᶜ] 0) (𝓝[Ioi 0] 0) :=
(continuous_abs.tendsto' (0 : α) 0 abs_zero).inf $ tendsto_principal_principal.2 $ λ x, abs_pos.2

end

/-- In a linearly ordered additive commutative group with the order topology, if `f` tends to `C`
and `g` tends to `at_top` then `f + g` tends to `at_top`. -/
lemma filter.tendsto.add_at_top {C : α} (hf : tendsto f l (𝓝 C)) (hg : tendsto g l at_top) :
  tendsto (λ x, f x + g x) l at_top :=
begin
  nontriviality α,
  obtain ⟨C', hC'⟩ : ∃ C', C' < C := no_bot C,
  refine tendsto_at_top_add_left_of_le' _ C' _ hg,
  exact (hf.eventually (lt_mem_nhds hC')).mono (λ x, le_of_lt)
end

/-- In a linearly ordered additive commutative group with the order topology, if `f` tends to `C`
and `g` tends to `at_bot` then `f + g` tends to `at_bot`. -/
lemma filter.tendsto.add_at_bot {C : α} (hf : tendsto f l (𝓝 C)) (hg : tendsto g l at_bot) :
  tendsto (λ x, f x + g x) l at_bot :=
@filter.tendsto.add_at_top (order_dual α) _ _ _ _ _ _ _ _ hf hg

/-- In a linearly ordered additive commutative group with the order topology, if `f` tends to
`at_top` and `g` tends to `C` then `f + g` tends to `at_top`. -/
lemma filter.tendsto.at_top_add {C : α} (hf : tendsto f l at_top) (hg : tendsto g l (𝓝 C)) :
  tendsto (λ x, f x + g x) l at_top :=
by { conv in (_ + _) { rw add_comm }, exact hg.add_at_top hf }

/-- In a linearly ordered additive commutative group with the order topology, if `f` tends to
`at_bot` and `g` tends to `C` then `f + g` tends to `at_bot`. -/
lemma filter.tendsto.at_bot_add {C : α} (hf : tendsto f l at_bot) (hg : tendsto g l (𝓝 C)) :
  tendsto (λ x, f x + g x) l at_bot :=
by { conv in (_ + _) { rw add_comm }, exact hg.add_at_bot hf }

end linear_ordered_add_comm_group

section linear_ordered_field
variables [linear_ordered_field α] [topological_space α] [order_topology α]
variables {l : filter β} {f g : β → α}

/-- In a linearly ordered field with the order topology, if `f` tends to `at_top` and `g` tends to
a positive constant `C` then `f * g` tends to `at_top`. -/
lemma filter.tendsto.at_top_mul {C : α} (hC : 0 < C) (hf : tendsto f l at_top)
  (hg : tendsto g l (𝓝 C)) :
  tendsto (λ x, (f x * g x)) l at_top :=
begin
  refine tendsto_at_top_mono' _ _ (hf.at_top_mul_const (half_pos hC)),
  filter_upwards [hg.eventually (lt_mem_nhds (half_lt_self hC)),
    hf.eventually (eventually_ge_at_top 0)],
  exact λ x hg hf, mul_le_mul_of_nonneg_left hg.le hf
end

/-- In a linearly ordered field with the order topology, if `f` tends to a positive constant `C` and
`g` tends to `at_top` then `f * g` tends to `at_top`. -/
lemma filter.tendsto.mul_at_top {C : α} (hC : 0 < C) (hf : tendsto f l (𝓝 C))
  (hg : tendsto g l at_top) :
  tendsto (λ x, (f x * g x)) l at_top :=
by simpa only [mul_comm] using hg.at_top_mul hC hf

/-- In a linearly ordered field with the order topology, if `f` tends to `at_top` and `g` tends to
a negative constant `C` then `f * g` tends to `at_bot`. -/
lemma filter.tendsto.at_top_mul_neg {C : α} (hC : C < 0) (hf : tendsto f l at_top)
  (hg : tendsto g l (𝓝 C)) :
  tendsto (λ x, (f x * g x)) l at_bot :=
by simpa only [(∘), neg_mul_eq_mul_neg, neg_neg]
  using tendsto_neg_at_top_at_bot.comp (hf.at_top_mul (neg_pos.2 hC) hg.neg)

/-- In a linearly ordered field with the order topology, if `f` tends to a negative constant `C` and
`g` tends to `at_top` then `f * g` tends to `at_bot`. -/
lemma filter.tendsto.neg_mul_at_top {C : α} (hC : C < 0) (hf : tendsto f l (𝓝 C))
  (hg : tendsto g l at_top) :
  tendsto (λ x, (f x * g x)) l at_bot :=
by simpa only [mul_comm] using hg.at_top_mul_neg hC hf

/-- In a linearly ordered field with the order topology, if `f` tends to `at_bot` and `g` tends to
a positive constant `C` then `f * g` tends to `at_bot`. -/
lemma filter.tendsto.at_bot_mul {C : α} (hC : 0 < C) (hf : tendsto f l at_bot)
  (hg : tendsto g l (𝓝 C)) :
  tendsto (λ x, (f x * g x)) l at_bot :=
by simpa [(∘)]
  using tendsto_neg_at_top_at_bot.comp ((tendsto_neg_at_bot_at_top.comp hf).at_top_mul hC hg)

/-- In a linearly ordered field with the order topology, if `f` tends to `at_bot` and `g` tends to
a negative constant `C` then `f * g` tends to `at_top`. -/
lemma filter.tendsto.at_bot_mul_neg {C : α} (hC : C < 0) (hf : tendsto f l at_bot)
  (hg : tendsto g l (𝓝 C)) :
  tendsto (λ x, (f x * g x)) l at_top :=
by simpa [(∘)]
  using tendsto_neg_at_bot_at_top.comp ((tendsto_neg_at_bot_at_top.comp hf).at_top_mul_neg hC hg)

/-- In a linearly ordered field with the order topology, if `f` tends to a positive constant `C` and
`g` tends to `at_bot` then `f * g` tends to `at_bot`. -/
lemma filter.tendsto.mul_at_bot {C : α} (hC : 0 < C) (hf : tendsto f l (𝓝 C))
  (hg : tendsto g l at_bot) :
  tendsto (λ x, (f x * g x)) l at_bot :=
by simpa only [mul_comm] using hg.at_bot_mul hC hf

/-- In a linearly ordered field with the order topology, if `f` tends to a negative constant `C` and
`g` tends to `at_bot` then `f * g` tends to `at_top`. -/
lemma filter.tendsto.neg_mul_at_bot {C : α} (hC : C < 0) (hf : tendsto f l (𝓝 C))
  (hg : tendsto g l at_bot) :
  tendsto (λ x, (f x * g x)) l at_top :=
by simpa only [mul_comm] using hg.at_bot_mul_neg hC hf

/-- The function `x ↦ x⁻¹` tends to `+∞` on the right of `0`. -/
lemma tendsto_inv_zero_at_top : tendsto (λx:α, x⁻¹) (𝓝[set.Ioi (0:α)] 0) at_top :=
begin
  refine (at_top_basis' 1).tendsto_right_iff.2 (λ b hb, _),
  have hb' : 0 < b := zero_lt_one.trans_le hb,
  filter_upwards [Ioc_mem_nhds_within_Ioi ⟨le_rfl, inv_pos.2 hb'⟩],
  exact λ x hx, (le_inv hx.1 hb').1 hx.2
end

/-- The function `r ↦ r⁻¹` tends to `0` on the right as `r → +∞`. -/
lemma tendsto_inv_at_top_zero' : tendsto (λr:α, r⁻¹) at_top (𝓝[set.Ioi (0:α)] 0) :=
begin
  refine (has_basis.tendsto_iff at_top_basis ⟨λ s, mem_nhds_within_Ioi_iff_exists_Ioc_subset⟩).2 _,
  refine λ b hb, ⟨b⁻¹, trivial, λ x hx, _⟩,
  have : 0 < x := lt_of_lt_of_le (inv_pos.2 hb) hx,
  exact ⟨inv_pos.2 this, (inv_le this hb).2 hx⟩
end

lemma tendsto_inv_at_top_zero : tendsto (λr:α, r⁻¹) at_top (𝓝 0) :=
tendsto_inv_at_top_zero'.mono_right inf_le_left

lemma filter.tendsto.div_at_top [has_continuous_mul α] {f g : β → α} {l : filter β} {a : α}
  (h : tendsto f l (𝓝 a)) (hg : tendsto g l at_top) : tendsto (λ x, f x / g x) l (𝓝 0) :=
by { simp only [div_eq_mul_inv], exact mul_zero a ▸ h.mul (tendsto_inv_at_top_zero.comp hg) }

lemma filter.tendsto.inv_tendsto_at_top (h : tendsto f l at_top) : tendsto (f⁻¹) l (𝓝 0) :=
tendsto_inv_at_top_zero.comp h

lemma filter.tendsto.inv_tendsto_zero (h : tendsto f l (𝓝[set.Ioi 0] 0)) :
  tendsto (f⁻¹) l at_top :=
tendsto_inv_zero_at_top.comp h

/-- The function `x^(-n)` tends to `0` at `+∞` for any positive natural `n`.
A version for positive real powers exists as `tendsto_rpow_neg_at_top`. -/
lemma tendsto_pow_neg_at_top {n : ℕ} (hn : 1 ≤ n) : tendsto (λ x : α, x ^ (-(n:ℤ))) at_top (𝓝 0) :=
tendsto.congr (λ x, (fpow_neg x n).symm)
  (filter.tendsto.inv_tendsto_at_top (by simpa [gpow_coe_nat] using tendsto_pow_at_top hn))

lemma tendsto_fpow_at_top_zero {n : ℤ} (hn : n < 0) :
  tendsto (λ x : α, x^n) at_top (𝓝 0) :=
begin
  have : 1 ≤ -n := le_neg.mp (int.le_of_lt_add_one (hn.trans_le (neg_add_self 1).symm.le)),
  apply tendsto.congr (show ∀ x : α, x^-(-n) = x^n, by simp),
  lift -n to ℕ using le_of_lt (neg_pos.mpr hn) with N,
  exact tendsto_pow_neg_at_top (by exact_mod_cast this)
end

end linear_ordered_field

lemma preimage_neg [add_group α] : preimage (has_neg.neg : α → α) = image (has_neg.neg : α → α) :=
(image_eq_preimage_of_inverse neg_neg neg_neg).symm

lemma filter.map_neg [add_group α] : map (has_neg.neg : α → α) = comap (has_neg.neg : α → α) :=
funext $ assume f, map_eq_comap_of_inverse (funext neg_neg) (funext neg_neg)

section order_topology

variables [topological_space α] [topological_space β]
  [linear_order α] [linear_order β] [order_topology α] [order_topology β]

lemma is_lub.frequently_mem {a : α} {s : set α} (ha : is_lub s a) (hs : s.nonempty) :
  ∃ᶠ x in 𝓝[Iic a] a, x ∈ s :=
begin
  rcases hs with ⟨a', ha'⟩,
  intro h,
  rcases (ha.1 ha').eq_or_lt with (rfl|ha'a),
  { exact h.self_of_nhds_within le_rfl ha' },
  { rcases (mem_nhds_within_Iic_iff_exists_Ioc_subset' ha'a).1 h
      with ⟨b, hba, hb⟩,
    rcases ha.exists_between hba with ⟨b', hb's, hb'⟩,
    exact hb hb' hb's },
end

lemma is_lub.frequently_nhds_mem {a : α} {s : set α} (ha : is_lub s a) (hs : s.nonempty) :
  ∃ᶠ x in 𝓝 a, x ∈ s :=
(ha.frequently_mem hs).filter_mono inf_le_left

lemma is_glb.frequently_mem {a : α} {s : set α} (ha : is_glb s a) (hs : s.nonempty) :
  ∃ᶠ x in 𝓝[Ici a] a, x ∈ s :=
@is_lub.frequently_mem (order_dual α) _ _ _ _ _ ha hs

lemma is_glb.frequently_nhds_mem {a : α} {s : set α} (ha : is_glb s a) (hs : s.nonempty) :
  ∃ᶠ x in 𝓝 a, x ∈ s :=
(ha.frequently_mem hs).filter_mono inf_le_left

lemma is_lub.mem_closure {a : α} {s : set α} (ha : is_lub s a) (hs : s.nonempty) :
  a ∈ closure s :=
(ha.frequently_nhds_mem hs).mem_closure

lemma is_glb.mem_closure {a : α} {s : set α} (ha : is_glb s a) (hs : s.nonempty) :
  a ∈ closure s :=
(ha.frequently_nhds_mem hs).mem_closure

lemma is_lub.nhds_within_ne_bot {a : α} {s : set α} (ha : is_lub s a) (hs : s.nonempty) :
  ne_bot (𝓝[s] a) :=
mem_closure_iff_nhds_within_ne_bot.1 (ha.mem_closure hs)

lemma is_glb.nhds_within_ne_bot : ∀ {a : α} {s : set α}, is_glb s a → s.nonempty →
  ne_bot (𝓝[s] a) :=
@is_lub.nhds_within_ne_bot (order_dual α) _ _ _

lemma is_lub_of_mem_nhds {s : set α} {a : α} {f : filter α}
  (hsa : a ∈ upper_bounds s) (hsf : s ∈ f) [ne_bot (f ⊓ 𝓝 a)] : is_lub s a :=
⟨hsa, assume b hb,
  not_lt.1 $ assume hba,
  have s ∩ {a | b < a} ∈ f ⊓ 𝓝 a,
    from inter_mem_inf_sets hsf (mem_nhds_sets (is_open_lt' _) hba),
  let ⟨x, ⟨hxs, hxb⟩⟩ := nonempty_of_mem_sets this in
  have b < b, from lt_of_lt_of_le hxb $ hb hxs,
  lt_irrefl b this⟩

lemma is_glb_of_mem_nhds : ∀ {s : set α} {a : α} {f : filter α},
  a ∈ lower_bounds s → s ∈ f → ne_bot (f ⊓ 𝓝 a) → is_glb s a :=
@is_lub_of_mem_nhds (order_dual α) _ _ _

lemma is_lub.mem_upper_bounds_of_tendsto [preorder γ] [topological_space γ]
  [order_closed_topology γ] {f : α → γ} {s : set α} {a : α} {b : γ}
  (hf : ∀x∈s, ∀y∈s, x ≤ y → f x ≤ f y) (ha : is_lub s a)
  (hb : tendsto f (𝓝[s] a) (𝓝 b)) : b ∈ upper_bounds (f '' s) :=
begin
  rintro _ ⟨x, hx, rfl⟩,
  replace ha := ha.inter_Ici_of_mem hx,
  haveI := ha.nhds_within_ne_bot ⟨x, hx, le_rfl⟩,
  refine ge_of_tendsto (hb.mono_left (nhds_within_mono _ (inter_subset_left s (Ici x)))) _,
  exact mem_sets_of_superset self_mem_nhds_within (λ y hy, hf _ hx _ hy.1 hy.2)
end

lemma is_lub.is_lub_of_tendsto [preorder γ] [topological_space γ]
  [order_closed_topology γ] {f : α → γ} {s : set α} {a : α} {b : γ}
  (hf : ∀x∈s, ∀y∈s, x ≤ y → f x ≤ f y) (ha : is_lub s a) (hs : s.nonempty)
  (hb : tendsto f (𝓝[s] a) (𝓝 b)) : is_lub (f '' s) b :=
begin
  haveI := ha.nhds_within_ne_bot hs,
  exact ⟨ha.mem_upper_bounds_of_tendsto hf hb, λ b' hb', le_of_tendsto hb
    (mem_sets_of_superset self_mem_nhds_within $ λ x hx, hb' $ mem_image_of_mem _ hx)⟩
end

lemma is_glb.mem_lower_bounds_of_tendsto [preorder γ] [topological_space γ]
  [order_closed_topology γ] {f : α → γ} {s : set α} {a : α} {b : γ}
  (hf : ∀x∈s, ∀y∈s, x ≤ y → f x ≤ f y) (ha : is_glb s a)
  (hb : tendsto f (𝓝[s] a) (𝓝 b)) : b ∈ lower_bounds (f '' s) :=
@is_lub.mem_upper_bounds_of_tendsto (order_dual α) (order_dual γ) _ _ _ _ _ _ _ _ _ _
  (λ x hx y hy, hf y hy x hx) ha hb

lemma is_glb.is_glb_of_tendsto [preorder γ] [topological_space γ]
  [order_closed_topology γ] {f : α → γ} {s : set α} {a : α} {b : γ}
  (hf : ∀x∈s, ∀y∈s, x ≤ y → f x ≤ f y) : is_glb s a → s.nonempty →
  tendsto f (𝓝[s] a) (𝓝 b) → is_glb (f '' s) b :=
@is_lub.is_lub_of_tendsto (order_dual α) (order_dual γ) _ _ _ _ _ _ f s a b
  (λ x hx y hy, hf y hy x hx)

lemma is_lub.mem_lower_bounds_of_tendsto [preorder γ] [topological_space γ]
  [order_closed_topology γ] {f : α → γ} {s : set α} {a : α} {b : γ}
  (hf : ∀x∈s, ∀y∈s, x ≤ y → f y ≤ f x) (ha : is_lub s a)
  (hb : tendsto f (𝓝[s] a) (𝓝 b)) : b ∈ lower_bounds (f '' s) :=
@is_lub.mem_upper_bounds_of_tendsto α (order_dual γ) _ _ _ _ _ _ _ _ _ _ hf ha hb

lemma is_lub.is_glb_of_tendsto [preorder γ] [topological_space γ]
  [order_closed_topology γ] : ∀ {f : α → γ} {s : set α} {a : α} {b : γ},
  (∀x∈s, ∀y∈s, x ≤ y → f y ≤ f x) → is_lub s a → s.nonempty →
  tendsto f (𝓝[s] a) (𝓝 b) → is_glb (f '' s) b :=
@is_lub.is_lub_of_tendsto α (order_dual γ) _ _ _ _ _ _

lemma is_glb.mem_upper_bounds_of_tendsto [preorder γ] [topological_space γ]
  [order_closed_topology γ] {f : α → γ} {s : set α} {a : α} {b : γ}
  (hf : ∀x∈s, ∀y∈s, x ≤ y → f y ≤ f x) (ha : is_glb s a)
  (hb : tendsto f (𝓝[s] a) (𝓝 b)) : b ∈ upper_bounds (f '' s) :=
@is_glb.mem_lower_bounds_of_tendsto α (order_dual γ) _ _ _ _ _ _ _ _ _ _ hf ha hb

lemma is_glb.is_lub_of_tendsto [preorder γ] [topological_space γ]
  [order_closed_topology γ] : ∀ {f : α → γ} {s : set α} {a : α} {b : γ},
  (∀x∈s, ∀y∈s, x ≤ y → f y ≤ f x) → is_glb s a → s.nonempty →
  tendsto f (𝓝[s] a) (𝓝 b) → is_lub (f '' s) b :=
@is_glb.is_glb_of_tendsto α (order_dual γ) _ _ _ _ _ _

lemma is_lub.mem_of_is_closed {a : α} {s : set α} (ha : is_lub s a) (hs : s.nonempty)
  (sc : is_closed s) : a ∈ s :=
sc.closure_subset $ ha.mem_closure hs

alias is_lub.mem_of_is_closed ← is_closed.is_lub_mem

lemma is_glb.mem_of_is_closed {a : α} {s : set α} (ha : is_glb s a) (hs : s.nonempty)
  (sc : is_closed s) : a ∈ s :=
sc.closure_subset $ ha.mem_closure hs

alias is_glb.mem_of_is_closed ← is_closed.is_glb_mem

/-- A compact set is bounded below -/
lemma is_compact.bdd_below {α : Type u} [topological_space α] [linear_order α]
  [order_closed_topology α] [nonempty α] {s : set α} (hs : is_compact s) : bdd_below s :=
begin
  by_contra H,
  rcases hs.elim_finite_subcover_image (λ x (_ : x ∈ s), @is_open_Ioi _ _ _ _ x) _
    with ⟨t, st, ft, ht⟩,
  { refine H (ft.bdd_below.imp $ λ C hC y hy, _),
    rcases mem_bUnion_iff.1 (ht hy) with ⟨x, hx, xy⟩,
    exact le_trans (hC hx) (le_of_lt xy) },
  { refine λ x hx, mem_bUnion_iff.2 (not_imp_comm.1 _ H),
    exact λ h, ⟨x, λ y hy, le_of_not_lt (h.imp $ λ ys, ⟨_, hy, ys⟩)⟩ }
end

/-- A compact set is bounded above -/
lemma is_compact.bdd_above {α : Type u} [topological_space α] [linear_order α]
  [order_topology α] : Π [nonempty α] {s : set α}, is_compact s → bdd_above s :=
@is_compact.bdd_below (order_dual α) _ _ _

end order_topology

section linear_order

variables [topological_space α] [linear_order α] [order_topology α] [densely_ordered α]

/-- The closure of the interval `(a, +∞)` is the closed interval `[a, +∞)`, unless `a` is a top
element. -/
lemma closure_Ioi' {a b : α} (hab : a < b) :
  closure (Ioi a) = Ici a :=
begin
  apply subset.antisymm,
  { exact closure_minimal Ioi_subset_Ici_self is_closed_Ici },
  { rw [← diff_subset_closure_iff, Ici_diff_Ioi_same, singleton_subset_iff],
    exact is_glb_Ioi.mem_closure ⟨_, hab⟩ }
end

/-- The closure of the interval `(a, +∞)` is the closed interval `[a, +∞)`. -/
@[simp] lemma closure_Ioi (a : α) [no_top_order α] :
  closure (Ioi a) = Ici a :=
let ⟨b, hb⟩ := no_top a in closure_Ioi' hb

/-- The closure of the interval `(-∞, a)` is the closed interval `(-∞, a]`, unless `a` is a bottom
element. -/
lemma closure_Iio' {a b : α} (hab : b < a) :
  closure (Iio a) = Iic a :=
@closure_Ioi' (order_dual α) _ _ _ _ _ _ hab

/-- The closure of the interval `(-∞, a)` is the interval `(-∞, a]`. -/
@[simp] lemma closure_Iio (a : α) [no_bot_order α] :
  closure (Iio a) = Iic a :=
let ⟨b, hb⟩ := no_bot a in closure_Iio' hb

/-- The closure of the open interval `(a, b)` is the closed interval `[a, b]`. -/
@[simp] lemma closure_Ioo {a b : α} (hab : a < b) :
  closure (Ioo a b) = Icc a b :=
begin
  apply subset.antisymm,
  { exact closure_minimal Ioo_subset_Icc_self is_closed_Icc },
  { rw [← diff_subset_closure_iff, Icc_diff_Ioo_same hab.le],
    have hab' : (Ioo a b).nonempty, from nonempty_Ioo.2 hab,
    simp only [insert_subset, singleton_subset_iff],
    exact ⟨(is_glb_Ioo hab).mem_closure hab', (is_lub_Ioo hab).mem_closure hab'⟩ }
end

/-- The closure of the interval `(a, b]` is the closed interval `[a, b]`. -/
@[simp] lemma closure_Ioc {a b : α} (hab : a < b) :
  closure (Ioc a b) = Icc a b :=
begin
  apply subset.antisymm,
  { exact closure_minimal Ioc_subset_Icc_self is_closed_Icc },
  { apply subset.trans _ (closure_mono Ioo_subset_Ioc_self),
    rw closure_Ioo hab }
end

/-- The closure of the interval `[a, b)` is the closed interval `[a, b]`. -/
@[simp] lemma closure_Ico {a b : α} (hab : a < b) :
  closure (Ico a b) = Icc a b :=
begin
  apply subset.antisymm,
  { exact closure_minimal Ico_subset_Icc_self is_closed_Icc },
  { apply subset.trans _ (closure_mono Ioo_subset_Ico_self),
    rw closure_Ioo hab }
end

@[simp] lemma interior_Ici [no_bot_order α] {a : α} : interior (Ici a) = Ioi a :=
by rw [← compl_Iio, interior_compl, closure_Iio, compl_Iic]

@[simp] lemma interior_Iic [no_top_order α] {a : α} : interior (Iic a) = Iio a :=
by rw [← compl_Ioi, interior_compl, closure_Ioi, compl_Ici]

@[simp] lemma interior_Icc [no_bot_order α] [no_top_order α] {a b : α}:
  interior (Icc a b) = Ioo a b :=
by rw [← Ici_inter_Iic, interior_inter, interior_Ici, interior_Iic, Ioi_inter_Iio]

@[simp] lemma interior_Ico [no_bot_order α] {a b : α} : interior (Ico a b) = Ioo a b :=
by rw [← Ici_inter_Iio, interior_inter, interior_Ici, interior_Iio, Ioi_inter_Iio]

@[simp] lemma interior_Ioc [no_top_order α] {a b : α} : interior (Ioc a b) = Ioo a b :=
by rw [← Ioi_inter_Iic, interior_inter, interior_Ioi, interior_Iic, Ioi_inter_Iio]

@[simp] lemma frontier_Ici [no_bot_order α] {a : α} : frontier (Ici a) = {a} :=
by simp [frontier]

@[simp] lemma frontier_Iic [no_top_order α] {a : α} : frontier (Iic a) = {a} :=
by simp [frontier]

@[simp] lemma frontier_Ioi [no_top_order α] {a : α} : frontier (Ioi a) = {a} :=
by simp [frontier]

@[simp] lemma frontier_Iio [no_bot_order α] {a : α} : frontier (Iio a) = {a} :=
by simp [frontier]

@[simp] lemma frontier_Icc [no_bot_order α] [no_top_order α] {a b : α} (h : a < b) :
  frontier (Icc a b) = {a, b} :=
by simp [frontier, le_of_lt h, Icc_diff_Ioo_same]

@[simp] lemma frontier_Ioo {a b : α} (h : a < b) : frontier (Ioo a b) = {a, b} :=
by simp [frontier, h, le_of_lt h, Icc_diff_Ioo_same]

@[simp] lemma frontier_Ico [no_bot_order α] {a b : α} (h : a < b) : frontier (Ico a b) = {a, b} :=
by simp [frontier, h, le_of_lt h, Icc_diff_Ioo_same]

@[simp] lemma frontier_Ioc [no_top_order α] {a b : α} (h : a < b) : frontier (Ioc a b) = {a, b} :=
by simp [frontier, h, le_of_lt h, Icc_diff_Ioo_same]

lemma nhds_within_Ioi_ne_bot' {a b c : α} (H₁ : a < c) (H₂ : a ≤ b) :
  ne_bot (𝓝[Ioi a] b) :=
mem_closure_iff_nhds_within_ne_bot.1 $ by { rw [closure_Ioi' H₁], exact H₂ }

lemma nhds_within_Ioi_ne_bot [no_top_order α] {a b : α} (H : a ≤ b) :
  ne_bot (𝓝[Ioi a] b) :=
let ⟨c, hc⟩ := no_top a in nhds_within_Ioi_ne_bot' hc H

lemma nhds_within_Ioi_self_ne_bot' {a b : α} (H : a < b) :
  ne_bot (𝓝[Ioi a] a) :=
nhds_within_Ioi_ne_bot' H (le_refl a)

@[instance]
lemma nhds_within_Ioi_self_ne_bot [no_top_order α] (a : α) :
  ne_bot (𝓝[Ioi a] a) :=
nhds_within_Ioi_ne_bot (le_refl a)

lemma nhds_within_Iio_ne_bot' {a b c : α} (H₁ : a < c) (H₂ : b ≤ c) :
  ne_bot (𝓝[Iio c] b) :=
mem_closure_iff_nhds_within_ne_bot.1 $ by { rw [closure_Iio' H₁], exact H₂ }

lemma nhds_within_Iio_ne_bot [no_bot_order α] {a b : α} (H : a ≤ b) :
  ne_bot (𝓝[Iio b] a) :=
let ⟨c, hc⟩ := no_bot b in nhds_within_Iio_ne_bot' hc H

lemma nhds_within_Iio_self_ne_bot' {a b : α} (H : a < b) :
  ne_bot (𝓝[Iio b] b) :=
nhds_within_Iio_ne_bot' H (le_refl b)

@[instance]
lemma nhds_within_Iio_self_ne_bot [no_bot_order α] (a : α) :
  ne_bot (𝓝[Iio a] a) :=
nhds_within_Iio_ne_bot (le_refl a)

lemma right_nhds_within_Ico_ne_bot {a b : α} (H : a < b) : ne_bot (𝓝[Ico a b] b) :=
(is_lub_Ico H).nhds_within_ne_bot (nonempty_Ico.2 H)

lemma left_nhds_within_Ioc_ne_bot {a b : α} (H : a < b) : ne_bot (𝓝[Ioc a b] a) :=
(is_glb_Ioc H).nhds_within_ne_bot (nonempty_Ioc.2 H)

lemma left_nhds_within_Ioo_ne_bot {a b : α} (H : a < b) : ne_bot (𝓝[Ioo a b] a) :=
(is_glb_Ioo H).nhds_within_ne_bot (nonempty_Ioo.2 H)

lemma right_nhds_within_Ioo_ne_bot {a b : α} (H : a < b) : ne_bot (𝓝[Ioo a b] b) :=
(is_lub_Ioo H).nhds_within_ne_bot (nonempty_Ioo.2 H)

end linear_order

section linear_order

variables [topological_space α] [linear_order α] [order_topology α] [densely_ordered α]
  {a b : α} {s : set α}

lemma comap_coe_nhds_within_Iio_of_Ioo_subset (hb : s ⊆ Iio b)
  (hs : s.nonempty → ∃ a < b, Ioo a b ⊆ s) :
  comap (coe : s → α) (𝓝[Iio b] b) = at_top :=
begin
  nontriviality,
  haveI : nonempty s := nontrivial_iff_nonempty.1 ‹_›,
  rcases hs (nonempty_subtype.1 ‹_›) with ⟨a, h, hs⟩,
  ext u, split,
  { rintros ⟨t, ht, hts⟩,
    obtain ⟨x, ⟨hxa : a ≤ x, hxb : x < b⟩, hxt : Ioo x b ⊆ t⟩ :=
      (mem_nhds_within_Iio_iff_exists_mem_Ico_Ioo_subset h).mp ht,
    obtain ⟨y, hxy, hyb⟩ := exists_between hxb,
    refine mem_sets_of_superset (mem_at_top ⟨y, hs ⟨hxa.trans_lt hxy, hyb⟩⟩) _,
    rintros ⟨z, hzs⟩ (hyz : y ≤ z),
    refine hts (hxt ⟨hxy.trans_le _, hb _⟩); assumption },
  { intros hu,
    obtain ⟨x : s, hx : ∀ z, x ≤ z → z ∈ u⟩ := mem_at_top_sets.1 hu,
    exact ⟨Ioo x b, Ioo_mem_nhds_within_Iio (right_mem_Ioc.2 $ hb x.2), λ z hz, hx _ hz.1.le⟩ }
end

lemma comap_coe_nhds_within_Ioi_of_Ioo_subset (ha : s ⊆ Ioi a)
  (hs : s.nonempty → ∃ b > a, Ioo a b ⊆ s) :
  comap (coe : s → α) (𝓝[Ioi a] a) = at_bot :=
begin
  refine @comap_coe_nhds_within_Iio_of_Ioo_subset (order_dual α) _ _ _ _ _ _ ha (λ h, _),
  rcases hs h with ⟨b, hab, h⟩,
  use [b, hab],
  rwa dual_Ioo
end

lemma map_coe_at_top_of_Ioo_subset (hb : s ⊆ Iio b)
  (hs : ∀ a' < b, ∃ a < b, Ioo a b ⊆ s) :
  map (coe : s → α) at_top = 𝓝[Iio b] b :=
begin
  rcases eq_empty_or_nonempty (Iio b) with (hb'|⟨a, ha⟩),
  { rw [filter_eq_bot_of_not_nonempty at_top, map_bot, hb', nhds_within_empty],
    exact λ ⟨⟨x, hx⟩⟩, not_nonempty_iff_eq_empty.2 hb' ⟨x, hb hx⟩ },
  { rw [← comap_coe_nhds_within_Iio_of_Ioo_subset hb (λ _, hs a ha), map_comap_of_mem],
    rw subtype.range_coe,
    exact (mem_nhds_within_Iio_iff_exists_Ioo_subset' ha).2 (hs a ha) },
end

lemma map_coe_at_bot_of_Ioo_subset (ha : s ⊆ Ioi a)
  (hs : ∀ b' > a, ∃ b > a, Ioo a b ⊆ s) :
  map (coe : s → α) at_bot = (𝓝[Ioi a] a) :=
begin
  refine @map_coe_at_top_of_Ioo_subset (order_dual α) _ _ _ _ a s ha (λ b' hb', _),
  rcases hs b' hb' with ⟨b, hab, hbs⟩,
  use [b, hab],
  rwa dual_Ioo
end

/-- The `at_top` filter for an open interval `Ioo a b` comes from the left-neighbourhoods filter at
the right endpoint in the ambient order. -/
lemma comap_coe_Ioo_nhds_within_Iio (a b : α) :
  comap (coe : Ioo a b → α) (𝓝[Iio b] b) = at_top :=
comap_coe_nhds_within_Iio_of_Ioo_subset Ioo_subset_Iio_self $
  λ h, ⟨a, nonempty_Ioo.1 h, subset.refl _⟩

/-- The `at_bot` filter for an open interval `Ioo a b` comes from the right-neighbourhoods filter at
the left endpoint in the ambient order. -/
lemma comap_coe_Ioo_nhds_within_Ioi (a b : α) :
  comap (coe : Ioo a b → α) (𝓝[Ioi a] a) = at_bot :=
comap_coe_nhds_within_Ioi_of_Ioo_subset Ioo_subset_Ioi_self $
  λ h, ⟨b, nonempty_Ioo.1 h, subset.refl _⟩

lemma comap_coe_Ioi_nhds_within_Ioi (a : α) : comap (coe : Ioi a → α) (𝓝[Ioi a] a) = at_bot :=
comap_coe_nhds_within_Ioi_of_Ioo_subset (subset.refl _) $
  λ ⟨x, hx⟩, ⟨x, hx, Ioo_subset_Ioi_self⟩

lemma comap_coe_Iio_nhds_within_Iio (a : α) :
  comap (coe : Iio a → α) (𝓝[Iio a] a) = at_top :=
@comap_coe_Ioi_nhds_within_Ioi (order_dual α) _ _ _ _ a

@[simp] lemma map_coe_Ioo_at_top {a b : α} (h : a < b) :
  map (coe : Ioo a b → α) at_top = 𝓝[Iio b] b :=
map_coe_at_top_of_Ioo_subset Ioo_subset_Iio_self $ λ _ _, ⟨_, h, subset.refl _⟩

@[simp] lemma map_coe_Ioo_at_bot {a b : α} (h : a < b) :
  map (coe : Ioo a b → α) at_bot = 𝓝[Ioi a] a :=
map_coe_at_bot_of_Ioo_subset Ioo_subset_Ioi_self $ λ _ _, ⟨_, h, subset.refl _⟩

@[simp] lemma map_coe_Ioi_at_bot (a : α) :
  map (coe : Ioi a → α) at_bot = 𝓝[Ioi a] a :=
map_coe_at_bot_of_Ioo_subset (subset.refl _) $ λ b hb, ⟨b, hb, Ioo_subset_Ioi_self⟩

@[simp] lemma map_coe_Iio_at_top (a : α) :
  map (coe : Iio a → α) at_top = 𝓝[Iio a] a :=
@map_coe_Ioi_at_bot (order_dual α) _ _ _ _ _

variables {l : filter β} {f : α → β}

@[simp] lemma tendsto_comp_coe_Ioo_at_top (h : a < b) :
  tendsto (λ x : Ioo a b, f x) at_top l ↔ tendsto f (𝓝[Iio b] b) l :=
by rw [← map_coe_Ioo_at_top h, tendsto_map'_iff]

@[simp] lemma tendsto_comp_coe_Ioo_at_bot (h : a < b) :
  tendsto (λ x : Ioo a b, f x) at_bot l ↔ tendsto f (𝓝[Ioi a] a) l :=
by rw [← map_coe_Ioo_at_bot h, tendsto_map'_iff]

@[simp] lemma tendsto_comp_coe_Ioi_at_bot :
  tendsto (λ x : Ioi a, f x) at_bot l ↔ tendsto f (𝓝[Ioi a] a) l :=
by rw [← map_coe_Ioi_at_bot, tendsto_map'_iff]

@[simp] lemma tendsto_comp_coe_Iio_at_top :
  tendsto (λ x : Iio a, f x) at_top l ↔ tendsto f (𝓝[Iio a] a) l :=
by rw [← map_coe_Iio_at_top, tendsto_map'_iff]

@[simp] lemma tendsto_Ioo_at_top {f : β → Ioo a b} :
  tendsto f l at_top ↔ tendsto (λ x, (f x : α)) l (𝓝[Iio b] b) :=
by rw [← comap_coe_Ioo_nhds_within_Iio, tendsto_comap_iff]

@[simp] lemma tendsto_Ioo_at_bot {f : β → Ioo a b} :
  tendsto f l at_bot ↔ tendsto (λ x, (f x : α)) l (𝓝[Ioi a] a) :=
by rw [← comap_coe_Ioo_nhds_within_Ioi, tendsto_comap_iff]

@[simp] lemma tendsto_Ioi_at_bot {f : β → Ioi a} :
  tendsto f l at_bot ↔ tendsto (λ x, (f x : α)) l (𝓝[Ioi a] a) :=
by rw [← comap_coe_Ioi_nhds_within_Ioi, tendsto_comap_iff]

@[simp] lemma tendsto_Iio_at_top {f : β → Iio a} :
  tendsto f l at_top ↔ tendsto (λ x, (f x : α)) l (𝓝[Iio a] a) :=
by rw [← comap_coe_Iio_nhds_within_Iio, tendsto_comap_iff]

end linear_order

section complete_linear_order

variables [complete_linear_order α] [topological_space α] [order_topology α]
  [complete_linear_order β] [topological_space β] [order_topology β] [nonempty γ]

lemma Sup_mem_closure {α : Type u} [topological_space α] [complete_linear_order α]
  [order_topology α] {s : set α} (hs : s.nonempty) :
  Sup s ∈ closure s :=
(is_lub_Sup s).mem_closure hs

lemma Inf_mem_closure {α : Type u} [topological_space α] [complete_linear_order α]
  [order_topology α] {s : set α} (hs : s.nonempty) :
  Inf s ∈ closure s :=
(is_glb_Inf s).mem_closure hs

lemma is_closed.Sup_mem {α : Type u} [topological_space α] [complete_linear_order α]
  [order_topology α] {s : set α} (hs : s.nonempty) (hc : is_closed s) :
  Sup s ∈ s :=
(is_lub_Sup s).mem_of_is_closed hs hc

lemma is_closed.Inf_mem {α : Type u} [topological_space α] [complete_linear_order α]
  [order_topology α] {s : set α} (hs : s.nonempty) (hc : is_closed s) :
  Inf s ∈ s :=
(is_glb_Inf s).mem_of_is_closed hs hc

/-- A monotone function continuous at the supremum of a nonempty set sends this supremum to
the supremum of the image of this set. -/
lemma map_Sup_of_continuous_at_of_monotone' {f : α → β} {s : set α} (Cf : continuous_at f (Sup s))
  (Mf : monotone f) (hs : s.nonempty) :
  f (Sup s) = Sup (f '' s) :=
--This is a particular case of the more general is_lub.is_lub_of_tendsto
((is_lub_Sup _).is_lub_of_tendsto (λ x hx y hy xy, Mf xy) hs $
  Cf.mono_left inf_le_left).Sup_eq.symm

/-- A monotone function `s` sending `bot` to `bot` and continuous at the supremum of a set sends
this supremum to the supremum of the image of this set. -/
lemma map_Sup_of_continuous_at_of_monotone {f : α → β} {s : set α} (Cf : continuous_at f (Sup s))
  (Mf : monotone f) (fbot : f ⊥ = ⊥) :
  f (Sup s) = Sup (f '' s) :=
begin
  cases s.eq_empty_or_nonempty with h h,
  { simp [h, fbot] },
  { exact map_Sup_of_continuous_at_of_monotone' Cf Mf h }
end

/-- A monotone function continuous at the indexed supremum over a nonempty `Sort` sends this indexed
supremum to the indexed supremum of the composition. -/
lemma map_supr_of_continuous_at_of_monotone' {ι : Sort*} [nonempty ι] {f : α → β} {g : ι → α}
  (Cf : continuous_at f (supr g)) (Mf : monotone f) :
  f (⨆ i, g i) = ⨆ i, f (g i) :=
by rw [supr, map_Sup_of_continuous_at_of_monotone' Cf Mf (range_nonempty g), ← range_comp, supr]

/-- If a monotone function sending `bot` to `bot` is continuous at the indexed supremum over
a `Sort`, then it sends this indexed supremum to the indexed supremum of the composition. -/
lemma map_supr_of_continuous_at_of_monotone {ι : Sort*} {f : α → β} {g : ι → α}
  (Cf : continuous_at f (supr g)) (Mf : monotone f) (fbot : f ⊥ = ⊥) :
  f (⨆ i, g i) = ⨆ i, f (g i) :=
by rw [supr, map_Sup_of_continuous_at_of_monotone Cf Mf fbot, ← range_comp, supr]

/-- A monotone function continuous at the infimum of a nonempty set sends this infimum to
the infimum of the image of this set. -/
lemma map_Inf_of_continuous_at_of_monotone' {f : α → β} {s : set α} (Cf : continuous_at f (Inf s))
  (Mf : monotone f) (hs : s.nonempty) :
  f (Inf s) = Inf (f '' s) :=
@map_Sup_of_continuous_at_of_monotone' (order_dual α) (order_dual β) _ _ _ _ _ _ f s Cf
  Mf.order_dual hs

/-- A monotone function `s` sending `top` to `top` and continuous at the infimum of a set sends
this infimum to the infimum of the image of this set. -/
lemma map_Inf_of_continuous_at_of_monotone {f : α → β} {s : set α} (Cf : continuous_at f (Inf s))
  (Mf : monotone f) (ftop : f ⊤ = ⊤) :
  f (Inf s) = Inf (f '' s) :=
@map_Sup_of_continuous_at_of_monotone (order_dual α) (order_dual β) _ _ _ _ _ _ f s Cf
  Mf.order_dual ftop

/-- A monotone function continuous at the indexed infimum over a nonempty `Sort` sends this indexed
infimum to the indexed infimum of the composition. -/
lemma map_infi_of_continuous_at_of_monotone' {ι : Sort*} [nonempty ι] {f : α → β} {g : ι → α}
  (Cf : continuous_at f (infi g)) (Mf : monotone f) :
  f (⨅ i, g i) = ⨅ i, f (g i) :=
@map_supr_of_continuous_at_of_monotone' (order_dual α) (order_dual β) _ _ _ _ _ _ ι _ f g Cf
  Mf.order_dual

/-- If a monotone function sending `top` to `top` is continuous at the indexed infimum over
a `Sort`, then it sends this indexed infimum to the indexed infimum of the composition. -/
lemma map_infi_of_continuous_at_of_monotone {ι : Sort*} {f : α → β} {g : ι → α}
  (Cf : continuous_at f (infi g)) (Mf : monotone f) (ftop : f ⊤ = ⊤) :
  f (infi g) = infi (f ∘ g) :=
@map_supr_of_continuous_at_of_monotone (order_dual α) (order_dual β) _ _ _ _ _ _ ι f g Cf
  Mf.order_dual ftop

end complete_linear_order

section conditionally_complete_linear_order

variables [conditionally_complete_linear_order α] [topological_space α] [order_topology α]
  [conditionally_complete_linear_order β] [topological_space β] [order_topology β] [nonempty γ]

lemma cSup_mem_closure {s : set α} (hs : s.nonempty) (B : bdd_above s) : Sup s ∈ closure s :=
(is_lub_cSup hs B).mem_closure hs

lemma cInf_mem_closure {s : set α} (hs : s.nonempty) (B : bdd_below s) : Inf s ∈ closure s :=
(is_glb_cInf hs B).mem_closure hs

lemma is_closed.cSup_mem {s : set α} (hc : is_closed s) (hs : s.nonempty) (B : bdd_above s) :
  Sup s ∈ s :=
(is_lub_cSup hs B).mem_of_is_closed hs hc

lemma is_closed.cInf_mem {s : set α} (hc : is_closed s) (hs : s.nonempty) (B : bdd_below s) :
  Inf s ∈ s :=
(is_glb_cInf hs B).mem_of_is_closed hs hc

/-- If a monotone function is continuous at the supremum of a nonempty bounded above set `s`,
then it sends this supremum to the supremum of the image of `s`. -/
lemma map_cSup_of_continuous_at_of_monotone {f : α → β} {s : set α} (Cf : continuous_at f (Sup s))
  (Mf : monotone f) (ne : s.nonempty) (H : bdd_above s) :
  f (Sup s) = Sup (f '' s) :=
begin
  refine ((is_lub_cSup (ne.image f) (Mf.map_bdd_above H)).unique _).symm,
  refine (is_lub_cSup ne H).is_lub_of_tendsto (λx hx y hy xy, Mf xy)  ne _,
  exact Cf.mono_left inf_le_left
end

/-- If a monotone function is continuous at the indexed supremum of a bounded function on
a nonempty `Sort`, then it sends this supremum to the supremum of the composition. -/
lemma map_csupr_of_continuous_at_of_monotone {f : α → β} {g : γ → α}
  (Cf : continuous_at f (⨆ i, g i)) (Mf : monotone f) (H : bdd_above (range g)) :
  f (⨆ i, g i) = ⨆ i, f (g i) :=
by rw [supr, map_cSup_of_continuous_at_of_monotone Cf Mf (range_nonempty _) H, ← range_comp, supr]

/-- If a monotone function is continuous at the infimum of a nonempty bounded below set `s`,
then it sends this infimum to the infimum of the image of `s`. -/
lemma map_cInf_of_continuous_at_of_monotone {f : α → β} {s : set α} (Cf : continuous_at f (Inf s))
  (Mf : monotone f) (ne : s.nonempty) (H : bdd_below s) :
  f (Inf s) = Inf (f '' s) :=
@map_cSup_of_continuous_at_of_monotone (order_dual α) (order_dual β) _ _ _ _ _ _ f s Cf
  Mf.order_dual ne H

/-- A continuous monotone function sends indexed infimum to indexed infimum in conditionally
complete linear order, under a boundedness assumption. -/
lemma map_cinfi_of_continuous_at_of_monotone {f : α → β} {g : γ → α}
  (Cf : continuous_at f (⨅ i, g i)) (Mf : monotone f) (H : bdd_below (range g)) :
  f (⨅ i, g i) = ⨅ i, f (g i) :=
@map_csupr_of_continuous_at_of_monotone (order_dual α) (order_dual β) _ _ _ _ _ _ _ _ _ _
  Cf Mf.order_dual H

/-- A bounded connected subset of a conditionally complete linear order includes the open interval
`(Inf s, Sup s)`. -/
lemma is_connected.Ioo_cInf_cSup_subset {s : set α} (hs : is_connected s) (hb : bdd_below s)
  (ha : bdd_above s) :
  Ioo (Inf s) (Sup s) ⊆ s :=
λ x hx, let ⟨y, ys, hy⟩ := (is_glb_lt_iff (is_glb_cInf hs.nonempty hb)).1 hx.1 in
let ⟨z, zs, hz⟩ := (lt_is_lub_iff (is_lub_cSup hs.nonempty ha)).1 hx.2 in
hs.Icc_subset ys zs ⟨le_of_lt hy, le_of_lt hz⟩

lemma eq_Icc_cInf_cSup_of_connected_bdd_closed {s : set α} (hc : is_connected s) (hb : bdd_below s)
  (ha : bdd_above s) (hcl : is_closed s) :
  s = Icc (Inf s) (Sup s) :=
subset.antisymm (subset_Icc_cInf_cSup hb ha) $
  hc.Icc_subset (hcl.cInf_mem hc.nonempty hb) (hcl.cSup_mem hc.nonempty ha)

lemma is_preconnected.Ioi_cInf_subset {s : set α} (hs : is_preconnected s) (hb : bdd_below s)
  (ha : ¬bdd_above s) :
  Ioi (Inf s) ⊆ s :=
begin
  have sne : s.nonempty := @nonempty_of_not_bdd_above α _ s ⟨Inf ∅⟩ ha,
  intros x hx,
  obtain ⟨y, ys, hy⟩ : ∃ y ∈ s, y < x := (is_glb_lt_iff (is_glb_cInf sne hb)).1 hx,
  obtain ⟨z, zs, hz⟩ : ∃ z ∈ s, x < z := not_bdd_above_iff.1 ha x,
  exact hs.Icc_subset ys zs ⟨le_of_lt hy, le_of_lt hz⟩
end

lemma is_preconnected.Iio_cSup_subset {s : set α} (hs : is_preconnected s) (hb : ¬bdd_below s)
  (ha : bdd_above s) :
  Iio (Sup s) ⊆ s :=
@is_preconnected.Ioi_cInf_subset (order_dual α) _ _ _ s hs ha hb

/-- A preconnected set in a conditionally complete linear order is either one of the intervals
`[Inf s, Sup s]`, `[Inf s, Sup s)`, `(Inf s, Sup s]`, `(Inf s, Sup s)`, `[Inf s, +∞)`,
`(Inf s, +∞)`, `(-∞, Sup s]`, `(-∞, Sup s)`, `(-∞, +∞)`, or `∅`. The converse statement requires
`α` to be densely ordererd. -/
lemma is_preconnected.mem_intervals {s : set α} (hs : is_preconnected s) :
  s ∈ ({Icc (Inf s) (Sup s), Ico (Inf s) (Sup s), Ioc (Inf s) (Sup s), Ioo (Inf s) (Sup s),
    Ici (Inf s), Ioi (Inf s), Iic (Sup s), Iio (Sup s), univ, ∅} : set (set α)) :=
begin
  rcases s.eq_empty_or_nonempty with rfl|hne,
  { apply_rules [or.inr, mem_singleton] },
  have hs' : is_connected s := ⟨hne, hs⟩,
  by_cases hb : bdd_below s; by_cases ha : bdd_above s,
  { rcases mem_Icc_Ico_Ioc_Ioo_of_subset_of_subset (hs'.Ioo_cInf_cSup_subset hb ha)
      (subset_Icc_cInf_cSup hb ha) with hs|hs|hs|hs,
    { exact (or.inl hs) },
    { exact (or.inr $ or.inl hs) },
    { exact (or.inr $ or.inr $ or.inl hs) },
    { exact (or.inr $ or.inr $ or.inr $ or.inl hs) } },
  { refine (or.inr $ or.inr $ or.inr $ or.inr _),
    cases mem_Ici_Ioi_of_subset_of_subset (hs.Ioi_cInf_subset hb ha) (λ x hx, cInf_le hb hx)
      with hs hs,
    { exact or.inl hs },
    { exact or.inr (or.inl hs) } },
  { iterate 6 { apply or.inr },
    cases mem_Iic_Iio_of_subset_of_subset (hs.Iio_cSup_subset hb ha) (λ x hx, le_cSup ha hx)
      with hs hs,
    { exact or.inl hs },
    { exact or.inr (or.inl hs) } },
  { iterate 8 { apply or.inr },
    exact or.inl (hs.eq_univ_of_unbounded hb ha) }
end

/-- A preconnected set is either one of the intervals `Icc`, `Ico`, `Ioc`, `Ioo`, `Ici`, `Ioi`,
`Iic`, `Iio`, or `univ`, or `∅`. The converse statement requires `α` to be densely ordererd. Though
one can represent `∅` as `(Inf s, Inf s)`, we include it into the list of possible cases to improve
readability. -/
lemma set_of_is_preconnected_subset_of_ordered :
  {s : set α | is_preconnected s} ⊆
    -- bounded intervals
    (range (uncurry Icc) ∪ range (uncurry Ico) ∪ range (uncurry Ioc) ∪ range (uncurry Ioo)) ∪
    -- unbounded intervals and `univ`
    (range Ici ∪ range Ioi ∪ range Iic ∪ range Iio ∪ {univ, ∅}) :=
begin
  intros s hs,
  rcases hs.mem_intervals with hs|hs|hs|hs|hs|hs|hs|hs|hs|hs,
  { exact (or.inl $ or.inl $ or.inl $ or.inl ⟨(Inf s, Sup s), hs.symm⟩) },
  { exact (or.inl $ or.inl $ or.inl $ or.inr ⟨(Inf s, Sup s), hs.symm⟩) },
  { exact (or.inl $ or.inl $ or.inr ⟨(Inf s, Sup s), hs.symm⟩) },
  { exact (or.inl $ or.inr ⟨(Inf s, Sup s), hs.symm⟩) },
  { exact (or.inr $ or.inl $ or.inl $ or.inl $ or.inl ⟨Inf s, hs.symm⟩) },
  { exact (or.inr $ or.inl $ or.inl $ or.inl $ or.inr ⟨Inf s, hs.symm⟩) },
  { exact (or.inr $ or.inl $ or.inl  $ or.inr ⟨Sup s, hs.symm⟩) },
  { exact (or.inr $ or.inl $  or.inr ⟨Sup s, hs.symm⟩) },
  { exact (or.inr $ or.inr $ or.inl hs) },
  { exact (or.inr $ or.inr $ or.inr hs) }
end

/-- A "continuous induction principle" for a closed interval: if a set `s` meets `[a, b]`
on a closed subset, contains `a`, and the set `s ∩ [a, b)` has no maximal point, then `b ∈ s`. -/
lemma is_closed.mem_of_ge_of_forall_exists_gt {a b : α} {s : set α} (hs : is_closed (s ∩ Icc a b))
  (ha : a ∈ s) (hab : a ≤ b) (hgt : ∀ x ∈ s ∩ Ico a b, (s ∩ Ioc x b).nonempty) :
  b ∈ s :=
begin
  let S := s ∩ Icc a b,
  replace ha : a ∈ S, from ⟨ha, left_mem_Icc.2 hab⟩,
  have Sbd : bdd_above S, from ⟨b, λ z hz, hz.2.2⟩,
  let c := Sup (s ∩ Icc a b),
  have c_mem : c ∈ S, from hs.cSup_mem ⟨_, ha⟩ Sbd,
  have c_le : c ≤ b, from cSup_le ⟨_, ha⟩ (λ x hx, hx.2.2),
  cases eq_or_lt_of_le c_le with hc hc, from hc ▸ c_mem.1,
  exfalso,
  rcases hgt c ⟨c_mem.1, c_mem.2.1, hc⟩ with ⟨x, xs, cx, xb⟩,
  exact not_lt_of_le (le_cSup Sbd ⟨xs, le_trans (le_cSup Sbd ha) (le_of_lt cx), xb⟩) cx
end

/-- A "continuous induction principle" for a closed interval: if a set `s` meets `[a, b]`
on a closed subset, contains `a`, and for any `a ≤ x < y ≤ b`, `x ∈ s`, the set `s ∩ (x, y]`
is not empty, then `[a, b] ⊆ s`. -/
lemma is_closed.Icc_subset_of_forall_exists_gt {a b : α} {s : set α} (hs : is_closed (s ∩ Icc a b))
  (ha : a ∈ s) (hgt : ∀ x ∈ s ∩ Ico a b, ∀ y ∈ Ioi x,  (s ∩ Ioc x y).nonempty) :
  Icc a b ⊆ s :=
begin
  assume y hy,
  have : is_closed (s ∩ Icc a y),
  { suffices : s ∩ Icc a y = s ∩ Icc a b ∩ Icc a y,
    { rw this, exact is_closed_inter hs is_closed_Icc },
    rw [inter_assoc],
    congr,
    exact (inter_eq_self_of_subset_right $ Icc_subset_Icc_right hy.2).symm },
  exact is_closed.mem_of_ge_of_forall_exists_gt this ha hy.1
    (λ x hx, hgt x ⟨hx.1, Ico_subset_Ico_right hy.2 hx.2⟩ y hx.2.2)
end

section densely_ordered

variables [densely_ordered α] {a b : α}

/-- A "continuous induction principle" for a closed interval: if a set `s` meets `[a, b]`
on a closed subset, contains `a`, and for any `x ∈ s ∩ [a, b)` the set `s` includes some open
neighborhood of `x` within `(x, +∞)`, then `[a, b] ⊆ s`. -/
lemma is_closed.Icc_subset_of_forall_mem_nhds_within {a b : α} {s : set α}
  (hs : is_closed (s ∩ Icc a b)) (ha : a ∈ s)
  (hgt : ∀ x ∈ s ∩ Ico a b, s ∈ 𝓝[Ioi x] x) :
  Icc a b ⊆ s :=
begin
  apply hs.Icc_subset_of_forall_exists_gt ha,
  rintros x ⟨hxs, hxab⟩ y hyxb,
  have : s ∩ Ioc x y ∈ 𝓝[Ioi x] x,
    from inter_mem_sets (hgt x ⟨hxs, hxab⟩) (Ioc_mem_nhds_within_Ioi ⟨le_refl _, hyxb⟩),
  exact (nhds_within_Ioi_self_ne_bot' hxab.2).nonempty_of_mem this
end

/-- A closed interval in a densely ordered conditionally complete linear order is preconnected. -/
lemma is_preconnected_Icc : is_preconnected (Icc a b) :=
is_preconnected_closed_iff.2
begin
  rintros s t hs ht hab ⟨x, hx⟩ ⟨y, hy⟩,
  wlog hxy : x ≤ y := le_total x y using [x y s t, y x t s],
  have xyab : Icc x y ⊆ Icc a b := Icc_subset_Icc hx.1.1 hy.1.2,
  by_contradiction hst,
  suffices : Icc x y ⊆ s,
    from hst ⟨y, xyab $ right_mem_Icc.2 hxy, this $ right_mem_Icc.2 hxy, hy.2⟩,
  apply (is_closed_inter hs is_closed_Icc).Icc_subset_of_forall_mem_nhds_within hx.2,
  rintros z ⟨zs, hz⟩,
  have zt : z ∈ tᶜ, from λ zt, hst ⟨z, xyab $ Ico_subset_Icc_self hz, zs, zt⟩,
  have : tᶜ ∩ Ioc z y ∈ 𝓝[Ioi z] z,
  { rw [← nhds_within_Ioc_eq_nhds_within_Ioi hz.2],
    exact mem_nhds_within.2 ⟨tᶜ, ht.is_open_compl, zt, subset.refl _⟩},
  apply mem_sets_of_superset this,
  have : Ioc z y ⊆ s ∪ t, from λ w hw, hab (xyab ⟨le_trans hz.1 (le_of_lt hw.1), hw.2⟩),
  exact λ w ⟨wt, wzy⟩, (this wzy).elim id (λ h, (wt h).elim)
end

lemma is_preconnected_interval : is_preconnected (interval a b) := is_preconnected_Icc

lemma is_preconnected_iff_ord_connected {s : set α} :
  is_preconnected s ↔ ord_connected s :=
⟨λ h, ⟨λ x hx y hy, h.Icc_subset hx hy⟩, λ h, is_preconnected_of_forall_pair $ λ x y hx hy,
  ⟨interval x y, h.interval_subset hx hy, left_mem_interval, right_mem_interval,
    is_preconnected_interval⟩⟩

alias is_preconnected_iff_ord_connected ↔
  is_preconnected.ord_connected set.ord_connected.is_preconnected

lemma is_preconnected_Ici : is_preconnected (Ici a) := ord_connected_Ici.is_preconnected
lemma is_preconnected_Iic : is_preconnected (Iic a) := ord_connected_Iic.is_preconnected
lemma is_preconnected_Iio : is_preconnected (Iio a) := ord_connected_Iio.is_preconnected
lemma is_preconnected_Ioi : is_preconnected (Ioi a) := ord_connected_Ioi.is_preconnected
lemma is_preconnected_Ioo : is_preconnected (Ioo a b) := ord_connected_Ioo.is_preconnected
lemma is_preconnected_Ioc : is_preconnected (Ioc a b) := ord_connected_Ioc.is_preconnected
lemma is_preconnected_Ico : is_preconnected (Ico a b) := ord_connected_Ico.is_preconnected

@[priority 100]
instance ordered_connected_space : preconnected_space α :=
⟨ord_connected_univ.is_preconnected⟩

/-- In a dense conditionally complete linear order, the set of preconnected sets is exactly
the set of the intervals `Icc`, `Ico`, `Ioc`, `Ioo`, `Ici`, `Ioi`, `Iic`, `Iio`, `(-∞, +∞)`,
or `∅`. Though one can represent `∅` as `(Inf s, Inf s)`, we include it into the list of
possible cases to improve readability. -/
lemma set_of_is_preconnected_eq_of_ordered :
  {s : set α | is_preconnected s} =
    -- bounded intervals
    (range (uncurry Icc) ∪ range (uncurry Ico) ∪ range (uncurry Ioc) ∪ range (uncurry Ioo)) ∪
    -- unbounded intervals and `univ`
    (range Ici ∪ range Ioi ∪ range Iic ∪ range Iio ∪ {univ, ∅}) :=
begin
  refine subset.antisymm set_of_is_preconnected_subset_of_ordered _,
  simp only [subset_def, -mem_range, forall_range_iff, uncurry, or_imp_distrib, forall_and_distrib,
    mem_union, mem_set_of_eq, insert_eq, mem_singleton_iff, forall_eq, forall_true_iff, and_true,
    is_preconnected_Icc, is_preconnected_Ico, is_preconnected_Ioc,
    is_preconnected_Ioo, is_preconnected_Ioi, is_preconnected_Iio, is_preconnected_Ici,
    is_preconnected_Iic, is_preconnected_univ, is_preconnected_empty],
end

variables {δ : Type*} [linear_order δ] [topological_space δ] [order_closed_topology δ]

/-- Intermediate Value Theorem for continuous functions on closed intervals, case `f a ≤ t ≤ f b`.-/
lemma intermediate_value_Icc {a b : α} (hab : a ≤ b) {f : α → δ} (hf : continuous_on f (Icc a b)) :
  Icc (f a) (f b) ⊆ f '' (Icc a b) :=
is_preconnected_Icc.intermediate_value (left_mem_Icc.2 hab) (right_mem_Icc.2 hab) hf

/-- Intermediate Value Theorem for continuous functions on closed intervals, case `f a ≥ t ≥ f b`.-/
lemma intermediate_value_Icc' {a b : α} (hab : a ≤ b) {f : α → δ} (hf : continuous_on f (Icc a b)) :
  Icc (f b) (f a) ⊆ f '' (Icc a b) :=
is_preconnected_Icc.intermediate_value (right_mem_Icc.2 hab) (left_mem_Icc.2 hab) hf

/-- Intermediate Value Theorem for continuous functions on closed intervals, unordered case. -/
lemma intermediate_value_interval {a b : α} {f : α → δ} (hf : continuous_on f (interval a b)) :
  interval (f a) (f b) ⊆ f '' interval a b :=
by cases le_total (f a) (f b); simp [*, is_preconnected_interval.intermediate_value]

lemma intermediate_value_Ico {a b : α} (hab : a ≤ b) {f : α → δ} (hf : continuous_on f (Icc a b)) :
  Ico (f a) (f b) ⊆ f '' (Ico a b) :=
or.elim (eq_or_lt_of_le hab) (λ he y h, absurd h.2 (not_lt_of_le (he ▸ h.1)))
(λ hlt, @is_preconnected.intermediate_value_Ico _ _ _ _ _ _ _ (is_preconnected_Ico)
  _ _ ⟨refl a, hlt⟩ (right_nhds_within_Ico_ne_bot hlt) inf_le_right _ (hf.mono Ico_subset_Icc_self)
  _ ((hf.continuous_within_at ⟨hab, refl b⟩).mono Ico_subset_Icc_self))

lemma intermediate_value_Ico' {a b : α} (hab : a ≤ b) {f : α → δ} (hf : continuous_on f (Icc a b)) :
  Ioc (f b) (f a) ⊆ f '' (Ico a b) :=
or.elim (eq_or_lt_of_le hab) (λ he y h, absurd h.1 (not_lt_of_le (he ▸ h.2)))
(λ hlt, @is_preconnected.intermediate_value_Ioc _ _ _ _ _ _ _ (is_preconnected_Ico)
  _ _ ⟨refl a, hlt⟩ (right_nhds_within_Ico_ne_bot hlt) inf_le_right _ (hf.mono Ico_subset_Icc_self)
  _ ((hf.continuous_within_at ⟨hab, refl b⟩).mono Ico_subset_Icc_self))

lemma intermediate_value_Ioc {a b : α} (hab : a ≤ b) {f : α → δ} (hf : continuous_on f (Icc a b)) :
  Ioc (f a) (f b) ⊆ f '' (Ioc a b) :=
or.elim (eq_or_lt_of_le hab) (λ he y h, absurd h.2 (not_le_of_lt (he ▸ h.1)))
(λ hlt, @is_preconnected.intermediate_value_Ioc _ _ _ _ _ _ _ (is_preconnected_Ioc)
  _ _ ⟨hlt, refl b⟩ (left_nhds_within_Ioc_ne_bot hlt) inf_le_right _ (hf.mono Ioc_subset_Icc_self)
  _ ((hf.continuous_within_at ⟨refl a, hab⟩).mono Ioc_subset_Icc_self))

lemma intermediate_value_Ioc' {a b : α} (hab : a ≤ b) {f : α → δ} (hf : continuous_on f (Icc a b)) :
  Ico (f b) (f a) ⊆ f '' (Ioc a b) :=
or.elim (eq_or_lt_of_le hab) (λ he y h, absurd h.1 (not_le_of_lt (he ▸ h.2)))
(λ hlt, @is_preconnected.intermediate_value_Ico _ _ _ _ _ _ _ (is_preconnected_Ioc)
  _ _ ⟨hlt, refl b⟩ (left_nhds_within_Ioc_ne_bot hlt) inf_le_right _ (hf.mono Ioc_subset_Icc_self)
  _ ((hf.continuous_within_at ⟨refl a, hab⟩).mono Ioc_subset_Icc_self))

lemma intermediate_value_Ioo {a b : α} (hab : a ≤ b) {f : α → δ} (hf : continuous_on f (Icc a b)) :
  Ioo (f a) (f b) ⊆ f '' (Ioo a b) :=
or.elim (eq_or_lt_of_le hab) (λ he y h, absurd h.2 (not_lt_of_lt (he ▸ h.1)))
(λ hlt, @is_preconnected.intermediate_value_Ioo _ _ _ _ _ _ _ (is_preconnected_Ioo)
  _ _ (left_nhds_within_Ioo_ne_bot hlt) (right_nhds_within_Ioo_ne_bot hlt)
  inf_le_right inf_le_right _ (hf.mono Ioo_subset_Icc_self)
  _ _ ((hf.continuous_within_at ⟨refl a, hab⟩).mono Ioo_subset_Icc_self)
  ((hf.continuous_within_at ⟨hab, refl b⟩).mono Ioo_subset_Icc_self))

lemma intermediate_value_Ioo' {a b : α} (hab : a ≤ b) {f : α → δ} (hf : continuous_on f (Icc a b)) :
  Ioo (f b) (f a) ⊆ f '' (Ioo a b) :=
or.elim (eq_or_lt_of_le hab) (λ he y h, absurd h.1 (not_lt_of_lt (he ▸ h.2)))
(λ hlt, @is_preconnected.intermediate_value_Ioo _ _ _ _ _ _ _ (is_preconnected_Ioo)
  _ _ (right_nhds_within_Ioo_ne_bot hlt) (left_nhds_within_Ioo_ne_bot hlt)
  inf_le_right inf_le_right _ (hf.mono Ioo_subset_Icc_self)
  _ _ ((hf.continuous_within_at ⟨hab, refl b⟩).mono Ioo_subset_Icc_self)
  ((hf.continuous_within_at ⟨refl a, hab⟩).mono Ioo_subset_Icc_self))

/-- A continuous function which tendsto `at_top` `at_top` and to `at_bot` `at_bot` is surjective. -/
lemma continuous.surjective {f : α → δ} (hf : continuous f) (h_top : tendsto f at_top at_top)
  (h_bot : tendsto f at_bot at_bot) :
  function.surjective f :=
λ p, mem_range_of_exists_le_of_exists_ge hf
  (h_bot.eventually (eventually_le_at_bot p)).exists
  (h_top.eventually (eventually_ge_at_top p)).exists

/-- A continuous function which tendsto `at_bot` `at_top` and to `at_top` `at_bot` is surjective. -/
lemma continuous.surjective' {f : α → δ} (hf : continuous f) (h_top : tendsto f at_bot at_top)
  (h_bot : tendsto f at_top at_bot) :
  function.surjective f :=
@continuous.surjective (order_dual α) _ _ _ _ _ _ _ _ _ hf h_top h_bot

/-- If a function `f : α → β` is continuous on a nonempty interval `s`, its restriction to `s`
tends to `at_bot : filter β` along `at_bot : filter ↥s` and tends to `at_top : filter β` along
`at_top : filter ↥s`, then the restriction of `f` to `s` is surjective. We formulate the
conclusion as `surj_on f s univ`. -/
lemma continuous_on.surj_on_of_tendsto {f : α → β} {s : set α} [ord_connected s]
  (hs : s.nonempty) (hf : continuous_on f s) (hbot : tendsto (λ x : s, f x) at_bot at_bot)
  (htop : tendsto (λ x : s, f x) at_top at_top) :
  surj_on f s univ :=
by haveI := inhabited_of_nonempty hs.to_subtype;
  exact (surj_on_iff_surjective.2 $
    (continuous_on_iff_continuous_restrict.1 hf).surjective htop hbot)

/-- If a function `f : α → β` is continuous on a nonempty interval `s`, its restriction to `s`
tends to `at_top : filter β` along `at_bot : filter ↥s` and tends to `at_bot : filter β` along
`at_top : filter ↥s`, then the restriction of `f` to `s` is surjective. We formulate the
conclusion as `surj_on f s univ`. -/
lemma continuous_on.surj_on_of_tendsto' {f : α → β} {s : set α} [ord_connected s]
  (hs : s.nonempty) (hf : continuous_on f s) (hbot : tendsto (λ x : s, f x) at_bot at_top)
  (htop : tendsto (λ x : s, f x) at_top at_bot) :
  surj_on f s univ :=
@continuous_on.surj_on_of_tendsto α (order_dual β) _ _ _ _ _ _ _ _ _ _ hs hf hbot htop

end densely_ordered

/-- A closed interval in a conditionally complete linear order is compact. -/
lemma compact_Icc {a b : α} : is_compact (Icc a b) :=
begin
  cases le_or_lt a b with hab hab, swap, { simp [hab] },
  refine compact_iff_ultrafilter_le_nhds.2 (λ f hf, _),
  contrapose! hf,
  rw [le_principal_iff],
  have hpt : ∀ x ∈ Icc a b, {x} ∉ f,
    from λ x hx hxf, hf x hx ((le_pure_iff.2 hxf).trans (pure_le_nhds x)),
  set s := {x ∈ Icc a b | Icc a x ∉ f},
  have hsb : b ∈ upper_bounds s, from λ x hx, hx.1.2,
  have sbd : bdd_above s, from ⟨b, hsb⟩,
  have ha : a ∈ s, by simp [hpt, hab],
  rcases hab.eq_or_lt with rfl|hlt, { exact ha.2 },
  set c := Sup s,
  have hsc : is_lub s c, from is_lub_cSup ⟨a, ha⟩ sbd,
  have hc : c ∈ Icc a b, from ⟨hsc.1 ha, hsc.2 hsb⟩,
  specialize hf c hc,
  have hcs : c ∈ s,
  { cases hc.1.eq_or_lt with heq hlt, { rwa ← heq },
    refine ⟨hc, λ hcf, hf (λ U hU, _)⟩,
    rcases (mem_nhds_within_Iic_iff_exists_Ioc_subset' hlt).1 (mem_nhds_within_of_mem_nhds hU)
      with ⟨x, hxc, hxU⟩,
    rcases ((hsc.frequently_mem ⟨a, ha⟩).and_eventually
      (Ioc_mem_nhds_within_Iic ⟨hxc, le_rfl⟩)).exists
      with ⟨y, ⟨hyab, hyf⟩, hy⟩,
    refine mem_sets_of_superset(f.diff_mem_iff.2 ⟨hcf, hyf⟩) (subset.trans _ hxU),
    rw diff_subset_iff,
    exact subset.trans Icc_subset_Icc_union_Ioc
      (union_subset_union subset.rfl $ Ioc_subset_Ioc_left hy.1.le) },
  cases hc.2.eq_or_lt with heq hlt, { rw ← heq, exact hcs.2 },
  contrapose! hf,
  intros U hU,
  rcases (mem_nhds_within_Ici_iff_exists_mem_Ioc_Ico_subset hlt).1 (mem_nhds_within_of_mem_nhds hU)
    with ⟨y, hxy, hyU⟩,
  refine mem_sets_of_superset _ hyU, clear_dependent U,
  have hy : y ∈ Icc a b, from ⟨hc.1.trans hxy.1.le, hxy.2⟩,
  by_cases hay : Icc a y ∈ f,
  { refine mem_sets_of_superset (f.diff_mem_iff.2 ⟨f.diff_mem_iff.2 ⟨hay, hcs.2⟩, hpt y hy⟩) _,
    rw [diff_subset_iff, union_comm, Ico_union_right hxy.1.le, diff_subset_iff],
    exact Icc_subset_Icc_union_Icc },
  { exact ((hsc.1 ⟨hy, hay⟩).not_lt hxy.1).elim },
end

/-- An unordered closed interval in a conditionally complete linear order is compact. -/
lemma compact_interval {a b : α} : is_compact (interval a b) := compact_Icc

lemma compact_pi_Icc {ι : Type*} {α : ι → Type*} [Π i, conditionally_complete_linear_order (α i)]
  [Π i, topological_space (α i)] [Π i, order_topology (α i)] (a b : Π i, α i) :
  is_compact (Icc a b) :=
pi_univ_Icc a b ▸ compact_univ_pi $ λ i, compact_Icc

instance compact_space_Icc (a b : α) : compact_space (Icc a b) :=
compact_iff_compact_space.mp compact_Icc

instance compact_space_pi_Icc {ι : Type*} {α : ι → Type*}
  [Π i, conditionally_complete_linear_order (α i)] [Π i, topological_space (α i)]
  [Π i, order_topology (α i)] (a b : Π i, α i) : compact_space (Icc a b) :=
compact_iff_compact_space.mp (compact_pi_Icc a b)

@[priority 100] -- See note [lower instance priority]
instance compact_space_of_complete_linear_order {α : Type*} [complete_linear_order α]
  [topological_space α] [order_topology α] :
  compact_space α :=
⟨by simp only [← Icc_bot_top, compact_Icc]⟩

lemma is_compact.Inf_mem {s : set α} (hs : is_compact s) (ne_s : s.nonempty) :
  Inf s ∈ s :=
hs.is_closed.cInf_mem ne_s hs.bdd_below

lemma is_compact.Sup_mem {s : set α} (hs : is_compact s) (ne_s : s.nonempty) :
  Sup s ∈ s :=
@is_compact.Inf_mem (order_dual α) _ _ _ _ hs ne_s

lemma is_compact.is_glb_Inf {s : set α} (hs : is_compact s) (ne_s : s.nonempty) :
  is_glb s (Inf s) :=
is_glb_cInf ne_s hs.bdd_below

lemma is_compact.is_lub_Sup {s : set α} (hs : is_compact s) (ne_s : s.nonempty) :
  is_lub s (Sup s) :=
@is_compact.is_glb_Inf (order_dual α) _ _ _ _ hs ne_s

lemma is_compact.is_least_Inf {s : set α} (hs : is_compact s) (ne_s : s.nonempty) :
  is_least s (Inf s) :=
⟨hs.Inf_mem ne_s, (hs.is_glb_Inf ne_s).1⟩

lemma is_compact.is_greatest_Sup {s : set α} (hs : is_compact s) (ne_s : s.nonempty) :
  is_greatest s (Sup s) :=
@is_compact.is_least_Inf (order_dual α) _ _ _ _ hs ne_s

lemma is_compact.exists_is_least {s : set α} (hs : is_compact s) (ne_s : s.nonempty) :
  ∃ x, is_least s x :=
⟨_, hs.is_least_Inf ne_s⟩

lemma is_compact.exists_is_greatest {s : set α} (hs : is_compact s) (ne_s : s.nonempty) :
  ∃ x, is_greatest s x :=
⟨_, hs.is_greatest_Sup ne_s⟩

lemma is_compact.exists_is_glb {s : set α} (hs : is_compact s) (ne_s : s.nonempty) :
  ∃ x ∈ s, is_glb s x :=
⟨_, hs.Inf_mem ne_s, hs.is_glb_Inf ne_s⟩

lemma is_compact.exists_is_lub {s : set α} (hs : is_compact s) (ne_s : s.nonempty) :
  ∃ x ∈ s, is_lub s x :=
⟨_, hs.Sup_mem ne_s, hs.is_lub_Sup ne_s⟩

lemma is_compact.exists_Inf_image_eq {α : Type u} [topological_space α]
  {s : set α} (hs : is_compact s) (ne_s : s.nonempty) {f : α → β} (hf : continuous_on f s) :
  ∃ x ∈ s,  Inf (f '' s) = f x :=
let ⟨x, hxs, hx⟩ := (hs.image_of_continuous_on hf).Inf_mem (ne_s.image f)
in ⟨x, hxs, hx.symm⟩

lemma is_compact.exists_Sup_image_eq {α : Type u} [topological_space α]:
  ∀ {s : set α}, is_compact s → s.nonempty → ∀ {f : α → β}, continuous_on f s →
  ∃ x ∈ s,  Sup (f '' s) = f x :=
@is_compact.exists_Inf_image_eq (order_dual β) _ _ _ _ _

lemma eq_Icc_of_connected_compact {s : set α} (h₁ : is_connected s) (h₂ : is_compact s) :
  s = Icc (Inf s) (Sup s) :=
eq_Icc_cInf_cSup_of_connected_bdd_closed h₁ h₂.bdd_below h₂.bdd_above h₂.is_closed

/-- The extreme value theorem: a continuous function realizes its minimum on a compact set -/
lemma is_compact.exists_forall_le {α : Type u} [topological_space α]
  {s : set α} (hs : is_compact s) (ne_s : s.nonempty) {f : α → β} (hf : continuous_on f s) :
  ∃x∈s, ∀y∈s, f x ≤ f y :=
begin
  rcases hs.exists_Inf_image_eq ne_s hf with ⟨x, hxs, hx⟩,
  refine ⟨x, hxs, λ y hy, _⟩,
  rw ← hx,
  exact ((hs.image_of_continuous_on hf).is_glb_Inf (ne_s.image f)).1 (mem_image_of_mem _ hy)
end

/-- The extreme value theorem: a continuous function realizes its maximum on a compact set -/
lemma is_compact.exists_forall_ge {α : Type u} [topological_space α]:
  ∀ {s : set α}, is_compact s → s.nonempty → ∀ {f : α → β}, continuous_on f s →
  ∃x∈s, ∀y∈s, f y ≤ f x :=
@is_compact.exists_forall_le (order_dual β) _ _ _ _ _

/-- The extreme value theorem: if a continuous function `f` tends to infinity away from compact
sets, then it has a global minimum. -/
lemma continuous.exists_forall_le {α : Type*} [topological_space α] [nonempty α] {f : α → β}
  (hf : continuous f) (hlim : tendsto f (cocompact α) at_top) :
  ∃ x, ∀ y, f x ≤ f y :=
begin
  inhabit α,
  obtain ⟨s : set α, hsc : is_compact s, hsf : ∀ x ∉ s, f (default α) ≤ f x⟩ :=
    (has_basis_cocompact.tendsto_iff at_top_basis).1 hlim (f $ default α) trivial,
  obtain ⟨x, -, hx⟩ :=
    (hsc.insert (default α)).exists_forall_le (nonempty_insert _ _) hf.continuous_on,
  refine ⟨x, λ y, _⟩,
  by_cases hy : y ∈ s,
  exacts [hx y (or.inr hy), (hx _ (or.inl rfl)).trans (hsf y hy)]
end

/-- The extreme value theorem: if a continuous function `f` tends to negative infinity away from
compactx sets, then it has a global maximum. -/
lemma continuous.exists_forall_ge {α : Type*} [topological_space α] [nonempty α] {f : α → β}
  (hf : continuous f) (hlim : tendsto f (cocompact α) at_bot) :
  ∃ x, ∀ y, f y ≤ f x :=
@continuous.exists_forall_le (order_dual β) _ _ _ _ _ _ _ hf hlim

end conditionally_complete_linear_order

section liminf_limsup

section order_closed_topology
variables [semilattice_sup α] [topological_space α] [order_topology α]

lemma is_bounded_le_nhds (a : α) : (𝓝 a).is_bounded (≤) :=
match forall_le_or_exists_lt_sup a with
| or.inl h := ⟨a, eventually_of_forall h⟩
| or.inr ⟨b, hb⟩ := ⟨b, ge_mem_nhds hb⟩
end

lemma filter.tendsto.is_bounded_under_le {f : filter β} {u : β → α} {a : α}
  (h : tendsto u f (𝓝 a)) : f.is_bounded_under (≤) u :=
(is_bounded_le_nhds a).mono h

lemma is_cobounded_ge_nhds (a : α) : (𝓝 a).is_cobounded (≥) :=
(is_bounded_le_nhds a).is_cobounded_flip

lemma filter.tendsto.is_cobounded_under_ge {f : filter β} {u : β → α} {a : α}
  [ne_bot f] (h : tendsto u f (𝓝 a)) : f.is_cobounded_under (≥) u :=
h.is_bounded_under_le.is_cobounded_flip

end order_closed_topology

section order_closed_topology
variables [semilattice_inf α] [topological_space α] [order_topology α]

lemma is_bounded_ge_nhds (a : α) : (𝓝 a).is_bounded (≥) :=
@is_bounded_le_nhds (order_dual α) _ _ _ a

lemma filter.tendsto.is_bounded_under_ge {f : filter β} {u : β → α} {a : α}
  (h : tendsto u f (𝓝 a)) : f.is_bounded_under (≥) u :=
(is_bounded_ge_nhds a).mono h

lemma is_cobounded_le_nhds (a : α) : (𝓝 a).is_cobounded (≤) :=
(is_bounded_ge_nhds a).is_cobounded_flip

lemma filter.tendsto.is_cobounded_under_le {f : filter β} {u : β → α} {a : α}
  [ne_bot f] (h : tendsto u f (𝓝 a)) : f.is_cobounded_under (≤) u :=
h.is_bounded_under_ge.is_cobounded_flip

end order_closed_topology

section conditionally_complete_linear_order
variables [conditionally_complete_linear_order α]

theorem lt_mem_sets_of_Limsup_lt {f : filter α} {b} (h : f.is_bounded (≤)) (l : f.Limsup < b) :
  ∀ᶠ a in f, a < b :=
let ⟨c, (h : ∀ᶠ a in f, a ≤ c), hcb⟩ := exists_lt_of_cInf_lt h l in
mem_sets_of_superset h $ assume a hac, lt_of_le_of_lt hac hcb

theorem gt_mem_sets_of_Liminf_gt : ∀ {f : filter α} {b}, f.is_bounded (≥) → b < f.Liminf →
  ∀ᶠ a in f, b < a :=
@lt_mem_sets_of_Limsup_lt (order_dual α) _

variables [topological_space α] [order_topology α]

/-- If the liminf and the limsup of a filter coincide, then this filter converges to
their common value, at least if the filter is eventually bounded above and below. -/
theorem le_nhds_of_Limsup_eq_Liminf {f : filter α} {a : α}
  (hl : f.is_bounded (≤)) (hg : f.is_bounded (≥)) (hs : f.Limsup = a) (hi : f.Liminf = a) :
  f ≤ 𝓝 a :=
tendsto_order.2 $ and.intro
  (assume b hb, gt_mem_sets_of_Liminf_gt hg $ hi.symm ▸ hb)
  (assume b hb, lt_mem_sets_of_Limsup_lt hl $ hs.symm ▸ hb)

theorem Limsup_nhds (a : α) : Limsup (𝓝 a) = a :=
cInf_intro (is_bounded_le_nhds a)
  (assume a' (h : {n : α | n ≤ a'} ∈ 𝓝 a), show a ≤ a', from @mem_of_nhds α _ a _ h)
  (assume b (hba : a < b), show ∃c (h : {n : α | n ≤ c} ∈ 𝓝 a), c < b, from
    match dense_or_discrete a b with
    | or.inl ⟨c, hac, hcb⟩ := ⟨c, ge_mem_nhds hac, hcb⟩
    | or.inr ⟨_, h⟩        := ⟨a, (𝓝 a).sets_of_superset (gt_mem_nhds hba) h, hba⟩
    end)

theorem Liminf_nhds : ∀ (a : α), Liminf (𝓝 a) = a :=
@Limsup_nhds (order_dual α) _ _ _

/-- If a filter is converging, its limsup coincides with its limit. -/
theorem Liminf_eq_of_le_nhds {f : filter α} {a : α} [ne_bot f] (h : f ≤ 𝓝 a) : f.Liminf = a :=
have hb_ge : is_bounded (≥) f, from (is_bounded_ge_nhds a).mono h,
have hb_le : is_bounded (≤) f, from (is_bounded_le_nhds a).mono h,
le_antisymm
  (calc f.Liminf ≤ f.Limsup : Liminf_le_Limsup hb_le hb_ge
    ... ≤ (𝓝 a).Limsup :
      Limsup_le_Limsup_of_le h hb_ge.is_cobounded_flip (is_bounded_le_nhds a)
    ... = a : Limsup_nhds a)
  (calc a = (𝓝 a).Liminf : (Liminf_nhds a).symm
    ... ≤ f.Liminf :
      Liminf_le_Liminf_of_le h (is_bounded_ge_nhds a) hb_le.is_cobounded_flip)

/-- If a filter is converging, its liminf coincides with its limit. -/
theorem Limsup_eq_of_le_nhds : ∀ {f : filter α} {a : α} [ne_bot f], f ≤ 𝓝 a → f.Limsup = a :=
@Liminf_eq_of_le_nhds (order_dual α) _ _ _

/-- If a function has a limit, then its limsup coincides with its limit. -/
theorem filter.tendsto.limsup_eq {f : filter β} {u : β → α} {a : α} [ne_bot f]
  (h : tendsto u f (𝓝 a)) : limsup f u = a :=
Limsup_eq_of_le_nhds h

/-- If a function has a limit, then its liminf coincides with its limit. -/
theorem filter.tendsto.liminf_eq {f : filter β} {u : β → α} {a : α} [ne_bot f]
  (h : tendsto u f (𝓝 a)) : liminf f u = a :=
Liminf_eq_of_le_nhds h

end conditionally_complete_linear_order

section complete_linear_order
variables [complete_linear_order α] [topological_space α] [order_topology α]
-- In complete_linear_order, the above theorems take a simpler form

/-- If the liminf and the limsup of a function coincide, then the limit of the function
exists and has the same value -/
theorem tendsto_of_liminf_eq_limsup {f : filter β} {u : β → α} {a : α}
  (hinf : liminf f u = a) (hsup : limsup f u = a) : tendsto u f (𝓝 a) :=
le_nhds_of_Limsup_eq_Liminf is_bounded_le_of_top is_bounded_ge_of_bot hsup hinf

/-- If a number `a` is less than or equal to the `liminf` of a function `f` at some filter
and is greater than or equal to the `limsup` of `f`, then `f` tends to `a` along this filter. -/
theorem tendsto_of_le_liminf_of_limsup_le {f : filter β} {u : β → α} {a : α}
  (hinf : a ≤ liminf f u) (hsup : limsup f u ≤ a) :
  tendsto u f (𝓝 a) :=
if hf : f = ⊥ then hf.symm ▸ tendsto_bot
else by haveI : ne_bot f := ⟨hf⟩; exact tendsto_of_liminf_eq_limsup
  (le_antisymm (le_trans liminf_le_limsup hsup) hinf)
  (le_antisymm hsup (le_trans hinf liminf_le_limsup))

end complete_linear_order

end liminf_limsup

end order_topology

/-!
Here is a counter-example to a version of the following with `conditionally_complete_lattice α`.
Take `α = [0, 1) → ℝ` with the natural lattice structure, `ι = ℕ`. Put `f n x = -x^n`. Then
`⨆ n, f n = 0` while none of `f n` is strictly greater than the constant function `-0.5`.
-/

lemma tendsto_at_top_csupr {ι α : Type*} [preorder ι] [topological_space α]
  [conditionally_complete_linear_order α] [order_topology α]
  {f : ι → α} (h_mono : monotone f) (hbdd : bdd_above $ range f) :
  tendsto f at_top (𝓝 (⨆i, f i)) :=
begin
  by_cases hi : nonempty ι,
  { resetI,
    rw tendsto_order,
    split,
    { intros a h,
      cases exists_lt_of_lt_csupr h with N hN,
      apply eventually.mono (mem_at_top N),
      exact λ i hi, lt_of_lt_of_le hN (h_mono hi) },
    { exact λ a h, eventually_of_forall (λ n, lt_of_le_of_lt (le_csupr hbdd n) h) } },
  { exact tendsto_of_not_nonempty hi }
end

lemma tendsto_at_bot_cinfi {ι α : Type*} [preorder ι] [topological_space α]
  [conditionally_complete_linear_order α] [order_topology α]
  {f : ι → α} (h_mono : monotone f) (hbdd : bdd_below $ range f) :
  tendsto f at_bot (𝓝 (⨅i, f i)) :=
@tendsto_at_top_csupr (order_dual ι) (order_dual α) _ _ _ _ _ h_mono.order_dual hbdd

lemma tendsto_at_top_cinfi {ι α : Type*} [preorder ι] [topological_space α]
  [conditionally_complete_linear_order α] [order_topology α]
  {f : ι → α} (h_mono : ∀ ⦃i j⦄, i ≤ j → f j ≤ f i) (hbdd : bdd_below $ range f) :
  tendsto f at_top (𝓝 (⨅i, f i)) :=
@tendsto_at_top_csupr _ (order_dual α) _ _ _ _ _ @h_mono hbdd

lemma tendsto_at_bot_csupr {ι α : Type*} [preorder ι] [topological_space α]
  [conditionally_complete_linear_order α] [order_topology α]
  {f : ι → α} (h_mono : ∀ ⦃i j⦄, i ≤ j → f j ≤ f i) (hbdd : bdd_above $ range f) :
  tendsto f at_bot (𝓝 (⨆i, f i)) :=
@tendsto_at_bot_cinfi ι (order_dual α) _ _ _ _ _ h_mono hbdd

lemma tendsto_at_top_supr {ι α : Type*} [preorder ι] [topological_space α]
  [complete_linear_order α] [order_topology α] {f : ι → α} (h_mono : monotone f) :
  tendsto f at_top (𝓝 (⨆i, f i)) :=
tendsto_at_top_csupr h_mono (order_top.bdd_above _)

lemma tendsto_at_bot_infi {ι α : Type*} [preorder ι] [topological_space α]
  [complete_linear_order α] [order_topology α] {f : ι → α} (h_mono : monotone f) :
  tendsto f at_bot (𝓝 (⨅i, f i)) :=
tendsto_at_bot_cinfi h_mono (order_bot.bdd_below _)

lemma tendsto_at_top_infi {ι α : Type*} [preorder ι] [topological_space α]
  [complete_linear_order α] [order_topology α] {f : ι → α} (h_mono : ∀ ⦃i j⦄, i ≤ j → f j ≤ f i) :
  tendsto f at_top (𝓝 (⨅i, f i)) :=
tendsto_at_top_cinfi @h_mono (order_bot.bdd_below _)

lemma tendsto_at_bot_supr {ι α : Type*} [preorder ι] [topological_space α]
  [complete_linear_order α] [order_topology α] {f : ι → α} (h_mono : ∀ ⦃i j⦄, i ≤ j → f j ≤ f i) :
  tendsto f at_bot (𝓝 (⨆i, f i)) :=
tendsto_at_bot_csupr h_mono (order_top.bdd_above _)

lemma tendsto_of_monotone {ι α : Type*} [preorder ι] [topological_space α]
  [conditionally_complete_linear_order α] [order_topology α] {f : ι → α} (h_mono : monotone f) :
  tendsto f at_top at_top ∨ (∃ l, tendsto f at_top (𝓝 l)) :=
if H : bdd_above (range f) then or.inr ⟨_, tendsto_at_top_csupr h_mono H⟩
else or.inl $ tendsto_at_top_at_top_of_monotone' h_mono H

lemma supr_eq_of_tendsto {α β} [topological_space α] [complete_linear_order α] [order_topology α]
  [nonempty β] [semilattice_sup β] {f : β → α} {a : α} (hf : monotone f) :
  tendsto f at_top (𝓝 a) → supr f = a :=
tendsto_nhds_unique (tendsto_at_top_supr hf)

lemma infi_eq_of_tendsto {α} [topological_space α] [complete_linear_order α] [order_topology α]
  [nonempty β] [semilattice_sup β] {f : β → α} {a : α} (hf : ∀n m, n ≤ m → f m ≤ f n) :
  tendsto f at_top (𝓝 a) → infi f = a :=
tendsto_nhds_unique (tendsto_at_top_infi hf)

@[to_additive] lemma tendsto_inv_nhds_within_Ioi [ordered_comm_group α]
  [topological_space α] [topological_group α] {a : α} :
  tendsto has_inv.inv (𝓝[Ioi a] a) (𝓝[Iio (a⁻¹)] (a⁻¹)) :=
(continuous_inv.tendsto a).inf $ by simp [tendsto_principal_principal]

@[to_additive] lemma tendsto_inv_nhds_within_Iio [ordered_comm_group α]
  [topological_space α] [topological_group α] {a : α} :
  tendsto has_inv.inv (𝓝[Iio a] a) (𝓝[Ioi (a⁻¹)] (a⁻¹)) :=
(continuous_inv.tendsto a).inf $ by simp [tendsto_principal_principal]

@[to_additive] lemma tendsto_inv_nhds_within_Ioi_inv [ordered_comm_group α]
  [topological_space α] [topological_group α] {a : α} :
  tendsto has_inv.inv (𝓝[Ioi (a⁻¹)] (a⁻¹)) (𝓝[Iio a] a) :=
by simpa only [inv_inv] using @tendsto_inv_nhds_within_Ioi _ _ _ _ (a⁻¹)

@[to_additive] lemma tendsto_inv_nhds_within_Iio_inv [ordered_comm_group α]
  [topological_space α] [topological_group α] {a : α} :
  tendsto has_inv.inv (𝓝[Iio (a⁻¹)] (a⁻¹)) (𝓝[Ioi a] a) :=
by simpa only [inv_inv] using @tendsto_inv_nhds_within_Iio _ _ _ _ (a⁻¹)

@[to_additive] lemma tendsto_inv_nhds_within_Ici [ordered_comm_group α]
  [topological_space α] [topological_group α] {a : α} :
  tendsto has_inv.inv (𝓝[Ici a] a) (𝓝[Iic (a⁻¹)] (a⁻¹)) :=
(continuous_inv.tendsto a).inf $ by simp [tendsto_principal_principal]

@[to_additive] lemma tendsto_inv_nhds_within_Iic [ordered_comm_group α]
  [topological_space α] [topological_group α] {a : α} :
  tendsto has_inv.inv (𝓝[Iic a] a) (𝓝[Ici (a⁻¹)] (a⁻¹)) :=
(continuous_inv.tendsto a).inf $ by simp [tendsto_principal_principal]

@[to_additive] lemma tendsto_inv_nhds_within_Ici_inv [ordered_comm_group α]
  [topological_space α] [topological_group α] {a : α} :
  tendsto has_inv.inv (𝓝[Ici (a⁻¹)] (a⁻¹)) (𝓝[Iic a] a) :=
by simpa only [inv_inv] using @tendsto_inv_nhds_within_Ici _ _ _ _ (a⁻¹)

@[to_additive] lemma tendsto_inv_nhds_within_Iic_inv [ordered_comm_group α]
  [topological_space α] [topological_group α] {a : α} :
  tendsto has_inv.inv (𝓝[Iic (a⁻¹)] (a⁻¹)) (𝓝[Ici a] a) :=
by simpa only [inv_inv] using @tendsto_inv_nhds_within_Iic _ _ _ _ (a⁻¹)

lemma nhds_left_sup_nhds_right (a : α) [topological_space α] [linear_order α] :
  𝓝[Iic a] a ⊔ 𝓝[Ici a] a = 𝓝 a :=
by rw [← nhds_within_union, Iic_union_Ici, nhds_within_univ]

lemma nhds_left'_sup_nhds_right (a : α) [topological_space α] [linear_order α] :
  𝓝[Iio a] a ⊔ 𝓝[Ici a] a = 𝓝 a :=
by rw [← nhds_within_union, Iio_union_Ici, nhds_within_univ]

lemma nhds_left_sup_nhds_right' (a : α) [topological_space α] [linear_order α] :
  𝓝[Iic a] a ⊔ 𝓝[Ioi a] a = 𝓝 a :=
by rw [← nhds_within_union, Iic_union_Ioi, nhds_within_univ]

lemma continuous_at_iff_continuous_left_right [topological_space α] [linear_order α]
  [topological_space β] {a : α} {f : α → β} :
  continuous_at f a ↔ continuous_within_at f (Iic a) a ∧ continuous_within_at f (Ici a) a :=
by simp only [continuous_within_at, continuous_at, ← tendsto_sup, nhds_left_sup_nhds_right]

lemma continuous_on_Icc_extend_from_Ioo [topological_space α] [linear_order α] [densely_ordered α]
  [order_topology α] [topological_space β] [regular_space β] {f : α → β} {a b : α}
  {la lb : β} (hab : a < b) (hf : continuous_on f (Ioo a b))
  (ha : tendsto f (𝓝[Ioi a] a) (𝓝 la)) (hb : tendsto f (𝓝[Iio b] b) (𝓝 lb)) :
  continuous_on (extend_from (Ioo a b) f) (Icc a b) :=
begin
  apply continuous_on_extend_from,
  { rw closure_Ioo hab, },
  { intros x x_in,
    rcases mem_Ioo_or_eq_endpoints_of_mem_Icc x_in with rfl | rfl | h,
    { use la,
      simpa [hab] },
    { use lb,
      simpa [hab] },
    { use [f x, hf x h] } }
end

lemma eq_lim_at_left_extend_from_Ioo [topological_space α] [linear_order α] [densely_ordered α]
  [order_topology α] [topological_space β] [t2_space β] {f : α → β} {a b : α}
  {la : β} (hab : a < b) (ha : tendsto f (𝓝[Ioi a] a) (𝓝 la)) :
  extend_from (Ioo a b) f a = la :=
begin
  apply extend_from_eq,
  { rw closure_Ioo hab,
    simp only [le_of_lt hab, left_mem_Icc, right_mem_Icc] },
  { simpa [hab] }
end

lemma eq_lim_at_right_extend_from_Ioo [topological_space α] [linear_order α] [densely_ordered α]
  [order_topology α] [topological_space β] [t2_space β] {f : α → β} {a b : α}
  {lb : β} (hab : a < b) (hb : tendsto f (𝓝[Iio b] b) (𝓝 lb)) :
  extend_from (Ioo a b) f b = lb :=
begin
  apply extend_from_eq,
  { rw closure_Ioo hab,
    simp only [le_of_lt hab, left_mem_Icc, right_mem_Icc] },
  { simpa [hab] }
end

lemma continuous_on_Ico_extend_from_Ioo [topological_space α]
  [linear_order α] [densely_ordered α] [order_topology α] [topological_space β]
  [regular_space β] {f : α → β} {a b : α} {la : β} (hab : a < b) (hf : continuous_on f (Ioo a b))
  (ha : tendsto f (𝓝[Ioi a] a) (𝓝 la)) :
  continuous_on (extend_from (Ioo a b) f) (Ico a b) :=
begin
  apply continuous_on_extend_from,
  { rw [closure_Ioo hab], exact Ico_subset_Icc_self, },
  { intros x x_in,
    rcases mem_Ioo_or_eq_left_of_mem_Ico x_in with rfl | h,
    { use la,
      simpa [hab] },
    { use [f x, hf x h] } }
end

lemma continuous_on_Ioc_extend_from_Ioo [topological_space α]
  [linear_order α] [densely_ordered α] [order_topology α] [topological_space β]
  [regular_space β] {f : α → β} {a b : α} {lb : β} (hab : a < b) (hf : continuous_on f (Ioo a b))
  (hb : tendsto f (𝓝[Iio b] b) (𝓝 lb)) :
  continuous_on (extend_from (Ioo a b) f) (Ioc a b) :=
begin
  have := @continuous_on_Ico_extend_from_Ioo (order_dual α) _ _ _ _ _ _ _ f _ _ _ hab,
  erw [dual_Ico, dual_Ioi, dual_Ioo] at this,
  exact this hf hb
end

lemma continuous_within_at_Ioi_iff_Ici {α β : Type*} [topological_space α] [partial_order α]
  [topological_space β] {a : α} {f : α → β} :
  continuous_within_at f (Ioi a) a ↔ continuous_within_at f (Ici a) a :=
by simp only [← Ici_diff_left, continuous_within_at_diff_self]

lemma continuous_within_at_Iio_iff_Iic
  {α β : Type*} [topological_space α] [linear_order α] [topological_space β] {a : α} {f : α → β} :
  continuous_within_at f (Iio a) a ↔ continuous_within_at f (Iic a) a :=
begin
  have := @continuous_within_at_Ioi_iff_Ici (order_dual α) _ _ _ _ _ f,
  erw [dual_Ici, dual_Ioi] at this,
  exact this,
end

lemma continuous_at_iff_continuous_left'_right' [topological_space α] [linear_order α]
  [topological_space β] {a : α} {f : α → β} :
  continuous_at f a ↔ continuous_within_at f (Iio a) a ∧ continuous_within_at f (Ioi a) a :=
by rw [continuous_within_at_Ioi_iff_Ici, continuous_within_at_Iio_iff_Iic,
  continuous_at_iff_continuous_left_right]

/-!
### Continuity of monotone functions

In this section we prove the following fact: if `f` is a monotone function on a neighborhood of `a`
and the image of this neighborhood is a neighborhood of `f a`, then `f` is continuous at `a`, see
`continuous_at_of_mono_incr_on_of_image_mem_nhds`, as well as several similar facts.
-/

section linear_order
variables [linear_order α] [topological_space α] [order_topology α]
variables [linear_order β] [topological_space β] [order_topology β]

/-- If `f` is a function strictly monotonically increasing on a right neighborhood of `a` and the
image of this neighborhood under `f` meets every interval `(f a, b]`, `b > f a`, then `f` is
continuous at `a` from the right.

The assumption `hfs : ∀ b > f a, ∃ c ∈ s, f c ∈ Ioc (f a) b` is required because otherwise the
function `f : ℝ → ℝ` given by `f x = if x ≤ 0 then x else x + 1` would be a counter-example at
`a = 0`. -/
lemma strict_mono_incr_on.continuous_at_right_of_exists_between {f : α → β} {s : set α} {a : α}
  (h_mono : strict_mono_incr_on f s) (hs : s ∈ 𝓝[Ici a] a)
  (hfs : ∀ b > f a, ∃ c ∈ s, f c ∈ Ioc (f a) b) :
  continuous_within_at f (Ici a) a :=
begin
  have ha : a ∈ Ici a := left_mem_Ici,
  have has : a ∈ s := mem_of_mem_nhds_within ha hs,
  refine tendsto_order.2 ⟨λ b hb, _, λ b hb, _⟩,
  { filter_upwards [hs, self_mem_nhds_within],
    intros x hxs hxa,
    exact hb.trans_le ((h_mono.le_iff_le has hxs).2 hxa) },
  { rcases hfs b hb with ⟨c, hcs, hac, hcb⟩,
    rw [h_mono.lt_iff_lt has hcs] at hac,
    filter_upwards [hs, Ico_mem_nhds_within_Ici (left_mem_Ico.2 hac)],
    rintros x hx ⟨hax, hxc⟩,
    exact ((h_mono.lt_iff_lt hx hcs).2 hxc).trans_le hcb }
end

/-- If `f` is a function monotonically increasing function on a right neighborhood of `a` and the
image of this neighborhood under `f` meets every interval `(f a, b)`, `b > f a`, then `f` is
continuous at `a` from the right.

The assumption `hfs : ∀ b > f a, ∃ c ∈ s, f c ∈ Ioo (f a) b` cannot be replaced by the weaker
assumption `hfs : ∀ b > f a, ∃ c ∈ s, f c ∈ Ioc (f a) b` we use for strictly monotone functions
because otherwise the function `ceil : ℝ → ℤ` would be a counter-example at `a = 0`. -/
lemma continuous_at_right_of_mono_incr_on_of_exists_between {f : α → β} {s : set α} {a : α}
  (h_mono : ∀ (x ∈ s) (y ∈ s), x ≤ y → f x ≤ f y) (hs : s ∈ 𝓝[Ici a] a)
  (hfs : ∀ b > f a, ∃ c ∈ s, f c ∈ Ioo (f a) b) :
  continuous_within_at f (Ici a) a :=
begin
  have ha : a ∈ Ici a := left_mem_Ici,
  have has : a ∈ s := mem_of_mem_nhds_within ha hs,
  refine tendsto_order.2 ⟨λ b hb, _, λ b hb, _⟩,
  { filter_upwards [hs, self_mem_nhds_within],
    intros x hxs hxa,
    exact hb.trans_le (h_mono _ has _ hxs hxa) },
  { rcases hfs b hb with ⟨c, hcs, hac, hcb⟩,
    have : a < c, from not_le.1 (λ h, hac.not_le $ h_mono _ hcs _ has h),
    filter_upwards [hs, Ico_mem_nhds_within_Ici (left_mem_Ico.2 this)],
    rintros x hx ⟨hax, hxc⟩,
    exact (h_mono _ hx _ hcs hxc.le).trans_lt hcb }
end

/-- If a function `f` with a densely ordered codomain is monotonically increasing on a right
neighborhood of `a` and the closure of the image of this neighborhood under `f` is a right
neighborhood of `f a`, then `f` is continuous at `a` from the right. -/
lemma continuous_at_right_of_mono_incr_on_of_closure_image_mem_nhds_within [densely_ordered β]
  {f : α → β} {s : set α} {a : α} (h_mono : ∀ (x ∈ s) (y ∈ s), x ≤ y → f x ≤ f y)
  (hs : s ∈ 𝓝[Ici a] a) (hfs : closure (f '' s) ∈ 𝓝[Ici (f a)] (f a)) :
  continuous_within_at f (Ici a) a :=
begin
  refine continuous_at_right_of_mono_incr_on_of_exists_between h_mono hs (λ b hb, _),
  rcases (mem_nhds_within_Ici_iff_exists_mem_Ioc_Ico_subset hb).1 hfs with ⟨b', ⟨hab', hbb'⟩, hb'⟩,
  rcases exists_between hab' with ⟨c', hc'⟩,
  rcases mem_closure_iff.1 (hb' ⟨hc'.1.le, hc'.2⟩) (Ioo (f a) b') is_open_Ioo hc'
    with ⟨_, hc, ⟨c, hcs, rfl⟩⟩,
  exact ⟨c, hcs, hc.1, hc.2.trans_le hbb'⟩
end

/-- If a function `f` with a densely ordered codomain is monotonically increasing on a right
neighborhood of `a` and the image of this neighborhood under `f` is a right neighborhood of `f a`,
then `f` is continuous at `a` from the right. -/
lemma continuous_at_right_of_mono_incr_on_of_image_mem_nhds_within [densely_ordered β] {f : α → β}
  {s : set α} {a : α} (h_mono : ∀ (x ∈ s) (y ∈ s), x ≤ y → f x ≤ f y) (hs : s ∈ 𝓝[Ici a] a)
  (hfs : f '' s ∈ 𝓝[Ici (f a)] (f a)) :
  continuous_within_at f (Ici a) a :=
continuous_at_right_of_mono_incr_on_of_closure_image_mem_nhds_within h_mono hs $
  mem_sets_of_superset hfs subset_closure

/-- If a function `f` with a densely ordered codomain is strictly monotonically increasing on a
right neighborhood of `a` and the closure of the image of this neighborhood under `f` is a right
neighborhood of `f a`, then `f` is continuous at `a` from the right. -/
lemma strict_mono_incr_on.continuous_at_right_of_closure_image_mem_nhds_within [densely_ordered β]
  {f : α → β} {s : set α} {a : α} (h_mono : strict_mono_incr_on f s) (hs : s ∈ 𝓝[Ici a] a)
  (hfs : closure (f '' s) ∈ 𝓝[Ici (f a)] (f a)) :
  continuous_within_at f (Ici a) a :=
continuous_at_right_of_mono_incr_on_of_closure_image_mem_nhds_within
  (λ x hx y hy, (h_mono.le_iff_le hx hy).2) hs hfs

/-- If a function `f` with a densely ordered codomain is strictly monotonically increasing on a
right neighborhood of `a` and the image of this neighborhood under `f` is a right neighborhood of
`f a`, then `f` is continuous at `a` from the right. -/
lemma strict_mono_incr_on.continuous_at_right_of_image_mem_nhds_within [densely_ordered β]
  {f : α → β} {s : set α} {a : α} (h_mono : strict_mono_incr_on f s) (hs : s ∈ 𝓝[Ici a] a)
  (hfs : f '' s ∈ 𝓝[Ici (f a)] (f a)) :
  continuous_within_at f (Ici a) a :=
h_mono.continuous_at_right_of_closure_image_mem_nhds_within hs
  (mem_sets_of_superset hfs subset_closure)

/-- If a function `f` is strictly monotonically increasing on a right neighborhood of `a` and the
image of this neighborhood under `f` includes `Ioi (f a)`, then `f` is continuous at `a` from the
right. -/
lemma strict_mono_incr_on.continuous_at_right_of_surj_on {f : α → β} {s : set α} {a : α}
  (h_mono : strict_mono_incr_on f s) (hs : s ∈ 𝓝[Ici a] a) (hfs : surj_on f s (Ioi (f a))) :
  continuous_within_at f (Ici a) a :=
h_mono.continuous_at_right_of_exists_between hs $ λ b hb, let ⟨c, hcs, hcb⟩ := hfs hb in
⟨c, hcs, hcb.symm ▸ hb, hcb.le⟩

/-- If `f` is a function strictly monotonically increasing on a left neighborhood of `a` and the
image of this neighborhood under `f` meets every interval `[b, f a)`, `b < f a`, then `f` is
continuous at `a` from the left.

The assumption `hfs : ∀ b < f a, ∃ c ∈ s, f c ∈ Ico b (f a)` is required because otherwise the
function `f : ℝ → ℝ` given by `f x = if x < 0 then x else x + 1` would be a counter-example at
`a = 0`. -/
lemma strict_mono_incr_on.continuous_at_left_of_exists_between {f : α → β} {s : set α} {a : α}
  (h_mono : strict_mono_incr_on f s) (hs : s ∈ 𝓝[Iic a] a)
  (hfs : ∀ b < f a, ∃ c ∈ s, f c ∈ Ico b (f a)) :
  continuous_within_at f (Iic a) a :=
h_mono.dual.continuous_at_right_of_exists_between hs $
  λ b hb, let ⟨c, hcs, hcb, hca⟩ := hfs b hb in ⟨c, hcs, hca, hcb⟩

/-- If `f` is a function monotonically increasing function on a left neighborhood of `a` and the
image of this neighborhood under `f` meets every interval `(b, f a)`, `b < f a`, then `f` is
continuous at `a` from the left.

The assumption `hfs : ∀ b < f a, ∃ c ∈ s, f c ∈ Ioo b (f a)` cannot be replaced by the weaker
assumption `hfs : ∀ b < f a, ∃ c ∈ s, f c ∈ Ico b (f a)` we use for strictly monotone functions
because otherwise the function `floor : ℝ → ℤ` would be a counter-example at `a = 0`. -/
lemma continuous_at_left_of_mono_incr_on_of_exists_between {f : α → β} {s : set α} {a : α}
  (h_mono : ∀ (x ∈ s) (y ∈ s), x ≤ y → f x ≤ f y) (hs : s ∈ 𝓝[Iic a] a)
  (hfs : ∀ b < f a, ∃ c ∈ s, f c ∈ Ioo b (f a)) :
  continuous_within_at f (Iic a) a :=
@continuous_at_right_of_mono_incr_on_of_exists_between (order_dual α) (order_dual β) _ _ _ _ _ _
  f s a (λ x hx y hy, h_mono y hy x hx) hs $
  λ b hb, let ⟨c, hcs, hcb, hca⟩ := hfs b hb in ⟨c, hcs, hca, hcb⟩

/-- If a function `f` with a densely ordered codomain is monotonically increasing on a left
neighborhood of `a` and the closure of the image of this neighborhood under `f` is a left
neighborhood of `f a`, then `f` is continuous at `a` from the left -/
lemma continuous_at_left_of_mono_incr_on_of_closure_image_mem_nhds_within [densely_ordered β]
  {f : α → β} {s : set α} {a : α} (h_mono : ∀ (x ∈ s) (y ∈ s), x ≤ y → f x ≤ f y)
  (hs : s ∈ 𝓝[Iic a] a) (hfs : closure (f '' s) ∈ 𝓝[Iic (f a)] (f a)) :
  continuous_within_at f (Iic a) a :=
@continuous_at_right_of_mono_incr_on_of_closure_image_mem_nhds_within (order_dual α) (order_dual β)
  _ _ _ _ _ _ _ f s a (λ x hx y hy, h_mono y hy x hx) hs hfs

/-- If a function `f` with a densely ordered codomain is monotonically increasing on a left
neighborhood of `a` and the image of this neighborhood under `f` is a left neighborhood of `f a`,
then `f` is continuous at `a` from the left. -/
lemma continuous_at_left_of_mono_incr_on_of_image_mem_nhds_within [densely_ordered β]
  {f : α → β} {s : set α} {a : α} (h_mono : ∀ (x ∈ s) (y ∈ s), x ≤ y → f x ≤ f y)
  (hs : s ∈ 𝓝[Iic a] a) (hfs : f '' s ∈ 𝓝[Iic (f a)] (f a)) :
  continuous_within_at f (Iic a) a :=
continuous_at_left_of_mono_incr_on_of_closure_image_mem_nhds_within h_mono hs
  (mem_sets_of_superset hfs subset_closure)

/-- If a function `f` with a densely ordered codomain is strictly monotonically increasing on a
left neighborhood of `a` and the closure of the image of this neighborhood under `f` is a left
neighborhood of `f a`, then `f` is continuous at `a` from the left. -/
lemma strict_mono_incr_on.continuous_at_left_of_closure_image_mem_nhds_within [densely_ordered β]
  {f : α → β} {s : set α} {a : α} (h_mono : strict_mono_incr_on f s) (hs : s ∈ 𝓝[Iic a] a)
  (hfs : closure (f '' s) ∈ 𝓝[Iic (f a)] (f a)) :
  continuous_within_at f (Iic a) a :=
h_mono.dual.continuous_at_right_of_closure_image_mem_nhds_within hs hfs

/-- If a function `f` with a densely ordered codomain is strictly monotonically increasing on a
left neighborhood of `a` and the image of this neighborhood under `f` is a left neighborhood of
`f a`, then `f` is continuous at `a` from the left. -/
lemma strict_mono_incr_on.continuous_at_left_of_image_mem_nhds_within [densely_ordered β]
  {f : α → β} {s : set α} {a : α} (h_mono : strict_mono_incr_on f s) (hs : s ∈ 𝓝[Iic a] a)
  (hfs : f '' s ∈ 𝓝[Iic (f a)] (f a)) :
  continuous_within_at f (Iic a) a :=
h_mono.dual.continuous_at_right_of_image_mem_nhds_within hs hfs

/-- If a function `f` is strictly monotonically increasing on a left neighborhood of `a` and the
image of this neighborhood under `f` includes `Iio (f a)`, then `f` is continuous at `a` from the
left. -/
lemma strict_mono_incr_on.continuous_at_left_of_surj_on {f : α → β} {s : set α} {a : α}
  (h_mono : strict_mono_incr_on f s) (hs : s ∈ 𝓝[Iic a] a) (hfs : surj_on f s (Iio (f a))) :
  continuous_within_at f (Iic a) a :=
h_mono.dual.continuous_at_right_of_surj_on hs hfs

/-- If a function `f` is strictly monotonically increasing on a neighborhood of `a` and the image of
this neighborhood under `f` meets every interval `[b, f a)`, `b < f a`, and every interval
`(f a, b]`, `b > f a`, then `f` is continuous at `a`. -/
lemma strict_mono_incr_on.continuous_at_of_exists_between {f : α → β} {s : set α} {a : α}
  (h_mono : strict_mono_incr_on f s) (hs : s ∈ 𝓝 a)
  (hfs_l : ∀ b < f a, ∃ c ∈ s, f c ∈ Ico b (f a)) (hfs_r : ∀ b > f a, ∃ c ∈ s, f c ∈ Ioc (f a) b) :
  continuous_at f a :=
continuous_at_iff_continuous_left_right.2
  ⟨h_mono.continuous_at_left_of_exists_between (mem_nhds_within_of_mem_nhds hs) hfs_l,
   h_mono.continuous_at_right_of_exists_between (mem_nhds_within_of_mem_nhds hs) hfs_r⟩

/-- If a function `f` with a densely ordered codomain is strictly monotonically increasing on a
neighborhood of `a` and the closure of the image of this neighborhood under `f` is a neighborhood of
`f a`, then `f` is continuous at `a`. -/
lemma strict_mono_incr_on.continuous_at_of_closure_image_mem_nhds [densely_ordered β] {f : α → β}
  {s : set α} {a : α} (h_mono : strict_mono_incr_on f s) (hs : s ∈ 𝓝 a)
  (hfs : closure (f '' s) ∈ 𝓝 (f a)) :
  continuous_at f a :=
continuous_at_iff_continuous_left_right.2
  ⟨h_mono.continuous_at_left_of_closure_image_mem_nhds_within (mem_nhds_within_of_mem_nhds hs)
     (mem_nhds_within_of_mem_nhds hfs),
   h_mono.continuous_at_right_of_closure_image_mem_nhds_within (mem_nhds_within_of_mem_nhds hs)
     (mem_nhds_within_of_mem_nhds hfs)⟩

/-- If a function `f` with a densely ordered codomain is strictly monotonically increasing on a
neighborhood of `a` and the image of this set under `f` is a neighborhood of `f a`, then `f` is
continuous at `a`. -/
lemma strict_mono_incr_on.continuous_at_of_image_mem_nhds [densely_ordered β] {f : α → β}
  {s : set α} {a : α} (h_mono : strict_mono_incr_on f s) (hs : s ∈ 𝓝 a) (hfs : f '' s ∈ 𝓝 (f a)) :
  continuous_at f a :=
h_mono.continuous_at_of_closure_image_mem_nhds hs (mem_sets_of_superset hfs subset_closure)

/-- If `f` is a function monotonically increasing function on a neighborhood of `a` and the image of
this neighborhood under `f` meets every interval `(b, f a)`, `b < f a`, and every interval `(f a,
b)`, `b > f a`, then `f` is continuous at `a`. -/
lemma continuous_at_of_mono_incr_on_of_exists_between {f : α → β} {s : set α} {a : α}
  (h_mono : ∀ (x ∈ s) (y ∈ s), x ≤ y → f x ≤ f y) (hs : s ∈ 𝓝 a)
  (hfs_l : ∀ b < f a, ∃ c ∈ s, f c ∈ Ioo b (f a)) (hfs_r : ∀ b > f a, ∃ c ∈ s, f c ∈ Ioo (f a) b) :
  continuous_at f a :=
continuous_at_iff_continuous_left_right.2
  ⟨continuous_at_left_of_mono_incr_on_of_exists_between h_mono
     (mem_nhds_within_of_mem_nhds hs) hfs_l,
   continuous_at_right_of_mono_incr_on_of_exists_between h_mono
     (mem_nhds_within_of_mem_nhds hs) hfs_r⟩

/-- If a function `f` with a densely ordered codomain is monotonically increasing on a neighborhood
of `a` and the closure of the image of this neighborhood under `f` is a neighborhood of `f a`, then
`f` is continuous at `a`. -/
lemma continuous_at_of_mono_incr_on_of_closure_image_mem_nhds [densely_ordered β] {f : α → β}
  {s : set α} {a : α} (h_mono : ∀ (x ∈ s) (y ∈ s), x ≤ y → f x ≤ f y) (hs : s ∈ 𝓝 a)
  (hfs : closure (f '' s) ∈ 𝓝 (f a)) :
  continuous_at f a :=
continuous_at_iff_continuous_left_right.2
  ⟨continuous_at_left_of_mono_incr_on_of_closure_image_mem_nhds_within h_mono
     (mem_nhds_within_of_mem_nhds hs) (mem_nhds_within_of_mem_nhds hfs),
   continuous_at_right_of_mono_incr_on_of_closure_image_mem_nhds_within h_mono
     (mem_nhds_within_of_mem_nhds hs) (mem_nhds_within_of_mem_nhds hfs)⟩

/-- If a function `f` with a densely ordered codomain is monotonically increasing on a neighborhood
of `a` and the image of this neighborhood under `f` is a neighborhood of `f a`, then `f` is
continuous at `a`. -/
lemma continuous_at_of_mono_incr_on_of_image_mem_nhds [densely_ordered β] {f : α → β}
  {s : set α} {a : α} (h_mono : ∀ (x ∈ s) (y ∈ s), x ≤ y → f x ≤ f y) (hs : s ∈ 𝓝 a)
  (hfs : f '' s ∈ 𝓝 (f a)) :
  continuous_at f a :=
continuous_at_of_mono_incr_on_of_closure_image_mem_nhds h_mono hs
  (mem_sets_of_superset hfs subset_closure)

/-- A monotone function with densely ordered codomain and a dense range is continuous. -/
lemma monotone.continuous_of_dense_range [densely_ordered β] {f : α → β}
  (h_mono : monotone f) (h_dense : dense_range f) :
  continuous f :=
continuous_iff_continuous_at.mpr $ λ a,
  continuous_at_of_mono_incr_on_of_closure_image_mem_nhds (λ x hx y hy hxy, h_mono hxy)
    univ_mem_sets $ by simp only [image_univ, h_dense.closure_eq, univ_mem_sets]

/-- A monotone surjective function with a densely ordered codomain is surjective. -/
lemma monotone.continuous_of_surjective [densely_ordered β] {f : α → β} (h_mono : monotone f)
  (h_surj : function.surjective f) :
  continuous f :=
h_mono.continuous_of_dense_range h_surj.dense_range

end linear_order

/-!
### Continuity of order isomorphisms

In this section we prove that an `order_iso` is continuous, hence it is a `homeomorph`. We prove
this for an `order_iso` between to partial orders with order topology.
-/

namespace order_iso

variables [partial_order α] [partial_order β] [topological_space α] [topological_space β]
  [order_topology α] [order_topology β]

protected lemma continuous (e : α ≃o β) : continuous e :=
begin
  rw [‹order_topology β›.topology_eq_generate_intervals],
  refine continuous_generated_from (λ s hs, _),
  rcases hs with ⟨a, rfl|rfl⟩,
  { rw e.preimage_Ioi, apply is_open_lt' },
  { rw e.preimage_Iio, apply is_open_gt' }
end

/-- An order isomorphism between two linear order `order_topology` spaces is a homeomorphism. -/
def to_homeomorph (e : α ≃o β) : α ≃ₜ β :=
{ continuous_to_fun := e.continuous,
  continuous_inv_fun := e.symm.continuous,
  .. e }

@[simp] lemma coe_to_homeomorph (e : α ≃o β) : ⇑e.to_homeomorph = e := rfl
@[simp] lemma coe_to_homeomorph_symm (e : α ≃o β) : ⇑e.to_homeomorph.symm = e.symm := rfl

end order_iso