1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
|
(************************************************************************)
(* * 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) *)
(************************************************************************)
(** Greatest Common Divisor *)
Require Import NZAxioms NZMulOrder.
(** Interface of a gcd function, then its specification on naturals *)
Module Type Gcd (Import A : Typ).
Parameter Inline gcd : t -> t -> t.
End Gcd.
Module Type NZGcdSpec (A : NZOrdAxiomsSig')(B : Gcd A).
Import A B.
Definition divide n m := exists p, m == p*n.
Local Notation "( n | m )" := (divide n m) (at level 0).
Axiom gcd_divide_l : forall n m, (gcd n m | n).
Axiom gcd_divide_r : forall n m, (gcd n m | m).
Axiom gcd_greatest : forall n m p, (p | n) -> (p | m) -> (p | gcd n m).
Axiom gcd_nonneg : forall n m, 0 <= gcd n m.
End NZGcdSpec.
Module Type DivideNotation (A:NZOrdAxiomsSig')(B:Gcd A)(C:NZGcdSpec A B).
Import A B C.
Notation "( n | m )" := (divide n m) (at level 0).
End DivideNotation.
Module Type NZGcd (A : NZOrdAxiomsSig) := Gcd A <+ NZGcdSpec A.
Module Type NZGcd' (A : NZOrdAxiomsSig) :=
Gcd A <+ NZGcdSpec A <+ DivideNotation A.
(** Derived properties of gcd *)
Module NZGcdProp
(Import A : NZOrdAxiomsSig')
(Import B : NZGcd' A)
(Import C : NZMulOrderProp A).
(** Results concerning divisibility*)
#[global]
Instance divide_wd : Proper (eq==>eq==>iff) divide.
Proof.
unfold divide. intros x x' Hx y y' Hy.
setoid_rewrite Hx. setoid_rewrite Hy. easy.
Qed.
Lemma divide_1_l : forall n, (1 | n).
Proof.
intros n. exists n. now nzsimpl.
Qed.
Lemma divide_0_r : forall n, (n | 0).
Proof.
intros n. exists 0. now nzsimpl.
Qed.
Lemma divide_0_l : forall n, (0 | n) -> n==0.
Proof.
intros n (m,Hm). revert Hm. now nzsimpl.
Qed.
Lemma eq_mul_1_nonneg : forall n m,
0<=n -> n*m == 1 -> n==1 /\ m==1.
Proof.
intros n m Hn H.
le_elim Hn.
- destruct (lt_ge_cases m 0) as [Hm|Hm].
+ generalize (mul_pos_neg n m Hn Hm). order'.
+ le_elim Hm.
* apply le_succ_l in Hn. rewrite <- one_succ in Hn.
le_elim Hn.
-- generalize (lt_1_mul_pos n m Hn Hm). order.
-- rewrite <- Hn, mul_1_l in H. now split.
* rewrite <- Hm, mul_0_r in H. order'.
- rewrite <- Hn, mul_0_l in H. order'.
Qed.
Lemma eq_mul_1_nonneg' : forall n m,
0<=m -> n*m == 1 -> n==1 /\ m==1.
Proof.
intros n m Hm H. rewrite mul_comm in H.
now apply and_comm, eq_mul_1_nonneg.
Qed.
Lemma divide_1_r_nonneg : forall n, 0<=n -> (n | 1) -> n==1.
Proof.
intros n Hn (m,Hm). symmetry in Hm.
now apply (eq_mul_1_nonneg' m n).
Qed.
Lemma divide_refl : forall n, (n | n).
Proof.
intros n. exists 1. now nzsimpl.
Qed.
Lemma divide_trans : forall n m p, (n | m) -> (m | p) -> (n | p).
Proof.
intros n m p (q,Hq) (r,Hr). exists (r*q).
now rewrite Hr, Hq, mul_assoc.
Qed.
#[global]
Instance divide_reflexive : Reflexive divide | 5 := divide_refl.
#[global]
Instance divide_transitive : Transitive divide | 5 := divide_trans.
(** Due to sign, no general antisymmetry result *)
Lemma divide_antisym_nonneg : forall n m,
0<=n -> 0<=m -> (n | m) -> (m | n) -> n == m.
Proof.
intros n m Hn Hm (q,Hq) (r,Hr).
le_elim Hn.
- destruct (lt_ge_cases q 0) as [Hq'|Hq'].
+ generalize (mul_neg_pos q n Hq' Hn). order.
+ rewrite Hq, mul_assoc in Hr. symmetry in Hr.
apply mul_id_l in Hr; [|order].
destruct (eq_mul_1_nonneg' r q) as [_ H]; trivial.
now rewrite H, mul_1_l in Hq.
- rewrite <- Hn, mul_0_r in Hq. now rewrite <- Hn.
Qed.
Lemma mul_divide_mono_l : forall n m p, (n | m) -> (p * n | p * m).
Proof.
intros n m p (q,Hq). exists q. now rewrite mul_shuffle3, Hq.
Qed.
Lemma mul_divide_mono_r : forall n m p, (n | m) -> (n * p | m * p).
Proof.
intros n m p (q,Hq). exists q. now rewrite mul_assoc, Hq.
Qed.
Lemma mul_divide_cancel_l : forall n m p, p ~= 0 ->
((p * n | p * m) <-> (n | m)).
Proof.
intros n m p Hp. split.
- intros (q,Hq). exists q. now rewrite mul_shuffle3, mul_cancel_l in Hq.
- apply mul_divide_mono_l.
Qed.
Lemma mul_divide_cancel_r : forall n m p, p ~= 0 ->
((n * p | m * p) <-> (n | m)).
Proof.
intros n m p ?. rewrite 2 (mul_comm _ p). now apply mul_divide_cancel_l.
Qed.
Lemma divide_add_r : forall n m p, (n | m) -> (n | p) -> (n | m + p).
Proof.
intros n m p (q,Hq) (r,Hr). exists (q+r).
now rewrite mul_add_distr_r, Hq, Hr.
Qed.
Lemma divide_mul_l : forall n m p, (n | m) -> (n | m * p).
Proof.
intros n m p (q,Hq). exists (q*p). now rewrite mul_shuffle0, Hq.
Qed.
Lemma divide_mul_r : forall n m p, (n | p) -> (n | m * p).
Proof.
intros n m p. rewrite mul_comm. apply divide_mul_l.
Qed.
Lemma divide_factor_l : forall n m, (n | n * m).
Proof.
intros. apply divide_mul_l, divide_refl.
Qed.
Lemma divide_factor_r : forall n m, (n | m * n).
Proof.
intros. apply divide_mul_r, divide_refl.
Qed.
Lemma divide_pos_le : forall n m, 0 < m -> (n | m) -> n <= m.
Proof.
intros n m Hm (q,Hq).
destruct (le_gt_cases n 0) as [Hn|Hn]. - order.
- rewrite Hq.
destruct (lt_ge_cases q 0) as [Hq'|Hq'].
+ generalize (mul_neg_pos q n Hq' Hn). order.
+ le_elim Hq'.
* rewrite <- (mul_1_l n) at 1. apply mul_le_mono_pos_r; trivial.
now rewrite one_succ, le_succ_l.
* rewrite <- Hq', mul_0_l in Hq. order.
Qed.
(** Basic properties of gcd *)
Lemma gcd_unique : forall n m p,
0<=p -> (p|n) -> (p|m) ->
(forall q, (q|n) -> (q|m) -> (q|p)) ->
gcd n m == p.
Proof.
intros n m p Hp Hn Hm H.
apply divide_antisym_nonneg; trivial. - apply gcd_nonneg.
- apply H. + apply gcd_divide_l. + apply gcd_divide_r.
- now apply gcd_greatest.
Qed.
#[global]
Instance gcd_wd : Proper (eq==>eq==>eq) gcd.
Proof.
intros x x' Hx y y' Hy.
apply gcd_unique.
- apply gcd_nonneg.
- rewrite Hx. apply gcd_divide_l.
- rewrite Hy. apply gcd_divide_r.
- intro. rewrite Hx, Hy. apply gcd_greatest.
Qed.
Lemma gcd_divide_iff : forall n m p,
(p | gcd n m) <-> (p | n) /\ (p | m).
Proof.
intros n m p. split. - split.
+ transitivity (gcd n m); trivial using gcd_divide_l.
+ transitivity (gcd n m); trivial using gcd_divide_r.
- intros (H,H'). now apply gcd_greatest.
Qed.
Lemma gcd_unique_alt : forall n m p, 0<=p ->
(forall q, (q|p) <-> (q|n) /\ (q|m)) ->
gcd n m == p.
Proof.
intros n m p Hp H.
apply gcd_unique; trivial.
- apply H. apply divide_refl.
- apply H. apply divide_refl.
- intros. apply H. now split.
Qed.
Lemma gcd_comm : forall n m, gcd n m == gcd m n.
Proof.
intros. apply gcd_unique_alt; try apply gcd_nonneg.
intros. rewrite and_comm. apply gcd_divide_iff.
Qed.
Lemma gcd_assoc : forall n m p, gcd n (gcd m p) == gcd (gcd n m) p.
Proof.
intros. apply gcd_unique_alt; try apply gcd_nonneg.
intros. now rewrite !gcd_divide_iff, and_assoc.
Qed.
Lemma gcd_0_l_nonneg : forall n, 0<=n -> gcd 0 n == n.
Proof.
intros. apply gcd_unique; trivial.
- apply divide_0_r.
- apply divide_refl.
Qed.
Lemma gcd_0_r_nonneg : forall n, 0<=n -> gcd n 0 == n.
Proof.
intros. now rewrite gcd_comm, gcd_0_l_nonneg.
Qed.
Lemma gcd_1_l : forall n, gcd 1 n == 1.
Proof.
intros. apply gcd_unique; trivial using divide_1_l, le_0_1.
Qed.
Lemma gcd_1_r : forall n, gcd n 1 == 1.
Proof.
intros. now rewrite gcd_comm, gcd_1_l.
Qed.
Lemma gcd_diag_nonneg : forall n, 0<=n -> gcd n n == n.
Proof.
intros. apply gcd_unique; trivial using divide_refl.
Qed.
Lemma gcd_eq_0_l : forall n m, gcd n m == 0 -> n == 0.
Proof.
intros n m H.
generalize (gcd_divide_l n m). rewrite H. apply divide_0_l.
Qed.
Lemma gcd_eq_0_r : forall n m, gcd n m == 0 -> m == 0.
Proof.
intros n m ?. apply gcd_eq_0_l with n. now rewrite gcd_comm.
Qed.
Lemma gcd_eq_0 : forall n m, gcd n m == 0 <-> n == 0 /\ m == 0.
Proof.
intros n m. split.
- split.
+ now apply gcd_eq_0_l with m.
+ now apply gcd_eq_0_r with n.
- intros (EQ,EQ'). rewrite EQ, EQ'. now apply gcd_0_r_nonneg.
Qed.
Lemma gcd_mul_diag_l : forall n m, 0<=n -> gcd n (n*m) == n.
Proof.
intros n m Hn. apply gcd_unique_alt; trivial.
intros q. split. - split; trivial. now apply divide_mul_l.
- now destruct 1.
Qed.
Lemma divide_gcd_iff : forall n m, 0<=n -> ((n|m) <-> gcd n m == n).
Proof.
intros n m Hn. split.
- intros (q,Hq). rewrite Hq.
rewrite mul_comm. now apply gcd_mul_diag_l.
- intros EQ. rewrite <- EQ. apply gcd_divide_r.
Qed.
End NZGcdProp.
|