Pure python single variable function solvers
Project description
pyroots
Abstract
A Python library implementing various root finding methods for singlevariable functions.
Currently the following methods have been implemented:
With regard to Brent
's method, there are two implementations, the
first one uses inverse quadratic extrapolation (Brentq
) while the
other ones uses hyperbolic extrapolation (Brenth
).
If you don't know which method to use, you should probably use Brentq
.
That being said, Bisect
method is safe and slow (i.e. lots of iterations).
Example
# define the function whose root you are searching def f(x, a): return x ** 2  a + 1 # Create the Solver object (instead of Brentq you could also import Brenth/Ridder/Bisect) from pyroots import Brentq brent = Brentq(epsilon=1e5) # solve the function in `[3, 0]` while `a` is equal to 2 result = brent(f, 3, 0, a=2) print(result)
will output:
converged : True
message : Solution converged.
iterations : 6
func calls : 9
x0 : 1.0000000748530762
xtol : 0.0000000000000002
f(x0) : 0.0000001497061579
epsilon : 0.0000100000000000
x_steps : [3, 0, 0.3333333333333333, 1.6666666666666665, 0.7777777777777779, 1.0686868686868687, 0.9917335278385606, 0.9997244260982788, 1.0000000748530762]
fx_steps : [8, 1, 0.8888888888888888, 1.7777777777777772, 0.3950617283950615, 0.14209162330374459, 0.01646460976088293, 0.0005510718624670563, 1.4970615791476405e07]
Rationale
The functionality of pyroots
is already implemented in scipy
, so the
natural question is why rediscover the wheel?
Well, the main reason is that scipy
is a huge dependency. Pyroots
on
the other hand is just a single package that is easily installed and
that you can easily bundle with py2exe
or similar projects. It doesn't
even need to get installed, just throw the pyroots
folder in your
project and you are ready to go.
Apart from that, the API used by scipy
's functions is not very
userfriendly. For example you can't use keyword arguments for your
functions. Moreover, in scipy
there is no reliable way to define how
many digits of accuracy you want in the obtained root. For example, you
may ask for 6 digits, but scipy may calculate up to 14 (or 12 or
whatever) digits. The main implication of this "glitch" is that scipy's
method may evaluate the function more times than those really needed. If
the function calculates something trivial like the functions in the
following examples, then these extra function calls are no big deal, but
if your functions take significant time to evaluate ,e.g. more than
seconds, then this can quickly become annoying, or even, simply
unacceptable, e.g. the function takes some minutes to return a value.
Installation
with pip:
pip install pyroots
Usage
All the solvers share the same API, so you can easily switch between the various methods.
Function
The function whose root you are searching must take at least a single argument and return a single number. This first argument is also the dependent variable and, apart from that, the function can also take any number of positional/keyword arguments. For example the following functions are totally valid ones:
def f(x, a): return x ** 2  a + 1 def g(x, a, b, c=3): return x ** 2 + a ** b  c
Solver Objects
The first thing you have to do is to create a Solver
object for the
method you want to use:
from pyroots import Brentq brent = Brentq()
When you create the Solver
object, you can specify several parameters
that will affect the convergence. The most important are:
 epsilon which specifies the number of digits that will be taken
under consideration when checking for convergence. It defaults to
1e6
. raise_on_fail
which will raise an exception if convergence failed. It defaults to True.
Using the above function definitions, in order to find the root of f
you must first define an interval that contains the root. Let's say that
this interval is defined as [xa, xb]
. In this case you will call the
solver like this:
def f(x, a): return x ** 2  a + 1 solver = Brentq() result = solver(f, xa, xb, a=3)
Result Objects
All the methods return a Result
object that has the following
attributes:
result.x0 # the root
result.fx0 # the value of ``f(x0)`
result.convergence # True/False
result.iterations # the number of iterations
result.func_calls # the number of function evaluations.
result.msg # a descriptive message regarding the convergence (or the failure of convergence)
result.x_steps # a list containing the x values that have been tried while the solver run
result.fx_steps # a list containing the f(x) values that have been calculated while the solver run
If, for some reason, convergence cannot be achieved, then a
ConvergenceError
is raised. If you don't want that to happen, then you
have to pass False
as the value of raise_on_fail
argument:
def f(x): return x ** 2  1 result = brent(f, xa=10, xb=5, raise_on_fail=False) print(result)
API
Each solver factory has the following signature:
SolverFactory(epsilon=1e6, xtol=EPS, max_iter=500, raise_on_fail=True, debug_precision=10)
where:
epsilon
is the required precision of the solution, i.e. a solution is achieved whenf(x0)
is smaller thanepsilon
.max_iter
is the maximum allowed number of iterations.raise_on_fail
is a boolean flag indicating whether or not an exception should be raised if convergence fails. It defaults to True
Each solver object has the following signature:
solver_object(f, xa, xb, *args, **kwargs)
where:
f
is the function whose root we are searching.xa
is the lower bracket of the interval of the solution we search.xb
is the upper bracket of the interval of the solution we search.*args
are passed as positional arguments whenf
is evaluated.**kwargs
are passed as keyword arguments whenf
is evaluated.
Documentation
For the time being documentation is not yet ready, but the examples in the README should be enough to get your feet wet.
The source code repository of pyroots can be found at: https://github.com/pmav99/pyroots
Feedback and contributions are greatly appreciated.
pmav99 <gmail>
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Filename, size  File type  Python version  Upload date  Hashes 

Filename, size pyroots0.5.0py2.py3noneany.whl (18.0 kB)  File type Wheel  Python version py2.py3  Upload date  Hashes View 
Filename, size pyroots0.5.0.tar.gz (14.0 kB)  File type Source  Python version None  Upload date  Hashes View 
Hashes for pyroots0.5.0py2.py3noneany.whl
Algorithm  Hash digest  

SHA256  830cf8248ee9d4ded2d2da94137f84ff5112b399d2bcf2a48e824e2213a5769f 

MD5  f746e661bcd4582fb5f5b3eece42e300 

BLAKE2256  bc36887abb4891f67ea0cf458f4af80f7aba29fd7df2d2723373a493a3a7152c 