src/Tools/isac/Knowledge/GCD_Poly.thy
author Walther Neuper <neuper@ist.tugraz.at>
Fri, 31 May 2013 17:49:34 +0200
changeset 48871 cf55b1438731
parent 48870 5a83cf4f184a
child 48874 7c5db55f3295
permissions -rw-r--r--
GCD_Poly.thy with writeln for try_new_prime_up

writeln used for testing codegen
meindl_diana@48797
     1
(* rationals, i.e. fractions of multivariate polynomials over the real field
meindl_diana@48797
     2
   author: Diana Meindl
meindl_diana@48797
     3
   (c) Diana Meindl
meindl_diana@48797
     4
   Use is subject to license terms. 
meindl_diana@48797
     5
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
meindl_diana@48797
     6
        10        20        30        40        50        60        70        80         90      100
meindl_diana@48797
     7
*)
meindl_diana@48797
     8
meindl_diana@48797
     9
theory GCD_Poly imports Complex_Main begin 
meindl_diana@48797
    10
meindl_diana@48797
    11
text {*
meindl_diana@48797
    12
  Below we reference 
neuper@48852
    13
  F. Winkler, Polynomial algorithyms in computer algebra. Springer 1996.
neuper@48831
    14
  by page 93 and 95. This is the final version of the Isabelle theory,
neuper@48831
    15
  which conforms with Isabelle's coding standards and with requirements
neuper@48831
    16
  in terms of logics appropriate for a theorem prover.
neuper@48831
    17
*}
neuper@48831
    18
neuper@48831
    19
section {* Predicates for the specifications *}
neuper@48831
    20
text {*
neuper@48831
    21
  This thesis provides program code to be integrated into the Isabelle 
neuper@48831
    22
  distribution.  Thus the code will be verified against specifications, and 
neuper@48831
    23
  consequently the code, as \emph{explicit} specification of how to calculate 
neuper@48831
    24
  results, is accompanied by \emph{implicit} specifications describing the 
neuper@48831
    25
  properties of the program code.
neuper@48831
    26
neuper@48831
    27
  For describing the properties of code the format of Haskell will be used.
neuper@48831
    28
  Haskell \cite{TODO} is front-of-the-wave in research on functional 
neuper@48831
    29
  programming and as such advances beyond SML. The advancement relevant for 
neuper@48831
    30
  this thesis is the concise combination of explicit and implicit specification
neuper@48831
    31
  of a function. The final result of the code developed within this thesis is 
neuper@48831
    32
  described as follows in Haskell format:
neuper@48831
    33
neuper@48831
    34
  \begin{verbatim} % TODO: find respective Isabelle/LaTeX features
neuper@48831
    35
    gcd_poly :: int poly \<Rightarrow> int poly \<Rightarrow> int poly
neuper@48831
    36
    gcd_poly p1 p2 = d
neuper@48831
    37
    assumes and p1 \<noteq> [:0:] and p2 \<noteq> [:0:]
neuper@48851
    38
    yields d dvd p1 \<and> d dvd p2 \<and> \<forall>d'. (d' dvd p1 \<and> d' dvd p2) \<longrightarrow> d' \<le> d
neuper@48831
    39
  \end{verbatim
neuper@48831
    40
  
neuper@48831
    41
  The above specification combines Haskell format with the term language of
neuper@48831
    42
  Isabelle\HOL. The latter provides a large and ever growing library of 
neuper@48831
    43
  mechanised mathematics knowledge, which this thesis re-uses in order to 
neuper@48831
    44
  prepare for integration of the code.
neuper@48831
    45
neuper@48831
    46
  In the sequel there is a brief account of the notions required for the 
neuper@48831
    47
  specification of the functions implemented within this thesis. *}
neuper@48831
    48
neuper@48831
    49
subsection {* The Isabelle types required *}
neuper@48831
    50
text {*
neuper@48851
    51
  bool, nat, int, option, THE, list, 'a poly
neuper@48831
    52
*}
neuper@48851
    53
neuper@48831
    54
subsection {* The connectives required *}
neuper@48831
    55
text {*
neuper@48831
    56
  logic ~~/doc/tutorial.pdf p.203
neuper@48851
    57
  arithmetic < \<le> + - * ^ div \<bar>_\<bar>
neuper@48831
    58
*}
neuper@48831
    59
neuper@48831
    60
subsection {* The Isabelle functions required *}
neuper@48831
    61
text {*
neuper@48831
    62
  number theory
neuper@48831
    63
    dvd, mod, gcd
neuper@48831
    64
    Primes.prime
neuper@48831
    65
    Primes.next_prime_bound
neuper@48831
    66
neuper@48831
    67
  lists
neuper@48831
    68
    List.hd, List.tl
neuper@48831
    69
    List.length, List.member
neuper@48831
    70
    List.fold, List.map
neuper@48831
    71
    List.nth, List.take, List.drop
neuper@48831
    72
    List.replicate
neuper@48831
    73
    
neuper@48831
    74
  others
neuper@48831
    75
    Fact.fact
meindl_diana@48797
    76
*}
meindl_diana@48797
    77
neuper@48813
    78
section {* gcd for univariate polynomials *}
meindl_diana@48797
    79
ML {*
meindl_diana@48799
    80
type unipoly = int list;
meindl_diana@48799
    81
val a = [~18, ~15, ~20, 12, 20, ~13, 2];
meindl_diana@48799
    82
val b = [8, 28, 22, ~11, ~14, 1, 2];
meindl_diana@48797
    83
*}
meindl_diana@48797
    84
neuper@48857
    85
subsection {* auxiliary functions *}
neuper@48857
    86
ML {* 
neuper@48857
    87
  (* a variant for div: 
neuper@48857
    88
    5 div 2 = 2; ~5 div 2 = ~3; BUT WEE NEED ~5 div2 2 = ~2; *)
neuper@48813
    89
  infix div2
neuper@48813
    90
  fun a div2 b = 
neuper@48851
    91
    if a div b < 0 then (abs a) div (abs b) * ~1 else a div b
neuper@48857
    92
neuper@48866
    93
  (* why has "last" been removed since 2002, although "last" is in List.thy ? *)
neuper@48866
    94
  fun last ls = (hd o rev) ls
neuper@48857
    95
neuper@48857
    96
  (* drop tail elements equal 0 *)
neuper@48857
    97
  fun drop_hd_zeros (0 :: ps) = drop_hd_zeros ps
neuper@48857
    98
    | drop_hd_zeros p = p
neuper@48857
    99
  fun drop_tl_zeros p = (rev o drop_hd_zeros o rev) p;
neuper@48870
   100
neuper@48870
   101
  (* swaps the arguments of a function *)
neuper@48870
   102
  fun swapf f a b = f b a
meindl_diana@48797
   103
*}
meindl_diana@48797
   104
meindl_diana@48797
   105
subsection {* modulo calculations for integers *}
meindl_diana@48797
   106
ML {*
neuper@48836
   107
  (* mod_inv :: int \<Rightarrow> nat 
neuper@48817
   108
     mod_inv r m = s
neuper@48836
   109
     assumes True
neuper@48836
   110
     yields r * s mod m = 1 *)
meindl_diana@48797
   111
  fun mod_inv r m =
meindl_diana@48797
   112
    let
meindl_diana@48797
   113
      fun modi (r, rold, m, rinv) = 
neuper@48836
   114
        if m <= rinv then 0 else
meindl_diana@48797
   115
          if r mod m = 1
meindl_diana@48797
   116
          then rinv
meindl_diana@48797
   117
          else modi (rold * (rinv + 1), rold, m, rinv + 1)
neuper@48861
   118
     in modi (r, r, m, 1) end
neuper@48862
   119
neuper@48865
   120
  (* mod_div :: int \<Rightarrow> int \<Rightarrow> nat \<Rightarrow> natO
neuper@48817
   121
     mod_div a b m = c
neuper@48836
   122
     assumes True
neuper@48865
   123
     yields a * b ^(-1) mod m = c   <\<Longrightarrow>  a mod m = (b * c) mod m*)
neuper@48862
   124
  fun mod_div a b m = a * (mod_inv b m) mod m
meindl_diana@48797
   125
neuper@48836
   126
  (* required just for one approximation:
neuper@48836
   127
     approx_root :: nat \<Rightarrow> nat
neuper@48817
   128
     approx_root a = r
neuper@48836
   129
     assumes True
neuper@48836
   130
     yields r * r \<ge> a *)
neuper@48813
   131
  fun approx_root a =
neuper@48836
   132
    let
neuper@48836
   133
      fun root1 a n = if n * n < a then root1 a (n + 1) else n
neuper@48836
   134
    in root1 a 1 end
meindl_diana@48797
   135
neuper@48862
   136
  (* chinese_remainder :: int * nat \<Rightarrow> int * nat \<Rightarrow> nat
neuper@48862
   137
     chinese_remainder (r1, m1) (r2, m2) = r
neuper@48836
   138
     assumes True
neuper@48836
   139
     yields r = r1 mod m1 \<and> r = r2 mod m2 *)
neuper@48862
   140
  fun chinese_remainder (r1, m1) (r2, m2) =
neuper@48862
   141
    (r1 mod m1) + 
neuper@48862
   142
     (((r2 - (r1 mod m1)) * (mod_inv m1 m2)) mod m2) * m1;
meindl_diana@48797
   143
*}
meindl_diana@48797
   144
neuper@48851
   145
subsection {* creation of lists of primes for efficiency *}
meindl_diana@48797
   146
ML{*
neuper@48830
   147
  (* is_prime :: int list \<Rightarrow> int \<Rightarrow> bool
neuper@48830
   148
     is_prime ps n = b
neuper@48830
   149
     assumes max ps < n  \<and>  n \<le> (max ps)^2  \<and>  
neuper@48830
   150
       (*     FIXME: really ^^^^^^^^^^^^^^^? *)
neuper@48831
   151
       (\<forall>p. List.member ps p \<longrightarrow> Primes.prime p) \<and> (\<forall>p. p < n \<and> Primes.prime p \<longrightarrow> List.member ps p)
neuper@48830
   152
     yields Primes.prime n *)
neuper@48834
   153
  fun is_prime [] _ = true
neuper@48834
   154
    | is_prime prs n = 
neuper@48834
   155
        if n mod (List.hd prs) <> 0 then is_prime (List.tl prs) n else false
meindl_diana@48797
   156
neuper@48830
   157
  (* make_primes is just local to primes_upto only:
neuper@48830
   158
     make_primes :: int list \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int list
neuper@48830
   159
     make_primes ps last_p n = pps
neuper@48831
   160
     assumes last_p = maxs ps  \<and>  (\<forall>p. List.member ps p \<longrightarrow> Primes.prime p)  \<and>
neuper@48831
   161
       (\<forall>p. p < last_p \<and> Primes.prime p \<longrightarrow> List.member ps p)
neuper@48836
   162
     yields n \<le> maxs pps  \<and>  (\<forall>p. List.member pps p \<longrightarrow> Primes.prime p)  \<and>
neuper@48831
   163
       (\<forall>p. (p < maxs pps \<and> Primes.prime p) \<longrightarrow> List.member pps p)*)
neuper@48834
   164
    fun make_primes ps last_p n =
neuper@48866
   165
        if n <= last ps then ps else
neuper@48813
   166
          if is_prime ps (last_p + 2) 
neuper@48813
   167
          then make_primes (ps @ [(last_p + 2)]) (last_p + 2) n
neuper@48834
   168
          else make_primes  ps                   (last_p + 2) n
neuper@48834
   169
neuper@48831
   170
  (* primes_upto :: nat \<Rightarrow> nat list
neuper@48830
   171
     primes_upto n = ps
neuper@48831
   172
       assumes True
neuper@48836
   173
       yields (\<forall>p. List.member ps p \<longrightarrow> Primes.prime p) \<and>
neuper@48831
   174
         n \<le> maxs ps \<and> maxs ps \<le> Fact.fact n + 1 \<and>
neuper@48835
   175
         (\<forall>p. p \<le> maxs ps \<and> Primes.prime p \<longrightarrow> List.member ps p) *)
neuper@48836
   176
  fun primes_upto n = if n < 3 then [2] else make_primes [2, 3] 3 n
neuper@48813
   177
 
neuper@48831
   178
  (* find the next prime greater p not dividing the number n:
neuper@48827
   179
    next_prime_not_dvd :: int \<Rightarrow> int \<Rightarrow> int (infix)
neuper@48827
   180
    n1 next_prime_not_dvd n2 = p
neuper@48831
   181
      assumes True
neuper@48837
   182
      yields p is_prime  \<and>  n1 < p  \<and>  \<not> p dvd n2  \<and> (* smallest with these properties... *)
neuper@48837
   183
        (\<forall> p'. (p' is_prime  \<and>  n1 < p'  \<and>  \<not> p' dvd n2)  \<longrightarrow>  p \<le> p') *)
neuper@48835
   184
  infix next_prime_not_dvd;
neuper@48835
   185
  fun n1 next_prime_not_dvd n2 = 
neuper@48813
   186
    let
neuper@48835
   187
      val ps = primes_upto (n1 + 1)
neuper@48813
   188
      val nxt = nth ps (List.length ps - 1);
meindl_diana@48797
   189
    in
neuper@48836
   190
      if n2 mod nxt <> 0 then nxt else nxt next_prime_not_dvd n2
meindl_diana@48797
   191
  end
meindl_diana@48797
   192
*}
meindl_diana@48797
   193
neuper@48851
   194
subsection {* basic notions for univariate polynomials *}
neuper@48813
   195
ML {*
neuper@48857
   196
  (* leading coefficient, includes drop_lc0_up ?FIXME130507 *)
neuper@48866
   197
  fun lcoeff_up (p: unipoly) = (last o drop_tl_zeros) p
meindl_diana@48797
   198
  
neuper@48857
   199
  (* drop leading coefficients equal 0 *)
neuper@48857
   200
  fun drop_lc0_up (p: unipoly) = drop_tl_zeros p : unipoly;
meindl_diana@48797
   201
neuper@48857
   202
  (* degree, includes drop_lc0_up ?FIXME130507 *)
neuper@48857
   203
  fun deg_up (p: unipoly) = ((Integer.add ~1) o length o drop_lc0_up) p;
meindl_diana@48797
   204
neuper@48846
   205
  (* normalise a unipoly such that lcoeff_up mod m = 1.
neuper@48817
   206
     normalise :: unipoly \<Rightarrow> nat \<Rightarrow> unipoly
neuper@48817
   207
     normalise [p_0, .., p_k] m = [q_0, .., q_k]
neuper@48827
   208
       assumes True
neuper@48817
   209
       yields \<exists> t. 0 \<le> i \<le> k \<Rightarrow> (p_i * t) mod m = q_i  \<and>  (p_k * t) mod m = 1 *)
neuper@48815
   210
  fun normalise (p: unipoly) (m: int) =
meindl_diana@48797
   211
    let
neuper@48846
   212
      val p = drop_lc0_up p
neuper@48846
   213
      val lcp = lcoeff_up p;
neuper@48815
   214
      fun norm nrm i =
neuper@48814
   215
        if i = 0
neuper@48815
   216
        then [mod_div (nth p i) lcp m] @ nrm
neuper@48815
   217
        else norm ([mod_div (nth p i) lcp m] @  nrm) (i - 1) ;
meindl_diana@48797
   218
    in 
neuper@48815
   219
      if List.length p = 0 then p else norm [] (List.length p - 1)
neuper@48815
   220
  end;
neuper@48851
   221
*}
meindl_diana@48797
   222
neuper@48851
   223
subsection {* addition, multiplication, division *}
neuper@48851
   224
ML {*
neuper@48815
   225
  (* scalar multiplication *)
neuper@48815
   226
  infix %*
neuper@48839
   227
  fun (p: unipoly) %* n =  map (Integer.mult n) p : unipoly
neuper@48815
   228
  
neuper@48815
   229
  (* scalar divison *)
neuper@48815
   230
  infix %/ 
neuper@48870
   231
  fun (p: unipoly) %/ n = map (swapf (curry op div2) n) p : unipoly
meindl_diana@48797
   232
neuper@48815
   233
  (* minus of polys *)
meindl_diana@48797
   234
  infix %-%
neuper@48839
   235
  fun (p1: unipoly) %-% (p2: unipoly) = 
neuper@48839
   236
    map2 (curry op -) p1 (p2 @ replicate (List.length p1 - List.length p2) 0) : unipoly
meindl_diana@48797
   237
neuper@48823
   238
  (* dvd for univariate polynomials *)
meindl_diana@48797
   239
  infix %|%
neuper@48845
   240
(**)
neuper@48847
   241
  fun [d] %|% [p] = (p mod d = 0)
neuper@48839
   242
    | (ds: unipoly) %|% (ps: unipoly) = 
neuper@48837
   243
      let 
neuper@48846
   244
        val ds = drop_lc0_up ds;
neuper@48846
   245
        val ps = drop_lc0_up ps;
neuper@48839
   246
        val d000 = (replicate (List.length ps - List.length ds) 0) @ ds ;
neuper@48846
   247
        val quot = (lcoeff_up ps) div2 (lcoeff_up d000);
neuper@48846
   248
        val rest = drop_lc0_up (ps %-% (d000 %* quot));
neuper@48845
   249
      in
neuper@48846
   250
        if rest = [] then true else
neuper@48845
   251
          if rest <> [] andalso quot <> 0 andalso List.length ds <= List.length rest
neuper@48846
   252
          then ds %|% rest
neuper@48846
   253
          else false
neuper@48837
   254
      end
neuper@48851
   255
*}
neuper@48851
   256
neuper@48851
   257
subsection {* normalisation and Landau-Mignotte bound *}
neuper@48851
   258
ML {* 
neuper@48855
   259
  (* normalise :: centr_up \<Rightarrow> unipoly => int \<Rightarrow> unipoly
neuper@48826
   260
     normalise [p_0, .., p_k] m = [q_0, .., q_k]
neuper@48826
   261
       assumes 
neuper@48836
   262
       yields 0 \<le> i \<le> k \<Rightarrow> |^ ~m/2 ^| <= q_i <=|^ m/2 ^| 
neuper@48836
   263
        (where |^ x ^| means round x up to the next greater integer) *)
neuper@48855
   264
  fun centr_up (p: unipoly) (m: int) =
meindl_diana@48797
   265
    let
neuper@48823
   266
      val mi = m div2 2;
neuper@48823
   267
      val mid = if m mod mi = 0 then mi else mi + 1;
neuper@48823
   268
      fun centr m mid p_i = if mid < p_i then p_i - m else p_i;
neuper@48839
   269
    in map (centr m mid) p : unipoly end;
meindl_diana@48797
   270
neuper@48836
   271
  (*** landau mignotte bound (Winkler p91)
neuper@48831
   272
    every coefficient of the gcd of a  and b in Z[x] is bounded in absolute value by
neuper@48827
   273
    2^{min(m,n)} * gcd(a_m,b_n) * min(1/|a_m| 
neuper@48836
   274
    * root(sum_{i=0}^{m}a_i^2) ,1/|b_n| * root( sum_{i=0}^{n}b_i^2 ) ***)
neuper@48826
   275
neuper@48855
   276
   (*  sum_lmb :: centr_up \<Rightarrow> unipoly \<Rightarrow> int \<Rightarrow> int
neuper@48826
   277
     sum_lmb [p_0, .., p_k] e = s
neuper@48826
   278
       assumes exp >= 0
neuper@48836
   279
       yields. p_0^e + p_1^e + ... + p_k^e *)
neuper@48823
   280
  fun sum_lmb (p: unipoly) exp = fold ((curry op +) o (Integer.pow exp)) p 0;
meindl_diana@48810
   281
neuper@48855
   282
   (* LANDAU_MIGNOTTE_bound :: centr_up \<Rightarrow> unipoly \<Rightarrow> unipoly \<Rightarrow> int
neuper@48830
   283
      LANDAU_MIGNOTTE_bound [a_0, ..., a_m] [b_0, .., b_n] = lmb
neuper@48827
   284
        assumes True
neuper@48836
   285
        yields lmb = 2^min(m,n) * gcd(a_m,b_n) * 
neuper@48827
   286
          min( 1/|a_m| * root(sum_lmb [a_0,...a_m] 2 , 1/|b_n| * root(sum_lmb [b_0,...b_n] 2)*)
neuper@48830
   287
  fun LANDAU_MIGNOTTE_bound (p1: unipoly) (p2: unipoly) = 
neuper@48846
   288
    (Integer.pow (Integer.min (deg_up p1) (deg_up p2)) 2) * (abs (Integer.gcd (lcoeff_up p1) (lcoeff_up p2))) * 
neuper@48846
   289
    (Int.min (abs((approx_root (sum_lmb p1 2)) div2 ~(lcoeff_up p1)), 
neuper@48846
   290
              abs((approx_root (sum_lmb p2 2)) div2 ~(lcoeff_up p2))));
meindl_diana@48797
   291
*}
meindl_diana@48797
   292
neuper@48851
   293
subsection {* modulo calculations on polynomials *}
meindl_diana@48797
   294
ML{*
neuper@48855
   295
  (* chinese_remainder_up :: int * int \<Rightarrow> unipoly * unipoly \<Rightarrow> unipoly
neuper@48855
   296
     chinese_remainder_up (m1, m2) (p1, p2) = p
meindl_diana@48838
   297
     assume m1, m2 relatively prime
neuper@48855
   298
     yields p1 = p mod m1 \<and> p2 = p mod m2 *)
neuper@48855
   299
  fun chinese_remainder_up (m1, m2) (p1: unipoly, p2: unipoly) = 
meindl_diana@48797
   300
  let 
neuper@48862
   301
    fun chinese_rem (m1, m2) (p_1i, p_2i) = chinese_remainder (p_1i, m1) (p_2i, m2)
neuper@48823
   302
  in map (chinese_rem (m1, m2)) (p1 ~~ p2): unipoly end
meindl_diana@48797
   303
neuper@48858
   304
  (* mod_up :: unipoly \<Rightarrow> int \<Rightarrow> unipoly
neuper@48858
   305
     mod_up [p1, p2, ..., pk] m = up 
meindl_diana@48838
   306
     assume m > 0
meindl_diana@48838
   307
     yields up = [p1 mod m, p2 mod m, ..., pk mod m]*)
neuper@48858
   308
  infix mod_up 
neuper@48858
   309
  fun (p : unipoly) mod_up m = 
neuper@48855
   310
  let 
neuper@48863
   311
    fun mod' m p = (curry op mod) p m 
neuper@48863
   312
  in map (mod' m) p : unipoly end
meindl_diana@48797
   313
meindl_diana@48819
   314
  (* euclidean algoritm in Z_p[x].
neuper@48858
   315
     mod_up_gcd :: unipoly \<Rightarrow> unipoly \<Rightarrow> int \<Rightarrow> unipoly
neuper@48858
   316
     mod_up_gcd p1 p2 m = g
neuper@48836
   317
       assumes True
neuper@48836
   318
       yields gcd ((p1 mod m), (p2 mod m)) = g *)
neuper@48858
   319
  fun mod_up_gcd (p1: unipoly) (p2: unipoly) (m: int) =
meindl_diana@48797
   320
    let 
neuper@48858
   321
      val p1m = p1 mod_up m;
neuper@48858
   322
      val p2m = drop_lc0_up (p2 mod_up m);
neuper@48823
   323
      val p2n = (replicate (List.length p1 - List.length p2m) 0) @ p2m;
neuper@48846
   324
      val quot =  mod_div (lcoeff_up p1m) (lcoeff_up p2n) m;
neuper@48858
   325
      val rest = drop_lc0_up ((p1m %-% (p2n %* quot)) mod_up m)
neuper@48836
   326
    in
neuper@48836
   327
      if rest = [] then p2 else
neuper@48836
   328
        if length rest < List.length p2
neuper@48858
   329
        then mod_up_gcd p2 rest m 
neuper@48858
   330
        else mod_up_gcd rest p2 m
neuper@48823
   331
    end;
neuper@48823
   332
neuper@48855
   333
  (* primitive_up :: unipoly \<Rightarrow> unipoly
neuper@48855
   334
     primitive_up p = pp
neuper@48831
   335
     assumes True
neuper@48836
   336
     yields \<forall>p1, p2. (List.member pp p1 \<and> List.member pp p2 \<and> p1 \<noteq> p2) \<longrightarrow> gcd p1 p2 = 1 *)
neuper@48863
   337
  fun primitive_up ([c] : unipoly) = 
neuper@48863
   338
      if c = 0 then ([0] : unipoly) else ([1] : unipoly)
neuper@48863
   339
    | primitive_up p =
neuper@48831
   340
        let
neuper@48831
   341
          val d = abs (Integer.gcds p)
neuper@48831
   342
        in
neuper@48831
   343
          if d = 1 then p else p %/ d
neuper@48831
   344
        end
meindl_diana@48797
   345
*}
meindl_diana@48797
   346
neuper@48855
   347
subsection {* gcd_up, code from [1] p.93 *}
meindl_diana@48797
   348
ML {*
meindl_diana@48838
   349
  (* try_new_prime_up :: unipoly \<Rightarrow> unipoly \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> unipoly \<Rightarrow> int  \<Rightarrow> unipoly
meindl_diana@48838
   350
     try_new_prime_up p1 p2 d M P g p = new_g
neuper@48855
   351
       assumes d = gcd (lcoeff_up p1, lcoeff_up p2)  \<and> 
neuper@48855
   352
               M = LANDAU_MIGNOTTE_bound  \<and>  p = prime \<and>  p ~| d  \<and>  P \<ge> p  \<and>
neuper@48855
   353
               p1 is primitive  \<and>  p2 is primitive
neuper@48855
   354
       yields  new_g = [1] \<or> (new_g \<ge> g \<and> P > M)
neuper@48855
   355
neuper@48855
   356
    argumentns "a b d M P g p" named according to [1] p.93 *)
neuper@48835
   357
  fun try_new_prime_up a b d M P g p =
neuper@48871
   358
(writeln ("try_new_prime_up:  a = " ^ PolyML.makestring a ^
neuper@48871
   359
", b = " ^ PolyML.makestring b ^
neuper@48871
   360
", d = " ^ PolyML.makestring d ^
neuper@48871
   361
", M = " ^ PolyML.makestring M ^
neuper@48871
   362
", P = " ^ PolyML.makestring P ^
neuper@48871
   363
", g = " ^ PolyML.makestring g ^
neuper@48871
   364
", p = " ^ PolyML.makestring p);
neuper@48871
   365
    if P > M then
neuper@48871
   366
(writeln ("try_new_prime_up 1 -----> " ^ PolyML.makestring g);
neuper@48871
   367
                  g 
neuper@48871
   368
)
neuper@48871
   369
                    else
neuper@48833
   370
      let
neuper@48865
   371
        val p = p next_prime_not_dvd d
neuper@48865
   372
        val g_p = centr_up (         (    (normalise (mod_up_gcd a b p) p) 
neuper@48865
   373
                                       %* (d mod p))                  
neuper@48865
   374
                              mod_up p) 
neuper@48865
   375
                            p
neuper@48827
   376
      in
neuper@48846
   377
        if deg_up g_p < deg_up g
neuper@48827
   378
        then
neuper@48871
   379
          if (deg_up g_p) = 0 then
neuper@48871
   380
(writeln ("try_new_prime_up 2 -----> " ^ PolyML.makestring [1]);
neuper@48871
   381
                                   [1]: unipoly
neuper@48871
   382
) 
neuper@48871
   383
                                                else try_new_prime_up a b d M p g_p p
neuper@48827
   384
        else
neuper@48865
   385
          if deg_up g_p <> deg_up g then try_new_prime_up a b d M P g p else
neuper@48827
   386
            let 
neuper@48865
   387
              val P = P * p
neuper@48865
   388
              val g = centr_up ((chinese_remainder_up (P, p) (g, g_p)) mod_up P) P
neuper@48865
   389
            in try_new_prime_up a b d M P g p end
neuper@48827
   390
      end
neuper@48871
   391
)      
meindl_diana@48838
   392
  (* HENSEL_lifting_up :: unipoly \<Rightarrow> unipoly \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> unipoly
meindl_diana@48838
   393
     HENSEL_lifting_up p1 p2 d M p = gcd
neuper@48855
   394
       assumes d = gcd (lcoeff_up p1, lcoeff_up p2) \<and> 
neuper@48855
   395
               M = LANDAU_MIGNOTTE_bound \<and> p = prime  \<and>  p ~| d  \<and>
neuper@48855
   396
               p1 is primitive  \<and>  p2 is primitive
neuper@48855
   397
       yields  gcd | p1  \<and>  gcd | p2  \<and>  gcd is primitive
neuper@48855
   398
neuper@48855
   399
    argumentns "a b d M p" named according to [1] p.93 *)
neuper@48871
   400
  fun HENSEL_lifting_up a b d M p =
neuper@48871
   401
(writeln ("HENSEL_lifting_up: a = " ^ PolyML.makestring a ^
neuper@48871
   402
", b = " ^ PolyML.makestring b ^
neuper@48871
   403
", d = " ^ PolyML.makestring d ^
neuper@48871
   404
", M = " ^ PolyML.makestring M ^
neuper@48871
   405
", p = " ^ PolyML.makestring p);
neuper@48868
   406
    let
neuper@48835
   407
      val p = p next_prime_not_dvd d 
neuper@48871
   408
      val g_p = centr_up (((normalise (mod_up_gcd a b p) p) %* (d mod p)) mod_up p) p 
neuper@48871
   409
        (*.. nesting of functions see above*)
neuper@48823
   410
    in
neuper@48871
   411
      if deg_up g_p = 0 then 
neuper@48871
   412
(writeln ("HENSEL_lifting_up 1 ----> " ^ PolyML.makestring [1]);
neuper@48871
   413
                             [1] 
neuper@48871
   414
)
neuper@48871
   415
                                else
neuper@48835
   416
        let 
neuper@48855
   417
          val g = primitive_up (try_new_prime_up a b d M p g_p p)
neuper@48827
   418
        in
neuper@48871
   419
          if (g %|% a) andalso (g %|% b) then 
neuper@48871
   420
(writeln ("HENSEL_lifting_up 2 -----> " ^ PolyML.makestring g);
neuper@48871
   421
                                              g:unipoly
neuper@48871
   422
) 
neuper@48871
   423
                                                        else HENSEL_lifting_up a b d M p
neuper@48827
   424
        end
neuper@48827
   425
    end
neuper@48871
   426
)
neuper@48855
   427
  (* gcd_up :: unipoly \<Rightarrow> unipoly \<Rightarrow> unipoly
neuper@48855
   428
     gcd_up a b = c
meindl_diana@48838
   429
     assumes not (a = [] \<or> a = [0]) \<and> not (b = []\<or> b = [0]) \<and> 
meindl_diana@48838
   430
             a is primitive \<and> b is primitive
neuper@48836
   431
     yields c dvd a \<and> c dvd b \<and> (\<forall>c'. (c' dvd a \<and> c' dvd b) \<longrightarrow> c' \<le> c) *)
neuper@48855
   432
  fun gcd_up a b =
neuper@48855
   433
    let val d = abs (Integer.gcd (lcoeff_up a) (lcoeff_up b))
neuper@48855
   434
    in 
neuper@48855
   435
      if a = b then a else
neuper@48855
   436
        HENSEL_lifting_up a b d (2 * d * LANDAU_MIGNOTTE_bound a b) 1
neuper@48855
   437
    end;
meindl_diana@48797
   438
*}
meindl_diana@48797
   439
neuper@48851
   440
section {* gcd for multivariate polynomials *}
meindl_diana@48797
   441
ML {*
meindl_diana@48797
   442
type monom = (int * int list);
neuper@48846
   443
type poly = monom list;
meindl_diana@48797
   444
*}
meindl_diana@48797
   445
neuper@48851
   446
subsection {* auxiliary functions *}
meindl_diana@48797
   447
ML {*
neuper@48846
   448
  fun land a b = a andalso b
neuper@48846
   449
  fun all_geq a b = fold land (map2 (curry op >=) a b) true
neuper@48850
   450
  fun all_geq' i es = fold land (map ((curry op <=) i) es) true
neuper@48850
   451
  fun maxs is = fold Integer.max is (hd is);
neuper@48850
   452
  fun div2_swapped d i = i div2 d
neuper@48850
   453
  fun nth_swapped i ls = nth ls i;
neuper@48849
   454
  fun drop_last ls = (rev o tl o rev) ls
neuper@48849
   455
  fun nth_ins n i xs = (*analogous to nth_drop: why not in library.ML?*)
neuper@48849
   456
    List.take (xs, n) @ [i] @ List.drop (xs, n);
neuper@48851
   457
*}
neuper@48850
   458
neuper@48851
   459
subsection {* basic notions for multivariate polynomials *}
neuper@48851
   460
ML {*
neuper@48849
   461
  fun lcoeff (p: poly) = (fst o hd o rev) p
neuper@48850
   462
  fun lexp (p: poly) = (snd o hd o rev) p
neuper@48850
   463
  fun lmonom (p: poly) = (hd o rev) p
neuper@48850
   464
neuper@48870
   465
  fun zero_poly (nro_vars: int) = [(0, replicate nro_vars 0)] : poly;
neuper@48850
   466
neuper@48851
   467
  (* drop leading coefficients equal 0 TODO: signature?*)
neuper@48870
   468
  fun drop_lc0 (p: poly as [(c, es)]) = if c = 0 then zero_poly (length es) else p
neuper@48851
   469
    | drop_lc0 p = if lcoeff p = 0 then drop_lc0 (drop_last p) else p
neuper@48851
   470
neuper@48851
   471
  (* gcd of coefficients WN find right location in file *)
neuper@48851
   472
  fun gcd_coeff (up: unipoly) = abs (Integer.gcds up)
neuper@48851
   473
neuper@48851
   474
 (* given p = 3x+4z = [(3,[1,0]),(4,[0,1])] with x<z
neuper@48851
   475
    add_variable p 2  =>  [(3,[1,0,0]),(4,[0,0,1])] with x<y<z *)
neuper@48870
   476
  fun add_variable pos (p: poly) = map (apsnd (nth_ins pos 0)) p : poly
neuper@48851
   477
*}
neuper@48851
   478
neuper@48851
   479
subsection {* ordering and other auxiliary funcions *}
neuper@48851
   480
ML {*
neuper@48857
   481
  (* monomial order: lexicographic order on exponents *)
neuper@48850
   482
  fun  lex_ord ((_, a): monom) ((_, b): monom) =
neuper@48857
   483
    let val d = drop_tl_zeros (a %-% b)
neuper@48850
   484
    in
neuper@48866
   485
      if d = [] then false else last d > 0
neuper@48850
   486
    end
neuper@48849
   487
  fun  lex_ord' ((_, a): monom, (_, b): monom) =
neuper@48857
   488
    let val d = drop_tl_zeros (a %-% b)
neuper@48849
   489
    in
neuper@48857
   490
      if  d = [] then EQUAL 
neuper@48866
   491
      else if last d > 0 then GREATER else LESS
neuper@48849
   492
    end
neuper@48850
   493
neuper@48848
   494
  (* add monomials in ordered polynomal *)
neuper@48850
   495
  fun add_monoms (p: poly) = 
neuper@48846
   496
    let 
neuper@48870
   497
      fun add [(0, es)] [] = zero_poly (length es)
neuper@48847
   498
        | add [(0, _)] (new: poly) = new
neuper@48847
   499
        | add [m] (new: poly) = new @ [m]
neuper@48847
   500
        | add ((c1, es1) :: (c2, es2) :: ms) (new: poly) =
neuper@48846
   501
          if es1 = es2
neuper@48847
   502
          then add ([(c1 + c2, es1)] @ ms) new 
neuper@48846
   503
          else
neuper@48846
   504
            if c1 = 0 
neuper@48847
   505
            then add ((c2, es2) :: ms) new 
neuper@48847
   506
            else add ((c2, es2) :: ms) (new @ [(c1, es1)])
neuper@48850
   507
    in add p [] : poly end
neuper@48850
   508
neuper@48848
   509
  (* brings the polynom in correct order and adds monomials *)
neuper@48851
   510
  fun order (p: poly) = (add_monoms o (sort lex_ord')) p;
neuper@48850
   511
neuper@48850
   512
  (* largest exponent of variable at location var *)
neuper@48851
   513
  fun max_deg_var (p: poly) var = (maxs o (map ((nth_swapped var) o snd))) p;
neuper@48851
   514
*}
neuper@48850
   515
neuper@48851
   516
subsection {* evaluation, translation uni--multivariate, etc *}
neuper@48851
   517
ML {*
neuper@48868
   518
  (* evaluate a polynomial in a certain variable and remove this var from the exp-list *)         
neuper@48870
   519
  fun eval_monom var value ((c, es): monom) =
neuper@48870
   520
    (c * (Integer.pow (nth es var) value), nth_drop var es) : monom
neuper@48870
   521
  fun eval (p: poly) var value = order (map (eval_monom var value) p)
neuper@48851
   522
neuper@48870
   523
  (* transform a multivariate to a univariate polynomial  TODO map?*)         
neuper@48851
   524
  fun multi_to_uni (p as (_, es)::_ : poly) = 
neuper@48851
   525
    if length es = 1 
neuper@48851
   526
    then 
neuper@48851
   527
      let fun transfer ([]: poly) (up: unipoly) = up 
neuper@48851
   528
            | transfer (mp as (c, es)::ps) up =
neuper@48851
   529
                if length up = hd es
neuper@48851
   530
                then transfer ps (up @ [c])
neuper@48851
   531
                else transfer mp (up @ [0])    
neuper@48851
   532
         in transfer (order p) [] end
neuper@48851
   533
    else error "Polynom has more than one variable!";
neuper@48851
   534
neuper@48870
   535
  (* transform a univariate to a multivariate polynomial TODO map *)         
neuper@48851
   536
  fun uni_to_multi (up: unipoly) =
neuper@48851
   537
    let fun transfer ([]: unipoly) (mp: poly) (_: int) = add_monoms mp
neuper@48851
   538
          | transfer up mp var = 
neuper@48851
   539
            transfer (tl up) (mp @ [(hd up, [var])]) (var + 1)
neuper@48851
   540
    in  transfer up [] 0 end
neuper@48853
   541
neuper@48851
   542
  (* multiply a poly with a variable represented by a unipoly (at position var) 
neuper@48870
   543
    e.g new z: (3x + 2y)*(z - 4)  TODO mp %%*%% (uni_to_multi up) !TODO equal es ! *)
neuper@48851
   544
  fun mult_with_new_var ([]: poly) (_: unipoly) (_: int) = []
neuper@48851
   545
    | mult_with_new_var mp up var = 
neuper@48851
   546
    let 
neuper@48851
   547
      fun mult ([]: poly) (_: unipoly) (_: int) (new: poly) (_: int) = add_monoms new
neuper@48851
   548
        | mult mp up var new _ =
neuper@48851
   549
          let
neuper@48851
   550
            (* the inner loop *)
neuper@48851
   551
            fun mult' (_: poly) ([]: unipoly) (_) (new': poly) (_: int) = order new'
neuper@48851
   552
              | mult' (mp' as (c, es)::ps) up' var new' c2' =
neuper@48851
   553
                let val (first, last) = chop var es
neuper@48851
   554
                in mult' mp' (tl up') var
neuper@48851
   555
                  (new' @ [(c * hd up', first @ [c2'] @ last)]) (c2' + 1)
neuper@48851
   556
                end
neuper@48851
   557
          in mult (tl mp) up var (new @ (mult' mp up var [] 0)) (0) end
neuper@48851
   558
    in mult mp up var [] 0 : poly end
neuper@48853
   559
neuper@48851
   560
  fun greater_deg (es1: int list) (es2: int list) =
neuper@48851
   561
    if es1 = [] andalso es2 =[] then 0
neuper@48851
   562
    else if (nth es1 (length es1 -1)) = (nth es2 (length es1 -1) ) 
neuper@48851
   563
         then greater_deg (nth_drop (length es1 -1) es1) (nth_drop (length es1 -1) es2)
neuper@48851
   564
         else if (nth es1 (length es1 -1)) > (nth es2 (length es1 -1)) 
neuper@48851
   565
              then 1 else 2
neuper@48853
   566
neuper@48851
   567
  (* Winkler p.95 *) 
neuper@48851
   568
  fun find_new_r (p1 as (_, es1)::_ : poly) (p2 as (_, es2)::_ : poly) old =
neuper@48855
   569
    let val p1' as (_, es1')::_ = eval p1 (length es1 - 2) (old + 1)
neuper@48855
   570
        val p2' as (_, es2')::_ = eval p2 (length es2 - 2) (old + 1);
neuper@48851
   571
    in
neuper@48851
   572
      if max_deg_var p1' (length es1' - 1) = max_deg_var p1 (length es1 - 1) orelse
neuper@48851
   573
         max_deg_var p2' (length es2' - 1) = max_deg_var p2 (length es1 - 1) 
neuper@48851
   574
      then old + 1
neuper@48851
   575
      else find_new_r p1 p2 (old + 1)
neuper@48851
   576
    end
neuper@48851
   577
*}
neuper@48851
   578
neuper@48851
   579
subsection {* addition, multiplication, division *}
neuper@48851
   580
ML {*
neuper@48850
   581
  (* resulting 0 coefficients are removed by add_monoms *)
meindl_diana@48797
   582
  infix %%/
neuper@48850
   583
  fun (p: poly) %%/ d = (add_monoms o (map (apfst (div2_swapped d)))) p;
meindl_diana@48797
   584
meindl_diana@48841
   585
  infix %%*
neuper@48850
   586
  fun (p: poly) %%* i = (add_monoms o (map (apfst (Integer.mult i)))) p;
meindl_diana@48841
   587
meindl_diana@48797
   588
  infix %%+%%
neuper@48853
   589
  (* the same algorithms as done by hand
neuper@48846
   590
  fun ([]: poly) %%+%% (mvp2: poly) = mvp2
neuper@48850
   591
    | p1 %%+%% [] = p1
neuper@48850
   592
    | p1 %%+%% p2 =
neuper@48850
   593
      let 
neuper@48851
   594
        fun plus [] p2 new = order (new @ p2)
neuper@48851
   595
          | plus p1 [] new = order (new @ p1)
neuper@48850
   596
          | plus (p1 as (c1, es1)::ps1) (p2 as (c2, es2)::ps2) new = 
neuper@48850
   597
            if greater_deg es1 es2 = 0
neuper@48850
   598
            then plus ps1 ps2 (new @ [((c1 + c2), es1)])
neuper@48850
   599
            else 
neuper@48850
   600
              if greater_deg es1 es2 = 1
neuper@48850
   601
              then plus p1 ps2 (new @ [(c2, es2)])
neuper@48850
   602
              else plus ps1 p2 (new @ [(c1, es1)])
neuper@48850
   603
      in plus p1 p2 [] end
neuper@48853
   604
  *)
neuper@48853
   605
  fun (p1 : poly) %%+%% (p2 : poly) = order (p1 @ p2)
neuper@48853
   606
meindl_diana@48797
   607
  infix %%-%%
neuper@48850
   608
  fun p1 %%-%% (p2: poly) = p1 %%+%% (map (apfst (Integer.mult ~1)) p2)
neuper@48851
   609
meindl_diana@48797
   610
  infix %%*%%
neuper@48853
   611
  fun mult_monom ((c1, es1): monom) ((c2, es2): monom) =
neuper@48853
   612
    (c1 * c2, map2 Integer.add es1 es2): monom;
neuper@48853
   613
  fun mult_monoms (ms: poly) m = map (mult_monom m) ms : poly
neuper@48853
   614
  fun p1 %%*%% (p2 : poly) = order (fold (curry op @) (map (mult_monoms p1) p2) [])
neuper@48853
   615
meindl_diana@48797
   616
  infix %%|%% 
neuper@48851
   617
  (* the same algorithms as done by hand; TODO fold / map ? *)
neuper@48850
   618
  fun ([(c1, es1)]: poly) %%|%%  ([(c2, es2)]: poly) = all_geq es2 es1 andalso c2 mod c1 = 0
neuper@48850
   619
    | _  %%|%% [(0,_)] = true
neuper@48850
   620
    | p1 %%|%% p2 =
neuper@48850
   621
      if [lmonom p1] %%|%% [lmonom p2]
neuper@48850
   622
      then 
neuper@48850
   623
        p1 %%|%% 
neuper@48850
   624
          (p2 %%-%%
neuper@48850
   625
            ([((lcoeff p2) div2 (lcoeff p1), (lexp p2) %-% (lexp p1))]
neuper@48850
   626
              %%*%% p1)) 
neuper@48850
   627
      else false
neuper@48853
   628
neuper@48851
   629
  (* %%/%% :: poly \<Rightarrow> poly \<Rightarrow> (poly \<times> poly)
neuper@48851
   630
     a %%/%% b = (c, r)
neuper@48851
   631
     assumes b \<noteq> [] \<and> 
neuper@48851
   632
     yields THE c r. c *\<^isub>p b  +\<^isub>p  r = a *)
neuper@48851
   633
  infix %%/%% 
neuper@48851
   634
  fun (p1: poly) %%/%% (p2: poly) =
neuper@48851
   635
    let 
neuper@48851
   636
      fun div_up p1 p2 quot_old = 
neuper@48851
   637
      let 
neuper@48851
   638
        val p1 as (c, es)::_ = drop_lc0 (order p1);
neuper@48851
   639
        val p2 = drop_lc0 (order p2);
neuper@48870
   640
        val [c] = zero_poly (length es);
neuper@48851
   641
        val d = (replicate (List.length p1 - List.length p2) c) @ p2 ;
neuper@48851
   642
        val quot = [(lcoeff p1 div2 lcoeff d, lexp p1 %-% lexp p2)];
neuper@48851
   643
        val rest = drop_lc0 (p1 %%-%% (d %%*%% quot));
neuper@48851
   644
      in 
neuper@48851
   645
        if rest <> [c] andalso all_geq' 0 (lexp rest %-% lexp p2)
neuper@48851
   646
        then div_up rest p2 (quot @ quot_old)
neuper@48851
   647
        else (quot @ quot_old : poly, rest)
neuper@48851
   648
      end
neuper@48851
   649
    in div_up p1 p2 [] end 
meindl_diana@48797
   650
*}
neuper@48848
   651
neuper@48846
   652
subsection {* Newton interpolation *}
meindl_diana@48797
   653
ML{* (* first step *)
neuper@48870
   654
  fun newton_first (x: int list) (f: poly list) (pos: int) =
neuper@48851
   655
    let 
neuper@48851
   656
      val new_vals = [(hd x) * ~1, 1];
neuper@48870
   657
      val p = (add_variable pos (hd f)) %%+%% 
neuper@48851
   658
        ((mult_with_new_var 
neuper@48870
   659
          (((nth f 1) %%-%% (hd f)) %%/ (nth x 1) - (hd x)))   new_vals pos);
neuper@48851
   660
      val steps = [((nth f 1) %%-%% (hd f)) %%/ ((nth x 1) - (hd x))]
neuper@48851
   661
    in (p, new_vals, steps) end
meindl_diana@48797
   662
  
neuper@48851
   663
   fun next_step ([]: poly list) (new_steps: poly list) (_: int list) = new_steps
neuper@48851
   664
     | next_step steps new_steps x =  
neuper@48851
   665
       next_step (tl steps)
neuper@48851
   666
         (new_steps @ 
neuper@48866
   667
           [((last new_steps) %%-%% (hd steps)) %%/ ((last x) - (nth x (length x - 3)))])
neuper@48851
   668
         (nth_drop (length x -2) x)
neuper@48851
   669
neuper@48870
   670
  fun NEWTON x f (steps: poly list) (up: unipoly) (p: poly) pos = 
meindl_diana@48797
   671
    if length x = 2
neuper@48851
   672
    then 
neuper@48870
   673
      let val (p', new_vals, steps) = newton_first x [(hd f), (nth f 1)] pos
neuper@48851
   674
      in (p', new_vals, steps) end
neuper@48851
   675
    else 
neuper@48850
   676
      let 
neuper@48851
   677
        val new_vals = 
neuper@48851
   678
          multi_to_uni ((uni_to_multi up) %%*%% (uni_to_multi [(nth x (length x -2) ) * ~1, 1]));
neuper@48851
   679
        val new_steps = [((nth f (length f - 1)) %%-%% (nth f (length f - 2))) %%/ 
neuper@48866
   680
          ((last x) - (nth x (length x - 2)))];
neuper@48851
   681
        val steps = next_step steps new_steps x;
neuper@48870
   682
        val p' = p %%+%% (mult_with_new_var (last steps) new_vals pos);
neuper@48851
   683
      in (order p', new_vals, steps) end 
meindl_diana@48841
   684
*}
meindl_diana@48797
   685
neuper@48851
   686
subsection {* gcd_poly algorithm, code for [1] p.95 *}
meindl_diana@48797
   687
ML {*
neuper@48868
   688
  (* naming of n, M, m, r, ...  follows Winkler p. 95 
neuper@48868
   689
    n: amount of variables 
neuper@48868
   690
    r: *)
neuper@48867
   691
  fun gcd_poly' (a as (_, es1)::_ : poly) (b as (_, es2)::_ : poly) n r =
neuper@48849
   692
    if lex_ord (lmonom b) (lmonom a) then gcd_poly' b a n r else
neuper@48868
   693
      if n > 1
neuper@48851
   694
      then
neuper@48868
   695
        let val M = 1 + Int.min (max_deg_var a (length es1 - 2), max_deg_var b (length es2 - 2)); 
neuper@48868
   696
        in try_new_r a b n M r [] [] end
neuper@48868
   697
      else 
neuper@48851
   698
        let val (a', b') = (multi_to_uni a, multi_to_uni b)
neuper@48851
   699
        in
neuper@48851
   700
          (* a b are made primitive and this is compensated by multiplying with gcd of divisors *)
neuper@48855
   701
          uni_to_multi ((gcd_up (primitive_up a') (primitive_up b')) %* 
neuper@48851
   702
                        (abs (Integer.gcd (gcd_coeff a') (gcd_coeff b'))))
neuper@48851
   703
        end
neuper@48867
   704
neuper@48867
   705
  (* fn: poly -> poly -> int -> 
neuper@48867
   706
                      int -> int -> int list -> poly list -> poly*)
neuper@48851
   707
  and try_new_r a b n M r r_list steps = 
meindl_diana@48816
   708
     let 
meindl_diana@48810
   709
        val r = find_new_r a b r;
meindl_diana@48810
   710
        val r_list = r_list @ [r];
neuper@48855
   711
        val g_r = gcd_poly' (order (eval a (n - 2) r)) 
neuper@48855
   712
                            (order (eval b (n - 2) r)) (n - 1) 0
meindl_diana@48810
   713
        val steps = steps @ [g_r];
neuper@48870
   714
      in HENSEL_lifting a b n M 1 r r_list steps g_r ( zero_poly n ) [1] end
neuper@48867
   715
  (* fn: poly -> poly -> int -> 
neuper@48867
   716
                           int -> int -> int -> int list -> poly list -> 
neuper@48867
   717
                           |                  poly -> poly -> int list -> poly*)
neuper@48867
   718
  and HENSEL_lifting a b n M m r r_list steps g g_n mult =
neuper@48869
   719
    if m > M then if g_n %%|%% a andalso g_n %%|%% b then g_n else
meindl_diana@48816
   720
      try_new_r a b n M r r_list steps 
meindl_diana@48810
   721
    else
meindl_diana@48810
   722
      let 
meindl_diana@48810
   723
        val r = find_new_r a b r; 
meindl_diana@48810
   724
        val r_list = r_list @ [r];
neuper@48855
   725
        val g_r = gcd_poly' (order (eval a (n - 2) r)) 
neuper@48855
   726
                            (order (eval b (n - 2) r)) (n - 1) 0
meindl_diana@48810
   727
      in  
neuper@48849
   728
        if lex_ord (lmonom g) (lmonom g_r)
neuper@48869
   729
        then HENSEL_lifting a b n M 1 r r_list steps g g_n mult
neuper@48850
   730
        else if (lexp g) = (lexp g_r) 
neuper@48867
   731
          then
neuper@48867
   732
            let val (g_n, new, steps) = NEWTON r_list [g, g_r] steps mult g_n (n - 2)
neuper@48867
   733
            in 
neuper@48870
   734
              if (nth steps (length steps - 1)) = (zero_poly (n - 1))
neuper@48869
   735
              then HENSEL_lifting a b n M (M + 1) r r_list steps g_r g_n new
neuper@48869
   736
              else HENSEL_lifting a b n M (m + 1) r r_list steps g_r g_n new
neuper@48867
   737
            end
neuper@48867
   738
          else (* \<not> lex_ord (lmonom g) (lmonom g_r) *)
neuper@48869
   739
            HENSEL_lifting a b n M (m + 1) r r_list steps g  g_n mult
neuper@48868
   740
      end
neuper@48853
   741
neuper@48851
   742
  (* gcd_poly :: poly \<Rightarrow> poly \<Rightarrow> poly
neuper@48851
   743
     gcd_poly a b = ((a', b'), c)
neuper@48851
   744
     assumes a \<noteq> [] \<and> b \<noteq> [] \<and> 
neuper@48851
   745
     yields a = a' *\<^isub>p c  \<and>  b = b' *\<^isub>p c \<and> 
neuper@48851
   746
       (\<forall>c'. (c' dvd\<^isub>p  a \<and> c' dvd\<^isub>p b) \<longrightarrow> c' \<le>\<^isub>p c) *)
neuper@48851
   747
  fun gcd_poly (a as (_, es)::_ : poly) b = 
neuper@48851
   748
    let val c = gcd_poly' a b (length es) 0
neuper@48851
   749
        val (a': poly, _) = a %%/%% c
neuper@48851
   750
        val (b': poly, _) = b %%/%% c
neuper@48851
   751
    in ((a', b'), c) end
meindl_diana@48797
   752
*}
meindl_diana@48797
   753
neuper@48851
   754
section {* example from the last mail *}
neuper@48851
   755
ML {* (* test, see text below *)
neuper@48851
   756
  val a = [(1,[2, 0]), (~1,[0, 2])];
neuper@48851
   757
  val b = [(1,[2, 0]), (~1,[1, 1])] ;
neuper@48851
   758
  val ((a', b'), c) = gcd_poly a b;
neuper@48851
   759
neuper@48851
   760
  a' = [(~1, [1, 0]), (~1, [0, 1])];
neuper@48851
   761
  b' = [(~1, [1, 0])];
neuper@48867
   762
  c = [(~1, [1, 0]), (1, [0, 1])];
neuper@48867
   763
  (* checking the postcondition: *)
neuper@48867
   764
  a = (a' %%*%% c) andalso b = (b' %%*%% c); (* where "%%*%%" is "*\<^isub>p" *)
neuper@48867
   765
  (* \<forall>c'. (c' dvd\<^isub>p  a \<and> c' dvd\<^isub>p b) \<longrightarrow> c' \<le>\<^isub>p c) can NOT be checked this way, of course *)
neuper@48851
   766
*}
neuper@48851
   767
neuper@48851
   768
text {* last mail to Tobias Nipkow:
neuper@48851
   769
Eine erste Idee, wie die Integration der Diplomarbeit für einen Benutzer 
neuper@48851
   770
von Isabelle aussehen könnte, wäre zum Beispiel im
neuper@48851
   771
neuper@48851
   772
   lemma cancel:
neuper@48851
   773
     assumes asm3: "x^2 - x*y \<noteq> 0" and asm4: "x \<noteq> 0"
neuper@48851
   774
     shows "(x^2 - y^2) / (x^2 - x*y) = (x + y) / (x::real)"
neuper@48851
   775
     apply (insert asm3 asm4)
neuper@48851
   776
     apply simp
neuper@48851
   777
   sorry
neuper@48851
   778
neuper@48851
   779
die Assumptions
neuper@48851
   780
neuper@48851
   781
   asm1: "(x^2 - y^2) = (x + y) * (x - y)" and asm2: "x^2 - x*y = x * (x - y)"
neuper@48851
   782
neuper@48851
   783
im Hintergrund automatisch zu erzeugen (mit der Garantie, dass "(x - y)" der GCD ist) 
neuper@48851
   784
und sie dem Simplifier (für die Rule nonzero_mult_divide_mult_cancel_right) zur 
neuper@48851
   785
Verfügung zu stellen, sodass anstelle von "sorry" einfach "done" stehen kann.
neuper@48851
   786
Und weiters wäre eventuell asm3 zu "x - y \<noteq> 0" zu vereinfachen, eine 
neuper@48851
   787
Rewriteorder zum Herstellen einer Normalform festzulegen, etc.
neuper@48851
   788
*}
meindl_diana@48797
   789
end
meindl_diana@48797
   790
meindl_diana@48797
   791