(* This program is free software; you can redistribute it and/or      *)
(* modify it under the terms of the GNU Lesser General Public License *)
(* as published by the Free Software Foundation; either version 2.1   *)
(* of the License, or (at your option) any later version.             *)
(*                                                                    *)
(* This program is distributed in the hope that it will be useful,    *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of     *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *)
(* GNU General Public License for more details.                       *)
(*                                                                    *)
(* You should have received a copy of the GNU Lesser General Public   *)
(* License along with this program; if not, write to the Free         *)
(* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *)
(* 02110-1301 USA                                                     *)
Require Export MiscRsa.
(******************************************************************************)
Inductive divides : nat -> nat -> Prop :=
dividesDef : forall a b q : nat, b = q * a -> divides a b.
intros a; apply dividesDef with (q := 1); auto with arith.
Qed.
intros x y; case x; case y; auto.
left; apply dividesDef with (q := 0); auto.
intros n; right; red in |- *; intros H'; inversion_clear H'.
rewrite (mult_comm q 0) in H; discriminate.
intros n; left; apply dividesDef with (q := 0); auto.
intros x' y'; case (divides_dec' (S x') (S y')); auto.
intros H'; left; apply div_divides; auto.
intros H'; right; red in |- *; intros H'0; case H'; auto.
inversion H'0.
exists q; auto.
apply is_div_def; auto with arith.
rewrite H; auto with arith.
Qed.
intros a b; case b.
intros H'; case H'; auto.
intros n H' H'0; inversion_clear H'0.
rewrite H; generalize H; case q; simpl in |- *; auto with arith; intros;
discriminate.
Qed.
intros a b H'1 H'2; red in |- *; intros H'3; absurd (a <= b); auto with arith.
apply divides_le; auto.
apply sym_not_eq; auto with arith.
Qed.
(********************************************************************)
Inductive prime : nat -> Prop :=
primeDef :
forall a : nat,
a <> 1 -> (forall b : nat, divides b a -> b <> 1 -> a = b) -> prime a.
Hint Resolve div_ref all_divides_O SO_divides_all not_prime_O not_prime_1.
(**********************************************************************)
Inductive is_gcd (a b c : nat) : Prop :=
is_gcd_intro :
divides c a ->
divides c b ->
(forall d : nat, divides d a -> divides d b -> divides d c) ->
is_gcd a b c.
intros a b c H; inversion_clear H; intros.
apply is_gcd_intro; auto.
Qed.
intros a.
apply is_gcd_intro; auto.
Qed.
intros a.
apply is_gcd_intro; auto.
Qed.
intros p n H' H'0.
apply is_gcd_intro; auto.
intros d H'1 H'2.
inversion_clear H'.
elim (eq_nat_dec d 1); intros H'4; auto.
rewrite H'4; auto.
elim (eq_nat_dec p d); intros H'5; auto.
case H'0; try rewrite H'5; auto.
case H'5; apply H0; auto.
Qed.
Inductive gcd_spec : nat -> nat -> nat -> Prop :=
| gcd_spec_ex0 : forall a : nat, gcd_spec a 0 a
| gcd_spec_ex1 : forall b : nat, gcd_spec 0 b b
| gcd_spec_ex2 :
forall a b c : nat, a < b -> gcd_spec a (b - a) c -> gcd_spec a b c
| gcd_spec_ex3 :
forall a b c : nat, b <= a -> gcd_spec (a - b) b c -> gcd_spec a b c.
Hint Resolve gcd_spec_ex0 gcd_spec_ex1.
intros a b c H'; elim H'; auto.
intros a0 b0 c0 H'0 H'1 H'2 H'3.
apply H'2; auto.
rewrite H'3; auto.
intros a0 b0 c0 H'0 H'1 H'2 H'3.
replace a0 with (a0 - b0); auto.
rewrite H'3; auto with arith.
Qed.
intros a b H'.
apply gcd_inv_Or_aux with (b := 0); auto.
Qed.
intros a b c H'; elim H'; auto.
intros a0 b0 c0 H'0 H'1 H'2 H'3.
replace b0 with (b0 - a0); auto.
rewrite H'3; auto with arith.
intros a0 b0 c0 H'0 H'1 H'2 H'3.
apply H'2; auto.
rewrite H'3; auto.
Qed.
intros a b H'.
apply gcd_inv_Ol_aux with (a := 0); auto.
Qed.
Definition gcd' :=
gcd_rec (fun _ _ : nat => nat) (fun x : nat => x)
(fun x : nat => x) (fun x y r : nat => r) (fun x y r : nat => r).
intros a b; pattern b, a in |- *; apply gcd_rec; clear a b.
intros a; exists a; auto.
intros b; exists b; auto.
intros a b Rr; case Rr; intros r Hr; exists r.
apply gcd_spec_ex3; auto with arith.
rewrite plus_comm; rewrite minus_plus; auto; rewrite <- minus_n_n; auto.
intros a b Rr; case Rr; intros r Hr; exists r.
case (zerop a); intros lta.
rewrite lta; simpl in |- *.
rewrite <- (gcd_inv_Or b r); auto.
apply gcd_spec_ex3; auto with arith.
rewrite <- minus_n_n; auto.
rewrite <- lta; auto.
apply gcd_spec_ex2; auto with arith.
pattern b at 1 in |- *; replace b with (0 + b); auto with arith.
rewrite plus_comm; rewrite minus_plus; auto; rewrite <- minus_n_n; auto.
Qed.
Definition gcd (a b : nat) := proj1_sig (gcd_ex a b).
Hint Resolve gcd_correct.
intros a b r1 r2 H'; generalize r2; elim H'; clear H' a b r1 r2.
exact gcd_inv_Or.
exact gcd_inv_Ol.
intros a b c H' H'0 H'1 r2 H'2; inversion H'2; auto.
apply H'1; auto.
rewrite <- H0; simpl in |- *; rewrite H1; auto.
apply H'1; auto.
rewrite <- H; simpl in |- *; rewrite <- minus_n_O; rewrite H1; auto.
absurd (a < b); auto with arith.
intros a b c H' H'0 H'1 r2 H'2; inversion H'2; auto.
apply H'1; auto.
rewrite <- H0; simpl in |- *; rewrite H1; rewrite <- minus_n_O; auto.
apply H'1; auto.
rewrite <- H; simpl in |- *; rewrite H1; auto.
absurd (a < b); auto with arith.
Qed.
intros; apply L_Euclides with a; auto.
apply is_gcd_sym.
apply prime_gcd; auto.
Qed.

Lemma L_Euclides2 :
forall p a b : nat,
prime p -> divides p (a * b) -> divides p a \/ divides p b.