Skip to main content

A fast and robust root-finding library written in C for Python, using the Modified Anderson-Bjork method: Ganchovski, N.; Smith, O.; Rackauckas, C.; Tomov, L.; Traykov, A. Improvements to the Modified Anderson–Björck(modAB) Root-Finding Algorithm. Algorithms 2026, 19, 332. https://doi.org/10.3390/a19050332 It finds the root of a single nonlinear equation f(x) = 0 within the specified interval [x1, x2].

Installation

pip install pymodab

Usage

import math
from pymodab import find_root, get_evaluation_count

# Find the root of cos(x) - x = 0 in [0, 1]
root = find_root(lambda x: math.cos(x) - x, 0, 1, 1e-3, 1e-3, 10)
print(f"Root: {root}")  # 0.7390851332086904

# Get the number of function evaluations
print(f"Evaluations: {get_evaluation_count()}")
print(f"Error:       {math.cos(root) - root}")

# Using default tolerances
root = find_root(lambda x: x**2 - 2, 1, 2)
print(f"sqrt(2) = {root}")  # 1.414213562373095

# Get the number of function evaluations
print(f"Evaluations: {get_evaluation_count()}")
print(f"Error:       {root**2 - 2}")

API

find_root(f, x1, x2, atol=1e-14, rtol=1e-14, max_iter=200)

Find the root of f(x) = 0 within the interval [x1, x2].

Parameters:

  • f: A continuous function of one variable, or the address (int) of a compiled C function double f(double)
  • x1, x2: Bracket interval endpoints (must satisfy f(x1) * f(x2) < 0)
  • atol: Absolute tolerance (default: 1e-14)
  • rtol: Relative tolerance (default: 1e-14)
  • max_iter: Maximum iterations (default: 200)

Returns: The root, or NaN if not found. Exceptions raised by f are propagated to the caller. This holds for the native extension only: with the ctypes fallback (pymodab.NATIVE is False), an exception in f is only printed to stderr, the search goes on with an undefined value of f(x), and the result cannot be trusted; it may be NaN or a wrong root.

Since version 1.0.6, find_root is a native CPython extension that calls f directly, which is about 2x faster than the previous ctypes wrapper. Version 1.0.7 ships it as a wheel for Windows, Linux (x86_64 and aarch64, glibc and musl) and macOS (Intel and Apple Silicon); one wheel serves every CPython from 3.8 up. On any other platform pymodab falls back to ctypes automatically; pymodab.NATIVE tells which one is used.

Version 1.0.8 improves the fallback from secant to bisection steps: a secant step that does not shrink the bracket fast enough is still kept if it at least halves the best residual of the bracket. This avoids needless bisection steps when the secant converges from one side, and falls back sooner when it stalls. get_evaluation_count() now returns the exact number of calls to f. Version 1.0.9 ships that work as wheels for every supported platform.

Version 1.0.10 adds overflow and NaN safeguards to the arithmetic. The midpoint and the secant point are computed without forming x1 + x2 or x1*y2 - x2*y1, so they stay finite and inside the bracket even for endpoints or residuals near the floating-point limits. A NaN from f stops the search with NaN instead of corrupting the bracket. The Anderson-Björck scaling never lets an auxiliary ordinate underflow to zero. The new secant formula rounds differently, so single problems may need a few evaluations more or less; the 100 benchmark problems below need 1895 in total instead of 1897.

Version 1.1.0 simplifies these safeguards without weakening them. The test that switches from bisection to secant steps is now computed inline as |ym - y3| < k·|ym| + k·|y3|, which cannot overflow, and it is skipped while f(x2) - f(x1) overflows, so the search keeps bisecting until the residuals shrink. The bracket is updated from the sign of the true residuals instead of the Anderson-Björck auxiliary ordinates, so an auxiliary ordinate that underflows to zero can no longer steer the update, and the extra underflow guard of 1.0.10 is no longer needed. The 100 benchmark problems give the same roots and evaluation counts as with 1.0.10.

Version 1.1.1 separates the bisection and Anderson-Björck steps in the solver loop. A bisection step now updates only the bracket and the true residuals. The Anderson-Björck corrections and the fallback test run only on secant steps, and the auxiliary ordinates start from the true residuals whenever the search switches to secant steps. It also caps the residual exception of 1.0.8: a secant step that does not shrink the bracket fast enough is kept on the strength of halving the residual for at most three consecutive steps (MAX_RESIDUAL_STEPS), after which the search falls back to bisection anyway. Without the cap, f(x) = -x*x for x < 0 and 7*x*x for x >= 0 on [-π, 1], a counterexample by L. Tomov, keeps halving the residual while the bracket never gets narrower than 1, and the search runs out of iterations; with the cap it converges in 76 evaluations. This function is now problem f101 of the benchmark. The other 100 problems give the same roots and evaluation counts as with 1.1.0; all 101 need 1971 evaluations in total.

Version 1.1.2 streamlines the solver loop. The bracket width and the difference of the true residuals are computed once per step and reused. The exits on a zero and on a NaN residual share a single test on the hot path. The best true residual of the bracket, which the fallback test needs, is now computed only when a secant step fails to shrink the bracket fast enough, instead of on every secant step, and the test is written as 2·|y3| >= ymin instead of |y3| >= 0.5·ymin. The 101 benchmark problems give the same roots and evaluation counts as with 1.1.1.

Version 1.1.3 replaces the capped residual exception of 1.1.1 with a stricter test and removes the MAX_RESIDUAL_STEPS counter. A secant step that does not shrink the bracket fast enough is now kept only if it reduces the residual more than 42 times, that is 42·|y3| < ymin, where ymin is the smaller true residual of the bracket. The factor comes from 2^(1074/200) ≈ 41.4: at this rate a residual that starts near 1 underflows to zero within the default limit of 200 iterations, because the smallest positive double is 2^-1074. A search that stays on secant steps this way therefore ends by itself, without a counter. The factor is a fixed constant and does not follow max_iter, so raising the limit does not weaken the test. On the benchmark, problem f101 now needs 65 evaluations instead of 76, and the other 100 problems give the same roots and evaluation counts as with 1.1.2; all 101 need 1960 evaluations in total instead of 1971.

For maximum speed, pass a compiled function, e.g. from numba. It is then called from C with no Python overhead:

import math
from numba import cfunc
from pymodab import find_root

@cfunc("float64(float64)")
def f(x):
    return math.cos(x) - x

root = find_root(f.address, 0, 1)

get_evaluation_count()

Returns the number of function evaluations from the last root-finding call.

Algorithm

Modified Anderson-Björck's method is a new robust and efficient bracketing root-finding algorithm. It combines bisection with Anderson-Björk's method to achieve both fast performance and worst-case optimality.

References:

Ganchovski N.; Traykov A. Modified Anderson-Björck's method for solving non-linear equations in structural mechanics. IOP Conference Series: Materials Science and Engineering 2023, 1276 (1) 012010, IOP Publishing.
https://iopscience.iop.org/article/10.1088/1757-899X/1276/1/012010/pdf

Ganchovski, N.; Smith, O.; Rackauckas, C.; Tomov, L.; Traykov, A. Improvements to the Modified Anderson–Björck (modAB) Root-Finding Algorithm. Algorithms 2026, 19, 332. https://doi.org/10.3390/a19050332

License

MIT License

Benchmark results

The modAB algorithm is benchmarked against the available algorithms in Python/SciPy in respect to number of evaluations and execution times:

  • bisect- Bisection method
  • brentq - Brent’s method (van Wijngaarden–Dekker–Brent, 1973)
  • brenth - Brent–Dekker variant (hyperbolic extrapolation variant, 1975)
  • ridder - Ridder’s method (1979)
  • toms748 - Alefeld–Potra–Shi method (1995 - TOMS Algorithm 748)
  • chandr - Chandrupatla's method (1997) - scipy.optimize.elementwise.find_root
  • cybrentq - Cython implementation of brentq by Gledis Caushaj
  • modAB_SG - Safeguarded Modified Anderson Bjork's method (Ganchovski & Traykov, 2023; improved 2026 by L.Tomov and N.Ganchovski)
  • modAB_ct - the old version of pymodab 1.0.5 implemented with ctypes

Function evaluations

Func bisect brentq brenth ridder chandr cybrentq modAB_ct modAB_SG
SUM 4883 2810 2769 3425 2112 2810 1993 1960
AVG 48 28 27 34 21 28 20 19
MEDIAN 49 13 12 16 12 13 13 13
MIN 3 4 4 3 3 4 3 3
MAX 53 102 102 202 70 102 78 65
FACTOR 2.491x 1.434x 1.413x 1.747x 1.078x 1.434x 1.017x 1.000x

Execution times (ms per problem, 200 iterations)

Func bisect brentq brenth ridder chandr cybrentq modAB_ct modAB_SG
SUM 1535.42 931.31 878.87 1047.95 58524.74 115.55 175.60 91.23
AVG 15.2021 9.2209 8.7017 10.3758 579.4528 1.1440 1.7386 0.9033
MEDIAN 14.7569 5.1910 4.9383 6.4764 345.7968 0.5879 1.3410 0.6511
MIN 1.7242 1.8918 1.8852 2.0780 73.8264 0.2071 0.5655 0.1677
MAX 70.1038 32.1594 41.2759 53.5572 1979.9811 6.4304 5.1045 3.8393
FACTOR 16.829x 10.208x 9.633x 11.486x 641.480x 1.266x 1.925x 1.000x

Notes:

Last Run on: 01.11.2026
Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz (1.50 GHz) with 16.0 GB RAM
Windows 11 Home
Python Version: 3.14.7
numpy Version: 2.4.6
scipy Version: 1.18.0
cybrentq Version: 0.1.5 - by Gledis Caushaj (https://github.com/gledi-ai/cybrentq)
modAB_ct: pymodab version 1.0.5 from PyPI - the previous implementation with ctypes
modAB_SG: pymodab version 1.1.3 - the latest implementation of the safeguarded modab as native C extension

Metadata

Release files for pymodab 1.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pymodab 1.1.3
File Size Uploaded Provenance Actions
pymodab-1.1.3.tar.gz 121.8 kB Without provenance Details for pymodab-1.1.3.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for pymodab 1.1.3
File Actions
pymodab-1.1.3-py3-none-any.whl Python 3 none any Details for pymodab-1.1.3-py3-none-any.whl
pymodab-1.1.3-cp38-abi3-win_amd64.whl CPython 3.8 abi3 Windows x86-64 Details for pymodab-1.1.3-cp38-abi3-win_amd64.whl
pymodab-1.1.3-cp38-abi3-musllinux_1_2_x86_64.whl CPython 3.8 abi3 Linux musl 1.2+ x86-64 Details for pymodab-1.1.3-cp38-abi3-musllinux_1_2_x86_64.whl
pymodab-1.1.3-cp38-abi3-musllinux_1_2_aarch64.whl CPython 3.8 abi3 Linux musl 1.2+ ARM64 Details for pymodab-1.1.3-cp38-abi3-musllinux_1_2_aarch64.whl
pymodab-1.1.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl CPython 3.8 abi3 Linux glibc 2.17+ ARM64, Linux glibc 2.28+ ARM64 Details for pymodab-1.1.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
pymodab-1.1.3-cp38-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl CPython 3.8 abi3 Linux glibc 2.5+ x86-64, Linux glibc 2.28+ x86-64 Details for pymodab-1.1.3-cp38-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
pymodab-1.1.3-cp38-abi3-macosx_10_9_universal2.whl CPython 3.8 abi3 macOS 10.9+ universal2 (ARM64, x86-64) Details for pymodab-1.1.3-cp38-abi3-macosx_10_9_universal2.whl

Total release size: 352.1 kB

Release files / pymodab-1.1.3.tar.gz

Download URL pymodab-1.1.3.tar.gz
Size 121.8 kB
Tags Source
SHA-256 checksum
How to use checksums
efa61c952e955778a9250f952254aa8245d338070aa7d5ea2d1008900dfdb87f
BLAKE2b-256 checksum
How to use checksums
26834981e592b22c84d8b965d38e3cbafcc3c7c3face48614a9d2aa0949de9eb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.7

Release files / pymodab-1.1.3-py3-none-any.whl

Download URL pymodab-1.1.3-py3-none-any.whl
Size 110.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a06e72d68f516ee14bcbcd126b7b64f14122019ac7e2470619f4787dfcf80940
BLAKE2b-256 checksum
How to use checksums
98dea91ce9d593a759e54b317471176a0286dc5fc59883e24ee26c1dda7f003e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.7

Release files / pymodab-1.1.3-cp38-abi3-win_amd64.whl

Download URL pymodab-1.1.3-cp38-abi3-win_amd64.whl
Size 15.7 kB
Tags CPython 3.8 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
aff08b299ce61543837f00c436e8d6c69fba6f42e8a988db01405b1fff42fe75
BLAKE2b-256 checksum
How to use checksums
c73cacf17252fbb608dd37ff0784bc41129f39d33725f022650954308da218d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.7

Release files / pymodab-1.1.3-cp38-abi3-musllinux_1_2_x86_64.whl

Download URL pymodab-1.1.3-cp38-abi3-musllinux_1_2_x86_64.whl
Size 21.6 kB
Tags CPython 3.8 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
c9760bf991a62e531b3a2d33a1a04366253eb95122f96080fea4e17541245a58
BLAKE2b-256 checksum
How to use checksums
cac1bb8759d6ed6961ebd01a8109bb7f351d33f2a0f129d49f9bb77418e3663b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.7

Release files / pymodab-1.1.3-cp38-abi3-musllinux_1_2_aarch64.whl

Download URL pymodab-1.1.3-cp38-abi3-musllinux_1_2_aarch64.whl
Size 21.9 kB
Tags CPython 3.8 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
6fed18074d7f6f8bc2ed2de18ea05c81b87231bd33eefe4faa72f79320ef0943
BLAKE2b-256 checksum
How to use checksums
e66ac9a3a19e32dd8fb931cc9547992b66ae4ef845f433295840bf09e8603f15
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.7

Release files / pymodab-1.1.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl

Download URL pymodab-1.1.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
Size 21.8 kB
Tags CPython 3.8 Linux glibc 2.17+ ARM64 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
2ec122173e273be2618c062f4e5bac74e8262b3ac541c473487718748ce222d1
BLAKE2b-256 checksum
How to use checksums
7b42781ac35ec0142a5f00b8e5767c6ba88e20371c3780b1bd490dc96c16bbde
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.7

Release files / pymodab-1.1.3-cp38-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl

Download URL pymodab-1.1.3-cp38-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Size 21.0 kB
Tags CPython 3.8 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 abi3
SHA-256 checksum
How to use checksums
296e33262385d6d781eeb30c65ad78b5790b27c1c055d1e6e2362b335ce6270e
BLAKE2b-256 checksum
How to use checksums
9d4a623ccbbfd7fa3c9eccad6e3d1d0fbb01febd4b99619a592f681a6e3d14b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.7

Release files / pymodab-1.1.3-cp38-abi3-macosx_10_9_universal2.whl

Download URL pymodab-1.1.3-cp38-abi3-macosx_10_9_universal2.whl
Size 17.6 kB
Tags CPython 3.8 abi3 macOS 10.9+ universal2 (ARM64, x86-64)
SHA-256 checksum
How to use checksums
57169a4688973c61e3ab31ec6f0e34b0b3aeef8fe977a679e854b99079264b41
BLAKE2b-256 checksum
How to use checksums
db1a5d264aec30e3a01bc79886bf43dcb0863c3b048dd0ee67144db6cac6564c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.7

Security for pymodab 1.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page