-- Mathlib/Analysis/InnerProductSpace/MeanErgodic.lean
theorem LinearMap.tendsto_birkhoffAverage_of_ker_subset_closure [NormedSpace 𝕜 E]
    (f : E →ₗ[𝕜] E) (hf : LipschitzWith 1 f) (g : E →L[𝕜] LinearMap.eqLocus f 1)
    (hg_proj : ∀ x : LinearMap.eqLocus f 1, g x = x)
    (hg_ker : (LinearMap.ker g : Set E) ⊆ closure (LinearMap.range (f - 1))) (x : E) :
    Tendsto (birkhoffAverage 𝕜 f _root_.id · x) atTop (𝓝 (g x))

Proof state:
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
y : E
hy : g y = 0
z : E
hz : IsFixedPt (⇑f) z
this : Tendsto (fun x => birkhoffAverage 𝕜 (⇑f) _root_.id x y) atTop (𝓝 0)
hgz : ↑(g z) = z
⊢ Tendsto (fun x => birkhoffAverage 𝕜 (⇑f) _root_.id x (y + z)) atTop (𝓝 ↑(g (y + z)))

Tactic:
simpa [hy, hgz, birkhoffAverage, birkhoffSum, Finset.sum_add_distrib, smul_add]
  using this.add (hz.tendsto_birkhoffAverage 𝕜 _root_.id)

Result:
no goals

Proof state:
case intro.intro.intro.intro
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
y : E
hy : g y = 0
z : E
hz : IsFixedPt (⇑f) z
this : IsClosed {x | Tendsto (fun x_1 => birkhoffAverage 𝕜 (⇑f) _root_.id x_1 x) atTop (𝓝 0)}
⊢ Tendsto (fun x => birkhoffAverage 𝕜 (⇑f) _root_.id x y) atTop (𝓝 0)

Tactic:
refine closure_minimal (Set.forall_mem_range.2 fun x ↦ ?_) this (hg_ker hy)

Result:
case intro.intro.intro.intro
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
y : E
hy : g y = 0
z : E
hz : IsFixedPt (⇑f) z
this : IsClosed {x | Tendsto (fun x_1 => birkhoffAverage 𝕜 (⇑f) _root_.id x_1 x) atTop (𝓝 0)}
x : E
⊢ (f - 1) x ∈ {x | Tendsto (fun x_1 => birkhoffAverage 𝕜 (⇑f) _root_.id x_1 x) atTop (𝓝 0)}

Proof state:
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
x : E
⊢ x = x - ↑(g x) + ↑(g x)

Tactic:
simp

Result:
no goals

Proof state:
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
y : E
hy : g y = 0
z : E
hz : IsFixedPt (⇑f) z
this : IsClosed {x | Tendsto (fun x_1 => birkhoffAverage 𝕜 (⇑f) _root_.id x_1 x) atTop (𝓝 0)}
x : E
n : ℕ
H : (⇑f)^[n] 0 = 0
⊢ ‖_root_.id ((⇑f)^[n] x)‖ ≤ ‖x‖

Tactic:
simpa [H] using (hf.iterate n).dist_le_mul x 0

Result:
no goals

Proof state:
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
x : E
⊢ g (x - ↑(g x)) = 0

Tactic:
simp [hg_proj]

Result:
no goals

Proof state:
case intro.intro.intro.intro
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
y : E
hy : g y = 0
z : E
hz : IsFixedPt (⇑f) z
this✝ : IsClosed {x | Tendsto (fun x_1 => birkhoffAverage 𝕜 (⇑f) _root_.id x_1 x) atTop (𝓝 0)}
x : E
this : Bornology.IsBounded (Set.range fun x_1 => _root_.id ((⇑f)^[x_1] x))
⊢ (f - 1) x ∈ {x | Tendsto (fun x_1 => birkhoffAverage 𝕜 (⇑f) _root_.id x_1 x) atTop (𝓝 0)}

Tactic:
have H : ∀ n x y, f^[n] (x - y) = f^[n] x - f^[n] y := iterate_map_sub (f : E →+ E)

Result:
case intro.intro.intro.intro
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
y : E
hy : g y = 0
z : E
hz : IsFixedPt (⇑f) z
this✝ : IsClosed {x | Tendsto (fun x_1 => birkhoffAverage 𝕜 (⇑f) _root_.id x_1 x) atTop (𝓝 0)}
x : E
this : Bornology.IsBounded (Set.range fun x_1 => _root_.id ((⇑f)^[x_1] x))
H : ∀ (n : ℕ) (x y : E), (⇑f)^[n] (x - y) = (⇑f)^[n] x - (⇑f)^[n] y
⊢ (f - 1) x ∈ {x | Tendsto (fun x_1 => birkhoffAverage 𝕜 (⇑f) _root_.id x_1 x) atTop (𝓝 0)}

Proof state:
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
y : E
hy : g y = 0
z : E
hz : IsFixedPt (⇑f) z
this : IsClosed {x | Tendsto (fun x_1 => birkhoffAverage 𝕜 (⇑f) _root_.id x_1 x) atTop (𝓝 0)}
x : E
n : ℕ
⊢ ‖_root_.id ((⇑f)^[n] x)‖ ≤ ‖x‖

Tactic:
have H : f^[n] 0 = 0 := iterate_map_zero (f : E →+ E) n

Result:
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
y : E
hy : g y = 0
z : E
hz : IsFixedPt (⇑f) z
this : IsClosed {x | Tendsto (fun x_1 => birkhoffAverage 𝕜 (⇑f) _root_.id x_1 x) atTop (𝓝 0)}
x : E
n : ℕ
H : (⇑f)^[n] 0 = 0
⊢ ‖_root_.id ((⇑f)^[n] x)‖ ≤ ‖x‖

Proof state:
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
x : E
⊢ Tendsto (fun x_1 => birkhoffAverage 𝕜 (⇑f) _root_.id x_1 x) atTop (𝓝 ↑(g x))

Tactic:
obtain ⟨y, hy, z, hz, rfl⟩ : ∃ y, g y = 0 ∧ ∃ z, IsFixedPt f z ∧ x = y + z :=
  ⟨x - g x, by simp [hg_proj], g x, (g x).2, by simp⟩

Result:
case intro.intro.intro.intro
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
y : E
hy : g y = 0
z : E
hz : IsFixedPt (⇑f) z
⊢ Tendsto (fun x => birkhoffAverage 𝕜 (⇑f) _root_.id x (y + z)) atTop (𝓝 ↑(g (y + z)))

Proof state:
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
y : E
hy : g y = 0
z : E
hz : IsFixedPt (⇑f) z
this : Tendsto (fun x => birkhoffAverage 𝕜 (⇑f) _root_.id x y) atTop (𝓝 0)
⊢ Tendsto (fun x => birkhoffAverage 𝕜 (⇑f) _root_.id x (y + z)) atTop (𝓝 ↑(g (y + z)))

Tactic:
have hgz : g z = z := congr_arg Subtype.val (hg_proj ⟨z, hz⟩)

Result:
𝕜 : Type u_1
E : Type u_2
inst✝² : RCLike 𝕜
inst✝¹ : NormedAddCommGroup E
inst✝ : NormedSpace 𝕜 E
f : E →ₗ[𝕜] E
hf : LipschitzWith 1 ⇑f
g : E →L[𝕜] ↥(eqLocus f 1)
hg_proj : ∀ (x : ↥(eqLocus f 1)), g ↑x = x
hg_ker : ↑(ker g) ⊆ closure ↑(range (f - 1))
y : E
hy : g y = 0
z : E
hz : IsFixedPt (⇑f) z
this : Tendsto (fun x => birkhoffAverage 𝕜 (⇑f) _root_.id x y) atTop (𝓝 0)
hgz : ↑(g z) = z
⊢ Tendsto (fun x => birkhoffAverage 𝕜 (⇑f) _root_.id x (y + z)) atTop (𝓝 ↑(g (y + z)))