# HG changeset patch # User Manuel Eberl # Date 1711736939 -3600 # Node ID 4c1347e172b1c6f0d3c1d40adb4c2ec33f944f1b # Parent f82639fe786e5a811af6d5e94e54bc6556f774fb moved over material from AFP; most importantly on algebraic numbers and algebraically closed fields diff -r f82639fe786e -r 4c1347e172b1 src/HOL/Computational_Algebra/Formal_Laurent_Series.thy --- a/src/HOL/Computational_Algebra/Formal_Laurent_Series.thy Sat Mar 30 01:12:48 2024 +0100 +++ b/src/HOL/Computational_Algebra/Formal_Laurent_Series.thy Fri Mar 29 19:28:59 2024 +0100 @@ -79,7 +79,7 @@ qed -subsubsection \Definition of basic zero, one, constant, X, and inverse X elements\ +subsubsection \Definition of basic Laurent series\ instantiation fls :: (zero) zero begin @@ -2008,14 +2008,13 @@ subsubsection \Inverses\ -\ \See lemma fls_left_inverse\ + abbreviation fls_left_inverse :: "'a::{comm_monoid_add,uminus,times} fls \ 'a \ 'a fls" where "fls_left_inverse f x \ fls_shift (fls_subdegree f) (fps_to_fls (fps_left_inverse (fls_base_factor_to_fps f) x))" -\ \See lemma fls_right_inverse\ abbreviation fls_right_inverse :: "'a::{comm_monoid_add,uminus,times} fls \ 'a \ 'a fls" where @@ -2605,7 +2604,7 @@ lemma fls_left_inverse_idempotent_ring1: fixes f :: "'a::ring_1 fls" assumes "x * f $$ fls_subdegree f = 1" "y * x = 1" - \ \These assumptions imply y equals f $$ fls_subdegree f, but no need to assume that.\ + \ \These assumptions imply y equals \f $$ fls_subdegree f\, but no need to assume that.\ shows "fls_left_inverse (fls_left_inverse f x) y = f" proof- from assms(1) have @@ -2630,7 +2629,7 @@ lemma fls_right_inverse_idempotent_ring1: fixes f :: "'a::ring_1 fls" assumes "f $$ fls_subdegree f * x = 1" "x * y = 1" - \ \These assumptions imply y equals f $$ fls_subdegree f, but no need to assume that.\ + \ \These assumptions imply y equals \f $$ fls_subdegree f\, but no need to assume that.\ shows "fls_right_inverse (fls_right_inverse f x) y = f" proof- from assms(1) have @@ -3645,7 +3644,7 @@ subsection \Formal differentiation and integration\ -subsubsection \Derivative definition and basic properties\ +subsubsection \Derivative\ definition "fls_deriv f = Abs_fls (\n. of_int (n+1) * f$$(n+1))" @@ -3802,7 +3801,7 @@ qed -subsubsection \Algebra rules of the derivative\ +subsubsection \Algebraic rules of the derivative\ lemma fls_deriv_add [simp]: "fls_deriv (f+g) = fls_deriv f + fls_deriv g" by (auto intro: fls_eqI simp: algebra_simps) @@ -4155,7 +4154,6 @@ subsubsection \Integral definition and basic properties\ -\ \To incorporate a constant of integration, just add an fps_const.\ definition fls_integral :: "'a::{ring_1,inverse} fls \ 'a fls" where "fls_integral a = Abs_fls (\n. if n=0 then 0 else inverse (of_int n) * a$$(n - 1))" @@ -4371,7 +4369,7 @@ qed -subsubsection \Algebra rules of the integral\ +subsubsection \Algebraic rules of the integral\ lemma fls_integral_add [simp]: "fls_integral (f+g) = fls_integral f + fls_integral g" by (intro fls_eqI) (simp add: algebra_simps) @@ -4580,7 +4578,7 @@ unfolding open_dist subset_eq by simp -subsection \Notation bundle\ +subsection \Notation\ no_notation fls_nth (infixl "$$" 75) diff -r f82639fe786e -r 4c1347e172b1 src/HOL/Computational_Algebra/Formal_Power_Series.thy --- a/src/HOL/Computational_Algebra/Formal_Power_Series.thy Sat Mar 30 01:12:48 2024 +0100 +++ b/src/HOL/Computational_Algebra/Formal_Power_Series.thy Fri Mar 29 19:28:59 2024 +0100 @@ -44,7 +44,7 @@ lemma fps_zero_nth [simp]: "0 $ n = 0" unfolding fps_zero_def by simp -lemma fps_nonzero_nth: "f \ 0 \ (\ n. f $n \ 0)" +lemma fps_nonzero_nth: "f \ 0 \ (\ n. f $ n \ 0)" by (simp add: expand_fps_eq) lemma fps_nonzero_nth_minimal: "f \ 0 \ (\n. f $ n \ 0 \ (\m < n. f $ m = 0))" @@ -412,8 +412,7 @@ by (auto simp: fps_mult_nth_conv_inside_subdegrees) -subsection \Formal power series form a commutative ring with unity, if the range of sequences - they represent is a commutative ring with unity\ +subsection \Ring structure\ instance fps :: (semigroup_add) semigroup_add proof @@ -539,8 +538,6 @@ instance fps :: (semiring_1_cancel) semiring_1_cancel .. -subsection \Selection of the nth power of the implicit variable in the infinite sum\ - lemma fps_square_nth: "(f^2) $ n = (\k\n. f $ k * f $ (n - k))" by (simp add: power2_eq_square fps_mult_nth atLeast0AtMost) @@ -554,8 +551,6 @@ qed -subsection \Injection of the basic ring elements and multiplication by scalars\ - definition "fps_const c = Abs_fps (\n. if n = 0 then c else 0)" lemma fps_nth_fps_const [simp]: "fps_const c $ n = (if n = 0 then c else 0)" @@ -619,8 +614,6 @@ by (induct n) auto -subsection \Formal power series form an integral domain\ - instance fps :: (ring) ring .. instance fps :: (comm_ring) comm_ring .. @@ -791,8 +784,6 @@ by (cases "f = 0"; induction n) simp_all -subsection \The efps_Xtractor series fps_X\ - lemma minus_one_power_iff: "(- (1::'a::ring_1)) ^ n = (if even n then 1 else - 1)" by (induct n) auto @@ -1324,7 +1315,7 @@ thus ?thesis by (simp add: fps_mult_nth) qed -subsection \Formal Power series form a metric space\ +subsection \Metrizability\ instantiation fps :: ("{minus,zero}") dist begin @@ -1472,7 +1463,7 @@ qed -subsection \Inverses and division of formal power series\ +subsection \Division\ declare sum.cong[fundef_cong] @@ -1483,7 +1474,7 @@ | "fps_left_inverse_constructor f a (Suc n) = - sum (\i. fps_left_inverse_constructor f a i * f$(Suc n - i)) {0..n} * a" -\ \This will construct a left inverse for f in case that x * f$0 = 1\ +\ \This will construct a left inverse for f in case that \<^prop>\x * f$0 = 1\\ abbreviation "fps_left_inverse \ (\f x. Abs_fps (fps_left_inverse_constructor f x))" fun fps_right_inverse_constructor :: @@ -1493,7 +1484,7 @@ | "fps_right_inverse_constructor f a n = - a * sum (\i. f$i * fps_right_inverse_constructor f a (n - i)) {1..n}" -\ \This will construct a right inverse for f in case that f$0 * y = 1\ +\ \This will construct a right inverse for f in case that \<^prop>\f$0 * y = 1\\ abbreviation "fps_right_inverse \ (\f y. Abs_fps (fps_right_inverse_constructor f y))" instantiation fps :: ("{comm_monoid_add,inverse,times,uminus}") inverse @@ -1721,14 +1712,14 @@ qed (simp add: f0 fps_inverse_def) qed -\ \ +text \ It is possible in a ring for an element to have a left inverse but not a right inverse, or vice versa. But when an element has both, they must be the same. \ lemma fps_left_inverse_eq_fps_right_inverse: fixes f :: "'a::ring_1 fps" assumes f0: "x * f$0 = 1" "f $ 0 * y = 1" - \ \These assumptions imply x equals y, but no need to assume that.\ + \ \These assumptions imply that $x$ equals $y$, but no need to assume that.\ shows "fps_left_inverse f x = fps_right_inverse f y" proof- from f0(2) have "f * fps_right_inverse f y = 1" @@ -1751,7 +1742,7 @@ lemma fps_left_inverse': fixes f :: "'a::ring_1 fps" assumes "x * f$0 = 1" "f$0 * y = 1" - \ \These assumptions imply x equals y, but no need to assume that.\ + \ \These assumptions imply $x$ equals $y$, but no need to assume that.\ shows "fps_right_inverse f y * f = 1" using assms fps_left_inverse_eq_fps_right_inverse[of x f y] fps_left_inverse[of x f] by simp @@ -1759,7 +1750,7 @@ lemma fps_right_inverse': fixes f :: "'a::ring_1 fps" assumes "x * f$0 = 1" "f$0 * y = 1" - \ \These assumptions imply x equals y, but no need to assume that.\ + \ \These assumptions imply $x$ equals $y$, but no need to assume that.\ shows "f * fps_left_inverse f x = 1" using assms fps_left_inverse_eq_fps_right_inverse[of x f y] fps_right_inverse[of f y] by simp @@ -1808,7 +1799,7 @@ lemma fps_left_inverse_idempotent_ring1: fixes f :: "'a::ring_1 fps" assumes "x * f$0 = 1" "y * x = 1" - \ \These assumptions imply y equals f$0, but no need to assume that.\ + \ \These assumptions imply $y$ equals \f$0\, but no need to assume that.\ shows "fps_left_inverse (fps_left_inverse f x) y = f" proof- from assms(1) have @@ -1831,7 +1822,7 @@ lemma fps_right_inverse_idempotent_ring1: fixes f :: "'a::ring_1 fps" assumes "f$0 * x = 1" "x * y = 1" - \ \These assumptions imply y equals f$0, but no need to assume that.\ + \ \These assumptions imply $y$ equals \f$0\, but no need to assume that.\ shows "fps_right_inverse (fps_right_inverse f x) y = f" proof- from assms(1) have "f * (fps_right_inverse f x * fps_right_inverse (fps_right_inverse f x) y) = @@ -2854,7 +2845,7 @@ end -subsection \Formal power series form a Euclidean ring\ +subsection \Euclidean division\ instantiation fps :: (field) euclidean_ring_cancel begin @@ -2994,7 +2985,7 @@ -subsection \Formal Derivatives, and the MacLaurin theorem around 0\ +subsection \Formal Derivatives\ definition "fps_deriv f = Abs_fps (\n. of_nat (n + 1) * f $ (n + 1))" @@ -3196,7 +3187,7 @@ lemma fps_deriv_lr_inverse: fixes x y :: "'a::ring_1" assumes "x * f$0 = 1" "f$0 * y = 1" - \ \These assumptions imply x equals y, but no need to assume that.\ + \ \These assumptions imply $x$ equals $y$, but no need to assume that.\ shows "fps_deriv (fps_left_inverse f x) = - fps_left_inverse f x * fps_deriv f * fps_left_inverse f x" and "fps_deriv (fps_right_inverse f y) = @@ -3622,7 +3613,7 @@ qed -subsection \Composition of FPSs\ +subsection \Composition\ definition fps_compose :: "'a::semiring_1 fps \ 'a fps \ 'a fps" (infixl "oo" 55) where "a oo b = Abs_fps (\n. sum (\i. a$i * (b^i$n)) {0..n})" @@ -3722,10 +3713,10 @@ subsubsection \Rule 3\ -text \Rule 3 is trivial and is given by \fps_times_def\.\ - - -subsubsection \Rule 5 --- summation and "division" by (1 - fps_X)\ +text \Rule 3 is trivial and is given by \texttt{fps\_times\_def}.\ + + +subsubsection \Rule 5 --- summation and ``division'' by $1 - X$\ lemma fps_divide_fps_X_minus1_sum_lemma: "a = ((1::'a::ring_1 fps) - fps_X) * Abs_fps (\n. sum (\i. a $ i) {0..n})" @@ -3759,8 +3750,10 @@ using fps_divide_fps_X_minus1_sum_ring1[of a] by simp -subsubsection \Rule 4 in its more general form: generalizes Rule 3 for an arbitrary - finite product of FPS, also the relvant instance of powers of a FPS\ +subsubsection \Rule 4 in its more general form\ + +text \This generalizes Rule 3 for an arbitrary + finite product of FPS, also the relevant instance of powers of a FPS.\ definition "natpermute n k = {l :: nat list. length l = k \ sum_list l = n}" @@ -4619,7 +4612,7 @@ by (simp add: divide_inverse fps_divide_def) -subsection \Derivative of composition\ +subsection \Chain rule\ lemma fps_compose_deriv: fixes a :: "'a::idom fps" @@ -4658,9 +4651,6 @@ then show ?thesis by (simp add: fps_eq_iff) qed - -subsection \Finite FPS (i.e. polynomials) and fps_X\ - lemma fps_poly_sum_fps_X: assumes "\i > n. a$i = 0" shows "a = sum (\i. fps_const (a$i) * fps_X^i) {0..n}" (is "a = ?r") @@ -5742,7 +5732,7 @@ qed -subsubsection \Formal trigonometric functions\ +subsubsection \Trigonometric functions\ definition "fps_sin (c::'a::field_char_0) = Abs_fps (\n. if even n then 0 else (- 1) ^((n - 1) div 2) * c^n /(of_nat (fact n)))" diff -r f82639fe786e -r 4c1347e172b1 src/HOL/Computational_Algebra/Fraction_Field.thy --- a/src/HOL/Computational_Algebra/Fraction_Field.thy Sat Mar 30 01:12:48 2024 +0100 +++ b/src/HOL/Computational_Algebra/Fraction_Field.thy Fri Mar 29 19:28:59 2024 +0100 @@ -2,8 +2,7 @@ Author: Amine Chaieb, University of Cambridge *) -section\A formalization of the fraction field of any integral domain; - generalization of theory Rat from int to any integral domain\ +section\The fraction field of any integral domain\ theory Fraction_Field imports Main diff -r f82639fe786e -r 4c1347e172b1 src/HOL/Computational_Algebra/Fundamental_Theorem_Algebra.thy --- a/src/HOL/Computational_Algebra/Fundamental_Theorem_Algebra.thy Sat Mar 30 01:12:48 2024 +0100 +++ b/src/HOL/Computational_Algebra/Fundamental_Theorem_Algebra.thy Fri Mar 29 19:28:59 2024 +0100 @@ -518,7 +518,7 @@ text \Fundamental theorem of algebra\ -lemma fundamental_theorem_of_algebra: +theorem fundamental_theorem_of_algebra: assumes nc: "\ constant (poly p)" shows "\z::complex. poly p z = 0" using nc @@ -779,6 +779,92 @@ by (metis degree_eq_zeroE pcompose_const poly_0 poly_pcompose that) qed +lemma complex_poly_decompose: + "smult (lead_coeff p) (\z|poly p z = 0. [:-z, 1:] ^ order z p) = (p :: complex poly)" +proof (induction p rule: poly_root_order_induct) + case (no_roots p) + show ?case + proof (cases "degree p = 0") + case False + hence "\constant (poly p)" by (subst constant_degree) + with fundamental_theorem_of_algebra and no_roots show ?thesis by blast + qed (auto elim!: degree_eq_zeroE) +next + case (root p x n) + from root have *: "{z. poly ([:- x, 1:] ^ n * p) z = 0} = insert x {z. poly p z = 0}" + by auto + have "smult (lead_coeff ([:-x, 1:] ^ n * p)) + (\z|poly ([:-x,1:] ^ n * p) z = 0. [:-z, 1:] ^ order z ([:- x, 1:] ^ n * p)) = + [:- x, 1:] ^ order x ([:- x, 1:] ^ n * p) * + smult (lead_coeff p) (\z\{z. poly p z = 0}. [:- z, 1:] ^ order z ([:- x, 1:] ^ n * p))" + by (subst *, subst prod.insert) + (insert root, auto intro: poly_roots_finite simp: mult_ac lead_coeff_mult lead_coeff_power) + also have "order x ([:- x, 1:] ^ n * p) = n" + using root by (subst order_mult) (auto simp: order_power_n_n order_0I) + also have "(\z\{z. poly p z = 0}. [:- z, 1:] ^ order z ([:- x, 1:] ^ n * p)) = + (\z\{z. poly p z = 0}. [:- z, 1:] ^ order z p)" + proof (intro prod.cong refl, goal_cases) + case (1 y) + with root have "order y ([:-x,1:] ^ n) = 0" by (intro order_0I) auto + thus ?case using root by (subst order_mult) auto + qed + also note root.IH + finally show ?case . +qed simp_all + +instance complex :: alg_closed_field + by standard (use fundamental_theorem_of_algebra constant_degree neq0_conv in blast) + +lemma size_proots_complex: "size (proots (p :: complex poly)) = degree p" +proof (cases "p = 0") + case [simp]: False + show "size (proots p) = degree p" + by (subst (1 2) complex_poly_decompose [symmetric]) + (simp add: proots_prod proots_power degree_prod_sum_eq degree_power_eq) +qed auto + +lemma complex_poly_decompose_multiset: + "smult (lead_coeff p) (\x\#proots p. [:-x, 1:]) = (p :: complex poly)" +proof (cases "p = 0") + case False + hence "(\x\#proots p. [:-x, 1:]) = (\x | poly p x = 0. [:-x, 1:] ^ order x p)" + by (subst image_prod_mset_multiplicity) simp_all + also have "smult (lead_coeff p) \ = p" + by (rule complex_poly_decompose) + finally show ?thesis . +qed auto + +lemma complex_poly_decompose': + obtains root where "smult (lead_coeff p) (\ix\#proots p. [:-x, 1:])" + by (rule complex_poly_decompose_multiset [symmetric]) + also have "(\x\#proots p. [:-x, 1:]) = (\x\roots. [:-x, 1:])" + by (subst prod_mset_prod_list [symmetric]) (simp add: roots) + also have "\ = (\iii. roots ! i"]) auto +qed + +lemma complex_poly_decompose_rsquarefree: + assumes "rsquarefree p" + shows "smult (lead_coeff p) (\z|poly p z = 0. [:-z, 1:]) = (p :: complex poly)" +proof (cases "p = 0") + case False + have "(\z|poly p z = 0. [:-z, 1:]) = (\z|poly p z = 0. [:-z, 1:] ^ order z p)" + using assms False by (intro prod.cong) (auto simp: rsquarefree_root_order) + also have "smult (lead_coeff p) \ = p" + by (rule complex_poly_decompose) + finally show ?thesis . +qed auto + + text \Arithmetic operations on multivariate polynomials.\ lemma mpoly_base_conv: diff -r f82639fe786e -r 4c1347e172b1 src/HOL/Computational_Algebra/Polynomial.thy --- a/src/HOL/Computational_Algebra/Polynomial.thy Sat Mar 30 01:12:48 2024 +0100 +++ b/src/HOL/Computational_Algebra/Polynomial.thy Fri Mar 29 19:28:59 2024 +0100 @@ -80,12 +80,41 @@ lemma MOST_coeff_eq_0: "\\<^sub>\ n. coeff p n = 0" using coeff [of p] by simp +lemma coeff_Abs_poly: + assumes "\i. i > n \ f i = 0" + shows "coeff (Abs_poly f) = f" +proof (rule Abs_poly_inverse, clarify) + have "eventually (\i. i > n) cofinite" + by (auto simp: MOST_nat) + thus "eventually (\i. f i = 0) cofinite" + by eventually_elim (use assms in auto) +qed + subsection \Degree of a polynomial\ definition degree :: "'a::zero poly \ nat" where "degree p = (LEAST n. \i>n. coeff p i = 0)" +lemma degree_cong: + assumes "\i. coeff p i = 0 \ coeff q i = 0" + shows "degree p = degree q" +proof - + have "(\n. \i>n. poly.coeff p i = 0) = (\n. \i>n. poly.coeff q i = 0)" + using assms by (auto simp: fun_eq_iff) + thus ?thesis + by (simp only: degree_def) +qed + +lemma coeff_Abs_poly_If_le: + "coeff (Abs_poly (\i. if i \ n then f i else 0)) = (\i. if i \ n then f i else 0)" +proof (rule Abs_poly_inverse, clarify) + have "eventually (\i. i > n) cofinite" + by (auto simp: MOST_nat) + thus "eventually (\i. (if i \ n then f i else 0) = 0) cofinite" + by eventually_elim auto +qed + lemma coeff_eq_0: assumes "degree p < n" shows "coeff p n = 0" @@ -156,6 +185,23 @@ lemma leading_coeff_0_iff [simp]: "coeff p (degree p) = 0 \ p = 0" by (cases "p = 0") (simp_all add: leading_coeff_neq_0) +lemma degree_lessI: + assumes "p \ 0 \ n > 0" "\k\n. coeff p k = 0" + shows "degree p < n" +proof (cases "p = 0") + case False + show ?thesis + proof (rule ccontr) + assume *: "\(degree p < n)" + define d where "d = degree p" + from \p \ 0\ have "coeff p d \ 0" + by (auto simp: d_def) + moreover have "coeff p d = 0" + using assms(2) * by (auto simp: not_less) + ultimately show False by contradiction + qed +qed (use assms in auto) + lemma eq_zero_or_degree_less: assumes "degree p \ n" and "coeff p n = 0" shows "p = 0 \ degree p < n" @@ -192,6 +238,9 @@ lemmas coeff_pCons = pCons.rep_eq +lemma coeff_pCons': "poly.coeff (pCons c p) n = (if n = 0 then c else poly.coeff p (n - 1))" + by transfer'(auto split: nat.splits) + lemma coeff_pCons_0 [simp]: "coeff (pCons a p) 0 = a" by transfer simp @@ -811,6 +860,12 @@ lemma poly_sum: "poly (\k\A. p k) x = (\k\A. poly (p k) x)" by (induct A rule: infinite_finite_induct) simp_all +lemma poly_sum_list: "poly (\p\ps. p) y = (\p\ps. poly p y)" + by (induction ps) auto + +lemma poly_sum_mset: "poly (\x\#A. p x) y = (\x\#A. poly (p x) y)" + by (induction A) auto + lemma degree_sum_le: "finite S \ (\p. p \ S \ degree (f p) \ n) \ degree (sum f S) \ n" proof (induct S rule: finite_induct) case empty @@ -823,6 +878,11 @@ unfolding sum.insert[OF insert(1-2)] by (metis degree_add_le) qed +lemma degree_sum_less: + assumes "\x. x \ A \ degree (f x) < n" "n > 0" + shows "degree (sum f A) < n" + using assms by (induction rule: infinite_finite_induct) (auto intro!: degree_add_less) + lemma poly_as_sum_of_monoms': assumes "degree p \ n" shows "(\i\n. monom (coeff p i) i) = p" @@ -1013,6 +1073,9 @@ by (cases n) (simp_all add: sum.atMost_Suc_shift del: sum.atMost_Suc) qed +lemma coeff_mult_0: "coeff (p * q) 0 = coeff p 0 * coeff q 0" + by (simp add: coeff_mult) + lemma degree_mult_le: "degree (p * q) \ degree p + degree q" proof (rule degree_le) show "\i>degree p + degree q. coeff (p * q) i = 0" @@ -1084,6 +1147,9 @@ instance poly :: (comm_ring_1) comm_ring_1 .. instance poly :: (comm_ring_1) comm_semiring_1_cancel .. +lemma prod_smult: "(\x\A. smult (c x) (p x)) = smult (prod c A) (prod p A)" + by (induction A rule: infinite_finite_induct) (auto simp: mult_ac) + lemma degree_power_le: "degree (p ^ n) \ degree p * n" by (induct n) (auto intro: order_trans degree_mult_le) @@ -1103,6 +1169,18 @@ lemma poly_prod: "poly (\k\A. p k) x = (\k\A. poly (p k) x)" by (induct A rule: infinite_finite_induct) simp_all +lemma poly_prod_list: "poly (\p\ps. p) y = (\p\ps. poly p y)" + by (induction ps) auto + +lemma poly_prod_mset: "poly (\x\#A. p x) y = (\x\#A. poly (p x) y)" + by (induction A) auto + +lemma poly_const_pow: "[: c :] ^ n = [: c ^ n :]" + by (induction n) (auto simp: algebra_simps) + +lemma monom_power: "monom c n ^ k = monom (c ^ k) (n * k)" + by (induction k) (auto simp: mult_monom) + lemma degree_prod_sum_le: "finite S \ degree (prod f S) \ sum (degree \ f) S" proof (induct S rule: finite_induct) case empty @@ -1261,6 +1339,43 @@ lemma smult_conv_map_poly: "smult c p = map_poly (\x. c * x) p" by (intro poly_eqI) (simp_all add: coeff_map_poly) +lemma poly_cnj: "cnj (poly p z) = poly (map_poly cnj p) (cnj z)" + by (simp add: poly_altdef degree_map_poly coeff_map_poly) + +lemma poly_cnj_real: + assumes "\n. poly.coeff p n \ \" + shows "cnj (poly p z) = poly p (cnj z)" +proof - + from assms have "map_poly cnj p = p" + by (intro poly_eqI) (auto simp: coeff_map_poly Reals_cnj_iff) + with poly_cnj[of p z] show ?thesis by simp +qed + +lemma real_poly_cnj_root_iff: + assumes "\n. poly.coeff p n \ \" + shows "poly p (cnj z) = 0 \ poly p z = 0" +proof - + have "poly p (cnj z) = cnj (poly p z)" + by (simp add: poly_cnj_real assms) + also have "\ = 0 \ poly p z = 0" by simp + finally show ?thesis . +qed + +lemma sum_to_poly: "(\x\A. [:f x:]) = [:\x\A. f x:]" + by (induction A rule: infinite_finite_induct) auto + +lemma diff_to_poly: "[:c:] - [:d:] = [:c - d:]" + by (simp add: poly_eq_iff mult_ac) + +lemma mult_to_poly: "[:c:] * [:d:] = [:c * d:]" + by (simp add: poly_eq_iff mult_ac) + +lemma prod_to_poly: "(\x\A. [:f x:]) = [:\x\A. f x:]" + by (induction A rule: infinite_finite_induct) (auto simp: mult_to_poly mult_ac) + +lemma poly_map_poly_cnj [simp]: "poly (map_poly cnj p) x = cnj (poly p (cnj x))" + by (induction p) (auto simp: map_poly_pCons) + subsection \Conversions\ @@ -1327,6 +1442,21 @@ "lead_coeff (numeral n) = numeral n" by (simp add: numeral_poly) +lemma coeff_linear_poly_power: + fixes c :: "'a :: semiring_1" + assumes "i \ n" + shows "coeff ([:a, b:] ^ n) i = of_nat (n choose i) * b ^ i * a ^ (n - i)" +proof - + have "[:a, b:] = monom b 1 + [:a:]" + by (simp add: monom_altdef) + also have "coeff (\ ^ n) i = (\k\n. a^(n-k) * of_nat (n choose k) * (if k = i then b ^ k else 0))" + by (subst binomial_ring) (simp add: coeff_sum of_nat_poly monom_power poly_const_pow mult_ac) + also have "\ = (\k\{i}. a ^ (n - i) * b ^ i * of_nat (n choose k))" + using assms by (intro sum.mono_neutral_cong_right) (auto simp: mult_ac) + finally show *: ?thesis by (simp add: mult_ac) +qed + + subsection \Lemmas about divisibility\ @@ -1407,6 +1537,11 @@ for p q :: "'a::{comm_semiring_0,semiring_no_zero_divisors} poly" by (rule order_antisym [OF degree_mult_le le_degree]) (simp add: coeff_mult_degree_sum) +lemma degree_prod_sum_eq: + "(\x. x \ A \ f x \ 0) \ + degree (prod f A :: 'a :: idom poly) = (\x\A. degree (f x))" + by (induction A rule: infinite_finite_induct) (auto simp: degree_mult_eq) + lemma dvd_imp_degree: \degree x \ degree y\ if \x dvd y\ \x \ 0\ \y \ 0\ for x y :: \'a::{comm_semiring_1,semiring_no_zero_divisors} poly\ @@ -1733,6 +1868,56 @@ for p :: "'a::{ring_char_0,comm_ring_1,ring_no_zero_divisors} poly" by (auto simp add: poly_eq_poly_eq_iff [symmetric]) +lemma card_poly_roots_bound: + fixes p :: "'a::{comm_ring_1,ring_no_zero_divisors} poly" + assumes "p \ 0" + shows "card {x. poly p x = 0} \ degree p" +using assms +proof (induction "degree p" arbitrary: p rule: less_induct) + case (less p) + show ?case + proof (cases "\x. poly p x = 0") + case False + hence "{x. poly p x = 0} = {}" by blast + thus ?thesis by simp + next + case True + then obtain x where x: "poly p x = 0" by blast + hence "[:-x, 1:] dvd p" by (subst (asm) poly_eq_0_iff_dvd) + then obtain q where q: "p = [:-x, 1:] * q" by (auto simp: dvd_def) + with \p \ 0\ have [simp]: "q \ 0" by auto + have deg: "degree p = Suc (degree q)" + by (subst q, subst degree_mult_eq) auto + have "card {x. poly p x = 0} \ card (insert x {x. poly q x = 0})" + by (intro card_mono) (auto intro: poly_roots_finite simp: q) + also have "\ \ Suc (card {x. poly q x = 0})" + by (rule card_insert_le_m1) auto + also from deg have "card {x. poly q x = 0} \ degree q" + using \p \ 0\ and q by (intro less) auto + also have "Suc \ = degree p" by (simp add: deg) + finally show ?thesis by - simp_all + qed +qed + +lemma poly_eqI_degree: + fixes p q :: "'a :: {comm_ring_1, ring_no_zero_divisors} poly" + assumes "\x. x \ A \ poly p x = poly q x" + assumes "card A > degree p" "card A > degree q" + shows "p = q" +proof (rule ccontr) + assume neq: "p \ q" + have "degree (p - q) \ max (degree p) (degree q)" + by (rule degree_diff_le_max) + also from assms have "\ < card A" by linarith + also have "\ \ card {x. poly (p - q) x = 0}" + using neq and assms by (intro card_mono poly_roots_finite) auto + finally have "degree (p - q) < card {x. poly (p - q) x = 0}" . + moreover have "degree (p - q) \ card {x. poly (p - q) x = 0}" + using neq by (intro card_poly_roots_bound) auto + ultimately show False by linarith +qed + + subsubsection \Order of polynomial roots\ @@ -1927,6 +2112,134 @@ lemma monom_1_dvd_iff: "p \ 0 \ monom 1 n dvd p \ n \ order 0 p" using order_divides[of 0 n p] by (simp add: monom_altdef) +lemma poly_root_order_induct [case_names 0 no_roots root]: + fixes p :: "'a :: idom poly" + assumes "P 0" "\p. (\x. poly p x \ 0) \ P p" + "\p x n. n > 0 \ poly p x \ 0 \ P p \ P ([:-x, 1:] ^ n * p)" + shows "P p" +proof (induction "degree p" arbitrary: p rule: less_induct) + case (less p) + consider "p = 0" | "p \ 0" "\x. poly p x = 0" | "\x. poly p x \ 0" by blast + thus ?case + proof cases + case 3 + with assms(2)[of p] show ?thesis by simp + next + case 2 + then obtain x where x: "poly p x = 0" by auto + have "[:-x, 1:] ^ order x p dvd p" by (intro order_1) + then obtain q where q: "p = [:-x, 1:] ^ order x p * q" by (auto simp: dvd_def) + with 2 have [simp]: "q \ 0" by auto + have order_pos: "order x p > 0" + using \p \ 0\ and x by (auto simp: order_root) + have "order x p = order x p + order x q" + by (subst q, subst order_mult) (auto simp: order_power_n_n) + hence [simp]: "order x q = 0" by simp + have deg: "degree p = order x p + degree q" + by (subst q, subst degree_mult_eq) (auto simp: degree_power_eq) + with order_pos have "degree q < degree p" by simp + hence "P q" by (rule less) + with order_pos have "P ([:-x, 1:] ^ order x p * q)" + by (intro assms(3)) (auto simp: order_root) + with q show ?thesis by simp + qed (simp_all add: assms(1)) +qed + + +context + includes multiset.lifting +begin + +lift_definition proots :: "('a :: idom) poly \ 'a multiset" is + "\(p :: 'a poly) (x :: 'a). if p = 0 then 0 else order x p" +proof - + fix p :: "'a poly" + show "finite {x. 0 < (if p = 0 then 0 else order x p)}" + by (cases "p = 0") + (auto simp: order_gt_0_iff intro: finite_subset[OF _ poly_roots_finite[of p]]) +qed + +lemma proots_0 [simp]: "proots (0 :: 'a :: idom poly) = {#}" + by transfer' auto + +lemma proots_1 [simp]: "proots (1 :: 'a :: idom poly) = {#}" + by transfer' auto + +lemma proots_const [simp]: "proots [: x :] = 0" + by transfer' (auto split: if_splits simp: fun_eq_iff order_eq_0_iff) + +lemma proots_numeral [simp]: "proots (numeral n) = 0" + by (simp add: numeral_poly) + +lemma count_proots [simp]: + "p \ 0 \ count (proots p) a = order a p" + by transfer' auto + +lemma set_count_proots [simp]: + "p \ 0 \ set_mset (proots p) = {x. poly p x = 0}" + by (auto simp: set_mset_def order_gt_0_iff) + +lemma proots_uminus [simp]: "proots (-p) = proots p" + by (cases "p = 0"; rule multiset_eqI) auto + +lemma proots_smult [simp]: "c \ 0 \ proots (smult c p) = proots p" + by (cases "p = 0"; rule multiset_eqI) (auto simp: order_smult) + +lemma proots_mult: + assumes "p \ 0" "q \ 0" + shows "proots (p * q) = proots p + proots q" + using assms by (intro multiset_eqI) (auto simp: order_mult) + +lemma proots_prod: + assumes "\x. x \ A \ f x \ 0" + shows "proots (\x\A. f x) = (\x\A. proots (f x))" + using assms by (induction A rule: infinite_finite_induct) (auto simp: proots_mult) + +lemma proots_prod_mset: + assumes "0 \# A" + shows "proots (\p\#A. p) = (\p\#A. proots p)" + using assms by (induction A) (auto simp: proots_mult) + +lemma proots_prod_list: + assumes "0 \ set ps" + shows "proots (\p\ps. p) = (\p\ps. proots p)" + using assms by (induction ps) (auto simp: proots_mult prod_list_zero_iff) + +lemma proots_power: "proots (p ^ n) = repeat_mset n (proots p)" +proof (cases "p = 0") + case False + thus ?thesis + by (induction n) (auto simp: proots_mult) +qed (auto simp: power_0_left) + +lemma proots_linear_factor [simp]: "proots [:x, 1:] = {#-x#}" +proof - + have "order (-x) [:x, 1:] > 0" + by (subst order_gt_0_iff) auto + moreover have "order (-x) [:x, 1:] \ degree [:x, 1:]" + by (rule order_degree) auto + moreover have "order y [:x, 1:] = 0" if "y \ -x" for y + by (rule order_0I) (use that in \auto simp: add_eq_0_iff\) + ultimately show ?thesis + by (intro multiset_eqI) auto +qed + +lemma size_proots_le: "size (proots p) \ degree p" +proof (induction p rule: poly_root_order_induct) + case (no_roots p) + hence "proots p = 0" + by (simp add: multiset_eqI order_root) + thus ?case by simp +next + case (root p x n) + have [simp]: "p \ 0" + using root.hyps by auto + from root.IH show ?case + by (auto simp: proots_mult proots_power degree_mult_eq degree_power_eq) +qed auto + +end + subsection \Additional induction rules on polynomials\ @@ -2015,6 +2328,13 @@ lemma pcompose_pCons: "pcompose (pCons a p) q = [:a:] + q * pcompose p q" by (cases "p = 0 \ a = 0") (auto simp add: pcompose_def) +lemma pcompose_altdef: "pcompose p q = poly (map_poly (\x. [:x:]) p) q" + by (induction p) (simp_all add: map_poly_pCons pcompose_pCons) + +lemma coeff_pcompose_0 [simp]: + "coeff (pcompose p q) 0 = poly p (coeff q 0)" + by (induction p) (simp_all add: coeff_mult_0 pcompose_pCons) + lemma pcompose_1: "pcompose 1 p = 1" for p :: "'a::comm_semiring_1 poly" by (auto simp: one_pCons pcompose_pCons) @@ -2155,6 +2475,16 @@ by simp qed +lemma pcompose_eq_0_iff: + fixes p q :: "'a::{comm_semiring_0,semiring_no_zero_divisors} poly" + assumes "degree q > 0" + shows "pcompose p q = 0 \ p = 0" + using pcompose_eq_0[OF _ assms] by auto + +lemma coeff_pcompose_linear: + "coeff (pcompose p [:0, a :: 'a :: comm_semiring_1:]) i = a ^ i * coeff p i" + by (induction p arbitrary: i) (auto simp: pcompose_pCons coeff_pCons mult_ac split: nat.splits) + lemma lead_coeff_comp: fixes p q :: "'a::{comm_semiring_1,semiring_no_zero_divisors} poly" assumes "degree q > 0" @@ -2439,6 +2769,9 @@ lemma degree_reflect_poly_eq [simp]: "coeff p 0 \ 0 \ degree (reflect_poly p) = degree p" by (cases p rule: pCons_cases) (simp add: reflect_poly_pCons degree_eq_length_coeffs) +lemma reflect_poly_eq_0_iff [simp]: "reflect_poly p = 0 \ p = 0" + using coeff_0_reflect_poly_0_iff by fastforce + (* TODO: does this work with zero divisors as well? Probably not. *) lemma reflect_poly_mult: "reflect_poly (p * q) = reflect_poly p * reflect_poly q" for p q :: "'a::{comm_semiring_0,semiring_no_zero_divisors} poly" @@ -2672,6 +3005,15 @@ by (simp add: pderiv_mult smult_add_left algebra_simps) qed auto +lemma pderiv_power: + "pderiv (p ^ n) = smult (of_nat n) (p ^ (n - 1) * pderiv p)" + by (cases n) (simp_all add: pderiv_power_Suc del: power_Suc) + +lemma pderiv_monom: + "pderiv (monom c n) = monom (of_nat n * c) (n - 1)" + by (cases n) + (simp_all add: monom_altdef pderiv_power_Suc pderiv_smult pderiv_pCons mult_ac del: power_Suc) + lemma pderiv_pcompose: "pderiv (pcompose p q) = pcompose (pderiv p) q * pderiv q" by (induction p rule: pCons_induct) (auto simp: pcompose_pCons pderiv_add pderiv_mult pderiv_pCons pcompose_add algebra_simps) @@ -2695,6 +3037,51 @@ by (auto simp add: ac_simps intro!: sum.cong) qed auto +lemma coeff_higher_pderiv: + "coeff ((pderiv ^^ m) f) n = pochhammer (of_nat (Suc n)) m * coeff f (n + m)" + by (induction m arbitrary: n) (simp_all add: coeff_pderiv pochhammer_rec algebra_simps) + +lemma higher_pderiv_0 [simp]: "(pderiv ^^ n) 0 = 0" + by (induction n) simp_all + +lemma higher_pderiv_add: "(pderiv ^^ n) (p + q) = (pderiv ^^ n) p + (pderiv ^^ n) q" + by (induction n arbitrary: p q) (simp_all del: funpow.simps add: funpow_Suc_right pderiv_add) + +lemma higher_pderiv_smult: "(pderiv ^^ n) (smult c p) = smult c ((pderiv ^^ n) p)" + by (induction n arbitrary: p) (simp_all del: funpow.simps add: funpow_Suc_right pderiv_smult) + +lemma higher_pderiv_monom: + "m \ n + 1 \ (pderiv ^^ m) (monom c n) = monom (pochhammer (int n - int m + 1) m * c) (n - m)" +proof (induction m arbitrary: c n) + case (Suc m) + thus ?case + by (cases n) + (simp_all del: funpow.simps add: funpow_Suc_right pderiv_monom pochhammer_rec' Suc.IH) +qed simp_all + +lemma higher_pderiv_monom_eq_zero: + "m > n + 1 \ (pderiv ^^ m) (monom c n) = 0" +proof (induction m arbitrary: c n) + case (Suc m) + thus ?case + by (cases n) + (simp_all del: funpow.simps add: funpow_Suc_right pderiv_monom pochhammer_rec' Suc.IH) +qed simp_all + +lemma higher_pderiv_sum: "(pderiv ^^ n) (sum f A) = (\x\A. (pderiv ^^ n) (f x))" + by (induction A rule: infinite_finite_induct) (simp_all add: higher_pderiv_add) + +lemma higher_pderiv_sum_mset: "(pderiv ^^ n) (sum_mset A) = (\p\#A. (pderiv ^^ n) p)" + by (induction A) (simp_all add: higher_pderiv_add) + +lemma higher_pderiv_sum_list: "(pderiv ^^ n) (sum_list ps) = (\p\ps. (pderiv ^^ n) p)" + by (induction ps) (simp_all add: higher_pderiv_add) + +lemma degree_higher_pderiv: "Polynomial.degree ((pderiv ^^ n) p) = Polynomial.degree p - n" + for p :: "'a::{comm_semiring_1,semiring_no_zero_divisors,semiring_char_0} poly" + by (induction n) (auto simp: degree_pderiv) + + lemma DERIV_pow2: "DERIV (\x. x ^ Suc n) x :> real (Suc n) * (x ^ n)" by (rule DERIV_cong, rule DERIV_pow) simp declare DERIV_pow2 [simp] DERIV_pow [simp] @@ -2919,6 +3306,15 @@ qed qed (simp add: rsquarefree_def) +lemma rsquarefree_root_order: + assumes "rsquarefree p" "poly p z = 0" "p \ 0" + shows "order z p = 1" +proof - + from assms have "order z p \ {0, 1}" by (auto simp: rsquarefree_def) + moreover from assms have "order z p > 0" by (auto simp: order_root) + ultimately show "order z p = 1" by auto +qed + lemma poly_squarefree_decomp: fixes p :: "'a::field_char_0 poly" assumes "pderiv p \ 0" @@ -2944,6 +3340,37 @@ subsection \Algebraic numbers\ + +lemma intpolyE: + assumes "\i. poly.coeff p i \ \" + obtains q where "p = map_poly of_int q" +proof - + have "\i\{..Polynomial.degree p}. \x. poly.coeff p i = of_int x" + using assms by (auto simp: Ints_def) + from bchoice[OF this] obtain f + where f: "\i. i \ Polynomial.degree p \ poly.coeff p i = of_int (f i)" by blast + define q where "q = Poly (map f [0..i. poly.coeff p i \ \" + obtains q where "p = map_poly of_rat q" +proof - + have "\i\{..Polynomial.degree p}. \x. poly.coeff p i = of_rat x" + using assms by (auto simp: Rats_def) + from bchoice[OF this] obtain f + where f: "\i. i \ Polynomial.degree p \ poly.coeff p i = of_rat (f i)" by blast + define q where "q = Poly (map f [0.. Algebraic numbers can be defined in two equivalent ways: all real numbers that are roots of rational polynomials or of integer polynomials. The Algebraic-Numbers AFP entry @@ -3024,6 +3451,200 @@ ultimately show "\p. (\i. coeff p i \ \) \ p \ 0 \ poly p x = 0" by auto qed +lemma algebraicI': "(\i. coeff p i \ \) \ p \ 0 \ poly p x = 0 \ algebraic x" + unfolding algebraic_altdef by blast + +lemma algebraicE': + assumes "algebraic (x :: 'a :: field_char_0)" + obtains p where "p \ 0" "poly (map_poly of_int p) x = 0" +proof - + from assms obtain q where q: "\i. coeff q i \ \" "q \ 0" "poly q x = 0" + by (erule algebraicE) + moreover from this(1) obtain q' where q': "q = map_poly of_int q'" by (erule intpolyE) + moreover have "q' \ 0" + using q' q by auto + ultimately show ?thesis by (intro that[of q']) simp_all +qed + +lemma algebraicE'_nonzero: + assumes "algebraic (x :: 'a :: field_char_0)" "x \ 0" + obtains p where "p \ 0" "coeff p 0 \ 0" "poly (map_poly of_int p) x = 0" +proof - + from assms(1) obtain p where p: "p \ 0" "poly (map_poly of_int p) x = 0" + by (erule algebraicE') + define n :: nat where "n = order 0 p" + have "monom 1 n dvd p" by (simp add: monom_1_dvd_iff p n_def) + then obtain q where q: "p = monom 1 n * q" by (erule dvdE) + have [simp]: "map_poly of_int (monom 1 n * q) = monom (1 :: 'a) n * map_poly of_int q" + by (induction n) (auto simp: monom_0 monom_Suc map_poly_pCons) + from p have "q \ 0" "poly (map_poly of_int q) x = 0" by (auto simp: q poly_monom assms(2)) + moreover from this have "order 0 p = n + order 0 q" by (simp add: q order_mult) + hence "order 0 q = 0" by (simp add: n_def) + with \q \ 0\ have "poly q 0 \ 0" by (simp add: order_root) + ultimately show ?thesis using that[of q] by (auto simp: poly_0_coeff_0) +qed + +lemma rat_imp_algebraic: "x \ \ \ algebraic x" +proof (rule algebraicI') + show "poly [:-x, 1:] x = 0" + by simp +qed (auto simp: coeff_pCons split: nat.splits) + +lemma algebraic_0 [simp, intro]: "algebraic 0" + and algebraic_1 [simp, intro]: "algebraic 1" + and algebraic_numeral [simp, intro]: "algebraic (numeral n)" + and algebraic_of_nat [simp, intro]: "algebraic (of_nat k)" + and algebraic_of_int [simp, intro]: "algebraic (of_int m)" + by (simp_all add: rat_imp_algebraic) + +lemma algebraic_ii [simp, intro]: "algebraic \" +proof (rule algebraicI) + show "poly [:1, 0, 1:] \ = 0" + by simp +qed (auto simp: coeff_pCons split: nat.splits) + +lemma algebraic_minus [intro]: + assumes "algebraic x" + shows "algebraic (-x)" +proof - + from assms obtain p where p: "\i. coeff p i \ \" "poly p x = 0" "p \ 0" + by (elim algebraicE) auto + define s where "s = (if even (degree p) then 1 else -1 :: 'a)" + + define q where "q = Polynomial.smult s (pcompose p [:0, -1:])" + have "poly q (-x) = 0" + using p by (auto simp: q_def poly_pcompose s_def) + moreover have "q \ 0" + using p by (auto simp: q_def s_def pcompose_eq_0_iff) + find_theorems "pcompose _ _ = 0" + moreover have "coeff q i \ \" for i + proof - + have "coeff (pcompose p [:0, -1:]) i \ \" + using p by (intro coeff_pcompose_semiring_closed) (auto simp: coeff_pCons split: nat.splits) + thus ?thesis by (simp add: q_def s_def) + qed + ultimately show ?thesis + by (auto simp: algebraic_def) +qed + +lemma algebraic_minus_iff [simp]: + "algebraic (-x) \ algebraic (x :: 'a :: field_char_0)" + using algebraic_minus[of x] algebraic_minus[of "-x"] by auto + +lemma algebraic_inverse [intro]: + assumes "algebraic x" + shows "algebraic (inverse x)" +proof (cases "x = 0") + case [simp]: False + from assms obtain p where p: "\i. coeff p i \ \" "poly p x = 0" "p \ 0" + by (elim algebraicE) auto + show ?thesis + proof (rule algebraicI) + show "poly (reflect_poly p) (inverse x) = 0" + using assms p by (simp add: poly_reflect_poly_nz) + qed (use assms p in \auto simp: coeff_reflect_poly\) +qed auto + +lemma algebraic_root: + assumes "algebraic y" + and "poly p x = y" and "\i. coeff p i \ \" and "lead_coeff p = 1" and "degree p > 0" + shows "algebraic x" +proof - + from assms obtain q where q: "poly q y = 0" "\i. coeff q i \ \" "q \ 0" + by (elim algebraicE) auto + show ?thesis + proof (rule algebraicI) + from assms q show "pcompose q p \ 0" + by (auto simp: pcompose_eq_0_iff) + from assms q show "coeff (pcompose q p) i \ \" for i + by (intro allI coeff_pcompose_semiring_closed) auto + show "poly (pcompose q p) x = 0" + using assms q by (simp add: poly_pcompose) + qed +qed + +lemma algebraic_abs_real [simp]: + "algebraic \x :: real\ \ algebraic x" + by (auto simp: abs_if) + +lemma algebraic_nth_root_real [intro]: + assumes "algebraic x" + shows "algebraic (root n x)" +proof (cases "n = 0") + case False + show ?thesis + proof (rule algebraic_root) + show "poly (monom 1 n) (root n x) = (if even n then \x\ else x)" + using sgn_power_root[of n x] False + by (auto simp add: poly_monom sgn_if split: if_splits) + qed (use False assms in \auto simp: degree_monom_eq\) +qed auto + +lemma algebraic_sqrt [intro]: "algebraic x \ algebraic (sqrt x)" + by (auto simp: sqrt_def) + +lemma algebraic_csqrt [intro]: "algebraic x \ algebraic (csqrt x)" + by (rule algebraic_root[where p = "monom 1 2"]) + (auto simp: poly_monom degree_monom_eq) + +lemma algebraic_cnj [intro]: + assumes "algebraic x" + shows "algebraic (cnj x)" +proof - + from assms obtain p where p: "poly p x = 0" "\i. coeff p i \ \" "p \ 0" + by (elim algebraicE) auto + show ?thesis + proof (rule algebraicI) + show "poly (map_poly cnj p) (cnj x) = 0" + using p by simp + show "map_poly cnj p \ 0" + using p by (auto simp: map_poly_eq_0_iff) + show "coeff (map_poly cnj p) i \ \" for i + using p by (auto simp: coeff_map_poly) + qed +qed + +lemma algebraic_cnj_iff [simp]: "algebraic (cnj x) \ algebraic x" + using algebraic_cnj[of x] algebraic_cnj[of "cnj x"] by auto + +lemma algebraic_of_real [intro]: + assumes "algebraic x" + shows "algebraic (of_real x)" +proof - + from assms obtain p where p: "p \ 0" "poly (map_poly of_int p) x = 0" by (erule algebraicE') + have 1: "map_poly of_int p \ (0 :: 'a poly)" + using p by (metis coeff_0 coeff_map_poly leading_coeff_0_iff of_int_eq_0_iff) + + have "poly (map_poly of_int p) (of_real x :: 'a) = of_real (poly (map_poly of_int p) x)" + by (simp add: poly_altdef degree_map_poly coeff_map_poly) + also note p(2) + finally have 2: "poly (map_poly of_int p) (of_real x :: 'a) = 0" + by simp + + from 1 2 show "algebraic (of_real x :: 'a)" + by (intro algebraicI[of "map_poly of_int p"]) (auto simp: coeff_map_poly) +qed + +lemma algebraic_of_real_iff [simp]: + "algebraic (of_real x :: 'a :: {real_algebra_1,field_char_0}) \ algebraic x" +proof + assume "algebraic (of_real x :: 'a)" + then obtain p where p: "p \ 0" "poly (map_poly of_int p) (of_real x :: 'a) = 0" + by (erule algebraicE') + have 1: "(map_poly of_int p :: real poly) \ 0" + using p by (metis coeff_0 coeff_map_poly leading_coeff_0_iff of_int_0 of_int_eq_iff) + + note p(2) + also have "poly (map_poly of_int p) (of_real x :: 'a) = of_real (poly (map_poly of_int p) x)" + by (simp add: poly_altdef degree_map_poly coeff_map_poly) + also have "\ = 0 \ poly (map_poly of_int p) x = 0" + using of_real_eq_0_iff by blast + finally have 2: "poly (map_poly real_of_int p) x = 0" . + + from 1 and 2 show "algebraic x" + by (intro algebraicI[of "map_poly of_int p"]) (auto simp: coeff_map_poly) +qed auto + subsection \Algebraic integers\ @@ -3227,9 +3848,6 @@ by (rule algebraic_int_root[where p = "monom 1 2"]) (auto simp: poly_monom degree_monom_eq) -lemma poly_map_poly_cnj [simp]: "poly (map_poly cnj p) x = cnj (poly p (cnj x))" - by (induction p) (auto simp: map_poly_pCons) - lemma algebraic_int_cnj [intro]: assumes "algebraic_int x" shows "algebraic_int (cnj x)" @@ -3564,6 +4182,39 @@ for p :: "'a::{comm_semiring_1,semiring_no_zero_divisors} poly" by (auto elim: is_unit_polyE simp add: is_unit_const_poly_iff) +lemma root_imp_reducible_poly: + fixes x :: "'a :: field" + assumes "poly p x = 0" and "degree p > 1" + shows "\irreducible p" +proof - + from assms have "p \ 0" + by auto + define q where "q = [:-x, 1:]" + have "q dvd p" + using assms by (simp add: poly_eq_0_iff_dvd q_def) + then obtain r where p_eq: "p = q * r" + by (elim dvdE) + have [simp]: "q \ 0" "r \ 0" + using \p \ 0\ by (auto simp: p_eq) + have "degree p = Suc (degree r)" + unfolding p_eq by (subst degree_mult_eq) (auto simp: q_def) + with assms(2) have "degree r > 0" + by auto + hence "\r dvd 1" + by (auto simp: is_unit_poly_iff) + moreover have "\q dvd 1" + by (auto simp: is_unit_poly_iff q_def) + ultimately show ?thesis using p_eq + by (auto simp: irreducible_def) +qed + +lemma reducible_polyI: + fixes p :: "'a :: field poly" + assumes "p = q * r" "degree q > 0" "degree r > 0" + shows "\irreducible p" + using assms unfolding irreducible_def + by (metis (no_types, opaque_lifting) is_unitE is_unit_iff_degree not_gr0) + subsubsection \Pseudo-Division\ @@ -5221,6 +5872,345 @@ by (simp_all add: content_mult mult_ac) qed (auto simp: content_mult) + +subsection \A typeclass for algebraically closed fields\ + +(* TODO: Move! *) + +text \ + Since the required sort constraints are not available inside the class, we have to resort + to a somewhat awkward way of writing the definition of algebraically closed fields: +\ +class alg_closed_field = field + + assumes alg_closed: "n > 0 \ f n \ 0 \ \x. (\k\n. f k * x ^ k) = 0" + +text \ + We can then however easily show the equivalence to the proper definition: +\ +lemma alg_closed_imp_poly_has_root: + assumes "degree (p :: 'a :: alg_closed_field poly) > 0" + shows "\x. poly p x = 0" +proof - + have "\x. (\k\degree p. coeff p k * x ^ k) = 0" + using assms by (intro alg_closed) auto + thus ?thesis + by (simp add: poly_altdef) +qed + +lemma alg_closedI [Pure.intro]: + assumes "\p :: 'a poly. degree p > 0 \ lead_coeff p = 1 \ \x. poly p x = 0" + shows "OFCLASS('a :: field, alg_closed_field_class)" +proof + fix n :: nat and f :: "nat \ 'a" + assume n: "n > 0" "f n \ 0" + define p where "p = Abs_poly (\k. if k \ n then f k else 0)" + have coeff_p: "coeff p k = (if k \ n then f k else 0)" for k + proof - + have "eventually (\k. k > n) cofinite" + by (auto simp: MOST_nat) + hence "eventually (\k. (if k \ n then f k else 0) = 0) cofinite" + by eventually_elim auto + thus ?thesis + unfolding p_def by (subst Abs_poly_inverse) auto + qed + + from n have "degree p \ n" + by (intro le_degree) (auto simp: coeff_p) + moreover have "degree p \ n" + by (intro degree_le) (auto simp: coeff_p) + ultimately have deg_p: "degree p = n" + by linarith + from deg_p and n have [simp]: "p \ 0" + by auto + + define p' where "p' = smult (inverse (lead_coeff p)) p" + have deg_p': "degree p' = degree p" + by (auto simp: p'_def) + have lead_coeff_p' [simp]: "lead_coeff p' = 1" + by (auto simp: p'_def) + + from deg_p and deg_p' and n have "degree p' > 0" + by simp + from assms[OF this] obtain x where "poly p' x = 0" + by auto + hence "poly p x = 0" + by (simp add: p'_def) + also have "poly p x = (\k\n. f k * x ^ k)" + unfolding poly_altdef by (intro sum.cong) (auto simp: deg_p coeff_p) + finally show "\x. (\k\n. f k * x ^ k) = 0" .. +qed + + +text \ + We can now prove by induction that every polynomial of degree \n\ splits into a product of + \n\ linear factors: +\ +lemma alg_closed_imp_factorization: + fixes p :: "'a :: alg_closed_field poly" + assumes "p \ 0" + shows "\A. size A = degree p \ p = smult (lead_coeff p) (\x\#A. [:-x, 1:])" + using assms +proof (induction "degree p" arbitrary: p rule: less_induct) + case (less p) + show ?case + proof (cases "degree p = 0") + case True + thus ?thesis + by (intro exI[of _ "{#}"]) (auto elim!: degree_eq_zeroE) + next + case False + then obtain x where x: "poly p x = 0" + using alg_closed_imp_poly_has_root by blast + hence "[:-x, 1:] dvd p" + using poly_eq_0_iff_dvd by blast + then obtain q where p_eq: "p = [:-x, 1:] * q" + by (elim dvdE) + have "q \ 0" + using less.prems p_eq by auto + moreover from this have deg: "degree p = Suc (degree q)" + unfolding p_eq by (subst degree_mult_eq) auto + ultimately obtain A where A: "size A = degree q" "q = smult (lead_coeff q) (\x\#A. [:-x, 1:])" + using less.hyps[of q] by auto + have "smult (lead_coeff p) (\y\#add_mset x A. [:- y, 1:]) = + [:- x, 1:] * smult (lead_coeff q) (\y\#A. [:- y, 1:])" + unfolding p_eq lead_coeff_mult by simp + also note A(2) [symmetric] + also note p_eq [symmetric] + finally show ?thesis using A(1) + by (intro exI[of _ "add_mset x A"]) (auto simp: deg) + qed +qed + +text \ + As an alternative characterisation of algebraic closure, one can also say that any + polynomial of degree at least 2 splits into non-constant factors: +\ +lemma alg_closed_imp_reducible: + assumes "degree (p :: 'a :: alg_closed_field poly) > 1" + shows "\irreducible p" +proof - + have "degree p > 0" + using assms by auto + then obtain z where z: "poly p z = 0" + using alg_closed_imp_poly_has_root[of p] by blast + then have dvd: "[:-z, 1:] dvd p" + by (subst dvd_iff_poly_eq_0) auto + then obtain q where q: "p = [:-z, 1:] * q" + by (erule dvdE) + have [simp]: "q \ 0" + using assms q by auto + + show ?thesis + proof (rule reducible_polyI) + show "p = [:-z, 1:] * q" + by fact + next + have "degree p = degree ([:-z, 1:] * q)" + by (simp only: q) + also have "\ = degree q + 1" + by (subst degree_mult_eq) auto + finally show "degree q > 0" + using assms by linarith + qed auto +qed + +text \ + When proving algebraic closure through reducibility, we can assume w.l.o.g. that the polynomial + is monic and has a non-zero constant coefficient: +\ +lemma alg_closedI_reducible: + assumes "\p :: 'a poly. degree p > 1 \ lead_coeff p = 1 \ coeff p 0 \ 0 \ + \irreducible p" + shows "OFCLASS('a :: field, alg_closed_field_class)" +proof + fix p :: "'a poly" assume p: "degree p > 0" "lead_coeff p = 1" + show "\x. poly p x = 0" + proof (cases "coeff p 0 = 0") + case True + hence "poly p 0 = 0" + by (simp add: poly_0_coeff_0) + thus ?thesis by blast + next + case False + from p and this show ?thesis + proof (induction "degree p" arbitrary: p rule: less_induct) + case (less p) + show ?case + proof (cases "degree p = 1") + case True + then obtain a b where p: "p = [:a, b:]" + by (cases p) (auto split: if_splits elim!: degree_eq_zeroE) + from True have [simp]: "b \ 0" + by (auto simp: p) + have "poly p (-a/b) = 0" + by (auto simp: p) + thus ?thesis by blast + next + case False + hence "degree p > 1" + using less.prems by auto + from assms[OF \degree p > 1\ \lead_coeff p = 1\ \coeff p 0 \ 0\] + have "\irreducible p" by auto + then obtain r s where rs: "degree r > 0" "degree s > 0" "p = r * s" + using less.prems unfolding irreducible_def + by (metis is_unit_iff_degree mult_not_zero zero_less_iff_neq_zero) + hence "coeff r 0 \ 0" + using \coeff p 0 \ 0\ by (auto simp: coeff_mult_0) + + define r' where "r' = smult (inverse (lead_coeff r)) r" + have [simp]: "degree r' = degree r" + by (simp add: r'_def) + have lc: "lead_coeff r' = 1" + using rs by (auto simp: r'_def) + have nz: "coeff r' 0 \ 0" + using \coeff r 0 \ 0\ by (auto simp: r'_def) + + have "degree r < degree r + degree s" + using rs by linarith + also have "\ = degree (r * s)" + using rs(3) less.prems by (subst degree_mult_eq) auto + also have "r * s = p" + using rs(3) by simp + finally have "\x. poly r' x = 0" + by (intro less) (use lc rs nz in auto) + thus ?thesis + using rs(3) by (auto simp: r'_def) + qed + qed + qed +qed + +text \ + Using a clever Tschirnhausen transformation mentioned e.g. in the article by + Nowak~\<^cite>\"nowak2000"\, we can also assume w.l.o.g. that the coefficient $a_{n-1}$ is zero. +\ +lemma alg_closedI_reducible_coeff_deg_minus_one_eq_0: + assumes "\p :: 'a poly. degree p > 1 \ lead_coeff p = 1 \ coeff p (degree p - 1) = 0 \ + coeff p 0 \ 0 \ \irreducible p" + shows "OFCLASS('a :: field_char_0, alg_closed_field_class)" +proof (rule alg_closedI_reducible, goal_cases) + case (1 p) + define n where [simp]: "n = degree p" + define a where "a = coeff p (n - 1)" + define r where "r = [: -a / of_nat n, 1 :]" + define s where "s = [: a / of_nat n, 1 :]" + define q where "q = pcompose p r" + + have "n > 0" + using 1 by simp + have r_altdef: "r = monom 1 1 + [:-a / of_nat n:]" + by (simp add: r_def monom_altdef) + have deg_q: "degree q = n" + by (simp add: q_def r_def degree_pcompose) + have lc_q: "lead_coeff q = 1" + unfolding q_def using 1 by (subst lead_coeff_comp) (simp_all add: r_def) + have "q \ 0" + using 1 deg_q by auto + + have "coeff q (n - 1) = + (\i\n. \k\i. coeff p i * (of_nat (i choose k) * + ((-a / of_nat n) ^ (i - k) * (if k = n - 1 then 1 else 0))))" + unfolding q_def pcompose_altdef poly_altdef r_altdef + by (simp_all add: degree_map_poly coeff_map_poly coeff_sum binomial_ring sum_distrib_left poly_const_pow + sum_distrib_right mult_ac monom_power coeff_monom_mult of_nat_poly cong: if_cong) + also have "\ = (\i\n. \k\(if i \ n - 1 then {n-1} else {}). + coeff p i * (of_nat (i choose k) * (-a / of_nat n) ^ (i - k)))" + by (rule sum.cong [OF refl], rule sum.mono_neutral_cong_right) (auto split: if_splits) + also have "\ = (\i\{n-1,n}. \k\(if i \ n - 1 then {n-1} else {}). + coeff p i * (of_nat (i choose k) * (-a / of_nat n) ^ (i - k)))" + by (rule sum.mono_neutral_right) auto + also have "\ = a - of_nat (n choose (n - 1)) * a / of_nat n" + using 1 by (simp add: a_def) + also have "n choose (n - 1) = n" + using \n > 0\ by (subst binomial_symmetric) auto + also have "a - of_nat n * a / of_nat n = 0" + using \n > 0\ by simp + finally have "coeff q (n - 1) = 0" . + + show ?case + proof (cases "coeff q 0 = 0") + case True + hence "poly p (- (a / of_nat (degree p))) = 0" + by (auto simp: q_def r_def) + thus ?thesis + by (rule root_imp_reducible_poly) (use 1 in auto) + next + case False + hence "\irreducible q" + using assms[of q] and lc_q and 1 and \coeff q (n - 1) = 0\ + by (auto simp: deg_q) + then obtain u v where uv: "degree u > 0" "degree v > 0" "q = u * v" + using \q \ 0\ 1 deg_q unfolding irreducible_def + by (metis degree_mult_eq_0 is_unit_iff_degree n_def neq0_conv not_one_less_zero) + + have "p = pcompose q s" + by (simp add: q_def r_def s_def pcompose_pCons flip: pcompose_assoc) + also have "q = u * v" + by fact + finally have "p = pcompose u s * pcompose v s" + by (simp add: pcompose_mult) + moreover have "degree (pcompose u s) > 0" "degree (pcompose v s) > 0" + using uv by (simp_all add: s_def degree_pcompose) + ultimately show "\irreducible p" + using 1 by (intro reducible_polyI) + qed +qed + +text \ + As a consequence of the full factorisation lemma proven above, we can also show that any + polynomial with at least two different roots splits into two non-constant coprime factors: +\ +lemma alg_closed_imp_poly_splits_coprime: + assumes "degree (p :: 'a :: {alg_closed_field} poly) > 1" + assumes "poly p x = 0" "poly p y = 0" "x \ y" + obtains r s where "degree r > 0" "degree s > 0" "coprime r s" "p = r * s" +proof - + define n where "n = order x p" + have "n > 0" + using assms by (metis degree_0 gr0I n_def not_one_less_zero order_root) + have "[:-x, 1:] ^ n dvd p" + unfolding n_def by (simp add: order_1) + then obtain q where p_eq: "p = [:-x, 1:] ^ n * q" + by (elim dvdE) + from assms have [simp]: "q \ 0" + by (auto simp: p_eq) + have "order x p = n + Polynomial.order x q" + unfolding p_eq by (subst order_mult) (auto simp: order_power_n_n) + hence "Polynomial.order x q = 0" + by (simp add: n_def) + hence "poly q x \ 0" + by (simp add: order_root) + + show ?thesis + proof (rule that) + show "coprime ([:-x, 1:] ^ n) q" + proof (rule coprimeI) + fix d + assume d: "d dvd [:-x, 1:] ^ n" "d dvd q" + have "degree d = 0" + proof (rule ccontr) + assume "\(degree d = 0)" + then obtain z where z: "poly d z = 0" + using alg_closed_imp_poly_has_root by blast + moreover from this and d(1) have "poly ([:-x, 1:] ^ n) z = 0" + using dvd_trans poly_eq_0_iff_dvd by blast + ultimately have "poly d x = 0" + by auto + with d(2) have "poly q x = 0" + using dvd_trans poly_eq_0_iff_dvd by blast + with \poly q x \ 0\ show False by contradiction + qed + thus "is_unit d" using d + by (metis \q \ 0\ dvd_0_left is_unit_iff_degree) + qed + next + have "poly q y = 0" + using \poly p y = 0\ \x \ y\ by (auto simp: p_eq) + with \q \ 0\ show "degree q > 0" + using order_degree order_gt_0_iff order_less_le_trans by blast + qed (use \n > 0\ in \simp_all add: p_eq degree_power_eq\) +qed + no_notation cCons (infixr "##" 65) end diff -r f82639fe786e -r 4c1347e172b1 src/HOL/Computational_Algebra/document/root.bib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/HOL/Computational_Algebra/document/root.bib Fri Mar 29 19:28:59 2024 +0100 @@ -0,0 +1,8 @@ +@article{nowak2000, + title={Some elementary proofs of {P}uiseux’s theorems}, + author={Nowak, Krzysztof Jan}, + journal={Univ. Iagel. Acta Math}, + volume={38}, + pages={279--282}, + year={2000} +} \ No newline at end of file diff -r f82639fe786e -r 4c1347e172b1 src/HOL/Computational_Algebra/document/root.tex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/HOL/Computational_Algebra/document/root.tex Fri Mar 29 19:28:59 2024 +0100 @@ -0,0 +1,38 @@ +\documentclass[11pt,a4paper]{article} +\usepackage[T1]{fontenc} +\usepackage{isabelle} +\usepackage{isabellesym} +\usepackage{latexsym} +\usepackage{textcomp} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage[only,bigsqcap]{stmaryrd} +\usepackage{pdfsetup} +\usepackage{graphicx} + +\urlstyle{rm} +\isabellestyle{it} + +\begin{document} + +\title{Computational Algebra} +\maketitle + +\tableofcontents + +\begin{center} + \includegraphics[width=\textwidth]{session_graph} +\end{center} + +\newpage + +\renewcommand{\setisabellecontext}[1]{\markright{\href{#1.html}{#1.thy}}} + +\parindent 0pt\parskip 0.5ex +\input{session} + +\pagestyle{headings} +\bibliographystyle{abbrv} +\bibliography{root} + +\end{document} diff -r f82639fe786e -r 4c1347e172b1 src/HOL/Groups_List.thy --- a/src/HOL/Groups_List.thy Sat Mar 30 01:12:48 2024 +0100 +++ b/src/HOL/Groups_List.thy Fri Mar 29 19:28:59 2024 +0100 @@ -47,6 +47,16 @@ "set.F g (set xs) = list.F (map g (remdups xs))" by (simp add: distinct_set_conv_list [symmetric]) +lemma list_conv_set_nth: + "list.F xs = set.F (\i. xs ! i) {0..i. xs ! i) [0.. = set.F (\i. xs ! i) {0.. \a. M = {#a#}" by (cases M) auto +lemma set_mset_subset_singletonD: + assumes "set_mset A \ {x}" + shows "A = replicate_mset (size A) x" + using assms by (induction A) auto + subsubsection \Strong induction and subset induction for multisets\ @@ -2308,6 +2313,15 @@ lemma size_replicate_mset[simp]: "size (replicate_mset n M) = n" by (induct n, simp_all) +lemma size_repeat_mset [simp]: "size (repeat_mset n A) = n * size A" + by (induction n) auto + +lemma size_multiset_sum [simp]: "size (\x\A. f x :: 'a multiset) = (\x\A. size (f x))" + by (induction A rule: infinite_finite_induct) auto + +lemma size_multiset_sum_list [simp]: "size (\X\Xs. X :: 'a multiset) = (\X\Xs. size X)" + by (induction Xs) auto + lemma count_le_replicate_mset_subset_eq: "n \ count M x \ replicate_mset n x \# M" by (auto simp add: mset_subset_eqI) (metis count_replicate_mset subseteq_mset_def) @@ -2774,7 +2788,10 @@ by (induction M) auto lemma Union_image_single_mset[simp]: "\\<^sub># (image_mset (\x. {#x#}) m) = m" -by(induction m) auto + by(induction m) auto + +lemma size_multiset_sum_mset [simp]: "size (\X\#A. X :: 'a multiset) = (\X\#A. size X)" + by (induction A) auto context comm_monoid_mult begin @@ -2891,6 +2908,32 @@ then show ?thesis by (simp add: normalize_prod_mset) qed +lemma image_prod_mset_multiplicity: + "prod_mset (image_mset f M) = prod (\x. f x ^ count M x) (set_mset M)" +proof (induction M) + case (add x M) + show ?case + proof (cases "x \ set_mset M") + case True + have "(\y\set_mset (add_mset x M). f y ^ count (add_mset x M) y) = + (\y\set_mset M. (if y = x then f x else 1) * f y ^ count M y)" + using True add by (intro prod.cong) auto + also have "\ = f x * (\y\set_mset M. f y ^ count M y)" + using True by (subst prod.distrib) auto + also note add.IH [symmetric] + finally show ?thesis using True by simp + next + case False + hence "(\y\set_mset (add_mset x M). f y ^ count (add_mset x M) y) = + f x * (\y\set_mset M. f y ^ count (add_mset x M) y)" + by (auto simp: not_in_iff) + also have "(\y\set_mset M. f y ^ count (add_mset x M) y) = + (\y\set_mset M. f y ^ count M y)" + using False by (intro prod.cong) auto + also note add.IH [symmetric] + finally show ?thesis by simp + qed +qed auto subsection \Multiset as order-ignorant lists\ diff -r f82639fe786e -r 4c1347e172b1 src/HOL/Library/Real_Mod.thy --- a/src/HOL/Library/Real_Mod.thy Sat Mar 30 01:12:48 2024 +0100 +++ b/src/HOL/Library/Real_Mod.thy Fri Mar 29 19:28:59 2024 +0100 @@ -7,6 +7,8 @@ imports Complex_Main begin +(* MOVED TO HOL-Library ON 20.03.2024 *) + definition rmod :: "real \ real \ real" (infixl "rmod" 70) where "x rmod y = x - \y\ * of_int \x / \y\\" diff -r f82639fe786e -r 4c1347e172b1 src/HOL/ROOT --- a/src/HOL/ROOT Sat Mar 30 01:12:48 2024 +0100 +++ b/src/HOL/ROOT Fri Mar 29 19:28:59 2024 +0100 @@ -148,6 +148,9 @@ Computational_Algebra (*conflicting type class instantiations and dependent applications*) Field_as_Ring + document_files + "root.tex" + "root.bib" session "HOL-Real_Asymp" in Real_Asymp = HOL + sessions diff -r f82639fe786e -r 4c1347e172b1 src/HOL/Rat.thy --- a/src/HOL/Rat.thy Sat Mar 30 01:12:48 2024 +0100 +++ b/src/HOL/Rat.thy Fri Mar 29 19:28:59 2024 +0100 @@ -877,6 +877,12 @@ for a :: "'a::field_char_0" by (metis Rats_cases Rats_of_rat of_rat_power) +lemma Rats_sum [intro]: "(\x. x \ A \ f x \ \) \ sum f A \ \" + by (induction A rule: infinite_finite_induct) auto + +lemma Rats_prod [intro]: "(\x. x \ A \ f x \ \) \ prod f A \ \" + by (induction A rule: infinite_finite_induct) auto + lemma Rats_induct [case_names of_rat, induct set: Rats]: "q \ \ \ (\r. P (of_rat r)) \ P q" by (rule Rats_cases) auto