import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ]

:=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1]

:= by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ]

:=
  entropy_map_of_injective κ μ inv_injective measurable_inv


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ]

:= by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ] := by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ]

:=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_right_injective hκ


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ] := by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_right_injective hκ

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ]

:=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_left_injective hκ


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ] := by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_right_injective hκ

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_left_injective hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ]

:= by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul' (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.2 * p.1) ∘ Prod.swap = (fun p ↦ p.1 * p.2) := rfl
    simp_rw [this]


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ] := by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_right_injective hκ

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_left_injective hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul' (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.2 * p.1) ∘ Prod.swap = (fun p ↦ p.1 * p.2) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ]

:= by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 * p.2) ∘ Prod.swap = (fun p ↦ p.2 * p.1) := rfl
    simp_rw [this]


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ] := by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_right_injective hκ

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_left_injective hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul' (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.2 * p.1) ∘ Prod.swap = (fun p ↦ p.1 * p.2) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 * p.2) ∘ Prod.swap = (fun p ↦ p.2 * p.1) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]

:=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ (fun _ ↦ div_right_injective) hκ


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ] := by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_right_injective hκ

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_left_injective hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul' (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.2 * p.1) ∘ Prod.swap = (fun p ↦ p.1 * p.2) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 * p.2) ∘ Prod.swap = (fun p ↦ p.2 * p.1) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ (fun _ ↦ div_right_injective) hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]

:= by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_div (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 / p.2) ∘ Prod.swap = (fun p ↦ p.2 / p.1) := rfl
    simp_rw [this]
    rw [← entropy_div_comm]


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ] := by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_right_injective hκ

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_left_injective hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul' (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.2 * p.1) ∘ Prod.swap = (fun p ↦ p.1 * p.2) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 * p.2) ∘ Prod.swap = (fun p ↦ p.2 * p.1) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ (fun _ ↦ div_right_injective) hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_div (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 / p.2) ∘ Prod.swap = (fun p ↦ p.2 / p.1) := rfl
    simp_rw [this]
    rw [← entropy_div_comm]

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ]

:= by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_mul _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_mul _ _ hκ⟩


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ] := by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_right_injective hκ

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_left_injective hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul' (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.2 * p.1) ∘ Prod.swap = (fun p ↦ p.1 * p.2) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 * p.2) ∘ Prod.swap = (fun p ↦ p.2 * p.1) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ (fun _ ↦ div_right_injective) hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_div (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 / p.2) ∘ Prod.swap = (fun p ↦ p.2 / p.1) := rfl
    simp_rw [this]
    rw [← entropy_div_comm]

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_mul _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_mul _ _ hκ⟩

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ]

:= by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_mul' _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_mul' _ _ hκ⟩


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ] := by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_right_injective hκ

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_left_injective hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul' (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.2 * p.1) ∘ Prod.swap = (fun p ↦ p.1 * p.2) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 * p.2) ∘ Prod.swap = (fun p ↦ p.2 * p.1) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ (fun _ ↦ div_right_injective) hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_div (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 / p.2) ∘ Prod.swap = (fun p ↦ p.2 / p.1) := rfl
    simp_rw [this]
    rw [← entropy_div_comm]

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_mul _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_mul _ _ hκ⟩

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] := by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_mul' _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_mul' _ _ hκ⟩

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]

:= by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_div _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_div _ _ hκ⟩


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ] := by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_right_injective hκ

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_left_injective hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul' (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.2 * p.1) ∘ Prod.swap = (fun p ↦ p.1 * p.2) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 * p.2) ∘ Prod.swap = (fun p ↦ p.2 * p.1) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ (fun _ ↦ div_right_injective) hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_div (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 / p.2) ∘ Prod.swap = (fun p ↦ p.2 / p.1) := rfl
    simp_rw [this]
    rw [← entropy_div_comm]

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_mul _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_mul _ _ hκ⟩

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] := by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_mul' _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_mul' _ _ hκ⟩

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] := by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_div _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_div _ _ hκ⟩

@[to_additive]
lemma max_entropy_le_entropy_mul_prod
    (κ : kernel T G) [IsMarkovKernel κ] (η : kernel T G) [IsMarkovKernel η]
    (μ : Measure T) [IsProbabilityMeasure μ] [FiniteSupport μ]
    (hκ : AEFiniteKernelSupport κ μ) (hη : AEFiniteKernelSupport η μ) :
    max (Hk[κ, μ]) (Hk[η, μ]) ≤ Hk[map (κ ×ₖ η) (fun p ↦ p.1 * p.2) measurable_mul, μ]

:= by
  calc max (Hk[κ, μ]) (Hk[η, μ])
    = max (Hk[κ, μ]) (Hk[η, μ]) - Ik[κ ×ₖ η, μ] := by
        rw [mutualInfo_prod _ hκ hη, sub_zero]
  _ ≤ Hk[map (κ ×ₖ η) (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
        convert max_entropy_sub_mutualInfo_le_entropy_mul (κ ×ₖ η) μ (hκ.prod hη)
        · simp
        · simp


import PFR.ForMathlib.Entropy.Kernel.MutualInfo
import Mathlib.MeasureTheory.Group.Arithmetic
/-!
# Kernel entropy and mutual information in a commutative group

## Main definitions

## Main results

-/
open MeasureTheory ProbabilityTheory

variable {Ω Ω' Ω'' Ω''' G T : Type*}
  [Countable T] [Nonempty T] [MeasurableSpace T] [MeasurableSingletonClass T]
  [MeasurableSpace G] [MeasurableSingletonClass G] [Group G]
  [MeasurableDiv₂ G] [MeasurableMul₂ G] [Countable G]
  {κ : kernel T G} {μ : Measure T}

@[to_additive (attr := simp)]
lemma measureEntropy_inv (μ : Measure G) : Hm[μ.map (·⁻¹)] = Hm[μ] :=
  measureEntropy_map_of_injective μ _ measurable_inv inv_injective

@[to_additive]
lemma measureEntropy_div_comm (μ : Measure (G × G)) :
    Hm[μ.map fun p ↦ p.1 / p.2] = Hm[μ.map fun p ↦ p.2 / p.1] := by
  rw [← measureEntropy_inv, Measure.map_map measurable_inv measurable_div]
  congr with x
  simp

namespace ProbabilityTheory.kernel

@[to_additive]
lemma entropy_inv (κ : kernel T G) (μ : Measure T) : Hk[map κ (·⁻¹) measurable_inv, μ] = Hk[κ, μ] :=
  entropy_map_of_injective κ μ inv_injective measurable_inv

@[to_additive]
lemma entropy_div_comm (κ : kernel T (G × G)) (μ : Measure T) :
    Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ]
      = Hk[map κ (fun p ↦ p.2 / p.1) (measurable_snd.div measurable_fst), μ] := by
  rw [← entropy_inv, kernel.map_map]
  congr with x
  simp

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_right_injective hκ

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ mul_left_injective hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul' (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.2 * p.1) ∘ Prod.swap = (fun p ↦ p.1 * p.2) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_mul (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 * p.2) ∘ Prod.swap = (fun p ↦ p.2 * p.1) := rfl
    simp_rw [this]

@[to_additive]
lemma entropy_snd_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[snd κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] :=
  entropy_snd_sub_mutualInfo_le_entropy_map_of_injective κ μ _ (fun _ ↦ div_right_injective) hκ

@[to_additive]
lemma entropy_fst_sub_mutualInfo_le_entropy_map_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    Hk[fst κ, μ] - Ik[κ, μ] ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] := by
    have h := entropy_snd_sub_mutualInfo_le_entropy_map_div (swapRight κ) μ hκ.swapRight
    simp only [snd_swapRight, mutualInfo_swapRight, map_swapRight] at h
    refine h.trans_eq ?_
    have : (fun p : G × G ↦ p.1 / p.2) ∘ Prod.swap = (fun p ↦ p.2 / p.1) := rfl
    simp_rw [this]
    rw [← entropy_div_comm]

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_mul
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_mul _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_mul _ _ hκ⟩

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_mul'
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ)  :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.2 * p.1) $ measurable_discrete _, μ] := by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_mul' _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_mul' _ _ hκ⟩

@[to_additive]
lemma max_entropy_sub_mutualInfo_le_entropy_div
    (κ : kernel T (G × G)) [IsMarkovKernel κ] (μ : Measure T) [IsProbabilityMeasure μ]
    [FiniteSupport μ] (hκ : AEFiniteKernelSupport κ μ) :
    max (Hk[fst κ, μ]) (Hk[snd κ, μ]) - Ik[κ, μ]
      ≤ Hk[map κ (fun p ↦ p.1 / p.2) measurable_div, μ] := by
  rw [← max_sub_sub_right, max_le_iff]
  exact ⟨entropy_fst_sub_mutualInfo_le_entropy_map_div _ _ hκ,
    entropy_snd_sub_mutualInfo_le_entropy_map_div _ _ hκ⟩

@[to_additive]
lemma max_entropy_le_entropy_mul_prod
    (κ : kernel T G) [IsMarkovKernel κ] (η : kernel T G) [IsMarkovKernel η]
    (μ : Measure T) [IsProbabilityMeasure μ] [FiniteSupport μ]
    (hκ : AEFiniteKernelSupport κ μ) (hη : AEFiniteKernelSupport η μ) :
    max (Hk[κ, μ]) (Hk[η, μ]) ≤ Hk[map (κ ×ₖ η) (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
  calc max (Hk[κ, μ]) (Hk[η, μ])
    = max (Hk[κ, μ]) (Hk[η, μ]) - Ik[κ ×ₖ η, μ] := by
        rw [mutualInfo_prod _ hκ hη, sub_zero]
  _ ≤ Hk[map (κ ×ₖ η) (fun p ↦ p.1 * p.2) measurable_mul, μ] := by
        convert max_entropy_sub_mutualInfo_le_entropy_mul (κ ×ₖ η) μ (hκ.prod hη)
        · simp
        · simp

@[to_additive max_entropy_le_entropy_sub_prod]
lemma max_entropy_le_entropy_div_prod
    (κ : kernel T G) [IsMarkovKernel κ] (η : kernel T G) [IsMarkovKernel η]
    (μ : Measure T) [IsProbabilityMeasure μ] [FiniteSupport μ]
    (hκ : AEFiniteKernelSupport κ μ) (hη : AEFiniteKernelSupport η μ) :
    max (Hk[κ, μ]) (Hk[η, μ]) ≤ Hk[map (κ ×ₖ η) (fun p ↦ p.1 / p.2) measurable_div, μ]

:= by
  calc max (Hk[κ, μ]) (Hk[η, μ])
    = max (Hk[κ, μ]) (Hk[η, μ]) - Ik[κ ×ₖ η, μ] := by
        rw [mutualInfo_prod _ hκ hη, sub_zero]
  _ ≤ Hk[map (κ ×ₖ η) (fun p ↦ p.1 / p.2) measurable_div, μ] := by
        convert max_entropy_sub_mutualInfo_le_entropy_div (κ ×ₖ η) μ (hκ.prod hη)
        · simp
        · simp


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ]

:= by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ]

:= by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ]

:= by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ]

:=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X * Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X + Y, Y] = H[X, Y]$"]
lemma entropy_mul_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X * Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ]

:=
  (entropy_comm (hX.mul hY) hY _).trans $ (entropy_mul_right' hY hX _).trans $ entropy_comm hY hX _


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X * Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X + Y, Y] = H[X, Y]$"]
lemma entropy_mul_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X * Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.mul hY) hY _).trans $ (entropy_mul_right' hY hX _).trans $ entropy_comm hY hX _

/-- $H[X, Y⁻¹] = H[X, Y]$ -/
@[to_additive "$H[X, -Y] = H[X, Y]$"]
lemma entropy_inv_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y⁻¹⟩; μ] = H[⟨X, Y⟩ ; μ]

:= by
  change H[(Equiv.refl _).prodCongr (Equiv.inv _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X * Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X + Y, Y] = H[X, Y]$"]
lemma entropy_mul_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X * Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.mul hY) hY _).trans $ (entropy_mul_right' hY hX _).trans $ entropy_comm hY hX _

/-- $H[X, Y⁻¹] = H[X, Y]$ -/
@[to_additive "$H[X, -Y] = H[X, Y]$"]
lemma entropy_inv_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y⁻¹⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodCongr (Equiv.inv _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X⁻¹, Y] = H[X, Y]$ -/
@[to_additive "$H[-X, Y] = H[X, Y]$"]
lemma entropy_inv_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X⁻¹, Y⟩; μ] = H[⟨X, Y⟩ ; μ]

:= by
  change H[(Equiv.inv _).prodCongr (Equiv.refl _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X * Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X + Y, Y] = H[X, Y]$"]
lemma entropy_mul_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X * Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.mul hY) hY _).trans $ (entropy_mul_right' hY hX _).trans $ entropy_comm hY hX _

/-- $H[X, Y⁻¹] = H[X, Y]$ -/
@[to_additive "$H[X, -Y] = H[X, Y]$"]
lemma entropy_inv_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y⁻¹⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodCongr (Equiv.inv _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X⁻¹, Y] = H[X, Y]$ -/
@[to_additive "$H[-X, Y] = H[X, Y]$"]
lemma entropy_inv_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X⁻¹, Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.inv _).prodCongr (Equiv.refl _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, X / Y] = H[X, Y]$ -/
@[to_additive "$H[X, X - Y] = H[X, Y]$"]
lemma entropy_div_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X / Y⟩; μ] = H[⟨X, Y⟩ ; μ]

:= by
  change H[(Equiv.refl _).prodShear Equiv.divLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X * Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X + Y, Y] = H[X, Y]$"]
lemma entropy_mul_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X * Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.mul hY) hY _).trans $ (entropy_mul_right' hY hX _).trans $ entropy_comm hY hX _

/-- $H[X, Y⁻¹] = H[X, Y]$ -/
@[to_additive "$H[X, -Y] = H[X, Y]$"]
lemma entropy_inv_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y⁻¹⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodCongr (Equiv.inv _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X⁻¹, Y] = H[X, Y]$ -/
@[to_additive "$H[-X, Y] = H[X, Y]$"]
lemma entropy_inv_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X⁻¹, Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.inv _).prodCongr (Equiv.refl _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, X / Y] = H[X, Y]$ -/
@[to_additive "$H[X, X - Y] = H[X, Y]$"]
lemma entropy_div_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X / Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, Y / X] = H[X, Y]$ -/
@[to_additive "$H[X, Y - X] = H[X, Y]$"]
lemma entropy_div_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y / X⟩; μ] = H[⟨X, Y⟩ ; μ]

:= by
  change H[(Equiv.refl _).prodShear Equiv.divRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X * Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X + Y, Y] = H[X, Y]$"]
lemma entropy_mul_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X * Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.mul hY) hY _).trans $ (entropy_mul_right' hY hX _).trans $ entropy_comm hY hX _

/-- $H[X, Y⁻¹] = H[X, Y]$ -/
@[to_additive "$H[X, -Y] = H[X, Y]$"]
lemma entropy_inv_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y⁻¹⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodCongr (Equiv.inv _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X⁻¹, Y] = H[X, Y]$ -/
@[to_additive "$H[-X, Y] = H[X, Y]$"]
lemma entropy_inv_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X⁻¹, Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.inv _).prodCongr (Equiv.refl _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, X / Y] = H[X, Y]$ -/
@[to_additive "$H[X, X - Y] = H[X, Y]$"]
lemma entropy_div_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X / Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, Y / X] = H[X, Y]$ -/
@[to_additive "$H[X, Y - X] = H[X, Y]$"]
lemma entropy_div_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y / X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[Y / X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y - X, Y] = H[X, Y]$"]
lemma entropy_div_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y / X, Y⟩; μ] = H[⟨X, Y⟩ ; μ]

:=
  (entropy_comm (hY.div hX) hY _).trans $ (entropy_div_right hY hX _).trans $ entropy_comm hY hX _


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X * Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X + Y, Y] = H[X, Y]$"]
lemma entropy_mul_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X * Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.mul hY) hY _).trans $ (entropy_mul_right' hY hX _).trans $ entropy_comm hY hX _

/-- $H[X, Y⁻¹] = H[X, Y]$ -/
@[to_additive "$H[X, -Y] = H[X, Y]$"]
lemma entropy_inv_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y⁻¹⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodCongr (Equiv.inv _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X⁻¹, Y] = H[X, Y]$ -/
@[to_additive "$H[-X, Y] = H[X, Y]$"]
lemma entropy_inv_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X⁻¹, Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.inv _).prodCongr (Equiv.refl _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, X / Y] = H[X, Y]$ -/
@[to_additive "$H[X, X - Y] = H[X, Y]$"]
lemma entropy_div_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X / Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, Y / X] = H[X, Y]$ -/
@[to_additive "$H[X, Y - X] = H[X, Y]$"]
lemma entropy_div_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y / X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[Y / X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y - X, Y] = H[X, Y]$"]
lemma entropy_div_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y / X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.div hX) hY _).trans $ (entropy_div_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X / Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X - Y, Y] = H[X, Y]$"]
lemma entropy_div_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X / Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ]

:=
  (entropy_comm (hX.div hY) hY _).trans $ (entropy_div_right' hY hX _).trans $ entropy_comm hY hX _


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X * Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X + Y, Y] = H[X, Y]$"]
lemma entropy_mul_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X * Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.mul hY) hY _).trans $ (entropy_mul_right' hY hX _).trans $ entropy_comm hY hX _

/-- $H[X, Y⁻¹] = H[X, Y]$ -/
@[to_additive "$H[X, -Y] = H[X, Y]$"]
lemma entropy_inv_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y⁻¹⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodCongr (Equiv.inv _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X⁻¹, Y] = H[X, Y]$ -/
@[to_additive "$H[-X, Y] = H[X, Y]$"]
lemma entropy_inv_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X⁻¹, Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.inv _).prodCongr (Equiv.refl _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, X / Y] = H[X, Y]$ -/
@[to_additive "$H[X, X - Y] = H[X, Y]$"]
lemma entropy_div_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X / Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, Y / X] = H[X, Y]$ -/
@[to_additive "$H[X, Y - X] = H[X, Y]$"]
lemma entropy_div_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y / X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[Y / X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y - X, Y] = H[X, Y]$"]
lemma entropy_div_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y / X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.div hX) hY _).trans $ (entropy_div_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X / Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X - Y, Y] = H[X, Y]$"]
lemma entropy_div_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X / Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.div hY) hY _).trans $ (entropy_div_right' hY hX _).trans $ entropy_comm hY hX _

/-- If $X$ is $G$-valued, then $H[X⁻¹]=H[X]$. -/
@[to_additive "If $X$ is $G$-valued, then $H[-X]=H[X]$."]
lemma entropy_inv (hX : Measurable X) : H[X⁻¹ ; μ] = H[X ; μ]

:=
  entropy_comp_of_injective μ hX (·⁻¹) inv_injective


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X * Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X + Y, Y] = H[X, Y]$"]
lemma entropy_mul_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X * Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.mul hY) hY _).trans $ (entropy_mul_right' hY hX _).trans $ entropy_comm hY hX _

/-- $H[X, Y⁻¹] = H[X, Y]$ -/
@[to_additive "$H[X, -Y] = H[X, Y]$"]
lemma entropy_inv_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y⁻¹⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodCongr (Equiv.inv _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X⁻¹, Y] = H[X, Y]$ -/
@[to_additive "$H[-X, Y] = H[X, Y]$"]
lemma entropy_inv_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X⁻¹, Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.inv _).prodCongr (Equiv.refl _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, X / Y] = H[X, Y]$ -/
@[to_additive "$H[X, X - Y] = H[X, Y]$"]
lemma entropy_div_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X / Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, Y / X] = H[X, Y]$ -/
@[to_additive "$H[X, Y - X] = H[X, Y]$"]
lemma entropy_div_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y / X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[Y / X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y - X, Y] = H[X, Y]$"]
lemma entropy_div_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y / X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.div hX) hY _).trans $ (entropy_div_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X / Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X - Y, Y] = H[X, Y]$"]
lemma entropy_div_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X / Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.div hY) hY _).trans $ (entropy_div_right' hY hX _).trans $ entropy_comm hY hX _

/-- If $X$ is $G$-valued, then $H[X⁻¹]=H[X]$. -/
@[to_additive "If $X$ is $G$-valued, then $H[-X]=H[X]$."]
lemma entropy_inv (hX : Measurable X) : H[X⁻¹ ; μ] = H[X ; μ] :=
  entropy_comp_of_injective μ hX (·⁻¹) inv_injective

/-- $$H[X / Y] = H[Y / X]$$ -/
@[to_additive "$$H[X - Y] = H[Y - X]$$"]
lemma entropy_div_comm {Y : Ω → G} (hX : Measurable X) (hY : Measurable Y) :
    H[X / Y ; μ] = H[Y / X ; μ]

:= by rw [← inv_div]; exact entropy_inv (hY.div hX)


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X * Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X + Y, Y] = H[X, Y]$"]
lemma entropy_mul_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X * Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.mul hY) hY _).trans $ (entropy_mul_right' hY hX _).trans $ entropy_comm hY hX _

/-- $H[X, Y⁻¹] = H[X, Y]$ -/
@[to_additive "$H[X, -Y] = H[X, Y]$"]
lemma entropy_inv_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y⁻¹⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodCongr (Equiv.inv _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X⁻¹, Y] = H[X, Y]$ -/
@[to_additive "$H[-X, Y] = H[X, Y]$"]
lemma entropy_inv_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X⁻¹, Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.inv _).prodCongr (Equiv.refl _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, X / Y] = H[X, Y]$ -/
@[to_additive "$H[X, X - Y] = H[X, Y]$"]
lemma entropy_div_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X / Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, Y / X] = H[X, Y]$ -/
@[to_additive "$H[X, Y - X] = H[X, Y]$"]
lemma entropy_div_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y / X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[Y / X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y - X, Y] = H[X, Y]$"]
lemma entropy_div_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y / X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.div hX) hY _).trans $ (entropy_div_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X / Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X - Y, Y] = H[X, Y]$"]
lemma entropy_div_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X / Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.div hY) hY _).trans $ (entropy_div_right' hY hX _).trans $ entropy_comm hY hX _

/-- If $X$ is $G$-valued, then $H[X⁻¹]=H[X]$. -/
@[to_additive "If $X$ is $G$-valued, then $H[-X]=H[X]$."]
lemma entropy_inv (hX : Measurable X) : H[X⁻¹ ; μ] = H[X ; μ] :=
  entropy_comp_of_injective μ hX (·⁻¹) inv_injective

/-- $$H[X / Y] = H[Y / X]$$ -/
@[to_additive "$$H[X - Y] = H[Y - X]$$"]
lemma entropy_div_comm {Y : Ω → G} (hX : Measurable X) (hY : Measurable Y) :
    H[X / Y ; μ] = H[Y / X ; μ] := by rw [← inv_div]; exact entropy_inv (hY.div hX)

end entropy

section condEntropy
variable [IsFiniteMeasure μ]

/-- $$H[Y * X | Y] = H[X | Y]$$ -/
@[to_additive "$$H[Y + X | Y] = H[X | Y]$$"]
lemma condEntropy_mul_left (hX : Measurable X) (hY : Measurable Y) :
     H[Y * X | Y ; μ] = H[X | Y ; μ]

:=
  condEntropy_of_injective μ hX hY (fun y x ↦ y * x) mul_right_injective


import PFR.ForMathlib.Entropy.Basic
import PFR.ForMathlib.Entropy.Kernel.Group

open Function MeasureTheory Measure Real
open scoped ENNReal NNReal Topology ProbabilityTheory BigOperators

universe uΩ uS uT uU
variable {Ω : Type uΩ} {G : Type uS} {T : Type uT} {U : Type uU} [mΩ : MeasurableSpace Ω]
  [Countable G] [Countable T] [Countable U]
  [Nonempty G] [Nonempty T] [Nonempty U]
  [MeasurableSpace G] [MeasurableSpace T] [MeasurableSpace U]
  [MeasurableSingletonClass G] [MeasurableSingletonClass T] [MeasurableSingletonClass U]
  [Group G] {X Y : Ω → G} {μ : Measure Ω}
  [FiniteRange X] [FiniteRange Y]

namespace ProbabilityTheory
section entropy

@[to_additive (attr := simp)]
lemma entropy_mul_const (hX : Measurable X) (c : G) :
    H[X * fun _ ↦ c; μ] = H[X ; μ] := by
  apply entropy_comp_of_injective μ hX _ $ mul_left_injective c

/-- $H[X, X * Y] = H[X, Y]$ -/
@[to_additive "$H[X, X + Y] = H[X, Y]$"]
lemma entropy_mul_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X * Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[X, Y * X] = H[X, Y]$ -/
@[to_additive "$H[X, Y + X] = H[X, Y]$"]
lemma entropy_mul_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y * X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.mulRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ $ Equiv.injective _

/-- $H[Y * X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y + X, Y] = H[X, Y]$"]
lemma entropy_mul_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y * X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.mul hX) hY _).trans $ (entropy_mul_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X * Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X + Y, Y] = H[X, Y]$"]
lemma entropy_mul_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X * Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.mul hY) hY _).trans $ (entropy_mul_right' hY hX _).trans $ entropy_comm hY hX _

/-- $H[X, Y⁻¹] = H[X, Y]$ -/
@[to_additive "$H[X, -Y] = H[X, Y]$"]
lemma entropy_inv_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y⁻¹⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodCongr (Equiv.inv _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X⁻¹, Y] = H[X, Y]$ -/
@[to_additive "$H[-X, Y] = H[X, Y]$"]
lemma entropy_inv_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X⁻¹, Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.inv _).prodCongr (Equiv.refl _) ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, X / Y] = H[X, Y]$ -/
@[to_additive "$H[X, X - Y] = H[X, Y]$"]
lemma entropy_div_right (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, X / Y⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divLeft ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[X, Y / X] = H[X, Y]$ -/
@[to_additive "$H[X, Y - X] = H[X, Y]$"]
lemma entropy_div_right' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X, Y / X⟩; μ] = H[⟨X, Y⟩ ; μ] := by
  change H[(Equiv.refl _).prodShear Equiv.divRight ∘ ⟨X, Y⟩ ; μ] = H[⟨X, Y⟩ ; μ]
  exact entropy_comp_of_injective μ (hX.prod_mk hY) _ (Equiv.injective _)

/-- $H[Y / X, Y] = H[X, Y]$ -/
@[to_additive "$H[Y - X, Y] = H[X, Y]$"]
lemma entropy_div_left (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨Y / X, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hY.div hX) hY _).trans $ (entropy_div_right hY hX _).trans $ entropy_comm hY hX _

/-- $H[X / Y, Y] = H[X, Y]$ -/
@[to_additive "$H[X - Y, Y] = H[X, Y]$"]
lemma entropy_div_left' (hX : Measurable X) (hY : Measurable Y) (μ : Measure Ω) :
    H[⟨X / Y, Y⟩; μ] = H[⟨X, Y⟩ ; μ] :=
  (entropy_comm (hX.div hY) hY _).trans $ (entropy_div_right' hY hX _).trans $ entropy_comm hY hX _

/-- If $X$ is $G$-valued, then $H[X⁻¹]=H[X]$. -/
@[to_additive "If $X$ is $G$-valued, then $H[-X]=H[X]$."]
lemma entropy_inv (hX : Measurable X) : H[X⁻¹ ; μ] = H[X ; μ] :=
  entropy_comp_of_injective μ hX (·⁻¹) inv_injective

/-- $$H[X / Y] = H[Y / X]$$ -/
@[to_additive "$$H[X - Y] = H[Y - X]$$"]
lemma entropy_div_comm {Y : Ω → G} (hX : Measurable X) (hY : Measurable Y) :
    H[X / Y ; μ] = H[Y / X ; μ] := by rw [← inv_div]; exact entropy_inv (hY.div hX)

end entropy

section condEntropy
variable [IsFiniteMeasure μ]

/-- $$H[Y * X | Y] = H[X | Y]$$ -/
@[to_additive "$$H[Y + X | Y] = H[X | Y]$$"]
lemma condEntropy_mul_left (hX : Measurable X) (hY : Measurable Y) :
     H[Y * X | Y ; μ] = H[X | Y ; μ] :=
  condEntropy_of_injective μ hX hY (fun y x ↦ y * x) mul_right_injective

/-- $$H[X * Y | Y] = H[X | Y]$$ -/
@[to_additive "$$H[X + Y | Y] = H[X | Y]$$"]
lemma condEntropy_mul_right (hX : Measurable X) (hY : Measurable Y) :
    H[X * Y | Y ; μ] = H[X | Y ; μ]

:=
  condEntropy_of_injective μ hX hY (fun y x ↦ x * y) mul_left_injective