src/HOL/Multivariate_Analysis/Derivative.thy
 author wenzelm Sat, 07 Apr 2012 16:41:59 +0200 changeset 47389 e8552cba702d parent 46898 1570b30ee040 child 50418 bd68cf816dd3 permissions -rw-r--r--
explicit checks stable_finished_theory/stable_command allow parallel asynchronous command transactions; tuned;
```
(*  Title:                       HOL/Multivariate_Analysis/Derivative.thy
Author:                      John Harrison
Translation from HOL Light:  Robert Himmelmann, TU Muenchen
*)

header {* Multivariate calculus in Euclidean space. *}

theory Derivative
imports Brouwer_Fixpoint Operator_Norm
begin

(* Because I do not want to type this all the time *)
lemmas linear_linear = linear_conv_bounded_linear[THEN sym]

subsection {* Derivatives *}

text {* The definition is slightly tricky since we make it work over
nets of a particular form. This lets us prove theorems generally and use
"at a" or "at a within s" for restriction to a set (1-sided on R etc.) *}

definition has_derivative :: "('a::real_normed_vector \<Rightarrow> 'b::real_normed_vector) \<Rightarrow> ('a \<Rightarrow> 'b) \<Rightarrow> ('a filter \<Rightarrow> bool)"
(infixl "(has'_derivative)" 12) where
"(f has_derivative f') net \<equiv> bounded_linear f' \<and> ((\<lambda>y. (1 / (norm (y - netlimit net))) *\<^sub>R
(f y - (f (netlimit net) + f'(y - netlimit net)))) ---> 0) net"

lemma derivative_linear[dest]:
"(f has_derivative f') net \<Longrightarrow> bounded_linear f'"
unfolding has_derivative_def by auto

lemma netlimit_at_vector:
(* TODO: move *)
fixes a :: "'a::real_normed_vector"
shows "netlimit (at a) = a"
proof (cases "\<exists>x. x \<noteq> a")
case True then obtain x where x: "x \<noteq> a" ..
have "\<not> trivial_limit (at a)"
unfolding trivial_limit_def eventually_at dist_norm
apply clarsimp
apply (rule_tac x="a + scaleR (d / 2) (sgn (x - a))" in exI)
apply (simp add: norm_sgn sgn_zero_iff x)
done
thus ?thesis
by (rule netlimit_within [of a UNIV, unfolded within_UNIV])
qed simp

lemma FDERIV_conv_has_derivative:
shows "FDERIV f x :> f' = (f has_derivative f') (at x)"
unfolding fderiv_def has_derivative_def netlimit_at_vector
by (simp add: diff_diff_eq Lim_at_zero [where a=x]
tendsto_norm_zero_iff [where 'b='b, symmetric])

lemma DERIV_conv_has_derivative:
"(DERIV f x :> f') = (f has_derivative op * f') (at x)"
unfolding deriv_fderiv FDERIV_conv_has_derivative
by (subst mult_commute, rule refl)

text {* These are the only cases we'll care about, probably. *}

lemma has_derivative_within: "(f has_derivative f') (at x within s) \<longleftrightarrow>
bounded_linear f' \<and> ((\<lambda>y. (1 / norm(y - x)) *\<^sub>R (f y - (f x + f' (y - x)))) ---> 0) (at x within s)"
unfolding has_derivative_def and Lim by(auto simp add:netlimit_within)

lemma has_derivative_at: "(f has_derivative f') (at x) \<longleftrightarrow>
bounded_linear f' \<and> ((\<lambda>y. (1 / (norm(y - x))) *\<^sub>R (f y - (f x + f' (y - x)))) ---> 0) (at x)"
using has_derivative_within [of f f' x UNIV] by simp

text {* More explicit epsilon-delta forms. *}

lemma has_derivative_within':
"(f has_derivative f')(at x within s) \<longleftrightarrow> bounded_linear f' \<and>
(\<forall>e>0. \<exists>d>0. \<forall>x'\<in>s. 0 < norm(x' - x) \<and> norm(x' - x) < d
\<longrightarrow> norm(f x' - f x - f'(x' - x)) / norm(x' - x) < e)"
unfolding has_derivative_within Lim_within dist_norm
unfolding diff_0_right by (simp add: diff_diff_eq)

lemma has_derivative_at':
"(f has_derivative f') (at x) \<longleftrightarrow> bounded_linear f' \<and>
(\<forall>e>0. \<exists>d>0. \<forall>x'. 0 < norm(x' - x) \<and> norm(x' - x) < d
\<longrightarrow> norm(f x' - f x - f'(x' - x)) / norm(x' - x) < e)"
using has_derivative_within' [of f f' x UNIV] by simp

lemma has_derivative_at_within: "(f has_derivative f') (at x) \<Longrightarrow> (f has_derivative f') (at x within s)"
unfolding has_derivative_within' has_derivative_at' by meson

lemma has_derivative_within_open:
"a \<in> s \<Longrightarrow> open s \<Longrightarrow> ((f has_derivative f') (at a within s) \<longleftrightarrow> (f has_derivative f') (at a))"
by (simp only: at_within_interior interior_open)

lemma has_derivative_right:
fixes f :: "real \<Rightarrow> real" and y :: "real"
shows "(f has_derivative (op * y)) (at x within ({x <..} \<inter> I)) \<longleftrightarrow>
((\<lambda>t. (f x - f t) / (x - t)) ---> y) (at x within ({x <..} \<inter> I))"
proof -
have "((\<lambda>t. (f t - (f x + y * (t - x))) / \<bar>t - x\<bar>) ---> 0) (at x within ({x<..} \<inter> I)) \<longleftrightarrow>
((\<lambda>t. (f t - f x) / (t - x) - y) ---> 0) (at x within ({x<..} \<inter> I))"
by (intro Lim_cong_within) (auto simp add: diff_divide_distrib add_divide_distrib)
also have "\<dots> \<longleftrightarrow> ((\<lambda>t. (f t - f x) / (t - x)) ---> y) (at x within ({x<..} \<inter> I))"
by (simp add: Lim_null[symmetric])
also have "\<dots> \<longleftrightarrow> ((\<lambda>t. (f x - f t) / (x - t)) ---> y) (at x within ({x<..} \<inter> I))"
by (intro Lim_cong_within) (simp_all add: field_simps)
finally show ?thesis
by (simp add: bounded_linear_mult_right has_derivative_within)
qed

lemma bounded_linear_imp_linear: "bounded_linear f \<Longrightarrow> linear f" (* TODO: move elsewhere *)
proof -
assume "bounded_linear f"
then interpret f: bounded_linear f .
show "linear f"
by (simp add: f.add f.scaleR linear_def)
qed

lemma derivative_is_linear:
"(f has_derivative f') net \<Longrightarrow> linear f'"
by (rule derivative_linear [THEN bounded_linear_imp_linear])

subsubsection {* Combining theorems. *}

lemma has_derivative_id: "((\<lambda>x. x) has_derivative (\<lambda>h. h)) net"
unfolding has_derivative_def
by (simp add: bounded_linear_ident tendsto_const)

lemma has_derivative_const: "((\<lambda>x. c) has_derivative (\<lambda>h. 0)) net"
unfolding has_derivative_def
by (simp add: bounded_linear_zero tendsto_const)

lemma (in bounded_linear) has_derivative': "(f has_derivative f) net"
unfolding has_derivative_def apply(rule,rule bounded_linear_axioms)
unfolding diff by (simp add: tendsto_const)

lemma (in bounded_linear) bounded_linear: "bounded_linear f" ..

lemma (in bounded_linear) has_derivative:
assumes "((\<lambda>x. g x) has_derivative (\<lambda>h. g' h)) net"
shows "((\<lambda>x. f (g x)) has_derivative (\<lambda>h. f (g' h))) net"
using assms unfolding has_derivative_def
apply safe
apply (erule bounded_linear_compose [OF local.bounded_linear])
apply (drule local.tendsto)
apply (simp add: local.scaleR local.diff local.add local.zero)
done

lemmas scaleR_right_has_derivative =
bounded_linear.has_derivative [OF bounded_linear_scaleR_right]

lemmas scaleR_left_has_derivative =
bounded_linear.has_derivative [OF bounded_linear_scaleR_left]

lemmas inner_right_has_derivative =
bounded_linear.has_derivative [OF bounded_linear_inner_right]

lemmas inner_left_has_derivative =
bounded_linear.has_derivative [OF bounded_linear_inner_left]

lemmas mult_right_has_derivative =
bounded_linear.has_derivative [OF bounded_linear_mult_right]

lemmas mult_left_has_derivative =
bounded_linear.has_derivative [OF bounded_linear_mult_left]

lemmas euclidean_component_has_derivative =
bounded_linear.has_derivative [OF bounded_linear_euclidean_component]

lemma has_derivative_neg:
assumes "(f has_derivative f') net"
shows "((\<lambda>x. -(f x)) has_derivative (\<lambda>h. -(f' h))) net"
using scaleR_right_has_derivative [where r="-1", OF assms] by auto

lemma has_derivative_add:
assumes "(f has_derivative f') net" and "(g has_derivative g') net"
shows "((\<lambda>x. f(x) + g(x)) has_derivative (\<lambda>h. f'(h) + g'(h))) net"
proof-
note as = assms[unfolded has_derivative_def]
show ?thesis unfolding has_derivative_def apply(rule,rule bounded_linear_add)
using tendsto_add[OF as(1)[THEN conjunct2] as(2)[THEN conjunct2]] and as
by (auto simp add: algebra_simps)
qed

lemma has_derivative_add_const:
"(f has_derivative f') net \<Longrightarrow> ((\<lambda>x. f x + c) has_derivative f') net"
by (drule has_derivative_add, rule has_derivative_const, auto)

lemma has_derivative_sub:
assumes "(f has_derivative f') net" and "(g has_derivative g') net"
shows "((\<lambda>x. f(x) - g(x)) has_derivative (\<lambda>h. f'(h) - g'(h))) net"
unfolding diff_minus by (intro has_derivative_add has_derivative_neg assms)

lemma has_derivative_setsum:
assumes "finite s" and "\<forall>a\<in>s. ((f a) has_derivative (f' a)) net"
shows "((\<lambda>x. setsum (\<lambda>a. f a x) s) has_derivative (\<lambda>h. setsum (\<lambda>a. f' a h) s)) net"
using assms by (induct, simp_all add: has_derivative_const has_derivative_add)
text {* Somewhat different results for derivative of scalar multiplier. *}

(** move **)
lemma linear_vmul_component: (* TODO: delete *)
assumes lf: "linear f"
shows "linear (\<lambda>x. f x \$\$ k *\<^sub>R v)"
using lf
by (auto simp add: linear_def algebra_simps)

lemmas has_derivative_intros =
has_derivative_id has_derivative_const
has_derivative_add has_derivative_sub has_derivative_neg
has_derivative_add_const
scaleR_left_has_derivative scaleR_right_has_derivative
inner_left_has_derivative inner_right_has_derivative
euclidean_component_has_derivative

subsubsection {* Limit transformation for derivatives *}

lemma has_derivative_transform_within:
assumes "0 < d" "x \<in> s" "\<forall>x'\<in>s. dist x' x < d \<longrightarrow> f x' = g x'" "(f has_derivative f') (at x within s)"
shows "(g has_derivative f') (at x within s)"
using assms(4) unfolding has_derivative_within apply- apply(erule conjE,rule,assumption)
apply(rule Lim_transform_within[OF assms(1)]) defer apply assumption
apply(rule,rule) apply(drule assms(3)[rule_format]) using assms(3)[rule_format, OF assms(2)] by auto

lemma has_derivative_transform_at:
assumes "0 < d" "\<forall>x'. dist x' x < d \<longrightarrow> f x' = g x'" "(f has_derivative f') (at x)"
shows "(g has_derivative f') (at x)"
using has_derivative_transform_within [of d x UNIV f g f'] assms by simp

lemma has_derivative_transform_within_open:
assumes "open s" "x \<in> s" "\<forall>y\<in>s. f y = g y" "(f has_derivative f') (at x)"
shows "(g has_derivative f') (at x)"
using assms(4) unfolding has_derivative_at apply- apply(erule conjE,rule,assumption)
apply(rule Lim_transform_within_open[OF assms(1,2)]) defer apply assumption
apply(rule,rule) apply(drule assms(3)[rule_format]) using assms(3)[rule_format, OF assms(2)] by auto

subsection {* Differentiability *}

no_notation Deriv.differentiable (infixl "differentiable" 60)

definition differentiable :: "('a::real_normed_vector \<Rightarrow> 'b::real_normed_vector) \<Rightarrow> 'a filter \<Rightarrow> bool" (infixr "differentiable" 30) where
"f differentiable net \<equiv> (\<exists>f'. (f has_derivative f') net)"

definition differentiable_on :: "('a::real_normed_vector \<Rightarrow> 'b::real_normed_vector) \<Rightarrow> 'a set \<Rightarrow> bool" (infixr "differentiable'_on" 30) where
"f differentiable_on s \<equiv> (\<forall>x\<in>s. f differentiable (at x within s))"

lemma differentiableI: "(f has_derivative f') net \<Longrightarrow> f differentiable net"
unfolding differentiable_def by auto

lemma differentiable_at_withinI: "f differentiable (at x) \<Longrightarrow> f differentiable (at x within s)"
unfolding differentiable_def using has_derivative_at_within by blast

lemma differentiable_within_open: (* TODO: delete *)
assumes "a \<in> s" and "open s"
shows "f differentiable (at a within s) \<longleftrightarrow> (f differentiable (at a))"
using assms by (simp only: at_within_interior interior_open)

lemma differentiable_on_eq_differentiable_at:
"open s \<Longrightarrow> (f differentiable_on s \<longleftrightarrow> (\<forall>x\<in>s. f differentiable at x))"
unfolding differentiable_on_def
by (auto simp add: at_within_interior interior_open)

lemma differentiable_transform_within:
assumes "0 < d" and "x \<in> s" and "\<forall>x'\<in>s. dist x' x < d \<longrightarrow> f x' = g x'"
assumes "f differentiable (at x within s)"
shows "g differentiable (at x within s)"
using assms(4) unfolding differentiable_def
by (auto intro!: has_derivative_transform_within[OF assms(1-3)])

lemma differentiable_transform_at:
assumes "0 < d" "\<forall>x'. dist x' x < d \<longrightarrow> f x' = g x'" "f differentiable at x"
shows "g differentiable at x"
using assms(3) unfolding differentiable_def
using has_derivative_transform_at[OF assms(1-2)] by auto

subsection {* Frechet derivative and Jacobian matrix. *}

definition "frechet_derivative f net = (SOME f'. (f has_derivative f') net)"

lemma frechet_derivative_works:
"f differentiable net \<longleftrightarrow> (f has_derivative (frechet_derivative f net)) net"
unfolding frechet_derivative_def differentiable_def and some_eq_ex[of "\<lambda> f' . (f has_derivative f') net"] ..

lemma linear_frechet_derivative:
shows "f differentiable net \<Longrightarrow> linear(frechet_derivative f net)"
unfolding frechet_derivative_works has_derivative_def
by (auto intro: bounded_linear_imp_linear)

subsection {* Differentiability implies continuity *}

lemma Lim_mul_norm_within:
fixes f::"'a::real_normed_vector \<Rightarrow> 'b::real_normed_vector"
shows "(f ---> 0) (at a within s) \<Longrightarrow> ((\<lambda>x. norm(x - a) *\<^sub>R f(x)) ---> 0) (at a within s)"
unfolding Lim_within apply(rule,rule)
apply(erule_tac x=e in allE,erule impE,assumption,erule exE,erule conjE)
apply(rule_tac x="min d 1" in exI) apply rule defer
apply(rule,erule_tac x=x in ballE) unfolding dist_norm diff_0_right
by(auto intro!: mult_strict_mono[of _ "1::real", unfolded mult_1_left])

lemma differentiable_imp_continuous_within:
assumes "f differentiable (at x within s)"
shows "continuous (at x within s) f"
proof-
from assms guess f' unfolding differentiable_def has_derivative_within ..
note f'=this
then interpret bounded_linear f' by auto
have *:"\<And>xa. x\<noteq>xa \<Longrightarrow> (f' \<circ> (\<lambda>y. y - x)) xa + norm (xa - x) *\<^sub>R ((1 / norm (xa - x)) *\<^sub>R (f xa - (f x + f' (xa - x)))) - ((f' \<circ> (\<lambda>y. y - x)) x + 0) = f xa - f x"
using zero by auto
have **:"continuous (at x within s) (f' \<circ> (\<lambda>y. y - x))"
apply(rule continuous_within_compose) apply(rule continuous_intros)+
by(rule linear_continuous_within[OF f'[THEN conjunct1]])
show ?thesis unfolding continuous_within
using f'[THEN conjunct2, THEN Lim_mul_norm_within]
apply- apply(drule tendsto_add)
apply(rule **[unfolded continuous_within])
unfolding Lim_within and dist_norm
apply (rule, rule)
apply (erule_tac x=e in allE)
apply (erule impE | assumption)+
apply (erule exE, rule_tac x=d in exI)
by (auto simp add: zero *)
qed

lemma differentiable_imp_continuous_at:
"f differentiable at x \<Longrightarrow> continuous (at x) f"
by(rule differentiable_imp_continuous_within[of _ x UNIV, unfolded within_UNIV])

lemma differentiable_imp_continuous_on:
"f differentiable_on s \<Longrightarrow> continuous_on s f"
unfolding differentiable_on_def continuous_on_eq_continuous_within
using differentiable_imp_continuous_within by blast

lemma has_derivative_within_subset:
"(f has_derivative f') (at x within s) \<Longrightarrow> t \<subseteq> s \<Longrightarrow> (f has_derivative f') (at x within t)"
unfolding has_derivative_within using Lim_within_subset by blast

lemma differentiable_within_subset:
"f differentiable (at x within t) \<Longrightarrow> s \<subseteq> t \<Longrightarrow> f differentiable (at x within s)"
unfolding differentiable_def using has_derivative_within_subset by blast

lemma differentiable_on_subset:
"f differentiable_on t \<Longrightarrow> s \<subseteq> t \<Longrightarrow> f differentiable_on s"
unfolding differentiable_on_def using differentiable_within_subset by blast

lemma differentiable_on_empty: "f differentiable_on {}"
unfolding differentiable_on_def by auto

text {* Several results are easier using a "multiplied-out" variant.
(I got this idea from Dieudonne's proof of the chain rule). *}

lemma has_derivative_within_alt:
"(f has_derivative f') (at x within s) \<longleftrightarrow> bounded_linear f' \<and>
(\<forall>e>0. \<exists>d>0. \<forall>y\<in>s. norm(y - x) < d \<longrightarrow> norm(f(y) - f(x) - f'(y - x)) \<le> e * norm(y - x))" (is "?lhs \<longleftrightarrow> ?rhs")
proof
assume ?lhs thus ?rhs
unfolding has_derivative_within apply-apply(erule conjE,rule,assumption)
unfolding Lim_within
apply(rule,erule_tac x=e in allE,rule,erule impE,assumption)
apply(erule exE,rule_tac x=d in exI)
apply(erule conjE,rule,assumption,rule,rule)
proof-
fix x y e d assume as:"0 < e" "0 < d" "norm (y - x) < d" "\<forall>xa\<in>s. 0 < dist xa x \<and> dist xa x < d \<longrightarrow>
dist ((1 / norm (xa - x)) *\<^sub>R (f xa - (f x + f' (xa - x)))) 0 < e" "y \<in> s" "bounded_linear f'"
then interpret bounded_linear f' by auto
show "norm (f y - f x - f' (y - x)) \<le> e * norm (y - x)" proof(cases "y=x")
case True thus ?thesis using `bounded_linear f'` by(auto simp add: zero)
next
case False hence "norm (f y - (f x + f' (y - x))) < e * norm (y - x)" using as(4)[rule_format, OF `y\<in>s`]
unfolding dist_norm diff_0_right using as(3)
using pos_divide_less_eq[OF False[unfolded dist_nz], unfolded dist_norm]
by (auto simp add: linear_0 linear_sub)
thus ?thesis by(auto simp add:algebra_simps)
qed
qed
next
assume ?rhs thus ?lhs unfolding has_derivative_within Lim_within
apply-apply(erule conjE,rule,assumption)
apply(rule,erule_tac x="e/2" in allE,rule,erule impE) defer
apply(erule exE,rule_tac x=d in exI)
apply(erule conjE,rule,assumption,rule,rule)
unfolding dist_norm diff_0_right norm_scaleR
apply(erule_tac x=xa in ballE,erule impE)
proof-
fix e d y assume "bounded_linear f'" "0 < e" "0 < d" "y \<in> s" "0 < norm (y - x) \<and> norm (y - x) < d"
"norm (f y - f x - f' (y - x)) \<le> e / 2 * norm (y - x)"
thus "\<bar>1 / norm (y - x)\<bar> * norm (f y - (f x + f' (y - x))) < e"
apply(rule_tac le_less_trans[of _ "e/2"])
by(auto intro!:mult_imp_div_pos_le simp add:algebra_simps)
qed auto
qed

lemma has_derivative_at_alt:
"(f has_derivative f') (at x) \<longleftrightarrow> bounded_linear f' \<and>
(\<forall>e>0. \<exists>d>0. \<forall>y. norm(y - x) < d \<longrightarrow> norm(f y - f x - f'(y - x)) \<le> e * norm(y - x))"
using has_derivative_within_alt[where s=UNIV] by simp

subsection {* The chain rule. *}

lemma diff_chain_within:
assumes "(f has_derivative f') (at x within s)"
assumes "(g has_derivative g') (at (f x) within (f ` s))"
shows "((g o f) has_derivative (g' o f'))(at x within s)"
unfolding has_derivative_within_alt
apply(rule,rule bounded_linear_compose[unfolded o_def[THEN sym]])
apply(rule assms(2)[unfolded has_derivative_def,THEN conjE],assumption)
apply(rule assms(1)[unfolded has_derivative_def,THEN conjE],assumption)
proof(rule,rule)
note assms = assms[unfolded has_derivative_within_alt]
fix e::real assume "0<e"
guess B1 using bounded_linear.pos_bounded[OF assms(1)[THEN conjunct1, rule_format]] .. note B1 = this
guess B2 using bounded_linear.pos_bounded[OF assms(2)[THEN conjunct1, rule_format]] .. note B2 = this
have *:"e / 2 / B2 > 0" using `e>0` B2 apply-apply(rule divide_pos_pos) by auto
guess d1 using assms(1)[THEN conjunct2, rule_format, OF *] .. note d1 = this
have *:"e / 2 / (1 + B1) > 0" using `e>0` B1 apply-apply(rule divide_pos_pos) by auto
guess de using assms(2)[THEN conjunct2, rule_format, OF *] .. note de = this
guess d2 using assms(1)[THEN conjunct2, rule_format, OF zero_less_one] .. note d2 = this

def d0 \<equiv> "(min d1 d2)/2" have d0:"d0>0" "d0 < d1" "d0 < d2" unfolding d0_def using d1 d2 by auto
def d \<equiv> "(min d0 (de / (B1 + 1))) / 2" have "de * 2 / (B1 + 1) > de / (B1 + 1)" apply(rule divide_strict_right_mono) using B1 de by auto
hence d:"d>0" "d < d1" "d < d2" "d < (de / (B1 + 1))" unfolding d_def using d0 d1 d2 de B1 by(auto intro!: divide_pos_pos simp add:min_less_iff_disj not_less)

show "\<exists>d>0. \<forall>y\<in>s. norm (y - x) < d \<longrightarrow> norm ((g \<circ> f) y - (g \<circ> f) x - (g' \<circ> f') (y - x)) \<le> e * norm (y - x)" apply(rule_tac x=d in exI)
proof(rule,rule `d>0`,rule,rule)
fix y assume as:"y \<in> s" "norm (y - x) < d"
hence 1:"norm (f y - f x - f' (y - x)) \<le> min (norm (y - x)) (e / 2 / B2 * norm (y - x))" using d1 d2 d by auto

have "norm (f y - f x) \<le> norm (f y - f x - f' (y - x)) + norm (f' (y - x))"
using norm_triangle_sub[of "f y - f x" "f' (y - x)"]
by(auto simp add:algebra_simps)
also have "\<dots> \<le> norm (f y - f x - f' (y - x)) + B1 * norm (y - x)"
apply(rule add_left_mono) using B1 by(auto simp add:algebra_simps)
also have "\<dots> \<le> min (norm (y - x)) (e / 2 / B2 * norm (y - x)) + B1 * norm (y - x)"
apply(rule add_right_mono) using d1 d2 d as by auto
also have "\<dots> \<le> norm (y - x) + B1 * norm (y - x)" by auto
also have "\<dots> = norm (y - x) * (1 + B1)" by(auto simp add:field_simps)
finally have 3:"norm (f y - f x) \<le> norm (y - x) * (1 + B1)" by auto

hence "norm (f y - f x) \<le> d * (1 + B1)" apply-
apply(rule order_trans,assumption,rule mult_right_mono)
using as B1 by auto
also have "\<dots> < de" using d B1 by(auto simp add:field_simps)
finally have "norm (g (f y) - g (f x) - g' (f y - f x)) \<le> e / 2 / (1 + B1) * norm (f y - f x)"
apply-apply(rule de[THEN conjunct2,rule_format])
using `y\<in>s` using d as by auto
also have "\<dots> = (e / 2) * (1 / (1 + B1) * norm (f y - f x))" by auto
also have "\<dots> \<le> e / 2 * norm (y - x)" apply(rule mult_left_mono)
using `e>0` and 3 using B1 and `e>0` by(auto simp add:divide_le_eq)
finally have 4:"norm (g (f y) - g (f x) - g' (f y - f x)) \<le> e / 2 * norm (y - x)" by auto

interpret g': bounded_linear g' using assms(2) by auto
interpret f': bounded_linear f' using assms(1) by auto
have "norm (- g' (f' (y - x)) + g' (f y - f x)) = norm (g' (f y - f x - f' (y - x)))"
by(auto simp add:algebra_simps f'.diff g'.diff g'.add)
also have "\<dots> \<le> B2 * norm (f y - f x - f' (y - x))" using B2
by (auto simp add: algebra_simps)
also have "\<dots> \<le> B2 * (e / 2 / B2 * norm (y - x))"
apply (rule mult_left_mono) using as d1 d2 d B2 by auto
also have "\<dots> \<le> e / 2 * norm (y - x)" using B2 by auto
finally have 5:"norm (- g' (f' (y - x)) + g' (f y - f x)) \<le> e / 2 * norm (y - x)" by auto

have "norm (g (f y) - g (f x) - g' (f y - f x)) + norm (g (f y) - g (f x) - g' (f' (y - x)) - (g (f y) - g (f x) - g' (f y - f x))) \<le> e * norm (y - x)"
using 5 4 by auto
thus "norm ((g \<circ> f) y - (g \<circ> f) x - (g' \<circ> f') (y - x)) \<le> e * norm (y - x)"
unfolding o_def apply- apply(rule order_trans, rule norm_triangle_sub)
by assumption
qed
qed

lemma diff_chain_at:
"(f has_derivative f') (at x) \<Longrightarrow> (g has_derivative g') (at (f x)) \<Longrightarrow> ((g o f) has_derivative (g' o f')) (at x)"
using diff_chain_within[of f f' x UNIV g g']
using has_derivative_within_subset[of g g' "f x" UNIV "range f"]
by simp

subsection {* Composition rules stated just for differentiability. *}

lemma differentiable_const [intro]:
"(\<lambda>z. c) differentiable (net::'a::real_normed_vector filter)"
unfolding differentiable_def using has_derivative_const by auto

lemma differentiable_id [intro]:
"(\<lambda>z. z) differentiable (net::'a::real_normed_vector filter)"
unfolding differentiable_def using has_derivative_id by auto

lemma differentiable_cmul [intro]:
"f differentiable net \<Longrightarrow>
(\<lambda>x. c *\<^sub>R f(x)) differentiable (net::'a::real_normed_vector filter)"
unfolding differentiable_def
apply(erule exE, drule scaleR_right_has_derivative) by auto

lemma differentiable_neg [intro]:
"f differentiable net \<Longrightarrow>
(\<lambda>z. -(f z)) differentiable (net::'a::real_normed_vector filter)"
unfolding differentiable_def
apply(erule exE, drule has_derivative_neg) by auto

lemma differentiable_add: "f differentiable net \<Longrightarrow> g differentiable net
\<Longrightarrow> (\<lambda>z. f z + g z) differentiable (net::'a::real_normed_vector filter)"
unfolding differentiable_def apply(erule exE)+ apply(rule_tac x="\<lambda>z. f' z + f'a z" in exI)
apply(rule has_derivative_add) by auto

lemma differentiable_sub: "f differentiable net \<Longrightarrow> g differentiable net
\<Longrightarrow> (\<lambda>z. f z - g z) differentiable (net::'a::real_normed_vector filter)"
unfolding differentiable_def apply(erule exE)+
apply(rule_tac x="\<lambda>z. f' z - f'a z" in exI)
apply(rule has_derivative_sub) by auto

lemma differentiable_setsum:
assumes "finite s" "\<forall>a\<in>s. (f a) differentiable net"
shows "(\<lambda>x. setsum (\<lambda>a. f a x) s) differentiable net"
proof-
guess f' using bchoice[OF assms(2)[unfolded differentiable_def]] ..
thus ?thesis unfolding differentiable_def apply-
apply(rule,rule has_derivative_setsum[where f'=f'],rule assms(1)) by auto
qed

lemma differentiable_setsum_numseg:
shows "\<forall>i. m \<le> i \<and> i \<le> n \<longrightarrow> (f i) differentiable net \<Longrightarrow> (\<lambda>x. setsum (\<lambda>a. f a x) {m::nat..n}) differentiable net"
apply(rule differentiable_setsum) using finite_atLeastAtMost[of n m] by auto

lemma differentiable_chain_at:
"f differentiable (at x) \<Longrightarrow> g differentiable (at(f x)) \<Longrightarrow> (g o f) differentiable (at x)"
unfolding differentiable_def by(meson diff_chain_at)

lemma differentiable_chain_within:
"f differentiable (at x within s) \<Longrightarrow> g differentiable (at(f x) within (f ` s))
\<Longrightarrow> (g o f) differentiable (at x within s)"
unfolding differentiable_def by(meson diff_chain_within)

subsection {* Uniqueness of derivative *}

text {*
The general result is a bit messy because we need approachability of the
limit point from any direction. But OK for nontrivial intervals etc.
*}

lemma frechet_derivative_unique_within:
fixes f :: "'a::euclidean_space \<Rightarrow> 'b::real_normed_vector"
assumes "(f has_derivative f') (at x within s)"
assumes "(f has_derivative f'') (at x within s)"
assumes "(\<forall>i<DIM('a). \<forall>e>0. \<exists>d. 0 < abs(d) \<and> abs(d) < e \<and> (x + d *\<^sub>R basis i) \<in> s)"
shows "f' = f''"
proof-
note as = assms(1,2)[unfolded has_derivative_def]
then interpret f': bounded_linear f' by auto
from as interpret f'': bounded_linear f'' by auto
have "x islimpt s" unfolding islimpt_approachable
proof(rule,rule)
fix e::real assume "0<e" guess d
using assms(3)[rule_format,OF DIM_positive `e>0`] ..
thus "\<exists>x'\<in>s. x' \<noteq> x \<and> dist x' x < e"
apply(rule_tac x="x + d *\<^sub>R basis 0" in bexI)
unfolding dist_norm by auto
qed
hence *:"netlimit (at x within s) = x" apply-apply(rule netlimit_within)
unfolding trivial_limit_within by simp
show ?thesis  apply(rule linear_eq_stdbasis)
unfolding linear_conv_bounded_linear
apply(rule as(1,2)[THEN conjunct1])+
proof(rule,rule,rule ccontr)
fix i assume i:"i<DIM('a)" def e \<equiv> "norm (f' (basis i) - f'' (basis i))"
assume "f' (basis i) \<noteq> f'' (basis i)"
hence "e>0" unfolding e_def by auto
guess d using tendsto_diff [OF as(1,2)[THEN conjunct2], unfolded * Lim_within,rule_format,OF `e>0`] .. note d=this
guess c using assms(3)[rule_format,OF i d[THEN conjunct1]] .. note c=this
have *:"norm (- ((1 / \<bar>c\<bar>) *\<^sub>R f' (c *\<^sub>R basis i)) + (1 / \<bar>c\<bar>) *\<^sub>R f'' (c *\<^sub>R basis i)) = norm ((1 / abs c) *\<^sub>R (- (f' (c *\<^sub>R basis i)) + f'' (c *\<^sub>R basis i)))"
unfolding scaleR_right_distrib by auto
also have "\<dots> = norm ((1 / abs c) *\<^sub>R (c *\<^sub>R (- (f' (basis i)) + f'' (basis i))))"
unfolding f'.scaleR f''.scaleR
unfolding scaleR_right_distrib scaleR_minus_right by auto
also have "\<dots> = e" unfolding e_def using c[THEN conjunct1]
using norm_minus_cancel[of "f' (basis i) - f'' (basis i)"]
by (auto simp add: add.commute ab_diff_minus)
finally show False using c
using d[THEN conjunct2,rule_format,of "x + c *\<^sub>R basis i"]
unfolding dist_norm
unfolding f'.scaleR f''.scaleR f'.add f''.add f'.diff f''.diff
scaleR_scaleR scaleR_right_diff_distrib scaleR_right_distrib
using i by auto
qed
qed

lemma frechet_derivative_unique_at:
shows "(f has_derivative f') (at x) \<Longrightarrow> (f has_derivative f'') (at x) \<Longrightarrow> f' = f''"
unfolding FDERIV_conv_has_derivative [symmetric]
by (rule FDERIV_unique)

lemma continuous_isCont: "isCont f x = continuous (at x) f"
unfolding isCont_def LIM_def
unfolding continuous_at Lim_at unfolding dist_nz by auto

lemma frechet_derivative_unique_within_closed_interval:
fixes f::"'a::ordered_euclidean_space \<Rightarrow> 'b::real_normed_vector"
assumes "\<forall>i<DIM('a). a\$\$i < b\$\$i" "x \<in> {a..b}" (is "x\<in>?I")
assumes "(f has_derivative f' ) (at x within {a..b})"
assumes "(f has_derivative f'') (at x within {a..b})"
shows "f' = f''"
apply(rule frechet_derivative_unique_within)
apply(rule assms(3,4))+
proof(rule,rule,rule,rule)
fix e::real and i assume "e>0" and i:"i<DIM('a)"
thus "\<exists>d. 0 < \<bar>d\<bar> \<and> \<bar>d\<bar> < e \<and> x + d *\<^sub>R basis i \<in> {a..b}"
proof(cases "x\$\$i=a\$\$i")
case True thus ?thesis
apply(rule_tac x="(min (b\$\$i - a\$\$i)  e) / 2" in exI)
using assms(1)[THEN spec[where x=i]] and `e>0` and assms(2)
unfolding mem_interval euclidean_simps
using i by (auto simp add: field_simps)
next note * = assms(2)[unfolded mem_interval,THEN spec[where x=i]]
case False moreover have "a \$\$ i < x \$\$ i" using False * by auto
moreover {
have "a \$\$ i * 2 + min (x \$\$ i - a \$\$ i) e \<le> a\$\$i *2 + x\$\$i - a\$\$i"
by auto
also have "\<dots> = a\$\$i + x\$\$i" by auto
also have "\<dots> \<le> 2 * x\$\$i" using * by auto
finally have "a \$\$ i * 2 + min (x \$\$ i - a \$\$ i) e \<le> x \$\$ i * 2" by auto
}
moreover have "min (x \$\$ i - a \$\$ i) e \<ge> 0" using * and `e>0` by auto
hence "x \$\$ i * 2 \<le> b \$\$ i * 2 + min (x \$\$ i - a \$\$ i) e" using * by auto
ultimately show ?thesis
apply(rule_tac x="- (min (x\$\$i - a\$\$i) e) / 2" in exI)
using assms(1)[THEN spec[where x=i]] and `e>0` and assms(2)
unfolding mem_interval euclidean_simps
using i by (auto simp add: field_simps)
qed
qed

lemma frechet_derivative_unique_within_open_interval:
fixes f::"'a::ordered_euclidean_space \<Rightarrow> 'b::real_normed_vector"
assumes "x \<in> {a<..<b}"
assumes "(f has_derivative f' ) (at x within {a<..<b})"
assumes "(f has_derivative f'') (at x within {a<..<b})"
shows "f' = f''"
proof -
from assms(1) have *: "at x within {a<..<b} = at x"
by (simp add: at_within_interior interior_open open_interval)
from assms(2,3) [unfolded *] show "f' = f''"
by (rule frechet_derivative_unique_at)
qed

lemma frechet_derivative_at:
shows "(f has_derivative f') (at x) \<Longrightarrow> (f' = frechet_derivative f (at x))"
apply(rule frechet_derivative_unique_at[of f],assumption)
unfolding frechet_derivative_works[THEN sym] using differentiable_def by auto

lemma frechet_derivative_within_closed_interval:
fixes f::"'a::ordered_euclidean_space \<Rightarrow> 'b::real_normed_vector"
assumes "\<forall>i<DIM('a). a\$\$i < b\$\$i" and "x \<in> {a..b}"
assumes "(f has_derivative f') (at x within {a.. b})"
shows "frechet_derivative f (at x within {a.. b}) = f'"
apply(rule frechet_derivative_unique_within_closed_interval[where f=f])
apply(rule assms(1,2))+ unfolding frechet_derivative_works[THEN sym]
unfolding differentiable_def using assms(3) by auto

subsection {* The traditional Rolle theorem in one dimension. *}

lemma linear_componentwise:
fixes f:: "'a::euclidean_space \<Rightarrow> 'b::euclidean_space"
assumes lf: "linear f"
shows "(f x) \$\$ j = (\<Sum>i<DIM('a). (x\$\$i) * (f (basis i)\$\$j))" (is "?lhs = ?rhs")
proof -
have fA: "finite {..<DIM('a)}" by simp
have "?rhs = (\<Sum>i<DIM('a). x\$\$i *\<^sub>R f (basis i))\$\$j"
by simp
then show ?thesis
unfolding linear_setsum_mul[OF lf fA, symmetric]
unfolding euclidean_representation[symmetric] ..
qed

text {* We do not introduce @{text jacobian}, which is defined on matrices, instead we use
the unfolding of it. *}

lemma jacobian_works:
"(f::('a::euclidean_space) \<Rightarrow> ('b::euclidean_space)) differentiable net \<longleftrightarrow>
(f has_derivative (\<lambda>h. \<chi>\<chi> i.
\<Sum>j<DIM('a). frechet_derivative f net (basis j) \$\$ i * h \$\$ j)) net"
(is "?differentiable \<longleftrightarrow> (f has_derivative (\<lambda>h. \<chi>\<chi> i. ?SUM h i)) net")
proof
assume *: ?differentiable
{ fix h i
have "?SUM h i = frechet_derivative f net h \$\$ i" using *
by (auto intro!: setsum_cong
simp: linear_componentwise[of _ h i] linear_frechet_derivative) }
thus "(f has_derivative (\<lambda>h. \<chi>\<chi> i. ?SUM h i)) net"
using * by (simp add: frechet_derivative_works)
qed (auto intro!: differentiableI)

lemma differential_zero_maxmin_component:
fixes f :: "'a::euclidean_space \<Rightarrow> 'b::euclidean_space"
assumes k: "k < DIM('b)"
and ball: "0 < e" "((\<forall>y \<in> ball x e. (f y)\$\$k \<le> (f x)\$\$k) \<or> (\<forall>y\<in>ball x e. (f x)\$\$k \<le> (f y)\$\$k))"
and diff: "f differentiable (at x)"
shows "(\<chi>\<chi> j. frechet_derivative f (at x) (basis j) \$\$ k) = (0::'a)" (is "?D k = 0")
proof (rule ccontr)
assume "?D k \<noteq> 0"
then obtain j where j: "?D k \$\$ j \<noteq> 0" "j < DIM('a)"
unfolding euclidean_lambda_beta euclidean_eq[of _ "0::'a"] by auto
hence *: "\<bar>?D k \$\$ j\<bar> / 2 > 0" by auto
note as = diff[unfolded jacobian_works has_derivative_at_alt]
guess e' using as[THEN conjunct2, rule_format, OF *] .. note e' = this
guess d using real_lbound_gt_zero[OF ball(1) e'[THEN conjunct1]] .. note d = this
{ fix c assume "abs c \<le> d"
hence *:"norm (x + c *\<^sub>R basis j - x) < e'" using norm_basis[of j] d by auto
let ?v = "(\<chi>\<chi> i. \<Sum>l<DIM('a). ?D i \$\$ l * (c *\<^sub>R basis j :: 'a) \$\$ l)"
have if_dist: "\<And> P a b c. a * (if P then b else c) = (if P then a * b else a * c)" by auto
have "\<bar>(f (x + c *\<^sub>R basis j) - f x - ?v) \$\$ k\<bar> \<le>
norm (f (x + c *\<^sub>R basis j) - f x - ?v)" by (rule component_le_norm)
also have "\<dots> \<le> \<bar>?D k \$\$ j\<bar> / 2 * \<bar>c\<bar>"
using e'[THEN conjunct2, rule_format, OF *] and norm_basis[of j] by fastforce
finally have "\<bar>(f (x + c *\<^sub>R basis j) - f x - ?v) \$\$ k\<bar> \<le> \<bar>?D k \$\$ j\<bar> / 2 * \<bar>c\<bar>" by simp
hence "\<bar>f (x + c *\<^sub>R basis j) \$\$ k - f x \$\$ k - c * ?D k \$\$ j\<bar> \<le> \<bar>?D k \$\$ j\<bar> / 2 * \<bar>c\<bar>"
unfolding euclidean_simps euclidean_lambda_beta using j k
by (simp add: if_dist setsum_cases field_simps) } note * = this
have "x + d *\<^sub>R basis j \<in> ball x e" "x - d *\<^sub>R basis j \<in> ball x e"
unfolding mem_ball dist_norm using norm_basis[of j] d by auto
hence **:"((f (x - d *\<^sub>R basis j))\$\$k \<le> (f x)\$\$k \<and> (f (x + d *\<^sub>R basis j))\$\$k \<le> (f x)\$\$k) \<or>
((f (x - d *\<^sub>R basis j))\$\$k \<ge> (f x)\$\$k \<and> (f (x + d *\<^sub>R basis j))\$\$k \<ge> (f x)\$\$k)" using ball by auto
have ***: "\<And>y y1 y2 d dx::real.
(y1\<le>y\<and>y2\<le>y) \<or> (y\<le>y1\<and>y\<le>y2) \<Longrightarrow> d < abs dx \<Longrightarrow> abs(y1 - y - - dx) \<le> d \<Longrightarrow> (abs (y2 - y - dx) \<le> d) \<Longrightarrow> False" by arith
show False apply(rule ***[OF **, where dx="d * ?D k \$\$ j" and d="\<bar>?D k \$\$ j\<bar> / 2 * \<bar>d\<bar>"])
using *[of "-d"] and *[of d] and d[THEN conjunct1] and j
unfolding mult_minus_left
unfolding abs_mult diff_minus_eq_add scaleR_minus_left
unfolding algebra_simps by (auto intro: mult_pos_pos)
qed

text {* In particular if we have a mapping into @{typ "real"}. *}

lemma differential_zero_maxmin:
fixes f::"'a\<Colon>euclidean_space \<Rightarrow> real"
assumes "x \<in> s" "open s"
and deriv: "(f has_derivative f') (at x)"
and mono: "(\<forall>y\<in>s. f y \<le> f x) \<or> (\<forall>y\<in>s. f x \<le> f y)"
shows "f' = (\<lambda>v. 0)"
proof -
obtain e where e:"e>0" "ball x e \<subseteq> s"
using `open s`[unfolded open_contains_ball] and `x \<in> s` by auto
with differential_zero_maxmin_component[where 'b=real, of 0 e x f, simplified]
have "(\<chi>\<chi> j. frechet_derivative f (at x) (basis j)) = (0::'a)"
unfolding differentiable_def using mono deriv by auto
with frechet_derivative_at[OF deriv, symmetric]
have "\<forall>i<DIM('a). f' (basis i) = 0"
by (simp add: euclidean_eq[of _ "0::'a"])
with derivative_is_linear[OF deriv, THEN linear_componentwise, of _ 0]
show ?thesis by (simp add: fun_eq_iff)
qed

lemma rolle: fixes f::"real\<Rightarrow>real"
assumes "a < b" and "f a = f b" and "continuous_on {a..b} f"
assumes "\<forall>x\<in>{a<..<b}. (f has_derivative f'(x)) (at x)"
shows "\<exists>x\<in>{a<..<b}. f' x = (\<lambda>v. 0)"
proof-
have "\<exists>x\<in>{a<..<b}. ((\<forall>y\<in>{a<..<b}. f x \<le> f y) \<or> (\<forall>y\<in>{a<..<b}. f y \<le> f x))"
proof-
have "(a + b) / 2 \<in> {a .. b}" using assms(1) by auto
hence *:"{a .. b}\<noteq>{}" by auto
guess d using continuous_attains_sup[OF compact_interval * assms(3)] .. note d=this
guess c using continuous_attains_inf[OF compact_interval * assms(3)] .. note c=this
show ?thesis
proof(cases "d\<in>{a<..<b} \<or> c\<in>{a<..<b}")
case True thus ?thesis
apply(erule_tac disjE) apply(rule_tac x=d in bexI)
apply(rule_tac[3] x=c in bexI)
using d c by auto
next
def e \<equiv> "(a + b) /2"
case False hence "f d = f c" using d c assms(2) by auto
hence "\<And>x. x\<in>{a..b} \<Longrightarrow> f x = f d"
using c d apply- apply(erule_tac x=x in ballE)+ by auto
thus ?thesis
apply(rule_tac x=e in bexI) unfolding e_def using assms(1) by auto
qed
qed
then guess x .. note x=this
hence "f' x = (\<lambda>v. 0)"
apply(rule_tac differential_zero_maxmin[of x "{a<..<b}" f "f' x"])
defer apply(rule open_interval)
apply(rule assms(4)[unfolded has_derivative_at[THEN sym],THEN bspec[where x=x]],assumption)
unfolding o_def apply(erule disjE,rule disjI2) by auto
thus ?thesis apply(rule_tac x=x in bexI) unfolding o_def apply rule
apply(drule_tac x=v in fun_cong) using x(1) by auto
qed

subsection {* One-dimensional mean value theorem. *}

lemma mvt: fixes f::"real \<Rightarrow> real"
assumes "a < b" and "continuous_on {a .. b} f"
assumes "\<forall>x\<in>{a<..<b}. (f has_derivative (f' x)) (at x)"
shows "\<exists>x\<in>{a<..<b}. (f b - f a = (f' x) (b - a))"
proof-
have "\<exists>x\<in>{a<..<b}. (\<lambda>xa. f' x xa - (f b - f a) / (b - a) * xa) = (\<lambda>v. 0)"
apply(rule rolle[OF assms(1), of "\<lambda>x. f x - (f b - f a) / (b - a) * x"])
defer
apply(rule continuous_on_intros assms(2))+
proof
fix x assume x:"x \<in> {a<..<b}"
show "((\<lambda>x. f x - (f b - f a) / (b - a) * x) has_derivative (\<lambda>xa. f' x xa - (f b - f a) / (b - a) * xa)) (at x)"
by (intro has_derivative_intros assms(3)[rule_format,OF x]
mult_right_has_derivative)
qed(insert assms(1), auto simp add:field_simps)
then guess x ..
thus ?thesis apply(rule_tac x=x in bexI)
apply(drule fun_cong[of _ _ "b - a"]) by auto
qed

lemma mvt_simple:
fixes f::"real \<Rightarrow> real"
assumes "a<b" and "\<forall>x\<in>{a..b}. (f has_derivative f' x) (at x within {a..b})"
shows "\<exists>x\<in>{a<..<b}. f b - f a = f' x (b - a)"
apply(rule mvt)
apply(rule assms(1), rule differentiable_imp_continuous_on)
unfolding differentiable_on_def differentiable_def defer
proof
fix x assume x:"x \<in> {a<..<b}" show "(f has_derivative f' x) (at x)"
unfolding has_derivative_within_open[OF x open_interval,THEN sym]
apply(rule has_derivative_within_subset)
apply(rule assms(2)[rule_format])
using x by auto
qed(insert assms(2), auto)

lemma mvt_very_simple:
fixes f::"real \<Rightarrow> real"
assumes "a \<le> b" and "\<forall>x\<in>{a..b}. (f has_derivative f'(x)) (at x within {a..b})"
shows "\<exists>x\<in>{a..b}. f b - f a = f' x (b - a)"
proof (cases "a = b")
interpret bounded_linear "f' b" using assms(2) assms(1) by auto
case True thus ?thesis apply(rule_tac x=a in bexI)
using assms(2)[THEN bspec[where x=a]] unfolding has_derivative_def
unfolding True using zero by auto next
case False thus ?thesis using mvt_simple[OF _ assms(2)] using assms(1) by auto
qed

text {* A nice generalization (see Havin's proof of 5.19 from Rudin's book). *}

lemma mvt_general:
fixes f::"real\<Rightarrow>'a::euclidean_space"
assumes "a<b" and "continuous_on {a..b} f"
assumes "\<forall>x\<in>{a<..<b}. (f has_derivative f'(x)) (at x)"
shows "\<exists>x\<in>{a<..<b}. norm(f b - f a) \<le> norm(f'(x) (b - a))"
proof-
have "\<exists>x\<in>{a<..<b}. (op \<bullet> (f b - f a) \<circ> f) b - (op \<bullet> (f b - f a) \<circ> f) a = (f b - f a) \<bullet> f' x (b - a)"
apply(rule mvt) apply(rule assms(1))
apply(rule continuous_on_inner continuous_on_intros assms(2))+
unfolding o_def apply(rule,rule has_derivative_intros)
using assms(3) by auto
then guess x .. note x=this
show ?thesis proof(cases "f a = f b")
case False
have "norm (f b - f a) * norm (f b - f a) = norm (f b - f a)^2"
by (simp add: power2_eq_square)
also have "\<dots> = (f b - f a) \<bullet> (f b - f a)" unfolding power2_norm_eq_inner ..
also have "\<dots> = (f b - f a) \<bullet> f' x (b - a)"
using x unfolding inner_simps by (auto simp add: inner_diff_left)
also have "\<dots> \<le> norm (f b - f a) * norm (f' x (b - a))"
by (rule norm_cauchy_schwarz)
finally show ?thesis using False x(1)
by (auto simp add: real_mult_left_cancel)
next
case True thus ?thesis using assms(1)
apply (rule_tac x="(a + b) /2" in bexI) by auto
qed
qed

text {* Still more general bound theorem. *}

lemma differentiable_bound:
fixes f::"'a::euclidean_space \<Rightarrow> 'b::euclidean_space"
assumes "convex s" and "\<forall>x\<in>s. (f has_derivative f'(x)) (at x within s)"
assumes "\<forall>x\<in>s. onorm(f' x) \<le> B" and x:"x\<in>s" and y:"y\<in>s"
shows "norm(f x - f y) \<le> B * norm(x - y)"
proof-
let ?p = "\<lambda>u. x + u *\<^sub>R (y - x)"
have *:"\<And>u. u\<in>{0..1} \<Longrightarrow> x + u *\<^sub>R (y - x) \<in> s"
using assms(1)[unfolded convex_alt,rule_format,OF x y]
unfolding scaleR_left_diff_distrib scaleR_right_diff_distrib
by (auto simp add: algebra_simps)
hence 1:"continuous_on {0..1} (f \<circ> ?p)" apply-
apply(rule continuous_on_intros)+
unfolding continuous_on_eq_continuous_within
apply(rule,rule differentiable_imp_continuous_within)
unfolding differentiable_def apply(rule_tac x="f' xa" in exI)
apply(rule has_derivative_within_subset)
apply(rule assms(2)[rule_format]) by auto
have 2:"\<forall>u\<in>{0<..<1}. ((f \<circ> ?p) has_derivative f' (x + u *\<^sub>R (y - x)) \<circ> (\<lambda>u. 0 + u *\<^sub>R (y - x))) (at u)"
proof rule
case goal1
let ?u = "x + u *\<^sub>R (y - x)"
have "(f \<circ> ?p has_derivative (f' ?u) \<circ> (\<lambda>u. 0 + u *\<^sub>R (y - x))) (at u within {0<..<1})"
apply(rule diff_chain_within) apply(rule has_derivative_intros)+
apply(rule has_derivative_within_subset)
apply(rule assms(2)[rule_format]) using goal1 * by auto
thus ?case
unfolding has_derivative_within_open[OF goal1 open_interval] by auto
qed
guess u using mvt_general[OF zero_less_one 1 2] .. note u = this
have **:"\<And>x y. x\<in>s \<Longrightarrow> norm (f' x y) \<le> B * norm y"
proof-
case goal1
have "norm (f' x y) \<le> onorm (f' x) * norm y"
using onorm(1)[OF derivative_is_linear[OF assms(2)[rule_format,OF goal1]]] by assumption
also have "\<dots> \<le> B * norm y"
apply(rule mult_right_mono)
using assms(3)[rule_format,OF goal1]
by(auto simp add:field_simps)
finally show ?case by simp
qed
have "norm (f x - f y) = norm ((f \<circ> (\<lambda>u. x + u *\<^sub>R (y - x))) 1 - (f \<circ> (\<lambda>u. x + u *\<^sub>R (y - x))) 0)"
by(auto simp add:norm_minus_commute)
also have "\<dots> \<le> norm (f' (x + u *\<^sub>R (y - x)) (y - x))" using u by auto
also have "\<dots> \<le> B * norm(y - x)" apply(rule **) using * and u by auto
finally show ?thesis by(auto simp add:norm_minus_commute)
qed

lemma differentiable_bound_real:
fixes f::"real \<Rightarrow> real"
assumes "convex s" and "\<forall>x\<in>s. (f has_derivative f' x) (at x within s)"
assumes "\<forall>x\<in>s. onorm(f' x) \<le> B" and x:"x\<in>s" and y:"y\<in>s"
shows "norm(f x - f y) \<le> B * norm(x - y)"
using differentiable_bound[of s f f' B x y]
unfolding Ball_def image_iff o_def using assms by auto

text {* In particular. *}

lemma has_derivative_zero_constant:
fixes f::"real\<Rightarrow>real"
assumes "convex s" "\<forall>x\<in>s. (f has_derivative (\<lambda>h. 0)) (at x within s)"
shows "\<exists>c. \<forall>x\<in>s. f x = c"
proof(cases "s={}")
case False then obtain x where "x\<in>s" by auto
have "\<And>y. y\<in>s \<Longrightarrow> f x = f y" proof- case goal1
thus ?case
using differentiable_bound_real[OF assms(1-2), of 0 x y] and `x\<in>s`
unfolding onorm_const by auto qed
thus ?thesis apply(rule_tac x="f x" in exI) by auto
qed auto

lemma has_derivative_zero_unique: fixes f::"real\<Rightarrow>real"
assumes "convex s" and "a \<in> s" and "f a = c"
assumes "\<forall>x\<in>s. (f has_derivative (\<lambda>h. 0)) (at x within s)" and "x\<in>s"
shows "f x = c"
using has_derivative_zero_constant[OF assms(1,4)] using assms(2-3,5) by auto

subsection {* Differentiability of inverse function (most basic form). *}

lemma has_derivative_inverse_basic:
fixes f::"'b::euclidean_space \<Rightarrow> 'c::euclidean_space"
assumes "(f has_derivative f') (at (g y))"
assumes "bounded_linear g'" and "g' \<circ> f' = id" and "continuous (at y) g"
assumes "open t" and "y \<in> t" and "\<forall>z\<in>t. f(g z) = z"
shows "(g has_derivative g') (at y)"
proof-
interpret f': bounded_linear f'
using assms unfolding has_derivative_def by auto
interpret g': bounded_linear g' using assms by auto
guess C using bounded_linear.pos_bounded[OF assms(2)] .. note C = this
(*  have fgid:"\<And>x. g' (f' x) = x" using assms(3) unfolding o_def id_def apply()*)
have lem1:"\<forall>e>0. \<exists>d>0. \<forall>z. norm(z - y) < d \<longrightarrow> norm(g z - g y - g'(z - y)) \<le> e * norm(g z - g y)"
proof(rule,rule)
case goal1
have *:"e / C > 0" apply(rule divide_pos_pos) using `e>0` C by auto
guess d0 using assms(1)[unfolded has_derivative_at_alt,THEN conjunct2,rule_format,OF *] .. note d0=this
guess d1 using assms(4)[unfolded continuous_at Lim_at,rule_format,OF d0[THEN conjunct1]] .. note d1=this
guess d2 using assms(5)[unfolded open_dist,rule_format,OF assms(6)] .. note d2=this
guess d using real_lbound_gt_zero[OF d1[THEN conjunct1] d2[THEN conjunct1]] .. note d=this
thus ?case apply(rule_tac x=d in exI) apply rule defer
proof(rule,rule)
fix z assume as:"norm (z - y) < d" hence "z\<in>t"
using d2 d unfolding dist_norm by auto
have "norm (g z - g y - g' (z - y)) \<le> norm (g' (f (g z) - y - f' (g z - g y)))"
unfolding g'.diff f'.diff
unfolding assms(3)[unfolded o_def id_def, THEN fun_cong]
unfolding assms(7)[rule_format,OF `z\<in>t`]
apply(subst norm_minus_cancel[THEN sym]) by auto
also have "\<dots> \<le> norm(f (g z) - y - f' (g z - g y)) * C"
by (rule C [THEN conjunct2, rule_format])
also have "\<dots> \<le> (e / C) * norm (g z - g y) * C"
apply(rule mult_right_mono)
apply(rule d0[THEN conjunct2,rule_format,unfolded assms(7)[rule_format,OF `y\<in>t`]])
apply(cases "z=y") defer
apply(rule d1[THEN conjunct2, unfolded dist_norm,rule_format])
using as d C d0 by auto
also have "\<dots> \<le> e * norm (g z - g y)"
using C by (auto simp add: field_simps)
finally show "norm (g z - g y - g' (z - y)) \<le> e * norm (g z - g y)"
by simp
qed auto
qed
have *:"(0::real) < 1 / 2" by auto
guess d using lem1[rule_format,OF *] .. note d=this
def B\<equiv>"C*2"
have "B>0" unfolding B_def using C by auto
have lem2:"\<forall>z. norm(z - y) < d \<longrightarrow> norm(g z - g y) \<le> B * norm(z - y)"
proof(rule,rule) case goal1
have "norm (g z - g y) \<le> norm(g' (z - y)) + norm ((g z - g y) - g'(z - y))"
by(rule norm_triangle_sub)
also have "\<dots> \<le> norm(g' (z - y)) + 1 / 2 * norm (g z - g y)"
apply(rule add_left_mono) using d and goal1 by auto
also have "\<dots> \<le> norm (z - y) * C + 1 / 2 * norm (g z - g y)"
apply(rule add_right_mono) using C by auto
finally show ?case unfolding B_def by(auto simp add:field_simps)
qed
show ?thesis unfolding has_derivative_at_alt
proof(rule,rule assms,rule,rule) case goal1
hence *:"e/B >0" apply-apply(rule divide_pos_pos) using `B>0` by auto
guess d' using lem1[rule_format,OF *] .. note d'=this
guess k using real_lbound_gt_zero[OF d[THEN conjunct1] d'[THEN conjunct1]] .. note k=this
show ?case
apply(rule_tac x=k in exI,rule) defer
proof(rule,rule)
fix z assume as:"norm(z - y) < k"
hence "norm (g z - g y - g' (z - y)) \<le> e / B * norm(g z - g y)"
using d' k by auto
also have "\<dots> \<le> e * norm(z - y)"
unfolding times_divide_eq_left pos_divide_le_eq[OF `B>0`]
using lem2[THEN spec[where x=z]] using k as using `e>0`
by (auto simp add: field_simps)
finally show "norm (g z - g y - g' (z - y)) \<le> e * norm (z - y)"
by simp qed(insert k, auto)
qed
qed

text {* Simply rewrite that based on the domain point x. *}

lemma has_derivative_inverse_basic_x:
fixes f::"'b::euclidean_space \<Rightarrow> 'c::euclidean_space"
assumes "(f has_derivative f') (at x)" "bounded_linear g'" "g' o f' = id"
"continuous (at (f x)) g" "g(f x) = x" "open t" "f x \<in> t" "\<forall>y\<in>t. f(g y) = y"
shows "(g has_derivative g') (at (f(x)))"
apply(rule has_derivative_inverse_basic) using assms by auto

text {* This is the version in Dieudonne', assuming continuity of f and g. *}

lemma has_derivative_inverse_dieudonne:
fixes f::"'a::euclidean_space \<Rightarrow> 'b::euclidean_space"
assumes "open s" "open (f ` s)" "continuous_on s f" "continuous_on (f ` s) g" "\<forall>x\<in>s. g(f x) = x"
(**) "x\<in>s" "(f has_derivative f') (at x)"  "bounded_linear g'" "g' o f' = id"
shows "(g has_derivative g') (at (f x))"
apply(rule has_derivative_inverse_basic_x[OF assms(7-9) _ _ assms(2)])
using assms(3-6) unfolding continuous_on_eq_continuous_at[OF assms(1)]
continuous_on_eq_continuous_at[OF assms(2)] by auto

text {* Here's the simplest way of not assuming much about g. *}

lemma has_derivative_inverse:
fixes f::"'a::euclidean_space \<Rightarrow> 'b::euclidean_space"
assumes "compact s" "x \<in> s" "f x \<in> interior(f ` s)" "continuous_on s f"
"\<forall>y\<in>s. g(f y) = y" "(f has_derivative f') (at x)" "bounded_linear g'" "g' \<circ> f' = id"
shows "(g has_derivative g') (at (f x))"
proof-
{ fix y assume "y\<in>interior (f ` s)"
then obtain x where "x\<in>s" and *:"y = f x"
unfolding image_iff using interior_subset by auto
have "f (g y) = y" unfolding * and assms(5)[rule_format,OF `x\<in>s`] ..
} note * = this
show ?thesis
apply(rule has_derivative_inverse_basic_x[OF assms(6-8)])
apply(rule continuous_on_interior[OF _ assms(3)])
apply(rule continuous_on_inv[OF assms(4,1)])
apply(rule assms(2,5) assms(5)[rule_format] open_interior assms(3))+
by(rule, rule *, assumption)
qed

subsection {* Proving surjectivity via Brouwer fixpoint theorem. *}

lemma brouwer_surjective:
fixes f::"'n::ordered_euclidean_space \<Rightarrow> 'n"
assumes "compact t" "convex t"  "t \<noteq> {}" "continuous_on t f"
"\<forall>x\<in>s. \<forall>y\<in>t. x + (y - f y) \<in> t" "x\<in>s"
shows "\<exists>y\<in>t. f y = x"
proof-
have *:"\<And>x y. f y = x \<longleftrightarrow> x + (y - f y) = y"
by(auto simp add:algebra_simps)
show ?thesis
unfolding *
apply(rule brouwer[OF assms(1-3), of "\<lambda>y. x + (y - f y)"])
apply(rule continuous_on_intros assms)+ using assms(4-6) by auto
qed

lemma brouwer_surjective_cball:
fixes f::"'n::ordered_euclidean_space \<Rightarrow> 'n"
assumes "0 < e" "continuous_on (cball a e) f"
"\<forall>x\<in>s. \<forall>y\<in>cball a e. x + (y - f y) \<in> cball a e" "x\<in>s"
shows "\<exists>y\<in>cball a e. f y = x"
apply(rule brouwer_surjective)
apply(rule compact_cball convex_cball)+
unfolding cball_eq_empty using assms by auto

text {* See Sussmann: "Multidifferential calculus", Theorem 2.1.1 *}

lemma sussmann_open_mapping:
fixes f::"'a::euclidean_space \<Rightarrow> 'b::ordered_euclidean_space"
assumes "open s" "continuous_on s f" "x \<in> s"
"(f has_derivative f') (at x)" "bounded_linear g'" "f' \<circ> g' = id"
"t \<subseteq> s" "x \<in> interior t"
shows "f x \<in> interior (f ` t)"
proof-
interpret f':bounded_linear f'
using assms unfolding has_derivative_def by auto
interpret g':bounded_linear g' using assms by auto
guess B using bounded_linear.pos_bounded[OF assms(5)] .. note B=this
hence *:"1/(2*B)>0" by (auto intro!: divide_pos_pos)
guess e0 using assms(4)[unfolded has_derivative_at_alt,THEN conjunct2,rule_format,OF *] .. note e0=this
guess e1 using assms(8)[unfolded mem_interior_cball] .. note e1=this
have *:"0<e0/B" "0<e1/B"
apply(rule_tac[!] divide_pos_pos) using e0 e1 B by auto
guess e using real_lbound_gt_zero[OF *] .. note e=this
have "\<forall>z\<in>cball (f x) (e/2). \<exists>y\<in>cball (f x) e. f (x + g' (y - f x)) = z"
apply(rule,rule brouwer_surjective_cball[where s="cball (f x) (e/2)"])
prefer 3 apply(rule,rule)
proof-
show "continuous_on (cball (f x) e) (\<lambda>y. f (x + g' (y - f x)))"
unfolding g'.diff
apply(rule continuous_on_compose[of _ _ f, unfolded o_def])
apply(rule continuous_on_intros linear_continuous_on[OF assms(5)])+
apply(rule continuous_on_subset[OF assms(2)])
apply(rule,unfold image_iff,erule bexE)
proof-
fix y z assume as:"y \<in>cball (f x) e"  "z = x + (g' y - g' (f x))"
have "dist x z = norm (g' (f x) - g' y)"
unfolding as(2) and dist_norm by auto
also have "\<dots> \<le> norm (f x - y) * B"
unfolding g'.diff[THEN sym] using B by auto
also have "\<dots> \<le> e * B"
using as(1)[unfolded mem_cball dist_norm] using B by auto
also have "\<dots> \<le> e1" using e unfolding less_divide_eq using B by auto
finally have "z\<in>cball x e1" unfolding mem_cball by force
thus "z \<in> s" using e1 assms(7) by auto
qed
next
fix y z assume as:"y \<in> cball (f x) (e / 2)" "z \<in> cball (f x) e"
have "norm (g' (z - f x)) \<le> norm (z - f x) * B" using B by auto
also have "\<dots> \<le> e * B" apply(rule mult_right_mono)
using as(2)[unfolded mem_cball dist_norm] and B
unfolding norm_minus_commute by auto
also have "\<dots> < e0" using e and B unfolding less_divide_eq by auto
finally have *:"norm (x + g' (z - f x) - x) < e0" by auto
have **:"f x + f' (x + g' (z - f x) - x) = z"
using assms(6)[unfolded o_def id_def,THEN cong] by auto
have "norm (f x - (y + (z - f (x + g' (z - f x))))) \<le> norm (f (x + g' (z - f x)) - z) + norm (f x - y)"
using norm_triangle_ineq[of "f (x + g'(z - f x)) - z" "f x - y"]
by (auto simp add: algebra_simps)
also have "\<dots> \<le> 1 / (B * 2) * norm (g' (z - f x)) + norm (f x - y)"
using e0[THEN conjunct2,rule_format,OF *]
unfolding algebra_simps ** by auto
also have "\<dots> \<le> 1 / (B * 2) * norm (g' (z - f x)) + e/2"
using as(1)[unfolded mem_cball dist_norm] by auto
also have "\<dots> \<le> 1 / (B * 2) * B * norm (z - f x) + e/2"
using * and B by (auto simp add: field_simps)
also have "\<dots> \<le> 1 / 2 * norm (z - f x) + e/2" by auto
also have "\<dots> \<le> e/2 + e/2" apply(rule add_right_mono)
using as(2)[unfolded mem_cball dist_norm]
unfolding norm_minus_commute by auto
finally show "y + (z - f (x + g' (z - f x))) \<in> cball (f x) e"
unfolding mem_cball dist_norm by auto
qed(insert e, auto) note lem = this
show ?thesis unfolding mem_interior apply(rule_tac x="e/2" in exI)
apply(rule,rule divide_pos_pos) prefer 3
proof
fix y assume "y \<in> ball (f x) (e/2)"
hence *:"y\<in>cball (f x) (e/2)" by auto
guess z using lem[rule_format,OF *] .. note z=this
hence "norm (g' (z - f x)) \<le> norm (z - f x) * B"
using B by (auto simp add: field_simps)
also have "\<dots> \<le> e * B"
apply (rule mult_right_mono) using z(1)
unfolding mem_cball dist_norm norm_minus_commute using B by auto
also have "\<dots> \<le> e1"  using e B unfolding less_divide_eq by auto
finally have "x + g'(z - f x) \<in> t" apply-
apply(rule e1[THEN conjunct2,unfolded subset_eq,rule_format])
unfolding mem_cball dist_norm by auto
thus "y \<in> f ` t" using z by auto
qed(insert e, auto)
qed

text {* Hence the following eccentric variant of the inverse function theorem.    *)
(* This has no continuity assumptions, but we do need the inverse function.  *)
(* We could put f' o g = I but this happens to fit with the minimal linear   *)
(* algebra theory I've set up so far. *}

(* move  before left_inverse_linear in Euclidean_Space*)

lemma right_inverse_linear:
fixes f::"'a::euclidean_space => 'a"
assumes lf: "linear f" and gf: "f o g = id"
shows "linear g"
proof-
from gf have fi: "surj f" by (auto simp add: surj_def o_def id_def) metis
from linear_surjective_isomorphism[OF lf fi]
obtain h:: "'a => 'a" where
h: "linear h" "\<forall>x. h (f x) = x" "\<forall>x. f (h x) = x" by blast
have "h = g" apply (rule ext) using gf h(2,3)
by (simp add: o_def id_def fun_eq_iff) metis
with h(1) show ?thesis by blast
qed

lemma has_derivative_inverse_strong:
fixes f::"'n::ordered_euclidean_space \<Rightarrow> 'n"
assumes "open s" and "x \<in> s" and "continuous_on s f"
assumes "\<forall>x\<in>s. g(f x) = x" "(f has_derivative f') (at x)" and "f' o g' = id"
shows "(g has_derivative g') (at (f x))"
proof-
have linf:"bounded_linear f'"
using assms(5) unfolding has_derivative_def by auto
hence ling:"bounded_linear g'"
unfolding linear_conv_bounded_linear[THEN sym]
apply- apply(rule right_inverse_linear) using assms(6) by auto
moreover have "g' \<circ> f' = id" using assms(6) linf ling
unfolding linear_conv_bounded_linear[THEN sym]
using linear_inverse_left by auto
moreover have *:"\<forall>t\<subseteq>s. x\<in>interior t \<longrightarrow> f x \<in> interior (f ` t)"
apply(rule,rule,rule,rule sussmann_open_mapping )
apply(rule assms ling)+ by auto
have "continuous (at (f x)) g" unfolding continuous_at Lim_at
proof(rule,rule)
fix e::real assume "e>0"
hence "f x \<in> interior (f ` (ball x e \<inter> s))"
using *[rule_format,of "ball x e \<inter> s"] `x\<in>s`
by(auto simp add: interior_open[OF open_ball] interior_open[OF assms(1)])
then guess d unfolding mem_interior .. note d=this
show "\<exists>d>0. \<forall>y. 0 < dist y (f x) \<and> dist y (f x) < d \<longrightarrow> dist (g y) (g (f x)) < e"
apply(rule_tac x=d in exI)
apply(rule,rule d[THEN conjunct1])
proof(rule,rule) case goal1
hence "g y \<in> g ` f ` (ball x e \<inter> s)"
using d[THEN conjunct2,unfolded subset_eq,THEN bspec[where x=y]]
by(auto simp add:dist_commute)
hence "g y \<in> ball x e \<inter> s" using assms(4) by auto
thus "dist (g y) (g (f x)) < e"
using assms(4)[rule_format,OF `x\<in>s`]
by (auto simp add: dist_commute)
qed
qed
moreover have "f x \<in> interior (f ` s)"
apply(rule sussmann_open_mapping)
apply(rule assms ling)+
using interior_open[OF assms(1)] and `x\<in>s` by auto
moreover have "\<And>y. y \<in> interior (f ` s) \<Longrightarrow> f (g y) = y"
proof- case goal1
hence "y\<in>f ` s" using interior_subset by auto
then guess z unfolding image_iff ..
thus ?case using assms(4) by auto
qed
ultimately show ?thesis
apply- apply(rule has_derivative_inverse_basic_x[OF assms(5)])
using assms by auto
qed

text {* A rewrite based on the other domain. *}

lemma has_derivative_inverse_strong_x:
fixes f::"'a::ordered_euclidean_space \<Rightarrow> 'a"
assumes "open s" and "g y \<in> s" and "continuous_on s f"
assumes "\<forall>x\<in>s. g(f x) = x" "(f has_derivative f') (at (g y))"
assumes "f' o g' = id" and "f(g y) = y"
shows "(g has_derivative g') (at y)"
using has_derivative_inverse_strong[OF assms(1-6)] unfolding assms(7) by simp

text {* On a region. *}

lemma has_derivative_inverse_on:
fixes f::"'n::ordered_euclidean_space \<Rightarrow> 'n"
assumes "open s" and "\<forall>x\<in>s. (f has_derivative f'(x)) (at x)"
assumes "\<forall>x\<in>s. g(f x) = x" and "f'(x) o g'(x) = id" and "x\<in>s"
shows "(g has_derivative g'(x)) (at (f x))"
apply(rule has_derivative_inverse_strong[where g'="g' x" and f=f])
apply(rule assms)+
unfolding continuous_on_eq_continuous_at[OF assms(1)]
apply(rule,rule differentiable_imp_continuous_at)
unfolding differentiable_def using assms by auto

text {* Invertible derivative continous at a point implies local
injectivity. It's only for this we need continuity of the derivative,
except of course if we want the fact that the inverse derivative is
also continuous. So if we know for some other reason that the inverse
function exists, it's OK. *}

lemma bounded_linear_sub:
"bounded_linear f \<Longrightarrow> bounded_linear g ==> bounded_linear (\<lambda>x. f x - g x)"
using bounded_linear_add[of f "\<lambda>x. - g x"] bounded_linear_minus[of g]
by (auto simp add: algebra_simps)

lemma has_derivative_locally_injective:
fixes f::"'n::euclidean_space \<Rightarrow> 'm::euclidean_space"
assumes "a \<in> s" "open s" "bounded_linear g'" "g' o f'(a) = id"
"\<forall>x\<in>s. (f has_derivative f'(x)) (at x)"
"\<forall>e>0. \<exists>d>0. \<forall>x. dist a x < d \<longrightarrow> onorm(\<lambda>v. f' x v - f' a v) < e"
obtains t where "a \<in> t" "open t" "\<forall>x\<in>t. \<forall>x'\<in>t. (f x' = f x) \<longrightarrow> (x' = x)"
proof-
interpret bounded_linear g' using assms by auto
note f'g' = assms(4)[unfolded id_def o_def,THEN cong]
have "g' (f' a (\<chi>\<chi> i.1)) = (\<chi>\<chi> i.1)" "(\<chi>\<chi> i.1) \<noteq> (0::'n)" defer
apply(subst euclidean_eq) using f'g' by auto
hence *:"0 < onorm g'"
unfolding onorm_pos_lt[OF assms(3)[unfolded linear_linear]] by fastforce
def k \<equiv> "1 / onorm g' / 2" have *:"k>0" unfolding k_def using * by auto
guess d1 using assms(6)[rule_format,OF *] .. note d1=this
from `open s` obtain d2 where "d2>0" "ball a d2 \<subseteq> s" using `a\<in>s` ..
obtain d2 where "d2>0" "ball a d2 \<subseteq> s" using assms(2,1) ..
guess d2 using assms(2)[unfolded open_contains_ball,rule_format,OF `a\<in>s`] ..
note d2=this
guess d using real_lbound_gt_zero[OF d1[THEN conjunct1] d2[THEN conjunct1]] ..
note d = this
show ?thesis
proof
show "a\<in>ball a d" using d by auto
show "\<forall>x\<in>ball a d. \<forall>x'\<in>ball a d. f x' = f x \<longrightarrow> x' = x"
proof (intro strip)
fix x y assume as:"x\<in>ball a d" "y\<in>ball a d" "f x = f y"
def ph \<equiv> "\<lambda>w. w - g'(f w - f x)"
have ph':"ph = g' \<circ> (\<lambda>w. f' a w - (f w - f x))"
unfolding ph_def o_def unfolding diff using f'g'
by (auto simp add: algebra_simps)
have "norm (ph x - ph y) \<le> (1/2) * norm (x - y)"
apply(rule differentiable_bound[OF convex_ball _ _ as(1-2), where f'="\<lambda>x v. v - g'(f' x v)"])
apply(rule_tac[!] ballI)
proof-
fix u assume u:"u \<in> ball a d"
hence "u\<in>s" using d d2 by auto
have *:"(\<lambda>v. v - g' (f' u v)) = g' \<circ> (\<lambda>w. f' a w - f' u w)"
unfolding o_def and diff using f'g' by auto
show "(ph has_derivative (\<lambda>v. v - g' (f' u v))) (at u within ball a d)"
unfolding ph' * apply(rule diff_chain_within) defer
apply(rule bounded_linear.has_derivative'[OF assms(3)])
apply(rule has_derivative_intros) defer
apply(rule has_derivative_sub[where g'="\<lambda>x.0",unfolded diff_0_right])
apply(rule has_derivative_at_within)
using assms(5) and `u\<in>s` `a\<in>s`
by(auto intro!: has_derivative_intros bounded_linear.has_derivative' derivative_linear)
have **:"bounded_linear (\<lambda>x. f' u x - f' a x)"
"bounded_linear (\<lambda>x. f' a x - f' u x)"
apply(rule_tac[!] bounded_linear_sub)
apply(rule_tac[!] derivative_linear)
using assms(5) `u\<in>s` `a\<in>s` by auto
have "onorm (\<lambda>v. v - g' (f' u v)) \<le> onorm g' * onorm (\<lambda>w. f' a w - f' u w)"
unfolding * apply(rule onorm_compose)
unfolding linear_conv_bounded_linear by(rule assms(3) **)+
also have "\<dots> \<le> onorm g' * k"
apply(rule mult_left_mono)
using d1[THEN conjunct2,rule_format,of u]
using onorm_neg[OF **(1)[unfolded linear_linear]]
using d and u and onorm_pos_le[OF assms(3)[unfolded linear_linear]]
by (auto simp add: algebra_simps)
also have "\<dots> \<le> 1/2" unfolding k_def by auto
finally show "onorm (\<lambda>v. v - g' (f' u v)) \<le> 1 / 2" by assumption
qed
moreover have "norm (ph y - ph x) = norm (y - x)"
apply(rule arg_cong[where f=norm])
unfolding ph_def using diff unfolding as by auto
ultimately show "x = y" unfolding norm_minus_commute by auto
qed
qed auto
qed

subsection {* Uniformly convergent sequence of derivatives. *}

lemma has_derivative_sequence_lipschitz_lemma:
fixes f::"nat \<Rightarrow> 'm::euclidean_space \<Rightarrow> 'n::euclidean_space"
assumes "convex s"
assumes "\<forall>n. \<forall>x\<in>s. ((f n) has_derivative (f' n x)) (at x within s)"
assumes "\<forall>n\<ge>N. \<forall>x\<in>s. \<forall>h. norm(f' n x h - g' x h) \<le> e * norm(h)"
shows "\<forall>m\<ge>N. \<forall>n\<ge>N. \<forall>x\<in>s. \<forall>y\<in>s. norm((f m x - f n x) - (f m y - f n y)) \<le> 2 * e * norm(x - y)"
proof (default)+
fix m n x y assume as:"N\<le>m" "N\<le>n" "x\<in>s" "y\<in>s"
show "norm((f m x - f n x) - (f m y - f n y)) \<le> 2 * e * norm(x - y)"
apply(rule differentiable_bound[where f'="\<lambda>x h. f' m x h - f' n x h", OF assms(1) _ _ as(3-4)])
apply(rule_tac[!] ballI)
proof-
fix x assume "x\<in>s"
show "((\<lambda>a. f m a - f n a) has_derivative (\<lambda>h. f' m x h - f' n x h)) (at x within s)"
by(rule has_derivative_intros assms(2)[rule_format] `x\<in>s`)+
{ fix h
have "norm (f' m x h - f' n x h) \<le> norm (f' m x h - g' x h) + norm (f' n x h - g' x h)"
using norm_triangle_ineq[of "f' m x h - g' x h" "- f' n x h + g' x h"]
unfolding norm_minus_commute by (auto simp add: algebra_simps)
also have "\<dots> \<le> e * norm h+ e * norm h"
using assms(3)[rule_format,OF `N\<le>m` `x\<in>s`, of h]
using assms(3)[rule_format,OF `N\<le>n` `x\<in>s`, of h]
by(auto simp add:field_simps)
finally have "norm (f' m x h - f' n x h) \<le> 2 * e * norm h" by auto }
thus "onorm (\<lambda>h. f' m x h - f' n x h) \<le> 2 * e"
apply-apply(rule onorm(2)) apply(rule linear_compose_sub)
unfolding linear_conv_bounded_linear
using assms(2)[rule_format,OF `x\<in>s`, THEN derivative_linear]
by auto
qed
qed

lemma has_derivative_sequence_lipschitz:
fixes f::"nat \<Rightarrow> 'm::euclidean_space \<Rightarrow> 'n::euclidean_space"
assumes "convex s"
assumes "\<forall>n. \<forall>x\<in>s. ((f n) has_derivative (f' n x)) (at x within s)"
assumes "\<forall>e>0. \<exists>N. \<forall>n\<ge>N. \<forall>x\<in>s. \<forall>h. norm(f' n x h - g' x h) \<le> e * norm(h)"
assumes "0 < e"
shows "\<forall>e>0. \<exists>N. \<forall>m\<ge>N. \<forall>n\<ge>N. \<forall>x\<in>s. \<forall>y\<in>s. norm((f m x - f n x) - (f m y - f n y)) \<le> e * norm(x - y)"
proof(rule,rule)
case goal1 have *:"2 * (1/2* e) = e" "1/2 * e >0" using `e>0` by auto
guess N using assms(3)[rule_format,OF *(2)] ..
thus ?case
apply(rule_tac x=N in exI)
apply(rule has_derivative_sequence_lipschitz_lemma[where e="1/2 *e", unfolded *])
using assms by auto
qed

lemma has_derivative_sequence:
fixes f::"nat\<Rightarrow> 'm::euclidean_space \<Rightarrow> 'n::euclidean_space"
assumes "convex s"
assumes "\<forall>n. \<forall>x\<in>s. ((f n) has_derivative (f' n x)) (at x within s)"
assumes "\<forall>e>0. \<exists>N. \<forall>n\<ge>N. \<forall>x\<in>s. \<forall>h. norm(f' n x h - g' x h) \<le> e * norm(h)"
assumes "x0 \<in> s" and "((\<lambda>n. f n x0) ---> l) sequentially"
shows "\<exists>g. \<forall>x\<in>s. ((\<lambda>n. f n x) ---> g x) sequentially \<and>
(g has_derivative g'(x)) (at x within s)"
proof-
have lem1:"\<forall>e>0. \<exists>N. \<forall>m\<ge>N. \<forall>n\<ge>N. \<forall>x\<in>s. \<forall>y\<in>s. norm((f m x - f n x) - (f m y - f n y)) \<le> e * norm(x - y)"
apply(rule has_derivative_sequence_lipschitz[where e="42::nat"])
apply(rule assms)+ by auto
have "\<exists>g. \<forall>x\<in>s. ((\<lambda>n. f n x) ---> g x) sequentially"
apply(rule bchoice) unfolding convergent_eq_cauchy
proof
fix x assume "x\<in>s" show "Cauchy (\<lambda>n. f n x)"
proof(cases "x=x0")
case True thus ?thesis using convergent_imp_cauchy[OF assms(5)] by auto
next
case False show ?thesis unfolding Cauchy_def
proof(rule,rule)
fix e::real assume "e>0"
hence *:"e/2>0" "e/2/norm(x-x0)>0"
using False by (auto intro!: divide_pos_pos)
guess M using convergent_imp_cauchy[OF assms(5), unfolded Cauchy_def, rule_format,OF *(1)] .. note M=this
guess N using lem1[rule_format,OF *(2)] .. note N = this
show "\<exists>M. \<forall>m\<ge>M. \<forall>n\<ge>M. dist (f m x) (f n x) < e"
apply(rule_tac x="max M N" in exI)
proof(default+)
fix m n assume as:"max M N \<le>m" "max M N\<le>n"
have "dist (f m x) (f n x) \<le> norm (f m x0 - f n x0) + norm (f m x - f n x - (f m x0 - f n x0))"
unfolding dist_norm by(rule norm_triangle_sub)
also have "\<dots> \<le> norm (f m x0 - f n x0) + e / 2"
using N[rule_format,OF _ _ `x\<in>s` `x0\<in>s`, of m n] and as and False
by auto
also have "\<dots> < e / 2 + e / 2"
apply(rule add_strict_right_mono)
using as and M[rule_format] unfolding dist_norm by auto
finally show "dist (f m x) (f n x) < e" by auto
qed
qed
qed
qed
then guess g .. note g = this
have lem2:"\<forall>e>0. \<exists>N. \<forall>n\<ge>N. \<forall>x\<in>s. \<forall>y\<in>s. norm((f n x - f n y) - (g x - g y)) \<le> e * norm(x - y)"
proof(rule,rule)
fix e::real assume *:"e>0"
guess N using lem1[rule_format,OF *] .. note N=this
show "\<exists>N. \<forall>n\<ge>N. \<forall>x\<in>s. \<forall>y\<in>s. norm (f n x - f n y - (g x - g y)) \<le> e * norm (x - y)"
apply(rule_tac x=N in exI)
proof(default+)
fix n x y assume as:"N \<le> n" "x \<in> s" "y \<in> s"
have "eventually (\<lambda>xa. norm (f n x - f n y - (f xa x - f xa y)) \<le> e * norm (x - y)) sequentially"
unfolding eventually_sequentially
apply(rule_tac x=N in exI)
proof(rule,rule)
fix m assume "N\<le>m"
thus "norm (f n x - f n y - (f m x - f m y)) \<le> e * norm (x - y)"
using N[rule_format, of n m x y] and as
by (auto simp add: algebra_simps)
qed
thus "norm (f n x - f n y - (g x - g y)) \<le> e * norm (x - y)"
apply-
apply(rule Lim_norm_ubound[OF trivial_limit_sequentially, where f="\<lambda>m. (f n x - f n y) - (f m x - f m y)"])
apply(rule tendsto_intros g[rule_format] as)+ by assumption
qed
qed
show ?thesis unfolding has_derivative_within_alt apply(rule_tac x=g in exI)
apply(rule,rule,rule g[rule_format],assumption)
proof fix x assume "x\<in>s"
have lem3:"\<forall>u. ((\<lambda>n. f' n x u) ---> g' x u) sequentially"
unfolding LIMSEQ_def
proof(rule,rule,rule)
fix u and e::real assume "e>0"
show "\<exists>N. \<forall>n\<ge>N. dist (f' n x u) (g' x u) < e"
proof(cases "u=0")
case True guess N using assms(3)[rule_format,OF `e>0`] .. note N=this
show ?thesis apply(rule_tac x=N in exI) unfolding True
using N[rule_format,OF _ `x\<in>s`,of _ 0] and `e>0` by auto
next
case False hence *:"e / 2 / norm u > 0"
using `e>0` by (auto intro!: divide_pos_pos)
guess N using assms(3)[rule_format,OF *] .. note N=this
show ?thesis apply(rule_tac x=N in exI)
proof(rule,rule) case goal1
show ?case unfolding dist_norm
using N[rule_format,OF goal1 `x\<in>s`, of u] False `e>0`
by (auto simp add:field_simps)
qed
qed
qed
show "bounded_linear (g' x)"
unfolding linear_linear linear_def
apply(rule,rule,rule) defer
proof(rule,rule)
fix x' y z::"'m" and c::real
note lin = assms(2)[rule_format,OF `x\<in>s`,THEN derivative_linear]
show "g' x (c *\<^sub>R x') = c *\<^sub>R g' x x'"
apply(rule tendsto_unique[OF trivial_limit_sequentially])
apply(rule lem3[rule_format])
unfolding lin[unfolded bounded_linear_def bounded_linear_axioms_def,THEN conjunct2,THEN conjunct1,rule_format]
apply (intro tendsto_intros) by(rule lem3[rule_format])
show "g' x (y + z) = g' x y + g' x z"
apply(rule tendsto_unique[OF trivial_limit_sequentially])
apply(rule lem3[rule_format])
unfolding lin[unfolded bounded_linear_def additive_def,THEN conjunct1,rule_format]
apply(rule tendsto_add) by(rule lem3[rule_format])+
qed
show "\<forall>e>0. \<exists>d>0. \<forall>y\<in>s. norm (y - x) < d \<longrightarrow> norm (g y - g x - g' x (y - x)) \<le> e * norm (y - x)"
proof(rule,rule) case goal1
have *:"e/3>0" using goal1 by auto
guess N1 using assms(3)[rule_format,OF *] .. note N1=this
guess N2 using lem2[rule_format,OF *] .. note N2=this
guess d1 using assms(2)[unfolded has_derivative_within_alt, rule_format,OF `x\<in>s`, of "max N1 N2",THEN conjunct2,rule_format,OF *] .. note d1=this
show ?case apply(rule_tac x=d1 in exI) apply(rule,rule d1[THEN conjunct1])
proof(rule,rule)
fix y assume as:"y \<in> s" "norm (y - x) < d1"
let ?N ="max N1 N2"
have "norm (g y - g x - (f ?N y - f ?N x)) \<le> e /3 * norm (y - x)"
apply(subst norm_minus_cancel[THEN sym])
using N2[rule_format, OF _ `y\<in>s` `x\<in>s`, of ?N] by auto
moreover
have "norm (f ?N y - f ?N x - f' ?N x (y - x)) \<le> e / 3 * norm (y - x)"
using d1 and as by auto
ultimately
have "norm (g y - g x - f' ?N x (y - x)) \<le> 2 * e / 3 * norm (y - x)"
using norm_triangle_le[of "g y - g x - (f ?N y - f ?N x)" "f ?N y - f ?N x - f' ?N x (y - x)" "2 * e / 3 * norm (y - x)"]
by (auto simp add:algebra_simps)
moreover
have " norm (f' ?N x (y - x) - g' x (y - x)) \<le> e / 3 * norm (y - x)"
using N1 `x\<in>s` by auto
ultimately show "norm (g y - g x - g' x (y - x)) \<le> e * norm (y - x)"
using norm_triangle_le[of "g y - g x - f' (max N1 N2) x (y - x)" "f' (max N1 N2) x (y - x) - g' x (y - x)"]
by(auto simp add:algebra_simps)
qed
qed
qed
qed

text {* Can choose to line up antiderivatives if we want. *}

lemma has_antiderivative_sequence:
fixes f::"nat\<Rightarrow> 'm::euclidean_space \<Rightarrow> 'n::euclidean_space"
assumes "convex s"
assumes "\<forall>n. \<forall>x\<in>s. ((f n) has_derivative (f' n x)) (at x within s)"
assumes "\<forall>e>0. \<exists>N. \<forall>n\<ge>N. \<forall>x\<in>s. \<forall>h. norm(f' n x h - g' x h) \<le> e * norm h"
shows "\<exists>g. \<forall>x\<in>s. (g has_derivative g'(x)) (at x within s)"
proof(cases "s={}")
case False then obtain a where "a\<in>s" by auto
have *:"\<And>P Q. \<exists>g. \<forall>x\<in>s. P g x \<and> Q g x \<Longrightarrow> \<exists>g. \<forall>x\<in>s. Q g x" by auto
show ?thesis
apply(rule *)
apply(rule has_derivative_sequence[OF assms(1) _ assms(3), of "\<lambda>n x. f n x + (f 0 a - f n a)"])
apply(rule,rule)
apply(rule has_derivative_add_const, rule assms(2)[rule_format], assumption)
apply(rule `a\<in>s`) by auto
qed auto

lemma has_antiderivative_limit:
fixes g'::"'m::euclidean_space \<Rightarrow> 'm \<Rightarrow> 'n::euclidean_space"
assumes "convex s"
assumes "\<forall>e>0. \<exists>f f'. \<forall>x\<in>s. (f has_derivative (f' x)) (at x within s) \<and> (\<forall>h. norm(f' x h - g' x h) \<le> e * norm(h))"
shows "\<exists>g. \<forall>x\<in>s. (g has_derivative g'(x)) (at x within s)"
proof-
have *:"\<forall>n. \<exists>f f'. \<forall>x\<in>s. (f has_derivative (f' x)) (at x within s) \<and> (\<forall>h. norm(f' x h - g' x h) \<le> inverse (real (Suc n)) * norm(h))"
apply(rule) using assms(2)
apply(erule_tac x="inverse (real (Suc n))" in allE) by auto
guess f using *[THEN choice] .. note * = this
guess f' using *[THEN choice] .. note f=this
show ?thesis apply(rule has_antiderivative_sequence[OF assms(1), of f f']) defer
proof(rule,rule)
fix e::real assume "0<e" guess  N using reals_Archimedean[OF `e>0`] .. note N=this
show "\<exists>N. \<forall>n\<ge>N. \<forall>x\<in>s. \<forall>h. norm (f' n x h - g' x h) \<le> e * norm h"
apply(rule_tac x=N in exI)
proof(default+)
case goal1
have *:"inverse (real (Suc n)) \<le> e" apply(rule order_trans[OF _ N[THEN less_imp_le]])
using goal1(1) by(auto simp add:field_simps)
show ?case
using f[rule_format,THEN conjunct2,OF goal1(2), of n, THEN spec[where x=h]]
apply(rule order_trans) using N * apply(cases "h=0") by auto
qed
qed(insert f,auto)
qed

subsection {* Differentiation of a series. *}

definition sums_seq :: "(nat \<Rightarrow> 'a::real_normed_vector) \<Rightarrow> 'a \<Rightarrow> (nat set) \<Rightarrow> bool"
(infixl "sums'_seq" 12) where "(f sums_seq l) s \<equiv> ((\<lambda>n. setsum f (s \<inter> {0..n})) ---> l) sequentially"

lemma has_derivative_series:
fixes f::"nat \<Rightarrow> 'm::euclidean_space \<Rightarrow> 'n::euclidean_space"
assumes "convex s"
assumes "\<forall>n. \<forall>x\<in>s. ((f n) has_derivative (f' n x)) (at x within s)"
assumes "\<forall>e>0. \<exists>N. \<forall>n\<ge>N. \<forall>x\<in>s. \<forall>h. norm(setsum (\<lambda>i. f' i x h) (k \<inter> {0..n}) - g' x h) \<le> e * norm(h)"
assumes "x\<in>s" and "((\<lambda>n. f n x) sums_seq l) k"
shows "\<exists>g. \<forall>x\<in>s. ((\<lambda>n. f n x) sums_seq (g x)) k \<and> (g has_derivative g'(x)) (at x within s)"
unfolding sums_seq_def
apply(rule has_derivative_sequence[OF assms(1) _ assms(3)])
apply(rule,rule)
apply(rule has_derivative_setsum) defer
apply(rule,rule assms(2)[rule_format],assumption)
using assms(4-5) unfolding sums_seq_def by auto

subsection {* Derivative with composed bilinear function. *}

lemma has_derivative_bilinear_within:
assumes "(f has_derivative f') (at x within s)"
assumes "(g has_derivative g') (at x within s)"
assumes "bounded_bilinear h"
shows "((\<lambda>x. h (f x) (g x)) has_derivative (\<lambda>d. h (f x) (g' d) + h (f' d) (g x))) (at x within s)"
proof-
have "(g ---> g x) (at x within s)"
apply(rule differentiable_imp_continuous_within[unfolded continuous_within])
using assms(2) unfolding differentiable_def by auto
moreover
interpret f':bounded_linear f'
using assms unfolding has_derivative_def by auto
interpret g':bounded_linear g'
using assms unfolding has_derivative_def by auto
interpret h:bounded_bilinear h
using assms by auto
have "((\<lambda>y. f' (y - x)) ---> 0) (at x within s)"
unfolding f'.zero[THEN sym]
using bounded_linear.tendsto [of f' "\<lambda>y. y - x" 0 "at x within s"]
using tendsto_diff [OF Lim_within_id tendsto_const, of x x s]
unfolding id_def using assms(1) unfolding has_derivative_def by auto
hence "((\<lambda>y. f x + f' (y - x)) ---> f x) (at x within s)"
using tendsto_add[OF tendsto_const, of "\<lambda>y. f' (y - x)" 0 "at x within s" "f x"]
by auto
ultimately
have *:"((\<lambda>x'. h (f x + f' (x' - x)) ((1/(norm (x' - x))) *\<^sub>R (g x' - (g x + g' (x' - x))))
+ h ((1/ (norm (x' - x))) *\<^sub>R (f x' - (f x + f' (x' - x)))) (g x')) ---> h (f x) 0 + h 0 (g x)) (at x within s)"
apply-apply(rule tendsto_add) apply(rule_tac[!] Lim_bilinear[OF _ _ assms(3)])
using assms(1-2)  unfolding has_derivative_within by auto
guess B using bounded_bilinear.pos_bounded[OF assms(3)] .. note B=this
guess C using f'.pos_bounded .. note C=this
guess D using g'.pos_bounded .. note D=this
have bcd:"B * C * D > 0" using B C D by (auto intro!: mult_pos_pos)
have **:"((\<lambda>y. (1/(norm(y - x))) *\<^sub>R (h (f'(y - x)) (g'(y - x)))) ---> 0) (at x within s)"
unfolding Lim_within
proof(rule,rule) case goal1
hence "e/(B*C*D)>0" using B C D by(auto intro!:divide_pos_pos mult_pos_pos)
thus ?case apply(rule_tac x="e/(B*C*D)" in exI,rule)
proof(rule,rule,erule conjE)
fix y assume as:"y \<in> s" "0 < dist y x" "dist y x < e / (B * C * D)"
have "norm (h (f' (y - x)) (g' (y - x))) \<le> norm (f' (y - x)) * norm (g' (y - x)) * B" using B by auto
also have "\<dots> \<le> (norm (y - x) * C) * (D * norm (y - x)) * B"
apply(rule mult_right_mono)
apply(rule mult_mono) using B C D
by (auto simp add: field_simps intro!:mult_nonneg_nonneg)
also have "\<dots> = (B * C * D * norm (y - x)) * norm (y - x)"
by (auto simp add: field_simps)
also have "\<dots> < e * norm (y - x)"
apply(rule mult_strict_right_mono)
using as(3)[unfolded dist_norm] and as(2)
unfolding pos_less_divide_eq[OF bcd] by (auto simp add: field_simps)
finally show "dist ((1 / norm (y - x)) *\<^sub>R h (f' (y - x)) (g' (y - x))) 0 < e"
unfolding dist_norm apply-apply(cases "y = x")
by(auto simp add: field_simps)
qed
qed
have "bounded_linear (\<lambda>d. h (f x) (g' d) + h (f' d) (g x))"
apply (rule bounded_linear_add)
apply (rule bounded_linear_compose [OF h.bounded_linear_right `bounded_linear g'`])
apply (rule bounded_linear_compose [OF h.bounded_linear_left `bounded_linear f'`])
done
thus ?thesis using tendsto_add[OF * **] unfolding has_derivative_within
unfolding g'.add f'.scaleR f'.add g'.scaleR f'.diff g'.diff
h.add_right h.add_left scaleR_right_distrib h.scaleR_left h.scaleR_right h.diff_right h.diff_left
scaleR_right_diff_distrib h.zero_right h.zero_left
by(auto simp add:field_simps)
qed

lemma has_derivative_bilinear_at:
assumes "(f has_derivative f') (at x)"
assumes "(g has_derivative g') (at x)"
assumes "bounded_bilinear h"
shows "((\<lambda>x. h (f x) (g x)) has_derivative (\<lambda>d. h (f x) (g' d) + h (f' d) (g x))) (at x)"
using has_derivative_bilinear_within[of f f' x UNIV g g' h] assms by simp

subsection {* Considering derivative @{typ "real \<Rightarrow> 'b\<Colon>real_normed_vector"} as a vector. *}

definition has_vector_derivative :: "(real \<Rightarrow> 'b::real_normed_vector) \<Rightarrow> 'b \<Rightarrow> (real filter \<Rightarrow> bool)"
(infixl "has'_vector'_derivative" 12) where
"(f has_vector_derivative f') net \<equiv> (f has_derivative (\<lambda>x. x *\<^sub>R f')) net"

definition "vector_derivative f net \<equiv> (SOME f'. (f has_vector_derivative f') net)"

lemma vector_derivative_works:
fixes f::"real \<Rightarrow> 'a::real_normed_vector"
shows "f differentiable net \<longleftrightarrow> (f has_vector_derivative (vector_derivative f net)) net" (is "?l = ?r")
proof
assume ?l guess f' using `?l`[unfolded differentiable_def] .. note f' = this
then interpret bounded_linear f' by auto
show ?r unfolding vector_derivative_def has_vector_derivative_def
apply-apply(rule someI_ex,rule_tac x="f' 1" in exI)
using f' unfolding scaleR[THEN sym] by auto
next
assume ?r thus ?l
unfolding vector_derivative_def has_vector_derivative_def differentiable_def
by auto
qed

lemma vector_derivative_unique_at:
assumes "(f has_vector_derivative f') (at x)"
assumes "(f has_vector_derivative f'') (at x)"
shows "f' = f''"
proof-
have "(\<lambda>x. x *\<^sub>R f') = (\<lambda>x. x *\<^sub>R f'')"
using assms [unfolded has_vector_derivative_def]
by (rule frechet_derivative_unique_at)
thus ?thesis unfolding fun_eq_iff by auto
qed

lemma vector_derivative_unique_within_closed_interval:
fixes f::"real \<Rightarrow> 'n::ordered_euclidean_space"
assumes "a < b" and "x \<in> {a..b}"
assumes "(f has_vector_derivative f') (at x within {a..b})"
assumes "(f has_vector_derivative f'') (at x within {a..b})"
shows "f' = f''"
proof-
have *:"(\<lambda>x. x *\<^sub>R f') = (\<lambda>x. x *\<^sub>R f'')"
apply(rule frechet_derivative_unique_within_closed_interval[of "a" "b"])
using assms(3-)[unfolded has_vector_derivative_def] using assms(1-2)
by auto
show ?thesis
proof(rule ccontr)
assume "f' \<noteq> f''"
moreover
hence "(\<lambda>x. x *\<^sub>R f') 1 = (\<lambda>x. x *\<^sub>R f'') 1"
using * by (auto simp: fun_eq_iff)
ultimately show False unfolding o_def by auto
qed
qed

lemma vector_derivative_at:
shows "(f has_vector_derivative f') (at x) \<Longrightarrow> vector_derivative f (at x) = f'"
apply(rule vector_derivative_unique_at) defer apply assumption
unfolding vector_derivative_works[THEN sym] differentiable_def
unfolding has_vector_derivative_def by auto

lemma vector_derivative_within_closed_interval:
fixes f::"real \<Rightarrow> 'a::ordered_euclidean_space"
assumes "a < b" and "x \<in> {a..b}"
assumes "(f has_vector_derivative f') (at x within {a..b})"
shows "vector_derivative f (at x within {a..b}) = f'"
apply(rule vector_derivative_unique_within_closed_interval)
using vector_derivative_works[unfolded differentiable_def]
using assms by(auto simp add:has_vector_derivative_def)

lemma has_vector_derivative_within_subset:
"(f has_vector_derivative f') (at x within s) \<Longrightarrow> t \<subseteq> s \<Longrightarrow> (f has_vector_derivative f') (at x within t)"
unfolding has_vector_derivative_def apply(rule has_derivative_within_subset) by auto

lemma has_vector_derivative_const:
"((\<lambda>x. c) has_vector_derivative 0) net"
unfolding has_vector_derivative_def using has_derivative_const by auto

lemma has_vector_derivative_id: "((\<lambda>x::real. x) has_vector_derivative 1) net"
unfolding has_vector_derivative_def using has_derivative_id by auto

lemma has_vector_derivative_cmul:
"(f has_vector_derivative f') net \<Longrightarrow> ((\<lambda>x. c *\<^sub>R f x) has_vector_derivative (c *\<^sub>R f')) net"
unfolding has_vector_derivative_def
apply (drule scaleR_right_has_derivative)
by (auto simp add: algebra_simps)

lemma has_vector_derivative_cmul_eq:
assumes "c \<noteq> 0"
shows "(((\<lambda>x. c *\<^sub>R f x) has_vector_derivative (c *\<^sub>R f')) net \<longleftrightarrow> (f has_vector_derivative f') net)"
apply rule apply(drule has_vector_derivative_cmul[where c="1/c"]) defer
apply(rule has_vector_derivative_cmul) using assms by auto

lemma has_vector_derivative_neg:
"(f has_vector_derivative f') net \<Longrightarrow> ((\<lambda>x. -(f x)) has_vector_derivative (- f')) net"
unfolding has_vector_derivative_def apply(drule has_derivative_neg) by auto

lemma has_vector_derivative_add:
assumes "(f has_vector_derivative f') net"
assumes "(g has_vector_derivative g') net"
shows "((\<lambda>x. f(x) + g(x)) has_vector_derivative (f' + g')) net"
using has_derivative_add[OF assms[unfolded has_vector_derivative_def]]
unfolding has_vector_derivative_def unfolding scaleR_right_distrib by auto

lemma has_vector_derivative_sub:
assumes "(f has_vector_derivative f') net"
assumes "(g has_vector_derivative g') net"
shows "((\<lambda>x. f(x) - g(x)) has_vector_derivative (f' - g')) net"
using has_derivative_sub[OF assms[unfolded has_vector_derivative_def]]
unfolding has_vector_derivative_def scaleR_right_diff_distrib by auto

lemma has_vector_derivative_bilinear_within:
assumes "(f has_vector_derivative f') (at x within s)"
assumes "(g has_vector_derivative g') (at x within s)"
assumes "bounded_bilinear h"
shows "((\<lambda>x. h (f x) (g x)) has_vector_derivative (h (f x) g' + h f' (g x))) (at x within s)"
proof-
interpret bounded_bilinear h using assms by auto
show ?thesis using has_derivative_bilinear_within[OF assms(1-2)[unfolded has_vector_derivative_def], of h]
unfolding o_def has_vector_derivative_def
using assms(3) unfolding scaleR_right scaleR_left scaleR_right_distrib
by auto
qed

lemma has_vector_derivative_bilinear_at:
assumes "(f has_vector_derivative f') (at x)"
assumes "(g has_vector_derivative g') (at x)"
assumes "bounded_bilinear h"
shows "((\<lambda>x. h (f x) (g x)) has_vector_derivative (h (f x) g' + h f' (g x))) (at x)"
using has_vector_derivative_bilinear_within[where s=UNIV] assms by simp

lemma has_vector_derivative_at_within:
"(f has_vector_derivative f') (at x) \<Longrightarrow> (f has_vector_derivative f') (at x within s)"
unfolding has_vector_derivative_def
by (rule has_derivative_at_within)

lemma has_vector_derivative_transform_within:
assumes "0 < d" and "x \<in> s" and "\<forall>x'\<in>s. dist x' x < d \<longrightarrow> f x' = g x'"
assumes "(f has_vector_derivative f') (at x within s)"
shows "(g has_vector_derivative f') (at x within s)"
using assms unfolding has_vector_derivative_def
by (rule has_derivative_transform_within)

lemma has_vector_derivative_transform_at:
assumes "0 < d" and "\<forall>x'. dist x' x < d \<longrightarrow> f x' = g x'"
assumes "(f has_vector_derivative f') (at x)"
shows "(g has_vector_derivative f') (at x)"
using assms unfolding has_vector_derivative_def
by (rule has_derivative_transform_at)

lemma has_vector_derivative_transform_within_open:
assumes "open s" and "x \<in> s" and "\<forall>y\<in>s. f y = g y"
assumes "(f has_vector_derivative f') (at x)"
shows "(g has_vector_derivative f') (at x)"
using assms unfolding has_vector_derivative_def
by (rule has_derivative_transform_within_open)

lemma vector_diff_chain_at:
assumes "(f has_vector_derivative f') (at x)"
assumes "(g has_vector_derivative g') (at (f x))"
shows "((g \<circ> f) has_vector_derivative (f' *\<^sub>R g')) (at x)"
using assms(2) unfolding has_vector_derivative_def apply-
apply(drule diff_chain_at[OF assms(1)[unfolded has_vector_derivative_def]])
unfolding o_def real_scaleR_def scaleR_scaleR .

lemma vector_diff_chain_within:
assumes "(f has_vector_derivative f') (at x within s)"
assumes "(g has_vector_derivative g') (at (f x) within f ` s)"
shows "((g o f) has_vector_derivative (f' *\<^sub>R g')) (at x within s)"
using assms(2) unfolding has_vector_derivative_def apply-
apply(drule diff_chain_within[OF assms(1)[unfolded has_vector_derivative_def]])
unfolding o_def real_scaleR_def scaleR_scaleR .

end
```