@@ -13,6 +13,10 @@ import data.nat.parity
13
13
14
14
This file contains results about quadratic residues modulo a prime number.
15
15
16
+ We define the Legendre symbol `(a / p)` as `legendre_sym p a`.
17
+ Note the order of arguments! The advantage of this form is that then `legendre_sym p`
18
+ is a multiplicative map.
19
+
16
20
The main results are the law of quadratic reciprocity, `quadratic_reciprocity`, as well as the
17
21
interpretations in terms of existence of square roots depending on the congruence mod 4,
18
22
`exists_sq_eq_prime_iff_of_mod_four_eq_one`, and
@@ -348,21 +352,23 @@ variables (p q : ℕ) [fact p.prime] [fact q.prime]
348
352
349
353
namespace zmod
350
354
351
- /-- The Legendre symbol of `a` and `p` is an integer defined as
355
+ /-- The Legendre symbol of `a` and `p`, `legendre_sym p a`, is an integer defined as
352
356
353
357
* `0` if `a` is `0` modulo `p`;
354
358
* `1` if `a ^ (p / 2)` is `1` modulo `p`
355
359
(by `euler_criterion` this is equivalent to “`a` is a square modulo `p`”);
356
360
* `-1` otherwise.
357
361
362
+ Note the order of the arguments! The advantage of the order chosen here is
363
+ that `legendre_sym p` is a multiplicative function `ℤ → ℤ`.
358
364
-/
359
- def legendre_sym (a : ℤ ) (p : ℕ ) : ℤ :=
365
+ def legendre_sym (p : ℕ ) (a : ℤ ) : ℤ :=
360
366
if (a : zmod p) = 0 then 0
361
367
else if (a : zmod p) ^ (p / 2 ) = 1 then 1
362
368
else -1
363
369
364
- lemma legendre_sym_eq_pow (a p : ℕ) [hp : fact p.prime] :
365
- (legendre_sym a p : zmod p) = (a ^ (p / 2 )) :=
370
+ lemma legendre_sym_eq_pow (p a : ℕ) [hp : fact p.prime] :
371
+ (legendre_sym p a : zmod p) = (a ^ (p / 2 )) :=
366
372
begin
367
373
rw legendre_sym,
368
374
by_cases ha : (a : zmod p) = 0 ,
@@ -379,41 +385,41 @@ begin
379
385
{ rw [h, if_neg this , int.cast_neg, int.cast_one], } }
380
386
end
381
387
382
- lemma legendre_sym_eq_one_or_neg_one (a p : ℕ) (ha : (a : zmod p) ≠ 0 ) :
383
- legendre_sym a p = -1 ∨ legendre_sym a p = 1 :=
388
+ lemma legendre_sym_eq_one_or_neg_one (p a : ℕ) (ha : (a : zmod p) ≠ 0 ) :
389
+ legendre_sym p a = -1 ∨ legendre_sym p a = 1 :=
384
390
begin
385
391
unfold legendre_sym,
386
392
split_ifs;
387
393
simp only [*, eq_self_iff_true, or_true, true_or, int.cast_coe_nat] at *,
388
394
end
389
395
390
- lemma legendre_sym_eq_zero_iff (a p : ℕ) :
391
- legendre_sym a p = 0 ↔ (a : zmod p) = 0 :=
396
+ lemma legendre_sym_eq_zero_iff (p a : ℕ) :
397
+ legendre_sym p a = 0 ↔ (a : zmod p) = 0 :=
392
398
begin
393
399
split,
394
400
{ classical, contrapose,
395
- assume ha, cases legendre_sym_eq_one_or_neg_one a p ha with h h,
401
+ assume ha, cases legendre_sym_eq_one_or_neg_one p a ha with h h,
396
402
all_goals { rw h, norm_num } },
397
403
{ assume ha, rw [legendre_sym, int.cast_coe_nat, if_pos ha] }
398
404
end
399
405
400
406
/-- Gauss' lemma. The legendre symbol can be computed by considering the number of naturals less
401
407
than `p/2` such that `(a * x) % p > p / 2` -/
402
408
lemma gauss_lemma {a : ℕ} [fact (p % 2 = 1 )] (ha0 : (a : zmod p) ≠ 0 ) :
403
- legendre_sym a p = (-1 ) ^ ((Ico 1 (p / 2 ).succ).filter
409
+ legendre_sym p a = (-1 ) ^ ((Ico 1 (p / 2 ).succ).filter
404
410
(λ x : ℕ, p / 2 < (a * x : zmod p).val)).card :=
405
- have (legendre_sym a p : zmod p) = (((-1 )^((Ico 1 (p / 2 ).succ).filter
411
+ have (legendre_sym p a : zmod p) = (((-1 )^((Ico 1 (p / 2 ).succ).filter
406
412
(λ x : ℕ, p / 2 < (a * x : zmod p).val)).card : ℤ) : zmod p),
407
413
by rw [legendre_sym_eq_pow, gauss_lemma_aux₂ p ha0]; simp,
408
414
begin
409
- cases legendre_sym_eq_one_or_neg_one a p ha0;
415
+ cases legendre_sym_eq_one_or_neg_one p a ha0;
410
416
cases neg_one_pow_eq_or ℤ ((Ico 1 (p / 2 ).succ).filter
411
417
(λ x : ℕ, p / 2 < (a * x : zmod p).val)).card;
412
418
simp [*, ne_neg_self p one_ne_zero, (ne_neg_self p one_ne_zero).symm] at *
413
419
end
414
420
415
421
lemma legendre_sym_eq_one_iff {a : ℕ} (ha0 : (a : zmod p) ≠ 0 ) :
416
- legendre_sym a p = 1 ↔ (∃ b : zmod p, b ^ 2 = a) :=
422
+ legendre_sym p a = 1 ↔ (∃ b : zmod p, b ^ 2 = a) :=
417
423
begin
418
424
rw [euler_criterion p ha0, legendre_sym, int.cast_coe_nat, if_neg ha0],
419
425
split_ifs,
@@ -422,19 +428,19 @@ begin
422
428
end
423
429
424
430
lemma eisenstein_lemma [fact (p % 2 = 1 )] {a : ℕ} (ha1 : a % 2 = 1 ) (ha0 : (a : zmod p) ≠ 0 ) :
425
- legendre_sym a p = (-1 )^∑ x in Ico 1 (p / 2 ).succ, (x * a) / p :=
431
+ legendre_sym p a = (-1 )^∑ x in Ico 1 (p / 2 ).succ, (x * a) / p :=
426
432
by rw [neg_one_pow_eq_pow_mod_two, gauss_lemma p ha0, neg_one_pow_eq_pow_mod_two,
427
433
show _ = _, from eisenstein_lemma_aux₂ p ha1 ha0]
428
434
429
435
/-- **Quadratic reciprocity theorem** -/
430
436
theorem quadratic_reciprocity [hp1 : fact (p % 2 = 1 )] [hq1 : fact (q % 2 = 1 )] (hpq : p ≠ q) :
431
- legendre_sym p q * legendre_sym q p = (-1 ) ^ ((p / 2 ) * (q / 2 )) :=
437
+ legendre_sym q p * legendre_sym p q = (-1 ) ^ ((p / 2 ) * (q / 2 )) :=
432
438
have hpq0 : (p : zmod q) ≠ 0 , from prime_ne_zero q p hpq.symm,
433
439
have hqp0 : (q : zmod p) ≠ 0 , from prime_ne_zero p q hpq,
434
440
by rw [eisenstein_lemma q hp1.1 hpq0, eisenstein_lemma p hq1.1 hqp0,
435
441
← pow_add, sum_mul_div_add_sum_mul_div_eq_mul q p hpq0, mul_comm]
436
442
437
- lemma legendre_sym_two [hp1 : fact (p % 2 = 1 )] : legendre_sym 2 p = (-1 ) ^ (p / 4 + p / 2 ) :=
443
+ lemma legendre_sym_two [hp1 : fact (p % 2 = 1 )] : legendre_sym p 2 = (-1 ) ^ (p / 4 + p / 2 ) :=
438
444
have hp2 : p ≠ 2 , from mt (congr_arg (% 2 )) (by simpa using hp1.1 ),
439
445
have hp22 : p / 2 / 2 = _ := div_eq_filter_card (show 0 < 2 , from dec_trivial)
440
446
(nat.div_le_self (p / 2 ) 2 ),
0 commit comments