paulson@10751: (* Title : Series.thy paulson@10751: Author : Jacques D. Fleuriot paulson@10751: Copyright : 1998 University of Cambridge paulson@14416: paulson@14416: Converted to Isar and polished by lcp nipkow@15539: Converted to setsum and polished yet more by TNN paulson@10751: *) paulson@10751: paulson@14416: header{*Finite Summation and Infinite Series*} paulson@10751: nipkow@15131: theory Series nipkow@15140: imports SEQ Lim nipkow@15131: begin paulson@10751: nipkow@15539: (* FIXME why not globally? *) nipkow@15536: declare atLeastLessThan_empty[simp]; nipkow@15539: declare atLeastLessThan_iff[iff] paulson@10751: paulson@10751: constdefs paulson@14416: sums :: "[nat=>real,real] => bool" (infixr "sums" 80) nipkow@15536: "f sums s == (%n. setsum f {0.. s" paulson@10751: paulson@14416: summable :: "(nat=>real) => bool" paulson@14416: "summable f == (\s. f sums s)" paulson@14416: paulson@14416: suminf :: "(nat=>real) => real" nipkow@15539: "suminf f == SOME s. f sums s" paulson@14416: nipkow@15539: lemma setsum_Suc[simp]: nipkow@15536: "setsum f {m..real) = sumr m n (%n. r * f n)" paulson@15047: by (simp add: setsum_mult) paulson@14416: paulson@14416: lemma sumr_split_add [rule_format]: paulson@15047: "n < p --> sumr 0 n f + sumr n p f = sumr 0 p (f::nat=>real)" paulson@15251: apply (induct "p", auto) paulson@14416: apply (rename_tac k) paulson@14416: apply (subgoal_tac "n=k", auto) paulson@14416: done nipkow@15536: nipkow@15536: lemma sumr_split_add: "\ m \ n; n \ p \ \ nipkow@15536: setsum f {m.. 'a::ab_group_add" nipkow@15537: shows "\ m \ n; n \ p \ \ nipkow@15537: setsum f {m..real)) \ sumr m n (%i. abs(f i))" paulson@15047: by (simp add: setsum_abs) paulson@14416: paulson@15047: lemma sumr_rabs_ge_zero [iff]: "0 \ sumr m n (%n. abs (f n))" paulson@15047: by (simp add: setsum_abs_ge_zero) paulson@14416: paulson@15047: text{*Just a congruence rule*} paulson@15047: lemma sumr_fun_eq: paulson@15047: "(\r. m \ r & r < n --> f r = g r) ==> sumr m n f = sumr m n g" paulson@15047: by (auto intro: setsum_cong) paulson@14416: paulson@15047: lemma sumr_less_bounds_zero [simp]: "n < m ==> sumr m n f = 0" paulson@15047: by (simp add: atLeastLessThan_empty) paulson@14416: paulson@14416: lemma sumr_minus: "sumr m n (%i. - f i) = - sumr m n f" paulson@15047: by (simp add: Finite_Set.setsum_negf) nipkow@15539: nipkow@15539: lemma sumr_shift_bounds: nipkow@15539: "setsum f {m+k..n\m. f n = r; m \ k|] nipkow@15539: ==> sumr m k f = (real (k - m) * r)" nipkow@15539: apply (induct "k", auto) paulson@15251: apply (drule_tac x = k in spec) paulson@14416: apply (auto dest!: le_imp_less_or_eq) paulson@15047: apply (simp add: left_distrib real_of_nat_Suc split: nat_diff_split) paulson@14416: done nipkow@15539: *) nipkow@15539: (* FIXME split in tow steps nipkow@15539: lemma setsum_nat_set_real_const: nipkow@15539: "(\n. n\A \ f n = r) \ setsum f A = real(card A) * r" (is "PROP ?P") nipkow@15539: proof (cases "finite A") nipkow@15539: case True nipkow@15539: thus "PROP ?P" nipkow@15539: proof induct nipkow@15539: case empty thus ?case by simp nipkow@15539: next nipkow@15539: case insert thus ?case by(simp add: left_distrib real_of_nat_Suc) nipkow@15539: qed nipkow@15539: next nipkow@15539: case False thus "PROP ?P" by (simp add: setsum_def) nipkow@15539: qed nipkow@15539: *) paulson@14416: nipkow@15539: (* nipkow@15539: lemma sumr_le: nipkow@15539: "[|\n\m. 0 \ (f n::real); m < k|] ==> setsum f {0.. setsum f {0..n\m. 0 \ f n; m < k|] ==> sumr 0 m f \ sumr 0 k f" paulson@15251: apply (induct "k") paulson@14416: apply (auto simp add: less_Suc_eq_le) paulson@15251: apply (drule_tac x = k in spec, safe) paulson@14416: apply (drule le_imp_less_or_eq, safe) paulson@15047: apply (arith) paulson@14416: apply (drule_tac a = "sumr 0 m f" in order_refl [THEN add_mono], auto) paulson@14416: done paulson@14416: paulson@14416: lemma sumr_le2 [rule_format (no_asm)]: paulson@14416: "(\r. m \ r & r < n --> f r \ g r) --> sumr m n f \ sumr m n g" paulson@15251: apply (induct "n") paulson@14416: apply (auto intro: add_mono simp add: le_def) paulson@14416: done nipkow@15539: *) paulson@14416: nipkow@15539: (* nipkow@15360: lemma sumr_ge_zero: "(\n\m. 0 \ f n) --> 0 \ sumr m n f" paulson@15251: apply (induct "n", auto) paulson@14416: apply (drule_tac x = n in spec, arith) paulson@14416: done nipkow@15539: *) paulson@14416: nipkow@15539: (* paulson@14416: lemma rabs_sumr_rabs_cancel [simp]: paulson@15229: "abs (sumr m n (%k. abs (f k))) = (sumr m n (%k. abs (f k)))" paulson@15251: by (induct "n", simp_all add: add_increasing) paulson@14416: paulson@14416: lemma sumr_zero [rule_format]: nipkow@15360: "\n \ N. f n = 0 ==> N \ m --> sumr m n f = 0" paulson@15251: by (induct "n", auto) nipkow@15539: *) paulson@14416: paulson@14416: lemma Suc_le_imp_diff_ge2: nipkow@15539: "[|\n \ N. f (Suc n) = 0; Suc N \ m|] ==> setsum f {m..n=Suc 0..p. m \ p & p < m+n --> (f p = g p)) --> sumr m n f = sumr m n g" paulson@15251: by (induct "n", auto) nipkow@15539: *) paulson@14416: nipkow@15539: lemma setsum_bounded: nipkow@15539: assumes le: "\i. i\A \ f i \ (K::'a::{comm_semiring_1_cancel, pordered_ab_semigroup_add})" nipkow@15539: shows "setsum f A \ of_nat(card A) * K" nipkow@15539: proof (cases "finite A") nipkow@15539: case True nipkow@15539: thus ?thesis using le setsum_mono[where K=A and g = "%x. K"] by simp nipkow@15539: next nipkow@15539: case False thus ?thesis by (simp add: setsum_def) nipkow@15539: qed nipkow@15539: (* paulson@14416: lemma sumr_bound [rule_format (no_asm)]: paulson@14416: "(\p. m \ p & p < m + n --> (f(p) \ K)) nipkow@15539: --> setsum f {m.. (real n * K)" paulson@15251: apply (induct "n") paulson@14416: apply (auto intro: add_mono simp add: left_distrib real_of_nat_Suc) paulson@14416: done nipkow@15539: *) nipkow@15539: (* FIXME should be generalized paulson@14416: lemma sumr_bound2 [rule_format (no_asm)]: paulson@14416: "(\p. 0 \ p & p < n --> (f(p) \ K)) nipkow@15539: --> setsum f {0.. (real n * K)" paulson@15251: apply (induct "n") paulson@15047: apply (auto intro: add_mono simp add: left_distrib real_of_nat_Suc add_commute) paulson@14416: done nipkow@15539: *) nipkow@15539: (* FIXME a bit specialized for [simp]! *) paulson@14416: lemma sumr_group [simp]: nipkow@15539: "(\m=0.. summable f" paulson@14416: by (simp add: sums_def summable_def, blast) paulson@14416: paulson@14416: lemma summable_sums: "summable f ==> f sums (suminf f)" paulson@14416: apply (simp add: summable_def suminf_def) paulson@14416: apply (blast intro: someI2) paulson@14416: done paulson@14416: paulson@14416: lemma summable_sumr_LIMSEQ_suminf: nipkow@15539: "summable f ==> (%n. setsum f {0.. (suminf f)" paulson@14416: apply (simp add: summable_def suminf_def sums_def) paulson@14416: apply (blast intro: someI2) paulson@14416: done paulson@14416: paulson@14416: (*------------------- paulson@14416: sum is unique paulson@14416: ------------------*) paulson@14416: lemma sums_unique: "f sums s ==> (s = suminf f)" paulson@14416: apply (frule sums_summable [THEN summable_sums]) paulson@14416: apply (auto intro!: LIMSEQ_unique simp add: sums_def) paulson@14416: done paulson@14416: paulson@14416: (* paulson@14416: Goalw [sums_def,LIMSEQ_def] paulson@14416: "(\m. n \ Suc m --> f(m) = 0) ==> f sums (sumr 0 n f)" paulson@14416: by safe paulson@14416: by (res_inst_tac [("x","n")] exI 1); paulson@14416: by (safe THEN ftac le_imp_less_or_eq 1) paulson@14416: by safe paulson@14416: by (dres_inst_tac [("f","f")] sumr_split_add_minus 1); paulson@14416: by (ALLGOALS (Asm_simp_tac)); paulson@14416: by (dtac (conjI RS sumr_interval_const) 1); paulson@14416: by Auto_tac paulson@14416: qed "series_zero"; paulson@14416: next one was called series_zero2 paulson@14416: **********************) paulson@14416: nipkow@15539: lemma ivl_subset[simp]: nipkow@15539: "({i.. {m.. i | m \ i & j \ (n::'a::linorder))" nipkow@15539: apply(auto simp:linorder_not_le) nipkow@15539: apply(rule ccontr) nipkow@15539: apply(frule subsetCE[where c = n]) nipkow@15539: apply(auto simp:linorder_not_le) nipkow@15539: done nipkow@15539: nipkow@15539: lemma ivl_diff[simp]: nipkow@15539: "i \ n \ {i..m. n \ m --> f(m) = 0) ==> f sums (setsum f {0.. (%n. c * x(n)) sums (c * x0)" nipkow@15536: by (auto simp add: sums_def setsum_mult [symmetric] paulson@14416: intro!: LIMSEQ_mult intro: LIMSEQ_const) paulson@14416: paulson@14416: lemma sums_divide: "x sums x' ==> (%n. x(n)/c) sums (x'/c)" paulson@14416: by (simp add: real_divide_def sums_mult mult_commute [of _ "inverse c"]) paulson@14416: paulson@14416: lemma sums_diff: "[| x sums x0; y sums y0 |] ==> (%n. x n - y n) sums (x0-y0)" nipkow@15536: by (auto simp add: sums_def setsum_subtractf intro: LIMSEQ_diff) paulson@14416: paulson@14416: lemma suminf_mult: "summable f ==> suminf f * c = suminf(%n. f n * c)" paulson@14416: by (auto intro!: sums_unique sums_mult summable_sums simp add: mult_commute) paulson@14416: paulson@14416: lemma suminf_mult2: "summable f ==> c * suminf f = suminf(%n. c * f n)" paulson@14416: by (auto intro!: sums_unique sums_mult summable_sums) paulson@14416: paulson@14416: lemma suminf_diff: paulson@14416: "[| summable f; summable g |] paulson@14416: ==> suminf f - suminf g = suminf(%n. f n - g n)" paulson@14416: by (auto intro!: sums_diff sums_unique summable_sums) paulson@14416: paulson@14416: lemma sums_minus: "x sums x0 ==> (%n. - x n) sums - x0" nipkow@15536: by (auto simp add: sums_def intro!: LIMSEQ_minus simp add: setsum_negf) paulson@14416: paulson@14416: lemma sums_group: nipkow@15539: "[|summable f; 0 < k |] ==> (%n. setsum f {n*k..d. - f (n + (d + d)) < (f (Suc (n + (d + d))) :: real) |] nipkow@15539: ==> setsum f {0.. setsum f {0..d. 0 < (f(n + (Suc(Suc 0) * d))) + f(n + ((Suc(Suc 0) * d) + 1))|] nipkow@15539: ==> setsum f {0.. nipkow@15539: setsum f {0 ..< Suc (Suc 0) * (Suc no) + n}") nipkow@15539: apply (rule_tac [2] y = "setsum f {0.. setsum f {0..< Suc (Suc 0) * (Suc no) + n}") paulson@14416: apply (rule_tac [2] y = "suminf f + (f (n) + f (n + 1))" in order_trans) nipkow@15539: prefer 3 apply simp paulson@14416: apply (drule_tac [2] x = 0 in spec) paulson@14416: prefer 2 apply simp nipkow@15539: apply (subgoal_tac "0 \ setsum f {0 ..< Suc (Suc 0) * Suc no + n} + - suminf f") nipkow@15539: apply (simp add: abs_if) paulson@14416: apply (auto simp add: linorder_not_less [symmetric]) paulson@14416: done paulson@14416: paulson@15085: text{*A summable series of positive terms has limit that is at least as paulson@15085: great as any partial sum.*} paulson@14416: paulson@14416: lemma series_pos_le: nipkow@15539: "[| summable f; \m \ n. 0 \ f(m) |] ==> setsum f {0.. suminf f" paulson@14416: apply (drule summable_sums) paulson@14416: apply (simp add: sums_def) nipkow@15539: apply (cut_tac k = "setsum f {0..m \ n. 0 < f(m) |] ==> setsum f {0.. (\i=0.. (%n. x ^ n) sums (1/(1 - x))" paulson@14416: apply (case_tac "x = 1") paulson@15234: apply (auto dest!: LIMSEQ_rabs_realpow_zero2 paulson@15234: simp add: sumr_geometric sums_def diff_minus add_divide_distrib) paulson@14416: apply (subgoal_tac "1 / (1 + -x) = 0/ (x - 1) + - 1/ (x - 1) ") paulson@14416: apply (erule ssubst) paulson@14416: apply (rule LIMSEQ_add, rule LIMSEQ_divide) paulson@15234: apply (auto intro: LIMSEQ_const simp add: diff_minus minus_divide_right LIMSEQ_rabs_realpow_zero2) paulson@14416: done paulson@14416: paulson@15085: text{*Cauchy-type criterion for convergence of series (c.f. Harrison)*} paulson@15085: nipkow@15539: lemma summable_convergent_sumr_iff: nipkow@15539: "summable f = convergent (%n. setsum f {0..e > 0. \N. \m \ N. \n. abs(setsum f {m..N. \n \ N. abs(f n) \ g n; summable g |] ==> summable f" paulson@14416: apply (auto simp add: summable_Cauchy) paulson@14416: apply (drule spec, auto) paulson@14416: apply (rule_tac x = "N + Na" in exI, auto) paulson@14416: apply (rotate_tac 2) paulson@14416: apply (drule_tac x = m in spec) paulson@14416: apply (auto, rotate_tac 2, drule_tac x = n in spec) nipkow@15539: apply (rule_tac y = "\k=m..N. \n \ N. abs(f n) \ g n; summable g |] paulson@14416: ==> summable (%k. abs (f k))" paulson@14416: apply (rule summable_comparison_test) paulson@14416: apply (auto simp add: abs_idempotent) paulson@14416: done paulson@14416: paulson@15085: text{*Limit comparison property for series (c.f. jrh)*} paulson@15085: paulson@14416: lemma summable_le: paulson@14416: "[|\n. f n \ g n; summable f; summable g |] ==> suminf f \ suminf g" paulson@14416: apply (drule summable_sums)+ paulson@14416: apply (auto intro!: LIMSEQ_le simp add: sums_def) paulson@14416: apply (rule exI) nipkow@15539: apply (auto intro!: setsum_mono) paulson@14416: done paulson@14416: paulson@14416: lemma summable_le2: paulson@14416: "[|\n. abs(f n) \ g n; summable g |] paulson@14416: ==> summable f & suminf f \ suminf g" paulson@14416: apply (auto intro: summable_comparison_test intro!: summable_le) paulson@14416: apply (simp add: abs_le_interval_iff) paulson@14416: done paulson@14416: paulson@15085: text{*Absolute convergence imples normal convergence*} paulson@14416: lemma summable_rabs_cancel: "summable (%n. abs (f n)) ==> summable f" nipkow@15536: apply (auto simp add: summable_Cauchy) paulson@14416: apply (drule spec, auto) paulson@14416: apply (rule_tac x = N in exI, auto) paulson@14416: apply (drule spec, auto) nipkow@15539: apply (rule_tac y = "\n=m.. abs(suminf f) \ suminf (%n. abs(f n))" nipkow@15536: by (auto intro: LIMSEQ_le LIMSEQ_imp_rabs summable_rabs_cancel summable_sumr_LIMSEQ_suminf) paulson@14416: paulson@14416: paulson@14416: subsection{* The Ratio Test*} paulson@14416: paulson@14416: lemma rabs_ratiotest_lemma: "[| c \ 0; abs x \ c * abs y |] ==> x = (0::real)" paulson@14416: apply (drule order_le_imp_less_or_eq, auto) paulson@14416: apply (subgoal_tac "0 \ c * abs y") paulson@14416: apply (simp add: zero_le_mult_iff, arith) paulson@14416: done paulson@14416: paulson@14416: lemma le_Suc_ex: "(k::nat) \ l ==> (\n. l = k + n)" paulson@14416: apply (drule le_imp_less_or_eq) paulson@14416: apply (auto dest: less_imp_Suc_add) paulson@14416: done paulson@14416: paulson@14416: lemma le_Suc_ex_iff: "((k::nat) \ l) = (\n. l = k + n)" paulson@14416: by (auto simp add: le_Suc_ex) paulson@14416: paulson@14416: (*All this trouble just to get 0n \ N. abs(f(Suc n)) \ c*abs(f n) |] paulson@14416: ==> 0 < c | summable f" paulson@14416: apply (simp (no_asm) add: linorder_not_le [symmetric]) paulson@14416: apply (simp add: summable_Cauchy) paulson@14416: apply (safe, subgoal_tac "\n. N \ n --> f (Suc n) = 0") paulson@14416: prefer 2 apply (blast intro: rabs_ratiotest_lemma) paulson@14416: apply (rule_tac x = "Suc N" in exI, clarify) paulson@14416: apply (drule_tac n=n in Suc_le_imp_diff_ge2, auto) paulson@14416: done paulson@14416: paulson@14416: lemma ratio_test: nipkow@15360: "[| c < 1; \n \ N. abs(f(Suc n)) \ c*abs(f n) |] paulson@14416: ==> summable f" paulson@14416: apply (frule ratio_test_lemma2, auto) paulson@15234: apply (rule_tac g = "%n. (abs (f N) / (c ^ N))*c ^ n" paulson@15234: in summable_comparison_test) paulson@14416: apply (rule_tac x = N in exI, safe) paulson@14416: apply (drule le_Suc_ex_iff [THEN iffD1]) paulson@14416: apply (auto simp add: power_add realpow_not_zero) nipkow@15539: apply (induct_tac "na", auto) paulson@14416: apply (rule_tac y = "c*abs (f (N + n))" in order_trans) paulson@14416: apply (auto intro: mult_right_mono simp add: summable_def) paulson@14416: apply (simp add: mult_ac) paulson@15234: apply (rule_tac x = "abs (f N) * (1/ (1 - c)) / (c ^ N)" in exI) paulson@15234: apply (rule sums_divide) paulson@15234: apply (rule sums_mult) paulson@15234: apply (auto intro!: geometric_sums) paulson@14416: done paulson@14416: paulson@14416: paulson@15085: text{*Differentiation of finite sum*} paulson@14416: paulson@14416: lemma DERIV_sumr [rule_format (no_asm)]: paulson@14416: "(\r. m \ r & r < (m + n) --> DERIV (%x. f r x) x :> (f' r x)) nipkow@15539: --> DERIV (%x. \n=m.. (\r=m..