Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Lecture 6 · Trapezoids, Simpson, Modules, and Tests

Block 2 · Week 3

San Diego State University

Trapezoids, Simpson, modules, and tests

Improve a local approximation, then make its implementation reusable

Last class we replaced the function on each panel with a constant. Today we use a line and a quadratic, then organize and test the rectangle rule in a lab.

The through-line

Jump to: Trapezoid · Simpson · Modules and tests · Sine lab

  1. Approximate the function on one panel.

  2. Integrate that approximation.

  3. Assemble a composite rule and explain its error order.

  4. Put a reusable function in a module.

  5. Write a test whose reference and tolerance have a stated basis.

The same choices apply to many scientific integrands.

Today’s question

How do better local approximations lead to better quadrature rules, and how can we make those rules reusable and testable?

By the end of class, you should be able to:

  • derive trapezoid and Simpson weights from local polynomials;

  • explain their composite orders and smoothness conditions;

  • organize a numerical function in an importable module;

  • run pytest tests from the project root; and

  • justify an accuracy assertion and test invalid inputs.

Recall · what a left rectangle retains

On a panel of width hh,

∫xixi+hf(x) dx=hf(xi)+h22f′(xi)+O(h3).\int_{x_i}^{x_i+h}f(x)\,dx =h f(x_i)+\frac{h^2}{2}f'(x_i)+O(h^3).

The left rectangle keeps hf(xi)h f(x_i) and omits the slope contribution.

Predict: if we use both endpoint heights and join them with a line, which term can we capture? What kind of function would the new rule integrate exactly?

I · Trapezoids retain the local slope

What accuracy do we gain by connecting the two endpoint heights?

Goals

  • integrate a linear interpolant on one panel;

  • assemble the endpoint and interior weights; and

  • derive the local and composite error orders with Taylor expansion.

Integrate the line between the endpoints

With s=x−xis=x-x_i on 0≤s≤h0\le s\le h, the interpolating line is

ℓ(s)=f(xi)+sh[f(xi+1)−f(xi)].\ell(s)=f(x_i)+\frac{s}{h}\bigl[f(x_{i+1})-f(x_i)\bigr].

Its area is

Ti=∫0hℓ(s) ds=h2[f(xi)+f(xi+1)].T_i=\int_0^h\ell(s)\,ds =\frac{h}{2}\bigl[f(x_i)+f(x_{i+1})\bigr].

This is the trapezoidal rule on one panel. A linear function is reproduced exactly by its endpoint interpolant.

Interior nodes belong to two neighboring trapezoids

Adding the panel contributions gives

Tn=h[12f(x0)+∑i=1n−1f(xi)+12f(xn)].T_n=h\left[\frac12 f(x_0)+\sum_{i=1}^{n-1}f(x_i) +\frac12 f(x_n)\right].
NodeNumber of neighboring panelsComposite weight
x0x_01h/2h/2
x1,…,xn−1x_1,\ldots,x_{n-1}2hh
xnx_n1h/2h/2

There are nn panels and n+1n+1 sampled heights. The weights carry the units of the integration variable.

Taylor expansion identifies the trapezoid error

Expand around the left endpoint:

Ti=hfi+h22fi′+h34fi′′+O(h4),T_i=h f_i+\frac{h^2}{2}f'_i+\frac{h^3}{4}f''_i+O(h^4),

whereas the exact panel integral is

Ii=hfi+h22fi′+h36fi′′+O(h4).I_i=h f_i+\frac{h^2}{2}f'_i+\frac{h^3}{6}f''_i+O(h^4).

Therefore Ti−Ii=h312fi′′+O(h4)T_i-I_i=\frac{h^3}{12}f''_i+O(h^4). The local error is O(h3)O(h^3); summing over a fixed interval gives O(h2)O(h^2).

Predict: sine is concave down on [0,π/2][0,\pi/2]. Does the chord lie above or below the curve, and what sign should Tn−IT_n-I have?

Compare the local approximations

Three panels compare the exponential on zero to one with a left-endpoint constant, an endpoint line, and a quadratic through zero, one half, and one. Shading shows the area under each approximating polynomial.

Quadrature integrates the approximating polynomial. The difference between that polynomial and the function determines the quadrature error.

Reference · trapezoid geometry and error

FeatureConsequence
Line through two endpointsExact for linear functions in exact arithmetic
Interior node shared by two panelsFull interior weight, half endpoint weights
Leading local error proportional to h3f′′h^3 f''Composite error bounded by a constant times h2h^2
Concave-down integrandChords underestimate the area

Rule: use curvature to predict the error sign before running the calculation.

II · Simpson uses a quadratic and symmetry

Why can an integral gain accuracy beyond the pointwise degree of its interpolant?

Goals

  • derive weights 1,4,11,4,1 across a pair of panels;

  • explain why composite Simpson requires an even panel count;

  • use symmetry to explain cubic exactness; and

  • state the smoothness assumptions behind fourth-order accuracy.

Fit a quadratic across two panels

Let mm be the midpoint of a two-panel interval [m−h,m+h][m-h,m+h]. Write its interpolating quadratic as

P(s)=A+Bs+Cs2,s=x−m.P(s)=A+Bs+Cs^2,\qquad s=x-m.

The three sample values determine the coefficients:

A=f(m),C=f(m−h)−2f(m)+f(m+h)2h2.A=f(m),\qquad C=\frac{f(m-h)-2f(m)+f(m+h)}{2h^2}.

The integral of BsBs over [−h,h][-h,h] is zero. Therefore

∫−hhP(s) ds=2hA+2h33C.\int_{-h}^{h}P(s)\,ds=2hA+\frac{2h^3}{3}C.

The coefficients give Simpson’s weights

Substitute AA and CC into the integral:

Spair=h3[f(m−h)+4f(m)+f(m+h)].S_{\rm pair}=\frac{h}{3}\bigl[f(m-h)+4f(m)+f(m+h)\bigr].

Here hh is the width of one panel. The pair has width 2h2h.

Check the units and weights: for f(x)=1f(x)=1, the result must be the interval length, 2h2h. The weights sum to (h/3)(1+4+1)=2h(h/3)(1+4+1)=2h.

Predict: is a cubic integrated exactly? A quadratic interpolant does not reproduce a cubic point by point, so explain your reasoning about its integral.

Symmetry cancels the cubic contribution to the error

Expand a smooth function about the midpoint:

f(m+s)=fm+sfm′+s22fm′′+s36fm′′′+s424fm(4)+⋯ .f(m+s)=f_m+s f'_m+\frac{s^2}{2}f''_m +\frac{s^3}{6}f'''_m+\frac{s^4}{24}f^{(4)}_m+\cdots.

Both the symmetric integral and Simpson’s symmetric weights cancel odd terms. The constant and quadratic contributions agree. The first possible mismatch is the fourth-derivative term.

Derive the Simpson error coefficient

For the fourth-order term, the integral contributes h5fm(4)/60h^5 f^{(4)}_m/60 and Simpson contributes h5fm(4)/36h^5 f^{(4)}_m/36. Their difference is (1/60−1/36)h5fm(4)=−h5fm(4)/90(1/60-1/36)h^5 f^{(4)}_m=-h^5 f^{(4)}_m/90. This identifies the coefficient. The error theorem makes the remainder exact: for f∈C4f\in C^4 on the pair, there is a point ξ\xi in it such that

Ipair−Spair=−h590f(4)(ξ).I_{\rm pair}-S_{\rm pair}=-\frac{h^5}{90}f^{(4)}(\xi).

The paired local error is O(h5)O(h^5) and the composite error is O(h4)O(h^4). For a cubic, the fourth derivative vanishes: Simpson is exact in exact arithmetic.

Pair the panels to build composite Simpson

Sn=h3[f(x0)+4∑i=1i oddn−1f(xi)+2∑i=2i evenn−2f(xi)+f(xn)].S_n=\frac{h}{3}\left[f(x_0) +4\sum_{\substack{i=1\\i\text{ odd}}}^{n-1}f(x_i) +2\sum_{\substack{i=2\\i\text{ even}}}^{n-2}f(x_i)+f(x_n)\right].
  • Endpoint weights: 1.

  • Odd-index interior weights: 4.

  • Even-index interior weights: 2 because they join adjacent pairs.

  • Multiply the sum by h/3h/3.

The panel count nn must be positive and even for this composite rule. An odd count is an invalid input, not a reason to silently change the grid.

Translate the weights into array slices

Suppose y = f(nodes) contains the n+1n+1 endpoint heights:

ExpressionSelected values
y[0], y[-1]Endpoints
y[1:-1]All interior heights, for trapezoid
y[1:-1:2]Odd-index interior heights, for Simpson
y[2:-1:2]Even-index interior heights, for Simpson

For n=4n=4, write the five weights on paper. Check that neither endpoint appears inside an interior sum. The complete implementations are your next exercise.

Compare the rectangle samples

Same integrand, same six panels: f(x)=e−x/2cos⁡(2x)+1f(x)=e^{-x/2}\cos(2x)+1 on [0,2][0,2].

Left and midpoint rectangles on the same six panels; their sample positions differ. The midpoint estimate has a smaller absolute error on this grid.

Explain: why does midpoint sampling give the smaller error on this grid?

Compare the endpoint interpolants

Trapezoid chords and paired Simpson quadratics use the same seven endpoints. The quadratic tracks this integrand more closely on these six panels.

Explain: why do both rules use seven heights for six panels?

Reference: all four methods and numerical values.

Explain the sample count

On this grid, Simpson has the smallest error; midpoint beats trapezoid. One grid does not establish convergence order or a universal ranking.

Explain: why do the endpoint rules need seven sampled heights for six panels? Where do neighboring Simpson pairs reuse a height?

Orders need a smoothness condition

For equal panel widths on a fixed interval:

RuleSufficient derivative boundComposite error bound
Left rectangleM1=max⁡∣f′∣M_1=\max\lvert f'\rvert(b−a)hM1/2(b-a)hM_1/2
TrapezoidM2=max⁡∣f′′∣M_2=\max\lvert f''\rvert(b−a)h2M2/12(b-a)h^2M_2/12
SimpsonM4=max⁡∣f(4)∣M_4=\max\lvert f^{(4)}\rvert(b−a)h4M4/180(b-a)h^4M_4/180

Assume the corresponding derivatives are continuous on [a,b][a,b], with a<ba<b. The bounds concern exact-arithmetic quadrature, not floating-point rounding.

When a needed derivative is unbounded or discontinuous, the usual error theorem does not supply that guarantee. We will investigate such an example later.

Reference · a corner changes the error pattern

Interpret: why does the corner in g(x)=ex+∣x−0.2∣g(x)=e^x+|x-0.2| invalidate the usual Simpson bound on [0,1][0,1]? Explain the effect of splitting at 0.2.

The left panel shows a corner at 0.2, marked by a dashed vertical line. The right log-log panel compares smooth exponential, unsplit corner, and split corner Simpson errors. Splitting restores fourth-order decay on this sequence, while the unsplit corner has roughly second-order decay.

Compare the smooth, unsplit, and split error curves at the same total panel count.

Open full-size figure.

Reference · why splitting at a corner helps

Each calculation uses n+1n+1 distinct samples. The split rule uses half the panels on each side and reuses the shared endpoint.

Each side is smooth: the quadratic no longer crosses the corner. This previews the reading’s investigation. Grid alignment can cancel an error term, so an observed slope alone does not prove smoothness.

Reference · composite Simpson

FeatureMeaning
n positive and evenEvery panel belongs to a pair
n + 1 heightsBoth boundaries and all interior nodes are sampled
Weights 1, 4, 2, ..., 4, 1Pair weights accumulated across the grid
Overall factor h / 3h is one panel’s width, not a pair’s width
Exact cubic integralA check of weights and indexing, up to rounding

Rule: polynomial exactness and measured convergence order are different checks.

III · A module gives a function an importable home

How can a notebook and a test call the same numerical implementation?

Goals

  • separate method definitions from analysis and tests;

  • import a local module and account for cached notebook imports;

  • recognize how pytest finds and runs tests; and

  • translate a stated tolerance into a pytest.approx assertion.

Give each file one role

quadrature-lab/
├── integrate.py
├── tests/
│   └── test_integrate.py
└── analysis.ipynb
  • integrate.py defines numerical methods.

  • The notebook imports them, makes figures, and explains results.

  • Test files import them and check specified behavior.

A notebook can contain assertions and be tested by execution. Modules make functions easier to import and test independently of notebook state.

Imports connect the files

In a notebook located in the lab directory:

import numpy as np
from integrate import rectangle

estimate = rectangle(np.sin, 0.0, np.pi/2, 100)

Python executes a module’s top-level statements when it first imports it in a process. Keep demonstration runs and plotting out of the module’s top level.

After editing the module, restart the notebook kernel and run from the top. Importing again does not normally reload a module already in memory.

What pytest does

pytest discovers test functions, calls them, and reports failed assertions and unexpected exceptions.

def test_example():
    result = 2 + 3
    assert result == 5

For this lab, use files named test_*.py and functions named test_*. An assertion should test a behavior you can explain.

Run from the directory containing integrate.py:

python -m pytest

If pytest is missing, install it in the same course environment with python -m pip install pytest, then rerun the command.

Carry rtol and atol into tests carefully

NumPy uses rtol and atol. pytest.approx uses rel and abs:

assert actual == pytest.approx(expected, rel=0.0, abs=error_bound)

For finite scalar values and both allowances explicitly supplied, pytest.approx permits a discrepancy up to

max⁡(abs,rel ∣expected∣).\max(\mathrm{abs},\mathrm{rel}\,\lvert\mathrm{expected}\rvert).

NumPy adds its allowances. These APIs therefore differ when both allowances are nonzero. With rel=0.0, our test has one explicit absolute criterion.

Source: pytest approx documentation.

Reference · modules and tests

PatternPurpose
from integrate import rectangleImport the shared implementation
tests/test_integrate.pyA discoverable home for lab tests
def test_rectangle_sine():One named behavior check
pytest.approx(reference, rel=0.0, abs=bound)An explicit absolute comparison
python -m pytestRun tests using this Python environment

Rule: a test should expose a plausible mistake, not repeat the implementation.

IV · Lab: rectangle integration of sine

Can another file import your rule and verify a claim about its result?

Goals

  • complete an importable rectangle module;

  • justify a sine-integral test with a derivative bound;

  • test an invalid-input contract; and

  • interpret a deliberate failure without weakening a justified criterion.

Predict · the sine integral and the module contract

Work with a partner to discuss the design; write and run your own implementation.

∫0π/2sin⁡x dx=1.\int_0^{\pi/2}\sin x\,dx=1.

Before typing:

  1. Sketch the curve and two left rectangles.

  2. Predict whether the result is above or below 1.

  3. State which endpoint is omitted from the sampled heights.

  4. Write the input and output contract for rectangle(f, a, b, n).

Use the known rectangle mathematics to concentrate on modules and tests.

Lab step 1 · Create integrate.py

Start with this skeleton and complete it using Lecture 5:

import numpy as np

def rectangle(f, a, b, n):
    """Approximate an integral using n left rectangles.

    f accepts and returns matching arrays of finite values.
    a and b are finite scalar limits; n is a positive integer.
    Return one float. Invalid n raises ValueError.
    """
    # Validate n, excluding bool and non-integer values.
    # Compute the panel width and n left endpoints.
    # Evaluate f at those endpoints and return the weighted sum.
    raise NotImplementedError("Complete the rectangle rule")

The placeholder is intentional; replace it with your implementation. Do not hard-code np.sin inside the rule.

Lab step 2 · Choose the tolerance before running the test

Lecture 5 established

∣I−Ln∣≤(b−a)22nM1.\lvert I-L_n\rvert\le\frac{(b-a)^2}{2n}M_1.

For sin⁡x\sin x on [0,π/2][0,\pi/2], M1=max⁡∣cos⁡x∣=1M_1=\max\lvert\cos x\rvert=1. At n=100n=100, the bound is π2/800≈0.01234\pi^2/800\approx0.01234.

Use this absolute bound for the known-integral test. The sine result has room below this conservative bound, much larger than rounding effects here.

Explain: a correct left-rectangle rule at n=100n=100 fails a 10-12 accuracy demand here. Why is that a tolerance problem rather than evidence of an implementation bug?

Lab step 3 · Write the known-integral test

Save this in tests/test_integrate.py:

import numpy as np
import pytest
from integrate import rectangle

def test_rectangle_sine():
    n = 100
    estimate = rectangle(np.sin, 0.0, np.pi/2, n)
    error_bound = np.pi**2 / (8*n)
    assert np.isfinite(estimate)
    assert estimate < 1.0  # increasing sine: left rectangles underestimate
    assert estimate == pytest.approx(1.0, rel=0.0, abs=error_bound)

Run python -m pytest. If the test fails, read the actual value and expected range before changing any code or tolerance.

Lab step 4 · Check invalid inputs

Append this test to the same file:

@pytest.mark.parametrize("bad_n", [0, -2, 2.5, True])
def test_rectangle_rejects_invalid_panel_count(bad_n):
    with pytest.raises(ValueError, match="positive integer"):
        rectangle(np.sin, 0.0, np.pi/2, bad_n)

parametrize runs the function once for each listed value. raises checks the exception type; match checks the message for the named problem.

If validation is missing, a division error is not the required ValueError. An error message is part of making the function usable.

Lab step 5 · Make a failure informative

Temporarily change the accuracy tolerance to abs=1e-12, leaving rel=0.0. Run the test and read the discrepancy it reports.

  • Is the calculation inconsistent with the first-order bound?

  • Or is this new accuracy demand unsupported at n=100n=100?

Restore the justified bound, rerun the tests, and import the rule into a clean notebook. Print the estimate and its absolute error.

If time remains, double n and compare the error ratio with the first-order prediction. The bound test alone does not establish convergence order.

What the lab establishes

EvidenceSupported claimRemaining limitation
Imported function runsThis module is usable from this environmentOther input contracts still need checking
Sine test passesThis case meets a justified bound and has the expected signOne case cannot establish general correctness
Invalid counts raiseThe listed invalid inputs fail as specifiedOther invalid inputs were not tested
Error ratio approaches 2This sequence is consistent with first-order errorThe conclusion is local to the tested regime

Testing a function, measuring its convergence, and validating a physical model answer different questions.

Documentation for the next question

ResourceUse it for
Python modules tutorialImports and module behavior
pytest getting startedTest discovery and a first run
pytest assertionsFailure reports and expected exceptions
pytest approxAbsolute and relative comparison semantics

Read a failure report alongside the test’s stated claim and the function’s contract. Check the documented API before changing the implementation.

Exit check

  1. Why does the trapezoid rule have half weights at the two endpoints?

  2. Why must composite Simpson use an even panel count?

  3. Why can Simpson integrate cubics exactly using quadratic interpolation?

  4. Where do reusable functions, figures, and tests belong?

  5. Why did the lab use rel=0.0 and an absolute error bound?

Carry forward

Implement trapezoid and Simpson with the same callable interface, then measure their convergence. Use a cubic integral as an independent Simpson check.

Your notebook imports the methods and explains their results. Your tests make specific contracts executable. Next class we will use error measurements to assess convergence and choose how much work an accuracy target requires.