neuper@48813
|
1 |
header {* GCD for polynomials, implemented using the function package (_FP) *}
|
neuper@48813
|
2 |
|
neuper@48813
|
3 |
theory GCD_Poly_FP
|
neuper@48813
|
4 |
imports "~~/src/HOL/Library/Polynomial" "~~/src/HOL/Number_Theory/Primes"
|
neuper@48813
|
5 |
begin
|
neuper@48813
|
6 |
|
neuper@48813
|
7 |
text {*
|
neuper@48813
|
8 |
This code has been translated from GCD_Poly.thy by Diana Meindl,
|
neuper@48813
|
9 |
who follows Franz Winkler, Polynomial algorithyms in computer algebra, Springer 1996.
|
neuper@48813
|
10 |
Winkler's original identifiers are in test/../gcd_poly_winkler.sml;
|
neuper@48813
|
11 |
test/../gcd_poly.sml documents the changes towards GCD_Poly.thy;
|
neuper@48813
|
12 |
the style of GCD_Poly.thy has been adapted to the function package.
|
neuper@48813
|
13 |
*}
|
neuper@48813
|
14 |
|
neuper@48813
|
15 |
section {* gcd for univariate polynomials *}
|
neuper@48813
|
16 |
|
neuper@48813
|
17 |
subsection {* a variant for div *}
|
neuper@48813
|
18 |
|
neuper@48813
|
19 |
fun div2 :: "int => int => int" (infixl "div2" 70)
|
neuper@48813
|
20 |
where "a div2 b = (if a div b < 0 then (\<bar>a\<bar> div \<bar>b\<bar>) * -1 else a div b)"
|
neuper@48813
|
21 |
text {* Meindl: infix div' ... div' didnt work, infix didnt work *}
|
neuper@48813
|
22 |
|
neuper@48813
|
23 |
text {*"----------- fun div2 -- --------------------------------"*};
|
neuper@48813
|
24 |
value " 5 div2 2" -- "= 2"
|
neuper@48813
|
25 |
value "-5 div2 2" -- "= -2"
|
neuper@48813
|
26 |
value "-5 div2 -2" -- "= 2"
|
neuper@48813
|
27 |
value " 5 div2 -2" -- "= -2"
|
neuper@48813
|
28 |
thm div2.simps -- "?a div2 ?b = (if ?a div ?b < 0 then \<bar>?a\<bar> div \<bar>?b\<bar> * -1 else ?a div ?b)"
|
neuper@48813
|
29 |
|
neuper@48813
|
30 |
text {*"----------- fun INT_GCD --------------------------------"*};
|
neuper@48813
|
31 |
value "gcd (15::int) (6::int)" -- "= 3"
|
neuper@48813
|
32 |
value "gcd (10::int) (3::int)" -- "= 1"
|
neuper@48813
|
33 |
value "gcd (6::int) (24::int)" -- "= 6"
|
neuper@48813
|
34 |
|
neuper@48813
|
35 |
subsection {* modulo calculations for integers *}
|
neuper@48813
|
36 |
|
neuper@48813
|
37 |
function modi :: "int => int => int => int => int"
|
neuper@48813
|
38 |
where "modi r rold m rinv =
|
neuper@48813
|
39 |
(if rinv < m
|
neuper@48813
|
40 |
then
|
neuper@48813
|
41 |
if r mod m = 1
|
neuper@48813
|
42 |
then rinv
|
neuper@48813
|
43 |
else modi (rold * (rinv + 1)) rold m (rinv + 1)
|
neuper@48813
|
44 |
else 0)"
|
neuper@48813
|
45 |
by auto
|
neuper@48813
|
46 |
termination sorry
|
neuper@48813
|
47 |
(* modi is just local for mod_inv *)
|
neuper@48813
|
48 |
fun mod_inv :: "int => int => int"
|
neuper@48813
|
49 |
where "mod_inv r m = modi r r m 1"
|
neuper@48813
|
50 |
|
neuper@48813
|
51 |
text {*"----------- fun mod_inv --------------------------------"*}
|
neuper@48813
|
52 |
value "modi 5 5 7 1" -- "= 3"
|
neuper@48813
|
53 |
value "modi 3 3 7 1" -- "= 5"
|
neuper@48813
|
54 |
value "modi 4 4 339 1" -- "= 85"
|
neuper@48813
|
55 |
|
neuper@48813
|
56 |
value "mod_inv 5 7" -- "= 3"
|
neuper@48813
|
57 |
value "mod_inv 3 7" -- "= 5"
|
neuper@48813
|
58 |
value "mod_inv 4 339" -- "= 85"
|
neuper@48813
|
59 |
|
neuper@48813
|
60 |
fun mod_div :: "int => int => int => int"
|
neuper@48813
|
61 |
where "mod_div a b m = a * (mod_inv b m) mod m"
|
neuper@48813
|
62 |
|
neuper@48813
|
63 |
function root1 :: "int => int => int"
|
neuper@48813
|
64 |
where "root1 a n = (if n * n < a then root1 a (n + 1) else n)"
|
neuper@48813
|
65 |
by auto
|
neuper@48813
|
66 |
termination sorry
|
neuper@48813
|
67 |
(* root1 is only local to approx_root *)
|
neuper@48813
|
68 |
fun approx_root :: "int => int"
|
neuper@48813
|
69 |
where "approx_root a = root1 a 1"
|
neuper@48813
|
70 |
|
neuper@48813
|
71 |
fun chinese_remainder :: "int => int => int => int => int"
|
neuper@48813
|
72 |
where "chinese_remainder r1 m1 r2 m2 =
|
neuper@48813
|
73 |
(r1 mod m1) + ((r2 - (r1 mod m1)) * (mod_inv m1 m2) mod m2) * m1"
|
neuper@48813
|
74 |
|
neuper@48813
|
75 |
text {*"----------- fun chinese_remainder ----------------------"*}
|
neuper@48813
|
76 |
value "chinese_remainder 17 9 3 4 " -- "= 35"
|
neuper@48813
|
77 |
value "chinese_remainder 7 2 6 11" -- "= 17"
|
neuper@48813
|
78 |
|
neuper@48813
|
79 |
subsection {* operations with primes *}
|
neuper@48813
|
80 |
|
neuper@48813
|
81 |
(* assumes: 'primes' contains all of first primes /\ n =< (max primes)^2 *)
|
neuper@48813
|
82 |
fun is_prime :: "int list \<Rightarrow> int \<Rightarrow> bool"
|
neuper@48813
|
83 |
where "is_prime primes n =
|
neuper@48813
|
84 |
(if List.length primes > 0
|
neuper@48813
|
85 |
then
|
neuper@48813
|
86 |
if (n mod (List.hd primes)) = 0
|
neuper@48813
|
87 |
then False
|
neuper@48813
|
88 |
else is_prime (List.tl primes) n
|
neuper@48813
|
89 |
else True)"
|
neuper@48813
|
90 |
|
neuper@48813
|
91 |
value "is_prime [2, 3] 2" -- "= False"
|
neuper@48813
|
92 |
value "is_prime [2, 3] 3" -- "= False"
|
neuper@48813
|
93 |
value "is_prime [2, 3] 4" -- "= False"
|
neuper@48813
|
94 |
value "is_prime [2, 3] 5" -- "= True"
|
neuper@48813
|
95 |
value "is_prime [2, 3] 6" -- "= False"
|
neuper@48813
|
96 |
value "is_prime [2, 3] 25" -- "= True ... because 5 not in list"
|
neuper@48813
|
97 |
|
neuper@48813
|
98 |
(* make_prims is local to make_primes *)
|
neuper@48813
|
99 |
function make_primes :: "int list \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int list"
|
neuper@48813
|
100 |
where "make_primes primes last_p n =
|
neuper@48813
|
101 |
(if (List.nth primes (List.length primes - 1)) < n
|
neuper@48813
|
102 |
then
|
neuper@48813
|
103 |
if is_prime primes (last_p + 2)
|
neuper@48813
|
104 |
then make_primes (primes @ [(last_p + 2)]) (last_p + 2) n
|
neuper@48813
|
105 |
else make_primes primes (last_p + 2) n
|
neuper@48813
|
106 |
else primes)"
|
neuper@48813
|
107 |
by pat_completeness (simp del: is_prime.simps)
|
neuper@48813
|
108 |
termination sorry
|
neuper@48813
|
109 |
|
neuper@48813
|
110 |
(* make_primes :: int \<Rightarrow> int list
|
neuper@48813
|
111 |
make_primes n = [2, 3, 5, 7, .., p_k] -- sloppy formulations
|
neuper@48813
|
112 |
assumes 0 < n
|
neuper@48813
|
113 |
yields SOME k. ([2, 3, 5, 7, .., p_k] contains all primes \<le> p_n) \<and> n \<le> p_k *)
|
neuper@48813
|
114 |
fun primes_upto :: "int \<Rightarrow> int list"
|
neuper@48813
|
115 |
where "primes_upto n = (if n < 3 then [2] else make_primes [2,3] 3 n)"
|
neuper@48813
|
116 |
|
neuper@48813
|
117 |
value "primes_upto 2" -- "[2]"
|
neuper@48813
|
118 |
value "primes_upto 3" -- "[2, 3]"
|
neuper@48813
|
119 |
value "primes_upto 4" -- "[2, 3]"
|
neuper@48813
|
120 |
value "primes_upto 5" -- "[2, 3, 5]"
|
neuper@48813
|
121 |
value "primes_upto 6" -- "[2, 3, 5, 7]"
|
neuper@48813
|
122 |
value "primes_upto 7" -- "[2, 3, 5, 7]"
|
neuper@48813
|
123 |
value "primes_upto 8" -- "[2, 3, 5, 7, 11]"
|
neuper@48813
|
124 |
value "primes_upto 9" -- "[2, 3, 5, 7, 11]"
|
neuper@48813
|
125 |
|
neuper@48813
|
126 |
(*---------------------------------------------------*)
|
neuper@48813
|
127 |
ML {*
|
neuper@48813
|
128 |
val ps = [2,3,5,7,11];
|
neuper@48813
|
129 |
nth ps (List.length ps - 1);
|
neuper@48813
|
130 |
*}
|
neuper@48813
|
131 |
thm primes_upto.simps
|
neuper@48813
|
132 |
thm primes_upto_def
|
neuper@48813
|
133 |
|
neuper@48813
|
134 |
(*---------------------------------------------------*)
|
neuper@48813
|
135 |
|
neuper@48813
|
136 |
text {*
|
neuper@48813
|
137 |
:
|
neuper@48813
|
138 |
by pat_completeness (simp del: is_prime.simps)
|
neuper@48813
|
139 |
by pat_completeness (simp del: primes_upto.simps)
|
neuper@48813
|
140 |
by pat_completeness (simp del: primes_upto.simps,is_prime.simps)
|
neuper@48813
|
141 |
by pat_completeness (simp (no_asm))
|
neuper@48813
|
142 |
by simp
|
neuper@48813
|
143 |
by pat_completeness auto
|
neuper@48813
|
144 |
by pat_completeness force
|
neuper@48813
|
145 |
by pat_completeness blast
|
neuper@48813
|
146 |
:
|
neuper@48813
|
147 |
|
neuper@48813
|
148 |
function next_prime_not_dividing :: "int \<Rightarrow> int \<Rightarrow> int" (infixl "next'_prime'_not'_dividing" 70)
|
neuper@48813
|
149 |
where "p next_prime_not_dividing n =
|
neuper@48813
|
150 |
(let
|
neuper@48813
|
151 |
ps = primes_upto (p + 1);
|
neuper@48813
|
152 |
nxt = nth ps (List.length ps - 1)
|
neuper@48813
|
153 |
in
|
neuper@48813
|
154 |
if n mod nxt \<noteq> 0
|
neuper@48813
|
155 |
then nxt
|
neuper@48813
|
156 |
else nxt next_prime_not_dividing n)"
|
neuper@48813
|
157 |
using [[simp_trace_depth_limit=999]]
|
neuper@48813
|
158 |
using [[simp_trace=true]]
|
neuper@48813
|
159 |
by (simp del: primes_upto.simps is_prime.simps)
|
neuper@48813
|
160 |
termination sorry
|
neuper@48813
|
161 |
*}
|
neuper@48813
|
162 |
|
neuper@48813
|
163 |
end
|