(* ========================================================================= *) (* Theory of integers. *) (* *) (* The integers are carved out of the real numbers; hence all the *) (* universal theorems can be derived trivially from the real analog. *) (* *) (* John Harrison, University of Cambridge Computer Laboratory *) (* *) (* (c) Copyright, University of Cambridge 1998 *) (* (c) Copyright, John Harrison 1998-2007 *) (* ========================================================================= *) open Num;; open Holcore;; open Proved1;; open Proved2;; (* ------------------------------------------------------------------------- *) (* Representing predicate. *) (* ------------------------------------------------------------------------- *) let is_int = new_definition `is_int(x) <=> ?n. (x = &n) \/ (x = --(&n))`;; (* ------------------------------------------------------------------------- *) (* Type of integers. *) (* ------------------------------------------------------------------------- *) let int_abstr,int_rep = let int_tybij = new_type_definition "int" ("int_of_real","real_of_int") (prove(`?x. is_int x`,EXISTS_TAC `&0` THEN REWRITE_TAC[is_int; REAL_OF_NUM_EQ; EXISTS_OR_THM; GSYM EXISTS_REFL])) in SPEC_ALL(CONJUNCT1 int_tybij),SPEC_ALL(CONJUNCT2 int_tybij);; let dest_int_rep = prove (`!i. ?n. (real_of_int i = &n) \/ (real_of_int i = --(&n))`, REWRITE_TAC[GSYM is_int; int_rep; int_abstr]);; (* ------------------------------------------------------------------------- *) (* We want the following too. *) (* ------------------------------------------------------------------------- *) let int_eq = prove (`!x y. (x = y) <=> (real_of_int x = real_of_int y)`, REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN POP_ASSUM(MP_TAC o AP_TERM `int_of_real`) THEN REWRITE_TAC[int_abstr]);; (* ------------------------------------------------------------------------- *) (* Set up interface map. *) (* ------------------------------------------------------------------------- *) do_list overload_interface ["+",`int_add:int->int->int`; "-",`int_sub:int->int->int`; "*",`int_mul:int->int->int`; "<",`int_lt:int->int->bool`; "<=",`int_le:int->int->bool`; ">",`int_gt:int->int->bool`; ">=",`int_ge:int->int->bool`; "--",`int_neg:int->int`; "pow",`int_pow:int->num->int`; "abs",`int_abs:int->int`; "max",`int_max:int->int->int`; "min",`int_min:int->int->int`; "&",`int_of_num:num->int`];; let prioritize_int() = prioritize_overload(mk_type("int",[]));; (* ------------------------------------------------------------------------- *) (* Definitions and closure derivations of all operations but "inv" and "/". *) (* ------------------------------------------------------------------------- *) let int_le = new_definition `x <= y <=> (real_of_int x) <= (real_of_int y)`;; let int_lt = new_definition `x < y <=> (real_of_int x) < (real_of_int y)`;; let int_ge = new_definition `x >= y <=> (real_of_int x) >= (real_of_int y)`;; let int_gt = new_definition `x > y <=> (real_of_int x) > (real_of_int y)`;; let int_of_num = new_definition `&n = int_of_real(real_of_num n)`;; let int_of_num_th = prove (`!n. real_of_int(int_of_num n) = real_of_num n`, REWRITE_TAC[int_of_num; GSYM int_rep; is_int] THEN REWRITE_TAC[REAL_OF_NUM_EQ; EXISTS_OR_THM; GSYM EXISTS_REFL]);; let int_neg = new_definition `--i = int_of_real(--(real_of_int i))`;; let int_neg_th = prove (`!x. real_of_int(int_neg x) = --(real_of_int x)`, REWRITE_TAC[int_neg; GSYM int_rep; is_int] THEN GEN_TAC THEN STRIP_ASSUME_TAC(SPEC `x:int` dest_int_rep) THEN ASM_REWRITE_TAC[REAL_NEG_NEG; EXISTS_OR_THM; REAL_EQ_NEG2; REAL_OF_NUM_EQ; GSYM EXISTS_REFL]);; let int_add = new_definition `x + y = int_of_real((real_of_int x) + (real_of_int y))`;; let int_add_th = prove (`!x y. real_of_int(x + y) = (real_of_int x) + (real_of_int y)`, REWRITE_TAC[int_add; GSYM int_rep; is_int] THEN REPEAT GEN_TAC THEN X_CHOOSE_THEN `m:num` DISJ_CASES_TAC (SPEC `x:int` dest_int_rep) THEN X_CHOOSE_THEN `n:num` DISJ_CASES_TAC (SPEC `y:int` dest_int_rep) THEN ASM_REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_EQ; EXISTS_OR_THM] THEN REWRITE_TAC[GSYM EXISTS_REFL] THEN DISJ_CASES_THEN MP_TAC (SPECL [`m:num`; `n:num`] LE_CASES) THEN REWRITE_TAC[LE_EXISTS] THEN DISCH_THEN(X_CHOOSE_THEN `d:num` SUBST1_TAC) THEN REWRITE_TAC[GSYM REAL_OF_NUM_ADD; OR_EXISTS_THM; REAL_NEG_ADD] THEN TRY(EXISTS_TAC `d:num` THEN REAL_ARITH_TAC) THEN REWRITE_TAC[EXISTS_OR_THM; GSYM REAL_NEG_ADD; REAL_EQ_NEG2; REAL_OF_NUM_ADD; REAL_OF_NUM_EQ; GSYM EXISTS_REFL]);; let int_sub = new_definition `x - y = int_of_real(real_of_int x - real_of_int y)`;; let int_sub_th = prove (`!x y. real_of_int(x - y) = (real_of_int x) - (real_of_int y)`, REWRITE_TAC[int_sub; real_sub; GSYM int_neg_th; GSYM int_add_th] THEN REWRITE_TAC[int_abstr]);; let int_mul = new_definition `x * y = int_of_real ((real_of_int x) * (real_of_int y))`;; let int_mul_th = prove (`!x y. real_of_int(x * y) = (real_of_int x) * (real_of_int y)`, REPEAT GEN_TAC THEN REWRITE_TAC[int_mul; GSYM int_rep; is_int] THEN X_CHOOSE_THEN `m:num` DISJ_CASES_TAC (SPEC `x:int` dest_int_rep) THEN X_CHOOSE_THEN `n:num` DISJ_CASES_TAC (SPEC `y:int` dest_int_rep) THEN ASM_REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_EQ; EXISTS_OR_THM] THEN REWRITE_TAC[REAL_MUL_LNEG; REAL_MUL_RNEG; REAL_NEG_NEG; REAL_OF_NUM_MUL] THEN REWRITE_TAC[REAL_EQ_NEG2; REAL_OF_NUM_EQ; GSYM EXISTS_REFL]);; let int_abs = new_definition `abs x = int_of_real(abs(real_of_int x))`;; let int_abs_th = prove (`!x. real_of_int(abs x) = abs(real_of_int x)`, GEN_TAC THEN REWRITE_TAC[int_abs; real_abs] THEN COND_CASES_TAC THEN REWRITE_TAC[GSYM int_neg; int_neg_th; int_abstr]);; let int_max = new_definition `int_max x y = int_of_real(max (real_of_int x) (real_of_int y))`;; let int_max_th = prove (`!x y. real_of_int(max x y) = max (real_of_int x) (real_of_int y)`, REPEAT GEN_TAC THEN REWRITE_TAC[int_max; real_max] THEN COND_CASES_TAC THEN REWRITE_TAC[int_abstr]);; let int_min = new_definition `int_min x y = int_of_real(min (real_of_int x) (real_of_int y))`;; let int_min_th = prove (`!x y. real_of_int(min x y) = min (real_of_int x) (real_of_int y)`, REPEAT GEN_TAC THEN REWRITE_TAC[int_min; real_min] THEN COND_CASES_TAC THEN REWRITE_TAC[int_abstr]);; let int_pow = new_definition `x pow n = int_of_real((real_of_int x) pow n)`;; let int_pow_th = prove (`!x n. real_of_int(x pow n) = (real_of_int x) pow n`, GEN_TAC THEN REWRITE_TAC[int_pow] THEN INDUCT_TAC THEN REWRITE_TAC[real_pow] THENL [REWRITE_TAC[GSYM int_of_num; int_of_num_th]; POP_ASSUM(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[GSYM int_mul; int_mul_th]]);; (* ------------------------------------------------------------------------- *) (* A couple of theorems peculiar to the integers. *) (* ------------------------------------------------------------------------- *) let INT_IMAGE = prove (`!x. (?n. x = &n) \/ (?n. x = --(&n))`, GEN_TAC THEN X_CHOOSE_THEN `n:num` DISJ_CASES_TAC (SPEC `x:int` dest_int_rep) THEN POP_ASSUM(MP_TAC o AP_TERM `int_of_real`) THEN REWRITE_TAC[int_abstr] THEN DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[int_of_num; int_neg] THENL [DISJ1_TAC; DISJ2_TAC] THEN EXISTS_TAC `n:num` THEN REWRITE_TAC[int_abstr] THEN REWRITE_TAC[GSYM int_of_num; int_of_num_th]);; let INT_LT_DISCRETE = prove (`!x y. x < y <=> (x + &1) <= y`, REPEAT GEN_TAC THEN REWRITE_TAC[int_le; int_lt; int_add_th] THEN DISJ_CASES_THEN(X_CHOOSE_THEN `m:num` SUBST1_TAC ) (SPEC `x:int` INT_IMAGE) THEN DISJ_CASES_THEN(X_CHOOSE_THEN `n:num` SUBST1_TAC ) (SPEC `y:int` INT_IMAGE) THEN REWRITE_TAC[int_neg_th; int_of_num_th] THEN REWRITE_TAC[REAL_LE_NEG2; REAL_LT_NEG2] THEN REWRITE_TAC[REAL_LE_LNEG; REAL_LT_LNEG; REAL_LE_RNEG; REAL_LT_RNEG] THEN REWRITE_TAC[GSYM REAL_ADD_ASSOC] THEN ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN REWRITE_TAC[GSYM real_sub; REAL_LE_SUB_RADD] THEN REWRITE_TAC[REAL_OF_NUM_LE; REAL_OF_NUM_LT; REAL_OF_NUM_ADD] THEN REWRITE_TAC[GSYM ADD1; ONCE_REWRITE_RULE[ADD_SYM] (GSYM ADD1)] THEN REWRITE_TAC[SYM(REWRITE_CONV[ARITH_SUC] `SUC 0`)] THEN REWRITE_TAC[ADD_CLAUSES; LE_SUC_LT; LT_SUC_LE]);; let INT_GT_DISCRETE = prove (`!x y. x > y <=> x >= (y + &1)`, REWRITE_TAC[int_gt; int_ge; real_ge; real_gt; GSYM int_le; GSYM int_lt] THEN MATCH_ACCEPT_TAC INT_LT_DISCRETE);; (* ------------------------------------------------------------------------- *) (* Conversions of integer constants to and from OCaml numbers. *) (* ------------------------------------------------------------------------- *) let is_intconst tm = match tm with Comb(Const("int_of_num",_),n) -> is_numeral n | Comb(Const("int_neg",_),Comb(Const("int_of_num",_),n)) -> is_numeral n & not(dest_numeral n = num_0) | _ -> false;; let dest_intconst tm = match tm with Comb(Const("int_of_num",_),n) -> dest_numeral n | Comb(Const("int_neg",_),Comb(Const("int_of_num",_),n)) -> let nn = dest_numeral n in if nn <>/ num_0 then minus_num(dest_numeral n) else failwith "dest_intconst" | _ -> failwith "dest_intconst";; let mk_intconst = let cast_tm = `int_of_num` and neg_tm = `int_neg` in let mk_numconst n = mk_comb(cast_tm,mk_numeral n) in fun x -> if x (!i. &0 <= i ==> P(i))`, EQ_TAC THEN DISCH_TAC THEN GEN_TAC THENL [DISJ_CASES_THEN (CHOOSE_THEN SUBST1_TAC) (SPEC `i:int` INT_IMAGE) THEN ASM_REWRITE_TAC[INT_LE_RNEG; INT_ADD_LID; INT_OF_NUM_LE; LE] THEN DISCH_THEN SUBST1_TAC THEN ASM_REWRITE_TAC[INT_NEG_0]; FIRST_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[INT_OF_NUM_LE; LE_0]]);; let INT_EXISTS_POS = prove (`(?n. P(&n)) <=> (?i. &0 <= i /\ P(i))`, GEN_REWRITE_TAC I [TAUT `(p <=> q) <=> (~p <=> ~q)`] THEN REWRITE_TAC[NOT_EXISTS_THM; INT_FORALL_POS] THEN MESON_TAC[]);; (* ------------------------------------------------------------------------- *) (* Sometimes handy in number-theoretic applications. *) (* ------------------------------------------------------------------------- *) let INT_ABS_MUL_1 = prove (`!x y. (abs(x * y) = &1) <=> (abs(x) = &1) /\ (abs(y) = &1)`, REPEAT GEN_TAC THEN REWRITE_TAC[INT_ABS_MUL] THEN MP_TAC(SPEC `y:int` INT_ABS_POS) THEN SPEC_TAC(`abs(y)`,`b:int`) THEN MP_TAC(SPEC `x:int` INT_ABS_POS) THEN SPEC_TAC(`abs(x)`,`a:int`) THEN REWRITE_TAC[GSYM INT_FORALL_POS; INT_OF_NUM_MUL; INT_OF_NUM_EQ; MULT_EQ_1]);; let INT_WOP = prove (`(?x. &0 <= x /\ P x) <=> (?x. &0 <= x /\ P x /\ !y. &0 <= y /\ P y ==> x <= y)`, ONCE_REWRITE_TAC[MESON[] `(?x. P x /\ Q x) <=> ~(!x. P x ==> ~Q x)`] THEN REWRITE_TAC[IMP_CONJ; GSYM INT_FORALL_POS; INT_OF_NUM_LE] THEN REWRITE_TAC[NOT_FORALL_THM] THEN GEN_REWRITE_TAC LAND_CONV [num_WOP] THEN REWRITE_TAC[GSYM NOT_LE; CONTRAPOS_THM]);; (* ------------------------------------------------------------------------- *) (* A few "pseudo definitions". *) (* ------------------------------------------------------------------------- *) let INT_POW = prove (`(x pow 0 = &1) /\ (!n. x pow (SUC n) = x * x pow n)`, REWRITE_TAC(map INT_OF_REAL_THM (CONJUNCTS real_pow)));; let INT_ABS = prove (`!x. abs(x) = if &0 <= x then x else --x`, GEN_TAC THEN MP_TAC(INT_OF_REAL_THM(SPEC `x:real` real_abs)) THEN COND_CASES_TAC THEN REWRITE_TAC[int_eq]);; let INT_GE = prove (`!x y. x >= y <=> y <= x`, REWRITE_TAC[int_ge; int_le; real_ge]);; let INT_GT = prove (`!x y. x > y <=> y < x`, REWRITE_TAC[int_gt; int_lt; real_gt]);; let INT_LT = prove (`!x y. x < y <=> ~(y <= x)`, REWRITE_TAC[int_lt; int_le; real_lt]);; (* ------------------------------------------------------------------------- *) (* Now a decision procedure for the integers. *) (* ------------------------------------------------------------------------- *) let INT_ARITH = let atom_CONV = let pth = prove (`(~(x <= y) <=> y + &1 <= x) /\ (~(x < y) <=> y <= x) /\ (~(x = y) <=> x + &1 <= y \/ y + &1 <= x) /\ (x < y <=> x + &1 <= y)`, REWRITE_TAC[INT_NOT_LE; INT_NOT_LT; INT_NOT_EQ; INT_LT_DISCRETE]) in GEN_REWRITE_CONV I [pth] and bub_CONV = GEN_REWRITE_CONV TOP_SWEEP_CONV [int_eq; int_le; int_lt; int_ge; int_gt; int_of_num_th; int_neg_th; int_add_th; int_mul_th; int_sub_th; int_pow_th; int_abs_th; int_max_th; int_min_th] in let base_CONV = TRY_CONV atom_CONV THENC bub_CONV in let NNF_NORM_CONV = GEN_NNF_CONV false (base_CONV,fun t -> base_CONV t,base_CONV(mk_neg t)) in let init_CONV = TOP_DEPTH_CONV BETA_CONV THENC PRESIMP_CONV THENC GEN_REWRITE_CONV DEPTH_CONV [INT_GT; INT_GE] THENC NNF_CONV THENC DEPTH_BINOP_CONV `(\/)` CONDS_ELIM_CONV THENC NNF_NORM_CONV in let p_tm = `p:bool` and not_tm = `(~)` in let pth = TAUT(mk_eq(mk_neg(mk_neg p_tm),p_tm)) in fun tm -> let th0 = INST [tm,p_tm] pth and th1 = init_CONV (mk_neg tm) in let th2 = REAL_ARITH(mk_neg(rand(concl th1))) in EQ_MP th0 (EQ_MP (AP_TERM not_tm (SYM th1)) th2);; let INT_ARITH_TAC = CONV_TAC(EQT_INTRO o INT_ARITH);; let ASM_INT_ARITH_TAC = REPEAT(FIRST_X_ASSUM(MP_TAC o check (not o is_forall o concl))) THEN INT_ARITH_TAC;; (* ------------------------------------------------------------------------- *) (* Some pseudo-definitions. *) (* ------------------------------------------------------------------------- *) let INT_SUB = INT_ARITH `!x y. x - y = x + --y`;; let INT_MAX = INT_ARITH `!x y. max x y = if x <= y then y else x`;; let INT_MIN = INT_ARITH `!x y. min x y = if x <= y then x else y`;; (* ------------------------------------------------------------------------- *) (* Archimedian property for the integers. *) (* ------------------------------------------------------------------------- *) let INT_ARCH = prove (`!x d. ~(d = &0) ==> ?c. x < c * d`, SUBGOAL_THEN `!x. &0 <= x ==> ?n. x <= &n` ASSUME_TAC THENL [REWRITE_TAC[GSYM INT_FORALL_POS; INT_OF_NUM_LE] THEN MESON_TAC[LE_REFL]; ALL_TAC] THEN SUBGOAL_THEN `!x. ?n. x <= &n` ASSUME_TAC THENL [ASM_MESON_TAC[INT_LE_TOTAL]; ALL_TAC] THEN SUBGOAL_THEN `!x d. &0 < d ==> ?c. x < c * d` ASSUME_TAC THENL [REPEAT GEN_TAC THEN REWRITE_TAC[INT_LT_DISCRETE; INT_ADD_LID] THEN ASM_MESON_TAC[INT_POS; INT_LE_LMUL; INT_ARITH `x + &1 <= &n /\ &n * &1 <= &n * d ==> x + &1 <= &n * d`]; ALL_TAC] THEN SUBGOAL_THEN `!x d. ~(d = &0) ==> ?c. x < c * d` ASSUME_TAC THENL [ASM_MESON_TAC[INT_ARITH `--x * y = x * --y`; INT_ARITH `~(d = &0) ==> &0 < d \/ &0 < --d`]; ALL_TAC] THEN ASM_MESON_TAC[INT_ARITH `--x * y = x * --y`; INT_ARITH `~(d = &0) ==> &0 < d \/ &0 < --d`]);; (* ------------------------------------------------------------------------- *) (* Definitions of ("Euclidean") integer division and remainder. *) (* ------------------------------------------------------------------------- *) let INT_DIVMOD_EXIST_0 = prove (`!m n:int. ?q r. if n = &0 then q = &0 /\ r = m else &0 <= r /\ r < abs(n) /\ m = q * n + r`, REPEAT GEN_TAC THEN ASM_CASES_TAC `n = &0` THEN ASM_REWRITE_TAC[RIGHT_EXISTS_AND_THM; EXISTS_REFL] THEN GEN_REWRITE_TAC I [SWAP_EXISTS_THM] THEN SUBGOAL_THEN `?r. &0 <= r /\ ?q:int. m = n * q + r` MP_TAC THENL [FIRST_ASSUM(MP_TAC o SPEC `--m:int` o MATCH_MP INT_ARCH) THEN DISCH_THEN(X_CHOOSE_TAC `s:int`) THEN EXISTS_TAC `m + s * n:int` THEN CONJ_TAC THENL [ASM_INT_ARITH_TAC; EXISTS_TAC `--s:int` THEN INT_ARITH_TAC]; GEN_REWRITE_TAC LAND_CONV [INT_WOP] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `r:int` THEN REWRITE_TAC[LEFT_AND_EXISTS_THM; RIGHT_AND_EXISTS_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN X_GEN_TAC `q:int` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MP_TAC o SPEC `r - abs n`) THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN DISCH_THEN(MP_TAC o SPEC `if &0 <= n then q + &1 else q - &1`) THEN ASM_INT_ARITH_TAC]);; parse_as_infix("div",(22,"left"));; parse_as_infix("rem",(22,"left"));; let INT_DIVISION_0 = new_specification ["div"; "rem"] (REWRITE_RULE[SKOLEM_THM] INT_DIVMOD_EXIST_0);; let INT_DIVISION = prove (`!m n. ~(n = &0) ==> m = m div n * n + m rem n /\ &0 <= m rem n /\ m rem n < abs n`, MESON_TAC[INT_DIVISION_0]);; (* ------------------------------------------------------------------------- *) (* Arithmetic operations on integers. Essentially a clone of stuff for reals *) (* in the file "calc_int.ml", except for div and rem, which are more like N. *) (* ------------------------------------------------------------------------- *) let INT_LE_CONV,INT_LT_CONV,INT_GE_CONV,INT_GT_CONV,INT_EQ_CONV = let tth = TAUT `(F /\ F <=> F) /\ (F /\ T <=> F) /\ (T /\ F <=> F) /\ (T /\ T <=> T)` in let nth = TAUT `(~T <=> F) /\ (~F <=> T)` in let NUM2_EQ_CONV = BINOP_CONV NUM_EQ_CONV THENC GEN_REWRITE_CONV I [tth] in let NUM2_NE_CONV = RAND_CONV NUM2_EQ_CONV THENC GEN_REWRITE_CONV I [nth] in let [pth_le1; pth_le2a; pth_le2b; pth_le3] = (CONJUNCTS o prove) (`(--(&m) <= &n <=> T) /\ (&m <= &n <=> m <= n) /\ (--(&m) <= --(&n) <=> n <= m) /\ (&m <= --(&n) <=> (m = 0) /\ (n = 0))`, REWRITE_TAC[INT_LE_NEG2] THEN REWRITE_TAC[INT_LE_LNEG; INT_LE_RNEG] THEN REWRITE_TAC[INT_OF_NUM_ADD; INT_OF_NUM_LE; LE_0] THEN REWRITE_TAC[LE; ADD_EQ_0]) in let INT_LE_CONV = FIRST_CONV [GEN_REWRITE_CONV I [pth_le1]; GEN_REWRITE_CONV I [pth_le2a; pth_le2b] THENC NUM_LE_CONV; GEN_REWRITE_CONV I [pth_le3] THENC NUM2_EQ_CONV] in let [pth_lt1; pth_lt2a; pth_lt2b; pth_lt3] = (CONJUNCTS o prove) (`(&m < --(&n) <=> F) /\ (&m < &n <=> m < n) /\ (--(&m) < --(&n) <=> n < m) /\ (--(&m) < &n <=> ~((m = 0) /\ (n = 0)))`, REWRITE_TAC[pth_le1; pth_le2a; pth_le2b; pth_le3; GSYM NOT_LE; INT_LT] THEN CONV_TAC TAUT) in let INT_LT_CONV = FIRST_CONV [GEN_REWRITE_CONV I [pth_lt1]; GEN_REWRITE_CONV I [pth_lt2a; pth_lt2b] THENC NUM_LT_CONV; GEN_REWRITE_CONV I [pth_lt3] THENC NUM2_NE_CONV] in let [pth_ge1; pth_ge2a; pth_ge2b; pth_ge3] = (CONJUNCTS o prove) (`(&m >= --(&n) <=> T) /\ (&m >= &n <=> n <= m) /\ (--(&m) >= --(&n) <=> m <= n) /\ (--(&m) >= &n <=> (m = 0) /\ (n = 0))`, REWRITE_TAC[pth_le1; pth_le2a; pth_le2b; pth_le3; INT_GE] THEN CONV_TAC TAUT) in let INT_GE_CONV = FIRST_CONV [GEN_REWRITE_CONV I [pth_ge1]; GEN_REWRITE_CONV I [pth_ge2a; pth_ge2b] THENC NUM_LE_CONV; GEN_REWRITE_CONV I [pth_ge3] THENC NUM2_EQ_CONV] in let [pth_gt1; pth_gt2a; pth_gt2b; pth_gt3] = (CONJUNCTS o prove) (`(--(&m) > &n <=> F) /\ (&m > &n <=> n < m) /\ (--(&m) > --(&n) <=> m < n) /\ (&m > --(&n) <=> ~((m = 0) /\ (n = 0)))`, REWRITE_TAC[pth_lt1; pth_lt2a; pth_lt2b; pth_lt3; INT_GT] THEN CONV_TAC TAUT) in let INT_GT_CONV = FIRST_CONV [GEN_REWRITE_CONV I [pth_gt1]; GEN_REWRITE_CONV I [pth_gt2a; pth_gt2b] THENC NUM_LT_CONV; GEN_REWRITE_CONV I [pth_gt3] THENC NUM2_NE_CONV] in let [pth_eq1a; pth_eq1b; pth_eq2a; pth_eq2b] = (CONJUNCTS o prove) (`((&m = &n) <=> (m = n)) /\ ((--(&m) = --(&n)) <=> (m = n)) /\ ((--(&m) = &n) <=> (m = 0) /\ (n = 0)) /\ ((&m = --(&n)) <=> (m = 0) /\ (n = 0))`, REWRITE_TAC[GSYM INT_LE_ANTISYM; GSYM LE_ANTISYM] THEN REWRITE_TAC[pth_le1; pth_le2a; pth_le2b; pth_le3; LE; LE_0] THEN CONV_TAC TAUT) in let INT_EQ_CONV = FIRST_CONV [GEN_REWRITE_CONV I [pth_eq1a; pth_eq1b] THENC NUM_EQ_CONV; GEN_REWRITE_CONV I [pth_eq2a; pth_eq2b] THENC NUM2_EQ_CONV] in INT_LE_CONV,INT_LT_CONV, INT_GE_CONV,INT_GT_CONV,INT_EQ_CONV;; let INT_NEG_CONV = let pth = prove (`(--(&0) = &0) /\ (--(--(&x)) = &x)`, REWRITE_TAC[INT_NEG_NEG; INT_NEG_0]) in GEN_REWRITE_CONV I [pth];; let INT_MUL_CONV = let pth0 = prove (`(&0 * &x = &0) /\ (&0 * --(&x) = &0) /\ (&x * &0 = &0) /\ (--(&x) * &0 = &0)`, REWRITE_TAC[INT_MUL_LZERO; INT_MUL_RZERO]) and pth1,pth2 = (CONJ_PAIR o prove) (`((&m * &n = &(m * n)) /\ (--(&m) * --(&n) = &(m * n))) /\ ((--(&m) * &n = --(&(m * n))) /\ (&m * --(&n) = --(&(m * n))))`, REWRITE_TAC[INT_MUL_LNEG; INT_MUL_RNEG; INT_NEG_NEG] THEN REWRITE_TAC[INT_OF_NUM_MUL]) in FIRST_CONV [GEN_REWRITE_CONV I [pth0]; GEN_REWRITE_CONV I [pth1] THENC RAND_CONV NUM_MULT_CONV; GEN_REWRITE_CONV I [pth2] THENC RAND_CONV(RAND_CONV NUM_MULT_CONV)];; let INT_ADD_CONV = let neg_tm = `(--)` in let amp_tm = `&` in let add_tm = `(+)` in let dest = dest_binop `(+)` in let m_tm = `m:num` and n_tm = `n:num` in let pth0 = prove (`(--(&m) + &m = &0) /\ (&m + --(&m) = &0)`, REWRITE_TAC[INT_ADD_LINV; INT_ADD_RINV]) in let [pth1; pth2; pth3; pth4; pth5; pth6] = (CONJUNCTS o prove) (`(--(&m) + --(&n) = --(&(m + n))) /\ (--(&m) + &(m + n) = &n) /\ (--(&(m + n)) + &m = --(&n)) /\ (&(m + n) + --(&m) = &n) /\ (&m + --(&(m + n)) = --(&n)) /\ (&m + &n = &(m + n))`, REWRITE_TAC[GSYM INT_OF_NUM_ADD; INT_NEG_ADD] THEN REWRITE_TAC[INT_ADD_ASSOC; INT_ADD_LINV; INT_ADD_LID] THEN REWRITE_TAC[INT_ADD_RINV; INT_ADD_LID] THEN ONCE_REWRITE_TAC[INT_ADD_SYM] THEN REWRITE_TAC[INT_ADD_ASSOC; INT_ADD_LINV; INT_ADD_LID] THEN REWRITE_TAC[INT_ADD_RINV; INT_ADD_LID]) in GEN_REWRITE_CONV I [pth0] ORELSEC (fun tm -> try let l,r = dest tm in if rator l = neg_tm then if rator r = neg_tm then let th1 = INST [rand(rand l),m_tm; rand(rand r),n_tm] pth1 in let tm1 = rand(rand(rand(concl th1))) in let th2 = AP_TERM neg_tm (AP_TERM amp_tm (NUM_ADD_CONV tm1)) in TRANS th1 th2 else let m = rand(rand l) and n = rand r in let m' = dest_numeral m and n' = dest_numeral n in if m' <=/ n' then let p = mk_numeral (n' -/ m') in let th1 = INST [m,m_tm; p,n_tm] pth2 in let th2 = NUM_ADD_CONV (rand(rand(lhand(concl th1)))) in let th3 = AP_TERM (rator tm) (AP_TERM amp_tm (SYM th2)) in TRANS th3 th1 else let p = mk_numeral (m' -/ n') in let th1 = INST [n,m_tm; p,n_tm] pth3 in let th2 = NUM_ADD_CONV (rand(rand(lhand(lhand(concl th1))))) in let th3 = AP_TERM neg_tm (AP_TERM amp_tm (SYM th2)) in let th4 = AP_THM (AP_TERM add_tm th3) (rand tm) in TRANS th4 th1 else if rator r = neg_tm then let m = rand l and n = rand(rand r) in let m' = dest_numeral m and n' = dest_numeral n in if n' <=/ m' then let p = mk_numeral (m' -/ n') in let th1 = INST [n,m_tm; p,n_tm] pth4 in let th2 = NUM_ADD_CONV (rand(lhand(lhand(concl th1)))) in let th3 = AP_TERM add_tm (AP_TERM amp_tm (SYM th2)) in let th4 = AP_THM th3 (rand tm) in TRANS th4 th1 else let p = mk_numeral (n' -/ m') in let th1 = INST [m,m_tm; p,n_tm] pth5 in let th2 = NUM_ADD_CONV (rand(rand(rand(lhand(concl th1))))) in let th3 = AP_TERM neg_tm (AP_TERM amp_tm (SYM th2)) in let th4 = AP_TERM (rator tm) th3 in TRANS th4 th1 else let th1 = INST [rand l,m_tm; rand r,n_tm] pth6 in let tm1 = rand(rand(concl th1)) in let th2 = AP_TERM amp_tm (NUM_ADD_CONV tm1) in TRANS th1 th2 with Failure _ -> failwith "INT_ADD_CONV");; let INT_SUB_CONV = GEN_REWRITE_CONV I [INT_SUB] THENC TRY_CONV(RAND_CONV INT_NEG_CONV) THENC INT_ADD_CONV;; let INT_POW_CONV = let pth1,pth2 = (CONJ_PAIR o prove) (`(&x pow n = &(x EXP n)) /\ ((--(&x)) pow n = if EVEN n then &(x EXP n) else --(&(x EXP n)))`, REWRITE_TAC[INT_OF_NUM_POW; INT_POW_NEG]) in let tth = prove (`((if T then x:int else y) = x) /\ ((if F then x:int else y) = y)`, REWRITE_TAC[]) in let neg_tm = `(--)` in (GEN_REWRITE_CONV I [pth1] THENC RAND_CONV NUM_EXP_CONV) ORELSEC (GEN_REWRITE_CONV I [pth2] THENC RATOR_CONV(RATOR_CONV(RAND_CONV NUM_EVEN_CONV)) THENC GEN_REWRITE_CONV I [tth] THENC (fun tm -> if rator tm = neg_tm then RAND_CONV(RAND_CONV NUM_EXP_CONV) tm else RAND_CONV NUM_EXP_CONV tm));; let INT_ABS_CONV = let pth = prove (`(abs(--(&x)) = &x) /\ (abs(&x) = &x)`, REWRITE_TAC[INT_ABS_NEG; INT_ABS_NUM]) in GEN_REWRITE_CONV I [pth];; let INT_MAX_CONV = REWR_CONV INT_MAX THENC RATOR_CONV(RATOR_CONV(RAND_CONV INT_LE_CONV)) THENC GEN_REWRITE_CONV I [COND_CLAUSES];; let INT_MIN_CONV = REWR_CONV INT_MIN THENC RATOR_CONV(RATOR_CONV(RAND_CONV INT_LE_CONV)) THENC GEN_REWRITE_CONV I [COND_CLAUSES];; (* ------------------------------------------------------------------------- *) (* Instantiate the normalizer. *) (* ------------------------------------------------------------------------- *) let INT_POLY_CONV = let sth = prove (`(!x y z. x + (y + z) = (x + y) + z) /\ (!x y. x + y = y + x) /\ (!x. &0 + x = x) /\ (!x y z. x * (y * z) = (x * y) * z) /\ (!x y. x * y = y * x) /\ (!x. &1 * x = x) /\ (!x. &0 * x = &0) /\ (!x y z. x * (y + z) = x * y + x * z) /\ (!x. x pow 0 = &1) /\ (!x n. x pow (SUC n) = x * x pow n)`, REWRITE_TAC[INT_POW] THEN INT_ARITH_TAC) and rth = prove (`(!x. --x = --(&1) * x) /\ (!x y. x - y = x + --(&1) * y)`, INT_ARITH_TAC) and is_semiring_constant = is_intconst and SEMIRING_ADD_CONV = INT_ADD_CONV and SEMIRING_MUL_CONV = INT_MUL_CONV and SEMIRING_POW_CONV = INT_POW_CONV in let _,_,_,_,_,INT_POLY_CONV = SEMIRING_NORMALIZERS_CONV sth rth (is_semiring_constant, SEMIRING_ADD_CONV,SEMIRING_MUL_CONV,SEMIRING_POW_CONV) (<) in INT_POLY_CONV;; (* ------------------------------------------------------------------------- *) (* Instantiate the ring and ideal procedures. *) (* ------------------------------------------------------------------------- *) let INT_RING,int_ideal_cofactors = let INT_INTEGRAL = prove (`(!x. &0 * x = &0) /\ (!x y z. (x + y = x + z) <=> (y = z)) /\ (!w x y z. (w * y + x * z = w * z + x * y) <=> (w = x) \/ (y = z))`, REWRITE_TAC[MULT_CLAUSES; EQ_ADD_LCANCEL] THEN REWRITE_TAC[GSYM INT_OF_NUM_EQ; GSYM INT_OF_NUM_ADD; GSYM INT_OF_NUM_MUL] THEN ONCE_REWRITE_TAC[GSYM INT_SUB_0] THEN REWRITE_TAC[GSYM INT_ENTIRE] THEN INT_ARITH_TAC) and int_ty = `:int` in let pure,ideal = RING_AND_IDEAL_CONV (dest_intconst,mk_intconst,INT_EQ_CONV, `(--):int->int`,`(+):int->int->int`,`(-):int->int->int`, genvar bool_ty,`(*):int->int->int`,genvar bool_ty, `(pow):int->num->int`, INT_INTEGRAL,TRUTH,INT_POLY_CONV) in pure, (fun tms tm -> if forall (fun t -> type_of t = int_ty) (tm::tms) then ideal tms tm else failwith "int_ideal_cofactors: not all terms have type :int");; (* ------------------------------------------------------------------------- *) (* Arithmetic operations also on div and rem, hence the whole lot. *) (* ------------------------------------------------------------------------- *) let INT_DIVMOD_UNIQ = prove (`!m n q r:int. m = q * n + r /\ &0 <= r /\ r < abs n ==> m div n = q /\ m rem n = r`, REPEAT GEN_TAC THEN STRIP_TAC THEN SUBGOAL_THEN `~(n = &0)` MP_TAC THENL [ASM_INT_ARITH_TAC; ALL_TAC] THEN DISCH_THEN(STRIP_ASSUME_TAC o SPEC `m:int` o MATCH_MP INT_DIVISION) THEN ASM_CASES_TAC `m div n = q` THENL [REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC INT_RING; ALL_TAC] THEN SUBGOAL_THEN `abs(m rem n - r) < abs n` MP_TAC THENL [ASM_INT_ARITH_TAC; MATCH_MP_TAC(TAUT `~p ==> p ==> q`)] THEN MATCH_MP_TAC(INT_ARITH `&1 * abs n <= abs(q - m div n) * abs n /\ abs(m rem n - r) = abs((q - m div n) * n) ==> ~(abs(m rem n - r) < abs n)`) THEN CONJ_TAC THENL [MATCH_MP_TAC INT_LE_RMUL THEN ASM_INT_ARITH_TAC; AP_TERM_TAC THEN REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC INT_RING]);; let INT_DIV_CONV,INT_REM_CONV = let pth = prove (`q * n + r = m ==> &0 <= r ==> r < abs n ==> m div n = q /\ m rem n = r`, MESON_TAC[INT_DIVMOD_UNIQ]) and m = `m:int` and n = `n:int` and q = `q:int` and r = `r:int` and dtm = `(div)` and mtm = `(rem)` in let emod_num x y = let r = mod_num x y in if r try let l,r = dest_binop dtm tm in CONJUNCT1(INT_DIVMOD_CONV (dest_intconst l) (dest_intconst r)) with Failure _ -> failwith "INT_DIV_CONV"), (fun tm -> try let l,r = dest_binop mtm tm in CONJUNCT2(INT_DIVMOD_CONV (dest_intconst l) (dest_intconst r)) with Failure _ -> failwith "INT_MOD_CONV");; let INT_RED_CONV = let gconv_net = itlist (uncurry net_of_conv) [`x <= y`,INT_LE_CONV; `x < y`,INT_LT_CONV; `x >= y`,INT_GE_CONV; `x > y`,INT_GT_CONV; `x:int = y`,INT_EQ_CONV; `--x`,CHANGED_CONV INT_NEG_CONV; `abs(x)`,INT_ABS_CONV; `x + y`,INT_ADD_CONV; `x - y`,INT_SUB_CONV; `x * y`,INT_MUL_CONV; `x div y`,INT_DIV_CONV; `x rem y`,INT_REM_CONV; `x pow n`,INT_POW_CONV; `max x y`,INT_MAX_CONV; `min x y`,INT_MIN_CONV] (basic_net()) in REWRITES_CONV gconv_net;; let INT_REDUCE_CONV = DEPTH_CONV INT_RED_CONV;; (* ------------------------------------------------------------------------- *) (* Set up overloading so we can use same symbols for N, Z and even R. *) (* ------------------------------------------------------------------------- *) make_overloadable "divides" `:A->A->bool`;; make_overloadable "mod" `:A->A->A->bool`;; make_overloadable "coprime" `:A#A->bool`;; make_overloadable "gcd" `:A#A->A`;; (* ------------------------------------------------------------------------- *) (* The general notion of congruence: just syntax for equivalence relation. *) (* ------------------------------------------------------------------------- *) parse_as_infix("==",(10,"right"));; let cong = new_definition `(x == y) (rel:A->A->bool) <=> rel x y`;; (* ------------------------------------------------------------------------- *) (* Get real moduli defined and out of the way first. *) (* ------------------------------------------------------------------------- *) let real_mod = new_definition `real_mod n (x:real) y = ?q. is_int q /\ x - y = q * n`;; overload_interface ("mod",`real_mod`);; (* ------------------------------------------------------------------------- *) (* Integer divisibility. *) (* ------------------------------------------------------------------------- *) parse_as_infix("divides",(12,"right"));; overload_interface("divides",`int_divides:int->int->bool`);; let int_divides = new_definition `a divides b <=> ?x. b = a * x`;; (* ------------------------------------------------------------------------- *) (* Integer congruences. *) (* ------------------------------------------------------------------------- *) parse_as_prefix "mod";; overload_interface ("mod",`int_mod:int->int->int->bool`);; let int_mod = new_definition `(mod n) x y = n divides (x - y)`;; let int_congruent = prove (`!x y n. (x == y) (mod n) <=> ?d. x - y = n * d`, REWRITE_TAC[int_mod; cong; int_divides]);; (* ------------------------------------------------------------------------- *) (* Integer coprimality. *) (* ------------------------------------------------------------------------- *) overload_interface("coprime",`int_coprime:int#int->bool`);; let int_coprime = new_definition `!a b. coprime(a,b) <=> ?x y. a * x + b * y = &1`;; (* ------------------------------------------------------------------------- *) (* A tactic for simple divisibility/congruence/coprimality goals. *) (* ------------------------------------------------------------------------- *) let INTEGER_TAC = let int_ty = `:int` in let INT_POLYEQ_CONV = GEN_REWRITE_CONV I [GSYM INT_SUB_0] THENC LAND_CONV INT_POLY_CONV in let ISOLATE_VARIABLE = let pth = INT_ARITH `!a x. a = &0 <=> x = x + a` in let is_defined v t = let mons = striplist(dest_binary "int_add") t in mem v mons & forall (fun m -> v = m or not(free_in v m)) mons in fun vars tm -> let th = INT_POLYEQ_CONV tm and th' = (SYM_CONV THENC INT_POLYEQ_CONV) tm in let v,th1 = try find (fun v -> is_defined v (lhand(rand(concl th)))) vars,th' with Failure _ -> find (fun v -> is_defined v (lhand(rand(concl th')))) vars,th in let th2 = TRANS th1 (SPECL [lhs(rand(concl th1)); v] pth) in CONV_RULE(RAND_CONV(RAND_CONV INT_POLY_CONV)) th2 in let UNWIND_POLYS_CONV tm = let vars,bod = strip_exists tm in let cjs = conjuncts bod in let th1 = tryfind (ISOLATE_VARIABLE vars) cjs in let eq = lhand(concl th1) in let bod' = list_mk_conj(eq::(subtract cjs [eq])) in let th2 = CONJ_ACI_RULE(mk_eq(bod,bod')) in let th3 = TRANS th2 (MK_CONJ th1 (REFL(rand(rand(concl th2))))) in let v = lhs(lhand(rand(concl th3))) in let vars' = (subtract vars [v]) @ [v] in let th4 = CONV_RULE(RAND_CONV(REWR_CONV UNWIND_THM2)) (MK_EXISTS v th3) in let IMP_RULE v v' = DISCH_ALL(itlist SIMPLE_CHOOSE v (itlist SIMPLE_EXISTS v' (ASSUME bod))) in let th5 = IMP_ANTISYM_RULE (IMP_RULE vars vars') (IMP_RULE vars' vars) in TRANS th5 (itlist MK_EXISTS (subtract vars [v]) th4) in let zero_tm = `&0` and one_tm = `&1` in let isolate_monomials = let mul_tm = `(int_mul)` and add_tm = `(int_add)` and neg_tm = `(int_neg)` in let dest_mul = dest_binop mul_tm and dest_add = dest_binop add_tm and mk_mul = mk_binop mul_tm and mk_add = mk_binop add_tm in let scrub_var v m = let ps = striplist dest_mul m in let ps' = subtract ps [v] in if ps' = [] then one_tm else end_itlist mk_mul ps' in let find_multipliers v mons = let mons1 = filter (fun m -> free_in v m) mons in let mons2 = map (scrub_var v) mons1 in if mons2 = [] then zero_tm else end_itlist mk_add mons2 in fun vars tm -> let cmons,vmons = partition (fun m -> intersect (frees m) vars = []) (striplist dest_add tm) in let cofactors = map (fun v -> find_multipliers v vmons) vars and cnc = if cmons = [] then zero_tm else mk_comb(neg_tm,end_itlist mk_add cmons) in cofactors,cnc in let isolate_variables evs ps eq = let vars = filter (fun v -> vfree_in v eq) evs in let qs,p = isolate_monomials vars eq in let rs = filter (fun t -> type_of t = int_ty) (qs @ ps) in let rs = int_ideal_cofactors rs p in eq,zip (fst(chop_list(length qs) rs)) vars in let subst_in_poly i p = rhs(concl(INT_POLY_CONV (vsubst i p))) in let rec solve_idealism evs ps eqs = if evs = [] then [] else let eq,cfs = tryfind (isolate_variables evs ps) eqs in let evs' = subtract evs (map snd cfs) and eqs' = map (subst_in_poly cfs) (subtract eqs [eq]) in cfs @ solve_idealism evs' ps eqs' in let rec GENVAR_EXISTS_CONV tm = if not(is_exists tm) then REFL tm else let ev,bod = dest_exists tm in let gv = genvar(type_of ev) in (GEN_ALPHA_CONV gv THENC BINDER_CONV GENVAR_EXISTS_CONV) tm in let EXISTS_POLY_TAC (asl,w as gl) = let evs,bod = strip_exists w and ps = mapfilter (check (fun t -> type_of t = int_ty) o lhs o concl o snd) asl in let cfs = solve_idealism evs ps (map lhs (conjuncts bod)) in (MAP_EVERY EXISTS_TAC(map (fun v -> rev_assocd v cfs zero_tm) evs) THEN REPEAT(POP_ASSUM MP_TAC) THEN CONV_TAC INT_RING) gl in let SCRUB_NEQ_TAC = MATCH_MP_TAC o MATCH_MP (MESON[] `~(x = y) ==> x = y \/ p ==> p`) in REWRITE_TAC[int_coprime; int_congruent; int_divides] THEN REPEAT(STRIP_TAC ORELSE EQ_TAC) THEN REWRITE_TAC[LEFT_AND_EXISTS_THM; RIGHT_AND_EXISTS_THM; LEFT_OR_EXISTS_THM; RIGHT_OR_EXISTS_THM] THEN CONV_TAC(REPEATC UNWIND_POLYS_CONV) THEN REPEAT(FIRST_X_ASSUM SCRUB_NEQ_TAC) THEN REWRITE_TAC[LEFT_AND_EXISTS_THM; RIGHT_AND_EXISTS_THM; LEFT_OR_EXISTS_THM; RIGHT_OR_EXISTS_THM] THEN REPEAT(FIRST_X_ASSUM(MP_TAC o SYM)) THEN CONV_TAC(ONCE_DEPTH_CONV INT_POLYEQ_CONV) THEN REWRITE_TAC[GSYM INT_ENTIRE; TAUT `a \/ (b /\ c) <=> (a \/ b) /\ (a \/ c)`] THEN POP_ASSUM_LIST(K ALL_TAC) THEN REPEAT DISCH_TAC THEN CONV_TAC GENVAR_EXISTS_CONV THEN CONV_TAC(ONCE_DEPTH_CONV INT_POLYEQ_CONV) THEN EXISTS_POLY_TAC;; let INTEGER_RULE tm = prove(tm,INTEGER_TAC);; (* ------------------------------------------------------------------------- *) (* Existence of integer gcd, and the Bezout identity. *) (* ------------------------------------------------------------------------- *) let FORALL_UNCURRY = prove (`!P. (!f:A->B->C. P f) <=> (!f. P (\a b. f(a,b)))`, GEN_TAC THEN EQ_TAC THEN SIMP_TAC[] THEN DISCH_TAC THEN X_GEN_TAC `f:A->B->C` THEN FIRST_ASSUM(MP_TAC o SPEC `\(a,b). (f:A->B->C) a b`) THEN SIMP_TAC[ETA_AX]);; let EXISTS_UNCURRY = prove (`!P. (?f:A->B->C. P f) <=> (?f. P (\a b. f(a,b)))`, ONCE_REWRITE_TAC[MESON[] `(?x. P x) <=> ~(!x. ~P x)`] THEN REWRITE_TAC[FORALL_UNCURRY]);; let WF_INT_MEASURE = prove (`!P m. (!x. &0 <= m(x)) /\ (!x. (!y. m(y) < m(x) ==> P(y)) ==> P(x)) ==> !x:A. P(x)`, REPEAT STRIP_TAC THEN SUBGOAL_THEN `!n x:A. m(x) = &n ==> P(x)` MP_TAC THENL [MATCH_MP_TAC num_WF; ALL_TAC] THEN REWRITE_TAC[GSYM INT_OF_NUM_LT; INT_FORALL_POS] THEN ASM_MESON_TAC[]);; let WF_INT_MEASURE_2 = prove (`!P m. (!x y. &0 <= m x y) /\ (!x y. (!x' y'. m x' y' < m x y ==> P x' y') ==> P x y) ==> !x:A y:B. P x y`, REWRITE_TAC[FORALL_UNCURRY; GSYM FORALL_PAIR_THM; WF_INT_MEASURE]);; let INT_GCD_EXISTS = prove (`!a b. ?d. d divides a /\ d divides b /\ ?x y. d = a * x + b * y`, let INT_GCD_EXISTS_CASES = INT_ARITH `(a = &0 \/ b = &0) \/ abs(a - b) + abs b < abs a + abs b \/ abs(a + b) + abs b < abs a + abs b \/ abs a + abs(b - a) < abs a + abs b \/ abs a + abs(b + a) < abs a + abs b` in MATCH_MP_TAC WF_INT_MEASURE_2 THEN EXISTS_TAC `\x y. abs(x) + abs(y)` THEN REWRITE_TAC[] THEN REPEAT STRIP_TAC THENL [INT_ARITH_TAC; ALL_TAC] THEN DISJ_CASES_THEN MP_TAC INT_GCD_EXISTS_CASES THENL [STRIP_TAC THEN ASM_REWRITE_TAC[INTEGER_RULE `d divides &0`] THEN REWRITE_TAC[INT_MUL_LZERO; INT_ADD_LID; INT_ADD_RID] THEN MESON_TAC[INTEGER_RULE `d divides d`; INT_MUL_RID]; DISCH_THEN(REPEAT_TCL DISJ_CASES_THEN (ANTE_RES_THEN MP_TAC)) THEN MATCH_MP_TAC MONO_EXISTS THEN INTEGER_TAC]);; let INT_GCD_EXISTS_POS = prove (`!a b. ?d. &0 <= d /\ d divides a /\ d divides b /\ ?x y. d = a * x + b * y`, REPEAT GEN_TAC THEN X_CHOOSE_TAC `d:int` (SPECL [`a:int`; `b:int`] INT_GCD_EXISTS) THEN DISJ_CASES_TAC(SPEC `d:int` INT_LE_NEGTOTAL) THEN ASM_MESON_TAC[INTEGER_RULE `(--d) divides x <=> d divides x`; INT_ARITH `a * --x + b * --y = --(a * x + b * y)`]);; (* ------------------------------------------------------------------------- *) (* Hence define (positive) gcd function; add elimination to INTEGER_TAC. *) (* ------------------------------------------------------------------------- *) overload_interface("gcd",`int_gcd:int#int->int`);; let int_gcd = new_specification ["int_gcd"] (REWRITE_RULE[EXISTS_UNCURRY; SKOLEM_THM] INT_GCD_EXISTS_POS);; let INTEGER_TAC = let GCD_ELIM_TAC = let gcd_tm = `gcd` in let dest_gcd tm = let l,r = dest_comb tm in if l = gcd_tm then dest_pair r else failwith "dest_gcd" in REPEAT GEN_TAC THEN W(fun (asl,w) -> let gts = find_terms (can dest_gcd) w in let ths = map (fun tm -> let a,b = dest_gcd tm in SPECL [a;b] int_gcd) gts in MAP_EVERY MP_TAC ths THEN MAP_EVERY SPEC_TAC (zip gts (map (genvar o type_of) gts))) in REPEAT(GEN_TAC ORELSE CONJ_TAC) THEN GCD_ELIM_TAC THEN INTEGER_TAC;; let INTEGER_RULE tm = prove(tm,INTEGER_TAC);; (* ------------------------------------------------------------------------- *) (* Mapping from nonnegative integers back to natural numbers. *) (* ------------------------------------------------------------------------- *) let num_of_int = new_definition `num_of_int x = @n. &n = x`;; let NUM_OF_INT_OF_NUM = prove (`!n. num_of_int(&n) = n`, REWRITE_TAC[num_of_int; INT_OF_NUM_EQ; SELECT_UNIQUE]);; let INT_OF_NUM_OF_INT = prove (`!x. &0 <= x ==> &(num_of_int x) = x`, REWRITE_TAC[GSYM INT_FORALL_POS; num_of_int] THEN GEN_TAC THEN CONV_TAC SELECT_CONV THEN MESON_TAC[]);; let NUM_OF_INT = prove (`!x. &0 <= x <=> (&(num_of_int x) = x)`, MESON_TAC[INT_OF_NUM_OF_INT; INT_POS]);; (* ------------------------------------------------------------------------- *) (* Now define similar notions over the natural numbers. *) (* ------------------------------------------------------------------------- *) overload_interface("divides",`num_divides:num->num->bool`);; overload_interface ("mod",`num_mod:num->num->num->bool`);; overload_interface("coprime",`num_coprime:num#num->bool`);; overload_interface("gcd",`num_gcd:num#num->num`);; let num_divides = new_definition `a divides b <=> &a divides &b`;; let num_mod = new_definition `(mod n) x y <=> (mod &n) (&x) (&y)`;; let num_congruent = prove (`!x y n. (x == y) (mod n) <=> (&x == &y) (mod &n)`, REWRITE_TAC[cong; num_mod]);; let num_coprime = new_definition `coprime(a,b) <=> coprime(&a,&b)`;; let num_gcd = new_definition `gcd(a,b) = num_of_int(gcd(&a,&b))`;; (* ------------------------------------------------------------------------- *) (* Map an assertion over N to an integer equivalent. *) (* To make this work nicely, all variables of type num should be quantified. *) (* ------------------------------------------------------------------------- *) let NUM_TO_INT_CONV = let pth_relativize = prove (`((!n. P(&n)) <=> (!i. ~(&0 <= i) \/ P i)) /\ ((?n. P(&n)) <=> (?i. &0 <= i /\ P i))`, REWRITE_TAC[INT_EXISTS_POS; INT_FORALL_POS] THEN MESON_TAC[]) in let relation_conv = (GEN_REWRITE_CONV TOP_SWEEP_CONV o map GSYM) [INT_OF_NUM_EQ; INT_OF_NUM_LE; INT_OF_NUM_LT; INT_OF_NUM_GE; INT_OF_NUM_GT; INT_OF_NUM_SUC; INT_OF_NUM_ADD; INT_OF_NUM_MUL; INT_OF_NUM_POW] and quantifier_conv = GEN_REWRITE_CONV DEPTH_CONV [pth_relativize] in NUM_SIMPLIFY_CONV THENC relation_conv THENC quantifier_conv;; (* ------------------------------------------------------------------------- *) (* Linear decision procedure for the naturals at last! *) (* ------------------------------------------------------------------------- *) let ARITH_RULE = let init_conv = NUM_SIMPLIFY_CONV THENC GEN_REWRITE_CONV DEPTH_CONV [ADD1] THENC PROP_ATOM_CONV (BINOP_CONV NUM_NORMALIZE_CONV) THENC PRENEX_CONV THENC (GEN_REWRITE_CONV TOP_SWEEP_CONV o map GSYM) [INT_OF_NUM_EQ; INT_OF_NUM_LE; INT_OF_NUM_LT; INT_OF_NUM_GE; INT_OF_NUM_GT; INT_OF_NUM_ADD; SPEC `NUMERAL k` INT_OF_NUM_MUL; INT_OF_NUM_MAX; INT_OF_NUM_MIN] and is_numimage t = match t with Comb(Const("int_of_num",_),n) when not(is_numeral n) -> true | _ -> false in fun tm -> let th1 = init_conv tm in let tm1 = rand(concl th1) in let avs,bod = strip_forall tm1 in let nim = setify(find_terms is_numimage bod) in let gvs = map (genvar o type_of) nim in let pths = map (fun v -> SPEC (rand v) INT_POS) nim in let ibod = itlist (curry mk_imp o concl) pths bod in let gbod = subst (zip gvs nim) ibod in let th2 = INST (zip nim gvs) (INT_ARITH gbod) in let th3 = GENL avs (rev_itlist (C MP) pths th2) in EQ_MP (SYM th1) th3;; let ARITH_TAC = CONV_TAC(EQT_INTRO o ARITH_RULE);; let ASM_ARITH_TAC = REPEAT(FIRST_X_ASSUM(MP_TAC o check (not o is_forall o concl))) THEN ARITH_TAC;; (* ------------------------------------------------------------------------- *) (* Also a similar divisibility procedure for natural numbers. *) (* ------------------------------------------------------------------------- *) let NUM_GCD = prove (`!a b. &(gcd(a,b)) = gcd(&a,&b)`, REWRITE_TAC[num_gcd; GSYM NUM_OF_INT; int_gcd]);; let NUMBER_TAC = let pth_relativize = prove (`((!n. P(&n)) <=> (!i. &0 <= i ==> P i)) /\ ((?n. P(&n)) <=> (?i. &0 <= i /\ P i))`, GEN_REWRITE_TAC RAND_CONV [TAUT `(a <=> b) <=> (~a <=> ~b)`] THEN REWRITE_TAC[NOT_EXISTS_THM; INT_FORALL_POS] THEN MESON_TAC[]) in let relation_conv = GEN_REWRITE_CONV TOP_SWEEP_CONV (num_divides::num_congruent::num_coprime::NUM_GCD::(map GSYM [INT_OF_NUM_EQ; INT_OF_NUM_LE; INT_OF_NUM_LT; INT_OF_NUM_GE; INT_OF_NUM_GT; INT_OF_NUM_SUC; INT_OF_NUM_ADD; INT_OF_NUM_MUL; INT_OF_NUM_POW])) and quantifier_conv = GEN_REWRITE_CONV DEPTH_CONV [pth_relativize] in W(fun (_,w) -> MAP_EVERY (fun v -> SPEC_TAC(v,v)) (frees w)) THEN CONV_TAC(relation_conv THENC quantifier_conv) THEN REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN REPEAT GEN_TAC THEN INTEGER_TAC;; let NUMBER_RULE tm = prove(tm,NUMBER_TAC);; (* ------------------------------------------------------------------------- *) (* Make sure we give priority to N. *) (* ------------------------------------------------------------------------- *) prioritize_num();; (* ========================================================================= *) (* Very basic set theory (using predicates as sets). *) (* *) (* John Harrison, University of Cambridge Computer Laboratory *) (* *) (* (c) Copyright, University of Cambridge 1998 *) (* (c) Copyright, John Harrison 1998-2007 *) (* ========================================================================= *) parse_as_infix("IN",(11,"right"));; parse_as_infix("SUBSET",(12,"right"));; parse_as_infix("PSUBSET",(12,"right"));; parse_as_infix("INTER",(20,"right"));; parse_as_infix("UNION",(16,"right"));; parse_as_infix("DIFF",(18,"left"));; parse_as_infix("INSERT",(21,"right"));; parse_as_infix("DELETE",(21,"left"));; parse_as_infix("HAS_SIZE",(12,"right"));; parse_as_infix("<=_c",(12,"right"));; parse_as_infix("<_c",(12,"right"));; parse_as_infix(">=_c",(12,"right"));; parse_as_infix(">_c",(12,"right"));; parse_as_infix("=_c",(12,"right"));; (* ------------------------------------------------------------------------- *) (* Set membership. *) (* ------------------------------------------------------------------------- *) let IN = new_definition `!P:A->bool. !x. x IN P <=> P x`;; (* ------------------------------------------------------------------------- *) (* Axiom of extensionality in this framework. *) (* ------------------------------------------------------------------------- *) let EXTENSION = prove (`!s t. (s = t) <=> !x:A. x IN s <=> x IN t`, REWRITE_TAC[IN; FUN_EQ_THM]);; (* ------------------------------------------------------------------------- *) (* General specification. *) (* ------------------------------------------------------------------------- *) let GSPEC = new_definition `GSPEC (p:A->bool) = p`;; let SETSPEC = new_definition `SETSPEC v P t <=> P /\ (v = t)`;; (* ------------------------------------------------------------------------- *) (* Rewrite rule for eliminating set-comprehension membership assertions. *) (* ------------------------------------------------------------------------- *) let IN_ELIM_THM = prove (`(!P x. x IN GSPEC (\v. P (SETSPEC v)) <=> P (\p t. p /\ (x = t))) /\ (!p x. x IN GSPEC (\v. ?y. SETSPEC v (p y) y) <=> p x) /\ (!P x. GSPEC (\v. P (SETSPEC v)) x <=> P (\p t. p /\ (x = t))) /\ (!p x. GSPEC (\v. ?y. SETSPEC v (p y) y) x <=> p x) /\ (!p x. x IN (\y. p y) <=> p x)`, REPEAT STRIP_TAC THEN REWRITE_TAC[IN; GSPEC] THEN TRY(AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM]) THEN REWRITE_TAC[SETSPEC] THEN MESON_TAC[]);; (* ------------------------------------------------------------------------- *) (* These two definitions are needed first, for the parsing of enumerations. *) (* ------------------------------------------------------------------------- *) let EMPTY = new_definition `EMPTY = (\x:A. F)`;; let INSERT_DEF = new_definition `x INSERT s = \y:A. y IN s \/ (y = x)`;; (* ------------------------------------------------------------------------- *) (* The other basic operations. *) (* ------------------------------------------------------------------------- *) let UNIV = new_definition `UNIV = (\x:A. T)`;; let UNION = new_definition `s UNION t = {x:A | x IN s \/ x IN t}`;; let UNIONS = new_definition `UNIONS s = {x:A | ?u. u IN s /\ x IN u}`;; let INTER = new_definition `s INTER t = {x:A | x IN s /\ x IN t}`;; let INTERS = new_definition `INTERS s = {x:A | !u. u IN s ==> x IN u}`;; let DIFF = new_definition `s DIFF t = {x:A | x IN s /\ ~(x IN t)}`;; let INSERT = prove (`x INSERT s = {y:A | y IN s \/ (y = x)}`, REWRITE_TAC[EXTENSION; INSERT_DEF; IN_ELIM_THM]);; let DELETE = new_definition `s DELETE x = {y:A | y IN s /\ ~(y = x)}`;; (* ------------------------------------------------------------------------- *) (* Other basic predicates. *) (* ------------------------------------------------------------------------- *) let SUBSET = new_definition `s SUBSET t <=> !x:A. x IN s ==> x IN t`;; let PSUBSET = new_definition `(s:A->bool) PSUBSET t <=> s SUBSET t /\ ~(s = t)`;; let DISJOINT = new_definition `DISJOINT (s:A->bool) t <=> (s INTER t = EMPTY)`;; let SING = new_definition `SING s = ?x:A. s = {x}`;; (* ------------------------------------------------------------------------- *) (* Finiteness. *) (* ------------------------------------------------------------------------- *) let FINITE_RULES,FINITE_INDUCT,FINITE_CASES = new_inductive_definition `FINITE (EMPTY:A->bool) /\ !(x:A) s. FINITE s ==> FINITE (x INSERT s)`;; let INFINITE = new_definition `INFINITE (s:A->bool) <=> ~(FINITE s)`;; (* ------------------------------------------------------------------------- *) (* Stuff concerned with functions. *) (* ------------------------------------------------------------------------- *) let IMAGE = new_definition `IMAGE (f:A->B) s = { y | ?x. x IN s /\ (y = f x)}`;; let INJ = new_definition `INJ (f:A->B) s t <=> (!x. x IN s ==> (f x) IN t) /\ (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y))`;; let SURJ = new_definition `SURJ (f:A->B) s t <=> (!x. x IN s ==> (f x) IN t) /\ (!x. (x IN t) ==> ?y. y IN s /\ (f y = x))`;; let BIJ = new_definition `BIJ (f:A->B) s t <=> INJ f s t /\ SURJ f s t`;; (* ------------------------------------------------------------------------- *) (* Another funny thing. *) (* ------------------------------------------------------------------------- *) let CHOICE = new_definition `CHOICE s = @x:A. x IN s`;; let REST = new_definition `REST (s:A->bool) = s DELETE (CHOICE s)`;; (* ------------------------------------------------------------------------- *) (* Basic membership properties. *) (* ------------------------------------------------------------------------- *) let NOT_IN_EMPTY = prove (`!x:A. ~(x IN EMPTY)`, REWRITE_TAC[IN; EMPTY]);; let IN_UNIV = prove (`!x:A. x IN UNIV`, REWRITE_TAC[UNIV; IN]);; let IN_UNION = prove (`!s t (x:A). x IN (s UNION t) <=> x IN s \/ x IN t`, REWRITE_TAC[IN_ELIM_THM; UNION]);; let IN_UNIONS = prove (`!s (x:A). x IN (UNIONS s) <=> ?t. t IN s /\ x IN t`, REWRITE_TAC[IN_ELIM_THM; UNIONS]);; let IN_INTER = prove (`!s t (x:A). x IN (s INTER t) <=> x IN s /\ x IN t`, REWRITE_TAC[IN_ELIM_THM; INTER]);; let IN_INTERS = prove (`!s (x:A). x IN (INTERS s) <=> !t. t IN s ==> x IN t`, REWRITE_TAC[IN_ELIM_THM; INTERS]);; let IN_DIFF = prove (`!(s:A->bool) t x. x IN (s DIFF t) <=> x IN s /\ ~(x IN t)`, REWRITE_TAC[IN_ELIM_THM; DIFF]);; let IN_INSERT = prove (`!x:A. !y s. x IN (y INSERT s) <=> (x = y) \/ x IN s`, ONCE_REWRITE_TAC[DISJ_SYM] THEN REWRITE_TAC[IN_ELIM_THM; INSERT]);; let IN_DELETE = prove (`!s. !x:A. !y. x IN (s DELETE y) <=> x IN s /\ ~(x = y)`, REWRITE_TAC[IN_ELIM_THM; DELETE]);; let IN_SING = prove (`!x y. x IN {y:A} <=> (x = y)`, REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY]);; let IN_IMAGE = prove (`!y:B. !s f. (y IN (IMAGE f s)) <=> ?x:A. (y = f x) /\ x IN s`, ONCE_REWRITE_TAC[CONJ_SYM] THEN REWRITE_TAC[IN_ELIM_THM; IMAGE]);; let IN_REST = prove (`!x:A. !s. x IN (REST s) <=> x IN s /\ ~(x = CHOICE s)`, REWRITE_TAC[REST; IN_DELETE]);; let FORALL_IN_INSERT = prove (`!P a s. (!x. x IN (a INSERT s) ==> P x) <=> P a /\ (!x. x IN s ==> P x)`, REWRITE_TAC[IN_INSERT] THEN MESON_TAC[]);; let EXISTS_IN_INSERT = prove (`!P a s. (?x. x IN (a INSERT s) /\ P x) <=> P a \/ ?x. x IN s /\ P x`, REWRITE_TAC[IN_INSERT] THEN MESON_TAC[]);; (* ------------------------------------------------------------------------- *) (* Basic property of the choice function. *) (* ------------------------------------------------------------------------- *) let CHOICE_DEF = prove (`!s:A->bool. ~(s = EMPTY) ==> (CHOICE s) IN s`, REWRITE_TAC[CHOICE; EXTENSION; NOT_IN_EMPTY; NOT_FORALL_THM; EXISTS_THM]);; (* ------------------------------------------------------------------------- *) (* Tactic to automate some routine set theory by reduction to FOL. *) (* ------------------------------------------------------------------------- *) let SET_TAC = let PRESET_TAC = TRY(POP_ASSUM_LIST(MP_TAC o end_itlist CONJ)) THEN REPEAT COND_CASES_TAC THEN REWRITE_TAC[EXTENSION; SUBSET; PSUBSET; DISJOINT; SING] THEN REWRITE_TAC[NOT_IN_EMPTY; IN_UNIV; IN_UNION; IN_INTER; IN_DIFF; IN_INSERT; IN_DELETE; IN_REST; IN_INTERS; IN_UNIONS; IN_IMAGE; IN_ELIM_THM; IN] in fun ths -> PRESET_TAC THEN (if ths = [] then ALL_TAC else MP_TAC(end_itlist CONJ ths)) THEN MESON_TAC[];; let SET_RULE tm = prove(tm,SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Misc. theorems. *) (* ------------------------------------------------------------------------- *) let NOT_EQUAL_SETS = prove (`!s:A->bool. !t. ~(s = t) <=> ?x. x IN t <=> ~(x IN s)`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* The empty set. *) (* ------------------------------------------------------------------------- *) let MEMBER_NOT_EMPTY = prove (`!s:A->bool. (?x. x IN s) <=> ~(s = EMPTY)`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* The universal set. *) (* ------------------------------------------------------------------------- *) let UNIV_NOT_EMPTY = prove (`~(UNIV:A->bool = EMPTY)`, SET_TAC[]);; let EMPTY_NOT_UNIV = prove (`~(EMPTY:A->bool = UNIV)`, SET_TAC[]);; let EQ_UNIV = prove (`(!x:A. x IN s) <=> (s = UNIV)`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Set inclusion. *) (* ------------------------------------------------------------------------- *) let SUBSET_TRANS = prove (`!(s:A->bool) t u. s SUBSET t /\ t SUBSET u ==> s SUBSET u`, SET_TAC[]);; let SUBSET_REFL = prove (`!s:A->bool. s SUBSET s`, SET_TAC[]);; let SUBSET_ANTISYM = prove (`!(s:A->bool) t. s SUBSET t /\ t SUBSET s ==> s = t`, SET_TAC[]);; let SUBSET_ANTISYM_EQ = prove (`!(s:A->bool) t. s SUBSET t /\ t SUBSET s <=> s = t`, SET_TAC[]);; let EMPTY_SUBSET = prove (`!s:A->bool. EMPTY SUBSET s`, SET_TAC[]);; let SUBSET_EMPTY = prove (`!s:A->bool. s SUBSET EMPTY <=> (s = EMPTY)`, SET_TAC[]);; let SUBSET_UNIV = prove (`!s:A->bool. s SUBSET UNIV`, SET_TAC[]);; let UNIV_SUBSET = prove (`!s:A->bool. UNIV SUBSET s <=> (s = UNIV)`, SET_TAC[]);; let SING_SUBSET = prove (`!s x. {x} SUBSET s <=> x IN s`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Proper subset. *) (* ------------------------------------------------------------------------- *) let PSUBSET_TRANS = prove (`!(s:A->bool) t u. s PSUBSET t /\ t PSUBSET u ==> s PSUBSET u`, SET_TAC[]);; let PSUBSET_SUBSET_TRANS = prove (`!(s:A->bool) t u. s PSUBSET t /\ t SUBSET u ==> s PSUBSET u`, SET_TAC[]);; let SUBSET_PSUBSET_TRANS = prove (`!(s:A->bool) t u. s SUBSET t /\ t PSUBSET u ==> s PSUBSET u`, SET_TAC[]);; let PSUBSET_IRREFL = prove (`!s:A->bool. ~(s PSUBSET s)`, SET_TAC[]);; let NOT_PSUBSET_EMPTY = prove (`!s:A->bool. ~(s PSUBSET EMPTY)`, SET_TAC[]);; let NOT_UNIV_PSUBSET = prove (`!s:A->bool. ~(UNIV PSUBSET s)`, SET_TAC[]);; let PSUBSET_UNIV = prove (`!s:A->bool. s PSUBSET UNIV <=> ?x. ~(x IN s)`, SET_TAC[]);; let PSUBSET_ALT = prove (`!s t:A->bool. s PSUBSET t <=> s SUBSET t /\ (?a. a IN t /\ ~(a IN s))`, REWRITE_TAC[PSUBSET] THEN SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Union. *) (* ------------------------------------------------------------------------- *) let UNION_ASSOC = prove (`!(s:A->bool) t u. (s UNION t) UNION u = s UNION (t UNION u)`, SET_TAC[]);; let UNION_IDEMPOT = prove (`!s:A->bool. s UNION s = s`, SET_TAC[]);; let UNION_COMM = prove (`!(s:A->bool) t. s UNION t = t UNION s`, SET_TAC[]);; let SUBSET_UNION = prove (`(!s:A->bool. !t. s SUBSET (s UNION t)) /\ (!s:A->bool. !t. s SUBSET (t UNION s))`, SET_TAC[]);; let SUBSET_UNION_ABSORPTION = prove (`!s:A->bool. !t. s SUBSET t <=> (s UNION t = t)`, SET_TAC[]);; let UNION_EMPTY = prove (`(!s:A->bool. EMPTY UNION s = s) /\ (!s:A->bool. s UNION EMPTY = s)`, SET_TAC[]);; let UNION_UNIV = prove (`(!s:A->bool. UNIV UNION s = UNIV) /\ (!s:A->bool. s UNION UNIV = UNIV)`, SET_TAC[]);; let EMPTY_UNION = prove (`!s:A->bool. !t. (s UNION t = EMPTY) <=> (s = EMPTY) /\ (t = EMPTY)`, SET_TAC[]);; let UNION_SUBSET = prove (`!s t u. (s UNION t) SUBSET u <=> s SUBSET u /\ t SUBSET u`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Intersection. *) (* ------------------------------------------------------------------------- *) let INTER_ASSOC = prove (`!(s:A->bool) t u. (s INTER t) INTER u = s INTER (t INTER u)`, SET_TAC[]);; let INTER_IDEMPOT = prove (`!s:A->bool. s INTER s = s`, SET_TAC[]);; let INTER_COMM = prove (`!(s:A->bool) t. s INTER t = t INTER s`, SET_TAC[]);; let INTER_SUBSET = prove (`(!s:A->bool. !t. (s INTER t) SUBSET s) /\ (!s:A->bool. !t. (t INTER s) SUBSET s)`, SET_TAC[]);; let SUBSET_INTER_ABSORPTION = prove (`!s:A->bool. !t. s SUBSET t <=> (s INTER t = s)`, SET_TAC[]);; let INTER_EMPTY = prove (`(!s:A->bool. EMPTY INTER s = EMPTY) /\ (!s:A->bool. s INTER EMPTY = EMPTY)`, SET_TAC[]);; let INTER_UNIV = prove (`(!s:A->bool. UNIV INTER s = s) /\ (!s:A->bool. s INTER UNIV = s)`, SET_TAC[]);; let SUBSET_INTER = prove (`!s t u. s SUBSET (t INTER u) <=> s SUBSET t /\ s SUBSET u`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Distributivity. *) (* ------------------------------------------------------------------------- *) let UNION_OVER_INTER = prove (`!s:A->bool. !t u. s INTER (t UNION u) = (s INTER t) UNION (s INTER u)`, SET_TAC[]);; let INTER_OVER_UNION = prove (`!s:A->bool. !t u. s UNION (t INTER u) = (s UNION t) INTER (s UNION u)`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Disjoint sets. *) (* ------------------------------------------------------------------------- *) let IN_DISJOINT = prove (`!s:A->bool. !t. DISJOINT s t <=> ~(?x. x IN s /\ x IN t)`, SET_TAC[]);; let DISJOINT_SYM = prove (`!s:A->bool. !t. DISJOINT s t <=> DISJOINT t s`, SET_TAC[]);; let DISJOINT_EMPTY = prove (`!s:A->bool. DISJOINT EMPTY s /\ DISJOINT s EMPTY`, SET_TAC[]);; let DISJOINT_EMPTY_REFL = prove (`!s:A->bool. (s = EMPTY) <=> (DISJOINT s s)`, SET_TAC[]);; let DISJOINT_UNION = prove (`!s:A->bool. !t u. DISJOINT (s UNION t) u <=> DISJOINT s u /\ DISJOINT t u`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Set difference. *) (* ------------------------------------------------------------------------- *) let DIFF_EMPTY = prove (`!s:A->bool. s DIFF EMPTY = s`, SET_TAC[]);; let EMPTY_DIFF = prove (`!s:A->bool. EMPTY DIFF s = EMPTY`, SET_TAC[]);; let DIFF_UNIV = prove (`!s:A->bool. s DIFF UNIV = EMPTY`, SET_TAC[]);; let DIFF_DIFF = prove (`!s:A->bool. !t. (s DIFF t) DIFF t = s DIFF t`, SET_TAC[]);; let DIFF_EQ_EMPTY = prove (`!s:A->bool. s DIFF s = EMPTY`, SET_TAC[]);; let SUBSET_DIFF = prove (`!s t. (s DIFF t) SUBSET s`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Insertsion and deletion. *) (* ------------------------------------------------------------------------- *) let COMPONENT = prove (`!x:A. !s. x IN (x INSERT s)`, SET_TAC[]);; let DECOMPOSITION = prove (`!s:A->bool. !x. x IN s <=> ?t. (s = x INSERT t) /\ ~(x IN t)`, REPEAT GEN_TAC THEN EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[IN_INSERT] THEN EXISTS_TAC `s DELETE x:A` THEN POP_ASSUM MP_TAC THEN SET_TAC[]);; let SET_CASES = prove (`!s:A->bool. (s = EMPTY) \/ ?x:A. ?t. (s = x INSERT t) /\ ~(x IN t)`, MESON_TAC[MEMBER_NOT_EMPTY; DECOMPOSITION]);; let ABSORPTION = prove (`!x:A. !s. x IN s <=> (x INSERT s = s)`, SET_TAC[]);; let INSERT_INSERT = prove (`!x:A. !s. x INSERT (x INSERT s) = x INSERT s`, SET_TAC[]);; let INSERT_COMM = prove (`!x:A. !y s. x INSERT (y INSERT s) = y INSERT (x INSERT s)`, SET_TAC[]);; let INSERT_UNIV = prove (`!x:A. x INSERT UNIV = UNIV`, SET_TAC[]);; let NOT_INSERT_EMPTY = prove (`!x:A. !s. ~(x INSERT s = EMPTY)`, SET_TAC[]);; let NOT_EMPTY_INSERT = prove (`!x:A. !s. ~(EMPTY = x INSERT s)`, SET_TAC[]);; let INSERT_UNION = prove (`!x:A. !s t. (x INSERT s) UNION t = if x IN t then s UNION t else x INSERT (s UNION t)`, REPEAT GEN_TAC THEN COND_CASES_TAC THEN POP_ASSUM MP_TAC THEN SET_TAC[]);; let INSERT_UNION_EQ = prove (`!x:A. !s t. (x INSERT s) UNION t = x INSERT (s UNION t)`, SET_TAC[]);; let INSERT_INTER = prove (`!x:A. !s t. (x INSERT s) INTER t = if x IN t then x INSERT (s INTER t) else s INTER t`, REPEAT GEN_TAC THEN COND_CASES_TAC THEN POP_ASSUM MP_TAC THEN SET_TAC[]);; let DISJOINT_INSERT = prove (`!(x:A) s t. DISJOINT (x INSERT s) t <=> (DISJOINT s t) /\ ~(x IN t)`, SET_TAC[]);; let INSERT_SUBSET = prove (`!x:A. !s t. (x INSERT s) SUBSET t <=> (x IN t /\ s SUBSET t)`, SET_TAC[]);; let SUBSET_INSERT = prove (`!x:A. !s. ~(x IN s) ==> !t. s SUBSET (x INSERT t) <=> s SUBSET t`, SET_TAC[]);; let INSERT_DIFF = prove (`!s t. !x:A. (x INSERT s) DIFF t = if x IN t then s DIFF t else x INSERT (s DIFF t)`, REPEAT GEN_TAC THEN COND_CASES_TAC THEN POP_ASSUM MP_TAC THEN SET_TAC[]);; let INSERT_AC = prove (`(x INSERT (y INSERT s) = y INSERT (x INSERT s)) /\ (x INSERT (x INSERT s) = x INSERT s)`, REWRITE_TAC[INSERT_COMM; INSERT_INSERT]);; let INTER_ACI = prove (`(p INTER q = q INTER p) /\ ((p INTER q) INTER r = p INTER q INTER r) /\ (p INTER q INTER r = q INTER p INTER r) /\ (p INTER p = p) /\ (p INTER p INTER q = p INTER q)`, SET_TAC[]);; let UNION_ACI = prove (`(p UNION q = q UNION p) /\ ((p UNION q) UNION r = p UNION q UNION r) /\ (p UNION q UNION r = q UNION p UNION r) /\ (p UNION p = p) /\ (p UNION p UNION q = p UNION q)`, SET_TAC[]);; let DELETE_NON_ELEMENT = prove (`!x:A. !s. ~(x IN s) <=> (s DELETE x = s)`, SET_TAC[]);; let IN_DELETE_EQ = prove (`!s x. !x':A. (x IN s <=> x' IN s) <=> (x IN (s DELETE x') <=> x' IN (s DELETE x))`, SET_TAC[]);; let EMPTY_DELETE = prove (`!x:A. EMPTY DELETE x = EMPTY`, SET_TAC[]);; let DELETE_DELETE = prove (`!x:A. !s. (s DELETE x) DELETE x = s DELETE x`, SET_TAC[]);; let DELETE_COMM = prove (`!x:A. !y. !s. (s DELETE x) DELETE y = (s DELETE y) DELETE x`, SET_TAC[]);; let DELETE_SUBSET = prove (`!x:A. !s. (s DELETE x) SUBSET s`, SET_TAC[]);; let SUBSET_DELETE = prove (`!x:A. !s t. s SUBSET (t DELETE x) <=> ~(x IN s) /\ (s SUBSET t)`, SET_TAC[]);; let SUBSET_INSERT_DELETE = prove (`!x:A. !s t. s SUBSET (x INSERT t) <=> ((s DELETE x) SUBSET t)`, SET_TAC[]);; let DIFF_INSERT = prove (`!s t. !x:A. s DIFF (x INSERT t) = (s DELETE x) DIFF t`, SET_TAC[]);; let PSUBSET_INSERT_SUBSET = prove (`!s t. s PSUBSET t <=> ?x:A. ~(x IN s) /\ (x INSERT s) SUBSET t`, SET_TAC[]);; let PSUBSET_MEMBER = prove (`!s:A->bool. !t. s PSUBSET t <=> (s SUBSET t /\ ?y. y IN t /\ ~(y IN s))`, SET_TAC[]);; let DELETE_INSERT = prove (`!x:A. !y s. (x INSERT s) DELETE y = if x = y then s DELETE y else x INSERT (s DELETE y)`, REPEAT GEN_TAC THEN COND_CASES_TAC THEN POP_ASSUM MP_TAC THEN SET_TAC[]);; let INSERT_DELETE = prove (`!x:A. !s. x IN s ==> (x INSERT (s DELETE x) = s)`, SET_TAC[]);; let DELETE_INTER = prove (`!s t. !x:A. (s DELETE x) INTER t = (s INTER t) DELETE x`, SET_TAC[]);; let DISJOINT_DELETE_SYM = prove (`!s t. !x:A. DISJOINT (s DELETE x) t = DISJOINT (t DELETE x) s`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Multiple union. *) (* ------------------------------------------------------------------------- *) let UNIONS_0 = prove (`UNIONS {} = {}`, SET_TAC[]);; let UNIONS_1 = prove (`UNIONS {s} = s`, SET_TAC[]);; let UNIONS_2 = prove (`UNIONS {s,t} = s UNION t`, SET_TAC[]);; let UNIONS_INSERT = prove (`UNIONS (s INSERT u) = s UNION (UNIONS u)`, SET_TAC[]);; let FORALL_IN_UNIONS = prove (`!P s. (!x. x IN UNIONS s ==> P x) <=> !t x. t IN s /\ x IN t ==> P x`, SET_TAC[]);; let EXISTS_IN_UNIONS = prove (`!P s. (?x. x IN UNIONS s /\ P x) <=> (?t x. t IN s /\ x IN t /\ P x)`, SET_TAC[]);; let EMPTY_UNIONS = prove (`!s. (UNIONS s = {}) <=> !t. t IN s ==> t = {}`, SET_TAC[]);; let INTER_UNIONS = prove (`(!s t. UNIONS s INTER t = UNIONS {x INTER t | x IN s}) /\ (!s t. t INTER UNIONS s = UNIONS {t INTER x | x IN s})`, ONCE_REWRITE_TAC[EXTENSION] THEN REWRITE_TAC[IN_UNIONS; IN_ELIM_THM; IN_INTER] THEN MESON_TAC[IN_INTER]);; let UNIONS_SUBSET = prove (`!f t. UNIONS f SUBSET t <=> !s. s IN f ==> s SUBSET t`, SET_TAC[]);; let SUBSET_UNIONS = prove (`!f g. f SUBSET g ==> UNIONS f SUBSET UNIONS g`, SET_TAC[]);; let UNIONS_UNION = prove (`!s t. UNIONS(s UNION t) = (UNIONS s) UNION (UNIONS t)`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Multiple intersection. *) (* ------------------------------------------------------------------------- *) let INTERS_0 = prove (`INTERS {} = (:A)`, SET_TAC[]);; let INTERS_1 = prove (`INTERS {s} = s`, SET_TAC[]);; let INTERS_2 = prove (`INTERS {s,t} = s INTER t`, SET_TAC[]);; let INTERS_INSERT = prove (`INTERS (s INSERT u) = s INTER (INTERS u)`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Image. *) (* ------------------------------------------------------------------------- *) let IMAGE_CLAUSES = prove (`(IMAGE f {} = {}) /\ (IMAGE f (x INSERT s) = (f x) INSERT (IMAGE f s))`, REWRITE_TAC[IMAGE; IN_ELIM_THM; NOT_IN_EMPTY; IN_INSERT; EXTENSION] THEN MESON_TAC[]);; let IMAGE_UNION = prove (`!f s t. IMAGE f (s UNION t) = (IMAGE f s) UNION (IMAGE f t)`, REWRITE_TAC[EXTENSION; IN_IMAGE; IN_UNION] THEN MESON_TAC[]);; let IMAGE_ID = prove (`!s. IMAGE (\x. x) s = s`, REWRITE_TAC[EXTENSION; IN_IMAGE; UNWIND_THM1]);; let IMAGE_I = prove (`!s. IMAGE I s = s`, REWRITE_TAC[I_DEF; IMAGE_ID]);; let IMAGE_o = prove (`!f g s. IMAGE (f o g) s = IMAGE f (IMAGE g s)`, REWRITE_TAC[EXTENSION; IN_IMAGE; o_THM] THEN MESON_TAC[]);; let IMAGE_SUBSET = prove (`!f s t. s SUBSET t ==> (IMAGE f s) SUBSET (IMAGE f t)`, REWRITE_TAC[SUBSET; IN_IMAGE] THEN MESON_TAC[]);; let IMAGE_INTER_INJ = prove (`!f s t. (!x y. (f(x) = f(y)) ==> (x = y)) ==> (IMAGE f (s INTER t) = (IMAGE f s) INTER (IMAGE f t))`, REWRITE_TAC[EXTENSION; IN_IMAGE; IN_INTER] THEN MESON_TAC[]);; let IMAGE_DIFF_INJ = prove (`!f s t. (!x y. (f(x) = f(y)) ==> (x = y)) ==> (IMAGE f (s DIFF t) = (IMAGE f s) DIFF (IMAGE f t))`, REWRITE_TAC[EXTENSION; IN_IMAGE; IN_DIFF] THEN MESON_TAC[]);; let IMAGE_DELETE_INJ = prove (`!f s a. (!x. (f(x) = f(a)) ==> (x = a)) ==> (IMAGE f (s DELETE a) = (IMAGE f s) DELETE (f a))`, REWRITE_TAC[EXTENSION; IN_IMAGE; IN_DELETE] THEN MESON_TAC[]);; let IMAGE_EQ_EMPTY = prove (`!f s. (IMAGE f s = {}) <=> (s = {})`, REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_IMAGE] THEN MESON_TAC[]);; let FORALL_IN_IMAGE = prove (`!f s. (!y. y IN IMAGE f s ==> P y) <=> (!x. x IN s ==> P(f x))`, REWRITE_TAC[IN_IMAGE] THEN MESON_TAC[]);; let EXISTS_IN_IMAGE = prove (`!f s. (?y. y IN IMAGE f s /\ P y) <=> ?x. x IN s /\ P(f x)`, REWRITE_TAC[IN_IMAGE] THEN MESON_TAC[]);; let SUBSET_IMAGE = prove (`!f:A->B s t. s SUBSET (IMAGE f t) <=> ?u. u SUBSET t /\ (s = IMAGE f u)`, REPEAT GEN_TAC THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[IMAGE_SUBSET]] THEN DISCH_TAC THEN EXISTS_TAC `{x | x IN t /\ (f:A->B) x IN s}` THEN POP_ASSUM MP_TAC THEN REWRITE_TAC[EXTENSION; SUBSET; IN_IMAGE; IN_ELIM_THM] THEN MESON_TAC[]);; let IMAGE_CONST = prove (`!s c. IMAGE (\x. c) s = if s = {} then {} else {c}`, REPEAT GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[IMAGE_CLAUSES] THEN REWRITE_TAC[EXTENSION; IN_IMAGE; IN_SING] THEN ASM_MESON_TAC[MEMBER_NOT_EMPTY]);; let SIMPLE_IMAGE = prove (`!f s. {f x | x IN s} = IMAGE f s`, REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_IMAGE] THEN MESON_TAC[]);; let SIMPLE_IMAGE_GEN = prove (`!f p. {f x | P x} = IMAGE f {x | P x}`, SET_TAC[]);; let IMAGE_UNIONS = prove (`!f s. IMAGE f (UNIONS s) = UNIONS (IMAGE (IMAGE f) s)`, ONCE_REWRITE_TAC[EXTENSION] THEN REWRITE_TAC[IN_UNIONS; IN_IMAGE] THEN REWRITE_TAC[LEFT_AND_EXISTS_THM] THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN REWRITE_TAC[GSYM CONJ_ASSOC; UNWIND_THM2; IN_IMAGE] THEN MESON_TAC[]);; let FUN_IN_IMAGE = prove (`!f s x. x IN s ==> f(x) IN IMAGE f s`, SET_TAC[]);; let SURJECTIVE_IMAGE_EQ = prove (`!s t. (!y. y IN t ==> ?x. f x = y) /\ (!x. (f x) IN t <=> x IN s) ==> IMAGE f s = t`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Misc lemmas. *) (* ------------------------------------------------------------------------- *) let EMPTY_GSPEC = prove (`{x | F} = {}`, SET_TAC[]);; let SING_GSPEC = prove (`(!a. {x | x = a} = {a}) /\ (!a. {x | a = x} = {a})`, SET_TAC[]);; let IN_ELIM_PAIR_THM = prove (`!P a b. (a,b) IN {(x,y) | P x y} <=> P a b`, REWRITE_TAC[IN_ELIM_THM] THEN MESON_TAC[PAIR_EQ]);; let FORALL_IN_GSPEC = prove (`(!P f. (!z. z IN {f x | P x} ==> Q z) <=> (!x. P x ==> Q(f x))) /\ (!P f. (!z. z IN {f x y | P x y} ==> Q z) <=> (!x y. P x y ==> Q(f x y))) /\ (!P f. (!z. z IN {f w x y | P w x y} ==> Q z) <=> (!w x y. P w x y ==> Q(f w x y)))`, SET_TAC[]);; let EXISTS_IN_GSPEC = prove (`(!P f. (?z. z IN {f x | P x} /\ Q z) <=> (?x. P x /\ Q(f x))) /\ (!P f. (?z. z IN {f x y | P x y} /\ Q z) <=> (?x y. P x y /\ Q(f x y))) /\ (!P f. (?z. z IN {f w x y | P w x y} /\ Q z) <=> (?w x y. P w x y /\ Q(f w x y)))`, SET_TAC[]);; (* ------------------------------------------------------------------------- *) (* Stronger form of induction is sometimes handy. *) (* ------------------------------------------------------------------------- *) let FINITE_INDUCT_STRONG = prove (`!P:(A->bool)->bool. P {} /\ (!x s. P s /\ ~(x IN s) /\ FINITE s ==> P(x INSERT s)) ==> !s. FINITE s ==> P s`, GEN_TAC THEN STRIP_TAC THEN SUBGOAL_THEN `!s:A->bool. FINITE s ==> FINITE s /\ P s` MP_TAC THENL [ALL_TAC; MESON_TAC[]] THEN MATCH_MP_TAC FINITE_INDUCT THEN ASM_SIMP_TAC[FINITE_RULES] THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_CASES_TAC `x:A IN s` THENL [SUBGOAL_THEN `x:A INSERT s = s` (fun th -> ASM_REWRITE_TAC[th]) THEN UNDISCH_TAC `x:A IN s` THEN SET_TAC[]; FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]]);; (* ------------------------------------------------------------------------- *) (* Basic combining theorems for finite sets. *) (* ------------------------------------------------------------------------- *) let FINITE_EMPTY = prove (`FINITE {}`, REWRITE_TAC[FINITE_RULES]);; let FINITE_SUBSET = prove (`!(s:A->bool) t. FINITE t /\ s SUBSET t ==> FINITE s`, ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN REWRITE_TAC[IMP_CONJ] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT THEN CONJ_TAC THENL [MESON_TAC[SUBSET_EMPTY; FINITE_RULES]; ALL_TAC] THEN X_GEN_TAC `x:A` THEN X_GEN_TAC `u:A->bool` THEN DISCH_TAC THEN X_GEN_TAC `t:A->bool` THEN DISCH_TAC THEN SUBGOAL_THEN `FINITE((x:A) INSERT (t DELETE x))` ASSUME_TAC THENL [MATCH_MP_TAC(CONJUNCT2 FINITE_RULES) THEN FIRST_ASSUM MATCH_MP_TAC THEN UNDISCH_TAC `t SUBSET (x:A INSERT u)` THEN SET_TAC[]; ASM_CASES_TAC `x:A IN t` THENL [SUBGOAL_THEN `x:A INSERT (t DELETE x) = t` SUBST_ALL_TAC THENL [UNDISCH_TAC `x:A IN t` THEN SET_TAC[]; ASM_REWRITE_TAC[]]; FIRST_ASSUM MATCH_MP_TAC THEN UNDISCH_TAC `t SUBSET x:A INSERT u` THEN UNDISCH_TAC `~(x:A IN t)` THEN SET_TAC[]]]);; let FINITE_UNION_IMP = prove (`!(s:A->bool) t. FINITE s /\ FINITE t ==> FINITE (s UNION t)`, REWRITE_TAC[IMP_CONJ] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT THEN REWRITE_TAC[UNION_EMPTY] THEN SUBGOAL_THEN `!x s t. (x:A INSERT s) UNION t = x INSERT (s UNION t)` (fun th -> REWRITE_TAC[th]) THENL [SET_TAC[]; MESON_TAC[FINITE_RULES]]);; let FINITE_UNION = prove (`!(s:A->bool) t. FINITE(s UNION t) <=> FINITE(s) /\ FINITE(t)`, REPEAT GEN_TAC THEN EQ_TAC THENL [REPEAT STRIP_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `(s:A->bool) UNION t` THEN ASM_REWRITE_TAC[] THEN SET_TAC[]; MATCH_ACCEPT_TAC FINITE_UNION_IMP]);; let FINITE_INTER = prove (`!(s:A->bool) t. FINITE s \/ FINITE t ==> FINITE (s INTER t)`, MESON_TAC[INTER_SUBSET; FINITE_SUBSET]);; let FINITE_INSERT = prove (`!(s:A->bool) x. FINITE (x INSERT s) <=> FINITE s`, REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THENL [MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `x:A INSERT s` THEN ASM_REWRITE_TAC[] THEN SET_TAC[]; MATCH_MP_TAC(CONJUNCT2 FINITE_RULES) THEN ASM_REWRITE_TAC[]]);; let FINITE_SING = prove (`!a. FINITE {a}`, REWRITE_TAC[FINITE_INSERT; FINITE_RULES]);; let FINITE_DELETE_IMP = prove (`!(s:A->bool) x. FINITE s ==> FINITE (s DELETE x)`, REPEAT STRIP_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN ASM_REWRITE_TAC[] THEN SET_TAC[]);; let FINITE_DELETE = prove (`!(s:A->bool) x. FINITE (s DELETE x) <=> FINITE s`, REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[FINITE_DELETE_IMP] THEN ASM_CASES_TAC `x:A IN s` THENL [SUBGOAL_THEN `s = x INSERT (s DELETE x:A)` (fun th -> GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [th]) THEN REWRITE_TAC[FINITE_INSERT] THEN POP_ASSUM MP_TAC THEN SET_TAC[]; SUBGOAL_THEN `s DELETE x:A = s` (fun th -> REWRITE_TAC[th]) THEN POP_ASSUM MP_TAC THEN SET_TAC[]]);; let FINITE_UNIONS = prove (`!s. FINITE(s) ==> (FINITE(UNIONS s) <=> (!t. t IN s ==> FINITE(t)))`, MATCH_MP_TAC FINITE_INDUCT THEN REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; UNIONS_0; UNIONS_INSERT] THEN REWRITE_TAC[FINITE_UNION; FINITE_RULES] THEN MESON_TAC[]);; let FINITE_IMAGE_EXPAND = prove (`!(f:A->B) s. FINITE s ==> FINITE {y | ?x. x IN s /\ (y = f x)}`, GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT THEN REWRITE_TAC[NOT_IN_EMPTY; REWRITE_RULE[] EMPTY_GSPEC; FINITE_RULES] THEN REPEAT GEN_TAC THEN SUBGOAL_THEN `{y | ?z. z IN (x INSERT s) /\ (y = (f:A->B) z)} = {y | ?z. z IN s /\ (y = f z)} UNION {(f x)}` (fun th -> REWRITE_TAC[th]) THENL [REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INSERT; IN_UNION; NOT_IN_EMPTY] THEN MESON_TAC[]; REWRITE_TAC[FINITE_UNION; FINITE_INSERT; FINITE_RULES]]);; let FINITE_IMAGE = prove (`!(f:A->B) s. FINITE s ==> FINITE (IMAGE f s)`, REWRITE_TAC[IMAGE; FINITE_IMAGE_EXPAND]);; let FINITE_IMAGE_INJ_GENERAL = prove (`!(f:A->B) A s. (!x y. x IN s /\ y IN s /\ (f(x) = f(y)) ==> (x = y)) /\ FINITE A ==> FINITE {x | x IN s /\ f(x) IN A}`, GEN_TAC THEN ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN DISCH_TAC THEN MATCH_MP_TAC FINITE_INDUCT THEN CONJ_TAC THENL [SUBGOAL_THEN `{x | x IN s /\ (f:A->B) x IN EMPTY} = EMPTY` SUBST1_TAC THEN REWRITE_TAC[FINITE_RULES] THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY]; ALL_TAC] THEN X_GEN_TAC `y:B` THEN X_GEN_TAC `t:B->bool` THEN DISCH_TAC THEN SUBGOAL_THEN `{x | x IN s /\ (f:A->B) x IN (y INSERT t)} = if (?x. x IN s /\ (f x = y)) then (@x. x IN s /\ (f x = y)) INSERT {x | x IN s /\ f x IN t} else {x | x IN s /\ f x IN t}` SUBST1_TAC THENL [ALL_TAC; COND_CASES_TAC THEN ASM_REWRITE_TAC[FINITE_INSERT]] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INSERT] THENL [ALL_TAC; ASM_MESON_TAC[]] THEN FIRST_ASSUM(MP_TAC o SELECT_RULE) THEN ABBREV_TAC `z = @x. x IN s /\ ((f:A->B) x = y)` THEN ASM_MESON_TAC[]);; let FINITE_FINITE_PREIMAGE_GENERAL = prove (`!f:A->B s t. FINITE t /\ (!y. y IN t ==> FINITE {x | x IN s /\ f(x) = y}) ==> FINITE {x | x IN s /\ f(x) IN t}`, REPEAT STRIP_TAC THEN SUBGOAL_THEN `{x | x IN s /\ (f:A->B)(x) IN t} = UNIONS (IMAGE (\a. {x | x IN s /\ f x = a}) t)` SUBST1_TAC THENL [GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[IN_ELIM_THM; IN_UNIONS] THEN REWRITE_TAC[EXISTS_IN_IMAGE] THEN SET_TAC[]; ASM_SIMP_TAC[FINITE_UNIONS; FINITE_IMAGE; FORALL_IN_IMAGE]]);; let FINITE_FINITE_PREIMAGE = prove (`!f:A->B t. FINITE t /\ (!y. y IN t ==> FINITE {x | f(x) = y}) ==> FINITE {x | f(x) IN t}`, REPEAT GEN_TAC THEN MP_TAC (ISPECL [`f:A->B`; `(:A)`; `t:B->bool`] FINITE_FINITE_PREIMAGE_GENERAL) THEN REWRITE_TAC[IN_UNIV]);; let FINITE_IMAGE_INJ_EQ = prove (`!(f:A->B) s. (!x y. x IN s /\ y IN s /\ (f(x) = f(y)) ==> (x = y)) ==> (FINITE(IMAGE f s) <=> FINITE s)`, REPEAT STRIP_TAC THEN EQ_TAC THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN POP_ASSUM MP_TAC THEN REWRITE_TAC[IMP_IMP] THEN DISCH_THEN(MP_TAC o MATCH_MP FINITE_IMAGE_INJ_GENERAL) THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN SET_TAC[]);; let FINITE_IMAGE_INJ = prove (`!(f:A->B) A. (!x y. (f(x) = f(y)) ==> (x = y)) /\ FINITE A ==> FINITE {x | f(x) IN A}`, REPEAT GEN_TAC THEN MP_TAC(SPECL [`f:A->B`; `A:B->bool`; `UNIV:A->bool`] FINITE_IMAGE_INJ_GENERAL) THEN REWRITE_TAC[IN_UNIV]);; let INFINITE_IMAGE_INJ = prove (`!f:A->B. (!x y. (f x = f y) ==> (x = y)) ==> !s. INFINITE s ==> INFINITE(IMAGE f s)`, GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN REWRITE_TAC[INFINITE; CONTRAPOS_THM] THEN DISCH_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `{x | f(x) IN IMAGE (f:A->B) s}` THEN CONJ_TAC THENL [MATCH_MP_TAC FINITE_IMAGE_INJ THEN ASM_REWRITE_TAC[]; REWRITE_TAC[SUBSET; IN_ELIM_THM; IMAGE] THEN MESON_TAC[]]);; let INFINITE_NONEMPTY = prove (`!s. INFINITE(s) ==> ~(s = EMPTY)`, MESON_TAC[INFINITE; FINITE_RULES]);; let INFINITE_DIFF_FINITE = prove (`!s:A->bool t. INFINITE(s) /\ FINITE(t) ==> INFINITE(s DIFF t)`, REPEAT GEN_TAC THEN MATCH_MP_TAC(TAUT `(b /\ ~c ==> ~a) ==> a /\ b ==> c`) THEN REWRITE_TAC[INFINITE] THEN STRIP_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `(t:A->bool) UNION (s DIFF t)` THEN ASM_REWRITE_TAC[FINITE_UNION] THEN SET_TAC[]);; let FINITE_SUBSET_IMAGE = prove (`!f:A->B s t. FINITE(t) /\ t SUBSET (IMAGE f s) <=> ?s'. FINITE s' /\ s' SUBSET s /\ (t = IMAGE f s')`, REPEAT GEN_TAC THEN EQ_TAC THENL [ALL_TAC; ASM_MESON_TAC[FINITE_IMAGE; IMAGE_SUBSET]] THEN STRIP_TAC THEN EXISTS_TAC `IMAGE (\y. @x. x IN s /\ ((f:A->B)(x) = y)) t` THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN REWRITE_TAC[EXTENSION; SUBSET; FORALL_IN_IMAGE] THEN CONJ_TAC THENL [ASM_MESON_TAC[SUBSET; IN_IMAGE]; ALL_TAC] THEN REWRITE_TAC[IN_IMAGE] THEN X_GEN_TAC `y:B` THEN REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN ONCE_REWRITE_TAC[SWAP_EXISTS_THM] THEN ONCE_REWRITE_TAC[CONJ_SYM] THEN REWRITE_TAC[UNWIND_THM2; GSYM CONJ_ASSOC] THEN ASM_MESON_TAC[SUBSET; IN_IMAGE]);; let FINITE_SUBSET_IMAGE_IMP = prove (`!f:A->B s t. FINITE(t) /\ t SUBSET (IMAGE f s) ==> ?s'. FINITE s' /\ s' SUBSET s /\ t SUBSET (IMAGE f s')`, MESON_TAC[SUBSET_REFL; FINITE_SUBSET_IMAGE]);; let FINITE_SUBSETS = prove (`!s:A->bool. FINITE(s) ==> FINITE {t | t SUBSET s}`, MATCH_MP_TAC FINITE_INDUCT THEN CONJ_TAC THENL [SUBGOAL_THEN `{t:A->bool | t SUBSET {}} = {{}}` (fun th -> SIMP_TAC[th; FINITE_RULES]) THEN REWRITE_TAC[SUBSET_EMPTY] THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INSERT; NOT_IN_EMPTY]; MAP_EVERY X_GEN_TAC [`x:A`; `s:A->bool`] THEN SUBGOAL_THEN `{t | t SUBSET x INSERT s} = {t | t SUBSET s} UNION (IMAGE (\u. x:A INSERT u) {t | t SUBSET s})` (fun th -> SIMP_TAC[th; FINITE_UNION; FINITE_IMAGE]) THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INSERT; IN_UNION; IN_IMAGE; SUBSET] THEN X_GEN_TAC `t:A->bool` THEN EQ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN DISCH_TAC THEN ASM_CASES_TAC `x:A IN s` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN ASM_CASES_TAC `x:A IN t` THENL [ALL_TAC; ASM_MESON_TAC[]] THEN DISJ2_TAC THEN EXISTS_TAC `s:A->bool INTER t` THEN ASM_MESON_TAC[IN_INTER]]);; let FINITE_DIFF = prove (`!s t. FINITE s ==> FINITE(s DIFF t)`, MESON_TAC[FINITE_SUBSET; SUBSET_DIFF]);; (* ------------------------------------------------------------------------- *) (* Recursion over finite sets; based on Ching-Tsun's code (archive 713). *) (* ------------------------------------------------------------------------- *) let FINREC = new_recursive_definition num_RECURSION `(FINREC (f:A->B->B) b s a 0 <=> (s = {}) /\ (a = b)) /\ (FINREC (f:A->B->B) b s a (SUC n) <=> ?x c. x IN s /\ FINREC f b (s DELETE x) c n /\ (a = f x c))`;; let FINREC_1_LEMMA = prove (`!f b s a. FINREC f b s a (SUC 0) <=> ?x. (s = {x}) /\ (a = f x b)`, REWRITE_TAC[FINREC] THEN REPEAT GEN_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN SET_TAC[]);; let FINREC_SUC_LEMMA = prove (`!(f:A->B->B) b. (!x y s. ~(x = y) ==> (f x (f y s) = f y (f x s))) ==> !n s z. FINREC f b s z (SUC n) ==> !x. x IN s ==> ?w. FINREC f b (s DELETE x) w n /\ (z = f x w)`, let lem = prove(`s DELETE (x:A) DELETE y = s DELETE y DELETE x`,SET_TAC[]) in REPEAT GEN_TAC THEN DISCH_TAC THEN INDUCT_TAC THENL [REWRITE_TAC[FINREC_1_LEMMA] THEN REWRITE_TAC[FINREC] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN DISCH_THEN SUBST1_TAC THEN EXISTS_TAC `b:B` THEN ASM_REWRITE_TAC[] THEN SET_TAC[]; REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [FINREC] THEN DISCH_THEN(X_CHOOSE_THEN `y:A` MP_TAC) THEN DISCH_THEN(X_CHOOSE_THEN `c:B` STRIP_ASSUME_TAC) THEN X_GEN_TAC `x:A` THEN DISCH_TAC THEN ASM_CASES_TAC `x:A = y` THEN ASM_REWRITE_TAC[] THENL [EXISTS_TAC `c:B` THEN ASM_REWRITE_TAC[]; UNDISCH_TAC `FINREC (f:A->B->B) b (s DELETE y) c (SUC n)` THEN DISCH_THEN(ANTE_RES_THEN (MP_TAC o SPEC `x:A`)) THEN ASM_REWRITE_TAC[IN_DELETE] THEN DISCH_THEN(X_CHOOSE_THEN `v:B` STRIP_ASSUME_TAC) THEN EXISTS_TAC `(f:A->B->B) y v` THEN ASM_REWRITE_TAC[FINREC] THEN CONJ_TAC THENL [MAP_EVERY EXISTS_TAC [`y:A`; `v:B`] THEN ONCE_REWRITE_TAC[lem] THEN ASM_REWRITE_TAC[IN_DELETE]; FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]]]]);; let FINREC_UNIQUE_LEMMA = prove (`!(f:A->B->B) b. (!x y s. ~(x = y) ==> (f x (f y s) = f y (f x s))) ==> !n1 n2 s a1 a2. FINREC f b s a1 n1 /\ FINREC f b s a2 n2 ==> (a1 = a2) /\ (n1 = n2)`, REPEAT GEN_TAC THEN DISCH_TAC THEN INDUCT_TAC THEN INDUCT_TAC THENL [REWRITE_TAC[FINREC] THEN MESON_TAC[NOT_IN_EMPTY]; REWRITE_TAC[FINREC] THEN MESON_TAC[NOT_IN_EMPTY]; REWRITE_TAC[FINREC] THEN MESON_TAC[NOT_IN_EMPTY]; IMP_RES_THEN ASSUME_TAC FINREC_SUC_LEMMA THEN REPEAT GEN_TAC THEN DISCH_THEN(fun th -> MP_TAC(CONJUNCT1 th) THEN MP_TAC th) THEN DISCH_THEN(CONJUNCTS_THEN (ANTE_RES_THEN ASSUME_TAC)) THEN REWRITE_TAC[FINREC] THEN STRIP_TAC THEN ASM_MESON_TAC[]]);; let FINREC_EXISTS_LEMMA = prove (`!(f:A->B->B) b s. FINITE s ==> ?a n. FINREC f b s a n`, let lem = prove(`~(x IN s ) ==> ((x:A INSERT s) DELETE x = s)`,SET_TAC[]) in GEN_TAC THEN GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REPEAT STRIP_TAC THENL [MAP_EVERY EXISTS_TAC [`b:B`; `0`] THEN REWRITE_TAC[FINREC]; MAP_EVERY EXISTS_TAC [`(f:A->B->B) x a`; `SUC n`] THEN REWRITE_TAC[FINREC] THEN MAP_EVERY EXISTS_TAC [`x:A`; `a:B`] THEN FIRST_ASSUM(fun th -> ASM_REWRITE_TAC[MATCH_MP lem th; IN_INSERT])]);; let FINREC_FUN_LEMMA = prove (`!P (R:A->B->C->bool). (!s. P s ==> ?a n. R s a n) /\ (!n1 n2 s a1 a2. R s a1 n1 /\ R s a2 n2 ==> (a1 = a2) /\ (n1 = n2)) ==> ?f. !s a. P s ==> ((?n. R s a n) <=> (f s = a))`, REPEAT STRIP_TAC THEN EXISTS_TAC `\s:A. @a:B. ?n:C. R s a n` THEN REPEAT STRIP_TAC THEN BETA_TAC THEN EQ_TAC THENL [STRIP_TAC THEN MATCH_MP_TAC SELECT_UNIQUE THEN ASM_MESON_TAC[]; DISCH_THEN(SUBST1_TAC o SYM) THEN CONV_TAC SELECT_CONV THEN ASM_MESON_TAC[]]);; let FINREC_FUN = prove (`!(f:A->B->B) b. (!x y s. ~(x = y) ==> (f x (f y s) = f y (f x s))) ==> ?g. (g {} = b) /\ !s x. FINITE s /\ x IN s ==> (g s = f x (g (s DELETE x)))`, REPEAT STRIP_TAC THEN IMP_RES_THEN MP_TAC FINREC_UNIQUE_LEMMA THEN DISCH_THEN(MP_TAC o SPEC `b:B`) THEN DISCH_THEN (MP_TAC o CONJ (SPECL [`f:A->B->B`; `b:B`] FINREC_EXISTS_LEMMA)) THEN DISCH_THEN(MP_TAC o MATCH_MP FINREC_FUN_LEMMA) THEN DISCH_THEN(X_CHOOSE_TAC `g:(A->bool)->B`) THEN EXISTS_TAC `g:(A->bool)->B` THEN CONJ_TAC THENL [SUBGOAL_THEN `FINITE(EMPTY:A->bool)` (ANTE_RES_THEN (fun th -> GEN_REWRITE_TAC I [GSYM th])) THENL [REWRITE_TAC[FINITE_RULES]; EXISTS_TAC `0` THEN REWRITE_TAC[FINREC]]; REPEAT STRIP_TAC THEN ANTE_RES_THEN MP_TAC (ASSUME `FINITE(s:A->bool)`) THEN DISCH_THEN(ASSUME_TAC o GSYM) THEN ASM_REWRITE_TAC[] THEN FIRST_ASSUM(MP_TAC o SPEC `(g:(A->bool)->B) s`) THEN REWRITE_TAC[] THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN INDUCT_TAC THENL [ASM_REWRITE_TAC[FINREC] THEN DISCH_TAC THEN UNDISCH_TAC `x:A IN s` THEN ASM_REWRITE_TAC[NOT_IN_EMPTY]; IMP_RES_THEN ASSUME_TAC FINREC_SUC_LEMMA THEN DISCH_THEN(ANTE_RES_THEN (MP_TAC o SPEC `x:A`)) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `w:B` (CONJUNCTS_THEN ASSUME_TAC)) THEN SUBGOAL_THEN `(g (s DELETE x:A) = w:B)` SUBST1_TAC THENL [SUBGOAL_THEN `FINITE(s DELETE x:A)` MP_TAC THENL [MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `s:A->bool` THEN ASM_REWRITE_TAC[] THEN SET_TAC[]; DISCH_THEN(ANTE_RES_THEN (MP_TAC o GSYM)) THEN DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN EXISTS_TAC `n:num` THEN ASM_REWRITE_TAC[]]; ASM_REWRITE_TAC[]]]]);; let SET_RECURSION_LEMMA = prove (`!(f:A->B->B) b. (!x y s. ~(x = y) ==> (f x (f y s) = f y (f x s))) ==> ?g. (g {} = b) /\ !x s. FINITE s ==> (g (x INSERT s) = if x IN s then g s else f x (g s))`, REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o SPEC `b:B` o MATCH_MP FINREC_FUN) THEN DISCH_THEN(X_CHOOSE_THEN `g:(A->bool)->B` STRIP_ASSUME_TAC) THEN EXISTS_TAC `g:(A->bool)->B` THEN ASM_REWRITE_TAC[] THEN REPEAT GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THENL [AP_TERM_TAC THEN REWRITE_TAC[GSYM ABSORPTION] THEN ASM_REWRITE_TAC[]; SUBGOAL_THEN `FINITE(x:A INSERT s) /\ x IN (x INSERT s)` MP_TAC THENL [REWRITE_TAC[IN_INSERT] THEN ASM_MESON_TAC[FINITE_RULES]; DISCH_THEN(ANTE_RES_THEN SUBST1_TAC) THEN REPEAT AP_TERM_TAC THEN UNDISCH_TAC `~(x:A IN s)` THEN SET_TAC[]]]);; let ITSET = new_definition `ITSET f s b = (@g. (g {} = b) /\ !x s. FINITE s ==> (g (x INSERT s) = if x IN s then g s else f x (g s))) s`;; let FINITE_RECURSION = prove (`!(f:A->B->B) b. (!x y s. ~(x = y) ==> (f x (f y s) = f y (f x s))) ==> (ITSET f {} b = b) /\ !x s. FINITE s ==> (ITSET f (x INSERT s) b = if x IN s then ITSET f s b else f x (ITSET f s b))`, REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[ITSET] THEN CONV_TAC SELECT_CONV THEN MATCH_MP_TAC SET_RECURSION_LEMMA THEN ASM_REWRITE_TAC[]);; let FINITE_RECURSION_DELETE = prove (`!(f:A->B->B) b. (!x y s. ~(x = y) ==> (f x (f y s) = f y (f x s))) ==> (ITSET f {} b = b) /\ !x s. FINITE s ==> (ITSET f s b = if x IN s then f x (ITSET f (s DELETE x) b) else ITSET f (s DELETE x) b)`, REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP FINITE_RECURSION) THEN DISCH_THEN(STRIP_ASSUME_TAC o SPEC `b:B`) THEN ASM_REWRITE_TAC[] THEN REPEAT GEN_TAC THEN ASM_CASES_TAC `x:A IN s` THEN ASM_REWRITE_TAC[] THENL [DISCH_THEN(MP_TAC o MATCH_MP FINITE_DELETE_IMP) THEN DISCH_THEN(ANTE_RES_THEN MP_TAC o SPEC `x:A`) THEN DISCH_THEN(MP_TAC o SPEC `x:A`) THEN REWRITE_TAC[IN_DELETE] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN AP_THM_TAC THEN AP_TERM_TAC THEN UNDISCH_TAC `x:A IN s` THEN SET_TAC[]; DISCH_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN UNDISCH_TAC `~(x:A IN s)` THEN SET_TAC[]]);; let ITSET_EQ = prove (`!s f g b. FINITE(s) /\ (!x. x IN s ==> (f x = g x)) /\ (!x y s. ~(x = y) ==> (f x (f y s) = f y (f x s))) /\ (!x y s. ~(x = y) ==> (g x (g y s) = g y (g x s))) ==> (ITSET f s b = ITSET g s b)`, ONCE_REWRITE_TAC[IMP_CONJ] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[FINITE_RECURSION; NOT_IN_EMPTY; IN_INSERT] THEN REPEAT STRIP_TAC THEN AP_TERM_TAC THEN FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[RIGHT_IMP_FORALL_THM]) THEN ASM_MESON_TAC[]);; let SUBSET_RESTRICT = prove (`!s P. {x | x IN s /\ P x} SUBSET s`, SIMP_TAC[SUBSET; IN_ELIM_THM]);; let FINITE_RESTRICT = prove (`!s:A->bool P. FINITE s ==> FINITE {x | x IN s /\ P x}`, MESON_TAC[SUBSET_RESTRICT; FINITE_SUBSET]);; (* ------------------------------------------------------------------------- *) (* Cardinality. *) (* ------------------------------------------------------------------------- *) let CARD = new_definition `CARD s = ITSET (\x n. SUC n) s 0`;; let CARD_CLAUSES = prove (`(CARD ({}:A->bool) = 0) /\ (!(x:A) s. FINITE s ==> (CARD (x INSERT s) = if x IN s then CARD s else SUC(CARD s)))`, MP_TAC(ISPECL [`\(x:A) n. SUC n`; `0`] FINITE_RECURSION) THEN REWRITE_TAC[CARD]);; let CARD_UNION = prove (`!(s:A->bool) t. FINITE(s) /\ FINITE(t) /\ (s INTER t = EMPTY) ==> (CARD (s UNION t) = CARD s + CARD t)`, REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> a ==> b /\ c ==> d`] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[UNION_EMPTY; CARD_CLAUSES; INTER_EMPTY; ADD_CLAUSES] THEN X_GEN_TAC `x:A` THEN X_GEN_TAC `s:A->bool` THEN REPEAT STRIP_TAC THEN SUBGOAL_THEN `(x:A INSERT s) UNION t = x INSERT (s UNION t)` SUBST1_TAC THENL [SET_TAC[]; ALL_TAC] THEN SUBGOAL_THEN `FINITE ((s:A->bool) UNION t) /\ FINITE s` STRIP_ASSUME_TAC THENL [ASM_REWRITE_TAC[] THEN MATCH_MP_TAC FINITE_UNION_IMP THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN MP_TAC(ISPECL [`x:A`; `s:A->bool`] (CONJUNCT2 CARD_CLAUSES)) THEN MP_TAC(ISPECL [`x:A`; `s:A->bool UNION t`] (CONJUNCT2 CARD_CLAUSES)) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN SUBGOAL_THEN `~(x:A IN (s UNION t))` ASSUME_TAC THENL [ASM_REWRITE_TAC[IN_UNION] THEN UNDISCH_TAC `(x:A INSERT s) INTER t = EMPTY` THEN REWRITE_TAC[EXTENSION; IN_INSERT; IN_INTER; NOT_IN_EMPTY] THEN MESON_TAC[]; ASM_REWRITE_TAC[SUC_INJ; ADD_CLAUSES] THEN FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN UNDISCH_TAC `x:A INSERT s INTER t = EMPTY` THEN SET_TAC[]]);; let CARD_DELETE = prove (`!x:A s. FINITE(s) ==> (CARD(s DELETE x) = if x IN s then CARD(s) - 1 else CARD(s))`, REPEAT STRIP_TAC THEN COND_CASES_TAC THENL [SUBGOAL_THEN `s = x:A INSERT (s DELETE x)` (fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [th]) THENL [UNDISCH_TAC `x:A IN s` THEN SET_TAC[]; ALL_TAC] THEN ASM_SIMP_TAC[CARD_CLAUSES; FINITE_DELETE; IN_DELETE] THEN ARITH_TAC; AP_TERM_TAC THEN UNDISCH_TAC `~(x:A IN s)` THEN SET_TAC[]]);; let CARD_UNION_EQ = prove (`!s t u. FINITE u /\ (s INTER t = {}) /\ (s UNION t = u) ==> (CARD s + CARD t = CARD u)`, MESON_TAC[CARD_UNION; FINITE_SUBSET; SUBSET_UNION]);; let CARD_DIFF = prove (`!s t. FINITE s /\ t SUBSET s ==> CARD(s DIFF t) = CARD s - CARD t`, REPEAT STRIP_TAC THEN MATCH_MP_TAC(ARITH_RULE `a + b:num = c ==> a = c - b`) THEN MATCH_MP_TAC CARD_UNION_EQ THEN ASM_SIMP_TAC[] THEN ASM SET_TAC[]);; let CARD_EQ_0 = prove (`!s. FINITE s ==> ((CARD s = 0) <=> (s = {}))`, MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[CARD_CLAUSES; NOT_INSERT_EMPTY; NOT_SUC]);; (* ------------------------------------------------------------------------- *) (* A stronger still form of induction where we get to choose the element. *) (* ------------------------------------------------------------------------- *) let FINITE_INDUCT_DELETE = prove (`!P. P {} /\ (!s. FINITE s /\ ~(s = {}) ==> ?x. x IN s /\ (P(s DELETE x) ==> P s)) ==> !s:A->bool. FINITE s ==> P s`, GEN_TAC THEN STRIP_TAC THEN GEN_TAC THEN WF_INDUCT_TAC `CARD(s:A->bool)` THEN ASM_CASES_TAC `s:A->bool = {}` THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN UNDISCH_TAC `!s. FINITE s /\ ~(s = {}) ==> ?x:A. x IN s /\ (P(s DELETE x) ==> P s)` THEN DISCH_THEN(MP_TAC o SPEC `s:A->bool`) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `x:A` (CONJUNCTS_THEN2 ASSUME_TAC MATCH_MP_TAC)) THEN FIRST_X_ASSUM(MP_TAC o SPEC `s DELETE (x:A)`) THEN ASM_SIMP_TAC[FINITE_DELETE; CARD_DELETE; CARD_EQ_0; ARITH_RULE `n - 1 < n <=> ~(n = 0)`]);; (* ------------------------------------------------------------------------- *) (* Relational form is often more useful. *) (* ------------------------------------------------------------------------- *) let HAS_SIZE = new_definition `s HAS_SIZE n <=> FINITE s /\ (CARD s = n)`;; let HAS_SIZE_CARD = prove (`!s n. s HAS_SIZE n ==> (CARD s = n)`, SIMP_TAC[HAS_SIZE]);; let HAS_SIZE_0 = prove (`!(s:A->bool) n. s HAS_SIZE 0 <=> (s = {})`, REPEAT GEN_TAC THEN REWRITE_TAC[HAS_SIZE] THEN EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[FINITE_RULES; CARD_CLAUSES] THEN FIRST_ASSUM(MP_TAC o CONJUNCT2) THEN FIRST_ASSUM(MP_TAC o CONJUNCT1) THEN SPEC_TAC(`s:A->bool`,`s:A->bool`) THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[NOT_INSERT_EMPTY] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP (CONJUNCT2 CARD_CLAUSES) th]) THEN ASM_REWRITE_TAC[NOT_SUC]);; let HAS_SIZE_SUC = prove (`!(s:A->bool) n. s HAS_SIZE (SUC n) <=> ~(s = {}) /\ !a. a IN s ==> (s DELETE a) HAS_SIZE n`, REPEAT GEN_TAC THEN REWRITE_TAC[HAS_SIZE] THEN ASM_CASES_TAC `s:A->bool = {}` THEN ASM_REWRITE_TAC[CARD_CLAUSES; FINITE_RULES; NOT_IN_EMPTY; NOT_SUC] THEN REWRITE_TAC[FINITE_DELETE] THEN ASM_CASES_TAC `FINITE(s:A->bool)` THEN ASM_REWRITE_TAC[NOT_FORALL_THM; MEMBER_NOT_EMPTY] THEN EQ_TAC THEN REPEAT STRIP_TAC THENL [MP_TAC(ISPECL [`a:A`; `s DELETE a:A`] (CONJUNCT2 CARD_CLAUSES)) THEN ASM_REWRITE_TAC[FINITE_DELETE; IN_DELETE] THEN SUBGOAL_THEN `a INSERT (s DELETE a:A) = s` SUBST1_TAC THENL [UNDISCH_TAC `a:A IN s` THEN SET_TAC[]; ASM_REWRITE_TAC[SUC_INJ] THEN MESON_TAC[]]; FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN DISCH_THEN(X_CHOOSE_TAC `a:A`) THEN MP_TAC(ISPECL [`a:A`; `s DELETE a:A`] (CONJUNCT2 CARD_CLAUSES)) THEN ASM_REWRITE_TAC[FINITE_DELETE; IN_DELETE] THEN SUBGOAL_THEN `a INSERT (s DELETE a:A) = s` SUBST1_TAC THENL [UNDISCH_TAC `a:A IN s` THEN SET_TAC[]; ASM_MESON_TAC[]]]);; let HAS_SIZE_UNION = prove (`!s t m n. s HAS_SIZE m /\ t HAS_SIZE n /\ DISJOINT s t ==> (s UNION t) HAS_SIZE (m + n)`, SIMP_TAC[HAS_SIZE; FINITE_UNION; DISJOINT; CARD_UNION]);; let HAS_SIZE_DIFF = prove (`!s t m n. s HAS_SIZE m /\ t HAS_SIZE n /\ t SUBSET s ==> (s DIFF t) HAS_SIZE (m - n)`, SIMP_TAC[HAS_SIZE; FINITE_DIFF; CARD_DIFF]);; let HAS_SIZE_UNIONS = prove (`!s t:A->B->bool m n. s HAS_SIZE m /\ (!x. x IN s ==> t(x) HAS_SIZE n) /\ (!x y. x IN s /\ y IN s /\ ~(x = y) ==> DISJOINT (t x) (t y)) ==> UNIONS {t(x) | x IN s} HAS_SIZE (m * n)`, GEN_REWRITE_TAC (funpow 4 BINDER_CONV o funpow 2 LAND_CONV) [HAS_SIZE] THEN REWRITE_TAC[GSYM CONJ_ASSOC] THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN CONJ_TAC THENL [REPEAT GEN_TAC THEN REWRITE_TAC[CARD_CLAUSES] THEN DISCH_THEN(CONJUNCTS_THEN2 (SUBST1_TAC o SYM) (K ALL_TAC)) THEN REWRITE_TAC[MULT_CLAUSES; HAS_SIZE_0; EMPTY_UNIONS] THEN REWRITE_TAC[IN_ELIM_THM; NOT_IN_EMPTY]; ALL_TAC] THEN MAP_EVERY X_GEN_TAC [`x:A`; `s:A->bool`] THEN STRIP_TAC THEN MAP_EVERY X_GEN_TAC [`t:A->B->bool`; `m:num`; `n:num`] THEN ASM_SIMP_TAC[CARD_CLAUSES] THEN DISCH_THEN(CONJUNCTS_THEN2 (SUBST1_TAC o SYM) STRIP_ASSUME_TAC) THEN REWRITE_TAC[SET_RULE `UNIONS {t y | y IN x INSERT s} = t x UNION UNIONS {t y | y IN s}`] THEN REWRITE_TAC[ARITH_RULE `SUC a * b = b + a * b`] THEN MATCH_MP_TAC HAS_SIZE_UNION THEN ASM_SIMP_TAC[IN_INSERT] THEN REWRITE_TAC[SET_RULE `DISJOINT a (UNIONS s) <=> !x. x IN s ==> DISJOINT a x`] THEN ASM_SIMP_TAC[IN_ELIM_THM; LEFT_IMP_EXISTS_THM] THEN ASM_MESON_TAC[IN_INSERT]);; (* ------------------------------------------------------------------------- *) (* This is often more useful as a rewrite. *) (* ------------------------------------------------------------------------- *) let HAS_SIZE_CLAUSES = prove (`(s HAS_SIZE 0 <=> (s = {})) /\ (s HAS_SIZE (SUC n) <=> ?a t. t HAS_SIZE n /\ ~(a IN t) /\ (s = a INSERT t))`, let lemma = SET_RULE `a IN s ==> (s = a INSERT (s DELETE a))` in REWRITE_TAC[HAS_SIZE_0] THEN REPEAT STRIP_TAC THEN EQ_TAC THENL [REWRITE_TAC[HAS_SIZE_SUC; GSYM MEMBER_NOT_EMPTY] THEN MESON_TAC[lemma; IN_DELETE]; SIMP_TAC[LEFT_IMP_EXISTS_THM; HAS_SIZE; CARD_CLAUSES; FINITE_INSERT]]);; (* ------------------------------------------------------------------------- *) (* Produce an explicit expansion for "s HAS_SIZE n" for numeral n. *) (* ------------------------------------------------------------------------- *) let HAS_SIZE_CONV = let pth = prove (`(~(a IN {}) /\ P <=> P) /\ (~(a IN {b}) /\ P <=> ~(a = b) /\ P) /\ (~(a IN (b INSERT cs)) /\ P <=> ~(a = b) /\ ~(a IN cs) /\ P)`, SET_TAC[]) and qth = prove (`((?s. s HAS_SIZE 0 /\ P s) <=> P {}) /\ ((?s. s HAS_SIZE (SUC n) /\ P s) <=> (?a s. s HAS_SIZE n /\ ~(a IN s) /\ P(a INSERT s)))`, REWRITE_TAC[HAS_SIZE_CLAUSES] THEN MESON_TAC[]) in let qconv_0 = GEN_REWRITE_CONV I [CONJUNCT1 qth] and qconv_1 = GEN_REWRITE_CONV I [CONJUNCT2 qth] and rconv_0 = GEN_REWRITE_CONV I [CONJUNCT1 pth] and rconv_1 = GEN_REWRITE_CONV I [CONJUNCT2 pth] in let rec EXISTS_HAS_SIZE_AND_CONV tm = (qconv_0 ORELSEC (BINDER_CONV(LAND_CONV(RAND_CONV num_CONV)) THENC qconv_1 THENC BINDER_CONV EXISTS_HAS_SIZE_AND_CONV)) tm in let rec NOT_IN_INSERT_CONV tm = ((rconv_0 THENC NOT_IN_INSERT_CONV) ORELSEC (rconv_1 THENC RAND_CONV NOT_IN_INSERT_CONV) ORELSEC ALL_CONV) tm in let HAS_SIZE_CONV = GEN_REWRITE_CONV I [CONJUNCT1 HAS_SIZE_CLAUSES] ORELSEC (RAND_CONV num_CONV THENC GEN_REWRITE_CONV I [CONJUNCT2 HAS_SIZE_CLAUSES] THENC BINDER_CONV EXISTS_HAS_SIZE_AND_CONV) in fun tm -> let th = HAS_SIZE_CONV tm in let tm' = rand(concl th) in let evs,bod = strip_exists tm' in if evs = [] then th else let th' = funpow (length evs) BINDER_CONV NOT_IN_INSERT_CONV tm' in TRANS th th';; (* ------------------------------------------------------------------------- *) (* Various useful lemmas about cardinalities of unions etc. *) (* ------------------------------------------------------------------------- *) let CARD_SUBSET_EQ = prove (`!(a:A->bool) b. FINITE b /\ a SUBSET b /\ (CARD a = CARD b) ==> (a = b)`, REPEAT STRIP_TAC THEN MP_TAC(SPECL [`a:A->bool`; `b DIFF (a:A->bool)`] CARD_UNION) THEN SUBGOAL_THEN `FINITE(a:A->bool)` ASSUME_TAC THENL [ASM_MESON_TAC[FINITE_SUBSET]; ALL_TAC] THEN SUBGOAL_THEN `FINITE(b:A->bool DIFF a)` ASSUME_TAC THENL [MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `b:A->bool` THEN ASM_REWRITE_TAC[] THEN SET_TAC[]; ALL_TAC] THEN SUBGOAL_THEN `a:A->bool INTER (b DIFF a) = EMPTY` ASSUME_TAC THENL [SET_TAC[]; ALL_TAC] THEN ASM_REWRITE_TAC[] THEN SUBGOAL_THEN `a UNION (b:A->bool DIFF a) = b` ASSUME_TAC THENL [UNDISCH_TAC `a:A->bool SUBSET b` THEN SET_TAC[]; ALL_TAC] THEN ASM_REWRITE_TAC[] THEN REWRITE_TAC[ARITH_RULE `(a = a + b) <=> (b = 0)`] THEN DISCH_TAC THEN SUBGOAL_THEN `b:A->bool DIFF a = EMPTY` MP_TAC THENL [REWRITE_TAC[GSYM HAS_SIZE_0] THEN ASM_REWRITE_TAC[HAS_SIZE]; UNDISCH_TAC `a:A->bool SUBSET b` THEN SET_TAC[]]);; let CARD_SUBSET = prove (`!(a:A->bool) b. a SUBSET b /\ FINITE(b) ==> CARD(a) <= CARD(b)`, REPEAT STRIP_TAC THEN SUBGOAL_THEN `b:A->bool = a UNION (b DIFF a)` SUBST1_TAC THENL [UNDISCH_TAC `a:A->bool SUBSET b` THEN SET_TAC[]; ALL_TAC] THEN SUBGOAL_THEN `CARD (a UNION b DIFF a) = CARD(a:A->bool) + CARD(b DIFF a)` SUBST1_TAC THENL [MATCH_MP_TAC CARD_UNION THEN REPEAT CONJ_TAC THENL [MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `b:A->bool` THEN ASM_REWRITE_TAC[]; MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `b:A->bool` THEN ASM_REWRITE_TAC[] THEN SET_TAC[]; SET_TAC[]]; ARITH_TAC]);; let CARD_SUBSET_LE = prove (`!(a:A->bool) b. FINITE b /\ a SUBSET b /\ (CARD b <= CARD a) ==> (a = b)`, MESON_TAC[CARD_SUBSET; CARD_SUBSET_EQ; LE_ANTISYM]);; let SUBSET_CARD_EQ = prove (`!s t. FINITE t /\ s SUBSET t ==> (CARD s = CARD t <=> s = t)`, MESON_TAC[CARD_SUBSET_EQ; LE_ANTISYM; CARD_SUBSET]);; let CARD_PSUBSET = prove (`!(a:A->bool) b. a PSUBSET b /\ FINITE(b) ==> CARD(a) < CARD(b)`, REPEAT GEN_TAC THEN REWRITE_TAC[SET_RULE `a PSUBSET b <=> ?x. x IN b /\ ~(x IN a) /\ a SUBSET (b DELETE x)` ] THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN DISCH_THEN(X_CHOOSE_THEN `x:A` STRIP_ASSUME_TAC) THEN MATCH_MP_TAC LET_TRANS THEN EXISTS_TAC `CARD(b DELETE (x:A))` THEN ASM_SIMP_TAC[CARD_SUBSET; FINITE_DELETE] THEN ASM_SIMP_TAC[CARD_DELETE; ARITH_RULE `n - 1 < n <=> ~(n = 0)`] THEN ASM_MESON_TAC[CARD_EQ_0; MEMBER_NOT_EMPTY]);; let CARD_UNION_LE = prove (`!s t:A->bool. FINITE s /\ FINITE t ==> CARD(s UNION t) <= CARD(s) + CARD(t)`, REPEAT STRIP_TAC THEN MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `CARD(s:A->bool) + CARD(t DIFF s)` THEN ASM_SIMP_TAC[LE_ADD_LCANCEL; CARD_SUBSET; SUBSET_DIFF; FINITE_DIFF] THEN MATCH_MP_TAC EQ_IMP_LE THEN ONCE_REWRITE_TAC[SET_RULE `s UNION t = s UNION (t DIFF s)`] THEN MATCH_MP_TAC CARD_UNION THEN ASM_SIMP_TAC[FINITE_DIFF] THEN SET_TAC[]);; let CARD_UNIONS_LE = prove (`!s t:A->B->bool m n. s HAS_SIZE m /\ (!x. x IN s ==> FINITE(t x) /\ CARD(t x) <= n) ==> CARD(UNIONS {t(x) | x IN s}) <= m * n`, GEN_REWRITE_TAC (funpow 4 BINDER_CONV o funpow 2 LAND_CONV) [HAS_SIZE] THEN REWRITE_TAC[GSYM CONJ_ASSOC] THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN CONJ_TAC THEN REWRITE_TAC[SET_RULE `UNIONS {t x | x IN {}} = {}`; CARD_CLAUSES; LE_0] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN REPEAT GEN_TAC THEN ASM_SIMP_TAC[CARD_CLAUSES; FINITE_RULES] THEN DISCH_THEN(CONJUNCTS_THEN2 (SUBST_ALL_TAC o SYM) ASSUME_TAC) THEN REWRITE_TAC[SET_RULE `UNIONS {t x | x IN a INSERT s} = t(a) UNION UNIONS {t x | x IN s}`] THEN MATCH_MP_TAC LE_TRANS THEN EXISTS_TAC `CARD((t:A->B->bool) x) + CARD(UNIONS {(t:A->B->bool) y | y IN s})` THEN CONJ_TAC THENL [MATCH_MP_TAC CARD_UNION_LE THEN ASM_SIMP_TAC[IN_INSERT] THEN REWRITE_TAC[SET_RULE `{t x | x IN s} = IMAGE t s`] THEN ASM_SIMP_TAC[FINITE_UNIONS; FINITE_IMAGE; FORALL_IN_IMAGE; IN_INSERT]; MATCH_MP_TAC(ARITH_RULE `a <= n /\ b <= x * n ==> a + b <= SUC x * n`) THEN ASM_SIMP_TAC[IN_INSERT]]);; let CARD_UNION_GEN = prove (`!s t. FINITE s /\ FINITE t ==> CARD(s UNION t) = (CARD(s) + CARD(t)) - CARD(s INTER t)`, REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[SET_RULE `s UNION t = s UNION (t DIFF s)`] THEN ASM_SIMP_TAC[ARITH_RULE `x:num <= y ==> (a + y) - x = a + (y - x)`; CARD_SUBSET; INTER_SUBSET; GSYM CARD_DIFF] THEN REWRITE_TAC[SET_RULE `t DIFF (s INTER t) = t DIFF s`] THEN MATCH_MP_TAC CARD_UNION THEN ASM_SIMP_TAC[FINITE_DIFF] THEN SET_TAC[]);; let CARD_UNION_OVERLAP_EQ = prove (`!s t. FINITE s /\ FINITE t ==> (CARD(s UNION t) = CARD s + CARD t <=> s INTER t = {})`, REPEAT GEN_TAC THEN STRIP_TAC THEN ASM_SIMP_TAC[CARD_UNION_GEN] THEN REWRITE_TAC[ARITH_RULE `a - b = a <=> b = 0 \/ a = 0`] THEN ASM_SIMP_TAC[ADD_EQ_0; CARD_EQ_0; FINITE_INTER] THEN SET_TAC[]);; let CARD_UNION_OVERLAP = prove (`!s t. FINITE s /\ FINITE t /\ CARD(s UNION t) < CARD(s) + CARD(t) ==> ~(s INTER t = {})`, SIMP_TAC[GSYM CARD_UNION_OVERLAP_EQ] THEN ARITH_TAC);; (* ------------------------------------------------------------------------- *) (* Cardinality of image under injective map. *) (* ------------------------------------------------------------------------- *) let CARD_IMAGE_INJ = prove (`!(f:A->B) s. (!x y. x IN s /\ y IN s /\ (f(x) = f(y)) ==> (x = y)) /\ FINITE s ==> (CARD (IMAGE f s) = CARD s)`, GEN_TAC THEN REWRITE_TAC[TAUT `a /\ b ==> c <=> b ==> a ==> c`] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[NOT_IN_EMPTY; IMAGE_CLAUSES] THEN REPEAT STRIP_TAC THEN ASM_SIMP_TAC[CARD_CLAUSES; FINITE_IMAGE; IN_IMAGE] THEN COND_CASES_TAC THEN ASM_MESON_TAC[IN_INSERT]);; let HAS_SIZE_IMAGE_INJ = prove (`!(f:A->B) s n. (!x y. x IN s /\ y IN s /\ (f(x) = f(y)) ==> (x = y)) /\ s HAS_SIZE n ==> (IMAGE f s) HAS_SIZE n`, SIMP_TAC[HAS_SIZE; FINITE_IMAGE] THEN MESON_TAC[CARD_IMAGE_INJ]);; let CARD_IMAGE_LE = prove (`!(f:A->B) s. FINITE s ==> (CARD (IMAGE f s) <= CARD s)`, GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[IMAGE_CLAUSES; CARD_CLAUSES; FINITE_IMAGE; LE_REFL] THEN REPEAT GEN_TAC THEN COND_CASES_TAC THEN DISCH_THEN(MP_TAC o CONJUNCT1) THEN ARITH_TAC);; let CARD_IMAGE_INJ_EQ = prove (`!f:A->B s t. FINITE s /\ (!x. x IN s ==> f(x) IN t) /\ (!y. y IN t ==> ?!x. x IN s /\ f(x) = y) ==> CARD t = CARD s`, REPEAT STRIP_TAC THEN SUBGOAL_THEN `t = IMAGE (f:A->B) s` SUBST1_TAC THENL [REWRITE_TAC[EXTENSION; IN_IMAGE] THEN ASM_MESON_TAC[]; MATCH_MP_TAC CARD_IMAGE_INJ THEN ASM_MESON_TAC[]]);; (* ------------------------------------------------------------------------- *) (* Choosing a smaller subset of a given size. *) (* ------------------------------------------------------------------------- *) let CHOOSE_SUBSET = prove (`!s:A->bool. FINITE s ==> !n. n <= CARD s ==> ?t. t SUBSET s /\ t HAS_SIZE n`, MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[CARD_CLAUSES; SUBSET_EMPTY; FINITE_RULES; LE; HAS_SIZE_0] THEN REWRITE_TAC[EXISTS_REFL] THEN REPEAT STRIP_TAC THENL [EXISTS_TAC `(x:A) INSERT s` THEN ASM_SIMP_TAC[SUBSET_REFL; FINITE_RULES; HAS_SIZE; CARD_CLAUSES]; FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN ASM SET_TAC[]]);; (* ------------------------------------------------------------------------- *) (* Cardinality of product. *) (* ------------------------------------------------------------------------- *) let HAS_SIZE_PRODUCT_DEPENDENT = prove (`!s m t n. s HAS_SIZE m /\ (!x. x IN s ==> t(x) HAS_SIZE n) ==> {(x:A,y:B) | x IN s /\ y IN t(x)} HAS_SIZE (m * n)`, GEN_REWRITE_TAC (funpow 4 BINDER_CONV o funpow 2 LAND_CONV) [HAS_SIZE] THEN REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[CARD_CLAUSES; NOT_IN_EMPTY; IN_INSERT] THEN CONJ_TAC THENL [GEN_TAC THEN DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[MULT_CLAUSES; HAS_SIZE_0] THEN SET_TAC[]; ALL_TAC] THEN MAP_EVERY X_GEN_TAC [`x:A`; `s:A->bool`] THEN STRIP_TAC THEN X_GEN_TAC `m:num` THEN DISCH_THEN(ASSUME_TAC o SYM) THEN MAP_EVERY X_GEN_TAC [`t:A->B->bool`; `n:num`] THEN REWRITE_TAC[TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN SIMP_TAC[FORALL_AND_THM; LEFT_FORALL_IMP_THM; EXISTS_REFL] THEN STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `CARD(s:A->bool)`) THEN ASM_REWRITE_TAC[MULT_CLAUSES] THEN DISCH_TAC THEN REWRITE_TAC[SET_RULE `{(x,y) | (x = a \/ x IN s) /\ y IN t(x)} = {(x,y) | x IN s /\ y IN t(x)} UNION IMAGE (\y. (a,y)) (t a)`] THEN MATCH_MP_TAC HAS_SIZE_UNION THEN ASM_SIMP_TAC[HAS_SIZE_IMAGE_INJ; PAIR_EQ] THEN REWRITE_TAC[DISJOINT; IN_IMAGE; IN_ELIM_THM; IN_INTER; EXTENSION; NOT_IN_EMPTY; EXISTS_PAIR_THM; PAIR_EQ] THEN REPEAT STRIP_TAC THEN ASM_MESON_TAC[PAIR_EQ]);; let FINITE_PRODUCT_DEPENDENT = prove (`!s t. FINITE s /\ (!x. x IN s ==> FINITE(t x)) ==> FINITE {(x:A,y:B) | x IN s /\ y IN (t x)}`, REWRITE_TAC[IMP_CONJ] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN CONJ_TAC THENL [GEN_TAC THEN SUBGOAL_THEN `{(x:A,y:B) | x IN {} /\ y IN (t x)} = {}` (fun th -> REWRITE_TAC[th; FINITE_RULES]) THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY]; ALL_TAC] THEN MAP_EVERY X_GEN_TAC [`a:A`; `s:A->bool`] THEN STRIP_TAC THEN X_GEN_TAC `t:A->B->bool` THEN SUBGOAL_THEN `{(x:A,y:B) | x IN (a INSERT s) /\ y IN (t x)} = IMAGE (\y. a,y) (t a) UNION {(x,y) | x IN s /\ y IN (t x)}` (fun th -> ASM_SIMP_TAC[IN_INSERT; FINITE_IMAGE; FINITE_UNION; th]) THEN REWRITE_TAC[EXTENSION; IN_IMAGE; IN_ELIM_THM; IN_INSERT; IN_UNION] THEN MESON_TAC[]);; let FINITE_PRODUCT = prove (`!s t. FINITE s /\ FINITE t ==> FINITE {(x:A,y:B) | x IN s /\ y IN t}`, SIMP_TAC[FINITE_PRODUCT_DEPENDENT]);; let CARD_PRODUCT = prove (`!s t. FINITE s /\ FINITE t ==> (CARD {(x:A,y:B) | x IN s /\ y IN t} = CARD s * CARD t)`, REPEAT STRIP_TAC THEN MP_TAC(SPECL [`s:A->bool`; `CARD(s:A->bool)`; `\x:A. t:B->bool`; `CARD(t:B->bool)`] HAS_SIZE_PRODUCT_DEPENDENT) THEN ASM_SIMP_TAC[HAS_SIZE]);; let HAS_SIZE_PRODUCT = prove (`!s m t n. s HAS_SIZE m /\ t HAS_SIZE n ==> {(x:A,y:B) | x IN s /\ y IN t} HAS_SIZE (m * n)`, SIMP_TAC[HAS_SIZE; CARD_PRODUCT; FINITE_PRODUCT]);; (* ------------------------------------------------------------------------- *) (* Actually introduce a Cartesian product operation. *) (* ------------------------------------------------------------------------- *) parse_as_infix("CROSS",(22,"right"));; let CROSS = new_definition `s CROSS t = {x,y | x IN s /\ y IN t}`;; let IN_CROSS = prove (`!x y s t. (x,y) IN (s CROSS t) <=> x IN s /\ y IN t`, REWRITE_TAC[CROSS; IN_ELIM_PAIR_THM]);; let HAS_SIZE_CROSS = prove (`!s t m n. s HAS_SIZE m /\ t HAS_SIZE n ==> (s CROSS t) HAS_SIZE (m * n)`, REWRITE_TAC[CROSS; HAS_SIZE_PRODUCT]);; let FINITE_CROSS = prove (`!s t. FINITE s /\ FINITE t ==> FINITE(s CROSS t)`, SIMP_TAC[CROSS; FINITE_PRODUCT]);; let CARD_CROSS = prove (`!s t. FINITE s /\ FINITE t ==> CARD(s CROSS t) = CARD s * CARD t`, SIMP_TAC[CROSS; CARD_PRODUCT]);; (* ------------------------------------------------------------------------- *) (* Cardinality of functions with bounded domain (support) and range. *) (* ------------------------------------------------------------------------- *) let HAS_SIZE_FUNSPACE = prove (`!d n t:B->bool m s:A->bool. s HAS_SIZE m /\ t HAS_SIZE n ==> {f | (!x. x IN s ==> f(x) IN t) /\ (!x. ~(x IN s) ==> (f x = d))} HAS_SIZE (n EXP m)`, GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN INDUCT_TAC THEN REWRITE_TAC[HAS_SIZE_CLAUSES] THENL [REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[NOT_IN_EMPTY; EXP] THEN CONV_TAC HAS_SIZE_CONV THEN EXISTS_TAC `(\x. d):A->B` THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_SING] THEN REWRITE_TAC[FUN_EQ_THM]; REWRITE_TAC[LEFT_IMP_EXISTS_THM; LEFT_AND_EXISTS_THM]] THEN MAP_EVERY X_GEN_TAC [`s0:A->bool`; `a:A`; `s:A->bool`] THEN STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `s:A->bool`) THEN ASM_REWRITE_TAC[] THEN STRIP_TAC THEN SUBGOAL_THEN `{f:A->B | (!x. x IN a INSERT s ==> f x IN t) /\ (!x. ~(x IN a INSERT s) ==> (f x = d))} = IMAGE (\(b,g) x. if x = a then b else g(x)) {b,g | b IN t /\ g IN {f | (!x. x IN s ==> f x IN t) /\ (!x. ~(x IN s) ==> (f x = d))}}` SUBST1_TAC THENL [REWRITE_TAC[EXTENSION; IN_IMAGE; FORALL_PAIR_THM; IN_ELIM_THM; EXISTS_PAIR_THM] THEN REWRITE_TAC[PAIR_EQ; CONJ_ASSOC; ONCE_REWRITE_RULE[CONJ_SYM] UNWIND_THM1] THEN X_GEN_TAC `f:A->B` THEN REWRITE_TAC[IN_INSERT] THEN EQ_TAC THENL [STRIP_TAC THEN MAP_EVERY EXISTS_TAC [`(f:A->B) a`; `\x. if x IN s then (f:A->B) x else d`] THEN REWRITE_TAC[FUN_EQ_THM] THEN ASM_MESON_TAC[]; DISCH_THEN(X_CHOOSE_THEN `b:B` (X_CHOOSE_THEN `g:A->B` STRIP_ASSUME_TAC)) THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]]; ALL_TAC] THEN MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN ASM_SIMP_TAC[EXP; HAS_SIZE_PRODUCT] THEN REWRITE_TAC[FORALL_PAIR_THM; IN_ELIM_THM; PAIR_EQ; CONJ_ASSOC] THEN REWRITE_TAC[ONCE_REWRITE_RULE[CONJ_SYM] UNWIND_THM1] THEN CONV_TAC(ONCE_DEPTH_CONV GEN_BETA_CONV) THEN REWRITE_TAC[FUN_EQ_THM] THEN REPEAT GEN_TAC THEN STRIP_TAC THEN CONJ_TAC THENL [FIRST_X_ASSUM(MP_TAC o SPEC `a:A`) THEN REWRITE_TAC[]; X_GEN_TAC `x:A` THEN FIRST_X_ASSUM(MP_TAC o SPEC `x:A`) THEN ASM_MESON_TAC[]]);; let CARD_FUNSPACE = prove (`!s t. FINITE s /\ FINITE t ==> (CARD {f | (!x. x IN s ==> f(x) IN t) /\ (!x. ~(x IN s) ==> (f x = d))} = (CARD t) EXP (CARD s))`, MESON_TAC[HAS_SIZE_FUNSPACE; HAS_SIZE]);; let FINITE_FUNSPACE = prove (`!s t. FINITE s /\ FINITE t ==> FINITE {f | (!x. x IN s ==> f(x) IN t) /\ (!x. ~(x IN s) ==> (f x = d))}`, MESON_TAC[HAS_SIZE_FUNSPACE; HAS_SIZE]);; (* ------------------------------------------------------------------------- *) (* Hence cardinality of powerset. *) (* ------------------------------------------------------------------------- *) let HAS_SIZE_POWERSET = prove (`!(s:A->bool) n. s HAS_SIZE n ==> {t | t SUBSET s} HAS_SIZE (2 EXP n)`, REPEAT STRIP_TAC THEN SUBGOAL_THEN `{t | t SUBSET s} = {f | (!x:A. x IN s ==> f(x) IN UNIV) /\ (!x. ~(x IN s) ==> (f x = F))}` SUBST1_TAC THENL [REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_UNIV; SUBSET; IN; CONTRAPOS_THM]; MATCH_MP_TAC HAS_SIZE_FUNSPACE THEN ASM_REWRITE_TAC[] THEN CONV_TAC HAS_SIZE_CONV THEN MAP_EVERY EXISTS_TAC [`T`; `F`] THEN REWRITE_TAC[EXTENSION; IN_UNIV; IN_INSERT; NOT_IN_EMPTY] THEN CONV_TAC TAUT]);; let CARD_POWERSET = prove (`!s:A->bool. FINITE s ==> (CARD {t | t SUBSET s} = 2 EXP (CARD s))`, MESON_TAC[HAS_SIZE_POWERSET; HAS_SIZE]);; let FINITE_POWERSET = prove (`!s:A->bool. FINITE s ==> FINITE {t | t SUBSET s}`, MESON_TAC[HAS_SIZE_POWERSET; HAS_SIZE]);; (* ------------------------------------------------------------------------- *) (* Set of numbers is infinite. *) (* ------------------------------------------------------------------------- *) let HAS_SIZE_NUMSEG_LT = prove (`!n. {m | m < n} HAS_SIZE n`, INDUCT_TAC THENL [SUBGOAL_THEN `{m | m < 0} = {}` (fun th -> REWRITE_TAC[HAS_SIZE_0; th]) THEN REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_ELIM_THM; LT]; SUBGOAL_THEN `{m | m < SUC n} = n INSERT {m | m < n}` SUBST1_TAC THENL [REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_INSERT] THEN ARITH_TAC; ALL_TAC] THEN RULE_ASSUM_TAC(REWRITE_RULE[HAS_SIZE]) THEN ASM_SIMP_TAC[HAS_SIZE; CARD_CLAUSES; FINITE_INSERT] THEN REWRITE_TAC[IN_ELIM_THM; LT_REFL]]);; let CARD_NUMSEG_LT = prove (`!n. CARD {m | m < n} = n`, REWRITE_TAC[REWRITE_RULE[HAS_SIZE] HAS_SIZE_NUMSEG_LT]);; let FINITE_NUMSEG_LT = prove (`!n:num. FINITE {m | m < n}`, REWRITE_TAC[REWRITE_RULE[HAS_SIZE] HAS_SIZE_NUMSEG_LT]);; let HAS_SIZE_NUMSEG_LE = prove (`!n. {m | m <= n} HAS_SIZE (n + 1)`, REWRITE_TAC[GSYM LT_SUC_LE; HAS_SIZE_NUMSEG_LT; ADD1]);; let FINITE_NUMSEG_LE = prove (`!n. FINITE {m | m <= n}`, REWRITE_TAC[REWRITE_RULE[HAS_SIZE] HAS_SIZE_NUMSEG_LE]);; let CARD_NUMSEG_LE = prove (`!n. CARD {m | m <= n} = n + 1`, REWRITE_TAC[REWRITE_RULE[HAS_SIZE] HAS_SIZE_NUMSEG_LE]);; let num_FINITE = prove (`!s:num->bool. FINITE s <=> ?a. !x. x IN s ==> x <= a`, GEN_TAC THEN EQ_TAC THENL [SPEC_TAC(`s:num->bool`,`s:num->bool`) THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN MESON_TAC[LE_CASES; LE_TRANS]; DISCH_THEN(X_CHOOSE_TAC `n:num`) THEN MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `{m:num | m <= n}` THEN REWRITE_TAC[FINITE_NUMSEG_LE] THEN ASM_SIMP_TAC[SUBSET; IN_ELIM_THM]]);; let num_FINITE_AVOID = prove (`!s:num->bool. FINITE(s) ==> ?a. ~(a IN s)`, MESON_TAC[num_FINITE; LT; NOT_LT]);; let num_INFINITE = prove (`INFINITE(:num)`, REWRITE_TAC[INFINITE] THEN MESON_TAC[num_FINITE_AVOID; IN_UNIV]);; (* ------------------------------------------------------------------------- *) (* Set of strings is infinite. *) (* ------------------------------------------------------------------------- *) let string_INFINITE = prove (`INFINITE(:string)`, MP_TAC num_INFINITE THEN REWRITE_TAC[INFINITE; CONTRAPOS_THM] THEN DISCH_THEN(MP_TAC o ISPEC `LENGTH:string->num` o MATCH_MP FINITE_IMAGE) THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_UNIV; IN_IMAGE] THEN MESON_TAC[LENGTH_REPLICATE]);; (* ------------------------------------------------------------------------- *) (* Indexing of finite sets. *) (* ------------------------------------------------------------------------- *) let HAS_SIZE_INDEX = prove (`!s n. s HAS_SIZE n ==> ?f:num->A. (!m. m < n ==> f(m) IN s) /\ (!x. x IN s ==> ?!m. m < n /\ (f m = x))`, ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN INDUCT_TAC THEN SIMP_TAC[HAS_SIZE_0; HAS_SIZE_SUC; LT; NOT_IN_EMPTY] THEN X_GEN_TAC `s:A->bool` THEN REWRITE_TAC[EXTENSION; NOT_IN_EMPTY] THEN REWRITE_TAC[NOT_FORALL_THM] THEN DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `a:A`) (MP_TAC o SPEC `a:A`)) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `s DELETE (a:A)`) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `f:num->A` STRIP_ASSUME_TAC) THEN EXISTS_TAC `\m:num. if m < n then f(m) else a:A` THEN CONJ_TAC THENL [GEN_TAC THEN REWRITE_TAC[] THEN COND_CASES_TAC THEN ASM_MESON_TAC[IN_DELETE]; ALL_TAC] THEN X_GEN_TAC `x:A` THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN FIRST_X_ASSUM(MP_TAC o SPEC `x:A`) THEN ASM_REWRITE_TAC[IN_DELETE] THEN CONV_TAC(ONCE_DEPTH_CONV COND_ELIM_CONV) THEN ASM_CASES_TAC `a:A = x` THEN ASM_SIMP_TAC[] THEN ASM_MESON_TAC[LT_REFL; IN_DELETE]);; (* ------------------------------------------------------------------------- *) (* Mapping between finite sets and lists. *) (* ------------------------------------------------------------------------- *) let set_of_list = new_recursive_definition list_RECURSION `(set_of_list ([]:A list) = {}) /\ (set_of_list (CONS (h:A) t) = h INSERT (set_of_list t))`;; let list_of_set = new_definition `list_of_set s = @l. (set_of_list l = s) /\ (LENGTH l = CARD s)`;; let LIST_OF_SET_PROPERTIES = prove (`!s:A->bool. FINITE(s) ==> (set_of_list(list_of_set s) = s) /\ (LENGTH(list_of_set s) = CARD s)`, REWRITE_TAC[list_of_set] THEN CONV_TAC(BINDER_CONV(RAND_CONV SELECT_CONV)) THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REPEAT STRIP_TAC THENL [EXISTS_TAC `[]:A list` THEN REWRITE_TAC[CARD_CLAUSES; LENGTH; set_of_list]; EXISTS_TAC `CONS (x:A) l` THEN ASM_REWRITE_TAC[LENGTH] THEN ASM_REWRITE_TAC[set_of_list] THEN FIRST_ASSUM(fun th -> REWRITE_TAC [MATCH_MP (CONJUNCT2 CARD_CLAUSES) th]) THEN ASM_REWRITE_TAC[]]);; let SET_OF_LIST_OF_SET = prove (`!s. FINITE(s) ==> (set_of_list(list_of_set s) = s)`, MESON_TAC[LIST_OF_SET_PROPERTIES]);; let LENGTH_LIST_OF_SET = prove (`!s. FINITE(s) ==> (LENGTH(list_of_set s) = CARD s)`, MESON_TAC[LIST_OF_SET_PROPERTIES]);; let MEM_LIST_OF_SET = prove (`!s:A->bool. FINITE(s) ==> !x. MEM x (list_of_set s) <=> x IN s`, GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP SET_OF_LIST_OF_SET) THEN DISCH_THEN(fun th -> GEN_REWRITE_TAC (BINDER_CONV o funpow 2 RAND_CONV) [GSYM th]) THEN SPEC_TAC(`list_of_set(s:A->bool)`,`l:A list`) THEN LIST_INDUCT_TAC THEN REWRITE_TAC[MEM; set_of_list; NOT_IN_EMPTY] THEN ASM_REWRITE_TAC[IN_INSERT]);; let FINITE_SET_OF_LIST = prove (`!l. FINITE(set_of_list l)`, LIST_INDUCT_TAC THEN ASM_SIMP_TAC[set_of_list; FINITE_RULES]);; let IN_SET_OF_LIST = prove (`!x l. x IN (set_of_list l) <=> MEM x l`, GEN_TAC THEN LIST_INDUCT_TAC THEN REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY; MEM; set_of_list] THEN ASM_MESON_TAC[]);; let SET_OF_LIST_APPEND = prove (`!l1 l2. set_of_list(APPEND l1 l2) = set_of_list(l1) UNION set_of_list(l2)`, REWRITE_TAC[EXTENSION; IN_SET_OF_LIST; IN_UNION; MEM_APPEND]);; let SET_OF_LIST_MAP = prove (`!f l. set_of_list(MAP f l) = IMAGE f (set_of_list l)`, GEN_TAC THEN LIST_INDUCT_TAC THEN ASM_REWRITE_TAC[set_of_list; MAP; IMAGE_CLAUSES]);; (* ------------------------------------------------------------------------- *) (* Mappings from finite set enumerations to lists (no "setification"). *) (* ------------------------------------------------------------------------- *) let dest_setenum = let fn = splitlist (dest_binary "INSERT") in fun tm -> let l,n = fn tm in if is_const n & fst(dest_const n) = "EMPTY" then l else failwith "dest_setenum: not a finite set enumeration";; let is_setenum = can dest_setenum;; let mk_setenum = let insert_atm = `(INSERT):A->(A->bool)->(A->bool)` and nil_atm = `(EMPTY):A->bool` in fun (l,ty) -> let insert_tm = inst [ty,aty] insert_atm and nil_tm = inst [ty,aty] nil_atm in itlist (mk_binop insert_tm) l nil_tm;; let mk_fset l = mk_setenum(l,type_of(hd l));; (* ------------------------------------------------------------------------- *) (* Pairwise property over sets and lists. *) (* ------------------------------------------------------------------------- *) let pairwise = new_definition `pairwise r s <=> !x y. x IN s /\ y IN s /\ ~(x = y) ==> r x y`;; let PAIRWISE = new_recursive_definition list_RECURSION `(PAIRWISE (r:A->A->bool) [] <=> T) /\ (PAIRWISE (r:A->A->bool) (CONS h t) <=> ALL (r h) t /\ PAIRWISE r t)`;; let PAIRWISE_EMPTY = prove (`!r. pairwise r {} <=> T`, REWRITE_TAC[pairwise; NOT_IN_EMPTY] THEN MESON_TAC[]);; let PAIRWISE_SING = prove (`!r x. pairwise r {x} <=> T`, REWRITE_TAC[pairwise; IN_SING] THEN MESON_TAC[]);; (* ------------------------------------------------------------------------- *) (* Some additional properties of "set_of_list". *) (* ------------------------------------------------------------------------- *) let CARD_SET_OF_LIST_LE = prove (`!l. CARD(set_of_list l) <= LENGTH l`, LIST_INDUCT_TAC THEN SIMP_TAC[LENGTH; set_of_list; CARD_CLAUSES; FINITE_SET_OF_LIST] THEN ASM_ARITH_TAC);; let HAS_SIZE_SET_OF_LIST = prove (`!l. (set_of_list l) HAS_SIZE (LENGTH l) <=> PAIRWISE (\x y. ~(x = y)) l`, REWRITE_TAC[HAS_SIZE; FINITE_SET_OF_LIST] THEN LIST_INDUCT_TAC THEN ASM_SIMP_TAC[CARD_CLAUSES; LENGTH; set_of_list; PAIRWISE; ALL; FINITE_SET_OF_LIST; GSYM ALL_MEM; IN_SET_OF_LIST] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[SUC_INJ] THEN ASM_MESON_TAC[CARD_SET_OF_LIST_LE; ARITH_RULE `~(SUC n <= n)`]);; (* ------------------------------------------------------------------------- *) (* Classic result on function of finite set into itself. *) (* ------------------------------------------------------------------------- *) let SURJECTIVE_IFF_INJECTIVE_GEN = prove (`!s t f:A->B. FINITE s /\ FINITE t /\ (CARD s = CARD t) /\ (IMAGE f s) SUBSET t ==> ((!y. y IN t ==> ?x. x IN s /\ (f x = y)) <=> (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)))`, REPEAT STRIP_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL [ASM_CASES_TAC `x:A = y` THEN ASM_REWRITE_TAC[] THEN SUBGOAL_THEN `CARD s <= CARD (IMAGE (f:A->B) (s DELETE y))` MP_TAC THENL [ASM_REWRITE_TAC[] THEN MATCH_MP_TAC CARD_SUBSET THEN ASM_SIMP_TAC[FINITE_IMAGE; FINITE_DELETE] THEN REWRITE_TAC[SUBSET; IN_IMAGE; IN_DELETE] THEN ASM_MESON_TAC[]; REWRITE_TAC[NOT_LE] THEN MATCH_MP_TAC LET_TRANS THEN EXISTS_TAC `CARD(s DELETE (y:A))` THEN ASM_SIMP_TAC[CARD_IMAGE_LE; FINITE_DELETE] THEN ASM_SIMP_TAC[CARD_DELETE; ARITH_RULE `x - 1 < x <=> ~(x = 0)`] THEN ASM_MESON_TAC[CARD_EQ_0; MEMBER_NOT_EMPTY]]; SUBGOAL_THEN `IMAGE (f:A->B) s = t` MP_TAC THENL [ALL_TAC; ASM_MESON_TAC[EXTENSION; IN_IMAGE]] THEN ASM_MESON_TAC[CARD_SUBSET_EQ; CARD_IMAGE_INJ]]);; let SURJECTIVE_IFF_INJECTIVE = prove (`!s f:A->A. FINITE s /\ (IMAGE f s) SUBSET s ==> ((!y. y IN s ==> ?x. x IN s /\ (f x = y)) <=> (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)))`, SIMP_TAC[SURJECTIVE_IFF_INJECTIVE_GEN]);; let IMAGE_IMP_INJECTIVE_GEN = prove (`!s t f:A->B. FINITE s /\ (CARD s = CARD t) /\ (IMAGE f s = t) ==> !x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)`, REPEAT GEN_TAC THEN DISCH_THEN(ASSUME_TAC o GSYM) THEN MP_TAC(ISPECL [`s:A->bool`; `t:B->bool`; `f:A->B`] SURJECTIVE_IFF_INJECTIVE_GEN) THEN ASM_SIMP_TAC[SUBSET_REFL; FINITE_IMAGE] THEN ASM_MESON_TAC[EXTENSION; IN_IMAGE]);; let IMAGE_IMP_INJECTIVE = prove (`!s f. FINITE s /\ (IMAGE f s = s) ==> !x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)`, MESON_TAC[IMAGE_IMP_INJECTIVE_GEN]);; (* ------------------------------------------------------------------------- *) (* Converse relation between cardinality and injection. *) (* ------------------------------------------------------------------------- *) let CARD_LE_INJ = prove (`!s t. FINITE s /\ FINITE t /\ CARD s <= CARD t ==> ?f:A->B. (IMAGE f s) SUBSET t /\ !x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)`, REWRITE_TAC[IMP_CONJ] THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[IMAGE_CLAUSES; EMPTY_SUBSET; NOT_IN_EMPTY] THEN SIMP_TAC[CARD_CLAUSES] THEN MAP_EVERY X_GEN_TAC [`x:A`; `s:A->bool`] THEN STRIP_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[CARD_CLAUSES; LE; NOT_SUC] THEN MAP_EVERY X_GEN_TAC [`y:B`; `t:B->bool`] THEN SIMP_TAC[CARD_CLAUSES] THEN DISCH_THEN(CONJUNCTS_THEN2 (K ALL_TAC) STRIP_ASSUME_TAC) THEN REWRITE_TAC[LE_SUC] THEN STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `t:B->bool`) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `f:A->B` STRIP_ASSUME_TAC) THEN EXISTS_TAC `\z:A. if z = x then (y:B) else f(z)` THEN REWRITE_TAC[IN_INSERT; SUBSET; IN_IMAGE] THEN ASM_MESON_TAC[SUBSET; IN_IMAGE]);; (* ------------------------------------------------------------------------- *) (* Occasionally handy rewrites. *) (* ------------------------------------------------------------------------- *) let FORALL_IN_CLAUSES = prove (`(!P. (!x. x IN {} ==> P x) <=> T) /\ (!P a s. (!x. x IN (a INSERT s) ==> P x) <=> P a /\ (!x. x IN s ==> P x))`, REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN MESON_TAC[]);; let EXISTS_IN_CLAUSES = prove (`(!P. (?x. x IN {} /\ P x) <=> F) /\ (!P a s. (?x. x IN (a INSERT s) /\ P x) <=> P a \/ (?x. x IN s /\ P x))`, REWRITE_TAC[IN_INSERT; NOT_IN_EMPTY] THEN MESON_TAC[]);; (* ------------------------------------------------------------------------- *) (* Useful general properties of functions. *) (* ------------------------------------------------------------------------- *) let SURJECTIVE_ON_RIGHT_INVERSE = prove (`!f t. (!y. y IN t ==> ?x. x IN s /\ (f(x) = y)) <=> (?g. !y. y IN t ==> g(y) IN s /\ (f(g(y)) = y))`, REWRITE_TAC[RIGHT_IMP_EXISTS_THM; SKOLEM_THM]);; let INJECTIVE_ON_LEFT_INVERSE = prove (`!f s. (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)) <=> (?g. !x. x IN s ==> (g(f(x)) = x))`, let lemma = MESON[] `(!x. x IN s ==> (g(f(x)) = x)) <=> (!y x. x IN s /\ (y = f x) ==> (g y = x))` in REWRITE_TAC[lemma; GSYM SKOLEM_THM] THEN MESON_TAC[]);; let BIJECTIVE_ON_LEFT_RIGHT_INVERSE = prove (`!f s t. (!x. x IN s ==> f(x) IN t) ==> ((!x y. x IN s /\ y IN s /\ f(x) = f(y) ==> x = y) /\ (!y. y IN t ==> ?x. x IN s /\ f x = y) <=> ?g. (!y. y IN t ==> g(y) IN s) /\ (!y. y IN t ==> (f(g(y)) = y)) /\ (!x. x IN s ==> (g(f(x)) = x)))`, REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[INJECTIVE_ON_LEFT_INVERSE; SURJECTIVE_ON_RIGHT_INVERSE] THEN REWRITE_TAC[RIGHT_AND_EXISTS_THM] THEN AP_TERM_TAC THEN ABS_TAC THEN EQ_TAC THEN ASM_MESON_TAC[]);; let SURJECTIVE_RIGHT_INVERSE = prove (`(!y. ?x. f(x) = y) <=> (?g. !y. f(g(y)) = y)`, MESON_TAC[SURJECTIVE_ON_RIGHT_INVERSE; IN_UNIV]);; let INJECTIVE_LEFT_INVERSE = prove (`(!x y. (f x = f y) ==> (x = y)) <=> (?g. !x. g(f(x)) = x)`, let th = REWRITE_RULE[IN_UNIV] (ISPECL [`f:A->B`; `UNIV:A->bool`] INJECTIVE_ON_LEFT_INVERSE) in REWRITE_TAC[th]);; let BIJECTIVE_LEFT_RIGHT_INVERSE = prove (`!f:A->B. (!x y. f(x) = f(y) ==> x = y) /\ (!y. ?x. f x = y) <=> ?g. (!y. f(g(y)) = y) /\ (!x. g(f(x)) = x)`, GEN_TAC THEN MP_TAC(ISPECL [`f:A->B`; `(:A)`; `(:B)`] BIJECTIVE_ON_LEFT_RIGHT_INVERSE) THEN REWRITE_TAC[IN_UNIV]);; let FUNCTION_FACTORS_RIGHT = prove (`!f g. (!x. ?y. g(y) = f(x)) <=> ?h. f = g o h`, REWRITE_TAC[FUN_EQ_THM; o_THM; GSYM SKOLEM_THM] THEN MESON_TAC[]);; let FUNCTION_FACTORS_LEFT = prove (`!f g. (!x y. (g x = g y) ==> (f x = f y)) <=> ?h. f = h o g`, let lemma = prove (`(f = h o g) <=> !y x. (y = g x) ==> (h y = f x)`, REWRITE_TAC[FUN_EQ_THM; o_THM] THEN MESON_TAC[]) in REWRITE_TAC[lemma; GSYM SKOLEM_THM] THEN MESON_TAC[]);; (* ------------------------------------------------------------------------- *) (* Existence of bijections between two finite sets of same size. *) (* ------------------------------------------------------------------------- *) let CARD_EQ_BIJECTION = prove (`!s t. FINITE s /\ FINITE t /\ CARD s = CARD t ==> ?f:A->B. (!x. x IN s ==> f(x) IN t) /\ (!y. y IN t ==> ?x. x IN s /\ f x = y) /\ !x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)`, MP_TAC CARD_LE_INJ THEN REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[LE_REFL] THEN MATCH_MP_TAC MONO_EXISTS THEN ASM_SIMP_TAC[SURJECTIVE_IFF_INJECTIVE_GEN] THEN MESON_TAC[SUBSET; IN_IMAGE]);; let CARD_EQ_BIJECTIONS = prove (`!s t. FINITE s /\ FINITE t /\ CARD s = CARD t ==> ?f:A->B g. (!x. x IN s ==> f(x) IN t /\ g(f x) = x) /\ (!y. y IN t ==> g(y) IN s /\ f(g y) = y)`, REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP CARD_EQ_BIJECTION) THEN MATCH_MP_TAC MONO_EXISTS THEN REWRITE_TAC[SURJECTIVE_ON_RIGHT_INVERSE] THEN GEN_TAC THEN REWRITE_TAC[LEFT_AND_EXISTS_THM; RIGHT_AND_EXISTS_THM] THEN MATCH_MP_TAC MONO_EXISTS THEN MESON_TAC[]);; let BIJECTIONS_HAS_SIZE = prove (`!s t f:A->B g. (!x. x IN s ==> f(x) IN t /\ g(f x) = x) /\ (!y. y IN t ==> g(y) IN s /\ f(g y) = y) /\ s HAS_SIZE n ==> t HAS_SIZE n`, REPEAT STRIP_TAC THEN SUBGOAL_THEN `t = IMAGE (f:A->B) s` SUBST_ALL_TAC THENL [ASM SET_TAC[]; MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN ASM_MESON_TAC[]]);; let BIJECTIONS_HAS_SIZE_EQ = prove (`!s t f:A->B g. (!x. x IN s ==> f(x) IN t /\ g(f x) = x) /\ (!y. y IN t ==> g(y) IN s /\ f(g y) = y) ==> !n. s HAS_SIZE n <=> t HAS_SIZE n`, REPEAT STRIP_TAC THEN EQ_TAC THEN MATCH_MP_TAC(ONCE_REWRITE_RULE [TAUT `a /\ b /\ c ==> d <=> a /\ b ==> c ==> d`] BIJECTIONS_HAS_SIZE) THENL [MAP_EVERY EXISTS_TAC [`f:A->B`; `g:B->A`]; MAP_EVERY EXISTS_TAC [`g:B->A`; `f:A->B`]] THEN ASM_MESON_TAC[]);; let BIJECTIONS_CARD_EQ = prove (`!s t f:A->B g. (FINITE s \/ FINITE t) /\ (!x. x IN s ==> f(x) IN t /\ g(f x) = x) /\ (!y. y IN t ==> g(y) IN s /\ f(g y) = y) ==> CARD s = CARD t`, REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (MP_TAC o MATCH_MP BIJECTIONS_HAS_SIZE_EQ)) THEN MESON_TAC[HAS_SIZE]);; (* ------------------------------------------------------------------------- *) (* Transitive relation with finitely many predecessors is wellfounded. *) (* ------------------------------------------------------------------------- *) let WF_FINITE = prove (`!(<<). (!x. ~(x << x)) /\ (!x y z. x << y /\ y << z ==> x << z) /\ (!x:A. FINITE {y | y << x}) ==> WF(<<)`, REPEAT STRIP_TAC THEN REWRITE_TAC[WF_DCHAIN] THEN DISCH_THEN(X_CHOOSE_THEN `s:num->A` STRIP_ASSUME_TAC) THEN SUBGOAL_THEN `!m n. m < n ==> (s:num->A) n << s m` ASSUME_TAC THENL [MATCH_MP_TAC TRANSITIVE_STEPWISE_LT THEN ASM_MESON_TAC[]; ALL_TAC] THEN MP_TAC(ISPEC `s:num->A` INFINITE_IMAGE_INJ) THEN ANTS_TAC THENL [ASM_MESON_TAC[LT_CASES]; ALL_TAC] THEN DISCH_THEN(MP_TAC o SPEC `(:num)`) THEN REWRITE_TAC[num_INFINITE] THEN REWRITE_TAC[INFINITE] THEN MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `s(0) INSERT {y:A | y << s(0)}` THEN ASM_REWRITE_TAC[FINITE_INSERT] THEN REWRITE_TAC[SUBSET; FORALL_IN_IMAGE; IN_UNIV; IN_INSERT] THEN INDUCT_TAC THEN REWRITE_TAC[IN_ELIM_THM] THEN ASM_MESON_TAC[LT_0]);; (* ------------------------------------------------------------------------- *) (* Cardinal comparisons (more theory in Examples/card.ml) *) (* ------------------------------------------------------------------------- *) let le_c = new_definition `s <=_c t <=> ?f. (!x. x IN s ==> f(x) IN t) /\ (!x y. x IN s /\ y IN s /\ (f(x) = f(y)) ==> (x = y))`;; let lt_c = new_definition `s <_c t <=> s <=_c t /\ ~(t <=_c s)`;; let eq_c = new_definition `s =_c t <=> ?f. (!x. x IN s ==> f(x) IN t) /\ !y. y IN t ==> ?!x. x IN s /\ (f x = y)`;; let ge_c = new_definition `s >=_c t <=> t <=_c s`;; let gt_c = new_definition `s >_c t <=> t <_c s`;; let LE_C = prove (`!s t. s <=_c t <=> ?g. !x. x IN s ==> ?y. y IN t /\ (g y = x)`, REWRITE_TAC[le_c; INJECTIVE_ON_LEFT_INVERSE; SURJECTIVE_ON_RIGHT_INVERSE; RIGHT_IMP_EXISTS_THM; SKOLEM_THM; RIGHT_AND_EXISTS_THM] THEN MESON_TAC[]);; let GE_C = prove (`!s t. s >=_c t <=> ?f. !y. y IN t ==> ?x. x IN s /\ (y = f x)`, REWRITE_TAC[ge_c; LE_C] THEN MESON_TAC[]);; let COUNTABLE = new_definition `COUNTABLE t <=> (:num) >=_c t`;; (* ========================================================================= *) (* Generic iterated operations and special cases of sums over N and R. *) (* *) (* (c) Copyright, John Harrison 1998-2007 *) (* (c) Copyright, Lars Schewe 2007 *) (* ========================================================================= *) prioritize_num();; (* ------------------------------------------------------------------------- *) (* A natural notation for segments of the naturals. *) (* ------------------------------------------------------------------------- *) parse_as_infix("..",(15,"right"));; let numseg = new_definition `m..n = {x:num | m <= x /\ x <= n}`;; let FINITE_NUMSEG = prove (`!m n. FINITE(m..n)`, REPEAT GEN_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `{x:num | x <= n}` THEN REWRITE_TAC[FINITE_NUMSEG_LE] THEN SIMP_TAC[SUBSET; IN_ELIM_THM; numseg]);; let NUMSEG_COMBINE_R = prove (`!m p n. m <= p + 1 /\ p <= n ==> ((m..p) UNION ((p+1)..n) = m..n)`, REWRITE_TAC[EXTENSION; IN_UNION; numseg; IN_ELIM_THM] THEN ARITH_TAC);; let NUMSEG_COMBINE_L = prove (`!m p n. m <= p /\ p <= n + 1 ==> ((m..(p-1)) UNION (p..n) = m..n)`, REWRITE_TAC[EXTENSION; IN_UNION; numseg; IN_ELIM_THM] THEN ARITH_TAC);; let NUMSEG_LREC = prove (`!m n. m <= n ==> (m INSERT ((m+1)..n) = m..n)`, REWRITE_TAC[EXTENSION; IN_INSERT; numseg; IN_ELIM_THM] THEN ARITH_TAC);; let NUMSEG_RREC = prove (`!m n. m <= n ==> (n INSERT (m..(n-1)) = m..n)`, REWRITE_TAC[EXTENSION; IN_INSERT; numseg; IN_ELIM_THM] THEN ARITH_TAC);; let NUMSEG_REC = prove (`!m n. m <= SUC n ==> (m..SUC n = (SUC n) INSERT (m..n))`, SIMP_TAC[GSYM NUMSEG_RREC; SUC_SUB1]);; let IN_NUMSEG = prove (`!m n p. p IN (m..n) <=> m <= p /\ p <= n`, REWRITE_TAC[numseg; IN_ELIM_THM]);; let IN_NUMSEG_0 = prove (`!m n. m IN (0..n) <=> m <= n`, REWRITE_TAC[IN_NUMSEG; LE_0]);; let NUMSEG_SING = prove (`!n. n..n = {n}`, REWRITE_TAC[EXTENSION; IN_SING; IN_NUMSEG] THEN ARITH_TAC);; let NUMSEG_EMPTY = prove (`!m n. (m..n = {}) <=> n < m`, REWRITE_TAC[EXTENSION; NOT_IN_EMPTY; IN_NUMSEG] THEN MESON_TAC[NOT_LE; LE_TRANS; LE_REFL]);; let CARD_NUMSEG_LEMMA = prove (`!m d. CARD(m..(m+d)) = d + 1`, GEN_TAC THEN INDUCT_TAC THEN ASM_SIMP_TAC[ADD_CLAUSES; NUMSEG_REC; NUMSEG_SING; FINITE_RULES; ARITH_RULE `m <= SUC(m + d)`; CARD_CLAUSES; FINITE_NUMSEG; NOT_IN_EMPTY; ARITH; IN_NUMSEG; ARITH_RULE `~(SUC n <= n)`]);; let CARD_NUMSEG = prove (`!m n. CARD(m..n) = (n + 1) - m`, REPEAT GEN_TAC THEN DISJ_CASES_THEN MP_TAC (ARITH_RULE `n:num < m \/ m <= n`) THENL [ASM_MESON_TAC[NUMSEG_EMPTY; CARD_CLAUSES; ARITH_RULE `n < m ==> ((n + 1) - m = 0)`]; SIMP_TAC[LE_EXISTS; LEFT_IMP_EXISTS_THM; CARD_NUMSEG_LEMMA] THEN REPEAT STRIP_TAC THEN ARITH_TAC]);; let HAS_SIZE_NUMSEG = prove (`!m n. (m..n) HAS_SIZE ((n + 1) - m)`, REWRITE_TAC[HAS_SIZE; FINITE_NUMSEG; CARD_NUMSEG]);; let CARD_NUMSEG_1 = prove (`!n. CARD(1..n) = n`, REWRITE_TAC[CARD_NUMSEG] THEN ARITH_TAC);; let HAS_SIZE_NUMSEG_1 = prove (`!n. (1..n) HAS_SIZE n`, REWRITE_TAC[CARD_NUMSEG; HAS_SIZE; FINITE_NUMSEG] THEN ARITH_TAC);; let NUMSEG_CLAUSES = prove (`(!m. m..0 = if m = 0 then {0} else {}) /\ (!m n. m..SUC n = if m <= SUC n then (SUC n) INSERT (m..n) else m..n)`, REPEAT STRIP_TAC THEN COND_CASES_TAC THEN GEN_REWRITE_TAC I [EXTENSION] THEN REWRITE_TAC[IN_NUMSEG; NOT_IN_EMPTY; IN_INSERT] THEN POP_ASSUM MP_TAC THEN ARITH_TAC);; let FINITE_INDEX_NUMSEG = prove (`!s:A->bool. FINITE s = ?f. (!i j. i IN (1..CARD(s)) /\ j IN (1..CARD(s)) /\ (f i = f j) ==> (i = j)) /\ (s = IMAGE f (1..CARD(s)))`, GEN_TAC THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[FINITE_NUMSEG; FINITE_IMAGE]] THEN DISCH_TAC THEN MP_TAC(ISPECL [`s:A->bool`; `CARD(s:A->bool)`] HAS_SIZE_INDEX) THEN ASM_REWRITE_TAC[HAS_SIZE] THEN DISCH_THEN(X_CHOOSE_THEN `f:num->A` STRIP_ASSUME_TAC) THEN EXISTS_TAC `\n. f(n - 1):A` THEN ASM_REWRITE_TAC[EXTENSION; IN_IMAGE; IN_NUMSEG] THEN CONJ_TAC THENL [REWRITE_TAC[ARITH_RULE `1 <= i /\ i <= n <=> ~(i = 0) /\ i - 1 < n`] THEN ASM_MESON_TAC[ARITH_RULE `~(x = 0) /\ ~(y = 0) /\ (x - 1 = y - 1) ==> (x = y)`]; ASM_MESON_TAC [ARITH_RULE `m < C ==> (m = (m + 1) - 1) /\ 1 <= m + 1 /\ m + 1 <= C`; ARITH_RULE `1 <= i /\ i <= n <=> ~(i = 0) /\ i - 1 < n`]]);; let FINITE_INDEX_NUMBERS = prove (`!s:A->bool. FINITE s = ?k:num->bool f. (!i j. i IN k /\ j IN k /\ (f i = f j) ==> (i = j)) /\ FINITE k /\ (s = IMAGE f k)`, MESON_TAC[FINITE_INDEX_NUMSEG; FINITE_NUMSEG; FINITE_IMAGE]);; let DISJOINT_NUMSEG = prove (`!m n p q. DISJOINT (m..n) (p..q) <=> n < p \/ q < m \/ n < m \/ q < p`, REWRITE_TAC[DISJOINT; IN_NUMSEG; EXTENSION; IN_INTER; NOT_IN_EMPTY] THEN REPEAT GEN_TAC THEN REWRITE_TAC[DE_MORGAN_THM; NOT_LE] THEN EQ_TAC THENL [MESON_TAC[LT_ANTISYM]; ARITH_TAC]);; let NUMSEG_ADD_SPLIT = prove (`!m n p. m <= n + 1 ==> (m..(n+p) = (m..n) UNION (n+1..n+p))`, REWRITE_TAC[EXTENSION; IN_UNION; IN_NUMSEG] THEN ARITH_TAC);; let NUMSEG_OFFSET_IMAGE = prove (`!m n p. (m+p..n+p) = IMAGE (\i. i + p) (m..n)`, REWRITE_TAC[EXTENSION; IN_IMAGE; IN_NUMSEG] THEN REPEAT GEN_TAC THEN EQ_TAC THENL [DISCH_THEN(fun th -> EXISTS_TAC `x - p:num` THEN MP_TAC th); ALL_TAC] THEN ARITH_TAC);; let SUBSET_NUMSEG = prove (`!m n p q. (m..n) SUBSET (p..q) <=> n < m \/ p <= m /\ n <= q`, REPEAT GEN_TAC THEN REWRITE_TAC[SUBSET; IN_NUMSEG] THEN EQ_TAC THENL [MESON_TAC[LE_TRANS; NOT_LE; LE_REFL]; ARITH_TAC]);; (* ------------------------------------------------------------------------- *) (* Equivalence with the more ad-hoc comprehension notation. *) (* ------------------------------------------------------------------------- *) let NUMSEG_LE = prove (`!n. {x | x <= n} = 0..n`, REWRITE_TAC[EXTENSION; IN_NUMSEG; IN_ELIM_THM] THEN ARITH_TAC);; let NUMSEG_LT = prove (`!n. {x | x < n} = if n = 0 then {} else 0..(n-1)`, GEN_TAC THEN COND_CASES_TAC THEN REWRITE_TAC[EXTENSION; IN_NUMSEG; IN_ELIM_THM; NOT_IN_EMPTY] THEN ASM_ARITH_TAC);; (* ------------------------------------------------------------------------- *) (* Conversion to evaluate m..n for specific numerals. *) (* ------------------------------------------------------------------------- *) let NUMSEG_CONV = let pth_0 = MESON[NUMSEG_EMPTY] `n < m ==> m..n = {}` and pth_1 = MESON[NUMSEG_SING] `m..m = {m}` and pth_2 = MESON[NUMSEG_LREC; ADD1] `m <= n ==> m..n = m INSERT (SUC m..n)` and ns_tm = `(..)` and m_tm = `m:num` and n_tm = `n:num` in let rec NUMSEG_CONV tm = let nstm,nt = dest_comb tm in let nst,mt = dest_comb nstm in if nst <> ns_tm then failwith "NUMSEG_CONV" else let m = dest_numeral mt and n = dest_numeral nt in if n x = y) /\ (!x y z. x << y /\ y << z ==> x << z) ==> !n s. s HAS_SIZE n ==> ?f. s = IMAGE f (1..n) /\ (!j k. j IN 1..n /\ k IN 1..n /\ j < k ==> ~(f k << f j))`, GEN_TAC THEN DISCH_TAC THEN SUBGOAL_THEN `!n s. s HAS_SIZE n /\ ~(s = {}) ==> ?a:A. a IN s /\ !b. b IN (s DELETE a) ==> ~(b << a)` ASSUME_TAC THENL [INDUCT_TAC THEN REWRITE_TAC[HAS_SIZE_0; HAS_SIZE_SUC; TAUT `~(a /\ ~a)`] THEN X_GEN_TAC `s:A->bool` THEN STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [GSYM MEMBER_NOT_EMPTY]) THEN DISCH_THEN(X_CHOOSE_TAC `a:A`) THEN FIRST_X_ASSUM(MP_TAC o SPEC `a:A`) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `s DELETE (a:A)`) THEN ASM_SIMP_TAC[SET_RULE `a IN s ==> (s DELETE a = {} <=> s = {a})`] THEN ASM_CASES_TAC `s = {a:A}` THEN ASM_REWRITE_TAC[] THENL [EXISTS_TAC `a:A` THEN SET_TAC[]; ALL_TAC] THEN DISCH_THEN(X_CHOOSE_THEN `b:A` STRIP_ASSUME_TAC) THEN ASM_CASES_TAC `((a:A) << (b:A)) :bool` THENL [EXISTS_TAC `a:A`; EXISTS_TAC `b:A`] THEN ASM SET_TAC[]; ALL_TAC] THEN INDUCT_TAC THENL [SIMP_TAC[HAS_SIZE_0; NUMSEG_CLAUSES; ARITH; IMAGE_CLAUSES; NOT_IN_EMPTY]; ALL_TAC] THEN REWRITE_TAC[HAS_SIZE_SUC] THEN X_GEN_TAC `s:A->bool` THEN STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL [`SUC n`; `s:A->bool`]) THEN ASM_REWRITE_TAC[HAS_SIZE_SUC] THEN DISCH_THEN(X_CHOOSE_THEN `a:A` MP_TAC) THEN STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `s DELETE (a:A)`) THEN ASM_SIMP_TAC[] THEN DISCH_THEN(X_CHOOSE_THEN `f:num->A` STRIP_ASSUME_TAC) THEN EXISTS_TAC `\k. if k = 1 then a:A else f(k - 1)` THEN SIMP_TAC[ARITH_RULE `1 <= k ==> ~(SUC k = 1)`; SUC_SUB1] THEN SUBGOAL_THEN `!i. i IN 1..SUC n <=> i = 1 \/ 1 < i /\ (i - 1) IN 1..n` (fun th -> REWRITE_TAC[EXTENSION; IN_IMAGE; th]) THENL [REWRITE_TAC[IN_NUMSEG] THEN ARITH_TAC; ALL_TAC] THEN CONJ_TAC THENL [X_GEN_TAC `b:A` THEN ASM_CASES_TAC `b:A = a` THENL [ASM_MESON_TAC[]; ALL_TAC] THEN FIRST_ASSUM(fun th -> ONCE_REWRITE_TAC[MATCH_MP (SET_RULE `~(b = a) ==> (b IN s <=> b IN (s DELETE a))`) th]) THEN ONCE_REWRITE_TAC[COND_RAND] THEN ASM_REWRITE_TAC[IN_IMAGE; IN_NUMSEG] THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[]] THEN DISCH_THEN(X_CHOOSE_TAC `i:num`) THEN EXISTS_TAC `i + 1` THEN ASM_SIMP_TAC[ARITH_RULE `1 <= x ==> 1 < x + 1 /\ ~(x + 1 = 1)`; ADD_SUB]; MAP_EVERY X_GEN_TAC [`j:num`; `k:num`] THEN MAP_EVERY ASM_CASES_TAC [`j = 1`; `k = 1`] THEN ASM_REWRITE_TAC[LT_REFL] THENL [STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM SET_TAC[]; ARITH_TAC; STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC]]);; (* ------------------------------------------------------------------------- *) (* Generic iteration of operation over set with finite support. *) (* ------------------------------------------------------------------------- *) let neutral = new_definition `neutral op = @x. !y. (op x y = y) /\ (op y x = y)`;; let monoidal = new_definition `monoidal op <=> (!x y. op x y = op y x) /\ (!x y z. op x (op y z) = op (op x y) z) /\ (!x:A. op (neutral op) x = x)`;; let MONOIDAL_AC = prove (`!op. monoidal op ==> (!a. op (neutral op) a = a) /\ (!a. op a (neutral op) = a) /\ (!a b. op a b = op b a) /\ (!a b c. op (op a b) c = op a (op b c)) /\ (!a b c. op a (op b c) = op b (op a c))`, REWRITE_TAC[monoidal] THEN MESON_TAC[]);; let support = new_definition `support op (f:A->B) s = {x | x IN s /\ ~(f x = neutral op)}`;; let iterate = new_definition `iterate op (s:A->bool) f = if FINITE(support op f s) then ITSET (\x a. op (f x) a) (support op f s) (neutral op) else neutral op`;; let IN_SUPPORT = prove (`!op f x s. x IN (support op f s) <=> x IN s /\ ~(f x = neutral op)`, REWRITE_TAC[support; IN_ELIM_THM]);; let SUPPORT_SUPPORT = prove (`!op f s. support op f (support op f s) = support op f s`, REWRITE_TAC[support; IN_ELIM_THM; EXTENSION] THEN REWRITE_TAC[CONJ_ACI]);; let SUPPORT_EMPTY = prove (`!op f s. (!x. x IN s ==> (f(x) = neutral op)) <=> (support op f s = {})`, REWRITE_TAC[IN_SUPPORT; EXTENSION; IN_ELIM_THM; NOT_IN_EMPTY] THEN MESON_TAC[]);; let SUPPORT_SUBSET = prove (`!op f s. (support op f s) SUBSET s`, SIMP_TAC[SUBSET; IN_SUPPORT]);; let FINITE_SUPPORT = prove (`!op f s. FINITE s ==> FINITE(support op f s)`, MESON_TAC[SUPPORT_SUBSET; FINITE_SUBSET]);; let SUPPORT_CLAUSES = prove (`(!f. support op f {} = {}) /\ (!f x s. support op f (x INSERT s) = if f(x) = neutral op then support op f s else x INSERT (support op f s)) /\ (!f x s. support op f (s DELETE x) = (support op f s) DELETE x) /\ (!f s t. support op f (s UNION t) = (support op f s) UNION (support op f t)) /\ (!f s t. support op f (s INTER t) = (support op f s) INTER (support op f t)) /\ (!f s t. support op f (s DIFF t) = (support op f s) DIFF (support op f t)) /\ (!f g s. support op g (IMAGE f s) = IMAGE f (support op (g o f) s))`, REWRITE_TAC[support; EXTENSION; IN_ELIM_THM; IN_INSERT; IN_DELETE; o_THM; IN_IMAGE; NOT_IN_EMPTY; IN_UNION; IN_INTER; IN_DIFF; COND_RAND] THEN REPEAT STRIP_TAC THEN TRY COND_CASES_TAC THEN ASM_MESON_TAC[]);; let SUPPORT_DELTA = prove (`!op s f a. support op (\x. if x = a then f(x) else neutral op) s = if a IN s then support op f {a} else {}`, REWRITE_TAC[EXTENSION; support; IN_ELIM_THM; IN_SING] THEN REPEAT GEN_TAC THEN REPEAT COND_CASES_TAC THEN ASM_REWRITE_TAC[IN_ELIM_THM; NOT_IN_EMPTY]);; let FINITE_SUPPORT_DELTA = prove (`!op f a. FINITE(support op (\x. if x = a then f(x) else neutral op) s)`, REWRITE_TAC[SUPPORT_DELTA] THEN REPEAT GEN_TAC THEN COND_CASES_TAC THEN SIMP_TAC[FINITE_RULES; FINITE_SUPPORT]);; (* ------------------------------------------------------------------------- *) (* Key lemmas about the generic notion. *) (* ------------------------------------------------------------------------- *) let ITERATE_SUPPORT = prove (`!op f s. iterate op (support op f s) f = iterate op s f`, SIMP_TAC[iterate; SUPPORT_SUPPORT]);; let ITERATE_EXPAND_CASES = prove (`!op f s. iterate op s f = if FINITE(support op f s) then iterate op (support op f s) f else neutral op`, SIMP_TAC[iterate; SUPPORT_SUPPORT]);; let ITERATE_CLAUSES_GEN = prove (`!op. monoidal op ==> (!(f:A->B). iterate op {} f = neutral op) /\ (!f x s. monoidal op /\ FINITE(support op (f:A->B) s) ==> (iterate op (x INSERT s) f = if x IN s then iterate op s f else op (f x) (iterate op s f)))`, GEN_TAC THEN STRIP_TAC THEN ONCE_REWRITE_TAC[AND_FORALL_THM] THEN GEN_TAC THEN MP_TAC(ISPECL [`\x a. (op:B->B->B) ((f:A->B)(x)) a`; `neutral op :B`] FINITE_RECURSION) THEN ANTS_TAC THENL [ASM_MESON_TAC[monoidal]; ALL_TAC] THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[iterate; SUPPORT_CLAUSES; FINITE_RULES] THEN GEN_REWRITE_TAC (LAND_CONV o RATOR_CONV o LAND_CONV) [COND_RAND] THEN ASM_REWRITE_TAC[SUPPORT_CLAUSES; FINITE_INSERT; COND_ID] THEN ASM_CASES_TAC `(f:A->B) x = neutral op` THEN ASM_SIMP_TAC[IN_SUPPORT] THEN COND_CASES_TAC THEN ASM_MESON_TAC[monoidal]);; let ITERATE_CLAUSES = prove (`!op. monoidal op ==> (!f. iterate op {} f = neutral op) /\ (!f x s. FINITE(s) ==> (iterate op (x INSERT s) f = if x IN s then iterate op s f else op (f x) (iterate op s f)))`, SIMP_TAC[ITERATE_CLAUSES_GEN; FINITE_SUPPORT]);; let ITERATE_UNION = prove (`!op. monoidal op ==> !f s t. FINITE s /\ FINITE t /\ DISJOINT s t ==> (iterate op (s UNION t) f = op (iterate op s f) (iterate op t f))`, let lemma = prove (`(s UNION (x INSERT t) = x INSERT (s UNION t)) /\ (DISJOINT s (x INSERT t) <=> ~(x IN s) /\ DISJOINT s t)`, SET_TAC[]) in GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN REPEAT DISCH_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN ASM_SIMP_TAC[ITERATE_CLAUSES; IN_UNION; UNION_EMPTY; REAL_ADD_RID; lemma; FINITE_UNION] THEN ASM_MESON_TAC[monoidal]);; let ITERATE_UNION_GEN = prove (`!op. monoidal op ==> !(f:A->B) s t. FINITE(support op f s) /\ FINITE(support op f t) /\ DISJOINT (support op f s) (support op f t) ==> (iterate op (s UNION t) f = op (iterate op s f) (iterate op t f))`, ONCE_REWRITE_TAC[GSYM ITERATE_SUPPORT] THEN SIMP_TAC[SUPPORT_CLAUSES; ITERATE_UNION]);; let ITERATE_DIFF = prove (`!op. monoidal op ==> !f s t. FINITE s /\ t SUBSET s ==> (op (iterate op (s DIFF t) f) (iterate op t f) = iterate op s f)`, let lemma = prove (`t SUBSET s ==> (s = (s DIFF t) UNION t) /\ DISJOINT (s DIFF t) t`, SET_TAC[]) in MESON_TAC[lemma; ITERATE_UNION; FINITE_UNION; FINITE_SUBSET; SUBSET_DIFF]);; let ITERATE_DIFF_GEN = prove (`!op. monoidal op ==> !f:A->B s t. FINITE (support op f s) /\ (support op f t) SUBSET (support op f s) ==> (op (iterate op (s DIFF t) f) (iterate op t f) = iterate op s f)`, ONCE_REWRITE_TAC[GSYM ITERATE_SUPPORT] THEN SIMP_TAC[SUPPORT_CLAUSES; ITERATE_DIFF]);; let ITERATE_INCL_EXCL = prove (`!op. monoidal op ==> !s t f. FINITE s /\ FINITE t ==> op (iterate op s f) (iterate op t f) = op (iterate op (s UNION t) f) (iterate op (s INTER t) f)`, REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[SET_RULE `a UNION b = ((a DIFF b) UNION (b DIFF a)) UNION (a INTER b)`] THEN GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o ONCE_DEPTH_CONV) [SET_RULE `s:A->bool = s DIFF t UNION s INTER t`] THEN GEN_REWRITE_TAC (LAND_CONV o RAND_CONV o ONCE_DEPTH_CONV) [SET_RULE `t:A->bool = t DIFF s UNION s INTER t`] THEN ASM_SIMP_TAC[ITERATE_UNION; FINITE_UNION; FINITE_DIFF; FINITE_INTER; SET_RULE `DISJOINT (s DIFF s' UNION s' DIFF s) (s INTER s')`; SET_RULE `DISJOINT (s DIFF s') (s' DIFF s)`; SET_RULE `DISJOINT (s DIFF s') (s' INTER s)`; SET_RULE `DISJOINT (s DIFF s') (s INTER s')`] THEN FIRST_X_ASSUM(fun th -> REWRITE_TAC[MATCH_MP MONOIDAL_AC th]));; let ITERATE_CLOSED = prove (`!op. monoidal op ==> !P. P(neutral op) /\ (!x y. P x /\ P y ==> P (op x y)) ==> !f:A->B s. FINITE s /\ (!x. x IN s ==> P(f x)) ==> P(iterate op s f)`, GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN STRIP_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN ASM_SIMP_TAC[ITERATE_CLAUSES; FINITE_INSERT; IN_INSERT]);; let ITERATE_CLOSED_GEN = prove (`!op. monoidal op ==> !P. P(neutral op) /\ (!x y. P x /\ P y ==> P (op x y)) ==> !f:A->B s. FINITE(support op f s) /\ (!x. x IN s /\ ~(f x = neutral op) ==> P(f x)) ==> P(iterate op s f)`, ONCE_REWRITE_TAC[GSYM ITERATE_SUPPORT] THEN REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o SPEC `P:B->bool` o MATCH_MP ITERATE_CLOSED) THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[ITERATE_CLOSED; IN_SUPPORT; FINITE_SUPPORT]);; let ITERATE_RELATED = prove (`!op. monoidal op ==> !R. R (neutral op) (neutral op) /\ (!x1 y1 x2 y2. R x1 x2 /\ R y1 y2 ==> R (op x1 y1) (op x2 y2)) ==> !f:A->B g s. FINITE s /\ (!x. x IN s ==> R (f x) (g x)) ==> R (iterate op s f) (iterate op s g)`, GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN STRIP_TAC THEN GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN ASM_SIMP_TAC[ITERATE_CLAUSES; FINITE_INSERT; IN_INSERT]);; let ITERATE_EQ_NEUTRAL = prove (`!op. monoidal op ==> !f:A->B s. (!x. x IN s ==> (f(x) = neutral op)) ==> (iterate op s f = neutral op)`, REPEAT STRIP_TAC THEN SUBGOAL_THEN `support op (f:A->B) s = {}` ASSUME_TAC THENL [ASM_MESON_TAC[EXTENSION; NOT_IN_EMPTY; IN_SUPPORT]; ASM_MESON_TAC[ITERATE_CLAUSES; FINITE_RULES; ITERATE_SUPPORT]]);; let ITERATE_SING = prove (`!op. monoidal op ==> !f:A->B x. (iterate op {x} f = f x)`, SIMP_TAC[ITERATE_CLAUSES; FINITE_RULES; NOT_IN_EMPTY] THEN MESON_TAC[monoidal]);; let ITERATE_DELETE = prove (`!op. monoidal op ==> !f:A->B s a. FINITE s /\ a IN s ==> op (f a) (iterate op (s DELETE a) f) = iterate op s f`, MESON_TAC[ITERATE_CLAUSES; FINITE_DELETE; IN_DELETE; INSERT_DELETE]);; let ITERATE_DELTA = prove (`!op. monoidal op ==> !f a s. iterate op s (\x. if x = a then f(x) else neutral op) = if a IN s then f(a) else neutral op`, GEN_TAC THEN DISCH_TAC THEN ONCE_REWRITE_TAC[GSYM ITERATE_SUPPORT] THEN REWRITE_TAC[SUPPORT_DELTA] THEN REPEAT GEN_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[ITERATE_CLAUSES] THEN REWRITE_TAC[SUPPORT_CLAUSES] THEN COND_CASES_TAC THEN ASM_SIMP_TAC[ITERATE_CLAUSES; ITERATE_SING]);; let ITERATE_IMAGE = prove (`!op. monoidal op ==> !f:A->B g:B->C s. (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)) ==> (iterate op (IMAGE f s) g = iterate op s (g o f))`, GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN GEN_TAC THEN SUBGOAL_THEN `!s. FINITE s /\ (!x y:A. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)) ==> (iterate op (IMAGE f s) (g:B->C) = iterate op s (g o f))` ASSUME_TAC THENL [REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN ASM_SIMP_TAC[ITERATE_CLAUSES; IMAGE_CLAUSES; FINITE_IMAGE] THEN REWRITE_TAC[o_THM; IN_INSERT] THEN ASM_MESON_TAC[IN_IMAGE]; GEN_TAC THEN DISCH_TAC THEN ONCE_REWRITE_TAC[ITERATE_EXPAND_CASES] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC(TAUT `(a <=> a') /\ (a' ==> (b = b')) ==> (if a then b else c) = (if a' then b' else c)`) THEN REWRITE_TAC[SUPPORT_CLAUSES] THEN REPEAT STRIP_TAC THENL [MATCH_MP_TAC FINITE_IMAGE_INJ_EQ THEN ASM_MESON_TAC[IN_SUPPORT]; FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[IN_SUPPORT]]]);; let ITERATE_BIJECTION = prove (`!op. monoidal op ==> !f:A->B p s. (!x. x IN s ==> p(x) IN s) /\ (!y. y IN s ==> ?!x. x IN s /\ p(x) = y) ==> iterate op s f = iterate op s (f o p)`, REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `iterate op (IMAGE (p:A->A) s) (f:A->B)` THEN CONJ_TAC THENL [AP_THM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[EXTENSION; IN_IMAGE]; FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (INST_TYPE [aty,bty] ITERATE_IMAGE))] THEN ASM_MESON_TAC[]);; let ITERATE_ITERATE_PRODUCT = prove (`!op. monoidal op ==> !s:A->bool t:A->B->bool x:A->B->C. FINITE s /\ (!i. i IN s ==> FINITE(t i)) ==> iterate op s (\i. iterate op (t i) (x i)) = iterate op {i,j | i IN s /\ j IN t i} (\(i,j). x i j)`, GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN ASM_SIMP_TAC[NOT_IN_EMPTY; SET_RULE `{a,b | F} = {}`; ITERATE_CLAUSES] THEN REWRITE_TAC[SET_RULE `{i,j | i IN a INSERT s /\ j IN t i} = IMAGE (\j. a,j) (t a) UNION {i,j | i IN s /\ j IN t i}`] THEN ASM_SIMP_TAC[FINITE_INSERT; ITERATE_CLAUSES; IN_INSERT] THEN REPEAT STRIP_TAC THEN FIRST_ASSUM(fun th -> W(MP_TAC o PART_MATCH (lhand o rand) (MATCH_MP ITERATE_UNION th) o rand o snd)) THEN ANTS_TAC THENL [ASM_SIMP_TAC[FINITE_IMAGE; FINITE_PRODUCT_DEPENDENT; IN_INSERT] THEN REWRITE_TAC[DISJOINT; EXTENSION; IN_IMAGE; IN_INTER; NOT_IN_EMPTY; IN_ELIM_THM; EXISTS_PAIR_THM; FORALL_PAIR_THM; PAIR_EQ] THEN ASM_MESON_TAC[]; ALL_TAC] THEN DISCH_THEN SUBST1_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN FIRST_ASSUM(fun th -> W(MP_TAC o PART_MATCH (lhand o rand) (MATCH_MP ITERATE_IMAGE th) o rand o snd)) THEN ANTS_TAC THENL [SIMP_TAC[FORALL_PAIR_THM] THEN CONV_TAC(ONCE_DEPTH_CONV GEN_BETA_CONV) THEN ASM_SIMP_TAC[PAIR_EQ]; DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[o_DEF] THEN CONV_TAC(ONCE_DEPTH_CONV GEN_BETA_CONV) THEN REWRITE_TAC[ETA_AX]]);; let ITERATE_EQ = prove (`!op. monoidal op ==> !f:A->B g s. (!x. x IN s ==> f x = g x) ==> iterate op s f = iterate op s g`, REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[ITERATE_EXPAND_CASES] THEN SUBGOAL_THEN `support op g s = support op (f:A->B) s` SUBST1_TAC THENL [REWRITE_TAC[EXTENSION; IN_SUPPORT] THEN ASM_MESON_TAC[]; ALL_TAC] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN SUBGOAL_THEN `FINITE(support op (f:A->B) s) /\ (!x. x IN (support op f s) ==> f x = g x)` MP_TAC THENL [ASM_MESON_TAC[IN_SUPPORT]; REWRITE_TAC[IMP_CONJ]] THEN SPEC_TAC(`support op (f:A->B) s`,`t:A->bool`) THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN ASM_SIMP_TAC[ITERATE_CLAUSES] THEN MESON_TAC[IN_INSERT]);; let ITERATE_EQ_GENERAL = prove (`!op. monoidal op ==> !s:A->bool t:B->bool f:A->C g h. (!y. y IN t ==> ?!x. x IN s /\ h(x) = y) /\ (!x. x IN s ==> h(x) IN t /\ g(h x) = f x) ==> iterate op s f = iterate op t g`, REPEAT STRIP_TAC THEN SUBGOAL_THEN `t = IMAGE (h:A->B) s` SUBST1_TAC THENL [REWRITE_TAC[EXTENSION; IN_IMAGE] THEN ASM_MESON_TAC[]; ALL_TAC] THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `iterate op s ((g:B->C) o (h:A->B))` THEN CONJ_TAC THENL [ASM_MESON_TAC[ITERATE_EQ; o_THM]; CONV_TAC SYM_CONV THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP ITERATE_IMAGE) THEN ASM_MESON_TAC[]]);; let ITERATE_EQ_GENERAL_INVERSES = prove (`!op. monoidal op ==> !s:A->bool t:B->bool f:A->C g h k. (!y. y IN t ==> k(y) IN s /\ h(k y) = y) /\ (!x. x IN s ==> h(x) IN t /\ k(h x) = x /\ g(h x) = f x) ==> iterate op s f = iterate op t g`, REPEAT STRIP_TAC THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP ITERATE_EQ_GENERAL) THEN EXISTS_TAC `h:A->B` THEN ASM_MESON_TAC[]);; let ITERATE_INJECTION = prove (`!op. monoidal op ==> !f:A->B p:A->A s. FINITE s /\ (!x. x IN s ==> p x IN s) /\ (!x y. x IN s /\ y IN s /\ p x = p y ==> x = y) ==> iterate op s (f o p) = iterate op s f`, REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP ITERATE_BIJECTION) THEN MP_TAC(ISPECL [`s:A->bool`; `p:A->A`] SURJECTIVE_IFF_INJECTIVE) THEN ASM_REWRITE_TAC[SUBSET; IN_IMAGE] THEN ASM_MESON_TAC[]);; let ITERATE_UNION_NONZERO = prove (`!op. monoidal op ==> !f:A->B s t. FINITE(s) /\ FINITE(t) /\ (!x. x IN (s INTER t) ==> f x = neutral(op)) ==> iterate op (s UNION t) f = op (iterate op s f) (iterate op t f)`, REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM ITERATE_SUPPORT] THEN REWRITE_TAC[SUPPORT_CLAUSES] THEN FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP ITERATE_UNION) THEN ASM_SIMP_TAC[FINITE_SUPPORT; DISJOINT; IN_INTER; IN_SUPPORT; EXTENSION] THEN ASM_MESON_TAC[IN_INTER; NOT_IN_EMPTY]);; let ITERATE_OP = prove (`!op. monoidal op ==> !f g s. FINITE s ==> iterate op s (\x. op (f x) (g x)) = op (iterate op s f) (iterate op s g)`, GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN ASM_SIMP_TAC[ITERATE_CLAUSES; MONOIDAL_AC]);; let ITERATE_SUPERSET = prove (`!op. monoidal op ==> !f:A->B u v. u SUBSET v /\ (!x. x IN v /\ ~(x IN u) ==> f(x) = neutral op) ==> iterate op v f = iterate op u f`, REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM ITERATE_SUPPORT] THEN AP_THM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[support; EXTENSION; IN_ELIM_THM] THEN ASM_MESON_TAC[SUBSET]);; let ITERATE_IMAGE_NONZERO = prove (`!op. monoidal op ==> !g:B->C f:A->B s. FINITE s /\ (!x y. x IN s /\ y IN s /\ ~(x = y) /\ f x = f y ==> g(f x) = neutral op) ==> iterate op (IMAGE f s) g = iterate op s (g o f)`, GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN ASM_SIMP_TAC[IMAGE_CLAUSES; ITERATE_CLAUSES; FINITE_IMAGE] THEN MAP_EVERY X_GEN_TAC [`a:A`; `s:A->bool`] THEN REWRITE_TAC[IN_INSERT] THEN REPEAT STRIP_TAC THEN SUBGOAL_THEN `iterate op s ((g:B->C) o (f:A->B)) = iterate op (IMAGE f s) g` SUBST1_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN REWRITE_TAC[IN_IMAGE] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[o_THM] THEN SUBGOAL_THEN `(g:B->C) ((f:A->B) a) = neutral op` SUBST1_TAC THEN ASM_MESON_TAC[MONOIDAL_AC]);; let ITERATE_CASES = prove (`!op. monoidal op ==> !s P f g:A->B. FINITE s ==> iterate op s (\x. if P x then f x else g x) = op (iterate op {x | x IN s /\ P x} f) (iterate op {x | x IN s /\ ~P x} g)`, REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `op (iterate op {x | x IN s /\ P x} (\x. if P x then f x else (g:A->B) x)) (iterate op {x | x IN s /\ ~P x} (\x. if P x then f x else g x))` THEN CONJ_TAC THENL [FIRST_ASSUM(fun th -> ASM_SIMP_TAC[GSYM(MATCH_MP ITERATE_UNION th); FINITE_RESTRICT; SET_RULE `DISJOINT {x | x IN s /\ P x} {x | x IN s /\ ~P x}`]) THEN AP_THM_TAC THEN AP_TERM_TAC THEN SET_TAC[]; BINOP_TAC THEN FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP ITERATE_EQ) THEN SIMP_TAC[IN_ELIM_THM]]);; (* ------------------------------------------------------------------------- *) (* Sums of natural numbers. *) (* ------------------------------------------------------------------------- *) prioritize_num();; let nsum = new_definition `nsum = iterate (+)`;; let NEUTRAL_ADD = prove (`neutral((+):num->num->num) = 0`, REWRITE_TAC[neutral] THEN MATCH_MP_TAC SELECT_UNIQUE THEN MESON_TAC[ADD_CLAUSES]);; let NEUTRAL_MUL = prove (`neutral(( * ):num->num->num) = 1`, REWRITE_TAC[neutral] THEN MATCH_MP_TAC SELECT_UNIQUE THEN MESON_TAC[MULT_CLAUSES; MULT_EQ_1]);; let MONOIDAL_ADD = prove (`monoidal((+):num->num->num)`, REWRITE_TAC[monoidal; NEUTRAL_ADD] THEN ARITH_TAC);; let MONOIDAL_MUL = prove (`monoidal(( * ):num->num->num)`, REWRITE_TAC[monoidal; NEUTRAL_MUL] THEN ARITH_TAC);; let NSUM_CLAUSES = prove (`(!f. nsum {} f = 0) /\ (!x f s. FINITE(s) ==> (nsum (x INSERT s) f = if x IN s then nsum s f else f(x) + nsum s f))`, REWRITE_TAC[nsum; GSYM NEUTRAL_ADD] THEN ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN MATCH_MP_TAC ITERATE_CLAUSES THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_UNION = prove (`!f s t. FINITE s /\ FINITE t /\ DISJOINT s t ==> (nsum (s UNION t) f = nsum s f + nsum t f)`, SIMP_TAC[nsum; ITERATE_UNION; MONOIDAL_ADD]);; let NSUM_DIFF = prove (`!f s t. FINITE s /\ t SUBSET s ==> (nsum (s DIFF t) f = nsum s f - nsum t f)`, REPEAT STRIP_TAC THEN MATCH_MP_TAC(ARITH_RULE `(x + z = y:num) ==> (x = y - z)`) THEN ASM_SIMP_TAC[nsum; ITERATE_DIFF; MONOIDAL_ADD]);; let NSUM_INCL_EXCL = prove (`!s t (f:A->num). FINITE s /\ FINITE t ==> nsum s f + nsum t f = nsum (s UNION t) f + nsum (s INTER t) f`, REWRITE_TAC[nsum; GSYM NEUTRAL_ADD] THEN MATCH_MP_TAC ITERATE_INCL_EXCL THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_SUPPORT = prove (`!f s. nsum (support (+) f s) f = nsum s f`, SIMP_TAC[nsum; iterate; SUPPORT_SUPPORT]);; let NSUM_ADD = prove (`!f g s. FINITE s ==> (nsum s (\x. f(x) + g(x)) = nsum s f + nsum s g)`, SIMP_TAC[nsum; ITERATE_OP; MONOIDAL_ADD]);; let NSUM_EQ_0 = prove (`!f s. (!x:A. x IN s ==> (f(x) = 0)) ==> (nsum s f = 0)`, REWRITE_TAC[nsum; GSYM NEUTRAL_ADD] THEN SIMP_TAC[ITERATE_EQ_NEUTRAL; MONOIDAL_ADD]);; let NSUM_0 = prove (`!s:A->bool. nsum s (\n. 0) = 0`, SIMP_TAC[NSUM_EQ_0]);; let NSUM_LMUL = prove (`!f c s:A->bool. nsum s (\x. c * f(x)) = c * nsum s f`, REPEAT GEN_TAC THEN ASM_CASES_TAC `c = 0` THEN ASM_REWRITE_TAC[MULT_CLAUSES; NSUM_0] THEN REWRITE_TAC[nsum] THEN ONCE_REWRITE_TAC[ITERATE_EXPAND_CASES] THEN SUBGOAL_THEN `support (+) (\x:A. c * f(x)) s = support (+) f s` SUBST1_TAC THENL [ASM_SIMP_TAC[support; MULT_EQ_0; NEUTRAL_ADD]; ALL_TAC] THEN COND_CASES_TAC THEN REWRITE_TAC[NEUTRAL_ADD; MULT_CLAUSES] THEN UNDISCH_TAC `FINITE (support (+) f (s:A->bool))` THEN SPEC_TAC(`support (+) f (s:A->bool)`,`t:A->bool`) THEN REWRITE_TAC[GSYM nsum] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[NSUM_CLAUSES; MULT_CLAUSES; LEFT_ADD_DISTRIB]);; let NSUM_RMUL = prove (`!f c s:A->bool. nsum s (\x. f(x) * c) = nsum s f * c`, ONCE_REWRITE_TAC[MULT_SYM] THEN REWRITE_TAC[NSUM_LMUL]);; let NSUM_LE = prove (`!f g s. FINITE(s) /\ (!x. x IN s ==> f(x) <= g(x)) ==> nsum s f <= nsum s g`, ONCE_REWRITE_TAC[IMP_CONJ] THEN GEN_TAC THEN GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[NSUM_CLAUSES; LE_REFL; LE_ADD2; IN_INSERT]);; let NSUM_LT = prove (`!f g s:A->bool. FINITE(s) /\ (!x. x IN s ==> f(x) <= g(x)) /\ (?x. x IN s /\ f(x) < g(x)) ==> nsum s f < nsum s g`, REPEAT GEN_TAC THEN REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN DISCH_THEN(X_CHOOSE_THEN `a:A` STRIP_ASSUME_TAC) THEN SUBGOAL_THEN `s = (a:A) INSERT (s DELETE a)` SUBST1_TAC THENL [UNDISCH_TAC `a:A IN s` THEN SET_TAC[]; ALL_TAC] THEN ASM_SIMP_TAC[NSUM_CLAUSES; FINITE_DELETE; IN_DELETE] THEN ASM_SIMP_TAC[LTE_ADD2; NSUM_LE; IN_DELETE; FINITE_DELETE]);; let NSUM_LT_ALL = prove (`!f g s. FINITE s /\ ~(s = {}) /\ (!x. x IN s ==> f(x) < g(x)) ==> nsum s f < nsum s g`, MESON_TAC[MEMBER_NOT_EMPTY; LT_IMP_LE; NSUM_LT]);; let NSUM_EQ = prove (`!f g s. (!x. x IN s ==> (f x = g x)) ==> (nsum s f = nsum s g)`, REWRITE_TAC[nsum] THEN MATCH_MP_TAC ITERATE_EQ THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_CONST = prove (`!c s. FINITE s ==> (nsum s (\n. c) = (CARD s) * c)`, GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[NSUM_CLAUSES; CARD_CLAUSES] THEN REPEAT STRIP_TAC THEN ARITH_TAC);; let NSUM_POS_BOUND = prove (`!f b s. FINITE s /\ nsum s f <= b ==> !x:A. x IN s ==> f x <= b`, GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[NSUM_CLAUSES; NOT_IN_EMPTY; IN_INSERT] THEN MESON_TAC[LE_0; ARITH_RULE `0 <= x /\ 0 <= y /\ x + y <= b ==> x <= b /\ y <= b`]);; let NSUM_EQ_0_IFF = prove (`!s. FINITE s ==> (nsum s f = 0 <=> !x. x IN s ==> f x = 0)`, REPEAT STRIP_TAC THEN EQ_TAC THEN ASM_SIMP_TAC[NSUM_EQ_0] THEN ASM_MESON_TAC[ARITH_RULE `n = 0 <=> n <= 0`; NSUM_POS_BOUND]);; let NSUM_DELETE = prove (`!f s a. FINITE s /\ a IN s ==> f(a) + nsum(s DELETE a) f = nsum s f`, SIMP_TAC[nsum; ITERATE_DELETE; MONOIDAL_ADD]);; let NSUM_SING = prove (`!f x. nsum {x} f = f(x)`, SIMP_TAC[NSUM_CLAUSES; FINITE_RULES; NOT_IN_EMPTY; ADD_CLAUSES]);; let NSUM_DELTA = prove (`!s a. nsum s (\x. if x = a:A then b else 0) = if a IN s then b else 0`, REWRITE_TAC[nsum; GSYM NEUTRAL_ADD] THEN SIMP_TAC[ITERATE_DELTA; MONOIDAL_ADD]);; let NSUM_SWAP = prove (`!f:A->B->num s t. FINITE(s) /\ FINITE(t) ==> (nsum s (\i. nsum t (f i)) = nsum t (\j. nsum s (\i. f i j)))`, GEN_TAC THEN REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[NSUM_CLAUSES; NSUM_0; NSUM_ADD; ETA_AX]);; let NSUM_IMAGE = prove (`!f g s. (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)) ==> (nsum (IMAGE f s) g = nsum s (g o f))`, REWRITE_TAC[nsum; GSYM NEUTRAL_ADD] THEN MATCH_MP_TAC ITERATE_IMAGE THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_SUPERSET = prove (`!f:A->num u v. u SUBSET v /\ (!x. x IN v /\ ~(x IN u) ==> (f(x) = 0)) ==> (nsum v f = nsum u f)`, SIMP_TAC[nsum; GSYM NEUTRAL_ADD; ITERATE_SUPERSET; MONOIDAL_ADD]);; let NSUM_UNION_RZERO = prove (`!f:A->num u v. FINITE u /\ (!x. x IN v /\ ~(x IN u) ==> (f(x) = 0)) ==> (nsum (u UNION v) f = nsum u f)`, let lemma = prove(`u UNION v = u UNION (v DIFF u)`,SET_TAC[]) in REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[lemma] THEN MATCH_MP_TAC NSUM_SUPERSET THEN ASM_MESON_TAC[IN_UNION; IN_DIFF; SUBSET]);; let NSUM_UNION_LZERO = prove (`!f:A->num u v. FINITE v /\ (!x. x IN u /\ ~(x IN v) ==> (f(x) = 0)) ==> (nsum (u UNION v) f = nsum v f)`, MESON_TAC[NSUM_UNION_RZERO; UNION_COMM]);; let NSUM_RESTRICT = prove (`!f s. FINITE s ==> (nsum s (\x. if x IN s then f(x) else 0) = nsum s f)`, REPEAT STRIP_TAC THEN MATCH_MP_TAC NSUM_EQ THEN ASM_SIMP_TAC[]);; let NSUM_BOUND = prove (`!s f b. FINITE s /\ (!x:A. x IN s ==> f(x) <= b) ==> nsum s f <= (CARD s) * b`, SIMP_TAC[GSYM NSUM_CONST; NSUM_LE]);; let NSUM_BOUND_GEN = prove (`!s t b. FINITE s /\ ~(s = {}) /\ (!x:A. x IN s ==> f(x) <= b DIV (CARD s)) ==> nsum s f <= b`, SIMP_TAC[IMP_CONJ; CARD_EQ_0; LE_RDIV_EQ] THEN REPEAT STRIP_TAC THEN SUBGOAL_THEN `nsum s (\x. CARD(s:A->bool) * f x) <= CARD s * b` MP_TAC THENL [ASM_SIMP_TAC[NSUM_BOUND]; ASM_SIMP_TAC[NSUM_LMUL; LE_MULT_LCANCEL; CARD_EQ_0]]);; let NSUM_BOUND_LT = prove (`!s f b. FINITE s /\ (!x:A. x IN s ==> f x <= b) /\ (?x. x IN s /\ f x < b) ==> nsum s f < (CARD s) * b`, REPEAT STRIP_TAC THEN MATCH_MP_TAC LTE_TRANS THEN EXISTS_TAC `nsum s (\x:A. b)` THEN CONJ_TAC THENL [MATCH_MP_TAC NSUM_LT THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ASM_SIMP_TAC[NSUM_CONST; LE_REFL]]);; let NSUM_BOUND_LT_ALL = prove (`!s f b. FINITE s /\ ~(s = {}) /\ (!x. x IN s ==> f(x) < b) ==> nsum s f < (CARD s) * b`, MESON_TAC[MEMBER_NOT_EMPTY; LT_IMP_LE; NSUM_BOUND_LT]);; let NSUM_BOUND_LT_GEN = prove (`!s t b. FINITE s /\ ~(s = {}) /\ (!x:A. x IN s ==> f(x) < b DIV (CARD s)) ==> nsum s f < b`, REPEAT STRIP_TAC THEN MATCH_MP_TAC LTE_TRANS THEN EXISTS_TAC `nsum (s:A->bool) (\a. f(a) + 1)` THEN CONJ_TAC THENL [MATCH_MP_TAC NSUM_LT_ALL THEN ASM_SIMP_TAC[] THEN ARITH_TAC; MATCH_MP_TAC NSUM_BOUND_GEN THEN ASM_REWRITE_TAC[ARITH_RULE `a + 1 <= b <=> a < b`]]);; let NSUM_UNION_EQ = prove (`!s t u. FINITE u /\ (s INTER t = {}) /\ (s UNION t = u) ==> (nsum s f + nsum t f = nsum u f)`, MESON_TAC[NSUM_UNION; DISJOINT; FINITE_SUBSET; SUBSET_UNION]);; let NSUM_EQ_SUPERSET = prove (`!f s t:A->bool. FINITE t /\ t SUBSET s /\ (!x. x IN t ==> (f x = g x)) /\ (!x. x IN s /\ ~(x IN t) ==> (f(x) = 0)) ==> (nsum s f = nsum t g)`, MESON_TAC[NSUM_SUPERSET; NSUM_EQ]);; let NSUM_RESTRICT_SET = prove (`!s f r. FINITE s ==> (nsum {x:A | x IN s /\ P x} f = nsum s (\x. if P x then f(x) else 0))`, REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC NSUM_EQ_SUPERSET THEN ASM_SIMP_TAC[FINITE_RESTRICT] THEN ASM_SIMP_TAC[SUBSET; IN_ELIM_THM] THEN MESON_TAC[]);; let NSUM_NSUM_RESTRICT = prove (`!R f s t. FINITE s /\ FINITE t ==> (nsum s (\x. nsum {y | y IN t /\ R x y} (\y. f x y)) = nsum t (\y. nsum {x | x IN s /\ R x y} (\x. f x y)))`, REPEAT GEN_TAC THEN SIMP_TAC[NSUM_RESTRICT_SET] THEN DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP NSUM_SWAP th]));; let CARD_EQ_NSUM = prove (`!s. FINITE s ==> ((CARD s) = nsum s (\x. 1))`, SIMP_TAC[NSUM_CONST; MULT_CLAUSES]);; let NSUM_MULTICOUNT_GEN = prove (`!R:A->B->bool s t k. FINITE s /\ FINITE t /\ (!j. j IN t ==> (CARD {i | i IN s /\ R i j} = k(j))) ==> (nsum s (\i. (CARD {j | j IN t /\ R i j})) = nsum t (\i. (k i)))`, REPEAT GEN_TAC THEN REWRITE_TAC[CONJ_ASSOC] THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `nsum s (\i:A. nsum {j:B | j IN t /\ R i j} (\j. 1))` THEN CONJ_TAC THENL [MATCH_MP_TAC NSUM_EQ THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN ASM_SIMP_TAC[CARD_EQ_NSUM; FINITE_RESTRICT]; FIRST_ASSUM(fun t -> ONCE_REWRITE_TAC[MATCH_MP NSUM_NSUM_RESTRICT t]) THEN MATCH_MP_TAC NSUM_EQ THEN ASM_SIMP_TAC[NSUM_CONST; FINITE_RESTRICT] THEN REWRITE_TAC[MULT_CLAUSES]]);; let NSUM_MULTICOUNT = prove (`!R:A->B->bool s t k. FINITE s /\ FINITE t /\ (!j. j IN t ==> (CARD {i | i IN s /\ R i j} = k)) ==> (nsum s (\i. (CARD {j | j IN t /\ R i j})) = (k * CARD t))`, REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `nsum t (\i:B. k)` THEN CONJ_TAC THENL [MATCH_MP_TAC NSUM_MULTICOUNT_GEN THEN ASM_REWRITE_TAC[]; ASM_SIMP_TAC[NSUM_CONST] THEN REWRITE_TAC[MULT_AC]]);; let NSUM_IMAGE_GEN = prove (`!f:A->B g s. FINITE s ==> (nsum s g = nsum (IMAGE f s) (\y. nsum {x | x IN s /\ (f(x) = y)} g))`, REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `nsum s (\x:A. nsum {y:B | y IN IMAGE f s /\ (f x = y)} (\y. g x))` THEN CONJ_TAC THENL [MATCH_MP_TAC NSUM_EQ THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:A` THEN DISCH_TAC THEN SUBGOAL_THEN `{y | y IN IMAGE (f:A->B) s /\ (f x = y)} = {(f x)}` (fun th -> REWRITE_TAC[th; NSUM_SING; o_THM]) THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_SING; IN_IMAGE] THEN ASM_MESON_TAC[]; GEN_REWRITE_TAC (funpow 2 RAND_CONV o ABS_CONV o RAND_CONV) [GSYM ETA_AX] THEN ASM_SIMP_TAC[NSUM_NSUM_RESTRICT; FINITE_IMAGE]]);; let NSUM_GROUP = prove (`!f:A->B g s t. FINITE s /\ IMAGE f s SUBSET t ==> nsum t (\y. nsum {x | x IN s /\ f(x) = y} g) = nsum s g`, REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`f:A->B`; `g:A->num`; `s:A->bool`] NSUM_IMAGE_GEN) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC NSUM_SUPERSET THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC NSUM_EQ_0 THEN ASM SET_TAC[]);; let NSUM_SUBSET = prove (`!u v f. FINITE u /\ FINITE v /\ (!x:A. x IN (u DIFF v) ==> f(x) = 0) ==> nsum u f <= nsum v f`, REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`f:A->num`; `u INTER v :A->bool`] NSUM_UNION) THEN DISCH_THEN(fun th -> MP_TAC(SPEC `v DIFF u :A->bool` th) THEN MP_TAC(SPEC `u DIFF v :A->bool` th)) THEN REWRITE_TAC[SET_RULE `(u INTER v) UNION (u DIFF v) = u`; SET_RULE `(u INTER v) UNION (v DIFF u) = v`] THEN ASM_SIMP_TAC[FINITE_DIFF; FINITE_INTER] THEN REPEAT(ANTS_TAC THENL [SET_TAC[]; DISCH_THEN SUBST1_TAC]) THEN ASM_SIMP_TAC[NSUM_EQ_0] THEN ARITH_TAC);; let NSUM_SUBSET_SIMPLE = prove (`!u v f. FINITE v /\ u SUBSET v ==> nsum u f <= nsum v f`, REPEAT STRIP_TAC THEN MATCH_MP_TAC NSUM_SUBSET THEN ASM_MESON_TAC[IN_DIFF; SUBSET; FINITE_SUBSET]);; let NSUM_IMAGE_NONZERO = prove (`!d:B->num i:A->B s. FINITE s /\ (!x y. x IN s /\ y IN s /\ ~(x = y) /\ i x = i y ==> d(i x) = 0) ==> nsum (IMAGE i s) d = nsum s (d o i)`, REWRITE_TAC[GSYM NEUTRAL_ADD; nsum] THEN MATCH_MP_TAC ITERATE_IMAGE_NONZERO THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_BIJECTION = prove (`!f p s:A->bool. (!x. x IN s ==> p(x) IN s) /\ (!y. y IN s ==> ?!x. x IN s /\ p(x) = y) ==> nsum s f = nsum s (f o p)`, REWRITE_TAC[nsum] THEN MATCH_MP_TAC ITERATE_BIJECTION THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_NSUM_PRODUCT = prove (`!s:A->bool t:A->B->bool x. FINITE s /\ (!i. i IN s ==> FINITE(t i)) ==> nsum s (\i. nsum (t i) (x i)) = nsum {i,j | i IN s /\ j IN t i} (\(i,j). x i j)`, REWRITE_TAC[nsum] THEN MATCH_MP_TAC ITERATE_ITERATE_PRODUCT THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_EQ_GENERAL = prove (`!s:A->bool t:B->bool f g h. (!y. y IN t ==> ?!x. x IN s /\ h(x) = y) /\ (!x. x IN s ==> h(x) IN t /\ g(h x) = f x) ==> nsum s f = nsum t g`, REWRITE_TAC[nsum] THEN MATCH_MP_TAC ITERATE_EQ_GENERAL THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_EQ_GENERAL_INVERSES = prove (`!s:A->bool t:B->bool f g h k. (!y. y IN t ==> k(y) IN s /\ h(k y) = y) /\ (!x. x IN s ==> h(x) IN t /\ k(h x) = x /\ g(h x) = f x) ==> nsum s f = nsum t g`, REWRITE_TAC[nsum] THEN MATCH_MP_TAC ITERATE_EQ_GENERAL_INVERSES THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_INJECTION = prove (`!f p s. FINITE s /\ (!x. x IN s ==> p x IN s) /\ (!x y. x IN s /\ y IN s /\ p x = p y ==> x = y) ==> nsum s (f o p) = nsum s f`, REWRITE_TAC[nsum] THEN MATCH_MP_TAC ITERATE_INJECTION THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_UNION_NONZERO = prove (`!f s t. FINITE s /\ FINITE t /\ (!x. x IN s INTER t ==> f(x) = 0) ==> nsum (s UNION t) f = nsum s f + nsum t f`, REWRITE_TAC[nsum; GSYM NEUTRAL_ADD] THEN MATCH_MP_TAC ITERATE_UNION_NONZERO THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_UNIONS_NONZERO = prove (`!f s. FINITE s /\ (!t:A->bool. t IN s ==> FINITE t) /\ (!t1 t2 x. t1 IN s /\ t2 IN s /\ ~(t1 = t2) /\ x IN t1 /\ x IN t2 ==> f x = 0) ==> nsum (UNIONS s) f = nsum s (\t. nsum t f)`, GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[UNIONS_0; UNIONS_INSERT; NSUM_CLAUSES; IN_INSERT] THEN MAP_EVERY X_GEN_TAC [`t:A->bool`; `s:(A->bool)->bool`] THEN DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN ASM_SIMP_TAC[NSUM_CLAUSES] THEN ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_THEN(SUBST_ALL_TAC o SYM)] THEN STRIP_TAC THEN MATCH_MP_TAC NSUM_UNION_NONZERO THEN ASM_SIMP_TAC[FINITE_UNIONS; IN_INTER; IN_UNIONS] THEN ASM_MESON_TAC[]);; let NSUM_CASES = prove (`!s P f g. FINITE s ==> nsum s (\x:A. if P x then f x else g x) = nsum {x | x IN s /\ P x} f + nsum {x | x IN s /\ ~P x} g`, REWRITE_TAC[nsum; GSYM NEUTRAL_ADD] THEN MATCH_MP_TAC ITERATE_CASES THEN REWRITE_TAC[MONOIDAL_ADD]);; let NSUM_ADD_NUMSEG = prove (`!f g m n. nsum(m..n) (\i. f(i) + g(i)) = nsum(m..n) f + nsum(m..n) g`, SIMP_TAC[NSUM_ADD; FINITE_NUMSEG]);; let NSUM_LE_NUMSEG = prove (`!f g m n. (!i. m <= i /\ i <= n ==> f(i) <= g(i)) ==> nsum(m..n) f <= nsum(m..n) g`, SIMP_TAC[NSUM_LE; FINITE_NUMSEG; IN_NUMSEG]);; let NSUM_EQ_NUMSEG = prove (`!f g m n. (!i. m <= i /\ i <= n ==> (f(i) = g(i))) ==> (nsum(m..n) f = nsum(m..n) g)`, MESON_TAC[NSUM_EQ; FINITE_NUMSEG; IN_NUMSEG]);; let NSUM_CONST_NUMSEG = prove (`!c m n. nsum(m..n) (\n. c) = ((n + 1) - m) * c`, SIMP_TAC[NSUM_CONST; FINITE_NUMSEG; CARD_NUMSEG]);; let NSUM_EQ_0_NUMSEG = prove (`!f s. (!i. m <= i /\ i <= n ==> (f(i) = 0)) ==> (nsum(m..n) f = 0)`, SIMP_TAC[NSUM_EQ_0; IN_NUMSEG]);; let NSUM_EQ_0_IFF_NUMSEG = prove (`!f m n. nsum (m..n) f = 0 <=> !i. m <= i /\ i <= n ==> f i = 0`, SIMP_TAC[NSUM_EQ_0_IFF; FINITE_NUMSEG; IN_NUMSEG]);; let NSUM_TRIV_NUMSEG = prove (`!f m n. n < m ==> (nsum(m..n) f = 0)`, MESON_TAC[NSUM_EQ_0_NUMSEG; LE_TRANS; NOT_LT]);; let NSUM_SING_NUMSEG = prove (`!f n. nsum(n..n) f = f(n)`, SIMP_TAC[NSUM_SING; NUMSEG_SING]);; let NSUM_CLAUSES_NUMSEG = prove (`(!m. nsum(m..0) f = if m = 0 then f(0) else 0) /\ (!m n. nsum(m..SUC n) f = if m <= SUC n then nsum(m..n) f + f(SUC n) else nsum(m..n) f)`, REWRITE_TAC[NUMSEG_CLAUSES] THEN REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[NSUM_SING; NSUM_CLAUSES; FINITE_NUMSEG; IN_NUMSEG] THEN REWRITE_TAC[ARITH_RULE `~(SUC n <= n)`; ADD_AC]);; let NSUM_SWAP_NUMSEG = prove (`!a b c d f. nsum(a..b) (\i. nsum(c..d) (f i)) = nsum(c..d) (\j. nsum(a..b) (\i. f i j))`, REPEAT GEN_TAC THEN MATCH_MP_TAC NSUM_SWAP THEN REWRITE_TAC[FINITE_NUMSEG]);; let NSUM_ADD_SPLIT = prove (`!f m n p. m <= n + 1 ==> (nsum (m..(n+p)) f = nsum(m..n) f + nsum(n+1..n+p) f)`, SIMP_TAC[NUMSEG_ADD_SPLIT; NSUM_UNION; DISJOINT_NUMSEG; FINITE_NUMSEG; ARITH_RULE `x < x + 1`]);; let NSUM_OFFSET = prove (`!p f m n. nsum(m+p..n+p) f = nsum(m..n) (\i. f(i + p))`, SIMP_TAC[NUMSEG_OFFSET_IMAGE; NSUM_IMAGE; EQ_ADD_RCANCEL; FINITE_NUMSEG] THEN REWRITE_TAC[o_DEF]);; let NSUM_OFFSET_0 = prove (`!f m n. m <= n ==> (nsum(m..n) f = nsum(0..n-m) (\i. f(i + m)))`, SIMP_TAC[GSYM NSUM_OFFSET; ADD_CLAUSES; SUB_ADD]);; let NSUM_CLAUSES_LEFT = prove (`!f m n. m <= n ==> nsum(m..n) f = f(m) + nsum(m+1..n) f`, SIMP_TAC[GSYM NUMSEG_LREC; NSUM_CLAUSES; FINITE_NUMSEG; IN_NUMSEG] THEN ARITH_TAC);; let NSUM_CLAUSES_RIGHT = prove (`!f m n. 0 < n /\ m <= n ==> nsum(m..n) f = nsum(m..n-1) f + f(n)`, GEN_TAC THEN GEN_TAC THEN INDUCT_TAC THEN SIMP_TAC[LT_REFL; NSUM_CLAUSES_NUMSEG; SUC_SUB1]);; let th = prove (`(!f g s. (!x. x IN s ==> f(x) = g(x)) ==> nsum s (\i. f(i)) = nsum s g) /\ (!f g a b. (!i. a <= i /\ i <= b ==> f(i) = g(i)) ==> nsum(a..b) (\i. f(i)) = nsum(a..b) g) /\ (!f g p. (!x. p x ==> f x = g x) ==> nsum {y | p y} (\i. f(i)) = nsum {y | p y} g)`, REPEAT STRIP_TAC THEN MATCH_MP_TAC NSUM_EQ THEN ASM_SIMP_TAC[IN_ELIM_THM; IN_NUMSEG]) in extend_basic_congs (map SPEC_ALL (CONJUNCTS th));; (* ------------------------------------------------------------------------- *) (* Thanks to finite sums, we can express cardinality of finite union. *) (* ------------------------------------------------------------------------- *) let CARD_UNIONS = prove (`!s:(A->bool)->bool. FINITE s /\ (!t. t IN s ==> FINITE t) /\ (!t u. t IN s /\ u IN s /\ ~(t = u) ==> t INTER u = {}) ==> CARD(UNIONS s) = nsum s CARD`, ONCE_REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[UNIONS_0; UNIONS_INSERT; NOT_IN_EMPTY; IN_INSERT] THEN REWRITE_TAC[CARD_CLAUSES; NSUM_CLAUSES] THEN MAP_EVERY X_GEN_TAC [`t:A->bool`; `f:(A->bool)->bool`] THEN DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_SIMP_TAC[NSUM_CLAUSES] THEN DISCH_THEN(CONJUNCTS_THEN2 (SUBST1_TAC o SYM) STRIP_ASSUME_TAC) THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC CARD_UNION_EQ THEN ASM_SIMP_TAC[FINITE_UNIONS; FINITE_UNION; INTER_UNIONS] THEN REWRITE_TAC[EMPTY_UNIONS; IN_ELIM_THM] THEN ASM MESON_TAC[]);; (* ------------------------------------------------------------------------- *) (* Sums of real numbers. *) (* ------------------------------------------------------------------------- *) prioritize_real();; let sum = new_definition `sum = iterate (+)`;; let NEUTRAL_REAL_ADD = prove (`neutral((+):real->real->real) = &0`, REWRITE_TAC[neutral] THEN MATCH_MP_TAC SELECT_UNIQUE THEN MESON_TAC[REAL_ADD_LID; REAL_ADD_RID]);; let NEUTRAL_REAL_MUL = prove (`neutral(( * ):real->real->real) = &1`, REWRITE_TAC[neutral] THEN MATCH_MP_TAC SELECT_UNIQUE THEN MESON_TAC[REAL_MUL_LID; REAL_MUL_RID]);; let MONOIDAL_REAL_ADD = prove (`monoidal((+):real->real->real)`, REWRITE_TAC[monoidal; NEUTRAL_REAL_ADD] THEN REAL_ARITH_TAC);; let MONOIDAL_REAL_MUL = prove (`monoidal(( * ):real->real->real)`, REWRITE_TAC[monoidal; NEUTRAL_REAL_MUL] THEN REAL_ARITH_TAC);; let SUM_CLAUSES = prove (`(!f. sum {} f = &0) /\ (!x f s. FINITE(s) ==> (sum (x INSERT s) f = if x IN s then sum s f else f(x) + sum s f))`, REWRITE_TAC[sum; GSYM NEUTRAL_REAL_ADD] THEN ONCE_REWRITE_TAC[SWAP_FORALL_THM] THEN MATCH_MP_TAC ITERATE_CLAUSES THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_UNION = prove (`!f s t. FINITE s /\ FINITE t /\ DISJOINT s t ==> (sum (s UNION t) f = sum s f + sum t f)`, SIMP_TAC[sum; ITERATE_UNION; MONOIDAL_REAL_ADD]);; let SUM_DIFF = prove (`!f s t. FINITE s /\ t SUBSET s ==> (sum (s DIFF t) f = sum s f - sum t f)`, SIMP_TAC[REAL_EQ_SUB_LADD; sum; ITERATE_DIFF; MONOIDAL_REAL_ADD]);; let SUM_INCL_EXCL = prove (`!s t (f:A->real). FINITE s /\ FINITE t ==> sum s f + sum t f = sum (s UNION t) f + sum (s INTER t) f`, REWRITE_TAC[sum; GSYM NEUTRAL_REAL_ADD] THEN MATCH_MP_TAC ITERATE_INCL_EXCL THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_SUPPORT = prove (`!f s. sum (support (+) f s) f = sum s f`, SIMP_TAC[sum; iterate; SUPPORT_SUPPORT]);; let SUM_ADD = prove (`!f g s. FINITE s ==> (sum s (\x. f(x) + g(x)) = sum s f + sum s g)`, SIMP_TAC[sum; ITERATE_OP; MONOIDAL_REAL_ADD]);; let SUM_EQ_0 = prove (`!f s. (!x:A. x IN s ==> (f(x) = &0)) ==> (sum s f = &0)`, REWRITE_TAC[sum; GSYM NEUTRAL_REAL_ADD] THEN SIMP_TAC[ITERATE_EQ_NEUTRAL; MONOIDAL_REAL_ADD]);; let SUM_0 = prove (`!s:A->bool. sum s (\n. &0) = &0`, SIMP_TAC[SUM_EQ_0]);; let SUM_LMUL = prove (`!f c s:A->bool. sum s (\x. c * f(x)) = c * sum s f`, REPEAT GEN_TAC THEN ASM_CASES_TAC `c = &0` THEN ASM_REWRITE_TAC[REAL_MUL_LZERO; SUM_0] THEN REWRITE_TAC[sum] THEN ONCE_REWRITE_TAC[ITERATE_EXPAND_CASES] THEN SUBGOAL_THEN `support (+) (\x:A. c * f(x)) s = support (+) f s` SUBST1_TAC THENL [ASM_SIMP_TAC[support; REAL_ENTIRE; NEUTRAL_REAL_ADD]; ALL_TAC] THEN COND_CASES_TAC THEN REWRITE_TAC[NEUTRAL_REAL_ADD; REAL_MUL_RZERO] THEN UNDISCH_TAC `FINITE (support (+) f (s:A->bool))` THEN SPEC_TAC(`support (+) f (s:A->bool)`,`t:A->bool`) THEN REWRITE_TAC[GSYM sum] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[SUM_CLAUSES; REAL_MUL_RZERO; REAL_MUL_LZERO; REAL_ADD_LDISTRIB]);; let SUM_RMUL = prove (`!f c s:A->bool. sum s (\x. f(x) * c) = sum s f * c`, ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[SUM_LMUL]);; let SUM_NEG = prove (`!f s. sum s (\x. --(f(x))) = --(sum s f)`, ONCE_REWRITE_TAC[REAL_ARITH `--x = --(&1) * x`] THEN SIMP_TAC[SUM_LMUL]);; let SUM_SUB = prove (`!f g s. FINITE s ==> (sum s (\x. f(x) - g(x)) = sum s f - sum s g)`, ONCE_REWRITE_TAC[real_sub] THEN SIMP_TAC[SUM_NEG; SUM_ADD]);; let SUM_LE = prove (`!f g s. FINITE(s) /\ (!x. x IN s ==> f(x) <= g(x)) ==> sum s f <= sum s g`, ONCE_REWRITE_TAC[IMP_CONJ] THEN GEN_TAC THEN GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[SUM_CLAUSES; REAL_LE_REFL; REAL_LE_ADD2; IN_INSERT]);; let SUM_LT = prove (`!f g s:A->bool. FINITE(s) /\ (!x. x IN s ==> f(x) <= g(x)) /\ (?x. x IN s /\ f(x) < g(x)) ==> sum s f < sum s g`, REPEAT GEN_TAC THEN REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN DISCH_THEN(X_CHOOSE_THEN `a:A` STRIP_ASSUME_TAC) THEN SUBGOAL_THEN `s = (a:A) INSERT (s DELETE a)` SUBST1_TAC THENL [UNDISCH_TAC `a:A IN s` THEN SET_TAC[]; ALL_TAC] THEN ASM_SIMP_TAC[SUM_CLAUSES; FINITE_DELETE; IN_DELETE] THEN ASM_SIMP_TAC[REAL_LTE_ADD2; SUM_LE; IN_DELETE; FINITE_DELETE]);; let SUM_LT_ALL = prove (`!f g s. FINITE s /\ ~(s = {}) /\ (!x. x IN s ==> f(x) < g(x)) ==> sum s f < sum s g`, MESON_TAC[MEMBER_NOT_EMPTY; REAL_LT_IMP_LE; SUM_LT]);; let SUM_EQ = prove (`!f g s. (!x. x IN s ==> (f x = g x)) ==> (sum s f = sum s g)`, REWRITE_TAC[sum] THEN MATCH_MP_TAC ITERATE_EQ THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_ABS = prove (`!f s. FINITE(s) ==> abs(sum s f) <= sum s (\x. abs(f x))`, GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[SUM_CLAUSES; REAL_ABS_NUM; REAL_LE_REFL; REAL_ARITH `abs(a) <= b ==> abs(x + a) <= abs(x) + b`]);; let SUM_ABS_LE = prove (`!f:A->real g s. FINITE s /\ (!x. x IN s ==> abs(f x) <= g x) ==> abs(sum s f) <= sum s g`, REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `sum s (\x:A. abs(f x))` THEN ASM_SIMP_TAC[SUM_ABS] THEN MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[]);; let SUM_CONST = prove (`!c s. FINITE s ==> (sum s (\n. c) = &(CARD s) * c)`, GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[SUM_CLAUSES; CARD_CLAUSES; GSYM REAL_OF_NUM_SUC] THEN REPEAT STRIP_TAC THEN REAL_ARITH_TAC);; let SUM_POS_LE = prove (`!f s. FINITE s /\ (!x. x IN s ==> &0 <= f(x)) ==> &0 <= sum s f`, REWRITE_TAC[REWRITE_RULE[SUM_0] (ISPEC `\x. &0` SUM_LE)]);; let SUM_POS_BOUND = prove (`!f b s. FINITE s /\ (!x. x IN s ==> &0 <= f x) /\ sum s f <= b ==> !x:A. x IN s ==> f x <= b`, GEN_TAC THEN GEN_TAC THEN REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[SUM_CLAUSES; NOT_IN_EMPTY; IN_INSERT] THEN MESON_TAC[SUM_POS_LE; REAL_ARITH `&0 <= x /\ &0 <= y /\ x + y <= b ==> x <= b /\ y <= b`]);; let SUM_POS_EQ_0 = prove (`!f s. FINITE s /\ (!x. x IN s ==> &0 <= f x) /\ (sum s f = &0) ==> !x. x IN s ==> f x = &0`, REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN MESON_TAC[SUM_POS_BOUND; SUM_POS_LE]);; let SUM_ZERO_EXISTS = prove (`!(u:A->real) s. FINITE s /\ sum s u = &0 ==> (!i. i IN s ==> u i = &0) \/ (?j k. j IN s /\ u j < &0 /\ k IN s /\ u k > &0)`, REPEAT STRIP_TAC THEN REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC (MESON[REAL_ARITH `(&0 <= --u <=> ~(u > &0)) /\ (&0 <= u <=> ~(u < &0))`] `(?j k:A. j IN s /\ u j < &0 /\ k IN s /\ u k > &0) \/ (!i. i IN s ==> &0 <= u i) \/ (!i. i IN s ==> &0 <= --(u i))`) THEN ASM_REWRITE_TAC[] THEN DISJ1_TAC THENL [ALL_TAC; ONCE_REWRITE_TAC[REAL_ARITH `x = &0 <=> --x = &0`]] THEN MATCH_MP_TAC SUM_POS_EQ_0 THEN ASM_REWRITE_TAC[SUM_NEG; REAL_NEG_0]);; let SUM_DELETE = prove (`!f s a. FINITE s /\ a IN s ==> sum (s DELETE a) f = sum s f - f(a)`, SIMP_TAC[REAL_ARITH `y = z - x <=> x + y = z:real`; sum; ITERATE_DELETE; MONOIDAL_REAL_ADD]);; let SUM_DELETE_CASES = prove (`!f s a. FINITE s ==> sum (s DELETE a) f = if a IN s then sum s f - f(a) else sum s f`, REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[SET_RULE `~(a IN s) ==> (s DELETE a = s)`; SUM_DELETE]);; let SUM_SING = prove (`!f x. sum {x} f = f(x)`, SIMP_TAC[SUM_CLAUSES; FINITE_RULES; NOT_IN_EMPTY; REAL_ADD_RID]);; let SUM_DELTA = prove (`!s a. sum s (\x. if x = a:A then b else &0) = if a IN s then b else &0`, REWRITE_TAC[sum; GSYM NEUTRAL_REAL_ADD] THEN SIMP_TAC[ITERATE_DELTA; MONOIDAL_REAL_ADD]);; let SUM_SWAP = prove (`!f:A->B->real s t. FINITE(s) /\ FINITE(t) ==> (sum s (\i. sum t (f i)) = sum t (\j. sum s (\i. f i j)))`, GEN_TAC THEN REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[SUM_CLAUSES; SUM_0; SUM_ADD; ETA_AX]);; let SUM_IMAGE = prove (`!f g s. (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)) ==> (sum (IMAGE f s) g = sum s (g o f))`, REWRITE_TAC[sum; GSYM NEUTRAL_REAL_ADD] THEN MATCH_MP_TAC ITERATE_IMAGE THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_SUPERSET = prove (`!f:A->real u v. u SUBSET v /\ (!x. x IN v /\ ~(x IN u) ==> (f(x) = &0)) ==> (sum v f = sum u f)`, SIMP_TAC[sum; GSYM NEUTRAL_REAL_ADD; ITERATE_SUPERSET; MONOIDAL_REAL_ADD]);; let SUM_UNION_RZERO = prove (`!f:A->real u v. FINITE u /\ (!x. x IN v /\ ~(x IN u) ==> (f(x) = &0)) ==> (sum (u UNION v) f = sum u f)`, let lemma = prove(`u UNION v = u UNION (v DIFF u)`,SET_TAC[]) in REPEAT STRIP_TAC THEN ONCE_REWRITE_TAC[lemma] THEN MATCH_MP_TAC SUM_SUPERSET THEN ASM_MESON_TAC[IN_UNION; IN_DIFF; SUBSET]);; let SUM_UNION_LZERO = prove (`!f:A->real u v. FINITE v /\ (!x. x IN u /\ ~(x IN v) ==> (f(x) = &0)) ==> (sum (u UNION v) f = sum v f)`, MESON_TAC[SUM_UNION_RZERO; UNION_COMM]);; let SUM_RESTRICT = prove (`!f s. FINITE s ==> (sum s (\x. if x IN s then f(x) else &0) = sum s f)`, REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ THEN ASM_SIMP_TAC[]);; let SUM_BOUND = prove (`!s f b. FINITE s /\ (!x:A. x IN s ==> f(x) <= b) ==> sum s f <= &(CARD s) * b`, SIMP_TAC[GSYM SUM_CONST; SUM_LE]);; let SUM_BOUND_GEN = prove (`!s t b. FINITE s /\ ~(s = {}) /\ (!x:A. x IN s ==> f(x) <= b / &(CARD s)) ==> sum s f <= b`, MESON_TAC[SUM_BOUND; REAL_DIV_LMUL; REAL_OF_NUM_EQ; HAS_SIZE_0; HAS_SIZE]);; let SUM_ABS_BOUND = prove (`!s f b. FINITE s /\ (!x:A. x IN s ==> abs(f(x)) <= b) ==> abs(sum s f) <= &(CARD s) * b`, REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `sum s (\x:A. abs(f x))` THEN ASM_SIMP_TAC[SUM_BOUND; SUM_ABS]);; let SUM_BOUND_LT = prove (`!s f b. FINITE s /\ (!x:A. x IN s ==> f x <= b) /\ (?x. x IN s /\ f x < b) ==> sum s f < &(CARD s) * b`, REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `sum s (\x:A. b)` THEN CONJ_TAC THENL [MATCH_MP_TAC SUM_LT THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]; ASM_SIMP_TAC[SUM_CONST; REAL_LE_REFL]]);; let SUM_BOUND_LT_ALL = prove (`!s f b. FINITE s /\ ~(s = {}) /\ (!x. x IN s ==> f(x) < b) ==> sum s f < &(CARD s) * b`, MESON_TAC[MEMBER_NOT_EMPTY; REAL_LT_IMP_LE; SUM_BOUND_LT]);; let SUM_BOUND_LT_GEN = prove (`!s t b. FINITE s /\ ~(s = {}) /\ (!x:A. x IN s ==> f(x) < b / &(CARD s)) ==> sum s f < b`, MESON_TAC[SUM_BOUND_LT_ALL; REAL_DIV_LMUL; REAL_OF_NUM_EQ; HAS_SIZE_0; HAS_SIZE]);; let SUM_UNION_EQ = prove (`!s t u. FINITE u /\ (s INTER t = {}) /\ (s UNION t = u) ==> (sum s f + sum t f = sum u f)`, MESON_TAC[SUM_UNION; DISJOINT; FINITE_SUBSET; SUBSET_UNION]);; let SUM_EQ_SUPERSET = prove (`!f s t:A->bool. FINITE t /\ t SUBSET s /\ (!x. x IN t ==> (f x = g x)) /\ (!x. x IN s /\ ~(x IN t) ==> (f(x) = &0)) ==> (sum s f = sum t g)`, MESON_TAC[SUM_SUPERSET; SUM_EQ]);; let SUM_RESTRICT_SET = prove (`!s f r. FINITE s ==> (sum {x:A | x IN s /\ P x} f = sum s (\x. if P x then f(x) else &0))`, REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_EQ_SUPERSET THEN ASM_SIMP_TAC[FINITE_RESTRICT] THEN ASM_SIMP_TAC[SUBSET; IN_ELIM_THM] THEN MESON_TAC[]);; let SUM_SUM_RESTRICT = prove (`!R f s t. FINITE s /\ FINITE t ==> (sum s (\x. sum {y | y IN t /\ R x y} (\y. f x y)) = sum t (\y. sum {x | x IN s /\ R x y} (\x. f x y)))`, REPEAT GEN_TAC THEN SIMP_TAC[SUM_RESTRICT_SET] THEN DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP SUM_SWAP th]));; let CARD_EQ_SUM = prove (`!s. FINITE s ==> (&(CARD s) = sum s (\x. &1))`, SIMP_TAC[SUM_CONST; REAL_MUL_RID]);; let SUM_MULTICOUNT_GEN = prove (`!R:A->B->bool s t k. FINITE s /\ FINITE t /\ (!j. j IN t ==> (CARD {i | i IN s /\ R i j} = k(j))) ==> (sum s (\i. &(CARD {j | j IN t /\ R i j})) = sum t (\i. &(k i)))`, REPEAT GEN_TAC THEN REWRITE_TAC[CONJ_ASSOC] THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `sum s (\i:A. sum {j:B | j IN t /\ R i j} (\j. &1))` THEN CONJ_TAC THENL [MATCH_MP_TAC SUM_EQ THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN ASM_SIMP_TAC[CARD_EQ_SUM; FINITE_RESTRICT]; FIRST_ASSUM(fun th -> ONCE_REWRITE_TAC[MATCH_MP SUM_SUM_RESTRICT th]) THEN MATCH_MP_TAC SUM_EQ THEN ASM_SIMP_TAC[SUM_CONST; FINITE_RESTRICT] THEN REWRITE_TAC[REAL_MUL_RID]]);; let SUM_MULTICOUNT = prove (`!R:A->B->bool s t k. FINITE s /\ FINITE t /\ (!j. j IN t ==> (CARD {i | i IN s /\ R i j} = k)) ==> (sum s (\i. &(CARD {j | j IN t /\ R i j})) = &(k * CARD t))`, REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `sum t (\i:B. &k)` THEN CONJ_TAC THENL [MATCH_MP_TAC SUM_MULTICOUNT_GEN THEN ASM_REWRITE_TAC[]; ASM_SIMP_TAC[SUM_CONST; REAL_OF_NUM_MUL] THEN REWRITE_TAC[MULT_AC]]);; let SUM_IMAGE_GEN = prove (`!f:A->B g s. FINITE s ==> (sum s g = sum (IMAGE f s) (\y. sum {x | x IN s /\ (f(x) = y)} g))`, REPEAT STRIP_TAC THEN MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC `sum s (\x:A. sum {y:B | y IN IMAGE f s /\ (f x = y)} (\y. g x))` THEN CONJ_TAC THENL [MATCH_MP_TAC SUM_EQ THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:A` THEN DISCH_TAC THEN SUBGOAL_THEN `{y | y IN IMAGE (f:A->B) s /\ (f x = y)} = {(f x)}` (fun th -> REWRITE_TAC[th; SUM_SING; o_THM]) THEN REWRITE_TAC[EXTENSION; IN_ELIM_THM; IN_SING; IN_IMAGE] THEN ASM_MESON_TAC[]; GEN_REWRITE_TAC (funpow 2 RAND_CONV o ABS_CONV o RAND_CONV) [GSYM ETA_AX] THEN ASM_SIMP_TAC[SUM_SUM_RESTRICT; FINITE_IMAGE]]);; let SUM_GROUP = prove (`!f:A->B g s t. FINITE s /\ IMAGE f s SUBSET t ==> sum t (\y. sum {x | x IN s /\ f(x) = y} g) = sum s g`, REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`f:A->B`; `g:A->real`; `s:A->bool`] SUM_IMAGE_GEN) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC SUM_SUPERSET THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ_0 THEN ASM SET_TAC[]);; let REAL_OF_NUM_SUM = prove (`!f s. FINITE s ==> (&(nsum s f) = sum s (\x. &(f x)))`, GEN_TAC THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[SUM_CLAUSES; NSUM_CLAUSES; GSYM REAL_OF_NUM_ADD]);; let SUM_SUBSET = prove (`!u v f. FINITE u /\ FINITE v /\ (!x. x IN (u DIFF v) ==> f(x) <= &0) /\ (!x:A. x IN (v DIFF u) ==> &0 <= f(x)) ==> sum u f <= sum v f`, REPEAT STRIP_TAC THEN MP_TAC(ISPECL [`f:A->real`; `u INTER v :A->bool`] SUM_UNION) THEN DISCH_THEN(fun th -> MP_TAC(SPEC `v DIFF u :A->bool` th) THEN MP_TAC(SPEC `u DIFF v :A->bool` th)) THEN REWRITE_TAC[SET_RULE `(u INTER v) UNION (u DIFF v) = u`; SET_RULE `(u INTER v) UNION (v DIFF u) = v`] THEN ASM_SIMP_TAC[FINITE_DIFF; FINITE_INTER] THEN REPEAT(ANTS_TAC THENL [SET_TAC[]; DISCH_THEN SUBST1_TAC]) THEN MATCH_MP_TAC(REAL_ARITH `&0 <= --x /\ &0 <= y ==> a + x <= a + y`) THEN ASM_SIMP_TAC[GSYM SUM_NEG; FINITE_DIFF] THEN CONJ_TAC THEN MATCH_MP_TAC SUM_POS_LE THEN ASM_SIMP_TAC[FINITE_DIFF; REAL_LE_RNEG; REAL_ADD_LID]);; let SUM_SUBSET_SIMPLE = prove (`!u v f. FINITE v /\ u SUBSET v /\ (!x:A. x IN (v DIFF u) ==> &0 <= f(x)) ==> sum u f <= sum v f`, REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_SUBSET THEN ASM_MESON_TAC[IN_DIFF; SUBSET; FINITE_SUBSET]);; let SUM_IMAGE_NONZERO = prove (`!d:B->real i:A->B s. FINITE s /\ (!x y. x IN s /\ y IN s /\ ~(x = y) /\ i x = i y ==> d(i x) = &0) ==> sum (IMAGE i s) d = sum s (d o i)`, REWRITE_TAC[GSYM NEUTRAL_REAL_ADD; sum] THEN MATCH_MP_TAC ITERATE_IMAGE_NONZERO THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_BIJECTION = prove (`!f p s:A->bool. (!x. x IN s ==> p(x) IN s) /\ (!y. y IN s ==> ?!x. x IN s /\ p(x) = y) ==> sum s f = sum s (f o p)`, REWRITE_TAC[sum] THEN MATCH_MP_TAC ITERATE_BIJECTION THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_SUM_PRODUCT = prove (`!s:A->bool t:A->B->bool x. FINITE s /\ (!i. i IN s ==> FINITE(t i)) ==> sum s (\i. sum (t i) (x i)) = sum {i,j | i IN s /\ j IN t i} (\(i,j). x i j)`, REWRITE_TAC[sum] THEN MATCH_MP_TAC ITERATE_ITERATE_PRODUCT THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_EQ_GENERAL = prove (`!s:A->bool t:B->bool f g h. (!y. y IN t ==> ?!x. x IN s /\ h(x) = y) /\ (!x. x IN s ==> h(x) IN t /\ g(h x) = f x) ==> sum s f = sum t g`, REWRITE_TAC[sum] THEN MATCH_MP_TAC ITERATE_EQ_GENERAL THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_EQ_GENERAL_INVERSES = prove (`!s:A->bool t:B->bool f g h k. (!y. y IN t ==> k(y) IN s /\ h(k y) = y) /\ (!x. x IN s ==> h(x) IN t /\ k(h x) = x /\ g(h x) = f x) ==> sum s f = sum t g`, REWRITE_TAC[sum] THEN MATCH_MP_TAC ITERATE_EQ_GENERAL_INVERSES THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_INJECTION = prove (`!f p s. FINITE s /\ (!x. x IN s ==> p x IN s) /\ (!x y. x IN s /\ y IN s /\ p x = p y ==> x = y) ==> sum s (f o p) = sum s f`, REWRITE_TAC[sum] THEN MATCH_MP_TAC ITERATE_INJECTION THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_UNION_NONZERO = prove (`!f s t. FINITE s /\ FINITE t /\ (!x. x IN s INTER t ==> f(x) = &0) ==> sum (s UNION t) f = sum s f + sum t f`, REWRITE_TAC[sum; GSYM NEUTRAL_REAL_ADD] THEN MATCH_MP_TAC ITERATE_UNION_NONZERO THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_UNIONS_NONZERO = prove (`!f s. FINITE s /\ (!t:A->bool. t IN s ==> FINITE t) /\ (!t1 t2 x. t1 IN s /\ t2 IN s /\ ~(t1 = t2) /\ x IN t1 /\ x IN t2 ==> f x = &0) ==> sum (UNIONS s) f = sum s (\t. sum t f)`, GEN_TAC THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN REWRITE_TAC[UNIONS_0; UNIONS_INSERT; SUM_CLAUSES; IN_INSERT] THEN MAP_EVERY X_GEN_TAC [`t:A->bool`; `s:(A->bool)->bool`] THEN DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ONCE_REWRITE_TAC[IMP_CONJ] THEN ASM_SIMP_TAC[SUM_CLAUSES] THEN ANTS_TAC THENL [ASM_MESON_TAC[]; DISCH_THEN(SUBST_ALL_TAC o SYM)] THEN STRIP_TAC THEN MATCH_MP_TAC SUM_UNION_NONZERO THEN ASM_SIMP_TAC[FINITE_UNIONS; IN_INTER; IN_UNIONS] THEN ASM_MESON_TAC[]);; let SUM_CASES = prove (`!s P f g. FINITE s ==> sum s (\x:A. if P x then f x else g x) = sum {x | x IN s /\ P x} f + sum {x | x IN s /\ ~P x} g`, REWRITE_TAC[sum; GSYM NEUTRAL_REAL_ADD] THEN MATCH_MP_TAC ITERATE_CASES THEN REWRITE_TAC[MONOIDAL_REAL_ADD]);; let SUM_LE_INCLUDED = prove (`!f:A->real g:B->real s t i. FINITE s /\ FINITE t /\ (!y. y IN t ==> &0 <= g y) /\ (!x. x IN s ==> ?y. y IN t /\ i y = x /\ f(x) <= g(y)) ==> sum s f <= sum t g`, REPEAT STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `sum (IMAGE (i:B->A) t) (\y. sum {x | x IN t /\ i x = y} g)` THEN CONJ_TAC THENL [ALL_TAC; MATCH_MP_TAC REAL_EQ_IMP_LE THEN MATCH_MP_TAC(GSYM SUM_IMAGE_GEN) THEN ASM_REWRITE_TAC[]] THEN MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `sum s (\y. sum {x | x IN t /\ (i:B->A) x = y} g)` THEN CONJ_TAC THENL [MATCH_MP_TAC SUM_LE THEN ASM_REWRITE_TAC[] THEN X_GEN_TAC `x:A` THEN DISCH_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `x:A`) THEN ASM_REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN X_GEN_TAC `y:B` THEN STRIP_TAC THEN MATCH_MP_TAC REAL_LE_TRANS THEN EXISTS_TAC `sum {y:B} g` THEN CONJ_TAC THENL [ASM_REWRITE_TAC[SUM_SING]; ALL_TAC]; ALL_TAC] THEN MATCH_MP_TAC SUM_SUBSET_SIMPLE THEN ASM_SIMP_TAC[FINITE_IMAGE] THEN ASM_SIMP_TAC[SUM_POS_LE; FINITE_RESTRICT; IN_ELIM_THM] THEN ASM SET_TAC[]);; let SUM_IMAGE_LE = prove (`!f:A->B g s. FINITE s /\ (!x. x IN s ==> &0 <= g(f x)) ==> sum (IMAGE f s) g <= sum s (g o f)`, REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_LE_INCLUDED THEN ASM_SIMP_TAC[FINITE_IMAGE; FORALL_IN_IMAGE] THEN ASM_REWRITE_TAC[o_THM] THEN EXISTS_TAC `f:A->B` THEN MESON_TAC[REAL_LE_REFL]);; (* ------------------------------------------------------------------------- *) (* Specialize them to sums over intervals of numbers. *) (* ------------------------------------------------------------------------- *) let SUM_ADD_NUMSEG = prove (`!f g m n. sum(m..n) (\i. f(i) + g(i)) = sum(m..n) f + sum(m..n) g`, SIMP_TAC[SUM_ADD; FINITE_NUMSEG]);; let SUM_SUB_NUMSEG = prove (`!f g m n. sum(m..n) (\i. f(i) - g(i)) = sum(m..n) f - sum(m..n) g`, SIMP_TAC[SUM_SUB; FINITE_NUMSEG]);; let SUM_LE_NUMSEG = prove (`!f g m n. (!i. m <= i /\ i <= n ==> f(i) <= g(i)) ==> sum(m..n) f <= sum(m..n) g`, SIMP_TAC[SUM_LE; FINITE_NUMSEG; IN_NUMSEG]);; let SUM_EQ_NUMSEG = prove (`!f g m n. (!i. m <= i /\ i <= n ==> (f(i) = g(i))) ==> (sum(m..n) f = sum(m..n) g)`, MESON_TAC[SUM_EQ; FINITE_NUMSEG; IN_NUMSEG]);; let SUM_ABS_NUMSEG = prove (`!f m n. abs(sum(m..n) f) <= sum(m..n) (\i. abs(f i))`, SIMP_TAC[SUM_ABS; FINITE_NUMSEG]);; let SUM_CONST_NUMSEG = prove (`!c m n. sum(m..n) (\n. c) = &((n + 1) - m) * c`, SIMP_TAC[SUM_CONST; FINITE_NUMSEG; CARD_NUMSEG]);; let SUM_EQ_0_NUMSEG = prove (`!f s. (!i. m <= i /\ i <= n ==> (f(i) = &0)) ==> (sum(m..n) f = &0)`, SIMP_TAC[SUM_EQ_0; IN_NUMSEG]);; let SUM_TRIV_NUMSEG = prove (`!f m n. n < m ==> (sum(m..n) f = &0)`, MESON_TAC[SUM_EQ_0_NUMSEG; LE_TRANS; NOT_LT]);; let SUM_POS_LE_NUMSEG = prove (`!m n f. (!p. m <= p /\ p <= n ==> &0 <= f(p)) ==> &0 <= sum(m..n) f`, SIMP_TAC[SUM_POS_LE; FINITE_NUMSEG; IN_NUMSEG]);; let SUM_POS_EQ_0_NUMSEG = prove (`!f m n. (!p. m <= p /\ p <= n ==> &0 <= f(p)) /\ (sum(m..n) f = &0) ==> !p. m <= p /\ p <= n ==> (f(p) = &0)`, MESON_TAC[SUM_POS_EQ_0; FINITE_NUMSEG; IN_NUMSEG]);; let SUM_SING_NUMSEG = prove (`!f n. sum(n..n) f = f(n)`, SIMP_TAC[SUM_SING; NUMSEG_SING]);; let SUM_CLAUSES_NUMSEG = prove (`(!m. sum(m..0) f = if m = 0 then f(0) else &0) /\ (!m n. sum(m..SUC n) f = if m <= SUC n then sum(m..n) f + f(SUC n) else sum(m..n) f)`, REWRITE_TAC[NUMSEG_CLAUSES] THEN REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[SUM_SING; SUM_CLAUSES; FINITE_NUMSEG; IN_NUMSEG] THEN REWRITE_TAC[ARITH_RULE `~(SUC n <= n)`; REAL_ADD_AC]);; let SUM_SWAP_NUMSEG = prove (`!a b c d f. sum(a..b) (\i. sum(c..d) (f i)) = sum(c..d) (\j. sum(a..b) (\i. f i j))`, REPEAT GEN_TAC THEN MATCH_MP_TAC SUM_SWAP THEN REWRITE_TAC[FINITE_NUMSEG]);; let SUM_ADD_SPLIT = prove (`!f m n p. m <= n + 1 ==> (sum (m..(n+p)) f = sum(m..n) f + sum(n+1..n+p) f)`, SIMP_TAC[NUMSEG_ADD_SPLIT; SUM_UNION; DISJOINT_NUMSEG; FINITE_NUMSEG; ARITH_RULE `x < x + 1`]);; let SUM_OFFSET = prove (`!p f m n. sum(m+p..n+p) f = sum(m..n) (\i. f(i + p))`, SIMP_TAC[NUMSEG_OFFSET_IMAGE; SUM_IMAGE; EQ_ADD_RCANCEL; FINITE_NUMSEG] THEN REWRITE_TAC[o_DEF]);; let SUM_OFFSET_0 = prove (`!f m n. m <= n ==> (sum(m..n) f = sum(0..n-m) (\i. f(i + m)))`, SIMP_TAC[GSYM SUM_OFFSET; ADD_CLAUSES; SUB_ADD]);; let SUM_CLAUSES_LEFT = prove (`!f m n. m <= n ==> sum(m..n) f = f(m) + sum(m+1..n) f`, SIMP_TAC[GSYM NUMSEG_LREC; SUM_CLAUSES; FINITE_NUMSEG; IN_NUMSEG] THEN ARITH_TAC);; let SUM_CLAUSES_RIGHT = prove (`!f m n. 0 < n /\ m <= n ==> sum(m..n) f = sum(m..n-1) f + f(n)`, GEN_TAC THEN GEN_TAC THEN INDUCT_TAC THEN SIMP_TAC[LT_REFL; SUM_CLAUSES_NUMSEG; SUC_SUB1]);; let REAL_OF_NUM_SUM_NUMSEG = prove (`!f m n. (&(nsum(m..n) f) = sum (m..n) (\i. &(f i)))`, SIMP_TAC[REAL_OF_NUM_SUM; FINITE_NUMSEG]);; (* ------------------------------------------------------------------------- *) (* Partial summation and other theorems specific to number segments. *) (* ------------------------------------------------------------------------- *) let SUM_PARTIAL_SUC = prove (`!f g m n. sum (m..n) (\k. f(k) * (g(k + 1) - g(k))) = if m <= n then f(n + 1) * g(n + 1) - f(m) * g(m) - sum (m..n) (\k. g(k + 1) * (f(k + 1) - f(k))) else &0`, GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN INDUCT_TAC THEN COND_CASES_TAC THEN ASM_SIMP_TAC[SUM_TRIV_NUMSEG; GSYM NOT_LE] THEN ASM_REWRITE_TAC[SUM_CLAUSES_NUMSEG] THENL [COND_CASES_TAC THEN ASM_SIMP_TAC[] THENL [REAL_ARITH_TAC; ASM_ARITH_TAC]; ALL_TAC] THEN FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [LE]) THEN DISCH_THEN(DISJ_CASES_THEN2 SUBST_ALL_TAC ASSUME_TAC) THEN ASM_SIMP_TAC[GSYM NOT_LT; SUM_TRIV_NUMSEG; ARITH_RULE `n < SUC n`] THEN ASM_SIMP_TAC[GSYM ADD1; ADD_CLAUSES] THEN REAL_ARITH_TAC);; let SUM_PARTIAL_PRE = prove (`!f g m n. sum (m..n) (\k. f(k) * (g(k) - g(k - 1))) = if m <= n then f(n + 1) * g(n) - f(m) * g(m - 1) - sum (m..n) (\k. g k * (f(k + 1) - f(k))) else &0`, REPEAT GEN_TAC THEN MP_TAC(ISPECL [`f:num->real`; `\k. (g:num->real)(k - 1)`; `m:num`; `n:num`] SUM_PARTIAL_SUC) THEN REWRITE_TAC[ADD_SUB] THEN DISCH_THEN SUBST1_TAC THEN COND_CASES_TAC THEN REWRITE_TAC[]);; let SUM_DIFFS = prove (`!m n. sum(m..n) (\k. f(k) - f(k + 1)) = if m <= n then f(m) - f(n + 1) else &0`, ONCE_REWRITE_TAC[REAL_ARITH `a - b = -- &1 * (b - a)`] THEN ONCE_REWRITE_TAC[SUM_PARTIAL_SUC] THEN REWRITE_TAC[REAL_SUB_REFL; REAL_MUL_RZERO; SUM_0] THEN REAL_ARITH_TAC);; let SUM_DIFFS_ALT = prove (`!m n. sum(m..n) (\k. f(k + 1) - f(k)) = if m <= n then f(n + 1) - f(m) else &0`, REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_NEG_SUB] THEN SIMP_TAC[SUM_NEG; SUM_DIFFS] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[REAL_NEG_SUB; REAL_NEG_0]);; let SUM_COMBINE_R = prove (`!f m n p. m <= n + 1 /\ n <= p ==> sum(m..n) f + sum(n+1..p) f = sum(m..p) f`, REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_UNION_EQ THEN REWRITE_TAC[FINITE_NUMSEG; EXTENSION; IN_INTER; IN_UNION; NOT_IN_EMPTY; IN_NUMSEG] THEN ASM_ARITH_TAC);; let SUM_COMBINE_L = prove (`!f m n p. 0 < n /\ m <= n /\ n <= p + 1 ==> sum(m..n-1) f + sum(n..p) f = sum(m..p) f`, REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_UNION_EQ THEN REWRITE_TAC[FINITE_NUMSEG; EXTENSION; IN_INTER; IN_UNION; NOT_IN_EMPTY; IN_NUMSEG] THEN ASM_ARITH_TAC);; (* ------------------------------------------------------------------------- *) (* Extend congruences to deal with sum. Note that we must have the eta *) (* redex or we'll get a loop since f(x) will lambda-reduce recursively. *) (* ------------------------------------------------------------------------- *) let th = prove (`(!f g s. (!x. x IN s ==> f(x) = g(x)) ==> sum s (\i. f(i)) = sum s g) /\ (!f g a b. (!i. a <= i /\ i <= b ==> f(i) = g(i)) ==> sum(a..b) (\i. f(i)) = sum(a..b) g) /\ (!f g p. (!x. p x ==> f x = g x) ==> sum {y | p y} (\i. f(i)) = sum {y | p y} g)`, REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ THEN ASM_SIMP_TAC[IN_ELIM_THM; IN_NUMSEG]) in extend_basic_congs (map SPEC_ALL (CONJUNCTS th));; (* ------------------------------------------------------------------------- *) (* Some special algebraic rearrangements. *) (* ------------------------------------------------------------------------- *) let REAL_SUB_POW = prove (`!x y n. 1 <= n ==> x pow n - y pow n = (x - y) * sum(0..n-1) (\i. x pow i * y pow (n - 1 - i))`, REWRITE_TAC[GSYM SUM_LMUL] THEN REWRITE_TAC[REAL_ARITH `(x - y) * (a * b):real = (x * a) * b - a * (y * b)`] THEN SIMP_TAC[GSYM real_pow; ADD1; ARITH_RULE `1 <= n /\ x <= n - 1 ==> n - 1 - x = n - (x + 1) /\ SUC(n - 1 - x) = n - x`] THEN REWRITE_TAC[SUM_DIFFS_ALT; LE_0] THEN SIMP_TAC[SUB_0; SUB_ADD; SUB_REFL; real_pow; REAL_MUL_LID; REAL_MUL_RID]);; let REAL_SUB_POW_R1 = prove (`!x n. 1 <= n ==> x pow n - &1 = (x - &1) * sum(0..n-1) (\i. x pow i)`, REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o SPECL [`x:real`; `&1`] o MATCH_MP REAL_SUB_POW) THEN REWRITE_TAC[REAL_POW_ONE; REAL_MUL_RID]);; let REAL_SUB_POW_L1 = prove (`!x n. 1 <= n ==> &1 - x pow n = (&1 - x) * sum(0..n-1) (\i. x pow i)`, ONCE_REWRITE_TAC[GSYM REAL_NEG_SUB] THEN SIMP_TAC[REAL_SUB_POW_R1] THEN REWRITE_TAC[REAL_MUL_LNEG]);; (* ------------------------------------------------------------------------- *) (* Make natural numbers the default again. *) (* ------------------------------------------------------------------------- *) prioritize_num();; (* ========================================================================= *) (* Definition of finite Cartesian product types. *) (* *) (* (c) Copyright, John Harrison 1998-2007 *) (* ========================================================================= *) let dimindex = new_definition `dimindex(s:A->bool) = if FINITE(:A) then CARD(:A) else 1`;; let DIMINDEX_NONZERO = prove (`!s:A->bool. ~(dimindex(s) = 0)`, GEN_TAC THEN REWRITE_TAC[dimindex] THEN COND_CASES_TAC THEN ASM_SIMP_TAC[CARD_EQ_0; ARITH] THEN SET_TAC[]);; let DIMINDEX_GE_1 = prove (`!s:A->bool. 1 <= dimindex(s)`, REWRITE_TAC[ARITH_RULE `1 <= x <=> ~(x = 0)`; DIMINDEX_NONZERO]);; let DIMINDEX_UNIV = prove (`!s. dimindex(s:A->bool) = dimindex(:A)`, REWRITE_TAC[dimindex]);; let DIMINDEX_UNIQUE = prove (`(:A) HAS_SIZE n ==> dimindex(:A) = n`, MESON_TAC[dimindex; HAS_SIZE]);; (* ------------------------------------------------------------------------- *) (* An indexing type with that size, parametrized by base type. *) (* ------------------------------------------------------------------------- *) let finite_image_tybij = let th = prove (`?x. x IN 1..dimindex(:A)`, EXISTS_TAC `1` THEN REWRITE_TAC[IN_NUMSEG; LE_REFL; DIMINDEX_GE_1]) in new_type_definition "finite_image" ("finite_index","dest_finite_image") th;; let FINITE_IMAGE_IMAGE = prove (`UNIV:(A)finite_image->bool = IMAGE finite_index (1..dimindex(:A))`, REWRITE_TAC[EXTENSION; IN_UNIV; IN_IMAGE] THEN MESON_TAC[finite_image_tybij]);; (* ------------------------------------------------------------------------- *) (* Dimension of such a type, and indexing over it. *) (* ------------------------------------------------------------------------- *) let HAS_SIZE_FINITE_IMAGE = prove (`!s. (UNIV:(A)finite_image->bool) HAS_SIZE dimindex(s:A->bool)`, GEN_TAC THEN SIMP_TAC[FINITE_IMAGE_IMAGE] THEN MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN ONCE_REWRITE_TAC[DIMINDEX_UNIV] THEN REWRITE_TAC[HAS_SIZE_NUMSEG_1] THEN MESON_TAC[finite_image_tybij]);; let CARD_FINITE_IMAGE = prove (`!s. CARD(UNIV:(A)finite_image->bool) = dimindex(s:A->bool)`, MESON_TAC[HAS_SIZE_FINITE_IMAGE; HAS_SIZE]);; let FINITE_FINITE_IMAGE = prove (`FINITE(UNIV:(A)finite_image->bool)`, MESON_TAC[HAS_SIZE_FINITE_IMAGE; HAS_SIZE]);; let DIMINDEX_FINITE_IMAGE = prove (`!s t. dimindex(s:(A)finite_image->bool) = dimindex(t:A->bool)`, REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [dimindex] THEN MP_TAC(ISPEC `t:A->bool` HAS_SIZE_FINITE_IMAGE) THEN SIMP_TAC[FINITE_FINITE_IMAGE; HAS_SIZE]);; let FINITE_INDEX_WORKS = prove (`!i:(A)finite_image. ?!n. 1 <= n /\ n <= dimindex(:A) /\ (finite_index n = i)`, REWRITE_TAC[CONJ_ASSOC; GSYM IN_NUMSEG] THEN MESON_TAC[finite_image_tybij]);; let FINITE_INDEX_INJ = prove (`!i j. 1 <= i /\ i <= dimindex(:A) /\ 1 <= j /\ j <= dimindex(:A) ==> ((finite_index i :A finite_image = finite_index j) <=> (i = j))`, MESON_TAC[FINITE_INDEX_WORKS]);; let FORALL_FINITE_INDEX = prove (`(!k:(N)finite_image. P k) = (!i. 1 <= i /\ i <= dimindex(:N) ==> P(finite_index i))`, MESON_TAC[FINITE_INDEX_WORKS]);; (* ------------------------------------------------------------------------- *) (* Hence finite Cartesian products, with indexing and lambdas. *) (* ------------------------------------------------------------------------- *) let cart_tybij = new_type_definition "cart" ("mk_cart","dest_cart") (prove(`?f:(B)finite_image->A. T`,REWRITE_TAC[]));; parse_as_infix("$",(25,"left"));; let finite_index = new_definition `x$i = dest_cart x (finite_index i)`;; let CART_EQ = prove (`!x:A^B y. (x = y) <=> !i. 1 <= i /\ i <= dimindex(:B) ==> (x$i = y$i)`, REPEAT GEN_TAC THEN REWRITE_TAC[finite_index; GSYM FORALL_FINITE_INDEX] THEN REWRITE_TAC[GSYM FUN_EQ_THM; ETA_AX] THEN MESON_TAC[cart_tybij]);; parse_as_binder "lambda";; let lambda = new_definition `(lambda) g = @f:A^B. !i. 1 <= i /\ i <= dimindex(:B) ==> (f$i = g i)`;; let LAMBDA_BETA = prove (`!i. 1 <= i /\ i <= dimindex(:B) ==> (((lambda) g:A^B) $i = g i)`, REWRITE_TAC[lambda] THEN CONV_TAC SELECT_CONV THEN EXISTS_TAC `mk_cart(\k. g(@i. 1 <= i /\ i <= dimindex(:B) /\ (finite_index i = k))):A^B` THEN REWRITE_TAC[finite_index; REWRITE_RULE[] cart_tybij] THEN REPEAT STRIP_TAC THEN AP_TERM_TAC THEN MATCH_MP_TAC SELECT_UNIQUE THEN GEN_TAC THEN REWRITE_TAC[] THEN ASM_MESON_TAC[FINITE_INDEX_INJ; DIMINDEX_FINITE_IMAGE]);; let LAMBDA_UNIQUE = prove (`!f:A^B g. (!i. 1 <= i /\ i <= dimindex(:B) ==> (f$i = g i)) <=> ((lambda) g = f)`, SIMP_TAC[CART_EQ; LAMBDA_BETA] THEN MESON_TAC[]);; let LAMBDA_ETA = prove (`!g. (lambda i. g$i) = g`, REWRITE_TAC[CART_EQ; LAMBDA_BETA]);; (* ------------------------------------------------------------------------- *) (* For some purposes we can avoid side-conditions on the index. *) (* ------------------------------------------------------------------------- *) let FINITE_INDEX_INRANGE = prove (`!i. ?k. 1 <= k /\ k <= dimindex(:N) /\ !x:A^N. x$i = x$k`, REWRITE_TAC[finite_index] THEN MESON_TAC[FINITE_INDEX_WORKS]);; let CART_EQ_FULL = prove (`!x y:A^N. x = y <=> !i. x$i = y$i`, REPEAT GEN_TAC THEN EQ_TAC THEN SIMP_TAC[] THEN SIMP_TAC[CART_EQ]);; (* ------------------------------------------------------------------------- *) (* We need a non-standard sum to "paste" together Cartesian products. *) (* ------------------------------------------------------------------------- *) let finite_sum_tybij = let th = prove (`?x. x IN 1..(dimindex(:A) + dimindex(:B))`, EXISTS_TAC `1` THEN SIMP_TAC[IN_NUMSEG; LE_REFL; DIMINDEX_GE_1; ARITH_RULE `1 <= a ==> 1 <= a + b`]) in new_type_definition "finite_sum" ("mk_finite_sum","dest_finite_sum") th;; let pastecart = new_definition `(pastecart:A^M->A^N->A^(M,N)finite_sum) f g = lambda i. if i <= dimindex(:M) then f$i else g$(i - dimindex(:M))`;; let fstcart = new_definition `(fstcart:A^(M,N)finite_sum->A^M) f = lambda i. f$i`;; let sndcart = new_definition `(sndcart:A^(M,N)finite_sum->A^N) f = lambda i. f$(i + dimindex(:M))`;; let FINITE_SUM_IMAGE = prove (`UNIV:(A,B)finite_sum->bool = IMAGE mk_finite_sum (1..(dimindex(:A)+dimindex(:B)))`, REWRITE_TAC[EXTENSION; IN_UNIV; IN_IMAGE] THEN MESON_TAC[finite_sum_tybij]);; let DIMINDEX_HAS_SIZE_FINITE_SUM = prove (`(UNIV:(M,N)finite_sum->bool) HAS_SIZE (dimindex(:M) + dimindex(:N))`, SIMP_TAC[FINITE_SUM_IMAGE] THEN MATCH_MP_TAC HAS_SIZE_IMAGE_INJ THEN ONCE_REWRITE_TAC[DIMINDEX_UNIV] THEN REWRITE_TAC[HAS_SIZE_NUMSEG_1] THEN MESON_TAC[finite_sum_tybij]);; let DIMINDEX_FINITE_SUM = prove (`dimindex(:(M,N)finite_sum) = dimindex(:M) + dimindex(:N)`, GEN_REWRITE_TAC LAND_CONV [dimindex] THEN REWRITE_TAC[REWRITE_RULE[HAS_SIZE] DIMINDEX_HAS_SIZE_FINITE_SUM]);; let FSTCART_PASTECART = prove (`!x y. fstcart(pastecart (x:A^M) (y:A^N)) = x`, SIMP_TAC[pastecart; fstcart; CART_EQ; LAMBDA_BETA; DIMINDEX_FINITE_SUM; ARITH_RULE `a <= b ==> a <= b + c`]);; let SNDCART_PASTECART = prove (`!x y. sndcart(pastecart (x:A^M) (y:A^N)) = y`, SIMP_TAC[pastecart; sndcart; CART_EQ; LAMBDA_BETA] THEN REPEAT STRIP_TAC THEN W(fun (_,w) -> MP_TAC (PART_MATCH (lhs o rand) LAMBDA_BETA (lhand w))) THEN ANTS_TAC THENL [REWRITE_TAC[DIMINDEX_FINITE_SUM] THEN MATCH_MP_TAC (ARITH_RULE `1 <= i /\ i <= b ==> 1 <= i + a /\ i + a <= a + b`) THEN ASM_REWRITE_TAC[]; DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[] THEN ASM_SIMP_TAC[ADD_SUB; ARITH_RULE `1 <= i ==> ~(i + a <= a)`]]);; let PASTECART_FST_SND = prove (`!z. pastecart (fstcart z) (sndcart z) = z`, SIMP_TAC[pastecart; fstcart; sndcart; CART_EQ; LAMBDA_BETA] THEN REPEAT GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[DIMINDEX_FINITE_SUM; LAMBDA_BETA; ARITH_RULE `i <= a + b ==> i - a <= b`; ARITH_RULE `~(i <= a) ==> 1 <= i - a`; ARITH_RULE `~(i <= a) ==> ((i - a) + a = i)`]);; let PASTECART_EQ = prove (`!x y. (x = y) <=> (fstcart x = fstcart y) /\ (sndcart x = sndcart y)`, MESON_TAC[PASTECART_FST_SND]);; let FORALL_PASTECART = prove (`(!p. P p) <=> !x y. P (pastecart x y)`, MESON_TAC[PASTECART_FST_SND; FSTCART_PASTECART; SNDCART_PASTECART]);; let EXISTS_PASTECART = prove (`(?p. P p) <=> ?x y. P (pastecart x y)`, MESON_TAC[PASTECART_FST_SND; FSTCART_PASTECART; SNDCART_PASTECART]);; (* ------------------------------------------------------------------------- *) (* Automatically define a type of size n. *) (* ------------------------------------------------------------------------- *) let define_finite_type = let lemma_pre = prove (`~(n = 0) ==> ?x. x IN 1..n`, DISCH_TAC THEN EXISTS_TAC `1` THEN REWRITE_TAC[IN_NUMSEG] THEN POP_ASSUM MP_TAC THEN ARITH_TAC) and lemma_post = prove (`(!a:A. mk(dest a) = a) /\ (!r. r IN 1..n <=> dest(mk r) = r) ==> (:A) HAS_SIZE n`, REPEAT STRIP_TAC THEN SUBGOAL_THEN `(:A) = IMAGE mk (1..n)` SUBST1_TAC THENL [REWRITE_TAC[EXTENSION; IN_IMAGE; IN_UNIV]; MATCH_MP_TAC HAS_SIZE_IMAGE_INJ] THEN ASM_MESON_TAC[HAS_SIZE_NUMSEG_1]) in let POST_RULE = MATCH_MP lemma_post and n_tm = `n:num` in fun n -> let ns = string_of_int n in let ns' = "auto_define_finite_type_"^ns in let th0 = INST [mk_small_numeral n,n_tm] lemma_pre in let th1 = MP th0 (EQF_ELIM(NUM_EQ_CONV(rand(lhand(concl th0))))) in POST_RULE(new_type_definition ns ("mk_"^ns',"dest_"^ns') th1);; (* ------------------------------------------------------------------------- *) (* Predefine the cases 2 and 3, which are useful for real^2 and real^3. *) (* ------------------------------------------------------------------------- *) let HAS_SIZE_1 = prove (`(:1) HAS_SIZE 1`, SUBGOAL_THEN `(:1) = {one}` SUBST1_TAC THENL [REWRITE_TAC[EXTENSION; IN_UNIV; IN_SING] THEN MESON_TAC[one]; SIMP_TAC[NOT_IN_EMPTY; HAS_SIZE; FINITE_RULES; CARD_CLAUSES; ARITH]]);; let HAS_SIZE_2 = define_finite_type 2;; let HAS_SIZE_3 = define_finite_type 3;; let DIMINDEX_1 = MATCH_MP DIMINDEX_UNIQUE HAS_SIZE_1;; let DIMINDEX_2 = MATCH_MP DIMINDEX_UNIQUE HAS_SIZE_2;; let DIMINDEX_3 = MATCH_MP DIMINDEX_UNIQUE HAS_SIZE_3;; (* ------------------------------------------------------------------------- *) (* Finiteness lemma. *) (* ------------------------------------------------------------------------- *) let FINITE_CART = prove (`!P. (!i. 1 <= i /\ i <= dimindex(:N) ==> FINITE {x | P i x}) ==> FINITE {v:A^N | !i. 1 <= i /\ i <= dimindex(:N) ==> P i (v$i)}`, GEN_TAC THEN DISCH_TAC THEN SUBGOAL_THEN `!n. n <= dimindex(:N) ==> FINITE {v:A^N | (!i. 1 <= i /\ i <= dimindex(:N) /\ i <= n ==> P i (v$i)) /\ (!i. 1 <= i /\ i <= dimindex(:N) /\ n < i ==> v$i = @x. F)}` (MP_TAC o SPEC `dimindex(:N)`) THEN REWRITE_TAC[LE_REFL; LET_ANTISYM] THEN INDUCT_TAC THENL [REWRITE_TAC[ARITH_RULE `1 <= i /\ i <= n /\ i <= 0 <=> F`] THEN SIMP_TAC[ARITH_RULE `1 <= i /\ i <= n /\ 0 < i <=> 1 <= i /\ i <= n`] THEN SUBGOAL_THEN `{v | !i. 1 <= i /\ i <= dimindex (:N) ==> v$i = (@x. F)} = {(lambda i. @x. F):A^N}` (fun th -> SIMP_TAC[FINITE_RULES;th]) THEN SIMP_TAC[EXTENSION; IN_SING; IN_ELIM_THM; CART_EQ; LAMBDA_BETA]; ALL_TAC] THEN DISCH_TAC THEN MATCH_MP_TAC FINITE_SUBSET THEN EXISTS_TAC `IMAGE (\(x:A,v:A^N). (lambda i. if i = SUC n then x else v$i):A^N) {x,v | x IN {x:A | P (SUC n) x} /\ v IN {v:A^N | (!i. 1 <= i /\ i <= dimindex(:N) /\ i <= n ==> P i (v$i)) /\ (!i. 1 <= i /\ i <= dimindex (:N) /\ n < i ==> v$i = (@x. F))}}` THEN CONJ_TAC THENL [MATCH_MP_TAC FINITE_IMAGE THEN ASM_SIMP_TAC[FINITE_PRODUCT; ARITH_RULE `1 <= SUC n`; ARITH_RULE `SUC n <= m ==> n <= m`]; ALL_TAC] THEN REWRITE_TAC[SUBSET; IN_IMAGE; IN_ELIM_PAIR_THM; EXISTS_PAIR_THM] THEN X_GEN_TAC `v:A^N` THEN REWRITE_TAC[IN_ELIM_THM] THEN STRIP_TAC THEN EXISTS_TAC `(v:A^N)$(SUC n)` THEN EXISTS_TAC `(lambda i. if i = SUC n then @x. F else (v:A^N)$i):A^N` THEN SIMP_TAC[CART_EQ; LAMBDA_BETA; ARITH_RULE `i <= n ==> ~(i = SUC n)`] THEN ASM_MESON_TAC[LE; ARITH_RULE `1 <= SUC n`; ARITH_RULE `n < i /\ ~(i = SUC n) ==> SUC n < i`]);; (* ------------------------------------------------------------------------- *) (* Explicit construction of a vector from a list of components. *) (* ------------------------------------------------------------------------- *) let vector = new_definition `(vector l):A^N = lambda i. EL (i - 1) l`;; (* ========================================================================= *) (* Automated support for general recursive definitions. *) (* *) (* (c) Copyright, John Harrison 1998-2007 *) (* ========================================================================= *) let CASEWISE_DEF = new_recursive_definition list_RECURSION `(CASEWISE [] f x = @y. T) /\ (CASEWISE (CONS h t) f x = if ?y. FST h y = x then SND h f (@y. FST h y = x) else CASEWISE t f x)`;; let CASEWISE = prove (`(CASEWISE [] f x = @y. T) /\ (CASEWISE (CONS (s,t) clauses) f x = if ?y. s y = x then t f (@y. s y = x) else CASEWISE clauses f x)`, REWRITE_TAC[CASEWISE_DEF]);; (* ------------------------------------------------------------------------- *) (* Conditions for all the clauses in a casewise definition to hold. *) (* ------------------------------------------------------------------------- *) let CASEWISE_CASES = prove (`!clauses c x. (?s t a. MEM (s,t) clauses /\ (s a = x) /\ (CASEWISE clauses c x = t c a)) \/ ~(?s t a. MEM (s,t) clauses /\ (s a = x)) /\ (CASEWISE clauses c x = @y. T)`, MATCH_MP_TAC list_INDUCT THEN REWRITE_TAC[MEM; CASEWISE; FORALL_PAIR_THM; PAIR_EQ] THEN REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_MESON_TAC[]);; let CASEWISE_WORKS = prove (`!clauses c:C. (!s t s' t' x y. MEM (s,t) clauses /\ MEM (s',t') clauses /\ (s x = s' y) ==> (t c x = t' c y)) ==> ALL (\(s:P->A,t). !x. CASEWISE clauses c (s x) :B = t c x) clauses`, REWRITE_TAC[GSYM ALL_MEM; FORALL_PAIR_THM] THEN MESON_TAC[CASEWISE_CASES]);; (* ------------------------------------------------------------------------- *) (* Various notions of admissibility, with tail recursion and preconditions. *) (* ------------------------------------------------------------------------- *) let admissible = new_definition `admissible(<<) p s t <=> !f g a. p f a /\ p g a /\ (!z. z << s(a) ==> (f z = g z)) ==> (t f a = t g a)`;; let tailadmissible = new_definition `tailadmissible(<<) p s t <=> ?P G H. (!f a y. P f a /\ y << G f a ==> y << s a) /\ (!f g a. (!z. z << s(a) ==> (f z = g z)) ==> (P f a = P g a) /\ (G f a = G g a) /\ (H f a = H g a)) /\ (!f a:P. p f a ==> (t (f:A->B) a = if P f a then f(G f a) else H f a))`;; let superadmissible = new_definition `superadmissible(<<) p s t <=> admissible(<<) (\f a. T) s p ==> tailadmissible(<<) p s t`;; (* ------------------------------------------------------------------------- *) (* A lemma. *) (* ------------------------------------------------------------------------- *) let MATCH_SEQPATTERN = prove (`_MATCH x (_SEQPATTERN r s) = if ?y. r x y then _MATCH x r else _MATCH x s`, REWRITE_TAC[_MATCH; _SEQPATTERN] THEN MESON_TAC[]);; (* ------------------------------------------------------------------------- *) (* Admissibility combinators. *) (* ------------------------------------------------------------------------- *) let ADMISSIBLE_CONST = prove (`!p s c. admissible(<<) p s (\f. c)`, REWRITE_TAC[admissible]);; let ADMISSIBLE_BASE = prove (`!(<<) p s t. (!f a. p f a ==> t a << s a) ==> admissible((<<):A->A->bool) p s (\f:A->B x:P. f(t x))`, REWRITE_TAC[admissible] THEN MESON_TAC[]);; let ADMISSIBLE_COMB = prove (`!(<<) p s:P->A g:(A->B)->P->C->D y:(A->B)->P->C. admissible(<<) p s g /\ admissible(<<) p s y ==> admissible(<<) p s (\f x. (g f x) (y f x))`, SIMP_TAC[admissible] THEN MESON_TAC[]);; let ADMISSIBLE_RAND = prove (`!(<<) p s:P->A g:P->C->D y:(A->B)->P->C. admissible(<<) p s y ==> admissible(<<) p s (\f x. (g x) (y f x))`, SIMP_TAC[admissible] THEN MESON_TAC[]);; let ADMISSIBLE_LAMBDA = prove (`!(<<) p s:P->A t:(A->B)->C->P->bool. admissible(<<) (\f (u,x). p f x) (\(u,x). s x) (\f (u,x). t f u x) ==> admissible(<<) p s (\f x. \u. t f u x)`, REWRITE_TAC[admissible; FUN_EQ_THM; FORALL_PAIR_THM] THEN MESON_TAC[]);; let ADMISSIBLE_NEST = prove (`!(<<) p s t. admissible(<<) p s t /\ (!f a. p f a ==> t f a << s a) ==> admissible((<<):A->A->bool) p s (\f:A->B x:P. f(t f x))`, REWRITE_TAC[admissible] THEN MESON_TAC[]);; let ADMISSIBLE_COND = prove (`!(<<) p P s h k. admissible(<<) p s P /\ admissible(<<) (\f x. p f x /\ P f x) s h /\ admissible(<<) (\f x. p f x /\ ~P f x) s k ==> admissible(<<) p s (\f x:P. if P f x then h f x else k f x)`, REPEAT GEN_TAC THEN REWRITE_TAC[admissible; AND_FORALL_THM] THEN REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]);; let ADMISSIBLE_MATCH = prove (`!(<<) p s e f c. admissible(<<) p s e /\ admissible(<<) p s (\f x. c f x (e f x)) ==> admissible(<<) p s (\f x:P. _MATCH (e f x) (c f x))`, REWRITE_TAC[admissible; _MATCH] THEN REPEAT STRIP_TAC THEN REPEAT COND_CASES_TAC THEN ASM_MESON_TAC[]);; let ADMISSIBLE_SEQPATTERN = prove (`!(<<) p s c1 c2 e. admissible(<<) p s (\f x:P. ?y. c1 f x (e f x) y) /\ admissible(<<) (\f x. p f x /\ ?y. c1 f x (e f x) y) s (\f x. c1 f x (e f x)) /\ admissible(<<) (\f x. p f x /\ ~(?y. c1 f x (e f x) y)) s (\f x. c2 f x (e f x)) ==> admissible(<<) p s (\f x. _SEQPATTERN (c1 f x) (c2 f x) (e f x))`, REWRITE_TAC[_SEQPATTERN; admissible] THEN MESON_TAC[]);; let ADMISSIBLE_UNGUARDED_PATTERN = prove (`!(<<) p s pat e t y. admissible (<<) p s pat /\ admissible (<<) p s e /\ admissible (<<) (\f x. p f x /\ pat f x = e f x) s t /\ admissible (<<) (\f x. p f x /\ pat f x = e f x) s y ==> admissible(<<) p s (\f x:P. _UNGUARDED_PATTERN (GEQ (pat f x) (e f x)) (GEQ (t f x) (y f x)))`, REPEAT GEN_TAC THEN REWRITE_TAC[admissible; FORALL_PAIR_THM; _UNGUARDED_PATTERN] THEN REWRITE_TAC[GEQ_DEF] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC(TAUT `(a <=> a') /\ (a /\ a' ==> (b <=> b')) ==> (a /\ b <=> a' /\ b')`) THEN ASM_MESON_TAC[]);; let ADMISSIBLE_GUARDED_PATTERN = prove (`!(<<) p s pat q e t y. admissible (<<) p s pat /\ admissible (<<) p s e /\ admissible (<<) (\f x. p f x /\ pat f x = e f x /\ q f x) s t /\ admissible (<<) (\f x. p f x /\ pat f x = e f x) s q /\ admissible (<<) (\f x. p f x /\ pat f x = e f x /\ q f x) s y ==> admissible(<<) p s (\f x:P. _GUARDED_PATTERN (GEQ (pat f x) (e f x)) (q f x) (GEQ (t f x) (y f x)))`, REPEAT GEN_TAC THEN REWRITE_TAC[admissible; FORALL_PAIR_THM; _GUARDED_PATTERN] THEN REWRITE_TAC[GEQ_DEF] THEN REPEAT STRIP_TAC THEN REPEAT(MATCH_MP_TAC(TAUT `(a <=> a') /\ (a /\ a' ==> (b <=> b')) ==> (a /\ b <=> a' /\ b')`) THEN REPEAT STRIP_TAC) THEN TRY(MATCH_MP_TAC(MESON[] `x = x' /\ y = y' ==> (x = y <=> x' = y')`)) THEN ASM_MESON_TAC[]);; let ADMISSIBLE_NSUM = prove (`!(<<) p:(B->C)->P->bool s:P->A h a b. admissible(<<) (\f (k,x). a(x) <= k /\ k <= b(x) /\ p f x) (\(k,x). s x) (\f (k,x). h f x k) ==> admissible(<<) p s (\f x. nsum(a(x)..b(x)) (h f x))`, REWRITE_TAC[admissible; FORALL_PAIR_THM] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC NSUM_EQ_NUMSEG THEN ASM_MESON_TAC[]);; let ADMISSIBLE_SUM = prove (`!(<<) p:(B->C)->P->bool s:P->A h a b. admissible(<<) (\f (k,x). a(x) <= k /\ k <= b(x) /\ p f x) (\(k,x). s x) (\f (k,x). h f x k) ==> admissible(<<) p s (\f x. sum(a(x)..b(x)) (h f x))`, REWRITE_TAC[admissible; FORALL_PAIR_THM] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC SUM_EQ_NUMSEG THEN ASM_MESON_TAC[]);; let ADMISSIBLE_MAP = prove (`!(<<) p s h l. admissible(<<) p s l /\ admissible (<<) (\f (y,x). p f x /\ MEM y (l f x)) (\(y,x). s x) (\f (y,x). h f x y) ==> admissible (<<) p s (\f:A->B x:P. MAP (h f x) (l f x))`, REWRITE_TAC[admissible; FORALL_PAIR_THM] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC(MESON[] `x = y /\ MAP f x = MAP g x ==> MAP f x = MAP g y`) THEN CONJ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN MATCH_MP_TAC MAP_EQ THEN REWRITE_TAC[GSYM ALL_MEM] THEN REPEAT STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[FORALL_PAIR_THM] THEN ASM_MESON_TAC[]);; let ADMISSIBLE_MATCH_SEQPATTERN = prove (`!(<<) p s c1 c2 e. admissible(<<) p s (\f x. ?y. c1 f x (e f x) y) /\ admissible(<<) (\f x. p f x /\ ?y. c1 f x (e f x) y) s (\f x. _MATCH (e f x) (c1 f x)) /\ admissible(<<) (\f x. p f x /\ ~(?y. c1 f x (e f x) y)) s (\f x. _MATCH (e f x) (c2 f x)) ==> admissible(<<) p s (\f x:P. _MATCH (e f x) (_SEQPATTERN (c1 f x) (c2 f x)))`, REWRITE_TAC[MATCH_SEQPATTERN; ADMISSIBLE_COND]);; (* ------------------------------------------------------------------------- *) (* Superadmissible generalizations where applicable. *) (* *) (* Note that we can't take the "higher type" route in the simple theorem *) (* ADMISSIBLE_MATCH because that isn't a context where tail recursion makes *) (* sense. Instead, we use specific theorems for the two _MATCH instances. *) (* Note that also, because of some delicacy over assessing welldefinedness *) (* of patterns, a special well-formedness hypothesis crops up here. (We need *) (* to separate it from the function f or we lose the "tail" optimization.) *) (* ------------------------------------------------------------------------- *) let ADMISSIBLE_IMP_SUPERADMISSIBLE = prove (`!(<<) p s t:(A->B)->P->B. admissible(<<) p s t ==> superadmissible(<<) p s t`, REWRITE_TAC[admissible; superadmissible; tailadmissible] THEN REPEAT STRIP_TAC THEN MAP_EVERY EXISTS_TAC [`\f:A->B x:P. F`; `\f:A->B. (anything:P->A)`; `\f:A->B a:P. if p f a then t f a :B else fixed`] THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]);; let SUPERADMISSIBLE_CONST = prove (`!p s c. superadmissible(<<) p s (\f. c)`, REPEAT GEN_TAC THEN MATCH_MP_TAC ADMISSIBLE_IMP_SUPERADMISSIBLE THEN REWRITE_TAC[ADMISSIBLE_CONST]);; let SUPERADMISSIBLE_TAIL = prove (`!(<<) p s t:(A->B)->P->A. admissible(<<) p s t /\ (!f a. p f a ==> !y. y << t f a ==> y << s a) ==> superadmissible(<<) p s (\f x. f(t f x))`, REWRITE_TAC[admissible; superadmissible; tailadmissible] THEN REPEAT STRIP_TAC THEN MAP_EVERY EXISTS_TAC [`\f:A->B x:P. T`; `\f:A->B a:P. if p f a then t f a :A else s a`; `\f:A->B. anything:P->B`] THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]);; let SUPERADMISSIBLE_COND = prove (`!(<<) p P s h k:(A->B)->P->B. admissible(<<) p s P /\ superadmissible(<<) (\f x. p f x /\ P f x) s h /\ superadmissible(<<) (\f x. p f x /\ ~P f x) s k ==> superadmissible(<<) p s (\f x. if P f x then h f x else k f x)`, REWRITE_TAC[superadmissible; admissible] THEN REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN DISCH_THEN(fun th -> DISCH_TAC THEN CONJUNCTS_THEN MP_TAC th) THEN ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN DISCH_THEN(fun th -> ANTS_TAC THENL [ASM_MESON_TAC[]; MP_TAC th]) THEN REWRITE_TAC[tailadmissible] THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM; RIGHT_IMP_FORALL_THM] THEN MAP_EVERY X_GEN_TAC [`P1:(A->B)->P->bool`; `G1:(A->B)->P->A`; `H1:(A->B)->P->B`; `P2:(A->B)->P->bool`; `G2:(A->B)->P->A`; `H2:(A->B)->P->B`] THEN REWRITE_TAC[TAUT `(a1 /\ b1 /\ c1 ==> a2 /\ b2 /\ c2 ==> x) <=> (a1 /\ a2) /\ (b1 /\ b2) /\ (c1 /\ c2) ==> x`] THEN DISCH_THEN(fun th -> MAP_EVERY EXISTS_TAC [`\f:A->B a:P. if p f a then if P f a then P2 f a else P1 f a else F`; `\f:A->B a:P. if p f a then if P f a then G2 f a else G1 f a else z:A`; `\f:A->B a:P. if p f a then if P f a then H2 f a else H1 f a else w:B`] THEN MP_TAC th) THEN REWRITE_TAC[] THEN REPEAT(MATCH_MP_TAC MONO_AND THEN CONJ_TAC) THENL [ASM_MESON_TAC[]; POP_ASSUM_LIST(MP_TAC o end_itlist CONJ); ALL_TAC] THEN REWRITE_TAC[IMP_IMP; AND_FORALL_THM] THEN REPEAT(MATCH_MP_TAC MONO_FORALL THEN GEN_TAC) THEN DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[]);; let SUPERADMISSIBLE_MATCH_SEQPATTERN = prove (`!(<<) p s c1 c2 e. admissible(<<) p s (\f x. ?y. c1 f x (e f x) y) /\ superadmissible(<<) (\f x. p f x /\ ?y. c1 f x (e f x) y) s (\f x. _MATCH (e f x) (c1 f x)) /\ superadmissible(<<) (\f x. p f x /\ ~(?y. c1 f x (e f x) y)) s (\f x. _MATCH (e f x) (c2 f x)) ==> superadmissible(<<) p s (\f x:P. _MATCH (e f x) (_SEQPATTERN (c1 f x) (c2 f x)))`, REWRITE_TAC[MATCH_SEQPATTERN; SUPERADMISSIBLE_COND]);; let SUPERADMISSIBLE_MATCH_UNGUARDED_PATTERN = prove (`!(<<) p s e:P->D pat:Q->D arg. (!f a t u. p f a /\ pat t = e a /\ pat u = e a ==> arg a t = arg a u) /\ (!f a t. p f a /\ pat t = e a ==> !y. y << arg a t ==> y << s a) ==> superadmissible(<<) p s (\f:A->B x. _MATCH (e x) (\u v. ?t. _UNGUARDED_PATTERN (GEQ (pat t) u) (GEQ (f(arg x t)) v)))`, REPEAT GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC[superadmissible] THEN DISCH_TAC THEN REWRITE_TAC[_UNGUARDED_PATTERN; GEQ_DEF; _MATCH] THEN REWRITE_TAC[tailadmissible] THEN SUBGOAL_THEN `!f:A->B x:P. p f x ==> ((?!v. ?t:Q. pat t:D = e x /\ f(arg x t) = v) <=> ?t. pat t = e x)` (fun th -> SIMP_TAC[th]) THENL [ASM_MESON_TAC[]; ALL_TAC] THEN MAP_EVERY EXISTS_TAC [`\(f:A->B) x:P. p f x /\ ?t:Q. pat t:D = e x`; `\f:A->B x:P. arg x (@t. (pat:Q->D) t = e x):A`; `\(f:A->B) x:P. (@z:B. F)`] THEN RULE_ASSUM_TAC(REWRITE_RULE[admissible]) THEN SIMP_TAC[] THEN ASM_MESON_TAC[]);; let SUPERADMISSIBLE_MATCH_GUARDED_PATTERN = prove (`!(<<) p s e:P->D pat:Q->D q arg. (!f a t u. p f a /\ pat t = e a /\ q a t /\ pat u = e a /\ q a u ==> arg a t = arg a u) /\ (!f a t. p f a /\ q a t /\ pat t = e a ==> !y. y << arg a t ==> y << s a) ==> superadmissible(<<) p s (\f:A->B x. _MATCH (e x) (\u v. ?t. _GUARDED_PATTERN (GEQ (pat t) u) (q x t) (GEQ (f(arg x t)) v)))`, REPEAT GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC[superadmissible] THEN DISCH_TAC THEN REWRITE_TAC[_GUARDED_PATTERN; GEQ_DEF; _MATCH] THEN REWRITE_TAC[tailadmissible] THEN SUBGOAL_THEN `!f:A->B x:P. p f x ==> ((?!v. ?t:Q. pat t:D = e x /\ q x t /\ f(arg x t) = v) <=> ?t. pat t = e x /\ q x t)` (fun th -> SIMP_TAC[th]) THENL [ASM_MESON_TAC[]; ALL_TAC] THEN MAP_EVERY EXISTS_TAC [`\(f:A->B) x:P. p f x /\ ?t:Q. pat t:D = e x /\ q x t`; `\f:A->B x:P. arg x (@t. (pat:Q->D) t = e x /\ q x t):A`; `\(f:A->B) x:P. (@z:B. F)`] THEN RULE_ASSUM_TAC(REWRITE_RULE[admissible]) THEN SIMP_TAC[] THEN ASM_MESON_TAC[]);; (* ------------------------------------------------------------------------- *) (* Combine general WF/tail recursion theorem with casewise definitions. *) (* ------------------------------------------------------------------------- *) let WF_REC_TAIL_GENERAL' = prove (`!P G H H'. WF (<<) /\ (!f g x. (!z. z << x ==> (f z = g z)) ==> (P f x <=> P g x) /\ (G f x = G g x) /\ (H' f x = H' g x)) /\ (!f x y. P f x /\ y << G f x ==> y << x) /\ (!f x. H f x = if P f x then f(G f x) else H' f x) ==> ?f. !x. f x = H f x`, REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN MATCH_MP_TAC WF_REC_TAIL_GENERAL THEN ASM_MESON_TAC[]);; let WF_REC_CASES = prove (`!(<<) clauses. WF((<<):A->A->bool) /\ ALL (\(s,t). ?P G H. (!f a y. P f a /\ y << G f a ==> y << s a) /\ (!f g a. (!z. z << s(a) ==> (f z = g z)) ==> (P f a = P g a) /\ (G f a = G g a) /\ (H f a = H g a)) /\ (!f a:P. t f a = if P f a then f(G f a) else H f a)) clauses ==> ?f:A->B. !x. f x = CASEWISE clauses f x`, REPEAT STRIP_TAC THEN MATCH_MP_TAC WF_REC_TAIL_GENERAL' THEN FIRST_X_ASSUM(MP_TAC o check(is_binary "ALL" o concl)) THEN SPEC_TAC(`clauses:((P->A)#((A->B)->P->B))list`, `clauses:((P->A)#((A->B)->P->B))list`) THEN ASM_REWRITE_TAC[] THEN POP_ASSUM(K ALL_TAC) THEN MATCH_MP_TAC list_INDUCT THEN REWRITE_TAC[ALL; CASEWISE; FORALL_PAIR_THM] THEN CONJ_TAC THENL [MAP_EVERY EXISTS_TAC [`\f:A->B x:A. F`; `\f:A->B. anything:A->A`; `\f:A->B x:A. @y:B. T`] THEN REWRITE_TAC[]; ALL_TAC] THEN MAP_EVERY X_GEN_TAC [`s:P->A`; `t:(A->B)->P->B`; `clauses:((P->A)#((A->B)->P->B))list`] THEN DISCH_THEN(fun th -> DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN POP_ASSUM_LIST(K ALL_TAC) THEN REWRITE_TAC[LEFT_IMP_EXISTS_THM] THEN REWRITE_TAC[RIGHT_IMP_FORALL_THM] THEN MAP_EVERY X_GEN_TAC [`P1:(A->B)->A->bool`; `G1:(A->B)->A->A`; `H1:(A->B)->A->B`; `P2:(A->B)->P->bool`; `G2:(A->B)->P->A`; `H2:(A->B)->P->B`] THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN EXISTS_TAC `\f:A->B x:A. if ?y:P. s y = x then P2 f (@y. s y = x) else P1 f x:bool` THEN EXISTS_TAC `\f:A->B x:A. if ?y:P. s y = x then G2 f (@y. s y = x) else G1 f x:A` THEN EXISTS_TAC `\f:A->B x:A. if ?y:P. s y = x then H2 f (@y. s y = x) else H1 f x:B` THEN ASM_MESON_TAC[]);; let WF_REC_CASES' = prove (`!(<<) clauses. WF((<<):A->A->bool) /\ ALL (\(s,t). tailadmissible(<<) (\f a. T) s t) clauses ==> ?f:A->B. !x. f x = CASEWISE clauses f x`, REWRITE_TAC[WF_REC_CASES; tailadmissible]);; let RECURSION_CASEWISE = prove (`!clauses. (?(<<). WF(<<) /\ ALL (\(s:P->A,t). tailadmissible(<<) (\f a. T) s t) clauses) /\ (!s t s' t' f x y. MEM (s,t) clauses /\ MEM (s',t') clauses ==> (s x = s' y) ==> (t f x = t' f y)) ==> ?f:A->B. ALL (\(s,t). !x. f (s x) = t f x) clauses`, REPEAT GEN_TAC THEN REWRITE_TAC[IMP_IMP; CONJ_ASSOC] THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN DISCH_THEN(CHOOSE_THEN (MP_TAC o MATCH_MP WF_REC_CASES')) THEN MATCH_MP_TAC MONO_EXISTS THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[CASEWISE_WORKS]);; let RECURSION_CASEWISE_PAIRWISE = prove (`!clauses. (?(<<). WF (<<) /\ ALL (\(s,t). tailadmissible(<<) (\f a. T) s t) clauses) /\ ALL (\(s,t). !f x y. (s x = s y) ==> (t f x = t f y)) clauses /\ PAIRWISE (\(s,t) (s',t'). !f x y. (s x = s' y) ==> (t f x = t' f y)) clauses ==> (?f. ALL (\(s,t). !x. f (s x) = t f x) clauses)`, let lemma = prove (`!P. (!x y. P x y ==> P y x) ==> !l. (!x y. MEM x l /\ MEM y l ==> P x y) <=> ALL (\x. P x x) l /\ PAIRWISE P l`, REWRITE_TAC[IMP_CONJ; RIGHT_FORALL_IMP_THM; GSYM ALL_MEM] THEN REPEAT GEN_TAC THEN DISCH_TAC THEN LIST_INDUCT_TAC THEN REWRITE_TAC[PAIRWISE; MEM; GSYM ALL_MEM] THEN ASM_MESON_TAC[]) and paired_lambda = prove (`(\x. P x) = (\(a,b). P (a,b))`, REWRITE_TAC[FUN_EQ_THM; FORALL_PAIR_THM]) in let pth = REWRITE_RULE[FORALL_PAIR_THM; paired_lambda] (ISPEC `\(s,t) (s',t'). !c x:A y:A. (s x = s' y) ==> (t c x = t' c y)` lemma) in let cth = prove(lhand(concl pth),MESON_TAC[]) in REWRITE_TAC[GSYM(MATCH_MP pth cth); RIGHT_IMP_FORALL_THM] THEN REWRITE_TAC[RECURSION_CASEWISE]);; let SUPERADMISSIBLE_T = prove (`superadmissible(<<) (\f x. T) s t <=> tailadmissible(<<) (\f x. T) s t`, REWRITE_TAC[superadmissible; admissible]);; let RECURSION_SUPERADMISSIBLE = REWRITE_RULE[GSYM SUPERADMISSIBLE_T] RECURSION_CASEWISE_PAIRWISE;; (* ------------------------------------------------------------------------- *) (* The main suite of functions for justifying recursion. *) (* ------------------------------------------------------------------------- *) let instantiate_casewise_recursion, pure_prove_recursive_function_exists, prove_general_recursive_function_exists = (* ------------------------------------------------------------------------- *) (* Make some basic simplification of conjunction of welldefinedness clauses. *) (* ------------------------------------------------------------------------- *) let SIMPLIFY_WELLDEFINEDNESS_CONV = let LSYM = GEN_ALL o CONV_RULE(LAND_CONV(ONCE_DEPTH_CONV SYM_CONV)) o SPEC_ALL and evensimps = prove (`((2 * m + 2 = 2 * n + 1) <=> F) /\ ((2 * m + 1 = 2 * n + 2) <=> F) /\ ((2 * m = 2 * n + 1) <=> F) /\ ((2 * m + 1 = 2 * n) <=> F) /\ ((2 * m = SUC(2 * n)) <=> F) /\ ((SUC(2 * m) = 2 * n) <=> F)`, REWRITE_TAC[] THEN REPEAT CONJ_TAC THEN DISCH_THEN(MP_TAC o AP_TERM `EVEN`) THEN REWRITE_TAC[EVEN_MULT; EVEN_ADD; ARITH; EVEN]) in let allsimps = itlist (mk_rewrites false) [EQ_ADD_RCANCEL; EQ_ADD_LCANCEL; EQ_ADD_RCANCEL_0; EQ_ADD_LCANCEL_0; LSYM EQ_ADD_RCANCEL_0; LSYM EQ_ADD_LCANCEL_0; EQ_MULT_RCANCEL; EQ_MULT_LCANCEL; EQT_INTRO(SPEC_ALL EQ_REFL); ADD_EQ_0; LSYM ADD_EQ_0; MULT_EQ_0; LSYM MULT_EQ_0; MULT_EQ_1; LSYM MULT_EQ_1; ARITH_RULE `(m + n = 1) <=> (m = 1) /\ (n = 0) \/ (m = 0) /\ (n = 1)`; ARITH_RULE `(1 = m + n) <=> (m = 1) /\ (n = 0) \/ (m = 0) /\ (n = 1)`; evensimps; ARITH_EQ] [] and [simp1; simp2; simp3] = map MATCH_MP (CONJUNCTS (TAUT `((a <=> F) /\ (b <=> b) ==> ((a ==> b) <=> T)) /\ ((a <=> a') /\ (a' ==> (b <=> T)) ==> ((a ==> b) <=> T)) /\ ((a <=> a') /\ (a' ==> (b <=> b')) ==> ((a ==> b) <=> (a' ==> b')))`)) and false_tm = `F` and and_tm = `(/\)` and eq_refl = EQT_INTRO(SPEC_ALL EQ_REFL) in fun tm -> let net = itlist (net_of_thm false) allsimps (!basic_rectype_net) in let RECTYPE_ARITH_EQ_CONV = TOP_SWEEP_CONV(REWRITES_CONV net) THENC GEN_REWRITE_CONV DEPTH_CONV [AND_CLAUSES; OR_CLAUSES] in let SIMPLIFY_CASE_DISTINCTNESS_CLAUSE tm = let avs,bod = strip_forall tm in let ant,cons = dest_imp bod in let ath = RECTYPE_ARITH_EQ_CONV ant in let atm = rand(concl ath) in let bth = CONJ ath (if atm = false_tm then REFL cons else DISCH atm (PURE_REWRITE_CONV[eq_refl; ASSUME atm] cons)) in let cth = try simp1 bth with Failure _ -> try simp2 bth with Failure _ -> simp3 bth in itlist MK_FORALL avs cth in (DEPTH_BINOP_CONV and_tm SIMPLIFY_CASE_DISTINCTNESS_CLAUSE THENC GEN_REWRITE_CONV DEPTH_CONV [FORALL_SIMP; AND_CLAUSES]) tm in (* ------------------------------------------------------------------------- *) (* Simplify an existential question about a pattern. *) (* ------------------------------------------------------------------------- *) let EXISTS_PAT_CONV = let pth = prove (`((?y. _UNGUARDED_PATTERN (GEQ s t) (GEQ z y)) <=> s = t) /\ ((?y. _GUARDED_PATTERN (GEQ s t) g (GEQ z y)) <=> g /\ s = t)`, REWRITE_TAC[_UNGUARDED_PATTERN; _GUARDED_PATTERN; GEQ_DEF] THEN MESON_TAC[]) in let basecnv = GEN_REWRITE_CONV I [pth] and pushcnv = GEN_REWRITE_CONV I [SWAP_EXISTS_THM] in let rec EXISTS_PAT_CONV tm = ((pushcnv THENC BINDER_CONV EXISTS_PAT_CONV) ORELSEC basecnv) tm in fun tm -> if is_exists tm then EXISTS_PAT_CONV tm else failwith "EXISTS_PAT_CONV" in (* ------------------------------------------------------------------------- *) (* Hack a proforma to introduce new pairing or pattern variables. *) (* ------------------------------------------------------------------------- *) let HACK_PROFORMA,EACK_PROFORMA = let elemma0 = prove (`((!z. GEQ (f z) (g z)) <=> (!x y. GEQ (f(x,y)) (g(x,y)))) /\ ((\p. P p) = (\(x,y). P(x,y)))`, REWRITE_TAC[FUN_EQ_THM; FORALL_PAIR_THM]) and elemma1 = prove (`(!P. (!t:A->B->C#D->E. P t) <=> (!t. P (\a b (c,d). t a b d c))) /\ (!P. (!t:B->C#D->E. P t) <=> (!t. P (\b (c,d). t b d c))) /\ (!P. (!t:C#D->E. P t) <=> (!t. P (\(c,d). t d c)))`, REPEAT STRIP_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THENL [FIRST_X_ASSUM(MP_TAC o SPEC `\a b d c. (t:A->B->C#D->E) a b (c,d)`); FIRST_X_ASSUM(MP_TAC o SPEC `\b d c. (t:B->C#D->E) b (c,d)`); FIRST_X_ASSUM(MP_TAC o SPEC `\d c. (t:C#D->E) (c,d)`)] THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN REWRITE_TAC[FUN_EQ_THM; FORALL_PAIR_THM]) in let HACK_PROFORMA n th = if n <= 1 then th else let mkname i = "_P"^string_of_int i in let ty = end_itlist (fun s t -> mk_type("prod",[s;t])) (map (mk_vartype o mkname) (1--n)) in let conv i = let name = "x"^string_of_int i in let cnv = ALPHA_CONV (mk_var(name,mk_vartype(mkname i))) in fun tm -> if is_abs tm & name_of(bndvar tm) <> name then cnv tm else failwith "conv" in let convs = FIRST_CONV (map conv (1--n)) in let th1 = INST_TYPE [ty,`:P`] th in let th2 = REWRITE_RULE[FORALL_PAIR_THM] th1 in let th3 = REWRITE_RULE[elemma0; elemma1] th2 in CONV_RULE(REDEPTH_CONV convs) th3 and EACK_PROFORMA n th = if n <= 1 then th else let mkname i = "_Q"^string_of_int i in let ty = end_itlist (fun s t -> mk_type("prod",[s;t])) (map (mk_vartype o mkname) (1--n)) in let conv i = let name = "t"^string_of_int i in let cnv = ALPHA_CONV (mk_var(name,mk_vartype(mkname i))) in fun tm -> if is_abs tm & name_of(bndvar tm) <> name then cnv tm else failwith "conv" in let convs = FIRST_CONV (map conv (1--n)) in let th1 = INST_TYPE [ty,`:Q`] th in let th2 = REWRITE_RULE[EXISTS_PAIR_THM] th1 in let th3 = REWRITE_RULE[elemma1] th2 in let th4 = REWRITE_RULE[FORALL_PAIR_THM] th3 in CONV_RULE(REDEPTH_CONV convs) th4 in HACK_PROFORMA,EACK_PROFORMA in (* ------------------------------------------------------------------------- *) (* Hack and apply. *) (* ------------------------------------------------------------------------- *) let APPLY_PROFORMA_TAC th (asl,w as gl) = let vs = fst(dest_gabs(body(rand w))) in let n = 1 + length(fst(splitlist dest_pair vs)) in (MATCH_MP_TAC(HACK_PROFORMA n th) THEN BETA_TAC) gl in let is_pattern p n tm = try let f,args = strip_comb(snd(strip_exists (body(body tm)))) in is_const f & name_of f = p & length args = n with Failure _ -> false in let SIMPLIFY_MATCH_WELLDEFINED_TAC = let pth0 = MESON[] `(a /\ x = k ==> x = y ==> d) ==> (a /\ x = k /\ y = k ==> d)` and pth1 = MESON[] `(a /\ b /\ c /\ x = k ==> x = y ==> d) ==> (a /\ x = k /\ b /\ y = k /\ c ==> d)` in REPEAT GEN_TAC THEN (MATCH_MP_TAC pth1 ORELSE MATCH_MP_TAC pth0) THEN CONV_TAC(RAND_CONV SIMPLIFY_WELLDEFINEDNESS_CONV) THEN PURE_REWRITE_TAC [AND_CLAUSES; IMP_CLAUSES; OR_CLAUSES; EQ_CLAUSES; NOT_CLAUSES] in let rec headonly f tm = match tm with Comb(s,t) -> headonly f s & headonly f t & not(t = f) | Abs(x,t) -> headonly f t | _ -> true in let MAIN_ADMISS_TAC (asl,w as gl) = let had,args = strip_comb w in if not(is_const had) then failwith "ADMISS_TAC" else let f,fbod = dest_abs(last args) in let xtup,bod = dest_gabs fbod in let hop,args = strip_comb bod in match (name_of had,name_of hop) with "superadmissible","COND" -> APPLY_PROFORMA_TAC SUPERADMISSIBLE_COND gl | "superadmissible","_MATCH" when name_of(repeat rator (last args)) = "_SEQPATTERN" -> (APPLY_PROFORMA_TAC SUPERADMISSIBLE_MATCH_SEQPATTERN THEN CONV_TAC(ONCE_DEPTH_CONV EXISTS_PAT_CONV)) gl | "superadmissible","_MATCH" when is_pattern "_UNGUARDED_PATTERN" 2 (last args) -> let n = length(fst(strip_exists(body(body(last args))))) in let th = EACK_PROFORMA n SUPERADMISSIBLE_MATCH_UNGUARDED_PATTERN in (APPLY_PROFORMA_TAC th THEN CONJ_TAC THENL [SIMPLIFY_MATCH_WELLDEFINED_TAC; ALL_TAC]) gl | "superadmissible","_MATCH" when is_pattern "_GUARDED_PATTERN" 3 (last args) -> let n = length(fst(strip_exists(body(body(last args))))) in let th = EACK_PROFORMA n SUPERADMISSIBLE_MATCH_GUARDED_PATTERN in (APPLY_PROFORMA_TAC th THEN CONJ_TAC THENL [SIMPLIFY_MATCH_WELLDEFINED_TAC; ALL_TAC]) gl | "superadmissible",_ when is_comb bod & rator bod = f -> APPLY_PROFORMA_TAC SUPERADMISSIBLE_TAIL gl | "admissible","sum" -> APPLY_PROFORMA_TAC ADMISSIBLE_SUM gl | "admissible","nsum" -> APPLY_PROFORMA_TAC ADMISSIBLE_NSUM gl | "admissible","MAP" -> APPLY_PROFORMA_TAC ADMISSIBLE_MAP gl | "admissible","_MATCH" when name_of(repeat rator (last args)) = "_SEQPATTERN" -> (APPLY_PROFORMA_TAC ADMISSIBLE_MATCH_SEQPATTERN THEN CONV_TAC(ONCE_DEPTH_CONV EXISTS_PAT_CONV)) gl | "admissible","_MATCH" -> APPLY_PROFORMA_TAC ADMISSIBLE_MATCH gl | "admissible","_UNGUARDED_PATTERN" -> APPLY_PROFORMA_TAC ADMISSIBLE_UNGUARDED_PATTERN gl | "admissible","_GUARDED_PATTERN" -> APPLY_PROFORMA_TAC ADMISSIBLE_GUARDED_PATTERN gl | "admissible",_ when is_abs bod -> APPLY_PROFORMA_TAC ADMISSIBLE_LAMBDA gl | "admissible",_ when is_comb bod & rator bod = f -> if free_in f (rand bod) then APPLY_PROFORMA_TAC ADMISSIBLE_NEST gl else APPLY_PROFORMA_TAC ADMISSIBLE_BASE gl | "admissible",_ when is_comb bod & headonly f bod -> APPLY_PROFORMA_TAC ADMISSIBLE_COMB gl | _ -> failwith "MAIN_ADMISS_TAC" in let ADMISS_TAC = CONJ_TAC ORELSE MATCH_ACCEPT_TAC ADMISSIBLE_CONST ORELSE MATCH_ACCEPT_TAC SUPERADMISSIBLE_CONST ORELSE MAIN_ADMISS_TAC ORELSE MATCH_MP_TAC ADMISSIBLE_IMP_SUPERADMISSIBLE in (* ------------------------------------------------------------------------- *) (* Instantiate the casewise recursion theorem for existential claim. *) (* Also make a first attempt to simplify the distinctness clause. This may *) (* yield a theorem with just the wellfoundedness "?(<<)" assumption, or it *) (* may be that and an additional distinctness one. *) (* ------------------------------------------------------------------------- *) let instantiate_casewise_recursion = let EXPAND_PAIRED_ALL_CONV = let pth0,pth1 = (CONJ_PAIR o prove) (`(ALL (\(s,t). P s t) [a,b] <=> P a b) /\ (ALL (\(s,t). P s t) (CONS (a,b) l) <=> P a b /\ ALL (\(s,t). P s t) l)`, REWRITE_TAC[ALL]) in let conv0 = REWR_CONV pth0 and conv1 = REWR_CONV pth1 in let rec conv tm = try conv0 tm with Failure _ -> let th = conv1 tm in CONV_RULE (funpow 2 RAND_CONV conv) th in conv and LAMBDA_PAIR_CONV = let rewr1 = GEN_REWRITE_RULE I [GSYM FORALL_PAIR_THM] and rewr2 = GEN_REWRITE_CONV I [FUN_EQ_THM] in fun parms tm -> let parm = end_itlist (curry mk_pair) parms in let x,bod = dest_abs tm in let tm' = mk_gabs(parm,vsubst[parm,x] bod) in let th1 = BETA_CONV(mk_comb(tm,parm)) and th2 = GEN_BETA_CONV (mk_comb(tm',parm)) in let th3 = TRANS th1 (SYM th2) in let th4 = itlist (fun v th -> rewr1 (GEN v th)) (butlast parms) (GEN (last parms) th3) in EQ_MP (SYM(rewr2(mk_eq(tm,tm')))) th4 and FORALL_PAIR_CONV = let rule = GEN_REWRITE_RULE RAND_CONV [GSYM FORALL_PAIR_THM] in let rec depair l t = match l with [v] -> REFL t | v::vs -> rule(BINDER_CONV (depair vs) t) in fun parm parms -> let p = mk_var("P",mk_fun_ty (type_of parm) bool_ty) in let tm = list_mk_forall(parms,mk_comb(p,parm)) in GEN p (SYM(depair parms tm)) in let ELIM_LISTOPS_CONV = PURE_REWRITE_CONV[PAIRWISE; ALL; GSYM CONJ_ASSOC; AND_CLAUSES] THENC TOP_DEPTH_CONV GEN_BETA_CONV in let tuple_function_existence tm = let f,def = dest_exists tm in let domtys0,ranty0 = splitlist dest_fun_ty (type_of f) in let nargs = itlist (max o length o snd o strip_comb o lhs o snd o strip_forall) (conjuncts(snd(strip_forall def))) 0 in let domtys,midtys = chop_list nargs domtys0 in let ranty = itlist mk_fun_ty midtys ranty0 in if length domtys <= 1 then ASSUME tm else let dty = end_itlist (fun ty1 ty2 -> mk_type("prod",[ty1;ty2])) domtys in let f' = variant (frees tm) (mk_var(fst(dest_var f),mk_fun_ty dty ranty)) in let gvs = map genvar domtys in let f'' = list_mk_abs(gvs,mk_comb(f',end_itlist (curry mk_pair) gvs)) in let def' = subst [f'',f] def in let th1 = EXISTS (tm,f'') (ASSUME def') and bth = BETAS_CONV (list_mk_comb(f'',gvs)) in let th2 = GEN_REWRITE_CONV TOP_DEPTH_CONV [bth] (hd(hyp th1)) in SIMPLE_CHOOSE f' (PROVE_HYP (UNDISCH(snd(EQ_IMP_RULE th2))) th1) in let pinstantiate_casewise_recursion def = try PART_MATCH I EXISTS_REFL def with Failure _ -> let f,bod = dest_exists def in let cjs = conjuncts bod in let eqs = map (snd o strip_forall) cjs in let lefts,rights = unzip(map dest_eq eqs) in let arglists = map (snd o strip_comb) lefts in let parms0 = freesl(unions arglists) in let parms = if parms0 <> [] then parms0 else [genvar aty] in let parm = end_itlist (curry mk_pair) parms in let ss = map (fun a -> mk_gabs(parm,end_itlist (curry mk_pair) a)) arglists and ts = map (fun a -> mk_abs(f,mk_gabs(parm,a))) rights in let clauses = mk_flist(map2 (curry mk_pair) ss ts) in let pth = ISPEC clauses RECURSION_SUPERADMISSIBLE in let FIDDLE_CONV = (LAND_CONV o LAND_CONV o BINDER_CONV o RAND_CONV o LAND_CONV o GABS_CONV o RATOR_CONV o LAND_CONV o ABS_CONV) in let th0 = UNDISCH(CONV_RULE(FIDDLE_CONV(LAMBDA_PAIR_CONV parms)) pth) in let th1 = EQ_MP (GEN_ALPHA_CONV f (concl th0)) th0 in let rewr_forall_th = REWR_CONV(FORALL_PAIR_CONV parm parms) in let th2 = CONV_RULE (BINDER_CONV (LAND_CONV(GABS_CONV rewr_forall_th) THENC EXPAND_PAIRED_ALL_CONV)) th1 in let f2,bod2 = dest_exists(concl th2) in let ths3 = map (CONV_RULE (COMB2_CONV (funpow 2 RAND_CONV GEN_BETA_CONV) (RATOR_CONV BETA_CONV THENC GEN_BETA_CONV)) o SPEC_ALL) (CONJUNCTS(ASSUME bod2)) in let ths4 = map2 (fun th t -> let avs,tbod = strip_forall t in itlist GEN avs (PART_MATCH I th tbod)) ths3 cjs in let th5 = SIMPLE_EXISTS f (end_itlist CONJ ths4) in let th6 = PROVE_HYP th2 (SIMPLE_CHOOSE f th5) in let th7 = (RAND_CONV(COMB2_CONV (RAND_CONV (LAND_CONV (GABS_CONV(BINDER_CONV (BINDER_CONV(rewr_forall_th) THENC rewr_forall_th))))) (LAND_CONV (funpow 2 GABS_CONV(BINDER_CONV (BINDER_CONV(rewr_forall_th) THENC rewr_forall_th))))) THENC ELIM_LISTOPS_CONV) (hd(hyp th6)) in let th8 = PROVE_HYP (UNDISCH(snd(EQ_IMP_RULE th7))) th6 in let wfasm,cdasm = dest_conj(hd(hyp th8)) in let th9 = PROVE_HYP (CONJ (ASSUME wfasm) (ASSUME cdasm)) th8 in let th10 = SIMPLIFY_WELLDEFINEDNESS_CONV cdasm in let th11 = PROVE_HYP (UNDISCH(snd(EQ_IMP_RULE th10))) th9 in PROVE_HYP TRUTH th11 in fun etm -> let eth = tuple_function_existence etm in let dtm = hd(hyp eth) in let dth = pinstantiate_casewise_recursion dtm in PROVE_HYP dth eth in (* ------------------------------------------------------------------------- *) (* Justify existence assertion and try to simplify/remove side-conditions. *) (* ------------------------------------------------------------------------- *) let pure_prove_recursive_function_exists = let break_down_admissibility th1 = if hyp th1 = [] then th1 else let def = concl th1 in let f,bod = dest_exists def in let cjs = conjuncts bod in let eqs = map (snd o strip_forall) cjs in let lefts,rights = unzip(map dest_eq eqs) in let arglists = map (snd o strip_comb) lefts in let parms0 = freesl(unions arglists) in let parms = if parms0 <> [] then parms0 else [genvar aty] in let wfasm = find is_exists (hyp th1) in let ord,bod = dest_exists wfasm in let SIMP_ADMISS_TAC = REWRITE_TAC[LET_DEF; LET_END_DEF] THEN REPEAT ADMISS_TAC THEN TRY(W(fun (asl,w) -> let v = fst(dest_forall w) in X_GEN_TAC v THEN MAP_EVERY (fun v -> TRY(GEN_REWRITE_TAC I [FORALL_PAIR_THM]) THEN X_GEN_TAC v) parms THEN CONV_TAC(TOP_DEPTH_CONV GEN_BETA_CONV) THEN MAP_EVERY (fun v -> SPEC_TAC(v,v)) (rev parms @ [v]))) THEN PURE_REWRITE_TAC[FORALL_SIMP] THEN W(fun (asl,w) -> MAP_EVERY (fun t -> SPEC_TAC(t,t)) (subtract (frees w) [ord])) THEN W(fun (asl,w) -> ACCEPT_TAC(ASSUME w)) in let th2 = prove(bod,SIMP_ADMISS_TAC) in let th3 = SIMPLE_EXISTS ord th2 in let allasms = hyp th3 and wfasm = lhand(concl th2) in let th4 = ASSUME(list_mk_conj(wfasm::subtract allasms [wfasm])) in let th5 = SIMPLE_CHOOSE ord (itlist PROVE_HYP (CONJUNCTS th4) th3) in PROVE_HYP th5 th1 in fun dtm -> let th = break_down_admissibility(instantiate_casewise_recursion dtm) in if concl th = dtm then th else failwith "prove_general_recursive_function_exists: sanity" in (* ------------------------------------------------------------------------- *) (* Same, but attempt to prove the wellfoundedness hyp by good guesses. *) (* ------------------------------------------------------------------------- *) let prove_general_recursive_function_exists = let prove_depth_measure_exists = let num_ty = `:num` in fun tyname -> let _,_,sth = assoc tyname (!inductive_type_store) in let ty,zty = dest_fun_ty (type_of(fst(dest_exists(snd(strip_forall(concl sth)))))) in let rth = INST_TYPE [num_ty,zty] sth in let avs,bod = strip_forall(concl rth) in let ev,cbod = dest_exists bod in let process_clause k t = let avs,eq = strip_forall t in let l,r = dest_eq eq in let fn,cargs = dest_comb l in let con,args = strip_comb cargs in let bargs = filter (fun t -> type_of t = ty) args in let r' = list_mk_binop `(+):num->num->num` (mk_small_numeral k :: map (curry mk_comb fn) bargs) in list_mk_forall(avs,mk_eq(l,r')) in let cjs = conjuncts cbod in let def = map2 process_clause (1--length cjs) cjs in prove_recursive_functions_exist sth (list_mk_conj def) in let INDUCTIVE_MEASURE_THEN tac (asl,w) = let ev,bod = dest_exists w in let ty = fst(dest_type(fst(dest_fun_ty(type_of ev)))) in let th = prove_depth_measure_exists ty in let ev',bod' = dest_exists(concl th) in let th' = INST_TYPE(type_match (type_of ev') (type_of ev) []) th in (MP_TAC th' THEN MATCH_MP_TAC MONO_EXISTS THEN GEN_TAC THEN DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN tac) (asl,w) in let CONSTANT_MEASURE_THEN = let one_tm = `1` in fun tac (asl,w) -> let ev,bod = dest_exists w in let ty = fst(dest_fun_ty(type_of ev)) in (EXISTS_TAC(mk_abs(genvar ty,one_tm)) THEN tac) (asl,w) in let GUESS_MEASURE_THEN tac = (EXISTS_TAC `\n. n + 1` THEN tac) ORELSE (INDUCTIVE_MEASURE_THEN tac) ORELSE CONSTANT_MEASURE_THEN tac in let pth_lexleft = prove (`(?r. WF(r) /\ ?s. WF(s) /\ P(\(x1,y1) (x2,y2). r x1 x2 \/ (x1 = x2) /\ s y1 y2)) ==> ?t:A#B->A#B->bool. WF(t) /\ P t`, REPEAT STRIP_TAC THEN EXISTS_TAC `\(x1:A,y1:B) (x2:A,y2:B). r x1 x2 \/ (x1 = x2) /\ s y1 y2` THEN ASM_SIMP_TAC[WF_LEX]) in let pth_lexright = prove (`(?r. WF(r) /\ ?s. WF(s) /\ P(\(x1,y1) (x2,y2). r y1 y2 \/ (y1 = y2) /\ s x1 x2)) ==> ?t:A#B->A#B->bool. WF(t) /\ P t`, REPEAT STRIP_TAC THEN EXISTS_TAC `\u:A#B v:A#B. (\(x1:B,y1:A) (x2:B,y2:A). r x1 x2 \/ (x1 = x2) /\ s y1 y2) ((\(a,b). b,a) u) ((\(a,b). b,a) v)` THEN ASM_SIMP_TAC[ISPEC `\(a,b). b,a` WF_MEASURE_GEN; WF_LEX; ETA_AX] THEN FIRST_X_ASSUM(fun th -> MP_TAC th THEN MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC) THEN REWRITE_TAC[FUN_EQ_THM; FORALL_PAIR_THM]) in let pth_measure = prove (`(?m:A->num. P(MEASURE m)) ==> ?r:A->A->bool. WF(r) /\ P r`, MESON_TAC[WF_MEASURE]) in let rec GUESS_WF_THEN tac (asl,w) = ((MATCH_MP_TAC pth_lexleft THEN GUESS_WF_THEN (GUESS_WF_THEN tac)) ORELSE (MATCH_MP_TAC pth_lexright THEN GUESS_WF_THEN (GUESS_WF_THEN tac)) ORELSE (MATCH_MP_TAC pth_measure THEN REWRITE_TAC[MEASURE; MEASURE_LE] THEN REWRITE_TAC[FORALL_PAIR_THM] THEN GUESS_MEASURE_THEN tac)) (asl,w) in let PRE_GUESS_TAC = CONV_TAC(BINDER_CONV(DEPTH_BINOP_CONV `(/\)` (TRY_CONV SIMPLIFY_WELLDEFINEDNESS_CONV THENC TRY_CONV FORALL_UNWIND_CONV))) in let GUESS_ORDERING_TAC = let false_tm = `\x:A y:A. F` and and_tm = `(/\)` in W(fun (asl,w) -> let ty = fst(dest_fun_ty(type_of(fst(dest_exists w)))) in EXISTS_TAC(inst [ty,aty] false_tm) THEN REWRITE_TAC[WF_FALSE] THEN NO_TAC) ORELSE GUESS_WF_THEN (REWRITE_TAC[FORALL_PAIR_THM] THEN ARITH_TAC) in fun etm -> let th = pure_prove_recursive_function_exists etm in try let wtm = find is_exists (hyp th) in let wth = prove(wtm,PRE_GUESS_TAC THEN GUESS_ORDERING_TAC) in PROVE_HYP wth th with Failure _ -> th in instantiate_casewise_recursion, pure_prove_recursive_function_exists, prove_general_recursive_function_exists;; (* ------------------------------------------------------------------------- *) (* Simple "define" function. *) (* ------------------------------------------------------------------------- *) let define = let close_definition_clauses tm = let avs,bod = strip_forall tm in let cjs = conjuncts bod in let fs = try map (repeat rator o lhs o snd o strip_forall) cjs with Failure _ -> failwith "close_definition_clauses: non-equation" in if length (setify fs) <> 1 then failwith "close_definition_clauses: defining multiple functions" else let f = hd fs in if mem f avs then failwith "close_definition_clauses: fn quantified" else let do_clause t = let lvs,bod = strip_forall t in let fvs = subtract (frees(lhs bod)) (f::lvs) in SPECL fvs (ASSUME(list_mk_forall(fvs,t))) in let ths = map do_clause cjs in let ajs = map (hd o hyp) ths in let th = ASSUME(list_mk_conj ajs) in f,itlist GEN avs (itlist PROVE_HYP (CONJUNCTS th) (end_itlist CONJ ths)) in fun tm -> let tm' = snd(strip_forall tm) in try let th,th' = tryfind (fun th -> th,PART_MATCH I th tm') (!the_definitions) in if can (PART_MATCH I th') (concl th) then (warn true "Benign redefinition"; th') else failwith "" with Failure _ -> let f,th = close_definition_clauses tm in let etm = mk_exists(f,hd(hyp th)) in let th1 = prove_general_recursive_function_exists etm in let th2 = new_specification[fst(dest_var f)] th1 in let g = mk_mconst(dest_var f) in let th3 = PROVE_HYP th2 (INST [g,f] th) in the_definitions := th3::(!the_definitions); th3;;