Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/scipy/optimize/_root_scalar.py : 15%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2Unified interfaces to root finding algorithms for real or complex
3scalar functions.
5Functions
6---------
7- root : find a root of a scalar function.
8"""
9import numpy as np
11from . import zeros as optzeros
13__all__ = ['root_scalar']
16class MemoizeDer(object):
17 """Decorator that caches the value and derivative(s) of function each
18 time it is called.
20 This is a simplistic memoizer that calls and caches a single value
21 of `f(x, *args)`.
22 It assumes that `args` does not change between invocations.
23 It supports the use case of a root-finder where `args` is fixed,
24 `x` changes, and only rarely, if at all, does x assume the same value
25 more than once."""
26 def __init__(self, fun):
27 self.fun = fun
28 self.vals = None
29 self.x = None
30 self.n_calls = 0
32 def __call__(self, x, *args):
33 r"""Calculate f or use cached value if available"""
34 # Derivative may be requested before the function itself, always check
35 if self.vals is None or x != self.x:
36 fg = self.fun(x, *args)
37 self.x = x
38 self.n_calls += 1
39 self.vals = fg[:]
40 return self.vals[0]
42 def fprime(self, x, *args):
43 r"""Calculate f' or use a cached value if available"""
44 if self.vals is None or x != self.x:
45 self(x, *args)
46 return self.vals[1]
48 def fprime2(self, x, *args):
49 r"""Calculate f'' or use a cached value if available"""
50 if self.vals is None or x != self.x:
51 self(x, *args)
52 return self.vals[2]
54 def ncalls(self):
55 return self.n_calls
58def root_scalar(f, args=(), method=None, bracket=None,
59 fprime=None, fprime2=None,
60 x0=None, x1=None,
61 xtol=None, rtol=None, maxiter=None,
62 options=None):
63 """
64 Find a root of a scalar function.
66 Parameters
67 ----------
68 f : callable
69 A function to find a root of.
70 args : tuple, optional
71 Extra arguments passed to the objective function and its derivative(s).
72 method : str, optional
73 Type of solver. Should be one of
75 - 'bisect' :ref:`(see here) <optimize.root_scalar-bisect>`
76 - 'brentq' :ref:`(see here) <optimize.root_scalar-brentq>`
77 - 'brenth' :ref:`(see here) <optimize.root_scalar-brenth>`
78 - 'ridder' :ref:`(see here) <optimize.root_scalar-ridder>`
79 - 'toms748' :ref:`(see here) <optimize.root_scalar-toms748>`
80 - 'newton' :ref:`(see here) <optimize.root_scalar-newton>`
81 - 'secant' :ref:`(see here) <optimize.root_scalar-secant>`
82 - 'halley' :ref:`(see here) <optimize.root_scalar-halley>`
84 bracket: A sequence of 2 floats, optional
85 An interval bracketing a root. `f(x, *args)` must have different
86 signs at the two endpoints.
87 x0 : float, optional
88 Initial guess.
89 x1 : float, optional
90 A second guess.
91 fprime : bool or callable, optional
92 If `fprime` is a boolean and is True, `f` is assumed to return the
93 value of the objective function and of the derivative.
94 `fprime` can also be a callable returning the derivative of `f`. In
95 this case, it must accept the same arguments as `f`.
96 fprime2 : bool or callable, optional
97 If `fprime2` is a boolean and is True, `f` is assumed to return the
98 value of the objective function and of the
99 first and second derivatives.
100 `fprime2` can also be a callable returning the second derivative of `f`.
101 In this case, it must accept the same arguments as `f`.
102 xtol : float, optional
103 Tolerance (absolute) for termination.
104 rtol : float, optional
105 Tolerance (relative) for termination.
106 maxiter : int, optional
107 Maximum number of iterations.
108 options : dict, optional
109 A dictionary of solver options. E.g., ``k``, see
110 :obj:`show_options()` for details.
112 Returns
113 -------
114 sol : RootResults
115 The solution represented as a ``RootResults`` object.
116 Important attributes are: ``root`` the solution , ``converged`` a
117 boolean flag indicating if the algorithm exited successfully and
118 ``flag`` which describes the cause of the termination. See
119 `RootResults` for a description of other attributes.
121 See also
122 --------
123 show_options : Additional options accepted by the solvers
124 root : Find a root of a vector function.
126 Notes
127 -----
128 This section describes the available solvers that can be selected by the
129 'method' parameter.
131 The default is to use the best method available for the situation
132 presented.
133 If a bracket is provided, it may use one of the bracketing methods.
134 If a derivative and an initial value are specified, it may
135 select one of the derivative-based methods.
136 If no method is judged applicable, it will raise an Exception.
139 Examples
140 --------
142 Find the root of a simple cubic
144 >>> from scipy import optimize
145 >>> def f(x):
146 ... return (x**3 - 1) # only one real root at x = 1
148 >>> def fprime(x):
149 ... return 3*x**2
151 The `brentq` method takes as input a bracket
153 >>> sol = optimize.root_scalar(f, bracket=[0, 3], method='brentq')
154 >>> sol.root, sol.iterations, sol.function_calls
155 (1.0, 10, 11)
157 The `newton` method takes as input a single point and uses the derivative(s)
159 >>> sol = optimize.root_scalar(f, x0=0.2, fprime=fprime, method='newton')
160 >>> sol.root, sol.iterations, sol.function_calls
161 (1.0, 11, 22)
163 The function can provide the value and derivative(s) in a single call.
165 >>> def f_p_pp(x):
166 ... return (x**3 - 1), 3*x**2, 6*x
168 >>> sol = optimize.root_scalar(f_p_pp, x0=0.2, fprime=True, method='newton')
169 >>> sol.root, sol.iterations, sol.function_calls
170 (1.0, 11, 11)
172 >>> sol = optimize.root_scalar(f_p_pp, x0=0.2, fprime=True, fprime2=True, method='halley')
173 >>> sol.root, sol.iterations, sol.function_calls
174 (1.0, 7, 8)
177 """
178 if not isinstance(args, tuple):
179 args = (args,)
181 if options is None:
182 options = {}
184 # fun also returns the derivative(s)
185 is_memoized = False
186 if fprime2 is not None and not callable(fprime2):
187 if bool(fprime2):
188 f = MemoizeDer(f)
189 is_memoized = True
190 fprime2 = f.fprime2
191 fprime = f.fprime
192 else:
193 fprime2 = None
194 if fprime is not None and not callable(fprime):
195 if bool(fprime):
196 f = MemoizeDer(f)
197 is_memoized = True
198 fprime = f.fprime
199 else:
200 fprime = None
202 # respect solver-specific default tolerances - only pass in if actually set
203 kwargs = {}
204 for k in ['xtol', 'rtol', 'maxiter']:
205 v = locals().get(k)
206 if v is not None:
207 kwargs[k] = v
209 # Set any solver-specific options
210 if options:
211 kwargs.update(options)
212 # Always request full_output from the underlying method as _root_scalar
213 # always returns a RootResults object
214 kwargs.update(full_output=True, disp=False)
216 # Pick a method if not specified.
217 # Use the "best" method available for the situation.
218 if not method:
219 if bracket:
220 method = 'brentq'
221 elif x0 is not None:
222 if fprime:
223 if fprime2:
224 method = 'halley'
225 else:
226 method = 'newton'
227 else:
228 method = 'secant'
229 if not method:
230 raise ValueError('Unable to select a solver as neither bracket '
231 'nor starting point provided.')
233 meth = method.lower()
234 map2underlying = {'halley': 'newton', 'secant': 'newton'}
236 try:
237 methodc = getattr(optzeros, map2underlying.get(meth, meth))
238 except AttributeError:
239 raise ValueError('Unknown solver %s' % meth)
241 if meth in ['bisect', 'ridder', 'brentq', 'brenth', 'toms748']:
242 if not isinstance(bracket, (list, tuple, np.ndarray)):
243 raise ValueError('Bracket needed for %s' % method)
245 a, b = bracket[:2]
246 r, sol = methodc(f, a, b, args=args, **kwargs)
247 elif meth in ['secant']:
248 if x0 is None:
249 raise ValueError('x0 must not be None for %s' % method)
250 if x1 is None:
251 raise ValueError('x1 must not be None for %s' % method)
252 if 'xtol' in kwargs:
253 kwargs['tol'] = kwargs.pop('xtol')
254 r, sol = methodc(f, x0, args=args, fprime=None, fprime2=None,
255 x1=x1, **kwargs)
256 elif meth in ['newton']:
257 if x0 is None:
258 raise ValueError('x0 must not be None for %s' % method)
259 if not fprime:
260 raise ValueError('fprime must be specified for %s' % method)
261 if 'xtol' in kwargs:
262 kwargs['tol'] = kwargs.pop('xtol')
263 r, sol = methodc(f, x0, args=args, fprime=fprime, fprime2=None,
264 **kwargs)
265 elif meth in ['halley']:
266 if x0 is None:
267 raise ValueError('x0 must not be None for %s' % method)
268 if not fprime:
269 raise ValueError('fprime must be specified for %s' % method)
270 if not fprime2:
271 raise ValueError('fprime2 must be specified for %s' % method)
272 if 'xtol' in kwargs:
273 kwargs['tol'] = kwargs.pop('xtol')
274 r, sol = methodc(f, x0, args=args, fprime=fprime, fprime2=fprime2, **kwargs)
275 else:
276 raise ValueError('Unknown solver %s' % method)
278 if is_memoized:
279 # Replace the function_calls count with the memoized count.
280 # Avoids double and triple-counting.
281 n_calls = f.n_calls
282 sol.function_calls = n_calls
284 return sol
287def _root_scalar_brentq_doc():
288 r"""
289 Options
290 -------
291 args : tuple, optional
292 Extra arguments passed to the objective function.
293 xtol : float, optional
294 Tolerance (absolute) for termination.
295 rtol : float, optional
296 Tolerance (relative) for termination.
297 maxiter : int, optional
298 Maximum number of iterations.
299 options: dict, optional
300 Specifies any method-specific options not covered above
302 """
303 pass
306def _root_scalar_brenth_doc():
307 r"""
308 Options
309 -------
310 args : tuple, optional
311 Extra arguments passed to the objective function.
312 xtol : float, optional
313 Tolerance (absolute) for termination.
314 rtol : float, optional
315 Tolerance (relative) for termination.
316 maxiter : int, optional
317 Maximum number of iterations.
318 options: dict, optional
319 Specifies any method-specific options not covered above.
321 """
322 pass
324def _root_scalar_toms748_doc():
325 r"""
326 Options
327 -------
328 args : tuple, optional
329 Extra arguments passed to the objective function.
330 xtol : float, optional
331 Tolerance (absolute) for termination.
332 rtol : float, optional
333 Tolerance (relative) for termination.
334 maxiter : int, optional
335 Maximum number of iterations.
336 options: dict, optional
337 Specifies any method-specific options not covered above.
339 """
340 pass
343def _root_scalar_secant_doc():
344 r"""
345 Options
346 -------
347 args : tuple, optional
348 Extra arguments passed to the objective function.
349 xtol : float, optional
350 Tolerance (absolute) for termination.
351 rtol : float, optional
352 Tolerance (relative) for termination.
353 maxiter : int, optional
354 Maximum number of iterations.
355 x0 : float, required
356 Initial guess.
357 x1 : float, required
358 A second guess.
359 options: dict, optional
360 Specifies any method-specific options not covered above.
362 """
363 pass
366def _root_scalar_newton_doc():
367 r"""
368 Options
369 -------
370 args : tuple, optional
371 Extra arguments passed to the objective function and its derivative.
372 xtol : float, optional
373 Tolerance (absolute) for termination.
374 rtol : float, optional
375 Tolerance (relative) for termination.
376 maxiter : int, optional
377 Maximum number of iterations.
378 x0 : float, required
379 Initial guess.
380 fprime : bool or callable, optional
381 If `fprime` is a boolean and is True, `f` is assumed to return the
382 value of derivative along with the objective function.
383 `fprime` can also be a callable returning the derivative of `f`. In
384 this case, it must accept the same arguments as `f`.
385 options: dict, optional
386 Specifies any method-specific options not covered above.
388 """
389 pass
392def _root_scalar_halley_doc():
393 r"""
394 Options
395 -------
396 args : tuple, optional
397 Extra arguments passed to the objective function and its derivatives.
398 xtol : float, optional
399 Tolerance (absolute) for termination.
400 rtol : float, optional
401 Tolerance (relative) for termination.
402 maxiter : int, optional
403 Maximum number of iterations.
404 x0 : float, required
405 Initial guess.
406 fprime : bool or callable, required
407 If `fprime` is a boolean and is True, `f` is assumed to return the
408 value of derivative along with the objective function.
409 `fprime` can also be a callable returning the derivative of `f`. In
410 this case, it must accept the same arguments as `f`.
411 fprime2 : bool or callable, required
412 If `fprime2` is a boolean and is True, `f` is assumed to return the
413 value of 1st and 2nd derivatives along with the objective function.
414 `fprime2` can also be a callable returning the 2nd derivative of `f`.
415 In this case, it must accept the same arguments as `f`.
416 options: dict, optional
417 Specifies any method-specific options not covered above.
419 """
420 pass
423def _root_scalar_ridder_doc():
424 r"""
425 Options
426 -------
427 args : tuple, optional
428 Extra arguments passed to the objective function.
429 xtol : float, optional
430 Tolerance (absolute) for termination.
431 rtol : float, optional
432 Tolerance (relative) for termination.
433 maxiter : int, optional
434 Maximum number of iterations.
435 options: dict, optional
436 Specifies any method-specific options not covered above.
438 """
439 pass
442def _root_scalar_bisect_doc():
443 r"""
444 Options
445 -------
446 args : tuple, optional
447 Extra arguments passed to the objective function.
448 xtol : float, optional
449 Tolerance (absolute) for termination.
450 rtol : float, optional
451 Tolerance (relative) for termination.
452 maxiter : int, optional
453 Maximum number of iterations.
454 options: dict, optional
455 Specifies any method-specific options not covered above.
457 """
458 pass