diff --git a/README.md b/README.md index 01fe47a4..3dee6e2e 100644 --- a/README.md +++ b/README.md @@ -4,99 +4,106 @@ Windows: [![Build status](https://ci.appveyor.com/api/projects/status/goteuptn5k # Root finding functions for Julia + This package contains simple routines for finding roots of continuous -scalar functions of a single real variable. The basic interface is -through the function `fzero` which dispatches to an appropriate -algorithm based on its argument(s): +scalar functions of a single real variable. The `find_zero`function provides the +primary interface. It supports various algorithms through the +specification of an method. These include: -* `fzero(f, a::Real, b::Real)` and `fzero(f, - bracket::Vector)` call the `find_zero` algorithm to find a root - within the bracket `[a,b]`. When a bracket is used with `Float64` - arguments, the algorithm is guaranteed to converge to a value `x` - with either `f(x) == 0` or at least one of `f(prevfloat(x))*f(x) < 0` - or `f(x)*f(nextfloat(x)) < 0`. (The function need not be continuous - to apply the algorithm, as the last condition can still hold.) +* Bisection-like algorithms. For functions where a bracketing interval +is known (one where f(a) and f(b) have alternate signs), the + `Bisection` method can be specified with a guaranteed + convergence. For most floating point number types, bisection occurs + in a manner exploiting floating point storage conventions. For + others, an algorithm of Alefeld, Potra, and Shi is used. -* `fzero(f, x0::Real; order::Int=0)` calls a - derivative-free method. The default method is a bit plodding but - more robust to the quality of the initial guess than some others. - For faster convergence and fewer function calls, an order can be - specified. Possible values are 1, 2, 5, 8, and 16. The order 2 - Steffensen method can be the fastest, but is in need of a good - initial guess. The order 8 method is more robust and often as - fast. The higher-order methods may be faster when using `Big` values. + For typically faster convergence -- though not guaranteed -- the + `FalsePosition` method can be specified. This method has one of 12 + implementations for a modified secant method to + accelerate convergence. -* `fzero(f, x0::Real, bracket::Vector)` calls - a derivative-free algorithm with initial guess `x0` with steps constrained - to remain in the specified bracket. +* Several derivative-free methods are implemented. These are specified + through the methods `Order0`, `Order1` (the secant method), `Order2` + (the Steffensen method), `Order5`, `Order8`, and `Order16`. The + number indicates roughly the order of convergence. The `Order0` + method is the default, and the most robust, but generally takes many more + function calls. The higher order methods promise higer order + convergence, though don't always yield results with fewer function + calls than `Order1` or `Order2`. -* `fzeros(f, a::Real, b::Real; no_pts::Int=200)` will split - the interval `[a,b]` into many subintervals and search for zeros in - each using a bracketing method if possible. This naive algorithm - may miss double zeros that lie within the same subinterval and zeros - where there is no crossing of the x-axis. +* There are two historic methods that require a derivative: + `Roots.Newton` and `Roots.Halley`. (Neither is currently exported.) + If a derivative is not given, an automatic derivative is found using + the `ForwardDiff` package. +Each method's documentation has additional detail. +Some examples: +```julia +f(x) = exp(x) - x^4 -For historical purposes, there are implementations of Newton's method -(`newton`), Halley's method (`halley`), and the secant method -(`secant_method`). For the first two, if derivatives are not -specified, they will be computed using the `ForwardDiff` package. +# a bisection method has the bracket specified with a tuple or vector +julia> find_zero(f, (8,9), Bisection()) +8.613169456441398 +julia> find_zero(f, (-10, 0)) # Bisection if x is a tuple and no method +-0.8155534188089606 -## Usage examples -```julia -f(x) = exp(x) - x^4 -## bracketing -fzero(f, 8, 9) # 8.613169456441398 -fzero(f, -10, 0) # -0.8155534188089606 -fzeros(f, -10, 10) # -0.815553, 1.42961 and 8.61317 +julia> find_zero(f, (-10, 0), FalsePosition()) # just 11 function evaluations +-0.8155534188089607 -## use a derivative free method -fzero(f, 3) # 1.4296118247255558 +## find_zero(f, x0::Number) will use Order0() +julia> find_zero(f, 3) # default is Order0() +1.4296118247255556 -## use a different order -fzero(sin, 3, order=16) # 3.141592653589793 +julia> find_zero(f, 3, Order1()) # same answer, different method +1.4296118247255556 -## BigFloat values yield more precision -fzero(sin, BigFloat(3.0)) # 3.1415926535897932384...with 256 bits of precision +julia> find_zero(sin, BigFloat(3.0), Order16()) +3.141592653589793238462643383279502884197169399375105820974944592307816406286198 ``` -The `fzero` function can be used with callable objects: + +The `find_zero` function can be used with callable objects: ```julia -using SymEngine; @vars x -fzero(x^5 - x - 1, 1.0) +using SymEngine +@vars x +find_zero(x^5 - x - 1, 1.0) # 1.1673039782614185 ``` Or, ```julia -using Polynomials; x = variable(Int) -fzero(x^5 - x - 1, 1.0) +using Polynomials +x = variable(Int) +fzero(x^5 - x - 1, 1.0) # 1.1673039782614185 ``` +The function should respect the units of the `Unitful` package: +```julia +using Unitful +s = u"s"; m = u"m" +g = 9.8*m/s^2 +v0 = 10m/s +y0 = 16m +y(t) = -g*t^2 + v0*t + y0 +find_zero(y, 1s) # 1.886053370668014 s +``` -The well-known methods can be used with or without supplied -derivatives. If not specified, the `ForwardDiff` package is used for -automatic differentiation. +Newton's method can be used without taking derivatives: ```julia -f(x) = exp(x) - x^4 -fp(x) = exp(x) - 4x^3 -fpp(x) = exp(x) - 12x^2 -newton(f, fp, 8) # 8.613169456441398 -newton(f, 8) -halley(f, fp, fpp, 8) -halley(f, 8) -secant_method(f, 8, 8.5) +f(x) = x^3 - 2x - 5 +x0 = 2 +find_zero(f, x0, Roots.Newton()) # 2.0945514815423265 ``` -The automatic derivatives allow for easy solutions to finding critical +Automatic derivatives allow for easy solutions to finding critical points of a function. ```julia @@ -110,28 +117,93 @@ fzero(D(M), .5) - mean(as) # 0.0 ## median function m(x) sum([abs(x-a) for a in as]) + end fzero(D(m), 0, 1) - median(as) # 0.0 ``` +### Multiple zeros -## Alternate interface +The `find_zeros` function can be used to search for all zeros in a +specified interval. The basic algorithm splits the interval into many +subintervals. For each, if there is a bracket a bracketing algorithm +is used to identify a zero, otherwise a derivative free method is used +to check. This algorithm can miss zeros for various reasons, so the +results should be confirmed by other means. -As an alternative interface to the MATLAB-inherited one through -`fzero`, the function `find_zero` can be used. For this, a type is -used to specify the method. For example, - -``` -find_zero(sin, 3.0, Order0()) -find_zero(x -> x^5 - x- 1, 1.0, Order1()) # also Order2(), Order5(), Order8(), Order16() +```julia +f(x) = exp(x) - x^4 +find_zeros(f, -10, 10) ``` -And bracketing methods: +### Convergence + +For most algorithms (besides the `Bisection` ones) convergence is decided when + +* The value f(x_n) ≈ 0 with tolerances `atol` and `rtol` *or* + +* the values x_n ≈ x_{n-1} with tolerances `xatol` and `xrtol` *and* +f(x_n) ≈ 0 with a *relaxed* tolerance based on `atol` and `rtol`. + +* an algorithm encounters an `NaN` or `Inf` and yet f(x_n) ≈ 0 with a *relaxed* tolerance based on `atol` and `rtol`. + +There is no convergence if the number of iterations exceed `maxevals`, +or the number of function calls exceeds `maxfnevals`. + +The tolerances may need to be adjusted. To determine if convergence +occurs due to f(x_n) ≈ 0, it is necessary to consider that even if +`xstar` is the correct answer mathematically, due to floating point +roundoff it is expected that f(xstar) ≈ f'(xstar) ⋅ xstar ⋅ ϵ. The +relative error used accounts for the value of `x`, but the default +tolerance may need adjustment if the derivative is large near the +zero, as the default is a bit aggressive. On the other hand, the +absolute tolerance might seem too relaxed. + +To determine if convergence is determined as x_n ≈ x_{n-1} the check +on f(x_n) ≈ 0 is done as algorithms can be fooled by asymptotes, or +other areas where the tangent lines have large slopes. + +The `Bisection` and `Roots.A42` methods will converge, so the tolerances are ignored. + +## An alternate interface + +For MATLAB users, this functionality is provided by the `fzero` +function. `Roots` also provides this alternative interface: + + +* `fzero(f, a::Real, b::Real)` and `fzero(f, + bracket::Vector)` call the `find_zero` algorithm with the + `Bisection` method. + +* `fzero(f, x0::Real; order::Int=0)` calls a + derivative-free method. with the order specified matching one of + `Order0`, `Order1`, etc. + +* `fzeros(f, a::Real, b::Real; no_pts::Int=200)` will call `find_zeros`. + +* The function `secant_method`, `newton`, and `halley` provide direct + access to those methods. + + +## Usage examples + +```julia +f(x) = exp(x) - x^4 +## bracketing +fzero(f, 8, 9) # 8.613169456441398 +fzero(f, -10, 0) # -0.8155534188089606 +fzeros(f, -10, 10) # -0.815553, 1.42961 and 8.61317 + +## use a derivative free method +fzero(f, 3) # 1.4296118247255558 + +## use a different order +fzero(sin, 3, order=16) # 3.141592653589793 ``` -find_zero(sin, (3, 4), Bisection()) -find_zero(x -> x^5 - x - 1, (1,2), FalsePosition()) -``` + + + ---- diff --git a/doc/roots.ipynb b/doc/roots.ipynb index 74f519fc..b0dbafea 100644 --- a/doc/roots.ipynb +++ b/doc/roots.ipynb @@ -1,112 +1,133 @@ { "cells": [ {"cell_type":"markdown","source":"

The Roots package

","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}}, -{"cell_type":"markdown","source":"

The Roots package contains simple routines for finding zeros of continuous scalar functions of a single real variable. A zero of $f$ is a value $c$ where $f(c) = 0$. The basic interface is through the function fzero, which through multiple dispatch and keyword arguments can handle many different cases.

","metadata":{}}, +{"cell_type":"markdown","source":"

The Roots package contains simple routines for finding zeros of continuous scalar functions of a single real variable. A zero of $f$ is a value $c$ where $f(c) = 0$. The basic interface is through the function find_zero, which through multiple dispatch can handle many different cases.

","metadata":{}}, {"cell_type":"markdown","source":"

We will use Plots for plotting.

","metadata":{}}, -{"outputs":[],"cell_type":"code","source":["using Roots \nusing Plots"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["Plots.PyPlotBackend()"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["using Roots \nusing Plots\npyplot()"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

Bracketing

","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}}, {"cell_type":"markdown","source":"

For a function $f: R \\rightarrow R$ a bracket is a pair $ a < b $ for which $f(a) \\cdot f(b) < 0$. That is they have different signs. If $f$ is a continuous function this ensures there to be a zero (a $c$ with $f(c) = 0$) in the interval $[a,b]$, otherwise, if $f$ is only piecewise continuous, there must be a point $c$ in $[a,b]$ with the left limit and right limit at $c$ having different signs (or $0$). Such values can be found, up to floating point roundoff.

","metadata":{}}, {"cell_type":"markdown","source":"

That is, given f(a) * f(b) < 0, a value c with a < c < b can be found where either f(c) == 0.0 or at least f(prevfloat(c)) * f(nextfloat(c)) <= 0.

","metadata":{}}, {"cell_type":"markdown","source":"

To illustrate, consider the function $f(x) = \\cos(x) - x$. From the graph we see readily that $[0,1]$ is a bracket (which we emphasize with an overlay):

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"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"},"metadata":{"image/png":{"height":480,"width":600}},"execution_count":null}],"cell_type":"code","source":["f(x) = cos(x) - x\nplot(f, -2, 2)\nplot!([0,1], [0,0], linewidth=2)"],"metadata":{},"execution_count":null}, -{"cell_type":"markdown","source":"

The basic function call specifies a bracket using either two values or vector notation:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(0.7390851332151607, 0.0)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["x = fzero(f, 0, 1) # also fzero(f, [0, 1])\nx, f(x)"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"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"},"metadata":{"image/png":{"height":480,"width":600}},"execution_count":1}],"cell_type":"code","source":["f(x) = cos(x) - x\nplot(f, -2, 2)\nplot!([0,1], [0,0], linewidth=2)"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"

We use a vector or tuple to specify the initial condition for Bisection:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(0.7390851332151607, 0.0)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["x = find_zero(f, (0, 1), Bisection()) # alternatively fzero(f, [0, 1])\nx, f(x)"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

For this function we see that f(x) == 0.0.

","metadata":{}}, {"cell_type":"markdown","source":"
","metadata":{}}, -{"cell_type":"markdown","source":"

Next consider $f(x) = \\sin(x)$. A known root is $\\pi$. Trignometry tells us that $[\\pi/2, 3\\pi/2]$ will be a bracket:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(3.1415926535897936, -3.216245299353273e-16)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["f(x) = sin(x)\nx = fzero(f, pi/2, 3pi/2)\nx, f(x)"],"metadata":{},"execution_count":null}, +{"cell_type":"markdown","source":"

Next consider $f(x) = \\sin(x)$. A known root is $\\pi$. Trignometry tells us that $[\\pi/2, 3\\pi/2]$ will be a bracket. Here Bisection() is not specified, as it will be the default when the initial value is specified as pair of numbers:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(3.141592653589793, 1.2246467991473532e-16)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["f(x) = sin(x)\nx = find_zero(f, (pi/2, 3pi/2))\nx, f(x)"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

This value of x does not produce f(x) == 0.0, however, it is as close as can be:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["true"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["f(prevfloat(x)) * f(x) < 0.0 || f(x) * f(nextfloat(x)) < 0.0"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["true"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["f(prevfloat(x)) * f(x) < 0.0 || f(x) * f(nextfloat(x)) < 0.0"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

That is, at x the function is changing sign.

","metadata":{}}, -{"cell_type":"markdown","source":"

The algorithm identifies discontinuities, not just zeros:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["0.0"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["fzero(x -> 1/x, -1, 1)"],"metadata":{},"execution_count":null}, -{"cell_type":"markdown","source":"

The basic algorithm used for bracketing when the values are simple floating point values is the bisection method. For big float values, an algorithm due to Alefeld, Potra, and Shi is used.

","metadata":{}}, +{"cell_type":"markdown","source":"

From a mathematical perspective, a zero is guaranteed for a continuous function. However, the computer algorithm doesn't assume continuity, it just looks for changes of sign. As such, the algorithm will identify discontinuities, not just zeros. For example:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["-0.0"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["find_zero(x -> 1/x, (-1, 1))"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

The endpoints can even be infinite:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["0.0"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["fzero(x -> Inf*sign(x), -Inf, Inf) # Float64 only"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["0.0"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["find_zero(x -> Inf*sign(x), (-Inf, Inf)) # Float64 only"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"

The basic algorithm used for bracketing when the values are simple floating point values is the bisection method. For big float values, an algorithm due to Alefeld, Potra, and Shi is used.

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["3.141592653589793238462643383279502884197169399375105820974944592307816406286198"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["find_zero(sin, (big(3), big(4))) # uses a different algorithm then for (3,4)"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

Using an initial guess

","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}}, -{"cell_type":"markdown","source":"

Bracketing methods have guaranteed convergence, but in general require many more function calls than are needed to produce an answer. If a good initial guess is known, then the fzero function provides an interface to some different iterative algorithms that are more efficient. Unlike bracketing methods, these algorithms may not converge to the desired root if the initial guess is not well chosen.

","metadata":{}}, -{"cell_type":"markdown","source":"

The default algorithm is modeled after an algorithm used for HP-34 calculators. This algorithm is designed to be more forgiving of the quality of the initial guess at the cost of possible performing many more steps. In many cases it satisfies the criteria for a bracketing solution, as it will use bracketing if within the algorithm a bracket is identified.

","metadata":{}}, +{"cell_type":"markdown","source":"

Bracketing methods have guaranteed convergence, but in general require many more function calls than are needed to produce an answer. If a good initial guess is known, then the find_zero function provides an interface to some different iterative algorithms that are more efficient. Unlike bracketing methods, these algorithms may not converge to the desired root if the initial guess is not well chosen.

","metadata":{}}, +{"cell_type":"markdown","source":"

The default algorithm is modeled after an algorithm used for HP-34 calculators. This algorithm is designed to be more forgiving of the quality of the initial guess at the cost of possibly performing many more steps. In many cases it satisfies the criteria for a bracketing solution, as it will use bracketing if within the algorithm a bracket is identified.

","metadata":{}}, {"cell_type":"markdown","source":"

For example, the answer to our initial problem is near 1. Given this, we can find the zero with:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(0.7390851332151607, 0.0)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["f(x) = cos(x) - x\nx = fzero(f , 1)\nx, f(x)"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(0.7390851332151607, 0.0)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["f(x) = cos(x) - x\nx = find_zero(f , 1)\nx, f(x)"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

For the polynomial $f(x) = x^3 - 2x - 5$, an initial guess of 2 seems reasonable:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(2.0945514815423265, -8.881784197001252e-16, -1.0)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["f(x) = x^3 - 2x - 5\nx = fzero(f, 2)\nx, f(x), sign(f(prevfloat(x)) * f(nextfloat(x)))"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(2.0945514815423265, -8.881784197001252e-16, -1.0)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["f(x) = x^3 - 2x - 5\nx = find_zero(f, 2)\nx, f(x), sign(f(prevfloat(x)) * f(nextfloat(x)))"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

For even more precision, BigFloat numbers can be used

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(3.141592653589793238462643383279502884197169399375105820974944592307816406286198, 1.096917440979352076742130626395698021050758236508687951179005716992142688513354e-77, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["x = fzero(sin, big(3))\nx, sin(x), x - pi"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(3.141592653589793238462643383279502884197169399375105820974944592307816406286198, 1.096917440979352076742130626395698021050758236508687951179005716992142688513354e-77, 0.000000000000000000000000000000000000000000000000000000000000000000000000000000)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["x = find_zero(sin, big(3))\nx, sin(x), x - pi"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

Higher order methods

","metadata":{"internals":{"slide_type":"subslide"},"slideshow":{"slide_type":"subslide"},"slide_helper":"slide_end"}}, -{"cell_type":"markdown","source":"

The default call to fzero uses a first order method and then possibly bracketing, which involves potentially many more function calls. Though specifying a initial value is more convenient than a bracket, there may be times where a more efficient algorithm is sought. For such, a higher-order method might be better suited. There are algorithms of order 1 (secant method), 2 (Steffensen), 5, 8, and 16. The order 2 method is generally more efficient, but is more sensitive to the initial guess than, say, the order 8 method. These algorithms are accessed by specifying a value for the order argument:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(0.3517337112491958, -1.1102230246251565e-16)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["f(x) = 2x - exp(-x)\nx = fzero(f, 1, order=2)\nx, f(x)"],"metadata":{},"execution_count":null}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(-3.0, 0.0)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["f(x) = (x + 3) * (x - 1)^2\nx = fzero(f, -2, order=5)\nx, f(x)"],"metadata":{},"execution_count":null}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(1.0000000027152591, 2.949052856287529e-17)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["x = fzero(f, 2, order=8)\nx, f(x)"],"metadata":{},"execution_count":null}, -{"cell_type":"markdown","source":"

The latter shows that zeros need not be simple zeros (i.e. $f'(x) = 0$, if defined) to be found.

","metadata":{}}, +{"cell_type":"markdown","source":"

The default call to fzero uses a first order method and then possibly bracketing, which involves potentially many more function calls. Though specifying a initial value is more convenient than a bracket, there may be times where a more efficient algorithm is sought. For such, a higher-order method might be better suited. There are algorithms Order1 (secant method), Order2 (Steffensen), Order5, Order8, and Order16. The order 2 method is generally more efficient, but is more sensitive to the initial guess than, say, the order 8 method. These algorithms are accessed by specifying the method after the initial point:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(0.3517337112491958, -1.1102230246251565e-16)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["f(x) = 2x - exp(-x)\nx = find_zero(f, 1, Order2()) # also fzero(f, 1, order=2)\nx, f(x)"],"metadata":{},"execution_count":1}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(-3.0, 0.0)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["f(x) = (x + 3) * (x - 1)^2\nx = find_zero(f, -2, Order5())\nx, f(x)"],"metadata":{},"execution_count":1}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(1.0000000027152591, 2.949052856287529e-17)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["x = find_zero(f, 2, Order8())\nx, f(x)"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"

The latter shows that zeros need not be simple zeros (i.e. $f'(x) = 0$, if defined) to be found. (Though non-simple zeros may take many more steps to converge.)

","metadata":{}}, {"cell_type":"markdown","source":"

To investigate the algorithm and its convergence, the argument verbose=true may be specified.

","metadata":{}}, -{"cell_type":"markdown","source":"

For some functions, adjusting the default tolerances may be necessary to achieve convergence. These include abstol and reltol, which are used to check if norm(f(x)) <= max(abstol, norm(x)*reltol); xabstol, xreltol, to check if norm(x1-x0) <= max(xabstol, norm(x1)*xreltol); and maxevals and maxfnevals to limit the number of steps in the algorithm or function calls.

","metadata":{}}, +{"cell_type":"markdown","source":"

For some functions, adjusting the default tolerances may be necessary to achieve convergence. These include atol and rtol, which are used to check if $f(x_n) \\approx 0$; xatol, xrtol, to check if $x_n \\approx x_{n-1}$; and maxevals and maxfnevals to limit the number of steps in the algorithm or function calls.

","metadata":{}}, {"cell_type":"markdown","source":"

The higher-order methods are basically various derivative-free versions of Newton's method (which has update step $x - f(x)/f'(x)$). For example, Steffensen's method is essentially replacing $f'(x)$ with $(f(x + f(x)) - f(x))/f(x)$. This is a forward-difference approximation to the derivative with \"$h$\" being $f(x)$, which presumably is close to $0$ already. The methods with higher order combine this with different secant line approaches that minimize the number of function calls. These higher-order methods can be susceptible to some of the usual issues found with Newton's method: poor initial guess, small first derivative, or large second derivative near the zero.

","metadata":{}}, {"cell_type":"markdown","source":"
","metadata":{}}, {"cell_type":"markdown","source":"

For a classic example where a large second derivative is the issue, we have $f(x) = x^{1/3}$:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["Roots.ConvergenceFailed(\"Stopped at: xn = -2.1990233589964556e12\")\n"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["f(x) = cbrt(x)\nx = fzero(f, 1, order=2)\t# all of 2, 5, 8, and 16 fail or diverge towards infinity"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["Roots.ConvergenceFailed(\"Stopped at: xn = -2.1990233589964556e12\")\n"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["f(x) = cbrt(x)\nx = find_zero(f, 1, Order2())\t# all of 2, 5, 8, and 16 fail or diverge towards infinity"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

However, the default finds the root here, as a bracket is identified:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(0.0, 0.0)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["x = fzero(f, 1)\nx, f(x)"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(0.0, 0.0)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["x = find_zero(f, 1)\nx, f(x)"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

Order 8 illustrates that sometimes the stopping rules can be misleading and checking the returned value is always a good idea:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["2.0998366730115564e23"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["fzero(f, 1, order=8)"],"metadata":{},"execution_count":null}, -{"cell_type":"markdown","source":"

The algorithm rapidly marches off towards infinity so the relative tolerance $|x| \\cdot \\epsilon$ is large compared to the far-from zero $f(x)$.

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["5.036302449511863e15"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["find_zero(f, 1, Order8())"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"

The algorithm rapidly marches off towards infinity so the relative tolerance $\\approx |x| \\cdot \\epsilon$ is large compared to the far-from zero $f(x)$.

","metadata":{}}, {"cell_type":"markdown","source":"
","metadata":{}}, -{"cell_type":"markdown","source":"

This example illustrates that the default fzero call is more forgiving to an initial guess. The devilish function defined below comes from a test suite of difficult functions. The default method finds the zero starting at 0:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"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"},"metadata":{"image/png":{"height":480,"width":600}},"execution_count":null}],"cell_type":"code","source":["f(x) = cos(100*x)-4*erf(30*x-10)\nplot(f, -2, 2)"],"metadata":{},"execution_count":null}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["0.3318660335745625"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["fzero(f, 0)"],"metadata":{},"execution_count":null}, -{"cell_type":"markdown","source":"

Whereas, with order=n methods fail. For example,

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["Roots.ConvergenceFailed(\"Stopped at: xn = 34772.380550438844\")\n"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["fzero(f, 0, order=8)"],"metadata":{},"execution_count":null}, +{"cell_type":"markdown","source":"

This example illustrates that the default find_zero call is more forgiving to an initial guess. The devilish function defined below comes from a test suite of difficult functions. The default method finds the zero starting at 0:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"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"},"metadata":{"image/png":{"height":480,"width":600}},"execution_count":1}],"cell_type":"code","source":["f(x) = cos(100*x)-4*erf(30*x-10)\nplot(f, -2, 2)"],"metadata":{},"execution_count":1}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["0.3318660335745625"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["find_zero(f, 0)"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"

Whereas, with higher order methods fail. For example,

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["Roots.ConvergenceFailed(\"Stopped at: xn = 34772.380550438844\")\n"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["find_zero(f, 0, Order8())"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

Basically the high order oscillation can send the proxy tangent line off in nearly random directions. The default method can be fooled here too.

","metadata":{}}, {"cell_type":"markdown","source":"
","metadata":{}}, {"cell_type":"markdown","source":"

Finally, for many functions, all of these methods need a good initial guess. For example, the polynomial function $f(x) = x^5 - x - 1$ has its one zero near $1.16$. If we start far from it, convergence may happen, but it isn't guaranteed:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["1.1673039782614185"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["f(x) = x^5 - x - 1\nx0 = 0.1\nfzero(f, x0)"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["1.1673039782614185"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["f(x) = x^5 - x - 1\nx0 = 0.1\nfind_zero(f, x0)"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

Whereas,

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["Roots.ConvergenceFailed(\"Stopped at: xn = -0.7503218333241642\")\n"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["fzero(f, x0, order=2)"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["Roots.ConvergenceFailed(\"Stopped at: xn = -0.7503218333241642\")\n"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["find_zero(f, x0, Order2())"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

A graph shows the issue. We have overlayed a 15 steps of Newton's method, the other algorithms being somewhat similar:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"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sBD8foHEyzGNkgymUZLBKegeP0qjDidu2wgncFcxCry5RmYA0yjJYBolGUyj7vGjNPrcXty0AeOise9yRIkcqTKNkgymUZLBNOoef3lntvTi59sB4On5QlMQTKMkhWmUZHAKusdf0uhdm9HSi2VZ+OYEuRdlGiUZTKMkg2nUPX6RRrc14cx/QafB7ktRGC+3JUyjJINplGQwjbrH9+9MhxM3boDDiZ9OF52CYBolKUyjJINT0D2+T6PP78eWRmRH494Z0i/NNEoymEZJBtOoe3ycRlv7UPgGmnvxzjJckiO8IUyjJIRplGQwjbrHx+/MuzejuRfnZvpgCoJplKQwW3TrbgAAA/FJREFUjZIMTkH3+DKNbm/GSwcRqsUzIteRORnTKMlgGiUZTKPu8dkgdDhx43o4nPjJNJwhu0ZmQHV1/Wuvfeib1yaVfPDB2t27y329FRT8HnvsFV9vQkByM41WVdU+/fT/NTS0lJRMvuWWq0JD9YO/+8wzr69bt8P1+MEHry8qyjv5Gf5yAJsbkRWF+8TXyAyw2ezt7V0+e3lShslk7uuz+HorKPg1Nrb6ehMCkpuD8OabH3766bsnTMh8++1PHn305QceuG7wd9eu3f7WW48P8+uOiJj7tgLA7+YhWj/MDxIREXmXm2n04ouXTJyYHRKiXbZsblVV7QnftVptq1dvfffdz6qr64f89Y65l7nWyFya697rExEReYabg/Daa7/tevDzn//x2msvOeG7FRXVZWWHzObe++9/9tVX3zv51836aI3d1vKHexcsuGbwf26++eFVq74AcPhwjcCD7dv3ib0WH6j8oKure9++wz7fDD7gA0UejNZw5xHu2VPxq189f8IXB3/m9+KL79bXN91//3Un/epxy5ff8t57vx/8lfb2ruIf/KW6tgmbP3Bjiz3NCWh8vQ1EROR1R46sHD8+/eSvu39C/TvvrPr0083PPfczjWa4QXLZZXcO+Xmh/In8RESkslNNKzcXy/zzn5+uXLnh+ecfGHje7m7ztm17zzpr1saNu9at23H33d8H0NLSbrPZR7VBREREktw5IiwtPTh//tUXXrhQq9UCiI6OfOmlX65a9cWKFffV1n6i1WoffPC5srIKvV5ns9keeeS2goLxXthyIiIiD/DBtUaJiIj8h+/vPkFERORDHIRf8eqr7/HSDORZNTXGW2555Mor73riib+e6iNzIk/hX2Ju4CDsZzb3PfDAc/fd90xzc7uvt4WCh9PpvOGG39x663dee+2R9PSkRx550ddbREGLf4m5jTdIO+6iixaHhHDPgDxpz56KWbMmT5yYDeCqq772rW/d7ustomDGv8Tcw//J+kVEhJ155lRfbwUFm6qq2vz846umeW9e8h7+JeY2td6Wp71WDpFn2Wx2nY43fybya2oNwqKivDfffMzXW0EKSU5O2LFj/8AfHQ6HDzeGiIbENErkRSUlkz/7bIvrbN3q6vq4uGhfbxERnUitI8LTCgsLDQ3l/ybkMZGR4StWXPSNb9wcERFutdqeeeYeX28RBTn+JeYGXlmGiIiUxjRKRERK4yAkIiKlcRASEZHSOAiJiEhpHIRERKQ0DkIiIlIaByERESmNg5CIiJTGQUhERErjICQiIqVxEBIRkdI4CImISGkchEREpDQOQiIiUhoHIRERKY2DkIiIlMZBSERESvv/bnYTu3e6pH0AAAAASUVORK5CYII="},"metadata":{"image/png":{"height":480,"width":600}},"execution_count":null}],"cell_type":"code","source":[""],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"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"},"metadata":{"image/png":{"height":480,"width":600}},"execution_count":1}],"cell_type":"code","source":[""],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

Though 15 steps are shown, only a few are discernible, as the function's relative maximum causes a trap for this algorithm. Starting to the right of the relative minimum – nearer the zero – would avoid this trap. The default method employs a trick to bounce out of such traps, though it doesn't always work.

","metadata":{}}, {"cell_type":"markdown","source":"

Finding more than one zero

","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}}, -{"cell_type":"markdown","source":"

The bracketing methods suggest a simple algorithm to recover multiple zeros: partition an interval into many small sub-intervals. For those that bracket a root find the root. This is essentially implemented with fzeros(f, a, b). The algorithm has problems with non-simple zeros (in particular ones that don't change sign at the zero) and zeros which bunch together. Simple usage is often succesful enough, but a graph should be used to assess if all the zeros are found:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["3-element Array{Float64,1}:\n -0.815553\n 1.42961 \n 8.61317 "]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["fzeros(x -> exp(x) - x^4, -10, 10)"],"metadata":{},"execution_count":null}, +{"cell_type":"markdown","source":"

The bracketing methods suggest a simple algorithm to recover multiple zeros: partition an interval into many small sub-intervals. For those that bracket a root find the root. This is essentially implemented with find_zeros(f, a, b). The algorithm has problems with non-simple zeros (in particular ones that don't change sign at the zero) and zeros which bunch together. Simple usage is often succesful enough, but a graph should be used to assess if all the zeros are found:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["3-element Array{Float64,1}:\n -0.815553\n 1.42961 \n 8.61317 "]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["find_zeros(x -> exp(x) - x^4, -10, 10)"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

Classical methods

","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}}, {"cell_type":"markdown","source":"

The package provides some classical methods for root finding: newton, halley, and secant_method. We can see how each works on a problem studied by Newton himself. Newton's method uses the function and its derivative:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(2.0945514815423265, -8.881784197001252e-16, -1.0)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["f(x) = x^3 - 2x - 5\nfp(x) = 3x^2 - 2\nx = newton(f, fp, 2)\nx, f(x), sign(f(prevfloat(x)) * f(nextfloat(x)))"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(2.0945514815423265, -8.881784197001252e-16, -1.0)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["f(x) = x^3 - 2x - 5\nfp(x) = 3x^2 - 2\nx = newton(f, fp, 2)\nx, f(x), sign(f(prevfloat(x)) * f(nextfloat(x)))"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

To see the algorithm in progress, the argument verbose=true may be specified.

","metadata":{}}, {"cell_type":"markdown","source":"

The secant method needs two starting points, here we start with 2 and 3:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(2.0945514815423265, -8.881784197001252e-16, -2.524354896707238e-29)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["x = secant_method(f, 2,3)\nx, f(x), f(prevfloat(x)) * f(nextfloat(x))"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(2.0945514815423265, -8.881784197001252e-16, -2.524354896707238e-29)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["x = secant_method(f, 2,3)\nx, f(x), f(prevfloat(x)) * f(nextfloat(x))"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

Halley's method has cubic convergence, as compared to Newton's quadratic convergence. It uses the second derivative as well:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(2.0945514815423265, -8.881784197001252e-16, -2.524354896707238e-29)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["fpp(x) = 6x\nx = halley(f, fp, fpp, 2)\nx, f(x), f(prevfloat(x)) * f(nextfloat(x))"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["(2.0945514815423265, -8.881784197001252e-16, -2.524354896707238e-29)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["fpp(x) = 6x\nx = halley(f, fp, fpp, 2)\nx, f(x), f(prevfloat(x)) * f(nextfloat(x))"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

For many function, the derivatives can be computed automatically. The ForwardDiff package provides a means. This package wraps the process into an operator, D which returns the derivative of a function f (for simple-enough functions):

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["2.0945514815423265"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["newton(f, D(f), 2) # just newton(f, 2) works here"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["2.0945514815423265"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["newton(f, D(f), 2) # just newton(f, 2) works here"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

Or for Halley's method

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["2.0945514815423265"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["halley(f, D(f), D(f,2), 2) # just halley(f, 2) works here"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["2.0945514815423265"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["halley(f, D(f), D(f,2), 2) # just halley(f, 2) works here"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

Specifying the derivative(s) can be skipped, the functions will default to the above calls.

","metadata":{}}, {"cell_type":"markdown","source":"

Finding critical points

","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}}, {"cell_type":"markdown","source":"

The D function makes it straightforward to find critical points (where the derivative is $0$ or undefined). For example, the critical point of the function $f(x) = 1/x^2 + x^3, x > 0$ near $1.0$ can be found with:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["0.9221079114817278"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["f(x) = 1/x^2 + x^3\nfzero(D(f), 1)"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["0.9221079114817278"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["f(x) = 1/x^2 + x^3\nfind_zero(D(f), 1)"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

For more complicated expressions, D will not work. In this example, we have a function $f(x, \\theta)$ that models the flight of an arrow on a windy day:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["flight (generic function with 1 method)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["function flight(x, theta)\n \t k = 1/2\n\t a = 200*cosd(theta)\n\t b = 32/k\n\t tand(theta)*x + (b/a)*x - b*log(a/(a-x))\nend"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["flight (generic function with 1 method)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["function flight(x, theta)\n \t k = 1/2\n\t a = 200*cosd(theta)\n\t b = 32/k\n\t tand(theta)*x + (b/a)*x - b*log(a/(a-x))\nend"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

The total distance flown is when flight(x) == 0.0 for some x > 0: This can be solved for different theta with fzero. In the following, we note that log(a/(a-x)) will have an asymptote at a, so we start our search at a-5:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["howfar (generic function with 1 method)"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["function howfar(theta)\n\t a = 200*cosd(theta)\n\t fzero(x -> flight(x, theta), a-5)\nend"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["howfar (generic function with 1 method)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["function howfar(theta)\n\t a = 200*cosd(theta)\n\t find_zero(x -> flight(x, theta), a-5)\nend"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

To see the trajectory if shot at 45 degrees, we have:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"iVBORw0KGgoAAAANSUhEUgAAAlgAAAGQCAIAAAD9V4nPAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nO3deVxVdf4/8Bc7griU4K7lvk2WKEIuuYu47+ZS04xafUttvmU17es3zZqmtMWaFh0zS9PUFEXEHVFTwdw3FEKRQBFkES73/v64/sgU8S7nfj7nfM7r+fDxmBMD97wtvC/Pi8/nHC+bzQYiIiKz8pY9ABERkUwMQiIiMjUGIRERmRqDkIiITI1BSEREpsYgJCIiU/MVf0qLpezChZz69cPEn5qI6HpZRbhS6soXenmhhj8AVPeHt5e2Q5FoEoIwPT2zV6/Jqamx4k9NRHQqD9syseUctmUirwTd6uL+2gjxw9UyFFpQZkNeKQBcugoAeSUos6HAgpKya59gsSG/FDYbcksA4HIJrDZU9YOfNwJ9UMUXft6o6gtvL1T3B4AudfBwC9wdIu83TLcjIQiJiESyAYcvYev5a/nn7YUH6qJbXcxsj9Y1ocnlnD0pi8tQZEGpFVcssNpwuQQWK9alo/MKtLsDf22BUU0QxDdd/eF/EyJSUJkNR3OxIxPxGdh0Dn7e6FoHferjxfvQtqb2pwv2RfAt3k2jG+LdSKxPx39P4B87MbARHmqB3vW1CWDSBIOQiBRhsSLlIrZnXsu/mgHoUx+DGmFOJBpXlTmYvzcGN8bgxsgsxPen8UwSiix4sBkeaSl5MLJjEBKRgRVYsD/7WvIlZaFRVXStg9FN8GlX3Bkoe7ib1AnCjHaY0Q57s7HwODotR/s7Mak5K1PJvMTfdDs1NYOLZYjIZfml2JV17cpv5wW0qoE+DdClNrrVvbaS0yiKy7D6LBYex84sjLwbk5qjax3ZM5kS/xJCapo/f+n48TEhIcGyByHNnMrDp4cR9xvOXkFUGLrVxSvhiAhFgI/syQAAeXlXlixZN3XqKMe/JNAHo5tgdBOcvYJvjuGhTajmj0daYkIz1NLf5azCeEVIaiooKAoKCvTy4ooEFezIxL9+xbbzmNwKw+/GfXfCV3/3ArHZbIWFxcHBVVx/BWDzOXx9DKvPold9PNIS0Q30+DtVD68ISU3uvB+RTlhtWJOGWcnILML0dljY85YrM/XAy8vLze86L6BnPfSsh7wS/HQGH/6KqVsxugn+1hLt79RqTKoA/7JBapo/f2l+foHsKchFV0rx+RG0/gGv78WjrXF8LGa003UKAsjLu/L558s0ealq/nioBTYMxObBqBmAoevRcTk+PIicYk1enm7EapTUxGrUoNKv4KOD+Po4+tTH0/egU6jsgRzmfjV6K2U2rE/HN8exIxOro9GhluZnMDt9/xWLyFWsRg1nfzY++BVr0jCxOfaOMN4GO/er0Vvx8UJMI8Q0wsoziF6LhT0R3dAT5zEvVqOkJlajRmG1IT4Dg9dh4Do0qYaT4/Dh/cZLQWhajd7K0LuwKhp/24LFJz16HtNhNUpqYjWqf1fL8P0pzE5BgA+eaocHm8HPyH8z91w1eoPDlxATi7+2xGvhnj6VWbAaJTWxGtWzrCJ8chifHkZEKD68H33qyx5IC56rRm/QpiYShyEmFpeu4oMoPgRKA0b+CxjRrbEa1afjlzEjES2/x+k8bB6M1dGKpCCEVKPl6gVh82Ak52BMPIrLxJxTZaxGSU2sRvVmeyZmJ+OXbDzaGtPa6vFGoG4SVo2Wu1qGhzYhuxgr+qGaoe4tpzesRklNrEZ1osSKJSfx3gF4AU+0xdK+CNTHHdE0J6waLRfgg8W9MW0Huq5C7ADU5/0EXcVqlNTEalS6yyX48CCafofPj+LtTkgehamtlU1BiK1Gy/l44ZOumNAM3Vbh+GXBJ1cHq1FSE6tRiU7l4aOD+O8JDGqEZ9uj3R2yBxJCfDV6vQXH8dwurOiHqNpSzm9srEZJTaxGpcgqwnO7sDYdj7XGkTGobab/COKr0es93AJ3BGBYHBb0+GO7/ZgxM3///aKskTwqOrrLc8/9TatXYxCSmvgYJsGsNiw6ged2Y0wTnBhrxrUbLjyGSVuDG2N1fwyNw5sdMbkVACQmJn/wwcxatWrKGslD1q9PPHIkVcMXZBCSmiZOHBQUpNzCRL3al40ntsPPG3Ex+Is5itCbhYQET5gwUO4MEWHYPgTRa/FbwbXt9lFR7Rs0UK0tPXv2XGZmtoYvyCAkNbEaFSO3BK/+giWn8GZHTGkNM/9IVm41Wq5pNWwdgphYXLwqexTj4KpRUhNXjXqaDVh4HK1/wKWrODwaU82dgpC0arRCdYOwbQiO5aKgVPYoBsErQlITq1GPSsnBEztQbMHKfogIkz2NPuihGi1X1Q+ro1Hb5H83cRiDkNSkh5JKSQUWvLkPXx3Fix0wrS1vdPkHnVSj5fy99f4oY/1gNUpqYjXqCavPos0POFeAQ2Mwox1T8E/0U42Ss/gXBlITq1FtHb+MJ3fg9yIs6c0t2xXTVTVKTmEQkpp0VVIZWqEF76bg08N44T482RY+vAq8Bb1Vo+Q4VqOkJlajmlh9Fm2X4nQeDozCjHZMwcqwGjUuXhGSmliNuulkHqbvwOl8fNFdnUcGehSrUePiFSGpKTi4Cu+47ZoiC17bi84rEBGGA6OYgo5iNeqmBQtWZWXJuTOqu0GYnZ37zDPvjxv37PWdQHp65vTps8aNe/b99xdaLHx8MknAatQ19i507+9IHonXwuHPvyo7jNWoy4qKrr788scvvjg3OztXygDufps/+ugbDz00+NtvZ2VkZCUlHQBgs9kee+ytGTMmLF48q27dWrNmfanFnETOmThxUNWqQbKnMJLfCjAmHk8n4dNuWB2NhlVlD2Q0rEYdkZV18cKFHPvxhQs55ZeAgwZ1nzx5hKyp3PoZYWpqRqNGde+5pwWA11//H/sHDx482bFjm6ZNGwIYPz5m+PB/uD8lkbNYUjmu1IpPDuPtffiftvhvTwSo++xcjzJENbr1PL46JuhcD9TFIy1v/GBubv68ed999NHzAN5++4snn3wwLOyOKlUCOnf+S2zsdkGT3cStK8KjR1NPnkwbNOjJUaOenjLl9atXSwCkpmY0b964/HP8/CrI2pycy1WrRt78a9iwGStWJAA4cuQ0D3jgzsHjj7+Vn18gfQz9H7z6fXLbpfj5WMHbwYmvheP0cb0MZriDPXsOPv7429LHuP6gtNSCP6sbhB71BP1qWQM3a9Gi8fnz2ZcvX8nPL8jKutiiReMKPskxlfzenWZzw7JlG8aNe9ZqtdpstlWrNr///kKbzfbjj/HffRdb/jmjRz9zw1edPv1b48b98/MLbv5VWFhUWmqx2WxlZWU84IE7B7m5+VarVfoYej4ostie3G5t/K1tbZou5jH6gcViyc3Nlz7G9Qf16/dJT8+06cyaNVv//e9FH3zw37Vrt13/8Vdf/eTQoVOOvMLXX//08MMvVfJ7d5Zb1WhISHC3bh3sa/P69YtasmQdgNDQmvv2HSn/HKvVevMXenl5Vf7zG29vb29vHvDA9YPq1asC8PLy0sk8ejs4locHN6Jlda/kUajhb/+YLgYz7oGPj4/9u04n81z7H/2Jju7y8cffA5g+fbw7r1PJ793pl3JnjsjIe+LidtpsNgBxcTvvvbclgPDwNgkJu+0fTEs7b//OIBKMq0YrsfA4uq/CIy3xfR97CpIGuGrUQd7e3pGR9/Tvf/8NqRUQ4O/vL2dru1tnrVYteOLEgYMHTwsI8A8Lu+Pf/34WQFBQ4KRJgwYPnlalSmBpqWXu3Oc1GpXICdxQX6G8Ejy2HQdykDDIvI+S9xCuGnVQcfHVxMTkZcvev+Hj//zn36XMA/fvLDNqVN9Ro/o68kEikfS/fk+83VkYn4De9bFnOKrwplJaM8SqUen27Dn09ttfvPDCZF39u9JpiUzkJlaj17Pa8OFBDIvDv+/H/G5MQY9gNeoIX1+fjz9+oVu3DrIH+RP+gSA1sRot91sBJibA2wt7hqN+sOxp1MVq1BH33ddK9ggV4BUhqYn3GrX76Qw6LkePeogfyBT0LFajxsUgJDWxGi0uw4xE/GMnfuyL18L5NHmPYzVqXKxGSU0mr0aP5OLBjWheHftGoGaA7GnMgdWocfGKkNRk5mq0fJvg0j5MQXFYjRoXg5DUZM5q9HIJxm3EhwexYyhmtJM9jcmwGjUuBiGpyYSPYUrKQoflqF0FiUPRorrsacyH1ahx8WeEpCZTlVRlNry5D/OP4D/dMbCR7GnMSofVqJeX1/vvLwwJUe1vhCkpx2vWrKbhCzIISU3z5y8dPz4mJET9HQPpVzAhAf4+2DsC9VR7xzOSvLwrS5asmzp1lOxB/rBq1UerV29x+cvLbJh3EIMao6mWoaOB8PA29ltba8XLfndskVJTM3r1mpyaGiv4vGQqBQVFQUGByq+XWXEGj23D423wSgdukJDMZrMVFhbr7aLQTUtP4+392DdC8e8u/oyQ1KT8qtEiC2Yk4n934qd+3CaoCzqsRt03uglC/LDguOw5PIxBSGpSe9XooUvo/BPOF2L/SETVlj0NAVB31ej7kXj5FxTc+Kx7pTAISU0KrxpdeBy9f8bM9viBTxPUE1VXjUaEoXtdvJciew5P4mIZUpN6JRWAnGI8sgWZhdgxVHfrF0jJatTunQiEL8eU1squxuIVIalJvWrUXoe2qM4U1ClVq1EAjaticiu8tEf2HB7DVaOkJsVWjcam45HNmN0ZD7eQPQrdgpKrRsvll6Ll91gdjfBaskfxAF4RkppUWjX64UFM3YqV/ZmCuqZwNQogxA8vd8DMJNlzeAaDkNSkRjV6tQwPb8aC49gxFJ3DZE9DlVK4GrWb2hq/F+PnNNlzeACDkNSkwKrRc4XovhpXy7B9CBpVlT0N3Y6qq0bL+XhhdgSeSUKpVfYoWmMQkpqMXo3uz8b9P2FAQ3zXG0Fc3G0EalejdjGN0LgqPj8iew6tMQhJTYauRpecQnQs/n0/XguHgcPcZJSvRu3mROLNfbhcInsOTXHVKKnJoKtGbcDre7HoBFb2R9uasqchZ6i9avR6k7fizgDM7ix7Du3wipDUZMRqNL8Uw+OQkIGdw5iCxmOGatTu7U746hhO5cmeQzsMQlKT4arRU3mI+gm1q2DjIIQGyp6GnGeSahRA7SqY1g4vKrS/nkFIajLWqtGt59FtFR5tjfnd4Mc/lMak/KrR6828BzsvYHum7Dk0wj9zpCYDVaOfH8HYjfi2F6a1kz0KucE81SiAKr54oyOeSYLoNSaewSAkNRmiGrVYMW0H5h1C4lD0rCd7GnKPeapRu0nNUWbDD6dkz6EFrholNel/1WhOMUbHI8gXi3uhGp+mZHzmWTVabst5/HUzjoxBoI/sUdzDK0JSk86r0V8votMKRIRhVX+moCJMVY3aPVAX7e/E3IOy53Abg5DUpOdqdE0a+qzBGx0xKwLe+g1rco7ZqlG79yPxbgouFMmewz2sRklN+qxGbcC7yfj4MH7si06hsqchTZmwGrWbngirDfO6yJ7DDbwiJDXpsBotLsNDm7DyLHYPYwoqyITVqN3r4Vh6GocuyZ7DDQxCUpPeqtGMAnRbBasNGweijmH2N5ITzFmNAqgZgGfb4/ldsudwA4OQ1KSrDfU7L6DzTxh1N77thSp8lISiTLWh/gbT2uFoLjb8JnsOVzEISU36qUb/ewLD4/DlA3juXtmjkCeZthoF4O+N/4vAs7tgNeYGewYhqUkn1ei7KXjlF2wejP4NZI9CHmbaatRuVBME+2HBcdlzuISrRklN0leN2oDnd+HnNKwbgIZ8vrwJmHbVaLndWRixAcfGItho/T+vCElNcqtRixWTt2DreWwdzBQ0CzNXo3YRYeheF3NSZM/hPAYhqUliNVpgwZD1yC5GwiDcyQcqmYbJq1G7dztj3iGkX5E9h5MYhKQmWatGL15F3zWoXQU/9uUCUXMx86rRcg2CMaUVXt0rew4nMQhJTVKq0TP5uH8lutfFVz3gyz9bJsNq1O6F+7AuHXuzZc/hDP5hJTWJr0YPXUL31ZjaCrMioIt9GyQWq1G7ED+83AHPJMmewxkMQlKT4Gp0y3n0+hlzOuN/7xF2TtIXVqPlprZGdjFWn5U9h8MYhKQmkdXoyjMYvQH/7YmxTcWckPSI1Wg5Hy/MjsDMXSi1yh7FMQxCUpOwavTrY3hiB9bHoB+3zJsbq9HrxTRC46qYf0T2HI7hhnpSk5gN9bOT8flRrBuA5tU9eh4yAG6ov8GBi+j9M46NxR0Bske5HV4Rkpo8XY2W2fD4diw9jZ1DmYIEsBq9yT13YOhdmJUsew4HMAhJTR6tRovLMCYeJy9j02CE8a2PALAarcgbHfHZYQP8pJBBSGry3KrRK6UYsh4AVkcjxM8TZyBD4qrRm9ULwl0hSMmRPcftMAhJTR6qRjML0W0VWlbH0j4I9NH85cnAWI1WKKo2dl6QPcTtMAhJTZ6oRk/noftqDL0Lc7vAm3vm6c9YjVYoqjaSsmQPcTsMQlKT5tXoL7+j6yrMbI/XwjV8VVIHq9EKRYbxipBIEm2r0Y0ZiInFvC6Y0kqrlyTVsBqtUMsayC9FZqHsOSrFICQ1aViNfnsS4xOwvB9G3K3J65GaWI1WyAvoFKr3dpRBSGrSqhr96CCe34UNA9G1jvsvRipjNXor+l8vwyAkNblfjdqA1/bis8PYMRT33KHVXKQsVqO3wiAkksPNarTMhqlbEZuOrUPQqKqGc5GyWI3eSucw7M9BiY631TMISU3uVKOFFgxdj8xCbBqEWoHazkXKYjV6KyF+uDsEB3S8rZ5BSGpyuRq9eBX91uLOQCzvhyBfzeciZbEarYTO21EGIanJtWr0XCF6rEZ4LXzTA378w0HOYDVaiaja2KnjhaP8s05qcqEaPZqLyJ8wuRU+vB+8bww5i9VoJSLDkMQrQiLBnK1GD19CnzV4uxOmt/PcUKQyVqOVaFkDl0v0u62eQUhqcqoaPZKL/mvxTgQmNffoUKQyVqOV8AIidXzTUQYhqcnxajQlB71+xqzOTEFyC6vRyun5pqMMQlKTg9Vocg76r8W/IjGhmYChSGWsRiun54WjDEJSkyPV6P5sxMTi0254kClIbmM1Wjk9b6tnEJKabluN7stGzDp80hXD7xI1EymN1Wjl9LytnkFIaqq8Gt2bjYHrML8bht0lcCZSGqvR29JtO8ogJDVVUo0mXsCAtfi8G4Y0FjwUqYzV6G3pdls9g5DUdKtqdEcmRsTh214YzBQkTbEava0ovS4cZRCSmiqsRrdlYuQGLOqFvg2kDEUqYzV6Wy1q4EopzutvWz2DkNR0czW69TxGbcDi3uhTX9ZQpDJWo7flBUSE6XFbPYOQ1HRDNbrlPEbHY0lv9KoncShSGatRR0Tp8qajDEJS0/XV6PrfMGoDvu+NnkxB8hhWo47Q58JRBiGpqbwaXZeOhzdhdTR6MAXJk1iNOiJCl9vqGYSkJns1ujYNf92Mlf0RGSZ7IFIdq1FH6HNbPYOQ1BQcXGVtutfftmBVf3RmCpLnsRp1kA7bUQYhqemxz3c+stm2OhoRTEESgtWog3S4rZ5BSApaehrLAyPXDkCnUNmjkGmwGnWQDrfVMwhJNT+cxlOJ2DjIq2OoE0+oJ3ITq1EH2bfVn9PTtnoGISllySn8IxHrY5C41Ikn1BO5j9Wog+zb6nfpqR1lEJI6vjuJp3cibiDa3eHEE+qJNMFq1HF6a0cZhKSIr47hmSRsGIi2NQGHn1BPpBVWo47T28JRBiGp4D9H8fpebBmCNjWvfcSRJ9QTaYjVqOMiwrA/W0fb6hmEZHhfHMVb+5AwCM2q/fFBVqMkGKtRx4X4oWk1HW2rZxCSsc0/gv/bj42D0LTanz7OapQEYzXqFF21owxCMrBPD2NWMhJuSkGwGiXhWI06JVJP2+oZhGRU/zqAOSnYNAh3h1Tw/7IaJcFYjTpFVwtHGYRkSO8dwPwj2DYEd1WUgmA1SsKxGnWKrrbVMwjJeN5NwX+OImEQ6gff8nNYjZJgrEadoqtt9QxCMpjZyfj62G1SEKxGSThWo87STzvKICQjeW0vvjmOhEGod7uMYzVKgrEadZZ+Fo4yCMkwXv0FK1KxdQjqOnClx2qUBGM16qyIMCTnoFQH2+oZhGQMHx7EklOIG4jQQIc+n9UoCcZq1FkhfmgSgmQdbKtnEJIBfHUMHxzAhoGo7XDzxGqUBGM16gKdtKMMQtK7RSfw2l4kDEKjqk58FatREozVqAuiaiNJBwtHGYSkaz+dwbO7sG4Amtx075jKsRolwViNuiBSHwtHGYSkX/EZeHQbVkf/8UwJx7EaJcFYjbpAJ9vqGYSkU4kXMCEBy/oivJYrX85qlARjNeoCnWyrZxCSHiXnYEQcFvZEtzouvgKrURKM1ahr9LCtXpsgvHjx8hdf/Fj+j+npmdOnzxo37tn3319osZRpcgoyj4MXMSAWX3RH/wauvwirURKM1ahr9LBwVJsgnDFjdnx8kv3YZrM99thbM2ZMWLx4Vt26tWbN+lKTU5BJnMzDgFh8EIXBjd16HVajJBirUdfo4Wn1GgThl1+u6NSpXfk/Hjx4smPHNk2bNvT29h4/Pmbv3iPun4JM4rcC9FuDV8Ixrqm7L8VqlARjNeoa+9PqU6Ruq3c3CE+dSl+3bse0aQ+WfyQ1NaN58z/+Mu/n53vzVxUUFD399Hs3/5o377uUlGMAMjOzeWC2g6wi9FxZNrzm71NaafCCJ0+meXl56eH3xQOTHFy4kHPyZJr0MYx40D6keNm+LA1f0FkVpJTjLJayp55694svXr3+hzEWS5mvr0/lX+jt7V2vXtjNH7/zzppVqgQC8PX15YGpDkr9gqJjMbZx6UOhhZq84MqVm5s0aSD998UD8xwUFV1dtWpL+/YtdTKPgQ4ialnXpQdr+ILO8rLZbC58md2vv554883P7cdJSQciI+955ZVHL13K27fvyIwZE+wfHzXq6WXL3r/+q1JTM3r1mpyaGuvyeUkxeSXoswZd6uCDKM1es6CgKCgokOtlSBibzVZYWMz1Mi44fhn91yL1QWkDuHVF+Je/NP/hhzn247FjZ37//RwAhYXF7723YPr08V5eXmlp56tXd+a+WGQ+RRYMWY9OoVqmIAC+H5FgXDXqsubVr22rv+3j1TxEs32EwcHXfgdBQYGTJg0aPHja6NHPTJ8++7XXHtfqFKSeEitGxaNRVcztovErc9UoCcZVoy7zAjpL3VbvVjXqGlajZFdmw/iNKLXihz7w1frWDqxGSTBWo+54ax/ySvFuZzln551lSA4b8Og2XCrBd721T0FwQz0Jx2rUHXK31TMISQIb8MR2HM3Fin4IuM0SYxexGiXBWI26Q+62egYhSfDP3dibjdgBCHZrtVZluKGeBOOGenfI3VbPICTR3tiHtWmIHYAQPw+ehdUoCcZq1E0S21EGIQk19yAWnUBcDO4I8OyJWI2SYKxG3cQgJFP45jjeO4ANA1HH850lq1ESjNWomxiEpL4fU/HibsTFoLGQWyywGiXBWI26qXl1FFiQIaPHYRCSCKvO4skdiBuIljUEnZHVKAnGatRNErfVMwjJ4zZmYMpWrO6PtjXFnZTVKAnGatR9UbWRxCAk9SRlYXwClvZBx1Ch52U1SoKxGnWfrB8TMgjJg1JyMGw9vumB7nVFn5rVKAnGatR9nULlbKtnEJKnHL+MmFjM7YIBDSWcndUoCcZq1H2yttUzCMkjTueh98+YE4nRTeQMwGqUBGM1qgkp7SiDkLSXVYT+a/HifRjfTNoMrEZJMFajmmAQkgrySxETi4nN8VgbmWOwGiXBWI1qgkFIhldqxegNCA/Fq+GSJ2E1SoKxGtWElG31DELSjA2YvBUBPvhY68fNu4DVKAnGalQTUrbVMwhJM0/vxJl8fO+Bx827gNUoCcZqVCvi21EdvGOREmYlY0MGfuqHQM88aNdZrEZJMFajWhF/fxkGIWlg0Ql8ehhro1HTww9XchyrURKM1ahWOochOUfotnoGIblrTRpm7sL6GDQU8lgJB7EaJcFYjWol2Ff0tnoGIblldxYe2Ywf+6KVqMdKOIjVKAnGalRDgn9MyCAk1524jOFxWNAT99eWPcpNWI2SYKxGNRQZxiAkIzhXiH5r8XaEnFuJ3harURKM1aiGeEVIBnC5BDGxeKIt/tpC9ii3wGqUBGM1qiHB2+oZhOS0IgsGr0PXOnjmHtmj3BqrURKM1aiGBG+rZxCSc8psmLgJDario/tlj1IpVqMkGKtRbYlsRxmE5JynEpF7FV8/AG99946sRkkwVqPaiqqNnbwiJB16+RckZWFlfwTo4/YxlWA1SoKxGtVW5zCkiNpWzyAkR80/giUn8XM0qvrJHsUBrEZJMFaj2rJvq0/OFnEuBiE5ZOUZvL4XawegtkG6H1ajJBirUc0Ju+kog5Bub8t5TN2GNdFoXl32KA5jNUqCsRrVXJSobfUMQrqNXy9iTDwW9cR9tWSP4gxWoyQYq1HNCVs4yiCkyqTmY0As5nVB3wayR3ESq1ESjNWo5pqJ2lbPIKRbyi7GgFg82x6jm8gexXmsRkkwVqOaE7atnkFIFSu0YMh6jG2C6e1kj+ISVqMkGKtRTxDTjjIIqQKlVozcgHY18XpH2aO4itUoCcZq1BPEbKtnENKNbMCUrfDzxiddZY/iBlajJBirUU8Qs62eQUg3mpmEY7lY0hu+Rv7uYDVKgrEa9QQx2+qN/FZHHjAnBevSsWYAgnxlj+IeVqMkGKtRDxHQjjII6Q+LT2LuIawdgDsCZI/iNlajJBirUQ8RsK2eQUjXxP2Gp5OwPgaNqsoeRQusRkkwVqMeElkbSQxCEuDQJTy8Gcv6oHUN2aNohNUoCcZq1EOaV0ehh7fVMwgJ5woxMBbvRaJLHdmjaIfVKAnGatRDBGyrZxCaXX4pBsbi8TaY0Ez2KJpiNUqCsRr1nEgPb6tnEJpamQ0TExAeiufulT2K1o9ouswAABUWSURBVFiNkmCsRj3H0wtHGYSmNiMRJVZ8ZuSN87fCapQEYzXqOZ7eVs8gNK/Zydhy3vAb52+F1SgJxmrUczy9rV7Ft0BywNLTmHcIa6NR3V/2KJ7BapQEYzXqUR5tRxmEZrQ7C9N2YHU0GiqxZbBCrEZJMFajHuXRbfUMQtM5nYdhcfiiO+69U/YonsRqlARjNepRHn0eE4PQXHKKMSAWL3XA4MayR/EwVqMkGKtRj2pWHUUe21bPIDSR4jIMjcPIu/E/bWSP4nmsRkkwVqMeZd9Wn+SZHxMyCM3CBkzegnpBeKuT7FGEYDVKgrEa9bQoj910lEFoFv/cjbNXsLAnvM3RF7IaJcFYjXqa5xaOMghN4cujWHYay/sh0Ef2KKKwGiXBWI16WkQYkrNxtUz7V2YQqm9dOl7cg7UDEBooexSBWI2SYKxGPS3YF82rIyVH+1dmECru4EX8dTOW90OL6rJHEYvVKAnGalSASM+0owxClZ0rxMB1+FcU7q8texThWI2SYKxGBfDQtnoGobLsz1d6si3Gq/V8JQexGiXBWI0K4KFt9QxCNZXZMCEBHUMxs73sUSRhNUqCsRoVwEPb6hmEapq+AxYrPlXx+UoOYjVKgrEaFcBD2+oZhAp6JxnbMvGdos9XchCrURKM1agYnmhHTfxOqailp/HJIawdoOzzlRzEapQEYzUqRlRtXhFSpbZn4ont+DkaDYJljyIbq1ESjNWoGJ7YVs8gVMepPIyNx6JeaK/085UcxGqUBGM1KoYnttUzCBWRU4yYWLzcAf0ayB5FH1iNkmCsRoXR/KajDEIVFJdhyHqMaYrHTPB8JQexGiXBWI0KE6n1tnoGoeHZgL9vQcOqeKOj7FH0hNUoCcZqVBjNF44yCA3vuV1Iv4IFPcAe8HqsRkkwVqPCaL6tnkFobP85ihWp+LEfAkzzfCUHsRolwViNCqP5tnoGoYHFpuPlX0z3fCUHsRolwViNiqRtO8ogNKqDF/HIZizvi+Yme76Sg1iNkmCsRkViEBLSr2BALD7uiijzPV/JQaxGSTBWoyJ1CsWBiyixavNqDELjKbBgyHo89ReMvFv2KDrGapQEYzUqUlU/NKuG/dnavBqD0GCsNkxMwH218PQ9skfRN1ajJBirUcE0vOkog9BgXtiDnGJ81k32HLrHapQEYzUqmIY/JmQQGsnC41h6Gj/2gz//u90Oq1ESjNWoYAxCM0q8gGeSsKo/N0s4hNUoCcZqVLCm1TTbVs8gNIYz+Ri1AV/3QNuaskcxCFajJBirUcE03FbPIDSA/FIMWY8X78PARrJHMQ5WoyQYq1HxtGpHGYR6Z7VhQgIiwvBEW9mjGAqrURKM1ah4DEKzmLkLxWX4rKvsOYyG1SgJxmpUvIgwpORo8LR6BqGufX0Ma9LwfW/48j+Uk1iNkmCsRsWzP60+2e2n1fP9Vb+2ZeKFPVjVHzUDZI9iQKxGSTBWo1Jo0o4yCHUqNR/j4rGoJ1rwntouYTVKgrEalUKT+8swCPUorwRD1uPlDuhdX/YohsVqlARjNSoFrwjVVGbD+AT0qY/H2sgexchYjZJgrEal0GRbPYNQd55KhMWKOZ1lz2FwrEZJMFajUngBkW63owxCffnyKDZmYEkfLhN1F6tREozVqCzut6N8u9WRLefx8i9YFY0a/rJHMT5WoyQYq1FZIsMYhKo4losx8VjcC82qyR5FCaxGSTBWo7K4v62eQagLF69iyHq81Qk96skeRRWsRkkwVqOyuL+tnkEoX6kVY+Ix7C5MaSV7FIWwGiXBWI1K5OaPCRmE8k1PhL83/i9C9hxqYTVKgrEalYhBaGz//hVbz2NJb/jw6kVTrEZJMFajEkXVxk43dlAwCGVa/xveO4DYAajGZaJaYzVKgrEalahZNZSUub6tnkEozZFcPLwJS/ugUVXZo6iI1SgJxmpUrgg3nlbPIJQjpxhD1uG9SETVlj2KoliNkmCsRuVy58eEDEIJSq0YHY9xzTCxuexR1MVqlARjNSpXlBvb6hmEEjyxHTUD8Hq47DmUxmqUBGM1KlcnN7bVMwhFezcFv2RjYU9483LFk1iNkmCsRuUK9kWLGi5uq/d189ypqRkffvjthQs54eFtpk8f7+/vByA9PXPOnG+ysi526tRuxowJvr4+bp5FGbHpmHsQiUMR7O6/eLoNllQkGKtR6ew3He0c5vQXuntFOG3aO9OmPbho0TsNG9aZPftrADab7bHH3poxY8LixbPq1q01a9aXbp5CGYcv4ZHNWNYXDblM1PNYjZJgrEalc3m9jLtBOHRoz6ZNG/r4ePftG5mamgHg4MGTHTu2adq0obe39/jxMXv3Hrn5q8rKrMePn735V1raefubV0lJqWIHp34vjInFB53L2lTRxTzKHwwb1rNq1SDpY/DAPAcBAf5Dh/aQPoaZDzreYUnMtMF57gbhlCkj7QevvvrplCkjAKSmZjRv3rj8E/z8KigB8/KuDBr05M2/Xn310x07kgGcPXtepYOTZzKHrLU80hIdvTL0MI8ZDvbvP+bl5SV9DB6Y5yAtLXP//mPSxzDzgc/Fc/nFFhe21XvZbK7k5w2+/HLF+fO/v/TSVADLl28sKSkdNy7a/n+NGTPzhx/mXP/JqakZvXpNTk2Ndf+8RvHoNmQVYXk/cH2MMPPnLx0/PiYkJFj2IGQWeXlXlixZN3XqKNmDmNqQ9XioOUY1ce6rNFg1+uOP8Xv3Hn7xxSn2fwwNrXnhwh8Ld6xWq/unMLSPD2HbeSzowRQUiqtGSTCuGtWDqNqu3F/G3SBcvnzjunU75s37Z/nm5fDwNgkJu+0Xmmlp56tXN/XKkB2ZeGs/VkXzbqKicUM9CcZVo3rg2rZ6t1bxp6QcmzTphQEDuo4b9xyAqlWDvvrq9aCgwEmTBg0ePK1KlcDSUsvcuc+7cwpDS7uC0fH4+gE+dF4CVqMkGKtRPSjfVh/gzK49bX5G6BST/IywyILuqzGhGZ76i+xRTKmgoCgoKJAXhSSMzWYrLCzmRaF0HZbj067O7SbknWU8wgb8fSta12AKSsNqlARjNaoTLrSjDEKPmJWMY7mY3032HCbGDfUkGDfU64QL2+oZhNqL+w0fH8LK/qjC+6jJw1WjJBhXjepEpPNPq2cQauz4ZUxMwHe90YCrNKRiNUqCsRrVCfvT6n9zpg9iEGopvxTD4/B2BLrVkT2K6bEaJcFYjepHRBiSnGlHGYSasdowfiN618eUVrJHIVajJByrUf2IcrIdZRBq5qU9yC3Be5Gy5yAArEZJOFaj+uHswlEGoTaWp+K7U1jeD/78N6oPrEZJMFaj+tEpDAeceVo937Y1kJKDR7dhWV+EBsoehf4/VqMkGKtR/XD2afUMQnflFGPkBszrgvBaskeh67AaJcFYjeqKU+0og9AtFitGx2NcU4xtKnsU+jNWoyQYq1FdcWpbPYPQLU/thL83Xu8oew66CatREozVqK44tXCUQei6BccRn4Hv+8CHDZz+sBolwViN6kpTZ7bVMwhdtPMCZiZheV9U54MGdYnVKAnGalRvOju8rZ5B6IrzhRi7EV/3QJuaskehW2A1SoKxGtUbx286yiB0WnEZhsXhybYY2Ej2KHRrrEZJMFajeuP4wlEGodOe2I6GwZjZXvYcVClWoyQYq1G9cXxbPYPQOf86gH3ZWNgTvNbQOVajJBirUb2xb6vf78C2egahEzZm4N0ULO+HID5oUPdYjZJgrEZ1yMF2lEHoqDP5mLQJS3rj7hDZo5ADWI2SYKxGdSiqtkMLRxmEDrlSiiHr8XIH9KgnexRyDKtREozVqA45uK2eQXh7NuDvWxBeC4+3kT0KOYzVKAnGalSHHNxWzyC8vdf34rcCfNZN9hzkDFajJBirUX1yZFs9g/A2Vp7Bf45iaV8E+MgehZzBapQEYzWqT460owzCyhzNxaPbsKIf6vEd1WhYjZJgrEb1KdKBhaMMwlu6dBWD1+GdCHQKlT0KOY/VKAnGalSfHNlWzyCsWJkNExIw7C480lL2KOQSVqMkGKtRfXJkWz2DsGLP7oLFhnciZM9BrmI1SoKxGtWt226rZxBWYNEJrEjF4l7w5b8ew2I1SoKxGtWt2z6tnu/0N9qfjaeTsKo/agXKHoXcwGqUBGM1qltRtbEjs7JPYBD+yYUiDIvDx13Q7g7Zo5B7WI2SYKxGdatpNZTZKttWzyD8Q4kVIzfg760wqonsUchtrEZJMFajelb5tnoG4R/+dydCA/FyB9lzkBZYjZJgrEb1rPJt9QzCaxafRNxv+KYHHzSoCFajJBirUT2rfL0MgxAAfr2If+zE8r6o7i97FNIIq1ESjNWonnUKrWxbPYMQuSUYEYcPorhARimsRkkwVqN6FuSLljVwrrDi/9fsj1q3P2JpYCOMbyZ7FNIUSyoSjNWozkXVvuX/ZfYrwnf2I7MQcyJlz0FaYzVKgrEa1bnJrW65O9zLZrOJHQapqRm9ek1OTY0VfN6bbczAQ5uwezjqB8sehbRWUFAUFBTI9TIkjM1mKyws5kWhEZm3Gk2/gkmb8F1vpqCa+H5EgrEaNS6TVqNXyzByA56+Bw/UlT0KeQarURKM1ahxmbQafXQbsoqwvB93DSqL1SgJxmrUuMxYjS46gc3nsGc4U1BlfD8iwViNGpfpqtGUHDydhOX9UI1755XGapQEYzVqXOa6Irx0FSM3YG4XtK0pexTysIkTBwUF8UlaJA431BuXiYLQasPETRh2F8bw4RImwJKKBGM1alwmqkbf2Ifcq3gnQvYcJASrURKM1ahxmeWKMD4DXxzBnhHwM1H0mxqrURKM1ahxmSIIz17BpE34oQ/q8SbMpsGSigRjNWpc6l8fFZdhZBz+eS+61ZE9CgnEapQEYzVqXOpvqP/7FhRa8F1vMWcjveCGehKMG+qNS/Fq9PMjSLyA3cNlz0HC8f2IBGM1alwqV6PJOXj5FyzvhxA/2aOQcKxGSTBWo8al7BXhxasYuQEfd0HrGrJHIRm4apQE46pR41IzCK02TEjA6CYYxb3zZsWSigRjNWpcalajr/yCq2V4q6PsOUgeVqMkGKtR41LwivDnNHx9DL+MgK+aKU8OYTVKgrEaNS7VgvBMPqZsxbI+qMu98+bGkooEYzVqXEpdNBWXYeQGvNwBXbh33vRYjZJgrEaNS6kN9Y9sRokV3/bS/IXJeLihngTjhnrjUqca/eQw9mYjaZjsOUgf+H5EgrEaNS5FqtFdWXhjL5b3Q5A6yU5uYTVKgrEaNS4VciOnGOM24tNuaFZN9iikG1w1SoJx1ahxGT4IrTaMT8DE5hh+l+xRSE9YUpFgrEaNy/DV6At7UGbDa+Gy5yCdYTVKgrEaNS5jXxGuOoslJ7FnBHy4NpD+jNUoCcZq1LgMHIQnLmPKVvwcjVC+3dFNWFKRYKxGjcuo1WiBBSM24K1O6BQqexTSJVajJBirUeMy6ob6hzfDasN/e2o1FKmGG+pJMG6oNy5DVqMfHkRKDhKHyp6DdIzvRyQYq1HjMl41mpSFd/ZjeV/unafKsBolwViNGpfBwuRCEcbE46sH0IR756lSXDVKgnHVqHEZKQgtVoyNx99bIqaR7FFI91hSkWCsRo3LSNXo87vh74OXOsieg4yA1SgJxmrUuAxzRfjTGfyYij3DuXeeHMJqlARjNWpcxgjC45fx6DasHYBafGcjx7CkIsFYjRqXAarRK6UYHod3IhBeS/YoZBysRkkwVqPGpfcN9TZgXDxqBGB+N0/PRUrhhnoSjBvqjUvv1ei/DuD4Ze6dJ6fx/YgEYzVqXLquRhMvYE4KlvdDFb3nNekOq1ESjNWocek3YTILMTYe3/TA3SGyRyED4qpREoyrRo1Lp0FYasWYeDzWBtENZY9CxsSSigRjNWpcOq1Gn0lCdX/8817Zc5BhsRolwViNGpcerwiXnMKqs/hlOLy54o9cxWqUBGM1aly6C8KjuZiRiNgBuJNvYuQGllQkGKtR49JXNZpfihFxmN0ZHbh3ntzDapQEYzVqXDraUG8DxsSjdhXM6yJ4IlIQN9STYNxQb1w6qkZnJyP9Chb1lD0HKYHvRyQYq1Hj0ks1uukcPjqIZX0R4CN7FFICq1ESjNWoceniivB8ISZtwjc90CBY9iikCq4aJcG4atS45AdhqRWj4zG9Hfo1kD0KKYQlFQnGatS45FejTyXizgDMbC97DlILq1ESjNWocUkOwsUnsSEDC3uCa/tIW599tjQvj0FI4uTlFXz22VLZU5ArZFajv17EP3Zi40BU95c4BakpOzvXarXKnoJMxGq1Zmfnyp6CXCHtijC3BCPiMKcz2t0hawQiIiJZQejl9bfNGNgID7WQc34iIiI7OdVoXqdhWcX4vo+UkxMREf1BQhDWrFmtptfVHQ/38c/9XfzZyTwaNeovewQyHS8vroDXrzNn1jVuXPfmj0u416idrPMSEZE53ermw9KCkIiISA/kb6gnIiKSiEFIRESmxiAkIiJTk3/TbSJNzJ373bZt++zHr7zyaLt2zQCkp2fOmfNNVtbFTp3azZgxwdeXT/kibSxYsGrAgK5hYdduCFLhdxq//QzDRqSEUaOevuEjVqs1JuaJkyfTysrKvv12zZtvzpcyGCmmsLD4pZfm1a/f59ChU/aPVPidxm8/A2E1SoooLbVs2rRnxYqEtLTz9o8cPHiyY8c2TZs29Pb2Hj8+Zu/eI3InJGUMGtR98uQR5f9Y4Xcav/0MhEFIijh5Mu3XX08UFRW/9NK8BQtWAUhNzWjevHH5J/j58QcBpIEqVQI6d/7L9R+p8DuN334Gwv82pIiDB5fbD8aPjxkyZPrDDw+xWMr4UxkSoMLvNH77GQivCElBAQH+AEJDa164kFP+QT6ViTykwu80fvsZCIOQVJCYmDx79lf245ycXIulDEB4eJuEhN02mw1AWtr56tWryhyR1FXhdxq//QyE1Sip4P777123bsfw4f/w8/O1WCyzZz8FICgocNKkQYMHT6tSJbC01DJ37vOyxyR1BAT4+/tfe/+s8DuN334GwnuNEhGRqbEaJSIiU2MQEhGRqTEIiYjI1BiERERkagxCIiIyNQYhERGZGoOQiIhMjUFIRESmxiAkIiJTYxASEZGpMQiJiMjUGIRERGRqDEIiIjI1BiEREZkag5CIiEyNQUhERKbGICQiIlP7f7DF0HAT5hsYAAAAAElFTkSuQmCC"},"metadata":{"image/png":{"height":480,"width":600}},"execution_count":null}],"cell_type":"code","source":["theta = 45\nplot(x -> flight(x, theta), 0, howfar(theta))"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"iVBORw0KGgoAAAANSUhEUgAAAlgAAAGQCAYAAAByNR6YAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAIABJREFUeJzs3Xl4VNXh//H3uXeSQBKSEPZAQlgCyKKgoEFFZBVBEapoq1JtXaqttYv9Cda2tlZttX5tq62lWsUq1YJ1bUFkEUHEJSrggqAogbAvIQRIQjL3nt8fg7RRloRMMtvn9Tx5wkxm7pyZc+feD+ece46x1lpEREREJGycSBdAREREJN4oYImIiIiEWdgDlrWW8vJy1PMoIiIiiSoQ7g3u3buXzMxM9uzZQ0ZGRrg3Lw2wZ88eMjMzI10MqSPVV+xRndWftZatlbB8p2XFrv/+fL4XvGP8Pz09CVoc+jGH/p2WBKVVULLfUrIf9tX89zmOgZxUyE0ztE+poUtWMrlpkJtuDv1u1xwcYxr3jUu9xdr3K+wBS6KX53mRLoLUg+or9qjOjs7zLZ/soVaQWlFq2V4Z+ntWMvRvZRiX59AjEzKSzf8EqK+GqLqEIGste6qhZD+U7LOh0LUPNu63fF4GH673KdkPVf9TdS2SYFRHw9hch7F5hg6pClvRINa+XwpYIiISdtWe5b1DrVKwotTy/i5L5cFzZOf0UJi6/gSH/q0M/VsZOqeDCXPLkTGGrBTISoF+2bW3XVpaTnZ2NtZadh2Akn2hVq+VuywvlViuec3DAgNawbg8h7G5hlPbGFxHgUuOTQFLRETCorTKMqfE8uJ6n7kbLXtrIGCgd8tQmLqkayhMnZRtyG4WPSHFGEPrZtC6GQxobRjfGX5+Muyssry80TJng8+Dq3zuWA6tUmBMbqh165xOhlZR9D4kuihgiYjIcVu7JxSoXtxgWbrV4lkY2Nrw/050GJNrODHbkOLGZghp3cxwWXfDZd0dPN/y1g7L7A2WOSU+/1jr4RgobGsYm2sY39n5SguZhFRXV7N+/foGd/GVlZWRlZUVplLVn+M4dOjQgRYtWtTp8SbcE42Wl5drkHuUKi0tJTs7O9LFkDpSfcWeRKgzz7e8vcPywvpQsPq4DFJcGJFjGN/ZcF6eQ8e02AgaDamvTftD3YhzSnzmb7Lsq4HRHQ23DnA4q4NmQPrCxo0bufTSS6moqGjwtnzfx3Ei/9lOnDiRW2655ZhlUQuWiIgc1f4ay4JNoUD1n5LQoPTWzeC8PMOdAx1GdTKkJ8VGqAqXjmmGq3sZru7lcMCzPF9suXOFx9D/eAxp73Nrf4fRnUzYx5TFEt/3uf3228nKyuL++++nWbNmDdpeMBgkEIhcbKmpqWH58uU88MADANx6661HfbwCloiIfEX1wdDwxFqfBZssVR70yoIrCxzGdzYUttVg7y+kuIZLuhkmdTX8Z4PlzuU+Y+Z6DGwdatEa39kk5LQPO3fu5L333uPOO++kf//+Dd5epAMWQL9+/QC4//77ufHGG4/aXaiAJSIihxTvtTy82ueRNT7bKuH0doY7Bjqcn+fQIyvxQkJ9OCbUTXp+nmHBJsudK3wmzvfo2xJ+2t/l4q6JFUrLysoA6NSpU4RLEl4DBgwAYMuWLQpYIiJyZJ5vmbvR8pdVPnNKLC2S4JsFDted4NBHA7frzRjDqE6GUZ0clm71uXO5z6WLPH7xLtzS3+Xy7obkGB34Xx++7wPgum6ESxJeSUlJwH/f35FEfrSYiIhExLYKy13LPbrNDHLeyx5bKi0PDXHZfFmAB85wFa7C4Mz2Di+dG+CdCQH6ZRuuWuLRfWaQP3/kURnUknLRori4mLPPPpvMzMywdGeCApaISEKx1vLqZp9LFgbJfSrIr5f7DM8xvD3B5Z0JAa7u5ZCWYAPWm8IpbQzPjgrwwYUBhrQ33PiGT7eZQZ5dd/RWEGkaGRkZ3HHHHTz55JNh26YClohIAig7YLn/Q48+/woybLbHyl2We0512HxZgEeHBhjUxknoK96aSt9swz+GB1gzKcCpbQwXLvC4ZGGQHZVqzWoK9957L9dee+2h22VlZbRu3RqAM888k7S0tLC9lsZgiYjEsXd3WB5c5fHUZ5YaHybmG/58hsPZHRJ7CoFI655peG6Uy8zPLTe87tH7X0H+fLrLpK7xWy8VQcvqsuN/fjBoCQSOHER7ZUFq4Oif3dVXX02PHj245557yMrKYvr06VxwwQWNMn+dApaISBx6c5vPbe/6zNtkyUuHWwc4fLuno4WLo4gxhq93MwzrYLhhmcclr3jM/Nzw4Bku7eKwnlaXwSnPBRu4lSM//92JAU5uffRnZ2VlcdFFF/Hoo4/yox/9iL/85S/MnDmzgWU6PAUsEZE48tZ2n1++G1oLsHcWzBzucmGXxJoeINa0SzU8PTLA05/7fO9ga9YDp7t8o1t8tWb1ygqFoON1rHmwetVxFZ0bb7yR8ePHc8IJJ9CmTZtD0y6EmwKWiEgcKNoRarF6qcRyQhb8c3iouykRJ7iMVZO6hrpub3zD47JFHrM+Nzx6lhtVC2M3RGrAHLOF6WiCQUPgGF2AddGrVy+6du3Ktddeyz333NPg7R2JBrmLiMSwd3b4nDc3yKnPe6zba3lymMsHFwa4pJujcBWD2jQ3PDU8wLMjXV7bajn1hSCrdmsAfLhdc801BINBLrroIgAqKiro1KkTkyZNYtWqVXTq1IlbbrmlQa+hFiwRkRj07g7Lr97z+PcGS89M+Mcwl0sSbKbweDaxi8NJrQwXzAtS+EKQfwxzOb+z2kTCZdGiRXz3u989NGloamoqGzduDOtrKGCJiMSQ5Tstv3zP48X1loIMeOLs0FgdBav40zXDsGx8gG++6nHBPI87Blpu6a/pNBpi8+bNDB8+nOzsbF5++eVGfS0FLBGRGLByl+WX73o8v97SPQMePxisAgpWca1FsuGZUS6/es/n1nd83i+1PDrUPeZ0BHJ4OTk5rF69ukleSwFLRCSKfVhque1dj2eLLd0y4LGhLpd1V7BKJI4x/OoUl34tDVcs9jjzxSDPjw6Ql659IJqpQ1dEJArtrbb8+A2Pk54NsmKXZfpQl9WTAlzRw1G4SlAXdXVYNj5A6QEY9HyQpVuje5kdxwlFjJqamgiXJLyqqqoAjjplBKgFS0Qkqlhrea7YcuMbHqVVcNdAhx/1c0h2FaoETmplKJoQ4KIFHsNnezwzkqgd/J6Tk0NycjIPP/ww11xzzaEB5cfrWPNgNTbP89i4cSN/+tOfSE1NJS8v76iPV8ASEYkS68ot31/mMbvEcl6e4YHTXfJbKFhJbW2aG+aPdbl0kceFCzyeHgEX5EdfyEpPT+e+++7jxz/+McuWLWvw9nzfP9QqFkmnnHIK06ZNIzk5+aiPU8ASEYmwas9y3wc+t7/n06oZPDfK5YLO8TWLt4RXsmt4arjLZa94XLTAY9aI0NQO0aawsJB58+axefNmfL9hXZplZWVkZdVxuvZG4DgOLVu2pFWrVnUKegpYIiIRtGSLz/VLPdbsgR/2dfjlKQ7pSQpWcmxJjuHJ4S6XL/K4eKHHzBHwtSgMWenp6fTo0aPB2yktLW2URZkbiwKWiEgE7Ki03Py2x2OfWAa3Nbw30eXEVgpWUj8BxzBjmIsxoZD1z+GhwfASeQpYIiJNyLeW6WtC4coCDw1xuaqn1gyU4xdwDE+c7eLg8fVXPJ60cHE3haxIU8ASEWkiH5Rarl/q8fo2yzcLDL87zaVtcwUrabiAY3j8bBfHeFy6yMMHvq6QFVEKWCIijWx/jeX293zu+8CneyYsGudydo5OfhJermN4bKiLweOyRR6+hUu7az+LFAUsEZFG9OJ6n+8v89heCb86xeEnJ2pOK2k8rmOYPtTFdTwmv+rRMgXOzVXIigQFLBGRRrBhn+XGZR4vrLeM6WRYNM6la4aClTQ+1zH8bYjLziqPSxZ6vDHe0Cdb+15TU6wVEQmjGt9y7/seJzwdpGiH5ekRLnPGKFxJ03Idw5PDXPJbwPnzguyotJEuUsJRwBIRCZO3drqc/GyQKW/7XNPL4eNJAS7q6mjCUImIFsmGf48OsD8IE+d7HPAUsprSVwLWgQMHuOGGGygoKKBfv35cfvnlAGzfvp0xY8ZQUFBA3759WbJkSZMXVkQkGu2qslyzJMjYxak0D4TWivvDYJeMZAUriazOLQzPj3J5Z6fl2tc8rFXIaipfGYM1depUjDF88sknGGPYunXrofsLCwuZO3cuRUVFTJw4kXXr1jV48UYRkVhlreXxTy0/ecujxoff9a/iR6ek4zoKVhI9BrdzeOQsuHyRxwlZPlP7u5EuUkKoFbD279/PI488wsaNGw81abdv3x6AWbNmsXbtWgAGDRpETk4OixcvZuTIkU1cZBGRyPt4t+X61z0Wb7Fc2s3wf4UuyVU1ClcSlS7r7rC6zHJLkU/PTBOV6xbGm1qf8GeffUZ2djZ33XUXAwcOZMiQISxcuJBdu3ZRU1NzKGwB5Ofns2HDhiNuuLy8vNbPgQMHGu9diIg0kYqg5dYij5OeDbJ5v2X+WJd/DA/QPlXBSqLbr05xuKiL4fJXPZbvVFdhY6vVghUMBlm/fj29e/fmt7/9LcuXL2fUqFF89NFH9d5wbm5urds333wzU6ZMaVhppUF2794d6SJIPai+os+bO12+W9SMLVWGH/es5sae1TRzobQ09HfVWWxJxPr6/YmwtiyVcXN95g+roEPz2Ala0V5fX16IulbAysvLw3EcLrvsMgAGDBhAly5d+OCDDwgEAmzduvVQK1ZxcTF5eXlHfKGSkhIyMjIO3U5JSSElJSVsb0SOTyytRC6qr2jh+ZbfrvS57V2fwW0N889zKchMPuxjVWexJdHqKxuYfa7l1BeCXPl2C5aOd0mJoYlvY6m+anURtm7dmhEjRvDyyy8DsG7dOtatW8cJJ5zApEmTmDZtGgBFRUVs2rSJoUOHHnHDGRkZtX4UrkQkFm2tsJzzksfP3/G5pb/DovNcCjJj54Qk8mU5aYYXRgV4v9Ty0yI/0sWJW1+5inDatGlcddVVTJkyBcdx+Otf/0rHjh25++67mTx5MgUFBSQnJzNjxgxdQSgicW3+Rp/LX/VwgPljXUZ01MBgiQ+ntDH8ZpDDTW/5nJtrGKl9O+yMDfOkGOXl5WRmZrJnz55aXYQSeaWlpTHVvJroVF+RE/Qtv3jX57crfEZ1NDx+tku7OgxiV53FlkSvL9+GWmdX7ba8f2GAVs2iu2U21upLkVVE5H9s2GcZ+h+Pe1b63DXI4aVz6xauRGKNYwyPDXWp8uAaTUIadgpYIiIHvbjep/+zQTbutyw532VqfxdHy9xIHOuYZnh4iMtzxZZH1yhghZMClogkvAOe5QfLPC6Y5zG0vWH5xACnt9PhURLD17o4XNXT8IM3PD7do5AVLjqCiEhCW7vHcvqLQaZ97HP/YIdnR7lkR/lYFJFw+8Nglw6pcNkijxpfISscFLBEJGE9tdbn5OeClFfDGxcE+H5f99AyYSKJJD3J8I9hLu/ttNz+nqZuCAcFLBFJOBVByzVLgly6yOP8PMN7EwOc3FrBShLbqW0dfnmyw10rfJZuVchqKAUsEUkoH5VaTn0+yD/WWh45y2XGMJcWyQpXIgC39Hc4va3h8kUee6rVVdgQClgikhCstfxttc+g54MAFE0I8O2ejroERf6H6xieGOay+wD8+A0v0sWJaQpYIhL3yqstly7yuOY1j8sLDG9PCNAnW8FK5HDyWxh+e6rDo59Ylm1TV+HxUsASkbj27g7Lyc8Fmb3B8tRwl4eGBEgNKFyJHM21vRwGtjZ873WPoK4qPC4KWCISl6y13P+hx+AXg2Qlhwayf72bDnkideE6hgfPdFi5C/6ySq1Yx0NHGxGJO6VVlonzPX7whs/3eju8Pt6le6ZarUTqY1Abh2t6OfzsHZ+tFWrFqi8FLBGJK69vDS13s2Sr5YXRLr8f7JLiKlyJHI+7BjkkOXDzWxrwXl8KWCISF3xr+c0Kj6H/8chLN6z4WoDxnXWIE2mIVs0Md5/q8sRay5It6iqsDx19RCTmbauwjHnJ49YinyknObx6nkteulqtRMLhWz0NhW1DA961jE7dKWCJSExbsMnnpGeDvF9qmTfW5c5BLgFH4UokXBxjePAMl1Vl8MCHasWqKwUsEYlJ1lrueM9j9ByPftmhLsGRHXVIE2kMA1obvnuCw23v+Wzar1asutDRSERiTmXQctkij5+/63PbyQ4vn+vSPlWtViKN6dcDHVID8BMNeK8TBSwRiSlbKyzDZns8X2yZNcLltlNcHC13I9LoslIMvzvV5Z+fWRZuUlfhsShgiUjMWLErtFBzyT7LkvNdJnXVIUykKU0uMJzZznDDMg14PxYdnUQkJrxQ7HPmi0HaNIe3JwQY2EaHL5GmZozhT2e4rCmDxz5RwDoaHaFEJKpZa7l7hcfE+R5jcg1LzgvQMU1dgiKRclIrwyXdDLe/51EVVMg6EgUsEYlaBzzLtxZ7TC3yuXWAw6wRLmlJClcikfbLk102V8DDqzUW60gUsEQkKu2otIyY7fHPzy0zhrn8eqAGs4tEi55Zhm8WGO5c4VOhVqzDUsASkajzYWloMPun5ZZF41wu665DlUi0+cUAl11V8OeP1Ip1ODpqiUhUmbPB5/QXg2Qkw9sXBBjcTocpkWjUJcNwdS+Hu1f6lFerFevLdOQSkahgreX3H3icP8/j7A6GpecH6NxCXYIi0ezW/g77gvBHLaHzFQpYIhJx1Z7lO0s9fvymz039HJ4b5dIiWeFKJNp1Sjdcf4LDve/7lFapFet/KWCJSETtqrKc85LHY59YHj3L5Z7TXFwt1iwSM6ae5BC08H8fqBXrfylgiUjErC6zFL4Q5INSy8KxLt/qqUOSSKxpl2q4sY/DHz/02V6pVqwv6GgmIhExf6NP4QtBkp3QzOxDOuhwJBKr/t+JDq6Bu1eqFesLOqKJSJN7cJXHuXM9Brc1LLsgQNcMdQmKxLLsZoYf93N4cJXPpv1qxQIFLBFpQkHfcsPrHt973eeGPg7/PsclU4PZReLCD/s5pAbgrhVqxQIFLBFpImUHLOPmevz1Y59pZzr8YbBLQIPZReJGZrLh5hMdHl7tU7xXrVgKWCLS6NbusQx+MUjRTsvL57p85wQ30kUSkUZwQx+HlinwG7ViKWCJSON6dbPPaS8E8S28OT7A8I467IjEq7Qkww/6ODz+qc/OBJ8XS0c6EWk0j6z2GTXHY0Arw5sXBOiRpS5BkXh37QmhaPHXjxO7FUsBS0TCzvMtN73pcfVrHlf3cnjpXJeWKQpXIomgdTPDNwsc/rzKp9pL3FYsBSwRCauqoOXihR5/+NDngdMdHjzDIUmD2UUSyg/7OmypgJmfK2CJiDTY3mrLuJc95pRYnh/lckMfF2MUrkQSzQktDWM6GX7/gYe1iRmyFLBEJCx2VlmGz/Z4Z0foSsHzO+vwIpLIftjXYfkueG2rApaIyHEp2Wc588UgG/ZbXj0vwFla9kYk4Y3uZOidBb9P0EWgdRQUkQZZXWY548UgVR4sPT/AgNbqEhQRMMbww34uL6y3fFaeeK1YClgictyKdvic+WKQjGR4fXyAgkyFKxH5r8u7G7JT4P4PE68VSwFLRI7Lwk0+w2d7FGQalpwXoGOawpWI1NY8YLjuBIdHP/HZU51YrVgKWCJSb8+u8xk71+OMdoYFY12ymylcicjhfa+PwwEvNPFwIlHAEpF6+dtqn0kLPSbmG14c7ZKWpHAlIkfWIdXw9a6G+z/yCfqJ04qlgCUidXbPSo9rXvP4Ti+HfwxzSXYVrkTk2H7Yz2X9PnhhvQKWiMgh1lpufstjyts+Px/g8OczHFzNzi4idXRya8NZ7U1CTdnwlYCVn59Pz5496d+/P/3792fmzJkAbN++nTFjxlBQUEDfvn1ZsmRJkxdWRJpe0LdcvcTjd+/7/GGww+0DNTu7iNTfj/o5vL7NUrQjMUJW4HB3zpw5k/79+9e6b+rUqRQWFjJ37lyKioqYOHEi69atIykpqUkKKiJNrypo+cYrHv/eYHnibJfLC9ToLSLH5/w8Q9cWoYlHnxwe/8eSOr/DWbNmcd111wEwaNAgcnJyWLx4caMVTEQiq7zaMnaux9yNoXUFFa5EpCFcx3BjX4enP7dsqYj/sViHPWJOnjyZfv36cdVVV7Fjxw527dpFTU0N7du3P/SY/Px8NmzYcMQNl5eX1/o5cOBA+EsvIo1ie6Vl2Owg7+60zDvX5TytKygiYXBFgUPAgSc+jf9uwq90ES5ZsoS8vDxqamr42c9+xhVXXMETTzxR7w3n5ubWun3zzTczZcqU4y+pNNju3bsjXQSph0jVV8l+w4VLU9lbAy+eVUmfFJ/S0ogUJeboOxZbVF+RcV5OMx5e5XBVpz3UZzhntNdXdnZ2rdtfCVh5eXkAJCUl8cMf/pAePXrQqlUrAoEAW7duPdSKVVxcfOixh1NSUkJGRsah2ykpKaSkpITlTcjx+/IOINGtqetr1W7LuNeCJDuwbEKAbhn6ztaXvmOxRfXV9K7r5zNyjseaYBant6tf63gs1Vetd7Z//37KysoO3X7qqacYMGAAAJMmTWLatGkAFBUVsWnTJoYOHXrEDWdkZNT6UbgSiW5vb/cZ8u8gLZNDizZ3y9CVgiISfsNyDJ3TYfqa+O4mrNWCtW3bNi688EI8z8NaS9euXXn88ccBuPvuu5k8eTIFBQUkJyczY8YMXUEoEicWbPKZMM/jpFaG/5zj0jJF4UpEGodjDFf2cPi/D3z+MNjG7WoQtQJW165dWb58+WEf2K5dO+bNm9ckhRKRpvOvz30uXeQxIsfwr5Fa+kZEGt+VPRx+9Z7Pv9ZZrugRn8ccXRokksAe+tjn4oUeF3UxvKB1BUWkieS3MIzIMUz/JH67CRWwRBKQtZbfrPD4zlKP7/Z2mKF1BUWkiX2rp8PiLZa1e+JzTiwFLJEE41vLT97y+WmRz20nOzxwuoOjpW9EpIl9Ld+QmQyPxWkrlgKWSAIJ+pZvL/a47wOf+wc7/PIUrSsoIpHRPGD4RjeHxz718fz4a8VSwBJJEJVBy4ULPP6x1jJjmMv3+7qRLpKIJLhv9TBs2g8LNilgiUgM2lNtOXeux/yNlhdGu1zWXV99EYm8QW0MfVrCo3HYTaijrEic215pGfafICt3WeaPdRmbp6+9iEQHYwzf7uHwfLGltCq+WrF0pBWJY5v2W4b8O8iWClh8XoAz2usrLyLR5fICB9/Ck5/FVyuWjrYicWrT/lDLVWUQlo4PcGIrDWYXkejTtrnhvDzDo3G2dI4Clkgc2vxFuPJg0XlaV1BEotu3ejos3wUflMZPN6EClkic2bzfMmx2KFy9qnAlIjFgTKfQnFhPfx4/rVgKWCJxZEuFZfjsIPuDsGicwpWIxIZk1zChs+HpdT7WxkcrlgKWSJzYejBc7QvCq+MCdM9UuBKR2HFxV4fVZfDh7kiXJDwUsETiwNaKULdgeXWo5UrhSkRizciOhqxkmBUn3YQKWCIxbtvBlqs91aExVwUKVyISg5Jdw4R8w9Ofx0c3oQKWSAzbdrDlqqw61C2ocCUisezirg5r9sAHpZEuScMpYInEqC9arsoOdgv2yFK4EpHYNiInfroJFbBEYtD2ylC4Kj0QClc9Fa5EJA4ku4aJ+fFxNaEClkiMqRWuzlO4EpH4cnFXh0/2wPsx3k2ogCUSQ3ZUWkbMDrKzKhSueilciUicGdHR0DIl9rsJFbBEYsSOgy1XO6pC3YIKVyISj5Icw8TOsX81oQKWSAzYUWkZMSfI9ip4ZVyAE1oqXIlI/Lq4q8On5bAyhrsJFbBEotzOqlC42lYZarnqrXAlInFueEdDdox3EypgiUSxXVWhMVdbK+CVsQpXIpIYkpyDVxPGcDehApZIlCo9ACNmB9lSEWq56pOtcCUiiePirg5ry2HFrkiX5PgoYIlEoV1Vlq+9lsrmitCYK4UrEUk0w3JC3YRPr4vNbkIFLJEoU1plGTUnyOZKwyvjAvRVuBKRBJTkGL6Wb5gVo92EClgiUaS0yjJyTpCS/fD8WZUKVyKS0CZ1dfisPDYnHVXAEokSpVWWUS8F2bAPFo4N0DszNpvFRUTCZWgHQ1oAZm+IveOhApZIFNh9IBSu1u8Njbk6sZVarkREUlzDqI6G2SXqIhSRetp9wDJqjsf6vbBQ4UpEpJZxeQ5vbreUHoh0SepHAUskgsoOWEbP8Vi317JwXICTFK5ERGoZm2vwLbyyLRDpotSLApZIhJQdbLn6XOFKROSIctIMA1rB/K0KWCJyDGUHLKNf8vhsr2XB2AD9Fa5ERI5oXJ7Dwm0BPD92xmIpYIk0sT3VlnNe8lhbHgpXA1orXImIHM24XMPuasOb2xWwROQw9lSHxlx9sicUrk5WuBIROaZBbQytkv2YuppQAUukiZQfbLlSuBIRqR/XMYxo78XUfFgKWCJN4ItwtabMMn+syyltFK5EROpjdPsg75dCyb7YaMVSwBJpZOXVljEveXx8MFwNbKOvnYhIfQ1vF8Q1MKckNlqxdKQXaUR7qy3nzvVYpXAlItIgmclwRjvD7A1qwRJJaPtqLGPmenxYapl3rssghSsRkQYZl2dYuNlSFYz+kKUjvkgjqApaJszz+KA01HJ1alt91UREGmpcrkNFEF7dooAlknCCvuUbr3i8vs3y73MUrkREwqV3S+icTkx0E+rILxJGvrVc85rHfzZYnh7hMrSDvmIiIuFijGFsrsPsEh9roztk6egvEibWWm560+fvn1j+frbLeZ319RIRCbdxeYZ1e2F1WaRLcnQ6A4iEyR3Lff7woc+fznC4tLu+WiIijWFYjqGZC7OjfLoGnQVEwuCBDz1+8a7PHQMdvtvbjXRxRETiVmrAMDwn+qdrUMASaaAZn/rc+IbPTf0cftpfXykRkcY2Ls+wdKtlT3X0hiydDUQa4MX1Plcu9vh2D8PvTnMwRkvgiIg0tjGdHIIWlkTxdA2HDVjTp0/HGMPzzz8PwPbt2xnFvHZLAAAgAElEQVQzZgwFBQX07duXJUuWNGkhRaLRq5t9Ll7oMSHf8NAQV+FKRKSJdGkBeemwaHMMBazi4mIefvhhCgsLD903depUCgsL+fTTT5k+fTqXXnopNTU1TVpQkWjyzg6f8+d5nNXe8I9hLq6jcCUi0lSMMQzrYHhlc/QOdK8VsHzf5+qrr+aBBx4gJSXl0P2zZs3iuuuuA2DQoEHk5OSwePHipi2pSJT4eHdo8ea+LQ3PjnJJcRWuRESa2rAch5WlsKsqOluxagWs++67jzPOOINTTjnl0H27du2ipqaG9u3bH7ovPz+fDRs2HHXD5eXltX4OHDgQ5qKLNL3ivZZRLwXpkAqzz3FJT1K4EhGJhGE5oePv4igdhxX44h8ffvghzzzzTNjGV+Xm5ta6ffPNNzNlypSwbFuOz+7duyNdhJi2rcpw3qupJAMzB1dAhaW0ovFeT/UVe1RnsUX1FVu+XF/pQH5aGi+tq+bszMg34mRnZ9e6fShgvfbaaxQXF1NQUADA1q1bufbaa/nVr35FIBBg69ath1qxiouLycvLO+oLlZSUkJGRceh2SkpKrW5HiYwv7wBSN2UHLF9fFKTSwuvnB+iS0TT7suor9qjOYovqK7Z8ub5GdgryxnaH7Oy0CJXoyA51EV5//fVs2bKF4uJiiouLKSws5KGHHuL6669n0qRJTJs2DYCioiI2bdrE0KFDj7rhjIyMWj8KVxKr9tdYxr3ssXE/zD83QJcMdQuKiESDYTkOH+2GbRXR100YOPZD4O6772by5MkUFBSQnJzMjBkzSEpKauyyiURctWe5cIHHyl2WV8a59MlWuBIRiRZfjMN6dYvlkm7RdXw+YsB69dVXD/27Xbt2zJs3rynKIxI1PN9y+SKPRZstc8a4nNpW8/KKiESTDqmGnpmh+bAu6Rbp0tSmM4bIYVhruf51j2eLLTNHuIzoqK+KiEg0GpbjsGhL9M2HpbOGyGFMfdvn4dWWR85ymZCvr4mISLQa1sHwyR7YvD+6xmHpzCHyJb9d4XHP+z5/GOxwRQ99RUREotnZB8dhLYqy+bB09hD5H3/92OOWIp/bTnb4QV830sUREZFjaNvc0LclLIqyZXMUsEQO+udnPtcv9fl+H4fbTtZXQ0QkVgzLcXglyhZ+1llEBJizwWfyIo/Luxv+MNjBmOi63FdERI5sWAfDur2wfm/0hCwFLEl4r23xuWiBx9g8wyNDXRyFKxGRmDK0g8EQXeOwFLAkoS3faTnvZY/CtoaZw12SHIUrEZFYk93McFKr6BqHpYAlCeuTMss5LwXpmWV4YbRLs4DClYhIrBrWwWHRZou10dGKpYAlCalkn2XknCBtmsGcMS4tkhWuRERi2fAcQ8l++HxvpEsSooAlCWdHpWXUnCCOgXljA7RupnAlIhLrhnQwOIaouZpQAUsSyp5qy5i5QcqqYcHYAB3TFK5EROJBZrLhlNYmasZhKWBJwqgMWsa/7PF5Ocw7N0D3TIUrEZF4MqyDiZpxWApYkhCCvuXihR7v7LTMHuNyYiuFKxGReDMsx7C1Ej7ZE+mSKGBJArDWcv1Sj7kllmdHupzeTru9iEg8GtwuNB/Wm9vVgiXS6H693Odvayx/O8vlnFzt8iIi8Soz2XBClgKWSKN7ZLXPbe/63DnQ4Yoe2t1FROJdYVvDG9siP9BdZxyJW3M2+Hxnqcd1Jzjc0l+7uohIIhjczuGD3bCvJrKtWDrrSFx6Z4fPpIUe4/IMfzpdizeLiCSKwrYG38I7OxSwRMLq83LLuJc9Tsw2PDXcxdX6giIiCeOELGiRFPlxWApYEld2VFrGvBQkMwn+fY5LqtYXFBFJKK5jOK2t4Q0FLJHwqAhazp/nsacG5p6rJXBERBJVYVvDm9sjO+GoApbEhaBv+fpCjw9LLXPOCdA1Q+FKRCRRFbY1bK+E4ggu/KyAJTHPWssNr/vMKbE8PdLllDYKVyIiiey0tqHzQCS7CRWwJObdtcLnr6t9Hh7icq4mEhURSXitmxkKMiI70F1nI4lpj33i87N3fH51isO3emp3FhGRkC/GYUWKzkgSs14u8blmicc1vQw/H6BdWURE/quwnWH5TktlMDIhS2cliUnv7bRcuMDjnE6GB89wNZGoiIjUMritQ9CGzheRoIAlMWdduWXs3CB9WhpmjnAJaCJRERH5kn7Z0NyN3DgsBSyJKbuqLOfODZJ+cCLRtCSFKxER+aqAYxjUJnLjsBSwJGZUBi3nv+xRegDmjgnQtrnClYiIHFkkB7orYElM8HzLpa94rCy1/Occl+6ZClciInJ0g9sZNu6HjfuaPmQpYEnUs9Zy4xs+/95gmTXC5dS22m1FROTYvphwNBKtWDpTSdS7e6XPg6t8pp3pMi5Pu6yIiNRNh1RD53QFLJGveOJTn1uKfH5xssPVvbS7iohI/URqHJbOWBK15m/0+fZij2/3MPzyZO2qIiJSf4PbGd7Zaan2mjZk6awlUWnFrtBEoiM7GqYN0USiIiJyfArbGg54sLJUAUsS3Pq9lnNfCtIj0/D0SJckTSQqIiLHqX8rQ7IDb25TwJIEVlplGTM3SPMAzD7HJV0TiYqISAOkuIZTWhveaOJxWApYEjWqgpYL5nnsqAxNJNouVeFKREQaLhID3RWwJCp4vuXyVz3e3RmaSLRHlsKViIiER2Fbw7q9sK2i6UKWApZEnLWWH73p81yx5Z8jXArbabcUEZHwGdQm9J/25bsUsCSB3Pu+zwMf+fz5dIfxnbVLiohIeOW3gIwkBSxJIE+t9bn5bZ+f9ne4rrcb6eKIiEgcMsbQv5VhhQKWJILXt/pcudhjcnfDHQO1K4qISONRwJKE8Fm5ZcJ8j8HtDH87SxOJiohI4xrQ2vDpHthX0zQhSwFLmtzuA5bzXg7SMhmeGemS7CpciYhI4+rfymCBD5poRncFLGlSNb7logUe2yth9pgArZopXImISOPrnQVJTtMNdA80yauIEJqO4fqlHq9ttcwf61KQqXAlIiJNI9k19M6iycZhfaUFa/To0Zx44on079+fIUOGsHz5cgC2b9/OmDFjKCgooG/fvixZsqRJCijx4973fR5ZY3l4iMvQDmo8FRGRphUa6N40r/WVFqxZs2aRlZUFwHPPPceVV17JypUrmTp1KoWFhcydO5eioiImTpzIunXrSEpKapqSSkx7dp3PlLd9bu3vcEUPhSsREWl6A1obZn7uE/QtAadxe1G+cqb7IlwB7Nmz59DVXbNmzeK6664DYNCgQeTk5LB48eJGLZzEh3d2+Fy+yGNSV8Ptmo5BREQipH8rQ5UHn+xp/Nc67Bisb37zmyxatAiAOXPmsGvXLmpqamjfvv2hx+Tn57Nhw4Yjbri8vLzW7ZSUFFJSUsJRZokhJfss57/scWIrw2NDXRxNxyAiIhFyUvZ/l8zp3bJxz0eHDViPP/44AH//+9+ZMmUKTzzxRL03nJubW+v2zTffzJQpU46jiBIuu3fvbtLX21sD4xankmQMjw2qoLLcUtmkJYhtTV1f0nCqs9ii+oot4aqvvNQ03txYzbnZB8KyvS9kZ2fXun3UqwivuOKKQ92CgUCArVu3HmrFKi4uJi8v74jPLSkpISMj49BttWBFhy/vAI0l6Fsmz/MoqbAsGx+gV7bq/ng0VX1J+KjOYovqK7aEo75ObhNkdYVLdnZaGEp0ZLUGxJSVlbF58+ZDt59//nlatWpFdnY2kyZNYtq0aQAUFRWxadMmhg4desQNZ2Rk1PpRuEosN73p8/JGy6wRLn2y1S0oIiLR4Yslc6xt3OkaarVg7dmzh0mTJlFZWYnjOLRp04b//Oc/GGO4++67mTx5MgUFBSQnJzNjxgxdQSiH9aePPO7/yOfBMxzOydWgdhERiR4DWht2VsHmCujYiI1YtQJW586defvttw/7wHbt2jFv3rzGK4nEhTkbfH7whs+P+jpc39uNdHFERERq6d/q4ED3nZaOaY3Xw6LmBQmb93dZLnnFY1yu4XenadcSEZHok5sGLVMaf0Z3nQUlLLZWhBZw7p4BTw53cRt5AjcREZHjYYyhf7ZhRSMv+qyAJQ1WEbSMn+fhWfj36ADpSQpXIiISvb4Y6N6YFLCkQXxr+earHh/ttvz7nACd0hWuREQkug1obfisHMqrGy9kKWBJg9xa5PPsOsuTw1xObq1wJSIi0e+Lge4rG7EVSwFLjtuja3x+u9Lnd6c5XJCvXUlERGJDryxIdhp3oLvOinJcFm32+c5rHtf2cvhxP+1GIiISO5IcQ99sBSyJMmvKLF+b73F2juFPZzgYLeAsIiIxprGvJFTAknrZWWUZ93KQDqnw9AiXJE3HICIiMWhAa8OHpVDjN07IUsCSOjvgWSbO8yivhtnnBMhKUbgSEZHY1L+VodqHj3c3zvYVsKROrLVcvcSjaKfl+dEuXTIUrkREJHadmB06jzXWOCwFLKmTO5b7zFhrmX6Wy+nttNuIiEhsy0g2dMtQwJIIemqtzy/e9bn9FIdvdNcuIyIi8aExZ3TX2VKOatk2n28t8bi8u+FnA7S7iIhI/BjQKnQlobXhD1k6Y8oRrSu3TJjnMai14W9nuZqOQURE4kr/VobdB2DDvvBvWwFLDqvsQGg6hoxkeG60S4qrcCUiIvGl38GB7h/uVguWNIEa33LxQo8tFaHpGFo3U7gSEZH4k5sG6UmwqhECViDsW5SYZq3l+6/7LNpsmTfWpWeWwpWIiMQnYwy9swwfqQVLGtvvP/D562qfh4a4DMvR7iEiIvGtT0tYVRb+7eoMKoe8UOzzk7d8pp7k8K2e2jVERCT+9W5pWLXb4of5SkKdRQWA93dZLlvk8bUuhjsHabcQEZHE0KelYX8w/FcS6kwq7Ki0jJ8XpCAT/j7UxdF0DCIikiB6HxxrHO6B7gpYCa7as1y0wKMiCC+MDpCWpHAlIiKJIy89dCVhuAe66yrCBGat5fvLfN7Yblk0ziUvXeFKREQSyxdXEq4qU8CSMPnLxz4PrfZ55CyXM9qrMVNERBJT75bw0e7wblNn1QT1yiafG5f5/KCvw7d1xaCIiCSwPo1wJaHOrAnos3LLpIUew3MM956mXUBERBJb76zQlYQlYbySUGfXBFNebRn/cpDsFJg5wiXgaNyViIgktj4tQ+fCcA50V8BKIJ6FyxZ5bNwP/z4nQMsUhSsREZHcdEgLENaB7hrknkDu+iiZ2Rsss8e49NIagyIiIgA4xtC7ZXjXJFTAShBPrvX5w5oUfneaw7m5argUERH5X31awqowXkmoM20CKNrhc9USj0vyaripn6pcRETky76YC8uG6UpCnW3j3JYKy4R5Hie1Mtx3chVGy+CIiIh8RZ+Whn014VuTUAErjlUFQ+HKGHhulEszN9IlEhERiU4nHBybvDpMA90VsOKUtZZrX/N4v9Ty/CiXDqlquRIRETmSvHRIcWHNnvAELA1yj1P/94HPE2stTw5zGdhGOVpERORoXMdQkAFr9oRnezrzxqE5G3xufsvnp/0dvtFdVSwiIlIXPbMMa9RFKIfz8W7LN17xOC/P8OuBql4REZG66plpwtZFqDNwHNl9wDJ+XpDcdPjHMBdHVwyKiIjUWc9Mw8b9sL+m4SFLAStOBH3LxQs9Sg/Ai6MDtEhWuBIREamPnlmh35+EYRyWAlac+MlbPq9utvxrpEvXDIUrERGR+uqZGTp/hqObUFcRxoFHVvv88UOfB89wGJajzCwiInI8slIMbZsTloHuOhvHuKVbfa5/3eO6Exyu762ZREVERBoiXAPdFbBi2IZ9lq/N9zi9neH+01WVIiIiDdUzMzxdhDorx6j9NZbxLwdJC8C/RrokORp3JSIi0lA9swyf7KHBiz4rYMUg31quWOyxthxePCdA62YKVyIiIuHQMzO06PPmioZtRwErBt2x3OeZdZYZw1z6ZStciYiIhMuhKwkbONBdASvGPLPO57Z3fe4Y6DAhX9UnIiISTl0yIGAaPg5LZ+gYsnKX5ZuvelzS1fDT/qo6ERGRcEtyDN3CsOhzrbN0VVUVEyZMoEePHpx00kmMGjWKtWvXArB9+3bGjBlDQUEBffv2ZcmSJQ17ZamX7ZWhZXB6ZcGjQ12MlsERERFpFOFY9PkrzSDXXnsta9asYeXKlVxwwQVcffXVAEydOpXCwkI+/fRTpk+fzqWXXkpNTU2DXlzqptqzXLTA44AHz48KkBpQuBIREWks4ZgLq1bAatasGWPHjj3UOlJYWEhxcTEAs2bN4rrrrgNg0KBB5OTksHjx4ga9uBybtZbvve7x1nbLc6NcctMVrkRERBpTz0xD8V6oDB5/yDrqUjl//OMfueCCC9i1axc1NTW0b9/+0N/y8/PZsGHDEZ9bXl5e63ZKSgopKSnHXdBE9eAqn7+tsTw21GVwO427EhERaWw9s8ACa8uhX/bxbeOIAeuuu+5i7dq1LFy4kMrKynpvODc3t9btm2++mSlTptS/hAnsjZ0uP3yjOd/pXsP5rQ9QWtqw7e3evTs8BZMmofqKPaqz2KL6ii1NWV+tfAOks2LTXjoSrNNzsrNrJ7HDBqx7772XZ599lgULFpCamkpqaiqBQICtW7ceasUqLi4mLy/viC9UUlJCRkbGodtqwaqfTfst3347yJntDQ8MTSXJSQvLdr+8A0h0U33FHtVZbFF9xZamqq+W1pIWCLLNppGdfXzr/H6lz+m+++7jqaeeYv78+WRlZR26f9KkSUybNg2AoqIiNm3axNChQ4+44YyMjFo/Cld1d8CzXLjAI8WBmSO0DI6IiEhTMsbQPQM+Kz/2Y4+kVgvWxo0buemmm+jatSvDhg0DQi1Pb731FnfffTeTJ0+moKCA5ORkZsyYQVJSUoPegBze95d5rNhlWXq+S9vmClciIiJNrVuGYW15mAa5d+rU6YiLG7Zr14558+Yd9wtJ3Tz0sc/Dqy3Th7oMbKNB7SIiIpHQPcPw9Dr/uJ+vM3gUeWObzw3LPL7X2+HKHqoaERGRSOmeaVi/LzQX5fHQWTxKbKkIjbs6rY3hvkJVi4iISCR1awG+heK9x/d8ncmjQLVnmbTAwwBPj3RJdjXuSkREJJK6Z4bOxZ/tVQtWzPrRmz5v77A8M9KlfarClYiISKR1SoMUF9Ye55I5R53JXRrf9DU+D67yeWiIS6FmahcREYkKjjF0aQGfqYsw9hTt8Ln+dY9rezlc00tVISIiEk26Z5jjbsHSWT1CtldavjbfY0Arw/2nqxpERESiTfcGzIWlM3sE1PiWixd61Pjwr5EuKRrULiIiEnW6ZcC6veD59Q9ZClgR8P/e8nl9q+VfI106pilciYiIRKPuGYZqHzbur/9zFbCa2IxPff74oc8fBjuc2V4fv4iISLTqlnFwqobj6CbUGb4JLd9pueY1jyt7GL7bWx+9iIhINOucDq6Btcex6LPO8k1kZ5Vl4vwgfVsa/nKGizHqGhQREYlmya6hczrHNdBdAasJBH3L1xd6VATh2VEuzQIKVyIiIrGgW4ZRF2G0+mmRz6tbLLNGuOSmK1yJiIjEiuOdqkEBq5HN/Mznd+/73Huaw9k5+rhFRERiSfcM+KwcrK1fyNIZvxG9v8vy7SUel3U3/KCvPmoREZFY0y3DsD8I2yrr9zyd9RtJ6cFB7T0y4aEhGtQuIiISi453qgYFrEbg+ZbLFnmUVcNzowKkalC7iIhITMpvEfpdvK9+zwuEvyjyi3d95m2yzB3jkt9C4UpERCRWpScZWjeD4r31a8FSwAqzZ9b53LXC555THUZ1UgOhiIhIrMtPN6yrZ8BSAgijVbstVy72uLir4Scn6qMVERGJB11aQPHe+j1HKSBM9lRbJswLkp8Oj5ylQe0iIiLxIr+FoXifugibnG8tly/y2FEFRRMCpCcpXImIiMSL/BawYV/oIjbXqds5Xi1YYXD7ez6zN1ieHO7SPVPhSkREJJ50aWGo8WFzRd2fo4DVQC+u9/nVez6/Huhwbq4+ThERkXiTf3CZu/pcSahE0ABryiyTF3lMzDfc0l8fpYiISDzqfHAurHX1GOiuVHCcyqstE+YH6ZgGfx/q4mhQu4iISFxKDRjaNqdeA901yP04+NZyxasem/fD2xMCtEhWuBIREYlnXVqYenURKmAdh9+s8Hl+veWF0S49sxSuRERE4l1+ev3mwlIXYT29VOLz83d8bjvZYXxnfXwiIiKJIL9F/WZzV0Koh7V7LJe+4jEuz/CLk/XRiYiIJIouLaBkPwT9uoUspYQ62ldjmTg/SJtmMGOYBrWLiIgkkvx0g2dh0/66PV4Bqw6stVy1xKN4Hzw/OkCmBrWLiIgklPwWoXN/XbsJNci9Du5932fW55ZnRrr0bqlwJSIikmg6p4d+F++r2+PVgnUMizb7TC3yuaW/w9e66OMSERFJRM0Chg6pdZ/NXYnhKDbvt3z9FY9hHQy/PkUflYiISCLLT6/7lYRKDUcQ9EPhKmDgyeFunVfPFhERkfiU36Luc2EpYB3BrUU+y7ZZZo1wadtc4UpERCTRdWlh6rxcjgLWYbxQ7HPP+z73nOpwRnt9RCIiIhK6knDjfqipw1xYSg9f8nm55YrFHhPzDT/qp49HREREQvLTwbdQUocrCZUg/kdV0HLRgiCtm8H0oS5Gk4mKiIjIQV/MhVWXKwk1D9b/+MEbPh+XwRsXaDJRERERqa1TWuh3SR1mc1fAOujxT3weWu3ztyEu/VspXImIiEhtzQOGNs1gQx0GuquLEPig1HLdUo8rexi+3VPhSkRERA4vL91Qsl8B65j2VofGXXXPhD+foXFXIiIicmR56bBBg9yPzlrL1a95bKmAf40IkBpQuBIREZEjy0s3deoiTOgxWH/6KLSI89MjXHpkKVyJiIjI0eWlhVqwrLVH7fVK2BasN7f53PSWzw/7OlzUNWE/BhEREamH3HTD/iCUVR/9cQmZLHZWWS5e6DGwteHuUxPyIxAREZHjkJce+n2scVi10sWNN95Ifn4+xhhWrFhx6P7t27czZswYCgoK6Nu3L0uWLAl7gZuKby2XL/Ko9GDmCJdkV12DIiIiUjd56aHccKxxWLUC1kUXXcTSpUvp3LlzrQdNnTqVwsJCPv30U6ZPn86ll15KTU1NmIvcNO5c7jNvo+Ufw1xy0xWuREREpO7aNYck59gBq9Yg97POOuuwD5o1axZr164FYNCgQeTk5LB48WJGjhwZpuI2jQWbfG571+e2kx1Gd1LXoIiIiNSPYwy5acfuIjzmVYS7du2ipqaG9u3bH7ovPz+fDRs2HPV55eXltW6npKSQkpJyrJdrNBv3Wb7xiseojoafDVC4EhERkeOTW4fJRhttmobc3Nxat2+++WamTJnSWC93VDU+XLgklWRjeGBABXvKjj1/RTzavXt3pIsg9aD6ij2qs9ii+oot0VRf7ZKa8XmZobT0v41J2dnZtR5zzIDVqlUrAoEAW7duPdSKVVxcTF5e3lGfV1JSQkZGxqHbkWzBuulNj/dKfZac79KjXcuIlCFafHkHkOim+oo9qrPYovqKLdFSXwXZHm/s8o9anjr1lU2aNIlp06YBUFRUxKZNmxg6dOhRn5ORkVHrJ1Lh6tl1Pvd94HNvocPgduoaFBERkYbJSzdsqoCgf+QesVqJ4zvf+Q6dOnVi48aNnHPOOXTv3h2Au+++m2XLllFQUMCVV17JjBkzSEpKatzSh8GneyzfWuxxURfDjX0UrkRERKThctPBt7C14siPqdVF+Ne//vWwD2rXrh3z5s0La+EaW2UwtIhzu+bwyFlaxFlERETCo1NaKFNs3G/pdIQpn+J2LcIbXvf4dA+8NSFARrLClYiIiIRHx9TQ7437j/yYuAxY09f4PPqJ5bGhLv2yFa5EREQkfFqmQHM31IJ1JHE3MGnlLst3X/e4uqfhih5x9/ZEREQkwowxdEo7egtWXCWQPdWhcVe9suD+091IF0dERETiVKc0kxgtWNZarlrisb0S/jUyQPOAugZFRESkcXRKg02J0IL1xw99nlkXGnfVLUPhSkRERBpPp/QEaMFats3n/73lc1M/h4ld4uItiYiISBTrmAqbKsC3hw9ZMZ9GdlRaLl7ocVpbw29Ojfm3IyIiIjGgU5qhxocdlYf/e0wnEs+3XLbIo9qDmSNckhx1DYqIiEjj++9ko4f/e0wHrF8v91mwyfLUcJeOaQpXIiIi0jQ6pYV+H2kcVswGrJdLfG5/z+f2UxxGdIzZtyEiIiIxqE1zSHLiLGCV7At1DY7JNfx0QEy+BREREYlhjjF0TI2jLsJqLzSoPTUAT5zt4mgRZxEREYmAjmmGTUdowYq5tQhvftvn3Z2W1853adVM4UpEREQi42jL5cRUC9bTn/v88UOf+wodTmsbU0UXERGRONMpzVAS62Ow1pRZvr3E45Kuhu/1jplii4iISJzqmAabK0LL9X1ZTCSVimBoEeeOqfDwEBejcVciIiISYTmphooglNd89W9RH7CstVy/1OPzvfDMyAAtkhWuREREJPJyUkO/Nx9mHFbUB6xH1lge/9Qy7UyXPtkKVyIiIhIdcg5Ocr65Isa6CJfvtNywzOM7vRwmF0R1UUVERCTBdPiiBaviq3+L2tRSdiA07qpPS/jD4KgtpoiIiCSo1IAhKxk2H+ZKwqicB8tay5WLPUoPwIKxAZoF1DUoIiIi0Scn9fAtWFEZsP7vA58X1lteGO3SJUPhSkRERKJTTpqJjTFYr23xmfq2z5STHMZ3jrriiYiIiBxypBasqEow2yosl7zicUY7wx0Do6poIiIiIl+Rk2oOOwYralKM51u+8YqHb+GfI1wCjroGRUREJLpF/Ris2971WbzVsmCsS4dUhSsRERGJfjlphmr/q/dHRcB6qcTnzhU+dw1yGJYTNY1qIiIiIkfVMfXw90c8zazfa4XjakkAAAc8SURBVLl8kce4XMOUkyJeHBEREZE6+2I29y+LaKI54FkuXujRIgkeP9vF0SLOIiIiEkPaNz/8/RHtIvzJmz4rdlleH++S3UzhSkRERGJLsmv4/+3dbUyTVxgG4Lsf+MFWdCsEYpUWhtUtdq3JTIhGi4tGZY1inBqXYC2d0SzG+UeXLCaGRDFGAzaaxZnwSx1roxKjxGT4Abg4I06dJNs0XUEER9WKElAr0LMfzDcQEDdT+vK29/ULztuUhzx52pueQ5s2bvC6bAHrx78iOPh7BN/NUeOTNG4NEhERkTJNGuIclizJ5o92gS/revHFByps/JDhioiIiJRrqHNYMU83Xd19H+Kc+S7w/VwNVDx3RURERAq2aPLgLBPTLUIhBDb83Iu7nUB9gRbvJjFcERERkbJ9PUMzaC2mAevwnxEc8wscm6/Bh+8xXBEREVF8itkW4a8PBTZfjuCrj9T4IofnroiIiCh+xSTptIf7zl19/L4KpbkMV0RERBTfRnyLMCIE1tb04mk3cNGhwVgNtwaJiIgovo14wNr7WwRnmgXOLNLApGO4IiIiovg3ovt1Nfcj+PZaBN/a1Pgsk1uDcgqHw9izZw/C4bDcpdB/wH4pD3umLOyXsiixXyohhIjmHXZ0dGDChAm4/fcTzDuXjI8mqvBTvgZaNV+9ktOrvjx9+hQpKSlyl0NvwH4pD3umLOyXsiixXyP2slJRXS/UKuCHTxmuiIiIKLGM2BmsX4ICFz/XICOZ4YqIiIgSS9QD1qsdx2+mdcL2ThI6OqL9E+htdPzbiA42RBHYL+Vhz5SF/VIWpfRLp9NJHwEY9TNYLS0tmDJlSjTvkoiIiGjU639GLOoBKxKJ4P79+wNSHBEREVG8G9FXsIiIiIgSHd+cioiIiCjKGLCIiIiIoowBKw69ePECBQUFMJvNsFqtWLhwIfx+PwAgLy8PWVlZsNlssNlsKCsrk7laAgCTyYRp06ZJffF6vQCABw8eYPHixZg6dSpmzJiBuro6mSulUCgk9clms8FsNkOr1eLx48ecr1Fi8+bNMJlMUKlUuHnzprQ+3Dw9e/YMa9asQU5ODsxmM44fPy5H6Qnpdf1yuVzS89icOXNQX18vXVu3bh0MBoM0a1u3bpWj9OEJijvPnz8XVVVVIhKJCCGEOHDggLDb7UIIIex2u6isrJSxOhqK0WgUN27cGLTucrnEjh07hBBCXL16VRgMBvHy5csYV0fD2bt3r3A4HEIIztdoUVtbK+7duzdoroabp+LiYuF0OoUQQgQCAZGWliYePXoU69IT0uv6derUKdHd3S2EEOL06dPCaDRK15xOpygrK4t1qf8LX8GKQ+PGjUN+fr70nwy5ubloamqStyh6Kz6fDxs3bgQAzJo1C5MmTUJtba3MVVF/5eXlcLvdcpdB/cybNw+TJ08etD7cPHm9XulaVlYW8vLyUFlZGbuiE9jr+rV06VJotX1v15mbm4vW1lb09PTEury3xoCVADweD5YtWyZ9v23bNlgsFqxevRqBQEDGyqi/wsJCWCwWuN1uPHz4EKFQCN3d3cjIyJBuYzKZ0NzcLGOV1N/ly5fR3t4Oh8MhrXG+Rqc3zVNzczOMRuOQ10h+Ho8H+fn5UuACgP3798NiscDhcAzYWhwtGLDiXElJCfx+P3bv3g0AOHLkCO7cuYNbt25h7ty5A54YSD51dXVoaGjA9evXkZqaCqfTKXdJ9B+Ul5dj7dq10oM+54so+o4ePQqfz4fDhw9La7t27UIgEEBDQwPcbjeWLFmCzs5OGascjAErju3btw8nT57E2bNnkZycDADSu+yrVCps2rQJgUAAoVBIzjIJQGZmJgAgKSkJW7ZswaVLl6DX66HVatHW1ibdrqmpSbotyauzsxM+nw9FRUXSGudr9HrTPGVmZuLu3btDXiP5eL1eFBcXo7q6Gunp6dK6wWCAWt0XYZYvX46UlBTcvn1brjKHxIAVp0pLS1FRUYHq6mpMnDgRANDT04NgMCjd5sSJE0hPT4der5erTALQ1dWFJ0+eSN9XVFRg5syZAICVK1fi0KFDAID6+nq0trbCbrfLUicN5PV6YbVaMX36dACcLyUYbp76X2tsbERNTQ0KCgpkq5X6zsxt374d586dGxR2W1papK+vXLmCUCiEnJycWJc4LL6Texx69XmQ2dnZ0Ol0AICxY8fiwoULsNvtCIfDUKvVSE1NRWlpKaxWq8wVJ7ZAIIAVK1agt7cXQghkZ2fD4/HAZDIhGAyisLAQjY2NGDNmDA4ePIj58+fLXTIBmD17NtavXw+XywWgLyhzvkaHDRs2oKqqCm1tbdDr9dDpdPD7/cPOU1dXF4qKinDt2jVoNBrs3LkTq1atkvk3SQyv61dSUhIyMjIG/JFy/vx56PV6LFiwAMFgEBqNBuPHj0dJScmoe2xkwCIiIiKKMm4REhEREUUZAxYRERFRlDFgEREREUXZPzbpKzCjya23AAAAAElFTkSuQmCC"},"metadata":{"image/png":{"height":480,"width":600}},"execution_count":1}],"cell_type":"code","source":["theta = 45\nplot(x -> flight(x, theta), 0, howfar(theta))"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

To maximize the range we solve for the lone critical point of howfar within the range. The derivative can not be taken automatically with D. So, here we use a central-difference approximation and start the search at 45 degrees, the angle which maximizes the trajectory on a non-windy day:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":["26.262308906498127"]},"metadata":{},"execution_count":null}],"cell_type":"code","source":["h = 1e-5\nhowfarp(theta) = (howfar(theta+h) - howfar(theta-h)) / (2h)\ntstar = fzero(howfarp, 45)"],"metadata":{},"execution_count":null}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["26.26230890667609"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["h = 1e-5\nhowfarp(theta) = (howfar(theta+h) - howfar(theta-h)) / (2h)\ntstar = find_zero(howfarp, 45)"],"metadata":{},"execution_count":1}, {"cell_type":"markdown","source":"

This shows the differences in the trajectories:

","metadata":{}}, -{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"iVBORw0KGgoAAAANSUhEUgAAAlgAAAGQCAIAAAD9V4nPAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nOzdd3xUVdoH8N/M3JnJTHoIkAoI0luAoKFJ71V6EVSUYgF01dXV3bWs7uK77rp2QVE60pHeiwREIPQOEiGkQUiZyfRy3z+CAUNuSDJ35ty583w//DGGmXMfFHNyf/c55yh4ngchhBASqJSsCyCEEEJYoomQEEJIQKOJkBBCSECjiZAQQkhAo4mQEEJIQKOJkBBCSEDjfH9Jp9OVm3s7Pr6W7y9NCPEN3mF3Gw1V+ohCqVJoteA4hVrjpaoIKReDiTAjI6dHj2fT07f4/tKEEK9y5mQ5Lp23XzznuP4bl1BH06iJUh/M2x28y8HbbHC5eZuFd/O81QwevMXM8zxvtcDl4m023uXk7XY4HbzDoVCrwakVGo1CxSm0WqhUiiCdguO0rdsFJbWDisE3LiJj9PeJEOIR3mK2X75gv3TefvGcQsVpGjfTdeoa9uRUhUZb/TEddjidvN3Ou5y8zQaXi7da3Baz9ZcDpi0/6lK6BHXoogwOEfFPQQIZTYSEkKrjeWdmhv3KBcfli46Ma+rEuuqGjcNTpnEJdUQZXqHWQK1R6PRlvq5t2caVd9NycF/+/72rbdpC1603FxMnyhVJIFP4fou19PRMikYJ8UduU7Hj10v2yxft508rOLW6YRNt0xbqRk0UnNrHlfBWi/XoIfNPu1QRkbrO3bUtkqCk1j9STTQREkIq5HY7s27Yzp+2nz/junVTXf9hbbOWmsbNlBFRrCsDXC7b2ZOW/XvcxQZdp25Bj3RSaKjRhlQZRaOEkHK48m87Lp+3X75ov3JRFVVD83CT4P5DNfUbQqViXdo9VCptq7baVm2dN65bUvfc3rklqG17XZeeqkgJTNLEf9AdIWEpP79o3bo9kycPY10IuYO3mM0/7bKdOsbbbJpGzTSNm6obNlHqg31fyZEjZ8xma9euyZX/iKvgtuXAPtvRQ+qGjXVdeqjrPOS98ghDy5dv69ixdWJijFgD0kRIWHK73VarXa8PYl0IAW+zWlL3WlL3aFq01nXsysXEQaFgWI/D4XS73VptlaNO3ma1Hj1kSd2rDA7WdemhbdmGHh/KjMVi02jUKpVo/1lpIiQk4Lmc1qOHTDs2q+s1CO47WFVTFptd8Lz9ykVL6h5nZkbQo510nboxua8lfoGeERKWKBplzOW0HD5o3r1NnVgvfMoMrnYs64LuqkY0+gcKhaZhE03DJs7sTMv+Pfn/925Q67a6zj1kMs0HNopGiaxQNMqM2209dti8Y7Oqdkxwn0Firf8TUbWj0XK5i43Wn/dbfv4pbMIz6gYNRRmTsCJ6NEp3hIQlpVJJs6Cv8bzt9HHTto1KfXDo6CfUDRqxLqh8arWY352UIaH63gPUDZsYFs4Nm/is+qGHRRyc+JhOV/1Ni8pFz5AJS/n5Rd99t451FQHEfvlCwacfmvftChn4eMQLr0h2FgRw5MiZffuOijumul790HFPGRZ967xxXdyRiS8tX74tIyNHxAEpGiUsUTTqM47ffjVtXc+bTPreA7Qt27DtCK0McaPRe9kvnjMuXxj+zAtcfKLogxMfoGiUyApFoz7guJ5u3rrBlZ+n794nqH1Hf1lLIG40ei9N42Yhw8cWff9VxJQZKin1B5FKomiUyApFo17lzMkyLJ5nWPydtnXbqD+/E/RoZ3+ZBeGdaLSUtkVS8IBhhfO+cOXneekSxHsoGiWyQtGol7hu5pi2b3Jcvax7rIeuc3ffb4rtOe9Fo6WsR34279wcPv0lVWQN712FiI6iUSIrFI2KzlWQb969zX72pO6xHqFjJinU/jcFlvBeNFoqqH0H3m4r+ubziOkvKcPCvX05IhaKRomsUDQqIndRYfH6lYWfzFbq9FF/flvfrY//zoLwcjRaStepmy6lc+GcT9zFRm9fi4iFolEiKxSNisJdbDTv3mo7diTo0c76br3uP8/WH/kgGi1l2rbBfuFsxNRZCp3OB5cjHqJolMgKRaOes51IK16/UtsmOfLVvylDQlmXIxofRKOlgvsO5h2OonlfhE95UaGVz1/I0aNfu3Urn3UVXtGvX6fXX58s1mg0ERKWaK9RT/BWa/GmtY70K+GTn5fgHmke8nSv0SoKGfh48boVRd9+ET7lRYVG5EdQrBw8eOLjj1+Ljo5kXYjItm07eOzYeREHpImQsBQRETp2bD/WVfglx7Wrxh8WqB9uEjnzdVkey56U1MTtdvvuegpFyLDRxjXLDAvmhj093R/7bMvVoUPrhITarKsQ2bVrWdnZt0QckJplCEsUjVaHy2Xascmw6NuQIaNCR4yT5SwIQK3mfPOA8C6FIvTxsYqQUMOCubzT6dNLkypSiLo1Ek2EhCXqGq0qV252wef/dmVnRb78pqZpC9bleJFvukbLUirDxkxSaIOMS7+HL+9HSRVZLFYRR6OJkLBE0WgV8Lz1l9TCOZ/oUjqHTZqiDA5hXZB3JSU1SUlpxeDCSmXYuCd5l9O4YhF83lRPKikoSMznuDQREpYoGq0kt9FQ9P1X1iOHIl54JejRzqzL8QUG0WgpFRf2xLOuokLjyiU0F0oTRaNEPigarQzb6eMFH/+TS6wb8fyfVDVqsi7HR9hEo79TqNXhk59z5d8qXr+KVQ2kAuJGo9Q1SliiaLRivy+QuCzLBRIV83XX6H0Uak34U88VfvNp8cY1IYOGM6yE3I+iUSIfFI1WwHEtveCT2QAiZ74RaLMg2Eajv1MEBUU8O8Px6yXzrq1sKyFlUDRK5IOi0fLdWSDxTcjgETJeIFExttFoKYVOF/7si9YTR817t7OuhdxF0SiRD4pG7+e6mWNYNl8ZGhY56w1laBjrcphhHo2WUgaHRDz7YuHXHyu0QboOj7EuhwAUjRI5oWj0D0oWSHz1cVC7R8MnPx/IsyCkEY2WUoZHREybZdm30/rLAda1yNaCBetv3qzszqjSikbz8gpfffU/Y8f+ee7cu71VGRk5M2fOHjv2z//5z0Kn0+XhJYiMUTRayl1sLJr/tfXIzxEvvKLr3J11OexJJBotpYyICp8yw7Rzs+34Eda1yI3FYvvb3754663P8vIKK/0RKS2onzbtvUmTBi9ZMjsz8+ahQ6cA8Dw/ffr7s2ZNWLp0dmxs9OzZ88Sok8gTRaMlbKePF/z3A652XMRzf1JF12JdjiQwW1AvTFWjZsTUmcWb1tpOHmNdi7+6eTM/N/d2yevc3Nult4CDBj327LNVaM0VNxr16BlhenpmnTqxrVo1AvDuu8+XfPHMmSvJyc0aNEgEMH78gMcff/n+Dzoczp07D93/9bCwkHr14mrViiouNpvNVnpBL+T/4naBecuP3I109ahJphoxwSqVVAqjF+W9sOhCXY8/Ubxmkc3NW+MfYl5PxS/uP272p2x8d9GT7/pV0DUWTzcu+8XCQuPnny/79NM3AHzwwTcvvjiuVq0onU776KMtt2xJrfzgCoWigj97VUv1aCK8cCH9ypXrgwa9GBSkjYwM+/zzv2i1mvT0zIYN65a+p9xDxcxm6+zZ393/9aSkxkOGdKtVKyovr/D69Wx6IfsXZ85cuXkzv0ePRyRSj49fRNkM5gXfFEbGNHzlrWuZedcvpEukMCm82L79YOPG9erWjZNIPXdf3LZ0eHJawbwvM5Ieq/X4IPb1CL9wucp2G8Xq0S3Ok+/6VdAovLwvNqqbnZ1XVFSsVCpu3sxv1KhuOW+qBIvFWsGfvaqjeXRC/erVO1et2rF06WyFQrFhw77Ll6//6U8T16zZZbc7SvOu0aNfW7Hi3/d+ik6oJ6UC+YT6kgN1Q0eO1zSTVgAoEb48ob4aHFevGBZ/K/GNDhISeh86tFhqxzBt3rz/8uXrPM83blyvf/+7+wW+885Xo0f3bdas/gNHmD//xz17jixY8L5YJXn0jDA0NLhLl7Yl3Tt9+nRISzsHoGbNyNIIGIBEGqCJNAVo1yjPm3ZsMm39MXzqTJoFhUiqa/R+6voPBw8YVrxpLetC/E+/fp22b/95x45Dfft2rPYgEuoaTUlptX37zyX3lNu3/5yU1BhAu3bNdu8+XPLF69ezw8Nlvkc+8UQAdo3yTqdx+ULHxfMRL77GxfgqpfJDUusavV9Q20fcRYWO335lXYifUSqVKSmt+vbtqFT+YQLSajUaTWWf1kloQX1YWPATTwwcPHiGVqupVSvqf//7MwC9PmjixEGDB8/Q6YIcDudnn70hUqlEhgKta9RtKjYsmKsMjwifNkuhlskZ6F4inQX1gpRKfdee5t3bwic/z7oUf2K12g4ePLFq1X/KfP0vf3mm8oNIqGsUwMiRvUeO7F2ZLxJyv4CKRp05WYbvv9YmPxrcawBEDXZkqdw+O6kJSu5g3r3NeeO6lJ8USsqRI2c/+OCbN998NjhY58k4EopGCfFQ4ESj9gtni+Z+GtxvcHDvgTQLVob0o1EAUKl0XXqad29jXYff4DjVF1+82aVLWw/HkVA0SoiHAiQataTuMe/bGf70c1xiNZvFA5AfRKMAgKCUTuZ9O5w5WfTEtzLatGkiyji01yiRD/lHo2538dofrEd+jnzhFZoFq0TiXaOlFJxa16mbeQ+dTeFTFI0S+ZB3NMqbTYXffOY2GiNeeFUZUeVFvgHOP6JRAICuY1fH5QuuWzdZFxJApLXXKCGekHE06sq7WfDFf7jYuLCJzwbmgYIekuBeo0IUGo2u42N0YKEvSatrlBBPyDUatV++YFw2P3jgsKB2Kaxr8Vd+0TVaSte5e/6H77gKbqsia7Cuxf+kp2d+8smS3Nzb7do1mzlzvEbz4JVFFI0S+ZBlNGr9JdX4w4KwJ56hWdATfhSNAlAE6YIe6WTZt4t1IX5pxox/zZgxbvHifyUmxnz44feV+QhFo0Q+5BaNut2mzT9aUvdGvPCqun5D1tX4Nz+KRkvouva0nTjqNhSxLkTSyj2GaejQ7g0aJKpUyt69U9LTMyszDkWjRD7kFI3yNqth6fdwuSJeeEUR5NFiYQJ/i0YBKPXB2naPmn/aFTKoCufq+ZgzM8N29qRvrsXF19E2L/ujTLnHME2ZMqLkd99++6spUyr1b4+iUSIfsolGXfl5BZ9/pAyLCJ/8PM2CovCvaLSEvltv29FDblMx60IqolAqffbr/quXHsNkNJrKHMM0b97a2rWjOnRoXZk/BS2oJ/Ihj2jUce2qYdG3+h59dR27sq5FPvxlQf29lKFh2tZtLal7gvsOZl1L+bj4RC4+kW0NTz89dP78H3mef/LJIaVfXL16Z1rauS++eLOSg9CCeiIfMohGbSeOGhZ9Gzr2SZoFxeUvC+rL0HfvYz2UylvMrAuRrvuPYVqzZtfWrQc+//wvlQ88KRol8uHf0WjJsYLbNkZMnal5uDHrauTGH6NRAMqIKE3TlpYD+1gXIl1ljmE6efLixIlvFhQYxo59ffTo1yZPfrsyg1A0SuTDf6NR3m43LpvvNhVHvPiqMpgO3RSfP0ajJfQ9+xV+8ZGuS3eF1r/TDi8pcwxT69aNTaZfqjoIRaNEPvw0GnUXGwu/+q8iODhi2iyaBb3ET6NRAKoa0eqHG1sOpbIuRIqOHDk7duzrdAwTIXf5YzTqLios/PpjTbOWoSMnQKViXY5s+Wk0WkLfo69l/27e4WBdiOTQMUyElOV30airIL9o7qdBKZ31XXuxrkXm/DcaBcDFxKkT61mPHKQWqjLoGCZCyvKvaNR1K7fwq//qOnWjWdAH/DcaLaHv1d+8dwdcTtaFyBNFo0Q+/CgadeZmF879NLjPIF3nbqxrCQh+HY2iZMVe7Vhr2mHWhcgTRaNEPvwlGnXeuF40/+uQoaO0LduwriVQ+HU0WkLfa4Bx2fyg5BSUt8cK8QRFo0Q+/CIadVy9UjTvi9DhY2kW9CV/j0YBqOs+pIyMtJ7w4/tayaJolMiH9KNR+4WzhkXfhE6YrGnmTychyIC/R6Ml9D36mXdvA8+zLkRuKBol8iHxaNR+7pRx9bKwp6ar6z7EupaAI4NoFICmYROlXm87c4LiBHHRMUxEPqQcjdqOHynetDb82Re52HjWtQQivzuGSYi+e1/Ttg3aFkkQNc2rpB9+2BoZGeb763rVwYMnxI1GZfJXjfip/Pyidev2TJ48jHUhZVkO7Tfv2ho+ZQZXO5Z1LQHqyJEzZrO1a9dk1oV4StO0hWnHJvuFs5qmLXx86Tlz/r5mzU4fX9QHrl/PKd2wWxQK3ufhdXp6Zo8ez6anb/HxdYkEud1uq9UutZtC894d1p/3h0+dqaoRzbqWwOVwON1ut7/3y5SwnTpm+WlXxIuvsS5EJiwWm0ajVqlE63GhZhnCkgSjUfPe7dajP0c8/yeaBdmSQddoKW3LNrzdbr9ykXUhMqHTaUWcBUETIWFLWl2jPF+8cY3t5LGI5/6kDI9gXU2gk0fX6B0Kha5bb/OurazrkInly7dlZOSIOCA9IyQsSahrlOeLf1zpyPgtYsoMhT6YdTVEJl2jpYKSks07tzh++1VdrwHrWvzekCHdNBq1iAPSHSFhSSrRqNttXLHYmZMVMXUmzYISIadoFACUSn3XXubd21jXIQcUjRJZkUQ06nIaFs9zm4zhz7xAJ6lKh6yiUQBAUHKKKzfbmXGNdSF+T/RolLpGCUvMu0Z5h92wYK5Cpwsb+xQdLigpcuoaLWU5sNfx66WwSVNZF+LfqGuUyArbaJS324q+/1oRHBI27mmaBaVGbtEoACDo0U6OjGvOnCzWhfg3ikaJrDCMRnmLuWjuZ1x0rbCxT9LhABIkv2gUgIJT6zp1M+/ZzroQ/yZ6NEr//xOWWHWNuouNhV99rG7QMGT4WCYbX5EHSkpqkpIiw43OdR0fc1y+4Mq7yboQPzZkSLe4uFoiDkgTIWGJSTTqNpuK5n6qbdUmuP9QH1+aVJ4so1EACo1W17GreTfdFFYfRaNEVnwfjfJWa9G3n6sbNtH3GuDL65KqkmU0WkLXuZv9/GlXwW3Whfgr6holsuLjrlHeYS+a9wUXEx8ybLRvrkiqTZZdo6VMW9fzFkvI42NYF+KXqGuUyIpPo1GX07DoW1VkdMjQUT66IvGAXKPRErrHetpOprmLClkX4pcoGiWy4rto1OUqWvStQq0OHTWBumP8goyjUQBKfbA2OcW8fzfrQvwSdY0SWfFR16jbbVi+AFCEjZ9MKyX8hVy7Rkvpu/ayHT3kNhWzLsT/UNcokRVfRKM8b1z7A28yhT0xmVbN+xF5R6MAlKFh2tZtLal7WBfifygaJbLig2i0eNNaV0522JNTFZyY29UTb5N3NFpC372P9VAqbzGzLsTPUNcokRVvd42atvxov3guYtpLCp3OS5cgXiLvrtFSxhWLVVE19L36sy7En1DXKJEVr0aj5p2b7efPhE+dSbOgP5J9NFpC37Of5eA+3mZlXYg/oWiUyIr3olFL6l7rsSPhz76opPMF/VMgRKMAVDWi1Q83thxKZV2IP6GuUSIrXuoatR792bJ/V/iUGcqwcNEHJ74h+67RUsE9+1n27+YdDtaF+A3qGiWy4o1o1HrssGn7pvBps1SRUeKOTHwpQKJRAKrasVxCXdvJNNaF+A2KRomsiB6N2s6eNG1eF/HMC6qoaBGHJb4XINFoCU3Dxs7rv7Guwm+IHo1yIo5FSFWJG43aL18oXr0sfPLzqtqxYo1JWElKauJ2u1lX4SNcfKLt+BHWVfiNIUO6aTRiroaiiZCwJGI06vjtqnHZ/LBJU7iEOqIMSNhSqwPouxMXl+DMyYLbTTsfVYZOpxV3QPqXTlgSKxp1XP/NsHBu2IRn1PUaeD4akYKAikYVGq0yPMJ5K5d1If6BolEiK6JEo87sTMOCOaGjnlA3aChKVUQKAioaBcDFJTozMzhK9StB9GiU7ggJS55Ho65bN4u++zJkyChN0xZiVUWkIHC6Rktw8QnOrBusq/AP1DVKZMXDaNR1O69w7ifBfQZpW7cVsSoiBQEVjeL3O0LWVfgHikaJrHgSjbqLCou++Uzfs19Q+w7iVkWkIOCi0fhEZ9YN8Dydl/lAFI0SWal2NOo2FRd+81lQhy66lC6iV0WkINCiUWVwiEKjcRXksy7ED1A0SmSletEob7EUfft5UJv2+q69vFEVkYJAi0Zx56aQ0tEHo2iUyEo1olHeai389jN1/Yf1Pb1/tD1hJ9CiUfz+mFDbIol1IVJH0SiRlapGo7zDXjT/a3VivZDBI71XFZGCQItGQY2jlUbRKJGVqkWjLqdhwVxVVHTI0FHeLIpIQiBGo9Q4WjkUjRJZqUI0yvPGlUsUGm3oyPHUVhcIAjAaVUVG8U6nu9ioDAllXYukUTRKZKXy0ahp+0bnrdzQcU/SZowBIgCjUZRsOko3hQ9C0SiRlUpGo9bDB20njoY//ZxCHXDfGQNWAEajANTUOFoJFI0SWalMNGq/eM60bUPE9JcpLwooARiNAuDiEmxnT7GuQuooGiWy8sBo1JmTZVyxKGzSFFXNWj6rikhBgEaj8dQv82AUjRJZqTgadRcVGr7/KuTxMeq69X1ZFZGCwIxGVdG13EYDb7WwLkTSKBolslJBNMpbrUXffanr0pPWFwemwIxGoVRyMXHO7Ez1Qw+zLkW6KBolsiIYjbpchkXfqBs20XXu5uuaiDQEZjQKSkcrgaJRIivlR6M8b1y5WKHThwx8nEVRRBICMxrFnYmQ9pepCEWjRFbKjUZNWzc4b92MmD6LFs4HsgCNRgEuLsFyYC/rKiSNolEiK/dHo9bDB22n0sIn05LBQBew0agqJs6Vd5N3OlgXIl0UjRJZKRON2i+cNW3bEP7MC8rgEIZVESkI2GhUwXGq6FqunGzWhUgXRaNEVu6NRp03rhuXLwx7aroqmpYMksCNRvH77ttcQh3WhUiU6NEoTYSEpdJo1FVwu2j+1yEjxqvrPsS6KCIJanXgfnfi4hNoo7UK6HRacQekaJSwVBKN8laL4fuv9d37aFu0Zl0RkYqAjUZBjaMPQtEokZWIiNCxo3oZFn6jadJc16kb63KIhAR0NBqb4MzJhNtNZ62Ui7pGiawoFQrXptWK4ODg/kNZ10KkJWC7RgEogoKUoeGuvJusC5Eo6holsnJ77YqsC5dDx0yiJYOkjECORkH7y1SIolEiH9ZfUhVXLyXO+JOCEzPlIPIQyNEo7vTL3NC2ac+6ECmiaJTIhP38GdP2TeFPT9fXiGJdC5GiQI5GAXBxiQ66IxRA0SiRA+eN68YVi8KenFqk0FTmhHoSgCgadWZmgOdZFyJFFI0Sv+fKv100/+uQkRPUdR6KcLsfeEI9CUwBHo0qQ0IVarWrsEAVSZFJWRSNEv/Gm01F877Q9+irbd4KlTihngSsAI9GUXJTSMvqy0PRKPFjvNNRNH+OtkWSrmPXkq9UfEI9CWQBHo0C4OISaFl9uSgaJX6L540rlyjDI4L7DS79WgUn1JMAF+DRKAAuPtF69BDrKqSIolHir4o3rXUXFZRZMkjRKBFC0WjJ1tusq5AiikaJX7IeSrVfPBf+5DQF94cQgqJRIoSiUVVkFO9wuIuNrAuRHIpGif+xnz9j2rUl4vlXFDp9md+iaJQIoWgUCgUXG+/MuqFp1JR1KdJC0SjxM86Ma8ZVS8Kfml5uFzhFo0QIRaOgxlEBFI0Sf+LKzytaMCd0xDguPrHcN1A0SoRQNApqHBVA0SjxG26zqWjel/qe/TTNWgm9h6JRIoSiUQBcfKJ51xbWVUgOnVBP/ITLaZg/R9uqja7DYxW8i6JRIiSQT6gvxdWs7S4q5G1WhZb+N7mLTqgn/sG4bqUyJCS4z6CK30bRKBFC0SgAKJVcTJwzO5N1HdJC0SjxA5bUPc7r6REvvPrAUwYpGiVCKBotUbKaUF2vAetCJIS6RonU2S9fMO/eFvbkVIXmwS1/FI0SIdQ1WoKLp36ZsqhrlEiaK/+2cfnCsAnPqKKiK/N+ikaJEIpGS3BxtIKiLIpGiXTxNqth/tfBvQaoGzSs5EcoGiVCKBotoYqNc926yTudZXZlCmQUjRKp4nnDsvnq+g2DUjpX/kMUjRIhFI2WUHBqVY1oV24260IkhKJRIlGmLet5iyVk8PAqfYqiUSKEotFSd06rJ7+TaDSan1+0evXOKVNGlPxjRkbOv/89/+bN/PbtW8yaNYHjVKJchUiW7dQx26m0iBl/hqpqf6MoGiVCKBotxcUlOrOoX+YuiUajs2Z9uHPnnXOzeJ6fPv39WbMmLF06OzY2evbseaJcgkiWMzOjeN2KsKemK4NDqvpZikaJEIpGS3HxCXRHeC8pRqPz5q1t375F6T+eOXMlOblZgwaJSqVy/PgBaWnnPb8EkSy30VC0YG7oyPFcTFw1Pk7RKBFC0WgpLi7RmZMFuj/+nejRqKcT4a+/ZmzdemDGjHGlX0lPz2zYsG7pP5a7T1JhoTE5edz9v5577v1du34pGZZe+MGLS+kZn/5Xl9I5QxtZvXGOHTs/dmw/qfxx6IWUXuTnG1JSWjEvQwovrmbesqk4V94tidTD/EVoaHBcXK0K3lNlvAccDuegQS9mZ9/ieX706FdLvrh69c5ly7aUvmfUqFfLfOrq1RsJCb2PHDlz/6+zZ3/Nzy/ied5sttIL6b8o+GHBrW+/4N1uidRDL+iFXF/c+vZL6/EjzMvwlxdVpeB5vjrzJwDg9OnL//jH3JLXhw6dSklp9fe/TysoMBw7dn7WrAklXx858pVVq/5z76fS0zN79Hg2PZ22VPdv5n07bSeORjz/J4W6+g9y8vOL1q3bM3nyMBELI/Jw5MgZs9natWsy60Ikwbx7G28xBw98nHUhkrB8+baOHVsnJsaINaBHXaMtWzZcseLfJa/HjHlt+fJ/AzCbrR99tGDmzPEKheL69ezw8Co3UBDps186b0ndE/nCq57MgqCuUSKMukbvxcUlWPbvZl2FVEj3GKbgYIfm5IcAACAASURBVH3JC70+aOLEQYMHz9DpghwO52efvSHWJYhEuG7lGpfND5s4RRkR6eFQ1DVKhNAxTPfiEupQ42gp0Y9hEu2v2nffvVv6euTI3iNH9hZrZCIpvNVatPCb4P5D1fUf9nw0ikaJEIpG76UMCYVK5S7MV0ZEsa6FPWlFoyTguN2Gpd9pGjcLeqSjKONRNEqEUDRaBhef6Mi8oaWJULIL6kmAKN60Fi5XyADRbuAoGiVCaEF9GVw8HUNxhxQX1JMAYU37xX7hTNgTz0Ap2l+bfFpQTwTQgvoyuDg6mPAOie41SmTPcS3dtHFN+PSXFDq9iMNSNEqEUDRaBhef6NywmnUVkiDdrlEiY25DkWHJvNDRE7naseKOTNEoEUJdo2WoImvwNpvbVFyNTX1lRvSuUYpGyQPwDkfRgjm6Tt00TVs8+N1VRNEoEULRaFkKBRcbT8dQgKJR4ms8b1y5mKtZW9+1lzeGp2iUCKFo9H4lBxNqGjZhXQhj1DVKfMq8e5sr72bIiPFeGp+iUSKEukbvR42jJahrlPiO/cJZy6H94U9OU6jF/OHrXhSNEiEUjd6PGkdLUDRKfMR1M8e4YlH409OV4RHeuwpFo0QIRaP342rFuIsKebtNoRG5W8S/UDRKfIE3m4q+/zpk8AgusZ5XL0TRKBFC0Wg5lEpV7RhndibrOhijaJR4n9tdtHietlUbbZv23r4URaNECEWj5Srpl2FdBWMUjRKvK964WqFWB/cb4oNrUTRKhFA0Wi4uLsGZcY11FYxRNEq8y3biqP382bCxT0Gh8MHlKBolQigaLZc6PpGWElI0SrzImZNVvG5F2BPPKHQ631yRolEihKLRcqli4l03c+Fysi6EJYpGibfwNqth8bfBg4dz8Yk+uyhFo0QIRaPlUqjVqqgaztwcLi6BdS3MUDRKvIPnjcsXaRo2DWqX4svLUjRKhFA0KoT6ZSgaJV5h3rPdbSgKGfS4j69L0SgRQtGoEC4uIcAnQopGifgcVy5aDu6LnPFnqHz994GiUSKEolEhXHwd25kTrKtgiY5hIiJzFxYYflgQNv5pr+4gI4SiUSKEjmESwsUlOLOzwPO+ae2WIDqGiYiJdzqLFn2jf6ynun5DJgVQNEqEUDQqRKHTKYODXXm3WBfCDEWjREzFP65UhUXouvRgVQBFo0QIRaMV4OISnVkZqpq1WBfCBnWNEtFYjx12XL0cOmYSw4CFolEihLpGK8DFJwbyMRTUNUrE4czONG1cEz5piiKI5TxE0SgRQtFoBbi4BGfmddZVMEPRKBEBbzEbFs4NGTZaVTuWbSUUjRIhFI1WIMCXElI0SjzG84Zl87UtkrSt2rIuhaJRIoii0Qoow8KhUrmLClkXwgZFo8RTph2beYc9uP9Q1oUAFI0SYRSNViyQl9VTNEo8Yj9/xnr4QOTM16GUxM9AFI0SIRSNVqykcVTTrCXrQhigaJRUn6sg37hqSdgTzyjDwlnXcgdFo0QIRaMV4+ITArZxlKJRUk2802FYOFffs5+6XgPWtdxF0SgRQtFoxbj4RAdFoyKhaDRQFK9ZrqoVo+vYlXUhf0DRKBFC0WjFVFHRvNXiNhUrg0NY1+JrFI2S6rD8/JPzxrXQkeNZF1IWRaNECEWjD6BQcHHxzuxM1nUwQNEoqTLH9d/MOzaHPTlVoZbctxWKRokQikYfiIsL0NWEFI2SqnEXGw2Lvw0ZPk5VoybrWspB0Si5n4tHrgXuxKa3i/k555FtRpYJ2WZkmZFthtUFPQetCsEcNEqEqKFWIlQNTokwDVQKhGugVCBCAwUQqYVCgQgNlAqEa6BSIEwDToFQNdRKhKihUSHYb78LcvEJ9ksXWFfBAB3DRKrC7Tb+sCAoOUXbojXrUspH0WhgcvPItdyd20rnuZIXt6yIDkKcXhWrR1ww4vRIrnnnRaweQSqYnLC7UOyEww2jHU4eBjtcPIrscPMotIPnUWAHz+OqEW4eRXa4eBjscPIw2uFwo9gJuwsmJ2wumJ3QqlAvFMnRaFcTyTXRpgZCxPw26y1cXKJ5zw7WVTAg+jFMNBHKmWnrerjdwb0GsC5EUH5+0bp1eyZPHsa6ECIyHsg1I8eCTBNyzMi8Z8LLNN2Z6mL0iNejZLZrE42Bv7+urYNKgSNHzpjN1q5dku8fPFLkb4OwuvCrAUdvIS0PK6/idD7qhCC5JtpFI7kmkmpAL8nvlFztWHdBPm+3KTRi/xuRtuXLt3Xs2DoxMUasARU8z4s1ViWlp2f26PFsevoWH1830NjOnjKtXxkx83UpN5W53W6r1U43hTJQYMORW3d+Hc9DjhlRQYjRIT74zoQXo0d8MGL1iNOjtg7cg/oTHA6n2+1m0i/jdONcIY7eujM1ns1H/TAk17wzNbaugSCV74sqX8GnH4YMHa2u+xDrQnzKYrFpNGoR+2Uk+XMO8Zjr1s3i1UvDJz8v5VkQFI36M7MTx/J+n/xu4qYV7aLRviYmNsT/OiA+GGrPvk0xPKGeU6JVFFpFYXJjAHC4cTofaXk4egvzLuBCIRqF350XW9WAhl3TIRef6MzKCLSJkKJR8mC83WZYODe43xAuoQ7rWh6AolE/4nTjYhHSbiEtD2l5OJGHuqFoF41usXirDZpGQCnquZZ3otGu5USjPqZWom002kZjShPgj/8eFl2++++hXc07PwpofXi/yMUlBuB5TBSNkgczLJmnCNKFjpDcqsH7UTQqcVlmpN3CgVyk5uDUbSSG3P2On1zTuwkhw2i0ShxuXCrv54OSf0uP1PLu/aLjenrxuhWRM1/34jWkh6JR8gCW/Xtct/Minv8T60IqhaJRqckovvuo7+gtRAehfU20r4l/PYK20T5dacAwGq0StRLNI9E8EpMaAYDJiRN5OJqHo7cw5xwyTOgSg6lNMajOgx+LVgMXG+/KzYHLBZVknlt6H0WjpCKO6+nmPdsiZvxZwflD9zdFoxJQaMeh3LuTH3Bn5nu1FdrXRA12P6VIJxqtkmAOnWLQ6ffQzujAut/w0Sm8eADPNMazTZAo6lN7hVqjjKrhvJnDxcaLOa60UTRKBPEWc8Ens4MHj9A2l+iqwftRNMrKuQJsuo5N13H8NpKj8UitO/OfuN+mPeEv0WglncnHnPNYegWdYjCtKfonivZI1bBsvqZhk6DkFHGG8wcUjRIBPG9csVjTIsmPZkFQNOpbVhdSc7AzEz/+BosTfRPxQnP0T5To4nF/iUYrqUUUPuuEf6dgwzX87zSm/oSJjfB8M9Tx+CcPdXyiMysDCKCJUPRolPYalQnL/t0uQ1FI/yGsC6ka2mvUB3ItWHgJo3cidhHe+AVBKizugfTxmNMFo+pLdBaETPcaDVJhVH3sGIgdAwGg3Rr03oSVV+HyIJjj4gLuYELR9xqlaFQOnBnXir7/KuLF11RRNVjXUjUUjXqJm8fx29hwDRuv4VoxusdhUB0Mriv+nizeI7NotFxGB5ZdwZzzuGnBM03wfDPU0lV5EN5ivv2vv0W/+xEUoq5fkTCKRklZvMViWPJdyIhxfjcLgqJRseXbsCsTOzOx/hqitBhcF7MfRbdYr/QrepvMotFyhaoxtSmmNkVaHuaeR5MV6BWPqU3RMx6Vn9MUOr1SF+y6fUsVXcuLtUoJRaPkj3jeuHKRpkVr/3o0WIqiUVFcNeCTM+i9CQ8tw9zzaBaJw8NwdhRmP4Je8X45C0Km0aiQdtGY0wW/jUOveLx6CI2X48MTuGWt7Me5+MBKRykaJX9g+WmX9WRa5PN/gsovf3ymaLTaLE4cyMWGa1j3G1QK9E7AoDronSChbTA9FAjRqJCSG8SVVyt7g2jeuYV32IP7D/VRfaxRNErucmZcM+/dEfHia346C4Ki0aq7VoxN17HxGlJzkFwTA+pg2wA0iWBdlhcEQjQqpOQG8V+PYOElzDgAlQLTmmJiI0QI/FTAxSdaDuz1aYlMUTRK7uAtFsOSeSHD/fLRYCmKRiupwIa559FlPdqvwZGbeLoxMiZg9yC82kqesyACLBotV5QWL7XEudH4ojN+vomHlmLqT8grLy/l4hKcWRSNVl/g/szl3+48GkyS7Im7lUQn1FfM7saW61h0Gbsy0ScBryehb4Knpzr4i6SkJm63m3UV7CmArrHoGotbVnx4Aq1W4YvOeLzeH96jDI8A4C4qLHkhe3RCPQEAS+oeV1Fh2ITJrAvxFEWjQtLysPASlv+Kh8Mxqj7mdGG52xkTgRyNlqtmED5Kwcj6eGovll3BV53/8Fei5KZQExgTIUWjBM6Ma+Y928MmPOO/jwZLUTRaRkYxPjyBxsvxxG5EanFgKFKHYFaLgJsFQdGogJRaOD4c9cPQahV+/O3u17n4RGdmBrOyfIu6RgMdb7EUfDI7eNBwfw9FS1DXaIlCO9b/hkWXcfw2RjyEiQ3RWbT9hP1VIHeNVsbBXDy1F0k18HUXRGlhO3nMdvJo2KSprOvyBeoaDWwljwabt5LHLIiAj0btbmzLwMqr2HgdnWpjalMMqxcojwAfiKLRinWsjZMj8O4xtFqFrzpjQHyCaXOghCsUjQY0S+peV1FhyAD5rBYK2Gg0LQ+zDqLOEnx4Eu1q4vIYbOiHUfVpFryLotEH0nGY/QiW9cTLP2PyqZoui5k3m1gX5QvUNRq4nBnXzHu2+fWqwfsFWtfo9WIsu4J5F6FSYEwDHByK+mGsa5Iq6hqtpC4xODYcr/2iOKmKCzt945FHG7OuyOuoazRA3dlQ1M9XDd4vQKLRMo8Av+tKjwAfjKLRygvTYE4XnM1IXHroxjx74/+kSPdQEVFQNBqQeN64crGcHg2Wkn00euQWJu3BQ0ux9QZebomcJzCnC82ClULRaFU1aJT4cnSG1YU2q5EqZnAoORSNBiJL6l5XUUHYhKdZFyI+uUajdjd+/A1zz+OqEVOb4OMOgbj+wUMUjVYVF5+o3LdzwQRsycC4XRhQB//tgGA5fo8XPRqlO0KpK3k0KI9Vg/eTXzSaY8aHJ9BgGT45g6lNcXE0Xk+iWbA61GqO1k5UCVcrxl1wm3fY+yfi9CgAaL0K++V4a6jTaUVcOwGaCCXu90eDY2X2aLCUnKLRtDxM2oPmK3HViC39kToEo+r76xFIUkDRaJWpVKqatZ3ZmQAiNJjTBf/riHG7MOsgbC7WtYmKFtQHFsPCb5SRkSGDR7IuxFtksKDe5sL6a/j4NG5Z8GwTTG3qT6fASxktqK8G46olXHwdXYcupV+5ZcVz+3GhEPO7Ibkmw9LERAvqA4gldY9cHw2W8utoNNuMOefx1Tm0isLLLTH8Iagqf6w4eRDqGq0GLj7RmfWHjdZqBmFVb6y8isHb8GQjvJcMjf+nFNQ1GiicN66bd8v20WApP41GS1LQFiuRbcbewdgxEKPq0ywoMopGq4GLK3/H0VH1cWIELhai3Rocy/N9XSKjrtGAwFsshsXzZPxosJR/dY1aXVjxK/5zClYXnm+OLzvLfLUWW9Q1Wg1cXLzrZg5cLqhUZX6rtg5r+2DlVQzYgqca+/etIS2oDwjGlYs1zVpqWySxLsTr/CUavWrA3Av47gJa18D77TGoLuj2z9soGq0GhVqjjIh03srlYuLKfcOo+ugSg6n70X4NFnRHkn/+pE3RqPxZUve4CvODBwxjXYgvSD8aTc3B6J1ovxYWJ355HDsGYjDNgj5B0Wj1cHGJzszrFbwhRo/1ffHXtui7Ge+kweXrdkkRUNeozDlvXC/67suIF19VRUWzrsUXJNs1anRg2RV8dhZON6Y3w7NN5LkwWcqoa7R6zPt2uosKQ4Y8uNX8WjGe2YdiB+Z3QxO/OtCXukbljLdYDEtKHg0GxCwISUajVwz49gLmXUBKLXzcAT3j6f6PDYpGq4eLTzSfP12Zd9YNwY6B+OY8HluPV1rh1dZ+0/BF0aicGVct1jQNiEeDpSQVjf6ci0Fb0flHcAocH4EN/dCLZkF2KBqtHi4uwZl1A5WL+hTA1Kb4eRg2XUefTSh2eLs6cVDXqGxZDux1FeSHjZfzqsH7SaRrdG8W3j+Oqwa8kYTVvaEt23BHGKCu0epR6oMVQXpXfp6qRmXXzzcIw97BmLYfj2/Hxn5+8Pef9hqVJ2dmhnnX1rAnZL5q8H7Mo9HUHPTahGd+wuj6uDgGU5v6wXeBAEF7jVabOj7BmXWjSh9RKjCnC2oEYcwuOCX/4wftNSpDvN1uWPZ9yOARgfNosBTDaHRnJlLWYfp+TGqIi6MxtSmdDi8tFI1Wm9Cy+oopFVjUHXYXnvkJEu8kpa5RGTKuXAyeDx09kXUhDPi+a9TNY9N1vHcMdhdeaYUJDf2mQSDQUNdotdnPnbL8vD/8mReq8VmzE/02Iykan3YUvS7RiN41Sj8DM2Y7fdxx9XLI0FGsC2HDl9Gom8fKq2ixEm+n4c+tcWIkJjWiWVC6KBqtNi6+TjXuCEvoOWzoh9QcfHBc3KLERNGorLgLC4rXLg8d97RCK60lBD7jm2jU4cbCS2i6Ap+cwYeP4thwjKpP7aBSR9FotSnDI8DzbkNR9T4ersHW/lh0Gf+r1CoMBqhrVEZ43rB8gb5bb3WdeqxLYcbbXaN2N364gn8cQ209vuyMnvHeuxQRGXWNeqJkEYUmLLx6H6+lw44B6LIeEVo81Ujc0kRAe43Kh2nHZoWK03XpwboQlrwXjdpcWHAJ7x1D0wgs7oFHa3njIsSLaEG9J7j4RGdmhqZJ82qPkBiC7QPRYyNqBmFgHRFLEwEtqJcJx2+/Wg8fCB09EYqAjui8EY0WO/DJGdRfhg3XsK4PdgykWdAvUTTqCS6u7MGE1dAoHGv7YPI+/JQtSlGioWhUDniLxbhsQejwccrqBheyIW40anTgy7P46BS6x2HHQDSLFGtgwgBFo57g4hNMW3/0fJz2NfFDT4zaic390U4yy7toQb0cGNcs07RopWnWknUh7IkVjeZZ8U4aGizD2QKkDsGKXjQL+j3qGvWEKrqW22TiLWbPh+oeh28ew+CtOF/o+WDioK5Rv2f9JdWVmx3cfyjrQiTB82j0pgXvpKHpClw14OAwLOyOxn61jz4RQtGoRxQKLjbOmZUpymBD6uL/HkXfzbhWLMp4nqJo1L+5buaYtm6IeO5lBUdHmwOeRaPXi/GfU1h4CaMb4PgIJASLWxphjKJRD5U8JlQ3aCjKaE80RKEdvTdh/xDU1okyZPVR16gf451Ow9Lvg/sPVdWKYV2LVFQvGv3NiI9PY+kVjH8Y50YjVu+N0ghj1DXqIS4+0fHrJREHfLE5blrQdzP2DkYE09Caukb9mGnzWlWN6KBHJLxzkc9VNRq9UIhJe/DIWkRocHEMPulIs6BsUTTqoTvnMYnqvWR0jsGwbbA4xR24akSPRmki9BH7hbO2M6dCR4xnXYi0VD4azSjGM/vQdQOaRODKWLybjCiRfygk0pKU1CQlpRXrKvwYFxPrup3HO+ziDvtpRyQEY8wuONjl1kOGdIuLE3NRFE2EvuAuNhpXLQkbM0mhpwdZf1CZaLTAhjcOo80a1NTh4hi82QZh1EsYAKhr1FMqTlWrtisnS9xRlQos6A61Ek/thZvRKRXUNeqHeN64bL7u0c5iPbWWk4qjUbsbc8+j6QpkmXBqJGY/wvjJBPElikY9x8UlODNFTkcBqBRY3B2ZJsw4IPrYlUJdo/7HvG8n73Doe7I/h12ChKJRN4/V6Xj9FzQIw46BaBnl+9IIY9Q16jkuPtGRleGNPQx1HNb3Rc9N+PtRvJfshQtUiLpG/YzzxnXLT7siZrwGJd18l6PcaHRnJl49BD2HBd3RhRpsAxV1jXqOi0u0ph320uBhGmzpj8fWI0yDV337MJe6Rv0Jb7cbls0PGTJKFVmDdS0SVSYa/eUmum3AzAN4qw0ODqVZMKBRNOo5Li7elZMFl8tL40cHYcdAfHkW8y546Qrlo2jUnxSv/UFd/2FtUjvWhUhXaTR6oRB/P4pDN/HXNnimCZ2XSygaFYFCo1VGRDpv5XIxcV66RHwwtg9E1/UI02BUfS9dpCzaa9Rv2E4ec1xLDxk8gnUhkqZUKgv4oGn78dh6tIvGxdGY2pRmQQJQ16hIuHjxVxOW8XAYtgzAjAPY5t3r3EVdo/7BlZ9XvG552ITJCg0tdhNU7MDrqbYmS+2RWlwai9eToKOEgvyOolFRcHGJzkxPz2N6oFZRWNsHE3fjgJiBpSCKRv2B221cNl/fsx8Xn8i6FImyuzH/It5OQ+famsND7U3pvEByH4pGRcHFJ5p3b/XBhTrUxpIeGL4D2wegtZebIqhr1A+Ytm1UBOl0nbqxLkSK7l0XsW0AWkUpALppJuWgrlFRcPGJzswb4HkfnAHeOwFfdcbgbdg3GA+FevFC1DUqdY6rV6xph+jo+XLtzES7NfjvKczvhh0D0SrKKyfUE3mgaFQUSn2wIijIVXDbN5cb/hD+koTem5AtwkmIgigalTTeYjYuXxA6coIyNIx1LdJy+CZeP4xcM95N/kNrmbgn1BM5oWhULCWPCVVRPjpg/rlmyLehz2bsG+ytDYGpa1TSjCsWaVu11TRpzroQCblYiNE7MWIHxjXA6VFlG6zFOqGeyA91jYrFB42jZbzVBv0TMWALih1eGV9yXaPp6ZkvvfR/48a9/tFHC+z2O3/ojIycmTNnjx375//8Z6HT6a21nFJjObjPVVQY3G8w60KkIsuMafvRZT3a18SlMeWvi6BolAihaFQsvmkcLePDR9E8EiN3wO6Fu3rJHcM0Y8a/ZswYt3jxvxITYz788HsAPM9Pn/7+rFkTli6dHRsbPXv2PDHqlDpnbrZ5x+awcU9BRWkzrC788zhar7pzauBrrQXXRVA0SoTQMUxiUfv8jhCAApj7GILVmLhb/MEldwzT0KHdGzRIVKmUvXunpKdnAjhz5kpycrMGDRKVSuX48QPS0s7f/ymbzbFy5fb7f+3a9cuNG7kADAaTP724lmlc8p2y54BsGyRRD9MX36YVNl+JQ9nO9R3yPnwUKltFb87KuqXXBzGvmV5I8EVu7m2tVsO8DBm8KFZq3Xa722jw8dWzM3OX9sDZfPf8Y4Xijnz7dqFKpazgPVXl6UQ4ZcqdnVPefvurKVOGA0hPz2zYsG7pG8rtgbbb7StWbL//1/79x0r+GEVFRj96Yd22QRUTW1y3sUTqYfXiQiGG7uLeP6P7ohO+aJmnuJ31wE+dO/frd9+tk0Lx9EJqL3bs+HnfvqPMy5DHC0tYDWdmhu+vrlXh5fpF758JcvNijjx//vqMjJwK3lNVCp4X4WjFefPWZmff+utfpwJYs2aX3e4ozbtGj35txYp/3/vm9PTMHj2eTU/f4vl1pcB++YJx5eKol/4SyIfuFtjwThqWXcFbbfFCM3CV/vnK7XZbrXbqlyH3czicbreb+mVEYdq0VqHT63v0ZXL1DuvwciuMFm8nUovFptGoReyXEWGg1at3pqWde+utKSX/WLNmZG7u3TUr8m6A5i2W4lVLwkZPDNhZ0M1j4SU0XYECG86OxqwWVZgFQV2jRBh1jYqIi2fQL1PqvWT87Qic4k0FkusaXbNm19atBz7//C+K39ePt2vXbPfuwyU3mtevZ4eHh3hao4QZ1yzTtGyjfrgx60LY2JuFNqsx/xK2D8TC7qhZ9RmNukaJEOoaFREXl+jMYjYR9k5AXDAWXxFtQGktqD958uLEiW/279957NjXAYSE6L/77l29PmjixEGDB8/Q6YIcDudnn70hUqmSY0075MrJCh0zkXUhDNww4c3D2JuN95MxqVH1x6GuUSKEFtSLSFWzlru4mLdaFEE6JgW8n4wJuzGuAbQqEUaT1l6jrVs3Npl+uf/rI0f2HjmytycjS5+r4LZp49rwqTMVnJj/PaTP7MT/ncTnZ/Fic8x9DEGe/bWmaJQIob1GxaRQcDGxzqwb6voNmVy/UwyaRmLeRTzfTITRaK9RaeB544pF+u59uNh41qX41IZraL4S5wqQNhzvtPN0FgRFo0QYRaPi4uLrODN9vZrwXu+3xwfHYHaKMJS0otGAZd67HTyv69KDdSG+cywPsw7C7MSi7ugcI9qwFI0SIRSNiouLS3Cki/eYruraRSOlNr46h1c83iaB9hplz5mZYdm/J2zskwFyvsRtK2YdRP8tGFkfhx8XcxYERaNEGHWNiott42iJf7bHv0/CYPd0HMl1jQYa3ukwLl8YMmSkMiKKdS1e53DjkzNosgIALo3BrBblbBbqIYpGiRCKRsXFxcS6bufxTu9sg105jSPQOwGfnPF0HIpGGTNtXKuKjdcmJbMuxOt2ZuKlg4jVY99gNIv01lUoGiVCKBoVmYpTRdd0ZWdxiXUf/Gav+UcyHlmLF5p7dEITRaMs2S9fsJ07FTpsNOtCvOtyEQZvxfOpmP0odgz04iwIikaJMIpGRcfFs1xNWKJeKB5/CP8+6dEgFI0yw1vMxpVLwkZPVOj0rGvxlmIH3klDhx/RriZOj8SgOl6/IkWjRAhFo6Lj4hLZNo6WeLsdvr2AHA+OsKdolBnjmmVBrdvKeBOZZVfw6iEMqINzo1DLV4tuKRolQigaFR2XkGg7cYR1FYjTY2JD/PMEPu1YzRGktaA+cFiPHnLlZIeOmcS6EK/41YAXUpFjware6FDbp5emaJQIoQX1ouPiEpw5WXC7oWScBb7ZBk1W4OWWeCi0Oh+nBfUMuPJvmzatDR3/tPw2kXG48eEJPLIWKbVx5HFfz4KgaJQIo2hUdAqNVhkW4bpVnYOKxBUdhGlN8c/j1fw4RaM+V7KJTI++8ttEZl82ntuPBmE4PgJ1GG2NTtEoEULRqDdw8QmOzAxV7VjWheC11mj0A15thcYRVf4sdY36mnnPdoVSqevcnXUhYsq1YNIePLEb/2iPDf2YzYKgaJQIo65Rb+DiEp1Z7PtlAERopafYFgAAFQZJREFUMKsl3jtWnc9S16hPOTMzLKl7Qkc/IZtNZHhg4SUkrUakFudHY8RDjOuhaJQIoWjUG6Swv0ypl1pidxZO3n7wO8ugaNR3ft9EZpRsNpE5lY/p+6FSYMcAtJDGn4miUSKEolFv4OITnVk3wPNS+OE+mMOfW+OdNKztU7UPUjTqO6aNa7m4BG1SO9aFiMDsxDtp6L0JYxpg32CpzIKgaJQIo2jUG5TBIQqNxlWYz7qQO55rhrQ8/HKzap+iaNRH7JfO286dChk6inUhIig5O+mqAWdGYVYLKNn/IHgXRaNECEWjXsLFJUhhWX2JIBXeaoO/V/G/M0WjvuA2FRtXLg4b+6S/byKTacJLP+PkbXzzGHpJsumVolEihKJRLynZaE3bojXrQu6Y3Bj/Pom9WegWV9mPUDTqC8Vrlwe1aa9u0Ih1IdXndOOTM2izGs0jcXqkRGdBUDRKhFE06iVcnIT6ZQColXi7Hf5alZtCika9znrkZ1dutr7PQNaFVF9qDtqswfrfsH8I3mkHrcfnyHsPRaNECEWjXiKpxtES4x9GgQ1bK10URaPe5cq/bdq8LnzqTD/dRKbAhnfSsDod/2yPSf5wQ0vRKBFC0aiXqCKjeKfTXWxUhlRrfzMvUCnwXjL+egR9E1GZHgaKRr2pZBOZnv38cROZkgWCTVfA6sK5Uf4xC4KiUSKMolHv4eISJLKsvtTwh6BSYm16pd5M0agXmXdvU6hUuk7dWBdSZZeL0GcT/ncG6/tiTheE+c93D4pGiRCKRr2Hi0uQWjqqAN5ph78fhYt/8JtFj0ZpIrzDmZlhObA3dNQEKawzrTyLE++kofN6DKqLI4/jkVqsC6oiikaJkKSkJikprVhXIU9qCZzQe7/+iYgOwrIrD37nkCHd4uLE/GZHEyEA8A67Ydn3IUP9bBOZ3VloswZpt5A2HLNaQOVPM/gdFI0SIRSNeg8Xl+C8IbmJEMD77fG3o7A/6NEwRaNeYdq4Vp1QV9vabzaRybVg9E5M+wmfdcSGfkgIZl1QdVE0SoRQNOo9qpq13UYDb7WwLqSszjFoGI75Fx/wNopGxWe/dN52/rQfbSKz8BJar0LDcJwehd4JrKvxDEWjRAhFo16kVHIxcc7sTNZ1lOP9ZLx/HFZXRe8RPRoN9OUTv28i85RfbCKTZcbzqUg3YGM/JNdkXY0YKBolQuiEeq/i4hOcmTfUDz3MupCyHqmFNjXw9Tm81FLwPXRCvciK1y4PavOIukFD1oU8AA/MPY9Wq9AkAkeGy2QWBEWjRBhFo17FxUmxX6bEB+0x+wSMDsE30IJ6MVkPH3TdvhU27knWhTzAVQOm/ASLC/uHoGnVT3OWMopGiRBaUO9VXHyi5eA+1lWUr0UUusfhszN4s035b6AF9aJx5d82bfkxdMwkqKT700DJlqEp69AnQYazICgaJcKoa9SrVDFxrrybvFP4toup95Lx8WkU2Mr/XeoaFQnPG1cs1Pfsz8VUesNznzuTj07rsSYdB4bi9SS/XB3xQBSNEiEUjXqVguNU0bVcOdmsCylfw3AMqYv/ni7/dykaFYd5z3aFitN16sq6kPI53PjvKfz3NP6RjClNK7X5np+iaJQIoWjU27i4RGfWDS6hDutCyvd2O7RdgxnNUUtX9rcoGhWBKzfbkrpHspvInLiNR9dhfw7ShmOqrGdBUDRKhFE06m1cvOQ2WrtXnRCMa4APT5bzWxSNesztNixfGDxgmAQ3kbE48cZhDNiCl1pgoz8vk688ikaJEIpGvU3KjaMl3mqD+Rdxw1T26xSNesq0a4syNCwoOYV1IWWl5uDZn9AqCqdGIjpg7pEoGiVCKBr1Ni4uwZmdCbcbSoneEcXo8WwTfHAcX3X+w9cpGvWIM+uG9eBPocPHsS7kDwx2zDqIsbsw+xGs6BVAsyAoGiXCKBr1NkVQkDI03JV3k3UhFXkjCWvS8avhD1+kaLT6eKfT+MOCkCEjleESWoWwJQOtVqHAhtMjMawe62p8jqJRIoSiUR/QNGriNhoe/D52IrV4vhneO/aHL4oejSp4vhKnP4kqPT2zR49n09O3+Pi6pi3rnbnZ4U9N8/F1hRTY8MZh7MzE3C7o6X8nAYvD7XZbrXa6KST3czicbrebbgpJsQMNl2PXQDSLvPMVi8Wm0ahFvCkMlDtCZ2aG9ejPoSPHsy7kjg3X0GoVAJwcEbizICgaJcIoGiUlQtT4U0u8nXb3KxSNVsfvoegoZUgo61qQY8bIHfjLYazqjTldECLmE1//Q9EoEULRKCk1owUO5eLIrTv/SNFodZg2rXUVFoRNmOyzKwpZeRUzDuCpxni3HbQq1tVIAEWjRAhFo+ReX5zF5gxs6gd4IRqV//IJx7V067HDkS+/ybaMjGI88xMKbdgxEC0lt4KRGYpGiRA6honca0pTfHQKB3LQKYaOYaoi3mE3rlgYMmw021B04SUkr0X3OPw8jGbBP6BolAihaJTcS6PE39vir0cBikarqnj9St5sDh3L7KClmxZM349LRVjYHW2jWVUhXRSNEiEUjZIyXDxarsSnndApirpGK83x21Xb6RMhQ0ayKmDzdbRdg8QQpA2nWbB8FI0SIdQ1SspQKfB2O/zlMIKoa7SSeLvduHxhyLDRCj2DLTuL7Ji2HzMOYmkPfNKR+mIEUTRKhFA0Su43ugGcbry+5Li40ahsJ0LTpjXq+g9rm7f2/aV33Li7RvCxWN9f35/QXqNESFJSk5SUVqyrINKiAN5LxiZ1UkxsLRGHledE6Lhy0XbudMig4T6+bsnxEU/vw1edaY1gpVA0SoRQNErKNbguwrWK1dcoGq0Qb7UaVy4OHTFeodP78rqHbiJpNa4acGokBkj0qEvJoWiUCKFolAjpWXz0zUMup3hnk8iwa9S4agmUSl8eMeFw44PjmHseX3TG4/V8dlk5oK5RIoS6RokQi8U2cKfmiUaKyY3FGVBud4T2yxccVy6GDHzcZ1c8nY9H1uJMPk6OpFmwyigaJUIoGiVCdDrt7EcV76XB5hJnQFlNhLzVYly5JGT4OIXWF99bnW58eAI9N+K5ZljVGzXp+3nVUTRKhFA0SoQsX74t1pbTPArfXBBnQFlFo8blCxXaoJBho0Uf+X6/GvDUXug4fNcVCQwWaMgERaNECEWjREjJXqNni5T9N+PyWOg93oxPPneE9vNnHOlXggcM9faFeGDueaSsw8j62DaAZkGPUDRKhFA0SoSUHMPUKgodY/D5WREGlMlEyFssxrU/hI6eqNCIvBlrGdeK0XMj5l/CwaGY1QIKr14sAFA0SoRQNEqElO41+kF7/PcUDHZPB5RJNGpY+r0yLNzbCwdXXsXMg3ipBV5tDRXNgWKgaJQIoWiUCLn3GKYn9+KhULzTzqMB5XDQie3sKWdmRuSoJ7x3iVwLpu3HVQO29EdSDe9dJ+BQNEqE0DFMRMi9xzC92w7t1uCF5h61K/p9NOo2FRev/SF01ASF2lv7uKy8itar0CQCR4fTLCgyikaJEIpGiZB7j2GqF4rRDfDRSY8G9Pto1LB4nioq2ks9MoV2vP4L9mdjQXe0r+mNKwQ6ikaJEIpGiZAyJ9Rnm9FiJU6NRHx1Wxf9+47QduKoMydL32eANwbf9vve2UeH0yzoLRSNEiHUNUqE6P54DFOsHk81xuwT1R/QjydCt6m4eOOasDGTFJzIoajRgWn7MX0/FnTDnC4iLFIhQigaJUIoGiVC7j+h/i9JWPYr0o3VHNCPo1HDwm9UtWOC+w4WpapSB3Px5B50qI0vOiOUjo/wMopGiRCKRomQMtFoib8dRZYJ87pWZ0B/vdmxpv3iun0rbMLTIo5pd+Otw1j2K+Z2oeMjfISiUSKEukaJkHu7Rku90gqNfsDFQjSOqPKAfhmNug1Fpk1rQ0c9AZVo/6ukG9FtAy4bcHIEzYK+Q9EoEULRKBFyfzQKIEKDl1vhnbTqDOiX0WjRd1+q69TT9xKtR2bhJbxyCH9ti5m0WYxvUTRKhFA0SoSUG40CMDnR8Adsrvpqb/8LH6yHD7qNBn33vqKMZrDj+VQcy8POgWhNawR9jqJRIoSiUSKk3GgUQDCH15Pw9lH8WMX5wc+iUXdRoWnr+tAxk6BSeT7akVtotwZKBY4Op1mQDYpGiRCKRomQcqPREtOb4sRtHLpZtQH9Khrl+aLvvlTXb6jv3sfDGnjg0zP44Bg+74zR9T0cjFQfRaNECEWjRIhQNFrimwtY8St2DKzCgP50R2g5lOouNuof6+nhOLkW9N+Mdb/h2AiaBRmjaJQIoQX1REiZBfVlTG6MDBP2ZFVhQL+ZCF0Ft83bN4aOfdLDUPTH39B6FVJqY+dAOkqQPYpGiRCKRomQCqJRACoF/tYWfz1ShQH9JBrl+cK5n2ibttR5cDtodeH1X/Djb1jSA51iqj0MERNFo0QIRaNESMXRKAA3j7Zr8M/2lV0L5x93hJYD++B06jp3r/YI5wuRsg5ZZhwfQbOghFA0SoRQNEqEVByNAlAq8HY7/OUw3JW70fODidCVn2fevTV0zCQoq1ntwkt4bD2eboyVvRDp3RPsSdVQNEqEUDRKhFQcjZZ4vB50HNakV2pAyUejPF8453/aFm10nbtV41qFdkz7Cb8asLQnGoVXYwDiXRSNEiEUjRIhD4xGS2y7gZkHcHYUuAfdQ0n9jtD80y643bpO1dlIdW8WWq1CjB4Hh9EsKFEUjRIhFI0SIQ+MRkv0TUBcMJZeefCAkp4IXbdyLXt3hI6ZBEXVNj5zuvFOGsbvxted8UlHaCT9pwxoFI0SIRSNEiGViUZL/CMZb6fB7n7A2yS8iRHPG1cu0fcdpKpRtVNxrxVjwm7oOaQNR6zeS8URcUREhI4d2491FUSKkpKauN3/3969xUZRxXEc/7X0trrl4gVFIo0CilgiUm5ivaOhtS0pxQtVYkw0mnhBY4w8VBODPhB9IahRo0RQMIgKEigVpaggkVrxQuu1UlqCIqFSXNkWdnbXhyWV0D3LQroz053v52l39rR7Hv45/85vpnNOtoDBkyoqrs/JSWqTvOLzdekgLflZD45NNMy950rBzzYqK8s3pfiUfur9XZq6RuUjVFdCF+wHiEZhQjQKkySj0ZjnJ2vBDgWtRGNc2gjD+/d1bdk88Pa7kw9FuyzN26aaRtXO0FPjlckuEv0B0ShMiEZhknw0KqnoHE0eqld/TDTGlXeNRiIHX37RN6U4b/K0JH/nNwc0Z5OmDtUrxfKzrXz/wV2jMOGuUZgkeddoj+aDunGdWu5UvqE7uPGMMFhfl5nny5t0VTKDo9KiJpXU6tkiLbuBLtjPEI3ChGgUJqcUjUq6fIimD9eincYBrmuE1p97u778PP+2pELRfUHNqNWqXfp6luaMsmF26GNEozAhGoXJKUWjMc9O1KImBULxP3XZXaPhcGDVO2eWV2UOHnLSsbXtuu8L3T9GT084+f9Lwp24axQm3DUKk+TvGu0xaqBmX6xDR+Ono+5qhIc/rc0cOChvwuTEw46ENb9Bq1u1crqu4cGh/RnRKEzYoR4mph3qE3ulWKaY0UVnUtbePd0N2/KrqhMP+6VTV32ktoB2VNEF+z2iUZgQjcLkNKJRydgF5Z4zwqhlBVYu85fPzswfmGDYsl/1xFeqmaB5hbZNDSlENAoTolGYnEY0mphbGmFw47oBZ5+TO77INOCfo3pwq37oUH2Zxp1l59SQQkSjMCEahcnpRaMJuCIaDbW3djd+5TeHotv3a8KHys9WQyVdMK0QjcKEaBQmpxeNJuD831xRywqsWu6vvCPTn9/703BUL36vRU167RqVF9g/O6QW0ShMiEZhkobR6OENH2UNG5477sreH+35V3dvVlaGGmfpAh4cmo6IRmFCNAqTdItGQ227jnzX6J95W++PVu/WxNW64QJ9citdMG0RjcKEaBQmaRWNRkNHAyvf9lfekXmm//jjXZbmN2htm1bfomnnOTU72IFoFCZEozBJq2j08Po12QUX5xaOP/5g80HN2aQxg/VtlQbzoMF0RzQKE6JRmKRPNBr6/dcjzd/7K6p6jkSl13/STev05BV6bzpd0BOIRmFCNAqTPo9GnWmEvqzMwPvL86uqM3zHrv4d6NbMj/XGz9o6U3NHOzIpOODAgYNvvvmh07OAG23f3rRpU4PTs4AbrVhR29b2Rx/+Qmca4b1jBmePvCRnzOWxt/V/6MoPdFG+ts7UqEQPlkG6iUSiHR2HnJ4F3Ki7+0gw2OX0LOBGhw79a1l9ef3YmRS+NRDyl1VJsiJ67lu9/pOWXKcZFzoyFwCApznTCDe0BTLy8nYHdFe9/NnaMUvn8w8SAAAnOHazzKpdmrpGt49UXSldEADgmIxoNGrzV3Z2Bm4uebjxvKvVuFF7f7P52wEA3rR7d11BwbDexx1ohDFOfS8AwJsyMuJvSuhYIwQAwA1csQ0TAABOoRECADyNRggA8DQeawu7LV787pYtO2Kvn3nmgcLCUZL27Nn3wgtv7d//96RJhfPm3ZWVNcDROcJuS5euLSkpHjr0rNjbuPVAkXjTCbWRkgUkCthr9uwnTjgSiURKSx9qaWkPh8PLl69fsOA1RyYGRwSD3TU1Lw0fPr25+ffYkbj1QJF4UO/aiKZmAeGMEHYLhazNm7/u7AwUFV02YsQwSU1NLRMnjh058kJJ1dWllZWPOz1H2Kqs7NoBA/6/TBO3HigSbzqhNpSaBYRrhLBbS0v7zp2/dXV119S8tHTpWkmtrXtHjy7oGcBGdJ7i8+VOmTLu+CNx64Ei8aDetaHULCAUE+zW1HRs36Xq6tKKikfvuafCssJc70GPuPVAkSAmFQsIZ4RwUm5ujqRzzx3y118dPQcjkb7cYAX9Ttx6oEjQW18tIDRC2Grbtu8WLlwSe93R0WlZYUlFRWPr6xui0aik9vY/Bw3yOzlFOC1uPVAkUMoWEKJR2GratPF1dV9WVj6enZ1lWdbChY9JOuOMvLlzy8rLH/H58kIha/Hi+U5PE3bLzc3JyTm2HMWtB4rEs46vjRQtIDxrFADgaUSjAABPoxECADyNRggA8DQaIQDA02iEAABPoxECADyNRggA8DQaIQDA02iEAABPoxECADyNRggA8DQaIQDA02iEAABPoxECADyNRggA8DQaIQDA02iEAABP+w/X1Rry8TwQ1QAAAABJRU5ErkJggg=="},"metadata":{"image/png":{"height":480,"width":600}},"execution_count":null}],"cell_type":"code","source":["plot(x -> flight(x, tstar), 0, howfar(tstar))\nplot!(x -> flight(x, 45), 0, howfar(45))"],"metadata":{},"execution_count":null} +{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"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"},"metadata":{"image/png":{"height":480,"width":600}},"execution_count":1}],"cell_type":"code","source":["plot(x -> flight(x, tstar), 0, howfar(tstar))\nplot!(x -> flight(x, 45), 0, howfar(45))"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"

Use with other number types

","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}}, +{"cell_type":"markdown","source":"

The Unitful package provides a means to attach units to numeric values.

","metadata":{}}, +{"cell_type":"markdown","source":"

For example, a projectile motion with $v_0=10$ and $x_0=16$ could be represented with:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["y (generic function with 1 method)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["using Unitful\ns = u\"s\"; m = u\"m\"\ng = 9.8*m/s^2\nv0 = 10m/s\ny0 = 16m\ny(t) = -g*t^2 + v0*t + y0"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"

This motion starts at a height of 16 meters and has an initial velocity of 10 meters per second.

","metadata":{}}, +{"cell_type":"markdown","source":"

The time of touching the ground is found with:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["1.8860533706680143 s"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["a = find_zero(y, 1s, Order2())\na"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"

Automatic derivatives don't propogate through Unitful, so we define the approximate derivative–paying attention to units–with:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["Df (generic function with 2 methods)"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["Df(f, h=1e-6) = x -> (f(x + h*oneunit(x)) - f(x)) / (h*oneunit(x))"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"

And then the fact the peak is the only local maximum, it can be found from:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["0.5102035817418523 s"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["find_zero(Df(y), (0s, a), Bisection())"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"
","metadata":{}}, +{"cell_type":"markdown","source":"

The SymEngine package provides symbolic values to Julia. Rather than passing a function to find_zero, we can pass a symbolic expression:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["16 + 10*t - 9.8*t^2"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["using SymEngine\ng, v0, y0 = 9.8, 10, 16\n@vars t\nyt = -g * t^2 + v0 * t + y0"],"metadata":{},"execution_count":1}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["1.8860533706680143"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["a = find_zero(yt, 1, Order2())\na"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"

And the peak is determined to be at:

","metadata":{}}, +{"outputs":[{"output_type":"execute_result","data":{"text/plain":["0.510204081632653"]},"metadata":{},"execution_count":1}],"cell_type":"code","source":["find_zero(diff(yt, t), (0, a), Bisection())"],"metadata":{},"execution_count":1}, +{"cell_type":"markdown","source":"

(This also illustrates that symbolic values can be passed to describe the x-axis values.)

","metadata":{}} ], "metadata": { "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", "name": "julia", - "version": "0.4" + "version": "0.6" }, "kernelspec": { - "display_name": "Julia 0.4.0", + "display_name": "Julia 0.6.0", "language": "julia", - "name": "julia-0.4" + "name": "julia-0.6" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 2 } diff --git a/doc/roots.md b/doc/roots.md index 1d918ef1..41508298 100644 --- a/doc/roots.md +++ b/doc/roots.md @@ -3,14 +3,14 @@ The `Roots` package contains simple routines for finding zeros of continuous scalar functions of a single real variable. A zero of $f$ is a value $c$ where $f(c) = 0$. The basic interface is through the -function `fzero`, which through multiple dispatch and keyword -arguments can handle many different cases. +function `find_zero`, which through multiple dispatch can handle many different cases. We will use `Plots` for plotting. ``` using Roots using Plots +pyplot() ``` ## Bracketing @@ -38,11 +38,10 @@ plot(f, -2, 2) plot!([0,1], [0,0], linewidth=2) ``` -The basic function call specifies a bracket using either two values or -vector notation: +We use a vector or tuple to specify the initial condition for `Bisection`: ``` -x = fzero(f, 0, 1) # also fzero(f, [0, 1]) +x = find_zero(f, (0, 1), Bisection()) # alternatively fzero(f, [0, 1]) x, f(x) ``` @@ -51,11 +50,13 @@ For this function we see that `f(x) == 0.0`. ---- Next consider $f(x) = \sin(x)$. A known root is $\pi$. Trignometry -tells us that $[\pi/2, 3\pi/2]$ will be a bracket: +tells us that $[\pi/2, 3\pi/2]$ will be a bracket. Here `Bisection()` +is not specified, as it will be the default when the initial value is +specified as pair of numbers: ``` f(x) = sin(x) -x = fzero(f, pi/2, 3pi/2) +x = find_zero(f, (pi/2, 3pi/2)) x, f(x) ``` @@ -67,10 +68,20 @@ f(prevfloat(x)) * f(x) < 0.0 || f(x) * f(nextfloat(x)) < 0.0 That is, at `x` the function is changing sign. -The algorithm identifies discontinuities, not just zeros: +From a mathematical perspective, a zero is guaranteed for a +*continuous* function. However, the computer algorithm doesn't assume +continuity, it just looks for changes of sign. As such, the algorithm +will identify discontinuities, not just zeros. For example: ``` -fzero(x -> 1/x, -1, 1) +find_zero(x -> 1/x, (-1, 1)) +``` + + +The endpoints can even be infinite: + +``` +find_zero(x -> Inf*sign(x), (-Inf, Inf)) # Float64 only ``` @@ -78,17 +89,15 @@ The basic algorithm used for bracketing when the values are simple floating point values is the bisection method. For big float values, an algorithm due to Alefeld, Potra, and Shi is used. -The endpoints can even be infinite: - ``` -fzero(x -> Inf*sign(x), -Inf, Inf) # Float64 only +find_zero(sin, (big(3), big(4))) # uses a different algorithm then for (3,4) ``` ## Using an initial guess Bracketing methods have guaranteed convergence, but in general require many more function calls than are needed to produce an answer. If a -good initial guess is known, then the `fzero` function provides an +good initial guess is known, then the `find_zero` function provides an interface to some different iterative algorithms that are more efficient. Unlike bracketing methods, these algorithms may not converge to the desired root if the initial guess is not well chosen. @@ -96,7 +105,7 @@ converge to the desired root if the initial guess is not well chosen. The default algorithm is modeled after an algorithm used for [HP-34 calculators](http://www.hpl.hp.com/hpjournal/pdfs/IssuePDFs/1979-12.pdf). This algorithm is designed to be more forgiving of the quality of the -initial guess at the cost of possible performing many more steps. In +initial guess at the cost of possibly performing many more steps. In many cases it satisfies the criteria for a bracketing solution, as it will use bracketing if within the algorithm a bracket is identified. @@ -105,7 +114,7 @@ we can find the zero with: ``` f(x) = cos(x) - x -x = fzero(f , 1) +x = find_zero(f , 1) x, f(x) ``` @@ -113,14 +122,14 @@ For the polynomial $f(x) = x^3 - 2x - 5$, an initial guess of 2 seems reasonable ``` f(x) = x^3 - 2x - 5 -x = fzero(f, 2) +x = find_zero(f, 2) x, f(x), sign(f(prevfloat(x)) * f(nextfloat(x))) ``` For even more precision, `BigFloat` numbers can be used ``` -x = fzero(sin, big(3)) +x = find_zero(sin, big(3)) x, sin(x), x - pi ``` @@ -131,42 +140,41 @@ then possibly bracketing, which involves potentially many more function calls. Though specifying a initial value is more convenient than a bracket, there may be times where a more efficient algorithm is sought. For such, a higher-order method might be better -suited. There are algorithms of order 1 (secant method), 2 -([Steffensen](http://en.wikipedia.org/wiki/Steffensen's_method)), 5, -8, and 16. The order 2 method is generally more efficient, but is more +suited. There are algorithms `Order1` (secant method), `Order2` +([Steffensen](http://en.wikipedia.org/wiki/Steffensen's_method)), `Order5`, +`Order8`, and `Order16`. The order 2 method is generally more efficient, but is more sensitive to the initial guess than, say, the order 8 method. These -algorithms are accessed by specifying a value for the `order` -argument: +algorithms are accessed by specifying the method after the initial point: ``` f(x) = 2x - exp(-x) -x = fzero(f, 1, order=2) +x = find_zero(f, 1, Order2()) # also fzero(f, 1, order=2) x, f(x) ``` ``` f(x) = (x + 3) * (x - 1)^2 -x = fzero(f, -2, order=5) +x = find_zero(f, -2, Order5()) x, f(x) ``` ``` -x = fzero(f, 2, order=8) +x = find_zero(f, 2, Order8()) x, f(x) ``` The latter shows that zeros need not be simple zeros (i.e. $f'(x) = 0$, -if defined) to be found. +if defined) to be found. (Though non-simple zeros may take many more +steps to converge.) To investigate the algorithm and its convergence, the argument `verbose=true` may be specified. For some functions, adjusting the default tolerances may be necessary -to achieve convergence. These include `abstol` and `reltol`, which are -used to check if `norm(f(x)) <= max(abstol, norm(x)*reltol)`; -`xabstol`, `xreltol`, to check if `norm(x1-x0) <= max(xabstol, -norm(x1)*xreltol)`; and `maxevals` and `maxfnevals` to limit the +to achieve convergence. These include `atol` and `rtol`, which are +used to check if $f(x_n) \approx 0$; +`xatol`, `xrtol`, to check if $x_n \approx x_{n-1}$; and `maxevals` and `maxfnevals` to limit the number of steps in the algorithm or function calls. @@ -189,13 +197,13 @@ the issue, we have $f(x) = x^{1/3}$: ``` f(x) = cbrt(x) -x = fzero(f, 1, order=2) # all of 2, 5, 8, and 16 fail or diverge towards infinity +x = find_zero(f, 1, Order2()) # all of 2, 5, 8, and 16 fail or diverge towards infinity ``` However, the default finds the root here, as a bracket is identified: ``` -x = fzero(f, 1) +x = find_zero(f, 1) x, f(x) ``` @@ -203,16 +211,16 @@ Order 8 illustrates that sometimes the stopping rules can be misleading and checking the returned value is always a good idea: ``` -fzero(f, 1, order=8) +find_zero(f, 1, Order8()) ``` The algorithm rapidly marches off towards infinity so the relative -tolerance $|x| \cdot +tolerance $\approx |x| \cdot \epsilon$ is large compared to the far-from zero $f(x)$. ---- -This example illustrates that the default `fzero` +This example illustrates that the default `find_zero` call is more forgiving to an initial guess. The devilish function defined below comes from a [test suite](http://people.sc.fsu.edu/~jburkardt/cpp_src/test_zero/test_zero.html) @@ -224,13 +232,13 @@ plot(f, -2, 2) ``` ``` -fzero(f, 0) +find_zero(f, 0) ``` -Whereas, with `order=n` methods fail. For example, +Whereas, with higher order methods fail. For example, ``` -fzero(f, 0, order=8) +find_zero(f, 0, Order8()) ``` Basically the high order oscillation can send the proxy tangent line @@ -247,13 +255,13 @@ happen, but it isn't guaranteed: ``` f(x) = x^5 - x - 1 x0 = 0.1 -fzero(f, x0) +find_zero(f, x0) ``` Whereas, ``` -fzero(f, x0, order=2) +find_zero(f, x0, Order2()) ``` A graph shows the issue. We have overlayed a 15 steps of Newton's @@ -280,13 +288,13 @@ always work. The bracketing methods suggest a simple algorithm to recover multiple zeros: partition an interval into many small sub-intervals. For those -that bracket a root find the root. This is essentially implemented with `fzeros(f, +that bracket a root find the root. This is essentially implemented with `find_zeros(f, a, b)`. The algorithm has problems with non-simple zeros (in particular ones that don't change sign at the zero) and zeros which bunch together. Simple usage is often succesful enough, but a graph should be used to assess if all the zeros are found: ``` -fzeros(x -> exp(x) - x^4, -10, 10) +find_zeros(x -> exp(x) - x^4, -10, 10) ``` @@ -350,7 +358,7 @@ point of the function $f(x) = 1/x^2 + x^3, x > 0$ near $1.0$ can be found with: ``` f(x) = 1/x^2 + x^3 -fzero(D(f), 1) +find_zero(D(f), 1) ``` For more complicated expressions, `D` will not work. In this example, @@ -376,7 +384,7 @@ so we start our search at `a-5`: ``` function howfar(theta) a = 200*cosd(theta) - fzero(x -> flight(x, theta), a-5) + find_zero(x -> flight(x, theta), a-5) end ``` @@ -398,7 +406,7 @@ non-windy day: ``` h = 1e-5 howfarp(theta) = (howfar(theta+h) - howfar(theta-h)) / (2h) -tstar = fzero(howfarp, 45) +tstar = find_zero(howfarp, 45) ``` This shows the differences in the trajectories: @@ -408,3 +416,71 @@ plot(x -> flight(x, tstar), 0, howfar(tstar)) plot!(x -> flight(x, 45), 0, howfar(45)) ``` + + +# Use with other number types + + +The `Unitful` package provides a means to attach units to numeric +values. + +For example, a projectile motion with $v_0=10$ and $x_0=16$ could be +represented with: + +``` +using Unitful +s = u"s"; m = u"m" +g = 9.8*m/s^2 +v0 = 10m/s +y0 = 16m +y(t) = -g*t^2 + v0*t + y0 +``` + +This motion starts at a height of 16 meters and has an initial +velocity of 10 meters per second. + +The time of touching the ground is found with: + +``` +a = find_zero(y, 1s, Order2()) +a +``` + +Automatic derivatives don't propogate through `Unitful`, so we define +the approximate derivative--paying attention to units--with: + +``` +Df(f, h=1e-6) = x -> (f(x + h*oneunit(x)) - f(x)) / (h*oneunit(x)) +``` + +And then the fact the peak is the only local maximum, it can be found from: + +``` +find_zero(Df(y), (0s, a), Bisection()) +``` + +---- + +The `SymEngine` package provides symbolic values to `Julia`. Rather +than passing a function to `find_zero`, we can pass a symbolic expression: + +``` +using SymEngine +g, v0, y0 = 9.8, 10, 16 +@vars t +yt = -g * t^2 + v0 * t + y0 +``` + +``` +a = find_zero(yt, 1, Order2()) +a +``` + +And the peak is determined to be at: + +``` +find_zero(diff(yt, t), (0, a), Bisection()) +``` + +(This also illustrates that symbolic values can be passed to describe +the `x`-axis values.) diff --git a/src/Roots.jl b/src/Roots.jl index 2220874a..59e1e54c 100644 --- a/src/Roots.jl +++ b/src/Roots.jl @@ -9,7 +9,7 @@ else end using ForwardDiff -using Compat: @nospecialize +using Compat: @nospecialize, lastindex export fzero, @@ -18,145 +18,18 @@ export fzero, secant_method, steffensen, D -export find_zero, +export find_zero, find_zeros, Order0, Order1, Order2, Order5, Order8, Order16 export Bisection, FalsePosition ## load in files include("adiff.jl") +include("utils.jl") include("find_zero.jl") include("bracketing.jl") include("derivative_free.jl") include("newton.jl") - - -## Main functions are -## * fzero(f, ...) to find _a_ zero of f -## * fzeros(f, ...) to attempt to find all zeros of f - - - -""" - -Find zero of a function using an iterative algorithm - -* `f`: a scalar function or callable object -* `x0`: an initial guess, finite valued. - -Keyword arguments: - -* `ftol`: tolerance for a guess `abs(f(x)) < ftol` -* `xtol`: stop if `abs(xold - xnew) <= xtol + max(1, |xnew|)*xtolrel` -* `xtolrel`: see `xtol` -* `maxeval`: maximum number of steps -* `verbose`: Boolean. Set `true` to trace algorithm -* `order`: Can specify order of algorithm. 0 is most robust, also 1, 2, 5, 8, 16. -* `kwargs...` passed on to different algorithms. There are `maxfneval` when `order` is 1,2,5,8, or 16 and `beta` for orders 2,5,8,16, - -This is a polyalgorithm redirecting different algorithms based on the value of `order`. - -""" -function fzero(f, x0::Real; kwargs...) - x = float(x0) - isinf(x) && throw(ConvergenceFailed("An initial value must be finite")) - derivative_free(f, x; kwargs...) -end - - - -""" -Find zero of a function within a bracket - -Uses a modified bisection method for non `big` arguments - -Arguments: - -* `f` A scalar function or callable object -* `a` left endpont of interval -* `b` right endpont of interval -* `xtol` optional additional tolerance on sub-bracket size. - -For a bracket to be valid, it must be that `f(a)*f(b) < 0`. - -For `Float64` values, the answer is such that `f(prevfloat(x)) * -f(nextfloat(x)) < 0` unless a non-zero value of `xtol` is specified in -which case, it stops when the sub-bracketing produces an bracket with -length less than `max(xtol, abs(x1)*xtolrel)`. - -For `Big` values, which defaults to the algorithm of Alefeld, Potra, and Shi, a -default tolerance is used for the sub-bracket length that can be enlarged with `xtol`. - -If `a==-Inf` it is replaced with `nextfloat(a)`; if `b==Inf` it is replaced with `prevfloat(b)`. - -Example: - - `fzero(sin, 3, 4)` # find pi - `fzero(sin, [big(3), 4]) find pi with more digits -""" -function fzero(f, a::Real, b::Real; kwargs...) - bracket = adjust_bracket((a, b)) - a0, b0 = a < b ? promote(float(a), b) : promote(float(b), a) - (a0 == -Inf) && (a0 = nextfloat(a0)) - (b0 == Inf) && (b0 = prevfloat(b0)) - find_zero(f, bracket, Bisection(); kwargs...) -end - -""" -Find a zero with bracket specified via `[a,b]`, as `fzero(sin, [3,4])`. -""" -function fzero(f, bracket::Vector{T}; kwargs...) where {T <: Real} - fzero(f, float(bracket[1]), float(bracket[2]); kwargs...) -end - - -""" -Find a zero within a bracket with an initial guess to *possibly* speed things along. -""" -function fzero(f, x0::Real, bracket::Vector{T}; kwargs...) where {T <: Real} - - a, b = adjust_bracket(bracket) - - try - ex = a42a(f, a, b, float(x0); kwargs...) - catch ex - if isa(ex, StateConverged) - return(ex.x0) - else - rethrow(ex) - end - end -end - - -""" -Find zero using Newton's method. -""" -fzero(f::Function, fp::Function, x0::Real; kwargs...) = newton(f, fp, float(x0); kwargs...) - - - -## fzeros -""" - -`fzeros(f, a, b)` - -Attempt to find all zeros of `f` within an interval `[a,b]`. - -Simple algorithm that splits `[a,b]` into subintervals and checks each -for a root. For bracketing subintervals, bisection is -used. Otherwise, a derivative-free method is used. If there are a -large number of zeros found relative to the number of subintervals, the -number of subintervals is increased and the process is re-run. - -There are possible issues with close-by zeros and zeros which do not -cross the origin (non-simple zeros). Answers should be confirmed -graphically, if possible. - -""" -function fzeros(f, a::Real, b::Real; kwargs...) - find_zeros(f, float(a), float(b); kwargs...) -end -fzeros(f, bracket::Vector{T}; kwargs...) where {T <: Real} = fzeros(f, a, b; kwargs...) +include("fzero.jl") diff --git a/src/adiff.jl b/src/adiff.jl index f80e33ac..daa2b2f9 100644 --- a/src/adiff.jl +++ b/src/adiff.jl @@ -19,7 +19,6 @@ function D(f::Function, k::Int=1) D(x -> ForwardDiff.derivative(f, x), k-1) end -D2(f::Function) = D(f, 2) ## This conflicts with a definition in Calculus, but is more convenient. ## Base.ctranspose(f::Function) = x -> ForwardDiff.derivative(f, x) diff --git a/src/bracketing.jl b/src/bracketing.jl index 051a5d49..81640c61 100644 --- a/src/bracketing.jl +++ b/src/bracketing.jl @@ -1,16 +1,7 @@ ### -# type to throw on succesful convergence -mutable struct StateConverged - x0::Real -end - -# type to throw on failure -mutable struct ConvergenceFailed - reason::AbstractString -end -bracketing_error = """The interval [a,b] is not a bracketing interval. +const bracketing_error = """The interval [a,b] is not a bracketing interval. You need f(a) and f(b) to have different signs (f(a) * f(b) < 0). Consider a different bracket or try fzero(f, c) with an initial guess c. @@ -24,9 +15,9 @@ Consider a different bracket or try fzero(f, c) with an initial guess c. ## cf. http://squishythinking.com/2014/02/22/bisecting-floats/ # Alternative "mean" definition that operates on the binary representation # of a float. Using this definition, bisection will never take more than -# 64 steps. +# 64 steps (over Float64) const FloatNN = Union{Float64, Float32, Float16} -_float_int_pairs = Dict(Float64 => UInt64, Float32 => UInt32, Float16 => UInt16) +const _float_int_pairs = Dict(Float64 => UInt64, Float32 => UInt32, Float16 => UInt16) function _middle(x::T, y::T) where {T <: FloatNN} # Use the usual float rules for combining non-finite numbers @@ -34,7 +25,7 @@ function _middle(x::T, y::T) where {T <: FloatNN} return x + y end # Always return 0.0 when inputs have opposite sign - if sign(x) != sign(y) && !iszero(x) && ! iszero(y) + if sign(x) != sign(y) && !iszero(x) && !iszero(y) return zero(T) end @@ -52,7 +43,7 @@ function _middle(x::T, y::T) where {T <: FloatNN} end ## fall back or non Floats -function _middle(x::Real, y::Real) +function _middle(x::Number, y::Number) x + (y-x)/2 end @@ -127,18 +118,21 @@ end Bisection() -Use the bisection method over `Float64` values. The bisection method -starts with a bracketing interval `[a,b]` and splits it into two -intervals `[a,c]` and `[c,b]`, If `c` is not a zero, then one of these -two will be a bracketing interval and the process continues. The -computation of `c` is done by `_middle`, which reinterprets floating -point values as unsigned 64-bit integers and splits there. This method -avoids floating point issues and guarantees a "best" solution (one -where a zero is found or the bracketing interval is of the type `[a, -nextfloat(a)]`). +If possible, will use the bisection method over `Float64` values. The +bisection method starts with a bracketing interval `[a,b]` and splits +it into two intervals `[a,c]` and `[c,b]`, If `c` is not a zero, then +one of these two will be a bracketing interval and the process +continues. The computation of `c` is done by `_middle`, which +reinterprets floating point values as unsigned integers and splits +there. This method avoids floating point issues and guarantees a +"best" solution (one where a zero is found or the bracketing interval +is of the type `[a, nextfloat(a)]`). + +When this is not possible, will default to `A42` method. """ mutable struct Bisection <: AbstractBisection end +mutable struct Bisection64 <: AbstractBisection end """ Roots.A42() @@ -152,83 +146,139 @@ Trans. Math. Softw. 21, 327–344 (1995). mutable struct A42 <: AbstractBisection end -function find_zero(f, x0::Vector{T}, method::AbstractBisection; kwargs...) where {T <: Real} +function init_options(::M, + state; + xatol=missing, + xrtol=missing, + atol=missing, + rtol=missing, + maxevals::Int=typemax(Int), + maxfnevals::Int=typemax(Int), + verbose::Bool=false, + kwargs...) where {M <: Union{Bisection64, A42}} + + ## Where we set defaults + x1 = real(oneunit(state.xn1)) + fx1 = real(oneunit(float(state.fxn1))) + + ## map old tol names to new + ## deprecate in future + xatol, xrtol, atol, rtol = _map_tolerance_arguments(Dict(kwargs), xatol, xrtol, atol, rtol) - find_zero(f, (x0[1], x0[2]), method; kwargs...) + # all are 0 by default + options = UnivariateZeroOptions(ismissing(xatol) ? zero(x1) : xatol, # unit of x + ismissing(xrtol) ? zero(x1/oneunit(x1)) : xrtol, # unitless + ismissing(atol) ? zero(fx1) : atol, # units of f(x) + ismissing(rtol) ? zero(fx1/oneunit(fx1)) : rtol, # unitless + maxevals, maxfnevals, + verbose) + + options end -## For speed, bypass find_zero setup for bisection+Float64 -function find_zero(f, x0::Tuple{T,S}, method::Bisection; verbose=false, kwargs...) where {T <: FloatNN, S <: FloatNN} - x = adjust_bracket(x0) - if verbose - prob, options = derivative_free_setup(method, DerivativeFree(f), x; verbose=verbose, kwargs...) - find_zero(prob, method, options) +## we dispatch to either floating-point-bisection or A42 here. +function find_zero(fs, x0, method::AbstractBisection; kwargs...) + + x = float.(x0) + F = callable_function(fs) + state = init_state(method, F, x) + options = init_options(method, state; kwargs...) + + # we try a faster alternative for floating point values based on verboseness + isa(method, A42) && return find_zero(method, F, options, state) + isa(method, FalsePosition) && return find_zero(method, F, options, state) + + T = eltype(state.xn1) + if T <: FloatNN + if options.verbose + find_zero(Bisection64(), F, options, state) + else + x0, x1 = state.xn0, state.xn1 + state.xn1 = bisection64(F, x0, x1) + state.message = "Used bisection to find the zero, steps not counted." + state.stopped = state.x_converged = true + return state.xn1 + end else - bisection64(f, x[1], x[2])::eltype(x) + find_zero(A42(), F, options, state) end + end +function find_zero(method::A42, F, options::UnivariateZeroOptions, state::UnivariateZeroState{T,S}) where {T<:Number, S<:Number} + x0, x1 = state.xn0, state.xn1 + state.xn1 = a42(F, x0, x1; xtol=options.xabstol, maxeval=options.maxevals, + verbose=options.verbose) + state.message = "Used Alefeld-Potra-Shi method, `Roots.a42`, to find the zero. Iterations and function evaluations are not counted properly." + state.stopped = state.x_converged = true + + options.verbose && show_trace(state, [state.xn1], [state.fxn1], method) + return state.xn1 +end -## This is a bit clunky, as we use `a42` for bisection when we don't have `Float64` values. -## As we don't have the `A42` algorithm implemented through `find_zero`, we adjust here. -function find_zero(f, x0::Tuple{T,S}, method::M; kwargs...) where {M <: Union{Bisection, A42}, T <: Real, S <: Real} - - x = adjust_bracket(x0) - ## round about way to get options and state - prob, options = derivative_free_setup(method, DerivativeFree(f), x[1]; kwargs...) - o = init_state(method, prob.fs, prob.x0, prob.bracket) - o.xn1 = a42(f, x[1], x[2]; xtol=options.xreltol, maxeval=options.maxevals, verbose=options.verbose) - o.message = "Used Alefeld-Potra-Shi method, `Roots.a42`, to find the zero. Iterations and function evaluations are not counted properly." - o.stopped = o.x_converged = true +## in Order0, we run bisection if a bracketing interval is found +## this is meant to be as speedy as possible +function _run_bisection(fs, options, state::UnivariateZeroState{T,S}) where {T<:FloatNN, S<:Number} + xn0, xn1 = state.xn0, state.xn1 + state.xn1 = bisection64(fs, xn0, xn1) + state.x_converged = true + state.message = "Used Bisection() for last step, steps not counted" +end - options.verbose && show_trace(prob.fs, o, [o.xn1], [o.fxn1], method) - o.xn1 +function _run_bisection(fs, options, state::UnivariateZeroState{T,S}) where {T<:Number, S<:Number} + state.xn1 = find_zero(A42(), fs, options, state) + state.x_converged = true + state.message = "Used A42() for last step, steps not counted" end -# this is hacky. -# we reach here from calling Bisection midway through the Order0() routine with "big" values. -# call a42 in this case -const BigSomething = Union{BigFloat, BigInt} -function find_zero(method::Bisection, fs, o::UnivariateZeroState{T, S}, options::UnivariateZeroOptions) where {T<:BigSomething, S} - xn0, xn1 = o.xn0 < o.xn1 ? (o.xn0, o.xn1) : (o.xn1, o.xn0) - o.xn1 = a42(fs, o.xn0, o.xn1; xtol=options.xreltol, maxeval=options.maxevals, verbose=options.verbose) - o.message = "Used Alefeld-Potra-Shi method, `Roots.a42`, to find the zero. Iterations and function evaluations are not counted properly." - o.stopped = o.x_converged = true +# ## helper function +function adjust_bracket(x0) + u, v = float.(promote(x0...)) + if u > v + u, v = v, u + end - nothing + + if isinf(u) + u = nextfloat(u) + end + if isinf(v) + v = prevfloat(v) + end + u, v end -function init_state(method::AbstractBisection, fs, x::Union{Tuple{T,T}, Vector{T}}, bracket) where {T <: Real} + +function init_state(method::AbstractBisection, fs, x) + length(x) > 1 || throw(ArgumentError(bracketing_error)) + x0, x2 = adjust_bracket(x) - y0 = fs(x0) - y2 = fs(x2) + y0, y2 = promote(fs(x0), fs(x2)) sign(y0) * sign(y2) > 0 && throw(ArgumentError(bracketing_error)) - state = UnivariateZeroStateBase(x0, x2, - y0, y2, - ismissing(bracket) ? bracket : float.(bracket), - 0, 2, - false, false, false, false, - "") + state = UnivariateZeroState(x0, x2, + y0, y2, + 0, 2, + false, false, false, false, + "") state end -## This uses _middle bisection -## Find zero using modified bisection method for Float64 arguments. -## This is guaranteed to take no more than 64 steps. The `a42` alternative usually has -## fewer iterations, but this seems to find the value with fewer function evaluations. +## This uses _middle bisection Find zero using modified bisection +## method for FloatXX arguments. This is guaranteed to take no more +## steps the bits of the type. The `a42` alternative usually has fewer +## iterations, but this seems to find the value with fewer function +## evaluations. ## -## Terminates with `x1` when the bracket length of `[x0,x2]` is `<= max(xtol, xtolrel*abs(x1))` where `x1` is the midpoint . -## The tolerances can be set to 0, in which case, the termination occurs when `nextfloat(x0) = x2`. -## The bracket `[a,b]` must be bounded. +## This terminates when there is no more subdivision or function is zero -function update_state(method::Bisection, fs, o::Roots.UnivariateZeroState{T,S}, options::UnivariateZeroOptions) where {T<:FloatNN,S} +function update_state(method::Union{Bisection,Bisection64}, fs, o::UnivariateZeroState{T,S}, options::UnivariateZeroOptions) where {T<:Number,S<:Number} x0, x2 = o.xn0, o.xn1 y0, y2 = o.fxn0, o.fxn1 @@ -251,8 +301,10 @@ function update_state(method::Bisection, fs, o::Roots.UnivariateZeroState{T,S}, nothing end -## convergence is much differen there, as we bound between x0, nextfloat(x0) is not measured by eps(), but eps(x0) -function assess_convergence(method::Bisection, fs, state, options) +## convergence is much different here +## the method converges, +## as we bound between x0, nextfloat(x0) is not measured by eps(), but eps(x0) +function assess_convergence(method::Union{Bisection64,Bisection}, state, options) x0, x2 = state.xn0, state.xn1 if x0 > x2 x0, x2 = x2, x0 @@ -261,10 +313,17 @@ function assess_convergence(method::Bisection, fs, state, options) x1 = _middle(x0, x2) if iszero(state.fxn1) state.message = "" - state.stopped = state.x_converged = true + state.stopped = state.f_converged = true return true end - x0 < x1 && x1 < x2 && return false + + x0 == x1 || x1 == x2 && return true + d1 = isapprox(x0, x1, atol=options.xabstol, rtol=options.xreltol) + d2 = isapprox(x1, x2, atol=options.xabstol, rtol=options.xreltol) + !d1 && !d2 && return false + +# x0 < x1 && x1 < x2 && return false + state.message = "" state.stopped = state.x_converged = true @@ -312,12 +371,12 @@ function a42(f, a, b; if a >= b || sign(fa)*sign(fb) >= 0 error("on input a < b and f(a)f(b) < 0 must both hold") end - if xtol < 0.0 + if xtol/oneunit(xtol) < 0.0 error("tolerance must be >= 0.0") end - + c, fc = secant(f, a, fa, b, fb) - a42a(f, a, fa, b, fb, c, fc, + a42a(f, float(a), fa, float(b), fb, float(c), fc, xtol=xtol, maxeval=maxeval, verbose=verbose) end @@ -365,7 +424,11 @@ function a42a(f, a, fa, b, fb, c, fc; u, fu = bb, fbb end # u = abs(fab) < abs(fbb) ? ab : bb - cb = u - 2*fu/(fbb - fab)*(bb - ab) +# cb = u - 2*fu/(fbb - fab)*(bb - ab) + del = 2*fu/(fbb - fab)*(bb - ab) + if !isnan(del) # add check on NaN + cb = u - del + end fcb = f(cb) if abs(cb - u) > (bb - ab)/2 ch, fch = ab+(bb-ab)/2, f(ab+(bb-ab)/2) @@ -388,10 +451,10 @@ function a42a(f, a, fa, b, fb, c, fc; verbose && println(@sprintf("a=%18.15f, n=%s", float(a), n)) - if nextfloat(ch) * prevfloat(ch) <= 0 + if nextfloat(float(ch)) * prevfloat(float(ch)) <= 0 * oneunit(ch)^2 throw(StateConverged(ch)) end - if nextfloat(a) >= b + if nextfloat(float(a)) >= b throw(StateConverged(a)) end end @@ -411,9 +474,9 @@ end # calculate a scaled tolerance # based on algorithm on page 340 of [1] function tole(a::S, b::R, fa, fb, tol) where {S,R} - T = promote_type(S,R) u = abs(fa) < abs(fb) ? abs(a) : abs(b) - 2u*eps(T) + tol + T = promote_type(S,R) + 2u*eps(T)/oneunit(T) + tol end @@ -436,7 +499,7 @@ end # # based on algorithm on page 341 of [1] function bracket(f, a, fa, b, fb, c, fc, tol) - + if !(a <= c <= b) error("c must be in (a,b)") end @@ -453,7 +516,7 @@ function bracket(f, a, fa, b, fb, c, fc, tol) end if fc == 0 throw(Roots.StateConverged(c)) - elseif sign(fa)*sign(fc) < 0 + elseif sign(fa)*sign(fc) < 0 aa, faa = a, fa bb, fbb = c, fc db, fdb = b, fb @@ -475,7 +538,7 @@ end function secant(f, a::T, fa, b, fb) where {T} c = a - fa/(fb - fa)*(b - a) - tol = eps(T)*5 + tol = 5*eps(T)/oneunit(T) if isnan(c) || c <= a + abs(a)*tol || c >= b - abs(b)*tol return a + (b - a)/2, f(a+(b-a)/2) end @@ -492,7 +555,8 @@ function newton_quadratic(f, a, fa, b, fb, d, fd, k::Int) if A == 0 return secant(f, a, fa, b, fb) end - r = A*fa > 0 ? a : b + + r = A*fa/oneunit(A*fa) > 0 ? a : b for i = 1:k r -= (fa + (B + A*(r - b))*(r - a))/(B + A*(2*r - a - b)) end @@ -529,7 +593,7 @@ end # floating point comparison function function almost_equal(x::T, y::T) where {T} - const min_diff = realmin(T)*32 + min_diff = oneunit(x) * realmin(float(x/oneunit(x)))*32 abs(x - y) < min_diff end @@ -573,7 +637,7 @@ Examples find_zero(x -> x^5 - x - 1, [-2, 2], FalsePosition()) ``` """ -mutable struct FalsePosition <: AbstractBisection +struct FalsePosition <: AbstractBisection reduction_factor::Union{Int, Symbol} FalsePosition(x=:anderson_bjork) = new(x) end @@ -587,7 +651,7 @@ function update_state(method::FalsePosition, fs, o, options) lambda = fb / (fb - fa) tau = 1e-10 # some engineering to avoid short moves - if !(tau < norm(lambda) < 1-tau) + if !(tau < abs(lambda) < 1-tau) lambda = 1/2 end x = b - lambda * (b-a) @@ -627,35 +691,13 @@ galdino = Dict{Union{Int,Symbol},Function}(:1 => (fa, fb, fx) -> fa*fb/(fb+fx), :9 => (fa, fb, fx) -> fa/(1 + fx/fb)^2, :10 => (fa, fb, fx) -> (fa-fx)/4, :11 => (fa, fb, fx) -> fx*fa/(fb+fx), - :12 => (fa, fb, fx) -> (fa * (1-fx/fb > 0 ? 1-fx/fb : 1/2)) + :12 => (fa, fb, fx) -> (fa * (1-fx/fb > 0 ? 1-fx/fb : 1/2)) ) # give common names for (nm, i) in [(:pegasus, 1), (:illinois, 8), (:anderson_bjork, 12)] galdino[nm] = galdino[i] end -function find_zero(f, x0::Tuple{T,S}, method::FalsePosition; kwargs...) where {T<:Real,S<:Real} - x = adjust_bracket(x0) - prob, options = derivative_free_setup(method, DerivativeFree(f), x; kwargs...) - find_zero(prob, method, options) -end -## helper function -function adjust_bracket(x0) - u, v = float.(x0) - if u > v - u, v = v, u - end - - - if isinf(u) - u = nextfloat(u) - end - if isinf(v) - v = prevfloat(v) - end - u, v -end - ## -------------------------------------- """ diff --git a/src/derivative_free.jl b/src/derivative_free.jl index 99fec718..98bf0c37 100644 --- a/src/derivative_free.jl +++ b/src/derivative_free.jl @@ -1,71 +1,5 @@ # Many derivative free methods of different orders -################################################## -## Helpers for the various methods -## issue with approx derivative -isissue(x) = (x == 0.0) || isnan(x) || isinf(x) - - -""" -heuristic to get a decent first step with Steffensen steps -""" -function steff_step(x::T, fx) where {T} - thresh = max(1, norm(x)) * sqrt(eps(T)) # max(1, sqrt(abs(x/fx))) * 1e-6 - norm(fx) <= thresh ? fx : sign(fx) * thresh -end - -function guarded_secant_step(alpha::T, beta::T, falpha, fbeta) where {T <: AbstractFloat} - - fp = (fbeta - falpha) / (beta - alpha) - Δ::T = fbeta / fp - ## odd, we get allocations if we define Delta, then beta - Delta - ## Δ = beta - fbeta * (beta - alpha) / (fbeta - falpha) - - if isissue(Δ) - Δ = one(T)/1000 - elseif norm(Δ) >= 100 * norm(alpha - beta) # guard runaway - Δ = sign(Δ) * 100 * min(one(T), norm(alpha - beta)) - end - - if isissue(Δ) - return (alpha + (beta - alpha)*(0.5), true) # midpoint - else - return (beta - Δ, false) - end -end - - -## Different functions for approximating f'(xn) -## return fpxn and whether it is an issue - -## use f[a,b] to approximate f'(x) -function _fbracket(a, b, fa, fb) - num, den = fb - fa, b - a - num == 0 && den == 0 && return Inf, true - out = num / den - out, isissue(out) -end - -## use f[y,z] - f[x,y] + f[x,z] to approximate -function _fbracket_diff(a,b,c, fa, fb, fc) - x1, _ = _fbracket(b, c, fb, fc) - x2, _ = _fbracket(a, b, fa, fb) - x3, _ = _fbracket(a, c, fa, fc) - out = x1 - x2 + x3 - out, isissue(out) -end - - -## use f[a,b] * f[a,c] / f[b,c] -function _fbracket_ratio(a, b, c, fa, fb, fc) - x1, _ = _fbracket(a, b, fa, fb) - x2, _ = _fbracket(a, c, fa, fc) - x3, _ = _fbracket(b, c, fb, fc) - out = (x2 * x3) / x3 - out, isissue(out) -end - - ################################################## ## Order0 and Secant are related @@ -100,42 +34,31 @@ evaluation and has order `(1+sqrt(5))/2`. mutable struct Secant <: AbstractSecant end const Order1 = Secant -function init_state(method::AbstractSecant, fs, x::Union{T, Vector{T}}, bracket) where {T <: AbstractFloat} +function init_state(method::AbstractSecant, fs, x) - if isa(x, Vector) - x0, x1 = x[1:2] - # fx0, fx1 = fs.f(x0), fs.f(x1) + if isa(x, Vector) || isa(x, Tuple) + x0, x1 = x[1], x[2] fx0, fx1 = fs(x0), fs(x1) else - x0 = float(x) - # fx0 = fs.f(x0) + # need an initial x0,x1 if two not specified + x0 = x fx0 = fs(x0) - stepsize = max(1/100, min(abs(fx0), abs(x0/100))) - x1 = x0 + stepsize -# x0, x1, fx0, fx1 = x1, x0, fs.f(x1), fx0 # switch + stepsize = max(1/100, min(abs(fx0/oneunit(fx0)), abs(x0/oneunit(x0)/100))) + x1 = x0 + stepsize*oneunit(x0) x0, x1, fx0, fx1 = x1, x0, fs(x1), fx0 # switch end - state = UnivariateZeroStateBase( - promote(float(x1), float(x0))..., - promote(fx1, fx0)..., - bracket, - 0, 2, - false, false, false, false, - "") + state = UnivariateZeroState( promote(x1, x0)..., + promote(fx1, fx0)..., + 0, 2, + false, false, false, false, + "") state + end ################################################## -## in Order0, we run bisection if a bracketing interval is found -function _run_bisection(fs, o, options) - verbose = options.verbose; options.verbose=false # turn off verbose - find_zero(Bisection(), fs, o, options) - options.verbose = verbose - o.message = "Used bisection for last step" -end - ## order 0 # goal: more robust to initial guess than higher order methods @@ -149,31 +72,30 @@ end # * `f(x) == 0.0` or # * `f(prevfloat(x)) * f(nextfloat(x)) < 0`. # if a bracket is found that can be done, otherwise secant step is used -function update_state(method::Order0, fs, o::UnivariateZeroState{T}, options::UnivariateZeroOptions) where {T} +function update_state(method::Order0, fs, o::UnivariateZeroState{T,S}, options::UnivariateZeroOptions) where {T,S} - f = fs.f alpha, beta = o.xn0, o.xn1 falpha, fbeta = o.fxn0, o.fxn1 incsteps(o) if sign(falpha) * sign(fbeta) < 0.0 - _run_bisection(fs, o, options) + _run_bisection(fs, options, o) return nothing end gamma, issue = guarded_secant_step(alpha, beta, falpha, fbeta) - fgamma = f(gamma); incfn(o) + fgamma = fs(gamma); incfn(o) if sign(fgamma)*sign(fbeta) < 0.0 o.xn0, o.xn1 = gamma, beta o.fxn0, o.fxn1 = fgamma, fbeta - _run_bisection(fs, o, options) + _run_bisection(fs, options, o) return nothing end - if norm(fgamma) <= norm(fbeta) + if abs(fgamma) <= abs(fbeta) o.xn0, o.xn1 = beta, gamma o.fxn0, o.fxn1 = fbeta, fgamma return nothing @@ -199,10 +121,10 @@ function update_state(method::Order0, fs, o::UnivariateZeroState{T}, options::Un gamma = beta - ((beta - alpha)^2 * (fbeta - fgamma) - (beta - gamma)^2 * (fbeta - falpha))/denom/2 - fgamma = f(gamma); incfn(o) + fgamma = fs(gamma); incfn(o) incfn(o) - if norm(fgamma) < norm(fbeta) + if abs(fgamma) < abs(fbeta) o.xn0, o.xn1 = beta, gamma o.fxn0, o.fxn1 = fbeta, fgamma return nothing @@ -210,13 +132,13 @@ function update_state(method::Order0, fs, o::UnivariateZeroState{T}, options::Un theta, issue = guarded_secant_step(beta, gamma, fbeta, fgamma) - ftheta = f(theta); incfn(o) + ftheta = fs(theta); incfn(o) if sign(ftheta) * sign(fbeta) < 0 o.xn0, o.xn1 = beta, theta o.fxn0, o.fxn1 = fbeta, ftheta - _run_bisection(fs, o, options) + _run_bisection(fs, options, o) return nothing end end @@ -231,7 +153,7 @@ end ## Secant ## https://en.wikipedia.org/wiki/Secant_method -function update_state(method::Secant, fs, o::UnivariateZeroState{T}, options::UnivariateZeroOptions{T}) where {T <: AbstractFloat} +function update_state(method::Secant, fs, o, options) incsteps(o) @@ -246,7 +168,6 @@ function update_state(method::Secant, fs, o::UnivariateZeroState{T}, options::Un o.fxn0 = o.fxn1 o.xn1 = o.xn1 - o.fxn1 / fp - # o.fxn1 = fs.f(o.xn1) o.fxn1 = fs(o.xn1) incfn(o) @@ -261,14 +182,14 @@ Solve for zero of `f(x) = 0` using the secant method. Not exported. Use `find_zero` with `Order1()`. """ -secant_method(f, x0::Real, x1::Real; kwargs...) = find_zero(f, map(float, [x0,x1]), Order1(); kwargs...) +secant_method(f, x0::Number, x1::Number; kwargs...) = find_zero(f, (x0, x1), Order1(); kwargs...) ################################################## ### Steffensen ## https://en.wikipedia.org/wiki/Steffensen's_method#Simple_description -mutable struct Steffensen <: UnivariateZeroMethod +mutable struct Steffensen <: AbstractUnivariateZeroMethod end """ @@ -285,14 +206,12 @@ initial guesses. """ const Order2 = Steffensen -function update_state(method::Steffensen, fs, o::UnivariateZeroState{T}, options::UnivariateZeroOptions{T}) where {T <: AbstractFloat} - - S = eltype(o.fxn1) +function update_state(method::Steffensen, fs, o, options) incsteps(o) - wn = o.xn1 + steff_step(o.xn1, o.fxn1)::T - fwn = fs(wn)::S + wn = o.xn1 + steff_step(o.xn1, o.fxn1) + fwn = fs(wn) incfn(o) fp, issue = _fbracket(o.xn1, wn, o.fxn1, fwn) @@ -327,18 +246,61 @@ by Manoj Kumar, Akhilesh Kumar Singh, and Akanksha, Appl. Math. Inf. Sci. 9, No. 3, 1507-1513 (2015). Four function calls per step are needed. """ -mutable struct Order5 <: UnivariateZeroMethod end +mutable struct Order5 <: AbstractUnivariateZeroMethod end + +## If we have a derivative, we have this +function update_state(method::Order5, fs::Union{FirstDerivative,SecondDerivative}, o, options) -function update_state(method::Order5, fs, o::UnivariateZeroState{T}, options::UnivariateZeroOptions) where {T} + + xn, fxn = o.xn1, o.fxn1 + + incsteps(o) + + fpxn = fs(xn, 1) + incfn(o) + + if isissue(fpxn) + o.stopped = true + return + end + + yn = xn - fxn / fpxn + fyn, fpyn = fs(yn), fs(yn, 1) + incfn(o, 2) + + if isissue(fpyn) + o.xn0, o.xn1 = xn, yn + o.fxn0, o.fxn1 = fxn, fyn + o.stopped = true + return + end + + + zn = xn - (fxn + fyn) / fpxn + fzn = fs(zn) + incfn(o, 1) + + xn1 = zn - fzn / fpyn + fxn1 = fs(xn1) + incfn(o, 1) + + o.xn0, o.xn1 = xn, xn1 + o.fxn0, o.fxn1 = fxn, fxn1 + + nothing +end + + +function update_state(method::Order5, fs, o, options) xn = o.xn1 fxn = o.fxn1 - S = eltype(o.fxn1) incsteps(o) - wn::T = o.xn1 + steff_step(o.xn1, o.fxn1) - fwn = fs(wn)::S + wn = o.xn1 + steff_step(o.xn1, o.fxn1) + + fwn = fs(wn) incfn(o) fp, issue = _fbracket(o.xn1, wn, o.fxn1, fwn) @@ -350,13 +312,13 @@ function update_state(method::Order5, fs, o::UnivariateZeroState{T}, options::Un return end - yn::T = o.xn1 - o.fxn1 / fp - fyn = fs(yn)::S + yn = o.xn1 - o.fxn1 / fp + fyn = fs(yn) incfn(o) - zn::T = xn - (fxn + fyn) / fp - fzn = fs(zn)::S + zn = xn - (fxn + fyn) / fp + fzn = fs(zn) incfn(o) fp, issue = _fbracket_ratio(yn, o.xn1, wn, fyn, o.fxn1, fwn) @@ -377,50 +339,6 @@ function update_state(method::Order5, fs, o::UnivariateZeroState{T}, options::Un nothing end -## If we have a derivative -function update_state(method::Order5, fs::FirstDerivative, o::UnivariateZeroState{T}, options::UnivariateZeroOptions) where {T} - - - xn, fxn = o.xn1, o.fxn1 - S = eltype(fxn) - - incsteps(o) - - fpxn = fs.fp(xn) - incfn(o) - - if isissue(fpxn) - o.stopped = true - return - end - - yn = xn - fxn / fpxn - fyn, fpyn = fs.f(yn), fs.fp(yn) - incfn(o, 2) - - if isissue(fpyn) - o.xn0, o.xn1 = xn, yn - o.fxn0, o.fxn1 = fxn, fyn - o.stopped = true - return - end - - - zn = xn - (fxn + fyn) / fpxn - fzn = fs.f(zn) - incfn(o, 1) - - xn1 = zn - fzn / fpyn - fxn1 = fs.f(xn1) - incfn(o, 1) - - o.xn0, o.xn1 = xn, xn1 - o.fxn0, o.fxn1 = fxn, fxn1 - - nothing -end - - ################################################## @@ -434,17 +352,17 @@ by Rajinder Thukral, International Journal of Mathematics and Mathematical Sciences Volume 2012 (2012), Article ID 493456, 12 pages. Four function calls per step are required. """ -mutable struct Order8 <: UnivariateZeroMethod +mutable struct Order8 <: AbstractUnivariateZeroMethod end -function update_state(method::Order8, fs, o::UnivariateZeroState{T}, options::UnivariateZeroOptions) where {T} +function update_state(method::Order8, fs, o, options) + xn = o.xn1 fxn = o.fxn1 - S = eltype(fxn) - incsteps(o) + S = eltype(fxn) - wn::T = xn + steff_step(xn, fxn) + wn = xn + steff_step(xn, fxn) fwn::S = fs(wn) incfn(o) @@ -467,7 +385,7 @@ function update_state(method::Order8, fs, o::UnivariateZeroState{T}, options::Un return end - yn::T = xn - fxn / fp + yn = xn - fxn / fp fyn::S = fs(yn) incfn(o) @@ -495,11 +413,11 @@ function update_state(method::Order8, fs, o::UnivariateZeroState{T}, options::Un return end - w::T = 1 / (1 - fzn/fwn) + w = 1 / (1 - fzn/fwn) - xi::T = (1 - 2fyn*fyn*fyn / (fwn * fwn * fxn)) + xi = (1 - 2fyn*fyn*fyn / (fwn * fwn * fxn)) - xn1::T = zn - w * xi * fzn / fp + xn1 = zn - w * xi * fzn / fp fxn1::S = fs(xn1) incfn(o) @@ -521,21 +439,23 @@ American Journal of Computational and Applied Mathematics p-ISSN: 2165-8935; e-ISSN: 2165-8943; 2012; 2(3): 112-118 doi: 10.5923/j.ajcam.20120203.08. -Five function calls per step are required. Though rapidly converging, this method generally isn't faster (fewer -function calls/steps) over other methods when using `Float64` values, -but may be useful for solving over `BigFloat`. +Five function calls per step are required. Though rapidly converging, +this method generally isn't faster (fewer function calls/steps) over +other methods when using `Float64` values, but may be useful for +solving over `BigFloat`. + """ -mutable struct Order16 <: UnivariateZeroMethod +mutable struct Order16 <: AbstractUnivariateZeroMethod end -function update_state(method::Order16, fs, o::UnivariateZeroState{T}, options::UnivariateZeroOptions) where {T} +function update_state(method::Order16, fs, o, options) xn = o.xn1 fxn = o.fxn1 S = eltype(fxn) incsteps(o) - wn::T = xn + steff_step(xn, fxn) + wn = xn + steff_step(xn, fxn) fwn::S = fs(wn) incfn(o) @@ -550,7 +470,7 @@ function update_state(method::Order16, fs, o::UnivariateZeroState{T}, options::U return end - yn::T = xn - fxn / fp + yn = xn - fxn / fp fyn::S = fs(yn) incfn(o) @@ -565,13 +485,14 @@ function update_state(method::Order16, fs, o::UnivariateZeroState{T}, options::U - zn::T = yn - fyn / fp + zn = yn - fyn / fp fzn::S = fs(zn) incfn(o) - fp, issue = _fbracket_diff(xn, yn, zn, fxn, fyn, fzn) u2, u3, u4 = fzn/fwn, fyn/fxn, fyn/fwn + + eta = 1 / (1 + 2*u3*u4^2) / (1 - u2) if issue o.xn0, o.xn1 = xn, zn @@ -582,7 +503,7 @@ function update_state(method::Order16, fs, o::UnivariateZeroState{T}, options::U end an = zn - eta * fzn / fp - fan = fs(an) + fan::S = fs(an) incfn(o) @@ -596,15 +517,15 @@ function update_state(method::Order16, fs, o::UnivariateZeroState{T}, options::U end u1, u5, u6 = fzn/fxn, fan/fxn, fan/fwn - sigma = 1 + u1*u2 - u1*u3*u4^2 + u5 + u6 + u1^2*u4 + - u2^2*u3 + 3*u1*u4^2*(u3^2 - u4^2)/_fbracket(xn,yn, fxn, fyn)[1] - - + fp1, issue = _fbracket(xn,yn, fxn, fyn) + sigma = 1 + u1*u2 - u1*u3*u4^2 + u5 + u6 + u1^2*u4 + + u2^2*u3 + 3*u1*u4^2*(u3^2 - u4^2)/(fp1/oneunit(fp1)) + xn1 = an - sigma * fan / fp - fxn1 = fs(xn1) + fxn1::S = fs(xn1) incfn(o) o.xn0, o.xn1 = xn, xn1 diff --git a/src/find_zero.jl b/src/find_zero.jl index 1d6a2ecb..5b0c709a 100644 --- a/src/find_zero.jl +++ b/src/find_zero.jl @@ -1,56 +1,45 @@ ## Framework for setting up an iterative problem for finding a zero -## Different methods can implement: -## - A subtype of UnivariateZeroMethod (reqd) -## - UnivariateZeroProblem -## - callable_function -## - init_state -## - assess_convergence -## - udpate_state (reqd) ## TODO ## * a graphic of trace when verbose=true? -## method names are subtypes -abstract type UnivariateZeroMethod end -abstract type AbstractBisection <: UnivariateZeroMethod end -abstract type AbstractSecant <: UnivariateZeroMethod end -# container for callable objects; not really necessary, but has some value. -abstract type CallableFunction end -struct DerivativeFree <: CallableFunction - f -end -(F::DerivativeFree)(x::Number) = F.f(x) +# +# In McNamee & Pan (DOI:10.1016/j.camwa.2011.11.015 there are a number of +# results on efficiencies of a solution, (1/d) log_10(q) +# Those implemented here are: +# quadratic cut (Muller) .265 (in a42) +# Newton() newton = .1505 or 1/2log(2) +# Order1() secant method .20 (1/1 * log(1.6) +# FalsePostion(12) Anderson-Bjork [.226, .233] +# FalsePostion(3) (King?) .264 +# A42() 0.191 but convergence guaranteed +# Order8() 8th order 4 steps: .225 (log10(8)/4 +# Order16() 16th order 5 steps .240 +# Order5(): 5th order, 4 steps. 0.1747 -struct FirstDerivative <: CallableFunction - f - fp -end -(F::FirstDerivative)(x::Number) = F.f(x) -struct SecondDerivative <: CallableFunction - f - fp - fpp -end -(F::SecondDerivative)(x::Number) = F.f(x) -## allows override for automatic derivatives, see Newton -function callable_function(m::UnivariateZeroMethod, @nospecialize(f)) - !isa(f, Tuple) && return DerivativeFree(f) - length(f) == 1 && return DerivativeFree(f[1]) - length(f) == 2 && return FirstDerivative(f[1], f[2]) - SecondDerivative(f[1], f[2], f[3]) -end +# A zero is found by specifying: +# the method to use <: AbstractUnivariateZeroMethod +# the function(s) <: CallableFunction +# the initial state through a value for x either x, [a,b], or (a,b) <: AbstractUnivariateZeroState +# the options (e.g., tolerances) <: UnivariateZeroOptions + +# The minimal amount needed to add a method, is to define a Method and an update_state method. + +### Methods +abstract type AbstractUnivariateZeroMethod end +abstract type AbstractBisection <: AbstractUnivariateZeroMethod end +abstract type AbstractSecant <: AbstractUnivariateZeroMethod end -## object to hold state; allow for subtypes with additional fields -abstract type UnivariateZeroState{T, S} end -mutable struct UnivariateZeroStateBase{T,S} <: UnivariateZeroState{T,S} +### States +abstract type AbstractUnivariateZeroState end +mutable struct UnivariateZeroState{T,S} <: AbstractUnivariateZeroState where {T,S} xn1::T - xn0::T + xn0::Union{Missing, T} fxn1::S - fxn0::S - bracket::Union{Vector{T}, Missing} + fxn0::Union{Missing, S} steps::Int fnevals::Int stopped::Bool # stopped, butmay not have converged @@ -59,96 +48,158 @@ mutable struct UnivariateZeroStateBase{T,S} <: UnivariateZeroState{T,S} convergence_failed::Bool message::AbstractString end - incfn(o::UnivariateZeroState, k=1) = o.fnevals += k incsteps(o::UnivariateZeroState, k=1) = o.steps += k -## generic initialization. Modify as necessary for a method, such as secant which uses both xn1 and xn0 -## we use x0 + typemax(Int) as a sentinel. This could be a Missing, but that -## is a bit more hassle -function init_state(method::Any, fs, x0::T, bracket) where {T} - fx0 = fs(x0); fnevals = 1 - if !ismissing(bracket) - a,b = bracket[1:2] - sign(fs(a)) * sign(fs(b)) > 0 && (warn(bracketing_error); throw(ArgumentError)) - fnevals += 2 - end +# initialize state for most methods +function init_state(method::Any, fs, x) + + x1 = float(x) + fx1 = fs(x1); fnevals = 1 + - S = eltype(fx0) - state = UnivariateZeroStateBase(x0, x0 + typemax(Int), - fx0, fx0, - !ismissing(bracket) ? float.(bracket) : bracket, - 0, fnevals, - false, false, false, false, - "") + state = UnivariateZeroState(x1, missing, + fx1, missing, + 0, fnevals, + false, false, false, false, + "") state end -## Options for convergence, reporting -mutable struct UnivariateZeroOptions{T} - xabstol::T - xreltol::T - abstol::T + +### Options +mutable struct UnivariateZeroOptions{Q,R,S,T} + xabstol::Q + xreltol::R + abstol::S reltol::T maxevals::Int maxfnevals::Int verbose::Bool end +# Allow for override of default tolerances. Useful, say, for methods like bisection +function _map_tolerance_arguments(d, xatol, xrtol, atol, rtol) + xatol = get(d, :xabstol, xatol) + xrtol = get(d, :xreltol, xrtol) + atol = get(d, :abstol, atol) + atol = get(d, :reltol, rtol) + xatol, xrtol, atol, rtol +end -function univariate_zero_options(args...; - xabstol::T=zero(T), - xreltol::T=eps(T), - abstol::T=zero(T), - reltol::T=4*eps(T), - maxevals::Int=40, - maxfnevals::Int=typemax(Int), - verbose::Bool=false, - kwargs...) where {T} - - ## adjust for old argument names - kw = Dict(kwargs) - z = zero(T) - UnivariateZeroOptions(max(z, get(kw, :xtol, xabstol)), - max(z, get(kw, :xtolrel, xreltol)), - max(z, abstol), - max(z, get(kw, :ftol, reltol)), - max(0, get(kw, :maxeval, get(kw, :maxsteps, maxevals))), - max(0, get(kw, :maxfneval, maxfnevals)), - verbose) +function init_options(::Any, + state; + xatol=missing, + xrtol=missing, + atol=missing, + rtol=missing, + maxevals::Int=40, + maxfnevals::Int=typemax(Int), + verbose::Bool=false, + kwargs...) + + ## Where we set defaults + x1 = real(oneunit(state.xn1)) + fx1 = real(oneunit(float(state.fxn1))) + + ## map old tol names to new + ## deprecate in future + xatol, xrtol, atol, rtol = _map_tolerance_arguments(Dict(kwargs), xatol, xrtol, atol, rtol) + + # assign defaults when missing + options = UnivariateZeroOptions(ismissing(xatol) ? zero(x1) : xatol, # units of x + ismissing(xrtol) ? eps(x1/oneunit(x1)) : xrtol, # unitless + ismissing(atol) ? 4 * eps(fx1) : atol, # units of f(x) + ismissing(rtol) ? 4 * eps(fx1/oneunit(fx1)) : rtol, # unitless + maxevals, maxfnevals, + verbose) + + options end - -## basic container -mutable struct UnivariateZeroProblem{T<:AbstractFloat} - fs - x0::Union{T, Tuple{T,T}, Vector{T}, Complex{T}} - bracket::Union{Vector{T}, Missing} +### Functions +abstract type CallableFunction end + +## It is faster the first time a function is used if we do not +## parameterize this. (As this requires less compilation) It is slower +## the second time a function is used. This seems like the proper +## tradeoff. If it a case where the same function is being used many +## times, this function would be helpful +## +## function _find_zero(f, x0, method::Roots.AbstractUnivariateZeroMethod;kwargs...) +## state = Roots.init_state(method, f, float.(x0)) +## options = Roots.init_options(method, state; kwargs...) +## find_zero(method, f, options, state) +## end +struct DerivativeFree <: CallableFunction + f end -## frame the problem and the options -function derivative_free_setup(method::Any, fs, x0::Union{T, Tuple{T,T}, Vector{T}}; - bracket=missing, - xabstol=zero(T), xreltol=eps(T), - abstol=4*eps(T), reltol=4*eps(T), - maxevals=40, maxfnevals=typemax(Int), - verbose::Bool=false, - kwargs... - ) where {T<:AbstractFloat} - x = float.(x0) - prob = UnivariateZeroProblem(fs, x, - !ismissing(bracket) ? float.(bracket) : missing) - options = UnivariateZeroOptions(xabstol, xreltol, abstol, - reltol, maxevals, maxfnevals, verbose) - prob, options +struct FirstDerivative <: CallableFunction + f + fp +end + +struct SecondDerivative <: CallableFunction + f + fp + fpp end +(F::DerivativeFree)(x::Number) = F.f(x) +(F::FirstDerivative)(x::Number) = F.f(x) +(F::SecondDerivative)(x::Number) = F.f(x) + +(F::DerivativeFree)(x::Number, n::Int) = F(x, Val{n}) +(F::FirstDerivative)(x::Number, n::Int) = F(x, Val{n}) +(F::SecondDerivative)(x::Number, n::Int) = F(x, Val{n}) + +(F::DerivativeFree)(x::Number, ::Type{Val{1}}) = D(F.f)(x) +(F::FirstDerivative)(x::Number, ::Type{Val{1}}) = F.fp(x) +(F::SecondDerivative)(x::Number, ::Type{Val{1}}) = F.fp(x) + +(F::DerivativeFree)(x::Number, ::Type{Val{2}}) = D(F.f, 2)(x) +(F::FirstDerivative)(x::Number, ::Type{Val{2}}) = D(F.f, 2)(x) +(F::SecondDerivative)(x::Number, ::Type{Val{2}}) = F.fpp(x) + + +function callable_function(@nospecialize(fs)) + if isa(fs, Tuple) + length(fs)==1 && return DerivativeFree(fs[1]) + length(fs)==2 && return FirstDerivative(fs[1],fs[2]) + return SecondDerivative(fs[1],fs[2],fs[3]) + end + DerivativeFree(fs) +end + + + ## has UnivariateZeroProblem converged? -function assess_convergence(method::Any, fs, state, options) +## allow missing values in isapprox +_isapprox(a, b, rtol, atol, lambda=missing, relaxed=false) = _isapprox(Val{ismissing(a) || ismissing(b)}, a, b, rtol, atol,lambda,relaxed) + +### missing data so not approx +_isapprox(::Type{Val{true}}, a, b, rtol, atol,lambda, relaxed) = false + +function _isapprox(::Type{Val{false}}, a, b, rtol, atol, lambda, relaxed) + + if !ismissing(lambda) + rtol *= max(one(lambda), abs(lambda/oneunit(lambda))) + end + + if relaxed + tol = cbrt(max(atol/oneunit(atol), rtol)) + abs(a - b)/oneunit(a) <= tol + else + isapprox(a, b, rtol=rtol, atol=atol) + end +end + +function assess_convergence(method::Any, state, options) xn0, xn1 = state.xn0, state.xn1 fxn0, fxn1 = state.fxn0, state.fxn1 @@ -157,7 +208,7 @@ function assess_convergence(method::Any, fs, state, options) if (state.x_converged || state.f_converged) return true end - + if state.steps > options.maxevals state.stopped = true state.message = "too many steps taken." @@ -172,26 +223,29 @@ function assess_convergence(method::Any, fs, state, options) if isnan(xn1) state.convergence_failed = true - state.message = "NaN produced by algorithm" + state.message = "NaN produced by algorithm." return true end if isinf(fxn1) state.convergence_failed = true - state.message = "Inf produced by algorithm" + state.message = "Inf produced by algorithm." return true end - λ = max(one(real(xn1)), norm(xn1)) - - if norm(fxn1) <= max(options.abstol, λ * options.reltol) + # f(xstar) ≈ xstar * f'(xstar)*eps(), so we pass in lambda + if _isapprox(fxn1, zero(fxn1), options.reltol, options.abstol, abs(xn1)) state.f_converged = true return true end - if isapprox(xn1, xn0, rtol = options.xreltol, atol=options.xabstol) && norm(fxn1) <= cbrt(max(options.abstol, λ * options.reltol)) - state.x_converged = true - return true + if _isapprox(xn1, xn0, options.xreltol, options.xabstol) + # Heuristic check that f is small too in unitless way + λ = max(one(real(xn1)), abs(xn1/oneunit(xn1))) + if _isapprox(fxn1, zero(fxn1), options.reltol, options.abstol, λ, true) + state.x_converged = true + return true + end end @@ -205,7 +259,7 @@ function assess_convergence(method::Any, fs, state, options) return false end -function show_trace(fs, state, xns, fxns, method) +function show_trace(state, xns, fxns, method) converged = state.x_converged || state.f_converged println("Results of univariate zero finding:\n") @@ -214,8 +268,8 @@ function show_trace(fs, state, xns, fxns, method) println("* Algorithm: $(method)") println("* iterations: $(state.steps)") println("* function evaluations: $(state.fnevals)") - state.x_converged && println("* stopped as x_n ≈ x_{n-1} using atol=xabstol, rtol=xreltol") - state.f_converged && state.message == "" && println("* stopped as |f(x_n)| ≤ max(δ, max(1,|x|)⋅ϵ) using δ = abstol, ϵ = reltol") + state.x_converged && println("* stopped as x_n ≈ x_{n-1} using atol=xatol, rtol=xrtol") + state.f_converged && state.message == "" && println("* stopped as |f(x_n)| ≤ max(δ, max(1,|x|)⋅ϵ) using δ = atol, ϵ = rtol") state.message != "" && println("* Note: $(state.message)") else println("* Convergence failed: $(state.message)") @@ -224,241 +278,200 @@ function show_trace(fs, state, xns, fxns, method) println("") println("Trace:") - itr, offset = 0:(endof(xns)-1), 1 + itr, offset = 0:(lastindex(xns)-1), 1 for i in itr x_i,fx_i, xi, fxi = "x_$i", "f(x_$i)", xns[i+offset], fxns[i+offset] println(@sprintf("%s = % 18.16f,\t %s = % 18.16f", x_i, float(xi), fx_i, float(fxi))) end println("") - + end -### find_zero method has potentially many interfaces -## problem, method, options. This may be a main entry point -function find_zero(prob::UnivariateZeroProblem, method::UnivariateZeroMethod, options::UnivariateZeroOptions) - fs = prob.fs - state = init_state(method, fs, prob.x0, prob.bracket) - find_zero(method, fs, state, options) -end +""" -## method, state, options. Could be used to switch between methods -function find_zero(method::UnivariateZeroMethod, fs, state::UnivariateZeroState, options::UnivariateZeroOptions) + find_zero(fs, x0, method; kwargs...) - # in case verbose=true - if isa(method, AbstractSecant) - xns, fxns = [state.xn0, state.xn1], [state.fxn0, state.fxn1] - else - xns, fxns = [state.xn1], [state.fxn1] - end +Interface to one of several methods for find zeros of a univariate function. - ## XXX Should just deprecate this in favor of FalsePosition method XXX - while true - if !ismissing(state.bracket) - m,M = state.bracket[1:2] - if (state.xn1 < m || state.xn1 > M) || state.stopped - # do bisection step, update bracket - c = m + (M-m)/2 - # don't land on xn0 - if c == state.xn0 - c = m + (M-m)/4 - end - fc = fs(c) - if norm(fc) < norm(state.fxn1) - state.xn0 = state.xn1 - state.xn1 = c - state.fxn0 = state.fxn1 - state.fxn1 = fc - else - state.xn0 = c - state.fxn1 = fc - end - if sign(state.fxn1) * sign(fs(m)) < 0 - state.bracket[2] = c - else - state.bracket[1] = c - end - state.stopped && (state.stopped = false) - incfn(state) - end - end - - val = assess_convergence(method, fs, state, options) +# Initial starting value +For most methods, `x0` is a scalar value indicating the initial value in the iterative procedure. Values must be a subtype of `Number` and have methods for `float`, `real`, and `oneunit` defined. - if val - if state.stopped && !(state.x_converged || state.f_converged) - ## stopped is a heuristic, there was an issue with an approximate derivative - ## say it converged if pretty close, else say convergence failed. - ## (Is this a good idea?) - xstar, fxstar = state.xn1, state.fxn1 - if abs(fxstar) <= (options.abstol)^(2/3) - msg = "Algorithm stopped early, but |f(xn)| < ϵ^(2/3), where ϵ = abstol" - state.message = state.message == "" ? msg : state.message * "\n\t" * msg - state.f_converged = true - else - state.convergence_failed = true - end - end - - if state.x_converged || state.f_converged - options.verbose && show_trace(fs, state, xns, fxns, method) - return state.xn1 - end +May also be a bracketing interval, specified as a tuple or a vector. A bracketing interval, (a,b), is one where f(a) and f(b) have different signs. - if state.convergence_failed - options.verbose && show_trace(fs, state, xns, fxns, method) - throw(ConvergenceFailed("Stopped at: xn = $(state.xn1)")) - end - end +# Specifying a method - update_state(method, fs, state, options) - if options.verbose - push!(xns, state.xn1) - push!(fxns, state.fxn1) - end +A method is specified to indicate which algorithm to employ: - end -end +* There are methods for bisection where a bracket is specified: `Bisection` -""" +* There are methods for guarded bisection where a bracket is specified: `FalsePosition` -Find a zero of a univariate function using one of several different methods. +* There are several derivative-free methods: cf. `Order0`, `Order1` (secant method), `Order2` (Steffensen), `Order5`, `Order8`, and `Order16`, where the number indicates the order of the convergence. -Positional arugments: +* There are some classical methods where a derivative is assumed or computed using `ForwardDiff`: `Newton`, `Halley`. (The are not exported, so they need qualification, e.g., `Roots.Newton()`. -* `f` a function, callable object, or tuple of same. A tuple is used - to pass in derivatives, as desired. Most methods are derivative - free. Some (`Newton`, `Halley`) may have derivative(s) computed - using the `ForwardDiff` pacakge. +For more detail, see the help page for each method (e.g., `?Order5`). -* `x0` an initial starting value. Typically a scalar, but may be a two-element - tuple or array for bisection methods. The value `float.(x0)` is passed on. +If no method is specified, the default method depends on `x0`: -* `method` one of several methods, see below. +* If `x0` is a scalar, the default is the slower, but more robust `Order0` method. -Keyword arguments: +* If `x0` is a tuple or vector indicating a *bracketing* interval, the `Bisection` method is use. (this method specializes on floating point values, but otherwise uses an algorithm of Alefeld, Potra, and Shi.) -* `xabstol=zero()`: declare convergence if |x_n - x_{n-1}| <= max(xabstol, max(1, |x_n|) * xreltol) +# Specifying the function -* `xreltol=eps()`: +The function(s) are passed as the first argument. -* `abstol=zero()`: declare convergence if |f(x_n)| <= max(abstol, max(1, |x_n|) * reltol) +For the few methods that use a derivative (`Newton`, `Halley`, and optionally `Order5`) +a tuple of functions is used. For methods requiring a derivative and +second derivative, a tuple of three functions is used. If the +derivative functions are not specified, automatic differentiation via +the `ForwardDiff` package will be employed (for `Newton` and `Halley`). -* `reltol`: +# Optional arguments (tolerances, limit evaluations, tracing) -* `bracket`: Optional. A bracketing interval for the sought after - root. If given, a hybrid algorithm may be used where bisection is - utilized for steps that would go out of bounds. (Using a `FalsePosition` method - instead would be suggested.) +* `xatol` - absolute tolerance for `x` values. Passed to `isapprox(x_n, x_{n-1})` +* `xrtol` - relative tolerance for `x` values. Passed to `isapprox(x_n, x_{n-1})` +* `atol` - absolute tolerance for `f(x)` values. Passed to `isapprox(f(x_n), zero(f(x_n))` +* `rtol` - relative tolerance for `f(x)` values. Passed to `isapprox(f(x_n), zero(f(x_n))` +* `maxevals` - limit on maximum number of iterations +* `maxfnevals` - limit on maximum number of function evaluations +* `verbose` - if `true` a trace of the algorithm will be shown on successful completion. -* `maxevals::Int=40`: stop trying after `maxevals` steps +# Convergence -* `maxfnevals::Int=typemax(Int)`: stop trying after `maxfnevals` function evaluations +For most methods there are several heuristics used for convergence: -* `verbose::Bool=false`: If `true` show information about algorithm and a trace. +* if f(x_n) ≈ 0, using the tolerances `atol` and `rtol`, convergence is declared -Returns: +* if x_n ≈ x_{n-1}, using the tolerances `xatol` and `xrtol`, *and* f(x_n) ≈ 0 with a relaxed tolerance then convergence is declared. -Returns `xn` if the algorithm converges. If the algorithm stops, returns `xn` if -|f(xn)| ≤ ϵ^(2/3), where ϵ = reltol, otherwise a `ConvergenceFailed` error is thrown. +* if the algorithm has an issue (say a value of NaN appears) *and* f(x_n) ≈ 0 with a relaxed tolerance then convergence is declared, otherwise a failure to converge is declared -Exported methods: +* if the number of iterations exceeds `maxevals` or the number of function evaluations exceeds `maxfnevals` a failure to converge is declared -`Bisection()`; -`Order0()` (heuristic, slow more robust); -`Order1()` (also `Secant()`); -`Order2()` (also `Steffensen()`); -`Order5()` (KSS); -`Order8()` (Thukral); -`Order16()` (Thukral); -`FalsePosition(i)` (false position, i in 1..12); +* if x_n is `NaN` or f(x_n) is infinite a failure to converge is declared -Not exported: -`Secant()`, use `Order1()` -`Steffensen()` use `Order2()` -`Newton()` (use `newton()` function) -`Halley()` (use `halley()` function) +In general, with floating point numbers, convergence must be +understood as not an absolute statement. Even if mathematically x is +an answer the floating point realization, say xstar, may have +f(xstar) - f(x) = f(xstar) ≈ f'(x) ⋅ eps(x), so tolerances must be +appreciated, and at times specified. -The order 0 method is more robust to the initial starting point, but -can utilize many more function calls. The higher order methods may be -of use when greater precision is desired.` +For the `Bisection` methods, convergence is guaranteed, so the tolerances are set to be 0 by default. -Examples: +# Examples: ``` -f(x) = x^5 - x - 1 -find_zero(f, 1.0, Order5()) -find_zero(f, 1.0, Steffensen()) # also Order2() -find_zero(f, (1.0, 2.0), FalsePosition()) +# default methods +find_zero(sin, 3) # use Order0() +find_zero(sin, (3,4)) # use Bisection() + +# specifying a method +find_zero(sin, 3.0, Order2()) # Use Steffensen method +find_zero(sin, big(3.0), Order16()) # rapid convergence +find_zero(sin, (3, 4), FalsePosition()) # fewer function calls than Bisection(), in this case +find_zero(sin, (3, 4), FalsePosition(8)) # 1 or 12 possible algorithms for false position +find_zero((sin,cos), 3.0, Roots.Newton()) # use Newton's method +find_zero(sin, 3.0, Roots.Newton()) # use Newton's method with automatic f'(x) +find_zero((sin, cos, x->-sin(x)), 3.0, Roots.Halley()) # use Halley's method + +# changing tolerances +fn, x0, xstar = (x -> (2x*cos(x) + x^2 - 3)^10/(x^2 + 1), 3.0, 2.9806452794385368) +find_zero(fn, x0, Order2()) - xstar # 0.011550654688925466 +find_zero(fn, x0, Order2(), atol=0.0, rtol=0.0) # error: x_n ≉ x_{n-1}; just f(x_n) ≈ 0 +fn, x0, xstar = (x -> (sin(x)*cos(x) - x^3 + 1)^9, 1.0, 1.117078770687451) +find_zero(fn, x0, Order2()) # 1.1122461983100858 +find_zero(fn, x0, Order2(), maxevals=10) # Roots.ConvergenceFailed: 26 iterations needed + +# tracing output +find_zero(x->sin(x), 3.0, Order2(), verbose=true) # 3 iterations +find_zero(x->sin(x)^5, 3.0, Order2(), verbose=true) # 23 iterations + + ``` """ -function find_zero(f, x0::T, method::M; kwargs...) where {M <: AbstractBisection, T<:Number} - throw(ArgumentError("For bisection methods, x0 must be a vector")) -end +function find_zero(fs, x0, method::AbstractUnivariateZeroMethod; kwargs...) -function find_zero(f, x0::Vector{T}, method::M; kwargs...) where {T<:Number, M<:AbstractBisection} - find_zero(method, callable_function(method, f), x0; kwargs...) -end - -function find_zero(f, x0::Tuple{T}, method::M; kwargs...) where {T<:Number, M<:AbstractBisection} - find_zero(method, callable_function(method, f), x0; kwargs...) -end + x = float.(x0) -function find_zero(f, x0::T, method::UnivariateZeroMethod; kwargs...) where {T<:Number} - find_zero(method, callable_function(method, f), x0; kwargs...) -end + F = callable_function(fs) + state = init_state(method, F, x) + options = init_options(method, state; kwargs...) -function find_zero(f, x0::T, method::AbstractSecant; kwargs...) where {T<:Number} - find_zero(method, callable_function(method, f), x0; kwargs...) -end -function find_zero(f, x0::Vector{T}, method::AbstractSecant; kwargs...) where {T<:Number} - find_zero(method, callable_function(method, f), x0; kwargs...) + find_zero(method, F, options, state) + end -## some defaults for methods find_zero(f, x0::T; kwargs...) where {T <: Number}= find_zero(f, x0, Order0(); kwargs...) -find_zero(f, x0::Vector{T}; kwargs...) where {T <: Number}= find_zero(f, x0, Bisection(); kwargs...) -find_zero(f, x0::Tuple{T,S};kwargs...) where {T<:Number, S<:Number} = find_zero(f, x0, Bisection(); kwargs...) +find_zero(f, x0::Vector; kwargs...) = find_zero(f, x0, Bisection(); kwargs...) +find_zero(f, x0::Tuple; kwargs...) = find_zero(f, x0, Bisection(); kwargs...) +# Main method +function find_zero(M::AbstractUnivariateZeroMethod, + F, + options::UnivariateZeroOptions, + state::UnivariateZeroState{T,S} + ) where {T<:Number, S<:Number} -function find_zero(method::UnivariateZeroMethod, fs, x0; kwargs...) - x = float.(x0) - prob, options = derivative_free_setup(method, fs, x; kwargs...) - find_zero(prob, method, options) -end + + # in case verbose=true + if options.verbose + if isa(M, AbstractSecant) + xns, fxns = T[state.xn0, state.xn1], S[state.fxn0, state.fxn1] + else + xns, fxns = T[state.xn1], S[state.fxn1] + end + end + while true + + val = assess_convergence(M, state, options) + if val + if state.stopped && !(state.x_converged || state.f_converged) + ## stopped is a heuristic, there was an issue with an approximate derivative + ## say it converged if pretty close, else say convergence failed. + ## (Is this a good idea?) + xstar, fxstar = state.xn1, state.fxn1 + λ = max(one(real(xstar)), abs(xstar/oneunit(xstar))) + if _isapprox(fxstar, zero(fxstar), options.reltol, options.abstol, λ, true) + msg = "Algorithm stopped early, but |f(xn)| < ϵ^(1/3), where ϵ depends on xn, rtol, and atol" + state.message = state.message == "" ? msg : state.message * "\n\t" * msg + state.f_converged = true + else + state.convergence_failed = true + end + end + + if state.x_converged || state.f_converged + options.verbose && show_trace(state, xns, fxns, M) + return state.xn1 + end -## old interface for fzero -## old keyword arguments (see ?fzero) handled in univariate_zero_options -@noinline function derivative_free(f, x0::T; order::Int=0, - kwargs...) where {T <: AbstractFloat} - - if order == 0 - method = Order0() - elseif order == 1 - method = Order1() - elseif order == 2 - method = Order2() - elseif order == 5 - method = Order5() - elseif order == 8 - method = Order8() - elseif order == 16 - method = Order16() - else - warn("Invalid order. Valid orders are 0, 1, 2, 5, 8, and 16") - throw(ArgumentError()) - end + if state.convergence_failed + options.verbose && show_trace(state, xns, fxns, M) + throw(ConvergenceFailed("Stopped at: xn = $(state.xn1)")) + return state.xn1 + end + end + + update_state(M, F, state, options) - find_zero(f, x0, method; kwargs...) + if options.verbose + push!(xns, state.xn1) + push!(fxns, state.fxn1) + end + + end end diff --git a/src/fzero.jl b/src/fzero.jl new file mode 100644 index 00000000..10fa2f2c --- /dev/null +++ b/src/fzero.jl @@ -0,0 +1,161 @@ +## MATLAB interfcae to find_zero +## Main functions are +## * fzero(f, ...) to find _a_ zero of f +## * fzeros(f, ...) to attempt to find all zeros of f + + + +""" + +Find zero of a function using an iterative algorithm + +* `f`: a scalar function or callable object +* `x0`: an initial guess, finite valued. + +Keyword arguments: + +* `ftol`: tolerance for a guess `abs(f(x)) < ftol + max(1, |xnew|) * ftolrel` +* `ftolrel`: relative tolerance for convergence towards 0 of f(x) +* `xtol`: stop if `abs(xold - xnew) <= xtol + max(1, |xnew|)*xtolrel` +* `xtolrel`: see `xtol` +* `maxeval`: maximum number of steps +* `verbose`: Boolean. Set `true` to trace algorithm +* `order`: Can specify order of algorithm. 0 is most robust, also 1, 2, 5, 8, 16. +* `kwargs...` passed on to different algorithms. There are `maxfneval` when `order` is 1,2,5,8, or 16 and `beta` for orders 2,5,8,16, + +This is a polyalgorithm redirecting to different algorithms based on the value of `order`. + +(The tolerance arguments can also be given through `atol`, `rtol`, `xatol`, and `xrtol`, as is done with `find_zero`.) + +""" +function fzero(f, x0::Number; kwargs...) + x = float(x0) + isinf(x) && throw(ConvergenceFailed("An initial value must be finite")) + derivative_free(f, x; kwargs...) +end + + + +""" +Find zero of a function within a bracket + +Uses a modified bisection method for non `big` arguments + +Arguments: + +* `f` A scalar function or callable object +* `a` left endpont of interval +* `b` right endpont of interval +* `xtol` optional additional tolerance on sub-bracket size. + +For a bracket to be valid, it must be that `f(a)*f(b) < 0`. + +For `Float64` values, the answer is such that `f(prevfloat(x)) * +f(nextfloat(x)) < 0` unless a non-zero value of `xtol` is specified in +which case, it stops when the sub-bracketing produces an bracket with +length less than `max(xtol, abs(x1)*xtolrel)`. + +For `Big` values, which defaults to the algorithm of Alefeld, Potra, and Shi, a +default tolerance is used for the sub-bracket length that can be enlarged with `xtol`. + +If `a==-Inf` it is replaced with `nextfloat(a)`; if `b==Inf` it is replaced with `prevfloat(b)`. + +Example: + + `fzero(sin, 3, 4)` # find pi + `fzero(sin, [big(3), 4]) find pi with more digits +""" +fzero(f, a::Number, b::Number; kwargs...) = find_zero(f, (a,b), Bisection(); kwargs...) +fzero(f, bracket::Vector{T}; kwargs...) where {T <: Number} = find_zero(f, bracket, Bisection(); kwargs...) +fzero(f, bracket::Tuple{T,S}; kwargs...) where {T <: Number, S<:Number} = find_zero(f, bracket, Bisection();kwargs...) + + + + +""" +Find zero using Newton's method. +""" +fzero(f::Function, fp::Function, x0::Real; kwargs...) = newton(f, fp, float(x0); kwargs...) + + + + + + +# match fzero up with find_zero +@noinline function derivative_free(f, x0; order::Int=0, kwargs...) + + if order == 0 + method = Order0() + elseif order == 1 + method = Order1() + elseif order == 2 + method = Order2() + elseif order == 5 + method = Order5() + elseif order == 8 + method = Order8() + elseif order == 16 + method = Order16() + else + warn("Invalid order. Valid orders are 0, 1, 2, 5, 8, and 16") + throw(ArgumentError()) + end + + d = Dict(kwargs) + for (o, n) in ((:ftol, :atol), (:ftolrel, :rtol), + (:xtol, :xatol), (:xtolrel, :xrtol)) + if haskey(d, o) + d[n] = d[o] + end + end + + + + find_zero(f, x0, method; d...) +end + +## +""" +Find a zero within a bracket with an initial guess to *possibly* speed things along. +""" +function fzero(f, x0::Real, bracket::Vector{T}; kwargs...) where {T <: Number} + + a, b = adjust_bracket(bracket) + + try + ex = a42a(f, a, b, float(x0); kwargs...) + catch ex + if isa(ex, StateConverged) + return(ex.x0) + else + rethrow(ex) + end + end +end + + +## fzeros +""" + +`fzeros(f, a, b)` + +Attempt to find all zeros of `f` within an interval `[a,b]`. + +Simple algorithm that splits `[a,b]` into subintervals and checks each +for a root. For bracketing subintervals, bisection is +used. Otherwise, a derivative-free method is used. If there are a +large number of zeros found relative to the number of subintervals, the +number of subintervals is increased and the process is re-run. + +There are possible issues with close-by zeros and zeros which do not +cross the origin (non-simple zeros). Answers should be confirmed +graphically, if possible. + +""" +function fzeros(f, a::Number, b::Number; kwargs...) + find_zeros(f, float(a), float(b); kwargs...) +end +fzeros(f, bracket::Vector{T}; kwargs...) where {T <: Number} = fzeros(f, a, b; kwargs...) +fzeros(f, bracket::Tuple{T,S}; kwargs...) where {T <: Number, S<:Number} = fzeros(f, a, b; kwargs...) + diff --git a/src/newton.jl b/src/newton.jl index 999a03ac..e9a59c26 100644 --- a/src/newton.jl +++ b/src/newton.jl @@ -15,19 +15,13 @@ will be used, as applicable. Unlike other methods, this method accepts complex inputs. """ -struct Newton <: UnivariateZeroMethod +struct Newton <: AbstractUnivariateZeroMethod end -function callable_function(method::Newton, f::Tuple) - length(f) == 1 && return FirstDerivative(f[1], D(f[1])) - FirstDerivative(f[1], f[2]) -end -callable_function(method::Newton, f::Any) = FirstDerivative(f, D(f)) - -function update_state(method::Newton, fs, o::UnivariateZeroState{T}, options::UnivariateZeroOptions) where {T} +function update_state(method::Newton, fs, o, options) xn = o.xn1 fxn = o.fxn1 - fpxn = fs.fp(xn) + fpxn = fs(xn,1) if isissue(fpxn) o.stopped=true @@ -35,7 +29,7 @@ function update_state(method::Newton, fs, o::UnivariateZeroState{T}, options::Un end xn1 = xn - fxn / fpxn - fxn1 = fs.f(xn1) + fxn1 = fs(xn1) incfn(o) o.xn0, o.xn1 = xn, xn1 @@ -46,37 +40,6 @@ function update_state(method::Newton, fs, o::UnivariateZeroState{T}, options::Un end -## extra work to allow for complex values - -## extra work to allow for complex values -function derivative_free_setup(method::Newton, fs::CallableFunction, x0::T; - bracket=missing, - xabstol=zero(T), xreltol=zero(T), - abstol=4*eps(T), reltol=4*eps(T), - maxevals=40, maxfnevals=typemax(Int), - verbose::Bool=false) where {T<:AbstractFloat} - x = float(x0) - - - prob = UnivariateZeroProblem(fs, x, bracket) - options = UnivariateZeroOptions(xabstol, xreltol, abstol, reltol, maxevals, maxfnevals, verbose) - prob, options -end - -function derivative_free_setup(method::Newton, fs::CallableFunction, x0::Complex{T}; - bracket=missing, - xabstol=zero(T), xreltol=zero(T), - abstol=4*eps(T), reltol=4*eps(T), - maxevals=40, maxfnevals=typemax(Int), - verbose::Bool=false) where {T<:AbstractFloat} - x = float(x0) - bracket = missing # bracket makes no sense for complex input, but one is expected - - prob = UnivariateZeroProblem(fs, x, bracket) - options = UnivariateZeroOptions(xabstol, xreltol, abstol, reltol, maxevals, maxfnevals, verbose) - prob, options -end - """ Implementation of Newton's method: `x_n1 = x_n - f(x_n)/ f'(x_n)` @@ -89,19 +52,7 @@ Arguments: * `x0::Number` -- initial guess. For Newton's method this may be complex. -Keyword arguments: - -* `ftol`. Stop iterating when |f(xn)| <= max(1, |xn|) * ftol. - -* `xtol`. Stop iterating when |xn+1 - xn| <= xtol + max(1, |xn|) * xtolrel - -* `xtolrel`. Stop iterating when |xn+1 - xn| <= xtol + max(1, |xn|) * xtolrel - -* `maxeval`. Stop iterating if more than this many steps, throw error. - -* `maxfneval`. Stop iterating if more than this many function calls, throw error. - -* `verbose::Bool=false` Set to `true` to see trace. +Keyword arguments are passed to `find_zero`. """ newton(f, x0; kwargs...) = find_zero(f, x0, Newton(); kwargs...) @@ -120,25 +71,18 @@ Implements Halley's [method](http://tinyurl.com/yd83eytb), This method is cubically converging, but requires more function calls per step than other methods. """ -struct Halley <: UnivariateZeroMethod +struct Halley <: AbstractUnivariateZeroMethod end -function callable_function(method::Halley, f::Tuple) - length(f) == 1 && return SecondDerivative(f[1], D(f[1]), D(f[1],2)) - length(f) == 2 && return SecondDerivative(f[1], f[2], D(f[2],1)) - SecondDerivative(f[1], f[2], f[3]) -end -callable_function(method::Halley, f) = SecondDerivative(f, D(f), D(f, 2)) - -function update_state(method::Halley, fs, o::UnivariateZeroState{T}, options::UnivariateZeroOptions) where {T} +function update_state(method::Halley, fs, o::UnivariateZeroState{T,S}, options::UnivariateZeroOptions) where {T,S} xn = o.xn1 fxn = o.fxn1 - fpxn = fs.fp(xn); incfn(o) - fppxn = fs.fpp(xn); incfn(o) + fpxn = fs(xn,1); incfn(o) + fppxn = fs(xn,2); incfn(o) xn1 = xn - 2fxn*fpxn / (2*fpxn*fpxn - fxn * fppxn) - fxn1 = fs.f(xn1); incfn(o) + fxn1 = fs(xn1); incfn(o) o.xn0, o.xn1 = xn, xn1 o.fxn0, o.fxn1 = fxn, fxn1 @@ -148,7 +92,7 @@ end """ Implementation of Halley's method. `xn1 = xn - 2f(xn)*f'(xn) / (2*f'(xn)^2 - f(xn) * f''(xn))` - + Arguments: * `f::Function` -- function to find zero of @@ -157,19 +101,9 @@ Arguments: * `fpp:Function=D(f,2)` -- second derivative of `f`. -* `x0::Real` -- initial guess - -Keyword arguments: - -* `ftol`. Stop iterating when |f(xn)| <= max(1, |xn|) * ftol. - -* `xtol`. Stop iterating when |xn+1 - xn| <= xtol + max(1, |xn|) * xtolrel - -* `xtolrel`. Stop iterating when |xn+1 - xn| <= xtol + max(1, |xn|) * xtolrel - -* `maxeval`. Stop iterating if more than this many steps, throw error. +* `x0::Number` -- initial guess -* `verbose::Bool=false` Set to `true` to see trace. +Keyword arguments are passed to `find_zero`. """ halley(f, x0; kwargs...) = find_zero(f, x0, Halley(); kwargs...) diff --git a/src/utils.jl b/src/utils.jl new file mode 100644 index 00000000..7dd15804 --- /dev/null +++ b/src/utils.jl @@ -0,0 +1,86 @@ +################################################## + +# type to throw on succesful convergence +mutable struct StateConverged + x0::Number +end + +# type to throw on failure +mutable struct ConvergenceFailed + reason::AbstractString +end + +################################################## +## Helpers for the various methods +## issue with approx derivative +isissue(x) = iszero(x) || isnan(x) || isinf(x) + + +""" +heuristic to get a decent first step with Steffensen steps +""" +function steff_step(x, fx) + + xbar, fxbar = x/oneunit(x), fx/oneunit(fx) + thresh = max(1, abs(xbar)) * sqrt(eps(one(xbar))) #^(1/2) # max(1, sqrt(abs(x/fx))) * 1e-6 + + out = abs(fxbar) <= thresh ? fxbar : sign(fx) * thresh + out * oneunit(x) + +end + +function guarded_secant_step(alpha, beta, falpha, fbeta) + + fp = (fbeta - falpha) / (beta - alpha) + Δ = fbeta / fp + ## odd, we get allocations if we define Delta, then beta - Delta + ## Δ = beta - fbeta * (beta - alpha) / (fbeta - falpha) + + if isissue(Δ) + Δ = oneunit(alpha)/1000 + elseif abs(Δ) >= 100 * abs(alpha - beta) # guard runaway + Δ = sign(Δ) * 100 * min(oneunit(alpha), abs(alpha - beta)) + end + + if isissue(Δ) + return (alpha + (beta - alpha)*(0.5), true) # midpoint + else + return (beta - Δ, false) + end +end + + +## Different functions for approximating f'(xn) +## return fpxn and whether it is an issue + +## use f[a,b] to approximate f'(x) +function _fbracket(a, b, fa, fb) + num, den = fb - fa, b - a + iszero(num) && iszero(den) && return Inf, true + out = num / den + out, isissue(out) +end + +## use f[y,z] - f[x,y] + f[x,z] to approximate +function _fbracket_diff(a,b,c, fa, fb, fc) + x1, issue = _fbracket(b, c, fb, fc) + issue && return x1, issue + x2, issue = _fbracket(a, b, fa, fb) + issue && return x2, issue + x3, issue = _fbracket(a, c, fa, fc) + issue && return x3, issue + + out = x1 - x2 + x3 + out, isissue(out) +end + + +## use f[a,b] * f[a,c] / f[b,c] +function _fbracket_ratio(a, b, c, fa, fb, fc) + x1, _ = _fbracket(a, b, fa, fb) + x2, _ = _fbracket(a, c, fa, fc) + x3, _ = _fbracket(b, c, fb, fc) + out = (x2 * x3) / x3 + out, isissue(out) +end + diff --git a/test/test_find_zero.jl b/test/test_find_zero.jl index 03ad7a02..9fef1263 100644 --- a/test/test_find_zero.jl +++ b/test/test_find_zero.jl @@ -29,7 +29,7 @@ for (i, (f, xstar, xs)) in enumerate(fns) for x0_ in xs out = try xn = find_zero(f, x0_, m) - @test norm(xn - xstar) < 1e-14 || norm(f(xn)) < 1e-13 + @test abs(xn - xstar) < 1e-14 || abs(f(xn)) < 1e-13 "." catch err "*" @@ -65,8 +65,8 @@ multiplicity_tests = [ for (i, (fn_, x0_, xstar)) in enumerate(multiplicity_tests) for m in meths - # println("$i: $m") - @test norm(find_zero(fn_, x0_, m, maxevals=100) - xstar) < 1e-1 # wow, not too ambitious here, 9th powers... + #println("$i: $m") + @test abs(find_zero(fn_, x0_, m, maxevals=100) - xstar) < 1e-1 # wow, not too ambitious here, 9th powers... end end @@ -85,7 +85,7 @@ end fn, xstar, x0 = x -> cos(x) - 1, 0.0, 0.1 for m in meths xn = find_zero(fn, x0, m) - @test norm(fn(xn)) <= 1e-10 + @test abs(fn(xn)) <= 1e-10 end ## issue with large steps @@ -105,16 +105,16 @@ end ## Methods guarded with a bracket -fn, xstar, x0 = (x -> sin(x) - x - 1, -1.9345632107520243, 2) -@test_throws Roots.ConvergenceFailed find_zero(fn, x0, Order2()) -for m in meths - @test find_zero(fn, x0, m, bracket=[-2,3]) ≈ xstar -end +# fn, xstar, x0 = (x -> sin(x) - x - 1, -1.9345632107520243, 2) +# @test_throws Roots.ConvergenceFailed find_zero(fn, x0, Order2()) +# for m in meths +# @test find_zero(fn, x0, m, bracket=[-2,3]) ≈ xstar +# end -fn, xstar, x0 = (x -> x * exp( - x ), 0, 1.0) -@test find_zero(fn, x0, Order0(), bracket=[-1,2]) ≈ xstar -@test find_zero(fn, 7.0, Order0(), bracket=[-1,2]) ≈ xstar # out of bracket +# fn, xstar, x0 = (x -> x * exp( - x ), 0, 1.0) +# @test find_zero(fn, x0, Order0(), bracket=[-1,2]) ≈ xstar +# @test find_zero(fn, 7.0, Order0(), bracket=[-1,2]) ≈ xstar # out of bracket ## bisection methods @test find_zero(x -> cos(x) - x, [0, pi], Bisection()) ≈ 0.7390851332151607 @@ -162,7 +162,7 @@ galadino_probs = [(x -> x^3 - 1, [.5, 1.5]), for (fn_, ab) in galadino_probs for m in [Roots.A42(), Bisection(), (FalsePosition(i) for i in 1:12)...] global x0 = find_zero(fn_, ab, m, maxevals=120) - @test norm(fn_(x0)) <= 1e-14 + @test abs(fn_(x0)) <= 1e-14 end end @@ -170,7 +170,7 @@ end fn = x -> x^5 - x - 1 for m in [Roots.A42(), Bisection(), (FalsePosition(i) for i in 1:12)...] global x0 = find_zero(fn, (1,2.0), m) - @test norm(fn(x0)) <= 1e-14 + @test abs(fn(x0)) <= 1e-14 end @@ -203,9 +203,9 @@ end ## test tolerance arguments fn, xstar = x -> sin(x) - x + 1, 1.9345632107520243 @test find_zero(fn, 20.0, Order2()) ≈ xstar # needs 16 iterations, 33 fn evaluations -@test norm(fn(find_zero(fn, 20.0, Order2(), abstol=1e-2)) - xstar) > 1e-12 -@test norm(fn(find_zero(fn, 20.0, Order2(), reltol=1e-2)) - xstar) > 1e-12 -@test_throws Roots.ConvergenceFailed find_zero(fn, 20.0, Order2(), maxevals=10) +@test abs(fn(find_zero(fn, 20.0, Order2(), abstol=1e-2)) - xstar) > 1e-12 +@test abs(fn(find_zero(fn, 20.0, Order2(), reltol=1e-2)) - xstar) > 1e-12 +@test_throws Roots.ConvergenceFailed find_zero(fn, 20.0, Order2(), maxevals=5) @test_throws Roots.ConvergenceFailed find_zero(fn, 20.0, Order2(), maxfnevals=10) @@ -268,9 +268,11 @@ test_94 = function(;kwargs...) end meth = Roots.FalsePosition() - prob, options = Roots.derivative_free_setup(meth, lhs, [atan(α*tf), atan(α*(tf-t1))]) - state = Roots.init_state(meth, prob.fs, prob.x0, prob.bracket) - find_zero(meth, prob.fs, state, options) + f, x0 = lhs, [atan(α*tf), atan(α*(tf-t1))] + F = Roots.DerivativeFree(lhs) + state = Roots.init_state(meth, F, x0) + options = Roots.init_options(meth, state) + find_zero(meth, F, options, state) @test state.steps <= 15 end diff --git a/test/test_fzero.jl b/test/test_fzero.jl index c4dd834e..f726b954 100644 --- a/test/test_fzero.jl +++ b/test/test_fzero.jl @@ -21,10 +21,10 @@ fn, xstar, x0, br = x -> x^5 - x - 1, 1.1673039782614187, 1.0, [1.0, 2.0] @test fzero(fn, x0, order=1) ≈ xstar @test_throws Roots.ConvergenceFailed fzero(fn, x0, order=1, maxevals=2) -#@test norm(fzero(fn, x0, order=1, ftol=1e-2) - xstar) > 1e-5 -#@test norm(fzero(fn, x0, order=1, xtol=1e-2) - xstar) > 1e-10 +#@test abs(fzero(fn, x0, order=1, ftol=1e-2) - xstar) > 1e-5 +#@test abs(fzero(fn, x0, order=1, xtol=1e-2) - xstar) > 1e-10 -@test norm(Roots.a42(fn, br[1], br[2], xtol=1e-2) - xstar) > 1e-5 +@test abs(Roots.a42(fn, br[1], br[2], xtol=1e-2) - xstar) > 1e-5 ## various tests @@ -41,7 +41,8 @@ f = x -> 1/x - 1 ################################################## ## fzeros function rts = 1:5 -@test norm(fzeros(x -> prod([x-r for r in rts]),0,10) .- collect(1:5)) <= 1e-15 +@test all((abs.(fzeros(x -> prod([x-r for r in rts]),0,10)) .- collect(1:5)) .<= 1e-15) + fn = x -> sin(10*pi*x) @test length(fzeros(fn, 0, 1)) == 11 diff --git a/test/test_newton.jl b/test/test_newton.jl index 9e08cbb0..8d6ecf61 100644 --- a/test/test_newton.jl +++ b/test/test_newton.jl @@ -1,15 +1,15 @@ using Compat.Test import Roots.newton, Roots.halley -@test norm(newton(sin, cos, 0.5) - 0.0) <= 100*eps(1.0) +@test abs(newton(sin, cos, 0.5) - 0.0) <= 100*eps(1.0) @test newton(cos, x -> -sin(x), 1.0) ≈ pi/2 @test newton(x -> x^2 - 2x - 1, x -> 2x - 2, 3.0) ≈ 2.414213562373095 -@test norm(newton(x -> exp(x) - cos(x), x -> exp(x) + sin(x), 3.0) - 0.0) <= 1e-14 +@test abs(newton(x -> exp(x) - cos(x), x -> exp(x) + sin(x), 3.0) - 0.0) <= 1e-14 @test halley(x -> x^2 - 2x - 1,x -> 2x - 2,x -> 2, 3.0) ≈ 2.414213562373095 a = halley(x -> exp(x) - cos(x), x -> exp(x) + sin(x), x -> exp(x) + cos(x), 3.0) -@test norm(a - 0.0) <= 1e-14 +@test abs(a - 0.0) <= 1e-14 ## tests with auto derivatives @@ -17,7 +17,7 @@ a = halley(x -> exp(x) - cos(x), @test halley(sin, 3) ≈ pi ## More tests with autoderivaitves. Derivative of D operation: -isdefined(ForwardDiff, :derivative) && @test newton(D(sin), 1.5) ≈ pi/2 +@test newton(D(sin), 1.5) ≈ pi/2 ## test with Complex input