# HG changeset patch # User Manuel Eberl # Date 1526658718 -7200 # Node ID b48bab5119391a03af2288617d063b809d35d3e2 # Parent 37974ddde92844c3389aab7e2977b350f737568a Moved Landau_Symbols from the AFP to HOL-Library diff -r 37974ddde928 -r b48bab511939 CONTRIBUTORS --- a/CONTRIBUTORS Tue May 22 11:05:47 2018 +0200 +++ b/CONTRIBUTORS Fri May 18 17:51:58 2018 +0200 @@ -6,6 +6,9 @@ Contributions to this Isabelle version -------------------------------------- +* May 2018: Manuel Eberl + Landau symbols and asymptotic equivalence (moved from the AFP) + * May 2018: Jose Divasón (Universidad de la Rioja), Jesús Aransay (Universidad de la Rioja), Johannes Hölzl (VU Amsterdam), Fabian Immler (TUM) diff -r 37974ddde928 -r b48bab511939 NEWS --- a/NEWS Tue May 22 11:05:47 2018 +0200 +++ b/NEWS Fri May 18 17:51:58 2018 +0200 @@ -201,6 +201,8 @@ *** HOL *** +* Landau_Symbols from the AFP was moved to HOL-Library + * Clarified relationship of characters, strings and code generation: * Type "char" is now a proper datatype of 8-bit values. diff -r 37974ddde928 -r b48bab511939 src/HOL/Library/Landau_Symbols.thy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/HOL/Library/Landau_Symbols.thy Fri May 18 17:51:58 2018 +0200 @@ -0,0 +1,2208 @@ +(* + File: Landau_Symbols_Definition.thy + Author: Manuel Eberl + + Landau symbols for reasoning about the asymptotic growth of functions. +*) +section {* Definition of Landau symbols *} + +theory Landau_Symbols +imports + Complex_Main +begin + +lemma eventually_subst': + "eventually (\x. f x = g x) F \ eventually (\x. P x (f x)) F = eventually (\x. P x (g x)) F" + by (rule eventually_subst, erule eventually_rev_mp) simp + + +subsection {* Definition of Landau symbols *} + +text {* + Our Landau symbols are sign-oblivious, i.e. any function always has the same growth + as its absolute. This has the advantage of making some cancelling rules for sums nicer, but + introduces some problems in other places. Nevertheless, we found this definition more convenient + to work with. +*} + +definition bigo :: "'a filter \ ('a \ ('b :: real_normed_field)) \ ('a \ 'b) set" + ("(1O[_]'(_'))") + where "bigo F g = {f. (\c>0. eventually (\x. norm (f x) \ c * norm (g x)) F)}" + +definition smallo :: "'a filter \ ('a \ ('b :: real_normed_field)) \ ('a \ 'b) set" + ("(1o[_]'(_'))") + where "smallo F g = {f. (\c>0. eventually (\x. norm (f x) \ c * norm (g x)) F)}" + +definition bigomega :: "'a filter \ ('a \ ('b :: real_normed_field)) \ ('a \ 'b) set" + ("(1\[_]'(_'))") + where "bigomega F g = {f. (\c>0. eventually (\x. norm (f x) \ c * norm (g x)) F)}" + +definition smallomega :: "'a filter \ ('a \ ('b :: real_normed_field)) \ ('a \ 'b) set" + ("(1\[_]'(_'))") + where "smallomega F g = {f. (\c>0. eventually (\x. norm (f x) \ c * norm (g x)) F)}" + +definition bigtheta :: "'a filter \ ('a \ ('b :: real_normed_field)) \ ('a \ 'b) set" + ("(1\[_]'(_'))") + where "bigtheta F g = bigo F g \ bigomega F g" + +abbreviation bigo_at_top ("(2O'(_'))") where + "O(g) \ bigo at_top g" + +abbreviation smallo_at_top ("(2o'(_'))") where + "o(g) \ smallo at_top g" + +abbreviation bigomega_at_top ("(2\'(_'))") where + "\(g) \ bigomega at_top g" + +abbreviation smallomega_at_top ("(2\'(_'))") where + "\(g) \ smallomega at_top g" + +abbreviation bigtheta_at_top ("(2\'(_'))") where + "\(g) \ bigtheta at_top g" + + +text {* The following is a set of properties that all Landau symbols satisfy. *} + +named_theorems landau_divide_simps + +locale landau_symbol = + fixes L :: "'a filter \ ('a \ ('b :: real_normed_field)) \ ('a \ 'b) set" + and L' :: "'c filter \ ('c \ ('b :: real_normed_field)) \ ('c \ 'b) set" + and Lr :: "'a filter \ ('a \ real) \ ('a \ real) set" + assumes bot': "L bot f = UNIV" + assumes filter_mono': "F1 \ F2 \ L F2 f \ L F1 f" + assumes in_filtermap_iff: + "f' \ L (filtermap h' F') g' \ (\x. f' (h' x)) \ L' F' (\x. g' (h' x))" + assumes filtercomap: + "f' \ L F'' g' \ (\x. f' (h' x)) \ L' (filtercomap h' F'') (\x. g' (h' x))" + assumes sup: "f \ L F1 g \ f \ L F2 g \ f \ L (sup F1 F2) g" + assumes in_cong: "eventually (\x. f x = g x) F \ f \ L F (h) \ g \ L F (h)" + assumes cong: "eventually (\x. f x = g x) F \ L F (f) = L F (g)" + assumes cong_bigtheta: "f \ \[F](g) \ L F (f) = L F (g)" + assumes in_cong_bigtheta: "f \ \[F](g) \ f \ L F (h) \ g \ L F (h)" + assumes cmult [simp]: "c \ 0 \ L F (\x. c * f x) = L F (f)" + assumes cmult_in_iff [simp]: "c \ 0 \ (\x. c * f x) \ L F (g) \ f \ L F (g)" + assumes mult_left [simp]: "f \ L F (g) \ (\x. h x * f x) \ L F (\x. h x * g x)" + assumes inverse: "eventually (\x. f x \ 0) F \ eventually (\x. g x \ 0) F \ + f \ L F (g) \ (\x. inverse (g x)) \ L F (\x. inverse (f x))" + assumes subsetI: "f \ L F (g) \ L F (f) \ L F (g)" + assumes plus_subset1: "f \ o[F](g) \ L F (g) \ L F (\x. f x + g x)" + assumes trans: "f \ L F (g) \ g \ L F (h) \ f \ L F (h)" + assumes compose: "f \ L F (g) \ filterlim h' F G \ (\x. f (h' x)) \ L' G (\x. g (h' x))" + assumes norm_iff [simp]: "(\x. norm (f x)) \ Lr F (\x. norm (g x)) \ f \ L F (g)" + assumes abs [simp]: "Lr Fr (\x. \fr x\) = Lr Fr fr" + assumes abs_in_iff [simp]: "(\x. \fr x\) \ Lr Fr gr \ fr \ Lr Fr gr" +begin + +lemma bot [simp]: "f \ L bot g" by (simp add: bot') + +lemma filter_mono: "F1 \ F2 \ f \ L F2 g \ f \ L F1 g" + using filter_mono'[of F1 F2] by blast + +lemma cong_ex: + "eventually (\x. f1 x = f2 x) F \ eventually (\x. g1 x = g2 x) F \ + f1 \ L F (g1) \ f2 \ L F (g2)" + by (subst cong, assumption, subst in_cong, assumption, rule refl) + +lemma cong_ex_bigtheta: + "f1 \ \[F](f2) \ g1 \ \[F](g2) \ f1 \ L F (g1) \ f2 \ L F (g2)" + by (subst cong_bigtheta, assumption, subst in_cong_bigtheta, assumption, rule refl) + +lemma bigtheta_trans1: + "f \ L F (g) \ g \ \[F](h) \ f \ L F (h)" + by (subst cong_bigtheta[symmetric]) + +lemma bigtheta_trans2: + "f \ \[F](g) \ g \ L F (h) \ f \ L F (h)" + by (subst in_cong_bigtheta) + +lemma cmult' [simp]: "c \ 0 \ L F (\x. f x * c) = L F (f)" + by (subst mult.commute) (rule cmult) + +lemma cmult_in_iff' [simp]: "c \ 0 \ (\x. f x * c) \ L F (g) \ f \ L F (g)" + by (subst mult.commute) (rule cmult_in_iff) + +lemma cdiv [simp]: "c \ 0 \ L F (\x. f x / c) = L F (f)" + using cmult'[of "inverse c" F f] by (simp add: field_simps) + +lemma cdiv_in_iff' [simp]: "c \ 0 \ (\x. f x / c) \ L F (g) \ f \ L F (g)" + using cmult_in_iff'[of "inverse c" f] by (simp add: field_simps) + +lemma uminus [simp]: "L F (\x. -g x) = L F (g)" using cmult[of "-1"] by simp + +lemma uminus_in_iff [simp]: "(\x. -f x) \ L F (g) \ f \ L F (g)" + using cmult_in_iff[of "-1"] by simp + +lemma const: "c \ 0 \ L F (\_. c) = L F (\_. 1)" + by (subst (2) cmult[symmetric]) simp_all + +(* Simplifier loops without the NO_MATCH *) +lemma const' [simp]: "NO_MATCH 1 c \ c \ 0 \ L F (\_. c) = L F (\_. 1)" + by (rule const) + +lemma const_in_iff: "c \ 0 \ (\_. c) \ L F (f) \ (\_. 1) \ L F (f)" + using cmult_in_iff'[of c "\_. 1"] by simp + +lemma const_in_iff' [simp]: "NO_MATCH 1 c \ c \ 0 \ (\_. c) \ L F (f) \ (\_. 1) \ L F (f)" + by (rule const_in_iff) + +lemma plus_subset2: "g \ o[F](f) \ L F (f) \ L F (\x. f x + g x)" + by (subst add.commute) (rule plus_subset1) + +lemma mult_right [simp]: "f \ L F (g) \ (\x. f x * h x) \ L F (\x. g x * h x)" + using mult_left by (simp add: mult.commute) + +lemma mult: "f1 \ L F (g1) \ f2 \ L F (g2) \ (\x. f1 x * f2 x) \ L F (\x. g1 x * g2 x)" + by (rule trans, erule mult_left, erule mult_right) + +lemma inverse_cancel: + assumes "eventually (\x. f x \ 0) F" + assumes "eventually (\x. g x \ 0) F" + shows "(\x. inverse (f x)) \ L F (\x. inverse (g x)) \ g \ L F (f)" +proof + assume "(\x. inverse (f x)) \ L F (\x. inverse (g x))" + from inverse[OF _ _ this] assms show "g \ L F (f)" by simp +qed (intro inverse assms) + +lemma divide_right: + assumes "eventually (\x. h x \ 0) F" + assumes "f \ L F (g)" + shows "(\x. f x / h x) \ L F (\x. g x / h x)" + by (subst (1 2) divide_inverse) (intro mult_right inverse assms) + +lemma divide_right_iff: + assumes "eventually (\x. h x \ 0) F" + shows "(\x. f x / h x) \ L F (\x. g x / h x) \ f \ L F (g)" +proof + assume "(\x. f x / h x) \ L F (\x. g x / h x)" + from mult_right[OF this, of h] assms show "f \ L F (g)" + by (subst (asm) cong_ex[of _ f F _ g]) (auto elim!: eventually_mono) +qed (simp add: divide_right assms) + +lemma divide_left: + assumes "eventually (\x. f x \ 0) F" + assumes "eventually (\x. g x \ 0) F" + assumes "g \ L F(f)" + shows "(\x. h x / f x) \ L F (\x. h x / g x)" + by (subst (1 2) divide_inverse) (intro mult_left inverse assms) + +lemma divide_left_iff: + assumes "eventually (\x. f x \ 0) F" + assumes "eventually (\x. g x \ 0) F" + assumes "eventually (\x. h x \ 0) F" + shows "(\x. h x / f x) \ L F (\x. h x / g x) \ g \ L F (f)" +proof + assume A: "(\x. h x / f x) \ L F (\x. h x / g x)" + from assms have B: "eventually (\x. h x / f x / h x = inverse (f x)) F" + by eventually_elim (simp add: divide_inverse) + from assms have C: "eventually (\x. h x / g x / h x = inverse (g x)) F" + by eventually_elim (simp add: divide_inverse) + from divide_right[OF assms(3) A] assms show "g \ L F (f)" + by (subst (asm) cong_ex[OF B C]) (simp add: inverse_cancel) +qed (simp add: divide_left assms) + +lemma divide: + assumes "eventually (\x. g1 x \ 0) F" + assumes "eventually (\x. g2 x \ 0) F" + assumes "f1 \ L F (f2)" "g2 \ L F (g1)" + shows "(\x. f1 x / g1 x) \ L F (\x. f2 x / g2 x)" + by (subst (1 2) divide_inverse) (intro mult inverse assms) + +lemma divide_eq1: + assumes "eventually (\x. h x \ 0) F" + shows "f \ L F (\x. g x / h x) \ (\x. f x * h x) \ L F (g)" +proof- + have "f \ L F (\x. g x / h x) \ (\x. f x * h x / h x) \ L F (\x. g x / h x)" + using assms by (intro in_cong) (auto elim: eventually_mono) + thus ?thesis by (simp only: divide_right_iff assms) +qed + +lemma divide_eq2: + assumes "eventually (\x. h x \ 0) F" + shows "(\x. f x / h x) \ L F (\x. g x) \ f \ L F (\x. g x * h x)" +proof- + have "L F (\x. g x) = L F (\x. g x * h x / h x)" + using assms by (intro cong) (auto elim: eventually_mono) + thus ?thesis by (simp only: divide_right_iff assms) +qed + +lemma inverse_eq1: + assumes "eventually (\x. g x \ 0) F" + shows "f \ L F (\x. inverse (g x)) \ (\x. f x * g x) \ L F (\_. 1)" + using divide_eq1[of g F f "\_. 1"] by (simp add: divide_inverse assms) + +lemma inverse_eq2: + assumes "eventually (\x. f x \ 0) F" + shows "(\x. inverse (f x)) \ L F (g) \ (\x. 1) \ L F (\x. f x * g x)" + using divide_eq2[of f F "\_. 1" g] by (simp add: divide_inverse assms mult_ac) + +lemma inverse_flip: + assumes "eventually (\x. g x \ 0) F" + assumes "eventually (\x. h x \ 0) F" + assumes "(\x. inverse (g x)) \ L F (h)" + shows "(\x. inverse (h x)) \ L F (g)" +using assms by (simp add: divide_eq1 divide_eq2 inverse_eq_divide mult.commute) + +lemma lift_trans: + assumes "f \ L F (g)" + assumes "(\x. t x (g x)) \ L F (h)" + assumes "\f g. f \ L F (g) \ (\x. t x (f x)) \ L F (\x. t x (g x))" + shows "(\x. t x (f x)) \ L F (h)" + by (rule trans[OF assms(3)[OF assms(1)] assms(2)]) + +lemma lift_trans': + assumes "f \ L F (\x. t x (g x))" + assumes "g \ L F (h)" + assumes "\g h. g \ L F (h) \ (\x. t x (g x)) \ L F (\x. t x (h x))" + shows "f \ L F (\x. t x (h x))" + by (rule trans[OF assms(1) assms(3)[OF assms(2)]]) + +lemma lift_trans_bigtheta: + assumes "f \ L F (g)" + assumes "(\x. t x (g x)) \ \[F](h)" + assumes "\f g. f \ L F (g) \ (\x. t x (f x)) \ L F (\x. t x (g x))" + shows "(\x. t x (f x)) \ L F (h)" + using cong_bigtheta[OF assms(2)] assms(3)[OF assms(1)] by simp + +lemma lift_trans_bigtheta': + assumes "f \ L F (\x. t x (g x))" + assumes "g \ \[F](h)" + assumes "\g h. g \ \[F](h) \ (\x. t x (g x)) \ \[F](\x. t x (h x))" + shows "f \ L F (\x. t x (h x))" + using cong_bigtheta[OF assms(3)[OF assms(2)]] assms(1) by simp + +lemma (in landau_symbol) mult_in_1: + assumes "f \ L F (\_. 1)" "g \ L F (\_. 1)" + shows "(\x. f x * g x) \ L F (\_. 1)" + using mult[OF assms] by simp + +lemma (in landau_symbol) of_real_cancel: + "(\x. of_real (f x)) \ L F (\x. of_real (g x)) \ f \ Lr F g" + by (subst (asm) norm_iff [symmetric], subst (asm) (1 2) norm_of_real) simp_all + +lemma (in landau_symbol) of_real_iff: + "(\x. of_real (f x)) \ L F (\x. of_real (g x)) \ f \ Lr F g" + by (subst norm_iff [symmetric], subst (1 2) norm_of_real) simp_all + +lemmas [landau_divide_simps] = + inverse_cancel divide_left_iff divide_eq1 divide_eq2 inverse_eq1 inverse_eq2 + +end + + +text {* + The symbols $O$ and $o$ and $\Omega$ and $\omega$ are dual, so for many rules, replacing $O$ with + $\Omega$, $o$ with $\omega$, and $\leq$ with $\geq$ in a theorem yields another valid theorem. + The following locale captures this fact. +*} + +locale landau_pair = + fixes L l :: "'a filter \ ('a \ ('b :: real_normed_field)) \ ('a \ 'b) set" + fixes L' l' :: "'c filter \ ('c \ ('b :: real_normed_field)) \ ('c \ 'b) set" + fixes Lr lr :: "'a filter \ ('a \ real) \ ('a \ real) set" + and R :: "real \ real \ bool" + assumes L_def: "L F g = {f. \c>0. eventually (\x. R (norm (f x)) (c * norm (g x))) F}" + and l_def: "l F g = {f. \c>0. eventually (\x. R (norm (f x)) (c * norm (g x))) F}" + and L'_def: "L' F' g' = {f. \c>0. eventually (\x. R (norm (f x)) (c * norm (g' x))) F'}" + and l'_def: "l' F' g' = {f. \c>0. eventually (\x. R (norm (f x)) (c * norm (g' x))) F'}" + and Lr_def: "Lr F'' g'' = {f. \c>0. eventually (\x. R (norm (f x)) (c * norm (g'' x))) F''}" + and lr_def: "lr F'' g'' = {f. \c>0. eventually (\x. R (norm (f x)) (c * norm (g'' x))) F''}" + and R: "R = (\) \ R = (\)" + +interpretation landau_o: + landau_pair bigo smallo bigo smallo bigo smallo "(\)" + by unfold_locales (auto simp: bigo_def smallo_def intro!: ext) + +interpretation landau_omega: + landau_pair bigomega smallomega bigomega smallomega bigomega smallomega "(\)" + by unfold_locales (auto simp: bigomega_def smallomega_def intro!: ext) + + +context landau_pair +begin + +lemmas R_E = disjE [OF R, case_names le ge] + +lemma bigI: + "c > 0 \ eventually (\x. R (norm (f x)) (c * norm (g x))) F \ f \ L F (g)" + unfolding L_def by blast + +lemma bigE: + assumes "f \ L F (g)" + obtains c where "c > 0" "eventually (\x. R (norm (f x)) (c * (norm (g x)))) F" + using assms unfolding L_def by blast + +lemma smallI: + "(\c. c > 0 \ eventually (\x. R (norm (f x)) (c * (norm (g x)))) F) \ f \ l F (g)" + unfolding l_def by blast + +lemma smallD: + "f \ l F (g) \ c > 0 \ eventually (\x. R (norm (f x)) (c * (norm (g x)))) F" + unfolding l_def by blast + +lemma bigE_nonneg_real: + assumes "f \ Lr F (g)" "eventually (\x. f x \ 0) F" + obtains c where "c > 0" "eventually (\x. R (f x) (c * \g x\)) F" +proof- + from assms(1) obtain c where c: "c > 0" "eventually (\x. R (norm (f x)) (c * norm (g x))) F" + by (auto simp: Lr_def) + from c(2) assms(2) have "eventually (\x. R (f x) (c * \g x\)) F" + by eventually_elim simp + from c(1) and this show ?thesis by (rule that) +qed + +lemma smallD_nonneg_real: + assumes "f \ lr F (g)" "eventually (\x. f x \ 0) F" "c > 0" + shows "eventually (\x. R (f x) (c * \g x\)) F" + using assms by (auto simp: lr_def dest!: spec[of _ c] elim: eventually_elim2) + +lemma small_imp_big: "f \ l F (g) \ f \ L F (g)" + by (rule bigI[OF _ smallD, of 1]) simp_all + +lemma small_subset_big: "l F (g) \ L F (g)" + using small_imp_big by blast + +lemma R_refl [simp]: "R x x" using R by auto + +lemma R_linear: "\R x y \ R y x" + using R by auto + +lemma R_trans [trans]: "R a b \ R b c \ R a c" + using R by auto + +lemma R_mult_left_mono: "R a b \ c \ 0 \ R (c*a) (c*b)" + using R by (auto simp: mult_left_mono) + +lemma R_mult_right_mono: "R a b \ c \ 0 \ R (a*c) (b*c)" + using R by (auto simp: mult_right_mono) + +lemma big_trans: + assumes "f \ L F (g)" "g \ L F (h)" + shows "f \ L F (h)" +proof- + from assms(1) guess c by (elim bigE) note c = this + from assms(2) guess d by (elim bigE) note d = this + from c(2) d(2) have "eventually (\x. R (norm (f x)) (c * d * (norm (h x)))) F" + proof eventually_elim + fix x assume "R (norm (f x)) (c * (norm (g x)))" + also assume "R (norm (g x)) (d * (norm (h x)))" + with c(1) have "R (c * (norm (g x))) (c * (d * (norm (h x))))" + by (intro R_mult_left_mono) simp_all + finally show "R (norm (f x)) (c * d * (norm (h x)))" by (simp add: algebra_simps) + qed + with c(1) d(1) show ?thesis by (intro bigI[of "c*d"]) simp_all +qed + +lemma big_small_trans: + assumes "f \ L F (g)" "g \ l F (h)" + shows "f \ l F (h)" +proof (rule smallI) + fix c :: real assume c: "c > 0" + from assms(1) guess d by (elim bigE) note d = this + note d(2) + moreover from c d assms(2) + have "eventually (\x. R (norm (g x)) (c * inverse d * norm (h x))) F" + by (intro smallD) simp_all + ultimately show "eventually (\x. R (norm (f x)) (c * (norm (h x)))) F" + by eventually_elim (erule R_trans, insert R d(1), auto simp: field_simps) +qed + +lemma small_big_trans: + assumes "f \ l F (g)" "g \ L F (h)" + shows "f \ l F (h)" +proof (rule smallI) + fix c :: real assume c: "c > 0" + from assms(2) guess d by (elim bigE) note d = this + note d(2) + moreover from c d assms(1) + have "eventually (\x. R (norm (f x)) (c * inverse d * norm (g x))) F" + by (intro smallD) simp_all + ultimately show "eventually (\x. R (norm (f x)) (c * norm (h x))) F" + by eventually_elim (rotate_tac 2, erule R_trans, insert R c d(1), auto simp: field_simps) +qed + +lemma small_trans: + "f \ l F (g) \ g \ l F (h) \ f \ l F (h)" + by (rule big_small_trans[OF small_imp_big]) + +lemma small_big_trans': + "f \ l F (g) \ g \ L F (h) \ f \ L F (h)" + by (rule small_imp_big[OF small_big_trans]) + +lemma big_small_trans': + "f \ L F (g) \ g \ l F (h) \ f \ L F (h)" + by (rule small_imp_big[OF big_small_trans]) + +lemma big_subsetI [intro]: "f \ L F (g) \ L F (f) \ L F (g)" + by (intro subsetI) (drule (1) big_trans) + +lemma small_subsetI [intro]: "f \ L F (g) \ l F (f) \ l F (g)" + by (intro subsetI) (drule (1) small_big_trans) + +lemma big_refl [simp]: "f \ L F (f)" + by (rule bigI[of 1]) simp_all + +lemma small_refl_iff: "f \ l F (f) \ eventually (\x. f x = 0) F" +proof (rule iffI[OF _ smallI]) + assume f: "f \ l F f" + have "(1/2::real) > 0" "(2::real) > 0" by simp_all + from smallD[OF f this(1)] smallD[OF f this(2)] + show "eventually (\x. f x = 0) F" by eventually_elim (insert R, auto) +next + fix c :: real assume "c > 0" "eventually (\x. f x = 0) F" + from this(2) show "eventually (\x. R (norm (f x)) (c * norm (f x))) F" + by eventually_elim simp_all +qed + +lemma big_small_asymmetric: "f \ L F (g) \ g \ l F (f) \ eventually (\x. f x = 0) F" + by (drule (1) big_small_trans) (simp add: small_refl_iff) + +lemma small_big_asymmetric: "f \ l F (g) \ g \ L F (f) \ eventually (\x. f x = 0) F" + by (drule (1) small_big_trans) (simp add: small_refl_iff) + +lemma small_asymmetric: "f \ l F (g) \ g \ l F (f) \ eventually (\x. f x = 0) F" + by (drule (1) small_trans) (simp add: small_refl_iff) + + +lemma plus_aux: + assumes "f \ o[F](g)" + shows "g \ L F (\x. f x + g x)" +proof (rule R_E) + assume [simp]: "R = (\)" + have A: "1/2 > (0::real)" by simp + { + fix x assume "norm (f x) \ 1/2 * norm (g x)" + hence "1/2 * (norm (g x)) \ (norm (g x)) - (norm (f x))" by simp + also have "norm (g x) - norm (f x) \ norm (f x + g x)" + by (subst add.commute) (rule norm_diff_ineq) + finally have "1/2 * (norm (g x)) \ norm (f x + g x)" by simp + } note B = this + + show "g \ L F (\x. f x + g x)" + apply (rule bigI[of "2"], simp) + using landau_o.smallD[OF assms A] apply eventually_elim + using B apply (simp add: algebra_simps) + done +next + assume [simp]: "R = (\x y. x \ y)" + show "g \ L F (\x. f x + g x)" + proof (rule bigI[of "1/2"]) + show "eventually (\x. R (norm (g x)) (1/2 * norm (f x + g x))) F" + using landau_o.smallD[OF assms zero_less_one] + proof eventually_elim + case (elim x) + have "norm (f x + g x) \ norm (f x) + norm (g x)" by (rule norm_triangle_ineq) + also note elim + finally show ?case by simp + qed + qed simp_all +qed + +end + + + +lemma bigomega_iff_bigo: "g \ \[F](f) \ f \ O[F](g)" +proof + assume "f \ O[F](g)" + then guess c by (elim landau_o.bigE) + thus "g \ \[F](f)" by (intro landau_omega.bigI[of "inverse c"]) (simp_all add: field_simps) +next + assume "g \ \[F](f)" + then guess c by (elim landau_omega.bigE) + thus "f \ O[F](g)" by (intro landau_o.bigI[of "inverse c"]) (simp_all add: field_simps) +qed + +lemma smallomega_iff_smallo: "g \ \[F](f) \ f \ o[F](g)" +proof + assume "f \ o[F](g)" + from landau_o.smallD[OF this, of "inverse c" for c] + show "g \ \[F](f)" by (intro landau_omega.smallI) (simp_all add: field_simps) +next + assume "g \ \[F](f)" + from landau_omega.smallD[OF this, of "inverse c" for c] + show "f \ o[F](g)" by (intro landau_o.smallI) (simp_all add: field_simps) +qed + + +context landau_pair +begin + +lemma big_mono: + "eventually (\x. R (norm (f x)) (norm (g x))) F \ f \ L F (g)" + by (rule bigI[OF zero_less_one]) simp + +lemma big_mult: + assumes "f1 \ L F (g1)" "f2 \ L F (g2)" + shows "(\x. f1 x * f2 x) \ L F (\x. g1 x * g2 x)" +proof- + from assms(1) guess c1 by (elim bigE) note c1 = this + from assms(2) guess c2 by (elim bigE) note c2 = this + + from c1(1) and c2(1) have "c1 * c2 > 0" by simp + moreover have "eventually (\x. R (norm (f1 x * f2 x)) (c1 * c2 * norm (g1 x * g2 x))) F" + using c1(2) c2(2) + proof eventually_elim + case (elim x) + show ?case + proof (cases rule: R_E) + case le + have "norm (f1 x) * norm (f2 x) \ (c1 * norm (g1 x)) * (c2 * norm (g2 x))" + using elim le c1(1) c2(1) by (intro mult_mono mult_nonneg_nonneg) auto + with le show ?thesis by (simp add: le norm_mult mult_ac) + next + case ge + have "(c1 * norm (g1 x)) * (c2 * norm (g2 x)) \ norm (f1 x) * norm (f2 x)" + using elim ge c1(1) c2(1) by (intro mult_mono mult_nonneg_nonneg) auto + with ge show ?thesis by (simp_all add: norm_mult mult_ac) + qed + qed + ultimately show ?thesis by (rule bigI) +qed + +lemma small_big_mult: + assumes "f1 \ l F (g1)" "f2 \ L F (g2)" + shows "(\x. f1 x * f2 x) \ l F (\x. g1 x * g2 x)" +proof (rule smallI) + fix c1 :: real assume c1: "c1 > 0" + from assms(2) guess c2 by (elim bigE) note c2 = this + with c1 assms(1) have "eventually (\x. R (norm (f1 x)) (c1 * inverse c2 * norm (g1 x))) F" + by (auto intro!: smallD) + thus "eventually (\x. R (norm (f1 x * f2 x)) (c1 * norm (g1 x * g2 x))) F" using c2(2) + proof eventually_elim + case (elim x) + show ?case + proof (cases rule: R_E) + case le + have "norm (f1 x) * norm (f2 x) \ (c1 * inverse c2 * norm (g1 x)) * (c2 * norm (g2 x))" + using elim le c1(1) c2(1) by (intro mult_mono mult_nonneg_nonneg) auto + with le c2(1) show ?thesis by (simp add: le norm_mult field_simps) + next + case ge + have "norm (f1 x) * norm (f2 x) \ (c1 * inverse c2 * norm (g1 x)) * (c2 * norm (g2 x))" + using elim ge c1(1) c2(1) by (intro mult_mono mult_nonneg_nonneg) auto + with ge c2(1) show ?thesis by (simp add: ge norm_mult field_simps) + qed + qed +qed + +lemma big_small_mult: + "f1 \ L F (g1) \ f2 \ l F (g2) \ (\x. f1 x * f2 x) \ l F (\x. g1 x * g2 x)" + by (subst (1 2) mult.commute) (rule small_big_mult) + +lemma small_mult: "f1 \ l F (g1) \ f2 \ l F (g2) \ (\x. f1 x * f2 x) \ l F (\x. g1 x * g2 x)" + by (rule small_big_mult, assumption, rule small_imp_big) + +lemmas mult = big_mult small_big_mult big_small_mult small_mult + + +sublocale big: landau_symbol L L' Lr +proof + have L: "L = bigo \ L = bigomega" + by (rule R_E) (auto simp: bigo_def L_def bigomega_def fun_eq_iff) + { + fix c :: 'b and F and f :: "'a \ 'b" assume "c \ 0" + hence "(\x. c * f x) \ L F f" by (intro bigI[of "norm c"]) (simp_all add: norm_mult) + } note A = this + { + fix c :: 'b and F and f :: "'a \ 'b" assume "c \ 0" + from `c \ 0` and A[of c f] and A[of "inverse c" "\x. c * f x"] + show "L F (\x. c * f x) = L F f" by (intro equalityI big_subsetI) (simp_all add: field_simps) + } + { + fix c :: 'b and F and f g :: "'a \ 'b" assume "c \ 0" + from `c \ 0` and A[of c f] and A[of "inverse c" "\x. c * f x"] + have "(\x. c * f x) \ L F f" "f \ L F (\x. c * f x)" by (simp_all add: field_simps) + thus "((\x. c * f x) \ L F g) = (f \ L F g)" by (intro iffI) (erule (1) big_trans)+ + } + { + fix f g :: "'a \ 'b" and F assume A: "f \ L F (g)" + assume B: "eventually (\x. f x \ 0) F" "eventually (\x. g x \ 0) F" + from A guess c by (elim bigE) note c = this + from c(2) B have "eventually (\x. R (norm (inverse (g x))) (c * norm (inverse (f x)))) F" + by eventually_elim (rule R_E, insert c(1), simp_all add: field_simps norm_inverse norm_divide) + with c(1) show "(\x. inverse (g x)) \ L F (\x. inverse (f x))" by (rule bigI) + } + { + fix f g :: "'a \ 'b" and F assume "f \ o[F](g)" + with plus_aux show "L F g \ L F (\x. f x + g x)" by (blast intro!: big_subsetI) + } + { + fix f g :: "'a \ 'b" and F assume A: "eventually (\x. f x = g x) F" + show "L F (f) = L F (g)" unfolding L_def + + thm eventually_subst A + by (subst eventually_subst'[OF A]) (rule refl) + } + { + fix f g h :: "'a \ 'b" and F assume A: "eventually (\x. f x = g x) F" + show "f \ L F (h) \ g \ L F (h)" unfolding L_def mem_Collect_eq + by (subst (1) eventually_subst'[OF A]) (rule refl) + } + { + fix f g :: "'a \ 'b" and F assume "f \ L F g" thus "L F f \ L F g" by (rule big_subsetI) + } + { + fix f g :: "'a \ 'b" and F assume A: "f \ \[F](g)" + with A L show "L F (f) = L F (g)" unfolding bigtheta_def + by (intro equalityI big_subsetI) (auto simp: bigomega_iff_bigo) + fix h:: "'a \ 'b" + show "f \ L F (h) \ g \ L F (h)" by (rule disjE[OF L]) + (insert A, auto simp: bigtheta_def bigomega_iff_bigo intro: landau_o.big_trans) + } + { + fix f g h :: "'a \ 'b" and F assume "f \ L F g" + thus "(\x. h x * f x) \ L F (\x. h x * g x)" by (intro big_mult) simp + } + { + fix f g h :: "'a \ 'b" and F assume "f \ L F g" "g \ L F h" + thus "f \ L F (h)" by (rule big_trans) + } + { + fix f g :: "'a \ 'b" and h :: "'c \ 'a" and F G + assume "f \ L F g" and "filterlim h F G" + thus "(\x. f (h x)) \ L' G (\x. g (h x))" by (auto simp: L_def L'_def filterlim_iff) + } + { + fix f g :: "'a \ 'b" and F G :: "'a filter" + assume "f \ L F g" "f \ L G g" + from this [THEN bigE] guess c1 c2 . note c12 = this + define c where "c = (if R c1 c2 then c2 else c1)" + from c12 have c: "R c1 c" "R c2 c" "c > 0" by (auto simp: c_def dest: R_linear) + with c12(2,4) have "eventually (\x. R (norm (f x)) (c * norm (g x))) F" + "eventually (\x. R (norm (f x)) (c * norm (g x))) G" + by (force elim: eventually_mono intro: R_trans[OF _ R_mult_right_mono])+ + with c show "f \ L (sup F G) g" by (auto simp: L_def eventually_sup) + } + { + fix f g :: "'a \ 'b" and h :: "'c \ 'a" and F G :: "'a filter" + assume "(f \ L F g)" + thus "((\x. f (h x)) \ L' (filtercomap h F) (\x. g (h x)))" + unfolding L_def L'_def by auto + } +qed (auto simp: L_def Lr_def eventually_filtermap L'_def + intro: filter_leD exI[of _ "1::real"]) + +sublocale small: landau_symbol l l' lr +proof + { + fix c :: 'b and f :: "'a \ 'b" and F assume "c \ 0" + hence "(\x. c * f x) \ L F f" by (intro bigI[of "norm c"]) (simp_all add: norm_mult) + } note A = this + { + fix c :: 'b and f :: "'a \ 'b" and F assume "c \ 0" + from `c \ 0` and A[of c f] and A[of "inverse c" "\x. c * f x"] + show "l F (\x. c * f x) = l F f" + by (intro equalityI small_subsetI) (simp_all add: field_simps) + } + { + fix c :: 'b and f g :: "'a \ 'b" and F assume "c \ 0" + from `c \ 0` and A[of c f] and A[of "inverse c" "\x. c * f x"] + have "(\x. c * f x) \ L F f" "f \ L F (\x. c * f x)" by (simp_all add: field_simps) + thus "((\x. c * f x) \ l F g) = (f \ l F g)" by (intro iffI) (erule (1) big_small_trans)+ + } + { + fix f g :: "'a \ 'b" and F assume "f \ o[F](g)" + with plus_aux show "l F g \ l F (\x. f x + g x)" by (blast intro!: small_subsetI) + } + { + fix f g :: "'a \ 'b" and F assume A: "f \ l F (g)" + assume B: "eventually (\x. f x \ 0) F" "eventually (\x. g x \ 0) F" + show "(\x. inverse (g x)) \ l F (\x. inverse (f x))" + proof (rule smallI) + fix c :: real assume c: "c > 0" + from B smallD[OF A c] + show "eventually (\x. R (norm (inverse (g x))) (c * norm (inverse (f x)))) F" + by eventually_elim (rule R_E, simp_all add: field_simps norm_inverse norm_divide) + qed + } + { + fix f g :: "'a \ 'b" and F assume A: "eventually (\x. f x = g x) F" + show "l F (f) = l F (g)" unfolding l_def by (subst eventually_subst'[OF A]) (rule refl) + } + { + fix f g h :: "'a \ 'b" and F assume A: "eventually (\x. f x = g x) F" + show "f \ l F (h) \ g \ l F (h)" unfolding l_def mem_Collect_eq + by (subst (1) eventually_subst'[OF A]) (rule refl) + } + { + fix f g :: "'a \ 'b" and F assume "f \ l F g" + thus "l F f \ l F g" by (intro small_subsetI small_imp_big) + } + { + fix f g :: "'a \ 'b" and F assume A: "f \ \[F](g)" + have L: "L = bigo \ L = bigomega" + by (rule R_E) (auto simp: bigo_def L_def bigomega_def fun_eq_iff) + with A show "l F (f) = l F (g)" unfolding bigtheta_def + by (intro equalityI small_subsetI) (auto simp: bigomega_iff_bigo) + have l: "l = smallo \ l = smallomega" + by (rule R_E) (auto simp: smallo_def l_def smallomega_def fun_eq_iff) + fix h:: "'a \ 'b" + show "f \ l F (h) \ g \ l F (h)" by (rule disjE[OF l]) + (insert A, auto simp: bigtheta_def bigomega_iff_bigo smallomega_iff_smallo + intro: landau_o.big_small_trans landau_o.small_big_trans) + } + { + fix f g h :: "'a \ 'b" and F assume "f \ l F g" + thus "(\x. h x * f x) \ l F (\x. h x * g x)" by (intro big_small_mult) simp + } + { + fix f g h :: "'a \ 'b" and F assume "f \ l F g" "g \ l F h" + thus "f \ l F (h)" by (rule small_trans) + } + { + fix f g :: "'a \ 'b" and h :: "'c \ 'a" and F G + assume "f \ l F g" and "filterlim h F G" + thus "(\x. f (h x)) \ l' G (\x. g (h x))" + by (auto simp: l_def l'_def filterlim_iff) + } + { + fix f g :: "'a \ 'b" and h :: "'c \ 'a" and F G :: "'a filter" + assume "(f \ l F g)" + thus "((\x. f (h x)) \ l' (filtercomap h F) (\x. g (h x)))" + unfolding l_def l'_def by auto + } +qed (auto simp: l_def lr_def eventually_filtermap l'_def eventually_sup intro: filter_leD) + + +text {* These rules allow chaining of Landau symbol propositions in Isar with "also".*} + +lemma big_mult_1: "f \ L F (g) \ (\_. 1) \ L F (h) \ f \ L F (\x. g x * h x)" + and big_mult_1': "(\_. 1) \ L F (g) \ f \ L F (h) \ f \ L F (\x. g x * h x)" + and small_mult_1: "f \ l F (g) \ (\_. 1) \ L F (h) \ f \ l F (\x. g x * h x)" + and small_mult_1': "(\_. 1) \ L F (g) \ f \ l F (h) \ f \ l F (\x. g x * h x)" + and small_mult_1'': "f \ L F (g) \ (\_. 1) \ l F (h) \ f \ l F (\x. g x * h x)" + and small_mult_1''': "(\_. 1) \ l F (g) \ f \ L F (h) \ f \ l F (\x. g x * h x)" + by (drule (1) big.mult big_small_mult small_big_mult, simp)+ + +lemma big_1_mult: "f \ L F (g) \ h \ L F (\_. 1) \ (\x. f x * h x) \ L F (g)" + and big_1_mult': "h \ L F (\_. 1) \ f \ L F (g) \ (\x. f x * h x) \ L F (g)" + and small_1_mult: "f \ l F (g) \ h \ L F (\_. 1) \ (\x. f x * h x) \ l F (g)" + and small_1_mult': "h \ L F (\_. 1) \ f \ l F (g) \ (\x. f x * h x) \ l F (g)" + and small_1_mult'': "f \ L F (g) \ h \ l F (\_. 1) \ (\x. f x * h x) \ l F (g)" + and small_1_mult''': "h \ l F (\_. 1) \ f \ L F (g) \ (\x. f x * h x) \ l F (g)" + by (drule (1) big.mult big_small_mult small_big_mult, simp)+ + +lemmas mult_1_trans = + big_mult_1 big_mult_1' small_mult_1 small_mult_1' small_mult_1'' small_mult_1''' + big_1_mult big_1_mult' small_1_mult small_1_mult' small_1_mult'' small_1_mult''' + +lemma big_equal_iff_bigtheta: "L F (f) = L F (g) \ f \ \[F](g)" +proof + have L: "L = bigo \ L = bigomega" + by (rule R_E) (auto simp: fun_eq_iff L_def bigo_def bigomega_def) + fix f g :: "'a \ 'b" assume "L F (f) = L F (g)" + with big_refl[of f F] big_refl[of g F] have "f \ L F (g)" "g \ L F (f)" by simp_all + thus "f \ \[F](g)" using L unfolding bigtheta_def by (auto simp: bigomega_iff_bigo) +qed (rule big.cong_bigtheta) + +lemma big_prod: + assumes "\x. x \ A \ f x \ L F (g x)" + shows "(\y. \x\A. f x y) \ L F (\y. \x\A. g x y)" + using assms by (induction A rule: infinite_finite_induct) (auto intro!: big.mult) + +lemma big_prod_in_1: + assumes "\x. x \ A \ f x \ L F (\_. 1)" + shows "(\y. \x\A. f x y) \ L F (\_. 1)" + using assms by (induction A rule: infinite_finite_induct) (auto intro!: big.mult_in_1) + +end + + +context landau_symbol +begin + +lemma plus_absorb1: + assumes "f \ o[F](g)" + shows "L F (\x. f x + g x) = L F (g)" +proof (intro equalityI) + from plus_subset1 and assms show "L F g \ L F (\x. f x + g x)" . + from landau_o.small.plus_subset1[OF assms] and assms have "(\x. -f x) \ o[F](\x. f x + g x)" + by (auto simp: landau_o.small.uminus_in_iff) + from plus_subset1[OF this] show "L F (\x. f x + g x) \ L F (g)" by simp +qed + +lemma plus_absorb2: "g \ o[F](f) \ L F (\x. f x + g x) = L F (f)" + using plus_absorb1[of g F f] by (simp add: add.commute) + +lemma diff_absorb1: "f \ o[F](g) \ L F (\x. f x - g x) = L F (g)" + by (simp only: diff_conv_add_uminus plus_absorb1 landau_o.small.uminus uminus) + +lemma diff_absorb2: "g \ o[F](f) \ L F (\x. f x - g x) = L F (f)" + by (simp only: diff_conv_add_uminus plus_absorb2 landau_o.small.uminus_in_iff) + +lemmas absorb = plus_absorb1 plus_absorb2 diff_absorb1 diff_absorb2 + +end + + +lemma bigthetaI [intro]: "f \ O[F](g) \ f \ \[F](g) \ f \ \[F](g)" + unfolding bigtheta_def bigomega_def by blast + +lemma bigthetaD1 [dest]: "f \ \[F](g) \ f \ O[F](g)" + and bigthetaD2 [dest]: "f \ \[F](g) \ f \ \[F](g)" + unfolding bigtheta_def bigo_def bigomega_def by blast+ + +lemma bigtheta_refl [simp]: "f \ \[F](f)" + unfolding bigtheta_def by simp + +lemma bigtheta_sym: "f \ \[F](g) \ g \ \[F](f)" + unfolding bigtheta_def by (auto simp: bigomega_iff_bigo) + +lemmas landau_flip = + bigomega_iff_bigo[symmetric] smallomega_iff_smallo[symmetric] + bigomega_iff_bigo smallomega_iff_smallo bigtheta_sym + + +interpretation landau_theta: landau_symbol bigtheta bigtheta bigtheta +proof + fix f g :: "'a \ 'b" and F + assume "f \ o[F](g)" + hence "O[F](g) \ O[F](\x. f x + g x)" "\[F](g) \ \[F](\x. f x + g x)" + by (rule landau_o.big.plus_subset1 landau_omega.big.plus_subset1)+ + thus "\[F](g) \ \[F](\x. f x + g x)" unfolding bigtheta_def by blast +next + fix f g :: "'a \ 'b" and F + assume "f \ \[F](g)" + thus A: "\[F](f) = \[F](g)" + apply (subst (1 2) bigtheta_def) + apply (subst landau_o.big.cong_bigtheta landau_omega.big.cong_bigtheta, assumption)+ + apply (rule refl) + done + thus "\[F](f) \ \[F](g)" by simp + fix h :: "'a \ 'b" + show "f \ \[F](h) \ g \ \[F](h)" by (subst (1 2) bigtheta_sym) (simp add: A) +next + fix f g h :: "'a \ 'b" and F + assume "f \ \[F](g)" "g \ \[F](h)" + thus "f \ \[F](h)" unfolding bigtheta_def + by (blast intro: landau_o.big.trans landau_omega.big.trans) +next + fix f :: "'a \ 'b" and F1 F2 :: "'a filter" + assume "F1 \ F2" + thus "\[F2](f) \ \[F1](f)" + by (auto simp: bigtheta_def intro: landau_o.big.filter_mono landau_omega.big.filter_mono) +qed (auto simp: bigtheta_def landau_o.big.norm_iff + landau_o.big.cmult landau_omega.big.cmult + landau_o.big.cmult_in_iff landau_omega.big.cmult_in_iff + landau_o.big.in_cong landau_omega.big.in_cong + landau_o.big.mult landau_omega.big.mult + landau_o.big.inverse landau_omega.big.inverse + landau_o.big.compose landau_omega.big.compose + landau_o.big.bot' landau_omega.big.bot' + landau_o.big.in_filtermap_iff landau_omega.big.in_filtermap_iff + landau_o.big.sup landau_omega.big.sup + landau_o.big.filtercomap landau_omega.big.filtercomap + dest: landau_o.big.cong landau_omega.big.cong) + +lemmas landau_symbols = + landau_o.big.landau_symbol_axioms landau_o.small.landau_symbol_axioms + landau_omega.big.landau_symbol_axioms landau_omega.small.landau_symbol_axioms + landau_theta.landau_symbol_axioms + +lemma bigoI [intro]: + assumes "eventually (\x. (norm (f x)) \ c * (norm (g x))) F" + shows "f \ O[F](g)" +proof (rule landau_o.bigI) + show "max 1 c > 0" by simp + note assms + moreover have "\x. c * (norm (g x)) \ max 1 c * (norm (g x))" by (simp add: mult_right_mono) + ultimately show "eventually (\x. (norm (f x)) \ max 1 c * (norm (g x))) F" + by (auto elim!: eventually_mono dest: order.trans) +qed + +lemma smallomegaD [dest]: + assumes "f \ \[F](g)" + shows "eventually (\x. (norm (f x)) \ c * (norm (g x))) F" +proof (cases "c > 0") + case False + show ?thesis + by (intro always_eventually allI, rule order.trans[of _ 0]) + (insert False, auto intro!: mult_nonpos_nonneg) +qed (blast dest: landau_omega.smallD[OF assms, of c]) + + +lemma bigthetaI': + assumes "c1 > 0" "c2 > 0" + assumes "eventually (\x. c1 * (norm (g x)) \ (norm (f x)) \ (norm (f x)) \ c2 * (norm (g x))) F" + shows "f \ \[F](g)" +apply (rule bigthetaI) +apply (rule landau_o.bigI[OF assms(2)]) using assms(3) apply (eventually_elim, simp) +apply (rule landau_omega.bigI[OF assms(1)]) using assms(3) apply (eventually_elim, simp) +done + +lemma bigthetaI_cong: "eventually (\x. f x = g x) F \ f \ \[F](g)" + by (intro bigthetaI'[of 1 1]) (auto elim!: eventually_mono) + +lemma (in landau_symbol) ev_eq_trans1: + "f \ L F (\x. g x (h x)) \ eventually (\x. h x = h' x) F \ f \ L F (\x. g x (h' x))" + by (rule bigtheta_trans1[OF _ bigthetaI_cong]) (auto elim!: eventually_mono) + +lemma (in landau_symbol) ev_eq_trans2: + "eventually (\x. f x = f' x) F \ (\x. g x (f' x)) \ L F (h) \ (\x. g x (f x)) \ L F (h)" + by (rule bigtheta_trans2[OF bigthetaI_cong]) (auto elim!: eventually_mono) + +declare landau_o.smallI landau_omega.bigI landau_omega.smallI [intro] +declare landau_o.bigE landau_omega.bigE [elim] +declare landau_o.smallD + +lemma (in landau_symbol) bigtheta_trans1': + "f \ L F (g) \ h \ \[F](g) \ f \ L F (h)" + by (subst cong_bigtheta[symmetric]) (simp add: bigtheta_sym) + +lemma (in landau_symbol) bigtheta_trans2': + "g \ \[F](f) \ g \ L F (h) \ f \ L F (h)" + by (rule bigtheta_trans2, subst bigtheta_sym) + +lemma bigo_bigomega_trans: "f \ O[F](g) \ h \ \[F](g) \ f \ O[F](h)" + and bigo_smallomega_trans: "f \ O[F](g) \ h \ \[F](g) \ f \ o[F](h)" + and smallo_bigomega_trans: "f \ o[F](g) \ h \ \[F](g) \ f \ o[F](h)" + and smallo_smallomega_trans: "f \ o[F](g) \ h \ \[F](g) \ f \ o[F](h)" + and bigomega_bigo_trans: "f \ \[F](g) \ h \ O[F](g) \ f \ \[F](h)" + and bigomega_smallo_trans: "f \ \[F](g) \ h \ o[F](g) \ f \ \[F](h)" + and smallomega_bigo_trans: "f \ \[F](g) \ h \ O[F](g) \ f \ \[F](h)" + and smallomega_smallo_trans: "f \ \[F](g) \ h \ o[F](g) \ f \ \[F](h)" + by (unfold bigomega_iff_bigo smallomega_iff_smallo) + (erule (1) landau_o.big_trans landau_o.big_small_trans landau_o.small_big_trans + landau_o.big_trans landau_o.small_trans)+ + +lemmas landau_trans_lift [trans] = + landau_symbols[THEN landau_symbol.lift_trans] + landau_symbols[THEN landau_symbol.lift_trans'] + landau_symbols[THEN landau_symbol.lift_trans_bigtheta] + landau_symbols[THEN landau_symbol.lift_trans_bigtheta'] + +lemmas landau_mult_1_trans [trans] = + landau_o.mult_1_trans landau_omega.mult_1_trans + +lemmas landau_trans [trans] = + landau_symbols[THEN landau_symbol.bigtheta_trans1] + landau_symbols[THEN landau_symbol.bigtheta_trans2] + landau_symbols[THEN landau_symbol.bigtheta_trans1'] + landau_symbols[THEN landau_symbol.bigtheta_trans2'] + landau_symbols[THEN landau_symbol.ev_eq_trans1] + landau_symbols[THEN landau_symbol.ev_eq_trans2] + + landau_o.big_trans landau_o.small_trans landau_o.small_big_trans landau_o.big_small_trans + landau_omega.big_trans landau_omega.small_trans + landau_omega.small_big_trans landau_omega.big_small_trans + + bigo_bigomega_trans bigo_smallomega_trans smallo_bigomega_trans smallo_smallomega_trans + bigomega_bigo_trans bigomega_smallo_trans smallomega_bigo_trans smallomega_smallo_trans + +lemma bigtheta_inverse [simp]: + shows "(\x. inverse (f x)) \ \[F](\x. inverse (g x)) \ f \ \[F](g)" +proof- + { + fix f g :: "'a \ 'b" and F assume A: "f \ \[F](g)" + then guess c1 c2 :: real unfolding bigtheta_def by (elim landau_o.bigE landau_omega.bigE IntE) + note c = this + from c(3) have "inverse c2 > 0" by simp + moreover from c(2,4) + have "eventually (\x. norm (inverse (f x)) \ inverse c2 * norm (inverse (g x))) F" + proof eventually_elim + fix x assume A: "(norm (f x)) \ c1 * (norm (g x))" "c2 * (norm (g x)) \ (norm (f x))" + from A c(1,3) have "f x = 0 \ g x = 0" by (auto simp: field_simps mult_le_0_iff) + with A c(1,3) show "norm (inverse (f x)) \ inverse c2 * norm (inverse (g x))" + by (force simp: field_simps norm_inverse norm_divide) + qed + ultimately have "(\x. inverse (f x)) \ O[F](\x. inverse (g x))" by (rule landau_o.bigI) + } + thus ?thesis unfolding bigtheta_def + by (force simp: bigomega_iff_bigo bigtheta_sym) +qed + +lemma bigtheta_divide: + assumes "f1 \ \(f2)" "g1 \ \(g2)" + shows "(\x. f1 x / g1 x) \ \(\x. f2 x / g2 x)" + by (subst (1 2) divide_inverse, intro landau_theta.mult) (simp_all add: bigtheta_inverse assms) + +lemma eventually_nonzero_bigtheta: + assumes "f \ \[F](g)" + shows "eventually (\x. f x \ 0) F \ eventually (\x. g x \ 0) F" +proof- + { + fix f g :: "'a \ 'b" and F assume A: "f \ \[F](g)" and B: "eventually (\x. f x \ 0) F" + from A guess c1 c2 unfolding bigtheta_def by (elim landau_o.bigE landau_omega.bigE IntE) + from B this(2,4) have "eventually (\x. g x \ 0) F" by eventually_elim auto + } + with assms show ?thesis by (force simp: bigtheta_sym) +qed + + +subsection {* Landau symbols and limits *} + +lemma bigoI_tendsto_norm: + fixes f g + assumes "((\x. norm (f x / g x)) \ c) F" + assumes "eventually (\x. g x \ 0) F" + shows "f \ O[F](g)" +proof (rule bigoI) + from assms have "eventually (\x. dist (norm (f x / g x)) c < 1) F" + using tendstoD by force + thus "eventually (\x. (norm (f x)) \ (norm c + 1) * (norm (g x))) F" + unfolding dist_real_def using assms(2) + proof eventually_elim + case (elim x) + have "(norm (f x)) - norm c * (norm (g x)) \ norm ((norm (f x)) - c * (norm (g x)))" + unfolding norm_mult [symmetric] using norm_triangle_ineq2[of "norm (f x)" "c * norm (g x)"] + by (simp add: norm_mult abs_mult) + also from elim have "\ = norm (norm (g x)) * norm (norm (f x / g x) - c)" + unfolding norm_mult [symmetric] by (simp add: algebra_simps norm_divide) + also from elim have "norm (norm (f x / g x) - c) \ 1" by simp + hence "norm (norm (g x)) * norm (norm (f x / g x) - c) \ norm (norm (g x)) * 1" + by (rule mult_left_mono) simp_all + finally show ?case by (simp add: algebra_simps) + qed +qed + +lemma bigoI_tendsto: + assumes "((\x. f x / g x) \ c) F" + assumes "eventually (\x. g x \ 0) F" + shows "f \ O[F](g)" + using assms by (rule bigoI_tendsto_norm[OF tendsto_norm]) + +lemma bigomegaI_tendsto_norm: + assumes c_not_0: "(c::real) \ 0" + assumes lim: "((\x. norm (f x / g x)) \ c) F" + shows "f \ \[F](g)" +proof (cases "F = bot") + case False + show ?thesis + proof (rule landau_omega.bigI) + from lim have "c \ 0" by (rule tendsto_lowerbound) (insert False, simp_all) + with c_not_0 have "c > 0" by simp + with c_not_0 show "c/2 > 0" by simp + from lim have ev: "\\. \ > 0 \ eventually (\x. norm (norm (f x / g x) - c) < \) F" + by (subst (asm) tendsto_iff) (simp add: dist_real_def) + from ev[OF `c/2 > 0`] show "eventually (\x. (norm (f x)) \ c/2 * (norm (g x))) F" + proof (eventually_elim) + fix x assume B: "norm (norm (f x / g x) - c) < c / 2" + from B have g: "g x \ 0" by auto + from B have "-c/2 < -norm (norm (f x / g x) - c)" by simp + also have "... \ norm (f x / g x) - c" by simp + finally show "(norm (f x)) \ c/2 * (norm (g x))" using g + by (simp add: field_simps norm_mult norm_divide) + qed + qed +qed simp + +lemma bigomegaI_tendsto: + assumes c_not_0: "(c::real) \ 0" + assumes lim: "((\x. f x / g x) \ c) F" + shows "f \ \[F](g)" + by (rule bigomegaI_tendsto_norm[OF _ tendsto_norm, of c]) (insert assms, simp_all) + +lemma smallomegaI_filterlim_at_top_norm: + assumes lim: "filterlim (\x. norm (f x / g x)) at_top F" + shows "f \ \[F](g)" +proof (rule landau_omega.smallI) + fix c :: real assume c_pos: "c > 0" + from lim have ev: "eventually (\x. norm (f x / g x) \ c) F" + by (subst (asm) filterlim_at_top) simp + thus "eventually (\x. (norm (f x)) \ c * (norm (g x))) F" + proof eventually_elim + fix x assume A: "norm (f x / g x) \ c" + from A c_pos have "g x \ 0" by auto + with A show "(norm (f x)) \ c * (norm (g x))" by (simp add: field_simps norm_divide) + qed +qed + +lemma smallomegaI_filterlim_at_infinity: + assumes lim: "filterlim (\x. f x / g x) at_infinity F" + shows "f \ \[F](g)" +proof (rule smallomegaI_filterlim_at_top_norm) + from lim show "filterlim (\x. norm (f x / g x)) at_top F" + by (rule filterlim_at_infinity_imp_norm_at_top) +qed + +lemma smallomegaD_filterlim_at_top_norm: + assumes "f \ \[F](g)" + assumes "eventually (\x. g x \ 0) F" + shows "LIM x F. norm (f x / g x) :> at_top" +proof (subst filterlim_at_top_gt, clarify) + fix c :: real assume c: "c > 0" + from landau_omega.smallD[OF assms(1) this] assms(2) + show "eventually (\x. norm (f x / g x) \ c) F" + by eventually_elim (simp add: field_simps norm_divide) +qed + +lemma smallomegaD_filterlim_at_infinity: + assumes "f \ \[F](g)" + assumes "eventually (\x. g x \ 0) F" + shows "LIM x F. f x / g x :> at_infinity" + using assms by (intro filterlim_norm_at_top_imp_at_infinity smallomegaD_filterlim_at_top_norm) + +lemma smallomega_1_conv_filterlim: "f \ \[F](\_. 1) \ filterlim f at_infinity F" + by (auto intro: smallomegaI_filterlim_at_infinity dest: smallomegaD_filterlim_at_infinity) + +lemma smalloI_tendsto: + assumes lim: "((\x. f x / g x) \ 0) F" + assumes "eventually (\x. g x \ 0) F" + shows "f \ o[F](g)" +proof (rule landau_o.smallI) + fix c :: real assume c_pos: "c > 0" + from c_pos and lim have ev: "eventually (\x. norm (f x / g x) < c) F" + by (subst (asm) tendsto_iff) (simp add: dist_real_def) + with assms(2) show "eventually (\x. (norm (f x)) \ c * (norm (g x))) F" + by eventually_elim (simp add: field_simps norm_divide) +qed + +lemma smalloD_tendsto: + assumes "f \ o[F](g)" + shows "((\x. f x / g x) \ 0) F" +unfolding tendsto_iff +proof clarify + fix e :: real assume e: "e > 0" + hence "e/2 > 0" by simp + from landau_o.smallD[OF assms this] show "eventually (\x. dist (f x / g x) 0 < e) F" + proof eventually_elim + fix x assume "(norm (f x)) \ e/2 * (norm (g x))" + with e have "dist (f x / g x) 0 \ e/2" + by (cases "g x = 0") (simp_all add: dist_real_def norm_divide field_simps) + also from e have "... < e" by simp + finally show "dist (f x / g x) 0 < e" by simp + qed +qed + +lemma bigthetaI_tendsto_norm: + assumes c_not_0: "(c::real) \ 0" + assumes lim: "((\x. norm (f x / g x)) \ c) F" + shows "f \ \[F](g)" +proof (rule bigthetaI) + from c_not_0 have "\c\ > 0" by simp + with lim have "eventually (\x. norm (norm (f x / g x) - c) < \c\) F" + by (subst (asm) tendsto_iff) (simp add: dist_real_def) + hence g: "eventually (\x. g x \ 0) F" by eventually_elim (auto simp add: field_simps) + + from lim g show "f \ O[F](g)" by (rule bigoI_tendsto_norm) + from c_not_0 and lim show "f \ \[F](g)" by (rule bigomegaI_tendsto_norm) +qed + +lemma bigthetaI_tendsto: + assumes c_not_0: "(c::real) \ 0" + assumes lim: "((\x. f x / g x) \ c) F" + shows "f \ \[F](g)" + using assms by (intro bigthetaI_tendsto_norm[OF _ tendsto_norm, of "c"]) simp_all + +lemma tendsto_add_smallo: + assumes "(f1 \ a) F" + assumes "f2 \ o[F](f1)" + shows "((\x. f1 x + f2 x) \ a) F" +proof (subst filterlim_cong[OF refl refl]) + from landau_o.smallD[OF assms(2) zero_less_one] + have "eventually (\x. norm (f2 x) \ norm (f1 x)) F" by simp + thus "eventually (\x. f1 x + f2 x = f1 x * (1 + f2 x / f1 x)) F" + by eventually_elim (auto simp: field_simps) +next + from assms(1) show "((\x. f1 x * (1 + f2 x / f1 x)) \ a) F" + by (force intro: tendsto_eq_intros smalloD_tendsto[OF assms(2)]) +qed + +lemma tendsto_diff_smallo: + shows "(f1 \ a) F \ f2 \ o[F](f1) \ ((\x. f1 x - f2 x) \ a) F" + using tendsto_add_smallo[of f1 a F "\x. -f2 x"] by simp + +lemma tendsto_add_smallo_iff: + assumes "f2 \ o[F](f1)" + shows "(f1 \ a) F \ ((\x. f1 x + f2 x) \ a) F" +proof + assume "((\x. f1 x + f2 x) \ a) F" + hence "((\x. f1 x + f2 x - f2 x) \ a) F" + by (rule tendsto_diff_smallo) (simp add: landau_o.small.plus_absorb2 assms) + thus "(f1 \ a) F" by simp +qed (rule tendsto_add_smallo[OF _ assms]) + +lemma tendsto_diff_smallo_iff: + shows "f2 \ o[F](f1) \ (f1 \ a) F \ ((\x. f1 x - f2 x) \ a) F" + using tendsto_add_smallo_iff[of "\x. -f2 x" F f1 a] by simp + +lemma tendsto_divide_smallo: + assumes "((\x. f1 x / g1 x) \ a) F" + assumes "f2 \ o[F](f1)" "g2 \ o[F](g1)" + assumes "eventually (\x. g1 x \ 0) F" + shows "((\x. (f1 x + f2 x) / (g1 x + g2 x)) \ a) F" (is "(?f \ _) _") +proof (subst tendsto_cong) + let ?f' = "\x. (f1 x / g1 x) * (1 + f2 x / f1 x) / (1 + g2 x / g1 x)" + + have "(?f' \ a * (1 + 0) / (1 + 0)) F" + by (rule tendsto_mult tendsto_divide tendsto_add assms tendsto_const + smalloD_tendsto[OF assms(2)] smalloD_tendsto[OF assms(3)])+ simp_all + thus "(?f' \ a) F" by simp + + have "(1/2::real) > 0" by simp + from landau_o.smallD[OF assms(2) this] landau_o.smallD[OF assms(3) this] + have "eventually (\x. norm (f2 x) \ norm (f1 x)/2) F" + "eventually (\x. norm (g2 x) \ norm (g1 x)/2) F" by simp_all + with assms(4) show "eventually (\x. ?f x = ?f' x) F" + proof eventually_elim + fix x assume A: "norm (f2 x) \ norm (f1 x)/2" and + B: "norm (g2 x) \ norm (g1 x)/2" and C: "g1 x \ 0" + show "?f x = ?f' x" + proof (cases "f1 x = 0") + assume D: "f1 x \ 0" + from D have "f1 x + f2 x = f1 x * (1 + f2 x/f1 x)" by (simp add: field_simps) + moreover from C have "g1 x + g2 x = g1 x * (1 + g2 x/g1 x)" by (simp add: field_simps) + ultimately have "?f x = (f1 x * (1 + f2 x/f1 x)) / (g1 x * (1 + g2 x/g1 x))" by (simp only:) + also have "... = ?f' x" by simp + finally show ?thesis . + qed (insert A, simp) + qed +qed + + +lemma bigo_powr: + fixes f :: "'a \ real" + assumes "f \ O[F](g)" "p \ 0" + shows "(\x. \f x\ powr p) \ O[F](\x. \g x\ powr p)" +proof- + from assms(1) guess c by (elim landau_o.bigE landau_omega.bigE IntE) + note c = this + from c(2) assms(2) have "eventually (\x. (norm (f x)) powr p \ (c * (norm (g x))) powr p) F" + by (auto elim!: eventually_mono intro!: powr_mono2) + thus "(\x. \f x\ powr p) \ O[F](\x. \g x\ powr p)" using c(1) + by (intro bigoI[of _ "c powr p"]) (simp_all add: powr_mult) +qed + +lemma smallo_powr: + fixes f :: "'a \ real" + assumes "f \ o[F](g)" "p > 0" + shows "(\x. \f x\ powr p) \ o[F](\x. \g x\ powr p)" +proof (rule landau_o.smallI) + fix c :: real assume c: "c > 0" + hence "c powr (1/p) > 0" by simp + from landau_o.smallD[OF assms(1) this] + show "eventually (\x. norm (\f x\ powr p) \ c * norm (\g x\ powr p)) F" + proof eventually_elim + fix x assume "(norm (f x)) \ c powr (1 / p) * (norm (g x))" + with assms(2) have "(norm (f x)) powr p \ (c powr (1 / p) * (norm (g x))) powr p" + by (intro powr_mono2) simp_all + also from assms(2) c have "... = c * (norm (g x)) powr p" + by (simp add: field_simps powr_mult powr_powr) + finally show "norm (\f x\ powr p) \ c * norm (\g x\ powr p)" by simp + qed +qed + +lemma smallo_powr_nonneg: + fixes f :: "'a \ real" + assumes "f \ o[F](g)" "p > 0" "eventually (\x. f x \ 0) F" "eventually (\x. g x \ 0) F" + shows "(\x. f x powr p) \ o[F](\x. g x powr p)" +proof - + from assms(3) have "(\x. f x powr p) \ \[F](\x. \f x\ powr p)" + by (intro bigthetaI_cong) (auto elim!: eventually_mono) + also have "(\x. \f x\ powr p) \ o[F](\x. \g x\ powr p)" by (intro smallo_powr) fact+ + also from assms(4) have "(\x. \g x\ powr p) \ \[F](\x. g x powr p)" + by (intro bigthetaI_cong) (auto elim!: eventually_mono) + finally show ?thesis . +qed + +lemma bigtheta_powr: + fixes f :: "'a \ real" + shows "f \ \[F](g) \ (\x. \f x\ powr p) \ \[F](\x. \g x\ powr p)" +apply (cases "p < 0") +apply (subst bigtheta_inverse[symmetric], subst (1 2) powr_minus[symmetric]) +unfolding bigtheta_def apply (auto simp: bigomega_iff_bigo intro!: bigo_powr) +done + +lemma bigo_powr_nonneg: + fixes f :: "'a \ real" + assumes "f \ O[F](g)" "p \ 0" "eventually (\x. f x \ 0) F" "eventually (\x. g x \ 0) F" + shows "(\x. f x powr p) \ O[F](\x. g x powr p)" +proof - + from assms(3) have "(\x. f x powr p) \ \[F](\x. \f x\ powr p)" + by (intro bigthetaI_cong) (auto elim!: eventually_mono) + also have "(\x. \f x\ powr p) \ O[F](\x. \g x\ powr p)" by (intro bigo_powr) fact+ + also from assms(4) have "(\x. \g x\ powr p) \ \[F](\x. g x powr p)" + by (intro bigthetaI_cong) (auto elim!: eventually_mono) + finally show ?thesis . +qed + +lemma zero_in_smallo [simp]: "(\_. 0) \ o[F](f)" + by (intro landau_o.smallI) simp_all + +lemma zero_in_bigo [simp]: "(\_. 0) \ O[F](f)" + by (intro landau_o.bigI[of 1]) simp_all + +lemma in_bigomega_zero [simp]: "f \ \[F](\x. 0)" + by (rule landau_omega.bigI[of 1]) simp_all + +lemma in_smallomega_zero [simp]: "f \ \[F](\x. 0)" + by (simp add: smallomega_iff_smallo) + + +lemma in_smallo_zero_iff [simp]: "f \ o[F](\_. 0) \ eventually (\x. f x = 0) F" +proof + assume "f \ o[F](\_. 0)" + from landau_o.smallD[OF this, of 1] show "eventually (\x. f x = 0) F" by simp +next + assume "eventually (\x. f x = 0) F" + hence "\c>0. eventually (\x. (norm (f x)) \ c * \0\) F" by simp + thus "f \ o[F](\_. 0)" unfolding smallo_def by simp +qed + +lemma in_bigo_zero_iff [simp]: "f \ O[F](\_. 0) \ eventually (\x. f x = 0) F" +proof + assume "f \ O[F](\_. 0)" + thus "eventually (\x. f x = 0) F" by (elim landau_o.bigE) simp +next + assume "eventually (\x. f x = 0) F" + hence "eventually (\x. (norm (f x)) \ 1 * \0\) F" by simp + thus "f \ O[F](\_. 0)" by (intro landau_o.bigI[of 1]) simp_all +qed + +lemma zero_in_smallomega_iff [simp]: "(\_. 0) \ \[F](f) \ eventually (\x. f x = 0) F" + by (simp add: smallomega_iff_smallo) + +lemma zero_in_bigomega_iff [simp]: "(\_. 0) \ \[F](f) \ eventually (\x. f x = 0) F" + by (simp add: bigomega_iff_bigo) + +lemma zero_in_bigtheta_iff [simp]: "(\_. 0) \ \[F](f) \ eventually (\x. f x = 0) F" + unfolding bigtheta_def by simp + +lemma in_bigtheta_zero_iff [simp]: "f \ \[F](\x. 0) \ eventually (\x. f x = 0) F" + unfolding bigtheta_def by simp + + +lemma cmult_in_bigo_iff [simp]: "(\x. c * f x) \ O[F](g) \ c = 0 \ f \ O[F](g)" + and cmult_in_bigo_iff' [simp]: "(\x. f x * c) \ O[F](g) \ c = 0 \ f \ O[F](g)" + and cmult_in_smallo_iff [simp]: "(\x. c * f x) \ o[F](g) \ c = 0 \ f \ o[F](g)" + and cmult_in_smallo_iff' [simp]: "(\x. f x * c) \ o[F](g) \ c = 0 \ f \ o[F](g)" + by (cases "c = 0", simp, simp)+ + +lemma bigo_const [simp]: "(\_. c) \ O[F](\_. 1)" by (rule bigoI[of _ "norm c"]) simp + +lemma bigo_const_iff [simp]: "(\_. c1) \ O[F](\_. c2) \ F = bot \ c1 = 0 \ c2 \ 0" + by (cases "c1 = 0"; cases "c2 = 0") + (auto simp: bigo_def eventually_False intro: exI[of _ 1] exI[of _ "norm c1 / norm c2"]) + +lemma bigomega_const_iff [simp]: "(\_. c1) \ \[F](\_. c2) \ F = bot \ c1 \ 0 \ c2 = 0" + by (cases "c1 = 0"; cases "c2 = 0") + (auto simp: bigomega_def eventually_False mult_le_0_iff + intro: exI[of _ 1] exI[of _ "norm c1 / norm c2"]) + +lemma smallo_real_nat_transfer: + "(f :: real \ real) \ o(g) \ (\x::nat. f (real x)) \ o(\x. g (real x))" + by (rule landau_o.small.compose[OF _ filterlim_real_sequentially]) + +lemma bigo_real_nat_transfer: + "(f :: real \ real) \ O(g) \ (\x::nat. f (real x)) \ O(\x. g (real x))" + by (rule landau_o.big.compose[OF _ filterlim_real_sequentially]) + +lemma smallomega_real_nat_transfer: + "(f :: real \ real) \ \(g) \ (\x::nat. f (real x)) \ \(\x. g (real x))" + by (rule landau_omega.small.compose[OF _ filterlim_real_sequentially]) + +lemma bigomega_real_nat_transfer: + "(f :: real \ real) \ \(g) \ (\x::nat. f (real x)) \ \(\x. g (real x))" + by (rule landau_omega.big.compose[OF _ filterlim_real_sequentially]) + +lemma bigtheta_real_nat_transfer: + "(f :: real \ real) \ \(g) \ (\x::nat. f (real x)) \ \(\x. g (real x))" + unfolding bigtheta_def using bigo_real_nat_transfer bigomega_real_nat_transfer by blast + +lemmas landau_real_nat_transfer [intro] = + bigo_real_nat_transfer smallo_real_nat_transfer bigomega_real_nat_transfer + smallomega_real_nat_transfer bigtheta_real_nat_transfer + + +lemma landau_symbol_if_at_top_eq [simp]: + assumes "landau_symbol L L' Lr" + shows "L at_top (\x::'a::linordered_semidom. if x = a then f x else g x) = L at_top (g)" +apply (rule landau_symbol.cong[OF assms]) +using less_add_one[of a] apply (auto intro: eventually_mono eventually_ge_at_top[of "a + 1"]) +done + +lemmas landau_symbols_if_at_top_eq [simp] = landau_symbols[THEN landau_symbol_if_at_top_eq] + + + +lemma sum_in_smallo: + assumes "f \ o[F](h)" "g \ o[F](h)" + shows "(\x. f x + g x) \ o[F](h)" "(\x. f x - g x) \ o[F](h)" +proof- + { + fix f g assume fg: "f \ o[F](h)" "g \ o[F](h)" + have "(\x. f x + g x) \ o[F](h)" + proof (rule landau_o.smallI) + fix c :: real assume "c > 0" + hence "c/2 > 0" by simp + from fg[THEN landau_o.smallD[OF _ this]] + show "eventually (\x. norm (f x + g x) \ c * (norm (h x))) F" + by eventually_elim (auto intro: order.trans[OF norm_triangle_ineq]) + qed + } + from this[of f g] this[of f "\x. -g x"] assms + show "(\x. f x + g x) \ o[F](h)" "(\x. f x - g x) \ o[F](h)" by simp_all +qed + +lemma big_sum_in_smallo: + assumes "\x. x \ A \ f x \ o[F](g)" + shows "(\x. sum (\y. f y x) A) \ o[F](g)" + using assms by (induction A rule: infinite_finite_induct) (auto intro: sum_in_smallo) + +lemma sum_in_bigo: + assumes "f \ O[F](h)" "g \ O[F](h)" + shows "(\x. f x + g x) \ O[F](h)" "(\x. f x - g x) \ O[F](h)" +proof- + { + fix f g assume fg: "f \ O[F](h)" "g \ O[F](h)" + from fg(1) guess c1 by (elim landau_o.bigE) note c1 = this + from fg(2) guess c2 by (elim landau_o.bigE) note c2 = this + from c1(2) c2(2) have "eventually (\x. norm (f x + g x) \ (c1 + c2) * (norm (h x))) F" + by eventually_elim (auto simp: algebra_simps intro: order.trans[OF norm_triangle_ineq]) + hence "(\x. f x + g x) \ O[F](h)" by (rule bigoI) + } + from this[of f g] this[of f "\x. -g x"] assms + show "(\x. f x + g x) \ O[F](h)" "(\x. f x - g x) \ O[F](h)" by simp_all +qed + +lemma big_sum_in_bigo: + assumes "\x. x \ A \ f x \ O[F](g)" + shows "(\x. sum (\y. f y x) A) \ O[F](g)" + using assms by (induction A rule: infinite_finite_induct) (auto intro: sum_in_bigo) + +context landau_symbol +begin + +lemma mult_cancel_left: + assumes "f1 \ \[F](g1)" and "eventually (\x. g1 x \ 0) F" + notes [trans] = bigtheta_trans1 bigtheta_trans2 + shows "(\x. f1 x * f2 x) \ L F (\x. g1 x * g2 x) \ f2 \ L F (g2)" +proof + assume A: "(\x. f1 x * f2 x) \ L F (\x. g1 x * g2 x)" + from assms have nz: "eventually (\x. f1 x \ 0) F" by (simp add: eventually_nonzero_bigtheta) + hence "f2 \ \[F](\x. f1 x * f2 x / f1 x)" + by (intro bigthetaI_cong) (auto elim!: eventually_mono) + also from A assms nz have "(\x. f1 x * f2 x / f1 x) \ L F (\x. g1 x * g2 x / f1 x)" + by (intro divide_right) simp_all + also from assms nz have "(\x. g1 x * g2 x / f1 x) \ \[F](\x. g1 x * g2 x / g1 x)" + by (intro landau_theta.mult landau_theta.divide) (simp_all add: bigtheta_sym) + also from assms have "(\x. g1 x * g2 x / g1 x) \ \[F](g2)" + by (intro bigthetaI_cong) (auto elim!: eventually_mono) + finally show "f2 \ L F (g2)" . +next + assume "f2 \ L F (g2)" + hence "(\x. f1 x * f2 x) \ L F (\x. f1 x * g2 x)" by (rule mult_left) + also have "(\x. f1 x * g2 x) \ \[F](\x. g1 x * g2 x)" + by (intro landau_theta.mult_right assms) + finally show "(\x. f1 x * f2 x) \ L F (\x. g1 x * g2 x)" . +qed + +lemma mult_cancel_right: + assumes "f2 \ \[F](g2)" and "eventually (\x. g2 x \ 0) F" + shows "(\x. f1 x * f2 x) \ L F (\x. g1 x * g2 x) \ f1 \ L F (g1)" + by (subst (1 2) mult.commute) (rule mult_cancel_left[OF assms]) + +lemma divide_cancel_right: + assumes "f2 \ \[F](g2)" and "eventually (\x. g2 x \ 0) F" + shows "(\x. f1 x / f2 x) \ L F (\x. g1 x / g2 x) \ f1 \ L F (g1)" + by (subst (1 2) divide_inverse, intro mult_cancel_right bigtheta_inverse) (simp_all add: assms) + +lemma divide_cancel_left: + assumes "f1 \ \[F](g1)" and "eventually (\x. g1 x \ 0) F" + shows "(\x. f1 x / f2 x) \ L F (\x. g1 x / g2 x) \ + (\x. inverse (f2 x)) \ L F (\x. inverse (g2 x))" + by (simp only: divide_inverse mult_cancel_left[OF assms]) + +end + + +lemma powr_smallo_iff: + assumes "filterlim g at_top F" "F \ bot" + shows "(\x. g x powr p :: real) \ o[F](\x. g x powr q) \ p < q" +proof- + from assms have "eventually (\x. g x \ 1) F" by (force simp: filterlim_at_top) + hence A: "eventually (\x. g x \ 0) F" by eventually_elim simp + have B: "(\x. g x powr q) \ O[F](\x. g x powr p) \ (\x. g x powr p) \ o[F](\x. g x powr q)" + proof + assume "(\x. g x powr q) \ O[F](\x. g x powr p)" "(\x. g x powr p) \ o[F](\x. g x powr q)" + from landau_o.big_small_asymmetric[OF this] have "eventually (\x. g x = 0) F" by simp + with A have "eventually (\_::'a. False) F" by eventually_elim simp + thus False by (simp add: eventually_False assms) + qed + show ?thesis + proof (cases p q rule: linorder_cases) + assume "p < q" + hence "(\x. g x powr p) \ o[F](\x. g x powr q)" using assms A + by (auto intro!: smalloI_tendsto tendsto_neg_powr simp: powr_diff [symmetric] ) + with `p < q` show ?thesis by auto + next + assume "p = q" + hence "(\x. g x powr q) \ O[F](\x. g x powr p)" by (auto intro!: bigthetaD1) + with B `p = q` show ?thesis by auto + next + assume "p > q" + hence "(\x. g x powr q) \ O[F](\x. g x powr p)" using assms A + by (auto intro!: smalloI_tendsto tendsto_neg_powr landau_o.small_imp_big simp: powr_diff [symmetric] ) + with B `p > q` show ?thesis by auto + qed +qed + +lemma powr_bigo_iff: + assumes "filterlim g at_top F" "F \ bot" + shows "(\x. g x powr p :: real) \ O[F](\x. g x powr q) \ p \ q" +proof- + from assms have "eventually (\x. g x \ 1) F" by (force simp: filterlim_at_top) + hence A: "eventually (\x. g x \ 0) F" by eventually_elim simp + have B: "(\x. g x powr q) \ o[F](\x. g x powr p) \ (\x. g x powr p) \ O[F](\x. g x powr q)" + proof + assume "(\x. g x powr q) \ o[F](\x. g x powr p)" "(\x. g x powr p) \ O[F](\x. g x powr q)" + from landau_o.small_big_asymmetric[OF this] have "eventually (\x. g x = 0) F" by simp + with A have "eventually (\_::'a. False) F" by eventually_elim simp + thus False by (simp add: eventually_False assms) + qed + show ?thesis + proof (cases p q rule: linorder_cases) + assume "p < q" + hence "(\x. g x powr p) \ o[F](\x. g x powr q)" using assms A + by (auto intro!: smalloI_tendsto tendsto_neg_powr simp: powr_diff [symmetric] ) + with `p < q` show ?thesis by (auto intro: landau_o.small_imp_big) + next + assume "p = q" + hence "(\x. g x powr q) \ O[F](\x. g x powr p)" by (auto intro!: bigthetaD1) + with B `p = q` show ?thesis by auto + next + assume "p > q" + hence "(\x. g x powr q) \ o[F](\x. g x powr p)" using assms A + by (auto intro!: smalloI_tendsto tendsto_neg_powr simp: powr_diff [symmetric] ) + with B `p > q` show ?thesis by (auto intro: landau_o.small_imp_big) + qed +qed + +lemma powr_bigtheta_iff: + assumes "filterlim g at_top F" "F \ bot" + shows "(\x. g x powr p :: real) \ \[F](\x. g x powr q) \ p = q" + using assms unfolding bigtheta_def by (auto simp: bigomega_iff_bigo powr_bigo_iff) + + +subsection \Flatness of real functions\ + +text \ + Given two real-valued functions $f$ and $g$, we say that $f$ is flatter than $g$ if + any power of $f(x)$ is asymptotically dominated by any positive power of $g(x)$. This is + a useful notion since, given two products of powers of functions sorted by flatness, we can + compare them asymptotically by simply comparing the exponent lists lexicographically. + + A simple sufficient criterion for flatness it that $\ln f(x) \in o(\ln g(x))$, which we show + now. +\ +lemma ln_smallo_imp_flat: + fixes f g :: "real \ real" + assumes lim_f: "filterlim f at_top at_top" + assumes lim_g: "filterlim g at_top at_top" + assumes ln_o_ln: "(\x. ln (f x)) \ o(\x. ln (g x))" + assumes q: "q > 0" + shows "(\x. f x powr p) \ o(\x. g x powr q)" +proof (rule smalloI_tendsto) + from lim_f have "eventually (\x. f x > 0) at_top" + by (simp add: filterlim_at_top_dense) + hence f_nz: "eventually (\x. f x \ 0) at_top" by eventually_elim simp + + from lim_g have g_gt_1: "eventually (\x. g x > 1) at_top" + by (simp add: filterlim_at_top_dense) + hence g_nz: "eventually (\x. g x \ 0) at_top" by eventually_elim simp + thus "eventually (\x. g x powr q \ 0) at_top" + by eventually_elim simp + + have eq: "eventually (\x. q * (p/q * (ln (f x) / ln (g x)) - 1) * ln (g x) = + p * ln (f x) - q * ln (g x)) at_top" + using g_gt_1 by eventually_elim (insert q, simp_all add: field_simps) + have "filterlim (\x. q * (p/q * (ln (f x) / ln (g x)) - 1) * ln (g x)) at_bot at_top" + by (insert q) + (rule filterlim_tendsto_neg_mult_at_bot tendsto_mult + tendsto_const tendsto_diff smalloD_tendsto[OF ln_o_ln] lim_g + filterlim_compose[OF ln_at_top] | simp)+ + hence "filterlim (\x. p * ln (f x) - q * ln (g x)) at_bot at_top" + by (subst (asm) filterlim_cong[OF refl refl eq]) + hence *: "((\x. exp (p * ln (f x) - q * ln (g x))) \ 0) at_top" + by (rule filterlim_compose[OF exp_at_bot]) + have eq: "eventually (\x. exp (p * ln (f x) - q * ln (g x)) = f x powr p / g x powr q) at_top" + using f_nz g_nz by eventually_elim (simp add: powr_def exp_diff) + show "((\x. f x powr p / g x powr q) \ 0) at_top" + using * by (subst (asm) filterlim_cong[OF refl refl eq]) +qed + +lemma ln_smallo_imp_flat': + fixes f g :: "real \ real" + assumes lim_f: "filterlim f at_top at_top" + assumes lim_g: "filterlim g at_top at_top" + assumes ln_o_ln: "(\x. ln (f x)) \ o(\x. ln (g x))" + assumes q: "q < 0" + shows "(\x. g x powr q) \ o(\x. f x powr p)" +proof - + from lim_f lim_g have "eventually (\x. f x > 0) at_top" "eventually (\x. g x > 0) at_top" + by (simp_all add: filterlim_at_top_dense) + hence "eventually (\x. f x \ 0) at_top" "eventually (\x. g x \ 0) at_top" + by (auto elim: eventually_mono) + moreover from assms have "(\x. f x powr -p) \ o(\x. g x powr -q)" + by (intro ln_smallo_imp_flat assms) simp_all + ultimately show ?thesis unfolding powr_minus + by (simp add: landau_o.small.inverse_cancel) +qed + + +subsection \Asymptotic Equivalence\ + +(* TODO Move *) +lemma Lim_eventually: "eventually (\x. f x = c) F \ filterlim f (nhds c) F" + by (simp add: eventually_mono eventually_nhds_x_imp_x filterlim_iff) + +named_theorems asymp_equiv_intros +named_theorems asymp_equiv_simps + +definition asymp_equiv :: "('a \ ('b :: real_normed_field)) \ 'a filter \ ('a \ 'b) \ bool" + ("_ \[_] _" [51, 10, 51] 50) + where "f \[F] g \ ((\x. if f x = 0 \ g x = 0 then 1 else f x / g x) \ 1) F" + +abbreviation (input) asymp_equiv_at_top where + "asymp_equiv_at_top f g \ f \[at_top] g" + +bundle asymp_equiv_notation +begin +notation asymp_equiv_at_top (infix "\" 50) +end + +lemma asymp_equivI: "((\x. if f x = 0 \ g x = 0 then 1 else f x / g x) \ 1) F \ f \[F] g" + by (simp add: asymp_equiv_def) + +lemma asymp_equivD: "f \[F] g \ ((\x. if f x = 0 \ g x = 0 then 1 else f x / g x) \ 1) F" + by (simp add: asymp_equiv_def) + +lemma asymp_equiv_filtermap_iff: + "f \[filtermap h F] g \ (\x. f (h x)) \[F] (\x. g (h x))" + by (simp add: asymp_equiv_def filterlim_filtermap) + +lemma asymp_equiv_refl [simp, asymp_equiv_intros]: "f \[F] f" +proof (intro asymp_equivI) + have "eventually (\x. 1 = (if f x = 0 \ f x = 0 then 1 else f x / f x)) F" + by (intro always_eventually) simp + moreover have "((\_. 1) \ 1) F" by simp + ultimately show "((\x. if f x = 0 \ f x = 0 then 1 else f x / f x) \ 1) F" + by (rule Lim_transform_eventually) +qed + +lemma asymp_equiv_symI: + assumes "f \[F] g" + shows "g \[F] f" + using tendsto_inverse[OF asymp_equivD[OF assms]] + by (auto intro!: asymp_equivI simp: if_distrib conj_commute cong: if_cong) + +lemma asymp_equiv_sym: "f \[F] g \ g \[F] f" + by (blast intro: asymp_equiv_symI) + +lemma asymp_equivI': + assumes "((\x. f x / g x) \ 1) F" + shows "f \[F] g" +proof (cases "F = bot") + case False + have "eventually (\x. f x \ 0) F" + proof (rule ccontr) + assume "\eventually (\x. f x \ 0) F" + hence "frequently (\x. f x = 0) F" by (simp add: frequently_def) + hence "frequently (\x. f x / g x = 0) F" by (auto elim!: frequently_elim1) + from limit_frequently_eq[OF False this assms] show False by simp_all + qed + hence "eventually (\x. f x / g x = (if f x = 0 \ g x = 0 then 1 else f x / g x)) F" + by eventually_elim simp + from this and assms show "f \[F] g" unfolding asymp_equiv_def + by (rule Lim_transform_eventually) +qed (simp_all add: asymp_equiv_def) + + +lemma asymp_equiv_cong: + assumes "eventually (\x. f1 x = f2 x) F" "eventually (\x. g1 x = g2 x) F" + shows "f1 \[F] g1 \ f2 \[F] g2" + unfolding asymp_equiv_def +proof (rule tendsto_cong, goal_cases) + case 1 + from assms show ?case by eventually_elim simp +qed + +lemma asymp_equiv_eventually_zeros: + fixes f g :: "'a \ 'b :: real_normed_field" + assumes "f \[F] g" + shows "eventually (\x. f x = 0 \ g x = 0) F" +proof - + let ?h = "\x. if f x = 0 \ g x = 0 then 1 else f x / g x" + have "eventually (\x. x \ 0) (nhds (1::'b))" + by (rule t1_space_nhds) auto + hence "eventually (\x. x \ 0) (filtermap ?h F)" + using assms unfolding asymp_equiv_def filterlim_def + by (rule filter_leD [rotated]) + hence "eventually (\x. ?h x \ 0) F" by (simp add: eventually_filtermap) + thus ?thesis by eventually_elim (auto split: if_splits) +qed + +lemma asymp_equiv_transfer: + assumes "f1 \[F] g1" "eventually (\x. f1 x = f2 x) F" "eventually (\x. g1 x = g2 x) F" + shows "f2 \[F] g2" + using assms(1) asymp_equiv_cong[OF assms(2,3)] by simp + +lemma asymp_equiv_transfer_trans [trans]: + assumes "(\x. f x (h1 x)) \[F] (\x. g x (h1 x))" + assumes "eventually (\x. h1 x = h2 x) F" + shows "(\x. f x (h2 x)) \[F] (\x. g x (h2 x))" + by (rule asymp_equiv_transfer[OF assms(1)]) (insert assms(2), auto elim!: eventually_mono) + +lemma asymp_equiv_trans [trans]: + fixes f g h + assumes "f \[F] g" "g \[F] h" + shows "f \[F] h" +proof - + let ?T = "\f g x. if f x = 0 \ g x = 0 then 1 else f x / g x" + from assms[THEN asymp_equiv_eventually_zeros] + have "eventually (\x. ?T f g x * ?T g h x = ?T f h x) F" by eventually_elim simp + moreover from tendsto_mult[OF assms[THEN asymp_equivD]] + have "((\x. ?T f g x * ?T g h x) \ 1) F" by simp + ultimately show ?thesis unfolding asymp_equiv_def by (rule Lim_transform_eventually) +qed + +lemma asymp_equiv_trans_lift1 [trans]: + assumes "a \[F] f b" "b \[F] c" "\c d. c \[F] d \ f c \[F] f d" + shows "a \[F] f c" + using assms by (blast intro: asymp_equiv_trans) + +lemma asymp_equiv_trans_lift2 [trans]: + assumes "f a \[F] b" "a \[F] c" "\c d. c \[F] d \ f c \[F] f d" + shows "f c \[F] b" + using asymp_equiv_symI[OF assms(3)[OF assms(2)]] assms(1) + by (blast intro: asymp_equiv_trans) + +lemma asymp_equivD_const: + assumes "f \[F] (\_. c)" + shows "(f \ c) F" +proof (cases "c = 0") + case False + with tendsto_mult_right[OF asymp_equivD[OF assms], of c] show ?thesis by simp +next + case True + with asymp_equiv_eventually_zeros[OF assms] show ?thesis + by (simp add: Lim_eventually) +qed + +lemma asymp_equiv_refl_ev: + assumes "eventually (\x. f x = g x) F" + shows "f \[F] g" + by (intro asymp_equivI Lim_eventually) + (insert assms, auto elim!: eventually_mono) + +lemma asymp_equiv_sandwich: + fixes f g h :: "'a \ 'b :: {real_normed_field, order_topology, linordered_field}" + assumes "eventually (\x. f x \ 0) F" + assumes "eventually (\x. f x \ g x) F" + assumes "eventually (\x. g x \ h x) F" + assumes "f \[F] h" + shows "g \[F] f" "g \[F] h" +proof - + show "g \[F] f" + proof (rule asymp_equivI, rule tendsto_sandwich) + from assms(1-3) asymp_equiv_eventually_zeros[OF assms(4)] + show "eventually (\n. (if h n = 0 \ f n = 0 then 1 else h n / f n) \ + (if g n = 0 \ f n = 0 then 1 else g n / f n)) F" + by eventually_elim (auto intro!: divide_right_mono) + from assms(1-3) asymp_equiv_eventually_zeros[OF assms(4)] + show "eventually (\n. 1 \ + (if g n = 0 \ f n = 0 then 1 else g n / f n)) F" + by eventually_elim (auto intro!: divide_right_mono) + qed (insert asymp_equiv_symI[OF assms(4)], simp_all add: asymp_equiv_def) + also note \f \[F] h\ + finally show "g \[F] h" . +qed + +lemma asymp_equiv_imp_eventually_same_sign: + fixes f g :: "real \ real" + assumes "f \[F] g" + shows "eventually (\x. sgn (f x) = sgn (g x)) F" +proof - + from assms have "((\x. sgn (if f x = 0 \ g x = 0 then 1 else f x / g x)) \ sgn 1) F" + unfolding asymp_equiv_def by (rule tendsto_sgn) simp_all + from order_tendstoD(1)[OF this, of "1/2"] + have "eventually (\x. sgn (if f x = 0 \ g x = 0 then 1 else f x / g x) > 1/2) F" + by simp + thus "eventually (\x. sgn (f x) = sgn (g x)) F" + proof eventually_elim + case (elim x) + thus ?case + by (cases "f x" "0 :: real" rule: linorder_cases; + cases "g x" "0 :: real" rule: linorder_cases) simp_all + qed +qed + +lemma + fixes f g :: "_ \ real" + assumes "f \[F] g" + shows asymp_equiv_eventually_same_sign: "eventually (\x. sgn (f x) = sgn (g x)) F" (is ?th1) + and asymp_equiv_eventually_neg_iff: "eventually (\x. f x < 0 \ g x < 0) F" (is ?th2) + and asymp_equiv_eventually_pos_iff: "eventually (\x. f x > 0 \ g x > 0) F" (is ?th3) +proof - + from assms have "filterlim (\x. if f x = 0 \ g x = 0 then 1 else f x / g x) (nhds 1) F" + by (rule asymp_equivD) + from order_tendstoD(1)[OF this zero_less_one] + show ?th1 ?th2 ?th3 + by (eventually_elim; force simp: sgn_if divide_simps split: if_splits)+ +qed + +lemma asymp_equiv_tendsto_transfer: + assumes "f \[F] g" and "(f \ c) F" + shows "(g \ c) F" +proof - + let ?h = "\x. (if g x = 0 \ f x = 0 then 1 else g x / f x) * f x" + have "eventually (\x. ?h x = g x) F" + using asymp_equiv_eventually_zeros[OF assms(1)] by eventually_elim simp + moreover from assms(1) have "g \[F] f" by (rule asymp_equiv_symI) + hence "filterlim (\x. if g x = 0 \ f x = 0 then 1 else g x / f x) (nhds 1) F" + by (rule asymp_equivD) + from tendsto_mult[OF this assms(2)] have "(?h \ c) F" by simp + ultimately show ?thesis by (rule Lim_transform_eventually) +qed + +lemma tendsto_asymp_equiv_cong: + assumes "f \[F] g" + shows "(f \ c) F \ (g \ c) F" +proof - + { + fix f g :: "'a \ 'b" + assume *: "f \[F] g" "(g \ c) F" + have "eventually (\x. g x * (if f x = 0 \ g x = 0 then 1 else f x / g x) = f x) F" + using asymp_equiv_eventually_zeros[OF *(1)] by eventually_elim simp + moreover have "((\x. g x * (if f x = 0 \ g x = 0 then 1 else f x / g x)) \ c * 1) F" + by (intro tendsto_intros asymp_equivD *) + ultimately have "(f \ c * 1) F" + by (rule Lim_transform_eventually) + } + from this[of f g] this[of g f] assms show ?thesis by (auto simp: asymp_equiv_sym) +qed + + +lemma smallo_imp_eventually_sgn: + fixes f g :: "real \ real" + assumes "g \ o(f)" + shows "eventually (\x. sgn (f x + g x) = sgn (f x)) at_top" +proof - + have "0 < (1/2 :: real)" by simp + from landau_o.smallD[OF assms, OF this] + have "eventually (\x. \g x\ \ 1/2 * \f x\) at_top" by simp + thus ?thesis + proof eventually_elim + case (elim x) + thus ?case + by (cases "f x" "0::real" rule: linorder_cases; + cases "f x + g x" "0::real" rule: linorder_cases) simp_all + qed +qed + +context +begin + +private lemma asymp_equiv_add_rightI: + assumes "f \[F] g" "h \ o[F](g)" + shows "(\x. f x + h x) \[F] g" +proof - + let ?T = "\f g x. if f x = 0 \ g x = 0 then 1 else f x / g x" + from landau_o.smallD[OF assms(2) zero_less_one] + have ev: "eventually (\x. g x = 0 \ h x = 0) F" by eventually_elim auto + have "(\x. f x + h x) \[F] g \ ((\x. ?T f g x + h x / g x) \ 1) F" + unfolding asymp_equiv_def using ev + by (intro tendsto_cong) (auto elim!: eventually_mono simp: divide_simps) + also have "\ \ ((\x. ?T f g x + h x / g x) \ 1 + 0) F" by simp + also have \ by (intro tendsto_intros asymp_equivD assms smalloD_tendsto) + finally show "(\x. f x + h x) \[F] g" . +qed + +lemma asymp_equiv_add_right [asymp_equiv_simps]: + assumes "h \ o[F](g)" + shows "(\x. f x + h x) \[F] g \ f \[F] g" +proof + assume "(\x. f x + h x) \[F] g" + from asymp_equiv_add_rightI[OF this, of "\x. -h x"] assms show "f \[F] g" + by simp +qed (simp_all add: asymp_equiv_add_rightI assms) + +end + +lemma asymp_equiv_add_left [asymp_equiv_simps]: + assumes "h \ o[F](g)" + shows "(\x. h x + f x) \[F] g \ f \[F] g" + using asymp_equiv_add_right[OF assms] by (simp add: add.commute) + +lemma asymp_equiv_add_right' [asymp_equiv_simps]: + assumes "h \ o[F](g)" + shows "g \[F] (\x. f x + h x) \ g \[F] f" + using asymp_equiv_add_right[OF assms] by (simp add: asymp_equiv_sym) + +lemma asymp_equiv_add_left' [asymp_equiv_simps]: + assumes "h \ o[F](g)" + shows "g \[F] (\x. h x + f x) \ g \[F] f" + using asymp_equiv_add_left[OF assms] by (simp add: asymp_equiv_sym) + +lemma smallo_imp_asymp_equiv: + assumes "(\x. f x - g x) \ o[F](g)" + shows "f \[F] g" +proof - + from assms have "(\x. f x - g x + g x) \[F] g" + by (subst asymp_equiv_add_left) simp_all + thus ?thesis by simp +qed + +lemma asymp_equiv_uminus [asymp_equiv_intros]: + "f \[F] g \ (\x. -f x) \[F] (\x. -g x)" + by (simp add: asymp_equiv_def cong: if_cong) + +lemma asymp_equiv_uminus_iff [asymp_equiv_simps]: + "(\x. -f x) \[F] g \ f \[F] (\x. -g x)" + by (simp add: asymp_equiv_def cong: if_cong) + +lemma asymp_equiv_mult [asymp_equiv_intros]: + fixes f1 f2 g1 g2 :: "'a \ 'b :: real_normed_field" + assumes "f1 \[F] g1" "f2 \[F] g2" + shows "(\x. f1 x * f2 x) \[F] (\x. g1 x * g2 x)" +proof - + let ?T = "\f g x. if f x = 0 \ g x = 0 then 1 else f x / g x" + let ?S = "\x. (if f1 x = 0 \ g1 x = 0 then 1 - ?T f2 g2 x + else if f2 x = 0 \ g2 x = 0 then 1 - ?T f1 g1 x else 0)" + let ?S' = "\x. ?T (\x. f1 x * f2 x) (\x. g1 x * g2 x) x - ?T f1 g1 x * ?T f2 g2 x" + { + fix f g :: "'a \ 'b" assume "f \[F] g" + have "((\x. 1 - ?T f g x) \ 0) F" + by (rule tendsto_eq_intros refl asymp_equivD[OF \f \[F] g\])+ simp_all + } note A = this + + from assms have "((\x. ?T f1 g1 x * ?T f2 g2 x) \ 1 * 1) F" + by (intro tendsto_mult asymp_equivD) + moreover { + have "eventually (\x. ?S x = ?S' x) F" + using assms[THEN asymp_equiv_eventually_zeros] by eventually_elim auto + moreover have "(?S \ 0) F" + by (intro filterlim_If assms[THEN A, THEN tendsto_mono[rotated]]) + (auto intro: le_infI1 le_infI2) + ultimately have "(?S' \ 0) F" by (rule Lim_transform_eventually) + } + ultimately have "(?T (\x. f1 x * f2 x) (\x. g1 x * g2 x) \ 1 * 1) F" + by (rule Lim_transform) + thus ?thesis by (simp add: asymp_equiv_def) +qed + +lemma asymp_equiv_power [asymp_equiv_intros]: + "f \[F] g \ (\x. f x ^ n) \[F] (\x. g x ^ n)" + by (induction n) (simp_all add: asymp_equiv_mult) + +lemma asymp_equiv_inverse [asymp_equiv_intros]: + assumes "f \[F] g" + shows "(\x. inverse (f x)) \[F] (\x. inverse (g x))" +proof - + from tendsto_inverse[OF asymp_equivD[OF assms]] + have "((\x. if f x = 0 \ g x = 0 then 1 else g x / f x) \ 1) F" + by (simp add: if_distrib cong: if_cong) + also have "(\x. if f x = 0 \ g x = 0 then 1 else g x / f x) = + (\x. if f x = 0 \ g x = 0 then 1 else inverse (f x) / inverse (g x))" + by (intro ext) (simp add: field_simps) + finally show ?thesis by (simp add: asymp_equiv_def) +qed + +lemma asymp_equiv_inverse_iff [asymp_equiv_simps]: + "(\x. inverse (f x)) \[F] (\x. inverse (g x)) \ f \[F] g" +proof + assume "(\x. inverse (f x)) \[F] (\x. inverse (g x))" + hence "(\x. inverse (inverse (f x))) \[F] (\x. inverse (inverse (g x)))" (is ?P) + by (rule asymp_equiv_inverse) + also have "?P \ f \[F] g" by (intro asymp_equiv_cong) simp_all + finally show "f \[F] g" . +qed (simp_all add: asymp_equiv_inverse) + +lemma asymp_equiv_divide [asymp_equiv_intros]: + assumes "f1 \[F] g1" "f2 \[F] g2" + shows "(\x. f1 x / f2 x) \[F] (\x. g1 x / g2 x)" + using asymp_equiv_mult[OF assms(1) asymp_equiv_inverse[OF assms(2)]] by (simp add: field_simps) + +lemma asymp_equiv_compose [asymp_equiv_intros]: + assumes "f \[G] g" "filterlim h G F" + shows "f \ h \[F] g \ h" +proof - + let ?T = "\f g x. if f x = 0 \ g x = 0 then 1 else f x / g x" + have "f \ h \[F] g \ h \ ((?T f g \ h) \ 1) F" + by (simp add: asymp_equiv_def o_def) + also have "\ \ (?T f g \ 1) (filtermap h F)" + by (rule tendsto_compose_filtermap) + also have "\" + by (rule tendsto_mono[of _ G]) (insert assms, simp_all add: asymp_equiv_def filterlim_def) + finally show ?thesis . +qed + +lemma asymp_equiv_compose': + assumes "f \[G] g" "filterlim h G F" + shows "(\x. f (h x)) \[F] (\x. g (h x))" + using asymp_equiv_compose[OF assms] by (simp add: o_def) + +lemma asymp_equiv_powr_real [asymp_equiv_intros]: + fixes f g :: "'a \ real" + assumes "f \[F] g" "eventually (\x. f x \ 0) F" "eventually (\x. g x \ 0) F" + shows "(\x. f x powr y) \[F] (\x. g x powr y)" +proof - + let ?T = "\f g x. if f x = 0 \ g x = 0 then 1 else f x / g x" + have "eventually (\x. ?T f g x powr y = ?T (\x. f x powr y) (\x. g x powr y) x) F" + using asymp_equiv_eventually_zeros[OF assms(1)] assms(2,3) + by eventually_elim (auto simp: powr_divide) + moreover have "((\x. ?T f g x powr y) \ 1 powr y) F" + by (intro tendsto_intros asymp_equivD[OF assms(1)]) simp_all + hence "((\x. ?T f g x powr y) \ 1) F" by simp + ultimately show ?thesis unfolding asymp_equiv_def by (rule Lim_transform_eventually) +qed + +lemma asymp_equiv_norm [asymp_equiv_intros]: + fixes f g :: "'a \ 'b :: real_normed_field" + assumes "f \[F] g" + shows "(\x. norm (f x)) \[F] (\x. norm (g x))" + using tendsto_norm[OF asymp_equivD[OF assms]] + by (simp add: if_distrib asymp_equiv_def norm_divide cong: if_cong) + +lemma asymp_equiv_abs_real [asymp_equiv_intros]: + fixes f g :: "'a \ real" + assumes "f \[F] g" + shows "(\x. \f x\) \[F] (\x. \g x\)" + using tendsto_rabs[OF asymp_equivD[OF assms]] + by (simp add: if_distrib asymp_equiv_def cong: if_cong) + +lemma asymp_equiv_imp_eventually_le: + assumes "f \[F] g" "c > 1" + shows "eventually (\x. norm (f x) \ c * norm (g x)) F" +proof - + from order_tendstoD(2)[OF asymp_equivD[OF asymp_equiv_norm[OF assms(1)]] assms(2)] + asymp_equiv_eventually_zeros[OF assms(1)] + show ?thesis by eventually_elim (auto split: if_splits simp: field_simps) +qed + +lemma asymp_equiv_imp_eventually_ge: + assumes "f \[F] g" "c < 1" + shows "eventually (\x. norm (f x) \ c * norm (g x)) F" +proof - + from order_tendstoD(1)[OF asymp_equivD[OF asymp_equiv_norm[OF assms(1)]] assms(2)] + asymp_equiv_eventually_zeros[OF assms(1)] + show ?thesis by eventually_elim (auto split: if_splits simp: field_simps) +qed + +lemma asymp_equiv_imp_bigo: + assumes "f \[F] g" + shows "f \ O[F](g)" +proof (rule bigoI) + have "(3/2::real) > 1" by simp + from asymp_equiv_imp_eventually_le[OF assms this] + show "eventually (\x. norm (f x) \ 3/2 * norm (g x)) F" + by eventually_elim simp +qed + +lemma asymp_equiv_imp_bigomega: + "f \[F] g \ f \ \[F](g)" + using asymp_equiv_imp_bigo[of g F f] by (simp add: asymp_equiv_sym bigomega_iff_bigo) + +lemma asymp_equiv_imp_bigtheta: + "f \[F] g \ f \ \[F](g)" + by (intro bigthetaI asymp_equiv_imp_bigo asymp_equiv_imp_bigomega) + +lemma asymp_equiv_at_infinity_transfer: + assumes "f \[F] g" "filterlim f at_infinity F" + shows "filterlim g at_infinity F" +proof - + from assms(1) have "g \ \[F](f)" by (rule asymp_equiv_imp_bigtheta[OF asymp_equiv_symI]) + also from assms have "f \ \[F](\_. 1)" by (simp add: smallomega_1_conv_filterlim) + finally show ?thesis by (simp add: smallomega_1_conv_filterlim) +qed + +lemma asymp_equiv_at_top_transfer: + fixes f g :: "_ \ real" + assumes "f \[F] g" "filterlim f at_top F" + shows "filterlim g at_top F" +proof (rule filterlim_at_infinity_imp_filterlim_at_top) + show "filterlim g at_infinity F" + by (rule asymp_equiv_at_infinity_transfer[OF assms(1) filterlim_mono[OF assms(2)]]) + (auto simp: at_top_le_at_infinity) + from assms(2) have "eventually (\x. f x > 0) F" + using filterlim_at_top_dense by blast + with asymp_equiv_eventually_pos_iff[OF assms(1)] show "eventually (\x. g x > 0) F" + by eventually_elim blast +qed + +lemma asymp_equiv_at_bot_transfer: + fixes f g :: "_ \ real" + assumes "f \[F] g" "filterlim f at_bot F" + shows "filterlim g at_bot F" + unfolding filterlim_uminus_at_bot + by (rule asymp_equiv_at_top_transfer[of "\x. -f x" F "\x. -g x"]) + (insert assms, auto simp: filterlim_uminus_at_bot asymp_equiv_uminus) + +lemma asymp_equivI'_const: + assumes "((\x. f x / g x) \ c) F" "c \ 0" + shows "f \[F] (\x. c * g x)" + using tendsto_mult[OF assms(1) tendsto_const[of "inverse c"]] assms(2) + by (intro asymp_equivI') (simp add: field_simps) + +lemma asymp_equivI'_inverse_const: + assumes "((\x. f x / g x) \ inverse c) F" "c \ 0" + shows "(\x. c * f x) \[F] g" + using tendsto_mult[OF assms(1) tendsto_const[of "c"]] assms(2) + by (intro asymp_equivI') (simp add: field_simps) + +lemma filterlim_at_bot_imp_at_infinity: "filterlim f at_bot F \ filterlim f at_infinity F" + for f :: "_ \ real" using at_bot_le_at_infinity filterlim_mono by blast + +lemma asymp_equiv_imp_diff_smallo: + assumes "f \[F] g" + shows "(\x. f x - g x) \ o[F](g)" +proof (rule landau_o.smallI) + fix c :: real assume "c > 0" + hence c: "min c 1 > 0" by simp + let ?h = "\x. if f x = 0 \ g x = 0 then 1 else f x / g x" + from assms have "((\x. ?h x - 1) \ 1 - 1) F" + by (intro tendsto_diff asymp_equivD tendsto_const) + from tendstoD[OF this c] show "eventually (\x. norm (f x - g x) \ c * norm (g x)) F" + proof eventually_elim + case (elim x) + from elim have "norm (f x - g x) \ norm (f x / g x - 1) * norm (g x)" + by (subst norm_mult [symmetric]) (auto split: if_splits simp: divide_simps) + also have "norm (f x / g x - 1) * norm (g x) \ c * norm (g x)" using elim + by (auto split: if_splits simp: mult_right_mono) + finally show ?case . + qed +qed + +lemma asymp_equiv_altdef: + "f \[F] g \ (\x. f x - g x) \ o[F](g)" + by (rule iffI[OF asymp_equiv_imp_diff_smallo smallo_imp_asymp_equiv]) + +lemma asymp_equiv_0_left_iff [simp]: "(\_. 0) \[F] f \ eventually (\x. f x = 0) F" + and asymp_equiv_0_right_iff [simp]: "f \[F] (\_. 0) \ eventually (\x. f x = 0) F" + by (simp_all add: asymp_equiv_altdef landau_o.small_refl_iff) + +lemma asymp_equiv_sandwich_real: + fixes f g l u :: "'a \ real" + assumes "l \[F] g" "u \[F] g" "eventually (\x. f x \ {l x..u x}) F" + shows "f \[F] g" + unfolding asymp_equiv_altdef +proof (rule landau_o.smallI) + fix c :: real assume c: "c > 0" + have "eventually (\x. norm (f x - g x) \ max (norm (l x - g x)) (norm (u x - g x))) F" + using assms(3) by eventually_elim auto + moreover have "eventually (\x. norm (l x - g x) \ c * norm (g x)) F" + "eventually (\x. norm (u x - g x) \ c * norm (g x)) F" + using assms(1,2) by (auto simp: asymp_equiv_altdef dest: landau_o.smallD[OF _ c]) + hence "eventually (\x. max (norm (l x - g x)) (norm (u x - g x)) \ c * norm (g x)) F" + by eventually_elim simp + ultimately show "eventually (\x. norm (f x - g x) \ c * norm (g x)) F" + by eventually_elim (rule order.trans) +qed + +lemma asymp_equiv_sandwich_real': + fixes f g l u :: "'a \ real" + assumes "f \[F] l" "f \[F] u" "eventually (\x. g x \ {l x..u x}) F" + shows "f \[F] g" + using asymp_equiv_sandwich_real[of l F f u g] assms by (simp add: asymp_equiv_sym) + +lemma asymp_equiv_sandwich_real'': + fixes f g l u :: "'a \ real" + assumes "l1 \[F] u1" "u1 \[F] l2" "l2 \[F] u2" + "eventually (\x. f x \ {l1 x..u1 x}) F" "eventually (\x. g x \ {l2 x..u2 x}) F" + shows "f \[F] g" + by (rule asymp_equiv_sandwich_real[OF asymp_equiv_sandwich_real'[OF _ _ assms(5)] + asymp_equiv_sandwich_real'[OF _ _ assms(5)] assms(4)]; + blast intro: asymp_equiv_trans assms(1,2,3))+ + +end diff -r 37974ddde928 -r b48bab511939 src/HOL/Library/Library.thy --- a/src/HOL/Library/Library.thy Tue May 22 11:05:47 2018 +0200 +++ b/src/HOL/Library/Library.thy Fri May 18 17:51:58 2018 +0200 @@ -38,6 +38,7 @@ Indicator_Function Infinite_Set IArray + Landau_Symbols Lattice_Algebras Lattice_Syntax Lattice_Constructions