aboutsummaryrefslogtreecommitdiff
path: root/coqprime/num/Lucas.v
diff options
context:
space:
mode:
Diffstat (limited to 'coqprime/num/Lucas.v')
-rw-r--r--coqprime/num/Lucas.v213
1 files changed, 213 insertions, 0 deletions
diff --git a/coqprime/num/Lucas.v b/coqprime/num/Lucas.v
new file mode 100644
index 000000000..f969dc106
--- /dev/null
+++ b/coqprime/num/Lucas.v
@@ -0,0 +1,213 @@
+
+(*************************************************************)
+(* This file is distributed under the terms of the *)
+(* GNU Lesser General Public License Version 2.1 *)
+(*************************************************************)
+(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *)
+(*************************************************************)
+
+Set Implicit Arguments.
+
+Require Import ZArith Znumtheory Zpow_facts.
+Require Import CyclicAxioms DoubleCyclic BigN Cyclic31 Int31.
+Require Import ZCAux.
+Require Import W.
+Require Import Mod_op.
+Require Import LucasLehmer.
+Require Import Bits.
+Import CyclicAxioms DoubleType DoubleBase.
+
+Open Scope Z_scope.
+
+Section test.
+
+Variable w: Type.
+Variable w_op: ZnZ.Ops w.
+Variable op_spec: ZnZ.Specs w_op.
+Variable p: positive.
+Variable b: w.
+
+Notation "[| x |]" :=
+ (ZnZ.to_Z x) (at level 0, x at level 99).
+
+
+Hypothesis p_more_1: 2 < Zpos p.
+Hypothesis b_p: [|b|] = 2 ^ Zpos p - 1.
+
+Lemma b_pos: 0 < [|b|].
+rewrite b_p; auto with zarith.
+assert (2 ^ 0 < 2 ^ Zpos p); auto with zarith.
+apply Zpower_lt_monotone; auto with zarith.
+rewrite Zpower_0_r in H; auto with zarith.
+Qed.
+
+Hint Resolve b_pos.
+
+Variable m_op: mod_op w.
+Variable m_op_spec: mod_spec w_op b m_op.
+
+Let w2 := m_op.(add_mod) ZnZ.one ZnZ.one.
+
+Lemma w1_b: [|ZnZ.one|] = 1 mod [|b|].
+rewrite ZnZ.spec_1; simpl; auto.
+rewrite Zmod_small; auto with zarith.
+split; auto with zarith.
+rewrite b_p.
+assert (2 ^ 1 < 2 ^ Zpos p); auto with zarith.
+apply Zpower_lt_monotone; auto with zarith.
+rewrite Zpower_1_r in H; auto with zarith.
+Qed.
+
+Lemma w2_b: [|w2|] = 2 mod [|b|].
+unfold w2; rewrite (add_mod_spec m_op_spec _ _ _ _ w1_b w1_b).
+rewrite w1_b; rewrite <- Zplus_mod; auto with zarith.
+Qed.
+
+Let w4 := m_op.(add_mod) w2 w2.
+
+Lemma w4_b: [|w4|] = 4 mod [|b|].
+unfold w4; rewrite (add_mod_spec m_op_spec _ _ _ _ w2_b w2_b).
+rewrite w2_b; rewrite <- Zplus_mod; auto with zarith.
+Qed.
+
+Let square_m2 :=
+ let square := m_op.(square_mod) in
+ let sub := m_op.(sub_mod) in
+ fun x => sub (square x) w2.
+
+Definition lucastest :=
+ ZnZ.to_Z (iter_pos (Pminus p 2) _ square_m2 w4).
+
+Theorem lucastest_aux_correct:
+ forall p1 z n, 0 <= n -> [|z|] = fst (s n) mod (2 ^ Zpos p - 1) ->
+ [|iter_pos p1 _ square_m2 z|] = fst (s (n + Zpos p1)) mod (2 ^ Zpos p - 1).
+intros p1; pattern p1; apply Pind; simpl iter_pos; simpl s; clear p1.
+intros z p1 Hp1 H.
+unfold square_m2.
+rewrite <- b_p in H.
+generalize (square_mod_spec m_op_spec _ _ H); intros H1.
+rewrite (sub_mod_spec m_op_spec _ _ _ _ H1 w2_b).
+rewrite H1; rewrite w2_b; auto with zarith.
+rewrite H; rewrite <- Zmult_mod; auto with zarith.
+rewrite <- Zminus_mod; auto with zarith.
+rewrite sn; simpl; auto with zarith.
+rewrite b_p; auto.
+intros p1 Rec w1 z Hz Hw1.
+rewrite Pplus_one_succ_l; rewrite iter_pos_plus;
+ simpl iter_pos.
+match goal with |- context[square_m2 ?X] =>
+ set (tmp := X); unfold square_m2; unfold tmp; clear tmp
+end.
+generalize (Rec _ _ Hz Hw1); intros H1.
+rewrite <- b_p in H1.
+generalize (square_mod_spec m_op_spec _ _ H1); intros H2.
+rewrite (sub_mod_spec m_op_spec _ _ _ _ H2 w2_b).
+rewrite H2; rewrite w2_b; auto with zarith.
+rewrite H1; rewrite <- Zmult_mod; auto with zarith.
+rewrite <- Zminus_mod; auto with zarith.
+replace (z + Zpos (1 + p1)) with ((z + Zpos p1) + 1); auto with zarith.
+rewrite sn; simpl fst; try rewrite b_p; auto with zarith.
+rewrite Zpos_plus_distr; auto with zarith.
+Qed.
+
+Theorem lucastest_prop: lucastest = fst(s (Zpos p -2)) mod (2 ^ Zpos p - 1).
+unfold lucastest.
+assert (F: 0 <= 0); auto with zarith.
+generalize (lucastest_aux_correct (p -2) w4 F); simpl Zplus;
+ rewrite Zpos_minus; auto with zarith.
+rewrite Zmax_right; auto with zarith.
+intros tmp; apply tmp; clear tmp.
+rewrite <- b_p; simpl; exact w4_b.
+Qed.
+
+Theorem lucastest_prop_cor: lucastest = 0 -> (2 ^ Zpos p - 1 | fst(s (Zpos p - 2)))%Z.
+intros H.
+apply Zmod_divide.
+assert (H1: 2 ^ 1 < 2 ^ Zpos p); auto with zarith.
+apply Zpower_lt_monotone; auto with zarith.
+rewrite Zpower_1_r in H1; auto with zarith.
+apply trans_equal with (2:= H); apply sym_equal; apply lucastest_prop; auto.
+Qed.
+
+Theorem lucastest_prime: lucastest = 0 -> prime (2 ^ Zpos p - 1).
+intros H1; case (prime_dec (2 ^ Zpos p - 1)); auto; intros H2.
+case Zdivide_div_prime_le_square with (2 := H2).
+assert (H3: 2 ^ 1 < 2 ^ Zpos p); auto with zarith.
+apply Zpower_lt_monotone; auto with zarith.
+rewrite Zpower_1_r in H3; auto with zarith.
+intros q (H3, (H4, H5)).
+contradict H5; apply Zlt_not_le.
+generalize q_more_than_square; unfold Mp; intros tmp; apply tmp;
+ auto; clear tmp.
+apply lucastest_prop_cor; auto.
+case (Zle_lt_or_eq 2 q); auto.
+apply prime_ge_2; auto.
+intros H5; subst.
+absurd (2 <= 1); auto with arith.
+apply Zdivide_le; auto with zarith.
+case H4; intros x Hx.
+exists (2 ^ (Zpos p -1) - x).
+rewrite Zmult_minus_distr_r; rewrite <- Hx; unfold Mp.
+pattern 2 at 2; rewrite <- Zpower_1_r; rewrite <- Zpower_exp; auto with zarith.
+replace (Zpos p - 1 + 1) with (Zpos p); auto with zarith.
+Qed.
+
+End test.
+
+Definition znz_of_Z (w: Type) (op: ZnZ.Ops w) z :=
+ match z with
+ | Zpos p => snd (ZnZ.of_pos p)
+ | _ => ZnZ.zero
+ end.
+
+Definition lucas p :=
+ let op := cmk_op (Peano.pred (nat_of_P (get_height 31 p))) in
+ let b := znz_of_Z op (Zpower 2 (Zpos p) - 1) in
+ let zp := znz_of_Z op (Zpos p) in
+ let mod_op := mmake_mod_op op b zp in
+ lucastest op p mod_op.
+
+Theorem lucas_prime:
+ forall p, 2 < Zpos p -> lucas p = 0 -> prime (2 ^ Zpos p - 1).
+unfold lucas; intros p Hp H.
+match type of H with lucastest (cmk_op ?x) ?y ?z = _ =>
+ set (w_op := (cmk_op x)); assert(A1: ZnZ.Specs w_op)
+end.
+unfold w_op; apply cmk_spec.
+assert (F0: Zpos p <= Zpos (ZnZ.digits w_op)).
+unfold w_op, base; rewrite (cmk_op_digits (Peano.pred (nat_of_P (get_height 31 p)))).
+generalize (get_height_correct 31 p).
+replace (Z_of_nat (Peano.pred (nat_of_P (get_height 31 p)))) with
+ ((Zpos (get_height 31 p) - 1) ); auto with zarith.
+rewrite pred_of_minus; rewrite inj_minus1; auto with zarith.
+rewrite <- Zpos_eq_Z_of_nat_o_nat_of_P; auto with zarith.
+generalize (lt_O_nat_of_P (get_height 31 p)); auto with zarith.
+assert (F1: ZnZ.to_Z (znz_of_Z w_op (2 ^ (Zpos p) - 1)) = 2 ^ (Zpos p) - 1).
+assert (F1: 0 < 2 ^ (Zpos p) - 1).
+assert (F2: 2 ^ 0 < 2 ^ (Zpos p)); auto with zarith.
+apply Zpower_lt_monotone; auto with zarith.
+rewrite Zpower_0_r in F2; auto with zarith.
+case_eq (2 ^ (Zpos p) - 1); simpl ZnZ.to_Z.
+intros HH; contradict F1; rewrite HH; auto with zarith.
+2: intros p1 HH; contradict F1; rewrite HH;
+ apply Zle_not_lt; red; simpl; intros; discriminate.
+intros p1 Hp1; apply ZnZ.of_pos_correct; auto.
+rewrite <- Hp1.
+unfold base.
+apply Zlt_le_trans with (2 ^ (Zpos p)); auto with zarith.
+apply Zpower_le_monotone; auto with zarith.
+match type of H with lucastest (cmk_op ?x) ?y ?z = _ =>
+ apply
+ (@lucastest_prime _ _ (cmk_spec x) p (znz_of_Z w_op (2 ^ Zpos p -1)) Hp F1 z)
+end; auto with zarith; fold w_op.
+eapply mmake_mod_spec with (p := p); auto with zarith.
+unfold znz_of_Z; unfold znz_of_Z in F1; rewrite F1.
+assert (F2: 2 ^ 1 < 2 ^ (Zpos p)); auto with zarith.
+apply Zpower_lt_monotone; auto with zarith.
+rewrite Zpower_1_r in F2; auto with zarith.
+rewrite ZnZ.of_Z_correct; auto with zarith.
+split; auto with zarith.
+apply Zle_lt_trans with (1 := F0); auto with zarith.
+unfold base; apply Zpower2_lt_lin; auto with zarith.
+Qed.
+