(* ========================================================================= *)
(* Generic iterated operations and special cases of sums over N and R. *)
(* *)
(* (c) Copyright, John Harrison 1998-2007 *)
(* (c) Copyright, Lars Schewe 2007 *)
(* ========================================================================= *)
needs "sets.ml";;
prioritize_num();;
(* ------------------------------------------------------------------------- *)
(* A natural notation for segments of the naturals. *)
(* ------------------------------------------------------------------------- *)
parse_as_infix("..",(15,"right"));;
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)`,
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`]]);;
(* ------------------------------------------------------------------------- *)
(* Equivalence with the more ad-hoc comprehension notation. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* 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 </ m then MP_CONV NUM_LT_CONV (INST [mt,m_tm; nt,n_tm] pth_0)
else if n =/ m then INST [mt,m_tm] pth_1
else let th = MP_CONV NUM_LE_CONV (INST [mt,m_tm; nt,n_tm] pth_2) in
CONV_RULE(funpow 2 RAND_CONV
(LAND_CONV NUM_SUC_CONV THENC NUMSEG_CONV)) th in
NUMSEG_CONV;;
(* ------------------------------------------------------------------------- *)
(* Topological sorting of a finite set. *)
(* ------------------------------------------------------------------------- *)
let TOPOLOGICAL_SORT = prove
(`!(<<). (!x y:A. x << y /\ y << x ==> 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]]);;
(* ------------------------------------------------------------------------- *)
(* Analogous finiteness theorem for segments of integers. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Generic iteration of operation over set with finite support. *)
(* ------------------------------------------------------------------------- *)
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_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))`,
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 {}`,
(* ------------------------------------------------------------------------- *)
(* Key lemmas about the generic notion. *)
(* ------------------------------------------------------------------------- *)
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)))`,
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)`,
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. (!x. x
IN s /\ ~(f x = neutral op) ==> P(f x))
==> P(iterate op s f)`,
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)`,
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`,
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))`,
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_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`,
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)`,
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]]);;
let ITERATE_OP_GEN = prove
(`!op. monoidal op
==> !f g:A->B s.
FINITE(support op f s) /\
FINITE(support op g s)
==> iterate op s (\x. op (f x) (g x)) =
op (iterate op s f) (iterate op s g)`,
let ITERATE_CLAUSES_NUMSEG = prove
(`!op. monoidal op
==> (!m. iterate op (m..0) f = if m = 0 then f(0) else neutral op) /\
(!m n. iterate op (m..SUC n) f =
if m <= SUC n then op (iterate op (m..n) f) (f(SUC n))
else iterate op (m..n) f)`,
let ITERATE_PAIR = prove
(`!op. monoidal op
==> !f m n. iterate op (2*m..2*n+1) f =
iterate op (m..n) (\i. op (f(2*i)) (f(2*i+1)))`,
GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN GEN_TAC THEN
INDUCT_TAC THEN CONV_TAC NUM_REDUCE_CONV THENL
[ASM_SIMP_TAC[num_CONV `1`;
ITERATE_CLAUSES_NUMSEG] THEN
REWRITE_TAC[ARITH_RULE `2 * m <= SUC 0 <=> m = 0`] THEN
COND_CASES_TAC THEN ASM_REWRITE_TAC[
MULT_EQ_0; ARITH];
REWRITE_TAC[ARITH_RULE `2 * SUC n + 1 = SUC(SUC(2 * n + 1))`] THEN
ASM_SIMP_TAC[
ITERATE_CLAUSES_NUMSEG] THEN
REWRITE_TAC[ARITH_RULE `2 * m <= SUC(SUC(2 * n + 1)) <=> m <= SUC n`;
ARITH_RULE `2 * m <= SUC(2 * n + 1) <=> m <= SUC n`] THEN
COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
REWRITE_TAC[ARITH_RULE `2 * SUC n = SUC(2 * n + 1)`;
ARITH_RULE `2 * SUC n + 1 = SUC(SUC(2 * n + 1))`] THEN
ASM_MESON_TAC[monoidal]]);;
(* ------------------------------------------------------------------------- *)
(* Sums of natural numbers. *)
(* ------------------------------------------------------------------------- *)
prioritize_num();;
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`,
let NSUM_EQ = prove
(`!f g s. (!x. x
IN s ==> (f x = g x)) ==> (nsum s f = nsum s g)`,
let NSUM_BOUND_LT_GEN = prove
(`!s f 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_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_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`,
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`,
let NSUM_CLOSED = prove
(`!P f:A->num s.
P(0) /\ (!x y. P x /\ P y ==> P(x + y)) /\ (!a. a
IN s ==> P(f a))
==> P(nsum s f)`,
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`,
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)`,
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)`,
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))`,
let NSUM_PAIR = prove
(`!f m n. nsum(2*m..2*n+1) f = nsum(m..n) (\i. f(2*i) + f(2*i+1))`,
let MOD_NSUM_MOD = prove
(`!f:A->num n s.
FINITE s /\ ~(n = 0)
==> (nsum s f) MOD n = nsum s (\i. f(i) MOD n) MOD n`,
GEN_TAC THEN GEN_TAC THEN
ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC[] THEN
MATCH_MP_TAC
FINITE_INDUCT_STRONG THEN SIMP_TAC[
NSUM_CLAUSES] THEN
REPEAT STRIP_TAC THEN
W(MP_TAC o PART_MATCH (rand o rand)
MOD_ADD_MOD o lhand o snd) THEN
ASM_REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
W(MP_TAC o PART_MATCH (rand o rand)
MOD_ADD_MOD o rand o snd) THEN
ASM_SIMP_TAC[
MOD_MOD_REFL]);;
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. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Sums of real numbers. *)
(* ------------------------------------------------------------------------- *)
prioritize_real();;
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_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`,
let SUM_EQ = prove
(`!f g s. (!x. x
IN s ==> (f x = g x)) ==> (sum s f = sum s g)`,
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_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_DELTA = prove
(`!s a. sum s (\x. if x = a:A then b else &0) = if a
IN s then b else &0`,
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 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`,
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`,
let SUM_CASES_1 = prove
(`!s a.
FINITE s /\ a
IN s
==> sum s (\x. if x = a then y else f(x)) = sum s f + (y - f a)`,
REPEAT STRIP_TAC THEN ASM_SIMP_TAC[
SUM_CASES] THEN
ASM_SIMP_TAC[GSYM
DELETE;
SUM_DELETE] THEN
ASM_SIMP_TAC[SET_RULE `a
IN s ==> {x | x
IN s /\ x = a} = {a}`] THEN
REWRITE_TAC[
SUM_SING] THEN REAL_ARITH_TAC);;
let SUM_CLOSED = prove
(`!P f:A->real s.
P(&0) /\ (!x y. P x /\ P y ==> P(x + y)) /\ (!a. a
IN s ==> P(f a))
==> P(sum s f)`,
(* ------------------------------------------------------------------------- *)
(* Specialize them to sums over intervals of numbers. *)
(* ------------------------------------------------------------------------- *)
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`,
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)`,
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)`,
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)`,
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))`,
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)`,
let SUM_PAIR = prove
(`!f m n. sum(2*m..2*n+1) f = sum(m..n) (\i. f(2*i) + f(2*i+1))`,
(* ------------------------------------------------------------------------- *)
(* 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`,
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`,
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`,
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`,
(* ------------------------------------------------------------------------- *)
(* 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))`,
(* ------------------------------------------------------------------------- *)
(* Some useful facts about real polynomial functions. *)
(* ------------------------------------------------------------------------- *)
let REAL_SUB_POLYFUN = prove
(`!a x y n.
1 <= n
==> sum(0..n) (\i. a i * x pow i) - sum(0..n) (\i. a i * y pow i) =
(x - y) *
sum(0..n-1) (\j. sum(j+1..n) (\i. a i * y pow (i - j - 1)) * x pow j)`,
let REAL_SUB_POLYFUN_ALT = prove
(`!a x y n.
1 <= n
==> sum(0..n) (\i. a i * x pow i) - sum(0..n) (\i. a i * y pow i) =
(x - y) *
sum(0..n-1) (\j. sum(0..n-j-1) (\k. a(j+k+1) * y pow k) * x pow j)`,
REPEAT STRIP_TAC THEN ASM_SIMP_TAC[
REAL_SUB_POLYFUN] THEN AP_TERM_TAC THEN
MATCH_MP_TAC
SUM_EQ_NUMSEG THEN X_GEN_TAC `j:num` THEN REPEAT STRIP_TAC THEN
REWRITE_TAC[] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
MATCH_MP_TAC
SUM_EQ_GENERAL_INVERSES THEN
MAP_EVERY EXISTS_TAC
[`\i. i - (j + 1)`; `\k. j + k + 1`] THEN
REWRITE_TAC[
IN_NUMSEG] THEN REPEAT STRIP_TAC THEN
TRY(BINOP_TAC THEN AP_TERM_TAC) THEN ASM_ARITH_TAC);;
let REAL_POLYFUN_EQ_CONST = prove
(`!n c k. (!x. sum(0..n) (\i. c i * x pow i) = k) <=>
c 0 = k /\ (!i. i
IN 1..n ==> c i = &0)`,
REPEAT GEN_TAC THEN MATCH_MP_TAC
EQ_TRANS THEN EXISTS_TAC
`!x. sum(0..n) (\i. (if i = 0 then c 0 - k else c i) * x pow i) = &0` THEN
CONJ_TAC THENL
[SIMP_TAC[
SUM_CLAUSES_LEFT;
LE_0;
real_pow;
REAL_MUL_RID] THEN
REWRITE_TAC[REAL_ARITH `(c - k) + s = &0 <=> c + s = k`] THEN
AP_TERM_TAC THEN ABS_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
AP_TERM_TAC THEN MATCH_MP_TAC
SUM_EQ THEN GEN_TAC THEN
REWRITE_TAC[
IN_NUMSEG] THEN
COND_CASES_TAC THEN ASM_REWRITE_TAC[ARITH];
REWRITE_TAC[
REAL_POLYFUN_EQ_0;
IN_NUMSEG;
LE_0] THEN
GEN_REWRITE_TAC LAND_CONV [MESON[]
`(!n. P n) <=> P 0 /\ (!n. ~(n = 0) ==> P n)`] THEN
SIMP_TAC[
LE_0;
REAL_SUB_0] THEN MESON_TAC[
LE_1]]);;
(* ------------------------------------------------------------------------- *)
(* Make natural numbers the default again. *)
(* ------------------------------------------------------------------------- *)
prioritize_num();;