Skip to content

Instantly share code, notes, and snippets.

@behackl
Last active July 19, 2023 17:29
Show Gist options
  • Save behackl/08f50c8baaa8e8085547f2c601a2c273 to your computer and use it in GitHub Desktop.
Save behackl/08f50c8baaa8e8085547f2c601a2c273 to your computer and use it in GitHub Desktop.
SD120 - Asymptotic Expansions in SageMath
FROM sagemath/sagemath:9.7
ARG NB_UID=1000
ARG NB_USER=sage
USER root
RUN apt update && apt install -y python3 python3-pip
USER ${NB_UID}
ENV PATH="${PATH}:${HOME}/.local/bin"
RUN pip3 install notebook
RUN sage -pip install RISE sage_acsv
RUN ln -s $(sage -sh -c 'ls -d $SAGE_VENV/share/jupyter/kernels/sagemath') $HOME/.local/share/jupyter/kernels/sagemath-dev
# partially superfluous -- create separate directory to hold notebooks
WORKDIR ${HOME}/notebooks
COPY --chown=${NB_UID}:${NB_UID} . .
USER root
RUN chown -R ${NB_UID}:${NB_UID} .
USER ${NB_UID}
ENTRYPOINT []
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "f6589899",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Asymptotic Expansions and the `AsymptoticRing`\n",
"\n",
"Joint work with Thomas Hagelmayer, Clemens Heuberger, Daniel Krenn, ..."
]
},
{
"cell_type": "markdown",
"id": "16cd6dc7",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"```\n",
"git shortlog -n -s -- src/sage/rings/asymptotic | wc -l\n",
" 31\n",
"```\n",
":-)"
]
},
{
"cell_type": "markdown",
"id": "3f59e330",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"An asymptotic expansion is an expression like\n",
"$$ 5z^3 + 4z^2 + O(z) $$\n",
"as $z\\to\\infty$, or\n",
"$$ 3 x^42 y^2 + 7 x^3 y^3 + O(x^2) + O(y) $$\n",
"as $x, y\\to\\infty$."
]
},
{
"cell_type": "markdown",
"id": "29f973ee",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"*Reminder:* big-Oh (*Bachmann-Landau*) notation expresses a class of functions of (specified) bounded growth:\n",
"$$f(n) = O(g(n)) :\\iff \\exists n_0 > 0, C > 0 \\forall n > n_0: |f(n)| \\leq C |g(n)|$$"
]
},
{
"cell_type": "markdown",
"id": "fac10cd1",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"*Examples:*\n",
"$n = O(n)$, $n = O(n^2)$, $n! = O(n^n) = O(e^{n \\log n})$"
]
},
{
"cell_type": "markdown",
"id": "acec7400",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"**Want:** Computations with such expressions in SageMath.\n",
"\n",
"Why not just use the already existing `PowerSeriesRing`?"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6608c31c",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"PSR.<n> = PowerSeriesRing(QQ)\n",
"PSR"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b2e20507",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"n + O(n)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5d0a0c30",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"n + O(n^2) # in PSR, n -> 0 instead of -> oo (workaround possible ...)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "78733bb6",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [],
"source": [
"n*log(n) # hmm. :-/"
]
},
{
"cell_type": "markdown",
"id": "d5739243",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"Logarithmic growth is not exotic, appears naturally in e.g. $n!$ and of course also in applications like Analysis of Algorithms (e.g., Mergesort (among many others): $O(n \\log n)$ comparisons ...)"
]
},
{
"cell_type": "markdown",
"id": "0ba55894",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"**Want (actually):** Flexible structure able to handle a broad spectrum of expansions like\n",
"$$ \\sqrt{\\pi} e^{n\\log n} - 42 n^2 \\log(n)^{3/2} + \\frac{1 + \\sqrt{5}}{2} n \\log(n) \\log(\\log(n)) + O(\\log(n)/n) $$"
]
},
{
"cell_type": "markdown",
"id": "720b6153",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## ... well, then we'll just implement it ourselves!\n",
"\n",
"- Initial implementation within GSoC 2015 (Student: BH, Mentors: Daniel Krenn, Clemens Heuberger),\n",
"- gradual improvements over the years,\n",
"- recently (GSoC 2022): initial implementation of new feature (Student: Thomas Hagelmayer, Mentor: BH, Clemens Heuberger)"
]
},
{
"cell_type": "markdown",
"id": "f42ec61a",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"- [Overview](https://doc.sagemath.org/html/en/reference/asymptotic/index.html)\n",
"- [Documentation of the main structure, `AsymptoticRing`](https://doc.sagemath.org/html/en/reference/asymptotic/sage/rings/asymptotic/asymptotic_ring.html)"
]
},
{
"cell_type": "markdown",
"id": "78b33e64",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# What can it do? Demo Time!\n",
"\n",
"### Creating an `AsymptoticRing`"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9ead441b",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"SCR = SR.subring(no_variables=True)\n",
"SCR # our coefficient ring"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e12856cb",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"A = AsymptoticRing(\n",
" growth_group='QQ^n * n^QQ * log(n)^QQ', # \"structure\" of the expansions\n",
" coefficient_ring=SCR,\n",
" default_prec=7, # default precision\n",
")\n",
"A"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21e7f2f1",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [],
"source": [
"n = A.gen()\n",
"n # the \"asymptotic variable\", we consider n -> oo ..."
]
},
{
"cell_type": "markdown",
"id": "50eca18e",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Creation of expansions *just works*™️:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "64f94bf9",
"metadata": {},
"outputs": [],
"source": [
"%display typeset"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ac7e6975",
"metadata": {},
"outputs": [],
"source": [
"expansion = (\n",
" 42 * (1/3)^n * n^(5/2) * log(n)^2 \n",
" + O((1/3)^n * n * log(n)^(1/2))\n",
")\n",
"expansion"
]
},
{
"cell_type": "markdown",
"id": "a3115ae7",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## Basic Expansion Arithmetic\n",
"\n",
"Addition, subtraction, multiplication and absorption (via $O$-terms) is easy!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dab8de01",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"(n^2 + n + 1) + (2*n + O(n^(-1)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "660e5fca",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"n^2 + O(n) - O(n)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "af829f44",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"O(n^2 + n + 1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cc4aa833",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"(1 + 1/n) * (n^3 - n^2 + n + O(n^0)) # O(n^0) = O(1)"
]
},
{
"cell_type": "markdown",
"id": "37bbac2a",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"More operations that work out of the box: division, taking $\\exp$ / $\\log$: if necessary, the expressions are expanded as series. Number of terms before cutoff depends on chosen default precision."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "11946360",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"(n - 1) / (n^3 + n^2 + O(n))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1ee62ecd",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"exp(1 + 1/n^2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "65d6373d",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"log(n+1)"
]
},
{
"cell_type": "markdown",
"id": "684edd0c",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"Advanced computations are possible as well, e.g. computing the power of some asymptotic expansion to another asymptotic expansion:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ab2d9272",
"metadata": {},
"outputs": [],
"source": [
"(1 + 1/n)^n"
]
},
{
"cell_type": "markdown",
"id": "a2d7b2ff",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## Asymptotic Expansion Generators\n",
"\n",
"Asymptotic expansions of certain well-known objects (like binomial coefficients $\\binom{kn}{n}$) can be accessed easily via *generators*: `asymptotic_expansion`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "73cca67a",
"metadata": {},
"outputs": [],
"source": [
"asymptotic_expansions.Binomial_kn_over_n(n, k=2, precision=4)"
]
},
{
"cell_type": "markdown",
"id": "7c97ed16",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"#### Harmonic Numbers\n",
"... are defined as $H_n = \\sum_{k=1}^n \\frac{1}{k}$. We have implemented their expansion directly via a generator:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bdcf0094",
"metadata": {},
"outputs": [],
"source": [
"asymptotic_expansions.HarmonicNumber('n', precision=5)"
]
},
{
"cell_type": "markdown",
"id": "ac59dd5c",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"#### Catalan Numbers\n",
"... are given by $C_n = \\frac{1}{n+1} \\binom{2n}{n}$, and can be obtained by dividing the asymptotic expansion of the central binomial coefficient (available via `asymptotic_expansions.Binomial_kn_over_n`) by $n+1$:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0223eb9e",
"metadata": {},
"outputs": [],
"source": [
"catalan_n = (\n",
" asymptotic_expansions.Binomial_kn_over_n(n, k=2, precision=5)\n",
" / (n + 1)\n",
")\n",
"catalan_n"
]
},
{
"cell_type": "markdown",
"id": "60c04ff9",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"## Singularity Analysis\n",
"\n",
"For explicity given generating functions, our module can extract the coefficient growth by means of singularity analysis directly: this is implemented as a method of the underlying asymptotic ring.\n",
"\n",
"Consider the well-known\n",
"$$ \\mathrm{Catalan}(z) = \\frac{1 - \\sqrt{1 - 4z}}{2z}. $$"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a3cd3042",
"metadata": {},
"outputs": [],
"source": [
"def catalan(z):\n",
" return (1 - sqrt(1 - 4*z))/(2*z)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "08d0bfd7",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [],
"source": [
"catalan(x).series(x==0, 6)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a8419369",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"C_n = A.coefficients_of_generating_function(\n",
" function=catalan,\n",
" singularities=(1/4,),\n",
" precision=5\n",
")\n",
"C_n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "45de61d4",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"catalan_n - C_n"
]
},
{
"cell_type": "markdown",
"id": "635b8cf9",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"Harmonic numbers have the generating function\n",
"$$ \\sum_{n\\geq 0} H_n z^n = -\\frac{\\log(1 - z)}{1 - z}. $$"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a92e2545",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"H_n = A.coefficients_of_generating_function(\n",
" function=lambda z: -log(1 - z)/(1 - z),\n",
" singularities=(1,),\n",
" precision=10\n",
")\n",
"H_n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0db75840",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"asymptotic_expansions.HarmonicNumber('n', precision=10) - H_n"
]
},
{
"cell_type": "markdown",
"id": "f52da6bd",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"#### Inverse Functions\n",
"There is also a generator that extracts the coefficient growth of a function $y(z)$ satisfying the implicit equation $y(z) = z \\Phi(y(z))$ (\"singular inversion\" -- Flajolet–Sedgewick, Analytic Combinatorics, Chapter VI.7); the *usual conditions* with respect to $\\Phi$ need to hold."
]
},
{
"cell_type": "markdown",
"id": "6e06c6b8",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"*Example:* the generating function $y(z)$ of unary-binary-ternary trees satisfies\n",
"$$ y = z (1 + 3y + 3y^2 + y^3). $$"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0a28120d",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"assume(SR.an_element() > 0) # required to make coercions work better ...\n",
"tree_asy = asymptotic_expansions.InverseFunctionAnalysis(\n",
" var=n,\n",
" phi=lambda y: 1 + 3*y + 3*y^2 + y^3,\n",
" precision=7,\n",
")\n",
"tree_asy"
]
},
{
"cell_type": "markdown",
"id": "a69fc697",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## New feature: [$B$-Terms](https://benjamin-hackl.at/downloads/talks/2023-06-29-aofa23/#/2/3)\n",
"\n",
"... are like $O$-terms, but without implicitly hidden constants:\n",
"\n",
"$$ f(n) = B_{n\\geq n_0}(C \\cdot g(n)) :\\iff \\forall n \\geq n_0: |f(n)| \\leq C |g(n)| $$"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c8a70b10",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"A.<n> = AsymptoticRing(\"n^QQ\", QQ, default_prec=6)\n",
"A.B(42*n^2, valid_from=5)"
]
},
{
"cell_type": "markdown",
"id": "5ad18c36",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"$B$-term arithmetic sometimes requires some thinking!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cf0e96c5",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"11*n + A.B(3*n, valid_from=1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c1f44e30",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"A.B(42*n^2, valid_from=5) - A.B(5*n^2, valid_from=5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "461d0d51",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"n^2 + A.B(19/n, valid_from=42) + O(1/n)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9cd775c4",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"A.B(5*n^3, valid_from=7) + A.B(3*n, valid_from=10)"
]
},
{
"cell_type": "markdown",
"id": "2ed2924e",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"... **lots** of open tasks in the context of $B$-term arithmetic!\n",
"\n",
"- Make arithmetic work for more complex growths than just monomials\n",
"- Implement some form of integral estimate to make series expansions with $B$-terms work\n",
"- $B$-term GSoC [meta issue #31922](https://github.com/sagemath/sage/issues/31922)\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "5e7883cc",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"... and even more tasks for asymptotic expansions in general, see [meta issue #17601](https://github.com/sagemath/sage/issues/17601)."
]
},
{
"cell_type": "markdown",
"id": "7075bb13",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Internals of the `AsymptoticRing`"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "524f8bda",
"metadata": {},
"outputs": [],
"source": [
"%display plain"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "46ed0f2e",
"metadata": {},
"outputs": [],
"source": [
"AR.<m, n> = AsymptoticRing(\"QQ^m * m^QQ * log(m)^QQ * n^QQ * log(n)^QQ * log(log(n))^QQ\", QQ, default_prec=5)\n",
"expr = 42 * 3^m * n + n^2 * log(log(n))^(1/2) + O(log(m)/n) + O(n)\n",
"expr"
]
},
{
"cell_type": "markdown",
"id": "64c54561",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"Expansion data is stored in a `MutablePoset`, order is determined from specification of growth group!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "62a9c42c",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"type(expr._summands_)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f37712cf",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"print(expr._summands_.repr_full())"
]
},
{
"cell_type": "markdown",
"id": "6ca4100c",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"Summands are elements from corresponding `TermMonoid` classes (e.g., `ExactTermMonoid`, `OTermMonoid`, ...)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a838f516",
"metadata": {},
"outputs": [],
"source": [
"terms = list(expr._summands_)\n",
"[s.parent() for s in terms]"
]
},
{
"cell_type": "markdown",
"id": "16166d91",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"... and terms primarily hold a growth, with is an element from a given growth group:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e1617b8f",
"metadata": {},
"outputs": [],
"source": [
"terms[0], terms[0].growth"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "57c451aa",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"terms[0].growth.parent()"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "SageMath 10.0",
"language": "sage",
"name": "sagemath"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.9"
},
"rise": {
"overlay": "<div style='position: absolute; right: 1em; top: 1em; font-size: 1.5em;'><em>Benjamin Hackl</em></div><div style='position: absolute; left: 1em; bottom: 1em;'><img width='100' src='https://benjamin-hackl.at/downloads/logo_uni_graz.jpeg'></div><div><img style='width: 100%; height: 100%; max-width: 100%; max-height: 100%; opacity: 0.5;' src='https://benjamin-hackl.at/downloads/background_uni_graz.png'></div>"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment