Repository: ImperialCollegeLondon/FLT
Pull request #525: Fujisaki: Proofs of X_meets_kernel and X_meets_kernel'
Author: login: WilliamCoram
Labels: name: awaiting-author
Created: 2025-05-20T15:08:58Z | Merged: 2025-05-21T17:36:12Z

Complete proofs of X_meets_kernel and X_meets_kernel'. Not golfed as nicely as the last proofs unfortunately.
These required an addition of $$e_1 \neq e_2$$ in the existsE statement, and an addition of a lemma E_noninjective_right.

Does this seem like reasonable adjustments? I think proving E_noninjective_right should follow from 9.25 in blueprint and E_noninjective_left (renaming of prev E_noninjective).

I also have a T_finite proof modulo some sorry's. Feel free to delay merging until I finish them, it requires the discrete statements I mentioned.


Diff:
diff --git a/FLT/DivisionAlgebra/Finiteness.lean b/FLT/DivisionAlgebra/Finiteness.lean
index 2c1e797c7..db9471fab 100644
--- a/FLT/DivisionAlgebra/Finiteness.lean
+++ b/FLT/DivisionAlgebra/Finiteness.lean
@@ -64,9 +64,8 @@ noncomputable abbrev incl : Dˣ →* D_𝔸ˣ :=
 namespace Aux
 
 lemma existsE : ∃ E : Set (D_𝔸), IsCompact E ∧
-    ∀ x ∈ ringHaarChar_ker D_𝔸,
-    ∃ e₁ ∈ E, ∃ e₂ ∈ E,
-    x * e₁ - x * e₂ ∈ Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸) :=
+    ∀ φ : D_𝔸 ≃ₜ+ D_𝔸, addEquivAddHaarChar φ = 1 → ∃ e₁ ∈ E, ∃ e₂ ∈ E,
+    e₁ ≠ e₂ ∧ φ e₁ - φ e₂ ∈ Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸) :=
   sorry
 
 /-- An auxiliary set E used in the proof of Fukisaki's lemma. -/
@@ -74,10 +73,17 @@ def E : Set D_𝔸 := (existsE K D).choose
 
 lemma E_compact : IsCompact (E K D) := (existsE K D).choose_spec.1
 
-lemma E_noninjective : ∀ x ∈ ringHaarChar_ker D_𝔸,
-    ∃ e₁ ∈ E K D, ∃ e₂ ∈ E K D,
+lemma E_noninjective_left {x : D_𝔸ˣ} (h : x ∈ ringHaarChar_ker D_𝔸) :
+    ∃ e₁ ∈ E K D, ∃ e₂ ∈ E K D, e₁ ≠ e₂ ∧
     x * e₁ - x * e₂ ∈ Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸) :=
-  (existsE K D).choose_spec.2
+  (existsE K D).choose_spec.2 (ContinuousAddEquiv.mulLeft x) h
+
+lemma E_noninjective_right {x : D_𝔸ˣ} (h : x ∈ ringHaarChar_ker D_𝔸) :
+    ∃ e₁ ∈ E K D, ∃ e₂ ∈ E K D, e₁ ≠ e₂ ∧
+    e₁ * x⁻¹ - e₂ * x⁻¹  ∈ Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸) := by
+  let φ : D_𝔸 ≃ₜ+ D_𝔸 := ContinuousAddEquiv.mulRight x⁻¹
+  have hφ : addEquivAddHaarChar φ = 1 := sorry
+  exact (existsE K D).choose_spec.2 φ hφ
 
 open scoped Pointwise in
 /-- An auxiliary set X used in the proof of Fukisaki's lemma. Defined as E - E. -/
@@ -96,16 +102,52 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D hβ
+  refine ⟨e1 - e2, by simpa only using (Set.sub_mem_sub he1 he2), ?_⟩
+  obtain ⟨b1, rfl⟩ : IsUnit b := by
+    simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+    have h1 : ↑β * (e1 - e2) ≠ 0 := by
+      simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+    simp only [isUnit_iff_ne_zero, ne_eq]
+    rintro rfl
+    simp only [← hb, TensorProduct.zero_tmul, ne_eq, not_true_eq_false] at h1
+  exact ⟨incl K D b1, ⟨b1, rfl⟩, by simpa [mul_sub] using hb.symm⟩
 
 lemma X_meets_kernel' {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), x * β⁻¹ = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), x * β⁻¹ = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_right K D hβ
+  refine ⟨e1 - e2, by simpa only using (Set.sub_mem_sub he1 he2), ?_⟩
+  obtain ⟨b1, rfl⟩ : IsUnit b := by
+    simp_rw [← mul_sub_right_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+    have h1 : (e1 - e2) * ↑β⁻¹ ≠ 0 := by
+      simpa only [ne_eq, Units.mul_left_eq_zero] using (sub_ne_zero_of_ne noteq)
+    simp only [isUnit_iff_ne_zero, ne_eq]
+    rintro rfl
+    simp only [← hb, TensorProduct.zero_tmul, ne_eq, not_true_eq_false] at h1
+  exact ⟨incl K D b1, ⟨b1, rfl⟩, by simpa [sub_mul] using hb.symm⟩
 
 /-- An auxiliary set T used in the proof of Fukisaki's lemma. Defined as Y ∩ Dˣ. -/
 def T : Set D_𝔸ˣ := ((↑) : D_𝔸ˣ → D_𝔸) ⁻¹' (Y K D) ∩ Set.range ((incl K D : Dˣ → D_𝔸ˣ))
 
-lemma T_finite : Set.Finite (T K D) :=
-  sorry
+-- Need something saying D ⊆ D_𝔸 is discrete
+
+lemma T_finite : Set.Finite (T K D) := by
+  have h : Set.Finite ((Y K D) ∩ (Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸)))
+      := by
+    apply IsCompact.finite
+    · refine IsCompact.inter_right (Y_compact K D) ?_
+
+      -- Subgroup.isClosed_of_discrete
+      sorry
+    · -- follows form D being discrete
+
+      sorry
+  have h1 : Units.val '' T K D ⊆ (Y K D) ∩
+      (Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸)) := by
+    rintro _ ⟨t, ⟨ht1, d, rfl⟩, rfl⟩
+    exact ⟨ht1, d, rfl⟩
+  exact Set.Finite.of_finite_image (Set.Finite.subset h h1) (Function.Injective.injOn Units.ext)
 
 open scoped Pointwise in
 /-- An auxiliary set C used in the proof of Fukisaki's lemma. Defined as T⁻¹X × X. -/
@@ -182,7 +224,7 @@ of `(D ⊗ 𝔸_F^infty)ˣ`.
 -/
 theorem NumberField.FiniteAdeleRing.DivisionAlgebra.finiteDoubleCoset
     {U : Subgroup (Dfx K D)} (hU : IsOpen (U : Set (Dfx K D))) :
-    Finite (Doset.Quotient (Set.range (incl₁ K D)) U) :=
+    Finite (Doset.Quotient (Set.range (incl₁ K D)) U) := by
   sorry
 
 end FiniteAdeleRing
diff --git a/blueprint/src/chapter/FujisakiProject.tex b/blueprint/src/chapter/FujisakiProject.tex
index c841c41e6..47b77f45e 100644
--- a/blueprint/src/chapter/FujisakiProject.tex
+++ b/blueprint/src/chapter/FujisakiProject.tex
@@ -158,6 +158,7 @@ \section{The proof}
   $X$ is a compact subset of $D_{\A}$.
 \end{lemma}
 \begin{proof}
+  \leanok
   It's the continuous image of the compact set~$E\times E$.
 \end{proof}
 
@@ -169,6 +170,7 @@ \section{The proof}
   $Y$ is a compact subset of $D_{\A}$.
 \end{lemma}
 \begin{proof}
+  \leanok
   It's the continuous image of the compact set~$X\times X$.
 \end{proof}
 
@@ -182,6 +184,7 @@ \section{The proof}
 $\beta X\cap D^\times\not=\emptyset$.
 \end{lemma}
 \begin{proof}
+  \leanok
 Indeed by lemma~\ref{NumberField.AdeleRing.DivisionAlgebra.Aux.existsE},
 the map $\beta E\to D\backslash D_{\A}$
 isn't injective, so there are distinct
@@ -200,6 +203,7 @@ \section{The proof}
   $X\beta^{-1}\cap D^\times\not=\emptyset$.
 \end{lemma}
 \begin{proof}
+  \leanok
   % TODO does this make the lines dottted? I used E in the proof here
   \uses{NumberField.AdeleRing.DivisionAlgebra.Aux.E}%, addHaarScalarFactor.left_mul_eq_right_mul}
   Indeed, $\beta^{-1}\in D_{\A}^{(1)}$, and so left multiplication by $\beta^{-1}$
@@ -253,6 +257,7 @@ \section{The proof}
   $C$ is compact.
 \end{lemma}
 \begin{proof}
+  \leanok
    $X$ is compact and $T$ is finite.
 \end{proof}
 


Reviews:
user: login: kbuzzard
body: Thanks a lot! I've left some hopefully helpful comments.
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-20T21:05:18Z
user: login: WilliamCoram
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:41:23Z
user: login: WilliamCoram
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:42:07Z
user: login: WilliamCoram
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:48:06Z
user: login: WilliamCoram
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:49:19Z
user: login: kbuzzard
body: Thanks a lot!
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-21T17:33:27Z
user: login: kbuzzard
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-21T17:35:32Z

Review comments:
diff_hunk: @@ -63,22 +63,25 @@ noncomputable abbrev incl : Dˣ →* D_𝔸ˣ :=
 
 namespace Aux
 
-lemma existsE : ∃ E : Set (D_𝔸), IsCompact E ∧
-    ∀ x ∈ ringHaarChar_ker D_𝔸,
-    ∃ e₁ ∈ E, ∃ e₂ ∈ E,
-    x * e₁ - x * e₂ ∈ Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸) :=
+lemma existsE : ∃ E : Set (D_𝔸), IsCompact E ∧ ∀ x ∈ ringHaarChar_ker D_𝔸, ∃ e₁ ∈ E, ∃ e₂ ∈ E,
+    e₁ ≠ e₂ ∧ x * e₁ - x * e₂ ∈ Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸) :=
   sorry
 
 /-- An auxiliary set E used in the proof of Fukisaki's lemma. -/
 def E : Set D_𝔸 := (existsE K D).choose
 
 lemma E_compact : IsCompact (E K D) := (existsE K D).choose_spec.1
 
-lemma E_noninjective : ∀ x ∈ ringHaarChar_ker D_𝔸,
-    ∃ e₁ ∈ E K D, ∃ e₂ ∈ E K D,
+lemma E_noninjective_left : ∀ x ∈ ringHaarChar_ker D_𝔸,
+    ∃ e₁ ∈ E K D, ∃ e₂ ∈ E K D, e₁ ≠ e₂ ∧
     x * e₁ - x * e₂ ∈ Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸) :=
   (existsE K D).choose_spec.2
 
+lemma E_noninjective_right : ∀ x ∈ ringHaarChar_ker D_𝔸,
+    ∃ e₁ ∈ E K D, ∃ e₂ ∈ E K D, e₁ ≠ e₂ ∧
+    e₁ * x⁻¹ - e₂ * x⁻¹  ∈ Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸) := by
+  sorry
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: kbuzzard
body: I don't think we can do it like this. The only thing we will know about E is what we have claimed in existsE and I don't think E_noninjective_left and compactness (the only hypotheses you have on E) implies E_noninjective_right. I think this will work (I write down exactly what it is that we can prove about E, and deduce what you need from it, modulo a sorry which I'm currently working on).

```lean
lemma existsE : ∃ E : Set (D_𝔸), IsCompact E ∧
    ∀ φ : D_𝔸 ≃ₜ+ D_𝔸, addEquivAddHaarChar φ = 1 → ∃ e₁ ∈ E, ∃ e₂ ∈ E,
    e₁ ≠ e₂ ∧ φ e₁ - φ e₂ ∈ Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸) :=
  sorry

/-- An auxiliary set E used in the proof of Fukisaki's lemma. -/
def E : Set D_𝔸 := (existsE K D).choose

lemma E_compact : IsCompact (E K D) := (existsE K D).choose_spec.1

lemma E_noninjective_left {x : D_𝔸ˣ} (h : x ∈ ringHaarChar_ker D_𝔸) :
    ∃ e₁ ∈ E K D, ∃ e₂ ∈ E K D, e₁ ≠ e₂ ∧
    x * e₁ - x * e₂ ∈ Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸) :=
  (existsE K D).choose_spec.2 (ContinuousAddEquiv.mulLeft x) h

lemma E_noninjective_right {x : D_𝔸ˣ} (h : x ∈ ringHaarChar_ker D_𝔸) :
    ∃ e₁ ∈ E K D, ∃ e₂ ∈ E K D, e₁ ≠ e₂ ∧
    e₁ * x⁻¹ - e₂ * x⁻¹  ∈ Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸) := by
  let φ : D_𝔸 ≃ₜ+ D_𝔸 := ContinuousAddEquiv.mulRight x⁻¹
  have hφ : addEquivAddHaarChar φ = 1 := sorry
  exact (existsE K D).choose_spec.2 φ hφ
```

I am currently working on Haar characters but unfortunately I am just a day or two short of stating the lemmas from the Haar character project which will fill in the sorry in `E_noninjective_right`. The idea is that in the Haar character project I prove that left and right multiplication scale Haar measure by the same factor.
created_at: 2025-05-20T20:18:02Z
author_association: COLLABORATOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: kbuzzard
body: If you go with my suggestion about E then you can delete the beta here, I made it implicit when I moved it left of the colon.
created_at: 2025-05-20T20:20:30Z
author_association: COLLABORATOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: kbuzzard
body: ```suggestion
  refine ⟨e1 - e2, by simpa only using (Set.sub_mem_sub he1 he2), ?_⟩
```
(and then remove the . and unindent everything). This is exactly the same as what you wrote but saves the indentation.
created_at: 2025-05-20T20:21:56Z
author_association: COLLABORATOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : ↑β * (e1 - e2) ≠ 0 := by
+        simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: kbuzzard
body: ```suggestion
    rintro rfl
    simp [← hb] at h1
```
Your goal at this point is `¬b = 0`, which by definition means `b = 0 -> False`, so `rintro rfl` defines `b` to be `0` (and replaces `b` by `0` everywhere in the tactic state) and leaves us with a goal of `False`. Now after this substitution, `hb` has become (something which simp can show is 0) = (the thing which h1 tells us isn't zero) so there's the contradiction.
created_at: 2025-05-20T20:29:55Z
author_association: COLLABORATOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : ↑β * (e1 - e2) ≠ 0 := by
+        simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: kbuzzard
body: If that's all you wanted to do with `IsUnit b` then you could have written
```
  obtain ⟨b1, hb1⟩ : IsUnit b := by
```
instead of `have : IsUnit b` earlier, and then you wouldn't need this line. In fact `hb1` just says `↑b1 = b` so even better would be
```
  obtain ⟨b1, rfl⟩ : IsUnit b := by
```
which will then replace `b` by `↑b1` everywhere.
created_at: 2025-05-20T20:31:49Z
author_association: COLLABORATOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : ↑β * (e1 - e2) ≠ 0 := by
+        simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_left_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: kbuzzard
body: ```suggestion
  exact ⟨incl K D b1, ⟨b1, rfl⟩, by simpa [mul_sub] using hb.symm⟩
```
You're using `simp` to close the goal, you only use `hb` once and it's backwards, so you can just build the term you want easily and let `simp` do all the heavy lifting instead of explicitly writing all those lemmas.
created_at: 2025-05-20T20:38:37Z
author_association: COLLABORATOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : ↑β * (e1 - e2) ≠ 0 := by
+        simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_left_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
 
 lemma X_meets_kernel' {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), x * β⁻¹ = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), x * β⁻¹ = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_right K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_right_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : (e1 - e2) * ↑β⁻¹ ≠ 0 := by
+        simpa only [ne_eq, Units.mul_left_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_right_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: kbuzzard
body: See if you can use the same tricks to tidy up this one.
created_at: 2025-05-20T20:39:07Z
author_association: COLLABORATOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : ↑β * (e1 - e2) ≠ 0 := by
+        simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_left_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
 
 lemma X_meets_kernel' {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), x * β⁻¹ = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), x * β⁻¹ = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_right K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_right_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : (e1 - e2) * ↑β⁻¹ ≠ 0 := by
+        simpa only [ne_eq, Units.mul_left_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_right_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
 
 /-- An auxiliary set T used in the proof of Fukisaki's lemma. Defined as Y ∩ Dˣ. -/
 def T : Set D_𝔸ˣ := ((↑) : D_𝔸ˣ → D_𝔸) ⁻¹' (Y K D) ∩ Set.range ((incl K D : Dˣ → D_𝔸ˣ))
 
-lemma T_finite : Set.Finite (T K D) :=
-  sorry
+-- Need something saying D ⊆ D_𝔸 is discrete
+
+lemma T_finite : Set.Finite (T K D) := by
+  have h : Set.Finite ((Y K D) ∩ (Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸)))
+      := by
+    apply IsCompact.finite
+    · refine IsCompact.inter_right (Y_compact K D) ?_
+
+      -- Subgroup.isClosed_of_discrete
+      sorry
+    · -- follows form D being discrete
+
+      sorry
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: kbuzzard
body: These sorries look fine, happy to leave them for now. I will be back on adeles in a few days and we can talk about them then. The idea would be to deduce them from the analogous statements for K in A_K.
created_at: 2025-05-20T20:41:22Z
author_association: COLLABORATOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : ↑β * (e1 - e2) ≠ 0 := by
+        simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_left_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
 
 lemma X_meets_kernel' {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), x * β⁻¹ = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), x * β⁻¹ = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_right K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_right_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : (e1 - e2) * ↑β⁻¹ ≠ 0 := by
+        simpa only [ne_eq, Units.mul_left_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_right_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
 
 /-- An auxiliary set T used in the proof of Fukisaki's lemma. Defined as Y ∩ Dˣ. -/
 def T : Set D_𝔸ˣ := ((↑) : D_𝔸ˣ → D_𝔸) ⁻¹' (Y K D) ∩ Set.range ((incl K D : Dˣ → D_𝔸ˣ))
 
-lemma T_finite : Set.Finite (T K D) :=
-  sorry
+-- Need something saying D ⊆ D_𝔸 is discrete
+
+lemma T_finite : Set.Finite (T K D) := by
+  have h : Set.Finite ((Y K D) ∩ (Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸)))
+      := by
+    apply IsCompact.finite
+    · refine IsCompact.inter_right (Y_compact K D) ?_
+
+      -- Subgroup.isClosed_of_discrete
+      sorry
+    · -- follows form D being discrete
+
+      sorry
+  have h1 : Units.val '' T K D ⊆ (Y K D) ∩
+      (Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸)) := by
+    simp only [Set.subset_inter_iff, Set.image_subset_iff]
+    constructor
+    · simp only [T, Set.inter_subset_left]
+    · refine Set.image_subset_iff.mp ?_
+      rw [T]
+      have h2 : Units.val '' (Set.range (incl K D : Dˣ → D_𝔸ˣ)) ⊆
+          (Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸)) := by
+        simp only [Set.image_subset_iff]
+        refine Set.range_subset_iff.mpr ?_
+        intro y
+        simp only [Set.mem_preimage, Units.coe_map, RingHom.toMonoidHom_eq_coe, MonoidHom.coe_coe,
+          Algebra.TensorProduct.includeLeftRingHom_apply, Set.mem_range,
+          Algebra.TensorProduct.includeLeft_apply, exists_apply_eq_apply]
+      simp only [Set.image_inter Units.ext]
+      exact (Set.Subset.trans Set.inter_subset_right h2)
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: kbuzzard
body: ```suggestion
    rintro _ ⟨t, ⟨ht1, d, rfl⟩, rfl⟩
    exact ⟨ht, d, rfl⟩
```
I didn't just write down this proof immediately, it took a little time to find, and I am using a lot of defeq abuse.
The goal is `Units.val '' T K D ⊆ Y K D ∩ Set.range ⇑Algebra.TensorProduct.includeLeft` and I know that *by definition of `⊆`* this means "for all x, if x is in the image of T then x is in Y and x is in the range of includeLeft"; the definitions in set theory in mathlib are all what you think they are. So I want to start with "intro x". Then I want to intro the hypothesis that x is in the image of T so in fact I want to start with `rintro x \<t, ht\>` with t being the thing which gets mapped to x. Now I'm looking at `ht` and I see it says `t \in T and ↑t = x` so I figure I can define x to be `↑t` and I change it to `rintro x ⟨t, ht, rfl⟩ ` (note that pointy brackets are right associative, this means `rintro x ⟨t, ⟨ht, rfl⟩⟩`) and now there's no point even naming x because I've just replaced it with `↑t` everywhere so I change it to `rintro _ ⟨t, ht, rfl⟩`. Now I look at `ht` and it says t is in T, and T is defined to be an intersection so this just says that t is in 2 things, so I can change ht to `⟨ht, ht'⟩`. Now ht' says that t is in the range of `incl` so by definition ht' says "there exists d in D^* such that incl d = t" so I can replace it by `⟨d, ht'⟩` and now `ht'` just says t = something so we can define t to be this something by using the rfl trick again. That gives us the first line.

We now have
```
d : Dˣ
ht : (incl K D) d ∈ Units.val ⁻¹' Y K D
⊢ ↑((incl K D) d) ∈ Y K D ∩ Set.range ⇑Algebra.TensorProduct.includeLeft
```
and we need to write the next line. Well something being in an intersection just means it's in both things, by definition, so the goal is a pair, and the first element of the pair is ht *by definition of preimage* (because the up-arrow is Units.val) so we start with `refine ⟨ht, ?_⟩`. What's left is that we have to prove that incl d is in the range of something which is basically incl, so the goal is again a pair consisting of the thing which it's the image of (which is d again) and then the proof that it's the image, so the second line is now `refine ⟨ht, d, ?_⟩` and now I tried `rfl` on the goal and it worked.

So it's all about knowing the definitions of things behind the scenes, but once you know these tricks they'll save you a lot of time.

created_at: 2025-05-20T21:01:01Z
author_association: COLLABORATOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : ↑β * (e1 - e2) ≠ 0 := by
+        simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_left_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: WilliamCoram
body: Is it okay to just say `by simpa [mul_sub]`, or should I be using `by simpa?` to get the full ` simpa only [sub_mul, Units.coe_map,
    RingHom.toMonoidHom_eq_coe, MonoidHom.coe_coe, Algebra.TensorProduct.includeLeftRingHom_apply,
    Algebra.TensorProduct.includeLeft_apply] using hb.symm`?
created_at: 2025-05-21T12:41:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : ↑β * (e1 - e2) ≠ 0 := by
+        simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_left_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: WilliamCoram
body: The first certainly looks nicer, but I believed it was always better to change simps to simp only when possible
created_at: 2025-05-21T12:42:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : ↑β * (e1 - e2) ≠ 0 := by
+        simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_left_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
 
 lemma X_meets_kernel' {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), x * β⁻¹ = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), x * β⁻¹ = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_right K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_right_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : (e1 - e2) * ↑β⁻¹ ≠ 0 := by
+        simpa only [ne_eq, Units.mul_left_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_right_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
 
 /-- An auxiliary set T used in the proof of Fukisaki's lemma. Defined as Y ∩ Dˣ. -/
 def T : Set D_𝔸ˣ := ((↑) : D_𝔸ˣ → D_𝔸) ⁻¹' (Y K D) ∩ Set.range ((incl K D : Dˣ → D_𝔸ˣ))
 
-lemma T_finite : Set.Finite (T K D) :=
-  sorry
+-- Need something saying D ⊆ D_𝔸 is discrete
+
+lemma T_finite : Set.Finite (T K D) := by
+  have h : Set.Finite ((Y K D) ∩ (Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸)))
+      := by
+    apply IsCompact.finite
+    · refine IsCompact.inter_right (Y_compact K D) ?_
+
+      -- Subgroup.isClosed_of_discrete
+      sorry
+    · -- follows form D being discrete
+
+      sorry
+  have h1 : Units.val '' T K D ⊆ (Y K D) ∩
+      (Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸)) := by
+    simp only [Set.subset_inter_iff, Set.image_subset_iff]
+    constructor
+    · simp only [T, Set.inter_subset_left]
+    · refine Set.image_subset_iff.mp ?_
+      rw [T]
+      have h2 : Units.val '' (Set.range (incl K D : Dˣ → D_𝔸ˣ)) ⊆
+          (Set.range (Algebra.TensorProduct.includeLeft : D →ₐ[K] D_𝔸)) := by
+        simp only [Set.image_subset_iff]
+        refine Set.range_subset_iff.mpr ?_
+        intro y
+        simp only [Set.mem_preimage, Units.coe_map, RingHom.toMonoidHom_eq_coe, MonoidHom.coe_coe,
+          Algebra.TensorProduct.includeLeftRingHom_apply, Set.mem_range,
+          Algebra.TensorProduct.includeLeft_apply, exists_apply_eq_apply]
+      simp only [Set.image_inter Units.ext]
+      exact (Set.Subset.trans Set.inter_subset_right h2)
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: WilliamCoram
body: Thanks. I think this way of thinking of problems will help a lot in the future. I'm currently pretty bad at golfing down using definitions, this method is something I will practice more.
created_at: 2025-05-21T12:48:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : ↑β * (e1 - e2) ≠ 0 := by
+        simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: WilliamCoram
body: I did not know rintro rfl works like that. That is a good piece of information to know. Thanks!
created_at: 2025-05-21T12:49:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -96,16 +99,89 @@ lemma Y_compact : IsCompact (Y K D) := by
     ((X_compact K D).prod (X_compact K D)) ((continuous_fst.mul continuous_snd).continuousOn))
 
 lemma X_meets_kernel {β : D_𝔸ˣ} (hβ : β ∈ ringHaarChar_ker D_𝔸) :
-    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := sorry
+    ∃ x ∈ X K D, ∃ d ∈ Set.range (incl K D : Dˣ → D_𝔸ˣ), β * x = d := by
+  obtain ⟨e1, he1, e2, he2, noteq, b, hb⟩ := E_noninjective_left K D β hβ
+  use (e1 - e2)
+  constructor
+  · simpa only using (Set.sub_mem_sub he1 he2)
+  · have : IsUnit b := by
+      simp_rw [← mul_sub_left_distrib, Algebra.TensorProduct.includeLeft_apply] at hb
+      have h1 : ↑β * (e1 - e2) ≠ 0 := by
+        simpa only [ne_eq, not_not, Units.mul_right_eq_zero] using (sub_ne_zero_of_ne noteq)
+      simp only [isUnit_iff_ne_zero, ne_eq]
+      have h2 : b ⊗ₜ[K] (1 : AdeleRing (𝓞 K) K) ≠ 0 → b ≠ 0 := by
+        intro h
+        contrapose h
+        simp only [ne_eq, not_not] at h ⊢
+        simp only [h, TensorProduct.zero_tmul]
+      simpa only [ne_eq] using h2 (Ne.symm (Lean.Grind.ne_of_ne_of_eq_right hb (id (Ne.symm h1))))
+    obtain ⟨b1 , hb1⟩ := this
+    simp only [Set.mem_range, exists_exists_eq_and, Units.coe_map, RingHom.toMonoidHom_eq_coe,
+      MonoidHom.coe_coe]
+    use b1
+    simp only [mul_sub_left_distrib, (Eq.symm hb), Algebra.TensorProduct.includeLeft_apply, hb1,
+      Algebra.TensorProduct.includeLeftRingHom_apply]
path: FLT/DivisionAlgebra/Finiteness.lean
user: login: kbuzzard
body: No no no, the rule is "change `simp` to `simp only` in one of the following two situations: (1) it's not the last line of a proof (2) `simp` is visibly slow and `simp only` is much quicker". Here `simp` is quick and you're closing a goal so `simp` is fine.
created_at: 2025-05-21T17:35:32Z
author_association: COLLABORATOR

PR comments:
user: login: kbuzzard
created_at: 2025-05-20T16:26:20Z
body: Can you add `\leanok` to the corresponding proofs in the blueprint? Right now the graph https://imperialcollegelondon.github.io/FLT/blueprint/dep_graph_chapter_10.html says you've done nothing; if you put `\leanok` just after `\begin{proof}` then it will turn the corresponding node from blue to green. The relevant file is `FLT/blueprint/src/chapter/FujisakiProject.tex`.
author_association: COLLABORATOR
user: login: pitmonticone
created_at: 2025-05-21T14:03:47Z
body: Hi @WilliamCoram, thank you very much for your PR!

For future contributions, could you please avoid working directly on your main `branch`, and instead use a dedicated feature branch for each PR?

This helps prevent potential issues with the CI pipeline, such as workflows being triggered unintentionally or conflicts arising from updates to `main`. It also makes it easier to manage multiple contributions in parallel and ensures a cleaner commit history.
author_association: COLLABORATOR
user: login: WilliamCoram
created_at: 2025-05-21T14:14:50Z
body: > Hi @WilliamCoram, thank you very much for your PR!
> 
> For future contributions, could you please avoid working directly on your main `branch`, and instead use a dedicated feature branch for each PR?
> 
> This helps prevent potential issues with the CI pipeline, such as workflows being triggered unintentionally or conflicts arising from updates to `main`. It also makes it easier to manage multiple contributions in parallel and ensures a cleaner commit history.

Sure, will do!
author_association: CONTRIBUTOR