import tactic.fin_cases
import tactic.apply_fun
import linear_algebra.finite_dimensional
import analysis.normed_space.basic
import linear_algebra.dual
import linear_algebra.basis
noncomputable theory

open function

section
local attribute [instance, priority 1] classical.prop_decidable
local attribute [instance, priority 0] set.decidable_mem_of_fintype

-- The next proof was found by `library_search`, there may be a more direct one
lemma set.to_finset_card {α : Type*} [fintype α] (H : set α) :
  H.to_finset.card = fintype.card H :=
multiset.card_map subtype.val (finset.univ.val)
end

section duality
open vector_space module module.dual linear_map function

local attribute [instance, priority 1] classical.prop_decidable
local attribute [instance, priority 0] set.decidable_mem_of_fintype

section

open module vector_space

universes u v w
variables {K : Type u} {V : Type v} {ι : Type w} [decidable_eq ι] [fintype ι] [decidable_eq V]
variables [discrete_field K] [add_comm_group V] [vector_space K V]
variables {b : ι → V} (h : is_basis K b)
include h

lemma fg_of_finite_basis  : submodule.fg (⊤ : submodule K V) :=
⟨ finset.univ.image b, by {convert h.2, simp} ⟩

def fin_dim_of_finite_basis : finite_dimensional K V :=
finite_dimensional.of_fg $ fg_of_finite_basis h

lemma dim_eq_card : dim K V = fintype.card ι :=
by rw [←h.mk_range_eq_dim, cardinal.fintype_card,
       set.card_range_of_injective (h.injective zero_ne_one)]

end

universes u v w
variables {K : Type u} {V : Type v} {ι : Type w} [decidable_eq ι]
variables [discrete_field K] [add_comm_group V] [vector_space K V]
          [decidable_eq V] [decidable_eq (ι → V)] [decidable_eq $ dual K V]

local notation `V'` := dual K V

/-- `e` and `ε` have characteristic properties of a basis and its dual -/
structure dual_pair (e : ι → V) (ε : ι → V') :=
(eval : ∀ i j : ι, ε i (e j) = if i = j then 1 else 0)
(total : ∀ {v : V}, (∀ i, ε i v = 0) → v = 0)
[finite : ∀ v : V, fintype {i | ε i v ≠ 0}]

variables {e : ι → V} {ε : ι → dual K V} (h : dual_pair e ε)

include  h
/-- The coefficients of `v` on the basis `e` -/
def dual_pair.coeffs (v : V) : ι →₀ K :=
{ to_fun := λ i, ε i v,
  support := by { haveI := h.finite v, exact {i : ι | ε i v ≠ 0}.to_finset },
  mem_support_to_fun := by {intro i, rw set.mem_to_finset, exact iff.rfl } }

omit h

@[simp]
lemma dual_pair.coeffs_apply (v : V) (i : ι) : h.coeffs v i = ε i v := rfl

def help_tcs : has_scalar K V := mul_action.to_has_scalar _ _

local attribute [instance] help_tcs

/-- linear combinations of elements of `e` -/
def dual_pair.lc (e : ι → V) (l : ι →₀ K) : V := l.sum (λ (i : ι) (a : K), a • (e i))

include h

lemma dual_pair.dual_lc (l : ι →₀ K) (i : ι) : ε i (dual_pair.lc e l) = l i :=
begin
  erw linear_map.map_sum,
  simp only [h.eval, map_smul, smul_eq_mul],
  rw finset.sum_eq_single i,
  { simp },
  { intros q q_in q_ne,
    simp [q_ne.symm] },
  { intro p_not_in,
    simp [finsupp.not_mem_support_iff.1 p_not_in] },
end

@[simp]
lemma dual_pair.coeffs_lc (l : ι →₀ K) : h.coeffs (dual_pair.lc e l) = l :=
by { ext i, rw [h.coeffs_apply, h.dual_lc] }

/-- For any v : V n, \sum_{p ∈ Q n} (ε p v) • e p = v -/
lemma dual_pair.decomposition (v : V) : dual_pair.lc e (h.coeffs v) = v :=
begin
  refine eq_of_sub_eq_zero (h.total _),
  intros i,
  simp [-sub_eq_add_neg, linear_map.map_sub, h.dual_lc, sub_eq_zero_iff_eq]
end

lemma dual_pair.mem_of_mem_span {H : set ι} {x : V} (hmem : x ∈ submodule.span K (e '' H)) :
  ∀ i : ι, ε i x ≠ 0 →  i ∈ H :=
begin
  intros i hi,
  rcases (finsupp.mem_span_iff_total _).mp hmem with ⟨l, supp_l, sum_l⟩,
  change dual_pair.lc e l = x at sum_l,
  rw finsupp.mem_supported' at supp_l,
  by_contradiction i_not,
  apply hi,
  rw ← sum_l,
  simpa [h.dual_lc] using supp_l i i_not,
end

lemma dual_pair.is_basis : is_basis K e :=
begin
  split,
  { rw linear_independent_iff,
    intros l H,
    change dual_pair.lc e l = 0 at H,
    ext i,
    apply_fun ε i at H,
    simpa [h.dual_lc] using H },
  { rw submodule.eq_top_iff',
    intro v,
    rw [← set.image_univ, finsupp.mem_span_iff_total],
    exact ⟨h.coeffs v, by simp, h.decomposition v⟩ },
end
omit h

lemma dual_pair.eq_dual  : ε = is_basis.dual_basis h.is_basis :=
begin
  funext i,
  refine h.is_basis.ext (λ _, _),
  erw [is_basis.to_dual_apply, h.eval]
end

end duality

lemma linear_map.map_finsupp_total {R : Type*} {β : Type*} {γ : Type*} [ring R] [decidable_eq R]
  [add_comm_group β] [decidable_eq β] [module R β]
  [add_comm_group γ] [decidable_eq γ] [module R γ]
  (f : β →ₗ[R] γ)
  {ι : Type*} [fintype ι] [decidable_eq ι]
  {g : ι → β} (l : ι →₀ R) : f (finsupp.total ι β R g l) = finsupp.total ι γ R (f ∘ g) l :=
begin
  rw [finsupp.total_apply,
     finsupp.total_apply, finsupp.sum, finsupp.sum, f.map_sum],
  congr,
  ext i,
  exact f.map_smul _ _,
end

lemma finset.sum_ite {α : Type*} [decidable_eq α] {β : Type*} [semiring β] (s : finset α)
  (P : set α) [decidable_pred P] [fintype P] (f : α → β) :
  s.sum (λ a, (f a) * (if P a then 1 else 0)) = (s ∩ P.to_finset).sum f :=
begin
  have : s ∩ P.to_finset ⊆ s,
  { exact finset.filter_subset _ },
  rw ← finset.sum_subset this,
  { apply finset.sum_congr rfl,
    intros x x_in,
    cases finset.mem_inter.mp x_in with _ x_in,
    replace x_in : P x := set.mem_to_finset.mp x_in,
    simp [x_in] },
  { intros x x_in x_not_in,
    suffices : ¬ P x, by simp [this],
    intros hPx,
    apply x_not_in,
    rw finset.mem_inter,
    exact ⟨x_in, set.mem_to_finset.mpr hPx⟩ },
end

section

local attribute [instance, priority 1] classical.prop_decidable
local attribute [instance, priority 0] set.decidable_mem_of_fintype

-- type class problems adding this to mathlib at data/set/finite
lemma finset.to_finset_inter {α : Type*} [fintype α] (s t : set α) [decidable_eq α] :
  (s ∩ t).to_finset = s.to_finset ∩ t.to_finset :=
by { ext x, simp }

end

lemma module.smul_eq_smul {R : Type*} [ring R] {β : Type*} [add_comm_group β] [module R β] (n : ℕ) (b : β) :
    n • b = (n : R) • b :=
begin
  induction n with n ih,
  { rw [nat.cast_zero, zero_smul, zero_smul] },
  { change (n + 1) • b = (n + 1 : R) • b,
    rw [add_smul, add_smul, one_smul, ih, one_smul] }
end

lemma finset.sum_const' {α : Type*} {R : Type*} [ring R] {β : Type*} [add_comm_group β] [module R β] {s : finset α} (b : β) :
    finset.sum s (λ (a : α), b) = (finset.card s : R) • b :=
begin
  rw [finset.sum_const, ← module.smul_eq_smul], refl,
end

lemma fintype.exists_max {α : Type*} [fintype α] [nonempty α] {β : Type*} [decidable_linear_order β] (f : α → β) :
  ∃ x₀ : α, ∀ x, f x ≤ f x₀ :=
begin
  let r := (set.range f).to_finset,
  obtain ⟨y, hy⟩ : ∃ y, y ∈ (set.range f).to_finset,
  { haveI := classical.inhabited_of_nonempty ‹nonempty α›,
    exact ⟨f (default α), set.mem_to_finset.mpr $ set.mem_range_self _⟩ },
  rcases finset.max_of_mem hy with ⟨y₀, h⟩,
  rcases set.mem_to_finset.1 (finset.mem_of_max h) with ⟨x₀, rfl⟩,
  use x₀,
  intro x,
  apply finset.le_max_of_mem (set.mem_to_finset.mpr $ set.mem_range_self x) h
end


/-
Copyright (c) 2021 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov
-/
import set_theory.cardinal.ordinal

/-!
# Cardinality of continuum

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

In this file we define `cardinal.continuum` (notation: `𝔠`, localized in `cardinal`) to be `2 ^ ℵ₀`.
We also prove some `simp` lemmas about cardinal arithmetic involving `𝔠`.

## Notation

- `𝔠` : notation for `cardinal.continuum` in locale `cardinal`.
-/

namespace cardinal

universes u v

open_locale cardinal

/-- Cardinality of continuum. -/
def continuum : cardinal.{u} := 2 ^ aleph_0.{u}

localized "notation (name := cardinal.continuum) `𝔠` := cardinal.continuum" in cardinal

@[simp] lemma two_power_aleph_0 : 2 ^ aleph_0.{u} = continuum.{u} := rfl

@[simp] lemma lift_continuum : lift.{v} 𝔠 = 𝔠 :=
by rw [←two_power_aleph_0, lift_two_power, lift_aleph_0, two_power_aleph_0]

/-!
### Inequalities
-/

lemma aleph_0_lt_continuum : ℵ₀ < 𝔠 := cantor ℵ₀

lemma aleph_0_le_continuum : ℵ₀ ≤ 𝔠 := aleph_0_lt_continuum.le

@[simp] lemma beth_one : beth 1 = 𝔠 := by simpa using beth_succ 0

lemma nat_lt_continuum (n : ℕ) : ↑n < 𝔠 := (nat_lt_aleph_0 n).trans aleph_0_lt_continuum

lemma mk_set_nat : #(set ℕ) = 𝔠 := by simp

lemma continuum_pos : 0 < 𝔠 := nat_lt_continuum 0

lemma continuum_ne_zero : 𝔠 ≠ 0 := continuum_pos.ne'

lemma aleph_one_le_continuum : aleph 1 ≤ 𝔠 :=
by { rw ←succ_aleph_0, exact order.succ_le_of_lt aleph_0_lt_continuum }

@[simp] theorem continuum_to_nat : continuum.to_nat = 0 :=
to_nat_apply_of_aleph_0_le aleph_0_le_continuum

@[simp] theorem continuum_to_part_enat : continuum.to_part_enat = ⊤ :=
to_part_enat_apply_of_aleph_0_le aleph_0_le_continuum

/-!
### Addition
-/

@[simp] lemma aleph_0_add_continuum : ℵ₀ + 𝔠 = 𝔠 :=
add_eq_right aleph_0_le_continuum aleph_0_le_continuum

@[simp] lemma continuum_add_aleph_0 : 𝔠 + ℵ₀ = 𝔠 :=
(add_comm _ _).trans aleph_0_add_continuum

@[simp] lemma continuum_add_self : 𝔠 + 𝔠 = 𝔠 :=
add_eq_right aleph_0_le_continuum le_rfl

@[simp] lemma nat_add_continuum (n : ℕ) : ↑n + 𝔠 = 𝔠 :=
add_eq_right aleph_0_le_continuum (nat_lt_continuum n).le

@[simp] lemma continuum_add_nat (n : ℕ) : 𝔠 + n = 𝔠 :=
(add_comm _ _).trans (nat_add_continuum n)

/-!
### Multiplication
-/

@[simp]

@[simp] lemma continuum_mul_aleph_0 : 𝔠 * ℵ₀ = 𝔠 :=
mul_eq_left aleph_0_le_continuum aleph_0_le_continuum aleph_0_ne_zero

@[simp] lemma aleph_0_mul_continuum : ℵ₀ * 𝔠 = 𝔠 :=
(mul_comm _ _).trans continuum_mul_aleph_0

@[simp] lemma nat_mul_continuum {n : ℕ} (hn : n ≠ 0) : ↑n * 𝔠 = 𝔠 :=
mul_eq_right aleph_0_le_continuum (nat_lt_continuum n).le (nat.cast_ne_zero.2 hn)

@[simp] lemma continuum_mul_nat {n : ℕ} (hn : n ≠ 0) : 𝔠 * n = 𝔠 :=
(mul_comm _ _).trans (nat_mul_continuum hn)

/-!
### Power
-/

@[simp] lemma aleph_0_power_aleph_0 : aleph_0.{u} ^ aleph_0.{u} = 𝔠 :=
power_self_eq le_rfl

@[simp] lemma nat_power_aleph_0 {n : ℕ} (hn : 2 ≤ n) : (n ^ aleph_0.{u} : cardinal.{u}) = 𝔠 :=
nat_power_eq le_rfl hn

@[simp] lemma continuum_power_aleph_0 : continuum.{u} ^ aleph_0.{u} = 𝔠 :=
by rw [←two_power_aleph_0, ←power_mul, mul_eq_left le_rfl le_rfl aleph_0_ne_zero]

end cardinal


/-
Copyright (c) 2020 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison
-/
import data.polynomial.derivative
import data.nat.choose.sum
import ring_theory.polynomial.pochhammer
import data.polynomial.algebra_map
import linear_algebra.linear_independent
import data.mv_polynomial.pderiv

/-!
# Bernstein polynomials

The definition of the Bernstein polynomials
```
bernstein_polynomial (R : Type*) [comm_ring R] (n ν : ℕ) : R[X] :=
(choose n ν) * X^ν * (1 - X)^(n - ν)
```
and the fact that for `ν : fin (n+1)` these are linearly independent over `ℚ`.

We prove the basic identities
* `(finset.range (n + 1)).sum (λ ν, bernstein_polynomial R n ν) = 1`
* `(finset.range (n + 1)).sum (λ ν, ν • bernstein_polynomial R n ν) = n • X`
* `(finset.range (n + 1)).sum (λ ν, (ν * (ν-1)) • bernstein_polynomial R n ν) = (n * (n-1)) • X^2`

## Notes

See also `analysis.special_functions.bernstein`, which defines the Bernstein approximations
of a continuous function `f : C([0,1], ℝ)`, and shows that these converge uniformly to `f`.
-/

noncomputable theory

open nat (choose)
open polynomial (X)
open_locale big_operators polynomial

variables (R : Type*) [comm_ring R]

/--
`bernstein_polynomial R n ν` is `(choose n ν) * X^ν * (1 - X)^(n - ν)`.

Although the coefficients are integers, it is convenient to work over an arbitrary commutative ring.
-/
def bernstein_polynomial (n ν : ℕ) : R[X] := choose n ν * X^ν * (1 - X)^(n - ν)

example : bernstein_polynomial ℤ 3 2 = 3 * X^2 - 3 * X^3 :=
begin
  norm_num [bernstein_polynomial, choose],
  ring,
end

namespace bernstein_polynomial

lemma eq_zero_of_lt {n ν : ℕ} (h : n < ν) : bernstein_polynomial R n ν = 0 :=
by simp [bernstein_polynomial, nat.choose_eq_zero_of_lt h]

section
variables {R} {S : Type*} [comm_ring S]

@[simp] lemma map (f : R →+* S) (n ν : ℕ) :
  (bernstein_polynomial R n ν).map f = bernstein_polynomial S n ν :=
by simp [bernstein_polynomial]

end

lemma flip (n ν : ℕ) (h : ν ≤ n) :
  (bernstein_polynomial R n ν).comp (1-X) = bernstein_polynomial R n (n-ν) :=
begin
  dsimp [bernstein_polynomial],
  simp [h, tsub_tsub_assoc, mul_right_comm],
end

lemma flip' (n ν : ℕ) (h : ν ≤ n) :
  bernstein_polynomial R n ν = (bernstein_polynomial R n (n-ν)).comp (1-X) :=
begin
  rw [←flip _ _ _ h, polynomial.comp_assoc],
  simp,
end

lemma eval_at_0 (n ν : ℕ) : (bernstein_polynomial R n ν).eval 0 = if ν = 0 then 1 else 0 :=
begin
  dsimp [bernstein_polynomial],
  split_ifs,
  { subst h, simp, },
  { simp [zero_pow (nat.pos_of_ne_zero h)], },
end

lemma eval_at_1 (n ν : ℕ) : (bernstein_polynomial R n ν).eval 1 = if ν = n then 1 else 0 :=
begin
  dsimp [bernstein_polynomial],
  split_ifs,
  { subst h, simp, },
  { obtain w | w := (n - ν).eq_zero_or_pos,
    { simp [nat.choose_eq_zero_of_lt ((tsub_eq_zero_iff_le.mp w).lt_of_ne (ne.symm h))] },
    { simp [zero_pow w] } },
end.

lemma derivative_succ_aux (n ν : ℕ) :
  (bernstein_polynomial R (n+1) (ν+1)).derivative =
    (n+1) * (bernstein_polynomial R n ν - bernstein_polynomial R n (ν + 1)) :=
begin
  dsimp [bernstein_polynomial],
  suffices :
    ↑((n + 1).choose (ν + 1)) * ((↑ν + 1) * X ^ ν) * (1 - X) ^ (n - ν)
      -(↑((n + 1).choose (ν + 1)) * X ^ (ν + 1) * (↑(n - ν) * (1 - X) ^ (n - ν - 1))) =
    (↑n + 1) * (↑(n.choose ν) * X ^ ν * (1 - X) ^ (n - ν) -
         ↑(n.choose (ν + 1)) * X ^ (ν + 1) * (1 - X) ^ (n - (ν + 1))),
  { simpa [polynomial.derivative_pow, ←sub_eq_add_neg], },
  conv_rhs { rw mul_sub, },
  -- We'll prove the two terms match up separately.
  refine congr (congr_arg has_sub.sub _) _,
  { simp only [←mul_assoc],
    refine congr (congr_arg (*) (congr (congr_arg (*) _) rfl)) rfl,
    -- Now it's just about binomial coefficients
    exact_mod_cast congr_arg (λ m : ℕ, (m : R[X])) (nat.succ_mul_choose_eq n ν).symm, },
  { rw [← tsub_add_eq_tsub_tsub, ← mul_assoc, ← mul_assoc], congr' 1,
    rw mul_comm , rw [←mul_assoc,←mul_assoc],  congr' 1,
    norm_cast,
    congr' 1,
    convert (nat.choose_mul_succ_eq n (ν + 1)).symm using 1,
    { convert mul_comm _ _ using 2,
      simp, },
    { apply mul_comm, }, },
end

lemma derivative_succ (n ν : ℕ) :
  (bernstein_polynomial R n (ν+1)).derivative =
    n * (bernstein_polynomial R (n-1) ν - bernstein_polynomial R (n-1) (ν+1)) :=
begin
  cases n,
  { simp [bernstein_polynomial], },
  { apply derivative_succ_aux, }
end

lemma derivative_zero (n : ℕ) :
  (bernstein_polynomial R n 0).derivative = -n * bernstein_polynomial R (n-1) 0 :=
begin
  dsimp [bernstein_polynomial],
  simp [polynomial.derivative_pow],
end

lemma iterate_derivative_at_0_eq_zero_of_lt (n : ℕ) {ν k : ℕ} :
  k < ν → (polynomial.derivative^[k] (bernstein_polynomial R n ν)).eval 0 = 0 :=
begin
  cases ν,
  { rintro ⟨⟩, },
  { rw nat.lt_succ_iff,
    induction k with k ih generalizing n ν,
    { simp [eval_at_0], },
    { simp only [derivative_succ, int.coe_nat_eq_zero, int.nat_cast_eq_coe_nat, mul_eq_zero,
        function.comp_app, function.iterate_succ,
        polynomial.iterate_derivative_sub, polynomial.iterate_derivative_cast_nat_mul,
        polynomial.eval_mul, polynomial.eval_nat_cast, polynomial.eval_sub],
      intro h,
      apply mul_eq_zero_of_right,
      rw [ih _ _ (nat.le_of_succ_le h), sub_zero],
      convert ih _ _ (nat.pred_le_pred h),
      exact (nat.succ_pred_eq_of_pos (k.succ_pos.trans_le h)).symm } },
end

@[simp]
lemma iterate_derivative_succ_at_0_eq_zero (n ν : ℕ) :
  (polynomial.derivative^[ν] (bernstein_polynomial R n (ν+1))).eval 0 = 0 :=
iterate_derivative_at_0_eq_zero_of_lt R n (lt_add_one ν)

open polynomial

@[simp]

lemma iterate_derivative_at_0_ne_zero [char_zero R] (n ν : ℕ) (h : ν ≤ n) :
  (polynomial.derivative^[ν] (bernstein_polynomial R n ν)).eval 0 ≠ 0 :=
begin
  simp only [int.coe_nat_eq_zero, bernstein_polynomial.iterate_derivative_at_0, ne.def,
    nat.cast_eq_zero],
  simp only [←pochhammer_eval_cast],
  norm_cast,
  apply ne_of_gt,
  obtain rfl|h' := nat.eq_zero_or_pos ν,
  { simp, },
  { rw ← nat.succ_pred_eq_of_pos h' at h,
    exact pochhammer_pos _ _ (tsub_pos_of_lt (nat.lt_of_succ_le h)) }
end

/-!
Rather than redoing the work of evaluating the derivatives at 1,
we use the symmetry of the Bernstein polynomials.
-/
lemma iterate_derivative_at_1_eq_zero_of_lt (n : ℕ) {ν k : ℕ} :
  k < n - ν → (polynomial.derivative^[k] (bernstein_polynomial R n ν)).eval 1 = 0 :=
begin
  intro w,
  rw flip' _ _ _ (tsub_pos_iff_lt.mp (pos_of_gt w)).le,
  simp [polynomial.eval_comp, iterate_derivative_at_0_eq_zero_of_lt R n w],
end

@[simp]
lemma iterate_derivative_at_1 (n ν : ℕ) (h : ν ≤ n) :
  (polynomial.derivative^[n-ν] (bernstein_polynomial R n ν)).eval 1 =
    (-1)^(n-ν) * (pochhammer R (n - ν)).eval (ν + 1) :=
begin
  rw flip' _ _ _ h,
  simp [polynomial.eval_comp, h],
  obtain rfl | h' := h.eq_or_lt,
  { simp, },
  { congr,
    norm_cast,
    rw [← tsub_add_eq_tsub_tsub, tsub_tsub_cancel_of_le (nat.succ_le_iff.mpr h')] },
end

lemma iterate_derivative_at_1_ne_zero [char_zero R] (n ν : ℕ) (h : ν ≤ n) :
  (polynomial.derivative^[n-ν] (bernstein_polynomial R n ν)).eval 1 ≠ 0 :=
begin
  rw [bernstein_polynomial.iterate_derivative_at_1 _ _ _ h, ne.def, neg_one_pow_mul_eq_zero_iff,
    ←nat.cast_succ, ←pochhammer_eval_cast, ←nat.cast_zero, nat.cast_inj],
  exact (pochhammer_pos _ _ (nat.succ_pos ν)).ne',
end

open submodule

lemma linear_independent_aux (n k : ℕ) (h : k ≤ n + 1):
  linear_independent ℚ (λ ν : fin k, bernstein_polynomial ℚ n ν) :=
begin
  induction k with k ih,
  { apply linear_independent_empty_type, },
  { apply linear_independent_fin_succ'.mpr,
    fsplit,
    { exact ih (le_of_lt h), },
    { -- The actual work!
      -- We show that the (n-k)-th derivative at 1 doesn't vanish,
      -- but vanishes for everything in the span.
      clear ih,
      simp only [nat.succ_eq_add_one, add_le_add_iff_right] at h,
      simp only [fin.coe_last, fin.init_def],
      dsimp,
      apply not_mem_span_of_apply_not_mem_span_image ((@polynomial.derivative ℚ _)^(n-k)),
      simp only [not_exists, not_and, submodule.mem_map, submodule.span_image],
      intros p m,
      apply_fun (polynomial.eval (1 : ℚ)),
      simp only [linear_map.pow_apply],
      -- The right hand side is nonzero,
      -- so it will suffice to show the left hand side is always zero.
      suffices : (polynomial.derivative^[n-k] p).eval 1 = 0,
      { rw [this],
        exact (iterate_derivative_at_1_ne_zero ℚ n k h).symm, },
      apply span_induction m,
      { simp,
        rintro ⟨a, w⟩, simp only [fin.coe_mk],
        rw [iterate_derivative_at_1_eq_zero_of_lt ℚ n ((tsub_lt_tsub_iff_left_of_le h).mpr w)] },
      { simp, },
      { intros x y hx hy, simp [hx, hy], },
      { intros a x h, simp [h], }, }, },
end

/--
The Bernstein polynomials are linearly independent.

We prove by induction that the collection of `bernstein_polynomial n ν` for `ν = 0, ..., k`
are linearly independent.
The inductive step relies on the observation that the `(n-k)`-th derivative, evaluated at 1,
annihilates `bernstein_polynomial n ν` for `ν < k`, but has a nonzero value at `ν = k`.
-/

lemma linear_independent (n : ℕ) :
  linear_independent ℚ (λ ν : fin (n+1), bernstein_polynomial ℚ n ν) :=
linear_independent_aux n (n+1) le_rfl

lemma sum (n : ℕ) : ∑ ν in finset.range (n + 1), bernstein_polynomial R n ν = 1 :=
calc ∑ ν in finset.range (n + 1), bernstein_polynomial R n ν = (X + (1 - X)) ^ n :
  by { rw add_pow, simp only [bernstein_polynomial, mul_comm, mul_assoc, mul_left_comm] }
... = 1 : by simp

open polynomial
open mv_polynomial

lemma sum_smul (n : ℕ) :
  ∑ ν in finset.range (n + 1), ν • bernstein_polynomial R n ν = n • X :=
begin
  -- We calculate the `x`-derivative of `(x+y)^n`, evaluated at `y=(1-x)`,
  -- either directly or by using the binomial theorem.

  -- We'll work in `mv_polynomial bool R`.
  let x : mv_polynomial bool R := mv_polynomial.X tt,
  let y : mv_polynomial bool R := mv_polynomial.X ff,

  have pderiv_tt_x : pderiv tt x = 1, { simp [x], },
  have pderiv_tt_y : pderiv tt y = 0, { simp [pderiv_X, y], },

  let e : bool → R[X] := λ i, cond i X (1-X),

  -- Start with `(x+y)^n = (x+y)^n`,
  -- take the `x`-derivative, evaluate at `x=X, y=1-X`, and multiply by `X`:
  have h : (x+y)^n = (x+y)^n := rfl,
  apply_fun (pderiv tt) at h,
  apply_fun (aeval e) at h,
  apply_fun (λ p, p * X) at h,

  -- On the left hand side we'll use the binomial theorem, then simplify.

  -- We first prepare a tedious rewrite:
  have w : ∀ k : ℕ,
    ↑k * polynomial.X ^ (k - 1) * (1 - polynomial.X) ^ (n - k) * ↑(n.choose k) * polynomial.X =
      k • bernstein_polynomial R n k,
  { rintro (_|k),
    { simp, },
    { dsimp [bernstein_polynomial],
      simp only [←nat_cast_mul, nat.succ_eq_add_one, nat.add_succ_sub_one, add_zero, pow_succ],
      push_cast,
      ring, }, },

  conv at h
  { to_lhs,
    rw [add_pow, (pderiv tt).map_sum, (mv_polynomial.aeval e).map_sum, finset.sum_mul],
    -- Step inside the sum:
    apply_congr, skip,
    simp [pderiv_mul, pderiv_tt_x, pderiv_tt_y, e, w], },
  -- On the right hand side, we'll just simplify.
  conv at h
  { to_rhs,
    rw [(pderiv tt).leibniz_pow, (pderiv tt).map_add, pderiv_tt_x, pderiv_tt_y],
    simp [e] },
  simpa using h,
end

lemma sum_mul_smul (n : ℕ) :
  ∑ ν in finset.range (n + 1), (ν * (ν-1)) • bernstein_polynomial R n ν = (n * (n-1)) • X^2 :=
begin
  -- We calculate the second `x`-derivative of `(x+y)^n`, evaluated at `y=(1-x)`,
  -- either directly or by using the binomial theorem.

  -- We'll work in `mv_polynomial bool R`.
  let x : mv_polynomial bool R := mv_polynomial.X tt,
  let y : mv_polynomial bool R := mv_polynomial.X ff,

  have pderiv_tt_x : pderiv tt x = 1, { simp [x], },
  have pderiv_tt_y : pderiv tt y = 0, { simp [pderiv_X, y], },

  let e : bool → R[X] := λ i, cond i X (1-X),

  -- Start with `(x+y)^n = (x+y)^n`,
  -- take the second `x`-derivative, evaluate at `x=X, y=1-X`, and multiply by `X`:
  have h : (x+y)^n = (x+y)^n := rfl,
  apply_fun (pderiv tt) at h,
  apply_fun (pderiv tt) at h,
  apply_fun (aeval e) at h,
  apply_fun (λ p, p * X^2) at h,

  -- On the left hand side we'll use the binomial theorem, then simplify.

  -- We first prepare a tedious rewrite:
  have w : ∀ k : ℕ,
    ↑k * (↑(k-1) * polynomial.X ^ (k - 1 - 1)) *
      (1 - polynomial.X) ^ (n - k) * ↑(n.choose k) * polynomial.X^2 =
      (k * (k-1)) • bernstein_polynomial R n k,
  { rintro (_|k),
    { simp, },
    { rcases k with (_|k),
      { simp, },
      { dsimp [bernstein_polynomial],
        simp only [←nat_cast_mul, nat.succ_eq_add_one, nat.add_succ_sub_one, add_zero, pow_succ],
        push_cast,
        ring, }, }, },

  conv at h
  { to_lhs,
    rw [add_pow, (pderiv tt).map_sum, (pderiv tt).map_sum, (mv_polynomial.aeval e).map_sum,
      finset.sum_mul],
    -- Step inside the sum:
    apply_congr, skip,
    simp [pderiv_mul, pderiv_tt_x, pderiv_tt_y, e, w] },
  -- On the right hand side, we'll just simplify.
  conv at h
  { to_rhs,
    simp only [pderiv_one, pderiv_mul, (pderiv _).leibniz_pow, (pderiv _).map_coe_nat,
      (pderiv tt).map_add, pderiv_tt_x, pderiv_tt_y],
    simp [e, smul_smul] },
  simpa using h,
end

/--
A certain linear combination of the previous three identities,
which we'll want later.
-/
lemma variance (n : ℕ) :
  ∑ ν in finset.range (n+1), (n • polynomial.X - ν)^2 * bernstein_polynomial R n ν =
    n • polynomial.X * (1 - polynomial.X) :=
begin
  have p :
    (finset.range (n+1)).sum (λ ν, (ν * (ν-1)) • bernstein_polynomial R n ν) +
    (1 - (2 * n) • polynomial.X) * (finset.range (n+1)).sum (λ ν, ν • bernstein_polynomial R n ν) +
    (n^2 • X^2) * (finset.range (n+1)).sum (λ ν, bernstein_polynomial R n ν) = _ := rfl,
  conv at p { to_lhs,
    rw [finset.mul_sum, finset.mul_sum, ←finset.sum_add_distrib, ←finset.sum_add_distrib],
    simp only [←nat_cast_mul],
    simp only [←mul_assoc],
    simp only [←add_mul], },
  conv at p { to_rhs,
    rw [sum, sum_smul, sum_mul_smul, ←nat_cast_mul], },
  calc _ = _ : finset.sum_congr rfl (λ k m, _)
     ... = _ : p
     ... = _ : _,
  { congr' 1, simp only [←nat_cast_mul] with push_cast,
    cases k; { simp, ring, }, },
  { simp only [←nat_cast_mul] with push_cast,
    cases n,
    { simp, },
    { simp, ring, }, },
end

end bernstein_polynomial


/-
Copyright (c) 2022 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov, Heather Macbeth

! This file was ported from Lean 3 source module analysis.normed.group.ball_sphere
! leanprover-community/mathlib commit 3339976e2bcae9f1c81e620836d1eb736e3c4700
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Analysis.Normed.Group.Basic

/-!
# Negation on spheres and balls

In this file we define `InvolutiveNeg` and `ContinuousNeg` instances for spheres, open balls, and
closed balls in a semi normed group.
-/

open Metric Set

variable {E : Type _} [i : SeminormedAddCommGroup E] {r : ℝ}

/-- We equip the sphere, in a seminormed group, with a formal operation of negation, namely the
antipodal map. -/
instance : InvolutiveNeg (sphere (0 : E) r) where
  neg := Subtype.map Neg.neg fun w => by simp
  neg_neg x := Subtype.ext <| neg_neg x.1

@[simp]
theorem coe_neg_sphere {r : ℝ} (v : sphere (0 : E) r) : ↑(-v) = (-v : E) :=
  rfl
#align coe_neg_sphere coe_neg_sphere

-- porting note: todo: need to specify instance to avoid timeout
instance : ContinuousNeg (sphere (0 : E) r) :=
  @Inducing.continuousNeg (sphere (0 : E) r) E _ _ _ _ TopologicalAddGroup.toContinuousNeg
    Subtype.val inducing_subtype_val fun _ => rfl

/-- We equip the ball, in a seminormed group, with a formal operation of negation, namely the
antipodal map. -/
instance {r : ℝ} : InvolutiveNeg (ball (0 : E) r) where
  neg := Subtype.map Neg.neg fun w => by simp
  neg_neg x := Subtype.ext <| neg_neg x.1

@[simp] theorem coe_neg_ball {r : ℝ} (v : ball (0 : E) r) : ↑(-v) = (-v : E) := rfl
#align coe_neg_ball coe_neg_ball

-- porting note: todo: need to specify instance to avoid timeout
instance : ContinuousNeg (ball (0 : E) r) :=
  @Inducing.continuousNeg (ball (0 : E) r) E _ _ _ _ TopologicalAddGroup.toContinuousNeg
    Subtype.val inducing_subtype_val fun _ => rfl

/-- We equip the closed ball, in a seminormed group, with a formal operation of negation, namely the
antipodal map. -/
instance {r : ℝ} : InvolutiveNeg (closedBall (0 : E) r) where
  neg := Subtype.map Neg.neg fun w => by simp
  neg_neg x := Subtype.ext <| neg_neg x.1

@[simp] theorem coe_neg_closedBall {r : ℝ} (v : closedBall (0 : E) r) : ↑(-v) = (-v : E) := rfl
#align coe_neg_closed_ball coe_neg_closedBall

-- porting note: todo: need to specify instance to avoid timeout
instance : ContinuousNeg (closedBall (0 : E) r) :=
  @Inducing.continuousNeg (closedBall (0 : E) r) E _ _ _ _ TopologicalAddGroup.toContinuousNeg
    Subtype.val inducing_subtype_val fun _ => rfl


import tactic

lemma binomial_solution (x : ℤ) : x ^ 2 - 2 * x + 1 = 0 ↔ x = 1 :=
begin
  split; intro h,
  { have : (x - 1) ^ 2 = x ^ 2 - 2 * x + 1 := by {
      rw[pow_two, pow_two, two_mul, mul_sub, mul_one, sub_mul, one_mul],
      rw[← sub_add, sub_add_eq_sub_sub]
    },
    rw[← this] at h,
    exact sub_eq_zero.mp (pow_eq_zero h)
  },
  { rw[h], refl }
end

lemma binomial_solution' (x : ℤ) : x ^ 2 - 2 * x + 1 = 0 ↔ x = 1 :=
  by { split; intro h, nlinarith, simp[h], refl }

#print binomial_solution


/-
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, Patrick Massot, Yury Kudryashov, Rémy Degenne
Ported by: Winston Yin, Arien Malec

! This file was ported from Lean 3 source module data.set.intervals.basic
! leanprover-community/mathlib commit 198161d833f2c01498c39c266b0b3dbe2c7a8c07
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Order.MinMax
import Mathlib.Data.Set.Prod

/-!
# Intervals

In any preorder `α`, we define intervals (which on each side can be either infinite, open, or
closed) using the following naming conventions:
- `i`: infinite
- `o`: open
- `c`: closed

Each interval has the name `I` + letter for left side + letter for right side. For instance,
`Ioc a b` denotes the inverval `(a, b]`.

This file contains these definitions, and basic facts on inclusion, intersection, difference of
intervals (where the precise statements may depend on the properties of the order, in particular
for some statements it should be `LinearOrder` or `DenselyOrdered`).

TODO: This is just the beginning; a lot of rules are missing
-/

open Function

open OrderDual (toDual ofDual)

variable {α β : Type _}

namespace Set

section Preorder

variable [Preorder α] {a a₁ a₂ b b₁ b₂ c x : α}

/-- Left-open right-open interval -/
def Ioo (a b : α) :=
  { x | a < x ∧ x < b }
#align set.Ioo Set.Ioo

/-- Left-closed right-open interval -/
def Ico (a b : α) :=
  { x | a ≤ x ∧ x < b }
#align set.Ico Set.Ico

/-- Left-infinite right-open interval -/
def Iio (a : α) :=
  { x | x < a }
#align set.Iio Set.Iio

/-- Left-closed right-closed interval -/
def Icc (a b : α) :=
  { x | a ≤ x ∧ x ≤ b }
#align set.Icc Set.Icc

/-- Left-infinite right-closed interval -/
def Iic (b : α) :=
  { x | x ≤ b }
#align set.Iic Set.Iic

/-- Left-open right-closed interval -/
def Ioc (a b : α) :=
  { x | a < x ∧ x ≤ b }
#align set.Ioc Set.Ioc

/-- Left-closed right-infinite interval -/
def Ici (a : α) :=
  { x | a ≤ x }
#align set.Ici Set.Ici

/-- Left-open right-infinite interval -/
def Ioi (a : α) :=
  { x | a < x }
#align set.Ioi Set.Ioi

theorem Ioo_def (a b : α) : { x | a < x ∧ x < b } = Ioo a b :=
  rfl
#align set.Ioo_def Set.Ioo_def

theorem Ico_def (a b : α) : { x | a ≤ x ∧ x < b } = Ico a b :=
  rfl
#align set.Ico_def Set.Ico_def

theorem Iio_def (a : α) : { x | x < a } = Iio a :=
  rfl
#align set.Iio_def Set.Iio_def

theorem Icc_def (a b : α) : { x | a ≤ x ∧ x ≤ b } = Icc a b :=
  rfl
#align set.Icc_def Set.Icc_def

theorem Iic_def (b : α) : { x | x ≤ b } = Iic b :=
  rfl
#align set.Iic_def Set.Iic_def

theorem Ioc_def (a b : α) : { x | a < x ∧ x ≤ b } = Ioc a b :=
  rfl
#align set.Ioc_def Set.Ioc_def

theorem Ici_def (a : α) : { x | a ≤ x } = Ici a :=
  rfl
#align set.Ici_def Set.Ici_def

theorem Ioi_def (a : α) : { x | a < x } = Ioi a :=
  rfl
#align set.Ioi_def Set.Ioi_def

@[simp]
theorem mem_Ioo : x ∈ Ioo a b ↔ a < x ∧ x < b :=
  Iff.rfl
#align set.mem_Ioo Set.mem_Ioo

@[simp]
theorem mem_Ico : x ∈ Ico a b ↔ a ≤ x ∧ x < b :=
  Iff.rfl
#align set.mem_Ico Set.mem_Ico

@[simp]
theorem mem_Iio : x ∈ Iio b ↔ x < b :=
  Iff.rfl
#align set.mem_Iio Set.mem_Iio

@[simp]
theorem mem_Icc : x ∈ Icc a b ↔ a ≤ x ∧ x ≤ b :=
  Iff.rfl
#align set.mem_Icc Set.mem_Icc

@[simp]
theorem mem_Iic : x ∈ Iic b ↔ x ≤ b :=
  Iff.rfl
#align set.mem_Iic Set.mem_Iic

@[simp]
theorem mem_Ioc : x ∈ Ioc a b ↔ a < x ∧ x ≤ b :=
  Iff.rfl
#align set.mem_Ioc Set.mem_Ioc

@[simp]
theorem mem_Ici : x ∈ Ici a ↔ a ≤ x :=
  Iff.rfl
#align set.mem_Ici Set.mem_Ici

@[simp]
theorem mem_Ioi : x ∈ Ioi a ↔ a < x :=
  Iff.rfl
#align set.mem_Ioi Set.mem_Ioi

instance decidableMemIoo [Decidable (a < x ∧ x < b)] : Decidable (x ∈ Ioo a b) := by assumption
#align set.decidable_mem_Ioo Set.decidableMemIoo

instance decidableMemIco [Decidable (a ≤ x ∧ x < b)] : Decidable (x ∈ Ico a b) := by assumption
#align set.decidable_mem_Ico Set.decidableMemIco

instance decidableMemIio [Decidable (x < b)] : Decidable (x ∈ Iio b) := by assumption
#align set.decidable_mem_Iio Set.decidableMemIio

instance decidableMemIcc [Decidable (a ≤ x ∧ x ≤ b)] : Decidable (x ∈ Icc a b) := by assumption
#align set.decidable_mem_Icc Set.decidableMemIcc

instance decidableMemIic [Decidable (x ≤ b)] : Decidable (x ∈ Iic b) := by assumption
#align set.decidable_mem_Iic Set.decidableMemIic

instance decidableMemIoc [Decidable (a < x ∧ x ≤ b)] : Decidable (x ∈ Ioc a b) := by assumption
#align set.decidable_mem_Ioc Set.decidableMemIoc

instance decidableMemIci [Decidable (a ≤ x)] : Decidable (x ∈ Ici a) := by assumption
#align set.decidable_mem_Ici Set.decidableMemIci

instance decidableMemIoi [Decidable (a < x)] : Decidable (x ∈ Ioi a) := by assumption
#align set.decidable_mem_Ioi Set.decidableMemIoi

-- Porting note: `simp` can prove this
-- @[simp]
theorem left_mem_Ioo : a ∈ Ioo a b ↔ False := by simp [lt_irrefl]
#align set.left_mem_Ioo Set.left_mem_Ioo

-- Porting note: `simp` can prove this
-- @[simp]
theorem left_mem_Ico : a ∈ Ico a b ↔ a < b := by simp [le_refl]
#align set.left_mem_Ico Set.left_mem_Ico

-- Porting note: `simp` can prove this
-- @[simp]
theorem left_mem_Icc : a ∈ Icc a b ↔ a ≤ b := by simp [le_refl]
#align set.left_mem_Icc Set.left_mem_Icc

-- Porting note: `simp` can prove this
-- @[simp]
theorem left_mem_Ioc : a ∈ Ioc a b ↔ False := by simp [lt_irrefl]
#align set.left_mem_Ioc Set.left_mem_Ioc

theorem left_mem_Ici : a ∈ Ici a := by simp
#align set.left_mem_Ici Set.left_mem_Ici

-- Porting note: `simp` can prove this
-- @[simp]
theorem right_mem_Ioo : b ∈ Ioo a b ↔ False := by simp [lt_irrefl]
#align set.right_mem_Ioo Set.right_mem_Ioo

-- Porting note: `simp` can prove this
-- @[simp]
theorem right_mem_Ico : b ∈ Ico a b ↔ False := by simp [lt_irrefl]
#align set.right_mem_Ico Set.right_mem_Ico

-- Porting note: `simp` can prove this
-- @[simp]
theorem right_mem_Icc : b ∈ Icc a b ↔ a ≤ b := by simp [le_refl]
#align set.right_mem_Icc Set.right_mem_Icc

-- Porting note: `simp` can prove this
-- @[simp]
theorem right_mem_Ioc : b ∈ Ioc a b ↔ a < b := by simp [le_refl]
#align set.right_mem_Ioc Set.right_mem_Ioc

theorem right_mem_Iic : a ∈ Iic a := by simp
#align set.right_mem_Iic Set.right_mem_Iic

@[simp]
theorem dual_Ici : Ici (toDual a) = ofDual ⁻¹' Iic a :=
  rfl
#align set.dual_Ici Set.dual_Ici

@[simp]
theorem dual_Iic : Iic (toDual a) = ofDual ⁻¹' Ici a :=
  rfl
#align set.dual_Iic Set.dual_Iic

@[simp]
theorem dual_Ioi : Ioi (toDual a) = ofDual ⁻¹' Iio a :=
  rfl
#align set.dual_Ioi Set.dual_Ioi

@[simp]
theorem dual_Iio : Iio (toDual a) = ofDual ⁻¹' Ioi a :=
  rfl
#align set.dual_Iio Set.dual_Iio

@[simp]
theorem dual_Icc : Icc (toDual a) (toDual b) = ofDual ⁻¹' Icc b a :=
  Set.ext fun _ => and_comm
#align set.dual_Icc Set.dual_Icc

@[simp]
theorem dual_Ioc : Ioc (toDual a) (toDual b) = ofDual ⁻¹' Ico b a :=
  Set.ext fun _ => and_comm
#align set.dual_Ioc Set.dual_Ioc

@[simp]
theorem dual_Ico : Ico (toDual a) (toDual b) = ofDual ⁻¹' Ioc b a :=
  Set.ext fun _ => and_comm
#align set.dual_Ico Set.dual_Ico

@[simp]
theorem dual_Ioo : Ioo (toDual a) (toDual b) = ofDual ⁻¹' Ioo b a :=
  Set.ext fun _ => and_comm
#align set.dual_Ioo Set.dual_Ioo

@[simp]
theorem nonempty_Icc : (Icc a b).Nonempty ↔ a ≤ b :=
  ⟨fun ⟨_, hx⟩ => hx.1.trans hx.2, fun h => ⟨a, left_mem_Icc.2 h⟩⟩
#align set.nonempty_Icc Set.nonempty_Icc

@[simp]
theorem nonempty_Ico : (Ico a b).Nonempty ↔ a < b :=
  ⟨fun ⟨_, hx⟩ => hx.1.trans_lt hx.2, fun h => ⟨a, left_mem_Ico.2 h⟩⟩
#align set.nonempty_Ico Set.nonempty_Ico

@[simp]
theorem nonempty_Ioc : (Ioc a b).Nonempty ↔ a < b :=
  ⟨fun ⟨_, hx⟩ => hx.1.trans_le hx.2, fun h => ⟨b, right_mem_Ioc.2 h⟩⟩
#align set.nonempty_Ioc Set.nonempty_Ioc

@[simp]
theorem nonempty_Ici : (Ici a).Nonempty :=
  ⟨a, left_mem_Ici⟩
#align set.nonempty_Ici Set.nonempty_Ici

@[simp]
theorem nonempty_Iic : (Iic a).Nonempty :=
  ⟨a, right_mem_Iic⟩
#align set.nonempty_Iic Set.nonempty_Iic

@[simp]
theorem nonempty_Ioo [DenselyOrdered α] : (Ioo a b).Nonempty ↔ a < b :=
  ⟨fun ⟨_, ha, hb⟩ => ha.trans hb, exists_between⟩
#align set.nonempty_Ioo Set.nonempty_Ioo

@[simp]
theorem nonempty_Ioi [NoMaxOrder α] : (Ioi a).Nonempty :=
  exists_gt a
#align set.nonempty_Ioi Set.nonempty_Ioi

@[simp]
theorem nonempty_Iio [NoMinOrder α] : (Iio a).Nonempty :=
  exists_lt a
#align set.nonempty_Iio Set.nonempty_Iio

theorem nonempty_Icc_subtype (h : a ≤ b) : Nonempty (Icc a b) :=
  Nonempty.to_subtype (nonempty_Icc.mpr h)
#align set.nonempty_Icc_subtype Set.nonempty_Icc_subtype

theorem nonempty_Ico_subtype (h : a < b) : Nonempty (Ico a b) :=
  Nonempty.to_subtype (nonempty_Ico.mpr h)
#align set.nonempty_Ico_subtype Set.nonempty_Ico_subtype

theorem nonempty_Ioc_subtype (h : a < b) : Nonempty (Ioc a b) :=
  Nonempty.to_subtype (nonempty_Ioc.mpr h)
#align set.nonempty_Ioc_subtype Set.nonempty_Ioc_subtype

/-- An interval `Ici a` is nonempty. -/
instance nonempty_Ici_subtype : Nonempty (Ici a) :=
  Nonempty.to_subtype nonempty_Ici
#align set.nonempty_Ici_subtype Set.nonempty_Ici_subtype

/-- An interval `Iic a` is nonempty. -/
instance nonempty_Iic_subtype : Nonempty (Iic a) :=
  Nonempty.to_subtype nonempty_Iic
#align set.nonempty_Iic_subtype Set.nonempty_Iic_subtype

theorem nonempty_Ioo_subtype [DenselyOrdered α] (h : a < b) : Nonempty (Ioo a b) :=
  Nonempty.to_subtype (nonempty_Ioo.mpr h)
#align set.nonempty_Ioo_subtype Set.nonempty_Ioo_subtype

/-- In an order without maximal elements, the intervals `Ioi` are nonempty. -/
instance nonempty_Ioi_subtype [NoMaxOrder α] : Nonempty (Ioi a) :=
  Nonempty.to_subtype nonempty_Ioi
#align set.nonempty_Ioi_subtype Set.nonempty_Ioi_subtype

/-- In an order without minimal elements, the intervals `Iio` are nonempty. -/
instance nonempty_Iio_subtype [NoMinOrder α] : Nonempty (Iio a) :=
  Nonempty.to_subtype nonempty_Iio
#align set.nonempty_Iio_subtype Set.nonempty_Iio_subtype

instance [NoMinOrder α] : NoMinOrder (Iio a) :=
  ⟨fun a =>
    let ⟨b, hb⟩ := exists_lt (a : α)
    ⟨⟨b, lt_trans hb a.2⟩, hb⟩⟩

instance [NoMinOrder α] : NoMinOrder (Iic a) :=
  ⟨fun a =>
    let ⟨b, hb⟩ := exists_lt (a : α)
    ⟨⟨b, hb.le.trans a.2⟩, hb⟩⟩

instance [NoMaxOrder α] : NoMaxOrder (Ioi a) :=
  OrderDual.noMaxOrder (α := Iio (toDual a))

instance [NoMaxOrder α] : NoMaxOrder (Ici a) :=
  OrderDual.noMaxOrder (α := Iic (toDual a))

@[simp]
theorem Icc_eq_empty (h : ¬a ≤ b) : Icc a b = ∅ :=
  eq_empty_iff_forall_not_mem.2 fun _ ⟨ha, hb⟩ => h (ha.trans hb)
#align set.Icc_eq_empty Set.Icc_eq_empty

@[simp]
theorem Ico_eq_empty (h : ¬a < b) : Ico a b = ∅ :=
  eq_empty_iff_forall_not_mem.2 fun _ ⟨ha, hb⟩ => h (ha.trans_lt hb)
#align set.Ico_eq_empty Set.Ico_eq_empty

@[simp]
theorem Ioc_eq_empty (h : ¬a < b) : Ioc a b = ∅ :=
  eq_empty_iff_forall_not_mem.2 fun _ ⟨ha, hb⟩ => h (ha.trans_le hb)
#align set.Ioc_eq_empty Set.Ioc_eq_empty

@[simp]
theorem Ioo_eq_empty (h : ¬a < b) : Ioo a b = ∅ :=
  eq_empty_iff_forall_not_mem.2 fun _ ⟨ha, hb⟩ => h (ha.trans hb)
#align set.Ioo_eq_empty Set.Ioo_eq_empty

@[simp]
theorem Icc_eq_empty_of_lt (h : b < a) : Icc a b = ∅ :=
  Icc_eq_empty h.not_le
#align set.Icc_eq_empty_of_lt Set.Icc_eq_empty_of_lt

@[simp]
theorem Ico_eq_empty_of_le (h : b ≤ a) : Ico a b = ∅ :=
  Ico_eq_empty h.not_lt
#align set.Ico_eq_empty_of_le Set.Ico_eq_empty_of_le

@[simp]
theorem Ioc_eq_empty_of_le (h : b ≤ a) : Ioc a b = ∅ :=
  Ioc_eq_empty h.not_lt
#align set.Ioc_eq_empty_of_le Set.Ioc_eq_empty_of_le

@[simp]
theorem Ioo_eq_empty_of_le (h : b ≤ a) : Ioo a b = ∅ :=
  Ioo_eq_empty h.not_lt
#align set.Ioo_eq_empty_of_le Set.Ioo_eq_empty_of_le

-- Porting note: `simp` can prove this
-- @[simp]
theorem Ico_self (a : α) : Ico a a = ∅ :=
  Ico_eq_empty <| lt_irrefl _
#align set.Ico_self Set.Ico_self

-- Porting note: `simp` can prove this
-- @[simp]
theorem Ioc_self (a : α) : Ioc a a = ∅ :=
  Ioc_eq_empty <| lt_irrefl _
#align set.Ioc_self Set.Ioc_self

-- Porting note: `simp` can prove this
-- @[simp]
theorem Ioo_self (a : α) : Ioo a a = ∅ :=
  Ioo_eq_empty <| lt_irrefl _
#align set.Ioo_self Set.Ioo_self

theorem Ici_subset_Ici : Ici a ⊆ Ici b ↔ b ≤ a :=
  ⟨fun h => h <| left_mem_Ici, fun h _ hx => h.trans hx⟩
#align set.Ici_subset_Ici Set.Ici_subset_Ici

theorem Iic_subset_Iic : Iic a ⊆ Iic b ↔ a ≤ b :=
  @Ici_subset_Ici αᵒᵈ _ _ _
#align set.Iic_subset_Iic Set.Iic_subset_Iic

theorem Ici_subset_Ioi : Ici a ⊆ Ioi b ↔ b < a :=
  ⟨fun h => h left_mem_Ici, fun h _ hx => h.trans_le hx⟩
#align set.Ici_subset_Ioi Set.Ici_subset_Ioi

theorem Iic_subset_Iio : Iic a ⊆ Iio b ↔ a < b :=
  ⟨fun h => h right_mem_Iic, fun h _ hx => lt_of_le_of_lt hx h⟩
#align set.Iic_subset_Iio Set.Iic_subset_Iio

theorem Ioo_subset_Ioo (h₁ : a₂ ≤ a₁) (h₂ : b₁ ≤ b₂) : Ioo a₁ b₁ ⊆ Ioo a₂ b₂ := fun _ ⟨hx₁, hx₂⟩ =>
  ⟨h₁.trans_lt hx₁, hx₂.trans_le h₂⟩
#align set.Ioo_subset_Ioo Set.Ioo_subset_Ioo

theorem Ioo_subset_Ioo_left (h : a₁ ≤ a₂) : Ioo a₂ b ⊆ Ioo a₁ b :=
  Ioo_subset_Ioo h le_rfl
#align set.Ioo_subset_Ioo_left Set.Ioo_subset_Ioo_left

theorem Ioo_subset_Ioo_right (h : b₁ ≤ b₂) : Ioo a b₁ ⊆ Ioo a b₂ :=
  Ioo_subset_Ioo le_rfl h
#align set.Ioo_subset_Ioo_right Set.Ioo_subset_Ioo_right

theorem Ico_subset_Ico (h₁ : a₂ ≤ a₁) (h₂ : b₁ ≤ b₂) : Ico a₁ b₁ ⊆ Ico a₂ b₂ := fun _ ⟨hx₁, hx₂⟩ =>
  ⟨h₁.trans hx₁, hx₂.trans_le h₂⟩
#align set.Ico_subset_Ico Set.Ico_subset_Ico

theorem Ico_subset_Ico_left (h : a₁ ≤ a₂) : Ico a₂ b ⊆ Ico a₁ b :=
  Ico_subset_Ico h le_rfl
#align set.Ico_subset_Ico_left Set.Ico_subset_Ico_left

theorem Ico_subset_Ico_right (h : b₁ ≤ b₂) : Ico a b₁ ⊆ Ico a b₂ :=
  Ico_subset_Ico le_rfl h
#align set.Ico_subset_Ico_right Set.Ico_subset_Ico_right

theorem Icc_subset_Icc (h₁ : a₂ ≤ a₁) (h₂ : b₁ ≤ b₂) : Icc a₁ b₁ ⊆ Icc a₂ b₂ := fun _ ⟨hx₁, hx₂⟩ =>
  ⟨h₁.trans hx₁, le_trans hx₂ h₂⟩
#align set.Icc_subset_Icc Set.Icc_subset_Icc

theorem Icc_subset_Icc_left (h : a₁ ≤ a₂) : Icc a₂ b ⊆ Icc a₁ b :=
  Icc_subset_Icc h le_rfl
#align set.Icc_subset_Icc_left Set.Icc_subset_Icc_left

theorem Icc_subset_Icc_right (h : b₁ ≤ b₂) : Icc a b₁ ⊆ Icc a b₂ :=
  Icc_subset_Icc le_rfl h
#align set.Icc_subset_Icc_right Set.Icc_subset_Icc_right

theorem Icc_subset_Ioo (ha : a₂ < a₁) (hb : b₁ < b₂) : Icc a₁ b₁ ⊆ Ioo a₂ b₂ := fun _ hx =>
  ⟨ha.trans_le hx.1, hx.2.trans_lt hb⟩
#align set.Icc_subset_Ioo Set.Icc_subset_Ioo

theorem Icc_subset_Ici_self : Icc a b ⊆ Ici a := fun _ => And.left
#align set.Icc_subset_Ici_self Set.Icc_subset_Ici_self

theorem Icc_subset_Iic_self : Icc a b ⊆ Iic b := fun _ => And.right
#align set.Icc_subset_Iic_self Set.Icc_subset_Iic_self

theorem Ioc_subset_Iic_self : Ioc a b ⊆ Iic b := fun _ => And.right
#align set.Ioc_subset_Iic_self Set.Ioc_subset_Iic_self

theorem Ioc_subset_Ioc (h₁ : a₂ ≤ a₁) (h₂ : b₁ ≤ b₂) : Ioc a₁ b₁ ⊆ Ioc a₂ b₂ := fun _ ⟨hx₁, hx₂⟩ =>
  ⟨h₁.trans_lt hx₁, hx₂.trans h₂⟩
#align set.Ioc_subset_Ioc Set.Ioc_subset_Ioc

theorem Ioc_subset_Ioc_left (h : a₁ ≤ a₂) : Ioc a₂ b ⊆ Ioc a₁ b :=
  Ioc_subset_Ioc h le_rfl
#align set.Ioc_subset_Ioc_left Set.Ioc_subset_Ioc_left

theorem Ioc_subset_Ioc_right (h : b₁ ≤ b₂) : Ioc a b₁ ⊆ Ioc a b₂ :=
  Ioc_subset_Ioc le_rfl h
#align set.Ioc_subset_Ioc_right Set.Ioc_subset_Ioc_right

theorem Ico_subset_Ioo_left (h₁ : a₁ < a₂) : Ico a₂ b ⊆ Ioo a₁ b := fun _ =>
  And.imp_left h₁.trans_le
#align set.Ico_subset_Ioo_left Set.Ico_subset_Ioo_left

theorem Ioc_subset_Ioo_right (h : b₁ < b₂) : Ioc a b₁ ⊆ Ioo a b₂ := fun _ =>
  And.imp_right fun h' => h'.trans_lt h
#align set.Ioc_subset_Ioo_right Set.Ioc_subset_Ioo_right

theorem Icc_subset_Ico_right (h₁ : b₁ < b₂) : Icc a b₁ ⊆ Ico a b₂ := fun _ =>
  And.imp_right fun h₂ => h₂.trans_lt h₁
#align set.Icc_subset_Ico_right Set.Icc_subset_Ico_right

theorem Ioo_subset_Ico_self : Ioo a b ⊆ Ico a b := fun _ => And.imp_left le_of_lt
#align set.Ioo_subset_Ico_self Set.Ioo_subset_Ico_self

theorem Ioo_subset_Ioc_self : Ioo a b ⊆ Ioc a b := fun _ => And.imp_right le_of_lt
#align set.Ioo_subset_Ioc_self Set.Ioo_subset_Ioc_self

theorem Ico_subset_Icc_self : Ico a b ⊆ Icc a b := fun _ => And.imp_right le_of_lt
#align set.Ico_subset_Icc_self Set.Ico_subset_Icc_self

theorem Ioc_subset_Icc_self : Ioc a b ⊆ Icc a b := fun _ => And.imp_left le_of_lt
#align set.Ioc_subset_Icc_self Set.Ioc_subset_Icc_self

theorem Ioo_subset_Icc_self : Ioo a b ⊆ Icc a b :=
  Subset.trans Ioo_subset_Ico_self Ico_subset_Icc_self
#align set.Ioo_subset_Icc_self Set.Ioo_subset_Icc_self

theorem Ico_subset_Iio_self : Ico a b ⊆ Iio b := fun _ => And.right
#align set.Ico_subset_Iio_self Set.Ico_subset_Iio_self

theorem Ioo_subset_Iio_self : Ioo a b ⊆ Iio b := fun _ => And.right
#align set.Ioo_subset_Iio_self Set.Ioo_subset_Iio_self

theorem Ioc_subset_Ioi_self : Ioc a b ⊆ Ioi a := fun _ => And.left
#align set.Ioc_subset_Ioi_self Set.Ioc_subset_Ioi_self

theorem Ioo_subset_Ioi_self : Ioo a b ⊆ Ioi a := fun _ => And.left
#align set.Ioo_subset_Ioi_self Set.Ioo_subset_Ioi_self

theorem Ioi_subset_Ici_self : Ioi a ⊆ Ici a := fun _ hx => le_of_lt hx
#align set.Ioi_subset_Ici_self Set.Ioi_subset_Ici_self

theorem Iio_subset_Iic_self : Iio a ⊆ Iic a := fun _ hx => le_of_lt hx
#align set.Iio_subset_Iic_self Set.Iio_subset_Iic_self

theorem Ico_subset_Ici_self : Ico a b ⊆ Ici a := fun _ => And.left
#align set.Ico_subset_Ici_self Set.Ico_subset_Ici_self

theorem Ioi_ssubset_Ici_self : Ioi a ⊂ Ici a :=
  ⟨Ioi_subset_Ici_self, fun h => lt_irrefl a (h le_rfl)⟩
#align set.Ioi_ssubset_Ici_self Set.Ioi_ssubset_Ici_self

theorem Iio_ssubset_Iic_self : Iio a ⊂ Iic a :=
  @Ioi_ssubset_Ici_self αᵒᵈ _ _
#align set.Iio_ssubset_Iic_self Set.Iio_ssubset_Iic_self

theorem Icc_subset_Icc_iff (h₁ : a₁ ≤ b₁) : Icc a₁ b₁ ⊆ Icc a₂ b₂ ↔ a₂ ≤ a₁ ∧ b₁ ≤ b₂ :=
  ⟨fun h => ⟨(h ⟨le_rfl, h₁⟩).1, (h ⟨h₁, le_rfl⟩).2⟩, fun ⟨h, h'⟩ _ ⟨hx, hx'⟩ =>
    ⟨h.trans hx, hx'.trans h'⟩⟩
#align set.Icc_subset_Icc_iff Set.Icc_subset_Icc_iff

theorem Icc_subset_Ioo_iff (h₁ : a₁ ≤ b₁) : Icc a₁ b₁ ⊆ Ioo a₂ b₂ ↔ a₂ < a₁ ∧ b₁ < b₂ :=
  ⟨fun h => ⟨(h ⟨le_rfl, h₁⟩).1, (h ⟨h₁, le_rfl⟩).2⟩, fun ⟨h, h'⟩ _ ⟨hx, hx'⟩ =>
    ⟨h.trans_le hx, hx'.trans_lt h'⟩⟩
#align set.Icc_subset_Ioo_iff Set.Icc_subset_Ioo_iff

theorem Icc_subset_Ico_iff (h₁ : a₁ ≤ b₁) : Icc a₁ b₁ ⊆ Ico a₂ b₂ ↔ a₂ ≤ a₁ ∧ b₁ < b₂ :=
  ⟨fun h => ⟨(h ⟨le_rfl, h₁⟩).1, (h ⟨h₁, le_rfl⟩).2⟩, fun ⟨h, h'⟩ _ ⟨hx, hx'⟩ =>
    ⟨h.trans hx, hx'.trans_lt h'⟩⟩
#align set.Icc_subset_Ico_iff Set.Icc_subset_Ico_iff

theorem Icc_subset_Ioc_iff (h₁ : a₁ ≤ b₁) : Icc a₁ b₁ ⊆ Ioc a₂ b₂ ↔ a₂ < a₁ ∧ b₁ ≤ b₂ :=
  ⟨fun h => ⟨(h ⟨le_rfl, h₁⟩).1, (h ⟨h₁, le_rfl⟩).2⟩, fun ⟨h, h'⟩ _ ⟨hx, hx'⟩ =>
    ⟨h.trans_le hx, hx'.trans h'⟩⟩
#align set.Icc_subset_Ioc_iff Set.Icc_subset_Ioc_iff

theorem Icc_subset_Iio_iff (h₁ : a₁ ≤ b₁) : Icc a₁ b₁ ⊆ Iio b₂ ↔ b₁ < b₂ :=
  ⟨fun h => h ⟨h₁, le_rfl⟩, fun h _ ⟨_, hx'⟩ => hx'.trans_lt h⟩
#align set.Icc_subset_Iio_iff Set.Icc_subset_Iio_iff

theorem Icc_subset_Ioi_iff (h₁ : a₁ ≤ b₁) : Icc a₁ b₁ ⊆ Ioi a₂ ↔ a₂ < a₁ :=
  ⟨fun h => h ⟨le_rfl, h₁⟩, fun h _ ⟨hx, _⟩ => h.trans_le hx⟩
#align set.Icc_subset_Ioi_iff Set.Icc_subset_Ioi_iff

theorem Icc_subset_Iic_iff (h₁ : a₁ ≤ b₁) : Icc a₁ b₁ ⊆ Iic b₂ ↔ b₁ ≤ b₂ :=
  ⟨fun h => h ⟨h₁, le_rfl⟩, fun h _ ⟨_, hx'⟩ => hx'.trans h⟩
#align set.Icc_subset_Iic_iff Set.Icc_subset_Iic_iff

theorem Icc_subset_Ici_iff (h₁ : a₁ ≤ b₁) : Icc a₁ b₁ ⊆ Ici a₂ ↔ a₂ ≤ a₁ :=
  ⟨fun h => h ⟨le_rfl, h₁⟩, fun h _ ⟨hx, _⟩ => h.trans hx⟩
#align set.Icc_subset_Ici_iff Set.Icc_subset_Ici_iff

theorem Icc_ssubset_Icc_right (hI : a₂ ≤ b₂) (ha : a₂ ≤ a₁) (hb : b₁ < b₂) :
    Icc a₁ b₁ ⊂ Icc a₂ b₂ :=
  (ssubset_iff_of_subset (Icc_subset_Icc ha (le_of_lt hb))).mpr
    ⟨b₂, right_mem_Icc.mpr hI, fun f => lt_irrefl b₁ (hb.trans_le f.2)⟩
#align set.Icc_ssubset_Icc_right Set.Icc_ssubset_Icc_right

/-- If `a ≤ b`, then `(b, +∞) ⊆ (a, +∞)`. In preorders, this is just an implication. If you need
the equivalence in linear orders, use `Ioi_subset_Ioi_iff`. -/
theorem Ioi_subset_Ioi (h : a ≤ b) : Ioi b ⊆ Ioi a := fun _ hx => h.trans_lt hx
#align set.Ioi_subset_Ioi Set.Ioi_subset_Ioi

/-- If `a ≤ b`, then `(b, +∞) ⊆ [a, +∞)`. In preorders, this is just an implication. If you need
the equivalence in dense linear orders, use `Ioi_subset_Ici_iff`. -/
theorem Ioi_subset_Ici (h : a ≤ b) : Ioi b ⊆ Ici a :=
  Subset.trans (Ioi_subset_Ioi h) Ioi_subset_Ici_self
#align set.Ioi_subset_Ici Set.Ioi_subset_Ici

/-- If `a ≤ b`, then `(-∞, a) ⊆ (-∞, b)`. In preorders, this is just an implication. If you need
the equivalence in linear orders, use `Iio_subset_Iio_iff`. -/
theorem Iio_subset_Iio (h : a ≤ b) : Iio a ⊆ Iio b := fun _ hx => lt_of_lt_of_le hx h
#align set.Iio_subset_Iio Set.Iio_subset_Iio

/-- If `a ≤ b`, then `(-∞, a) ⊆ (-∞, b]`. In preorders, this is just an implication. If you need
the equivalence in dense linear orders, use `Iio_subset_Iic_iff`. -/
theorem Iio_subset_Iic (h : a ≤ b) : Iio a ⊆ Iic b :=
  Subset.trans (Iio_subset_Iio h) Iio_subset_Iic_self
#align set.Iio_subset_Iic Set.Iio_subset_Iic

theorem Ici_inter_Iic : Ici a ∩ Iic b = Icc a b :=
  rfl
#align set.Ici_inter_Iic Set.Ici_inter_Iic

theorem Ici_inter_Iio : Ici a ∩ Iio b = Ico a b :=
  rfl
#align set.Ici_inter_Iio Set.Ici_inter_Iio

theorem Ioi_inter_Iic : Ioi a ∩ Iic b = Ioc a b :=
  rfl
#align set.Ioi_inter_Iic Set.Ioi_inter_Iic

theorem Ioi_inter_Iio : Ioi a ∩ Iio b = Ioo a b :=
  rfl
#align set.Ioi_inter_Iio Set.Ioi_inter_Iio

theorem Iic_inter_Ici : Iic a ∩ Ici b = Icc b a :=
  inter_comm _ _
#align set.Iic_inter_Ici Set.Iic_inter_Ici

theorem Iio_inter_Ici : Iio a ∩ Ici b = Ico b a :=
  inter_comm _ _
#align set.Iio_inter_Ici Set.Iio_inter_Ici

theorem Iic_inter_Ioi : Iic a ∩ Ioi b = Ioc b a :=
  inter_comm _ _
#align set.Iic_inter_Ioi Set.Iic_inter_Ioi

theorem Iio_inter_Ioi : Iio a ∩ Ioi b = Ioo b a :=
  inter_comm _ _
#align set.Iio_inter_Ioi Set.Iio_inter_Ioi

theorem mem_Icc_of_Ioo (h : x ∈ Ioo a b) : x ∈ Icc a b :=
  Ioo_subset_Icc_self h
#align set.mem_Icc_of_Ioo Set.mem_Icc_of_Ioo

theorem mem_Ico_of_Ioo (h : x ∈ Ioo a b) : x ∈ Ico a b :=
  Ioo_subset_Ico_self h
#align set.mem_Ico_of_Ioo Set.mem_Ico_of_Ioo

theorem mem_Ioc_of_Ioo (h : x ∈ Ioo a b) : x ∈ Ioc a b :=
  Ioo_subset_Ioc_self h
#align set.mem_Ioc_of_Ioo Set.mem_Ioc_of_Ioo

theorem mem_Icc_of_Ico (h : x ∈ Ico a b) : x ∈ Icc a b :=
  Ico_subset_Icc_self h
#align set.mem_Icc_of_Ico Set.mem_Icc_of_Ico

theorem mem_Icc_of_Ioc (h : x ∈ Ioc a b) : x ∈ Icc a b :=
  Ioc_subset_Icc_self h
#align set.mem_Icc_of_Ioc Set.mem_Icc_of_Ioc

theorem mem_Ici_of_Ioi (h : x ∈ Ioi a) : x ∈ Ici a :=
  Ioi_subset_Ici_self h
#align set.mem_Ici_of_Ioi Set.mem_Ici_of_Ioi

theorem mem_Iic_of_Iio (h : x ∈ Iio a) : x ∈ Iic a :=
  Iio_subset_Iic_self h
#align set.mem_Iic_of_Iio Set.mem_Iic_of_Iio

theorem Icc_eq_empty_iff : Icc a b = ∅ ↔ ¬a ≤ b := by
  rw [← not_nonempty_iff_eq_empty, not_iff_not, nonempty_Icc]
#align set.Icc_eq_empty_iff Set.Icc_eq_empty_iff

theorem Ico_eq_empty_iff : Ico a b = ∅ ↔ ¬a < b := by
  rw [← not_nonempty_iff_eq_empty, not_iff_not, nonempty_Ico]
#align set.Ico_eq_empty_iff Set.Ico_eq_empty_iff

theorem Ioc_eq_empty_iff : Ioc a b = ∅ ↔ ¬a < b := by
  rw [← not_nonempty_iff_eq_empty, not_iff_not, nonempty_Ioc]
#align set.Ioc_eq_empty_iff Set.Ioc_eq_empty_iff

theorem Ioo_eq_empty_iff [DenselyOrdered α] : Ioo a b = ∅ ↔ ¬a < b := by
  rw [← not_nonempty_iff_eq_empty, not_iff_not, nonempty_Ioo]
#align set.Ioo_eq_empty_iff Set.Ioo_eq_empty_iff

theorem _root_.IsTop.Iic_eq (h : IsTop a) : Iic a = univ :=
  eq_univ_of_forall h
#align is_top.Iic_eq IsTop.Iic_eq

theorem _root_.IsBot.Ici_eq (h : IsBot a) : Ici a = univ :=
  eq_univ_of_forall h
#align is_bot.Ici_eq IsBot.Ici_eq

theorem _root_.IsMax.Ioi_eq (h : IsMax a) : Ioi a = ∅ :=
  eq_empty_of_subset_empty fun _ => h.not_lt
#align is_max.Ioi_eq IsMax.Ioi_eq

theorem _root_.IsMin.Iio_eq (h : IsMin a) : Iio a = ∅ :=
  eq_empty_of_subset_empty fun _ => h.not_lt
#align is_min.Iio_eq IsMin.Iio_eq

theorem Iic_inter_Ioc_of_le (h : a ≤ c) : Iic a ∩ Ioc b c = Ioc b a :=
  ext fun _ => ⟨fun H => ⟨H.2.1, H.1⟩, fun H => ⟨H.2, H.1, H.2.trans h⟩⟩
#align set.Iic_inter_Ioc_of_le Set.Iic_inter_Ioc_of_le

end Preorder

section PartialOrder

variable [PartialOrder α] {a b c : α}

@[simp]
theorem Icc_self (a : α) : Icc a a = {a} :=
  Set.ext <| by simp [Icc, le_antisymm_iff, and_comm]
#align set.Icc_self Set.Icc_self

@[simp]
theorem Icc_eq_singleton_iff : Icc a b = {c} ↔ a = c ∧ b = c := by
  refine' ⟨fun h => _, _⟩
  · have hab : a ≤ b := nonempty_Icc.1 (h.symm.subst <| singleton_nonempty c)
    exact
      ⟨eq_of_mem_singleton <| h.subst <| left_mem_Icc.2 hab,
        eq_of_mem_singleton <| h.subst <| right_mem_Icc.2 hab⟩
  · rintro ⟨rfl, rfl⟩
    exact Icc_self _
#align set.Icc_eq_singleton_iff Set.Icc_eq_singleton_iff

@[simp]
theorem Icc_diff_left : Icc a b \ {a} = Ioc a b :=
  ext fun x => by simp [lt_iff_le_and_ne, eq_comm, and_right_comm]
#align set.Icc_diff_left Set.Icc_diff_left

@[simp]
theorem Icc_diff_right : Icc a b \ {b} = Ico a b :=
  ext fun x => by simp [lt_iff_le_and_ne, and_assoc]
#align set.Icc_diff_right Set.Icc_diff_right

@[simp]
theorem Ico_diff_left : Ico a b \ {a} = Ioo a b :=
  ext fun x => by simp [and_right_comm, ← lt_iff_le_and_ne, eq_comm]
#align set.Ico_diff_left Set.Ico_diff_left

@[simp]
theorem Ioc_diff_right : Ioc a b \ {b} = Ioo a b :=
  ext fun x => by simp [and_assoc, ← lt_iff_le_and_ne]
#align set.Ioc_diff_right Set.Ioc_diff_right

@[simp]
theorem Icc_diff_both : Icc a b \ {a, b} = Ioo a b := by
  rw [insert_eq, ← diff_diff, Icc_diff_left, Ioc_diff_right]
#align set.Icc_diff_both Set.Icc_diff_both

@[simp]
theorem Ici_diff_left : Ici a \ {a} = Ioi a :=
  ext fun x => by simp [lt_iff_le_and_ne, eq_comm]
#align set.Ici_diff_left Set.Ici_diff_left

@[simp]
theorem Iic_diff_right : Iic a \ {a} = Iio a :=
  ext fun x => by simp [lt_iff_le_and_ne]
#align set.Iic_diff_right Set.Iic_diff_right

@[simp]
theorem Ico_diff_Ioo_same (h : a < b) : Ico a b \ Ioo a b = {a} := by
  rw [← Ico_diff_left, diff_diff_cancel_left (singleton_subset_iff.2 <| left_mem_Ico.2 h)]
#align set.Ico_diff_Ioo_same Set.Ico_diff_Ioo_same

@[simp]
theorem Ioc_diff_Ioo_same (h : a < b) : Ioc a b \ Ioo a b = {b} := by
  rw [← Ioc_diff_right, diff_diff_cancel_left (singleton_subset_iff.2 <| right_mem_Ioc.2 h)]
#align set.Ioc_diff_Ioo_same Set.Ioc_diff_Ioo_same

@[simp]
theorem Icc_diff_Ico_same (h : a ≤ b) : Icc a b \ Ico a b = {b} := by
  rw [← Icc_diff_right, diff_diff_cancel_left (singleton_subset_iff.2 <| right_mem_Icc.2 h)]
#align set.Icc_diff_Ico_same Set.Icc_diff_Ico_same

@[simp]
theorem Icc_diff_Ioc_same (h : a ≤ b) : Icc a b \ Ioc a b = {a} := by
  rw [← Icc_diff_left, diff_diff_cancel_left (singleton_subset_iff.2 <| left_mem_Icc.2 h)]
#align set.Icc_diff_Ioc_same Set.Icc_diff_Ioc_same

@[simp]
theorem Icc_diff_Ioo_same (h : a ≤ b) : Icc a b \ Ioo a b = {a, b} := by
  rw [← Icc_diff_both, diff_diff_cancel_left]
  simp [insert_subset, h]
#align set.Icc_diff_Ioo_same Set.Icc_diff_Ioo_same

@[simp]
theorem Ici_diff_Ioi_same : Ici a \ Ioi a = {a} := by
  rw [← Ici_diff_left, diff_diff_cancel_left (singleton_subset_iff.2 left_mem_Ici)]
#align set.Ici_diff_Ioi_same Set.Ici_diff_Ioi_same

@[simp]
theorem Iic_diff_Iio_same : Iic a \ Iio a = {a} := by
  rw [← Iic_diff_right, diff_diff_cancel_left (singleton_subset_iff.2 right_mem_Iic)]
#align set.Iic_diff_Iio_same Set.Iic_diff_Iio_same

-- Porting note: `simp` can prove this
-- @[simp]
theorem Ioi_union_left : Ioi a ∪ {a} = Ici a :=
  ext fun x => by simp [eq_comm, le_iff_eq_or_lt]
#align set.Ioi_union_left Set.Ioi_union_left

-- Porting note: `simp` can prove this
-- @[simp]
theorem Iio_union_right : Iio a ∪ {a} = Iic a :=
  ext fun _ => le_iff_lt_or_eq.symm
#align set.Iio_union_right Set.Iio_union_right

theorem Ioo_union_left (hab : a < b) : Ioo a b ∪ {a} = Ico a b := by
  rw [← Ico_diff_left, diff_union_self,
    union_eq_self_of_subset_right (singleton_subset_iff.2 <| left_mem_Ico.2 hab)]
#align set.Ioo_union_left Set.Ioo_union_left

theorem Ioo_union_right (hab : a < b) : Ioo a b ∪ {b} = Ioc a b := by
  simpa only [dual_Ioo, dual_Ico] using Ioo_union_left hab.dual
#align set.Ioo_union_right Set.Ioo_union_right

theorem Ioc_union_left (hab : a ≤ b) : Ioc a b ∪ {a} = Icc a b := by
  rw [← Icc_diff_left, diff_union_self,
    union_eq_self_of_subset_right (singleton_subset_iff.2 <| left_mem_Icc.2 hab)]
#align set.Ioc_union_left Set.Ioc_union_left

theorem Ico_union_right (hab : a ≤ b) : Ico a b ∪ {b} = Icc a b := by
  simpa only [dual_Ioc, dual_Icc] using Ioc_union_left hab.dual
#align set.Ico_union_right Set.Ico_union_right

@[simp]
theorem Ico_insert_right (h : a ≤ b) : insert b (Ico a b) = Icc a b := by
  rw [insert_eq, union_comm, Ico_union_right h]
#align set.Ico_insert_right Set.Ico_insert_right

@[simp]
theorem Ioc_insert_left (h : a ≤ b) : insert a (Ioc a b) = Icc a b := by
  rw [insert_eq, union_comm, Ioc_union_left h]
#align set.Ioc_insert_left Set.Ioc_insert_left

@[simp]
theorem Ioo_insert_left (h : a < b) : insert a (Ioo a b) = Ico a b := by
  rw [insert_eq, union_comm, Ioo_union_left h]
#align set.Ioo_insert_left Set.Ioo_insert_left

@[simp]
theorem Ioo_insert_right (h : a < b) : insert b (Ioo a b) = Ioc a b := by
  rw [insert_eq, union_comm, Ioo_union_right h]
#align set.Ioo_insert_right Set.Ioo_insert_right

@[simp]
theorem Iio_insert : insert a (Iio a) = Iic a :=
  ext fun _ => le_iff_eq_or_lt.symm
#align set.Iio_insert Set.Iio_insert

@[simp]
theorem Ioi_insert : insert a (Ioi a) = Ici a :=
  ext fun _ => (or_congr_left eq_comm).trans le_iff_eq_or_lt.symm
#align set.Ioi_insert Set.Ioi_insert

theorem mem_Ici_Ioi_of_subset_of_subset {s : Set α} (ho : Ioi a ⊆ s) (hc : s ⊆ Ici a) :
    s ∈ ({Ici a, Ioi a} : Set (Set α)) :=
  by_cases
    (fun h : a ∈ s =>
      Or.inl <| Subset.antisymm hc <| by rw [← Ioi_union_left, union_subset_iff]; simp [*])
    fun h =>
    Or.inr <| Subset.antisymm (fun x hx => lt_of_le_of_ne (hc hx) fun heq => h <| heq.symm ▸ hx) ho
#align set.mem_Ici_Ioi_of_subset_of_subset Set.mem_Ici_Ioi_of_subset_of_subset

theorem mem_Iic_Iio_of_subset_of_subset {s : Set α} (ho : Iio a ⊆ s) (hc : s ⊆ Iic a) :
    s ∈ ({Iic a, Iio a} : Set (Set α)) :=
  @mem_Ici_Ioi_of_subset_of_subset αᵒᵈ _ a s ho hc
#align set.mem_Iic_Iio_of_subset_of_subset Set.mem_Iic_Iio_of_subset_of_subset

theorem mem_Icc_Ico_Ioc_Ioo_of_subset_of_subset {s : Set α} (ho : Ioo a b ⊆ s) (hc : s ⊆ Icc a b) :
    s ∈ ({Icc a b, Ico a b, Ioc a b, Ioo a b} : Set (Set α)) := by
  classical
    by_cases ha : a ∈ s <;> by_cases hb : b ∈ s
    · refine' Or.inl (Subset.antisymm hc _)
      rwa [← Ico_diff_left, diff_singleton_subset_iff, insert_eq_of_mem ha, ← Icc_diff_right,
        diff_singleton_subset_iff, insert_eq_of_mem hb] at ho
    · refine' Or.inr <| Or.inl <| Subset.antisymm _ _
      · rw [← Icc_diff_right]
        exact subset_diff_singleton hc hb
      · rwa [← Ico_diff_left, diff_singleton_subset_iff, insert_eq_of_mem ha] at ho
    · refine' Or.inr <| Or.inr <| Or.inl <| Subset.antisymm _ _
      · rw [← Icc_diff_left]
        exact subset_diff_singleton hc ha
      · rwa [← Ioc_diff_right, diff_singleton_subset_iff, insert_eq_of_mem hb] at ho
    · refine' Or.inr <| Or.inr <| Or.inr <| Subset.antisymm _ ho
      rw [← Ico_diff_left, ← Icc_diff_right]
      apply_rules [subset_diff_singleton]
#align set.mem_Icc_Ico_Ioc_Ioo_of_subset_of_subset Set.mem_Icc_Ico_Ioc_Ioo_of_subset_of_subset

theorem eq_left_or_mem_Ioo_of_mem_Ico {x : α} (hmem : x ∈ Ico a b) : x = a ∨ x ∈ Ioo a b :=
  hmem.1.eq_or_gt.imp_right fun h => ⟨h, hmem.2⟩
#align set.eq_left_or_mem_Ioo_of_mem_Ico Set.eq_left_or_mem_Ioo_of_mem_Ico

theorem eq_right_or_mem_Ioo_of_mem_Ioc {x : α} (hmem : x ∈ Ioc a b) : x = b ∨ x ∈ Ioo a b :=
  hmem.2.eq_or_lt.imp_right <| And.intro hmem.1
#align set.eq_right_or_mem_Ioo_of_mem_Ioc Set.eq_right_or_mem_Ioo_of_mem_Ioc

theorem eq_endpoints_or_mem_Ioo_of_mem_Icc {x : α} (hmem : x ∈ Icc a b) :
    x = a ∨ x = b ∨ x ∈ Ioo a b :=
  hmem.1.eq_or_gt.imp_right fun h => eq_right_or_mem_Ioo_of_mem_Ioc ⟨h, hmem.2⟩
#align set.eq_endpoints_or_mem_Ioo_of_mem_Icc Set.eq_endpoints_or_mem_Ioo_of_mem_Icc

theorem _root_.IsMax.Ici_eq (h : IsMax a) : Ici a = {a} :=
  eq_singleton_iff_unique_mem.2 ⟨left_mem_Ici, fun _ => h.eq_of_ge⟩
#align is_max.Ici_eq IsMax.Ici_eq

theorem _root_.IsMin.Iic_eq (h : IsMin a) : Iic a = {a} :=
  h.toDual.Ici_eq
#align is_min.Iic_eq IsMin.Iic_eq

theorem Ici_injective : Injective (Ici : α → Set α) := fun _ _ =>
  eq_of_forall_ge_iff ∘ Set.ext_iff.1
#align set.Ici_injective Set.Ici_injective

theorem Iic_injective : Injective (Iic : α → Set α) := fun _ _ =>
  eq_of_forall_le_iff ∘ Set.ext_iff.1
#align set.Iic_injective Set.Iic_injective

theorem Ici_inj : Ici a = Ici b ↔ a = b :=
  Ici_injective.eq_iff
#align set.Ici_inj Set.Ici_inj

theorem Iic_inj : Iic a = Iic b ↔ a = b :=
  Iic_injective.eq_iff
#align set.Iic_inj Set.Iic_inj

end PartialOrder

section OrderTop

@[simp]
theorem Ici_top [PartialOrder α] [OrderTop α] : Ici (⊤ : α) = {⊤} :=
  isMax_top.Ici_eq
#align set.Ici_top Set.Ici_top

variable [Preorder α] [OrderTop α] {a : α}

@[simp]
theorem Ioi_top : Ioi (⊤ : α) = ∅ :=
  isMax_top.Ioi_eq
#align set.Ioi_top Set.Ioi_top

@[simp]
theorem Iic_top : Iic (⊤ : α) = univ :=
  isTop_top.Iic_eq
#align set.Iic_top Set.Iic_top

@[simp]
theorem Icc_top : Icc a ⊤ = Ici a := by simp [← Ici_inter_Iic]
#align set.Icc_top Set.Icc_top

@[simp]
theorem Ioc_top : Ioc a ⊤ = Ioi a := by simp [← Ioi_inter_Iic]
#align set.Ioc_top Set.Ioc_top

end OrderTop

section OrderBot

@[simp]
theorem Iic_bot [PartialOrder α] [OrderBot α] : Iic (⊥ : α) = {⊥} :=
  isMin_bot.Iic_eq
#align set.Iic_bot Set.Iic_bot

variable [Preorder α] [OrderBot α] {a : α}

@[simp]
theorem Iio_bot : Iio (⊥ : α) = ∅ :=
  isMin_bot.Iio_eq
#align set.Iio_bot Set.Iio_bot

@[simp]
theorem Ici_bot : Ici (⊥ : α) = univ :=
  isBot_bot.Ici_eq
#align set.Ici_bot Set.Ici_bot

@[simp]
theorem Icc_bot : Icc ⊥ a = Iic a := by simp [← Ici_inter_Iic]
#align set.Icc_bot Set.Icc_bot

@[simp]
theorem Ico_bot : Ico ⊥ a = Iio a := by simp [← Ici_inter_Iio]
#align set.Ico_bot Set.Ico_bot

end OrderBot

theorem Icc_bot_top [PartialOrder α] [BoundedOrder α] : Icc (⊥ : α) ⊤ = univ := by simp
#align set.Icc_bot_top Set.Icc_bot_top

section LinearOrder

variable [LinearOrder α] {a a₁ a₂ b b₁ b₂ c d : α}

theorem not_mem_Ici : c ∉ Ici a ↔ c < a :=
  not_le
#align set.not_mem_Ici Set.not_mem_Ici

theorem not_mem_Iic : c ∉ Iic b ↔ b < c :=
  not_le
#align set.not_mem_Iic Set.not_mem_Iic

theorem not_mem_Icc_of_lt (ha : c < a) : c ∉ Icc a b :=
  not_mem_subset Icc_subset_Ici_self <| not_mem_Ici.mpr ha
#align set.not_mem_Icc_of_lt Set.not_mem_Icc_of_lt

theorem not_mem_Icc_of_gt (hb : b < c) : c ∉ Icc a b :=
  not_mem_subset Icc_subset_Iic_self <| not_mem_Iic.mpr hb
#align set.not_mem_Icc_of_gt Set.not_mem_Icc_of_gt

theorem not_mem_Ico_of_lt (ha : c < a) : c ∉ Ico a b :=
  not_mem_subset Ico_subset_Ici_self <| not_mem_Ici.mpr ha
#align set.not_mem_Ico_of_lt Set.not_mem_Ico_of_lt

theorem not_mem_Ioc_of_gt (hb : b < c) : c ∉ Ioc a b :=
  not_mem_subset Ioc_subset_Iic_self <| not_mem_Iic.mpr hb
#align set.not_mem_Ioc_of_gt Set.not_mem_Ioc_of_gt

theorem not_mem_Ioi : c ∉ Ioi a ↔ c ≤ a :=
  not_lt
#align set.not_mem_Ioi Set.not_mem_Ioi

theorem not_mem_Iio : c ∉ Iio b ↔ b ≤ c :=
  not_lt
#align set.not_mem_Iio Set.not_mem_Iio

-- Porting note: `simp` can prove this
-- @[simp]
theorem not_mem_Ioi_self : a ∉ Ioi a :=
  lt_irrefl _
#align set.not_mem_Ioi_self Set.not_mem_Ioi_self

-- Porting note: `simp` can prove this
-- @[simp]
theorem not_mem_Iio_self : b ∉ Iio b :=
  lt_irrefl _
#align set.not_mem_Iio_self Set.not_mem_Iio_self

theorem not_mem_Ioc_of_le (ha : c ≤ a) : c ∉ Ioc a b :=
  not_mem_subset Ioc_subset_Ioi_self <| not_mem_Ioi.mpr ha
#align set.not_mem_Ioc_of_le Set.not_mem_Ioc_of_le

theorem not_mem_Ico_of_ge (hb : b ≤ c) : c ∉ Ico a b :=
  not_mem_subset Ico_subset_Iio_self <| not_mem_Iio.mpr hb
#align set.not_mem_Ico_of_ge Set.not_mem_Ico_of_ge

theorem not_mem_Ioo_of_le (ha : c ≤ a) : c ∉ Ioo a b :=
  not_mem_subset Ioo_subset_Ioi_self <| not_mem_Ioi.mpr ha
#align set.not_mem_Ioo_of_le Set.not_mem_Ioo_of_le

theorem not_mem_Ioo_of_ge (hb : b ≤ c) : c ∉ Ioo a b :=
  not_mem_subset Ioo_subset_Iio_self <| not_mem_Iio.mpr hb
#align set.not_mem_Ioo_of_ge Set.not_mem_Ioo_of_ge

@[simp]
theorem compl_Iic : Iic aᶜ = Ioi a :=
  ext fun _ => not_le
#align set.compl_Iic Set.compl_Iic

@[simp]
theorem compl_Ici : Ici aᶜ = Iio a :=
  ext fun _ => not_le
#align set.compl_Ici Set.compl_Ici

@[simp]
theorem compl_Iio : Iio aᶜ = Ici a :=
  ext fun _ => not_lt
#align set.compl_Iio Set.compl_Iio

@[simp]
theorem compl_Ioi : Ioi aᶜ = Iic a :=
  ext fun _ => not_lt
#align set.compl_Ioi Set.compl_Ioi

@[simp]
theorem Ici_diff_Ici : Ici a \ Ici b = Ico a b := by rw [diff_eq, compl_Ici, Ici_inter_Iio]
#align set.Ici_diff_Ici Set.Ici_diff_Ici

@[simp]
theorem Ici_diff_Ioi : Ici a \ Ioi b = Icc a b := by rw [diff_eq, compl_Ioi, Ici_inter_Iic]
#align set.Ici_diff_Ioi Set.Ici_diff_Ioi

@[simp]
theorem Ioi_diff_Ioi : Ioi a \ Ioi b = Ioc a b := by rw [diff_eq, compl_Ioi, Ioi_inter_Iic]
#align set.Ioi_diff_Ioi Set.Ioi_diff_Ioi

@[simp]
theorem Ioi_diff_Ici : Ioi a \ Ici b = Ioo a b := by rw [diff_eq, compl_Ici, Ioi_inter_Iio]
#align set.Ioi_diff_Ici Set.Ioi_diff_Ici

@[simp]
theorem Iic_diff_Iic : Iic b \ Iic a = Ioc a b := by
  rw [diff_eq, compl_Iic, inter_comm, Ioi_inter_Iic]
#align set.Iic_diff_Iic Set.Iic_diff_Iic

@[simp]
theorem Iio_diff_Iic : Iio b \ Iic a = Ioo a b := by
  rw [diff_eq, compl_Iic, inter_comm, Ioi_inter_Iio]
#align set.Iio_diff_Iic Set.Iio_diff_Iic

@[simp]
theorem Iic_diff_Iio : Iic b \ Iio a = Icc a b := by
  rw [diff_eq, compl_Iio, inter_comm, Ici_inter_Iic]
#align set.Iic_diff_Iio Set.Iic_diff_Iio

@[simp]
theorem Iio_diff_Iio : Iio b \ Iio a = Ico a b := by
  rw [diff_eq, compl_Iio, inter_comm, Ici_inter_Iio]
#align set.Iio_diff_Iio Set.Iio_diff_Iio

theorem Ioi_injective : Injective (Ioi : α → Set α) := fun _ _ =>
  eq_of_forall_gt_iff ∘ Set.ext_iff.1
#align set.Ioi_injective Set.Ioi_injective

theorem Iio_injective : Injective (Iio : α → Set α) := fun _ _ =>
  eq_of_forall_lt_iff ∘ Set.ext_iff.1
#align set.Iio_injective Set.Iio_injective

theorem Ioi_inj : Ioi a = Ioi b ↔ a = b :=
  Ioi_injective.eq_iff
#align set.Ioi_inj Set.Ioi_inj

theorem Iio_inj : Iio a = Iio b ↔ a = b :=
  Iio_injective.eq_iff
#align set.Iio_inj Set.Iio_inj

theorem Ico_subset_Ico_iff (h₁ : a₁ < b₁) : Ico a₁ b₁ ⊆ Ico a₂ b₂ ↔ a₂ ≤ a₁ ∧ b₁ ≤ b₂ :=
  ⟨fun h =>
    have : a₂ ≤ a₁ ∧ a₁ < b₂ := h ⟨le_rfl, h₁⟩
    ⟨this.1, le_of_not_lt fun h' => lt_irrefl b₂ (h ⟨this.2.le, h'⟩).2⟩,
    fun ⟨h₁, h₂⟩ => Ico_subset_Ico h₁ h₂⟩
#align set.Ico_subset_Ico_iff Set.Ico_subset_Ico_iff

theorem Ioc_subset_Ioc_iff (h₁ : a₁ < b₁) : Ioc a₁ b₁ ⊆ Ioc a₂ b₂ ↔ b₁ ≤ b₂ ∧ a₂ ≤ a₁ := by
  convert @Ico_subset_Ico_iff αᵒᵈ _ b₁ b₂ a₁ a₂ h₁ using 2 <;> exact (@dual_Ico α _ _ _).symm
#align set.Ioc_subset_Ioc_iff Set.Ioc_subset_Ioc_iff

theorem Ioo_subset_Ioo_iff [DenselyOrdered α] (h₁ : a₁ < b₁) :
    Ioo a₁ b₁ ⊆ Ioo a₂ b₂ ↔ a₂ ≤ a₁ ∧ b₁ ≤ b₂ :=
  ⟨fun h => by
    rcases exists_between h₁ with ⟨x, xa, xb⟩
    constructor <;> refine' le_of_not_lt fun h' => _
    · have ab := (h ⟨xa, xb⟩).1.trans xb
      exact lt_irrefl _ (h ⟨h', ab⟩).1
    · have ab := xa.trans (h ⟨xa, xb⟩).2
      exact lt_irrefl _ (h ⟨ab, h'⟩).2,
    fun ⟨h₁, h₂⟩ => Ioo_subset_Ioo h₁ h₂⟩
#align set.Ioo_subset_Ioo_iff Set.Ioo_subset_Ioo_iff

theorem Ico_eq_Ico_iff (h : a₁ < b₁ ∨ a₂ < b₂) : Ico a₁ b₁ = Ico a₂ b₂ ↔ a₁ = a₂ ∧ b₁ = b₂ :=
  ⟨fun e => by
      simp [Subset.antisymm_iff] at e
      simp [le_antisymm_iff]
      cases' h with h h <;>
      simp [Ico_subset_Ico_iff h] at e <;>
      [ rcases e with ⟨⟨h₁, h₂⟩, e'⟩, rcases e with ⟨e', ⟨h₁, h₂⟩⟩ ] <;>
      -- Porting note: restore `tauto`
      have hab := (Ico_subset_Ico_iff <| h₁.trans_lt <| h.trans_le h₂).1 e' <;>
      [ exact ⟨⟨hab.left, h₁⟩, ⟨h₂, hab.right⟩⟩, exact ⟨⟨h₁, hab.left⟩, ⟨hab.right, h₂⟩⟩ ],
    fun ⟨h₁, h₂⟩ => by rw [h₁, h₂]⟩
#align set.Ico_eq_Ico_iff Set.Ico_eq_Ico_iff

open Classical

@[simp]
theorem Ioi_subset_Ioi_iff : Ioi b ⊆ Ioi a ↔ a ≤ b := by
  refine' ⟨fun h => _, fun h => Ioi_subset_Ioi h⟩
  by_contra ba
  exact lt_irrefl _ (h (not_le.mp ba))
#align set.Ioi_subset_Ioi_iff Set.Ioi_subset_Ioi_iff

@[simp]
theorem Ioi_subset_Ici_iff [DenselyOrdered α] : Ioi b ⊆ Ici a ↔ a ≤ b := by
  refine' ⟨fun h => _, fun h => Ioi_subset_Ici h⟩
  by_contra ba
  obtain ⟨c, bc, ca⟩ : ∃ c, b < c ∧ c < a := exists_between (not_le.mp ba)
  exact lt_irrefl _ (ca.trans_le (h bc))
#align set.Ioi_subset_Ici_iff Set.Ioi_subset_Ici_iff

@[simp]
theorem Iio_subset_Iio_iff : Iio a ⊆ Iio b ↔ a ≤ b := by
  refine' ⟨fun h => _, fun h => Iio_subset_Iio h⟩
  by_contra ab
  exact lt_irrefl _ (h (not_le.mp ab))
#align set.Iio_subset_Iio_iff Set.Iio_subset_Iio_iff

@[simp]
theorem Iio_subset_Iic_iff [DenselyOrdered α] : Iio a ⊆ Iic b ↔ a ≤ b := by
  rw [← diff_eq_empty, Iio_diff_Iic, Ioo_eq_empty_iff, not_lt]
#align set.Iio_subset_Iic_iff Set.Iio_subset_Iic_iff

/-! ### Unions of adjacent intervals -/

/-! #### Two infinite intervals -/

theorem Iic_union_Ioi_of_le (h : a ≤ b) : Iic b ∪ Ioi a = univ :=
  eq_univ_of_forall fun x => (h.lt_or_le x).symm
#align set.Iic_union_Ioi_of_le Set.Iic_union_Ioi_of_le

theorem Iio_union_Ici_of_le (h : a ≤ b) : Iio b ∪ Ici a = univ :=
  eq_univ_of_forall fun x => (h.le_or_lt x).symm
#align set.Iio_union_Ici_of_le Set.Iio_union_Ici_of_le

theorem Iic_union_Ici_of_le (h : a ≤ b) : Iic b ∪ Ici a = univ :=
  eq_univ_of_forall fun x => (h.le_or_le x).symm
#align set.Iic_union_Ici_of_le Set.Iic_union_Ici_of_le

theorem Iio_union_Ioi_of_lt (h : a < b) : Iio b ∪ Ioi a = univ :=
  eq_univ_of_forall fun x => (h.lt_or_lt x).symm
#align set.Iio_union_Ioi_of_lt Set.Iio_union_Ioi_of_lt

@[simp]
theorem Iic_union_Ici : Iic a ∪ Ici a = univ :=
  Iic_union_Ici_of_le le_rfl
#align set.Iic_union_Ici Set.Iic_union_Ici

@[simp]
theorem Iio_union_Ici : Iio a ∪ Ici a = univ :=
  Iio_union_Ici_of_le le_rfl
#align set.Iio_union_Ici Set.Iio_union_Ici

@[simp]
theorem Iic_union_Ioi : Iic a ∪ Ioi a = univ :=
  Iic_union_Ioi_of_le le_rfl
#align set.Iic_union_Ioi Set.Iic_union_Ioi

@[simp]
theorem Iio_union_Ioi : Iio a ∪ Ioi a = {a}ᶜ :=
  ext fun _ => lt_or_lt_iff_ne
#align set.Iio_union_Ioi Set.Iio_union_Ioi

/-! #### A finite and an infinite interval -/

theorem Ioo_union_Ioi' (h₁ : c < b) : Ioo a b ∪ Ioi c = Ioi (min a c) := by
  ext1 x
  simp_rw [mem_union, mem_Ioo, mem_Ioi, min_lt_iff]
  by_cases hc : c < x
  · simp only [hc, or_true] -- Porting note: restore `tauto`
  · have hxb : x < b := (le_of_not_gt hc).trans_lt h₁
    simp only [hxb, and_true] -- Porting note: restore `tauto`
#align set.Ioo_union_Ioi' Set.Ioo_union_Ioi'

theorem Ioo_union_Ioi (h : c < max a b) : Ioo a b ∪ Ioi c = Ioi (min a c) := by
  cases' le_total a b with hab hab <;> simp [hab] at h
  · exact Ioo_union_Ioi' h
  · rw [min_comm]
    simp [*, min_eq_left_of_lt]
#align set.Ioo_union_Ioi Set.Ioo_union_Ioi

theorem Ioi_subset_Ioo_union_Ici : Ioi a ⊆ Ioo a b ∪ Ici b := fun x hx =>
  (lt_or_le x b).elim (fun hxb => Or.inl ⟨hx, hxb⟩) fun hxb => Or.inr hxb
#align set.Ioi_subset_Ioo_union_Ici Set.Ioi_subset_Ioo_union_Ici

@[simp]
theorem Ioo_union_Ici_eq_Ioi (h : a < b) : Ioo a b ∪ Ici b = Ioi a :=
  Subset.antisymm (fun _ hx => hx.elim And.left h.trans_le) Ioi_subset_Ioo_union_Ici
#align set.Ioo_union_Ici_eq_Ioi Set.Ioo_union_Ici_eq_Ioi

theorem Ici_subset_Ico_union_Ici : Ici a ⊆ Ico a b ∪ Ici b := fun x hx =>
  (lt_or_le x b).elim (fun hxb => Or.inl ⟨hx, hxb⟩) fun hxb => Or.inr hxb
#align set.Ici_subset_Ico_union_Ici Set.Ici_subset_Ico_union_Ici

@[simp]
theorem Ico_union_Ici_eq_Ici (h : a ≤ b) : Ico a b ∪ Ici b = Ici a :=
  Subset.antisymm (fun _ hx => hx.elim And.left h.trans) Ici_subset_Ico_union_Ici
#align set.Ico_union_Ici_eq_Ici Set.Ico_union_Ici_eq_Ici

theorem Ico_union_Ici' (h₁ : c ≤ b) : Ico a b ∪ Ici c = Ici (min a c) := by
  ext1 x
  simp_rw [mem_union, mem_Ico, mem_Ici, min_le_iff]
  by_cases hc : c ≤ x
  · simp only [hc, or_true] -- Porting note: restore `tauto`
  · have hxb : x < b := (lt_of_not_ge hc).trans_le h₁
    simp only [hxb, and_true] -- Porting note: restore `tauto`
#align set.Ico_union_Ici' Set.Ico_union_Ici'

theorem Ico_union_Ici (h : c ≤ max a b) : Ico a b ∪ Ici c = Ici (min a c) := by
  cases' le_total a b with hab hab <;> simp [hab] at h
  · exact Ico_union_Ici' h
  · simp [*]
#align set.Ico_union_Ici Set.Ico_union_Ici

theorem Ioi_subset_Ioc_union_Ioi : Ioi a ⊆ Ioc a b ∪ Ioi b := fun x hx =>
  (le_or_lt x b).elim (fun hxb => Or.inl ⟨hx, hxb⟩) fun hxb => Or.inr hxb
#align set.Ioi_subset_Ioc_union_Ioi Set.Ioi_subset_Ioc_union_Ioi

@[simp]
theorem Ioc_union_Ioi_eq_Ioi (h : a ≤ b) : Ioc a b ∪ Ioi b = Ioi a :=
  Subset.antisymm (fun _ hx => hx.elim And.left h.trans_lt) Ioi_subset_Ioc_union_Ioi
#align set.Ioc_union_Ioi_eq_Ioi Set.Ioc_union_Ioi_eq_Ioi

theorem Ioc_union_Ioi' (h₁ : c ≤ b) : Ioc a b ∪ Ioi c = Ioi (min a c) := by
  ext1 x
  simp_rw [mem_union, mem_Ioc, mem_Ioi, min_lt_iff]
  by_cases hc : c < x
  · simp only [hc, or_true] -- Porting note: restore `tauto`
  · have hxb : x ≤ b := (le_of_not_gt hc).trans h₁
    simp only [hxb, and_true] -- Porting note: restore `tauto`
#align set.Ioc_union_Ioi' Set.Ioc_union_Ioi'

theorem Ioc_union_Ioi (h : c ≤ max a b) : Ioc a b ∪ Ioi c = Ioi (min a c) := by
  cases' le_total a b with hab hab <;> simp [hab] at h
  · exact Ioc_union_Ioi' h
  · simp [*]
#align set.Ioc_union_Ioi Set.Ioc_union_Ioi

theorem Ici_subset_Icc_union_Ioi : Ici a ⊆ Icc a b ∪ Ioi b := fun x hx =>
  (le_or_lt x b).elim (fun hxb => Or.inl ⟨hx, hxb⟩) fun hxb => Or.inr hxb
#align set.Ici_subset_Icc_union_Ioi Set.Ici_subset_Icc_union_Ioi

@[simp]
theorem Icc_union_Ioi_eq_Ici (h : a ≤ b) : Icc a b ∪ Ioi b = Ici a :=
  Subset.antisymm (fun _ hx => (hx.elim And.left) fun hx' => h.trans <| le_of_lt hx')
    Ici_subset_Icc_union_Ioi
#align set.Icc_union_Ioi_eq_Ici Set.Icc_union_Ioi_eq_Ici

theorem Ioi_subset_Ioc_union_Ici : Ioi a ⊆ Ioc a b ∪ Ici b :=
  Subset.trans Ioi_subset_Ioo_union_Ici (union_subset_union_left _ Ioo_subset_Ioc_self)
#align set.Ioi_subset_Ioc_union_Ici Set.Ioi_subset_Ioc_union_Ici

@[simp]
theorem Ioc_union_Ici_eq_Ioi (h : a < b) : Ioc a b ∪ Ici b = Ioi a :=
  Subset.antisymm (fun _ hx => hx.elim And.left h.trans_le) Ioi_subset_Ioc_union_Ici
#align set.Ioc_union_Ici_eq_Ioi Set.Ioc_union_Ici_eq_Ioi

theorem Ici_subset_Icc_union_Ici : Ici a ⊆ Icc a b ∪ Ici b :=
  Subset.trans Ici_subset_Ico_union_Ici (union_subset_union_left _ Ico_subset_Icc_self)
#align set.Ici_subset_Icc_union_Ici Set.Ici_subset_Icc_union_Ici

@[simp]
theorem Icc_union_Ici_eq_Ici (h : a ≤ b) : Icc a b ∪ Ici b = Ici a :=
  Subset.antisymm (fun _ hx => hx.elim And.left h.trans) Ici_subset_Icc_union_Ici
#align set.Icc_union_Ici_eq_Ici Set.Icc_union_Ici_eq_Ici

theorem Icc_union_Ici' (h₁ : c ≤ b) : Icc a b ∪ Ici c = Ici (min a c) := by
  ext1 x
  simp_rw [mem_union, mem_Icc, mem_Ici, min_le_iff]
  by_cases hc : c ≤ x
  · simp only [hc, or_true] -- Porting note: restore `tauto`
  · have hxb : x ≤ b := (le_of_not_ge hc).trans h₁
    simp only [hxb, and_true] -- Porting note: restore `tauto`
#align set.Icc_union_Ici' Set.Icc_union_Ici'

theorem Icc_union_Ici (h : c ≤ max a b) : Icc a b ∪ Ici c = Ici (min a c) := by
  cases' le_or_lt a b with hab hab <;> simp [hab] at h
  · exact Icc_union_Ici' h
  · cases' h with h h
    · simp [*]
    · have hca : c ≤ a := h.trans hab.le
      simp [*]
#align set.Icc_union_Ici Set.Icc_union_Ici

/-! #### An infinite and a finite interval -/

theorem Iic_subset_Iio_union_Icc : Iic b ⊆ Iio a ∪ Icc a b := fun x hx =>
  (lt_or_le x a).elim (fun hxa => Or.inl hxa) fun hxa => Or.inr ⟨hxa, hx⟩
#align set.Iic_subset_Iio_union_Icc Set.Iic_subset_Iio_union_Icc

@[simp]
theorem Iio_union_Icc_eq_Iic (h : a ≤ b) : Iio a ∪ Icc a b = Iic b :=
  Subset.antisymm (fun _ hx => hx.elim (fun hx => (le_of_lt hx).trans h) And.right)
    Iic_subset_Iio_union_Icc
#align set.Iio_union_Icc_eq_Iic Set.Iio_union_Icc_eq_Iic

theorem Iio_subset_Iio_union_Ico : Iio b ⊆ Iio a ∪ Ico a b := fun x hx =>
  (lt_or_le x a).elim (fun hxa => Or.inl hxa) fun hxa => Or.inr ⟨hxa, hx⟩
#align set.Iio_subset_Iio_union_Ico Set.Iio_subset_Iio_union_Ico

@[simp]
theorem Iio_union_Ico_eq_Iio (h : a ≤ b) : Iio a ∪ Ico a b = Iio b :=
  Subset.antisymm (fun _ hx => hx.elim (fun hx' => lt_of_lt_of_le hx' h) And.right)
    Iio_subset_Iio_union_Ico
#align set.Iio_union_Ico_eq_Iio Set.Iio_union_Ico_eq_Iio

theorem Iio_union_Ico' (h₁ : c ≤ b) : Iio b ∪ Ico c d = Iio (max b d) := by
  ext1 x
  simp_rw [mem_union, mem_Iio, mem_Ico, lt_max_iff]
  by_cases hc : c ≤ x
  · simp only [hc, true_and] -- Porting note: restore `tauto`
  · have hxb : x < b := (lt_of_not_ge hc).trans_le h₁
    simp only [hxb, true_or] -- Porting note: restore `tauto`
#align set.Iio_union_Ico' Set.Iio_union_Ico'

theorem Iio_union_Ico (h : min c d ≤ b) : Iio b ∪ Ico c d = Iio (max b d) := by
  cases' le_total c d with hcd hcd <;> simp [hcd] at h
  · exact Iio_union_Ico' h
  · simp [*]
#align set.Iio_union_Ico Set.Iio_union_Ico

theorem Iic_subset_Iic_union_Ioc : Iic b ⊆ Iic a ∪ Ioc a b := fun x hx =>
  (le_or_lt x a).elim (fun hxa => Or.inl hxa) fun hxa => Or.inr ⟨hxa, hx⟩
#align set.Iic_subset_Iic_union_Ioc Set.Iic_subset_Iic_union_Ioc

@[simp]
theorem Iic_union_Ioc_eq_Iic (h : a ≤ b) : Iic a ∪ Ioc a b = Iic b :=
  Subset.antisymm (fun _ hx => hx.elim (fun hx' => le_trans hx' h) And.right)
    Iic_subset_Iic_union_Ioc
#align set.Iic_union_Ioc_eq_Iic Set.Iic_union_Ioc_eq_Iic

theorem Iic_union_Ioc' (h₁ : c < b) : Iic b ∪ Ioc c d = Iic (max b d) := by
  ext1 x
  simp_rw [mem_union, mem_Iic, mem_Ioc, le_max_iff]
  by_cases hc : c < x
  · simp only [hc, true_and] -- Porting note: restore `tauto`
  · have hxb : x ≤ b := (le_of_not_gt hc).trans h₁.le
    simp only [hxb, true_or] -- Porting note: restore `tauto`
#align set.Iic_union_Ioc' Set.Iic_union_Ioc'

theorem Iic_union_Ioc (h : min c d < b) : Iic b ∪ Ioc c d = Iic (max b d) := by
  cases' le_total c d with hcd hcd <;> simp [hcd] at h
  · exact Iic_union_Ioc' h
  · rw [max_comm]
    simp [*, max_eq_right_of_lt h]
#align set.Iic_union_Ioc Set.Iic_union_Ioc

theorem Iio_subset_Iic_union_Ioo : Iio b ⊆ Iic a ∪ Ioo a b := fun x hx =>
  (le_or_lt x a).elim (fun hxa => Or.inl hxa) fun hxa => Or.inr ⟨hxa, hx⟩
#align set.Iio_subset_Iic_union_Ioo Set.Iio_subset_Iic_union_Ioo

@[simp]
theorem Iic_union_Ioo_eq_Iio (h : a < b) : Iic a ∪ Ioo a b = Iio b :=
  Subset.antisymm (fun _ hx => hx.elim (fun hx' => lt_of_le_of_lt hx' h) And.right)
    Iio_subset_Iic_union_Ioo
#align set.Iic_union_Ioo_eq_Iio Set.Iic_union_Ioo_eq_Iio

theorem Iio_union_Ioo' (h₁ : c < b) : Iio b ∪ Ioo c d = Iio (max b d) := by
  ext x
  cases' lt_or_le x b with hba hba
  · simp [hba, h₁]
  · simp only [mem_Iio, mem_union, mem_Ioo, lt_max_iff]
    refine' or_congr Iff.rfl ⟨And.right, _⟩
    exact fun h₂ => ⟨h₁.trans_le hba, h₂⟩
#align set.Iio_union_Ioo' Set.Iio_union_Ioo'

theorem Iio_union_Ioo (h : min c d < b) : Iio b ∪ Ioo c d = Iio (max b d) := by
  cases' le_total c d with hcd hcd <;> simp [hcd] at h
  · exact Iio_union_Ioo' h
  · rw [max_comm]
    simp [*, max_eq_right_of_lt h]
#align set.Iio_union_Ioo Set.Iio_union_Ioo

theorem Iic_subset_Iic_union_Icc : Iic b ⊆ Iic a ∪ Icc a b :=
  Subset.trans Iic_subset_Iic_union_Ioc (union_subset_union_right _ Ioc_subset_Icc_self)
#align set.Iic_subset_Iic_union_Icc Set.Iic_subset_Iic_union_Icc

@[simp]
theorem Iic_union_Icc_eq_Iic (h : a ≤ b) : Iic a ∪ Icc a b = Iic b :=
  Subset.antisymm (fun _ hx => hx.elim (fun hx' => le_trans hx' h) And.right)
    Iic_subset_Iic_union_Icc
#align set.Iic_union_Icc_eq_Iic Set.Iic_union_Icc_eq_Iic

theorem Iic_union_Icc' (h₁ : c ≤ b) : Iic b ∪ Icc c d = Iic (max b d) := by
  ext1 x
  simp_rw [mem_union, mem_Iic, mem_Icc, le_max_iff]
  by_cases hc : c ≤ x
  · simp only [hc, true_and] -- Porting note: restore `tauto`
  · have hxb : x ≤ b := (le_of_not_ge hc).trans h₁
    simp only [hxb, true_or] -- Porting note: restore `tauto`
#align set.Iic_union_Icc' Set.Iic_union_Icc'

theorem Iic_union_Icc (h : min c d ≤ b) : Iic b ∪ Icc c d = Iic (max b d) := by
  cases' le_or_lt c d with hcd hcd <;> simp [hcd] at h
  · exact Iic_union_Icc' h
  · cases' h with h h
    · have hdb : d ≤ b := hcd.le.trans h
      simp [*]
    · simp [*]
#align set.Iic_union_Icc Set.Iic_union_Icc

theorem Iio_subset_Iic_union_Ico : Iio b ⊆ Iic a ∪ Ico a b :=
  Subset.trans Iio_subset_Iic_union_Ioo (union_subset_union_right _ Ioo_subset_Ico_self)
#align set.Iio_subset_Iic_union_Ico Set.Iio_subset_Iic_union_Ico

@[simp]
theorem Iic_union_Ico_eq_Iio (h : a < b) : Iic a ∪ Ico a b = Iio b :=
  Subset.antisymm (fun _ hx => hx.elim (fun hx' => lt_of_le_of_lt hx' h) And.right)
    Iio_subset_Iic_union_Ico
#align set.Iic_union_Ico_eq_Iio Set.Iic_union_Ico_eq_Iio

/-! #### Two finite intervals, `I?o` and `Ic?` -/

theorem Ioo_subset_Ioo_union_Ico : Ioo a c ⊆ Ioo a b ∪ Ico b c := fun x hx =>
  (lt_or_le x b).elim (fun hxb => Or.inl ⟨hx.1, hxb⟩) fun hxb => Or.inr ⟨hxb, hx.2⟩
#align set.Ioo_subset_Ioo_union_Ico Set.Ioo_subset_Ioo_union_Ico

@[simp]
theorem Ioo_union_Ico_eq_Ioo (h₁ : a < b) (h₂ : b ≤ c) : Ioo a b ∪ Ico b c = Ioo a c :=
  Subset.antisymm
    (fun _ hx => hx.elim (fun hx => ⟨hx.1, hx.2.trans_le h₂⟩) fun hx => ⟨h₁.trans_le hx.1, hx.2⟩)
    Ioo_subset_Ioo_union_Ico
#align set.Ioo_union_Ico_eq_Ioo Set.Ioo_union_Ico_eq_Ioo

theorem Ico_subset_Ico_union_Ico : Ico a c ⊆ Ico a b ∪ Ico b c := fun x hx =>
  (lt_or_le x b).elim (fun hxb => Or.inl ⟨hx.1, hxb⟩) fun hxb => Or.inr ⟨hxb, hx.2⟩
#align set.Ico_subset_Ico_union_Ico Set.Ico_subset_Ico_union_Ico

@[simp]
theorem Ico_union_Ico_eq_Ico (h₁ : a ≤ b) (h₂ : b ≤ c) : Ico a b ∪ Ico b c = Ico a c :=
  Subset.antisymm
    (fun _ hx => hx.elim (fun hx => ⟨hx.1, hx.2.trans_le h₂⟩) fun hx => ⟨h₁.trans hx.1, hx.2⟩)
    Ico_subset_Ico_union_Ico
#align set.Ico_union_Ico_eq_Ico Set.Ico_union_Ico_eq_Ico

theorem Ico_union_Ico' (h₁ : c ≤ b) (h₂ : a ≤ d) : Ico a b ∪ Ico c d = Ico (min a c) (max b d) := by
  ext1 x
  simp_rw [mem_union, mem_Ico, min_le_iff, lt_max_iff]
  by_cases hc : c ≤ x <;> by_cases hd : x < d
  · simp only [hc, hd, and_self, or_true] -- Porting note: restore `tauto`
  · have hax : a ≤ x := h₂.trans (le_of_not_gt hd)
    simp only [hax, true_and, hc, or_self] -- Porting note: restore `tauto`
  · have hxb : x < b := (lt_of_not_ge hc).trans_le h₁
    simp only [hxb, and_true, hc, false_and, or_false, true_or] -- Porting note: restore `tauto`
  · simp only [hc, hd, and_self, or_false] -- Porting note: restore `tauto`
#align set.Ico_union_Ico' Set.Ico_union_Ico'

theorem Ico_union_Ico (h₁ : min a b ≤ max c d) (h₂ : min c d ≤ max a b) :
    Ico a b ∪ Ico c d = Ico (min a c) (max b d) := by
  cases' le_total a b with hab hab <;> cases' le_total c d with hcd hcd <;> simp [hab, hcd] at h₁ h₂
  · exact Ico_union_Ico' h₂ h₁
  all_goals simp [*]
#align set.Ico_union_Ico Set.Ico_union_Ico

theorem Icc_subset_Ico_union_Icc : Icc a c ⊆ Ico a b ∪ Icc b c := fun x hx =>
  (lt_or_le x b).elim (fun hxb => Or.inl ⟨hx.1, hxb⟩) fun hxb => Or.inr ⟨hxb, hx.2⟩
#align set.Icc_subset_Ico_union_Icc Set.Icc_subset_Ico_union_Icc

@[simp]
theorem Ico_union_Icc_eq_Icc (h₁ : a ≤ b) (h₂ : b ≤ c) : Ico a b ∪ Icc b c = Icc a c :=
  Subset.antisymm
    (fun _ hx => hx.elim (fun hx => ⟨hx.1, hx.2.le.trans h₂⟩) fun hx => ⟨h₁.trans hx.1, hx.2⟩)
    Icc_subset_Ico_union_Icc
#align set.Ico_union_Icc_eq_Icc Set.Ico_union_Icc_eq_Icc

theorem Ioc_subset_Ioo_union_Icc : Ioc a c ⊆ Ioo a b ∪ Icc b c := fun x hx =>
  (lt_or_le x b).elim (fun hxb => Or.inl ⟨hx.1, hxb⟩) fun hxb => Or.inr ⟨hxb, hx.2⟩
#align set.Ioc_subset_Ioo_union_Icc Set.Ioc_subset_Ioo_union_Icc

@[simp]
theorem Ioo_union_Icc_eq_Ioc (h₁ : a < b) (h₂ : b ≤ c) : Ioo a b ∪ Icc b c = Ioc a c :=
  Subset.antisymm
    (fun _ hx => hx.elim (fun hx => ⟨hx.1, hx.2.le.trans h₂⟩) fun hx => ⟨h₁.trans_le hx.1, hx.2⟩)
    Ioc_subset_Ioo_union_Icc
#align set.Ioo_union_Icc_eq_Ioc Set.Ioo_union_Icc_eq_Ioc

/-! #### Two finite intervals, `I?c` and `Io?` -/

theorem Ioo_subset_Ioc_union_Ioo : Ioo a c ⊆ Ioc a b ∪ Ioo b c := fun x hx =>
  (le_or_lt x b).elim (fun hxb => Or.inl ⟨hx.1, hxb⟩) fun hxb => Or.inr ⟨hxb, hx.2⟩
#align set.Ioo_subset_Ioc_union_Ioo Set.Ioo_subset_Ioc_union_Ioo

@[simp]
theorem Ioc_union_Ioo_eq_Ioo (h₁ : a ≤ b) (h₂ : b < c) : Ioc a b ∪ Ioo b c = Ioo a c :=
  Subset.antisymm
    (fun _ hx => hx.elim (fun hx => ⟨hx.1, hx.2.trans_lt h₂⟩) fun hx => ⟨h₁.trans_lt hx.1, hx.2⟩)
    Ioo_subset_Ioc_union_Ioo
#align set.Ioc_union_Ioo_eq_Ioo Set.Ioc_union_Ioo_eq_Ioo

theorem Ico_subset_Icc_union_Ioo : Ico a c ⊆ Icc a b ∪ Ioo b c := fun x hx =>
  (le_or_lt x b).elim (fun hxb => Or.inl ⟨hx.1, hxb⟩) fun hxb => Or.inr ⟨hxb, hx.2⟩
#align set.Ico_subset_Icc_union_Ioo Set.Ico_subset_Icc_union_Ioo

@[simp]
theorem Icc_union_Ioo_eq_Ico (h₁ : a ≤ b) (h₂ : b < c) : Icc a b ∪ Ioo b c = Ico a c :=
  Subset.antisymm
    (fun _ hx => hx.elim (fun hx => ⟨hx.1, hx.2.trans_lt h₂⟩) fun hx => ⟨h₁.trans hx.1.le, hx.2⟩)
    Ico_subset_Icc_union_Ioo
#align set.Icc_union_Ioo_eq_Ico Set.Icc_union_Ioo_eq_Ico

theorem Icc_subset_Icc_union_Ioc : Icc a c ⊆ Icc a b ∪ Ioc b c := fun x hx =>
  (le_or_lt x b).elim (fun hxb => Or.inl ⟨hx.1, hxb⟩) fun hxb => Or.inr ⟨hxb, hx.2⟩
#align set.Icc_subset_Icc_union_Ioc Set.Icc_subset_Icc_union_Ioc

@[simp]
theorem Icc_union_Ioc_eq_Icc (h₁ : a ≤ b) (h₂ : b ≤ c) : Icc a b ∪ Ioc b c = Icc a c :=
  Subset.antisymm
    (fun _ hx => hx.elim (fun hx => ⟨hx.1, hx.2.trans h₂⟩) fun hx => ⟨h₁.trans hx.1.le, hx.2⟩)
    Icc_subset_Icc_union_Ioc
#align set.Icc_union_Ioc_eq_Icc Set.Icc_union_Ioc_eq_Icc

theorem Ioc_subset_Ioc_union_Ioc : Ioc a c ⊆ Ioc a b ∪ Ioc b c := fun x hx =>
  (le_or_lt x b).elim (fun hxb => Or.inl ⟨hx.1, hxb⟩) fun hxb => Or.inr ⟨hxb, hx.2⟩
#align set.Ioc_subset_Ioc_union_Ioc Set.Ioc_subset_Ioc_union_Ioc

@[simp]
theorem Ioc_union_Ioc_eq_Ioc (h₁ : a ≤ b) (h₂ : b ≤ c) : Ioc a b ∪ Ioc b c = Ioc a c :=
  Subset.antisymm
    (fun _ hx => hx.elim (fun hx => ⟨hx.1, hx.2.trans h₂⟩) fun hx => ⟨h₁.trans_lt hx.1, hx.2⟩)
    Ioc_subset_Ioc_union_Ioc
#align set.Ioc_union_Ioc_eq_Ioc Set.Ioc_union_Ioc_eq_Ioc

theorem Ioc_union_Ioc' (h₁ : c ≤ b) (h₂ : a ≤ d) : Ioc a b ∪ Ioc c d = Ioc (min a c) (max b d) := by
  ext1 x
  simp_rw [mem_union, mem_Ioc, min_lt_iff, le_max_iff]
  by_cases hc : c < x <;> by_cases hd : x ≤ d
  · simp only [hc, hd, and_self, or_true] -- Porting note: restore `tauto`
  · have hax : a < x := h₂.trans_lt (lt_of_not_ge hd)
    simp only [hax, true_and, hc, or_self] -- Porting note: restore `tauto`
  · have hxb : x ≤ b := (le_of_not_gt hc).trans h₁
    simp only [hxb, and_true, hc, false_and, or_false, true_or] -- Porting note: restore `tauto`
  · simp only [hc, hd, and_self, or_false] -- Porting note: restore `tauto`
#align set.Ioc_union_Ioc' Set.Ioc_union_Ioc'

theorem Ioc_union_Ioc (h₁ : min a b ≤ max c d) (h₂ : min c d ≤ max a b) :
    Ioc a b ∪ Ioc c d = Ioc (min a c) (max b d) := by
  cases' le_total a b with hab hab <;> cases' le_total c d with hcd hcd <;> simp [hab, hcd] at h₁ h₂
  · exact Ioc_union_Ioc' h₂ h₁
  all_goals simp [*]
#align set.Ioc_union_Ioc Set.Ioc_union_Ioc

/-! #### Two finite intervals with a common point -/

theorem Ioo_subset_Ioc_union_Ico : Ioo a c ⊆ Ioc a b ∪ Ico b c :=
  Subset.trans Ioo_subset_Ioc_union_Ioo (union_subset_union_right _ Ioo_subset_Ico_self)
#align set.Ioo_subset_Ioc_union_Ico Set.Ioo_subset_Ioc_union_Ico

@[simp]
theorem Ioc_union_Ico_eq_Ioo (h₁ : a < b) (h₂ : b < c) : Ioc a b ∪ Ico b c = Ioo a c :=
  Subset.antisymm
    (fun _ hx =>
      hx.elim (fun hx' => ⟨hx'.1, hx'.2.trans_lt h₂⟩) fun hx' => ⟨h₁.trans_le hx'.1, hx'.2⟩)
    Ioo_subset_Ioc_union_Ico
#align set.Ioc_union_Ico_eq_Ioo Set.Ioc_union_Ico_eq_Ioo

theorem Ico_subset_Icc_union_Ico : Ico a c ⊆ Icc a b ∪ Ico b c :=
  Subset.trans Ico_subset_Icc_union_Ioo (union_subset_union_right _ Ioo_subset_Ico_self)
#align set.Ico_subset_Icc_union_Ico Set.Ico_subset_Icc_union_Ico

@[simp]
theorem Icc_union_Ico_eq_Ico (h₁ : a ≤ b) (h₂ : b < c) : Icc a b ∪ Ico b c = Ico a c :=
  Subset.antisymm
    (fun _ hx => hx.elim (fun hx => ⟨hx.1, hx.2.trans_lt h₂⟩) fun hx => ⟨h₁.trans hx.1, hx.2⟩)
    Ico_subset_Icc_union_Ico
#align set.Icc_union_Ico_eq_Ico Set.Icc_union_Ico_eq_Ico

theorem Icc_subset_Icc_union_Icc : Icc a c ⊆ Icc a b ∪ Icc b c :=
  Subset.trans Icc_subset_Icc_union_Ioc (union_subset_union_right _ Ioc_subset_Icc_self)
#align set.Icc_subset_Icc_union_Icc Set.Icc_subset_Icc_union_Icc

@[simp]
theorem Icc_union_Icc_eq_Icc (h₁ : a ≤ b) (h₂ : b ≤ c) : Icc a b ∪ Icc b c = Icc a c :=
  Subset.antisymm
    (fun _ hx => hx.elim (fun hx => ⟨hx.1, hx.2.trans h₂⟩) fun hx => ⟨h₁.trans hx.1, hx.2⟩)
    Icc_subset_Icc_union_Icc
#align set.Icc_union_Icc_eq_Icc Set.Icc_union_Icc_eq_Icc

theorem Icc_union_Icc' (h₁ : c ≤ b) (h₂ : a ≤ d) : Icc a b ∪ Icc c d = Icc (min a c) (max b d) := by
  ext1 x
  simp_rw [mem_union, mem_Icc, min_le_iff, le_max_iff]
  by_cases hc : c ≤ x <;> by_cases hd : x ≤ d
  · simp only [hc, hd, and_self, or_true] -- Porting note: restore `tauto`
  · have hax : a ≤ x := h₂.trans (le_of_not_ge hd)
    simp only [hax, true_and, hc, or_self] -- Porting note: restore `tauto`
  · have hxb : x ≤ b := (le_of_not_ge hc).trans h₁
    simp only [hxb, and_true, hc, false_and, or_false, true_or] -- Porting note: restore `tauto`
  · simp only [hc, hd, and_self, or_false] -- Porting note: restore `tauto`
#align set.Icc_union_Icc' Set.Icc_union_Icc'

/-- We cannot replace `<` by `≤` in the hypotheses.
Otherwise for `b < a = d < c` the l.h.s. is `∅` and the r.h.s. is `{a}`.
-/
theorem Icc_union_Icc (h₁ : min a b < max c d) (h₂ : min c d < max a b) :
    Icc a b ∪ Icc c d = Icc (min a c) (max b d) := by
  cases' le_or_lt a b with hab hab <;> cases' le_or_lt c d with hcd hcd <;>
    simp only [min_eq_left, min_eq_right, max_eq_left, max_eq_right, min_eq_left_of_lt,
      min_eq_right_of_lt, max_eq_left_of_lt, max_eq_right_of_lt, hab, hcd] at h₁ h₂
  · exact Icc_union_Icc' h₂.le h₁.le
  all_goals simp [*, min_eq_left_of_lt, max_eq_left_of_lt, min_eq_right_of_lt, max_eq_right_of_lt]
#align set.Icc_union_Icc Set.Icc_union_Icc

theorem Ioc_subset_Ioc_union_Icc : Ioc a c ⊆ Ioc a b ∪ Icc b c :=
  Subset.trans Ioc_subset_Ioc_union_Ioc (union_subset_union_right _ Ioc_subset_Icc_self)
#align set.Ioc_subset_Ioc_union_Icc Set.Ioc_subset_Ioc_union_Icc

@[simp]
theorem Ioc_union_Icc_eq_Ioc (h₁ : a < b) (h₂ : b ≤ c) : Ioc a b ∪ Icc b c = Ioc a c :=
  Subset.antisymm
    (fun _ hx => hx.elim (fun hx => ⟨hx.1, hx.2.trans h₂⟩) fun hx => ⟨h₁.trans_le hx.1, hx.2⟩)
    Ioc_subset_Ioc_union_Icc
#align set.Ioc_union_Icc_eq_Ioc Set.Ioc_union_Icc_eq_Ioc

theorem Ioo_union_Ioo' (h₁ : c < b) (h₂ : a < d) : Ioo a b ∪ Ioo c d = Ioo (min a c) (max b d) := by
  ext1 x
  simp_rw [mem_union, mem_Ioo, min_lt_iff, lt_max_iff]
  by_cases hc : c < x <;> by_cases hd : x < d
  · simp only [hc, hd, and_self, or_true] -- Porting note: restore `tauto`
  · have hax : a < x := h₂.trans_le (le_of_not_lt hd)
    simp only [hax, true_and, hc, or_self] -- Porting note: restore `tauto`
  · have hxb : x < b := (le_of_not_lt hc).trans_lt h₁
    simp only [hxb, and_true, hc, false_and, or_false, true_or] -- Porting note: restore `tauto`
  · simp only [hc, hd, and_self, or_false] -- Porting note: restore `tauto`
#align set.Ioo_union_Ioo' Set.Ioo_union_Ioo'

theorem Ioo_union_Ioo (h₁ : min a b < max c d) (h₂ : min c d < max a b) :
    Ioo a b ∪ Ioo c d = Ioo (min a c) (max b d) := by
  cases' le_total a b with hab hab <;> cases' le_total c d with hcd hcd <;>
    simp only [min_eq_left, min_eq_right, max_eq_left, max_eq_right, hab, hcd] at h₁ h₂
  · exact Ioo_union_Ioo' h₂ h₁
  all_goals
    simp [*, min_eq_left_of_lt, min_eq_right_of_lt, max_eq_left_of_lt, max_eq_right_of_lt,
      le_of_lt h₂, le_of_lt h₁]
#align set.Ioo_union_Ioo Set.Ioo_union_Ioo

end LinearOrder

section Lattice

section Inf

variable [SemilatticeInf α]

@[simp]
theorem Iic_inter_Iic {a b : α} : Iic a ∩ Iic b = Iic (a ⊓ b) := by
  ext x
  simp [Iic]
#align set.Iic_inter_Iic Set.Iic_inter_Iic

@[simp]
theorem Ioc_inter_Iic (a b c : α) : Ioc a b ∩ Iic c = Ioc a (b ⊓ c) := by
  rw [← Ioi_inter_Iic, ← Ioi_inter_Iic, inter_assoc, Iic_inter_Iic]
#align set.Ioc_inter_Iic Set.Ioc_inter_Iic

end Inf

section Sup

variable [SemilatticeSup α]

@[simp]
theorem Ici_inter_Ici {a b : α} : Ici a ∩ Ici b = Ici (a ⊔ b) := by
  ext x
  simp [Ici]
#align set.Ici_inter_Ici Set.Ici_inter_Ici

@[simp]
theorem Ico_inter_Ici (a b c : α) : Ico a b ∩ Ici c = Ico (a ⊔ c) b := by
  rw [← Ici_inter_Iio, ← Ici_inter_Iio, ← Ici_inter_Ici, inter_right_comm]
#align set.Ico_inter_Ici Set.Ico_inter_Ici

end Sup

section Both

variable [Lattice α] {a b c a₁ a₂ b₁ b₂ : α}

theorem Icc_inter_Icc : Icc a₁ b₁ ∩ Icc a₂ b₂ = Icc (a₁ ⊔ a₂) (b₁ ⊓ b₂) := by
  simp only [Ici_inter_Iic.symm, Ici_inter_Ici.symm, Iic_inter_Iic.symm]; ac_rfl
#align set.Icc_inter_Icc Set.Icc_inter_Icc

@[simp]
theorem Icc_inter_Icc_eq_singleton (hab : a ≤ b) (hbc : b ≤ c) : Icc a b ∩ Icc b c = {b} := by
  rw [Icc_inter_Icc, sup_of_le_right hab, inf_of_le_left hbc, Icc_self]
#align set.Icc_inter_Icc_eq_singleton Set.Icc_inter_Icc_eq_singleton

end Both

end Lattice

section LinearOrder

variable [LinearOrder α] [LinearOrder β] {f : α → β} {a a₁ a₂ b b₁ b₂ c d : α}

@[simp]
theorem Ioi_inter_Ioi : Ioi a ∩ Ioi b = Ioi (a ⊔ b) :=
  ext fun _ => sup_lt_iff.symm
#align set.Ioi_inter_Ioi Set.Ioi_inter_Ioi

@[simp]
theorem Iio_inter_Iio : Iio a ∩ Iio b = Iio (a ⊓ b) :=
  ext fun _ => lt_inf_iff.symm
#align set.Iio_inter_Iio Set.Iio_inter_Iio

theorem Ico_inter_Ico : Ico a₁ b₁ ∩ Ico a₂ b₂ = Ico (a₁ ⊔ a₂) (b₁ ⊓ b₂) := by
  simp only [Ici_inter_Iio.symm, Ici_inter_Ici.symm, Iio_inter_Iio.symm]; ac_rfl
#align set.Ico_inter_Ico Set.Ico_inter_Ico

theorem Ioc_inter_Ioc : Ioc a₁ b₁ ∩ Ioc a₂ b₂ = Ioc (a₁ ⊔ a₂) (b₁ ⊓ b₂) := by
  simp only [Ioi_inter_Iic.symm, Ioi_inter_Ioi.symm, Iic_inter_Iic.symm]; ac_rfl
#align set.Ioc_inter_Ioc Set.Ioc_inter_Ioc

theorem Ioo_inter_Ioo : Ioo a₁ b₁ ∩ Ioo a₂ b₂ = Ioo (a₁ ⊔ a₂) (b₁ ⊓ b₂) := by
  simp only [Ioi_inter_Iio.symm, Ioi_inter_Ioi.symm, Iio_inter_Iio.symm]; ac_rfl
#align set.Ioo_inter_Ioo Set.Ioo_inter_Ioo

theorem Ioc_inter_Ioo_of_left_lt (h : b₁ < b₂) : Ioc a₁ b₁ ∩ Ioo a₂ b₂ = Ioc (max a₁ a₂) b₁ :=
  ext fun x => by
    simp [and_assoc, @and_left_comm (x ≤ _), and_iff_left_iff_imp.2 fun h' => lt_of_le_of_lt h' h]
#align set.Ioc_inter_Ioo_of_left_lt Set.Ioc_inter_Ioo_of_left_lt

theorem Ioc_inter_Ioo_of_right_le (h : b₂ ≤ b₁) : Ioc a₁ b₁ ∩ Ioo a₂ b₂ = Ioo (max a₁ a₂) b₂ :=
  ext fun x => by
    simp [and_assoc, @and_left_comm (x ≤ _),
      and_iff_right_iff_imp.2 fun h' => (le_of_lt h').trans h]
#align set.Ioc_inter_Ioo_of_right_le Set.Ioc_inter_Ioo_of_right_le

theorem Ioo_inter_Ioc_of_left_le (h : b₁ ≤ b₂) : Ioo a₁ b₁ ∩ Ioc a₂ b₂ = Ioo (max a₁ a₂) b₁ := by
  rw [inter_comm, Ioc_inter_Ioo_of_right_le h, max_comm]
#align set.Ioo_inter_Ioc_of_left_le Set.Ioo_inter_Ioc_of_left_le

theorem Ioo_inter_Ioc_of_right_lt (h : b₂ < b₁) : Ioo a₁ b₁ ∩ Ioc a₂ b₂ = Ioc (max a₁ a₂) b₂ := by
  rw [inter_comm, Ioc_inter_Ioo_of_left_lt h, max_comm]
#align set.Ioo_inter_Ioc_of_right_lt Set.Ioo_inter_Ioc_of_right_lt

@[simp]
theorem Ico_diff_Iio : Ico a b \ Iio c = Ico (max a c) b := by
  rw [diff_eq, compl_Iio, Ico_inter_Ici, sup_eq_max]
#align set.Ico_diff_Iio Set.Ico_diff_Iio

@[simp]
theorem Ioc_diff_Ioi : Ioc a b \ Ioi c = Ioc a (min b c) :=
  ext <| by simp (config := { contextual := true }) [iff_def]
#align set.Ioc_diff_Ioi Set.Ioc_diff_Ioi

@[simp]
theorem Ioc_inter_Ioi : Ioc a b ∩ Ioi c = Ioc (a ⊔ c) b := by
  rw [← Ioi_inter_Iic, inter_assoc, inter_comm, inter_assoc, Ioi_inter_Ioi, inter_comm,
    Ioi_inter_Iic, sup_comm]
#align set.Ioc_inter_Ioi Set.Ioc_inter_Ioi

@[simp]
theorem Ico_inter_Iio : Ico a b ∩ Iio c = Ico a (min b c) :=
  ext <| by simp (config := { contextual := true }) [iff_def]
#align set.Ico_inter_Iio Set.Ico_inter_Iio

@[simp]
theorem Ioc_diff_Iic : Ioc a b \ Iic c = Ioc (max a c) b := by
  rw [diff_eq, compl_Iic, Ioc_inter_Ioi, sup_eq_max]
#align set.Ioc_diff_Iic Set.Ioc_diff_Iic

@[simp]
theorem Ioc_union_Ioc_right : Ioc a b ∪ Ioc a c = Ioc a (max b c) := by
  rw [Ioc_union_Ioc, min_self] <;> exact (min_le_left _ _).trans (le_max_left _ _)
#align set.Ioc_union_Ioc_right Set.Ioc_union_Ioc_right

@[simp]
theorem Ioc_union_Ioc_left : Ioc a c ∪ Ioc b c = Ioc (min a b) c := by
  rw [Ioc_union_Ioc, max_self] <;> exact (min_le_right _ _).trans (le_max_right _ _)
#align set.Ioc_union_Ioc_left Set.Ioc_union_Ioc_left

@[simp]
theorem Ioc_union_Ioc_symm : Ioc a b ∪ Ioc b a = Ioc (min a b) (max a b) := by
  rw [max_comm]
  apply Ioc_union_Ioc <;> rw [max_comm] <;> exact min_le_max
#align set.Ioc_union_Ioc_symm Set.Ioc_union_Ioc_symm

@[simp]
theorem Ioc_union_Ioc_union_Ioc_cycle :
    Ioc a b ∪ Ioc b c ∪ Ioc c a = Ioc (min a (min b c)) (max a (max b c)) := by
  rw [Ioc_union_Ioc, Ioc_union_Ioc] <;>
  -- Porting note: mathlib3 proof finished from here as folllows:
  -- (It can probably be restored after https://github.com/leanprover-community/mathlib4/pull/856)
  -- ac_rfl
  -- all_goals
  --   solve_by_elim (config := { max_depth := 5 }) [min_le_of_left_le, min_le_of_right_le,
  --     le_max_of_le_left, le_max_of_le_right, le_refl]
  simp [min_le_of_left_le, min_le_of_right_le, le_max_of_le_left, le_max_of_le_right, le_refl,
    min_assoc, max_comm]

#align set.Ioc_union_Ioc_union_Ioc_cycle Set.Ioc_union_Ioc_union_Ioc_cycle

end LinearOrder

/-!
### Closed intervals in `α × β`
-/

section Prod

variable [Preorder α] [Preorder β]

@[simp]
theorem Iic_prod_Iic (a : α) (b : β) : Iic a ×ˢ Iic b = Iic (a, b) :=
  rfl
#align set.Iic_prod_Iic Set.Iic_prod_Iic

@[simp]
theorem Ici_prod_Ici (a : α) (b : β) : Ici a ×ˢ Ici b = Ici (a, b) :=
  rfl
#align set.Ici_prod_Ici Set.Ici_prod_Ici

theorem Ici_prod_eq (a : α × β) : Ici a = Ici a.1 ×ˢ Ici a.2 :=
  rfl
#align set.Ici_prod_eq Set.Ici_prod_eq

theorem Iic_prod_eq (a : α × β) : Iic a = Iic a.1 ×ˢ Iic a.2 :=
  rfl
#align set.Iic_prod_eq Set.Iic_prod_eq

@[simp]
theorem Icc_prod_Icc (a₁ a₂ : α) (b₁ b₂ : β) : Icc a₁ a₂ ×ˢ Icc b₁ b₂ = Icc (a₁, b₁) (a₂, b₂) := by
  ext ⟨x, y⟩
  simp [and_assoc, and_comm, and_left_comm]
#align set.Icc_prod_Icc Set.Icc_prod_Icc

theorem Icc_prod_eq (a b : α × β) : Icc a b = Icc a.1 b.1 ×ˢ Icc a.2 b.2 := by simp
#align set.Icc_prod_eq Set.Icc_prod_eq

end Prod

end Set

/-! ### Lemmas about intervals in dense orders -/

section Dense

variable (α) [Preorder α] [DenselyOrdered α] {x y : α}

instance : NoMinOrder (Set.Ioo x y) :=
  ⟨fun ⟨a, ha₁, ha₂⟩ => by
    rcases exists_between ha₁ with ⟨b, hb₁, hb₂⟩
    exact ⟨⟨b, hb₁, hb₂.trans ha₂⟩, hb₂⟩⟩

instance : NoMinOrder (Set.Ioc x y) :=
  ⟨fun ⟨a, ha₁, ha₂⟩ => by
    rcases exists_between ha₁ with ⟨b, hb₁, hb₂⟩
    exact ⟨⟨b, hb₁, hb₂.le.trans ha₂⟩, hb₂⟩⟩

instance : NoMinOrder (Set.Ioi x) :=
  ⟨fun ⟨a, ha⟩ => by
    rcases exists_between ha with ⟨b, hb₁, hb₂⟩
    exact ⟨⟨b, hb₁⟩, hb₂⟩⟩

instance : NoMaxOrder (Set.Ioo x y) :=
  ⟨fun ⟨a, ha₁, ha₂⟩ => by
    rcases exists_between ha₂ with ⟨b, hb₁, hb₂⟩
    exact ⟨⟨b, ha₁.trans hb₁, hb₂⟩, hb₁⟩⟩

instance : NoMaxOrder (Set.Ico x y) :=
  ⟨fun ⟨a, ha₁, ha₂⟩ => by
    rcases exists_between ha₂ with ⟨b, hb₁, hb₂⟩
    exact ⟨⟨b, ha₁.trans hb₁.le, hb₂⟩, hb₁⟩⟩

instance : NoMaxOrder (Set.Iio x) :=
  ⟨fun ⟨a, ha⟩ => by
    rcases exists_between ha with ⟨b, hb₁, hb₂⟩
    exact ⟨⟨b, hb₂⟩, hb₁⟩⟩

end Dense