/-
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Johannes Hölzl
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.algebra.ordered_monoid
import Mathlib.PostPort

universes u l u_1 u_2

namespace Mathlib

/-!
# Ordered groups

This file develops the basics of ordered groups.

## Implementation details

Unfortunately, the number of `'` appended to lemmas in this file
may differ between the multiplicative and the additive version of a lemma.
The reason is that we did not want to change existing names in the library.

-/

/-- An ordered additive commutative group is an additive commutative group
with a partial order in which addition is strictly monotone. -/
class ordered_add_comm_group (α : Type u)
extends partial_order α, add_comm_group α
where
  add_le_add_left : ∀ (a b : α), a ≤ b → ∀ (c : α), c + a ≤ c + b

/-- An ordered commutative group is an commutative group
with a partial order in which multiplication is strictly monotone. -/
class ordered_comm_group (α : Type u)
extends comm_group α, partial_order α
where
  mul_le_mul_left : ∀ (a b : α), a ≤ b → ∀ (c : α), c * a ≤ c * b

/--The units of an ordered commutative monoid form an ordered commutative group. -/
protected instance add_units.ordered_add_comm_group {α : Type u} [ordered_add_comm_monoid α] : ordered_add_comm_group (add_units α) :=
  ordered_add_comm_group.mk add_comm_group.add sorry add_comm_group.zero sorry sorry add_comm_group.neg add_comm_group.sub
    sorry sorry partial_order.le partial_order.lt sorry sorry sorry sorry

theorem ordered_comm_group.mul_lt_mul_left' {α : Type u} [ordered_comm_group α] (a : α) (b : α) (h : a < b) (c : α) : c * a < c * b := sorry

theorem ordered_comm_group.le_of_mul_le_mul_left {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} (h : a * b ≤ a * c) : b ≤ c := sorry

theorem ordered_comm_group.lt_of_mul_lt_mul_left {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} (h : a * b < a * c) : b < c := sorry

protected instance ordered_add_comm_group.to_ordered_cancel_add_comm_monoid (α : Type u) [s : ordered_add_comm_group α] : ordered_cancel_add_comm_monoid α :=
  ordered_cancel_add_comm_monoid.mk ordered_add_comm_group.add ordered_add_comm_group.add_assoc sorry
    ordered_add_comm_group.zero ordered_add_comm_group.zero_add ordered_add_comm_group.add_zero
    ordered_add_comm_group.add_comm sorry ordered_add_comm_group.le ordered_add_comm_group.lt
    ordered_add_comm_group.le_refl ordered_add_comm_group.le_trans ordered_add_comm_group.le_antisymm
    ordered_add_comm_group.add_le_add_left ordered_add_comm_group.le_of_add_le_add_left

theorem neg_le_neg {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} (h : a ≤ b) : -b ≤ -a := sorry

theorem le_of_inv_le_inv {α : Type u} [ordered_comm_group α] {a : α} {b : α} (h : b⁻¹ ≤ (a⁻¹)) : a ≤ b := sorry

theorem one_le_of_inv_le_one {α : Type u} [ordered_comm_group α] {a : α} (h : a⁻¹ ≤ 1) : 1 ≤ a :=
  (fun (this : a⁻¹ ≤ (1⁻¹)) => le_of_inv_le_inv this) (eq.mpr (id (Eq._oldrec (Eq.refl (a⁻¹ ≤ (1⁻¹))) one_inv)) h)

theorem inv_le_one_of_one_le {α : Type u} [ordered_comm_group α] {a : α} (h : 1 ≤ a) : a⁻¹ ≤ 1 :=
  (fun (this : a⁻¹ ≤ (1⁻¹)) => eq.mp (Eq._oldrec (Eq.refl (a⁻¹ ≤ (1⁻¹))) one_inv) this) (inv_le_inv' h)

theorem le_one_of_one_le_inv {α : Type u} [ordered_comm_group α] {a : α} (h : 1 ≤ (a⁻¹)) : a ≤ 1 :=
  (fun (this : 1⁻¹ ≤ (a⁻¹)) => le_of_inv_le_inv this) (eq.mpr (id (Eq._oldrec (Eq.refl (1⁻¹ ≤ (a⁻¹))) one_inv)) h)

theorem neg_nonneg_of_nonpos {α : Type u} [ordered_add_comm_group α] {a : α} (h : a ≤ 0) : 0 ≤ -a :=
  (fun (this : -0 ≤ -a) => eq.mp (Eq._oldrec (Eq.refl (-0 ≤ -a)) neg_zero) this) (neg_le_neg h)

theorem neg_lt_neg {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} (h : a < b) : -b < -a := sorry

theorem lt_of_neg_lt_neg {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} (h : -b < -a) : a < b :=
  neg_neg a ▸ neg_neg b ▸ neg_lt_neg h

theorem pos_of_neg_neg {α : Type u} [ordered_add_comm_group α] {a : α} (h : -a < 0) : 0 < a :=
  (fun (this : -a < -0) => lt_of_neg_lt_neg this) (eq.mpr (id (Eq._oldrec (Eq.refl (-a < -0)) neg_zero)) h)

theorem inv_inv_of_one_lt {α : Type u} [ordered_comm_group α] {a : α} (h : 1 < a) : a⁻¹ < 1 :=
  (fun (this : a⁻¹ < (1⁻¹)) => eq.mp (Eq._oldrec (Eq.refl (a⁻¹ < (1⁻¹))) one_inv) this) (inv_lt_inv' h)

theorem inv_of_one_lt_inv {α : Type u} [ordered_comm_group α] {a : α} (h : 1 < (a⁻¹)) : a < 1 :=
  (fun (this : 1⁻¹ < (a⁻¹)) => lt_of_inv_lt_inv this) (eq.mpr (id (Eq._oldrec (Eq.refl (1⁻¹ < (a⁻¹))) one_inv)) h)

theorem one_lt_inv_of_inv {α : Type u} [ordered_comm_group α] {a : α} (h : a < 1) : 1 < (a⁻¹) :=
  (fun (this : 1⁻¹ < (a⁻¹)) => eq.mp (Eq._oldrec (Eq.refl (1⁻¹ < (a⁻¹))) one_inv) this) (inv_lt_inv' h)

theorem le_inv_of_le_inv {α : Type u} [ordered_comm_group α] {a : α} {b : α} (h : a ≤ (b⁻¹)) : b ≤ (a⁻¹) :=
  eq.mp (Eq._oldrec (Eq.refl (b⁻¹⁻¹ ≤ (a⁻¹))) (inv_inv b)) (inv_le_inv' h)

theorem neg_le_of_neg_le {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} (h : -a ≤ b) : -b ≤ a :=
  eq.mp (Eq._oldrec (Eq.refl (-b ≤ --a)) (neg_neg a)) (neg_le_neg h)

theorem lt_inv_of_lt_inv {α : Type u} [ordered_comm_group α] {a : α} {b : α} (h : a < (b⁻¹)) : b < (a⁻¹) :=
  eq.mp (Eq._oldrec (Eq.refl (b⁻¹⁻¹ < (a⁻¹))) (inv_inv b)) (inv_lt_inv' h)

theorem neg_lt_of_neg_lt {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} (h : -a < b) : -b < a :=
  eq.mp (Eq._oldrec (Eq.refl (-b < --a)) (neg_neg a)) (neg_lt_neg h)

theorem add_le_of_le_neg_add {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : b ≤ -a + c) : a + b ≤ c :=
  eq.mp (Eq._oldrec (Eq.refl (a + b ≤ a + (-a + c))) (add_neg_cancel_left a c)) (add_le_add_left h a)

theorem le_inv_mul_of_mul_le {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} (h : a * b ≤ c) : b ≤ a⁻¹ * c :=
  eq.mp (Eq._oldrec (Eq.refl (a⁻¹ * (a * b) ≤ a⁻¹ * c)) (inv_mul_cancel_left a b)) (mul_le_mul_left' h (a⁻¹))

theorem le_mul_of_inv_mul_le {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} (h : b⁻¹ * a ≤ c) : a ≤ b * c :=
  eq.mp (Eq._oldrec (Eq.refl (b * (b⁻¹ * a) ≤ b * c)) (mul_inv_cancel_left b a)) (mul_le_mul_left' h b)

theorem inv_mul_le_of_le_mul {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} (h : a ≤ b * c) : b⁻¹ * a ≤ c :=
  eq.mp (Eq._oldrec (Eq.refl (b⁻¹ * a ≤ b⁻¹ * (b * c))) (inv_mul_cancel_left b c)) (mul_le_mul_left' h (b⁻¹))

theorem le_mul_of_inv_mul_le_left {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} (h : b⁻¹ * a ≤ c) : a ≤ b * c :=
  le_mul_of_inv_mul_le h

theorem neg_add_le_left_of_le_add {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : a ≤ b + c) : -b + a ≤ c :=
  neg_add_le_of_le_add h

theorem le_add_of_neg_add_le_right {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : -c + a ≤ b) : a ≤ b + c :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a ≤ b + c)) (add_comm b c))) (le_add_of_neg_add_le h)

theorem inv_mul_le_right_of_le_mul {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} (h : a ≤ b * c) : c⁻¹ * a ≤ b :=
  inv_mul_le_left_of_le_mul (eq.mp (Eq._oldrec (Eq.refl (a ≤ b * c)) (mul_comm b c)) h)

theorem mul_lt_of_lt_inv_mul {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} (h : b < a⁻¹ * c) : a * b < c :=
  eq.mp (Eq._oldrec (Eq.refl (a * b < a * (a⁻¹ * c))) (mul_inv_cancel_left a c)) (mul_lt_mul_left' h a)

theorem lt_neg_add_of_add_lt {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : a + b < c) : b < -a + c :=
  eq.mp (Eq._oldrec (Eq.refl (-a + (a + b) < -a + c)) (neg_add_cancel_left a b)) (add_lt_add_left h (-a))

theorem lt_mul_of_inv_mul_lt {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} (h : b⁻¹ * a < c) : a < b * c :=
  eq.mp (Eq._oldrec (Eq.refl (b * (b⁻¹ * a) < b * c)) (mul_inv_cancel_left b a)) (mul_lt_mul_left' h b)

theorem neg_add_lt_of_lt_add {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : a < b + c) : -b + a < c :=
  eq.mp (Eq._oldrec (Eq.refl (-b + a < -b + (b + c))) (neg_add_cancel_left b c)) (add_lt_add_left h (-b))

theorem lt_add_of_neg_add_lt_left {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : -b + a < c) : a < b + c :=
  lt_add_of_neg_add_lt h

theorem neg_add_lt_left_of_lt_add {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : a < b + c) : -b + a < c :=
  neg_add_lt_of_lt_add h

theorem lt_add_of_neg_add_lt_right {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : -c + a < b) : a < b + c :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a < b + c)) (add_comm b c))) (lt_add_of_neg_add_lt h)

theorem neg_add_lt_right_of_lt_add {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : a < b + c) : -c + a < b :=
  neg_add_lt_of_lt_add (eq.mp (Eq._oldrec (Eq.refl (a < b + c)) (add_comm b c)) h)

@[simp] theorem neg_neg_iff_pos {α : Type u} [ordered_add_comm_group α] {a : α} : -a < 0 ↔ 0 < a :=
  { mp := pos_of_neg_neg, mpr := neg_neg_of_pos }

@[simp] theorem neg_le_neg_iff {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : -a ≤ -b ↔ b ≤ a := sorry

theorem inv_le' {α : Type u} [ordered_comm_group α] {a : α} {b : α} : a⁻¹ ≤ b ↔ b⁻¹ ≤ a :=
  (fun (this : a⁻¹ ≤ (b⁻¹⁻¹) ↔ b⁻¹ ≤ a) => eq.mp (Eq._oldrec (Eq.refl (a⁻¹ ≤ (b⁻¹⁻¹) ↔ b⁻¹ ≤ a)) (inv_inv b)) this)
    inv_le_inv_iff

theorem le_inv' {α : Type u} [ordered_comm_group α] {a : α} {b : α} : a ≤ (b⁻¹) ↔ b ≤ (a⁻¹) :=
  (fun (this : a⁻¹⁻¹ ≤ (b⁻¹) ↔ b ≤ (a⁻¹)) => eq.mp (Eq._oldrec (Eq.refl (a⁻¹⁻¹ ≤ (b⁻¹) ↔ b ≤ (a⁻¹))) (inv_inv a)) this)
    inv_le_inv_iff

theorem inv_le_iff_one_le_mul {α : Type u} [ordered_comm_group α] {a : α} {b : α} : a⁻¹ ≤ b ↔ 1 ≤ b * a :=
  iff.trans (iff.symm (mul_le_mul_iff_right a))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a⁻¹ * a ≤ b * a ↔ 1 ≤ b * a)) (inv_mul_self a))) (iff.refl (1 ≤ b * a)))

theorem neg_le_iff_add_nonneg' {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : -a ≤ b ↔ 0 ≤ a + b :=
  iff.trans (iff.symm (add_le_add_iff_left a))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a + -a ≤ a + b ↔ 0 ≤ a + b)) (add_neg_self a))) (iff.refl (0 ≤ a + b)))

theorem inv_lt_iff_one_lt_mul {α : Type u} [ordered_comm_group α] {a : α} {b : α} : a⁻¹ < b ↔ 1 < b * a :=
  iff.trans (iff.symm (mul_lt_mul_iff_right a))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a⁻¹ * a < b * a ↔ 1 < b * a)) (inv_mul_self a))) (iff.refl (1 < b * a)))

theorem neg_lt_iff_pos_add' {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : -a < b ↔ 0 < a + b :=
  iff.trans (iff.symm (add_lt_add_iff_left a))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a + -a < a + b ↔ 0 < a + b)) (add_neg_self a))) (iff.refl (0 < a + b)))

theorem le_neg_iff_add_nonpos {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : a ≤ -b ↔ a + b ≤ 0 :=
  iff.trans (iff.symm (add_le_add_iff_right b))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a + b ≤ -b + b ↔ a + b ≤ 0)) (neg_add_self b))) (iff.refl (a + b ≤ 0)))

theorem le_inv_iff_mul_le_one' {α : Type u} [ordered_comm_group α] {a : α} {b : α} : a ≤ (b⁻¹) ↔ b * a ≤ 1 :=
  iff.trans (iff.symm (mul_le_mul_iff_left b))
    (eq.mpr (id (Eq._oldrec (Eq.refl (b * a ≤ b * (b⁻¹) ↔ b * a ≤ 1)) (mul_inv_self b))) (iff.refl (b * a ≤ 1)))

theorem lt_neg_iff_add_neg {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : a < -b ↔ a + b < 0 :=
  iff.trans (iff.symm (add_lt_add_iff_right b))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a + b < -b + b ↔ a + b < 0)) (neg_add_self b))) (iff.refl (a + b < 0)))

theorem lt_inv_iff_mul_lt_one' {α : Type u} [ordered_comm_group α] {a : α} {b : α} : a < (b⁻¹) ↔ b * a < 1 :=
  iff.trans (iff.symm (mul_lt_mul_iff_left b))
    (eq.mpr (id (Eq._oldrec (Eq.refl (b * a < b * (b⁻¹) ↔ b * a < 1)) (mul_inv_self b))) (iff.refl (b * a < 1)))

@[simp] theorem inv_le_one' {α : Type u} [ordered_comm_group α] {a : α} : a⁻¹ ≤ 1 ↔ 1 ≤ a :=
  (fun (this : a⁻¹ ≤ (1⁻¹) ↔ 1 ≤ a) => eq.mp (Eq._oldrec (Eq.refl (a⁻¹ ≤ (1⁻¹) ↔ 1 ≤ a)) one_inv) this) inv_le_inv_iff

@[simp] theorem one_le_inv' {α : Type u} [ordered_comm_group α] {a : α} : 1 ≤ (a⁻¹) ↔ a ≤ 1 :=
  (fun (this : 1⁻¹ ≤ (a⁻¹) ↔ a ≤ 1) => eq.mp (Eq._oldrec (Eq.refl (1⁻¹ ≤ (a⁻¹) ↔ a ≤ 1)) one_inv) this) inv_le_inv_iff

theorem inv_le_self {α : Type u} [ordered_comm_group α] {a : α} (h : 1 ≤ a) : a⁻¹ ≤ a :=
  le_trans (iff.mpr inv_le_one' h) h

theorem self_le_inv {α : Type u} [ordered_comm_group α] {a : α} (h : a ≤ 1) : a ≤ (a⁻¹) :=
  le_trans h (iff.mpr one_le_inv' h)

@[simp] theorem neg_lt_neg_iff {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : -a < -b ↔ b < a := sorry

theorem neg_lt_zero {α : Type u} [ordered_add_comm_group α] {a : α} : -a < 0 ↔ 0 < a :=
  (fun (this : -a < -0 ↔ 0 < a) => eq.mp (Eq._oldrec (Eq.refl (-a < -0 ↔ 0 < a)) neg_zero) this) neg_lt_neg_iff

theorem one_lt_inv' {α : Type u} [ordered_comm_group α] {a : α} : 1 < (a⁻¹) ↔ a < 1 :=
  (fun (this : 1⁻¹ < (a⁻¹) ↔ a < 1) => eq.mp (Eq._oldrec (Eq.refl (1⁻¹ < (a⁻¹) ↔ a < 1)) one_inv) this) inv_lt_inv_iff

theorem neg_lt {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : -a < b ↔ -b < a :=
  (fun (this : -a < --b ↔ -b < a) => eq.mp (Eq._oldrec (Eq.refl (-a < --b ↔ -b < a)) (neg_neg b)) this) neg_lt_neg_iff

theorem lt_neg {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : a < -b ↔ b < -a :=
  (fun (this : --a < -b ↔ b < -a) => eq.mp (Eq._oldrec (Eq.refl ( --a < -b ↔ b < -a)) (neg_neg a)) this) neg_lt_neg_iff

theorem neg_lt_self {α : Type u} [ordered_add_comm_group α] {a : α} (h : 0 < a) : -a < a :=
  has_lt.lt.trans (iff.mpr neg_lt_zero h) h

theorem le_inv_mul_iff_mul_le {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} : b ≤ a⁻¹ * c ↔ a * b ≤ c :=
  (fun (this : a⁻¹ * (a * b) ≤ a⁻¹ * c ↔ a * b ≤ c) =>
      eq.mp (Eq._oldrec (Eq.refl (a⁻¹ * (a * b) ≤ a⁻¹ * c ↔ a * b ≤ c)) (inv_mul_cancel_left a b)) this)
    (mul_le_mul_iff_left (a⁻¹))

@[simp] theorem inv_mul_le_iff_le_mul {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} : b⁻¹ * a ≤ c ↔ a ≤ b * c :=
  (fun (this : b⁻¹ * a ≤ b⁻¹ * (b * c) ↔ a ≤ b * c) =>
      eq.mp (Eq._oldrec (Eq.refl (b⁻¹ * a ≤ b⁻¹ * (b * c) ↔ a ≤ b * c)) (inv_mul_cancel_left b c)) this)
    (mul_le_mul_iff_left (b⁻¹))

theorem mul_inv_le_iff_le_mul {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} : a * (c⁻¹) ≤ b ↔ a ≤ b * c := sorry

@[simp] theorem mul_inv_le_iff_le_mul' {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} : a * (b⁻¹) ≤ c ↔ a ≤ b * c :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a * (b⁻¹) ≤ c ↔ a ≤ b * c)) (Eq.symm (propext inv_mul_le_iff_le_mul))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a * (b⁻¹) ≤ c ↔ b⁻¹ * a ≤ c)) (mul_comm a (b⁻¹)))) (iff.refl (b⁻¹ * a ≤ c)))

theorem neg_add_le_iff_le_add' {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : -c + a ≤ b ↔ a ≤ b + c :=
  eq.mpr (id (Eq._oldrec (Eq.refl (-c + a ≤ b ↔ a ≤ b + c)) (propext neg_add_le_iff_le_add)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a ≤ c + b ↔ a ≤ b + c)) (add_comm c b))) (iff.refl (a ≤ b + c)))

@[simp] theorem lt_neg_add_iff_add_lt {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : b < -a + c ↔ a + b < c :=
  (fun (this : -a + (a + b) < -a + c ↔ a + b < c) =>
      eq.mp (Eq._oldrec (Eq.refl (-a + (a + b) < -a + c ↔ a + b < c)) (neg_add_cancel_left a b)) this)
    (add_lt_add_iff_left (-a))

@[simp] theorem inv_mul_lt_iff_lt_mul {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} : b⁻¹ * a < c ↔ a < b * c :=
  (fun (this : b⁻¹ * a < b⁻¹ * (b * c) ↔ a < b * c) =>
      eq.mp (Eq._oldrec (Eq.refl (b⁻¹ * a < b⁻¹ * (b * c) ↔ a < b * c)) (inv_mul_cancel_left b c)) this)
    (mul_lt_mul_iff_left (b⁻¹))

theorem inv_mul_lt_iff_lt_mul_right {α : Type u} [ordered_comm_group α] {a : α} {b : α} {c : α} : c⁻¹ * a < b ↔ a < b * c :=
  eq.mpr (id (Eq._oldrec (Eq.refl (c⁻¹ * a < b ↔ a < b * c)) (propext inv_mul_lt_iff_lt_mul)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a < c * b ↔ a < b * c)) (mul_comm c b))) (iff.refl (a < b * c)))

theorem add_neg_le_add_neg_iff {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} {d : α} : a + -b ≤ c + -d ↔ a + d ≤ c + b := sorry

theorem sub_le_sub {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} {d : α} (hab : a ≤ b) (hcd : c ≤ d) : a - d ≤ b - c := sorry

theorem sub_lt_sub {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} {d : α} (hab : a < b) (hcd : c < d) : a - d < b - c := sorry

@[simp] theorem sub_le_self_iff {α : Type u} [ordered_add_comm_group α] (a : α) {b : α} : a - b ≤ a ↔ 0 ≤ b := sorry

theorem sub_le_self {α : Type u} [ordered_add_comm_group α] (a : α) {b : α} : 0 ≤ b → a - b ≤ a :=
  iff.mpr (sub_le_self_iff a)

@[simp] theorem sub_lt_self_iff {α : Type u} [ordered_add_comm_group α] (a : α) {b : α} : a - b < a ↔ 0 < b := sorry

theorem sub_lt_self {α : Type u} [ordered_add_comm_group α] (a : α) {b : α} : 0 < b → a - b < a :=
  iff.mpr (sub_lt_self_iff a)

theorem sub_le_sub_iff {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} {d : α} : a - b ≤ c - d ↔ a + d ≤ c + b := sorry

@[simp] theorem sub_le_sub_iff_left {α : Type u} [ordered_add_comm_group α] (a : α) {b : α} {c : α} : a - b ≤ a - c ↔ c ≤ b := sorry

theorem sub_le_sub_left {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} (h : a ≤ b) (c : α) : c - b ≤ c - a :=
  iff.mpr (sub_le_sub_iff_left c) h

@[simp] theorem sub_le_sub_iff_right {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} (c : α) : a - c ≤ b - c ↔ a ≤ b := sorry

theorem sub_le_sub_right {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} (h : a ≤ b) (c : α) : a - c ≤ b - c :=
  iff.mpr (sub_le_sub_iff_right c) h

@[simp] theorem sub_lt_sub_iff_left {α : Type u} [ordered_add_comm_group α] (a : α) {b : α} {c : α} : a - b < a - c ↔ c < b := sorry

theorem sub_lt_sub_left {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} (h : a < b) (c : α) : c - b < c - a :=
  iff.mpr (sub_lt_sub_iff_left c) h

@[simp] theorem sub_lt_sub_iff_right {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} (c : α) : a - c < b - c ↔ a < b := sorry

theorem sub_lt_sub_right {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} (h : a < b) (c : α) : a - c < b - c :=
  iff.mpr (sub_lt_sub_iff_right c) h

@[simp] theorem sub_nonneg {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : 0 ≤ a - b ↔ b ≤ a :=
  eq.mpr (id (Eq._oldrec (Eq.refl (0 ≤ a - b ↔ b ≤ a)) (Eq.symm (sub_self a))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a - a ≤ a - b ↔ b ≤ a)) (propext (sub_le_sub_iff_left a)))) (iff.refl (b ≤ a)))

theorem sub_nonneg_of_le {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : b ≤ a → 0 ≤ a - b :=
  iff.mpr sub_nonneg

@[simp] theorem sub_nonpos {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : a - b ≤ 0 ↔ a ≤ b :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a - b ≤ 0 ↔ a ≤ b)) (Eq.symm (sub_self b))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a - b ≤ b - b ↔ a ≤ b)) (propext (sub_le_sub_iff_right b)))) (iff.refl (a ≤ b)))

theorem le_of_sub_nonpos {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : a - b ≤ 0 → a ≤ b :=
  iff.mp sub_nonpos

@[simp] theorem sub_pos {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : 0 < a - b ↔ b < a :=
  eq.mpr (id (Eq._oldrec (Eq.refl (0 < a - b ↔ b < a)) (Eq.symm (sub_self a))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a - a < a - b ↔ b < a)) (propext (sub_lt_sub_iff_left a)))) (iff.refl (b < a)))

theorem lt_of_sub_pos {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : 0 < a - b → b < a :=
  iff.mp sub_pos

@[simp] theorem sub_lt_zero {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : a - b < 0 ↔ a < b :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a - b < 0 ↔ a < b)) (Eq.symm (sub_self b))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a - b < b - b ↔ a < b)) (propext (sub_lt_sub_iff_right b)))) (iff.refl (a < b)))

theorem lt_of_sub_neg {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} : a - b < 0 → a < b :=
  iff.mp sub_lt_zero

theorem le_sub_iff_add_le' {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : b ≤ c - a ↔ a + b ≤ c := sorry

theorem le_sub_iff_add_le {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a ≤ c - b ↔ a + b ≤ c :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a ≤ c - b ↔ a + b ≤ c)) (propext le_sub_iff_add_le')))
    (eq.mpr (id (Eq._oldrec (Eq.refl (b + a ≤ c ↔ a + b ≤ c)) (add_comm b a))) (iff.refl (a + b ≤ c)))

theorem add_le_of_le_sub_right {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a ≤ c - b → a + b ≤ c :=
  iff.mp le_sub_iff_add_le

theorem sub_le_iff_le_add' {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a - b ≤ c ↔ a ≤ b + c := sorry

theorem le_sub_left_of_add_le {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a + b ≤ c → b ≤ c - a :=
  iff.mpr le_sub_iff_add_le'

theorem sub_le_iff_le_add {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a - c ≤ b ↔ a ≤ b + c :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a - c ≤ b ↔ a ≤ b + c)) (propext sub_le_iff_le_add')))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a ≤ c + b ↔ a ≤ b + c)) (add_comm c b))) (iff.refl (a ≤ b + c)))

@[simp] theorem neg_le_sub_iff_le_add {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : -b ≤ a - c ↔ c ≤ a + b :=
  iff.trans le_sub_iff_add_le neg_add_le_iff_le_add'

theorem neg_le_sub_iff_le_add' {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : -a ≤ b - c ↔ c ≤ a + b :=
  eq.mpr (id (Eq._oldrec (Eq.refl (-a ≤ b - c ↔ c ≤ a + b)) (propext neg_le_sub_iff_le_add)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (c ≤ b + a ↔ c ≤ a + b)) (add_comm b a))) (iff.refl (c ≤ a + b)))

theorem sub_le {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a - b ≤ c ↔ a - c ≤ b :=
  iff.trans sub_le_iff_le_add' (iff.symm sub_le_iff_le_add)

theorem le_sub {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a ≤ b - c ↔ c ≤ b - a :=
  iff.trans le_sub_iff_add_le' (iff.symm le_sub_iff_add_le)

theorem lt_sub_iff_add_lt' {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : b < c - a ↔ a + b < c := sorry

theorem add_lt_of_lt_sub_left {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : b < c - a → a + b < c :=
  iff.mp lt_sub_iff_add_lt'

theorem lt_sub_iff_add_lt {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a < c - b ↔ a + b < c :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a < c - b ↔ a + b < c)) (propext lt_sub_iff_add_lt')))
    (eq.mpr (id (Eq._oldrec (Eq.refl (b + a < c ↔ a + b < c)) (add_comm b a))) (iff.refl (a + b < c)))

theorem lt_sub_right_of_add_lt {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a + b < c → a < c - b :=
  iff.mpr lt_sub_iff_add_lt

theorem sub_lt_iff_lt_add' {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a - b < c ↔ a < b + c := sorry

theorem lt_add_of_sub_left_lt {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a - b < c → a < b + c :=
  iff.mp sub_lt_iff_lt_add'

theorem sub_lt_iff_lt_add {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a - c < b ↔ a < b + c :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a - c < b ↔ a < b + c)) (propext sub_lt_iff_lt_add')))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a < c + b ↔ a < b + c)) (add_comm c b))) (iff.refl (a < b + c)))

theorem sub_right_lt_of_lt_add {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a < b + c → a - c < b :=
  iff.mpr sub_lt_iff_lt_add

@[simp] theorem neg_lt_sub_iff_lt_add {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : -b < a - c ↔ c < a + b :=
  iff.trans lt_sub_iff_add_lt neg_add_lt_iff_lt_add_right

theorem neg_lt_sub_iff_lt_add' {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : -a < b - c ↔ c < a + b :=
  eq.mpr (id (Eq._oldrec (Eq.refl (-a < b - c ↔ c < a + b)) (propext neg_lt_sub_iff_lt_add)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (c < b + a ↔ c < a + b)) (add_comm b a))) (iff.refl (c < a + b)))

theorem sub_lt {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a - b < c ↔ a - c < b :=
  iff.trans sub_lt_iff_lt_add' (iff.symm sub_lt_iff_lt_add)

theorem lt_sub {α : Type u} [ordered_add_comm_group α] {a : α} {b : α} {c : α} : a < b - c ↔ c < b - a :=
  iff.trans lt_sub_iff_add_lt' (iff.symm lt_sub_iff_add_lt)

/-!

### Linearly ordered commutative groups

-/

/-- A linearly ordered additive commutative group is an
additive commutative group with a linear order in which
addition is monotone. -/
class linear_ordered_add_comm_group (α : Type u)
extends add_comm_group α, linear_order α
where
  add_le_add_left : ∀ (a b : α), a ≤ b → ∀ (c : α), c + a ≤ c + b

/-- A linearly ordered commutative group is a
commutative group with a linear order in which
multiplication is monotone. -/
class linear_ordered_comm_group (α : Type u)
extends linear_order α, comm_group α
where
  mul_le_mul_left : ∀ (a b : α), a ≤ b → ∀ (c : α), c * a ≤ c * b

protected instance linear_ordered_comm_group.to_ordered_comm_group (α : Type u) [s : linear_ordered_comm_group α] : ordered_comm_group α :=
  ordered_comm_group.mk linear_ordered_comm_group.mul linear_ordered_comm_group.mul_assoc linear_ordered_comm_group.one
    linear_ordered_comm_group.one_mul linear_ordered_comm_group.mul_one linear_ordered_comm_group.inv
    linear_ordered_comm_group.div linear_ordered_comm_group.mul_left_inv linear_ordered_comm_group.mul_comm
    linear_ordered_comm_group.le linear_ordered_comm_group.lt linear_ordered_comm_group.le_refl
    linear_ordered_comm_group.le_trans linear_ordered_comm_group.le_antisymm linear_ordered_comm_group.mul_le_mul_left

protected instance linear_ordered_add_comm_group.to_linear_ordered_cancel_add_comm_monoid {α : Type u} [linear_ordered_add_comm_group α] : linear_ordered_cancel_add_comm_monoid α :=
  linear_ordered_cancel_add_comm_monoid.mk linear_ordered_add_comm_group.add linear_ordered_add_comm_group.add_assoc sorry
    linear_ordered_add_comm_group.zero linear_ordered_add_comm_group.zero_add linear_ordered_add_comm_group.add_zero
    linear_ordered_add_comm_group.add_comm sorry linear_ordered_add_comm_group.le linear_ordered_add_comm_group.lt
    linear_ordered_add_comm_group.le_refl linear_ordered_add_comm_group.le_trans linear_ordered_add_comm_group.le_antisymm
    linear_ordered_add_comm_group.add_le_add_left sorry linear_ordered_add_comm_group.le_total
    linear_ordered_add_comm_group.decidable_le linear_ordered_add_comm_group.decidable_eq
    linear_ordered_add_comm_group.decidable_lt

theorem linear_ordered_add_comm_group.add_lt_add_left {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) (h : a < b) (c : α) : c + a < c + b :=
  ordered_add_comm_group.add_lt_add_left a b h c

theorem le_of_forall_pos_le_add {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} [densely_ordered α] (h : ∀ (ε : α), 0 < ε → a ≤ b + ε) : a ≤ b :=
  le_of_forall_le_of_dense
    fun (c : α) (hc : c > b) => trans_rel_left LessEq (h (c - b) (sub_pos_of_lt hc)) (add_sub_cancel'_right b c)

theorem min_neg_neg {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) : min (-a) (-b) = -max a b :=
  Eq.symm (monotone.map_max fun (a b : α) => neg_le_neg)

theorem max_neg_neg {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) : max (-a) (-b) = -min a b :=
  Eq.symm (monotone.map_min fun (a b : α) => neg_le_neg)

theorem min_sub_sub_right {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) (c : α) : min (a - c) (b - c) = min a b - c := sorry

theorem max_sub_sub_right {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) (c : α) : max (a - c) (b - c) = max a b - c := sorry

theorem min_sub_sub_left {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) (c : α) : min (a - b) (a - c) = a - max b c := sorry

theorem max_sub_sub_left {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) (c : α) : max (a - b) (a - c) = a - min b c := sorry

theorem max_zero_sub_eq_self {α : Type u} [linear_ordered_add_comm_group α] (a : α) : max a 0 - max (-a) 0 = a := sorry

/-- `abs a` is the absolute value of `a`. -/
def abs {α : Type u} [linear_ordered_add_comm_group α] (a : α) : α :=
  max a (-a)

theorem abs_of_nonneg {α : Type u} [linear_ordered_add_comm_group α] {a : α} (h : 0 ≤ a) : abs a = a :=
  max_eq_left (has_le.le.trans (iff.mpr neg_nonpos h) h)

theorem abs_of_pos {α : Type u} [linear_ordered_add_comm_group α] {a : α} (h : 0 < a) : abs a = a :=
  abs_of_nonneg (has_lt.lt.le h)

theorem abs_of_nonpos {α : Type u} [linear_ordered_add_comm_group α] {a : α} (h : a ≤ 0) : abs a = -a :=
  max_eq_right (has_le.le.trans h (iff.mpr neg_nonneg h))

theorem abs_of_neg {α : Type u} [linear_ordered_add_comm_group α] {a : α} (h : a < 0) : abs a = -a :=
  abs_of_nonpos (has_lt.lt.le h)

@[simp] theorem abs_zero {α : Type u} [linear_ordered_add_comm_group α] : abs 0 = 0 :=
  abs_of_nonneg le_rfl

@[simp] theorem abs_neg {α : Type u} [linear_ordered_add_comm_group α] (a : α) : abs (-a) = abs a := sorry

@[simp] theorem abs_pos {α : Type u} [linear_ordered_add_comm_group α] {a : α} : 0 < abs a ↔ a ≠ 0 := sorry

theorem abs_pos_of_pos {α : Type u} [linear_ordered_add_comm_group α] {a : α} (h : 0 < a) : 0 < abs a :=
  iff.mpr abs_pos (ne.symm (has_lt.lt.ne h))

theorem abs_pos_of_neg {α : Type u} [linear_ordered_add_comm_group α] {a : α} (h : a < 0) : 0 < abs a :=
  iff.mpr abs_pos (has_lt.lt.ne h)

theorem abs_sub {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) : abs (a - b) = abs (b - a) :=
  eq.mpr (id (Eq._oldrec (Eq.refl (abs (a - b) = abs (b - a))) (Eq.symm (neg_sub b a))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (abs (-(b - a)) = abs (b - a))) (abs_neg (b - a)))) (Eq.refl (abs (b - a))))

theorem abs_le' {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} : abs a ≤ b ↔ a ≤ b ∧ -a ≤ b :=
  max_le_iff

theorem abs_le {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} : abs a ≤ b ↔ -b ≤ a ∧ a ≤ b :=
  eq.mpr (id (Eq._oldrec (Eq.refl (abs a ≤ b ↔ -b ≤ a ∧ a ≤ b)) (propext abs_le')))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a ≤ b ∧ -a ≤ b ↔ -b ≤ a ∧ a ≤ b)) (propext and.comm)))
      (eq.mpr (id (Eq._oldrec (Eq.refl (-a ≤ b ∧ a ≤ b ↔ -b ≤ a ∧ a ≤ b)) (propext neg_le))) (iff.refl (-b ≤ a ∧ a ≤ b))))

theorem le_abs_self {α : Type u} [linear_ordered_add_comm_group α] (a : α) : a ≤ abs a :=
  le_max_left a (-a)

theorem neg_le_abs_self {α : Type u} [linear_ordered_add_comm_group α] (a : α) : -a ≤ abs a :=
  le_max_right a (-a)

theorem abs_nonneg {α : Type u} [linear_ordered_add_comm_group α] (a : α) : 0 ≤ abs a :=
  or.elim (le_total 0 a) (fun (h : 0 ≤ a) => has_le.le.trans h (le_abs_self a))
    fun (h : a ≤ 0) => has_le.le.trans (iff.mpr neg_nonneg h) (neg_le_abs_self a)

@[simp] theorem abs_abs {α : Type u} [linear_ordered_add_comm_group α] (a : α) : abs (abs a) = abs a :=
  abs_of_nonneg (abs_nonneg a)

@[simp] theorem abs_eq_zero {α : Type u} [linear_ordered_add_comm_group α] {a : α} : abs a = 0 ↔ a = 0 :=
  iff.mp not_iff_not (iff.trans ne_comm (iff.trans (iff.symm (has_le.le.lt_iff_ne (abs_nonneg a))) abs_pos))

@[simp] theorem abs_nonpos_iff {α : Type u} [linear_ordered_add_comm_group α] {a : α} : abs a ≤ 0 ↔ a = 0 :=
  iff.trans (has_le.le.le_iff_eq (abs_nonneg a)) abs_eq_zero

theorem abs_lt {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} : abs a < b ↔ -b < a ∧ a < b :=
  iff.trans max_lt_iff
    (iff.trans and.comm
      (eq.mpr (id (Eq._oldrec (Eq.refl (-a < b ∧ a < b ↔ -b < a ∧ a < b)) (propext neg_lt))) (iff.refl (-b < a ∧ a < b))))

theorem lt_abs {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} : a < abs b ↔ a < b ∨ a < -b :=
  lt_max_iff

theorem max_sub_min_eq_abs' {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) : max a b - min a b = abs (a - b) := sorry

theorem max_sub_min_eq_abs {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) : max a b - min a b = abs (b - a) :=
  eq.mpr (id (Eq._oldrec (Eq.refl (max a b - min a b = abs (b - a))) (abs_sub b a))) (max_sub_min_eq_abs' a b)

theorem abs_add {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) : abs (a + b) ≤ abs a + abs b := sorry

theorem abs_sub_le_iff {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} {c : α} : abs (a - b) ≤ c ↔ a - b ≤ c ∧ b - a ≤ c := sorry

theorem abs_sub_lt_iff {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} {c : α} : abs (a - b) < c ↔ a - b < c ∧ b - a < c := sorry

theorem sub_le_of_abs_sub_le_left {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : abs (a - b) ≤ c) : b - c ≤ a :=
  iff.mp sub_le (and.right (iff.mp abs_sub_le_iff h))

theorem sub_le_of_abs_sub_le_right {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : abs (a - b) ≤ c) : a - c ≤ b :=
  sub_le_of_abs_sub_le_left (abs_sub a b ▸ h)

theorem sub_lt_of_abs_sub_lt_left {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : abs (a - b) < c) : b - c < a :=
  iff.mp sub_lt (and.right (iff.mp abs_sub_lt_iff h))

theorem sub_lt_of_abs_sub_lt_right {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} {c : α} (h : abs (a - b) < c) : a - c < b :=
  sub_lt_of_abs_sub_lt_left (abs_sub a b ▸ h)

theorem abs_sub_abs_le_abs_sub {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) : abs a - abs b ≤ abs (a - b) := sorry

theorem abs_abs_sub_abs_le_abs_sub {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) : abs (abs a - abs b) ≤ abs (a - b) := sorry

theorem abs_eq {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} (hb : 0 ≤ b) : abs a = b ↔ a = b ∨ a = -b := sorry

theorem abs_le_max_abs_abs {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} {c : α} (hab : a ≤ b) (hbc : b ≤ c) : abs b ≤ max (abs a) (abs c) := sorry

theorem abs_le_abs {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} (h₀ : a ≤ b) (h₁ : -a ≤ b) : abs a ≤ abs b :=
  has_le.le.trans (iff.mpr abs_le' { left := h₀, right := h₁ }) (le_abs_self b)

theorem abs_max_sub_max_le_abs {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) (c : α) : abs (max a c - max b c) ≤ abs (a - b) := sorry

theorem eq_zero_of_neg_eq {α : Type u} [linear_ordered_add_comm_group α] {a : α} (h : -a = a) : a = 0 := sorry

theorem eq_of_abs_sub_eq_zero {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} (h : abs (a - b) = 0) : a = b :=
  iff.mp sub_eq_zero (iff.mp abs_eq_zero h)

theorem abs_by_cases {α : Type u} [linear_ordered_add_comm_group α] (P : α → Prop) {a : α} (h1 : P a) (h2 : P (-a)) : P (abs a) :=
  sup_ind a (-a) h1 h2

theorem abs_sub_le {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) (c : α) : abs (a - c) ≤ abs (a - b) + abs (b - c) := sorry

theorem abs_add_three {α : Type u} [linear_ordered_add_comm_group α] (a : α) (b : α) (c : α) : abs (a + b + c) ≤ abs a + abs b + abs c :=
  has_le.le.trans (abs_add (a + b) c) (add_le_add_right (abs_add a b) (abs c))

theorem dist_bdd_within_interval {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} {lb : α} {ub : α} (hal : lb ≤ a) (hau : a ≤ ub) (hbl : lb ≤ b) (hbu : b ≤ ub) : abs (a - b) ≤ ub - lb :=
  iff.mpr abs_sub_le_iff { left := sub_le_sub hau hbl, right := sub_le_sub hbu hal }

theorem eq_of_abs_sub_nonpos {α : Type u} [linear_ordered_add_comm_group α] {a : α} {b : α} (h : abs (a - b) ≤ 0) : a = b :=
  eq_of_abs_sub_eq_zero (le_antisymm h (abs_nonneg (a - b)))

theorem exists_zero_lt {α : Type u} [linear_ordered_add_comm_group α] [nontrivial α] : ∃ (a : α), 0 < a := sorry

protected instance linear_ordered_add_comm_group.to_no_top_order {α : Type u} [linear_ordered_add_comm_group α] [nontrivial α] : no_top_order α :=
  no_top_order.mk
    (Exists.dcases_on exists_zero_lt fun (y : α) (hy : 0 < y) (a : α) => Exists.intro (a + y) (lt_add_of_pos_right a hy))

protected instance linear_ordered_add_comm_group.to_no_bot_order {α : Type u} [linear_ordered_add_comm_group α] [nontrivial α] : no_bot_order α :=
  no_bot_order.mk
    (Exists.dcases_on exists_zero_lt fun (y : α) (hy : 0 < y) (a : α) => Exists.intro (a - y) (sub_lt_self a hy))

/-- This is not so much a new structure as a construction mechanism
  for ordered groups, by specifying only the "positive cone" of the group. -/
class nonneg_add_comm_group (α : Type u_1)
extends add_comm_group α
where
  nonneg : α → Prop
  pos : α → Prop
  pos_iff : autoParam (∀ (a : α), pos a ↔ nonneg a ∧ ¬nonneg (-a))
  (Lean.Syntax.ident Lean.SourceInfo.none (String.toSubstring "Mathlib.order_laws_tac")
    (Lean.Name.mkStr (Lean.Name.mkStr Lean.Name.anonymous "Mathlib") "order_laws_tac") [])
  zero_nonneg : nonneg 0
  add_nonneg : ∀ {a b : α}, nonneg a → nonneg b → nonneg (a + b)
  nonneg_antisymm : ∀ {a : α}, nonneg a → nonneg (-a) → a = 0

namespace nonneg_add_comm_group

protected instance to_ordered_add_comm_group {α : Type u} [s : nonneg_add_comm_group α] : ordered_add_comm_group α :=
  ordered_add_comm_group.mk add add_assoc zero zero_add add_zero neg sub add_left_neg add_comm
    (fun (a b : α) => nonneg (b - a)) (fun (a b : α) => pos (b - a)) sorry sorry sorry sorry

theorem nonneg_def {α : Type u} [s : nonneg_add_comm_group α] {a : α} : nonneg a ↔ 0 ≤ a := sorry

theorem pos_def {α : Type u} [s : nonneg_add_comm_group α] {a : α} : pos a ↔ 0 < a := sorry

theorem not_zero_pos {α : Type u} [s : nonneg_add_comm_group α] : ¬pos 0 :=
  mt (iff.mp pos_def) (lt_irrefl 0)

theorem zero_lt_iff_nonneg_nonneg {α : Type u} [s : nonneg_add_comm_group α] {a : α} : 0 < a ↔ nonneg a ∧ ¬nonneg (-a) :=
  iff.trans (iff.symm pos_def) (pos_iff a)

theorem nonneg_total_iff {α : Type u} [s : nonneg_add_comm_group α] : (∀ (a : α), nonneg a ∨ nonneg (-a)) ↔ ∀ (a b : α), a ≤ b ∨ b ≤ a := sorry

/--
A `nonneg_add_comm_group` is a `linear_ordered_add_comm_group`
if `nonneg` is total and decidable.
-/
def to_linear_ordered_add_comm_group {α : Type u} [s : nonneg_add_comm_group α] [decidable_pred nonneg] (nonneg_total : ∀ (a : α), nonneg a ∨ nonneg (-a)) : linear_ordered_add_comm_group α :=
  linear_ordered_add_comm_group.mk ordered_add_comm_group.add sorry ordered_add_comm_group.zero sorry sorry
    ordered_add_comm_group.neg ordered_add_comm_group.sub sorry sorry LessEq Less sorry sorry sorry sorry
    (fun (a b : α) => _inst_1 (b - a))
    (linear_order.decidable_eq._default LessEq Less sorry sorry sorry fun (a b : α) => _inst_1 (b - a))
    (fun (a b : α) => Mathlib.decidable_lt_of_decidable_le a b) sorry

end nonneg_add_comm_group

namespace order_dual

protected instance ordered_add_comm_group {α : Type u} [ordered_add_comm_group α] : ordered_add_comm_group (order_dual α) :=
  ordered_add_comm_group.mk ordered_add_comm_monoid.add sorry ordered_add_comm_monoid.zero sorry sorry add_comm_group.neg
    (fun (a b : order_dual α) => a - b) sorry sorry ordered_add_comm_monoid.le ordered_add_comm_monoid.lt sorry sorry
    sorry sorry

protected instance linear_ordered_add_comm_group {α : Type u} [linear_ordered_add_comm_group α] : linear_ordered_add_comm_group (order_dual α) :=
  linear_ordered_add_comm_group.mk add_comm_group.add sorry add_comm_group.zero sorry sorry add_comm_group.neg
    add_comm_group.sub sorry sorry linear_order.le linear_order.lt sorry sorry sorry sorry linear_order.decidable_le
    linear_order.decidable_eq linear_order.decidable_lt sorry

end order_dual

namespace prod

protected instance ordered_add_comm_group {G : Type u_1} {H : Type u_2} [ordered_add_comm_group G] [ordered_add_comm_group H] : ordered_add_comm_group (G × H) :=
  ordered_add_comm_group.mk add_comm_group.add sorry add_comm_group.zero sorry sorry add_comm_group.neg add_comm_group.sub
    sorry sorry partial_order.le partial_order.lt sorry sorry sorry sorry

end prod

protected instance multiplicative.ordered_comm_group {α : Type u} [ordered_add_comm_group α] : ordered_comm_group (multiplicative α) :=
  ordered_comm_group.mk comm_group.mul sorry comm_group.one sorry sorry comm_group.inv comm_group.div sorry sorry
    ordered_comm_monoid.le ordered_comm_monoid.lt sorry sorry sorry sorry

protected instance additive.ordered_add_comm_group {α : Type u} [ordered_comm_group α] : ordered_add_comm_group (additive α) :=
  ordered_add_comm_group.mk add_comm_group.add sorry add_comm_group.zero sorry sorry add_comm_group.neg add_comm_group.sub
    sorry sorry ordered_add_comm_monoid.le ordered_add_comm_monoid.lt sorry sorry sorry sorry


/-
Copyright (c) 2020 Zhouhang Zhou. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Zhouhang Zhou, Yury Kudryashov
-/
import measure_theory.bochner_integration
import analysis.normed_space.indicator_function

/-!
# Set integral

In this file we prove some properties of `∫ x in s, f x ∂μ`. Recall that this notation
is defined as `∫ x, f x ∂(μ.restrict s)`. In `integral_indicator` we prove that for a measurable
function `f` and a measurable set `s` this definition coincides with another natural definition:
`∫ x, indicator s f x ∂μ = ∫ x in s, f x ∂μ`, where `indicator s f x` is equal to `f x` for `x ∈ s`
and is zero otherwise.

Since `∫ x in s, f x ∂μ` is a notation, one can rewrite or apply any theorem about `∫ x, f x ∂μ`
directly. In this file we prove some theorems about dependence of `∫ x in s, f x ∂μ` on `s`, e.g.
`integral_union`, `integral_empty`, `integral_univ`.

We also define `integrable_on f s μ := integrable f (μ.restrict s)` and prove theorems like
`integrable_on_union : integrable_on f (s ∪ t) μ ↔ integrable_on f s μ ∧ integrable_on f t μ`.

Next we define a predicate `integrable_at_filter (f : α → E) (l : filter α) (μ : measure α)`
saying that `f` is integrable at some set `s ∈ l` and prove that a measurable function is integrable
at `l` with respect to `μ` provided that `f` is bounded above at `l ⊓ μ.ae` and `μ` is finite
at `l`.

Finally, we prove a version of the
[Fundamental theorem of calculus](https://en.wikipedia.org/wiki/Fundamental_theorem_of_calculus)
for set integral, see `filter.tendsto.integral_sub_linear_is_o_ae` and its corollaries.
Namely, consider a measurably generated filter `l`, a measure `μ` finite at this filter, and
a function `f` that has a finite limit `c` at `l ⊓ μ.ae`. Then `∫ x in s, f x ∂μ = μ s • c + o(μ s)`
as `s` tends to `l.lift' powerset`, i.e. for any `ε>0` there exists `t ∈ l` such that
`∥∫ x in s, f x ∂μ - μ s • c∥ ≤ ε * μ s` whenever `s ⊆ t`. We also formulate a version of this
theorem for a locally finite measure `μ` and a function `f` continuous at a point `a`.

## Notation

We provide the following notations for expressing the integral of a function on a set :
* `∫ a in s, f a ∂μ` is `measure_theory.integral (μ.restrict s) f`
* `∫ a in s, f a` is `∫ a in s, f a ∂volume`

Note that the set notations are defined in the file `measure_theory/bochner_integration`,
but we reference them here because all theorems about set integrals are in this file.

## TODO

The file ends with over a hundred lines of commented out code. This is the old contents of this file
using the `indicator` approach to the definition of `∫ x in s, f x ∂μ`. This code should be
migrated to the new definition.

-/

noncomputable theory
open set filter topological_space measure_theory function
open_locale classical topological_space interval big_operators filter ennreal measure_theory

variables {α β E F : Type*} [measurable_space α]

section piecewise

variables {μ : measure α} {s : set α} {f g : α → β}

lemma piecewise_ae_eq_restrict (hs : measurable_set s) : piecewise s f g =ᵐ[μ.restrict s] f :=
begin
  rw [ae_restrict_eq hs],
  exact (piecewise_eq_on s f g).eventually_eq.filter_mono inf_le_right
end

lemma piecewise_ae_eq_restrict_compl (hs : measurable_set s) :
  piecewise s f g =ᵐ[μ.restrict sᶜ] g :=
begin
  rw [ae_restrict_eq hs.compl],
  exact (piecewise_eq_on_compl s f g).eventually_eq.filter_mono inf_le_right
end

end piecewise

section indicator_function

variables [has_zero β] {μ : measure α} {s : set α} {f : α → β}

lemma indicator_ae_eq_restrict (hs : measurable_set s) : indicator s f =ᵐ[μ.restrict s] f :=
piecewise_ae_eq_restrict hs

lemma indicator_ae_eq_restrict_compl (hs : measurable_set s) : indicator s f =ᵐ[μ.restrict sᶜ] 0 :=
piecewise_ae_eq_restrict_compl hs

end indicator_function

section

variables [measurable_space β] {l l' : filter α} {f g : α → β} {μ ν : measure α}

/-- A function `f` is measurable at filter `l` w.r.t. a measure `μ` if it is ae-measurable
w.r.t. `μ.restrict s` for some `s ∈ l`. -/
def measurable_at_filter (f : α → β) (l : filter α) (μ : measure α . volume_tac) :=
∃ s ∈ l, ae_measurable f (μ.restrict s)

@[simp] lemma measurable_at_bot {f : α → β} : measurable_at_filter f ⊥ μ :=
⟨∅, mem_bot_sets, by simp⟩

protected lemma measurable_at_filter.eventually (h : measurable_at_filter f l μ) :
  ∀ᶠ s in l.lift' powerset, ae_measurable f (μ.restrict s) :=
(eventually_lift'_powerset' $ λ s t, ae_measurable.mono_set).2 h

protected lemma measurable_at_filter.filter_mono (h : measurable_at_filter f l μ) (h' : l' ≤ l) :
  measurable_at_filter f l' μ :=
let ⟨s, hsl, hs⟩ := h in ⟨s, h' hsl, hs⟩

protected lemma ae_measurable.measurable_at_filter (h : ae_measurable f μ) :
  measurable_at_filter f l μ :=
⟨univ, univ_mem_sets, by rwa measure.restrict_univ⟩

lemma ae_measurable.measurable_at_filter_of_mem {s} (h : ae_measurable f (μ.restrict s))
  (hl : s ∈ l):
  measurable_at_filter f l μ :=
⟨s, hl, h⟩

protected lemma measurable.measurable_at_filter (h : measurable f) :
  measurable_at_filter f l μ :=
h.ae_measurable.measurable_at_filter

end

namespace measure_theory

section normed_group

lemma has_finite_integral_restrict_of_bounded [normed_group E] {f : α → E} {s : set α}
  {μ : measure α} {C}  (hs : μ s < ∞) (hf : ∀ᵐ x ∂(μ.restrict s), ∥f x∥ ≤ C) :
  has_finite_integral f (μ.restrict s) :=
by haveI : finite_measure (μ.restrict s) := ⟨by rwa [measure.restrict_apply_univ]⟩;
  exact has_finite_integral_of_bounded hf

variables [normed_group E] [measurable_space E] {f g : α → E} {s t : set α} {μ ν : measure α}

/-- A function is `integrable_on` a set `s` if it is a measurable function and if the integral of
  its pointwise norm over `s` is less than infinity. -/
def integrable_on (f : α → E) (s : set α) (μ : measure α . volume_tac) : Prop :=
integrable f (μ.restrict s)

lemma integrable_on.integrable (h : integrable_on f s μ) :
  integrable f (μ.restrict s) :=
h

@[simp] lemma integrable_on_empty : integrable_on f ∅ μ :=
by simp [integrable_on, integrable_zero_measure]

@[simp] lemma integrable_on_univ : integrable_on f univ μ ↔ integrable f μ :=
by rw [integrable_on, measure.restrict_univ]

lemma integrable_on_zero : integrable_on (λ _, (0:E)) s μ := integrable_zero _ _ _

lemma integrable_on_const {C : E} : integrable_on (λ _, C) s μ ↔ C = 0 ∨ μ s < ∞ :=
integrable_const_iff.trans $ by rw [measure.restrict_apply_univ]

lemma integrable_on.mono (h : integrable_on f t ν) (hs : s ⊆ t) (hμ : μ ≤ ν) :
  integrable_on f s μ :=
h.mono_measure $ measure.restrict_mono hs hμ

lemma integrable_on.mono_set (h : integrable_on f t μ) (hst : s ⊆ t) :
  integrable_on f s μ :=
h.mono hst (le_refl _)

lemma integrable_on.mono_measure (h : integrable_on f s ν) (hμ : μ ≤ ν) :
  integrable_on f s μ :=
h.mono (subset.refl _) hμ

lemma integrable_on.mono_set_ae (h : integrable_on f t μ) (hst : s ≤ᵐ[μ] t) :
  integrable_on f s μ :=
h.integrable.mono_measure $ restrict_mono_ae hst

lemma integrable.integrable_on (h : integrable f μ) : integrable_on f s μ :=
h.mono_measure $ measure.restrict_le_self

lemma integrable.integrable_on' (h : integrable f (μ.restrict s)) : integrable_on f s μ :=
h

lemma integrable_on.left_of_union (h : integrable_on f (s ∪ t) μ) : integrable_on f s μ :=
h.mono_set $ subset_union_left _ _

lemma integrable_on.right_of_union (h : integrable_on f (s ∪ t) μ) : integrable_on f t μ :=
h.mono_set $ subset_union_right _ _

lemma integrable_on.union (hs : integrable_on f s μ) (ht : integrable_on f t μ) :
  integrable_on f (s ∪ t) μ :=
(hs.add_measure ht).mono_measure $ measure.restrict_union_le _ _

@[simp] lemma integrable_on_union :
  integrable_on f (s ∪ t) μ ↔ integrable_on f s μ ∧ integrable_on f t μ :=
⟨λ h, ⟨h.left_of_union, h.right_of_union⟩, λ h, h.1.union h.2⟩

@[simp] lemma integrable_on_finite_union {s : set β} (hs : finite s)
  {t : β → set α} : integrable_on f (⋃ i ∈ s, t i) μ ↔ ∀ i ∈ s, integrable_on f (t i) μ :=
begin
  apply hs.induction_on,
  { simp },
  { intros a s ha hs hf, simp [hf, or_imp_distrib, forall_and_distrib] }
end

@[simp] lemma integrable_on_finset_union  {s : finset β} {t : β → set α} :
  integrable_on f (⋃ i ∈ s, t i) μ ↔ ∀ i ∈ s, integrable_on f (t i) μ :=
integrable_on_finite_union s.finite_to_set

lemma integrable_on.add_measure (hμ : integrable_on f s μ) (hν : integrable_on f s ν) :
  integrable_on f s (μ + ν) :=
by { delta integrable_on, rw measure.restrict_add, exact hμ.integrable.add_measure hν }

@[simp] lemma integrable_on_add_measure :
  integrable_on f s (μ + ν) ↔ integrable_on f s μ ∧ integrable_on f s ν :=
⟨λ h, ⟨h.mono_measure (measure.le_add_right (le_refl _)),
  h.mono_measure (measure.le_add_left (le_refl _))⟩,
  λ h, h.1.add_measure h.2⟩

lemma ae_measurable_indicator_iff (hs : measurable_set s) :
  ae_measurable f (μ.restrict s) ↔ ae_measurable (indicator s f) μ :=
begin
  split,
  { assume h,
    refine ⟨indicator s (h.mk f), h.measurable_mk.indicator hs, _⟩,
    have A : s.indicator f =ᵐ[μ.restrict s] s.indicator (ae_measurable.mk f h) :=
      (indicator_ae_eq_restrict hs).trans (h.ae_eq_mk.trans $ (indicator_ae_eq_restrict hs).symm),
    have B : s.indicator f =ᵐ[μ.restrict sᶜ] s.indicator (ae_measurable.mk f h) :=
      (indicator_ae_eq_restrict_compl hs).trans (indicator_ae_eq_restrict_compl hs).symm,
    have : s.indicator f =ᵐ[μ.restrict s + μ.restrict sᶜ] s.indicator (ae_measurable.mk f h) :=
      ae_add_measure_iff.2 ⟨A, B⟩,
    simpa only [hs, measure.restrict_add_restrict_compl] using this },
  { assume h,
    exact (h.mono_measure measure.restrict_le_self).congr (indicator_ae_eq_restrict hs) }
end

lemma integrable_indicator_iff (hs : measurable_set s) :
  integrable (indicator s f) μ ↔ integrable_on f s μ :=
by simp [integrable_on, integrable, has_finite_integral, nnnorm_indicator_eq_indicator_nnnorm,
  ennreal.coe_indicator, lintegral_indicator _ hs, ae_measurable_indicator_iff hs]

lemma integrable_on.indicator (h : integrable_on f s μ) (hs : measurable_set s) :
  integrable (indicator s f) μ :=
(integrable_indicator_iff hs).2 h

lemma integrable.indicator (h : integrable f μ) (hs : measurable_set s) :
  integrable (indicator s f) μ :=
h.integrable_on.indicator hs

/-- We say that a function `f` is *integrable at filter* `l` if it is integrable on some
set `s ∈ l`. Equivalently, it is eventually integrable on `s` in `l.lift' powerset`. -/
def integrable_at_filter (f : α → E) (l : filter α) (μ : measure α . volume_tac) :=
∃ s ∈ l, integrable_on f s μ

variables {l l' : filter α}

protected lemma integrable_at_filter.eventually (h : integrable_at_filter f l μ) :
  ∀ᶠ s in l.lift' powerset, integrable_on f s μ :=
by { refine (eventually_lift'_powerset' $ λ s t hst ht, _).2 h, exact ht.mono_set hst }

lemma integrable_at_filter.filter_mono (hl : l ≤ l') (hl' : integrable_at_filter f l' μ) :
  integrable_at_filter f l μ :=
let ⟨s, hs, hsf⟩ := hl' in ⟨s, hl hs, hsf⟩

lemma integrable_at_filter.inf_of_left (hl : integrable_at_filter f l μ) :
  integrable_at_filter f (l ⊓ l') μ :=
hl.filter_mono inf_le_left

lemma integrable_at_filter.inf_of_right (hl : integrable_at_filter f l μ) :
  integrable_at_filter f (l' ⊓ l) μ :=
hl.filter_mono inf_le_right

@[simp] lemma integrable_at_filter.inf_ae_iff {l : filter α} :
  integrable_at_filter f (l ⊓ μ.ae) μ ↔ integrable_at_filter f l μ :=
begin
  refine ⟨_, λ h, h.filter_mono inf_le_left⟩,
  rintros ⟨s, ⟨t, ht, u, hu, hs⟩, hf⟩,
  refine ⟨t, ht, _⟩,
  refine hf.integrable.mono_measure (λ v hv, _),
  simp only [measure.restrict_apply hv],
  refine measure_mono_ae (mem_sets_of_superset hu $ λ x hx, _),
  exact λ ⟨hv, ht⟩, ⟨hv, hs ⟨ht, hx⟩⟩
end

alias integrable_at_filter.inf_ae_iff ↔ measure_theory.integrable_at_filter.of_inf_ae _

/-- If `μ` is a measure finite at filter `l` and `f` is a function such that its norm is bounded
above at `l`, then `f` is integrable at `l`. -/
lemma measure.finite_at_filter.integrable_at_filter {l : filter α} [is_measurably_generated l]
  (hfm : measurable_at_filter f l μ) (hμ : μ.finite_at_filter l)
  (hf : l.is_bounded_under (≤) (norm ∘ f)) :
  integrable_at_filter f l μ :=
begin
  obtain ⟨C, hC⟩ : ∃ C, ∀ᶠ s in (l.lift' powerset), ∀ x ∈ s, ∥f x∥ ≤ C,
    from hf.imp (λ C hC, eventually_lift'_powerset.2 ⟨_, hC, λ t, id⟩),
  rcases (hfm.eventually.and (hμ.eventually.and hC)).exists_measurable_mem_of_lift'
    with ⟨s, hsl, hsm, hfm, hμ, hC⟩,
  refine ⟨s, hsl, ⟨hfm, has_finite_integral_restrict_of_bounded hμ _⟩⟩,
  exact C,
  rw [ae_restrict_eq hsm, eventually_inf_principal],
  exact eventually_of_forall hC
end

lemma measure.finite_at_filter.integrable_at_filter_of_tendsto_ae
  {l : filter α} [is_measurably_generated l] (hfm : measurable_at_filter f l μ)
  (hμ : μ.finite_at_filter l) {b} (hf : tendsto f (l ⊓ μ.ae) (𝓝 b)) :
  integrable_at_filter f l μ :=
(hμ.inf_of_left.integrable_at_filter (hfm.filter_mono inf_le_left)
  hf.norm.is_bounded_under_le).of_inf_ae

alias measure.finite_at_filter.integrable_at_filter_of_tendsto_ae ←
  filter.tendsto.integrable_at_filter_ae

lemma measure.finite_at_filter.integrable_at_filter_of_tendsto {l : filter α}
  [is_measurably_generated l] (hfm : measurable_at_filter f l μ) (hμ : μ.finite_at_filter l)
  {b} (hf : tendsto f l (𝓝 b)) :
  integrable_at_filter f l μ :=
hμ.integrable_at_filter hfm hf.norm.is_bounded_under_le

alias measure.finite_at_filter.integrable_at_filter_of_tendsto ← filter.tendsto.integrable_at_filter

variables [borel_space E] [second_countable_topology E]

lemma integrable_add [opens_measurable_space E] {f g : α → E}
  (h : disjoint (support f) (support g)) (hf : measurable f) (hg : measurable g) :
  integrable (f + g) μ ↔ integrable f μ ∧ integrable g μ :=
begin
  refine ⟨λ hfg, ⟨_, _⟩, λ h, h.1.add h.2⟩,
  { rw ← indicator_add_eq_left h, exact hfg.indicator (measurable_set_support hf) },
  { rw ← indicator_add_eq_right h, exact hfg.indicator (measurable_set_support hg) }
end

/-- To prove something for an arbitrary integrable function in a second countable
Borel normed group, it suffices to show that
* the property holds for (multiples of) characteristic functions;
* is closed under addition;
* the set of functions in the `L¹` space for which the property holds is closed.
* the property is closed under the almost-everywhere equal relation.

It is possible to make the hypotheses in the induction steps a bit stronger, and such conditions
can be added once we need them (for example in `h_add` it is only necessary to consider the sum of
a simple function with a multiple of a characteristic function and that the intersection
of their images is a subset of `{0}`).
-/
@[elab_as_eliminator]
lemma integrable.induction (P : (α → E) → Prop)
  (h_ind : ∀ (c : E) ⦃s⦄, measurable_set s → μ s < ∞ → P (s.indicator (λ _, c)))
  (h_add : ∀ ⦃f g : α → E⦄, disjoint (support f) (support g) → integrable f μ → integrable g μ →
    P f → P g → P (f + g))
  (h_closed : is_closed {f : α →₁[μ] E | P f} )
  (h_ae : ∀ ⦃f g⦄, f =ᵐ[μ] g → integrable f μ → P f → P g) :
  ∀ ⦃f : α → E⦄ (hf : integrable f μ), P f :=
begin
  have : ∀ (f : simple_func α E), integrable f μ → P f,
  { refine simple_func.induction _ _,
    { intros c s hs h, dsimp only [simple_func.coe_const, simple_func.const_zero,
        piecewise_eq_indicator, simple_func.coe_zero, simple_func.coe_piecewise] at h ⊢,
      by_cases hc : c = 0,
      { subst hc, convert h_ind 0 measurable_set.empty (by simp) using 1, simp [const] },
      apply h_ind c hs,
      have : (nnnorm c : ℝ≥0∞) * μ s < ∞,
      { have := @comp_indicator _ _ _ _ (λ x : E, (nnnorm x : ℝ≥0∞)) (const α c) s,
        dsimp only at this,
        have h' := h.has_finite_integral,
        simpa [has_finite_integral, this, lintegral_indicator, hs] using h' },
      exact ennreal.lt_top_of_mul_lt_top_right this (by simp [hc]) },
    { intros f g hfg hf hg int_fg,
      rw [simple_func.coe_add, integrable_add hfg f.measurable g.measurable] at int_fg,
      refine h_add hfg int_fg.1 int_fg.2 (hf int_fg.1) (hg int_fg.2) } },
  have : ∀ (f : α →₁ₛ[μ] E), P f,
  { intro f,
    exact h_ae (L1.simple_func.to_simple_func_eq_to_fun f) (L1.simple_func.integrable f)
      (this (L1.simple_func.to_simple_func f) (L1.simple_func.integrable f)) },
  have : ∀ (f : α →₁[μ] E), P f :=
    λ f, L1.simple_func.dense_range.induction_on f h_closed this,
  exact λ f hf, h_ae hf.coe_fn_to_L1 (L1.integrable_coe_fn _) (this (hf.to_L1 f)),
end

variables [complete_space E] [normed_space ℝ E]

lemma set_integral_congr_ae (hs : measurable_set s) (h : ∀ᵐ x ∂μ, x ∈ s → f x = g x) :
  ∫ x in s, f x ∂μ = ∫ x in s, g x ∂μ :=
integral_congr_ae ((ae_restrict_iff' hs).2 h)

lemma set_integral_congr (hs : measurable_set s) (h : eq_on f g s) :
  ∫ x in s, f x ∂μ = ∫ x in s, g x ∂μ :=
set_integral_congr_ae hs $ eventually_of_forall h

lemma integral_union (hst : disjoint s t) (hs : measurable_set s) (ht : measurable_set t)
  (hfs : integrable_on f s μ) (hft : integrable_on f t μ) :
  ∫ x in s ∪ t, f x ∂μ = ∫ x in s, f x ∂μ + ∫ x in t, f x ∂μ :=
by simp only [integrable_on, measure.restrict_union hst hs ht, integral_add_measure hfs hft]

lemma integral_empty : ∫ x in ∅, f x ∂μ = 0 := by rw [measure.restrict_empty, integral_zero_measure]

lemma integral_univ : ∫ x in univ, f x ∂μ = ∫ x, f x ∂μ := by rw [measure.restrict_univ]

lemma integral_add_compl (hs : measurable_set s) (hfi : integrable f μ) :
  ∫ x in s, f x ∂μ + ∫ x in sᶜ, f x ∂μ = ∫ x, f x ∂μ :=
by rw [← integral_union (@disjoint_compl_right (set α) _ _) hs hs.compl
    hfi.integrable_on hfi.integrable_on, union_compl_self, integral_univ]

/-- For a function `f` and a measurable set `s`, the integral of `indicator s f`
over the whole space is equal to `∫ x in s, f x ∂μ` defined as `∫ x, f x ∂(μ.restrict s)`. -/
lemma integral_indicator (hs : measurable_set s) :
  ∫ x, indicator s f x ∂μ = ∫ x in s, f x ∂μ :=
begin
  by_cases hf : ae_measurable f (μ.restrict s), swap,
  { rw integral_non_ae_measurable hf,
    rw [ae_measurable_indicator_iff hs] at hf,
    exact integral_non_ae_measurable hf },
  by_cases hfi : integrable_on f s μ, swap,
  { rwa [integral_undef, integral_undef],
    rwa integrable_indicator_iff hs },
  calc ∫ x, indicator s f x ∂μ = ∫ x in s, indicator s f x ∂μ + ∫ x in sᶜ, indicator s f x ∂μ :
    (integral_add_compl hs (hfi.indicator hs)).symm
  ... = ∫ x in s, f x ∂μ + ∫ x in sᶜ, 0 ∂μ :
    congr_arg2 (+) (integral_congr_ae (indicator_ae_eq_restrict hs))
      (integral_congr_ae (indicator_ae_eq_restrict_compl hs))
  ... = ∫ x in s, f x ∂μ : by simp
end

lemma set_integral_const (c : E) : ∫ x in s, c ∂μ = (μ s).to_real • c :=
by rw [integral_const, measure.restrict_apply_univ]

@[simp]
lemma integral_indicator_const (e : E) ⦃s : set α⦄ (s_meas : measurable_set s) :
  ∫ (a : α), s.indicator (λ (x : α), e) a ∂μ = (μ s).to_real • e :=
by rw [integral_indicator s_meas, ← set_integral_const]

lemma set_integral_map {β} [measurable_space β] {g : α → β} {f : β → E} {s : set β}
  (hs : measurable_set s) (hf : ae_measurable f (measure.map g μ)) (hg : measurable g) :
  ∫ y in s, f y ∂(measure.map g μ) = ∫ x in g ⁻¹' s, f (g x) ∂μ :=
begin
  rw [measure.restrict_map hg hs, integral_map hg (hf.mono_measure _)],
  exact measure.map_mono g measure.restrict_le_self
end

lemma set_integral_map_of_closed_embedding [topological_space α] [borel_space α]
  {β} [measurable_space β] [topological_space β] [borel_space β]
  {g : α → β} {f : β → E} {s : set β} (hs : measurable_set s) (hg : closed_embedding g) :
  ∫ y in s, f y ∂(measure.map g μ) = ∫ x in g ⁻¹' s, f (g x) ∂μ :=
by rw [measure.restrict_map hg.measurable hs, integral_map_of_closed_embedding hg]

lemma norm_set_integral_le_of_norm_le_const_ae {C : ℝ} (hs : μ s < ∞)
  (hC : ∀ᵐ x ∂μ.restrict s, ∥f x∥ ≤ C) :
  ∥∫ x in s, f x ∂μ∥ ≤ C * (μ s).to_real :=
begin
  rw ← measure.restrict_apply_univ at *,
  haveI : finite_measure (μ.restrict s) := ⟨‹_›⟩,
  exact norm_integral_le_of_norm_le_const hC
end

lemma norm_set_integral_le_of_norm_le_const_ae' {C : ℝ} (hs : μ s < ∞)
  (hC : ∀ᵐ x ∂μ, x ∈ s → ∥f x∥ ≤ C) (hfm : ae_measurable f (μ.restrict s)) :
  ∥∫ x in s, f x ∂μ∥ ≤ C * (μ s).to_real :=
begin
  apply norm_set_integral_le_of_norm_le_const_ae hs,
  have A : ∀ᵐ (x : α) ∂μ, x ∈ s → ∥ae_measurable.mk f hfm x∥ ≤ C,
  { filter_upwards [hC, hfm.ae_mem_imp_eq_mk],
    assume a h1 h2 h3,
    rw [← h2 h3],
    exact h1 h3 },
  have B : measurable_set {x | ∥(hfm.mk f) x∥ ≤ C} := hfm.measurable_mk.norm measurable_set_Iic,
  filter_upwards [hfm.ae_eq_mk, (ae_restrict_iff B).2 A],
  assume a h1 h2,
  rwa h1
end

lemma norm_set_integral_le_of_norm_le_const_ae'' {C : ℝ} (hs : μ s < ∞) (hsm : measurable_set s)
  (hC : ∀ᵐ x ∂μ, x ∈ s → ∥f x∥ ≤ C) :
  ∥∫ x in s, f x ∂μ∥ ≤ C * (μ s).to_real :=
norm_set_integral_le_of_norm_le_const_ae hs $ by rwa [ae_restrict_eq hsm, eventually_inf_principal]

lemma norm_set_integral_le_of_norm_le_const {C : ℝ} (hs : μ s < ∞)
  (hC : ∀ x ∈ s, ∥f x∥ ≤ C) (hfm : ae_measurable f (μ.restrict s)) :
  ∥∫ x in s, f x ∂μ∥ ≤ C * (μ s).to_real :=
norm_set_integral_le_of_norm_le_const_ae' hs (eventually_of_forall hC) hfm

lemma norm_set_integral_le_of_norm_le_const' {C : ℝ} (hs : μ s < ∞) (hsm : measurable_set s)
  (hC : ∀ x ∈ s, ∥f x∥ ≤ C) :
  ∥∫ x in s, f x ∂μ∥ ≤ C * (μ s).to_real :=
norm_set_integral_le_of_norm_le_const_ae'' hs hsm $ eventually_of_forall hC

lemma set_integral_eq_zero_iff_of_nonneg_ae {f : α → ℝ} (hf : 0 ≤ᵐ[μ.restrict s] f)
  (hfi : integrable_on f s μ) :
  ∫ x in s, f x ∂μ = 0 ↔ f =ᵐ[μ.restrict s] 0 :=
integral_eq_zero_iff_of_nonneg_ae hf hfi

lemma set_integral_pos_iff_support_of_nonneg_ae {f : α → ℝ} (hf : 0 ≤ᵐ[μ.restrict s] f)
  (hfi : integrable_on f s μ) :
  0 < ∫ x in s, f x ∂μ ↔ 0 < μ (support f ∩ s) :=
begin
  rw [integral_pos_iff_support_of_nonneg_ae hf hfi, restrict_apply_of_null_measurable_set],
  exact hfi.ae_measurable.null_measurable_set (measurable_set_singleton 0).compl
end

end normed_group

section mono

variables {μ : measure α} {f g : α → ℝ} {s : set α}
  (hf : integrable_on f s μ) (hg : integrable_on g s μ)

lemma set_integral_mono_ae_restrict (h : f ≤ᵐ[μ.restrict s] g) :
  ∫ a in s, f a ∂μ ≤ ∫ a in s, g a ∂μ :=
integral_mono_ae hf hg h

lemma set_integral_mono_ae (h : f ≤ᵐ[μ] g) :
  ∫ a in s, f a ∂μ ≤ ∫ a in s, g a ∂μ :=
set_integral_mono_ae_restrict hf hg (ae_restrict_of_ae h)

lemma set_integral_mono_on (hs : measurable_set s) (h : ∀ x ∈ s, f x ≤ g x) :
  ∫ a in s, f a ∂μ ≤ ∫ a in s, g a ∂μ :=
set_integral_mono_ae_restrict hf hg
  (by simp [hs, eventually_le, eventually_inf_principal, ae_of_all _ h])

lemma set_integral_mono (h : f ≤ g) :
  ∫ a in s, f a ∂μ ≤ ∫ a in s, g a ∂μ :=
integral_mono hf hg h

end mono

section nonneg

variables {μ : measure α} {f : α → ℝ} {s : set α}

lemma set_integral_nonneg_of_ae_restrict (hf : 0 ≤ᵐ[μ.restrict s] f) :
  (0:ℝ) ≤ (∫ a in s, f a ∂μ) :=
integral_nonneg_of_ae hf

lemma set_integral_nonneg_of_ae (hf : 0 ≤ᵐ[μ] f) : (0:ℝ) ≤ (∫ a in s, f a ∂μ) :=
set_integral_nonneg_of_ae_restrict (ae_restrict_of_ae hf)

lemma set_integral_nonneg (hs : measurable_set s) (hf : ∀ a, a ∈ s → 0 ≤ f a) :
  (0:ℝ) ≤ (∫ a in s, f a ∂μ) :=
set_integral_nonneg_of_ae_restrict ((ae_restrict_iff' hs).mpr (ae_of_all μ hf))

end nonneg

end measure_theory

open measure_theory asymptotics metric

variables {ι : Type*} [measurable_space E] [normed_group E]

/-- Fundamental theorem of calculus for set integrals: if `μ` is a measure that is finite at a
filter `l` and `f` is a measurable function that has a finite limit `b` at `l ⊓ μ.ae`, then `∫ x in
s i, f x ∂μ = μ (s i) • b + o(μ (s i))` at a filter `li` provided that `s i` tends to `l.lift'
powerset` along `li`. Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in the
actual statement.

Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional
argument `m` with this formula and a proof `of `(λ i, (μ (s i)).to_real) =ᶠ[li] m`. Without these
arguments, `m i = (μ (s i)).to_real` is used in the output. -/
lemma filter.tendsto.integral_sub_linear_is_o_ae
  [normed_space ℝ E] [second_countable_topology E] [complete_space E] [borel_space E]
  {μ : measure α} {l : filter α} [l.is_measurably_generated]
  {f : α → E} {b : E} (h : tendsto f (l ⊓ μ.ae) (𝓝 b))
  (hfm : measurable_at_filter f l μ) (hμ : μ.finite_at_filter l)
  {s : ι → set α} {li : filter ι} (hs : tendsto s li (l.lift' powerset))
  (m : ι → ℝ := λ i, (μ (s i)).to_real)
  (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) :
  is_o (λ i, ∫ x in s i, f x ∂μ - m i • b) m li :=
begin
  suffices : is_o (λ s, ∫ x in s, f x ∂μ - (μ s).to_real • b) (λ s, (μ s).to_real)
    (l.lift' powerset),
    from (this.comp_tendsto hs).congr' (hsμ.mono $ λ a ha, ha ▸ rfl) hsμ,
  refine is_o_iff.2 (λ ε ε₀, _),
  have : ∀ᶠ s in l.lift' powerset, ∀ᶠ x in μ.ae, x ∈ s → f x ∈ closed_ball b ε :=
    eventually_lift'_powerset_eventually.2 (h.eventually $ closed_ball_mem_nhds _ ε₀),
  filter_upwards [hμ.eventually, (hμ.integrable_at_filter_of_tendsto_ae hfm h).eventually,
    hfm.eventually, this],
  simp only [mem_closed_ball, dist_eq_norm],
  intros s hμs h_integrable hfm h_norm,
  rw [← set_integral_const, ← integral_sub h_integrable (integrable_on_const.2 $ or.inr hμs),
    real.norm_eq_abs, abs_of_nonneg ennreal.to_real_nonneg],
  exact norm_set_integral_le_of_norm_le_const_ae' hμs h_norm (hfm.sub ae_measurable_const)
end

/-- Fundamental theorem of calculus for set integrals, `nhds_within` version: if `μ` is a locally
finite measure and `f` is an almost everywhere measurable function that is continuous at a point `a`
within a measurable set `t`, then `∫ x in s i, f x ∂μ = μ (s i) • f a + o(μ (s i))` at a filter `li`
provided that `s i` tends to `(𝓝[t] a).lift' powerset` along `li`.  Since `μ (s i)` is an `ℝ≥0∞`
number, we use `(μ (s i)).to_real` in the actual statement.

Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional
argument `m` with this formula and a proof `of `(λ i, (μ (s i)).to_real) =ᶠ[li] m`. Without these
arguments, `m i = (μ (s i)).to_real` is used in the output. -/
lemma continuous_within_at.integral_sub_linear_is_o_ae
  [topological_space α] [opens_measurable_space α]
  [normed_space ℝ E] [second_countable_topology E] [complete_space E] [borel_space E]
  {μ : measure α} [locally_finite_measure μ] {a : α} {t : set α}
  {f : α → E} (ha : continuous_within_at f t a) (ht : measurable_set t)
  (hfm : measurable_at_filter f (𝓝[t] a) μ)
  {s : ι → set α} {li : filter ι} (hs : tendsto s li ((𝓝[t] a).lift' powerset))
  (m : ι → ℝ := λ i, (μ (s i)).to_real)
  (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) :
  is_o (λ i, ∫ x in s i, f x ∂μ - m i • f a) m li :=
by haveI : (𝓝[t] a).is_measurably_generated := ht.nhds_within_is_measurably_generated _;
exact (ha.mono_left inf_le_left).integral_sub_linear_is_o_ae
  hfm (μ.finite_at_nhds_within a t) hs m hsμ

/-- Fundamental theorem of calculus for set integrals, `nhds` version: if `μ` is a locally finite
measure and `f` is an almost everywhere measurable function that is continuous at a point `a`, then
`∫ x in s i, f x ∂μ = μ (s i) • f a + o(μ (s i))` at `li` provided that `s` tends to `(𝓝 a).lift'
powerset` along `li.  Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in the
actual statement.

Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional
argument `m` with this formula and a proof `of `(λ i, (μ (s i)).to_real) =ᶠ[li] m`. Without these
arguments, `m i = (μ (s i)).to_real` is used in the output. -/
lemma continuous_at.integral_sub_linear_is_o_ae
  [topological_space α] [opens_measurable_space α]
  [normed_space ℝ E] [second_countable_topology E] [complete_space E] [borel_space E]
  {μ : measure α} [locally_finite_measure μ] {a : α}
  {f : α → E} (ha : continuous_at f a) (hfm : measurable_at_filter f (𝓝 a) μ)
  {s : ι → set α} {li : filter ι} (hs : tendsto s li ((𝓝 a).lift' powerset))
  (m : ι → ℝ := λ i, (μ (s i)).to_real)
  (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) :
  is_o (λ i, ∫ x in s i, f x ∂μ - m i • f a) m li :=
(ha.mono_left inf_le_left).integral_sub_linear_is_o_ae hfm (μ.finite_at_nhds a) hs m hsμ

/-- If a function is integrable at `𝓝[s] x` for each point `x` of a compact set `s`, then it is
integrable on `s`. -/
lemma is_compact.integrable_on_of_nhds_within [topological_space α] {μ : measure α} {s : set α}
  (hs : is_compact s) {f : α → E} (hf : ∀ x ∈ s, integrable_at_filter f (𝓝[s] x) μ) :
  integrable_on f s μ :=
is_compact.induction_on hs integrable_on_empty (λ s t hst ht, ht.mono_set hst)
  (λ s t hs ht, hs.union ht) hf

/-- A function which is continuous on a set `s` is almost everywhere measurable with respect to
`μ.restrict s`. -/
lemma continuous_on.ae_measurable [topological_space α] [opens_measurable_space α] [borel_space E]
  {f : α → E} {s : set α} {μ : measure α} (hf : continuous_on f s) (hs : measurable_set s) :
  ae_measurable f (μ.restrict s) :=
begin
  refine ⟨indicator s f, _, (indicator_ae_eq_restrict hs).symm⟩,
  apply measurable_of_is_open,
  assume t ht,
  obtain ⟨u, u_open, hu⟩ : ∃ (u : set α), is_open u ∧ f ⁻¹' t ∩ s = u ∩ s :=
    _root_.continuous_on_iff'.1 hf t ht,
  rw [indicator_preimage, set.ite, hu],
  exact (u_open.measurable_set.inter hs).union ((measurable_zero ht.measurable_set).diff hs)
end

lemma continuous_on.integrable_at_nhds_within
  [topological_space α] [opens_measurable_space α] [borel_space E]
  {μ : measure α} [locally_finite_measure μ] {a : α} {t : set α} {f : α → E}
  (hft : continuous_on f t) (ht : measurable_set t) (ha : a ∈ t) :
  integrable_at_filter f (𝓝[t] a) μ :=
by haveI : (𝓝[t] a).is_measurably_generated := ht.nhds_within_is_measurably_generated _;
exact (hft a ha).integrable_at_filter ⟨_, self_mem_nhds_within, hft.ae_measurable ht⟩
  (μ.finite_at_nhds_within _ _)

/-- Fundamental theorem of calculus for set integrals, `nhds_within` version: if `μ` is a locally
finite measure, `f` is continuous on a measurable set `t`, and `a ∈ t`, then `∫ x in (s i), f x ∂μ =
μ (s i) • f a + o(μ (s i))` at `li` provided that `s i` tends to `(𝓝[t] a).lift' powerset` along
`li`.  Since `μ (s i)` is an `ℝ≥0∞` number, we use `(μ (s i)).to_real` in the actual statement.

Often there is a good formula for `(μ (s i)).to_real`, so the formalization can take an optional
argument `m` with this formula and a proof `of `(λ i, (μ (s i)).to_real) =ᶠ[li] m`. Without these
arguments, `m i = (μ (s i)).to_real` is used in the output. -/
lemma continuous_on.integral_sub_linear_is_o_ae
  [topological_space α] [opens_measurable_space α]
  [normed_space ℝ E] [second_countable_topology E] [complete_space E] [borel_space E]
  {μ : measure α} [locally_finite_measure μ] {a : α} {t : set α}
  {f : α → E} (hft : continuous_on f t) (ha : a ∈ t) (ht : measurable_set t)
  {s : ι → set α} {li : filter ι} (hs : tendsto s li ((𝓝[t] a).lift' powerset))
  (m : ι → ℝ := λ i, (μ (s i)).to_real)
  (hsμ : (λ i, (μ (s i)).to_real) =ᶠ[li] m . tactic.interactive.refl) :
  is_o (λ i, ∫ x in s i, f x ∂μ - m i • f a) m li :=
(hft a ha).integral_sub_linear_is_o_ae ht ⟨t, self_mem_nhds_within, hft.ae_measurable ht⟩ hs m hsμ

/-- A function `f` continuous on a compact set `s` is integrable on this set with respect to any
locally finite measure. -/
lemma continuous_on.integrable_on_compact
  [topological_space α] [opens_measurable_space α] [borel_space E]
  [t2_space α] {μ : measure α} [locally_finite_measure μ]
  {s : set α} (hs : is_compact s) {f : α → E} (hf : continuous_on f s) :
  integrable_on f s μ :=
hs.integrable_on_of_nhds_within $ λ x hx, hf.integrable_at_nhds_within hs.measurable_set hx

/-- A continuous function `f` is integrable on any compact set with respect to any locally finite
measure. -/
lemma continuous.integrable_on_compact
  [topological_space α] [opens_measurable_space α] [t2_space α]
  [borel_space E] {μ : measure α} [locally_finite_measure μ] {s : set α}
  (hs : is_compact s) {f : α → E} (hf : continuous f) :
  integrable_on f s μ :=
hf.continuous_on.integrable_on_compact hs

/-- A continuous function with compact closure of the support is integrable on the whole space. -/
lemma continuous.integrable_of_compact_closure_support
  [topological_space α] [opens_measurable_space α] [t2_space α] [borel_space E]
  {μ : measure α} [locally_finite_measure μ] {f : α → E} (hf : continuous f)
  (hfc : is_compact (closure $ support f)) :
  integrable f μ :=
begin
  rw [← indicator_eq_self.2 (@subset_closure _ _ (support f)),
    integrable_indicator_iff is_closed_closure.measurable_set],
  { exact hf.integrable_on_compact hfc },
  { apply_instance }
end

section
/-! ### Continuous linear maps composed with integration

The goal of this section is to prove that integration commutes with continuous linear maps.
This holds for simple functions. The general result follows from the continuity of all involved
operations on the space `L¹`. Note that composition by a continuous linear map on `L¹` is not just
the composition, as we are dealing with classes of functions, but it has already been defined
as `continuous_linear_map.comp_Lp`. We take advantage of this construction here.
-/

variables {μ : measure α} [normed_space ℝ E]
variables [normed_group F] [normed_space ℝ F]
variables {p : ennreal}

local attribute [instance] fact_one_le_one_ennreal

namespace continuous_linear_map

variables [measurable_space F] [borel_space F]

lemma integrable_comp [opens_measurable_space E] {φ : α → E} (L : E →L[ℝ] F)
  (φ_int : integrable φ μ) : integrable (λ (a : α), L (φ a)) μ :=
((integrable.norm φ_int).const_mul ∥L∥).mono' (L.measurable.comp_ae_measurable φ_int.ae_measurable)
  (eventually_of_forall $ λ a, L.le_op_norm (φ a))

variables [second_countable_topology F] [complete_space F]
[borel_space E] [second_countable_topology E]

lemma integral_comp_Lp (L : E →L[ℝ] F) (φ : Lp E p μ) :
  ∫ a, (L.comp_Lp φ) a ∂μ = ∫ a, L (φ a) ∂μ :=
integral_congr_ae $ coe_fn_comp_Lp _ _

lemma continuous_integral_comp_L1 (L : E →L[ℝ] F) :
  continuous (λ (φ : α →₁[μ] E), ∫ (a : α), L (φ a) ∂μ) :=
begin
  rw ← funext L.integral_comp_Lp,
  exact continuous_integral.comp (L.comp_LpL 1 μ).continuous
end

variables [complete_space E]

lemma integral_comp_comm (L : E →L[ℝ] F) {φ : α → E} (φ_int : integrable φ μ) :
  ∫ a, L (φ a) ∂μ = L (∫ a, φ a ∂μ) :=
begin
  apply integrable.induction (λ φ, ∫ a, L (φ a) ∂μ = L (∫ a, φ a ∂μ)),
  { intros e s s_meas s_finite,
    rw [integral_indicator_const e s_meas, continuous_linear_map.map_smul,
        ← integral_indicator_const (L e) s_meas],
    congr' 1 with a,
    rw set.indicator_comp_of_zero L.map_zero },
  { intros f g H f_int g_int hf hg,
    simp [L.map_add, integral_add f_int g_int,
      integral_add (L.integrable_comp f_int) (L.integrable_comp g_int), hf, hg] },
  { exact is_closed_eq L.continuous_integral_comp_L1 (L.continuous.comp continuous_integral) },
  { intros f g hfg f_int hf,
    convert hf using 1 ; clear hf,
    { exact integral_congr_ae (hfg.fun_comp L).symm },
    { rw integral_congr_ae hfg.symm } },
  all_goals { assumption }
end

lemma integral_apply {H : Type*} [normed_group H] [normed_space ℝ H]
  [second_countable_topology $ H →L[ℝ] E] {φ : α → H →L[ℝ] E} (φ_int : integrable φ μ) (v : H) :
  (∫ a, φ a ∂μ) v = ∫ a, φ a v ∂μ :=
((continuous_linear_map.apply ℝ E v).integral_comp_comm φ_int).symm

lemma integral_comp_comm' (L : E →L[ℝ] F) {K} (hL : antilipschitz_with K L) (φ : α → E) :
  ∫ a, L (φ a) ∂μ = L (∫ a, φ a ∂μ) :=
begin
  by_cases h : integrable φ μ,
  { exact integral_comp_comm L h },
  have : ¬ (integrable (L ∘ φ) μ),
    by rwa lipschitz_with.integrable_comp_iff_of_antilipschitz L.lipschitz hL (L.map_zero),
  simp [integral_undef, h, this]
end

lemma integral_comp_L1_comm (L : E →L[ℝ] F) (φ : α →₁[μ] E) : ∫ a, L (φ a) ∂μ = L (∫ a, φ a ∂μ) :=
L.integral_comp_comm (L1.integrable_coe_fn φ)

end continuous_linear_map

namespace linear_isometry

variables [measurable_space F] [borel_space F] [complete_space E]
[second_countable_topology F] [complete_space F]
[borel_space E] [second_countable_topology E]

lemma integral_comp_comm (L : E →ₗᵢ[ℝ] F) (φ : α → E) :
  ∫ a, L (φ a) ∂μ = L (∫ a, φ a ∂μ) :=
L.to_continuous_linear_map.integral_comp_comm' L.antilipschitz _

end linear_isometry

variables [borel_space E] [second_countable_topology E] [complete_space E]
  [measurable_space F] [borel_space F] [second_countable_topology F] [complete_space F]

@[norm_cast] lemma integral_of_real {𝕜 : Type*} [is_R_or_C 𝕜] [measurable_space 𝕜] [borel_space 𝕜]
  {f : α → ℝ} :
  ∫ a, (f a : 𝕜) ∂μ = ↑∫ a, f a ∂μ :=
linear_isometry.integral_comp_comm (@is_R_or_C.of_real_li 𝕜 _) f

lemma integral_conj {𝕜 : Type*} [is_R_or_C 𝕜] [measurable_space 𝕜] [borel_space 𝕜] {f : α → 𝕜} :
  ∫ a, is_R_or_C.conj (f a) ∂μ = is_R_or_C.conj ∫ a, f a ∂μ :=
linear_isometry.integral_comp_comm (@is_R_or_C.conj_li 𝕜 _) f

lemma fst_integral {f : α → E × F} (hf : integrable f μ) :
  (∫ x, f x ∂μ).1 = ∫ x, (f x).1 ∂μ :=
((continuous_linear_map.fst ℝ E F).integral_comp_comm hf).symm

lemma snd_integral {f : α → E × F} (hf : integrable f μ) :
  (∫ x, f x ∂μ).2 = ∫ x, (f x).2 ∂μ :=
((continuous_linear_map.snd ℝ E F).integral_comp_comm hf).symm

lemma integral_pair {f : α → E} {g : α → F} (hf : integrable f μ) (hg : integrable g μ) :
  ∫ x, (f x, g x) ∂μ = (∫ x, f x ∂μ, ∫ x, g x ∂μ) :=
have _ := hf.prod_mk hg, prod.ext (fst_integral this) (snd_integral this)

lemma integral_smul_const (f : α → ℝ) (c : E) :
  ∫ x, f x • c ∂μ = (∫ x, f x ∂μ) • c :=
begin
  by_cases hf : integrable f μ,
  { exact ((continuous_linear_map.id ℝ ℝ).smul_right c).integral_comp_comm hf },
  { by_cases hc : c = 0,
    { simp only [hc, integral_zero, smul_zero] },
    rw [integral_undef hf, integral_undef, zero_smul],
    simp_rw [integrable_smul_const hc, hf, not_false_iff] }
end

end

/-
namespace integrable

variables [measurable_space α] [measurable_space β] [normed_group E]

protected lemma measure_mono

end integrable

end measure_theory

section integral_on
variables [measurable_space α]
  [normed_group β] [second_countable_topology β] [normed_space ℝ β] [complete_space β]
  [measurable_space β] [borel_space β]
  {s t : set α} {f g : α → β} {μ : measure α}
open set

lemma integral_on_congr (hf : measurable f) (hg : measurable g) (hs : measurable_set s)
  (h : ∀ᵐ a ∂μ, a ∈ s → f a = g a) : ∫ a in s, f a ∂μ = ∫ a in s, g a ∂μ :=
integral_congr_ae hf hg $ _

lemma integral_on_congr_of_set (hsm : measurable_on s f) (htm : measurable_on t f)
  (h : ∀ᵐ a, a ∈ s ↔ a ∈ t) : (∫ a in s, f a) = (∫ a in t, f a) :=
integral_congr_ae hsm htm $ indicator_congr_of_set h

lemma integral_on_add {s : set α} (hfm : measurable_on s f) (hfi : integrable_on s f)
  (hgm : measurable_on s g) (hgi : integrable_on s g) :
  (∫ a in s, f a + g a) = (∫ a in s, f a) + (∫ a in s, g a) :=
by { simp only [indicator_add], exact integral_add hfm hfi hgm hgi }

lemma integral_on_sub (hfm : measurable_on s f) (hfi : integrable_on s f) (hgm : measurable_on s g)
  (hgi : integrable_on s g) : (∫ a in s, f a - g a) = (∫ a in s, f a) - (∫ a in s, g a) :=
by { simp only [indicator_sub], exact integral_sub hfm hfi hgm hgi }

lemma integral_on_le_integral_on_ae {f g : α → ℝ} (hfm : measurable_on s f)
  (hfi : integrable_on s f) (hgm : measurable_on s g) (hgi : integrable_on s g)
  (h : ∀ᵐ a, a ∈ s → f a ≤ g a) :
  (∫ a in s, f a) ≤ (∫ a in s, g a) :=
begin
  apply integral_le_integral_ae hfm hfi hgm hgi,
  apply indicator_le_indicator_ae,
  exact h
end

lemma integral_on_le_integral_on {f g : α → ℝ} (hfm : measurable_on s f) (hfi : integrable_on s f)
  (hgm : measurable_on s g) (hgi : integrable_on s g) (h : ∀ a, a ∈ s → f a ≤ g a) :
  (∫ a in s, f a) ≤ (∫ a in s, g a) :=
integral_on_le_integral_on_ae hfm hfi hgm hgi $ by filter_upwards [] h

lemma integral_on_union (hsm : measurable_on s f) (hsi : integrable_on s f)
  (htm : measurable_on t f) (hti : integrable_on t f) (h : disjoint s t) :
  (∫ a in (s ∪ t), f a) = (∫ a in s, f a) + (∫ a in t, f a) :=
by { rw [indicator_union_of_disjoint h, integral_add hsm hsi htm hti] }

lemma integral_on_union_ae (hs : measurable_set s) (ht : measurable_set t) (hsm : measurable_on s f)
  (hsi : integrable_on s f) (htm : measurable_on t f) (hti : integrable_on t f)
  (h : ∀ᵐ a, a ∉ s ∩ t) :
  (∫ a in (s ∪ t), f a) = (∫ a in s, f a) + (∫ a in t, f a) :=
begin
  have := integral_congr_ae _ _ (indicator_union_ae h f),
  rw [this, integral_add hsm hsi htm hti],
  { exact hsm.union hs ht htm },
  { exact measurable.add hsm htm }
end

lemma integral_on_nonneg_of_ae {f : α → ℝ} (hf : ∀ᵐ a, a ∈ s → 0 ≤ f a) : (0:ℝ) ≤ (∫ a in s, f a) :=
integral_nonneg_of_ae $ by { filter_upwards [hf] λ a h, indicator_nonneg' h }

lemma integral_on_nonneg {f : α → ℝ} (hf : ∀ a, a ∈ s → 0 ≤ f a) : (0:ℝ) ≤ (∫ a in s, f a) :=
integral_on_nonneg_of_ae $ univ_mem_sets' hf

lemma integral_on_nonpos_of_ae {f : α → ℝ} (hf : ∀ᵐ a, a ∈ s → f a ≤ 0) : (∫ a in s, f a) ≤ 0 :=
integral_nonpos_of_nonpos_ae $ by { filter_upwards [hf] λ a h, indicator_nonpos' h }

lemma integral_on_nonpos {f : α → ℝ} (hf : ∀ a, a ∈ s → f a ≤ 0) : (∫ a in s, f a) ≤ 0 :=
integral_on_nonpos_of_ae $ univ_mem_sets' hf

lemma tendsto_integral_on_of_monotone {s : ℕ → set α} {f : α → β} (hsm : ∀i, measurable_set (s i))
  (h_mono : monotone s) (hfm : measurable_on (Union s) f) (hfi : integrable_on (Union s) f) :
  tendsto (λi, ∫ a in (s i), f a) at_top (nhds (∫ a in (Union s), f a)) :=
let bound : α → ℝ := indicator (Union s) (λa, ∥f a∥) in
begin
  apply tendsto_integral_of_dominated_convergence,
  { assume i, exact hfm.subset (hsm i) (subset_Union _ _) },
  { assumption },
  { show integrable_on (Union s) (λa, ∥f a∥), rwa integrable_on_norm_iff },
  { assume i, apply ae_of_all,
    assume a,
    rw [norm_indicator_eq_indicator_norm],
    exact indicator_le_indicator_of_subset (subset_Union _ _) (λa, norm_nonneg _) _ },
  { filter_upwards [] λa, le_trans (tendsto_indicator_of_monotone _ h_mono _ _) (pure_le_nhds _) }
end

lemma tendsto_integral_on_of_antimono (s : ℕ → set α) (f : α → β) (hsm : ∀i, measurable_set (s i))
  (h_mono : ∀i j, i ≤ j → s j ⊆ s i) (hfm : measurable_on (s 0) f) (hfi : integrable_on (s 0) f) :
  tendsto (λi, ∫ a in (s i), f a) at_top (nhds (∫ a in (Inter s), f a)) :=
let bound : α → ℝ := indicator (s 0) (λa, ∥f a∥) in
begin
  apply tendsto_integral_of_dominated_convergence,
  { assume i, refine hfm.subset (hsm i) (h_mono _ _ (zero_le _)) },
  { exact hfm.subset (measurable_set.Inter hsm) (Inter_subset _ _) },
  { show integrable_on (s 0) (λa, ∥f a∥), rwa integrable_on_norm_iff },
  { assume i, apply ae_of_all,
    assume a,
    rw [norm_indicator_eq_indicator_norm],
    refine indicator_le_indicator_of_subset (h_mono _ _ (zero_le _)) (λa, norm_nonneg _) _ },
  { filter_upwards [] λa, le_trans (tendsto_indicator_of_antimono _ h_mono _ _) (pure_le_nhds _) }
end

-- TODO : prove this for an encodable type
-- by proving an encodable version of `filter.is_countably_generated_at_top_finset_nat `
lemma integral_on_Union (s : ℕ → set α) (f : α → β) (hm : ∀i, measurable_set (s i))
  (hd : ∀ i j, i ≠ j → s i ∩ s j = ∅) (hfm : measurable_on (Union s) f)
  (hfi : integrable_on (Union s) f) :
  (∫ a in (Union s), f a) = ∑'i, ∫ a in s i, f a :=
suffices h : tendsto (λn:finset ℕ, ∑ i in n, ∫ a in s i, f a) at_top (𝓝 $ (∫ a in (Union s), f a)),
  by { rwa has_sum.tsum_eq },
begin
  have : (λn:finset ℕ, ∑ i in n, ∫ a in s i, f a) = λn:finset ℕ, ∫ a in (⋃i∈n, s i), f a,
  { funext,
    rw [← integral_finset_sum, indicator_finset_bUnion],
    { assume i hi j hj hij, exact hd i j hij },
    { assume i, refine hfm.subset (hm _) (subset_Union _ _) },
    { assume i, refine hfi.subset (subset_Union _ _) } },
  rw this,
  refine tendsto_integral_filter_of_dominated_convergence _ _ _ _ _ _ _,
  { exact indicator (Union s) (λ a, ∥f a∥) },
  { exact is_countably_generated_at_top_finset_nat },
  { refine univ_mem_sets' (λ n, _),
    simp only [mem_set_of_eq],
    refine hfm.subset (measurable_set.Union (λ i, measurable_set.Union_Prop (λh, hm _)))
      (bUnion_subset_Union _ _), },
  { assumption },
  { refine univ_mem_sets' (λ n, univ_mem_sets' $ _),
    simp only [mem_set_of_eq],
    assume a,
    rw ← norm_indicator_eq_indicator_norm,
    refine norm_indicator_le_of_subset (bUnion_subset_Union _ _) _ _ },
  { rw [← integrable_on, integrable_on_norm_iff], assumption },
  { filter_upwards [] λa, le_trans (tendsto_indicator_bUnion_finset _ _ _) (pure_le_nhds _) }
end

end integral_on
-/


/-
Copyright (c) 2018 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/
import data.finset.lattice

/-!
# The powerset of a finset
-/

namespace finset
open multiset

variables {α : Type*}

/-! ### powerset -/
section powerset

/-- When `s` is a finset, `s.powerset` is the finset of all subsets of `s` (seen as finsets). -/
def powerset (s : finset α) : finset (finset α) :=
⟨s.1.powerset.pmap finset.mk
  (λ t h, nodup_of_le (mem_powerset.1 h) s.2),
 nodup_pmap (λ a ha b hb, congr_arg finset.val)
   (nodup_powerset.2 s.2)⟩

@[simp] theorem mem_powerset {s t : finset α} : s ∈ powerset t ↔ s ⊆ t :=
by cases s; simp only [powerset, mem_mk, mem_pmap, mem_powerset, exists_prop, exists_eq_right];
  rw ← val_le_iff

@[simp] theorem empty_mem_powerset (s : finset α) : ∅ ∈ powerset s :=
mem_powerset.2 (empty_subset _)

@[simp] theorem mem_powerset_self (s : finset α) : s ∈ powerset s :=
mem_powerset.2 (subset.refl _)

@[simp] lemma powerset_empty : finset.powerset (∅ : finset α) = {∅} := rfl

@[simp] theorem powerset_mono {s t : finset α} : powerset s ⊆ powerset t ↔ s ⊆ t :=
⟨λ h, (mem_powerset.1 $ h $ mem_powerset_self _),
 λ st u h, mem_powerset.2 $ subset.trans (mem_powerset.1 h) st⟩

/-- **Number of Subsets of a Set** -/
@[simp] theorem card_powerset (s : finset α) :
  card (powerset s) = 2 ^ card s :=
(card_pmap _ _ _).trans (card_powerset s.1)

lemma not_mem_of_mem_powerset_of_not_mem {s t : finset α} {a : α}
  (ht : t ∈ s.powerset) (h : a ∉ s) : a ∉ t :=
by { apply mt _ h, apply mem_powerset.1 ht }

lemma powerset_insert [decidable_eq α] (s : finset α) (a : α) :
  powerset (insert a s) = s.powerset ∪ s.powerset.image (insert a) :=
begin
  ext t,
  simp only [exists_prop, mem_powerset, mem_image, mem_union, subset_insert_iff],
  by_cases h : a ∈ t,
  { split,
    { exact λH, or.inr ⟨_, H, insert_erase h⟩ },
    { intros H,
      cases H,
      { exact subset.trans (erase_subset a t) H },
      { rcases H with ⟨u, hu⟩,
        rw ← hu.2,
        exact subset.trans (erase_insert_subset a u) hu.1 } } },
  { have : ¬ ∃ (u : finset α), u ⊆ s ∧ insert a u = t,
      by simp [ne.symm (ne_insert_of_not_mem _ _ h)],
    simp [finset.erase_eq_of_not_mem h, this] }
end

/-- For predicate `p` decidable on subsets, it is decidable whether `p` holds for any subset. -/
instance decidable_exists_of_decidable_subsets {s : finset α} {p : Π t ⊆ s, Prop}
  [Π t (h : t ⊆ s), decidable (p t h)] : decidable (∃ t (h : t ⊆ s), p t h) :=
decidable_of_iff (∃ t (hs : t ∈ s.powerset), p t (mem_powerset.1 hs))
⟨(λ ⟨t, _, hp⟩, ⟨t, _, hp⟩), (λ ⟨t, hs, hp⟩, ⟨t, mem_powerset.2 hs, hp⟩)⟩

/-- For predicate `p` decidable on subsets, it is decidable whether `p` holds for every subset. -/
instance decidable_forall_of_decidable_subsets {s : finset α} {p : Π t ⊆ s, Prop}
  [Π t (h : t ⊆ s), decidable (p t h)] : decidable (∀ t (h : t ⊆ s), p t h) :=
decidable_of_iff (∀ t (h : t ∈ s.powerset), p t (mem_powerset.1 h))
⟨(λ h t hs, h t (mem_powerset.2 hs)), (λ h _ _, h _ _)⟩

/-- A version of `finset.decidable_exists_of_decidable_subsets` with a non-dependent `p`.
Typeclass inference cannot find `hu` here, so this is not an instance. -/
def decidable_exists_of_decidable_subsets' {s : finset α} {p : finset α → Prop}
  (hu : Π t (h : t ⊆ s), decidable (p t)) : decidable (∃ t (h : t ⊆ s), p t) :=
@finset.decidable_exists_of_decidable_subsets _ _ _ hu

/-- A version of `finset.decidable_forall_of_decidable_subsets` with a non-dependent `p`.
Typeclass inference cannot find `hu` here, so this is not an instance. -/
def decidable_forall_of_decidable_subsets' {s : finset α} {p : finset α → Prop}
  (hu : Π t (h : t ⊆ s), decidable (p t)) : decidable (∀ t (h : t ⊆ s), p t) :=
@finset.decidable_forall_of_decidable_subsets _ _ _ hu

end powerset

section ssubsets
variables [decidable_eq α]

/-- For `s` a finset, `s.ssubsets` is the finset comprising strict subsets of `s`. -/
def ssubsets (s : finset α) : finset (finset α) :=
erase (powerset s) s

@[simp] lemma mem_ssubsets {s t : finset α} : t ∈ s.ssubsets ↔ t ⊂ s :=
by rw [ssubsets, mem_erase, mem_powerset, ssubset_iff_subset_ne, and.comm]

lemma empty_mem_ssubsets {s : finset α} (h : s.nonempty) : ∅ ∈ s.ssubsets :=
by { rw [mem_ssubsets, ssubset_iff_subset_ne], exact ⟨empty_subset s, h.ne_empty.symm⟩, }

/-- For predicate `p` decidable on ssubsets, it is decidable whether `p` holds for any ssubset. -/
instance decidable_exists_of_decidable_ssubsets {s : finset α} {p : Π t ⊂ s, Prop}
  [Π t (h : t ⊂ s), decidable (p t h)] : decidable (∃ t h, p t h) :=
decidable_of_iff (∃ t (hs : t ∈ s.ssubsets), p t (mem_ssubsets.1 hs))
⟨(λ ⟨t, _, hp⟩, ⟨t, _, hp⟩), (λ ⟨t, hs, hp⟩, ⟨t, mem_ssubsets.2 hs, hp⟩)⟩

/-- For predicate `p` decidable on ssubsets, it is decidable whether `p` holds for every ssubset. -/
instance decidable_forall_of_decidable_ssubsets {s : finset α} {p : Π t ⊂ s, Prop}
  [Π t (h : t ⊂ s), decidable (p t h)] : decidable (∀ t h, p t h) :=
decidable_of_iff (∀ t (h : t ∈ s.ssubsets), p t (mem_ssubsets.1 h))
⟨(λ h t hs, h t (mem_ssubsets.2 hs)), (λ h _ _, h _ _)⟩

/-- A version of `finset.decidable_exists_of_decidable_ssubsets` with a non-dependent `p`.
Typeclass inference cannot find `hu` here, so this is not an instance. -/
def decidable_exists_of_decidable_ssubsets' {s : finset α} {p : finset α → Prop}
  (hu : Π t (h : t ⊂ s), decidable (p t)) : decidable (∃ t (h : t ⊂ s), p t) :=
@finset.decidable_exists_of_decidable_ssubsets _ _ _ _ hu

/-- A version of `finset.decidable_forall_of_decidable_ssubsets` with a non-dependent `p`.
Typeclass inference cannot find `hu` here, so this is not an instance. -/
def decidable_forall_of_decidable_ssubsets' {s : finset α} {p : finset α → Prop}
  (hu : Π t (h : t ⊂ s), decidable (p t)) : decidable (∀ t (h : t ⊂ s), p t) :=
@finset.decidable_forall_of_decidable_ssubsets _ _ _ _ hu

end ssubsets

section powerset_len

/-- Given an integer `n` and a finset `s`, then `powerset_len n s` is the finset of subsets of `s`
of cardinality `n`. -/
def powerset_len (n : ℕ) (s : finset α) : finset (finset α) :=
⟨(s.1.powerset_len n).pmap finset.mk
  (λ t h, nodup_of_le (mem_powerset_len.1 h).1 s.2),
 nodup_pmap (λ a ha b hb, congr_arg finset.val)
   (nodup_powerset_len s.2)⟩

/-- **Formula for the Number of Combinations** -/
theorem mem_powerset_len {n} {s t : finset α} :
  s ∈ powerset_len n t ↔ s ⊆ t ∧ card s = n :=
by cases s; simp [powerset_len, val_le_iff.symm]; refl

@[simp] theorem powerset_len_mono {n} {s t : finset α} (h : s ⊆ t) :
  powerset_len n s ⊆ powerset_len n t :=
λ u h', mem_powerset_len.2 $
  and.imp (λ h₂, subset.trans h₂ h) id (mem_powerset_len.1 h')

/-- **Formula for the Number of Combinations** -/
@[simp] theorem card_powerset_len (n : ℕ) (s : finset α) :
  card (powerset_len n s) = nat.choose (card s) n :=
(card_pmap _ _ _).trans (card_powerset_len n s.1)

@[simp] lemma powerset_len_zero (s : finset α) : finset.powerset_len 0 s = {∅} :=
begin
  ext, rw [mem_powerset_len, mem_singleton, card_eq_zero],
  refine ⟨λ h, h.2, λ h, by { rw h, exact ⟨empty_subset s, rfl⟩ }⟩,
end

@[simp] theorem powerset_len_empty (n : ℕ) {s : finset α} (h : s.card < n) :
  powerset_len n s = ∅ :=
finset.card_eq_zero.mp (by rw [card_powerset_len, nat.choose_eq_zero_of_lt h])

theorem powerset_len_eq_filter {n} {s : finset α} :
  powerset_len n s = (powerset s).filter (λ x, x.card = n) :=
by { ext, simp [mem_powerset_len] }

lemma powerset_len_succ_insert [decidable_eq α] {x : α} {s : finset α} (h : x ∉ s) (n : ℕ) :
  powerset_len n.succ (insert x s) = powerset_len n.succ s ∪ (powerset_len n s).image (insert x) :=
begin
  rw [powerset_len_eq_filter, powerset_insert, filter_union, ←powerset_len_eq_filter],
  congr,
  rw [powerset_len_eq_filter, image_filter],
  congr' 1,
  ext t,
  simp only [mem_powerset, mem_filter, function.comp_app, and.congr_right_iff],
  intro ht,
  have : x ∉ t := λ H, h (ht H),
  simp [card_insert_of_not_mem this, nat.succ_inj']
end

lemma powerset_len_nonempty {n : ℕ} {s : finset α} (h : n < s.card) :
  (powerset_len n s).nonempty :=
begin
  classical,
  induction s using finset.induction_on with x s hx IH generalizing n,
  { simpa using h },
  { cases n,
    { simp },
    { rw [card_insert_of_not_mem hx, nat.succ_lt_succ_iff] at h,
      rw powerset_len_succ_insert hx,
      refine nonempty.mono _ ((IH h).image (insert x)),
      convert (subset_union_right _ _) } }
end

@[simp] lemma powerset_len_self (s : finset α) :
  powerset_len s.card s = {s} :=
begin
  ext,
  rw [mem_powerset_len, mem_singleton],
  split,
  { exact λ ⟨hs, hc⟩, eq_of_subset_of_card_le hs hc.ge },
  { rintro rfl,
    simp }
end

lemma powerset_card_bUnion [decidable_eq (finset α)] (s : finset α) :
  finset.powerset s = (range (s.card + 1)).bUnion (λ i, powerset_len i s) :=
begin
  refine ext (λ a, ⟨λ ha, _, λ ha, _ ⟩),
  { rw mem_bUnion,
    exact ⟨a.card, mem_range.mpr (nat.lt_succ_of_le (card_le_of_subset (mem_powerset.mp ha))),
      mem_powerset_len.mpr ⟨mem_powerset.mp ha, rfl⟩⟩ },
  { rcases mem_bUnion.mp ha with ⟨i, hi, ha⟩,
    exact mem_powerset.mpr (mem_powerset_len.mp ha).1, }
end

lemma powerset_len_sup [decidable_eq α] (u : finset α) (n : ℕ) (hn : n < u.card) :
  (powerset_len n.succ u).sup id = u :=
begin
  apply le_antisymm,
  { simp_rw [sup_le_iff, mem_powerset_len],
    rintros x ⟨h, -⟩,
    exact h },
  { rw [sup_eq_bUnion, le_iff_subset, subset_iff],
    cases (nat.succ_le_of_lt hn).eq_or_lt with h' h',
    { simp [h'] },
    { intros x hx,
      simp only [mem_bUnion, exists_prop, id.def],
      obtain ⟨t, ht⟩ : ∃ t, t ∈ powerset_len n (u.erase x) := powerset_len_nonempty _,
      { refine ⟨insert x t, _, mem_insert_self _ _⟩,
        rw [←insert_erase hx, powerset_len_succ_insert (not_mem_erase _ _)],
        exact mem_union_right _ (mem_image_of_mem _ ht) },
      { rwa [card_erase_of_mem hx, nat.lt_pred_iff] } } }
end

end powerset_len
end finset


/-
Copyright (c) 2022 Thomas Browning. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Thomas Browning
-/

import group_theory.complement
import tactic.group

/-!
# Schreier's Lemma

In this file we prove Schreier's lemma.

## Main results

- `closure_mul_eq` : **Schreier's Lemma**: If `R` is a right_transversal of `H : subgroup G`
  with `1 ∈ R`, and if `G` is generated by `S : set G`, then `H` is generated by the set
  `(R * S).image (λ g, g * (mem_right_transversals.to_fun hR g)⁻¹)`.
-/

open_locale pointwise

namespace subgroup

variables {G : Type*} [group G] {H : subgroup G} {R S : set G}

lemma closure_mul_eq_top
  (hR : R ∈ right_transversals (H : set G)) (hR1 : (1 : G) ∈ R) (hS : closure S = ⊤) :
  (closure ((R * S).image (λ g, g * (mem_right_transversals.to_fun hR g)⁻¹)) : set G) * R = ⊤ :=
begin
  let f : G → R := λ g, mem_right_transversals.to_fun hR g,
  let U : set G := (R * S).image (λ g, g * (f g)⁻¹),
  change (closure U : set G) * R = ⊤,
  refine top_le_iff.mp (λ g hg, _),
  apply closure_induction_right (eq_top_iff.mp hS (mem_top g)),
  { exact ⟨1, 1, (closure U).one_mem, hR1, one_mul 1⟩ },
  { rintros - s hs ⟨u, r, hu, hr, rfl⟩,
    rw show u * r * s = u * ((r * s) * (f (r * s))⁻¹) * f (r * s), by group,
    refine set.mul_mem_mul ((closure U).mul_mem hu _) (f (r * s)).coe_prop,
    exact subset_closure ⟨r * s, set.mul_mem_mul hr hs, rfl⟩ },
  { rintros - s hs ⟨u, r, hu, hr, rfl⟩,
    rw show u * r * s⁻¹ = u * (f (r * s⁻¹) * s * r⁻¹)⁻¹ * f (r * s⁻¹), by group,
    refine set.mul_mem_mul ((closure U).mul_mem hu ((closure U).inv_mem _)) (f (r * s⁻¹)).2,
    refine subset_closure ⟨f (r * s⁻¹) * s, set.mul_mem_mul (f (r * s⁻¹)).2 hs, _⟩,
    rw [mul_right_inj, inv_inj, ←subtype.coe_mk r hr, ←subtype.ext_iff, subtype.coe_mk],
    apply (mem_right_transversals_iff_exists_unique_mul_inv_mem.mp hR (f (r * s⁻¹) * s)).unique
      (mem_right_transversals.mul_inv_to_fun_mem hR (f (r * s⁻¹) * s)),
    rw [mul_assoc, ←inv_inv s, ←mul_inv_rev, inv_inv],
    exact mem_right_transversals.to_fun_mul_inv_mem hR (r * s⁻¹) },
end

/-- **Schreier's Lemma**: If `R` is a right_transversal of `H : subgroup G`
  with `1 ∈ R`, and if `G` is generated by `S : set G`, then `H` is generated by the set
  `(R * S).image (λ g, g * (mem_right_transversals.to_fun hR g)⁻¹)`. -/
lemma closure_mul_eq
  (hR : R ∈ right_transversals (H : set G)) (hR1 : (1 : G) ∈ R) (hS : closure S = ⊤) :
  closure ((R * S).image (λ g, g * (mem_right_transversals.to_fun hR g)⁻¹)) = H :=
begin
  have hU : closure ((R * S).image (λ g, g * (mem_right_transversals.to_fun hR g)⁻¹)) ≤ H,
  { rw closure_le,
    rintros - ⟨g, -, rfl⟩,
    exact mem_right_transversals.mul_inv_to_fun_mem hR g },
  refine le_antisymm hU (λ h hh, _),
  obtain ⟨g, r, hg, hr, rfl⟩ :=
  show h ∈ _, from eq_top_iff.mp (closure_mul_eq_top hR hR1 hS) (mem_top h),
  suffices : (⟨r, hr⟩ : R) = (⟨1, hR1⟩ : R),
  { rwa [show r = 1, from subtype.ext_iff.mp this, mul_one] },
  apply (mem_right_transversals_iff_exists_unique_mul_inv_mem.mp hR r).unique,
  { rw [subtype.coe_mk, mul_inv_self],
    exact H.one_mem },
  { rw [subtype.coe_mk, one_inv, mul_one],
    exact (H.mul_mem_cancel_left (hU hg)).mp hh },
end

end subgroup