{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# First contact with SageMath\n", "\n", "This Jupyter notebook presents some elementary features of [SageMath](https://www.sagemath.org/).\n", "\n", "First we set up the display for LaTeX-typset outputs:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "tags": [] }, "outputs": [], "source": [ "%display latex" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Starting with numbers...\n", "\n", "SageMath knows about $\\pi$, $e$ and $i$ (well, it's mathematical software, isn't it ?):" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 0\\)" ], "text/latex": [ "$\\displaystyle 0$" ], "text/plain": [ "0" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "e^(i*pi) + 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*--- It's nice, but I thought SageMath was based on Python: shouldn't the above be written* `e**(i*pi) + 1`, \n", "*given that* `^` *is the bitwise XOR operator in Python?*\n", "\n", "Actually, the input cells are **preparsed** by SageMath before being sent to the Python interpreter. The action of the preparser is revealed by the function `preparse`:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\verb|e**(i*pi)|\\verb| |\\verb|+|\\verb| |\\verb|Integer(1)|\\)" ], "text/latex": [ "$\\displaystyle \\verb|e**(i*pi)|\\verb| |\\verb|+|\\verb| |\\verb|Integer(1)|$" ], "text/plain": [ "'e**(i*pi) + Integer(1)'" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "preparse(\"e^(i*pi) + 1\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see that indeed, the character `^` has been changed to `**`.\n", "\n", "Another noticable change is `1` $\\to$ `Integer(1)`. This means that the preparser is turning integers into SageMath integers, which belong to the class `Integer`:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\verb|<class|\\verb| |\\verb|'sage.rings.integer.Integer'>|\\)" ], "text/latex": [ "$\\displaystyle \\verb||$" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This type of integer is much more sophisticated than a mere Python integer (`int`). In particular, it knows to which mathematical set it belongs. The latter is returned by the function `parent`:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\newcommand{\\Bold}[1]{\\mathbf{#1}}\\Bold{Z}\\)" ], "text/latex": [ "$\\displaystyle \\newcommand{\\Bold}[1]{\\mathbf{#1}}\\Bold{Z}$" ], "text/plain": [ "Integer Ring" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "parent(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To have more information than just the symbol of the parent, one can use the `print` function:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Integer Ring\n" ] } ], "source": [ "print(parent(1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us denote this object by the Python variable `Z`:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\newcommand{\\Bold}[1]{\\mathbf{#1}}\\Bold{Z}\\)" ], "text/latex": [ "$\\displaystyle \\newcommand{\\Bold}[1]{\\mathbf{#1}}\\Bold{Z}$" ], "text/plain": [ "Integer Ring" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z = parent(1)\n", "Z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Z` is endowed with many methods, which can be discovered via the **TAB key**:\n", "```\n", " Z.\n", "```\n", "Once a method has been selected, one can get some **documentation** about it via `?`:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/plain": [ "\u001b[1;31mSignature:\u001b[0m \u001b[0mZ\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcardinality\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mDocstring:\u001b[0m \n", " Count the elements of the enumerated set.\n", "\n", " EXAMPLES:\n", "\n", " sage: NN = InfiniteEnumeratedSets().example()\n", " sage: NN.cardinality()\n", " +Infinity\n", "\u001b[1;31mInit docstring:\u001b[0m Initialize self. See help(type(self)) for accurate signature.\n", "\u001b[1;31mFile:\u001b[0m ~/sage/10.8/src/sage/categories/sets_cat.py\n", "\u001b[1;31mType:\u001b[0m method" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "Z.cardinality?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A double question mark leads directly to the **source code** (recall that SageMath is free software!):" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/plain": [ "\u001b[1;31mSignature:\u001b[0m \u001b[0mZ\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcardinality\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mDocstring:\u001b[0m\n", " Count the elements of the enumerated set.\n", "\n", " EXAMPLES:\n", "\n", " sage: NN = InfiniteEnumeratedSets().example()\n", " sage: NN.cardinality()\n", " +Infinity\n", "\u001b[1;31mSource:\u001b[0m \n", " \u001b[1;32mdef\u001b[0m \u001b[0mcardinality\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n", "\u001b[1;33m\u001b[0m \u001b[1;34m\"\"\"\u001b[0m\n", "\u001b[1;34m Count the elements of the enumerated set.\u001b[0m\n", "\u001b[1;34m\u001b[0m\n", "\u001b[1;34m EXAMPLES::\u001b[0m\n", "\u001b[1;34m\u001b[0m\n", "\u001b[1;34m sage: NN = InfiniteEnumeratedSets().example()\u001b[0m\n", "\u001b[1;34m sage: NN.cardinality()\u001b[0m\n", "\u001b[1;34m +Infinity\u001b[0m\n", "\u001b[1;34m \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n", "\u001b[1;33m\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0msage\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrings\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfinity\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0minfinity\u001b[0m\u001b[1;33m\u001b[0m\n", "\u001b[1;33m\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0minfinity\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mFile:\u001b[0m ~/sage/10.8/src/sage/categories/sets_cat.py\n", "\u001b[1;31mType:\u001b[0m method" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "Z.cardinality??" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "More documentation is available in the [reference manual](https://doc.sagemath.org/html/en/reference/) as well as in various [tutorials and guides](https://doc.sagemath.org/html/en/)." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle +\\infty\\)" ], "text/latex": [ "$\\displaystyle +\\infty$" ], "text/plain": [ "+Infinity" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z.cardinality()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other methods:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\mathrm{True}\\)" ], "text/latex": [ "$\\displaystyle \\mathrm{True}$" ], "text/plain": [ "True" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z.is_ring()" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\mathrm{False}\\)" ], "text/latex": [ "$\\displaystyle \\mathrm{False}$" ], "text/plain": [ "False" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z.is_field()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left(0, 1\\right)\\)" ], "text/latex": [ "$\\displaystyle \\left(0, 1\\right)$" ], "text/plain": [ "(0, 1)" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z.zero(), Z.one() # the ring zero and unit elements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Expressing $1\\in \\mathbb{Z}$ in SageMath:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\mathrm{True}\\)" ], "text/latex": [ "$\\displaystyle \\mathrm{True}$" ], "text/plain": [ "True" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 in Z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1 is actually the unit element of the ring $\\mathbb{Z}$:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\mathrm{True}\\)" ], "text/latex": [ "$\\displaystyle \\mathrm{True}$" ], "text/plain": [ "True" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 == Z.one()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that there exits a predefined variable, `ZZ`, for $\\mathbb{Z}$:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\mathrm{True}\\)" ], "text/latex": [ "$\\displaystyle \\mathrm{True}$" ], "text/plain": [ "True" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Z is ZZ" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "SageMath integers can be arbitrarily large (up to the limit of the computer memory!):" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 170141183460469231731687303715884105727\\)" ], "text/latex": [ "$\\displaystyle 170141183460469231731687303715884105727$" ], "text/plain": [ "170141183460469231731687303715884105727" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = 2^127 - 1\n", "m" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\mathrm{True}\\)" ], "text/latex": [ "$\\displaystyle \\mathrm{True}$" ], "text/plain": [ "True" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.is_prime()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that one has still access to the Python integers, via `int`:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 1\\)" ], "text/latex": [ "$\\displaystyle 1$" ], "text/plain": [ "1" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int(1)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\verb|<class|\\verb| |\\verb|'int'>|\\)" ], "text/latex": [ "$\\displaystyle \\verb||$" ], "text/plain": [ "" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(_) # the underscore stands for the latest output" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An alternative for accessing Python integers is to use the suffix `r` (standing for \"raw\", i.e. unpreparsed):" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 1\\)" ], "text/latex": [ "$\\displaystyle 1$" ], "text/plain": [ "1" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1r" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\verb|<class|\\verb| |\\verb|'int'>|\\)" ], "text/latex": [ "$\\displaystyle \\verb||$" ], "text/plain": [ "" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Python integers are automatically converted (coerced) into SageMath integers if necessary, for instance if they are\n", "added to some SageMath integer:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 3\\)" ], "text/latex": [ "$\\displaystyle 3$" ], "text/plain": [ "3" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int(1) + 2" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\verb|<class|\\verb| |\\verb|'sage.rings.integer.Integer'>|\\)" ], "text/latex": [ "$\\displaystyle \\verb||$" ], "text/plain": [ "" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course, SageMath also knows about **rational numbers**:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\frac{2}{3}\\)" ], "text/latex": [ "$\\displaystyle \\frac{2}{3}$" ], "text/plain": [ "2/3" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2/3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python would have returned 0.6666666666666666. This is not the case here because" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\verb|Integer(2)/Integer(3)|\\)" ], "text/latex": [ "$\\displaystyle \\verb|Integer(2)/Integer(3)|$" ], "text/plain": [ "'Integer(2)/Integer(3)'" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "preparse('2/3')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and the division of the (Sage) integer 2 by the (Sage) integer 3 is the (Sage) rational number $2/3$: " ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\newcommand{\\Bold}[1]{\\mathbf{#1}}\\Bold{Q}\\)" ], "text/latex": [ "$\\displaystyle \\newcommand{\\Bold}[1]{\\mathbf{#1}}\\Bold{Q}$" ], "text/plain": [ "Rational Field" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "parent(2/3)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Rational Field\n" ] } ], "source": [ "print(_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As the above examples illustrate, SageMath is based on a **Parent/Element scheme**: `parent(a)` is the algebraic or topological/differential structure to which `a` belongs. \n", "\n", "SageMath has also the concept of **mathematical categories**:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Join of Category of Dedekind domains and Category of euclidean domains and Category of noetherian rings and Category of infinite enumerated sets and Category of metric spaces\n" ] } ], "source": [ "print(category(Z))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Real numbers\n", "\n", "SageMath can compute numerical values with an arbitrary number of digits:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420199\\)" ], "text/latex": [ "$\\displaystyle 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420199$" ], "text/plain": [ "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420199" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n(pi, digits=1000)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`n` is the shortcut alias for `numerical_approx`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another interesting computation regards the *Hermite-Ramanujan constant*:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle e^{\\left(\\sqrt{163} \\pi\\right)}\\)" ], "text/latex": [ "$\\displaystyle e^{\\left(\\sqrt{163} \\pi\\right)}$" ], "text/plain": [ "e^(sqrt(163)*pi)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = exp(pi*sqrt(163))\n", "a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Actually, this number is very close to an integer, as announced by [Charles Hermite in 1859](https://gallica.bnf.fr/ark:/12148/bpt6k6209489m/f60) (probably without using SageMath...):" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 2.6253741264076874399999999999925007259719818568889 \\times 10^{17}\\)" ], "text/latex": [ "$\\displaystyle 2.6253741264076874399999999999925007259719818568889 \\times 10^{17}$" ], "text/plain": [ "2.6253741264076874399999999999925007259719818568889e17" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n(a, digits=50)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That's clear if we turn off scientific notation:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 262537412640768743.99999999999925007259719818568888661\\)" ], "text/latex": [ "$\\displaystyle 262537412640768743.99999999999925007259719818568888661$" ], "text/plain": [ "'262537412640768743.99999999999925007259719818568888661'" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n(a, digits=50).str(no_sci=2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Symbolic computations\n", "\n", "Beside numerical computations, SageMath can perform symbolic ones. For instance, it can compute a **derivative**:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 2 \\, x \\cos\\left(x^{2}\\right)\\)" ], "text/latex": [ "$\\displaystyle 2 \\, x \\cos\\left(x^{2}\\right)$" ], "text/plain": [ "2*x*cos(x^2)" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = diff(sin(x^2), x)\n", "f" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Due to the command `%display latex` in the first cell of this notebook, SageMath displays all results, such as the one above, in LaTeX format. To get them in console mode, use the function `print`:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2*x*cos(x^2)\n" ] } ], "source": [ "print(f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The explicit LaTeX code can be obtained:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2 \\, x \\cos\\left(x^{2}\\right)\n" ] } ], "source": [ "print(latex(f))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A pdf file with the LaTeX typeset formula is generated by the function `view`:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "view(f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The symbolic variable `x` used above is the only one that is predefined in a SageMath session. All other symbolic variables must be declared explicitly, via the function `var`:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [], "source": [ "y = var('y')\n", "\n", "alp = var('alp', latex_name=r'\\alpha')" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle {\\alpha} y + x\\)" ], "text/latex": [ "$\\displaystyle {\\alpha} y + x$" ], "text/plain": [ "alp*y + x" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = alp*y + x\n", "f" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle y\\)" ], "text/latex": [ "$\\displaystyle y$" ], "text/plain": [ "y" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diff(f, alp)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "SageMath can also compute **primitives**:" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\int \\frac{x^{5}}{x^{3} - 2 \\, x + 1}\\,{d x}\\)" ], "text/latex": [ "$\\displaystyle \\int \\frac{x^{5}}{x^{3} - 2 \\, x + 1}\\,{d x}$" ], "text/plain": [ "integrate(x^5/(x^3 - 2*x + 1), x)" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "integrate(x^5/(x^3 - 2*x +1), x, hold=True) " ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\frac{1}{3} \\, x^{3} + \\frac{2}{5} \\, \\sqrt{5} \\log\\left(\\frac{2 \\, x - \\sqrt{5} + 1}{2 \\, x + \\sqrt{5} + 1}\\right) + 2 \\, x - \\log\\left(x^{2} + x - 1\\right) + \\log\\left(x - 1\\right)\\)" ], "text/latex": [ "$\\displaystyle \\frac{1}{3} \\, x^{3} + \\frac{2}{5} \\, \\sqrt{5} \\log\\left(\\frac{2 \\, x - \\sqrt{5} + 1}{2 \\, x + \\sqrt{5} + 1}\\right) + 2 \\, x - \\log\\left(x^{2} + x - 1\\right) + \\log\\left(x - 1\\right)$" ], "text/plain": [ "1/3*x^3 + 2/5*sqrt(5)*log((2*x - sqrt(5) + 1)/(2*x + sqrt(5) + 1)) + 2*x - log(x^2 + x - 1) + log(x - 1)" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "integrate(x^5/(x^3 - 2*x + 1), x) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and of course definite integrals: it suffices to provide the two boundaries after the argument `x`. A first attempt with 0 and 1 fails:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "# integrate(x^5/(x^3 - 2*x + 1), x, 0, 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Don't panic:** error messages are usually long because they display the whole call stack. The important information lies at the end:\n", "```\n", "ValueError: Integral is divergent\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Choosing the boundaries to be 2 and 3 yields a convergent integral:" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\frac{2}{5} \\, \\sqrt{5} \\log\\left(-\\frac{7}{22} \\, \\sqrt{5} + \\frac{27}{22}\\right) - \\frac{2}{5} \\, \\sqrt{5} \\log\\left(-\\frac{1}{2} \\, \\sqrt{5} + \\frac{3}{2}\\right) - \\log\\left(11\\right) + \\log\\left(5\\right) + \\log\\left(2\\right) + \\frac{25}{3}\\)" ], "text/latex": [ "$\\displaystyle \\frac{2}{5} \\, \\sqrt{5} \\log\\left(-\\frac{7}{22} \\, \\sqrt{5} + \\frac{27}{22}\\right) - \\frac{2}{5} \\, \\sqrt{5} \\log\\left(-\\frac{1}{2} \\, \\sqrt{5} + \\frac{3}{2}\\right) - \\log\\left(11\\right) + \\log\\left(5\\right) + \\log\\left(2\\right) + \\frac{25}{3}$" ], "text/plain": [ "2/5*sqrt(5)*log(-7/22*sqrt(5) + 27/22) - 2/5*sqrt(5)*log(-1/2*sqrt(5) + 3/2) - log(11) + log(5) + log(2) + 25/3" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "integrate(x^5/(x^3 - 2*x + 1), x, 2, 3)" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 8.50669189170048\\)" ], "text/latex": [ "$\\displaystyle 8.50669189170048$" ], "text/plain": [ "8.50669189170048" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n(_) # numerical approximation of the above result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "SageMath proposes various symbolic engines to evaluate a primitive. The default one is [Maxima](https://maxima.sourceforge.io/):" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\frac{1}{3} \\, x^{3} + \\frac{2}{5} \\, \\sqrt{5} \\log\\left(\\frac{2 \\, x - \\sqrt{5} + 1}{2 \\, x + \\sqrt{5} + 1}\\right) + 2 \\, x - \\log\\left(x^{2} + x - 1\\right) + \\log\\left(x - 1\\right)\\)" ], "text/latex": [ "$\\displaystyle \\frac{1}{3} \\, x^{3} + \\frac{2}{5} \\, \\sqrt{5} \\log\\left(\\frac{2 \\, x - \\sqrt{5} + 1}{2 \\, x + \\sqrt{5} + 1}\\right) + 2 \\, x - \\log\\left(x^{2} + x - 1\\right) + \\log\\left(x - 1\\right)$" ], "text/plain": [ "1/3*x^3 + 2/5*sqrt(5)*log((2*x - sqrt(5) + 1)/(2*x + sqrt(5) + 1)) + 2*x - log(x^2 + x - 1) + log(x - 1)" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "integrate(x^5/(x^3 - 2*x + 1), x, algorithm='maxima') # same result as above" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "but [SymPy](https://www.sympy.org) is also available:" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\frac{1}{3} \\, x^{3} - \\frac{1}{5} \\, {\\left(2 \\, \\sqrt{5} + 5\\right)} \\log\\left(\\frac{1}{80} \\, {\\left(2 \\, \\sqrt{5} + 5\\right)}^{2} + x + \\frac{1}{4} \\, \\sqrt{5} - \\frac{1}{16}\\right) + \\frac{1}{5} \\, {\\left(2 \\, \\sqrt{5} - 5\\right)} \\log\\left(\\frac{1}{80} \\, {\\left(2 \\, \\sqrt{5} - 5\\right)}^{2} + x - \\frac{1}{4} \\, \\sqrt{5} - \\frac{1}{16}\\right) + 2 \\, x + \\log\\left(x - 1\\right)\\)" ], "text/latex": [ "$\\displaystyle \\frac{1}{3} \\, x^{3} - \\frac{1}{5} \\, {\\left(2 \\, \\sqrt{5} + 5\\right)} \\log\\left(\\frac{1}{80} \\, {\\left(2 \\, \\sqrt{5} + 5\\right)}^{2} + x + \\frac{1}{4} \\, \\sqrt{5} - \\frac{1}{16}\\right) + \\frac{1}{5} \\, {\\left(2 \\, \\sqrt{5} - 5\\right)} \\log\\left(\\frac{1}{80} \\, {\\left(2 \\, \\sqrt{5} - 5\\right)}^{2} + x - \\frac{1}{4} \\, \\sqrt{5} - \\frac{1}{16}\\right) + 2 \\, x + \\log\\left(x - 1\\right)$" ], "text/plain": [ "1/3*x^3 - 1/5*(2*sqrt(5) + 5)*log(1/80*(2*sqrt(5) + 5)^2 + x + 1/4*sqrt(5) - 1/16) + 1/5*(2*sqrt(5) - 5)*log(1/80*(2*sqrt(5) - 5)^2 + x - 1/4*sqrt(5) - 1/16) + 2*x + log(x - 1)" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "integrate(x^5/(x^3 - 2*x + 1), x, algorithm='sympy')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "as well as [Giac](https://www-fourier.ujf-grenoble.fr/~parisse/giac.html) (for SageMath version >= 10.6, this requires Giac to be installed seperately, cf. https://github.com/sagemath/sagemath-giac): " ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\int \\frac{x^{5}}{x^{3} - 2 \\, x + 1}\\,{d x}\\)" ], "text/latex": [ "$\\displaystyle \\int \\frac{x^{5}}{x^{3} - 2 \\, x + 1}\\,{d x}$" ], "text/plain": [ "integrate(x^5/(x^3 - 2*x + 1), x)" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "integrate(x^5/(x^3-2*x+1), x, algorithm='giac')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One can even use [WolframAlpha](https://www.wolframalpha.com/calculators/integral-calculator/) via some internet connection:" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\frac{1}{3} \\, x^{3} - \\frac{1}{5} \\, {\\left(2 \\, \\sqrt{5} + 5\\right)} \\log\\left(2 \\, x + \\sqrt{5} + 1\\right) + \\frac{1}{5} \\, {\\left(2 \\, \\sqrt{5} - 5\\right)} \\log\\left(-2 \\, x + \\sqrt{5} - 1\\right) + 2 \\, x + \\log\\left(-x + 1\\right)\\)" ], "text/latex": [ "$\\displaystyle \\frac{1}{3} \\, x^{3} - \\frac{1}{5} \\, {\\left(2 \\, \\sqrt{5} + 5\\right)} \\log\\left(2 \\, x + \\sqrt{5} + 1\\right) + \\frac{1}{5} \\, {\\left(2 \\, \\sqrt{5} - 5\\right)} \\log\\left(-2 \\, x + \\sqrt{5} - 1\\right) + 2 \\, x + \\log\\left(-x + 1\\right)$" ], "text/plain": [ "1/3*x^3 - 1/5*(2*sqrt(5) + 5)*log(2*x + sqrt(5) + 1) + 1/5*(2*sqrt(5) - 5)*log(-2*x + sqrt(5) - 1) + 2*x + log(-x + 1)" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "integrate(x^5/(x^3-2*x+1), x, algorithm='mathematica_free')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Actually SageMath is endowed with some interface to Mathematica:" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\verb|Cos[(x)^(2)]|\\)" ], "text/latex": [ "$\\displaystyle \\verb|Cos[(x)^(2)]|$" ], "text/plain": [ "'Cos[(x)^(2)]'" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cos(x^2)._mathematica_init_()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "as well as to SymPy, Maxima and Giac:" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\verb|cos(x**2)|\\)" ], "text/latex": [ "$\\displaystyle \\verb|cos(x**2)|$" ], "text/plain": [ "cos(x**2)" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cos(x^2)._sympy_()" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 2\n", " cos(_SAGE_VAR_x )\n" ] } ], "source": [ "print(cos(x^2)._maxima_())" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [], "source": [ "# cos(x^2)._giac_() # requires Giac to be installed " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us check the primitive computation:" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\frac{1}{3} \\, x^{3} + \\frac{2}{5} \\, \\sqrt{5} \\log\\left(\\frac{2 \\, x - \\sqrt{5} + 1}{2 \\, x + \\sqrt{5} + 1}\\right) + 2 \\, x - \\log\\left(x^{2} + x - 1\\right) + \\log\\left(x - 1\\right)\\)" ], "text/latex": [ "$\\displaystyle \\frac{1}{3} \\, x^{3} + \\frac{2}{5} \\, \\sqrt{5} \\log\\left(\\frac{2 \\, x - \\sqrt{5} + 1}{2 \\, x + \\sqrt{5} + 1}\\right) + 2 \\, x - \\log\\left(x^{2} + x - 1\\right) + \\log\\left(x - 1\\right)$" ], "text/plain": [ "1/3*x^3 + 2/5*sqrt(5)*log((2*x - sqrt(5) + 1)/(2*x + sqrt(5) + 1)) + 2*x - log(x^2 + x - 1) + log(x - 1)" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = integrate(x^5/(x^3-2*x+1), x) \n", "f" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle x^{2} + \\frac{4 \\, \\sqrt{5} {\\left(2 \\, x + \\sqrt{5} + 1\\right)} {\\left(\\frac{1}{2 \\, x + \\sqrt{5} + 1} - \\frac{2 \\, x - \\sqrt{5} + 1}{{\\left(2 \\, x + \\sqrt{5} + 1\\right)}^{2}}\\right)}}{5 \\, {\\left(2 \\, x - \\sqrt{5} + 1\\right)}} - \\frac{2 \\, x + 1}{x^{2} + x - 1} + \\frac{1}{x - 1} + 2\\)" ], "text/latex": [ "$\\displaystyle x^{2} + \\frac{4 \\, \\sqrt{5} {\\left(2 \\, x + \\sqrt{5} + 1\\right)} {\\left(\\frac{1}{2 \\, x + \\sqrt{5} + 1} - \\frac{2 \\, x - \\sqrt{5} + 1}{{\\left(2 \\, x + \\sqrt{5} + 1\\right)}^{2}}\\right)}}{5 \\, {\\left(2 \\, x - \\sqrt{5} + 1\\right)}} - \\frac{2 \\, x + 1}{x^{2} + x - 1} + \\frac{1}{x - 1} + 2$" ], "text/plain": [ "x^2 + 4/5*sqrt(5)*(2*x + sqrt(5) + 1)*(1/(2*x + sqrt(5) + 1) - (2*x - sqrt(5) + 1)/(2*x + sqrt(5) + 1)^2)/(2*x - sqrt(5) + 1) - (2*x + 1)/(x^2 + x - 1) + 1/(x - 1) + 2" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diff(f, x)" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\frac{x^{5}}{x^{3} - 2 \\, x + 1}\\)" ], "text/latex": [ "$\\displaystyle \\frac{x^{5}}{x^{3} - 2 \\, x + 1}$" ], "text/plain": [ "x^5/(x^3 - 2*x + 1)" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "_.simplify_full()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Indefinite integrals can also be computed:" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\sqrt{\\pi}\\)" ], "text/latex": [ "$\\displaystyle \\sqrt{\\pi}$" ], "text/plain": [ "sqrt(pi)" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "integrate(exp(-x^2), x, -oo, +oo)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Other examples of symbolic computations: \n", "\n", "- Taylor expansions:" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\frac{1}{40320} \\, x^{8} + \\frac{1}{5040} \\, x^{7} + \\frac{1}{720} \\, x^{6} + \\frac{1}{120} \\, x^{5} + \\frac{1}{24} \\, x^{4} + \\frac{1}{6} \\, x^{3} + \\frac{1}{2} \\, x^{2} + x + 1\\)" ], "text/latex": [ "$\\displaystyle \\frac{1}{40320} \\, x^{8} + \\frac{1}{5040} \\, x^{7} + \\frac{1}{720} \\, x^{6} + \\frac{1}{120} \\, x^{5} + \\frac{1}{24} \\, x^{4} + \\frac{1}{6} \\, x^{3} + \\frac{1}{2} \\, x^{2} + x + 1$" ], "text/plain": [ "1/40320*x^8 + 1/5040*x^7 + 1/720*x^6 + 1/120*x^5 + 1/24*x^4 + 1/6*x^3 + 1/2*x^2 + x + 1" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "exp(x).taylor(x, 0, 8)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- limits:" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 1\\)" ], "text/latex": [ "$\\displaystyle 1$" ], "text/plain": [ "1" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lim(sin(x)/x, x=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- series: Riemann's zeta function $\\zeta(s)$ for $s=2$ and $s=3$ (Apéry's constant):" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle {\\sum_{n=1}^{+\\infty} \\frac{1}{n^{2}}} = \\frac{1}{6} \\, \\pi^{2}\\)" ], "text/latex": [ "$\\displaystyle {\\sum_{n=1}^{+\\infty} \\frac{1}{n^{2}}} = \\frac{1}{6} \\, \\pi^{2}$" ], "text/plain": [ "sum(n^(-2), n, 1, +Infinity) == 1/6*pi^2" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n = var('n') # declaring n as a symbolic variable\n", "sum(1/n^2, n, 1, +oo, hold=True) == sum(1/n^2, n, 1, +oo)" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\zeta(3)\\)" ], "text/latex": [ "$\\displaystyle \\zeta(3)$" ], "text/plain": [ "zeta(3)" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sum(1/n^3, n, 1, +oo)" ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "tags": [] }, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle 1.20205690315959\\)" ], "text/latex": [ "$\\displaystyle 1.20205690315959$" ], "text/plain": [ "1.20205690315959" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numerical_approx(_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course, as many standard functions, Riemann's zeta function is already implemented in SageMath:" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\frac{1}{6} \\, \\pi^{2}\\)" ], "text/latex": [ "$\\displaystyle \\frac{1}{6} \\, \\pi^{2}$" ], "text/plain": [ "1/6*pi^2" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "zeta(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Solving an equation:" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\left[x = -\\frac{1}{2} \\, \\sqrt{5} + \\frac{1}{2}, x = \\frac{1}{2} \\, \\sqrt{5} + \\frac{1}{2}\\right]\\)" ], "text/latex": [ "$\\displaystyle \\left[x = -\\frac{1}{2} \\, \\sqrt{5} + \\frac{1}{2}, x = \\frac{1}{2} \\, \\sqrt{5} + \\frac{1}{2}\\right]$" ], "text/plain": [ "[x == -1/2*sqrt(5) + 1/2, x == 1/2*sqrt(5) + 1/2]" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "solve(x^2 == x + 1, x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Solving a differential equation:" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle -y\\left(x\\right) + \\frac{\\partial}{\\partial x}y\\left(x\\right) = x y\\left(x\\right)^{4}\\)" ], "text/latex": [ "$\\displaystyle -y\\left(x\\right) + \\frac{\\partial}{\\partial x}y\\left(x\\right) = x y\\left(x\\right)^{4}$" ], "text/plain": [ "-y(x) + diff(y(x), x) == x*y(x)^4" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = function('y')\n", "eq = diff(y(x), x) - y(x) == x*y(x)^4\n", "eq" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\(\\displaystyle \\frac{e^{x}}{{\\left(-\\frac{1}{3} \\, {\\left(3 \\, x - 1\\right)} e^{\\left(3 \\, x\\right)} + C\\right)}^{\\frac{1}{3}}}\\)" ], "text/latex": [ "$\\displaystyle \\frac{e^{x}}{{\\left(-\\frac{1}{3} \\, {\\left(3 \\, x - 1\\right)} e^{\\left(3 \\, x\\right)} + C\\right)}^{\\frac{1}{3}}}$" ], "text/plain": [ "e^x/(-1/3*(3*x - 1)*e^(3*x) + _C)^(1/3)" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "desolve(eq, y(x))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The power of Python" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, to illustrate the advantage of being built atop of Python, here is a loop for displaying Pascal's triangle with only two instruction lines:" ] }, { "cell_type": "code", "execution_count": 67, "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1]\n", "[1, 1]\n", "[1, 2, 1]\n", "[1, 3, 3, 1]\n", "[1, 4, 6, 4, 1]\n", "[1, 5, 10, 10, 5, 1]\n", "[1, 6, 15, 20, 15, 6, 1]\n", "[1, 7, 21, 35, 35, 21, 7, 1]\n", "[1, 8, 28, 56, 70, 56, 28, 8, 1]\n", "[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]\n" ] } ], "source": [ "for n in range(10): \n", " print([binomial(n, p) for p in range(n+1)])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Next step:\n", "\n", "### Plots and functions in SageMath" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAnQAAAHUCAYAAACznbW8AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjUsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvWftoOwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAYrVJREFUeJzt3XlcVXX+P/DXldUFcWUTENxQUlEQldwyzdJy2idrvlYzTb8WnLZpKts3s9WpGammaZmZasZmMlumcrRMzdQJF9xQEEFBhdxBUUHh/P54z3EFvMA993PO57yejweP8wjv8u56hdf9LO+PxzAMA0RERETkWC1UF0BEREREzcNAR0RERORwDHREREREDsdAR0RERORwDHREREREDqdFoNu3bx9+/etf48orr8S1116LY8eOnfbnDz74IK6++mpF1RERERFZy6ND25IpU6bg0Ucfxd69e9G3b198/vnnmDhxIgDAMAx07NgRgwYNwrx58xRXSkREROR7jh+h27hxI6KjoxEVFYWlS5cCACIiIk78+bp167B//35ceOGFqkokIiIispTjA93u3bsxefJkAMDf/vY39OjRA4MHDz7x54sXLwYABjoiIiLSVqDqAppr5MiRAIDi4mIsWbIEzz77LDwez4k/X7x4Mdq2bYu0tDRVJRIRERFZyvEjdKZPPvkEAHDNNdec9v3Fixdj5MiRCAgIUFEWERERkeW0CXTZ2dmIjo5GUlLSie/l5eXhp59+4nQrERERaU2bQLd371507dr1tO998803AIDRo0erKImIiIjIL7QJdIMGDUJxcTFqamoAAGvXrsVjjz2GDh06ICUlRXF1RERERNZx/KYI08MPP4zt27djwoQJ6NGjB9q0aYNjx45h/Pjxp22SICIiItKNFo2FDcPA0aNH0bJlyxPf+/TTT3HllVfiiy++wGWXXaawOiIiIiJraRHoLr74YixbtgylpaVo3bo1DMPAsGHD0LZtW8ydO1d1eURERESW0mINXXZ2NgYPHoyWLVuipqYG9957L2pra/HRRx+pLo2IiIjIclqM0M2fPx/z58/H4cOHsWvXLgwePBh33303goKCVJdGREREZDktAh0RERGRm2kx5UpERETkZgx0RERERA7HQEdERETkcAx0RERERA7HQEdERETkcAx0RERERA7HQEdERETkcAx0RERERA7H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jbO8LLIRj2EYhuoifKmiogLh4eEoLy9H27ZtVZdDRJo6fFi6+PfuDXz9deP6x+3aBZx3HjB6NPDPf1pXI+nlqquA/Hxg3br6329VVUDXrnJbK3omkn1xhI6IqAlatZJ2I//5D/Daa42775QpsiFi5kxraiM9ZWbKqG5DZ7vOmgX89BN3TbsRR+iIiJrht78F/vAHYNEi4Pzzz337P/8Z+H//T37xXned9fWRPgwDSEsDQkKApUvPHqU7dgxISZFGwl99paREUsiyEbpp06bh/PPPR6tWrdCuXTuv7mMYBp588knExMSgZcuWuOCCC7BhwwarSiQiarbnn5cgN2ECkJ3d8G2//BK44w7gzjulnx1RY3g8wCuvAMuXAx99dPafv/46sGkT12W6lWWBrrq6Gtdeey3uuOMOr+/z4osvYsaMGZg5cyays7MRFRWFiy66CAe92dZDRKRAUBDwxReynu6ii+ruFWYYwIwZ0kbi0ktlipZntlJTjB4NXHmlTNtv3Xry+2vWAI8+Ctx2G3saupXlU65/+ctfcM899+DAOVpcG4aBmJgY3HPPPXjwwQcBAFVVVYiMjMQLL7yA2267zavn45QrEalQXi796b78ErjsMuD//g+Ii5NdsG+/DSxeLDtjp08HAgNVV0tOtm8fkJ4uGyBeflmOj7v/fqBLF5n6b9NGdYWkgm02RRQVFaGsrAzjTtlnHRISglGjRmHp0qX13q+qqgoVFRWnfRER+Vt4uIzUffihHLk0aZKcwXnjjUB1tQS9l15imKPm69AB+P57IClJzgCePFnWzn31FcOcm9nmR0tZWRkAIDIy8rTvR0ZGYtu2bfXeb/r06XjqqacsrY2IyBseD3DDDfK1a5d8RUcDHTuqrox0ExMDfPstUFIiHxKio1VXRKo1aoTuySefhMfjafBrxYoVzSrIc8bCEsMwzvreqaZOnYry8vITXyUlJc16fiIiX4iIAPr2ZZgja8XFMcyRaNQI3ZQpUzDpHGeJJCQkNKmQqKgoADJSF33Ku3PXrl1njdqdKiQkBCEhIU16TiIiIiIdNCrQderUCZ06dbKkkMTERERFRWH+/PkY+L8tOtXV1Vi0aBFeeOEFS56TiIiISAeWbYooLi5GTk4OiouLUVNTg5ycHOTk5ODQoUMnbtO7d2/MmTMHgEy13nPPPXjuuecwZ84crF+/HjfffDNatWqFG264waoyiYiIiBzPsk0Rjz/+OP7617+e+G9z1O27777DBRdcAADIy8tDeXn5ids88MADOHLkCO68807s378fQ4YMwbx58xAWFmZVmURERESOx6O/iIiIiBzONn3oiIiIiKhpGOiIiIiIHE67KVfDMHDw4EGEhYU12L+OiIiISBfaBToiIiIit+GUKxEREZHDMdARERERORwDHREREZHDMdARERERORwDHREREZHDMdARERERORwDHREREZHD/X8iS/vJK4u2XgAAAABJRU5ErkJggg==", "text/plain": [ "Graphics object consisting of 1 graphics primitive" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "plot(sin(x^2), (x, 0, 4), axes_labels=['$x$', '$y$'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "See the [dedicated notebook](https://nbviewer.org/github/egourgoulhon/SageMathTour/blob/master/Notebooks/plot_tour_2D.ipynb) for more on plots in SageMath. " ] } ], "metadata": { "kernelspec": { "display_name": "SageMath 10.8", "language": "sage", "name": "sagemath" }, "language": "python", "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.12.3" } }, "nbformat": 4, "nbformat_minor": 4 }