Calculus 1, Lab 2: Derivatives!#

By Raheem Mir

As the title suggests, in this notebook we are going to be working with Derivatives… Let’s Begin!

First, what’s been covered so far?

  • Rates of Change

  • Finding the Derivative at a Point

  • Tangent Lines

And of course, the limit definition of the Derivative:

Let \(f(x)\) be a function that is defined on an open interval (a,b). The derivative of \(f(x)\), written as \(f'(x)\), is defined by the limit

\[ f'(x) = \lim_{h \to 0} \frac{f(x+h) - f(x)}{h}, \]

as long as the limit exists. If the limit exists for a certain value \(x=c\), we say that \(f\) is differentiable at \(c\).

Now for a quick example! (found in your textbook)

Let \(f(x) = 3x^2 + 5x - 7\). To find \(f'(x)\):

\[\begin{split} \begin{aligned} f'(x) &= \lim_{h \to 0} \frac{f(x+h) - f(x)}{h} \\ &= \lim_{h \to 0} \frac{3(x+h)^2 + 5(x+h) - 7 - (3x^2 +5x -7)}{h} \\ &= \lim_{h \to 0} \frac{3h^2 + 6xh + 5h}{h} \\ &= \lim_{h \to 0} 3h + 6x + 5 \\ &= 6x + 5 \end{aligned} \end{split}\]

With an example like this, using the limit definition to compute the derivative is all well and good. However, when we start working with more complex and intricate functions, computing derivatives this way becomes increasingly more inefficient and awkward (not to mention ugly!).

In your next class, you’ll learn some much easier and more efficient ways of taking derivatives by hand.

But for now, let’s compute our derivatives using Python, more specifically, SymPy!

Getting Started with Python and SymPy#

As you may recall from our last Python notebook a couple weeks ago, to access the functionality from the SymPy library, we need to import it:
→ Run the code cell(s) by hitting shift + enter or by using the play button at the top.

# Make sure to run this cell!
import sympy as sy
sy.init_printing()       

A Quick Refresher:

The line: import sympy as sy loads in the SymPy library for us to use. We give it the shorthand name sy, so every time we call something from SymPy, we prefix it with sy.. This is a good way to keep things organized, especially when we are working with multiple libraries.

The next line: sy.init_printing() calls SymPy’s init_printing() function, which gets the output to be displayed as nicely formatted mathematics.

Now is a good time to tell Sympy that we want to use \(x\) as variable. This is done by using the symbols() function.

x = sy.symbols('x')    # this makes x a symbol

Next, let’s represent a function in SymPy:

We can use the example seen at the begining, \(f(x) = 3x^2 + 5x - 7\)

f = 3*x**2 + 5*x -7     # Notice how multiplication is represented by a single '*', and exponents with two '**'
f  

Remember with SymPy we are not creating “functions” per se, that are defined on an input/output basis, rather we are defining symbolic expressions, intended to be easily manipulated with algebra and/or calculus. If you were to do something like calling f(3), instead of getting an output of \(35\), an error would be returned instead.

To input a value into your SymPy expression, you can use the subs() function, where you substitute a value in for \(x\) or whichever variable the function is using.
Let’s see this in action by evaluating the function when \(x = 5\), also written as \(f(5)\):

f.subs(x, 5) 

It’s also important to note that when we create our SymPy expressions, like f = ..., we don’t have to use the names f or g. Since we are just storing the expressions to a variable, the name can be anything of our choosing. The naming convention of this notebook, uses the names f or g, except we add a 2 or 3 etc. to ensure clarity and that the code runs smoothly.

Computing Derivatives with SymPy#

Alright, now that we’ve reviewed some SymPy basics, and run a couple of cells, its time to compute derivatives!

Taking derivatives with SympPy is very convenient and time efficient. We simply use the diff() function!

Let’s continue with our existing example, f, which represents the function \(f(x) = 3x^2 + 5x - 7\).
We can find \(f'(x)\) as follows:

f_prime = f.diff(x)       # The 'x' inbetween the '()' means we are differentiating with respect to x
f_prime                   # Also notice that we are using a variable to store the result of using the diff() function

Take a look at the output… is it what you were expecting? Does it match the \(f'(x)\) calculated at the top?
Double-click on the empty markdown cell below to type your answer! Hit shift + enter once you’re done.

Now let’s try to evaluate \(f'(x)\) when \(x = 3\). This can simply be done by tagging on a call to the subs() function to our existing code:

f_prime.subs(x, 3)

Exercise#

For the function \(f\) above, use the diff and subs commands to write the equation of the tangent line to \(y=f(x)\) at \(x=2\). You will need to edit the cell below. We’ve added one line to start you off: you need to declare \(y\) as a symbol before you can use it in an equation.

y = sy.symbols('y')

Let’s look at some more examples!

Consider the function, \(f(x) = \dfrac{1}{x+1}\) (Example 2.1.23. in your textbook), what does it’s derivative look like?

# First, we represent g(x) in SymPy
f2 = 1 / (x + 1)     # using brackets is a good idea with fractions
f2
# Taking the derivative with respect to x
f_prime2 = f2.diff(x)
f_prime2 

Now lets’s try differentiating \(g(x) = \displaystyle \sqrt{x}\). To do this we can use the built in sqrt() function from SymPy!
Trigonometric functions are also implemented by SymPy which you’ll see in following examples.

g = sy.sqrt(x)
g
g_prime = g.diff(x)
g_prime

Now for some trigonometric examples…

Let’s find the derivative of the function \(f(x) = \sin(x)\).

Before we use SymPy, what do you think the derivative will be? And how do you know?
Double-click on the empty markdown cell below to type your answer! Hit shift + enter once you’re done.

f3 = sy.sin(x)
f3
f_prime3 = f3.diff(x)
f_prime3

Interesting! The derivative of the sine function, is the cosine function, or when \(f(x) = \sin(x)\), \(f'(x) = \cos(x)\).
Why might this be the case? Provide an explanation in the empty cell below.
When crafting your answer, think of the behaviour of \(\sin(x)\) and \(\cos(x)\), and even have a look at Example 2.1.24. from your textbook.

Now let’s consider the function \(g(x) = \cos(x)\) and find it’s derivative!

g2 = sy.cos(x)
g_prime2 = g2.diff(x)  
g_prime2

Were you expecting the derivative to be equal to \(\sin(x)\) as opposed to \(-\sin(x)\)? Regardless, it’s clear that a relationship exists here.

Let’s keep exploring, but this time you get to write the code!

Find the derivative of the function \(f(x) = -\sin(x)\) using the code cell below!

# Write your code here! Look at previous examples if you get stuck

Give another one a try! Find the derivative of the function \(g(x) = -\cos(x)\) using the code cell below!

# Write your code here! Look at previous examples if you get stuck

Let’s work on some more exercises!

For each given function \(f(x)\), find \(f'(x)\) using SymPy, good luck!

Exercise #1: \(f(x) = x^7\)

# Write your code here! Look at previous examples if you get stuck

Exercise #2: \(f(x) = 4x^3 - 2x^2 + 6\)

# Write your code here!

Exercise #3: \(f(x) = 5e^x\)

Tip: To represent the \(e^x\) in SymPy we simply use the exp() function. For example, to represent \(y = e^x\), we’d type y = sy.exp(x)

# Write your code here!

Exercise #4: \(f(x) = x^2\sin(x)\)

# Write your code here!

Exercise #5: \(f(x) = (2x^2 + 1)(3x^2 - 1)\)

# Write your code here!

Exercise #6: \(f(x) =\dfrac{x^2 - 4}{x + 2}\)

# Write your code here!

Exploring Higher Order Derivatives#

When we take the derivative of a given function, we get its instantaneous rate of change, but what if we wanted to know the rate of change of that rate of change? This is where higher order derivatives come in. Remember that the derivative of a function is also a function itself, so it’s derivative can be found as well!

Given a function \(f(x)\), we know that it’s derivative, \(f'(x)\) is also a function, meaning we can take it’s derivative, which is known as the second derivative of \(f\) and denoted as \(f''(x)\). If we were to take another successive derivative, it would be known as the third derivative, written as \(f'''(x)\).

Now let’s compute higher order derivatives using SymPy, first illustrating with an example!

Find the first three derivatives of the function, \(f(x) = 9x^2\).

Method 1:

f = 9*x**2
fp = f.diff(x) # 'fp' refers to "f prime"
fpp = fp.diff(x)
fppp = fpp.diff(x)

fp, fpp, fppp   # Outputting the first three derivatives

Method 2: Computing the higher order derivatives directly
Much like how we add a tick (or prime) to our notation when taking the next higher order derivative, we simply add an argument to the diff() function!

fpp = f.diff(x, x)      # gives us the second derivative
fppp = f.diff(x, x, x)   # gives us the third derivative
fpp, fppp

Let’s try some exercises! Compute the specified higher order derivative using SymPy.

Exercise 1:
Find the second derivative of the function, \(f(x) = 3x^4\).

# Write your code here!

Exercise 2:
Find the third derivative of the function, \(g(x) = \cos(x)\).

# Write your code here!

Root Finding: The Bisection Method#

Let’s consider the function, \(f(x) = x -\cos(x)\) on the interval \(\left[0, \dfrac{\pi}{2}\right]\).

The function \(f(x)\) is continuous. Can you explain why?

Double-click on the empty markdown cell below to type your explanation! Hit shift + enter once you’re done.

First, we can evaluate \(f\) at \(x = 0\) and \(x = \dfrac{\pi}{2}\), the endpoints of our interval:

f = x - sy.cos(x)
f.subs(x, 0), f.subs(x, sy.pi/2)

Since \(f\) changes from negative to positive, by the Intermediate Value Theorem, we know that \(f(c) = 0\), for some \(c\) in \(\left(0, \dfrac{\pi}{2}\right)\).

Except, we can’t solve for it! We instead have to approximate it, using the Bisection Method of root finding.

The goal is to continuously cut our interval in half, we know \(c\) exists, but we dont know where exactly. We start by computing \(f\) at the midpoint of the interval, if the result is zero, or sufficiently close to it, we’ve found our root, otherwise we halve our interval depending on the sign of \(f\) at the midpoint, and repeat until a specified level of precision (or length of the interval) is reached.

Our goal is to eventually find an interval of length \(\dfrac{\pi}{32}\) that contains the root.

The midpoint of our interval is \(\dfrac{\pi}{4}\), so let’s compute \(f\left(\dfrac{\pi}{4}\right)\).

f.subs(x, sy.pi/4)

We can also get a decimal approximation for \(f\left(\dfrac{\pi}{4}\right)\) using the evalf() function.
This will be more helpful, since we are only concerned with the signs of our results.

f.subs(x, sy.pi/4).evalf()

As we can see \(f\left(\dfrac{\pi}{4}\right) > 0\), so our new sub-interval is \(\left[0, \dfrac{\pi}{4}\right]\). The length of this interval is \(\dfrac{\pi}{4} - 0 = \dfrac{\pi}{4}\).

Let’s evaluate \(f(x)\) at the new midpoint, \(x = \displaystyle\frac{\pi}{8}\).

f.subs(x, sy.pi/8).evalf()

\(f\left(\dfrac{\pi}{8}\right) < 0\), so our new sub-interval is \(\left[\dfrac{\pi}{8}, \dfrac{\pi}{4}\right]\). The length of this interval is \(\dfrac{\pi}{4} - \dfrac{\pi}{8} = \dfrac{\pi}{8}\).

Let’s evaluate \(f(x)\) at the new midpoint, \(x = \dfrac{3\pi}{16}\), but this time it’s your turn!

Continue with the Bisection Method until you find an interval of length \(\displaystyle\frac{\pi}{32}\) containing the root. Use the code cells below.

# Write your code here! Look at previous cells/steps if you get stuck
# Write your code here! 
# Write your code here! 
# Write your code here! 

You may also be interested in automating this process. Can we write a program to do it for us?

Maybe we can’t… but Patrick Walls at UBC can! Here is a program from his website.

Basically, we first check that \(f(a)f(b)<0\) (opposite signs at the two endpoints).

Then we compute \(f(m)\) and check the sign, where \(m=\dfrac{a+b}{2}\) is the midpoint of \((a,b)\).

If \(f(a)f(m)<0\), repeat the process on \((a,m)\). If \(f(m)f(b)<0\), repeat on \((m,b)\).

We also have to tell the computer how many steps to take, so it knows when to stop!

def bisection(f,a,b,N):
    if f(a)*f(b) >= 0:
        print("Bisection method fails.")
        return None
    a_n = a
    b_n = b
    for n in range(1,N+1):
        m_n = (a_n + b_n)/2
        f_m_n = f(m_n)
        if f(a_n)*f_m_n < 0:
            a_n = a_n
            b_n = m_n
        elif f(b_n)*f_m_n < 0:
            a_n = m_n
            b_n = b_n
        elif f_m_n == 0:
            print("Found exact solution.")
            return m_n
        else:
            print("Bisection method fails.")
            return None
    return (a_n + b_n)/2

To use the program, you will first have to define a function, using NumPy (do you remember how to do that from the first lab?).

Then you can call the program using the syntax bisection(f,a,b,n), where f is the function you define, a and b are the endpoints of your interval, and n is the number of steps to use.