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.

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 1971
AVG 48 28 27 34 21 28 20 20
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 76
FACTOR 2.477x 1.426x 1.405x 1.738x 1.072x 1.426x 1.011x 1.000x

Execution times (ms per problem, 200 iterations)

Func bisect brentq brenth ridder chandr cybrentq modAB_ct modAB_SG
SUM 1497.81 888.81 878.13 1103.39 62435.64 118.77 176.71 90.70
AVG 14.8298 8.8001 8.6944 10.9246 618.1747 1.1759 1.7496 0.8981
MEDIAN 14.1046 4.5237 4.4239 5.5108 366.5141 0.6629 1.3385 0.6881
MIN 1.6523 1.6333 1.8243 1.4128 68.0820 0.1926 0.5485 0.1625
MAX 39.1626 36.7848 31.6445 121.3956 2159.4610 5.8503 5.9590 3.2718
FACTOR 16.513x 9.799x 9.681x 12.165x 688.344x 1.309x 1.948x 1.000x

Notes:

Last Run on: 06.10.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.2 - the latest implementation of the safeguarded modab as native C extension

Metadata

Release files for pymodab 1.1.2

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.2
File Size Uploaded Provenance Actions
pymodab-1.1.2.tar.gz 121.4 kB Without provenance Details for pymodab-1.1.2.tar.gz

Built distributions (wheels)

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

Total release size: 351.7 kB

Release files / pymodab-1.1.2.tar.gz

Download URL pymodab-1.1.2.tar.gz
Size 121.4 kB
Tags Source
SHA-256 checksum
How to use checksums
7f16efcbf366f5842622263d39f02fdee2a7fdfa8f59150157f61ed681c2d6fa
BLAKE2b-256 checksum
How to use checksums
8888ccd8d8e82d5039637fe267603ec705db30512dfbaa3a3004dc053bccd9d9
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.2-py3-none-any.whl

Download URL pymodab-1.1.2-py3-none-any.whl
Size 110.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3bc0b514d8f9233d437414f5a30665dfc0c2c4b724d2bb873c13a47c5ea65e61
BLAKE2b-256 checksum
How to use checksums
58f8696de9eac723cf4b2ab23cbbd061c9e9ce26181fc8867df2bf6fc7e1d14c
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.2-cp38-abi3-win_amd64.whl

Download URL pymodab-1.1.2-cp38-abi3-win_amd64.whl
Size 15.4 kB
Tags CPython 3.8 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
011842f874778c976bfce488ac0e0a2a78ed604b712435a9886befcd97f2ebd8
BLAKE2b-256 checksum
How to use checksums
a0d6e9cdb14fc009ab2b97652bf80206fb41cd3281ec9c659e836212aa9f311b
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.2-cp38-abi3-musllinux_1_2_x86_64.whl

Download URL pymodab-1.1.2-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
fe8b52fdcffbd6e7c371593c7f3f4ac31eac505a4ef9d08786101e873fd7728c
BLAKE2b-256 checksum
How to use checksums
d5cd5a5c662c229bbf82e495219790beaea7b7e1102b01d05870ebecb391da3e
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.2-cp38-abi3-musllinux_1_2_aarch64.whl

Download URL pymodab-1.1.2-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
296614e9d675dea43ff61a4fa3fac6db33b24906f9f46b2f084c5709a5c838ff
BLAKE2b-256 checksum
How to use checksums
599ea2dda7d76088f4185deafb1a7ed5a89c1ac44909a08cec6870727ac41739
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.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl

Download URL pymodab-1.1.2-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
5895b1c66472e4fe76b4063c5538c35a39a1d1b328d49cacc85f4e3963618cad
BLAKE2b-256 checksum
How to use checksums
6bef37109de6a9ecf8ad5d03d68204c0581ac241859a3abf46064acae73da66f
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.2-cp38-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl

Download URL pymodab-1.1.2-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
4a63be7e98f6486a4578748901c8883ca8c8ad4d9d9dfe4bc843e8d8ec25fcc3
BLAKE2b-256 checksum
How to use checksums
b8200d42dbb18182b4382c1aac3e3ec1094ab7602da8f959198b9467d14e7180
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.2-cp38-abi3-macosx_10_9_universal2.whl

Download URL pymodab-1.1.2-cp38-abi3-macosx_10_9_universal2.whl
Size 17.9 kB
Tags CPython 3.8 abi3 macOS 10.9+ universal2 (ARM64, x86-64)
SHA-256 checksum
How to use checksums
ad055299eb88dfa8f094fb1d619c16c09c6252888107210b4eb914586274aa35
BLAKE2b-256 checksum
How to use checksums
3980113da34f67c18e21471643b1ae6a5efef4bb8d7c05c2c3c981cc1d497d42
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.2

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