l3lab/ntp-mathlib huggingface dataset:
/-- `primitiveRoots n K` is a subset of the roots of the minimal polynomial of a primitive
`n`-th root of unity `μ`. -/
theorem is_roots_of_minpoly [DecidableEq K] :
    primitiveRoots n K ⊆ (map (Int.castRingHom K) (minpoly ℤ μ)).roots.toFinset := by
  

Proof state:
n : ℕ
K : Type u_1
inst✝³ : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝² : IsDomain K
inst✝¹ : CharZero K
inst✝ : DecidableEq K
⊢ primitiveRoots n K ⊆ Multiset.toFinset (roots (map (Int.castRingHom K) (minpoly ℤ μ)))

Next tactic:
by_cases hn : n = 0
/-- `primitiveRoots n K` is a subset of the roots of the minimal polynomial of a primitive
`n`-th root of unity `μ`. -/
theorem is_roots_of_minpoly [DecidableEq K] :
    primitiveRoots n K ⊆ (map (Int.castRingHom K) (minpoly ℤ μ)).roots.toFinset := by
  by_cases hn : n = 0; · 

Proof state:
case pos
n : ℕ
K : Type u_1
inst✝³ : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝² : IsDomain K
inst✝¹ : CharZero K
inst✝ : DecidableEq K
hn : n = 0
⊢ primitiveRoots n K ⊆ Multiset.toFinset (roots (map (Int.castRingHom K) (minpoly ℤ μ)))

Next tactic:
simp_all
/-- `primitiveRoots n K` is a subset of the roots of the minimal polynomial of a primitive
`n`-th root of unity `μ`. -/
theorem is_roots_of_minpoly [DecidableEq K] :
    primitiveRoots n K ⊆ (map (Int.castRingHom K) (minpoly ℤ μ)).roots.toFinset := by
  by_cases hn : n = 0; · simp_all
  

Proof state:
case neg
n : ℕ
K : Type u_1
inst✝³ : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝² : IsDomain K
inst✝¹ : CharZero K
inst✝ : DecidableEq K
hn : ¬n = 0
⊢ primitiveRoots n K ⊆ Multiset.toFinset (roots (map (Int.castRingHom K) (minpoly ℤ μ)))

Next tactic:
have hpos := Nat.pos_of_ne_zero hn
/-- `primitiveRoots n K` is a subset of the roots of the minimal polynomial of a primitive
`n`-th root of unity `μ`. -/
theorem is_roots_of_minpoly [DecidableEq K] :
    primitiveRoots n K ⊆ (map (Int.castRingHom K) (minpoly ℤ μ)).roots.toFinset := by
  by_cases hn : n = 0; · simp_all
  have hpos := Nat.pos_of_ne_zero hn
  

Proof state:
case neg
n : ℕ
K : Type u_1
inst✝³ : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝² : IsDomain K
inst✝¹ : CharZero K
inst✝ : DecidableEq K
hn : ¬n = 0
hpos : 0 < n
⊢ primitiveRoots n K ⊆ Multiset.toFinset (roots (map (Int.castRingHom K) (minpoly ℤ μ)))

Next tactic:
intro x hx
/-- `primitiveRoots n K` is a subset of the roots of the minimal polynomial of a primitive
`n`-th root of unity `μ`. -/
theorem is_roots_of_minpoly [DecidableEq K] :
    primitiveRoots n K ⊆ (map (Int.castRingHom K) (minpoly ℤ μ)).roots.toFinset := by
  by_cases hn : n = 0; · simp_all
  have hpos := Nat.pos_of_ne_zero hn
  intro x hx
  

Proof state:
case neg
n : ℕ
K : Type u_1
inst✝³ : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝² : IsDomain K
inst✝¹ : CharZero K
inst✝ : DecidableEq K
hn : ¬n = 0
hpos : 0 < n
x : K
hx : x ∈ primitiveRoots n K
⊢ x ∈ Multiset.toFinset (roots (map (Int.castRingHom K) (minpoly ℤ μ)))

Next tactic:
obtain ⟨m, _, hcop, rfl⟩ := (isPrimitiveRoot_iff h hpos).1 ((mem_primitiveRoots hpos).1 hx)
/-- `primitiveRoots n K` is a subset of the roots of the minimal polynomial of a primitive
`n`-th root of unity `μ`. -/
theorem is_roots_of_minpoly [DecidableEq K] :
    primitiveRoots n K ⊆ (map (Int.castRingHom K) (minpoly ℤ μ)).roots.toFinset := by
  by_cases hn : n = 0; · simp_all
  have hpos := Nat.pos_of_ne_zero hn
  intro x hx
  obtain ⟨m, _, hcop, rfl⟩ := (isPrimitiveRoot_iff h hpos).1 ((mem_primitiveRoots hpos).1 hx)
  

Proof state:
case neg.intro.intro.intro
n : ℕ
K : Type u_1
inst✝³ : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝² : IsDomain K
inst✝¹ : CharZero K
inst✝ : DecidableEq K
hn : ¬n = 0
hpos : 0 < n
m : ℕ
left✝ : m < n
hcop : Nat.Coprime m n
hx : μ ^ m ∈ primitiveRoots n K
⊢ μ ^ m ∈ Multiset.toFinset (roots (map (Int.castRingHom K) (minpoly ℤ μ)))

Next tactic:
simp only [Multiset.mem_toFinset, mem_roots]
/-- `primitiveRoots n K` is a subset of the roots of the minimal polynomial of a primitive
`n`-th root of unity `μ`. -/
theorem is_roots_of_minpoly [DecidableEq K] :
    primitiveRoots n K ⊆ (map (Int.castRingHom K) (minpoly ℤ μ)).roots.toFinset := by
  by_cases hn : n = 0; · simp_all
  have hpos := Nat.pos_of_ne_zero hn
  intro x hx
  obtain ⟨m, _, hcop, rfl⟩ := (isPrimitiveRoot_iff h hpos).1 ((mem_primitiveRoots hpos).1 hx)
  simp only [Multiset.mem_toFinset, mem_roots]
  

Proof state:
case neg.intro.intro.intro
n : ℕ
K : Type u_1
inst✝³ : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝² : IsDomain K
inst✝¹ : CharZero K
inst✝ : DecidableEq K
hn : ¬n = 0
hpos : 0 < n
m : ℕ
left✝ : m < n
hcop : Nat.Coprime m n
hx : μ ^ m ∈ primitiveRoots n K
⊢ μ ^ m ∈ roots (map (Int.castRingHom K) (minpoly ℤ μ))

Next tactic:
convert pow_isRoot_minpoly h hcop
/-- `primitiveRoots n K` is a subset of the roots of the minimal polynomial of a primitive
`n`-th root of unity `μ`. -/
theorem is_roots_of_minpoly [DecidableEq K] :
    primitiveRoots n K ⊆ (map (Int.castRingHom K) (minpoly ℤ μ)).roots.toFinset := by
  by_cases hn : n = 0; · simp_all
  have hpos := Nat.pos_of_ne_zero hn
  intro x hx
  obtain ⟨m, _, hcop, rfl⟩ := (isPrimitiveRoot_iff h hpos).1 ((mem_primitiveRoots hpos).1 hx)
  simp only [Multiset.mem_toFinset, mem_roots]
  convert pow_isRoot_minpoly h hcop
  

Proof state:
case a
n : ℕ
K : Type u_1
inst✝³ : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝² : IsDomain K
inst✝¹ : CharZero K
inst✝ : DecidableEq K
hn : ¬n = 0
hpos : 0 < n
m : ℕ
left✝ : m < n
hcop : Nat.Coprime m n
hx : μ ^ m ∈ primitiveRoots n K
⊢ μ ^ m ∈ roots (map (Int.castRingHom K) (minpoly ℤ μ)) ↔ IsRoot (map (Int.castRingHom K) (minpoly ℤ μ)) (μ ^ m)

Next tactic:
rw [← mem_roots]
/-- `primitiveRoots n K` is a subset of the roots of the minimal polynomial of a primitive
`n`-th root of unity `μ`. -/
theorem is_roots_of_minpoly [DecidableEq K] :
    primitiveRoots n K ⊆ (map (Int.castRingHom K) (minpoly ℤ μ)).roots.toFinset := by
  by_cases hn : n = 0; · simp_all
  have hpos := Nat.pos_of_ne_zero hn
  intro x hx
  obtain ⟨m, _, hcop, rfl⟩ := (isPrimitiveRoot_iff h hpos).1 ((mem_primitiveRoots hpos).1 hx)
  simp only [Multiset.mem_toFinset, mem_roots]
  convert pow_isRoot_minpoly h hcop
  rw [← mem_roots]
  

Proof state:
case a
n : ℕ
K : Type u_1
inst✝³ : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝² : IsDomain K
inst✝¹ : CharZero K
inst✝ : DecidableEq K
hn : ¬n = 0
hpos : 0 < n
m : ℕ
left✝ : m < n
hcop : Nat.Coprime m n
hx : μ ^ m ∈ primitiveRoots n K
⊢ map (Int.castRingHom K) (minpoly ℤ μ) ≠ 0

Next tactic:
exact map_monic_ne_zero <| minpoly.monic <| isIntegral h hpos
/-- The degree of the minimal polynomial of `μ` is at least `totient n`. -/
theorem totient_le_degree_minpoly : Nat.totient n ≤ (minpoly ℤ μ).natDegree := by
  

Proof state:
n : ℕ
K : Type u_1
inst✝² : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝¹ : IsDomain K
inst✝ : CharZero K
⊢ Nat.totient n ≤ natDegree (minpoly ℤ μ)

Next tactic:
classical
  let P : ℤ[X] := minpoly ℤ μ
  -- minimal polynomial of `μ`
  let P_K : K[X] := map (Int.castRingHom K) P
  -- minimal polynomial of `μ` sent to `K[X]`
  calc
    n.totient = (primitiveRoots n K).card := h.card_primitiveRoots.symm
    _ ≤ P_K.roots.toFinset.card := (Finset.card_le_of_subset (is_roots_of_minpoly h))
    _ ≤ Multiset.card P_K.roots := (Multiset.toFinset_card_le _)
    _ ≤ P_K.natDegree := (card_roots' _)
    _ ≤ P.natDegree := natDegree_map_le _ _
/-- The degree of the minimal polynomial of `μ` is at least `totient n`. -/
theorem totient_le_degree_minpoly : Nat.totient n ≤ (minpoly ℤ μ).natDegree := by
  classical
  

Proof state:
n : ℕ
K : Type u_1
inst✝² : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝¹ : IsDomain K
inst✝ : CharZero K
⊢ Nat.totient n ≤ natDegree (minpoly ℤ μ)

Next tactic:
let P : ℤ[X] := minpoly ℤ μ
/-- The degree of the minimal polynomial of `μ` is at least `totient n`. -/
theorem totient_le_degree_minpoly : Nat.totient n ≤ (minpoly ℤ μ).natDegree := by
  classical
  let P : ℤ[X] := minpoly ℤ μ
  -- minimal polynomial of `μ`
  

Proof state:
n : ℕ
K : Type u_1
inst✝² : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝¹ : IsDomain K
inst✝ : CharZero K
P : ℤ[X] := minpoly ℤ μ
⊢ Nat.totient n ≤ natDegree (minpoly ℤ μ)

Next tactic:
let P_K : K[X] := map (Int.castRingHom K) P
/-- The degree of the minimal polynomial of `μ` is at least `totient n`. -/
theorem totient_le_degree_minpoly : Nat.totient n ≤ (minpoly ℤ μ).natDegree := by
  classical
  let P : ℤ[X] := minpoly ℤ μ
  -- minimal polynomial of `μ`
  let P_K : K[X] := map (Int.castRingHom K) P
  -- minimal polynomial of `μ` sent to `K[X]`
  

Proof state:
n : ℕ
K : Type u_1
inst✝² : CommRing K
μ : K
h : IsPrimitiveRoot μ n
inst✝¹ : IsDomain K
inst✝ : CharZero K
P : ℤ[X] := minpoly ℤ μ
P_K : K[X] := map (Int.castRingHom K) P
⊢ Nat.totient n ≤ natDegree (minpoly ℤ μ)

Next tactic:
calc
    n.totient = (primitiveRoots n K).card := h.card_primitiveRoots.symm
    _ ≤ P_K.roots.toFinset.card := (Finset.card_le_of_subset (is_roots_of_minpoly h))
    _ ≤ Multiset.card P_K.roots := (Multiset.toFinset_card_le _)
    _ ≤ P_K.natDegree := (card_roots' _)
    _ ≤ P.natDegree := natDegree_map_le _ _
theorem measure_self_or_compl_eq_zero (hf : PreErgodic f μ) (hs : MeasurableSet s)
    (hs' : f ⁻¹' s = s) : μ s = 0 ∨ μ sᶜ = 0 := by
  

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
hf : PreErgodic f
hs : MeasurableSet s
hs' : f ⁻¹' s = s
⊢ ↑↑μ s = 0 ∨ ↑↑μ sᶜ = 0

Next tactic:
simpa using hf.ae_empty_or_univ hs hs'
/-- On a probability space, the (pre)ergodicity condition is a zero one law. -/
theorem prob_eq_zero_or_one [IsProbabilityMeasure μ] (hf : PreErgodic f μ) (hs : MeasurableSet s)
    (hs' : f ⁻¹' s = s) : μ s = 0 ∨ μ s = 1 := by
  

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
inst✝ : IsProbabilityMeasure μ
hf : PreErgodic f
hs : MeasurableSet s
hs' : f ⁻¹' s = s
⊢ ↑↑μ s = 0 ∨ ↑↑μ s = 1

Next tactic:
simpa [hs] using hf.measure_self_or_compl_eq_zero hs hs'
theorem preErgodic_of_preErgodic_conjugate (hg : MeasurePreserving g μ μ') (hf : PreErgodic f μ)
    {f' : β → β} (h_comm : g ∘ f = f' ∘ g) : PreErgodic f' μ' :=
  ⟨by
    

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
hg : MeasurePreserving g
hf : PreErgodic f
f' : β → β
h_comm : g ∘ f = f' ∘ g
⊢ ∀ ⦃s : Set β⦄, MeasurableSet s → f' ⁻¹' s = s → s =ᶠ[ae μ'] ∅ ∨ s =ᶠ[ae μ'] univ

Next tactic:
intro s hs₀ hs₁
theorem preErgodic_of_preErgodic_conjugate (hg : MeasurePreserving g μ μ') (hf : PreErgodic f μ)
    {f' : β → β} (h_comm : g ∘ f = f' ∘ g) : PreErgodic f' μ' :=
  ⟨by
    intro s hs₀ hs₁
    

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s✝ : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
hg : MeasurePreserving g
hf : PreErgodic f
f' : β → β
h_comm : g ∘ f = f' ∘ g
s : Set β
hs₀ : MeasurableSet s
hs₁ : f' ⁻¹' s = s
⊢ s =ᶠ[ae μ'] ∅ ∨ s =ᶠ[ae μ'] univ

Next tactic:
replace hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s
theorem preErgodic_of_preErgodic_conjugate (hg : MeasurePreserving g μ μ') (hf : PreErgodic f μ)
    {f' : β → β} (h_comm : g ∘ f = f' ∘ g) : PreErgodic f' μ' :=
  ⟨by
    intro s hs₀ hs₁
    replace hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s; · 

Proof state:
case hs₁
α : Type u_1
m : MeasurableSpace α
f : α → α
s✝ : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
hg : MeasurePreserving g
hf : PreErgodic f
f' : β → β
h_comm : g ∘ f = f' ∘ g
s : Set β
hs₀ : MeasurableSet s
hs₁ : f' ⁻¹' s = s
⊢ f ⁻¹' (g ⁻¹' s) = g ⁻¹' s

Next tactic:
rw [← preimage_comp, h_comm, preimage_comp, hs₁]
theorem preErgodic_of_preErgodic_conjugate (hg : MeasurePreserving g μ μ') (hf : PreErgodic f μ)
    {f' : β → β} (h_comm : g ∘ f = f' ∘ g) : PreErgodic f' μ' :=
  ⟨by
    intro s hs₀ hs₁
    replace hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s; · rw [← preimage_comp, h_comm, preimage_comp, hs₁]
    

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s✝ : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
hg : MeasurePreserving g
hf : PreErgodic f
f' : β → β
h_comm : g ∘ f = f' ∘ g
s : Set β
hs₀ : MeasurableSet s
hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s
⊢ s =ᶠ[ae μ'] ∅ ∨ s =ᶠ[ae μ'] univ

Next tactic:
cases' hf.ae_empty_or_univ (hg.measurable hs₀) hs₁ with hs₂ hs₂ <;> [left; right]
theorem preErgodic_of_preErgodic_conjugate (hg : MeasurePreserving g μ μ') (hf : PreErgodic f μ)
    {f' : β → β} (h_comm : g ∘ f = f' ∘ g) : PreErgodic f' μ' :=
  ⟨by
    intro s hs₀ hs₁
    replace hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s; · rw [← preimage_comp, h_comm, preimage_comp, hs₁]
    

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s✝ : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
hg : MeasurePreserving g
hf : PreErgodic f
f' : β → β
h_comm : g ∘ f = f' ∘ g
s : Set β
hs₀ : MeasurableSet s
hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s
⊢ s =ᶠ[ae μ'] ∅ ∨ s =ᶠ[ae μ'] univ

Next tactic:
cases' hf.ae_empty_or_univ (hg.measurable hs₀) hs₁ with hs₂ hs₂
theorem preErgodic_of_preErgodic_conjugate (hg : MeasurePreserving g μ μ') (hf : PreErgodic f μ)
    {f' : β → β} (h_comm : g ∘ f = f' ∘ g) : PreErgodic f' μ' :=
  ⟨by
    intro s hs₀ hs₁
    replace hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s; · rw [← preimage_comp, h_comm, preimage_comp, hs₁]
    cases' hf.ae_empty_or_univ (hg.measurable hs₀) hs₁ with hs₂ hs₂ <;> [

Proof state:
case inl
α : Type u_1
m : MeasurableSpace α
f : α → α
s✝ : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
hg : MeasurePreserving g
hf : PreErgodic f
f' : β → β
h_comm : g ∘ f = f' ∘ g
s : Set β
hs₀ : MeasurableSet s
hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s
hs₂ : g ⁻¹' s =ᶠ[ae μ] ∅
⊢ s =ᶠ[ae μ'] ∅ ∨ s =ᶠ[ae μ'] univ

Next tactic:
left
theorem preErgodic_of_preErgodic_conjugate (hg : MeasurePreserving g μ μ') (hf : PreErgodic f μ)
    {f' : β → β} (h_comm : g ∘ f = f' ∘ g) : PreErgodic f' μ' :=
  ⟨by
    intro s hs₀ hs₁
    replace hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s; · rw [← preimage_comp, h_comm, preimage_comp, hs₁]
    cases' hf.ae_empty_or_univ (hg.measurable hs₀) hs₁ with hs₂ hs₂ <;> [left; 

Proof state:
case inr
α : Type u_1
m : MeasurableSpace α
f : α → α
s✝ : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
hg : MeasurePreserving g
hf : PreErgodic f
f' : β → β
h_comm : g ∘ f = f' ∘ g
s : Set β
hs₀ : MeasurableSet s
hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s
hs₂ : g ⁻¹' s =ᶠ[ae μ] univ
⊢ s =ᶠ[ae μ'] ∅ ∨ s =ᶠ[ae μ'] univ

Next tactic:
right
theorem preErgodic_of_preErgodic_conjugate (hg : MeasurePreserving g μ μ') (hf : PreErgodic f μ)
    {f' : β → β} (h_comm : g ∘ f = f' ∘ g) : PreErgodic f' μ' :=
  ⟨by
    intro s hs₀ hs₁
    replace hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s; · rw [← preimage_comp, h_comm, preimage_comp, hs₁]
    cases' hf.ae_empty_or_univ (hg.measurable hs₀) hs₁ with hs₂ hs₂ <;> [left; right]
    · 

Proof state:
case inl.h
α : Type u_1
m : MeasurableSpace α
f : α → α
s✝ : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
hg : MeasurePreserving g
hf : PreErgodic f
f' : β → β
h_comm : g ∘ f = f' ∘ g
s : Set β
hs₀ : MeasurableSet s
hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s
hs₂ : g ⁻¹' s =ᶠ[ae μ] ∅
⊢ s =ᶠ[ae μ'] ∅

Next tactic:
simpa only [ae_eq_empty, hg.measure_preimage hs₀] using hs₂
theorem preErgodic_of_preErgodic_conjugate (hg : MeasurePreserving g μ μ') (hf : PreErgodic f μ)
    {f' : β → β} (h_comm : g ∘ f = f' ∘ g) : PreErgodic f' μ' :=
  ⟨by
    intro s hs₀ hs₁
    replace hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s; · rw [← preimage_comp, h_comm, preimage_comp, hs₁]
    cases' hf.ae_empty_or_univ (hg.measurable hs₀) hs₁ with hs₂ hs₂ <;> [left; right]
    · simpa only [ae_eq_empty, hg.measure_preimage hs₀] using hs₂
    · 

Proof state:
case inr.h
α : Type u_1
m : MeasurableSpace α
f : α → α
s✝ : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
hg : MeasurePreserving g
hf : PreErgodic f
f' : β → β
h_comm : g ∘ f = f' ∘ g
s : Set β
hs₀ : MeasurableSet s
hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s
hs₂ : g ⁻¹' s =ᶠ[ae μ] univ
⊢ s =ᶠ[ae μ'] univ

Next tactic:
simpa only [ae_eq_univ, ← preimage_compl, hg.measure_preimage hs₀.compl] using hs₂
theorem preErgodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') :
    PreErgodic (e ∘ f ∘ e.symm) μ' ↔ PreErgodic f μ := by
  

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
e : α ≃ᵐ β
h : MeasurePreserving ⇑e
⊢ PreErgodic (⇑e ∘ f ∘ ⇑e.symm) ↔ PreErgodic f

Next tactic:
refine' ⟨fun hf => preErgodic_of_preErgodic_conjugate (h.symm e) hf _,
      fun hf => preErgodic_of_preErgodic_conjugate h hf _⟩
theorem preErgodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') :
    PreErgodic (e ∘ f ∘ e.symm) μ' ↔ PreErgodic f μ := by
  refine' ⟨fun hf => preErgodic_of_preErgodic_conjugate (h.symm e) hf _,
      fun hf => preErgodic_of_preErgodic_conjugate h hf _⟩
  · 

Proof state:
case refine'_1
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
e : α ≃ᵐ β
h : MeasurePreserving ⇑e
hf : PreErgodic (⇑e ∘ f ∘ ⇑e.symm)
⊢ ⇑e.symm ∘ ⇑e ∘ f ∘ ⇑e.symm = f ∘ ⇑e.symm

Next tactic:
change (e.symm ∘ e) ∘ f ∘ e.symm = f ∘ e.symm
theorem preErgodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') :
    PreErgodic (e ∘ f ∘ e.symm) μ' ↔ PreErgodic f μ := by
  refine' ⟨fun hf => preErgodic_of_preErgodic_conjugate (h.symm e) hf _,
      fun hf => preErgodic_of_preErgodic_conjugate h hf _⟩
  · change (e.symm ∘ e) ∘ f ∘ e.symm = f ∘ e.symm
    

Proof state:
case refine'_1
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
e : α ≃ᵐ β
h : MeasurePreserving ⇑e
hf : PreErgodic (⇑e ∘ f ∘ ⇑e.symm)
⊢ (⇑e.symm ∘ ⇑e) ∘ f ∘ ⇑e.symm = f ∘ ⇑e.symm

Next tactic:
rw [MeasurableEquiv.symm_comp_self, comp.left_id]
theorem preErgodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') :
    PreErgodic (e ∘ f ∘ e.symm) μ' ↔ PreErgodic f μ := by
  refine' ⟨fun hf => preErgodic_of_preErgodic_conjugate (h.symm e) hf _,
      fun hf => preErgodic_of_preErgodic_conjugate h hf _⟩
  · change (e.symm ∘ e) ∘ f ∘ e.symm = f ∘ e.symm
    rw [MeasurableEquiv.symm_comp_self, comp.left_id]
  · 

Proof state:
case refine'_2
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
e : α ≃ᵐ β
h : MeasurePreserving ⇑e
hf : PreErgodic f
⊢ ⇑e ∘ f = (⇑e ∘ f ∘ ⇑e.symm) ∘ ⇑e

Next tactic:
change e ∘ f = e ∘ f ∘ e.symm ∘ e
theorem preErgodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') :
    PreErgodic (e ∘ f ∘ e.symm) μ' ↔ PreErgodic f μ := by
  refine' ⟨fun hf => preErgodic_of_preErgodic_conjugate (h.symm e) hf _,
      fun hf => preErgodic_of_preErgodic_conjugate h hf _⟩
  · change (e.symm ∘ e) ∘ f ∘ e.symm = f ∘ e.symm
    rw [MeasurableEquiv.symm_comp_self, comp.left_id]
  · change e ∘ f = e ∘ f ∘ e.symm ∘ e
    

Proof state:
case refine'_2
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
e : α ≃ᵐ β
h : MeasurePreserving ⇑e
hf : PreErgodic f
⊢ ⇑e ∘ f = ⇑e ∘ f ∘ ⇑e.symm ∘ ⇑e

Next tactic:
rw [MeasurableEquiv.symm_comp_self, comp.right_id]
theorem ergodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') :
    Ergodic (e ∘ f ∘ e.symm) μ' ↔ Ergodic f μ := by
  

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
e : α ≃ᵐ β
h : MeasurePreserving ⇑e
⊢ Ergodic (⇑e ∘ f ∘ ⇑e.symm) ↔ Ergodic f

Next tactic:
have : MeasurePreserving (e ∘ f ∘ e.symm) μ' μ' ↔ MeasurePreserving f μ μ := by
    rw [h.comp_left_iff, (MeasurePreserving.symm e h).comp_right_iff]
theorem ergodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') :
    Ergodic (e ∘ f ∘ e.symm) μ' ↔ Ergodic f μ := by
  have : MeasurePreserving (e ∘ f ∘ e.symm) μ' μ' ↔ MeasurePreserving f μ μ := by
    

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
e : α ≃ᵐ β
h : MeasurePreserving ⇑e
⊢ MeasurePreserving (⇑e ∘ f ∘ ⇑e.symm) ↔ MeasurePreserving f

Next tactic:
rw [h.comp_left_iff, (MeasurePreserving.symm e h).comp_right_iff]
theorem ergodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') :
    Ergodic (e ∘ f ∘ e.symm) μ' ↔ Ergodic f μ := by
  have : MeasurePreserving (e ∘ f ∘ e.symm) μ' μ' ↔ MeasurePreserving f μ μ := by
    rw [h.comp_left_iff, (MeasurePreserving.symm e h).comp_right_iff]
  

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
e : α ≃ᵐ β
h : MeasurePreserving ⇑e
this : MeasurePreserving (⇑e ∘ f ∘ ⇑e.symm) ↔ MeasurePreserving f
⊢ Ergodic (⇑e ∘ f ∘ ⇑e.symm) ↔ Ergodic f

Next tactic:
replace h : PreErgodic (e ∘ f ∘ e.symm) μ' ↔ PreErgodic f μ := h.preErgodic_conjugate_iff
theorem ergodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') :
    Ergodic (e ∘ f ∘ e.symm) μ' ↔ Ergodic f μ := by
  have : MeasurePreserving (e ∘ f ∘ e.symm) μ' μ' ↔ MeasurePreserving f μ μ := by
    rw [h.comp_left_iff, (MeasurePreserving.symm e h).comp_right_iff]
  replace h : PreErgodic (e ∘ f ∘ e.symm) μ' ↔ PreErgodic f μ := h.preErgodic_conjugate_iff
  

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
β : Type u_2
m' : MeasurableSpace β
μ' : Measure β
s' : Set β
g : α → β
e : α ≃ᵐ β
this : MeasurePreserving (⇑e ∘ f ∘ ⇑e.symm) ↔ MeasurePreserving f
h : PreErgodic (⇑e ∘ f ∘ ⇑e.symm) ↔ PreErgodic f
⊢ Ergodic (⇑e ∘ f ∘ ⇑e.symm) ↔ Ergodic f

Next tactic:
exact ⟨fun hf => { this.mp hf.toMeasurePreserving, h.mp hf.toPreErgodic with },
    fun hf => { this.mpr hf.toMeasurePreserving, h.mpr hf.toPreErgodic with }⟩
/-- For a quasi ergodic map, sets that are almost invariant (rather than strictly invariant) are
still either almost empty or full. -/
theorem ae_empty_or_univ' (hf : QuasiErgodic f μ) (hs : MeasurableSet s) (hs' : f ⁻¹' s =ᵐ[μ] s) :
    s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := by
  

Proof state:
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
hf : QuasiErgodic f
hs : MeasurableSet s
hs' : f ⁻¹' s =ᶠ[ae μ] s
⊢ s =ᶠ[ae μ] ∅ ∨ s =ᶠ[ae μ] univ

Next tactic:
obtain ⟨t, h₀, h₁, h₂⟩ := hf.toQuasiMeasurePreserving.exists_preimage_eq_of_preimage_ae hs hs'
/-- For a quasi ergodic map, sets that are almost invariant (rather than strictly invariant) are
still either almost empty or full. -/
theorem ae_empty_or_univ' (hf : QuasiErgodic f μ) (hs : MeasurableSet s) (hs' : f ⁻¹' s =ᵐ[μ] s) :
    s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := by
  obtain ⟨t, h₀, h₁, h₂⟩ := hf.toQuasiMeasurePreserving.exists_preimage_eq_of_preimage_ae hs hs'
  

Proof state:
case intro.intro.intro
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
hf : QuasiErgodic f
hs : MeasurableSet s
hs' : f ⁻¹' s =ᶠ[ae μ] s
t : Set α
h₀ : MeasurableSet t
h₁ : t =ᶠ[ae μ] s
h₂ : f ⁻¹' t = t
⊢ s =ᶠ[ae μ] ∅ ∨ s =ᶠ[ae μ] univ

Next tactic:
rcases hf.ae_empty_or_univ h₀ h₂ with (h₃ | h₃) <;> [left; right]
/-- For a quasi ergodic map, sets that are almost invariant (rather than strictly invariant) are
still either almost empty or full. -/
theorem ae_empty_or_univ' (hf : QuasiErgodic f μ) (hs : MeasurableSet s) (hs' : f ⁻¹' s =ᵐ[μ] s) :
    s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := by
  obtain ⟨t, h₀, h₁, h₂⟩ := hf.toQuasiMeasurePreserving.exists_preimage_eq_of_preimage_ae hs hs'
  

Proof state:
case intro.intro.intro
α : Type u_1
m : MeasurableSpace α
f : α → α
s : Set α
μ : Measure α
hf : QuasiErgodic f
hs : MeasurableSet s
hs' : f ⁻¹' s =ᶠ[ae μ] s
t : Set α
h₀ : MeasurableSet t
h₁ : t =ᶠ[ae μ] s
h₂ : f ⁻¹' t = t
⊢ s =ᶠ[ae μ] ∅ ∨ s =ᶠ[ae μ] univ

Next tactic:
rcases hf.ae_empty_or_univ h₀ h₂ with (h₃ | h₃)