src/Tools/isac/Knowledge/GCD_Poly_OLD.thy
author Walther Neuper <walther.neuper@jku.at>
Tue, 13 Apr 2021 13:20:05 +0200
changeset 60189 6b021e8cb8da
parent 59617 5c4230e32124
child 60354 716dd4a05cc8
permissions -rw-r--r--
trial with setup for session "Doc", unsuccessful
wneuper@59353
     1
(* 1st approach to Isabelle's new Polynomials
wneuper@59353
     2
   continued in TPPL/material/AD_Polynomal.thy *)
neuper@52168
     3
neuper@52164
     4
theory GCD_Poly_OLD 
wneuper@59354
     5
  imports "HOL-Computational_Algebra.Polynomial"
neuper@52164
     6
        (*"~~/src/HOL/Number_Theory/Primes" ??? rm ???, thys for code_gen missing*)
neuper@52164
     7
      (*"~~/src/HOL/Library/Code_Target_Numeral"  ...note (4)*)
neuper@52164
     8
begin
wneuper@59467
     9
value "xxx" \<comment> \<open>TODO\<close>
neuper@52164
    10
wneuper@59472
    11
subsection \<open>Euclidean Algorithm with generalised division\<close>
wneuper@59472
    12
text \<open>
neuper@52164
    13
  "generalised division" addresses the generation of "polynomial remainder sequences"
neuper@52164
    14
  according to [1].p.83. These sequences allow tho generalise the Euclidean Algorithm
neuper@52164
    15
  to univariate polynomials in Z[x], i.e. keeping integer coefficients; see [1].p.84.
neuper@52164
    16
  References: 
wneuper@59472
    17
  [1] Franz Winkler, Polynomial Algorithms in Computer Algebra. Springer 1996\<close>
neuper@52164
    18
wneuper@59472
    19
subsubsection \<open>Auxiliary functions\<close>
wneuper@59472
    20
text \<open>
neuper@52164
    21
  Some of these functions might be inappropriate due to lack of knowledge 
neuper@52164
    22
  about Isabelle's Polynomials at this first approach.
wneuper@59472
    23
\<close>
neuper@52164
    24
fun gcds :: "int list \<Rightarrow> int" where "gcds ns = List.fold gcd ns (List.hd ns)"
neuper@52164
    25
(*
neuper@52164
    26
lift_definition sdiv :: "'a::comm_semiring_1 \<Rightarrow> 'a poly \<Rightarrow> 'a poly"
neuper@52164
    27
  is "\<lambda>a p n. (coeff p n) div a"
neuper@52164
    28
proof sorry
neuper@52164
    29
neuper@52164
    30
Lifting failed for the following term:
neuper@52164
    31
Term:  \<lambda>a p n. coeff p n div a
neuper@52164
    32
Type:  ?'b \<Rightarrow> ?'b poly \<Rightarrow> nat \<Rightarrow> ?'b
neuper@52164
    33
neuper@52164
    34
Reason:  The type of the term cannot be instancied to "'a \<Rightarrow> 'a poly \<Rightarrow> nat \<Rightarrow> 'a".
neuper@52164
    35
*)
neuper@52164
    36
(*/------------------------------------------------------------------------------\
neuper@52164
    37
  this is an odd bypass for the above problem: 
neuper@52164
    38
  divide a polynomial with (a factor of) the gcd; i.e. remainder is expected 0 *)
neuper@52164
    39
fun pConss :: "int list \<Rightarrow> int poly \<Rightarrow> int poly" where
neuper@52164
    40
"pConss [] p = p" |
neuper@52164
    41
"pConss (x # xs) p = pConss xs (pCons x p)"
walther@59617
    42
value "pConss (rev \<comment> \<open>!!!\<close> [1,2,3]) [:0:]" \<comment> \<open>Poly [1, 2, 3]\<close>
wneuper@59467
    43
value "pConss [] [:1,2,3:]"                \<comment> \<open>Poly [1, 2, 3]\<close>
wneuper@59467
    44
value "pConss [0,0] [:1,2,3:]"             \<comment> \<open>Poly [0, 0, 1, 2, 3]\<close>
neuper@52164
    45
neuper@52164
    46
fun sdiv :: "int poly \<Rightarrow> int \<Rightarrow> int poly" where
neuper@52164
    47
"sdiv p n =
wneuper@59467
    48
(let cs = map (\<lambda>i. i div n) (coeffs p)
neuper@52164
    49
 in pConss (rev cs) [:0:])"
wneuper@59467
    50
value "sdiv [:2,4,6::int:] 2" \<comment> \<open>Poly [1, 2, 3]\<close>
neuper@52164
    51
(*\------------------------------------------------------------------------------/*)
neuper@52164
    52
neuper@52164
    53
(* find the primitive part of a polynomial, see [1].p.83
neuper@52164
    54
   primitive p = p'
neuper@52164
    55
    assumes p = [:c\<^isub>1, .., c\<^isub>n:]
neuper@52164
    56
    yields p' = [:c\<^isub>1, .., c\<^isub>n:] = [:c\<^isub>1', .., c\<^isub>n':] * d
neuper@52164
    57
      \<and>  d = gcds c\<^isub>1, .., c\<^isub>n *)
neuper@52164
    58
definition primitive :: "int poly \<Rightarrow> int poly" where
neuper@52164
    59
"primitive p = sdiv p (gcds (coeffs p))"
neuper@52164
    60
wneuper@59467
    61
value "primitive [:1::int, 2, 3:]"             \<comment> \<open>Poly [1, 2, 3]\<close>
wneuper@59467
    62
value "primitive [:2::int, 4, 6:]"             \<comment> \<open>Poly [1, 2, 3]\<close>
wneuper@59467
    63
value "primitive [:2000::int, 4000, 6000:]"    \<comment> \<open>Poly [1, 2, 3]\<close>
neuper@52164
    64
neuper@52164
    65
(* arguments from the example from [1].p.94 *)
neuper@52164
    66
value "       primitive [:-5000595353600, -2500297676800, 2500297676800::int:]" 
wneuper@59467
    67
  \<comment> \<open>= Poly [-2, -1, 1]  OK\<close>
wneuper@59111
    68
value (*[simp]*) "primitive [:-5000595353600, -2500297676800, 2500297676800::int:]" 
wneuper@59467
    69
  \<comment> \<open>= [:-2, -1, 1, 0:]  incorrect ???????????????????????????????????????????????????????????\<close>
neuper@52164
    70
(* goes forever:
wneuper@59111
    71
value (*[nbe]*)  "primitive [:-5000595353600, -2500297676800, 2500297676800::int:]" 
neuper@52164
    72
*)
wneuper@59111
    73
value (*[code]*) "primitive [:-5000595353600, -2500297676800, 2500297676800::int:]" 
wneuper@59467
    74
  \<comment> \<open>= Poly [-2, -1, 1] ...ok\<close>
neuper@52164
    75
neuper@52164
    76
(*where does [simp] fail:*)
wneuper@59111
    77
value (*[simp]*) "let p = [:-5000595353600, -2500297676800, 2500297676800::int:] 
wneuper@59467
    78
in (coeffs p)"      \<comment> \<open>= "[-5000595353600, -2500297676800, 2500297676800]" :: "int list" OK\<close>
wneuper@59111
    79
value (*[simp]*) "let p = [:-5000595353600, -2500297676800, 2500297676800::int:] 
wneuper@59467
    80
in gcds (coeffs p)"  \<comment> \<open>= "2500297676800" :: "int" OK\<close>
neuper@52164
    81
(* declare [[simp_trace = true]]
neuper@52164
    82
value [simp] "let p = [:-5000595353600, -2500297676800, 2500297676800::int:] 
neuper@52164
    83
in sdiv p (gcds (coeffs p))"  --{* = "[:-2, -1, 1, 0:]" :: "int poly" ???*}
neuper@52164
    84
... gives an unreadable trace, unfortunately.*)
neuper@52164
    85
neuper@52164
    86
(*where does  [nbe] fail:*)
wneuper@59111
    87
value (*[nbe]*)  "let p = [:-5000595353600, -2500297676800, 2500297676800::int:] 
wneuper@59467
    88
in (coeffs p)" \<comment> \<open>= "coeffs (Poly (-5000595353600 # coeffs (Poly (-2500297676800 # coef... ???\<close>
neuper@52164
    89
(* value [nbe]  "let p = [:-5000595353600, -2500297676800, 2500297676800::int:] 
neuper@52164
    90
in gcds (coeffs p)"
neuper@52164
    91
... goes forever, clear due to the above line, which is unclear.*)
neuper@52164
    92
neuper@52164
    93
(* regard zeros occurring in the quotient, also in the last step of division *)
neuper@52164
    94
fun for_quot_regarding :: "int poly \<Rightarrow> int poly \<Rightarrow> int poly \<Rightarrow> int poly \<Rightarrow> int poly \<Rightarrow> nat" where
neuper@52164
    95
"for_quot_regarding p1 p2 p1' quot remd =
neuper@52164
    96
(let
walther@59617
    97
  zeros = degree p1' - degree remd - 1\<comment> \<open>length [q]\<close>;
neuper@52164
    98
  max_qot_deg = degree p1 - degree p2
neuper@52164
    99
in 
walther@59617
   100
  if zeros + 1 \<comment> \<open>length [q]\<close> + degree quot > max_qot_deg \<comment> \<open>possible in last step of div\<close>
walther@59617
   101
  then max_qot_deg - degree quot - 1 \<comment> \<open>length [q]\<close>
neuper@52164
   102
  else zeros)"
neuper@52164
   103
neuper@52164
   104
(* multiply polynomial p such that it has degree d with d = deg p*)
neuper@52164
   105
fun mult_to_deg :: "nat \<Rightarrow> int poly \<Rightarrow> int poly" where
neuper@52164
   106
"mult_to_deg d p =
neuper@52164
   107
(let
neuper@52164
   108
  d' = degree p
neuper@52164
   109
in 
neuper@52164
   110
  if d \<ge> d' then pConss (replicate (d - d') 0) p else p)"
neuper@52164
   111
wneuper@59467
   112
value "mult_to_deg 4 [:1, 2, 3::int:]" \<comment> \<open>Poly [0, 0, 1, 2, 3]\<close>
neuper@52164
   113
neuper@52164
   114
(* find a factor for the dividend, such the divisor divides to an integer quotient.
wneuper@59467
   115
value "xxx" 
neuper@52164
   116
   fact_quot c1 c2 = (n, q)
neuper@52164
   117
    assumes c2 \<noteq> 0
neuper@52164
   118
    yields c1 * n = q * c2 *)
neuper@52164
   119
fun fact_quot :: "int \<Rightarrow> int \<Rightarrow> int \<times> int" where
neuper@52164
   120
"fact_quot c1 c2 =
neuper@52164
   121
(let
neuper@52164
   122
  d = gcd c1 c2;
neuper@52164
   123
  n = c2 div d;
neuper@52164
   124
  q = c1 div d
neuper@52164
   125
 in if n > 0 then (n, q) else (-1 * n, -1 * q))"
neuper@52164
   126
value "fact_quot 6 4 = (2, 3)"
neuper@52164
   127
neuper@52164
   128
definition leading_coeff :: "'a poly \<Rightarrow> 'a::zero" where
neuper@52164
   129
"leading_coeff p = coeff p (degree p)"
neuper@52164
   130
neuper@52164
   131
value "leading_coeff [:1, 2, 3::int:] = 3"
neuper@52164
   132
wneuper@59472
   133
subsubsection \<open>Generalised division\<close>
wneuper@59472
   134
text \<open>
neuper@52164
   135
  The "generalised division" is used to create "polynomial remainder sequences"
neuper@52164
   136
  which in turn allow to generalise the Euclidean Algorithm to Z[x].
wneuper@59472
   137
\<close>
neuper@52164
   138
(* "generalized division" for "generalised Euclidean algorithms:
neuper@52164
   139
   divide in Z[x] while multiplying the dividend such that the quotient is again in Z[x], 
neuper@52164
   140
   i.e. has integer coefficients.
neuper@52164
   141
neuper@52164
   142
   fact_div :: unipoly \<Rightarrow> unipoly \<Rightarrow> (unipoly, unipoly, nat)
neuper@52164
   143
   fact_div p\<^isub>1 p\<^isub>2 = (n, q, r)
neuper@52164
   144
     assumes p\<^isub>2 \<noteq> [0]  \<and>  deg p\<^isub>1 \<ge> deg p\<^isub>2
neuper@52164
   145
     yields p\<^isub>1 *\<^isub>s n = q *\<^isub>p p\<^isub>2   +\<^isub>p   r *)
neuper@52164
   146
(* TODO: generalise to 'a poly *)
neuper@52164
   147
function div_int_up :: "int poly \<Rightarrow> int poly \<Rightarrow> int poly \<Rightarrow> int poly \<Rightarrow> int \<Rightarrow> int \<times> int poly \<times> int poly" where
neuper@52164
   148
"div_int_up p1 p1' p2 quot ns = 
neuper@52164
   149
(let
neuper@52164
   150
  (n, q) = fact_quot (leading_coeff p1') (leading_coeff p2);
neuper@52164
   151
  remd = smult n p1' - smult q (mult_to_deg (degree p1') p2);
neuper@52164
   152
  zeros = for_quot_regarding p1 p2 p1' quot remd;
neuper@52164
   153
  quot = pConss (replicate zeros 0) (pCons q (smult n quot));
neuper@52164
   154
  ns = n * ns
neuper@52164
   155
in 
neuper@52164
   156
  if degree remd \<ge> degree p2 
neuper@52164
   157
  then div_int_up p1 remd p2 quot ns
neuper@52164
   158
  else (ns, quot, remd))"
neuper@52164
   159
by pat_completeness (auto simp del: mult_to_deg.simps)
neuper@52164
   160
termination sorry
neuper@52164
   161
(*TODO how can we retain the operator with nice subscripts ?*)
neuper@52164
   162
neuper@52164
   163
definition mult_div :: "int poly \<Rightarrow> int poly \<Rightarrow> int \<times> int poly \<times> int poly" (infixl "div\<^sub>*\<^sub>P" 70) where
neuper@52164
   164
"p1 div\<^sub>*\<^sub>P p2 = (div_int_up p1 p1 p2 0 1)"
neuper@52164
   165
wneuper@59472
   166
subsubsection \<open>Euclidean Algorithm applied to univariate polynomials\<close>
wneuper@59472
   167
text \<open>
neuper@52164
   168
  See [1].p.84.
wneuper@59472
   169
\<close>
neuper@52164
   170
function euclidean_algorithm :: "int poly \<Rightarrow> int poly \<Rightarrow> int poly" where
neuper@52164
   171
"euclidean_algorithm a b =
neuper@52164
   172
  (if b  = [:0:] then primitive a else
neuper@52164
   173
     if degree a < degree b then euclidean_algorithm b a else
neuper@52164
   174
     let (n, q, r) = a div\<^sub>*\<^sub>P b
neuper@52164
   175
     in euclidean_algorithm b r)"
neuper@52164
   176
by pat_completeness auto
neuper@52164
   177
termination sorry
neuper@52164
   178
neuper@52164
   179
(*The example used in the inital mail to Tobias Nipkow made univariate: y -> 1*)
wneuper@59467
   180
value "euclidean_algorithm [:0::int, -1, 1:]  [:-1, 0, 1:]"    \<comment> \<open>Poly [1, -1]\<close>
neuper@52164
   181
(*                                -x + x^2    -1 + x^2                
neuper@52164
   182
                     gcd     -x * (1 - x  )  (-1-x)*(1 - x)  =       (1 - x) *)
neuper@52164
   183
neuper@52164
   184
(* example from [1].p.94: DOESN'T WORK SINCE REMOVAL OF BUG IN function div_int_up 
neuper@52164
   185
  in changeset 044419cc7bf8 this example works (with [code]), if in
neuper@52164
   186
  https://intra.ist.tugraz.at/hg/isa/file/044419cc7bf8/src/Tools/isac/Knowledge/GCD_Poly.thy
neuper@52164
   187
  in line #30 "2" is replaced by "n".
neuper@52164
   188
*)
neuper@52164
   189
(* these go forever (on Intel\<registered> Coreā„¢ i5-2410M CPU @ 2.30GHz \<times> 4, 3.8 GiB)
neuper@52164
   190
value 
neuper@52164
   191
  "euclidean_algorithm [:-18, -15, -20, 12, 20, -13, 2::int:]  [:8, 28, 22, -11, -14, 1, 2:]"
neuper@52164
   192
value [simp]
neuper@52164
   193
  "euclidean_algorithm [:-18, -15, -20, 12, 20, -13, 2::int:]  [:8, 28, 22, -11, -14, 1, 2:]"*)
wneuper@59111
   194
value (*[nbe]*)
neuper@52164
   195
  "euclidean_algorithm [:-18, -15, -20, 12, 20, -13, 2::int:]  [:8, 28, 22, -11, -14, 1, 2:]"
neuper@52164
   196
(* = "euclidean_algorithm (Poly (-18 # coeffs (Poly (-15 # coeffs ...why not simplified ???*)
wneuper@59111
   197
value (*[code]*)
neuper@52164
   198
  "euclidean_algorithm [:-18, -15, -20, 12, 20, -13, 2::int:]  [:8, 28, 22, -11, -14, 1, 2:]"
neuper@52164
   199
(* = "Poly [-2, -1, 1]"*)
neuper@52164
   200
wneuper@59472
   201
subsubsection \<open>Observations and conclusions\<close>
wneuper@59472
   202
text \<open>Which part of the code crucially slows down with large numerals ?
neuper@52164
   203
  For answering this questions we investigate the last iteration in the
neuper@52164
   204
  example from [1].p.94. The test-data are obtained from the respective test
wneuper@59467
   205
  "--- last step in EUCLID -\<comment> \<open> in gcd_poly.sml.\<close>
wneuper@59472
   206
\<close>
neuper@52164
   207
(* we step through the function:
neuper@52164
   208
"div_int_up p1 p1' p2 quot ns = 
neuper@52164
   209
(let
neuper@52164
   210
##1##   (n, q) = fact_quot (leading_coeff p1') (leading_coeff p2);
neuper@52164
   211
##2##   remd = smult (int n) p1' - smult q (mult_to_deg (degree p1') p2);
neuper@52164
   212
##3##   zeros = for_quot_regarding p1 p2 p1' quot remd;
neuper@52164
   213
##4##   quot = pConss (replicate zeros 0) (pCons q (smult (int n) quot));
neuper@52164
   214
##5##   ns = n * ns
neuper@52164
   215
in 
neuper@52164
   216
##6##   if degree remd \<ge> degree p2 
neuper@52164
   217
##7##   then div_int_up p1 remd p2 quot ns
neuper@52164
   218
##8##   else (ns, quot, remd))"
neuper@52164
   219
*)
neuper@52164
   220
neuper@52164
   221
(*
neuper@52164
   222
##1##   (n, q) = fact_quot (leading_coeff p1') (leading_coeff p2);
neuper@52164
   223
*)
neuper@52164
   224
value "let 
neuper@52164
   225
  p1' = pConss (rev [-1316434, -3708859, -867104, 1525321]) [:0:] 
neuper@52164
   226
in leading_coeff p1'"
neuper@52164
   227
value "let 
neuper@52164
   228
  p1' = pConss (rev [-1316434, -3708859, -867104, 1525321]) [:0:];
neuper@52164
   229
  p2 = pConss (rev [-5000595353600, -2500297676800, 2500297676800]) [:0:] 
neuper@52164
   230
in fact_quot (leading_coeff p1') (leading_coeff p2)"
neuper@52164
   231
(* note: this example shows that "value" selects the appropriate evaluation strategy
neuper@52164
   232
   very reasonably:
neuper@52164
   233
HANGS: gcd, div
wneuper@59467
   234
value "let c1 = 1525321; c2 = 2500297676800 in gcd c1 c2" \<comment> \<open> = 343\<close>
neuper@52164
   235
                                               =========
wneuper@59467
   236
value "let c2 = 2500297676800; d = 343 in c2 div d"       \<comment> \<open> = 7289497600\<close>
neuper@52164
   237
                                          ========                        *)
neuper@52164
   238
(*
neuper@52164
   239
##2##   remd = smult (int n) p1' - smult q (mult_to_deg (degree p1') p2);
neuper@52164
   240
*)
neuper@52164
   241
value "let 
walther@59617
   242
  n = 7289497600::int \<comment> \<open>nat\<close>;
neuper@52164
   243
  p1' = pConss (rev [-1316434, -3708859, -867104, 1525321]) [:0:] 
walther@59617
   244
in smult (\<comment> \<open>int\<close> n) p1'" \<comment> \<open>the type conversion hangs !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\<close>
neuper@52164
   245
value "let 
neuper@52164
   246
  q = 111::int;
neuper@52164
   247
  p1' = pConss (rev [-1316434, -3708859, -867104, 1525321]) [:0:];
neuper@52164
   248
  p2 = pConss (rev [-5000595353600, -2500297676800, 2500297676800]) [:0:] 
neuper@52164
   249
in smult q (mult_to_deg (degree p1') p2)"
neuper@52164
   250
neuper@52164
   251
(* 
neuper@52164
   252
##3##   zeros = for_quot_regarding p1 p2 p1' quot remd;
neuper@52164
   253
*)
neuper@52164
   254
value "let
neuper@52164
   255
  p1 = pConss (rev [-1316434, -3708859, -867104, 1525321]) [:0:];
neuper@52164
   256
  p2 = pConss (rev [-5000595353600, -2500297676800, 2500297676800]) [:0:];
neuper@52164
   257
  p1' = pConss (rev [-1316434, -3708859, -867104, 1525321]) [:0:];
neuper@52164
   258
  quot = [:0::int:];
neuper@52164
   259
  remd = pConss (rev [-9596142483558400, -4798071241779200, 4798071241779200]) [:0:]
neuper@52164
   260
in for_quot_regarding p1 p2 p1' quot remd"
neuper@52164
   261
neuper@52164
   262
(* 
neuper@52164
   263
##4##   quot = pConss (replicate zeros 0) (pCons q (smult (int n) quot));
neuper@52164
   264
*)
neuper@52164
   265
value "let
neuper@52164
   266
  zeros = 0::nat;
neuper@52164
   267
  q = 4447::int;
walther@59617
   268
  n = 7289497600::\<comment> \<open>nat\<close> int;
neuper@52164
   269
  quot = [:0::int:]
walther@59617
   270
in pConss (replicate zeros 0) (pCons q (smult (\<comment> \<open>int\<close> n) quot))"
neuper@52164
   271
neuper@52164
   272
(* 
neuper@52164
   273
##5##   ns = n * ns
neuper@52164
   274
*)
neuper@52164
   275
value "let 
walther@59617
   276
  n = 7289497600::int\<comment> \<open>nat\<close>; \<comment> \<open>nat even cannot be initialised !!!!!!!!!!!!!!!!!!!!!!!!!!!!!\<close>
neuper@52164
   277
  ns = 1::int
wneuper@59467
   278
in n * ns" \<comment> \<open>\<close>
neuper@52164
   279
neuper@52164
   280
wneuper@59467
   281
\<comment> \<open>-------------------------------------------------------------------------------------------\<close>
neuper@52164
   282
wneuper@59467
   283
value "xxx" \<comment> \<open>"\<close>
neuper@52164
   284
end