# HG changeset patch # User Manuel Eberl # Date 1744966696 -7200 # Node ID ff4b062aae573d061e92a4a24c35f4929c31d9c7 # Parent 3704717ed7bf986256f1685a4c4f732cf6a2299c moved some lemmas to where they fit better diff -r 3704717ed7bf -r ff4b062aae57 src/HOL/Analysis/Derivative.thy --- a/src/HOL/Analysis/Derivative.thy Mon Apr 21 08:24:58 2025 +0200 +++ b/src/HOL/Analysis/Derivative.thy Fri Apr 18 10:58:16 2025 +0200 @@ -1742,7 +1742,7 @@ using islimpt_approachable_real[of x S] not_bot by (auto simp add: trivial_limit_within) then show ?thesis - using eq_iff_diff_eq_0 by fastforce + using eq_iff_diff_eq_0 by (metis add.commute diff_add_cancel) qed qed (use f' f'' in \auto simp: has_vector_derivative_def\) then show ?thesis @@ -1777,6 +1777,17 @@ by (intro vector_derivative_unique_within[OF not_bot vector_derivative_works[THEN iffD1] y]) (auto simp: differentiable_def has_vector_derivative_def) +lemma vector_derivative_translate [simp]: + "vector_derivative ((+) z \ g) (at x within A) = vector_derivative g (at x within A)" +proof - + have "(((+) z \ g) has_vector_derivative g') (at x within A)" + if "(g has_vector_derivative g') (at x within A)" for g :: "real \ 'a" and z g' + unfolding o_def using that by (auto intro!: derivative_eq_intros) + from this[of g _ z] this[of "\x. z + g x" _ "-z"] show ?thesis + unfolding vector_derivative_def + by (intro arg_cong[where f = Eps] ext) (auto simp: o_def algebra_simps) +qed + lemma deriv_of_real [simp]: "at x within A \ bot \ vector_derivative of_real (at x within A) = 1" by (auto intro!: vector_derivative_within derivative_eq_intros) @@ -2256,6 +2267,43 @@ definition\<^marker>\tag important\ deriv :: "('a \ 'a::real_normed_field) \ 'a \ 'a" where "deriv f x \ SOME D. DERIV f x :> D" +lemma deriv_shift_0: "deriv f z = deriv (f \ (\x. z + x)) 0" +proof - + have *: "(f \ (+) z has_field_derivative D) (at z')" + if "(f has_field_derivative D) (at (z + z'))" for D z z' and f :: "'a \ 'a" + proof - + have "(f \ (+) z has_field_derivative D * 1) (at z')" + by (rule DERIV_chain that derivative_eq_intros refl)+ auto + thus ?thesis by simp + qed + have "(\D. (f has_field_derivative D) (at z)) = (\ D. (f \ (+) z has_field_derivative D) (at 0))" + using *[of f _ z 0] *[of "f \ (+) z" _ "-z" z] by (intro ext iffI) (auto simp: o_def) + thus ?thesis + by (simp add: deriv_def) +qed + +lemma deriv_shift_0': "NO_MATCH 0 z \ deriv f z = deriv (f \ (\x. z + x)) 0" + by (rule deriv_shift_0) + +lemma higher_deriv_shift_0: "(deriv ^^ n) f z = (deriv ^^ n) (f \ (\x. z + x)) 0" +proof (induction n arbitrary: f) + case (Suc n) + have "(deriv ^^ Suc n) f z = (deriv ^^ n) (deriv f) z" + by (subst funpow_Suc_right) auto + also have "\ = (deriv ^^ n) (\x. deriv f (z + x)) 0" + by (subst Suc) (auto simp: o_def) + also have "\ = (deriv ^^ n) (\x. deriv (\xa. f (z + x + xa)) 0) 0" + by (subst deriv_shift_0) (auto simp: o_def) + also have "(\x. deriv (\xa. f (z + x + xa)) 0) = deriv (\x. f (z + x))" + by (rule ext) (simp add: deriv_shift_0' o_def add_ac) + also have "(deriv ^^ n) \ 0 = (deriv ^^ Suc n) (f \ (\x. z + x)) 0" + by (subst funpow_Suc_right) (auto simp: o_def) + finally show ?case . +qed auto + +lemma higher_deriv_shift_0': "NO_MATCH 0 z \ (deriv ^^ n) f z = (deriv ^^ n) (f \ (\x. z + x)) 0" + by (rule higher_deriv_shift_0) + lemma DERIV_imp_deriv: "DERIV f x :> f' \ deriv f x = f'" unfolding deriv_def by (metis some_equality DERIV_unique) diff -r 3704717ed7bf -r ff4b062aae57 src/HOL/Analysis/FPS_Convergence.thy --- a/src/HOL/Analysis/FPS_Convergence.thy Mon Apr 21 08:24:58 2025 +0200 +++ b/src/HOL/Analysis/FPS_Convergence.thy Fri Apr 18 10:58:16 2025 +0200 @@ -61,6 +61,9 @@ lemma open_eball [simp, intro]: "open (eball z r)" by (cases r) auto +lemma connected_eball [intro]: "connected (eball (z :: 'a :: real_normed_vector) r)" + by (cases r) auto + subsection \Basic properties of convergent power series\ diff -r 3704717ed7bf -r ff4b062aae57 src/HOL/Analysis/Infinite_Products.thy --- a/src/HOL/Analysis/Infinite_Products.thy Mon Apr 21 08:24:58 2025 +0200 +++ b/src/HOL/Analysis/Infinite_Products.thy Fri Apr 18 10:58:16 2025 +0200 @@ -846,11 +846,16 @@ by (metis convergent_mult_const_iff \C \ 0\ cong cf convergent_LIMSEQ_iff convergent_prod_iff_convergent convergent_prod_imp_convergent g) next assume cg: "convergent_prod g" - have "\a. C * a \ 0 \ (\n. prod g {..n}) \ a" - by (metis (no_types) \C \ 0\ cg convergent_prod_iff_nz_lim divide_eq_0_iff g nonzero_mult_div_cancel_right) + have **: "eventually (\n. prod g {..n} = prod f {..n} / C) sequentially" + using * by eventually_elim (use \C \ 0\ in auto) + from cg and g have "\ (\n. prod g {..n}) \ 0" + by simp + then have "\ (\n. prod f {..n}) \ 0" + using ** \C \ 0\ filterlim_cong by fastforce then show "convergent_prod f" - using "*" tendsto_mult_left filterlim_cong - by (fastforce simp add: convergent_prod_iff_nz_lim f) + by (metis \C \ 0\ cg convergent_LIMSEQ_iff + convergent_mult_const_iff convergent_prod_iff_convergent + convergent_prod_imp_convergent f local.cong) qed qed @@ -953,8 +958,14 @@ lemma convergent_prod_If_finite[simp, intro]: fixes f :: "nat \ 'a::{idom,t2_space}" - shows "finite {r. P r} \ convergent_prod (\r. if P r then f r else 1)" - using convergent_prod_def has_prod_If_finite has_prod_def by fastforce + assumes "finite {r. P r}" + shows "convergent_prod (\r. if P r then f r else 1)" +proof - + have "(\r. if P r then f r else 1) has_prod (\r | P r. f r)" + by (rule has_prod_If_finite) fact + thus ?thesis + by (meson convergent_prod_def has_prod_def) +qed lemma has_prod_single: fixes f :: "nat \ 'a::{idom,t2_space}" diff -r 3704717ed7bf -r ff4b062aae57 src/HOL/Analysis/Infinite_Sum.thy --- a/src/HOL/Analysis/Infinite_Sum.thy Mon Apr 21 08:24:58 2025 +0200 +++ b/src/HOL/Analysis/Infinite_Sum.thy Fri Apr 18 10:58:16 2025 +0200 @@ -27,6 +27,7 @@ Elementary_Topology "HOL-Library.Extended_Nonnegative_Real" "HOL-Library.Complex_Order" + "HOL-Computational_Algebra.Formal_Power_Series" begin subsection \Definition and syntax\ @@ -3578,5 +3579,79 @@ shows "(f has_sum S) A \ ((\x. -f x) has_sum (-S)) A" using has_sum_cmult_right[of f A S "-1"] by simp + +subsection \Infinite sums of formal power series\ + +text \ + Consequently, a family $(f_x)_{x\in A}$ of formal power series sums to a series $s$ iff for + any $n\geq 0$, the set $A_n = \{x\in A \mid [X^n]\,f_x \neq 0\}$ is finite and + $[X^n]\,s = \sum_{x\in A_n} [X^n]\,f_x$. + + The first condition can be rephrased as follows: for any $n\geq 0$, for all but finitely many + $x$, the series $f_x$ has subdegree ${>}\,n$. +\ +lemma has_sum_fpsI: + assumes "\n. finite {x\A. fps_nth (F x) n \ 0}" + assumes "\n. fps_nth S n = (\x | x \ A \ fps_nth (F x) n \ 0. fps_nth (F x) n)" + shows "(F has_sum S) A" + unfolding has_sum_def +proof (rule tendsto_fpsI) + fix n :: nat + define B where "B = {x\A. fps_nth (F x) n \ 0}" + from assms(1) have [intro]: "finite B" + unfolding B_def by auto + moreover have "B \ A" + by (auto simp: B_def) + ultimately have "eventually (\X. finite X \ B \ X \ X \ A) (finite_subsets_at_top A)" + by (subst eventually_finite_subsets_at_top) blast + thus "eventually (\X. fps_nth (\x\X. F x) n = fps_nth S n) (finite_subsets_at_top A)" + proof eventually_elim + case (elim X) + have "fps_nth (\x\X. F x) n = (\x\X. fps_nth (F x) n)" + by (simp add: fps_sum_nth) + also have "\ = (\x\B. fps_nth (F x) n)" + by (rule sum.mono_neutral_right) (use \finite B\ \B \ A\ elim in \auto simp: B_def\) + also have "\ = fps_nth S n" + using assms(2)[of n] by (simp add: B_def) + finally show "fps_nth (\x\X. F x) n = fps_nth S n" . + qed +qed + +lemma has_sum_fpsD: + fixes F :: "'a \ 'b :: ab_group_add fps" + assumes "(F has_sum S) A" + shows "finite {x\A. fps_nth (F x) n \ 0}" + "fps_nth S n = (\x | x \ A \ fps_nth (F x) n \ 0. fps_nth (F x) n)" +proof - + from assms have "\\<^sub>F X in finite_subsets_at_top A. fps_nth (sum F X) k = fps_nth S k" for k + unfolding has_sum_def tendsto_fps_iff by blast + hence "\\<^sub>F X in finite_subsets_at_top A. fps_nth (sum F X) n = fps_nth S n" + by eventually_elim force + then obtain B where [intro, simp]: "finite B" and B: "B \ A" + "\X. finite X \ B \ X \ X \ A \ fps_nth (sum F X) n = fps_nth S n" + unfolding eventually_finite_subsets_at_top by metis + + have subset: "{x\A. fps_nth (F x) n \ 0} \ B" + proof safe + fix x assume x: "x \ A" "fps_nth (F x) n \ 0" + have "fps_nth (sum F B) n = fps_nth S n" + by (rule B(2)) (use B(1) in auto) + moreover have "fps_nth (sum F (insert x B)) n = fps_nth S n" + by (rule B(2)) (use B(1) x in auto) + ultimately show "x \ B" + using x by (auto simp: sum.insert_if split: if_splits) + qed + thus finite: "finite {x\A. fps_nth (F x) n \ 0}" + by (rule finite_subset) auto + + have "fps_nth S n = fps_nth (\x\B. F x) n" + by (rule sym, rule B(2)) (use B(1) in auto) + also have "\ = (\x\B. fps_nth (F x) n)" + by (simp add: fps_sum_nth) + also have "\ = (\x | x \ A \ fps_nth (F x) n \ 0. fps_nth (F x) n)" + by (rule sum.mono_neutral_right) (use subset B(1) in auto) + finally show "fps_nth S n = (\x | x \ A \ fps_nth (F x) n \ 0. fps_nth (F x) n)" . +qed + end diff -r 3704717ed7bf -r ff4b062aae57 src/HOL/Complex_Analysis/Complex_Residues.thy --- a/src/HOL/Complex_Analysis/Complex_Residues.thy Mon Apr 21 08:24:58 2025 +0200 +++ b/src/HOL/Complex_Analysis/Complex_Residues.thy Fri Apr 18 10:58:16 2025 +0200 @@ -52,6 +52,26 @@ with assms show ?thesis by simp qed +lemma residue_shift_0: "residue f z = residue (\x. f (z + x)) 0" +proof - + define Q where + "Q = (\r f z \. (f has_contour_integral complex_of_real (2 * pi) * \ * r) (circlepath z \))" + define P where + "P = (\r f z. \e>0. \\>0. \ < e \ Q r f z \)" + have path_eq: "circlepath (z - w) \ = (+) (-w) \ circlepath z \" for z w \ + by (simp add: circlepath_def o_def part_circlepath_def algebra_simps) + have *: "P r f z" if "P r (\x. f (x + w)) (z - w)" for r w f z + using that by (auto simp: P_def Q_def path_eq has_contour_integral_translate) + have "(SOME r. P r f z) = (SOME r. P r (\x. f (z + x)) 0)" + using *[of _ f z z] *[of _ "\x. f (z + x)" "-z"] + by (intro arg_cong[where f = Eps] ext iffI) (simp_all add: add_ac) + thus ?thesis + by (simp add: residue_def P_def Q_def) +qed + +lemma residue_shift_0': "NO_MATCH 0 z \ residue f z = residue (\x. f (z + x)) 0" + by (rule residue_shift_0) + lemma contour_integral_circlepath_eq: assumes "open s" and f_holo:"f holomorphic_on (s-{z})" and "0e2" and e2_cball:"cball z e2 \ s" diff -r 3704717ed7bf -r ff4b062aae57 src/HOL/Complex_Analysis/Contour_Integration.thy --- a/src/HOL/Complex_Analysis/Contour_Integration.thy Mon Apr 21 08:24:58 2025 +0200 +++ b/src/HOL/Complex_Analysis/Contour_Integration.thy Fri Apr 18 10:58:16 2025 +0200 @@ -68,6 +68,18 @@ using has_integral_unique by (auto simp: has_contour_integral_def) +lemma has_contour_integral_translate: + "(f has_contour_integral I) ((+) z \ g) \ ((\x. f (x + z)) has_contour_integral I) g" + by (simp add: has_contour_integral_def add_ac) + +lemma contour_integrable_translate: + "f contour_integrable_on ((+) z \ g) \ (\x. f (x + z)) contour_integrable_on g" + by (simp add: contour_integrable_on_def has_contour_integral_translate) + +lemma contour_integral_translate: + "contour_integral ((+) z \ g) f = contour_integral g (\x. f (x + z))" + by (simp add: contour_integral_def contour_integrable_translate has_contour_integral_translate) + lemma has_contour_integral_integrable: "(f has_contour_integral i) g \ f contour_integrable_on g" using contour_integrable_on_def by blast diff -r 3704717ed7bf -r ff4b062aae57 src/HOL/Complex_Analysis/Laurent_Convergence.thy --- a/src/HOL/Complex_Analysis/Laurent_Convergence.thy Mon Apr 21 08:24:58 2025 +0200 +++ b/src/HOL/Complex_Analysis/Laurent_Convergence.thy Fri Apr 18 10:58:16 2025 +0200 @@ -4,80 +4,6 @@ begin -instance fps :: (semiring_char_0) semiring_char_0 -proof - show "inj (of_nat :: nat \ 'a fps)" - proof - fix m n :: nat - assume "of_nat m = (of_nat n :: 'a fps)" - hence "fps_nth (of_nat m) 0 = (fps_nth (of_nat n) 0 :: 'a)" - by (simp only: ) - thus "m = n" - by simp - qed -qed - -instance fls :: (semiring_char_0) semiring_char_0 -proof - show "inj (of_nat :: nat \ 'a fls)" - by (metis fls_regpart_of_nat injI of_nat_eq_iff) -qed - -lemma fls_const_eq_0_iff [simp]: "fls_const c = 0 \ c = 0" - using fls_const_0 fls_const_nonzero by blast - -lemma fls_subdegree_add_eq1: - assumes "f \ 0" "fls_subdegree f < fls_subdegree g" - shows "fls_subdegree (f + g) = fls_subdegree f" -proof (intro antisym) - from assms have *: "fls_nth (f + g) (fls_subdegree f) \ 0" - by auto - from * show "fls_subdegree (f + g) \ fls_subdegree f" - by (rule fls_subdegree_leI) - from * have "f + g \ 0" - using fls_nonzeroI by blast - thus "fls_subdegree f \ fls_subdegree (f + g)" - using assms(2) fls_plus_subdegree by force -qed - -lemma fls_subdegree_add_eq2: - assumes "g \ 0" "fls_subdegree g < fls_subdegree f" - shows "fls_subdegree (f + g) = fls_subdegree g" -proof (intro antisym) - from assms have *: "fls_nth (f + g) (fls_subdegree g) \ 0" - by auto - from * show "fls_subdegree (f + g) \ fls_subdegree g" - by (rule fls_subdegree_leI) - from * have "f + g \ 0" - using fls_nonzeroI by blast - thus "fls_subdegree g \ fls_subdegree (f + g)" - using assms(2) fls_plus_subdegree by force -qed - -lemma fls_subdegree_diff_eq1: - assumes "f \ 0" "fls_subdegree f < fls_subdegree g" - shows "fls_subdegree (f - g) = fls_subdegree f" - using fls_subdegree_add_eq1[of f "-g"] assms by simp - -lemma fls_subdegree_diff_eq2: - assumes "g \ 0" "fls_subdegree g < fls_subdegree f" - shows "fls_subdegree (f - g) = fls_subdegree g" - using fls_subdegree_add_eq2[of "-g" f] assms by simp - -lemma nat_minus_fls_subdegree_plus_const_eq: - "nat (-fls_subdegree (F + fls_const c)) = nat (-fls_subdegree F)" -proof (cases "fls_subdegree F < 0") - case True - hence "fls_subdegree (F + fls_const c) = fls_subdegree F" - by (intro fls_subdegree_add_eq1) auto - thus ?thesis - by simp -next - case False - thus ?thesis - by (auto simp: fls_subdegree_ge0I) -qed - definition%important fls_conv_radius :: "complex fls \ ereal" where "fls_conv_radius f = fps_conv_radius (fls_regpart f)" @@ -139,12 +65,6 @@ and eval_fps_of_int [simp]: "eval_fps (of_int m) z = of_int m" by (simp_all flip: fps_of_nat fps_of_int) -lemma fls_subdegree_numeral [simp]: "fls_subdegree (numeral n) = 0" - by (metis fls_subdegree_of_nat of_nat_numeral) - -lemma fls_regpart_numeral [simp]: "fls_regpart (numeral n) = numeral n" - by (metis fls_regpart_of_nat of_nat_numeral) - lemma fps_conv_radius_of_nat [simp]: "fps_conv_radius (of_nat n) = \" and fps_conv_radius_of_int [simp]: "fps_conv_radius (of_int m) = \" by (simp_all flip: fps_of_nat fps_of_int) @@ -486,9 +406,6 @@ lemmas has_field_derivative_eval_fps' [derivative_intros] = DERIV_chain2[OF has_field_derivative_eval_fps] -lemma fps_deriv_fls_regpart: "fps_deriv (fls_regpart F) = fls_regpart (fls_deriv F)" - by (intro fps_ext) (auto simp: add_ac) - (* TODO: generalise for nonneg subdegree *) lemma has_field_derivative_eval_fls: assumes "z \ eball 0 (fls_conv_radius f) - {0}" @@ -1186,43 +1103,6 @@ shows "f has_fps_expansion fps_expansion f 0" using assms has_fps_expansion_fps_expansion analytic_at by fast -lemma deriv_shift_0: "deriv f z = deriv (f \ (\x. z + x)) 0" -proof - - have *: "(f \ (+) z has_field_derivative D) (at z')" - if "(f has_field_derivative D) (at (z + z'))" for D z z' and f :: "'a \ 'a" - proof - - have "(f \ (+) z has_field_derivative D * 1) (at z')" - by (rule DERIV_chain that derivative_eq_intros refl)+ auto - thus ?thesis by simp - qed - have "(\D. (f has_field_derivative D) (at z)) = (\ D. (f \ (+) z has_field_derivative D) (at 0))" - using *[of f _ z 0] *[of "f \ (+) z" _ "-z" z] by (intro ext iffI) (auto simp: o_def) - thus ?thesis - by (simp add: deriv_def) -qed - -lemma deriv_shift_0': "NO_MATCH 0 z \ deriv f z = deriv (f \ (\x. z + x)) 0" - by (rule deriv_shift_0) - -lemma higher_deriv_shift_0: "(deriv ^^ n) f z = (deriv ^^ n) (f \ (\x. z + x)) 0" -proof (induction n arbitrary: f) - case (Suc n) - have "(deriv ^^ Suc n) f z = (deriv ^^ n) (deriv f) z" - by (subst funpow_Suc_right) auto - also have "\ = (deriv ^^ n) (\x. deriv f (z + x)) 0" - by (subst Suc) (auto simp: o_def) - also have "\ = (deriv ^^ n) (\x. deriv (\xa. f (z + x + xa)) 0) 0" - by (subst deriv_shift_0) (auto simp: o_def) - also have "(\x. deriv (\xa. f (z + x + xa)) 0) = deriv (\x. f (z + x))" - by (rule ext) (simp add: deriv_shift_0' o_def add_ac) - also have "(deriv ^^ n) \ 0 = (deriv ^^ Suc n) (f \ (\x. z + x)) 0" - by (subst funpow_Suc_right) (auto simp: o_def) - finally show ?case . -qed auto - -lemma higher_deriv_shift_0': "NO_MATCH 0 z \ (deriv ^^ n) f z = (deriv ^^ n) (f \ (\x. z + x)) 0" - by (rule higher_deriv_shift_0) - lemma analytic_at_imp_has_fps_expansion: assumes "f analytic_on {z}" shows "(\x. f (z + x)) has_fps_expansion fps_expansion f z" @@ -1624,49 +1504,6 @@ by (simp add: field_simps) qed -lemma vector_derivative_translate [simp]: - "vector_derivative ((+) z \ g) (at x within A) = vector_derivative g (at x within A)" -proof - - have "(((+) z \ g) has_vector_derivative g') (at x within A)" - if "(g has_vector_derivative g') (at x within A)" for g :: "real \ 'a" and z g' - unfolding o_def using that by (auto intro!: derivative_eq_intros) - from this[of g _ z] this[of "\x. z + g x" _ "-z"] show ?thesis - unfolding vector_derivative_def - by (intro arg_cong[where f = Eps] ext) (auto simp: o_def algebra_simps) -qed - -lemma has_contour_integral_translate: - "(f has_contour_integral I) ((+) z \ g) \ ((\x. f (x + z)) has_contour_integral I) g" - by (simp add: has_contour_integral_def add_ac) - -lemma contour_integrable_translate: - "f contour_integrable_on ((+) z \ g) \ (\x. f (x + z)) contour_integrable_on g" - by (simp add: contour_integrable_on_def has_contour_integral_translate) - -lemma contour_integral_translate: - "contour_integral ((+) z \ g) f = contour_integral g (\x. f (x + z))" - by (simp add: contour_integral_def contour_integrable_translate has_contour_integral_translate) - -lemma residue_shift_0: "residue f z = residue (\x. f (z + x)) 0" -proof - - define Q where - "Q = (\r f z \. (f has_contour_integral complex_of_real (2 * pi) * \ * r) (circlepath z \))" - define P where - "P = (\r f z. \e>0. \\>0. \ < e \ Q r f z \)" - have path_eq: "circlepath (z - w) \ = (+) (-w) \ circlepath z \" for z w \ - by (simp add: circlepath_def o_def part_circlepath_def algebra_simps) - have *: "P r f z" if "P r (\x. f (x + w)) (z - w)" for r w f z - using that by (auto simp: P_def Q_def path_eq has_contour_integral_translate) - have "(SOME r. P r f z) = (SOME r. P r (\x. f (z + x)) 0)" - using *[of _ f z z] *[of _ "\x. f (z + x)" "-z"] - by (intro arg_cong[where f = Eps] ext iffI) (simp_all add: add_ac) - thus ?thesis - by (simp add: residue_def P_def Q_def) -qed - -lemma residue_shift_0': "NO_MATCH 0 z \ residue f z = residue (\x. f (z + x)) 0" - by (rule residue_shift_0) - lemma has_laurent_expansion_residue_0: assumes "f has_laurent_expansion F" shows "residue f 0 = fls_residue F" @@ -1768,9 +1605,6 @@ by (simp add: fls_conv_radius_altdef G_def) qed -lemma connected_eball [intro]: "connected (eball (z :: 'a :: real_normed_vector) r)" - by (cases r) auto - lemma eval_fls_eqI: assumes "f has_laurent_expansion F" "f holomorphic_on eball 0 r - {0}" assumes "z \ eball 0 r - {0}" @@ -1821,7 +1655,7 @@ lemma tendsto_0_subdegree_iff_0: assumes F:"f has_laurent_expansion F" and "F\0" - shows "(f \0\0) \ fls_subdegree F > 0" + shows "(f \0\ 0) \ fls_subdegree F > 0" proof - have ?thesis if "is_pole f 0" proof - @@ -1872,15 +1706,15 @@ qed lemma tendsto_0_subdegree_iff: - assumes F:"(\w. f (z+w)) has_laurent_expansion F" and "F\0" - shows "(f \z\0) \ fls_subdegree F > 0" + assumes F: "(\w. f (z+w)) has_laurent_expansion F" and "F \ 0" + shows "(f \z\ 0) \ fls_subdegree F > 0" apply (subst Lim_at_zero) apply (rule tendsto_0_subdegree_iff_0) using assms by auto lemma is_pole_0_deriv_divide_iff: - assumes F:"f has_laurent_expansion F" and "F\0" - shows "is_pole (\x. deriv f x / f x) 0 \ is_pole f 0 \ (f \0\0)" + assumes F: "f has_laurent_expansion F" and "F \ 0" + shows "is_pole (\x. deriv f x / f x) 0 \ is_pole f 0 \ (f \0\ 0)" proof - have "(\x. deriv f x / f x) has_laurent_expansion fls_deriv F / F" using F by (auto intro:laurent_expansion_intros) @@ -2396,43 +2230,6 @@ qed qed -lemma subdegree_fps_compose [simp]: - fixes F G :: "'a :: idom fps" - assumes [simp]: "fps_nth G 0 = 0" - shows "subdegree (fps_compose F G) = subdegree F * subdegree G" -proof (cases "G = 0"; cases "F = 0") - assume [simp]: "G \ 0" "F \ 0" - define m where "m = subdegree F" - define F' where "F' = fps_shift m F" - have F_eq: "F = F' * fps_X ^ m" - unfolding F'_def by (simp add: fps_shift_times_fps_X_power m_def) - have [simp]: "F' \ 0" - using \F \ 0\ unfolding F_eq by auto - have "subdegree (fps_compose F G) = subdegree (fps_compose F' G) + m * subdegree G" - by (simp add: F_eq fps_compose_mult_distrib fps_compose_eq_0_iff flip: fps_compose_power) - also have "subdegree (fps_compose F' G) = 0" - by (intro subdegree_eq_0) (auto simp: F'_def m_def) - finally show ?thesis by (simp add: m_def) -qed auto - -lemma fls_subdegree_power_int [simp]: - fixes F :: "'a :: field fls" - shows "fls_subdegree (F powi n) = n * fls_subdegree F" - by (auto simp: power_int_def fls_subdegree_pow) - -lemma subdegree_fls_compose_fps [simp]: - fixes G :: "'a :: field fps" - assumes [simp]: "fps_nth G 0 = 0" - shows "fls_subdegree (fls_compose_fps F G) = fls_subdegree F * subdegree G" -proof (cases "F = 0"; cases "G = 0") - assume [simp]: "G \ 0" "F \ 0" - have nz1: "fls_base_factor_to_fps F \ 0" - using \F \ 0\ fls_base_factor_to_fps_nonzero by blast - show ?thesis - unfolding fls_compose_fps_def using nz1 - by (subst fls_subdegree_mult) (simp_all add: fps_compose_eq_0_iff fls_subdegree_fls_to_fps) -qed (auto simp: fls_compose_fps_0_right) - lemma zorder_compose_aux: assumes "isolated_singularity_at f 0" "not_essential f 0" assumes G: "g has_fps_expansion G" "G \ 0" "g 0 = 0" diff -r 3704717ed7bf -r ff4b062aae57 src/HOL/Computational_Algebra/Formal_Laurent_Series.thy --- a/src/HOL/Computational_Algebra/Formal_Laurent_Series.thy Mon Apr 21 08:24:58 2025 +0200 +++ b/src/HOL/Computational_Algebra/Formal_Laurent_Series.thy Fri Apr 18 10:58:16 2025 +0200 @@ -1165,6 +1165,58 @@ shows "fls_const x * fls_const y = fls_const (x*y)" by (intro fls_eqI) simp +lemma fls_subdegree_add_eq1: + assumes "f \ 0" "fls_subdegree f < fls_subdegree g" + shows "fls_subdegree (f + g) = fls_subdegree f" +proof (intro antisym) + from assms have *: "fls_nth (f + g) (fls_subdegree f) \ 0" + by auto + from * show "fls_subdegree (f + g) \ fls_subdegree f" + by (rule fls_subdegree_leI) + from * have "f + g \ 0" + using fls_nonzeroI by blast + thus "fls_subdegree f \ fls_subdegree (f + g)" + using assms(2) fls_plus_subdegree by force +qed + +lemma fls_subdegree_add_eq2: + assumes "g \ 0" "fls_subdegree g < fls_subdegree f" + shows "fls_subdegree (f + g) = fls_subdegree g" +proof (intro antisym) + from assms have *: "fls_nth (f + g) (fls_subdegree g) \ 0" + by auto + from * show "fls_subdegree (f + g) \ fls_subdegree g" + by (rule fls_subdegree_leI) + from * have "f + g \ 0" + using fls_nonzeroI by blast + thus "fls_subdegree g \ fls_subdegree (f + g)" + using assms(2) fls_plus_subdegree by force +qed + +lemma fls_subdegree_diff_eq1: + assumes "f \ 0" "fls_subdegree f < fls_subdegree g" + shows "fls_subdegree (f - g) = fls_subdegree f" + using fls_subdegree_add_eq1[of f "-g"] assms by simp + +lemma fls_subdegree_diff_eq2: + assumes "g \ 0" "fls_subdegree g < fls_subdegree f" + shows "fls_subdegree (f - g) = fls_subdegree g" + using fls_subdegree_add_eq2[of "-g" f] assms by simp + +lemma nat_minus_fls_subdegree_plus_const_eq: + "nat (-fls_subdegree (F + fls_const c)) = nat (-fls_subdegree F)" +proof (cases "fls_subdegree F < 0") + case True + hence "fls_subdegree (F + fls_const c) = fls_subdegree F" + by (intro fls_subdegree_add_eq1) auto + thus ?thesis + by simp +next + case False + thus ?thesis + by (auto simp: fls_subdegree_ge0I) +qed + lemma fls_mult_subdegree_ge: fixes f g :: "'a::{comm_monoid_add,mult_zero} fls" assumes "f*g \ 0" @@ -1705,6 +1757,13 @@ by standard +lemma fls_subdegree_numeral [simp]: "fls_subdegree (numeral n) = 0" + by (metis fls_subdegree_of_nat of_nat_numeral) + +lemma fls_regpart_numeral [simp]: "fls_regpart (numeral n) = numeral n" + by (metis fls_regpart_of_nat of_nat_numeral) + + subsubsection \Powers\ lemma fls_subdegree_prod: @@ -2946,6 +3005,20 @@ instance fls :: ("{field_prime_char,comm_semiring_1}") field_prime_char by (rule field_prime_charI') auto +instance fls :: (semiring_char_0) semiring_char_0 +proof + show "inj (of_nat :: nat \ 'a fls)" + by (metis fls_regpart_of_nat injI of_nat_eq_iff) +qed + +instance fls :: (field_char_0) field_char_0 .. + + +lemma fls_subdegree_power_int [simp]: + fixes F :: "'a :: field fls" + shows "fls_subdegree (F powi n) = n * fls_subdegree F" + by (auto simp: power_int_def fls_subdegree_pow) + subsubsection \Division\ @@ -3440,45 +3513,6 @@ shows "fls_compose_fps (F - G) H = fls_compose_fps F H - fls_compose_fps G H" using fls_compose_fps_add[of H F "-G"] by simp -lemma fps_compose_eq_0_iff: - fixes F G :: "'a :: idom fps" - assumes "fps_nth G 0 = 0" - shows "fps_compose F G = 0 \ F = 0 \ (G = 0 \ fps_nth F 0 = 0)" -proof safe - assume *: "fps_compose F G = 0" "F \ 0" - have "fps_nth (fps_compose F G) 0 = fps_nth F 0" - by simp - also have "fps_compose F G = 0" - by (simp add: *) - finally show "fps_nth F 0 = 0" - by simp - show "G = 0" - proof (rule ccontr) - assume "G \ 0" - hence "subdegree G > 0" using assms - using subdegree_eq_0_iff by blast - define N where "N = subdegree F * subdegree G" - have "fps_nth (fps_compose F G) N = (\i = 0..N. fps_nth F i * fps_nth (G ^ i) N)" - unfolding fps_compose_def by (simp add: N_def) - also have "\ = (\i\{subdegree F}. fps_nth F i * fps_nth (G ^ i) N)" - proof (intro sum.mono_neutral_right ballI) - fix i assume i: "i \ {0..N} - {subdegree F}" - show "fps_nth F i * fps_nth (G ^ i) N = 0" - proof (cases i "subdegree F" rule: linorder_cases) - assume "i > subdegree F" - hence "fps_nth (G ^ i) N = 0" - using i \subdegree G > 0\ by (intro fps_pow_nth_below_subdegree) (auto simp: N_def) - thus ?thesis by simp - qed (use i in \auto simp: N_def\) - qed (use \subdegree G > 0\ in \auto simp: N_def\) - also have "\ = fps_nth F (subdegree F) * fps_nth (G ^ subdegree F) N" - by simp - also have "\ \ 0" - using \G \ 0\ \F \ 0\ by (auto simp: N_def) - finally show False using * by auto - qed -qed auto - lemma fls_compose_fps_eq_0_iff: assumes "H \ 0" "fps_nth H 0 = 0" shows "fls_compose_fps F H = 0 \ F = 0" @@ -3588,7 +3622,7 @@ assumes "d > 0" shows "fls_compose_power f d $$ n = (if int d dvd n then f $$ (n div int d) else 0)" by (simp add: assms fls_compose_power.rep_eq) - + lemma fls_compose_power_0_left [simp]: "fls_compose_power 0 d = 0" by transfer auto @@ -3680,6 +3714,20 @@ "d dvd n \ d > 0 \ fls_compose_power f d $$ int n = f $$ int (n div d)" by (transfer; force; fail)+ +lemma subdegree_fls_compose_fps [simp]: + fixes G :: "'a :: field fps" + assumes [simp]: "fps_nth G 0 = 0" + shows "fls_subdegree (fls_compose_fps F G) = fls_subdegree F * subdegree G" +proof (cases "F = 0"; cases "G = 0") + assume [simp]: "G \ 0" "F \ 0" + have nz1: "fls_base_factor_to_fps F \ 0" + using \F \ 0\ fls_base_factor_to_fps_nonzero by blast + show ?thesis + unfolding fls_compose_fps_def using nz1 + by (subst fls_subdegree_mult) (simp_all add: fps_compose_eq_0_iff fls_subdegree_fls_to_fps) +qed (auto simp: fls_compose_fps_0_right) + + subsection \Formal differentiation and integration\ subsubsection \Derivative\ @@ -3747,6 +3795,9 @@ shows "fls_subdegree (fls_deriv f) = fls_subdegree f - 1" by (auto intro: fls_subdegree_deriv' simp: assms) +lemma fps_deriv_fls_regpart: "fps_deriv (fls_regpart F) = fls_regpart (fls_deriv F)" + by (intro fps_ext) (auto simp: add_ac) + text \ Shifting is like multiplying by a power of the implied variable, and so satisfies a product-like rule. diff -r 3704717ed7bf -r ff4b062aae57 src/HOL/Computational_Algebra/Formal_Power_Series.thy --- a/src/HOL/Computational_Algebra/Formal_Power_Series.thy Mon Apr 21 08:24:58 2025 +0200 +++ b/src/HOL/Computational_Algebra/Formal_Power_Series.thy Fri Apr 18 10:58:16 2025 +0200 @@ -11,6 +11,7 @@ Complex_Main Euclidean_Algorithm Primes + "HOL-Library.FuncSet" begin @@ -748,6 +749,19 @@ from arg_cong[of _ _ "\F. F $ 0", OF this] show False by simp qed +instance fps :: (semiring_char_0) semiring_char_0 +proof + show "inj (of_nat :: nat \ 'a fps)" + proof + fix m n :: nat + assume "of_nat m = (of_nat n :: 'a fps)" + hence "fps_nth (of_nat m) 0 = (fps_nth (of_nat n) 0 :: 'a)" + by (simp only: ) + thus "m = n" + by simp + qed +qed + lemma subdegree_power_ge: "f^n \ 0 \ subdegree (f^n) \ n * subdegree f" proof (induct n) @@ -801,6 +815,12 @@ "subdegree ((f :: ('a :: semiring_1_no_zero_divisors) fps) ^ n) = n * subdegree f" by (cases "f = 0"; induction n) simp_all +lemma subdegree_prod: + fixes f :: "'a \ 'b :: idom fps" + assumes "\x. x \ A \ f x \ 0" + shows "subdegree (\x\A. f x) = (\x\A. subdegree (f x))" + using assms by (induction A rule: infinite_finite_induct) auto + lemma minus_one_power_iff: "(- (1::'a::ring_1)) ^ n = (if even n then 1 else - 1)" by (induct n) auto @@ -976,6 +996,25 @@ qed simp_all +subsection \Truncation\ + +text \ + Truncation of formal power series: all monomials $cx^k$ with $k\geq n$ are removed; + the remainder is a polynomial of degree at most $n-1$. +\ +definition truncate_fps :: "nat \ 'a fps \ 'a :: zero fps" where + "truncate_fps n F = Abs_fps (\k. if k \ n then 0 else fps_nth F k)" + +lemma fps_nth_truncate' [simp]: + "k \ n \ fps_nth (truncate_fps n F) k = 0" + "k < n \ fps_nth (truncate_fps n F) k = fps_nth F k" + by (auto simp: truncate_fps_def) + +lemma truncate_fps_eq_truncate_fps_iff: + "truncate_fps N F = truncate_fps N G \ (\nShifting and slicing\ definition fps_shift :: "nat \ 'a fps \ 'a fps" where @@ -1402,6 +1441,144 @@ lemma open_fps_def: "open (S :: 'a::group_add fps set) = (\a \ S. \r. r >0 \ {y. dist y a < r} \ S)" unfolding open_dist subset_eq by simp + +text \Topology\ + +subsection \The topology of formal power series\ + +text \ + A set of formal power series is open iff for any power series $f$ in it, there exists some + number $n$ such that all power series that agree with $f$ on the first $n$ components are + also in it. +\ +lemma open_fps_iff: + "open A \ (\F\A. \n. {G. truncate_fps n G = truncate_fps n F} \ A)" +proof + assume "open A" + show "\F\A. \n. {G. truncate_fps n G = truncate_fps n F} \ A" + proof + fix F :: "'a fps" + assume F: "F \ A" + with \open A\ obtain e where e: "e > 0" "\G. dist G F < e \ G \ A" + by (force simp: open_fps_def) + thm dist_fps_def + have "filterlim (\n. (1/2)^n :: real) (nhds 0) at_top" + by (intro LIMSEQ_realpow_zero) auto + from order_tendstoD(2)[OF this e(1)] have "eventually (\n. 1 / 2 ^ n < e) at_top" + by (simp add: power_divide) + then obtain n where n: "1 / 2 ^ n < e" + by (auto simp: eventually_sequentially) + show "\n. {G. truncate_fps n G = truncate_fps n F} \ A" + proof (rule exI[of _ n], safe) + fix G assume *: "truncate_fps n G = truncate_fps n F" + show "G \ A" + proof (cases "G = F") + case False + hence "dist G F = inverse (2 ^ subdegree (G - F))" + by (auto simp: dist_fps_def) + also have "subdegree (G - F) \ n" + proof (rule subdegree_geI) + fix i assume "i < n" + hence "fps_nth (G - F) i = fps_nth (truncate_fps n G - truncate_fps n F) i" + by (auto simp: fps_eq_iff) + also from * have "\ = 0" + by simp + finally show "fps_nth (G - F) i = 0" . + qed (use False in auto) + hence "inverse (2 ^ subdegree (G - F) :: real) \ inverse (2 ^ n)" + by (intro le_imp_inverse_le power_increasing) auto + also have "\ < e" + using n by (simp add: field_simps) + finally show "G \ A" + using e(2)[of G] by auto + qed (use \F \ A\ in auto) + qed + qed +next + assume *: "\F\A. \n. {G. truncate_fps n G = truncate_fps n F} \ A" + show "open A" + unfolding open_fps_def + proof safe + fix F assume F: "F \ A" + with * obtain n where n: "\G. truncate_fps n G = truncate_fps n F \ G \ A" + by blast + show "\r>0. {G. dist G F < r} \ A" + proof (rule exI[of _ "1 / 2 ^ n"], safe) + fix G assume dist: "dist G F < 1 / 2 ^ n" + show "G \ A" + proof (cases "G = F") + case False + hence "dist G F = inverse (2 ^ subdegree (F - G))" + by (simp add: dist_fps_def) + with dist have "n < subdegree (F - G)" + by (auto simp: field_simps) + hence "fps_nth (F - G) i = 0" if "i \ n" for i + using that nth_less_subdegree_zero[of i "F - G"] by simp + hence "truncate_fps n G = truncate_fps n F" + by (auto simp: fps_eq_iff truncate_fps_def) + thus "G \ A" + by (rule n) + qed (use \F \ A\ in auto) + qed auto + qed +qed + +lemma open_truncate_fps: "open {H. truncate_fps N H = truncate_fps N G}" + unfolding open_fps_iff +proof safe + fix F assume F: "truncate_fps N F = truncate_fps N G" + show "\n. {G. truncate_fps n G = truncate_fps n F} + \ {H. truncate_fps N H = truncate_fps N G}" + by (rule exI[of _ N]) (use F in \auto simp: fps_eq_iff\) +qed + +text \ + A family of formal power series $f_x$ tends to a limit series $g$ at some filter $F$ + iff for any $N\geq 0$, the set of $x$ for which $f_x$ and $G$ agree on the first $N$ coefficients + is in $F$. + + For a sequence $(f_i)_{n\geq 0}$ this means that $f_i \longrightarrow G$ iff for any + $N\geq 0$, $f_x$ and $G$ agree for all but finitely many $x$. +\ + +lemma tendsto_fps_iff: + "filterlim f (nhds (g :: 'a :: group_add fps)) F \ + (\n. eventually (\x. fps_nth (f x) n = fps_nth g n) F)" +proof safe + assume lim: "filterlim f (nhds (g :: 'a :: group_add fps)) F" + show "eventually (\x. fps_nth (f x) n = fps_nth g n) F" for n + proof - + define S where "S = {H. truncate_fps (n+1) H = truncate_fps (n+1) g}" + have S: "open S" "g \ S" + unfolding S_def using open_truncate_fps[of "n+1" g] by (auto simp: S_def) + from lim and S have "eventually (\x. f x \ S) F" + using topological_tendstoD by blast + thus "eventually (\x. fps_nth (f x) n = fps_nth g n) F" + by eventually_elim (auto simp: S_def truncate_fps_eq_truncate_fps_iff) + qed +next + assume *: "\n. eventually (\x. fps_nth (f x) n = fps_nth g n) F" + show "filterlim f (nhds (g :: 'a :: group_add fps)) F" + proof (rule topological_tendstoI) + fix S :: "'a fps set" + assume S: "open S" "g \ S" + then obtain N where N: "{H. truncate_fps N H = truncate_fps N g} \ S" + unfolding open_fps_iff by blast + have "eventually (\x. \n\{..x. f x \ {H. truncate_fps N H = truncate_fps N g}) F" + by eventually_elim (auto simp: truncate_fps_eq_truncate_fps_iff) + thus "eventually (\x. f x \ S) F" + by eventually_elim (use N in auto) + qed +qed + +lemma tendsto_fpsI: + assumes "\n. eventually (\x. fps_nth (f x) n = fps_nth G n) F" + shows "filterlim f (nhds (G :: 'a :: group_add fps)) F" + unfolding tendsto_fps_iff using assms by blast + + text \The infinite sums and justification of the notation in textbooks.\ lemma reals_power_lt_ex: @@ -3447,6 +3624,333 @@ by (simp add: fps_deriv_power' fps_of_nat) +subsection \Finite and infinite products\ + +text \ + The following operator gives the set of all functions $A \to \mathbb{N}$ with + $\sum_{x\in A} f(x) = n$, i.e.\ all the different ways to put $n$ unlabelled balls into + the labelled bins $A$. +\ +definition nat_partitions :: "'a set \ nat \ ('a \ nat) set" where + "nat_partitions A n = + {f. finite {x. f x > 0} \ {x. f x > 0} \ A \ (\x\{x\A. f x > 0}. f x) = n}" + +lemma + assumes "h \ nat_partitions A n" + shows nat_partitions_outside: "x \ A \ h x = 0" + and nat_partitions_sum: "(\x\{x\A. h x > 0}. h x) = n" + and nat_partitions_finite_support: "finite {x. h x > 0}" + using assms by (auto simp: nat_partitions_def) + +lemma nat_partitions_finite_def: + assumes "finite A" + shows "nat_partitions A n = {f. {x. f x > 0} \ A \ (\x\A. f x) = n}" +proof (intro equalityI subsetI) + fix f assume f: "f \ nat_partitions A n" + have "(\x\A. f x) = (\x | x \ A \ f x > 0. f x)" + by (rule sum.mono_neutral_right) (use assms in auto) + thus "f \ {f. {x. f x > 0} \ A \ (\x\A. f x) = n}" + using f nat_partitions_def by auto +next + fix f assume "f \ {f. {x. f x > 0} \ A \ (\x\A. f x) = n}" + hence f: "{x. f x > 0} \ A" "(\x\A. f x) = n" + by blast+ + have "(\x\A. f x) = (\x | x \ A \ f x > 0. f x)" + by (rule sum.mono_neutral_right) (use assms in auto) + moreover have "finite {x. f x > 0}" + using f(1) assms by (rule finite_subset) + ultimately show "f \ nat_partitions A n" + using f by (simp add: nat_partitions_def) +qed + +lemma nat_partitions_subset: + "nat_partitions A n \ A \ {0..n}" +proof + fix f assume f: "f \ nat_partitions A n" + have "f x \ n" if x: "x \ A" for x + proof (cases "f x = 0") + case False + have "f x \ (\x\{x\A. f x \ 0}. f x)" + by (rule member_le_sum) (use x False f in \auto simp: nat_partitions_def\) + also have "\ = n" + using f by (auto simp: nat_partitions_def) + finally show "f x \ n" . + qed auto + thus "f \ A \ {0..n}" + using f by (auto simp: nat_partitions_def) +qed + +lemma conj_mono_strong: "(P1 \ Q1) \ (P1 \ P2 \ Q2) \ (P1 \ P2) \ (Q1 \ Q2)" + by iprover + +lemma nat_partitions_mono: + assumes "A \ B" + shows "nat_partitions A n \ nat_partitions B n" + unfolding nat_partitions_def +proof (intro Collect_mono conj_mono_strong impI) + fix f :: "'a \ nat" + assume 1: "finite {x. f x > 0}" + assume 2: "{x. f x > 0} \ A" + thus "{x. f x > 0} \ B" + using assms by blast + assume 3: "(\x | x \ A \ f x > 0. f x) = n" + have *: "{x\B. f x > 0} = {x\A. f x > 0} \ {x\B-A. f x > 0}" + using assms by auto + have "(\x | x \ B \ f x > 0. f x) = (\x | x \ A \ f x > 0. f x)" + by (intro sum.mono_neutral_right) (use assms 2 in \auto intro: finite_subset[OF _ 1]\) + with 3 show "(\x | x \ B \ f x > 0. f x) = n" + by simp +qed + +lemma in_nat_partitions_imp_le: + assumes "h \ nat_partitions A n" "x \ A" + shows "h x \ n" + using nat_partitions_subset[of A n] assms by (auto simp: PiE_def Pi_def) + +lemma nat_partitions_0 [simp]: "nat_partitions A 0 = {\_. 0}" +proof (intro equalityI subsetI) + fix h :: "'a \ nat" assume "h \ {\_. 0}" + thus "h \ nat_partitions A 0" + by (auto simp: nat_partitions_def) +qed (auto simp: nat_partitions_def fun_eq_iff) + +lemma nat_partitions_empty [simp]: "n > 0 \ nat_partitions {} n = {}" + by (auto simp: nat_partitions_def fun_eq_iff) + +lemma nat_partitions_insert: + assumes [simp]: "a \ A" + shows "bij_betw (\(m,f). f(a := m)) + (SIGMA m:{0..n}. nat_partitions A (n - m)) (nat_partitions (insert a A) n)" +proof (rule bij_betwI[of _ _ _ "\f. (f a, f(a := 0))"], goal_cases) + case 1 + show ?case + proof safe + fix m f assume m: "m \ {0..n}" and f: "f \ nat_partitions A (n - m)" + define f' where "f' = f(a := m)" + have "(\x\{x\insert a A. f' x > 0}. f' x) = (\x\insert a {x\A. f x > 0}. f' x)" + by (rule sum.mono_neutral_cong_left) + (use f in \auto simp: f'_def nat_partitions_def\) + also have "\ = m + (\x\{x\A. f x > 0}. f' x)" + by (subst sum.insert) (use f in \auto simp: nat_partitions_def f'_def\) + also have "(\x\{x\A. f x > 0}. f' x) = (\x\{x\A. f x > 0}. f x)" + by (intro sum.cong) (auto simp: f'_def) + also have "\ = n - m" + using f by (auto simp: nat_partitions_def) + finally have "(\x\{x\insert a A. f' x > 0}. f' x) = n" + using m by simp + moreover have "finite {x. f' x > 0}" + by (rule finite_subset[of _ "insert a {x\A. f x > 0}"]) + (use f in \auto simp: nat_partitions_def f'_def\) + moreover have "{x. f' x > 0} \ insert a A" + using f by (auto simp: f'_def nat_partitions_def) + ultimately show "f' \ nat_partitions (insert a A) n" + by (simp add: nat_partitions_def) + qed +next + case 2 + show ?case + proof safe + fix f assume "f \ nat_partitions (insert a A) n" + define f' where "f' = f(a := 0)" + have fin: "finite {x. f x > 0}" + and subset: "{x. f x > 0} \ insert a A" + and sum: "(\x\{x\insert a A. f x > 0}. f x) = n" + using \f \ _\ by (auto simp: nat_partitions_def) + + show le: "f a \ {0..n}" + proof (cases "f a = 0") + case False + hence "f a \ (\x\{x\insert a A. f x > 0}. f x)" + by (intro member_le_sum) (use fin in auto) + with sum show ?thesis + by simp + qed auto + + have "n = (\x\{x\insert a A. f x > 0}. f x)" + using sum by simp + also have "(\x\{x\insert a A. f x > 0}. f x) = (\x\insert a {x\A. f x > 0}. f x)" + by (rule sum.mono_neutral_left) (auto intro: finite_subset[OF _ fin]) + also have "\ = f a + (\x\{x\A. f x > 0}. f x)" + by (subst sum.insert) (auto intro: finite_subset[OF _ fin]) + also have "(\x\{x\A. f x > 0}. f x) = (\x\{x\A. f' x > 0}. f' x)" + by (intro sum.cong) (auto simp: f'_def) + finally have "(\x\{x\A. f' x > 0}. f' x) = n - f a" + using le by simp + + moreover have "finite {x. 0 < f' x}" + by (rule finite_subset[OF _ fin]) (auto simp: f'_def) + moreover have "{x. 0 < f' x} \ A" + using subset by (auto simp: f'_def) + ultimately show "f' \ nat_partitions A (n - f a)" + by (auto simp: nat_partitions_def) + qed +next + case (3 f) + thus ?case + by (fastforce simp: nat_partitions_def fun_eq_iff) +qed (auto simp: nat_partitions_def) + +lemma finite_nat_partitions [intro]: + assumes "finite A" + shows "finite (nat_partitions A n)" + using assms +proof (induction arbitrary: n rule: finite_induct) + case empty + thus ?case + by (cases "n = 0") auto +next + case (insert x A n) + have "finite (SIGMA m:{0..n}. nat_partitions A (n - m))" + by (auto intro: insert.IH) + also have "?this \ finite (nat_partitions (insert x A) n)" + by (rule bij_betw_finite, rule nat_partitions_insert) fact + finally show ?case . +qed + +lemma fps_prod_nth': + assumes "finite A" + shows "fps_nth (\x\A. f x) n = (\h\nat_partitions A n. \x\A. fps_nth (f x) (h x))" + using assms +proof (induction A arbitrary: n rule: finite_induct) + case (insert a A n) + note [simp] = \a \ A\ + note [intro, simp] = \finite A\ + have "(\h\nat_partitions (insert a A) n. \x\insert a A. fps_nth (f x) (h x)) = + (\(m,h)\(SIGMA m:{0..n}. nat_partitions A (n-m)). \x\insert a A. fps_nth (f x) ((h(a := m)) x))" + by (subst sum.reindex_bij_betw[OF nat_partitions_insert, symmetric]) + (simp_all add: case_prod_unfold) + also have "\ = (\m=0..n. \h\nat_partitions A (n-m). \x\insert a A. fps_nth (f x) ((h(a := m)) x))" + by (rule sum.Sigma [symmetric]) auto + also have "\ = (\m=0..n. fps_nth (f a) m * fps_nth (\x\A. f x) (n - m))" + proof (rule sum.cong) + fix m + assume m: "m \ {0..n}" + have "(\h\nat_partitions A (n-m). \x\insert a A. fps_nth (f x) ((h(a := m)) x)) = + fps_nth (f a) m * (\h\nat_partitions A (n-m). \x\A. fps_nth (f x) ((h(a := m)) x))" + by (simp add: sum_distrib_left) + also have "(\h\nat_partitions A (n-m). \x\A. fps_nth (f x) ((h(a := m)) x)) = + (\h\nat_partitions A (n-m). \x\A. fps_nth (f x) (h x))" + by (intro sum.cong prod.cong) auto + also have "\ = fps_nth (\x\A. f x) (n - m)" + by (rule insert.IH [symmetric]) + finally show "(\h\nat_partitions A (n-m). \x\insert a A. fps_nth (f x) ((h(a := m)) x)) = + fps_nth (f a) m * fps_nth (\x\A. f x) (n - m)" . + qed auto + also have "\ = fps_nth (\x\insert a A. f x) n" + by (simp add: fps_mult_nth) + finally show ?case .. +qed auto + +theorem tendsto_prod_fps: + fixes f :: "nat \ 'a :: {idom, t2_space} fps" + assumes [simp]: "\k. f k \ 0" + assumes g: "\n k. k > g n \ subdegree (f k - 1) > n" + defines "P \ Abs_fps (\n. (\h\nat_partitions {..g n} n. \i\g n. fps_nth (f i) (h i)))" + shows "(\n. \k\n. f k) \ P" +proof (rule tendsto_fpsI) + fix n :: nat + show "eventually (\N. fps_nth (prod f {..N}) n = fps_nth P n) at_top" + using eventually_ge_at_top[of "g n"] + proof eventually_elim + case (elim N) + have "fps_nth (prod f {..N}) n = (\h\nat_partitions {..N} n. \x\N. fps_nth (f x) (h x))" + by (subst fps_prod_nth') auto + also have "\ = (\h | h \ nat_partitions {..N} n \ (\x\N. fps_nth (f x) (h x) \ 0). + \x\N. fps_nth (f x) (h x))" + by (intro sum.mono_neutral_right) auto + + also have "{h. h \ nat_partitions {..N} n \ (\x\N. fps_nth (f x) (h x) \ 0)} = + {h. h \ nat_partitions {..g n} n \ (\x\N. fps_nth (f x) (h x) \ 0)}" (is "?lhs = ?rhs") + proof (intro equalityI subsetI) + fix h assume "h \ ?rhs" + thus "h \ ?lhs" using elim nat_partitions_mono[of "{..g n}" "{..N}"] by auto + next + fix h assume "h \ ?lhs" + hence h: "{x. 0 < h x} \ {..N}" "(\x\N. h x) = n" "\x. x \ N \ fps_nth (f x) (h x) \ 0" + by (auto simp: nat_partitions_finite_def) + have "{x. 0 < h x} \ {..g n}" + proof + fix x assume *: "x \ {x. h x > 0}" + show "x \ {..g n}" + proof (rule ccontr) + assume "x \ {..g n}" + hence x: "x > g n" "x \ N" + using h(1) * by auto + have "h x \ n" + using \h \ ?lhs\ nat_partitions_subset[of "{..N}" n] x by (auto simp: Pi_def) + also have "n < subdegree (f x - 1)" + by (rule g) (use x in auto) + finally have "fps_nth (f x - 1) (h x) = 0" + by blast + hence "fps_nth (f x) (h x) = 0" + using * by simp + moreover have "fps_nth (f x) (h x) \ 0" + by (intro h(3)) (use x in auto) + ultimately show False by contradiction + qed + qed + moreover from this have "(\x\N. h x) = (\x\g n. h x)" + by (intro sum.mono_neutral_right) (use elim in auto) + ultimately show "h \ ?rhs" using elim h + by (auto simp: nat_partitions_finite_def) + qed + + also have "(\h | h \ nat_partitions {..g n} n \ (\x\N. fps_nth (f x) (h x) \ 0). + \x\N. fps_nth (f x) (h x)) = + (\h | h \ nat_partitions {..g n} n \ (\x\N. fps_nth (f x) (h x) \ 0). + \i\g n. fps_nth (f i) (h i))" + proof (intro sum.cong prod.mono_neutral_right ballI) + fix h i + assume i: "i \ {..N} - {..g n}" + assume "h \ {h. h \ nat_partitions {..g n} n \ (\x\N. fps_nth (f x) (h x) \ 0)}" + hence h: "h \ nat_partitions {..g n} n" "\x. x \ N \ fps_nth (f x) (h x) \ 0" + by blast+ + have [simp]: "h i = 0" + using i h unfolding nat_partitions_def by auto + have "n < subdegree (f i - 1)" + by (intro g) (use i in auto) + moreover have "h i \ n" + by auto + ultimately have "fps_nth (f i - 1) (h i) = 0" + by (intro nth_less_subdegree_zero) auto + thus "fps_nth (f i) (h i) = 1" + using h(2) i by (auto split: if_splits) + qed (use elim in auto) + + also have "(\h | h \ nat_partitions {..g n} n \ (\x\N. fps_nth (f x) (h x) \ 0). + \i\g n. fps_nth (f i) (h i)) = + (\h \ nat_partitions {..g n} n. \i\g n. fps_nth (f i) (h i))" + proof (intro sum.mono_neutral_left ballI) + fix h assume "h \ nat_partitions {..g n} n - {h\nat_partitions {..g n} n. \x\N. fps_nth (f x) (h x) \ 0}" + then obtain i where h: "h \ nat_partitions {..g n} n" and i: "i \ N" "fps_nth (f i) (h i) = 0" + by blast + have "\(i > g n)" + proof + assume i': "i > g n" + hence "h i = 0" + using h by (auto simp: nat_partitions_def) + have "subdegree (f i - 1) > n" + by (intro g) (use i' in auto) + hence "subdegree (f i - 1) > 0" + by simp + hence "fps_nth (f i - 1) 0 = 0" + by blast + hence "fps_nth (f i) (h i) = 1" + using \h i = 0\ by simp + thus False using i by simp + qed + thus " (\x\g n. fps_nth (f x) (h x)) = 0" + using i by auto + qed auto + + also have "\ = fps_nth P n" + by (simp add: P_def) + finally show "fps_nth (\k\N. f k) n = fps_nth P n" . + qed +qed + + + subsection \Integration\ definition fps_integral :: "'a::{semiring_1,inverse} fps \ 'a \ 'a fps" @@ -4911,6 +5415,64 @@ lemma fps_X_fps_compose: "fps_X oo a = Abs_fps (\n. if n = 0 then (0::'a::comm_ring_1) else a$n)" by (simp add: fps_eq_iff fps_compose_nth mult_delta_left) +lemma fps_compose_eq_0_iff: + fixes F G :: "'a :: idom fps" + assumes "fps_nth G 0 = 0" + shows "fps_compose F G = 0 \ F = 0 \ (G = 0 \ fps_nth F 0 = 0)" +proof safe + assume *: "fps_compose F G = 0" "F \ 0" + have "fps_nth (fps_compose F G) 0 = fps_nth F 0" + by simp + also have "fps_compose F G = 0" + by (simp add: *) + finally show "fps_nth F 0 = 0" + by simp + show "G = 0" + proof (rule ccontr) + assume "G \ 0" + hence "subdegree G > 0" using assms + using subdegree_eq_0_iff by blast + define N where "N = subdegree F * subdegree G" + have "fps_nth (fps_compose F G) N = (\i = 0..N. fps_nth F i * fps_nth (G ^ i) N)" + unfolding fps_compose_def by (simp add: N_def) + also have "\ = (\i\{subdegree F}. fps_nth F i * fps_nth (G ^ i) N)" + proof (intro sum.mono_neutral_right ballI) + fix i assume i: "i \ {0..N} - {subdegree F}" + show "fps_nth F i * fps_nth (G ^ i) N = 0" + proof (cases i "subdegree F" rule: linorder_cases) + assume "i > subdegree F" + hence "fps_nth (G ^ i) N = 0" + using i \subdegree G > 0\ by (intro fps_pow_nth_below_subdegree) (auto simp: N_def) + thus ?thesis by simp + qed (use i in \auto simp: N_def\) + qed (use \subdegree G > 0\ in \auto simp: N_def\) + also have "\ = fps_nth F (subdegree F) * fps_nth (G ^ subdegree F) N" + by simp + also have "\ \ 0" + using \G \ 0\ \F \ 0\ by (auto simp: N_def) + finally show False using * by auto + qed +qed auto + +lemma subdegree_fps_compose [simp]: + fixes F G :: "'a :: idom fps" + assumes [simp]: "fps_nth G 0 = 0" + shows "subdegree (fps_compose F G) = subdegree F * subdegree G" +proof (cases "G = 0"; cases "F = 0") + assume [simp]: "G \ 0" "F \ 0" + define m where "m = subdegree F" + define F' where "F' = fps_shift m F" + have F_eq: "F = F' * fps_X ^ m" + unfolding F'_def by (simp add: fps_shift_times_fps_X_power m_def) + have [simp]: "F' \ 0" + using \F \ 0\ unfolding F_eq by auto + have "subdegree (fps_compose F G) = subdegree (fps_compose F' G) + m * subdegree G" + by (simp add: F_eq fps_compose_mult_distrib fps_compose_eq_0_iff flip: fps_compose_power) + also have "subdegree (fps_compose F' G) = 0" + by (intro subdegree_eq_0) (auto simp: F'_def m_def) + finally show ?thesis by (simp add: m_def) +qed auto + lemma fps_inverse_compose: assumes b0: "(b$0 :: 'a::field) = 0" and a0: "a$0 \ 0" diff -r 3704717ed7bf -r ff4b062aae57 src/HOL/Groups_Big.thy --- a/src/HOL/Groups_Big.thy Mon Apr 21 08:24:58 2025 +0200 +++ b/src/HOL/Groups_Big.thy Fri Apr 18 10:58:16 2025 +0200 @@ -1792,4 +1792,74 @@ finally show ?case . qed +lemma prod_add: + fixes f1 f2 :: "'a \ 'c :: comm_semiring_1" + assumes finite: "finite A" + shows "(\x\A. f1 x + f2 x) = (\X\Pow A. (\x\X. f1 x) * (\x\A-X. f2 x))" + using assms +proof (induction A rule: finite_induct) + case (insert x A) + have "(\X\Pow (insert x A). (\x\X. f1 x) * (\x\insert x A-X. f2 x)) = + (\X\Pow A. (\x\X. f1 x) * (\x\insert x A-X. f2 x)) + + (\X\insert x ` (Pow A). (\x\X. f1 x) * (\x\insert x A-X. f2 x))" + unfolding Pow_insert by (rule sum.union_disjoint) (use insert.hyps in auto) + also have "(\X\Pow A. (\x\X. f1 x) * (\x\insert x A-X. f2 x)) = + (\X\Pow A. f2 x * (\x\X. f1 x) * (\x\A-X. f2 x))" + proof (rule sum.cong) + fix X assume X: "X \ Pow A" + have "(\x\X. f1 x) * (\x\insert x (A-X). f2 x) = f2 x * (\x\X. f1 x) * (\x\A-X. f2 x)" + by (subst prod.insert) (use insert.hyps finite_subset[of X A] X in \auto simp: mult_ac\) + also have "insert x (A - X) = insert x A - X" + using insert.hyps X by auto + finally show "(\x\X. f1 x) * (\x\insert x A-X. f2 x) = f2 x * (\x\X. f1 x) * (\x\A-X. f2 x)" . + qed auto + also have "(\X\insert x ` (Pow A). (\x\X. f1 x) * (\x\insert x A-X. f2 x)) = + (\X\Pow A. (\x\insert x X. f1 x) * (\x\insert x A-insert x X. f2 x))" + by (subst sum.reindex) (use insert.hyps in \auto intro!: inj_onI simp: o_def\) + also have "(\X\Pow A. (\x\insert x X. f1 x) * (\x\insert x A-insert x X. f2 x)) = + (\X\Pow A. f1 x * (\x\X. f1 x) * (\x\A-X. f2 x))" + proof (rule sum.cong) + fix X assume X: "X \ Pow A" + show "(\x\insert x X. f1 x) * (\x\insert x A-insert x X. f2 x) = + f1 x * (\x\X. f1 x) * (\x\A-X. f2 x)" + by (subst prod.insert) (use insert.hyps finite_subset[of X A] X in auto) + qed auto + also have "(\X\Pow A. f2 x * prod f1 X * prod f2 (A - X)) + + (\X\Pow A. f1 x * prod f1 X * prod f2 (A - X)) = + (f1 x + f2 x) * (\X\Pow A. prod f1 X * prod f2 (A - X))" + by (simp add: algebra_simps flip: sum_distrib_left sum_distrib_right) + finally show ?case + by (subst (asm) insert.IH [symmetric]) (use insert.hyps in simp) +qed auto + +lemma prod_diff1: + fixes f1 f2 :: "'a \ 'c :: comm_ring_1" + assumes finite: "finite A" + shows "(\x\A. f1 x - f2 x) = (\X\Pow A. (-1) ^ card X * (\x\X. f2 x) * (\x\A-X. f1 x))" +proof - + have "(\x\A. f1 x - f2 x) = (\x\A. -f2 x + f1 x)" + by simp + also have "\ = (\X\Pow A. (\x\X. - f2 x) * prod f1 (A - X))" + by (rule prod_add) fact+ + also have "\ = (\X\Pow A. (-1) ^ card X * (\x\X. f2 x) * prod f1 (A - X))" + by (simp add: prod_uminus) + finally show ?thesis . +qed + +lemma prod_diff2: + fixes f1 f2 :: "'a \ 'c :: comm_ring_1" + assumes finite: "finite A" + shows "(\x\A. f1 x - f2 x) = (\X\Pow A. (-1) ^ (card A - card X) * (\x\X. f1 x) * (\x\A-X. f2 x))" +proof - + have "(\x\A. f1 x - f2 x) = (\x\A. f1 x + (-f2 x))" + by simp + also have "\ = (\X\Pow A. (\x\X. f1 x) * (\x\A-X. -f2 x))" + by (rule prod_add) fact+ + also have "\ = (\X\Pow A. (-1) ^ card (A - X) * (\x\X. f1 x) * (\x\A-X. f2 x))" + by (simp add: prod_uminus mult_ac) + also have "\ = (\X\Pow A. (-1) ^ (card A - card X) * (\x\X. f1 x) * (\x\A-X. f2 x))" + using finite_subset[OF _ assms] by (intro sum.cong refl, subst card_Diff_subset) auto + finally show ?thesis . +qed + end diff -r 3704717ed7bf -r ff4b062aae57 src/HOL/Library/FuncSet.thy --- a/src/HOL/Library/FuncSet.thy Mon Apr 21 08:24:58 2025 +0200 +++ b/src/HOL/Library/FuncSet.thy Fri Apr 18 10:58:16 2025 +0200 @@ -810,4 +810,37 @@ by blast qed +subsection \Products of sums\ + +lemma prod_sum_PiE: + fixes f :: "'a \ 'b \ 'c :: comm_semiring_1" + assumes finite: "finite A" and finite: "\x. x \ A \ finite (B x)" + shows "(\x\A. \y\B x. f x y) = (\g\PiE A B. \x\A. f x (g x))" + using assms +proof (induction A rule: finite_induct) + case empty + thus ?case by auto +next + case (insert x A) + have "(\g\Pi\<^sub>E (insert x A) B. \x\insert x A. f x (g x)) = + (\g\Pi\<^sub>E (insert x A) B. f x (g x) * (\x'\A. f x' (g x')))" + using insert by simp + also have "(\g. \x'\A. f x' (g x')) = (\g. \x'\A. f x' (if x' = x then undefined else g x'))" + using insert by (intro ext prod.cong) auto + also have "(\g\Pi\<^sub>E (insert x A) B. f x (g x) * \ g) = + (\(y,g)\B x \ Pi\<^sub>E A B. f x y * (\x'\A. f x' (g x')))" + using insert.prems insert.hyps + by (intro sum.reindex_bij_witness[of _ "\(y,g). g(x := y)" "\g. (g x, g(x := undefined))"]) + (auto simp: PiE_def extensional_def) + also have "\ = (\y\B x. \g\Pi\<^sub>E A B. f x y * (\x'\A. f x' (g x')))" + by (subst sum.cartesian_product) auto + also have "\ = (\y\B x. f x y) * (\g\Pi\<^sub>E A B. \x'\A. f x' (g x'))" + using insert by (subst sum.swap) (simp add: sum_distrib_left sum_distrib_right) + also have "(\g\Pi\<^sub>E A B. \x'\A. f x' (g x')) = (\x\A. \y\B x. f x y)" + using insert.prems by (intro insert.IH [symmetric]) auto + also have "(\y\B x. f x y) * \ = (\x\insert x A. \y\B x. f x y)" + using insert.hyps by simp + finally show ?case .. +qed + end