yroots.solve()

Solver

yroots.Combined_Solver.solve(funcs, a=-1, b=1, verbose=False, returnBoundingBoxes=False, exact=False, minBoundingIntervalSize=1e-05, max_cpu=1, parallel_depth=1)

Finds and returns the roots of a system of functions on the search interval [a,b].

Generates an approximation for each function using Chebyshev polynomials on the interval given, then uses properties of the approximations to shrink the search interval. When the information contained in the approximation is insufficient to shrink the interval further, the interval is subdivided into subregions, and the searching function is recursively called until it zeros in on each root. A specific point (and, optionally, a bounding box) is returned for each root found.

NOTE: YRoots uses just-in-time compiling with an on-disk cache. The first time the solver is called at a given dimension on any given install, numba compiles the required specializations (which takes several seconds or minutes) and writes them to yroots/__pycache__/ as .nbi/.nbc files. Every later Python process that solves a system of that same dimension loads the compiled code from disk on first call – no recompilation, no warmup. The cache is invalidated automatically when the source file or the numba version changes, and it is rebuilt lazily on the next call. Because the cache is keyed by the dimension of the system (a new type signature per dimension), the very first solve at each new dimension on a fresh install still pays a one-time compile cost.

NOTE: The solve function is only guaranteed to work well on systems of equations where each function is continuous and smooth and each root in the interval is a simple root. If a function is not continuous and smooth on an interval or an infinite number of roots exist in the interval, the solver may get stuck in recursion or the kernel may crash.

Examples

>>> f = lambda x,y,z: 2*x**2 / (x**4-4) - 2*y**2 + .5*z
>>> g = lambda x,y,z: 2*x**2*y / (y**2+4) - 2*y + 2*x*z
>>> h = lambda x,y,z: 2*z / (z**2-4) - 2*z
>>> roots = yroots.solve([f, g, h], np.array([-0.5,0,-2**-2.44]), np.array([0.5,np.exp(1.1376),.8]))
>>> print(roots)
[[-4.46764373e-01  4.44089210e-16 -5.55111512e-17]
 [ 4.46764373e-01  4.44089210e-16 -5.55111512e-17]]
>>> M1 = yroots.MultiPower(np.array([[0,3,0,2],[1.5,0,7,0],[0,0,4,-2],[0,0,0,1]]))
>>> M2 = yroots.MultiCheb(np.array([[0.02,0.31],[-0.43,0.19],[0.06,0]]))
>>> roots = yroots.solve([M1,M2],-5,5)
>>> print(roots)
[[-0.98956615 -4.12372817]
 [-0.06810064  0.03420242]]
Parameters:
  • funcs (list) – List of functions for searching. NOTE: Valid input is restricted to callable Python functions (including user-created functions) and yroots Polynomial (MultiCheb and MultiPower) objects. String representations of functions are not valid input.

  • a (list or numpy array) – An array containing the lower bound of the search interval in each dimension, listed in dimension order. If the lower bound is to be the same in each dimension, a single float input is also accepted. Defaults to -1 in each dimension if no input is given.

  • b (list or numpy array) – An array containing the upper bound of the search interval in each dimension, listed in dimension order. If the upper bound is to be the same in each dimension, a single float input is also accepted. Defaults to 1 in each dimension if no input is given.

  • verbose (bool) – Defaults to False. When True, prints progress of approximation and rootfinding to the terminal. Useful for long-running systems.

  • returnBoundingBoxes (bool) – Defaults to False. Whether or not to return a precise bounding box for each root.

  • exact (bool) – Defaults to False. Whether transformations performed on the approximation should be performed with higher precision to minimize error.

  • minBoundingIntervalSize (float) – Defaults to 1e-5. If a root is found with a bounding interval of size > minBoundingIntervalSize in each dimension, the functions are solved again on the smaller interval. Setting too small could cause issues if the functions can’t be evaluated accurately on points close together, and will increase solve times. Should give more accurate roots when smaller. This number is absolute when the bounding interval in question is in [-1,1], and relative otherwise. So if an interval has an endpoint of magnitude > 1, then minBoundingIntervalSize is multiplied by that value for that dimension.

  • max_cpu (int) – Defaults to 1. Max number of allowed cpus when solving subdivided regions.

  • parallel_depth (int) – Defaults to 1. Subdivision depth at which child tasks start being pushed to the worker pool. Higher values keep work serial for longer before parallelizing.

Returns:

  • roots (numpy array) – The roots of the system of functions on the interval.

  • boundingBoxes (numpy array, optional) – Only returned when returnBoundingBoxes is True. The exact intervals (boxes) in which each root is bound to lie.