<jupyter_start><jupyter_text>SymPy: Open Source Symbolic MathematicsThis notebook uses the [SymPy](http://sympy.org) package to perform symbolic manipulations,and combined with numpy and matplotlib, also displays numerical visualizations of symbolicallyconstructed expressions.We first load sympy printing extensions, as well as all of sympy:<jupyter_code>from IPython.display import display

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

from __future__ import division
import sympy as sym
from sympy import *
x, y, z = symbols("x y z")
k, m, n = symbols("k m n", integer=True)
f, g, h = map(Function, 'fgh')<jupyter_output><empty_output><jupyter_text>Elementary operations<jupyter_code>Rational(3,2)*pi + exp(I*x) / (x**2 + y)
exp(I*x).subs(x,pi).evalf()
e = x + 2*y
srepr(e)
exp(pi * sqrt(163)).evalf(50)<jupyter_output><empty_output><jupyter_text>Algebra<jupyter_code>eq = ((x+y)**2 * (x+1))
eq
expand(eq)
a = 1/x + (x*sin(x) - 1)/x
a
simplify(a)
eq = Eq(x**3 + 2*x**2 + 4*x + 8, 0)
eq
solve(eq, x)
a, b = symbols('a b')
Sum(6*n**2 + 2**n, (n, a, b))<jupyter_output><empty_output><jupyter_text>Calculus<jupyter_code>limit((sin(x)-x)/x**3, x, 0)
(1/cos(x)).series(x, 0, 6)
diff(cos(x**2)**2 / (1+x), x)
integrate(x**2 * cos(x), (x, 0, pi/2))
eqn = Eq(Derivative(f(x),x,x) + 9*f(x), 1)
display(eqn)
dsolve(eqn, f(x))<jupyter_output><empty_output><jupyter_text>Illustrating Taylor seriesWe will define a function to compute the Taylor series expansions of a symbolically defined expression atvarious orders and visualize all the approximations together with the original function<jupyter_code>%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
# 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))
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)<jupyter_output><empty_output><jupyter_text>With this function defined, we can now use it for any sympy function or expression<jupyter_code>plot_taylor_approximations(sin, 0, [2, 4, 6], (0, 2*pi), (-2,2))
plot_taylor_approximations(cos, 0, [2, 4, 6], (0, 2*pi), (-2,2))<jupyter_output><empty_output><jupyter_text>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:<jupyter_code># 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/cos(x), 0, [2,4,6], (0, 2*pi), (-5,5))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12670327435428105, 'fraction_numerical': 0.018710595891803947, 'mean_word_length': 3.793372319688109, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '292772', 'license': 'BSD-2-Clause', 'n_tokens_mistral': 1752, 'n_tokens_neox': 1678, 'n_words': 562, 'path': 'example/source/SymPy.ipynb', 'repo_name': 'jtpavlock/RunNotebook', 'size': '4917'}