author | paulson |
Wed, 13 Sep 2000 18:47:30 +0200 | |
changeset 9945 | a0efbd7c88dc |
parent 9747 | 043098ba5098 |
child 10139 | 9fa7d3890488 |
permissions | -rw-r--r-- |
6917 | 1 |
(* Title: HOL/IntDiv.ML |
2 |
ID: $Id$ |
|
3 |
Author: Lawrence C Paulson, Cambridge University Computer Laboratory |
|
4 |
Copyright 1999 University of Cambridge |
|
5 |
||
6 |
The division operators div, mod and the divides relation "dvd" |
|
6992 | 7 |
|
8 |
Here is the division algorithm in ML: |
|
9 |
||
10 |
fun posDivAlg (a,b) = |
|
11 |
if a<b then (0,a) |
|
12 |
else let val (q,r) = posDivAlg(a, 2*b) |
|
13 |
in if 0<=r-b then (2*q+1, r-b) else (2*q, r) |
|
14 |
end; |
|
15 |
||
16 |
fun negDivAlg (a,b) = |
|
17 |
if 0<=a+b then (~1,a+b) |
|
18 |
else let val (q,r) = negDivAlg(a, 2*b) |
|
19 |
in if 0<=r-b then (2*q+1, r-b) else (2*q, r) |
|
20 |
end; |
|
21 |
||
22 |
fun negateSnd (q,r:int) = (q,~r); |
|
23 |
||
24 |
fun divAlg (a,b) = if 0<=a then |
|
25 |
if b>0 then posDivAlg (a,b) |
|
26 |
else if a=0 then (0,0) |
|
27 |
else negateSnd (negDivAlg (~a,~b)) |
|
28 |
else |
|
29 |
if 0<b then negDivAlg (a,b) |
|
30 |
else negateSnd (posDivAlg (~a,~b)); |
|
6917 | 31 |
*) |
32 |
||
33 |
Addsimps [zless_nat_conj]; |
|
34 |
||
35 |
(*** Uniqueness and monotonicity of quotients and remainders ***) |
|
36 |
||
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
37 |
Goal "[| b*q' + r' <= b*q + r; #0 <= r'; #0 < b; r < b |] \ |
6917 | 38 |
\ ==> q' <= (q::int)"; |
39 |
by (subgoal_tac "r' + b * (q'-q) <= r" 1); |
|
8918 | 40 |
by (simp_tac (simpset() addsimps [zdiff_zmult_distrib2]) 2); |
6917 | 41 |
by (subgoal_tac "#0 < b * (#1 + q - q')" 1); |
42 |
by (etac order_le_less_trans 2); |
|
8918 | 43 |
by (full_simp_tac (simpset() addsimps [zdiff_zmult_distrib2, |
44 |
zadd_zmult_distrib2]) 2); |
|
6917 | 45 |
by (subgoal_tac "b * q' < b * (#1 + q)" 1); |
8918 | 46 |
by (full_simp_tac (simpset() addsimps [zdiff_zmult_distrib2, |
47 |
zadd_zmult_distrib2]) 2); |
|
9633
a71a83253997
better rules for cancellation of common factors across comparisons
paulson
parents:
9509
diff
changeset
|
48 |
by (asm_full_simp_tac (simpset() addsimps [zmult_zless_cancel1]) 1); |
6917 | 49 |
qed "unique_quotient_lemma"; |
50 |
||
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
51 |
Goal "[| b*q' + r' <= b*q + r; r <= #0; b < #0; b < r' |] \ |
6917 | 52 |
\ ==> q <= (q'::int)"; |
53 |
by (res_inst_tac [("b", "-b"), ("r", "-r'"), ("r'", "-r")] |
|
54 |
unique_quotient_lemma 1); |
|
55 |
by (auto_tac (claset(), |
|
8918 | 56 |
simpset() addsimps [zmult_zminus, zmult_zminus_right])); |
6917 | 57 |
qed "unique_quotient_lemma_neg"; |
58 |
||
59 |
||
60 |
Goal "[| quorem ((a,b), (q,r)); quorem ((a,b), (q',r')); b ~= #0 |] \ |
|
61 |
\ ==> q = q'"; |
|
62 |
by (asm_full_simp_tac |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
63 |
(simpset() addsimps split_ifs@ |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
64 |
[quorem_def, linorder_neq_iff]) 1); |
6917 | 65 |
by Safe_tac; |
66 |
by (ALLGOALS Asm_full_simp_tac); |
|
67 |
by (REPEAT |
|
68 |
(blast_tac (claset() addIs [order_antisym] |
|
69 |
addDs [order_eq_refl RS unique_quotient_lemma, |
|
70 |
order_eq_refl RS unique_quotient_lemma_neg, |
|
71 |
sym]) 1)); |
|
72 |
qed "unique_quotient"; |
|
73 |
||
74 |
||
75 |
Goal "[| quorem ((a,b), (q,r)); quorem ((a,b), (q',r')); b ~= #0 |] \ |
|
76 |
\ ==> r = r'"; |
|
77 |
by (subgoal_tac "q = q'" 1); |
|
78 |
by (blast_tac (claset() addIs [unique_quotient]) 2); |
|
79 |
by (asm_full_simp_tac (simpset() addsimps [quorem_def]) 1); |
|
80 |
qed "unique_remainder"; |
|
81 |
||
82 |
||
83 |
(*** Correctness of posDivAlg, the division algorithm for a>=0 and b>0 ***) |
|
84 |
||
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
85 |
|
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
86 |
Goal "adjust a b (q,r) = (let diff = r-b in \ |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
87 |
\ if #0 <= diff then (#2*q + #1, diff) \ |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
88 |
\ else (#2*q, r))"; |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
89 |
by (simp_tac (simpset() addsimps [Let_def,adjust_def]) 1); |
6917 | 90 |
qed "adjust_eq"; |
91 |
Addsimps [adjust_eq]; |
|
92 |
||
93 |
(*Proving posDivAlg's termination condition*) |
|
94 |
val [tc] = posDivAlg.tcs; |
|
9367 | 95 |
goalw_cterm [] (cterm_of (sign_of (the_context ())) (HOLogic.mk_Trueprop tc)); |
8787 | 96 |
by Auto_tac; |
6917 | 97 |
val lemma = result(); |
98 |
||
99 |
(* removing the termination condition from the generated theorems *) |
|
100 |
||
8624 | 101 |
bind_thm ("posDivAlg_raw_eqn", lemma RS hd posDivAlg.simps); |
6917 | 102 |
|
103 |
(**use with simproc to avoid re-proving the premise*) |
|
104 |
Goal "#0 < b ==> \ |
|
105 |
\ posDivAlg (a,b) = \ |
|
106 |
\ (if a<b then (#0,a) else adjust a b (posDivAlg(a, #2*b)))"; |
|
107 |
by (rtac (posDivAlg_raw_eqn RS trans) 1); |
|
108 |
by (Asm_simp_tac 1); |
|
109 |
qed "posDivAlg_eqn"; |
|
110 |
||
9108 | 111 |
bind_thm ("posDivAlg_induct", lemma RS posDivAlg.induct); |
6917 | 112 |
|
113 |
||
114 |
(*Correctness of posDivAlg: it computes quotients correctly*) |
|
115 |
Goal "#0 <= a --> #0 < b --> quorem ((a, b), posDivAlg (a, b))"; |
|
9747 | 116 |
by (induct_thm_tac posDivAlg_induct "a b" 1); |
6917 | 117 |
by Auto_tac; |
9063 | 118 |
by (ALLGOALS (asm_full_simp_tac (simpset() addsimps [quorem_def]))); |
6917 | 119 |
(*base case: a<b*) |
120 |
by (asm_full_simp_tac (simpset() addsimps [posDivAlg_eqn]) 1); |
|
121 |
(*main argument*) |
|
122 |
by (stac posDivAlg_eqn 1); |
|
123 |
by (ALLGOALS Asm_simp_tac); |
|
124 |
by (etac splitE 1); |
|
8918 | 125 |
by (auto_tac (claset(), simpset() addsimps [zadd_zmult_distrib2, Let_def])); |
6917 | 126 |
qed_spec_mp "posDivAlg_correct"; |
127 |
||
128 |
||
129 |
(*** Correctness of negDivAlg, the division algorithm for a<0 and b>0 ***) |
|
130 |
||
131 |
(*Proving negDivAlg's termination condition*) |
|
132 |
val [tc] = negDivAlg.tcs; |
|
9422 | 133 |
goalw_cterm [] (cterm_of (sign_of (the_context ())) (HOLogic.mk_Trueprop tc)); |
8787 | 134 |
by Auto_tac; |
6917 | 135 |
val lemma = result(); |
136 |
||
137 |
(* removing the termination condition from the generated theorems *) |
|
138 |
||
8624 | 139 |
bind_thm ("negDivAlg_raw_eqn", lemma RS hd negDivAlg.simps); |
6917 | 140 |
|
141 |
(**use with simproc to avoid re-proving the premise*) |
|
142 |
Goal "#0 < b ==> \ |
|
143 |
\ negDivAlg (a,b) = \ |
|
144 |
\ (if #0<=a+b then (#-1,a+b) else adjust a b (negDivAlg(a, #2*b)))"; |
|
145 |
by (rtac (negDivAlg_raw_eqn RS trans) 1); |
|
146 |
by (Asm_simp_tac 1); |
|
147 |
qed "negDivAlg_eqn"; |
|
148 |
||
9108 | 149 |
bind_thm ("negDivAlg_induct", lemma RS negDivAlg.induct); |
6917 | 150 |
|
151 |
||
152 |
(*Correctness of negDivAlg: it computes quotients correctly |
|
153 |
It doesn't work if a=0 because the 0/b=0 rather than -1*) |
|
154 |
Goal "a < #0 --> #0 < b --> quorem ((a, b), negDivAlg (a, b))"; |
|
9747 | 155 |
by (induct_thm_tac negDivAlg_induct "a b" 1); |
6917 | 156 |
by Auto_tac; |
9063 | 157 |
by (ALLGOALS (asm_full_simp_tac (simpset() addsimps [quorem_def]))); |
6917 | 158 |
(*base case: 0<=a+b*) |
159 |
by (asm_full_simp_tac (simpset() addsimps [negDivAlg_eqn]) 1); |
|
160 |
(*main argument*) |
|
161 |
by (stac negDivAlg_eqn 1); |
|
162 |
by (ALLGOALS Asm_simp_tac); |
|
163 |
by (etac splitE 1); |
|
8918 | 164 |
by (auto_tac (claset(), simpset() addsimps [zadd_zmult_distrib2, Let_def])); |
6917 | 165 |
qed_spec_mp "negDivAlg_correct"; |
166 |
||
167 |
||
168 |
(*** Existence shown by proving the division algorithm to be correct ***) |
|
169 |
||
170 |
(*the case a=0*) |
|
171 |
Goal "b ~= #0 ==> quorem ((#0,b), (#0,#0))"; |
|
172 |
by (auto_tac (claset(), |
|
173 |
simpset() addsimps [quorem_def, linorder_neq_iff])); |
|
174 |
qed "quorem_0"; |
|
175 |
||
176 |
Goal "posDivAlg (#0, b) = (#0, #0)"; |
|
177 |
by (stac posDivAlg_raw_eqn 1); |
|
178 |
by Auto_tac; |
|
179 |
qed "posDivAlg_0"; |
|
180 |
Addsimps [posDivAlg_0]; |
|
181 |
||
182 |
Goal "negDivAlg (#-1, b) = (#-1, b-#1)"; |
|
183 |
by (stac negDivAlg_raw_eqn 1); |
|
184 |
by Auto_tac; |
|
185 |
qed "negDivAlg_minus1"; |
|
186 |
Addsimps [negDivAlg_minus1]; |
|
187 |
||
188 |
Goalw [negateSnd_def] "negateSnd(q,r) = (q,-r)"; |
|
189 |
by Auto_tac; |
|
190 |
qed "negateSnd_eq"; |
|
191 |
Addsimps [negateSnd_eq]; |
|
192 |
||
193 |
Goal "quorem ((-a,-b), qr) ==> quorem ((a,b), negateSnd qr)"; |
|
8785 | 194 |
by (auto_tac (claset(), simpset() addsimps split_ifs@[quorem_def])); |
6917 | 195 |
qed "quorem_neg"; |
196 |
||
197 |
Goal "b ~= #0 ==> quorem ((a,b), divAlg(a,b))"; |
|
198 |
by (auto_tac (claset(), |
|
199 |
simpset() addsimps [quorem_0, divAlg_def])); |
|
200 |
by (REPEAT_FIRST (resolve_tac [quorem_neg, posDivAlg_correct, |
|
201 |
negDivAlg_correct])); |
|
202 |
by (auto_tac (claset(), |
|
203 |
simpset() addsimps [quorem_def, linorder_neq_iff])); |
|
204 |
qed "divAlg_correct"; |
|
205 |
||
6992 | 206 |
(** Aribtrary definitions for division by zero. Useful to simplify |
207 |
certain equations **) |
|
208 |
||
209 |
Goal "a div (#0::int) = #0"; |
|
210 |
by (simp_tac (simpset() addsimps [div_def, divAlg_def, posDivAlg_raw_eqn]) 1); |
|
7035 | 211 |
qed "DIVISION_BY_ZERO_ZDIV"; (*NOT for adding to default simpset*) |
6992 | 212 |
|
213 |
Goal "a mod (#0::int) = a"; |
|
214 |
by (simp_tac (simpset() addsimps [mod_def, divAlg_def, posDivAlg_raw_eqn]) 1); |
|
7035 | 215 |
qed "DIVISION_BY_ZERO_ZMOD"; (*NOT for adding to default simpset*) |
6992 | 216 |
|
7035 | 217 |
fun zdiv_undefined_case_tac s i = |
6992 | 218 |
case_tac s i THEN |
7035 | 219 |
asm_simp_tac (simpset() addsimps [DIVISION_BY_ZERO_ZDIV, |
220 |
DIVISION_BY_ZERO_ZMOD]) i; |
|
6992 | 221 |
|
222 |
(** Basic laws about division and remainder **) |
|
223 |
||
224 |
Goal "(a::int) = b * (a div b) + (a mod b)"; |
|
7035 | 225 |
by (zdiv_undefined_case_tac "b = #0" 1); |
6917 | 226 |
by (cut_inst_tac [("a","a"),("b","b")] divAlg_correct 1); |
227 |
by (auto_tac (claset(), |
|
228 |
simpset() addsimps [quorem_def, div_def, mod_def])); |
|
229 |
qed "zmod_zdiv_equality"; |
|
230 |
||
231 |
Goal "(#0::int) < b ==> #0 <= a mod b & a mod b < b"; |
|
232 |
by (cut_inst_tac [("a","a"),("b","b")] divAlg_correct 1); |
|
233 |
by (auto_tac (claset(), |
|
234 |
simpset() addsimps [quorem_def, mod_def])); |
|
235 |
bind_thm ("pos_mod_sign", result() RS conjunct1); |
|
236 |
bind_thm ("pos_mod_bound", result() RS conjunct2); |
|
237 |
||
238 |
Goal "b < (#0::int) ==> a mod b <= #0 & b < a mod b"; |
|
239 |
by (cut_inst_tac [("a","a"),("b","b")] divAlg_correct 1); |
|
240 |
by (auto_tac (claset(), |
|
241 |
simpset() addsimps [quorem_def, div_def, mod_def])); |
|
242 |
bind_thm ("neg_mod_sign", result() RS conjunct1); |
|
243 |
bind_thm ("neg_mod_bound", result() RS conjunct2); |
|
244 |
||
245 |
||
6992 | 246 |
(** proving general properties of div and mod **) |
247 |
||
248 |
Goal "b ~= #0 ==> quorem ((a, b), (a div b, a mod b))"; |
|
249 |
by (cut_inst_tac [("a","a"),("b","b")] zmod_zdiv_equality 1); |
|
250 |
by (auto_tac |
|
251 |
(claset(), |
|
252 |
simpset() addsimps [quorem_def, linorder_neq_iff, |
|
253 |
pos_mod_sign,pos_mod_bound, |
|
254 |
neg_mod_sign, neg_mod_bound])); |
|
255 |
qed "quorem_div_mod"; |
|
256 |
||
257 |
Goal "[| quorem((a,b),(q,r)); b ~= #0 |] ==> a div b = q"; |
|
258 |
by (asm_simp_tac (simpset() addsimps [quorem_div_mod RS unique_quotient]) 1); |
|
259 |
qed "quorem_div"; |
|
260 |
||
261 |
Goal "[| quorem((a,b),(q,r)); b ~= #0 |] ==> a mod b = r"; |
|
262 |
by (asm_simp_tac (simpset() addsimps [quorem_div_mod RS unique_remainder]) 1); |
|
263 |
qed "quorem_mod"; |
|
264 |
||
265 |
Goal "[| (#0::int) <= a; a < b |] ==> a div b = #0"; |
|
266 |
by (rtac quorem_div 1); |
|
267 |
by (auto_tac (claset(), simpset() addsimps [quorem_def])); |
|
6999 | 268 |
qed "div_pos_pos_trivial"; |
6992 | 269 |
|
270 |
Goal "[| a <= (#0::int); b < a |] ==> a div b = #0"; |
|
271 |
by (rtac quorem_div 1); |
|
272 |
by (auto_tac (claset(), simpset() addsimps [quorem_def])); |
|
6999 | 273 |
qed "div_neg_neg_trivial"; |
274 |
||
275 |
Goal "[| (#0::int) < a; a+b <= #0 |] ==> a div b = #-1"; |
|
276 |
by (rtac quorem_div 1); |
|
277 |
by (auto_tac (claset(), simpset() addsimps [quorem_def])); |
|
278 |
qed "div_pos_neg_trivial"; |
|
279 |
||
280 |
(*There is no div_neg_pos_trivial because #0 div b = #0 would supersede it*) |
|
6992 | 281 |
|
282 |
Goal "[| (#0::int) <= a; a < b |] ==> a mod b = a"; |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
283 |
by (res_inst_tac [("q","#0")] quorem_mod 1); |
6992 | 284 |
by (auto_tac (claset(), simpset() addsimps [quorem_def])); |
6999 | 285 |
qed "mod_pos_pos_trivial"; |
6992 | 286 |
|
287 |
Goal "[| a <= (#0::int); b < a |] ==> a mod b = a"; |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
288 |
by (res_inst_tac [("q","#0")] quorem_mod 1); |
6992 | 289 |
by (auto_tac (claset(), simpset() addsimps [quorem_def])); |
6999 | 290 |
qed "mod_neg_neg_trivial"; |
291 |
||
292 |
Goal "[| (#0::int) < a; a+b <= #0 |] ==> a mod b = a+b"; |
|
293 |
by (res_inst_tac [("q","#-1")] quorem_mod 1); |
|
294 |
by (auto_tac (claset(), simpset() addsimps [quorem_def])); |
|
295 |
qed "mod_pos_neg_trivial"; |
|
296 |
||
297 |
(*There is no mod_neg_pos_trivial...*) |
|
6992 | 298 |
|
299 |
||
9945 | 300 |
(*Simpler laws such as -a div b = -(a div b) FAIL, but see just below*) |
6992 | 301 |
Goal "(-a) div (-b) = a div (b::int)"; |
7035 | 302 |
by (zdiv_undefined_case_tac "b = #0" 1); |
6992 | 303 |
by (stac ((simplify(simpset()) (quorem_div_mod RS quorem_neg)) |
304 |
RS quorem_div) 1); |
|
305 |
by Auto_tac; |
|
306 |
qed "zdiv_zminus_zminus"; |
|
307 |
Addsimps [zdiv_zminus_zminus]; |
|
308 |
||
9945 | 309 |
(*Simpler laws such as -a mod b = -(a mod b) FAIL, but see just below*) |
6992 | 310 |
Goal "(-a) mod (-b) = - (a mod (b::int))"; |
7035 | 311 |
by (zdiv_undefined_case_tac "b = #0" 1); |
6992 | 312 |
by (stac ((simplify(simpset()) (quorem_div_mod RS quorem_neg)) |
313 |
RS quorem_mod) 1); |
|
314 |
by Auto_tac; |
|
315 |
qed "zmod_zminus_zminus"; |
|
316 |
Addsimps [zmod_zminus_zminus]; |
|
317 |
||
318 |
||
9945 | 319 |
(*** div, mod and unary minus ***) |
320 |
||
321 |
Goal "quorem((a,b),(q,r)) \ |
|
322 |
\ ==> quorem ((-a,b), (if r=#0 then -q else -q-#1), \ |
|
323 |
\ (if r=#0 then #0 else b-r))"; |
|
324 |
by (auto_tac |
|
325 |
(claset(), |
|
326 |
simpset() addsimps split_ifs@ |
|
327 |
[quorem_def, linorder_neq_iff, |
|
328 |
zdiff_zmult_distrib2])); |
|
329 |
val lemma = result(); |
|
330 |
||
331 |
Goal "b ~= (#0::int) \ |
|
332 |
\ \\<Longrightarrow> (-a) div b = \ |
|
333 |
\ (if a mod b = #0 then - (a div b) else - (a div b) - #1)"; |
|
334 |
by (blast_tac (claset() addIs [quorem_div_mod RS lemma RS quorem_div]) 1); |
|
335 |
qed "zdiv_zminus1_eq_if"; |
|
336 |
||
337 |
Goal "(-a::int) mod b = (if a mod b = #0 then #0 else b - (a mod b))"; |
|
338 |
by (zdiv_undefined_case_tac "b = #0" 1); |
|
339 |
by (blast_tac (claset() addIs [quorem_div_mod RS lemma RS quorem_mod]) 1); |
|
340 |
qed "zmod_zminus1_eq_if"; |
|
341 |
||
342 |
Goal "a div (-b) = (-a::int) div b"; |
|
343 |
by (cut_inst_tac [("a","-a")] zdiv_zminus_zminus 1); |
|
344 |
by Auto_tac; |
|
345 |
qed "zdiv_zminus2"; |
|
346 |
||
347 |
Goal "a mod (-b) = - ((-a::int) mod b)"; |
|
348 |
by (cut_inst_tac [("a","-a"),("b","b")] zmod_zminus_zminus 1); |
|
349 |
by Auto_tac; |
|
350 |
qed "zmod_zminus2"; |
|
351 |
||
352 |
Goal "b ~= (#0::int) \ |
|
353 |
\ \\<Longrightarrow> a div (-b) = \ |
|
354 |
\ (if a mod b = #0 then - (a div b) else - (a div b) - #1)"; |
|
355 |
by (asm_simp_tac (simpset() addsimps [zdiv_zminus1_eq_if, zdiv_zminus2]) 1); |
|
356 |
qed "zdiv_zminus2_eq_if"; |
|
357 |
||
358 |
Goal "a mod (-b::int) = (if a mod b = #0 then #0 else (a mod b) - b)"; |
|
359 |
by (asm_simp_tac (simpset() addsimps [zmod_zminus1_eq_if, zmod_zminus2]) 1); |
|
360 |
qed "zmod_zminus2_eq_if"; |
|
361 |
||
362 |
||
6992 | 363 |
(*** division of a number by itself ***) |
364 |
||
365 |
Goal "[| (#0::int) < a; a = r + a*q; r < a |] ==> #1 <= q"; |
|
366 |
by (subgoal_tac "#0 < a*q" 1); |
|
367 |
by (arith_tac 2); |
|
9063 | 368 |
by (asm_full_simp_tac (simpset() addsimps [int_0_less_mult_iff]) 1); |
6992 | 369 |
val lemma1 = result(); |
370 |
||
371 |
Goal "[| (#0::int) < a; a = r + a*q; #0 <= r |] ==> q <= #1"; |
|
372 |
by (subgoal_tac "#0 <= a*(#1-q)" 1); |
|
373 |
by (asm_simp_tac (simpset() addsimps [zdiff_zmult_distrib2]) 2); |
|
9063 | 374 |
by (asm_full_simp_tac (simpset() addsimps [int_0_le_mult_iff]) 1); |
6992 | 375 |
val lemma2 = result(); |
376 |
||
377 |
Goal "[| quorem((a,a),(q,r)); a ~= (#0::int) |] ==> q = #1"; |
|
378 |
by (asm_full_simp_tac |
|
379 |
(simpset() addsimps split_ifs@[quorem_def, linorder_neq_iff]) 1); |
|
380 |
by (rtac order_antisym 1); |
|
381 |
by Safe_tac; |
|
382 |
by Auto_tac; |
|
383 |
by (res_inst_tac [("a", "-a"),("r", "-r")] lemma1 3); |
|
384 |
by (res_inst_tac [("a", "-a"),("r", "-r")] lemma2 1); |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
385 |
by (REPEAT (force_tac (claset() addIs [lemma1,lemma2], |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
386 |
simpset() addsimps [zadd_commute, zmult_zminus]) 1)); |
6992 | 387 |
qed "self_quotient"; |
388 |
||
389 |
Goal "[| quorem((a,a),(q,r)); a ~= (#0::int) |] ==> r = #0"; |
|
7499 | 390 |
by (ftac self_quotient 1); |
6992 | 391 |
by (assume_tac 1); |
392 |
by (asm_full_simp_tac (simpset() addsimps [quorem_def]) 1); |
|
393 |
qed "self_remainder"; |
|
394 |
||
395 |
Goal "a ~= #0 ==> a div a = (#1::int)"; |
|
396 |
by (asm_simp_tac (simpset() addsimps [quorem_div_mod RS self_quotient]) 1); |
|
397 |
qed "zdiv_self"; |
|
398 |
Addsimps [zdiv_self]; |
|
399 |
||
400 |
(*Here we have 0 mod 0 = 0, also assumed by Knuth (who puts m mod 0 = 0) *) |
|
401 |
Goal "a mod a = (#0::int)"; |
|
7035 | 402 |
by (zdiv_undefined_case_tac "a = #0" 1); |
6992 | 403 |
by (asm_simp_tac (simpset() addsimps [quorem_div_mod RS self_remainder]) 1); |
404 |
qed "zmod_self"; |
|
405 |
Addsimps [zmod_self]; |
|
406 |
||
407 |
||
6917 | 408 |
(*** Computation of division and remainder ***) |
409 |
||
410 |
Goal "(#0::int) div b = #0"; |
|
411 |
by (simp_tac (simpset() addsimps [div_def, divAlg_def]) 1); |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
412 |
qed "zdiv_zero"; |
6917 | 413 |
|
7035 | 414 |
Goal "(#0::int) < b ==> #-1 div b = #-1"; |
415 |
by (asm_simp_tac (simpset() addsimps [div_def, divAlg_def]) 1); |
|
416 |
qed "div_eq_minus1"; |
|
417 |
||
6917 | 418 |
Goal "(#0::int) mod b = #0"; |
419 |
by (simp_tac (simpset() addsimps [mod_def, divAlg_def]) 1); |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
420 |
qed "zmod_zero"; |
6917 | 421 |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
422 |
Addsimps [zdiv_zero, zmod_zero]; |
6917 | 423 |
|
7035 | 424 |
Goal "(#0::int) < b ==> #-1 div b = #-1"; |
425 |
by (asm_simp_tac (simpset() addsimps [div_def, divAlg_def]) 1); |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
426 |
qed "zdiv_minus1"; |
7035 | 427 |
|
428 |
Goal "(#0::int) < b ==> #-1 mod b = b-#1"; |
|
429 |
by (asm_simp_tac (simpset() addsimps [mod_def, divAlg_def]) 1); |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
430 |
qed "zmod_minus1"; |
7035 | 431 |
|
6917 | 432 |
(** a positive, b positive **) |
433 |
||
6992 | 434 |
Goal "[| #0 < a; #0 <= b |] ==> a div b = fst (posDivAlg(a,b))"; |
6917 | 435 |
by (asm_simp_tac (simpset() addsimps [div_def, divAlg_def]) 1); |
436 |
qed "div_pos_pos"; |
|
437 |
||
6992 | 438 |
Goal "[| #0 < a; #0 <= b |] ==> a mod b = snd (posDivAlg(a,b))"; |
6917 | 439 |
by (asm_simp_tac (simpset() addsimps [mod_def, divAlg_def]) 1); |
440 |
qed "mod_pos_pos"; |
|
441 |
||
442 |
(** a negative, b positive **) |
|
443 |
||
444 |
Goal "[| a < #0; #0 < b |] ==> a div b = fst (negDivAlg(a,b))"; |
|
445 |
by (asm_simp_tac (simpset() addsimps [div_def, divAlg_def]) 1); |
|
446 |
qed "div_neg_pos"; |
|
447 |
||
448 |
Goal "[| a < #0; #0 < b |] ==> a mod b = snd (negDivAlg(a,b))"; |
|
449 |
by (asm_simp_tac (simpset() addsimps [mod_def, divAlg_def]) 1); |
|
450 |
qed "mod_neg_pos"; |
|
451 |
||
452 |
(** a positive, b negative **) |
|
453 |
||
454 |
Goal "[| #0 < a; b < #0 |] ==> a div b = fst (negateSnd(negDivAlg(-a,-b)))"; |
|
455 |
by (asm_simp_tac (simpset() addsimps [div_def, divAlg_def]) 1); |
|
456 |
qed "div_pos_neg"; |
|
457 |
||
458 |
Goal "[| #0 < a; b < #0 |] ==> a mod b = snd (negateSnd(negDivAlg(-a,-b)))"; |
|
459 |
by (asm_simp_tac (simpset() addsimps [mod_def, divAlg_def]) 1); |
|
460 |
qed "mod_pos_neg"; |
|
461 |
||
462 |
(** a negative, b negative **) |
|
463 |
||
6992 | 464 |
Goal "[| a < #0; b <= #0 |] ==> a div b = fst (negateSnd(posDivAlg(-a,-b)))"; |
6917 | 465 |
by (asm_simp_tac (simpset() addsimps [div_def, divAlg_def]) 1); |
466 |
qed "div_neg_neg"; |
|
467 |
||
6992 | 468 |
Goal "[| a < #0; b <= #0 |] ==> a mod b = snd (negateSnd(posDivAlg(-a,-b)))"; |
6917 | 469 |
by (asm_simp_tac (simpset() addsimps [mod_def, divAlg_def]) 1); |
470 |
qed "mod_neg_neg"; |
|
471 |
||
9422 | 472 |
Addsimps (map (read_instantiate_sg (sign_of (the_context ())) |
6917 | 473 |
[("a", "number_of ?v"), ("b", "number_of ?w")]) |
474 |
[div_pos_pos, div_neg_pos, div_pos_neg, div_neg_neg, |
|
475 |
mod_pos_pos, mod_neg_pos, mod_pos_neg, mod_neg_neg, |
|
476 |
posDivAlg_eqn, negDivAlg_eqn]); |
|
6992 | 477 |
|
6917 | 478 |
|
479 |
(** Special-case simplification **) |
|
480 |
||
481 |
Goal "a mod (#1::int) = #0"; |
|
482 |
by (cut_inst_tac [("a","a"),("b","#1")] pos_mod_sign 1); |
|
483 |
by (cut_inst_tac [("a","a"),("b","#1")] pos_mod_bound 2); |
|
484 |
by Auto_tac; |
|
485 |
qed "zmod_1"; |
|
486 |
Addsimps [zmod_1]; |
|
487 |
||
488 |
Goal "a div (#1::int) = a"; |
|
489 |
by (cut_inst_tac [("a","a"),("b","#1")] zmod_zdiv_equality 1); |
|
490 |
by Auto_tac; |
|
491 |
qed "zdiv_1"; |
|
492 |
Addsimps [zdiv_1]; |
|
493 |
||
494 |
Goal "a mod (#-1::int) = #0"; |
|
495 |
by (cut_inst_tac [("a","a"),("b","#-1")] neg_mod_sign 1); |
|
496 |
by (cut_inst_tac [("a","a"),("b","#-1")] neg_mod_bound 2); |
|
497 |
by Auto_tac; |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
498 |
qed "zmod_minus1_right"; |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
499 |
Addsimps [zmod_minus1_right]; |
6917 | 500 |
|
501 |
Goal "a div (#-1::int) = -a"; |
|
502 |
by (cut_inst_tac [("a","a"),("b","#-1")] zmod_zdiv_equality 1); |
|
503 |
by Auto_tac; |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
504 |
qed "zdiv_minus1_right"; |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
505 |
Addsimps [zdiv_minus1_right]; |
6917 | 506 |
|
507 |
||
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
508 |
(*** Monotonicity in the first argument (divisor) ***) |
6917 | 509 |
|
510 |
Goal "[| a <= a'; #0 < (b::int) |] ==> a div b <= a' div b"; |
|
511 |
by (cut_inst_tac [("a","a"),("b","b")] zmod_zdiv_equality 1); |
|
6992 | 512 |
by (cut_inst_tac [("a","a'"),("b","b")] zmod_zdiv_equality 1); |
6917 | 513 |
by (rtac unique_quotient_lemma 1); |
514 |
by (etac subst 1); |
|
515 |
by (etac subst 1); |
|
516 |
by (ALLGOALS (asm_simp_tac (simpset() addsimps [pos_mod_sign,pos_mod_bound]))); |
|
517 |
qed "zdiv_mono1"; |
|
518 |
||
519 |
Goal "[| a <= a'; (b::int) < #0 |] ==> a' div b <= a div b"; |
|
520 |
by (cut_inst_tac [("a","a"),("b","b")] zmod_zdiv_equality 1); |
|
6992 | 521 |
by (cut_inst_tac [("a","a'"),("b","b")] zmod_zdiv_equality 1); |
6917 | 522 |
by (rtac unique_quotient_lemma_neg 1); |
523 |
by (etac subst 1); |
|
524 |
by (etac subst 1); |
|
525 |
by (ALLGOALS (asm_simp_tac (simpset() addsimps [neg_mod_sign,neg_mod_bound]))); |
|
526 |
qed "zdiv_mono1_neg"; |
|
527 |
||
528 |
||
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
529 |
(*** Monotonicity in the second argument (dividend) ***) |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
530 |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
531 |
Goal "[| b*q + r = b'*q' + r'; #0 <= b'*q' + r'; \ |
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
532 |
\ r' < b'; #0 <= r; #0 < b'; b' <= b |] \ |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
533 |
\ ==> q <= (q'::int)"; |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
534 |
by (subgoal_tac "#0 <= q'" 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
535 |
by (subgoal_tac "#0 < b'*(q' + #1)" 2); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
536 |
by (asm_simp_tac (simpset() addsimps [zadd_zmult_distrib2]) 3); |
9063 | 537 |
by (asm_full_simp_tac (simpset() addsimps [int_0_less_mult_iff]) 2); |
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
538 |
by (subgoal_tac "b*q < b*(q' + #1)" 1); |
9633
a71a83253997
better rules for cancellation of common factors across comparisons
paulson
parents:
9509
diff
changeset
|
539 |
by (asm_full_simp_tac (simpset() addsimps [zmult_zless_cancel1]) 1); |
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
540 |
by (subgoal_tac "b*q = r' - r + b'*q'" 1); |
8918 | 541 |
by (Simp_tac 2); |
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
542 |
by (asm_simp_tac (simpset() addsimps [zadd_zmult_distrib2]) 1); |
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
543 |
by (stac zadd_commute 1 THEN rtac zadd_zless_mono 1 THEN arith_tac 1); |
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
544 |
by (rtac zmult_zle_mono1 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
545 |
by Auto_tac; |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
546 |
qed "zdiv_mono2_lemma"; |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
547 |
|
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
548 |
Goal "[| (#0::int) <= a; #0 < b'; b' <= b |] \ |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
549 |
\ ==> a div b <= a div b'"; |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
550 |
by (subgoal_tac "b ~= #0" 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
551 |
by (arith_tac 2); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
552 |
by (cut_inst_tac [("a","a"),("b","b")] zmod_zdiv_equality 1); |
6992 | 553 |
by (cut_inst_tac [("a","a"),("b","b'")] zmod_zdiv_equality 1); |
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
554 |
by (rtac zdiv_mono2_lemma 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
555 |
by (etac subst 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
556 |
by (etac subst 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
557 |
by (ALLGOALS (asm_simp_tac (simpset() addsimps [pos_mod_sign,pos_mod_bound]))); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
558 |
qed "zdiv_mono2"; |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
559 |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
560 |
Goal "[| b*q + r = b'*q' + r'; b'*q' + r' < #0; \ |
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
561 |
\ r < b; #0 <= r'; #0 < b'; b' <= b |] \ |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
562 |
\ ==> q' <= (q::int)"; |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
563 |
by (subgoal_tac "q' < #0" 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
564 |
by (subgoal_tac "b'*q' < #0" 2); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
565 |
by (arith_tac 3); |
9063 | 566 |
by (asm_full_simp_tac (simpset() addsimps [zmult_less_0_iff]) 2); |
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
567 |
by (subgoal_tac "b*q' < b*(q + #1)" 1); |
9633
a71a83253997
better rules for cancellation of common factors across comparisons
paulson
parents:
9509
diff
changeset
|
568 |
by (asm_full_simp_tac (simpset() addsimps [zmult_zless_cancel1]) 1); |
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
569 |
by (asm_simp_tac (simpset() addsimps [zadd_zmult_distrib2]) 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
570 |
by (subgoal_tac "b*q' <= b'*q'" 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
571 |
by (asm_simp_tac (simpset() addsimps [zmult_zle_mono1_neg]) 2); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
572 |
by (subgoal_tac "b'*q' < b + b*q" 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
573 |
by (Asm_simp_tac 2); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
574 |
by (arith_tac 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
575 |
qed "zdiv_mono2_neg_lemma"; |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
576 |
|
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
577 |
Goal "[| a < (#0::int); #0 < b'; b' <= b |] \ |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
578 |
\ ==> a div b' <= a div b"; |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
579 |
by (cut_inst_tac [("a","a"),("b","b")] zmod_zdiv_equality 1); |
6992 | 580 |
by (cut_inst_tac [("a","a"),("b","b'")] zmod_zdiv_equality 1); |
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
581 |
by (rtac zdiv_mono2_neg_lemma 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
582 |
by (etac subst 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
583 |
by (etac subst 1); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
584 |
by (ALLGOALS (asm_simp_tac (simpset() addsimps [pos_mod_sign,pos_mod_bound]))); |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
585 |
qed "zdiv_mono2_neg"; |
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
586 |
|
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
587 |
|
6992 | 588 |
(*** More algebraic laws for div and mod ***) |
6943
2cde117d2738
faster division algorithm; monotonicity of div in 2nd arg
paulson
parents:
6917
diff
changeset
|
589 |
|
6992 | 590 |
(** proving (a*b) div c = a * (b div c) + a * (b mod c) **) |
591 |
||
592 |
Goal "[| quorem((b,c),(q,r)); c ~= #0 |] \ |
|
593 |
\ ==> quorem ((a*b, c), (a*q + a*r div c, a*r mod c))"; |
|
594 |
by (auto_tac |
|
595 |
(claset(), |
|
8918 | 596 |
simpset() addsimps split_ifs@ |
6992 | 597 |
[quorem_def, linorder_neq_iff, |
598 |
zadd_zmult_distrib2, |
|
599 |
pos_mod_sign,pos_mod_bound, |
|
600 |
neg_mod_sign, neg_mod_bound])); |
|
7549 | 601 |
by (ALLGOALS(rtac zmod_zdiv_equality)); |
6992 | 602 |
val lemma = result(); |
603 |
||
604 |
Goal "(a*b) div c = a*(b div c) + a*(b mod c) div (c::int)"; |
|
7035 | 605 |
by (zdiv_undefined_case_tac "c = #0" 1); |
6992 | 606 |
by (blast_tac (claset() addIs [quorem_div_mod RS lemma RS quorem_div]) 1); |
607 |
qed "zdiv_zmult1_eq"; |
|
608 |
||
609 |
Goal "(a*b) mod c = a*(b mod c) mod (c::int)"; |
|
7035 | 610 |
by (zdiv_undefined_case_tac "c = #0" 1); |
6992 | 611 |
by (blast_tac (claset() addIs [quorem_div_mod RS lemma RS quorem_mod]) 1); |
612 |
qed "zmod_zmult1_eq"; |
|
613 |
||
9509 | 614 |
Goal "(a*b) mod (c::int) = ((a mod c) * b) mod c"; |
615 |
by (rtac trans 1); |
|
616 |
by (res_inst_tac [("s","b*a mod c")] trans 1); |
|
617 |
by (rtac zmod_zmult1_eq 2); |
|
618 |
by (ALLGOALS (simp_tac (simpset() addsimps [zmult_commute]))); |
|
619 |
qed "zmod_zmult1_eq'"; |
|
620 |
||
621 |
Goal "(a*b) mod (c::int) = ((a mod c) * (b mod c)) mod c"; |
|
622 |
by (rtac (zmod_zmult1_eq' RS trans) 1); |
|
623 |
by (rtac zmod_zmult1_eq 1); |
|
624 |
qed "zmod_zmult_distrib"; |
|
625 |
||
6992 | 626 |
Goal "b ~= (#0::int) ==> (a*b) div b = a"; |
627 |
by (asm_simp_tac (simpset() addsimps [zdiv_zmult1_eq]) 1); |
|
628 |
qed "zdiv_zmult_self1"; |
|
629 |
||
630 |
Goal "b ~= (#0::int) ==> (b*a) div b = a"; |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
631 |
by (stac zmult_commute 1 THEN etac zdiv_zmult_self1 1); |
6992 | 632 |
qed "zdiv_zmult_self2"; |
633 |
||
634 |
Addsimps [zdiv_zmult_self1, zdiv_zmult_self2]; |
|
635 |
||
636 |
Goal "(a*b) mod b = (#0::int)"; |
|
637 |
by (simp_tac (simpset() addsimps [zmod_zmult1_eq]) 1); |
|
638 |
qed "zmod_zmult_self1"; |
|
639 |
||
640 |
Goal "(b*a) mod b = (#0::int)"; |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
641 |
by (simp_tac (simpset() addsimps [zmult_commute, zmod_zmult1_eq]) 1); |
6992 | 642 |
qed "zmod_zmult_self2"; |
643 |
||
644 |
Addsimps [zmod_zmult_self1, zmod_zmult_self2]; |
|
645 |
||
646 |
||
647 |
(** proving (a+b) div c = a div c + b div c + ((a mod c + b mod c) div c) **) |
|
6917 | 648 |
|
6992 | 649 |
Goal "[| quorem((a,c),(aq,ar)); quorem((b,c),(bq,br)); c ~= #0 |] \ |
650 |
\ ==> quorem ((a+b, c), (aq + bq + (ar+br) div c, (ar+br) mod c))"; |
|
651 |
by (auto_tac |
|
652 |
(claset(), |
|
8918 | 653 |
simpset() addsimps split_ifs@ |
6992 | 654 |
[quorem_def, linorder_neq_iff, |
655 |
zadd_zmult_distrib2, |
|
656 |
pos_mod_sign,pos_mod_bound, |
|
657 |
neg_mod_sign, neg_mod_bound])); |
|
7549 | 658 |
by (ALLGOALS(rtac zmod_zdiv_equality)); |
6992 | 659 |
val lemma = result(); |
660 |
||
6999 | 661 |
(*NOT suitable for rewriting: the RHS has an instance of the LHS*) |
6992 | 662 |
Goal "(a+b) div (c::int) = a div c + b div c + ((a mod c + b mod c) div c)"; |
7035 | 663 |
by (zdiv_undefined_case_tac "c = #0" 1); |
6992 | 664 |
by (blast_tac (claset() addIs [[quorem_div_mod,quorem_div_mod] |
665 |
MRS lemma RS quorem_div]) 1); |
|
666 |
qed "zdiv_zadd1_eq"; |
|
667 |
||
668 |
Goal "(a+b) mod (c::int) = (a mod c + b mod c) mod c"; |
|
7035 | 669 |
by (zdiv_undefined_case_tac "c = #0" 1); |
6992 | 670 |
by (blast_tac (claset() addIs [[quorem_div_mod,quorem_div_mod] |
671 |
MRS lemma RS quorem_mod]) 1); |
|
672 |
qed "zmod_zadd1_eq"; |
|
673 |
||
674 |
Goal "(a mod b) div b = (#0::int)"; |
|
7035 | 675 |
by (zdiv_undefined_case_tac "b = #0" 1); |
6992 | 676 |
by (auto_tac (claset(), |
6999 | 677 |
simpset() addsimps [linorder_neq_iff, |
678 |
pos_mod_sign, pos_mod_bound, div_pos_pos_trivial, |
|
679 |
neg_mod_sign, neg_mod_bound, div_neg_neg_trivial])); |
|
6992 | 680 |
qed "mod_div_trivial"; |
681 |
Addsimps [mod_div_trivial]; |
|
682 |
||
683 |
Goal "(a mod b) mod b = a mod (b::int)"; |
|
7035 | 684 |
by (zdiv_undefined_case_tac "b = #0" 1); |
6992 | 685 |
by (auto_tac (claset(), |
6999 | 686 |
simpset() addsimps [linorder_neq_iff, |
687 |
pos_mod_sign, pos_mod_bound, mod_pos_pos_trivial, |
|
688 |
neg_mod_sign, neg_mod_bound, mod_neg_neg_trivial])); |
|
6992 | 689 |
qed "mod_mod_trivial"; |
690 |
Addsimps [mod_mod_trivial]; |
|
691 |
||
9509 | 692 |
Goal "(a+b) mod (c::int) = ((a mod c) + b) mod c"; |
693 |
by (rtac (trans RS sym) 1); |
|
694 |
by (rtac zmod_zadd1_eq 1); |
|
695 |
by (Simp_tac 1); |
|
696 |
by (rtac (zmod_zadd1_eq RS sym) 1); |
|
697 |
qed "zmod_zadd_left_eq"; |
|
698 |
||
699 |
Goal "(a+b) mod (c::int) = (a + (b mod c)) mod c"; |
|
700 |
by (rtac (trans RS sym) 1); |
|
701 |
by (rtac zmod_zadd1_eq 1); |
|
702 |
by (Simp_tac 1); |
|
703 |
by (rtac (zmod_zadd1_eq RS sym) 1); |
|
704 |
qed "zmod_zadd_right_eq"; |
|
705 |
||
6992 | 706 |
|
707 |
Goal "a ~= (#0::int) ==> (a+b) div a = b div a + #1"; |
|
708 |
by (asm_simp_tac (simpset() addsimps [zdiv_zadd1_eq]) 1); |
|
709 |
qed "zdiv_zadd_self1"; |
|
710 |
||
711 |
Goal "a ~= (#0::int) ==> (b+a) div a = b div a + #1"; |
|
712 |
by (asm_simp_tac (simpset() addsimps [zdiv_zadd1_eq]) 1); |
|
713 |
qed "zdiv_zadd_self2"; |
|
714 |
Addsimps [zdiv_zadd_self1, zdiv_zadd_self2]; |
|
715 |
||
716 |
Goal "(a+b) mod a = b mod (a::int)"; |
|
7035 | 717 |
by (zdiv_undefined_case_tac "a = #0" 1); |
6992 | 718 |
by (asm_simp_tac (simpset() addsimps [zmod_zadd1_eq]) 1); |
719 |
qed "zmod_zadd_self1"; |
|
720 |
||
721 |
Goal "(b+a) mod a = b mod (a::int)"; |
|
7035 | 722 |
by (zdiv_undefined_case_tac "a = #0" 1); |
6992 | 723 |
by (asm_simp_tac (simpset() addsimps [zmod_zadd1_eq]) 1); |
724 |
qed "zmod_zadd_self2"; |
|
725 |
Addsimps [zmod_zadd_self1, zmod_zadd_self2]; |
|
726 |
||
727 |
||
728 |
(*** proving a div (b*c) = (a div b) div c ***) |
|
729 |
||
730 |
(*The condition c>0 seems necessary. Consider that 7 div ~6 = ~2 but |
|
731 |
7 div 2 div ~3 = 3 div ~3 = ~1. The subcase (a div b) mod c = 0 seems |
|
732 |
to cause particular problems.*) |
|
733 |
||
734 |
(** first, four lemmas to bound the remainder for the cases b<0 and b>0 **) |
|
6917 | 735 |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
736 |
Goal "[| (#0::int) < c; b < r; r <= #0 |] ==> b*c < b*(q mod c) + r"; |
6992 | 737 |
by (subgoal_tac "b * (c - q mod c) < r * #1" 1); |
738 |
by (asm_full_simp_tac (simpset() addsimps [zdiff_zmult_distrib2]) 1); |
|
739 |
by (rtac order_le_less_trans 1); |
|
740 |
by (etac zmult_zless_mono1 2); |
|
741 |
by (rtac zmult_zle_mono2_neg 1); |
|
742 |
by (auto_tac |
|
743 |
(claset(), |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
744 |
simpset() addsimps zcompare_rls@ |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
745 |
[zadd_commute, add1_zle_eq, pos_mod_bound])); |
6992 | 746 |
val lemma1 = result(); |
747 |
||
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
748 |
Goal "[| (#0::int) < c; b < r; r <= #0 |] ==> b * (q mod c) + r <= #0"; |
6992 | 749 |
by (subgoal_tac "b * (q mod c) <= #0" 1); |
750 |
by (arith_tac 1); |
|
9063 | 751 |
by (asm_simp_tac (simpset() addsimps [zmult_le_0_iff, pos_mod_sign]) 1); |
6992 | 752 |
val lemma2 = result(); |
753 |
||
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
754 |
Goal "[| (#0::int) < c; #0 <= r; r < b |] ==> #0 <= b * (q mod c) + r"; |
6992 | 755 |
by (subgoal_tac "#0 <= b * (q mod c)" 1); |
756 |
by (arith_tac 1); |
|
9063 | 757 |
by (asm_simp_tac (simpset() addsimps [int_0_le_mult_iff, pos_mod_sign]) 1); |
6992 | 758 |
val lemma3 = result(); |
759 |
||
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
760 |
Goal "[| (#0::int) < c; #0 <= r; r < b |] ==> b * (q mod c) + r < b * c"; |
6992 | 761 |
by (subgoal_tac "r * #1 < b * (c - q mod c)" 1); |
762 |
by (asm_full_simp_tac (simpset() addsimps [zdiff_zmult_distrib2]) 1); |
|
763 |
by (rtac order_less_le_trans 1); |
|
764 |
by (etac zmult_zless_mono1 1); |
|
765 |
by (rtac zmult_zle_mono2 2); |
|
766 |
by (auto_tac |
|
767 |
(claset(), |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
768 |
simpset() addsimps zcompare_rls@ |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
769 |
[zadd_commute, add1_zle_eq, pos_mod_bound])); |
6992 | 770 |
val lemma4 = result(); |
771 |
||
772 |
Goal "[| quorem ((a,b), (q,r)); b ~= #0; #0 < c |] \ |
|
773 |
\ ==> quorem ((a, b*c), (q div c, b*(q mod c) + r))"; |
|
8918 | 774 |
by (auto_tac |
6992 | 775 |
(claset(), |
8918 | 776 |
simpset() addsimps zmult_ac@ |
777 |
[zmod_zdiv_equality, quorem_def, linorder_neq_iff, |
|
9063 | 778 |
int_0_less_mult_iff, |
6992 | 779 |
zadd_zmult_distrib2 RS sym, |
780 |
lemma1, lemma2, lemma3, lemma4])); |
|
781 |
val lemma = result(); |
|
782 |
||
783 |
Goal "(#0::int) < c ==> a div (b*c) = (a div b) div c"; |
|
7035 | 784 |
by (zdiv_undefined_case_tac "b = #0" 1); |
6992 | 785 |
by (force_tac (claset(), |
786 |
simpset() addsimps [quorem_div_mod RS lemma RS quorem_div, |
|
787 |
zmult_eq_0_iff]) 1); |
|
788 |
qed "zdiv_zmult2_eq"; |
|
6917 | 789 |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
790 |
Goal "(#0::int) < c ==> a mod (b*c) = b*(a div b mod c) + a mod b"; |
7035 | 791 |
by (zdiv_undefined_case_tac "b = #0" 1); |
6992 | 792 |
by (force_tac (claset(), |
793 |
simpset() addsimps [quorem_div_mod RS lemma RS quorem_mod, |
|
794 |
zmult_eq_0_iff]) 1); |
|
795 |
qed "zmod_zmult2_eq"; |
|
796 |
||
797 |
||
798 |
(*** Cancellation of common factors in "div" ***) |
|
799 |
||
800 |
Goal "[| (#0::int) < b; c ~= #0 |] ==> (c*a) div (c*b) = a div b"; |
|
801 |
by (stac zdiv_zmult2_eq 1); |
|
802 |
by Auto_tac; |
|
803 |
val lemma1 = result(); |
|
804 |
||
805 |
Goal "[| b < (#0::int); c ~= #0 |] ==> (c*a) div (c*b) = a div b"; |
|
7127
48e235179ffb
added parentheses to cope with a possible reduction of the precedence of unary
paulson
parents:
7086
diff
changeset
|
806 |
by (subgoal_tac "(c * (-a)) div (c * (-b)) = (-a) div (-b)" 1); |
6992 | 807 |
by (rtac lemma1 2); |
8918 | 808 |
by Auto_tac; |
6992 | 809 |
val lemma2 = result(); |
810 |
||
811 |
Goal "c ~= (#0::int) ==> (c*a) div (c*b) = a div b"; |
|
7035 | 812 |
by (zdiv_undefined_case_tac "b = #0" 1); |
6992 | 813 |
by (auto_tac |
814 |
(claset(), |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
815 |
simpset() addsimps [read_instantiate [("x", "b")] linorder_neq_iff, |
6992 | 816 |
lemma1, lemma2])); |
817 |
qed "zdiv_zmult_zmult1"; |
|
6917 | 818 |
|
6992 | 819 |
Goal "c ~= (#0::int) ==> (a*c) div (b*c) = a div b"; |
820 |
by (dtac zdiv_zmult_zmult1 1); |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
821 |
by (auto_tac (claset(), simpset() addsimps [zmult_commute])); |
6992 | 822 |
qed "zdiv_zmult_zmult2"; |
823 |
||
824 |
||
825 |
||
826 |
(*** Distribution of factors over "mod" ***) |
|
827 |
||
828 |
Goal "[| (#0::int) < b; c ~= #0 |] ==> (c*a) mod (c*b) = c * (a mod b)"; |
|
829 |
by (stac zmod_zmult2_eq 1); |
|
830 |
by Auto_tac; |
|
831 |
val lemma1 = result(); |
|
832 |
||
833 |
Goal "[| b < (#0::int); c ~= #0 |] ==> (c*a) mod (c*b) = c * (a mod b)"; |
|
7127
48e235179ffb
added parentheses to cope with a possible reduction of the precedence of unary
paulson
parents:
7086
diff
changeset
|
834 |
by (subgoal_tac "(c * (-a)) mod (c * (-b)) = c * ((-a) mod (-b))" 1); |
6992 | 835 |
by (rtac lemma1 2); |
8918 | 836 |
by Auto_tac; |
6992 | 837 |
val lemma2 = result(); |
838 |
||
6999 | 839 |
Goal "(c*a) mod (c*b) = (c::int) * (a mod b)"; |
7035 | 840 |
by (zdiv_undefined_case_tac "b = #0" 1); |
841 |
by (zdiv_undefined_case_tac "c = #0" 1); |
|
6992 | 842 |
by (auto_tac |
843 |
(claset(), |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
844 |
simpset() addsimps [read_instantiate [("x", "b")] linorder_neq_iff, |
6992 | 845 |
lemma1, lemma2])); |
846 |
qed "zmod_zmult_zmult1"; |
|
847 |
||
6999 | 848 |
Goal "(a*c) mod (b*c) = (a mod b) * (c::int)"; |
849 |
by (cut_inst_tac [("c","c")] zmod_zmult_zmult1 1); |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
850 |
by (auto_tac (claset(), simpset() addsimps [zmult_commute])); |
6992 | 851 |
qed "zmod_zmult_zmult2"; |
852 |
||
853 |
||
6999 | 854 |
(*** Speeding up the division algorithm with shifting ***) |
6992 | 855 |
|
7035 | 856 |
(** computing "div" by shifting **) |
6999 | 857 |
|
858 |
Goal "(#0::int) <= a ==> (#1 + #2*b) div (#2*a) = b div a"; |
|
7035 | 859 |
by (zdiv_undefined_case_tac "a = #0" 1); |
6999 | 860 |
by (subgoal_tac "#1 <= a" 1); |
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
861 |
by (arith_tac 2); |
6999 | 862 |
by (subgoal_tac "#1 < a * #2" 1); |
8785 | 863 |
by (arith_tac 2); |
6999 | 864 |
by (subgoal_tac "#2*(#1 + b mod a) <= #2*a" 1); |
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
865 |
by (rtac zmult_zle_mono2 2); |
6999 | 866 |
by (auto_tac (claset(), |
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
867 |
simpset() addsimps [zadd_commute, zmult_commute, |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
868 |
add1_zle_eq, pos_mod_bound])); |
6999 | 869 |
by (stac zdiv_zadd1_eq 1); |
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
870 |
by (asm_simp_tac (simpset() addsimps [zdiv_zmult_zmult2, zmod_zmult_zmult2, |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
871 |
div_pos_pos_trivial]) 1); |
6999 | 872 |
by (stac div_pos_pos_trivial 1); |
8765
1bc30ff5fc54
[Int_CC.sum_conv, Int_CC.rel_conv] no longer exist
paulson
parents:
8624
diff
changeset
|
873 |
by (asm_simp_tac (simpset() |
8918 | 874 |
addsimps [mod_pos_pos_trivial, |
7549 | 875 |
pos_mod_sign RS zadd_zle_mono1 RSN (2,order_trans)]) 1); |
6999 | 876 |
by (auto_tac (claset(), |
877 |
simpset() addsimps [mod_pos_pos_trivial])); |
|
8785 | 878 |
by (subgoal_tac "#0 <= b mod a" 1); |
879 |
by (asm_simp_tac (simpset() addsimps [pos_mod_sign]) 2); |
|
880 |
by (arith_tac 1); |
|
9063 | 881 |
qed "pos_zdiv_mult_2"; |
6999 | 882 |
|
883 |
||
884 |
Goal "a <= (#0::int) ==> (#1 + #2*b) div (#2*a) = (b+#1) div a"; |
|
7127
48e235179ffb
added parentheses to cope with a possible reduction of the precedence of unary
paulson
parents:
7086
diff
changeset
|
885 |
by (subgoal_tac "(#1 + #2*(-b-#1)) div (#2 * (-a)) = (-b-#1) div (-a)" 1); |
9063 | 886 |
by (rtac pos_zdiv_mult_2 2); |
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
887 |
by (auto_tac (claset(), |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
888 |
simpset() addsimps [zmult_zminus_right])); |
7127
48e235179ffb
added parentheses to cope with a possible reduction of the precedence of unary
paulson
parents:
7086
diff
changeset
|
889 |
by (subgoal_tac "(#-1 - (#2 * b)) = - (#1 + (#2 * b))" 1); |
6999 | 890 |
by (Simp_tac 2); |
891 |
by (asm_full_simp_tac (HOL_ss |
|
892 |
addsimps [zdiv_zminus_zminus, zdiff_def, |
|
893 |
zminus_zadd_distrib RS sym]) 1); |
|
9063 | 894 |
qed "neg_zdiv_mult_2"; |
6999 | 895 |
|
896 |
||
897 |
(*Not clear why this must be proved separately; probably number_of causes |
|
898 |
simplification problems*) |
|
899 |
Goal "~ #0 <= x ==> x <= (#0::int)"; |
|
7035 | 900 |
by Auto_tac; |
6999 | 901 |
val lemma = result(); |
902 |
||
903 |
Goal "number_of (v BIT b) div number_of (w BIT False) = \ |
|
904 |
\ (if ~b | (#0::int) <= number_of w \ |
|
905 |
\ then number_of v div (number_of w) \ |
|
906 |
\ else (number_of v + (#1::int)) div (number_of w))"; |
|
9422 | 907 |
by (simp_tac (simpset_of Int.thy addsimps [zadd_assoc, number_of_BIT]) 1); |
7035 | 908 |
by (asm_simp_tac (simpset() |
7549 | 909 |
delsimps bin_arith_extra_simps@bin_rel_simps |
8787 | 910 |
addsimps [zdiv_zmult_zmult1, |
9063 | 911 |
pos_zdiv_mult_2, lemma, neg_zdiv_mult_2]) 1); |
6999 | 912 |
qed "zdiv_number_of_BIT"; |
913 |
||
914 |
Addsimps [zdiv_number_of_BIT]; |
|
915 |
||
916 |
||
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
917 |
(** computing "mod" by shifting (proofs resemble those for "div") **) |
7035 | 918 |
|
919 |
Goal "(#0::int) <= a ==> (#1 + #2*b) mod (#2*a) = #1 + #2 * (b mod a)"; |
|
920 |
by (zdiv_undefined_case_tac "a = #0" 1); |
|
921 |
by (subgoal_tac "#1 <= a" 1); |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
922 |
by (arith_tac 2); |
7035 | 923 |
by (subgoal_tac "#1 < a * #2" 1); |
8785 | 924 |
by (arith_tac 2); |
7035 | 925 |
by (subgoal_tac "#2*(#1 + b mod a) <= #2*a" 1); |
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
926 |
by (rtac zmult_zle_mono2 2); |
7035 | 927 |
by (auto_tac (claset(), |
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
928 |
simpset() addsimps [zadd_commute, zmult_commute, |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
929 |
add1_zle_eq, pos_mod_bound])); |
7035 | 930 |
by (stac zmod_zadd1_eq 1); |
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
931 |
by (asm_simp_tac (simpset() addsimps [zmod_zmult_zmult2, |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
932 |
mod_pos_pos_trivial]) 1); |
7035 | 933 |
by (rtac mod_pos_pos_trivial 1); |
8765
1bc30ff5fc54
[Int_CC.sum_conv, Int_CC.rel_conv] no longer exist
paulson
parents:
8624
diff
changeset
|
934 |
by (asm_simp_tac (simpset() |
8918 | 935 |
addsimps [mod_pos_pos_trivial, |
7549 | 936 |
pos_mod_sign RS zadd_zle_mono1 RSN (2,order_trans)]) 1); |
7035 | 937 |
by (auto_tac (claset(), |
938 |
simpset() addsimps [mod_pos_pos_trivial])); |
|
8785 | 939 |
by (subgoal_tac "#0 <= b mod a" 1); |
940 |
by (asm_simp_tac (simpset() addsimps [pos_mod_sign]) 2); |
|
941 |
by (arith_tac 1); |
|
9063 | 942 |
qed "pos_zmod_mult_2"; |
7035 | 943 |
|
944 |
||
945 |
Goal "a <= (#0::int) ==> (#1 + #2*b) mod (#2*a) = #2 * ((b+#1) mod a) - #1"; |
|
946 |
by (subgoal_tac |
|
7127
48e235179ffb
added parentheses to cope with a possible reduction of the precedence of unary
paulson
parents:
7086
diff
changeset
|
947 |
"(#1 + #2*(-b-#1)) mod (#2*(-a)) = #1 + #2*((-b-#1) mod (-a))" 1); |
9063 | 948 |
by (rtac pos_zmod_mult_2 2); |
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
949 |
by (auto_tac (claset(), |
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
950 |
simpset() addsimps [zmult_zminus_right])); |
7127
48e235179ffb
added parentheses to cope with a possible reduction of the precedence of unary
paulson
parents:
7086
diff
changeset
|
951 |
by (subgoal_tac "(#-1 - (#2 * b)) = - (#1 + (#2 * b))" 1); |
7035 | 952 |
by (Simp_tac 2); |
953 |
by (asm_full_simp_tac (HOL_ss |
|
954 |
addsimps [zmod_zminus_zminus, zdiff_def, |
|
955 |
zminus_zadd_distrib RS sym]) 1); |
|
7086 | 956 |
by (dtac (zminus_equation RS iffD1 RS sym) 1); |
8918 | 957 |
by Auto_tac; |
9063 | 958 |
qed "neg_zmod_mult_2"; |
7035 | 959 |
|
960 |
Goal "number_of (v BIT b) mod number_of (w BIT False) = \ |
|
961 |
\ (if b then \ |
|
962 |
\ if (#0::int) <= number_of w \ |
|
963 |
\ then #2 * (number_of v mod number_of w) + #1 \ |
|
964 |
\ else #2 * ((number_of v + (#1::int)) mod number_of w) - #1 \ |
|
965 |
\ else #2 * (number_of v mod number_of w))"; |
|
9422 | 966 |
by (simp_tac (simpset_of Int.thy addsimps [zadd_assoc, number_of_BIT]) 1); |
7035 | 967 |
by (asm_simp_tac (simpset() |
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
968 |
delsimps bin_arith_extra_simps@bin_rel_simps |
8787 | 969 |
addsimps [zmod_zmult_zmult1, |
9063 | 970 |
pos_zmod_mult_2, lemma, neg_zmod_mult_2]) 1); |
7035 | 971 |
qed "zmod_number_of_BIT"; |
972 |
||
973 |
Addsimps [zmod_number_of_BIT]; |
|
974 |
||
975 |
||
976 |
(** Quotients of signs **) |
|
977 |
||
978 |
Goal "[| a < (#0::int); #0 < b |] ==> a div b < #0"; |
|
979 |
by (subgoal_tac "a div b <= #-1" 1); |
|
980 |
by (Force_tac 1); |
|
981 |
by (rtac order_trans 1); |
|
982 |
by (res_inst_tac [("a'","#-1")] zdiv_mono1 1); |
|
7074
e0730ffaafcc
zadd_ac and zmult_ac are no longer included by default
paulson
parents:
7035
diff
changeset
|
983 |
by (auto_tac (claset(), simpset() addsimps [zdiv_minus1])); |
7127
48e235179ffb
added parentheses to cope with a possible reduction of the precedence of unary
paulson
parents:
7086
diff
changeset
|
984 |
qed "div_neg_pos_less0"; |
7035 | 985 |
|
986 |
Goal "[| (#0::int) <= a; b < #0 |] ==> a div b <= #0"; |
|
987 |
by (dtac zdiv_mono1_neg 1); |
|
988 |
by Auto_tac; |
|
7127
48e235179ffb
added parentheses to cope with a possible reduction of the precedence of unary
paulson
parents:
7086
diff
changeset
|
989 |
qed "div_nonneg_neg_le0"; |
7035 | 990 |
|
991 |
Goal "(#0::int) < b ==> (#0 <= a div b) = (#0 <= a)"; |
|
992 |
by Auto_tac; |
|
993 |
by (dtac zdiv_mono1 2); |
|
994 |
by (auto_tac (claset(), simpset() addsimps [linorder_neq_iff])); |
|
995 |
by (full_simp_tac (simpset() addsimps [linorder_not_less RS sym]) 1); |
|
7127
48e235179ffb
added parentheses to cope with a possible reduction of the precedence of unary
paulson
parents:
7086
diff
changeset
|
996 |
by (blast_tac (claset() addIs [div_neg_pos_less0]) 1); |
7035 | 997 |
qed "pos_imp_zdiv_nonneg_iff"; |
998 |
||
999 |
Goal "b < (#0::int) ==> (#0 <= a div b) = (a <= (#0::int))"; |
|
1000 |
by (stac (zdiv_zminus_zminus RS sym) 1); |
|
1001 |
by (stac pos_imp_zdiv_nonneg_iff 1); |
|
1002 |
by Auto_tac; |
|
1003 |
qed "neg_imp_zdiv_nonneg_iff"; |
|
1004 |
||
1005 |
(*But not (a div b <= 0 iff a<=0); consider a=1, b=2 when a div b = 0.*) |
|
1006 |
Goal "(#0::int) < b ==> (a div b < #0) = (a < #0)"; |
|
1007 |
by (asm_simp_tac (simpset() addsimps [linorder_not_le RS sym, |
|
1008 |
pos_imp_zdiv_nonneg_iff]) 1); |
|
1009 |
qed "pos_imp_zdiv_neg_iff"; |
|
1010 |
||
1011 |
(*Again the law fails for <=: consider a = -1, b = -2 when a div b = 0*) |
|
1012 |
Goal "b < (#0::int) ==> (a div b < #0) = (#0 < a)"; |
|
1013 |
by (asm_simp_tac (simpset() addsimps [linorder_not_le RS sym, |
|
1014 |
neg_imp_zdiv_nonneg_iff]) 1); |
|
1015 |
qed "neg_imp_zdiv_neg_iff"; |