Skip to content

Commit db0c64b

Browse files
jamesjames
authored andcommitted
Add maths/numerical_analysis/lagrange_interpolation.py
Implements Lagrange polynomial interpolation for arbitrarily spaced data points. Unlike Newton's forward-difference formula (which requires equidistant x-values), Lagrange interpolation works with any distinct x_points. Includes full type hints, 9 doctests, and raises ValueError for mismatched lengths, too few points, or duplicate x-values. References: - https://en.wikipedia.org/wiki/Lagrange_polynomial - https://mathworld.wolfram.com/LagrangeInterpolatingPolynomial.html
1 parent 144ef9c commit db0c64b

1 file changed

Lines changed: 94 additions & 0 deletions

File tree

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
"""
2+
Lagrange Interpolation
3+
4+
Given n+1 data points (x0, y0), (x1, y1), ..., (xn, yn) with distinct x-values,
5+
the Lagrange interpolating polynomial is the unique polynomial of degree <= n that
6+
passes through all given points.
7+
8+
For each i, the basis polynomial is:
9+
L_i(x) = product_{j != i} (x - x_j) / (x_i - x_j)
10+
11+
The interpolating polynomial is:
12+
P(x) = sum_i y_i * L_i(x)
13+
14+
Unlike Newton's forward-difference formula, Lagrange interpolation works for
15+
arbitrarily spaced data points.
16+
17+
References:
18+
- https://en.wikipedia.org/wiki/Lagrange_polynomial
19+
- https://mathworld.wolfram.com/LagrangeInterpolatingPolynomial.html
20+
"""
21+
22+
from __future__ import annotations
23+
24+
25+
def lagrange_interpolation(x_points: list[float], y_points: list[float], x: float) -> float:
26+
"""
27+
Estimate f(x) using the Lagrange interpolating polynomial through the
28+
given data points (x_points[i], y_points[i]).
29+
30+
:param x_points: List of distinct x-coordinates of the data points.
31+
:param y_points: List of y-coordinates corresponding to x_points.
32+
:param x: The x-value at which to evaluate the interpolating polynomial.
33+
:return: The interpolated value P(x).
34+
:raises ValueError: If x_points and y_points have different lengths,
35+
if fewer than 2 points are given, or if x_points
36+
contains duplicate values.
37+
38+
Examples — interpolating through known points of f(x) = x^2:
39+
>>> lagrange_interpolation([1, 2, 3], [1, 4, 9], 2.5)
40+
6.25
41+
>>> lagrange_interpolation([1, 2, 3], [1, 4, 9], 1.5)
42+
2.25
43+
>>> lagrange_interpolation([1, 2, 3], [1, 4, 9], 3.0)
44+
9.0
45+
46+
Two-point linear interpolation:
47+
>>> lagrange_interpolation([0, 1], [0, 1], 0.5)
48+
0.5
49+
>>> lagrange_interpolation([0, 2], [0, 4], 1.0)
50+
2.0
51+
52+
Four points from f(x) = x^3, interpolated at a non-grid point:
53+
>>> lagrange_interpolation([0, 1, 2, 3], [0, 1, 8, 27], 1.5)
54+
3.375
55+
56+
Error cases:
57+
>>> lagrange_interpolation([1, 2], [1], 1.5)
58+
Traceback (most recent call last):
59+
...
60+
ValueError: x_points and y_points must have the same length
61+
>>> lagrange_interpolation([1], [1], 1.0)
62+
Traceback (most recent call last):
63+
...
64+
ValueError: at least 2 data points are required
65+
>>> lagrange_interpolation([1, 1, 3], [1, 2, 3], 2.0)
66+
Traceback (most recent call last):
67+
...
68+
ValueError: x_points must be distinct (duplicate found: 1)
69+
"""
70+
if len(x_points) != len(y_points):
71+
raise ValueError("x_points and y_points must have the same length")
72+
n = len(x_points)
73+
if n < 2:
74+
raise ValueError("at least 2 data points are required")
75+
seen: set[float] = set()
76+
for val in x_points:
77+
if val in seen:
78+
raise ValueError(f"x_points must be distinct (duplicate found: {val})")
79+
seen.add(val)
80+
81+
result = 0.0
82+
for i in range(n):
83+
basis = 1.0
84+
for j in range(n):
85+
if j != i:
86+
basis *= (x - x_points[j]) / (x_points[i] - x_points[j])
87+
result += y_points[i] * basis
88+
return result
89+
90+
91+
if __name__ == "__main__":
92+
import doctest
93+
94+
doctest.testmod()

0 commit comments

Comments
 (0)