import Lean
import SciLean.Core

namespace SciLean

-- abbrev ℝ := Float
-- instance : DecidableEq ℝ := λ x y => if x==y then .isTrue sorry else .isFalse sorry

-- structure PhysicalScale where
-- Change to rational numbers
-- Maybe change scale to positive rationals
structure PhysicalUnit where
  -- meter
  mLog10Scale  : Int := 0
  mPower      : Int   := 0
  -- second
  sLog10Scale  : Int := 0
  sPower      : Int   := 0
  -- kilogram
  kgLog10Scale : Int := 0
  kgPower     : Int   := 0
deriving DecidableEq

def PhysicalUnit.scale (unit : PhysicalUnit) : Float :=
    2^(Float.ofInt (unit.mLog10Scale + unit.sLog10Scale + unit.kgLog10Scale))

instance : Mul PhysicalUnit := ⟨λ x y =>
  { mLog10Scale  := x.mLog10Scale + y.mLog10Scale,
    mPower      := x.mPower + y.mPower,
    sLog10Scale  := x.sLog10Scale + y.sLog10Scale,
    sPower      := x.sPower + y.sPower,
    kgLog10Scale := x.kgLog10Scale + y.kgLog10Scale,
    kgPower     := x.kgPower + y.kgPower }⟩

instance : Div PhysicalUnit := ⟨λ x y =>
  { mLog10Scale  := x.mLog10Scale - y.mLog10Scale,
    mPower      := x.mPower - y.mPower,
    sLog10Scale  := x.sLog10Scale - y.sLog10Scale,
    sPower      := x.sPower - y.sPower,
    kgLog10Scale := x.kgLog10Scale - y.kgLog10Scale,
    kgPower     := x.kgPower - y.kgPower }⟩

instance : HPow PhysicalUnit Int PhysicalUnit := ⟨λ x y =>
  { mLog10Scale  := x.mLog10Scale * y,
    mPower      := x.mPower * y,
    sLog10Scale  := x.sLog10Scale * y,
    sPower      := x.sPower * y,
    kgLog10Scale := x.kgLog10Scale * y,
    kgPower     := x.kgPower * y }⟩

instance : OfNat PhysicalUnit 1 := ⟨{}⟩

-- Maybe unit can be anything that is multiplicatie abelian group
structure PhysicalQuantity (α : Type u) (unit : PhysicalUnit) where
  val : α

instance {α units} [Add α] : Add (PhysicalQuantity α units) := ⟨λ x y => ⟨x.val + y.val⟩⟩
instance {α units} [OfNat α n] : OfNat (PhysicalQuantity α units) n := ⟨⟨OfNat.ofNat n⟩⟩

instance {α β γ units units'} [HMul α β γ]
  : HMul (PhysicalQuantity α units) (PhysicalQuantity β units') (PhysicalQuantity γ (units*units')) :=
  ⟨λ x y => ⟨x.val * y.val⟩⟩
instance {α β γ units} [HMul α β γ]
  : HMul (PhysicalQuantity α units) β (PhysicalQuantity γ (units)) :=
  ⟨λ x y => ⟨x.val * y⟩⟩
instance {α β γ units'} [HMul α β γ]
  : HMul α (PhysicalQuantity β units') (PhysicalQuantity γ (units')) :=
  ⟨λ x y => ⟨x * y.val⟩⟩

instance {α β γ units units'} [HDiv α β γ]
  : HDiv (PhysicalQuantity α units) (PhysicalQuantity β units') (PhysicalQuantity γ (units/units')) :=
  ⟨λ x y => ⟨x.val / y.val⟩⟩
instance {α β γ units} [HDiv α β γ]
  : HDiv (PhysicalQuantity α units) β (PhysicalQuantity γ (units)) :=
  ⟨λ x y => ⟨x.val / y⟩⟩
instance {α β γ units'} [HDiv α β γ]
  : HDiv α (PhysicalQuantity β units') (PhysicalQuantity γ (1/units')) :=
  ⟨λ x y => ⟨x / y.val⟩⟩

declare_syntax_cat siunit (behavior := both)

syntax "unit" term  : siunit

def meter : PhysicalUnit := { mPower := 1}
macro "m"  : siunit => `(siunit| unit meter)

def kilometer : PhysicalUnit := { mPower := 1, mLog10Scale := 3 }
macro "km" : siunit => `(siunit| unit kilometer)

def centimeter : PhysicalUnit := { mPower := 1, mLog10Scale := -2 }
macro "cm" : siunit => `(siunit| unit centimeter)

def millimeter : PhysicalUnit := { mPower := 1, mLog10Scale := -3 }
macro "mm" : siunit => `(siunit| unit millimeter)

def mile : PhysicalUnit := { mPower := 1, mLog10Scale := Float.log10 1609.34 |>.toUInt64.toNat}
macro "mi" : siunit => `(siunit| unit mile)

def yard : PhysicalUnit := { mPower := 1, mLog10Scale := Float.log10 0.9144 |>.toUInt64.toNat}
macro "yd" : siunit => `(siunit| unit yard)

def feet : PhysicalUnit := { mPower := 1, mLog10Scale := Float.log10 0.3048 |>.toUInt64.toNat}
macro "ft" : siunit => `(siunit| unit feet)

def inch : PhysicalUnit := { mPower := 1, mLog10Scale := Float.log10 0.0254 |>.toUInt64.toNat}
macro "in" : siunit => `(siunit| unit inch)

def hectare : PhysicalUnit := { mPower := 2, mLog10Scale := 4 }
macro "ha" : siunit => `(siunit| unit hectare)

def acre : PhysicalUnit := { mPower := 2, mLog10Scale := Float.log10 4046.86 |>.toUInt64.toNat}
macro "ac" : siunit => `(siunit| unit acre)

def second : PhysicalUnit := { sPower := 1 }
macro "s" : siunit => `(siunit| unit second)

def minute : PhysicalUnit := { sPower := 1, sLog10Scale := Float.log10 60 |>.toUInt64.toNat}
macro "min" : siunit => `(siunit| unit minute)

def hour : PhysicalUnit := { sPower := 1, sLog10Scale := Float.log10 360 |>.toUInt64.toNat}
macro "h" : siunit => `(siunit| unit hour)

def day : PhysicalUnit := { sPower := 1, sLog10Scale := Float.log10 8640 |>.toUInt64.toNat}
macro "day" : siunit => `(siunit| unit day)

def kilogram : PhysicalUnit := { kgPower := 1 }
macro "kg" : siunit => `(siunit| unit kilogram)

def gram : PhysicalUnit := { kgPower := 1, kgLog10Scale := -3}
macro "g" : siunit => `(siunit| unit gram)

def milligram : PhysicalUnit := { kgPower := 1, kgLog10Scale := -6}
macro "mg" : siunit => `(siunit| unit milligram)

def stone : PhysicalUnit := { kgPower := 1, kgLog10Scale := Float.log10 6.350288000002350941 |>.toUInt64.toNat}
macro "st" : siunit => `(siunit| unit stone)

def pound : PhysicalUnit := { kgPower := 1, kgLog10Scale := Float.log10 0.4535920000001679 |>.toUInt64.toNat}
macro "Lb" : siunit => `(siunit| unit pound)

def ounce : PhysicalUnit := { kgPower := 1, kgLog10Scale := Float.log10 0.028349500000010494777 |>.toUInt64.toNat}
macro "oz" : siunit => `(siunit| unit ounce)

def hertz : PhysicalUnit := { sPower := -1 }
macro "Hz" : siunit => `(siunit| unit hertz)

def newton : PhysicalUnit := { mPower := 1, sPower := -2, kgPower := 1 }
macro "N" : siunit => `(siunit| unit newton)

def pascal : PhysicalUnit := { mPower := -1, sPower := -2, kgPower := 1 }
macro "Pa" : siunit => `(siunit| unit pascal)

def watt : PhysicalUnit := { mPower := 2, sPower := -3, kgPower := 1 }
macro "W" : siunit => `(siunit| unit watt)

def joule : PhysicalUnit := { mPower := 2, sPower := -2, kgPower := 1 }
macro "J" : siunit => `(siunit| unit joule)

syntax siunit:71 "*" siunit:70 : siunit
syntax siunit:71 "/" siunit:70 : siunit
syntax siunit noWs "²" : siunit
syntax siunit noWs "³" : siunit
syntax siunit noWs "⁻¹" : siunit
syntax siunit noWs "⁻²" : siunit
syntax siunit noWs "⁻³" : siunit

syntax "ℝ[" siunit "]" : term

macro_rules
| `(siunit| $unit * $unit') => do
  match (← Lean.expandMacros unit) with
  | `(siunit| unit $u) =>
    match (← Lean.expandMacros unit') with
    | `(siunit| unit $u') =>
      `(siunit| unit ($u * $u'))
    | _ => Lean.Macro.throwUnsupported
  | _ => Lean.Macro.throwUnsupported
| `(siunit| $unit / $unit') => do
  match (← Lean.expandMacros unit) with
  | `(siunit| unit $u) =>
    match (← Lean.expandMacros unit') with
    | `(siunit| unit $u') =>
      `(siunit| unit ($u / $u'))
    | _ => Lean.Macro.throwUnsupported
  | _ => Lean.Macro.throwUnsupported
| `(siunit| $unit²) => do
  match (← Lean.expandMacros unit) with
  | `(siunit| unit $u) => `(siunit| unit $u^(2:Int))
  | _ => Lean.Macro.throwUnsupported
| `(siunit| $unit³) => do
  match (← Lean.expandMacros unit) with
  | `(siunit| unit $u) => `(siunit| unit $u^(3:Int))
  | _ => Lean.Macro.throwUnsupported
| `(siunit| $unit⁻¹) => do
  match (← Lean.expandMacros unit) with
  | `(siunit| unit $u) => `(siunit| unit $u^(-1:Int))
  | _ => Lean.Macro.throwUnsupported
| `(siunit| $unit⁻²) => do
  match (← Lean.expandMacros unit) with
  | `(siunit| unit $u) => `(siunit| unit $u^(-2:Int))
  | _ => Lean.Macro.throwUnsupported
| `(siunit| $unit⁻³) => do
  match (← Lean.expandMacros unit) with
  | `(siunit| unit $u) => `(siunit| unit $u^(-3:Int))
  | _ => Lean.Macro.throwUnsupported
| `(ℝ[ $units ]) => do
  match (← Lean.expandMacros units) with
  | `(siunit| unit $u) => `(PhysicalQuantity ℝ $u)
  | _ => Lean.Macro.throwUnsupported

open Lean Lean.Meta Lean.Elab Lean.Elab.Term in
elab_rules : term
| `(PhysicalQuantity $α $unit) => do
  let α ← elabTerm α none
  let unit ← reduce (← elabTerm unit (mkConst ``PhysicalUnit))
  mkAppM ``PhysicalQuantity #[α, unit]

example : ℝ[mm*km] = ℝ[m²] := by rfl
example : ℝ[m*s⁻¹] = ℝ[s⁻¹*m] := by rfl
example : ℝ[kg*mg] = ℝ[g²] := by rfl

example : ℝ[N]  = ℝ[kg*m*s⁻²] := by rfl
example : ℝ[J]  = ℝ[N*m]   := by rfl
example : ℝ[W]  = ℝ[J*s⁻¹] := by rfl
example : ℝ[Pa] = ℝ[N*m⁻²] := by rfl

example : ℝ[N*m²*kg⁻²] = ℝ[m³*kg⁻¹*s⁻²] := by rfl
example : ℝ[J*Hz⁻¹] = ℝ[J*s] := by rfl

namespace PhysicalConstants
  --- Source: https://en.wikipedia.org/wiki/Physical_constant#Table_of_physical_constants

  def gravitationalConstant : ℝ[N*m²*kg⁻²] := ⟨6.674 * 10.0^(-11.0)⟩
  abbrev G := gravitationalConstant

  def speedOfLight : ℝ[m*s⁻¹] := ⟨299792458.0⟩
  abbrev c := speedOfLight

  def planckConstant : ℝ[J*Hz⁻¹] := ⟨6.62607015 * 10.0^(-34.0)⟩
  abbrev h := planckConstant
  abbrev ℎ := planckConstant

  def reducedPlanckConstant : ℝ[J*s] := h / Math.pi
  abbrev ℏ := reducedPlanckConstant

  def electronMass : ℝ[kg] := ⟨9.1093837015 * 10.0^(-31.0)⟩
  abbrev mₑ : ℝ[kg] := electronMass

end PhysicalConstants


/-
Copyright (c) 2017 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Bhavik Mehta
-/
import data.int.cast.lemmas
import algebra.field.defs
import algebra.group_with_zero.units.lemmas

/-!
# Cast of integers into fields

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

This file concerns the canonical homomorphism `ℤ → F`, where `F` is a field.

## Main results

 * `int.cast_div`: if `n` divides `m`, then `↑(m / n) = ↑m / ↑n`
-/

namespace int

open nat
variables {α : Type*}

/--
Auxiliary lemma for norm_cast to move the cast `-↑n` upwards to `↑-↑n`.

(The restriction to `division_ring` is necessary, otherwise this would also apply in the case where
`R = ℤ` and cause nontermination.)
-/
@[norm_cast]
lemma cast_neg_nat_cast {R} [division_ring R] (n : ℕ) : ((-n : ℤ) : R) = -n := by simp

@[simp] theorem cast_div [division_ring α] {m n : ℤ} (n_dvd : n ∣ m) (n_nonzero : (n : α) ≠ 0) :
  ((m / n : ℤ) : α) = m / n :=
begin
  rcases n_dvd with ⟨k, rfl⟩,
  have : n ≠ 0, { rintro rfl, simpa using n_nonzero },
  rw [int.mul_div_cancel_left _ this, mul_comm n k, int.cast_mul, mul_div_cancel _ n_nonzero],
end

end int


import ..myset.basic
import .prime
import ..myint.dvd
import ..logic

/- Noncomputable HCF

In this file we make no attempt to remain computable or
minimise the axioms used.

We construct the HCF of a and b as the smallest positive
integer h for which there exist integers x and y such
that a * x + b * y = h, and then go on to prove some
properties of this.
-/

namespace hidden

open myint

namespace mynat

/-- Non-zero linear combinations of naturals -/
def lin_combs (a b : mynat) : myset mynat :=
λ c, c ≠ 0 ∧ ∃ x y : myint, ↑a * x + ↑b * y = ↑c

theorem lin_combs_comm (a b : mynat) : lin_combs a b = lin_combs b a :=
begin
  apply funext,
  intro c,
  apply propext,
  split,
  all_goals {
    assume h,
    unfold lin_combs at *,
    split,
      from h.left,
    cases h.right with x hx,
    cases hx with y hxy,
    existsi y,
    existsi x,
    rwa myint.add_comm,
  },
end

theorem lin_combs_nemp {a b : mynat} : a ≠ 0 ∨ b ≠ 0 → ¬myset.empty (lin_combs a b) :=
begin
  assume hab,
  rw ←myset.exists_iff_nempty,
  cases hab with ha hb, {
    existsi a,
    split,
      assumption,
    existsi (1 : myint),
    existsi (0 : myint),
    rw [myint.mul_one, myint.mul_zero, myint.add_zero],
  }, {
    existsi b,
    split,
      assumption,
    existsi (0 : myint),
    existsi (1 : myint),
    rw [myint.mul_one, myint.mul_zero, myint.zero_add],
  },
end

-- 0 if both 0, sadly this makes it an if :(
-- Inherits noncomputablility from `min`
/-- Given two integers, (noncomputably) get their hcf, and if both are
zero, return zero. -/
noncomputable def hcf (a b : mynat) : mynat :=
if h : a ≠ 0 ∨ b ≠ 0 then
  min (lin_combs a b) (lin_combs_nemp h)
else 0

variables m n k : mynat

theorem hcf_comm : hcf m n = hcf n m :=
begin
  by_cases m ≠ 0 ∨ n ≠ 0,
    unfold hcf,
    rw [dif_pos h, dif_pos (or.symm h)],
    apply min_rw,
    from lin_combs_comm m n,
  unfold hcf,
  have : ¬(n ≠ 0 ∨ m ≠ 0),
    assume hnm,
    from h (or.symm hnm),
  rw [dif_neg h, dif_neg this],
end

private lemma common_factor_dvd_lin_comb (k m n a : mynat):
k ∣ m → k ∣ n → a ∈ lin_combs m n → k ∣ a :=
begin
  assume hkm hkn h,
  cases h with ha h,
  cases h with x hx,
  cases hx with y hxy,
  have : ↑k ∣ ↑m * x + ↑n * y,
    apply myint.dvd_sum,
      apply myint.dvd_mul,
      apply myint.coe_coe_dvd.mp,
      assumption,
    apply myint.dvd_mul,
    apply myint.coe_coe_dvd.mp,
    assumption,
  apply myint.coe_coe_dvd.mpr,
  rwa ←hxy,
end

theorem hcf_is_lin_comb {m n : mynat} (h : m ≠ 0 ∨ n ≠ 0):
hcf m n ∈ lin_combs m n :=
begin
  unfold hcf,
  rw dif_pos h,
  from min_property _,
end

theorem hcf_min_if_one_nzero {m n : mynat} (h : m ≠ 0 ∨ n ≠ 0) :
hcf m n = min (lin_combs m n) (lin_combs_nemp h) :=
begin
  unfold hcf,
  rw dif_pos h,
end

theorem common_factor_dvd_hcf {k m n : mynat} :
k ∣ m → k ∣ n → k ∣ hcf m n :=
begin
  by_cases m ≠ 0 ∨ n ≠ 0; assume hkm hkn,
    apply common_factor_dvd_lin_comb k m n (hcf m n),
    any_goals { assumption, },
    from hcf_is_lin_comb h,
  have : hcf m n = 0,
    unfold hcf,
    rw dif_neg h,
  rw this,
  from dvd_zero,
end

theorem hcf_zero_iff_both_zero : hcf m n = 0 ↔ ¬(m ≠ 0 ∨ n ≠ 0) :=
begin
  split; assume h, {
    assume hmn0,
    unfold hcf at h,
    rw dif_pos hmn0 at h,
    have := min_property (lin_combs_nemp hmn0),
    rw myset.mem_def at this,
    cases this with h0 hright,
    contradiction,
  }, {
    unfold hcf,
    rw dif_neg h,
  },
end

-- NOTE: This example breaks if you open classical. Why?
-- (see below)
example {m n : mynat} (h : m ≠ 0 ∨ n ≠ 0) :
hcf m n = min (lin_combs m n) (lin_combs_nemp h) :=
begin
  unfold hcf,
  rw dif_pos h,
end

-- Let's open classical and make all propositions decidable

open classical

-- Proving dvd decidable almost certainly requires well-founded recursion
local attribute [instance] prop_decidable

-- Brok
example {m n : mynat} (h : m ≠ 0 ∨ n ≠ 0) :
hcf m n = min (lin_combs m n) (lin_combs_nemp h) :=
begin
  unfold hcf,
  -- rw dif_pos h,
  sorry,
end

-- A ridiculous proof, at this point might as well just be constructive
-- We need dvd decidable
-- TODO: Move somewhere, I guess
/-- Off-brand division algorithm -/
theorem exists_remainder {k n : mynat} :
k ≠ 0 → ¬k ∣ n → ∃ m r, 0 ≠ r ∧ r < k ∧ k ∣ m ∧ n = m + r :=
begin
  assume hk,
  induction n with n hn,
    assume h,
    have : k ∣ zero,
      rw zz,
      from dvd_zero,
    contradiction,
  assume hsucc,
  by_cases hkn: k ∣ n, {
    existsi n,
    existsi (1 : mynat),
    split,
      apply mynat.no_confusion,
    split,
      assume hk1,
      cases le_one hk1,
        contradiction,
      have : k ∣ (succ n),
        rw h,
        from one_dvd,
      contradiction,
    split,
      assumption,
    refl,
  }, {
    cases hn hkn with m hm,
    cases hm with r hmr,
    cases hmr with h0r hmr,
    cases hmr with hrk hmr,
    cases hmr with hkm hnmr,
    existsi m,
    existsi (succ r),
    split,
      apply mynat.no_confusion,
    split,
      rw [lt_iff_succ_le, le_iff_lt_or_eq] at hrk,
      cases hrk,
        assumption,
      have := congr_arg succ hnmr,
      cases hkm with a ha,
      rw [←add_succ, hrk, ha] at this,
      conv at this {
        to_rhs, congr, skip,
        rw ←mynat.one_mul k, skip,
      },
      rw ←add_mul at this,
      have hcontra : k ∣ (succ n),
        existsi (a + 1),
        assumption,
      contradiction,
    split,
      assumption,
    rwa [add_succ, hnmr],
  },
end

theorem hcf_dvd_left (h : m ≠ 0 ∨ n ≠ 0): hcf m n ∣ m :=
begin
  by_contradiction hdvd,
  have hprop := min_property (lin_combs_nemp h),
  rw ←hcf_min_if_one_nzero h at hprop,
  cases hprop with h0 hprop,
  cases hprop with x hx,
  cases hx with y hxy,

  -- Again, unfold enormous string of ∧.
  -- Mathlib has `rcases` tactic which makes this pleasant.
  cases exists_remainder h0 hdvd with a ha,
  cases ha with r har,
  cases har with h0r har,
  cases har with hrhcf har,
  cases har with hhcfdvd hmxr,
  cases hhcfdvd with q hq,

  have hmul := congr_arg (λ x, ↑q * x) hxy,
  dsimp only [] at hmul,
  rw [coe_coe_mul, ←hq] at hmul,

  have hcoe := congr_arg (λ x, (↑x : myint)) hmxr,
  dsimp only [] at hcoe,
  rw [←coe_coe_add, ←myint.add_cancel (-↑r), myint.add_assoc,
      self_neg_add, myint.add_zero] at hcoe,

  rw [←hcoe, ←myint.add_cancel (↑r), myint.add_assoc, neg_self_add,
      myint.add_zero, myint.add_comm,
      ←myint.add_cancel (-(↑q * (↑m * x + ↑n * y))), myint.add_assoc,
      self_neg_add, myint.add_zero, ←mul_neg_with, myint.mul_add,
      ←myint.mul_one (↑m)] at hmul,

  have : ↑m * 1 + (-↑q * (↑m * 1 * x) + -↑q * (↑n * y)) =
         ↑m * 1 + ↑m * (1 * -↑q * x) + ↑n * (-↑q * y),
    ac_refl,
  rw [this, ←myint.mul_add] at hmul, clear this,

  suffices : r ∈ lin_combs m n,
    have hle := min_le (lin_combs_nemp h) this,
    rw ←hcf_min_if_one_nzero h at hle,
    contradiction,

  split,
    from h0r.symm,
  existsi (1 + 1 * -↑q * x),
  existsi (-↑q * y),
  symmetry,
  assumption,
end

theorem hcf_dvd_right (h : m ≠ 0 ∨ n ≠ 0): hcf m n ∣ n :=
by rw hcf_comm; from hcf_dvd_left n m (or.symm h)

theorem bezouts_lemma {m n k : mynat} (h : m ≠ 0 ∨ n ≠ 0) :
(∃ x y : myint, ↑m * x + ↑n * y = k) ↔ hcf m n ∣ k :=
begin
  split; assume h₁, {
    cases h₁ with x hx,
    cases hx with y hxy,
    cases hcf_dvd_left _ _ h with a ha,
    cases hcf_dvd_right _ _ h with b hb,
    apply myint.coe_coe_dvd.mpr,
    existsi (↑a * x + ↑b * y),
    rw [myint.mul_comm, myint.mul_add, ←myint.mul_assoc, ←myint.mul_assoc,
        coe_coe_mul, coe_coe_mul, mul_comm, mul_comm _ b, ←ha, ←hb],
    symmetry, assumption,
  }, {
    have hprop := min_property (lin_combs_nemp h),
    rw ←hcf_min_if_one_nzero h at hprop,
    cases hprop with h0 hprop,
    cases hprop with x hx,
    cases hx with y hxy,

    cases h₁ with a ha,

    have := congr_arg (λ x, ↑a * x) hxy,
    dsimp only [] at this,
    rw [myint.mul_add, coe_coe_mul, ←ha] at this,
    existsi (↑a * x),
    existsi (↑a * y),
    rw ←this,
    ac_refl,
  },
end

end mynat

end hidden


/-
Copyright (c) 2014 Robert Lewis. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Robert Lewis, Leonardo de Moura, Mario Carneiro, Floris van Doorn

! This file was ported from Lean 3 source module algebra.order.field.canonical.basic
! leanprover-community/mathlib commit ee0c179cd3c8a45aa5bffbf1b41d8dbede452865
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Algebra.Order.Field.Canonical.Defs

/-!
# Lemmas about canonically ordered semifields.

-/

variable {α : Type _}

section CanonicallyLinearOrderedSemifield

variable [CanonicallyLinearOrderedSemifield α] [Sub α] [OrderedSub α]

theorem tsub_div (a b c : α) : (a - b) / c = a / c - b / c := by simp_rw [div_eq_mul_inv, tsub_mul]
#align tsub_div tsub_div

end CanonicallyLinearOrderedSemifield


/-
Copyright (c) 2019 Floris van Doorn. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Floris van Doorn, Yury Kudryashov

! This file was ported from Lean 3 source module data.set.intervals.disjoint
! leanprover-community/mathlib commit c3291da49cfa65f0d43b094750541c0731edc932
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Set.Lattice

/-!
# Extra lemmas about intervals

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

This file contains lemmas about intervals that cannot be included into `data.set.intervals.basic`
because this would create an `import` cycle. Namely, lemmas in this file can use definitions
from `data.set.lattice`, including `disjoint`.
-/

universe u v w

variable {ι : Sort u} {α : Type v} {β : Type w}

open Set

open OrderDual (toDual)

namespace Set

section Preorder

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

/- warning: set.Iic_disjoint_Ioi -> Set.Iic_disjoint_Ioi is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α}, (LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1) a b) -> (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.completeBooleanAlgebra.{u1} α)))))) (GeneralizedBooleanAlgebra.toOrderBot.{u1} (Set.{u1} α) (BooleanAlgebra.toGeneralizedBooleanAlgebra.{u1} (Set.{u1} α) (Set.booleanAlgebra.{u1} α))) (Set.Iic.{u1} α _inst_1 a) (Set.Ioi.{u1} α _inst_1 b))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α}, (LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1) a b) -> (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (BoundedOrder.toOrderBot.{u1} (Set.{u1} α) (Preorder.toLE.{u1} (Set.{u1} α) (PartialOrder.toPreorder.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))))) (CompleteLattice.toBoundedOrder.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (Set.Iic.{u1} α _inst_1 a) (Set.Ioi.{u1} α _inst_1 b))
Case conversion may be inaccurate. Consider using '#align set.Iic_disjoint_Ioi Set.Iic_disjoint_Ioiₓ'. -/
@[simp]
theorem Iic_disjoint_Ioi (h : a ≤ b) : Disjoint (Iic a) (Ioi b) :=
  disjoint_left.mpr fun x ha hb => (h.trans_lt hb).not_le ha
#align set.Iic_disjoint_Ioi Set.Iic_disjoint_Ioi

/- warning: set.Iic_disjoint_Ioc -> Set.Iic_disjoint_Ioc is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α} {c : α}, (LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1) a b) -> (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.completeBooleanAlgebra.{u1} α)))))) (GeneralizedBooleanAlgebra.toOrderBot.{u1} (Set.{u1} α) (BooleanAlgebra.toGeneralizedBooleanAlgebra.{u1} (Set.{u1} α) (Set.booleanAlgebra.{u1} α))) (Set.Iic.{u1} α _inst_1 a) (Set.Ioc.{u1} α _inst_1 b c))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α} {c : α}, (LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1) a b) -> (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (BoundedOrder.toOrderBot.{u1} (Set.{u1} α) (Preorder.toLE.{u1} (Set.{u1} α) (PartialOrder.toPreorder.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))))) (CompleteLattice.toBoundedOrder.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (Set.Iic.{u1} α _inst_1 a) (Set.Ioc.{u1} α _inst_1 b c))
Case conversion may be inaccurate. Consider using '#align set.Iic_disjoint_Ioc Set.Iic_disjoint_Iocₓ'. -/
@[simp]
theorem Iic_disjoint_Ioc (h : a ≤ b) : Disjoint (Iic a) (Ioc b c) :=
  (Iic_disjoint_Ioi h).mono le_rfl fun _ => And.left
#align set.Iic_disjoint_Ioc Set.Iic_disjoint_Ioc

/- warning: set.Ioc_disjoint_Ioc_same -> Set.Ioc_disjoint_Ioc_same is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α} {c : α}, Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.completeBooleanAlgebra.{u1} α)))))) (GeneralizedBooleanAlgebra.toOrderBot.{u1} (Set.{u1} α) (BooleanAlgebra.toGeneralizedBooleanAlgebra.{u1} (Set.{u1} α) (Set.booleanAlgebra.{u1} α))) (Set.Ioc.{u1} α _inst_1 a b) (Set.Ioc.{u1} α _inst_1 b c)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α} {c : α}, Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (BoundedOrder.toOrderBot.{u1} (Set.{u1} α) (Preorder.toLE.{u1} (Set.{u1} α) (PartialOrder.toPreorder.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))))) (CompleteLattice.toBoundedOrder.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (Set.Ioc.{u1} α _inst_1 a b) (Set.Ioc.{u1} α _inst_1 b c)
Case conversion may be inaccurate. Consider using '#align set.Ioc_disjoint_Ioc_same Set.Ioc_disjoint_Ioc_sameₓ'. -/
@[simp]
theorem Ioc_disjoint_Ioc_same {a b c : α} : Disjoint (Ioc a b) (Ioc b c) :=
  (Iic_disjoint_Ioc (le_refl b)).mono (fun _ => And.right) le_rfl
#align set.Ioc_disjoint_Ioc_same Set.Ioc_disjoint_Ioc_same

/- warning: set.Ico_disjoint_Ico_same -> Set.Ico_disjoint_Ico_same is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α} {c : α}, Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.completeBooleanAlgebra.{u1} α)))))) (GeneralizedBooleanAlgebra.toOrderBot.{u1} (Set.{u1} α) (BooleanAlgebra.toGeneralizedBooleanAlgebra.{u1} (Set.{u1} α) (Set.booleanAlgebra.{u1} α))) (Set.Ico.{u1} α _inst_1 a b) (Set.Ico.{u1} α _inst_1 b c)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α} {c : α}, Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (BoundedOrder.toOrderBot.{u1} (Set.{u1} α) (Preorder.toLE.{u1} (Set.{u1} α) (PartialOrder.toPreorder.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))))) (CompleteLattice.toBoundedOrder.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (Set.Ico.{u1} α _inst_1 a b) (Set.Ico.{u1} α _inst_1 b c)
Case conversion may be inaccurate. Consider using '#align set.Ico_disjoint_Ico_same Set.Ico_disjoint_Ico_sameₓ'. -/
@[simp]
theorem Ico_disjoint_Ico_same {a b c : α} : Disjoint (Ico a b) (Ico b c) :=
  disjoint_left.mpr fun x hab hbc => hab.2.not_le hbc.1
#align set.Ico_disjoint_Ico_same Set.Ico_disjoint_Ico_same

/- warning: set.Ici_disjoint_Iic -> Set.Ici_disjoint_Iic is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α}, Iff (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.completeBooleanAlgebra.{u1} α)))))) (GeneralizedBooleanAlgebra.toOrderBot.{u1} (Set.{u1} α) (BooleanAlgebra.toGeneralizedBooleanAlgebra.{u1} (Set.{u1} α) (Set.booleanAlgebra.{u1} α))) (Set.Ici.{u1} α _inst_1 a) (Set.Iic.{u1} α _inst_1 b)) (Not (LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1) a b))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α}, Iff (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (BoundedOrder.toOrderBot.{u1} (Set.{u1} α) (Preorder.toLE.{u1} (Set.{u1} α) (PartialOrder.toPreorder.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))))) (CompleteLattice.toBoundedOrder.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (Set.Ici.{u1} α _inst_1 a) (Set.Iic.{u1} α _inst_1 b)) (Not (LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1) a b))
Case conversion may be inaccurate. Consider using '#align set.Ici_disjoint_Iic Set.Ici_disjoint_Iicₓ'. -/
@[simp]
theorem Ici_disjoint_Iic : Disjoint (Ici a) (Iic b) ↔ ¬a ≤ b := by
  rw [Set.disjoint_iff_inter_eq_empty, Ici_inter_Iic, Icc_eq_empty_iff]
#align set.Ici_disjoint_Iic Set.Ici_disjoint_Iic

/- warning: set.Iic_disjoint_Ici -> Set.Iic_disjoint_Ici is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α}, Iff (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.completeBooleanAlgebra.{u1} α)))))) (GeneralizedBooleanAlgebra.toOrderBot.{u1} (Set.{u1} α) (BooleanAlgebra.toGeneralizedBooleanAlgebra.{u1} (Set.{u1} α) (Set.booleanAlgebra.{u1} α))) (Set.Iic.{u1} α _inst_1 a) (Set.Ici.{u1} α _inst_1 b)) (Not (LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1) b a))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : Preorder.{u1} α] {a : α} {b : α}, Iff (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (BoundedOrder.toOrderBot.{u1} (Set.{u1} α) (Preorder.toLE.{u1} (Set.{u1} α) (PartialOrder.toPreorder.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))))) (CompleteLattice.toBoundedOrder.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (Set.Iic.{u1} α _inst_1 a) (Set.Ici.{u1} α _inst_1 b)) (Not (LE.le.{u1} α (Preorder.toLE.{u1} α _inst_1) b a))
Case conversion may be inaccurate. Consider using '#align set.Iic_disjoint_Ici Set.Iic_disjoint_Iciₓ'. -/
@[simp]
theorem Iic_disjoint_Ici : Disjoint (Iic a) (Ici b) ↔ ¬b ≤ a :=
  disjoint_comm.trans Ici_disjoint_Iic
#align set.Iic_disjoint_Ici Set.Iic_disjoint_Ici

#print Set.unionᵢ_Iic /-
@[simp]
theorem unionᵢ_Iic : (⋃ a : α, Iic a) = univ :=
  unionᵢ_eq_univ_iff.2 fun x => ⟨x, right_mem_Iic⟩
#align set.Union_Iic Set.unionᵢ_Iic
-/

#print Set.unionᵢ_Ici /-
@[simp]
theorem unionᵢ_Ici : (⋃ a : α, Ici a) = univ :=
  unionᵢ_eq_univ_iff.2 fun x => ⟨x, left_mem_Ici⟩
#align set.Union_Ici Set.unionᵢ_Ici
-/

#print Set.unionᵢ_Icc_right /-
@[simp]
theorem unionᵢ_Icc_right (a : α) : (⋃ b, Icc a b) = Ici a := by
  simp only [← Ici_inter_Iic, ← inter_Union, Union_Iic, inter_univ]
#align set.Union_Icc_right Set.unionᵢ_Icc_right
-/

#print Set.unionᵢ_Ioc_right /-
@[simp]
theorem unionᵢ_Ioc_right (a : α) : (⋃ b, Ioc a b) = Ioi a := by
  simp only [← Ioi_inter_Iic, ← inter_Union, Union_Iic, inter_univ]
#align set.Union_Ioc_right Set.unionᵢ_Ioc_right
-/

#print Set.unionᵢ_Icc_left /-
@[simp]
theorem unionᵢ_Icc_left (b : α) : (⋃ a, Icc a b) = Iic b := by
  simp only [← Ici_inter_Iic, ← Union_inter, Union_Ici, univ_inter]
#align set.Union_Icc_left Set.unionᵢ_Icc_left
-/

#print Set.unionᵢ_Ico_left /-
@[simp]
theorem unionᵢ_Ico_left (b : α) : (⋃ a, Ico a b) = Iio b := by
  simp only [← Ici_inter_Iio, ← Union_inter, Union_Ici, univ_inter]
#align set.Union_Ico_left Set.unionᵢ_Ico_left
-/

#print Set.unionᵢ_Iio /-
@[simp]
theorem unionᵢ_Iio [NoMaxOrder α] : (⋃ a : α, Iio a) = univ :=
  unionᵢ_eq_univ_iff.2 exists_gt
#align set.Union_Iio Set.unionᵢ_Iio
-/

#print Set.unionᵢ_Ioi /-
@[simp]
theorem unionᵢ_Ioi [NoMinOrder α] : (⋃ a : α, Ioi a) = univ :=
  unionᵢ_eq_univ_iff.2 exists_lt
#align set.Union_Ioi Set.unionᵢ_Ioi
-/

#print Set.unionᵢ_Ico_right /-
@[simp]
theorem unionᵢ_Ico_right [NoMaxOrder α] (a : α) : (⋃ b, Ico a b) = Ici a := by
  simp only [← Ici_inter_Iio, ← inter_Union, Union_Iio, inter_univ]
#align set.Union_Ico_right Set.unionᵢ_Ico_right
-/

#print Set.unionᵢ_Ioo_right /-
@[simp]
theorem unionᵢ_Ioo_right [NoMaxOrder α] (a : α) : (⋃ b, Ioo a b) = Ioi a := by
  simp only [← Ioi_inter_Iio, ← inter_Union, Union_Iio, inter_univ]
#align set.Union_Ioo_right Set.unionᵢ_Ioo_right
-/

#print Set.unionᵢ_Ioc_left /-
@[simp]
theorem unionᵢ_Ioc_left [NoMinOrder α] (b : α) : (⋃ a, Ioc a b) = Iic b := by
  simp only [← Ioi_inter_Iic, ← Union_inter, Union_Ioi, univ_inter]
#align set.Union_Ioc_left Set.unionᵢ_Ioc_left
-/

#print Set.unionᵢ_Ioo_left /-
@[simp]
theorem unionᵢ_Ioo_left [NoMinOrder α] (b : α) : (⋃ a, Ioo a b) = Iio b := by
  simp only [← Ioi_inter_Iio, ← Union_inter, Union_Ioi, univ_inter]
#align set.Union_Ioo_left Set.unionᵢ_Ioo_left
-/

end Preorder

section LinearOrder

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

/- warning: set.Ico_disjoint_Ico -> Set.Ico_disjoint_Ico is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : LinearOrder.{u1} α] {a₁ : α} {a₂ : α} {b₁ : α} {b₂ : α}, Iff (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.completeBooleanAlgebra.{u1} α)))))) (GeneralizedBooleanAlgebra.toOrderBot.{u1} (Set.{u1} α) (BooleanAlgebra.toGeneralizedBooleanAlgebra.{u1} (Set.{u1} α) (Set.booleanAlgebra.{u1} α))) (Set.Ico.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1)))) a₁ a₂) (Set.Ico.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1)))) b₁ b₂)) (LE.le.{u1} α (Preorder.toLE.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1))))) (LinearOrder.min.{u1} α _inst_1 a₂ b₂) (LinearOrder.max.{u1} α _inst_1 a₁ b₁))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : LinearOrder.{u1} α] {a₁ : α} {a₂ : α} {b₁ : α} {b₂ : α}, Iff (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (BoundedOrder.toOrderBot.{u1} (Set.{u1} α) (Preorder.toLE.{u1} (Set.{u1} α) (PartialOrder.toPreorder.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))))) (CompleteLattice.toBoundedOrder.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (Set.Ico.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1))))) a₁ a₂) (Set.Ico.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1))))) b₁ b₂)) (LE.le.{u1} α (Preorder.toLE.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1)))))) (Min.min.{u1} α (LinearOrder.toMin.{u1} α _inst_1) a₂ b₂) (Max.max.{u1} α (LinearOrder.toMax.{u1} α _inst_1) a₁ b₁))
Case conversion may be inaccurate. Consider using '#align set.Ico_disjoint_Ico Set.Ico_disjoint_Icoₓ'. -/
@[simp]
theorem Ico_disjoint_Ico : Disjoint (Ico a₁ a₂) (Ico b₁ b₂) ↔ min a₂ b₂ ≤ max a₁ b₁ := by
  simp_rw [Set.disjoint_iff_inter_eq_empty, Ico_inter_Ico, Ico_eq_empty_iff, inf_eq_min, sup_eq_max,
    not_lt]
#align set.Ico_disjoint_Ico Set.Ico_disjoint_Ico

/- warning: set.Ioc_disjoint_Ioc -> Set.Ioc_disjoint_Ioc is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : LinearOrder.{u1} α] {a₁ : α} {a₂ : α} {b₁ : α} {b₂ : α}, Iff (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.completeBooleanAlgebra.{u1} α)))))) (GeneralizedBooleanAlgebra.toOrderBot.{u1} (Set.{u1} α) (BooleanAlgebra.toGeneralizedBooleanAlgebra.{u1} (Set.{u1} α) (Set.booleanAlgebra.{u1} α))) (Set.Ioc.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1)))) a₁ a₂) (Set.Ioc.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1)))) b₁ b₂)) (LE.le.{u1} α (Preorder.toLE.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1))))) (LinearOrder.min.{u1} α _inst_1 a₂ b₂) (LinearOrder.max.{u1} α _inst_1 a₁ b₁))
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : LinearOrder.{u1} α] {a₁ : α} {a₂ : α} {b₁ : α} {b₂ : α}, Iff (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (BoundedOrder.toOrderBot.{u1} (Set.{u1} α) (Preorder.toLE.{u1} (Set.{u1} α) (PartialOrder.toPreorder.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))))) (CompleteLattice.toBoundedOrder.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (Set.Ioc.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1))))) a₁ a₂) (Set.Ioc.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1))))) b₁ b₂)) (LE.le.{u1} α (Preorder.toLE.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1)))))) (Min.min.{u1} α (LinearOrder.toMin.{u1} α _inst_1) a₂ b₂) (Max.max.{u1} α (LinearOrder.toMax.{u1} α _inst_1) a₁ b₁))
Case conversion may be inaccurate. Consider using '#align set.Ioc_disjoint_Ioc Set.Ioc_disjoint_Iocₓ'. -/
@[simp]
theorem Ioc_disjoint_Ioc : Disjoint (Ioc a₁ a₂) (Ioc b₁ b₂) ↔ min a₂ b₂ ≤ max a₁ b₁ :=
  by
  have h : _ ↔ min (toDual a₁) (toDual b₁) ≤ max (toDual a₂) (toDual b₂) := Ico_disjoint_Ico
  simpa only [dual_Ico] using h
#align set.Ioc_disjoint_Ioc Set.Ioc_disjoint_Ioc

/- warning: set.eq_of_Ico_disjoint -> Set.eq_of_Ico_disjoint is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} [_inst_1 : LinearOrder.{u1} α] {x₁ : α} {x₂ : α} {y₁ : α} {y₂ : α}, (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.completeBooleanAlgebra.{u1} α)))))) (GeneralizedBooleanAlgebra.toOrderBot.{u1} (Set.{u1} α) (BooleanAlgebra.toGeneralizedBooleanAlgebra.{u1} (Set.{u1} α) (Set.booleanAlgebra.{u1} α))) (Set.Ico.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1)))) x₁ x₂) (Set.Ico.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1)))) y₁ y₂)) -> (LT.lt.{u1} α (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1))))) x₁ x₂) -> (Membership.Mem.{u1, u1} α (Set.{u1} α) (Set.hasMem.{u1} α) x₂ (Set.Ico.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (LinearOrder.toLattice.{u1} α _inst_1)))) y₁ y₂)) -> (Eq.{succ u1} α y₁ x₂)
but is expected to have type
  forall {α : Type.{u1}} [_inst_1 : LinearOrder.{u1} α] {x₁ : α} {x₂ : α} {y₁ : α} {y₂ : α}, (Disjoint.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (BoundedOrder.toOrderBot.{u1} (Set.{u1} α) (Preorder.toLE.{u1} (Set.{u1} α) (PartialOrder.toPreorder.{u1} (Set.{u1} α) (CompleteSemilatticeInf.toPartialOrder.{u1} (Set.{u1} α) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))))) (CompleteLattice.toBoundedOrder.{u1} (Set.{u1} α) (Order.Coframe.toCompleteLattice.{u1} (Set.{u1} α) (CompleteDistribLattice.toCoframe.{u1} (Set.{u1} α) (CompleteBooleanAlgebra.toCompleteDistribLattice.{u1} (Set.{u1} α) (Set.instCompleteBooleanAlgebraSet.{u1} α)))))) (Set.Ico.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1))))) x₁ x₂) (Set.Ico.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1))))) y₁ y₂)) -> (LT.lt.{u1} α (Preorder.toLT.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1)))))) x₁ x₂) -> (Membership.mem.{u1, u1} α (Set.{u1} α) (Set.instMembershipSet.{u1} α) x₂ (Set.Ico.{u1} α (PartialOrder.toPreorder.{u1} α (SemilatticeInf.toPartialOrder.{u1} α (Lattice.toSemilatticeInf.{u1} α (DistribLattice.toLattice.{u1} α (instDistribLattice.{u1} α _inst_1))))) y₁ y₂)) -> (Eq.{succ u1} α y₁ x₂)
Case conversion may be inaccurate. Consider using '#align set.eq_of_Ico_disjoint Set.eq_of_Ico_disjointₓ'. -/
/-- If two half-open intervals are disjoint and the endpoint of one lies in the other,
  then it must be equal to the endpoint of the other. -/
theorem eq_of_Ico_disjoint {x₁ x₂ y₁ y₂ : α} (h : Disjoint (Ico x₁ x₂) (Ico y₁ y₂)) (hx : x₁ < x₂)
    (h2 : x₂ ∈ Ico y₁ y₂) : y₁ = x₂ :=
  by
  rw [Ico_disjoint_Ico, min_eq_left (le_of_lt h2.2), le_max_iff] at h
  apply le_antisymm h2.1
  exact h.elim (fun h => absurd hx (not_lt_of_le h)) id
#align set.eq_of_Ico_disjoint Set.eq_of_Ico_disjoint

#print Set.unionᵢ_Ico_eq_Iio_self_iff /-
@[simp]
theorem unionᵢ_Ico_eq_Iio_self_iff {f : ι → α} {a : α} :
    (⋃ i, Ico (f i) a) = Iio a ↔ ∀ x < a, ∃ i, f i ≤ x := by
  simp [← Ici_inter_Iio, ← Union_inter, subset_def]
#align set.Union_Ico_eq_Iio_self_iff Set.unionᵢ_Ico_eq_Iio_self_iff
-/

#print Set.unionᵢ_Ioc_eq_Ioi_self_iff /-
@[simp]
theorem unionᵢ_Ioc_eq_Ioi_self_iff {f : ι → α} {a : α} :
    (⋃ i, Ioc a (f i)) = Ioi a ↔ ∀ x, a < x → ∃ i, x ≤ f i := by
  simp [← Ioi_inter_Iic, ← inter_Union, subset_def]
#align set.Union_Ioc_eq_Ioi_self_iff Set.unionᵢ_Ioc_eq_Ioi_self_iff
-/

#print Set.bunionᵢ_Ico_eq_Iio_self_iff /-
@[simp]
theorem bunionᵢ_Ico_eq_Iio_self_iff {p : ι → Prop} {f : ∀ i, p i → α} {a : α} :
    (⋃ (i) (hi : p i), Ico (f i hi) a) = Iio a ↔ ∀ x < a, ∃ i hi, f i hi ≤ x := by
  simp [← Ici_inter_Iio, ← Union_inter, subset_def]
#align set.bUnion_Ico_eq_Iio_self_iff Set.bunionᵢ_Ico_eq_Iio_self_iff
-/

#print Set.bunionᵢ_Ioc_eq_Ioi_self_iff /-
@[simp]
theorem bunionᵢ_Ioc_eq_Ioi_self_iff {p : ι → Prop} {f : ∀ i, p i → α} {a : α} :
    (⋃ (i) (hi : p i), Ioc a (f i hi)) = Ioi a ↔ ∀ x, a < x → ∃ i hi, x ≤ f i hi := by
  simp [← Ioi_inter_Iic, ← inter_Union, subset_def]
#align set.bUnion_Ioc_eq_Ioi_self_iff Set.bunionᵢ_Ioc_eq_Ioi_self_iff
-/

end LinearOrder

end Set

section UnionIxx

variable [LinearOrder α] {s : Set α} {a : α} {f : ι → α}

#print IsGLB.bunionᵢ_Ioi_eq /-
theorem IsGLB.bunionᵢ_Ioi_eq (h : IsGLB s a) : (⋃ x ∈ s, Ioi x) = Ioi a :=
  by
  refine' (Union₂_subset fun x hx => _).antisymm fun x hx => _
  · exact Ioi_subset_Ioi (h.1 hx)
  · rcases h.exists_between hx with ⟨y, hys, hay, hyx⟩
    exact mem_bUnion hys hyx
#align is_glb.bUnion_Ioi_eq IsGLB.bunionᵢ_Ioi_eq
-/

#print IsGLB.unionᵢ_Ioi_eq /-
theorem IsGLB.unionᵢ_Ioi_eq (h : IsGLB (range f) a) : (⋃ x, Ioi (f x)) = Ioi a :=
  bunionᵢ_range.symm.trans h.bunionᵢ_Ioi_eq
#align is_glb.Union_Ioi_eq IsGLB.unionᵢ_Ioi_eq
-/

#print IsLUB.bunionᵢ_Iio_eq /-
theorem IsLUB.bunionᵢ_Iio_eq (h : IsLUB s a) : (⋃ x ∈ s, Iio x) = Iio a :=
  h.dual.bunionᵢ_Ioi_eq
#align is_lub.bUnion_Iio_eq IsLUB.bunionᵢ_Iio_eq
-/

#print IsLUB.unionᵢ_Iio_eq /-
theorem IsLUB.unionᵢ_Iio_eq (h : IsLUB (range f) a) : (⋃ x, Iio (f x)) = Iio a :=
  h.dual.unionᵢ_Ioi_eq
#align is_lub.Union_Iio_eq IsLUB.unionᵢ_Iio_eq
-/

#print IsGLB.bunionᵢ_Ici_eq_Ioi /-
theorem IsGLB.bunionᵢ_Ici_eq_Ioi (a_glb : IsGLB s a) (a_not_mem : a ∉ s) :
    (⋃ x ∈ s, Ici x) = Ioi a :=
  by
  refine' (Union₂_subset fun x hx => _).antisymm fun x hx => _
  · exact Ici_subset_Ioi.mpr (lt_of_le_of_ne (a_glb.1 hx) fun h => (h ▸ a_not_mem) hx)
  · rcases a_glb.exists_between hx with ⟨y, hys, hay, hyx⟩
    apply mem_Union₂.mpr
    refine' ⟨y, hys, hyx.le⟩
#align is_glb.bUnion_Ici_eq_Ioi IsGLB.bunionᵢ_Ici_eq_Ioi
-/

#print IsGLB.bunionᵢ_Ici_eq_Ici /-
theorem IsGLB.bunionᵢ_Ici_eq_Ici (a_glb : IsGLB s a) (a_mem : a ∈ s) : (⋃ x ∈ s, Ici x) = Ici a :=
  by
  refine' (Union₂_subset fun x hx => _).antisymm fun x hx => _
  · exact Ici_subset_Ici.mpr (mem_lower_bounds.mp a_glb.1 x hx)
  · apply mem_Union₂.mpr
    refine' ⟨a, a_mem, hx⟩
#align is_glb.bUnion_Ici_eq_Ici IsGLB.bunionᵢ_Ici_eq_Ici
-/

#print IsLUB.bunionᵢ_Iic_eq_Iio /-
theorem IsLUB.bunionᵢ_Iic_eq_Iio (a_lub : IsLUB s a) (a_not_mem : a ∉ s) :
    (⋃ x ∈ s, Iic x) = Iio a :=
  a_lub.dual.bunionᵢ_Ici_eq_Ioi a_not_mem
#align is_lub.bUnion_Iic_eq_Iio IsLUB.bunionᵢ_Iic_eq_Iio
-/

#print IsLUB.bunionᵢ_Iic_eq_Iic /-
theorem IsLUB.bunionᵢ_Iic_eq_Iic (a_lub : IsLUB s a) (a_mem : a ∈ s) : (⋃ x ∈ s, Iic x) = Iic a :=
  a_lub.dual.bunionᵢ_Ici_eq_Ici a_mem
#align is_lub.bUnion_Iic_eq_Iic IsLUB.bunionᵢ_Iic_eq_Iic
-/

/- warning: Union_Ici_eq_Ioi_infi -> unionᵢ_Ici_eq_Ioi_infᵢ is a dubious translation:
lean 3 declaration is
  forall {ι : Sort.{u1}} {R : Type.{u2}} [_inst_2 : CompleteLinearOrder.{u2} R] {f : ι -> R}, (Not (Membership.Mem.{u2, u2} R (Set.{u2} R) (Set.hasMem.{u2} R) (infᵢ.{u2, u1} R (CompleteSemilatticeInf.toHasInf.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2))) ι (fun (i : ι) => f i)) (Set.range.{u2, u1} R ι f))) -> (Eq.{succ u2} (Set.{u2} R) (Set.unionᵢ.{u2, u1} R ι (fun (i : ι) => Set.Ici.{u2} R (PartialOrder.toPreorder.{u2} R (CompleteSemilatticeInf.toPartialOrder.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2)))) (f i))) (Set.Ioi.{u2} R (PartialOrder.toPreorder.{u2} R (CompleteSemilatticeInf.toPartialOrder.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2)))) (infᵢ.{u2, u1} R (CompleteSemilatticeInf.toHasInf.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2))) ι (fun (i : ι) => f i))))
but is expected to have type
  forall {ι : Sort.{u2}} {R : Type.{u1}} [_inst_2 : CompleteLinearOrder.{u1} R] {f : ι -> R}, (Not (Membership.mem.{u1, u1} R (Set.{u1} R) (Set.instMembershipSet.{u1} R) (infᵢ.{u1, u2} R (CompleteLattice.toInfSet.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)) ι (fun (i : ι) => f i)) (Set.range.{u1, u2} R ι f))) -> (Eq.{succ u1} (Set.{u1} R) (Set.unionᵢ.{u1, u2} R ι (fun (i : ι) => Set.Ici.{u1} R (PartialOrder.toPreorder.{u1} R (CompleteSemilatticeInf.toPartialOrder.{u1} R (CompleteLattice.toCompleteSemilatticeInf.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)))) (f i))) (Set.Ioi.{u1} R (PartialOrder.toPreorder.{u1} R (CompleteSemilatticeInf.toPartialOrder.{u1} R (CompleteLattice.toCompleteSemilatticeInf.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)))) (infᵢ.{u1, u2} R (CompleteLattice.toInfSet.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)) ι (fun (i : ι) => f i))))
Case conversion may be inaccurate. Consider using '#align Union_Ici_eq_Ioi_infi unionᵢ_Ici_eq_Ioi_infᵢₓ'. -/
theorem unionᵢ_Ici_eq_Ioi_infᵢ {R : Type _} [CompleteLinearOrder R] {f : ι → R}
    (no_least_elem : (⨅ i, f i) ∉ range f) : (⋃ i : ι, Ici (f i)) = Ioi (⨅ i, f i) := by
  simp only [← IsGLB.bunionᵢ_Ici_eq_Ioi (@isGLB_infᵢ _ _ _ f) no_least_elem, mem_range,
    Union_exists, Union_Union_eq']
#align Union_Ici_eq_Ioi_infi unionᵢ_Ici_eq_Ioi_infᵢ

/- warning: Union_Iic_eq_Iio_supr -> unionᵢ_Iic_eq_Iio_supᵢ is a dubious translation:
lean 3 declaration is
  forall {ι : Sort.{u1}} {R : Type.{u2}} [_inst_2 : CompleteLinearOrder.{u2} R] {f : ι -> R}, (Not (Membership.Mem.{u2, u2} R (Set.{u2} R) (Set.hasMem.{u2} R) (supᵢ.{u2, u1} R (CompleteSemilatticeSup.toHasSup.{u2} R (CompleteLattice.toCompleteSemilatticeSup.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2))) ι (fun (i : ι) => f i)) (Set.range.{u2, u1} R ι f))) -> (Eq.{succ u2} (Set.{u2} R) (Set.unionᵢ.{u2, u1} R ι (fun (i : ι) => Set.Iic.{u2} R (PartialOrder.toPreorder.{u2} R (CompleteSemilatticeInf.toPartialOrder.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2)))) (f i))) (Set.Iio.{u2} R (PartialOrder.toPreorder.{u2} R (CompleteSemilatticeInf.toPartialOrder.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2)))) (supᵢ.{u2, u1} R (CompleteSemilatticeSup.toHasSup.{u2} R (CompleteLattice.toCompleteSemilatticeSup.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2))) ι (fun (i : ι) => f i))))
but is expected to have type
  forall {ι : Sort.{u2}} {R : Type.{u1}} [_inst_2 : CompleteLinearOrder.{u1} R] {f : ι -> R}, (Not (Membership.mem.{u1, u1} R (Set.{u1} R) (Set.instMembershipSet.{u1} R) (supᵢ.{u1, u2} R (CompleteLattice.toSupSet.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)) ι (fun (i : ι) => f i)) (Set.range.{u1, u2} R ι f))) -> (Eq.{succ u1} (Set.{u1} R) (Set.unionᵢ.{u1, u2} R ι (fun (i : ι) => Set.Iic.{u1} R (PartialOrder.toPreorder.{u1} R (CompleteSemilatticeInf.toPartialOrder.{u1} R (CompleteLattice.toCompleteSemilatticeInf.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)))) (f i))) (Set.Iio.{u1} R (PartialOrder.toPreorder.{u1} R (CompleteSemilatticeInf.toPartialOrder.{u1} R (CompleteLattice.toCompleteSemilatticeInf.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)))) (supᵢ.{u1, u2} R (CompleteLattice.toSupSet.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)) ι (fun (i : ι) => f i))))
Case conversion may be inaccurate. Consider using '#align Union_Iic_eq_Iio_supr unionᵢ_Iic_eq_Iio_supᵢₓ'. -/
theorem unionᵢ_Iic_eq_Iio_supᵢ {R : Type _} [CompleteLinearOrder R] {f : ι → R}
    (no_greatest_elem : (⨆ i, f i) ∉ range f) : (⋃ i : ι, Iic (f i)) = Iio (⨆ i, f i) :=
  @unionᵢ_Ici_eq_Ioi_infᵢ ι (OrderDual R) _ f no_greatest_elem
#align Union_Iic_eq_Iio_supr unionᵢ_Iic_eq_Iio_supᵢ

/- warning: Union_Ici_eq_Ici_infi -> unionᵢ_Ici_eq_Ici_infᵢ is a dubious translation:
lean 3 declaration is
  forall {ι : Sort.{u1}} {R : Type.{u2}} [_inst_2 : CompleteLinearOrder.{u2} R] {f : ι -> R}, (Membership.Mem.{u2, u2} R (Set.{u2} R) (Set.hasMem.{u2} R) (infᵢ.{u2, u1} R (CompleteSemilatticeInf.toHasInf.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2))) ι (fun (i : ι) => f i)) (Set.range.{u2, u1} R ι f)) -> (Eq.{succ u2} (Set.{u2} R) (Set.unionᵢ.{u2, u1} R ι (fun (i : ι) => Set.Ici.{u2} R (PartialOrder.toPreorder.{u2} R (CompleteSemilatticeInf.toPartialOrder.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2)))) (f i))) (Set.Ici.{u2} R (PartialOrder.toPreorder.{u2} R (CompleteSemilatticeInf.toPartialOrder.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2)))) (infᵢ.{u2, u1} R (CompleteSemilatticeInf.toHasInf.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2))) ι (fun (i : ι) => f i))))
but is expected to have type
  forall {ι : Sort.{u2}} {R : Type.{u1}} [_inst_2 : CompleteLinearOrder.{u1} R] {f : ι -> R}, (Membership.mem.{u1, u1} R (Set.{u1} R) (Set.instMembershipSet.{u1} R) (infᵢ.{u1, u2} R (CompleteLattice.toInfSet.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)) ι (fun (i : ι) => f i)) (Set.range.{u1, u2} R ι f)) -> (Eq.{succ u1} (Set.{u1} R) (Set.unionᵢ.{u1, u2} R ι (fun (i : ι) => Set.Ici.{u1} R (PartialOrder.toPreorder.{u1} R (CompleteSemilatticeInf.toPartialOrder.{u1} R (CompleteLattice.toCompleteSemilatticeInf.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)))) (f i))) (Set.Ici.{u1} R (PartialOrder.toPreorder.{u1} R (CompleteSemilatticeInf.toPartialOrder.{u1} R (CompleteLattice.toCompleteSemilatticeInf.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)))) (infᵢ.{u1, u2} R (CompleteLattice.toInfSet.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)) ι (fun (i : ι) => f i))))
Case conversion may be inaccurate. Consider using '#align Union_Ici_eq_Ici_infi unionᵢ_Ici_eq_Ici_infᵢₓ'. -/
theorem unionᵢ_Ici_eq_Ici_infᵢ {R : Type _} [CompleteLinearOrder R] {f : ι → R}
    (has_least_elem : (⨅ i, f i) ∈ range f) : (⋃ i : ι, Ici (f i)) = Ici (⨅ i, f i) := by
  simp only [← IsGLB.bunionᵢ_Ici_eq_Ici (@isGLB_infᵢ _ _ _ f) has_least_elem, mem_range,
    Union_exists, Union_Union_eq']
#align Union_Ici_eq_Ici_infi unionᵢ_Ici_eq_Ici_infᵢ

/- warning: Union_Iic_eq_Iic_supr -> unionᵢ_Iic_eq_Iic_supᵢ is a dubious translation:
lean 3 declaration is
  forall {ι : Sort.{u1}} {R : Type.{u2}} [_inst_2 : CompleteLinearOrder.{u2} R] {f : ι -> R}, (Membership.Mem.{u2, u2} R (Set.{u2} R) (Set.hasMem.{u2} R) (supᵢ.{u2, u1} R (CompleteSemilatticeSup.toHasSup.{u2} R (CompleteLattice.toCompleteSemilatticeSup.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2))) ι (fun (i : ι) => f i)) (Set.range.{u2, u1} R ι f)) -> (Eq.{succ u2} (Set.{u2} R) (Set.unionᵢ.{u2, u1} R ι (fun (i : ι) => Set.Iic.{u2} R (PartialOrder.toPreorder.{u2} R (CompleteSemilatticeInf.toPartialOrder.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2)))) (f i))) (Set.Iic.{u2} R (PartialOrder.toPreorder.{u2} R (CompleteSemilatticeInf.toPartialOrder.{u2} R (CompleteLattice.toCompleteSemilatticeInf.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2)))) (supᵢ.{u2, u1} R (CompleteSemilatticeSup.toHasSup.{u2} R (CompleteLattice.toCompleteSemilatticeSup.{u2} R (CompleteLinearOrder.toCompleteLattice.{u2} R _inst_2))) ι (fun (i : ι) => f i))))
but is expected to have type
  forall {ι : Sort.{u2}} {R : Type.{u1}} [_inst_2 : CompleteLinearOrder.{u1} R] {f : ι -> R}, (Membership.mem.{u1, u1} R (Set.{u1} R) (Set.instMembershipSet.{u1} R) (supᵢ.{u1, u2} R (CompleteLattice.toSupSet.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)) ι (fun (i : ι) => f i)) (Set.range.{u1, u2} R ι f)) -> (Eq.{succ u1} (Set.{u1} R) (Set.unionᵢ.{u1, u2} R ι (fun (i : ι) => Set.Iic.{u1} R (PartialOrder.toPreorder.{u1} R (CompleteSemilatticeInf.toPartialOrder.{u1} R (CompleteLattice.toCompleteSemilatticeInf.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)))) (f i))) (Set.Iic.{u1} R (PartialOrder.toPreorder.{u1} R (CompleteSemilatticeInf.toPartialOrder.{u1} R (CompleteLattice.toCompleteSemilatticeInf.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)))) (supᵢ.{u1, u2} R (CompleteLattice.toSupSet.{u1} R (CompleteLinearOrder.toCompleteLattice.{u1} R _inst_2)) ι (fun (i : ι) => f i))))
Case conversion may be inaccurate. Consider using '#align Union_Iic_eq_Iic_supr unionᵢ_Iic_eq_Iic_supᵢₓ'. -/
theorem unionᵢ_Iic_eq_Iic_supᵢ {R : Type _} [CompleteLinearOrder R] {f : ι → R}
    (has_greatest_elem : (⨆ i, f i) ∈ range f) : (⋃ i : ι, Iic (f i)) = Iic (⨆ i, f i) :=
  @unionᵢ_Ici_eq_Ici_infᵢ ι (OrderDual R) _ f has_greatest_elem
#align Union_Iic_eq_Iic_supr unionᵢ_Iic_eq_Iic_supᵢ

end UnionIxx