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

! This file was ported from Lean 3 source module data.set.pointwise.interval
! leanprover-community/mathlib commit 2196ab363eb097c008d4497125e0dde23fb36db2
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathlib.Data.Set.Intervals.UnorderedInterval
import Mathlib.Data.Set.Intervals.Monoid
import Mathlib.Data.Set.Pointwise.Basic
import Mathlib.Algebra.Order.Field.Basic
import Mathlib.Algebra.Order.Group.MinMax

/-!
# (Pre)images of intervals

In this file we prove a bunch of trivial lemmas like “if we add `a` to all points of `[b, c]`,
then we get `[a + b, a + c]`”. For the functions `x ↦ x ± a`, `x ↦ a ± x`, and `x ↦ -x` we prove
lemmas about preimages and images of all intervals. We also prove a few lemmas about images under
`x ↦ a * x`, `x ↦ x * a` and `x ↦ x⁻¹`.
-/

open Interval Pointwise

variable {α : Type _}

namespace Set

section OrderedAddCommGroup

variable [OrderedAddCommGroup α] (a b c : α)

/-!
### Preimages under `x ↦ a + x`
-/

@[simp]
theorem preimage_const_add_Ici : (fun x => a + x) ⁻¹' Ici b = Ici (b - a) :=
  ext fun _x => sub_le_iff_le_add'.symm
#align set.preimage_const_add_Ici Set.preimage_const_add_Ici

@[simp]
theorem preimage_const_add_Ioi : (fun x => a + x) ⁻¹' Ioi b = Ioi (b - a) :=
  ext fun _x => sub_lt_iff_lt_add'.symm
#align set.preimage_const_add_Ioi Set.preimage_const_add_Ioi

@[simp]
theorem preimage_const_add_Iic : (fun x => a + x) ⁻¹' Iic b = Iic (b - a) :=
  ext fun _x => le_sub_iff_add_le'.symm
#align set.preimage_const_add_Iic Set.preimage_const_add_Iic

@[simp]
theorem preimage_const_add_Iio : (fun x => a + x) ⁻¹' Iio b = Iio (b - a) :=
  ext fun _x => lt_sub_iff_add_lt'.symm
#align set.preimage_const_add_Iio Set.preimage_const_add_Iio

@[simp]
theorem preimage_const_add_Icc : (fun x => a + x) ⁻¹' Icc b c = Icc (b - a) (c - a) := by
  simp [← Ici_inter_Iic]
#align set.preimage_const_add_Icc Set.preimage_const_add_Icc

@[simp]
theorem preimage_const_add_Ico : (fun x => a + x) ⁻¹' Ico b c = Ico (b - a) (c - a) := by
  simp [← Ici_inter_Iio]
#align set.preimage_const_add_Ico Set.preimage_const_add_Ico

@[simp]
theorem preimage_const_add_Ioc : (fun x => a + x) ⁻¹' Ioc b c = Ioc (b - a) (c - a) := by
  simp [← Ioi_inter_Iic]
#align set.preimage_const_add_Ioc Set.preimage_const_add_Ioc

@[simp]
theorem preimage_const_add_Ioo : (fun x => a + x) ⁻¹' Ioo b c = Ioo (b - a) (c - a) := by
  simp [← Ioi_inter_Iio]
#align set.preimage_const_add_Ioo Set.preimage_const_add_Ioo

/-!
### Preimages under `x ↦ x + a`
-/

@[simp]
theorem preimage_add_const_Ici : (fun x => x + a) ⁻¹' Ici b = Ici (b - a) :=
  ext fun _x => sub_le_iff_le_add.symm
#align set.preimage_add_const_Ici Set.preimage_add_const_Ici

@[simp]
theorem preimage_add_const_Ioi : (fun x => x + a) ⁻¹' Ioi b = Ioi (b - a) :=
  ext fun _x => sub_lt_iff_lt_add.symm
#align set.preimage_add_const_Ioi Set.preimage_add_const_Ioi

@[simp]
theorem preimage_add_const_Iic : (fun x => x + a) ⁻¹' Iic b = Iic (b - a) :=
  ext fun _x => le_sub_iff_add_le.symm
#align set.preimage_add_const_Iic Set.preimage_add_const_Iic

@[simp]
theorem preimage_add_const_Iio : (fun x => x + a) ⁻¹' Iio b = Iio (b - a) :=
  ext fun _x => lt_sub_iff_add_lt.symm
#align set.preimage_add_const_Iio Set.preimage_add_const_Iio

@[simp]
theorem preimage_add_const_Icc : (fun x => x + a) ⁻¹' Icc b c = Icc (b - a) (c - a) := by
  simp [← Ici_inter_Iic]
#align set.preimage_add_const_Icc Set.preimage_add_const_Icc

@[simp]
theorem preimage_add_const_Ico : (fun x => x + a) ⁻¹' Ico b c = Ico (b - a) (c - a) := by
  simp [← Ici_inter_Iio]
#align set.preimage_add_const_Ico Set.preimage_add_const_Ico

@[simp]
theorem preimage_add_const_Ioc : (fun x => x + a) ⁻¹' Ioc b c = Ioc (b - a) (c - a) := by
  simp [← Ioi_inter_Iic]
#align set.preimage_add_const_Ioc Set.preimage_add_const_Ioc

@[simp]
theorem preimage_add_const_Ioo : (fun x => x + a) ⁻¹' Ioo b c = Ioo (b - a) (c - a) := by
  simp [← Ioi_inter_Iio]
#align set.preimage_add_const_Ioo Set.preimage_add_const_Ioo

/-!
### Preimages under `x ↦ -x`
-/

@[simp]
theorem preimage_neg_Ici : -Ici a = Iic (-a) :=
  ext fun _x => le_neg
#align set.preimage_neg_Ici Set.preimage_neg_Ici

@[simp]
theorem preimage_neg_Iic : -Iic a = Ici (-a) :=
  ext fun _x => neg_le
#align set.preimage_neg_Iic Set.preimage_neg_Iic

@[simp]
theorem preimage_neg_Ioi : -Ioi a = Iio (-a) :=
  ext fun _x => lt_neg
#align set.preimage_neg_Ioi Set.preimage_neg_Ioi

@[simp]
theorem preimage_neg_Iio : -Iio a = Ioi (-a) :=
  ext fun _x => neg_lt
#align set.preimage_neg_Iio Set.preimage_neg_Iio

@[simp]
theorem preimage_neg_Icc : -Icc a b = Icc (-b) (-a) := by simp [← Ici_inter_Iic, inter_comm]
#align set.preimage_neg_Icc Set.preimage_neg_Icc

@[simp]
theorem preimage_neg_Ico : -Ico a b = Ioc (-b) (-a) := by
  simp [← Ici_inter_Iio, ← Ioi_inter_Iic, inter_comm]
#align set.preimage_neg_Ico Set.preimage_neg_Ico

@[simp]
theorem preimage_neg_Ioc : -Ioc a b = Ico (-b) (-a) := by
  simp [← Ioi_inter_Iic, ← Ici_inter_Iio, inter_comm]
#align set.preimage_neg_Ioc Set.preimage_neg_Ioc

@[simp]
theorem preimage_neg_Ioo : -Ioo a b = Ioo (-b) (-a) := by simp [← Ioi_inter_Iio, inter_comm]
#align set.preimage_neg_Ioo Set.preimage_neg_Ioo

/-!
### Preimages under `x ↦ x - a`
-/

@[simp]
theorem preimage_sub_const_Ici : (fun x => x - a) ⁻¹' Ici b = Ici (b + a) := by
  simp [sub_eq_add_neg]
#align set.preimage_sub_const_Ici Set.preimage_sub_const_Ici

@[simp]
theorem preimage_sub_const_Ioi : (fun x => x - a) ⁻¹' Ioi b = Ioi (b + a) := by
  simp [sub_eq_add_neg]
#align set.preimage_sub_const_Ioi Set.preimage_sub_const_Ioi

@[simp]
theorem preimage_sub_const_Iic : (fun x => x - a) ⁻¹' Iic b = Iic (b + a) := by
  simp [sub_eq_add_neg]
#align set.preimage_sub_const_Iic Set.preimage_sub_const_Iic

@[simp]
theorem preimage_sub_const_Iio : (fun x => x - a) ⁻¹' Iio b = Iio (b + a) := by
  simp [sub_eq_add_neg]
#align set.preimage_sub_const_Iio Set.preimage_sub_const_Iio

@[simp]
theorem preimage_sub_const_Icc : (fun x => x - a) ⁻¹' Icc b c = Icc (b + a) (c + a) := by
  simp [sub_eq_add_neg]
#align set.preimage_sub_const_Icc Set.preimage_sub_const_Icc

@[simp]
theorem preimage_sub_const_Ico : (fun x => x - a) ⁻¹' Ico b c = Ico (b + a) (c + a) := by
  simp [sub_eq_add_neg]
#align set.preimage_sub_const_Ico Set.preimage_sub_const_Ico

@[simp]
theorem preimage_sub_const_Ioc : (fun x => x - a) ⁻¹' Ioc b c = Ioc (b + a) (c + a) := by
  simp [sub_eq_add_neg]
#align set.preimage_sub_const_Ioc Set.preimage_sub_const_Ioc

@[simp]
theorem preimage_sub_const_Ioo : (fun x => x - a) ⁻¹' Ioo b c = Ioo (b + a) (c + a) := by
  simp [sub_eq_add_neg]
#align set.preimage_sub_const_Ioo Set.preimage_sub_const_Ioo

/-!
### Preimages under `x ↦ a - x`
-/

@[simp]
theorem preimage_const_sub_Ici : (fun x => a - x) ⁻¹' Ici b = Iic (a - b) :=
  ext fun _x => le_sub_comm
#align set.preimage_const_sub_Ici Set.preimage_const_sub_Ici

@[simp]
theorem preimage_const_sub_Iic : (fun x => a - x) ⁻¹' Iic b = Ici (a - b) :=
  ext fun _x => sub_le_comm
#align set.preimage_const_sub_Iic Set.preimage_const_sub_Iic

@[simp]
theorem preimage_const_sub_Ioi : (fun x => a - x) ⁻¹' Ioi b = Iio (a - b) :=
  ext fun _x => lt_sub_comm
#align set.preimage_const_sub_Ioi Set.preimage_const_sub_Ioi

@[simp]
theorem preimage_const_sub_Iio : (fun x => a - x) ⁻¹' Iio b = Ioi (a - b) :=
  ext fun _x => sub_lt_comm
#align set.preimage_const_sub_Iio Set.preimage_const_sub_Iio

@[simp]
theorem preimage_const_sub_Icc : (fun x => a - x) ⁻¹' Icc b c = Icc (a - c) (a - b) := by
  simp [← Ici_inter_Iic, inter_comm]
#align set.preimage_const_sub_Icc Set.preimage_const_sub_Icc

@[simp]
theorem preimage_const_sub_Ico : (fun x => a - x) ⁻¹' Ico b c = Ioc (a - c) (a - b) := by
  simp [← Ioi_inter_Iic, ← Ici_inter_Iio, inter_comm]
#align set.preimage_const_sub_Ico Set.preimage_const_sub_Ico

@[simp]
theorem preimage_const_sub_Ioc : (fun x => a - x) ⁻¹' Ioc b c = Ico (a - c) (a - b) := by
  simp [← Ioi_inter_Iic, ← Ici_inter_Iio, inter_comm]
#align set.preimage_const_sub_Ioc Set.preimage_const_sub_Ioc

@[simp]
theorem preimage_const_sub_Ioo : (fun x => a - x) ⁻¹' Ioo b c = Ioo (a - c) (a - b) := by
  simp [← Ioi_inter_Iio, inter_comm]
#align set.preimage_const_sub_Ioo Set.preimage_const_sub_Ioo

/-!
### Images under `x ↦ a + x`
-/

-- @[simp] -- Porting note: simp can prove this modulo `add_comm`
theorem image_const_add_Iic : (fun x => a + x) '' Iic b = Iic (a + b) := by simp [add_comm]
#align set.image_const_add_Iic Set.image_const_add_Iic

-- @[simp] -- Porting note: simp can prove this modulo `add_comm`
theorem image_const_add_Iio : (fun x => a + x) '' Iio b = Iio (a + b) := by simp [add_comm]
#align set.image_const_add_Iio Set.image_const_add_Iio

/-!
### Images under `x ↦ x + a`
-/

-- @[simp] -- Porting note: simp can prove this
theorem image_add_const_Iic : (fun x => x + a) '' Iic b = Iic (b + a) := by simp
#align set.image_add_const_Iic Set.image_add_const_Iic

-- @[simp] -- Porting note: simp can prove this
theorem image_add_const_Iio : (fun x => x + a) '' Iio b = Iio (b + a) := by simp
#align set.image_add_const_Iio Set.image_add_const_Iio

/-!
### Images under `x ↦ -x`
-/

theorem image_neg_Ici : Neg.neg '' Ici a = Iic (-a) := by simp
#align set.image_neg_Ici Set.image_neg_Ici

theorem image_neg_Iic : Neg.neg '' Iic a = Ici (-a) := by simp
#align set.image_neg_Iic Set.image_neg_Iic

theorem image_neg_Ioi : Neg.neg '' Ioi a = Iio (-a) := by simp
#align set.image_neg_Ioi Set.image_neg_Ioi

theorem image_neg_Iio : Neg.neg '' Iio a = Ioi (-a) := by simp
#align set.image_neg_Iio Set.image_neg_Iio

theorem image_neg_Icc : Neg.neg '' Icc a b = Icc (-b) (-a) := by simp
#align set.image_neg_Icc Set.image_neg_Icc

theorem image_neg_Ico : Neg.neg '' Ico a b = Ioc (-b) (-a) := by simp
#align set.image_neg_Ico Set.image_neg_Ico

theorem image_neg_Ioc : Neg.neg '' Ioc a b = Ico (-b) (-a) := by simp
#align set.image_neg_Ioc Set.image_neg_Ioc

theorem image_neg_Ioo : Neg.neg '' Ioo a b = Ioo (-b) (-a) := by simp
#align set.image_neg_Ioo Set.image_neg_Ioo

/-!
### Images under `x ↦ a - x`
-/

@[simp]
theorem image_const_sub_Ici : (fun x => a - x) '' Ici b = Iic (a - b) := by
  have := image_comp (fun x => a + x) fun x => -x; dsimp [Function.comp] at this
  simp [sub_eq_add_neg, this, add_comm]
#align set.image_const_sub_Ici Set.image_const_sub_Ici

@[simp]
theorem image_const_sub_Iic : (fun x => a - x) '' Iic b = Ici (a - b) := by
  have := image_comp (fun x => a + x) fun x => -x; dsimp [Function.comp] at this
  simp [sub_eq_add_neg, this, add_comm]
#align set.image_const_sub_Iic Set.image_const_sub_Iic

@[simp]
theorem image_const_sub_Ioi : (fun x => a - x) '' Ioi b = Iio (a - b) := by
  have := image_comp (fun x => a + x) fun x => -x; dsimp [Function.comp] at this
  simp [sub_eq_add_neg, this, add_comm]
#align set.image_const_sub_Ioi Set.image_const_sub_Ioi

@[simp]
theorem image_const_sub_Iio : (fun x => a - x) '' Iio b = Ioi (a - b) := by
  have := image_comp (fun x => a + x) fun x => -x; dsimp [Function.comp] at this
  simp [sub_eq_add_neg, this, add_comm]
#align set.image_const_sub_Iio Set.image_const_sub_Iio

@[simp]
theorem image_const_sub_Icc : (fun x => a - x) '' Icc b c = Icc (a - c) (a - b) := by
  have := image_comp (fun x => a + x) fun x => -x; dsimp [Function.comp] at this
  simp [sub_eq_add_neg, this, add_comm]
#align set.image_const_sub_Icc Set.image_const_sub_Icc

@[simp]
theorem image_const_sub_Ico : (fun x => a - x) '' Ico b c = Ioc (a - c) (a - b) := by
  have := image_comp (fun x => a + x) fun x => -x; dsimp [Function.comp] at this
  simp [sub_eq_add_neg, this, add_comm]
#align set.image_const_sub_Ico Set.image_const_sub_Ico

@[simp]
theorem image_const_sub_Ioc : (fun x => a - x) '' Ioc b c = Ico (a - c) (a - b) := by
  have := image_comp (fun x => a + x) fun x => -x; dsimp [Function.comp] at this
  simp [sub_eq_add_neg, this, add_comm]
#align set.image_const_sub_Ioc Set.image_const_sub_Ioc

@[simp]
theorem image_const_sub_Ioo : (fun x => a - x) '' Ioo b c = Ioo (a - c) (a - b) := by
  have := image_comp (fun x => a + x) fun x => -x; dsimp [Function.comp] at this
  simp [sub_eq_add_neg, this, add_comm]
#align set.image_const_sub_Ioo Set.image_const_sub_Ioo

/-!
### Images under `x ↦ x - a`
-/

@[simp]
theorem image_sub_const_Ici : (fun x => x - a) '' Ici b = Ici (b - a) := by simp [sub_eq_neg_add]
#align set.image_sub_const_Ici Set.image_sub_const_Ici

@[simp]
theorem image_sub_const_Iic : (fun x => x - a) '' Iic b = Iic (b - a) := by simp [sub_eq_neg_add]
#align set.image_sub_const_Iic Set.image_sub_const_Iic

@[simp]
theorem image_sub_const_Ioi : (fun x => x - a) '' Ioi b = Ioi (b - a) := by simp [sub_eq_neg_add]
#align set.image_sub_const_Ioi Set.image_sub_const_Ioi

@[simp]
theorem image_sub_const_Iio : (fun x => x - a) '' Iio b = Iio (b - a) := by simp [sub_eq_neg_add]
#align set.image_sub_const_Iio Set.image_sub_const_Iio

@[simp]
theorem image_sub_const_Icc : (fun x => x - a) '' Icc b c = Icc (b - a) (c - a) := by
  simp [sub_eq_neg_add]
#align set.image_sub_const_Icc Set.image_sub_const_Icc

@[simp]
theorem image_sub_const_Ico : (fun x => x - a) '' Ico b c = Ico (b - a) (c - a) := by
  simp [sub_eq_neg_add]
#align set.image_sub_const_Ico Set.image_sub_const_Ico

@[simp]
theorem image_sub_const_Ioc : (fun x => x - a) '' Ioc b c = Ioc (b - a) (c - a) := by
  simp [sub_eq_neg_add]
#align set.image_sub_const_Ioc Set.image_sub_const_Ioc

@[simp]
theorem image_sub_const_Ioo : (fun x => x - a) '' Ioo b c = Ioo (b - a) (c - a) := by
  simp [sub_eq_neg_add]
#align set.image_sub_const_Ioo Set.image_sub_const_Ioo

/-!
### Bijections
-/

theorem Iic_add_bij : BijOn (· + a) (Iic b) (Iic (b + a)) :=
  image_add_const_Iic a b ▸ ((add_left_injective _).injOn _).bijOn_image
#align set.Iic_add_bij Set.Iic_add_bij

theorem Iio_add_bij : BijOn (· + a) (Iio b) (Iio (b + a)) :=
  image_add_const_Iio a b ▸ ((add_left_injective _).injOn _).bijOn_image
#align set.Iio_add_bij Set.Iio_add_bij

end OrderedAddCommGroup

section LinearOrderedAddCommGroup

variable [LinearOrderedAddCommGroup α] (a b c d : α)

@[simp]
theorem preimage_const_add_uIcc : (fun x => a + x) ⁻¹' [[b, c]] = [[b - a, c - a]] := by
  simp only [← Icc_min_max, preimage_const_add_Icc, min_sub_sub_right, max_sub_sub_right]
#align set.preimage_const_add_uIcc Set.preimage_const_add_uIcc

@[simp]
theorem preimage_add_const_uIcc : (fun x => x + a) ⁻¹' [[b, c]] = [[b - a, c - a]] := by
  simpa only [add_comm] using preimage_const_add_uIcc a b c
#align set.preimage_add_const_uIcc Set.preimage_add_const_uIcc

-- TODO: Why is the notation `-[[a, b]]` broken?
@[simp]
theorem preimage_neg_uIcc : @Neg.neg (Set α) Set.neg [[a, b]] = [[-a, -b]] := by
  simp only [← Icc_min_max, preimage_neg_Icc, min_neg_neg, max_neg_neg]
#align set.preimage_neg_uIcc Set.preimage_neg_uIcc

@[simp]
theorem preimage_sub_const_uIcc : (fun x => x - a) ⁻¹' [[b, c]] = [[b + a, c + a]] := by
  simp [sub_eq_add_neg]
#align set.preimage_sub_const_uIcc Set.preimage_sub_const_uIcc

@[simp]
theorem preimage_const_sub_uIcc : (fun x => a - x) ⁻¹' [[b, c]] = [[a - b, a - c]] := by
  simp_rw [← Icc_min_max, preimage_const_sub_Icc]
  simp only [sub_eq_add_neg, min_add_add_left, max_add_add_left, min_neg_neg, max_neg_neg]
#align set.preimage_const_sub_uIcc Set.preimage_const_sub_uIcc

-- @[simp] -- Porting note: simp can prove this module `add_comm`
theorem image_const_add_uIcc : (fun x => a + x) '' [[b, c]] = [[a + b, a + c]] := by simp [add_comm]
#align set.image_const_add_uIcc Set.image_const_add_uIcc

-- @[simp] -- Porting note: simp can prove this
theorem image_add_const_uIcc : (fun x => x + a) '' [[b, c]] = [[b + a, c + a]] := by simp
#align set.image_add_const_uIcc Set.image_add_const_uIcc

@[simp]
theorem image_const_sub_uIcc : (fun x => a - x) '' [[b, c]] = [[a - b, a - c]] := by
  have := image_comp (fun x => a + x) fun x => -x; dsimp [Function.comp] at this
  simp [sub_eq_add_neg, this, add_comm]
#align set.image_const_sub_uIcc Set.image_const_sub_uIcc

@[simp]
theorem image_sub_const_uIcc : (fun x => x - a) '' [[b, c]] = [[b - a, c - a]] := by
  simp [sub_eq_add_neg, add_comm]
#align set.image_sub_const_uIcc Set.image_sub_const_uIcc

theorem image_neg_uIcc : Neg.neg '' [[a, b]] = [[-a, -b]] := by simp
#align set.image_neg_uIcc Set.image_neg_uIcc

variable {a b c d}

/-- If `[c, d]` is a subinterval of `[a, b]`, then the distance between `c` and `d` is less than or
equal to that of `a` and `b` -/
theorem abs_sub_le_of_uIcc_subset_uIcc (h : [[c, d]] ⊆ [[a, b]]) : |d - c| ≤ |b - a| := by
  rw [← max_sub_min_eq_abs, ← max_sub_min_eq_abs]
  rw [uIcc_subset_uIcc_iff_le] at h
  exact sub_le_sub h.2 h.1
#align set.abs_sub_le_of_uIcc_subset_uIcc Set.abs_sub_le_of_uIcc_subset_uIcc

/-- If `c ∈ [a, b]`, then the distance between `a` and `c` is less than or equal to
that of `a` and `b`  -/
theorem abs_sub_left_of_mem_uIcc (h : c ∈ [[a, b]]) : |c - a| ≤ |b - a| :=
  abs_sub_le_of_uIcc_subset_uIcc <| uIcc_subset_uIcc_left h
#align set.abs_sub_left_of_mem_uIcc Set.abs_sub_left_of_mem_uIcc

/-- If `x ∈ [a, b]`, then the distance between `c` and `b` is less than or equal to
that of `a` and `b`  -/
theorem abs_sub_right_of_mem_uIcc (h : c ∈ [[a, b]]) : |b - c| ≤ |b - a| :=
  abs_sub_le_of_uIcc_subset_uIcc <| uIcc_subset_uIcc_right h
#align set.abs_sub_right_of_mem_uIcc Set.abs_sub_right_of_mem_uIcc

end LinearOrderedAddCommGroup

/-!
### Multiplication and inverse in a field
-/

section LinearOrderedField

variable [LinearOrderedField α] {a : α}

@[simp]

@[simp]
theorem preimage_mul_const_Ioi (a : α) {c : α} (h : 0 < c) :
    (fun x => x * c) ⁻¹' Ioi a = Ioi (a / c) :=
  ext fun _x => (div_lt_iff h).symm
#align set.preimage_mul_const_Ioi Set.preimage_mul_const_Ioi

@[simp]
theorem preimage_mul_const_Iic (a : α) {c : α} (h : 0 < c) :
    (fun x => x * c) ⁻¹' Iic a = Iic (a / c) :=
  ext fun _x => (le_div_iff h).symm
#align set.preimage_mul_const_Iic Set.preimage_mul_const_Iic

@[simp]
theorem preimage_mul_const_Ici (a : α) {c : α} (h : 0 < c) :
    (fun x => x * c) ⁻¹' Ici a = Ici (a / c) :=
  ext fun _x => (div_le_iff h).symm
#align set.preimage_mul_const_Ici Set.preimage_mul_const_Ici

@[simp]
theorem preimage_mul_const_Ioo (a b : α) {c : α} (h : 0 < c) :
    (fun x => x * c) ⁻¹' Ioo a b = Ioo (a / c) (b / c) := by simp [← Ioi_inter_Iio, h]
#align set.preimage_mul_const_Ioo Set.preimage_mul_const_Ioo

@[simp]
theorem preimage_mul_const_Ioc (a b : α) {c : α} (h : 0 < c) :
    (fun x => x * c) ⁻¹' Ioc a b = Ioc (a / c) (b / c) := by simp [← Ioi_inter_Iic, h]
#align set.preimage_mul_const_Ioc Set.preimage_mul_const_Ioc

@[simp]
theorem preimage_mul_const_Ico (a b : α) {c : α} (h : 0 < c) :
    (fun x => x * c) ⁻¹' Ico a b = Ico (a / c) (b / c) := by simp [← Ici_inter_Iio, h]
#align set.preimage_mul_const_Ico Set.preimage_mul_const_Ico

@[simp]
theorem preimage_mul_const_Icc (a b : α) {c : α} (h : 0 < c) :
    (fun x => x * c) ⁻¹' Icc a b = Icc (a / c) (b / c) := by simp [← Ici_inter_Iic, h]
#align set.preimage_mul_const_Icc Set.preimage_mul_const_Icc

@[simp]
theorem preimage_mul_const_Iio_of_neg (a : α) {c : α} (h : c < 0) :
    (fun x => x * c) ⁻¹' Iio a = Ioi (a / c) :=
  ext fun _x => (div_lt_iff_of_neg h).symm
#align set.preimage_mul_const_Iio_of_neg Set.preimage_mul_const_Iio_of_neg

@[simp]
theorem preimage_mul_const_Ioi_of_neg (a : α) {c : α} (h : c < 0) :
    (fun x => x * c) ⁻¹' Ioi a = Iio (a / c) :=
  ext fun _x => (lt_div_iff_of_neg h).symm
#align set.preimage_mul_const_Ioi_of_neg Set.preimage_mul_const_Ioi_of_neg

@[simp]
theorem preimage_mul_const_Iic_of_neg (a : α) {c : α} (h : c < 0) :
    (fun x => x * c) ⁻¹' Iic a = Ici (a / c) :=
  ext fun _x => (div_le_iff_of_neg h).symm
#align set.preimage_mul_const_Iic_of_neg Set.preimage_mul_const_Iic_of_neg

@[simp]
theorem preimage_mul_const_Ici_of_neg (a : α) {c : α} (h : c < 0) :
    (fun x => x * c) ⁻¹' Ici a = Iic (a / c) :=
  ext fun _x => (le_div_iff_of_neg h).symm
#align set.preimage_mul_const_Ici_of_neg Set.preimage_mul_const_Ici_of_neg

@[simp]
theorem preimage_mul_const_Ioo_of_neg (a b : α) {c : α} (h : c < 0) :
    (fun x => x * c) ⁻¹' Ioo a b = Ioo (b / c) (a / c) := by simp [← Ioi_inter_Iio, h, inter_comm]
#align set.preimage_mul_const_Ioo_of_neg Set.preimage_mul_const_Ioo_of_neg

@[simp]
theorem preimage_mul_const_Ioc_of_neg (a b : α) {c : α} (h : c < 0) :
    (fun x => x * c) ⁻¹' Ioc a b = Ico (b / c) (a / c) := by
  simp [← Ioi_inter_Iic, ← Ici_inter_Iio, h, inter_comm]
#align set.preimage_mul_const_Ioc_of_neg Set.preimage_mul_const_Ioc_of_neg

@[simp]
theorem preimage_mul_const_Ico_of_neg (a b : α) {c : α} (h : c < 0) :
    (fun x => x * c) ⁻¹' Ico a b = Ioc (b / c) (a / c) := by
  simp [← Ici_inter_Iio, ← Ioi_inter_Iic, h, inter_comm]
#align set.preimage_mul_const_Ico_of_neg Set.preimage_mul_const_Ico_of_neg

@[simp]
theorem preimage_mul_const_Icc_of_neg (a b : α) {c : α} (h : c < 0) :
    (fun x => x * c) ⁻¹' Icc a b = Icc (b / c) (a / c) := by simp [← Ici_inter_Iic, h, inter_comm]
#align set.preimage_mul_const_Icc_of_neg Set.preimage_mul_const_Icc_of_neg

@[simp]
theorem preimage_const_mul_Iio (a : α) {c : α} (h : 0 < c) : (· * ·) c ⁻¹' Iio a = Iio (a / c) :=
  ext fun _x => (lt_div_iff' h).symm
#align set.preimage_const_mul_Iio Set.preimage_const_mul_Iio

@[simp]
theorem preimage_const_mul_Ioi (a : α) {c : α} (h : 0 < c) : (· * ·) c ⁻¹' Ioi a = Ioi (a / c) :=
  ext fun _x => (div_lt_iff' h).symm
#align set.preimage_const_mul_Ioi Set.preimage_const_mul_Ioi

@[simp]
theorem preimage_const_mul_Iic (a : α) {c : α} (h : 0 < c) : (· * ·) c ⁻¹' Iic a = Iic (a / c) :=
  ext fun _x => (le_div_iff' h).symm
#align set.preimage_const_mul_Iic Set.preimage_const_mul_Iic

@[simp]
theorem preimage_const_mul_Ici (a : α) {c : α} (h : 0 < c) : (· * ·) c ⁻¹' Ici a = Ici (a / c) :=
  ext fun _x => (div_le_iff' h).symm
#align set.preimage_const_mul_Ici Set.preimage_const_mul_Ici

@[simp]
theorem preimage_const_mul_Ioo (a b : α) {c : α} (h : 0 < c) :
    (· * ·) c ⁻¹' Ioo a b = Ioo (a / c) (b / c) := by simp [← Ioi_inter_Iio, h]
#align set.preimage_const_mul_Ioo Set.preimage_const_mul_Ioo

@[simp]
theorem preimage_const_mul_Ioc (a b : α) {c : α} (h : 0 < c) :
    (· * ·) c ⁻¹' Ioc a b = Ioc (a / c) (b / c) := by simp [← Ioi_inter_Iic, h]
#align set.preimage_const_mul_Ioc Set.preimage_const_mul_Ioc

@[simp]
theorem preimage_const_mul_Ico (a b : α) {c : α} (h : 0 < c) :
    (· * ·) c ⁻¹' Ico a b = Ico (a / c) (b / c) := by simp [← Ici_inter_Iio, h]
#align set.preimage_const_mul_Ico Set.preimage_const_mul_Ico

@[simp]
theorem preimage_const_mul_Icc (a b : α) {c : α} (h : 0 < c) :
    (· * ·) c ⁻¹' Icc a b = Icc (a / c) (b / c) := by simp [← Ici_inter_Iic, h]
#align set.preimage_const_mul_Icc Set.preimage_const_mul_Icc

@[simp]
theorem preimage_const_mul_Iio_of_neg (a : α) {c : α} (h : c < 0) :
    (· * ·) c ⁻¹' Iio a = Ioi (a / c) := by
  simpa only [mul_comm] using preimage_mul_const_Iio_of_neg a h
#align set.preimage_const_mul_Iio_of_neg Set.preimage_const_mul_Iio_of_neg

@[simp]
theorem preimage_const_mul_Ioi_of_neg (a : α) {c : α} (h : c < 0) :
    (· * ·) c ⁻¹' Ioi a = Iio (a / c) := by
  simpa only [mul_comm] using preimage_mul_const_Ioi_of_neg a h
#align set.preimage_const_mul_Ioi_of_neg Set.preimage_const_mul_Ioi_of_neg

@[simp]
theorem preimage_const_mul_Iic_of_neg (a : α) {c : α} (h : c < 0) :
    (· * ·) c ⁻¹' Iic a = Ici (a / c) := by
  simpa only [mul_comm] using preimage_mul_const_Iic_of_neg a h
#align set.preimage_const_mul_Iic_of_neg Set.preimage_const_mul_Iic_of_neg

@[simp]
theorem preimage_const_mul_Ici_of_neg (a : α) {c : α} (h : c < 0) :
    (· * ·) c ⁻¹' Ici a = Iic (a / c) := by
  simpa only [mul_comm] using preimage_mul_const_Ici_of_neg a h
#align set.preimage_const_mul_Ici_of_neg Set.preimage_const_mul_Ici_of_neg

@[simp]
theorem preimage_const_mul_Ioo_of_neg (a b : α) {c : α} (h : c < 0) :
    (· * ·) c ⁻¹' Ioo a b = Ioo (b / c) (a / c) := by
  simpa only [mul_comm] using preimage_mul_const_Ioo_of_neg a b h
#align set.preimage_const_mul_Ioo_of_neg Set.preimage_const_mul_Ioo_of_neg

@[simp]
theorem preimage_const_mul_Ioc_of_neg (a b : α) {c : α} (h : c < 0) :
    (· * ·) c ⁻¹' Ioc a b = Ico (b / c) (a / c) := by
  simpa only [mul_comm] using preimage_mul_const_Ioc_of_neg a b h
#align set.preimage_const_mul_Ioc_of_neg Set.preimage_const_mul_Ioc_of_neg

@[simp]
theorem preimage_const_mul_Ico_of_neg (a b : α) {c : α} (h : c < 0) :
    (· * ·) c ⁻¹' Ico a b = Ioc (b / c) (a / c) := by
  simpa only [mul_comm] using preimage_mul_const_Ico_of_neg a b h
#align set.preimage_const_mul_Ico_of_neg Set.preimage_const_mul_Ico_of_neg

@[simp]
theorem preimage_const_mul_Icc_of_neg (a b : α) {c : α} (h : c < 0) :
    (· * ·) c ⁻¹' Icc a b = Icc (b / c) (a / c) := by
  simpa only [mul_comm] using preimage_mul_const_Icc_of_neg a b h
#align set.preimage_const_mul_Icc_of_neg Set.preimage_const_mul_Icc_of_neg

@[simp]
theorem preimage_mul_const_uIcc (ha : a ≠ 0) (b c : α) :
    (fun x => x * a) ⁻¹' [[b, c]] = [[b / a, c / a]] :=
  (lt_or_gt_of_ne ha).elim
    (fun h => by
      simp [← Icc_min_max, h, h.le, min_div_div_right_of_nonpos, max_div_div_right_of_nonpos])
    fun ha : 0 < a => by simp [← Icc_min_max, ha, ha.le, min_div_div_right, max_div_div_right]
#align set.preimage_mul_const_uIcc Set.preimage_mul_const_uIcc

@[simp]
theorem preimage_const_mul_uIcc (ha : a ≠ 0) (b c : α) :
    (fun x => a * x) ⁻¹' [[b, c]] = [[b / a, c / a]] := by
  simp only [← preimage_mul_const_uIcc ha, mul_comm]
#align set.preimage_const_mul_uIcc Set.preimage_const_mul_uIcc

@[simp]
theorem preimage_div_const_uIcc (ha : a ≠ 0) (b c : α) :
    (fun x => x / a) ⁻¹' [[b, c]] = [[b * a, c * a]] := by
  simp only [div_eq_mul_inv, preimage_mul_const_uIcc (inv_ne_zero ha), inv_inv]
#align set.preimage_div_const_uIcc Set.preimage_div_const_uIcc

@[simp]
theorem image_mul_const_uIcc (a b c : α) : (fun x => x * a) '' [[b, c]] = [[b * a, c * a]] :=
  if ha : a = 0 then by simp [ha]
  else calc
    (fun x => x * a) '' [[b, c]] = (fun x => x * a⁻¹) ⁻¹' [[b, c]] :=
      (Units.mk0 a ha).mulRight.image_eq_preimage _
    _ = (fun x => x / a) ⁻¹' [[b, c]] := by simp only [div_eq_mul_inv]
    _ = [[b * a, c * a]] := preimage_div_const_uIcc ha _ _

#align set.image_mul_const_uIcc Set.image_mul_const_uIcc

@[simp]
theorem image_const_mul_uIcc (a b c : α) : (fun x => a * x) '' [[b, c]] = [[a * b, a * c]] := by
  simpa only [mul_comm] using image_mul_const_uIcc a b c
#align set.image_const_mul_uIcc Set.image_const_mul_uIcc

@[simp]
theorem image_div_const_uIcc (a b c : α) : (fun x => x / a) '' [[b, c]] = [[b / a, c / a]] := by
  simp only [div_eq_mul_inv, image_mul_const_uIcc]
#align set.image_div_const_uIcc Set.image_div_const_uIcc

theorem image_mul_right_Icc' (a b : α) {c : α} (h : 0 < c) :
    (fun x => x * c) '' Icc a b = Icc (a * c) (b * c) :=
  ((Units.mk0 c h.ne').mulRight.image_eq_preimage _).trans (by simp [h, division_def])
#align set.image_mul_right_Icc' Set.image_mul_right_Icc'

theorem image_mul_right_Icc {a b c : α} (hab : a ≤ b) (hc : 0 ≤ c) :
    (fun x => x * c) '' Icc a b = Icc (a * c) (b * c) := by
  cases eq_or_lt_of_le hc
  · subst c
    simp [(nonempty_Icc.2 hab).image_const]
  exact image_mul_right_Icc' a b ‹0 < c›
#align set.image_mul_right_Icc Set.image_mul_right_Icc

theorem image_mul_left_Icc' {a : α} (h : 0 < a) (b c : α) :
    (· * ·) a '' Icc b c = Icc (a * b) (a * c) := by
  convert image_mul_right_Icc' b c h using 1 <;> simp only [mul_comm _ a]
#align set.image_mul_left_Icc' Set.image_mul_left_Icc'

theorem image_mul_left_Icc {a b c : α} (ha : 0 ≤ a) (hbc : b ≤ c) :
    (· * ·) a '' Icc b c = Icc (a * b) (a * c) := by
  convert image_mul_right_Icc hbc ha using 1 <;> simp only [mul_comm _ a]
#align set.image_mul_left_Icc Set.image_mul_left_Icc

theorem image_mul_right_Ioo (a b : α) {c : α} (h : 0 < c) :
    (fun x => x * c) '' Ioo a b = Ioo (a * c) (b * c) :=
  ((Units.mk0 c h.ne').mulRight.image_eq_preimage _).trans (by simp [h, division_def])
#align set.image_mul_right_Ioo Set.image_mul_right_Ioo

theorem image_mul_left_Ioo {a : α} (h : 0 < a) (b c : α) :
    (· * ·) a '' Ioo b c = Ioo (a * b) (a * c) := by
  convert image_mul_right_Ioo b c h using 1 <;> simp only [mul_comm _ a]
#align set.image_mul_left_Ioo Set.image_mul_left_Ioo

/-- The (pre)image under `inv` of `Ioo 0 a` is `Ioi a⁻¹`. -/
theorem inv_Ioo_0_left {a : α} (ha : 0 < a) : (Ioo 0 a)⁻¹ = Ioi a⁻¹ := by
  ext x
  exact
    ⟨fun h => inv_inv x ▸ (inv_lt_inv ha h.1).2 h.2, fun h =>
      ⟨inv_pos.2 <| (inv_pos.2 ha).trans h,
        inv_inv a ▸ (inv_lt_inv ((inv_pos.2 ha).trans h) (inv_pos.2 ha)).2 h⟩⟩
#align set.inv_Ioo_0_left Set.inv_Ioo_0_left

theorem inv_Ioi {a : α} (ha : 0 < a) : (Ioi a)⁻¹ = Ioo 0 a⁻¹ := by
  rw [inv_eq_iff_eq_inv, inv_Ioo_0_left (inv_pos.2 ha), inv_inv]
#align set.inv_Ioi Set.inv_Ioi

theorem image_const_mul_Ioi_zero {k : Type _} [LinearOrderedField k] {x : k} (hx : 0 < x) :
    (fun y => x * y) '' Ioi (0 : k) = Ioi 0 := by
  erw [(Units.mk0 x hx.ne').mulLeft.image_eq_preimage, preimage_const_mul_Ioi 0 (inv_pos.mpr hx),
    zero_div]
#align set.image_const_mul_Ioi_zero Set.image_const_mul_Ioi_zero

/-!
### Images under `x ↦ a * x + b`
-/

@[simp]
theorem image_affine_Icc' {a : α} (h : 0 < a) (b c d : α) :
    (fun x => a * x + b) '' Icc c d = Icc (a * c + b) (a * d + b) := by
  suffices (fun x => x + b) '' ((fun x => a * x) '' Icc c d) = Icc (a * c + b) (a * d + b) by
    rwa [Set.image_image] at this
  rw [image_mul_left_Icc' h, image_add_const_Icc]
#align set.image_affine_Icc' Set.image_affine_Icc'

end LinearOrderedField

end Set


import SciLean.Data.PowType
-- import SciLean.Tactic.AutoDiff.Main

open SciLean

variable {α β γ : Type}
variable {X Y Z : Type} [Vec X] [Vec Y] [Vec Z]
variable {I : Type} [Enumtype I]

-- set_option maxHeartbeats 20000000
-- set_option synthInstance.maxHeartbeats 500000
-- set_option synthInstance.maxSize 2048

variable {n} [Fact (n≠0)]

example : Vec (ℝ^{n}) := by infer_instance
example : Vec (ℝ^I) := by infer_instance

-- This one is problematic. It clashes with this instance and it is
-- the reason why the instance is marked local.
-- local instance (priority := low) [AddMonoid Y] [DistribMulAction ℝ Y] : DistribMulAction ℝ T := DistribMulAction.mk sorry sorry
example : ∀ (i : Fin n), IsSmooth λ (x : ℝ^{n}) => ∥x[i]∥² := by infer_instance -- apply λ i => SciLean.comp.arg_x.isSmooth
example : IsSmooth (λ (x : ℝ^{n}) => ∥x∥²) := by infer_instance
example : IsSmooth (λ (x : ℝ^{n}) => ⟪x,x⟫) := by infer_instance

example (i) : ∂ (λ (x : ℝ^{n}) => ∥x[i]∥²) = λ x dx => 2*⟪dx[i],x[i]⟫:= by simp
example : ∂ (λ (x : ℝ^{n}) (i : Fin n) => x[i]) = λ x dx i => dx[i] := by simp

section
  -- variable {T Y : Type} [Hilbert Y] [FunType T (Fin n) Y] [FunType.HasIntro T] [FunType.HasSet T] [Fact (n≠0)]
example (h : Fin n) : ∂ (λ (x : ℝ^{n}) => ∑ i, ∥x[i+h]∥²) = λ x dx => ∑ i, 2*⟪dx[i+h],x[i+h]⟫ := by simp
example (h : Fin n) : ∂ (λ (x : ℝ^{n}) => ∑ i, ∥x[i+h] - x[i]∥²) = λ x dx => ∑ i, 2*⟪dx[i+h] - dx[i], x[i+h] - x[i]⟫ := by simp
end

variable {n : Nat} [Nonempty (Fin n)]

set_option trace.Meta.Tactic.simp.discharge true in
example : ∂ (λ x : ℝ^{n} => ∑ i, ∥x[i] - x[i - (1 : Fin n)]∥²) = 0 := by simp


import analysis.special_functions.trigonometric.deriv
import analysis.special_functions.log_deriv

namespace real

example : differentiable ℝ (λ (x : ℝ), exp x) :=
by simp

example : differentiable ℝ (λ (x : ℝ), exp ((sin x)^2) - exp (exp (cos (x - 3)))) :=
by simp

example (x : ℝ) : deriv (λ (x : ℝ), (cos x)^2 + 1 + (sin x)^2) x = 0 :=
by { simp, ring }

example (x : ℝ) : deriv (λ (x : ℝ), (1+x)^3 - x^3 - 3 * x^2 - 3 * x - 4) x = 0 :=
by { simp, ring }

example (x : ℝ) : deriv (λ x, cos (sin x) * exp x) x = (cos(sin(x))-sin(sin(x))*cos(x))*exp(x) :=
by { simp, ring }

example (x : ℝ) : differentiable_at ℝ (λ x, (cos x, x)) x := by simp

example (x : ℝ) (h : 1 + sin x ≠ 0) : deriv (λ x, exp (cos x) / (1 + sin x)) x =
  (-(exp (cos x) * sin x * (1 + sin x)) - exp (cos x) * cos x) / (1 + sin x) ^ 2 :=
by simp [h]

example (x : ℝ) : differentiable_at ℝ (λ x, (sin x) / (exp x)) x :=
by simp [exp_ne_zero]

example : differentiable ℝ (λ x, (sin x) / (exp x)) :=
by simp [exp_ne_zero]

example (x : ℝ) (h : x ≠ 0) : deriv (λ x, x * (log x - 1)) x = log x :=
by simp [h]

end real

namespace complex

example : differentiable ℂ  (λ (x : ℂ), exp x) :=
by simp

example : differentiable ℂ (λ (x : ℂ), exp ((sin x)^2) - exp (exp (cos (x - 3)))) :=
by simp

example (x : ℂ) : deriv (λ (x : ℂ), (cos x)^2 + I + (sin x)^2) x = 0 :=
by { simp, ring }

example (x : ℂ) : deriv (λ x, cos (sin x) * exp x) x = (cos(sin(x))-sin(sin(x))*cos(x))*exp(x) :=
by { simp, ring }

example (x : ℂ) : differentiable_at ℂ (λ x, (cos x, x)) x := by simp

example (x : ℂ) (h : 1 + sin x ≠ 0) : deriv (λ x, exp (cos x) / (1 + sin x)) x =
  (-(exp (cos x) * sin x * (1 + sin x)) - exp (cos x) * cos x) / (1 + sin x) ^ 2 :=
by simp [h]

example (x : ℂ) : differentiable_at ℂ (λ x, (sin x) / (exp x)) x :=
by simp [exp_ne_zero]

example : differentiable ℂ (λ x, (sin x) / (exp x)) :=
by simp [exp_ne_zero]

end complex

namespace polynomial

variables {R : Type*} [comm_semiring R]

example : (2 : polynomial R).derivative = 0 :=
by conv_lhs { simp }

example : (3 + X : polynomial R).derivative = 1 :=
by conv_lhs { simp }

example : (2 * X ^ 2 : polynomial R).derivative = 4 * X :=
by conv_lhs { simp, ring_nf, }

example : (X ^ 2 : polynomial R).derivative = 2 * X :=
by conv_lhs { simp }

example : ((C 2 * X ^ 3).derivative : polynomial R) = 6 * X ^ 2 :=
by conv_lhs { simp, ring_nf, }

end polynomial


theorem add_right_cancel_iff (t a b : mynat) :  a + t = b + t ↔ a = b :=
begin
split,
exact add_right_cancel a t b,
intro h,
rwa [h],
end


-- Prueba de la regla de reducción al absurdo
-- ==========================================

import tactic

variable (P : Prop)

-- ----------------------------------------------------
-- Ej. 1 (p. 22) Demostrar que
--    ¬P → false ⊢ P
-- ----------------------------------------------------

-- 1ª demostración
example
  (h1 : ¬P → false)
  : P :=
have h2 : ¬¬P, from
  assume h3 : ¬P,
  show false, from h1 h3,
show P, from not_not.mp h2

-- 2ª demostración
example
  (h1 : ¬P → false)
  : P :=
begin
  apply not_not.mp,
  intro h2,
  exact h1 h2,
end

-- 3ª demostración
example
  (h1 : ¬P → false)
  : P :=
begin
  apply not_not.mp,
  exact λ h2, h1 h2,
end

-- 4ª demostración
example
  (h1 : ¬P → false)
  : P :=
not_not.mp (λ h2, h1 h2)

-- #print axioms not_not

-- 5ª demostración
example
  (h1 : ¬P → false)
  : P :=
-- by library_search
by_contra h1

-- #print axioms by_contra

-- 6ª demostración
lemma RAA
  (h1 : ¬P → false)
  : P :=
-- by hint
by finish

-- #print axioms RAA


import init.data.string init.data data.buffer.parser
import .types .parsing

open lambda_types
open lambda_types.term

def free_variables : term → list string
| (var n) := [n]
| (application m n) := free_variables m ++ free_variables n
| (abstraction x m) := list.filter (≠ x) (free_variables m)

lemma eq1 : ∀ m : term, m = m :=
by {
    intro, induction m,
    repeat {reflexivity}
}

lemma eq2 : ∀ m n : term, m = n → n = m :=
by {
    intros,
    rw a
}
lemma eq3 : ∀ n l k : term, n = k ∧ k = l → n = l :=
by {
    intros, destruct a, intros, rw left, rw right
}

lemma compat1 : ∀ m m' z : term, m = m' → application m z = application m' z :=
by {
    intros, rw a
}
lemma compat2 : ∀ m m' z : term, m = m' → application z m = application z m' :=
by {
   intros, rw a
}
lemma compat3 : ∀ m m' : term, ∀ x : string, m = m' → abstraction x m = abstraction x m' :=
by {
    intros, rw a
}

--have h : 1 > 0, from nat.zero_lt_succ 0,
--exists.intro 1 h

theorem fixpoint1 (F W : term) : ∃ X : term, application F X = X :=
begin
    intros,

    let W := abstraction "x" (application F (application (var "x") (var "x"))),

    --existsi (application
    --    (abstraction "x" (application F (application (var "x") (var "x"))))
    --    (abstraction "x" (application F (application (var "x") (var "x"))))),
    --simp,
    existsi (application W W),
    simp [W],
    sorry

    --X = WW = (λx.F(xx))W = F(WW) = FX
end

theorem fixpoint2
    (Y : term)
    (h1: Y =
        abstraction "f" (
            application
                ( abstraction "x" (application (var "f") ( application (var "x")  (var "x") )))
                ( abstraction "x" (application (var "f") ( application (var "x")  (var "x") ))))) :
    ∀ F : term, (application F (application Y F)) = (application Y F) :=
by {
    sorry
}

def parse : string → term
| str :=
    match parser.run_string lambda_parser.LambdaParser str  with
    | (sum.inr x) := x
    | (sum.inl _) := var "x"
    end

-- #eval list.filter (≠ 2) [1, 2, 3]

-- #eval free_variables ( (parse "(λ z x. x t) y z"))
-- #check ( (parser.run_string lambda_parser.LambdaParser "λ x. x").inr)


/-
Copyright (c) 2022 Floris van Doorn. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Floris van Doorn
-/
import measure_theory.integral.bochner
import measure_theory.group.measure
import measure_theory.group.action

/-!
# Integration on Groups

We develop properties of integrals with a group as domain.
This file contains properties about integrability, Lebesgue integration and Bochner integration.
-/

namespace measure_theory

open measure topological_space
open_locale ennreal

variables {𝕜 M α G E F : Type*} [measurable_space G]
variables [normed_add_comm_group E] [normed_space ℝ E] [complete_space E] [normed_add_comm_group F]
variables {μ : measure G} {f : G → E} {g : G}

section measurable_inv

variables [group G] [has_measurable_inv G]

@[to_additive]
lemma integrable.comp_inv [is_inv_invariant μ] {f : G → F} (hf : integrable f μ) :
  integrable (λ t, f t⁻¹) μ :=
(hf.mono_measure (map_inv_eq_self μ).le).comp_measurable measurable_inv

@[to_additive]
lemma integral_inv_eq_self (f : G → E) (μ : measure G) [is_inv_invariant μ] :
  ∫ x, f (x⁻¹) ∂μ = ∫ x, f x ∂μ :=
begin
  have h : measurable_embedding (λ x : G, x⁻¹) :=
  (measurable_equiv.inv G).measurable_embedding,
  rw [← h.integral_map, map_inv_eq_self]
end

end measurable_inv

section measurable_mul

variables [group G] [has_measurable_mul G]

/-- Translating a function by left-multiplication does not change its `measure_theory.lintegral`
with respect to a left-invariant measure. -/
@[to_additive "Translating a function by left-addition does not change its
`measure_theory.lintegral` with respect to a left-invariant measure."]
lemma lintegral_mul_left_eq_self [is_mul_left_invariant μ] (f : G → ℝ≥0∞) (g : G) :
  ∫⁻ x, f (g * x) ∂μ = ∫⁻ x, f x ∂μ :=
begin
  convert (lintegral_map_equiv f $ measurable_equiv.mul_left g).symm,
  simp [map_mul_left_eq_self μ g]
end

/-- Translating a function by right-multiplication does not change its `measure_theory.lintegral`
with respect to a right-invariant measure. -/
@[to_additive "Translating a function by right-addition does not change its
`measure_theory.lintegral` with respect to a right-invariant measure."]
lemma lintegral_mul_right_eq_self [is_mul_right_invariant μ] (f : G → ℝ≥0∞) (g : G) :
  ∫⁻ x, f (x * g) ∂μ = ∫⁻ x, f x ∂μ :=
begin
  convert (lintegral_map_equiv f $ measurable_equiv.mul_right g).symm,
  simp [map_mul_right_eq_self μ g]
end

@[simp, to_additive]
lemma lintegral_div_right_eq_self [is_mul_right_invariant μ] (f : G → ℝ≥0∞) (g : G) :
  ∫⁻ x, f (x / g) ∂μ = ∫⁻ x, f x ∂μ :=
by simp_rw [div_eq_mul_inv, lintegral_mul_right_eq_self f g⁻¹]

/-- Translating a function by left-multiplication does not change its integral with respect to a
left-invariant measure. -/
@[simp, to_additive "Translating a function by left-addition does not change its integral with
  respect to a left-invariant measure."]
lemma integral_mul_left_eq_self [is_mul_left_invariant μ] (f : G → E) (g : G) :
  ∫ x, f (g * x) ∂μ = ∫ x, f x ∂μ :=
begin
  have h_mul : measurable_embedding (λ x, g * x) :=
    (measurable_equiv.mul_left g).measurable_embedding,
  rw [← h_mul.integral_map, map_mul_left_eq_self]
end

/-- Translating a function by right-multiplication does not change its integral with respect to a
right-invariant measure. -/
@[simp, to_additive "Translating a function by right-addition does not change its integral with
  respect to a right-invariant measure."]
lemma integral_mul_right_eq_self [is_mul_right_invariant μ] (f : G → E) (g : G) :
  ∫ x, f (x * g) ∂μ = ∫ x, f x ∂μ :=
begin
  have h_mul : measurable_embedding (λ x, x * g) :=
    (measurable_equiv.mul_right g).measurable_embedding,
  rw [← h_mul.integral_map, map_mul_right_eq_self]
end

@[simp, to_additive]
lemma integral_div_right_eq_self [is_mul_right_invariant μ] (f : G → E) (g : G) :
  ∫ x, f (x / g) ∂μ = ∫ x, f x ∂μ :=
by simp_rw [div_eq_mul_inv, integral_mul_right_eq_self f g⁻¹]

/-- If some left-translate of a function negates it, then the integral of the function with respect
to a left-invariant measure is 0. -/
@[to_additive "If some left-translate of a function negates it, then the integral of the function
with respect to a left-invariant measure is 0."]
lemma integral_eq_zero_of_mul_left_eq_neg [is_mul_left_invariant μ] (hf' : ∀ x, f (g * x) = - f x) :
  ∫ x, f x ∂μ = 0 :=
by simp_rw [← self_eq_neg ℝ E, ← integral_neg, ← hf', integral_mul_left_eq_self]

/-- If some right-translate of a function negates it, then the integral of the function with respect
to a right-invariant measure is 0. -/
@[to_additive "If some right-translate of a function negates it, then the integral of the function
with respect to a right-invariant measure is 0."]
lemma integral_eq_zero_of_mul_right_eq_neg [is_mul_right_invariant μ]
  (hf' : ∀ x, f (x * g) = - f x) : ∫ x, f x ∂μ = 0 :=
by simp_rw [← self_eq_neg ℝ E, ← integral_neg, ← hf', integral_mul_right_eq_self]

@[to_additive]
lemma integrable.comp_mul_left {f : G → F} [is_mul_left_invariant μ] (hf : integrable f μ)
  (g : G) : integrable (λ t, f (g * t)) μ :=
(hf.mono_measure (map_mul_left_eq_self μ g).le).comp_measurable $ measurable_const_mul g

@[to_additive]
lemma integrable.comp_mul_right {f : G → F} [is_mul_right_invariant μ] (hf : integrable f μ)
  (g : G) : integrable (λ t, f (t * g)) μ :=
(hf.mono_measure (map_mul_right_eq_self μ g).le).comp_measurable $ measurable_mul_const g

@[to_additive]
lemma integrable.comp_div_right {f : G → F} [is_mul_right_invariant μ] (hf : integrable f μ)
  (g : G) : integrable (λ t, f (t / g)) μ :=
by { simp_rw [div_eq_mul_inv], exact hf.comp_mul_right g⁻¹ }

variables [has_measurable_inv G]

@[to_additive]
lemma integrable.comp_div_left {f : G → F}
  [is_inv_invariant μ] [is_mul_left_invariant μ] (hf : integrable f μ) (g : G) :
  integrable (λ t, f (g / t)) μ :=
((measure_preserving_div_left μ g).integrable_comp hf.ae_strongly_measurable).mpr hf

@[simp, to_additive]
lemma integrable_comp_div_left (f : G → F)
  [is_inv_invariant μ] [is_mul_left_invariant μ] (g : G) :
  integrable (λ t, f (g / t)) μ ↔ integrable f μ :=
begin
  refine ⟨λ h, _, λ h, h.comp_div_left g⟩,
  convert h.comp_inv.comp_mul_left g⁻¹,
  simp_rw [div_inv_eq_mul, mul_inv_cancel_left]
end

@[simp, to_additive]
lemma integral_div_left_eq_self (f : G → E) (μ : measure G) [is_inv_invariant μ]
  [is_mul_left_invariant μ] (x' : G) : ∫ x, f (x' / x) ∂μ = ∫ x, f x ∂μ :=
by simp_rw [div_eq_mul_inv, integral_inv_eq_self (λ x, f (x' * x)) μ,
  integral_mul_left_eq_self f x']

end measurable_mul

section smul

variables [group G] [measurable_space α] [mul_action G α] [has_measurable_smul G α]

@[simp, to_additive]

end smul

section topological_group

variables [topological_space G] [group G] [topological_group G] [borel_space G]
  [is_mul_left_invariant μ]

/-- For nonzero regular left invariant measures, the integral of a continuous nonnegative function
  `f` is 0 iff `f` is 0. -/
@[to_additive "For nonzero regular left invariant measures, the integral of a continuous nonnegative
function `f` is 0 iff `f` is 0."]
lemma lintegral_eq_zero_of_is_mul_left_invariant [regular μ] (hμ : μ ≠ 0)
  {f : G → ℝ≥0∞} (hf : continuous f) :
  ∫⁻ x, f x ∂μ = 0 ↔ f = 0 :=
begin
  haveI := is_open_pos_measure_of_mul_left_invariant_of_regular hμ,
  rw [lintegral_eq_zero_iff hf.measurable, hf.ae_eq_iff_eq μ continuous_zero]
end

end topological_group

end measure_theory


/-
Copyright (c) 2018 Kevin Buzzard, Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kevin Buzzard, Patrick Massot

This file is to a certain extent based on `quotient_module.lean` by Johannes Hölzl.
-/
import group_theory.coset

/-!
# Quotients of groups by normal subgroups

This files develops the basic theory of quotients of groups by normal subgroups. In particular it
proves Noether's first and second isomorphism theorems.

## Main definitions

* `mk'`: the canonical group homomorphism `G →* G/N` given a normal subgroup `N` of `G`.
* `lift φ`: the group homomorphism `G/N →* H` given a group homomorphism `φ : G →* H` such that
  `N ⊆ ker φ`.
* `map f`: the group homomorphism `G/N →* H/M` given a group homomorphism `f : G →* H` such that
  `N ⊆ f⁻¹(M)`.

## Main statements

* `quotient_ker_equiv_range`: Noether's first isomorphism theorem, an explicit isomorphism
  `G/ker φ → range φ` for every group homomorphism `φ : G →* H`.
* `quotient_inf_equiv_prod_normal_quotient`: Noether's second isomorphism theorem, an explicit
  isomorphism between `H/(H ∩ N)` and `(HN)/N` given a subgroup `H` and a normal subgroup `N` of a
  group `G`.

## Tags

isomorphism theorems, quotient groups

## TODO

Noether's third isomorphism theorem
-/

universes u v

namespace quotient_group

variables {G : Type u} [group G] (N : subgroup G) [nN : N.normal] {H : Type v} [group H]
include nN

-- Define the `div_inv_monoid` before the `group` structure,
-- to make sure we have `inv` fully defined before we show `mul_left_inv`.
-- TODO: is there a non-invasive way of defining this in one declaration?
@[to_additive quotient_add_group.div_inv_monoid]
instance : div_inv_monoid (quotient N) :=
{ one := (1 : G),
  mul := quotient.map₂' (*)
  (λ a₁ b₁ hab₁ a₂ b₂ hab₂,
    ((N.mul_mem_cancel_right (N.inv_mem hab₂)).1
        (by rw [mul_inv_rev, mul_inv_rev, ← mul_assoc (a₂⁻¹ * a₁⁻¹),
          mul_assoc _ b₂, ← mul_assoc b₂, mul_inv_self, one_mul, mul_assoc (a₂⁻¹)];
          exact nN.conj_mem _ hab₁ _))),
  mul_assoc := λ a b c, quotient.induction_on₃' a b c
    (λ a b c, congr_arg mk (mul_assoc a b c)),
  one_mul := λ a, quotient.induction_on' a
    (λ a, congr_arg mk (one_mul a)),
  mul_one := λ a, quotient.induction_on' a
    (λ a, congr_arg mk (mul_one a)),
  inv := λ a, quotient.lift_on' a (λ a, ((a⁻¹ : G) : quotient N))
    (λ a b hab, quotient.sound' begin
      show a⁻¹⁻¹ * b⁻¹ ∈ N,
      rw ← mul_inv_rev,
      exact N.inv_mem (nN.mem_comm hab)
    end) }

@[to_additive quotient_add_group.add_group]
instance : group (quotient N) :=
{ mul_left_inv := λ a, quotient.induction_on' a
    (λ a, congr_arg mk (mul_left_inv a)),
 .. quotient.div_inv_monoid _ }

/-- The group homomorphism from `G` to `G/N`. -/
@[to_additive quotient_add_group.mk' "The additive group homomorphism from `G` to `G/N`."]
def mk' : G →* quotient N := monoid_hom.mk' (quotient_group.mk) (λ _ _, rfl)

@[simp, to_additive quotient_add_group.ker_mk]
lemma ker_mk :
  monoid_hom.ker (quotient_group.mk' N : G →* quotient_group.quotient N) = N :=
begin
  ext g,
  rw [monoid_hom.mem_ker, eq_comm],
  show (((1 : G) : quotient_group.quotient N)) = g ↔ _,
  rw [quotient_group.eq, one_inv, one_mul],
end

-- for commutative groups we don't need normality assumption
omit nN

@[to_additive quotient_add_group.add_comm_group]
instance {G : Type*} [comm_group G] (N : subgroup G) : comm_group (quotient N) :=
{ mul_comm := λ a b, quotient.induction_on₂' a b
    (λ a b, congr_arg mk (mul_comm a b)),
  .. @quotient_group.quotient.group _ _ N N.normal_of_comm }

include nN

local notation ` Q ` := quotient N

@[simp, to_additive quotient_add_group.coe_zero]
lemma coe_one : ((1 : G) : Q) = 1 := rfl

@[simp, to_additive quotient_add_group.coe_add]
lemma coe_mul (a b : G) : ((a * b : G) : Q) = a * b := rfl

@[simp, to_additive quotient_add_group.coe_neg]
lemma coe_inv (a : G) : ((a⁻¹ : G) : Q) = a⁻¹ := rfl

@[simp] lemma coe_pow (a : G) (n : ℕ) : ((a ^ n : G) : Q) = a ^ n :=
(mk' N).map_pow a n

@[simp] lemma coe_gpow (a : G) (n : ℤ) : ((a ^ n : G) : Q) = a ^ n :=
(mk' N).map_gpow a n

/-- A group homomorphism `φ : G →* H` with `N ⊆ ker(φ)` descends (i.e. `lift`s) to a
group homomorphism `G/N →* H`. -/
@[to_additive quotient_add_group.lift "An `add_group` homomorphism `φ : G →+ H` with `N ⊆ ker(φ)`
descends (i.e. `lift`s) to a group homomorphism `G/N →* H`."]
def lift (φ : G →* H) (HN : ∀x∈N, φ x = 1) : Q →* H :=
monoid_hom.mk'
  (λ q : Q, q.lift_on' φ $ assume a b (hab : a⁻¹ * b ∈ N),
  (calc φ a = φ a * 1           : (mul_one _).symm
  ...       = φ a * φ (a⁻¹ * b) : HN (a⁻¹ * b) hab ▸ rfl
  ...       = φ (a * (a⁻¹ * b)) : (is_mul_hom.map_mul φ a (a⁻¹ * b)).symm
  ...       = φ b               : by rw mul_inv_cancel_left))
  (λ q r, quotient.induction_on₂' q r $ is_mul_hom.map_mul φ)

@[simp, to_additive quotient_add_group.lift_mk]
lemma lift_mk {φ : G →* H} (HN : ∀x∈N, φ x = 1) (g : G) :
  lift N φ HN (g : Q) = φ g := rfl

@[simp, to_additive quotient_add_group.lift_mk']
lemma lift_mk' {φ : G →* H} (HN : ∀x∈N, φ x = 1) (g : G) :
  lift N φ HN (mk g : Q) = φ g := rfl

@[simp, to_additive quotient_add_group.lift_quot_mk]
lemma lift_quot_mk {φ : G →* H} (HN : ∀x∈N, φ x = 1) (g : G) :
  lift N φ HN (quot.mk _ g : Q) = φ g := rfl

/-- A group homomorphism `f : G →* H` induces a map `G/N →* H/M` if `N ⊆ f⁻¹(M)`. -/
@[to_additive quotient_add_group.map "An `add_group` homomorphism `f : G →+ H` induces a map
`G/N →+ H/M` if `N ⊆ f⁻¹(M)`."]
def map (M : subgroup H) [M.normal] (f : G →* H) (h : N ≤ M.comap f) :
  quotient N →* quotient M :=
begin
  refine quotient_group.lift N ((mk' M).comp f) _,
  assume x hx,
  refine quotient_group.eq.2 _,
  rw [mul_one, subgroup.inv_mem_iff],
  exact h hx,
end

omit nN
variables (φ : G →* H)

open function monoid_hom

/-- The induced map from the quotient by the kernel to the codomain. -/
@[to_additive quotient_add_group.ker_lift "The induced map from the quotient by the kernel to the
codomain."]
def ker_lift : quotient (ker φ) →* H :=
lift _ φ $ λ g, φ.mem_ker.mp

@[simp, to_additive quotient_add_group.ker_lift_mk]
lemma ker_lift_mk (g : G) : (ker_lift φ) g = φ g :=
lift_mk _ _ _

@[simp, to_additive quotient_add_group.ker_lift_mk']
lemma ker_lift_mk' (g : G) : (ker_lift φ) (mk g) = φ g :=
lift_mk' _ _ _

@[to_additive quotient_add_group.injective_ker_lift]
lemma ker_lift_injective : injective (ker_lift φ) :=
assume a b, quotient.induction_on₂' a b $
  assume a b (h : φ a = φ b), quotient.sound' $
show a⁻¹ * b ∈ ker φ, by rw [mem_ker,
  is_mul_hom.map_mul φ, ← h, is_group_hom.map_inv φ, inv_mul_self]

-- Note that `ker φ` isn't definitionally `ker (φ.range_restrict)`
-- so there is a bit of annoying code duplication here

/-- The induced map from the quotient by the kernel to the range. -/
@[to_additive quotient_add_group.range_ker_lift "The induced map from the quotient by the kernel to
the range."]
def range_ker_lift : quotient (ker φ) →* φ.range :=
lift _ φ.range_restrict $ λ g hg, (mem_ker _).mp $ by rwa range_restrict_ker

@[to_additive quotient_add_group.range_ker_lift_injective]
lemma range_ker_lift_injective : injective (range_ker_lift φ) :=
assume a b, quotient.induction_on₂' a b $
  assume a b (h : φ.range_restrict a = φ.range_restrict b), quotient.sound' $
show a⁻¹ * b ∈ ker φ, by rw [←range_restrict_ker, mem_ker,
  φ.range_restrict.map_mul, ← h, φ.range_restrict.map_inv, inv_mul_self]

@[to_additive quotient_add_group.range_ker_lift_surjective]
lemma range_ker_lift_surjective : surjective (range_ker_lift φ) :=
begin
  rintro ⟨_, g, rfl⟩,
  use mk g,
  refl,
end

/-- The first isomorphism theorem (a definition): the canonical isomorphism between
`G/(ker φ)` to `range φ`. -/
@[to_additive quotient_add_group.quotient_ker_equiv_range "The first isomorphism theorem
(a definition): the canonical isomorphism between `G/(ker φ)` to `range φ`."]
noncomputable def quotient_ker_equiv_range : (quotient (ker φ)) ≃* range φ :=
mul_equiv.of_bijective (range_ker_lift φ) ⟨range_ker_lift_injective φ, range_ker_lift_surjective φ⟩

/-- The canonical isomorphism `G/(ker φ) ≃* H` induced by a surjection `φ : G →* H`. -/
@[to_additive quotient_add_group.quotient_ker_equiv_of_surjective "The canonical isomorphism
`G/(ker φ) ≃+ H` induced by a surjection `φ : G →+ H`."]
noncomputable def quotient_ker_equiv_of_surjective (hφ : function.surjective φ) :
  (quotient (ker φ)) ≃* H :=
mul_equiv.of_bijective (ker_lift φ) ⟨ker_lift_injective φ, λ h, begin
  rcases hφ h with ⟨g, rfl⟩,
  use mk g,
  refl
end⟩

/-- If two normal subgroups `M` and `N` of `G` are the same, their quotient groups are
isomorphic. -/
@[to_additive "If two normal subgroups `M` and `N` of `G` are the same, their quotient groups are
isomorphic."]
def equiv_quotient_of_eq {M N : subgroup G} [M.normal] [N.normal] (h : M = N) :
  quotient M ≃* quotient N :=
{ to_fun := (lift M (mk' N) (λ m hm, quotient_group.eq.mpr (by simpa [← h] using M.inv_mem hm))),
  inv_fun := (lift N (mk' M) (λ n hn, quotient_group.eq.mpr (by simpa [← h] using N.inv_mem hn))),
  left_inv := λ x, x.induction_on' $ by { intro, refl },
  right_inv := λ x, x.induction_on' $ by { intro, refl },
  map_mul' := λ x y, by rw map_mul }

section snd_isomorphism_thm

open subgroup

/-- The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where `N`
is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`,
where `N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotient_inf_equiv_prod_normal_quotient (H N : subgroup G) [N.normal] :
  quotient ((H ⊓ N).comap H.subtype) ≃* quotient (N.comap (H ⊔ N).subtype) :=
/- φ is the natural homomorphism H →* (HN)/N. -/
let φ : H →* quotient (N.comap (H ⊔ N).subtype) :=
  (mk' $ N.comap (H ⊔ N).subtype).comp (inclusion le_sup_left) in
have φ_surjective : function.surjective φ := λ x, x.induction_on' $
  begin
    rintro ⟨y, (hy : y ∈ ↑(H ⊔ N))⟩, rw mul_normal H N at hy,
    rcases hy with ⟨h, n, hh, hn, rfl⟩,
    use [h, hh], apply quotient.eq.mpr, change h⁻¹ * (h * n) ∈ N,
    rwa [←mul_assoc, inv_mul_self, one_mul],
  end,
(equiv_quotient_of_eq (by simp [comap_comap, ←comap_ker])).trans
  (quotient_ker_equiv_of_surjective φ φ_surjective)

end snd_isomorphism_thm

end quotient_group