Gauss
un exemple concret
trois cas génériques
Lemma divides_1_n: forall n, 1|n.
Proof.
intros n.
exists n.
ring.
Qed.
Lemma divides_n_n: forall n, n|n.
Proof.
intros n.
exists 1.
ring.
Qed.
Lemma divides_n_0: forall n, n|0.
Proof.
intros n.
exists 0.
ring.
Qed.
lemmes généraux
Lemma divides_transitive: forall n m p, n|p -> p|m -> n|m.
Proof.
intros n m p.
intros Hnp Hpm.
destruct Hnp as [i Hi].
destruct Hpm as [j Hj].
exists (i*j).
rewrite Hj, Hi. ring.
Qed.
Lemma divides_mult_l: forall n m p, n|m -> n|m*p.
Proof. intros n m p [i Hi]. rewrite Hi. exists (i*p). ring. Qed.
Lemma divides_mult_r: forall n m p, n|m -> n|p*m.
Proof. intros n m p. rewrite Zmult_comm. apply divides_mult_l. Qed.
Lemma divides_plus: forall n m p, n|m -> n|p -> n|m+p.
Proof. intros n m p [i ->] [j ->]. exists (i+j). ring. Qed.
Lemma divides_minus: forall n m p, n|m -> n|p -> n|m-p.
Proof. intros n m p [i ->] [j ->]. exists (i-j). ring. Qed.
PGCD
un exemple concret
Lemma is_pgcd_27_36_9: is_pgcd 27 36 9.
Proof.
split. exists 3; reflexivity.
split. exists 4; reflexivity.
intros y [i Hi] [j Hj].
change 9 with (36-27). rewrite Hi, Hj.
auto using divides_minus, divides_mult_l, divides_n_n.
Qed.
trois cas génériques
Lemma is_pgcd_0: forall a, is_pgcd a 0 a.
Proof.
intros a.
split. apply divides_n_n.
split. apply divides_n_0.
intros b [i ->] _. apply divides_mult_l, divides_n_n.
Qed.
Lemma is_pgcd_1: forall a, is_pgcd a 1 1.
Proof.
intros a.
split. apply divides_1_n.
split. apply divides_1_n.
easy.
Qed.
Lemma is_pgcd_idem: forall a, is_pgcd a a a.
Proof.
intros a.
split. apply divides_n_n.
split. apply divides_n_n.
easy.
Qed.
Algorithme d'Euclide étendu
- on calcule une suite de triplets (r{i},u{i},v{i}) par une récurrence de rang 2:
- r{i+1} = r{i-1} mod r{i}
- u{i+1} = u{i-1} - (r{i-1} ÷ r{i}) * u{i}
- v{i+1} = v{i-1} - (r{i-1} ÷ r{i}) * v{i}
- on part de
- r{0} = a, u{0} = 1, v{0} = 0
- r{1} = b, u{1} = 0, v{1} = 1
- on s'arrête quand r{i} = 0: on a alors pgcd(a,b) = r{i-1} = a*u{i-1} + b*v{i-1}
- r,u,v sont les termes de rang {i-1};
- r',u',v' sont les termes de rang {i}.
- q = r ÷ r'
- t = r mod r'
Function Euclid (r u v r' u' v': Z) {measure Zabs_nat r'}: Z*Z*Z :=
if Zeq_bool r' 0 then (r,u,v) else
let (q,t) := Zdiv_eucl r r' in
Euclid r' u' v' t (u-q*u') (v-q*v').
if Zeq_bool r' 0 then (r,u,v) else
let (q,t) := Zdiv_eucl r r' in
Euclid r' u' v' t (u-q*u') (v-q*v').
la preuve suivante correspond à la terminaison de l'algorithme:
la valeur absolue du reste (r') décroit strictement
Proof.
intros r _ _ r' _ _ Hr' q t Hqt.
apply Zeq_bool_neq in Hr'.
apply (Z_div_mod_full r r') in Hr'. rewrite Hqt in Hr'. clear Hqt.
apply proj2, Remainder_equiv in Hr' as [H _].
rewrite <-(Zabs_nat_Zabs t), <-(Zabs_nat_Zabs r').
apply Zabs_nat_lt. auto using Zabs_pos.
Defined.
intros r _ _ r' _ _ Hr' q t Hqt.
apply Zeq_bool_neq in Hr'.
apply (Z_div_mod_full r r') in Hr'. rewrite Hqt in Hr'. clear Hqt.
apply proj2, Remainder_equiv in Hr' as [H _].
rewrite <-(Zabs_nat_Zabs t), <-(Zabs_nat_Zabs r').
apply Zabs_nat_lt. auto using Zabs_pos.
Defined.
le pgcd s'obtient en démarrant l'algorithme avec les bonnes valeurs
on peut vérifier que cette fonction retourne les bons résultats
sur quelques exemples
on démontre un invariant sur les termes de la suite
r = a*u + b*v ->
r' = a*u' + b*v' ->
spec3
(fun r'' u'' v'' => r'' = a*u''+b*v'' /\ r'' | r' /\ r'' | r)
(Euclid r u v r' u' v').
Proof.
intros a b r u v r' u' v'.
functional induction (Euclid r u v r' u' v')
as [?????? H|?????? H q t Hdiv IH]; intros Hr Hr'.
apply Zeq_bool_eq in H. split.
split. apply Hr.
split. rewrite H. apply divides_n_0.
apply divides_n_n.
apply Zeq_bool_neq, (Z_div_mod_full r r') in H.
rewrite Hdiv in H. clear Hdiv. destruct H as [Ht _].
case IH; clear IH.
assumption.
apply Zplus_minus_eq in Ht. rewrite Ht, Hr, Hr'. ring.
intros r'' u'' v'' [IH1 [IH2 IH3]]. split.
rewrite Ht. auto using divides_plus, divides_mult_l.
Qed.
r' = a*u' + b*v' ->
spec3
(fun r'' u'' v'' => r'' = a*u''+b*v'' /\ r'' | r' /\ r'' | r)
(Euclid r u v r' u' v').
Proof.
intros a b r u v r' u' v'.
functional induction (Euclid r u v r' u' v')
as [?????? H|?????? H q t Hdiv IH]; intros Hr Hr'.
apply Zeq_bool_eq in H. split.
split. apply Hr.
split. rewrite H. apply divides_n_0.
apply divides_n_n.
apply Zeq_bool_neq, (Z_div_mod_full r r') in H.
rewrite Hdiv in H. clear Hdiv. destruct H as [Ht _].
case IH; clear IH.
assumption.
apply Zplus_minus_eq in Ht. rewrite Ht, Hr, Hr'. ring.
intros r'' u'' v'' [IH1 [IH2 IH3]]. split.
rewrite Ht. auto using divides_plus, divides_mult_l.
Qed.
On en déduit que la fonction pgcd renvoie bien le pgcd
Theorem pgcd_spec: forall a b, is_pgcd a b (pgcd a b).
Proof.
intros a b. unfold pgcd. case (Euclid_spec a b). ring. ring.
intros r u v [-> [Hra Hrb]].
unfold is_pgcd. auto using divides_plus, divides_mult_l.
Qed.
Theorem Bachet_Bezout: forall a b, exists u, exists v, a*u+b*v = pgcd a b.
Proof.
intros a b. unfold pgcd. case (Euclid_spec a b). ring. ring.
intros r u v [-> _]. exists u, v. easy.
Qed.
Theorem Gauss: forall a b c, pgcd a b = 1 -> a|b*c -> a|c.
Proof.
intros a b c H [i Hi].
destruct (Bachet_Bezout a b) as (u&v&H'). rewrite H in H'.
exists (u*c+v*i).
transitivity (c*(a*u+b*v)).
rewrite H'. ring.
transitivity (c*a*u+b*c*v).
ring.
rewrite Hi. ring.
Qed.
This page has been generated by coqdoc