src/Tools/isac/Knowledge/GCD_Poly_ML.thy
changeset 60507 b125dcf14489
parent 60354 716dd4a05cc8
equal deleted inserted replaced
60506:145e45cd7a0f 60507:b125dcf14489
   962   ([1,2,1] %*% [1,3,3,1]) = [1, 5, 10, 10, 5, 1];
   962   ([1,2,1] %*% [1,3,3,1]) = [1, 5, 10, 10, 5, 1];
   963 
   963 
   964   replicate 3 0 = [0, 0, 0];
   964   replicate 3 0 = [0, 0, 0];
   965   replicate 0 0 = [];
   965   replicate 0 0 = [];
   966 
   966 
   967   val trace_div = Unsynchronized.ref true;
   967   val trace_div = Attrib.setup_config_bool \<^binding>\<open>trace_div\<close> (K true);
   968   val trace_div_invariant = Unsynchronized.ref false; (*.. true expects !trace_div = false *)
   968   val trace_div_invariant = Attrib.setup_config_bool \<^binding>\<open>trace_div_invariant\<close> 
       
   969     (K false); (*.. true expects !trace_div = false *)
       
   970   val trace_Euclid = Attrib.setup_config_bool \<^binding>\<open>trace_Euclid\<close> (K true);
       
   971 
   969   fun div_invariant2 p1 p2 n ns zeros q quot remd = 
   972   fun div_invariant2 p1 p2 n ns zeros q quot remd = 
   970     (@{make_string} p1 ^ " * "  ^ @{make_string} (n * ns) ^ " = " ^ 
   973     (@{make_string} p1 ^ " * "  ^ @{make_string} (n * ns) ^ " = " ^ 
   971      @{make_string} (mult_to_deg (deg_up p1 - deg_up p2) 
   974      @{make_string} (mult_to_deg (deg_up p1 - deg_up p2) 
   972       ((zeros @ [q] @ (quot %* n)))) ^ 
   975       ((zeros @ [q] @ (quot %* n)))) ^ 
   973      " ** " ^ @{make_string} p2 ^ " ++ " ^ 
   976      " ** " ^ @{make_string} p2 ^ " ++ " ^ 
   974      @{make_string} ((rev o (mult_to_deg (deg_up p1)) o rev) remd))
   977      @{make_string} ((rev o (mult_to_deg (deg_up p1)) o rev) remd))
   975   fun writeln_trace p1 p1' p2 quot n q (zeros:int) remd (ns: int) = 
   978   fun writeln_trace p1 p1' p2 quot n q (zeros:int) remd (ns: int) = 
   976     (if (! trace_div) then
   979     (if Config.get @{context} trace_div then
   977       ( writeln ("  div   " ^ @{make_string} p1' ^ " * " ^ @{make_string} n);
   980       ( writeln ("  div   " ^ @{make_string} p1' ^ " * " ^ @{make_string} n);
   978         writeln  "  div   ~~~~~~~~~~~~~~~~~~~~~~~~~~~";
   981         writeln  "  div   ~~~~~~~~~~~~~~~~~~~~~~~~~~~";
   979         writeln ("  div   " ^ @{make_string} (p1' %* n));
   982         writeln ("  div   " ^ @{make_string} (p1' %* n));
   980         writeln ("  div-- " ^ @{make_string} (mult_to_deg (deg_up p1') p2 %* q) ^ 
   983         writeln ("  div-- " ^ @{make_string} (mult_to_deg (deg_up p1') p2 %* q) ^ 
   981           " <--- " ^ @{make_string} p2 ^ " * " ^ @{make_string} q);
   984           " <--- " ^ @{make_string} p2 ^ " * " ^ @{make_string} q);
   993       (*invariant 2: initial p1 *\<^isub>s ns = quot *\<^isub>p p2   +\<^isub>p  remd *)
   996       (*invariant 2: initial p1 *\<^isub>s ns = quot *\<^isub>p p2   +\<^isub>p  remd *)
   994       if (p1 %* (n * ns)) = 
   997       if (p1 %* (n * ns)) = 
   995         ((mult_to_deg (deg_up p1 - deg_up p2) 
   998         ((mult_to_deg (deg_up p1 - deg_up p2) 
   996           ((replicate zeros 0) @ [q] @ (quot %* n)) %*% p2 %+% remd))
   999           ((replicate zeros 0) @ [q] @ (quot %* n)) %*% p2 %+% remd))
   997       then
  1000       then
   998         if (! trace_div_invariant) 
  1001         if Config.get @{context} trace_div_invariant
   999         then writeln ("  div   " ^ div_invariant2 p1 p2 n ns (replicate zeros 0) q quot remd)
  1002         then writeln ("  div   " ^ div_invariant2 p1 p2 n ns (replicate zeros 0) q quot remd)
  1000         else ()
  1003         else ()
  1001       else raise ERROR ("invariant 2 does not hold: " ^ div_invariant2 p1 p2 n ns (replicate zeros 0) q quot remd)
  1004       else raise ERROR ("invariant 2 does not hold: " ^ div_invariant2 p1 p2 n ns (replicate zeros 0) q quot remd)
  1002     )
  1005     )
  1003 
  1006 
  1027     end
  1030     end
  1028 
  1031 
  1029   fun p1 %*/% p2 = 
  1032   fun p1 %*/% p2 = 
  1030     let 
  1033     let 
  1031       val (n, q, r) = div_int_up p1 p1 p2 [] 1
  1034       val (n, q, r) = div_int_up p1 p1 p2 [] 1
  1032       val _ = if (! trace_div) then
  1035       val _ = if Config.get @{context} trace_div then
  1033         (writeln  "  div   .....................................................................";
  1036         (writeln  "  div   .....................................................................";
  1034          writeln ("  div   " ^ @{make_string} n ^ " * " ^ @{make_string} p1 ^ " = " ^ 
  1037          writeln ("  div   " ^ @{make_string} n ^ " * " ^ @{make_string} p1 ^ " = " ^ 
  1035          @{make_string} q ^ " ** " ^ @{make_string} p2 ^ " ++ " ^ @{make_string} r);
  1038          @{make_string} q ^ " ** " ^ @{make_string} p2 ^ " ++ " ^ @{make_string} r);
  1036          writeln  "  div   ....................................................................."
  1039          writeln  "  div   ....................................................................."
  1037         ) else ()
  1040         ) else ()
  1038     in (n, q, r) end;
  1041     in (n, q, r) end;
  1039 \<close>
  1042 \<close>
  1040 text \<open>Here is the check of the algorithm with the values from above: [[1]]\<close>
  1043 text \<open>Here is the check of the algorithm with the values from above: [[1]]\<close>
  1041 ML \<open>
  1044 declare [[trace_div = true]]
  1042   trace_div := true;
  1045 declare [[trace_div_invariant = false]]
  1043   trace_div_invariant := false;
  1046 ML \<open>
  1044   val p1 = [2, 2, 2, 2, 2];
  1047   val p1 = [2, 2, 2, 2, 2];
  1045   val p2 = [1, 2, 3];
  1048   val p2 = [1, 2, 3];
  1046   val (n (* = 27*), 
  1049   val (n (* = 27*), 
  1047        q (* = [8, 6, 18]*), 
  1050        q (* = [8, 6, 18]*), 
  1048        r (* = [46, 32]*)) = p1 %*/% p2;
  1051        r (* = [46, 32]*)) = p1 %*/% p2;
  1070 text \<open>
  1073 text \<open>
  1071   The generalized division implemented above really can replace the
  1074   The generalized division implemented above really can replace the
  1072   division of integers in the Euclidean Algorithm:
  1075   division of integers in the Euclidean Algorithm:
  1073 \<close>
  1076 \<close>
  1074 ML \<open>
  1077 ML \<open>
  1075   val trace_Euclid = Unsynchronized.ref true;
       
  1076   fun writeln_trace_Euclid (a: int list) (b: int list) (n: int) (q: int list) (r: int list) =
  1078   fun writeln_trace_Euclid (a: int list) (b: int list) (n: int) (q: int list) (r: int list) =
  1077     if (! trace_Euclid) then
  1079     if Config.get @{context} trace_Euclid then
  1078       writeln ("Euclid "  ^ @{make_string} a ^ "  *  "  ^ @{make_string} n ^ 
  1080       writeln ("Euclid "  ^ @{make_string} a ^ "  *  "  ^ @{make_string} n ^ 
  1079         "  ==  "  ^ @{make_string} q  ^ 
  1081         "  ==  "  ^ @{make_string} q  ^ 
  1080         "  **  "  ^ @{make_string} b ^ "  ++  "  ^ @{make_string} r)
  1082         "  **  "  ^ @{make_string} b ^ "  ++  "  ^ @{make_string} r)
  1081     else ();
  1083     else ();
  1082 
  1084 
  1086       let
  1088       let
  1087         val (n, q, r) = a %*/% b
  1089         val (n, q, r) = a %*/% b
  1088         val _ = writeln_trace_Euclid a b n q r
  1090         val _ = writeln_trace_Euclid a b n q r
  1089       in EUCLID_naive_up b r : unipoly end;
  1091       in EUCLID_naive_up b r : unipoly end;
  1090 \<close>
  1092 \<close>
       
  1093 declare [[trace_div = false]]
       
  1094 declare [[trace_div_invariant = false]]
       
  1095 declare [[trace_Euclid = true]]
  1091 ML \<open>
  1096 ML \<open>
  1092   (*The example used in the inital mail to Tobias Nipkow made univariate: y -> 1*)
  1097   (*The example used in the inital mail to Tobias Nipkow made univariate: y -> 1*)
  1093   trace_div := false;
       
  1094   trace_div_invariant := false;
       
  1095   trace_Euclid := true;
       
  1096   "--------------------------------";
  1098   "--------------------------------";
  1097   val a = [0,~1,1]: unipoly; (* -x + x^2 =  x   *(-1 + x) *)
  1099   val a = [0,~1,1]: unipoly; (* -x + x^2 =  x   *(-1 + x) *)
  1098   val b = [~1,0,1]: unipoly; (* -1 + x^2 = (1+x)*(-1 + x) *)
  1100   val b = [~1,0,1]: unipoly; (* -1 + x^2 = (1+x)*(-1 + x) *)
  1099   "--------------------------------";
  1101   "--------------------------------";
  1100   EUCLID_naive_up a b; (* = [1, ~1]*)          (*( 1 - x) *)
  1102   EUCLID_naive_up a b; (* = [1, ~1]*)          (*( 1 - x) *)
  1137 subsubsection \<open>Interactivity on Euclids Algorithm\<close>
  1139 subsubsection \<open>Interactivity on Euclids Algorithm\<close>
  1138 text \<open>
  1140 text \<open>
  1139   Euclids Algorithm in modern algebraic notation explains itself if presented
  1141   Euclids Algorithm in modern algebraic notation explains itself if presented
  1140   this way:
  1142   this way:
  1141 \<close>
  1143 \<close>
  1142 ML \<open>
  1144 declare [[trace_div = false]]
  1143   trace_div := false;
  1145 declare [[trace_div_invariant = false]]
  1144   trace_div_invariant := false;
  1146 declare [[trace_Euclid = true]]
  1145   trace_Euclid := true;
  1147 ML \<open>
  1146   "--------------------------------";
  1148   "--------------------------------";
  1147   val a = [~1,0,0,1]: unipoly; (* -1 + x^3 = (1+x+x^2)*(-1 + x) *)
  1149   val a = [~1,0,0,1]: unipoly; (* -1 + x^3 = (1+x+x^2)*(-1 + x) *)
  1148   val b = [0,~1,1]: unipoly;   (* -x + x^2 = x        *(-1 + x) *)
  1150   val b = [0,~1,1]: unipoly;   (* -x + x^2 = x        *(-1 + x) *)
  1149   "--------------------------------";
  1151   "--------------------------------";
  1150   EUCLID_naive_up a b; (*  = [~1, 1]*)      (*(-1 + x)     [[2]]*)
  1152   EUCLID_naive_up a b; (*  = [~1, 1]*)      (*(-1 + x)     [[2]]*)
  1151 (*
  1153 (*
  1152   Euclid [~1, 0, 0, 1]  *  1  ==  [1, 1]  **  [0, ~1, 1]  ++  [~1, 1] 
  1154   Euclid [~1, 0, 0, 1]  *  1  ==  [1, 1]  **  [0, ~1, 1]  ++  [~1, 1] 
  1153   Euclid [0, ~1, 1]  *  1  ==  [0, 1]  **  [~1, 1]  ++  [] 
  1155   Euclid [0, ~1, 1]  *  1  ==  [0, 1]  **  [~1, 1]  ++  [] 
  1154 *)
  1156 *)
  1155 \<close>
  1157 \<close>
  1156 ML \<open>
  1158 declare [[trace_Euclid = true]]
  1157   trace_Euclid := true;
  1159 ML \<open>
  1158   (* from [1].p.94 *)
  1160   (* from [1].p.94 *)
  1159   "--------------------------------";
  1161   "--------------------------------";
  1160   val a = [~18, ~15, ~20, 12, 20, ~13, 2]: unipoly;
  1162   val a = [~18, ~15, ~20, 12, 20, ~13, 2]: unipoly;
  1161   val b = [8, 28, 22, ~11, ~14, 1, 2]: unipoly;
  1163   val b = [8, 28, 22, ~11, ~14, 1, 2]: unipoly;
  1162   "--------------------------------";
  1164   "--------------------------------";
  1192   (1) a student wants to roughly understand what happens in the algorithm
  1194   (1) a student wants to roughly understand what happens in the algorithm
  1193   (2) a student wants to reproduce the algorithm by hand.
  1195   (2) a student wants to reproduce the algorithm by hand.
  1194 
  1196 
  1195   Case (1) again calls for the fixpoint:
  1197   Case (1) again calls for the fixpoint:
  1196 \<close>
  1198 \<close>
  1197 ML \<open>
  1199 declare [[trace_div = false]]
  1198   trace_div := false;
  1200 declare [[trace_div_invariant = true]]
  1199   trace_div_invariant := true;
  1201 ML \<open>
  1200   val p1 = [2, 2, 2, 2, 2];
  1202   val p1 = [2, 2, 2, 2, 2];
  1201   val p2 = [1, 2, 3];
  1203   val p2 = [1, 2, 3];
  1202   val (n (* = 27*), 
  1204   val (n (* = 27*), 
  1203        q (* = [8, 6, 18]*), 
  1205        q (* = [8, 6, 18]*), 
  1204        r (* = [46, 32]*)) = p1 %*/% p2;
  1206        r (* = [46, 32]*)) = p1 %*/% p2;
  1214   divisor.
  1216   divisor.
  1215 
  1217 
  1216   This representation, however, is inappropriate for reproduction by hand.
  1218   This representation, however, is inappropriate for reproduction by hand.
  1217   Dividing polynomials by hand is taught in this format:
  1219   Dividing polynomials by hand is taught in this format:
  1218 \<close>
  1220 \<close>
  1219 ML \<open>
  1221 declare [[trace_div = true]]
  1220   trace_div := true;
  1222 declare [[trace_div_invariant = false]]
  1221   trace_div_invariant := false;
  1223 ML \<open>
  1222   val p1 = [2, 2, 2, 2, 2];
  1224   val p1 = [2, 2, 2, 2, 2];
  1223   val p2 = [1, 2, 3];
  1225   val p2 = [1, 2, 3];
  1224   val (n (* = 27*), 
  1226   val (n (* = 27*), 
  1225        q (* = [8, 6, 18]*), 
  1227        q (* = [8, 6, 18]*), 
  1226        r (* = [46, 32]*)) = p1 %*/% p2;
  1228        r (* = [46, 32]*)) = p1 %*/% p2;
  1252   The above algorithm is unusual in that the dividend first is multiplied
  1254   The above algorithm is unusual in that the dividend first is multiplied
  1253   such that the quotient can have integer coefficients ("generalised division"). 
  1255   such that the quotient can have integer coefficients ("generalised division"). 
  1254   Thus the quotient needs to be multiplied subsequently as well. 
  1256   Thus the quotient needs to be multiplied subsequently as well. 
  1255   The algorithm also has to handle cases, where zeros occur in the quotient: 
  1257   The algorithm also has to handle cases, where zeros occur in the quotient: 
  1256 \<close>                      
  1258 \<close>                      
  1257 ML \<open>
  1259 declare [[trace_div = true]]
  1258   trace_div := true;
  1260 ML \<open>
  1259   val p1 = [3,2,2,2,1,1,1,1];
  1261   val p1 = [3,2,2,2,1,1,1,1];
  1260   val p2 = [1,1,1,1];
  1262   val p2 = [1,1,1,1];
  1261   val (n (* = 1*), 
  1263   val (n (* = 1*), 
  1262        q (* = [2, 0, 0, 0, 1]*), 
  1264        q (* = [2, 0, 0, 0, 1]*), 
  1263        r (* = [1]*)) = p1 %*/% p2;
  1265        r (* = [1]*)) = p1 %*/% p2;
  1360 text \<open>
  1362 text \<open>
  1361   Respective ML code and further examples are at [[1]] above.
  1363   Respective ML code and further examples are at [[1]] above.
  1362   PSEUDO-division is "%*/%";
  1364   PSEUDO-division is "%*/%";
  1363   we set switches to create output as found in the extended abstract:
  1365   we set switches to create output as found in the extended abstract:
  1364 \<close>
  1366 \<close>
  1365 ML \<open>
  1367 declare [[trace_div = false]]
  1366   trace_div_invariant := true;
  1368 declare [[trace_div_invariant = true]]
  1367   trace_div := false;
  1369 ML \<open>
  1368 \<close> ML \<open>
  1370 \<close> ML \<open>
  1369   [1, 2, 3, 4, 5, 6] %*/% [7, 8, 9]
  1371   [1, 2, 3, 4, 5, 6] %*/% [7, 8, 9]
  1370 \<close>
  1372 \<close>
  1371 text \<open>
  1373 text \<open>
  1372   We need a notepad for interactive trials!
  1374   We need a notepad for interactive trials!
  1373   And this gives the invariant of the GCD:
  1375   And this gives the invariant of the GCD:
  1374 \<close>
  1376 \<close>
  1375 ML \<open>
  1377 declare [[trace_div = true]]
  1376   trace_Euclid := true;
  1378 declare [[trace_div_invariant = false]]
  1377   trace_div_invariant := false;
  1379 ML \<open>
  1378   trace_div := false;
       
  1379   EUCLID_naive_up [~18, ~15, ~20, 12, 20, ~13, 2] [8, 28, 22, ~11, ~14, 1, 2]
  1380   EUCLID_naive_up [~18, ~15, ~20, 12, 20, ~13, 2] [8, 28, 22, ~11, ~14, 1, 2]
  1380 \<close>
  1381 \<close>
  1381 thm gcd_add_mult
  1382 thm gcd_add_mult
  1382 
  1383 
  1383 subsection \<open>Step-wise Construction of DIV and GCD\<close>
  1384 subsection \<open>Step-wise Construction of DIV and GCD\<close>
  1384 text \<open>
  1385 text \<open>
  1385   We take smaller polynomials for DIV; 
  1386   We take smaller polynomials for DIV; 
  1386 \<close>
  1387 \<close>
  1387 ML \<open>
  1388 declare [[trace_div = true]]
  1388   trace_div := true;
  1389 declare [[trace_div_invariant = false]]
  1389   trace_div_invariant := false;
  1390 ML \<open>
  1390   [4, 3, 2, 1] %*/% [2, 1]
  1391   [4, 3, 2, 1] %*/% [2, 1]
  1391 \<close>
  1392 \<close>
  1392 text \<open>
  1393 text \<open>
  1393   For GCD fill-in gaps in the invariant seem appropriate;
  1394   For GCD fill-in gaps in the invariant seem appropriate;
  1394   additionally a notepad is required.
  1395   additionally a notepad is required.