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. |