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

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

/-!
# Intervals in `pi`-space

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

In this we prove various simple lemmas about intervals in `Π i, α i`. Closed intervals (`Ici x`,
`Iic x`, `Icc x y`) are equal to products of their projections to `α i`, while (semi-)open intervals
usually include the corresponding products as proper subsets.
-/

variable {ι : Type _} {α : ι → Type _}

namespace Set

section PiPreorder

variable [∀ i, Preorder (α i)] (x y : ∀ i, α i)

/- warning: set.pi_univ_Ici -> Set.pi_univ_Ici is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] (x : forall (i : ι), α i), Eq.{succ (max u1 u2)} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ici.{u2} (α i) (_inst_1 i) (x i))) (Set.Ici.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) x)
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : forall (i : ι), Preorder.{u1} (α i)] (x : forall (i : ι), α i), Eq.{max (succ u2) (succ u1)} (Set.{max u2 u1} (forall (i : ι), α i)) (Set.pi.{u2, u1} ι (fun (i : ι) => α i) (Set.univ.{u2} ι) (fun (i : ι) => Set.Ici.{u1} (α i) (_inst_1 i) (x i))) (Set.Ici.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) x)
Case conversion may be inaccurate. Consider using '#align set.pi_univ_Ici Set.pi_univ_Iciₓ'. -/
@[simp]
theorem pi_univ_Ici : (pi univ fun i => Ici (x i)) = Ici x :=
  ext fun y => by simp [Pi.le_def]
#align set.pi_univ_Ici Set.pi_univ_Ici

/- warning: set.pi_univ_Iic -> Set.pi_univ_Iic is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] (x : forall (i : ι), α i), Eq.{succ (max u1 u2)} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Iic.{u2} (α i) (_inst_1 i) (x i))) (Set.Iic.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) x)
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : forall (i : ι), Preorder.{u1} (α i)] (x : forall (i : ι), α i), Eq.{max (succ u2) (succ u1)} (Set.{max u2 u1} (forall (i : ι), α i)) (Set.pi.{u2, u1} ι (fun (i : ι) => α i) (Set.univ.{u2} ι) (fun (i : ι) => Set.Iic.{u1} (α i) (_inst_1 i) (x i))) (Set.Iic.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) x)
Case conversion may be inaccurate. Consider using '#align set.pi_univ_Iic Set.pi_univ_Iicₓ'. -/
@[simp]
theorem pi_univ_Iic : (pi univ fun i => Iic (x i)) = Iic x :=
  ext fun y => by simp [Pi.le_def]
#align set.pi_univ_Iic Set.pi_univ_Iic

/- warning: set.pi_univ_Icc -> Set.pi_univ_Icc is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] (x : forall (i : ι), α i) (y : forall (i : ι), α i), Eq.{succ (max u1 u2)} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Icc.{u2} (α i) (_inst_1 i) (x i) (y i))) (Set.Icc.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) x y)
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : forall (i : ι), Preorder.{u1} (α i)] (x : forall (i : ι), α i) (y : forall (i : ι), α i), Eq.{max (succ u2) (succ u1)} (Set.{max u2 u1} (forall (i : ι), α i)) (Set.pi.{u2, u1} ι (fun (i : ι) => α i) (Set.univ.{u2} ι) (fun (i : ι) => Set.Icc.{u1} (α i) (_inst_1 i) (x i) (y i))) (Set.Icc.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) x y)
Case conversion may be inaccurate. Consider using '#align set.pi_univ_Icc Set.pi_univ_Iccₓ'. -/
@[simp]
theorem pi_univ_Icc : (pi univ fun i => Icc (x i) (y i)) = Icc x y :=
  ext fun y => by simp [Pi.le_def, forall_and]
#align set.pi_univ_Icc Set.pi_univ_Icc

/- warning: set.piecewise_mem_Icc -> Set.piecewise_mem_Icc is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] {s : Set.{u1} ι} [_inst_2 : forall (j : ι), Decidable (Membership.Mem.{u1, u1} ι (Set.{u1} ι) (Set.hasMem.{u1} ι) j s)] {f₁ : forall (i : ι), α i} {f₂ : forall (i : ι), α i} {g₁ : forall (i : ι), α i} {g₂ : forall (i : ι), α i}, (forall (i : ι), (Membership.Mem.{u1, u1} ι (Set.{u1} ι) (Set.hasMem.{u1} ι) i s) -> (Membership.Mem.{u2, u2} (α i) (Set.{u2} (α i)) (Set.hasMem.{u2} (α i)) (f₁ i) (Set.Icc.{u2} (α i) (_inst_1 i) (g₁ i) (g₂ i)))) -> (forall (i : ι), (Not (Membership.Mem.{u1, u1} ι (Set.{u1} ι) (Set.hasMem.{u1} ι) i s)) -> (Membership.Mem.{u2, u2} (α i) (Set.{u2} (α i)) (Set.hasMem.{u2} (α i)) (f₂ i) (Set.Icc.{u2} (α i) (_inst_1 i) (g₁ i) (g₂ i)))) -> (Membership.Mem.{max u1 u2, max u1 u2} (forall (i : ι), α i) (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasMem.{max u1 u2} (forall (i : ι), α i)) (Set.piecewise.{u1, succ u2} ι (fun (i : ι) => α i) s f₁ f₂ (fun (j : ι) => _inst_2 j)) (Set.Icc.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) g₁ g₂))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : forall (i : ι), Preorder.{u1} (α i)] {s : Set.{u2} ι} [_inst_2 : forall (j : ι), Decidable (Membership.mem.{u2, u2} ι (Set.{u2} ι) (Set.instMembershipSet.{u2} ι) j s)] {f₁ : forall (i : ι), α i} {f₂ : forall (i : ι), α i} {g₁ : forall (i : ι), α i} {g₂ : forall (i : ι), α i}, (forall (i : ι), (Membership.mem.{u2, u2} ι (Set.{u2} ι) (Set.instMembershipSet.{u2} ι) i s) -> (Membership.mem.{u1, u1} (α i) (Set.{u1} (α i)) (Set.instMembershipSet.{u1} (α i)) (f₁ i) (Set.Icc.{u1} (α i) (_inst_1 i) (g₁ i) (g₂ i)))) -> (forall (i : ι), (Not (Membership.mem.{u2, u2} ι (Set.{u2} ι) (Set.instMembershipSet.{u2} ι) i s)) -> (Membership.mem.{u1, u1} (α i) (Set.{u1} (α i)) (Set.instMembershipSet.{u1} (α i)) (f₂ i) (Set.Icc.{u1} (α i) (_inst_1 i) (g₁ i) (g₂ i)))) -> (Membership.mem.{max u2 u1, max u2 u1} (forall (i : ι), α i) (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instMembershipSet.{max u2 u1} (forall (i : ι), α i)) (Set.piecewise.{u2, succ u1} ι (fun (i : ι) => α i) s f₁ f₂ (fun (j : ι) => _inst_2 j)) (Set.Icc.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) g₁ g₂))
Case conversion may be inaccurate. Consider using '#align set.piecewise_mem_Icc Set.piecewise_mem_Iccₓ'. -/
/- ./././Mathport/Syntax/Translate/Basic.lean:635:2: warning: expanding binder collection (i «expr ∉ » s) -/
theorem piecewise_mem_Icc {s : Set ι} [∀ j, Decidable (j ∈ s)] {f₁ f₂ g₁ g₂ : ∀ i, α i}
    (h₁ : ∀ i ∈ s, f₁ i ∈ Icc (g₁ i) (g₂ i)) (h₂ : ∀ (i) (_ : i ∉ s), f₂ i ∈ Icc (g₁ i) (g₂ i)) :
    s.piecewise f₁ f₂ ∈ Icc g₁ g₂ :=
  ⟨le_piecewise (fun i hi => (h₁ i hi).1) fun i hi => (h₂ i hi).1,
    piecewise_le (fun i hi => (h₁ i hi).2) fun i hi => (h₂ i hi).2⟩
#align set.piecewise_mem_Icc Set.piecewise_mem_Icc

/- warning: set.piecewise_mem_Icc' -> Set.piecewise_mem_Icc' is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] {s : Set.{u1} ι} [_inst_2 : forall (j : ι), Decidable (Membership.Mem.{u1, u1} ι (Set.{u1} ι) (Set.hasMem.{u1} ι) j s)] {f₁ : forall (i : ι), α i} {f₂ : forall (i : ι), α i} {g₁ : forall (i : ι), α i} {g₂ : forall (i : ι), α i}, (Membership.Mem.{max u1 u2, max u1 u2} (forall (i : ι), α i) (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasMem.{max u1 u2} (forall (i : ι), α i)) f₁ (Set.Icc.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) g₁ g₂)) -> (Membership.Mem.{max u1 u2, max u1 u2} (forall (i : ι), α i) (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasMem.{max u1 u2} (forall (i : ι), α i)) f₂ (Set.Icc.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) g₁ g₂)) -> (Membership.Mem.{max u1 u2, max u1 u2} (forall (i : ι), α i) (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasMem.{max u1 u2} (forall (i : ι), α i)) (Set.piecewise.{u1, succ u2} ι (fun (i : ι) => α i) s f₁ f₂ (fun (j : ι) => _inst_2 j)) (Set.Icc.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) g₁ g₂))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : forall (i : ι), Preorder.{u1} (α i)] {s : Set.{u2} ι} [_inst_2 : forall (j : ι), Decidable (Membership.mem.{u2, u2} ι (Set.{u2} ι) (Set.instMembershipSet.{u2} ι) j s)] {f₁ : forall (i : ι), α i} {f₂ : forall (i : ι), α i} {g₁ : forall (i : ι), α i} {g₂ : forall (i : ι), α i}, (Membership.mem.{max u2 u1, max u2 u1} (forall (i : ι), α i) (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instMembershipSet.{max u2 u1} (forall (i : ι), α i)) f₁ (Set.Icc.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) g₁ g₂)) -> (Membership.mem.{max u2 u1, max u2 u1} (forall (i : ι), α i) (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instMembershipSet.{max u2 u1} (forall (i : ι), α i)) f₂ (Set.Icc.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) g₁ g₂)) -> (Membership.mem.{max u2 u1, max u2 u1} (forall (i : ι), α i) (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instMembershipSet.{max u2 u1} (forall (i : ι), α i)) (Set.piecewise.{u2, succ u1} ι (fun (i : ι) => α i) s f₁ f₂ (fun (j : ι) => _inst_2 j)) (Set.Icc.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => _inst_1 i)) g₁ g₂))
Case conversion may be inaccurate. Consider using '#align set.piecewise_mem_Icc' Set.piecewise_mem_Icc'ₓ'. -/
theorem piecewise_mem_Icc' {s : Set ι} [∀ j, Decidable (j ∈ s)] {f₁ f₂ g₁ g₂ : ∀ i, α i}
    (h₁ : f₁ ∈ Icc g₁ g₂) (h₂ : f₂ ∈ Icc g₁ g₂) : s.piecewise f₁ f₂ ∈ Icc g₁ g₂ :=
  piecewise_mem_Icc (fun i hi => ⟨h₁.1 _, h₁.2 _⟩) fun i hi => ⟨h₂.1 _, h₂.2 _⟩
#align set.piecewise_mem_Icc' Set.piecewise_mem_Icc'

section Nonempty

variable [Nonempty ι]

#print Set.pi_univ_Ioi_subset /-
theorem pi_univ_Ioi_subset : (pi univ fun i => Ioi (x i)) ⊆ Ioi x := fun z hz =>
  ⟨fun i => le_of_lt <| hz i trivial, fun h =>
    Nonempty.elim ‹Nonempty ι› fun i => (h i).not_lt (hz i trivial)⟩
#align set.pi_univ_Ioi_subset Set.pi_univ_Ioi_subset
-/

#print Set.pi_univ_Iio_subset /-
theorem pi_univ_Iio_subset : (pi univ fun i => Iio (x i)) ⊆ Iio x :=
  @pi_univ_Ioi_subset ι (fun i => (α i)ᵒᵈ) _ x _
#align set.pi_univ_Iio_subset Set.pi_univ_Iio_subset
-/

#print Set.pi_univ_Ioo_subset /-
theorem pi_univ_Ioo_subset : (pi univ fun i => Ioo (x i) (y i)) ⊆ Ioo x y := fun x hx =>
  ⟨pi_univ_Ioi_subset _ fun i hi => (hx i hi).1, pi_univ_Iio_subset _ fun i hi => (hx i hi).2⟩
#align set.pi_univ_Ioo_subset Set.pi_univ_Ioo_subset
-/

#print Set.pi_univ_Ioc_subset /-
theorem pi_univ_Ioc_subset : (pi univ fun i => Ioc (x i) (y i)) ⊆ Ioc x y := fun x hx =>
  ⟨pi_univ_Ioi_subset _ fun i hi => (hx i hi).1, fun i => (hx i trivial).2⟩
#align set.pi_univ_Ioc_subset Set.pi_univ_Ioc_subset
-/

#print Set.pi_univ_Ico_subset /-
theorem pi_univ_Ico_subset : (pi univ fun i => Ico (x i) (y i)) ⊆ Ico x y := fun x hx =>
  ⟨fun i => (hx i trivial).1, pi_univ_Iio_subset _ fun i hi => (hx i hi).2⟩
#align set.pi_univ_Ico_subset Set.pi_univ_Ico_subset
-/

end Nonempty

variable [DecidableEq ι]

open Function (update)

/- warning: set.pi_univ_Ioc_update_left -> Set.pi_univ_Ioc_update_left is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] [_inst_2 : DecidableEq.{succ u1} ι] {x : forall (i : ι), α i} {y : forall (i : ι), α i} {i₀ : ι} {m : α i₀}, (LE.le.{u2} (α i₀) (Preorder.toLE.{u2} (α i₀) (_inst_1 i₀)) (x i₀) m) -> (Eq.{succ (max u1 u2)} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (Function.update.{succ u1, succ u2} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_2 a b) x i₀ m i) (y i))) (Inter.inter.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasInter.{max u1 u2} (forall (i : ι), α i)) (setOf.{max u1 u2} (forall (i : ι), α i) (fun (z : forall (i : ι), α i) => LT.lt.{u2} (α i₀) (Preorder.toLT.{u2} (α i₀) (_inst_1 i₀)) m (z i₀))) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (x i) (y i)))))
but is expected to have type
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] [_inst_2 : DecidableEq.{succ u1} ι] {x : forall (i : ι), α i} {y : forall (i : ι), α i} {i₀ : ι} {m : α i₀}, (LE.le.{u2} (α i₀) (Preorder.toLE.{u2} (α i₀) (_inst_1 i₀)) (x i₀) m) -> (Eq.{max (succ u1) (succ u2)} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (Function.update.{succ u1, succ u2} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_2 a b) x i₀ m i) (y i))) (Inter.inter.{max u2 u1} (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instInterSet.{max u1 u2} (forall (i : ι), α i)) (setOf.{max u2 u1} (forall (i : ι), α i) (fun (z : forall (i : ι), α i) => LT.lt.{u2} (α i₀) (Preorder.toLT.{u2} (α i₀) (_inst_1 i₀)) m (z i₀))) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (x i) (y i)))))
Case conversion may be inaccurate. Consider using '#align set.pi_univ_Ioc_update_left Set.pi_univ_Ioc_update_leftₓ'. -/
theorem pi_univ_Ioc_update_left {x y : ∀ i, α i} {i₀ : ι} {m : α i₀} (hm : x i₀ ≤ m) :
    (pi univ fun i => Ioc (update x i₀ m i) (y i)) =
      { z | m < z i₀ } ∩ pi univ fun i => Ioc (x i) (y i) :=
  by
  have : Ioc m (y i₀) = Ioi m ∩ Ioc (x i₀) (y i₀) := by
    rw [← Ioi_inter_Iic, ← Ioi_inter_Iic, ← inter_assoc,
      inter_eq_self_of_subset_left (Ioi_subset_Ioi hm)]
  simp_rw [univ_pi_update i₀ _ _ fun i z => Ioc z (y i), ← pi_inter_compl ({i₀} : Set ι),
    singleton_pi', ← inter_assoc, this]
  rfl
#align set.pi_univ_Ioc_update_left Set.pi_univ_Ioc_update_left

/- warning: set.pi_univ_Ioc_update_right -> Set.pi_univ_Ioc_update_right is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] [_inst_2 : DecidableEq.{succ u1} ι] {x : forall (i : ι), α i} {y : forall (i : ι), α i} {i₀ : ι} {m : α i₀}, (LE.le.{u2} (α i₀) (Preorder.toLE.{u2} (α i₀) (_inst_1 i₀)) m (y i₀)) -> (Eq.{succ (max u1 u2)} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (x i) (Function.update.{succ u1, succ u2} ι α (fun (a : ι) (b : ι) => _inst_2 a b) y i₀ m i))) (Inter.inter.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasInter.{max u1 u2} (forall (i : ι), α i)) (setOf.{max u1 u2} (forall (i : ι), α i) (fun (z : forall (i : ι), α i) => LE.le.{u2} (α i₀) (Preorder.toLE.{u2} (α i₀) (_inst_1 i₀)) (z i₀) m)) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (x i) (y i)))))
but is expected to have type
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] [_inst_2 : DecidableEq.{succ u1} ι] {x : forall (i : ι), α i} {y : forall (i : ι), α i} {i₀ : ι} {m : α i₀}, (LE.le.{u2} (α i₀) (Preorder.toLE.{u2} (α i₀) (_inst_1 i₀)) m (y i₀)) -> (Eq.{max (succ u1) (succ u2)} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (x i) (Function.update.{succ u1, succ u2} ι (fun (a : ι) => α a) (fun (a : ι) (b : ι) => _inst_2 a b) y i₀ m i))) (Inter.inter.{max u2 u1} (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instInterSet.{max u1 u2} (forall (i : ι), α i)) (setOf.{max u2 u1} (forall (i : ι), α i) (fun (z : forall (i : ι), α i) => LE.le.{u2} (α i₀) (Preorder.toLE.{u2} (α i₀) (_inst_1 i₀)) (z i₀) m)) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (x i) (y i)))))
Case conversion may be inaccurate. Consider using '#align set.pi_univ_Ioc_update_right Set.pi_univ_Ioc_update_rightₓ'. -/
theorem pi_univ_Ioc_update_right {x y : ∀ i, α i} {i₀ : ι} {m : α i₀} (hm : m ≤ y i₀) :
    (pi univ fun i => Ioc (x i) (update y i₀ m i)) =
      { z | z i₀ ≤ m } ∩ pi univ fun i => Ioc (x i) (y i) :=
  by
  have : Ioc (x i₀) m = Iic m ∩ Ioc (x i₀) (y i₀) := by
    rw [← Ioi_inter_Iic, ← Ioi_inter_Iic, inter_left_comm,
      inter_eq_self_of_subset_left (Iic_subset_Iic.2 hm)]
  simp_rw [univ_pi_update i₀ y m fun i z => Ioc (x i) z, ← pi_inter_compl ({i₀} : Set ι),
    singleton_pi', ← inter_assoc, this]
  rfl
#align set.pi_univ_Ioc_update_right Set.pi_univ_Ioc_update_right

/- warning: set.disjoint_pi_univ_Ioc_update_left_right -> Set.disjoint_pi_univ_Ioc_update_left_right is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] [_inst_2 : DecidableEq.{succ u1} ι] {x : forall (i : ι), α i} {y : forall (i : ι), α i} {i₀ : ι} {m : α i₀}, Disjoint.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteSemilatticeInf.toPartialOrder.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteLattice.toCompleteSemilatticeInf.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Order.Coframe.toCompleteLattice.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteDistribLattice.toCoframe.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteBooleanAlgebra.toCompleteDistribLattice.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.completeBooleanAlgebra.{max u1 u2} (forall (i : ι), α i))))))) (GeneralizedBooleanAlgebra.toOrderBot.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (BooleanAlgebra.toGeneralizedBooleanAlgebra.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.booleanAlgebra.{max u1 u2} (forall (i : ι), α i)))) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (x i) (Function.update.{succ u1, succ u2} ι α (fun (a : ι) (b : ι) => _inst_2 a b) y i₀ m i))) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (Function.update.{succ u1, succ u2} ι α (fun (a : ι) (b : ι) => _inst_2 a b) x i₀ m i) (y i)))
but is expected to have type
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : forall (i : ι), Preorder.{u2} (α i)] [_inst_2 : DecidableEq.{succ u1} ι] {x : forall (i : ι), α i} {y : forall (i : ι), α i} {i₀ : ι} {m : α i₀}, Disjoint.{max u2 u1} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteSemilatticeInf.toPartialOrder.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteLattice.toCompleteSemilatticeInf.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Order.Coframe.toCompleteLattice.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteDistribLattice.toCoframe.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteBooleanAlgebra.toCompleteDistribLattice.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.instCompleteBooleanAlgebraSet.{max u1 u2} (forall (i : ι), α i))))))) (BoundedOrder.toOrderBot.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Preorder.toLE.{max u2 u1} (Set.{max u1 u2} (forall (i : ι), α i)) (PartialOrder.toPreorder.{max u2 u1} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteSemilatticeInf.toPartialOrder.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteLattice.toCompleteSemilatticeInf.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Order.Coframe.toCompleteLattice.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteDistribLattice.toCoframe.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteBooleanAlgebra.toCompleteDistribLattice.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.instCompleteBooleanAlgebraSet.{max u1 u2} (forall (i : ι), α i))))))))) (CompleteLattice.toBoundedOrder.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Order.Coframe.toCompleteLattice.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteDistribLattice.toCoframe.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (CompleteBooleanAlgebra.toCompleteDistribLattice.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.instCompleteBooleanAlgebraSet.{max u1 u2} (forall (i : ι), α i))))))) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (x i) (Function.update.{succ u1, succ u2} ι (fun (a : ι) => α a) (fun (a : ι) (b : ι) => _inst_2 a b) y i₀ m i))) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (_inst_1 i) (Function.update.{succ u1, succ u2} ι (fun (a : ι) => α a) (fun (a : ι) (b : ι) => _inst_2 a b) x i₀ m i) (y i)))
Case conversion may be inaccurate. Consider using '#align set.disjoint_pi_univ_Ioc_update_left_right Set.disjoint_pi_univ_Ioc_update_left_rightₓ'. -/
theorem disjoint_pi_univ_Ioc_update_left_right {x y : ∀ i, α i} {i₀ : ι} {m : α i₀} :
    Disjoint (pi univ fun i => Ioc (x i) (update y i₀ m i))
      (pi univ fun i => Ioc (update x i₀ m i) (y i)) :=
  by
  rw [disjoint_left]
  rintro z h₁ h₂
  refine' (h₁ i₀ (mem_univ _)).2.not_lt _
  simpa only [Function.update_same] using (h₂ i₀ (mem_univ _)).1
#align set.disjoint_pi_univ_Ioc_update_left_right Set.disjoint_pi_univ_Ioc_update_left_right

end PiPreorder

variable [DecidableEq ι] [∀ i, LinearOrder (α i)]

open Function (update)

/- warning: set.pi_univ_Ioc_update_union -> Set.pi_univ_Ioc_update_union is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : DecidableEq.{succ u1} ι] [_inst_2 : forall (i : ι), LinearOrder.{u2} (α i)] (x : forall (i : ι), α i) (y : forall (i : ι), α i) (i₀ : ι) (m : α i₀), (Membership.Mem.{u2, u2} (α i₀) (Set.{u2} (α i₀)) (Set.hasMem.{u2} (α i₀)) m (Set.Icc.{u2} (α i₀) (PartialOrder.toPreorder.{u2} (α i₀) (SemilatticeInf.toPartialOrder.{u2} (α i₀) (Lattice.toSemilatticeInf.{u2} (α i₀) (LinearOrder.toLattice.{u2} (α i₀) (_inst_2 i₀))))) (x i₀) (y i₀))) -> (Eq.{succ (max u1 u2)} (Set.{max u1 u2} (forall (i : ι), α i)) (Union.union.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasUnion.{max u1 u2} (forall (i : ι), α i)) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (LinearOrder.toLattice.{u2} (α i) (_inst_2 i))))) (x i) (Function.update.{succ u1, succ u2} ι α (fun (a : ι) (b : ι) => _inst_1 a b) y i₀ m i))) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (LinearOrder.toLattice.{u2} (α i) (_inst_2 i))))) (Function.update.{succ u1, succ u2} ι α (fun (a : ι) (b : ι) => _inst_1 a b) x i₀ m i) (y i)))) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (LinearOrder.toLattice.{u2} (α i) (_inst_2 i))))) (x i) (y i))))
but is expected to have type
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : DecidableEq.{succ u1} ι] [_inst_2 : forall (i : ι), LinearOrder.{u2} (α i)] (x : forall (i : ι), α i) (y : forall (i : ι), α i) (i₀ : ι) (m : α i₀), (Membership.mem.{u2, u2} (α i₀) (Set.{u2} (α i₀)) (Set.instMembershipSet.{u2} (α i₀)) m (Set.Icc.{u2} (α i₀) (PartialOrder.toPreorder.{u2} (α i₀) (SemilatticeInf.toPartialOrder.{u2} (α i₀) (Lattice.toSemilatticeInf.{u2} (α i₀) (DistribLattice.toLattice.{u2} (α i₀) (instDistribLattice.{u2} (α i₀) (_inst_2 i₀)))))) (x i₀) (y i₀))) -> (Eq.{max (succ u1) (succ u2)} (Set.{max u1 u2} (forall (i : ι), α i)) (Union.union.{max u2 u1} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.instUnionSet.{max u1 u2} (forall (i : ι), α i)) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (DistribLattice.toLattice.{u2} (α i) (instDistribLattice.{u2} (α i) (_inst_2 i)))))) (x i) (Function.update.{succ u1, succ u2} ι (fun (a : ι) => α a) (fun (a : ι) (b : ι) => _inst_1 a b) y i₀ m i))) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (DistribLattice.toLattice.{u2} (α i) (instDistribLattice.{u2} (α i) (_inst_2 i)))))) (Function.update.{succ u1, succ u2} ι (fun (a : ι) => α a) (fun (a : ι) (b : ι) => _inst_1 a b) x i₀ m i) (y i)))) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (DistribLattice.toLattice.{u2} (α i) (instDistribLattice.{u2} (α i) (_inst_2 i)))))) (x i) (y i))))
Case conversion may be inaccurate. Consider using '#align set.pi_univ_Ioc_update_union Set.pi_univ_Ioc_update_unionₓ'. -/
theorem pi_univ_Ioc_update_union (x y : ∀ i, α i) (i₀ : ι) (m : α i₀) (hm : m ∈ Icc (x i₀) (y i₀)) :
    ((pi univ fun i => Ioc (x i) (update y i₀ m i)) ∪
        pi univ fun i => Ioc (update x i₀ m i) (y i)) =
      pi univ fun i => Ioc (x i) (y i) :=
  by
  simp_rw [pi_univ_Ioc_update_left hm.1, pi_univ_Ioc_update_right hm.2, ← union_inter_distrib_right,
    ← set_of_or, le_or_lt, set_of_true, univ_inter]
#align set.pi_univ_Ioc_update_union Set.pi_univ_Ioc_update_union

/- warning: set.Icc_diff_pi_univ_Ioo_subset -> Set.Icc_diff_pi_univ_Ioo_subset is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : DecidableEq.{succ u1} ι] [_inst_2 : forall (i : ι), LinearOrder.{u2} (α i)] (x : forall (i : ι), α i) (y : forall (i : ι), α i) (x' : forall (i : ι), α i) (y' : forall (i : ι), α i), HasSubset.Subset.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasSubset.{max u1 u2} (forall (i : ι), α i)) (SDiff.sdiff.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (BooleanAlgebra.toHasSdiff.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.booleanAlgebra.{max u1 u2} (forall (i : ι), α i))) (Set.Icc.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (LinearOrder.toLattice.{u2} (α i) (_inst_2 i)))))) x y) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioo.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (LinearOrder.toLattice.{u2} (α i) (_inst_2 i))))) (x' i) (y' i)))) (Union.union.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasUnion.{max u1 u2} (forall (i : ι), α i)) (Set.unionᵢ.{max u1 u2, succ u1} (forall (i : ι), α i) ι (fun (i : ι) => Set.Icc.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (LinearOrder.toLattice.{u2} (α i) (_inst_2 i)))))) x (Function.update.{succ u1, succ u2} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) y i (x' i)))) (Set.unionᵢ.{max u1 u2, succ u1} (forall (i : ι), α i) ι (fun (i : ι) => Set.Icc.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (LinearOrder.toLattice.{u2} (α i) (_inst_2 i)))))) (Function.update.{succ u1, succ u2} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) x i (y' i)) y)))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : DecidableEq.{succ u2} ι] [_inst_2 : forall (i : ι), LinearOrder.{u1} (α i)] (x : forall (i : ι), α i) (y : forall (i : ι), α i) (x' : forall (i : ι), α i) (y' : forall (i : ι), α i), HasSubset.Subset.{max u2 u1} (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instHasSubsetSet.{max u2 u1} (forall (i : ι), α i)) (SDiff.sdiff.{max u2 u1} (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instSDiffSet.{max u2 u1} (forall (i : ι), α i)) (Set.Icc.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => PartialOrder.toPreorder.{u1} (α i) (SemilatticeInf.toPartialOrder.{u1} (α i) (Lattice.toSemilatticeInf.{u1} (α i) (DistribLattice.toLattice.{u1} (α i) (instDistribLattice.{u1} (α i) (_inst_2 i))))))) x y) (Set.pi.{u2, u1} ι (fun (i : ι) => α i) (Set.univ.{u2} ι) (fun (i : ι) => Set.Ioo.{u1} (α i) (PartialOrder.toPreorder.{u1} (α i) (SemilatticeInf.toPartialOrder.{u1} (α i) (Lattice.toSemilatticeInf.{u1} (α i) (DistribLattice.toLattice.{u1} (α i) (instDistribLattice.{u1} (α i) (_inst_2 i)))))) (x' i) (y' i)))) (Union.union.{max u2 u1} (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instUnionSet.{max u2 u1} (forall (i : ι), α i)) (Set.unionᵢ.{max u2 u1, succ u2} (forall (i : ι), α i) ι (fun (i : ι) => Set.Icc.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => PartialOrder.toPreorder.{u1} (α i) (SemilatticeInf.toPartialOrder.{u1} (α i) (Lattice.toSemilatticeInf.{u1} (α i) (DistribLattice.toLattice.{u1} (α i) (instDistribLattice.{u1} (α i) (_inst_2 i))))))) x (Function.update.{succ u2, succ u1} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) y i (x' i)))) (Set.unionᵢ.{max u2 u1, succ u2} (forall (i : ι), α i) ι (fun (i : ι) => Set.Icc.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => PartialOrder.toPreorder.{u1} (α i) (SemilatticeInf.toPartialOrder.{u1} (α i) (Lattice.toSemilatticeInf.{u1} (α i) (DistribLattice.toLattice.{u1} (α i) (instDistribLattice.{u1} (α i) (_inst_2 i))))))) (Function.update.{succ u2, succ u1} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) x i (y' i)) y)))
Case conversion may be inaccurate. Consider using '#align set.Icc_diff_pi_univ_Ioo_subset Set.Icc_diff_pi_univ_Ioo_subsetₓ'. -/
/-- If `x`, `y`, `x'`, and `y'` are functions `Π i : ι, α i`, then
the set difference between the box `[x, y]` and the product of the open intervals `(x' i, y' i)`
is covered by the union of the following boxes: for each `i : ι`, we take
`[x, update y i (x' i)]` and `[update x i (y' i), y]`.

E.g., if `x' = x` and `y' = y`, then this lemma states that the difference between a closed box
`[x, y]` and the corresponding open box `{z | ∀ i, x i < z i < y i}` is covered by the union
of the faces of `[x, y]`. -/
theorem Icc_diff_pi_univ_Ioo_subset (x y x' y' : ∀ i, α i) :
    (Icc x y \ pi univ fun i => Ioo (x' i) (y' i)) ⊆
      (⋃ i : ι, Icc x (update y i (x' i))) ∪ ⋃ i : ι, Icc (update x i (y' i)) y :=
  by
  rintro a ⟨⟨hxa, hay⟩, ha'⟩
  simpa [le_update_iff, update_le_iff, hxa, hay, hxa _, hay _, ← exists_or, not_and_or] using ha'
#align set.Icc_diff_pi_univ_Ioo_subset Set.Icc_diff_pi_univ_Ioo_subset

/- warning: set.Icc_diff_pi_univ_Ioc_subset -> Set.Icc_diff_pi_univ_Ioc_subset is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} {α : ι -> Type.{u2}} [_inst_1 : DecidableEq.{succ u1} ι] [_inst_2 : forall (i : ι), LinearOrder.{u2} (α i)] (x : forall (i : ι), α i) (y : forall (i : ι), α i) (z : forall (i : ι), α i), HasSubset.Subset.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.hasSubset.{max u1 u2} (forall (i : ι), α i)) (SDiff.sdiff.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (BooleanAlgebra.toHasSdiff.{max u1 u2} (Set.{max u1 u2} (forall (i : ι), α i)) (Set.booleanAlgebra.{max u1 u2} (forall (i : ι), α i))) (Set.Icc.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (LinearOrder.toLattice.{u2} (α i) (_inst_2 i)))))) x z) (Set.pi.{u1, u2} ι (fun (i : ι) => α i) (Set.univ.{u1} ι) (fun (i : ι) => Set.Ioc.{u2} (α i) (PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (LinearOrder.toLattice.{u2} (α i) (_inst_2 i))))) (y i) (z i)))) (Set.unionᵢ.{max u1 u2, succ u1} (forall (i : ι), α i) ι (fun (i : ι) => Set.Icc.{max u1 u2} (forall (i : ι), α i) (Pi.preorder.{u1, u2} ι (fun (i : ι) => α i) (fun (i : ι) => PartialOrder.toPreorder.{u2} (α i) (SemilatticeInf.toPartialOrder.{u2} (α i) (Lattice.toSemilatticeInf.{u2} (α i) (LinearOrder.toLattice.{u2} (α i) (_inst_2 i)))))) x (Function.update.{succ u1, succ u2} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) z i (y i))))
but is expected to have type
  forall {ι : Type.{u2}} {α : ι -> Type.{u1}} [_inst_1 : DecidableEq.{succ u2} ι] [_inst_2 : forall (i : ι), LinearOrder.{u1} (α i)] (x : forall (i : ι), α i) (y : forall (i : ι), α i) (z : forall (i : ι), α i), HasSubset.Subset.{max u2 u1} (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instHasSubsetSet.{max u2 u1} (forall (i : ι), α i)) (SDiff.sdiff.{max u2 u1} (Set.{max u2 u1} (forall (i : ι), α i)) (Set.instSDiffSet.{max u2 u1} (forall (i : ι), α i)) (Set.Icc.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => PartialOrder.toPreorder.{u1} (α i) (SemilatticeInf.toPartialOrder.{u1} (α i) (Lattice.toSemilatticeInf.{u1} (α i) (DistribLattice.toLattice.{u1} (α i) (instDistribLattice.{u1} (α i) (_inst_2 i))))))) x z) (Set.pi.{u2, u1} ι (fun (i : ι) => α i) (Set.univ.{u2} ι) (fun (i : ι) => Set.Ioc.{u1} (α i) (PartialOrder.toPreorder.{u1} (α i) (SemilatticeInf.toPartialOrder.{u1} (α i) (Lattice.toSemilatticeInf.{u1} (α i) (DistribLattice.toLattice.{u1} (α i) (instDistribLattice.{u1} (α i) (_inst_2 i)))))) (y i) (z i)))) (Set.unionᵢ.{max u2 u1, succ u2} (forall (i : ι), α i) ι (fun (i : ι) => Set.Icc.{max u2 u1} (forall (i : ι), α i) (Pi.preorder.{u2, u1} ι (fun (i : ι) => α i) (fun (i : ι) => PartialOrder.toPreorder.{u1} (α i) (SemilatticeInf.toPartialOrder.{u1} (α i) (Lattice.toSemilatticeInf.{u1} (α i) (DistribLattice.toLattice.{u1} (α i) (instDistribLattice.{u1} (α i) (_inst_2 i))))))) x (Function.update.{succ u2, succ u1} ι (fun (i : ι) => α i) (fun (a : ι) (b : ι) => _inst_1 a b) z i (y i))))
Case conversion may be inaccurate. Consider using '#align set.Icc_diff_pi_univ_Ioc_subset Set.Icc_diff_pi_univ_Ioc_subsetₓ'. -/
/-- If `x`, `y`, `z` are functions `Π i : ι, α i`, then
the set difference between the box `[x, z]` and the product of the intervals `(y i, z i]`
is covered by the union of the boxes `[x, update z i (y i)]`.

E.g., if `x = y`, then this lemma states that the difference between a closed box
`[x, y]` and the product of half-open intervals `{z | ∀ i, x i < z i ≤ y i}` is covered by the union
of the faces of `[x, y]` adjacent to `x`. -/
theorem Icc_diff_pi_univ_Ioc_subset (x y z : ∀ i, α i) :
    (Icc x z \ pi univ fun i => Ioc (y i) (z i)) ⊆ ⋃ i : ι, Icc x (update z i (y i)) :=
  by
  rintro a ⟨⟨hax, haz⟩, hay⟩
  simpa [not_and_or, hax, le_update_iff, haz _] using hay
#align set.Icc_diff_pi_univ_Ioc_subset Set.Icc_diff_pi_univ_Ioc_subset

end Set


-- Measure theory lemmas

import data.set.basic
import data.set.prod
import data.real.ennreal
import measure_theory.constructions.prod
import measure_theory.measure.complex_lebesgue
import measure_theory.measure.measure_space_def
import measure_theory.integral.average
import topology.subset_properties

import topology

open filter (liminf limsup at_top tendsto)
open function (curry uncurry)
open measure_theory
open metric (ball closed_ball sphere)
open set (Ioc Icc)
open topological_space (second_countable_topology)
open_locale real ennreal topological_space
noncomputable theory

variables {E : Type} [normed_add_comm_group E] [normed_space ℝ E] [complete_space E] [second_countable_topology E]
variables {F : Type} [normed_add_comm_group F] [normed_space ℝ F] [complete_space F]
variables {X : Type} [measure_space X] [metric_space X] [borel_space X]
variables {Y : Type} [measure_space Y] [metric_space Y] [borel_space Y]
variables {A : Type} [topological_space A]

lemma ennreal.le_zero_iff {x : ennreal} : x ≤ 0 ↔ x = 0 := begin
  rw ←ennreal.bot_eq_zero, exact le_bot_iff,
end

-- Implication works under ∀ᵐ
lemma ae_imp {f g : X → Prop} : (∀ᵐ x, f x) → (∀ x, f x → g x) → (∀ᵐ x, g x) := begin
  intros h i,
  rw [ae_iff, ←ennreal.le_zero_iff] at ⊢ h,
  have i' := λ x (ng : ¬g x), mt (i x) ng,
  rw ←set.set_of_subset_set_of at i',
  exact trans (measure_mono i') h,
end

-- We can ignore hypotheses under ∀ᵐ
lemma ae_drop_imp {f g : X → Prop} : (∀ᵐ x, g x) → (∀ᵐ x, f x → g x) := begin
  intro h,
  rw ae_iff at ⊢ h, simp, rw set.set_of_and, rw ←ennreal.le_zero_iff at ⊢ h,
  exact trans (measure_mono (set.inter_subset_right _ _)) h,
end

-- If a set has measure 0, any subset does too
lemma null_subset {s t : set ℝ} (h : s ⊆ t) : volume t = 0 → volume s = 0 := begin
  simp_rw ←ennreal.le_zero_iff, exact trans (measure_mono h),
end

-- Two functions are ae = on a set if the expected ae statement holds
lemma ae_eq_on_def {Y : Type} {f g : X → Y} {s : set X} (m : measurable_set s)
    : f =ᵐ[volume.restrict s] g ↔ ∀ᵐ x, x ∈ s → f x = g x :=
  by rw [filter.eventually_eq, ae_restrict_iff' m]

-- Removing a null set isn't significant measure-wise
lemma ae_minus_null {s t : set X} (tz : volume t = 0) : s =ᵐ[volume] (s \ t) := begin
  simp [filter.eventually_eq],
  have e : ∀ x, x ∉ t → (x ∈ s ↔ x ∈ (s \ t)), { intros x h, simp, finish },
  simp_rw [set.mem_def] at e, refine ae_imp _ e,
  rw [ae_iff], simpa [set.set_of_set],
end

-- Removing a point isn't significant measure-wise (if there are no atoms)
lemma ae_minus_point [has_no_atoms (volume : measure X)] {s : set X} {x : X}
    : s =ᵐ[volume] (s \ {x} : set X) := ae_minus_null (measure_singleton x)

-- ℂ has additive Haar measure
@[instance] def complex.is_add_haar_measure_volume : (volume : measure ℂ).is_add_haar_measure := begin
  have v : (volume : measure ℂ) = volume.map complex.equiv_real_prod_add_hom.symm, {
    have e : (⇑(complex.measurable_equiv_real_prod.symm) : ℝ × ℝ → ℂ) = ⇑(complex.equiv_real_prod_add_hom.symm), {
      apply funext, intro x, rw [complex.ext_iff, complex.measurable_equiv_real_prod], simp,
    },
    rw ←e, clear e,
    exact (measure_preserving.symm _ complex.volume_preserving_equiv_real_prod).map_eq.symm,
  },
  rw v,
  apply measure.is_add_haar_measure_map (volume : measure (ℝ × ℝ)) complex.equiv_real_prod_add_hom.symm, {
    have e : (⇑(complex.equiv_real_prodₗ.symm) : ℝ × ℝ → ℂ) = ⇑(complex.equiv_real_prod_add_hom.symm), {
      apply funext, intro x, rw complex.ext_iff, simp,
    },
    rw ←e, apply continuous_linear_map.continuous,
  }, {
    simp,
    have e : (⇑(complex.equiv_real_prodₗ) : ℂ → ℝ × ℝ) = ⇑(complex.equiv_real_prod_add_hom), {
      apply funext, intro x, simp,
    },
    rw ←e, apply continuous_linear_map.continuous,
  },
end

-- ℂ has no atoms
@[instance] def complex.has_no_atoms_volume : has_no_atoms (volume : measure ℂ) := {
  measure_singleton := begin
    intro z,
    rw ←(measure_preserving.symm _ complex.volume_preserving_equiv_real_prod).measure_preimage,
    rw ←measurable_equiv.image_eq_preimage, simp [measure_singleton],
    apply measurable_set_singleton,
  end,
}

-- Finite, positive measure sets
structure nice_volume (s : set X) : Prop :=
    (measurable : measurable_set s)
    (finite : volume s < ∞)
    (pos : volume s > 0)

-- Useful lemmas about nice_volume
lemma nice_volume.ne_zero {s : set X} (sn : nice_volume s) : volume s ≠ 0 := ne_of_gt sn.pos
lemma nice_volume.ne_top {s : set X} (sn : nice_volume s) : volume s ≠ ⊤ := ne_of_lt sn.finite
lemma nice_volume.real_pos {s : set X} (sn : nice_volume s) : (volume s).to_real > 0 :=
  ennreal.to_real_pos_iff.mpr ⟨sn.pos, sn.finite⟩
lemma nice_volume.real_nonneg {s : set X} (sn : nice_volume s) : (volume s).to_real ≠ 0 := ne_of_gt sn.real_pos

-- Constants are integrable on nice_volume sets
lemma nice_volume.integrable_on_const {s : set X} (sn : nice_volume s) (c : ℝ) : integrable_on (λ _, c) s :=
  integrable_on_const.mpr (or.inr sn.finite)

-- Uniform limits of continuous functions and integrals commute
lemma tendsto_uniformly_on.integral_tendsto {f : ℕ → X → E} {g : X → E} {s : set X}
    [is_locally_finite_measure (volume : measure X)]
    (u : tendsto_uniformly_on f g at_top s) (fc : ∀ n, continuous_on (f n) s) (sc : is_compact s)
    : tendsto (λ n, ∫ x in s, f n x) at_top (nhds (∫ x in s, g x)) := begin
  rcases u.uniform_cauchy_seq_on.bounded fc sc with ⟨b,bp,bh⟩,
  apply @tendsto_integral_of_dominated_convergence _ _ _ _ _ _ _ f g (λ _, b), {
    intro n, exact (fc n).ae_strongly_measurable sc.measurable_set,
  }, {
    exact continuous_on_const.integrable_on_compact sc,
  }, {
    intro n, specialize bh n, simp only, rw ae_restrict_iff' sc.measurable_set, exact ae_of_all _ bh,
  }, {
    rw ae_restrict_iff' sc.measurable_set, apply ae_of_all, intros x xs, exact u.tendsto_at xs,
  },
end

-- An abbreviation for Ioc 0 (2*π)
def Itau := Ioc 0 (2*π)

-- Lemmas about Itau
lemma Itau_volume : volume Itau = ennreal.of_real (2*π) := by simp [Itau]
lemma Itau_real_volume : (volume Itau).to_real = 2*π :=
  by simp [Itau_volume, ennreal.to_real_of_real (le_of_lt real.two_pi_pos)]
lemma nice_volume.Itau : nice_volume Itau := {
  measurable := by simp [Itau],
  finite := by simp [Itau_volume],
  pos := by simp [Itau_volume, real.pi_pos],
}
lemma measurable_set_Itau : measurable_set Itau := by simp [Itau, measurable_set_Ioc]
lemma tau_mem_Itau : 2*π ∈ Itau := by simp [Itau, real.pi_pos]

-- Continuous functions are integrable on spheres
lemma continuous_on.integrable_on_sphere {f : ℂ → E} {c : ℂ} {r : ℝ} (fc : continuous_on f (closed_ball c r)) (rp : r > 0)
    : integrable_on (λ t, f (circle_map c r t)) Itau := begin
  apply continuous.integrable_on_Ioc, apply fc.comp_continuous (continuous_circle_map _ _),
  intro t, simp [complex.dist_eq, abs_of_pos rp],
end

-- Continuous functions are integrable on closed_balls
lemma continuous_on.integrable_on_closed_ball {f : ℂ → E} {c : ℂ} {r : ℝ} (fc : continuous_on f (closed_ball c r))
    : integrable_on f (closed_ball c r) := fc.integrable_on_compact (is_compact_closed_ball _ _)

-- Averages add
lemma set_average.add {f g : X → E} {s : set X} (fi : integrable_on f s) (gi : integrable_on g s)
    : ⨍ z in s, f z + g z = (⨍ z in s, f z) + ⨍ z in s, g z := by simp_rw [set_average_eq, integral_add fi gi, smul_add]

-- Averages subtract
lemma set_average.sub {f g : X → E} {s : set X} (fi : integrable_on f s) (gi : integrable_on g s)
    : ⨍ z in s, f z - g z = (⨍ z in s, f z) - ⨍ z in s, g z := by simp_rw [set_average_eq, integral_sub fi gi, smul_sub]

-- average commutes with linear maps
lemma average_linear_comm {f : X → E} {s : set X} (fi : integrable_on f s) (g : E →L[ℝ] F)
    : ⨍ x in s, g (f x) = g ⨍ x in s, f x := begin
  simp only [set_average_eq, complex.smul_re],
  by_cases v0 : (volume s).to_real = 0, simp [v0],
  rw g.map_smul, rw (ne.is_unit v0).inv.smul_left_cancel,
  exact continuous_linear_map.integral_comp_comm _ fi,
end

-- Averages on a set depend only on ae values within the set
lemma average_congr_on {f g : X → E} {s : set X} (sn : nice_volume s) (h : ∀ᵐ x, x ∈ s → f x = g x)
    : ⨍ x in s, f x = ⨍ x in s, g x := begin
  rw ←ae_eq_on_def sn.measurable at h, exact average_congr h,
end

-- means are at most the values of the function
lemma mean_bound {f : X → ℝ} {s : set X} {b : ℝ}
    (sn : nice_volume s) (fi : integrable_on f s) (fb : ∀ z, z ∈ s → f z ≤ b)
    : ⨍ x in s, f x ≤ b := begin
  rw [set_average_eq, smul_eq_mul],
  have bi : integrable_on (λ _ : X, b) s := sn.integrable_on_const _,
  have ib := set_integral_mono_on fi bi sn.measurable fb,
  simp at ⊢ ib,
  transitivity (volume s).to_real⁻¹ * ((volume s).to_real * b),
  bound [sn.pos],
  rw [←mul_assoc _ _ b, inv_mul_cancel sn.real_nonneg], simp,
end

-- Sets where each point is near positive volume
def local_volume_set (s : set X) := ∀ x r, x ∈ s → r > 0 → volume (s ∩ ball x r) > 0

-- Sets in the closure of their interior have local volume
lemma local_volume.closure_interior (s : set X)
    (bp : ∀ (x : X) r, r > 0 → volume (ball x r) > 0) (ci : s ⊆ closure (interior s))
    : local_volume_set s := begin
  intros x r xs rp,
  have xci := ci xs,
  rcases metric.mem_closure_iff.mp xci r rp with ⟨y,ys,xy⟩,
  rcases metric.is_open_iff.mp is_open_interior y ys with ⟨e,ep,ye⟩,
  set t := min e (r - dist x y),
  have es : ball y t ⊆ s ∩ ball x r, {
    simp, constructor,
    exact trans (metric.ball_subset_ball (by bound)) (trans ye interior_subset),
    apply metric.ball_subset_ball',
    transitivity r - dist x y + dist y x, bound, simp [dist_comm],
  },
  exact lt_of_lt_of_le (bp y t (by bound)) (measure_mono es),
end

-- Intervals have local volume
lemma local_volume.Ioc {a b : ℝ} : local_volume_set (set.Ioc a b) := begin
  apply local_volume.closure_interior,
  intros x r rp, simp, exact rp,
  by_cases ab : a = b, { rw ab, simp },
  simp, rw closure_Ioo ab, simp [set.Ioc_subset_Icc_self],
end
lemma local_volume.Itau : local_volume_set Itau := local_volume.Ioc

-- If an interval mean is above b, and each value is below b, then each value is exactly b
lemma mean_squeeze {f : X → ℝ} {s : set X} {b : ℝ}
    (sn : nice_volume s) (lv : local_volume_set s) (fc : continuous_on f s) (fi : integrable_on f s)
    (lo : b ≤ ⨍ x in s, f x) (hi : ∀ x, x ∈ s → f x ≤ b)
    : ∀ x, x ∈ s → f x = b := begin
  contrapose lo, rw set_average_eq,
  simp, simp only [not_forall] at lo,
  rcases lo with ⟨x,xs,fx'⟩,
  have fx := lt_of_le_of_ne (hi x xs) fx', clear fx',
  rcases metric.continuous_on_iff.mp fc x xs ((b - f x)/2) (by bound) with ⟨e,ep,he⟩,
  have vtp' := lv x e xs ep,
  generalize ht : s ∩ ball x e = t, rw ht at vtp',
  have ts : t ⊆ s, { rw ←ht, exact set.inter_subset_left _ _ },
  have tf : volume t < ⊤ := lt_of_le_of_lt (measure_mono ts) sn.finite,
  have tm : measurable_set t, { rw ←ht, exact measurable_set.inter sn.measurable measurable_set_ball },
  have sc : s \ t ∪ t = s := set.diff_union_of_subset ts,
  nth_rewrite 1 ←sc,
  rw integral_union, {
    set m := (b + f x)/2,
    set vs := (volume s).to_real,
    set vt := (volume t).to_real,
    have vsp : vs > 0 := sn.real_pos,
    have vtp : vt > 0 := ennreal.to_real_pos (ne_of_gt vtp') (lt_top_iff_ne_top.mp tf),
    rw inv_mul_lt_iff' vsp,
    have mb : m < b, {
      calc (b + f x)/2 < (b + b)/2 : (div_lt_div_right (by norm_num)).mpr (by bound)
      ... = b : by ring
    },
    have i0 : (∫ x in s \ t, f x) ≤ (vs - vt) * b, {
      set b' := λ x, b,
      have df : volume (s \ t) < ⊤ := lt_of_le_of_lt (measure_mono (set.diff_subset _ _)) sn.finite,
      have dm : measurable_set (s \ t) := measurable_set.diff sn.measurable tm,
      have fb := @set_integral_mono_on _ _ volume f b' (s \ t) (fi.mono (set.diff_subset _ _) (le_refl _))
        (integrable_on_const.mpr (or.inr df)) dm _,
      simp [measure_diff ts tm (lt_top_iff_ne_top.mp tf),
            ennreal.to_real_sub_of_le (measure_mono ts) (lt_top_iff_ne_top.mp sn.finite)] at fb,
      exact fb,
      intros y yd, simp at yd, exact hi y yd.left,
    },
    have i1 : (∫ x in t, f x) ≤ vt * m, {
      set m' := λ x, m,
      have fm := @set_integral_mono_on _ _ volume f m' t (fi.mono ts (le_refl _))
        (integrable_on_const.mpr (or.inr tf)) tm _,
      simp at fm, exact fm,
      intros y yt,
      rw ←ht at yt, simp at ht yt,
      specialize he y yt.left yt.right,
      simp [real.dist_eq] at he,
      calc f y = f x + (f y - f x) : by ring
      ... ≤ f x + |f y - f x| : by bound [le_abs_self]
      ... ≤ f x + (b - f x)/2 : by bound
      ... = (b + f x)/2 : by ring
    },
    calc (∫ (x : X) in s \ t, f x) + ∫ (x : X) in t, f x
        ≤ (vs - vt) * b + vt * m : by bound
    ... = vs * b - vt * (b - m) : by ring
    ... < vs * b - 0 : sub_lt_sub_left (by bound) _
    ... = b * vs : by ring
  }, {
    rw disjoint.comm, exact set.disjoint_diff,
  }, {
    exact tm,
  }, {
    exact fi.mono (set.diff_subset _ _) (le_refl _),
  }, {
    exact fi.mono ts (le_refl _),
  },
end

lemma continuous_on.interval_integral {f : X → ℝ → E} {s : set X} {a b : ℝ}
    (fc : continuous_on (uncurry f) (s ×ˢ (Icc a b))) (sc : is_compact s) (ab : a ≤ b)
    : continuous_on (λ x, ∫ t in a..b, f x t) s := begin
  rcases fc.bounded_norm (sc.prod is_compact_Icc) with ⟨c,cp,fb⟩,
  simp only [set.forall_prod_set, uncurry] at fb,
  have e : ∀ x t, f x t = (uncurry f) (x,t) := by simp,
  intros x xs,
  apply @interval_integral.continuous_within_at_of_dominated_interval _ _ _ _ _ _ _ _ _ _ (λ _, c), {
    apply eventually_nhds_within_of_forall, intros y ys,
    refine continuous_on.ae_strongly_measurable _ measurable_set_Ioc,
    rw [set.interval_oc_of_le ab], simp_rw e, apply fc.comp, {
      apply continuous.continuous_on, continuity,
    }, {
     intros t ts, exact set.mk_mem_prod ys (set.Ioc_subset_Icc_self ts),
    },
  }, {
    apply eventually_nhds_within_of_forall, intros y ys, rw [set.interval_oc_of_le ab],
    apply ae_of_all, intros t ts, apply fb _ ys _ (set.Ioc_subset_Icc_self ts),
  }, {
    exact interval_integrable_const,
  }, {
    apply ae_of_all, intros t ts, simp_rw e, apply fc.comp, {
      apply continuous.continuous_on, continuity,
    }, {
      rw [set.interval_oc_of_le ab] at ts,
      intros y ys, exact set.mk_mem_prod ys (set.Ioc_subset_Icc_self ts),
    },
    assumption,
  }, {
    apply_instance,
  },
end

-- liminf preserves ae_measurability, general filter version
lemma ae_measurable_liminf' {I I' : Type} {u : filter I} {f : I → X → ennreal} {μ : measure X} {p : I' → Prop} {s : I' → set I}
    (fm : ∀ n, ae_measurable (f n) μ) (uc : u.has_countable_basis p s) (sc : ∀ i, (s i).countable)
    : ae_measurable (λ x, u.liminf (λ n, f n x)) μ := begin
  simp_rw [uc.to_has_basis.liminf_eq_supr_infi],
  refine ae_measurable_bsupr _ uc.countable _,
  exact λ i, ae_measurable_binfi _ (sc i) fm
end

-- liminf preserves ae_measurability, ℕ version
lemma ae_measurable_liminf {f : ℕ → X → ennreal} {μ : measure X} (fm : ∀ n, ae_measurable (f n) μ)
    : ae_measurable (λ x, at_top.liminf (λ n, f n x)) μ :=
  ae_measurable_liminf' fm filter.at_top_countable_basis (λ i, set.to_countable _)

lemma set_lintegral_mono_ae_measurable {s : set X} {f g : X → ennreal}
    (fm : ae_measurable f (volume.restrict s)) (gm : ae_measurable g (volume.restrict s)) (sm : measurable_set s)
    (fg : ∀ x, x ∈ s → f x ≤ g x)
    : ∫⁻ x in s, f x ≤ ∫⁻ x in s, g x := begin
  apply lintegral_mono_ae, rw ae_restrict_iff' sm, exact ae_of_all _ fg,
end


import analysis.inner_product_space.basic
import data.matrix.notation
import linear_algebra.bilinear_form
import linear_algebra.matrix
import tactic

universes u v
noncomputable theory

namespace lftcm

section exercise1

namespace module

open _root_.module

variables (R M : Type*) [comm_semiring R] [add_comm_monoid M] [module R M]

/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Exercise 1: defining modules and submodules
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/

/- The endomorphisms of an `R`-module `M` are the `R`-linear maps from `M` to `M` are defined as:
`def End := M →ₗ[R] M`
-/

/-- The following line tells Lean we can apply `f : End R M` as if it was a function. -/
instance : has_coe_to_fun (End R M) (λ _, M → M) := ⟨linear_map.to_fun⟩

/-- Endomorphisms inherit the pointwise addition operator from linear maps. -/
instance : add_comm_monoid (End R M) := linear_map.add_comm_monoid

/- Define the identity endomorphism `id`. -/
def End.id : End R M :=
sorry

/-
Show that the endomorphisms of `M` form a module over `R`.

Hint: we can re-use the scalar multiplication of linear maps using the `refine` tactic:
```
refine { smul := linear_map.has_scalar.smul, .. },
```
This will fill in the `smul` field of the `module` structure with the given value.
The remaining fields become goals that you can fill in yourself.

Hint: Prove the equalities using the module structure on `M`.
If `f` and `g` are linear maps, the `ext` tactic turns the goal `f = g` into `∀ x, f x = g x`.
-/
instance : module R (End R M) :=
begin
  sorry
end

variables {R M}

/- Bonus exercise: define the submodule of `End R M` consisting of the scalar multiplications.
That is, `f ∈ homothety R M` iff `f` is of the form `λ (x : M), s • x` for some `s : R`.

Hints:
  * You could specify the carrier subset and show it is closed under the operations.
  * You could instead use library functions: try `submodule.map` or `linear_map.range`.
-/
def homothety : submodule R (End R M) :=
sorry

end module

end exercise1

section exercise2

namespace matrix
open _root_.matrix

variables {m n R M : Type} [fintype m] [fintype n] [comm_ring R] [add_comm_group M] [module R M]

/- The following line allows us to write `⬝` (`\cdot`) and `ᵀ` (`\^T`) for
matrix multiplication and transpose. -/
open_locale matrix

/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Exercise 2: working with matrices
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/

/-- Prove the following four lemmas, that used to be missing from `mathlib`.

Hints:
  * Look up the definition of `vec_mul` and `mul_vec`.
  * Search the library for useful lemmas about the function used in that definition.
-/
@[simp] lemma add_vec_mul (v w : m → R) (M : matrix m n R) :
  vec_mul (v + w) M = vec_mul v M + vec_mul w M :=
sorry

@[simp] lemma smul_vec_mul (x : R) (v : m → R) (M : matrix m n R) :
vec_mul (x • v) M = x • vec_mul v M :=
sorry

@[simp] lemma mul_vec_add (M : matrix m n R) (v w : n → R) :
  mul_vec M (v + w) = mul_vec M v + mul_vec M w :=
sorry

@[simp] lemma mul_vec_smul (M : matrix m n R) (x : R) (v : n → R) :
  mul_vec M (x • v) = x • mul_vec M v :=
sorry

/- Define the canonical map from bilinear forms to matrices.
We assume `R` has a basis `v` indexed by `ι`.

Hint: Follow your nose, the types will guide you.
A matrix `A : matrix ι ι R` is not much more than a function `ι → ι → R`,
and a bilinear form is not much more than a function `M → M → R`. -/
def bilin_form_to_matrix {ι : Type*} [fintype ι] (v : ι → M)
  (B : bilin_form R M) : matrix ι ι R :=
sorry

/-- Define the canonical map from matrices to bilinear forms.

For a matrix `A`, `to_bilin_form A` should take two vectors `v`, `w`
and multiply `A` by `v` on the left and `v` on the right.
-/
def matrix_to_bilin_form (A : matrix n n R) : bilin_form R (n → R) :=
sorry

/- Can you define a bilinear form directly that is equivalent to this matrix `A`?
Don't use `bilin_form_to_matrix`, give the map explicitly in the form `λ v w, _`.
Check your definition by putting your cursor on the lines starting with `#eval`.

Hints:
  * Use the `simp` tactic to simplify `(x + y) i` to `x i + y i` and `(s • x) i` to `s * x i`.
  * To deal with equalities containing many `+` and `*` symbols, use the `ring` tactic.
-/
def A : matrix (fin 2) (fin 2) R := ![![1, 0], ![-2, 1]]
def your_bilin_form : bilin_form R (fin 2 → R) :=
sorry

/- Check your definition here, by uncommenting the #eval lines: -/
def v : fin 2 → ℤ := ![1, 3]
def w : fin 2 → ℤ := ![2, 4]
-- #eval matrix_to_bilin_form A v w
-- #eval your_bilin_form v w

end matrix

end exercise2

section exercise3

namespace pi

variables {n : Type*} [fintype n]

open _root_.matrix

/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Exercise 3: inner product spaces
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/

/- Use the `dot_product` function to put an inner product on `n → R`.

Hints:
* Try the lemmas `finset.sum_nonneg`, `finset.sum_eq_zero_iff_of_nonneg`,
  `mul_self_nonneg` and `mul_self_eq_zero`.
-/
noncomputable instance : inner_product_space ℝ (n → ℝ) :=
inner_product_space.of_core
sorry

end pi

end exercise3

section exercise4

namespace pi

variables (R n : Type) [comm_ring R] [fintype n] [decidable_eq n]

/- Enable sum and product notation with `∑` and `∏`. -/
open_locale big_operators

/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  Exercise 4: basis and dimension
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/

/-- The `i`'th vector in the standard basis of `n → R` is `1` at the `i`th entry
and `0` otherwise. -/
def std_basis_fun (i : n) : (n → R) := λ j, if i = j then 1 else 0

/- Bonus exercise: Show the standard basis of `n → R` is a basis.
This is a difficult exercise, so feel free to skip some parts.

Hints for showing linear independence:
  * Try using the lemma `linear_independent_iff` or `linear_independent_iff'`.
  * To derive `f x = 0` from `h : f = 0`, use a tactic `have := congr_fun h x`.
  * Take a term out of a sum by combining `finset.insert_erase` and `finset.sum_insert`.

Hints for showing it spans the whole module:
  * To show equality of set-like terms, apply the `ext` tactic.
  * First show `x = ∑ i, x i • std_basis R n i`, then rewrite with this equality.
-/
lemma linear_independent_std_basis : linear_independent R (std_basis_fun R n) :=
sorry

lemma range_std_basis : submodule.span R (set.range (std_basis_fun R n)) = ⊤ :=
sorry

/- Bases in mathlib are bundled, i.e., the data of a basis is given as an isomorphism
between the vector space and the space of finitely supported functions on the basis. This turns
out to be a convenient way to work out most arguments using bases. Of course, one can construct
such a bundled basis from the data that a family of vectors is linearly independent and spans
the whole space, as follows. -/

def std_basis : basis n R (n → R) :=
basis.mk (linear_independent_std_basis R n) (range_std_basis R n).ge

variables {K : Type} [field K]

/-
Instead of the dimension of a vector space, `mathlib` chooses to use the more general
notion of rank of a module.

If you want the rank/dimension as a potentially infinite cardinal number, you
can use `module.rank`. If you want the rank/dimension as a finite natural
number, you can use `finite_dimensional.finrank`. (If `module.rank` is infinite,
`finrank` is defined to be equal to `0`.)
-/

/-
Conclude `n → K` is a finite dimensional vector space for each field `K`
and the dimension of `n → K` over `K` is the cardinality of `n`.
You don't need to complete `std_basis_is_basis` to prove these two lemmas.

Hint: search the library for appropriate lemmas.
-/
lemma finite_dimensional : finite_dimensional K (n → K) :=
sorry

lemma finrank_eq : finite_dimensional.finrank K (n → K) = fintype.card n :=
sorry

end pi

end exercise4

end lftcm


import tactic
import data.set.basic
import .topology

section fiber_product

variables {E B B' : Type} (π : E → B) (f : B' → B)

@[reducible]
def fiber_product : Type := {pair : B' × E // f pair.fst = π pair.snd}
@[simp] def fiber_product.fst : fiber_product π f → B' := λ x, x.val.fst
@[simp] def fiber_product.snd : fiber_product π f → E := λ x, x.val.snd
infix `×f`:110 := fiber_product

lemma fiber_product.sound :
  f ∘ fiber_product.fst π f = π ∘ fiber_product.snd π f :=
begin
  ext ⟨_, h⟩, exact h,
end

@[simp]
def fiber_product.exact.map {Z : Type} (πZ : Z → B') (fZ : Z → E)
  (h : f ∘ πZ = π ∘ fZ) : Z → π ×f f :=
λ z, ⟨⟨πZ z, fZ z⟩, congr_fun h z⟩

lemma fiber_product.exact.prop (Z : Type) (πZ : Z → B') (fZ : Z → E)
  (h : f ∘ πZ = π ∘ fZ) :
  fiber_product.fst _ _ ∘ fiber_product.exact.map _ _ _ _ h = πZ ∧
  fiber_product.snd _ _ ∘ fiber_product.exact.map _ _ _ _ h = fZ :=
begin
  split; ext; refl,
end

lemma fiber_product.universal (Z : Type) (πZ : Z → B') (fZ : Z → E)
  (h : f ∘ πZ = π ∘ fZ) (g : Z → π ×f f)
  (hg : fiber_product.fst π f ∘ g = πZ ∧ fiber_product.snd π f ∘ g = fZ) :
  g = fiber_product.exact.map _ _ _ _ h :=
begin
  ext,
    change (g x).val.fst = πZ x, rw ← hg.1, refl,
    change (g x).val.snd = fZ x, rw ← hg.2, refl,
end

/-
Annoying technical thing:

If π = ρ and f = g, then the types `fiber_product π f` and
`fiber_product ρ g` are obviously not equal. I don't even know if they
are defeq. So, I wrote the lemma `fiber_product.ext` below which maps between
fiber products of equal functions.

This is useful for when we have `h : π ∘ φ = π'` and so on.
-/

def fiber_product.ext
  (pi : E → B) (eff : B' → B) (pi_eq : pi = π) (eff_eq : eff = f) :
  π ×f f → pi ×f eff :=
  subtype.map id begin intros a h, rwa [pi_eq, eff_eq] end

lemma fiber_product.ext_app
  (pi : E → B) (eff : B' → B) (pi_eq : pi = π) (eff_eq : eff = f)
  (x : π ×f f) :
    fiber_product.ext π f pi eff pi_eq eff_eq x =
    ⟨x.val, begin rw [pi_eq, eff_eq], exact x.prop, end⟩ := rfl

-- "Composition of pullbacks along the base":
-- The following are canonically isomorphic:
--   1. the pullback of π along (f ∘ f')
--   2. the pullback of (the pullback of π along f) along f'
-- but they are not *equal* :
--    #1 is a subtype of B'' × F, whereas
--    #2 is a subtype of B'' × (fiber_product π f).
-- Definitionally these are:
--   1. {pair : B'' × F // (f ∘ f') pair.fst = π pair.snd}
--   2. {pair : B'' × α // f' pair.fst = pullback.fst π f pair.snd}
--      where α is
--      fiber_product π f := {pair' : B' × F // f pair'.fst = π pair'.snd }.

variables {B'' : Type} (f' : B'' → B')

def fiber_product.comp_base :
  (fiber_product.fst π f) ×f f' ≃ π ×f (f ∘ f') :=
{
  to_fun :=
    fiber_product.exact.map π (f ∘ f')
      (fiber_product.fst _ f')
      (fiber_product.snd π f ∘ fiber_product.snd _ f')
      (by rw [function.comp.assoc, ←function.comp.assoc π,
              fiber_product.sound, ←fiber_product.sound π]),
  inv_fun :=
    let π'' := fiber_product.exact.map π f _
               (fiber_product.snd π (f ∘ f'))
               (by rw ← fiber_product.sound π)
    in fiber_product.exact.map _ f' _ π''
       (by rw (fiber_product.exact.prop _ _ _ _ _ _).1),
  left_inv := begin rintro ⟨⟨b'', ⟨⟨b', v⟩, h1⟩⟩, h2⟩,
                    simp, exact h2, end,
  right_inv := begin rintro ⟨⟨b'', e⟩, h⟩, refl, end }

section cts_fiber_product
variables [topology E] [topology B] [topology B'] [topology B'']

-- The topology on a fiber product is the subspace topology from E × B.
--instance fiber_product_topology : topology (π ×f f) := subtype_topology _

/-
Let's prove that all the maps in fiber product diagrams are continuous:
  -- the two projections,
  -- the map from the universal property.

Note: (fiber_product.fst π f) is cts even if π and/or f are not!
This is because it is the restriction of B' × E → B'.

It's convenient to also prove continuity of the composite map
  --  fiber_product π f → B
We give two different proofs (fiber_product.sound.cts and .cts') by going
around the square the two ways. These require either (h : cts π) or (h : cts f).
-/

lemma fiber_product.fst.cts : cts (fiber_product.fst π f) :=
  cts_of_comp _ _ coe_cts prod_fst_cts

lemma fiber_product.snd.cts : cts (fiber_product.snd π f) :=
  cts_of_comp _ _ coe_cts prod_snd_cts

lemma fiber_product.sound.cts
  (hf : cts f) : cts (f ∘ fiber_product.fst π f) :=
  cts_of_comp _ _ (fiber_product.fst.cts π f) hf

lemma fiber_product.sound.cts'
  (hπ : cts π) : cts (π ∘ fiber_product.snd π f) :=
  cts_of_comp _ _ (fiber_product.snd.cts π f) hπ

lemma fiber_product.exact.map.cts {Z : Type} [topology Z]
  {πZ : Z → B'} {fZ : Z → E} {h : f ∘ πZ = π ∘ fZ}
  (πZ_cts : cts πZ) (fZ_cts : cts fZ)
   :
  cts (fiber_product.exact.map π f πZ fZ h) :=
begin
  apply restrict_cod_cts,
  exact (cts_map_to_prod _).mpr ⟨πZ_cts, fZ_cts⟩,
end

lemma fiber_product.ext.cts
  (pi : E → B) (eff : B' → B) (pi_eq : pi = π) (eff_eq : eff = f) :
  cts (fiber_product.ext π f pi eff pi_eq eff_eq) :=
  subtype_map_cts cts.id

lemma fiber_product.comp_base.cts (hf : cts f) : cts (fiber_product.comp_base π f f').to_fun :=
begin
  apply fiber_product.exact.map.cts,
  apply fiber_product.fst.cts,
  simp,
  apply cts_of_comp, apply cts_of_comp, apply cts_of_comp,
  exact coe_cts, exact prod_snd_cts, exact coe_cts, exact prod_snd_cts,
end

lemma fiber_product.comp_base.inv_cts (hf' : cts f') : cts (fiber_product.comp_base π f f').inv_fun :=
begin
  apply fiber_product.exact.map.cts,
  apply fiber_product.fst.cts,
  apply restrict_cod_cts,
  exact cts_of_comp _ _ coe_cts (prod_map_cts _ _ hf' cts.id),
end

end cts_fiber_product

end fiber_product