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

Commit 09fd631

Browse files
ChrisHughes24mergify[bot]
authored andcommitted
feat(data/zmod/basic): val_min_abs (#1548)
* feat(data/zmod/basic): val_min_abs * Update basic.lean * docstring and fix `zmodp` versions
1 parent c3d1bd7 commit 09fd631

File tree

1 file changed

+85
-1
lines changed

1 file changed

+85
-1
lines changed

src/data/zmod/basic.lean

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,32 @@
22
Copyright (c) 2018 Chris Hughes. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
44
Author: Chris Hughes
5+
6+
# zmod and zmodp
7+
8+
Definition of the integers mod n, and the field structure on the integers mod p.
9+
10+
There are two types defined, `zmod n`, which is for integers modulo a positive nat `n : ℕ+`.
11+
`zmodp` is the type of integers modulo a prime number, for which a field structure is defined.
12+
13+
## Definitions
14+
15+
`val` is inherited from `fin` and returns the least natural number in the equivalence class
16+
17+
`val_min_abs` returns the integer closest to zero in the equivalence class.
18+
19+
A coercion `cast` is defined from `zmod n` into any semiring. This is a semiring hom if the ring has
20+
characteristic dividing `n`
21+
22+
## Implentation notes
23+
24+
`zmod` and `zmodp` are implemented as different types so that the field instance for `zmodp` can be
25+
synthesized. This leads to a lot of code duplication and most of the functions and theorems for
26+
`zmod` are restated for `zmodp`
27+
528
-/
6-
import data.int.modeq data.int.gcd data.fintype data.pnat.basic
29+
30+
import data.int.modeq data.int.gcd data.fintype data.pnat.basic tactic.ring
731

832
open nat nat.modeq int
933

@@ -241,6 +265,45 @@ def units_equiv_coprime {n : ℕ+} : units (zmod n) ≃ {x : zmod n // nat.copri
241265
left_inv := λ ⟨_, _, _, _⟩, units.ext rfl,
242266
right_inv := λ ⟨_, _⟩, rfl }
243267

268+
/-- `val_min_abs x` returns the integer in the same equivalence class as `x` that is closest to `0`,
269+
The result will be in the interval `(-n/2, n/2]` -/
270+
def val_min_abs {n : ℕ+} (x : zmod n) : ℤ :=
271+
if x.val ≤ n / 2 then x.val else x.val - n
272+
273+
@[simp] lemma coe_val_min_abs {n : ℕ+} (x : zmod n) :
274+
(x.val_min_abs : zmod n) = x :=
275+
by simp [zmod.val_min_abs]; split_ifs; simp
276+
277+
lemma nat_abs_val_min_abs_le {n : ℕ+} (x : zmod n) : x.val_min_abs.nat_abs ≤ n / 2 :=
278+
have (x.val - n : ℤ) ≤ 0, from sub_nonpos.2 $ int.coe_nat_le.2 $ le_of_lt x.2,
279+
begin
280+
rw zmod.val_min_abs,
281+
split_ifs with h,
282+
{ exact h },
283+
{ rw [← int.coe_nat_le, int.of_nat_nat_abs_of_nonpos this, neg_sub],
284+
conv_lhs { congr, rw [coe_coe, ← nat.mod_add_div n 2, int.coe_nat_add, int.coe_nat_mul,
285+
int.coe_nat_bit0, int.coe_nat_one] },
286+
rw ← sub_nonneg,
287+
suffices : (0 : ℤ) ≤ x.val - ((n % 2 : ℕ) + (n / 2 : ℕ)),
288+
{ exact le_trans this (le_of_eq $ by ring) },
289+
exact sub_nonneg.2 (by rw [← int.coe_nat_add, int.coe_nat_le];
290+
exact calc (n : ℕ) % 2 + n / 21 + n / 2 :
291+
add_le_add (nat.le_of_lt_succ (nat.mod_lt _ dec_trivial)) (le_refl _)
292+
... ≤ x.val : by rw add_comm; exact nat.succ_le_of_lt (lt_of_not_ge h)) }
293+
end
294+
295+
@[simp] lemma val_min_abs_zero {n : ℕ+} : (0 : zmod n).val_min_abs = 0 :=
296+
by simp [zmod.val_min_abs]
297+
298+
@[simp] lemma val_min_abs_eq_zero {n : ℕ+} (x : zmod n) :
299+
x.val_min_abs = 0 ↔ x = 0 :=
300+
⟨λ h, begin
301+
dsimp [zmod.val_min_abs] at h,
302+
split_ifs at h,
303+
{ exact fin.eq_of_veq (by simp * at *) },
304+
{ exact absurd h (mt sub_eq_zero.1 (ne_of_lt $ int.coe_nat_lt.2 x.2)) }
305+
end, λ hx0, hx0.symm ▸ zmod.val_min_abs_zero⟩
306+
244307
section
245308
variables {α : Type*} [has_zero α] [has_one α] [has_add α] {n : ℕ+}
246309

@@ -327,6 +390,27 @@ lemma le_div_two_iff_lt_neg {p : ℕ} (hp : prime p) (hp1 : p % 2 = 1)
327390
lemma ne_neg_self (hp1 : p % 2 = 1) {a : zmodp p hp} (ha : a ≠ 0) : a ≠ -a :=
328391
@zmod.ne_neg_self ⟨p, hp.pos⟩ hp1 _ ha
329392

393+
variable {hp}
394+
395+
/-- `val_min_abs x` returns the integer in the same equivalence class as `x` that is closest to `0`,
396+
The result will be in the interval `(-n/2, n/2]` -/
397+
def val_min_abs (x : zmodp p hp) : ℤ := zmod.val_min_abs x
398+
399+
@[simp] lemma coe_val_min_abs (x : zmodp p hp) :
400+
(x.val_min_abs : zmodp p hp) = x :=
401+
zmod.coe_val_min_abs x
402+
403+
lemma nat_abs_val_min_abs_le (x : zmodp p hp) : x.val_min_abs.nat_abs ≤ p / 2 :=
404+
zmod.nat_abs_val_min_abs_le x
405+
406+
@[simp] lemma val_min_abs_zero : (0 : zmodp p hp).val_min_abs = 0 :=
407+
zmod.val_min_abs_zero
408+
409+
@[simp] lemma val_min_abs_eq_zero (x : zmodp p hp) : x.val_min_abs = 0 ↔ x = 0 :=
410+
zmod.val_min_abs_eq_zero x
411+
412+
variable (hp)
413+
330414
lemma prime_ne_zero {q : ℕ} (hq : prime q) (hpq : p ≠ q) : (q : zmodp p hp) ≠ 0 :=
331415
by rwa [← nat.cast_zero, ne.def, zmodp.eq_iff_modeq_nat, nat.modeq.modeq_zero_iff,
332416
← hp.coprime_iff_not_dvd, coprime_primes hp hq]

0 commit comments

Comments
 (0)