# newton
A small Python library for finding roots of single-variable expressions with
Newton-Raphson iteration.
## Tutorial
We are going to approximate \(\sqrt{2}\) by finding the positive root of
\(f(x) = x^2 - 2\). We start by declaring a symbol and importing the
library:
```python
>>> import sympy as sym
>>> import newton
>>> x = sym.Symbol("x")
```
A single Newton step from \(x_0 = 1\) gives
\[
x_1 = x_0 - \frac{f(x_0)}{f'(x_0)} = 1 - \frac{-1}{2} = \frac{3}{2}.
\]
We can confirm this with the library:
```python
>>> newton.newton_step(x ** 2 - 2, x, sym.S(1))
3/2
```
To collect a list of successive iterates, we call `iterate`:
```python
>>> iterates = newton.iterate(x ** 2 - 2, x, sym.S(1), number_of_iterations=4)
>>> iterates
[1, 3/2, 17/12, 577/408, 665857/470832]
```
Each iterate is held as an exact rational. To get a closed answer we use
`find_root`, which stops as soon as two successive iterates agree to within
a tolerance:
```python
>>> root, iterations = newton.find_root(
... x ** 2 - 2,
... x,
... sym.S(1),
... tolerance=10 ** -10,
... maximum_iterations=50,
... )
>>> round(float(root), 8)
1.41421356
```
The number of iterations taken is small:
```python
>>> iterations
5
```
## How to guide
### How to take a single Newton step
To take one Newton step from `current_value` on the expression `expression`
in the symbol `variable`:
```python
>>> import sympy as sym
>>> import newton
>>> x = sym.Symbol("x")
>>> newton.newton_step(x ** 3 - 8, x, sym.S(1))
10/3
```
### How to collect a sequence of iterates
To collect the first `number_of_iterations + 1` iterates of Newton-Raphson:
```python
>>> import sympy as sym
>>> import newton
>>> x = sym.Symbol("x")
>>> newton.iterate(x ** 2 - 2, x, sym.S(2), number_of_iterations=3)
[2, 3/2, 17/12, 577/408]
```
### How to find a root to a given tolerance
To iterate until two successive iterates agree to within `tolerance`, or
until `maximum_iterations` steps have been taken:
```python
>>> import sympy as sym
>>> import newton
>>> x = sym.Symbol("x")
>>> root, iterations = newton.find_root(
... x ** 3 - 8,
... x,
... sym.S(1),
... tolerance=10 ** -8,
... maximum_iterations=50,
... )
>>> round(float(root), 6)
2.0
```
## Discussion
Newton-Raphson is a method for finding a root of a differentiable function
\(f\). Starting from an initial guess \(x_0\) close to a root, the method
updates the iterate by
\[
x_{n + 1} = x_n - \frac{f(x_n)}{f'(x_n)}.
\]
Geometrically each step replaces \(f\) by its tangent line at \(x_n\) and
takes the root of that line as the new iterate. When the method converges
to a simple root the error is squared at each step: this is the
quadratic-convergence property that makes Newton-Raphson the standard
choice when a derivative is available.
The method can fail to converge: a poor initial guess can land the iterate
in a region where the derivative is small, and the next step can overshoot.
A `maximum_iterations` cap protects against this. We return both the final
iterate and the number of iterations taken so the caller can detect that
the cap was reached.
### How we built this
We keep the iterates symbolic by using `sympy` because this avoids
floating-point drift in the early steps; we only call `float` when we
report the final answer. The derivative is computed inside `newton_step`
with `sympy.diff`, and the substitution at the current value uses the
dict form `expression.subs({variable: current_value})`. The library
accepts both symbolic and numeric inputs, but a symbolic `current_value`
(using `sympy.S`) gives the cleanest trail of iterates [1].
## Reference
### List of functionality
A list of functionality in this library is:
- `newton_step(expression, variable, current_value)`: apply one
Newton-Raphson step.
- `iterate(expression, variable, initial_value, number_of_iterations)`:
collect the first `number_of_iterations + 1` iterates.
- `find_root(expression, variable, initial_value, tolerance,
maximum_iterations)`: iterate to a tolerance.
### Tests
The tests live in `test_newton.py` and can be run with:
```sh
python test_newton.py
```
The tests cover all three functions, check that the iterates have the
expected exact rational form, and check that `find_root` recovers
\(\sqrt{2}\) and \(2\) (as the real root of \(x^3 - 8\)) to within
tolerance.
### Bibliography
[1] Knight, V. *Python for Mathematics*, vknight.org/pfm. Accessed 2026.