Theory Lambert_W
section ‹The Lambert $W$ Function on the reals›
theory Lambert_W
imports
Complex_Main
"HOL-Library.FuncSet"
"HOL-Real_Asymp.Real_Asymp"
begin
text ‹Some lemmas about asymptotic equivalence:›
lemma asymp_equiv_sandwich':
fixes f :: "'a ⇒ real"
assumes "⋀c'. c' ∈ {l<..<c} ⟹ eventually (λx. f x ≥ c' * g x) F"
assumes "⋀c'. c' ∈ {c<..<u} ⟹ eventually (λx. f x ≤ c' * g x) F"
assumes "l < c" "c < u" and [simp]: "c ≠ 0"
shows "f ∼[F] (λx. c * g x)"
proof -
have "(λx. f x - c * g x) ∈ o[F](g)"
proof (rule landau_o.smallI)
fix e :: real assume e: "e > 0"
define C1 where "C1 = min (c + e) ((c + u) / 2)"
have C1: "C1 ∈ {c<..<u}" "C1 - c ≤ e"
using e assms by (auto simp: C1_def min_def)
define C2 where "C2 = max (c - e) ((c + l) / 2)"
have C2: "C2 ∈ {l<..<c}" "c - C2 ≤ e"
using e assms by (auto simp: C2_def max_def field_simps)
show "eventually (λx. norm (f x - c * g x) ≤ e * norm (g x)) F"
using assms(2)[OF C1(1)] assms(1)[OF C2(1)]
proof eventually_elim
case (elim x)
show ?case
proof (cases "f x ≥ c * g x")
case True
hence "norm (f x - c * g x) = f x - c * g x"
by simp
also have "… ≤ (C1 - c) * g x"
using elim by (simp add: algebra_simps)
also have "… ≤ (C1 - c) * norm (g x)"
using C1 by (intro mult_left_mono) auto
also have "… ≤ e * norm (g x)"
using C1 elim by (intro mult_right_mono) auto
finally show ?thesis using elim by simp
next
case False
hence "norm (f x - c * g x) = c * g x - f x"
by simp
also have "… ≤ (c - C2) * g x"
using elim by (simp add: algebra_simps)
also have "… ≤ (c - C2) * norm (g x)"
using C2 by (intro mult_left_mono) auto
also have "… ≤ e * norm (g x)"
using C2 elim by (intro mult_right_mono) auto
finally show ?thesis using elim by simp
qed
qed
qed
also have "g ∈ O[F](λx. c * g x)"
by simp
finally show ?thesis
unfolding asymp_equiv_altdef by blast
qed
lemma asymp_equiv_sandwich'':
fixes f :: "'a ⇒ real"
assumes "⋀c'. c' ∈ {l<..<1} ⟹ eventually (λx. f x ≥ c' * g x) F"
assumes "⋀c'. c' ∈ {1<..<u} ⟹ eventually (λx. f x ≤ c' * g x) F"
assumes "l < 1" "1 < u"
shows "f ∼[F] (g)"
using asymp_equiv_sandwich'[of l 1 g f F u] assms by simp
subsection ‹Properties of the function $x\mapsto x e^{x}$›
lemma exp_times_self_gt:
assumes "x ≠ -1"
shows "x * exp x > -exp (-1::real)"
proof -
define f where "f = (λx::real. x * exp x)"
define f' where "f' = (λx::real. (x + 1) * exp x)"
have "(f has_field_derivative f' x) (at x)" for x
by (auto simp: f_def f'_def intro!: derivative_eq_intros simp: algebra_simps)
define l r where "l = min x (-1)" and "r = max x (-1)"
have "∃z. z > l ∧ z < r ∧ f r - f l = (r - l) * f' z"
unfolding f_def f'_def l_def r_def using assms
by (intro MVT2) (auto intro!: derivative_eq_intros simp: algebra_simps)
then obtain z where z: "z ∈ {l<..<r}" "f r - f l = (r - l) * f' z"
by auto
from z have "f x = f (-1) + (x + 1) * f' z"
using assms by (cases "x ≥ -1") (auto simp: l_def r_def max_def min_def algebra_simps)
moreover have "sgn ((x + 1) * f' z) = 1"
using z assms
by (cases x "(-1) :: real" rule: linorder_cases; cases z "(-1) :: real" rule: linorder_cases)
(auto simp: f'_def sgn_mult l_def r_def)
hence "(x + 1) * f' z > 0" using sgn_greater by fastforce
ultimately show ?thesis by (simp add: f_def)
qed
lemma exp_times_self_ge: "x * exp x ≥ -exp (-1::real)"
using exp_times_self_gt[of x] by (cases "x = -1") auto
lemma exp_times_self_strict_mono:
assumes "x ≥ -1" "x < (y :: real)"
shows "x * exp x < y * exp y"
using assms(2)
proof (rule DERIV_pos_imp_increasing_open)
fix t assume t: "x < t" "t < y"
have "((λx. x * exp x) has_real_derivative (t + 1) * exp t) (at t)"
by (auto intro!: derivative_eq_intros simp: algebra_simps)
moreover have "(t + 1) * exp t > 0"
using t assms by (intro mult_pos_pos) auto
ultimately show "∃y. ((λa. a * exp a) has_real_derivative y) (at t) ∧ 0 < y" by blast
qed (auto intro!: continuous_intros)
lemma exp_times_self_strict_antimono:
assumes "y ≤ -1" "x < (y :: real)"
shows "x * exp x > y * exp y"
proof -
have "-x * exp x < -y * exp y"
using assms(2)
proof (rule DERIV_pos_imp_increasing_open)
fix t assume t: "x < t" "t < y"
have "((λx. -x * exp x) has_real_derivative (-(t + 1)) * exp t) (at t)"
by (auto intro!: derivative_eq_intros simp: algebra_simps)
moreover have "(-(t + 1)) * exp t > 0"
using t assms by (intro mult_pos_pos) auto
ultimately show "∃y. ((λa. -a * exp a) has_real_derivative y) (at t) ∧ 0 < y" by blast
qed (auto intro!: continuous_intros)
thus ?thesis by simp
qed
lemma exp_times_self_mono:
assumes "x ≥ -1" "x ≤ (y :: real)"
shows "x * exp x ≤ y * exp y"
using exp_times_self_strict_mono[of x y] assms by (cases "x = y") auto
lemma exp_times_self_antimono:
assumes "y ≤ -1" "x ≤ (y :: real)"
shows "x * exp x ≥ y * exp y"
using exp_times_self_strict_antimono[of y x] assms by (cases "x = y") auto
lemma exp_times_self_inj: "inj_on (λx::real. x * exp x) {-1..}"
proof
fix x y :: real
assume "x ∈ {-1..}" "y ∈ {-1..}" "x * exp x = y * exp y"
thus "x = y"
using exp_times_self_strict_mono[of x y] exp_times_self_strict_mono[of y x]
by (cases x y rule: linorder_cases) auto
qed
lemma exp_times_self_inj': "inj_on (λx::real. x * exp x) {..-1}"
proof
fix x y :: real
assume "x ∈ {..-1}" "y ∈ {..-1}" "x * exp x = y * exp y"
thus "x = y"
using exp_times_self_strict_antimono[of x y] exp_times_self_strict_antimono[of y x]
by (cases x y rule: linorder_cases) auto
qed
subsection ‹Definition›
text ‹
The following are the two branches $W_0(x)$ and $W_{-1}(x)$ of the Lambert $W$ function on the
real numbers. These are the inverse functions of the function $x\mapsto xe^x$, i.\,e.\
we have $W(x)e^{W(x)} = x$ for both branches wherever they are defined. The two branches
meet at the point $x = -\frac{1}{e}$.
$W_0(x)$ is the principal branch, whose domain is $[-\frac{1}{e}; \infty)$ and whose
range is $[-1; \infty)$.
$W_{-1}(x)$ has the domain $[-\frac{1}{e}; 0)$ and the range $(-\infty;-1]$.
Figure~\ref{fig:lambertw} shows plots of these two branches for illustration.
›
text ‹
\definecolor{myblue}{HTML}{3869b1}
\definecolor{myred}{HTML}{cc2428}
\begin{figure}
\begin{center}
\begin{tikzpicture}
\begin{axis}[
xmin=-0.5, xmax=6.6, ymin=-3.8, ymax=1.5, axis lines=middle, ytick = {-3, -2, -1, 1}, xtick = {1,...,10}, yticklabel pos = right,
yticklabel style={right,xshift=1mm},
extra x tick style={tick label style={above,yshift=1mm}},
extra x ticks={-0.367879441},
extra x tick labels={$-\frac{1}{e}$},
width=\textwidth, height=0.8\textwidth,
xlabel={$x$}, tick style={thin,black}
]
\addplot [color=black, line width=0.5pt, densely dashed, mark=none,domain=-5:0,samples=200] ({-exp(-1)}, {x});
\addplot [color=myblue, line width=1pt, mark=none,domain=-1:1.5,samples=200] ({x*exp(x)}, {x});
\addplot [color=myred, line width=1pt, mark=none,domain=-5:-1,samples=200] ({x*exp(x)}, {x});
\end{axis}
\end{tikzpicture}
\end{center}
\caption{The two real branches of the Lambert $W$ function: $W_0$ (blue) and $W_{-1}$ (red).}
\label{fig:lambertw}
\end{figure}
›
definition Lambert_W :: "real ⇒ real" where
"Lambert_W x = (if x < -exp(-1) then -1 else (THE w. w ≥ -1 ∧ w * exp w = x))"
definition Lambert_W' :: "real ⇒ real" where
"Lambert_W' x = (if x ∈ {-exp(-1)..<0} then (THE w. w ≤ -1 ∧ w * exp w = x) else -1)"
lemma Lambert_W_ex1:
assumes "(x::real) ≥ -exp (-1)"
shows "∃!w. w ≥ -1 ∧ w * exp w = x"
proof (rule ex_ex1I)
have "filterlim (λw::real. w * exp w) at_top at_top"
by real_asymp
hence "eventually (λw. w * exp w ≥ x) at_top"
by (auto simp: filterlim_at_top)
hence "eventually (λw. w ≥ 0 ∧ w * exp w ≥ x) at_top"
by (intro eventually_conj eventually_ge_at_top)
then obtain w' where w': "w' * exp w' ≥ x" "w' ≥ 0"
by (auto simp: eventually_at_top_linorder)
from w' assms have "∃w. -1 ≤ w ∧ w ≤ w' ∧ w * exp w = x"
by (intro IVT' continuous_intros) auto
thus "∃w. w ≥ -1 ∧ w * exp w = x" by blast
next
fix w w' :: real
assume ww': "w ≥ -1 ∧ w * exp w = x" "w' ≥ -1 ∧ w' * exp w' = x"
hence "w * exp w = w' * exp w'" by simp
thus "w = w'"
using exp_times_self_strict_mono[of w w'] exp_times_self_strict_mono[of w' w] ww'
by (cases w w' rule: linorder_cases) auto
qed
lemma Lambert_W'_ex1:
assumes "(x::real) ∈ {-exp (-1)..<0}"
shows "∃!w. w ≤ -1 ∧ w * exp w = x"
proof (rule ex_ex1I)
have "eventually (λw. x ≤ w * exp w) at_bot"
using assms by real_asymp
hence "eventually (λw. w ≤ -1 ∧ w * exp w ≥ x) at_bot"
by (intro eventually_conj eventually_le_at_bot)
then obtain w' where w': "w' * exp w' ≥ x" "w' ≤ -1"
by (auto simp: eventually_at_bot_linorder)
from w' assms have "∃w. w' ≤ w ∧ w ≤ -1 ∧ w * exp w = x"
by (intro IVT2' continuous_intros) auto
thus "∃w. w ≤ -1 ∧ w * exp w = x" by blast
next
fix w w' :: real
assume ww': "w ≤ -1 ∧ w * exp w = x" "w' ≤ -1 ∧ w' * exp w' = x"
hence "w * exp w = w' * exp w'" by simp
thus "w = w'"
using exp_times_self_strict_antimono[of w w'] exp_times_self_strict_antimono[of w' w] ww'
by (cases w w' rule: linorder_cases) auto
qed
lemma Lambert_W_times_exp_self:
assumes "x ≥ -exp (-1)"
shows "Lambert_W x * exp (Lambert_W x) = x"
using theI'[OF Lambert_W_ex1[OF assms]] assms by (auto simp: Lambert_W_def)
lemma Lambert_W_times_exp_self':
assumes "x ≥ -exp (-1)"
shows "exp (Lambert_W x) * Lambert_W x = x"
using Lambert_W_times_exp_self[of x] assms by (simp add: mult_ac)
lemma Lambert_W'_times_exp_self:
assumes "x ∈ {-exp (-1)..<0}"
shows "Lambert_W' x * exp (Lambert_W' x) = x"
using theI'[OF Lambert_W'_ex1[OF assms]] assms by (auto simp: Lambert_W'_def)
lemma Lambert_W'_times_exp_self':
assumes "x ∈ {-exp (-1)..<0}"
shows "exp (Lambert_W' x) * Lambert_W' x = x"
using Lambert_W'_times_exp_self[of x] assms by (simp add: mult_ac)
lemma Lambert_W_ge: "Lambert_W x ≥ -1"
using theI'[OF Lambert_W_ex1[of x]] by (auto simp: Lambert_W_def)
lemma Lambert_W'_le: "Lambert_W' x ≤ -1"
using theI'[OF Lambert_W'_ex1[of x]] by (auto simp: Lambert_W'_def)
lemma Lambert_W_eqI:
assumes "w ≥ -1" "w * exp w = x"
shows "Lambert_W x = w"
proof -
from assms exp_times_self_ge[of w] have "x ≥ -exp (-1)"
by (cases "x ≥ -exp (-1)") auto
from Lambert_W_ex1[OF this] Lambert_W_times_exp_self[OF this] Lambert_W_ge[of x] assms
show ?thesis by metis
qed
lemma Lambert_W'_eqI:
assumes "w ≤ -1" "w * exp w = x"
shows "Lambert_W' x = w"
proof -
from assms exp_times_self_ge[of w] have "x ≥ -exp (-1)"
by (cases "x ≥ -exp (-1)") auto
moreover from assms have "w * exp w < 0"
by (intro mult_neg_pos) auto
ultimately have "x ∈ {-exp (-1)..<0}"
using assms by auto
from Lambert_W'_ex1[OF this(1)] Lambert_W'_times_exp_self[OF this(1)] Lambert_W'_le assms
show ?thesis by metis
qed
text ‹
$W_0(x)$ and $W_{-1}(x)$ together fully cover all solutions of $we^w = x$:
›
lemma exp_times_self_eqD:
assumes "w * exp w = x"
shows "x ≥ -exp (-1)" and "w = Lambert_W x ∨ x < 0 ∧ w = Lambert_W' x"
proof -
from assms show "x ≥ -exp (-1)"
using exp_times_self_ge[of w] by auto
show "w = Lambert_W x ∨ x < 0 ∧ w = Lambert_W' x"
proof (cases "w ≥ -1")
case True
hence "Lambert_W x = w"
using assms by (intro Lambert_W_eqI) auto
thus ?thesis by auto
next
case False
from False have "w * exp w < 0"
by (intro mult_neg_pos) auto
from False have "Lambert_W' x = w"
using assms by (intro Lambert_W'_eqI) auto
thus ?thesis using assms ‹w * exp w < 0› by auto
qed
qed
theorem exp_times_self_eq_iff:
"w * exp w = x ⟷ x ≥ -exp (-1) ∧ (w = Lambert_W x ∨ x < 0 ∧ w = Lambert_W' x)"
using exp_times_self_eqD[of w x]
by (auto simp: Lambert_W_times_exp_self Lambert_W'_times_exp_self)
lemma Lambert_W_exp_times_self [simp]: "x ≥ -1 ⟹ Lambert_W (x * exp x) = x"
by (rule Lambert_W_eqI) auto
lemma Lambert_W_exp_times_self' [simp]: "x ≥ -1 ⟹ Lambert_W (exp x * x) = x"
by (rule Lambert_W_eqI) auto
lemma Lambert_W'_exp_times_self [simp]: "x ≤ -1 ⟹ Lambert_W' (x * exp x) = x"
by (rule Lambert_W'_eqI) auto
lemma Lambert_W'_exp_times_self' [simp]: "x ≤ -1 ⟹ Lambert_W' (exp x * x) = x"
by (rule Lambert_W'_eqI) auto
lemma Lambert_W_times_ln_self:
assumes "x ≥ exp (-1)"
shows "Lambert_W (x * ln x) = ln x"
proof -
have "0 < exp (-1 :: real)"
by simp
also note ‹… ≤ x›
finally have "x > 0" .
from assms have "ln (exp (-1)) ≤ ln x"
using ‹x > 0› by (subst ln_le_cancel_iff) auto
hence "Lambert_W (exp (ln x) * ln x) = ln x"
by (subst Lambert_W_exp_times_self') auto
thus ?thesis using ‹x > 0› by simp
qed
lemma Lambert_W_times_ln_self':
assumes "x ≥ exp (-1)"
shows "Lambert_W (ln x * x) = ln x"
using Lambert_W_times_ln_self[OF assms] by (simp add: mult.commute)
lemma Lambert_W_eq_minus_exp_minus1 [simp]: "Lambert_W (-exp (-1)) = -1"
by (rule Lambert_W_eqI) auto
lemma Lambert_W'_eq_minus_exp_minus1 [simp]: "Lambert_W' (-exp (-1)) = -1"
by (rule Lambert_W'_eqI) auto
lemma Lambert_W_0 [simp]: "Lambert_W 0 = 0"
by (rule Lambert_W_eqI) auto
subsection ‹Monotonicity properties›
lemma Lambert_W_strict_mono:
assumes "x ≥ -exp(-1)" "x < y"
shows "Lambert_W x < Lambert_W y"
proof (rule ccontr)
assume "¬(Lambert_W x < Lambert_W y)"
hence "Lambert_W x * exp (Lambert_W x) ≥ Lambert_W y * exp (Lambert_W y)"
by (intro exp_times_self_mono) (auto simp: Lambert_W_ge)
hence "x ≥ y"
using assms by (simp add: Lambert_W_times_exp_self)
with assms show False by simp
qed
lemma Lambert_W_mono:
assumes "x ≥ -exp(-1)" "x ≤ y"
shows "Lambert_W x ≤ Lambert_W y"
using Lambert_W_strict_mono[of x y] assms by (cases "x = y") auto
lemma Lambert_W_eq_iff [simp]:
"x ≥ -exp(-1) ⟹ y ≥ -exp(-1) ⟹ Lambert_W x = Lambert_W y ⟷ x = y"
using Lambert_W_strict_mono[of x y] Lambert_W_strict_mono[of y x]
by (cases x y rule: linorder_cases) auto
lemma Lambert_W_le_iff [simp]:
"x ≥ -exp(-1) ⟹ y ≥ -exp(-1) ⟹ Lambert_W x ≤ Lambert_W y ⟷ x ≤ y"
using Lambert_W_strict_mono[of x y] Lambert_W_strict_mono[of y x]
by (cases x y rule: linorder_cases) auto
lemma Lambert_W_less_iff [simp]:
"x ≥ -exp(-1) ⟹ y ≥ -exp(-1) ⟹ Lambert_W x < Lambert_W y ⟷ x < y"
using Lambert_W_strict_mono[of x y] Lambert_W_strict_mono[of y x]
by (cases x y rule: linorder_cases) auto
lemma Lambert_W_le_minus_one:
assumes "x ≤ -exp(-1)"
shows "Lambert_W x = -1"
proof (cases "x = -exp(-1)")
case False
thus ?thesis using assms
by (auto simp: Lambert_W_def)
qed auto
lemma Lambert_W_pos_iff [simp]: "Lambert_W x > 0 ⟷ x > 0"
proof (cases "x ≥ -exp (-1)")
case True
thus ?thesis
using Lambert_W_less_iff[of 0 x] by (simp del: Lambert_W_less_iff)
next
case False
hence "x < - exp(-1)" by auto
also have "… ≤ 0" by simp
finally show ?thesis using False
by (auto simp: Lambert_W_le_minus_one)
qed
lemma Lambert_W_eq_0_iff [simp]: "Lambert_W x = 0 ⟷ x = 0"
using Lambert_W_eq_iff[of x 0]
by (cases "x ≥ -exp (-1)") (auto simp: Lambert_W_le_minus_one simp del: Lambert_W_eq_iff)
lemma Lambert_W_nonneg_iff [simp]: "Lambert_W x ≥ 0 ⟷ x ≥ 0"
using Lambert_W_pos_iff[of x]
by (cases "x = 0") (auto simp del: Lambert_W_pos_iff)
lemma Lambert_W_neg_iff [simp]: "Lambert_W x < 0 ⟷ x < 0"
using Lambert_W_nonneg_iff[of x] by (auto simp del: Lambert_W_nonneg_iff)
lemma Lambert_W_nonpos_iff [simp]: "Lambert_W x ≤ 0 ⟷ x ≤ 0"
using Lambert_W_pos_iff[of x] by (auto simp del: Lambert_W_pos_iff)
lemma Lambert_W_geI:
assumes "y * exp y ≤ x"
shows "Lambert_W x ≥ y"
proof (cases "y ≥ -1")
case False
hence "y ≤ -1" by simp
also have "-1 ≤ Lambert_W x" by (rule Lambert_W_ge)
finally show ?thesis .
next
case True
have "Lambert_W x ≥ Lambert_W (y * exp y)"
using assms exp_times_self_ge[of y] by (intro Lambert_W_mono) auto
thus ?thesis using assms True by simp
qed
lemma Lambert_W_gtI:
assumes "y * exp y < x"
shows "Lambert_W x > y"
proof (cases "y ≥ -1")
case False
hence "y < -1" by simp
also have "-1 ≤ Lambert_W x" by (rule Lambert_W_ge)
finally show ?thesis .
next
case True
have "Lambert_W x > Lambert_W (y * exp y)"
using assms exp_times_self_ge[of y] by (intro Lambert_W_strict_mono) auto
thus ?thesis using assms True by simp
qed
lemma Lambert_W_leI:
assumes "y * exp y ≥ x" "y ≥ -1" "x ≥ -exp (-1)"
shows "Lambert_W x ≤ y"
proof -
have "Lambert_W x ≤ Lambert_W (y * exp y)"
using assms exp_times_self_ge[of y] by (intro Lambert_W_mono) auto
thus ?thesis using assms by simp
qed
lemma Lambert_W_lessI:
assumes "y * exp y > x" "y ≥ -1" "x ≥ -exp (-1)"
shows "Lambert_W x < y"
proof -
have "Lambert_W x < Lambert_W (y * exp y)"
using assms exp_times_self_ge[of y] by (intro Lambert_W_strict_mono) auto
thus ?thesis using assms by simp
qed
lemma Lambert_W'_strict_antimono:
assumes "-exp (-1) ≤ x" "x < y" "y < 0"
shows "Lambert_W' x > Lambert_W' y"
proof (rule ccontr)
assume "¬(Lambert_W' x > Lambert_W' y)"
hence "Lambert_W' x * exp (Lambert_W' x) ≥ Lambert_W' y * exp (Lambert_W' y)"
using assms by (intro exp_times_self_antimono Lambert_W'_le) auto
hence "x ≥ y"
using assms by (simp add: Lambert_W'_times_exp_self)
with assms show False by simp
qed
lemma Lambert_W'_antimono:
assumes "x ≥ -exp(-1)" "x ≤ y" "y < 0"
shows "Lambert_W' x ≥ Lambert_W' y"
using Lambert_W'_strict_antimono[of x y] assms by (cases "x = y") auto
lemma Lambert_W'_eq_iff [simp]:
"x ∈ {-exp(-1)..<0} ⟹ y ∈ {-exp(-1)..<0} ⟹ Lambert_W' x = Lambert_W' y ⟷ x = y"
using Lambert_W'_strict_antimono[of x y] Lambert_W'_strict_antimono[of y x]
by (cases x y rule: linorder_cases) auto
lemma Lambert_W'_le_iff [simp]:
"x ∈ {-exp(-1)..<0} ⟹ y ∈ {-exp(-1)..<0} ⟹ Lambert_W' x ≤ Lambert_W' y ⟷ x ≥ y"
using Lambert_W'_strict_antimono[of x y] Lambert_W'_strict_antimono[of y x]
by (cases x y rule: linorder_cases) auto
lemma Lambert_W'_less_iff [simp]:
"x ∈ {-exp(-1)..<0} ⟹ y ∈ {-exp(-1)..<0} ⟹ Lambert_W' x < Lambert_W' y ⟷ x > y"
using Lambert_W'_strict_antimono[of x y] Lambert_W'_strict_antimono[of y x]
by (cases x y rule: linorder_cases) auto
lemma Lambert_W'_le_minus_one:
assumes "x ≤ -exp(-1)"
shows "Lambert_W' x = -1"
proof (cases "x = -exp(-1)")
case False
thus ?thesis using assms
by (auto simp: Lambert_W'_def)
qed auto
lemma Lambert_W'_ge_zero: "x ≥ 0 ⟹ Lambert_W' x = -1"
by (simp add: Lambert_W'_def)
lemma Lambert_W'_neg: "Lambert_W' x < 0"
by (rule le_less_trans[OF Lambert_W'_le]) auto
lemma Lambert_W'_nz [simp]: "Lambert_W' x ≠ 0"
using Lambert_W'_neg[of x] by simp
lemma Lambert_W'_geI:
assumes "y * exp y ≥ x" "y ≤ -1" "x ≥ -exp(-1)"
shows "Lambert_W' x ≥ y"
proof -
from assms have "y * exp y < 0"
by (intro mult_neg_pos) auto
hence "Lambert_W' x ≥ Lambert_W' (y * exp y)"
using assms exp_times_self_ge[of y] by (intro Lambert_W'_antimono) auto
thus ?thesis using assms by simp
qed
lemma Lambert_W'_gtI:
assumes "y * exp y > x" "y ≤ -1" "x ≥ -exp(-1)"
shows "Lambert_W' x ≥ y"
proof -
from assms have "y * exp y < 0"
by (intro mult_neg_pos) auto
hence "Lambert_W' x > Lambert_W' (y * exp y)"
using assms exp_times_self_ge[of y] by (intro Lambert_W'_strict_antimono) auto
thus ?thesis using assms by simp
qed
lemma Lambert_W'_leI:
assumes "y * exp y ≤ x" "x < 0"
shows "Lambert_W' x ≤ y"
proof (cases "y ≤ -1")
case True
have "Lambert_W' x ≤ Lambert_W' (y * exp y)"
using assms exp_times_self_ge[of y] by (intro Lambert_W'_antimono) auto
thus ?thesis using assms True by simp
next
case False
have "Lambert_W' x ≤ -1"
by (rule Lambert_W'_le)
also have "… < y"
using False by simp
finally show ?thesis by simp
qed
lemma Lambert_W'_lessI:
assumes "y * exp y < x" "x < 0"
shows "Lambert_W' x < y"
proof (cases "y ≤ -1")
case True
have "Lambert_W' x < Lambert_W' (y * exp y)"
using assms exp_times_self_ge[of y] by (intro Lambert_W'_strict_antimono) auto
thus ?thesis using assms True by simp
next
case False
have "Lambert_W' x ≤ -1"
by (rule Lambert_W'_le)
also have "… < y"
using False by simp
finally show ?thesis by simp
qed
lemma bij_betw_exp_times_self_atLeastAtMost:
fixes a b :: real
assumes "a ≥ -1" "a ≤ b"
shows "bij_betw (λx. x * exp x) {a..b} {a * exp a..b * exp b}"
unfolding bij_betw_def
proof
show "inj_on (λx. x * exp x) {a..b}"
by (rule inj_on_subset[OF exp_times_self_inj]) (use assms in auto)
next
show "(λx. x * exp x) ` {a..b} = {a * exp a..b * exp b}"
proof safe
fix x assume "x ∈ {a..b}"
thus "x * exp x ∈ {a * exp a..b * exp b}"
using assms by (auto intro!: exp_times_self_mono)
next
fix x assume x: "x ∈ {a * exp a..b * exp b}"
have "(-1) * exp (-1) ≤ a * exp a"
using assms by (intro exp_times_self_mono) auto
also have "… ≤ x" using x by simp
finally have "x ≥ -exp (-1)" by simp
have "Lambert_W x ∈ {a..b}"
using x ‹x ≥ -exp (-1)› assms by (auto intro!: Lambert_W_geI Lambert_W_leI)
moreover have "Lambert_W x * exp (Lambert_W x) = x"
using ‹x ≥ -exp (-1)› by (simp add: Lambert_W_times_exp_self)
ultimately show "x ∈ (λx. x * exp x) ` {a..b}"
unfolding image_iff by metis
qed
qed
lemma bij_betw_exp_times_self_atLeastAtMost':
fixes a b :: real
assumes "a ≤ b" "b ≤ -1"
shows "bij_betw (λx. x * exp x) {a..b} {b * exp b..a * exp a}"
unfolding bij_betw_def
proof
show "inj_on (λx. x * exp x) {a..b}"
by (rule inj_on_subset[OF exp_times_self_inj']) (use assms in auto)
next
show "(λx. x * exp x) ` {a..b} = {b * exp b..a * exp a}"
proof safe
fix x assume "x ∈ {a..b}"
thus "x * exp x ∈ {b * exp b..a * exp a}"
using assms by (auto intro!: exp_times_self_antimono)
next
fix x assume x: "x ∈ {b * exp b..a * exp a}"
from assms have "a * exp a < 0"
by (intro mult_neg_pos) auto
with x have "x < 0" by auto
have "(-1) * exp (-1) ≤ b * exp b"
using assms by (intro exp_times_self_antimono) auto
also have "… ≤ x" using x by simp
finally have "x ≥ -exp (-1)" by simp
have "Lambert_W' x ∈ {a..b}"
using x ‹x ≥ -exp (-1)› ‹x < 0› assms
by (auto intro!: Lambert_W'_geI Lambert_W'_leI)
moreover have "Lambert_W' x * exp (Lambert_W' x) = x"
using ‹x ≥ -exp (-1)› ‹x < 0› by (auto simp: Lambert_W'_times_exp_self)
ultimately show "x ∈ (λx. x * exp x) ` {a..b}"
unfolding image_iff by metis
qed
qed
lemma bij_betw_exp_times_self_atLeast:
fixes a :: real
assumes "a ≥ -1"
shows "bij_betw (λx. x * exp x) {a..} {a * exp a..}"
unfolding bij_betw_def
proof
show "inj_on (λx. x * exp x) {a..}"
by (rule inj_on_subset[OF exp_times_self_inj]) (use assms in auto)
next
show "(λx. x * exp x) ` {a..} = {a * exp a..}"
proof safe
fix x assume "x ≥ a"
thus "x * exp x ≥ a * exp a"
using assms by (auto intro!: exp_times_self_mono)
next
fix x assume x: "x ≥ a * exp a"
have "(-1) * exp (-1) ≤ a * exp a"
using assms by (intro exp_times_self_mono) auto
also have "… ≤ x" using x by simp
finally have "x ≥ -exp (-1)" by simp
have "Lambert_W x ∈ {a..}"
using x ‹x ≥ -exp (-1)› assms by (auto intro!: Lambert_W_geI Lambert_W_leI)
moreover have "Lambert_W x * exp (Lambert_W x) = x"
using ‹x ≥ -exp (-1)› by (simp add: Lambert_W_times_exp_self)
ultimately show "x ∈ (λx. x * exp x) ` {a..}"
unfolding image_iff by metis
qed
qed
subsection ‹Basic identities and bounds›
lemma Lambert_W_2_ln_2 [simp]: "Lambert_W (2 * ln 2) = ln 2"
proof -
have "-1 ≤ (0 :: real)"
by simp
also have "… ≤ ln 2"
by simp
finally have "-1 ≤ (ln 2 :: real)" .
thus ?thesis
by (intro Lambert_W_eqI) auto
qed
lemma Lambert_W_exp_1 [simp]: "Lambert_W (exp 1) = 1"
by (rule Lambert_W_eqI) auto
lemma Lambert_W_neg_ln_over_self:
assumes "x ∈ {exp (-1)..exp 1}"
shows "Lambert_W (-ln x / x) = -ln x"
proof -
have "0 < (exp (-1) :: real)"
by simp
also have "… ≤ x"
using assms by simp
finally have "x > 0" .
from ‹x > 0› assms have "ln x ≤ ln (exp 1)"
by (subst ln_le_cancel_iff) auto
also have "ln (exp 1) = (1 :: real)"
by simp
finally have "ln x ≤ 1" .
show ?thesis
using assms ‹x > 0› ‹ln x ≤ 1›
by (intro Lambert_W_eqI) (auto simp: exp_minus field_simps)
qed
lemma Lambert_W'_neg_ln_over_self:
assumes "x ≥ exp 1"
shows "Lambert_W' (-ln x / x) = -ln x"
proof (rule Lambert_W'_eqI)
have "0 < (exp 1 :: real)"
by simp
also have "… ≤ x"
by fact
finally have "x > 0" .
from assms ‹x > 0› have "ln x ≥ ln (exp 1)"
by (subst ln_le_cancel_iff) auto
thus "-ln x ≤ -1" by simp
show "-ln x * exp (-ln x) = -ln x / x"
using ‹x > 0› by (simp add: field_simps exp_minus)
qed
lemma exp_Lambert_W: "x ≥ -exp (-1) ⟹ x ≠ 0 ⟹ exp (Lambert_W x) = x / Lambert_W x"
using Lambert_W_times_exp_self[of x] by (auto simp add: divide_simps mult_ac)
lemma exp_Lambert_W': "x ∈ {-exp (-1)..<0} ⟹ exp (Lambert_W' x) = x / Lambert_W' x"
using Lambert_W'_times_exp_self[of x] by (auto simp add: divide_simps mult_ac)
lemma ln_Lambert_W:
assumes "x > 0"
shows "ln (Lambert_W x) = ln x - Lambert_W x"
proof -
have "-exp (-1) ≤ (0 :: real)"
by simp
also have "… < x" by fact
finally have x: "x > -exp(-1)" .
have "exp (ln (Lambert_W x)) = exp (ln x - Lambert_W x)"
using assms x by (subst exp_diff) (auto simp: exp_Lambert_W)
thus ?thesis by (subst (asm) exp_inj_iff)
qed
lemma ln_minus_Lambert_W':
assumes "x ∈ {-exp (-1)..<0}"
shows "ln (-Lambert_W' x) = ln (-x) - Lambert_W' x"
proof -
have "exp (ln (-x) - Lambert_W' x) = -Lambert_W' x"
using assms by (simp add: exp_diff exp_Lambert_W')
also have "… = exp (ln (-Lambert_W' x))"
using Lambert_W'_neg[of x] by simp
finally show ?thesis by simp
qed
lemma Lambert_W_plus_Lambert_W_eq:
assumes "x > 0" "y > 0"
shows "Lambert_W x + Lambert_W y = Lambert_W (x * y * (1 / Lambert_W x + 1 / Lambert_W y))"
proof (rule sym, rule Lambert_W_eqI)
have "x > -exp(-1)" "y > -exp (-1)"
by (rule less_trans[OF _ assms(1)] less_trans[OF _ assms(2)], simp)+
with assms show "(Lambert_W x + Lambert_W y) * exp (Lambert_W x + Lambert_W y) =
x * y * (1 / Lambert_W x + 1 / Lambert_W y)"
by (auto simp: field_simps exp_add exp_Lambert_W)
have "-1 ≤ (0 :: real)"
by simp
also from assms have "… ≤ Lambert_W x + Lambert_W y"
by (intro add_nonneg_nonneg) auto
finally show "… ≥ -1" .
qed
lemma Lambert_W'_plus_Lambert_W'_eq:
assumes "x ∈ {-exp(-1)..<0}" "y ∈ {-exp(-1)..<0}"
shows "Lambert_W' x + Lambert_W' y = Lambert_W' (x * y * (1 / Lambert_W' x + 1 / Lambert_W' y))"
proof (rule sym, rule Lambert_W'_eqI)
from assms show "(Lambert_W' x + Lambert_W' y) * exp (Lambert_W' x + Lambert_W' y) =
x * y * (1 / Lambert_W' x + 1 / Lambert_W' y)"
by (auto simp: field_simps exp_add exp_Lambert_W')
have "Lambert_W' x + Lambert_W' y ≤ -1 + -1"
by (intro add_mono Lambert_W'_le)
also have "… ≤ -1" by simp
finally show "Lambert_W' x + Lambert_W' y ≤ -1" .
qed
lemma Lambert_W_gt_ln_minus_ln_ln:
assumes "x > exp 1"
shows "Lambert_W x > ln x - ln (ln x)"
proof (rule Lambert_W_gtI)
have "x > 1"
by (rule less_trans[OF _ assms]) auto
have "ln x > ln (exp 1)"
by (subst ln_less_cancel_iff) (use ‹x > 1› assms in auto)
thus "(ln x - ln (ln x)) * exp (ln x - ln (ln x)) < x"
using assms ‹x > 1› by (simp add: exp_diff field_simps)
qed
lemma Lambert_W_less_ln:
assumes "x > exp 1"
shows "Lambert_W x < ln x"
proof (rule Lambert_W_lessI)
have "x > 0"
by (rule less_trans[OF _ assms]) auto
have "ln x > ln (exp 1)"
by (subst ln_less_cancel_iff) (use ‹x > 0› assms in auto)
thus "x < ln x * exp (ln x)"
using ‹x > 0› by simp
show "ln x ≥ -1"
by (rule less_imp_le[OF le_less_trans[OF _ ‹ln x > _›]]) auto
show "x ≥ -exp (-1)"
by (rule less_imp_le[OF le_less_trans[OF _ ‹x > 0›]]) auto
qed
subsection ‹Limits, continuity, and differentiability›
lemma filterlim_Lambert_W_at_top [tendsto_intros]: "filterlim Lambert_W at_top at_top"
unfolding filterlim_at_top
proof
fix C :: real
have "eventually (λx. x ≥ C * exp C) at_top"
by (rule eventually_ge_at_top)
thus "eventually (λx. Lambert_W x ≥ C) at_top"
proof eventually_elim
case (elim x)
thus ?case
by (intro Lambert_W_geI) auto
qed
qed
lemma filterlim_Lambert_W_at_left_0 [tendsto_intros]:
"filterlim Lambert_W' at_bot (at_left 0)"
unfolding filterlim_at_bot
proof
fix C :: real
define C' where "C' = min C (-1)"
have "C' < 0" "C' ≤ C"
by (simp_all add: C'_def)
have "C' * exp C' < 0"
using ‹C' < 0› by (intro mult_neg_pos) auto
hence "eventually (λx. x ≥ C' * exp C') (at_left 0)"
by real_asymp
moreover have "eventually (λx::real. x < 0) (at_left 0)"
by real_asymp
ultimately show "eventually (λx. Lambert_W' x ≤ C) (at_left 0)"
proof eventually_elim
case (elim x)
hence "Lambert_W' x ≤ C'"
by (intro Lambert_W'_leI) auto
also have "… ≤ C" by fact
finally show ?case .
qed
qed
lemma continuous_on_Lambert_W [continuous_intros]: "continuous_on {-exp (-1)..} Lambert_W"
proof -
have *: "continuous_on {-exp (-1)..b * exp b} Lambert_W" if "b ≥ 0" for b
proof -
have "continuous_on ((λx. x * exp x) ` {-1..b}) Lambert_W"
by (rule continuous_on_inv) (auto intro!: continuous_intros)
also have "(λx. x * exp x) ` {-1..b} = {-exp (-1)..b * exp b}"
using bij_betw_exp_times_self_atLeastAtMost[of "-1" b] ‹b ≥ 0›
by (simp add: bij_betw_def)
finally show ?thesis .
qed
have "continuous (at x) Lambert_W" if "x ≥ 0" for x
proof -
have x: "-exp (-1) < x"
by (rule less_le_trans[OF _ that]) auto
define b where "b = Lambert_W x + 1"
have "b ≥ 0"
using Lambert_W_ge[of x] by (simp add: b_def)
have "x = Lambert_W x * exp (Lambert_W x)"
using that x by (subst Lambert_W_times_exp_self) auto
also have "… < b * exp b"
by (intro exp_times_self_strict_mono) (auto simp: b_def Lambert_W_ge)
finally have "b * exp b > x" .
have "continuous_on {-exp(-1)<..<b * exp b} Lambert_W"
by (rule continuous_on_subset[OF *[of b]]) (use ‹b ≥ 0› in auto)
moreover have "x ∈ {-exp(-1)<..<b * exp b}"
using ‹b * exp b > x› x by auto
ultimately show "continuous (at x) Lambert_W"
by (subst (asm) continuous_on_eq_continuous_at) auto
qed
hence "continuous_on {0..} Lambert_W"
by (intro continuous_at_imp_continuous_on) auto
moreover have "continuous_on {-exp (-1)..0} Lambert_W"
using *[of 0] by simp
ultimately have "continuous_on ({-exp (-1)..0} ∪ {0..}) Lambert_W"
by (intro continuous_on_closed_Un) auto
also have "{-exp (-1)..0} ∪ {0..} = {-exp (-1::real)..}"
using order.trans[of "-exp (-1)::real" 0] by auto
finally show ?thesis .
qed
lemma continuous_on_Lambert_W_alt [continuous_intros]:
assumes "continuous_on A f" "⋀x. x ∈ A ⟹ f x ≥ -exp (-1)"
shows "continuous_on A (λx. Lambert_W (f x))"
using continuous_on_compose2[OF continuous_on_Lambert_W assms(1)] assms by auto
lemma continuous_on_Lambert_W' [continuous_intros]: "continuous_on {-exp (-1)..<0} Lambert_W'"
proof -
have *: "continuous_on {-exp (-1)..-b * exp (-b)} Lambert_W'" if "b ≥ 1" for b
proof -
have "continuous_on ((λx. x * exp x) ` {-b..-1}) Lambert_W'"
by (intro continuous_on_inv ballI) (auto intro!: continuous_intros)
also have "(λx. x * exp x) ` {-b..-1} = {-exp (-1)..-b * exp (-b)}"
using bij_betw_exp_times_self_atLeastAtMost'[of "-b" "-1"] that
by (simp add: bij_betw_def)
finally show ?thesis .
qed
have "continuous (at x) Lambert_W'" if "x > -exp (-1)" "x < 0" for x
proof -
define b where "b = Lambert_W x + 1"
have "eventually (λb. -b * exp (-b) > x) at_top"
using that by real_asymp
hence "eventually (λb. b ≥ 1 ∧ -b * exp (-b) > x) at_top"
by (intro eventually_conj eventually_ge_at_top)
then obtain b where b: "b ≥ 1" "-b * exp (-b) > x"
by (auto simp: eventually_at_top_linorder)
have "continuous_on {-exp(-1)<..<-b * exp (-b)} Lambert_W'"
by (rule continuous_on_subset[OF *[of b]]) (use ‹b ≥ 1› in auto)
moreover have "x ∈ {-exp(-1)<..<-b * exp (-b)}"
using b that by auto
ultimately show "continuous (at x) Lambert_W'"
by (subst (asm) continuous_on_eq_continuous_at) auto
qed
hence **: "continuous_on {-exp (-1)<..<0} Lambert_W'"
by (intro continuous_at_imp_continuous_on) auto
show ?thesis
unfolding continuous_on_def
proof
fix x :: real assume x: "x ∈ {-exp(-1)..<0}"
show "(Lambert_W' ⤏ Lambert_W' x) (at x within {-exp(-1)..<0})"
proof (cases "x = -exp(-1)")
case False
hence "isCont Lambert_W' x"
using x ** by (auto simp: continuous_on_eq_continuous_at)
thus ?thesis
using continuous_at filterlim_within_subset by blast
next
case True
define a :: real where "a = -2 * exp (-2)"
have a: "a > -exp (-1)"
using exp_times_self_strict_antimono[of "-1" "-2"] by (auto simp: a_def)
from True have "x ∈ {-exp (-1)..<a}"
using a by (auto simp: a_def)
have "continuous_on {-exp (-1)..<a} Lambert_W'"
unfolding a_def by (rule continuous_on_subset[OF *[of 2]]) auto
hence "(Lambert_W' ⤏ Lambert_W' x) (at x within {-exp (-1)..<a})"
using ‹x ∈ {-exp (-1)..<a}› by (auto simp: continuous_on_def)
also have "at x within {-exp (-1)..<a} = at_right x"
using a by (intro at_within_nhd[of _ "{..<a}"]) (auto simp: True)
also have "… = at x within {-exp (-1)..<0}"
using a by (intro at_within_nhd[of _ "{..<0}"]) (auto simp: True)
finally show ?thesis .
qed
qed
qed
lemma continuous_on_Lambert_W'_alt [continuous_intros]:
assumes "continuous_on A f" "⋀x. x ∈ A ⟹ f x ∈ {-exp (-1)..<0}"
shows "continuous_on A (λx. Lambert_W' (f x))"
using continuous_on_compose2[OF continuous_on_Lambert_W' assms(1)] assms
by (auto simp: subset_iff)
lemma tendsto_Lambert_W_1:
assumes "(f ⤏ L) F" "eventually (λx. f x ≥ -exp (-1)) F"
shows "((λx. Lambert_W (f x)) ⤏ Lambert_W L) F"
proof (cases "F = bot")
case [simp]: False
from tendsto_lowerbound[OF assms] have "L ≥ -exp (-1)" by simp
thus ?thesis
using continuous_on_tendsto_compose[OF continuous_on_Lambert_W assms(1)] assms(2) by simp
qed auto
lemma tendsto_Lambert_W_2:
assumes "(f ⤏ L) F" "L > -exp (-1)"
shows "((λx. Lambert_W (f x)) ⤏ Lambert_W L) F"
using order_tendstoD(1)[OF assms] assms
by (intro tendsto_Lambert_W_1) (auto elim: eventually_mono)
lemma tendsto_Lambert_W [tendsto_intros]:
assumes "(f ⤏ L) F" "eventually (λx. f x ≥ -exp (-1)) F ∨ L > -exp (-1)"
shows "((λx. Lambert_W (f x)) ⤏ Lambert_W L) F"
using assms(2)
proof
assume "L > -exp (-1)"
from order_tendstoD(1)[OF assms(1) this] assms(1) show ?thesis
by (intro tendsto_Lambert_W_1) (auto elim: eventually_mono)
qed (use tendsto_Lambert_W_1[OF assms(1)] in auto)
lemma tendsto_Lambert_W'_1:
assumes "(f ⤏ L) F" "eventually (λx. f x ≥ -exp (-1)) F" "L < 0"
shows "((λx. Lambert_W' (f x)) ⤏ Lambert_W' L) F"
proof (cases "F = bot")
case [simp]: False
from tendsto_lowerbound[OF assms(1,2)] have L_ge: "L ≥ -exp (-1)" by simp
from order_tendstoD(2)[OF assms(1,3)] have ev: "eventually (λx. f x < 0) F"
by auto
with assms(2) have "eventually (λx. f x ∈ {-exp (-1)..<0}) F"
by eventually_elim auto
thus ?thesis using L_ge assms(3)
by (intro continuous_on_tendsto_compose[OF continuous_on_Lambert_W' assms(1)]) auto
qed auto
lemma tendsto_Lambert_W'_2:
assumes "(f ⤏ L) F" "L > -exp (-1)" "L < 0"
shows "((λx. Lambert_W' (f x)) ⤏ Lambert_W' L) F"
using order_tendstoD(1)[OF assms(1,2)] assms
by (intro tendsto_Lambert_W'_1) (auto elim: eventually_mono)
lemma tendsto_Lambert_W' [tendsto_intros]:
assumes "(f ⤏ L) F" "eventually (λx. f x ≥ -exp (-1)) F ∨ L > -exp (-1)" "L < 0"
shows "((λx. Lambert_W' (f x)) ⤏ Lambert_W' L) F"
using assms(2)
proof
assume "L > -exp (-1)"
from order_tendstoD(1)[OF assms(1) this] assms(1,3) show ?thesis
by (intro tendsto_Lambert_W'_1) (auto elim: eventually_mono)
qed (use tendsto_Lambert_W'_1[OF assms(1) _ assms(3)] in auto)
lemma continuous_Lambert_W [continuous_intros]:
assumes "continuous F f" "f (Lim F (λx. x)) > -exp (-1) ∨ eventually (λx. f x ≥ -exp (-1)) F"
shows "continuous F (λx. Lambert_W (f x))"
using assms unfolding continuous_def by (intro tendsto_Lambert_W) auto
lemma continuous_Lambert_W' [continuous_intros]:
assumes "continuous F f" "f (Lim F (λx. x)) > -exp (-1) ∨ eventually (λx. f x ≥ -exp (-1)) F"
"f (Lim F (λx. x)) < 0"
shows "continuous F (λx. Lambert_W' (f x))"
using assms unfolding continuous_def by (intro tendsto_Lambert_W') auto
lemma has_field_derivative_Lambert_W [derivative_intros]:
assumes x: "x > -exp (-1)"
shows "(Lambert_W has_real_derivative inverse (x + exp (Lambert_W x))) (at x within A)"
proof -
write Lambert_W (‹W›)
from x have "W x > W (-exp (-1))"
by (subst Lambert_W_less_iff) auto
hence "W x > -1" by simp
note [derivative_intros] = DERIV_inverse_function[where g = Lambert_W]
have "((λx. x * exp x) has_real_derivative (1 + W x) * exp (W x)) (at (W x))"
by (auto intro!: derivative_eq_intros simp: algebra_simps)
hence "(W has_real_derivative inverse ((1 + W x) * exp (W x))) (at x)"
by (rule DERIV_inverse_function[where a = "-exp (-1)" and b = "x + 1"])
(use x ‹W x > -1› in ‹auto simp: Lambert_W_times_exp_self Lim_ident_at
intro!: continuous_intros›)
also have "(1 + W x) * exp (W x) = x + exp (W x)"
using x by (simp add: algebra_simps Lambert_W_times_exp_self)
finally show ?thesis by (rule has_field_derivative_at_within)
qed
lemma has_field_derivative_Lambert_W_gen [derivative_intros]:
assumes "(f has_real_derivative f') (at x within A)" "f x > -exp (-1)"
shows "((λx. Lambert_W (f x)) has_real_derivative
(f' / (f x + exp (Lambert_W (f x))))) (at x within A)"
using DERIV_chain2[OF has_field_derivative_Lambert_W[OF assms(2)] assms(1)]
by (simp add: field_simps)
lemma has_field_derivative_Lambert_W' [derivative_intros]:
assumes x: "x ∈ {-exp (-1)<..<0}"
shows "(Lambert_W' has_real_derivative inverse (x + exp (Lambert_W' x))) (at x within A)"
proof -
write Lambert_W' (‹W›)
from x have "W x < W (-exp (-1))"
by (subst Lambert_W'_less_iff) auto
hence "W x < -1" by simp
note [derivative_intros] = DERIV_inverse_function[where g = Lambert_W]
have "((λx. x * exp x) has_real_derivative (1 + W x) * exp (W x)) (at (W x))"
by (auto intro!: derivative_eq_intros simp: algebra_simps)
hence "(W has_real_derivative inverse ((1 + W x) * exp (W x))) (at x)"
by (rule DERIV_inverse_function[where a = "-exp (-1)" and b = "0"])
(use x ‹W x < -1› in ‹auto simp: Lambert_W'_times_exp_self Lim_ident_at
intro!: continuous_intros›)
also have "(1 + W x) * exp (W x) = x + exp (W x)"
using x by (simp add: algebra_simps Lambert_W'_times_exp_self)
finally show ?thesis by (rule has_field_derivative_at_within)
qed
lemma has_field_derivative_Lambert_W'_gen [derivative_intros]:
assumes "(f has_real_derivative f') (at x within A)" "f x ∈ {-exp (-1)<..<0}"
shows "((λx. Lambert_W' (f x)) has_real_derivative
(f' / (f x + exp (Lambert_W' (f x))))) (at x within A)"
using DERIV_chain2[OF has_field_derivative_Lambert_W'[OF assms(2)] assms(1)]
by (simp add: field_simps)
subsection ‹Asymptotic expansion›
text ‹
Lastly, we prove some more detailed asymptotic expansions of $W$ and $W'$ at their
singularities. First, we show that:
\begin{align*}
W(x) &= \log x - \log\log x + o(\log\log x) &&\text{for}\ x\to\infty\\
W'(x) &= \log (-x) - \log (-\log (-x)) + o(\log (-\log (-x))) &&\text{for}\ x\to 0^{-}
\end{align*}
›
theorem Lambert_W_asymp_equiv_at_top:
"(λx. Lambert_W x - ln x) ∼[at_top] (λx. -ln (ln x))"
proof -
have "(λx. Lambert_W x - ln x) ∼[at_top] (λx. (-1) * ln (ln x))"
proof (rule asymp_equiv_sandwich')
fix c' :: real assume c': "c' ∈ {-2<..<-1}"
have "eventually (λx. (ln x + c' * ln (ln x)) * exp (ln x + c' * ln (ln x)) ≤ x) at_top"
"eventually (λx. ln x + c' * ln (ln x) ≥ -1) at_top"
using c' by real_asymp+
thus "eventually (λx. Lambert_W x - ln x ≥ c' * ln (ln x)) at_top"
proof eventually_elim
case (elim x)
hence "Lambert_W x ≥ ln x + c' * ln (ln x)"
by (intro Lambert_W_geI)
thus ?case by simp
qed
next
fix c' :: real assume c': "c' ∈ {-1<..<0}"
have "eventually (λx. (ln x + c' * ln (ln x)) * exp (ln x + c' * ln (ln x)) ≥ x) at_top"
"eventually (λx. ln x + c' * ln (ln x) ≥ -1) at_top"
using c' by real_asymp+
thus "eventually (λx. Lambert_W x - ln x ≤ c' * ln (ln x)) at_top"
using eventually_ge_at_top[of "-exp (-1)"]
proof eventually_elim
case (elim x)
hence "Lambert_W x ≤ ln x + c' * ln (ln x)"
by (intro Lambert_W_leI)
thus ?case by simp
qed
qed auto
thus ?thesis by simp
qed
lemma Lambert_W_asymp_equiv_at_top' [asymp_equiv_intros]:
"Lambert_W ∼[at_top] ln"
proof -
have "(λx. Lambert_W x - ln x) ∈ Θ(λx. -ln (ln x))"
by (intro asymp_equiv_imp_bigtheta Lambert_W_asymp_equiv_at_top)
also have "(λx::real. -ln (ln x)) ∈ o(ln)"
by real_asymp
finally show ?thesis by (simp add: asymp_equiv_altdef)
qed
theorem Lambert_W'_asymp_equiv_at_left_0:
"(λx. Lambert_W' x - ln (-x)) ∼[at_left 0] (λx. -ln (-ln (-x)))"
proof -
have "(λx. Lambert_W' x - ln (-x)) ∼[at_left 0] (λx. (-1) * ln (-ln (-x)))"
proof (rule asymp_equiv_sandwich')
fix c' :: real assume c': "c' ∈ {-2<..<-1}"
have "eventually (λx. x ≤ (ln (-x) + c' * ln (-ln (-x))) * exp (ln (-x) + c' * ln (-ln (-x)))) (at_left 0)"
"eventually (λx::real. ln (-x) + c' * ln (-ln (-x)) ≤ -1) (at_left 0)"
"eventually (λx::real. -exp (-1) ≤ x) (at_left 0)"
using c' by real_asymp+
thus "eventually (λx. Lambert_W' x - ln (-x) ≥ c' * ln (-ln (-x))) (at_left 0)"
proof eventually_elim
case (elim x)
hence "Lambert_W' x ≥ ln (-x) + c' * ln (-ln (-x))"
by (intro Lambert_W'_geI)
thus ?case by simp
qed
next
fix c' :: real assume c': "c' ∈ {-1<..<0}"
have "eventually (λx. x ≥ (ln (-x) + c' * ln (-ln (-x))) * exp (ln (-x) + c' * ln (-ln (-x)))) (at_left 0)"
using c' by real_asymp
moreover have "eventually (λx::real. x < 0) (at_left 0)"
by (auto simp: eventually_at intro: exI[of _ 1])
ultimately show "eventually (λx. Lambert_W' x - ln (-x) ≤ c' * ln (-ln (-x))) (at_left 0)"
proof eventually_elim
case (elim x)
hence "Lambert_W' x ≤ ln (-x) + c' * ln (-ln (-x))"
by (intro Lambert_W'_leI)
thus ?case by simp
qed
qed auto
thus ?thesis by simp
qed
lemma Lambert_W'_asymp_equiv'_at_left_0 [asymp_equiv_intros]:
"Lambert_W' ∼[at_left 0] (λx. ln (-x))"
proof -
have "(λx. Lambert_W' x - ln (-x)) ∈ Θ[at_left 0](λx. -ln (-ln (-x)))"
by (intro asymp_equiv_imp_bigtheta Lambert_W'_asymp_equiv_at_left_0)
also have "(λx::real. -ln (-ln (-x))) ∈ o[at_left 0](λx. ln (-x))"
by real_asymp
finally show ?thesis by (simp add: asymp_equiv_altdef)
qed
text ‹
Next, we look at the branching point $a := \tfrac{1}{e}$. Here, the asymptotic behaviour
is as follows:
\begin{align*}
W(x) &= -1 + \sqrt{2e}(x - a)^{\frac{1}{2}} - \tfrac{2}{3}e(x-a) + o(x-a) &&\text{for} x\to a^+\\
W'(x) &= -1 - \sqrt{2e}(x - a)^{\frac{1}{2}} - \tfrac{2}{3}e(x-a) + o(x-a) &&\text{for} x\to a^+
\end{align*}
›
lemma sqrt_sqrt_mult:
assumes "x ≥ (0 :: real)"
shows "sqrt x * (sqrt x * y) = x * y"
using assms by (subst mult.assoc [symmetric]) auto
theorem Lambert_W_asymp_equiv_at_right_minus_exp_minus1:
defines "e ≡ exp 1"
defines "a ≡ -exp (-1)"
defines "C1 ≡ sqrt (2 * exp 1)"
defines "f ≡ (λx. -1 + C1 * sqrt (x - a))"
shows "(λx. Lambert_W x - f x) ∼[at_right a] (λx. -2/3 * e * (x - a))"
proof -
define C :: "real ⇒ real" where "C = (λc. sqrt (2/e)/3 * (2*e+3*c))"
have asymp_equiv: "(λx. (f x + c * (x - a)) * exp (f x + c * (x - a)) - x)
∼[at_right a] (λx. C c * (x - a) powr (3/2))" if "c ≠ -2/3 * e" for c
proof -
from that have "C c ≠ 0"
by (auto simp: C_def e_def)
have "(λx. (f x + c * (x - a)) * exp (f x + c * (x - a)) - x - C c * (x - a) powr (3/2))
∈ o[at_right a](λx. (x - a) powr (3/2))"
unfolding f_def a_def C_def C1_def e_def
by (real_asymp simp: field_simps real_sqrt_mult real_sqrt_divide sqrt_sqrt_mult
exp_minus simp flip: sqrt_def)
thus ?thesis
using ‹C c ≠ 0› by (intro smallo_imp_asymp_equiv) auto
qed
show ?thesis
proof (rule asymp_equiv_sandwich')
fix c' :: real assume c': "c' ∈ {-e<..<-2/3*e}"
hence neq: "c' ≠ -2/3 * e" by auto
from c' have neg: "C c' < 0" unfolding C_def by (auto intro!: mult_pos_neg)
hence "eventually (λx. C c' * (x - a) powr (3 / 2) < 0) (at_right a)"
by real_asymp
hence "eventually (λx. (f x + c' * (x - a)) * exp (f x + c' * (x - a)) - x < 0) (at_right a)"
using asymp_equiv_eventually_neg_iff[OF asymp_equiv[OF neq]]
by eventually_elim (use neg in auto)
thus "eventually (λx. Lambert_W x - f x ≥ c' * (x - a)) (at_right a)"
proof eventually_elim
case (elim x)
hence "Lambert_W x ≥ f x + c' * (x - a)"
by (intro Lambert_W_geI) auto
thus ?case by simp
qed
next
fix c' :: real assume c': "c' ∈ {-2/3*e<..<0}"
hence neq: "c' ≠ -2/3 * e" by auto
from c' have pos: "C c' > 0" unfolding C_def by auto
hence "eventually (λx. C c' * (x - a) powr (3 / 2) > 0) (at_right a)"
by real_asymp
hence "eventually (λx. (f x + c' * (x - a)) * exp (f x + c' * (x - a)) - x > 0) (at_right a)"
using asymp_equiv_eventually_pos_iff[OF asymp_equiv[OF neq]]
by eventually_elim (use pos in auto)
moreover have "eventually (λx. - 1 ≤ f x + c' * (x - a)) (at_right a)"
"eventually (λx. x > a) (at_right a)"
unfolding a_def f_def C1_def c' by real_asymp+
ultimately show "eventually (λx. Lambert_W x - f x ≤ c' * (x - a)) (at_right a)"
proof eventually_elim
case (elim x)
hence "Lambert_W x ≤ f x + c' * (x - a)"
by (intro Lambert_W_leI) (auto simp: a_def)
thus ?case by simp
qed
qed (auto simp: e_def)
qed
theorem Lambert_W'_asymp_equiv_at_right_minus_exp_minus1:
defines "e ≡ exp 1"
defines "a ≡ -exp (-1)"
defines "C1 ≡ sqrt (2 * exp 1)"
defines "f ≡ (λx. -1 - C1 * sqrt (x - a))"
shows "(λx. Lambert_W' x - f x) ∼[at_right a] (λx. -2/3 * e * (x - a))"
proof -
define C :: "real ⇒ real" where "C = (λc. -sqrt (2/e)/3 * (2*e+3*c))"
have asymp_equiv: "(λx. (f x + c * (x - a)) * exp (f x + c * (x - a)) - x)
∼[at_right a] (λx. C c * (x - a) powr (3/2))" if "c ≠ -2/3 * e" for c
proof -
from that have "C c ≠ 0"
by (auto simp: C_def e_def)
have "(λx. (f x + c * (x - a)) * exp (f x + c * (x - a)) - x - C c * (x - a) powr (3/2))
∈ o[at_right a](λx. (x - a) powr (3/2))"
unfolding f_def a_def C_def C1_def e_def
by (real_asymp simp: field_simps real_sqrt_mult real_sqrt_divide sqrt_sqrt_mult
exp_minus simp flip: sqrt_def)
thus ?thesis
using ‹C c ≠ 0› by (intro smallo_imp_asymp_equiv) auto
qed
show ?thesis
proof (rule asymp_equiv_sandwich')
fix c' :: real assume c': "c' ∈ {-e<..<-2/3*e}"
hence neq: "c' ≠ -2/3 * e" by auto
from c' have pos: "C c' > 0" unfolding C_def by (auto intro!: mult_pos_neg)
hence "eventually (λx. C c' * (x - a) powr (3 / 2) > 0) (at_right a)"
by real_asymp
hence "eventually (λx. (f x + c' * (x - a)) * exp (f x + c' * (x - a)) - x > 0) (at_right a)"
using asymp_equiv_eventually_pos_iff[OF asymp_equiv[OF neq]]
by eventually_elim (use pos in auto)
moreover have "eventually (λx. x > a) (at_right a)"
"eventually (λx. f x + c' * (x - a) ≤ -1) (at_right a)"
unfolding a_def f_def C1_def c' by real_asymp+
ultimately show "eventually (λx. Lambert_W' x - f x ≥ c' * (x - a)) (at_right a)"
proof eventually_elim
case (elim x)
hence "Lambert_W' x ≥ f x + c' * (x - a)"
by (intro Lambert_W'_geI) (auto simp: a_def)
thus ?case by simp
qed
next
fix c' :: real assume c': "c' ∈ {-2/3*e<..<0}"
hence neq: "c' ≠ -2/3 * e" by auto
from c' have neg: "C c' < 0" unfolding C_def by auto
hence "eventually (λx. C c' * (x - a) powr (3 / 2) < 0) (at_right a)"
by real_asymp
hence "eventually (λx. (f x + c' * (x - a)) * exp (f x + c' * (x - a)) - x < 0) (at_right a)"
using asymp_equiv_eventually_neg_iff[OF asymp_equiv[OF neq]]
by eventually_elim (use neg in auto)
moreover have "eventually (λx. x < 0) (at_right a)"
unfolding a_def by real_asymp
ultimately show "eventually (λx. Lambert_W' x - f x ≤ c' * (x - a)) (at_right a)"
proof eventually_elim
case (elim x)
hence "Lambert_W' x ≤ f x + c' * (x - a)"
by (intro Lambert_W'_leI) auto
thus ?case by simp
qed
qed (auto simp: e_def)
qed
text ‹
Lastly, just for fun, we derive a slightly more accurate expansion of $W_0(x)$ for $x\to\infty$:
›
theorem Lambert_W_asymp_equiv_at_top'':
"(λx. Lambert_W x - ln x + ln (ln x)) ∼[at_top] (λx. ln (ln x) / ln x)"
proof -
have "(λx. Lambert_W x - ln x + ln (ln x)) ∼[at_top] (λx. 1 * (ln (ln x) / ln x))"
proof (rule asymp_equiv_sandwich')
fix c' :: real assume c': "c' ∈ {0<..<1}"
define a where "a = (λx::real. ln x - ln (ln x) + c' * (ln (ln x) / ln x))"
have "eventually (λx. a x * exp (a x) ≤ x) at_top"
using c' unfolding a_def by real_asymp+
thus "eventually (λx. Lambert_W x - ln x + ln (ln x) ≥ c' * (ln (ln x) / ln x)) at_top"
proof eventually_elim
case (elim x)
hence "Lambert_W x ≥ a x"
by (intro Lambert_W_geI)
thus ?case by (simp add: a_def)
qed
next
fix c' :: real assume c': "c' ∈ {1<..<2}"
define a where "a = (λx::real. ln x - ln (ln x) + c' * (ln (ln x) / ln x))"
have "eventually (λx. a x * exp (a x) ≥ x) at_top"
"eventually (λx. a x ≥ -1) at_top"
using c' unfolding a_def by real_asymp+
thus "eventually (λx. Lambert_W x - ln x + ln (ln x) ≤ c' * (ln (ln x) / ln x)) at_top"
using eventually_ge_at_top[of "-exp (-1)"]
proof eventually_elim
case (elim x)
hence "Lambert_W x ≤ a x"
by (intro Lambert_W_leI)
thus ?case by (simp add: a_def)
qed
qed auto
thus ?thesis by simp
qed
end