JoeJoe1313
commited on
Commit
·
fb1f8cd
1
Parent(s):
5ce16fe
commit from `quarto publish`
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- src/.quarto/_freeze/posts/2025-01-04-fourier-method-fixed-string/index/execute-results/html.json +0 -0
- src/.quarto/_freeze/posts/2025-01-06-chebyshev-polynomials/index/execute-results/html.json +12 -0
- src/.quarto/_freeze/posts/wave-equation/index/execute-results/html.json +12 -0
- src/.quarto/_freeze/site_libs/clipboard/clipboard.min.js +7 -0
- src/.quarto/_freeze/site_libs/quarto-listing/list.min.js +2 -0
- src/.quarto/_freeze/site_libs/quarto-listing/quarto-listing.js +253 -0
- src/.quarto/idx/about.qmd.json +1 -0
- src/.quarto/idx/index.qmd.json +1 -0
- src/.quarto/idx/posts/2025-01-04-fourier-method-fixed-string/index.qmd.json +1 -0
- src/.quarto/idx/posts/2025-01-06-chebyshev-polynomials/index.qmd.json +1 -0
- src/.quarto/idx/posts/fourier/index.qmd.json +1 -0
- src/.quarto/idx/posts/post-with-code/index.qmd.json +1 -0
- src/.quarto/idx/posts/wave-equation/index.qmd.json +1 -0
- src/.quarto/idx/posts/welcome/index.qmd.json +1 -0
- src/.quarto/listing/listing-cache.json +7 -0
- src/.quarto/xref/0dea6315 +1 -0
- src/.quarto/xref/3c315252 +1 -0
- src/.quarto/xref/72c2ebbf +1 -0
- src/.quarto/xref/866fbff8 +1 -0
- src/.quarto/xref/INDEX +26 -0
- src/.quarto/xref/a1690d98 +1 -0
- src/.quarto/xref/a841ef91 +1 -0
- src/.quarto/xref/a98cc6c9 +1 -0
- src/.quarto/xref/ecb70ff4 +1 -0
- src/_freeze/posts/2025-01-04-fourier-method-fixed-string/index/execute-results/html.json +0 -0
- src/_freeze/posts/2025-01-06-chebyshev-polynomials/index/execute-results/html.json +12 -0
- src/_freeze/posts/wave-equation/index/execute-results/html.json +12 -0
- src/_freeze/site_libs/clipboard/clipboard.min.js +7 -0
- src/_freeze/site_libs/quarto-listing/list.min.js +2 -0
- src/_freeze/site_libs/quarto-listing/quarto-listing.js +253 -0
- src/_quarto.yml +15 -31
- src/_site/about.html +559 -0
- src/_site/index.html +707 -0
- src/_site/listings.json +9 -0
- src/_site/posts/2025-01-04-fourier-method-fixed-string/code/fixed_string_animation.html +0 -0
- src/_site/posts/2025-01-04-fourier-method-fixed-string/images/fixed_string.svg +114 -0
- src/_site/posts/2025-01-04-fourier-method-fixed-string/images/harmonics.svg +227 -0
- src/_site/posts/2025-01-04-fourier-method-fixed-string/images/odd_continuation.png +3 -0
- src/_site/posts/2025-01-04-fourier-method-fixed-string/index.html +0 -0
- src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_nodes.png +3 -0
- src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_nodes_visualization.svg +55 -0
- src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_polynomials.png +3 -0
- src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_polynomials_aliasing_even.png +3 -0
- src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_polynomials_aliasing_odd.png +3 -0
- src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_polynomials_stacked.png +3 -0
- src/_site/posts/2025-01-06-chebyshev-polynomials/images/polar_0.png +3 -0
- src/_site/posts/2025-01-06-chebyshev-polynomials/images/polar_1.png +3 -0
- src/_site/posts/2025-01-06-chebyshev-polynomials/images/polar_10.png +3 -0
- src/_site/posts/2025-01-06-chebyshev-polynomials/images/polar_11.png +3 -0
- src/_site/posts/2025-01-06-chebyshev-polynomials/images/polar_2.png +3 -0
src/.quarto/_freeze/posts/2025-01-04-fourier-method-fixed-string/index/execute-results/html.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
src/.quarto/_freeze/posts/2025-01-06-chebyshev-polynomials/index/execute-results/html.json
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"hash": "aa583ba3ab0462ca32f88764351645de",
|
3 |
+
"result": {
|
4 |
+
"engine": "jupyter",
|
5 |
+
"markdown": "---\ntitle: \"Chebyshev Polynomials: Part 1\"\nauthor: \"Joana Levtcheva\"\ndate: \"2025-01-06\"\ncategories: [mathematics, polynomials]\ndraft: false\n---\n\n\n\n\nChebyshev polynomials are a sequence of orthogonal polynomials that play a central role in numerical analysis, approximation theory, and applied mathematics. They are named after the Russian mathematician Pafnuty Chebyshev and come in two primary types: Chebyshev polynomials of the first kind ($T_n(x)$) and Chebyshev polynomials of the second kind ($U_n(x)$). In this post we are going to focus on the Chebyshev polynomials of the first kind.\n\n# Chebyshev Polynomials of the First Kind\n\nThere are many different ways to define the Chebyshev polynomials of the first kind. The one that seems most logical to me and most useful in terms of outlining various properties of the polynomials is\n\n$$\\label{eq:1}\nT_{n}(x) = \\cos{\\left(n \\arccos{x}\\right)}, \\quad x \\in [-1, 1].\\tag{1}\n$$\n\nLooking at \\eqref{eq:1} it is not obvious why $T_{n}(x)$ would be a polynomial. In order to show it is indeed a polynomial let's recall the de Moivre's formula\n\n$$\n\\cos{(n \\theta)} + i\\sin{(n \\theta)} = (\\cos(\\theta) + i \\sin{\\theta})^n.\n$$\n\nWe can apply binomial expansion and take the real part from it to obatin\n\n$$\\label{eq:2}\n\\cos(n \\theta) = \\sum_{k = 0}^{\\frac{n}{2}} C(n, 2k) (-1)^k \\cos^{n - 2k}\\theta \\sin^{2k}{\\theta}. \\tag{2}\n$$\n\nwhere \n\n$$\nC(n, 2k) = \\frac{n!}{(2k)!(n-2k)!}, \\quad n \\geq 2k, k \\in N, n \\in N\n$$ \n\ndenotes the binomal coefficient. We can also notice that\n\n$$\n\\sin^{2k}\\theta = (\\sin^2{\\theta})^k = (1 - \\cos^2{\\theta})^k,\n$$\n\nshowing that \\eqref{eq:2} is a polynomial of $\\cos{\\theta}$ of degree $n$. Now, let\n\n$$\n\\theta = \\arccos{x},\n$$\n\nand by utilising $\\cos{\\left(\\arccos{x}\\right)} = x$ we get\n\n$$\nx = \\cos{\\theta}.\n$$\n\nThis transforms \\eqref{eq:1} to \n\n$$\\label{eq:3}\nT_{n}(\\cos{\\theta}) = \\cos{\\left(n \\theta\\right)} \\tag{3}\n$$\n\nwhich we already showed is a polynomial of degree $n$. From here, because $\\cos(.)$ is an even function, we can note that\n\n$$\nT_{n}(x) = T_{-n}(x) = T_{|n|}(x.)\n$$\n\nFrom \\eqref{eq:3} it is also obvious that the values of $T_n$ in the interval $[-1, 1]$ are bounded in $[-1, 1]$ because of the cosine.\n\n## Chebyshev Nodes of the First Kind\n\nBefore we continue with exploring the roots of the polynomials, let's recall some trigonometry. \n\n---\n\nThe **unit circle** is a circle with a radius of 1, centered at the origin of the Cartesian coordinate system. Below is shown part of the unit circle corresponding to the region from $0$ to $\\frac{\\pi}{2}$.\n\n\n\nThe cosine of an angle $\\theta$ corresponds to the $x$-coordinate of the point where the terminal side of the angle (measured counterclockwise from the positive $x$-axis) intersects the unit circle. In other words, $\\cos(\\theta)$ gives the horizontal distance from the origin to this intersection point. \n\nThe **arccosine** is the inverse function of cosine, and it maps a cosine value back to its corresponding angle in the range $[0, \\pi]$ radians. For a given $x$-coordinate on the unit circle, the arccosine gives the angle $\\theta$ such that $\\cos(\\theta) = x$, meaning\n\n$$\n\\arccos(x) = \\theta, \\quad \\text{where } \\theta \\in [0, \\pi].\n$$\n\nMoreover, a **radian** is defined as the angle subtended at the center of a circle by an arc whose length is equal to the radius of the circle. For any circle, the length of an arc $s$ is given by\n\n$$\ns = r \\cdot \\theta,\n$$\n\nwhere $r$ is the radius of the circle, $\\theta$ is the angle subtended by the arc at the center. This means that on the unit circle the length of the arc equals the measure of the angle in radians because $r = 1$, and hence\n\n$$\ns = \\theta.\n$$\n\n---\n\nNow, let's find the roots of the polynomial $T_{n}(x)$. If we take the definition in \\eqref{eq:1} we have to solve\n\n$$\n\\cos{\\left(n \\arccos{x}\\right)} = 0, k \\in N.\n$$\n\nThe solutions in the interval $(-1, 1)$ are given by\n\n$$\nx_k = \\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n.\n$$\n\nThese roots are known as the **Chebyshev nodes of the first kind**, or the **Chebyshev zeros**. If we are working with an arbitrary interval $(a, b)$ the affine transformation \n\n$$\nx_k = \\frac{a + b}{2} + \\frac{b - a}{2}\\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n\n$$\n\nis needed. From the cosine properties we can also note that the nodes are symmetric with respect to the midpoint of the interval, and that the extrema of $T_n(x)$ over the interval $[-1, 1]$ alternate between $-1$ and $1$. Also, a very useful fact is that these nodes are used in polynomial interpolation to minimize the **Runge phenomenon**.\n\nIn the figure below we have shown the roots of $T_{8}(x)$ in blue. We have also built the perpendiculars from the roots to their interesction with the upper half of the unit circle, and marked these points in red.\n\n{ width=45% }{ width=45% }\n\nLooking at the figure we can notice that the arc lengths between the red points seem to be of the same length. Let's show that this is indeed the truth.\n\nWe showed the roots are the cosine functions $\\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n$. Thus, in the unit circle we have that the length of the corresponding arcs are equal to $\\left( \\frac{2k - 1}{2n}\\pi \\right), n \\in N, k = 1, 2, ...n$. Let's take two red points which are direct neighbours, or in other words let's take two red points corresponding to the randomly chosen $m$ and $m + 1$ roots, $m \\in k = \\{1, 2, ..., n\\}$. If we subtract them we are going to determine the length of the arc between them. We have\n\n$$\n\\frac{2(m + 1) - 1}{2n}\\pi - \\frac{2m - 1}{2n}\\pi = \\frac{\\pi}{n},\n$$\n\nmeaning that between every two nodes the arc length is equal and has a value of $\\frac{\\pi}{n}$. A polynomial of degree $n$ has $n$ roots, which in our case are in the open interval $(-1, 1)$, meaning the arcs corresponding to every two neighbouring roots are $n - 1$, and the two arcs between the $x$-axis and the first and last roots due to the symmetry of roots have lenghts of\n\n$$\n\\frac{1}{2}\\left(\\pi - \\frac{n-1}{n}\\pi\\right) = \\frac{\\pi}{2n}.\n$$\n\n## Recurrence relation\n\nThis is probably a bit out of nowhere, but let's take a look at the following trigonometric identity\n\n$$\\label{eq:4}\n\\cos{\\left((n + 1)\\theta\\right)} + \\cos{\\left((n - 1)\\theta\\right)} = 2 \\cos{(\\theta)} \\cos{(n\\theta)},\\tag{4}\n$$\n\nand show that the left side indeed is equal to the right one. We are going to need the following two fundamental formulas of angle addition in trigonometry\n\n$$\n\\cos{(\\alpha + \\beta)} = \\cos{\\alpha} \\cos{\\beta} - \\sin{\\alpha} \\sin{\\beta},\n$$\n\nand\n\n$$\n\\cos{(\\alpha - \\beta)} = \\cos{\\alpha} \\cos{\\beta} + \\sin{\\alpha} \\sin{\\beta}.\n$$\n\nIn our case we have\n\n$$\n\\cos{\\left((n + 1)\\theta\\right)} = \\cos{\\left(n\\theta + \\theta\\right)} = \\cos{(n\\theta)} \\cos{\\theta} - \\sin{(n\\theta)} \\sin{\\theta},\n$$\n\nand\n\n$$\n\\cos{\\left((n - 1)\\theta\\right)} = \\cos{\\left(n\\theta - \\theta\\right)} = \\cos{(n\\theta)} \\cos{\\theta} + \\sin{(n\\theta)} \\sin{\\theta}.\n$$\n\nAdding the above equations leads to the wanted result.\n\nNow, we can see that the terms of \\eqref{eq:4} are exactly in the form of the right side of \\eqref{eq:1}, \\eqref{eq:3}, hence we get\n\n$$\nT_{n + 1}(x) + T_{n - 1}(x) = 2T_{n}(x)T_{1}(x),\n$$\n\nor we get the useful **recurrence relation**\n\n$$\\label{eq:5}\nT_{n + 1}(x) - 2xT_{n}(x) + T_{n - 1}(x) = 0.\\tag{5}\n$$\n\nThis relation along with adding $T_{0}(x) = 1$ and $T_{1}(x) = x$ is another famous way to define the Chebyshev polynomials of the first kind, or\n\n$$\n\\left\\{\\begin{align*}\nT_{0}(x) = 1, \\\\\nT_{1}(x) = x, \\\\\nT_{n + 1}(x) - 2xT_{n}(x) + T_{n - 1}(x) = 0.\n\\end{align*}\\right.\\label{eq:6}\\tag{6}\n$$\n\nLet's write the first $6$ polynomials by using \\eqref{eq:6}:\n\n$$\n\\left\\{\\begin{align*}\nT_{0}(x) = 1, \\quad \\text{(even)}\\\\\nT_{1}(x) = x, \\quad \\text{(odd)}\\\\\nT_{2}(x) = 2x^2 - 1, \\quad \\text{(even)}\\\\\nT_{3}(x) = 4x^3 - 3x, \\quad \\text{(odd)}\\\\\nT_{4}(x) = 8x^4 - 8x^2 + 1, \\quad \\text{(even)}\\\\\nT_{5}(x) = 16x^5 - 20x^3 + 5x. \\quad \\text{(odd)}\n\\end{align*}\\right.\n$$\n\nWe can notice that\n\n$$\nT_{k}(x) = 2^{k-1}x^k + ...,\n$$\n\nand $T_{k}(x)$ is alternating between an even and an odd polynomial depending on whether $k$ is even or odd respectively.\n\nBefore we continue with some visualisations and more facts, let's mention that an interesting way to represent the recurrence relation \\eqref{eq:5} is via the determinant\n\n$$\nT_{k}(x) = \\det \\begin{bmatrix}\nx & 1 & 0 & \\dots & 0 \\\\\n1 & 2x & 1 & \\ddots & \\vdots \\\\\n0 & 1 & 2x & \\ddots & 0 \\\\\n\\vdots & \\ddots & \\ddots & \\ddots & 1 \\\\\n0 & \\dots & 0 & 1 & 2x\n\\end{bmatrix}.\n$$\n\nNow, let's visualise the first $8$ polynomials.\n\n\n\nBut what can we notice if we stack them together?\n\n\n\nIt is quite obvious that at the roots of the $N$-th Chebyshev polynomial there is an **aliasing** effect, meaning higher order polynomials look like lower order ones. We can formally show it by fixing $N$, at the roots $x_k$ of $T_{N}(x) = 0$, and using the Chebyshev identity\n\n$$\n\\cos{\\left((m + N)\\theta\\right)} + \\cos{\\left((m - N)\\theta\\right)} = 2\\cos{(m\\theta)}\\cos{(N\\theta)},\n$$\n\nor equivalently\n\n$$\nT_{m + N}(x) + T_{m - N}(x) = 2T_{m}(x)T_{N}(x).\n$$\n\nNow, having $T_{N}(x) = 0$ leads to\n\n$$\nT_{m + N}(x) = -T_{m - N}(x).\n$$\n\nIf we consecutevly set $m = N$, $m = 2N$, ..., $m = 6N$, etc. we would get\n\n$$\n\\left\\{\\begin{align*}\nT_{2N}(x_k) = -T_{0}(x_k) = -1, \\\\\nT_{3N}(x_k) = 0, \\\\\nT_{4N}(x_k) = 1, \\\\\nT_{5N}(x_k) = 0, \\\\\nT_{6N}(x_k) = -1, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nWe can safely say that any higher-order Chebyshev polynomial $T_{N}(x)$ can be reduced to a lower-order $j, 0 \\leq j \\leq N$ Chebyshev polynomial at the sample points $x_k$ which are the roots of $T_{N}(x)$. In the figure below we attempt to visualise this statement.\n\n\n\nThe horizontal axis represents the order of Chebyshev polynomials, and the blue wavy line represents a \"folded ribbon\". Think of it as taking the sequence of polynomial orders and folding it back and forth. This folding happens at specific points where higher-order polynomials can be reduced to lower-order ones, which are the red **x** marks showing the sample points: the roots of $T_n(x)$. The key insight is that at these special sample points, we don't need to work with the higher-order polynomials because we can use equivalent lower-order ones instead. This is incredibly useful in numerical computations as it can help reduce computational complexity, and makes the Chebyshev polynomials very computationally efficient.\n\nLet's illustarte this with a simple example. Let $N = 2$, then for even $m$ we have\n\n$$\n\\left\\{\\begin{align*}\nT_{4}(x_k) = -T_{0}(x_k) = -1, \\\\\nT_{6}(x_k) = - T_{2}(x_k) = 0, \\\\\nT_{8}(x_k) = - T_{4}(x_k) = 1, \\\\\nT_{10}(x_k) = -T_{6}(x_k) = 0, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nIn the figure below we can see the even polynomials and that indeed $T_{10}(x)$ behaves like $-T_{6}(x)$ which behaves like $T_{2}(x)$ at the roots having value $0$, $T_{8}(x)$ behaves like $-T_{4}(x)$ at the roots with value $1$ as in $T_{0}(x)$, $T_{6}(x)$ behaves like $-T_{2}(x)$ with value $0$, and $T_{4}(x)$ behaves like $-T_{0}(x)$ with value $-1$.\n\n::: {#be218886 .cell execution_count=1}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nfrom typing import Union\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\ndef chebyshev_polynomial(\n n: int, x: Union[float, np.ndarray]\n) -> Union[float, np.ndarray]:\n \"\"\"\n Calculate nth Chebyshev polynomial of the first kind T_n(x).\n\n Args:\n n: Order of polynomial (non-negative integer)\n x: Point(s) at which to evaluate polynomial\n\n Returns:\n Value of T_n(x)\n \"\"\"\n if n < 0:\n raise ValueError(\"Order must be non-negative\")\n\n if n == 0:\n return np.ones_like(x)\n elif n == 1:\n return x\n else:\n t_prev = np.ones_like(x) # T_0\n t_curr = x # T_1\n\n for _ in range(2, n + 1):\n t_next = 2 * x * t_curr - t_prev\n t_prev = t_curr\n t_curr = t_next\n\n return t_curr\n\n\ndef chebyshev_nodes(n):\n \"\"\"Generate n Chebyshev nodes in [-1,1]\"\"\"\n k = np.arange(1, n + 1)\n return np.cos((2 * k - 1) * np.pi / (2 * n))\n\n\nif __name__ == \"__main__\":\n\n x = np.linspace(-1, 1, 1000)\n plt.figure(figsize=(12, 6))\n plt.plot(x, -chebyshev_polynomial(0, x), \"--\", label=f\"-T_{0}(x)\", alpha=0.5)\n for n in [0, 2, 4, 6, 8, 10]:\n y = chebyshev_polynomial(n, x)\n plt.plot(x, y, label=f\"T_{n}(x)\")\n\n # plot nodes for n = 2\n n = 2\n nodes = chebyshev_nodes(n)\n y_nodes = np.cos(n * np.arccos(nodes))\n plt.plot(nodes, np.zeros_like(nodes), \"bo\", label=\"T_2(x) roots\")\n for node in nodes:\n plt.plot([node, node], [-1, 1], \"--\", color=\"gray\", alpha=0.5)\n\n # plt.grid(True)\n # Set aspect ratio to be equal\n # plt.gca().set_aspect('equal', adjustable='box')\n plt.xlabel(\"x\")\n plt.ylabel(\"T_n(x)\")\n plt.title(\"Chebyshev Polynomials Aliasing\")\n plt.legend(loc=\"center left\", bbox_to_anchor=(1, 0.5), fontsize=8)\n plt.xlim(-1.1, 1.1)\n plt.ylim(-1.1, 1.1)\n plt.axhline(y=0, color=\"k\", linestyle=\"-\", alpha=0.7)\n plt.savefig(\n \"content/images/2025-01-06-chebyshev-polynomials/chebyshev_polynomials_aliasing_even.png\"\n )\n plt.show()\n```\n:::\n\n\n\n\nFor odd $m$ we have\n$$\n\\left\\{\\begin{align*}\nT_{3}(x_k) = - T_{1}(x_k) = - x\\\\\nT_{5}(x_k) = - T_{3}(x_k) = x\\\\\nT_{7}(x_k) = - T_{5}(x_k) = -x, \\\\\nT_{9}(x_k) = - T_{7}(x_k) = x, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nIn the figure below we can see the odd polynomials and the aliasing as in the previous example.\n\n::: {#54809f08 .cell execution_count=2}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nfrom typing import Union\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\ndef chebyshev_polynomial(\n n: int, x: Union[float, np.ndarray]\n) -> Union[float, np.ndarray]:\n \"\"\"\n Calculate nth Chebyshev polynomial of the first kind T_n(x).\n\n Args:\n n: Order of polynomial (non-negative integer)\n x: Point(s) at which to evaluate polynomial\n\n Returns:\n Value of T_n(x)\n \"\"\"\n if n < 0:\n raise ValueError(\"Order must be non-negative\")\n\n if n == 0:\n return np.ones_like(x)\n elif n == 1:\n return x\n else:\n t_prev = np.ones_like(x) # T_0\n t_curr = x # T_1\n\n for _ in range(2, n + 1):\n t_next = 2 * x * t_curr - t_prev\n t_prev = t_curr\n t_curr = t_next\n\n return t_curr\n\n\ndef chebyshev_nodes(n):\n \"\"\"Generate n Chebyshev nodes in [-1,1]\"\"\"\n k = np.arange(1, n + 1)\n return np.cos((2 * k - 1) * np.pi / (2 * n))\n\n\nif __name__ == \"__main__\":\n\n x = np.linspace(-1, 1, 1000)\n plt.figure(figsize=(12, 6))\n plt.plot(x, -chebyshev_polynomial(1, x), \"--\", label=f\"-T_{1}(x)\", alpha=0.5)\n for n in [1, 2, 3, 5, 7, 9]:\n y = chebyshev_polynomial(n, x)\n plt.plot(x, y, label=f\"T_{n}(x)\")\n\n # plot nodes for n = 2\n n = 2\n nodes = chebyshev_nodes(n)\n y_nodes = np.cos(n * np.arccos(nodes))\n plt.plot(nodes, np.zeros_like(nodes), \"bo\", label=\"T_2(x) roots\")\n for node in nodes:\n plt.plot([node, node], [-1, 1], \"--\", color=\"gray\", alpha=0.5)\n\n # plt.grid(True)\n # Set aspect ratio to be equal\n # plt.gca().set_aspect('equal', adjustable='box')\n plt.xlabel(\"x\")\n plt.ylabel(\"T_n(x)\")\n plt.title(\"Chebyshev Polynomials Aliasing\")\n plt.legend(loc=\"center left\", bbox_to_anchor=(1, 0.5), fontsize=8)\n plt.xlim(-1.1, 1.1)\n plt.ylim(-1.1, 1.1)\n plt.axhline(y=0, color=\"k\", linestyle=\"-\", alpha=0.7)\n plt.savefig(\n \"content/images/2025-01-06-chebyshev-polynomials/chebyshev_polynomials_aliasing_odd.png\"\n )\n plt.show()\n```\n:::\n\n\n\n\n## Radial Plots\n\nAn interesting plot can be observed by plotting $T_n(x)$ radially. This means that instead of evaluating the polynomials over $[-1, 1]$ in a Cartesian plane we are evaluating them at $\\frac{\\theta}{\\pi} - 1$, and plotting $r = n + T_n(\\frac{\\theta}{\\pi} - 1)$ on polar axes. In other words, the input domain has been shifted and extended, and the results are drawn as radial distances $r$ around a circle defined by $\\theta$. This creates a polar visualization where each $n$ produces a distinct spiral-like ornament. We are also filling in the areas between the curves for a visual effect.\n\n::: {#b2db675f .cell execution_count=3}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom numpy.polynomial.chebyshev import Chebyshev\n\ntheta = np.linspace(0, 2 * np.pi, 2000)\nfig, ax = plt.subplots(subplot_kw={\"projection\": \"polar\"})\n\n# Generate and fill between consecutive curves\nfor n in range(0, 19 * 2, 2):\n r1 = n + Chebyshev([0] * n + [1])(theta / np.pi - 1)\n r2 = (n + 2) + Chebyshev([0] * (n + 2) + [1])(theta / np.pi - 1)\n\n # Create black and white alternating pattern\n if n % 4 == 0:\n ax.fill_between(theta, r1, r2, color=\"black\")\n else:\n ax.fill_between(theta, r1, r2, color=\"white\")\nax.set_title(\"x = t/π - 1\", y=1)\nplt.axis(\"off\")\nplt.show()\n```\n:::\n\n\n{ width=50% }{ width=41% }\n\nMore visualusations can be achieved by doing other domain changes. They can be seen below.\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\nIn a separate post, Chebyshev Polynomials, Part 2, we are going to explore the Chebyshev polynomials of the second kind, and their relations to the polynomials of the first kind.\n\n",
|
6 |
+
"supporting": [
|
7 |
+
"index_files"
|
8 |
+
],
|
9 |
+
"filters": [],
|
10 |
+
"includes": {}
|
11 |
+
}
|
12 |
+
}
|
src/.quarto/_freeze/posts/wave-equation/index/execute-results/html.json
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"hash": "acdc50e3128605e35f826beed13579e3",
|
3 |
+
"result": {
|
4 |
+
"engine": "jupyter",
|
5 |
+
"markdown": "---\ntitle: \"Wave Equation\"\nauthor: \"JoJo\"\ndate: \"2024-12-19\"\ncategories: [mathematics, python]\nimage: \"./images/rectangular_membrane_1_animation.gif\"\ndraft: true\n---\n\n\n\n\nPartial differential equations...\n\n# Introduction\n\nLet $u(x, y, t)$ be ...\n \nThe homogenous wave equation is given by\n\n$$\n\\frac{\\partial^2 u}{\\partial t^2} - c^2 (\\frac{\\partial^2 u}{\\partial x^2} + \\frac{\\partial^2 u}{\\partial y^2}) = 0\n$$\n\nor\n\n\\begin{equation}\nu_{tt} - c^2 (u_{xx} + u_{yy}) = 0.\n\\end{equation}\n\n# Physical interpretation\n\nThe wave equation is a simplified model for a vibrating\nstring (𝑛 = 1), membrane (𝑛 = 2), or elastic solid (𝑛 = 3). In these\nphysical interpretations 𝑢(𝑥, 𝑡) represents the displacement in some direction\nof the point 𝑥 at time 𝑡 ≥ 0.\n\n1D and 2D Equations\n\n# Rectangular Membrane\n\nPass\n\n$$\nD := \\{0 < x < a, 0 < y < b\\}\n$$\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - c^2 (u_{xx} + u_{yy}) = 0, (x,y,t) \\in G = D \\times (0, +\\infty), \\\\ \nu|_{t=0} = \\varphi(x, y), u_t |_{t=0} = \\psi(x, y), (x, y) \\in \\bar{D}, \\\\\nu|_{\\partial D} = 0, t \\geq 0.\n\\end{align*}\\right.\n$$\n\n...\n\n$$\n\\varphi(x, y) \\in C^3 (\\bar{D}), \\psi(x, y) \\in C^2 (\\bar{D})\n$$\n\nand ...\n\n$$\n\\varphi |_{\\partial D} = \\varphi_{xx} |_{x = 0} = \\varphi_{xx} |_{x = a} = \\varphi_{yy} |_{y =0} = \\varphi_{yy} |_{y = b} = \\psi |_{\\partial D} = 0.\n$$\n\nSolution... :\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} ct} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} ct} \\right) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = \\left(\\frac{\\pi n}{a} \\right)^2 + \\left(\\frac{\\pi m}{b} \\right)^2.\n$$\n\nFrom the initial conditions it follows\n\n$$\nA_{n, m} = \\frac{4}{ab} \\int_D \\varphi(x, y) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y \\mathrm{d}x \\mathrm{d}y,\n$$\n\nand\n\n$$\nB_{n, m} = \\frac{4}{abc\\sqrt{\\lambda_{n, m}}} \\int_D \\psi(x, y) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y \\mathrm{d}x \\mathrm{d}y.\n$$\n\n## Example 1\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - u_{xx} - u_{yy} = 0, 0 < x < \\pi, 0 < y < \\pi, t > 0, \\\\\nu|_{t=0} = \\sin{x} \\sin{y}, u_t |_{t=0} = \\sin{4x} \\sin{3y}, x, y \\in (0, \\pi), \\\\\nu|_{x = 0} = 0, u|_{x = \\pi} = 0, 0 < y < \\pi, t > 0, \\\\\nu|_{y = 0} = 0, u|_{y = \\pi} = 0, 0 < x < \\pi, t > 0.\n\\end{align*}\\right.\n$$\n\nSolution:\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} t} \\right) \\sin{n} x \\sin{m} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = n^2 + m^2,\n$$\n\n$$\nA_{n, m} = \\frac{4}{\\pi^2} \\int_0^\\pi \\sin{x} \\sin{nx} \\mathrm{d}x \\int_0^\\pi \\sin{y} \\sin{my} \\mathrm{d}y,\n$$\n\n$$\nB_{n, m} = \\frac{4}{\\pi^2\\sqrt{\\lambda_{n, m}}} \\int_0^\\pi \\sin{4x} \\sin{nx} \\mathrm{d}x \\int_0^\\pi \\sin{3y} \\sin{my} \\mathrm{d}y.\n$$\n\nTherefore, $A_{1, 1} = 1$, $B_{4, 3} = \\frac{1}{5}$, and every other coefficients is equal to $0$. Finally, \n\n$$\nu(x, y, t) = \\cos{\\sqrt{2}t} \\sin{x} \\sin{y} + \\frac{1}{5} \\sin{5t} \\sin{4x} \\sin{3y}.\n$$\n\nFor $t \\in [0, 6]$:\n\nAnimation:\n\n\n\n::: {#596976bd .cell execution_count=1}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.animation import FuncAnimation\n\n\ndef rectangular_membrane_1(t_max: int = 6):\n t = np.linspace(0, t_max, 100) # Time points for animation\n x = np.linspace(0, np.pi, 51) # x grid\n y = np.linspace(0, np.pi, 51) # y grid\n X, Y = np.meshgrid(x, y)\n\n # Define the solution function\n def solution(x, y, t):\n return (\n np.cos(np.sqrt(2) * t) * np.sin(x) * np.sin(y)\n + np.sin(5 * t) * np.sin(4 * x) * np.sin(3 * y) / 5\n )\n\n # Set up the figure and axis for animation\n fig = plt.figure()\n ax = fig.add_subplot(111, projection=\"3d\")\n ax.set_xlim(0, np.pi)\n ax.set_ylim(0, np.pi)\n ax.set_zlim(-1, 1)\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n ax.set_title(\"Rectangular Membrane\")\n\n # Update function for FuncAnimation\n def update(frame):\n ax.clear() # Clear the previous frame\n Z = solution(X, Y, frame) # Compute the new Z values\n _ = ax.plot_surface(X, Y, Z, cmap=\"viridis\", vmin=-1, vmax=1)\n ax.set_xlim(0, np.pi)\n ax.set_ylim(0, np.pi)\n ax.set_zlim(-1, 1)\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n ax.set_title(\"Rectangular Membrane\")\n\n # Create and save the animation\n anim = FuncAnimation(fig, update, frames=t, interval=50)\n anim.save(\"rectangular_membrane_1_animation.gif\", writer=\"imagemagick\", fps=20)\n\n plt.show()\n```\n:::\n\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n## Example 2\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - \\pi^2 (u_{xx} + u_{yy}) = 0, 0 < x < 1, 0 < y < 2, t > 0, \\\\\nu|_{t=0} = \\cos{\\left(\\left(x + \\frac{1}{2}\\right)\\pi\\right)} \\cos{\\left(\\frac{\\pi}{2}\\left(y + 1\\right)\\right)}, u_t |_{t=0} = 0, 0 \\leq x \\leq 1, 0 \\leq y \\leq 2, \\\\\nu|_{x = 0} = 0, u|_{x = 1} = 0, 0 \\leq y < 2, t \\geq 0, \\\\\nu|_{y = 0} = 0, u|_{y = 2} = 0, 0 \\leq x \\leq 1, t \\geq 0.\n\\end{align*}\\right.\n$$\n\nSolution with Fourier method:\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} t} \\right) \\sin{\\pi n} x \\sin{\\pi m} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = \\pi^2 (n^2 + m^2)\n$$\n\nand\n\n$$\nB_{n, m} = 0.\n$$\n\n$$\nA_{n, m} = 2 \\int_{0}^{1} \\cos{\\left(\\left(x + \\frac{1}{2}\\right)\\pi\\right)} \\sin{\\pi nx} \\mathrm{d}x \\int_0^2 \\cos{\\left(\\frac{\\pi}{2}\\left(y + 1\\right)\\right)} \\sin{\\pi my} \\mathrm{d}y.\n$$\n\nVisualising the solution for $t \\in [0, 6]$ with the partial sum\n\n$$\n\\tilde{u}(x, y, t) = \\sum_{n, m = 1}^{30} A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} \\sin{\\pi n} x \\sin{\\pi m} y.\n$$\n\nAnimation:\n\n\n\n::: {#f1605c55 .cell execution_count=2}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.animation import FuncAnimation\n\n\ndef rectangular_membrane_2(a: float = 1, b: float = 2, c: float = np.pi, tmax: int = 6):\n t = np.linspace(0, tmax, 100) # Time points for animation\n x = np.linspace(0, a, 50) # x grid\n y = np.linspace(0, b, 50) # y grid\n X, Y = np.meshgrid(x, y)\n\n # Define the solution function\n def solution(x, y, t):\n z = 0\n for n in range(1, 31):\n for m in range(1, 31):\n lambda_nm = np.pi**2 * (n**2 / a**2 + m**2 / b**2)\n # Compute the coefficient Anm\n xx = np.linspace(0, a, 100)\n yy = np.linspace(0, b, 100)\n Anm = (\n 4\n * np.trapezoid(\n np.cos(np.pi / 2 + np.pi * xx / a) * np.sin(n * np.pi * xx / a),\n xx,\n )\n * np.trapezoid(\n np.cos(np.pi / 2 + np.pi * yy / b) * np.sin(m * np.pi * yy / b),\n yy,\n )\n / (a * b)\n )\n z += (\n Anm\n * np.cos(c * np.sqrt(lambda_nm) * t)\n * np.sin(n * np.pi * x / a)\n * np.sin(m * np.pi * y / b)\n )\n return z\n\n # Set up the figure and axis for animation\n fig = plt.figure()\n ax = fig.add_subplot(111, projection=\"3d\")\n ax.set_xlim(0, a)\n ax.set_ylim(0, b)\n ax.set_zlim(-1, 1)\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n ax.set_title(\"Rectangular Membrane\")\n\n # Update function for FuncAnimation\n def update(frame):\n ax.clear()\n Z = solution(X, Y, frame) # Compute the new Z values\n ax.plot_surface(X, Y, Z, cmap=\"viridis\", vmin=-1, vmax=1)\n ax.set_xlim(0, a)\n ax.set_ylim(0, b)\n ax.set_zlim(-1, 1)\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n ax.set_title(\"Rectangular Membrane\")\n\n # Create and save the animation\n anim = FuncAnimation(fig, update, frames=t, interval=50)\n anim.save(\"rectangular_membrane_2_animation.gif\", writer=\"imagemagick\", fps=20)\n\n plt.show()\n```\n:::\n\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n# Circular Membrane\n\nPass\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - \\frac{1}{4} (u_{xx} + u_{yy}) = 0, x^2 + y^2 < 9, t > 0, \\\\ \nu|_{t=0} = (x^2 + y^2) \\sin^3(\\pi \\sqrt{x^2 + y^2}), u_t |_{t=0} = 0, x^2 + y^2 \\leq 9, \\\\\nu|_{x^2 + y^2 = 9} = 0, t \\geq 0.\n\\end{align*}\\right.\n$$\n\nFourier method: Change to polar coordinates\n\n$$\n\\left\\{\\begin{align*}\nx = \\rho \\cos(\\varphi), \\\\\ny = \\rho \\sin(\\varphi)\n\\end{align*}\\right.\n$$\n\n...\n\nThen the function in the first initial condition $u |_{t=0}$ becomes\n\n$$\n\\tau(\\rho) = \\rho^2 \\sin^3(\\pi \\rho)\n$$\n\nwhich is radially symmetric and hence the solution will be also radially symmetric. It is given by\n\n$$\nu(\\rho, t) = \\sum_{m=1}^{\\infty} A_m \\cos{\\frac{a \\mu_m^{(0)}t}{r}} J_0\\left(\\frac{\\mu_m^{(0)}}{r}\\rho\\right),\n$$\n\nwhere\n\n$$\nA_m = \\frac{4}{r^2 J_1^2(\\mu_m^{(0)})} \\int_0^r \\rho^3 \\sin^3(\\pi \\rho) J_0\\left(\\frac{\\mu_m^{(0)}}{r}\\rho\\right) d\\rho,\n$$\n\nand $\\mu_m^{(0)}$ are the positive solutions to $J_0(\\mu) = 0$.\n\n...\n\n\n\n...\n\nAnimation:\n\n\n\n::: {#d8e21121 .cell execution_count=3}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.animation import FuncAnimation\nfrom scipy.optimize import root_scalar\nfrom scipy.special import jv as besselj\n\n\ndef CircularMembrane(a=0.5, r=3, tmax=30, N=40):\n rho = np.linspace(0, r, 51) # Radial grid points\n phi = np.linspace(0, 2 * np.pi, 51) # Angular grid points\n t = np.linspace(0, tmax, 100) # Time steps\n\n # Find the first 40 positive zeros of the Bessel function J0\n mju = []\n for n in range(1, N + 1):\n zero = root_scalar(\n lambda x: besselj(0, x), bracket=[(n - 1) * np.pi, n * np.pi]\n )\n mju.append(zero.root)\n mju = np.array(mju)\n\n # Define the initial position function\n def tau(rho):\n return rho**2 * np.sin(np.pi * rho) ** 3\n\n # Compute the solution for given R and t\n def solution(R, t):\n y = np.zeros_like(R)\n for m in range(N):\n s = tau(R[0, :]) * R[0, :] * besselj(0, mju[m] * R[0, :] / r)\n A0m = 4 * np.trapezoid(s, R[0, :]) / ((r**2) * (besselj(1, mju[m]) ** 2))\n y += A0m * np.cos(a * mju[m] * t / r) * besselj(0, mju[m] * R / r)\n return y\n\n # Create a grid of points\n R, p = np.meshgrid(rho, phi)\n X = R * np.cos(p)\n Y = R * np.sin(p)\n\n # Set up the figure and axis for animation\n fig = plt.figure()\n ax = fig.add_subplot(111, projection=\"3d\")\n ax.set_xlim(-r, r)\n ax.set_ylim(-r, r)\n ax.set_zlim(-30, 30)\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n ax.set_title(\"Circular Membrane\")\n\n # Update function for animation\n def update(frame):\n ax.clear()\n Z = solution(R, frame)\n ax.plot_surface(X, Y, Z, cmap=\"viridis\", vmin=-30, vmax=30)\n ax.set_xlim(-r, r)\n ax.set_ylim(-r, r)\n ax.set_zlim(-30, 30)\n ax.set_title(\"Circular Membrane\")\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n\n # Create and save the animation\n anim = FuncAnimation(fig, update, frames=t, interval=50)\n anim.save(\"circular_membrane_animation.gif\", writer=\"imagemagick\", fps=20)\n\n plt.show()\n```\n:::\n\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n# References\n\n- [1](https://www.amazon.co.uk/Partial-Differential-Equations-Graduate-Mathematics/dp/1470469421/ref=sr_1_3?crid=2BINQDJ5R7XUB&dib=eyJ2IjoiMSJ9.GgU4uQBUKYO960lL6EjVJjksjFysLhCJKEHP436_saFGnfKf4uvgqyl_3WBjV779K4AwonOY5XnkRxVFCIqqGZCCE3I8YEjIC7mzvLwUa2lBPvByBCoFxTvGhrSKGLiAKlAvTVFSlbwklqyWEj4o852csy80_D3G2Gk9pedHKz22vqyc8UI8HAxWZ1wfu5bNoaqOOEDhy0W2XLaSijLCENnzVXjxTLS5xZkMCXr72G0.NeT6LdhY-WV9xVA26fbGHp37FbAKGo7mLwpV9m_2Rdk&dib_tag=se&keywords=partial+differential+equations&nsdOptOutParam=true&qid=1734133658&sprefix=partial+diff%2Caps%2C129&sr=8-3)\n- [2](https://mathworld.wolfram.com/BesselFunctionoftheFirstKind.html)\n\n",
|
6 |
+
"supporting": [
|
7 |
+
"index_files"
|
8 |
+
],
|
9 |
+
"filters": [],
|
10 |
+
"includes": {}
|
11 |
+
}
|
12 |
+
}
|
src/.quarto/_freeze/site_libs/clipboard/clipboard.min.js
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
* clipboard.js v2.0.11
|
3 |
+
* https://clipboardjs.com/
|
4 |
+
*
|
5 |
+
* Licensed MIT © Zeno Rocha
|
6 |
+
*/
|
7 |
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body},n="";return"string"==typeof t?n=o(t,e):t instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(null==t?void 0:t.type)?n=o(t.value,e):(n=r()(t),c("copy")),n};function l(t){return(l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var s=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},e=t.action,n=void 0===e?"copy":e,o=t.container,e=t.target,t=t.text;if("copy"!==n&&"cut"!==n)throw new Error('Invalid "action" value, use either "copy" or "cut"');if(void 0!==e){if(!e||"object"!==l(e)||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===n&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===n&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes')}return t?f(t,{container:o}):e?"cut"===n?a(e):f(e,{container:o}):void 0};function p(t){return(p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function d(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function y(t,e){return(y=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function h(n){var o=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(t){return!1}}();return function(){var t,e=v(n);return t=o?(t=v(this).constructor,Reflect.construct(e,arguments,t)):e.apply(this,arguments),e=this,!(t=t)||"object"!==p(t)&&"function"!=typeof t?function(t){if(void 0!==t)return t;throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}(e):t}}function v(t){return(v=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function m(t,e){t="data-clipboard-".concat(t);if(e.hasAttribute(t))return e.getAttribute(t)}var b=function(){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&y(t,e)}(r,i());var t,e,n,o=h(r);function r(t,e){var n;return function(t){if(!(t instanceof r))throw new TypeError("Cannot call a class as a function")}(this),(n=o.call(this)).resolveOptions(e),n.listenClick(t),n}return t=r,n=[{key:"copy",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body};return f(t,e)}},{key:"cut",value:function(t){return a(t)}},{key:"isSupported",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof t?[t]:t,e=!!document.queryCommandSupported;return t.forEach(function(t){e=e&&!!document.queryCommandSupported(t)}),e}}],(e=[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===p(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=u()(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget,n=this.action(e)||"copy",t=s({action:n,container:this.container,target:this.target(e),text:this.text(e)});this.emit(t?"success":"error",{action:n,text:t,trigger:e,clearSelection:function(){e&&e.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(t){return m("action",t)}},{key:"defaultTarget",value:function(t){t=m("target",t);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(t){return m("text",t)}},{key:"destroy",value:function(){this.listener.destroy()}}])&&d(t.prototype,e),n&&d(t,n),r}()},828:function(t){var e;"undefined"==typeof Element||Element.prototype.matches||((e=Element.prototype).matches=e.matchesSelector||e.mozMatchesSelector||e.msMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector),t.exports=function(t,e){for(;t&&9!==t.nodeType;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}},438:function(t,e,n){var u=n(828);function i(t,e,n,o,r){var i=function(e,n,t,o){return function(t){t.delegateTarget=u(t.target,n),t.delegateTarget&&o.call(e,t)}}.apply(this,arguments);return t.addEventListener(n,i,r),{destroy:function(){t.removeEventListener(n,i,r)}}}t.exports=function(t,e,n,o,r){return"function"==typeof t.addEventListener?i.apply(null,arguments):"function"==typeof n?i.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return i(t,e,n,o,r)}))}},879:function(t,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},370:function(t,e,n){var f=n(879),l=n(438);t.exports=function(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!f.string(e))throw new TypeError("Second argument must be a String");if(!f.fn(n))throw new TypeError("Third argument must be a Function");if(f.node(t))return c=e,a=n,(u=t).addEventListener(c,a),{destroy:function(){u.removeEventListener(c,a)}};if(f.nodeList(t))return o=t,r=e,i=n,Array.prototype.forEach.call(o,function(t){t.addEventListener(r,i)}),{destroy:function(){Array.prototype.forEach.call(o,function(t){t.removeEventListener(r,i)})}};if(f.string(t))return t=t,e=e,n=n,l(document.body,t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");var o,r,i,u,c,a}},817:function(t){t.exports=function(t){var e,n="SELECT"===t.nodeName?(t.focus(),t.value):"INPUT"===t.nodeName||"TEXTAREA"===t.nodeName?((e=t.hasAttribute("readonly"))||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),e||t.removeAttribute("readonly"),t.value):(t.hasAttribute("contenteditable")&&t.focus(),n=window.getSelection(),(e=document.createRange()).selectNodeContents(t),n.removeAllRanges(),n.addRange(e),n.toString());return n}},279:function(t){function e(){}e.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var o=this;function r(){o.off(t,r),e.apply(n,arguments)}return r._=e,this.on(t,r,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;o<r;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],r=[];if(o&&e)for(var i=0,u=o.length;i<u;i++)o[i].fn!==e&&o[i].fn._!==e&&r.push(o[i]);return r.length?n[t]=r:delete n[t],this}},t.exports=e,t.exports.TinyEmitter=e}},r={},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,{a:e}),e},o.d=function(t,e){for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o(686).default;function o(t){if(r[t])return r[t].exports;var e=r[t]={exports:{}};return n[t](e,e.exports,o),e.exports}var n,r});
|
src/.quarto/_freeze/site_libs/quarto-listing/list.min.js
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
var List;List=function(){var t={"./src/add-async.js":function(t){t.exports=function(t){return function e(r,n,s){var i=r.splice(0,50);s=(s=s||[]).concat(t.add(i)),r.length>0?setTimeout((function(){e(r,n,s)}),1):(t.update(),n(s))}}},"./src/filter.js":function(t){t.exports=function(t){return t.handlers.filterStart=t.handlers.filterStart||[],t.handlers.filterComplete=t.handlers.filterComplete||[],function(e){if(t.trigger("filterStart"),t.i=1,t.reset.filter(),void 0===e)t.filtered=!1;else{t.filtered=!0;for(var r=t.items,n=0,s=r.length;n<s;n++){var i=r[n];e(i)?i.filtered=!0:i.filtered=!1}}return t.update(),t.trigger("filterComplete"),t.visibleItems}}},"./src/fuzzy-search.js":function(t,e,r){r("./src/utils/classes.js");var n=r("./src/utils/events.js"),s=r("./src/utils/extend.js"),i=r("./src/utils/to-string.js"),a=r("./src/utils/get-by-class.js"),o=r("./src/utils/fuzzy.js");t.exports=function(t,e){e=s({location:0,distance:100,threshold:.4,multiSearch:!0,searchClass:"fuzzy-search"},e=e||{});var r={search:function(n,s){for(var i=e.multiSearch?n.replace(/ +$/,"").split(/ +/):[n],a=0,o=t.items.length;a<o;a++)r.item(t.items[a],s,i)},item:function(t,e,n){for(var s=!0,i=0;i<n.length;i++){for(var a=!1,o=0,l=e.length;o<l;o++)r.values(t.values(),e[o],n[i])&&(a=!0);a||(s=!1)}t.found=s},values:function(t,r,n){if(t.hasOwnProperty(r)){var s=i(t[r]).toLowerCase();if(o(s,n,e))return!0}return!1}};return n.bind(a(t.listContainer,e.searchClass),"keyup",t.utils.events.debounce((function(e){var n=e.target||e.srcElement;t.search(n.value,r.search)}),t.searchDelay)),function(e,n){t.search(e,n,r.search)}}},"./src/index.js":function(t,e,r){var n=r("./node_modules/string-natural-compare/natural-compare.js"),s=r("./src/utils/get-by-class.js"),i=r("./src/utils/extend.js"),a=r("./src/utils/index-of.js"),o=r("./src/utils/events.js"),l=r("./src/utils/to-string.js"),u=r("./src/utils/classes.js"),c=r("./src/utils/get-attribute.js"),f=r("./src/utils/to-array.js");t.exports=function(t,e,h){var d,v=this,g=r("./src/item.js")(v),m=r("./src/add-async.js")(v),p=r("./src/pagination.js")(v);d={start:function(){v.listClass="list",v.searchClass="search",v.sortClass="sort",v.page=1e4,v.i=1,v.items=[],v.visibleItems=[],v.matchingItems=[],v.searched=!1,v.filtered=!1,v.searchColumns=void 0,v.searchDelay=0,v.handlers={updated:[]},v.valueNames=[],v.utils={getByClass:s,extend:i,indexOf:a,events:o,toString:l,naturalSort:n,classes:u,getAttribute:c,toArray:f},v.utils.extend(v,e),v.listContainer="string"==typeof t?document.getElementById(t):t,v.listContainer&&(v.list=s(v.listContainer,v.listClass,!0),v.parse=r("./src/parse.js")(v),v.templater=r("./src/templater.js")(v),v.search=r("./src/search.js")(v),v.filter=r("./src/filter.js")(v),v.sort=r("./src/sort.js")(v),v.fuzzySearch=r("./src/fuzzy-search.js")(v,e.fuzzySearch),this.handlers(),this.items(),this.pagination(),v.update())},handlers:function(){for(var t in v.handlers)v[t]&&v.handlers.hasOwnProperty(t)&&v.on(t,v[t])},items:function(){v.parse(v.list),void 0!==h&&v.add(h)},pagination:function(){if(void 0!==e.pagination){!0===e.pagination&&(e.pagination=[{}]),void 0===e.pagination[0]&&(e.pagination=[e.pagination]);for(var t=0,r=e.pagination.length;t<r;t++)p(e.pagination[t])}}},this.reIndex=function(){v.items=[],v.visibleItems=[],v.matchingItems=[],v.searched=!1,v.filtered=!1,v.parse(v.list)},this.toJSON=function(){for(var t=[],e=0,r=v.items.length;e<r;e++)t.push(v.items[e].values());return t},this.add=function(t,e){if(0!==t.length){if(!e){var r=[],n=!1;void 0===t[0]&&(t=[t]);for(var s=0,i=t.length;s<i;s++){var a;n=v.items.length>v.page,a=new g(t[s],void 0,n),v.items.push(a),r.push(a)}return v.update(),r}m(t.slice(0),e)}},this.show=function(t,e){return this.i=t,this.page=e,v.update(),v},this.remove=function(t,e,r){for(var n=0,s=0,i=v.items.length;s<i;s++)v.items[s].values()[t]==e&&(v.templater.remove(v.items[s],r),v.items.splice(s,1),i--,s--,n++);return v.update(),n},this.get=function(t,e){for(var r=[],n=0,s=v.items.length;n<s;n++){var i=v.items[n];i.values()[t]==e&&r.push(i)}return r},this.size=function(){return v.items.length},this.clear=function(){return v.templater.clear(),v.items=[],v},this.on=function(t,e){return v.handlers[t].push(e),v},this.off=function(t,e){var r=v.handlers[t],n=a(r,e);return n>-1&&r.splice(n,1),v},this.trigger=function(t){for(var e=v.handlers[t].length;e--;)v.handlers[t][e](v);return v},this.reset={filter:function(){for(var t=v.items,e=t.length;e--;)t[e].filtered=!1;return v},search:function(){for(var t=v.items,e=t.length;e--;)t[e].found=!1;return v}},this.update=function(){var t=v.items,e=t.length;v.visibleItems=[],v.matchingItems=[],v.templater.clear();for(var r=0;r<e;r++)t[r].matching()&&v.matchingItems.length+1>=v.i&&v.visibleItems.length<v.page?(t[r].show(),v.visibleItems.push(t[r]),v.matchingItems.push(t[r])):t[r].matching()?(v.matchingItems.push(t[r]),t[r].hide()):t[r].hide();return v.trigger("updated"),v},d.start()}},"./src/item.js":function(t){t.exports=function(t){return function(e,r,n){var s=this;this._values={},this.found=!1,this.filtered=!1;this.values=function(e,r){if(void 0===e)return s._values;for(var n in e)s._values[n]=e[n];!0!==r&&t.templater.set(s,s.values())},this.show=function(){t.templater.show(s)},this.hide=function(){t.templater.hide(s)},this.matching=function(){return t.filtered&&t.searched&&s.found&&s.filtered||t.filtered&&!t.searched&&s.filtered||!t.filtered&&t.searched&&s.found||!t.filtered&&!t.searched},this.visible=function(){return!(!s.elm||s.elm.parentNode!=t.list)},function(e,r,n){if(void 0===r)n?s.values(e,n):s.values(e);else{s.elm=r;var i=t.templater.get(s,e);s.values(i)}}(e,r,n)}}},"./src/pagination.js":function(t,e,r){var n=r("./src/utils/classes.js"),s=r("./src/utils/events.js"),i=r("./src/index.js");t.exports=function(t){var e=!1,r=function(r,s){if(t.page<1)return t.listContainer.style.display="none",void(e=!0);e&&(t.listContainer.style.display="block");var i,o=t.matchingItems.length,l=t.i,u=t.page,c=Math.ceil(o/u),f=Math.ceil(l/u),h=s.innerWindow||2,d=s.left||s.outerWindow||0,v=s.right||s.outerWindow||0;v=c-v,r.clear();for(var g=1;g<=c;g++){var m=f===g?"active":"";a.number(g,d,v,f,h)?(i=r.add({page:g,dotted:!1})[0],m&&n(i.elm).add(m),i.elm.firstChild.setAttribute("data-i",g),i.elm.firstChild.setAttribute("data-page",u)):a.dotted(r,g,d,v,f,h,r.size())&&(i=r.add({page:"...",dotted:!0})[0],n(i.elm).add("disabled"))}},a={number:function(t,e,r,n,s){return this.left(t,e)||this.right(t,r)||this.innerWindow(t,n,s)},left:function(t,e){return t<=e},right:function(t,e){return t>e},innerWindow:function(t,e,r){return t>=e-r&&t<=e+r},dotted:function(t,e,r,n,s,i,a){return this.dottedLeft(t,e,r,n,s,i)||this.dottedRight(t,e,r,n,s,i,a)},dottedLeft:function(t,e,r,n,s,i){return e==r+1&&!this.innerWindow(e,s,i)&&!this.right(e,n)},dottedRight:function(t,e,r,n,s,i,a){return!t.items[a-1].values().dotted&&(e==n&&!this.innerWindow(e,s,i)&&!this.right(e,n))}};return function(e){var n=new i(t.listContainer.id,{listClass:e.paginationClass||"pagination",item:e.item||"<li><a class='page' href='#'></a></li>",valueNames:["page","dotted"],searchClass:"pagination-search-that-is-not-supposed-to-exist",sortClass:"pagination-sort-that-is-not-supposed-to-exist"});s.bind(n.listContainer,"click",(function(e){var r=e.target||e.srcElement,n=t.utils.getAttribute(r,"data-page"),s=t.utils.getAttribute(r,"data-i");s&&t.show((s-1)*n+1,n)})),t.on("updated",(function(){r(n,e)})),r(n,e)}}},"./src/parse.js":function(t,e,r){t.exports=function(t){var e=r("./src/item.js")(t),n=function(r,n){for(var s=0,i=r.length;s<i;s++)t.items.push(new e(n,r[s]))},s=function e(r,s){var i=r.splice(0,50);n(i,s),r.length>0?setTimeout((function(){e(r,s)}),1):(t.update(),t.trigger("parseComplete"))};return t.handlers.parseComplete=t.handlers.parseComplete||[],function(){var e=function(t){for(var e=t.childNodes,r=[],n=0,s=e.length;n<s;n++)void 0===e[n].data&&r.push(e[n]);return r}(t.list),r=t.valueNames;t.indexAsync?s(e,r):n(e,r)}}},"./src/search.js":function(t){t.exports=function(t){var e,r,n,s={resetList:function(){t.i=1,t.templater.clear(),n=void 0},setOptions:function(t){2==t.length&&t[1]instanceof Array?e=t[1]:2==t.length&&"function"==typeof t[1]?(e=void 0,n=t[1]):3==t.length?(e=t[1],n=t[2]):e=void 0},setColumns:function(){0!==t.items.length&&void 0===e&&(e=void 0===t.searchColumns?s.toArray(t.items[0].values()):t.searchColumns)},setSearchString:function(e){e=(e=t.utils.toString(e).toLowerCase()),r=e},toArray:function(t){var e=[];for(var r in t)e.push(r);return e}},i=function(){for(var n,s=[],i=r;null!==(n=i.match(/"([^"]+)"/));)s.push(n[1]),i=i.substring(0,n.index)+i.substring(n.index+n[0].length);(i=i.trim()).length&&(s=s.concat(i.split(/\s+/)));for(var a=0,o=t.items.length;a<o;a++){var l=t.items[a];if(l.found=!1,s.length){for(var u=0,c=s.length;u<c;u++){for(var f=!1,h=0,d=e.length;h<d;h++){var v=l.values(),g=e[h];if(v.hasOwnProperty(g)&&void 0!==v[g]&&null!==v[g])if(-1!==("string"!=typeof v[g]?v[g].toString():v[g]).toLowerCase().indexOf(s[u])){f=!0;break}}if(!f)break}l.found=f}}},a=function(){t.reset.search(),t.searched=!1},o=function(o){return t.trigger("searchStart"),s.resetList(),s.setSearchString(o),s.setOptions(arguments),s.setColumns(),""===r?a():(t.searched=!0,n?n(r,e):i()),t.update(),t.trigger("searchComplete"),t.visibleItems};return t.handlers.searchStart=t.handlers.searchStart||[],t.handlers.searchComplete=t.handlers.searchComplete||[],t.utils.events.bind(t.utils.getByClass(t.listContainer,t.searchClass),"keyup",t.utils.events.debounce((function(e){var r=e.target||e.srcElement;""===r.value&&!t.searched||o(r.value)}),t.searchDelay)),t.utils.events.bind(t.utils.getByClass(t.listContainer,t.searchClass),"input",(function(t){""===(t.target||t.srcElement).value&&o("")})),o}},"./src/sort.js":function(t){t.exports=function(t){var e={els:void 0,clear:function(){for(var r=0,n=e.els.length;r<n;r++)t.utils.classes(e.els[r]).remove("asc"),t.utils.classes(e.els[r]).remove("desc")},getOrder:function(e){var r=t.utils.getAttribute(e,"data-order");return"asc"==r||"desc"==r?r:t.utils.classes(e).has("desc")?"asc":t.utils.classes(e).has("asc")?"desc":"asc"},getInSensitive:function(e,r){var n=t.utils.getAttribute(e,"data-insensitive");r.insensitive="false"!==n},setOrder:function(r){for(var n=0,s=e.els.length;n<s;n++){var i=e.els[n];if(t.utils.getAttribute(i,"data-sort")===r.valueName){var a=t.utils.getAttribute(i,"data-order");"asc"==a||"desc"==a?a==r.order&&t.utils.classes(i).add(r.order):t.utils.classes(i).add(r.order)}}}},r=function(){t.trigger("sortStart");var r={},n=arguments[0].currentTarget||arguments[0].srcElement||void 0;n?(r.valueName=t.utils.getAttribute(n,"data-sort"),e.getInSensitive(n,r),r.order=e.getOrder(n)):((r=arguments[1]||r).valueName=arguments[0],r.order=r.order||"asc",r.insensitive=void 0===r.insensitive||r.insensitive),e.clear(),e.setOrder(r);var s,i=r.sortFunction||t.sortFunction||null,a="desc"===r.order?-1:1;s=i?function(t,e){return i(t,e,r)*a}:function(e,n){var s=t.utils.naturalSort;return s.alphabet=t.alphabet||r.alphabet||void 0,!s.alphabet&&r.insensitive&&(s=t.utils.naturalSort.caseInsensitive),s(e.values()[r.valueName],n.values()[r.valueName])*a},t.items.sort(s),t.update(),t.trigger("sortComplete")};return t.handlers.sortStart=t.handlers.sortStart||[],t.handlers.sortComplete=t.handlers.sortComplete||[],e.els=t.utils.getByClass(t.listContainer,t.sortClass),t.utils.events.bind(e.els,"click",r),t.on("searchStart",e.clear),t.on("filterStart",e.clear),r}},"./src/templater.js":function(t){var e=function(t){var e,r=this,n=function(e,r){var n=e.cloneNode(!0);n.removeAttribute("id");for(var s=0,i=r.length;s<i;s++){var a=void 0,o=r[s];if(o.data)for(var l=0,u=o.data.length;l<u;l++)n.setAttribute("data-"+o.data[l],"");else o.attr&&o.name?(a=t.utils.getByClass(n,o.name,!0))&&a.setAttribute(o.attr,""):(a=t.utils.getByClass(n,o,!0))&&(a.innerHTML="")}return n},s=function(){for(var e=t.list.childNodes,r=0,n=e.length;r<n;r++)if(void 0===e[r].data)return e[r].cloneNode(!0)},i=function(t){if("string"==typeof t){if(/<tr[\s>]/g.exec(t)){var e=document.createElement("tbody");return e.innerHTML=t,e.firstElementChild}if(-1!==t.indexOf("<")){var r=document.createElement("div");return r.innerHTML=t,r.firstElementChild}}},a=function(e,r,n){var s=void 0,i=function(e){for(var r=0,n=t.valueNames.length;r<n;r++){var s=t.valueNames[r];if(s.data){for(var i=s.data,a=0,o=i.length;a<o;a++)if(i[a]===e)return{data:e}}else{if(s.attr&&s.name&&s.name==e)return s;if(s===e)return e}}}(r);i&&(i.data?e.elm.setAttribute("data-"+i.data,n):i.attr&&i.name?(s=t.utils.getByClass(e.elm,i.name,!0))&&s.setAttribute(i.attr,n):(s=t.utils.getByClass(e.elm,i,!0))&&(s.innerHTML=n))};this.get=function(e,n){r.create(e);for(var s={},i=0,a=n.length;i<a;i++){var o=void 0,l=n[i];if(l.data)for(var u=0,c=l.data.length;u<c;u++)s[l.data[u]]=t.utils.getAttribute(e.elm,"data-"+l.data[u]);else l.attr&&l.name?(o=t.utils.getByClass(e.elm,l.name,!0),s[l.name]=o?t.utils.getAttribute(o,l.attr):""):(o=t.utils.getByClass(e.elm,l,!0),s[l]=o?o.innerHTML:"")}return s},this.set=function(t,e){if(!r.create(t))for(var n in e)e.hasOwnProperty(n)&&a(t,n,e[n])},this.create=function(t){return void 0===t.elm&&(t.elm=e(t.values()),r.set(t,t.values()),!0)},this.remove=function(e){e.elm.parentNode===t.list&&t.list.removeChild(e.elm)},this.show=function(e){r.create(e),t.list.appendChild(e.elm)},this.hide=function(e){void 0!==e.elm&&e.elm.parentNode===t.list&&t.list.removeChild(e.elm)},this.clear=function(){if(t.list.hasChildNodes())for(;t.list.childNodes.length>=1;)t.list.removeChild(t.list.firstChild)},function(){var r;if("function"!=typeof t.item){if(!(r="string"==typeof t.item?-1===t.item.indexOf("<")?document.getElementById(t.item):i(t.item):s()))throw new Error("The list needs to have at least one item on init otherwise you'll have to add a template.");r=n(r,t.valueNames),e=function(){return r.cloneNode(!0)}}else e=function(e){var r=t.item(e);return i(r)}}()};t.exports=function(t){return new e(t)}},"./src/utils/classes.js":function(t,e,r){var n=r("./src/utils/index-of.js"),s=/\s+/;Object.prototype.toString;function i(t){if(!t||!t.nodeType)throw new Error("A DOM element reference is required");this.el=t,this.list=t.classList}t.exports=function(t){return new i(t)},i.prototype.add=function(t){if(this.list)return this.list.add(t),this;var e=this.array();return~n(e,t)||e.push(t),this.el.className=e.join(" "),this},i.prototype.remove=function(t){if(this.list)return this.list.remove(t),this;var e=this.array(),r=n(e,t);return~r&&e.splice(r,1),this.el.className=e.join(" "),this},i.prototype.toggle=function(t,e){return this.list?(void 0!==e?e!==this.list.toggle(t,e)&&this.list.toggle(t):this.list.toggle(t),this):(void 0!==e?e?this.add(t):this.remove(t):this.has(t)?this.remove(t):this.add(t),this)},i.prototype.array=function(){var t=(this.el.getAttribute("class")||"").replace(/^\s+|\s+$/g,"").split(s);return""===t[0]&&t.shift(),t},i.prototype.has=i.prototype.contains=function(t){return this.list?this.list.contains(t):!!~n(this.array(),t)}},"./src/utils/events.js":function(t,e,r){var n=window.addEventListener?"addEventListener":"attachEvent",s=window.removeEventListener?"removeEventListener":"detachEvent",i="addEventListener"!==n?"on":"",a=r("./src/utils/to-array.js");e.bind=function(t,e,r,s){for(var o=0,l=(t=a(t)).length;o<l;o++)t[o][n](i+e,r,s||!1)},e.unbind=function(t,e,r,n){for(var o=0,l=(t=a(t)).length;o<l;o++)t[o][s](i+e,r,n||!1)},e.debounce=function(t,e,r){var n;return e?function(){var s=this,i=arguments,a=function(){n=null,r||t.apply(s,i)},o=r&&!n;clearTimeout(n),n=setTimeout(a,e),o&&t.apply(s,i)}:t}},"./src/utils/extend.js":function(t){t.exports=function(t){for(var e,r=Array.prototype.slice.call(arguments,1),n=0;e=r[n];n++)if(e)for(var s in e)t[s]=e[s];return t}},"./src/utils/fuzzy.js":function(t){t.exports=function(t,e,r){var n=r.location||0,s=r.distance||100,i=r.threshold||.4;if(e===t)return!0;if(e.length>32)return!1;var a=n,o=function(){var t,r={};for(t=0;t<e.length;t++)r[e.charAt(t)]=0;for(t=0;t<e.length;t++)r[e.charAt(t)]|=1<<e.length-t-1;return r}();function l(t,r){var n=t/e.length,i=Math.abs(a-r);return s?n+i/s:i?1:n}var u=i,c=t.indexOf(e,a);-1!=c&&(u=Math.min(l(0,c),u),-1!=(c=t.lastIndexOf(e,a+e.length))&&(u=Math.min(l(0,c),u)));var f,h,d=1<<e.length-1;c=-1;for(var v,g=e.length+t.length,m=0;m<e.length;m++){for(f=0,h=g;f<h;)l(m,a+h)<=u?f=h:g=h,h=Math.floor((g-f)/2+f);g=h;var p=Math.max(1,a-h+1),y=Math.min(a+h,t.length)+e.length,C=Array(y+2);C[y+1]=(1<<m)-1;for(var b=y;b>=p;b--){var j=o[t.charAt(b-1)];if(C[b]=0===m?(C[b+1]<<1|1)&j:(C[b+1]<<1|1)&j|(v[b+1]|v[b])<<1|1|v[b+1],C[b]&d){var x=l(m,b-1);if(x<=u){if(u=x,!((c=b-1)>a))break;p=Math.max(1,2*a-c)}}}if(l(m+1,a)>u)break;v=C}return!(c<0)}},"./src/utils/get-attribute.js":function(t){t.exports=function(t,e){var r=t.getAttribute&&t.getAttribute(e)||null;if(!r)for(var n=t.attributes,s=n.length,i=0;i<s;i++)void 0!==n[i]&&n[i].nodeName===e&&(r=n[i].nodeValue);return r}},"./src/utils/get-by-class.js":function(t){t.exports=function(t,e,r,n){return(n=n||{}).test&&n.getElementsByClassName||!n.test&&document.getElementsByClassName?function(t,e,r){return r?t.getElementsByClassName(e)[0]:t.getElementsByClassName(e)}(t,e,r):n.test&&n.querySelector||!n.test&&document.querySelector?function(t,e,r){return e="."+e,r?t.querySelector(e):t.querySelectorAll(e)}(t,e,r):function(t,e,r){for(var n=[],s=t.getElementsByTagName("*"),i=s.length,a=new RegExp("(^|\\s)"+e+"(\\s|$)"),o=0,l=0;o<i;o++)if(a.test(s[o].className)){if(r)return s[o];n[l]=s[o],l++}return n}(t,e,r)}},"./src/utils/index-of.js":function(t){var e=[].indexOf;t.exports=function(t,r){if(e)return t.indexOf(r);for(var n=0,s=t.length;n<s;++n)if(t[n]===r)return n;return-1}},"./src/utils/to-array.js":function(t){t.exports=function(t){if(void 0===t)return[];if(null===t)return[null];if(t===window)return[window];if("string"==typeof t)return[t];if(function(t){return"[object Array]"===Object.prototype.toString.call(t)}(t))return t;if("number"!=typeof t.length)return[t];if("function"==typeof t&&t instanceof Function)return[t];for(var e=[],r=0,n=t.length;r<n;r++)(Object.prototype.hasOwnProperty.call(t,r)||r in t)&&e.push(t[r]);return e.length?e:[]}},"./src/utils/to-string.js":function(t){t.exports=function(t){return t=(t=null===(t=void 0===t?"":t)?"":t).toString()}},"./node_modules/string-natural-compare/natural-compare.js":function(t){"use strict";var e,r,n=0;function s(t){return t>=48&&t<=57}function i(t,e){for(var i=(t+="").length,a=(e+="").length,o=0,l=0;o<i&&l<a;){var u=t.charCodeAt(o),c=e.charCodeAt(l);if(s(u)){if(!s(c))return u-c;for(var f=o,h=l;48===u&&++f<i;)u=t.charCodeAt(f);for(;48===c&&++h<a;)c=e.charCodeAt(h);for(var d=f,v=h;d<i&&s(t.charCodeAt(d));)++d;for(;v<a&&s(e.charCodeAt(v));)++v;var g=d-f-v+h;if(g)return g;for(;f<d;)if(g=t.charCodeAt(f++)-e.charCodeAt(h++))return g;o=d,l=v}else{if(u!==c)return u<n&&c<n&&-1!==r[u]&&-1!==r[c]?r[u]-r[c]:u-c;++o,++l}}return o>=i&&l<a&&i>=a?-1:l>=a&&o<i&&a>=i?1:i-a}i.caseInsensitive=i.i=function(t,e){return i((""+t).toLowerCase(),(""+e).toLowerCase())},Object.defineProperties(i,{alphabet:{get:function(){return e},set:function(t){r=[];var s=0;if(e=t)for(;s<e.length;s++)r[e.charCodeAt(s)]=s;for(n=r.length,s=0;s<n;s++)void 0===r[s]&&(r[s]=-1)}}}),t.exports=i}},e={};return function r(n){if(e[n])return e[n].exports;var s=e[n]={exports:{}};return t[n](s,s.exports,r),s.exports}("./src/index.js")}();
|
2 |
+
//# sourceMappingURL=list.min.js.map
|
src/.quarto/_freeze/site_libs/quarto-listing/quarto-listing.js
ADDED
@@ -0,0 +1,253 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const kProgressiveAttr = "data-src";
|
2 |
+
let categoriesLoaded = false;
|
3 |
+
|
4 |
+
window.quartoListingCategory = (category) => {
|
5 |
+
category = atob(category);
|
6 |
+
if (categoriesLoaded) {
|
7 |
+
activateCategory(category);
|
8 |
+
setCategoryHash(category);
|
9 |
+
}
|
10 |
+
};
|
11 |
+
|
12 |
+
window["quarto-listing-loaded"] = () => {
|
13 |
+
// Process any existing hash
|
14 |
+
const hash = getHash();
|
15 |
+
|
16 |
+
if (hash) {
|
17 |
+
// If there is a category, switch to that
|
18 |
+
if (hash.category) {
|
19 |
+
// category hash are URI encoded so we need to decode it before processing
|
20 |
+
// so that we can match it with the category element processed in JS
|
21 |
+
activateCategory(decodeURIComponent(hash.category));
|
22 |
+
}
|
23 |
+
// Paginate a specific listing
|
24 |
+
const listingIds = Object.keys(window["quarto-listings"]);
|
25 |
+
for (const listingId of listingIds) {
|
26 |
+
const page = hash[getListingPageKey(listingId)];
|
27 |
+
if (page) {
|
28 |
+
showPage(listingId, page);
|
29 |
+
}
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
const listingIds = Object.keys(window["quarto-listings"]);
|
34 |
+
for (const listingId of listingIds) {
|
35 |
+
// The actual list
|
36 |
+
const list = window["quarto-listings"][listingId];
|
37 |
+
|
38 |
+
// Update the handlers for pagination events
|
39 |
+
refreshPaginationHandlers(listingId);
|
40 |
+
|
41 |
+
// Render any visible items that need it
|
42 |
+
renderVisibleProgressiveImages(list);
|
43 |
+
|
44 |
+
// Whenever the list is updated, we also need to
|
45 |
+
// attach handlers to the new pagination elements
|
46 |
+
// and refresh any newly visible items.
|
47 |
+
list.on("updated", function () {
|
48 |
+
renderVisibleProgressiveImages(list);
|
49 |
+
setTimeout(() => refreshPaginationHandlers(listingId));
|
50 |
+
|
51 |
+
// Show or hide the no matching message
|
52 |
+
toggleNoMatchingMessage(list);
|
53 |
+
});
|
54 |
+
}
|
55 |
+
};
|
56 |
+
|
57 |
+
window.document.addEventListener("DOMContentLoaded", function (_event) {
|
58 |
+
// Attach click handlers to categories
|
59 |
+
const categoryEls = window.document.querySelectorAll(
|
60 |
+
".quarto-listing-category .category"
|
61 |
+
);
|
62 |
+
|
63 |
+
for (const categoryEl of categoryEls) {
|
64 |
+
// category needs to support non ASCII characters
|
65 |
+
const category = decodeURIComponent(
|
66 |
+
atob(categoryEl.getAttribute("data-category"))
|
67 |
+
);
|
68 |
+
categoryEl.onclick = () => {
|
69 |
+
activateCategory(category);
|
70 |
+
setCategoryHash(category);
|
71 |
+
};
|
72 |
+
}
|
73 |
+
|
74 |
+
// Attach a click handler to the category title
|
75 |
+
// (there should be only one, but since it is a class name, handle N)
|
76 |
+
const categoryTitleEls = window.document.querySelectorAll(
|
77 |
+
".quarto-listing-category-title"
|
78 |
+
);
|
79 |
+
for (const categoryTitleEl of categoryTitleEls) {
|
80 |
+
categoryTitleEl.onclick = () => {
|
81 |
+
activateCategory("");
|
82 |
+
setCategoryHash("");
|
83 |
+
};
|
84 |
+
}
|
85 |
+
|
86 |
+
categoriesLoaded = true;
|
87 |
+
});
|
88 |
+
|
89 |
+
function toggleNoMatchingMessage(list) {
|
90 |
+
const selector = `#${list.listContainer.id} .listing-no-matching`;
|
91 |
+
const noMatchingEl = window.document.querySelector(selector);
|
92 |
+
if (noMatchingEl) {
|
93 |
+
if (list.visibleItems.length === 0) {
|
94 |
+
noMatchingEl.classList.remove("d-none");
|
95 |
+
} else {
|
96 |
+
if (!noMatchingEl.classList.contains("d-none")) {
|
97 |
+
noMatchingEl.classList.add("d-none");
|
98 |
+
}
|
99 |
+
}
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
function setCategoryHash(category) {
|
104 |
+
setHash({ category });
|
105 |
+
}
|
106 |
+
|
107 |
+
function setPageHash(listingId, page) {
|
108 |
+
const currentHash = getHash() || {};
|
109 |
+
currentHash[getListingPageKey(listingId)] = page;
|
110 |
+
setHash(currentHash);
|
111 |
+
}
|
112 |
+
|
113 |
+
function getListingPageKey(listingId) {
|
114 |
+
return `${listingId}-page`;
|
115 |
+
}
|
116 |
+
|
117 |
+
function refreshPaginationHandlers(listingId) {
|
118 |
+
const listingEl = window.document.getElementById(listingId);
|
119 |
+
const paginationEls = listingEl.querySelectorAll(
|
120 |
+
".pagination li.page-item:not(.disabled) .page.page-link"
|
121 |
+
);
|
122 |
+
for (const paginationEl of paginationEls) {
|
123 |
+
paginationEl.onclick = (sender) => {
|
124 |
+
setPageHash(listingId, sender.target.getAttribute("data-i"));
|
125 |
+
showPage(listingId, sender.target.getAttribute("data-i"));
|
126 |
+
return false;
|
127 |
+
};
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
function renderVisibleProgressiveImages(list) {
|
132 |
+
// Run through the visible items and render any progressive images
|
133 |
+
for (const item of list.visibleItems) {
|
134 |
+
const itemEl = item.elm;
|
135 |
+
if (itemEl) {
|
136 |
+
const progressiveImgs = itemEl.querySelectorAll(
|
137 |
+
`img[${kProgressiveAttr}]`
|
138 |
+
);
|
139 |
+
for (const progressiveImg of progressiveImgs) {
|
140 |
+
const srcValue = progressiveImg.getAttribute(kProgressiveAttr);
|
141 |
+
if (srcValue) {
|
142 |
+
progressiveImg.setAttribute("src", srcValue);
|
143 |
+
}
|
144 |
+
progressiveImg.removeAttribute(kProgressiveAttr);
|
145 |
+
}
|
146 |
+
}
|
147 |
+
}
|
148 |
+
}
|
149 |
+
|
150 |
+
function getHash() {
|
151 |
+
// Hashes are of the form
|
152 |
+
// #name:value|name1:value1|name2:value2
|
153 |
+
const currentUrl = new URL(window.location);
|
154 |
+
const hashRaw = currentUrl.hash ? currentUrl.hash.slice(1) : undefined;
|
155 |
+
return parseHash(hashRaw);
|
156 |
+
}
|
157 |
+
|
158 |
+
const kAnd = "&";
|
159 |
+
const kEquals = "=";
|
160 |
+
|
161 |
+
function parseHash(hash) {
|
162 |
+
if (!hash) {
|
163 |
+
return undefined;
|
164 |
+
}
|
165 |
+
const hasValuesStrs = hash.split(kAnd);
|
166 |
+
const hashValues = hasValuesStrs
|
167 |
+
.map((hashValueStr) => {
|
168 |
+
const vals = hashValueStr.split(kEquals);
|
169 |
+
if (vals.length === 2) {
|
170 |
+
return { name: vals[0], value: vals[1] };
|
171 |
+
} else {
|
172 |
+
return undefined;
|
173 |
+
}
|
174 |
+
})
|
175 |
+
.filter((value) => {
|
176 |
+
return value !== undefined;
|
177 |
+
});
|
178 |
+
|
179 |
+
const hashObj = {};
|
180 |
+
hashValues.forEach((hashValue) => {
|
181 |
+
hashObj[hashValue.name] = decodeURIComponent(hashValue.value);
|
182 |
+
});
|
183 |
+
return hashObj;
|
184 |
+
}
|
185 |
+
|
186 |
+
function makeHash(obj) {
|
187 |
+
return Object.keys(obj)
|
188 |
+
.map((key) => {
|
189 |
+
return `${key}${kEquals}${obj[key]}`;
|
190 |
+
})
|
191 |
+
.join(kAnd);
|
192 |
+
}
|
193 |
+
|
194 |
+
function setHash(obj) {
|
195 |
+
const hash = makeHash(obj);
|
196 |
+
window.history.pushState(null, null, `#${hash}`);
|
197 |
+
}
|
198 |
+
|
199 |
+
function showPage(listingId, page) {
|
200 |
+
const list = window["quarto-listings"][listingId];
|
201 |
+
if (list) {
|
202 |
+
list.show((page - 1) * list.page + 1, list.page);
|
203 |
+
}
|
204 |
+
}
|
205 |
+
|
206 |
+
function activateCategory(category) {
|
207 |
+
// Deactivate existing categories
|
208 |
+
const activeEls = window.document.querySelectorAll(
|
209 |
+
".quarto-listing-category .category.active"
|
210 |
+
);
|
211 |
+
for (const activeEl of activeEls) {
|
212 |
+
activeEl.classList.remove("active");
|
213 |
+
}
|
214 |
+
|
215 |
+
// Activate this category
|
216 |
+
const categoryEl = window.document.querySelector(
|
217 |
+
`.quarto-listing-category .category[data-category='${btoa(
|
218 |
+
encodeURIComponent(category)
|
219 |
+
)}']`
|
220 |
+
);
|
221 |
+
if (categoryEl) {
|
222 |
+
categoryEl.classList.add("active");
|
223 |
+
}
|
224 |
+
|
225 |
+
// Filter the listings to this category
|
226 |
+
filterListingCategory(category);
|
227 |
+
}
|
228 |
+
|
229 |
+
function filterListingCategory(category) {
|
230 |
+
const listingIds = Object.keys(window["quarto-listings"]);
|
231 |
+
for (const listingId of listingIds) {
|
232 |
+
const list = window["quarto-listings"][listingId];
|
233 |
+
if (list) {
|
234 |
+
if (category === "") {
|
235 |
+
// resets the filter
|
236 |
+
list.filter();
|
237 |
+
} else {
|
238 |
+
// filter to this category
|
239 |
+
list.filter(function (item) {
|
240 |
+
const itemValues = item.values();
|
241 |
+
if (itemValues.categories !== null) {
|
242 |
+
const categories = decodeURIComponent(
|
243 |
+
atob(itemValues.categories)
|
244 |
+
).split(",");
|
245 |
+
return categories.includes(category);
|
246 |
+
} else {
|
247 |
+
return false;
|
248 |
+
}
|
249 |
+
});
|
250 |
+
}
|
251 |
+
}
|
252 |
+
}
|
253 |
+
}
|
src/.quarto/idx/about.qmd.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"title":"About","markdown":{"yaml":{"title":"About","image":"profile.jpg","about":{"template":"jolla","links":[{"icon":"linkedin","text":"LinkedIn","href":"https://www.linkedin.com/in/joana-levtcheva-479844164/"},{"icon":"github","text":"Github","href":"https://github.com/JoeJoe1313"}]}},"containsRefs":false,"markdown":"\n\nAbout this blog\n","srcMarkdownNoYaml":"\n\nAbout this blog\n"},"formats":{"html":{"identifier":{"display-name":"HTML","target-format":"html","base-format":"html"},"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":false,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"ipynb-shell-interactivity":null,"plotly-connected":true,"engine":"markdown"},"render":{"keep-tex":false,"keep-typ":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"inline-includes":false,"preserve-yaml":false,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-min-runs":1,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[],"notebook-links":true},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","html-math-method":"mathjax","css":["styles.css"],"output-file":"about.html"},"language":{"toc-title-document":"Table of contents","toc-title-website":"On this page","related-formats-title":"Other Formats","related-notebooks-title":"Notebooks","source-notebooks-prefix":"Source","other-links-title":"Other Links","code-links-title":"Code Links","launch-dev-container-title":"Launch Dev Container","launch-binder-title":"Launch Binder","article-notebook-label":"Article Notebook","notebook-preview-download":"Download Notebook","notebook-preview-download-src":"Download Source","notebook-preview-back":"Back to Article","manuscript-meca-bundle":"MECA Bundle","section-title-abstract":"Abstract","section-title-appendices":"Appendices","section-title-footnotes":"Footnotes","section-title-references":"References","section-title-reuse":"Reuse","section-title-copyright":"Copyright","section-title-citation":"Citation","appendix-attribution-cite-as":"For attribution, please cite this work as:","appendix-attribution-bibtex":"BibTeX citation:","appendix-view-license":"View License","title-block-author-single":"Author","title-block-author-plural":"Authors","title-block-affiliation-single":"Affiliation","title-block-affiliation-plural":"Affiliations","title-block-published":"Published","title-block-modified":"Modified","title-block-keywords":"Keywords","callout-tip-title":"Tip","callout-note-title":"Note","callout-warning-title":"Warning","callout-important-title":"Important","callout-caution-title":"Caution","code-summary":"Code","code-tools-menu-caption":"Code","code-tools-show-all-code":"Show All Code","code-tools-hide-all-code":"Hide All Code","code-tools-view-source":"View Source","code-tools-source-code":"Source Code","tools-share":"Share","tools-download":"Download","code-line":"Line","code-lines":"Lines","copy-button-tooltip":"Copy to Clipboard","copy-button-tooltip-success":"Copied!","repo-action-links-edit":"Edit this page","repo-action-links-source":"View source","repo-action-links-issue":"Report an issue","back-to-top":"Back to top","search-no-results-text":"No results","search-matching-documents-text":"matching documents","search-copy-link-title":"Copy link to search","search-hide-matches-text":"Hide additional matches","search-more-match-text":"more match in this document","search-more-matches-text":"more matches in this document","search-clear-button-title":"Clear","search-text-placeholder":"","search-detached-cancel-button-title":"Cancel","search-submit-button-title":"Submit","search-label":"Search","toggle-section":"Toggle section","toggle-sidebar":"Toggle sidebar navigation","toggle-dark-mode":"Toggle dark mode","toggle-reader-mode":"Toggle reader mode","toggle-navigation":"Toggle navigation","crossref-fig-title":"Figure","crossref-tbl-title":"Table","crossref-lst-title":"Listing","crossref-thm-title":"Theorem","crossref-lem-title":"Lemma","crossref-cor-title":"Corollary","crossref-prp-title":"Proposition","crossref-cnj-title":"Conjecture","crossref-def-title":"Definition","crossref-exm-title":"Example","crossref-exr-title":"Exercise","crossref-ch-prefix":"Chapter","crossref-apx-prefix":"Appendix","crossref-sec-prefix":"Section","crossref-eq-prefix":"Equation","crossref-lof-title":"List of Figures","crossref-lot-title":"List of Tables","crossref-lol-title":"List of Listings","environment-proof-title":"Proof","environment-remark-title":"Remark","environment-solution-title":"Solution","listing-page-order-by":"Order By","listing-page-order-by-default":"Default","listing-page-order-by-date-asc":"Oldest","listing-page-order-by-date-desc":"Newest","listing-page-order-by-number-desc":"High to Low","listing-page-order-by-number-asc":"Low to High","listing-page-field-date":"Date","listing-page-field-title":"Title","listing-page-field-description":"Description","listing-page-field-author":"Author","listing-page-field-filename":"File Name","listing-page-field-filemodified":"Modified","listing-page-field-subtitle":"Subtitle","listing-page-field-readingtime":"Reading Time","listing-page-field-wordcount":"Word Count","listing-page-field-categories":"Categories","listing-page-minutes-compact":"{0} min","listing-page-category-all":"All","listing-page-no-matches":"No matching items","listing-page-words":"{0} words","listing-page-filter":"Filter","draft":"Draft"},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.6.39","theme":"flatly","title":"About","image":"profile.jpg","about":{"template":"jolla","links":[{"icon":"linkedin","text":"LinkedIn","href":"https://www.linkedin.com/in/joana-levtcheva-479844164/"},{"icon":"github","text":"Github","href":"https://github.com/JoeJoe1313"}]}},"extensions":{"book":{"multiFile":true}}}},"projectFormats":["html"]}
|
src/.quarto/idx/index.qmd.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"title":"quarto-blog","markdown":{"yaml":{"title":"quarto-blog","listing":{"contents":"posts","sort":"date desc","type":"default","categories":true,"sort-ui":false,"filter-ui":false},"page-layout":"full","title-block-banner":true},"containsRefs":false,"markdown":"\n","srcMarkdownNoYaml":"\n"},"formats":{"html":{"identifier":{"display-name":"HTML","target-format":"html","base-format":"html"},"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":false,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"ipynb-shell-interactivity":null,"plotly-connected":true,"engine":"markdown"},"render":{"keep-tex":false,"keep-typ":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"inline-includes":false,"preserve-yaml":false,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-min-runs":1,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[],"notebook-links":true},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","html-math-method":"mathjax","css":["styles.css"],"output-file":"index.html"},"language":{"toc-title-document":"Table of contents","toc-title-website":"On this page","related-formats-title":"Other Formats","related-notebooks-title":"Notebooks","source-notebooks-prefix":"Source","other-links-title":"Other Links","code-links-title":"Code Links","launch-dev-container-title":"Launch Dev Container","launch-binder-title":"Launch Binder","article-notebook-label":"Article Notebook","notebook-preview-download":"Download Notebook","notebook-preview-download-src":"Download Source","notebook-preview-back":"Back to Article","manuscript-meca-bundle":"MECA Bundle","section-title-abstract":"Abstract","section-title-appendices":"Appendices","section-title-footnotes":"Footnotes","section-title-references":"References","section-title-reuse":"Reuse","section-title-copyright":"Copyright","section-title-citation":"Citation","appendix-attribution-cite-as":"For attribution, please cite this work as:","appendix-attribution-bibtex":"BibTeX citation:","appendix-view-license":"View License","title-block-author-single":"Author","title-block-author-plural":"Authors","title-block-affiliation-single":"Affiliation","title-block-affiliation-plural":"Affiliations","title-block-published":"Published","title-block-modified":"Modified","title-block-keywords":"Keywords","callout-tip-title":"Tip","callout-note-title":"Note","callout-warning-title":"Warning","callout-important-title":"Important","callout-caution-title":"Caution","code-summary":"Code","code-tools-menu-caption":"Code","code-tools-show-all-code":"Show All Code","code-tools-hide-all-code":"Hide All Code","code-tools-view-source":"View Source","code-tools-source-code":"Source Code","tools-share":"Share","tools-download":"Download","code-line":"Line","code-lines":"Lines","copy-button-tooltip":"Copy to Clipboard","copy-button-tooltip-success":"Copied!","repo-action-links-edit":"Edit this page","repo-action-links-source":"View source","repo-action-links-issue":"Report an issue","back-to-top":"Back to top","search-no-results-text":"No results","search-matching-documents-text":"matching documents","search-copy-link-title":"Copy link to search","search-hide-matches-text":"Hide additional matches","search-more-match-text":"more match in this document","search-more-matches-text":"more matches in this document","search-clear-button-title":"Clear","search-text-placeholder":"","search-detached-cancel-button-title":"Cancel","search-submit-button-title":"Submit","search-label":"Search","toggle-section":"Toggle section","toggle-sidebar":"Toggle sidebar navigation","toggle-dark-mode":"Toggle dark mode","toggle-reader-mode":"Toggle reader mode","toggle-navigation":"Toggle navigation","crossref-fig-title":"Figure","crossref-tbl-title":"Table","crossref-lst-title":"Listing","crossref-thm-title":"Theorem","crossref-lem-title":"Lemma","crossref-cor-title":"Corollary","crossref-prp-title":"Proposition","crossref-cnj-title":"Conjecture","crossref-def-title":"Definition","crossref-exm-title":"Example","crossref-exr-title":"Exercise","crossref-ch-prefix":"Chapter","crossref-apx-prefix":"Appendix","crossref-sec-prefix":"Section","crossref-eq-prefix":"Equation","crossref-lof-title":"List of Figures","crossref-lot-title":"List of Tables","crossref-lol-title":"List of Listings","environment-proof-title":"Proof","environment-remark-title":"Remark","environment-solution-title":"Solution","listing-page-order-by":"Order By","listing-page-order-by-default":"Default","listing-page-order-by-date-asc":"Oldest","listing-page-order-by-date-desc":"Newest","listing-page-order-by-number-desc":"High to Low","listing-page-order-by-number-asc":"Low to High","listing-page-field-date":"Date","listing-page-field-title":"Title","listing-page-field-description":"Description","listing-page-field-author":"Author","listing-page-field-filename":"File Name","listing-page-field-filemodified":"Modified","listing-page-field-subtitle":"Subtitle","listing-page-field-readingtime":"Reading Time","listing-page-field-wordcount":"Word Count","listing-page-field-categories":"Categories","listing-page-minutes-compact":"{0} min","listing-page-category-all":"All","listing-page-no-matches":"No matching items","listing-page-words":"{0} words","listing-page-filter":"Filter","draft":"Draft"},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.6.39","theme":"flatly","title":"quarto-blog","listing":{"contents":"posts","sort":"date desc","type":"default","categories":true,"sort-ui":false,"filter-ui":false},"page-layout":"full","title-block-banner":true},"extensions":{"book":{"multiFile":true}}}},"projectFormats":["html"]}
|
src/.quarto/idx/posts/2025-01-04-fourier-method-fixed-string/index.qmd.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"title":"Fourier Method for the 1D Wave Equation: Fixed String","markdown":{"yaml":{"title":"Fourier Method for the 1D Wave Equation: Fixed String","author":"Joana Levtcheva","date":"2025-01-04","categories":["mathematics","pde"],"draft":false},"headingText":"1D Wave Equation","containsRefs":false,"markdown":"\n\nIn this post we are going to explore the Fourier method for solving the 1D wave equation. The method is more known under the name of the **method of separation of variables**. For the 1D wave equation we are going to show the application of the method to a fixed string. We are also going to attempt to outline some of the physical interpretations of the fixed string.\n\n\nThe 1D wave equation is of the form\n\n$$\nu_{tt} = a^2 u_{xx}.\n$$\n\n## Fixed String\n\nFirst, let's take a look at the model of a string with length $l$ which is also fixed at both ends:\n\n$$\n\\left\\{\\begin{aligned}\nu_{tt} = a^2 u_{xx}, \\\\ \nu(x, 0) = \\varphi_1(x),\\\\\nu_t(x, 0) = \\varphi_2(x), \\\\\nu(0, t) = u(l, t) = 0.\n\\end{aligned}\\right.\n$$\n\nA visualisation of the string can be seen in the figure below.\n\n{width=60%}\n\nWe start solving the equation by taking into account only the boundary conditions $u(0, t) = u(l, t) = 0$. The idea is to find solution $u(x, t)$ of the form\n\n$$\nu(x, t) = X(x)T(t).\n$$\n\nWe substitute this form of the solution into the wave equation and get \n\n$$\n\\frac{1}{a^2} T^{\\prime\\prime}(t)X(x) = T(t)X^{\\prime\\prime}(x),\n$$\n\nfurther divding by $X(x)T(t)$ leads to\n\n$$\n\\frac{1}{a^2} \\frac{T^{\\prime\\prime}(t)}{T(t)} = \\frac{X^{\\prime\\prime}(x)}{X(x)}.\n$$\n\nWe have two functions of independent variables which are equal. This is only possible if they are equal to the same constant. Therefore, let\n\n$$\n\\frac{1}{a^2} \\frac{T^{\\prime\\prime}(t)}{T(t)} = \\frac{X^{\\prime\\prime}(x)}{X(x)} = -\\lambda,\n$$\n\nproducing the following two equeations:\n\n$$\nT^{\\prime\\prime}(t) + a^2 \\lambda T(t) = 0\n$$\n\nand\n\n$$\\label{eq:ref}\nX^{\\prime\\prime}(x) + \\lambda X(x) = 0. \\tag{*}\n$$\n\nLet's begin with solving the second equation. The boundary conditions give\n\n$$\nX(0)T(t) = 0 \\quad \\text{and} \\quad X(l)T(t) = 0.\n$$\n\nBecause we are interested only in non-trivial solutions and thus $T \\neq 0$, we have\n\n$$\\label{eq:ref2}\nX(0) = 0 \\quad \\text{and} \\quad X(l) = 0. \\tag{**}\n$$\n\nNow, we have to find the non-trivial solutions for $X(x)$ satisfying\n\n$$\n\\left\\{\\begin{align*}\nX^{\\prime\\prime}(x) + \\lambda X(x) = 0, \\\\\nX(0) = 0, \\quad X(l) = 0.\n\\end{align*}\\right.\n$$\n\nThe above problem is an example of the so called **Sturm-Liouville problem**. In order to find the general solution of the second order linear homogeneous differential equation with constant coefficients $\\eqref{eq:ref}$ we should solve its characteristic equation\n\n$$\nr^2 + \\lambda = 0.\n$$\n\n- If $\\lambda < 0$, then $r_{1, 2} = \\pm \\sqrt{-\\lambda}$, hence the general solution is\n$$\nX(x) = c_1 e^{\\sqrt{-\\lambda}x} + c_2 e^{-\\sqrt{-\\lambda}x}\n$$\nfor some constants $c_1$ and $c_2$. In order to determine the constants we substitute the above solution into the boundary conditions $\\eqref{eq:ref2}$ and get the system\n$$\n\\left\\{\\begin{align*}\nc_1 + c_2 = 0, \\\\\nc_1 e^{\\sqrt{-\\lambda}l} + c_2 e^{-\\sqrt{-\\lambda}l} = 0. \n\\end{align*}\\right.\n$$\nThis results in $c_1 = c_2 = 0$, meaning our Sturm-Liouville problem doesn't have a non-zero solution for $\\lambda < 0$.\n\n- If $\\lambda = 0$, then $r_1 = r_2 = 0$ and the general solution is\n$$\nX(x) = c_1 + c_2 x.\n$$\nSubstituing it into the boundary conditions $\\eqref{eq:ref2}$ again lead to $c_1 = c_2 = 0$, hence no non-zero solutions of our Sturm-Liouville problem for $\\lambda \\leq 0$.\n\n- If $\\lambda > 0$, then $r_{1, 2} = \\pm i \\sqrt{\\lambda}$, and the general solution becomes\n$$\nX(x) = c_1 \\cos{\\left( \\sqrt{\\lambda} x \\right)} + c_2 \\sin{\\left(\\sqrt{\\lambda}x\\right)}.\n$$\nSubstituting into the boundary conditions $\\eqref{eq:ref2}$ results in\n$$\n\\left\\{\\begin{align*}\nc_1 = 0, \\\\\nc_2 \\sin{\\left(\\sqrt{\\lambda}l\\right)} = 0\n\\end{align*}\\right.\n$$\nIf $c_2 = 0$, then $X(x) \\equiv 0$ which is a trivial solution. Therefore, we set $c_2 \\neq 0$ and hence\n$$\n\\sin{\\left(\\sqrt{\\lambda}l\\right)} = 0,\n$$\ngiving $\\sqrt{\\lambda}l = k \\pi$, $k = \\pm 1, \\pm 2, ...$. Theerfore,\n$$\n\\lambda = \\lambda_k = \\left(\\frac{k \\pi}{l}\\right)^2,\n$$\nmeaning eigenvalues exist when $\\lambda > 0$. The eigenfunctions corresponding to the above eigenvalues are\n$$\nX_k(x) = \\sin{\\left(\\frac{k \\pi x}{l}\\right)}, \\quad k > 0, k \\in N.\n$$\n\nGoing back to $T^{\\prime\\prime}(t) + a^2 \\lambda T(t) = 0$, solving in analogical way, when $\\lambda = \\lambda_k$ the solution becomes\n\n$$\nT_k(t) = A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\n$$\n\nfor some constants $A_k$ and $B_k$. Hence,\n\n$$\nu_k(x,t) = X_k(x) T_k(t) = \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}, \\quad k > 0, k \\in N\n$$\n\nare solutions to our wave equation, also satisfying the boundary conditions. Since our equation is linear, forming a linear system with its conditions, the **principle of superposition** is valid. In other words, if $u_1, u_2, ..., u_n$ are solutions of our system, then\n\n$$\n\\alpha_1 u_1 + \\alpha_2 u_2 + ... + \\alpha_n u_n\n$$\n\nfor some constants $\\alpha_1, \\alpha_2, ..., \\alpha_n$ is also a solution of the system. But in our case we have an infinite number of functions $u_1, u_2, ...$ which satisfy the linear system. Therefore, we need the **generalised superposition principle** stating that in such case\n\n$$\nu = \\sum_n^{\\infty} \\alpha_n u_n\n$$\n\nfor some arbitrary constants $\\alpha_n$ is a solution to the system if the series converges uniformly and is twice differentiable termwise. This generalisation is a Lemma and should be prooved. The proof can be found in ...\n\nAssuming we have prooved the said Lemma, we can state that our system has a solution of the form\n\n$$\nu(x, t) = \\sum_{k=1}\n^{\\infty} u_k(x, t) = \\sum_{k=1}^{\\infty} \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}.\n$$\n\nThe next task we have to tackle is to determine the coefficients $A_k$ and $B_k$. We can achieve this by using the initial conditions \n\n$$\nu(x, 0) = \\varphi_1(x), \\quad \\text{and} \\quad u_t(x, 0) = \\varphi_2(x).\n$$\n\nWe get\n\n$$\nu(x, 0) = \\sum_{k=1}\n^{\\infty} A_k \\sin{\\left(\\frac{k \\pi x}{l}\\right)} = \\varphi_1(x)\n$$\n\nand\n\n$$\nu_t(x, 0) = \\sum_{k=1}^{\\infty} \\frac{ak\\pi}{l} B_k \\sin{\\left(\\frac{k \\pi x}{l}\\right)} = \\varphi_2(x).\n$$\n\nNow, we have to expand both $\\varphi_1(x)$ and $\\varphi_2(x)$ into series in terms of sines only (why?). We have\n\n$$\n\\varphi_1(x) = \\sum_{k=1}^{\\infty} \\varphi_k^{(1)} \\sin{\\left(\\frac{k \\pi}{l}x\\right)}\n$$\n\nand\n\n$$\n\\varphi_2(x) = \\sum_{k=1}^{\\infty} \\varphi_k^{(2)} \\sin{\\left(\\frac{k \\pi}{l}x\\right)}.\n$$\n\nBy the Fourier series theroem of uniqueness, we get\n\n$$\nA_k = \\varphi_k^{(1)} \\quad \\text{and} \\quad B_k = \\frac{l}{ak\\pi} \\varphi_k^{(2)},\n$$\n\nor (why?)\n\n$$\nA_k = \\frac{2}{l} \\int_{0}^{l} \\varphi_1(x) \\sin{\\left(\\frac{k \\pi}{l}x\\right)} \\mathrm{d}x\n$$\n\nand\n\n$$\nB_k = \\frac{2}{ak\\pi} \\int_{0}^{l} \\varphi_2(x) \\sin{\\left(\\frac{k \\pi}{l}x\\right)} \\mathrm{d}x.\n$$\n\nWe are left with the task of the covergence of the infinite series. We have to explore the following series\n\n$$\n|u(x, t)| \\leq \\sum_{k=1}^{\\infty}(|A_k| + |B_k|),\n$$\n\n$$\n|u_t(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{ak\\pi}{l}(|A_k| + |B_k|),\n$$\n\n$$\n|u_x(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{k\\pi}{l}(|A_k| + |B_k|),\n$$\n\n$$\n|u_{tt}(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{a^2 k^2 \\pi^2}{l^2}(|A_k| + |B_k|),\n$$\n\n$$\n|u_{xx}(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{k^2 \\pi^2}{l^2}(|A_k| + |B_k|).\n$$\n\nIf the series on the right side (majorizing series) converge then the series on the left would also converge and the needed differentiation would exist. It is enough (why?) for the following series to converge\n\n$$\n\\sum_{k=1}^{\\infty} k^j \\left(|\\varphi_k^{(1)}| + \\frac{2}{ak\\pi}|\\varphi_k^{(2)}|\\right), j = 0, 1, 2.\n$$\n\nThis is possible only if \n\n$$\n\\left\\{\\begin{align*}\n\\sum_{k=1}^{\\infty} k^j |\\varphi_k^{(1)}|, \\\\\n\\sum_{k=1}^{\\infty} k^{j-1} |\\varphi_k^{(2)}|,\n\\end{align*}\\right. \\quad j = 0, 1, 2.\n$$\n\nconverge. From Calculus we know (theorem) that if $\\varphi(x)$ is $m$-times differentiable then\n\n$$\n\\sum_{k=1}^{\\infty} k^{m-1} |\\varphi_k|\n$$\n\nconvergres. Therefore, in order for all the majorzing series to converge it is enough $\\varphi_1(x)$ to be $3$-times differentiable, and $\\varphi_2(x)$ to be $2$-times differentiable.\n\nFinally, we should note a few things about the expansion of $\\varphi_1(x)$ and $\\varphi_2(x)$ into sine series. We have to note that in order to do that the function needs to be continued as an odd function which my lead to loss of the regularity of the lower derivatives. Let $\\tilde{\\varphi}_1(x)$ be the continuation of $\\varphi_1(x)$ as an odd function (see the Figure below) defined as\n\n{width=50%}\n</center>\n\n$$\n\\tilde{\\varphi}_1(x) = \\left\\{\\begin{align*}\n\\varphi_1(x), \\quad 0 \\leq x \\leq l, \\\\\n-\\varphi_1(-x), \\quad -l \\leq x \\leq 0.\n\\end{align*}\\right.\n$$\n\nHence, in order for it to be continous and continously differentibale we need to enforce the following condition\n\n$$\n\\varphi_1(0) = \\varphi_1(l) = 0.\n$$\n\nTo summarise, in order for $\\sum_{k=1}^{\\infty} \\varphi_k^{(1)} \\sin{\\left( \\frac{k\\pi}{l}x\\right)}$ to converge in $[0, l]$ it is necessary to enforce the above conditions to have zero values at both ends of the interval. As for the second derivative, if it exists it would be continuous as well. Similarly, for the third derivative to exist we enforce\n\n$$\n\\varphi_1^{\\prime\\prime}(0) = \\varphi_1^{\\prime\\prime}(l) = 0\n$$\n\nand obtain the corresponding necessary condition\n\n$$\n\\varphi_2(0) = \\varphi_2(l) = 0.\n$$\n\nFinally, after these enforced conditions we can conclude that (tehorem)\n\n$$\nu(x, t) = \\sum_{k=1}^{\\infty} \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}\n$$\n\nis a regular solution of the problem.\n\n**Physical interpretation:**\n\nIf we go back to the eigenfunction\n\n$$\nu_k(x,t) = \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi}{l}x\\right)}, \\quad k > 0, k \\in N\n$$\n\nwe can rewrite it as\n\n$$\nu_k(x,t) = \\sqrt{A_k^2 + B_k^2} \\sin{\\left(\\frac{k \\pi}{l}x\\right)} \\sin{\\left(\\frac{ak\\pi}{l}t + \\phi_k\\right)}, \\quad k \\in N,\n$$\n\nwhere\n\n$$\n\\tan{(\\phi_k)} = \\frac{A_k}{B_k}.\n$$\n\nWe can translate this as the points of the string to oscillate at the frequency $\\omega_k = \\frac{ak\\pi}{l}$ with phase $\\phi_k$. The amplitude is dependant on $x$ and is given by\n$$\nF_k = \\sqrt{A_k^2 + B_k^2} \\sin{\\left(\\frac{k\\pi}{l}x\\right)}.\n$$\n\nThe $u_k(x, t)$ waves are called **standing-waves**. Depending on the values of $k$ we have the following scenarios:\n\n- When $k = 1$ there are $2$ motionless points which are the ends of the (fixed) string\n- When $k = 2$ a third moitonless point $x = \\frac{l}{2}$ is added\n\nThese motionless points are called **nodes** of the standing wave. In general, $u_k(x, t)$ has $(k + 1)$ nodes located ate $0, \\frac{1}{k}l, \\frac{2}{k}l, ..., \\frac{k-1}{k}l, l$. The maximum amplitude is achieved in the middle points between two nodes. These points are called **crests**. The fundamental tone, or the lowest tone, has frequency of $\\omega_1 = \\frac{a\\pi}{l}$. The frequencies $\\omega_k$ are called **harmonics**, while the higher tones corresponding to $\\omega_k$, $k = 2, 3, ...$ are called **overtones**. It is quite natural to notice that the higher the value of $k$ the rapidly lower the amplitude of $u_k(x, t)$ becomes. Meaning, the effect from the higher harmonics all combined influences the quality of the sound. The below figure shows the harmonics for $k = 1, 2, 3$.\n\n{width=70%}\n\n### Example\n\nHere, we are going to show an example of a fixed string. We are going to show an animated solution with the help of Python. The fixed string problem is given by\n\n$$\n\\left\\{\\begin{aligned}\nu_{tt} = \\left(\\frac{2}{3}\\right)^2 u_{xx}, \\\\ \nu(x, 0) = \\left\\{\\begin{align*}\n\\sin^3{(\\pi x)}, \\quad 1 \\leq x \\leq3, \\\\\n0, \\quad x \\in R \\backslash [1, 3],\n\\end{align*}\\right.,\\\\\nu_t(x, 0) = 0, \\\\\nu(0, t) = u(\\pi \\sqrt{5}, t) = 0.\n\\end{aligned}\\right.\n$$\n\nUsing the $100$-th partial Fourier sum, below is shown the animated solution for $t \\in [0, 30]$.\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include code/fixed_string.py >}}\n```\n\n<iframe src=\"code/fixed_string_animation.html\" width=\"100%\" height=\"300px\" frameborder=\"0\"></iframe>\n\nTest\n\n```{python}\n#| echo: true\n#| eval: true\n#| fig-format: html\n#| output: true\nimport plotly.io as pio\nimport numpy as np\nimport pandas as pd\nimport plotly.express as px\n\npio.renderers.default = \"plotly_mimetype+notebook_connected\"\n\n# Define constants\nL = np.pi * np.sqrt(5)\na = 2 / 3\ntmax = 30\nx = np.linspace(0, L, 101)\nt = np.linspace(0, tmax, 31) # Fewer points for smoother interaction\n\n\n# Define the initial condition phi(x)\ndef phi(x):\n y = np.zeros_like(x)\n y[(1 < x) & (x < 3)] = np.sin(np.pi * x[(1 < x) & (x < 3)]) ** 3\n return y\n\n\n# Define the initial velocity psi(x)\ndef psi(x):\n return np.zeros_like(x)\n\n\n# Define the Fourier solution for u(x, t)\ndef fourier_u(x, t):\n y = np.zeros_like(x)\n for k in range(1, 101):\n Xk = np.sin(k * np.pi * x / L)\n Ak = (2 / L) * np.trapezoid(phi(x) * Xk, x)\n Bk = (2 / (a * k * np.pi)) * np.trapezoid(psi(x) * Xk, x)\n Tk = Ak * np.cos(a * k * np.pi * t / L) + Bk * np.sin(a * k * np.pi * t / L)\n y += Tk * Xk\n return y\n\n\n# Create animation data\ndata = []\nfor t_val in t:\n y = fourier_u(x, t_val)\n for x_val, y_val in zip(x, y):\n data.append({\"x\": x_val, \"y\": y_val, \"t\": f\"t = {t_val:.2f}\"})\n\n# Create DataFrame and plot\ndf = pd.DataFrame(data)\nfig = px.line(\n df,\n x=\"x\",\n y=\"y\",\n animation_frame=\"t\",\n # title=\"String Motion\",\n labels={\"x\": \"x\", \"y\": \"u(x, t)\"},\n range_x=[-0.06, L + 0.06],\n range_y=[-1.1, 1.1],\n color_discrete_sequence=[\"red\"],\n)\n\n# Add fixed points as black dots\nfixed_points = pd.DataFrame(\n {\n \"x\": [0, L],\n \"y\": [0, 0],\n }\n)\n\nfig.add_scatter(\n x=fixed_points[\"x\"],\n y=fixed_points[\"y\"],\n mode=\"markers\",\n marker=dict(color=\"black\", size=10),\n showlegend=False,\n)\n\nfig.update_layout(\n showlegend=False,\n height=280,\n margin=dict(l=10, r=30, t=30, b=10),\n updatemenus=[\n {\n \"buttons\": [\n {\n \"args\": [\n None,\n {\n \"frame\": {\"duration\": 200, \"redraw\": True},\n \"fromcurrent\": True,\n \"mode\": \"immediate\",\n \"transition\": {\"duration\": 0},\n },\n ],\n \"label\": \"Play\",\n \"method\": \"animate\",\n },\n {\n \"args\": [\n [None],\n {\n \"frame\": {\"duration\": 0, \"redraw\": True},\n \"mode\": \"immediate\",\n \"transition\": {\"duration\": 0},\n },\n ],\n \"label\": \"Pause\",\n \"method\": \"animate\",\n },\n ],\n \"type\": \"buttons\",\n \"direction\": \"left\",\n \"showactive\": True,\n \"x\": 0.2,\n \"y\": 0.3,\n \"xanchor\": \"right\",\n \"yanchor\": \"top\",\n }\n ],\n sliders=[\n {\n \"active\": 0,\n \"yanchor\": \"top\",\n \"xanchor\": \"left\",\n \"currentvalue\": {\"font\": {\"size\": 16}, \"visible\": True, \"xanchor\": \"right\"},\n \"transition\": {\"duration\": 500, \"easing\": \"cubic-in-out\"},\n \"pad\": {\"b\": 10, \"t\": 50},\n \"len\": 1,\n \"x\": 0,\n \"y\": 0,\n \"steps\": [\n {\n \"args\": [\n [f\"t = {t:.2f}\"],\n {\n \"frame\": {\n \"duration\": 500,\n \"easing\": \"cubic-in-out\",\n \"redraw\": True,\n },\n \"mode\": \"immediate\",\n \"transition\": {\"duration\": 0},\n },\n ],\n \"label\": f\"{t:.0f}\",\n \"method\": \"animate\",\n }\n for t in t\n ],\n }\n ],\n)\n\nfig.show()\n```\n\n```{python}\n#| eval: true\n#| echo: true\n#| fig-format: html\n#| output: true\nimport plotly.express as px\nimport plotly.io as pio\nimport numpy as np\nimport pandas as pd\nimport plotly.express as px\n\npio.renderers.default = \"plotly_mimetype+notebook_connected\"\n\ndf = px.data.iris()\nfig = px.scatter(df, x=\"sepal_width\", y=\"sepal_length\", \n color=\"species\", \n marginal_y=\"violin\", marginal_x=\"box\", \n trendline=\"ols\", template=\"simple_white\")\nfig.show()\n```\n\nTest\n","srcMarkdownNoYaml":"\n\nIn this post we are going to explore the Fourier method for solving the 1D wave equation. The method is more known under the name of the **method of separation of variables**. For the 1D wave equation we are going to show the application of the method to a fixed string. We are also going to attempt to outline some of the physical interpretations of the fixed string.\n\n# 1D Wave Equation\n\nThe 1D wave equation is of the form\n\n$$\nu_{tt} = a^2 u_{xx}.\n$$\n\n## Fixed String\n\nFirst, let's take a look at the model of a string with length $l$ which is also fixed at both ends:\n\n$$\n\\left\\{\\begin{aligned}\nu_{tt} = a^2 u_{xx}, \\\\ \nu(x, 0) = \\varphi_1(x),\\\\\nu_t(x, 0) = \\varphi_2(x), \\\\\nu(0, t) = u(l, t) = 0.\n\\end{aligned}\\right.\n$$\n\nA visualisation of the string can be seen in the figure below.\n\n{width=60%}\n\nWe start solving the equation by taking into account only the boundary conditions $u(0, t) = u(l, t) = 0$. The idea is to find solution $u(x, t)$ of the form\n\n$$\nu(x, t) = X(x)T(t).\n$$\n\nWe substitute this form of the solution into the wave equation and get \n\n$$\n\\frac{1}{a^2} T^{\\prime\\prime}(t)X(x) = T(t)X^{\\prime\\prime}(x),\n$$\n\nfurther divding by $X(x)T(t)$ leads to\n\n$$\n\\frac{1}{a^2} \\frac{T^{\\prime\\prime}(t)}{T(t)} = \\frac{X^{\\prime\\prime}(x)}{X(x)}.\n$$\n\nWe have two functions of independent variables which are equal. This is only possible if they are equal to the same constant. Therefore, let\n\n$$\n\\frac{1}{a^2} \\frac{T^{\\prime\\prime}(t)}{T(t)} = \\frac{X^{\\prime\\prime}(x)}{X(x)} = -\\lambda,\n$$\n\nproducing the following two equeations:\n\n$$\nT^{\\prime\\prime}(t) + a^2 \\lambda T(t) = 0\n$$\n\nand\n\n$$\\label{eq:ref}\nX^{\\prime\\prime}(x) + \\lambda X(x) = 0. \\tag{*}\n$$\n\nLet's begin with solving the second equation. The boundary conditions give\n\n$$\nX(0)T(t) = 0 \\quad \\text{and} \\quad X(l)T(t) = 0.\n$$\n\nBecause we are interested only in non-trivial solutions and thus $T \\neq 0$, we have\n\n$$\\label{eq:ref2}\nX(0) = 0 \\quad \\text{and} \\quad X(l) = 0. \\tag{**}\n$$\n\nNow, we have to find the non-trivial solutions for $X(x)$ satisfying\n\n$$\n\\left\\{\\begin{align*}\nX^{\\prime\\prime}(x) + \\lambda X(x) = 0, \\\\\nX(0) = 0, \\quad X(l) = 0.\n\\end{align*}\\right.\n$$\n\nThe above problem is an example of the so called **Sturm-Liouville problem**. In order to find the general solution of the second order linear homogeneous differential equation with constant coefficients $\\eqref{eq:ref}$ we should solve its characteristic equation\n\n$$\nr^2 + \\lambda = 0.\n$$\n\n- If $\\lambda < 0$, then $r_{1, 2} = \\pm \\sqrt{-\\lambda}$, hence the general solution is\n$$\nX(x) = c_1 e^{\\sqrt{-\\lambda}x} + c_2 e^{-\\sqrt{-\\lambda}x}\n$$\nfor some constants $c_1$ and $c_2$. In order to determine the constants we substitute the above solution into the boundary conditions $\\eqref{eq:ref2}$ and get the system\n$$\n\\left\\{\\begin{align*}\nc_1 + c_2 = 0, \\\\\nc_1 e^{\\sqrt{-\\lambda}l} + c_2 e^{-\\sqrt{-\\lambda}l} = 0. \n\\end{align*}\\right.\n$$\nThis results in $c_1 = c_2 = 0$, meaning our Sturm-Liouville problem doesn't have a non-zero solution for $\\lambda < 0$.\n\n- If $\\lambda = 0$, then $r_1 = r_2 = 0$ and the general solution is\n$$\nX(x) = c_1 + c_2 x.\n$$\nSubstituing it into the boundary conditions $\\eqref{eq:ref2}$ again lead to $c_1 = c_2 = 0$, hence no non-zero solutions of our Sturm-Liouville problem for $\\lambda \\leq 0$.\n\n- If $\\lambda > 0$, then $r_{1, 2} = \\pm i \\sqrt{\\lambda}$, and the general solution becomes\n$$\nX(x) = c_1 \\cos{\\left( \\sqrt{\\lambda} x \\right)} + c_2 \\sin{\\left(\\sqrt{\\lambda}x\\right)}.\n$$\nSubstituting into the boundary conditions $\\eqref{eq:ref2}$ results in\n$$\n\\left\\{\\begin{align*}\nc_1 = 0, \\\\\nc_2 \\sin{\\left(\\sqrt{\\lambda}l\\right)} = 0\n\\end{align*}\\right.\n$$\nIf $c_2 = 0$, then $X(x) \\equiv 0$ which is a trivial solution. Therefore, we set $c_2 \\neq 0$ and hence\n$$\n\\sin{\\left(\\sqrt{\\lambda}l\\right)} = 0,\n$$\ngiving $\\sqrt{\\lambda}l = k \\pi$, $k = \\pm 1, \\pm 2, ...$. Theerfore,\n$$\n\\lambda = \\lambda_k = \\left(\\frac{k \\pi}{l}\\right)^2,\n$$\nmeaning eigenvalues exist when $\\lambda > 0$. The eigenfunctions corresponding to the above eigenvalues are\n$$\nX_k(x) = \\sin{\\left(\\frac{k \\pi x}{l}\\right)}, \\quad k > 0, k \\in N.\n$$\n\nGoing back to $T^{\\prime\\prime}(t) + a^2 \\lambda T(t) = 0$, solving in analogical way, when $\\lambda = \\lambda_k$ the solution becomes\n\n$$\nT_k(t) = A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\n$$\n\nfor some constants $A_k$ and $B_k$. Hence,\n\n$$\nu_k(x,t) = X_k(x) T_k(t) = \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}, \\quad k > 0, k \\in N\n$$\n\nare solutions to our wave equation, also satisfying the boundary conditions. Since our equation is linear, forming a linear system with its conditions, the **principle of superposition** is valid. In other words, if $u_1, u_2, ..., u_n$ are solutions of our system, then\n\n$$\n\\alpha_1 u_1 + \\alpha_2 u_2 + ... + \\alpha_n u_n\n$$\n\nfor some constants $\\alpha_1, \\alpha_2, ..., \\alpha_n$ is also a solution of the system. But in our case we have an infinite number of functions $u_1, u_2, ...$ which satisfy the linear system. Therefore, we need the **generalised superposition principle** stating that in such case\n\n$$\nu = \\sum_n^{\\infty} \\alpha_n u_n\n$$\n\nfor some arbitrary constants $\\alpha_n$ is a solution to the system if the series converges uniformly and is twice differentiable termwise. This generalisation is a Lemma and should be prooved. The proof can be found in ...\n\nAssuming we have prooved the said Lemma, we can state that our system has a solution of the form\n\n$$\nu(x, t) = \\sum_{k=1}\n^{\\infty} u_k(x, t) = \\sum_{k=1}^{\\infty} \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}.\n$$\n\nThe next task we have to tackle is to determine the coefficients $A_k$ and $B_k$. We can achieve this by using the initial conditions \n\n$$\nu(x, 0) = \\varphi_1(x), \\quad \\text{and} \\quad u_t(x, 0) = \\varphi_2(x).\n$$\n\nWe get\n\n$$\nu(x, 0) = \\sum_{k=1}\n^{\\infty} A_k \\sin{\\left(\\frac{k \\pi x}{l}\\right)} = \\varphi_1(x)\n$$\n\nand\n\n$$\nu_t(x, 0) = \\sum_{k=1}^{\\infty} \\frac{ak\\pi}{l} B_k \\sin{\\left(\\frac{k \\pi x}{l}\\right)} = \\varphi_2(x).\n$$\n\nNow, we have to expand both $\\varphi_1(x)$ and $\\varphi_2(x)$ into series in terms of sines only (why?). We have\n\n$$\n\\varphi_1(x) = \\sum_{k=1}^{\\infty} \\varphi_k^{(1)} \\sin{\\left(\\frac{k \\pi}{l}x\\right)}\n$$\n\nand\n\n$$\n\\varphi_2(x) = \\sum_{k=1}^{\\infty} \\varphi_k^{(2)} \\sin{\\left(\\frac{k \\pi}{l}x\\right)}.\n$$\n\nBy the Fourier series theroem of uniqueness, we get\n\n$$\nA_k = \\varphi_k^{(1)} \\quad \\text{and} \\quad B_k = \\frac{l}{ak\\pi} \\varphi_k^{(2)},\n$$\n\nor (why?)\n\n$$\nA_k = \\frac{2}{l} \\int_{0}^{l} \\varphi_1(x) \\sin{\\left(\\frac{k \\pi}{l}x\\right)} \\mathrm{d}x\n$$\n\nand\n\n$$\nB_k = \\frac{2}{ak\\pi} \\int_{0}^{l} \\varphi_2(x) \\sin{\\left(\\frac{k \\pi}{l}x\\right)} \\mathrm{d}x.\n$$\n\nWe are left with the task of the covergence of the infinite series. We have to explore the following series\n\n$$\n|u(x, t)| \\leq \\sum_{k=1}^{\\infty}(|A_k| + |B_k|),\n$$\n\n$$\n|u_t(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{ak\\pi}{l}(|A_k| + |B_k|),\n$$\n\n$$\n|u_x(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{k\\pi}{l}(|A_k| + |B_k|),\n$$\n\n$$\n|u_{tt}(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{a^2 k^2 \\pi^2}{l^2}(|A_k| + |B_k|),\n$$\n\n$$\n|u_{xx}(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{k^2 \\pi^2}{l^2}(|A_k| + |B_k|).\n$$\n\nIf the series on the right side (majorizing series) converge then the series on the left would also converge and the needed differentiation would exist. It is enough (why?) for the following series to converge\n\n$$\n\\sum_{k=1}^{\\infty} k^j \\left(|\\varphi_k^{(1)}| + \\frac{2}{ak\\pi}|\\varphi_k^{(2)}|\\right), j = 0, 1, 2.\n$$\n\nThis is possible only if \n\n$$\n\\left\\{\\begin{align*}\n\\sum_{k=1}^{\\infty} k^j |\\varphi_k^{(1)}|, \\\\\n\\sum_{k=1}^{\\infty} k^{j-1} |\\varphi_k^{(2)}|,\n\\end{align*}\\right. \\quad j = 0, 1, 2.\n$$\n\nconverge. From Calculus we know (theorem) that if $\\varphi(x)$ is $m$-times differentiable then\n\n$$\n\\sum_{k=1}^{\\infty} k^{m-1} |\\varphi_k|\n$$\n\nconvergres. Therefore, in order for all the majorzing series to converge it is enough $\\varphi_1(x)$ to be $3$-times differentiable, and $\\varphi_2(x)$ to be $2$-times differentiable.\n\nFinally, we should note a few things about the expansion of $\\varphi_1(x)$ and $\\varphi_2(x)$ into sine series. We have to note that in order to do that the function needs to be continued as an odd function which my lead to loss of the regularity of the lower derivatives. Let $\\tilde{\\varphi}_1(x)$ be the continuation of $\\varphi_1(x)$ as an odd function (see the Figure below) defined as\n\n{width=50%}\n</center>\n\n$$\n\\tilde{\\varphi}_1(x) = \\left\\{\\begin{align*}\n\\varphi_1(x), \\quad 0 \\leq x \\leq l, \\\\\n-\\varphi_1(-x), \\quad -l \\leq x \\leq 0.\n\\end{align*}\\right.\n$$\n\nHence, in order for it to be continous and continously differentibale we need to enforce the following condition\n\n$$\n\\varphi_1(0) = \\varphi_1(l) = 0.\n$$\n\nTo summarise, in order for $\\sum_{k=1}^{\\infty} \\varphi_k^{(1)} \\sin{\\left( \\frac{k\\pi}{l}x\\right)}$ to converge in $[0, l]$ it is necessary to enforce the above conditions to have zero values at both ends of the interval. As for the second derivative, if it exists it would be continuous as well. Similarly, for the third derivative to exist we enforce\n\n$$\n\\varphi_1^{\\prime\\prime}(0) = \\varphi_1^{\\prime\\prime}(l) = 0\n$$\n\nand obtain the corresponding necessary condition\n\n$$\n\\varphi_2(0) = \\varphi_2(l) = 0.\n$$\n\nFinally, after these enforced conditions we can conclude that (tehorem)\n\n$$\nu(x, t) = \\sum_{k=1}^{\\infty} \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}\n$$\n\nis a regular solution of the problem.\n\n**Physical interpretation:**\n\nIf we go back to the eigenfunction\n\n$$\nu_k(x,t) = \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi}{l}x\\right)}, \\quad k > 0, k \\in N\n$$\n\nwe can rewrite it as\n\n$$\nu_k(x,t) = \\sqrt{A_k^2 + B_k^2} \\sin{\\left(\\frac{k \\pi}{l}x\\right)} \\sin{\\left(\\frac{ak\\pi}{l}t + \\phi_k\\right)}, \\quad k \\in N,\n$$\n\nwhere\n\n$$\n\\tan{(\\phi_k)} = \\frac{A_k}{B_k}.\n$$\n\nWe can translate this as the points of the string to oscillate at the frequency $\\omega_k = \\frac{ak\\pi}{l}$ with phase $\\phi_k$. The amplitude is dependant on $x$ and is given by\n$$\nF_k = \\sqrt{A_k^2 + B_k^2} \\sin{\\left(\\frac{k\\pi}{l}x\\right)}.\n$$\n\nThe $u_k(x, t)$ waves are called **standing-waves**. Depending on the values of $k$ we have the following scenarios:\n\n- When $k = 1$ there are $2$ motionless points which are the ends of the (fixed) string\n- When $k = 2$ a third moitonless point $x = \\frac{l}{2}$ is added\n\nThese motionless points are called **nodes** of the standing wave. In general, $u_k(x, t)$ has $(k + 1)$ nodes located ate $0, \\frac{1}{k}l, \\frac{2}{k}l, ..., \\frac{k-1}{k}l, l$. The maximum amplitude is achieved in the middle points between two nodes. These points are called **crests**. The fundamental tone, or the lowest tone, has frequency of $\\omega_1 = \\frac{a\\pi}{l}$. The frequencies $\\omega_k$ are called **harmonics**, while the higher tones corresponding to $\\omega_k$, $k = 2, 3, ...$ are called **overtones**. It is quite natural to notice that the higher the value of $k$ the rapidly lower the amplitude of $u_k(x, t)$ becomes. Meaning, the effect from the higher harmonics all combined influences the quality of the sound. The below figure shows the harmonics for $k = 1, 2, 3$.\n\n{width=70%}\n\n### Example\n\nHere, we are going to show an example of a fixed string. We are going to show an animated solution with the help of Python. The fixed string problem is given by\n\n$$\n\\left\\{\\begin{aligned}\nu_{tt} = \\left(\\frac{2}{3}\\right)^2 u_{xx}, \\\\ \nu(x, 0) = \\left\\{\\begin{align*}\n\\sin^3{(\\pi x)}, \\quad 1 \\leq x \\leq3, \\\\\n0, \\quad x \\in R \\backslash [1, 3],\n\\end{align*}\\right.,\\\\\nu_t(x, 0) = 0, \\\\\nu(0, t) = u(\\pi \\sqrt{5}, t) = 0.\n\\end{aligned}\\right.\n$$\n\nUsing the $100$-th partial Fourier sum, below is shown the animated solution for $t \\in [0, 30]$.\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include code/fixed_string.py >}}\n```\n\n<iframe src=\"code/fixed_string_animation.html\" width=\"100%\" height=\"300px\" frameborder=\"0\"></iframe>\n\nTest\n\n```{python}\n#| echo: true\n#| eval: true\n#| fig-format: html\n#| output: true\nimport plotly.io as pio\nimport numpy as np\nimport pandas as pd\nimport plotly.express as px\n\npio.renderers.default = \"plotly_mimetype+notebook_connected\"\n\n# Define constants\nL = np.pi * np.sqrt(5)\na = 2 / 3\ntmax = 30\nx = np.linspace(0, L, 101)\nt = np.linspace(0, tmax, 31) # Fewer points for smoother interaction\n\n\n# Define the initial condition phi(x)\ndef phi(x):\n y = np.zeros_like(x)\n y[(1 < x) & (x < 3)] = np.sin(np.pi * x[(1 < x) & (x < 3)]) ** 3\n return y\n\n\n# Define the initial velocity psi(x)\ndef psi(x):\n return np.zeros_like(x)\n\n\n# Define the Fourier solution for u(x, t)\ndef fourier_u(x, t):\n y = np.zeros_like(x)\n for k in range(1, 101):\n Xk = np.sin(k * np.pi * x / L)\n Ak = (2 / L) * np.trapezoid(phi(x) * Xk, x)\n Bk = (2 / (a * k * np.pi)) * np.trapezoid(psi(x) * Xk, x)\n Tk = Ak * np.cos(a * k * np.pi * t / L) + Bk * np.sin(a * k * np.pi * t / L)\n y += Tk * Xk\n return y\n\n\n# Create animation data\ndata = []\nfor t_val in t:\n y = fourier_u(x, t_val)\n for x_val, y_val in zip(x, y):\n data.append({\"x\": x_val, \"y\": y_val, \"t\": f\"t = {t_val:.2f}\"})\n\n# Create DataFrame and plot\ndf = pd.DataFrame(data)\nfig = px.line(\n df,\n x=\"x\",\n y=\"y\",\n animation_frame=\"t\",\n # title=\"String Motion\",\n labels={\"x\": \"x\", \"y\": \"u(x, t)\"},\n range_x=[-0.06, L + 0.06],\n range_y=[-1.1, 1.1],\n color_discrete_sequence=[\"red\"],\n)\n\n# Add fixed points as black dots\nfixed_points = pd.DataFrame(\n {\n \"x\": [0, L],\n \"y\": [0, 0],\n }\n)\n\nfig.add_scatter(\n x=fixed_points[\"x\"],\n y=fixed_points[\"y\"],\n mode=\"markers\",\n marker=dict(color=\"black\", size=10),\n showlegend=False,\n)\n\nfig.update_layout(\n showlegend=False,\n height=280,\n margin=dict(l=10, r=30, t=30, b=10),\n updatemenus=[\n {\n \"buttons\": [\n {\n \"args\": [\n None,\n {\n \"frame\": {\"duration\": 200, \"redraw\": True},\n \"fromcurrent\": True,\n \"mode\": \"immediate\",\n \"transition\": {\"duration\": 0},\n },\n ],\n \"label\": \"Play\",\n \"method\": \"animate\",\n },\n {\n \"args\": [\n [None],\n {\n \"frame\": {\"duration\": 0, \"redraw\": True},\n \"mode\": \"immediate\",\n \"transition\": {\"duration\": 0},\n },\n ],\n \"label\": \"Pause\",\n \"method\": \"animate\",\n },\n ],\n \"type\": \"buttons\",\n \"direction\": \"left\",\n \"showactive\": True,\n \"x\": 0.2,\n \"y\": 0.3,\n \"xanchor\": \"right\",\n \"yanchor\": \"top\",\n }\n ],\n sliders=[\n {\n \"active\": 0,\n \"yanchor\": \"top\",\n \"xanchor\": \"left\",\n \"currentvalue\": {\"font\": {\"size\": 16}, \"visible\": True, \"xanchor\": \"right\"},\n \"transition\": {\"duration\": 500, \"easing\": \"cubic-in-out\"},\n \"pad\": {\"b\": 10, \"t\": 50},\n \"len\": 1,\n \"x\": 0,\n \"y\": 0,\n \"steps\": [\n {\n \"args\": [\n [f\"t = {t:.2f}\"],\n {\n \"frame\": {\n \"duration\": 500,\n \"easing\": \"cubic-in-out\",\n \"redraw\": True,\n },\n \"mode\": \"immediate\",\n \"transition\": {\"duration\": 0},\n },\n ],\n \"label\": f\"{t:.0f}\",\n \"method\": \"animate\",\n }\n for t in t\n ],\n }\n ],\n)\n\nfig.show()\n```\n\n```{python}\n#| eval: true\n#| echo: true\n#| fig-format: html\n#| output: true\nimport plotly.express as px\nimport plotly.io as pio\nimport numpy as np\nimport pandas as pd\nimport plotly.express as px\n\npio.renderers.default = \"plotly_mimetype+notebook_connected\"\n\ndf = px.data.iris()\nfig = px.scatter(df, x=\"sepal_width\", y=\"sepal_length\", \n color=\"species\", \n marginal_y=\"violin\", marginal_x=\"box\", \n trendline=\"ols\", template=\"simple_white\")\nfig.show()\n```\n\nTest\n"},"formats":{"html":{"identifier":{"display-name":"HTML","target-format":"html","base-format":"html"},"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":false,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"ipynb-shell-interactivity":null,"plotly-connected":true,"engine":"jupyter"},"render":{"keep-tex":false,"keep-typ":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"inline-includes":false,"preserve-yaml":false,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-min-runs":1,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[],"notebook-links":true},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","html-math-method":"mathjax","css":["../../styles.css"],"output-file":"index.html"},"language":{"toc-title-document":"Table of contents","toc-title-website":"On this page","related-formats-title":"Other Formats","related-notebooks-title":"Notebooks","source-notebooks-prefix":"Source","other-links-title":"Other Links","code-links-title":"Code Links","launch-dev-container-title":"Launch Dev Container","launch-binder-title":"Launch Binder","article-notebook-label":"Article Notebook","notebook-preview-download":"Download Notebook","notebook-preview-download-src":"Download Source","notebook-preview-back":"Back to Article","manuscript-meca-bundle":"MECA Bundle","section-title-abstract":"Abstract","section-title-appendices":"Appendices","section-title-footnotes":"Footnotes","section-title-references":"References","section-title-reuse":"Reuse","section-title-copyright":"Copyright","section-title-citation":"Citation","appendix-attribution-cite-as":"For attribution, please cite this work as:","appendix-attribution-bibtex":"BibTeX citation:","appendix-view-license":"View License","title-block-author-single":"Author","title-block-author-plural":"Authors","title-block-affiliation-single":"Affiliation","title-block-affiliation-plural":"Affiliations","title-block-published":"Published","title-block-modified":"Modified","title-block-keywords":"Keywords","callout-tip-title":"Tip","callout-note-title":"Note","callout-warning-title":"Warning","callout-important-title":"Important","callout-caution-title":"Caution","code-summary":"Code","code-tools-menu-caption":"Code","code-tools-show-all-code":"Show All Code","code-tools-hide-all-code":"Hide All Code","code-tools-view-source":"View Source","code-tools-source-code":"Source Code","tools-share":"Share","tools-download":"Download","code-line":"Line","code-lines":"Lines","copy-button-tooltip":"Copy to Clipboard","copy-button-tooltip-success":"Copied!","repo-action-links-edit":"Edit this page","repo-action-links-source":"View source","repo-action-links-issue":"Report an issue","back-to-top":"Back to top","search-no-results-text":"No results","search-matching-documents-text":"matching documents","search-copy-link-title":"Copy link to search","search-hide-matches-text":"Hide additional matches","search-more-match-text":"more match in this document","search-more-matches-text":"more matches in this document","search-clear-button-title":"Clear","search-text-placeholder":"","search-detached-cancel-button-title":"Cancel","search-submit-button-title":"Submit","search-label":"Search","toggle-section":"Toggle section","toggle-sidebar":"Toggle sidebar navigation","toggle-dark-mode":"Toggle dark mode","toggle-reader-mode":"Toggle reader mode","toggle-navigation":"Toggle navigation","crossref-fig-title":"Figure","crossref-tbl-title":"Table","crossref-lst-title":"Listing","crossref-thm-title":"Theorem","crossref-lem-title":"Lemma","crossref-cor-title":"Corollary","crossref-prp-title":"Proposition","crossref-cnj-title":"Conjecture","crossref-def-title":"Definition","crossref-exm-title":"Example","crossref-exr-title":"Exercise","crossref-ch-prefix":"Chapter","crossref-apx-prefix":"Appendix","crossref-sec-prefix":"Section","crossref-eq-prefix":"Equation","crossref-lof-title":"List of Figures","crossref-lot-title":"List of Tables","crossref-lol-title":"List of Listings","environment-proof-title":"Proof","environment-remark-title":"Remark","environment-solution-title":"Solution","listing-page-order-by":"Order By","listing-page-order-by-default":"Default","listing-page-order-by-date-asc":"Oldest","listing-page-order-by-date-desc":"Newest","listing-page-order-by-number-desc":"High to Low","listing-page-order-by-number-asc":"Low to High","listing-page-field-date":"Date","listing-page-field-title":"Title","listing-page-field-description":"Description","listing-page-field-author":"Author","listing-page-field-filename":"File Name","listing-page-field-filemodified":"Modified","listing-page-field-subtitle":"Subtitle","listing-page-field-readingtime":"Reading Time","listing-page-field-wordcount":"Word Count","listing-page-field-categories":"Categories","listing-page-minutes-compact":"{0} min","listing-page-category-all":"All","listing-page-no-matches":"No matching items","listing-page-words":"{0} words","listing-page-filter":"Filter","draft":"Draft"},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.6.39","theme":"flatly","title-block-banner":true,"title":"Fourier Method for the 1D Wave Equation: Fixed String","author":"Joana Levtcheva","date":"2025-01-04","categories":["mathematics","pde"],"draft":false},"extensions":{"book":{"multiFile":true}}}},"draft":false,"projectFormats":["html"]}
|
src/.quarto/idx/posts/2025-01-06-chebyshev-polynomials/index.qmd.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"title":"Chebyshev Polynomials: Part 1","markdown":{"yaml":{"title":"Chebyshev Polynomials: Part 1","author":"Joana Levtcheva","date":"2025-01-06","categories":["mathematics","polynomials"],"draft":false},"headingText":"Chebyshev Polynomials of the First Kind","containsRefs":false,"markdown":"\n\nChebyshev polynomials are a sequence of orthogonal polynomials that play a central role in numerical analysis, approximation theory, and applied mathematics. They are named after the Russian mathematician Pafnuty Chebyshev and come in two primary types: Chebyshev polynomials of the first kind ($T_n(x)$) and Chebyshev polynomials of the second kind ($U_n(x)$). In this post we are going to focus on the Chebyshev polynomials of the first kind.\n\n\nThere are many different ways to define the Chebyshev polynomials of the first kind. The one that seems most logical to me and most useful in terms of outlining various properties of the polynomials is\n\n$$\\label{eq:1}\nT_{n}(x) = \\cos{\\left(n \\arccos{x}\\right)}, \\quad x \\in [-1, 1].\\tag{1}\n$$\n\nLooking at \\eqref{eq:1} it is not obvious why $T_{n}(x)$ would be a polynomial. In order to show it is indeed a polynomial let's recall the de Moivre's formula\n\n$$\n\\cos{(n \\theta)} + i\\sin{(n \\theta)} = (\\cos(\\theta) + i \\sin{\\theta})^n.\n$$\n\nWe can apply binomial expansion and take the real part from it to obatin\n\n$$\\label{eq:2}\n\\cos(n \\theta) = \\sum_{k = 0}^{\\frac{n}{2}} C(n, 2k) (-1)^k \\cos^{n - 2k}\\theta \\sin^{2k}{\\theta}. \\tag{2}\n$$\n\nwhere \n\n$$\nC(n, 2k) = \\frac{n!}{(2k)!(n-2k)!}, \\quad n \\geq 2k, k \\in N, n \\in N\n$$ \n\ndenotes the binomal coefficient. We can also notice that\n\n$$\n\\sin^{2k}\\theta = (\\sin^2{\\theta})^k = (1 - \\cos^2{\\theta})^k,\n$$\n\nshowing that \\eqref{eq:2} is a polynomial of $\\cos{\\theta}$ of degree $n$. Now, let\n\n$$\n\\theta = \\arccos{x},\n$$\n\nand by utilising $\\cos{\\left(\\arccos{x}\\right)} = x$ we get\n\n$$\nx = \\cos{\\theta}.\n$$\n\nThis transforms \\eqref{eq:1} to \n\n$$\\label{eq:3}\nT_{n}(\\cos{\\theta}) = \\cos{\\left(n \\theta\\right)} \\tag{3}\n$$\n\nwhich we already showed is a polynomial of degree $n$. From here, because $\\cos(.)$ is an even function, we can note that\n\n$$\nT_{n}(x) = T_{-n}(x) = T_{|n|}(x.)\n$$\n\nFrom \\eqref{eq:3} it is also obvious that the values of $T_n$ in the interval $[-1, 1]$ are bounded in $[-1, 1]$ because of the cosine.\n\n## Chebyshev Nodes of the First Kind\n\nBefore we continue with exploring the roots of the polynomials, let's recall some trigonometry. \n\n---\n\nThe **unit circle** is a circle with a radius of 1, centered at the origin of the Cartesian coordinate system. Below is shown part of the unit circle corresponding to the region from $0$ to $\\frac{\\pi}{2}$.\n\n\n\nThe cosine of an angle $\\theta$ corresponds to the $x$-coordinate of the point where the terminal side of the angle (measured counterclockwise from the positive $x$-axis) intersects the unit circle. In other words, $\\cos(\\theta)$ gives the horizontal distance from the origin to this intersection point. \n\nThe **arccosine** is the inverse function of cosine, and it maps a cosine value back to its corresponding angle in the range $[0, \\pi]$ radians. For a given $x$-coordinate on the unit circle, the arccosine gives the angle $\\theta$ such that $\\cos(\\theta) = x$, meaning\n\n$$\n\\arccos(x) = \\theta, \\quad \\text{where } \\theta \\in [0, \\pi].\n$$\n\nMoreover, a **radian** is defined as the angle subtended at the center of a circle by an arc whose length is equal to the radius of the circle. For any circle, the length of an arc $s$ is given by\n\n$$\ns = r \\cdot \\theta,\n$$\n\nwhere $r$ is the radius of the circle, $\\theta$ is the angle subtended by the arc at the center. This means that on the unit circle the length of the arc equals the measure of the angle in radians because $r = 1$, and hence\n\n$$\ns = \\theta.\n$$\n\n---\n\nNow, let's find the roots of the polynomial $T_{n}(x)$. If we take the definition in \\eqref{eq:1} we have to solve\n\n$$\n\\cos{\\left(n \\arccos{x}\\right)} = 0, k \\in N.\n$$\n\nThe solutions in the interval $(-1, 1)$ are given by\n\n$$\nx_k = \\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n.\n$$\n\nThese roots are known as the **Chebyshev nodes of the first kind**, or the **Chebyshev zeros**. If we are working with an arbitrary interval $(a, b)$ the affine transformation \n\n$$\nx_k = \\frac{a + b}{2} + \\frac{b - a}{2}\\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n\n$$\n\nis needed. From the cosine properties we can also note that the nodes are symmetric with respect to the midpoint of the interval, and that the extrema of $T_n(x)$ over the interval $[-1, 1]$ alternate between $-1$ and $1$. Also, a very useful fact is that these nodes are used in polynomial interpolation to minimize the **Runge phenomenon**.\n\nIn the figure below we have shown the roots of $T_{8}(x)$ in blue. We have also built the perpendiculars from the roots to their interesction with the upper half of the unit circle, and marked these points in red.\n\n{ width=45% }{ width=45% }\n\nLooking at the figure we can notice that the arc lengths between the red points seem to be of the same length. Let's show that this is indeed the truth.\n\nWe showed the roots are the cosine functions $\\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n$. Thus, in the unit circle we have that the length of the corresponding arcs are equal to $\\left( \\frac{2k - 1}{2n}\\pi \\right), n \\in N, k = 1, 2, ...n$. Let's take two red points which are direct neighbours, or in other words let's take two red points corresponding to the randomly chosen $m$ and $m + 1$ roots, $m \\in k = \\{1, 2, ..., n\\}$. If we subtract them we are going to determine the length of the arc between them. We have\n\n$$\n\\frac{2(m + 1) - 1}{2n}\\pi - \\frac{2m - 1}{2n}\\pi = \\frac{\\pi}{n},\n$$\n\nmeaning that between every two nodes the arc length is equal and has a value of $\\frac{\\pi}{n}$. A polynomial of degree $n$ has $n$ roots, which in our case are in the open interval $(-1, 1)$, meaning the arcs corresponding to every two neighbouring roots are $n - 1$, and the two arcs between the $x$-axis and the first and last roots due to the symmetry of roots have lenghts of\n\n$$\n\\frac{1}{2}\\left(\\pi - \\frac{n-1}{n}\\pi\\right) = \\frac{\\pi}{2n}.\n$$\n\n## Recurrence relation\n\nThis is probably a bit out of nowhere, but let's take a look at the following trigonometric identity\n\n$$\\label{eq:4}\n\\cos{\\left((n + 1)\\theta\\right)} + \\cos{\\left((n - 1)\\theta\\right)} = 2 \\cos{(\\theta)} \\cos{(n\\theta)},\\tag{4}\n$$\n\nand show that the left side indeed is equal to the right one. We are going to need the following two fundamental formulas of angle addition in trigonometry\n\n$$\n\\cos{(\\alpha + \\beta)} = \\cos{\\alpha} \\cos{\\beta} - \\sin{\\alpha} \\sin{\\beta},\n$$\n\nand\n\n$$\n\\cos{(\\alpha - \\beta)} = \\cos{\\alpha} \\cos{\\beta} + \\sin{\\alpha} \\sin{\\beta}.\n$$\n\nIn our case we have\n\n$$\n\\cos{\\left((n + 1)\\theta\\right)} = \\cos{\\left(n\\theta + \\theta\\right)} = \\cos{(n\\theta)} \\cos{\\theta} - \\sin{(n\\theta)} \\sin{\\theta},\n$$\n\nand\n\n$$\n\\cos{\\left((n - 1)\\theta\\right)} = \\cos{\\left(n\\theta - \\theta\\right)} = \\cos{(n\\theta)} \\cos{\\theta} + \\sin{(n\\theta)} \\sin{\\theta}.\n$$\n\nAdding the above equations leads to the wanted result.\n\nNow, we can see that the terms of \\eqref{eq:4} are exactly in the form of the right side of \\eqref{eq:1}, \\eqref{eq:3}, hence we get\n\n$$\nT_{n + 1}(x) + T_{n - 1}(x) = 2T_{n}(x)T_{1}(x),\n$$\n\nor we get the useful **recurrence relation**\n\n$$\\label{eq:5}\nT_{n + 1}(x) - 2xT_{n}(x) + T_{n - 1}(x) = 0.\\tag{5}\n$$\n\nThis relation along with adding $T_{0}(x) = 1$ and $T_{1}(x) = x$ is another famous way to define the Chebyshev polynomials of the first kind, or\n\n$$\n\\left\\{\\begin{align*}\nT_{0}(x) = 1, \\\\\nT_{1}(x) = x, \\\\\nT_{n + 1}(x) - 2xT_{n}(x) + T_{n - 1}(x) = 0.\n\\end{align*}\\right.\\label{eq:6}\\tag{6}\n$$\n\nLet's write the first $6$ polynomials by using \\eqref{eq:6}:\n\n$$\n\\left\\{\\begin{align*}\nT_{0}(x) = 1, \\quad \\text{(even)}\\\\\nT_{1}(x) = x, \\quad \\text{(odd)}\\\\\nT_{2}(x) = 2x^2 - 1, \\quad \\text{(even)}\\\\\nT_{3}(x) = 4x^3 - 3x, \\quad \\text{(odd)}\\\\\nT_{4}(x) = 8x^4 - 8x^2 + 1, \\quad \\text{(even)}\\\\\nT_{5}(x) = 16x^5 - 20x^3 + 5x. \\quad \\text{(odd)}\n\\end{align*}\\right.\n$$\n\nWe can notice that\n\n$$\nT_{k}(x) = 2^{k-1}x^k + ...,\n$$\n\nand $T_{k}(x)$ is alternating between an even and an odd polynomial depending on whether $k$ is even or odd respectively.\n\nBefore we continue with some visualisations and more facts, let's mention that an interesting way to represent the recurrence relation \\eqref{eq:5} is via the determinant\n\n$$\nT_{k}(x) = \\det \\begin{bmatrix}\nx & 1 & 0 & \\dots & 0 \\\\\n1 & 2x & 1 & \\ddots & \\vdots \\\\\n0 & 1 & 2x & \\ddots & 0 \\\\\n\\vdots & \\ddots & \\ddots & \\ddots & 1 \\\\\n0 & \\dots & 0 & 1 & 2x\n\\end{bmatrix}.\n$$\n\nNow, let's visualise the first $8$ polynomials.\n\n\n\nBut what can we notice if we stack them together?\n\n\n\nIt is quite obvious that at the roots of the $N$-th Chebyshev polynomial there is an **aliasing** effect, meaning higher order polynomials look like lower order ones. We can formally show it by fixing $N$, at the roots $x_k$ of $T_{N}(x) = 0$, and using the Chebyshev identity\n\n$$\n\\cos{\\left((m + N)\\theta\\right)} + \\cos{\\left((m - N)\\theta\\right)} = 2\\cos{(m\\theta)}\\cos{(N\\theta)},\n$$\n\nor equivalently\n\n$$\nT_{m + N}(x) + T_{m - N}(x) = 2T_{m}(x)T_{N}(x).\n$$\n\nNow, having $T_{N}(x) = 0$ leads to\n\n$$\nT_{m + N}(x) = -T_{m - N}(x).\n$$\n\nIf we consecutevly set $m = N$, $m = 2N$, ..., $m = 6N$, etc. we would get\n\n$$\n\\left\\{\\begin{align*}\nT_{2N}(x_k) = -T_{0}(x_k) = -1, \\\\\nT_{3N}(x_k) = 0, \\\\\nT_{4N}(x_k) = 1, \\\\\nT_{5N}(x_k) = 0, \\\\\nT_{6N}(x_k) = -1, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nWe can safely say that any higher-order Chebyshev polynomial $T_{N}(x)$ can be reduced to a lower-order $j, 0 \\leq j \\leq N$ Chebyshev polynomial at the sample points $x_k$ which are the roots of $T_{N}(x)$. In the figure below we attempt to visualise this statement.\n\n\n\nThe horizontal axis represents the order of Chebyshev polynomials, and the blue wavy line represents a \"folded ribbon\". Think of it as taking the sequence of polynomial orders and folding it back and forth. This folding happens at specific points where higher-order polynomials can be reduced to lower-order ones, which are the red **x** marks showing the sample points: the roots of $T_n(x)$. The key insight is that at these special sample points, we don't need to work with the higher-order polynomials because we can use equivalent lower-order ones instead. This is incredibly useful in numerical computations as it can help reduce computational complexity, and makes the Chebyshev polynomials very computationally efficient.\n\nLet's illustarte this with a simple example. Let $N = 2$, then for even $m$ we have\n\n$$\n\\left\\{\\begin{align*}\nT_{4}(x_k) = -T_{0}(x_k) = -1, \\\\\nT_{6}(x_k) = - T_{2}(x_k) = 0, \\\\\nT_{8}(x_k) = - T_{4}(x_k) = 1, \\\\\nT_{10}(x_k) = -T_{6}(x_k) = 0, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nIn the figure below we can see the even polynomials and that indeed $T_{10}(x)$ behaves like $-T_{6}(x)$ which behaves like $T_{2}(x)$ at the roots having value $0$, $T_{8}(x)$ behaves like $-T_{4}(x)$ at the roots with value $1$ as in $T_{0}(x)$, $T_{6}(x)$ behaves like $-T_{2}(x)$ with value $0$, and $T_{4}(x)$ behaves like $-T_{0}(x)$ with value $-1$.\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include code/chebyshev_polynomials_aliasing_even.py >}}\n```\n\n\n\nFor odd $m$ we have\n$$\n\\left\\{\\begin{align*}\nT_{3}(x_k) = - T_{1}(x_k) = - x\\\\\nT_{5}(x_k) = - T_{3}(x_k) = x\\\\\nT_{7}(x_k) = - T_{5}(x_k) = -x, \\\\\nT_{9}(x_k) = - T_{7}(x_k) = x, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nIn the figure below we can see the odd polynomials and the aliasing as in the previous example.\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include code/chebyshev_polynomials_aliasing_odd.py >}}\n```\n\n\n\n## Radial Plots\n\nAn interesting plot can be observed by plotting $T_n(x)$ radially. This means that instead of evaluating the polynomials over $[-1, 1]$ in a Cartesian plane we are evaluating them at $\\frac{\\theta}{\\pi} - 1$, and plotting $r = n + T_n(\\frac{\\theta}{\\pi} - 1)$ on polar axes. In other words, the input domain has been shifted and extended, and the results are drawn as radial distances $r$ around a circle defined by $\\theta$. This creates a polar visualization where each $n$ produces a distinct spiral-like ornament. We are also filling in the areas between the curves for a visual effect.\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include code/polar_plot.py >}}\n```\n\n{ width=50% }{ width=41% }\n\nMore visualusations can be achieved by doing other domain changes. They can be seen below.\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\nIn a separate post, Chebyshev Polynomials, Part 2, we are going to explore the Chebyshev polynomials of the second kind, and their relations to the polynomials of the first kind.\n","srcMarkdownNoYaml":"\n\nChebyshev polynomials are a sequence of orthogonal polynomials that play a central role in numerical analysis, approximation theory, and applied mathematics. They are named after the Russian mathematician Pafnuty Chebyshev and come in two primary types: Chebyshev polynomials of the first kind ($T_n(x)$) and Chebyshev polynomials of the second kind ($U_n(x)$). In this post we are going to focus on the Chebyshev polynomials of the first kind.\n\n# Chebyshev Polynomials of the First Kind\n\nThere are many different ways to define the Chebyshev polynomials of the first kind. The one that seems most logical to me and most useful in terms of outlining various properties of the polynomials is\n\n$$\\label{eq:1}\nT_{n}(x) = \\cos{\\left(n \\arccos{x}\\right)}, \\quad x \\in [-1, 1].\\tag{1}\n$$\n\nLooking at \\eqref{eq:1} it is not obvious why $T_{n}(x)$ would be a polynomial. In order to show it is indeed a polynomial let's recall the de Moivre's formula\n\n$$\n\\cos{(n \\theta)} + i\\sin{(n \\theta)} = (\\cos(\\theta) + i \\sin{\\theta})^n.\n$$\n\nWe can apply binomial expansion and take the real part from it to obatin\n\n$$\\label{eq:2}\n\\cos(n \\theta) = \\sum_{k = 0}^{\\frac{n}{2}} C(n, 2k) (-1)^k \\cos^{n - 2k}\\theta \\sin^{2k}{\\theta}. \\tag{2}\n$$\n\nwhere \n\n$$\nC(n, 2k) = \\frac{n!}{(2k)!(n-2k)!}, \\quad n \\geq 2k, k \\in N, n \\in N\n$$ \n\ndenotes the binomal coefficient. We can also notice that\n\n$$\n\\sin^{2k}\\theta = (\\sin^2{\\theta})^k = (1 - \\cos^2{\\theta})^k,\n$$\n\nshowing that \\eqref{eq:2} is a polynomial of $\\cos{\\theta}$ of degree $n$. Now, let\n\n$$\n\\theta = \\arccos{x},\n$$\n\nand by utilising $\\cos{\\left(\\arccos{x}\\right)} = x$ we get\n\n$$\nx = \\cos{\\theta}.\n$$\n\nThis transforms \\eqref{eq:1} to \n\n$$\\label{eq:3}\nT_{n}(\\cos{\\theta}) = \\cos{\\left(n \\theta\\right)} \\tag{3}\n$$\n\nwhich we already showed is a polynomial of degree $n$. From here, because $\\cos(.)$ is an even function, we can note that\n\n$$\nT_{n}(x) = T_{-n}(x) = T_{|n|}(x.)\n$$\n\nFrom \\eqref{eq:3} it is also obvious that the values of $T_n$ in the interval $[-1, 1]$ are bounded in $[-1, 1]$ because of the cosine.\n\n## Chebyshev Nodes of the First Kind\n\nBefore we continue with exploring the roots of the polynomials, let's recall some trigonometry. \n\n---\n\nThe **unit circle** is a circle with a radius of 1, centered at the origin of the Cartesian coordinate system. Below is shown part of the unit circle corresponding to the region from $0$ to $\\frac{\\pi}{2}$.\n\n\n\nThe cosine of an angle $\\theta$ corresponds to the $x$-coordinate of the point where the terminal side of the angle (measured counterclockwise from the positive $x$-axis) intersects the unit circle. In other words, $\\cos(\\theta)$ gives the horizontal distance from the origin to this intersection point. \n\nThe **arccosine** is the inverse function of cosine, and it maps a cosine value back to its corresponding angle in the range $[0, \\pi]$ radians. For a given $x$-coordinate on the unit circle, the arccosine gives the angle $\\theta$ such that $\\cos(\\theta) = x$, meaning\n\n$$\n\\arccos(x) = \\theta, \\quad \\text{where } \\theta \\in [0, \\pi].\n$$\n\nMoreover, a **radian** is defined as the angle subtended at the center of a circle by an arc whose length is equal to the radius of the circle. For any circle, the length of an arc $s$ is given by\n\n$$\ns = r \\cdot \\theta,\n$$\n\nwhere $r$ is the radius of the circle, $\\theta$ is the angle subtended by the arc at the center. This means that on the unit circle the length of the arc equals the measure of the angle in radians because $r = 1$, and hence\n\n$$\ns = \\theta.\n$$\n\n---\n\nNow, let's find the roots of the polynomial $T_{n}(x)$. If we take the definition in \\eqref{eq:1} we have to solve\n\n$$\n\\cos{\\left(n \\arccos{x}\\right)} = 0, k \\in N.\n$$\n\nThe solutions in the interval $(-1, 1)$ are given by\n\n$$\nx_k = \\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n.\n$$\n\nThese roots are known as the **Chebyshev nodes of the first kind**, or the **Chebyshev zeros**. If we are working with an arbitrary interval $(a, b)$ the affine transformation \n\n$$\nx_k = \\frac{a + b}{2} + \\frac{b - a}{2}\\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n\n$$\n\nis needed. From the cosine properties we can also note that the nodes are symmetric with respect to the midpoint of the interval, and that the extrema of $T_n(x)$ over the interval $[-1, 1]$ alternate between $-1$ and $1$. Also, a very useful fact is that these nodes are used in polynomial interpolation to minimize the **Runge phenomenon**.\n\nIn the figure below we have shown the roots of $T_{8}(x)$ in blue. We have also built the perpendiculars from the roots to their interesction with the upper half of the unit circle, and marked these points in red.\n\n{ width=45% }{ width=45% }\n\nLooking at the figure we can notice that the arc lengths between the red points seem to be of the same length. Let's show that this is indeed the truth.\n\nWe showed the roots are the cosine functions $\\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n$. Thus, in the unit circle we have that the length of the corresponding arcs are equal to $\\left( \\frac{2k - 1}{2n}\\pi \\right), n \\in N, k = 1, 2, ...n$. Let's take two red points which are direct neighbours, or in other words let's take two red points corresponding to the randomly chosen $m$ and $m + 1$ roots, $m \\in k = \\{1, 2, ..., n\\}$. If we subtract them we are going to determine the length of the arc between them. We have\n\n$$\n\\frac{2(m + 1) - 1}{2n}\\pi - \\frac{2m - 1}{2n}\\pi = \\frac{\\pi}{n},\n$$\n\nmeaning that between every two nodes the arc length is equal and has a value of $\\frac{\\pi}{n}$. A polynomial of degree $n$ has $n$ roots, which in our case are in the open interval $(-1, 1)$, meaning the arcs corresponding to every two neighbouring roots are $n - 1$, and the two arcs between the $x$-axis and the first and last roots due to the symmetry of roots have lenghts of\n\n$$\n\\frac{1}{2}\\left(\\pi - \\frac{n-1}{n}\\pi\\right) = \\frac{\\pi}{2n}.\n$$\n\n## Recurrence relation\n\nThis is probably a bit out of nowhere, but let's take a look at the following trigonometric identity\n\n$$\\label{eq:4}\n\\cos{\\left((n + 1)\\theta\\right)} + \\cos{\\left((n - 1)\\theta\\right)} = 2 \\cos{(\\theta)} \\cos{(n\\theta)},\\tag{4}\n$$\n\nand show that the left side indeed is equal to the right one. We are going to need the following two fundamental formulas of angle addition in trigonometry\n\n$$\n\\cos{(\\alpha + \\beta)} = \\cos{\\alpha} \\cos{\\beta} - \\sin{\\alpha} \\sin{\\beta},\n$$\n\nand\n\n$$\n\\cos{(\\alpha - \\beta)} = \\cos{\\alpha} \\cos{\\beta} + \\sin{\\alpha} \\sin{\\beta}.\n$$\n\nIn our case we have\n\n$$\n\\cos{\\left((n + 1)\\theta\\right)} = \\cos{\\left(n\\theta + \\theta\\right)} = \\cos{(n\\theta)} \\cos{\\theta} - \\sin{(n\\theta)} \\sin{\\theta},\n$$\n\nand\n\n$$\n\\cos{\\left((n - 1)\\theta\\right)} = \\cos{\\left(n\\theta - \\theta\\right)} = \\cos{(n\\theta)} \\cos{\\theta} + \\sin{(n\\theta)} \\sin{\\theta}.\n$$\n\nAdding the above equations leads to the wanted result.\n\nNow, we can see that the terms of \\eqref{eq:4} are exactly in the form of the right side of \\eqref{eq:1}, \\eqref{eq:3}, hence we get\n\n$$\nT_{n + 1}(x) + T_{n - 1}(x) = 2T_{n}(x)T_{1}(x),\n$$\n\nor we get the useful **recurrence relation**\n\n$$\\label{eq:5}\nT_{n + 1}(x) - 2xT_{n}(x) + T_{n - 1}(x) = 0.\\tag{5}\n$$\n\nThis relation along with adding $T_{0}(x) = 1$ and $T_{1}(x) = x$ is another famous way to define the Chebyshev polynomials of the first kind, or\n\n$$\n\\left\\{\\begin{align*}\nT_{0}(x) = 1, \\\\\nT_{1}(x) = x, \\\\\nT_{n + 1}(x) - 2xT_{n}(x) + T_{n - 1}(x) = 0.\n\\end{align*}\\right.\\label{eq:6}\\tag{6}\n$$\n\nLet's write the first $6$ polynomials by using \\eqref{eq:6}:\n\n$$\n\\left\\{\\begin{align*}\nT_{0}(x) = 1, \\quad \\text{(even)}\\\\\nT_{1}(x) = x, \\quad \\text{(odd)}\\\\\nT_{2}(x) = 2x^2 - 1, \\quad \\text{(even)}\\\\\nT_{3}(x) = 4x^3 - 3x, \\quad \\text{(odd)}\\\\\nT_{4}(x) = 8x^4 - 8x^2 + 1, \\quad \\text{(even)}\\\\\nT_{5}(x) = 16x^5 - 20x^3 + 5x. \\quad \\text{(odd)}\n\\end{align*}\\right.\n$$\n\nWe can notice that\n\n$$\nT_{k}(x) = 2^{k-1}x^k + ...,\n$$\n\nand $T_{k}(x)$ is alternating between an even and an odd polynomial depending on whether $k$ is even or odd respectively.\n\nBefore we continue with some visualisations and more facts, let's mention that an interesting way to represent the recurrence relation \\eqref{eq:5} is via the determinant\n\n$$\nT_{k}(x) = \\det \\begin{bmatrix}\nx & 1 & 0 & \\dots & 0 \\\\\n1 & 2x & 1 & \\ddots & \\vdots \\\\\n0 & 1 & 2x & \\ddots & 0 \\\\\n\\vdots & \\ddots & \\ddots & \\ddots & 1 \\\\\n0 & \\dots & 0 & 1 & 2x\n\\end{bmatrix}.\n$$\n\nNow, let's visualise the first $8$ polynomials.\n\n\n\nBut what can we notice if we stack them together?\n\n\n\nIt is quite obvious that at the roots of the $N$-th Chebyshev polynomial there is an **aliasing** effect, meaning higher order polynomials look like lower order ones. We can formally show it by fixing $N$, at the roots $x_k$ of $T_{N}(x) = 0$, and using the Chebyshev identity\n\n$$\n\\cos{\\left((m + N)\\theta\\right)} + \\cos{\\left((m - N)\\theta\\right)} = 2\\cos{(m\\theta)}\\cos{(N\\theta)},\n$$\n\nor equivalently\n\n$$\nT_{m + N}(x) + T_{m - N}(x) = 2T_{m}(x)T_{N}(x).\n$$\n\nNow, having $T_{N}(x) = 0$ leads to\n\n$$\nT_{m + N}(x) = -T_{m - N}(x).\n$$\n\nIf we consecutevly set $m = N$, $m = 2N$, ..., $m = 6N$, etc. we would get\n\n$$\n\\left\\{\\begin{align*}\nT_{2N}(x_k) = -T_{0}(x_k) = -1, \\\\\nT_{3N}(x_k) = 0, \\\\\nT_{4N}(x_k) = 1, \\\\\nT_{5N}(x_k) = 0, \\\\\nT_{6N}(x_k) = -1, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nWe can safely say that any higher-order Chebyshev polynomial $T_{N}(x)$ can be reduced to a lower-order $j, 0 \\leq j \\leq N$ Chebyshev polynomial at the sample points $x_k$ which are the roots of $T_{N}(x)$. In the figure below we attempt to visualise this statement.\n\n\n\nThe horizontal axis represents the order of Chebyshev polynomials, and the blue wavy line represents a \"folded ribbon\". Think of it as taking the sequence of polynomial orders and folding it back and forth. This folding happens at specific points where higher-order polynomials can be reduced to lower-order ones, which are the red **x** marks showing the sample points: the roots of $T_n(x)$. The key insight is that at these special sample points, we don't need to work with the higher-order polynomials because we can use equivalent lower-order ones instead. This is incredibly useful in numerical computations as it can help reduce computational complexity, and makes the Chebyshev polynomials very computationally efficient.\n\nLet's illustarte this with a simple example. Let $N = 2$, then for even $m$ we have\n\n$$\n\\left\\{\\begin{align*}\nT_{4}(x_k) = -T_{0}(x_k) = -1, \\\\\nT_{6}(x_k) = - T_{2}(x_k) = 0, \\\\\nT_{8}(x_k) = - T_{4}(x_k) = 1, \\\\\nT_{10}(x_k) = -T_{6}(x_k) = 0, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nIn the figure below we can see the even polynomials and that indeed $T_{10}(x)$ behaves like $-T_{6}(x)$ which behaves like $T_{2}(x)$ at the roots having value $0$, $T_{8}(x)$ behaves like $-T_{4}(x)$ at the roots with value $1$ as in $T_{0}(x)$, $T_{6}(x)$ behaves like $-T_{2}(x)$ with value $0$, and $T_{4}(x)$ behaves like $-T_{0}(x)$ with value $-1$.\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include code/chebyshev_polynomials_aliasing_even.py >}}\n```\n\n\n\nFor odd $m$ we have\n$$\n\\left\\{\\begin{align*}\nT_{3}(x_k) = - T_{1}(x_k) = - x\\\\\nT_{5}(x_k) = - T_{3}(x_k) = x\\\\\nT_{7}(x_k) = - T_{5}(x_k) = -x, \\\\\nT_{9}(x_k) = - T_{7}(x_k) = x, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nIn the figure below we can see the odd polynomials and the aliasing as in the previous example.\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include code/chebyshev_polynomials_aliasing_odd.py >}}\n```\n\n\n\n## Radial Plots\n\nAn interesting plot can be observed by plotting $T_n(x)$ radially. This means that instead of evaluating the polynomials over $[-1, 1]$ in a Cartesian plane we are evaluating them at $\\frac{\\theta}{\\pi} - 1$, and plotting $r = n + T_n(\\frac{\\theta}{\\pi} - 1)$ on polar axes. In other words, the input domain has been shifted and extended, and the results are drawn as radial distances $r$ around a circle defined by $\\theta$. This creates a polar visualization where each $n$ produces a distinct spiral-like ornament. We are also filling in the areas between the curves for a visual effect.\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include code/polar_plot.py >}}\n```\n\n{ width=50% }{ width=41% }\n\nMore visualusations can be achieved by doing other domain changes. They can be seen below.\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\nIn a separate post, Chebyshev Polynomials, Part 2, we are going to explore the Chebyshev polynomials of the second kind, and their relations to the polynomials of the first kind.\n"},"formats":{"html":{"identifier":{"display-name":"HTML","target-format":"html","base-format":"html"},"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":false,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"ipynb-shell-interactivity":null,"plotly-connected":true,"engine":"jupyter"},"render":{"keep-tex":false,"keep-typ":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"inline-includes":false,"preserve-yaml":false,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-min-runs":1,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[],"notebook-links":true},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","html-math-method":"mathjax","css":["../../styles.css"],"output-file":"index.html"},"language":{"toc-title-document":"Table of contents","toc-title-website":"On this page","related-formats-title":"Other Formats","related-notebooks-title":"Notebooks","source-notebooks-prefix":"Source","other-links-title":"Other Links","code-links-title":"Code Links","launch-dev-container-title":"Launch Dev Container","launch-binder-title":"Launch Binder","article-notebook-label":"Article Notebook","notebook-preview-download":"Download Notebook","notebook-preview-download-src":"Download Source","notebook-preview-back":"Back to Article","manuscript-meca-bundle":"MECA Bundle","section-title-abstract":"Abstract","section-title-appendices":"Appendices","section-title-footnotes":"Footnotes","section-title-references":"References","section-title-reuse":"Reuse","section-title-copyright":"Copyright","section-title-citation":"Citation","appendix-attribution-cite-as":"For attribution, please cite this work as:","appendix-attribution-bibtex":"BibTeX citation:","appendix-view-license":"View License","title-block-author-single":"Author","title-block-author-plural":"Authors","title-block-affiliation-single":"Affiliation","title-block-affiliation-plural":"Affiliations","title-block-published":"Published","title-block-modified":"Modified","title-block-keywords":"Keywords","callout-tip-title":"Tip","callout-note-title":"Note","callout-warning-title":"Warning","callout-important-title":"Important","callout-caution-title":"Caution","code-summary":"Code","code-tools-menu-caption":"Code","code-tools-show-all-code":"Show All Code","code-tools-hide-all-code":"Hide All Code","code-tools-view-source":"View Source","code-tools-source-code":"Source Code","tools-share":"Share","tools-download":"Download","code-line":"Line","code-lines":"Lines","copy-button-tooltip":"Copy to Clipboard","copy-button-tooltip-success":"Copied!","repo-action-links-edit":"Edit this page","repo-action-links-source":"View source","repo-action-links-issue":"Report an issue","back-to-top":"Back to top","search-no-results-text":"No results","search-matching-documents-text":"matching documents","search-copy-link-title":"Copy link to search","search-hide-matches-text":"Hide additional matches","search-more-match-text":"more match in this document","search-more-matches-text":"more matches in this document","search-clear-button-title":"Clear","search-text-placeholder":"","search-detached-cancel-button-title":"Cancel","search-submit-button-title":"Submit","search-label":"Search","toggle-section":"Toggle section","toggle-sidebar":"Toggle sidebar navigation","toggle-dark-mode":"Toggle dark mode","toggle-reader-mode":"Toggle reader mode","toggle-navigation":"Toggle navigation","crossref-fig-title":"Figure","crossref-tbl-title":"Table","crossref-lst-title":"Listing","crossref-thm-title":"Theorem","crossref-lem-title":"Lemma","crossref-cor-title":"Corollary","crossref-prp-title":"Proposition","crossref-cnj-title":"Conjecture","crossref-def-title":"Definition","crossref-exm-title":"Example","crossref-exr-title":"Exercise","crossref-ch-prefix":"Chapter","crossref-apx-prefix":"Appendix","crossref-sec-prefix":"Section","crossref-eq-prefix":"Equation","crossref-lof-title":"List of Figures","crossref-lot-title":"List of Tables","crossref-lol-title":"List of Listings","environment-proof-title":"Proof","environment-remark-title":"Remark","environment-solution-title":"Solution","listing-page-order-by":"Order By","listing-page-order-by-default":"Default","listing-page-order-by-date-asc":"Oldest","listing-page-order-by-date-desc":"Newest","listing-page-order-by-number-desc":"High to Low","listing-page-order-by-number-asc":"Low to High","listing-page-field-date":"Date","listing-page-field-title":"Title","listing-page-field-description":"Description","listing-page-field-author":"Author","listing-page-field-filename":"File Name","listing-page-field-filemodified":"Modified","listing-page-field-subtitle":"Subtitle","listing-page-field-readingtime":"Reading Time","listing-page-field-wordcount":"Word Count","listing-page-field-categories":"Categories","listing-page-minutes-compact":"{0} min","listing-page-category-all":"All","listing-page-no-matches":"No matching items","listing-page-words":"{0} words","listing-page-filter":"Filter","draft":"Draft"},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.6.39","theme":"flatly","title-block-banner":true,"title":"Chebyshev Polynomials: Part 1","author":"Joana Levtcheva","date":"2025-01-06","categories":["mathematics","polynomials"],"draft":false},"extensions":{"book":{"multiFile":true}}}},"draft":false,"projectFormats":["html"]}
|
src/.quarto/idx/posts/fourier/index.qmd.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"title":"Fourier Method for the Wave Equation","markdown":{"yaml":{"title":"Fourier Method for the Wave Equation","author":"JoJo","date":"2024-12-18","categories":["mathematics"],"image":"membrane.png","draft":true},"headingText":"1D Wave Equation","containsRefs":false,"markdown":"\n\nIn this post we are going to explore the Fourier method for solving the 1D and 2D wave equations. The method is more known under the name of the method of separation of variables. For the 1D wave equation we are going to show the application of the method to a fixed string, and for the 2D wave equation we are going to apply the method to a rectangular membrane and a circular membrane. We are also going to attempt to outline the physical interpretations of all scenarios.\n\n\n## Fixed String\n\nFirst, let's take a look at the model of a string with length $l$ which is also fixed at both ends:\n\n\\begin{equation}\n\\left\\{\\begin{aligned}\nu_{tt} = a^2 u_{xx}, \\\\ \nu(x, 0) = \\varphi_1(x),\\\\\nu_t(x, 0) = \\varphi_2(x), \\\\\nu(0, t) = u(l, t) = 0.\n\\end{aligned}\\right.\n\\end{equation}\n\nWe start solving the equation by taking into account only the boundary conditions $u(0, t) = u(l, t) = 0$. The idea is to find solution $u(x, t)$ of the form\n\n$$\nu(x, t) = X(x)T(t).\n$$\n\nWe substitute this form of the solution into the wave equation and get \n\n$$\n\\frac{1}{a^2} T^{\\prime\\prime}(t)X(x) = T(t)X^{\\prime\\prime}(x),\n$$\n\nfurther divding by $X(x)T(t)$ leads to\n\n$$\n\\frac{1}{a^2} \\frac{T^{\\prime\\prime}(t)}{T(t)} = \\frac{X^{\\prime\\prime}(x)}{X(x)}.\n$$\n\nWe have two functions of independent variables which are equal. This is only possible if they are equal to the same constant. Therefore, let\n\n$$\n\\frac{1}{a^2} \\frac{T^{\\prime\\prime}(t)}{T(t)} = \\frac{X^{\\prime\\prime}(x)}{X(x)} = -\\lambda,\n$$\n\nproducing the following two equeations:\n\n$$\nT^{\\prime\\prime}(t) + a^2 \\lambda T(t) = 0\n$$\n\nand\n\n$$\\label{eq:ref}\nX^{\\prime\\prime}(x) + \\lambda X(x) = 0. \\tag{*}\n$$\n\nLet's begin with solving the second equation. The boundary conditions give\n\n$$\nX(0)T(t) = 0 \\quad \\text{and} \\quad X(l)T(t) = 0.\n$$\n\nBecause we are interested only in non-trivial solutions and thus $T \\neq 0$, we have\n\n$$\\label{eq:ref2}\nX(0) = 0 \\quad \\text{and} \\quad X(l) = 0. \\tag{**}\n$$\n\nNow, we have to find the non-trivial solutions for $X(x)$ satisfying\n\n$$\n\\left\\{\\begin{align*}\nX^{\\prime\\prime}(x) + \\lambda X(x) = 0, \\\\\nX(0) = 0, \\quad X(l) = 0.\n\\end{align*}\\right.\n$$\n\nThe above problem is an example of the so called **Sturm-Liouville problem**. In order to find the general solution of the second order linear homogeneous differential equation with constant coefficients $\\eqref{eq:ref}$ we should solve its characteristic equation\n\n$$\nr^2 + \\lambda = 0.\n$$\n\n- If $\\lambda < 0$, then $r_{1, 2} = \\pm \\sqrt{-\\lambda}$, hence the general solution is\n$$\nX(x) = c_1 e^{\\sqrt{-\\lambda}x} + c_2 e^{-\\sqrt{-\\lambda}x}\n$$\nfor some constants $c_1$ and $c_2$. In order to determine the constants we substitute the above solution into the boundary conditions $\\eqref{eq:ref2}$ and get the system\n$$\n\\left\\{\\begin{align*}\nc_1 + c_2 = 0, \\\\\nc_1 e^{\\sqrt{-\\lambda}l} + c_2 e^{-\\sqrt{-\\lambda}l} = 0. \n\\end{align*}\\right.\n$$\nThis results in $c_1 = c_2 = 0$, meaning our Sturm-Liouville problem doesn't have a non-zero solution for $\\lambda < 0$.\n\n- If $\\lambda = 0$, then $r_1 = r_2 = 0$ and the general solution is\n$$\nX(x) = c_1 + c_2 x.\n$$\nSubstituing it into the boundary conditions $\\eqref{eq:ref2}$ again lead to $c_1 = c_2 = 0$, hence no non-zero solutions of our Sturm-Liouville problem for $\\lambda \\leq 0$.\n\n- If $\\lambda > 0$, then $r_{1, 2} = \\pm i \\sqrt{\\lambda}$, and the general solution becomes\n$$\nX(x) = c_1 \\cos{\\left( \\sqrt{\\lambda} x \\right)} + c_2 \\sin{\\left(\\sqrt{\\lambda}x\\right)}.\n$$\nSubstituting into the boundary conditions $\\eqref{eq:ref2}$ results in\n$$\n\\left\\{\\begin{align*}\nc_1 = 0, \\\\\nc_2 \\sin{\\left(\\sqrt{\\lambda}l\\right)} = 0\n\\end{align*}\\right.\n$$\nIf $c_2 = 0$, then $X(x) \\equiv 0$ which is a trivial solution. Therefore, we set $c_2 \\neq 0$ and hence\n$$\n\\sin{\\left(\\sqrt{\\lambda}l\\right)} = 0,\n$$\ngiving $\\sqrt{\\lambda}l = k \\pi$, $k = \\pm 1, \\pm 2, ...$. Theerfore,\n$$\n\\lambda = \\lambda_k = \\left(\\frac{k \\pi}{l}\\right)^2,\n$$\nmeaning eigenvalues exist when $\\lambda > 0$. The eigenfunctions corresponding to the above eigenvalues are\n$$\nX_k(x) = \\sin{\\left(\\frac{k \\pi x}{l}\\right)}, \\quad k > 0, k \\in N.\n$$\n\nGoing back to $T^{\\prime\\prime}(t) + a^2 \\lambda T(t) = 0$, solving in analogical way, when $\\lambda = \\lambda_k$ the solution becomes\n\n$$\nT_k(t) = A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\n$$\n\nfor some constants $A_k$ and $B_k$. Hence,\n\n$$\nu_k(x,t) = X_k(x) T_k(t) = \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}, \\quad k > 0, k \\in N\n$$\n\nare solutions to our wave equation, also satisfying the boundary conditions. Since our equation is linear, forming a linear system with its conditions, the **principle of superposition** is valid. In other words, if $u_1, u_2, ..., u_n$ are solutions of our system, then\n\n$$\n\\alpha_1 u_1 + \\alpha_2 u_2 + ... + \\alpha_n u_n\n$$\n\nfor some constants $\\alpha_1, \\alpha_2, ..., \\alpha_n$ is also a solution of the system. But in our case we have an infinite number of functions $u_1, u_2, ...$ which satisfy the linear system. Therefore, we need the **generalised superposition principle** stating that in such case\n\n$$\nu = \\sum_n^{\\infty} \\alpha_n u_n\n$$\n\nfor some arbitrary constants $\\alpha_n$ is a solution to the system if the series converges uniformly and is twice differentiable termwise. This generalisation is a Lemma and should be prooved. The proof can be found in ...\n\nAssuming we have prooved the said Lemma, we can state that our system has a solution of the form\n\n$$\nu(x, t) = \\sum_{k=1}\n^{\\infty} u_k(x, t) = \\sum_{k=1}^{\\infty} \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}.\n$$\n\nThe next task we have to tackle is to determine the coefficients $A_k$ and $B_k$. We can achieve this by using the initial conditions \n\n$$\nu(x, 0) = \\varphi_1(x), \\quad \\text{and} \\quad u_t(x, 0) = \\varphi_2(x).\n$$\n\nWe get\n\n$$\nu(x, 0) = \\sum_{k=1}\n^{\\infty} A_k \\sin{\\left(\\frac{k \\pi x}{l}\\right)} = \\varphi_1(x)\n$$\n\nand\n\n$$\nu_t(x, 0) = \\sum_{k=1}^{\\infty} \\frac{ak\\pi}{l} B_k \\sin{\\left(\\frac{k \\pi x}{l}\\right)} = \\varphi_2(x).\n$$\n\nNow, we have to expand both $\\varphi_1(x)$ and $\\varphi_2(x)$ into series in terms of sines only (why?). We have\n\n$$\n\\varphi_1(x) = \\sum_{k=1}^{\\infty} \\varphi_k^{(1)} \\sin{\\left(\\frac{k \\pi}{l}x\\right)}\n$$\n\nand\n\n$$\n\\varphi_2(x) = \\sum_{k=1}^{\\infty} \\varphi_k^{(2)} \\sin{\\left(\\frac{k \\pi}{l}x\\right)}.\n$$\n\nBy the Fourier series theroem of uniqueness, we get\n\n$$\nA_k = \\varphi_k^{(1)} \\quad \\text{and} \\quad B_k = \\frac{l}{ak\\pi} \\varphi_k^{(2)},\n$$\n\nor (why?)\n\n$$\nA_k = \\frac{2}{l} \\int_{0}^{l} \\varphi_1(x) \\sin{\\left(\\frac{k \\pi}{l}x\\right)} \\mathrm{d}x\n$$\n\nand\n\n$$\nB_k = \\frac{2}{ak\\pi} \\int_{0}^{l} \\varphi_2(x) \\sin{\\left(\\frac{k \\pi}{l}x\\right)} \\mathrm{d}x.\n$$\n\nWe are left with the task of the covergence of the infinite series. We have to explore the following series\n\n$$\n|u(x, t)| \\leq \\sum_{k=1}^{\\infty}(|A_k| + |B_k|),\n$$\n\n$$\n|u_t(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{ak\\pi}{l}(|A_k| + |B_k|),\n$$\n\n$$\n|u_x(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{k\\pi}{l}(|A_k| + |B_k|),\n$$\n\n$$\n|u_{tt}(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{a^2 k^2 \\pi^2}{l^2}(|A_k| + |B_k|),\n$$\n\n$$\n|u_{xx}(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{k^2 \\pi^2}{l^2}(|A_k| + |B_k|).\n$$\n\nIf the series on the right side (majorizing series) converge then the series on the left would also converge and the needed differentiation would exist. It is enough (why?) for the following series to converge\n\n$$\n\\sum_{k=1}^{\\infty} k^j \\left(|\\varphi_k^{(1)}| + \\frac{2}{ak\\pi}|\\varphi_k^{(2)}|\\right), j = 0, 1, 2.\n$$\n\nThis is possible only if \n\n$$\n\\left\\{\\begin{align*}\n\\sum_{k=1}^{\\infty} k^j |\\varphi_k^{(1)}|, \\\\\n\\sum_{k=1}^{\\infty} k^{j-1} |\\varphi_k^{(2)}|,\n\\end{align*}\\right. \\quad j = 0, 1, 2.\n$$\n\nconverge. From Calculus we know (theorem) that if $\\varphi(x)$ is $m$-times differentiable then\n\n$$\n\\sum_{k=1}^{\\infty} k^{m-1} |\\varphi_k|\n$$\n\nconvergres. Therefore, in order for all the majorzing series to converge it is enough $\\varphi_1(x)$ to be $3$-times differentiable, and $\\varphi_2(x)$ to be $2$-times differentiable.\n\nFinally, we should note a few things about the expansion of $\\varphi_1(x)$ and $\\varphi_2(x)$ into sine series. We have to note that in order to do that the function needs to be continued as an odd function which my lead to loss of the regularity of the lower derivatives. Let $\\tilde{\\varphi}_1(x)$ be the continuation of $\\varphi_1(x)$ as an odd function (see the Figure below) defined as\n\n<center>\n{width=50%}\n</center>\n\n$$\n\\tilde{\\varphi}_1(x) = \\left\\{\\begin{align*}\n\\varphi_1(x), \\quad 0 \\leq x \\leq l, \\\\\n-\\varphi_1(-x), \\quad -l \\leq x \\leq 0.\n\\end{align*}\\right.\n$$\n\nHence, in order for it to be continous and continously differentibale we need to enforce the following condition\n\n$$\n\\varphi_1(0) = \\varphi_1(l) = 0.\n$$\n\nTo summarise, in order for $\\sum_{k=1}^{\\infty} \\varphi_k^{(1)} \\sin{\\left( \\frac{k\\pi}{l}x\\right)}$ to converge in $[0, l]$ it is necessary to enforce the above conditions to have zero values at both ends of the interval. As for the second derivative, if it exists it would be continuous as well. Similarly, for the third derivative to exist we enforce\n\n$$\n\\varphi_1^{\\prime\\prime}(0) = \\varphi_1^{\\prime\\prime}(l) = 0\n$$\n\nand obtain the corresponding necessary condition\n\n$$\n\\varphi_2(0) = \\varphi_2(l) = 0.\n$$\n\nFinally, after these enforced conditions we can conclude that (tehorem)\n\n$$\nu(x, t) = \\sum_{k=1}^{\\infty} \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}\n$$\n\nis a regular solution of the problem.\n\n**Physical interpretation:** TBD\n\n# 2D Wave Equation\n\n## Rectangular Membrane\n\nTBD\n\n## Circular Membrane\n\nTBD\n","srcMarkdownNoYaml":"\n\nIn this post we are going to explore the Fourier method for solving the 1D and 2D wave equations. The method is more known under the name of the method of separation of variables. For the 1D wave equation we are going to show the application of the method to a fixed string, and for the 2D wave equation we are going to apply the method to a rectangular membrane and a circular membrane. We are also going to attempt to outline the physical interpretations of all scenarios.\n\n# 1D Wave Equation\n\n## Fixed String\n\nFirst, let's take a look at the model of a string with length $l$ which is also fixed at both ends:\n\n\\begin{equation}\n\\left\\{\\begin{aligned}\nu_{tt} = a^2 u_{xx}, \\\\ \nu(x, 0) = \\varphi_1(x),\\\\\nu_t(x, 0) = \\varphi_2(x), \\\\\nu(0, t) = u(l, t) = 0.\n\\end{aligned}\\right.\n\\end{equation}\n\nWe start solving the equation by taking into account only the boundary conditions $u(0, t) = u(l, t) = 0$. The idea is to find solution $u(x, t)$ of the form\n\n$$\nu(x, t) = X(x)T(t).\n$$\n\nWe substitute this form of the solution into the wave equation and get \n\n$$\n\\frac{1}{a^2} T^{\\prime\\prime}(t)X(x) = T(t)X^{\\prime\\prime}(x),\n$$\n\nfurther divding by $X(x)T(t)$ leads to\n\n$$\n\\frac{1}{a^2} \\frac{T^{\\prime\\prime}(t)}{T(t)} = \\frac{X^{\\prime\\prime}(x)}{X(x)}.\n$$\n\nWe have two functions of independent variables which are equal. This is only possible if they are equal to the same constant. Therefore, let\n\n$$\n\\frac{1}{a^2} \\frac{T^{\\prime\\prime}(t)}{T(t)} = \\frac{X^{\\prime\\prime}(x)}{X(x)} = -\\lambda,\n$$\n\nproducing the following two equeations:\n\n$$\nT^{\\prime\\prime}(t) + a^2 \\lambda T(t) = 0\n$$\n\nand\n\n$$\\label{eq:ref}\nX^{\\prime\\prime}(x) + \\lambda X(x) = 0. \\tag{*}\n$$\n\nLet's begin with solving the second equation. The boundary conditions give\n\n$$\nX(0)T(t) = 0 \\quad \\text{and} \\quad X(l)T(t) = 0.\n$$\n\nBecause we are interested only in non-trivial solutions and thus $T \\neq 0$, we have\n\n$$\\label{eq:ref2}\nX(0) = 0 \\quad \\text{and} \\quad X(l) = 0. \\tag{**}\n$$\n\nNow, we have to find the non-trivial solutions for $X(x)$ satisfying\n\n$$\n\\left\\{\\begin{align*}\nX^{\\prime\\prime}(x) + \\lambda X(x) = 0, \\\\\nX(0) = 0, \\quad X(l) = 0.\n\\end{align*}\\right.\n$$\n\nThe above problem is an example of the so called **Sturm-Liouville problem**. In order to find the general solution of the second order linear homogeneous differential equation with constant coefficients $\\eqref{eq:ref}$ we should solve its characteristic equation\n\n$$\nr^2 + \\lambda = 0.\n$$\n\n- If $\\lambda < 0$, then $r_{1, 2} = \\pm \\sqrt{-\\lambda}$, hence the general solution is\n$$\nX(x) = c_1 e^{\\sqrt{-\\lambda}x} + c_2 e^{-\\sqrt{-\\lambda}x}\n$$\nfor some constants $c_1$ and $c_2$. In order to determine the constants we substitute the above solution into the boundary conditions $\\eqref{eq:ref2}$ and get the system\n$$\n\\left\\{\\begin{align*}\nc_1 + c_2 = 0, \\\\\nc_1 e^{\\sqrt{-\\lambda}l} + c_2 e^{-\\sqrt{-\\lambda}l} = 0. \n\\end{align*}\\right.\n$$\nThis results in $c_1 = c_2 = 0$, meaning our Sturm-Liouville problem doesn't have a non-zero solution for $\\lambda < 0$.\n\n- If $\\lambda = 0$, then $r_1 = r_2 = 0$ and the general solution is\n$$\nX(x) = c_1 + c_2 x.\n$$\nSubstituing it into the boundary conditions $\\eqref{eq:ref2}$ again lead to $c_1 = c_2 = 0$, hence no non-zero solutions of our Sturm-Liouville problem for $\\lambda \\leq 0$.\n\n- If $\\lambda > 0$, then $r_{1, 2} = \\pm i \\sqrt{\\lambda}$, and the general solution becomes\n$$\nX(x) = c_1 \\cos{\\left( \\sqrt{\\lambda} x \\right)} + c_2 \\sin{\\left(\\sqrt{\\lambda}x\\right)}.\n$$\nSubstituting into the boundary conditions $\\eqref{eq:ref2}$ results in\n$$\n\\left\\{\\begin{align*}\nc_1 = 0, \\\\\nc_2 \\sin{\\left(\\sqrt{\\lambda}l\\right)} = 0\n\\end{align*}\\right.\n$$\nIf $c_2 = 0$, then $X(x) \\equiv 0$ which is a trivial solution. Therefore, we set $c_2 \\neq 0$ and hence\n$$\n\\sin{\\left(\\sqrt{\\lambda}l\\right)} = 0,\n$$\ngiving $\\sqrt{\\lambda}l = k \\pi$, $k = \\pm 1, \\pm 2, ...$. Theerfore,\n$$\n\\lambda = \\lambda_k = \\left(\\frac{k \\pi}{l}\\right)^2,\n$$\nmeaning eigenvalues exist when $\\lambda > 0$. The eigenfunctions corresponding to the above eigenvalues are\n$$\nX_k(x) = \\sin{\\left(\\frac{k \\pi x}{l}\\right)}, \\quad k > 0, k \\in N.\n$$\n\nGoing back to $T^{\\prime\\prime}(t) + a^2 \\lambda T(t) = 0$, solving in analogical way, when $\\lambda = \\lambda_k$ the solution becomes\n\n$$\nT_k(t) = A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\n$$\n\nfor some constants $A_k$ and $B_k$. Hence,\n\n$$\nu_k(x,t) = X_k(x) T_k(t) = \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}, \\quad k > 0, k \\in N\n$$\n\nare solutions to our wave equation, also satisfying the boundary conditions. Since our equation is linear, forming a linear system with its conditions, the **principle of superposition** is valid. In other words, if $u_1, u_2, ..., u_n$ are solutions of our system, then\n\n$$\n\\alpha_1 u_1 + \\alpha_2 u_2 + ... + \\alpha_n u_n\n$$\n\nfor some constants $\\alpha_1, \\alpha_2, ..., \\alpha_n$ is also a solution of the system. But in our case we have an infinite number of functions $u_1, u_2, ...$ which satisfy the linear system. Therefore, we need the **generalised superposition principle** stating that in such case\n\n$$\nu = \\sum_n^{\\infty} \\alpha_n u_n\n$$\n\nfor some arbitrary constants $\\alpha_n$ is a solution to the system if the series converges uniformly and is twice differentiable termwise. This generalisation is a Lemma and should be prooved. The proof can be found in ...\n\nAssuming we have prooved the said Lemma, we can state that our system has a solution of the form\n\n$$\nu(x, t) = \\sum_{k=1}\n^{\\infty} u_k(x, t) = \\sum_{k=1}^{\\infty} \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}.\n$$\n\nThe next task we have to tackle is to determine the coefficients $A_k$ and $B_k$. We can achieve this by using the initial conditions \n\n$$\nu(x, 0) = \\varphi_1(x), \\quad \\text{and} \\quad u_t(x, 0) = \\varphi_2(x).\n$$\n\nWe get\n\n$$\nu(x, 0) = \\sum_{k=1}\n^{\\infty} A_k \\sin{\\left(\\frac{k \\pi x}{l}\\right)} = \\varphi_1(x)\n$$\n\nand\n\n$$\nu_t(x, 0) = \\sum_{k=1}^{\\infty} \\frac{ak\\pi}{l} B_k \\sin{\\left(\\frac{k \\pi x}{l}\\right)} = \\varphi_2(x).\n$$\n\nNow, we have to expand both $\\varphi_1(x)$ and $\\varphi_2(x)$ into series in terms of sines only (why?). We have\n\n$$\n\\varphi_1(x) = \\sum_{k=1}^{\\infty} \\varphi_k^{(1)} \\sin{\\left(\\frac{k \\pi}{l}x\\right)}\n$$\n\nand\n\n$$\n\\varphi_2(x) = \\sum_{k=1}^{\\infty} \\varphi_k^{(2)} \\sin{\\left(\\frac{k \\pi}{l}x\\right)}.\n$$\n\nBy the Fourier series theroem of uniqueness, we get\n\n$$\nA_k = \\varphi_k^{(1)} \\quad \\text{and} \\quad B_k = \\frac{l}{ak\\pi} \\varphi_k^{(2)},\n$$\n\nor (why?)\n\n$$\nA_k = \\frac{2}{l} \\int_{0}^{l} \\varphi_1(x) \\sin{\\left(\\frac{k \\pi}{l}x\\right)} \\mathrm{d}x\n$$\n\nand\n\n$$\nB_k = \\frac{2}{ak\\pi} \\int_{0}^{l} \\varphi_2(x) \\sin{\\left(\\frac{k \\pi}{l}x\\right)} \\mathrm{d}x.\n$$\n\nWe are left with the task of the covergence of the infinite series. We have to explore the following series\n\n$$\n|u(x, t)| \\leq \\sum_{k=1}^{\\infty}(|A_k| + |B_k|),\n$$\n\n$$\n|u_t(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{ak\\pi}{l}(|A_k| + |B_k|),\n$$\n\n$$\n|u_x(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{k\\pi}{l}(|A_k| + |B_k|),\n$$\n\n$$\n|u_{tt}(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{a^2 k^2 \\pi^2}{l^2}(|A_k| + |B_k|),\n$$\n\n$$\n|u_{xx}(x, t)| \\leq \\sum_{k=1}^{\\infty}\\frac{k^2 \\pi^2}{l^2}(|A_k| + |B_k|).\n$$\n\nIf the series on the right side (majorizing series) converge then the series on the left would also converge and the needed differentiation would exist. It is enough (why?) for the following series to converge\n\n$$\n\\sum_{k=1}^{\\infty} k^j \\left(|\\varphi_k^{(1)}| + \\frac{2}{ak\\pi}|\\varphi_k^{(2)}|\\right), j = 0, 1, 2.\n$$\n\nThis is possible only if \n\n$$\n\\left\\{\\begin{align*}\n\\sum_{k=1}^{\\infty} k^j |\\varphi_k^{(1)}|, \\\\\n\\sum_{k=1}^{\\infty} k^{j-1} |\\varphi_k^{(2)}|,\n\\end{align*}\\right. \\quad j = 0, 1, 2.\n$$\n\nconverge. From Calculus we know (theorem) that if $\\varphi(x)$ is $m$-times differentiable then\n\n$$\n\\sum_{k=1}^{\\infty} k^{m-1} |\\varphi_k|\n$$\n\nconvergres. Therefore, in order for all the majorzing series to converge it is enough $\\varphi_1(x)$ to be $3$-times differentiable, and $\\varphi_2(x)$ to be $2$-times differentiable.\n\nFinally, we should note a few things about the expansion of $\\varphi_1(x)$ and $\\varphi_2(x)$ into sine series. We have to note that in order to do that the function needs to be continued as an odd function which my lead to loss of the regularity of the lower derivatives. Let $\\tilde{\\varphi}_1(x)$ be the continuation of $\\varphi_1(x)$ as an odd function (see the Figure below) defined as\n\n<center>\n{width=50%}\n</center>\n\n$$\n\\tilde{\\varphi}_1(x) = \\left\\{\\begin{align*}\n\\varphi_1(x), \\quad 0 \\leq x \\leq l, \\\\\n-\\varphi_1(-x), \\quad -l \\leq x \\leq 0.\n\\end{align*}\\right.\n$$\n\nHence, in order for it to be continous and continously differentibale we need to enforce the following condition\n\n$$\n\\varphi_1(0) = \\varphi_1(l) = 0.\n$$\n\nTo summarise, in order for $\\sum_{k=1}^{\\infty} \\varphi_k^{(1)} \\sin{\\left( \\frac{k\\pi}{l}x\\right)}$ to converge in $[0, l]$ it is necessary to enforce the above conditions to have zero values at both ends of the interval. As for the second derivative, if it exists it would be continuous as well. Similarly, for the third derivative to exist we enforce\n\n$$\n\\varphi_1^{\\prime\\prime}(0) = \\varphi_1^{\\prime\\prime}(l) = 0\n$$\n\nand obtain the corresponding necessary condition\n\n$$\n\\varphi_2(0) = \\varphi_2(l) = 0.\n$$\n\nFinally, after these enforced conditions we can conclude that (tehorem)\n\n$$\nu(x, t) = \\sum_{k=1}^{\\infty} \\left(A_k \\cos{\\left(\\frac{ak\\pi}{l}t\\right)} + B_k \\sin{\\left(\\frac{ak\\pi}{l}t\\right)}\\right) \\sin{\\left(\\frac{k \\pi x}{l}\\right)}\n$$\n\nis a regular solution of the problem.\n\n**Physical interpretation:** TBD\n\n# 2D Wave Equation\n\n## Rectangular Membrane\n\nTBD\n\n## Circular Membrane\n\nTBD\n"},"formats":{"html":{"identifier":{"display-name":"HTML","target-format":"html","base-format":"html"},"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":false,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"ipynb-shell-interactivity":null,"plotly-connected":true,"engine":"markdown"},"render":{"keep-tex":false,"keep-typ":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"inline-includes":false,"preserve-yaml":false,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-min-runs":1,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[],"notebook-links":true},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","html-math-method":"mathjax","css":["../../styles.css"],"output-file":"index.html"},"language":{"toc-title-document":"Table of contents","toc-title-website":"On this page","related-formats-title":"Other Formats","related-notebooks-title":"Notebooks","source-notebooks-prefix":"Source","other-links-title":"Other Links","code-links-title":"Code Links","launch-dev-container-title":"Launch Dev Container","launch-binder-title":"Launch Binder","article-notebook-label":"Article Notebook","notebook-preview-download":"Download Notebook","notebook-preview-download-src":"Download Source","notebook-preview-back":"Back to Article","manuscript-meca-bundle":"MECA Bundle","section-title-abstract":"Abstract","section-title-appendices":"Appendices","section-title-footnotes":"Footnotes","section-title-references":"References","section-title-reuse":"Reuse","section-title-copyright":"Copyright","section-title-citation":"Citation","appendix-attribution-cite-as":"For attribution, please cite this work as:","appendix-attribution-bibtex":"BibTeX citation:","appendix-view-license":"View License","title-block-author-single":"Author","title-block-author-plural":"Authors","title-block-affiliation-single":"Affiliation","title-block-affiliation-plural":"Affiliations","title-block-published":"Published","title-block-modified":"Modified","title-block-keywords":"Keywords","callout-tip-title":"Tip","callout-note-title":"Note","callout-warning-title":"Warning","callout-important-title":"Important","callout-caution-title":"Caution","code-summary":"Code","code-tools-menu-caption":"Code","code-tools-show-all-code":"Show All Code","code-tools-hide-all-code":"Hide All Code","code-tools-view-source":"View Source","code-tools-source-code":"Source Code","tools-share":"Share","tools-download":"Download","code-line":"Line","code-lines":"Lines","copy-button-tooltip":"Copy to Clipboard","copy-button-tooltip-success":"Copied!","repo-action-links-edit":"Edit this page","repo-action-links-source":"View source","repo-action-links-issue":"Report an issue","back-to-top":"Back to top","search-no-results-text":"No results","search-matching-documents-text":"matching documents","search-copy-link-title":"Copy link to search","search-hide-matches-text":"Hide additional matches","search-more-match-text":"more match in this document","search-more-matches-text":"more matches in this document","search-clear-button-title":"Clear","search-text-placeholder":"","search-detached-cancel-button-title":"Cancel","search-submit-button-title":"Submit","search-label":"Search","toggle-section":"Toggle section","toggle-sidebar":"Toggle sidebar navigation","toggle-dark-mode":"Toggle dark mode","toggle-reader-mode":"Toggle reader mode","toggle-navigation":"Toggle navigation","crossref-fig-title":"Figure","crossref-tbl-title":"Table","crossref-lst-title":"Listing","crossref-thm-title":"Theorem","crossref-lem-title":"Lemma","crossref-cor-title":"Corollary","crossref-prp-title":"Proposition","crossref-cnj-title":"Conjecture","crossref-def-title":"Definition","crossref-exm-title":"Example","crossref-exr-title":"Exercise","crossref-ch-prefix":"Chapter","crossref-apx-prefix":"Appendix","crossref-sec-prefix":"Section","crossref-eq-prefix":"Equation","crossref-lof-title":"List of Figures","crossref-lot-title":"List of Tables","crossref-lol-title":"List of Listings","environment-proof-title":"Proof","environment-remark-title":"Remark","environment-solution-title":"Solution","listing-page-order-by":"Order By","listing-page-order-by-default":"Default","listing-page-order-by-date-asc":"Oldest","listing-page-order-by-date-desc":"Newest","listing-page-order-by-number-desc":"High to Low","listing-page-order-by-number-asc":"Low to High","listing-page-field-date":"Date","listing-page-field-title":"Title","listing-page-field-description":"Description","listing-page-field-author":"Author","listing-page-field-filename":"File Name","listing-page-field-filemodified":"Modified","listing-page-field-subtitle":"Subtitle","listing-page-field-readingtime":"Reading Time","listing-page-field-wordcount":"Word Count","listing-page-field-categories":"Categories","listing-page-minutes-compact":"{0} min","listing-page-category-all":"All","listing-page-no-matches":"No matching items","listing-page-words":"{0} words","listing-page-filter":"Filter","draft":"Draft"},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.6.39","theme":"flatly","title-block-banner":true,"title":"Fourier Method for the Wave Equation","author":"JoJo","date":"2024-12-18","categories":["mathematics"],"image":"membrane.png","draft":true},"extensions":{"book":{"multiFile":true}}}},"draft":true,"projectFormats":["html"]}
|
src/.quarto/idx/posts/post-with-code/index.qmd.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"title":"Post With Code","markdown":{"yaml":{"title":"Post With Code","author":"Harlow Malloc","date":"2024-12-17","categories":["news","code","analysis"],"image":"image.jpg","draft":true},"containsRefs":false,"markdown":"\n\nThis is a post with executable code.\n","srcMarkdownNoYaml":"\n\nThis is a post with executable code.\n"},"formats":{"html":{"identifier":{"display-name":"HTML","target-format":"html","base-format":"html"},"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":false,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"ipynb-shell-interactivity":null,"plotly-connected":true,"engine":"markdown"},"render":{"keep-tex":false,"keep-typ":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"inline-includes":false,"preserve-yaml":false,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-min-runs":1,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[],"notebook-links":true},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","html-math-method":"mathjax","css":["../../styles.css"],"output-file":"index.html"},"language":{"toc-title-document":"Table of contents","toc-title-website":"On this page","related-formats-title":"Other Formats","related-notebooks-title":"Notebooks","source-notebooks-prefix":"Source","other-links-title":"Other Links","code-links-title":"Code Links","launch-dev-container-title":"Launch Dev Container","launch-binder-title":"Launch Binder","article-notebook-label":"Article Notebook","notebook-preview-download":"Download Notebook","notebook-preview-download-src":"Download Source","notebook-preview-back":"Back to Article","manuscript-meca-bundle":"MECA Bundle","section-title-abstract":"Abstract","section-title-appendices":"Appendices","section-title-footnotes":"Footnotes","section-title-references":"References","section-title-reuse":"Reuse","section-title-copyright":"Copyright","section-title-citation":"Citation","appendix-attribution-cite-as":"For attribution, please cite this work as:","appendix-attribution-bibtex":"BibTeX citation:","appendix-view-license":"View License","title-block-author-single":"Author","title-block-author-plural":"Authors","title-block-affiliation-single":"Affiliation","title-block-affiliation-plural":"Affiliations","title-block-published":"Published","title-block-modified":"Modified","title-block-keywords":"Keywords","callout-tip-title":"Tip","callout-note-title":"Note","callout-warning-title":"Warning","callout-important-title":"Important","callout-caution-title":"Caution","code-summary":"Code","code-tools-menu-caption":"Code","code-tools-show-all-code":"Show All Code","code-tools-hide-all-code":"Hide All Code","code-tools-view-source":"View Source","code-tools-source-code":"Source Code","tools-share":"Share","tools-download":"Download","code-line":"Line","code-lines":"Lines","copy-button-tooltip":"Copy to Clipboard","copy-button-tooltip-success":"Copied!","repo-action-links-edit":"Edit this page","repo-action-links-source":"View source","repo-action-links-issue":"Report an issue","back-to-top":"Back to top","search-no-results-text":"No results","search-matching-documents-text":"matching documents","search-copy-link-title":"Copy link to search","search-hide-matches-text":"Hide additional matches","search-more-match-text":"more match in this document","search-more-matches-text":"more matches in this document","search-clear-button-title":"Clear","search-text-placeholder":"","search-detached-cancel-button-title":"Cancel","search-submit-button-title":"Submit","search-label":"Search","toggle-section":"Toggle section","toggle-sidebar":"Toggle sidebar navigation","toggle-dark-mode":"Toggle dark mode","toggle-reader-mode":"Toggle reader mode","toggle-navigation":"Toggle navigation","crossref-fig-title":"Figure","crossref-tbl-title":"Table","crossref-lst-title":"Listing","crossref-thm-title":"Theorem","crossref-lem-title":"Lemma","crossref-cor-title":"Corollary","crossref-prp-title":"Proposition","crossref-cnj-title":"Conjecture","crossref-def-title":"Definition","crossref-exm-title":"Example","crossref-exr-title":"Exercise","crossref-ch-prefix":"Chapter","crossref-apx-prefix":"Appendix","crossref-sec-prefix":"Section","crossref-eq-prefix":"Equation","crossref-lof-title":"List of Figures","crossref-lot-title":"List of Tables","crossref-lol-title":"List of Listings","environment-proof-title":"Proof","environment-remark-title":"Remark","environment-solution-title":"Solution","listing-page-order-by":"Order By","listing-page-order-by-default":"Default","listing-page-order-by-date-asc":"Oldest","listing-page-order-by-date-desc":"Newest","listing-page-order-by-number-desc":"High to Low","listing-page-order-by-number-asc":"Low to High","listing-page-field-date":"Date","listing-page-field-title":"Title","listing-page-field-description":"Description","listing-page-field-author":"Author","listing-page-field-filename":"File Name","listing-page-field-filemodified":"Modified","listing-page-field-subtitle":"Subtitle","listing-page-field-readingtime":"Reading Time","listing-page-field-wordcount":"Word Count","listing-page-field-categories":"Categories","listing-page-minutes-compact":"{0} min","listing-page-category-all":"All","listing-page-no-matches":"No matching items","listing-page-words":"{0} words","listing-page-filter":"Filter","draft":"Draft"},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.6.39","theme":"flatly","title-block-banner":true,"title":"Post With Code","author":"Harlow Malloc","date":"2024-12-17","categories":["news","code","analysis"],"image":"image.jpg","draft":true},"extensions":{"book":{"multiFile":true}}}},"draft":true,"projectFormats":["html"]}
|
src/.quarto/idx/posts/wave-equation/index.qmd.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"title":"Wave Equation","markdown":{"yaml":{"title":"Wave Equation","author":"JoJo","date":"2024-12-19","categories":["mathematics","python"],"image":"./images/rectangular_membrane_1_animation.gif","draft":true},"headingText":"Introduction","containsRefs":false,"markdown":"\n\nPartial differential equations...\n\n\nLet $u(x, y, t)$ be ...\n \nThe homogenous wave equation is given by\n\n$$\n\\frac{\\partial^2 u}{\\partial t^2} - c^2 (\\frac{\\partial^2 u}{\\partial x^2} + \\frac{\\partial^2 u}{\\partial y^2}) = 0\n$$\n\nor\n\n\\begin{equation}\nu_{tt} - c^2 (u_{xx} + u_{yy}) = 0.\n\\end{equation}\n\n# Physical interpretation\n\nThe wave equation is a simplified model for a vibrating\nstring (𝑛 = 1), membrane (𝑛 = 2), or elastic solid (𝑛 = 3). In these\nphysical interpretations 𝑢(𝑥, 𝑡) represents the displacement in some direction\nof the point 𝑥 at time 𝑡 ≥ 0.\n\n1D and 2D Equations\n\n# Rectangular Membrane\n\nPass\n\n$$\nD := \\{0 < x < a, 0 < y < b\\}\n$$\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - c^2 (u_{xx} + u_{yy}) = 0, (x,y,t) \\in G = D \\times (0, +\\infty), \\\\ \nu|_{t=0} = \\varphi(x, y), u_t |_{t=0} = \\psi(x, y), (x, y) \\in \\bar{D}, \\\\\nu|_{\\partial D} = 0, t \\geq 0.\n\\end{align*}\\right.\n$$\n\n...\n\n$$\n\\varphi(x, y) \\in C^3 (\\bar{D}), \\psi(x, y) \\in C^2 (\\bar{D})\n$$\n\nand ...\n\n$$\n\\varphi |_{\\partial D} = \\varphi_{xx} |_{x = 0} = \\varphi_{xx} |_{x = a} = \\varphi_{yy} |_{y =0} = \\varphi_{yy} |_{y = b} = \\psi |_{\\partial D} = 0.\n$$\n\nSolution... :\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} ct} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} ct} \\right) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = \\left(\\frac{\\pi n}{a} \\right)^2 + \\left(\\frac{\\pi m}{b} \\right)^2.\n$$\n\nFrom the initial conditions it follows\n\n$$\nA_{n, m} = \\frac{4}{ab} \\int_D \\varphi(x, y) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y \\mathrm{d}x \\mathrm{d}y,\n$$\n\nand\n\n$$\nB_{n, m} = \\frac{4}{abc\\sqrt{\\lambda_{n, m}}} \\int_D \\psi(x, y) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y \\mathrm{d}x \\mathrm{d}y.\n$$\n\n## Example 1\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - u_{xx} - u_{yy} = 0, 0 < x < \\pi, 0 < y < \\pi, t > 0, \\\\\nu|_{t=0} = \\sin{x} \\sin{y}, u_t |_{t=0} = \\sin{4x} \\sin{3y}, x, y \\in (0, \\pi), \\\\\nu|_{x = 0} = 0, u|_{x = \\pi} = 0, 0 < y < \\pi, t > 0, \\\\\nu|_{y = 0} = 0, u|_{y = \\pi} = 0, 0 < x < \\pi, t > 0.\n\\end{align*}\\right.\n$$\n\nSolution:\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} t} \\right) \\sin{n} x \\sin{m} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = n^2 + m^2,\n$$\n\n$$\nA_{n, m} = \\frac{4}{\\pi^2} \\int_0^\\pi \\sin{x} \\sin{nx} \\mathrm{d}x \\int_0^\\pi \\sin{y} \\sin{my} \\mathrm{d}y,\n$$\n\n$$\nB_{n, m} = \\frac{4}{\\pi^2\\sqrt{\\lambda_{n, m}}} \\int_0^\\pi \\sin{4x} \\sin{nx} \\mathrm{d}x \\int_0^\\pi \\sin{3y} \\sin{my} \\mathrm{d}y.\n$$\n\nTherefore, $A_{1, 1} = 1$, $B_{4, 3} = \\frac{1}{5}$, and every other coefficients is equal to $0$. Finally, \n\n$$\nu(x, y, t) = \\cos{\\sqrt{2}t} \\sin{x} \\sin{y} + \\frac{1}{5} \\sin{5t} \\sin{4x} \\sin{3y}.\n$$\n\nFor $t \\in [0, 6]$:\n\nAnimation:\n\n\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include ./code/rectangular_membrane_1.py >}}\n```\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n## Example 2\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - \\pi^2 (u_{xx} + u_{yy}) = 0, 0 < x < 1, 0 < y < 2, t > 0, \\\\\nu|_{t=0} = \\cos{\\left(\\left(x + \\frac{1}{2}\\right)\\pi\\right)} \\cos{\\left(\\frac{\\pi}{2}\\left(y + 1\\right)\\right)}, u_t |_{t=0} = 0, 0 \\leq x \\leq 1, 0 \\leq y \\leq 2, \\\\\nu|_{x = 0} = 0, u|_{x = 1} = 0, 0 \\leq y < 2, t \\geq 0, \\\\\nu|_{y = 0} = 0, u|_{y = 2} = 0, 0 \\leq x \\leq 1, t \\geq 0.\n\\end{align*}\\right.\n$$\n\nSolution with Fourier method:\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} t} \\right) \\sin{\\pi n} x \\sin{\\pi m} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = \\pi^2 (n^2 + m^2)\n$$\n\nand\n\n$$\nB_{n, m} = 0.\n$$\n\n$$\nA_{n, m} = 2 \\int_{0}^{1} \\cos{\\left(\\left(x + \\frac{1}{2}\\right)\\pi\\right)} \\sin{\\pi nx} \\mathrm{d}x \\int_0^2 \\cos{\\left(\\frac{\\pi}{2}\\left(y + 1\\right)\\right)} \\sin{\\pi my} \\mathrm{d}y.\n$$\n\nVisualising the solution for $t \\in [0, 6]$ with the partial sum\n\n$$\n\\tilde{u}(x, y, t) = \\sum_{n, m = 1}^{30} A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} \\sin{\\pi n} x \\sin{\\pi m} y.\n$$\n\nAnimation:\n\n\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include ./code/rectangular_membrane_2.py >}}\n```\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n# Circular Membrane\n\nPass\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - \\frac{1}{4} (u_{xx} + u_{yy}) = 0, x^2 + y^2 < 9, t > 0, \\\\ \nu|_{t=0} = (x^2 + y^2) \\sin^3(\\pi \\sqrt{x^2 + y^2}), u_t |_{t=0} = 0, x^2 + y^2 \\leq 9, \\\\\nu|_{x^2 + y^2 = 9} = 0, t \\geq 0.\n\\end{align*}\\right.\n$$\n\nFourier method: Change to polar coordinates\n\n$$\n\\left\\{\\begin{align*}\nx = \\rho \\cos(\\varphi), \\\\\ny = \\rho \\sin(\\varphi)\n\\end{align*}\\right.\n$$\n\n...\n\nThen the function in the first initial condition $u |_{t=0}$ becomes\n\n$$\n\\tau(\\rho) = \\rho^2 \\sin^3(\\pi \\rho)\n$$\n\nwhich is radially symmetric and hence the solution will be also radially symmetric. It is given by\n\n$$\nu(\\rho, t) = \\sum_{m=1}^{\\infty} A_m \\cos{\\frac{a \\mu_m^{(0)}t}{r}} J_0\\left(\\frac{\\mu_m^{(0)}}{r}\\rho\\right),\n$$\n\nwhere\n\n$$\nA_m = \\frac{4}{r^2 J_1^2(\\mu_m^{(0)})} \\int_0^r \\rho^3 \\sin^3(\\pi \\rho) J_0\\left(\\frac{\\mu_m^{(0)}}{r}\\rho\\right) d\\rho,\n$$\n\nand $\\mu_m^{(0)}$ are the positive solutions to $J_0(\\mu) = 0$.\n\n...\n\n\n\n...\n\nAnimation:\n\n\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include ./code/circular_membrane.py >}}\n```\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n# References\n\n- [1](https://www.amazon.co.uk/Partial-Differential-Equations-Graduate-Mathematics/dp/1470469421/ref=sr_1_3?crid=2BINQDJ5R7XUB&dib=eyJ2IjoiMSJ9.GgU4uQBUKYO960lL6EjVJjksjFysLhCJKEHP436_saFGnfKf4uvgqyl_3WBjV779K4AwonOY5XnkRxVFCIqqGZCCE3I8YEjIC7mzvLwUa2lBPvByBCoFxTvGhrSKGLiAKlAvTVFSlbwklqyWEj4o852csy80_D3G2Gk9pedHKz22vqyc8UI8HAxWZ1wfu5bNoaqOOEDhy0W2XLaSijLCENnzVXjxTLS5xZkMCXr72G0.NeT6LdhY-WV9xVA26fbGHp37FbAKGo7mLwpV9m_2Rdk&dib_tag=se&keywords=partial+differential+equations&nsdOptOutParam=true&qid=1734133658&sprefix=partial+diff%2Caps%2C129&sr=8-3)\n- [2](https://mathworld.wolfram.com/BesselFunctionoftheFirstKind.html)\n","srcMarkdownNoYaml":"\n\nPartial differential equations...\n\n# Introduction\n\nLet $u(x, y, t)$ be ...\n \nThe homogenous wave equation is given by\n\n$$\n\\frac{\\partial^2 u}{\\partial t^2} - c^2 (\\frac{\\partial^2 u}{\\partial x^2} + \\frac{\\partial^2 u}{\\partial y^2}) = 0\n$$\n\nor\n\n\\begin{equation}\nu_{tt} - c^2 (u_{xx} + u_{yy}) = 0.\n\\end{equation}\n\n# Physical interpretation\n\nThe wave equation is a simplified model for a vibrating\nstring (𝑛 = 1), membrane (𝑛 = 2), or elastic solid (𝑛 = 3). In these\nphysical interpretations 𝑢(𝑥, 𝑡) represents the displacement in some direction\nof the point 𝑥 at time 𝑡 ≥ 0.\n\n1D and 2D Equations\n\n# Rectangular Membrane\n\nPass\n\n$$\nD := \\{0 < x < a, 0 < y < b\\}\n$$\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - c^2 (u_{xx} + u_{yy}) = 0, (x,y,t) \\in G = D \\times (0, +\\infty), \\\\ \nu|_{t=0} = \\varphi(x, y), u_t |_{t=0} = \\psi(x, y), (x, y) \\in \\bar{D}, \\\\\nu|_{\\partial D} = 0, t \\geq 0.\n\\end{align*}\\right.\n$$\n\n...\n\n$$\n\\varphi(x, y) \\in C^3 (\\bar{D}), \\psi(x, y) \\in C^2 (\\bar{D})\n$$\n\nand ...\n\n$$\n\\varphi |_{\\partial D} = \\varphi_{xx} |_{x = 0} = \\varphi_{xx} |_{x = a} = \\varphi_{yy} |_{y =0} = \\varphi_{yy} |_{y = b} = \\psi |_{\\partial D} = 0.\n$$\n\nSolution... :\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} ct} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} ct} \\right) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = \\left(\\frac{\\pi n}{a} \\right)^2 + \\left(\\frac{\\pi m}{b} \\right)^2.\n$$\n\nFrom the initial conditions it follows\n\n$$\nA_{n, m} = \\frac{4}{ab} \\int_D \\varphi(x, y) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y \\mathrm{d}x \\mathrm{d}y,\n$$\n\nand\n\n$$\nB_{n, m} = \\frac{4}{abc\\sqrt{\\lambda_{n, m}}} \\int_D \\psi(x, y) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y \\mathrm{d}x \\mathrm{d}y.\n$$\n\n## Example 1\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - u_{xx} - u_{yy} = 0, 0 < x < \\pi, 0 < y < \\pi, t > 0, \\\\\nu|_{t=0} = \\sin{x} \\sin{y}, u_t |_{t=0} = \\sin{4x} \\sin{3y}, x, y \\in (0, \\pi), \\\\\nu|_{x = 0} = 0, u|_{x = \\pi} = 0, 0 < y < \\pi, t > 0, \\\\\nu|_{y = 0} = 0, u|_{y = \\pi} = 0, 0 < x < \\pi, t > 0.\n\\end{align*}\\right.\n$$\n\nSolution:\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} t} \\right) \\sin{n} x \\sin{m} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = n^2 + m^2,\n$$\n\n$$\nA_{n, m} = \\frac{4}{\\pi^2} \\int_0^\\pi \\sin{x} \\sin{nx} \\mathrm{d}x \\int_0^\\pi \\sin{y} \\sin{my} \\mathrm{d}y,\n$$\n\n$$\nB_{n, m} = \\frac{4}{\\pi^2\\sqrt{\\lambda_{n, m}}} \\int_0^\\pi \\sin{4x} \\sin{nx} \\mathrm{d}x \\int_0^\\pi \\sin{3y} \\sin{my} \\mathrm{d}y.\n$$\n\nTherefore, $A_{1, 1} = 1$, $B_{4, 3} = \\frac{1}{5}$, and every other coefficients is equal to $0$. Finally, \n\n$$\nu(x, y, t) = \\cos{\\sqrt{2}t} \\sin{x} \\sin{y} + \\frac{1}{5} \\sin{5t} \\sin{4x} \\sin{3y}.\n$$\n\nFor $t \\in [0, 6]$:\n\nAnimation:\n\n\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include ./code/rectangular_membrane_1.py >}}\n```\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n## Example 2\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - \\pi^2 (u_{xx} + u_{yy}) = 0, 0 < x < 1, 0 < y < 2, t > 0, \\\\\nu|_{t=0} = \\cos{\\left(\\left(x + \\frac{1}{2}\\right)\\pi\\right)} \\cos{\\left(\\frac{\\pi}{2}\\left(y + 1\\right)\\right)}, u_t |_{t=0} = 0, 0 \\leq x \\leq 1, 0 \\leq y \\leq 2, \\\\\nu|_{x = 0} = 0, u|_{x = 1} = 0, 0 \\leq y < 2, t \\geq 0, \\\\\nu|_{y = 0} = 0, u|_{y = 2} = 0, 0 \\leq x \\leq 1, t \\geq 0.\n\\end{align*}\\right.\n$$\n\nSolution with Fourier method:\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} t} \\right) \\sin{\\pi n} x \\sin{\\pi m} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = \\pi^2 (n^2 + m^2)\n$$\n\nand\n\n$$\nB_{n, m} = 0.\n$$\n\n$$\nA_{n, m} = 2 \\int_{0}^{1} \\cos{\\left(\\left(x + \\frac{1}{2}\\right)\\pi\\right)} \\sin{\\pi nx} \\mathrm{d}x \\int_0^2 \\cos{\\left(\\frac{\\pi}{2}\\left(y + 1\\right)\\right)} \\sin{\\pi my} \\mathrm{d}y.\n$$\n\nVisualising the solution for $t \\in [0, 6]$ with the partial sum\n\n$$\n\\tilde{u}(x, y, t) = \\sum_{n, m = 1}^{30} A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} \\sin{\\pi n} x \\sin{\\pi m} y.\n$$\n\nAnimation:\n\n\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include ./code/rectangular_membrane_2.py >}}\n```\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n# Circular Membrane\n\nPass\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - \\frac{1}{4} (u_{xx} + u_{yy}) = 0, x^2 + y^2 < 9, t > 0, \\\\ \nu|_{t=0} = (x^2 + y^2) \\sin^3(\\pi \\sqrt{x^2 + y^2}), u_t |_{t=0} = 0, x^2 + y^2 \\leq 9, \\\\\nu|_{x^2 + y^2 = 9} = 0, t \\geq 0.\n\\end{align*}\\right.\n$$\n\nFourier method: Change to polar coordinates\n\n$$\n\\left\\{\\begin{align*}\nx = \\rho \\cos(\\varphi), \\\\\ny = \\rho \\sin(\\varphi)\n\\end{align*}\\right.\n$$\n\n...\n\nThen the function in the first initial condition $u |_{t=0}$ becomes\n\n$$\n\\tau(\\rho) = \\rho^2 \\sin^3(\\pi \\rho)\n$$\n\nwhich is radially symmetric and hence the solution will be also radially symmetric. It is given by\n\n$$\nu(\\rho, t) = \\sum_{m=1}^{\\infty} A_m \\cos{\\frac{a \\mu_m^{(0)}t}{r}} J_0\\left(\\frac{\\mu_m^{(0)}}{r}\\rho\\right),\n$$\n\nwhere\n\n$$\nA_m = \\frac{4}{r^2 J_1^2(\\mu_m^{(0)})} \\int_0^r \\rho^3 \\sin^3(\\pi \\rho) J_0\\left(\\frac{\\mu_m^{(0)}}{r}\\rho\\right) d\\rho,\n$$\n\nand $\\mu_m^{(0)}$ are the positive solutions to $J_0(\\mu) = 0$.\n\n...\n\n\n\n...\n\nAnimation:\n\n\n\n```{python}\n#| code-fold: true\n#| code-summary: \"Click to expand the code\"\n{{< include ./code/circular_membrane.py >}}\n```\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n# References\n\n- [1](https://www.amazon.co.uk/Partial-Differential-Equations-Graduate-Mathematics/dp/1470469421/ref=sr_1_3?crid=2BINQDJ5R7XUB&dib=eyJ2IjoiMSJ9.GgU4uQBUKYO960lL6EjVJjksjFysLhCJKEHP436_saFGnfKf4uvgqyl_3WBjV779K4AwonOY5XnkRxVFCIqqGZCCE3I8YEjIC7mzvLwUa2lBPvByBCoFxTvGhrSKGLiAKlAvTVFSlbwklqyWEj4o852csy80_D3G2Gk9pedHKz22vqyc8UI8HAxWZ1wfu5bNoaqOOEDhy0W2XLaSijLCENnzVXjxTLS5xZkMCXr72G0.NeT6LdhY-WV9xVA26fbGHp37FbAKGo7mLwpV9m_2Rdk&dib_tag=se&keywords=partial+differential+equations&nsdOptOutParam=true&qid=1734133658&sprefix=partial+diff%2Caps%2C129&sr=8-3)\n- [2](https://mathworld.wolfram.com/BesselFunctionoftheFirstKind.html)\n"},"formats":{"html":{"identifier":{"display-name":"HTML","target-format":"html","base-format":"html"},"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":false,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"ipynb-shell-interactivity":null,"plotly-connected":true,"engine":"jupyter"},"render":{"keep-tex":false,"keep-typ":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"inline-includes":false,"preserve-yaml":false,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-min-runs":1,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[],"notebook-links":true},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","html-math-method":"mathjax","css":["../../styles.css"],"output-file":"index.html"},"language":{"toc-title-document":"Table of contents","toc-title-website":"On this page","related-formats-title":"Other Formats","related-notebooks-title":"Notebooks","source-notebooks-prefix":"Source","other-links-title":"Other Links","code-links-title":"Code Links","launch-dev-container-title":"Launch Dev Container","launch-binder-title":"Launch Binder","article-notebook-label":"Article Notebook","notebook-preview-download":"Download Notebook","notebook-preview-download-src":"Download Source","notebook-preview-back":"Back to Article","manuscript-meca-bundle":"MECA Bundle","section-title-abstract":"Abstract","section-title-appendices":"Appendices","section-title-footnotes":"Footnotes","section-title-references":"References","section-title-reuse":"Reuse","section-title-copyright":"Copyright","section-title-citation":"Citation","appendix-attribution-cite-as":"For attribution, please cite this work as:","appendix-attribution-bibtex":"BibTeX citation:","appendix-view-license":"View License","title-block-author-single":"Author","title-block-author-plural":"Authors","title-block-affiliation-single":"Affiliation","title-block-affiliation-plural":"Affiliations","title-block-published":"Published","title-block-modified":"Modified","title-block-keywords":"Keywords","callout-tip-title":"Tip","callout-note-title":"Note","callout-warning-title":"Warning","callout-important-title":"Important","callout-caution-title":"Caution","code-summary":"Code","code-tools-menu-caption":"Code","code-tools-show-all-code":"Show All Code","code-tools-hide-all-code":"Hide All Code","code-tools-view-source":"View Source","code-tools-source-code":"Source Code","tools-share":"Share","tools-download":"Download","code-line":"Line","code-lines":"Lines","copy-button-tooltip":"Copy to Clipboard","copy-button-tooltip-success":"Copied!","repo-action-links-edit":"Edit this page","repo-action-links-source":"View source","repo-action-links-issue":"Report an issue","back-to-top":"Back to top","search-no-results-text":"No results","search-matching-documents-text":"matching documents","search-copy-link-title":"Copy link to search","search-hide-matches-text":"Hide additional matches","search-more-match-text":"more match in this document","search-more-matches-text":"more matches in this document","search-clear-button-title":"Clear","search-text-placeholder":"","search-detached-cancel-button-title":"Cancel","search-submit-button-title":"Submit","search-label":"Search","toggle-section":"Toggle section","toggle-sidebar":"Toggle sidebar navigation","toggle-dark-mode":"Toggle dark mode","toggle-reader-mode":"Toggle reader mode","toggle-navigation":"Toggle navigation","crossref-fig-title":"Figure","crossref-tbl-title":"Table","crossref-lst-title":"Listing","crossref-thm-title":"Theorem","crossref-lem-title":"Lemma","crossref-cor-title":"Corollary","crossref-prp-title":"Proposition","crossref-cnj-title":"Conjecture","crossref-def-title":"Definition","crossref-exm-title":"Example","crossref-exr-title":"Exercise","crossref-ch-prefix":"Chapter","crossref-apx-prefix":"Appendix","crossref-sec-prefix":"Section","crossref-eq-prefix":"Equation","crossref-lof-title":"List of Figures","crossref-lot-title":"List of Tables","crossref-lol-title":"List of Listings","environment-proof-title":"Proof","environment-remark-title":"Remark","environment-solution-title":"Solution","listing-page-order-by":"Order By","listing-page-order-by-default":"Default","listing-page-order-by-date-asc":"Oldest","listing-page-order-by-date-desc":"Newest","listing-page-order-by-number-desc":"High to Low","listing-page-order-by-number-asc":"Low to High","listing-page-field-date":"Date","listing-page-field-title":"Title","listing-page-field-description":"Description","listing-page-field-author":"Author","listing-page-field-filename":"File Name","listing-page-field-filemodified":"Modified","listing-page-field-subtitle":"Subtitle","listing-page-field-readingtime":"Reading Time","listing-page-field-wordcount":"Word Count","listing-page-field-categories":"Categories","listing-page-minutes-compact":"{0} min","listing-page-category-all":"All","listing-page-no-matches":"No matching items","listing-page-words":"{0} words","listing-page-filter":"Filter","draft":"Draft"},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.6.39","theme":"flatly","title-block-banner":true,"title":"Wave Equation","author":"JoJo","date":"2024-12-19","categories":["mathematics","python"],"image":"./images/rectangular_membrane_1_animation.gif","draft":true},"extensions":{"book":{"multiFile":true}}}},"draft":true,"projectFormats":["html"]}
|
src/.quarto/idx/posts/welcome/index.qmd.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"title":"Welcome To My Blog","markdown":{"yaml":{"title":"Welcome To My Blog","author":"Tristan O'Malley","date":"2024-12-16","categories":["news"],"draft":true},"containsRefs":false,"markdown":"\n\nThis is the first post in a Quarto blog. Welcome!\n\n\n\nSince this post doesn't specify an explicit `image`, the first image in the post will be used in the listing page of posts.\n","srcMarkdownNoYaml":"\n\nThis is the first post in a Quarto blog. Welcome!\n\n\n\nSince this post doesn't specify an explicit `image`, the first image in the post will be used in the listing page of posts.\n"},"formats":{"html":{"identifier":{"display-name":"HTML","target-format":"html","base-format":"html"},"execute":{"fig-width":7,"fig-height":5,"fig-format":"retina","fig-dpi":96,"df-print":"default","error":false,"eval":false,"cache":null,"freeze":true,"echo":true,"output":true,"warning":true,"include":true,"keep-md":false,"keep-ipynb":false,"ipynb":null,"enabled":null,"daemon":null,"daemon-restart":false,"debug":false,"ipynb-filters":[],"ipynb-shell-interactivity":null,"plotly-connected":true,"engine":"markdown"},"render":{"keep-tex":false,"keep-typ":false,"keep-source":false,"keep-hidden":false,"prefer-html":false,"output-divs":true,"output-ext":"html","fig-align":"default","fig-pos":null,"fig-env":null,"code-fold":"none","code-overflow":"scroll","code-link":false,"code-line-numbers":false,"code-tools":false,"tbl-colwidths":"auto","merge-includes":true,"inline-includes":false,"preserve-yaml":false,"latex-auto-mk":true,"latex-auto-install":true,"latex-clean":true,"latex-min-runs":1,"latex-max-runs":10,"latex-makeindex":"makeindex","latex-makeindex-opts":[],"latex-tlmgr-opts":[],"latex-input-paths":[],"latex-output-dir":null,"link-external-icon":false,"link-external-newwindow":false,"self-contained-math":false,"format-resources":[],"notebook-links":true},"pandoc":{"standalone":true,"wrap":"none","default-image-extension":"png","to":"html","html-math-method":"mathjax","css":["../../styles.css"],"output-file":"index.html"},"language":{"toc-title-document":"Table of contents","toc-title-website":"On this page","related-formats-title":"Other Formats","related-notebooks-title":"Notebooks","source-notebooks-prefix":"Source","other-links-title":"Other Links","code-links-title":"Code Links","launch-dev-container-title":"Launch Dev Container","launch-binder-title":"Launch Binder","article-notebook-label":"Article Notebook","notebook-preview-download":"Download Notebook","notebook-preview-download-src":"Download Source","notebook-preview-back":"Back to Article","manuscript-meca-bundle":"MECA Bundle","section-title-abstract":"Abstract","section-title-appendices":"Appendices","section-title-footnotes":"Footnotes","section-title-references":"References","section-title-reuse":"Reuse","section-title-copyright":"Copyright","section-title-citation":"Citation","appendix-attribution-cite-as":"For attribution, please cite this work as:","appendix-attribution-bibtex":"BibTeX citation:","appendix-view-license":"View License","title-block-author-single":"Author","title-block-author-plural":"Authors","title-block-affiliation-single":"Affiliation","title-block-affiliation-plural":"Affiliations","title-block-published":"Published","title-block-modified":"Modified","title-block-keywords":"Keywords","callout-tip-title":"Tip","callout-note-title":"Note","callout-warning-title":"Warning","callout-important-title":"Important","callout-caution-title":"Caution","code-summary":"Code","code-tools-menu-caption":"Code","code-tools-show-all-code":"Show All Code","code-tools-hide-all-code":"Hide All Code","code-tools-view-source":"View Source","code-tools-source-code":"Source Code","tools-share":"Share","tools-download":"Download","code-line":"Line","code-lines":"Lines","copy-button-tooltip":"Copy to Clipboard","copy-button-tooltip-success":"Copied!","repo-action-links-edit":"Edit this page","repo-action-links-source":"View source","repo-action-links-issue":"Report an issue","back-to-top":"Back to top","search-no-results-text":"No results","search-matching-documents-text":"matching documents","search-copy-link-title":"Copy link to search","search-hide-matches-text":"Hide additional matches","search-more-match-text":"more match in this document","search-more-matches-text":"more matches in this document","search-clear-button-title":"Clear","search-text-placeholder":"","search-detached-cancel-button-title":"Cancel","search-submit-button-title":"Submit","search-label":"Search","toggle-section":"Toggle section","toggle-sidebar":"Toggle sidebar navigation","toggle-dark-mode":"Toggle dark mode","toggle-reader-mode":"Toggle reader mode","toggle-navigation":"Toggle navigation","crossref-fig-title":"Figure","crossref-tbl-title":"Table","crossref-lst-title":"Listing","crossref-thm-title":"Theorem","crossref-lem-title":"Lemma","crossref-cor-title":"Corollary","crossref-prp-title":"Proposition","crossref-cnj-title":"Conjecture","crossref-def-title":"Definition","crossref-exm-title":"Example","crossref-exr-title":"Exercise","crossref-ch-prefix":"Chapter","crossref-apx-prefix":"Appendix","crossref-sec-prefix":"Section","crossref-eq-prefix":"Equation","crossref-lof-title":"List of Figures","crossref-lot-title":"List of Tables","crossref-lol-title":"List of Listings","environment-proof-title":"Proof","environment-remark-title":"Remark","environment-solution-title":"Solution","listing-page-order-by":"Order By","listing-page-order-by-default":"Default","listing-page-order-by-date-asc":"Oldest","listing-page-order-by-date-desc":"Newest","listing-page-order-by-number-desc":"High to Low","listing-page-order-by-number-asc":"Low to High","listing-page-field-date":"Date","listing-page-field-title":"Title","listing-page-field-description":"Description","listing-page-field-author":"Author","listing-page-field-filename":"File Name","listing-page-field-filemodified":"Modified","listing-page-field-subtitle":"Subtitle","listing-page-field-readingtime":"Reading Time","listing-page-field-wordcount":"Word Count","listing-page-field-categories":"Categories","listing-page-minutes-compact":"{0} min","listing-page-category-all":"All","listing-page-no-matches":"No matching items","listing-page-words":"{0} words","listing-page-filter":"Filter","draft":"Draft"},"metadata":{"lang":"en","fig-responsive":true,"quarto-version":"1.6.39","theme":"flatly","title-block-banner":true,"title":"Welcome To My Blog","author":"Tristan O'Malley","date":"2024-12-16","categories":["news"],"draft":true},"extensions":{"book":{"multiFile":true}}}},"draft":true,"projectFormats":["html"]}
|
src/.quarto/listing/listing-cache.json
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"listingMap": {
|
3 |
+
"index.qmd": [
|
4 |
+
"posts"
|
5 |
+
]
|
6 |
+
}
|
7 |
+
}
|
src/.quarto/xref/0dea6315
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"entries":[],"headings":["d-wave-equation","fixed-string","example"]}
|
src/.quarto/xref/3c315252
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"entries":[],"headings":[]}
|
src/.quarto/xref/72c2ebbf
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"entries":[],"headings":[]}
|
src/.quarto/xref/866fbff8
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"entries":[],"headings":[]}
|
src/.quarto/xref/INDEX
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"posts/post-with-code/index.qmd": {
|
3 |
+
"index.html": "ecb70ff4"
|
4 |
+
},
|
5 |
+
"posts/2025-01-06-chebyshev-polynomials/index.qmd": {
|
6 |
+
"index.html": "a841ef91"
|
7 |
+
},
|
8 |
+
"posts/2025-01-04-fourier-method-fixed-string/index.qmd": {
|
9 |
+
"index.html": "0dea6315"
|
10 |
+
},
|
11 |
+
"posts/fourier/index.qmd": {
|
12 |
+
"index.html": "3c315252"
|
13 |
+
},
|
14 |
+
"posts/welcome/index.qmd": {
|
15 |
+
"index.html": "866fbff8"
|
16 |
+
},
|
17 |
+
"posts/wave-equation/index.qmd": {
|
18 |
+
"index.html": "a1690d98"
|
19 |
+
},
|
20 |
+
"index.qmd": {
|
21 |
+
"index.html": "a98cc6c9"
|
22 |
+
},
|
23 |
+
"about.qmd": {
|
24 |
+
"about.html": "72c2ebbf"
|
25 |
+
}
|
26 |
+
}
|
src/.quarto/xref/a1690d98
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"entries":[],"headings":[]}
|
src/.quarto/xref/a841ef91
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"entries":[],"headings":["chebyshev-polynomials-of-the-first-kind","chebyshev-nodes-of-the-first-kind","recurrence-relation","radial-plots"]}
|
src/.quarto/xref/a98cc6c9
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"entries":[],"headings":[]}
|
src/.quarto/xref/ecb70ff4
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"entries":[],"headings":[]}
|
src/_freeze/posts/2025-01-04-fourier-method-fixed-string/index/execute-results/html.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
src/_freeze/posts/2025-01-06-chebyshev-polynomials/index/execute-results/html.json
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"hash": "aa583ba3ab0462ca32f88764351645de",
|
3 |
+
"result": {
|
4 |
+
"engine": "jupyter",
|
5 |
+
"markdown": "---\ntitle: \"Chebyshev Polynomials: Part 1\"\nauthor: \"Joana Levtcheva\"\ndate: \"2025-01-06\"\ncategories: [mathematics, polynomials]\ndraft: false\n---\n\n\n\n\nChebyshev polynomials are a sequence of orthogonal polynomials that play a central role in numerical analysis, approximation theory, and applied mathematics. They are named after the Russian mathematician Pafnuty Chebyshev and come in two primary types: Chebyshev polynomials of the first kind ($T_n(x)$) and Chebyshev polynomials of the second kind ($U_n(x)$). In this post we are going to focus on the Chebyshev polynomials of the first kind.\n\n# Chebyshev Polynomials of the First Kind\n\nThere are many different ways to define the Chebyshev polynomials of the first kind. The one that seems most logical to me and most useful in terms of outlining various properties of the polynomials is\n\n$$\\label{eq:1}\nT_{n}(x) = \\cos{\\left(n \\arccos{x}\\right)}, \\quad x \\in [-1, 1].\\tag{1}\n$$\n\nLooking at \\eqref{eq:1} it is not obvious why $T_{n}(x)$ would be a polynomial. In order to show it is indeed a polynomial let's recall the de Moivre's formula\n\n$$\n\\cos{(n \\theta)} + i\\sin{(n \\theta)} = (\\cos(\\theta) + i \\sin{\\theta})^n.\n$$\n\nWe can apply binomial expansion and take the real part from it to obatin\n\n$$\\label{eq:2}\n\\cos(n \\theta) = \\sum_{k = 0}^{\\frac{n}{2}} C(n, 2k) (-1)^k \\cos^{n - 2k}\\theta \\sin^{2k}{\\theta}. \\tag{2}\n$$\n\nwhere \n\n$$\nC(n, 2k) = \\frac{n!}{(2k)!(n-2k)!}, \\quad n \\geq 2k, k \\in N, n \\in N\n$$ \n\ndenotes the binomal coefficient. We can also notice that\n\n$$\n\\sin^{2k}\\theta = (\\sin^2{\\theta})^k = (1 - \\cos^2{\\theta})^k,\n$$\n\nshowing that \\eqref{eq:2} is a polynomial of $\\cos{\\theta}$ of degree $n$. Now, let\n\n$$\n\\theta = \\arccos{x},\n$$\n\nand by utilising $\\cos{\\left(\\arccos{x}\\right)} = x$ we get\n\n$$\nx = \\cos{\\theta}.\n$$\n\nThis transforms \\eqref{eq:1} to \n\n$$\\label{eq:3}\nT_{n}(\\cos{\\theta}) = \\cos{\\left(n \\theta\\right)} \\tag{3}\n$$\n\nwhich we already showed is a polynomial of degree $n$. From here, because $\\cos(.)$ is an even function, we can note that\n\n$$\nT_{n}(x) = T_{-n}(x) = T_{|n|}(x.)\n$$\n\nFrom \\eqref{eq:3} it is also obvious that the values of $T_n$ in the interval $[-1, 1]$ are bounded in $[-1, 1]$ because of the cosine.\n\n## Chebyshev Nodes of the First Kind\n\nBefore we continue with exploring the roots of the polynomials, let's recall some trigonometry. \n\n---\n\nThe **unit circle** is a circle with a radius of 1, centered at the origin of the Cartesian coordinate system. Below is shown part of the unit circle corresponding to the region from $0$ to $\\frac{\\pi}{2}$.\n\n\n\nThe cosine of an angle $\\theta$ corresponds to the $x$-coordinate of the point where the terminal side of the angle (measured counterclockwise from the positive $x$-axis) intersects the unit circle. In other words, $\\cos(\\theta)$ gives the horizontal distance from the origin to this intersection point. \n\nThe **arccosine** is the inverse function of cosine, and it maps a cosine value back to its corresponding angle in the range $[0, \\pi]$ radians. For a given $x$-coordinate on the unit circle, the arccosine gives the angle $\\theta$ such that $\\cos(\\theta) = x$, meaning\n\n$$\n\\arccos(x) = \\theta, \\quad \\text{where } \\theta \\in [0, \\pi].\n$$\n\nMoreover, a **radian** is defined as the angle subtended at the center of a circle by an arc whose length is equal to the radius of the circle. For any circle, the length of an arc $s$ is given by\n\n$$\ns = r \\cdot \\theta,\n$$\n\nwhere $r$ is the radius of the circle, $\\theta$ is the angle subtended by the arc at the center. This means that on the unit circle the length of the arc equals the measure of the angle in radians because $r = 1$, and hence\n\n$$\ns = \\theta.\n$$\n\n---\n\nNow, let's find the roots of the polynomial $T_{n}(x)$. If we take the definition in \\eqref{eq:1} we have to solve\n\n$$\n\\cos{\\left(n \\arccos{x}\\right)} = 0, k \\in N.\n$$\n\nThe solutions in the interval $(-1, 1)$ are given by\n\n$$\nx_k = \\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n.\n$$\n\nThese roots are known as the **Chebyshev nodes of the first kind**, or the **Chebyshev zeros**. If we are working with an arbitrary interval $(a, b)$ the affine transformation \n\n$$\nx_k = \\frac{a + b}{2} + \\frac{b - a}{2}\\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n\n$$\n\nis needed. From the cosine properties we can also note that the nodes are symmetric with respect to the midpoint of the interval, and that the extrema of $T_n(x)$ over the interval $[-1, 1]$ alternate between $-1$ and $1$. Also, a very useful fact is that these nodes are used in polynomial interpolation to minimize the **Runge phenomenon**.\n\nIn the figure below we have shown the roots of $T_{8}(x)$ in blue. We have also built the perpendiculars from the roots to their interesction with the upper half of the unit circle, and marked these points in red.\n\n{ width=45% }{ width=45% }\n\nLooking at the figure we can notice that the arc lengths between the red points seem to be of the same length. Let's show that this is indeed the truth.\n\nWe showed the roots are the cosine functions $\\cos{\\left(\\frac{2k - 1}{2n}\\pi\\right)}, n \\in N, k = 1, 2, ...n$. Thus, in the unit circle we have that the length of the corresponding arcs are equal to $\\left( \\frac{2k - 1}{2n}\\pi \\right), n \\in N, k = 1, 2, ...n$. Let's take two red points which are direct neighbours, or in other words let's take two red points corresponding to the randomly chosen $m$ and $m + 1$ roots, $m \\in k = \\{1, 2, ..., n\\}$. If we subtract them we are going to determine the length of the arc between them. We have\n\n$$\n\\frac{2(m + 1) - 1}{2n}\\pi - \\frac{2m - 1}{2n}\\pi = \\frac{\\pi}{n},\n$$\n\nmeaning that between every two nodes the arc length is equal and has a value of $\\frac{\\pi}{n}$. A polynomial of degree $n$ has $n$ roots, which in our case are in the open interval $(-1, 1)$, meaning the arcs corresponding to every two neighbouring roots are $n - 1$, and the two arcs between the $x$-axis and the first and last roots due to the symmetry of roots have lenghts of\n\n$$\n\\frac{1}{2}\\left(\\pi - \\frac{n-1}{n}\\pi\\right) = \\frac{\\pi}{2n}.\n$$\n\n## Recurrence relation\n\nThis is probably a bit out of nowhere, but let's take a look at the following trigonometric identity\n\n$$\\label{eq:4}\n\\cos{\\left((n + 1)\\theta\\right)} + \\cos{\\left((n - 1)\\theta\\right)} = 2 \\cos{(\\theta)} \\cos{(n\\theta)},\\tag{4}\n$$\n\nand show that the left side indeed is equal to the right one. We are going to need the following two fundamental formulas of angle addition in trigonometry\n\n$$\n\\cos{(\\alpha + \\beta)} = \\cos{\\alpha} \\cos{\\beta} - \\sin{\\alpha} \\sin{\\beta},\n$$\n\nand\n\n$$\n\\cos{(\\alpha - \\beta)} = \\cos{\\alpha} \\cos{\\beta} + \\sin{\\alpha} \\sin{\\beta}.\n$$\n\nIn our case we have\n\n$$\n\\cos{\\left((n + 1)\\theta\\right)} = \\cos{\\left(n\\theta + \\theta\\right)} = \\cos{(n\\theta)} \\cos{\\theta} - \\sin{(n\\theta)} \\sin{\\theta},\n$$\n\nand\n\n$$\n\\cos{\\left((n - 1)\\theta\\right)} = \\cos{\\left(n\\theta - \\theta\\right)} = \\cos{(n\\theta)} \\cos{\\theta} + \\sin{(n\\theta)} \\sin{\\theta}.\n$$\n\nAdding the above equations leads to the wanted result.\n\nNow, we can see that the terms of \\eqref{eq:4} are exactly in the form of the right side of \\eqref{eq:1}, \\eqref{eq:3}, hence we get\n\n$$\nT_{n + 1}(x) + T_{n - 1}(x) = 2T_{n}(x)T_{1}(x),\n$$\n\nor we get the useful **recurrence relation**\n\n$$\\label{eq:5}\nT_{n + 1}(x) - 2xT_{n}(x) + T_{n - 1}(x) = 0.\\tag{5}\n$$\n\nThis relation along with adding $T_{0}(x) = 1$ and $T_{1}(x) = x$ is another famous way to define the Chebyshev polynomials of the first kind, or\n\n$$\n\\left\\{\\begin{align*}\nT_{0}(x) = 1, \\\\\nT_{1}(x) = x, \\\\\nT_{n + 1}(x) - 2xT_{n}(x) + T_{n - 1}(x) = 0.\n\\end{align*}\\right.\\label{eq:6}\\tag{6}\n$$\n\nLet's write the first $6$ polynomials by using \\eqref{eq:6}:\n\n$$\n\\left\\{\\begin{align*}\nT_{0}(x) = 1, \\quad \\text{(even)}\\\\\nT_{1}(x) = x, \\quad \\text{(odd)}\\\\\nT_{2}(x) = 2x^2 - 1, \\quad \\text{(even)}\\\\\nT_{3}(x) = 4x^3 - 3x, \\quad \\text{(odd)}\\\\\nT_{4}(x) = 8x^4 - 8x^2 + 1, \\quad \\text{(even)}\\\\\nT_{5}(x) = 16x^5 - 20x^3 + 5x. \\quad \\text{(odd)}\n\\end{align*}\\right.\n$$\n\nWe can notice that\n\n$$\nT_{k}(x) = 2^{k-1}x^k + ...,\n$$\n\nand $T_{k}(x)$ is alternating between an even and an odd polynomial depending on whether $k$ is even or odd respectively.\n\nBefore we continue with some visualisations and more facts, let's mention that an interesting way to represent the recurrence relation \\eqref{eq:5} is via the determinant\n\n$$\nT_{k}(x) = \\det \\begin{bmatrix}\nx & 1 & 0 & \\dots & 0 \\\\\n1 & 2x & 1 & \\ddots & \\vdots \\\\\n0 & 1 & 2x & \\ddots & 0 \\\\\n\\vdots & \\ddots & \\ddots & \\ddots & 1 \\\\\n0 & \\dots & 0 & 1 & 2x\n\\end{bmatrix}.\n$$\n\nNow, let's visualise the first $8$ polynomials.\n\n\n\nBut what can we notice if we stack them together?\n\n\n\nIt is quite obvious that at the roots of the $N$-th Chebyshev polynomial there is an **aliasing** effect, meaning higher order polynomials look like lower order ones. We can formally show it by fixing $N$, at the roots $x_k$ of $T_{N}(x) = 0$, and using the Chebyshev identity\n\n$$\n\\cos{\\left((m + N)\\theta\\right)} + \\cos{\\left((m - N)\\theta\\right)} = 2\\cos{(m\\theta)}\\cos{(N\\theta)},\n$$\n\nor equivalently\n\n$$\nT_{m + N}(x) + T_{m - N}(x) = 2T_{m}(x)T_{N}(x).\n$$\n\nNow, having $T_{N}(x) = 0$ leads to\n\n$$\nT_{m + N}(x) = -T_{m - N}(x).\n$$\n\nIf we consecutevly set $m = N$, $m = 2N$, ..., $m = 6N$, etc. we would get\n\n$$\n\\left\\{\\begin{align*}\nT_{2N}(x_k) = -T_{0}(x_k) = -1, \\\\\nT_{3N}(x_k) = 0, \\\\\nT_{4N}(x_k) = 1, \\\\\nT_{5N}(x_k) = 0, \\\\\nT_{6N}(x_k) = -1, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nWe can safely say that any higher-order Chebyshev polynomial $T_{N}(x)$ can be reduced to a lower-order $j, 0 \\leq j \\leq N$ Chebyshev polynomial at the sample points $x_k$ which are the roots of $T_{N}(x)$. In the figure below we attempt to visualise this statement.\n\n\n\nThe horizontal axis represents the order of Chebyshev polynomials, and the blue wavy line represents a \"folded ribbon\". Think of it as taking the sequence of polynomial orders and folding it back and forth. This folding happens at specific points where higher-order polynomials can be reduced to lower-order ones, which are the red **x** marks showing the sample points: the roots of $T_n(x)$. The key insight is that at these special sample points, we don't need to work with the higher-order polynomials because we can use equivalent lower-order ones instead. This is incredibly useful in numerical computations as it can help reduce computational complexity, and makes the Chebyshev polynomials very computationally efficient.\n\nLet's illustarte this with a simple example. Let $N = 2$, then for even $m$ we have\n\n$$\n\\left\\{\\begin{align*}\nT_{4}(x_k) = -T_{0}(x_k) = -1, \\\\\nT_{6}(x_k) = - T_{2}(x_k) = 0, \\\\\nT_{8}(x_k) = - T_{4}(x_k) = 1, \\\\\nT_{10}(x_k) = -T_{6}(x_k) = 0, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nIn the figure below we can see the even polynomials and that indeed $T_{10}(x)$ behaves like $-T_{6}(x)$ which behaves like $T_{2}(x)$ at the roots having value $0$, $T_{8}(x)$ behaves like $-T_{4}(x)$ at the roots with value $1$ as in $T_{0}(x)$, $T_{6}(x)$ behaves like $-T_{2}(x)$ with value $0$, and $T_{4}(x)$ behaves like $-T_{0}(x)$ with value $-1$.\n\n::: {#be218886 .cell execution_count=1}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nfrom typing import Union\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\ndef chebyshev_polynomial(\n n: int, x: Union[float, np.ndarray]\n) -> Union[float, np.ndarray]:\n \"\"\"\n Calculate nth Chebyshev polynomial of the first kind T_n(x).\n\n Args:\n n: Order of polynomial (non-negative integer)\n x: Point(s) at which to evaluate polynomial\n\n Returns:\n Value of T_n(x)\n \"\"\"\n if n < 0:\n raise ValueError(\"Order must be non-negative\")\n\n if n == 0:\n return np.ones_like(x)\n elif n == 1:\n return x\n else:\n t_prev = np.ones_like(x) # T_0\n t_curr = x # T_1\n\n for _ in range(2, n + 1):\n t_next = 2 * x * t_curr - t_prev\n t_prev = t_curr\n t_curr = t_next\n\n return t_curr\n\n\ndef chebyshev_nodes(n):\n \"\"\"Generate n Chebyshev nodes in [-1,1]\"\"\"\n k = np.arange(1, n + 1)\n return np.cos((2 * k - 1) * np.pi / (2 * n))\n\n\nif __name__ == \"__main__\":\n\n x = np.linspace(-1, 1, 1000)\n plt.figure(figsize=(12, 6))\n plt.plot(x, -chebyshev_polynomial(0, x), \"--\", label=f\"-T_{0}(x)\", alpha=0.5)\n for n in [0, 2, 4, 6, 8, 10]:\n y = chebyshev_polynomial(n, x)\n plt.plot(x, y, label=f\"T_{n}(x)\")\n\n # plot nodes for n = 2\n n = 2\n nodes = chebyshev_nodes(n)\n y_nodes = np.cos(n * np.arccos(nodes))\n plt.plot(nodes, np.zeros_like(nodes), \"bo\", label=\"T_2(x) roots\")\n for node in nodes:\n plt.plot([node, node], [-1, 1], \"--\", color=\"gray\", alpha=0.5)\n\n # plt.grid(True)\n # Set aspect ratio to be equal\n # plt.gca().set_aspect('equal', adjustable='box')\n plt.xlabel(\"x\")\n plt.ylabel(\"T_n(x)\")\n plt.title(\"Chebyshev Polynomials Aliasing\")\n plt.legend(loc=\"center left\", bbox_to_anchor=(1, 0.5), fontsize=8)\n plt.xlim(-1.1, 1.1)\n plt.ylim(-1.1, 1.1)\n plt.axhline(y=0, color=\"k\", linestyle=\"-\", alpha=0.7)\n plt.savefig(\n \"content/images/2025-01-06-chebyshev-polynomials/chebyshev_polynomials_aliasing_even.png\"\n )\n plt.show()\n```\n:::\n\n\n\n\nFor odd $m$ we have\n$$\n\\left\\{\\begin{align*}\nT_{3}(x_k) = - T_{1}(x_k) = - x\\\\\nT_{5}(x_k) = - T_{3}(x_k) = x\\\\\nT_{7}(x_k) = - T_{5}(x_k) = -x, \\\\\nT_{9}(x_k) = - T_{7}(x_k) = x, \\\\\n\\text{etc}.\n\\end{align*}\\right.\n$$\n\nIn the figure below we can see the odd polynomials and the aliasing as in the previous example.\n\n::: {#54809f08 .cell execution_count=2}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nfrom typing import Union\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\ndef chebyshev_polynomial(\n n: int, x: Union[float, np.ndarray]\n) -> Union[float, np.ndarray]:\n \"\"\"\n Calculate nth Chebyshev polynomial of the first kind T_n(x).\n\n Args:\n n: Order of polynomial (non-negative integer)\n x: Point(s) at which to evaluate polynomial\n\n Returns:\n Value of T_n(x)\n \"\"\"\n if n < 0:\n raise ValueError(\"Order must be non-negative\")\n\n if n == 0:\n return np.ones_like(x)\n elif n == 1:\n return x\n else:\n t_prev = np.ones_like(x) # T_0\n t_curr = x # T_1\n\n for _ in range(2, n + 1):\n t_next = 2 * x * t_curr - t_prev\n t_prev = t_curr\n t_curr = t_next\n\n return t_curr\n\n\ndef chebyshev_nodes(n):\n \"\"\"Generate n Chebyshev nodes in [-1,1]\"\"\"\n k = np.arange(1, n + 1)\n return np.cos((2 * k - 1) * np.pi / (2 * n))\n\n\nif __name__ == \"__main__\":\n\n x = np.linspace(-1, 1, 1000)\n plt.figure(figsize=(12, 6))\n plt.plot(x, -chebyshev_polynomial(1, x), \"--\", label=f\"-T_{1}(x)\", alpha=0.5)\n for n in [1, 2, 3, 5, 7, 9]:\n y = chebyshev_polynomial(n, x)\n plt.plot(x, y, label=f\"T_{n}(x)\")\n\n # plot nodes for n = 2\n n = 2\n nodes = chebyshev_nodes(n)\n y_nodes = np.cos(n * np.arccos(nodes))\n plt.plot(nodes, np.zeros_like(nodes), \"bo\", label=\"T_2(x) roots\")\n for node in nodes:\n plt.plot([node, node], [-1, 1], \"--\", color=\"gray\", alpha=0.5)\n\n # plt.grid(True)\n # Set aspect ratio to be equal\n # plt.gca().set_aspect('equal', adjustable='box')\n plt.xlabel(\"x\")\n plt.ylabel(\"T_n(x)\")\n plt.title(\"Chebyshev Polynomials Aliasing\")\n plt.legend(loc=\"center left\", bbox_to_anchor=(1, 0.5), fontsize=8)\n plt.xlim(-1.1, 1.1)\n plt.ylim(-1.1, 1.1)\n plt.axhline(y=0, color=\"k\", linestyle=\"-\", alpha=0.7)\n plt.savefig(\n \"content/images/2025-01-06-chebyshev-polynomials/chebyshev_polynomials_aliasing_odd.png\"\n )\n plt.show()\n```\n:::\n\n\n\n\n## Radial Plots\n\nAn interesting plot can be observed by plotting $T_n(x)$ radially. This means that instead of evaluating the polynomials over $[-1, 1]$ in a Cartesian plane we are evaluating them at $\\frac{\\theta}{\\pi} - 1$, and plotting $r = n + T_n(\\frac{\\theta}{\\pi} - 1)$ on polar axes. In other words, the input domain has been shifted and extended, and the results are drawn as radial distances $r$ around a circle defined by $\\theta$. This creates a polar visualization where each $n$ produces a distinct spiral-like ornament. We are also filling in the areas between the curves for a visual effect.\n\n::: {#b2db675f .cell execution_count=3}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom numpy.polynomial.chebyshev import Chebyshev\n\ntheta = np.linspace(0, 2 * np.pi, 2000)\nfig, ax = plt.subplots(subplot_kw={\"projection\": \"polar\"})\n\n# Generate and fill between consecutive curves\nfor n in range(0, 19 * 2, 2):\n r1 = n + Chebyshev([0] * n + [1])(theta / np.pi - 1)\n r2 = (n + 2) + Chebyshev([0] * (n + 2) + [1])(theta / np.pi - 1)\n\n # Create black and white alternating pattern\n if n % 4 == 0:\n ax.fill_between(theta, r1, r2, color=\"black\")\n else:\n ax.fill_between(theta, r1, r2, color=\"white\")\nax.set_title(\"x = t/π - 1\", y=1)\nplt.axis(\"off\")\nplt.show()\n```\n:::\n\n\n{ width=50% }{ width=41% }\n\nMore visualusations can be achieved by doing other domain changes. They can be seen below.\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\n{ width=25% }{ width=25% }{ width=25% }{ width=25% }\n\nIn a separate post, Chebyshev Polynomials, Part 2, we are going to explore the Chebyshev polynomials of the second kind, and their relations to the polynomials of the first kind.\n\n",
|
6 |
+
"supporting": [
|
7 |
+
"index_files"
|
8 |
+
],
|
9 |
+
"filters": [],
|
10 |
+
"includes": {}
|
11 |
+
}
|
12 |
+
}
|
src/_freeze/posts/wave-equation/index/execute-results/html.json
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"hash": "acdc50e3128605e35f826beed13579e3",
|
3 |
+
"result": {
|
4 |
+
"engine": "jupyter",
|
5 |
+
"markdown": "---\ntitle: \"Wave Equation\"\nauthor: \"JoJo\"\ndate: \"2024-12-19\"\ncategories: [mathematics, python]\nimage: \"./images/rectangular_membrane_1_animation.gif\"\ndraft: true\n---\n\n\n\n\nPartial differential equations...\n\n# Introduction\n\nLet $u(x, y, t)$ be ...\n \nThe homogenous wave equation is given by\n\n$$\n\\frac{\\partial^2 u}{\\partial t^2} - c^2 (\\frac{\\partial^2 u}{\\partial x^2} + \\frac{\\partial^2 u}{\\partial y^2}) = 0\n$$\n\nor\n\n\\begin{equation}\nu_{tt} - c^2 (u_{xx} + u_{yy}) = 0.\n\\end{equation}\n\n# Physical interpretation\n\nThe wave equation is a simplified model for a vibrating\nstring (𝑛 = 1), membrane (𝑛 = 2), or elastic solid (𝑛 = 3). In these\nphysical interpretations 𝑢(𝑥, 𝑡) represents the displacement in some direction\nof the point 𝑥 at time 𝑡 ≥ 0.\n\n1D and 2D Equations\n\n# Rectangular Membrane\n\nPass\n\n$$\nD := \\{0 < x < a, 0 < y < b\\}\n$$\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - c^2 (u_{xx} + u_{yy}) = 0, (x,y,t) \\in G = D \\times (0, +\\infty), \\\\ \nu|_{t=0} = \\varphi(x, y), u_t |_{t=0} = \\psi(x, y), (x, y) \\in \\bar{D}, \\\\\nu|_{\\partial D} = 0, t \\geq 0.\n\\end{align*}\\right.\n$$\n\n...\n\n$$\n\\varphi(x, y) \\in C^3 (\\bar{D}), \\psi(x, y) \\in C^2 (\\bar{D})\n$$\n\nand ...\n\n$$\n\\varphi |_{\\partial D} = \\varphi_{xx} |_{x = 0} = \\varphi_{xx} |_{x = a} = \\varphi_{yy} |_{y =0} = \\varphi_{yy} |_{y = b} = \\psi |_{\\partial D} = 0.\n$$\n\nSolution... :\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} ct} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} ct} \\right) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = \\left(\\frac{\\pi n}{a} \\right)^2 + \\left(\\frac{\\pi m}{b} \\right)^2.\n$$\n\nFrom the initial conditions it follows\n\n$$\nA_{n, m} = \\frac{4}{ab} \\int_D \\varphi(x, y) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y \\mathrm{d}x \\mathrm{d}y,\n$$\n\nand\n\n$$\nB_{n, m} = \\frac{4}{abc\\sqrt{\\lambda_{n, m}}} \\int_D \\psi(x, y) \\sin{\\frac{\\pi n}{a}} x \\sin{\\frac{\\pi m}{b}} y \\mathrm{d}x \\mathrm{d}y.\n$$\n\n## Example 1\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - u_{xx} - u_{yy} = 0, 0 < x < \\pi, 0 < y < \\pi, t > 0, \\\\\nu|_{t=0} = \\sin{x} \\sin{y}, u_t |_{t=0} = \\sin{4x} \\sin{3y}, x, y \\in (0, \\pi), \\\\\nu|_{x = 0} = 0, u|_{x = \\pi} = 0, 0 < y < \\pi, t > 0, \\\\\nu|_{y = 0} = 0, u|_{y = \\pi} = 0, 0 < x < \\pi, t > 0.\n\\end{align*}\\right.\n$$\n\nSolution:\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} t} \\right) \\sin{n} x \\sin{m} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = n^2 + m^2,\n$$\n\n$$\nA_{n, m} = \\frac{4}{\\pi^2} \\int_0^\\pi \\sin{x} \\sin{nx} \\mathrm{d}x \\int_0^\\pi \\sin{y} \\sin{my} \\mathrm{d}y,\n$$\n\n$$\nB_{n, m} = \\frac{4}{\\pi^2\\sqrt{\\lambda_{n, m}}} \\int_0^\\pi \\sin{4x} \\sin{nx} \\mathrm{d}x \\int_0^\\pi \\sin{3y} \\sin{my} \\mathrm{d}y.\n$$\n\nTherefore, $A_{1, 1} = 1$, $B_{4, 3} = \\frac{1}{5}$, and every other coefficients is equal to $0$. Finally, \n\n$$\nu(x, y, t) = \\cos{\\sqrt{2}t} \\sin{x} \\sin{y} + \\frac{1}{5} \\sin{5t} \\sin{4x} \\sin{3y}.\n$$\n\nFor $t \\in [0, 6]$:\n\nAnimation:\n\n\n\n::: {#596976bd .cell execution_count=1}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.animation import FuncAnimation\n\n\ndef rectangular_membrane_1(t_max: int = 6):\n t = np.linspace(0, t_max, 100) # Time points for animation\n x = np.linspace(0, np.pi, 51) # x grid\n y = np.linspace(0, np.pi, 51) # y grid\n X, Y = np.meshgrid(x, y)\n\n # Define the solution function\n def solution(x, y, t):\n return (\n np.cos(np.sqrt(2) * t) * np.sin(x) * np.sin(y)\n + np.sin(5 * t) * np.sin(4 * x) * np.sin(3 * y) / 5\n )\n\n # Set up the figure and axis for animation\n fig = plt.figure()\n ax = fig.add_subplot(111, projection=\"3d\")\n ax.set_xlim(0, np.pi)\n ax.set_ylim(0, np.pi)\n ax.set_zlim(-1, 1)\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n ax.set_title(\"Rectangular Membrane\")\n\n # Update function for FuncAnimation\n def update(frame):\n ax.clear() # Clear the previous frame\n Z = solution(X, Y, frame) # Compute the new Z values\n _ = ax.plot_surface(X, Y, Z, cmap=\"viridis\", vmin=-1, vmax=1)\n ax.set_xlim(0, np.pi)\n ax.set_ylim(0, np.pi)\n ax.set_zlim(-1, 1)\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n ax.set_title(\"Rectangular Membrane\")\n\n # Create and save the animation\n anim = FuncAnimation(fig, update, frames=t, interval=50)\n anim.save(\"rectangular_membrane_1_animation.gif\", writer=\"imagemagick\", fps=20)\n\n plt.show()\n```\n:::\n\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n## Example 2\n\n...\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - \\pi^2 (u_{xx} + u_{yy}) = 0, 0 < x < 1, 0 < y < 2, t > 0, \\\\\nu|_{t=0} = \\cos{\\left(\\left(x + \\frac{1}{2}\\right)\\pi\\right)} \\cos{\\left(\\frac{\\pi}{2}\\left(y + 1\\right)\\right)}, u_t |_{t=0} = 0, 0 \\leq x \\leq 1, 0 \\leq y \\leq 2, \\\\\nu|_{x = 0} = 0, u|_{x = 1} = 0, 0 \\leq y < 2, t \\geq 0, \\\\\nu|_{y = 0} = 0, u|_{y = 2} = 0, 0 \\leq x \\leq 1, t \\geq 0.\n\\end{align*}\\right.\n$$\n\nSolution with Fourier method:\n\n$$\nu(x, y, t) = \\sum_{n, m = 1}^{\\infty} \\left(A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} + B_{n, m} \\sin{\\sqrt{\\lambda_{n, m}} t} \\right) \\sin{\\pi n} x \\sin{\\pi m} y,\n$$\n\nwhere\n\n$$\n\\lambda_{n, m} = \\pi^2 (n^2 + m^2)\n$$\n\nand\n\n$$\nB_{n, m} = 0.\n$$\n\n$$\nA_{n, m} = 2 \\int_{0}^{1} \\cos{\\left(\\left(x + \\frac{1}{2}\\right)\\pi\\right)} \\sin{\\pi nx} \\mathrm{d}x \\int_0^2 \\cos{\\left(\\frac{\\pi}{2}\\left(y + 1\\right)\\right)} \\sin{\\pi my} \\mathrm{d}y.\n$$\n\nVisualising the solution for $t \\in [0, 6]$ with the partial sum\n\n$$\n\\tilde{u}(x, y, t) = \\sum_{n, m = 1}^{30} A_{n, m} \\cos{\\sqrt{\\lambda_{n, m}} t} \\sin{\\pi n} x \\sin{\\pi m} y.\n$$\n\nAnimation:\n\n\n\n::: {#f1605c55 .cell execution_count=2}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.animation import FuncAnimation\n\n\ndef rectangular_membrane_2(a: float = 1, b: float = 2, c: float = np.pi, tmax: int = 6):\n t = np.linspace(0, tmax, 100) # Time points for animation\n x = np.linspace(0, a, 50) # x grid\n y = np.linspace(0, b, 50) # y grid\n X, Y = np.meshgrid(x, y)\n\n # Define the solution function\n def solution(x, y, t):\n z = 0\n for n in range(1, 31):\n for m in range(1, 31):\n lambda_nm = np.pi**2 * (n**2 / a**2 + m**2 / b**2)\n # Compute the coefficient Anm\n xx = np.linspace(0, a, 100)\n yy = np.linspace(0, b, 100)\n Anm = (\n 4\n * np.trapezoid(\n np.cos(np.pi / 2 + np.pi * xx / a) * np.sin(n * np.pi * xx / a),\n xx,\n )\n * np.trapezoid(\n np.cos(np.pi / 2 + np.pi * yy / b) * np.sin(m * np.pi * yy / b),\n yy,\n )\n / (a * b)\n )\n z += (\n Anm\n * np.cos(c * np.sqrt(lambda_nm) * t)\n * np.sin(n * np.pi * x / a)\n * np.sin(m * np.pi * y / b)\n )\n return z\n\n # Set up the figure and axis for animation\n fig = plt.figure()\n ax = fig.add_subplot(111, projection=\"3d\")\n ax.set_xlim(0, a)\n ax.set_ylim(0, b)\n ax.set_zlim(-1, 1)\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n ax.set_title(\"Rectangular Membrane\")\n\n # Update function for FuncAnimation\n def update(frame):\n ax.clear()\n Z = solution(X, Y, frame) # Compute the new Z values\n ax.plot_surface(X, Y, Z, cmap=\"viridis\", vmin=-1, vmax=1)\n ax.set_xlim(0, a)\n ax.set_ylim(0, b)\n ax.set_zlim(-1, 1)\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n ax.set_title(\"Rectangular Membrane\")\n\n # Create and save the animation\n anim = FuncAnimation(fig, update, frames=t, interval=50)\n anim.save(\"rectangular_membrane_2_animation.gif\", writer=\"imagemagick\", fps=20)\n\n plt.show()\n```\n:::\n\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n# Circular Membrane\n\nPass\n\n$$\n\\left\\{\\begin{align*}\nu_{tt} - \\frac{1}{4} (u_{xx} + u_{yy}) = 0, x^2 + y^2 < 9, t > 0, \\\\ \nu|_{t=0} = (x^2 + y^2) \\sin^3(\\pi \\sqrt{x^2 + y^2}), u_t |_{t=0} = 0, x^2 + y^2 \\leq 9, \\\\\nu|_{x^2 + y^2 = 9} = 0, t \\geq 0.\n\\end{align*}\\right.\n$$\n\nFourier method: Change to polar coordinates\n\n$$\n\\left\\{\\begin{align*}\nx = \\rho \\cos(\\varphi), \\\\\ny = \\rho \\sin(\\varphi)\n\\end{align*}\\right.\n$$\n\n...\n\nThen the function in the first initial condition $u |_{t=0}$ becomes\n\n$$\n\\tau(\\rho) = \\rho^2 \\sin^3(\\pi \\rho)\n$$\n\nwhich is radially symmetric and hence the solution will be also radially symmetric. It is given by\n\n$$\nu(\\rho, t) = \\sum_{m=1}^{\\infty} A_m \\cos{\\frac{a \\mu_m^{(0)}t}{r}} J_0\\left(\\frac{\\mu_m^{(0)}}{r}\\rho\\right),\n$$\n\nwhere\n\n$$\nA_m = \\frac{4}{r^2 J_1^2(\\mu_m^{(0)})} \\int_0^r \\rho^3 \\sin^3(\\pi \\rho) J_0\\left(\\frac{\\mu_m^{(0)}}{r}\\rho\\right) d\\rho,\n$$\n\nand $\\mu_m^{(0)}$ are the positive solutions to $J_0(\\mu) = 0$.\n\n...\n\n\n\n...\n\nAnimation:\n\n\n\n::: {#d8e21121 .cell execution_count=3}\n``` {.python .cell-code code-fold=\"true\" code-summary=\"Click to expand the code\"}\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.animation import FuncAnimation\nfrom scipy.optimize import root_scalar\nfrom scipy.special import jv as besselj\n\n\ndef CircularMembrane(a=0.5, r=3, tmax=30, N=40):\n rho = np.linspace(0, r, 51) # Radial grid points\n phi = np.linspace(0, 2 * np.pi, 51) # Angular grid points\n t = np.linspace(0, tmax, 100) # Time steps\n\n # Find the first 40 positive zeros of the Bessel function J0\n mju = []\n for n in range(1, N + 1):\n zero = root_scalar(\n lambda x: besselj(0, x), bracket=[(n - 1) * np.pi, n * np.pi]\n )\n mju.append(zero.root)\n mju = np.array(mju)\n\n # Define the initial position function\n def tau(rho):\n return rho**2 * np.sin(np.pi * rho) ** 3\n\n # Compute the solution for given R and t\n def solution(R, t):\n y = np.zeros_like(R)\n for m in range(N):\n s = tau(R[0, :]) * R[0, :] * besselj(0, mju[m] * R[0, :] / r)\n A0m = 4 * np.trapezoid(s, R[0, :]) / ((r**2) * (besselj(1, mju[m]) ** 2))\n y += A0m * np.cos(a * mju[m] * t / r) * besselj(0, mju[m] * R / r)\n return y\n\n # Create a grid of points\n R, p = np.meshgrid(rho, phi)\n X = R * np.cos(p)\n Y = R * np.sin(p)\n\n # Set up the figure and axis for animation\n fig = plt.figure()\n ax = fig.add_subplot(111, projection=\"3d\")\n ax.set_xlim(-r, r)\n ax.set_ylim(-r, r)\n ax.set_zlim(-30, 30)\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n ax.set_title(\"Circular Membrane\")\n\n # Update function for animation\n def update(frame):\n ax.clear()\n Z = solution(R, frame)\n ax.plot_surface(X, Y, Z, cmap=\"viridis\", vmin=-30, vmax=30)\n ax.set_xlim(-r, r)\n ax.set_ylim(-r, r)\n ax.set_zlim(-30, 30)\n ax.set_title(\"Circular Membrane\")\n ax.set_xlabel(\"x\")\n ax.set_ylabel(\"y\")\n ax.set_zlabel(\"u(x,y,t)\")\n\n # Create and save the animation\n anim = FuncAnimation(fig, update, frames=t, interval=50)\n anim.save(\"circular_membrane_animation.gif\", writer=\"imagemagick\", fps=20)\n\n plt.show()\n```\n:::\n\n\nSnapshots:\n\n{width=33%}{width=33%}{width=33%}\n\n# References\n\n- [1](https://www.amazon.co.uk/Partial-Differential-Equations-Graduate-Mathematics/dp/1470469421/ref=sr_1_3?crid=2BINQDJ5R7XUB&dib=eyJ2IjoiMSJ9.GgU4uQBUKYO960lL6EjVJjksjFysLhCJKEHP436_saFGnfKf4uvgqyl_3WBjV779K4AwonOY5XnkRxVFCIqqGZCCE3I8YEjIC7mzvLwUa2lBPvByBCoFxTvGhrSKGLiAKlAvTVFSlbwklqyWEj4o852csy80_D3G2Gk9pedHKz22vqyc8UI8HAxWZ1wfu5bNoaqOOEDhy0W2XLaSijLCENnzVXjxTLS5xZkMCXr72G0.NeT6LdhY-WV9xVA26fbGHp37FbAKGo7mLwpV9m_2Rdk&dib_tag=se&keywords=partial+differential+equations&nsdOptOutParam=true&qid=1734133658&sprefix=partial+diff%2Caps%2C129&sr=8-3)\n- [2](https://mathworld.wolfram.com/BesselFunctionoftheFirstKind.html)\n\n",
|
6 |
+
"supporting": [
|
7 |
+
"index_files"
|
8 |
+
],
|
9 |
+
"filters": [],
|
10 |
+
"includes": {}
|
11 |
+
}
|
12 |
+
}
|
src/_freeze/site_libs/clipboard/clipboard.min.js
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
* clipboard.js v2.0.11
|
3 |
+
* https://clipboardjs.com/
|
4 |
+
*
|
5 |
+
* Licensed MIT © Zeno Rocha
|
6 |
+
*/
|
7 |
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body},n="";return"string"==typeof t?n=o(t,e):t instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(null==t?void 0:t.type)?n=o(t.value,e):(n=r()(t),c("copy")),n};function l(t){return(l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var s=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},e=t.action,n=void 0===e?"copy":e,o=t.container,e=t.target,t=t.text;if("copy"!==n&&"cut"!==n)throw new Error('Invalid "action" value, use either "copy" or "cut"');if(void 0!==e){if(!e||"object"!==l(e)||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===n&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===n&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes')}return t?f(t,{container:o}):e?"cut"===n?a(e):f(e,{container:o}):void 0};function p(t){return(p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function d(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function y(t,e){return(y=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function h(n){var o=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(t){return!1}}();return function(){var t,e=v(n);return t=o?(t=v(this).constructor,Reflect.construct(e,arguments,t)):e.apply(this,arguments),e=this,!(t=t)||"object"!==p(t)&&"function"!=typeof t?function(t){if(void 0!==t)return t;throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}(e):t}}function v(t){return(v=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function m(t,e){t="data-clipboard-".concat(t);if(e.hasAttribute(t))return e.getAttribute(t)}var b=function(){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&y(t,e)}(r,i());var t,e,n,o=h(r);function r(t,e){var n;return function(t){if(!(t instanceof r))throw new TypeError("Cannot call a class as a function")}(this),(n=o.call(this)).resolveOptions(e),n.listenClick(t),n}return t=r,n=[{key:"copy",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body};return f(t,e)}},{key:"cut",value:function(t){return a(t)}},{key:"isSupported",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof t?[t]:t,e=!!document.queryCommandSupported;return t.forEach(function(t){e=e&&!!document.queryCommandSupported(t)}),e}}],(e=[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===p(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=u()(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget,n=this.action(e)||"copy",t=s({action:n,container:this.container,target:this.target(e),text:this.text(e)});this.emit(t?"success":"error",{action:n,text:t,trigger:e,clearSelection:function(){e&&e.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(t){return m("action",t)}},{key:"defaultTarget",value:function(t){t=m("target",t);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(t){return m("text",t)}},{key:"destroy",value:function(){this.listener.destroy()}}])&&d(t.prototype,e),n&&d(t,n),r}()},828:function(t){var e;"undefined"==typeof Element||Element.prototype.matches||((e=Element.prototype).matches=e.matchesSelector||e.mozMatchesSelector||e.msMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector),t.exports=function(t,e){for(;t&&9!==t.nodeType;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}},438:function(t,e,n){var u=n(828);function i(t,e,n,o,r){var i=function(e,n,t,o){return function(t){t.delegateTarget=u(t.target,n),t.delegateTarget&&o.call(e,t)}}.apply(this,arguments);return t.addEventListener(n,i,r),{destroy:function(){t.removeEventListener(n,i,r)}}}t.exports=function(t,e,n,o,r){return"function"==typeof t.addEventListener?i.apply(null,arguments):"function"==typeof n?i.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return i(t,e,n,o,r)}))}},879:function(t,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},370:function(t,e,n){var f=n(879),l=n(438);t.exports=function(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!f.string(e))throw new TypeError("Second argument must be a String");if(!f.fn(n))throw new TypeError("Third argument must be a Function");if(f.node(t))return c=e,a=n,(u=t).addEventListener(c,a),{destroy:function(){u.removeEventListener(c,a)}};if(f.nodeList(t))return o=t,r=e,i=n,Array.prototype.forEach.call(o,function(t){t.addEventListener(r,i)}),{destroy:function(){Array.prototype.forEach.call(o,function(t){t.removeEventListener(r,i)})}};if(f.string(t))return t=t,e=e,n=n,l(document.body,t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");var o,r,i,u,c,a}},817:function(t){t.exports=function(t){var e,n="SELECT"===t.nodeName?(t.focus(),t.value):"INPUT"===t.nodeName||"TEXTAREA"===t.nodeName?((e=t.hasAttribute("readonly"))||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),e||t.removeAttribute("readonly"),t.value):(t.hasAttribute("contenteditable")&&t.focus(),n=window.getSelection(),(e=document.createRange()).selectNodeContents(t),n.removeAllRanges(),n.addRange(e),n.toString());return n}},279:function(t){function e(){}e.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var o=this;function r(){o.off(t,r),e.apply(n,arguments)}return r._=e,this.on(t,r,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;o<r;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],r=[];if(o&&e)for(var i=0,u=o.length;i<u;i++)o[i].fn!==e&&o[i].fn._!==e&&r.push(o[i]);return r.length?n[t]=r:delete n[t],this}},t.exports=e,t.exports.TinyEmitter=e}},r={},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,{a:e}),e},o.d=function(t,e){for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o(686).default;function o(t){if(r[t])return r[t].exports;var e=r[t]={exports:{}};return n[t](e,e.exports,o),e.exports}var n,r});
|
src/_freeze/site_libs/quarto-listing/list.min.js
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
var List;List=function(){var t={"./src/add-async.js":function(t){t.exports=function(t){return function e(r,n,s){var i=r.splice(0,50);s=(s=s||[]).concat(t.add(i)),r.length>0?setTimeout((function(){e(r,n,s)}),1):(t.update(),n(s))}}},"./src/filter.js":function(t){t.exports=function(t){return t.handlers.filterStart=t.handlers.filterStart||[],t.handlers.filterComplete=t.handlers.filterComplete||[],function(e){if(t.trigger("filterStart"),t.i=1,t.reset.filter(),void 0===e)t.filtered=!1;else{t.filtered=!0;for(var r=t.items,n=0,s=r.length;n<s;n++){var i=r[n];e(i)?i.filtered=!0:i.filtered=!1}}return t.update(),t.trigger("filterComplete"),t.visibleItems}}},"./src/fuzzy-search.js":function(t,e,r){r("./src/utils/classes.js");var n=r("./src/utils/events.js"),s=r("./src/utils/extend.js"),i=r("./src/utils/to-string.js"),a=r("./src/utils/get-by-class.js"),o=r("./src/utils/fuzzy.js");t.exports=function(t,e){e=s({location:0,distance:100,threshold:.4,multiSearch:!0,searchClass:"fuzzy-search"},e=e||{});var r={search:function(n,s){for(var i=e.multiSearch?n.replace(/ +$/,"").split(/ +/):[n],a=0,o=t.items.length;a<o;a++)r.item(t.items[a],s,i)},item:function(t,e,n){for(var s=!0,i=0;i<n.length;i++){for(var a=!1,o=0,l=e.length;o<l;o++)r.values(t.values(),e[o],n[i])&&(a=!0);a||(s=!1)}t.found=s},values:function(t,r,n){if(t.hasOwnProperty(r)){var s=i(t[r]).toLowerCase();if(o(s,n,e))return!0}return!1}};return n.bind(a(t.listContainer,e.searchClass),"keyup",t.utils.events.debounce((function(e){var n=e.target||e.srcElement;t.search(n.value,r.search)}),t.searchDelay)),function(e,n){t.search(e,n,r.search)}}},"./src/index.js":function(t,e,r){var n=r("./node_modules/string-natural-compare/natural-compare.js"),s=r("./src/utils/get-by-class.js"),i=r("./src/utils/extend.js"),a=r("./src/utils/index-of.js"),o=r("./src/utils/events.js"),l=r("./src/utils/to-string.js"),u=r("./src/utils/classes.js"),c=r("./src/utils/get-attribute.js"),f=r("./src/utils/to-array.js");t.exports=function(t,e,h){var d,v=this,g=r("./src/item.js")(v),m=r("./src/add-async.js")(v),p=r("./src/pagination.js")(v);d={start:function(){v.listClass="list",v.searchClass="search",v.sortClass="sort",v.page=1e4,v.i=1,v.items=[],v.visibleItems=[],v.matchingItems=[],v.searched=!1,v.filtered=!1,v.searchColumns=void 0,v.searchDelay=0,v.handlers={updated:[]},v.valueNames=[],v.utils={getByClass:s,extend:i,indexOf:a,events:o,toString:l,naturalSort:n,classes:u,getAttribute:c,toArray:f},v.utils.extend(v,e),v.listContainer="string"==typeof t?document.getElementById(t):t,v.listContainer&&(v.list=s(v.listContainer,v.listClass,!0),v.parse=r("./src/parse.js")(v),v.templater=r("./src/templater.js")(v),v.search=r("./src/search.js")(v),v.filter=r("./src/filter.js")(v),v.sort=r("./src/sort.js")(v),v.fuzzySearch=r("./src/fuzzy-search.js")(v,e.fuzzySearch),this.handlers(),this.items(),this.pagination(),v.update())},handlers:function(){for(var t in v.handlers)v[t]&&v.handlers.hasOwnProperty(t)&&v.on(t,v[t])},items:function(){v.parse(v.list),void 0!==h&&v.add(h)},pagination:function(){if(void 0!==e.pagination){!0===e.pagination&&(e.pagination=[{}]),void 0===e.pagination[0]&&(e.pagination=[e.pagination]);for(var t=0,r=e.pagination.length;t<r;t++)p(e.pagination[t])}}},this.reIndex=function(){v.items=[],v.visibleItems=[],v.matchingItems=[],v.searched=!1,v.filtered=!1,v.parse(v.list)},this.toJSON=function(){for(var t=[],e=0,r=v.items.length;e<r;e++)t.push(v.items[e].values());return t},this.add=function(t,e){if(0!==t.length){if(!e){var r=[],n=!1;void 0===t[0]&&(t=[t]);for(var s=0,i=t.length;s<i;s++){var a;n=v.items.length>v.page,a=new g(t[s],void 0,n),v.items.push(a),r.push(a)}return v.update(),r}m(t.slice(0),e)}},this.show=function(t,e){return this.i=t,this.page=e,v.update(),v},this.remove=function(t,e,r){for(var n=0,s=0,i=v.items.length;s<i;s++)v.items[s].values()[t]==e&&(v.templater.remove(v.items[s],r),v.items.splice(s,1),i--,s--,n++);return v.update(),n},this.get=function(t,e){for(var r=[],n=0,s=v.items.length;n<s;n++){var i=v.items[n];i.values()[t]==e&&r.push(i)}return r},this.size=function(){return v.items.length},this.clear=function(){return v.templater.clear(),v.items=[],v},this.on=function(t,e){return v.handlers[t].push(e),v},this.off=function(t,e){var r=v.handlers[t],n=a(r,e);return n>-1&&r.splice(n,1),v},this.trigger=function(t){for(var e=v.handlers[t].length;e--;)v.handlers[t][e](v);return v},this.reset={filter:function(){for(var t=v.items,e=t.length;e--;)t[e].filtered=!1;return v},search:function(){for(var t=v.items,e=t.length;e--;)t[e].found=!1;return v}},this.update=function(){var t=v.items,e=t.length;v.visibleItems=[],v.matchingItems=[],v.templater.clear();for(var r=0;r<e;r++)t[r].matching()&&v.matchingItems.length+1>=v.i&&v.visibleItems.length<v.page?(t[r].show(),v.visibleItems.push(t[r]),v.matchingItems.push(t[r])):t[r].matching()?(v.matchingItems.push(t[r]),t[r].hide()):t[r].hide();return v.trigger("updated"),v},d.start()}},"./src/item.js":function(t){t.exports=function(t){return function(e,r,n){var s=this;this._values={},this.found=!1,this.filtered=!1;this.values=function(e,r){if(void 0===e)return s._values;for(var n in e)s._values[n]=e[n];!0!==r&&t.templater.set(s,s.values())},this.show=function(){t.templater.show(s)},this.hide=function(){t.templater.hide(s)},this.matching=function(){return t.filtered&&t.searched&&s.found&&s.filtered||t.filtered&&!t.searched&&s.filtered||!t.filtered&&t.searched&&s.found||!t.filtered&&!t.searched},this.visible=function(){return!(!s.elm||s.elm.parentNode!=t.list)},function(e,r,n){if(void 0===r)n?s.values(e,n):s.values(e);else{s.elm=r;var i=t.templater.get(s,e);s.values(i)}}(e,r,n)}}},"./src/pagination.js":function(t,e,r){var n=r("./src/utils/classes.js"),s=r("./src/utils/events.js"),i=r("./src/index.js");t.exports=function(t){var e=!1,r=function(r,s){if(t.page<1)return t.listContainer.style.display="none",void(e=!0);e&&(t.listContainer.style.display="block");var i,o=t.matchingItems.length,l=t.i,u=t.page,c=Math.ceil(o/u),f=Math.ceil(l/u),h=s.innerWindow||2,d=s.left||s.outerWindow||0,v=s.right||s.outerWindow||0;v=c-v,r.clear();for(var g=1;g<=c;g++){var m=f===g?"active":"";a.number(g,d,v,f,h)?(i=r.add({page:g,dotted:!1})[0],m&&n(i.elm).add(m),i.elm.firstChild.setAttribute("data-i",g),i.elm.firstChild.setAttribute("data-page",u)):a.dotted(r,g,d,v,f,h,r.size())&&(i=r.add({page:"...",dotted:!0})[0],n(i.elm).add("disabled"))}},a={number:function(t,e,r,n,s){return this.left(t,e)||this.right(t,r)||this.innerWindow(t,n,s)},left:function(t,e){return t<=e},right:function(t,e){return t>e},innerWindow:function(t,e,r){return t>=e-r&&t<=e+r},dotted:function(t,e,r,n,s,i,a){return this.dottedLeft(t,e,r,n,s,i)||this.dottedRight(t,e,r,n,s,i,a)},dottedLeft:function(t,e,r,n,s,i){return e==r+1&&!this.innerWindow(e,s,i)&&!this.right(e,n)},dottedRight:function(t,e,r,n,s,i,a){return!t.items[a-1].values().dotted&&(e==n&&!this.innerWindow(e,s,i)&&!this.right(e,n))}};return function(e){var n=new i(t.listContainer.id,{listClass:e.paginationClass||"pagination",item:e.item||"<li><a class='page' href='#'></a></li>",valueNames:["page","dotted"],searchClass:"pagination-search-that-is-not-supposed-to-exist",sortClass:"pagination-sort-that-is-not-supposed-to-exist"});s.bind(n.listContainer,"click",(function(e){var r=e.target||e.srcElement,n=t.utils.getAttribute(r,"data-page"),s=t.utils.getAttribute(r,"data-i");s&&t.show((s-1)*n+1,n)})),t.on("updated",(function(){r(n,e)})),r(n,e)}}},"./src/parse.js":function(t,e,r){t.exports=function(t){var e=r("./src/item.js")(t),n=function(r,n){for(var s=0,i=r.length;s<i;s++)t.items.push(new e(n,r[s]))},s=function e(r,s){var i=r.splice(0,50);n(i,s),r.length>0?setTimeout((function(){e(r,s)}),1):(t.update(),t.trigger("parseComplete"))};return t.handlers.parseComplete=t.handlers.parseComplete||[],function(){var e=function(t){for(var e=t.childNodes,r=[],n=0,s=e.length;n<s;n++)void 0===e[n].data&&r.push(e[n]);return r}(t.list),r=t.valueNames;t.indexAsync?s(e,r):n(e,r)}}},"./src/search.js":function(t){t.exports=function(t){var e,r,n,s={resetList:function(){t.i=1,t.templater.clear(),n=void 0},setOptions:function(t){2==t.length&&t[1]instanceof Array?e=t[1]:2==t.length&&"function"==typeof t[1]?(e=void 0,n=t[1]):3==t.length?(e=t[1],n=t[2]):e=void 0},setColumns:function(){0!==t.items.length&&void 0===e&&(e=void 0===t.searchColumns?s.toArray(t.items[0].values()):t.searchColumns)},setSearchString:function(e){e=(e=t.utils.toString(e).toLowerCase()),r=e},toArray:function(t){var e=[];for(var r in t)e.push(r);return e}},i=function(){for(var n,s=[],i=r;null!==(n=i.match(/"([^"]+)"/));)s.push(n[1]),i=i.substring(0,n.index)+i.substring(n.index+n[0].length);(i=i.trim()).length&&(s=s.concat(i.split(/\s+/)));for(var a=0,o=t.items.length;a<o;a++){var l=t.items[a];if(l.found=!1,s.length){for(var u=0,c=s.length;u<c;u++){for(var f=!1,h=0,d=e.length;h<d;h++){var v=l.values(),g=e[h];if(v.hasOwnProperty(g)&&void 0!==v[g]&&null!==v[g])if(-1!==("string"!=typeof v[g]?v[g].toString():v[g]).toLowerCase().indexOf(s[u])){f=!0;break}}if(!f)break}l.found=f}}},a=function(){t.reset.search(),t.searched=!1},o=function(o){return t.trigger("searchStart"),s.resetList(),s.setSearchString(o),s.setOptions(arguments),s.setColumns(),""===r?a():(t.searched=!0,n?n(r,e):i()),t.update(),t.trigger("searchComplete"),t.visibleItems};return t.handlers.searchStart=t.handlers.searchStart||[],t.handlers.searchComplete=t.handlers.searchComplete||[],t.utils.events.bind(t.utils.getByClass(t.listContainer,t.searchClass),"keyup",t.utils.events.debounce((function(e){var r=e.target||e.srcElement;""===r.value&&!t.searched||o(r.value)}),t.searchDelay)),t.utils.events.bind(t.utils.getByClass(t.listContainer,t.searchClass),"input",(function(t){""===(t.target||t.srcElement).value&&o("")})),o}},"./src/sort.js":function(t){t.exports=function(t){var e={els:void 0,clear:function(){for(var r=0,n=e.els.length;r<n;r++)t.utils.classes(e.els[r]).remove("asc"),t.utils.classes(e.els[r]).remove("desc")},getOrder:function(e){var r=t.utils.getAttribute(e,"data-order");return"asc"==r||"desc"==r?r:t.utils.classes(e).has("desc")?"asc":t.utils.classes(e).has("asc")?"desc":"asc"},getInSensitive:function(e,r){var n=t.utils.getAttribute(e,"data-insensitive");r.insensitive="false"!==n},setOrder:function(r){for(var n=0,s=e.els.length;n<s;n++){var i=e.els[n];if(t.utils.getAttribute(i,"data-sort")===r.valueName){var a=t.utils.getAttribute(i,"data-order");"asc"==a||"desc"==a?a==r.order&&t.utils.classes(i).add(r.order):t.utils.classes(i).add(r.order)}}}},r=function(){t.trigger("sortStart");var r={},n=arguments[0].currentTarget||arguments[0].srcElement||void 0;n?(r.valueName=t.utils.getAttribute(n,"data-sort"),e.getInSensitive(n,r),r.order=e.getOrder(n)):((r=arguments[1]||r).valueName=arguments[0],r.order=r.order||"asc",r.insensitive=void 0===r.insensitive||r.insensitive),e.clear(),e.setOrder(r);var s,i=r.sortFunction||t.sortFunction||null,a="desc"===r.order?-1:1;s=i?function(t,e){return i(t,e,r)*a}:function(e,n){var s=t.utils.naturalSort;return s.alphabet=t.alphabet||r.alphabet||void 0,!s.alphabet&&r.insensitive&&(s=t.utils.naturalSort.caseInsensitive),s(e.values()[r.valueName],n.values()[r.valueName])*a},t.items.sort(s),t.update(),t.trigger("sortComplete")};return t.handlers.sortStart=t.handlers.sortStart||[],t.handlers.sortComplete=t.handlers.sortComplete||[],e.els=t.utils.getByClass(t.listContainer,t.sortClass),t.utils.events.bind(e.els,"click",r),t.on("searchStart",e.clear),t.on("filterStart",e.clear),r}},"./src/templater.js":function(t){var e=function(t){var e,r=this,n=function(e,r){var n=e.cloneNode(!0);n.removeAttribute("id");for(var s=0,i=r.length;s<i;s++){var a=void 0,o=r[s];if(o.data)for(var l=0,u=o.data.length;l<u;l++)n.setAttribute("data-"+o.data[l],"");else o.attr&&o.name?(a=t.utils.getByClass(n,o.name,!0))&&a.setAttribute(o.attr,""):(a=t.utils.getByClass(n,o,!0))&&(a.innerHTML="")}return n},s=function(){for(var e=t.list.childNodes,r=0,n=e.length;r<n;r++)if(void 0===e[r].data)return e[r].cloneNode(!0)},i=function(t){if("string"==typeof t){if(/<tr[\s>]/g.exec(t)){var e=document.createElement("tbody");return e.innerHTML=t,e.firstElementChild}if(-1!==t.indexOf("<")){var r=document.createElement("div");return r.innerHTML=t,r.firstElementChild}}},a=function(e,r,n){var s=void 0,i=function(e){for(var r=0,n=t.valueNames.length;r<n;r++){var s=t.valueNames[r];if(s.data){for(var i=s.data,a=0,o=i.length;a<o;a++)if(i[a]===e)return{data:e}}else{if(s.attr&&s.name&&s.name==e)return s;if(s===e)return e}}}(r);i&&(i.data?e.elm.setAttribute("data-"+i.data,n):i.attr&&i.name?(s=t.utils.getByClass(e.elm,i.name,!0))&&s.setAttribute(i.attr,n):(s=t.utils.getByClass(e.elm,i,!0))&&(s.innerHTML=n))};this.get=function(e,n){r.create(e);for(var s={},i=0,a=n.length;i<a;i++){var o=void 0,l=n[i];if(l.data)for(var u=0,c=l.data.length;u<c;u++)s[l.data[u]]=t.utils.getAttribute(e.elm,"data-"+l.data[u]);else l.attr&&l.name?(o=t.utils.getByClass(e.elm,l.name,!0),s[l.name]=o?t.utils.getAttribute(o,l.attr):""):(o=t.utils.getByClass(e.elm,l,!0),s[l]=o?o.innerHTML:"")}return s},this.set=function(t,e){if(!r.create(t))for(var n in e)e.hasOwnProperty(n)&&a(t,n,e[n])},this.create=function(t){return void 0===t.elm&&(t.elm=e(t.values()),r.set(t,t.values()),!0)},this.remove=function(e){e.elm.parentNode===t.list&&t.list.removeChild(e.elm)},this.show=function(e){r.create(e),t.list.appendChild(e.elm)},this.hide=function(e){void 0!==e.elm&&e.elm.parentNode===t.list&&t.list.removeChild(e.elm)},this.clear=function(){if(t.list.hasChildNodes())for(;t.list.childNodes.length>=1;)t.list.removeChild(t.list.firstChild)},function(){var r;if("function"!=typeof t.item){if(!(r="string"==typeof t.item?-1===t.item.indexOf("<")?document.getElementById(t.item):i(t.item):s()))throw new Error("The list needs to have at least one item on init otherwise you'll have to add a template.");r=n(r,t.valueNames),e=function(){return r.cloneNode(!0)}}else e=function(e){var r=t.item(e);return i(r)}}()};t.exports=function(t){return new e(t)}},"./src/utils/classes.js":function(t,e,r){var n=r("./src/utils/index-of.js"),s=/\s+/;Object.prototype.toString;function i(t){if(!t||!t.nodeType)throw new Error("A DOM element reference is required");this.el=t,this.list=t.classList}t.exports=function(t){return new i(t)},i.prototype.add=function(t){if(this.list)return this.list.add(t),this;var e=this.array();return~n(e,t)||e.push(t),this.el.className=e.join(" "),this},i.prototype.remove=function(t){if(this.list)return this.list.remove(t),this;var e=this.array(),r=n(e,t);return~r&&e.splice(r,1),this.el.className=e.join(" "),this},i.prototype.toggle=function(t,e){return this.list?(void 0!==e?e!==this.list.toggle(t,e)&&this.list.toggle(t):this.list.toggle(t),this):(void 0!==e?e?this.add(t):this.remove(t):this.has(t)?this.remove(t):this.add(t),this)},i.prototype.array=function(){var t=(this.el.getAttribute("class")||"").replace(/^\s+|\s+$/g,"").split(s);return""===t[0]&&t.shift(),t},i.prototype.has=i.prototype.contains=function(t){return this.list?this.list.contains(t):!!~n(this.array(),t)}},"./src/utils/events.js":function(t,e,r){var n=window.addEventListener?"addEventListener":"attachEvent",s=window.removeEventListener?"removeEventListener":"detachEvent",i="addEventListener"!==n?"on":"",a=r("./src/utils/to-array.js");e.bind=function(t,e,r,s){for(var o=0,l=(t=a(t)).length;o<l;o++)t[o][n](i+e,r,s||!1)},e.unbind=function(t,e,r,n){for(var o=0,l=(t=a(t)).length;o<l;o++)t[o][s](i+e,r,n||!1)},e.debounce=function(t,e,r){var n;return e?function(){var s=this,i=arguments,a=function(){n=null,r||t.apply(s,i)},o=r&&!n;clearTimeout(n),n=setTimeout(a,e),o&&t.apply(s,i)}:t}},"./src/utils/extend.js":function(t){t.exports=function(t){for(var e,r=Array.prototype.slice.call(arguments,1),n=0;e=r[n];n++)if(e)for(var s in e)t[s]=e[s];return t}},"./src/utils/fuzzy.js":function(t){t.exports=function(t,e,r){var n=r.location||0,s=r.distance||100,i=r.threshold||.4;if(e===t)return!0;if(e.length>32)return!1;var a=n,o=function(){var t,r={};for(t=0;t<e.length;t++)r[e.charAt(t)]=0;for(t=0;t<e.length;t++)r[e.charAt(t)]|=1<<e.length-t-1;return r}();function l(t,r){var n=t/e.length,i=Math.abs(a-r);return s?n+i/s:i?1:n}var u=i,c=t.indexOf(e,a);-1!=c&&(u=Math.min(l(0,c),u),-1!=(c=t.lastIndexOf(e,a+e.length))&&(u=Math.min(l(0,c),u)));var f,h,d=1<<e.length-1;c=-1;for(var v,g=e.length+t.length,m=0;m<e.length;m++){for(f=0,h=g;f<h;)l(m,a+h)<=u?f=h:g=h,h=Math.floor((g-f)/2+f);g=h;var p=Math.max(1,a-h+1),y=Math.min(a+h,t.length)+e.length,C=Array(y+2);C[y+1]=(1<<m)-1;for(var b=y;b>=p;b--){var j=o[t.charAt(b-1)];if(C[b]=0===m?(C[b+1]<<1|1)&j:(C[b+1]<<1|1)&j|(v[b+1]|v[b])<<1|1|v[b+1],C[b]&d){var x=l(m,b-1);if(x<=u){if(u=x,!((c=b-1)>a))break;p=Math.max(1,2*a-c)}}}if(l(m+1,a)>u)break;v=C}return!(c<0)}},"./src/utils/get-attribute.js":function(t){t.exports=function(t,e){var r=t.getAttribute&&t.getAttribute(e)||null;if(!r)for(var n=t.attributes,s=n.length,i=0;i<s;i++)void 0!==n[i]&&n[i].nodeName===e&&(r=n[i].nodeValue);return r}},"./src/utils/get-by-class.js":function(t){t.exports=function(t,e,r,n){return(n=n||{}).test&&n.getElementsByClassName||!n.test&&document.getElementsByClassName?function(t,e,r){return r?t.getElementsByClassName(e)[0]:t.getElementsByClassName(e)}(t,e,r):n.test&&n.querySelector||!n.test&&document.querySelector?function(t,e,r){return e="."+e,r?t.querySelector(e):t.querySelectorAll(e)}(t,e,r):function(t,e,r){for(var n=[],s=t.getElementsByTagName("*"),i=s.length,a=new RegExp("(^|\\s)"+e+"(\\s|$)"),o=0,l=0;o<i;o++)if(a.test(s[o].className)){if(r)return s[o];n[l]=s[o],l++}return n}(t,e,r)}},"./src/utils/index-of.js":function(t){var e=[].indexOf;t.exports=function(t,r){if(e)return t.indexOf(r);for(var n=0,s=t.length;n<s;++n)if(t[n]===r)return n;return-1}},"./src/utils/to-array.js":function(t){t.exports=function(t){if(void 0===t)return[];if(null===t)return[null];if(t===window)return[window];if("string"==typeof t)return[t];if(function(t){return"[object Array]"===Object.prototype.toString.call(t)}(t))return t;if("number"!=typeof t.length)return[t];if("function"==typeof t&&t instanceof Function)return[t];for(var e=[],r=0,n=t.length;r<n;r++)(Object.prototype.hasOwnProperty.call(t,r)||r in t)&&e.push(t[r]);return e.length?e:[]}},"./src/utils/to-string.js":function(t){t.exports=function(t){return t=(t=null===(t=void 0===t?"":t)?"":t).toString()}},"./node_modules/string-natural-compare/natural-compare.js":function(t){"use strict";var e,r,n=0;function s(t){return t>=48&&t<=57}function i(t,e){for(var i=(t+="").length,a=(e+="").length,o=0,l=0;o<i&&l<a;){var u=t.charCodeAt(o),c=e.charCodeAt(l);if(s(u)){if(!s(c))return u-c;for(var f=o,h=l;48===u&&++f<i;)u=t.charCodeAt(f);for(;48===c&&++h<a;)c=e.charCodeAt(h);for(var d=f,v=h;d<i&&s(t.charCodeAt(d));)++d;for(;v<a&&s(e.charCodeAt(v));)++v;var g=d-f-v+h;if(g)return g;for(;f<d;)if(g=t.charCodeAt(f++)-e.charCodeAt(h++))return g;o=d,l=v}else{if(u!==c)return u<n&&c<n&&-1!==r[u]&&-1!==r[c]?r[u]-r[c]:u-c;++o,++l}}return o>=i&&l<a&&i>=a?-1:l>=a&&o<i&&a>=i?1:i-a}i.caseInsensitive=i.i=function(t,e){return i((""+t).toLowerCase(),(""+e).toLowerCase())},Object.defineProperties(i,{alphabet:{get:function(){return e},set:function(t){r=[];var s=0;if(e=t)for(;s<e.length;s++)r[e.charCodeAt(s)]=s;for(n=r.length,s=0;s<n;s++)void 0===r[s]&&(r[s]=-1)}}}),t.exports=i}},e={};return function r(n){if(e[n])return e[n].exports;var s=e[n]={exports:{}};return t[n](s,s.exports,r),s.exports}("./src/index.js")}();
|
2 |
+
//# sourceMappingURL=list.min.js.map
|
src/_freeze/site_libs/quarto-listing/quarto-listing.js
ADDED
@@ -0,0 +1,253 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const kProgressiveAttr = "data-src";
|
2 |
+
let categoriesLoaded = false;
|
3 |
+
|
4 |
+
window.quartoListingCategory = (category) => {
|
5 |
+
category = atob(category);
|
6 |
+
if (categoriesLoaded) {
|
7 |
+
activateCategory(category);
|
8 |
+
setCategoryHash(category);
|
9 |
+
}
|
10 |
+
};
|
11 |
+
|
12 |
+
window["quarto-listing-loaded"] = () => {
|
13 |
+
// Process any existing hash
|
14 |
+
const hash = getHash();
|
15 |
+
|
16 |
+
if (hash) {
|
17 |
+
// If there is a category, switch to that
|
18 |
+
if (hash.category) {
|
19 |
+
// category hash are URI encoded so we need to decode it before processing
|
20 |
+
// so that we can match it with the category element processed in JS
|
21 |
+
activateCategory(decodeURIComponent(hash.category));
|
22 |
+
}
|
23 |
+
// Paginate a specific listing
|
24 |
+
const listingIds = Object.keys(window["quarto-listings"]);
|
25 |
+
for (const listingId of listingIds) {
|
26 |
+
const page = hash[getListingPageKey(listingId)];
|
27 |
+
if (page) {
|
28 |
+
showPage(listingId, page);
|
29 |
+
}
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
const listingIds = Object.keys(window["quarto-listings"]);
|
34 |
+
for (const listingId of listingIds) {
|
35 |
+
// The actual list
|
36 |
+
const list = window["quarto-listings"][listingId];
|
37 |
+
|
38 |
+
// Update the handlers for pagination events
|
39 |
+
refreshPaginationHandlers(listingId);
|
40 |
+
|
41 |
+
// Render any visible items that need it
|
42 |
+
renderVisibleProgressiveImages(list);
|
43 |
+
|
44 |
+
// Whenever the list is updated, we also need to
|
45 |
+
// attach handlers to the new pagination elements
|
46 |
+
// and refresh any newly visible items.
|
47 |
+
list.on("updated", function () {
|
48 |
+
renderVisibleProgressiveImages(list);
|
49 |
+
setTimeout(() => refreshPaginationHandlers(listingId));
|
50 |
+
|
51 |
+
// Show or hide the no matching message
|
52 |
+
toggleNoMatchingMessage(list);
|
53 |
+
});
|
54 |
+
}
|
55 |
+
};
|
56 |
+
|
57 |
+
window.document.addEventListener("DOMContentLoaded", function (_event) {
|
58 |
+
// Attach click handlers to categories
|
59 |
+
const categoryEls = window.document.querySelectorAll(
|
60 |
+
".quarto-listing-category .category"
|
61 |
+
);
|
62 |
+
|
63 |
+
for (const categoryEl of categoryEls) {
|
64 |
+
// category needs to support non ASCII characters
|
65 |
+
const category = decodeURIComponent(
|
66 |
+
atob(categoryEl.getAttribute("data-category"))
|
67 |
+
);
|
68 |
+
categoryEl.onclick = () => {
|
69 |
+
activateCategory(category);
|
70 |
+
setCategoryHash(category);
|
71 |
+
};
|
72 |
+
}
|
73 |
+
|
74 |
+
// Attach a click handler to the category title
|
75 |
+
// (there should be only one, but since it is a class name, handle N)
|
76 |
+
const categoryTitleEls = window.document.querySelectorAll(
|
77 |
+
".quarto-listing-category-title"
|
78 |
+
);
|
79 |
+
for (const categoryTitleEl of categoryTitleEls) {
|
80 |
+
categoryTitleEl.onclick = () => {
|
81 |
+
activateCategory("");
|
82 |
+
setCategoryHash("");
|
83 |
+
};
|
84 |
+
}
|
85 |
+
|
86 |
+
categoriesLoaded = true;
|
87 |
+
});
|
88 |
+
|
89 |
+
function toggleNoMatchingMessage(list) {
|
90 |
+
const selector = `#${list.listContainer.id} .listing-no-matching`;
|
91 |
+
const noMatchingEl = window.document.querySelector(selector);
|
92 |
+
if (noMatchingEl) {
|
93 |
+
if (list.visibleItems.length === 0) {
|
94 |
+
noMatchingEl.classList.remove("d-none");
|
95 |
+
} else {
|
96 |
+
if (!noMatchingEl.classList.contains("d-none")) {
|
97 |
+
noMatchingEl.classList.add("d-none");
|
98 |
+
}
|
99 |
+
}
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
function setCategoryHash(category) {
|
104 |
+
setHash({ category });
|
105 |
+
}
|
106 |
+
|
107 |
+
function setPageHash(listingId, page) {
|
108 |
+
const currentHash = getHash() || {};
|
109 |
+
currentHash[getListingPageKey(listingId)] = page;
|
110 |
+
setHash(currentHash);
|
111 |
+
}
|
112 |
+
|
113 |
+
function getListingPageKey(listingId) {
|
114 |
+
return `${listingId}-page`;
|
115 |
+
}
|
116 |
+
|
117 |
+
function refreshPaginationHandlers(listingId) {
|
118 |
+
const listingEl = window.document.getElementById(listingId);
|
119 |
+
const paginationEls = listingEl.querySelectorAll(
|
120 |
+
".pagination li.page-item:not(.disabled) .page.page-link"
|
121 |
+
);
|
122 |
+
for (const paginationEl of paginationEls) {
|
123 |
+
paginationEl.onclick = (sender) => {
|
124 |
+
setPageHash(listingId, sender.target.getAttribute("data-i"));
|
125 |
+
showPage(listingId, sender.target.getAttribute("data-i"));
|
126 |
+
return false;
|
127 |
+
};
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
function renderVisibleProgressiveImages(list) {
|
132 |
+
// Run through the visible items and render any progressive images
|
133 |
+
for (const item of list.visibleItems) {
|
134 |
+
const itemEl = item.elm;
|
135 |
+
if (itemEl) {
|
136 |
+
const progressiveImgs = itemEl.querySelectorAll(
|
137 |
+
`img[${kProgressiveAttr}]`
|
138 |
+
);
|
139 |
+
for (const progressiveImg of progressiveImgs) {
|
140 |
+
const srcValue = progressiveImg.getAttribute(kProgressiveAttr);
|
141 |
+
if (srcValue) {
|
142 |
+
progressiveImg.setAttribute("src", srcValue);
|
143 |
+
}
|
144 |
+
progressiveImg.removeAttribute(kProgressiveAttr);
|
145 |
+
}
|
146 |
+
}
|
147 |
+
}
|
148 |
+
}
|
149 |
+
|
150 |
+
function getHash() {
|
151 |
+
// Hashes are of the form
|
152 |
+
// #name:value|name1:value1|name2:value2
|
153 |
+
const currentUrl = new URL(window.location);
|
154 |
+
const hashRaw = currentUrl.hash ? currentUrl.hash.slice(1) : undefined;
|
155 |
+
return parseHash(hashRaw);
|
156 |
+
}
|
157 |
+
|
158 |
+
const kAnd = "&";
|
159 |
+
const kEquals = "=";
|
160 |
+
|
161 |
+
function parseHash(hash) {
|
162 |
+
if (!hash) {
|
163 |
+
return undefined;
|
164 |
+
}
|
165 |
+
const hasValuesStrs = hash.split(kAnd);
|
166 |
+
const hashValues = hasValuesStrs
|
167 |
+
.map((hashValueStr) => {
|
168 |
+
const vals = hashValueStr.split(kEquals);
|
169 |
+
if (vals.length === 2) {
|
170 |
+
return { name: vals[0], value: vals[1] };
|
171 |
+
} else {
|
172 |
+
return undefined;
|
173 |
+
}
|
174 |
+
})
|
175 |
+
.filter((value) => {
|
176 |
+
return value !== undefined;
|
177 |
+
});
|
178 |
+
|
179 |
+
const hashObj = {};
|
180 |
+
hashValues.forEach((hashValue) => {
|
181 |
+
hashObj[hashValue.name] = decodeURIComponent(hashValue.value);
|
182 |
+
});
|
183 |
+
return hashObj;
|
184 |
+
}
|
185 |
+
|
186 |
+
function makeHash(obj) {
|
187 |
+
return Object.keys(obj)
|
188 |
+
.map((key) => {
|
189 |
+
return `${key}${kEquals}${obj[key]}`;
|
190 |
+
})
|
191 |
+
.join(kAnd);
|
192 |
+
}
|
193 |
+
|
194 |
+
function setHash(obj) {
|
195 |
+
const hash = makeHash(obj);
|
196 |
+
window.history.pushState(null, null, `#${hash}`);
|
197 |
+
}
|
198 |
+
|
199 |
+
function showPage(listingId, page) {
|
200 |
+
const list = window["quarto-listings"][listingId];
|
201 |
+
if (list) {
|
202 |
+
list.show((page - 1) * list.page + 1, list.page);
|
203 |
+
}
|
204 |
+
}
|
205 |
+
|
206 |
+
function activateCategory(category) {
|
207 |
+
// Deactivate existing categories
|
208 |
+
const activeEls = window.document.querySelectorAll(
|
209 |
+
".quarto-listing-category .category.active"
|
210 |
+
);
|
211 |
+
for (const activeEl of activeEls) {
|
212 |
+
activeEl.classList.remove("active");
|
213 |
+
}
|
214 |
+
|
215 |
+
// Activate this category
|
216 |
+
const categoryEl = window.document.querySelector(
|
217 |
+
`.quarto-listing-category .category[data-category='${btoa(
|
218 |
+
encodeURIComponent(category)
|
219 |
+
)}']`
|
220 |
+
);
|
221 |
+
if (categoryEl) {
|
222 |
+
categoryEl.classList.add("active");
|
223 |
+
}
|
224 |
+
|
225 |
+
// Filter the listings to this category
|
226 |
+
filterListingCategory(category);
|
227 |
+
}
|
228 |
+
|
229 |
+
function filterListingCategory(category) {
|
230 |
+
const listingIds = Object.keys(window["quarto-listings"]);
|
231 |
+
for (const listingId of listingIds) {
|
232 |
+
const list = window["quarto-listings"][listingId];
|
233 |
+
if (list) {
|
234 |
+
if (category === "") {
|
235 |
+
// resets the filter
|
236 |
+
list.filter();
|
237 |
+
} else {
|
238 |
+
// filter to this category
|
239 |
+
list.filter(function (item) {
|
240 |
+
const itemValues = item.values();
|
241 |
+
if (itemValues.categories !== null) {
|
242 |
+
const categories = decodeURIComponent(
|
243 |
+
atob(itemValues.categories)
|
244 |
+
).split(",");
|
245 |
+
return categories.includes(category);
|
246 |
+
} else {
|
247 |
+
return false;
|
248 |
+
}
|
249 |
+
});
|
250 |
+
}
|
251 |
+
}
|
252 |
+
}
|
253 |
+
}
|
src/_quarto.yml
CHANGED
@@ -1,37 +1,21 @@
|
|
1 |
project:
|
2 |
type: website
|
3 |
-
website:
|
4 |
-
title: "Open-Source AI Cookbook"
|
5 |
-
sidebar:
|
6 |
-
style: "docked"
|
7 |
-
search: true
|
8 |
-
collapse-level: 3
|
9 |
-
contents:
|
10 |
-
- section: "About"
|
11 |
-
contents:
|
12 |
-
- href: index.qmd
|
13 |
-
text: About Quarto
|
14 |
-
- section: "Open-Source AI Cookbook"
|
15 |
-
contents:
|
16 |
-
- section: "RAG Techniques"
|
17 |
-
contents:
|
18 |
-
- href: notebooks/rag_zephyr_langchain.qmd
|
19 |
-
text: "RAG Zephyr & LangChain"
|
20 |
-
- href: notebooks/advanced_rag.qmd
|
21 |
-
text: "Advanced RAG"
|
22 |
-
- href: notebooks/rag_evaluation.qmd
|
23 |
-
text: "RAG Evaluation"
|
24 |
-
- section: "Additional Techniques"
|
25 |
-
contents:
|
26 |
-
- href: notebooks/automatic_embedding.ipynb
|
27 |
-
text: "Automatic Embedding"
|
28 |
-
- href: notebooks/faiss.ipynb
|
29 |
-
text: "FAISS for Efficient Search"
|
30 |
-
- href: notebooks/single_gpu.ipynb
|
31 |
-
text: "Single GPU Optimization"
|
32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
format:
|
34 |
html:
|
35 |
-
theme:
|
|
|
36 |
css: styles.css
|
37 |
-
|
|
|
|
|
|
|
|
1 |
project:
|
2 |
type: website
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
+
website:
|
5 |
+
title: "quarto-blog"
|
6 |
+
navbar:
|
7 |
+
right:
|
8 |
+
- about.qmd
|
9 |
+
- icon: github
|
10 |
+
href: https://github.com/
|
11 |
+
- icon: twitter
|
12 |
+
href: https://twitter.com
|
13 |
format:
|
14 |
html:
|
15 |
+
theme: flatly
|
16 |
+
html-math-method: mathjax
|
17 |
css: styles.css
|
18 |
+
|
19 |
+
execute:
|
20 |
+
eval: false
|
21 |
+
freeze: true
|
src/_site/about.html
ADDED
@@ -0,0 +1,559 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
3 |
+
|
4 |
+
<meta charset="utf-8">
|
5 |
+
<meta name="generator" content="quarto-1.6.39">
|
6 |
+
|
7 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
8 |
+
|
9 |
+
|
10 |
+
<title>About – quarto-blog</title>
|
11 |
+
<style>
|
12 |
+
code{white-space: pre-wrap;}
|
13 |
+
span.smallcaps{font-variant: small-caps;}
|
14 |
+
div.columns{display: flex; gap: min(4vw, 1.5em);}
|
15 |
+
div.column{flex: auto; overflow-x: auto;}
|
16 |
+
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
17 |
+
ul.task-list{list-style: none;}
|
18 |
+
ul.task-list li input[type="checkbox"] {
|
19 |
+
width: 0.8em;
|
20 |
+
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
|
21 |
+
vertical-align: middle;
|
22 |
+
}
|
23 |
+
</style>
|
24 |
+
|
25 |
+
|
26 |
+
<script src="site_libs/quarto-nav/quarto-nav.js"></script>
|
27 |
+
<script src="site_libs/quarto-nav/headroom.min.js"></script>
|
28 |
+
<script src="site_libs/clipboard/clipboard.min.js"></script>
|
29 |
+
<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
|
30 |
+
<script src="site_libs/quarto-search/fuse.min.js"></script>
|
31 |
+
<script src="site_libs/quarto-search/quarto-search.js"></script>
|
32 |
+
<meta name="quarto:offset" content="./">
|
33 |
+
<script src="site_libs/quarto-html/quarto.js"></script>
|
34 |
+
<script src="site_libs/quarto-html/popper.min.js"></script>
|
35 |
+
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
|
36 |
+
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
|
37 |
+
<link href="site_libs/quarto-html/quarto-syntax-highlighting-e26003cea8cd680ca0c55a263523d882.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
38 |
+
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
|
39 |
+
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
40 |
+
<link href="site_libs/bootstrap/bootstrap-d1b12f2568ecbe55642fee6aa00bd082.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
41 |
+
<script id="quarto-search-options" type="application/json">{
|
42 |
+
"location": "navbar",
|
43 |
+
"copy-button": false,
|
44 |
+
"collapse-after": 3,
|
45 |
+
"panel-placement": "end",
|
46 |
+
"type": "overlay",
|
47 |
+
"limit": 50,
|
48 |
+
"keyboard-shortcut": [
|
49 |
+
"f",
|
50 |
+
"/",
|
51 |
+
"s"
|
52 |
+
],
|
53 |
+
"show-item-context": false,
|
54 |
+
"language": {
|
55 |
+
"search-no-results-text": "No results",
|
56 |
+
"search-matching-documents-text": "matching documents",
|
57 |
+
"search-copy-link-title": "Copy link to search",
|
58 |
+
"search-hide-matches-text": "Hide additional matches",
|
59 |
+
"search-more-match-text": "more match in this document",
|
60 |
+
"search-more-matches-text": "more matches in this document",
|
61 |
+
"search-clear-button-title": "Clear",
|
62 |
+
"search-text-placeholder": "",
|
63 |
+
"search-detached-cancel-button-title": "Cancel",
|
64 |
+
"search-submit-button-title": "Submit",
|
65 |
+
"search-label": "Search"
|
66 |
+
}
|
67 |
+
}</script>
|
68 |
+
|
69 |
+
|
70 |
+
<link rel="stylesheet" href="styles.css">
|
71 |
+
</head>
|
72 |
+
|
73 |
+
<body class="nav-fixed fullcontent">
|
74 |
+
|
75 |
+
<div id="quarto-search-results"></div>
|
76 |
+
<header id="quarto-header" class="headroom fixed-top">
|
77 |
+
<nav class="navbar navbar-expand-lg " data-bs-theme="dark">
|
78 |
+
<div class="navbar-container container-fluid">
|
79 |
+
<div class="navbar-brand-container mx-auto">
|
80 |
+
<a class="navbar-brand" href="./index.html">
|
81 |
+
<span class="navbar-title">quarto-blog</span>
|
82 |
+
</a>
|
83 |
+
</div>
|
84 |
+
<div id="quarto-search" class="" title="Search"></div>
|
85 |
+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" role="menu" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
86 |
+
<span class="navbar-toggler-icon"></span>
|
87 |
+
</button>
|
88 |
+
<div class="collapse navbar-collapse" id="navbarCollapse">
|
89 |
+
<ul class="navbar-nav navbar-nav-scroll ms-auto">
|
90 |
+
<li class="nav-item">
|
91 |
+
<a class="nav-link active" href="./about.html" aria-current="page">
|
92 |
+
<span class="menu-text">About</span></a>
|
93 |
+
</li>
|
94 |
+
<li class="nav-item compact">
|
95 |
+
<a class="nav-link" href="https://github.com/"> <i class="bi bi-github" role="img">
|
96 |
+
</i>
|
97 |
+
<span class="menu-text"></span></a>
|
98 |
+
</li>
|
99 |
+
<li class="nav-item compact">
|
100 |
+
<a class="nav-link" href="https://twitter.com"> <i class="bi bi-twitter" role="img">
|
101 |
+
</i>
|
102 |
+
<span class="menu-text"></span></a>
|
103 |
+
</li>
|
104 |
+
</ul>
|
105 |
+
</div> <!-- /navcollapse -->
|
106 |
+
<div class="quarto-navbar-tools">
|
107 |
+
</div>
|
108 |
+
</div> <!-- /container-fluid -->
|
109 |
+
</nav>
|
110 |
+
</header>
|
111 |
+
<!-- content -->
|
112 |
+
<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
|
113 |
+
<!-- sidebar -->
|
114 |
+
<!-- margin-sidebar -->
|
115 |
+
|
116 |
+
<!-- main -->
|
117 |
+
<div class="quarto-about-jolla">
|
118 |
+
<img src="profile.jpg" class="about-image
|
119 |
+
round " style="height: 15em; width: 15em;">
|
120 |
+
<header id="title-block-header" class="quarto-title-block default">
|
121 |
+
<div class="quarto-title">
|
122 |
+
<h1 class="title">About</h1>
|
123 |
+
</div>
|
124 |
+
<div class="quarto-title-meta">
|
125 |
+
</div>
|
126 |
+
</header><main class="content" id="quarto-document-content">
|
127 |
+
<p>About this blog</p>
|
128 |
+
|
129 |
+
|
130 |
+
</main>
|
131 |
+
<hr class="about-sep">
|
132 |
+
<div class="about-links">
|
133 |
+
<a href="https://www.linkedin.com/in/joana-levtcheva-479844164/" class="about-link" rel="" target="">
|
134 |
+
<i class="bi bi-linkedin"></i>
|
135 |
+
<span class="about-link-text">LinkedIn</span>
|
136 |
+
</a>
|
137 |
+
<a href="https://github.com/JoeJoe1313" class="about-link" rel="" target="">
|
138 |
+
<i class="bi bi-github"></i>
|
139 |
+
<span class="about-link-text">Github</span>
|
140 |
+
</a>
|
141 |
+
</div>
|
142 |
+
</div>
|
143 |
+
<!-- /main -->
|
144 |
+
<script id="quarto-html-after-body" type="application/javascript">
|
145 |
+
window.document.addEventListener("DOMContentLoaded", function (event) {
|
146 |
+
const toggleBodyColorMode = (bsSheetEl) => {
|
147 |
+
const mode = bsSheetEl.getAttribute("data-mode");
|
148 |
+
const bodyEl = window.document.querySelector("body");
|
149 |
+
if (mode === "dark") {
|
150 |
+
bodyEl.classList.add("quarto-dark");
|
151 |
+
bodyEl.classList.remove("quarto-light");
|
152 |
+
} else {
|
153 |
+
bodyEl.classList.add("quarto-light");
|
154 |
+
bodyEl.classList.remove("quarto-dark");
|
155 |
+
}
|
156 |
+
}
|
157 |
+
const toggleBodyColorPrimary = () => {
|
158 |
+
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
|
159 |
+
if (bsSheetEl) {
|
160 |
+
toggleBodyColorMode(bsSheetEl);
|
161 |
+
}
|
162 |
+
}
|
163 |
+
toggleBodyColorPrimary();
|
164 |
+
const isCodeAnnotation = (el) => {
|
165 |
+
for (const clz of el.classList) {
|
166 |
+
if (clz.startsWith('code-annotation-')) {
|
167 |
+
return true;
|
168 |
+
}
|
169 |
+
}
|
170 |
+
return false;
|
171 |
+
}
|
172 |
+
const onCopySuccess = function(e) {
|
173 |
+
// button target
|
174 |
+
const button = e.trigger;
|
175 |
+
// don't keep focus
|
176 |
+
button.blur();
|
177 |
+
// flash "checked"
|
178 |
+
button.classList.add('code-copy-button-checked');
|
179 |
+
var currentTitle = button.getAttribute("title");
|
180 |
+
button.setAttribute("title", "Copied!");
|
181 |
+
let tooltip;
|
182 |
+
if (window.bootstrap) {
|
183 |
+
button.setAttribute("data-bs-toggle", "tooltip");
|
184 |
+
button.setAttribute("data-bs-placement", "left");
|
185 |
+
button.setAttribute("data-bs-title", "Copied!");
|
186 |
+
tooltip = new bootstrap.Tooltip(button,
|
187 |
+
{ trigger: "manual",
|
188 |
+
customClass: "code-copy-button-tooltip",
|
189 |
+
offset: [0, -8]});
|
190 |
+
tooltip.show();
|
191 |
+
}
|
192 |
+
setTimeout(function() {
|
193 |
+
if (tooltip) {
|
194 |
+
tooltip.hide();
|
195 |
+
button.removeAttribute("data-bs-title");
|
196 |
+
button.removeAttribute("data-bs-toggle");
|
197 |
+
button.removeAttribute("data-bs-placement");
|
198 |
+
}
|
199 |
+
button.setAttribute("title", currentTitle);
|
200 |
+
button.classList.remove('code-copy-button-checked');
|
201 |
+
}, 1000);
|
202 |
+
// clear code selection
|
203 |
+
e.clearSelection();
|
204 |
+
}
|
205 |
+
const getTextToCopy = function(trigger) {
|
206 |
+
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
207 |
+
for (const childEl of codeEl.children) {
|
208 |
+
if (isCodeAnnotation(childEl)) {
|
209 |
+
childEl.remove();
|
210 |
+
}
|
211 |
+
}
|
212 |
+
return codeEl.innerText;
|
213 |
+
}
|
214 |
+
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
215 |
+
text: getTextToCopy
|
216 |
+
});
|
217 |
+
clipboard.on('success', onCopySuccess);
|
218 |
+
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
219 |
+
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
220 |
+
text: getTextToCopy,
|
221 |
+
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
222 |
+
});
|
223 |
+
clipboardModal.on('success', onCopySuccess);
|
224 |
+
}
|
225 |
+
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
226 |
+
var mailtoRegex = new RegExp(/^mailto:/);
|
227 |
+
var filterRegex = new RegExp('/' + window.location.host + '/');
|
228 |
+
var isInternal = (href) => {
|
229 |
+
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
230 |
+
}
|
231 |
+
// Inspect non-navigation links and adorn them if external
|
232 |
+
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
233 |
+
for (var i=0; i<links.length; i++) {
|
234 |
+
const link = links[i];
|
235 |
+
if (!isInternal(link.href)) {
|
236 |
+
// undo the damage that might have been done by quarto-nav.js in the case of
|
237 |
+
// links that we want to consider external
|
238 |
+
if (link.dataset.originalHref !== undefined) {
|
239 |
+
link.href = link.dataset.originalHref;
|
240 |
+
}
|
241 |
+
}
|
242 |
+
}
|
243 |
+
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
244 |
+
const config = {
|
245 |
+
allowHTML: true,
|
246 |
+
maxWidth: 500,
|
247 |
+
delay: 100,
|
248 |
+
arrow: false,
|
249 |
+
appendTo: function(el) {
|
250 |
+
return el.parentElement;
|
251 |
+
},
|
252 |
+
interactive: true,
|
253 |
+
interactiveBorder: 10,
|
254 |
+
theme: 'quarto',
|
255 |
+
placement: 'bottom-start',
|
256 |
+
};
|
257 |
+
if (contentFn) {
|
258 |
+
config.content = contentFn;
|
259 |
+
}
|
260 |
+
if (onTriggerFn) {
|
261 |
+
config.onTrigger = onTriggerFn;
|
262 |
+
}
|
263 |
+
if (onUntriggerFn) {
|
264 |
+
config.onUntrigger = onUntriggerFn;
|
265 |
+
}
|
266 |
+
window.tippy(el, config);
|
267 |
+
}
|
268 |
+
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
269 |
+
for (var i=0; i<noterefs.length; i++) {
|
270 |
+
const ref = noterefs[i];
|
271 |
+
tippyHover(ref, function() {
|
272 |
+
// use id or data attribute instead here
|
273 |
+
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
274 |
+
try { href = new URL(href).hash; } catch {}
|
275 |
+
const id = href.replace(/^#\/?/, "");
|
276 |
+
const note = window.document.getElementById(id);
|
277 |
+
if (note) {
|
278 |
+
return note.innerHTML;
|
279 |
+
} else {
|
280 |
+
return "";
|
281 |
+
}
|
282 |
+
});
|
283 |
+
}
|
284 |
+
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
285 |
+
const processXRef = (id, note) => {
|
286 |
+
// Strip column container classes
|
287 |
+
const stripColumnClz = (el) => {
|
288 |
+
el.classList.remove("page-full", "page-columns");
|
289 |
+
if (el.children) {
|
290 |
+
for (const child of el.children) {
|
291 |
+
stripColumnClz(child);
|
292 |
+
}
|
293 |
+
}
|
294 |
+
}
|
295 |
+
stripColumnClz(note)
|
296 |
+
if (id === null || id.startsWith('sec-')) {
|
297 |
+
// Special case sections, only their first couple elements
|
298 |
+
const container = document.createElement("div");
|
299 |
+
if (note.children && note.children.length > 2) {
|
300 |
+
container.appendChild(note.children[0].cloneNode(true));
|
301 |
+
for (let i = 1; i < note.children.length; i++) {
|
302 |
+
const child = note.children[i];
|
303 |
+
if (child.tagName === "P" && child.innerText === "") {
|
304 |
+
continue;
|
305 |
+
} else {
|
306 |
+
container.appendChild(child.cloneNode(true));
|
307 |
+
break;
|
308 |
+
}
|
309 |
+
}
|
310 |
+
if (window.Quarto?.typesetMath) {
|
311 |
+
window.Quarto.typesetMath(container);
|
312 |
+
}
|
313 |
+
return container.innerHTML
|
314 |
+
} else {
|
315 |
+
if (window.Quarto?.typesetMath) {
|
316 |
+
window.Quarto.typesetMath(note);
|
317 |
+
}
|
318 |
+
return note.innerHTML;
|
319 |
+
}
|
320 |
+
} else {
|
321 |
+
// Remove any anchor links if they are present
|
322 |
+
const anchorLink = note.querySelector('a.anchorjs-link');
|
323 |
+
if (anchorLink) {
|
324 |
+
anchorLink.remove();
|
325 |
+
}
|
326 |
+
if (window.Quarto?.typesetMath) {
|
327 |
+
window.Quarto.typesetMath(note);
|
328 |
+
}
|
329 |
+
if (note.classList.contains("callout")) {
|
330 |
+
return note.outerHTML;
|
331 |
+
} else {
|
332 |
+
return note.innerHTML;
|
333 |
+
}
|
334 |
+
}
|
335 |
+
}
|
336 |
+
for (var i=0; i<xrefs.length; i++) {
|
337 |
+
const xref = xrefs[i];
|
338 |
+
tippyHover(xref, undefined, function(instance) {
|
339 |
+
instance.disable();
|
340 |
+
let url = xref.getAttribute('href');
|
341 |
+
let hash = undefined;
|
342 |
+
if (url.startsWith('#')) {
|
343 |
+
hash = url;
|
344 |
+
} else {
|
345 |
+
try { hash = new URL(url).hash; } catch {}
|
346 |
+
}
|
347 |
+
if (hash) {
|
348 |
+
const id = hash.replace(/^#\/?/, "");
|
349 |
+
const note = window.document.getElementById(id);
|
350 |
+
if (note !== null) {
|
351 |
+
try {
|
352 |
+
const html = processXRef(id, note.cloneNode(true));
|
353 |
+
instance.setContent(html);
|
354 |
+
} finally {
|
355 |
+
instance.enable();
|
356 |
+
instance.show();
|
357 |
+
}
|
358 |
+
} else {
|
359 |
+
// See if we can fetch this
|
360 |
+
fetch(url.split('#')[0])
|
361 |
+
.then(res => res.text())
|
362 |
+
.then(html => {
|
363 |
+
const parser = new DOMParser();
|
364 |
+
const htmlDoc = parser.parseFromString(html, "text/html");
|
365 |
+
const note = htmlDoc.getElementById(id);
|
366 |
+
if (note !== null) {
|
367 |
+
const html = processXRef(id, note);
|
368 |
+
instance.setContent(html);
|
369 |
+
}
|
370 |
+
}).finally(() => {
|
371 |
+
instance.enable();
|
372 |
+
instance.show();
|
373 |
+
});
|
374 |
+
}
|
375 |
+
} else {
|
376 |
+
// See if we can fetch a full url (with no hash to target)
|
377 |
+
// This is a special case and we should probably do some content thinning / targeting
|
378 |
+
fetch(url)
|
379 |
+
.then(res => res.text())
|
380 |
+
.then(html => {
|
381 |
+
const parser = new DOMParser();
|
382 |
+
const htmlDoc = parser.parseFromString(html, "text/html");
|
383 |
+
const note = htmlDoc.querySelector('main.content');
|
384 |
+
if (note !== null) {
|
385 |
+
// This should only happen for chapter cross references
|
386 |
+
// (since there is no id in the URL)
|
387 |
+
// remove the first header
|
388 |
+
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
389 |
+
note.children[0].remove();
|
390 |
+
}
|
391 |
+
const html = processXRef(null, note);
|
392 |
+
instance.setContent(html);
|
393 |
+
}
|
394 |
+
}).finally(() => {
|
395 |
+
instance.enable();
|
396 |
+
instance.show();
|
397 |
+
});
|
398 |
+
}
|
399 |
+
}, function(instance) {
|
400 |
+
});
|
401 |
+
}
|
402 |
+
let selectedAnnoteEl;
|
403 |
+
const selectorForAnnotation = ( cell, annotation) => {
|
404 |
+
let cellAttr = 'data-code-cell="' + cell + '"';
|
405 |
+
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
406 |
+
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
407 |
+
return selector;
|
408 |
+
}
|
409 |
+
const selectCodeLines = (annoteEl) => {
|
410 |
+
const doc = window.document;
|
411 |
+
const targetCell = annoteEl.getAttribute("data-target-cell");
|
412 |
+
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
413 |
+
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
414 |
+
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
415 |
+
const lineIds = lines.map((line) => {
|
416 |
+
return targetCell + "-" + line;
|
417 |
+
})
|
418 |
+
let top = null;
|
419 |
+
let height = null;
|
420 |
+
let parent = null;
|
421 |
+
if (lineIds.length > 0) {
|
422 |
+
//compute the position of the single el (top and bottom and make a div)
|
423 |
+
const el = window.document.getElementById(lineIds[0]);
|
424 |
+
top = el.offsetTop;
|
425 |
+
height = el.offsetHeight;
|
426 |
+
parent = el.parentElement.parentElement;
|
427 |
+
if (lineIds.length > 1) {
|
428 |
+
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
429 |
+
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
430 |
+
height = bottom - top;
|
431 |
+
}
|
432 |
+
if (top !== null && height !== null && parent !== null) {
|
433 |
+
// cook up a div (if necessary) and position it
|
434 |
+
let div = window.document.getElementById("code-annotation-line-highlight");
|
435 |
+
if (div === null) {
|
436 |
+
div = window.document.createElement("div");
|
437 |
+
div.setAttribute("id", "code-annotation-line-highlight");
|
438 |
+
div.style.position = 'absolute';
|
439 |
+
parent.appendChild(div);
|
440 |
+
}
|
441 |
+
div.style.top = top - 2 + "px";
|
442 |
+
div.style.height = height + 4 + "px";
|
443 |
+
div.style.left = 0;
|
444 |
+
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
445 |
+
if (gutterDiv === null) {
|
446 |
+
gutterDiv = window.document.createElement("div");
|
447 |
+
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
448 |
+
gutterDiv.style.position = 'absolute';
|
449 |
+
const codeCell = window.document.getElementById(targetCell);
|
450 |
+
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
451 |
+
gutter.appendChild(gutterDiv);
|
452 |
+
}
|
453 |
+
gutterDiv.style.top = top - 2 + "px";
|
454 |
+
gutterDiv.style.height = height + 4 + "px";
|
455 |
+
}
|
456 |
+
selectedAnnoteEl = annoteEl;
|
457 |
+
}
|
458 |
+
};
|
459 |
+
const unselectCodeLines = () => {
|
460 |
+
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
461 |
+
elementsIds.forEach((elId) => {
|
462 |
+
const div = window.document.getElementById(elId);
|
463 |
+
if (div) {
|
464 |
+
div.remove();
|
465 |
+
}
|
466 |
+
});
|
467 |
+
selectedAnnoteEl = undefined;
|
468 |
+
};
|
469 |
+
// Handle positioning of the toggle
|
470 |
+
window.addEventListener(
|
471 |
+
"resize",
|
472 |
+
throttle(() => {
|
473 |
+
elRect = undefined;
|
474 |
+
if (selectedAnnoteEl) {
|
475 |
+
selectCodeLines(selectedAnnoteEl);
|
476 |
+
}
|
477 |
+
}, 10)
|
478 |
+
);
|
479 |
+
function throttle(fn, ms) {
|
480 |
+
let throttle = false;
|
481 |
+
let timer;
|
482 |
+
return (...args) => {
|
483 |
+
if(!throttle) { // first call gets through
|
484 |
+
fn.apply(this, args);
|
485 |
+
throttle = true;
|
486 |
+
} else { // all the others get throttled
|
487 |
+
if(timer) clearTimeout(timer); // cancel #2
|
488 |
+
timer = setTimeout(() => {
|
489 |
+
fn.apply(this, args);
|
490 |
+
timer = throttle = false;
|
491 |
+
}, ms);
|
492 |
+
}
|
493 |
+
};
|
494 |
+
}
|
495 |
+
// Attach click handler to the DT
|
496 |
+
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
497 |
+
for (const annoteDlNode of annoteDls) {
|
498 |
+
annoteDlNode.addEventListener('click', (event) => {
|
499 |
+
const clickedEl = event.target;
|
500 |
+
if (clickedEl !== selectedAnnoteEl) {
|
501 |
+
unselectCodeLines();
|
502 |
+
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
503 |
+
if (activeEl) {
|
504 |
+
activeEl.classList.remove('code-annotation-active');
|
505 |
+
}
|
506 |
+
selectCodeLines(clickedEl);
|
507 |
+
clickedEl.classList.add('code-annotation-active');
|
508 |
+
} else {
|
509 |
+
// Unselect the line
|
510 |
+
unselectCodeLines();
|
511 |
+
clickedEl.classList.remove('code-annotation-active');
|
512 |
+
}
|
513 |
+
});
|
514 |
+
}
|
515 |
+
const findCites = (el) => {
|
516 |
+
const parentEl = el.parentElement;
|
517 |
+
if (parentEl) {
|
518 |
+
const cites = parentEl.dataset.cites;
|
519 |
+
if (cites) {
|
520 |
+
return {
|
521 |
+
el,
|
522 |
+
cites: cites.split(' ')
|
523 |
+
};
|
524 |
+
} else {
|
525 |
+
return findCites(el.parentElement)
|
526 |
+
}
|
527 |
+
} else {
|
528 |
+
return undefined;
|
529 |
+
}
|
530 |
+
};
|
531 |
+
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
532 |
+
for (var i=0; i<bibliorefs.length; i++) {
|
533 |
+
const ref = bibliorefs[i];
|
534 |
+
const citeInfo = findCites(ref);
|
535 |
+
if (citeInfo) {
|
536 |
+
tippyHover(citeInfo.el, function() {
|
537 |
+
var popup = window.document.createElement('div');
|
538 |
+
citeInfo.cites.forEach(function(cite) {
|
539 |
+
var citeDiv = window.document.createElement('div');
|
540 |
+
citeDiv.classList.add('hanging-indent');
|
541 |
+
citeDiv.classList.add('csl-entry');
|
542 |
+
var biblioDiv = window.document.getElementById('ref-' + cite);
|
543 |
+
if (biblioDiv) {
|
544 |
+
citeDiv.innerHTML = biblioDiv.innerHTML;
|
545 |
+
}
|
546 |
+
popup.appendChild(citeDiv);
|
547 |
+
});
|
548 |
+
return popup.innerHTML;
|
549 |
+
});
|
550 |
+
}
|
551 |
+
}
|
552 |
+
});
|
553 |
+
</script>
|
554 |
+
</div> <!-- /content -->
|
555 |
+
|
556 |
+
|
557 |
+
|
558 |
+
|
559 |
+
</body></html>
|
src/_site/index.html
ADDED
@@ -0,0 +1,707 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
|
3 |
+
|
4 |
+
<meta charset="utf-8">
|
5 |
+
<meta name="generator" content="quarto-1.6.39">
|
6 |
+
|
7 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
8 |
+
|
9 |
+
|
10 |
+
<title>quarto-blog</title>
|
11 |
+
<style>
|
12 |
+
code{white-space: pre-wrap;}
|
13 |
+
span.smallcaps{font-variant: small-caps;}
|
14 |
+
div.columns{display: flex; gap: min(4vw, 1.5em);}
|
15 |
+
div.column{flex: auto; overflow-x: auto;}
|
16 |
+
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
17 |
+
ul.task-list{list-style: none;}
|
18 |
+
ul.task-list li input[type="checkbox"] {
|
19 |
+
width: 0.8em;
|
20 |
+
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
|
21 |
+
vertical-align: middle;
|
22 |
+
}
|
23 |
+
</style>
|
24 |
+
|
25 |
+
|
26 |
+
<script src="site_libs/quarto-nav/quarto-nav.js"></script>
|
27 |
+
<script src="site_libs/quarto-nav/headroom.min.js"></script>
|
28 |
+
<script src="site_libs/clipboard/clipboard.min.js"></script>
|
29 |
+
<script src="site_libs/quarto-search/autocomplete.umd.js"></script>
|
30 |
+
<script src="site_libs/quarto-search/fuse.min.js"></script>
|
31 |
+
<script src="site_libs/quarto-search/quarto-search.js"></script>
|
32 |
+
<meta name="quarto:offset" content="./">
|
33 |
+
<script src="site_libs/quarto-listing/list.min.js"></script>
|
34 |
+
<script src="site_libs/quarto-listing/quarto-listing.js"></script>
|
35 |
+
<script src="site_libs/quarto-html/quarto.js"></script>
|
36 |
+
<script src="site_libs/quarto-html/popper.min.js"></script>
|
37 |
+
<script src="site_libs/quarto-html/tippy.umd.min.js"></script>
|
38 |
+
<script src="site_libs/quarto-html/anchor.min.js"></script>
|
39 |
+
<link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
|
40 |
+
<link href="site_libs/quarto-html/quarto-syntax-highlighting-e26003cea8cd680ca0c55a263523d882.css" rel="stylesheet" id="quarto-text-highlighting-styles">
|
41 |
+
<script src="site_libs/bootstrap/bootstrap.min.js"></script>
|
42 |
+
<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
|
43 |
+
<link href="site_libs/bootstrap/bootstrap-d1b12f2568ecbe55642fee6aa00bd082.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
|
44 |
+
<script id="quarto-search-options" type="application/json">{
|
45 |
+
"location": "navbar",
|
46 |
+
"copy-button": false,
|
47 |
+
"collapse-after": 3,
|
48 |
+
"panel-placement": "end",
|
49 |
+
"type": "overlay",
|
50 |
+
"limit": 50,
|
51 |
+
"keyboard-shortcut": [
|
52 |
+
"f",
|
53 |
+
"/",
|
54 |
+
"s"
|
55 |
+
],
|
56 |
+
"show-item-context": false,
|
57 |
+
"language": {
|
58 |
+
"search-no-results-text": "No results",
|
59 |
+
"search-matching-documents-text": "matching documents",
|
60 |
+
"search-copy-link-title": "Copy link to search",
|
61 |
+
"search-hide-matches-text": "Hide additional matches",
|
62 |
+
"search-more-match-text": "more match in this document",
|
63 |
+
"search-more-matches-text": "more matches in this document",
|
64 |
+
"search-clear-button-title": "Clear",
|
65 |
+
"search-text-placeholder": "",
|
66 |
+
"search-detached-cancel-button-title": "Cancel",
|
67 |
+
"search-submit-button-title": "Submit",
|
68 |
+
"search-label": "Search"
|
69 |
+
}
|
70 |
+
}</script>
|
71 |
+
<script>
|
72 |
+
|
73 |
+
window.document.addEventListener("DOMContentLoaded", function (_event) {
|
74 |
+
const listingTargetEl = window.document.querySelector('#listing-listing .list');
|
75 |
+
if (!listingTargetEl) {
|
76 |
+
// No listing discovered, do not attach.
|
77 |
+
return;
|
78 |
+
}
|
79 |
+
|
80 |
+
const options = {
|
81 |
+
valueNames: ['listing-date','listing-title','listing-author','listing-image','listing-description','listing-categories',{ data: ['index'] },{ data: ['categories'] },{ data: ['listing-date-sort'] },{ data: ['listing-file-modified-sort'] }],
|
82 |
+
|
83 |
+
searchColumns: ["listing-date","listing-title","listing-author","listing-image","listing-description","listing-categories"],
|
84 |
+
};
|
85 |
+
|
86 |
+
window['quarto-listings'] = window['quarto-listings'] || {};
|
87 |
+
window['quarto-listings']['listing-listing'] = new List('listing-listing', options);
|
88 |
+
|
89 |
+
if (window['quarto-listing-loaded']) {
|
90 |
+
window['quarto-listing-loaded']();
|
91 |
+
}
|
92 |
+
});
|
93 |
+
|
94 |
+
window.addEventListener('hashchange',() => {
|
95 |
+
if (window['quarto-listing-loaded']) {
|
96 |
+
window['quarto-listing-loaded']();
|
97 |
+
}
|
98 |
+
})
|
99 |
+
</script>
|
100 |
+
|
101 |
+
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=es6"></script>
|
102 |
+
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>
|
103 |
+
|
104 |
+
<script type="text/javascript">
|
105 |
+
const typesetMath = (el) => {
|
106 |
+
if (window.MathJax) {
|
107 |
+
// MathJax Typeset
|
108 |
+
window.MathJax.typeset([el]);
|
109 |
+
} else if (window.katex) {
|
110 |
+
// KaTeX Render
|
111 |
+
var mathElements = el.getElementsByClassName("math");
|
112 |
+
var macros = [];
|
113 |
+
for (var i = 0; i < mathElements.length; i++) {
|
114 |
+
var texText = mathElements[i].firstChild;
|
115 |
+
if (mathElements[i].tagName == "SPAN") {
|
116 |
+
window.katex.render(texText.data, mathElements[i], {
|
117 |
+
displayMode: mathElements[i].classList.contains('display'),
|
118 |
+
throwOnError: false,
|
119 |
+
macros: macros,
|
120 |
+
fleqn: false
|
121 |
+
});
|
122 |
+
}
|
123 |
+
}
|
124 |
+
}
|
125 |
+
}
|
126 |
+
window.Quarto = {
|
127 |
+
typesetMath
|
128 |
+
};
|
129 |
+
</script>
|
130 |
+
|
131 |
+
<link rel="stylesheet" href="styles.css">
|
132 |
+
</head>
|
133 |
+
|
134 |
+
<body class="nav-fixed">
|
135 |
+
|
136 |
+
<div id="quarto-search-results"></div>
|
137 |
+
<header id="quarto-header" class="headroom fixed-top quarto-banner">
|
138 |
+
<nav class="navbar navbar-expand-lg " data-bs-theme="dark">
|
139 |
+
<div class="navbar-container container-fluid">
|
140 |
+
<div class="navbar-brand-container mx-auto">
|
141 |
+
<a class="navbar-brand" href="./index.html">
|
142 |
+
<span class="navbar-title">quarto-blog</span>
|
143 |
+
</a>
|
144 |
+
</div>
|
145 |
+
<div id="quarto-search" class="" title="Search"></div>
|
146 |
+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" role="menu" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
|
147 |
+
<span class="navbar-toggler-icon"></span>
|
148 |
+
</button>
|
149 |
+
<div class="collapse navbar-collapse" id="navbarCollapse">
|
150 |
+
<ul class="navbar-nav navbar-nav-scroll ms-auto">
|
151 |
+
<li class="nav-item">
|
152 |
+
<a class="nav-link" href="./about.html">
|
153 |
+
<span class="menu-text">About</span></a>
|
154 |
+
</li>
|
155 |
+
<li class="nav-item compact">
|
156 |
+
<a class="nav-link" href="https://github.com/"> <i class="bi bi-github" role="img">
|
157 |
+
</i>
|
158 |
+
<span class="menu-text"></span></a>
|
159 |
+
</li>
|
160 |
+
<li class="nav-item compact">
|
161 |
+
<a class="nav-link" href="https://twitter.com"> <i class="bi bi-twitter" role="img">
|
162 |
+
</i>
|
163 |
+
<span class="menu-text"></span></a>
|
164 |
+
</li>
|
165 |
+
</ul>
|
166 |
+
</div> <!-- /navcollapse -->
|
167 |
+
<div class="quarto-navbar-tools">
|
168 |
+
</div>
|
169 |
+
</div> <!-- /container-fluid -->
|
170 |
+
</nav>
|
171 |
+
</header>
|
172 |
+
<!-- content -->
|
173 |
+
<header id="title-block-header" class="quarto-title-block default page-columns page-full">
|
174 |
+
<div class="quarto-title-banner page-columns page-full">
|
175 |
+
<div class="quarto-title column-page-left">
|
176 |
+
<h1 class="title">quarto-blog</h1>
|
177 |
+
</div>
|
178 |
+
</div>
|
179 |
+
|
180 |
+
|
181 |
+
<div class="quarto-title-meta column-page-left">
|
182 |
+
|
183 |
+
|
184 |
+
|
185 |
+
|
186 |
+
</div>
|
187 |
+
|
188 |
+
|
189 |
+
</header><div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-full page-navbar">
|
190 |
+
<!-- sidebar -->
|
191 |
+
<!-- margin-sidebar -->
|
192 |
+
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
|
193 |
+
|
194 |
+
<h5 class="quarto-listing-category-title">Categories</h5><div class="quarto-listing-category category-default"><div class="category" data-category="">All <span class="quarto-category-count">(2)</span></div><div class="category" data-category="bWF0aGVtYXRpY3M=">mathematics <span class="quarto-category-count">(2)</span></div><div class="category" data-category="cGRl">pde <span class="quarto-category-count">(1)</span></div><div class="category" data-category="cG9seW5vbWlhbHM=">polynomials <span class="quarto-category-count">(1)</span></div></div></div>
|
195 |
+
<!-- main -->
|
196 |
+
<main class="content quarto-banner-title-block column-page-left" id="quarto-document-content">
|
197 |
+
|
198 |
+
|
199 |
+
|
200 |
+
|
201 |
+
|
202 |
+
|
203 |
+
|
204 |
+
|
205 |
+
|
206 |
+
<div class="quarto-listing quarto-listing-container-default" id="listing-listing">
|
207 |
+
<div class="list quarto-listing-default">
|
208 |
+
<div class="quarto-post image-right" data-index="0" data-categories="bWF0aGVtYXRpY3MlMkNwb2x5bm9taWFscw==" data-listing-date-sort="1736114400000" data-listing-file-modified-sort="1748623629839" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="10" data-listing-word-count-sort="1915">
|
209 |
+
<div class="thumbnail">
|
210 |
+
<p><a href="./posts/2025-01-06-chebyshev-polynomials/index.html" class="no-external"></a></p><a href="./posts/2025-01-06-chebyshev-polynomials/index.html" class="no-external">
|
211 |
+
<p class="card-img-top"><img src="posts/2025-01-06-chebyshev-polynomials/images/unit_circle.svg" class="thumbnail-image card-img"/></p>
|
212 |
+
</a><p><a href="./posts/2025-01-06-chebyshev-polynomials/index.html" class="no-external"></a></p>
|
213 |
+
</div>
|
214 |
+
<div class="body">
|
215 |
+
<h3 class="no-anchor listing-title">
|
216 |
+
<a href="./posts/2025-01-06-chebyshev-polynomials/index.html" class="no-external">Chebyshev Polynomials: Part 1</a>
|
217 |
+
</h3>
|
218 |
+
<div class="listing-subtitle">
|
219 |
+
<a href="./posts/2025-01-06-chebyshev-polynomials/index.html" class="no-external"></a>
|
220 |
+
</div>
|
221 |
+
<div class="listing-categories">
|
222 |
+
<div class="listing-category" onclick="window.quartoListingCategory('bWF0aGVtYXRpY3M='); return false;">
|
223 |
+
mathematics
|
224 |
+
</div>
|
225 |
+
<div class="listing-category" onclick="window.quartoListingCategory('cG9seW5vbWlhbHM='); return false;">
|
226 |
+
polynomials
|
227 |
+
</div>
|
228 |
+
</div>
|
229 |
+
<div class="listing-description">
|
230 |
+
<a href="./posts/2025-01-06-chebyshev-polynomials/index.html" class="no-external">Chebyshev polynomials are a sequence of orthogonal polynomials that play a central role in numerical analysis, approximation theory, and applied mathematics. They are named…<span class="math inline"></span><span class="math inline"></span></a>
|
231 |
+
</div>
|
232 |
+
</div>
|
233 |
+
<div class="metadata">
|
234 |
+
<a href="./posts/2025-01-06-chebyshev-polynomials/index.html" class="no-external">
|
235 |
+
<div class="listing-date">
|
236 |
+
Jan 6, 2025
|
237 |
+
</div>
|
238 |
+
<div class="listing-author">
|
239 |
+
Joana Levtcheva
|
240 |
+
</div>
|
241 |
+
</a>
|
242 |
+
</div>
|
243 |
+
</div>
|
244 |
+
<div class="quarto-post image-right" data-index="1" data-categories="bWF0aGVtYXRpY3MlMkNwZGU=" data-listing-date-sort="1735941600000" data-listing-file-modified-sort="1748623629822" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="17" data-listing-word-count-sort="3389">
|
245 |
+
<div class="thumbnail">
|
246 |
+
<p><a href="./posts/2025-01-04-fourier-method-fixed-string/index.html" class="no-external"></a></p><a href="./posts/2025-01-04-fourier-method-fixed-string/index.html" class="no-external">
|
247 |
+
<p class="card-img-top"><img src="posts/2025-01-04-fourier-method-fixed-string/images/fixed_string.svg" class="thumbnail-image card-img"/></p>
|
248 |
+
</a><p><a href="./posts/2025-01-04-fourier-method-fixed-string/index.html" class="no-external"></a></p>
|
249 |
+
</div>
|
250 |
+
<div class="body">
|
251 |
+
<h3 class="no-anchor listing-title">
|
252 |
+
<a href="./posts/2025-01-04-fourier-method-fixed-string/index.html" class="no-external">Fourier Method for the 1D Wave Equation: Fixed String</a>
|
253 |
+
</h3>
|
254 |
+
<div class="listing-subtitle">
|
255 |
+
<a href="./posts/2025-01-04-fourier-method-fixed-string/index.html" class="no-external"></a>
|
256 |
+
</div>
|
257 |
+
<div class="listing-categories">
|
258 |
+
<div class="listing-category" onclick="window.quartoListingCategory('bWF0aGVtYXRpY3M='); return false;">
|
259 |
+
mathematics
|
260 |
+
</div>
|
261 |
+
<div class="listing-category" onclick="window.quartoListingCategory('cGRl'); return false;">
|
262 |
+
pde
|
263 |
+
</div>
|
264 |
+
</div>
|
265 |
+
<div class="listing-description">
|
266 |
+
<a href="./posts/2025-01-04-fourier-method-fixed-string/index.html" class="no-external">In this post we are going to explore the Fourier method for solving the 1D wave equation. The method is more known under the name of the <strong>method of separation of variables</strong>.…</a>
|
267 |
+
</div>
|
268 |
+
</div>
|
269 |
+
<div class="metadata">
|
270 |
+
<a href="./posts/2025-01-04-fourier-method-fixed-string/index.html" class="no-external">
|
271 |
+
<div class="listing-date">
|
272 |
+
Jan 4, 2025
|
273 |
+
</div>
|
274 |
+
<div class="listing-author">
|
275 |
+
Joana Levtcheva
|
276 |
+
</div>
|
277 |
+
</a>
|
278 |
+
</div>
|
279 |
+
</div>
|
280 |
+
</div>
|
281 |
+
<div class="listing-no-matching d-none">
|
282 |
+
No matching items
|
283 |
+
</div>
|
284 |
+
</div></main> <!-- /main -->
|
285 |
+
<script id="quarto-html-after-body" type="application/javascript">
|
286 |
+
window.document.addEventListener("DOMContentLoaded", function (event) {
|
287 |
+
const toggleBodyColorMode = (bsSheetEl) => {
|
288 |
+
const mode = bsSheetEl.getAttribute("data-mode");
|
289 |
+
const bodyEl = window.document.querySelector("body");
|
290 |
+
if (mode === "dark") {
|
291 |
+
bodyEl.classList.add("quarto-dark");
|
292 |
+
bodyEl.classList.remove("quarto-light");
|
293 |
+
} else {
|
294 |
+
bodyEl.classList.add("quarto-light");
|
295 |
+
bodyEl.classList.remove("quarto-dark");
|
296 |
+
}
|
297 |
+
}
|
298 |
+
const toggleBodyColorPrimary = () => {
|
299 |
+
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
|
300 |
+
if (bsSheetEl) {
|
301 |
+
toggleBodyColorMode(bsSheetEl);
|
302 |
+
}
|
303 |
+
}
|
304 |
+
toggleBodyColorPrimary();
|
305 |
+
const icon = "";
|
306 |
+
const anchorJS = new window.AnchorJS();
|
307 |
+
anchorJS.options = {
|
308 |
+
placement: 'right',
|
309 |
+
icon: icon
|
310 |
+
};
|
311 |
+
anchorJS.add('.anchored');
|
312 |
+
const isCodeAnnotation = (el) => {
|
313 |
+
for (const clz of el.classList) {
|
314 |
+
if (clz.startsWith('code-annotation-')) {
|
315 |
+
return true;
|
316 |
+
}
|
317 |
+
}
|
318 |
+
return false;
|
319 |
+
}
|
320 |
+
const onCopySuccess = function(e) {
|
321 |
+
// button target
|
322 |
+
const button = e.trigger;
|
323 |
+
// don't keep focus
|
324 |
+
button.blur();
|
325 |
+
// flash "checked"
|
326 |
+
button.classList.add('code-copy-button-checked');
|
327 |
+
var currentTitle = button.getAttribute("title");
|
328 |
+
button.setAttribute("title", "Copied!");
|
329 |
+
let tooltip;
|
330 |
+
if (window.bootstrap) {
|
331 |
+
button.setAttribute("data-bs-toggle", "tooltip");
|
332 |
+
button.setAttribute("data-bs-placement", "left");
|
333 |
+
button.setAttribute("data-bs-title", "Copied!");
|
334 |
+
tooltip = new bootstrap.Tooltip(button,
|
335 |
+
{ trigger: "manual",
|
336 |
+
customClass: "code-copy-button-tooltip",
|
337 |
+
offset: [0, -8]});
|
338 |
+
tooltip.show();
|
339 |
+
}
|
340 |
+
setTimeout(function() {
|
341 |
+
if (tooltip) {
|
342 |
+
tooltip.hide();
|
343 |
+
button.removeAttribute("data-bs-title");
|
344 |
+
button.removeAttribute("data-bs-toggle");
|
345 |
+
button.removeAttribute("data-bs-placement");
|
346 |
+
}
|
347 |
+
button.setAttribute("title", currentTitle);
|
348 |
+
button.classList.remove('code-copy-button-checked');
|
349 |
+
}, 1000);
|
350 |
+
// clear code selection
|
351 |
+
e.clearSelection();
|
352 |
+
}
|
353 |
+
const getTextToCopy = function(trigger) {
|
354 |
+
const codeEl = trigger.previousElementSibling.cloneNode(true);
|
355 |
+
for (const childEl of codeEl.children) {
|
356 |
+
if (isCodeAnnotation(childEl)) {
|
357 |
+
childEl.remove();
|
358 |
+
}
|
359 |
+
}
|
360 |
+
return codeEl.innerText;
|
361 |
+
}
|
362 |
+
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
|
363 |
+
text: getTextToCopy
|
364 |
+
});
|
365 |
+
clipboard.on('success', onCopySuccess);
|
366 |
+
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
|
367 |
+
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
|
368 |
+
text: getTextToCopy,
|
369 |
+
container: window.document.getElementById('quarto-embedded-source-code-modal')
|
370 |
+
});
|
371 |
+
clipboardModal.on('success', onCopySuccess);
|
372 |
+
}
|
373 |
+
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
|
374 |
+
var mailtoRegex = new RegExp(/^mailto:/);
|
375 |
+
var filterRegex = new RegExp('/' + window.location.host + '/');
|
376 |
+
var isInternal = (href) => {
|
377 |
+
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
|
378 |
+
}
|
379 |
+
// Inspect non-navigation links and adorn them if external
|
380 |
+
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
|
381 |
+
for (var i=0; i<links.length; i++) {
|
382 |
+
const link = links[i];
|
383 |
+
if (!isInternal(link.href)) {
|
384 |
+
// undo the damage that might have been done by quarto-nav.js in the case of
|
385 |
+
// links that we want to consider external
|
386 |
+
if (link.dataset.originalHref !== undefined) {
|
387 |
+
link.href = link.dataset.originalHref;
|
388 |
+
}
|
389 |
+
}
|
390 |
+
}
|
391 |
+
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
|
392 |
+
const config = {
|
393 |
+
allowHTML: true,
|
394 |
+
maxWidth: 500,
|
395 |
+
delay: 100,
|
396 |
+
arrow: false,
|
397 |
+
appendTo: function(el) {
|
398 |
+
return el.parentElement;
|
399 |
+
},
|
400 |
+
interactive: true,
|
401 |
+
interactiveBorder: 10,
|
402 |
+
theme: 'quarto',
|
403 |
+
placement: 'bottom-start',
|
404 |
+
};
|
405 |
+
if (contentFn) {
|
406 |
+
config.content = contentFn;
|
407 |
+
}
|
408 |
+
if (onTriggerFn) {
|
409 |
+
config.onTrigger = onTriggerFn;
|
410 |
+
}
|
411 |
+
if (onUntriggerFn) {
|
412 |
+
config.onUntrigger = onUntriggerFn;
|
413 |
+
}
|
414 |
+
window.tippy(el, config);
|
415 |
+
}
|
416 |
+
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
|
417 |
+
for (var i=0; i<noterefs.length; i++) {
|
418 |
+
const ref = noterefs[i];
|
419 |
+
tippyHover(ref, function() {
|
420 |
+
// use id or data attribute instead here
|
421 |
+
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
|
422 |
+
try { href = new URL(href).hash; } catch {}
|
423 |
+
const id = href.replace(/^#\/?/, "");
|
424 |
+
const note = window.document.getElementById(id);
|
425 |
+
if (note) {
|
426 |
+
return note.innerHTML;
|
427 |
+
} else {
|
428 |
+
return "";
|
429 |
+
}
|
430 |
+
});
|
431 |
+
}
|
432 |
+
const xrefs = window.document.querySelectorAll('a.quarto-xref');
|
433 |
+
const processXRef = (id, note) => {
|
434 |
+
// Strip column container classes
|
435 |
+
const stripColumnClz = (el) => {
|
436 |
+
el.classList.remove("page-full", "page-columns");
|
437 |
+
if (el.children) {
|
438 |
+
for (const child of el.children) {
|
439 |
+
stripColumnClz(child);
|
440 |
+
}
|
441 |
+
}
|
442 |
+
}
|
443 |
+
stripColumnClz(note)
|
444 |
+
if (id === null || id.startsWith('sec-')) {
|
445 |
+
// Special case sections, only their first couple elements
|
446 |
+
const container = document.createElement("div");
|
447 |
+
if (note.children && note.children.length > 2) {
|
448 |
+
container.appendChild(note.children[0].cloneNode(true));
|
449 |
+
for (let i = 1; i < note.children.length; i++) {
|
450 |
+
const child = note.children[i];
|
451 |
+
if (child.tagName === "P" && child.innerText === "") {
|
452 |
+
continue;
|
453 |
+
} else {
|
454 |
+
container.appendChild(child.cloneNode(true));
|
455 |
+
break;
|
456 |
+
}
|
457 |
+
}
|
458 |
+
if (window.Quarto?.typesetMath) {
|
459 |
+
window.Quarto.typesetMath(container);
|
460 |
+
}
|
461 |
+
return container.innerHTML
|
462 |
+
} else {
|
463 |
+
if (window.Quarto?.typesetMath) {
|
464 |
+
window.Quarto.typesetMath(note);
|
465 |
+
}
|
466 |
+
return note.innerHTML;
|
467 |
+
}
|
468 |
+
} else {
|
469 |
+
// Remove any anchor links if they are present
|
470 |
+
const anchorLink = note.querySelector('a.anchorjs-link');
|
471 |
+
if (anchorLink) {
|
472 |
+
anchorLink.remove();
|
473 |
+
}
|
474 |
+
if (window.Quarto?.typesetMath) {
|
475 |
+
window.Quarto.typesetMath(note);
|
476 |
+
}
|
477 |
+
if (note.classList.contains("callout")) {
|
478 |
+
return note.outerHTML;
|
479 |
+
} else {
|
480 |
+
return note.innerHTML;
|
481 |
+
}
|
482 |
+
}
|
483 |
+
}
|
484 |
+
for (var i=0; i<xrefs.length; i++) {
|
485 |
+
const xref = xrefs[i];
|
486 |
+
tippyHover(xref, undefined, function(instance) {
|
487 |
+
instance.disable();
|
488 |
+
let url = xref.getAttribute('href');
|
489 |
+
let hash = undefined;
|
490 |
+
if (url.startsWith('#')) {
|
491 |
+
hash = url;
|
492 |
+
} else {
|
493 |
+
try { hash = new URL(url).hash; } catch {}
|
494 |
+
}
|
495 |
+
if (hash) {
|
496 |
+
const id = hash.replace(/^#\/?/, "");
|
497 |
+
const note = window.document.getElementById(id);
|
498 |
+
if (note !== null) {
|
499 |
+
try {
|
500 |
+
const html = processXRef(id, note.cloneNode(true));
|
501 |
+
instance.setContent(html);
|
502 |
+
} finally {
|
503 |
+
instance.enable();
|
504 |
+
instance.show();
|
505 |
+
}
|
506 |
+
} else {
|
507 |
+
// See if we can fetch this
|
508 |
+
fetch(url.split('#')[0])
|
509 |
+
.then(res => res.text())
|
510 |
+
.then(html => {
|
511 |
+
const parser = new DOMParser();
|
512 |
+
const htmlDoc = parser.parseFromString(html, "text/html");
|
513 |
+
const note = htmlDoc.getElementById(id);
|
514 |
+
if (note !== null) {
|
515 |
+
const html = processXRef(id, note);
|
516 |
+
instance.setContent(html);
|
517 |
+
}
|
518 |
+
}).finally(() => {
|
519 |
+
instance.enable();
|
520 |
+
instance.show();
|
521 |
+
});
|
522 |
+
}
|
523 |
+
} else {
|
524 |
+
// See if we can fetch a full url (with no hash to target)
|
525 |
+
// This is a special case and we should probably do some content thinning / targeting
|
526 |
+
fetch(url)
|
527 |
+
.then(res => res.text())
|
528 |
+
.then(html => {
|
529 |
+
const parser = new DOMParser();
|
530 |
+
const htmlDoc = parser.parseFromString(html, "text/html");
|
531 |
+
const note = htmlDoc.querySelector('main.content');
|
532 |
+
if (note !== null) {
|
533 |
+
// This should only happen for chapter cross references
|
534 |
+
// (since there is no id in the URL)
|
535 |
+
// remove the first header
|
536 |
+
if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
|
537 |
+
note.children[0].remove();
|
538 |
+
}
|
539 |
+
const html = processXRef(null, note);
|
540 |
+
instance.setContent(html);
|
541 |
+
}
|
542 |
+
}).finally(() => {
|
543 |
+
instance.enable();
|
544 |
+
instance.show();
|
545 |
+
});
|
546 |
+
}
|
547 |
+
}, function(instance) {
|
548 |
+
});
|
549 |
+
}
|
550 |
+
let selectedAnnoteEl;
|
551 |
+
const selectorForAnnotation = ( cell, annotation) => {
|
552 |
+
let cellAttr = 'data-code-cell="' + cell + '"';
|
553 |
+
let lineAttr = 'data-code-annotation="' + annotation + '"';
|
554 |
+
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
|
555 |
+
return selector;
|
556 |
+
}
|
557 |
+
const selectCodeLines = (annoteEl) => {
|
558 |
+
const doc = window.document;
|
559 |
+
const targetCell = annoteEl.getAttribute("data-target-cell");
|
560 |
+
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
|
561 |
+
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
|
562 |
+
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
|
563 |
+
const lineIds = lines.map((line) => {
|
564 |
+
return targetCell + "-" + line;
|
565 |
+
})
|
566 |
+
let top = null;
|
567 |
+
let height = null;
|
568 |
+
let parent = null;
|
569 |
+
if (lineIds.length > 0) {
|
570 |
+
//compute the position of the single el (top and bottom and make a div)
|
571 |
+
const el = window.document.getElementById(lineIds[0]);
|
572 |
+
top = el.offsetTop;
|
573 |
+
height = el.offsetHeight;
|
574 |
+
parent = el.parentElement.parentElement;
|
575 |
+
if (lineIds.length > 1) {
|
576 |
+
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
|
577 |
+
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
|
578 |
+
height = bottom - top;
|
579 |
+
}
|
580 |
+
if (top !== null && height !== null && parent !== null) {
|
581 |
+
// cook up a div (if necessary) and position it
|
582 |
+
let div = window.document.getElementById("code-annotation-line-highlight");
|
583 |
+
if (div === null) {
|
584 |
+
div = window.document.createElement("div");
|
585 |
+
div.setAttribute("id", "code-annotation-line-highlight");
|
586 |
+
div.style.position = 'absolute';
|
587 |
+
parent.appendChild(div);
|
588 |
+
}
|
589 |
+
div.style.top = top - 2 + "px";
|
590 |
+
div.style.height = height + 4 + "px";
|
591 |
+
div.style.left = 0;
|
592 |
+
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
|
593 |
+
if (gutterDiv === null) {
|
594 |
+
gutterDiv = window.document.createElement("div");
|
595 |
+
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
|
596 |
+
gutterDiv.style.position = 'absolute';
|
597 |
+
const codeCell = window.document.getElementById(targetCell);
|
598 |
+
const gutter = codeCell.querySelector('.code-annotation-gutter');
|
599 |
+
gutter.appendChild(gutterDiv);
|
600 |
+
}
|
601 |
+
gutterDiv.style.top = top - 2 + "px";
|
602 |
+
gutterDiv.style.height = height + 4 + "px";
|
603 |
+
}
|
604 |
+
selectedAnnoteEl = annoteEl;
|
605 |
+
}
|
606 |
+
};
|
607 |
+
const unselectCodeLines = () => {
|
608 |
+
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
|
609 |
+
elementsIds.forEach((elId) => {
|
610 |
+
const div = window.document.getElementById(elId);
|
611 |
+
if (div) {
|
612 |
+
div.remove();
|
613 |
+
}
|
614 |
+
});
|
615 |
+
selectedAnnoteEl = undefined;
|
616 |
+
};
|
617 |
+
// Handle positioning of the toggle
|
618 |
+
window.addEventListener(
|
619 |
+
"resize",
|
620 |
+
throttle(() => {
|
621 |
+
elRect = undefined;
|
622 |
+
if (selectedAnnoteEl) {
|
623 |
+
selectCodeLines(selectedAnnoteEl);
|
624 |
+
}
|
625 |
+
}, 10)
|
626 |
+
);
|
627 |
+
function throttle(fn, ms) {
|
628 |
+
let throttle = false;
|
629 |
+
let timer;
|
630 |
+
return (...args) => {
|
631 |
+
if(!throttle) { // first call gets through
|
632 |
+
fn.apply(this, args);
|
633 |
+
throttle = true;
|
634 |
+
} else { // all the others get throttled
|
635 |
+
if(timer) clearTimeout(timer); // cancel #2
|
636 |
+
timer = setTimeout(() => {
|
637 |
+
fn.apply(this, args);
|
638 |
+
timer = throttle = false;
|
639 |
+
}, ms);
|
640 |
+
}
|
641 |
+
};
|
642 |
+
}
|
643 |
+
// Attach click handler to the DT
|
644 |
+
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
|
645 |
+
for (const annoteDlNode of annoteDls) {
|
646 |
+
annoteDlNode.addEventListener('click', (event) => {
|
647 |
+
const clickedEl = event.target;
|
648 |
+
if (clickedEl !== selectedAnnoteEl) {
|
649 |
+
unselectCodeLines();
|
650 |
+
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
|
651 |
+
if (activeEl) {
|
652 |
+
activeEl.classList.remove('code-annotation-active');
|
653 |
+
}
|
654 |
+
selectCodeLines(clickedEl);
|
655 |
+
clickedEl.classList.add('code-annotation-active');
|
656 |
+
} else {
|
657 |
+
// Unselect the line
|
658 |
+
unselectCodeLines();
|
659 |
+
clickedEl.classList.remove('code-annotation-active');
|
660 |
+
}
|
661 |
+
});
|
662 |
+
}
|
663 |
+
const findCites = (el) => {
|
664 |
+
const parentEl = el.parentElement;
|
665 |
+
if (parentEl) {
|
666 |
+
const cites = parentEl.dataset.cites;
|
667 |
+
if (cites) {
|
668 |
+
return {
|
669 |
+
el,
|
670 |
+
cites: cites.split(' ')
|
671 |
+
};
|
672 |
+
} else {
|
673 |
+
return findCites(el.parentElement)
|
674 |
+
}
|
675 |
+
} else {
|
676 |
+
return undefined;
|
677 |
+
}
|
678 |
+
};
|
679 |
+
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
|
680 |
+
for (var i=0; i<bibliorefs.length; i++) {
|
681 |
+
const ref = bibliorefs[i];
|
682 |
+
const citeInfo = findCites(ref);
|
683 |
+
if (citeInfo) {
|
684 |
+
tippyHover(citeInfo.el, function() {
|
685 |
+
var popup = window.document.createElement('div');
|
686 |
+
citeInfo.cites.forEach(function(cite) {
|
687 |
+
var citeDiv = window.document.createElement('div');
|
688 |
+
citeDiv.classList.add('hanging-indent');
|
689 |
+
citeDiv.classList.add('csl-entry');
|
690 |
+
var biblioDiv = window.document.getElementById('ref-' + cite);
|
691 |
+
if (biblioDiv) {
|
692 |
+
citeDiv.innerHTML = biblioDiv.innerHTML;
|
693 |
+
}
|
694 |
+
popup.appendChild(citeDiv);
|
695 |
+
});
|
696 |
+
return popup.innerHTML;
|
697 |
+
});
|
698 |
+
}
|
699 |
+
}
|
700 |
+
});
|
701 |
+
</script>
|
702 |
+
</div> <!-- /content -->
|
703 |
+
|
704 |
+
|
705 |
+
|
706 |
+
|
707 |
+
</body></html>
|
src/_site/listings.json
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"listing": "/index.html",
|
4 |
+
"items": [
|
5 |
+
"/posts/2025-01-06-chebyshev-polynomials/index.html",
|
6 |
+
"/posts/2025-01-04-fourier-method-fixed-string/index.html"
|
7 |
+
]
|
8 |
+
}
|
9 |
+
]
|
src/_site/posts/2025-01-04-fourier-method-fixed-string/code/fixed_string_animation.html
ADDED
The diff for this file is too large to render.
See raw diff
|
|
src/_site/posts/2025-01-04-fourier-method-fixed-string/images/fixed_string.svg
ADDED
|
src/_site/posts/2025-01-04-fourier-method-fixed-string/images/harmonics.svg
ADDED
|
src/_site/posts/2025-01-04-fourier-method-fixed-string/images/odd_continuation.png
ADDED
![]() |
Git LFS Details
|
src/_site/posts/2025-01-04-fourier-method-fixed-string/index.html
ADDED
The diff for this file is too large to render.
See raw diff
|
|
src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_nodes.png
ADDED
![]() |
Git LFS Details
|
src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_nodes_visualization.svg
ADDED
|
src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_polynomials.png
ADDED
![]() |
Git LFS Details
|
src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_polynomials_aliasing_even.png
ADDED
![]() |
Git LFS Details
|
src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_polynomials_aliasing_odd.png
ADDED
![]() |
Git LFS Details
|
src/_site/posts/2025-01-06-chebyshev-polynomials/images/chebyshev_polynomials_stacked.png
ADDED
![]() |
Git LFS Details
|
src/_site/posts/2025-01-06-chebyshev-polynomials/images/polar_0.png
ADDED
![]() |
Git LFS Details
|
src/_site/posts/2025-01-06-chebyshev-polynomials/images/polar_1.png
ADDED
![]() |
Git LFS Details
|
src/_site/posts/2025-01-06-chebyshev-polynomials/images/polar_10.png
ADDED
![]() |
Git LFS Details
|
src/_site/posts/2025-01-06-chebyshev-polynomials/images/polar_11.png
ADDED
![]() |
Git LFS Details
|
src/_site/posts/2025-01-06-chebyshev-polynomials/images/polar_2.png
ADDED
![]() |
Git LFS Details
|