intermed.
1 header {* GCD for polynomials, implemented using the function package (_FP) *}
4 imports "~~/src/HOL/Library/Polynomial" "~~/src/HOL/Number_Theory/Primes"
8 This code has been translated from GCD_Poly.thy by Diana Meindl,
9 who follows Franz Winkler, Polynomial algorithyms in computer algebra, Springer 1996.
10 Winkler's original identifiers are in test/../gcd_poly_winkler.sml;
11 test/../gcd_poly.sml documents the changes towards GCD_Poly.thy;
12 the style of GCD_Poly.thy has been adapted to the function package.
15 section {* gcd for univariate polynomials *}
17 type_synonym unipoly = "int list"
18 value "[0, 1, 2, 3, 4, 5] :: unipoly"
20 subsection {* a variant for div *}
21 (* 5 div 2 = 2; ~5 div 2 = ~3; but ~5 div2 2 = ~2; *)
22 definition div2 :: "int => int => int" (infixl "div2" 70) where
23 "a div2 b = (if a div b < 0 then (\<bar>a\<bar> div \<bar>b\<bar>) * -1 else a div b)"
24 text {* div' didnt work *}
27 value "-5 div2 2 = -2"
28 value "-5 div2 -2 = 2"
29 value " 5 div2 -2 = -2"
31 value "gcd (15::int) (6::int) = 3"
32 value "gcd (10::int) (3::int) = 1"
33 value "gcd (6::int) (24::int) = 6"
35 subsection {* modulo calculations for integers *}
36 (* modi is just local for mod_inv *)
37 function modi :: "int => int => int => int => int" where
43 else modi (rold * (rinv + 1)) rold m (rinv + 1)
47 (* mod_inv :: int -> nat
50 yields SOME s. r * s mod m = 1 *)
51 fun mod_inv :: "int => int => int" where
52 "mod_inv r m = modi r r m 1"
54 value "modi 5 5 7 1 = 3"
55 value "modi 3 3 7 1 = 5"
56 value "modi 4 4 339 1 = 85"
58 value "mod_inv 5 7 = 3"
59 value "mod_inv 3 7 = 5"
60 value "mod_inv 4 339 = 85"
62 (* mod_div :: int -> int -> nat -> nat
65 yields SOME c. a * b^(-1) mod m = c *)
66 definition mod_div :: "int => int => int => int" where
67 "mod_div a b m = a * (mod_inv b m) mod m"
69 (* root1 is just local to approx_root *)
70 function root1 :: "int => int => int" where
71 "root1 a n = (if n * n < a then root1 a (n + 1) else n)"
74 (* required just for one approximation:
75 approx_root :: nat -> nat
78 yields SOME r. (r-1) * (r-1) < a \<and> a \<le> r * r*)
79 definition approx_root :: "int => int" where
80 "approx_root a = root1 a 1"
82 (* yields SOME r. r = r1 mod m1 \<and> r = r2 mod m2 *)
83 definition chinese_remainder :: "int => int => int => int => int" where
84 "chinese_remainder r1 m1 r2 m2 =
85 (r1 mod m1) + ((r2 - (r1 mod m1)) * (mod_inv m1 m2) mod m2) * m1"
87 value "chinese_remainder 17 9 3 4 = 35"
88 value "chinese_remainder 7 2 6 11 = 17"
90 subsection {* operations with primes *}
92 (* assumes: 'primes' contains all of first primes \<and> n \<le> (max primes)^2 *)
93 fun is_prime :: "int list \<Rightarrow> int \<Rightarrow> bool" where
95 (if List.length primes > 0
97 if (n mod (List.hd primes)) = 0
99 else is_prime (List.tl primes) n
102 value "is_prime [2, 3] 2 = False"
103 value "is_prime [2, 3] 3 = False"
104 value "is_prime [2, 3] 4 = False"
105 value "is_prime [2, 3] 5 = True"
106 value "is_prime [2, 3] 6 = False"
107 value "is_prime [2, 3] 25 = True" -- "... because 5 not in list"
109 (* make_primes is just local to primes_upto only *)
110 function make_primes :: "int list \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int list" where
111 "make_primes ps last_p n =
112 (if (List.nth ps (List.length ps - 1)) < n
114 if is_prime ps (last_p + 2)
115 then make_primes (ps @ [(last_p + 2)]) (last_p + 2) n
116 else make_primes ps (last_p + 2) n
118 by pat_completeness (simp del: is_prime.simps)
121 (* primes_upto :: int \<Rightarrow> int list
122 primes_upto n = [2, 3, 5, 7, .., p_k] -- sloppy formulations
124 yields SOME k. ([2, 3, 5, 7, .., p_k] contains all primes \<le> p_k) \<and> p_(k-1) < n \<and> n \<le> p_k *)
125 fun primes_upto :: "int \<Rightarrow> int list" where
126 "primes_upto n = (if n < 3 then [2] else make_primes [2, 3] 3 n)"
128 value "primes_upto 2 = [2]"
129 value "primes_upto 3 = [2, 3]"
130 value "primes_upto 4 = [2, 3, 5]"
131 value "primes_upto 5 = [2, 3, 5]"
132 value "primes_upto 6 = [2, 3, 5, 7]"
133 value "primes_upto 7 = [2, 3, 5, 7]"
134 value "primes_upto 8 = [2, 3, 5, 7, 11]"
135 value "primes_upto 9 = [2, 3, 5, 7, 11]"
136 value "primes_upto 10 = [2, 3, 5, 7, 11]"
137 value "primes_upto 11 = [2, 3, 5, 7, 11]"
139 text {* FIXME next_prime_not_dvd loops with all the following:
141 (* find a prime greater p not dividing the number n *)
143 function next_prime_not_dvd :: "int \<Rightarrow> int \<Rightarrow> int" (infixl "next'_prime'_not'_dvd" 70) where
144 "p next_prime_not_dvd n =
146 ps = primes_upto (p + 1);
147 nxt = List.nth ps (List.length ps - 1)
149 if n mod nxt \<noteq> 0
152 by pat_completeness (simp del: primes_upto.simps is_prime.simps)
155 function next_prime_not_dvd :: "int \<Rightarrow> int \<Rightarrow> int" (infixl "next'_prime'_not'_dvd" 70) where
156 "p next_prime_not_dvd n =
158 ps = primes_upto (p + 1);
159 nxt = List.nth ps (List.length ps - 1)
161 if n mod nxt \<noteq> 0
163 else nxt next_prime_not_dvd n)"
164 by pat_completeness (simp del: is_prime.simps make_primes.simps)
168 loops : by pat_completeness auto
169 loops : by pat_completeness simp
170 Failed to finish proof : by pat_completeness (simp del: is_prime.simps make_primes.simps)
171 Failed to finish proof : by pat_completeness (simp del: make_primes.simps)
173 declare [[simp_trace_depth_limit=99]]
174 declare [[simp_trace=true]]
176 thm make_primes.simps
178 function next_prime_not_dvd :: "int \<Rightarrow> int \<Rightarrow> int" (infixl "next'_prime'_not'_dvd" 70) where
179 "p next_prime_not_dvd n =
181 ps = primes_upto (p + 1);
182 nxt = List.nth ps (List.length ps - 1)
184 if n mod nxt \<noteq> 0
186 else nxt next_prime_not_dvd n)"
187 by pat_completeness (simp del: make_primes.simps)
190 (*---------------------------------------------------------------------------------------------
191 subsection {* auxiliary functions for univariate polynomials *}
193 (* not in List.thy, copy from library.ML *)
194 fun nth_drop :: "nat \<Rightarrow> 'a list \<Rightarrow> 'a list" where
195 "nth_drop n xs = List.take n xs @ List.drop (n + 1) xs"
196 value "nth_drop 0 [] = []"
197 value "nth_drop 0 [1, 2, 3::int] = [2, 3]"
198 value "nth_drop 2 [1, 2, 3::int] = [1, 2]"
199 value "nth_drop 77 [1, 2, 3::int] = [1, 2, 3]"
201 (* leading coefficient *)
202 function lc :: "unipoly \<Rightarrow> int" where
204 (if List.nth uvp (List.length uvp - 1) \<noteq> 0
205 then List.nth uvp (List.length uvp - 1)
206 else lc (nth_drop (List.length uvp - 1) uvp))"
210 text {*"----------- fun lc -------------------------------------"*}
211 value "lc [3, 4, 5, 6] = 6"
212 value "lc [3, 4, 5, 6, 0] = 6"
215 function deg :: "unipoly \<Rightarrow> nat" where
217 (if nth uvp (List.length uvp - 1) \<noteq> 0
218 then List.length uvp - 1
219 else deg (nth_drop (List.length uvp - 1) uvp))"
222 (* TODO: ?let l = length uvp - 1? more efficient??? compare drop_lc0 !!! *)
224 text {*"----------- fun deg ------------------------------------"*}
225 value "deg [3, 4, 5, 6] = 3"
226 value "deg [3, 4, 5, 6, 0] = 3"
228 (* drop leading coefficients equal 0 *)
229 fun drop_lc0 :: "unipoly \<Rightarrow> unipoly" where
232 (let l = List.length uvp - 1
235 then drop_lc0 (nth_drop l uvp)
238 text {*"----------- fun drop_lc0 -------------------------------";*}
239 value "drop_lc0 [0, 1, 2, 3, 4, 5, 0, 0] = [0, 1, 2, 3, 4, 5]"
240 value "drop_lc0 [0, 1, 2, 3, 4, 5] = [0, 1, 2, 3, 4, 5]"
242 (* norm is just local to normalise *)
243 fun norm :: "unipoly \<Rightarrow> unipoly \<Rightarrow> int (*nat?*) \<Rightarrow> int \<Rightarrow> nat \<Rightarrow> unipoly" where
244 "norm pol nrm m lcp i =
246 then [mod_div (nth pol i) lcp m] @ nrm
247 else norm pol ([mod_div (nth pol i) lcp m] @ nrm) m lcp (i - 1))"
248 (* normalise a unipoly such that the lc mod m = 1.
249 normalise :: unipoly \<Rightarrow> nat \<Rightarrow> unipoly
250 normalise [p_0, .., p_k] m = [q_0, .., q_k]
252 yields \<exists> t. 0 \<le> i \<le> k \<Rightarrow> (p_i * t) mod m = q_i \<and> (p_k * t) mod m = 1 *)
253 fun normalise :: "unipoly \<Rightarrow> int (*nat?*) \<Rightarrow> unipoly" where
259 if List.length p = 0 then p else norm p [] m lcp (List.length p - 1))"
261 text {*"----------- fun normalise ------------------------------";*}
262 value "normalise [-18, -15, -20, 12, 20, -13, 2] 5 = [1, 0, 0, 1, 0, 1, 1]"
263 value "normalise [9, 6, 3] 10 = [3, 2, 1]"
265 (* scalar multiplication, %* in GCD_Poly.thy *)
266 fun mult_ups :: "unipoly \<Rightarrow> int \<Rightarrow> unipoly" (infixl "mult'_ups" 70) where
267 "p mult_ups m = map (op * m) p"
269 value "[5, 4, 7, 8, 1] mult_ups 5 = [25, 20, 35, 40, 5]"
270 value "[5, 4, -7, 8, -1] mult_ups 5 = [25, 20, -35, 40, -5]"
272 (* scalar divison, %/ in GCD_Poly.thy *)
273 definition swapf :: "('a \<Rightarrow> 'b \<Rightarrow> 'c) \<Rightarrow> 'b \<Rightarrow> 'a \<Rightarrow> 'c" where
274 "swapf f a b = f b a"
275 definition div_ups :: "unipoly \<Rightarrow> int \<Rightarrow> unipoly" (infixl "div'_ups" 70) where
276 "p div_ups m = map (swapf op div2 m) p"
278 value "[4, 3, 2, 5, 6] div_ups 3 = [1, 1, 0, 1, 2]"
279 value "[4, 3, 2, 0] div_ups 3 = [1, 1, 0, 0]"
281 (* not in List.thy, copy from library.ML *)
282 fun map2 :: "('a \<Rightarrow> 'b \<Rightarrow> 'c) \<Rightarrow> 'a list \<Rightarrow> 'b list \<Rightarrow> 'c list" where
284 | "map2 f (x # xs) (y # ys) = f x y # map2 f xs ys"
285 | "map2 _ _ _ = []" (*raise ListPair.UnequalLengths*)
287 (* minus of polys, %-% in GCD_Poly.thy *)
288 definition minus_up :: "unipoly \<Rightarrow> unipoly \<Rightarrow> unipoly" (infixl "minus'_up" 70) where
289 "p1 minus_up p2 = map2 (op -) p1 p2"
291 value "[8, -7, 0, 1] minus_up [-2, 2, 3, 0] = [10, -9, -3, 1]"
292 value "[8, 7, 6, 5, 4] minus_up [2, 2, 3, 1, 1] = [6, 5, 3, 4, 3]"
294 (* dvd for univariate polynomials *)
295 function dvd_up :: "unipoly \<Rightarrow> unipoly \<Rightarrow> bool" (infixl "dvd'_up" 70) where
296 (* FIXME this makes induction proof loop .......
298 (if (\<bar>d\<bar> \<le> \<bar>i\<bar>) & (i mod d = 0) then True else False)"
303 d000 = (List.replicate (List.length p - List.length d) 0) @ d;
304 quot = (lc p) div2 (lc d000);
305 rest = drop_lc0 (p minus_up (d000 div_ups quot))
307 if rest = [] then True
309 (if quot \<noteq> 0 & List.length d \<le> List.length rest
312 by pat_completeness auto
318 value "[2, 3] dvd_up [8, 22, 15] = True"
319 ... FIXME loops, incorrect: ALL SHOULD EVALUATE TO TRUE .......
321 value "[4] dvd_up [6] = False"
322 value "[8] dvd_up [16, 0] = True"
323 value "[3, 2] dvd_up [0, 0, 9, 12, 4] = True"
324 value "[8, 0] dvd_up [16] = True"
326 (* centr is just local to poly_centr *)
327 definition centr :: "int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int" where
328 "centr m mid p_i = (if mid < p_i then p_i - m else p_i)"
330 definition poly_centr :: "unipoly \<Rightarrow> int \<Rightarrow> unipoly" where
334 mid = if m mod mi = 0 then mi else mi + 1
335 in map (centr m mid) p)"
337 value "poly_centr [7, 3, 5, 8, 1, 3] 10 = [-3, 3, 5, -2, 1, 3]"
338 value "poly_centr [1, 2, 3, 4, 5] 2 = [1, 0, 1, 2, 3]"
339 value "poly_centr [1, 2, 3, 4, 5] 3 = [1, -1, 0, 1, 2]"
340 value "poly_centr [1, 2, 3, 4, 5] 4 = [1, 2, -1, 0, 1]"
341 value "poly_centr [1, 2, 3, 4, 5] 5 = [1, 2, 3, -1, 0]"
342 value "poly_centr [1, 2, 3, 4, 5] 6 = [1, 2, 3, -2, -1]"
343 value "poly_centr [1, 2, 3, 4, 5] 7 = [1, 2, 3, 4, -2]"
344 value "poly_centr [1, 2, 3, 4, 5] 8 = [1, 2, 3, 4, -3]"
345 value "poly_centr [1, 2, 3, 4, 5] 9 = [1, 2, 3, 4, 5]"
346 value "poly_centr [1, 2, 3, 4, 5] 10 = [1, 2, 3, 4, 5]"
347 value "poly_centr [1, 2, 3, 4, 5] 11 = [1, 2, 3, 4, 5]"
350 definition sum_lmb :: "unipoly \<Rightarrow> nat \<Rightarrow> int" where
351 "sum_lmb p exp = fold ((op +) o (swapf power exp)) p 0"
353 value "sum_lmb [-1, 2, -3, 4, -5] 1 = -3"
354 value "sum_lmb [-1, 2, -3, 4, -5] 2 = 55"
355 value "sum_lmb [-1, 2, -3, 4, -5] 3 = -81"
356 value "sum_lmb [-1, 2, -3, 4, -5] 4 = 979"
357 value "sum_lmb [-1, 2, -3, 4, -5] 5 = -2313"
358 value "sum_lmb [-1, 2, -3, 4, -5] 6 = 20515"
361 definition landau_mignotte_bound :: "unipoly \<Rightarrow> unipoly \<Rightarrow> nat" where
362 "landau_mignotte_bound p1 p2 =
363 ((power 2 (min (deg p1) (deg p2))) * (nat (gcd (lc p1) (lc p2))) *
364 (nat (min (abs ((approx_root (sum_lmb p1 2)) div2 -(lc p1)))
365 (abs ((approx_root (sum_lmb p2 2)) div2 -(lc p2))))))"
367 value "landau_mignotte_bound [1] [4, 5] = 1"
368 value "landau_mignotte_bound [1, 2] [4, 5] = 2"
369 value "landau_mignotte_bound [1, 2, 3] [4, 5] = 2"
370 value "landau_mignotte_bound [1, 2, 3] [4] = 1"
371 value "landau_mignotte_bound [1, 2, 3] [4, 5] = 2"
372 value "landau_mignotte_bound [1, 2, 3] [4, 5, 6] = 12"
374 value "landau_mignotte_bound [-1] [4, 5] = 1"
375 value "landau_mignotte_bound [-1, 2] [4, 5] = 2"
376 value "landau_mignotte_bound [-1, 2, -3] [4, -5] = 2"
377 value "landau_mignotte_bound [-1, 2, -3] [4] = 1"
378 value "landau_mignotte_bound [-1, 2, -3] [4, -5] = 2"
379 value "landau_mignotte_bound [-1, 2, -3] [4, -5, 6] = 12"
381 subsection {* modulo calculations for polynomials *}
383 (* pair is just local to chinese_remainder_poly *)
384 fun pair :: "unipoly \<Rightarrow> unipoly \<Rightarrow> ((int * int) list)" (infix "pair" 4) where
386 | "([] pair ys) = []" (*raise ListPair.UnequalLengths*)
387 | "(xs pair []) = []" (*raise ListPair.UnequalLengths*)
388 | "((x#xs) pair (y#ys)) = (x, y) # (xs pair ys)"
390 (* chinese_rem is just local to chinese_remainder_poly *)
391 fun chinese_rem :: "int * int \<Rightarrow> int * int \<Rightarrow> int" where
392 "chinese_rem (m1, m2) (p1, p2) = (chinese_remainder p1 m1 p2 m2)"
395 fun chinese_remainder_poly :: "int * int \<Rightarrow> unipoly * unipoly \<Rightarrow> unipoly" where
396 "chinese_remainder_poly (m1, m2) (p1, p2) = map (chinese_rem (m1, m2)) (p1 pair p2)"
398 value "chinese_remainder_poly (5, 7) ([2, 2, 4, 3], [3, 2, 3, 5]) = [17, 2, 24, 33]"
400 (* mod_pol is just local to mod_poly *)
401 function mod_pol :: "unipoly \<Rightarrow> int \<Rightarrow> nat \<Rightarrow> unipoly" where
402 "mod_pol p m n = (if n < List.length p
403 then mod_pol ((List.tl p) @ [(List.hd p) mod m]) m (n + 1)
405 by pat_completeness auto
408 definition mod_poly :: "unipoly \<Rightarrow> int \<Rightarrow> unipoly" (infixl "mod'_poly" 70) where
409 "p mod_poly m = mod_pol p m 0"
411 value "[5, 4, 7, 8, 1] mod_poly 5 = [0, 4, 2, 3, 1]"
412 value "[5, 4, -7, 8, -1] mod_poly 5 = [0, 4, 3, 3, 4]"
414 (* euclidean algoritm in Z_p[x].
415 mod_poly_gcd :: unipoly -> unipoly -> int -> unipoly
416 mod_poly_gcd p1 p2 m = g
418 yields \<exists> g. gcd((p1 mod m),(p2 mod m)) = g *)
419 function mod_poly_gcd :: "unipoly \<Rightarrow> unipoly \<Rightarrow> int \<Rightarrow> unipoly" where
420 "mod_poly_gcd p1 p2 m =
423 p2m = drop_lc0 (p2 mod_poly m);
424 p2n = (replicate (List.length p1 - List.length p2m) 0) @ p2m;
425 quot = mod_div (lc p1m) (lc p2n) m;
426 rest = drop_lc0 ((p1m minus_up (p2n mult_ups quot)) mod_poly m)
431 if length rest < List.length p2
432 then mod_poly_gcd p2 rest m
433 else mod_poly_gcd rest p2 m)"
434 by pat_completeness auto
437 value "mod_poly_gcd [-18, -15, -20, 12, 20, -13, 2] [8, 28, 22, -11, -14, 1, 2] 7 = [2, 6, 0, 2, 6]"
438 value "mod_poly_gcd [8, 28, 22, -11, -14, 1, 2] [2, 6, 0, 2, 6] 7 = [2, 6, 0, 2, 6]"
439 value "mod_poly_gcd [20, 15, 8, 6] [8, -2, -2, 3] 2 = [0, 1]"
444 (*----------------------------------------------------------------------------*)
448 declare [[simp_trace_depth_limit=99]]
449 declare [[simp_trace=true]]
450 ---------------------------------------------------------------------------------------------*)