src/HOL/Divides.ML
author oheimb
Wed Jan 31 10:15:55 2001 +0100 (2001-01-31)
changeset 11008 f7333f055ef6
parent 10964 afc1dfc5a92d
child 11313 04c8da2e0917
permissions -rw-r--r--
improved theory reference in comment
paulson@3366
     1
(*  Title:      HOL/Divides.ML
paulson@3366
     2
    ID:         $Id$
paulson@3366
     3
    Author:     Lawrence C Paulson, Cambridge University Computer Laboratory
paulson@3366
     4
    Copyright   1993  University of Cambridge
paulson@3366
     5
paulson@3366
     6
The division operators div, mod and the divides relation "dvd"
paulson@3366
     7
*)
paulson@3366
     8
paulson@3366
     9
paulson@3366
    10
(** Less-then properties **)
paulson@3366
    11
wenzelm@9108
    12
bind_thm ("wf_less_trans", [eq_reflection, wf_pred_nat RS wf_trancl] MRS 
wenzelm@9108
    13
                    def_wfrec RS trans);
paulson@3366
    14
wenzelm@5069
    15
Goal "(%m. m mod n) = wfrec (trancl pred_nat) \
paulson@7029
    16
\                           (%f j. if j<n | n=0 then j else f (j-n))";
wenzelm@4089
    17
by (simp_tac (simpset() addsimps [mod_def]) 1);
paulson@3366
    18
qed "mod_eq";
paulson@3366
    19
paulson@7029
    20
Goal "(%m. m div n) = wfrec (trancl pred_nat) \
paulson@7029
    21
\            (%f j. if j<n | n=0 then 0 else Suc (f (j-n)))";
paulson@7029
    22
by (simp_tac (simpset() addsimps [div_def]) 1);
paulson@7029
    23
qed "div_eq";
paulson@7029
    24
paulson@7029
    25
paulson@7029
    26
(** Aribtrary definitions for division by zero.  Useful to simplify 
paulson@7029
    27
    certain equations **)
paulson@7029
    28
paulson@8935
    29
Goal "a div 0 = (0::nat)";
paulson@7029
    30
by (rtac (div_eq RS wf_less_trans) 1);
paulson@7029
    31
by (Asm_simp_tac 1);
paulson@7029
    32
qed "DIVISION_BY_ZERO_DIV";  (*NOT for adding to default simpset*)
paulson@7029
    33
paulson@8935
    34
Goal "a mod 0 = (a::nat)";
paulson@7029
    35
by (rtac (mod_eq RS wf_less_trans) 1);
paulson@7029
    36
by (Asm_simp_tac 1);
paulson@7029
    37
qed "DIVISION_BY_ZERO_MOD";  (*NOT for adding to default simpset*)
paulson@7029
    38
paulson@7029
    39
fun div_undefined_case_tac s i =
paulson@7029
    40
  case_tac s i THEN 
paulson@7029
    41
  Full_simp_tac (i+1) THEN
paulson@7029
    42
  asm_simp_tac (simpset() addsimps [DIVISION_BY_ZERO_DIV, 
paulson@7029
    43
				    DIVISION_BY_ZERO_MOD]) i;
paulson@7029
    44
paulson@7029
    45
(*** Remainder ***)
paulson@7029
    46
paulson@6865
    47
Goal "m<n ==> m mod n = (m::nat)";
paulson@3366
    48
by (rtac (mod_eq RS wf_less_trans) 1);
paulson@3366
    49
by (Asm_simp_tac 1);
paulson@3366
    50
qed "mod_less";
paulson@8393
    51
Addsimps [mod_less];
paulson@3366
    52
paulson@7029
    53
Goal "~ m < (n::nat) ==> m mod n = (m-n) mod n";
paulson@7029
    54
by (div_undefined_case_tac "n=0" 1);
paulson@3366
    55
by (rtac (mod_eq RS wf_less_trans) 1);
wenzelm@4089
    56
by (asm_simp_tac (simpset() addsimps [diff_less, cut_apply, less_eq]) 1);
paulson@3366
    57
qed "mod_geq";
paulson@3366
    58
paulson@5415
    59
(*Avoids the ugly ~m<n above*)
paulson@7029
    60
Goal "(n::nat) <= m ==> m mod n = (m-n) mod n";
paulson@5415
    61
by (asm_simp_tac (simpset() addsimps [mod_geq, not_less_iff_le]) 1);
paulson@5415
    62
qed "le_mod_geq";
paulson@5415
    63
paulson@7029
    64
Goal "m mod (n::nat) = (if m<n then m else (m-n) mod n)";
paulson@8393
    65
by (asm_simp_tac (simpset() addsimps [mod_geq]) 1);
paulson@4774
    66
qed "mod_if";
paulson@4774
    67
paulson@8935
    68
Goal "m mod 1 = (0::nat)";
paulson@3366
    69
by (induct_tac "m" 1);
paulson@8393
    70
by (ALLGOALS (asm_simp_tac (simpset() addsimps [mod_geq])));
paulson@3366
    71
qed "mod_1";
paulson@3366
    72
Addsimps [mod_1];
paulson@3366
    73
paulson@8935
    74
Goal "n mod n = (0::nat)";
paulson@7029
    75
by (div_undefined_case_tac "n=0" 1);
paulson@8393
    76
by (asm_simp_tac (simpset() addsimps [mod_geq]) 1);
paulson@3366
    77
qed "mod_self";
paulson@10559
    78
Addsimps [mod_self];
paulson@3366
    79
paulson@7029
    80
Goal "(m+n) mod n = m mod (n::nat)";
paulson@3366
    81
by (subgoal_tac "(n + m) mod n = (n+m-n) mod n" 1);
paulson@3366
    82
by (stac (mod_geq RS sym) 2);
wenzelm@4089
    83
by (ALLGOALS (asm_full_simp_tac (simpset() addsimps [add_commute])));
paulson@4811
    84
qed "mod_add_self2";
paulson@4810
    85
paulson@7029
    86
Goal "(n+m) mod n = m mod (n::nat)";
paulson@4811
    87
by (asm_simp_tac (simpset() addsimps [add_commute, mod_add_self2]) 1);
paulson@4811
    88
qed "mod_add_self1";
paulson@4810
    89
paulson@8783
    90
Addsimps [mod_add_self1, mod_add_self2];
paulson@8783
    91
paulson@7029
    92
Goal "(m + k*n) mod n = m mod (n::nat)";
paulson@4810
    93
by (induct_tac "k" 1);
paulson@7029
    94
by (ALLGOALS
paulson@7029
    95
    (asm_simp_tac 
paulson@8783
    96
     (simpset() addsimps [read_instantiate [("y","n")] add_left_commute])));
paulson@4811
    97
qed "mod_mult_self1";
paulson@4810
    98
paulson@7029
    99
Goal "(m + n*k) mod n = m mod (n::nat)";
paulson@4811
   100
by (asm_simp_tac (simpset() addsimps [mult_commute, mod_mult_self1]) 1);
paulson@4811
   101
qed "mod_mult_self2";
paulson@4810
   102
paulson@4811
   103
Addsimps [mod_mult_self1, mod_mult_self2];
paulson@3366
   104
paulson@7029
   105
Goal "(m mod n) * (k::nat) = (m*k) mod (n*k)";
paulson@7029
   106
by (div_undefined_case_tac "n=0" 1);
paulson@7029
   107
by (div_undefined_case_tac "k=0" 1);
nipkow@9870
   108
by (induct_thm_tac nat_less_induct "m" 1);
paulson@4774
   109
by (stac mod_if 1);
paulson@4774
   110
by (Asm_simp_tac 1);
paulson@8393
   111
by (asm_simp_tac (simpset() addsimps [mod_geq, 
paulson@4774
   112
				      diff_less, diff_mult_distrib]) 1);
paulson@3366
   113
qed "mod_mult_distrib";
paulson@3366
   114
paulson@7029
   115
Goal "(k::nat) * (m mod n) = (k*m) mod (k*n)";
paulson@7029
   116
by (asm_simp_tac 
paulson@7029
   117
    (simpset() addsimps [read_instantiate [("m","k")] mult_commute, 
paulson@7029
   118
			 mod_mult_distrib]) 1);
paulson@3366
   119
qed "mod_mult_distrib2";
paulson@3366
   120
paulson@8935
   121
Goal "(m*n) mod n = (0::nat)";
paulson@7029
   122
by (div_undefined_case_tac "n=0" 1);
paulson@3366
   123
by (induct_tac "m" 1);
paulson@8393
   124
by (Asm_simp_tac 1);
paulson@7029
   125
by (rename_tac "k" 1);
paulson@7029
   126
by (cut_inst_tac [("m","k*n"),("n","n")] mod_add_self2 1);
wenzelm@4089
   127
by (asm_full_simp_tac (simpset() addsimps [add_commute]) 1);
paulson@3366
   128
qed "mod_mult_self_is_0";
paulson@7082
   129
paulson@8935
   130
Goal "(n*m) mod n = (0::nat)";
paulson@7082
   131
by (simp_tac (simpset() addsimps [mult_commute, mod_mult_self_is_0]) 1);
paulson@7082
   132
qed "mod_mult_self1_is_0";
paulson@7082
   133
Addsimps [mod_mult_self_is_0, mod_mult_self1_is_0];
paulson@3366
   134
paulson@7029
   135
paulson@3366
   136
(*** Quotient ***)
paulson@3366
   137
paulson@8935
   138
Goal "m<n ==> m div n = (0::nat)";
paulson@3366
   139
by (rtac (div_eq RS wf_less_trans) 1);
paulson@3366
   140
by (Asm_simp_tac 1);
paulson@3366
   141
qed "div_less";
paulson@8393
   142
Addsimps [div_less];
paulson@3366
   143
paulson@5143
   144
Goal "[| 0<n;  ~m<n |] ==> m div n = Suc((m-n) div n)";
paulson@3366
   145
by (rtac (div_eq RS wf_less_trans) 1);
wenzelm@4089
   146
by (asm_simp_tac (simpset() addsimps [diff_less, cut_apply, less_eq]) 1);
paulson@3366
   147
qed "div_geq";
paulson@3366
   148
paulson@5415
   149
(*Avoids the ugly ~m<n above*)
paulson@5415
   150
Goal "[| 0<n;  n<=m |] ==> m div n = Suc((m-n) div n)";
paulson@5415
   151
by (asm_simp_tac (simpset() addsimps [div_geq, not_less_iff_le]) 1);
paulson@5415
   152
qed "le_div_geq";
paulson@5415
   153
paulson@5143
   154
Goal "0<n ==> m div n = (if m<n then 0 else Suc((m-n) div n))";
paulson@8393
   155
by (asm_simp_tac (simpset() addsimps [div_geq]) 1);
paulson@4774
   156
qed "div_if";
paulson@4774
   157
paulson@7029
   158
paulson@3366
   159
(*Main Result about quotient and remainder.*)
paulson@7029
   160
Goal "(m div n)*n + m mod n = (m::nat)";
paulson@7029
   161
by (div_undefined_case_tac "n=0" 1);
nipkow@9870
   162
by (induct_thm_tac nat_less_induct "m" 1);
paulson@4774
   163
by (stac mod_if 1);
paulson@4774
   164
by (ALLGOALS (asm_simp_tac 
paulson@8393
   165
	      (simpset() addsimps [add_assoc, div_geq,
paulson@5537
   166
				   add_diff_inverse, diff_less])));
paulson@3366
   167
qed "mod_div_equality";
paulson@3366
   168
nipkow@4358
   169
(* a simple rearrangement of mod_div_equality: *)
paulson@7029
   170
Goal "(n::nat) * (m div n) = m - (m mod n)";
paulson@7029
   171
by (cut_inst_tac [("m","m"),("n","n")] mod_div_equality 1);
paulson@9912
   172
by (full_simp_tac (simpset() addsimps mult_ac) 1);
paulson@9912
   173
by (arith_tac 1);
nipkow@4358
   174
qed "mult_div_cancel";
nipkow@4358
   175
paulson@10559
   176
Goal "0<n ==> m mod n < (n::nat)";
paulson@10559
   177
by (induct_thm_tac nat_less_induct "m" 1);
paulson@10559
   178
by (case_tac "na<n" 1);
paulson@10559
   179
(*case n le na*)
paulson@10559
   180
by (asm_full_simp_tac (simpset() addsimps [mod_geq, diff_less]) 2);
paulson@10559
   181
(*case na<n*)
paulson@10559
   182
by (Asm_simp_tac 1);
paulson@10559
   183
qed "mod_less_divisor";
paulson@10559
   184
Addsimps [mod_less_divisor];
paulson@10559
   185
paulson@10559
   186
(*** More division laws ***)
paulson@10559
   187
paulson@10559
   188
Goal "0<n ==> (m*n) div n = (m::nat)";
paulson@10559
   189
by (cut_inst_tac [("m", "m*n"),("n","n")] mod_div_equality 1);
paulson@10559
   190
by Auto_tac;
paulson@10559
   191
qed "div_mult_self_is_m";
paulson@10559
   192
paulson@10559
   193
Goal "0<n ==> (n*m) div n = (m::nat)";
paulson@10559
   194
by (asm_simp_tac (simpset() addsimps [mult_commute, div_mult_self_is_m]) 1);
paulson@10559
   195
qed "div_mult_self1_is_m";
paulson@10559
   196
Addsimps [div_mult_self_is_m, div_mult_self1_is_m];
paulson@10559
   197
paulson@10559
   198
(*mod_mult_distrib2 above is the counterpart for remainder*)
paulson@10559
   199
paulson@10559
   200
paulson@10559
   201
(*** Proving facts about div and mod using quorem ***)
paulson@10559
   202
paulson@10559
   203
Goal "[| b*q' + r'  <= b*q + r;  0 < b;  r < b |] \
paulson@10559
   204
\     ==> q' <= (q::nat)";
paulson@10559
   205
by (rtac leI 1); 
paulson@10559
   206
by (stac less_iff_Suc_add 1);
paulson@10559
   207
by (auto_tac (claset(), simpset() addsimps [add_mult_distrib2]));   
paulson@10559
   208
qed "unique_quotient_lemma";
paulson@10559
   209
paulson@10559
   210
Goal "[| quorem ((a,b), (q,r));  quorem ((a,b), (q',r'));  0 < b |] \
paulson@10559
   211
\     ==> q = q'";
paulson@10559
   212
by (asm_full_simp_tac 
paulson@10600
   213
    (simpset() addsimps split_ifs @ [Divides.quorem_def]) 1);
paulson@10559
   214
by Auto_tac;  
paulson@10559
   215
by (REPEAT 
paulson@10559
   216
    (blast_tac (claset() addIs [order_antisym]
paulson@10559
   217
			 addDs [order_eq_refl RS unique_quotient_lemma, 
paulson@10559
   218
				sym]) 1));
paulson@10559
   219
qed "unique_quotient";
paulson@10559
   220
paulson@10559
   221
Goal "[| quorem ((a,b), (q,r));  quorem ((a,b), (q',r'));  0 < b |] \
paulson@10559
   222
\     ==> r = r'";
paulson@10559
   223
by (subgoal_tac "q = q'" 1);
paulson@10559
   224
by (blast_tac (claset() addIs [unique_quotient]) 2);
paulson@10600
   225
by (asm_full_simp_tac (simpset() addsimps [Divides.quorem_def]) 1);
paulson@10559
   226
qed "unique_remainder";
paulson@10559
   227
paulson@10559
   228
Goal "0 < b ==> quorem ((a, b), (a div b, a mod b))";
paulson@10559
   229
by (cut_inst_tac [("m","a"),("n","b")] mod_div_equality 1);
paulson@10559
   230
by (auto_tac
paulson@10559
   231
    (claset() addEs [sym],
paulson@10600
   232
     simpset() addsimps mult_ac@[Divides.quorem_def]));
paulson@10559
   233
qed "quorem_div_mod";
paulson@10559
   234
paulson@10559
   235
Goal "[| quorem((a,b),(q,r));  0 < b |] ==> a div b = q";
paulson@10559
   236
by (asm_simp_tac (simpset() addsimps [quorem_div_mod RS unique_quotient]) 1);
paulson@10559
   237
qed "quorem_div";
paulson@10559
   238
paulson@10559
   239
Goal "[| quorem((a,b),(q,r));  0 < b |] ==> a mod b = r";
paulson@10559
   240
by (asm_simp_tac (simpset() addsimps [quorem_div_mod RS unique_remainder]) 1);
paulson@10559
   241
qed "quorem_mod";
paulson@10559
   242
paulson@10600
   243
(** A dividend of zero **)
paulson@10600
   244
paulson@10600
   245
Goal "0 div m = (0::nat)";
paulson@10600
   246
by (div_undefined_case_tac "m=0" 1);
paulson@10600
   247
by (Asm_simp_tac 1);
paulson@10600
   248
qed "div_0"; 
paulson@10600
   249
paulson@10600
   250
Goal "0 mod m = (0::nat)";
paulson@10600
   251
by (div_undefined_case_tac "m=0" 1);
paulson@10600
   252
by (Asm_simp_tac 1);
paulson@10600
   253
qed "mod_0"; 
paulson@10600
   254
Addsimps [div_0, mod_0];
paulson@10600
   255
paulson@10559
   256
(** proving (a*b) div c = a * (b div c) + a * (b mod c) **)
paulson@10559
   257
paulson@10559
   258
Goal "[| quorem((b,c),(q,r));  0 < c |] \
paulson@10559
   259
\     ==> quorem ((a*b, c), (a*q + a*r div c, a*r mod c))";
paulson@10559
   260
by (cut_inst_tac [("m", "a*r"), ("n","c")] mod_div_equality 1);
paulson@10559
   261
by (auto_tac
paulson@10559
   262
    (claset(),
paulson@10559
   263
     simpset() addsimps split_ifs@mult_ac@
paulson@10600
   264
                        [Divides.quorem_def, add_mult_distrib2]));
paulson@10559
   265
val lemma = result();
paulson@10559
   266
paulson@10559
   267
Goal "(a*b) div c = a*(b div c) + a*(b mod c) div (c::nat)";
paulson@10559
   268
by (div_undefined_case_tac "c = 0" 1);
paulson@10559
   269
by (blast_tac (claset() addIs [quorem_div_mod RS lemma RS quorem_div]) 1);
paulson@10559
   270
qed "div_mult1_eq";
paulson@10559
   271
paulson@10559
   272
Goal "(a*b) mod c = a*(b mod c) mod (c::nat)";
paulson@10559
   273
by (div_undefined_case_tac "c = 0" 1);
paulson@10559
   274
by (blast_tac (claset() addIs [quorem_div_mod RS lemma RS quorem_mod]) 1);
paulson@10559
   275
qed "mod_mult1_eq";
paulson@10559
   276
paulson@10559
   277
Goal "(a*b) mod (c::nat) = ((a mod c) * b) mod c";
paulson@10559
   278
by (rtac trans 1);
paulson@10559
   279
by (res_inst_tac [("s","b*a mod c")] trans 1);
paulson@10559
   280
by (rtac mod_mult1_eq 2);
paulson@10559
   281
by (ALLGOALS (simp_tac (simpset() addsimps [mult_commute])));
paulson@10559
   282
qed "mod_mult1_eq'";
paulson@10559
   283
paulson@10559
   284
Goal "(a*b) mod (c::nat) = ((a mod c) * (b mod c)) mod c";
paulson@10559
   285
by (rtac (mod_mult1_eq' RS trans) 1);
paulson@10559
   286
by (rtac mod_mult1_eq 1);
paulson@10559
   287
qed "mod_mult_distrib_mod";
paulson@10559
   288
paulson@10559
   289
(** proving (a+b) div c = a div c + b div c + ((a mod c + b mod c) div c) **)
paulson@10559
   290
paulson@10559
   291
Goal "[| quorem((a,c),(aq,ar));  quorem((b,c),(bq,br));  0 < c |] \
paulson@10559
   292
\     ==> quorem ((a+b, c), (aq + bq + (ar+br) div c, (ar+br) mod c))";
paulson@10559
   293
by (cut_inst_tac [("m", "ar+br"), ("n","c")] mod_div_equality 1);
paulson@10559
   294
by (auto_tac
paulson@10559
   295
    (claset(),
paulson@10559
   296
     simpset() addsimps split_ifs@mult_ac@
paulson@10600
   297
                        [Divides.quorem_def, add_mult_distrib2]));
paulson@10559
   298
val lemma = result();
paulson@10559
   299
paulson@10559
   300
(*NOT suitable for rewriting: the RHS has an instance of the LHS*)
paulson@10559
   301
Goal "(a+b) div (c::nat) = a div c + b div c + ((a mod c + b mod c) div c)";
paulson@10559
   302
by (div_undefined_case_tac "c = 0" 1);
paulson@10559
   303
by (blast_tac (claset() addIs [[quorem_div_mod,quorem_div_mod]
paulson@10559
   304
			       MRS lemma RS quorem_div]) 1);
paulson@10559
   305
qed "div_add1_eq";
paulson@10559
   306
paulson@10559
   307
Goal "(a+b) mod (c::nat) = (a mod c + b mod c) mod c";
paulson@10559
   308
by (div_undefined_case_tac "c = 0" 1);
paulson@10559
   309
by (blast_tac (claset() addIs [[quorem_div_mod,quorem_div_mod]
paulson@10559
   310
			       MRS lemma RS quorem_mod]) 1);
paulson@10559
   311
qed "mod_add1_eq";
paulson@10559
   312
paulson@10559
   313
paulson@10559
   314
(*** proving  a div (b*c) = (a div b) div c ***)
paulson@10559
   315
paulson@10600
   316
(** first, a lemma to bound the remainder **)
paulson@10559
   317
paulson@10559
   318
Goal "[| (0::nat) < c; r < b |] ==> b * (q mod c) + r < b * c";
paulson@10559
   319
by (cut_inst_tac [("m","q"),("n","c")] mod_less_divisor 1);
paulson@10559
   320
by (dres_inst_tac [("m","q mod c")] less_imp_Suc_add 2); 
paulson@10559
   321
by Auto_tac;  
paulson@10559
   322
by (eres_inst_tac [("P","%x. ?lhs < ?rhs x")] ssubst 1); 
paulson@10559
   323
by (asm_simp_tac (simpset() addsimps [add_mult_distrib2]) 1);
paulson@10600
   324
val mod_lemma = result();
paulson@10559
   325
paulson@10559
   326
Goal "[| quorem ((a,b), (q,r));  0 < b;  0 < c |] \
paulson@10559
   327
\     ==> quorem ((a, b*c), (q div c, b*(q mod c) + r))";
paulson@10559
   328
by (cut_inst_tac [("m", "q"), ("n","c")] mod_div_equality 1);
paulson@10559
   329
by (auto_tac  
paulson@10559
   330
    (claset(),
paulson@10559
   331
     simpset() addsimps mult_ac@
paulson@10600
   332
                        [Divides.quorem_def, add_mult_distrib2 RS sym,
paulson@10600
   333
			 mod_lemma]));
paulson@10559
   334
val lemma = result();
paulson@10559
   335
paulson@10600
   336
Goal "a div (b*c) = (a div b) div (c::nat)";
paulson@10600
   337
by (div_undefined_case_tac "b=0" 1);
paulson@10600
   338
by (div_undefined_case_tac "c=0" 1);
paulson@10559
   339
by (force_tac (claset(),
paulson@10559
   340
	       simpset() addsimps [quorem_div_mod RS lemma RS quorem_div]) 1);
paulson@10559
   341
qed "div_mult2_eq";
paulson@10559
   342
paulson@10600
   343
Goal "a mod (b*c) = b*(a div b mod c) + a mod (b::nat)";
paulson@10600
   344
by (div_undefined_case_tac "b=0" 1);
paulson@10600
   345
by (div_undefined_case_tac "c=0" 1);
paulson@10600
   346
by (cut_inst_tac [("m", "a"), ("n","b")] mod_div_equality 1);
paulson@10600
   347
by (auto_tac (claset(),
paulson@10600
   348
	       simpset() addsimps [mult_commute, 
paulson@10600
   349
				   quorem_div_mod RS lemma RS quorem_mod]));
paulson@10559
   350
qed "mod_mult2_eq";
paulson@10559
   351
paulson@10559
   352
paulson@10559
   353
(*** Cancellation of common factors in "div" ***)
paulson@10559
   354
paulson@10559
   355
Goal "[| (0::nat) < b;  0 < c |] ==> (c*a) div (c*b) = a div b";
paulson@10559
   356
by (stac div_mult2_eq 1);
paulson@10559
   357
by Auto_tac;
paulson@10559
   358
val lemma1 = result();
paulson@10559
   359
paulson@10559
   360
Goal "(0::nat) < c ==> (c*a) div (c*b) = a div b";
paulson@10559
   361
by (div_undefined_case_tac "b = 0" 1);
paulson@10559
   362
by (auto_tac
paulson@10559
   363
    (claset(), 
paulson@10559
   364
     simpset() addsimps [read_instantiate [("x", "b")] linorder_neq_iff, 
paulson@10559
   365
			 lemma1, lemma2]));
paulson@10559
   366
qed "div_mult_mult1";
paulson@10559
   367
paulson@10559
   368
Goal "(0::nat) < c ==> (a*c) div (b*c) = a div b";
paulson@10559
   369
by (dtac div_mult_mult1 1);
paulson@10559
   370
by (auto_tac (claset(), simpset() addsimps [mult_commute]));
paulson@10559
   371
qed "div_mult_mult2";
paulson@10559
   372
paulson@10559
   373
Addsimps [div_mult_mult1, div_mult_mult2];
paulson@10559
   374
paulson@10559
   375
paulson@10559
   376
(*** Distribution of factors over "mod"
paulson@10559
   377
paulson@10559
   378
Could prove these as in Integ/IntDiv.ML, but we already have
paulson@10559
   379
mod_mult_distrib and mod_mult_distrib2 above!
paulson@10559
   380
paulson@10559
   381
Goal "(c*a) mod (c*b) = (c::nat) * (a mod b)";
paulson@10559
   382
qed "mod_mult_mult1";
paulson@10559
   383
paulson@10559
   384
Goal "(a*c) mod (b*c) = (a mod b) * (c::nat)";
paulson@10559
   385
qed "mod_mult_mult2";
paulson@10559
   386
 ***)
paulson@10559
   387
paulson@10559
   388
(*** Further facts about div and mod ***)
paulson@10559
   389
wenzelm@5069
   390
Goal "m div 1 = m";
paulson@3366
   391
by (induct_tac "m" 1);
paulson@8393
   392
by (ALLGOALS (asm_simp_tac (simpset() addsimps [div_geq])));
paulson@3366
   393
qed "div_1";
paulson@3366
   394
Addsimps [div_1];
paulson@3366
   395
paulson@8935
   396
Goal "0<n ==> n div n = (1::nat)";
paulson@8393
   397
by (asm_simp_tac (simpset() addsimps [div_geq]) 1);
paulson@3366
   398
qed "div_self";
paulson@10559
   399
Addsimps [div_self];
paulson@4811
   400
paulson@5143
   401
Goal "0<n ==> (m+n) div n = Suc (m div n)";
paulson@4811
   402
by (subgoal_tac "(n + m) div n = Suc ((n+m-n) div n)" 1);
paulson@4811
   403
by (stac (div_geq RS sym) 2);
paulson@4811
   404
by (ALLGOALS (asm_full_simp_tac (simpset() addsimps [add_commute])));
paulson@4811
   405
qed "div_add_self2";
paulson@4811
   406
paulson@5143
   407
Goal "0<n ==> (n+m) div n = Suc (m div n)";
paulson@4811
   408
by (asm_simp_tac (simpset() addsimps [add_commute, div_add_self2]) 1);
paulson@4811
   409
qed "div_add_self1";
paulson@4811
   410
paulson@8935
   411
Goal "!!n::nat. 0<n ==> (m + k*n) div n = k + m div n";
paulson@10559
   412
by (stac div_add1_eq 1); 
paulson@10559
   413
by (stac div_mult1_eq 1); 
paulson@10559
   414
by (Asm_simp_tac 1); 
paulson@4811
   415
qed "div_mult_self1";
paulson@4811
   416
paulson@8935
   417
Goal "0<n ==> (m + n*k) div n = k + m div (n::nat)";
paulson@4811
   418
by (asm_simp_tac (simpset() addsimps [mult_commute, div_mult_self1]) 1);
paulson@4811
   419
qed "div_mult_self2";
paulson@4811
   420
paulson@4811
   421
Addsimps [div_mult_self1, div_mult_self2];
paulson@4811
   422
nipkow@3484
   423
(* Monotonicity of div in first argument *)
paulson@7029
   424
Goal "ALL m::nat. m <= n --> (m div k) <= (n div k)";
paulson@7029
   425
by (div_undefined_case_tac "k=0" 1);
nipkow@9870
   426
by (induct_thm_tac nat_less_induct "n" 1);
paulson@3718
   427
by (Clarify_tac 1);
paulson@5143
   428
by (case_tac "n<k" 1);
nipkow@3484
   429
(* 1  case n<k *)
paulson@8393
   430
by (Asm_simp_tac 1);
nipkow@3484
   431
(* 2  case n >= k *)
nipkow@3484
   432
by (case_tac "m<k" 1);
nipkow@3484
   433
(* 2.1  case m<k *)
paulson@8393
   434
by (Asm_simp_tac 1);
nipkow@3484
   435
(* 2.2  case m>=k *)
wenzelm@4089
   436
by (asm_simp_tac (simpset() addsimps [div_geq, diff_less, diff_le_mono]) 1);
nipkow@3484
   437
qed_spec_mp "div_le_mono";
nipkow@3484
   438
nipkow@3484
   439
(* Antimonotonicity of div in second argument *)
paulson@8935
   440
Goal "!!m::nat. [| 0<m; m<=n |] ==> (k div n) <= (k div m)";
nipkow@3484
   441
by (subgoal_tac "0<n" 1);
nipkow@6073
   442
 by (Asm_simp_tac 2);
nipkow@9870
   443
by (induct_thm_tac nat_less_induct "k" 1);
paulson@3496
   444
by (rename_tac "k" 1);
nipkow@3484
   445
by (case_tac "k<n" 1);
paulson@8393
   446
 by (Asm_simp_tac 1);
nipkow@3484
   447
by (subgoal_tac "~(k<m)" 1);
nipkow@6073
   448
 by (Asm_simp_tac 2);
wenzelm@4089
   449
by (asm_simp_tac (simpset() addsimps [div_geq]) 1);
nipkow@3484
   450
by (subgoal_tac "(k-n) div n <= (k-m) div n" 1);
paulson@7029
   451
 by (REPEAT (ares_tac [div_le_mono,diff_le_mono2] 2));
paulson@5318
   452
by (rtac le_trans 1);
paulson@5316
   453
by (Asm_simp_tac 1);
paulson@5316
   454
by (asm_simp_tac (simpset() addsimps [diff_less]) 1);
nipkow@3484
   455
qed "div_le_mono2";
nipkow@3484
   456
paulson@7029
   457
Goal "m div n <= (m::nat)";
paulson@7029
   458
by (div_undefined_case_tac "n=0" 1);
nipkow@3484
   459
by (subgoal_tac "m div n <= m div 1" 1);
nipkow@3484
   460
by (Asm_full_simp_tac 1);
nipkow@3484
   461
by (rtac div_le_mono2 1);
nipkow@6073
   462
by (ALLGOALS Asm_simp_tac);
nipkow@3484
   463
qed "div_le_dividend";
nipkow@3484
   464
Addsimps [div_le_dividend];
nipkow@3484
   465
nipkow@3484
   466
(* Similar for "less than" *)
paulson@8935
   467
Goal "!!n::nat. 1<n ==> (0 < m) --> (m div n < m)";
nipkow@9870
   468
by (induct_thm_tac nat_less_induct "m" 1);
paulson@3496
   469
by (rename_tac "m" 1);
nipkow@3484
   470
by (case_tac "m<n" 1);
paulson@8393
   471
 by (Asm_full_simp_tac 1);
nipkow@3484
   472
by (subgoal_tac "0<n" 1);
nipkow@6073
   473
 by (Asm_simp_tac 2);
wenzelm@4089
   474
by (asm_full_simp_tac (simpset() addsimps [div_geq]) 1);
nipkow@3484
   475
by (case_tac "n<m" 1);
nipkow@3484
   476
 by (subgoal_tac "(m-n) div n < (m-n)" 1);
nipkow@3484
   477
  by (REPEAT (ares_tac [impI,less_trans_Suc] 1));
wenzelm@4089
   478
  by (asm_full_simp_tac (simpset() addsimps [diff_less]) 1);
wenzelm@4089
   479
 by (asm_full_simp_tac (simpset() addsimps [diff_less]) 1);
nipkow@3484
   480
(* case n=m *)
nipkow@3484
   481
by (subgoal_tac "m=n" 1);
nipkow@6073
   482
 by (Asm_simp_tac 2);
paulson@8393
   483
by (Asm_simp_tac 1);
nipkow@3484
   484
qed_spec_mp "div_less_dividend";
nipkow@3484
   485
Addsimps [div_less_dividend];
paulson@3366
   486
paulson@3366
   487
(*** Further facts about mod (mainly for the mutilated chess board ***)
paulson@3366
   488
paulson@10964
   489
Goal "Suc(m) mod n = (if Suc(m mod n) = n then 0 else Suc(m mod n))";
paulson@10964
   490
by (div_undefined_case_tac "n=0" 1);
nipkow@9870
   491
by (induct_thm_tac nat_less_induct "m" 1);
paulson@8860
   492
by (case_tac "Suc(na)<n" 1);
paulson@3366
   493
(* case Suc(na) < n *)
paulson@8860
   494
by (forward_tac [lessI RS less_trans] 1 
paulson@8860
   495
    THEN asm_simp_tac (simpset() addsimps [less_not_refl3]) 1);
paulson@3366
   496
(* case n <= Suc(na) *)
paulson@5415
   497
by (asm_full_simp_tac (simpset() addsimps [not_less_iff_le, le_Suc_eq, 
paulson@5415
   498
					   mod_geq]) 1);
paulson@8860
   499
by (auto_tac (claset(), 
paulson@8860
   500
	      simpset() addsimps [Suc_diff_le, diff_less, le_mod_geq]));
paulson@3366
   501
qed "mod_Suc";
paulson@3366
   502
paulson@3366
   503
paulson@3366
   504
(************************************************)
paulson@3366
   505
(** Divides Relation                           **)
paulson@3366
   506
(************************************************)
paulson@3366
   507
paulson@8935
   508
Goalw [dvd_def] "m dvd (0::nat)";
wenzelm@4089
   509
by (blast_tac (claset() addIs [mult_0_right RS sym]) 1);
paulson@3366
   510
qed "dvd_0_right";
paulson@7029
   511
AddIffs [dvd_0_right];
paulson@3366
   512
paulson@8935
   513
Goalw [dvd_def] "0 dvd m ==> m = (0::nat)";
paulson@6865
   514
by Auto_tac;
paulson@3366
   515
qed "dvd_0_left";
paulson@3366
   516
paulson@8935
   517
Goalw [dvd_def] "1 dvd (k::nat)";
paulson@3366
   518
by (Simp_tac 1);
paulson@3366
   519
qed "dvd_1_left";
paulson@3366
   520
AddIffs [dvd_1_left];
paulson@3366
   521
paulson@6865
   522
Goalw [dvd_def] "m dvd (m::nat)";
wenzelm@4089
   523
by (blast_tac (claset() addIs [mult_1_right RS sym]) 1);
paulson@3366
   524
qed "dvd_refl";
paulson@3366
   525
Addsimps [dvd_refl];
paulson@3366
   526
paulson@6865
   527
Goalw [dvd_def] "[| m dvd n; n dvd p |] ==> m dvd (p::nat)";
wenzelm@4089
   528
by (blast_tac (claset() addIs [mult_assoc] ) 1);
paulson@3366
   529
qed "dvd_trans";
paulson@3366
   530
paulson@6865
   531
Goalw [dvd_def] "[| m dvd n; n dvd m |] ==> m = (n::nat)";
paulson@6865
   532
by (force_tac (claset() addDs [mult_eq_self_implies_10],
paulson@6865
   533
	       simpset() addsimps [mult_assoc, mult_eq_1_iff]) 1);
paulson@3366
   534
qed "dvd_anti_sym";
paulson@3366
   535
paulson@6865
   536
Goalw [dvd_def] "[| k dvd m; k dvd n |] ==> k dvd (m+n :: nat)";
wenzelm@4089
   537
by (blast_tac (claset() addIs [add_mult_distrib2 RS sym]) 1);
paulson@3366
   538
qed "dvd_add";
paulson@3366
   539
paulson@6865
   540
Goalw [dvd_def] "[| k dvd m; k dvd n |] ==> k dvd (m-n :: nat)";
wenzelm@4089
   541
by (blast_tac (claset() addIs [diff_mult_distrib2 RS sym]) 1);
paulson@3366
   542
qed "dvd_diff";
paulson@3366
   543
nipkow@10789
   544
Goal "[| k dvd m-n; k dvd n; n<=m |] ==> k dvd (m::nat)";
paulson@3457
   545
by (etac (not_less_iff_le RS iffD2 RS add_diff_inverse RS subst) 1);
wenzelm@4089
   546
by (blast_tac (claset() addIs [dvd_add]) 1);
paulson@3366
   547
qed "dvd_diffD";
paulson@3366
   548
paulson@6865
   549
Goalw [dvd_def] "k dvd n ==> k dvd (m*n :: nat)";
wenzelm@4089
   550
by (blast_tac (claset() addIs [mult_left_commute]) 1);
paulson@3366
   551
qed "dvd_mult";
paulson@3366
   552
paulson@6865
   553
Goal "k dvd m ==> k dvd (m*n :: nat)";
paulson@3366
   554
by (stac mult_commute 1);
paulson@3366
   555
by (etac dvd_mult 1);
paulson@3366
   556
qed "dvd_mult2";
paulson@3366
   557
paulson@3366
   558
(* k dvd (m*k) *)
paulson@3366
   559
AddIffs [dvd_refl RS dvd_mult, dvd_refl RS dvd_mult2];
paulson@3366
   560
nipkow@10789
   561
Goal "(k dvd n + k) = (k dvd (n::nat))";
wenzelm@7499
   562
by (rtac iffI 1);
wenzelm@7499
   563
by (etac dvd_add 2);
wenzelm@7499
   564
by (rtac dvd_refl 2);
oheimb@7493
   565
by (subgoal_tac "n = (n+k)-k" 1);
oheimb@7493
   566
by  (Simp_tac 2);
wenzelm@7499
   567
by (etac ssubst 1);
wenzelm@7499
   568
by (etac dvd_diff 1);
wenzelm@7499
   569
by (rtac dvd_refl 1);
oheimb@7493
   570
qed "dvd_reduce";
oheimb@7493
   571
nipkow@10789
   572
Goalw [dvd_def] "!!n::nat. [| f dvd m; f dvd n; 0<n |] ==> f dvd m mod n";
paulson@3718
   573
by (Clarify_tac 1);
paulson@7029
   574
by (Full_simp_tac 1);
paulson@3366
   575
by (res_inst_tac 
paulson@3366
   576
    [("x", "(((k div ka)*ka + k mod ka) - ((f*k) div (f*ka)) * ka)")] 
paulson@3366
   577
    exI 1);
paulson@7029
   578
by (asm_simp_tac
paulson@7029
   579
    (simpset() addsimps [diff_mult_distrib2, mod_mult_distrib2 RS sym, 
paulson@7029
   580
			 add_mult_distrib2]) 1);
paulson@3366
   581
qed "dvd_mod";
paulson@3366
   582
nipkow@10789
   583
Goal "[| (k::nat) dvd m mod n;  k dvd n |] ==> k dvd m";
nipkow@10789
   584
by (subgoal_tac "k dvd (m div n)*n + m mod n" 1);
wenzelm@4089
   585
by (asm_simp_tac (simpset() addsimps [dvd_add, dvd_mult]) 2);
nipkow@4356
   586
by (asm_full_simp_tac (simpset() addsimps [mod_div_equality]) 1);
paulson@3366
   587
qed "dvd_mod_imp_dvd";
paulson@3366
   588
nipkow@10789
   589
Goalw [dvd_def] "!!n::nat. [| f dvd m; f dvd n |] ==> f dvd m mod n";
paulson@9881
   590
by (div_undefined_case_tac "n=0" 1);
paulson@9881
   591
by (Clarify_tac 1);
paulson@9881
   592
by (Full_simp_tac 1);
paulson@9881
   593
by (rename_tac "j" 1);
paulson@9881
   594
by (res_inst_tac 
paulson@9881
   595
    [("x", "(((k div j)*j + k mod j) - ((f*k) div (f*j)) * j)")] 
paulson@9881
   596
    exI 1);
paulson@9881
   597
by (asm_simp_tac
paulson@9881
   598
    (simpset() addsimps [diff_mult_distrib2, mod_mult_distrib2 RS sym, 
paulson@9881
   599
			 add_mult_distrib2]) 1);
paulson@9881
   600
qed "dvd_mod";
paulson@9881
   601
nipkow@10789
   602
Goal "k dvd n ==> ((k::nat) dvd m mod n) = (k dvd m)";
paulson@9881
   603
by (blast_tac (claset() addIs [dvd_mod_imp_dvd, dvd_mod]) 1); 
paulson@9881
   604
qed "dvd_mod_iff";
paulson@9881
   605
nipkow@10789
   606
Goalw [dvd_def]  "!!k::nat. [| k*m dvd k*n; 0<k |] ==> m dvd n";
paulson@3366
   607
by (etac exE 1);
wenzelm@4089
   608
by (asm_full_simp_tac (simpset() addsimps mult_ac) 1);
paulson@3366
   609
qed "dvd_mult_cancel";
paulson@3366
   610
nipkow@10789
   611
Goalw [dvd_def] "[| i dvd m; j dvd n|] ==> i*j dvd (m*n :: nat)";
paulson@3718
   612
by (Clarify_tac 1);
paulson@3366
   613
by (res_inst_tac [("x","k*ka")] exI 1);
wenzelm@4089
   614
by (asm_simp_tac (simpset() addsimps mult_ac) 1);
paulson@3366
   615
qed "mult_dvd_mono";
paulson@3366
   616
paulson@6865
   617
Goalw [dvd_def] "(i*j :: nat) dvd k ==> i dvd k";
wenzelm@4089
   618
by (full_simp_tac (simpset() addsimps [mult_assoc]) 1);
paulson@3366
   619
by (Blast_tac 1);
paulson@3366
   620
qed "dvd_mult_left";
paulson@3366
   621
paulson@8935
   622
Goalw [dvd_def] "[| k dvd n; 0 < n |] ==> k <= (n::nat)";
paulson@3718
   623
by (Clarify_tac 1);
wenzelm@4089
   624
by (ALLGOALS (full_simp_tac (simpset() addsimps [zero_less_mult_iff])));
paulson@3457
   625
by (etac conjE 1);
paulson@3457
   626
by (rtac le_trans 1);
paulson@3457
   627
by (rtac (le_refl RS mult_le_mono) 2);
paulson@3366
   628
by (etac Suc_leI 2);
paulson@3366
   629
by (Simp_tac 1);
paulson@3366
   630
qed "dvd_imp_le";
paulson@3366
   631
paulson@8935
   632
Goalw [dvd_def] "!!k::nat. (k dvd n) = (n mod k = 0)";
paulson@7029
   633
by (div_undefined_case_tac "k=0" 1);
paulson@3724
   634
by Safe_tac;
paulson@5143
   635
by (asm_simp_tac (simpset() addsimps [mult_commute]) 1);
paulson@7029
   636
by (res_inst_tac [("t","n"),("n1","k")] (mod_div_equality RS subst) 1);
paulson@3366
   637
by (stac mult_commute 1);
paulson@3366
   638
by (Asm_simp_tac 1);
paulson@3366
   639
qed "dvd_eq_mod_eq_0";
paulson@10195
   640
paulson@10195
   641
Goal "(m mod d = 0) = (EX q::nat. m = d*q)";
paulson@10195
   642
by (auto_tac (claset(), 
paulson@10195
   643
     simpset() addsimps [dvd_eq_mod_eq_0 RS sym, dvd_def]));  
paulson@10195
   644
qed "mod_eq_0_iff";
paulson@10195
   645
AddSDs [mod_eq_0_iff RS iffD1];
paulson@10195
   646
paulson@10195
   647
(*Loses information, namely we also have r<d provided d is nonzero*)
paulson@10195
   648
Goal "(m mod d = r) ==> EX q::nat. m = r + q*d";
paulson@10195
   649
by (cut_inst_tac [("m","m")] mod_div_equality 1);
paulson@10195
   650
by (full_simp_tac (simpset() addsimps add_ac) 1); 
paulson@10195
   651
by (blast_tac (claset() addIs [sym]) 1); 
paulson@10195
   652
qed "mod_eqD";
paulson@10195
   653