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

! This file was ported from Lean 3 source module group_theory.subgroup.zpowers
! leanprover-community/mathlib commit a11f9106a169dd302a285019e5165f8ab32ff433
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.GroupTheory.Subgroup.Basic

/-!
# Subgroups generated by an element

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

## Tags
subgroup, subgroups

-/

variable {G : Type _} [Group G]

variable {A : Type _} [AddGroup A]

variable {N : Type _} [Group N]

namespace Subgroup

#print Subgroup.zpowers /-
/-- The subgroup generated by an element. -/
def zpowers (g : G) : Subgroup G :=
  Subgroup.copy (zpowersHom G g).range (Set.range ((· ^ ·) g : ℤ → G)) rfl
#align subgroup.zpowers Subgroup.zpowers
-/

/- warning: subgroup.mem_zpowers -> Subgroup.mem_zpowers is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G), Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g (Subgroup.zpowers.{u1} G _inst_1 g)
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G), Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) g (Subgroup.zpowers.{u1} G _inst_1 g)
Case conversion may be inaccurate. Consider using '#align subgroup.mem_zpowers Subgroup.mem_zpowersₓ'. -/
@[simp]
theorem mem_zpowers (g : G) : g ∈ zpowers g :=
  ⟨1, zpow_one _⟩
#align subgroup.mem_zpowers Subgroup.mem_zpowers

#print Subgroup.zpowers_eq_closure /-
theorem zpowers_eq_closure (g : G) : zpowers g = closure {g} :=
  by
  ext
  exact mem_closure_singleton.symm
#align subgroup.zpowers_eq_closure Subgroup.zpowers_eq_closure
-/

#print Subgroup.range_zpowersHom /-
@[simp]
theorem range_zpowersHom (g : G) : (zpowersHom G g).range = zpowers g :=
  rfl
#align subgroup.range_zpowers_hom Subgroup.range_zpowersHom
-/

/- warning: subgroup.zpowers_subset -> Subgroup.zpowers_subset is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {a : G} {K : Subgroup.{u1} G _inst_1}, (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) a K) -> (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (SetLike.partialOrder.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) (Subgroup.zpowers.{u1} G _inst_1 a) K)
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {a : G} {K : Subgroup.{u1} G _inst_1}, (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) a K) -> (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G _inst_1) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instCompleteLatticeSubgroup.{u1} G _inst_1))))) (Subgroup.zpowers.{u1} G _inst_1 a) K)
Case conversion may be inaccurate. Consider using '#align subgroup.zpowers_subset Subgroup.zpowers_subsetₓ'. -/
theorem zpowers_subset {a : G} {K : Subgroup G} (h : a ∈ K) : zpowers a ≤ K := fun x hx =>
  match x, hx with
  | _, ⟨i, rfl⟩ => K.zpow_mem h i
#align subgroup.zpowers_subset Subgroup.zpowers_subset

/- warning: subgroup.mem_zpowers_iff -> Subgroup.mem_zpowers_iff is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g : G} {h : G}, Iff (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) h (Subgroup.zpowers.{u1} G _inst_1 g)) (Exists.{1} Int (fun (k : Int) => Eq.{succ u1} G (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) g k) h))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g : G} {h : G}, Iff (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) h (Subgroup.zpowers.{u1} G _inst_1 g)) (Exists.{1} Int (fun (k : Int) => Eq.{succ u1} G (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) g k) h))
Case conversion may be inaccurate. Consider using '#align subgroup.mem_zpowers_iff Subgroup.mem_zpowers_iffₓ'. -/
theorem mem_zpowers_iff {g h : G} : h ∈ zpowers g ↔ ∃ k : ℤ, g ^ k = h :=
  Iff.rfl
#align subgroup.mem_zpowers_iff Subgroup.mem_zpowers_iff

/- warning: subgroup.zpow_mem_zpowers -> Subgroup.zpow_mem_zpowers is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G) (k : Int), Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) g k) (Subgroup.zpowers.{u1} G _inst_1 g)
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G) (k : Int), Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) g k) (Subgroup.zpowers.{u1} G _inst_1 g)
Case conversion may be inaccurate. Consider using '#align subgroup.zpow_mem_zpowers Subgroup.zpow_mem_zpowersₓ'. -/
@[simp]
theorem zpow_mem_zpowers (g : G) (k : ℤ) : g ^ k ∈ zpowers g :=
  mem_zpowers_iff.mpr ⟨k, rfl⟩
#align subgroup.zpow_mem_zpowers Subgroup.zpow_mem_zpowers

/- warning: subgroup.npow_mem_zpowers -> Subgroup.npow_mem_zpowers is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G) (k : Nat), Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) (HPow.hPow.{u1, 0, u1} G Nat G (instHPow.{u1, 0} G Nat (Monoid.Pow.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))) g k) (Subgroup.zpowers.{u1} G _inst_1 g)
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (g : G) (k : Nat), Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) (HPow.hPow.{u1, 0, u1} G Nat G (instHPow.{u1, 0} G Nat (Monoid.Pow.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))) g k) (Subgroup.zpowers.{u1} G _inst_1 g)
Case conversion may be inaccurate. Consider using '#align subgroup.npow_mem_zpowers Subgroup.npow_mem_zpowersₓ'. -/
@[simp]
theorem npow_mem_zpowers (g : G) (k : ℕ) : g ^ k ∈ zpowers g :=
  zpow_ofNat g k ▸ zpow_mem_zpowers g k
#align subgroup.npow_mem_zpowers Subgroup.npow_mem_zpowers

/- warning: subgroup.forall_zpowers -> Subgroup.forall_zpowers is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {x : G} {p : (coeSort.{succ u1, succ (succ u1)} (Subgroup.{u1} G _inst_1) Type.{u1} (SetLike.hasCoeToSort.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) (Subgroup.zpowers.{u1} G _inst_1 x)) -> Prop}, Iff (forall (g : coeSort.{succ u1, succ (succ u1)} (Subgroup.{u1} G _inst_1) Type.{u1} (SetLike.hasCoeToSort.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) (Subgroup.zpowers.{u1} G _inst_1 x)), p g) (forall (m : Int), p (Subtype.mk.{succ u1} G (fun (x_1 : G) => Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) x_1 (Subgroup.zpowers.{u1} G _inst_1 x)) (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m) (Exists.intro.{1} Int (fun (y : Int) => Eq.{succ u1} G (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x y) (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m)) m (rfl.{succ u1} G (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m)))))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {x : G} {p : (Subtype.{succ u1} G (fun (x_1 : G) => Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) x_1 (Subgroup.zpowers.{u1} G _inst_1 x))) -> Prop}, Iff (forall (g : Subtype.{succ u1} G (fun (x_1 : G) => Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) x_1 (Subgroup.zpowers.{u1} G _inst_1 x))), p g) (forall (m : Int), p (Subtype.mk.{succ u1} G (fun (x_1 : G) => Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) x_1 (Subgroup.zpowers.{u1} G _inst_1 x)) (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m) (Exists.intro.{1} Int (fun (y : Int) => Eq.{succ u1} G ((fun (x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.75 : G) (x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.77 : Int) => HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.75 x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.77) x y) (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m)) m (rfl.{succ u1} G ((fun (x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.75 : G) (x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.77 : Int) => HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.75 x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.77) x m)))))
Case conversion may be inaccurate. Consider using '#align subgroup.forall_zpowers Subgroup.forall_zpowersₓ'. -/
@[simp]
theorem forall_zpowers {x : G} {p : zpowers x → Prop} : (∀ g, p g) ↔ ∀ m : ℤ, p ⟨x ^ m, m, rfl⟩ :=
  Set.forall_subtype_range_iff
#align subgroup.forall_zpowers Subgroup.forall_zpowers

/- warning: subgroup.exists_zpowers -> Subgroup.exists_zpowers is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {x : G} {p : (coeSort.{succ u1, succ (succ u1)} (Subgroup.{u1} G _inst_1) Type.{u1} (SetLike.hasCoeToSort.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) (Subgroup.zpowers.{u1} G _inst_1 x)) -> Prop}, Iff (Exists.{succ u1} (coeSort.{succ u1, succ (succ u1)} (Subgroup.{u1} G _inst_1) Type.{u1} (SetLike.hasCoeToSort.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) (Subgroup.zpowers.{u1} G _inst_1 x)) (fun (g : coeSort.{succ u1, succ (succ u1)} (Subgroup.{u1} G _inst_1) Type.{u1} (SetLike.hasCoeToSort.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) (Subgroup.zpowers.{u1} G _inst_1 x)) => p g)) (Exists.{1} Int (fun (m : Int) => p (Subtype.mk.{succ u1} G (fun (x_1 : G) => Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) x_1 (Subgroup.zpowers.{u1} G _inst_1 x)) (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m) (Exists.intro.{1} Int (fun (y : Int) => Eq.{succ u1} G (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x y) (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m)) m (rfl.{succ u1} G (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m))))))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {x : G} {p : (Subtype.{succ u1} G (fun (x_1 : G) => Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) x_1 (Subgroup.zpowers.{u1} G _inst_1 x))) -> Prop}, Iff (Exists.{succ u1} (Subtype.{succ u1} G (fun (x_1 : G) => Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) x_1 (Subgroup.zpowers.{u1} G _inst_1 x))) (fun (g : Subtype.{succ u1} G (fun (x_1 : G) => Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) x_1 (Subgroup.zpowers.{u1} G _inst_1 x))) => p g)) (Exists.{1} Int (fun (m : Int) => p (Subtype.mk.{succ u1} G (fun (x_1 : G) => Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) x_1 (Subgroup.zpowers.{u1} G _inst_1 x)) (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m) (Exists.intro.{1} Int (fun (y : Int) => Eq.{succ u1} G ((fun (x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.75 : G) (x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.77 : Int) => HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.75 x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.77) x y) (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m)) m (rfl.{succ u1} G ((fun (x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.75 : G) (x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.77 : Int) => HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.75 x._@.Mathlib.GroupTheory.Subgroup.Zpowers._hyg.77) x m))))))
Case conversion may be inaccurate. Consider using '#align subgroup.exists_zpowers Subgroup.exists_zpowersₓ'. -/
@[simp]
theorem exists_zpowers {x : G} {p : zpowers x → Prop} : (∃ g, p g) ↔ ∃ m : ℤ, p ⟨x ^ m, m, rfl⟩ :=
  Set.exists_subtype_range_iff
#align subgroup.exists_zpowers Subgroup.exists_zpowers

/- warning: subgroup.forall_mem_zpowers -> Subgroup.forall_mem_zpowers is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {x : G} {p : G -> Prop}, Iff (forall (g : G), (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g (Subgroup.zpowers.{u1} G _inst_1 x)) -> (p g)) (forall (m : Int), p (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {x : G} {p : G -> Prop}, Iff (forall (g : G), (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) g (Subgroup.zpowers.{u1} G _inst_1 x)) -> (p g)) (forall (m : Int), p (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m))
Case conversion may be inaccurate. Consider using '#align subgroup.forall_mem_zpowers Subgroup.forall_mem_zpowersₓ'. -/
theorem forall_mem_zpowers {x : G} {p : G → Prop} : (∀ g ∈ zpowers x, p g) ↔ ∀ m : ℤ, p (x ^ m) :=
  Set.forall_range_iff
#align subgroup.forall_mem_zpowers Subgroup.forall_mem_zpowers

/- warning: subgroup.exists_mem_zpowers -> Subgroup.exists_mem_zpowers is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {x : G} {p : G -> Prop}, Iff (Exists.{succ u1} G (fun (g : G) => Exists.{0} (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g (Subgroup.zpowers.{u1} G _inst_1 x)) (fun (H : Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g (Subgroup.zpowers.{u1} G _inst_1 x)) => p g))) (Exists.{1} Int (fun (m : Int) => p (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m)))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {x : G} {p : G -> Prop}, Iff (Exists.{succ u1} G (fun (g : G) => And (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) g (Subgroup.zpowers.{u1} G _inst_1 x)) (p g))) (Exists.{1} Int (fun (m : Int) => p (HPow.hPow.{u1, 0, u1} G Int G (instHPow.{u1, 0} G Int (DivInvMonoid.Pow.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) x m)))
Case conversion may be inaccurate. Consider using '#align subgroup.exists_mem_zpowers Subgroup.exists_mem_zpowersₓ'. -/
theorem exists_mem_zpowers {x : G} {p : G → Prop} : (∃ g ∈ zpowers x, p g) ↔ ∃ m : ℤ, p (x ^ m) :=
  Set.exists_range_iff
#align subgroup.exists_mem_zpowers Subgroup.exists_mem_zpowers

instance (a : G) : Countable (zpowers a) :=
  ((zpowersHom G a).rangeRestrict_surjective.comp Multiplicative.ofAdd.Surjective).Countable

end Subgroup

namespace AddSubgroup

#print AddSubgroup.zmultiples /-
/-- The subgroup generated by an element. -/
def zmultiples (a : A) : AddSubgroup A :=
  AddSubgroup.copy (zmultiplesHom A a).range (Set.range ((· • a) : ℤ → A)) rfl
#align add_subgroup.zmultiples AddSubgroup.zmultiples
-/

#print AddSubgroup.range_zmultiplesHom /-
@[simp]
theorem range_zmultiplesHom (a : A) : (zmultiplesHom A a).range = zmultiples a :=
  rfl
#align add_subgroup.range_zmultiples_hom AddSubgroup.range_zmultiplesHom
-/

attribute [to_additive AddSubgroup.zmultiples] Subgroup.zpowers

attribute [to_additive AddSubgroup.mem_zmultiples] Subgroup.mem_zpowers

attribute [to_additive AddSubgroup.zmultiples_eq_closure] Subgroup.zpowers_eq_closure

attribute [to_additive AddSubgroup.range_zmultiplesHom] Subgroup.range_zpowersHom

attribute [to_additive AddSubgroup.zmultiples_subset] Subgroup.zpowers_subset

attribute [to_additive AddSubgroup.mem_zmultiples_iff] Subgroup.mem_zpowers_iff

attribute [to_additive AddSubgroup.zsmul_mem_zmultiples] Subgroup.zpow_mem_zpowers

attribute [to_additive AddSubgroup.nsmul_mem_zmultiples] Subgroup.npow_mem_zpowers

attribute [to_additive AddSubgroup.forall_zmultiples] Subgroup.forall_zpowers

attribute [to_additive AddSubgroup.forall_mem_zmultiples] Subgroup.forall_mem_zpowers

attribute [to_additive AddSubgroup.exists_zmultiples] Subgroup.exists_zpowers

attribute [to_additive AddSubgroup.exists_mem_zmultiples] Subgroup.exists_mem_zpowers

instance (a : A) : Countable (zmultiples a) :=
  (zmultiplesHom A a).rangeRestrict_surjective.Countable

section Ring

variable {R : Type _} [Ring R] (r : R) (k : ℤ)

/- warning: add_subgroup.int_cast_mul_mem_zmultiples -> AddSubgroup.int_cast_mul_mem_zmultiples is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_4 : Ring.{u1} R] (r : R) (k : Int), Membership.Mem.{u1, u1} R (AddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_4)))) (SetLike.hasMem.{u1, u1} (AddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_4)))) R (AddSubgroup.setLike.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_4))))) (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (Distrib.toHasMul.{u1} R (Ring.toDistrib.{u1} R _inst_4))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Int R (HasLiftT.mk.{1, succ u1} Int R (CoeTCₓ.coe.{1, succ u1} Int R (Int.castCoe.{u1} R (AddGroupWithOne.toHasIntCast.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_4)))))) k) r) (AddSubgroup.zmultiples.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_4))) r)
but is expected to have type
  forall {R : Type.{u1}} [_inst_4 : Ring.{u1} R] (r : R) (k : Int), Membership.mem.{u1, u1} R (AddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_4))) (SetLike.instMembership.{u1, u1} (AddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_4))) R (AddSubgroup.instSetLikeAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_4)))) (HMul.hMul.{u1, u1, u1} R R R (instHMul.{u1} R (NonUnitalNonAssocRing.toMul.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R _inst_4)))) (Int.cast.{u1} R (Ring.toIntCast.{u1} R _inst_4) k) r) (AddSubgroup.zmultiples.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_4)) r)
Case conversion may be inaccurate. Consider using '#align add_subgroup.int_cast_mul_mem_zmultiples AddSubgroup.int_cast_mul_mem_zmultiplesₓ'. -/
@[simp]
theorem int_cast_mul_mem_zmultiples : ↑(k : ℤ) * r ∈ zmultiples r := by
  simpa only [← zsmul_eq_mul] using zsmul_mem_zmultiples r k
#align add_subgroup.int_cast_mul_mem_zmultiples AddSubgroup.int_cast_mul_mem_zmultiples

/- warning: add_subgroup.int_cast_mem_zmultiples_one -> AddSubgroup.int_cast_mem_zmultiples_one is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_4 : Ring.{u1} R] (k : Int), Membership.Mem.{u1, u1} R (AddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_4)))) (SetLike.hasMem.{u1, u1} (AddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_4)))) R (AddSubgroup.setLike.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_4))))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Int R (HasLiftT.mk.{1, succ u1} Int R (CoeTCₓ.coe.{1, succ u1} Int R (Int.castCoe.{u1} R (AddGroupWithOne.toHasIntCast.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_4)))))) k) (AddSubgroup.zmultiples.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_4))) (OfNat.ofNat.{u1} R 1 (OfNat.mk.{u1} R 1 (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R _inst_4))))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_4 : Ring.{u1} R] (k : Int), Membership.mem.{u1, u1} R (AddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_4))) (SetLike.instMembership.{u1, u1} (AddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_4))) R (AddSubgroup.instSetLikeAddSubgroup.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_4)))) (Int.cast.{u1} R (Ring.toIntCast.{u1} R _inst_4) k) (AddSubgroup.zmultiples.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (Ring.toAddGroupWithOne.{u1} R _inst_4)) (OfNat.ofNat.{u1} R 1 (One.toOfNat1.{u1} R (NonAssocRing.toOne.{u1} R (Ring.toNonAssocRing.{u1} R _inst_4)))))
Case conversion may be inaccurate. Consider using '#align add_subgroup.int_cast_mem_zmultiples_one AddSubgroup.int_cast_mem_zmultiples_oneₓ'. -/
@[simp]
theorem int_cast_mem_zmultiples_one : ↑(k : ℤ) ∈ zmultiples (1 : R) :=
  mem_zmultiples_iff.mp ⟨k, by simp⟩
#align add_subgroup.int_cast_mem_zmultiples_one AddSubgroup.int_cast_mem_zmultiples_one

end Ring

end AddSubgroup

/- warning: monoid_hom.map_zpowers -> MonoidHom.map_zpowers is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {N : Type.{u2}} [_inst_3 : Group.{u2} N] (f : MonoidHom.{u1, u2} G N (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} N (DivInvMonoid.toMonoid.{u2} N (Group.toDivInvMonoid.{u2} N _inst_3)))) (x : G), Eq.{succ u2} (Subgroup.{u2} N _inst_3) (Subgroup.map.{u1, u2} G _inst_1 N _inst_3 f (Subgroup.zpowers.{u1} G _inst_1 x)) (Subgroup.zpowers.{u2} N _inst_3 (coeFn.{max (succ u2) (succ u1), max (succ u1) (succ u2)} (MonoidHom.{u1, u2} G N (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} N (DivInvMonoid.toMonoid.{u2} N (Group.toDivInvMonoid.{u2} N _inst_3)))) (fun (_x : MonoidHom.{u1, u2} G N (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} N (DivInvMonoid.toMonoid.{u2} N (Group.toDivInvMonoid.{u2} N _inst_3)))) => G -> N) (MonoidHom.hasCoeToFun.{u1, u2} G N (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))) (Monoid.toMulOneClass.{u2} N (DivInvMonoid.toMonoid.{u2} N (Group.toDivInvMonoid.{u2} N _inst_3)))) f x))
but is expected to have type
  forall {G : Type.{u2}} [_inst_1 : Group.{u2} G] {N : Type.{u1}} [_inst_3 : Group.{u1} N] (f : MonoidHom.{u2, u1} G N (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} N (DivInvMonoid.toMonoid.{u1} N (Group.toDivInvMonoid.{u1} N _inst_3)))) (x : G), Eq.{succ u1} (Subgroup.{u1} N _inst_3) (Subgroup.map.{u2, u1} G _inst_1 N _inst_3 f (Subgroup.zpowers.{u2} G _inst_1 x)) (Subgroup.zpowers.{u1} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => N) x) _inst_3 (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (MonoidHom.{u2, u1} G N (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} N (DivInvMonoid.toMonoid.{u1} N (Group.toDivInvMonoid.{u1} N _inst_3)))) G (fun (_x : G) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : G) => N) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} G N (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} N (DivInvMonoid.toMonoid.{u1} N (Group.toDivInvMonoid.{u1} N _inst_3)))) G N (MulOneClass.toMul.{u2} G (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1)))) (MulOneClass.toMul.{u1} N (Monoid.toMulOneClass.{u1} N (DivInvMonoid.toMonoid.{u1} N (Group.toDivInvMonoid.{u1} N _inst_3)))) (MonoidHomClass.toMulHomClass.{max u2 u1, u2, u1} (MonoidHom.{u2, u1} G N (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} N (DivInvMonoid.toMonoid.{u1} N (Group.toDivInvMonoid.{u1} N _inst_3)))) G N (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} N (DivInvMonoid.toMonoid.{u1} N (Group.toDivInvMonoid.{u1} N _inst_3))) (MonoidHom.monoidHomClass.{u2, u1} G N (Monoid.toMulOneClass.{u2} G (DivInvMonoid.toMonoid.{u2} G (Group.toDivInvMonoid.{u2} G _inst_1))) (Monoid.toMulOneClass.{u1} N (DivInvMonoid.toMonoid.{u1} N (Group.toDivInvMonoid.{u1} N _inst_3)))))) f x))
Case conversion may be inaccurate. Consider using '#align monoid_hom.map_zpowers MonoidHom.map_zpowersₓ'. -/
@[simp, to_additive map_zmultiples]
theorem MonoidHom.map_zpowers (f : G →* N) (x : G) :
    (Subgroup.zpowers x).map f = Subgroup.zpowers (f x) := by
  rw [Subgroup.zpowers_eq_closure, Subgroup.zpowers_eq_closure, f.map_closure, Set.image_singleton]
#align monoid_hom.map_zpowers MonoidHom.map_zpowers
#align add_monoid_hom.map_zmultiples AddMonoidHom.map_zmultiples

/- warning: int.mem_zmultiples_iff -> Int.mem_zmultiples_iff is a dubious translation:
lean 3 declaration is
  forall {a : Int} {b : Int}, Iff (Membership.Mem.{0, 0} Int (AddSubgroup.{0} Int Int.addGroup) (SetLike.hasMem.{0, 0} (AddSubgroup.{0} Int Int.addGroup) Int (AddSubgroup.setLike.{0} Int Int.addGroup)) b (AddSubgroup.zmultiples.{0} Int Int.addGroup a)) (Dvd.Dvd.{0} Int (semigroupDvd.{0} Int Int.semigroup) a b)
but is expected to have type
  forall {a : Int} {b : Int}, Iff (Membership.mem.{0, 0} Int (AddSubgroup.{0} Int Int.instAddGroupInt) (SetLike.instMembership.{0, 0} (AddSubgroup.{0} Int Int.instAddGroupInt) Int (AddSubgroup.instSetLikeAddSubgroup.{0} Int Int.instAddGroupInt)) b (AddSubgroup.zmultiples.{0} Int Int.instAddGroupInt a)) (Dvd.dvd.{0} Int Int.instDvdInt a b)
Case conversion may be inaccurate. Consider using '#align int.mem_zmultiples_iff Int.mem_zmultiples_iffₓ'. -/
theorem Int.mem_zmultiples_iff {a b : ℤ} : b ∈ AddSubgroup.zmultiples a ↔ a ∣ b :=
  exists_congr fun k => by rw [mul_comm, eq_comm, ← smul_eq_mul]
#align int.mem_zmultiples_iff Int.mem_zmultiples_iff

/- warning: of_mul_image_zpowers_eq_zmultiples_of_mul -> ofMul_image_zpowers_eq_zmultiples_ofMul is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {x : G}, Eq.{succ u1} (Set.{u1} (Additive.{u1} G)) (Set.image.{u1, u1} G (Additive.{u1} G) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} G (Additive.{u1} G)) (fun (_x : Equiv.{succ u1, succ u1} G (Additive.{u1} G)) => G -> (Additive.{u1} G)) (Equiv.hasCoeToFun.{succ u1, succ u1} G (Additive.{u1} G)) (Additive.ofMul.{u1} G)) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Subgroup.{u1} G _inst_1) (Set.{u1} G) (HasLiftT.mk.{succ u1, succ u1} (Subgroup.{u1} G _inst_1) (Set.{u1} G) (CoeTCₓ.coe.{succ u1, succ u1} (Subgroup.{u1} G _inst_1) (Set.{u1} G) (SetLike.Set.hasCoeT.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) (Subgroup.zpowers.{u1} G _inst_1 x))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (AddSubgroup.{u1} (Additive.{u1} G) (Additive.addGroup.{u1} G _inst_1)) (Set.{u1} (Additive.{u1} G)) (HasLiftT.mk.{succ u1, succ u1} (AddSubgroup.{u1} (Additive.{u1} G) (Additive.addGroup.{u1} G _inst_1)) (Set.{u1} (Additive.{u1} G)) (CoeTCₓ.coe.{succ u1, succ u1} (AddSubgroup.{u1} (Additive.{u1} G) (Additive.addGroup.{u1} G _inst_1)) (Set.{u1} (Additive.{u1} G)) (SetLike.Set.hasCoeT.{u1, u1} (AddSubgroup.{u1} (Additive.{u1} G) (Additive.addGroup.{u1} G _inst_1)) (Additive.{u1} G) (AddSubgroup.setLike.{u1} (Additive.{u1} G) (Additive.addGroup.{u1} G _inst_1))))) (AddSubgroup.zmultiples.{u1} (Additive.{u1} G) (Additive.addGroup.{u1} G _inst_1) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} G (Additive.{u1} G)) (fun (_x : Equiv.{succ u1, succ u1} G (Additive.{u1} G)) => G -> (Additive.{u1} G)) (Equiv.hasCoeToFun.{succ u1, succ u1} G (Additive.{u1} G)) (Additive.ofMul.{u1} G) x)))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {x : G}, Eq.{succ u1} (Set.{u1} (Additive.{u1} G)) (Set.image.{u1, u1} G (Additive.{u1} G) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} G (Additive.{u1} G)) G (fun (_x : G) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : G) => Additive.{u1} G) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} G (Additive.{u1} G)) (Additive.ofMul.{u1} G)) (SetLike.coe.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1) (Subgroup.zpowers.{u1} G _inst_1 x))) (SetLike.coe.{u1, u1} (AddSubgroup.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : G) => Additive.{u1} G) x) (Additive.addGroup.{u1} G _inst_1)) (Additive.{u1} G) (AddSubgroup.instSetLikeAddSubgroup.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : G) => Additive.{u1} G) x) (Additive.addGroup.{u1} G _inst_1)) (AddSubgroup.zmultiples.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : G) => Additive.{u1} G) x) (Additive.addGroup.{u1} G _inst_1) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} G (Additive.{u1} G)) G (fun (_x : G) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : G) => Additive.{u1} G) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} G (Additive.{u1} G)) (Additive.ofMul.{u1} G) x)))
Case conversion may be inaccurate. Consider using '#align of_mul_image_zpowers_eq_zmultiples_of_mul ofMul_image_zpowers_eq_zmultiples_ofMulₓ'. -/
theorem ofMul_image_zpowers_eq_zmultiples_ofMul {x : G} :
    Additive.ofMul '' (Subgroup.zpowers x : Set G) = AddSubgroup.zmultiples (Additive.ofMul x) :=
  by
  ext y
  constructor
  · rintro ⟨z, ⟨m, hm⟩, hz2⟩
    use m
    simp only
    rwa [← ofMul_zpow, hm]
  · rintro ⟨n, hn⟩
    refine' ⟨x ^ n, ⟨n, rfl⟩, _⟩
    rwa [ofMul_zpow]
#align of_mul_image_zpowers_eq_zmultiples_of_mul ofMul_image_zpowers_eq_zmultiples_ofMul

/- warning: of_add_image_zmultiples_eq_zpowers_of_add -> ofAdd_image_zmultiples_eq_zpowers_ofAdd is a dubious translation:
lean 3 declaration is
  forall {A : Type.{u1}} [_inst_2 : AddGroup.{u1} A] {x : A}, Eq.{succ u1} (Set.{u1} (Multiplicative.{u1} A)) (Set.image.{u1, u1} A (Multiplicative.{u1} A) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} A (Multiplicative.{u1} A)) (fun (_x : Equiv.{succ u1, succ u1} A (Multiplicative.{u1} A)) => A -> (Multiplicative.{u1} A)) (Equiv.hasCoeToFun.{succ u1, succ u1} A (Multiplicative.{u1} A)) (Multiplicative.ofAdd.{u1} A)) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (AddSubgroup.{u1} A _inst_2) (Set.{u1} A) (HasLiftT.mk.{succ u1, succ u1} (AddSubgroup.{u1} A _inst_2) (Set.{u1} A) (CoeTCₓ.coe.{succ u1, succ u1} (AddSubgroup.{u1} A _inst_2) (Set.{u1} A) (SetLike.Set.hasCoeT.{u1, u1} (AddSubgroup.{u1} A _inst_2) A (AddSubgroup.setLike.{u1} A _inst_2)))) (AddSubgroup.zmultiples.{u1} A _inst_2 x))) ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (Subgroup.{u1} (Multiplicative.{u1} A) (Multiplicative.group.{u1} A _inst_2)) (Set.{u1} (Multiplicative.{u1} A)) (HasLiftT.mk.{succ u1, succ u1} (Subgroup.{u1} (Multiplicative.{u1} A) (Multiplicative.group.{u1} A _inst_2)) (Set.{u1} (Multiplicative.{u1} A)) (CoeTCₓ.coe.{succ u1, succ u1} (Subgroup.{u1} (Multiplicative.{u1} A) (Multiplicative.group.{u1} A _inst_2)) (Set.{u1} (Multiplicative.{u1} A)) (SetLike.Set.hasCoeT.{u1, u1} (Subgroup.{u1} (Multiplicative.{u1} A) (Multiplicative.group.{u1} A _inst_2)) (Multiplicative.{u1} A) (Subgroup.setLike.{u1} (Multiplicative.{u1} A) (Multiplicative.group.{u1} A _inst_2))))) (Subgroup.zpowers.{u1} (Multiplicative.{u1} A) (Multiplicative.group.{u1} A _inst_2) (coeFn.{succ u1, succ u1} (Equiv.{succ u1, succ u1} A (Multiplicative.{u1} A)) (fun (_x : Equiv.{succ u1, succ u1} A (Multiplicative.{u1} A)) => A -> (Multiplicative.{u1} A)) (Equiv.hasCoeToFun.{succ u1, succ u1} A (Multiplicative.{u1} A)) (Multiplicative.ofAdd.{u1} A) x)))
but is expected to have type
  forall {A : Type.{u1}} [_inst_2 : AddGroup.{u1} A] {x : A}, Eq.{succ u1} (Set.{u1} (Multiplicative.{u1} A)) (Set.image.{u1, u1} A (Multiplicative.{u1} A) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} A (Multiplicative.{u1} A)) A (fun (_x : A) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : A) => Multiplicative.{u1} A) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} A (Multiplicative.{u1} A)) (Multiplicative.ofAdd.{u1} A)) (SetLike.coe.{u1, u1} (AddSubgroup.{u1} A _inst_2) A (AddSubgroup.instSetLikeAddSubgroup.{u1} A _inst_2) (AddSubgroup.zmultiples.{u1} A _inst_2 x))) (SetLike.coe.{u1, u1} (Subgroup.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : A) => Multiplicative.{u1} A) x) (Multiplicative.group.{u1} A _inst_2)) (Multiplicative.{u1} A) (Subgroup.instSetLikeSubgroup.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : A) => Multiplicative.{u1} A) x) (Multiplicative.group.{u1} A _inst_2)) (Subgroup.zpowers.{u1} ((fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : A) => Multiplicative.{u1} A) x) (Multiplicative.group.{u1} A _inst_2) (FunLike.coe.{succ u1, succ u1, succ u1} (Equiv.{succ u1, succ u1} A (Multiplicative.{u1} A)) A (fun (_x : A) => (fun (x._@.Mathlib.Logic.Equiv.Defs._hyg.808 : A) => Multiplicative.{u1} A) _x) (Equiv.instFunLikeEquiv.{succ u1, succ u1} A (Multiplicative.{u1} A)) (Multiplicative.ofAdd.{u1} A) x)))
Case conversion may be inaccurate. Consider using '#align of_add_image_zmultiples_eq_zpowers_of_add ofAdd_image_zmultiples_eq_zpowers_ofAddₓ'. -/
theorem ofAdd_image_zmultiples_eq_zpowers_ofAdd {x : A} :
    Multiplicative.ofAdd '' (AddSubgroup.zmultiples x : Set A) =
      Subgroup.zpowers (Multiplicative.ofAdd x) :=
  by
  symm
  rw [Equiv.eq_image_iff_symm_image_eq]
  exact ofMul_image_zpowers_eq_zmultiples_ofMul
#align of_add_image_zmultiples_eq_zpowers_of_add ofAdd_image_zmultiples_eq_zpowers_ofAdd

namespace Subgroup

#print Subgroup.zpowers_isCommutative /-
@[to_additive zmultiples_is_commutative]
instance zpowers_isCommutative (g : G) : (zpowers g).IsCommutative :=
  ⟨⟨fun ⟨_, _, h₁⟩ ⟨_, _, h₂⟩ => by
      rw [Subtype.ext_iff, coe_mul, coe_mul, Subtype.coe_mk, Subtype.coe_mk, ← h₁, ← h₂,
        zpow_mul_comm]⟩⟩
#align subgroup.zpowers_is_commutative Subgroup.zpowers_isCommutative
#align add_subgroup.zmultiples_is_commutative AddSubgroup.zmultiples_isCommutative
-/

/- warning: subgroup.zpowers_le -> Subgroup.zpowers_le is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g : G} {H : Subgroup.{u1} G _inst_1}, Iff (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (SetLike.partialOrder.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)))) (Subgroup.zpowers.{u1} G _inst_1 g) H) (Membership.Mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.hasMem.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.setLike.{u1} G _inst_1)) g H)
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g : G} {H : Subgroup.{u1} G _inst_1}, Iff (LE.le.{u1} (Subgroup.{u1} G _inst_1) (Preorder.toLE.{u1} (Subgroup.{u1} G _inst_1) (PartialOrder.toPreorder.{u1} (Subgroup.{u1} G _inst_1) (CompleteSemilatticeInf.toPartialOrder.{u1} (Subgroup.{u1} G _inst_1) (CompleteLattice.toCompleteSemilatticeInf.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instCompleteLatticeSubgroup.{u1} G _inst_1))))) (Subgroup.zpowers.{u1} G _inst_1 g) H) (Membership.mem.{u1, u1} G (Subgroup.{u1} G _inst_1) (SetLike.instMembership.{u1, u1} (Subgroup.{u1} G _inst_1) G (Subgroup.instSetLikeSubgroup.{u1} G _inst_1)) g H)
Case conversion may be inaccurate. Consider using '#align subgroup.zpowers_le Subgroup.zpowers_leₓ'. -/
@[simp, to_additive zmultiples_le]
theorem zpowers_le {g : G} {H : Subgroup G} : zpowers g ≤ H ↔ g ∈ H := by
  rw [zpowers_eq_closure, closure_le, Set.singleton_subset_iff, SetLike.mem_coe]
#align subgroup.zpowers_le Subgroup.zpowers_le
#align add_subgroup.zmultiples_le AddSubgroup.zmultiples_le

/- warning: subgroup.zpowers_eq_bot -> Subgroup.zpowers_eq_bot is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g : G}, Iff (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.zpowers.{u1} G _inst_1 g) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasBot.{u1} G _inst_1))) (Eq.{succ u1} G g (OfNat.ofNat.{u1} G 1 (OfNat.mk.{u1} G 1 (One.one.{u1} G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1))))))))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] {g : G}, Iff (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.zpowers.{u1} G _inst_1 g) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instBotSubgroup.{u1} G _inst_1))) (Eq.{succ u1} G g (OfNat.ofNat.{u1} G 1 (One.toOfNat1.{u1} G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1)))))))
Case conversion may be inaccurate. Consider using '#align subgroup.zpowers_eq_bot Subgroup.zpowers_eq_botₓ'. -/
@[simp, to_additive zmultiples_eq_bot]
theorem zpowers_eq_bot {g : G} : zpowers g = ⊥ ↔ g = 1 := by rw [eq_bot_iff, zpowers_le, mem_bot]
#align subgroup.zpowers_eq_bot Subgroup.zpowers_eq_bot
#align add_subgroup.zmultiples_eq_bot AddSubgroup.zmultiples_eq_bot

/- warning: subgroup.zpowers_one_eq_bot -> Subgroup.zpowers_one_eq_bot is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G], Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.zpowers.{u1} G _inst_1 (OfNat.ofNat.{u1} G 1 (OfNat.mk.{u1} G 1 (One.one.{u1} G (MulOneClass.toHasOne.{u1} G (Monoid.toMulOneClass.{u1} G (DivInvMonoid.toMonoid.{u1} G (Group.toDivInvMonoid.{u1} G _inst_1)))))))) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasBot.{u1} G _inst_1))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G], Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.zpowers.{u1} G _inst_1 (OfNat.ofNat.{u1} G 1 (One.toOfNat1.{u1} G (InvOneClass.toOne.{u1} G (DivInvOneMonoid.toInvOneClass.{u1} G (DivisionMonoid.toDivInvOneMonoid.{u1} G (Group.toDivisionMonoid.{u1} G _inst_1))))))) (Bot.bot.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instBotSubgroup.{u1} G _inst_1))
Case conversion may be inaccurate. Consider using '#align subgroup.zpowers_one_eq_bot Subgroup.zpowers_one_eq_botₓ'. -/
@[simp, to_additive zmultiples_zero_eq_bot]
theorem zpowers_one_eq_bot : Subgroup.zpowers (1 : G) = ⊥ :=
  Subgroup.zpowers_eq_bot.mpr rfl
#align subgroup.zpowers_one_eq_bot Subgroup.zpowers_one_eq_bot
#align add_subgroup.zmultiples_zero_eq_bot AddSubgroup.zmultiples_zero_eq_bot

#print Subgroup.centralizer_closure /-
@[to_additive]
theorem centralizer_closure (S : Set G) :
    (closure S).centralizer = ⨅ g ∈ S, (zpowers g).centralizer :=
  le_antisymm
      (le_infᵢ fun g => le_infᵢ fun hg => centralizer_le <| zpowers_le.2 <| subset_closure hg) <|
    le_centralizer_iff.1 <|
      (closure_le _).2 fun g =>
        SetLike.mem_coe.2 ∘ zpowers_le.1 ∘ le_centralizer_iff.1 ∘ infᵢ_le_of_le g ∘ infᵢ_le _
#align subgroup.centralizer_closure Subgroup.centralizer_closure
#align add_subgroup.centralizer_closure AddSubgroup.centralizer_closure
-/

/- warning: subgroup.center_eq_infi -> Subgroup.center_eq_infᵢ is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (S : Set.{u1} G), (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.closure.{u1} G _inst_1 S) (Top.top.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasTop.{u1} G _inst_1))) -> (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.center.{u1} G _inst_1) (infᵢ.{u1, succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasInf.{u1} G _inst_1) G (fun (g : G) => infᵢ.{u1, 0} (Subgroup.{u1} G _inst_1) (Subgroup.hasInf.{u1} G _inst_1) (Membership.Mem.{u1, u1} G (Set.{u1} G) (Set.hasMem.{u1} G) g S) (fun (H : Membership.Mem.{u1, u1} G (Set.{u1} G) (Set.hasMem.{u1} G) g S) => Subgroup.centralizer.{u1} G _inst_1 (Subgroup.zpowers.{u1} G _inst_1 g)))))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (S : Set.{u1} G), (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.closure.{u1} G _inst_1 S) (Top.top.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instTopSubgroup.{u1} G _inst_1))) -> (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.center.{u1} G _inst_1) (infᵢ.{u1, succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.instInfSetSubgroup.{u1} G _inst_1) G (fun (g : G) => infᵢ.{u1, 0} (Subgroup.{u1} G _inst_1) (Subgroup.instInfSetSubgroup.{u1} G _inst_1) (Membership.mem.{u1, u1} G (Set.{u1} G) (Set.instMembershipSet.{u1} G) g S) (fun (H : Membership.mem.{u1, u1} G (Set.{u1} G) (Set.instMembershipSet.{u1} G) g S) => Subgroup.centralizer.{u1} G _inst_1 (Subgroup.zpowers.{u1} G _inst_1 g)))))
Case conversion may be inaccurate. Consider using '#align subgroup.center_eq_infi Subgroup.center_eq_infᵢₓ'. -/
@[to_additive]
theorem center_eq_infᵢ (S : Set G) (hS : closure S = ⊤) :
    center G = ⨅ g ∈ S, centralizer (zpowers g) := by
  rw [← centralizer_top, ← hS, centralizer_closure]
#align subgroup.center_eq_infi Subgroup.center_eq_infᵢ
#align add_subgroup.center_eq_infi AddSubgroup.center_eq_infᵢ

/- warning: subgroup.center_eq_infi' -> Subgroup.center_eq_infi' is a dubious translation:
lean 3 declaration is
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (S : Set.{u1} G), (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.closure.{u1} G _inst_1 S) (Top.top.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasTop.{u1} G _inst_1))) -> (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.center.{u1} G _inst_1) (infᵢ.{u1, succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.hasInf.{u1} G _inst_1) (coeSort.{succ u1, succ (succ u1)} (Set.{u1} G) Type.{u1} (Set.hasCoeToSort.{u1} G) S) (fun (g : coeSort.{succ u1, succ (succ u1)} (Set.{u1} G) Type.{u1} (Set.hasCoeToSort.{u1} G) S) => Subgroup.centralizer.{u1} G _inst_1 (Subgroup.zpowers.{u1} G _inst_1 ((fun (a : Type.{u1}) (b : Type.{u1}) [self : HasLiftT.{succ u1, succ u1} a b] => self.0) (coeSort.{succ u1, succ (succ u1)} (Set.{u1} G) Type.{u1} (Set.hasCoeToSort.{u1} G) S) G (HasLiftT.mk.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} G) Type.{u1} (Set.hasCoeToSort.{u1} G) S) G (CoeTCₓ.coe.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} G) Type.{u1} (Set.hasCoeToSort.{u1} G) S) G (coeBase.{succ u1, succ u1} (coeSort.{succ u1, succ (succ u1)} (Set.{u1} G) Type.{u1} (Set.hasCoeToSort.{u1} G) S) G (coeSubtype.{succ u1} G (fun (x : G) => Membership.Mem.{u1, u1} G (Set.{u1} G) (Set.hasMem.{u1} G) x S))))) g)))))
but is expected to have type
  forall {G : Type.{u1}} [_inst_1 : Group.{u1} G] (S : Set.{u1} G), (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.closure.{u1} G _inst_1 S) (Top.top.{u1} (Subgroup.{u1} G _inst_1) (Subgroup.instTopSubgroup.{u1} G _inst_1))) -> (Eq.{succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.center.{u1} G _inst_1) (infᵢ.{u1, succ u1} (Subgroup.{u1} G _inst_1) (Subgroup.instInfSetSubgroup.{u1} G _inst_1) (Set.Elem.{u1} G S) (fun (g : Set.Elem.{u1} G S) => Subgroup.centralizer.{u1} G _inst_1 (Subgroup.zpowers.{u1} G _inst_1 (Subtype.val.{succ u1} G (fun (x : G) => Membership.mem.{u1, u1} G (Set.{u1} G) (Set.instMembershipSet.{u1} G) x S) g)))))
Case conversion may be inaccurate. Consider using '#align subgroup.center_eq_infi' Subgroup.center_eq_infi'ₓ'. -/
@[to_additive]
theorem center_eq_infi' (S : Set G) (hS : closure S = ⊤) :
    center G = ⨅ g : S, centralizer (zpowers g) := by rw [center_eq_infi S hS, ← infᵢ_subtype'']
#align subgroup.center_eq_infi' Subgroup.center_eq_infi'
#align add_subgroup.center_eq_infi' AddSubgroup.center_eq_infi'

end Subgroup


/-
Copyright (c) 2020 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Mario Carneiro
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.data.set.basic
import Mathlib.PostPort

universes u_1

namespace Mathlib

/-!
# Well-founded relations

A relation is well-founded if it can be used for induction: for each `x`, `(∀ y, r y x → P y) → P x`
implies `P x`. Well-founded relations can be used for induction and recursion, including
construction of fixed points in the space of dependent functions `Π x : α , β x`.

The predicate `well_founded` is defined in the core library. In this file we prove some extra lemmas
and provide a few new definitions: `well_founded.min`, `well_founded.sup`, and `well_founded.succ`.
-/

namespace well_founded

/-- If `r` is a well-founded relation, then any nonempty set has a minimal element
with respect to `r`. -/
theorem has_min {α : Type u_1} {r : α → α → Prop} (H : well_founded r) (s : set α) : set.nonempty s → ∃ (a : α), ∃ (H : a ∈ s), ∀ (x : α), x ∈ s → ¬r x a := sorry

/-- A minimal element of a nonempty set in a well-founded order -/
def min {α : Type u_1} {r : α → α → Prop} (H : well_founded r) (p : set α) (h : set.nonempty p) : α :=
  classical.some (has_min H p h)

theorem min_mem {α : Type u_1} {r : α → α → Prop} (H : well_founded r) (p : set α) (h : set.nonempty p) : min H p h ∈ p := sorry

theorem not_lt_min {α : Type u_1} {r : α → α → Prop} (H : well_founded r) (p : set α) (h : set.nonempty p) {x : α} (xp : x ∈ p) : ¬r x (min H p h) := sorry

theorem well_founded_iff_has_min {α : Type u_1} {r : α → α → Prop} : well_founded r ↔ ∀ (p : set α), set.nonempty p → ∃ (m : α), ∃ (H : m ∈ p), ∀ (x : α), x ∈ p → ¬r x m := sorry

theorem eq_iff_not_lt_of_le {α : Type u_1} [partial_order α] {x : α} {y : α} : x ≤ y → y = x ↔ ¬x < y := sorry

theorem well_founded_iff_has_max' {α : Type u_1} [partial_order α] : well_founded gt ↔ ∀ (p : set α), set.nonempty p → ∃ (m : α), ∃ (H : m ∈ p), ∀ (x : α), x ∈ p → m ≤ x → x = m := sorry

theorem well_founded_iff_has_min' {α : Type u_1} [partial_order α] : well_founded Less ↔ ∀ (p : set α), set.nonempty p → ∃ (m : α), ∃ (H : m ∈ p), ∀ (x : α), x ∈ p → x ≤ m → x = m :=
  well_founded_iff_has_max'

/-- The supremum of a bounded, well-founded order -/
protected def sup {α : Type u_1} {r : α → α → Prop} (wf : well_founded r) (s : set α) (h : bounded r s) : α :=
  min wf (set_of fun (x : α) => ∀ (a : α), a ∈ s → r a x) h

protected theorem lt_sup {α : Type u_1} {r : α → α → Prop} (wf : well_founded r) {s : set α} (h : bounded r s) {x : α} (hx : x ∈ s) : r x (well_founded.sup wf s h) :=
  min_mem wf (set_of fun (x : α) => ∀ (a : α), a ∈ s → r a x) h x hx

/-- A successor of an element `x` in a well-founded order is a minimal element `y` such that
`x < y` if one exists. Otherwise it is `x` itself. -/
protected def succ {α : Type u_1} {r : α → α → Prop} (wf : well_founded r) (x : α) : α :=
  dite (∃ (y : α), r x y) (fun (h : ∃ (y : α), r x y) => min wf (set_of fun (y : α) => r x y) h)
    fun (h : ¬∃ (y : α), r x y) => x

protected theorem lt_succ {α : Type u_1} {r : α → α → Prop} (wf : well_founded r) {x : α} (h : ∃ (y : α), r x y) : r x (well_founded.succ wf x) := sorry

protected theorem lt_succ_iff {α : Type u_1} {r : α → α → Prop} [wo : is_well_order α r] {x : α} (h : ∃ (y : α), r x y) (y : α) : r y (well_founded.succ is_well_order.wf x) ↔ r y x ∨ y = x := sorry


import data.set.finite
import algebra.big_operators
import data.support
import data.finsupp

variables {α : Type*}

open set

lemma set.insert_inter_of_mem {α : Type*} {s₁ s₂ : set α} {a : α} (h : a ∈ s₂) :
  insert a s₁ ∩ s₂ = insert a (s₁ ∩ s₂) :=
by simp [set.insert_inter, h]

lemma set.insert_inter_of_not_mem {s₁ s₂ : set α} {a : α} (h : a ∉ s₂) :
  insert a s₁ ∩ s₂ = s₁ ∩ s₂ :=
begin
  ext x,
  simp only [mem_inter_iff, mem_insert_iff, mem_inter_eq, and.congr_left_iff, or_iff_right_iff_imp],
  cc,
end

lemma set.image_inter_support_eq {α β M : Type*} {f : α → M} [has_zero M] {s : set β} {g : β → α} :
  (g '' s ∩ function.support f) = g '' (s ∩ function.support (f ∘ g)) :=
begin
  ext y, split; intro hy,
    { rcases hy with ⟨⟨x, hx₀, rfl⟩, hy⟩,
      exact ⟨x, ⟨hx₀, hy⟩, rfl⟩ },
    { rcases hy with ⟨y, ⟨hys, hyfg⟩, rfl⟩, exact ⟨⟨y, hys, rfl⟩, hyfg⟩ }
end

lemma set.image_inter_support_finite_iff {α β M : Type*} {f : α → M} [has_zero M]
  {s : set β} {g : β → α} (hg : set.inj_on g s) :
  (g '' s ∩ function.support f).finite ↔ (s ∩ function.support (f ∘ g)).finite :=
begin
  rw [set.image_inter_support_eq, set.finite_image_iff],
  exact set.inj_on.mono (set.inter_subset_left s _) hg
end


/- Rewriting -/

example (f : Nat → Nat) (k : Nat) (h₁ : f 0 = 0) (h₂ : k = 0) : f k = 0 := by
  rw [h₂] -- replace k with 0
  rw [h₁] -- replace f 0 with 0

example (f : Nat → Nat) (k : Nat) (h₁ : f 0 = 0) (h₂ : k = 0) : f k = 0 := by
  rw [h₂, h₁]

example (f : Nat → Nat) (a b : Nat) (h₁ : a = b) (h₂ : f a = 0) : f b = 0 := by
  rw [← h₁, h₂]

example (f : Nat → Nat) (a : Nat) (h : 0 + a = 0) : f a = f 0 := by
  rw [Nat.zero_add] at h
  rw [h]

def Tuple (α : Type) (n : Nat) :=
  { as : List α // as.length = n }

example (n : Nat) (h : n = 0) (t : Tuple α n) : Tuple α 0 := by
  rw [h] at t
  exact t


/-
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Yury Kudryashov
-/
import measure_theory.pi

/-!
# Lebesgue measure on the real line and on `ℝⁿ`
-/

noncomputable theory
open classical set filter
open ennreal (of_real)
open_locale big_operators ennreal

namespace measure_theory

/-!
### Preliminary definitions
-/

/-- Length of an interval. This is the largest monotonic function which correctly
  measures all intervals. -/
def lebesgue_length (s : set ℝ) : ℝ≥0∞ := ⨅a b (h : s ⊆ Ico a b), of_real (b - a)

@[simp] lemma lebesgue_length_empty : lebesgue_length ∅ = 0 :=
nonpos_iff_eq_zero.1 $ infi_le_of_le 0 $ infi_le_of_le 0 $ by simp

@[simp] lemma lebesgue_length_Ico (a b : ℝ) :
  lebesgue_length (Ico a b) = of_real (b - a) :=
begin
  refine le_antisymm (infi_le_of_le a $ binfi_le b (subset.refl _))
    (le_infi $ λ a', le_infi $ λ b', le_infi $ λ h, ennreal.coe_le_coe.2 _),
  cases le_or_lt b a with ab ab,
  { rw nnreal.of_real_of_nonpos (sub_nonpos.2 ab), apply zero_le },
  cases (Ico_subset_Ico_iff ab).1 h with h₁ h₂,
  exact nnreal.of_real_le_of_real (sub_le_sub h₂ h₁)
end

lemma lebesgue_length_mono {s₁ s₂ : set ℝ} (h : s₁ ⊆ s₂) :
  lebesgue_length s₁ ≤ lebesgue_length s₂ :=
infi_le_infi $ λ a, infi_le_infi $ λ b, infi_le_infi2 $ λ h', ⟨subset.trans h h', le_refl _⟩

lemma lebesgue_length_eq_infi_Ioo (s) :
  lebesgue_length s = ⨅a b (h : s ⊆ Ioo a b), of_real (b - a) :=
begin
  refine le_antisymm
    (infi_le_infi $ λ a, infi_le_infi $ λ b, infi_le_infi2 $ λ h,
      ⟨subset.trans h Ioo_subset_Ico_self, le_refl _⟩) _,
  refine le_infi (λ a, le_infi $ λ b, le_infi $ λ h, _),
  refine ennreal.le_of_forall_pos_le_add (λ ε ε0 _, _),
  refine infi_le_of_le (a - ε) (infi_le_of_le b $ infi_le_of_le
    (subset.trans h $ Ico_subset_Ioo_left $ (sub_lt_self_iff _).2 ε0) _),
  rw ← sub_add,
  refine le_trans ennreal.of_real_add_le (add_le_add_left _ _),
  simp only [ennreal.of_real_coe_nnreal, le_refl]
end

@[simp] lemma lebesgue_length_Ioo (a b : ℝ) :
  lebesgue_length (Ioo a b) = of_real (b - a) :=
begin
  rw ← lebesgue_length_Ico,
  refine le_antisymm (lebesgue_length_mono Ioo_subset_Ico_self) _,
  rw lebesgue_length_eq_infi_Ioo (Ioo a b),
  refine (le_infi $ λ a', le_infi $ λ b', le_infi $ λ h, _),
  cases le_or_lt b a with ab ab, {simp [ab]},
  cases (Ioo_subset_Ioo_iff ab).1 h with h₁ h₂,
  rw [lebesgue_length_Ico],
  exact ennreal.of_real_le_of_real (sub_le_sub h₂ h₁)
end

lemma lebesgue_length_eq_infi_Icc (s) :
  lebesgue_length s = ⨅a b (h : s ⊆ Icc a b), of_real (b - a) :=
begin
  refine le_antisymm _
    (infi_le_infi $ λ a, infi_le_infi $ λ b, infi_le_infi2 $ λ h,
      ⟨subset.trans h Ico_subset_Icc_self, le_refl _⟩),
  refine le_infi (λ a, le_infi $ λ b, le_infi $ λ h, _),
  refine ennreal.le_of_forall_pos_le_add (λ ε ε0 _, _),
  refine infi_le_of_le a (infi_le_of_le (b + ε) $ infi_le_of_le
    (subset.trans h $ Icc_subset_Ico_right $ (lt_add_iff_pos_right _).2 ε0) _),
  rw [← sub_add_eq_add_sub],
  refine le_trans ennreal.of_real_add_le (add_le_add_left _ _),
  simp only [ennreal.of_real_coe_nnreal, le_refl]
end

@[simp] lemma lebesgue_length_Icc (a b : ℝ) :
  lebesgue_length (Icc a b) = of_real (b - a) :=
begin
  rw ← lebesgue_length_Ico,
  refine le_antisymm _ (lebesgue_length_mono Ico_subset_Icc_self),
  rw lebesgue_length_eq_infi_Icc (Icc a b),
  exact infi_le_of_le a (infi_le_of_le b $ infi_le_of_le (by refl) (by simp [le_refl]))
end

/-- The Lebesgue outer measure, as an outer measure of ℝ. -/
def lebesgue_outer : outer_measure ℝ :=
outer_measure.of_function lebesgue_length lebesgue_length_empty

lemma lebesgue_outer_le_length (s : set ℝ) : lebesgue_outer s ≤ lebesgue_length s :=
outer_measure.of_function_le _

lemma lebesgue_length_subadditive {a b : ℝ} {c d : ℕ → ℝ}
  (ss : Icc a b ⊆ ⋃i, Ioo (c i) (d i)) :
  (of_real (b - a) : ℝ≥0∞) ≤ ∑' i, of_real (d i - c i) :=
begin
  suffices : ∀ (s:finset ℕ) b
    (cv : Icc a b ⊆ ⋃ i ∈ (↑s:set ℕ), Ioo (c i) (d i)),
    (of_real (b - a) : ℝ≥0∞) ≤ ∑ i in s, of_real (d i - c i),
  { rcases compact_Icc.elim_finite_subcover_image (λ (i : ℕ) (_ : i ∈ univ),
      @is_open_Ioo _ _ _ _ (c i) (d i)) (by simpa using ss) with ⟨s, su, hf, hs⟩,
    have e : (⋃ i ∈ (↑hf.to_finset:set ℕ),
      Ioo (c i) (d i)) = (⋃ i ∈ s, Ioo (c i) (d i)), {simp [set.ext_iff]},
    rw ennreal.tsum_eq_supr_sum,
    refine le_trans _ (le_supr _ hf.to_finset),
    exact this hf.to_finset _ (by simpa [e]) },
  clear ss b,
  refine λ s, finset.strong_induction_on s (λ s IH b cv, _),
  cases le_total b a with ab ab,
  { rw ennreal.of_real_eq_zero.2 (sub_nonpos.2 ab), exact zero_le _ },
  have := cv ⟨ab, le_refl _⟩, simp at this,
  rcases this with ⟨i, is, cb, bd⟩,
  rw [← finset.insert_erase is] at cv ⊢,
  rw [finset.coe_insert, bUnion_insert] at cv,
  rw [finset.sum_insert (finset.not_mem_erase _ _)],
  refine le_trans _ (add_le_add_left (IH _ (finset.erase_ssubset is) (c i) _) _),
  { refine le_trans (ennreal.of_real_le_of_real _) ennreal.of_real_add_le,
    rw sub_add_sub_cancel,
    exact sub_le_sub_right (le_of_lt bd) _ },
  { rintro x ⟨h₁, h₂⟩,
    refine (cv ⟨h₁, le_trans h₂ (le_of_lt cb)⟩).resolve_left
      (mt and.left (not_lt_of_le h₂)) }
end

@[simp] lemma lebesgue_outer_Icc (a b : ℝ) :
  lebesgue_outer (Icc a b) = of_real (b - a) :=
begin
  refine le_antisymm (by rw ← lebesgue_length_Icc; apply lebesgue_outer_le_length)
    (le_binfi $ λ f hf, ennreal.le_of_forall_pos_le_add $ λ ε ε0 h, _),
  rcases ennreal.exists_pos_sum_of_encodable
    (ennreal.zero_lt_coe_iff.2 ε0) ℕ with ⟨ε', ε'0, hε⟩,
  refine le_trans _ (add_le_add_left (le_of_lt hε) _),
  rw ← ennreal.tsum_add,
  choose g hg using show
    ∀ i, ∃ p:ℝ×ℝ, f i ⊆ Ioo p.1 p.2 ∧ (of_real (p.2 - p.1) : ℝ≥0∞) <
      lebesgue_length (f i) + ε' i,
  { intro i,
    have := (ennreal.lt_add_right (lt_of_le_of_lt (ennreal.le_tsum i) h)
        (ennreal.zero_lt_coe_iff.2 (ε'0 i))),
    conv at this {to_lhs, rw lebesgue_length_eq_infi_Ioo},
    simpa [infi_lt_iff] },
  refine le_trans _ (ennreal.tsum_le_tsum $ λ i, le_of_lt (hg i).2),
  exact lebesgue_length_subadditive (subset.trans hf $
    Union_subset_Union $ λ i, (hg i).1)
end

@[simp] lemma lebesgue_outer_singleton (a : ℝ) : lebesgue_outer {a} = 0 :=
by simpa using lebesgue_outer_Icc a a

@[simp] lemma lebesgue_outer_Ico (a b : ℝ) :
  lebesgue_outer (Ico a b) = of_real (b - a) :=
by rw [← Icc_diff_right, lebesgue_outer.diff_null _ (lebesgue_outer_singleton _),
  lebesgue_outer_Icc]

@[simp] lemma lebesgue_outer_Ioo (a b : ℝ) :
  lebesgue_outer (Ioo a b) = of_real (b - a) :=
by rw [← Ico_diff_left, lebesgue_outer.diff_null _ (lebesgue_outer_singleton _), lebesgue_outer_Ico]

@[simp] lemma lebesgue_outer_Ioc (a b : ℝ) :
  lebesgue_outer (Ioc a b) = of_real (b - a) :=
by rw [← Icc_diff_left, lebesgue_outer.diff_null _ (lebesgue_outer_singleton _), lebesgue_outer_Icc]

lemma is_lebesgue_measurable_Iio {c : ℝ} :
  lebesgue_outer.caratheodory.measurable_set' (Iio c) :=
outer_measure.of_function_caratheodory $ λ t,
le_infi $ λ a, le_infi $ λ b, le_infi $ λ h, begin
  refine le_trans (add_le_add
    (lebesgue_length_mono $ inter_subset_inter_left _ h)
    (lebesgue_length_mono $ diff_subset_diff_left h)) _,
  cases le_total a c with hac hca; cases le_total b c with hbc hcb;
    simp [*, -sub_eq_add_neg, sub_add_sub_cancel', le_refl],
  { simp [*, ← ennreal.of_real_add, -sub_eq_add_neg, sub_add_sub_cancel', le_refl] },
  { simp only [ennreal.of_real_eq_zero.2 (sub_nonpos.2 (le_trans hbc hca)), zero_add, le_refl] }
end

theorem lebesgue_outer_trim : lebesgue_outer.trim = lebesgue_outer :=
begin
  refine le_antisymm (λ s, _) (outer_measure.le_trim _),
  rw outer_measure.trim_eq_infi,
  refine le_infi (λ f, le_infi $ λ hf,
    ennreal.le_of_forall_pos_le_add $ λ ε ε0 h, _),
  rcases ennreal.exists_pos_sum_of_encodable
    (ennreal.zero_lt_coe_iff.2 ε0) ℕ with ⟨ε', ε'0, hε⟩,
  refine le_trans _ (add_le_add_left (le_of_lt hε) _),
  rw ← ennreal.tsum_add,
  choose g hg using show
    ∀ i, ∃ s, f i ⊆ s ∧ measurable_set s ∧
      lebesgue_outer s ≤ lebesgue_length (f i) + of_real (ε' i),
  { intro i,
    have := (ennreal.lt_add_right (lt_of_le_of_lt (ennreal.le_tsum i) h)
        (ennreal.zero_lt_coe_iff.2 (ε'0 i))),
    conv at this {to_lhs, rw lebesgue_length},
    simp only [infi_lt_iff] at this,
    rcases this with ⟨a, b, h₁, h₂⟩,
    rw ← lebesgue_outer_Ico at h₂,
    exact ⟨_, h₁, measurable_set_Ico, le_of_lt $ by simpa using h₂⟩ },
  simp at hg,
  apply infi_le_of_le (Union g) _,
  apply infi_le_of_le (subset.trans hf $ Union_subset_Union (λ i, (hg i).1)) _,
  apply infi_le_of_le (measurable_set.Union (λ i, (hg i).2.1)) _,
  exact le_trans (lebesgue_outer.Union _) (ennreal.tsum_le_tsum $ λ i, (hg i).2.2)
end

lemma borel_le_lebesgue_measurable : borel ℝ ≤ lebesgue_outer.caratheodory :=
begin
  rw real.borel_eq_generate_from_Iio_rat,
  refine measurable_space.generate_from_le _,
  simp [is_lebesgue_measurable_Iio] { contextual := tt }
end

/-!
### Definition of the Lebesgue measure and lengths of intervals
-/

/-- Lebesgue measure on the Borel sets

The outer Lebesgue measure is the completion of this measure. (TODO: proof this)
-/
instance real.measure_space : measure_space ℝ :=
⟨{to_outer_measure := lebesgue_outer,
  m_Union := λ f hf, lebesgue_outer.Union_eq_of_caratheodory $
    λ i, borel_le_lebesgue_measurable _ (hf i),
  trimmed := lebesgue_outer_trim }⟩

@[simp] theorem lebesgue_to_outer_measure :
  (volume : measure ℝ).to_outer_measure = lebesgue_outer := rfl

end measure_theory

open measure_theory

namespace real

variables {ι : Type*} [fintype ι]

open_locale topological_space

theorem volume_val (s) : volume s = lebesgue_outer s := rfl

instance has_no_atoms_volume : has_no_atoms (volume : measure ℝ) :=
⟨lebesgue_outer_singleton⟩

@[simp] lemma volume_Ico {a b : ℝ} : volume (Ico a b) = of_real (b - a) := lebesgue_outer_Ico a b

@[simp] lemma volume_Icc {a b : ℝ} : volume (Icc a b) = of_real (b - a) := lebesgue_outer_Icc a b

@[simp] lemma volume_Ioo {a b : ℝ} : volume (Ioo a b) = of_real (b - a) := lebesgue_outer_Ioo a b

@[simp] lemma volume_Ioc {a b : ℝ} : volume (Ioc a b) = of_real (b - a) := lebesgue_outer_Ioc a b

@[simp] lemma volume_singleton {a : ℝ} : volume ({a} : set ℝ) = 0 := lebesgue_outer_singleton a

@[simp] lemma volume_interval {a b : ℝ} : volume (interval a b) = of_real (abs (b - a)) :=
by rw [interval, volume_Icc, max_sub_min_eq_abs]

@[simp] lemma volume_Ioi {a : ℝ} : volume (Ioi a) = ∞ :=
top_unique $ le_of_tendsto' ennreal.tendsto_nat_nhds_top $ λ n,
calc (n : ℝ≥0∞) = volume (Ioo a (a + n)) : by simp
... ≤ volume (Ioi a) : measure_mono Ioo_subset_Ioi_self

@[simp] lemma volume_Ici {a : ℝ} : volume (Ici a) = ∞ :=
by simp [← measure_congr Ioi_ae_eq_Ici]

@[simp] lemma volume_Iio {a : ℝ} : volume (Iio a) = ∞ :=
top_unique $ le_of_tendsto' ennreal.tendsto_nat_nhds_top $ λ n,
calc (n : ℝ≥0∞) = volume (Ioo (a - n) a) : by simp
... ≤ volume (Iio a) : measure_mono Ioo_subset_Iio_self

@[simp] lemma volume_Iic {a : ℝ} : volume (Iic a) = ∞ :=
by simp [← measure_congr Iio_ae_eq_Iic]

instance locally_finite_volume : locally_finite_measure (volume : measure ℝ) :=
⟨λ x, ⟨Ioo (x - 1) (x + 1),
  mem_nhds_sets is_open_Ioo ⟨sub_lt_self _ zero_lt_one, lt_add_of_pos_right _ zero_lt_one⟩,
  by simp only [real.volume_Ioo, ennreal.of_real_lt_top]⟩⟩

/-!
### Volume of a box in `ℝⁿ`
-/

lemma volume_Icc_pi {a b : ι → ℝ} : volume (Icc a b) = ∏ i, ennreal.of_real (b i - a i) :=
begin
  rw [← pi_univ_Icc, volume_pi_pi],
  { simp only [real.volume_Icc] },
  { exact λ i, measurable_set_Icc }
end

@[simp] lemma volume_Icc_pi_to_real {a b : ι → ℝ} (h : a ≤ b) :
  (volume (Icc a b)).to_real = ∏ i, (b i - a i) :=
by simp only [volume_Icc_pi, ennreal.to_real_prod, ennreal.to_real_of_real (sub_nonneg.2 (h _))]

lemma volume_pi_Ioo {a b : ι → ℝ} :
  volume (pi univ (λ i, Ioo (a i) (b i))) = ∏ i, ennreal.of_real (b i - a i) :=
(measure_congr measure.univ_pi_Ioo_ae_eq_Icc).trans volume_Icc_pi

@[simp] lemma volume_pi_Ioo_to_real {a b : ι → ℝ} (h : a ≤ b) :
  (volume (pi univ (λ i, Ioo (a i) (b i)))).to_real = ∏ i, (b i - a i) :=
by simp only [volume_pi_Ioo, ennreal.to_real_prod, ennreal.to_real_of_real (sub_nonneg.2 (h _))]

lemma volume_pi_Ioc {a b : ι → ℝ} :
  volume (pi univ (λ i, Ioc (a i) (b i))) = ∏ i, ennreal.of_real (b i - a i) :=
(measure_congr measure.univ_pi_Ioc_ae_eq_Icc).trans volume_Icc_pi

@[simp] lemma volume_pi_Ioc_to_real {a b : ι → ℝ} (h : a ≤ b) :
  (volume (pi univ (λ i, Ioc (a i) (b i)))).to_real = ∏ i, (b i - a i) :=
by simp only [volume_pi_Ioc, ennreal.to_real_prod, ennreal.to_real_of_real (sub_nonneg.2 (h _))]

lemma volume_pi_Ico {a b : ι → ℝ} :
  volume (pi univ (λ i, Ico (a i) (b i))) = ∏ i, ennreal.of_real (b i - a i) :=
(measure_congr measure.univ_pi_Ico_ae_eq_Icc).trans volume_Icc_pi

@[simp] lemma volume_pi_Ico_to_real {a b : ι → ℝ} (h : a ≤ b) :
  (volume (pi univ (λ i, Ico (a i) (b i)))).to_real = ∏ i, (b i - a i) :=
by simp only [volume_pi_Ico, ennreal.to_real_prod, ennreal.to_real_of_real (sub_nonneg.2 (h _))]

/-!
### Images of the Lebesgue measure under translation/multiplication/...
-/

lemma map_volume_add_left (a : ℝ) : measure.map ((+) a) volume = volume :=
eq.symm $ real.measure_ext_Ioo_rat $ λ p q,
  by simp [measure.map_apply (measurable_const_add a) measurable_set_Ioo, sub_sub_sub_cancel_right]

lemma map_volume_add_right (a : ℝ) : measure.map (+ a) volume = volume :=
by simpa only [add_comm] using real.map_volume_add_left a

lemma smul_map_volume_mul_left {a : ℝ} (h : a ≠ 0) :
  ennreal.of_real (abs a) • measure.map ((*) a) volume = volume :=
begin
  refine (real.measure_ext_Ioo_rat $ λ p q, _).symm,
  cases lt_or_gt_of_ne h with h h,
  { simp only [real.volume_Ioo, measure.smul_apply, ← ennreal.of_real_mul (le_of_lt $ neg_pos.2 h),
      measure.map_apply (measurable_const_mul a) measurable_set_Ioo, neg_sub_neg,
      ← neg_mul_eq_neg_mul, preimage_const_mul_Ioo_of_neg _ _ h, abs_of_neg h, mul_sub,
      mul_div_cancel' _ (ne_of_lt h)] },
  { simp only [real.volume_Ioo, measure.smul_apply, ← ennreal.of_real_mul (le_of_lt h),
      measure.map_apply (measurable_const_mul a) measurable_set_Ioo, preimage_const_mul_Ioo _ _ h,
      abs_of_pos h, mul_sub, mul_div_cancel' _ (ne_of_gt h)] }
end

lemma map_volume_mul_left {a : ℝ} (h : a ≠ 0) :
  measure.map ((*) a) volume = ennreal.of_real (abs a⁻¹) • volume :=
by conv_rhs { rw [← real.smul_map_volume_mul_left h, smul_smul,
  ← ennreal.of_real_mul (abs_nonneg _), ← abs_mul, inv_mul_cancel h, abs_one, ennreal.of_real_one,
  one_smul] }

lemma smul_map_volume_mul_right {a : ℝ} (h : a ≠ 0) :
  ennreal.of_real (abs a) • measure.map (* a) volume = volume :=
by simpa only [mul_comm] using real.smul_map_volume_mul_left h

lemma map_volume_mul_right {a : ℝ} (h : a ≠ 0) :
  measure.map (* a) volume = ennreal.of_real (abs a⁻¹) • volume :=
by simpa only [mul_comm] using real.map_volume_mul_left h

@[simp] lemma map_volume_neg : measure.map has_neg.neg (volume : measure ℝ) = volume :=
eq.symm $ real.measure_ext_Ioo_rat $ λ p q,
  by simp [show measure.map has_neg.neg volume (Ioo (p : ℝ) q) = _,
    from measure.map_apply measurable_neg measurable_set_Ioo]

end real

open_locale topological_space

lemma filter.eventually.volume_pos_of_nhds_real {p : ℝ → Prop} {a : ℝ} (h : ∀ᶠ x in 𝓝 a, p x) :
  (0 : ℝ≥0∞) < volume {x | p x} :=
begin
  rcases h.exists_Ioo_subset with ⟨l, u, hx, hs⟩,
  refine lt_of_lt_of_le _ (measure_mono hs),
  simpa [-mem_Ioo] using hx.1.trans hx.2
end

section region_between

open_locale classical

variable {α : Type*}

/-- The region between two real-valued functions on an arbitrary set. -/
def region_between (f g : α → ℝ) (s : set α) : set (α × ℝ) :=
{p : α × ℝ | p.1 ∈ s ∧ p.2 ∈ Ioo (f p.1) (g p.1)}

lemma region_between_subset (f g : α → ℝ) (s : set α) : region_between f g s ⊆ s.prod univ :=
by simpa only [prod_univ, region_between, set.preimage, set_of_subset_set_of] using λ a, and.left

variables [measurable_space α] {μ : measure α} {f g : α → ℝ} {s : set α}

/-- The region between two measurable functions on a measurable set is measurable. -/
lemma measurable_set_region_between
  (hf : measurable f) (hg : measurable g) (hs : measurable_set s) :
  measurable_set (region_between f g s) :=
begin
  dsimp only [region_between, Ioo, mem_set_of_eq, set_of_and],
  refine measurable_set.inter _ ((measurable_set_lt (hf.comp measurable_fst) measurable_snd).inter
    (measurable_set_lt measurable_snd (hg.comp measurable_fst))),
  convert hs.prod measurable_set.univ,
  simp only [and_true, mem_univ],
end

theorem volume_region_between_eq_lintegral'
  (hf : measurable f) (hg : measurable g) (hs : measurable_set s) :
  μ.prod volume (region_between f g s) = ∫⁻ y in s, ennreal.of_real ((g - f) y) ∂μ :=
begin
  rw measure.prod_apply,
  { have h : (λ x, volume {a | x ∈ s ∧ a ∈ Ioo (f x) (g x)})
            = s.indicator (λ x, ennreal.of_real (g x - f x)),
    { funext x,
      rw indicator_apply,
      split_ifs,
      { have hx : {a | x ∈ s ∧ a ∈ Ioo (f x) (g x)} = Ioo (f x) (g x) := by simp [h, Ioo],
        simp only [hx, real.volume_Ioo, sub_zero] },
      { have hx : {a | x ∈ s ∧ a ∈ Ioo (f x) (g x)} = ∅ := by simp [h],
        simp only [hx, measure_empty] } },
    dsimp only [region_between, preimage_set_of_eq],
    rw [h, lintegral_indicator];
    simp only [hs, pi.sub_apply] },
  { exact measurable_set_region_between hf hg hs },
end

/-- The volume of the region between two almost everywhere measurable functions on a measurable set
    can be represented as a Lebesgue integral. -/
theorem volume_region_between_eq_lintegral [sigma_finite μ]
  (hf : ae_measurable f (μ.restrict s)) (hg : ae_measurable g (μ.restrict s))
  (hs : measurable_set s) :
  μ.prod volume (region_between f g s) = ∫⁻ y in s, ennreal.of_real ((g - f) y) ∂μ :=
begin
  have h₁ : (λ y, ennreal.of_real ((g - f) y))
          =ᵐ[μ.restrict s]
              λ y, ennreal.of_real ((ae_measurable.mk g hg - ae_measurable.mk f hf) y) :=
    eventually_eq.fun_comp (eventually_eq.sub hg.ae_eq_mk hf.ae_eq_mk) _,
  have h₂ : (μ.restrict s).prod volume (region_between f g s) =
    (μ.restrict s).prod volume (region_between (ae_measurable.mk f hf) (ae_measurable.mk g hg) s),
  { apply measure_congr,
    apply eventually_eq.inter, { refl },
    exact eventually_eq.inter
            (eventually_eq.comp₂ (ae_eq_comp' measurable_fst hf.ae_eq_mk
              measure.prod_fst_absolutely_continuous) _ eventually_eq.rfl)
            (eventually_eq.comp₂ eventually_eq.rfl _
              (ae_eq_comp' measurable_fst hg.ae_eq_mk measure.prod_fst_absolutely_continuous)) },
  rw [lintegral_congr_ae h₁,
      ← volume_region_between_eq_lintegral' hf.measurable_mk hg.measurable_mk hs],
  convert h₂ using 1,
  { rw measure.restrict_prod_eq_prod_univ,
    exacts [ (measure.restrict_eq_self_of_subset_of_measurable (hs.prod measurable_set.univ)
      (region_between_subset f g s)).symm, hs], },
  { rw measure.restrict_prod_eq_prod_univ,
    exacts [(measure.restrict_eq_self_of_subset_of_measurable (hs.prod measurable_set.univ)
      (region_between_subset (ae_measurable.mk f hf) (ae_measurable.mk g hg) s)).symm, hs] },
end

theorem volume_region_between_eq_integral' [sigma_finite μ]
  (f_int : integrable_on f s μ) (g_int : integrable_on g s μ)
  (hs : measurable_set s) (hfg : f ≤ᵐ[μ.restrict s] g ) :
  μ.prod volume (region_between f g s) = ennreal.of_real (∫ y in s, (g - f) y ∂μ) :=
begin
  have h : g - f =ᵐ[μ.restrict s] (λ x, nnreal.of_real (g x - f x)),
  { apply hfg.mono,
    simp only [nnreal.of_real, max, sub_nonneg, pi.sub_apply],
    intros x hx,
    split_ifs,
    refl },
  rw [volume_region_between_eq_lintegral f_int.ae_measurable g_int.ae_measurable hs,
    integral_congr_ae h, lintegral_congr_ae,
    lintegral_coe_eq_integral _ ((integrable_congr h).mp (g_int.sub f_int))],
  simpa only,
end

/-- If two functions are integrable on a measurable set, and one function is less than
    or equal to the other on that set, then the volume of the region
    between the two functions can be represented as an integral. -/
theorem volume_region_between_eq_integral [sigma_finite μ]
  (f_int : integrable_on f s μ) (g_int : integrable_on g s μ)
  (hs : measurable_set s) (hfg : ∀ x ∈ s, f x ≤ g x) :
  μ.prod volume (region_between f g s) = ennreal.of_real (∫ y in s, (g - f) y ∂μ) :=
volume_region_between_eq_integral' f_int g_int hs
  ((ae_restrict_iff' hs).mpr (eventually_of_forall hfg))

end region_between

/-
section vitali

def vitali_aux_h (x : ℝ) (h : x ∈ Icc (0:ℝ) 1) :
  ∃ y ∈ Icc (0:ℝ) 1, ∃ q:ℚ, ↑q = x - y :=
⟨x, h, 0, by simp⟩

def vitali_aux (x : ℝ) (h : x ∈ Icc (0:ℝ) 1) : ℝ :=
classical.some (vitali_aux_h x h)

theorem vitali_aux_mem (x : ℝ) (h : x ∈ Icc (0:ℝ) 1) : vitali_aux x h ∈ Icc (0:ℝ) 1 :=
Exists.fst (classical.some_spec (vitali_aux_h x h):_)

theorem vitali_aux_rel (x : ℝ) (h : x ∈ Icc (0:ℝ) 1) :
 ∃ q:ℚ, ↑q = x - vitali_aux x h :=
Exists.snd (classical.some_spec (vitali_aux_h x h):_)

def vitali : set ℝ := {x | ∃ h, x = vitali_aux x h}

theorem vitali_nonmeasurable : ¬ null_measurable_set measure_space.μ vitali :=
sorry

end vitali
-/


universes u

def concat {α} : List α → α → List α
  | [],    a => [a]
  | x::xs, a => x :: concat xs a

def last {α} : (xs : List α) → xs ≠ [] → α
  | [],       h => by contradiction
  | [a],      h => a
  | _::a::as, h => last (a::as) (fun h => by injection h)

def dropLast {α} : List α → List α
  | []    => []
  | [a]   => []
  | a::as => a :: dropLast as

variable {α}

theorem concatEq (xs : List α) (h : xs ≠ []) : concat (dropLast xs) (last xs h) = xs := by
  match xs, h with
  | [],  h        => contradiction
  | [x], h        => rfl
  | x₁::x₂::xs, h => simp [concat, last, concatEq (x₂::xs) List.noConfusion]

theorem lengthCons {α} (x : α) (xs : List α) : (x::xs).length = xs.length + 1 :=
  let rec aux (a : α) (xs : List α) : (n : Nat) → (a::xs).lengthAux n = xs.lengthAux n + 1 :=
    match xs with
    | []    => fun _ => rfl
    | x::xs => fun n => aux a xs (n+1)
  aux x xs 0

theorem eqNilOfLengthZero {α} : (xs : List α) → xs.length = 0 → xs = []
  | [],    h => rfl
  | x::xs, h => by rw [lengthCons] at h; contradiction

theorem dropLastLen {α} (xs : List α) : (n : Nat) → xs.length = n+1 → (dropLast xs).length = n := by
  match xs with
  | []    => intros; contradiction
  | [a]   =>
    intro n h
    have : 1 = n + 1 := h
    have : 0 = n := by injection this; assumption
    subst this
    rfl
  | x₁::x₂::xs =>
    intro n h
    cases n with
    | zero   =>
      simp [lengthCons] at h
      injection h
    | succ n =>
      have : (x₁ :: x₂ :: xs).length = xs.length + 2 := by simp [lengthCons]
      have : xs.length = n := by rw [this] at h; injection h with h; injection h with h; assumption
      simp [dropLast, lengthCons, dropLastLen (x₂::xs) xs.length (lengthCons ..), this]

@[inline]
def concatElim {α}
    (motive : List α → Sort u)
    (base   : Unit → motive [])
    (ind    : (xs : List α) → (a : α) → motive xs → motive (concat xs a))
    (xs : List α)
    : motive xs :=
  let rec @[specialize] aux : (n : Nat) → (xs : List α) → xs.length = n → motive xs
    | 0, xs, h   => by
      have aux := eqNilOfLengthZero _ h
      subst aux
      apply base ()
    | n+1, xs, h => by
      have notNil : xs ≠ [] := by intro h1; subst h1; injection h
      let ih  := aux n (dropLast xs) (dropLastLen _ _ h)
      let aux := ind (dropLast xs) (last xs notNil) ih
      rw [concatEq] at aux
      exact aux
  aux xs.length xs rfl

-- The generated code is tail recursive
def test (xs : List Nat) : IO Unit :=
  concatElim (motive := fun _ => IO Unit)
    (fun _ => pure ())
    (fun xs x r => do IO.println s!"step xs: {xs} x: {x}"; r)
    xs

#eval test [1, 2, 3, 4]


/-
Defines a notion of getting two distinct indexes from a list.

Authors: Cayden Codel
Carnegie Mellon University
-/

import basic

import data.list.basic
import data.nat.basic
import tactic

namespace distinct

open list nat

def distinct {α : Type*} (a₁ a₂ : α) (l : list α) :=
  ∃ (i j : nat) (Hi : i < l.length) (Hj : j < l.length),
  i < j ∧ l.nth_le i Hi = a₁ ∧ l.nth_le j Hj = a₂

theorem not_distinct_nil {α : Type*} (a₁ a₂ : α) : ¬distinct a₁ a₂ [] :=
begin
  rintro ⟨i, _, hi, _, _⟩,
  rw length at hi,
  linarith
end

theorem not_distinct_singleton {α : Type*} (a₁ a₂ a₃ : α) : ¬distinct a₁ a₂ [a₃] :=
begin
  rintro ⟨i, j, _, hj, hij, _⟩,
  have := gt_of_gt_of_ge hij (zero_le i),
  rw [length, length] at hj,
  linarith
end

theorem distinct_double {α : Type*} (a₁ a₂ : α) : distinct a₁ a₂ [a₁, a₂] :=
by { use [0, 1], simp }

theorem eq_of_distinct_double {α : Type*} {a₁ a₂ b₁ b₂ : α} :
  distinct a₁ a₂ [b₁, b₂] → a₁ = b₁ ∧ a₂ = b₂ :=
begin
  rintros ⟨i, j, hi, hj, hij, hil, hjl⟩,
  cases i,
  { rcases nth_le_of_ge hj (succ_le_iff.mpr hij) with ⟨h₁, h₂⟩,
    rw [hjl, nth_le, nth_le_singleton] at h₂,
    rw nth_le at hil,
    exact ⟨hil.symm, h₂⟩ },
  { simp [length] at hj,
    have : 1 ≤ i + 1, exact le_add_self,
    have := gt_of_gt_of_ge hij this,
    linarith }
end

theorem length_ge_two_of_distinct {α : Type*} {a₁ a₂ : α} {l : list α} :
  distinct a₁ a₂ l → length l ≥ 2 :=
begin
  rintros ⟨i, j, _, Hj, hij, _, _⟩,
  have : 1 ≤ j, exact succ_le_iff.mpr (pos_of_gt hij),
  have : 1 < length l, exact gt_of_gt_of_ge Hj this,
  exact succ_le_iff.mpr this
end

theorem exists_distinct_of_length_ge_two {α : Type*} {l : list α} :
  length l ≥ 2 → ∃ {a₁ a₂ : α}, distinct a₁ a₂ l :=
begin
  intro hl,
  rcases exists_cons_cons_of_length_ge_two hl with ⟨a₁, a₂, as, rfl⟩,
  use [a₁, a₂, 0, 1], simp
end

theorem distinct_cons_of_mem {α : Type*} (a₁ : α) {a₂ : α} {l : list α} :
  a₂ ∈ l → distinct a₁ a₂ (a₁ :: l) :=
begin
  intro h,
  rcases mem_iff_nth_le.mp h with ⟨n, hlen, hn⟩,
  have hi : 0 < length (a₁ :: l), simp,
  have hj : n + 1 < length (a₁ :: l),
    by { rw [length, succ_lt_succ_iff], exact hlen },
  use [0, n + 1, hi, hj],
  simp [← hn],
  refl
end

theorem distinct_cons_of_distinct {α : Type*} {a₁ a₂ : α} {l : list α} (a : α) :
  distinct a₁ a₂ l → distinct a₁ a₂ (a :: l) :=
begin
  rintros ⟨i, j, hi, hj, hij, hil, hjl⟩,
  have hi₂ : i + 1 < (a :: l).length,
  { simp only [hi, length, add_lt_add_iff_right] },
  have hj₂ : j + 1 < (a :: l).length,
  { simp only [hj, length, add_lt_add_iff_right] },
  use [i + 1, j + 1, hi₂, hj₂, succ_lt_succ hij],
  rw [nth_le, nth_le],
  exact ⟨hil, hjl⟩
end

theorem distinct_of_distinct_cons_of_ne {α : Type*} {a₁ a₂ a : α} {l : list α} :
  distinct a₁ a₂ (a :: l) → a₁ ≠ a → distinct a₁ a₂ l :=
begin
  rintros ⟨i, j, hi, hj, hij, hil, hjl⟩ hne,
  cases i,
  { rw nth_le at hil, exact absurd hil.symm hne },
  { rw length at hi,
    have := succ_le_iff.mpr ((gt_of_gt_of_ge hij (zero_le i.succ))),
    rcases nth_le_of_ge hj this with ⟨hjm, hnth⟩,
    rw [← nat.sub_add_cancel this, length] at hj,
    rw ← nat.sub_add_cancel this at hij,
    use [i, j - 1, succ_lt_succ_iff.mp hi, succ_lt_succ_iff.mp hj,
      succ_lt_succ_iff.mp hij],
    rw [← hil, ← hjl, hnth, nth_le, nth_le],
    exact ⟨rfl, rfl⟩ }
end

theorem eq_or_distinct_of_distinct_cons {α : Type*} {a₁ a₂ a : α} {l : list α} :
  distinct a₁ a₂ (a :: l) → a₁ = a ∨ distinct a₁ a₂ l :=
begin
  intro hdis,
  by_cases h : (a₁ = a),
  { exact or.inl h },
  { exact or.inr (distinct_of_distinct_cons_of_ne hdis h) }
end

theorem mem_tail_of_distinct_cons {α : Type*} {a₁ a₂ a : α} {as : list α} :
  distinct a₁ a₂ (a :: as) → a₂ ∈ as :=
begin
  rintro ⟨i, j, Hi, Hj, hij, hil, hjl⟩,
  have := succ_le_iff.mpr ((gt_of_gt_of_ge hij (zero_le i))),
  rcases (nth_le_of_ge Hj this) with ⟨Hj₂, hnth⟩,
  rw hjl at hnth,
  rw [hnth, nth_le],
  exact nth_le_mem as _ _
end

theorem distinct_sublist {α : Type*} {a₁ a₂ : α} {l₁ l₂ : list α} :
  l₁ <+ l₂ → distinct a₁ a₂ l₁ → distinct a₁ a₂ l₂ :=
begin
  induction l₂ with a as ih generalizing l₁,
  { rw sublist_nil_iff_eq_nil, rintro rfl, exact id },
  { intros hl₁ hdis,
    cases hl₁,
    { exact distinct_cons_of_distinct a (ih hl₁_ᾰ hdis) },
    { by_cases ha : (a₁ = a),
      { have := (sublist.subset hl₁_ᾰ) (mem_tail_of_distinct_cons hdis),
        rcases mem_iff_nth_le.mp this with ⟨n, hn₁, hn₂⟩,
        have Hi : 0 < (a :: as).length, by dec_trivial,
        have Hj : n + 1 < (a :: as).length,
        { rw length, exact succ_lt_succ_iff.mpr hn₁ },
        use [0, n + 1, Hi, Hj],
        simp [ha],
        rw ← hn₂,
        refl },
      { have := distinct_of_distinct_cons_of_ne hdis ha,
        exact distinct_cons_of_distinct a (ih hl₁_ᾰ this) } } }
end

-- TODO way to do in a non-tactic way?
theorem mem_of_distinct_left {α : Type*} {a₁ a₂ : α} {l : list α} :
  distinct a₁ a₂ l → a₁ ∈ l :=
begin
  rintro ⟨i, _, hi, _, _, hil, _⟩,
  rw ← hil, exact nth_le_mem l _ _
end

-- TODO this too
theorem mem_of_distinct_right {α : Type*} {a₁ a₂ : α} {l : list α} :
  distinct a₁ a₂ l → a₂ ∈ l :=
begin
  rintro ⟨_, j, _, hj, _, _, hjl⟩,
  rw ← hjl, exact nth_le_mem l _ _
end

theorem countp_ge_two_of_distinct_of_pos {α : Type*} {a₁ a₂ : α}
  {p : α → Prop} [decidable_pred p] (h₁ : p a₁) (h₂ : p a₂) :
  ∀ {l : list α}, distinct a₁ a₂ l → countp p l ≥ 2
| [] hdis := absurd hdis (not_distinct_nil _ _)
| [a] hdis := absurd hdis (not_distinct_singleton _ _ _)
| (a :: b :: bs) hdis := begin
  have hmem := mem_tail_of_distinct_cons hdis,
  rcases hdis with ⟨i, j, hi, hj, hij, hil, hjl⟩,
  cases i,
  { rw nth_le at hil,
    rw [hil, countp_cons_of_pos p (b :: bs) h₁],
    apply succ_le_succ_iff.mpr,
    apply succ_le_iff.mpr,
    apply (countp_pos p).mpr,
    use [a₂, hmem, h₂] },
  { cases j,
    { linarith },
    { have : distinct a₁ a₂ (b :: bs),
      { rw [length, succ_lt_succ_iff] at hi hj,
        rw succ_lt_succ_iff at hij,
        rw nth_le at hil hjl,
        use [i, j, hi, hj, hij, hil, hjl] },
      have ih := countp_ge_two_of_distinct_of_pos this,
      exact le_trans ih (sublist.countp_le p (sublist_cons a (b :: bs))) } }
end

theorem distinct_of_mem_take_of_mem_drop {α : Type*} {a₁ a₂ : α} {l : list α} :
  ∀ {i : nat}, a₁ ∈ l.take i → a₂ ∈ l.drop i → distinct a₁ a₂ l :=
begin
  intros i htake hdrop,
  induction i with i ih generalizing l,
  { rw take at htake, exact absurd htake (not_mem_nil _) },
  { cases l with x xs,
    { rw take_nil at htake, exact absurd htake (not_mem_nil _) },
    { rw take at htake, rw drop at hdrop,
      rcases eq_or_mem_of_mem_cons htake with (rfl | h),
      { exact distinct_cons_of_mem a₁ (mem_of_mem_drop hdrop) },
      { exact distinct_cons_of_distinct _ (ih h hdrop) } } }
end

end distinct