{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "# Symolic Computation playground!" ] }, { "cell_type": "markdown", "id": "1", "metadata": {}, "source": [ "This is a playgrond area for learning and trying out stuffs of symbolic computation via `sympy` for Vitor." ] }, { "cell_type": "markdown", "id": "2", "metadata": {}, "source": [ "The try out here is based on [`Sympy` toturial](https://docs.sympy.org/latest/tutorials/intro-tutorial/index.html): an introduction to SymPy for someone who has not used the library before." ] }, { "cell_type": "markdown", "id": "3", "metadata": {}, "source": [ "## [Introductory](https://docs.sympy.org/latest/tutorials/intro-tutorial/intro.html) (What is Symbolic Computation?)" ] }, { "cell_type": "markdown", "id": "4", "metadata": {}, "source": [ "### manipulate irrational numbers" ] }, { "cell_type": "markdown", "id": "5", "metadata": {}, "source": [ "perfect square: precise result" ] }, { "cell_type": "code", "execution_count": null, "id": "6", "metadata": {}, "outputs": [], "source": [ "import math\n", "math.sqrt(9)" ] }, { "cell_type": "markdown", "id": "7", "metadata": {}, "source": [ "non-perfect square: approximation result" ] }, { "cell_type": "code", "execution_count": null, "id": "8", "metadata": {}, "outputs": [], "source": [ "math.sqrt(8)" ] }, { "cell_type": "markdown", "id": "9", "metadata": {}, "source": [ "The way it does in `sympy`: square roots of numbers that are not perfect squares are left unevaluated by default." ] }, { "cell_type": "code", "execution_count": null, "id": "10", "metadata": {}, "outputs": [], "source": [ "import sympy\n", "sympy.sqrt(3)" ] }, { "cell_type": "markdown", "id": "11", "metadata": {}, "source": [ "And symbolic results can be symbolically simplified!" ] }, { "cell_type": "code", "execution_count": null, "id": "12", "metadata": {}, "outputs": [], "source": [ "sympy.sqrt(8)" ] }, { "cell_type": "markdown", "id": "13", "metadata": {}, "source": [ "### A More Interesting Example: computing symbolic expressions with variables\n" ] }, { "cell_type": "markdown", "id": "14", "metadata": {}, "source": [ "Symbolic computation systems (often called computer algebra systems, or just CASs) such as SymPy are capable of computing symbolic expressions with variables." ] }, { "cell_type": "code", "execution_count": null, "id": "15", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [ "raises-exception" ] }, "outputs": [], "source": [ "x, y = symbols('x y')\n", "try:\n", " expr1 = x + 2y # not like this!\n", "except error:\n", " print(\"SyntaxError: invalid decimal literal\")" ] }, { "cell_type": "markdown", "id": "16", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "For example, the way in `sympy` to define $x+2y$" ] }, { "cell_type": "code", "execution_count": null, "id": "17", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "from sympy import symbols\n", "x, y = symbols('x y')\n", "expr = x + 2*y\n", "expr" ] }, { "cell_type": "markdown", "id": "18", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "Play around now!" ] }, { "cell_type": "markdown", "id": "19", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "simplification automatically" ] }, { "cell_type": "code", "execution_count": null, "id": "20", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "expr + 1" ] }, { "cell_type": "code", "execution_count": null, "id": "21", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "expr - x" ] }, { "cell_type": "markdown", "id": "22", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "Notice: factor form" ] }, { "cell_type": "code", "execution_count": null, "id": "23", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "x*expr" ] }, { "cell_type": "markdown", "id": "24", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "What if we want expanded form? use `expand`" ] }, { "cell_type": "code", "execution_count": null, "id": "25", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "from sympy import expand, factor\n", "expanded_expr = expand(x*expr)\n", "expanded_expr" ] }, { "cell_type": "markdown", "id": "26", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "The other way around? To factor the expaned form:" ] }, { "cell_type": "code", "execution_count": null, "id": "27", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "factor(expanded_expr)" ] }, { "cell_type": "markdown", "id": "28", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "### The Real Power of Symbolic Computation !?" ] }, { "cell_type": "markdown", "id": "29", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "The real power of a symbolic computation system such as SymPy is the ability to do all sorts of computations symbolically." ] }, { "cell_type": "markdown", "id": "30", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "\"Symbolically\"... What does it imply actually?" ] }, { "cell_type": "markdown", "id": "31", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "We will see some more examples!" ] }, { "cell_type": "code", "execution_count": null, "id": "32", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "from sympy import *\n", "x, t, z, nu = symbols('x t z nu')" ] }, { "cell_type": "code", "execution_count": null, "id": "33", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "x\n", "t\n", "z" ] }, { "cell_type": "code", "execution_count": null, "id": "34", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "nu" ] }, { "cell_type": "code", "execution_count": null, "id": "35", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "# init_printing(pretty_print=False,use_unicode=True)" ] }, { "cell_type": "code", "execution_count": null, "id": "36", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "diff(sin(x)*exp(x), x)" ] }, { "cell_type": "code", "execution_count": null, "id": "37", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "integrate(exp(x)*sin(x) + exp(x)*cos(x), x)" ] }, { "cell_type": "code", "execution_count": null, "id": "38", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "integrate(sin(x**2), (x, -oo, oo))" ] }, { "cell_type": "code", "execution_count": null, "id": "39", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "limit(sin(x)/x, x, 0)" ] }, { "cell_type": "code", "execution_count": null, "id": "40", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "solve(x**2 - 2, x)" ] }, { "cell_type": "code", "execution_count": null, "id": "41", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "y = Function('y')\n", "dsolve(Eq(y(t).diff(t, t) - y(t), exp(t)), y(t))" ] }, { "cell_type": "code", "execution_count": null, "id": "42", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "Matrix([[1, 2], [2, 2]]).eigenvals()" ] }, { "cell_type": "code", "execution_count": null, "id": "43", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "besselj(nu, z).rewrite(jn)" ] }, { "cell_type": "code", "execution_count": null, "id": "44", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "latex(Integral(cos(x)**2, (x, 0, pi)))" ] }, { "cell_type": "markdown", "id": "45", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "Why two \" \\ \" above???" ] }, { "cell_type": "code", "execution_count": null, "id": "46", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "print(\"\\\\pi\")" ] }, { "cell_type": "code", "execution_count": null, "id": "47", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [ "raises-exception" ] }, "outputs": [], "source": [ "print(\"\\pi\")" ] }, { "cell_type": "markdown", "id": "48", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "Conclusion: needed to change ` \\\\ ` to `\\` manually... For a direct copy-paste into a Markdown cell without manual intervention, unfortunately, there's no automatic way to convert the double backslashes to single backslashes due to the escape character behavior in Python strings and the different contexts in which the LaTeX is rendered (Python string vs. Markdown).\n", "\n", "Consider to create a python function to achieve it!" ] }, { "cell_type": "markdown", "id": "49", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "$\\\\int\\\\limits_{0}^{\\\\pi} \\\\cos^{2}{\\\\left(x \\\\right)}\\\\, dx$" ] }, { "cell_type": "code", "execution_count": null, "id": "50", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "import re\n", "def convert_latex_for_markdown(latex_str):\n", " return re.sub(r'\\\\\\\\', r'\\\\', latex_str)" ] }, { "cell_type": "code", "execution_count": null, "id": "51", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "print(convert_latex_for_markdown(latex(Integral(cos(x)**2, (x, 0, pi)))))" ] }, { "cell_type": "markdown", "id": "52", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "$\\int\\limits_{0}^{\\pi} \\cos^{2}{\\left(x \\right)}\\, dx$" ] }, { "cell_type": "markdown", "id": "53", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "## [Gotchas](https://docs.sympy.org/latest/explanation/gotchas.html) (Working with symbolic expressions in Python)" ] }, { "cell_type": "markdown", "id": "54", "metadata": {}, "source": [ "### Symbols\n" ] }, { "cell_type": "code", "execution_count": null, "id": "55", "metadata": {}, "outputs": [], "source": [ "from sympy import *" ] }, { "cell_type": "code", "execution_count": null, "id": "56", "metadata": {}, "outputs": [], "source": [ "x + 1" ] }, { "cell_type": "markdown", "id": "57", "metadata": {}, "source": [ "If we run in python and not in jupter notebook, it would gives error:\n", "\n", "Traceback (most recent call last):\n", "\n", " File \"\", line 1, in \n", " \n", "NameError: name 'x' is not defined" ] }, { "cell_type": "markdown", "id": "58", "metadata": {}, "source": [ "Naming of symbols!" ] }, { "cell_type": "code", "execution_count": null, "id": "59", "metadata": {}, "outputs": [], "source": [ "x = symbols('x')\n" ] }, { "cell_type": "code", "execution_count": null, "id": "60", "metadata": {}, "outputs": [], "source": [ "x + 1" ] }, { "cell_type": "code", "execution_count": null, "id": "61", "metadata": {}, "outputs": [], "source": [ "x, y, z = symbols('x y z')" ] }, { "cell_type": "code", "execution_count": null, "id": "62", "metadata": {}, "outputs": [], "source": [ "a, b = symbols('b a')" ] }, { "cell_type": "code", "execution_count": null, "id": "63", "metadata": {}, "outputs": [], "source": [ "a" ] }, { "cell_type": "code", "execution_count": null, "id": "64", "metadata": {}, "outputs": [], "source": [ "b" ] }, { "cell_type": "code", "execution_count": null, "id": "65", "metadata": {}, "outputs": [], "source": [ "crazy = symbols('unrelated')\n", "crazy + 1" ] }, { "cell_type": "markdown", "id": "66", "metadata": {}, "source": [ "\"Symbol\": `Sympy` symbol\n", "\n", "\"Variable\": `Python` variable" ] }, { "cell_type": "code", "execution_count": null, "id": "67", "metadata": {}, "outputs": [], "source": [ "x = symbols('x')\n", "expr = x + 1\n", "x = 2\n", "print(expr)" ] }, { "cell_type": "markdown", "id": "68", "metadata": {}, "source": [ "`python` variable changed. But not `sympy` symbol." ] }, { "cell_type": "code", "execution_count": null, "id": "69", "metadata": {}, "outputs": [], "source": [ "x = 'abc'\n", "expr = x + 'def'\n", "expr" ] }, { "cell_type": "code", "execution_count": null, "id": "70", "metadata": {}, "outputs": [], "source": [ "x = 'ABC'\n", "expr" ] }, { "cell_type": "markdown", "id": "71", "metadata": {}, "source": [ "To change the value of a Symbol in an expression, use `subs`:" ] }, { "cell_type": "code", "execution_count": null, "id": "72", "metadata": {}, "outputs": [], "source": [ "x = symbols('x')\n", "expr = x + 1\n", "expr.subs(x, 2)" ] }, { "cell_type": "markdown", "id": "73", "metadata": {}, "source": [ "### Equal signs" ] }, { "cell_type": "code", "execution_count": null, "id": "74", "metadata": {}, "outputs": [], "source": [ "x + 1 == 4" ] }, { "cell_type": "code", "execution_count": null, "id": "75", "metadata": {}, "outputs": [], "source": [ "Eq(x + 1, 4)" ] }, { "cell_type": "code", "execution_count": null, "id": "76", "metadata": {}, "outputs": [], "source": [ "(x + 1)**2 == x**2 + 2*x + 1" ] }, { "cell_type": "markdown", "id": "77", "metadata": {}, "source": [ "\"==\" only equals in \"exact structure! It is for structural equality.\n", "\n", "Not for symbolic equality and mathematical equality." ] }, { "cell_type": "markdown", "id": "78", "metadata": {}, "source": [ "recall that if $a = b$, then $a - b = 0$\n", "\n", "If two symbolic expressions are identically equal. " ] }, { "cell_type": "markdown", "id": "79", "metadata": {}, "source": [ "`simplify`" ] }, { "cell_type": "code", "execution_count": null, "id": "80", "metadata": {}, "outputs": [], "source": [ "a = (x + 1)**2\n", "b = x**2 + 2*x + 1\n", "simplify(a - b)\n" ] }, { "cell_type": "code", "execution_count": null, "id": "81", "metadata": {}, "outputs": [], "source": [ "c = x**2 - 2*x + 1\n", "simplify(a - c)" ] }, { "cell_type": "markdown", "id": "82", "metadata": {}, "source": [ "`equals`: evaluating them numerically at random points." ] }, { "cell_type": "code", "execution_count": null, "id": "83", "metadata": {}, "outputs": [], "source": [ "a = cos(x)**2 - sin(x)**2\n", "b = cos(2*x)\n", "a.equals(b)" ] }, { "cell_type": "markdown", "id": "84", "metadata": {}, "source": [ "### ^ and /" ] }, { "cell_type": "markdown", "id": "85", "metadata": {}, "source": [ "^ represent logical exclusive OR, XOR in `Python`" ] }, { "cell_type": "code", "execution_count": null, "id": "86", "metadata": {}, "outputs": [], "source": [ "True ^ False\n" ] }, { "cell_type": "code", "execution_count": null, "id": "87", "metadata": {}, "outputs": [], "source": [ "True ^ True\n" ] }, { "cell_type": "code", "execution_count": null, "id": "88", "metadata": {}, "outputs": [], "source": [ "False ^ False" ] }, { "cell_type": "code", "execution_count": null, "id": "89", "metadata": {}, "outputs": [], "source": [ "Xor(x, y)" ] }, { "cell_type": "markdown", "id": "90", "metadata": {}, "source": [ "`Sympy` objects and `Python` objects" ] }, { "cell_type": "code", "execution_count": null, "id": "91", "metadata": {}, "outputs": [], "source": [ "type(Integer(1) + 1)\n" ] }, { "cell_type": "code", "execution_count": null, "id": "92", "metadata": {}, "outputs": [], "source": [ "type(1 + 1)" ] }, { "cell_type": "markdown", "id": "93", "metadata": {}, "source": [ "Division in `sympy` gives rational" ] }, { "cell_type": "code", "execution_count": null, "id": "94", "metadata": {}, "outputs": [], "source": [ "Integer(1)/Integer(3)\n" ] }, { "cell_type": "code", "execution_count": null, "id": "95", "metadata": {}, "outputs": [], "source": [ "type(Integer(1)/Integer(3))" ] }, { "cell_type": "code", "execution_count": null, "id": "96", "metadata": {}, "outputs": [], "source": [ "from __future__ import division\n", "1/2" ] }, { "cell_type": "code", "execution_count": null, "id": "97", "metadata": {}, "outputs": [], "source": [ "Rational(1, 2)" ] }, { "cell_type": "code", "execution_count": null, "id": "98", "metadata": {}, "outputs": [], "source": [ "x + 1/2" ] }, { "cell_type": "code", "execution_count": null, "id": "99", "metadata": {}, "outputs": [], "source": [ "x + Rational(1, 2)" ] }, { "cell_type": "markdown", "id": "100", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "## [Lambdify](https://docs.sympy.org/latest/modules/utilities/lambdify.html) (Lambdification to numerical functions)" ] }, { "cell_type": "markdown", "id": "101", "metadata": {}, "source": [ "forwards" ] }, { "cell_type": "code", "execution_count": null, "id": "102", "metadata": {}, "outputs": [], "source": [ "import numpy \n", "a = numpy.arange(10) \n", "expr = sin(x)\n", "f = lambdify(x, expr, \"numpy\") \n", "f(a) " ] }, { "cell_type": "code", "execution_count": null, "id": "103", "metadata": {}, "outputs": [], "source": [ "f = lambdify(x, expr, \"math\")\n", "f(0.1)" ] }, { "cell_type": "code", "execution_count": null, "id": "104", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "def mysin(x):\n", " \"\"\"\n", " My sine. Note that this is only accurate for small x.\n", " \"\"\"\n", " return x\n", "f = lambdify(x, cos(x)*sin(x), {\"sin\":mysin,\"cos\":mysin})\n", "f(0.1)" ] }, { "cell_type": "code", "execution_count": null, "id": "105", "metadata": {}, "outputs": [], "source": [ "0.1+0.2" ] }, { "cell_type": "code", "execution_count": null, "id": "106", "metadata": {}, "outputs": [], "source": [ "import inspect\n", "\n", "print(inspect.getsource(f))" ] }, { "cell_type": "code", "execution_count": null, "id": "107", "metadata": {}, "outputs": [], "source": [ "sympy.print_tree(expr)" ] }, { "cell_type": "code", "execution_count": null, "id": "108", "metadata": {}, "outputs": [], "source": [ "f(0.5)" ] }, { "cell_type": "code", "execution_count": null, "id": "109", "metadata": {}, "outputs": [], "source": [ "sin(0.5)" ] }, { "cell_type": "code", "execution_count": null, "id": "110", "metadata": {}, "outputs": [], "source": [ "type(sympy.sin)" ] }, { "cell_type": "code", "execution_count": null, "id": "111", "metadata": {}, "outputs": [], "source": [ "type(sin)" ] }, { "cell_type": "markdown", "id": "112", "metadata": {}, "source": [ "This module provides convenient functions to transform SymPy expressions to lambda functions which can be used to calculate numerical values very fast." ] }, { "cell_type": "code", "execution_count": null, "id": "113", "metadata": {}, "outputs": [], "source": [ "from sympy.abc import x\n", "from sympy.utilities.lambdify import implemented_function\n", "from sympy import lambdify\n", "f = implemented_function('f', lambda x: x+1)\n", "lam_f = lambdify(x, f(x))\n", "lam_f(4)" ] }, { "cell_type": "code", "execution_count": null, "id": "114", "metadata": {}, "outputs": [], "source": [ "from sympy.abc import x, y, z\n", "from sympy.utilities.lambdify import lambdastr\n", "lambdastr(x, x**2)\n", "lambdastr((x,y,z), [z,y,x])" ] }, { "cell_type": "code", "execution_count": null, "id": "115", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ "lambdastr((x, (y, z)), x + y)" ] }, { "cell_type": "code", "execution_count": null, "id": "116", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "117", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "## [Codegen](https://docs.sympy.org/latest/modules/codegen.html) (Code generation: the principle behind lambdification)" ] }, { "cell_type": "markdown", "id": "118", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "See [here](https://docs.sympy.org/latest/modules/codegen.html)." ] }, { "cell_type": "code", "execution_count": null, "id": "119", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.8" } }, "nbformat": 4, "nbformat_minor": 5 }