aboutsummaryrefslogtreecommitdiffstats
path: root/buch/papers/laguerre
diff options
context:
space:
mode:
authorAndreas Müller <andreas.mueller@ost.ch>2022-05-12 18:54:44 +0200
committerGitHub <noreply@github.com>2022-05-12 18:54:44 +0200
commit522ef9d6cbac8aedc42b55ceced3482b2b8de515 (patch)
tree5b91b0e91a3e7aad4de16a2d26c5aae95cac538b /buch/papers/laguerre
parentdreiecksdaten (diff)
parentMerge branch 'AndreasFMueller:master' into master (diff)
downloadSeminarSpezielleFunktionen-522ef9d6cbac8aedc42b55ceced3482b2b8de515.tar.gz
SeminarSpezielleFunktionen-522ef9d6cbac8aedc42b55ceced3482b2b8de515.zip
Merge pull request #8 from p1mueller/master
Update Laguerre
Diffstat (limited to 'buch/papers/laguerre')
-rw-r--r--buch/papers/laguerre/Makefile6
-rw-r--r--buch/papers/laguerre/Makefile.inc4
-rw-r--r--buch/papers/laguerre/definition.tex174
-rw-r--r--buch/papers/laguerre/eigenschaften.tex94
-rw-r--r--buch/papers/laguerre/images/laguerre_polynomes.pdfbin0 -> 16239 bytes
-rw-r--r--buch/papers/laguerre/main.tex4
-rw-r--r--buch/papers/laguerre/packages.tex1
-rw-r--r--buch/papers/laguerre/scripts/gamma_approx.ipynb395
-rw-r--r--buch/papers/laguerre/scripts/laguerre_plot.py100
-rw-r--r--buch/papers/laguerre/transformation.tex31
-rw-r--r--buch/papers/laguerre/wasserstoff.tex29
11 files changed, 734 insertions, 104 deletions
diff --git a/buch/papers/laguerre/Makefile b/buch/papers/laguerre/Makefile
index 606d7e1..0f0985a 100644
--- a/buch/papers/laguerre/Makefile
+++ b/buch/papers/laguerre/Makefile
@@ -4,6 +4,8 @@
# (c) 2020 Prof Dr Andreas Mueller
#
-images:
- @echo "no images to be created in laguerre"
+images: images/laguerre_polynomes.pdf
+
+images/laguerre_polynomes.pdf: scripts/laguerre_plot.py
+ python3 scripts/laguerre_plot.py
diff --git a/buch/papers/laguerre/Makefile.inc b/buch/papers/laguerre/Makefile.inc
index 1eb5034..aae51f9 100644
--- a/buch/papers/laguerre/Makefile.inc
+++ b/buch/papers/laguerre/Makefile.inc
@@ -9,8 +9,6 @@ dependencies-laguerre = \
papers/laguerre/references.bib \
papers/laguerre/definition.tex \
papers/laguerre/eigenschaften.tex \
- papers/laguerre/quadratur.tex \
- papers/laguerre/transformation.tex \
- papers/laguerre/wasserstoff.tex
+ papers/laguerre/quadratur.tex
diff --git a/buch/papers/laguerre/definition.tex b/buch/papers/laguerre/definition.tex
index 5f6d8bd..edd2b7b 100644
--- a/buch/papers/laguerre/definition.tex
+++ b/buch/papers/laguerre/definition.tex
@@ -4,45 +4,151 @@
% (c) 2022 Patrik Müller, Ostschweizer Fachhochschule
%
\section{Definition
-\label{laguerre:section:definition}}
+ \label{laguerre:section:definition}}
\rhead{Definition}
-
+Die verallgemeinerte Laguerre-Differentialgleichung ist gegeben durch
\begin{align}
- x y''(x) + (1 - x) y'(x) + n y(x)
- =
- 0
- \label{laguerre:dgl}
+x y''(x) + (\nu + 1 - x) y'(x) + n y(x)
+=
+0
+, \quad
+n \in \mathbb{N}_0
+, \quad
+x \in \mathbb{R}
+.
+\label{laguerre:dgl}
\end{align}
-
+Hier wird die verallgemeinerte Laguerre-Differentialgleichung verwendet,
+weil die Lösung gleich berechnet werden kann,
+aber man zusätzlich die Lösung für den allgmeinen Fall erhält.
+Zur Lösung der Gleichung \eqref{laguerre:dgl} verwenden wir einen
+Potenzreihenansatz.
+Da wir bereits wissen, dass die Lösung orthogonale Polynome sind,
+erscheint dieser Ansatz sinnvoll.
+Setzt man nun den Ansatz
+\begin{align*}
+y(x)
+ & =
+\sum_{k=0}^\infty a_k x^k
+\\
+y'(x)
+ & =
+\sum_{k=1}^\infty k a_k x^{k-1}
+=
+\sum_{k=0}^\infty (k+1) a_{k+1} x^k
+\\
+y''(x)
+ & =
+\sum_{k=2}^\infty k (k-1) a_k x^{k-2}
+=
+\sum_{k=1}^\infty (k+1) k a_{k+1} x^{k-1}
+\end{align*}
+in die Differentialgleichung ein, erhält man:
+\begin{align*}
+\sum_{k=1}^\infty (k+1) k a_{k+1} x^k
++
+(\nu + 1)\sum_{k=0}^\infty (k+1) a_{k+1} x^k
+-
+\sum_{k=0}^\infty k a_k x^k
++
+n \sum_{k=0}^\infty a_k x^k
+ & =
+0 \\
+\sum_{k=1}^\infty
+\left[ (k+1) k a_{k+1} + (\nu + 1)(k+1) a_{k+1} - k a_k + n a_k \right] x^k
+ & =
+0.
+\end{align*}
+Daraus lässt sich die Rekursionsbeziehung
+\begin{align*}
+a_{k+1}
+ & =
+\frac{k-n}{(k+1) (k + \nu + 1)} a_k
+\end{align*}
+ableiten.
+Für ein konstantes $n$ erhalten wir als Potenzreihenlösung ein Polynom vom Grad
+$n$,
+denn für $k=n$ wird $a_{n+1} = 0$ und damit auch $a_{n+2}=a_{n+3}=\ldots=0$.
+Aus der Rekursionsbeziehung ist zudem ersichtlich,
+dass $a_0 \neq 0$ beliebig gewählt werden kann.
+Wählen wir nun $a_0 = 1$, dann folgt für die Koeffizienten $a_1, a_2, a_3$
+\begin{align*}
+a_1
+=
+-\frac{n}{1 \cdot (\nu + 1)}
+, & &
+a_2
+=
+\frac{(n-1)n}{1 \cdot 2 \cdot (\nu + 1)(\nu + 2)}
+, & &
+a_3
+=
+-\frac{(n-2)(n-1)n}{1 \cdot 2 \cdot 3 \cdot (\nu + 1)(\nu + 2)(\nu + 3)}
+\end{align*}
+und allgemein
+\begin{align*}
+k
+ & \leq
+n:
+ &
+a_k
+ & =
+(-1)^k \frac{n!}{(n-k)!} \frac{1}{k!(\nu + 1)_k}
+=
+\frac{(-1)^k}{(\nu + 1)_k} \binom{n}{k}
+\\
+k & >n:
+ &
+a_k
+ & =
+0.
+\end{align*}
+Somit erhalten wir für $\nu = 0$ die Laguerre-Polynome
\begin{align}
- L_n(x)
- =
- \sum_{k=0}^{n}
- \frac{(-1)^k}{k!}
- \begin{pmatrix}
- n \\
- k
- \end{pmatrix}
- x^k
- \label{laguerre:polynom}
+L_n(x)
+=
+\sum_{k=0}^{n} \frac{(-1)^k}{k!} \binom{n}{k} x^k
+\label{laguerre:polynom}
\end{align}
-
+und mit $\nu \in \mathbb{R}$ die verallgemeinerten Laguerre-Polynome
\begin{align}
- x y''(x) + (\alpha + 1 - x) y'(x) + n y(x)
- =
- 0
- \label{laguerre:generell_dgl}
+L_n^\nu(x)
+=
+\sum_{k=0}^{n} \frac{(-1)^k}{(\nu + 1)_k} \binom{n}{k} x^k.
+\label{laguerre:allg_polynom}
\end{align}
+Durch die analytische Fortsetzung erhalten wir zudem noch die zweite Lösung der
+Differentialgleichung mit der Form
+\begin{align*}
+\Xi_n(x)
+=
+L_n(x) \ln(x) + \sum_{k=1}^\infty d_k x^k
+\end{align*}
+Nach einigen mühsamen Rechnungen,
+die den Rahmen dieses Kapitel sprengen würden,
+erhalten wir
+\begin{align*}
+\Xi_n
+=
+L_n(x) \ln(x)
++
+\sum_{k=1}^n \frac{(-1)^k}{k!} \binom{n}{k}
+(\alpha_{n-k} - \alpha_n - 2 \alpha_k)x^k
++
+(-1)^n \sum_{k=1}^\infty \frac{(k-1)!n!}{((n+k)!)^2} x^{n+k},
+\end{align*}
+wobei $\alpha_0 = 0$ und $\alpha_k =\sum_{i=1}^k i^{-1}$,
+$\forall k \in \mathbb{N}$.
+Die Laguerre-Polynome von Grad $0$ bis $7$ sind in
+Abbildung~\ref{laguerre:fig:polyeval} dargestellt.
+\begin{figure}
+\centering
+\includegraphics[width=0.7\textwidth]{%
+ papers/laguerre/images/laguerre_polynomes.pdf%
+}
+\caption{Laguerre-Polynome vom Grad $0$ bis $7$}
+\label{laguerre:fig:polyeval}
+\end{figure}
-\begin{align}
- L_n^\alpha (x)
- =
- \sum_{k=0}^{n}
- \frac{(-1)^k}{k!}
- \begin{pmatrix}
- n + \alpha \\
- n - k
- \end{pmatrix}
- x^k
- \label{laguerre:polynom}
-\end{align}
+% https://www.math.kit.edu/iana1/lehre/hm3phys2012w/media/laguerre.pdf
+% http://www.physics.okayama-u.ac.jp/jeschke_homepage/E4/kapitel4.pdf
diff --git a/buch/papers/laguerre/eigenschaften.tex b/buch/papers/laguerre/eigenschaften.tex
index b7597e5..c589c92 100644
--- a/buch/papers/laguerre/eigenschaften.tex
+++ b/buch/papers/laguerre/eigenschaften.tex
@@ -4,5 +4,95 @@
% (c) 2022 Patrik Müller, Ostschweizer Fachhochschule
%
\section{Eigenschaften
-\label{laguerre:section:eigenschaften}}
-\rhead{Eigenschaften} \ No newline at end of file
+ \label{laguerre:section:eigenschaften}}
+\rhead{Eigenschaften}
+
+\subsection{Orthogonalität}
+Wenn wir die Laguerre\--Differentialgleichung in ein
+Sturm\--Liouville\--Problem umwandeln können, haben wir bewiesen, dass es sich
+bei
+den Laguerre\--Polynomen um orthogonale Polynome handelt (siehe
+Abschnitt~\ref{buch:integrale:subsection:sturm-liouville-problem}).
+Der Sturm-Liouville-Operator hat die Form
+\begin{align}
+S
+=
+\frac{1}{w(x)} \left(-\frac{d}{dx}p(x) \frac{d}{dx} + q(x) \right).
+\label{laguerre:slop}
+\end{align}
+Aus der Beziehung
+\begin{align}
+S
+ & =
+\Lambda
+\nonumber
+\\
+\frac{1}{w(x)} \left(-\frac{d}{dx}p(x) \frac{d}{dx} + q(x) \right)
+ & =
+x \frac{d^2}{dx^2} + (\nu + 1 - x) \frac{d}{dx}
+\label{laguerre:sl-lag}
+\end{align}
+lässt sich sofort erkennen, dass $q(x) = 0$.
+Ausserdem ist ersichtlich, dass $p(x)$ die Differentialgleichung
+\begin{align*}
+x \frac{dp}{dx}
+=
+-(\nu + 1 - x) p,
+\end{align*}
+erfüllen muss.
+Durch Separation erhalten wir dann
+\begin{align*}
+\int \frac{dp}{p}
+ & =
+-\int \frac{\nu + 1 - x}{x}dx
+\\
+\log p
+ & =
+-\log \nu + 1 - x + C
+\\
+p(x)
+ & =
+-C x^{\nu + 1} e^{-x}
+\end{align*}
+Eingefügt in Gleichung~\eqref{laguerre:sl-lag} erhalten wir
+\begin{align*}
+\frac{C}{w(x)}
+\left(
+x^{\nu+1} e^{-x} \frac{d^2}{dx^2} +
+(\nu + 1 - x) x^{\nu} e^{-x} \frac{d}{dx}
+\right)
+=
+x \frac{d^2}{dx^2} + (\nu + 1 - x) \frac{d}{dx}.
+\end{align*}
+Mittels Koeffizientenvergleich kann nun abgelesen werden, dass $w(x) = x^\nu
+e^{-x}$ und $C=1$ mit $\nu > -1$.
+Die Gewichtsfunktion $w(x)$ wächst für $x\rightarrow-\infty$ sehr schnell an,
+deshalb ist die Laguerre-Gewichtsfunktion nur geeignet für den
+Definitionsbereich $(0, \infty)$.
+Bleibt nur noch sicherzustellen, dass die Randbedingungen,
+\begin{align}
+k_0 y(0) + h_0 p(0)y'(0)
+ & =
+0
+\label{laguerre:sllag_randa}
+\\
+k_\infty y(\infty) + h_\infty p(\infty) y'(\infty)
+ & =
+0
+\label{laguerre:sllag_randb}
+\end{align}
+mit $|k_i|^2 + |h_i|^2 \neq 0,\,\forall i \in \{0, \infty\}$, erfüllt sind.
+Am linken Rand (Gleichung~\eqref{laguerre:sllag_randa}) kann $y(0) = 1$, $k_0 =
+0$ und $h_0 = 1$ verwendet werden,
+was auch die Laguerre-Polynome ergeben haben.
+Für den rechten Rand ist die Bedingung (Gleichung~\eqref{laguerre:sllag_randb})
+\begin{align*}
+\lim_{x \rightarrow \infty} p(x) y'(x)
+ & =
+\lim_{x \rightarrow \infty} -x^{\nu + 1} e^{-x} y'(x)
+=
+0
+\end{align*}
+für beliebige Polynomlösungen erfüllt für $k_\infty=0$ und $h_\infty=1$.
+Damit können wir schlussfolgern, dass die Laguerre-Polynome orthogonal
+bezüglich des Skalarproduktes mit der Laguerre\--Gewichtsfunktion sind.
diff --git a/buch/papers/laguerre/images/laguerre_polynomes.pdf b/buch/papers/laguerre/images/laguerre_polynomes.pdf
new file mode 100644
index 0000000..3976bc7
--- /dev/null
+++ b/buch/papers/laguerre/images/laguerre_polynomes.pdf
Binary files differ
diff --git a/buch/papers/laguerre/main.tex b/buch/papers/laguerre/main.tex
index 1fe0f8b..3db67d5 100644
--- a/buch/papers/laguerre/main.tex
+++ b/buch/papers/laguerre/main.tex
@@ -13,8 +13,8 @@ Hier kommt eine Einleitung.
\input{papers/laguerre/definition}
\input{papers/laguerre/eigenschaften}
\input{papers/laguerre/quadratur}
-\input{papers/laguerre/transformation}
-\input{papers/laguerre/wasserstoff}
+% \input{papers/laguerre/transformation}
+% \input{papers/laguerre/wasserstoff}
\printbibliography[heading=subbibliography]
\end{refsection}
diff --git a/buch/papers/laguerre/packages.tex b/buch/papers/laguerre/packages.tex
index ab55228..4ebc172 100644
--- a/buch/papers/laguerre/packages.tex
+++ b/buch/papers/laguerre/packages.tex
@@ -7,4 +7,3 @@
% if your paper needs special packages, add package commands as in the
% following example
\usepackage{derivative}
-
diff --git a/buch/papers/laguerre/scripts/gamma_approx.ipynb b/buch/papers/laguerre/scripts/gamma_approx.ipynb
new file mode 100644
index 0000000..44f3abd
--- /dev/null
+++ b/buch/papers/laguerre/scripts/gamma_approx.ipynb
@@ -0,0 +1,395 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Gauss-Laguerre Quadratur für die Gamma-Funktion\n",
+ "\n",
+ "$$\n",
+ " \\Gamma(z)\n",
+ " = \n",
+ " \\int_0^\\infty t^{z-1}e^{-t}dt\n",
+ "$$\n",
+ "\n",
+ "$$\n",
+ " \\int_0^\\infty f(x) e^{-x} dx \n",
+ " \\approx \n",
+ " \\sum_{i=1}^{N} f(x_i) w_i\n",
+ " \\qquad\\text{ wobei }\n",
+ " w_i = \\frac{x_i}{(n+1)^2 [L_{n+1}(x_i)]^2}\n",
+ "$$\n",
+ "und $x_i$ sind Nullstellen des Laguerre Polynoms $L_n(x)$\n",
+ "\n",
+ "Der Fehler ist gegeben als\n",
+ "\n",
+ "$$\n",
+ " E \n",
+ " =\n",
+ " \\frac{(n!)^2}{(2n)!} f^{(2n)}(\\xi) \n",
+ " = \n",
+ " \\frac{(-2n + z)_{2n}}{(z-m)_m} \\frac{(n!)^2}{(2n)!} \\xi^{z + m - 2n - 1}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "from cmath import exp, pi, sin, sqrt\n",
+ "import scipy.special\n",
+ "\n",
+ "EPSILON = 1e-07\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "lanczos_p = [\n",
+ " 676.5203681218851,\n",
+ " -1259.1392167224028,\n",
+ " 771.32342877765313,\n",
+ " -176.61502916214059,\n",
+ " 12.507343278686905,\n",
+ " -0.13857109526572012,\n",
+ " 9.9843695780195716e-6,\n",
+ " 1.5056327351493116e-7,\n",
+ "]\n",
+ "\n",
+ "\n",
+ "def drop_imag(z):\n",
+ " if abs(z.imag) <= EPSILON:\n",
+ " z = z.real\n",
+ " return z\n",
+ "\n",
+ "\n",
+ "def lanczos_gamma(z):\n",
+ " z = complex(z)\n",
+ " if z.real < 0.5:\n",
+ " y = pi / (sin(pi * z) * lanczos_gamma(1 - z)) # Reflection formula\n",
+ " else:\n",
+ " z -= 1\n",
+ " x = 0.99999999999980993\n",
+ " for (i, pval) in enumerate(lanczos_p):\n",
+ " x += pval / (z + i + 1)\n",
+ " t = z + len(lanczos_p) - 0.5\n",
+ " y = sqrt(2 * pi) * t ** (z + 0.5) * exp(-t) * x\n",
+ " return drop_imag(y)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "zeros, weights = np.polynomial.laguerre.laggauss(8)\n",
+ "# zeros = np.array(\n",
+ "# [\n",
+ "# 1.70279632305101000e-1,\n",
+ "# 9.03701776799379912e-1,\n",
+ "# 2.25108662986613069e0,\n",
+ "# 4.26670017028765879e0,\n",
+ "# 7.04590540239346570e0,\n",
+ "# 1.07585160101809952e1,\n",
+ "# 1.57406786412780046e1,\n",
+ "# 2.28631317368892641e1,\n",
+ "# ]\n",
+ "# )\n",
+ "\n",
+ "# weights = np.array(\n",
+ "# [\n",
+ "# 3.69188589341637530e-1,\n",
+ "# 4.18786780814342956e-1,\n",
+ "# 1.75794986637171806e-1,\n",
+ "# 3.33434922612156515e-2,\n",
+ "# 2.79453623522567252e-3,\n",
+ "# 9.07650877335821310e-5,\n",
+ "# 8.48574671627253154e-7,\n",
+ "# 1.04800117487151038e-9,\n",
+ "# ]\n",
+ "# )\n",
+ "\n",
+ "\n",
+ "def pochhammer(z, n):\n",
+ " return np.prod(z + np.arange(n))\n",
+ "\n",
+ "\n",
+ "def find_shift(z, target):\n",
+ " factor = 1.0\n",
+ " steps = int(np.floor(target - np.real(z)))\n",
+ " zs = z + steps\n",
+ " if steps > 0:\n",
+ " factor = 1 / pochhammer(z, steps)\n",
+ " elif steps < 0:\n",
+ " factor = pochhammer(zs, -steps)\n",
+ " return zs, factor\n",
+ "\n",
+ "\n",
+ "def laguerre_gamma(z, x, w, target=11):\n",
+ " # res = 0.0\n",
+ " z = complex(z)\n",
+ " if z.real < 1e-3:\n",
+ " res = pi / (\n",
+ " sin(pi * z) * laguerre_gamma(1 - z, x, w, target)\n",
+ " ) # Reflection formula\n",
+ " else:\n",
+ " z_shifted, correction_factor = find_shift(z, target)\n",
+ " res = np.sum(x ** (z_shifted - 1) * w)\n",
+ " res *= correction_factor\n",
+ " res = drop_imag(res)\n",
+ " return res\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def eval_laguerre(x, target=12):\n",
+ " return np.array([laguerre_gamma(xi, zeros, weights, target) for xi in x])\n",
+ "\n",
+ "\n",
+ "def eval_lanczos(x):\n",
+ " return np.array([lanczos_gamma(xi) for xi in x])\n",
+ "\n",
+ "\n",
+ "def eval_mean_laguerre(x, targets):\n",
+ " return np.mean([eval_laguerre(x, target) for target in targets], 0)\n",
+ "\n",
+ "\n",
+ "def calc_rel_error(x, y):\n",
+ " return (y - x) / x\n",
+ "\n",
+ "\n",
+ "def evaluate(x, target=12):\n",
+ " lanczos_gammas = eval_lanczos(x)\n",
+ " laguerre_gammas = eval_laguerre(x, target)\n",
+ " rel_error = calc_rel_error(lanczos_gammas, laguerre_gammas)\n",
+ " return rel_error\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Test with real values"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Empirische Tests zeigen:\n",
+ "- $n=4 \\Rightarrow m=6$\n",
+ "- $n=5 \\Rightarrow m=7$ oder $m=8$\n",
+ "- $n=6 \\Rightarrow m=9$\n",
+ "- $n=7 \\Rightarrow m=10$\n",
+ "- $n=8 \\Rightarrow m=11$ oder $m=12$\n",
+ "- $n=9 \\Rightarrow m=13$\n",
+ "- $n=10 \\Rightarrow m=14$\n",
+ "- $n=11 \\Rightarrow m=15$ oder $m=16$\n",
+ "- $n=12 \\Rightarrow m=17$\n",
+ "- $n=13 \\Rightarrow m=18 \\Rightarrow $ Beginnt numerisch instabil zu werden \n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "zeros, weights = np.polynomial.laguerre.laggauss(12)\n",
+ "targets = np.arange(16, 21)\n",
+ "mean_targets = ((16, 17),)\n",
+ "x = np.linspace(EPSILON, 1 - EPSILON, 101)\n",
+ "_, axs = plt.subplots(\n",
+ " 2, sharex=True, clear=True, constrained_layout=True, figsize=(12, 12)\n",
+ ")\n",
+ "\n",
+ "lanczos = eval_lanczos(x)\n",
+ "for mean_target in mean_targets:\n",
+ " vals = eval_mean_laguerre(x, mean_target)\n",
+ " rel_error_mean = calc_rel_error(lanczos, vals)\n",
+ " axs[0].plot(x, rel_error_mean, label=mean_target)\n",
+ " axs[1].semilogy(x, np.abs(rel_error_mean), label=mean_target)\n",
+ "\n",
+ "mins = []\n",
+ "maxs = []\n",
+ "for target in targets:\n",
+ " rel_error = evaluate(x, target)\n",
+ " mins.append(np.min(np.abs(rel_error[(0.1 <= x) & (x <= 0.9)])))\n",
+ " maxs.append(np.max(np.abs(rel_error)))\n",
+ " axs[0].plot(x, rel_error, label=target)\n",
+ " axs[1].semilogy(x, np.abs(rel_error), label=target)\n",
+ "# axs[0].set_ylim(*(np.array([-1, 1]) * 3.5e-8))\n",
+ "\n",
+ "axs[0].set_xlim(x[0], x[-1])\n",
+ "axs[1].set_ylim(np.min(mins), 1.04*np.max(maxs))\n",
+ "for ax in axs:\n",
+ " ax.legend()\n",
+ " ax.grid(which=\"both\")\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "targets = (16, 17)\n",
+ "xmax = 15\n",
+ "x = np.linspace(-xmax + EPSILON, xmax - EPSILON, 1000)\n",
+ "\n",
+ "mean_lag = eval_mean_laguerre(x, targets)\n",
+ "lanczos = eval_lanczos(x)\n",
+ "rel_error = calc_rel_error(lanczos, mean_lag)\n",
+ "rel_error_simple = evaluate(x, targets[-1])\n",
+ "# rel_error = evaluate(x, target)\n",
+ "\n",
+ "_, axs = plt.subplots(\n",
+ " 2, sharex=True, clear=True, constrained_layout=True, figsize=(12, 12)\n",
+ ")\n",
+ "axs[0].plot(x, rel_error, label=targets)\n",
+ "axs[1].semilogy(x, np.abs(rel_error), label=targets)\n",
+ "axs[0].plot(x, rel_error_simple, label=targets[-1])\n",
+ "axs[1].semilogy(x, np.abs(rel_error_simple), label=targets[-1])\n",
+ "axs[0].set_xlim(x[0], x[-1])\n",
+ "# axs[0].set_ylim(*(np.array([-1, 1]) * 4.2e-8))\n",
+ "# axs[1].set_ylim(1e-10, 5e-8)\n",
+ "for ax in axs:\n",
+ " ax.legend()\n",
+ "\n",
+ "x2 = np.linspace(-5 + EPSILON, 5, 4001)\n",
+ "_, ax = plt.subplots(constrained_layout=True, figsize=(8, 6))\n",
+ "ax.plot(x2, eval_mean_laguerre(x2, targets))\n",
+ "ax.set_xlim(x2[0], x2[-1])\n",
+ "ax.set_ylim(-7.5, 25)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Test with complex values"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "targets = (16, 17)\n",
+ "vals = np.linspace(-5 + EPSILON, 5, 100)\n",
+ "x, y = np.meshgrid(vals, vals)\n",
+ "mesh = x + 1j * y\n",
+ "input = mesh.flatten()\n",
+ "\n",
+ "mean_lag = eval_mean_laguerre(input, targets).reshape(mesh.shape)\n",
+ "lanczos = eval_lanczos(input).reshape(mesh.shape)\n",
+ "rel_error = np.abs(calc_rel_error(lanczos, mean_lag))\n",
+ "\n",
+ "lag = eval_laguerre(input, targets[-1]).reshape(mesh.shape)\n",
+ "rel_error_simple = np.abs(calc_rel_error(lanczos, lag))\n",
+ "# rel_error = evaluate(x, target)\n",
+ "\n",
+ "fig, axs = plt.subplots(\n",
+ " 2,\n",
+ " 2,\n",
+ " sharex=True,\n",
+ " sharey=True,\n",
+ " clear=True,\n",
+ " constrained_layout=True,\n",
+ " figsize=(12, 10),\n",
+ ")\n",
+ "_c = axs[0, 1].pcolormesh(x, y, np.log10(np.abs(lanczos - mean_lag)), shading=\"gouraud\")\n",
+ "_c = axs[0, 0].pcolormesh(x, y, np.log10(np.abs(lanczos - lag)), shading=\"gouraud\")\n",
+ "fig.colorbar(_c, ax=axs[0, :])\n",
+ "_c = axs[1, 1].pcolormesh(x, y, np.log10(rel_error), shading=\"gouraud\")\n",
+ "_c = axs[1, 0].pcolormesh(x, y, np.log10(rel_error_simple), shading=\"gouraud\")\n",
+ "fig.colorbar(_c, ax=axs[1, :])\n",
+ "_ = axs[0, 0].set_title(\"Absolute Error\")\n",
+ "_ = axs[1, 0].set_title(\"Relative Error\")\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "z = 0.5\n",
+ "ns = [4, 5, 5, 6, 7, 8, 8, 9, 10, 11, 11, 12] # np.arange(4, 13)\n",
+ "ms = np.arange(6, 18)\n",
+ "xi = np.logspace(0, 2, 201)[:, None]\n",
+ "lanczos = eval_lanczos([z])[0]\n",
+ "\n",
+ "_, ax = plt.subplots(clear=True, constrained_layout=True, figsize=(12, 8))\n",
+ "ax.grid(1)\n",
+ "for n, m in zip(ns, ms):\n",
+ " zeros, weights = np.polynomial.laguerre.laggauss(n)\n",
+ " c = scipy.special.factorial(n) ** 2 / scipy.special.factorial(2 * n)\n",
+ " e = np.abs(\n",
+ " scipy.special.poch(z - 2 * n, 2 * n)\n",
+ " / scipy.special.poch(z - m, m)\n",
+ " * c\n",
+ " * xi ** (z - 2 * n + m - 1)\n",
+ " )\n",
+ " ez = np.sum(\n",
+ " scipy.special.poch(z - 2 * n, 2 * n)\n",
+ " / scipy.special.poch(z - m, m)\n",
+ " * c\n",
+ " * zeros[:, None] ** (z - 2 * n + m - 1),\n",
+ " 0,\n",
+ " )\n",
+ " lag = eval_laguerre([z], m)[0]\n",
+ " err = np.abs(lanczos - lag)\n",
+ " # print(m+z,ez)\n",
+ " # for zi,ezi in zip(z[0], ez):\n",
+ " # print(f\"{m+zi}: {ezi}\")\n",
+ " # ax.semilogy(xi, e, color=color)\n",
+ " lines = ax.loglog(xi, e, label=str(n))\n",
+ " ax.axhline(err, color=lines[0].get_color())\n",
+ " # ax.set_xticks(np.arange(xi[-1] + 1))\n",
+ " # ax.set_ylim(1e-8, 1e5)\n",
+ "_ = ax.legend()\n",
+ "# _ = ax.legend([f\"z={zi}\" for zi in z[0]])\n",
+ "# _ = [ax.axvline(x) for x in zeros]\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "interpreter": {
+ "hash": "767d51c1340bd893661ea55ea3124f6de3c7a262a8b4abca0554b478b1e2ff90"
+ },
+ "kernelspec": {
+ "display_name": "Python 3.8.10 64-bit",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.10"
+ },
+ "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/buch/papers/laguerre/scripts/laguerre_plot.py b/buch/papers/laguerre/scripts/laguerre_plot.py
new file mode 100644
index 0000000..b9088d0
--- /dev/null
+++ b/buch/papers/laguerre/scripts/laguerre_plot.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+# -*- coding:utf-8 -*-
+"""Some plots for Laguerre Polynomials."""
+
+import os
+from pathlib import Path
+
+import matplotlib.pyplot as plt
+import numpy as np
+import scipy.special as ss
+
+
+def get_ticks(start, end, step=1):
+ ticks = np.arange(start, end, step)
+ return ticks[ticks != 0]
+
+
+N = 1000
+step = 5
+t = np.linspace(-1.05, 10.5, N)[:, None]
+root = str(Path(__file__).parent)
+img_path = f"{root}/../images"
+os.makedirs(img_path, exist_ok=True)
+
+
+# fig = plt.figure(num=1, clear=True, tight_layout=True, figsize=(5.5, 3.7))
+# ax = fig.add_subplot(axes_class=AxesZero)
+fig, ax = plt.subplots(num=1, clear=True, constrained_layout=True, figsize=(6, 4))
+for n in np.arange(0, 8):
+ k = np.arange(0, n + 1)[None]
+ L = np.sum((-1) ** k * ss.binom(n, k) / ss.factorial(k) * t ** k, -1)
+ ax.plot(t, L, label=f"n={n}")
+
+ax.set_xticks(get_ticks(int(t[0]), t[-1]), minor=True)
+ax.set_xticks(get_ticks(0, t[-1], step))
+ax.set_xlim(t[0], t[-1] + 0.1 * (t[1] - t[0]))
+ax.set_xlabel(r"$x$", x=1.0, labelpad=-10, rotation=0, fontsize="large")
+
+ylim = 13
+ax.set_yticks(np.arange(-ylim, ylim), minor=True)
+ax.set_yticks(np.arange(-step * (ylim // step), ylim, step))
+ax.set_ylim(-ylim, ylim)
+ax.set_ylabel(r"$y$", y=0.95, labelpad=-18, rotation=0, fontsize="large")
+
+ax.legend(ncol=2, loc=(0.125, 0.01), fontsize="large")
+
+# set the x-spine
+ax.spines[["left", "bottom"]].set_position("zero")
+ax.spines[["right", "top"]].set_visible(False)
+ax.xaxis.set_ticks_position("bottom")
+hlx = 0.4
+dx = t[-1, 0] - t[0, 0]
+dy = 2 * ylim
+hly = dy / dx * hlx
+dps = fig.dpi_scale_trans.inverted()
+bbox = ax.get_window_extent().transformed(dps)
+width, height = bbox.width, bbox.height
+
+# manual arrowhead width and length
+hw = 1.0 / 60.0 * dy
+hl = 1.0 / 30.0 * dx
+lw = 0.5 # axis line width
+ohg = 0.0 # arrow overhang
+
+# compute matching arrowhead length and width
+yhw = hw / dy * dx * height / width
+yhl = hl / dx * dy * width / height
+
+# draw x and y axis
+ax.arrow(
+ t[-1, 0] - hl,
+ 0,
+ hl,
+ 0.0,
+ fc="k",
+ ec="k",
+ lw=lw,
+ head_width=hw,
+ head_length=hl,
+ overhang=ohg,
+ length_includes_head=True,
+ clip_on=False,
+)
+
+ax.arrow(
+ 0,
+ ylim - yhl,
+ 0.0,
+ yhl,
+ fc="k",
+ ec="k",
+ lw=lw,
+ head_width=yhw,
+ head_length=yhl,
+ overhang=ohg,
+ length_includes_head=True,
+ clip_on=False,
+)
+
+fig.savefig(f"{img_path}/laguerre_polynomes.pdf")
diff --git a/buch/papers/laguerre/transformation.tex b/buch/papers/laguerre/transformation.tex
deleted file mode 100644
index 4de86b6..0000000
--- a/buch/papers/laguerre/transformation.tex
+++ /dev/null
@@ -1,31 +0,0 @@
-%
-% transformation.tex
-%
-% (c) 2022 Patrik Müller, Ostschweizer Fachhochschule
-%
-\section{Laguerre Transformation
-\label{laguerre:section:transformation}}
-\begin{align}
- L \left\{ f(x) \right\}
- =
- \tilde{f}_\alpha(n)
- =
- \int_0^\infty e^{-x} x^\alpha L_n^\alpha(x) f(x) dx
- \label{laguerre:transformation}
-\end{align}
-
-\begin{align}
- L^{-1} \left\{ \tilde{f}_\alpha(n) \right\}
- =
- f(x)
- =
- \sum_{n=0}^{\infty}
- \begin{pmatrix}
- n + \alpha \\
- n
- \end{pmatrix}^{-1}
- \frac{1}{\Gamma(\alpha + 1)}
- \tilde{f}_\alpha(n)
- L_n^\alpha(x)
- \label{laguerre:inverse_transformation}
-\end{align} \ No newline at end of file
diff --git a/buch/papers/laguerre/wasserstoff.tex b/buch/papers/laguerre/wasserstoff.tex
deleted file mode 100644
index caaa6af..0000000
--- a/buch/papers/laguerre/wasserstoff.tex
+++ /dev/null
@@ -1,29 +0,0 @@
-%
-% wasserstoff.tex
-%
-% (c) 2022 Patrik Müller, Ostschweizer Fachhochschule
-%
-\section{Radialer Schwingungsanteil eines Wasserstoffatoms
-\label{laguerre:section:radial_h_atom}}
-
-\begin{align}
- \nonumber
- - \frac{\hbar^2}{2m}
- &
- \left(
- \frac{1}{r^2} \pdv{}{r}
- \left( r^2 \pdv{}{r} \right)
- +
- \frac{1}{r^2 \sin \vartheta} \pdv{}{\vartheta}
- \left( \sin \vartheta \pdv{}{\vartheta} \right)
- +
- \frac{1}{r^2 \sin^2 \vartheta} \pdv[2]{}{\varphi}
- \right)
- u(r, \vartheta, \varphi)
- \\
- & -
- \frac{e^2}{4 \pi \epsilon_0 r} u(r, \vartheta, \varphi)
- =
- E u(r, \vartheta, \varphi)
- \label{laguerre:pdg_h_atom}
-\end{align}