# Introduction to sympy

A Python library for symbolic computations

<h1>Table of Contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Python-set-up" data-toc-modified-id="Python-set-up-1"><span class="toc-item-num">1&nbsp;&nbsp;</span>Python set-up</a></span></li><li><span><a href="#Numbers" data-toc-modified-id="Numbers-2"><span class="toc-item-num">2&nbsp;&nbsp;</span>Numbers</a></span><ul class="toc-item"><li><span><a href="#Integers" data-toc-modified-id="Integers-2.1"><span class="toc-item-num">2.1&nbsp;&nbsp;</span>Integers</a></span></li><li><span><a href="#Floats-or-Reals" data-toc-modified-id="Floats-or-Reals-2.2"><span class="toc-item-num">2.2&nbsp;&nbsp;</span>Floats or Reals</a></span></li><li><span><a href="#Rationals-or-Fractions" data-toc-modified-id="Rationals-or-Fractions-2.3"><span class="toc-item-num">2.3&nbsp;&nbsp;</span>Rationals or Fractions</a></span></li><li><span><a href="#Surds" data-toc-modified-id="Surds-2.4"><span class="toc-item-num">2.4&nbsp;&nbsp;</span>Surds</a></span></li><li><span><a href="#Useful-constants" data-toc-modified-id="Useful-constants-2.5"><span class="toc-item-num">2.5&nbsp;&nbsp;</span>Useful constants</a></span></li><li><span><a href="#Complex-numbers" data-toc-modified-id="Complex-numbers-2.6"><span class="toc-item-num">2.6&nbsp;&nbsp;</span>Complex numbers</a></span></li><li><span><a href="#Miscellaneous" data-toc-modified-id="Miscellaneous-2.7"><span class="toc-item-num">2.7&nbsp;&nbsp;</span>Miscellaneous</a></span></li><li><span><a href="#Be-a-little-careful-when-dividing-by-zero-and-of-arithmetic-with-infinities" data-toc-modified-id="Be-a-little-careful-when-dividing-by-zero-and-of-arithmetic-with-infinities-2.8"><span class="toc-item-num">2.8&nbsp;&nbsp;</span>Be a little careful when dividing by zero and of arithmetic with infinities</a></span></li></ul></li><li><span><a href="#Symbols" data-toc-modified-id="Symbols-3"><span class="toc-item-num">3&nbsp;&nbsp;</span>Symbols</a></span><ul class="toc-item"><li><span><a href="#Import-symbols-from-sympy.abc" data-toc-modified-id="Import-symbols-from-sympy.abc-3.1"><span class="toc-item-num">3.1&nbsp;&nbsp;</span>Import symbols from sympy.abc</a></span></li><li><span><a href="#Define--one-symbol-at-a-time" data-toc-modified-id="Define--one-symbol-at-a-time-3.2"><span class="toc-item-num">3.2&nbsp;&nbsp;</span>Define  one symbol at a time</a></span></li><li><span><a href="#Define-multiple-symbols-in-one-line-of-code" data-toc-modified-id="Define-multiple-symbols-in-one-line-of-code-3.3"><span class="toc-item-num">3.3&nbsp;&nbsp;</span>Define multiple symbols in one line of code</a></span></li><li><span><a href="#Set-the-attributes-of-a-symbol" data-toc-modified-id="Set-the-attributes-of-a-symbol-3.4"><span class="toc-item-num">3.4&nbsp;&nbsp;</span>Set the attributes of a symbol</a></span></li><li><span><a href="#Check-the-assumptions/properties-of-a-symbol" data-toc-modified-id="Check-the-assumptions/properties-of-a-symbol-3.5"><span class="toc-item-num">3.5&nbsp;&nbsp;</span>Check the assumptions/properties of a symbol</a></span></li><li><span><a href="#Symbolic-functions" data-toc-modified-id="Symbolic-functions-3.6"><span class="toc-item-num">3.6&nbsp;&nbsp;</span>Symbolic functions</a></span></li></ul></li><li><span><a href="#Functions" data-toc-modified-id="Functions-4"><span class="toc-item-num">4&nbsp;&nbsp;</span>Functions</a></span><ul class="toc-item"><li><span><a href="#In-line-arithmetic" data-toc-modified-id="In-line-arithmetic-4.1"><span class="toc-item-num">4.1&nbsp;&nbsp;</span>In-line arithmetic</a></span></li><li><span><a href="#Absolute-Values" data-toc-modified-id="Absolute-Values-4.2"><span class="toc-item-num">4.2&nbsp;&nbsp;</span>Absolute Values</a></span></li><li><span><a href="#Factorials" data-toc-modified-id="Factorials-4.3"><span class="toc-item-num">4.3&nbsp;&nbsp;</span>Factorials</a></span></li><li><span><a href="#Trig-functions" data-toc-modified-id="Trig-functions-4.4"><span class="toc-item-num">4.4&nbsp;&nbsp;</span>Trig functions</a></span></li><li><span><a href="#Exponential-and-logarithmic-functions" data-toc-modified-id="Exponential-and-logarithmic-functions-4.5"><span class="toc-item-num">4.5&nbsp;&nbsp;</span>Exponential and logarithmic functions</a></span></li></ul></li><li><span><a href="#Expressions" data-toc-modified-id="Expressions-5"><span class="toc-item-num">5&nbsp;&nbsp;</span>Expressions</a></span><ul class="toc-item"><li><span><a href="#Creating-an-expression" data-toc-modified-id="Creating-an-expression-5.1"><span class="toc-item-num">5.1&nbsp;&nbsp;</span>Creating an expression</a></span></li><li><span><a href="#Creating-expressions-from-strings" data-toc-modified-id="Creating-expressions-from-strings-5.2"><span class="toc-item-num">5.2&nbsp;&nbsp;</span>Creating expressions from strings</a></span></li><li><span><a href="#Substituting-values-into-an-expression" data-toc-modified-id="Substituting-values-into-an-expression-5.3"><span class="toc-item-num">5.3&nbsp;&nbsp;</span>Substituting values into an expression</a></span></li><li><span><a href="#Simplifying-expressions" data-toc-modified-id="Simplifying-expressions-5.4"><span class="toc-item-num">5.4&nbsp;&nbsp;</span>Simplifying expressions</a></span><ul class="toc-item"><li><span><a href="#Finding-factors" data-toc-modified-id="Finding-factors-5.4.1"><span class="toc-item-num">5.4.1&nbsp;&nbsp;</span>Finding factors</a></span></li><li><span><a href="#Expanding-out" data-toc-modified-id="Expanding-out-5.4.2"><span class="toc-item-num">5.4.2&nbsp;&nbsp;</span>Expanding out</a></span></li><li><span><a href="#Collecting-terms" data-toc-modified-id="Collecting-terms-5.4.3"><span class="toc-item-num">5.4.3&nbsp;&nbsp;</span>Collecting terms</a></span></li><li><span><a href="#Canceling-common-factors,-expressing-as-$\frac{p}{q}$" data-toc-modified-id="Canceling-common-factors,-expressing-as-$\frac{p}{q}$-5.4.4"><span class="toc-item-num">5.4.4&nbsp;&nbsp;</span>Canceling common factors, expressing as $\frac{p}{q}$</a></span></li><li><span><a href="#Trig-simplification" data-toc-modified-id="Trig-simplification-5.4.5"><span class="toc-item-num">5.4.5&nbsp;&nbsp;</span>Trig simplification</a></span></li><li><span><a href="#Trig-expansions" data-toc-modified-id="Trig-expansions-5.4.6"><span class="toc-item-num">5.4.6&nbsp;&nbsp;</span>Trig expansions</a></span></li><li><span><a href="#Power-simplifications" data-toc-modified-id="Power-simplifications-5.4.7"><span class="toc-item-num">5.4.7&nbsp;&nbsp;</span>Power simplifications</a></span></li><li><span><a href="#Log-simplifications" data-toc-modified-id="Log-simplifications-5.4.8"><span class="toc-item-num">5.4.8&nbsp;&nbsp;</span>Log simplifications</a></span></li><li><span><a href="#Rewriting-functions" data-toc-modified-id="Rewriting-functions-5.4.9"><span class="toc-item-num">5.4.9&nbsp;&nbsp;</span>Rewriting functions</a></span></li></ul></li><li><span><a href="#Solving-expressions" data-toc-modified-id="Solving-expressions-5.5"><span class="toc-item-num">5.5&nbsp;&nbsp;</span>Solving expressions</a></span><ul class="toc-item"><li><span><a href="#Example-quadratic-solution" data-toc-modified-id="Example-quadratic-solution-5.5.1"><span class="toc-item-num">5.5.1&nbsp;&nbsp;</span>Example quadratic solution</a></span></li><li><span><a href="#Generalised-quadratic-solution" data-toc-modified-id="Generalised-quadratic-solution-5.5.2"><span class="toc-item-num">5.5.2&nbsp;&nbsp;</span>Generalised quadratic solution</a></span></li><li><span><a href="#Quadratic-with-a-complex-solution" data-toc-modified-id="Quadratic-with-a-complex-solution-5.5.3"><span class="toc-item-num">5.5.3&nbsp;&nbsp;</span>Quadratic with a complex solution</a></span></li><li><span><a href="#Manipulating-expressions-to-re-arrange-terms" data-toc-modified-id="Manipulating-expressions-to-re-arrange-terms-5.5.4"><span class="toc-item-num">5.5.4&nbsp;&nbsp;</span>Manipulating expressions to re-arrange terms</a></span></li></ul></li><li><span><a href="#Plotting-expressions" data-toc-modified-id="Plotting-expressions-5.6"><span class="toc-item-num">5.6&nbsp;&nbsp;</span>Plotting expressions</a></span></li></ul></li><li><span><a href="#Equations" data-toc-modified-id="Equations-6"><span class="toc-item-num">6&nbsp;&nbsp;</span>Equations</a></span><ul class="toc-item"><li><span><a href="#Creating-equations" data-toc-modified-id="Creating-equations-6.1"><span class="toc-item-num">6.1&nbsp;&nbsp;</span>Creating equations</a></span></li><li><span><a href="#Solving-equations" data-toc-modified-id="Solving-equations-6.2"><span class="toc-item-num">6.2&nbsp;&nbsp;</span>Solving equations</a></span><ul class="toc-item"><li><span><a href="#Rearranging-terms" data-toc-modified-id="Rearranging-terms-6.2.1"><span class="toc-item-num">6.2.1&nbsp;&nbsp;</span>Rearranging terms</a></span></li><li><span><a href="#Exponential-example" data-toc-modified-id="Exponential-example-6.2.2"><span class="toc-item-num">6.2.2&nbsp;&nbsp;</span>Exponential example</a></span></li><li><span><a href="#Quadratic-example" data-toc-modified-id="Quadratic-example-6.2.3"><span class="toc-item-num">6.2.3&nbsp;&nbsp;</span>Quadratic example</a></span></li><li><span><a href="#A-trigonometric-example" data-toc-modified-id="A-trigonometric-example-6.2.4"><span class="toc-item-num">6.2.4&nbsp;&nbsp;</span>A trigonometric example</a></span></li></ul></li><li><span><a href="#Solving-systems-of-equations" data-toc-modified-id="Solving-systems-of-equations-6.3"><span class="toc-item-num">6.3&nbsp;&nbsp;</span>Solving systems of equations</a></span><ul class="toc-item"><li><span><a href="#Two-linear-equations" data-toc-modified-id="Two-linear-equations-6.3.1"><span class="toc-item-num">6.3.1&nbsp;&nbsp;</span>Two linear equations</a></span></li><li><span><a href="#A-linear-and-cubic-system-with-three-point-solutions" data-toc-modified-id="A-linear-and-cubic-system-with-three-point-solutions-6.3.2"><span class="toc-item-num">6.3.2&nbsp;&nbsp;</span>A linear and cubic system with three point-solutions</a></span></li><li><span><a href="#A-system-of-equations-with-no-solutions" data-toc-modified-id="A-system-of-equations-with-no-solutions-6.3.3"><span class="toc-item-num">6.3.3&nbsp;&nbsp;</span>A system of equations with no solutions</a></span></li></ul></li></ul></li><li><span><a href="#Limits" data-toc-modified-id="Limits-7"><span class="toc-item-num">7&nbsp;&nbsp;</span>Limits</a></span><ul class="toc-item"><li><span><a href="#Simple-example" data-toc-modified-id="Simple-example-7.1"><span class="toc-item-num">7.1&nbsp;&nbsp;</span>Simple example</a></span></li><li><span><a href="#More-complicated-examples" data-toc-modified-id="More-complicated-examples-7.2"><span class="toc-item-num">7.2&nbsp;&nbsp;</span>More complicated examples</a></span><ul class="toc-item"><li><span><a href="#$f(x)-=-x^n$" data-toc-modified-id="$f(x)-=-x^n$-7.2.1"><span class="toc-item-num">7.2.1&nbsp;&nbsp;</span>$f(x) = x^n$</a></span></li><li><span><a href="#$f(x)=a^x$" data-toc-modified-id="$f(x)=a^x$-7.2.2"><span class="toc-item-num">7.2.2&nbsp;&nbsp;</span>$f(x)=a^x$</a></span></li><li><span><a href="#$f(x)=sin(x)$" data-toc-modified-id="$f(x)=sin(x)$-7.2.3"><span class="toc-item-num">7.2.3&nbsp;&nbsp;</span>$f(x)=sin(x)$</a></span></li></ul></li><li><span><a href="#Limits,-where-the-direction-in-which-we-approach-the-limit-is-important" data-toc-modified-id="Limits,-where-the-direction-in-which-we-approach-the-limit-is-important-7.3"><span class="toc-item-num">7.3&nbsp;&nbsp;</span>Limits, where the direction in which we approach the limit is important</a></span></li></ul></li><li><span><a href="#Derivatives" data-toc-modified-id="Derivatives-8"><span class="toc-item-num">8&nbsp;&nbsp;</span>Derivatives</a></span><ul class="toc-item"><li><span><a href="#First,-second-and-subsequent-derivatives" data-toc-modified-id="First,-second-and-subsequent-derivatives-8.1"><span class="toc-item-num">8.1&nbsp;&nbsp;</span>First, second and subsequent derivatives</a></span></li><li><span><a href="#Partial-derivatives" data-toc-modified-id="Partial-derivatives-8.2"><span class="toc-item-num">8.2&nbsp;&nbsp;</span>Partial derivatives</a></span></li></ul></li><li><span><a href="#Integrals" data-toc-modified-id="Integrals-9"><span class="toc-item-num">9&nbsp;&nbsp;</span>Integrals</a></span><ul class="toc-item"><li><span><a href="#Definite-Integrals" data-toc-modified-id="Definite-Integrals-9.1"><span class="toc-item-num">9.1&nbsp;&nbsp;</span>Definite Integrals</a></span></li><li><span><a href="#Indefinite-integrals" data-toc-modified-id="Indefinite-integrals-9.2"><span class="toc-item-num">9.2&nbsp;&nbsp;</span>Indefinite integrals</a></span></li><li><span><a href="#sympy-cannot-evaluate-some-integrals" data-toc-modified-id="sympy-cannot-evaluate-some-integrals-9.3"><span class="toc-item-num">9.3&nbsp;&nbsp;</span>sympy cannot evaluate some integrals</a></span></li></ul></li><li><span><a href="#Sums" data-toc-modified-id="Sums-10"><span class="toc-item-num">10&nbsp;&nbsp;</span>Sums</a></span><ul class="toc-item"><li><span><a href="#Infinite-sums" data-toc-modified-id="Infinite-sums-10.1"><span class="toc-item-num">10.1&nbsp;&nbsp;</span>Infinite sums</a></span></li><li><span><a href="#Finite-sums" data-toc-modified-id="Finite-sums-10.2"><span class="toc-item-num">10.2&nbsp;&nbsp;</span>Finite sums</a></span></li></ul></li><li><span><a href="#Taylor-series-expansion" data-toc-modified-id="Taylor-series-expansion-11"><span class="toc-item-num">11&nbsp;&nbsp;</span>Taylor series expansion</a></span><ul class="toc-item"><li><span><a href="#A-finite-Taylor-series" data-toc-modified-id="A-finite-Taylor-series-11.1"><span class="toc-item-num">11.1&nbsp;&nbsp;</span>A finite Taylor series</a></span></li><li><span><a href="#Infinite-Taylor-series" data-toc-modified-id="Infinite-Taylor-series-11.2"><span class="toc-item-num">11.2&nbsp;&nbsp;</span>Infinite Taylor series</a></span></li></ul></li><li><span><a href="#Matrices-/-Linear-Algebra" data-toc-modified-id="Matrices-/-Linear-Algebra-12"><span class="toc-item-num">12&nbsp;&nbsp;</span>Matrices / Linear Algebra</a></span></li><li><span><a href="#The-End" data-toc-modified-id="The-End-13"><span class="toc-item-num">13&nbsp;&nbsp;</span>The End</a></span></li></ul></div>

## Python set-up

Install with pip or conda (as appropriate to your system)


```python
from platform import python_version
python_version() # version of python on my machine
```




    '3.9.7'




```python
import sympy as sp
sp.__version__ # version of sympy on my machine
```




    '1.9'




```python
# This makes the notebook easier to read ...
sp.init_printing(use_unicode=True)
```

## Numbers

### Integers


```python
sp.Integer(5) # this is a sympy integer
```

### Floats or Reals


```python
sp.Float(1 / 2) # this is a sympy float
```

### Rationals or Fractions

Hint: using Rationals in calculus should be preferred over using floats, as it will yield easire to understand symbolic answers.


```python
y = sp.Rational(1, 3) # this is a sympy Rational
y
```


```python
# get the numeric value for an expression to n decimal places
y.n(22)
```


```python
# we can do the usual maths with Rationals
sp.Rational(3, 4) + sp.Rational(1, 3)
```


```python
# Note: if we divide sympy Integers, we also get a Rational
sp.Integer(1) / sp.Integer(4)
```


```python
# We get a sympy Rational even when one of the numerator or denominator is a python integer.
sp.Integer(5) / 2
```


```python
# getting the numerator and denominator
numerator, denominator = sp.fraction(sp.Rational(-55, 10))
numerator, denominator
```


```python
# or ...
r = sp.Rational(-55, 10)
numerator = r.numerator
denominator = r.denominator
numerator, denominator
```


```python
# It is a little challenging to represent an improper Rational
# as a mixed fraction or mixed numer (whole number plus fraction)

def mixed_number(rational: sp.Rational):
    numerator, denominator = sp.fraction(rational)
    whole = sp.Abs(numerator) // sp.Abs(denominator)
    part = (
        sp.Rational(sp.Abs(numerator) % sp.Abs(denominator), 
                    sp.Abs(denominator))
    )
    with sp.evaluate(False):
        # Use the context manager to avoid simplification back to
        # a Rational. And make sure we have the correct sign ...
        mixed_number = whole + part if rational >= 0 else (- whole - part)
    return mixed_number

mixed_number(sp.Rational(-55, 10))
```


```python
_.n()
```

### Surds


```python
sp.sqrt(8) 
# Note, surds are automatically simplified if possible
```


```python
# if you don't want the simplification
sp.sqrt(8, evaluate=False) 
```


```python
# or you can use this context manager to avoid evaluation
with sp.evaluate(False):
    y = sp.sqrt(8)
y
```


```python
sp.N(_) # numberic value for the last calculation
```


```python
sp.cbrt(3) # cube roots
```


```python
sp.real_root(4, 6) # nth real root
```


```python
# Use a context manager to prevent auto-simplification
with sp.evaluate(False):
    t = sp.Integer(-2) ** sp.Rational(-1, 2)
t
```


```python
# same as previous cell with simplification 
1 / sp.sqrt(-2) 
```

### Useful constants

Remember, these constants are symbols, not their approximate values


```python
sp.pi # use sp.pi for 𝜋
```


```python
sp.E # capital E for the base of the natural logarithm (Euler's number)
```


```python
sp.I # capital I for the square root of -1
```


```python
sp.I ** 2
```


```python
sp.oo # oo (two lower-case letters o) for infinity
```


```python
-sp.oo # negative infinity
```


```python
# This is the "not a number" construct for sympy
sp.nan # in a result, this typically means undefined ...
```

### Complex numbers


```python
z = 3 + 4 * sp.I # Construct complex numbers
z
```


```python
sp.re(z), sp.im(z) # get the real and imaginary parts of z
```


```python
sp.Abs(z) # the Absolute value of a complex number
          # It's distance from the origin on the Argand plane
```


```python
# To obtain the complex conjugate 
t = sp.conjugate(4 + 5j) # from a python complex number (ugly)
s = (4 + 5 * sp.I).conjugate() # from a sympy complex number (better)
display(t, s)
```

### Miscellaneous 


```python
sp.prime(5) # get the nth prime number
```


```python
sp.pi.evalf(5) # evaluate to a python floating with n decimal places
```

### Be a little careful when dividing by zero and of arithmetic with infinities

The results may differ with your expectations


```python
# This is undefined ...
sp.oo - sp.oo
```


```python
# This is also undefined ...
sp.Integer(0) / sp.Integer(0)
```


```python
# I would have pegged this one as undefined
# or as complex infinity. But not as real infinity???
sp.oo / 0
```


```python
sp.Rational(1, 0) # yields complex infinity
```


```python
sp.Integer(1) / sp.Integer(0) # Also yeilds complex infinity
```

## Symbols

You must define symbols before using them with sympy. 

To avoid confusion, match the name of the symbol to the python variable name.

There are a number of ways to create a sympy symbol ...

### Import symbols from sympy.abc


```python
# The quick and easy way to get English and Greek letter names
from sympy.abc import a, b, c, x, n, alpha, beta, gamma, delta
alpha
```


```python
delta
```

### Define  one symbol at a time


```python
a = sp.Symbol('a') # defining a symbol, one at a time
```

### Define multiple symbols in one line of code


```python
x, y, z = sp.symbols('x y z') # define multiple symbols at a time
```

### Set the attributes of a symbol


```python
# you can set attributes for a symbol
i, j, k = sp.symbols('i, j, k', integer=True, positive=True)
```

### Check the assumptions/properties of a symbol


```python
i.assumptions0
```




    {'integer': True,
     'commutative': True,
     'complex': True,
     'extended_real': True,
     'finite': True,
     'infinite': False,
     'rational': True,
     'irrational': False,
     'noninteger': False,
     'algebraic': True,
     'imaginary': False,
     'hermitian': True,
     'transcendental': False,
     'real': True,
     'positive': True,
     'extended_negative': False,
     'nonnegative': True,
     'zero': False,
     'extended_nonpositive': False,
     'nonpositive': False,
     'extended_nonzero': True,
     'nonzero': True,
     'negative': False,
     'extended_nonnegative': True,
     'extended_positive': True}



### Symbolic functions


```python
# We can also declare that symbols are [undefined] functions
x = sp.Symbol('x')
f = sp.Function('f')
f
```




    f




```python
# Including as functions that take arguments
g = sp.Function('g')(x)
g
```


```python
x, y = sp.symbols('x y')
h = sp.Function('h')(x, y)
h
```


```python
# And we can do multiple functions at once
f, g = sp.symbols('f g', function=True)
f.assumptions0
```




    {'function': True, 'commutative': True}



## Functions

### In-line arithmetic

sympy recognizes the usual python in-line operators, and applies the proper order of operations


```python
# python operators work as expected
x, y = sp.symbols('x y')
x + x - 2 * y * x / x ** 3
# Note: some simplification ocurred
```


```python
with sp.evaluate(False):
    y = sp.E ** (sp.I * sp.pi) + 1
y
```


```python
# The .doit() method evaluates an expression ...
y.doit() # Thank you Euler
```


```python
# Note: While this might look like a Rational, 
# This is not a Rational, rather, it is a division
p, q = sp.symbols('p q', Integer=True)
frac = p / q
frac
```


```python
# Use sp.numer() and sp.denom() to get the numerator, denominator
sp.numer(frac), sp.denom(frac)
```

### Absolute Values


```python
# Absolute value
x = sp.Symbol('x')
sp.Abs(x)
```

### Factorials


```python
sp.factorial(4, evaluate=False) # factorials
```

### Trig functions


```python
from sympy.abc import theta
sp.sin(theta) # also cos, tan, 
```


```python
sp.asin(1) # also acos, atan
```


```python
# secant example (which is the reciprocol of cos(𝜃))
sp.sec(theta) # also csc and cot for cosecant and cotangent
```

### Exponential and logarithmic functions


```python
sp.exp(x)
```


```python
# Which is the same as ...
sp.E ** x
```


```python
sp.E ** x == sp.exp(x)
```




    True




```python
sp.log(x) # log to the base of e
```


```python
sp.log(x, 10) # log to the base of 10
```

## Expressions

### Creating an expression


```python
# We start by defining the symbols used in the expression
x = sp.Symbol('x')

# Then we use those symbols to create an expression.
y = x + x + x * x # Note: This assigns a sympy expression 
                  #       to the python variable y.
                  #       This does not create an equation.

# sympy will collect simple polynomial terms automatically
y
```

### Creating expressions from strings

Note: the string should be a valid python string


```python
y = sp.simplify('m ** 2 + 2 * m - 8') 
y
```

### Substituting values into an expression


```python
x, y = sp.symbols('x y')
f = x ** 2 + y
f
```


```python
f.subs(x, 4)
```


```python
x, a, b, c = sp.symbols('x a b c')
quadratic = a * (x ** 2) + b * x + c
quadratic
```


```python
# multiple substitutions with a dictionary
quadratic.subs({a:1, b:2, c:1}) 
```

### Simplifying expressions

Note: Often the .simplify() method is all you need. However, simplifying with the .simplify() method is not well defined. You may need to call a specific simplification method that is well defined to achieve a desired result. 

Note: beyond some minimal simplification, sympy does not automatically simplify your expressions. 

Note: this is not a complete list of simplification functions


```python
# Often the .simplify() method is all you need ...
x = sp.Symbol('x')
y = ((2 * x) / (x - 1)) - ((x ** 2 - 1) / (x - 1) ** 2)
y
```


```python
# This expression can be simplified to the number 1
y.simplify()
```


```python
# Another example ...
x = sp.Symbol('x')
with sp.evaluate(False): 
    # this context manager prevents any
    # automatic simplification, resulting
    # in a very ugly expression
    y = (2 / (x + 3)) / (1 + (3 / x))
y
```


```python
y.simplify()
```

#### Finding factors


```python
x = sp.Symbol('x')
y = x ** 2 - 1
y
```


```python
y.factor()
```

#### Expanding out


```python
x = sp.Symbol('x')
y = (x + 1) * (x - 1)
y
```


```python
y.expand() # for polynomials, this is the opposite to .factor()
```

#### Collecting terms


```python
x, y, z = sp.symbols('x y z')
expr = x * y + 3 * x ** 2 + 2 * x ** 3 + z * x ** 2
expr
```


```python
expr.collect(x)
```

#### Canceling common factors, expressing as $\frac{p}{q}$


```python
x = sp.Symbol('x')
y = (x**2 - 1) / (x - 1)
y
```


```python
y.cancel()
```

#### Trig simplification


```python
x = sp.Symbol('x')
y = (sp.tan(x) ** 2) / ( sp.sec(x) ** 2 )
y
```


```python
y.trigsimp()
```

#### Trig expansions


```python
x, y = sp.symbols('x y')
f = sp.sin(x + y)
f
```


```python
sp.expand_trig(f)
```

#### Power simplifications


```python
x, a, b = sp.symbols('x a b')
y = x ** a * x ** b
y
```


```python
y.powsimp()
```

#### Log simplifications


```python
# Note: positive constraint in the next line ...
a, b = sp.symbols('a b', positive=True)
y = sp.log(a * b)
y
```


```python
sp.expand_log(y)
```


```python
y = sp.log(a / b)
y
```


```python
sp.expand_log(y)
```

#### Rewriting functions


```python
# rewite an expression in terms of a particular function
x = sp.Symbol('x')
y = sp.tan(x)
y
```


```python
# express our tan(x) function in terms of sin
y.rewrite(sp.sin)
```


```python
# express our tan(x) function in terms of the exponetial function
y.rewrite(sp.exp)
```

### Solving expressions

Solving these expressions assumes they are equations that are equal to zero. 

#### Example quadratic solution


```python
# solve a quadratic equation
x = sp.Symbol('x')
sp.solve(x ** 2 - 1, x) # solve expression in nrespect of x
                        # yields two possible solutions
```

#### Generalised quadratic solution


```python
# More generally ...
a, b, c, x = sp.symbols('a b c x')
y = a * x ** 2 + b * x + c # standard quadratic equation
sp.solve(y, x) # yields a list of two possible solutions
```

#### Quadratic with a complex solution


```python
# and if the only solutions are complex ...
sp.solve(x ** 2 + 2 * x + 10, x) 
# yields a list of two possible solutions
```

#### Manipulating expressions to re-arrange terms


```python
# rearrange terms ...
x, y = sp.symbols('x y')
f = x ** 2 - 2 * x * y + 3
sp.solve(f, y) # solve for y = ...; yeilds one possible solution
```

### Plotting expressions


```python
x = sp.Symbol('x')
expr = sp.sin(x) ** 2 + sp.cos(x)
expr
```


```python
plot = sp.plot(expr, show=True)
print(type(k))
```


```python
# plot multiple lines at once
sp.plot(sp.sin(x), sp.cos(x), legend=True, show=True)
```


```python
from sympy.plotting import plot3d
x, y = sp.symbols('x y')
plot = plot3d(x**2 + y**2, show=True)
```

## Equations

### Creating equations


```python
# Note: we use sp.Eq(left_expr, right_expr) 
# to create an equation in sympy
x, y = sp.symbols('x y')
sp.Eq(y, 3 * x + 2)
```

### Solving equations

#### Rearranging terms


```python
x, y = sp.symbols('x y')
eqn = sp.Eq(x ** 2 + 2 * x * y - 1, 0)
eqn # this is our equation
```


```python
solution = sp.solve(eqn, y)
solution # yields a list of solutions, 
# in this case a list of 1 ...
```


```python
# Which we can turn back into an equation
sp.Eq(y, solution[0])
```

#### Exponential example


```python
a, b, x = sp.symbols('a b x')
eq = sp.Eq(a ** b, sp.E ** x)
eq # our equation
```


```python
sp.Eq(x, sp.solve(eq, x)[0])
```

#### Quadratic example


```python
y = sp.Symbol('y')
eq = sp.Eq(x ** 2 - 2 * x, 0)
sp.solve(eq)
```


```python
y = sp.Symbol('y')
eq = sp.Eq(x ** 2 - 2 * x, y)
sp.solve(eq)
```


```python
y = sp.Symbol('y')
eq = sp.Eq(x ** 2 - 2 * x, y)
sp.solve(eq, x) # solve for x
```

#### A trigonometric example 


```python
x = sp.Symbol('x')
eq = sp.Eq(sp.sin(x) ** 2 + sp.cos(x), 0)
sp.solve(eq)
```


```python
# solveset allows us to capture tbe set of infinite solutions
sp.solveset(eq)
```

### Solving systems of equations

#### Two linear equations


```python
x, y = sp.symbols('x y')
eq1 = sp.Eq(y, 3 * x + 2) # an equation
eq1
```


```python
eq2 = sp.Eq(y, -2 * x - 1)
eq2
```


```python
sp.solve([eq1, eq2], [x, y])
```

#### A linear and cubic system with three point-solutions


```python
eq1 = sp.Eq(y, x)
eq2 = sp.Eq(y, sp.Rational(1, 10) * x ** 3)
sp.solve([eq1, eq2], [x, y]) 
```

#### A system of equations with no solutions


```python
eq1 = sp.Eq(y, x)
eq2 = sp.Eq(y, x + 1)
sp.solve([eq1, eq2], [x, y]) 
```

## Limits

### Simple example


```python
x = sp.Symbol('x')
expr = (x * x  - 1)/(x - 1)
expr
```


```python
# the function of this expression is a straight line
sp.plot(expr, xlim=(-4,4), ylim=(-2,6))
```


```python
# But our expression is not defined when x is 1
# as it evaluates to zero divided by zero
expr.subs(x, 1)
```


```python
# The limit as x approaches 1
sp.limit(expr, x, 1) # using the global limit() function
```


```python
expr.limit(x, 1) # using the .limit() method
```


```python
# We can display the limit with the Limit() function
# Note: by default, this is the limit approached from 
#       the positive side.
lim = sp.Limit(expr, x, 1)
lim
```


```python
# And we can use the .doit() method to calculate the limit
lim.doit()
```

### More complicated examples

Calculate the derivative from first principles (using limits), for a selection of functions
$$f'(x) = \lim_{h \to 0} \frac{f(x+h) - f(x)}{h}$$

#### $f(x) = x^n$


```python
# This is our generic function x to the power of n
def f(x, n):
    return x ** n

x, h, n = sp.symbols('x h n')
f(x, n) # what is our function f(x, n) ...
```


```python
# Apply the limit to our function ...
# Note: our arguments x, h and n are sympy symbols
lim = sp.Limit((f(x + h, n) - f(x, n))/h, h, 0)
lim
```


```python
# Calculate the limit ...
lim.doit()
```

#### $f(x)=a^x$


```python
# Let's change the function to an exponential: a ** x
def f(a, x):
    return a ** x

x, h, a = sp.symbols('x h a')
f(a, x) # what is our function f(x) ...
```


```python
# Apply the limit to our function ...
lim = sp.Limit((f(a, x + h) - f(a, x))/h, h, 0)
lim
```


```python
# Calculate the limit ...
lim.doit()
```

#### $f(x)=sin(x)$


```python
# One last example, the derivative of sin(x)
def f(x):
    return sp.sin(x)

x, h = sp.symbols('x h')
f(x) # Our function f(x) = sin(x)
```


```python
# Apply the limit to our function ...
lim = sp.Limit((f(x + h) - f(x))/h, h, 0)
lim
```


```python
# And evaluating the limit
lim.doit()
```

### Limits, where the direction in which we approach the limit is important


```python
x = sp.Symbol('x')
expr = 1 / x
expr
```


```python
sp.plot(expr, xlim=(-8, 8), ylim=(-8, 8))
```


```python
# Let's display the limit from the positve direction
lim = sp.Limit(expr, x, 0, '+')
lim
```


```python
# And calculate it ...
lim.doit()
```


```python
# And the limit from the negative direction
expr.limit(x, 0, '-')  
```


```python
# We can also do the limit from both directions
expr.limit(x, 0, '+-') # which yields complex infinity
```

## Derivatives

### First, second and subsequent derivatives

For one-variable expressions ... sympy has multiple ways to get the ordinary derivative
* using the `.diff()` method on an expression
* using the `diff()` function on an expression
* using the combined `Derivative().doit()` function/method on an expression


```python
# Let's generate a polynomial ...
x = sp.Symbol('x')
y = 3 * x ** 4 + 2 * x ** 2 - x - 1
y
```


```python
# provide the symbolic forumala for the first derivative
y_dash = sp.Derivative(y, x)
y_dash
```


```python
# And calculate the differential ...
y_dash.doit()
```


```python
# Also ... using the .diff() method
y.diff(x) # differentiate with respect to x
```


```python
# Also using the diff() function
sp.diff(y, x) # differentiate with respect to x
```


```python
# provide the symbolic formula for the second derivative
y_2dash = sp.Derivative(y, x, 2)
y_2dash
```


```python
# second derivative can also be done like this
y_2dash.doit()
```


```python
# Also ...
y.diff(x, x) # differentiate twice in respect of x
```


```python
# Also ...
y.diff(x, 2)
```


```python
# And the formula for the third Derivative
y_3dash = sp.Derivative(y, x, 3)
y_3dash
```


```python
# third derivative (and so on ...)
y_3dash.doit()
```


```python
# Also ...
y.diff(x, 3)
```


```python
# Also ...
y.diff(x, x, x)
```


```python
# Also ...
sp.diff(y, x, 3) 
```


```python
# Generalisations ...
a, x = sp.symbols('a x')
(x ** a).diff(x).simplify()
```


```python
# Generalisations ...
a, x = sp.symbols('a x')
(a ** x).diff(x)
```

### Partial derivatives

As with the above differentials, there are multiple ways to do this ...


```python
x, y = sp.symbols('x y')
g = x* y ** 2 + x ** 3
g
```


```python
# The first partial derivative of the expression with respect to x
partial_x = sp.Derivative(g, x, 1)
partial_x
```


```python
# Calculate ...
partial_x.doit()
```


```python
# And the first order partial derivative in respect of y
partial_y = sp.Derivative(g, y, 1)
partial_y.doit()
```

## Integrals

### Definite Integrals


```python
# Definite integral using the integrate() function
# The tuple contains (with_respect_to, lower_limit, upper_limit)
x = sp.Symbol('x')
f = sp.sin(x)
y = sp.Integral(f, (x, 0, sp.pi / 2))
y
```


```python
# we can then calculate it as follows
y.doit()
```


```python
# We can calculate the definite interval using the .integrate() method
x = sp.Symbol('x')
f.integrate((x, 0, sp.pi / 2))
```


```python
# We can calculate the definite interval using the integrate() function
sp.integrate(f, (x, 0, sp.pi / 2))
```

### Indefinite integrals 

***Caution***: sympy does not yield the constant of integration (the "+ C") that arises from the indefinite integral. So technically, we are getting the anti-derivative, rather than the indefinite integral. Note: the constant of integration is netted out when the definite integral is calculated. 


```python
x = sp.Symbol('x')
y = x ** 2 + 2 * x
y.integrate(x) # integreate in respect of x
```


```python
x = sp.Symbol('x')
sp.log(x).integrate(x)
```


```python
x = sp.Symbol('x')
sp.sin(x).integrate(x)
```

### sympy cannot evaluate some integrals 

If `integrate()` is unable to compute an integral, it returns an unevaluated Integral object.


```python
# for example ... sysmpy cannot calculate this integral
sp.log(sp.sin(x)).integrate(x)
```

## Sums

Sums can be achieved with either the summation function or the Sum constructor

### Infinite sums


```python
# A sum from the sum constructor
# Note: the second term is the tuple: (index, lower_bound, upper_bound)
# Where: the range is from lower_bound to upper_bound inclusive
x, n = sp.symbols('x n')
s = sp.Sum(6 * (x ** -2), (x, 1, sp.oo)) # sum constructor
s # display the sum
```


```python
s.doit() # evaluate the sum
```


```python
s.n() # approximate value
```


```python
# A sum using the summation function
x = sp.symbols('x')
s = sp.summation(90 / x ** 4, (x, 1, sp.oo))
s
```


```python
# A sum using the summation function
# with a defined python function
n = sp.symbols('n')
def f(n): return 945 / (n ** 6) # a defined function
s = sp.summation(f(n), (n, 1, sp.oo))
s
```


```python
# And another example that sums to one
x = sp.symbols('x')
with sp.evaluate(False):
    expr = 1 / (2 ** x)
expr
```


```python
s = sp.Sum(expr, (x, 1, sp.oo))
s
```


```python
s.doit()
```

### Finite sums


```python
x, a, b, c, n = sp.symbols('x a b c n')
quad = a * (x ** 2) + b * x + c
quad
```


```python
quad_sum = sp.summation(1 / quad, (x, 0, n))
quad_sum
```


```python
quad_sum.subs(n, 10)
```


```python
quad_sum.subs({a:1, b:2, c:1, n:10})
```


```python
_.n() # previous value approximated ...
```


```python
quad_sum = sp.summation(1 / quad, (x, 0, 10))
quad_sum
```


```python
quad_sum.subs({a:1, b:2, c:1})
```


```python
_.n() # previous value approximated ...
```

## Taylor series expansion

Taylor series is a technique to approximate a function at/near a point using polynomials. The technique requires that multiple n-order derivatives can be found for the function. It works well with exponential and trigonometric functions. The series used to approximate the function over a range, using a specified number of polynomial terms, or it can be expressed as an infinite series.

Why do it? Mathematically, polynomials are sometimes easier to work with. These approximations are remarkably accurate with just a small number of terms. 

### A finite Taylor series


```python
x = sp.Symbol('x')
s = sp.series(sp.cos(x), x, x0=0, n=6) # at x=0, for six polynomial terms
                                       # noting that the odd powers for our
                                       # polynomial are zero.
s # note the donominators are 0!, 2!, 4!, 6! ... (where 0! equals 1)
s
```


```python
# We can remove the Big-O notation
s.removeO()
```


```python
# We can compare cos(0.5) with our taylor-approximation of cos(0.5)
# and see for this point-value it is accurate to three decimal places. 
point = 0.5
print(f'cos={sp.cos(point)} Taylor={s.removeO().subs(x, point).n()}')
```

    cos=0.877582561890373 Taylor=0.877604166666667



```python
# This Taylor series looks like it provides 
# a workable approximation for cos(x) between 
# at least x=-π/4 and +π/4

sp.plot(sp.cos(x), s.removeO(), 
        legend=True, 
        show=True, ylim=(-1,1.5))
```


```python
# Let's try plotting a few more terms, which expands the
# range for which our approximation provides good results. 
x = sp.Symbol('x')
s_6 = sp.series(sp.cos(x), x, x0=0, n=6).removeO()
s_16 = sp.series(sp.cos(x), x, x0=0, n=16).removeO()
sp.plot(sp.cos(x), s_6, s_16,        
        #legend=True, 
        show=True, ylim=(-1.3,1.3))
```


```python
# Let's compare the two plotted approximations at π/4
p = sp.pi / 4

print(f'cos({p})={sp.cos(p.evalf())}; ')
print(f'n=6-->    {s_6.subs(x, p).n()}, ')
print(f'n=16-->   {s_16.subs(x, p).n()}')

```

    cos(pi/4)=0.707106781186548; 
    n=6-->    0.707429206709773, 
    n=16-->   0.707106781186547


### Infinite Taylor series


```python
# Instead of specifying n for the order of the polynomial, we set n=None
t_log = sp.series(sp.log(x), x=x, x0=1, n=None)
t_log # this returns a python generator for the series. 
```




    <generator object Expr.series.<locals>.<genexpr> at 0x1880e66d0>




```python
# Let's display the first 8 terms of this series
# Note: generators can only be used once in Python ...
lst = []
for i in range(8):
    lst.append(next(t_log))
display(lst)
```


```python
sum(lst) # which we can sum in python ...
```

## Matrices / Linear Algebra


```python

```


```python

```


```python

```

## The End


```python

```

6c10dd658eb51a794c7dc029ec3cf318805b61c5
ipynb
Jupyter Notebook
notebooks/Introduction to sympy.ipynb
bpalmer4/code-snippets
e87f7baade69ff25e062f54d58b3f6f611c4c283
MIT
notebooks/Introduction to sympy.ipynb
bpalmer4/code-snippets
e87f7baade69ff25e062f54d58b3f6f611c4c283
MIT
notebooks/Introduction to sympy.ipynb
bpalmer4/code-snippets
e87f7baade69ff25e062f54d58b3f6f611c4c283
MIT
Qwen/Qwen-72B
1. YES
2. YES