Timings for Znumtheory.v

  1. /home/gitlab-runner/builds/v6HyzL39/0/coq/coq/_bench/opam.OLD/ocaml-OLD/.opam-switch/build/coq-stdlib.dev/_build/default/theories//./ZArith/Znumtheory.timing
  2. /home/gitlab-runner/builds/v6HyzL39/0/coq/coq/_bench/opam.NEW/ocaml-NEW/.opam-switch/build/coq-stdlib.dev/_build/default/theories//./ZArith/Znumtheory.timing
(************************************************************************) (* * The Coq Proof Assistant / The Coq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* <O___,, * (see version control and CREDITS file for authors & dates) *) (* \VV/ **************************************************************) (* // * This file is distributed under the terms of the *) (* * GNU Lesser General Public License Version 2.1 *) (* * (see LICENSE file for the text of the license) *) (************************************************************************)
Require Import ZArith_base.
Require Import ZArithRing.
Require Import Zcomplements.
Require Import Zdiv.
Require Import Wf_nat.
(** For compatibility reasons, this Open Scope isn't local as it should *)
Open Scope Z_scope.
Local Ltac Tauto.intuition_solver ::= auto with zarith.
(** This file contains some notions of number theory upon Z numbers: - a divisibility predicate [Z.divide] - a gcd predicate [gcd] - Euclid algorithm [extgcd] - a relatively prime predicate [rel_prime] - a prime predicate [prime] - properties of the efficient [Z.gcd] function *) (** The former specialized inductive predicate [Z.divide] is now a generic existential predicate. *) (** Its former constructor is now a pseudo-constructor. *)
Definition Zdivide_intro a b q (H:b=q*a) : Z.divide a b := ex_intro _ q H.
(** Results concerning divisibility*)
Notation Zone_divide := Z.divide_1_l (only parsing).
Notation Zdivide_0 := Z.divide_0_r (only parsing).
Notation Zmult_divide_compat_l := Z.mul_divide_mono_l (only parsing).
Notation Zmult_divide_compat_r := Z.mul_divide_mono_r (only parsing).
Notation Zdivide_plus_r := Z.divide_add_r (only parsing).
Notation Zdivide_minus_l := Z.divide_sub_r (only parsing).
Notation Zdivide_mult_l := Z.divide_mul_l (only parsing).
Notation Zdivide_mult_r := Z.divide_mul_r (only parsing).
Notation Zdivide_factor_r := Z.divide_factor_l (only parsing).
Notation Zdivide_factor_l := Z.divide_factor_r (only parsing).
Lemma Zdivide_opp_r a b : (a | b) -> (a | - b).
Proof.
apply Z.divide_opp_r.
Qed.
Lemma Zdivide_opp_r_rev a b : (a | - b) -> (a | b).
Proof.
apply Z.divide_opp_r.
Qed.
Lemma Zdivide_opp_l a b : (a | b) -> (- a | b).
Proof.
apply Z.divide_opp_l.
Qed.
Lemma Zdivide_opp_l_rev a b : (- a | b) -> (a | b).
Proof.
apply Z.divide_opp_l.
Qed.
Theorem Zdivide_Zabs_l a b : (Z.abs a | b) -> (a | b).
Proof.
apply Z.divide_abs_l.
Qed.
Theorem Zdivide_Zabs_inv_l a b : (a | b) -> (Z.abs a | b).
Proof.
apply Z.divide_abs_l.
Qed.
#[global] Hint Resolve Z.divide_refl Z.divide_1_l Z.divide_0_r: zarith.
#[global] Hint Resolve Z.mul_divide_mono_l Z.mul_divide_mono_r: zarith.
#[global] Hint Resolve Z.divide_add_r Zdivide_opp_r Zdivide_opp_r_rev Zdivide_opp_l Zdivide_opp_l_rev Z.divide_sub_r Z.divide_mul_l Z.divide_mul_r Z.divide_factor_l Z.divide_factor_r: zarith.
(** Auxiliary result. *)
Lemma Zmult_one x y : x >= 0 -> x * y = 1 -> x = 1.
Proof.
Z.swap_greater.
apply Z.eq_mul_1_nonneg.
Qed.
(** Only [1] and [-1] divide [1]. *)
Notation Zdivide_1 := Z.divide_1_r (only parsing).
(** If [a] divides [b] and [b<>0] then [|a| <= |b|]. *)
Lemma Zdivide_bounds a b : (a | b) -> b <> 0 -> Z.abs a <= Z.abs b.
Proof.
intros H Hb.
rewrite <- Z.divide_abs_l, <- Z.divide_abs_r in H.
apply Z.abs_pos in Hb.
now apply Z.divide_pos_le.
Qed.
(** [Z.divide] can be expressed using [Z.modulo]. *)
Lemma Zmod_divide : forall a b, b<>0 -> a mod b = 0 -> (b | a).
Proof.
apply Z.mod_divide.
Qed.
Lemma Zdivide_mod : forall a b, (b | a) -> a mod b = 0.
Proof.
intros a b (c,->); apply Z_mod_mult.
Qed.
(** [Z.divide] is hence decidable *)
Lemma Zdivide_dec a b : {(a | b)} + {~ (a | b)}.
Proof.
destruct (Z.eq_dec a 0) as [Ha|Ha].
-
destruct (Z.eq_dec b 0) as [Hb|Hb].
+
left; subst; apply Z.divide_0_r.
+
right.
subst.
contradict Hb.
now apply Z.divide_0_l.
-
destruct (Z.eq_dec (b mod a) 0).
+
left.
now apply Z.mod_divide.
+
right.
now rewrite <- Z.mod_divide.
Defined.
Lemma Z_lt_neq {x y: Z} : x < y -> y <> x.
Proof.
auto using Z.lt_neq, Z.neq_sym.
Qed.
Theorem Zdivide_Zdiv_eq a b : 0 < a -> (a | b) -> b = a * (b / a).
Proof.
intros Ha H.
rewrite (Z.div_mod b a) at 1.
+
rewrite Zdivide_mod; auto with zarith.
+
auto using Z_lt_neq.
Qed.
Theorem Zdivide_Zdiv_eq_2 a b c : 0 < a -> (a | b) -> (c * b) / a = c * (b / a).
Proof.
intros.
apply Z.divide_div_mul_exact.
+
now apply Z_lt_neq.
+
auto with zarith.
Qed.
Theorem Zdivide_le: forall a b : Z, 0 <= a -> 0 < b -> (a | b) -> a <= b.
Proof.
intros.
now apply Z.divide_pos_le.
Qed.
Theorem Zdivide_Zdiv_lt_pos a b : 1 < a -> 0 < b -> (a | b) -> 0 < b / a < b .
Proof.
intros H1 H2 H3.
assert (0 < a) by (now transitivity 1).
split.
+
apply Z.mul_pos_cancel_l with a; auto.
rewrite <- Zdivide_Zdiv_eq; auto.
+
now apply Z.div_lt.
Qed.
Lemma Zmod_div_mod n m a: 0 < n -> 0 < m -> (n | m) -> a mod n = (a mod m) mod n.
Proof with auto using Z_lt_neq.
intros H1 H2 (p,Hp).
rewrite (Z.div_mod a m) at 1...
rewrite Hp at 1.
rewrite Z.mul_shuffle0, Z.add_comm, Z.mod_add...
Qed.
Lemma Zmod_divide_minus a b c: 0 < b -> a mod b = c -> (b | a - c).
Proof with auto using Z_lt_neq.
intros H H1.
apply Z.mod_divide...
rewrite Zminus_mod.
rewrite H1.
rewrite <- (Z.mod_small c b) at 1.
-
rewrite Z.sub_diag, Z.mod_0_l...
-
subst.
now apply Z.mod_pos_bound.
Qed.
Lemma Zdivide_mod_minus a b c: 0 <= c < b -> (b | a - c) -> a mod b = c.
Proof.
intros (H1, H2) H3.
assert (0 < b) by Z.order.
assert (b <> 0) by now apply Z_lt_neq.
replace a with ((a - c) + c) by ring.
rewrite Z.add_mod; auto.
rewrite (Zdivide_mod (a-c) b); try rewrite Z.add_0_l; auto.
rewrite Z.mod_mod; try apply Zmod_small; auto.
Qed.
(** * Greatest common divisor (gcd). *) (** There is no unicity of the gcd; hence we define the predicate [Zis_gcd a b g] expressing that [g] is a gcd of [a] and [b]. (We show later that the [gcd] is actually unique if we discard its sign.) *)
Inductive Zis_gcd (a b g:Z) : Prop := Zis_gcd_intro : (g | a) -> (g | b) -> (forall x, (x | a) -> (x | b) -> (x | g)) -> Zis_gcd a b g.
Lemma Zgcd_is_gcd : forall a b, Zis_gcd a b (Z.gcd a b).
Proof.
constructor.
-
apply Z.gcd_divide_l.
-
apply Z.gcd_divide_r.
-
apply Z.gcd_greatest.
Qed.
(** Trivial properties of [gcd] *)
Lemma Zis_gcd_sym : forall a b d, Zis_gcd a b d -> Zis_gcd b a d.
Proof.
induction 1; constructor; intuition.
Qed.
Lemma Zis_gcd_0 : forall a, Zis_gcd a 0 a.
Proof.
constructor; auto with zarith.
Qed.
Lemma Zis_gcd_1 : forall a, Zis_gcd a 1 1.
Proof.
constructor; auto with zarith.
Qed.
Lemma Zis_gcd_refl : forall a, Zis_gcd a a a.
Proof.
constructor; auto with zarith.
Qed.
Lemma Zis_gcd_minus : forall a b d, Zis_gcd a (- b) d -> Zis_gcd b a d.
Proof.
induction 1; constructor; intuition.
Qed.
Lemma Zis_gcd_opp : forall a b d, Zis_gcd a b d -> Zis_gcd b a (- d).
Proof.
induction 1; constructor; intuition.
Qed.
Lemma Zis_gcd_0_abs a : Zis_gcd 0 a (Z.abs a).
Proof.
apply Zabs_ind.
-
intros; apply Zis_gcd_sym; apply Zis_gcd_0; auto.
-
intros; apply Zis_gcd_opp; apply Zis_gcd_0; auto.
Qed.
#[global] Hint Resolve Zis_gcd_sym Zis_gcd_0 Zis_gcd_minus Zis_gcd_opp: zarith.
Theorem Zis_gcd_unique: forall a b c d : Z, Zis_gcd a b c -> Zis_gcd a b d -> c = d \/ c = (- d).
Proof.
intros a b c d [Hc1 Hc2 Hc3] [Hd1 Hd2 Hd3].
assert (c|d) by auto.
assert (d|c) by auto.
apply Z.divide_antisym; auto.
Qed.
(** * Extended Euclid algorithm. *)
Lemma deprecated_Zis_gcd_for_euclid : forall a b d q:Z, Zis_gcd b (a - q * b) d -> Zis_gcd a b d.
Proof.
intros a b d q; simple induction 1; constructor; intuition.
replace a with (a - q * b + q * b).
-
auto with zarith.
-
ring.
Qed.
#[deprecated(since="8.17")] Notation Zis_gcd_for_euclid := deprecated_Zis_gcd_for_euclid (only parsing).
(* this lemma is still used below and in Zgcd_alt *)
Lemma Zis_gcd_for_euclid2 : forall b d q r:Z, Zis_gcd r b d -> Zis_gcd b (b * q + r) d.
Proof.
intros b d q r; destruct 1 as [? ? H]; constructor; intuition.
apply H; auto.
replace r with (b * q + r - b * q).
-
auto with zarith.
-
ring.
Qed.
(** We implement the extended version of Euclid's algorithm, i.e. the one computing Bezout's coefficients as it computes the [gcd]. We follow the algorithm given in Knuth's "Art of Computer Programming", vol 2, page 325. *)
Section extended_euclid_algorithm.
Variables a b : Z.
Local Lemma extgcd_rec_helper r1 r2 q : Z.gcd r1 r2 = Z.gcd a b -> Z.gcd (r2 - q * r1) r1 = Z.gcd a b.
Proof.
intros H; rewrite <-H, Z.gcd_comm.
rewrite <-(Z.gcd_add_mult_diag_r r1 r2 (-q)).
f_equal; ring.
Qed.
Let f := S(S(Z.to_nat(Z.log2_up(Z.log2_up(Z.abs(a*b)))))).
(* log2(fuel) *)
Local Definition extgcd_rec : forall r1 u1 v1 r2 u2 v2, (True -> 0 <= r1 /\ 0 <= r2 /\ r1 = u1 * a + v1 * b /\ r2 = u2 * a + v2 * b /\ Z.gcd r1 r2 = Z.gcd a b) -> { '(u, v, d) | True -> u * a + v * b = d /\ d = Z.gcd a b}.
Proof.
refine (Fix (Acc_intro_generator f (Z.lt_wf 0)) _ (fun r1 rec u1 v1 r2 u2 v2 H => if Z.eq_dec r1 0 then exist (fun '(u, v, d) => _) (u2, v2, r2) (fun _ => _) else let q := r2 / r1 in rec (r2 - q * r1) _ (u2 - q * u1) (v2 - q * v1) r1 u1 v1 (fun _ => _))).
all : abstract (intuition (solve [ subst; rewrite ?Z.gcd_0_l_nonneg in *; auto using extgcd_rec_helper; ring | subst q; rewrite <-Zmod_eq_full by trivial; apply Z.mod_pos_bound, Z.le_neq; intuition congruence ])).
Defined.
Definition extgcd : Z*Z*Z.
Proof.
refine (proj1_sig (extgcd_rec (Z.abs a) (Z.sgn a) 0 (Z.abs b) 0 (Z.sgn b) _)).
abstract (intuition (trivial using Z.abs_nonneg; rewrite ?Z.gcd_abs_r, ?Z.gcd_abs_l, <-?Z.sgn_abs; ring)).
Defined.
Lemma extgcd_correct [u v d] : extgcd = (u, v, d) -> u * a + v * b = d /\ d = Z.gcd a b.
Proof.
cbv [extgcd proj1_sig].
case extgcd_rec as (([],?),?).
intuition congruence.
Qed.
Inductive deprecated_Euclid : Set := deprecated_Euclid_intro : forall u v d:Z, u * a + v * b = d -> Zis_gcd a b d -> deprecated_Euclid.
Lemma deprecated_euclid : deprecated_Euclid.
Proof.
case extgcd as [[]?] eqn:H; case (extgcd_correct H); esplit; subst; eauto using Zgcd_is_gcd.
Qed.
Lemma deprecated_euclid_rec : forall v3:Z, 0 <= v3 -> forall u1 u2 u3 v1 v2:Z, u1 * a + u2 * b = u3 -> v1 * a + v2 * b = v3 -> (forall d:Z, Zis_gcd u3 v3 d -> Zis_gcd a b d) -> deprecated_Euclid.
Proof.
intros; apply deprecated_euclid.
Qed.
End extended_euclid_algorithm.
#[deprecated(since="8.17", note="Use Coq.ZArith.Znumtheory.extgcd")] Notation Euclid := deprecated_Euclid (only parsing).
#[deprecated(since="8.17", note="Use Coq.ZArith.Znumtheory.extgcd")] Notation Euclid_intro := deprecated_Euclid_intro (only parsing).
#[deprecated(since="8.17", note="Use Coq.ZArith.Znumtheory.extgcd")] Notation euclid := deprecated_euclid (only parsing).
#[deprecated(since="8.17", note="Use Coq.ZArith.Znumtheory.extgcd")] Notation euclid_rec := deprecated_euclid_rec (only parsing).
Theorem Zis_gcd_uniqueness_apart_sign : forall a b d d':Z, Zis_gcd a b d -> Zis_gcd a b d' -> d = d' \/ d = - d'.
Proof.
intros a b d d'; simple induction 1.
intros H1 H2 H3; destruct 1 as [H4 H5 H6].
generalize (H3 d' H4 H5); intro Hd'd.
generalize (H6 d H1 H2); intro Hdd'.
exact (Z.divide_antisym d d' Hdd' Hd'd).
Qed.
(** * Bezout's coefficients *)
Inductive Bezout (a b d:Z) : Prop := Bezout_intro : forall u v:Z, u * a + v * b = d -> Bezout a b d.
(** Existence of Bezout's coefficients for the [gcd] of [a] and [b] *)
Lemma Zis_gcd_bezout : forall a b d:Z, Zis_gcd a b d -> Bezout a b d.
Proof.
intros a b d Hgcd.
case (extgcd a b) as [[u v] g] eqn:E, (extgcd_correct _ _ E) as [G ?Hg].
destruct (Zis_gcd_uniqueness_apart_sign a b d g Hgcd ltac:(rewrite Hg; apply Zgcd_is_gcd)); subst; (apply Bezout_intro with u v + apply Bezout_intro with (- u) (- v)); ring.
Qed.
(** gcd of [ca] and [cb] is [c gcd(a,b)]. *)
Lemma Zis_gcd_mult : forall a b c d:Z, Zis_gcd a b d -> Zis_gcd (c * a) (c * b) (c * d).
Proof.
intros a b c d; intro H; generalize H; simple induction 1.
constructor; auto with zarith.
intros x Ha Hb.
elim (Zis_gcd_bezout a b d H).
intros u v Huv.
elim Ha; intros a' Ha'.
elim Hb; intros b' Hb'.
apply Zdivide_intro with (u * a' + v * b').
rewrite <- Huv.
replace (c * (u * a + v * b)) with (u * (c * a) + v * (c * b)).
-
rewrite Ha'; rewrite Hb'; ring.
-
ring.
Qed.
(** * Relative primality *)
Definition rel_prime (a b:Z) : Prop := Zis_gcd a b 1.
(** Bezout's theorem: [a] and [b] are relatively prime if and only if there exist [u] and [v] such that [ua+vb = 1]. *)
Lemma rel_prime_bezout : forall a b:Z, rel_prime a b -> Bezout a b 1.
Proof.
intros a b; exact (Zis_gcd_bezout a b 1).
Qed.
Lemma bezout_rel_prime : forall a b:Z, Bezout a b 1 -> rel_prime a b.
Proof.
simple induction 1; intros ? ? H0; constructor; auto with zarith.
intros.
rewrite <- H0; auto with zarith.
Qed.
(** Gauss's theorem: if [a] divides [bc] and if [a] and [b] are relatively prime, then [a] divides [c]. *)
Theorem Gauss : forall a b c:Z, (a | b * c) -> rel_prime a b -> (a | c).
Proof.
intros a b c H H0.
elim (rel_prime_bezout a b H0); intros u v H1.
replace c with (c * 1); [ idtac | ring ].
rewrite <- H1.
replace (c * (u * a + v * b)) with (c * u * a + v * (b * c)); [ eauto with zarith | ring ].
Qed.
(** If [a] is relatively prime to [b] and [c], then it is to [bc] *)
Lemma rel_prime_mult : forall a b c:Z, rel_prime a b -> rel_prime a c -> rel_prime a (b * c).
Proof.
intros a b c Hb Hc.
elim (rel_prime_bezout a b Hb); intros u v H.
elim (rel_prime_bezout a c Hc); intros u0 v0 H0.
apply bezout_rel_prime.
apply (Bezout_intro _ _ _ (u * u0 * a + v0 * c * u + u0 * v * b) (v * v0)).
rewrite <- H.
replace (u * a + v * b) with ((u * a + v * b) * 1); [ idtac | ring ].
rewrite <- H0.
ring.
Qed.
Lemma rel_prime_cross_prod : forall a b c d:Z, rel_prime a b -> rel_prime c d -> b > 0 -> d > 0 -> a * d = b * c -> a = c /\ b = d.
Proof.
intros a b c d; intros H H0 H1 H2 H3.
elim (Z.divide_antisym b d).
-
intros H4; split; auto with zarith.
rewrite H4 in H3.
rewrite Z.mul_comm in H3.
apply Z.mul_reg_l with d; auto.
contradict H2; rewrite H2; discriminate.
-
intros H4; contradict H1; rewrite H4.
apply Zgt_asym, Z.lt_gt, Z.opp_lt_mono.
now rewrite Z.opp_involutive; apply Z.gt_lt.
-
apply Gauss with a.
+
rewrite H3; auto with zarith.
+
now apply Zis_gcd_sym.
-
apply Gauss with c.
+
rewrite Z.mul_comm.
rewrite <- H3.
auto with zarith.
+
now apply Zis_gcd_sym.
Qed.
(** After factorization by a gcd, the original numbers are relatively prime. *)
Lemma Zis_gcd_rel_prime : forall a b g:Z, b > 0 -> g >= 0 -> Zis_gcd a b g -> rel_prime (a / g) (b / g).
Proof.
intros a b g; intros H H0 H1.
assert (H2 : g <> 0) by (intro H2; elim H1; intros ? H4 ?; elim H4; intros ? H6; rewrite H2 in H6; subst b; contradict H; rewrite Z.mul_0_r; discriminate).
assert (H3 : g > 0) by (apply Z.lt_gt, Z.le_neq; split; try apply Z.ge_le; auto).
unfold rel_prime.
destruct H1 as [Ha Hb Hab].
destruct Ha as [a' Ha'].
destruct Hb as [b' Hb'].
replace (a/g) with a'; [|rewrite Ha'; rewrite Z_div_mult; auto with zarith].
replace (b/g) with b'; [|rewrite Hb'; rewrite Z_div_mult; auto with zarith].
constructor.
-
exists a'; rewrite ?Z.mul_1_r; auto with zarith.
-
exists b'; rewrite ?Z.mul_1_r; auto with zarith.
-
intros x (xa,H5) (xb,H6).
destruct (Hab (x*g)) as (x',Hx').
+
exists xa; rewrite Z.mul_assoc; rewrite <- H5; auto.
+
exists xb; rewrite Z.mul_assoc; rewrite <- H6; auto.
+
replace g with (1*g) in Hx'; auto with zarith.
do 2 rewrite Z.mul_assoc in Hx'.
apply Z.mul_reg_r in Hx'; trivial.
rewrite Z.mul_1_r in Hx'.
exists x'; auto with zarith.
Qed.
Theorem rel_prime_sym: forall a b, rel_prime a b -> rel_prime b a.
Proof.
intros a b H; auto with zarith.
red; apply Zis_gcd_sym; auto with zarith.
Qed.
Theorem rel_prime_div: forall p q r, rel_prime p q -> (r | p) -> rel_prime r q.
Proof.
intros p q r H (u, H1); subst.
inversion_clear H as [H1 H2 H3].
red; apply Zis_gcd_intro; try apply Z.divide_1_l.
intros x H4 H5; apply H3; auto.
apply Z.divide_mul_r; auto.
Qed.
Theorem rel_prime_1: forall n, rel_prime 1 n.
Proof.
intros n; red; apply Zis_gcd_intro; auto.
-
exists 1; reflexivity.
-
exists n; rewrite Z.mul_1_r; reflexivity.
Qed.
Theorem not_rel_prime_0: forall n, 1 < n -> ~ rel_prime 0 n.
Proof.
intros n H H1; absurd (n = 1 \/ n = -1).
-
intros [H2 | H2]; subst; contradict H; discriminate.
-
case (Zis_gcd_unique 0 n n 1); auto.
apply Zis_gcd_intro; auto.
+
exists 0; reflexivity.
+
exists 1; rewrite Z.mul_1_l; reflexivity.
Qed.
Theorem rel_prime_mod: forall p q, 0 < q -> rel_prime p q -> rel_prime (p mod q) q.
Proof.
intros p q H H0.
assert (H1: Bezout p q 1).
-
apply rel_prime_bezout; auto.
-
inversion_clear H1 as [q1 r1 H2].
apply bezout_rel_prime.
apply Bezout_intro with q1 (r1 + q1 * (p / q)).
rewrite <- H2.
pattern p at 3; rewrite (Z_div_mod_eq_full p q); ring.
Qed.
Theorem rel_prime_mod_rev: forall p q, 0 < q -> rel_prime (p mod q) q -> rel_prime p q.
Proof.
intros p q H H0.
rewrite (Z_div_mod_eq_full p q).
red.
apply Zis_gcd_sym; apply Zis_gcd_for_euclid2; auto.
Qed.
Theorem Zrel_prime_neq_mod_0: forall a b, 1 < b -> rel_prime a b -> a mod b <> 0.
Proof.
intros a b H H1 H2.
case (not_rel_prime_0 _ H).
rewrite <- H2.
apply rel_prime_mod; auto.
now transitivity 1.
Qed.
(** * Primality *)
Inductive prime (p:Z) : Prop := prime_intro : 1 < p -> (forall n:Z, 1 <= n < p -> rel_prime n p) -> prime p.
(** The sole divisors of a prime number [p] are [-1], [1], [p] and [-p]. *)
Lemma prime_divisors : forall p:Z, prime p -> forall a:Z, (a | p) -> a = -1 \/ a = 1 \/ a = p \/ a = - p.
Proof.
intros p; destruct 1 as [H H0]; intros a ?.
assert (a = - p \/ - p < a < -1 \/ a = -1 \/ a = 0 \/ a = 1 \/ 1 < a < p \/ a = p).
{
assert (Z.abs a <= Z.abs p) as H2 by (apply Zdivide_bounds; [ assumption | now intros -> ]).
revert H2.
pattern (Z.abs a); apply Zabs_ind; pattern (Z.abs p); apply Zabs_ind; intros H2 H3 H4.
-
destruct (Zle_lt_or_eq _ _ H4) as [H5 | H5]; try intuition.
destruct (Zle_lt_or_eq _ _ (Z.ge_le _ _ H3)) as [H6 | H6]; try intuition.
destruct (Zle_lt_or_eq _ _ (Zlt_le_succ _ _ H6)) as [H7 | H7]; intuition.
-
contradict H2; apply Zlt_not_le; apply Z.lt_trans with (2 := H); red; auto.
-
destruct (Zle_lt_or_eq _ _ H4) as [H5 | H5].
+
destruct (Zle_lt_or_eq _ _ H3) as [H6 | H6]; try intuition.
assert (H7 : a <= Z.pred 0) by (apply Z.lt_le_pred; auto).
destruct (Zle_lt_or_eq _ _ H7) as [H8 | H8]; intuition.
assert (- p < a < -1); try intuition.
now apply Z.opp_lt_mono; rewrite Z.opp_involutive.
+
now left; rewrite <- H5, Z.opp_involutive.
-
contradict H2.
apply Zlt_not_le; apply Z.lt_trans with (2 := H); red; auto.
}
intuition idtac.
(* -p < a < -1 *)
-
match goal with [hyp : a < -1 |- _] => rename hyp into H4 end.
absurd (rel_prime (- a) p).
+
intros [H1p H2p H3p].
assert (- a | - a) by auto with zarith.
assert (- a | p) as H5 by auto with zarith.
apply H3p, Z.divide_1_r in H5; auto with zarith.
destruct H5 as [H5|H5].
*
contradict H4; rewrite <- (Z.opp_involutive a), H5 .
apply Z.lt_irrefl.
*
contradict H4; rewrite <- (Z.opp_involutive a), H5 .
discriminate.
+
apply H0; split.
*
now apply Z.opp_le_mono; rewrite Z.opp_involutive; apply Z.lt_le_incl.
*
now apply Z.opp_lt_mono; rewrite Z.opp_involutive.
(* a = 0 *)
-
match goal with [hyp : a = 0 |- _] => rename hyp into H2 end.
contradict H.
replace p with 0; try discriminate.
now apply sym_equal, Z.divide_0_l; rewrite <-H2.
(* 1 < a < p *)
-
match goal with [hyp : 1 < a |- _] => rename hyp into H3 end.
absurd (rel_prime a p).
+
intros [H1p H2p H3p].
assert (a | a) by auto with zarith.
assert (a | p) as H5 by auto with zarith.
apply H3p, Z.divide_1_r in H5; auto with zarith.
destruct H5 as [H5|H5].
*
contradict H3; rewrite <- (Z.opp_involutive a), H5 .
apply Z.lt_irrefl.
*
contradict H3; rewrite <- (Z.opp_involutive a), H5 .
discriminate.
+
apply H0; split; auto.
now apply Z.lt_le_incl.
Qed.
(** A prime number is relatively prime with any number it does not divide *)
Lemma prime_rel_prime : forall p:Z, prime p -> forall a:Z, ~ (p | a) -> rel_prime p a.
Proof.
intros p H a H0; constructor; auto with zarith; intros ? H1 H2.
apply prime_divisors in H1; intuition; subst; auto with zarith.
-
absurd (p | a); auto with zarith.
-
absurd (p | a); intuition.
Qed.
#[global] Hint Resolve prime_rel_prime: zarith.
(** As a consequence, a prime number is relatively prime with smaller numbers *)
Theorem rel_prime_le_prime: forall a p, prime p -> 1 <= a < p -> rel_prime a p.
Proof.
intros a p Hp [H1 H2].
apply rel_prime_sym; apply prime_rel_prime; auto.
intros [q Hq]; subst a.
destruct Hp as [H3 H4].
contradict H2; apply Zle_not_lt.
rewrite <- (Z.mul_1_l p) at 1.
apply Zmult_le_compat_r.
-
apply (Zlt_le_succ 0).
apply Zmult_lt_0_reg_r with p.
+
apply Z.le_succ_l, Z.lt_le_incl; auto.
+
now apply Z.le_succ_l.
-
apply Z.lt_le_incl, Z.le_succ_l, Z.lt_le_incl; auto.
Qed.
(** If a prime [p] divides [ab] then it divides either [a] or [b] *)
Lemma prime_mult : forall p:Z, prime p -> forall a b:Z, (p | a * b) -> (p | a) \/ (p | b).
Proof.
intro p; simple induction 1; intros ? ? a b ?.
case (Zdivide_dec p a); intuition.
right; apply Gauss with a; auto with zarith.
Qed.
Lemma not_prime_0: ~ prime 0.
Proof.
intros H1; case (prime_divisors _ H1 2); auto with zarith; intuition; discriminate.
Qed.
Lemma not_prime_1: ~ prime 1.
Proof.
intros H1; absurd (1 < 1).
-
discriminate.
-
inversion H1; auto.
Qed.
Lemma prime_2: prime 2.
Proof.
apply prime_intro.
-
red; auto.
-
intros n (H,H'); Z.le_elim H; auto with zarith.
+
contradict H'; auto with zarith.
now apply Zle_not_lt, (Zlt_le_succ 1).
+
subst n.
constructor; auto with zarith.
Qed.
Theorem prime_3: prime 3.
Proof.
apply prime_intro; auto with zarith.
-
red; auto.
-
intros n (H,H'); Z.le_elim H; auto with zarith.
+
replace n with 2.
*
constructor; auto with zarith.
intros x (q,Hq) (q',Hq').
exists (q' - q).
ring_simplify.
now rewrite <- Hq, <- Hq'.
*
apply Z.le_antisymm.
++
now apply (Zlt_le_succ 1).
++
now apply (Z.lt_le_pred _ 3).
+
replace n with 1 by trivial.
constructor; auto with zarith.
Qed.
Theorem prime_ge_2 p : prime p -> 2 <= p.
Proof.
now intros (Hp,_); apply (Zlt_le_succ 1).
Qed.
Definition prime' p := 1<p /\ (forall n, 1<n<p -> ~ (n|p)).
Lemma Z_0_1_more x : 0<=x -> x=0 \/ x=1 \/ 1<x.
Proof.
intros H.
Z.le_elim H; auto.
apply Z.le_succ_l in H.
change (1 <= x) in H.
Z.le_elim H; auto.
Qed.
Theorem prime_alt p : prime' p <-> prime p.
Proof.
split; intros (Hp,H).
-
(* prime -> prime' *)
constructor; trivial; intros n Hn.
constructor; auto with zarith; intros x Hxn Hxp.
rewrite <- Z.divide_abs_l in Hxn, Hxp |- *.
assert (Hx := Z.abs_nonneg x).
set (y:=Z.abs x) in *; clearbody y; clear x; rename y into x.
destruct (Z_0_1_more x Hx) as [->|[->|Hx']].
+
exfalso.
apply Z.divide_0_l in Hxn.
absurd (1 <= n).
*
rewrite Hxn; red; auto.
*
intuition.
+
now exists 1.
+
elim (H x); auto.
split; trivial.
apply Z.le_lt_trans with n; try tauto.
apply Z.divide_pos_le; auto with zarith.
apply Z.lt_le_trans with (2 := proj1 Hn); red; auto.
-
(* prime' -> prime *)
constructor; trivial.
intros n Hn Hnp.
case (Zis_gcd_unique n p n 1).
+
constructor; auto with zarith.
+
apply H; auto with zarith.
now intuition; apply Z.lt_le_incl.
+
intros H1; intuition; subst n; discriminate.
+
intros H1; intuition; subst n; discriminate.
Qed.
Theorem square_not_prime: forall a, ~ prime (a * a).
Proof.
intros a Ha.
rewrite <- (Z.abs_square a) in Ha.
assert (H:=Z.abs_nonneg a).
set (b:=Z.abs a) in *; clearbody b; clear a; rename b into a.
rewrite <- prime_alt in Ha; destruct Ha as (Ha,Ha').
assert (H' : 1 < a) by now apply (Z.square_lt_simpl_nonneg 1).
apply (Ha' a).
+
split; trivial.
rewrite <- (Z.mul_1_l a) at 1.
apply Z.mul_lt_mono_pos_r; auto.
apply Z.lt_trans with (2 := H'); red; auto.
+
exists a; auto.
Qed.
Theorem prime_div_prime: forall p q, prime p -> prime q -> (p | q) -> p = q.
Proof.
intros p q H H1 H2; assert (Hp: 0 < p); try apply Z.lt_le_trans with 2; try apply prime_ge_2; auto with zarith.
assert (Hq: 0 < q); try apply Z.lt_le_trans with 2; try apply prime_ge_2; auto with zarith.
case prime_divisors with (2 := H2); auto.
-
intros H4; contradict Hp; subst; discriminate.
-
intros [H4| [H4 | H4]]; subst; auto.
+
contradict H; auto; apply not_prime_1.
+
contradict Hp; apply Zle_not_lt, (Z.opp_le_mono _ 0).
now rewrite Z.opp_involutive; apply Z.lt_le_incl.
Qed.
Notation Zgcd_is_pos := Z.gcd_nonneg (only parsing).
Theorem Zgcd_spec : forall x y : Z, {z : Z | Zis_gcd x y z /\ 0 <= z}.
Proof.
intros x y; exists (Z.gcd x y).
split; [apply Zgcd_is_gcd | apply Z.gcd_nonneg].
Qed.
Theorem Zdivide_Zgcd: forall p q r : Z, (p | q) -> (p | r) -> (p | Z.gcd q r).
Proof.
intros.
now apply Z.gcd_greatest.
Qed.
Theorem Zis_gcd_gcd: forall a b c : Z, 0 <= c -> Zis_gcd a b c -> Z.gcd a b = c.
Proof.
intros a b c H1 H2.
case (Zis_gcd_uniqueness_apart_sign a b c (Z.gcd a b)); auto.
-
apply Zgcd_is_gcd; auto.
-
Z.le_elim H1.
+
generalize (Z.gcd_nonneg a b); auto with zarith.
intros H3 H4; contradict H3.
rewrite <- (Z.opp_involutive (Z.gcd a b)), <- H4.
now apply Zlt_not_le, Z.opp_lt_mono; rewrite Z.opp_involutive.
+
subst.
now case (Z.gcd a b).
Qed.
Notation Zgcd_inv_0_l := Z.gcd_eq_0_l (only parsing).
Notation Zgcd_inv_0_r := Z.gcd_eq_0_r (only parsing).
Theorem Zgcd_div_swap0 : forall a b : Z, 0 < Z.gcd a b -> 0 < b -> (a / Z.gcd a b) * b = a * (b/Z.gcd a b).
Proof.
intros a b Hg Hb.
assert (F := Zgcd_is_gcd a b); inversion F as [F1 F2 F3].
pattern b at 2; rewrite (Zdivide_Zdiv_eq (Z.gcd a b) b); auto.
repeat rewrite Z.mul_assoc; f_equal.
rewrite Z.mul_comm.
rewrite <- Zdivide_Zdiv_eq; auto.
Qed.
Theorem Zgcd_div_swap : forall a b c : Z, 0 < Z.gcd a b -> 0 < b -> (c * a) / Z.gcd a b * b = c * a * (b/Z.gcd a b).
Proof.
intros a b c Hg Hb.
assert (F := Zgcd_is_gcd a b); inversion F as [F1 F2 F3].
pattern b at 2; rewrite (Zdivide_Zdiv_eq (Z.gcd a b) b); auto.
repeat rewrite Z.mul_assoc; f_equal.
rewrite Zdivide_Zdiv_eq_2; auto.
repeat rewrite <- Z.mul_assoc; f_equal.
rewrite Z.mul_comm.
rewrite <- Zdivide_Zdiv_eq; auto.
Qed.
Lemma Zgcd_ass a b c : Z.gcd (Z.gcd a b) c = Z.gcd a (Z.gcd b c).
Proof.
symmetry.
apply Z.gcd_assoc.
Qed.
Notation Zgcd_Zabs := Z.gcd_abs_l (only parsing).
Notation Zgcd_0 := Z.gcd_0_r (only parsing).
Notation Zgcd_1 := Z.gcd_1_r (only parsing).
#[global] Hint Resolve Z.gcd_0_r Z.gcd_1_r : zarith.
Theorem Zgcd_1_rel_prime : forall a b, Z.gcd a b = 1 <-> rel_prime a b.
Proof.
unfold rel_prime; intros a b; split; intro H.
-
rewrite <- H; apply Zgcd_is_gcd.
-
case (Zis_gcd_unique a b (Z.gcd a b) 1); auto.
+
apply Zgcd_is_gcd.
+
intros H2; absurd (0 <= Z.gcd a b); auto with zarith.
*
rewrite H2; red; auto.
*
generalize (Z.gcd_nonneg a b); auto with zarith.
Qed.
Definition rel_prime_dec: forall a b, { rel_prime a b }+{ ~ rel_prime a b }.
Proof.
intros a b; case (Z.eq_dec (Z.gcd a b) 1); intros H1.
-
left; apply -> Zgcd_1_rel_prime; auto.
-
right; contradict H1; apply <- Zgcd_1_rel_prime; auto.
Defined.
Definition prime_dec_aux: forall p m, { forall n, 1 < n < m -> rel_prime n p } + { exists n, 1 < n < m /\ ~ rel_prime n p }.
Proof.
intros p m.
case (Z_lt_dec 1 m); intros H1; [ | left; intros n ?; exfalso; contradict H1; apply Z.lt_trans with n; intuition].
pattern m; apply natlike_rec; auto with zarith.
-
left; intros n ?; exfalso.
absurd (1 < 0); try discriminate.
apply Z.lt_trans with n; intuition.
-
intros x Hx IH; destruct IH as [F|E].
+
destruct (rel_prime_dec x p) as [Y|N].
*
left; intros n [HH1 HH2].
rewrite Z.lt_succ_r in HH2.
Z.le_elim HH2; subst; auto with zarith.
*
case (Z_lt_dec 1 x); intros HH1.
--
right; exists x; split; auto with zarith.
--
left; intros n [HHH1 HHH2]; contradict HHH1; auto with zarith.
apply Zle_not_lt; apply Z.le_trans with x.
++
now apply Zlt_succ_le.
++
now apply Znot_gt_le; contradict HH1; apply Z.gt_lt.
+
right; destruct E as (n,((H0,H2),H3)); exists n; auto with zarith.
-
apply Z.le_trans with (2 := Z.lt_le_incl _ _ H1); discriminate.
Defined.
Definition prime_dec: forall p, { prime p }+{ ~ prime p }.
Proof.
intros p; case (Z_lt_dec 1 p); intros H1.
+
case (prime_dec_aux p p); intros H2.
*
left; apply prime_intro; auto.
intros n (Hn1,Hn2).
Z.le_elim Hn1; auto; subst n.
constructor; auto with zarith.
*
right; intros H3; inversion_clear H3 as [Hp1 Hp2].
case H2; intros n [Hn1 Hn2]; case Hn2; auto with zarith.
now apply Hp2; intuition; apply Z.lt_le_incl.
+
right; intros H3; inversion_clear H3 as [Hp1 Hp2]; case H1; auto.
Defined.
Theorem not_prime_divide: forall p, 1 < p -> ~ prime p -> exists n, 1 < n < p /\ (n | p).
Proof.
intros p Hp Hp1.
case (prime_dec_aux p p); intros H1.
-
elim Hp1; constructor; auto.
intros n (Hn1,Hn2).
Z.le_elim Hn1; auto with zarith.
subst n; constructor; auto with zarith.
-
case H1; intros n (Hn1,Hn2).
destruct (Z_0_1_more _ (Z.gcd_nonneg n p)) as [H|[H|H]].
+
exfalso.
apply Z.gcd_eq_0_l in H.
absurd (1 < n).
*
rewrite H; discriminate.
*
now intuition.
+
elim Hn2.
red.
rewrite <- H.
apply Zgcd_is_gcd.
+
exists (Z.gcd n p); split; [ split; auto | apply Z.gcd_divide_r ].
apply Z.le_lt_trans with n; auto with zarith.
*
apply Z.divide_pos_le; auto with zarith.
--
apply Z.lt_trans with 1; intuition.
--
apply Z.gcd_divide_l.
*
intuition.
Qed.