Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 084f76e

Browse files
ocfnasheric-wieser
andcommitted
feat(analysis/normed/group/add_circle): results about finite-order points on the circle (#17321)
The main motivation for developing this API is the lemma `add_circle.le_add_order_smul_norm_of_is_of_fin_add_order` Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
1 parent 8709a59 commit 084f76e

5 files changed

Lines changed: 233 additions & 3 deletions

File tree

src/algebra/order/floor.lean

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,45 @@ sub_nonneg_of_le $ (le_div_iff hb).1 $ floor_le _
678678
lemma sub_floor_div_mul_lt (a : k) (hb : 0 < b) : a - ⌊a / b⌋ * b < b :=
679679
sub_lt_iff_lt_add.2 $ by { rw [←one_add_mul, ←div_lt_iff hb, add_comm], exact lt_floor_add_one _ }
680680

681+
lemma fract_div_nat_cast_eq_div_nat_cast_mod {m n : ℕ} :
682+
fract ((m : k) / n) = ↑(m % n) / n :=
683+
begin
684+
rcases n.eq_zero_or_pos with rfl | hn, { simp, },
685+
have hn' : 0 < (n : k), { norm_cast, assumption, },
686+
refine fract_eq_iff.mpr ⟨by positivity, _, m / n, _⟩,
687+
{ simpa only [div_lt_one hn', nat.cast_lt] using m.mod_lt hn, },
688+
{ rw [sub_eq_iff_eq_add', ← mul_right_inj' hn'.ne.symm, mul_div_cancel' _ hn'.ne.symm, mul_add,
689+
mul_div_cancel' _ hn'.ne.symm],
690+
norm_cast,
691+
rw [← nat.cast_add, nat.mod_add_div m n], },
692+
end
693+
694+
-- TODO Generalise this to allow `n : ℤ` using `int.fmod` instead of `int.mod`.
695+
lemma fract_div_int_cast_eq_div_int_cast_mod {m : ℤ} {n : ℕ} :
696+
fract ((m : k) / n) = ↑(m % n) / n :=
697+
begin
698+
rcases n.eq_zero_or_pos with rfl | hn, { simp, },
699+
replace hn : 0 < (n : k), { norm_cast, assumption, },
700+
have : ∀ {l : ℤ} (hl : 0 ≤ l), fract ((l : k) / n) = ↑(l % n) / n,
701+
{ intros,
702+
obtain ⟨l₀, rfl | rfl⟩ := l.eq_coe_or_neg,
703+
{ rw [cast_coe_nat, ← coe_nat_mod, cast_coe_nat, fract_div_nat_cast_eq_div_nat_cast_mod], },
704+
{ rw [right.nonneg_neg_iff, coe_nat_nonpos_iff] at hl, simp [hl, zero_mod], }, },
705+
obtain ⟨m₀, rfl | rfl⟩ := m.eq_coe_or_neg, { exact this (of_nat_nonneg m₀), },
706+
let q := ⌈↑m₀ / (n : k)⌉,
707+
let m₁ := (q * ↑n) -(↑m₀ : ℤ),
708+
have hm₁ : 0 ≤ m₁, { simpa [←@cast_le k, ←div_le_iff hn] using floor_ring.gc_ceil_coe.le_u_l _, },
709+
calc fract (↑-↑m₀ / ↑n) = fract (-(m₀ : k) / n) : by rw [coe_neg, cast_coe_nat]
710+
... = fract ((m₁ : k) / n) : _
711+
... = ↑(m₁ % (n : ℤ)) / ↑n : this hm₁
712+
... = ↑(-(↑m₀ : ℤ) % ↑n) / ↑n : _,
713+
{ rw [← fract_int_add q, ← mul_div_cancel (q : k) (ne_of_gt hn), ← add_div, ← sub_eq_add_neg,
714+
coe_sub, coe_mul, cast_coe_nat, cast_coe_nat], },
715+
{ congr' 2,
716+
change ((q * ↑n) -(↑m₀ : ℤ)) % ↑n = _,
717+
rw [sub_eq_add_neg, add_comm (q * ↑n), add_mul_mod_self], },
718+
end
719+
681720
end linear_ordered_field
682721

683722
/-! #### Ceil -/
@@ -925,6 +964,16 @@ begin
925964
split; linarith
926965
end
927966

967+
lemma abs_sub_round_div_nat_cast_eq {m n : ℕ} :
968+
|(m : α) / n - round ((m : α) / n)| = ↑(min (m % n) (n - m % n)) / n :=
969+
begin
970+
rcases n.eq_zero_or_pos with rfl | hn, { simp, },
971+
have hn' : 0 < (n : α), { norm_cast, assumption, },
972+
rw [abs_sub_round_eq_min, nat.cast_min, ← min_div_div_right hn'.le,
973+
fract_div_nat_cast_eq_div_nat_cast_mod, nat.cast_sub (m.mod_lt hn).le, sub_div,
974+
div_self hn'.ne.symm],
975+
end
976+
928977
end linear_ordered_field
929978

930979
end round

src/analysis/normed/group/add_circle.lean

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ begin
109109
simp, },
110110
end
111111

112+
lemma norm_eq' (hp : 0 < p) {x : ℝ} :
113+
‖(x : add_circle p)‖ = p * |(p⁻¹ * x) - round (p⁻¹ * x)| :=
114+
begin
115+
conv_rhs { congr, rw ← abs_eq_self.mpr hp.le, },
116+
rw [← abs_mul, mul_sub, mul_inv_cancel_left₀ hp.ne.symm, norm_eq, mul_comm p],
117+
end
118+
112119
lemma norm_le_half_period {x : add_circle p} (hp : p ≠ 0) : ‖x‖ ≤ |p|/2 :=
113120
begin
114121
obtain ⟨x⟩ := x,
@@ -211,6 +218,43 @@ begin
211218
linarith [abs_eq_neg_self.mpr hp.le] } } },
212219
end
213220

221+
section finite_order_points
222+
223+
variables {p} [hp : fact (0 < p)]
224+
include hp
225+
226+
lemma norm_div_nat_cast {m n : ℕ} :
227+
‖(↑((↑m / ↑n) * p) : add_circle p)‖ = p * (↑(min (m % n) (n - m % n)) / n) :=
228+
begin
229+
have : p⁻¹ * (↑m / ↑n * p) = ↑m / ↑n, { rw [mul_comm _ p, inv_mul_cancel_left₀ hp.out.ne.symm], },
230+
rw [norm_eq' p hp.out, this, abs_sub_round_div_nat_cast_eq],
231+
end
232+
233+
lemma exists_norm_eq_of_fin_add_order {u : add_circle p} (hu : is_of_fin_add_order u) :
234+
∃ (k : ℕ), ‖u‖ = p * (k / add_order_of u) :=
235+
begin
236+
let n := add_order_of u,
237+
change ∃ (k : ℕ), ‖u‖ = p * (k / n),
238+
obtain ⟨m, -, -, hm⟩ := exists_gcd_eq_one_of_is_of_fin_add_order hu,
239+
refine ⟨min (m % n) (n - m % n), _⟩,
240+
rw [← hm, norm_div_nat_cast],
241+
end
242+
243+
lemma le_add_order_smul_norm_of_is_of_fin_add_order
244+
{u : add_circle p} (hu : is_of_fin_add_order u) (hu' : u ≠ 0) :
245+
p ≤ add_order_of u • ‖u‖ :=
246+
begin
247+
obtain ⟨n, hn⟩ := exists_norm_eq_of_fin_add_order hu,
248+
replace hu : (add_order_of u : ℝ) ≠ 0, { norm_cast, exact (add_order_of_pos_iff.mpr hu).ne.symm },
249+
conv_lhs { rw ← mul_one p, },
250+
rw [hn, nsmul_eq_mul, ← mul_assoc, mul_comm _ p, mul_assoc, mul_div_cancel' _ hu,
251+
mul_le_mul_left hp.out, nat.one_le_cast, nat.one_le_iff_ne_zero],
252+
contrapose! hu',
253+
simpa only [hu', algebra_map.coe_zero, zero_div, mul_zero, norm_eq_zero] using hn,
254+
end
255+
256+
end finite_order_points
257+
214258
end add_circle
215259

216260
namespace unit_add_circle

src/data/nat/cast/field.lean

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ begin
3030
rw [nat.mul_div_cancel_left _ this.bot_lt, cast_mul, mul_div_cancel_left _ n_nonzero],
3131
end
3232

33+
lemma cast_div_div_div_cancel_right [field α] [char_zero α] {m n d : ℕ} (hn : d ∣ n) (hm : d ∣ m) :
34+
(↑(m / d) : α) / (↑(n / d) : α) = (m : α) / n :=
35+
begin
36+
rcases eq_or_ne d 0 with rfl | hd, { simp [zero_dvd_iff.mp hm], },
37+
replace hd : (d : α) ≠ 0, { norm_cast, assumption, },
38+
simp [hd, hm, hn, div_div_div_cancel_right _ hd],
39+
end
40+
3341
section linear_ordered_semifield
3442
variables [linear_ordered_semifield α]
3543

src/group_theory/subgroup/basic.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,6 +2605,9 @@ iff.rfl
26052605
@[simp] lemma zpow_mem_zpowers (g : G) (k : ℤ) : g^k ∈ zpowers g :=
26062606
mem_zpowers_iff.mpr ⟨k, rfl⟩
26072607

2608+
@[simp] lemma npow_mem_zpowers (g : G) (k : ℕ) : g^k ∈ zpowers g :=
2609+
(zpow_coe_nat g k) ▸ zpow_mem_zpowers g k
2610+
26082611
@[simp] lemma forall_zpowers {x : G} {p : zpowers x → Prop} :
26092612
(∀ g, p g) ↔ ∀ m : ℤ, p ⟨x ^ m, m, rfl⟩ :=
26102613
set.forall_subtype_range_iff
@@ -2641,6 +2644,7 @@ attribute [to_additive add_subgroup.range_zmultiples_hom] subgroup.range_zpowers
26412644
attribute [to_additive add_subgroup.zmultiples_subset] subgroup.zpowers_subset
26422645
attribute [to_additive add_subgroup.mem_zmultiples_iff] subgroup.mem_zpowers_iff
26432646
attribute [to_additive add_subgroup.zsmul_mem_zmultiples] subgroup.zpow_mem_zpowers
2647+
attribute [to_additive add_subgroup.nsmul_mem_zmultiples] subgroup.npow_mem_zpowers
26442648
attribute [to_additive add_subgroup.forall_zmultiples] subgroup.forall_zpowers
26452649
attribute [to_additive add_subgroup.forall_mem_zmultiples] subgroup.forall_mem_zpowers
26462650
attribute [to_additive add_subgroup.exists_zmultiples] subgroup.exists_zpowers

src/topology/instances/add_circle.lean

Lines changed: 128 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Oliver Nash
55
-/
66
import group_theory.divisible
7+
import group_theory.order_of_element
8+
import ring_theory.int.basic
79
import algebra.order.floor
810
import algebra.order.to_interval_mod
911
import topology.instances.real
@@ -22,6 +24,8 @@ See also `circle` and `real.angle`. For the normed group structure on `add_circ
2224
* `unit_add_circle`: the special case `ℝ ⧸ ℤ`
2325
* `add_circle.equiv_add_circle`: the rescaling equivalence `add_circle p ≃+ add_circle q`
2426
* `add_circle.equiv_Ico`: the natural equivalence `add_circle p ≃ Ico 0 p`
27+
* `add_circle.add_order_of_div_of_gcd_eq_one`: rational points have finite order
28+
* `add_circle.exists_gcd_eq_one_of_is_of_fin_add_order`: finite-order points are rational
2529
2630
## Implementation notes:
2731
@@ -38,7 +42,7 @@ the rational circle `add_circle (1 : ℚ)`, and so we set things up more general
3842

3943
noncomputable theory
4044

41-
open set int (hiding mem_zmultiples_iff) add_subgroup topological_space
45+
open set add_subgroup topological_space
4246

4347
variables {𝕜 : Type*}
4448

@@ -54,6 +58,26 @@ section linear_ordered_field
5458

5559
variables [linear_ordered_field 𝕜] [topological_space 𝕜] [order_topology 𝕜] (p q : 𝕜)
5660

61+
instance : coe_is_add_monoid_hom 𝕜 (add_circle p) :=
62+
{ coe_zero := rfl,
63+
coe_add := λ x y, rfl }
64+
65+
lemma coe_eq_zero_iff {x : 𝕜} : (x : add_circle p) = 0 ↔ ∃ (n : ℤ), n • p = x :=
66+
by simp [add_subgroup.mem_zmultiples_iff]
67+
68+
lemma coe_eq_zero_of_pos_iff (hp : 0 < p) {x : 𝕜} (hx : 0 < x) :
69+
(x : add_circle p) = 0 ↔ ∃ (n : ℕ), n • p = x :=
70+
begin
71+
rw coe_eq_zero_iff,
72+
split;
73+
rintros ⟨n, rfl⟩,
74+
{ replace hx : 0 < n,
75+
{ contrapose! hx,
76+
simpa only [←neg_nonneg, ←zsmul_neg, zsmul_neg'] using zsmul_nonneg hp.le (neg_nonneg.2 hx) },
77+
exact ⟨n.to_nat, by rw [← coe_nat_zsmul, int.to_nat_of_nonneg hx.le]⟩, },
78+
{ exact ⟨(n : ℤ), by simp⟩, },
79+
end
80+
5781
@[continuity, nolint unused_arguments] protected lemma continuous_mk' :
5882
continuous (quotient_add_group.mk' (zmultiples p) : 𝕜 → add_circle p) :=
5983
continuous_coinduced_rng
@@ -80,9 +104,13 @@ rfl
80104
(equiv_add_circle p q hp hq).symm (x : 𝕜) = (x * (q⁻¹ * p) : 𝕜) :=
81105
rfl
82106

83-
variables [floor_ring 𝕜] [hp : fact (0 < p)]
107+
variables [hp : fact (0 < p)]
84108
include hp
85109

110+
section floor_ring
111+
112+
variables [floor_ring 𝕜]
113+
86114
/-- The natural equivalence between `add_circle p` and the half-open interval `[0, p)`. -/
87115
def equiv_Ico : add_circle p ≃ Ico 0 p :=
88116
{ inv_fun := quotient_add_group.mk' _ ∘ coe,
@@ -98,7 +126,7 @@ def equiv_Ico : add_circle p ≃ Ico 0 p :=
98126
end }
99127

100128
@[simp] lemma coe_equiv_Ico_mk_apply (x : 𝕜) :
101-
(equiv_Ico p $ quotient_add_group.mk x : 𝕜) = fract (x / p) * p :=
129+
(equiv_Ico p $ quotient_add_group.mk x : 𝕜) = int.fract (x / p) * p :=
102130
to_Ico_mod_eq_fract_mul _ x
103131

104132
@[continuity] lemma continuous_equiv_Ico_symm : continuous (equiv_Ico p).symm :=
@@ -126,6 +154,103 @@ instance : divisible_by (add_circle p) ℤ :=
126154
exact (equiv_Ico p).symm_apply_apply x,
127155
end, }
128156

157+
end floor_ring
158+
159+
section finite_order_points
160+
161+
variables {p}
162+
163+
lemma add_order_of_div_of_gcd_eq_one {m n : ℕ} (hn : 0 < n) (h : gcd m n = 1) :
164+
add_order_of (↑(↑m / ↑n * p) : add_circle p) = n :=
165+
begin
166+
rcases m.eq_zero_or_pos with rfl | hm, { rw [gcd_zero_left, normalize_eq] at h, simp [h], },
167+
set x : add_circle p := ↑(↑m / ↑n * p),
168+
have hn₀ : (n : 𝕜) ≠ 0, { norm_cast, exact ne_of_gt hn, },
169+
have hnx : n • x = 0,
170+
{ rw [← _root_.coe_nsmul, nsmul_eq_mul, ← mul_assoc, mul_div, mul_div_cancel_left _ hn₀,
171+
← nsmul_eq_mul, quotient_add_group.eq_zero_iff],
172+
exact nsmul_mem_zmultiples p m, },
173+
apply nat.dvd_antisymm (add_order_of_dvd_of_nsmul_eq_zero hnx),
174+
suffices : ∃ (z : ℕ), z * n = (add_order_of x) * m,
175+
{ obtain ⟨z, hz⟩ := this,
176+
simpa only [h, mul_one, gcd_comm n] using dvd_mul_gcd_of_dvd_mul (dvd.intro_left z hz), },
177+
replace hp := hp.out,
178+
have : 0 < add_order_of x • (↑m / ↑n * p) := smul_pos
179+
(add_order_of_pos' $ (is_of_fin_add_order_iff_nsmul_eq_zero _).2 ⟨n, hn, hnx⟩) (by positivity),
180+
obtain ⟨z, hz⟩ := (coe_eq_zero_of_pos_iff p hp this).mp (add_order_of_nsmul_eq_zero x),
181+
rw [← smul_mul_assoc, nsmul_eq_mul, nsmul_eq_mul, mul_left_inj' hp.ne.symm, mul_div,
182+
eq_div_iff hn₀] at hz,
183+
norm_cast at hz,
184+
exact ⟨z, hz⟩,
185+
end
186+
187+
lemma add_order_of_div_of_gcd_eq_one' {m : ℤ} {n : ℕ} (hn : 0 < n) (h : gcd m.nat_abs n = 1) :
188+
add_order_of (↑(↑m / ↑n * p) : add_circle p) = n :=
189+
begin
190+
induction m,
191+
{ simp only [int.of_nat_eq_coe, int.cast_coe_nat, int.nat_abs_of_nat] at h ⊢,
192+
exact add_order_of_div_of_gcd_eq_one hn h, },
193+
{ simp only [int.cast_neg_succ_of_nat, neg_div, neg_mul, _root_.coe_neg, order_of_neg],
194+
exact add_order_of_div_of_gcd_eq_one hn h, },
195+
end
196+
197+
lemma add_order_of_coe_rat {q : ℚ} : add_order_of (↑(↑q * p) : add_circle p) = q.denom :=
198+
begin
199+
have : (↑(q.denom : ℤ) : 𝕜) ≠ 0, { norm_cast, exact q.pos.ne.symm, },
200+
rw [← @rat.num_denom q, rat.cast_mk_of_ne_zero _ _ this, int.cast_coe_nat, rat.num_denom,
201+
add_order_of_div_of_gcd_eq_one' q.pos q.cop],
202+
apply_instance,
203+
end
204+
205+
variables (p)
206+
207+
lemma gcd_mul_add_order_of_div_eq {n : ℕ} (m : ℕ) (hn : 0 < n) :
208+
gcd m n * add_order_of (↑(↑m / ↑n * p) : add_circle p) = n :=
209+
begin
210+
let n' := n / gcd m n,
211+
let m' := m / gcd m n,
212+
have h₀ : 0 < gcd m n,
213+
{ rw zero_lt_iff at hn ⊢, contrapose! hn, exact ((gcd_eq_zero_iff m n).mp hn).2, },
214+
have hk' : 0 < n' := nat.div_pos (nat.le_of_dvd hn $ gcd_dvd_right m n) h₀,
215+
have hgcd : gcd m' n' = 1 := nat.coprime_div_gcd_div_gcd h₀,
216+
simp only [mul_left_inj' hp.out.ne.symm,
217+
← nat.cast_div_div_div_cancel_right (gcd_dvd_right m n) (gcd_dvd_left m n),
218+
add_order_of_div_of_gcd_eq_one hk' hgcd, mul_comm _ n', nat.div_mul_cancel (gcd_dvd_right m n)],
219+
end
220+
221+
variables {p} [floor_ring 𝕜]
222+
223+
lemma exists_gcd_eq_one_of_is_of_fin_add_order {u : add_circle p} (h : is_of_fin_add_order u) :
224+
∃ m, gcd m (add_order_of u) = 1
225+
m < (add_order_of u) ∧
226+
↑(((m : 𝕜) / add_order_of u) * p) = u :=
227+
begin
228+
rcases eq_or_ne u 0 with rfl | hu, { exact ⟨0, by simp⟩, },
229+
set n := add_order_of u,
230+
change ∃ m, gcd m n = 1 ∧ m < n ∧ ↑((↑m / ↑n) * p) = u,
231+
have hn : 0 < n := add_order_of_pos' h,
232+
have hn₀ : (n : 𝕜) ≠ 0, { norm_cast, exact ne_of_gt hn, },
233+
let x := (equiv_Ico p u : 𝕜),
234+
have hxu : (x : add_circle p) = u := (equiv_Ico p).symm_apply_apply u,
235+
have hx₀ : 0 < (add_order_of (x : add_circle p)), { rw ← hxu at h, exact add_order_of_pos' h, },
236+
have hx₁ : 0 < x,
237+
{ refine lt_of_le_of_ne (equiv_Ico p u).2.1 _,
238+
contrapose! hu,
239+
rw [← hxu, ← hu, quotient_add_group.coe_zero], },
240+
obtain ⟨m, hm : m • p = add_order_of ↑x • x⟩ := (coe_eq_zero_of_pos_iff p hp.out
241+
(by positivity)).mp (add_order_of_nsmul_eq_zero (x : add_circle p)),
242+
replace hm : ↑m * p = ↑n * x, { simpa only [hxu, nsmul_eq_mul] using hm, },
243+
have hux : ↑(↑m / ↑n * p) = u,
244+
{ rw [← hxu, ← mul_div_right_comm, hm, mul_comm _ x, mul_div_cancel x hn₀], },
245+
refine ⟨m, (_ : gcd m n = 1), (_ : m < n), hux⟩,
246+
{ have := gcd_mul_add_order_of_div_eq p m hn,
247+
rwa [hux, nat.mul_left_eq_self_iff hn] at this, },
248+
{ have : n • x < n • p := smul_lt_smul_of_pos (equiv_Ico p u).2.2 hn,
249+
rwa [nsmul_eq_mul, nsmul_eq_mul, ← hm, mul_lt_mul_right hp.out, nat.cast_lt] at this, },
250+
end
251+
252+
end finite_order_points
253+
129254
end linear_ordered_field
130255

131256
variables (p : ℝ)

0 commit comments

Comments
 (0)