import data.fintype.basic
import tactic
import matroid
import finset
import base_of

variables {α : Type*} [fintype α] [decidable_eq α] {m : matroid α} {A B X: finset α}

open finset

namespace matroid

instance : decidable_pred m.ind := m.ind_dec

-- def rank (m : matroid α) (A : finset α) : ℕ := card (classical.some $ exists_base_of m A)
def rank (m : matroid α) (A : finset α) : ℕ := sup (filter m.ind (powerset A)) card

@[simp] lemma rank_def : rank m A = sup (filter m.ind (powerset A)) card := rfl

@[simp] lemma rank_empty : rank m ∅ = 0 :=
begin
  rw rank,
  simp only [card_empty, filter_true_of_mem, forall_eq, powerset_empty, sup_singleton, ind_empty_def, mem_singleton],
end

lemma rank_eq_card_base_of (Bbase : m.base_of A B) : rank m A = B.card :=
begin
  rw rank_def,
  apply nat.le_antisymm, {
    apply finset.sup_le,
    intros C hC,
    simp only [mem_powerset, mem_filter] at hC,
    exact ind_card_le_base_of_card hC.1 hC.2 Bbase,
  }, {
    apply le_sup,
    simp only [mem_powerset, mem_filter],
    exact ⟨Bbase.1, Bbase.2.1⟩,
  }
end

lemma rank_exists_base_of (m : matroid α) (A : finset α) :
  ∃ (B : finset α), m.rank A = B.card ∧ m.base_of A B :=
begin
  obtain ⟨B, Bbase⟩ := exists_base_of m A,
  refine ⟨B, rank_eq_card_base_of Bbase, Bbase⟩,
end

theorem rank_le_card : rank m A ≤ A.card :=
begin
  obtain ⟨bA, bAcard, bAbase⟩ := rank_exists_base_of m A,
  rw bAcard,
  exact card_le_of_subset bAbase.1,
end

@[simp] lemma rank_subset (hAB : A ⊆ B) : rank m A ≤ rank m B :=
begin
  obtain ⟨bA, bAbase⟩ := exists_base_of m A,
  obtain ⟨bB, bBbase⟩ := exists_base_of m B,
  rw rank_eq_card_base_of bAbase,
  rw rank_eq_card_base_of bBbase,
  refine ind_card_le_base_of_card (subset.trans bAbase.1 hAB) bAbase.2.1 bBbase,
end

@[simp] lemma rank_ind : m.ind A ↔ rank m A = A.card :=
begin
  split, {
    intro Aind,
    rw [base_of_refl_iff_ind] at Aind,
    rw rank_eq_card_base_of Aind,
  }, {
    intro h_card,
    obtain ⟨B, Bcard, Bbase⟩ := rank_exists_base_of m A,
    rw h_card at Bcard,
    suffices h_eq : A = B, {
      subst h_eq,
      exact Bbase.2.1,
    },
    symmetry,
    exact eq_of_subset_of_card_le Bbase.1 (le_of_eq Bcard),
  }
end

theorem rank_submodular : m.rank (A ∩ B) + m.rank (A ∪ B) ≤ m.rank A + m.rank B :=
begin
  obtain ⟨bInter, bInter_base⟩ := exists_base_of m (A ∩ B),
  have rankInter := rank_eq_card_base_of bInter_base,

  obtain ⟨bA, bA_sub, bA_base⟩ := ind_subset_base_of (subset.trans bInter_base.1 (inter_subset_left _ _)) (bInter_base.2.1),
  have rankA := rank_eq_card_base_of bA_base,

  obtain ⟨bUnion, bUnion_sub, bUnion_base⟩ :=
    ind_subset_base_of (subset.trans bA_base.1 (subset_union_left A B)) bA_base.2.1,
  have rankUnion := rank_eq_card_base_of bUnion_base,

  obtain ⟨bB, bB_base⟩ := exists_base_of m B,
  have rankB := rank_eq_card_base_of bB_base,

  have indB_sub : (bUnion \ (bA \ bInter)) ⊆ B := by {
    intros x hx,
    rw [mem_sdiff, not_mem_sdiff_iff] at hx,
    rcases hx with ⟨xBunion, xA | xInter⟩, {
      have xAB := bUnion_base.1 xBunion,
      cases (mem_union.1 xAB), {
        exfalso,
        have h_insert_dep := bA_base.2.2 _ xA h,
        refine h_insert_dep (ind_subset_def _ (bUnion_base.2.1)),
        rw ← insert_eq_of_mem xBunion,
        refine insert_subset_insert x bUnion_sub,
      }, {
        exact h,
      }
    }, {
      exact mem_of_mem_inter_right (bInter_base.1 xInter),
    },
  },
  have indB_ind : m.ind (bUnion \ (bA \ bInter)) := ind_subset_def (sdiff_subset _ _) bUnion_base.2.1,

  have tmp := ind_card_le_base_of_card indB_sub indB_ind bB_base,
  have indB_card : (bUnion \ (bA \ bInter)).card + bA.card = bUnion.card + bInter.card := by {
    zify,
    rw card_sdiff_ℤ (subset.trans (sdiff_subset bA bInter) bUnion_sub),
    rw card_sdiff_ℤ bA_sub,
    ring,
  },

  rw [rankInter, rankA, rankUnion, rankB],
  linarith,
end

end matroid


/-
Copyright (c) 2020 Anne Baanen. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Anne Baanen

A typeclass for the two-sided multiplicative inverse.
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.algebra.char_zero
import Mathlib.algebra.char_p.basic
import Mathlib.PostPort

universes u l u_1 u_2

namespace Mathlib

/-!
# Invertible elements

This file defines a typeclass `invertible a` for elements `a` with a
multiplicative inverse.

The intent of the typeclass is to provide a way to write e.g. `⅟2` in a ring
like `ℤ[1/2]` where some inverses exist but there is no general `⁻¹` operator;
or to specify that a field has characteristic `≠ 2`.
It is the `Type`-valued analogue to the `Prop`-valued `is_unit`.

This file also includes some instances of `invertible` for specific numbers in
characteristic zero. Some more cases are given as a `def`, to be included only
when needed. To construct instances for concrete numbers,
`invertible_of_nonzero` is a useful definition.

## Notation

 * `⅟a` is `invertible.inv_of a`, the inverse of `a`

## Implementation notes

The `invertible` class lives in `Type`, not `Prop`, to make computation easier.
If multiplication is associative, `invertible` is a subsingleton anyway.

The `simp` normal form tries to normalize `⅟a` to `a ⁻¹`. Otherwise, it pushes
`⅟` inside the expression as much as possible.

## Tags

invertible, inverse element, inv_of, a half, one half, a third, one third, ½, ⅓

-/

/-- `invertible a` gives a two-sided multiplicative inverse of `a`. -/
class invertible {α : Type u} [Mul α] [HasOne α] (a : α)
where
  inv_of : α
  inv_of_mul_self : inv_of * a = 1
  mul_inv_of_self : a * inv_of = 1

notation:1024 "⅟" => Mathlib.invertible.inv_of

-- This notation has the same precedence as `has_inv.inv`.

@[simp] theorem inv_of_mul_self {α : Type u} [Mul α] [HasOne α] (a : α) [invertible a] : ⅟ * a = 1 :=
  invertible.inv_of_mul_self

@[simp] theorem mul_inv_of_self {α : Type u} [Mul α] [HasOne α] (a : α) [invertible a] : a * ⅟ = 1 :=
  invertible.mul_inv_of_self

@[simp] theorem inv_of_mul_self_assoc {α : Type u} [monoid α] (a : α) (b : α) [invertible a] : ⅟ * (a * b) = b :=
  eq.mpr (id (Eq._oldrec (Eq.refl (⅟ * (a * b) = b)) (Eq.symm (mul_assoc ⅟ a b))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (⅟ * a * b = b)) (inv_of_mul_self a)))
      (eq.mpr (id (Eq._oldrec (Eq.refl (1 * b = b)) (one_mul b))) (Eq.refl b)))

@[simp] theorem mul_inv_of_self_assoc {α : Type u} [monoid α] (a : α) (b : α) [invertible a] : a * (⅟ * b) = b :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a * (⅟ * b) = b)) (Eq.symm (mul_assoc a ⅟ b))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a * ⅟ * b = b)) (mul_inv_of_self a)))
      (eq.mpr (id (Eq._oldrec (Eq.refl (1 * b = b)) (one_mul b))) (Eq.refl b)))

@[simp] theorem mul_inv_of_mul_self_cancel {α : Type u} [monoid α] (a : α) (b : α) [invertible b] : a * ⅟ * b = a := sorry

@[simp] theorem mul_mul_inv_of_self_cancel {α : Type u} [monoid α] (a : α) (b : α) [invertible b] : a * b * ⅟ = a := sorry

theorem inv_of_eq_right_inv {α : Type u} [monoid α] {a : α} {b : α} [invertible a] (hac : a * b = 1) : ⅟ = b :=
  left_inv_eq_right_inv (inv_of_mul_self a) hac

theorem invertible_unique {α : Type u} [monoid α] (a : α) (b : α) (h : a = b) [invertible a] [invertible b] : ⅟ = ⅟ :=
  inv_of_eq_right_inv
    (eq.mpr (id (Eq._oldrec (Eq.refl (a * ⅟ = 1)) h))
      (eq.mpr (id (Eq._oldrec (Eq.refl (b * ⅟ = 1)) (mul_inv_of_self b))) (Eq.refl 1)))

protected instance invertible.subsingleton {α : Type u} [monoid α] (a : α) : subsingleton (invertible a) :=
  subsingleton.intro fun (_x : invertible a) => sorry

/-- An `invertible` element is a unit. -/
def unit_of_invertible {α : Type u} [monoid α] (a : α) [invertible a] : units α :=
  units.mk a ⅟ sorry sorry

@[simp] theorem unit_of_invertible_val {α : Type u} [monoid α] (a : α) [invertible a] : ↑(unit_of_invertible a) = a :=
  rfl

@[simp] theorem unit_of_invertible_inv {α : Type u} [monoid α] (a : α) [invertible a] : ↑(unit_of_invertible a⁻¹) = ⅟ :=
  rfl

theorem is_unit_of_invertible {α : Type u} [monoid α] (a : α) [invertible a] : is_unit a :=
  Exists.intro (unit_of_invertible a) rfl

/-- Each element of a group is invertible. -/
def invertible_of_group {α : Type u} [group α] (a : α) : invertible a :=
  invertible.mk (a⁻¹) (inv_mul_self a) (mul_inv_self a)

@[simp] theorem inv_of_eq_group_inv {α : Type u} [group α] (a : α) [invertible a] : ⅟ = (a⁻¹) :=
  inv_of_eq_right_inv (mul_inv_self a)

/-- `1` is the inverse of itself -/
def invertible_one {α : Type u} [monoid α] : invertible 1 :=
  invertible.mk 1 sorry sorry

@[simp] theorem inv_of_one {α : Type u} [monoid α] [invertible 1] : ⅟ = 1 :=
  inv_of_eq_right_inv (mul_one 1)

/-- `-⅟a` is the inverse of `-a` -/
def invertible_neg {α : Type u} [ring α] (a : α) [invertible a] : invertible (-a) :=
  invertible.mk (-⅟) sorry sorry

@[simp] theorem inv_of_neg {α : Type u} [ring α] (a : α) [invertible a] [invertible (-a)] : ⅟ = -⅟ := sorry

@[simp] theorem one_sub_inv_of_two {α : Type u} [ring α] [invertible (bit0 1)] : 1 - ⅟ = ⅟ := sorry

/-- `a` is the inverse of `⅟a`. -/
protected instance invertible_inv_of {α : Type u} [HasOne α] [Mul α] {a : α} [invertible a] : invertible ⅟ :=
  invertible.mk a (mul_inv_of_self a) (inv_of_mul_self a)

@[simp] theorem inv_of_inv_of {α : Type u} [monoid α] {a : α} [invertible a] [invertible ⅟] : ⅟ = a :=
  inv_of_eq_right_inv (inv_of_mul_self a)

/-- `⅟b * ⅟a` is the inverse of `a * b` -/
def invertible_mul {α : Type u} [monoid α] (a : α) (b : α) [invertible a] [invertible b] : invertible (a * b) :=
  invertible.mk (⅟ * ⅟) sorry sorry

@[simp] theorem inv_of_mul {α : Type u} [monoid α] (a : α) (b : α) [invertible a] [invertible b] [invertible (a * b)] : ⅟ = ⅟ * ⅟ := sorry

/--
If `r` is invertible and `s = r`, then `s` is invertible.
-/
def invertible.copy {α : Type u} [monoid α] {r : α} (hr : invertible r) (s : α) (hs : s = r) : invertible s :=
  invertible.mk ⅟ sorry sorry

theorem commute_inv_of {M : Type u_1} [HasOne M] [Mul M] (m : M) [invertible m] : commute m ⅟ :=
  Eq.trans (mul_inv_of_self m) (Eq.symm (inv_of_mul_self m))

protected instance invertible_pow {M : Type u_1} [monoid M] (m : M) [invertible m] (n : ℕ) : invertible (m ^ n) :=
  invertible.mk (⅟ ^ n) sorry sorry

theorem nonzero_of_invertible {α : Type u} [group_with_zero α] (a : α) [invertible a] : a ≠ 0 := sorry

/-- `a⁻¹` is an inverse of `a` if `a ≠ 0` -/
def invertible_of_nonzero {α : Type u} [group_with_zero α] {a : α} (h : a ≠ 0) : invertible a :=
  invertible.mk (a⁻¹) (inv_mul_cancel h) (mul_inv_cancel h)

@[simp] theorem inv_of_eq_inv {α : Type u} [group_with_zero α] (a : α) [invertible a] : ⅟ = (a⁻¹) :=
  inv_of_eq_right_inv (mul_inv_cancel (nonzero_of_invertible a))

@[simp] theorem inv_mul_cancel_of_invertible {α : Type u} [group_with_zero α] (a : α) [invertible a] : a⁻¹ * a = 1 :=
  inv_mul_cancel (nonzero_of_invertible a)

@[simp] theorem mul_inv_cancel_of_invertible {α : Type u} [group_with_zero α] (a : α) [invertible a] : a * (a⁻¹) = 1 :=
  mul_inv_cancel (nonzero_of_invertible a)

@[simp] theorem div_mul_cancel_of_invertible {α : Type u} [group_with_zero α] (a : α) (b : α) [invertible b] : a / b * b = a :=
  div_mul_cancel a (nonzero_of_invertible b)

@[simp] theorem mul_div_cancel_of_invertible {α : Type u} [group_with_zero α] (a : α) (b : α) [invertible b] : a * b / b = a :=
  mul_div_cancel a (nonzero_of_invertible b)

@[simp] theorem div_self_of_invertible {α : Type u} [group_with_zero α] (a : α) [invertible a] : a / a = 1 :=
  div_self (nonzero_of_invertible a)

/-- `b / a` is the inverse of `a / b` -/
def invertible_div {α : Type u} [group_with_zero α] (a : α) (b : α) [invertible a] [invertible b] : invertible (a / b) :=
  invertible.mk (b / a) sorry sorry

@[simp] theorem inv_of_div {α : Type u} [group_with_zero α] (a : α) (b : α) [invertible a] [invertible b] [invertible (a / b)] : ⅟ = b / a := sorry

/-- `a` is the inverse of `a⁻¹` -/
def invertible_inv {α : Type u} [group_with_zero α] {a : α} [invertible a] : invertible (a⁻¹) :=
  invertible.mk a sorry sorry

/--
Monoid homs preserve invertibility.
-/
def invertible.map {R : Type u_1} {S : Type u_2} [monoid R] [monoid S] (f : R →* S) (r : R) [invertible r] : invertible (coe_fn f r) :=
  invertible.mk (coe_fn f ⅟) sorry sorry

/-- A natural number `t` is invertible in a field `K` if the charactistic of `K` does not divide
`t`. -/
def invertible_of_ring_char_not_dvd {K : Type u_1} [field K] {t : ℕ} (not_dvd : ¬ring_char K ∣ t) : invertible ↑t :=
  invertible_of_nonzero sorry

/-- A natural number `t` is invertible in a field `K` of charactistic `p` if `p` does not divide
`t`. -/
def invertible_of_char_p_not_dvd {K : Type u_1} [field K] {p : ℕ} [char_p K p] {t : ℕ} (not_dvd : ¬p ∣ t) : invertible ↑t :=
  invertible_of_nonzero sorry

protected instance invertible_of_pos {K : Type u_1} [field K] [char_zero K] (n : ℕ) [h : fact (0 < n)] : invertible ↑n :=
  invertible_of_nonzero sorry

protected instance invertible_succ {α : Type u} [division_ring α] [char_zero α] (n : ℕ) : invertible ↑(Nat.succ n) :=
  invertible_of_nonzero sorry

/-!
A few `invertible n` instances for small numerals `n`. Feel free to add your own
number when you need its inverse.
-/

protected instance invertible_two {α : Type u} [division_ring α] [char_zero α] : invertible (bit0 1) :=
  invertible_of_nonzero sorry

protected instance invertible_three {α : Type u} [division_ring α] [char_zero α] : invertible (bit1 1) :=
  invertible_of_nonzero sorry


import data.real.basic
import data.int.parity
import algebra.geom_sum

open set
open finset

open_locale big_operators

noncomputable theory

-- exercici 9
example (θ χ : Prop) : θ ↔ (θ ∧ χ) ∨ (θ ∧ (¬ χ)) :=
begin
  sorry
end

example (θ χ : Prop) : θ ↔ (θ ∧ χ) ∨ (θ ∧ (¬ χ)) :=
begin
  split;finish,
end

-- exercici 11
def R := λ (x y : ℕ), x < y
def S := λ (x y : ℕ), x > y

example : ∀ x, ∃ y, R x y :=
begin
  unfold R,
  intro x,
  use x+10,
  linarith,
end

example : ¬ (∀ x, ∃ y, S x y) :=
begin
  unfold S,
  push_neg,
  use 0,
  intro y,
  exact zero_le y,
end

-- exercici 12
def S' := λ (a b c : ℕ), c = a + b

example : ∃ (x : ℕ), ∃ (z : ℕ), (¬ x = z) ∧
  (∃ y, S' y y x) ∧
  (∃ t, S' t t z) :=
begin
  unfold S',
  use 0,
  use 2,
  split,
  {
    change 0 ≠ 2,
    exact two_ne_zero.symm,
  },
  split,
  {
    use 0,
  },
  {
    use 1,
  }
end

example : ¬ (∃ x, (∀ y, ∃ z, S' y z x)) :=
begin
  sorry
end

--@[simp]
--lemma simp_succ (n : ℕ) : n.succ = n + 1 := rfl

-- 14a
example (n : ℕ) : ∑ k in range (n + 1), (k : ℝ) = n * (n + 1) / 2 :=
begin
  induction n with n hn,
  {
    norm_num,
  },
  {
    rw sum_range_succ,
    simp at hn ⊢,
    rw hn,
    ring,
  }
end

-- 14b
example (n : ℕ) : ∑ k in range (n + 1), (k^2 : ℝ) = n*(n + 1)*(2*n + 1) / 6 :=
begin
  induction n with n hn,
  {
    norm_num,
  },
  {
    rw sum_range_succ,
    simp at hn ⊢,
    rw hn,
    ring,
  }
end

-- 14c
example (n : ℕ) : 6 ∣ (n * (n^2 + 5)) :=
begin
  sorry
end

-- exercici 15
example (n : ℕ) : 3 ∣ (4:ℤ)^n - 1 :=
begin
  sorry
end

example : ∃ (n:ℕ), ¬ 3 ∣ (4:ℤ)^n + 1 :=
begin
  sorry
end

-- exercici 17
example (a : ℕ → ℝ) (h1 : (∀ n, 0 < a n) ∨ (∀ n, a n < 0))
(h2 : ∀ n, a n > -1) (n : ℕ):
1 + ∑ i in range (n+2), a i < ∏ i in range (n+2), (1 + a i):=
begin
  induction n with n hn,
  sorry
end

-- exercici 17bis
example (a : ℕ → ℝ) (h1 : (∀ n, 0 < a n) ∨ (∀ n, a n < 0)) (h2 : ∀ n, a n > -1) :
∀ n : ℕ, 2 ≤ n → 1 + ∑ i in range n, a i < ∏ i in range n, (1 + a i):=
begin
  sorry
end


import tactic

variables P Q R :  Prop

example : (P → Q) ∧ (Q → R) → (P → R) :=
begin
    intros h,
    have hpq : P → Q,
    exact h.left,
    have hqr : Q → R,
    exact h.right,
    clear h,
    intro hp,
    have hq : Q,
    exact hpq hp,
    exact hqr hq,
end

-- Alternatively
example : (P → Q) ∧ (Q → R) → (P → R) :=
begin
    intros h,
    have hpq : P → Q := h.left,
    have hqr : Q → R := h.right,
    clear h,
    intro hp,
    have hq : Q,
    exact hpq hp,
    exact hqr hq,
end

/- Alternatively, using the cases tactic -/

example : (P → Q) ∧ (Q → R) → (P → R) :=
begin
    intros h,
    cases h with hpq hqr,
    intro hp,
    exact (hqr (hpq (hp))),
end


import Init.WF
import Init.Data.Nat

theorem nat_lt : ∀ n : Nat,
  Acc (fun (x y : Nat) => x < y) n := by
  intros n
  induction n with
  | zero =>
    focus
      apply Acc.intro
      intros y Hy
      cases Hy
  | succ n ih =>
    focus
      apply Acc.intro
      intros y Hy
      apply Acc.intro
      intros z Hz
      cases ih with
      | _ _ R =>
        apply R
        have Ht := Nat.le_of_lt_succ Hy
        have Hw := Nat.lt_of_lt_of_le Hz Ht
        exact Hw

class One (α : Type u) where
  one : α

class Op (α : Type u) where
  op : α → α → α

class Associative (α : Type u) extends (One α), (Op α) where
  op_associative : ∀ (x y z : α), op x (op y z) = op (op x y) z

class LeftOne (α : Type u) extends (One α), (Op α) where
  left_one : ∀ x : α, op one x = x

class RightOne (α : Type u) extends (One α), (Op α) where
  right_one : ∀ x : α, op x one = x

class Monoid (α : Type u) extends
  (One α), (Op α), (Associative α),
  (LeftOne α), (RightOne α)

class Inv (α : Type u) where
   inv : α → α

class LeftInv (α : Type u) extends (Inv α), (Op α) where
  left_inv : forall x : α, op (inv x) x = one

class RightInv (α : Type u) extends (Inv α), (Op α) where
    right_inv : forall x : α, op x (inv x) = one

class Group (α : Type u) extends (Monoid α), (Inv α),
  (LeftInv α), (RightInv α)

theorem monoid_cancel_left
  {α : Type u}
  [H : Monoid α]
  (z iz x y : α) :
  H.op iz z = H.one →
  (H.op z x = H.op z y ↔ x = y) := by
  intro ha
  apply Iff.intro
  focus
    intro hb
    have Hcut : (H.op iz  (H.op z x))  = (H.op iz (H.op z  y)) := by
      rewrite [hb]; exact rfl
    rewrite [H.op_associative, ha, H.left_one] at Hcut
    rewrite [H.op_associative, ha, H.left_one] at Hcut
    exact Hcut
  focus
    intro hb
    rewrite [hb]
    exact rfl

theorem monoid_cancel_right
  {α : Type u}
  [H : Monoid α]
  (z iz x y : α) :
  H.op z iz = H.one →
  (H.op x z = H.op y z ↔ x = y) := by
  intro ha
  apply Iff.intro
  focus
    intro hb
    have Hcut : (H.op (H.op x z) iz)  = (H.op (H.op y z) iz) := by
      rewrite [hb]; exact rfl
    rewrite [<-H.op_associative, ha, H.right_one] at Hcut
    rewrite [<-H.op_associative, ha, H.right_one] at Hcut
    exact Hcut
  focus
    intro hb
    subst hb
    exact rfl


import data.real.basic
open classical
attribute [instance] prop_decidable

/-
  Rigorous definition of a limit
  For a sequence x_n, we say that \lim_{n \to \infty} x_n = l if
    ∀ ε > 0, ∃ N, n ≥ N → |x_n - l| < ε
-/

def lim_to_inf (x : ℕ → ℝ) (l : ℝ) :=
  ∀ ε > 0, ∃ N, ∀ n ≥ N, abs (x n - l) < ε

theorem exercise_1p4 (x : ℕ → ℝ) (l : ℝ) (h₁ : lim_to_inf x l) :
  lim_to_inf (λ n, abs (x n)) (abs l) :=
begin
    intros ε ε_pos,
    rcases h₁ ε ε_pos with ⟨N, hN⟩,
    use N,
    intros n hn,
    calc
    abs (abs (x n) - abs l) ≤ abs ((x n) - l) : abs_abs_sub_le_abs_sub (x n) l
    ... < ε : hN n hn
end


/-
Copyright (c) 2020 Aaron Anderson. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Aaron Anderson
-/

import order.bounds

/-!
# Intervals in Lattices

In this file, we provide instances of lattice structures on intervals within lattices.
Some of them depend on the order of the endpoints of the interval, and thus are not made
global instances. These are probably not all of the lattice instances that could be placed on these
intervals, but more can be added easily along the same lines when needed.

## Main definitions
In the following, `*` can represent either `c`, `o`, or `i`.
  * `set.Ic*.order_bot`
  * `set.Ii*.semillatice_inf`
  * `set.I*c.order_top`
  * `set.I*c.semillatice_inf`
  * `set.I**.lattice`
  * `set.Iic.bounded_order`, within an `order_bot`
  * `set.Ici.bounded_order`, within an `order_top`

-/

variable {α : Type*}

namespace set

namespace Ico

variables {a b : α}

instance [semilattice_inf α] : semilattice_inf (Ico a b) :=
subtype.semilattice_inf (λ x y hx hy, ⟨le_inf hx.1 hy.1, lt_of_le_of_lt inf_le_left hx.2⟩)

/-- `Ico a b` has a bottom element whenever `a < b`. -/
@[reducible] protected def order_bot [partial_order α] (h : a < b) : order_bot (Ico a b) :=
(is_least_Ico h).order_bot

end Ico

namespace Iio

instance [semilattice_inf α] {a : α} : semilattice_inf (Iio a) :=
subtype.semilattice_inf (λ x y hx hy, lt_of_le_of_lt inf_le_left hx)

end Iio

namespace Ioc

variables {a b : α}

instance [semilattice_sup α] : semilattice_sup (Ioc a b) :=
subtype.semilattice_sup (λ x y hx hy, ⟨lt_of_lt_of_le hx.1 le_sup_left, sup_le hx.2 hy.2⟩)

/-- `Ioc a b` has a top element whenever `a < b`. -/
@[reducible] protected def order_top [partial_order α] (h : a < b) : order_top (Ioc a b) :=
(is_greatest_Ioc h).order_top

end Ioc

namespace Iio

instance [semilattice_sup α] {a : α} : semilattice_sup (Ioi a) :=
subtype.semilattice_sup (λ x y hx hy, lt_of_lt_of_le hx le_sup_left)

end Iio

namespace Iic

variables {a : α}

instance [semilattice_inf α] : semilattice_inf (Iic a) :=
subtype.semilattice_inf (λ x y hx hy, le_trans inf_le_left hx)

instance [semilattice_sup α] : semilattice_sup (Iic a) :=
subtype.semilattice_sup (λ x y hx hy, sup_le hx hy)

instance [lattice α] : lattice (Iic a) :=
{ .. Iic.semilattice_inf,
  .. Iic.semilattice_sup }

instance [preorder α] : order_top (Iic a) :=
{ top := ⟨a, le_refl a⟩,
  le_top := λ x, x.prop }

@[simp] lemma coe_top [partial_order α] {a : α} : ↑(⊤ : Iic a) = a := rfl

instance [preorder α] [order_bot α] : order_bot (Iic a) :=
{ bot := ⟨⊥, bot_le⟩,
  bot_le := λ ⟨_,_⟩, subtype.mk_le_mk.2 bot_le }

@[simp] lemma coe_bot [preorder α] [order_bot α] {a : α} : ↑(⊥ : Iic a) = (⊥ : α) := rfl

instance [partial_order α] [no_min_order α] {a : α} : no_min_order (Iic a) :=
⟨λ x, let ⟨y, hy⟩ := exists_lt x.1 in ⟨⟨y, le_trans hy.le x.2⟩, hy⟩ ⟩

instance [preorder α] [order_bot α] : bounded_order (Iic a) :=
{ .. Iic.order_top,
  .. Iic.order_bot }

end Iic

namespace Ici

variables {a : α}

instance [semilattice_inf α] : semilattice_inf (Ici a) :=
subtype.semilattice_inf (λ x y hx hy, le_inf hx hy)

instance [semilattice_sup α] : semilattice_sup (Ici a) :=
subtype.semilattice_sup (λ x y hx hy, le_trans hx le_sup_left)

instance [lattice α] : lattice (Ici a) :=
{ .. Ici.semilattice_inf,
  .. Ici.semilattice_sup }

instance [preorder α] : order_bot (Ici a) :=
{ bot := ⟨a, le_refl a⟩,
  bot_le := λ x, x.prop }

@[simp] lemma coe_bot [partial_order α] {a : α} : ↑(⊥ : Ici a) = a := rfl

instance [preorder α] [order_top α] : order_top (Ici a) :=
{ top := ⟨⊤, le_top⟩,
  le_top := λ ⟨_,_⟩, subtype.mk_le_mk.2 le_top }

@[simp] lemma coe_top [preorder α] [order_top α] {a : α} : ↑(⊤ : Ici a) = (⊤ : α) := rfl

instance [partial_order α] [no_max_order α] {a : α} : no_max_order (Ici a) :=
⟨λ x, let ⟨y, hy⟩ := exists_gt x.1 in ⟨⟨y, le_trans x.2 hy.le⟩, hy⟩ ⟩

instance [preorder α] [order_top α] : bounded_order (Ici a) :=
{ .. Ici.order_top,
  .. Ici.order_bot }

end Ici

namespace Icc

instance [semilattice_inf α] {a b : α} : semilattice_inf (Icc a b) :=
subtype.semilattice_inf (λ x y hx hy, ⟨le_inf hx.1 hy.1, le_trans inf_le_left hx.2⟩)

instance [semilattice_sup α] {a b : α} : semilattice_sup (Icc a b) :=
subtype.semilattice_sup (λ x y hx hy, ⟨le_trans hx.1 le_sup_left, sup_le hx.2 hy.2⟩)

instance [lattice α] {a b : α} : lattice (Icc a b) :=
{ .. Icc.semilattice_inf,
  .. Icc.semilattice_sup }

/-- `Icc a b` has a bottom element whenever `a ≤ b`. -/
@[reducible] protected def order_bot [preorder α] {a b : α} (h : a ≤ b) : order_bot (Icc a b) :=
(is_least_Icc h).order_bot

/-- `Icc a b` has a top element whenever `a ≤ b`. -/
@[reducible] protected def order_top [preorder α] {a b : α} (h : a ≤ b) : order_top (Icc a b) :=
(is_greatest_Icc h).order_top

/-- `Icc a b` is a `bounded_order` whenever `a ≤ b`. -/
@[reducible] protected def bounded_order [preorder α] {a b : α} (h : a ≤ b) :
  bounded_order (Icc a b) :=
{ .. Icc.order_top h,
  .. Icc.order_bot h }

end Icc

end set


-- Interseccion_de_intersecciones.lean
-- Intersección de intersecciones
-- José A. Alonso Jiménez
-- Sevilla, 3 de junio de 2021
-- ---------------------------------------------------------------------

-- ---------------------------------------------------------------------
-- Demostrar que
--    (⋂ i, A i ∩ B i) = (⋂ i, A i) ∩ (⋂ i, B i)
-- ----------------------------------------------------------------------

import data.set.basic
import tactic

open set

variable  {α : Type}
variables A B : ℕ → set α

-- 1ª demostración
-- ===============

example : (⋂ i, A i ∩ B i) = (⋂ i, A i) ∩ (⋂ i, B i) :=
begin
  ext x,
  simp only [mem_inter_eq, mem_Inter],
  split,
  { intro h,
    split,
    { intro i,
      exact (h i).1 },
    { intro i,
      exact (h i).2 }},
  { intros h i,
    cases h with h1 h2,
    split,
    { exact h1 i },
    { exact h2 i }},
end

-- 2ª demostración
-- ===============

example : (⋂ i, A i ∩ B i) = (⋂ i, A i) ∩ (⋂ i, B i) :=
begin
  ext x,
  simp only [mem_inter_eq, mem_Inter],
  exact ⟨λ h, ⟨λ i, (h i).1, λ i, (h i).2⟩,
         λ ⟨h1, h2⟩ i, ⟨h1 i, h2 i⟩⟩,
end

-- 3ª demostración
-- ===============

example : (⋂ i, A i ∩ B i) = (⋂ i, A i) ∩ (⋂ i, B i) :=
begin
  ext,
  simp only [mem_inter_eq, mem_Inter],
  finish,
end

-- 4ª demostración
-- ===============

example : (⋂ i, A i ∩ B i) = (⋂ i, A i) ∩ (⋂ i, B i) :=
begin
  ext,
  finish [mem_inter_eq, mem_Inter],
end

-- 5ª demostración
-- ===============

example : (⋂ i, A i ∩ B i) = (⋂ i, A i) ∩ (⋂ i, B i) :=
by finish [mem_inter_eq, mem_Inter, ext_iff]


import tactic data.nat.prime
open nat

/--------------------------------------------------------------------------

``have``

  ``have hp : P,`` creates a new goal with target ``P`` and
  adds ``hp : P`` as a hypothesis to the original goal.

You'll need the following theorem from the library:

nat.dvd_sub : n ≤ m → k ∣ m → k ∣ n → k ∣ m - n

   (Note that you don't need to provide n m k as inputs to dvd_sub
   Lean can infer these from the rest of the expression.
   More on this tomorrow.)

Delete the ``sorry,`` below and replace it with a legitimate proof.

--------------------------------------------------------------------------/

theorem dvd_sub_one {p a : ℕ} : (p ∣ a) → (p ∣ a + 1) → (p ∣ 1) :=
begin
  sorry,
end


/-
Copyright (c) 2022 Kevin Buzzard. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author : Kevin Buzzard
-/

import tactic -- imports all the Lean tactics

/-!

# Quotients in Lean -- how it works

If `X` is a type and `≈` is an equivalence relation on `X`, then I claim
that there exits a type `Y` and a map `q : X → Y` with the following
two properties:

1) `q` is surjective;
2) `q(x₁) = q(x₂) ↔ x₁ ≈ x₂`.

I want to call `Y` "the quotient of `X` by `≈`" but this name is problematic
for reasons I'll describe a little later on. An important exercise if you
want to understand what's going on here is to figure out what this type
`Y` is before reading the spoiler below.

## My favourite equivalence relation, and a spoiler.

Let me tell you about my favourite equivalence relation. The type `X` is
the collection of red, green, blue and yellow plastic shapes in my office.
I have several hundred of them; they are squares, triangles and pentagons,
they click together, and you can make some pretty cool 3D shapes with them.
The equivalence relation `≈` on `X` is that two shapes are equivalent if
(and only if) they have the same colour.

Now here's the spoiler. With notation as above (so back to the general
cases, with `X` a general type and `≈` a general equivalence relation),
we can define `Y` to be the type of equivalence classes for `≈`. Let's
use the notation `⟦x⟧ : Y` to denote the equivalence class of `x : X`.
The function `q` sends `x` to `⟦x⟧`. You know from earlier on in your
mathematical career that `⟦x₁⟧ = ⟦x₂⟧` if and only if `x₁ ≈ x₂`,
and clearly `q` is surjective because given an arbitrary `y : Y`, it's
an equivalence class and hence by definition equal to `⟦x⟧` for some
element `x` of the class. Hence `Y` and `q` satisfy all the axioms
above.

In the example above, my favourite equivalence relation, there are
four equivalence classes, so `Y` has four elements. One consists of
about 70 red plastic shapes, one consists of about 70 blue plastic shapes,
one is all the green shapes and one is all the yellow shapes, the
function `q` sends a plastic shape `x` to the element corresponding to its
colour and you can easily check the two axioms above are satisfied.

But here is a second possibility for `Y`. We let `Y` be the set
`{red, yellow, green, blue}`, and we let `q` be the map sending
a shape to its colour. Again it's easy to check that all the axioms work.

So in fact there is more than one answer to the question "what is `Y`?".
Let's take a closer look at those two answers. Let's call `Y₁` the
first answer (so an element of `Y₁` is a collection of shapes all of which
have the same colour, e.g. "the 70 red shapes"), and let's
call `Y₂` the second answer (so an element of `Y₂` is a colour, e.g. "red").
There are obvious bijections between `Y₁` and `Y₂`, and furthermore
one can check that those bijections "commute with the `q`s" in the sense
that if you do `q₁ : X → Y₁` and then do the bijection, you end up with
the map `q₂ : X → Y₂`. Quotients are unique up to unique isomorphism,
but they are not unique.

This is why I don't like to talk about *the* quotient of `X` by `≈`,
I would rather talk about *a* quotient of `X` by `≈`.

Another example is the ring `ℤ/10ℤ`. When I was at school I imagined
that this quotient ring was `{0,1,2,3,4,5,6,7,8,9}`. At university
I leant that actually the elements were cosets of the ideal `10ℤ` in
the ring `ℤ` and I was foolish enough to believe the lecturer who told
me this. Both of these choices are just *models* for the quotient.
It doesn't make sense to talk about "the" quotient -- it's nice to know
that models exist, but when we're proving things about quotients
like `ℤ/10ℤ` (e.g. proving that it has a natural ring structure),
the model doesn't matter; all that matters is that there's a "reduce mod 10"
map from `ℤ` to `ℤ/10ℤ` and that the axioms above are satisfied.

## Lean's quotients

Lean's choice of `Y` is called `quotient s`, where `s` is a term which packages
up `X` and `≈` and the proof that `≈` is an equivalence relation all into
one thing. The type of `s` is `setoid X` and to give a term of type `setoid X`
you have to give two pieces of information: a binary relation on `X`,
and a proof that it's an equivalence relation.

## Let's make a quotient

Let's make the quotient `ℤ/37ℤ`. We will do this by starting with the integers,
defining a binary relation `R` on them by `R a b` is true iff `a` and `b`
are congruent mod `37`, proving it's an equivalence relation, making
the corresponding term `s : setoid ℤ` and then defining `Zmod37` to be the
quotient.

-/

/-- The binary relation `R a b` is defined to be the statement that `a - b`
is a multiple of 37. -/
def R (a b : ℤ) : Prop :=
∃ z : ℤ, a - b = 37 * z

lemma R_def (a b : ℤ) : R a b ↔ ∃ z : ℤ, a - b = 37 * z :=
begin
  refl,
end

lemma R_reflexive : reflexive R :=
begin
  unfold reflexive, -- if you like
  sorry
end

lemma R_symmetric : symmetric R :=
begin
  sorry
end

lemma R_transitive : transitive R :=
begin
  sorry
end

lemma R_equivalence : equivalence R :=
begin
  sorry,
end

-- The "setoid" -- everything we've defined and proved so far,
-- all bundled up into one term
def s : setoid ℤ :=
{ r := R,
  iseqv := R_equivalence }

-- Let's not make a definition, let's just make notation
notation `Zmod37` := quotient s

-- Then `Zmod37` and `quotient s` are syntactically equal

/-

In the next sheet we'll start to learn about the
API for `quotient`. We'll learn the name of the
map from `ℤ` to `Zmod37`, we'll set up the notation
`≈` and `⟦x⟧`, and we'll prove the two axioms, as well
as discussing another fundamental property of quotients.

-/


import data.real.basic
import tactic
-- import C_Limits.fae_solutions.Course
-- open vilnius

namespace vilnius

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

-- Recall the
definition is_limit (a : ℕ → ℝ) (l : ℝ) : Prop :=
∀ ε > 0, ∃ N, ∀ n ≥ N, | a n - l | < ε

example {a : ℕ → ℝ} {l : ℝ} (c : ℝ) (ha : is_limit a l) :
  is_limit (λ i, a i + c) (l + c) :=
begin
  intros ε hε,
  obtain ⟨N, hN⟩ := ha ε hε,
  use N,
  intros k hk,
  simp only,
  rw add_sub_add_comm,
  rw sub_self,
  rw add_zero,
  exact hN k hk,
end

example (a : ℕ → ℝ) (l : ℝ) :
  is_limit a l ↔ is_limit (λ i, a i - l) 0 :=
begin
  split,
  all_goals { intros ha ε hε,
    obtain ⟨N, hN⟩ := ha ε hε,
    use N,
    intros n hn,
    simp only [sub_zero] at *,
    exact hN n hn},
end

/- Helpful things:
`abs_pos : 0 < |a| ↔ a ≠ 0`
`div_pos : 0 < a → 0 < b → 0 < a / b`
`abs_mul x y : |x * y| = |x| * |y|`
`lt_div_iff' : 0 < c → (a < b / c ↔ c * a < b)`
I typically find these things myself with a combination of
the "guess the name of the lemma" game (and ctrl-space).

Recall also that we have proved the-/

theorem is_limit_add {a b : ℕ → ℝ} {l m : ℝ}
  (h1 : is_limit a l) (h2 : is_limit b m) :
  is_limit (a + b) (l + m) := sorry

--as well as the

theorem is_limit_mul_const_left {a : ℕ → ℝ} {l c : ℝ} (h : is_limit a l) :
  is_limit (λ n, c * (a n)) (c * l) := sorry

-- And now, over to you!

-- This should just be a couple of lines now.
example (a : ℕ → ℝ) (b : ℕ → ℝ) (α β c d : ℝ)
    (ha : is_limit a α) (hb : is_limit b β) :
    is_limit ( λ n, c * (a n) + d * (b n) ) (c * α + d * β) :=
begin
  -- intros ε hε,**BAD IDEA**
  apply is_limit_add,
  apply is_limit_mul_const_left ha,
  apply is_limit_mul_const_left hb,
end

example (a : ℕ → ℝ) (b : ℕ → ℝ)
  (l : ℝ) (m : ℝ) (hl : is_limit a l) (hm : is_limit b m)
  (hle : ∀ n, a n ≤ b n) : l ≤ m :=
begin
  set ε := l - m with def_ε,
  by_cases hε : ε ≤ 0,
  { exact le_of_sub_nonpos hε },
  { cases hl (ε / 2) (half_pos (not_le.mp hε)) with N hN,
    cases hm (ε / 2) (half_pos (not_le.mp hε)) with M hM,
    specialize hN (max N M) (le_max_left N M),
    specialize hM (max N M) (le_max_right N M),
    rw abs_sub_lt_iff at hN hM,
    replace hM := hM.1,
    replace hN := hN.2,
    rw def_ε at hM hN,
    rw [sub_lt_iff_lt_add] at hM,
    rw sub_lt at hN,
    rw sub_div at hM hN,
    have h_calc: l - (l / 2 - m /2 ) = l / 2 - m / 2 + m,
    rw ← sub_add,
    rw sub_half,
    rw sub_add,
    rw half_sub,
    rw sub_eq_add_neg,
    rw neg_neg,
    by_contra,
    rw h_calc at hN,
    have := hM.trans hN,
    rw ← not_le at this,
    apply this,
    exact hle (max N M) },
end

end vilnius


/-
Copyright (c) 2021 Anne Baanen. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Anne Baanen
-/
import algebra.algebra.basic
import number_theory.class_number.admissible_absolute_value

/-!
# Admissible absolute value on the integers

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.
This file defines an admissible absolute value `absolute_value.abs_is_admissible`
which we use to show the class number of the ring of integers of a number field
is finite.

## Main results

 * `absolute_value.abs_is_admissible` shows the "standard" absolute value on `ℤ`,
   mapping negative `x` to `-x`, is admissible.
-/

namespace absolute_value

open int

/-- We can partition a finite family into `partition_card ε` sets, such that the remainders
in each set are close together. -/
lemma exists_partition_int (n : ℕ) {ε : ℝ} (hε : 0 < ε) {b : ℤ} (hb : b ≠ 0) (A : fin n → ℤ) :
  ∃ (t : fin n → fin ⌈1 / ε⌉₊),
  ∀ i₀ i₁, t i₀ = t i₁ → ↑(abs (A i₁ % b - A i₀ % b)) < abs b • ε :=
begin
  have hb' : (0 : ℝ) < ↑(abs b) := int.cast_pos.mpr (abs_pos.mpr hb),
  have hbε : 0 < abs b • ε,
  { rw algebra.smul_def,
    exact mul_pos hb' hε },
  have hfloor : ∀ i, 0 ≤ floor ((A i % b : ℤ) / (abs b • ε) : ℝ),
  { intro i,
    exact floor_nonneg.mpr (div_nonneg (cast_nonneg.mpr (mod_nonneg _ hb)) hbε.le) },
  refine ⟨λ i, ⟨nat_abs (floor ((A i % b : ℤ) / (abs b • ε) : ℝ)), _⟩, _⟩,
  { rw [← coe_nat_lt, nat_abs_of_nonneg (hfloor i), floor_lt],
    apply lt_of_lt_of_le _ (nat.le_ceil _),
    rw [algebra.smul_def, eq_int_cast, ← div_div, div_lt_div_right hε,
        div_lt_iff hb', one_mul, cast_lt],
    exact int.mod_lt _ hb },
  intros i₀ i₁ hi,
  have hi : (⌊↑(A i₀ % b) / abs b • ε⌋.nat_abs : ℤ) = ⌊↑(A i₁ % b) / abs b • ε⌋.nat_abs :=
    congr_arg (coe : ℕ → ℤ) (fin.mk_eq_mk.mp hi),
  rw [nat_abs_of_nonneg (hfloor i₀), nat_abs_of_nonneg (hfloor i₁)] at hi,
  have hi := abs_sub_lt_one_of_floor_eq_floor hi,
  rw [abs_sub_comm, ← sub_div, abs_div, abs_of_nonneg hbε.le, div_lt_iff hbε, one_mul] at hi,
  rwa [int.cast_abs, int.cast_sub]
end

/-- `abs : ℤ → ℤ` is an admissible absolute value -/
noncomputable def abs_is_admissible : is_admissible absolute_value.abs :=
{ card := λ ε, ⌈1 / ε⌉₊,
  exists_partition' := λ n ε hε b hb, exists_partition_int n hε hb,
  .. absolute_value.abs_is_euclidean }

noncomputable instance : inhabited (is_admissible absolute_value.abs) :=
⟨abs_is_admissible⟩

end absolute_value


/-
Copyright (c) 2020 Fox Thomson. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Fox Thomson
-/
import set_theory.game.winner
import tactic.nth_rewrite.default
import tactic.equiv_rw

/-!
# Basic definitions about impartial (pre-)games

We will define an impartial game, one in which left and right can make exactly the same moves.
Our definition differs slightly by saying that the game is always equivalent to its negative,
no matter what moves are played. This allows for games such as poker-nim to be classifed as
impartial.
-/

universe u

namespace pgame

local infix ` ≈ ` := equiv

/-- The definition for a impartial game, defined using Conway induction -/
def impartial_aux : pgame → Prop
| G := G ≈ -G ∧ (∀ i, impartial_aux (G.move_left i)) ∧ (∀ j, impartial_aux (G.move_right j))
using_well_founded { dec_tac := pgame_wf_tac }

lemma impartial_aux_def {G : pgame} : G.impartial_aux ↔ G ≈ -G ∧
  (∀ i, impartial_aux (G.move_left i)) ∧ (∀ j, impartial_aux (G.move_right j)) :=
begin
  split,
  { intro hi,
    unfold1 impartial_aux at hi,
    exact hi },
  { intro hi,
    unfold1 impartial_aux,
    exact hi }
end

/-- A typeclass on impartial games. -/
class impartial (G : pgame) : Prop := (out : impartial_aux G)

lemma impartial_iff_aux {G : pgame} : G.impartial ↔ G.impartial_aux :=
⟨λ h, h.1, λ h, ⟨h⟩⟩

lemma impartial_def {G : pgame} : G.impartial ↔ G ≈ -G ∧
  (∀ i, impartial (G.move_left i)) ∧ (∀ j, impartial (G.move_right j)) :=
by simpa only [impartial_iff_aux] using impartial_aux_def

namespace impartial

instance impartial_zero : impartial 0 :=
by { rw impartial_def, dsimp, simp }

lemma neg_equiv_self (G : pgame) [h : G.impartial] : G ≈ -G := (impartial_def.1 h).1

instance move_left_impartial {G : pgame} [h : G.impartial] (i : G.left_moves) :
  (G.move_left i).impartial :=
(impartial_def.1 h).2.1 i

instance move_right_impartial {G : pgame} [h : G.impartial] (j : G.right_moves) :
  (G.move_right j).impartial :=
(impartial_def.1 h).2.2 j

instance impartial_add : ∀ (G H : pgame) [G.impartial] [H.impartial], (G + H).impartial
| G H :=
begin
  introsI hG hH,
  rw impartial_def,
  split,
  { apply equiv_trans _ (neg_add_relabelling G H).equiv.symm,
    exact add_congr (neg_equiv_self _) (neg_equiv_self _) },
  split,
  all_goals
  { intro i,
    equiv_rw pgame.left_moves_add G H at i <|> equiv_rw pgame.right_moves_add G H at i,
    cases i },
  all_goals
  { simp only [add_move_left_inl, add_move_right_inl, add_move_left_inr, add_move_right_inr],
    exact impartial_add _ _ }
end
using_well_founded { dec_tac := pgame_wf_tac }

instance impartial_neg : ∀ (G : pgame) [G.impartial], (-G).impartial
| G :=
begin
  introI hG,
  rw impartial_def,
  split,
  { rw neg_neg,
    symmetry,
    exact neg_equiv_self G },
  split,
  all_goals
  { intro i,
    equiv_rw G.left_moves_neg at i <|> equiv_rw G.right_moves_neg at i,
    simp only [move_left_left_moves_neg_symm, move_right_right_moves_neg_symm],
    exact impartial_neg _ }
end
using_well_founded { dec_tac := pgame_wf_tac }

lemma winner_cases (G : pgame) [G.impartial] : G.first_loses ∨ G.first_wins :=
begin
  rcases G.winner_cases with hl | hr | hp | hn,
  { cases hl with hpos hnonneg,
    rw ←not_lt at hnonneg,
    have hneg := lt_of_lt_of_equiv hpos (neg_equiv_self G),
    rw [lt_iff_neg_gt, neg_neg, neg_zero] at hneg,
    contradiction },
  { cases hr with hnonpos hneg,
    rw ←not_lt at hnonpos,
    have hpos := lt_of_equiv_of_lt (neg_equiv_self G).symm hneg,
    rw [lt_iff_neg_gt, neg_neg, neg_zero] at hpos,
    contradiction },
  { left, assumption },
  { right, assumption }
end

lemma not_first_wins (G : pgame) [G.impartial] : ¬G.first_wins ↔ G.first_loses :=
by cases winner_cases G; finish using [not_first_loses_of_first_wins]

lemma not_first_loses (G : pgame) [G.impartial] : ¬G.first_loses ↔ G.first_wins :=
iff.symm $ iff_not_comm.1 $ iff.symm $ not_first_wins G

lemma add_self (G : pgame) [G.impartial] : (G + G).first_loses :=
  first_loses_is_zero.2 $ equiv_trans (add_congr (neg_equiv_self G) G.equiv_refl)
  add_left_neg_equiv

lemma equiv_iff_sum_first_loses (G H : pgame) [G.impartial] [H.impartial] :
  G ≈ H ↔ (G + H).first_loses :=
begin
  split,
  { intro heq,
    exact first_loses_of_equiv (add_congr (equiv_refl _) heq) (add_self G) },
  { intro hGHp,
    split,
    { rw le_iff_sub_nonneg,
      exact le_trans hGHp.2
        (le_trans add_comm_le $ le_of_le_of_equiv (le_refl _) $ add_congr (equiv_refl _)
        (neg_equiv_self G)) },
    { rw le_iff_sub_nonneg,
      exact le_trans hGHp.2
        (le_of_le_of_equiv (le_refl _) $ add_congr (equiv_refl _) (neg_equiv_self H)) } }
end

lemma le_zero_iff {G : pgame} [G.impartial] : G ≤ 0 ↔ 0 ≤ G :=
by rw [le_zero_iff_zero_le_neg, le_congr (equiv_refl 0) (neg_equiv_self G)]

lemma lt_zero_iff {G : pgame} [G.impartial] : G < 0 ↔ 0 < G :=
by rw [lt_iff_neg_gt, neg_zero, lt_congr (equiv_refl 0) (neg_equiv_self G)]

lemma first_loses_symm (G : pgame) [G.impartial] : G.first_loses ↔ G ≤ 0 :=
⟨and.left, λ h, ⟨h, le_zero_iff.1 h⟩⟩

lemma first_wins_symm (G : pgame) [G.impartial] : G.first_wins ↔ G < 0 :=
⟨and.right, λ h, ⟨lt_zero_iff.1 h, h⟩⟩

lemma first_loses_symm' (G : pgame) [G.impartial] : G.first_loses ↔ 0 ≤ G :=
⟨and.right, λ h, ⟨le_zero_iff.2 h, h⟩⟩

lemma first_wins_symm' (G : pgame) [G.impartial] : G.first_wins ↔ 0 < G :=
⟨and.left, λ h, ⟨h, lt_zero_iff.2 h⟩⟩

lemma no_good_left_moves_iff_first_loses (G : pgame) [G.impartial] :
  (∀ (i : G.left_moves), (G.move_left i).first_wins) ↔ G.first_loses :=
begin
  split,
  { intro hbad,
    rw [first_loses_symm G, le_def_lt],
    split,
    { intro i,
      specialize hbad i,
      exact hbad.2 },
    { intro j,
      exact pempty.elim j } },
  { intros hp i,
    rw first_wins_symm,
    exact (le_def_lt.1 $ (first_loses_symm G).1 hp).1 i }
end

lemma no_good_right_moves_iff_first_loses (G : pgame) [G.impartial] :
  (∀ (j : G.right_moves), (G.move_right j).first_wins) ↔ G.first_loses :=
begin
  rw [first_loses_of_equiv_iff (neg_equiv_self G), ←no_good_left_moves_iff_first_loses],
  refine ⟨λ h i, _, λ h i, _⟩,
  { simpa [first_wins_of_equiv_iff (neg_equiv_self ((-G).move_left i))]
    using h (left_moves_neg _ i) },
  { simpa [first_wins_of_equiv_iff (neg_equiv_self (G.move_right i))]
      using h ((left_moves_neg _).symm i) }
end

lemma good_left_move_iff_first_wins (G : pgame) [G.impartial] :
  (∃ (i : G.left_moves), (G.move_left i).first_loses) ↔ G.first_wins :=
begin
  refine ⟨λ ⟨i, hi⟩, (first_wins_symm' G).2 (lt_def_le.2 $ or.inl ⟨i, hi.2⟩), λ hn, _⟩,
  rw [first_wins_symm' G, lt_def_le] at hn,
  rcases hn with ⟨i, hi⟩ | ⟨j, _⟩,
  { exact ⟨i, (first_loses_symm' _).2 hi⟩ },
  { exact pempty.elim j }
end

lemma good_right_move_iff_first_wins (G : pgame) [G.impartial] :
  (∃ j : G.right_moves, (G.move_right j).first_loses) ↔ G.first_wins :=
begin
  refine ⟨λ ⟨j, hj⟩, (first_wins_symm G).2 (lt_def_le.2 $ or.inr ⟨j, hj.1⟩), λ hn, _⟩,
  rw [first_wins_symm G, lt_def_le] at hn,
  rcases hn with ⟨i, _⟩ | ⟨j, hj⟩,
  { exact pempty.elim i },
  { exact ⟨j, (first_loses_symm _).2 hj⟩ }
end

end impartial
end pgame


/-
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
-/
import algebra.ordered_ring
import algebra.field
import tactic.monotonicity.basic

/-!
# Linear ordered fields

A linear ordered field is a field equipped with a linear order such that
* addition respects the order: `a ≤ b → c + a ≤ c + b`;
* multiplication of positives is positive: `0 < a → 0 < b → 0 < a * b`;
* `0 < 1`.

## Main Definitions

* `linear_ordered_field`: the class of linear ordered fields.
-/

set_option old_structure_cmd true

variable {α : Type*}

/-- A linear ordered field is a field with a linear order respecting the operations. -/
@[protect_proj] class linear_ordered_field (α : Type*) extends linear_ordered_comm_ring α, field α

section linear_ordered_field
variables [linear_ordered_field α] {a b c d e : α}

/-!
### Lemmas about pos, nonneg, nonpos, neg
-/

@[simp] lemma inv_pos : 0 < a⁻¹ ↔ 0 < a :=
suffices ∀ a : α, 0 < a → 0 < a⁻¹,
from ⟨λ h, inv_inv' a ▸ this _ h, this a⟩,
assume a ha, flip lt_of_mul_lt_mul_left ha.le $ by simp [ne_of_gt ha, zero_lt_one]

@[simp] lemma inv_nonneg : 0 ≤ a⁻¹ ↔ 0 ≤ a :=
by simp only [le_iff_eq_or_lt, inv_pos, zero_eq_inv]

@[simp] lemma inv_lt_zero : a⁻¹ < 0 ↔ a < 0 :=
by simp only [← not_le, inv_nonneg]

@[simp] lemma inv_nonpos : a⁻¹ ≤ 0 ↔ a ≤ 0 :=
by simp only [← not_lt, inv_pos]

lemma one_div_pos : 0 < 1 / a ↔ 0 < a :=
inv_eq_one_div a ▸ inv_pos

lemma one_div_neg : 1 / a < 0 ↔ a < 0 :=
inv_eq_one_div a ▸ inv_lt_zero

lemma one_div_nonneg : 0 ≤ 1 / a ↔ 0 ≤ a :=
inv_eq_one_div a ▸ inv_nonneg

lemma one_div_nonpos : 1 / a ≤ 0 ↔ a ≤ 0 :=
inv_eq_one_div a ▸ inv_nonpos

lemma div_pos_iff : 0 < a / b ↔ 0 < a ∧ 0 < b ∨ a < 0 ∧ b < 0 :=
by simp [division_def, mul_pos_iff]

lemma div_neg_iff : a / b < 0 ↔ 0 < a ∧ b < 0 ∨ a < 0 ∧ 0 < b :=
by simp [division_def, mul_neg_iff]

lemma div_nonneg_iff : 0 ≤ a / b ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 :=
by simp [division_def, mul_nonneg_iff]

lemma div_nonpos_iff : a / b ≤ 0 ↔ 0 ≤ a ∧ b ≤ 0 ∨ a ≤ 0 ∧ 0 ≤ b :=
by simp [division_def, mul_nonpos_iff]

lemma div_pos (ha : 0 < a) (hb : 0 < b) : 0 < a / b :=
div_pos_iff.2 $ or.inl ⟨ha, hb⟩

lemma div_pos_of_neg_of_neg (ha : a < 0) (hb : b < 0) : 0 < a / b :=
div_pos_iff.2 $ or.inr ⟨ha, hb⟩

lemma div_neg_of_neg_of_pos (ha : a < 0) (hb : 0 < b) : a / b < 0 :=
div_neg_iff.2 $ or.inr ⟨ha, hb⟩

lemma div_neg_of_pos_of_neg (ha : 0 < a) (hb : b < 0) : a / b < 0 :=
div_neg_iff.2 $ or.inl ⟨ha, hb⟩

lemma div_nonneg (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a / b :=
div_nonneg_iff.2 $ or.inl ⟨ha, hb⟩

lemma div_nonneg_of_nonpos (ha : a ≤ 0) (hb : b ≤ 0) : 0 ≤ a / b :=
div_nonneg_iff.2 $ or.inr ⟨ha, hb⟩

lemma div_nonpos_of_nonpos_of_nonneg (ha : a ≤ 0) (hb : 0 ≤ b) : a / b ≤ 0 :=
div_nonpos_iff.2 $ or.inr ⟨ha, hb⟩

lemma div_nonpos_of_nonneg_of_nonpos (ha : 0 ≤ a) (hb : b ≤ 0) : a / b ≤ 0 :=
div_nonpos_iff.2 $ or.inl ⟨ha, hb⟩

/-!
### Relating one division with another term.
-/

lemma le_div_iff (hc : 0 < c) : a ≤ b / c ↔ a * c ≤ b :=
⟨λ h, div_mul_cancel b (ne_of_lt hc).symm ▸ mul_le_mul_of_nonneg_right h hc.le,
  λ h, calc
    a   = a * c * (1 / c) : mul_mul_div a (ne_of_lt hc).symm
    ... ≤ b * (1 / c)     : mul_le_mul_of_nonneg_right h (one_div_pos.2 hc).le
    ... = b / c           : (div_eq_mul_one_div b c).symm⟩

lemma le_div_iff' (hc : 0 < c) : a ≤ b / c ↔ c * a ≤ b :=
by rw [mul_comm, le_div_iff hc]

lemma div_le_iff (hb : 0 < b) : a / b ≤ c ↔ a ≤ c * b :=
⟨λ h, calc
  a = a / b * b : by rw (div_mul_cancel _ (ne_of_lt hb).symm)
  ... ≤ c * b     : mul_le_mul_of_nonneg_right h hb.le,
  λ h, calc
  a / b = a * (1 / b)     : div_eq_mul_one_div a b
  ... ≤ (c * b) * (1 / b) : mul_le_mul_of_nonneg_right h (one_div_pos.2 hb).le
  ... = (c * b) / b       : (div_eq_mul_one_div (c * b) b).symm
  ... = c                 : by refine (div_eq_iff (ne_of_gt hb)).mpr rfl⟩

lemma div_le_iff' (hb : 0 < b) : a / b ≤ c ↔ a ≤ b * c :=
by rw [mul_comm, div_le_iff hb]

lemma lt_div_iff (hc : 0 < c) : a < b / c ↔ a * c < b :=
lt_iff_lt_of_le_iff_le $ div_le_iff hc

lemma lt_div_iff' (hc : 0 < c) : a < b / c ↔ c * a < b :=
by rw [mul_comm, lt_div_iff hc]

lemma div_lt_iff (hc : 0 < c) : b / c < a ↔ b < a * c :=
lt_iff_lt_of_le_iff_le (le_div_iff hc)

lemma div_lt_iff' (hc : 0 < c) : b / c < a ↔ b < c * a :=
by rw [mul_comm, div_lt_iff hc]

lemma inv_mul_le_iff (h : 0 < b) : b⁻¹ * a ≤ c ↔ a ≤ b * c :=
begin
  rw [inv_eq_one_div, mul_comm, ← div_eq_mul_one_div],
  exact div_le_iff' h,
end

lemma inv_mul_le_iff' (h : 0 < b) : b⁻¹ * a ≤ c ↔ a ≤ c * b :=
by rw [inv_mul_le_iff h, mul_comm]

lemma mul_inv_le_iff (h : 0 < b) : a * b⁻¹ ≤ c ↔ a ≤ b * c :=
by rw [mul_comm, inv_mul_le_iff h]

lemma mul_inv_le_iff' (h : 0 < b) : a * b⁻¹ ≤ c ↔ a ≤ c * b :=
by rw [mul_comm, inv_mul_le_iff' h]

lemma inv_mul_lt_iff (h : 0 < b) : b⁻¹ * a < c ↔ a < b * c :=
begin
  rw [inv_eq_one_div, mul_comm, ← div_eq_mul_one_div],
  exact div_lt_iff' h,
end

lemma inv_mul_lt_iff' (h : 0 < b) : b⁻¹ * a < c ↔ a < c * b :=
by rw [inv_mul_lt_iff h, mul_comm]

lemma mul_inv_lt_iff (h : 0 < b) : a * b⁻¹ < c ↔ a < b * c :=
by rw [mul_comm, inv_mul_lt_iff h]

lemma mul_inv_lt_iff' (h : 0 < b) : a * b⁻¹ < c ↔ a < c * b :=
by rw [mul_comm, inv_mul_lt_iff' h]

lemma inv_pos_le_iff_one_le_mul (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ b * a :=
by { rw [inv_eq_one_div], exact div_le_iff ha }

lemma inv_pos_le_iff_one_le_mul' (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ a * b :=
by { rw [inv_eq_one_div], exact div_le_iff' ha }

lemma inv_pos_lt_iff_one_lt_mul (ha : 0 < a) : a⁻¹ < b ↔ 1 < b * a :=
by { rw [inv_eq_one_div], exact div_lt_iff ha }

lemma inv_pos_lt_iff_one_lt_mul' (ha : 0 < a) : a⁻¹ < b ↔ 1 < a * b :=
by { rw [inv_eq_one_div], exact div_lt_iff' ha }

lemma div_le_iff_of_neg (hc : c < 0) : b / c ≤ a ↔ a * c ≤ b :=
⟨λ h, div_mul_cancel b (ne_of_lt hc) ▸ mul_le_mul_of_nonpos_right h hc.le,
  λ h, calc
    a = a * c * (1 / c) : mul_mul_div a (ne_of_lt hc)
  ... ≥ b * (1 / c)     : mul_le_mul_of_nonpos_right h (one_div_neg.2 hc).le
  ... = b / c           : (div_eq_mul_one_div b c).symm⟩

lemma div_le_iff_of_neg' (hc : c < 0) : b / c ≤ a ↔ c * a ≤ b :=
by rw [mul_comm, div_le_iff_of_neg hc]

lemma le_div_iff_of_neg (hc : c < 0) : a ≤ b / c ↔ b ≤ a * c :=
by rw [← neg_neg c, mul_neg_eq_neg_mul_symm, div_neg, le_neg,
    div_le_iff (neg_pos.2 hc), neg_mul_eq_neg_mul_symm]

lemma le_div_iff_of_neg' (hc : c < 0) : a ≤ b / c ↔ b ≤ c * a :=
by rw [mul_comm, le_div_iff_of_neg hc]

lemma div_lt_iff_of_neg (hc : c < 0) : b / c < a ↔ a * c < b :=
lt_iff_lt_of_le_iff_le $ le_div_iff_of_neg hc

lemma div_lt_iff_of_neg' (hc : c < 0) : b / c < a ↔ c * a < b :=
by rw [mul_comm, div_lt_iff_of_neg hc]

lemma lt_div_iff_of_neg (hc : c < 0) : a < b / c ↔ b < a * c :=
lt_iff_lt_of_le_iff_le $ div_le_iff_of_neg hc

lemma lt_div_iff_of_neg' (hc : c < 0) : a < b / c ↔ b < c * a :=
by rw [mul_comm, lt_div_iff_of_neg hc]

/-- One direction of `div_le_iff` where `b` is allowed to be `0` (but `c` must be nonnegative) -/
lemma div_le_of_nonneg_of_le_mul (hb : 0 ≤ b) (hc : 0 ≤ c) (h : a ≤ c * b) : a / b ≤ c :=
by { rcases eq_or_lt_of_le hb with rfl|hb', simp [hc], rwa [div_le_iff hb'] }

lemma div_le_one_of_le (h : a ≤ b) (hb : 0 ≤ b) : a / b ≤ 1 :=
div_le_of_nonneg_of_le_mul hb zero_le_one $ by rwa one_mul

/-!
### Bi-implications of inequalities using inversions
-/

lemma inv_le_inv_of_le (ha : 0 < a) (h : a ≤ b) : b⁻¹ ≤ a⁻¹ :=
by rwa [← one_div a, le_div_iff' ha, ← div_eq_mul_inv, div_le_iff (ha.trans_le h), one_mul]

/-- See `inv_le_inv_of_le` for the implication from right-to-left with one fewer assumption. -/
lemma inv_le_inv (ha : 0 < a) (hb : 0 < b) : a⁻¹ ≤ b⁻¹ ↔ b ≤ a :=
by rw [← one_div, div_le_iff ha, ← div_eq_inv_mul, le_div_iff hb, one_mul]

lemma inv_le (ha : 0 < a) (hb : 0 < b) : a⁻¹ ≤ b ↔ b⁻¹ ≤ a :=
by rw [← inv_le_inv hb (inv_pos.2 ha), inv_inv']

lemma le_inv (ha : 0 < a) (hb : 0 < b) : a ≤ b⁻¹ ↔ b ≤ a⁻¹ :=
by rw [← inv_le_inv (inv_pos.2 hb) ha, inv_inv']

lemma inv_lt_inv (ha : 0 < a) (hb : 0 < b) : a⁻¹ < b⁻¹ ↔ b < a :=
lt_iff_lt_of_le_iff_le (inv_le_inv hb ha)

lemma inv_lt (ha : 0 < a) (hb : 0 < b) : a⁻¹ < b ↔ b⁻¹ < a :=
lt_iff_lt_of_le_iff_le (le_inv hb ha)

lemma lt_inv (ha : 0 < a) (hb : 0 < b) : a < b⁻¹ ↔ b < a⁻¹ :=
lt_iff_lt_of_le_iff_le (inv_le hb ha)

lemma inv_le_inv_of_neg (ha : a < 0) (hb : b < 0) : a⁻¹ ≤ b⁻¹ ↔ b ≤ a :=
by rw [← one_div, div_le_iff_of_neg ha, ← div_eq_inv_mul, div_le_iff_of_neg hb, one_mul]

lemma inv_le_of_neg (ha : a < 0) (hb : b < 0) : a⁻¹ ≤ b ↔ b⁻¹ ≤ a :=
by rw [← inv_le_inv_of_neg hb (inv_lt_zero.2 ha), inv_inv']

lemma le_inv_of_neg (ha : a < 0) (hb : b < 0) : a ≤ b⁻¹ ↔ b ≤ a⁻¹ :=
by rw [← inv_le_inv_of_neg (inv_lt_zero.2 hb) ha, inv_inv']

lemma inv_lt_inv_of_neg (ha : a < 0) (hb : b < 0) : a⁻¹ < b⁻¹ ↔ b < a :=
lt_iff_lt_of_le_iff_le (inv_le_inv_of_neg hb ha)

lemma inv_lt_of_neg (ha : a < 0) (hb : b < 0) : a⁻¹ < b ↔ b⁻¹ < a :=
lt_iff_lt_of_le_iff_le (le_inv_of_neg hb ha)

lemma lt_inv_of_neg (ha : a < 0) (hb : b < 0) : a < b⁻¹ ↔ b < a⁻¹ :=
lt_iff_lt_of_le_iff_le (inv_le_of_neg hb ha)

lemma inv_lt_one (ha : 1 < a) : a⁻¹ < 1 :=
by rwa [inv_lt ((@zero_lt_one α _ _).trans ha) zero_lt_one, inv_one]

lemma one_lt_inv (h₁ : 0 < a) (h₂ : a < 1) : 1 < a⁻¹ :=
by rwa [lt_inv (@zero_lt_one α _ _) h₁, inv_one]

lemma inv_le_one (ha : 1 ≤ a) : a⁻¹ ≤ 1 :=
by rwa [inv_le ((@zero_lt_one α _ _).trans_le ha) zero_lt_one, inv_one]

lemma one_le_inv (h₁ : 0 < a) (h₂ : a ≤ 1) : 1 ≤ a⁻¹ :=
by rwa [le_inv (@zero_lt_one α _ _) h₁, inv_one]

lemma inv_lt_one_iff_of_pos (h₀ : 0 < a) : a⁻¹ < 1 ↔ 1 < a :=
⟨λ h₁, inv_inv' a ▸ one_lt_inv (inv_pos.2 h₀) h₁, inv_lt_one⟩

lemma inv_lt_one_iff : a⁻¹ < 1 ↔ a ≤ 0 ∨ 1 < a :=
begin
  cases le_or_lt a 0 with ha ha,
  { simp [ha, (inv_nonpos.2 ha).trans_lt zero_lt_one] },
  { simp only [ha.not_le, false_or, inv_lt_one_iff_of_pos ha] }
end

lemma one_lt_inv_iff : 1 < a⁻¹ ↔ 0 < a ∧ a < 1 :=
⟨λ h, ⟨inv_pos.1 (zero_lt_one.trans h), inv_inv' a ▸ inv_lt_one h⟩, and_imp.2 one_lt_inv⟩

lemma inv_le_one_iff : a⁻¹ ≤ 1 ↔ a ≤ 0 ∨ 1 ≤ a :=
begin
  rcases em (a = 1) with (rfl|ha),
  { simp [le_rfl] },
  { simp only [ne.le_iff_lt (ne.symm ha), ne.le_iff_lt (mt inv_eq_one'.1 ha), inv_lt_one_iff] }
end

lemma one_le_inv_iff : 1 ≤ a⁻¹ ↔ 0 < a ∧ a ≤ 1 :=
⟨λ h, ⟨inv_pos.1 (zero_lt_one.trans_le h), inv_inv' a ▸ inv_le_one h⟩, and_imp.2 one_le_inv⟩

/-!
### Relating two divisions.
-/

@[mono] lemma div_le_div_of_le (hc : 0 ≤ c) (h : a ≤ b) : a / c ≤ b / c :=
begin
  rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c],
  exact mul_le_mul_of_nonneg_right h (one_div_nonneg.2 hc)
end

@[mono] lemma div_le_div_of_le_left (ha : 0 ≤ a) (hc : 0 < c) (h : c ≤ b) : a / b ≤ a / c :=
begin
  rw [div_eq_mul_inv, div_eq_mul_inv],
  exact mul_le_mul_of_nonneg_left ((inv_le_inv (hc.trans_le h) hc).mpr h) ha
end

lemma div_le_div_of_le_of_nonneg (hab : a ≤ b) (hc : 0 ≤ c) : a / c ≤ b / c :=
div_le_div_of_le hc hab

lemma div_le_div_of_nonpos_of_le (hc : c ≤ 0) (h : b ≤ a) : a / c ≤ b / c :=
begin
  rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c],
  exact mul_le_mul_of_nonpos_right h (one_div_nonpos.2 hc)
end

lemma div_lt_div_of_lt (hc : 0 < c) (h : a < b) : a / c < b / c :=
begin
  rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c],
  exact mul_lt_mul_of_pos_right h (one_div_pos.2 hc)
end

lemma div_lt_div_of_neg_of_lt (hc : c < 0) (h : b < a) : a / c < b / c :=
begin
  rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c],
  exact mul_lt_mul_of_neg_right h (one_div_neg.2 hc)
end

lemma div_le_div_right (hc : 0 < c) : a / c ≤ b / c ↔ a ≤ b :=
⟨le_imp_le_of_lt_imp_lt $ div_lt_div_of_lt hc, div_le_div_of_le $ hc.le⟩

lemma div_le_div_right_of_neg (hc : c < 0) : a / c ≤ b / c ↔ b ≤ a :=
⟨le_imp_le_of_lt_imp_lt $ div_lt_div_of_neg_of_lt hc, div_le_div_of_nonpos_of_le $ hc.le⟩

lemma div_lt_div_right (hc : 0 < c) : a / c < b / c ↔ a < b :=
lt_iff_lt_of_le_iff_le $ div_le_div_right hc

lemma div_lt_div_right_of_neg (hc : c < 0) : a / c < b / c ↔ b < a :=
lt_iff_lt_of_le_iff_le $ div_le_div_right_of_neg hc

lemma div_lt_div_left (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : a / b < a / c ↔ c < b :=
by simp only [div_eq_mul_inv, mul_lt_mul_left ha, inv_lt_inv hb hc]

lemma div_le_div_left (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : a / b ≤ a / c ↔ c ≤ b :=
le_iff_le_iff_lt_iff_lt.2 (div_lt_div_left ha hc hb)

lemma div_lt_div_iff (b0 : 0 < b) (d0 : 0 < d) :
  a / b < c / d ↔ a * d < c * b :=
by rw [lt_div_iff d0, div_mul_eq_mul_div, div_lt_iff b0]

lemma div_le_div_iff (b0 : 0 < b) (d0 : 0 < d) : a / b ≤ c / d ↔ a * d ≤ c * b :=
by rw [le_div_iff d0, div_mul_eq_mul_div, div_le_iff b0]

@[mono] lemma div_le_div (hc : 0 ≤ c) (hac : a ≤ c) (hd : 0 < d) (hbd : d ≤ b) : a / b ≤ c / d :=
by { rw div_le_div_iff (hd.trans_le hbd) hd, exact mul_le_mul hac hbd hd.le hc }

lemma div_lt_div (hac : a < c) (hbd : d ≤ b) (c0 : 0 ≤ c) (d0 : 0 < d) :
  a / b < c / d :=
(div_lt_div_iff (d0.trans_le hbd) d0).2 (mul_lt_mul hac hbd d0 c0)

lemma div_lt_div' (hac : a ≤ c) (hbd : d < b) (c0 : 0 < c) (d0 : 0 < d) :
  a / b < c / d :=
(div_lt_div_iff (d0.trans hbd) d0).2 (mul_lt_mul' hac hbd d0.le c0)

lemma div_lt_div_of_lt_left (hb : 0 < b) (h : b < a) (hc : 0 < c) : c / a < c / b :=
(div_lt_div_left hc (hb.trans h) hb).mpr h

/-!
### Relating one division and involving `1`
-/

lemma one_le_div (hb : 0 < b) : 1 ≤ a / b ↔ b ≤ a :=
by rw [le_div_iff hb, one_mul]

lemma div_le_one (hb : 0 < b) : a / b ≤ 1 ↔ a ≤ b :=
by rw [div_le_iff hb, one_mul]

lemma one_lt_div (hb : 0 < b) : 1 < a / b ↔ b < a :=
by rw [lt_div_iff hb, one_mul]

lemma div_lt_one (hb : 0 < b) : a / b < 1 ↔ a < b :=
by rw [div_lt_iff hb, one_mul]

lemma one_le_div_of_neg (hb : b < 0) : 1 ≤ a / b ↔ a ≤ b :=
by rw [le_div_iff_of_neg hb, one_mul]

lemma div_le_one_of_neg (hb : b < 0) : a / b ≤ 1 ↔ b ≤ a :=
by rw [div_le_iff_of_neg hb, one_mul]

lemma one_lt_div_of_neg (hb : b < 0) : 1 < a / b ↔ a < b :=
by rw [lt_div_iff_of_neg hb, one_mul]

lemma div_lt_one_of_neg (hb : b < 0) : a / b < 1 ↔ b < a :=
by rw [div_lt_iff_of_neg hb, one_mul]

lemma one_div_le (ha : 0 < a) (hb : 0 < b) : 1 / a ≤ b ↔ 1 / b ≤ a :=
by simpa using inv_le ha hb

lemma one_div_lt (ha : 0 < a) (hb : 0 < b) : 1 / a < b ↔ 1 / b < a :=
by simpa using inv_lt ha hb

lemma le_one_div (ha : 0 < a) (hb : 0 < b) : a ≤ 1 / b ↔ b ≤ 1 / a :=
by simpa using le_inv ha hb

lemma lt_one_div (ha : 0 < a) (hb : 0 < b) : a < 1 / b ↔ b < 1 / a :=
by simpa using lt_inv ha hb

lemma one_div_le_of_neg (ha : a < 0) (hb : b < 0) : 1 / a ≤ b ↔ 1 / b ≤ a :=
by simpa using inv_le_of_neg ha hb

lemma one_div_lt_of_neg (ha : a < 0) (hb : b < 0) : 1 / a < b ↔ 1 / b < a :=
by simpa using inv_lt_of_neg ha hb

lemma le_one_div_of_neg (ha : a < 0) (hb : b < 0) : a ≤ 1 / b ↔ b ≤ 1 / a :=
by simpa using le_inv_of_neg ha hb

lemma lt_one_div_of_neg (ha : a < 0) (hb : b < 0) : a < 1 / b ↔ b < 1 / a :=
by simpa using lt_inv_of_neg ha hb

lemma one_lt_div_iff : 1 < a / b ↔ 0 < b ∧ b < a ∨ b < 0 ∧ a < b :=
begin
  rcases lt_trichotomy b 0 with (hb|rfl|hb),
  { simp [hb, hb.not_lt, one_lt_div_of_neg] },
  { simp [lt_irrefl, zero_le_one] },
  { simp [hb, hb.not_lt, one_lt_div] }
end

lemma one_le_div_iff : 1 ≤ a / b ↔ 0 < b ∧ b ≤ a ∨ b < 0 ∧ a ≤ b :=
begin
  rcases lt_trichotomy b 0 with (hb|rfl|hb),
  { simp [hb, hb.not_lt, one_le_div_of_neg] },
  { simp [lt_irrefl, zero_lt_one.not_le, zero_lt_one] },
  { simp [hb, hb.not_lt, one_le_div] }
end

lemma div_lt_one_iff : a / b < 1 ↔ 0 < b ∧ a < b ∨ b = 0 ∨ b < 0 ∧ b < a :=
begin
  rcases lt_trichotomy b 0 with (hb|rfl|hb),
  { simp [hb, hb.not_lt, hb.ne, div_lt_one_of_neg] },
  { simp [zero_lt_one], },
  { simp [hb, hb.not_lt, div_lt_one, hb.ne.symm] }
end

lemma div_le_one_iff : a / b ≤ 1 ↔ 0 < b ∧ a ≤ b ∨ b = 0 ∨ b < 0 ∧ b ≤ a :=
begin
  rcases lt_trichotomy b 0 with (hb|rfl|hb),
  { simp [hb, hb.not_lt, hb.ne, div_le_one_of_neg] },
  { simp [zero_le_one], },
  { simp [hb, hb.not_lt, div_le_one, hb.ne.symm] }
end

/-!
### Relating two divisions, involving `1`
-/
lemma one_div_le_one_div_of_le (ha : 0 < a) (h : a ≤ b) : 1 / b ≤ 1 / a :=
by simpa using inv_le_inv_of_le ha h

lemma one_div_lt_one_div_of_lt (ha : 0 < a) (h : a < b) : 1 / b < 1 / a :=
by rwa [lt_div_iff' ha, ← div_eq_mul_one_div, div_lt_one (ha.trans h)]

lemma one_div_le_one_div_of_neg_of_le (hb : b < 0) (h : a ≤ b) : 1 / b ≤ 1 / a :=
by rwa [div_le_iff_of_neg' hb, ← div_eq_mul_one_div, div_le_one_of_neg (h.trans_lt hb)]

lemma one_div_lt_one_div_of_neg_of_lt (hb : b < 0) (h : a < b) : 1 / b < 1 / a :=
by rwa [div_lt_iff_of_neg' hb, ← div_eq_mul_one_div, div_lt_one_of_neg (h.trans hb)]

lemma le_of_one_div_le_one_div (ha : 0 < a) (h : 1 / a ≤ 1 / b) : b ≤ a :=
le_imp_le_of_lt_imp_lt (one_div_lt_one_div_of_lt ha) h

lemma lt_of_one_div_lt_one_div (ha : 0 < a) (h : 1 / a < 1 / b) : b < a :=
lt_imp_lt_of_le_imp_le (one_div_le_one_div_of_le ha) h

lemma le_of_neg_of_one_div_le_one_div (hb : b < 0) (h : 1 / a ≤ 1 / b) : b ≤ a :=
le_imp_le_of_lt_imp_lt (one_div_lt_one_div_of_neg_of_lt hb) h

lemma lt_of_neg_of_one_div_lt_one_div (hb : b < 0) (h : 1 / a < 1 / b) : b < a :=
lt_imp_lt_of_le_imp_le (one_div_le_one_div_of_neg_of_le hb) h

/-- For the single implications with fewer assumptions, see `one_div_le_one_div_of_le` and
  `le_of_one_div_le_one_div` -/
lemma one_div_le_one_div (ha : 0 < a) (hb : 0 < b) : 1 / a ≤ 1 / b ↔ b ≤ a :=
div_le_div_left zero_lt_one ha hb

/-- For the single implications with fewer assumptions, see `one_div_lt_one_div_of_lt` and
  `lt_of_one_div_lt_one_div` -/
lemma one_div_lt_one_div (ha : 0 < a) (hb : 0 < b) : 1 / a < 1 / b ↔ b < a :=
div_lt_div_left zero_lt_one ha hb

/-- For the single implications with fewer assumptions, see `one_div_lt_one_div_of_neg_of_lt` and
  `lt_of_one_div_lt_one_div` -/
lemma one_div_le_one_div_of_neg (ha : a < 0) (hb : b < 0) : 1 / a ≤ 1 / b ↔ b ≤ a :=
by simpa [one_div] using inv_le_inv_of_neg ha hb

/-- For the single implications with fewer assumptions, see `one_div_lt_one_div_of_lt` and
  `lt_of_one_div_lt_one_div` -/
lemma one_div_lt_one_div_of_neg (ha : a < 0) (hb : b < 0) : 1 / a < 1 / b ↔ b < a :=
lt_iff_lt_of_le_iff_le (one_div_le_one_div_of_neg hb ha)

lemma one_lt_one_div (h1 : 0 < a) (h2 : a < 1) : 1 < 1 / a :=
by rwa [lt_one_div (@zero_lt_one α _ _) h1, one_div_one]

lemma one_le_one_div (h1 : 0 < a) (h2 : a ≤ 1) : 1 ≤ 1 / a :=
by rwa [le_one_div (@zero_lt_one α _ _) h1, one_div_one]

lemma one_div_lt_neg_one (h1 : a < 0) (h2 : -1 < a) : 1 / a < -1 :=
suffices 1 / a < 1 / -1, by rwa one_div_neg_one_eq_neg_one at this,
one_div_lt_one_div_of_neg_of_lt h1 h2

lemma one_div_le_neg_one (h1 : a < 0) (h2 : -1 ≤ a) : 1 / a ≤ -1 :=
suffices 1 / a ≤ 1 / -1, by rwa one_div_neg_one_eq_neg_one at this,
one_div_le_one_div_of_neg_of_le h1 h2

/-!
### Results about halving.

The equalities also hold in fields of characteristic `0`. -/
lemma add_halves (a : α) : a / 2 + a / 2 = a :=
by rw [div_add_div_same, ← two_mul, mul_div_cancel_left a two_ne_zero]

lemma sub_self_div_two (a : α) : a - a / 2 = a / 2 :=
suffices a / 2 + a / 2 - a / 2 = a / 2, by rwa add_halves at this,
by rw [add_sub_cancel]

lemma div_two_sub_self (a : α) : a / 2 - a = - (a / 2) :=
suffices a / 2 - (a / 2 + a / 2) = - (a / 2), by rwa add_halves at this,
by rw [sub_add_eq_sub_sub, sub_self, zero_sub]

lemma add_self_div_two (a : α) : (a + a) / 2 = a :=
by rw [← mul_two, mul_div_cancel a two_ne_zero]

lemma half_pos (h : 0 < a) : 0 < a / 2 := div_pos h zero_lt_two

lemma one_half_pos : (0:α) < 1 / 2 := half_pos zero_lt_one

lemma div_two_lt_of_pos (h : 0 < a) : a / 2 < a :=
by { rw [div_lt_iff (@zero_lt_two α _ _)], exact lt_mul_of_one_lt_right h one_lt_two }

lemma half_lt_self : 0 < a → a / 2 < a := div_two_lt_of_pos

lemma half_le_self (ha_nonneg : 0 ≤ a) : a / 2 ≤ a :=
begin
  by_cases h0 : a = 0,
  { simp [h0], },
  { rw ← ne.def at h0,
    exact (half_lt_self (lt_of_le_of_ne ha_nonneg h0.symm)).le, },
end

lemma one_half_lt_one : (1 / 2 : α) < 1 := half_lt_self zero_lt_one

lemma add_sub_div_two_lt (h : a < b) : a + (b - a) / 2 < b :=
begin
  rwa [← div_sub_div_same, sub_eq_add_neg, add_comm (b/2), ← add_assoc, ← sub_eq_add_neg,
    ← lt_sub_iff_add_lt, sub_self_div_two, sub_self_div_two, div_lt_div_right (@zero_lt_two α _ _)]
end

/-!
### Miscellaneous lemmas
-/

/-- Pullback a `linear_ordered_field` under an injective map. -/
def function.injective.linear_ordered_field {β : Type*}
  [has_zero β] [has_one β] [has_add β] [has_mul β] [has_neg β] [has_sub β] [has_inv β] [has_div β]
  [nontrivial β]
  (f : β → α) (hf : function.injective f) (zero : f 0 = 0) (one : f 1 = 1)
  (add : ∀ x y, f (x + y) = f x + f y) (mul : ∀ x y, f (x * y) = f x * f y)
  (neg : ∀ x, f (-x) = -f x) (sub : ∀ x y, f (x - y) = f x - f y)
  (inv : ∀ x, f (x⁻¹) = (f x)⁻¹) (div : ∀ x y, f (x / y) = f x / f y) :
  linear_ordered_field β :=
{ ..hf.linear_ordered_ring f zero one add mul neg sub,
  ..hf.field f zero one add mul neg sub inv div}

lemma mul_sub_mul_div_mul_neg_iff (hc : c ≠ 0) (hd : d ≠ 0) :
  (a * d - b * c) / (c * d) < 0 ↔ a / c < b / d :=
by rw [mul_comm b c, ← div_sub_div _ _ hc hd, sub_lt_zero]

alias mul_sub_mul_div_mul_neg_iff ↔ div_lt_div_of_mul_sub_mul_div_neg mul_sub_mul_div_mul_neg

lemma mul_sub_mul_div_mul_nonpos_iff (hc : c ≠ 0) (hd : d ≠ 0) :
      (a * d - b * c) / (c * d) ≤ 0 ↔ a / c ≤ b / d :=
by rw [mul_comm b c, ← div_sub_div _ _ hc hd, sub_nonpos]

alias mul_sub_mul_div_mul_nonpos_iff ↔
  div_le_div_of_mul_sub_mul_div_nonpos mul_sub_mul_div_mul_nonpos

lemma mul_le_mul_of_mul_div_le (h : a * (b / c) ≤ d) (hc : 0 < c) : b * a ≤ d * c :=
begin
  rw [← mul_div_assoc] at h,
  rwa [mul_comm b, ← div_le_iff hc],
end

lemma div_mul_le_div_mul_of_div_le_div (h : a / b ≤ c / d) (he : 0 ≤ e) :
  a / (b * e) ≤ c / (d * e) :=
begin
  rw [div_mul_eq_div_mul_one_div, div_mul_eq_div_mul_one_div],
  exact mul_le_mul_of_nonneg_right h (one_div_nonneg.2 he)
end

lemma exists_add_lt_and_pos_of_lt (h : b < a) : ∃ c : α, b + c < a ∧ 0 < c :=
⟨(a - b) / 2, add_sub_div_two_lt h, div_pos (sub_pos_of_lt h) zero_lt_two⟩

lemma le_of_forall_sub_le (h : ∀ ε > 0, b - ε ≤ a) : b ≤ a :=
begin
  contrapose! h,
  simpa only [and_comm ((0 : α) < _), lt_sub_iff_add_lt, gt_iff_lt]
    using exists_add_lt_and_pos_of_lt h,
end

lemma monotone.div_const {β : Type*} [preorder β] {f : β → α} (hf : monotone f)
  {c : α} (hc : 0 ≤ c) : monotone (λ x, (f x) / c) :=
by simpa only [div_eq_mul_inv] using hf.mul_const (inv_nonneg.2 hc)

lemma strict_mono.div_const {β : Type*} [preorder β] {f : β → α} (hf : strict_mono f)
  {c : α} (hc : 0 < c) :
  strict_mono (λ x, (f x) / c) :=
by simpa only [div_eq_mul_inv] using hf.mul_const (inv_pos.2 hc)

@[priority 100] -- see Note [lower instance priority]
instance linear_ordered_field.to_densely_ordered : densely_ordered α :=
{ dense := λ a₁ a₂ h, ⟨(a₁ + a₂) / 2,
  calc a₁ = (a₁ + a₁) / 2 : (add_self_div_two a₁).symm
      ... < (a₁ + a₂) / 2 : div_lt_div_of_lt zero_lt_two (add_lt_add_left h _),
  calc (a₁ + a₂) / 2 < (a₂ + a₂) / 2 : div_lt_div_of_lt zero_lt_two (add_lt_add_right h _)
                 ... = a₂            : add_self_div_two a₂⟩ }

lemma mul_self_inj_of_nonneg (a0 : 0 ≤ a) (b0 : 0 ≤ b) : a * a = b * b ↔ a = b :=
mul_self_eq_mul_self_iff.trans $ or_iff_left_of_imp $
  λ h, by { subst a, have : b = 0 := le_antisymm (neg_nonneg.1 a0) b0, rw [this, neg_zero] }

lemma min_div_div_right {c : α} (hc : 0 ≤ c) (a b : α) : min (a / c) (b / c) = (min a b) / c :=
eq.symm $ monotone.map_min (λ x y, div_le_div_of_le hc)

lemma max_div_div_right {c : α} (hc : 0 ≤ c) (a b : α) : max (a / c) (b / c) = (max a b) / c :=
eq.symm $ monotone.map_max (λ x y, div_le_div_of_le hc)

lemma min_div_div_right_of_nonpos {c : α} (hc : c ≤ 0) (a b : α) :
  min (a / c) (b / c) = (max a b) / c :=
eq.symm $ @monotone.map_max α (order_dual α) _ _ _ _ _ (λ x y, div_le_div_of_nonpos_of_le hc)

lemma max_div_div_right_of_nonpos {c : α} (hc : c ≤ 0) (a b : α) :
  max (a / c) (b / c) = (min a b) / c :=
eq.symm $ @monotone.map_min α (order_dual α) _ _ _ _ _ (λ x y, div_le_div_of_nonpos_of_le hc)

lemma abs_div (a b : α) : abs (a / b) = abs a / abs b :=
(abs_hom : monoid_with_zero_hom α α).map_div a b

lemma abs_one_div (a : α) : abs (1 / a) = 1 / abs a :=
by rw [abs_div, abs_one]

lemma abs_inv (a : α) : abs a⁻¹ = (abs a)⁻¹ :=
(abs_hom : monoid_with_zero_hom α α).map_inv' a

end linear_ordered_field


import measure_theory.interval_integral
import analysis.calculus.mean_value

noncomputable theory

open measure_theory set classical filter topological_space
open interval_integral

open_locale classical topological_space filter

variables {E : Type*} [measurable_space E] [normed_group E]
                      [second_countable_topology E] [complete_space E]
                      [normed_space ℝ E] [borel_space E]
variables {f : ℝ → ℝ} {a b : ℝ}
variables {f' g : ℝ → ℝ}

-- Two cts functions with the same derivative in an interval and same initial
-- value coincide in the whole interval.
theorem eq_of_deriv_eq
  (contf : continuous_on f (Icc a b))
  (contg : continuous_on g (Icc a b))
  (hfderiv : ∀ x ∈ Ico a b, has_deriv_within_at f (f' x) (Ioi x) x)
  (hgderiv : ∀ x ∈ Ico a b, has_deriv_within_at g (f' x) (Ioi x) x)
  (hi : f a = g a) :
  ∀ y ∈ Ico a b, f y = g y :=
begin
  have hzero : ∀ z ∈ Ico a b, has_deriv_within_at (f - g) 0 (Ioi z) z,
  { intros z hz,
    convert has_deriv_within_at.sub (hfderiv z hz) (hgderiv z hz),
    rw sub_self, },
  have hbound : ∀ z ∈ Ico a b, ∥(0 : ℝ)∥ ≤ 0
    := λ _ _, by rw norm_le_zero_iff,
  intros y hy,
  have hnormle := norm_image_sub_le_of_norm_deriv_right_le_segment
    (contf.sub contg) hzero hbound y (mem_Icc_of_Ico hy),
  simpa [zero_mul, norm_le_zero_iff, sub_eq_zero, sub_eq_zero.mpr hi] using hnormle,
end

-- Has derivative from the right.
lemma deriv_integral_right
  (contf' : continuous f')
  (derivf : ∀ x ∈ Ico a b, has_deriv_within_at f (f' x) (Ioi x) x)
  (intgf' : ∀ x ∈ Icc a b, interval_integrable f' volume a x) :
  ∀ x ∈ Ico a b,
  has_deriv_within_at (λ u, ∫ y in a..u, f' y) (f' x) (Ioi x) x :=
begin
  intros x hx,
  have intgf'r := intgf' x (mem_Icc_of_Ico hx),
  have hderivci := @integral_has_deriv_within_at_right
    _ _ _ _ _ _ _ _ _ _ intgf'r _ _ (FTC_filter.nhds_right x)
    (continuous.continuous_within_at contf'),
  have hderivxb := has_deriv_within_at.mono hderivci (@Icc_subset_Ici_self _ _ x b),
  refine has_deriv_within_at.nhds_within hderivxb _,
  apply Icc_mem_nhds_within_Ioi,
  exact ⟨le_refl x, hx.2⟩,
end

-- Benjamin's lemma. We should put it and versions of it in mathlib.
lemma integral_sub_at_right
  (a c d : ℝ)
  (h1 : interval_integrable f' volume a d)
  (h2 : interval_integrable f' volume a c) :
  (∫ (y : ℝ) in a..d, f' y) - ∫ (y : ℝ) in a..c, f' y = ∫ (y : ℝ) in c..d, f' y :=
by rw [integral_interval_sub_interval_comm' h1 h2
      (interval_integrable.refl (interval_integrable.measurable h1)), integral_same, sub_zero]

-- TODO: Move
lemma eventually_le_of_eq {α β : Type*} [preorder β] (l : filter α) (f g : α → β) (h : f =ᶠ[l] g)
: f ≤ᶠ[l] g :=
eventually_le.congr (eventually_le.refl _ _) (eventually_eq.refl _ _) h

-- Second part of the Fundamental Theorem of Calculus.
theorem ftc2
  (contf : continuous_on f (Icc a b))
  (contf' : continuous f')
  (derivf : ∀ x ∈ Ico a b, has_deriv_within_at f (f' x) (Ioi x) x)
  (intgf' : ∀ x ∈ Icc a b, interval_integrable f' volume a x) :
  ∀ x ∈ Ico a b, ∫ y in a..x, f' y = f x - f a :=
begin
    intros x hx,
    by_cases hab : b < a,
    { have hc := lt_of_le_of_lt hx.1 (lt_trans hx.2 hab),
      exfalso, exact lt_irrefl _ hc, },
    -- We know a ≤ b.
    replace hab := le_of_not_lt hab,
    have hbab : b ∈ Icc a b := ⟨hab, le_refl b⟩,
    -- Needed to apply extreme value theorem.
    have hneab := nonempty_Icc.2 hab,
    have hcmpab := @compact_Icc a b,
    have hctsnorm : continuous_on (λ x, ∥f' x∥) (Icc a b),
    { apply continuous.continuous_on,
      exact continuous.norm contf', },
    have hfbdd := is_compact.exists_forall_ge hcmpab hneab hctsnorm,
    apply eq_sub_of_add_eq, symmetry,
    -- Derivative of integral of the derivative is the derivative.
    have derivint : ∀ z ∈ Ico a b,
      has_deriv_within_at (λ u, (∫ y in a..u, f' y) + f a) (f' z) (Ioi z) z,
    { intros y hy, apply has_deriv_within_at.add_const,
      exact (deriv_integral_right contf' derivf intgf' y hy), },
    -- Ready to apply main result. Only thing missing is continuity.
    refine (eq_of_deriv_eq contf _ derivf derivint _) x hx,
    { refine continuous_on.add _ continuous_on_const,
      rcases hfbdd with ⟨z, hzab, hzbd⟩,
      by_cases hfz : ∥f' z∥ ≤ 0,
      { -- If it is nonpositive, the function is zero on [a, b] and everything follows.
        replace hfz := le_antisymm hfz (norm_nonneg (f' z)),
        have hzero : ∀ y ∈ Icc a b, f' y = 0,
        { intros y hy, apply norm_le_zero_iff.1,
          specialize hzbd y hy, dsimp at hzbd,
          rw hfz at hzbd, exact hzbd, },
        have hrestrictint : restrict (λ x, ∫ y in a..x, f' y) (Icc a b) = λ x, 0,
        { funext v, show ∫ y in a..v.val, f' y = 0,
          have eventzero : f' =ᵐ[volume.restrict (Ioc a v.val)] 0,
          { rw eventually_eq_iff_exists_mem, use [Ioc a v.val], split,
            { simp, use univ, split,
              { show volume univᶜ = 0, rw compl_univ, simp, },
              { use [Ioc a v.val], split,
                { exact subset.refl _, },
                { erw [univ_inter _], exact subset.refl _, }, }, },
            { intros w hw,
              rw [hzero w ⟨le_of_lt hw.1, le_trans hw.2 v.2.2⟩], refl, }, },
          rw integral_eq_zero_iff_of_le_of_nonneg_ae v.2.1,
          { exact eventzero, },
          { apply @eventually_le.congr _ _ _ _ 0 0 0 f',
            { exact eventually_le.refl _ _, },
            { exact eventually_eq.refl _ _, },
            { exact (eventually_eq.symm eventzero), }, },
          { exact (intgf' v.1 v.2), }, },
        rw continuous_on_iff_continuous_restrict,
        erw hrestrictint, exact continuous_const, },
      replace hfz := lt_of_not_ge hfz,
      -- Prove from first principles...
      rw metric.continuous_on_iff, intros c hc ε hε,
      -- Choose appropriate δ.
      let δ := ε / ∥f' z∥,
      have hδ : 0 < δ := div_pos hε hfz,
      use [δ, hδ], intros d hd hdist, rw [dist_eq_norm],
      calc ∥(∫ (y : ℝ) in a..d, f' y) - ∫ (y : ℝ) in a..c, f' y∥
          -- Apply subtraction lemma.
          = ∥∫ (y : ℝ) in c..d, f' y∥
          : begin
              apply congr_arg norm,
              exact (integral_sub_at_right a c d (intgf' d hd) (intgf' c hc)),
            end
            -- Since the norm of f' is bounded, its integral is bounded.
      ... ≤ ∥f' z∥ * abs (d - c)
          : begin
              apply interval_integral.norm_integral_le_of_norm_le_const,
              intros w hw, by_cases hcd : c ≤ d,
              { rw [min_eq_left hcd, max_eq_right hcd] at hw,
                have haw : a ≤ w := le_of_lt (lt_of_le_of_lt hc.1 hw.1),
                have hwb : w ≤ b := le_trans hw.2 hd.2,
                exact hzbd w ⟨haw, hwb⟩, },
              { replace hcd := le_of_not_le hcd,
                rw [min_eq_right hcd, max_eq_left hcd] at hw,
                have haw : a ≤ w := le_of_lt (lt_of_le_of_lt hd.1 hw.1),
                have hwb : w ≤ b := le_trans hw.2 hc.2,
                exact hzbd w ⟨haw, hwb⟩, },
            end
            -- abs is just dist.
      ... = ∥f' z∥ * dist d c
          : by rw [dist_eq_norm, real.norm_eq_abs (d - c), abs_sub d c]
            -- dist is less than δ by assumption.
      ... < ∥f' z∥ * δ
          : mul_lt_mul_of_pos_left hdist hfz
            -- and it was convenientyly chosen so that the whole thing is less than ε.
      ... = ε
          : begin
              erw ←mul_div_assoc,
              exact mul_div_cancel_left ε (ne_of_gt hfz),
            end, },
    { simp only [integral_same, zero_add], },
end