src/Tools/isac/Knowledge/GCD_Poly.thy
author diana <meindl_diana@yahoo.com>
Sat, 16 Mar 2013 14:52:02 +0100
changeset 48841 0dcb6d42fbea
parent 48840 b4eb4e916967
child 48844 286814b700a9
permissions -rw-r--r--
GCD_POLY -> new fun %%/%%
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
meindl_diana@48797
    12
chapter {* The Isabelle Theory *}
meindl_diana@48797
    13
text {*
meindl_diana@48797
    14
  Below we reference 
meindl_diana@48797
    15
  F. Winkler, Polynomial Algorithms. ...
neuper@48831
    16
  by page 93 and 95. This is the final version of the Isabelle theory,
neuper@48831
    17
  which conforms with Isabelle's coding standards and with requirements
neuper@48831
    18
  in terms of logics appropriate for a theorem prover.
neuper@48831
    19
*}
neuper@48831
    20
neuper@48831
    21
section {* Predicates for the specifications *}
neuper@48831
    22
text {*
neuper@48831
    23
  This thesis provides program code to be integrated into the Isabelle 
neuper@48831
    24
  distribution.  Thus the code will be verified against specifications, and 
neuper@48831
    25
  consequently the code, as \emph{explicit} specification of how to calculate 
neuper@48831
    26
  results, is accompanied by \emph{implicit} specifications describing the 
neuper@48831
    27
  properties of the program code.
neuper@48831
    28
neuper@48831
    29
  For describing the properties of code the format of Haskell will be used.
neuper@48831
    30
  Haskell \cite{TODO} is front-of-the-wave in research on functional 
neuper@48831
    31
  programming and as such advances beyond SML. The advancement relevant for 
neuper@48831
    32
  this thesis is the concise combination of explicit and implicit specification
neuper@48831
    33
  of a function. The final result of the code developed within this thesis is 
neuper@48831
    34
  described as follows in Haskell format:
neuper@48831
    35
neuper@48831
    36
  \begin{verbatim} % TODO: find respective Isabelle/LaTeX features
neuper@48831
    37
    gcd_poly :: int poly \<Rightarrow> int poly \<Rightarrow> int poly
neuper@48831
    38
    gcd_poly p1 p2 = d
neuper@48831
    39
    assumes and p1 \<noteq> [:0:] and p2 \<noteq> [:0:]
neuper@48831
    40
    yields d dvd p1 \<and> d dvd p2 \<and> \<forall>dd. (dd dvd p1 \<and> dd dvd p2) \<longrightarrow> dd \<le> d
neuper@48831
    41
  \end{verbatim
neuper@48831
    42
  
neuper@48831
    43
  The above specification combines Haskell format with the term language of
neuper@48831
    44
  Isabelle\HOL. The latter provides a large and ever growing library of 
neuper@48831
    45
  mechanised mathematics knowledge, which this thesis re-uses in order to 
neuper@48831
    46
  prepare for integration of the code.
neuper@48831
    47
neuper@48831
    48
  In the sequel there is a brief account of the notions required for the 
neuper@48831
    49
  specification of the functions implemented within this thesis. *}
neuper@48831
    50
neuper@48831
    51
subsection {* The Isabelle types required *}
neuper@48831
    52
text {*
neuper@48831
    53
  bool, nat, int, option, THE, list, poly
neuper@48831
    54
*}
neuper@48831
    55
subsection {* The connectives required *}
neuper@48831
    56
text {*
neuper@48831
    57
  logic ~~/doc/tutorial.pdf p.203
neuper@48831
    58
  arithmetic < \<le> + - * ^ (*\<equiv> Power.power FIXME: make uniform*) div \<bar> \<bar>
neuper@48831
    59
*}
neuper@48831
    60
neuper@48831
    61
subsection {* The Isabelle functions required *}
neuper@48831
    62
text {*
neuper@48831
    63
  number theory
neuper@48831
    64
    dvd, mod, gcd
neuper@48831
    65
    Primes.prime
neuper@48831
    66
    Primes.next_prime_bound
neuper@48831
    67
neuper@48831
    68
  lists
neuper@48831
    69
    List.hd, List.tl
neuper@48831
    70
    List.length, List.member
neuper@48831
    71
    List.fold, List.map
neuper@48831
    72
    List.nth, List.take, List.drop
neuper@48831
    73
    List.replicate
neuper@48831
    74
    
neuper@48831
    75
  others
neuper@48831
    76
    Fact.fact
meindl_diana@48797
    77
*}
meindl_diana@48797
    78
neuper@48813
    79
section {* gcd for univariate polynomials *}
meindl_diana@48797
    80
ML {*
meindl_diana@48799
    81
type unipoly = int list;
meindl_diana@48799
    82
val a = [~18, ~15, ~20, 12, 20, ~13, 2];
meindl_diana@48799
    83
val b = [8, 28, 22, ~11, ~14, 1, 2];
meindl_diana@48797
    84
*}
meindl_diana@48797
    85
neuper@48813
    86
subsection {* a variant for div *}
neuper@48817
    87
ML {* (* 5 div 2 = 2; ~5 div 2 = ~3; but ~5 div2 2 = ~2; *)
neuper@48813
    88
  infix div2
neuper@48813
    89
  fun a div2 b = 
neuper@48836
    90
    if a div b < 0 
neuper@48836
    91
    then (abs a) div (abs b) * ~1
meindl_diana@48799
    92
    else a div b;
meindl_diana@48797
    93
*}
meindl_diana@48797
    94
meindl_diana@48797
    95
subsection {* modulo calculations for integers *}
meindl_diana@48797
    96
ML {*
neuper@48836
    97
  (* mod_inv :: int \<Rightarrow> nat 
neuper@48817
    98
     mod_inv r m = s
neuper@48836
    99
     assumes True
neuper@48836
   100
     yields r * s mod m = 1 *)
meindl_diana@48797
   101
  fun mod_inv r m =
meindl_diana@48797
   102
    let
meindl_diana@48797
   103
      fun modi (r, rold, m, rinv) = 
neuper@48836
   104
        if m <= rinv then 0 else
meindl_diana@48797
   105
          if r mod m = 1
meindl_diana@48797
   106
          then rinv
meindl_diana@48797
   107
          else modi (rold * (rinv + 1), rold, m, rinv + 1)
meindl_diana@48799
   108
     in modi (r, r, m, 1) end;
meindl_diana@48797
   109
neuper@48836
   110
  (* mod_div :: int \<Rightarrow> int \<Rightarrow> nat \<Rightarrow> nat
neuper@48817
   111
     mod_div a b m = c
neuper@48836
   112
     assumes True
neuper@48836
   113
     yields a * b ^(-1) mod m = c   <\<Longrightarrow>  a mod m = *)
neuper@48813
   114
  fun mod_div a b m = a * (mod_inv b m) mod m;
meindl_diana@48797
   115
neuper@48836
   116
  (* required just for one approximation:
neuper@48836
   117
     approx_root :: nat \<Rightarrow> nat
neuper@48817
   118
     approx_root a = r
neuper@48836
   119
     assumes True
neuper@48836
   120
     yields r * r \<ge> a *)
neuper@48813
   121
  fun approx_root a =
neuper@48836
   122
    let
neuper@48836
   123
      fun root1 a n = if n * n < a then root1 a (n + 1) else n
neuper@48836
   124
    in root1 a 1 end
meindl_diana@48797
   125
neuper@48836
   126
  (* chinese_remainder :: int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int
neuper@48836
   127
     chinese_remainder r1 m1 r2 m2 = r
neuper@48836
   128
     assumes True
neuper@48836
   129
     yields r = r1 mod m1 \<and> r = r2 mod m2 *)
meindl_diana@48810
   130
  fun chinese_remainder (r1: int, m1: int, r2: int, m2: int ) =
meindl_diana@48797
   131
   (r1 mod m1) + ((r2 - (r1 mod m1)) * (mod_inv m1 m2) mod m2) * m1
meindl_diana@48797
   132
*}
meindl_diana@48797
   133
neuper@48813
   134
subsection {* operations with primes *}
meindl_diana@48797
   135
ML{*
neuper@48830
   136
  (* is_prime :: int list \<Rightarrow> int \<Rightarrow> bool
neuper@48830
   137
     is_prime ps n = b
neuper@48830
   138
     assumes max ps < n  \<and>  n \<le> (max ps)^2  \<and>  
neuper@48830
   139
       (*     FIXME: really ^^^^^^^^^^^^^^^? *)
neuper@48831
   140
       (\<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
   141
     yields Primes.prime n *)
neuper@48834
   142
  fun is_prime [] _ = true
neuper@48834
   143
    | is_prime prs n = 
neuper@48834
   144
        if n mod (List.hd prs) <> 0 then is_prime (List.tl prs) n else false
meindl_diana@48797
   145
neuper@48830
   146
  (* make_primes is just local to primes_upto only:
neuper@48830
   147
     make_primes :: int list \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int list
neuper@48830
   148
     make_primes ps last_p n = pps
neuper@48831
   149
     assumes last_p = maxs ps  \<and>  (\<forall>p. List.member ps p \<longrightarrow> Primes.prime p)  \<and>
neuper@48831
   150
       (\<forall>p. p < last_p \<and> Primes.prime p \<longrightarrow> List.member ps p)
neuper@48836
   151
     yields n \<le> maxs pps  \<and>  (\<forall>p. List.member pps p \<longrightarrow> Primes.prime p)  \<and>
neuper@48831
   152
       (\<forall>p. (p < maxs pps \<and> Primes.prime p) \<longrightarrow> List.member pps p)*)
neuper@48834
   153
    fun make_primes ps last_p n =
neuper@48834
   154
        if n <= (nth ps (List.length ps - 1)) then ps else
neuper@48813
   155
          if is_prime ps (last_p + 2) 
neuper@48813
   156
          then make_primes (ps @ [(last_p + 2)]) (last_p + 2) n
neuper@48834
   157
          else make_primes  ps                   (last_p + 2) n
neuper@48834
   158
neuper@48831
   159
  (* primes_upto :: nat \<Rightarrow> nat list
neuper@48830
   160
     primes_upto n = ps
neuper@48831
   161
       assumes True
neuper@48836
   162
       yields (\<forall>p. List.member ps p \<longrightarrow> Primes.prime p) \<and>
neuper@48831
   163
         n \<le> maxs ps \<and> maxs ps \<le> Fact.fact n + 1 \<and>
neuper@48835
   164
         (\<forall>p. p \<le> maxs ps \<and> Primes.prime p \<longrightarrow> List.member ps p) *)
neuper@48836
   165
  fun primes_upto n = if n < 3 then [2] else make_primes [2, 3] 3 n
neuper@48813
   166
 
neuper@48831
   167
  (* find the next prime greater p not dividing the number n:
neuper@48827
   168
    next_prime_not_dvd :: int \<Rightarrow> int \<Rightarrow> int (infix)
neuper@48827
   169
    n1 next_prime_not_dvd n2 = p
neuper@48831
   170
      assumes True
neuper@48837
   171
      yields p is_prime  \<and>  n1 < p  \<and>  \<not> p dvd n2  \<and> (* smallest with these properties... *)
neuper@48837
   172
        (\<forall> p'. (p' is_prime  \<and>  n1 < p'  \<and>  \<not> p' dvd n2)  \<longrightarrow>  p \<le> p') *)
neuper@48835
   173
  infix next_prime_not_dvd;
neuper@48835
   174
  fun n1 next_prime_not_dvd n2 = 
neuper@48813
   175
    let
neuper@48835
   176
      val ps = primes_upto (n1 + 1)
neuper@48813
   177
      val nxt = nth ps (List.length ps - 1);
meindl_diana@48797
   178
    in
neuper@48836
   179
      if n2 mod nxt <> 0 then nxt else nxt next_prime_not_dvd n2
meindl_diana@48797
   180
  end
meindl_diana@48797
   181
*}
meindl_diana@48797
   182
neuper@48814
   183
subsection {* auxiliary functions for univariate polynomials *}
neuper@48813
   184
ML {*
neuper@48815
   185
  (* leading coefficient *)
neuper@48839
   186
  fun lcoeff (p: unipoly) =
neuper@48839
   187
    if nth p (List.length p - 1) <> 0
neuper@48839
   188
    then nth p (List.length p - 1)
neuper@48839
   189
    else lcoeff (nth_drop (length p - 1) p : unipoly);
meindl_diana@48797
   190
  
neuper@48815
   191
  (* degree *)
neuper@48839
   192
  fun deg (p: unipoly) = 
neuper@48839
   193
    if nth p (length p - 1) <> 0
neuper@48839
   194
    then length p - 1
neuper@48839
   195
    else deg (nth_drop (length p - 1) p : unipoly);
meindl_diana@48797
   196
neuper@48815
   197
  (* drop leading coefficients equal 0 *)
neuper@48815
   198
  fun drop_lc0 [] = []
neuper@48839
   199
    | drop_lc0 (p: unipoly) = 
neuper@48839
   200
      if nth p (length p - 1) = 0
neuper@48839
   201
      then drop_lc0 (nth_drop (length p - 1) p : unipoly)
neuper@48839
   202
      else p;
meindl_diana@48797
   203
neuper@48836
   204
  (* normalise a unipoly such that lcoeff mod m = 1.
neuper@48817
   205
     normalise :: unipoly \<Rightarrow> nat \<Rightarrow> unipoly
neuper@48817
   206
     normalise [p_0, .., p_k] m = [q_0, .., q_k]
neuper@48827
   207
       assumes True
neuper@48817
   208
       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
   209
  fun normalise (p: unipoly) (m: int) =
meindl_diana@48797
   210
    let
neuper@48815
   211
      val p = drop_lc0 p
neuper@48830
   212
      val lcp = lcoeff p;
neuper@48815
   213
      fun norm nrm i =
neuper@48814
   214
        if i = 0
neuper@48815
   215
        then [mod_div (nth p i) lcp m] @ nrm
neuper@48815
   216
        else norm ([mod_div (nth p i) lcp m] @  nrm) (i - 1) ;
meindl_diana@48797
   217
    in 
neuper@48815
   218
      if List.length p = 0 then p else norm [] (List.length p - 1)
neuper@48815
   219
  end;
meindl_diana@48797
   220
neuper@48815
   221
  (* scalar multiplication *)
neuper@48815
   222
  infix %*
neuper@48839
   223
  fun (p: unipoly) %* n =  map (Integer.mult n) p : unipoly
neuper@48815
   224
  
neuper@48815
   225
  (* scalar divison *)
neuper@48815
   226
  infix %/ 
neuper@48817
   227
  fun (p: unipoly) %/ n =
neuper@48817
   228
    let fun swapf f a b = f b a (* swaps the arguments of a function *)
neuper@48839
   229
    in map (swapf (curry op div2) n) p : unipoly end;
meindl_diana@48797
   230
neuper@48815
   231
  (* minus of polys *)
meindl_diana@48797
   232
  infix %-%
neuper@48839
   233
  fun (p1: unipoly) %-% (p2: unipoly) = 
neuper@48839
   234
    map2 (curry op -) p1 (p2 @ replicate (List.length p1 - List.length p2) 0) : unipoly
meindl_diana@48797
   235
neuper@48823
   236
  (* dvd for univariate polynomials *)
meindl_diana@48797
   237
  infix %|%
neuper@48839
   238
  fun [d] %|% [p] =
neuper@48839
   239
      if abs d <= abs p andalso p mod d = 0 then true else false
neuper@48839
   240
    | (ds: unipoly) %|% (ps: unipoly) = 
neuper@48837
   241
      let 
neuper@48839
   242
        val ds = drop_lc0 ds;
neuper@48839
   243
        val ps = drop_lc0 ps;
neuper@48839
   244
        val d000 = (replicate (List.length ps - List.length ds) 0) @ ds ;
neuper@48839
   245
        val quot = (lcoeff ps) div2 (lcoeff d000);
neuper@48839
   246
        val rest = drop_lc0 (ps %-% (d000 %* quot));
neuper@48837
   247
      in 
neuper@48837
   248
        if rest = [] then true else
neuper@48839
   249
          if quot <> 0 andalso List.length ds <= List.length rest
neuper@48839
   250
          then ds %|% rest 
neuper@48837
   251
          else false
neuper@48837
   252
      end
neuper@48826
   253
 
neuper@48827
   254
  (* normalise :: poly_centr \<Rightarrow> unipoly => int \<Rightarrow> unipoly
neuper@48826
   255
     normalise [p_0, .., p_k] m = [q_0, .., q_k]
neuper@48826
   256
       assumes 
neuper@48836
   257
       yields 0 \<le> i \<le> k \<Rightarrow> |^ ~m/2 ^| <= q_i <=|^ m/2 ^| 
neuper@48836
   258
        (where |^ x ^| means round x up to the next greater integer) *)
neuper@48823
   259
  fun poly_centr (p: unipoly) (m: int) =
meindl_diana@48797
   260
    let
neuper@48823
   261
      val mi = m div2 2;
neuper@48823
   262
      val mid = if m mod mi = 0 then mi else mi + 1;
neuper@48823
   263
      fun centr m mid p_i = if mid < p_i then p_i - m else p_i;
neuper@48839
   264
    in map (centr m mid) p : unipoly end;
meindl_diana@48797
   265
neuper@48836
   266
  (*** landau mignotte bound (Winkler p91)
neuper@48831
   267
    every coefficient of the gcd of a  and b in Z[x] is bounded in absolute value by
neuper@48827
   268
    2^{min(m,n)} * gcd(a_m,b_n) * min(1/|a_m| 
neuper@48836
   269
    * root(sum_{i=0}^{m}a_i^2) ,1/|b_n| * root( sum_{i=0}^{n}b_i^2 ) ***)
neuper@48826
   270
neuper@48831
   271
   (*  sum_lmb :: poly_centr \<Rightarrow> unipoly \<Rightarrow> int \<Rightarrow> int
neuper@48826
   272
     sum_lmb [p_0, .., p_k] e = s
neuper@48826
   273
       assumes exp >= 0
neuper@48836
   274
       yields. p_0^e + p_1^e + ... + p_k^e *)
neuper@48823
   275
  fun sum_lmb (p: unipoly) exp = fold ((curry op +) o (Integer.pow exp)) p 0;
meindl_diana@48810
   276
neuper@48831
   277
   (* LANDAU_MIGNOTTE_bound :: poly_centr \<Rightarrow> unipoly \<Rightarrow> unipoly \<Rightarrow> int
neuper@48830
   278
      LANDAU_MIGNOTTE_bound [a_0, ..., a_m] [b_0, .., b_n] = lmb
neuper@48827
   279
        assumes True
neuper@48836
   280
        yields lmb = 2^min(m,n) * gcd(a_m,b_n) * 
neuper@48827
   281
          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
   282
  fun LANDAU_MIGNOTTE_bound (p1: unipoly) (p2: unipoly) = 
neuper@48830
   283
    (Integer.pow (Integer.min (deg p1) (deg p2)) 2) * (abs (Integer.gcd (lcoeff p1) (lcoeff p2))) * 
neuper@48830
   284
    (Int.min (abs((approx_root (sum_lmb p1 2)) div2 ~(lcoeff p1)), 
neuper@48830
   285
              abs((approx_root (sum_lmb p2 2)) div2 ~(lcoeff p2))));
meindl_diana@48797
   286
*}
meindl_diana@48797
   287
meindl_diana@48797
   288
subsection {* modulo calculations for polynomials *}
meindl_diana@48797
   289
ML{*
meindl_diana@48838
   290
  (* chinese_remainder_poly :: int * int \<Rightarrow> unipoly * unipoly \<Rightarrow> unipoly
meindl_diana@48838
   291
     chinese_remainder_poly (m1, m2) (p1, p2) = p
meindl_diana@48838
   292
     assume m1, m2 relatively prime
meindl_diana@48838
   293
     yields p1 = p mod m1 \<and> p2 = p mod m2
meindl_diana@48838
   294
 *)
neuper@48823
   295
  fun chinese_remainder_poly (m1, m2) (p1: unipoly, p2: unipoly) = 
meindl_diana@48797
   296
  let 
neuper@48823
   297
    fun chinese_rem (m1, m2) (p_1i, p_2i) = chinese_remainder (p_1i, m1, p_2i, m2)
neuper@48823
   298
  in map (chinese_rem (m1, m2)) (p1 ~~ p2): unipoly end
meindl_diana@48797
   299
meindl_diana@48838
   300
  (* mod_poly :: unipoly \<Rightarrow> int \<Rightarrow> unipoly
meindl_diana@48838
   301
     mod_poly [p1, p2, ..., pk] m = up 
meindl_diana@48838
   302
     assume m > 0
meindl_diana@48838
   303
     yields up = [p1 mod m, p2 mod m, ..., pk mod m]*)
meindl_diana@48838
   304
  infix mod_poly 
meindl_diana@48838
   305
    fun uvp mod_poly m = 
neuper@48815
   306
    let 
meindl_diana@48838
   307
      fun modp m up = (curry op mod) up m 
meindl_diana@48838
   308
    in map (modp m) uvp end
meindl_diana@48797
   309
meindl_diana@48819
   310
  (* euclidean algoritm in Z_p[x].
neuper@48831
   311
     mod_poly_gcd :: unipoly \<Rightarrow> unipoly \<Rightarrow> int \<Rightarrow> unipoly
meindl_diana@48819
   312
     mod_poly_gcd p1 p2 m = g
neuper@48836
   313
       assumes True
neuper@48836
   314
       yields gcd ((p1 mod m), (p2 mod m)) = g *)
neuper@48823
   315
  fun mod_poly_gcd (p1: unipoly) (p2: unipoly) (m: int) =
meindl_diana@48797
   316
    let 
neuper@48823
   317
      val p1m = p1 mod_poly m;
neuper@48823
   318
      val p2m = drop_lc0 (p2 mod_poly m);
neuper@48823
   319
      val p2n = (replicate (List.length p1 - List.length p2m) 0) @ p2m;
neuper@48830
   320
      val quot =  mod_div (lcoeff p1m) (lcoeff p2n) m;
neuper@48823
   321
      val rest = drop_lc0 ((p1m %-% (p2n %* quot)) mod_poly m)
neuper@48836
   322
    in
neuper@48836
   323
      if rest = [] then p2 else
neuper@48836
   324
        if length rest < List.length p2
neuper@48836
   325
        then mod_poly_gcd p2 rest m 
neuper@48836
   326
        else mod_poly_gcd rest p2 m
neuper@48823
   327
    end;
neuper@48823
   328
neuper@48831
   329
  (* prim_poly :: unipoly \<Rightarrow> unipoly
neuper@48831
   330
     prim_poly p = pp
neuper@48831
   331
     assumes True
neuper@48836
   332
     yields \<forall>p1, p2. (List.member pp p1 \<and> List.member pp p2 \<and> p1 \<noteq> p2) \<longrightarrow> gcd p1 p2 = 1 *)
neuper@48831
   333
  fun prim_poly [c: int] = if c = 0 then [0] else [1]
neuper@48831
   334
    | prim_poly (p: unipoly) =
neuper@48831
   335
        let
neuper@48831
   336
          val d = abs (Integer.gcds p)
neuper@48831
   337
        in
neuper@48831
   338
          if d = 1 then p else p %/ d
neuper@48831
   339
        end
meindl_diana@48797
   340
*}
meindl_diana@48797
   341
neuper@48834
   342
subsection {* gcd_unipoly, code from [1] p.93 *}
meindl_diana@48797
   343
ML {*
meindl_diana@48838
   344
  (* try_new_prime_up :: unipoly \<Rightarrow> unipoly \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> unipoly \<Rightarrow> int  \<Rightarrow> unipoly
meindl_diana@48838
   345
     try_new_prime_up p1 p2 d M P g p = new_g
meindl_diana@48838
   346
       assumes d = gcd(lc(p1), lc(p2)) \<and> M = LANDAU_MIGNOTTE_bound \<and> p = prime \<and> p ~| d \<and> P \<ge> p \<and>
meindl_diana@48838
   347
               p1 is primitive \<and> p2 is primitive  ----> primitive = prim_poly
meindl_diana@48838
   348
       yields  new_g = [1] \<or> (new_g \<ge> g \<and> P > M)*)
neuper@48835
   349
  fun try_new_prime_up a b d M P g p =
neuper@48836
   350
    if P > M then g else
neuper@48833
   351
      let
neuper@48835
   352
        val p = p next_prime_not_dvd d
neuper@48834
   353
        val g_p = 
neuper@48834
   354
          poly_centr (((normalise (mod_poly_gcd a b p) p) %* (d mod p)) mod_poly p) p: unipoly
neuper@48827
   355
      in
neuper@48827
   356
        if deg g_p < deg g
neuper@48827
   357
        then
neuper@48835
   358
          if (deg g_p) = 0 then [1]: unipoly else try_new_prime_up a b d M p g_p p
neuper@48827
   359
        else
neuper@48836
   360
          if deg g_p <> deg g then try_new_prime_up a b d M P g p else
neuper@48827
   361
            let 
neuper@48827
   362
              val P = P * p
neuper@48827
   363
              val g = poly_centr ((chinese_remainder_poly (P, p) (g, g_p)) mod_poly P) P
neuper@48835
   364
            in try_new_prime_up a b d M P g p end
neuper@48827
   365
      end
neuper@48834
   366
      
meindl_diana@48838
   367
  (* HENSEL_lifting_up :: unipoly \<Rightarrow> unipoly \<Rightarrow> int \<Rightarrow> int \<Rightarrow> int \<Rightarrow> unipoly
meindl_diana@48838
   368
     HENSEL_lifting_up p1 p2 d M p = gcd
meindl_diana@48838
   369
       assumes d = gcd(lc(p1), lc(p2)) \<and> M = LANDAU_MIGNOTTE_bound \<and> p = prime \<and> p ~| d  \<and>
meindl_diana@48838
   370
               p1 is primitive \<and> p2 is primitive  ----> primitive = prim_poly
meindl_diana@48838
   371
       yields  gcd|p1  \<and> gcd|p2  \<and> gcd is primitive*)
neuper@48835
   372
  fun HENSEL_lifting_up a b d M p = 
neuper@48823
   373
    let 
neuper@48835
   374
      val p = p next_prime_not_dvd d 
neuper@48835
   375
      val g_p = poly_centr(((normalise ( mod_poly_gcd a b p) p) %* (d mod p)) mod_poly p) p
neuper@48823
   376
    in
neuper@48836
   377
      if deg g_p = 0 then [1] else
neuper@48835
   378
        let 
neuper@48835
   379
          val g = prim_poly (try_new_prime_up a b d M p g_p p)
neuper@48827
   380
        in
neuper@48836
   381
          if (g %|% a) andalso (g %|% b) then g else HENSEL_lifting_up a b d M p
neuper@48827
   382
        end
neuper@48827
   383
    end
neuper@48834
   384
neuper@48836
   385
  (* gcd_poly :: unipoly \<Rightarrow> unipoly \<Rightarrow> unipoly
neuper@48829
   386
     gcd_poly a b = c
meindl_diana@48838
   387
     assumes not (a = [] \<or> a = [0]) \<and> not (b = []\<or> b = [0]) \<and> 
meindl_diana@48838
   388
             a is primitive \<and> b is primitive
neuper@48836
   389
     yields c dvd a \<and> c dvd b \<and> (\<forall>c'. (c' dvd a \<and> c' dvd b) \<longrightarrow> c' \<le> c) *)
neuper@48829
   390
  fun gcd_unipoly (a: unipoly) (b: unipoly) =
neuper@48829
   391
    if a = b then a else
neuper@48835
   392
      HENSEL_lifting_up a b (abs (Integer.gcd (lcoeff a) (lcoeff b)))  
neuper@48835
   393
        (2 * (abs (Integer.gcd (lcoeff a) (lcoeff b))) * LANDAU_MIGNOTTE_bound a b) 1;
meindl_diana@48797
   394
*}
meindl_diana@48797
   395
(* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
neuper@48807
   396
subsection {* gcd_poly Algorgithmus, auxiliary functions multivariate *}
meindl_diana@48797
   397
(* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
meindl_diana@48797
   398
meindl_diana@48797
   399
ML {*
meindl_diana@48797
   400
type monom = (int * int list);
meindl_diana@48797
   401
type multipoly = monom list;
meindl_diana@48797
   402
*}
meindl_diana@48797
   403
meindl_diana@48797
   404
subsection {* calculations for multivariate polynomials *}
meindl_diana@48797
   405
meindl_diana@48797
   406
ML {*
neuper@48829
   407
(* assumes a and b have the same length*)
meindl_diana@48797
   408
  fun listgreater a b = 
meindl_diana@48797
   409
    let fun gr a b = a>=b;
meindl_diana@48797
   410
    fun all [] = true 
meindl_diana@48797
   411
      | all list = 
neuper@48826
   412
      if List.hd list then all (List.tl list)  else false 
meindl_diana@48797
   413
    in all (map2 gr a b)
meindl_diana@48797
   414
  end
neuper@48826
   415
 
meindl_diana@48797
   416
  fun get_coef (mvp: multipoly) (place: int) =
neuper@48826
   417
    let fun coef ((c,_): monom) = c;
neuper@48826
   418
    in coef (List.nth (mvp, place)) end 
meindl_diana@48797
   419
  
meindl_diana@48797
   420
  fun get_varlist (mvp: multipoly) (place: int) =
meindl_diana@48797
   421
    let fun varlist ((_,var): monom) = var;
meindl_diana@48797
   422
    in varlist (nth mvp place) end
neuper@48826
   423
meindl_diana@48797
   424
  fun get_coeflist (poly: multipoly) = 
meindl_diana@48797
   425
    let 
neuper@48826
   426
      fun get_clist (poly: multipoly) list = 
neuper@48826
   427
        if poly = [] then list
neuper@48828
   428
        else get_clist (List.tl poly) (list @ [get_coef poly 0])
neuper@48828
   429
    in get_clist poly [] end
neuper@48826
   430
*}
neuper@48826
   431
ML{*
neuper@48826
   432
(* like 3x+4z = [(3,[1,0]),(4,[0,1])] with x<z
neuper@48826
   433
add_var y with order 2  =>  3x+4y = [(3,[1,0,0]),(4,[0,0,1])] with x<y<z*)
neuper@48826
   434
(* OFIZIELLE BESCHREIBUNG!!*)
meindl_diana@48797
   435
  fun add_var_to_multipoly (mvp: multipoly) (order: int) =
meindl_diana@48797
   436
    let fun add ([]: multipoly) (_: int) (new: multipoly) = new
meindl_diana@48797
   437
          | add (mvp: multipoly) (order: int) (new: multipoly) =
meindl_diana@48797
   438
          let val (first, last) = chop order (get_varlist mvp 0)
neuper@48826
   439
          in add (List.tl mvp) (order) (new @ [((get_coef mvp 0),(first @ [0] @ last))]) end 
meindl_diana@48797
   440
    in add mvp order [] end
meindl_diana@48797
   441
neuper@48829
   442
  fun cero_multipoly (different_var: int) = [(0, replicate different_var 0)];
neuper@48826
   443
*}
neuper@48826
   444
ML{*
neuper@48826
   445
  (* if a is greater than b --> true or false*)
neuper@48826
   446
  fun  greater_var (a: int list) (b: int list) =
neuper@48830
   447
   if drop_lc0 (a %-% b) = [] then false else lcoeff (drop_lc0 (a %-% b)) > 0 ;
neuper@48826
   448
*}
neuper@48826
   449
ML{*
neuper@48826
   450
   (* drop leading coefficients equal 0 *)
neuper@48826
   451
  fun drop_lc0_multipoly [m: monom] = 
neuper@48826
   452
    if get_coef [m] (length [m] - 1) = 0
neuper@48826
   453
    then cero_multipoly (length (get_varlist [m] 0))
neuper@48826
   454
    else [m]
neuper@48826
   455
    | drop_lc0_multipoly (mvp: multipoly) = 
neuper@48826
   456
      if get_coef mvp (length mvp - 1) = 0  
neuper@48826
   457
      then drop_lc0_multipoly (nth_drop (length mvp - 1) mvp)
neuper@48826
   458
      else mvp
meindl_diana@48797
   459
neuper@48828
   460
  (* add same variables *)
meindl_diana@48810
   461
  fun short_multipoly (mvp: multipoly) = 
neuper@48829
   462
    let fun short (mvp: multipoly) (new: multipoly) =
neuper@48829
   463
              if length mvp =1 
neuper@48829
   464
              then if (get_coef mvp 0) = 0 
neuper@48829
   465
                   then if new = [] then cero_multipoly (length (get_varlist mvp 0)) else new
neuper@48829
   466
                   else  new @ mvp 
neuper@48829
   467
              else if get_varlist  mvp 0 = get_varlist mvp 1
neuper@48829
   468
                then short ( [(get_coef mvp 0 + get_coef mvp 1,get_varlist  mvp 0)]
neuper@48829
   469
                             @ nth_drop 0 (nth_drop 0 mvp))   new 
neuper@48829
   470
                else if (get_coef mvp 0) = 0 then short (nth_drop 0 mvp) new 
neuper@48829
   471
                  else short (nth_drop 0 mvp) (new @ [nth mvp 0])
neuper@48829
   472
    in short mvp [] end
meindl_diana@48797
   473
neuper@48826
   474
  (* brings the polynom in correct order and add same variables*)
meindl_diana@48797
   475
  fun order_multipoly (a: multipoly)=
meindl_diana@48797
   476
    let 
meindl_diana@48797
   477
      val ordered = [nth a 0];
meindl_diana@48797
   478
      fun order_mp [] [] = cero_multipoly (length (get_varlist a 0))
meindl_diana@48810
   479
        | order_mp [] (ordered: multipoly) = short_multipoly ordered
meindl_diana@48797
   480
        | order_mp a (ordered: multipoly) =
meindl_diana@48797
   481
        if  greater_var (get_varlist a 0) (get_varlist ordered (length ordered -1))
meindl_diana@48797
   482
          then order_mp (nth_drop 0 a)(ordered @ [nth a 0])
meindl_diana@48797
   483
          else let 
meindl_diana@48797
   484
            val rest = [nth ordered (length ordered -1)];
meindl_diana@48797
   485
            fun order_mp' [] (new: multipoly) (rest: multipoly) = new @ rest
meindl_diana@48797
   486
              | order_mp' (ordered': multipoly) (new: multipoly) (rest: multipoly) =
meindl_diana@48797
   487
                if greater_var (get_varlist new 0) (get_varlist ordered' (length ordered' -1))
meindl_diana@48797
   488
                  then ordered' @ new @ rest
meindl_diana@48797
   489
                  else order_mp' (nth_drop (length ordered' -1) ordered') new 
meindl_diana@48797
   490
                                 ([nth ordered' (length ordered' -1)]@ rest)
meindl_diana@48797
   491
            in order_mp (nth_drop 0 a) 
meindl_diana@48797
   492
                        (order_mp' (nth_drop (length ordered -1) ordered) [nth a 0] rest)
meindl_diana@48797
   493
          end
meindl_diana@48797
   494
    in order_mp (nth_drop 0 a) ordered
meindl_diana@48797
   495
    end
meindl_diana@48797
   496
meindl_diana@48797
   497
 (* greatest variablegroup  *)
meindl_diana@48797
   498
  fun deg_multipoly (mvp: multipoly) = 
meindl_diana@48797
   499
    get_varlist (order_multipoly mvp) (length (order_multipoly mvp) -1)
meindl_diana@48797
   500
 
meindl_diana@48797
   501
  fun  max_deg_var [m: monom] (x: int) = nth (get_varlist [m] 0) x |
meindl_diana@48797
   502
   max_deg_var (mvp: multipoly) (x: int) =
meindl_diana@48797
   503
    let
meindl_diana@48797
   504
      fun max_monom (m1: monom) (m2: monom) (x: int)=
meindl_diana@48797
   505
        if nth (get_varlist [m1] 0) x < nth (get_varlist [m2] 0) x  then m2  else m1;
meindl_diana@48797
   506
    in
meindl_diana@48797
   507
    max_deg_var ([max_monom (nth(mvp) 0)( nth(mvp) 1) x] @ nth_drop 0 (nth_drop 0 mvp)) x
meindl_diana@48810
   508
    end
meindl_diana@48797
   509
          
meindl_diana@48797
   510
  infix %%/
meindl_diana@48797
   511
  fun (poly: multipoly) %%/ b = (* =quotient*)
neuper@48813
   512
    let fun division monom b = (((get_coef [monom] 0) div2 b),get_varlist [monom] 0);
meindl_diana@48797
   513
    in order_multipoly(map2 division poly (replicate (length(poly)) b)) end
meindl_diana@48797
   514
meindl_diana@48841
   515
  infix %%*
meindl_diana@48841
   516
    fun (poly: multipoly) %%* (b: int) = 
meindl_diana@48841
   517
      let fun mult monom b = (((get_coef [monom] 0) * b),get_varlist [monom] 0);
meindl_diana@48841
   518
      in order_multipoly(map2 mult poly (replicate (length(poly)) b)) end
meindl_diana@48841
   519
     
meindl_diana@48841
   520
meindl_diana@48797
   521
  fun cont [a: int] = a
meindl_diana@48810
   522
    | cont (poly1: unipoly) = abs (Integer.gcds poly1)
meindl_diana@48797
   523
meindl_diana@48810
   524
  fun evaluate_multipoly (mvp: multipoly) (var: int) (value: int) = 
meindl_diana@48797
   525
    let fun eval ([]: multipoly) (_: int) (_: int) (new: multipoly) = order_multipoly new |
meindl_diana@48797
   526
      eval (mvp: multipoly) (var: int) (value: int) (new: multipoly) =
meindl_diana@48797
   527
      eval (nth_drop 0 mvp) var value
meindl_diana@48799
   528
           (new @  [((Integer.pow  (nth (get_varlist mvp 0) var)value) * get_coef mvp 0, 
meindl_diana@48797
   529
                    nth_drop var (get_varlist mvp 0))]);
meindl_diana@48797
   530
    in eval mvp var value [] end
meindl_diana@48797
   531
meindl_diana@48797
   532
  fun multi_to_uni (mvp: multipoly) = 
meindl_diana@48797
   533
    if length (get_varlist mvp 0) = 1 
meindl_diana@48797
   534
    then let fun mtu ([]: multipoly) (uvp: unipoly) = uvp |
meindl_diana@48797
   535
                 mtu (mvp: multipoly) (uvp: unipoly) =
meindl_diana@48797
   536
               if length uvp = (nth(get_varlist mvp 0) 0)
meindl_diana@48797
   537
               then mtu (nth_drop 0 mvp) (uvp @ [get_coef mvp 0])
meindl_diana@48797
   538
               else mtu mvp (uvp @ [0])    
meindl_diana@48797
   539
         in mtu (order_multipoly mvp) [] end
meindl_diana@48797
   540
    else error "Polynom has more than one variable!";
meindl_diana@48797
   541
meindl_diana@48797
   542
  fun uni_to_multi (uvp: unipoly) =
meindl_diana@48810
   543
    let fun utm ([]: unipoly) (mvp: multipoly) (_: int)=  short_multipoly mvp
meindl_diana@48797
   544
          | utm (uvp: unipoly) (mvp: multipoly) (counter: int) = 
meindl_diana@48797
   545
          utm (nth_drop 0 uvp) (mvp @ [((nth uvp 0),[counter])]) (counter+1)
meindl_diana@48797
   546
    in  utm uvp [] 0 end
neuper@48826
   547
meindl_diana@48797
   548
  fun mult_with_new_var ([]: multipoly) (_: unipoly) (_: int) = []
meindl_diana@48797
   549
    | mult_with_new_var (mvp: multipoly) (uvp: unipoly) (order: int) = 
meindl_diana@48810
   550
    let 
meindl_diana@48810
   551
      fun mult ([]: multipoly) (_: unipoly) (_: int) (new: multipoly) (_: int) = 
meindl_diana@48810
   552
            short_multipoly new
meindl_diana@48810
   553
        | mult (mvp: multipoly) (uvp: unipoly) (order: int) (new: multipoly) (_: int)  =
meindl_diana@48810
   554
        let 
meindl_diana@48810
   555
          fun mult' (_: multipoly) ([]: unipoly) (_) (new': multipoly) (_) = order_multipoly new'
meindl_diana@48810
   556
            | mult' (mvp': multipoly) (uvp': unipoly) (order: int) (new': multipoly) (c2': int) =
meindl_diana@48810
   557
            let val (first, last) = chop order (get_varlist mvp' 0)
meindl_diana@48810
   558
            in mult' mvp' (nth_drop 0 uvp') order
meindl_diana@48810
   559
                    (new' @ [(((get_coef mvp' 0) * (nth uvp' 0)),(first @ [c2'] @ last))]) (c2'+1)
meindl_diana@48810
   560
            end
meindl_diana@48810
   561
        in mult (nth_drop 0 mvp) uvp order (new @ (mult' mvp uvp order [] 0)) (0) 
meindl_diana@48810
   562
        end
meindl_diana@48797
   563
    in mult mvp uvp order [] 0 end
meindl_diana@48797
   564
  
meindl_diana@48797
   565
  fun greater_deg_multipoly (var1: int list) (var2: int list) =
meindl_diana@48797
   566
    if var1 = [] andalso var2 =[] then 0
meindl_diana@48797
   567
    else if (nth var1 (length var1 -1)) = (nth var2 (length var1 -1) ) 
meindl_diana@48797
   568
         then greater_deg_multipoly (nth_drop (length var1 -1) var1) (nth_drop (length var1 -1) var2)
meindl_diana@48797
   569
         else if (nth var1 (length var1 -1)) > (nth var2 (length var1 -1)) 
meindl_diana@48797
   570
              then 1 else 2 ;
meindl_diana@48797
   571
meindl_diana@48797
   572
  infix %%+%%
meindl_diana@48797
   573
  fun ([]: multipoly) %%+%% (mvp2: multipoly) = mvp2
meindl_diana@48797
   574
    | (mvp1: multipoly) %%+%% ([]: multipoly) = mvp1
meindl_diana@48797
   575
    | (mvp1: multipoly) %%+%% (mvp2: multipoly) =
meindl_diana@48797
   576
    let fun plus ([]: multipoly) (mvp2: multipoly) (new: multipoly) = order_multipoly (new @ mvp2)
meindl_diana@48797
   577
          | plus (mvp1: multipoly) ([]: multipoly) (new: multipoly) = order_multipoly (new @ mvp1)
meindl_diana@48797
   578
          | plus (mvp1: multipoly) (mvp2: multipoly) (new: multipoly) = 
meindl_diana@48797
   579
          if greater_deg_multipoly (get_varlist mvp1 0) (get_varlist mvp2 0) = 0
meindl_diana@48797
   580
          then plus (nth_drop 0 mvp1) (nth_drop 0 mvp2) 
meindl_diana@48797
   581
                    (new @ [(((get_coef mvp1 0) + (get_coef mvp2 0)), get_varlist mvp1 0)])
meindl_diana@48797
   582
          else if greater_deg_multipoly (get_varlist mvp1 0) (get_varlist mvp2 0) = 1
meindl_diana@48797
   583
               then plus mvp1 (nth_drop 0 mvp2) (new @ [nth mvp2 0])
meindl_diana@48797
   584
               else plus (nth_drop 0 mvp1) mvp2 (new @ [nth mvp1 0])
meindl_diana@48797
   585
    in plus mvp1 mvp2 [] end
neuper@48826
   586
meindl_diana@48797
   587
  infix %%-%%
meindl_diana@48797
   588
  fun (mvp1: multipoly) %%-%% (mvp2: multipoly) = 
meindl_diana@48797
   589
    let fun neg ([]: multipoly) (new: multipoly) = order_multipoly new
meindl_diana@48797
   590
          | neg (mvp: multipoly) (new: multipoly) =
meindl_diana@48797
   591
          neg (nth_drop 0 mvp) (new @ [(((get_coef mvp 0) * ~1), get_varlist mvp 0)])
meindl_diana@48797
   592
        val neg_mvp2 = neg mvp2
meindl_diana@48797
   593
    in mvp1 %%+%% (neg_mvp2 [])  end         
meindl_diana@48810
   594
     
meindl_diana@48797
   595
  infix %%*%%
meindl_diana@48797
   596
  fun (mvp1: multipoly) %%*%% (mvp2: multipoly) =
meindl_diana@48810
   597
    let fun mult ([]: multipoly) (_: multipoly) (_: multipoly) (new: multipoly) = 
meindl_diana@48810
   598
              order_multipoly new
meindl_diana@48810
   599
          | mult (mvp1: multipoly) ([]: multipoly) (regular_mvp2: multipoly) (new: multipoly) =
meindl_diana@48810
   600
            mult (nth_drop 0 mvp1) regular_mvp2 regular_mvp2 new
meindl_diana@48797
   601
          | mult (mvp1: multipoly) (mvp2: multipoly) (regular_mvp2: multipoly) (new: multipoly) = 
meindl_diana@48810
   602
            mult mvp1 (nth_drop 0 mvp2) regular_mvp2 (new @ [(((get_coef mvp1 0) * (get_coef mvp2 0)),
meindl_diana@48810
   603
            (map2 Integer.add (get_varlist mvp1 0) (get_varlist mvp2 0)))])
meindl_diana@48810
   604
    in if (length mvp1) > (length mvp2) then mult mvp1 mvp2 mvp2 [] else mult mvp2 mvp1 mvp1 [] end
meindl_diana@48797
   605
meindl_diana@48797
   606
 (* if poly1|poly2 *)
meindl_diana@48797
   607
  infix %%|%% 
meindl_diana@48797
   608
  fun [(coef2, var2): monom] %%|%%  [(coef1, var1): monom]  = 
meindl_diana@48797
   609
    ( (listgreater var1 var2) 
meindl_diana@48797
   610
        andalso (coef1 mod coef2) = 0)
meindl_diana@48797
   611
    | (_: multipoly) %%|%% [(0,_)]=  true
meindl_diana@48797
   612
    | (poly2: multipoly)  %%|%% (poly1: multipoly) =
neuper@48815
   613
    if [nth poly2 (length poly2 -1)]   %%|%% [nth poly1 (length poly1 -1)]
meindl_diana@48797
   614
    then poly2 %%|%% (poly1 %%-%%
neuper@48823
   615
      ([((get_coef poly1 (length poly1 -1)) div2 (get_coef poly2 (length poly2 -1)),
meindl_diana@48797
   616
      (get_varlist poly1 (length poly1 -1)) %-%(get_varlist poly2 (length poly2 -1)))] %%*%%
meindl_diana@48797
   617
      poly2)) 
meindl_diana@48797
   618
    else false
meindl_diana@48810
   619
meindl_diana@48810
   620
  fun find_new_r (mvp1: multipoly) (mvp2: multipoly) (old: int) =
meindl_diana@48810
   621
    let val poly1 = evaluate_multipoly mvp1 (length (get_varlist mvp1 0) - 2) (old + 1)
meindl_diana@48810
   622
        val poly2 = evaluate_multipoly mvp2 (length (get_varlist mvp2 0) - 2) (old + 1);
meindl_diana@48810
   623
    in
meindl_diana@48810
   624
      if max_deg_var poly1 (length (get_varlist poly1 0) - 1)=
meindl_diana@48810
   625
          max_deg_var mvp1 (length (get_varlist mvp1 0) - 1) orelse
meindl_diana@48810
   626
         max_deg_var poly2 (length (get_varlist poly2 0) - 1)= 
meindl_diana@48810
   627
          max_deg_var mvp2 (length (get_varlist mvp2 0) - 1) 
meindl_diana@48810
   628
      then old + 1
meindl_diana@48810
   629
      else find_new_r (mvp1) (mvp2) (old + 1)
meindl_diana@48810
   630
    end
meindl_diana@48797
   631
*}
meindl_diana@48797
   632
subsection {* Newtoninterpolation *}
meindl_diana@48797
   633
ML{* (* first step *)
meindl_diana@48797
   634
  fun newton_first (x: int list) (f: multipoly list) (order: int) =
meindl_diana@48797
   635
    let val polynom =(add_var_to_multipoly (nth f 0) order) %%+%% 
meindl_diana@48797
   636
            ((mult_with_new_var (((nth f 1)%%-%% (nth f 0))%%/
meindl_diana@48797
   637
               (nth x 1) - (nth x 0))) [(nth x 0) * ~1, 1] order);
meindl_diana@48797
   638
        val new_value_poly =   [(nth x 0) * ~1, 1];
meindl_diana@48797
   639
        val steps = [((nth f 1) %%-%%(nth f 0))%%/ ((nth x 1) - (nth x 0))]
meindl_diana@48797
   640
    in (polynom, new_value_poly, steps) end
meindl_diana@48797
   641
  
meindl_diana@48810
   642
  fun newton_multipoly (x: int list) (f: multipoly list) (steps: multipoly list) 
meindl_diana@48810
   643
                       (t: unipoly) (p: multipoly) order = 
meindl_diana@48797
   644
    if length x = 2
meindl_diana@48797
   645
    then let val (polynom, new_value_poly, steps) =  newton_first x [(nth f 0), (nth f 1)] order
meindl_diana@48797
   646
         in (polynom, new_value_poly, steps) end
meindl_diana@48810
   647
    else let val new_value_poly = multi_to_uni((uni_to_multi t)  %%*%% 
meindl_diana@48810
   648
                                  (uni_to_multi [(nth x (length x -2) )* ~1, 1]));
meindl_diana@48810
   649
             val new_steps = [((nth f (length f -1))  %%-%% (nth f (length f -2)))  %%/ 
meindl_diana@48810
   650
                               ((nth x (length x - 1)) - (nth x (length x - 2)))];
meindl_diana@48797
   651
             fun next_step ([]: multipoly list) (new_steps: multipoly list) (_: int list) = new_steps
meindl_diana@48797
   652
               | next_step (steps: multipoly list) (new_steps: multipoly list) (x': int list) =  
meindl_diana@48797
   653
                 next_step (nth_drop 0 steps)
meindl_diana@48797
   654
                           (new_steps @ [(((nth new_steps (length new_steps -1)) %%-%%(nth steps 0)) %%/
meindl_diana@48797
   655
                                    ((nth x' (length x' - 1)) - (nth x' (length x' - 3))))])
meindl_diana@48810
   656
                           (nth_drop (length x' -2) x')
meindl_diana@48797
   657
             val steps = next_step steps new_steps x;
meindl_diana@48810
   658
             val polynom' = p %%+%% 
meindl_diana@48810
   659
                            (mult_with_new_var (nth steps (length steps -1)) new_value_poly order);
meindl_diana@48797
   660
       in (order_multipoly(polynom'), new_value_poly, steps) end 
meindl_diana@48797
   661
*}
meindl_diana@48841
   662
ML{*
meindl_diana@48841
   663
fun lc_multipoly (mpoly: multipoly) = 
meindl_diana@48841
   664
   get_coef (order_multipoly mpoly) (length (order_multipoly mpoly) - 1);
meindl_diana@48797
   665
meindl_diana@48841
   666
fun bool_list [] = true 
meindl_diana@48841
   667
  | bool_list list = if nth list 0 then bool_list (List.tl list) else false;
meindl_diana@48841
   668
meindl_diana@48841
   669
fun list_smaler (a: int) (list: int list)= 
meindl_diana@48841
   670
  let fun s a b = a <= b;
meindl_diana@48841
   671
  in map (s a) list
meindl_diana@48841
   672
 end
meindl_diana@48841
   673
(* assume up2 | up1  and use the same variables *)
meindl_diana@48841
   674
infix %%/%% 
meindl_diana@48841
   675
fun (up1: multipoly) %%/%% (up2: multipoly) =
meindl_diana@48841
   676
    let 
meindl_diana@48841
   677
      fun div_up (up1: multipoly) (up2: multipoly) (quot_old: multipoly) = 
meindl_diana@48841
   678
      let 
meindl_diana@48841
   679
        val up1 = drop_lc0_multipoly (order_multipoly up1);
meindl_diana@48841
   680
        val up2 = drop_lc0_multipoly (order_multipoly up2);
meindl_diana@48841
   681
        val [c] = cero_multipoly (length (get_varlist up1 0));
meindl_diana@48841
   682
        val d = (replicate (List.length up1 - List.length up2) c) @ up2 ;
meindl_diana@48841
   683
        val quot = [(lc_multipoly up1 div2 lc_multipoly d,
meindl_diana@48841
   684
                    get_varlist up1 (length up1 - 1) %-% get_varlist up2 (length up2 - 1))];
meindl_diana@48841
   685
        val rest = drop_lc0_multipoly (up1 %%-%% (d %%*%% quot));
meindl_diana@48841
   686
      in if  rest <>  [c] andalso
meindl_diana@48841
   687
             bool_list ((list_smaler 0) (get_varlist rest (length rest - 1) %-% get_varlist up2 (length up2 - 1)))
meindl_diana@48841
   688
        then div_up rest up2 (quot @ quot_old)
meindl_diana@48841
   689
        else (quot @ quot_old, rest)
meindl_diana@48841
   690
      end
meindl_diana@48841
   691
    in div_up up1 up2 [] 
meindl_diana@48841
   692
 end 
meindl_diana@48841
   693
meindl_diana@48841
   694
*}
meindl_diana@48797
   695
neuper@48807
   696
subsection {* gcd_poly algorithm, code for [1] p.95: multivariate *}
meindl_diana@48797
   697
meindl_diana@48797
   698
ML {*
meindl_diana@48810
   699
  fun gcd_poly' (a: multipoly) (b: multipoly) n r=
meindl_diana@48810
   700
    if greater_var (deg_multipoly b) (deg_multipoly a) then gcd_poly' b a n r else
meindl_diana@48810
   701
    if (n-1) = 0 
neuper@48831
   702
    then  uni_to_multi((gcd_unipoly (prim_poly(multi_to_uni a)) (prim_poly(multi_to_uni b))) %* 
meindl_diana@48810
   703
                       (abs (Integer.gcd (cont (multi_to_uni a)) (cont( multi_to_uni b)))))
meindl_diana@48810
   704
    else 
meindl_diana@48810
   705
      let 
meindl_diana@48810
   706
        val M = 1 + Int.min (max_deg_var a (length(get_varlist a 0)-2), 
meindl_diana@48810
   707
                             max_deg_var b (length(get_varlist b 0)-2)); 
meindl_diana@48816
   708
      in try_new_r a b n M r [] [] end
meindl_diana@48816
   709
 
meindl_diana@48816
   710
and try_new_r a b n M r r_list steps = 
meindl_diana@48816
   711
     let 
meindl_diana@48810
   712
        val r = find_new_r a b r;
meindl_diana@48810
   713
        val r_list = r_list @ [r];
meindl_diana@48810
   714
        val g_r = gcd_poly' (order_multipoly (evaluate_multipoly a (n-2) r)) 
meindl_diana@48816
   715
                            ( order_multipoly (evaluate_multipoly b (n-2) r)) (n-1) 0
meindl_diana@48810
   716
        val steps = steps @ [g_r];
meindl_diana@48816
   717
      in Hensel_lifting a b n M 1 r r_list steps g_r ( cero_multipoly n ) [1] end
meindl_diana@48816
   718
meindl_diana@48816
   719
  and Hensel_lifting a b n M m r r_list steps g g_n mult =  
meindl_diana@48816
   720
    if m > M then if g_n %%|%% a andalso g_n %%|%% b then  g_n else
meindl_diana@48816
   721
      try_new_r a b n M r r_list steps 
meindl_diana@48810
   722
    else
meindl_diana@48810
   723
      let 
meindl_diana@48810
   724
        val r = find_new_r a b r; 
meindl_diana@48810
   725
        val r_list = r_list @ [r];
meindl_diana@48810
   726
        val g_r = gcd_poly' (order_multipoly  (evaluate_multipoly a (n-2) r)) 
meindl_diana@48810
   727
                            (order_multipoly  (evaluate_multipoly b (n-2) r)) (n-1) 0
meindl_diana@48810
   728
      in  
meindl_diana@48810
   729
        if greater_var  (deg_multipoly g) (deg_multipoly g_r)
meindl_diana@48816
   730
        then Hensel_lifting a b n M 1  r r_list steps g g_n mult
meindl_diana@48810
   731
        else if (deg_multipoly g)= (deg_multipoly g_r) 
meindl_diana@48810
   732
          then let 
meindl_diana@48810
   733
            val (g_n, new, steps) = newton_multipoly r_list [g, g_r] steps mult g_n (n-2)
meindl_diana@48810
   734
          in 
meindl_diana@48810
   735
            if (nth steps (length steps -1)) = (cero_multipoly (n-1))
meindl_diana@48816
   736
            then Hensel_lifting a b n M (M+1) r r_list steps g_r g_n new
meindl_diana@48816
   737
            else Hensel_lifting a b n M (m+1) r r_list steps g_r g_n new 
meindl_diana@48810
   738
          end
meindl_diana@48816
   739
          else Hensel_lifting a b n M (m+1) r r_list steps g  g_n mult
meindl_diana@48810
   740
      end     
meindl_diana@48797
   741
meindl_diana@48841
   742
  fun gcd_poly (a: multipoly) (b: multipoly) = 
meindl_diana@48841
   743
    let val gcd = gcd_poly' a b (length(get_varlist a 0)) 0;
meindl_diana@48841
   744
        val (m1, _) = a %%/%% gcd;
meindl_diana@48841
   745
        val (m2, _) = b %%/%% gcd;
meindl_diana@48841
   746
    in ((m1, m2), gcd)  end
meindl_diana@48797
   747
*}
meindl_diana@48797
   748
meindl_diana@48810
   749
ML {*
meindl_diana@48816
   750
gcd_poly [(6,[0])] [(9,[0])];
neuper@48826
   751
(* gcd_poly [(6,[0])] [(0,[0])]; ERROR div with 0*)
meindl_diana@48816
   752
meindl_diana@48841
   753
(* (gcd_poly "x^2 - y^2"  "x^2 - x*y")-> (("x + y", "x"), "x - y") *)
meindl_diana@48841
   754
val p1 = [(1,[2,0]),(~1,[0,2])]; val p2 =  [(1,[2,0]),(~1,[1,1])];
meindl_diana@48841
   755
val (a,g) = gcd_poly p1 p2;
meindl_diana@48841
   756
val t1 = p1 %%/%% g;
meindl_diana@48841
   757
val t2 = p2 %%/%% g;
meindl_diana@48841
   758
meindl_diana@48810
   759
*}
meindl_diana@48797
   760
end
meindl_diana@48797
   761
meindl_diana@48797
   762