The Definite Integral

GOALS:

  • Investigate general behavior of Riemann Sums
  • Define the Definite Integral as a Limit of Riemann Sums
  • Recognize polynomial patterns with summations
  • Use tables to evaluate integrals
  • Use computer to evaluate integrals
In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
import pandas as pd

The Riemann Sum

$$width \times height$$

$$\frac{b - a}{n} \times \sum_{i = 1}^n f(a + \frac{b - a}{n} i)$$

In [2]:
#define our function
def f(x): return x
In [3]:
#define the limits
a = 0
b = 1
In [4]:
#define n as a symbolic variable
n = sy.Symbol('n')
In [5]:
#determine the width
width = (b-a)/n
In [6]:
#example of how symbols and numbers play
for i in range(1,10):
    print(f(a + i*width))
1/n
2/n
3/n
4/n
5/n
6/n
7/n
8/n
9/n
In [7]:
def f(x): return x**2
In [8]:
for i in range(1,10):
    print(f(a + i*width))
n**(-2)
4/n**2
9/n**2
16/n**2
25/n**2
36/n**2
49/n**2
64/n**2
81/n**2
In [9]:
i, n = sy.symbols('i, n')
In [10]:
sy.summation(i, (i, 1, n))
Out[10]:
n**2/2 + n/2
In [11]:
sy.pprint(sy.summation(i**2, (i, 1, n)))
 3    2    
n    n    n
── + ── + ─
3    2    6
In [12]:
def riemann(a, b, n):
    #This is a function to evaluate our riemann sum formula
    #first we determine the width
    width = (b - a)/n
    #then we determine the heights and their sum
    #define symbols i and n as symbolic variables
    i, n = sy.symbols('i, n')
    s = sy.summation(f(a + (b-a)/n*i), (i, 1, n))
    #finally we return the results of the sum
    return sy.pprint(width*s)
In [13]:
def f(x): return x
In [14]:
riemann(0, 1, n)
 2    
n    n
── + ─
2    2
──────
   2  
  n   
In [15]:
def f(x): return x**2
riemann(0, 1, n)
 3    2    
n    n    n
── + ── + ─
3    2    6
───────────
      3    
     n     
In [16]:
def f(x): return x**3
riemann(0, 1, n)
 4    3    2
n    n    n 
── + ── + ──
4    2    4 
────────────
      4     
     n      
In [17]:
def f(x): return x**4
riemann(0, 1, n)
 5    4    3     
n    n    n    n 
── + ── + ── - ──
5    2    3    30
─────────────────
         5       
        n        

PROBLEM

  1. Examine the results for $f(x) = x^3$ and $f(x) = x^4$ on the interval $[0, 1]$.
  2. Simplify the results and make a list for $x, x^2, x^3,$ and $x^4$.
  3. Determine what happens if you increase $n \to \infty$ in all your expressions. Is there a pattern?

Successive Approximations

In [18]:
def f(x): return x**2
n = 4
In [19]:
#basic walkthrough for computing area
#first determine width and heights of rectangles
width = (b-a)/n
height = [f(a + width*i) for i in range(n)]

#find the individual areas of each rectangle
area = [(width * height[i]) for i in range(n)]
#add the areas together
sum(area)
Out[19]:
0.21875
In [20]:
#change the number of rectangles
n = 10

width = (b-a)/n
height = [f(a + width*i) for i in range(n)]
area = [(width * height[i]) for i in range(n)]
sum(area)
Out[20]:
0.2850000000000001
In [21]:
#more rectangles
n = 100

width = (b-a)/n
height = [f(a + width*i) for i in range(n)]
area = [(width * height[i]) for i in range(n)]
sum(area)
Out[21]:
0.32835000000000014
In [22]:
#a function to make this easier
def area_approximations(n):
    width = (b-a)/n
    height = [f(a + width*i) for i in range(n)]
    area = [(width * height[i]) for i in range(n)]
    return sum(area)
In [23]:
#look at what happens as we increase the number of rectangles
#each loop corresponds with an increase of 5 rectangles
for i in range(1, 100, 5):
    print(area_approximations(i))
0.0
0.2546296296296296
0.2892561983471075
0.302734375
0.309901738473167
0.31434911242603564
0.3173777315296566
0.31957304526748964
0.3212373587150506
0.32254253308128544
0.323593489683455
0.3244579081632653
0.32518140284869673
0.3257958371594735
0.3263241420353105
0.3267832409972298
0.32718589645887297
0.32754191454840453
0.3278589542325806
0.3281430844907407
In [24]:
appx = []
for i in range(1, 100, 5):
    appx.append(area_approximations(i))
    
plt.plot(appx, '--o')
Out[24]:
[<matplotlib.lines.Line2D at 0x115cf3048>]
In [25]:
def area_experiment(a, b, n):
    width = (b-a)/n
    height = [f(a + width*i) for i in range(n)]
    area = [(width * height[i]) for i in range(10)]
    print("The area approximation with", n, "rectangles is {:.5f}".format(sum(area)))
In [26]:
area_experiment(-4, 4, 100)
The area approximation with 100 rectangles is 10.64192

PROBLEMS

  1. Determine what you think is the exact area underneath your four examples above by examining the resulting pattern of increasing the number or rectangles.
In [27]:
def f(x): return x
area_experiment(0, 2, 100)
The area approximation with 100 rectangles is 0.01800

Plotting the Areas

In [28]:
bar_h = [f(-1 + width * i) for i in range(1, n)]
In [29]:
x = np.linspace(-1,1,100)
In [30]:
plt.figure(figsize = (10, 7))
b = np.arange(-1,1,n)
plt.plot(x, f(x), linewidth = 4)
plt.axhline(color = 'black')
for i in range(n):
    plt.bar([a+i*width], f(a + i*width), width, align = 'center', color = 'grey', alpha = 0.2, edgecolor = 'black')
In [31]:
from ipywidgets import interact
from ipywidgets import widgets
In [32]:
def re_slides(a, b, n):
    #compute the width of the rectangles
    width = (b-a)/n
    #compute the height of each rectangle
    bar_h = [f(a + width * i) for i in range(1, n)]
    #create some x values for line plot
    x = np.linspace(a, b, 1000)
    #plot the function
    plt.figure(figsize = (14, 6))
    plt.plot(x, f(x), color = 'black', linewidth = 8)
    plt.axhline(color = 'black')
    #find the area and print it
    area = [width * bar_h[i] for i in range(len(bar_h))]
    print("The area approximation with", n, "rectangles is {:.4f}".format(sum(area)))
    #make a bar for each rectangle on the plot
    for i in range(n):
        plt.bar([a+i*width], f(a + i*width), width, align = 'center', color = 'purple', edgecolor = 'black')   
In [33]:
interact(re_slides, a = -1, b = 1, n = widgets.IntSlider(min=1,max=100,step=10,value=10))
Out[33]:
<function __main__.re_slides(a, b, n)>

Summation Machine

In [68]:
i, n, x = sy.symbols('i, n, x')
In [69]:
i = sy.Symbol('i')
sum1 = sy.summation(i, (i, 1, n))
In [70]:
sy.pprint(sum1)
 2    
n    n
── + ─
2    2
In [71]:
def summer(power):
    i = sy.Symbol('i')
    sum1 = sy.summation(i**power, (i, 1, n))
    sy.pprint(sum1)
In [72]:
interact(summer, power = widgets.IntSlider(1, 1, 20))
 2    
n    n
── + ─
2    2
Out[72]:
<function __main__.summer>
In [73]:
interact(re_slides, a = 0, b = -1, n = widgets.IntSlider(1,min = 1, max = 100, start = 4))
The area approximation with 1 rectangles is 0.0000
Out[73]:
<function __main__.re_slides>

PROBLEMS

  1. Investigate your areas on the intervals $[0, 2], [0, 3], [0, 4],$ and $[0, 5]$

  2. Plot these solutions together as successive approximations. Do you see a pattern?

The Definite Integral

$$\lim_{n \to \infty} \Delta x \sum_{i = 1}^n f(a + \Delta x i) = \int_{a}^{b} f(x) dx$$

In [33]:
def f(x): return -x**6 + x**3 - x + 4
In [34]:
x = sy.Symbol('x')
In [35]:
sy.integrate(f(x), (x, -1, 1))
Out[35]:
54/7
In [36]:
x = np.linspace(-1,1, 1000)
plt.figure(figsize = (10, 5))
plt.plot(x, f(x), color = 'black', linewidth = 4)
plt.fill_between(x, f(x), alpha = 0.4, hatch = 'x')
plt.axhline(color = 'black')
x = sy.Symbol('x')
plt.title("The area under the curve is:    {}".format(sy.integrate(f(x), (x, -1, 1))), fontsize = 16, loc = 'left')
Out[36]:
Text(0,1,'The area under the curve is:    54/7')
In [37]:
def definite_integral(a, b):
    x = np.linspace(a, b, 1000)
    plt.figure(figsize = (10, 5))
    plt.plot(x, f(x), color = 'black', linewidth = 4)
    plt.fill_between(x, f(x), alpha = 0.4, hatch = 'x')
    plt.axhline(color = 'black')
    x = sy.Symbol('x')
    plt.title("The area under the curve is:     {}".format(sy.integrate(f(x), (x, -1, 1))), fontsize = 16, loc = 'left')
In [38]:
def f(x): return -x**2 + 4
definite_integral(-2,2)
In [39]:
def f(x): return -x**3 + 4
definite_integral(-2,2)
In [40]:
def f(x): return x**5 - 10*x**3 + x**2 - 17
sy.integrate(f(x), (x, -2, 15))
Out[40]:
1772743