# SymPy: Open Source Symbolic Mathematics

This notebook uses the [SymPy](http://sympy.org) package to perform symbolic manipulations,
and combined with numpy and matplotlib, also displays numerical visualizations of symbolically
constructed expressions.

We first load sympy printing extensions, as well as all of sympy:


```python
from IPython.display import display

from sympy.interactive import printing
printing.init_printing(use_latex='mathjax')

import sympy as sym
x, y, z = sym.symbols("x y z")
k, m, n = sym.symbols("k m n", integer=True)
f, g, h = map(sym.Function, 'fgh')
```

<h2>Elementary operations</h2>


```python
sym.Rational(3,2)*sym.pi + sym.exp(sym.I*x) / (x**2 + y)
```


```python
sym.exp(sym.I*x).subs(x,sym.pi).evalf()
```


```python
e = x + 2*y
```


```python
sym.srepr(e)
```


```python
sym.exp(sym.pi * sym.sqrt(163)).evalf(50)
```

<h2>Algebra<h2>


```python
eq = ((x+y)**2 * (x+1))
eq
```


```python
sym.expand(eq)
```


```python
a = 1/x + (x*sym.sin(x) - 1)/x
a
```


```python
sym.simplify(a)
```


```python
eq = sym.Eq(x**3 + 2*x**2 + 4*x + 8, 0)
eq
```


```python
sym.solve(eq, x)
```


```python
a, b = sym.symbols('a b')
sym.Sum(6*n**2 + 2**n, (n, a, b))
```

<h2>Calculus</h2>


```python
sym.limit((sym.sin(x)-x)/x**3, x, 0)
```


```python
(1/sym.cos(x)).series(x, 0, 6)
```


```python
sym.diff(sym.cos(x**2)**2 / (1+x), x)
```


```python
sym.integrate(x**2 * sym.cos(x), (x, 0, sym.pi/2))
```


```python
eqn = sym.Eq(sym.Derivative(f(x),x,x) + 9*f(x), 1)
display(eqn)
sym.dsolve(eqn, f(x))
```

# Illustrating Taylor series

We will define a function to compute the Taylor series expansions of a symbolically defined expression at
various orders and visualize all the approximations together with the original function


```python
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
```


```python
# You can change the default figure size to be a bit larger if you want,
# uncomment the next line for that:
#plt.rc('figure', figsize=(10, 6))
```


```python
def plot_taylor_approximations(func, x0=None, orders=(2, 4), xrange=(0,1), yrange=None, npts=200):
    """Plot the Taylor series approximations to a function at various orders.

    Parameters
    ----------
    func : a sympy function
    x0 : float
      Origin of the Taylor series expansion.  If not given, x0=xrange[0].
    orders : list
      List of integers with the orders of Taylor series to show.  Default is (2, 4).
    xrange : 2-tuple or array.
      Either an (xmin, xmax) tuple indicating the x range for the plot (default is (0, 1)),
      or the actual array of values to use.
    yrange : 2-tuple
      (ymin, ymax) tuple indicating the y range for the plot.  If not given,
      the full range of values will be automatically used. 
    npts : int
      Number of points to sample the x range with.  Default is 200.
    """
    if not callable(func):
        raise ValueError('func must be callable')
    if isinstance(xrange, (list, tuple)):
        x = np.linspace(float(xrange[0]), float(xrange[1]), npts)
    else:
        x = xrange
    if x0 is None: x0 = x[0]
    xs = sym.Symbol('x')
    # Make a numpy-callable form of the original function for plotting
    fx = func(xs)
    f = sym.lambdify(xs, fx, modules=['numpy'])
    # We could use latex(fx) instead of str(), but matploblib gets confused
    # with some of the (valid) latex constructs sympy emits.  So we play it safe.
    plt.plot(x, f(x), label=str(fx), lw=2)
    # Build the Taylor approximations, plotting as we go
    apps = {}
    for order in orders:
        app = fx.series(xs, x0, n=order).removeO()
        apps[order] = app
        # Must be careful here: if the approximation is a constant, we can't
        # blindly use lambdify as it won't do the right thing.  In that case, 
        # evaluate the number as a float and fill the y array with that value.
        if isinstance(app, sym.numbers.Number):
            y = np.zeros_like(x)
            y.fill(app.evalf())
        else:
            fa = sym.lambdify(xs, app, modules=['numpy'])
            y = fa(x)
        tex = sym.latex(app).replace('$', '')
        plt.plot(x, y, label=r'$n=%s:\, %s$' % (order, tex) )
        
    # Plot refinements
    if yrange is not None:
        plt.ylim(*yrange)
    plt.grid()
    plt.legend(loc='best').get_frame().set_alpha(0.8)
```

With this function defined, we can now use it for any sympy function or expression


```python
plot_taylor_approximations(sym.sin, 0, [2, 4, 6], (0, 2*sym.pi), (-2,2))
```


```python
plot_taylor_approximations(sym.cos, 0, [2, 4, 6], (0, 2*sym.pi), (-2,2))
```

This shows easily how a Taylor series is useless beyond its convergence radius, illustrated by 
a simple function that has singularities on the real axis:


```python
# For an expression made from elementary functions, we must first make it into
# a callable function, the simplest way is to use the Python lambda construct.
plot_taylor_approximations(lambda x: 1/sym.cos(x), 0, [2,4,6], (0, 2*sym.pi), (-5,5))
```


```python

```

b2c2e53d9e6b8fc1c31f5d91fa5f02882881be63
ipynb
Jupyter Notebook
001-Jupyter/001-Tutorials/003-IPython-in-Depth/examples/IPython Kernel/SymPy.ipynb
jhgoebbert/jupyter-jsc-notebooks
bcd08ced04db00e7a66473b146f8f31f2e657539
BSD-3-Clause
001-Jupyter/001-Tutorials/003-IPython-in-Depth/examples/IPython Kernel/SymPy.ipynb
jhgoebbert/jupyter-jsc-notebooks
bcd08ced04db00e7a66473b146f8f31f2e657539
BSD-3-Clause
001-Jupyter/001-Tutorials/003-IPython-in-Depth/examples/IPython Kernel/SymPy.ipynb
jhgoebbert/jupyter-jsc-notebooks
bcd08ced04db00e7a66473b146f8f31f2e657539
BSD-3-Clause
2022-01-13T18:49:12.000Z
2022-01-13T18:49:12.000Z
Qwen/Qwen-72B
1. YES
2. YES