19 gcd :: "nat \<times> nat => nat" -- {* Euclid's algorithm *} |
19 gcd :: "nat \<times> nat => nat" -- {* Euclid's algorithm *} |
20 |
20 |
21 recdef gcd "measure ((\<lambda>(m, n). n) :: nat \<times> nat => nat)" |
21 recdef gcd "measure ((\<lambda>(m, n). n) :: nat \<times> nat => nat)" |
22 "gcd (m, n) = (if n = 0 then m else gcd (n, m mod n))" |
22 "gcd (m, n) = (if n = 0 then m else gcd (n, m mod n))" |
23 |
23 |
24 constdefs |
24 definition |
25 is_gcd :: "nat => nat => nat => bool" -- {* @{term gcd} as a relation *} |
25 is_gcd :: "nat => nat => nat => bool" -- {* @{term gcd} as a relation *} |
26 "is_gcd p m n == p dvd m \<and> p dvd n \<and> |
26 "is_gcd p m n = (p dvd m \<and> p dvd n \<and> |
27 (\<forall>d. d dvd m \<and> d dvd n --> d dvd p)" |
27 (\<forall>d. d dvd m \<and> d dvd n --> d dvd p))" |
28 |
28 |
29 |
29 |
30 lemma gcd_induct: |
30 lemma gcd_induct: |
31 "(!!m. P m 0) ==> |
31 "(!!m. P m 0) ==> |
32 (!!m n. 0 < n ==> P n (m mod n) ==> P m n) |
32 (!!m n. 0 < n ==> P n (m mod n) ==> P m n) |
36 apply simp_all |
36 apply simp_all |
37 done |
37 done |
38 |
38 |
39 |
39 |
40 lemma gcd_0 [simp]: "gcd (m, 0) = m" |
40 lemma gcd_0 [simp]: "gcd (m, 0) = m" |
41 apply simp |
41 by simp |
42 done |
|
43 |
42 |
44 lemma gcd_non_0: "0 < n ==> gcd (m, n) = gcd (n, m mod n)" |
43 lemma gcd_non_0: "0 < n ==> gcd (m, n) = gcd (n, m mod n)" |
45 apply simp |
44 by simp |
46 done |
|
47 |
45 |
48 declare gcd.simps [simp del] |
46 declare gcd.simps [simp del] |
49 |
47 |
50 lemma gcd_1 [simp]: "gcd (m, Suc 0) = 1" |
48 lemma gcd_1 [simp]: "gcd (m, Suc 0) = 1" |
51 apply (simp add: gcd_non_0) |
49 by (simp add: gcd_non_0) |
52 done |
|
53 |
50 |
54 text {* |
51 text {* |
55 \medskip @{term "gcd (m, n)"} divides @{text m} and @{text n}. The |
52 \medskip @{term "gcd (m, n)"} divides @{text m} and @{text n}. The |
56 conjunctions don't seem provable separately. |
53 conjunctions don't seem provable separately. |
57 *} |
54 *} |
58 |
55 |
59 lemma gcd_dvd1 [iff]: "gcd (m, n) dvd m" |
56 lemma gcd_dvd1 [iff]: "gcd (m, n) dvd m" |
60 and gcd_dvd2 [iff]: "gcd (m, n) dvd n" |
57 and gcd_dvd2 [iff]: "gcd (m, n) dvd n" |
61 apply (induct m n rule: gcd_induct) |
58 apply (induct m n rule: gcd_induct) |
62 apply (simp_all add: gcd_non_0) |
59 apply (simp_all add: gcd_non_0) |
63 apply (blast dest: dvd_mod_imp_dvd) |
60 apply (blast dest: dvd_mod_imp_dvd) |
64 done |
61 done |
65 |
62 |
66 text {* |
63 text {* |
67 \medskip Maximality: for all @{term m}, @{term n}, @{term k} |
64 \medskip Maximality: for all @{term m}, @{term n}, @{term k} |
68 naturals, if @{term k} divides @{term m} and @{term k} divides |
65 naturals, if @{term k} divides @{term m} and @{term k} divides |
69 @{term n} then @{term k} divides @{term "gcd (m, n)"}. |
66 @{term n} then @{term k} divides @{term "gcd (m, n)"}. |
70 *} |
67 *} |
71 |
68 |
72 lemma gcd_greatest: "k dvd m ==> k dvd n ==> k dvd gcd (m, n)" |
69 lemma gcd_greatest: "k dvd m ==> k dvd n ==> k dvd gcd (m, n)" |
73 apply (induct m n rule: gcd_induct) |
70 by (induct m n rule: gcd_induct) (simp_all add: gcd_non_0 dvd_mod) |
74 apply (simp_all add: gcd_non_0 dvd_mod) |
|
75 done |
|
76 |
71 |
77 lemma gcd_greatest_iff [iff]: "(k dvd gcd (m, n)) = (k dvd m \<and> k dvd n)" |
72 lemma gcd_greatest_iff [iff]: "(k dvd gcd (m, n)) = (k dvd m \<and> k dvd n)" |
78 apply (blast intro!: gcd_greatest intro: dvd_trans) |
73 by (blast intro!: gcd_greatest intro: dvd_trans) |
79 done |
|
80 |
74 |
81 lemma gcd_zero: "(gcd (m, n) = 0) = (m = 0 \<and> n = 0)" |
75 lemma gcd_zero: "(gcd (m, n) = 0) = (m = 0 \<and> n = 0)" |
82 by (simp only: dvd_0_left_iff [THEN sym] gcd_greatest_iff) |
76 by (simp only: dvd_0_left_iff [symmetric] gcd_greatest_iff) |
83 |
77 |
84 |
78 |
85 text {* |
79 text {* |
86 \medskip Function gcd yields the Greatest Common Divisor. |
80 \medskip Function gcd yields the Greatest Common Divisor. |
87 *} |
81 *} |