paulson@13871: (* Title: HOL/Quadratic_Reciprocity/Quadratic_Reciprocity.thy paulson@13871: Authors: Jeremy Avigad, David Gray, and Adam Kramer paulson@13871: License: GPL (GNU GENERAL PUBLIC LICENSE) paulson@13871: *) paulson@13871: paulson@13871: header {* The law of Quadratic reciprocity *} paulson@13871: paulson@13871: theory Quadratic_Reciprocity = Gauss:; paulson@13871: paulson@13871: (***************************************************************) paulson@13871: (* *) paulson@13871: (* Lemmas leading up to the proof of theorem 3.3 in *) paulson@13871: (* Niven and Zuckerman's presentation *) paulson@13871: (* *) paulson@13871: (***************************************************************) paulson@13871: paulson@13871: lemma (in GAUSS) QRLemma1: "a * setsum id A = paulson@13871: p * setsum (%x. ((x * a) div p)) A + setsum id D + setsum id E"; paulson@13871: proof -; paulson@13871: from finite_A have "a * setsum id A = setsum (%x. a * x) A"; paulson@13871: by (auto simp add: setsum_const_mult id_def) paulson@13871: also have "setsum (%x. a * x) = setsum (%x. x * a)"; paulson@13871: by (auto simp add: zmult_commute) paulson@13871: also; have "setsum (%x. x * a) A = setsum id B"; paulson@13871: by (auto simp add: B_def sum_prop_id finite_A inj_on_xa_A) paulson@13871: also have "... = setsum (%x. p * (x div p) + StandardRes p x) B"; paulson@13871: apply (rule setsum_same_function) paulson@13871: by (auto simp add: finite_B StandardRes_def zmod_zdiv_equality) paulson@13871: also have "... = setsum (%x. p * (x div p)) B + setsum (StandardRes p) B"; paulson@13871: by (rule setsum_addf) paulson@13871: also; have "setsum (StandardRes p) B = setsum id C"; paulson@13871: by (auto simp add: C_def sum_prop_id [THEN sym] finite_B paulson@13871: SR_B_inj) paulson@13871: also; from C_eq have "... = setsum id (D \ E)"; paulson@13871: by auto paulson@13871: also; from finite_D finite_E have "... = setsum id D + setsum id E"; paulson@13871: apply (rule setsum_Un_disjoint) paulson@13871: by (auto simp add: D_def E_def) paulson@13871: also have "setsum (%x. p * (x div p)) B = paulson@13871: setsum ((%x. p * (x div p)) o (%x. (x * a))) A"; paulson@13871: by (auto simp add: B_def sum_prop finite_A inj_on_xa_A) paulson@13871: also have "... = setsum (%x. p * ((x * a) div p)) A"; paulson@13871: by (auto simp add: o_def) paulson@13871: also from finite_A have "setsum (%x. p * ((x * a) div p)) A = paulson@13871: p * setsum (%x. ((x * a) div p)) A"; paulson@13871: by (auto simp add: setsum_const_mult) paulson@13871: finally show ?thesis by arith paulson@13871: qed; paulson@13871: paulson@13871: lemma (in GAUSS) QRLemma2: "setsum id A = p * int (card E) - setsum id E + paulson@13871: setsum id D"; paulson@13871: proof -; paulson@13871: from F_Un_D_eq_A have "setsum id A = setsum id (D \ F)"; paulson@13871: by (simp add: Un_commute) paulson@13871: also from F_D_disj finite_D finite_F have paulson@13871: "... = setsum id D + setsum id F"; paulson@13871: apply (simp add: Int_commute) paulson@13871: by (intro setsum_Un_disjoint) paulson@13871: also from F_def have "F = (%x. (p - x)) ` E"; paulson@13871: by auto paulson@13871: also from finite_E inj_on_pminusx_E have "setsum id ((%x. (p - x)) ` E) = paulson@13871: setsum (%x. (p - x)) E"; paulson@13871: by (auto simp add: sum_prop) paulson@13871: also from finite_E have "setsum (op - p) E = setsum (%x. p) E - setsum id E"; paulson@13871: by (auto simp add: setsum_minus id_def) paulson@13871: also from finite_E have "setsum (%x. p) E = p * int(card E)"; paulson@13871: by (intro setsum_const) paulson@13871: finally show ?thesis; paulson@13871: by arith paulson@13871: qed; paulson@13871: paulson@13871: lemma (in GAUSS) QRLemma3: "(a - 1) * setsum id A = paulson@13871: p * (setsum (%x. ((x * a) div p)) A - int(card E)) + 2 * setsum id E"; paulson@13871: proof -; paulson@13871: have "(a - 1) * setsum id A = a * setsum id A - setsum id A"; paulson@13871: by (auto simp add: zdiff_zmult_distrib) paulson@13871: also note QRLemma1; paulson@13871: also; from QRLemma2 have "p * (\x \ A. x * a div p) + setsum id D + paulson@13871: setsum id E - setsum id A = paulson@13871: p * (\x \ A. x * a div p) + setsum id D + paulson@13871: setsum id E - (p * int (card E) - setsum id E + setsum id D)"; paulson@13871: by auto paulson@13871: also; have "... = p * (\x \ A. x * a div p) - paulson@13871: p * int (card E) + 2 * setsum id E"; paulson@13871: by arith paulson@13871: finally show ?thesis; paulson@13871: by (auto simp only: zdiff_zmult_distrib2) paulson@13871: qed; paulson@13871: paulson@13871: lemma (in GAUSS) QRLemma4: "a \ zOdd ==> paulson@13871: (setsum (%x. ((x * a) div p)) A \ zEven) = (int(card E): zEven)"; paulson@13871: proof -; paulson@13871: assume a_odd: "a \ zOdd"; paulson@13871: from QRLemma3 have a: "p * (setsum (%x. ((x * a) div p)) A - int(card E)) = paulson@13871: (a - 1) * setsum id A - 2 * setsum id E"; paulson@13871: by arith paulson@13871: from a_odd have "a - 1 \ zEven" paulson@13871: by (rule odd_minus_one_even) paulson@13871: hence "(a - 1) * setsum id A \ zEven"; paulson@13871: by (rule even_times_either) paulson@13871: moreover have "2 * setsum id E \ zEven"; paulson@13871: by (auto simp add: zEven_def) paulson@13871: ultimately have "(a - 1) * setsum id A - 2 * setsum id E \ zEven" paulson@13871: by (rule even_minus_even) paulson@13871: with a have "p * (setsum (%x. ((x * a) div p)) A - int(card E)): zEven"; paulson@13871: by simp paulson@13871: hence "p \ zEven | (setsum (%x. ((x * a) div p)) A - int(card E)): zEven"; paulson@13871: by (rule even_product) paulson@13871: with p_odd have "(setsum (%x. ((x * a) div p)) A - int(card E)): zEven"; paulson@13871: by (auto simp add: odd_iff_not_even) paulson@13871: thus ?thesis; paulson@13871: by (auto simp only: even_diff [THEN sym]) paulson@13871: qed; paulson@13871: paulson@13871: lemma (in GAUSS) QRLemma5: "a \ zOdd ==> paulson@13871: (-1::int)^(card E) = (-1::int)^(nat(setsum (%x. ((x * a) div p)) A))"; paulson@13871: proof -; paulson@13871: assume "a \ zOdd"; paulson@13871: from QRLemma4 have paulson@13871: "(int(card E): zEven) = (setsum (%x. ((x * a) div p)) A \ zEven)";..; paulson@13871: moreover have "0 \ int(card E)"; paulson@13871: by auto paulson@13871: moreover have "0 \ setsum (%x. ((x * a) div p)) A"; paulson@13871: proof (intro setsum_non_neg); paulson@13871: from finite_A show "finite A";.; paulson@13871: next show "\x \ A. 0 \ x * a div p"; paulson@13871: proof; paulson@13871: fix x; paulson@13871: assume "x \ A"; paulson@13871: then have "0 \ x"; paulson@13871: by (auto simp add: A_def) paulson@13871: with a_nonzero have "0 \ x * a"; paulson@14353: by (auto simp add: zero_le_mult_iff) paulson@13871: with p_g_2 show "0 \ x * a div p"; paulson@13871: by (auto simp add: pos_imp_zdiv_nonneg_iff) paulson@13871: qed; paulson@13871: qed; paulson@13871: ultimately have "(-1::int)^nat((int (card E))) = paulson@13871: (-1)^nat(((\x \ A. x * a div p)))"; paulson@13871: by (intro neg_one_power_parity, auto) paulson@13871: also have "nat (int(card E)) = card E"; paulson@13871: by auto paulson@13871: finally show ?thesis;.; paulson@13871: qed; paulson@13871: paulson@13871: lemma MainQRLemma: "[| a \ zOdd; 0 < a; ~([a = 0] (mod p));p \ zprime; 2 < p; paulson@13871: A = {x. 0 < x & x \ (p - 1) div 2} |] ==> paulson@13871: (Legendre a p) = (-1::int)^(nat(setsum (%x. ((x * a) div p)) A))"; paulson@13871: apply (subst GAUSS.gauss_lemma) paulson@13871: apply (auto simp add: GAUSS_def) paulson@13871: apply (subst GAUSS.QRLemma5) paulson@13871: by (auto simp add: GAUSS_def) paulson@13871: paulson@13871: (******************************************************************) paulson@13871: (* *) paulson@13871: (* Stuff about S, S1 and S2... *) paulson@13871: (* *) paulson@13871: (******************************************************************) paulson@13871: paulson@13871: locale QRTEMP = paulson@13871: fixes p :: "int" paulson@13871: fixes q :: "int" paulson@13871: fixes P_set :: "int set" paulson@13871: fixes Q_set :: "int set" paulson@13871: fixes S :: "(int * int) set" paulson@13871: fixes S1 :: "(int * int) set" paulson@13871: fixes S2 :: "(int * int) set" paulson@13871: fixes f1 :: "int => (int * int) set" paulson@13871: fixes f2 :: "int => (int * int) set" paulson@13871: paulson@13871: assumes p_prime: "p \ zprime" paulson@13871: assumes p_g_2: "2 < p" paulson@13871: assumes q_prime: "q \ zprime" paulson@13871: assumes q_g_2: "2 < q" paulson@13871: assumes p_neq_q: "p \ q" paulson@13871: paulson@13871: defines P_set_def: "P_set == {x. 0 < x & x \ ((p - 1) div 2) }" paulson@13871: defines Q_set_def: "Q_set == {x. 0 < x & x \ ((q - 1) div 2) }" paulson@13871: defines S_def: "S == P_set <*> Q_set" paulson@13871: defines S1_def: "S1 == { (x, y). (x, y):S & ((p * y) < (q * x)) }" paulson@13871: defines S2_def: "S2 == { (x, y). (x, y):S & ((q * x) < (p * y)) }" paulson@13871: defines f1_def: "f1 j == { (j1, y). (j1, y):S & j1 = j & paulson@13871: (y \ (q * j) div p) }" paulson@13871: defines f2_def: "f2 j == { (x, j1). (x, j1):S & j1 = j & paulson@13871: (x \ (p * j) div q) }"; paulson@13871: paulson@13871: lemma (in QRTEMP) p_fact: "0 < (p - 1) div 2"; paulson@13871: proof -; paulson@13871: from prems have "2 < p" by (simp add: QRTEMP_def) paulson@13871: then have "2 \ p - 1" by arith paulson@13871: then have "2 div 2 \ (p - 1) div 2" by (rule zdiv_mono1, auto) paulson@13871: then show ?thesis by auto paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) q_fact: "0 < (q - 1) div 2"; paulson@13871: proof -; paulson@13871: from prems have "2 < q" by (simp add: QRTEMP_def) paulson@13871: then have "2 \ q - 1" by arith paulson@13871: then have "2 div 2 \ (q - 1) div 2" by (rule zdiv_mono1, auto) paulson@13871: then show ?thesis by auto paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) pb_neq_qa: "[|1 \ b; b \ (q - 1) div 2 |] ==> paulson@13871: (p * b \ q * a)"; paulson@13871: proof; paulson@13871: assume "p * b = q * a" and "1 \ b" and "b \ (q - 1) div 2"; paulson@13871: then have "q dvd (p * b)" by (auto simp add: dvd_def) paulson@13871: with q_prime p_g_2 have "q dvd p | q dvd b"; paulson@13871: by (auto simp add: zprime_zdvd_zmult) paulson@13871: moreover have "~ (q dvd p)"; paulson@13871: proof; paulson@13871: assume "q dvd p"; paulson@13871: with p_prime have "q = 1 | q = p" paulson@13871: apply (auto simp add: zprime_def QRTEMP_def) paulson@13871: apply (drule_tac x = q and R = False in allE) paulson@13871: apply (simp add: QRTEMP_def) paulson@13871: apply (subgoal_tac "0 \ q", simp add: QRTEMP_def) paulson@13871: apply (insert prems) paulson@13871: by (auto simp add: QRTEMP_def) paulson@13871: with q_g_2 p_neq_q show False by auto paulson@13871: qed; paulson@13871: ultimately have "q dvd b" by auto paulson@13871: then have "q \ b"; paulson@13871: proof -; paulson@13871: assume "q dvd b"; paulson@13871: moreover from prems have "0 < b" by auto paulson@13871: ultimately show ?thesis by (insert zdvd_bounds [of q b], auto) paulson@13871: qed; paulson@13871: with prems have "q \ (q - 1) div 2" by auto paulson@13871: then have "2 * q \ 2 * ((q - 1) div 2)" by arith paulson@13871: then have "2 * q \ q - 1"; paulson@13871: proof -; paulson@13871: assume "2 * q \ 2 * ((q - 1) div 2)"; paulson@13871: with prems have "q \ zOdd" by (auto simp add: QRTEMP_def zprime_zOdd_eq_grt_2) paulson@13871: with odd_minus_one_even have "(q - 1):zEven" by auto paulson@13871: with even_div_2_prop2 have "(q - 1) = 2 * ((q - 1) div 2)" by auto paulson@13871: with prems show ?thesis by auto paulson@13871: qed; paulson@13871: then have p1: "q \ -1" by arith paulson@13871: with q_g_2 show False by auto paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) P_set_finite: "finite (P_set)"; paulson@13871: by (insert p_fact, auto simp add: P_set_def bdd_int_set_l_le_finite) paulson@13871: paulson@13871: lemma (in QRTEMP) Q_set_finite: "finite (Q_set)"; paulson@13871: by (insert q_fact, auto simp add: Q_set_def bdd_int_set_l_le_finite) paulson@13871: paulson@13871: lemma (in QRTEMP) S_finite: "finite S"; paulson@13871: by (auto simp add: S_def P_set_finite Q_set_finite cartesian_product_finite) paulson@13871: paulson@13871: lemma (in QRTEMP) S1_finite: "finite S1"; paulson@13871: proof -; paulson@13871: have "finite S" by (auto simp add: S_finite) paulson@13871: moreover have "S1 \ S" by (auto simp add: S1_def S_def) paulson@13871: ultimately show ?thesis by (auto simp add: finite_subset) paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) S2_finite: "finite S2"; paulson@13871: proof -; paulson@13871: have "finite S" by (auto simp add: S_finite) paulson@13871: moreover have "S2 \ S" by (auto simp add: S2_def S_def) paulson@13871: ultimately show ?thesis by (auto simp add: finite_subset) paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) P_set_card: "(p - 1) div 2 = int (card (P_set))"; paulson@13871: by (insert p_fact, auto simp add: P_set_def card_bdd_int_set_l_le) paulson@13871: paulson@13871: lemma (in QRTEMP) Q_set_card: "(q - 1) div 2 = int (card (Q_set))"; paulson@13871: by (insert q_fact, auto simp add: Q_set_def card_bdd_int_set_l_le) paulson@13871: paulson@13871: lemma (in QRTEMP) S_card: "((p - 1) div 2) * ((q - 1) div 2) = int (card(S))"; paulson@13871: apply (insert P_set_card Q_set_card P_set_finite Q_set_finite) paulson@13871: apply (auto simp add: S_def zmult_int) paulson@13871: done paulson@13871: paulson@13871: lemma (in QRTEMP) S1_Int_S2_prop: "S1 \ S2 = {}"; paulson@13871: by (auto simp add: S1_def S2_def) paulson@13871: paulson@13871: lemma (in QRTEMP) S1_Union_S2_prop: "S = S1 \ S2"; paulson@13871: apply (auto simp add: S_def P_set_def Q_set_def S1_def S2_def) paulson@13871: proof -; paulson@13871: fix a and b; paulson@13871: assume "~ q * a < p * b" and b1: "0 < b" and b2: "b \ (q - 1) div 2"; paulson@13871: with zless_linear have "(p * b < q * a) | (p * b = q * a)" by auto paulson@13871: moreover from pb_neq_qa b1 b2 have "(p * b \ q * a)" by auto paulson@13871: ultimately show "p * b < q * a" by auto paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) card_sum_S1_S2: "((p - 1) div 2) * ((q - 1) div 2) = paulson@13871: int(card(S1)) + int(card(S2))"; paulson@13871: proof-; paulson@13871: have "((p - 1) div 2) * ((q - 1) div 2) = int (card(S))"; paulson@13871: by (auto simp add: S_card) paulson@13871: also have "... = int( card(S1) + card(S2))"; paulson@13871: apply (insert S1_finite S2_finite S1_Int_S2_prop S1_Union_S2_prop) paulson@13871: apply (drule card_Un_disjoint, auto) paulson@13871: done paulson@13871: also have "... = int(card(S1)) + int(card(S2))" by auto paulson@13871: finally show ?thesis .; paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) aux1a: "[| 0 < a; a \ (p - 1) div 2; paulson@13871: 0 < b; b \ (q - 1) div 2 |] ==> paulson@13871: (p * b < q * a) = (b \ q * a div p)"; paulson@13871: proof -; paulson@13871: assume "0 < a" and "a \ (p - 1) div 2" and "0 < b" and "b \ (q - 1) div 2"; paulson@13871: have "p * b < q * a ==> b \ q * a div p"; paulson@13871: proof -; paulson@13871: assume "p * b < q * a"; paulson@13871: then have "p * b \ q * a" by auto paulson@13871: then have "(p * b) div p \ (q * a) div p"; paulson@13871: by (rule zdiv_mono1, insert p_g_2, auto) paulson@13871: then show "b \ (q * a) div p"; paulson@13871: apply (subgoal_tac "p \ 0") paulson@13871: apply (frule zdiv_zmult_self2, force) paulson@13871: by (insert p_g_2, auto) paulson@13871: qed; paulson@13871: moreover have "b \ q * a div p ==> p * b < q * a"; paulson@13871: proof -; paulson@13871: assume "b \ q * a div p"; paulson@13871: then have "p * b \ p * ((q * a) div p)"; paulson@13871: by (insert p_g_2, auto simp add: zmult_zle_cancel1) paulson@13871: also have "... \ q * a"; paulson@13871: by (rule zdiv_leq_prop, insert p_g_2, auto) paulson@13871: finally have "p * b \ q * a" .; paulson@13871: then have "p * b < q * a | p * b = q * a"; paulson@13871: by (simp only: order_le_imp_less_or_eq) paulson@13871: moreover have "p * b \ q * a"; paulson@13871: by (rule pb_neq_qa, insert prems, auto) paulson@13871: ultimately show ?thesis by auto paulson@13871: qed; paulson@13871: ultimately show ?thesis ..; paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) aux1b: "[| 0 < a; a \ (p - 1) div 2; paulson@13871: 0 < b; b \ (q - 1) div 2 |] ==> paulson@13871: (q * a < p * b) = (a \ p * b div q)"; paulson@13871: proof -; paulson@13871: assume "0 < a" and "a \ (p - 1) div 2" and "0 < b" and "b \ (q - 1) div 2"; paulson@13871: have "q * a < p * b ==> a \ p * b div q"; paulson@13871: proof -; paulson@13871: assume "q * a < p * b"; paulson@13871: then have "q * a \ p * b" by auto paulson@13871: then have "(q * a) div q \ (p * b) div q"; paulson@13871: by (rule zdiv_mono1, insert q_g_2, auto) paulson@13871: then show "a \ (p * b) div q"; paulson@13871: apply (subgoal_tac "q \ 0") paulson@13871: apply (frule zdiv_zmult_self2, force) paulson@13871: by (insert q_g_2, auto) paulson@13871: qed; paulson@13871: moreover have "a \ p * b div q ==> q * a < p * b"; paulson@13871: proof -; paulson@13871: assume "a \ p * b div q"; paulson@13871: then have "q * a \ q * ((p * b) div q)"; paulson@13871: by (insert q_g_2, auto simp add: zmult_zle_cancel1) paulson@13871: also have "... \ p * b"; paulson@13871: by (rule zdiv_leq_prop, insert q_g_2, auto) paulson@13871: finally have "q * a \ p * b" .; paulson@13871: then have "q * a < p * b | q * a = p * b"; paulson@13871: by (simp only: order_le_imp_less_or_eq) paulson@13871: moreover have "p * b \ q * a"; paulson@13871: by (rule pb_neq_qa, insert prems, auto) paulson@13871: ultimately show ?thesis by auto paulson@13871: qed; paulson@13871: ultimately show ?thesis ..; paulson@13871: qed; paulson@13871: paulson@13871: lemma aux2: "[| p \ zprime; q \ zprime; 2 < p; 2 < q |] ==> paulson@13871: (q * ((p - 1) div 2)) div p \ (q - 1) div 2"; paulson@13871: proof-; paulson@13871: assume "p \ zprime" and "q \ zprime" and "2 < p" and "2 < q"; paulson@13871: (* Set up what's even and odd *) paulson@13871: then have "p \ zOdd & q \ zOdd"; paulson@13871: by (auto simp add: zprime_zOdd_eq_grt_2) paulson@13871: then have even1: "(p - 1):zEven & (q - 1):zEven"; paulson@13871: by (auto simp add: odd_minus_one_even) paulson@13871: then have even2: "(2 * p):zEven & ((q - 1) * p):zEven"; paulson@13871: by (auto simp add: zEven_def) paulson@13871: then have even3: "(((q - 1) * p) + (2 * p)):zEven"; paulson@13871: by (auto simp: even_plus_even) paulson@13871: (* using these prove it *) paulson@13871: from prems have "q * (p - 1) < ((q - 1) * p) + (2 * p)"; paulson@13871: by (auto simp add: int_distrib) paulson@13871: then have "((p - 1) * q) div 2 < (((q - 1) * p) + (2 * p)) div 2"; paulson@13871: apply (rule_tac x = "((p - 1) * q)" in even_div_2_l); paulson@13871: by (auto simp add: even3, auto simp add: zmult_ac) paulson@13871: also have "((p - 1) * q) div 2 = q * ((p - 1) div 2)"; paulson@13871: by (auto simp add: even1 even_prod_div_2) paulson@13871: also have "(((q - 1) * p) + (2 * p)) div 2 = (((q - 1) div 2) * p) + p"; paulson@13871: by (auto simp add: even1 even2 even_prod_div_2 even_sum_div_2) paulson@13871: finally show ?thesis paulson@13871: apply (rule_tac x = " q * ((p - 1) div 2)" and paulson@13871: y = "(q - 1) div 2" in div_prop2); paulson@13871: by (insert prems, auto) paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) aux3a: "\j \ P_set. int (card (f1 j)) = (q * j) div p"; paulson@13871: proof; paulson@13871: fix j; paulson@13871: assume j_fact: "j \ P_set"; paulson@13871: have "int (card (f1 j)) = int (card {y. y \ Q_set & y \ (q * j) div p})"; paulson@13871: proof -; paulson@13871: have "finite (f1 j)"; paulson@13871: proof -; paulson@13871: have "(f1 j) \ S" by (auto simp add: f1_def) paulson@13871: with S_finite show ?thesis by (auto simp add: finite_subset) paulson@13871: qed; paulson@13871: moreover have "inj_on (%(x,y). y) (f1 j)"; paulson@13871: by (auto simp add: f1_def inj_on_def) paulson@13871: ultimately have "card ((%(x,y). y) ` (f1 j)) = card (f1 j)"; paulson@13871: by (auto simp add: f1_def card_image) paulson@13871: moreover have "((%(x,y). y) ` (f1 j)) = {y. y \ Q_set & y \ (q * j) div p}"; paulson@13871: by (insert prems, auto simp add: f1_def S_def Q_set_def P_set_def paulson@13871: image_def) paulson@13871: ultimately show ?thesis by (auto simp add: f1_def) paulson@13871: qed; paulson@13871: also have "... = int (card {y. 0 < y & y \ (q * j) div p})"; paulson@13871: proof -; paulson@13871: have "{y. y \ Q_set & y \ (q * j) div p} = paulson@13871: {y. 0 < y & y \ (q * j) div p}"; paulson@13871: apply (auto simp add: Q_set_def) paulson@13871: proof -; paulson@13871: fix x; paulson@13871: assume "0 < x" and "x \ q * j div p"; paulson@13871: with j_fact P_set_def have "j \ (p - 1) div 2"; by auto paulson@13871: with q_g_2; have "q * j \ q * ((p - 1) div 2)"; paulson@13871: by (auto simp add: zmult_zle_cancel1) paulson@13871: with p_g_2 have "q * j div p \ q * ((p - 1) div 2) div p"; paulson@13871: by (auto simp add: zdiv_mono1) paulson@13871: also from prems have "... \ (q - 1) div 2"; paulson@13871: apply simp apply (insert aux2) by (simp add: QRTEMP_def) paulson@13871: finally show "x \ (q - 1) div 2" by (insert prems, auto) paulson@13871: qed; paulson@13871: then show ?thesis by auto paulson@13871: qed; paulson@13871: also have "... = (q * j) div p"; paulson@13871: proof -; paulson@13871: from j_fact P_set_def have "0 \ j" by auto paulson@13871: with q_g_2 have "q * 0 \ q * j" by (auto simp only: zmult_zle_mono2) paulson@13871: then have "0 \ q * j" by auto paulson@13871: then have "0 div p \ (q * j) div p"; paulson@13871: apply (rule_tac a = 0 in zdiv_mono1) paulson@13871: by (insert p_g_2, auto) paulson@13871: also have "0 div p = 0" by auto paulson@13871: finally show ?thesis by (auto simp add: card_bdd_int_set_l_le) paulson@13871: qed; paulson@13871: finally show "int (card (f1 j)) = q * j div p" .; paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) aux3b: "\j \ Q_set. int (card (f2 j)) = (p * j) div q"; paulson@13871: proof; paulson@13871: fix j; paulson@13871: assume j_fact: "j \ Q_set"; paulson@13871: have "int (card (f2 j)) = int (card {y. y \ P_set & y \ (p * j) div q})"; paulson@13871: proof -; paulson@13871: have "finite (f2 j)"; paulson@13871: proof -; paulson@13871: have "(f2 j) \ S" by (auto simp add: f2_def) paulson@13871: with S_finite show ?thesis by (auto simp add: finite_subset) paulson@13871: qed; paulson@13871: moreover have "inj_on (%(x,y). x) (f2 j)"; paulson@13871: by (auto simp add: f2_def inj_on_def) paulson@13871: ultimately have "card ((%(x,y). x) ` (f2 j)) = card (f2 j)"; paulson@13871: by (auto simp add: f2_def card_image) paulson@13871: moreover have "((%(x,y). x) ` (f2 j)) = {y. y \ P_set & y \ (p * j) div q}"; paulson@13871: by (insert prems, auto simp add: f2_def S_def Q_set_def paulson@13871: P_set_def image_def) paulson@13871: ultimately show ?thesis by (auto simp add: f2_def) paulson@13871: qed; paulson@13871: also have "... = int (card {y. 0 < y & y \ (p * j) div q})"; paulson@13871: proof -; paulson@13871: have "{y. y \ P_set & y \ (p * j) div q} = paulson@13871: {y. 0 < y & y \ (p * j) div q}"; paulson@13871: apply (auto simp add: P_set_def) paulson@13871: proof -; paulson@13871: fix x; paulson@13871: assume "0 < x" and "x \ p * j div q"; paulson@13871: with j_fact Q_set_def have "j \ (q - 1) div 2"; by auto paulson@13871: with p_g_2; have "p * j \ p * ((q - 1) div 2)"; paulson@13871: by (auto simp add: zmult_zle_cancel1) paulson@13871: with q_g_2 have "p * j div q \ p * ((q - 1) div 2) div q"; paulson@13871: by (auto simp add: zdiv_mono1) paulson@13871: also from prems have "... \ (p - 1) div 2"; paulson@13871: by (auto simp add: aux2 QRTEMP_def) paulson@13871: finally show "x \ (p - 1) div 2" by (insert prems, auto) paulson@13871: qed; paulson@13871: then show ?thesis by auto paulson@13871: qed; paulson@13871: also have "... = (p * j) div q"; paulson@13871: proof -; paulson@13871: from j_fact Q_set_def have "0 \ j" by auto paulson@13871: with p_g_2 have "p * 0 \ p * j" by (auto simp only: zmult_zle_mono2) paulson@13871: then have "0 \ p * j" by auto paulson@13871: then have "0 div q \ (p * j) div q"; paulson@13871: apply (rule_tac a = 0 in zdiv_mono1) paulson@13871: by (insert q_g_2, auto) paulson@13871: also have "0 div q = 0" by auto paulson@13871: finally show ?thesis by (auto simp add: card_bdd_int_set_l_le) paulson@13871: qed; paulson@13871: finally show "int (card (f2 j)) = p * j div q" .; paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) S1_card: "int (card(S1)) = setsum (%j. (q * j) div p) P_set"; paulson@13871: proof -; paulson@13871: have "\x \ P_set. finite (f1 x)"; paulson@13871: proof; paulson@13871: fix x; paulson@13871: have "f1 x \ S" by (auto simp add: f1_def) paulson@13871: with S_finite show "finite (f1 x)" by (auto simp add: finite_subset) paulson@13871: qed; paulson@13871: moreover have "(\x \ P_set. \y \ P_set. x \ y --> (f1 x) \ (f1 y) = {})"; paulson@13871: by (auto simp add: f1_def) paulson@13871: moreover note P_set_finite; paulson@13871: ultimately have "int(card (UNION P_set f1)) = paulson@13871: setsum (%x. int(card (f1 x))) P_set"; paulson@13871: by (rule_tac A = P_set in int_card_indexed_union_disjoint_sets, auto) paulson@13871: moreover have "S1 = UNION P_set f1"; paulson@13871: by (auto simp add: f1_def S_def S1_def S2_def P_set_def Q_set_def aux1a) paulson@13871: ultimately have "int(card (S1)) = setsum (%j. int(card (f1 j))) P_set" paulson@13871: by auto paulson@13871: also have "... = setsum (%j. q * j div p) P_set"; paulson@13871: proof -; paulson@13871: note aux3a paulson@13871: with P_set_finite show ?thesis by (rule setsum_same_function) paulson@13871: qed; paulson@13871: finally show ?thesis .; paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) S2_card: "int (card(S2)) = setsum (%j. (p * j) div q) Q_set"; paulson@13871: proof -; paulson@13871: have "\x \ Q_set. finite (f2 x)"; paulson@13871: proof; paulson@13871: fix x; paulson@13871: have "f2 x \ S" by (auto simp add: f2_def) paulson@13871: with S_finite show "finite (f2 x)" by (auto simp add: finite_subset) paulson@13871: qed; paulson@13871: moreover have "(\x \ Q_set. \y \ Q_set. x \ y --> paulson@13871: (f2 x) \ (f2 y) = {})"; paulson@13871: by (auto simp add: f2_def) paulson@13871: moreover note Q_set_finite; paulson@13871: ultimately have "int(card (UNION Q_set f2)) = paulson@13871: setsum (%x. int(card (f2 x))) Q_set"; paulson@13871: by (rule_tac A = Q_set in int_card_indexed_union_disjoint_sets, auto) paulson@13871: moreover have "S2 = UNION Q_set f2"; paulson@13871: by (auto simp add: f2_def S_def S1_def S2_def P_set_def Q_set_def aux1b) paulson@13871: ultimately have "int(card (S2)) = setsum (%j. int(card (f2 j))) Q_set" paulson@13871: by auto paulson@13871: also have "... = setsum (%j. p * j div q) Q_set"; paulson@13871: proof -; paulson@13871: note aux3b; paulson@13871: with Q_set_finite show ?thesis by (rule setsum_same_function) paulson@13871: qed; paulson@13871: finally show ?thesis .; paulson@13871: qed; paulson@13871: paulson@13871: lemma (in QRTEMP) S1_carda: "int (card(S1)) = paulson@13871: setsum (%j. (j * q) div p) P_set"; paulson@13871: by (auto simp add: S1_card zmult_ac) paulson@13871: paulson@13871: lemma (in QRTEMP) S2_carda: "int (card(S2)) = paulson@13871: setsum (%j. (j * p) div q) Q_set"; paulson@13871: by (auto simp add: S2_card zmult_ac) paulson@13871: paulson@13871: lemma (in QRTEMP) pq_sum_prop: "(setsum (%j. (j * p) div q) Q_set) + paulson@13871: (setsum (%j. (j * q) div p) P_set) = ((p - 1) div 2) * ((q - 1) div 2)"; paulson@13871: proof -; paulson@13871: have "(setsum (%j. (j * p) div q) Q_set) + paulson@13871: (setsum (%j. (j * q) div p) P_set) = int (card S2) + int (card S1)"; paulson@13871: by (auto simp add: S1_carda S2_carda) paulson@13871: also have "... = int (card S1) + int (card S2)"; paulson@13871: by auto paulson@13871: also have "... = ((p - 1) div 2) * ((q - 1) div 2)"; paulson@13871: by (auto simp add: card_sum_S1_S2) paulson@13871: finally show ?thesis .; paulson@13871: qed; paulson@13871: paulson@13871: lemma pq_prime_neq: "[| p \ zprime; q \ zprime; p \ q |] ==> (~[p = 0] (mod q))"; paulson@13871: apply (auto simp add: zcong_eq_zdvd_prop zprime_def) paulson@13871: apply (drule_tac x = q in allE) paulson@13871: apply (drule_tac x = p in allE) paulson@13871: by auto paulson@13871: paulson@13871: lemma (in QRTEMP) QR_short: "(Legendre p q) * (Legendre q p) = paulson@13871: (-1::int)^nat(((p - 1) div 2)*((q - 1) div 2))"; paulson@13871: proof -; paulson@13871: from prems have "~([p = 0] (mod q))"; paulson@13871: by (auto simp add: pq_prime_neq QRTEMP_def) paulson@13871: with prems have a1: "(Legendre p q) = (-1::int) ^ paulson@13871: nat(setsum (%x. ((x * p) div q)) Q_set)"; paulson@13871: apply (rule_tac p = q in MainQRLemma) paulson@13871: by (auto simp add: zprime_zOdd_eq_grt_2 QRTEMP_def) paulson@13871: from prems have "~([q = 0] (mod p))"; paulson@13871: apply (rule_tac p = q and q = p in pq_prime_neq) paulson@13871: apply (simp add: QRTEMP_def)+; paulson@13871: by arith paulson@13871: with prems have a2: "(Legendre q p) = paulson@13871: (-1::int) ^ nat(setsum (%x. ((x * q) div p)) P_set)"; paulson@13871: apply (rule_tac p = p in MainQRLemma) paulson@13871: by (auto simp add: zprime_zOdd_eq_grt_2 QRTEMP_def) paulson@13871: from a1 a2 have "(Legendre p q) * (Legendre q p) = paulson@13871: (-1::int) ^ nat(setsum (%x. ((x * p) div q)) Q_set) * paulson@13871: (-1::int) ^ nat(setsum (%x. ((x * q) div p)) P_set)"; paulson@13871: by auto paulson@13871: also have "... = (-1::int) ^ (nat(setsum (%x. ((x * p) div q)) Q_set) + paulson@13871: nat(setsum (%x. ((x * q) div p)) P_set))"; paulson@13871: by (auto simp add: zpower_zadd_distrib) paulson@13871: also have "nat(setsum (%x. ((x * p) div q)) Q_set) + paulson@13871: nat(setsum (%x. ((x * q) div p)) P_set) = paulson@13871: nat((setsum (%x. ((x * p) div q)) Q_set) + paulson@13871: (setsum (%x. ((x * q) div p)) P_set))"; paulson@13871: apply (rule_tac z1 = "setsum (%x. ((x * p) div q)) Q_set" in paulson@13871: nat_add_distrib [THEN sym]); paulson@13871: by (auto simp add: S1_carda [THEN sym] S2_carda [THEN sym]) paulson@13871: also have "... = nat(((p - 1) div 2) * ((q - 1) div 2))"; paulson@13871: by (auto simp add: pq_sum_prop) paulson@13871: finally show ?thesis .; paulson@13871: qed; paulson@13871: paulson@13871: theorem Quadratic_Reciprocity: paulson@13871: "[| p \ zOdd; p \ zprime; q \ zOdd; q \ zprime; paulson@13871: p \ q |] paulson@13871: ==> (Legendre p q) * (Legendre q p) = paulson@13871: (-1::int)^nat(((p - 1) div 2)*((q - 1) div 2))"; paulson@13871: by (auto simp add: QRTEMP.QR_short zprime_zOdd_eq_grt_2 [THEN sym] paulson@13871: QRTEMP_def) paulson@13871: paulson@13871: end